semihosting, plugin and doc updates:
- log a guest_error for failed semihosting open() - clean up semihosting includes to reduce build duplication - re-factor misc device initialisation to fail with &error_exit - propagate Error * to gdbserver_start sub-functions - fix 32-bit build of plugins and re-enable by default - ensure IRQs don't preempt io recompiled instructions - remove usage of gcc_struct to enable clang builds - enable clang/lld to build plugins on windows - various small kdoc typo fixes - add perl scripts to editorconfig - remove unused field from MemoryRegion - make kdoc script a dependency so doc rebuilds get triggered - expand developer documentation: - notes on git-publish - describe usage of b4 - setting up build dependencies - codebase layout - add a glossary of common terms - optimise the windows ndis script -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAmeKO8sACgkQ+9DbCVqe KkTbBQf9HRlspCl2r5a8K9O1ymylKiZ653OBWMStGTQ8xPXeLDFhT+ION34VBgBh LXHEcjIHn24cN2s1BO5+xJs0nzqYe7UEAK6JQmdX3/HEuf8VmaVslvhm+nCWKoIL JQbsHno92wh6vvTWQu53zijEuG5HdBseWiwQKHbE1oSRc2CikG70o902AL9zXAsp mpUYWxUmWwg5uQATztp4XfylJBcSX3SiVgv22jXLqBj9drXPftl/E33fcWXxTj5f AM3kz9fxaCfo5+znmYw3R1tT/Hv52Q6hW+oNAm34XeWp1/+ho27QMRrpIi/dpdwX mCbvJwI75sCnD91p9NW7vZIYZJKsLg== =SLCY -----END PGP SIGNATURE----- Merge tag 'pull-10.0-gdb-plugins-doc-updates-170125-1' of https://gitlab.com/stsquad/qemu into staging semihosting, plugin and doc updates: - log a guest_error for failed semihosting open() - clean up semihosting includes to reduce build duplication - re-factor misc device initialisation to fail with &error_exit - propagate Error * to gdbserver_start sub-functions - fix 32-bit build of plugins and re-enable by default - ensure IRQs don't preempt io recompiled instructions - remove usage of gcc_struct to enable clang builds - enable clang/lld to build plugins on windows - various small kdoc typo fixes - add perl scripts to editorconfig - remove unused field from MemoryRegion - make kdoc script a dependency so doc rebuilds get triggered - expand developer documentation: - notes on git-publish - describe usage of b4 - setting up build dependencies - codebase layout - add a glossary of common terms - optimise the windows ndis script # -----BEGIN PGP SIGNATURE----- # # iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAmeKO8sACgkQ+9DbCVqe # KkTbBQf9HRlspCl2r5a8K9O1ymylKiZ653OBWMStGTQ8xPXeLDFhT+ION34VBgBh # LXHEcjIHn24cN2s1BO5+xJs0nzqYe7UEAK6JQmdX3/HEuf8VmaVslvhm+nCWKoIL # JQbsHno92wh6vvTWQu53zijEuG5HdBseWiwQKHbE1oSRc2CikG70o902AL9zXAsp # mpUYWxUmWwg5uQATztp4XfylJBcSX3SiVgv22jXLqBj9drXPftl/E33fcWXxTj5f # AM3kz9fxaCfo5+znmYw3R1tT/Hv52Q6hW+oNAm34XeWp1/+ho27QMRrpIi/dpdwX # mCbvJwI75sCnD91p9NW7vZIYZJKsLg== # =SLCY # -----END PGP SIGNATURE----- # gpg: Signature made Fri 17 Jan 2025 06:15:23 EST # gpg: using RSA key 6685AE99E75167BCAFC8DF35FBD0DB095A9E2A44 # gpg: Good signature from "Alex Bennée (Master Work Key) <alex.bennee@linaro.org>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 6685 AE99 E751 67BC AFC8 DF35 FBD0 DB09 5A9E 2A44 * tag 'pull-10.0-gdb-plugins-doc-updates-170125-1' of https://gitlab.com/stsquad/qemu: (37 commits) scripts/nsis.py: Run dependency check for each DLL file only once docs: add a glossary docs/devel: add a codebase section docs/devel: add information on how to setup build environments docs/devel: add b4 for patch retrieval docs/devel: add git-publish for patch submitting docs/sphinx: include kernel-doc script as a dependency include/exec: remove warning_printed from MemoryRegion include/exec: fix some copy and paste errors in kdoc tests/qtest: fix some copy and paste errors in kdoc editorconfig: update for perl scripts plugins: fix kdoc annotation plugins: enable linking with clang/lld docs/devel/style: add a section about bitfield, and disallow them for packed structures win32: remove usage of attribute gcc_struct accel/tcg: also suppress asynchronous IRQs for cpu_io_recompile configure: reenable plugins by default for 32-bit hosts contrib/plugins/hotpages: fix 32-bit build contrib/plugins/hwprofile: fix 32-bit build contrib/plugins/cflow: fix 32-bit build ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
0e3aff9ec3
@ -47,3 +47,16 @@ emacs_mode = glsl
|
||||
[*.json]
|
||||
indent_style = space
|
||||
emacs_mode = python
|
||||
|
||||
# by default follow QEMU's style
|
||||
[*.pl]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
emacs_mode = perl
|
||||
|
||||
# but user kernel "style" for imported scripts
|
||||
[scripts/{kernel-doc,get_maintainer.pl,checkpatch.pl}]
|
||||
indent_style = tab
|
||||
indent_size = 8
|
||||
emacs_mode = perl
|
||||
|
||||
|
@ -72,11 +72,14 @@ R: Markus Armbruster <armbru@redhat.com>
|
||||
R: Philippe Mathieu-Daudé <philmd@linaro.org>
|
||||
W: https://www.qemu.org/docs/master/devel/index.html
|
||||
S: Odd Fixes
|
||||
F: docs/devel/style.rst
|
||||
F: docs/devel/build-environment.rst
|
||||
F: docs/devel/code-of-conduct.rst
|
||||
F: docs/devel/codebase.rst
|
||||
F: docs/devel/conflict-resolution.rst
|
||||
F: docs/devel/style.rst
|
||||
F: docs/devel/submitting-a-patch.rst
|
||||
F: docs/devel/submitting-a-pull-request.rst
|
||||
F: docs/glossary.rst
|
||||
|
||||
Responsible Disclosure, Reporting Security Issues
|
||||
-------------------------------------------------
|
||||
|
@ -633,9 +633,10 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
|
||||
* Exit the loop and potentially generate a new TB executing the
|
||||
* just the I/O insns. We also limit instrumentation to memory
|
||||
* operations only (which execute after completion) so we don't
|
||||
* double instrument the instruction.
|
||||
* double instrument the instruction. Also don't let an IRQ sneak
|
||||
* in before we execute it.
|
||||
*/
|
||||
cpu->cflags_next_tb = curr_cflags(cpu) | CF_MEMI_ONLY | n;
|
||||
cpu->cflags_next_tb = curr_cflags(cpu) | CF_MEMI_ONLY | CF_NOIRQ | n;
|
||||
|
||||
if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
|
||||
vaddr pc = cpu->cc->get_pc(cpu);
|
||||
|
@ -628,7 +628,7 @@ int main(int argc, char **argv)
|
||||
target_cpu_init(env, regs);
|
||||
|
||||
if (gdbstub) {
|
||||
gdbserver_start(gdbstub);
|
||||
gdbserver_start(gdbstub, &error_fatal);
|
||||
gdb_handlesig(cpu, 0, NULL, NULL, 0);
|
||||
}
|
||||
cpu_loop(env);
|
||||
|
21
configure
vendored
21
configure
vendored
@ -528,25 +528,6 @@ case "$cpu" in
|
||||
;;
|
||||
esac
|
||||
|
||||
# Now we have our CPU_CFLAGS we can check if we are targeting a 32 or
|
||||
# 64 bit host.
|
||||
|
||||
check_64bit_host() {
|
||||
cat > $TMPC <<EOF
|
||||
#if __SIZEOF_POINTER__ != 8
|
||||
#error not 64 bit system
|
||||
#endif
|
||||
int main(void) { return 0; }
|
||||
EOF
|
||||
compile_object "$1"
|
||||
}
|
||||
|
||||
if check_64bit_host "$CPU_CFLAGS"; then
|
||||
host_bits=64
|
||||
else
|
||||
host_bits=32
|
||||
fi
|
||||
|
||||
if test -n "$host_arch" && {
|
||||
! test -d "$source_path/linux-user/include/host/$host_arch" ||
|
||||
! test -d "$source_path/common-user/host/$host_arch"; }; then
|
||||
@ -1072,7 +1053,7 @@ if test "$static" = "yes" ; then
|
||||
fi
|
||||
plugins="no"
|
||||
fi
|
||||
if test "$plugins" != "no" && test $host_bits -eq 64; then
|
||||
if test "$plugins" != "no"; then
|
||||
if has_meson_option "-Dtcg_interpreter=true"; then
|
||||
plugins="no"
|
||||
else
|
||||
|
@ -208,7 +208,7 @@ static int fifo_get_first_block(Cache *cache, int set)
|
||||
static void fifo_update_on_miss(Cache *cache, int set, int blk_idx)
|
||||
{
|
||||
GQueue *q = cache->sets[set].fifo_queue;
|
||||
g_queue_push_head(q, GINT_TO_POINTER(blk_idx));
|
||||
g_queue_push_head(q, (gpointer)(intptr_t) blk_idx);
|
||||
}
|
||||
|
||||
static void fifo_destroy(Cache *cache)
|
||||
@ -471,13 +471,8 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
|
||||
n_insns = qemu_plugin_tb_n_insns(tb);
|
||||
for (i = 0; i < n_insns; i++) {
|
||||
struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
|
||||
uint64_t effective_addr;
|
||||
|
||||
if (sys) {
|
||||
effective_addr = (uint64_t) qemu_plugin_insn_haddr(insn);
|
||||
} else {
|
||||
effective_addr = (uint64_t) qemu_plugin_insn_vaddr(insn);
|
||||
}
|
||||
uint64_t effective_addr = sys ? (uintptr_t) qemu_plugin_insn_haddr(insn) :
|
||||
qemu_plugin_insn_vaddr(insn);
|
||||
|
||||
/*
|
||||
* Instructions might get translated multiple times, we do not create
|
||||
@ -485,14 +480,13 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
|
||||
* entry from the hash table and register it for the callback again.
|
||||
*/
|
||||
g_mutex_lock(&hashtable_lock);
|
||||
data = g_hash_table_lookup(miss_ht, GUINT_TO_POINTER(effective_addr));
|
||||
data = g_hash_table_lookup(miss_ht, &effective_addr);
|
||||
if (data == NULL) {
|
||||
data = g_new0(InsnData, 1);
|
||||
data->disas_str = qemu_plugin_insn_disas(insn);
|
||||
data->symbol = qemu_plugin_insn_symbol(insn);
|
||||
data->addr = effective_addr;
|
||||
g_hash_table_insert(miss_ht, GUINT_TO_POINTER(effective_addr),
|
||||
(gpointer) data);
|
||||
g_hash_table_insert(miss_ht, &data->addr, data);
|
||||
}
|
||||
g_mutex_unlock(&hashtable_lock);
|
||||
|
||||
@ -853,7 +847,7 @@ int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info,
|
||||
qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
|
||||
qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
|
||||
|
||||
miss_ht = g_hash_table_new_full(NULL, g_direct_equal, NULL, insn_free);
|
||||
miss_ht = g_hash_table_new_full(g_int64_hash, g_int64_equal, NULL, insn_free);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -76,6 +76,8 @@ typedef struct {
|
||||
|
||||
/* We use this to track the current execution state */
|
||||
typedef struct {
|
||||
/* address of current translated block */
|
||||
uint64_t tb_pc;
|
||||
/* address of end of block */
|
||||
uint64_t end_block;
|
||||
/* next pc after end of block */
|
||||
@ -85,6 +87,7 @@ typedef struct {
|
||||
} VCPUScoreBoard;
|
||||
|
||||
/* descriptors for accessing the above scoreboard */
|
||||
static qemu_plugin_u64 tb_pc;
|
||||
static qemu_plugin_u64 end_block;
|
||||
static qemu_plugin_u64 pc_after_block;
|
||||
static qemu_plugin_u64 last_pc;
|
||||
@ -189,10 +192,11 @@ static void plugin_exit(qemu_plugin_id_t id, void *p)
|
||||
static void plugin_init(void)
|
||||
{
|
||||
g_mutex_init(&node_lock);
|
||||
nodes = g_hash_table_new(NULL, g_direct_equal);
|
||||
nodes = g_hash_table_new(g_int64_hash, g_int64_equal);
|
||||
state = qemu_plugin_scoreboard_new(sizeof(VCPUScoreBoard));
|
||||
|
||||
/* score board declarations */
|
||||
tb_pc = qemu_plugin_scoreboard_u64_in_struct(state, VCPUScoreBoard, tb_pc);
|
||||
end_block = qemu_plugin_scoreboard_u64_in_struct(state, VCPUScoreBoard,
|
||||
end_block);
|
||||
pc_after_block = qemu_plugin_scoreboard_u64_in_struct(state, VCPUScoreBoard,
|
||||
@ -215,10 +219,10 @@ static NodeData *fetch_node(uint64_t addr, bool create_if_not_found)
|
||||
NodeData *node = NULL;
|
||||
|
||||
g_mutex_lock(&node_lock);
|
||||
node = (NodeData *) g_hash_table_lookup(nodes, (gconstpointer) addr);
|
||||
node = (NodeData *) g_hash_table_lookup(nodes, &addr);
|
||||
if (!node && create_if_not_found) {
|
||||
node = create_node(addr);
|
||||
g_hash_table_insert(nodes, (gpointer) addr, (gpointer) node);
|
||||
g_hash_table_insert(nodes, &node->addr, node);
|
||||
}
|
||||
g_mutex_unlock(&node_lock);
|
||||
return node;
|
||||
@ -234,7 +238,7 @@ static void vcpu_tb_branched_exec(unsigned int cpu_index, void *udata)
|
||||
uint64_t lpc = qemu_plugin_u64_get(last_pc, cpu_index);
|
||||
uint64_t ebpc = qemu_plugin_u64_get(end_block, cpu_index);
|
||||
uint64_t npc = qemu_plugin_u64_get(pc_after_block, cpu_index);
|
||||
uint64_t pc = GPOINTER_TO_UINT(udata);
|
||||
uint64_t pc = qemu_plugin_u64_get(tb_pc, cpu_index);
|
||||
|
||||
/* return early for address 0 */
|
||||
if (!lpc) {
|
||||
@ -305,10 +309,11 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
|
||||
* handle both early block exits and normal branches in the
|
||||
* callback if we hit it.
|
||||
*/
|
||||
gpointer udata = GUINT_TO_POINTER(pc);
|
||||
qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu(
|
||||
tb, QEMU_PLUGIN_INLINE_STORE_U64, tb_pc, pc);
|
||||
qemu_plugin_register_vcpu_tb_exec_cond_cb(
|
||||
tb, vcpu_tb_branched_exec, QEMU_PLUGIN_CB_NO_REGS,
|
||||
QEMU_PLUGIN_COND_NE, pc_after_block, pc, udata);
|
||||
QEMU_PLUGIN_COND_NE, pc_after_block, pc, NULL);
|
||||
|
||||
/*
|
||||
* Now we can set start/end for this block so the next block can
|
||||
|
@ -29,7 +29,7 @@ static guint64 limit = 20;
|
||||
*
|
||||
* The internals of the TCG are not exposed to plugins so we can only
|
||||
* get the starting PC for each block. We cheat this slightly by
|
||||
* xor'ing the number of instructions to the hash to help
|
||||
* checking the number of instructions as well to help
|
||||
* differentiate.
|
||||
*/
|
||||
typedef struct {
|
||||
@ -50,6 +50,20 @@ static gint cmp_exec_count(gconstpointer a, gconstpointer b)
|
||||
return count_a > count_b ? -1 : 1;
|
||||
}
|
||||
|
||||
static guint exec_count_hash(gconstpointer v)
|
||||
{
|
||||
const ExecCount *e = v;
|
||||
return e->start_addr ^ e->insns;
|
||||
}
|
||||
|
||||
static gboolean exec_count_equal(gconstpointer v1, gconstpointer v2)
|
||||
{
|
||||
const ExecCount *ea = v1;
|
||||
const ExecCount *eb = v2;
|
||||
return (ea->start_addr == eb->start_addr) &&
|
||||
(ea->insns == eb->insns);
|
||||
}
|
||||
|
||||
static void exec_count_free(gpointer key, gpointer value, gpointer user_data)
|
||||
{
|
||||
ExecCount *cnt = value;
|
||||
@ -91,7 +105,7 @@ static void plugin_exit(qemu_plugin_id_t id, void *p)
|
||||
|
||||
static void plugin_init(void)
|
||||
{
|
||||
hotblocks = g_hash_table_new(NULL, g_direct_equal);
|
||||
hotblocks = g_hash_table_new(exec_count_hash, exec_count_equal);
|
||||
}
|
||||
|
||||
static void vcpu_tb_exec(unsigned int cpu_index, void *udata)
|
||||
@ -111,10 +125,15 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
|
||||
ExecCount *cnt;
|
||||
uint64_t pc = qemu_plugin_tb_vaddr(tb);
|
||||
size_t insns = qemu_plugin_tb_n_insns(tb);
|
||||
uint64_t hash = pc ^ insns;
|
||||
|
||||
g_mutex_lock(&lock);
|
||||
cnt = (ExecCount *) g_hash_table_lookup(hotblocks, (gconstpointer) hash);
|
||||
{
|
||||
ExecCount e;
|
||||
e.start_addr = pc;
|
||||
e.insns = insns;
|
||||
cnt = (ExecCount *) g_hash_table_lookup(hotblocks, &e);
|
||||
}
|
||||
|
||||
if (cnt) {
|
||||
cnt->trans_count++;
|
||||
} else {
|
||||
@ -123,7 +142,7 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
|
||||
cnt->trans_count = 1;
|
||||
cnt->insns = insns;
|
||||
cnt->exec_count = qemu_plugin_scoreboard_new(sizeof(uint64_t));
|
||||
g_hash_table_insert(hotblocks, (gpointer) hash, (gpointer) cnt);
|
||||
g_hash_table_insert(hotblocks, cnt, cnt);
|
||||
}
|
||||
|
||||
g_mutex_unlock(&lock);
|
||||
|
@ -103,7 +103,7 @@ static void plugin_exit(qemu_plugin_id_t id, void *p)
|
||||
static void plugin_init(void)
|
||||
{
|
||||
page_mask = (page_size - 1);
|
||||
pages = g_hash_table_new(NULL, g_direct_equal);
|
||||
pages = g_hash_table_new(g_int64_hash, g_int64_equal);
|
||||
}
|
||||
|
||||
static void vcpu_haddr(unsigned int cpu_index, qemu_plugin_meminfo_t meminfo,
|
||||
@ -130,12 +130,12 @@ static void vcpu_haddr(unsigned int cpu_index, qemu_plugin_meminfo_t meminfo,
|
||||
page &= ~page_mask;
|
||||
|
||||
g_mutex_lock(&lock);
|
||||
count = (PageCounters *) g_hash_table_lookup(pages, GUINT_TO_POINTER(page));
|
||||
count = (PageCounters *) g_hash_table_lookup(pages, &page);
|
||||
|
||||
if (!count) {
|
||||
count = g_new0(PageCounters, 1);
|
||||
count->page_address = page;
|
||||
g_hash_table_insert(pages, GUINT_TO_POINTER(page), (gpointer) count);
|
||||
g_hash_table_insert(pages, &count->page_address, count);
|
||||
}
|
||||
if (qemu_plugin_mem_is_store(meminfo)) {
|
||||
count->writes++;
|
||||
|
@ -253,6 +253,8 @@ static struct qemu_plugin_scoreboard *find_counter(
|
||||
int i;
|
||||
uint64_t *cnt = NULL;
|
||||
uint32_t opcode = 0;
|
||||
/* if opcode is greater than 32 bits, we should refactor insn hash table. */
|
||||
G_STATIC_ASSERT(sizeof(opcode) == sizeof(uint32_t));
|
||||
InsnClassExecCount *class = NULL;
|
||||
|
||||
/*
|
||||
@ -284,7 +286,7 @@ static struct qemu_plugin_scoreboard *find_counter(
|
||||
|
||||
g_mutex_lock(&lock);
|
||||
icount = (InsnExecCount *) g_hash_table_lookup(insns,
|
||||
GUINT_TO_POINTER(opcode));
|
||||
(gpointer)(intptr_t) opcode);
|
||||
|
||||
if (!icount) {
|
||||
icount = g_new0(InsnExecCount, 1);
|
||||
@ -295,8 +297,7 @@ static struct qemu_plugin_scoreboard *find_counter(
|
||||
qemu_plugin_scoreboard_new(sizeof(uint64_t));
|
||||
icount->count = qemu_plugin_scoreboard_u64(score);
|
||||
|
||||
g_hash_table_insert(insns, GUINT_TO_POINTER(opcode),
|
||||
(gpointer) icount);
|
||||
g_hash_table_insert(insns, (gpointer)(intptr_t) opcode, icount);
|
||||
}
|
||||
g_mutex_unlock(&lock);
|
||||
|
||||
|
@ -43,6 +43,8 @@ typedef struct {
|
||||
|
||||
static GMutex lock;
|
||||
static GHashTable *devices;
|
||||
static struct qemu_plugin_scoreboard *source_pc_scoreboard;
|
||||
static qemu_plugin_u64 source_pc;
|
||||
|
||||
/* track the access pattern to a piece of HW */
|
||||
static bool pattern;
|
||||
@ -159,7 +161,7 @@ static DeviceCounts *new_count(const char *name, uint64_t base)
|
||||
count->name = name;
|
||||
count->base = base;
|
||||
if (pattern || source) {
|
||||
count->detail = g_hash_table_new(NULL, NULL);
|
||||
count->detail = g_hash_table_new(g_int64_hash, g_int64_equal);
|
||||
}
|
||||
g_hash_table_insert(devices, (gpointer) name, count);
|
||||
return count;
|
||||
@ -169,7 +171,7 @@ static IOLocationCounts *new_location(GHashTable *table, uint64_t off_or_pc)
|
||||
{
|
||||
IOLocationCounts *loc = g_new0(IOLocationCounts, 1);
|
||||
loc->off_or_pc = off_or_pc;
|
||||
g_hash_table_insert(table, (gpointer) off_or_pc, loc);
|
||||
g_hash_table_insert(table, &loc->off_or_pc, loc);
|
||||
return loc;
|
||||
}
|
||||
|
||||
@ -224,12 +226,12 @@ static void vcpu_haddr(unsigned int cpu_index, qemu_plugin_meminfo_t meminfo,
|
||||
|
||||
/* either track offsets or source of access */
|
||||
if (source) {
|
||||
off = (uint64_t) udata;
|
||||
off = qemu_plugin_u64_get(source_pc, cpu_index);
|
||||
}
|
||||
|
||||
if (pattern || source) {
|
||||
IOLocationCounts *io_count = g_hash_table_lookup(counts->detail,
|
||||
(gpointer) off);
|
||||
&off);
|
||||
if (!io_count) {
|
||||
io_count = new_location(counts->detail, off);
|
||||
}
|
||||
@ -247,10 +249,14 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
|
||||
gpointer udata = (gpointer) (source ? qemu_plugin_insn_vaddr(insn) : 0);
|
||||
if (source) {
|
||||
uint64_t pc = qemu_plugin_insn_vaddr(insn);
|
||||
qemu_plugin_register_vcpu_mem_inline_per_vcpu(
|
||||
insn, rw, QEMU_PLUGIN_INLINE_STORE_U64,
|
||||
source_pc, pc);
|
||||
}
|
||||
qemu_plugin_register_vcpu_mem_cb(insn, vcpu_haddr,
|
||||
QEMU_PLUGIN_CB_NO_REGS,
|
||||
rw, udata);
|
||||
QEMU_PLUGIN_CB_NO_REGS, rw, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -306,10 +312,9 @@ int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Just warn about overflow */
|
||||
if (info->system.smp_vcpus > 64 ||
|
||||
info->system.max_vcpus > 64) {
|
||||
fprintf(stderr, "hwprofile: can only track up to 64 CPUs\n");
|
||||
if (source) {
|
||||
source_pc_scoreboard = qemu_plugin_scoreboard_new(sizeof(uint64_t));
|
||||
source_pc = qemu_plugin_scoreboard_u64(source_pc_scoreboard);
|
||||
}
|
||||
|
||||
plugin_init();
|
||||
|
@ -12,7 +12,7 @@ if get_option('plugins')
|
||||
t += shared_module(i, files(i + '.c') + 'win32_linker.c',
|
||||
include_directories: '../../include/qemu',
|
||||
link_depends: [win32_qemu_plugin_api_lib],
|
||||
link_args: ['-Lplugins', '-lqemu_plugin_api'],
|
||||
link_args: win32_qemu_plugin_api_link_flags,
|
||||
dependencies: glib)
|
||||
else
|
||||
t += shared_module(i, files(i + '.c'),
|
||||
|
@ -21,9 +21,11 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
|
||||
/* Scoreboard to track executed instructions count */
|
||||
typedef struct {
|
||||
uint64_t insn_count;
|
||||
uint64_t current_pc;
|
||||
} InstructionsCount;
|
||||
static struct qemu_plugin_scoreboard *insn_count_sb;
|
||||
static qemu_plugin_u64 insn_count;
|
||||
static qemu_plugin_u64 current_pc;
|
||||
|
||||
static uint64_t icount;
|
||||
static int icount_exit_code;
|
||||
@ -34,6 +36,11 @@ static bool exit_on_address;
|
||||
/* Map trigger addresses to exit code */
|
||||
static GHashTable *addrs_ht;
|
||||
|
||||
typedef struct {
|
||||
uint64_t exit_addr;
|
||||
int exit_code;
|
||||
} ExitInfo;
|
||||
|
||||
static void exit_emulation(int return_code, char *message)
|
||||
{
|
||||
qemu_plugin_outs(message);
|
||||
@ -43,23 +50,18 @@ static void exit_emulation(int return_code, char *message)
|
||||
|
||||
static void exit_icount_reached(unsigned int cpu_index, void *udata)
|
||||
{
|
||||
uint64_t insn_vaddr = GPOINTER_TO_UINT(udata);
|
||||
uint64_t insn_vaddr = qemu_plugin_u64_get(current_pc, cpu_index);
|
||||
char *msg = g_strdup_printf("icount reached at 0x%" PRIx64 ", exiting\n",
|
||||
insn_vaddr);
|
||||
|
||||
exit_emulation(icount_exit_code, msg);
|
||||
}
|
||||
|
||||
static void exit_address_reached(unsigned int cpu_index, void *udata)
|
||||
{
|
||||
uint64_t insn_vaddr = GPOINTER_TO_UINT(udata);
|
||||
char *msg = g_strdup_printf("0x%" PRIx64 " reached, exiting\n", insn_vaddr);
|
||||
int exit_code;
|
||||
|
||||
exit_code = GPOINTER_TO_INT(
|
||||
g_hash_table_lookup(addrs_ht, GUINT_TO_POINTER(insn_vaddr)));
|
||||
|
||||
exit_emulation(exit_code, msg);
|
||||
ExitInfo *ei = udata;
|
||||
g_assert(ei);
|
||||
char *msg = g_strdup_printf("0x%" PRIx64 " reached, exiting\n", ei->exit_addr);
|
||||
exit_emulation(ei->exit_code, msg);
|
||||
}
|
||||
|
||||
static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
|
||||
@ -67,23 +69,25 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
|
||||
size_t tb_n = qemu_plugin_tb_n_insns(tb);
|
||||
for (size_t i = 0; i < tb_n; i++) {
|
||||
struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
|
||||
gpointer insn_vaddr = GUINT_TO_POINTER(qemu_plugin_insn_vaddr(insn));
|
||||
uint64_t insn_vaddr = qemu_plugin_insn_vaddr(insn);
|
||||
|
||||
if (exit_on_icount) {
|
||||
/* Increment and check scoreboard for each instruction */
|
||||
qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(
|
||||
insn, QEMU_PLUGIN_INLINE_ADD_U64, insn_count, 1);
|
||||
qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(
|
||||
insn, QEMU_PLUGIN_INLINE_STORE_U64, current_pc, insn_vaddr);
|
||||
qemu_plugin_register_vcpu_insn_exec_cond_cb(
|
||||
insn, exit_icount_reached, QEMU_PLUGIN_CB_NO_REGS,
|
||||
QEMU_PLUGIN_COND_EQ, insn_count, icount + 1, insn_vaddr);
|
||||
QEMU_PLUGIN_COND_EQ, insn_count, icount + 1, NULL);
|
||||
}
|
||||
|
||||
if (exit_on_address) {
|
||||
if (g_hash_table_contains(addrs_ht, insn_vaddr)) {
|
||||
ExitInfo *ei = g_hash_table_lookup(addrs_ht, &insn_vaddr);
|
||||
if (ei) {
|
||||
/* Exit triggered by address */
|
||||
qemu_plugin_register_vcpu_insn_exec_cb(
|
||||
insn, exit_address_reached, QEMU_PLUGIN_CB_NO_REGS,
|
||||
insn_vaddr);
|
||||
insn, exit_address_reached, QEMU_PLUGIN_CB_NO_REGS, ei);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -99,11 +103,13 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
|
||||
const qemu_info_t *info, int argc,
|
||||
char **argv)
|
||||
{
|
||||
addrs_ht = g_hash_table_new(NULL, g_direct_equal);
|
||||
addrs_ht = g_hash_table_new_full(g_int64_hash, g_int64_equal, NULL, g_free);
|
||||
|
||||
insn_count_sb = qemu_plugin_scoreboard_new(sizeof(InstructionsCount));
|
||||
insn_count = qemu_plugin_scoreboard_u64_in_struct(
|
||||
insn_count_sb, InstructionsCount, insn_count);
|
||||
current_pc = qemu_plugin_scoreboard_u64_in_struct(
|
||||
insn_count_sb, InstructionsCount, current_pc);
|
||||
|
||||
for (int i = 0; i < argc; i++) {
|
||||
char *opt = argv[i];
|
||||
@ -124,13 +130,13 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
|
||||
exit_on_icount = true;
|
||||
} else if (g_strcmp0(tokens[0], "addr") == 0) {
|
||||
g_auto(GStrv) addr_tokens = g_strsplit(tokens[1], ":", 2);
|
||||
uint64_t exit_addr = g_ascii_strtoull(addr_tokens[0], NULL, 0);
|
||||
int exit_code = 0;
|
||||
ExitInfo *ei = g_malloc(sizeof(ExitInfo));
|
||||
ei->exit_addr = g_ascii_strtoull(addr_tokens[0], NULL, 0);
|
||||
ei->exit_code = 0;
|
||||
if (addr_tokens[1]) {
|
||||
exit_code = g_ascii_strtoull(addr_tokens[1], NULL, 0);
|
||||
ei->exit_code = g_ascii_strtoull(addr_tokens[1], NULL, 0);
|
||||
}
|
||||
g_hash_table_insert(addrs_ht, GUINT_TO_POINTER(exit_addr),
|
||||
GINT_TO_POINTER(exit_code));
|
||||
g_hash_table_insert(addrs_ht, &ei->exit_addr, ei);
|
||||
exit_on_address = true;
|
||||
} else {
|
||||
fprintf(stderr, "option parsing failed: %s\n", opt);
|
||||
|
@ -29,6 +29,9 @@ The `Repology`_ site is a useful resource to identify
|
||||
currently shipped versions of software in various operating systems,
|
||||
though it does not cover all distros listed below.
|
||||
|
||||
You can find how to install build dependencies for different systems on the
|
||||
:ref:`setup-build-env` page.
|
||||
|
||||
Supported host architectures
|
||||
----------------------------
|
||||
|
||||
@ -130,7 +133,6 @@ Optional build dependencies
|
||||
cross compilation using ``docker`` or ``podman``, or to use pre-built
|
||||
binaries distributed with QEMU.
|
||||
|
||||
|
||||
Windows
|
||||
-------
|
||||
|
||||
|
@ -176,6 +176,8 @@ for that architecture.
|
||||
- System
|
||||
- Tensilica ISS SIMCALL
|
||||
|
||||
.. _tcg-plugins:
|
||||
|
||||
TCG Plugins
|
||||
-----------
|
||||
|
||||
|
118
docs/devel/build-environment.rst
Normal file
118
docs/devel/build-environment.rst
Normal file
@ -0,0 +1,118 @@
|
||||
|
||||
.. _setup-build-env:
|
||||
|
||||
Setup build environment
|
||||
=======================
|
||||
|
||||
QEMU uses a lot of dependencies on the host system. glib2 is used everywhere in
|
||||
the code base, and most of the other dependencies are optional.
|
||||
|
||||
We present here simple instructions to enable native builds on most popular
|
||||
systems.
|
||||
|
||||
You can find additional instructions on `QEMU wiki <https://wiki.qemu.org/>`_:
|
||||
|
||||
- `Linux <https://wiki.qemu.org/Hosts/Linux>`_
|
||||
- `MacOS <https://wiki.qemu.org/Hosts/Mac>`_
|
||||
- `Windows <https://wiki.qemu.org/Hosts/W32>`_
|
||||
- `BSD <https://wiki.qemu.org/Hosts/BSD>`_
|
||||
|
||||
Note: Installing dependencies using your package manager build dependencies may
|
||||
miss out on deps that have been newly introduced in qemu.git. In more, it misses
|
||||
deps the distribution has decided to exclude.
|
||||
|
||||
Linux
|
||||
-----
|
||||
|
||||
Fedora
|
||||
++++++
|
||||
|
||||
::
|
||||
|
||||
sudo dnf update && sudo dnf builddep qemu
|
||||
|
||||
Debian/Ubuntu
|
||||
+++++++++++++
|
||||
|
||||
You first need to enable `Sources List <https://wiki.debian.org/SourcesList>`_.
|
||||
Then, use apt to install dependencies:
|
||||
|
||||
::
|
||||
|
||||
sudo apt update && sudo apt build-dep qemu
|
||||
|
||||
MacOS
|
||||
-----
|
||||
|
||||
You first need to install `Homebrew <https://brew.sh/>`_. Then, use it to
|
||||
install dependencies:
|
||||
|
||||
::
|
||||
|
||||
brew update && brew install $(brew deps --include-build qemu)
|
||||
|
||||
Windows
|
||||
-------
|
||||
|
||||
You first need to install `MSYS2 <https://www.msys2.org/>`_.
|
||||
MSYS2 offers `different environments <https://www.msys2.org/docs/environments/>`_.
|
||||
x86_64 environments are based on GCC, while aarch64 is based on Clang.
|
||||
|
||||
We recommend to use MINGW64 for windows-x86_64 and CLANGARM64 for windows-aarch64
|
||||
(only available on windows-aarch64 hosts).
|
||||
|
||||
Then, you can open a windows shell, and enter msys2 env using:
|
||||
|
||||
::
|
||||
|
||||
c:/msys64/msys2_shell.cmd -defterm -here -no-start -mingw64
|
||||
# Replace -ucrt64 by -clangarm64 or -ucrt64 for other environments.
|
||||
|
||||
MSYS2 package manager does not offer a built-in way to install build
|
||||
dependencies. You can start with this list of packages using pacman:
|
||||
|
||||
Note: Dependencies need to be installed again if you use a different MSYS2
|
||||
environment.
|
||||
|
||||
::
|
||||
|
||||
# update MSYS2 itself, you need to reopen your shell at the end.
|
||||
pacman -Syu
|
||||
pacman -S \
|
||||
base-devel binutils bison diffutils flex git grep make sed \
|
||||
${MINGW_PACKAGE_PREFIX}-toolchain \
|
||||
${MINGW_PACKAGE_PREFIX}-glib2 \
|
||||
${MINGW_PACKAGE_PREFIX}-gtk3 \
|
||||
${MINGW_PACKAGE_PREFIX}-libnfs \
|
||||
${MINGW_PACKAGE_PREFIX}-libssh \
|
||||
${MINGW_PACKAGE_PREFIX}-ninja \
|
||||
${MINGW_PACKAGE_PREFIX}-pixman \
|
||||
${MINGW_PACKAGE_PREFIX}-pkgconf \
|
||||
${MINGW_PACKAGE_PREFIX}-python \
|
||||
${MINGW_PACKAGE_PREFIX}-SDL2 \
|
||||
${MINGW_PACKAGE_PREFIX}-zstd
|
||||
|
||||
If you want to install all dependencies, it's possible to use recipe used to
|
||||
build QEMU in MSYS2 itself.
|
||||
|
||||
::
|
||||
|
||||
pacman -S wget
|
||||
wget https://raw.githubusercontent.com/msys2/MINGW-packages/refs/heads/master/mingw-w64-qemu/PKGBUILD
|
||||
# Some packages may be missing for your environment, installation will still
|
||||
# be done though.
|
||||
makepkg -s PKGBUILD || true
|
||||
|
||||
Build on windows-aarch64
|
||||
++++++++++++++++++++++++
|
||||
|
||||
When trying to cross compile meson for x86_64 using UCRT64 or MINGW64 env,
|
||||
configure will run into an error because the cpu detected is not correct.
|
||||
|
||||
Meson detects x86_64 processes emulated, so you need to manually set the cpu,
|
||||
and force a cross compilation (with empty prefix).
|
||||
|
||||
::
|
||||
|
||||
./configure --cpu=x86_64 --cross-prefix=
|
||||
|
220
docs/devel/codebase.rst
Normal file
220
docs/devel/codebase.rst
Normal file
@ -0,0 +1,220 @@
|
||||
========
|
||||
Codebase
|
||||
========
|
||||
|
||||
This section presents the various parts of QEMU and how the codebase is
|
||||
organized.
|
||||
|
||||
Beyond giving succint descriptions, the goal is to offer links to various
|
||||
parts of the documentation/codebase.
|
||||
|
||||
Subsystems
|
||||
----------
|
||||
|
||||
An exhaustive list of subsystems and associated files can be found in the
|
||||
`MAINTAINERS <https://gitlab.com/qemu-project/qemu/-/blob/master/MAINTAINERS>`_
|
||||
file.
|
||||
|
||||
Some of the main QEMU subsystems are:
|
||||
|
||||
- `Accelerators<Accelerators>`
|
||||
- Block devices and `disk images<disk images>` support
|
||||
- `CI<ci>` and `Tests<testing>`
|
||||
- `Devices<device-emulation>` & Board models
|
||||
- `Documentation <documentation-root>`
|
||||
- `GDB support<GDB usage>`
|
||||
- `Migration<migration>`
|
||||
- `Monitor<QEMU monitor>`
|
||||
- :ref:`QOM (QEMU Object Model)<qom>`
|
||||
- `System mode<System emulation>`
|
||||
- :ref:`TCG (Tiny Code Generator)<tcg>`
|
||||
- `User mode<user-mode>` (`Linux<linux-user-mode>` & `BSD<bsd-user-mode>`)
|
||||
- User Interfaces
|
||||
|
||||
More documentation on QEMU subsystems can be found on :ref:`internal-subsystem`
|
||||
page.
|
||||
|
||||
The Grand tour
|
||||
--------------
|
||||
|
||||
We present briefly here what every folder in the top directory of the codebase
|
||||
contains. Hop on!
|
||||
|
||||
The folder name links here will take you to that folder in our gitlab
|
||||
repository. Other links will take you to more detailed documentation for that
|
||||
subsystem, where we have it. Unfortunately not every subsystem has documentation
|
||||
yet, so sometimes the source code is all you have.
|
||||
|
||||
* `accel <https://gitlab.com/qemu-project/qemu/-/tree/master/accel>`_:
|
||||
Infrastructure and architecture agnostic code related to the various
|
||||
`accelerators <Accelerators>` supported by QEMU
|
||||
(TCG, KVM, hvf, whpx, xen, nvmm).
|
||||
Contains interfaces for operations that will be implemented per
|
||||
`target <https://gitlab.com/qemu-project/qemu/-/tree/master/target>`_.
|
||||
* `audio <https://gitlab.com/qemu-project/qemu/-/tree/master/audio>`_:
|
||||
Audio (host) support.
|
||||
* `authz <https://gitlab.com/qemu-project/qemu/-/tree/master/authz>`_:
|
||||
`QEMU Authorization framework<client authorization>`.
|
||||
* `backends <https://gitlab.com/qemu-project/qemu/-/tree/master/backends>`_:
|
||||
Various backends that are used to access resources on the host (e.g. for
|
||||
random number generation, memory backing or cryptographic functions).
|
||||
* `block <https://gitlab.com/qemu-project/qemu/-/tree/master/block>`_:
|
||||
Block devices and `image formats<disk images>` implementation.
|
||||
* `bsd-user <https://gitlab.com/qemu-project/qemu/-/tree/master/bsd-user>`_:
|
||||
`BSD User mode<bsd-user-mode>`.
|
||||
* build: Where the code built goes by default. You can tell the QEMU build
|
||||
system to put the built code anywhere else you like.
|
||||
* `chardev <https://gitlab.com/qemu-project/qemu/-/tree/master/chardev>`_:
|
||||
Various backends used by char devices.
|
||||
* `common-user <https://gitlab.com/qemu-project/qemu/-/tree/master/common-user>`_:
|
||||
User-mode assembly code for dealing with signals occuring during syscalls.
|
||||
* `configs <https://gitlab.com/qemu-project/qemu/-/tree/master/configs>`_:
|
||||
Makefiles defining configurations to build QEMU.
|
||||
* `contrib <https://gitlab.com/qemu-project/qemu/-/tree/master/contrib>`_:
|
||||
Community contributed devices/plugins/tools.
|
||||
* `crypto <https://gitlab.com/qemu-project/qemu/-/tree/master/crypto>`_:
|
||||
Cryptographic algorithms used in QEMU.
|
||||
* `disas <https://gitlab.com/qemu-project/qemu/-/tree/master/disas>`_:
|
||||
Disassembly functions used by QEMU target code.
|
||||
* `docs <https://gitlab.com/qemu-project/qemu/-/tree/master/docs>`_:
|
||||
QEMU Documentation.
|
||||
* `dump <https://gitlab.com/qemu-project/qemu/-/tree/master/dump>`_:
|
||||
Code to dump memory of a running VM.
|
||||
* `ebpf <https://gitlab.com/qemu-project/qemu/-/tree/master/ebpf>`_:
|
||||
eBPF program support in QEMU. `virtio-net RSS<ebpf-rss>` uses it.
|
||||
* `fpu <https://gitlab.com/qemu-project/qemu/-/tree/master/fpu>`_:
|
||||
Floating-point software emulation.
|
||||
* `fsdev <https://gitlab.com/qemu-project/qemu/-/tree/master/fsdev>`_:
|
||||
`VirtFS <https://www.linux-kvm.org/page/VirtFS>`_ support.
|
||||
* `gdbstub <https://gitlab.com/qemu-project/qemu/-/tree/master/gdbstub>`_:
|
||||
`GDB <GDB usage>` support.
|
||||
* `gdb-xml <https://gitlab.com/qemu-project/qemu/-/tree/master/gdb-xml>`_:
|
||||
Set of XML files describing architectures and used by `gdbstub <GDB usage>`.
|
||||
* `host <https://gitlab.com/qemu-project/qemu/-/tree/master/host>`_:
|
||||
Various architecture specific header files (crypto, atomic, memory
|
||||
operations).
|
||||
* `linux-headers <https://gitlab.com/qemu-project/qemu/-/tree/master/linux-headers>`_:
|
||||
A subset of headers imported from Linux kernel and used for implementing
|
||||
KVM support and user-mode.
|
||||
* `linux-user <https://gitlab.com/qemu-project/qemu/-/tree/master/linux-user>`_:
|
||||
`User mode <user-mode>` implementation. Contains one folder per target
|
||||
architecture.
|
||||
* `.gitlab-ci.d <https://gitlab.com/qemu-project/qemu/-/tree/master/.gitlab-ci.d>`_:
|
||||
`CI <ci>` yaml and scripts.
|
||||
* `include <https://gitlab.com/qemu-project/qemu/-/tree/master/include>`_:
|
||||
All headers associated to different subsystems in QEMU. The hierachy used
|
||||
mirrors source code organization and naming.
|
||||
* `hw <https://gitlab.com/qemu-project/qemu/-/tree/master/hw>`_:
|
||||
`Devices <device-emulation>` and boards emulation. Devices are categorized by
|
||||
type/protocol/architecture and located in associated subfolder.
|
||||
* `io <https://gitlab.com/qemu-project/qemu/-/tree/master/io>`_:
|
||||
QEMU `I/O channels <https://lists.gnu.org/archive/html/qemu-devel/2015-11/msg04208.html>`_.
|
||||
* `libdecnumber <https://gitlab.com/qemu-project/qemu/-/tree/master/libdecnumber>`_:
|
||||
Import of gcc library, used to implement decimal number arithmetic.
|
||||
* `migration <https://gitlab.com/qemu-project/qemu/-/tree/master/migration>`__:
|
||||
`Migration framework <migration>`.
|
||||
* `monitor <https://gitlab.com/qemu-project/qemu/-/tree/master/monitor>`_:
|
||||
`Monitor <QEMU monitor>` implementation (HMP & QMP).
|
||||
* `nbd <https://gitlab.com/qemu-project/qemu/-/tree/master/nbd>`_:
|
||||
QEMU `NBD (Network Block Device) <nbd>` server.
|
||||
* `net <https://gitlab.com/qemu-project/qemu/-/tree/master/net>`_:
|
||||
Network (host) support.
|
||||
* `pc-bios <https://gitlab.com/qemu-project/qemu/-/tree/master/pc-bios>`_:
|
||||
Contains pre-built firmware binaries and boot images, ready to use in
|
||||
QEMU without compilation.
|
||||
* `plugins <https://gitlab.com/qemu-project/qemu/-/tree/master/plugins>`_:
|
||||
:ref:`TCG plugins <tcg-plugins>` core implementation. Plugins can be found in
|
||||
`tests <https://gitlab.com/qemu-project/qemu/-/tree/master/tests/tcg/plugins>`__
|
||||
and `contrib <https://gitlab.com/qemu-project/qemu/-/tree/master/contrib/plugins>`__
|
||||
folders.
|
||||
* `po <https://gitlab.com/qemu-project/qemu/-/tree/master/po>`_:
|
||||
Translation files.
|
||||
* `python <https://gitlab.com/qemu-project/qemu/-/tree/master/python>`_:
|
||||
Python part of our build/test system.
|
||||
* `qapi <https://gitlab.com/qemu-project/qemu/-/tree/master/qapi>`_:
|
||||
`QAPI <qapi>` implementation.
|
||||
* `qobject <https://gitlab.com/qemu-project/qemu/-/tree/master/qobject>`_:
|
||||
QEMU Object implementation.
|
||||
* `qga <https://gitlab.com/qemu-project/qemu/-/tree/master/qga>`_:
|
||||
QEMU `Guest agent <qemu-ga>` implementation.
|
||||
* `qom <https://gitlab.com/qemu-project/qemu/-/tree/master/qom>`_:
|
||||
QEMU :ref:`Object model <qom>` implementation, with monitor associated commands.
|
||||
* `replay <https://gitlab.com/qemu-project/qemu/-/tree/master/replay>`_:
|
||||
QEMU :ref:`Record/replay <replay>` implementation.
|
||||
* `roms <https://gitlab.com/qemu-project/qemu/-/tree/master/roms>`_:
|
||||
Contains source code for various firmware and ROMs, which can be compiled if
|
||||
custom or updated versions are needed.
|
||||
* `rust <https://gitlab.com/qemu-project/qemu/-/tree/master/rust>`_:
|
||||
Rust integration in QEMU. It contains the new interfaces defined and
|
||||
associated devices using it.
|
||||
* `scripts <https://gitlab.com/qemu-project/qemu/-/tree/master/scripts>`_:
|
||||
Collection of scripts used in build and test systems, and various
|
||||
tools for QEMU codebase and execution traces.
|
||||
* `scsi <https://gitlab.com/qemu-project/qemu/-/tree/master/scsi>`_:
|
||||
Code related to SCSI support, used by SCSI devices.
|
||||
* `semihosting <https://gitlab.com/qemu-project/qemu/-/tree/master/semihosting>`_:
|
||||
QEMU `Semihosting <Semihosting>` implementation.
|
||||
* `stats <https://gitlab.com/qemu-project/qemu/-/tree/master/stats>`_:
|
||||
`Monitor <QEMU monitor>` stats commands implementation.
|
||||
* `storage-daemon <https://gitlab.com/qemu-project/qemu/-/tree/master/storage-daemon>`_:
|
||||
QEMU `Storage daemon <storage-daemon>` implementation.
|
||||
* `stubs <https://gitlab.com/qemu-project/qemu/-/tree/master/stubs>`_:
|
||||
Various stubs (empty functions) used to compile QEMU with specific
|
||||
configurations.
|
||||
* `subprojects <https://gitlab.com/qemu-project/qemu/-/tree/master/subprojects>`_:
|
||||
QEMU submodules used by QEMU build system.
|
||||
* `system <https://gitlab.com/qemu-project/qemu/-/tree/master/system>`_:
|
||||
QEMU `system mode <System emulation>` implementation (cpu, mmu, boot support).
|
||||
* `target <https://gitlab.com/qemu-project/qemu/-/tree/master/target>`_:
|
||||
Contains code for all target architectures supported (one subfolder
|
||||
per arch). For every architecture, you can find accelerator specific
|
||||
implementations.
|
||||
* `tcg <https://gitlab.com/qemu-project/qemu/-/tree/master/tcg>`_:
|
||||
:ref:`TCG <tcg>` related code.
|
||||
Contains one subfolder per host supported architecture.
|
||||
* `tests <https://gitlab.com/qemu-project/qemu/-/tree/master/tests>`_:
|
||||
QEMU `test <testing>` suite
|
||||
|
||||
- `avocado <https://gitlab.com/qemu-project/qemu/-/tree/master/tests/avocado>`_:
|
||||
Functional tests booting full VM using `Avocado framework <checkavocado-ref>`.
|
||||
Those tests will be transformed and moved into
|
||||
`tests/functional <https://gitlab.com/qemu-project/qemu/-/tree/master/tests/functional>`_
|
||||
in the future.
|
||||
- `data <https://gitlab.com/qemu-project/qemu/-/tree/master/tests/data>`_:
|
||||
Data for various tests.
|
||||
- `decode <https://gitlab.com/qemu-project/qemu/-/tree/master/tests/decode>`_:
|
||||
Testsuite for :ref:`decodetree <decodetree>` implementation.
|
||||
- `docker <https://gitlab.com/qemu-project/qemu/-/tree/master/tests/docker>`_:
|
||||
Code and scripts to create `containers <container-ref>` used in `CI <ci>`.
|
||||
- `fp <https://gitlab.com/qemu-project/qemu/-/tree/master/tests/fp>`_:
|
||||
QEMU testsuite for soft float implementation.
|
||||
- `functional <https://gitlab.com/qemu-project/qemu/-/tree/master/tests/functional>`_:
|
||||
`Functional tests <checkfunctional-ref>` (full VM boot).
|
||||
- `lcitool <https://gitlab.com/qemu-project/qemu/-/tree/master/tests/lcitool>`_:
|
||||
Generate dockerfiles for CI containers.
|
||||
- `migration <https://gitlab.com/qemu-project/qemu/-/tree/master/tests/migration>`_:
|
||||
Test scripts and data for `Migration framework <migration>`.
|
||||
- `multiboot <https://gitlab.com/qemu-project/qemu/-/tree/master/tests/multiboot>`_:
|
||||
Test multiboot functionality for x86_64/i386.
|
||||
- `qapi-schema <https://gitlab.com/qemu-project/qemu/-/tree/master/tests/qapi-schema>`_:
|
||||
Test scripts and data for `QAPI <qapi-tests>`.
|
||||
- `qemu-iotests <https://gitlab.com/qemu-project/qemu/-/tree/master/tests/qemu-iotests>`_:
|
||||
`Disk image and block tests <qemu-iotests>`.
|
||||
- `qtest <https://gitlab.com/qemu-project/qemu/-/tree/master/tests/qtest>`_:
|
||||
`Device emulation testing <qtest>`.
|
||||
- `tcg <https://gitlab.com/qemu-project/qemu/-/tree/master/tests/tcg>`__:
|
||||
`TCG related tests <checktcg-ref>`. Contains code per architecture
|
||||
(subfolder) and multiarch tests as well.
|
||||
- `tsan <https://gitlab.com/qemu-project/qemu/-/tree/master/tests/tsan>`_:
|
||||
`Suppressions <tsan-suppressions>` for thread sanitizer.
|
||||
- `uefi-test-tools <https://gitlab.com/qemu-project/qemu/-/tree/master/tests/uefi-test-tools>`_:
|
||||
Test tool for UEFI support.
|
||||
- `unit <https://gitlab.com/qemu-project/qemu/-/tree/master/tests/unit>`_:
|
||||
QEMU `Unit tests <unit-tests>`.
|
||||
* `trace <https://gitlab.com/qemu-project/qemu/-/tree/master/trace>`_:
|
||||
:ref:`Tracing framework <tracing>`. Used to print information associated to various
|
||||
events during execution.
|
||||
* `ui <https://gitlab.com/qemu-project/qemu/-/tree/master/ui>`_:
|
||||
QEMU User interfaces.
|
||||
* `util <https://gitlab.com/qemu-project/qemu/-/tree/master/util>`_:
|
||||
Utility code used by other parts of QEMU.
|
@ -1,3 +1,5 @@
|
||||
.. _cfi:
|
||||
|
||||
============================
|
||||
Control-Flow Integrity (CFI)
|
||||
============================
|
||||
|
@ -1,3 +1,5 @@
|
||||
.. _decodetree:
|
||||
|
||||
========================
|
||||
Decodetree Specification
|
||||
========================
|
||||
|
@ -1,3 +1,5 @@
|
||||
.. _ebpf-rss:
|
||||
|
||||
===========================
|
||||
eBPF RSS virtio-net support
|
||||
===========================
|
||||
|
@ -8,6 +8,7 @@ some of the basics if you are adding new files and targets to the build.
|
||||
:maxdepth: 3
|
||||
|
||||
build-system
|
||||
build-environment
|
||||
kconfig
|
||||
docs
|
||||
qapi-code-gen
|
||||
|
@ -1,3 +1,5 @@
|
||||
.. _internal-subsystem:
|
||||
|
||||
Internal Subsystem Information
|
||||
------------------------------
|
||||
|
||||
|
@ -35,3 +35,4 @@ the :ref:`tcg_internals`.
|
||||
index-api
|
||||
index-internals
|
||||
index-tcg
|
||||
codebase
|
||||
|
@ -1,3 +1,5 @@
|
||||
.. _migration:
|
||||
|
||||
===================
|
||||
Migration framework
|
||||
===================
|
||||
|
@ -4,6 +4,8 @@
|
||||
This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
later. See the COPYING file in the top-level directory.
|
||||
|
||||
.. _mttcg:
|
||||
|
||||
==================
|
||||
Multi-threaded TCG
|
||||
==================
|
||||
|
@ -9,6 +9,7 @@ How to use the QAPI code generator
|
||||
This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
later. See the COPYING file in the top-level directory.
|
||||
|
||||
.. _qapi:
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
@ -416,6 +416,26 @@ definitions instead of typedefs in headers and function prototypes; this
|
||||
avoids problems with duplicated typedefs and reduces the need to include
|
||||
headers from other headers.
|
||||
|
||||
Bitfields
|
||||
---------
|
||||
|
||||
C bitfields can be a cause of non-portability issues, especially under windows
|
||||
where `MSVC has a different way to lay them out than GCC
|
||||
<https://gcc.gnu.org/onlinedocs/gcc/x86-Type-Attributes.html>`_, or where
|
||||
endianness matters.
|
||||
|
||||
For this reason, we disallow usage of bitfields in packed structures and in any
|
||||
structures which are supposed to exactly match a specific layout in guest
|
||||
memory. Some existing code may use it, and we carefully ensured the layout was
|
||||
the one expected.
|
||||
|
||||
We also suggest avoiding bitfields even in structures where the exact
|
||||
layout does not matter, unless you can show that they provide a significant
|
||||
usability benefit.
|
||||
|
||||
We encourage the usage of ``include/hw/registerfields.h`` as a safe replacement
|
||||
for bitfields.
|
||||
|
||||
Reserved namespaces in C and POSIX
|
||||
----------------------------------
|
||||
|
||||
|
@ -235,6 +235,31 @@ to another list.) ``git send-email`` (`step-by-step setup guide
|
||||
works best for delivering the patch without mangling it, but
|
||||
attachments can be used as a last resort on a first-time submission.
|
||||
|
||||
.. _use_git_publish:
|
||||
|
||||
Use git-publish
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
If you already configured git send-email, you can simply use `git-publish
|
||||
<https://github.com/stefanha/git-publish>`__ to send series.
|
||||
|
||||
::
|
||||
|
||||
$ git checkout master -b my-feature
|
||||
$ # work on new commits, add your 'Signed-off-by' lines to each
|
||||
$ git publish
|
||||
$ ... more work, rebase on master, ...
|
||||
$ git publish # will send a v2
|
||||
|
||||
Each time you post a series, git-publish will create a local tag with the format
|
||||
``<branchname>-v<version>`` to record the patch series.
|
||||
|
||||
When sending patch emails, 'git publish' will consult the output of
|
||||
'scripts/get_maintainers.pl' and automatically CC anyone listed as maintainers
|
||||
of the affected code. Generally you should accept the suggested CC list, but
|
||||
there may sometimes be scenarios where it is appropriate to cut it down (eg on
|
||||
certain large tree-wide cleanups), or augment it with other interested people.
|
||||
|
||||
.. _if_you_cannot_send_patch_emails:
|
||||
|
||||
If you cannot send patch emails
|
||||
@ -408,6 +433,20 @@ For more details on how QEMU's stable process works, refer to the
|
||||
|
||||
.. _participating_in_code_review:
|
||||
|
||||
Retrieve an existing series
|
||||
---------------------------
|
||||
|
||||
If you want to apply an existing series on top of your tree, you can simply use
|
||||
`b4 <https://github.com/mricon/b4>`__.
|
||||
|
||||
::
|
||||
|
||||
b4 shazam $msg-id
|
||||
|
||||
The message id is related to the patch series that has been sent to the mailing
|
||||
list. You need to retrieve the "Message-Id:" header from one of the patches. Any
|
||||
of them can be used and b4 will apply the whole series.
|
||||
|
||||
Participating in Code Review
|
||||
----------------------------
|
||||
|
||||
|
@ -39,6 +39,8 @@ Before running tests, it is best to build QEMU programs first. Some tests
|
||||
expect the executables to exist and will fail with obscure messages if they
|
||||
cannot find them.
|
||||
|
||||
.. _unit-tests:
|
||||
|
||||
Unit tests
|
||||
~~~~~~~~~~
|
||||
|
||||
@ -126,6 +128,8 @@ successfully on various hosts. The following list shows some best practices:
|
||||
#ifdef in the codes. If the whole test suite cannot run on Windows, disable
|
||||
the build in the meson.build file.
|
||||
|
||||
.. _qapi-tests:
|
||||
|
||||
QAPI schema tests
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -160,6 +164,8 @@ check-block
|
||||
are in the "auto" group).
|
||||
See the "QEMU iotests" section below for more information.
|
||||
|
||||
.. _qemu-iotests:
|
||||
|
||||
QEMU iotests
|
||||
------------
|
||||
|
||||
@ -679,6 +685,8 @@ The above exitcode=0 has TSan continue without error if any warnings are found.
|
||||
This allows for running the test and then checking the warnings afterwards.
|
||||
If you want TSan to stop and exit with error on warnings, use exitcode=66.
|
||||
|
||||
.. _tsan-suppressions:
|
||||
|
||||
TSan Suppressions
|
||||
~~~~~~~~~~~~~~~~~
|
||||
Keep in mind that for any data race warning, although there might be a data race
|
||||
@ -901,7 +909,6 @@ You can run the avocado tests simply by executing:
|
||||
|
||||
See :ref:`checkavocado-ref` for more details.
|
||||
|
||||
|
||||
.. _checktcg-ref:
|
||||
|
||||
Testing with "make check-tcg"
|
||||
|
@ -1,3 +1,5 @@
|
||||
.. _qtest:
|
||||
|
||||
========================================
|
||||
QTest Device Emulation Testing Framework
|
||||
========================================
|
||||
|
280
docs/glossary.rst
Normal file
280
docs/glossary.rst
Normal file
@ -0,0 +1,280 @@
|
||||
.. _Glossary:
|
||||
|
||||
--------
|
||||
Glossary
|
||||
--------
|
||||
|
||||
This section of the manual presents brief definitions of acronyms and terms used
|
||||
by QEMU developers.
|
||||
|
||||
Accelerator
|
||||
-----------
|
||||
|
||||
A specific API used to accelerate execution of guest instructions. It can be
|
||||
hardware-based, through a virtualization API provided by the host OS (kvm, hvf,
|
||||
whpx, ...), or software-based (tcg). See this description of `supported
|
||||
accelerators<Accelerators>`.
|
||||
|
||||
Board
|
||||
-----
|
||||
|
||||
Another name for :ref:`machine`.
|
||||
|
||||
Block
|
||||
-----
|
||||
|
||||
Block drivers are the available `disk formats and front-ends
|
||||
<block-drivers>` available, and block devices `(see Block device section on
|
||||
options page)<sec_005finvocation>` are using them to implement disks for a
|
||||
virtual machine.
|
||||
|
||||
CFI
|
||||
---
|
||||
|
||||
Control Flow Integrity is a hardening technique used to prevent exploits
|
||||
targeting QEMU by detecting unexpected branches during execution. QEMU `actively
|
||||
supports<cfi>` being compiled with CFI enabled.
|
||||
|
||||
Device
|
||||
------
|
||||
|
||||
In QEMU, a device is a piece of hardware visible to the guest. Examples include
|
||||
UARTs, PCI controllers, PCI cards, VGA controllers, and many more.
|
||||
|
||||
QEMU is able to emulate a CPU, and all the hardware interacting with it,
|
||||
including `many devices<device-emulation>`. When QEMU runs a virtual machine
|
||||
using a hardware-based accelerator, it is responsible for emulating, using
|
||||
software, all devices.
|
||||
|
||||
EDK2
|
||||
----
|
||||
|
||||
EDK2, as known as `TianoCore <https://www.tianocore.org/>`_, is an open source
|
||||
implementation of UEFI standard. QEMU virtual machines that boot a UEFI firmware
|
||||
usually use EDK2.
|
||||
|
||||
gdbstub
|
||||
-------
|
||||
|
||||
QEMU implements a `gdb server <GDB usage>`, allowing gdb to attach to it and
|
||||
debug a running virtual machine, or a program in user-mode. This allows
|
||||
debugging the guest code that is running inside QEMU.
|
||||
|
||||
glib2
|
||||
-----
|
||||
|
||||
`GLib2 <https://docs.gtk.org/glib/>`_ is one of the most important libraries we
|
||||
are using through the codebase. It provides many data structures, macros, string
|
||||
and thread utilities and portable functions across different OS. It's required
|
||||
to build QEMU.
|
||||
|
||||
Guest agent
|
||||
-----------
|
||||
|
||||
The `QEMU Guest Agent <qemu-ga>` is a daemon intended to be run within virtual
|
||||
machines. It provides various services to help QEMU to interact with it.
|
||||
|
||||
.. _guest:
|
||||
|
||||
Guest
|
||||
-----
|
||||
|
||||
Guest is the architecture of the virtual machine, which is emulated.
|
||||
See also :ref:`host`.
|
||||
|
||||
Sometimes this is called the :ref:`target` architecture, but that term
|
||||
can be ambiguous.
|
||||
|
||||
.. _host:
|
||||
|
||||
Host
|
||||
----
|
||||
|
||||
Host is the architecture on which QEMU is running on, which is native.
|
||||
See also :ref:`guest`.
|
||||
|
||||
Hypervisor
|
||||
----------
|
||||
|
||||
The formal definition of an hypervisor is a program or API than can be used to
|
||||
manage a virtual machine. QEMU is a virtualizer, that interacts with various
|
||||
hypervisors.
|
||||
|
||||
In the context of QEMU, an hypervisor is an API, provided by the Host OS,
|
||||
allowing to execute virtual machines. Linux implementation is KVM (and supports
|
||||
Xen as well). For MacOS, it's HVF. Windows defines WHPX. And NetBSD provides
|
||||
NVMM.
|
||||
|
||||
.. _machine:
|
||||
|
||||
Machine
|
||||
-------
|
||||
|
||||
QEMU's system emulation models many different types of hardware. A machine model
|
||||
(sometimes called a board model) is the model of a complete virtual system with
|
||||
RAM, one or more CPUs, and various devices. It can be selected with the option
|
||||
``-machine`` of qemu-system. Our machine models can be found on this `page
|
||||
<system-targets-ref>`.
|
||||
|
||||
Migration
|
||||
---------
|
||||
|
||||
QEMU can save and restore the execution of a virtual machine between different
|
||||
host systems. This is provided by the `Migration framework<migration>`.
|
||||
|
||||
NBD
|
||||
---
|
||||
|
||||
The `QEMU Network Block Device server <qemu-nbd>` is a tool that can be used to
|
||||
mount and access QEMU images, providing functionality similar to a loop device.
|
||||
|
||||
Mailing List
|
||||
------------
|
||||
|
||||
This is `where <https://wiki.qemu.org/Contribute/MailingLists>`_ all the
|
||||
development happens! Changes are posted as series, that all developers can
|
||||
review and share feedback for.
|
||||
|
||||
For reporting issues, our `GitLab
|
||||
<https://gitlab.com/qemu-project/qemu/-/issues>`_ tracker is the best place.
|
||||
|
||||
.. _softmmu:
|
||||
|
||||
MMU / softmmu
|
||||
-------------
|
||||
|
||||
The Memory Management Unit is responsible for translating virtual addresses to
|
||||
physical addresses and managing memory protection. QEMU system mode is named
|
||||
"softmmu" precisely because it implements this in software, including a TLB
|
||||
(Translation lookaside buffer), for the guest virtual machine.
|
||||
|
||||
QEMU user-mode does not implement a full software MMU, but "simply" translates
|
||||
virtual addresses by adding a specific offset, and relying on host MMU/OS
|
||||
instead.
|
||||
|
||||
Monitor / QMP / HMP
|
||||
-------------------
|
||||
|
||||
The `QEMU Monitor <QEMU monitor>` is a text interface which can be used to interact
|
||||
with a running virtual machine.
|
||||
|
||||
QMP stands for QEMU Monitor Protocol and is a json based interface.
|
||||
HMP stands for Human Monitor Protocol and is a set of text commands available
|
||||
for users who prefer natural language to json.
|
||||
|
||||
MTTCG
|
||||
-----
|
||||
|
||||
Multiple CPU support was first implemented using a round-robin algorithm
|
||||
running on a single thread. Later on, `Multi-threaded TCG <mttcg>` was developed
|
||||
to benefit from multiple cores to speed up execution.
|
||||
|
||||
Plugins
|
||||
-------
|
||||
|
||||
`TCG Plugins <TCG Plugins>` is an API used to instrument guest code, in system
|
||||
and user mode. The end goal is to have a similar set of functionality compared
|
||||
to `DynamoRIO <https://dynamorio.org/>`_ or `valgrind <https://valgrind.org/>`_.
|
||||
|
||||
One key advantage of QEMU plugins is that they can be used to perform
|
||||
architecture agnostic instrumentation.
|
||||
|
||||
Patchew
|
||||
-------
|
||||
|
||||
`Patchew <https://patchew.org/QEMU/>`_ is a website that tracks patches on the
|
||||
Mailing List.
|
||||
|
||||
PR
|
||||
--
|
||||
|
||||
Once a series is reviewed and accepted by a subsystem maintainer, it will be
|
||||
included in a PR (Pull Request) that the project maintainer will merge into QEMU
|
||||
main branch, after running tests.
|
||||
|
||||
The QEMU project doesn't currently expect most developers to directly submit
|
||||
pull requests.
|
||||
|
||||
QCOW2
|
||||
-----
|
||||
|
||||
QEMU Copy On Write is a disk format developed by QEMU. It provides transparent
|
||||
compression, automatic extension, and many other advantages over a raw image.
|
||||
|
||||
qcow2 is the recommended format to use.
|
||||
|
||||
QEMU
|
||||
----
|
||||
|
||||
`QEMU (Quick Emulator) <https://www.qemu.org/>`_ is a generic and open source
|
||||
machine emulator and virtualizer.
|
||||
|
||||
QOM
|
||||
---
|
||||
|
||||
`QEMU Object Model <qom>` is an object oriented API used to define various
|
||||
devices and hardware in the QEMU codebase.
|
||||
|
||||
Record/replay
|
||||
-------------
|
||||
|
||||
`Record/replay <replay>` is a feature of QEMU allowing to have a deterministic
|
||||
and reproducible execution of a virtual machine.
|
||||
|
||||
Rust
|
||||
----
|
||||
|
||||
`A new programming language <https://www.rust-lang.org/>`_, memory safe by
|
||||
default. There is a work in progress to integrate it in QEMU codebase for
|
||||
various subsystems.
|
||||
|
||||
System mode
|
||||
-----------
|
||||
|
||||
QEMU System mode provides a virtual model of an entire machine (CPU, memory and
|
||||
emulated devices) to run a guest OS. In this mode the CPU may be fully emulated,
|
||||
or it may work with a hypervisor such as KVM, Xen or Hypervisor.Framework to
|
||||
allow the guest to run directly on the host CPU.
|
||||
|
||||
QEMU System mode is called :ref:`softmmu <softmmu>` as well.
|
||||
|
||||
.. _target:
|
||||
|
||||
Target
|
||||
------
|
||||
|
||||
The term "target" can be ambiguous. In most places in QEMU it is used as a
|
||||
synonym for :ref:`guest`. For example the code for emulating Arm CPUs is in
|
||||
``target/arm/``. However in the :ref:`TCG subsystem <tcg>` "target" refers to the
|
||||
architecture which QEMU is running on, i.e. the :ref:`host`.
|
||||
|
||||
TCG
|
||||
---
|
||||
|
||||
TCG is the QEMU `Tiny Code Generator <tcg>`. It is the JIT (just-in-time)
|
||||
compiler we use to emulate a guest CPU in software.
|
||||
|
||||
It is one of the accelerators supported by QEMU, and supports a lot of
|
||||
guest/host architectures.
|
||||
|
||||
User mode
|
||||
---------
|
||||
|
||||
QEMU User mode can launch processes compiled for one CPU on another CPU. In this
|
||||
mode the CPU is always emulated. In this mode, QEMU translate system calls from
|
||||
guest to host kernel. It is available for Linux and BSD.
|
||||
|
||||
VirtIO
|
||||
------
|
||||
|
||||
VirtIO is an open standard used to define and implement virtual devices with a
|
||||
minimal overhead, defining a set of data structures and hypercalls (similar to
|
||||
system calls, but targeting an hypervisor, which happens to be QEMU in our
|
||||
case). It's designed to be more efficient than emulating a real device, by
|
||||
minimizing the amount of interactions between a guest VM and its hypervisor.
|
||||
|
||||
vhost-user
|
||||
----------
|
||||
|
||||
`Vhost-user <vhost_user>` is an interface used to implement VirtIO devices
|
||||
outside of QEMU itself.
|
@ -3,6 +3,8 @@
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
.. _documentation-root:
|
||||
|
||||
================================
|
||||
Welcome to QEMU's documentation!
|
||||
================================
|
||||
@ -18,3 +20,4 @@ Welcome to QEMU's documentation!
|
||||
interop/index
|
||||
specs/index
|
||||
devel/index
|
||||
glossary
|
||||
|
@ -1,3 +1,5 @@
|
||||
.. _qemu-ga:
|
||||
|
||||
QEMU Guest Agent
|
||||
================
|
||||
|
||||
|
@ -31,6 +31,9 @@ def get_infiles(env):
|
||||
for path in Path(static_path).rglob('*'):
|
||||
yield str(path)
|
||||
|
||||
# also include kdoc script
|
||||
yield str(env.config.kerneldoc_bin[1])
|
||||
|
||||
|
||||
def write_depfile(app, exception):
|
||||
if exception:
|
||||
|
@ -1,3 +1,5 @@
|
||||
.. _arm-virt:
|
||||
|
||||
'virt' generic virtual platform (``virt``)
|
||||
==========================================
|
||||
|
||||
|
@ -82,4 +82,6 @@ VM snapshots currently have the following known limitations:
|
||||
- A few device drivers still have incomplete snapshot support so their
|
||||
state is not saved or restored properly (in particular USB).
|
||||
|
||||
.. _block-drivers:
|
||||
|
||||
.. include:: qemu-block-drivers.rst.inc
|
||||
|
@ -500,6 +500,8 @@ What you should *never* do:
|
||||
- expect it to work when loadvm'ing
|
||||
- write to the FAT directory on the host system while accessing it with the guest system
|
||||
|
||||
.. _nbd:
|
||||
|
||||
NBD access
|
||||
~~~~~~~~~~
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
.. _qemu-nbd:
|
||||
|
||||
=====================================
|
||||
QEMU Disk Network Block Device Server
|
||||
=====================================
|
||||
|
@ -1,3 +1,5 @@
|
||||
.. _storage-daemon:
|
||||
|
||||
===================
|
||||
QEMU Storage Daemon
|
||||
===================
|
||||
|
@ -1,3 +1,5 @@
|
||||
.. _user-mode:
|
||||
|
||||
QEMU User space emulator
|
||||
========================
|
||||
|
||||
@ -42,6 +44,8 @@ QEMU was conceived so that ultimately it can emulate itself. Although it
|
||||
is not very useful, it is an important test to show the power of the
|
||||
emulator.
|
||||
|
||||
.. _linux-user-mode:
|
||||
|
||||
Linux User space emulator
|
||||
-------------------------
|
||||
|
||||
@ -175,6 +179,8 @@ Other binaries
|
||||
* ``qemu-sparc64`` can execute some Sparc64 (Sparc64 CPU, 64 bit ABI) and
|
||||
SPARC32PLUS binaries (Sparc64 CPU, 32 bit ABI).
|
||||
|
||||
.. _bsd-user-mode:
|
||||
|
||||
BSD User space emulator
|
||||
-----------------------
|
||||
|
||||
|
@ -330,26 +330,27 @@ static void create_processes(GDBState *s)
|
||||
gdb_create_default_process(s);
|
||||
}
|
||||
|
||||
int gdbserver_start(const char *device)
|
||||
bool gdbserver_start(const char *device, Error **errp)
|
||||
{
|
||||
Chardev *chr = NULL;
|
||||
Chardev *mon_chr;
|
||||
g_autoptr(GString) cs = g_string_new(device);
|
||||
|
||||
if (!first_cpu) {
|
||||
error_report("gdbstub: meaningless to attach gdb to a "
|
||||
"machine without any CPU.");
|
||||
return -1;
|
||||
error_setg(errp, "gdbstub: meaningless to attach gdb to a "
|
||||
"machine without any CPU.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!gdb_supports_guest_debug()) {
|
||||
error_report("gdbstub: current accelerator doesn't "
|
||||
"support guest debugging");
|
||||
return -1;
|
||||
error_setg(errp, "gdbstub: current accelerator doesn't "
|
||||
"support guest debugging");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cs->len == 0) {
|
||||
return -1;
|
||||
error_setg(errp, "gdbstub: missing connection string");
|
||||
return false;
|
||||
}
|
||||
|
||||
trace_gdbstub_op_start(cs->str);
|
||||
@ -374,7 +375,8 @@ int gdbserver_start(const char *device)
|
||||
*/
|
||||
chr = qemu_chr_new_noreplay("gdb", cs->str, true, NULL);
|
||||
if (!chr) {
|
||||
return -1;
|
||||
error_setg(errp, "gdbstub: couldn't create chardev");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -406,7 +408,7 @@ int gdbserver_start(const char *device)
|
||||
gdbserver_system_state.mon_chr = mon_chr;
|
||||
gdb_syscall_reset();
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void register_types(void)
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "qemu/bitops.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/sockets.h"
|
||||
#include "qapi/error.h"
|
||||
#include "exec/hwaddr.h"
|
||||
#include "exec/tb-flush.h"
|
||||
#include "exec/gdbstub.h"
|
||||
@ -372,14 +373,14 @@ static bool gdb_accept_tcp(int gdb_fd)
|
||||
return true;
|
||||
}
|
||||
|
||||
static int gdbserver_open_port(int port)
|
||||
static int gdbserver_open_port(int port, Error **errp)
|
||||
{
|
||||
struct sockaddr_in sockaddr;
|
||||
int fd, ret;
|
||||
|
||||
fd = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
perror("socket");
|
||||
error_setg_errno(errp, errno, "Failed to create socket");
|
||||
return -1;
|
||||
}
|
||||
qemu_set_cloexec(fd);
|
||||
@ -391,13 +392,13 @@ static int gdbserver_open_port(int port)
|
||||
sockaddr.sin_addr.s_addr = 0;
|
||||
ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
|
||||
if (ret < 0) {
|
||||
perror("bind");
|
||||
error_setg_errno(errp, errno, "Failed to bind socket");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
ret = listen(fd, 1);
|
||||
if (ret < 0) {
|
||||
perror("listen");
|
||||
error_setg_errno(errp, errno, "Failed to listen to socket");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
@ -405,31 +406,32 @@ static int gdbserver_open_port(int port)
|
||||
return fd;
|
||||
}
|
||||
|
||||
int gdbserver_start(const char *port_or_path)
|
||||
bool gdbserver_start(const char *port_or_path, Error **errp)
|
||||
{
|
||||
int port = g_ascii_strtoull(port_or_path, NULL, 10);
|
||||
int gdb_fd;
|
||||
|
||||
if (port > 0) {
|
||||
gdb_fd = gdbserver_open_port(port);
|
||||
gdb_fd = gdbserver_open_port(port, errp);
|
||||
} else {
|
||||
gdb_fd = gdbserver_open_socket(port_or_path);
|
||||
}
|
||||
|
||||
if (gdb_fd < 0) {
|
||||
return -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (port > 0 && gdb_accept_tcp(gdb_fd)) {
|
||||
return 0;
|
||||
return true;
|
||||
} else if (gdb_accept_socket(gdb_fd)) {
|
||||
gdbserver_user_state.socket_path = g_strdup(port_or_path);
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* gone wrong */
|
||||
close(gdb_fd);
|
||||
return -1;
|
||||
error_setg(errp, "gdbstub: failed to accept connection");
|
||||
return false;
|
||||
}
|
||||
|
||||
void gdbserver_fork_start(void)
|
||||
|
@ -49,12 +49,18 @@ void gdb_unregister_coprocessor_all(CPUState *cpu);
|
||||
/**
|
||||
* gdbserver_start: start the gdb server
|
||||
* @port_or_device: connection spec for gdb
|
||||
* @errp: error handle
|
||||
*
|
||||
* For CONFIG_USER this is either a tcp port or a path to a fifo. For
|
||||
* system emulation you can use a full chardev spec for your gdbserver
|
||||
* port.
|
||||
*
|
||||
* The error handle should be either &error_fatal (for start-up) or
|
||||
* &error_warn (for QMP/HMP initiated sessions).
|
||||
*
|
||||
* Returns true when server successfully started.
|
||||
*/
|
||||
int gdbserver_start(const char *port_or_device);
|
||||
bool gdbserver_start(const char *port_or_device, Error **errp);
|
||||
|
||||
/**
|
||||
* gdb_feature_builder_init() - Initialize GDBFeatureBuilder.
|
||||
|
@ -784,7 +784,6 @@ struct MemoryRegion {
|
||||
bool terminates;
|
||||
bool ram_device;
|
||||
bool enabled;
|
||||
bool warning_printed; /* For reservations */
|
||||
uint8_t vga_logging_count;
|
||||
MemoryRegion *alias;
|
||||
hwaddr alias_offset;
|
||||
@ -1194,7 +1193,7 @@ static inline bool MemoryRegionSection_eq(MemoryRegionSection *a,
|
||||
MemoryRegionSection *memory_region_section_new_copy(MemoryRegionSection *s);
|
||||
|
||||
/**
|
||||
* memory_region_section_new_copy: Free a copied memory region section
|
||||
* memory_region_section_free_copy: Free a copied memory region section
|
||||
*
|
||||
* Free a copy of a memory section created via memory_region_section_new_copy().
|
||||
* properly dropping references on all relevant members.
|
||||
@ -2510,7 +2509,7 @@ MemoryRegionSection memory_region_find(MemoryRegion *mr,
|
||||
void memory_global_dirty_log_sync(bool last_stage);
|
||||
|
||||
/**
|
||||
* memory_global_dirty_log_sync: synchronize the dirty log for all memory
|
||||
* memory_global_after_dirty_log_sync: synchronize the dirty log for all memory
|
||||
*
|
||||
* Synchronizes the vCPUs with a thread that is reading the dirty bitmap.
|
||||
* This function must be called after the dirty log bitmap is cleared, and
|
||||
|
@ -22,12 +22,7 @@
|
||||
#define QEMU_EXTERN_C extern
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && (defined(__x86_64__) || defined(__i386__))
|
||||
# define QEMU_PACKED __attribute__((gcc_struct, packed))
|
||||
#else
|
||||
# define QEMU_PACKED __attribute__((packed))
|
||||
#endif
|
||||
|
||||
#define QEMU_PACKED __attribute__((packed))
|
||||
#define QEMU_ALIGNED(X) __attribute__((aligned(X)))
|
||||
|
||||
#ifndef glue
|
||||
|
@ -583,7 +583,7 @@ QEMU_PLUGIN_API
|
||||
bool qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info);
|
||||
|
||||
/**
|
||||
* qemu_plugin_mem_get_mem_value() - return last value loaded/stored
|
||||
* qemu_plugin_mem_get_value() - return last value loaded/stored
|
||||
* @info: opaque memory transaction handle
|
||||
*
|
||||
* Returns: memory value
|
||||
|
@ -9,8 +9,6 @@
|
||||
#ifndef SEMIHOST_CONSOLE_H
|
||||
#define SEMIHOST_CONSOLE_H
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
/**
|
||||
* qemu_semihosting_console_read:
|
||||
* @cs: CPUState
|
||||
|
@ -9,6 +9,7 @@
|
||||
#ifndef SEMIHOSTING_SYSCALLS_H
|
||||
#define SEMIHOSTING_SYSCALLS_H
|
||||
|
||||
#include "exec/cpu-defs.h"
|
||||
#include "gdbstub/syscalls.h"
|
||||
|
||||
/*
|
||||
|
@ -19,41 +19,96 @@
|
||||
#include "exec/tswap.h"
|
||||
#include "exec/page-protection.h"
|
||||
|
||||
/**
|
||||
* get_user_u64:
|
||||
*
|
||||
* Returns: 0 on success, -1 on error.
|
||||
*/
|
||||
#define get_user_u64(val, addr) \
|
||||
({ uint64_t val_ = 0; \
|
||||
int ret_ = cpu_memory_rw_debug(env_cpu(env), (addr), \
|
||||
&val_, sizeof(val_), 0); \
|
||||
(val) = tswap64(val_); ret_; })
|
||||
|
||||
/**
|
||||
* get_user_u32:
|
||||
*
|
||||
* Returns: 0 on success, -1 on error.
|
||||
*/
|
||||
#define get_user_u32(val, addr) \
|
||||
({ uint32_t val_ = 0; \
|
||||
int ret_ = cpu_memory_rw_debug(env_cpu(env), (addr), \
|
||||
&val_, sizeof(val_), 0); \
|
||||
(val) = tswap32(val_); ret_; })
|
||||
|
||||
/**
|
||||
* get_user_u8:
|
||||
*
|
||||
* Returns: 0 on success, -1 on error.
|
||||
*/
|
||||
#define get_user_u8(val, addr) \
|
||||
({ uint8_t val_ = 0; \
|
||||
int ret_ = cpu_memory_rw_debug(env_cpu(env), (addr), \
|
||||
&val_, sizeof(val_), 0); \
|
||||
(val) = val_; ret_; })
|
||||
|
||||
/**
|
||||
* get_user_ual:
|
||||
*
|
||||
* Returns: 0 on success, -1 on error.
|
||||
*/
|
||||
#define get_user_ual(arg, p) get_user_u32(arg, p)
|
||||
|
||||
/**
|
||||
* put_user_u64:
|
||||
*
|
||||
* Returns: 0 on success, -1 on error.
|
||||
*/
|
||||
#define put_user_u64(val, addr) \
|
||||
({ uint64_t val_ = tswap64(val); \
|
||||
cpu_memory_rw_debug(env_cpu(env), (addr), &val_, sizeof(val_), 1); })
|
||||
|
||||
/**
|
||||
* put_user_u32:
|
||||
*
|
||||
* Returns: 0 on success, -1 on error.
|
||||
*/
|
||||
#define put_user_u32(val, addr) \
|
||||
({ uint32_t val_ = tswap32(val); \
|
||||
cpu_memory_rw_debug(env_cpu(env), (addr), &val_, sizeof(val_), 1); })
|
||||
|
||||
/**
|
||||
* put_user_ual:
|
||||
*
|
||||
* Returns: 0 on success, -1 on error.
|
||||
*/
|
||||
#define put_user_ual(arg, p) put_user_u32(arg, p)
|
||||
|
||||
/**
|
||||
* uaccess_lock_user:
|
||||
*
|
||||
* The returned pointer should be freed using uaccess_unlock_user().
|
||||
*/
|
||||
void *uaccess_lock_user(CPUArchState *env, target_ulong addr,
|
||||
target_ulong len, bool copy);
|
||||
/**
|
||||
* lock_user:
|
||||
*
|
||||
* The returned pointer should be freed using unlock_user().
|
||||
*/
|
||||
#define lock_user(type, p, len, copy) uaccess_lock_user(env, p, len, copy)
|
||||
|
||||
/**
|
||||
* uaccess_lock_user_string:
|
||||
*
|
||||
* The returned string should be freed using uaccess_unlock_user().
|
||||
*/
|
||||
char *uaccess_lock_user_string(CPUArchState *env, target_ulong addr);
|
||||
/**
|
||||
* uaccess_lock_user_string:
|
||||
*
|
||||
* The returned string should be freed using unlock_user().
|
||||
*/
|
||||
#define lock_user_string(p) uaccess_lock_user_string(env, p)
|
||||
|
||||
void uaccess_unlock_user(CPUArchState *env, void *p,
|
||||
|
@ -1023,11 +1023,7 @@ int main(int argc, char **argv, char **envp)
|
||||
target_cpu_copy_regs(env, regs);
|
||||
|
||||
if (gdbstub) {
|
||||
if (gdbserver_start(gdbstub) < 0) {
|
||||
fprintf(stderr, "qemu: could not open gdbserver on %s\n",
|
||||
gdbstub);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
gdbserver_start(gdbstub, &error_fatal);
|
||||
gdb_handlesig(cpu, 0, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
|
@ -378,9 +378,9 @@ elif host_os == 'sunos'
|
||||
elif host_os == 'haiku'
|
||||
qemu_common_flags += ['-DB_USE_POSITIVE_POSIX_ERRORS', '-D_BSD_SOURCE', '-fPIC']
|
||||
elif host_os == 'windows'
|
||||
if not compiler.compiles('struct x { int y; } __attribute__((gcc_struct));',
|
||||
args: '-Werror')
|
||||
error('Your compiler does not support __attribute__((gcc_struct)) - please use GCC instead of Clang')
|
||||
# plugins use delaylib, and clang needs to be used with lld to make it work.
|
||||
if compiler.get_id() == 'clang' and compiler.get_linker_id() != 'ld.lld'
|
||||
error('On windows, you need to use lld with clang - use msys2 clang64/clangarm64 env')
|
||||
endif
|
||||
endif
|
||||
|
||||
|
@ -285,7 +285,7 @@ void hmp_gdbserver(Monitor *mon, const QDict *qdict)
|
||||
device = "tcp::" DEFAULT_GDBSTUB_PORT;
|
||||
}
|
||||
|
||||
if (gdbserver_start(device) < 0) {
|
||||
if (!gdbserver_start(device, &error_warn)) {
|
||||
monitor_printf(mon, "Could not open gdbserver on device '%s'\n",
|
||||
device);
|
||||
} else if (strcmp(device, "none") == 0) {
|
||||
|
@ -17,14 +17,15 @@ if not enable_modules
|
||||
capture: true,
|
||||
command: ['sed', '-ne', 's/^[[:space:]]*\\(qemu_.*\\);/_\\1/p', '@INPUT@'])
|
||||
emulator_link_args += ['-Wl,-exported_symbols_list,plugins/qemu-plugins-ld64.symbols']
|
||||
elif host_os == 'windows' and meson.get_compiler('c').get_id() == 'clang'
|
||||
# LLVM/lld does not support exporting specific symbols. However, it works
|
||||
# out of the box with dllexport/dllimport attribute we set in the code.
|
||||
else
|
||||
emulator_link_args += ['-Xlinker', '--dynamic-list=' + qemu_plugin_symbols.full_path()]
|
||||
endif
|
||||
endif
|
||||
|
||||
if host_os == 'windows'
|
||||
dlltool = find_program('dlltool', required: true)
|
||||
|
||||
# Generate a .lib file for plugins to link against.
|
||||
# First, create a .def file listing all the symbols a plugin should expect to have
|
||||
# available in qemu
|
||||
@ -33,12 +34,27 @@ if host_os == 'windows'
|
||||
output: 'qemu_plugin_api.def',
|
||||
capture: true,
|
||||
command: ['sed', '-e', '0,/^/s//EXPORTS/; s/[{};]//g', '@INPUT@'])
|
||||
|
||||
# then use dlltool to assemble a delaylib.
|
||||
# The delaylib will have an "imaginary" name (qemu.exe), that is used by the
|
||||
# linker file we add with plugins (win32_linker.c) to identify that we want
|
||||
# to find missing symbols in current program.
|
||||
win32_qemu_plugin_api_link_flags = ['-Lplugins', '-lqemu_plugin_api']
|
||||
if meson.get_compiler('c').get_id() == 'clang'
|
||||
# With LLVM/lld, delaylib is specified at link time (-delayload)
|
||||
dlltool = find_program('llvm-dlltool', required: true)
|
||||
dlltool_cmd = [dlltool, '-d', '@INPUT@', '-l', '@OUTPUT@', '-D', 'qemu.exe']
|
||||
win32_qemu_plugin_api_link_flags += ['-Wl,-delayload=qemu.exe']
|
||||
else
|
||||
# With gcc/ld, delay lib is built with a specific delay parameter.
|
||||
dlltool = find_program('dlltool', required: true)
|
||||
dlltool_cmd = [dlltool, '--input-def', '@INPUT@',
|
||||
'--output-delaylib', '@OUTPUT@', '--dllname', 'qemu.exe']
|
||||
endif
|
||||
win32_qemu_plugin_api_lib = configure_file(
|
||||
input: win32_plugin_def,
|
||||
output: 'libqemu_plugin_api.a',
|
||||
command: [dlltool, '--input-def', '@INPUT@',
|
||||
'--output-delaylib', '@OUTPUT@', '--dllname', 'qemu.exe']
|
||||
command: dlltool_cmd
|
||||
)
|
||||
endif
|
||||
specific_ss.add(files(
|
||||
|
@ -23,11 +23,7 @@
|
||||
#define G_GNUC_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
|
||||
#define G_GNUC_NULL_TERMINATED __attribute__((sentinel))
|
||||
|
||||
#if defined(_WIN32) && (defined(__x86_64__) || defined(__i386__))
|
||||
# define QEMU_PACKED __attribute__((gcc_struct, packed))
|
||||
#else
|
||||
# define QEMU_PACKED __attribute__((packed))
|
||||
#endif
|
||||
#define QEMU_PACKED __attribute__((packed))
|
||||
|
||||
#define cat(x,y) x ## y
|
||||
#define cat2(x,y) cat(x,y)
|
||||
|
@ -37,10 +37,10 @@ def find_deps(exe_or_dll, search_path, analyzed_deps):
|
||||
|
||||
analyzed_deps.add(dep)
|
||||
# locate the dll dependencies recursively
|
||||
rdeps = find_deps(dll, search_path, analyzed_deps)
|
||||
analyzed_deps, rdeps = find_deps(dll, search_path, analyzed_deps)
|
||||
deps.extend(rdeps)
|
||||
|
||||
return deps
|
||||
return analyzed_deps, deps
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="QEMU NSIS build helper.")
|
||||
@ -92,18 +92,18 @@ def main():
|
||||
dlldir = os.path.join(destdir + prefix, "dll")
|
||||
os.mkdir(dlldir)
|
||||
|
||||
analyzed_deps = set()
|
||||
for exe in glob.glob(os.path.join(destdir + prefix, "*.exe")):
|
||||
signcode(exe)
|
||||
|
||||
# find all dll dependencies
|
||||
deps = set(find_deps(exe, search_path, set()))
|
||||
analyzed_deps, deps = find_deps(exe, search_path, analyzed_deps)
|
||||
deps = set(deps)
|
||||
deps.remove(exe)
|
||||
|
||||
# copy all dlls to the DLLDIR
|
||||
for dep in deps:
|
||||
dllfile = os.path.join(dlldir, os.path.basename(dep))
|
||||
if (os.path.exists(dllfile)):
|
||||
continue
|
||||
print("Copying '%s' to '%s'" % (dep, dllfile))
|
||||
shutil.copy(dep, dllfile)
|
||||
|
||||
|
@ -166,6 +166,7 @@ static LayoutInfo common_semi_find_bases(CPUState *cs)
|
||||
|
||||
#endif
|
||||
|
||||
#include "cpu.h"
|
||||
#include "common-semi-target.h"
|
||||
|
||||
/*
|
||||
|
@ -18,14 +18,15 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "semihosting/semihost.h"
|
||||
#include "semihosting/console.h"
|
||||
#include "exec/cpu-common.h"
|
||||
#include "exec/gdbstub.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "qemu/log.h"
|
||||
#include "chardev/char.h"
|
||||
#include "chardev/char-fe.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/fifo8.h"
|
||||
#include "hw/core/cpu.h"
|
||||
|
||||
/* Access to this structure is protected by the BQL */
|
||||
typedef struct SemihostingConsole {
|
||||
|
@ -4,13 +4,16 @@ specific_ss.add(when: 'CONFIG_SEMIHOSTING', if_true: files(
|
||||
))
|
||||
|
||||
specific_ss.add(when: ['CONFIG_SEMIHOSTING', 'CONFIG_SYSTEM_ONLY'], if_true: files(
|
||||
'config.c',
|
||||
'console.c',
|
||||
'uaccess.c',
|
||||
))
|
||||
|
||||
common_ss.add(when: ['CONFIG_SEMIHOSTING', 'CONFIG_SYSTEM_ONLY'], if_false: files('stubs-all.c'))
|
||||
system_ss.add(when: ['CONFIG_SEMIHOSTING'], if_false: files('stubs-system.c'))
|
||||
system_ss.add(when: ['CONFIG_SEMIHOSTING'], if_true: files(
|
||||
'config.c',
|
||||
'console.c',
|
||||
), if_false: files(
|
||||
'stubs-system.c',
|
||||
))
|
||||
|
||||
specific_ss.add(when: ['CONFIG_ARM_COMPATIBLE_SEMIHOSTING'],
|
||||
if_true: files('arm-compat-semi.c'))
|
||||
|
@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "cpu.h"
|
||||
#include "gdbstub/syscalls.h"
|
||||
#include "semihosting/guestfd.h"
|
||||
@ -287,6 +288,7 @@ static void host_open(CPUState *cs, gdb_syscall_complete_cb complete,
|
||||
|
||||
ret = open(p, host_flags, mode);
|
||||
if (ret < 0) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to open %s\n", __func__, p);
|
||||
complete(cs, -1, errno);
|
||||
} else {
|
||||
int guestfd = alloc_guestfd();
|
||||
|
@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "exec/cpu-all.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "semihosting/uaccess.h"
|
||||
|
||||
|
@ -186,11 +186,7 @@ typedef struct VhostUserShared {
|
||||
unsigned char uuid[UUID_LEN];
|
||||
} VhostUserShared;
|
||||
|
||||
#if defined(_WIN32) && (defined(__x86_64__) || defined(__i386__))
|
||||
# define VU_PACKED __attribute__((gcc_struct, packed))
|
||||
#else
|
||||
# define VU_PACKED __attribute__((packed))
|
||||
#endif
|
||||
#define VU_PACKED __attribute__((packed))
|
||||
|
||||
typedef struct VhostUserMsg {
|
||||
int request;
|
||||
|
101
system/vl.c
101
system/vl.c
@ -811,29 +811,15 @@ static void configure_msg(QemuOpts *opts)
|
||||
/***********************************************************/
|
||||
/* USB devices */
|
||||
|
||||
static int usb_device_add(const char *devname)
|
||||
static bool usb_parse(const char *cmdline, Error **errp)
|
||||
{
|
||||
USBDevice *dev = NULL;
|
||||
g_assert(machine_usb(current_machine));
|
||||
|
||||
if (!machine_usb(current_machine)) {
|
||||
return -1;
|
||||
if (!usbdevice_create(cmdline)) {
|
||||
error_setg(errp, "could not add USB device '%s'", cmdline);
|
||||
return false;
|
||||
}
|
||||
|
||||
dev = usbdevice_create(devname);
|
||||
if (!dev)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb_parse(const char *cmdline)
|
||||
{
|
||||
int r;
|
||||
r = usb_device_add(cmdline);
|
||||
if (r < 0) {
|
||||
error_report("could not add USB device '%s'", cmdline);
|
||||
}
|
||||
return r;
|
||||
return true;
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
@ -1307,22 +1293,27 @@ static void add_device_config(int type, const char *cmdline)
|
||||
QTAILQ_INSERT_TAIL(&device_configs, conf, next);
|
||||
}
|
||||
|
||||
static int foreach_device_config(int type, int (*func)(const char *cmdline))
|
||||
/**
|
||||
* foreach_device_config_or_exit(): process per-device configs
|
||||
* @type: device_config type
|
||||
* @func: device specific config function, returning pass/fail
|
||||
*
|
||||
* @func is called with the &error_fatal handler so device specific
|
||||
* error messages can be reported on failure.
|
||||
*/
|
||||
static void foreach_device_config_or_exit(int type,
|
||||
bool (*func)(const char *cmdline,
|
||||
Error **errp))
|
||||
{
|
||||
struct device_config *conf;
|
||||
int rc;
|
||||
|
||||
QTAILQ_FOREACH(conf, &device_configs, next) {
|
||||
if (conf->type != type)
|
||||
continue;
|
||||
loc_push_restore(&conf->loc);
|
||||
rc = func(conf->cmdline);
|
||||
func(conf->cmdline, &error_fatal);
|
||||
loc_pop(&conf->loc);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qemu_disable_default_devices(void)
|
||||
@ -1452,7 +1443,7 @@ static void qemu_create_default_devices(void)
|
||||
}
|
||||
}
|
||||
|
||||
static int serial_parse(const char *devname)
|
||||
static bool serial_parse(const char *devname, Error **errp)
|
||||
{
|
||||
int index = num_serial_hds;
|
||||
|
||||
@ -1467,13 +1458,13 @@ static int serial_parse(const char *devname)
|
||||
|
||||
serial_hds[index] = qemu_chr_new_mux_mon(label, devname, NULL);
|
||||
if (!serial_hds[index]) {
|
||||
error_report("could not connect serial device"
|
||||
" to character backend '%s'", devname);
|
||||
return -1;
|
||||
error_setg(errp, "could not connect serial device"
|
||||
" to character backend '%s'", devname);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
num_serial_hds++;
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
Chardev *serial_hd(int i)
|
||||
@ -1485,44 +1476,44 @@ Chardev *serial_hd(int i)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int parallel_parse(const char *devname)
|
||||
static bool parallel_parse(const char *devname, Error **errp)
|
||||
{
|
||||
static int index = 0;
|
||||
char label[32];
|
||||
|
||||
if (strcmp(devname, "none") == 0)
|
||||
return 0;
|
||||
return true;
|
||||
if (index == MAX_PARALLEL_PORTS) {
|
||||
error_report("too many parallel ports");
|
||||
exit(1);
|
||||
error_setg(errp, "too many parallel ports");
|
||||
return false;
|
||||
}
|
||||
snprintf(label, sizeof(label), "parallel%d", index);
|
||||
parallel_hds[index] = qemu_chr_new_mux_mon(label, devname, NULL);
|
||||
if (!parallel_hds[index]) {
|
||||
error_report("could not connect parallel device"
|
||||
" to character backend '%s'", devname);
|
||||
return -1;
|
||||
error_setg(errp, "could not connect parallel device"
|
||||
" to character backend '%s'", devname);
|
||||
return false;
|
||||
}
|
||||
index++;
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int debugcon_parse(const char *devname)
|
||||
static bool debugcon_parse(const char *devname, Error **errp)
|
||||
{
|
||||
QemuOpts *opts;
|
||||
|
||||
if (!qemu_chr_new_mux_mon("debugcon", devname, NULL)) {
|
||||
error_report("invalid character backend '%s'", devname);
|
||||
exit(1);
|
||||
error_setg(errp, "invalid character backend '%s'", devname);
|
||||
return false;
|
||||
}
|
||||
opts = qemu_opts_create(qemu_find_opts("device"), "debugcon", 1, NULL);
|
||||
if (!opts) {
|
||||
error_report("already have a debugcon device");
|
||||
exit(1);
|
||||
error_setg(errp, "already have a debugcon device");
|
||||
return false;
|
||||
}
|
||||
qemu_opt_set(opts, "driver", "isa-debugcon", &error_abort);
|
||||
qemu_opt_set(opts, "chardev", "debugcon", &error_abort);
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static gint machine_class_cmp(gconstpointer a, gconstpointer b)
|
||||
@ -2044,12 +2035,9 @@ static void qemu_create_late_backends(void)
|
||||
qemu_opts_foreach(qemu_find_opts("mon"),
|
||||
mon_init_func, NULL, &error_fatal);
|
||||
|
||||
if (foreach_device_config(DEV_SERIAL, serial_parse) < 0)
|
||||
exit(1);
|
||||
if (foreach_device_config(DEV_PARALLEL, parallel_parse) < 0)
|
||||
exit(1);
|
||||
if (foreach_device_config(DEV_DEBUGCON, debugcon_parse) < 0)
|
||||
exit(1);
|
||||
foreach_device_config_or_exit(DEV_SERIAL, serial_parse);
|
||||
foreach_device_config_or_exit(DEV_PARALLEL, parallel_parse);
|
||||
foreach_device_config_or_exit(DEV_DEBUGCON, debugcon_parse);
|
||||
|
||||
/* now chardevs have been created we may have semihosting to connect */
|
||||
qemu_semihosting_chardev_init();
|
||||
@ -2667,8 +2655,7 @@ static void qemu_create_cli_devices(void)
|
||||
|
||||
/* init USB devices */
|
||||
if (machine_usb(current_machine)) {
|
||||
if (foreach_device_config(DEV_USB, usb_parse) < 0)
|
||||
exit(1);
|
||||
foreach_device_config_or_exit(DEV_USB, usb_parse);
|
||||
}
|
||||
|
||||
/* init generic devices */
|
||||
@ -2715,10 +2702,8 @@ static bool qemu_machine_creation_done(Error **errp)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (foreach_device_config(DEV_GDB, gdbserver_start) < 0) {
|
||||
error_setg(errp, "could not start gdbserver");
|
||||
return false;
|
||||
}
|
||||
foreach_device_config_or_exit(DEV_GDB, gdbserver_start);
|
||||
|
||||
if (!vga_interface_created && !default_vga &&
|
||||
vga_interface_type != VGA_NONE) {
|
||||
warn_report("A -vga option was passed but this machine "
|
||||
|
@ -355,7 +355,7 @@ void qos_object_start_hw(QOSGraphObject *obj);
|
||||
QOSGraphObject *qos_machine_new(QOSGraphNode *node, QTestState *qts);
|
||||
|
||||
/**
|
||||
* qos_machine_new(): instantiate a new driver node
|
||||
* qos_driver_new(): instantiate a new driver node
|
||||
* @node: A driver node to be instantiated
|
||||
* @parent: A #QOSGraphObject to be consumed by the new driver node
|
||||
* @alloc: An allocator to be used by the new driver node.
|
||||
|
@ -365,7 +365,7 @@ QDict *qtest_qmp_event_ref(QTestState *s, const char *event);
|
||||
char *qtest_hmp(QTestState *s, const char *fmt, ...) G_GNUC_PRINTF(2, 3);
|
||||
|
||||
/**
|
||||
* qtest_hmpv:
|
||||
* qtest_vhmp:
|
||||
* @s: #QTestState instance to operate on.
|
||||
* @fmt: HMP command to send to QEMU, formats arguments like vsprintf().
|
||||
* @ap: HMP command arguments
|
||||
@ -904,7 +904,7 @@ void qtest_qmp_assert_success(QTestState *qts, const char *fmt, ...)
|
||||
|
||||
#ifndef _WIN32
|
||||
/**
|
||||
* qtest_qmp_fd_assert_success_ref:
|
||||
* qtest_qmp_fds_assert_success_ref:
|
||||
* @qts: QTestState instance to operate on
|
||||
* @fds: the file descriptors to send
|
||||
* @nfds: number of @fds to send
|
||||
@ -921,7 +921,7 @@ QDict *qtest_qmp_fds_assert_success_ref(QTestState *qts, int *fds, size_t nfds,
|
||||
G_GNUC_PRINTF(4, 5);
|
||||
|
||||
/**
|
||||
* qtest_qmp_fd_assert_success:
|
||||
* qtest_qmp_fds_assert_success:
|
||||
* @qts: QTestState instance to operate on
|
||||
* @fds: the file descriptors to send
|
||||
* @nfds: number of @fds to send
|
||||
|
@ -150,10 +150,8 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
|
||||
qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(
|
||||
insn, QEMU_PLUGIN_INLINE_ADD_U64, insn_count, 1);
|
||||
} else {
|
||||
uint64_t vaddr = qemu_plugin_insn_vaddr(insn);
|
||||
qemu_plugin_register_vcpu_insn_exec_cb(
|
||||
insn, vcpu_insn_exec_before, QEMU_PLUGIN_CB_NO_REGS,
|
||||
GUINT_TO_POINTER(vaddr));
|
||||
insn, vcpu_insn_exec_before, QEMU_PLUGIN_CB_NO_REGS, NULL);
|
||||
}
|
||||
|
||||
if (do_size) {
|
||||
|
@ -135,14 +135,14 @@ static void update_region_info(uint64_t region, uint64_t offset,
|
||||
g_assert(offset + size <= region_size);
|
||||
|
||||
g_mutex_lock(&lock);
|
||||
ri = (RegionInfo *) g_hash_table_lookup(regions, GUINT_TO_POINTER(region));
|
||||
ri = (RegionInfo *) g_hash_table_lookup(regions, ®ion);
|
||||
|
||||
if (!ri) {
|
||||
ri = g_new0(RegionInfo, 1);
|
||||
ri->region_address = region;
|
||||
ri->data = g_malloc0(region_size);
|
||||
ri->seen_all = true;
|
||||
g_hash_table_insert(regions, GUINT_TO_POINTER(region), (gpointer) ri);
|
||||
g_hash_table_insert(regions, &ri->region_address, ri);
|
||||
}
|
||||
|
||||
if (is_store) {
|
||||
@ -392,7 +392,7 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
|
||||
|
||||
if (do_region_summary) {
|
||||
region_mask = (region_size - 1);
|
||||
regions = g_hash_table_new(NULL, g_direct_equal);
|
||||
regions = g_hash_table_new(g_int64_hash, g_int64_equal);
|
||||
}
|
||||
|
||||
counts = qemu_plugin_scoreboard_new(sizeof(CPUCount));
|
||||
|
@ -5,9 +5,8 @@ if get_option('plugins')
|
||||
t += shared_module(i, files(i + '.c') + '../../../contrib/plugins/win32_linker.c',
|
||||
include_directories: '../../../include/qemu',
|
||||
link_depends: [win32_qemu_plugin_api_lib],
|
||||
link_args: ['-Lplugins', '-lqemu_plugin_api'],
|
||||
link_args: win32_qemu_plugin_api_link_flags,
|
||||
dependencies: glib)
|
||||
|
||||
else
|
||||
t += shared_module(i, files(i + '.c'),
|
||||
include_directories: '../../../include/qemu',
|
||||
|
@ -76,12 +76,12 @@ static int64_t write_sysno = -1;
|
||||
static SyscallStats *get_or_create_entry(int64_t num)
|
||||
{
|
||||
SyscallStats *entry =
|
||||
(SyscallStats *) g_hash_table_lookup(statistics, GINT_TO_POINTER(num));
|
||||
(SyscallStats *) g_hash_table_lookup(statistics, &num);
|
||||
|
||||
if (!entry) {
|
||||
entry = g_new0(SyscallStats, 1);
|
||||
entry->num = num;
|
||||
g_hash_table_insert(statistics, GINT_TO_POINTER(num), (gpointer) entry);
|
||||
g_hash_table_insert(statistics, &entry->num, entry);
|
||||
}
|
||||
|
||||
return entry;
|
||||
@ -232,7 +232,7 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
|
||||
}
|
||||
|
||||
if (!do_print) {
|
||||
statistics = g_hash_table_new_full(NULL, g_direct_equal, NULL, g_free);
|
||||
statistics = g_hash_table_new_full(g_int64_hash, g_int64_equal, NULL, g_free);
|
||||
}
|
||||
|
||||
if (do_log_writes) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user