Merge tag 'qtest-20250117-pull-request' of https://gitlab.com/farosas/qemu into staging
Qtest pull request
- RISCV CSR test
- migration recover changed to OOB
- removal of dead code in test-x86-cpuid-compat
# -----BEGIN PGP SIGNATURE-----
#
# iQJEBAABCAAuFiEEqhtIsKIjJqWkw2TPx5jcdBvsMZ0FAmeKbx4QHGZhcm9zYXNA
# c3VzZS5kZQAKCRDHmNx0G+wxnRD7D/9v4ovvGn/IwSXjjpOpkjhCSgV8TMi1F61P
# hqB5TTCY8yejvT7JauplMUHmcJsVCNx+HF36D+YjxBjqrhQE8vzPRXgcLxHL9RX4
# Kwgdk24kFKADE3gsiys9gOpwRhmtY0/2CT5LvitfJRMxUNPtm0Mr7qM3Z0Taeusu
# lxZgIMTBeNakpY5vua8nlLQ4r+/Df6S3TFFAaQ4UYab/T5zHVcjKaySXDlT1QXpp
# M+Be21jPxuUYJnKCSxMCUtuY9wkSPcITzJW91V+JxL9STSpsKpnQe10JWDRbwLBt
# /am2Jg5f8iFEblCwr5aQRMwXB+e/Y7K4qKPOUalj+weGnCXh9DmWPXnV6qzdZNO8
# sePKoFj1AMtqbVf3iOpDBRkH8dECiDh1jHmflW1grF0BuOwOw8dKYW+i2qz9ZDiW
# rKWKfRcZZ059aOCQWqpMC9TGQ8osMC/v6GGJwiPBDLapGjnAm5d1683w4Z1l8tAg
# vf9yti2mpzK15PB6doEj/IuZr8WKWFMklizmMMZpXgHIUpjtm3JFKXX/jGHcD3KU
# E8F4ns3zPMlq7ncIwc6GADRB3XzEuzzuXAaEO8HMN0fYHevfnFIon749udyBDI/n
# a1/CTzTmchItwzgpdvcoiKO6gkg6DO9n08QULCMPSVCtl5KAlz5yuwxWGI/rM6u7
# ixPi8i24oA==
# =i4AD
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 17 Jan 2025 09:54:22 EST
# gpg: using RSA key AA1B48B0A22326A5A4C364CFC798DC741BEC319D
# gpg: issuer "farosas@suse.de"
# gpg: Good signature from "Fabiano Rosas <farosas@suse.de>" [unknown]
# gpg: aka "Fabiano Almeida Rosas <fabiano.rosas@suse.com>" [unknown]
# gpg: WARNING: The key's User ID is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: AA1B 48B0 A223 26A5 A4C3 64CF C798 DC74 1BEC 319D
* tag 'qtest-20250117-pull-request' of https://gitlab.com/farosas/qemu:
tests/qtest/test-x86-cpuid-compat: Remove tests related to pc-i440fx-2.3
tests/qtest/migration: Use out-of-band execution for migrate-recover
tests/qtest: Introduce qtest_init_with_env_and_capabilities()
tests/qtest: QTest example for RISC-V CSR register
target/riscv: Add RISC-V CSR qtest support
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
diff --git a/.editorconfig b/.editorconfig
index 7303759..a04cb90 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -47,3 +47,16 @@
[*.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
+
diff --git a/MAINTAINERS b/MAINTAINERS
index a928ce3..846b81e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -72,11 +72,14 @@
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
-------------------------------------------------
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index 453eb20..d56ca13 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -633,9 +633,10 @@
* 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);
diff --git a/bsd-user/main.c b/bsd-user/main.c
index 0a5bc57..b2f6a9b 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -628,7 +628,7 @@
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);
diff --git a/configure b/configure
index 1833637..02f1dd2 100755
--- a/configure
+++ b/configure
@@ -528,25 +528,6 @@
;;
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 @@
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
diff --git a/contrib/plugins/cache.c b/contrib/plugins/cache.c
index 512ef67..7baff86 100644
--- a/contrib/plugins/cache.c
+++ b/contrib/plugins/cache.c
@@ -208,7 +208,7 @@
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 @@
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 @@
* 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 @@
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;
}
diff --git a/contrib/plugins/cflow.c b/contrib/plugins/cflow.c
index b39974d..930ecb4 100644
--- a/contrib/plugins/cflow.c
+++ b/contrib/plugins/cflow.c
@@ -76,6 +76,8 @@
/* 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 @@
} 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_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 @@
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 @@
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 @@
* 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
diff --git a/contrib/plugins/hotblocks.c b/contrib/plugins/hotblocks.c
index 02bc507..f12bfb7 100644
--- a/contrib/plugins/hotblocks.c
+++ b/contrib/plugins/hotblocks.c
@@ -29,7 +29,7 @@
*
* 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 @@
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_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 @@
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 @@
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);
diff --git a/contrib/plugins/hotpages.c b/contrib/plugins/hotpages.c
index 8316ae5..c6e6493 100644
--- a/contrib/plugins/hotpages.c
+++ b/contrib/plugins/hotpages.c
@@ -103,7 +103,7 @@
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 @@
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++;
diff --git a/contrib/plugins/howvec.c b/contrib/plugins/howvec.c
index 9be67f7..2aa9029 100644
--- a/contrib/plugins/howvec.c
+++ b/contrib/plugins/howvec.c
@@ -253,6 +253,8 @@
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 @@
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 @@
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);
diff --git a/contrib/plugins/hwprofile.c b/contrib/plugins/hwprofile.c
index 739ac0c..2a4cbc4 100644
--- a/contrib/plugins/hwprofile.c
+++ b/contrib/plugins/hwprofile.c
@@ -43,6 +43,8 @@
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 @@
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 @@
{
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 @@
/* 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 @@
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 @@
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();
diff --git a/contrib/plugins/meson.build b/contrib/plugins/meson.build
index 63a32c2..484b9a8 100644
--- a/contrib/plugins/meson.build
+++ b/contrib/plugins/meson.build
@@ -12,7 +12,7 @@
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'),
diff --git a/contrib/plugins/stoptrigger.c b/contrib/plugins/stoptrigger.c
index 03ee22f..b3a6ed6 100644
--- a/contrib/plugins/stoptrigger.c
+++ b/contrib/plugins/stoptrigger.c
@@ -21,9 +21,11 @@
/* 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 @@
/* 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_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 @@
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 @@
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 @@
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);
diff --git a/docs/about/build-platforms.rst b/docs/about/build-platforms.rst
index d8b0445..482b098 100644
--- a/docs/about/build-platforms.rst
+++ b/docs/about/build-platforms.rst
@@ -29,6 +29,9 @@
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 @@
cross compilation using ``docker`` or ``podman``, or to use pre-built
binaries distributed with QEMU.
-
Windows
-------
diff --git a/docs/about/emulation.rst b/docs/about/emulation.rst
index 3028d5f..3bc3579 100644
--- a/docs/about/emulation.rst
+++ b/docs/about/emulation.rst
@@ -176,6 +176,8 @@
- System
- Tensilica ISS SIMCALL
+.. _tcg-plugins:
+
TCG Plugins
-----------
diff --git a/docs/devel/build-environment.rst b/docs/devel/build-environment.rst
new file mode 100644
index 0000000..f133ef2
--- /dev/null
+++ b/docs/devel/build-environment.rst
@@ -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=
+
diff --git a/docs/devel/codebase.rst b/docs/devel/codebase.rst
new file mode 100644
index 0000000..4039875
--- /dev/null
+++ b/docs/devel/codebase.rst
@@ -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.
diff --git a/docs/devel/control-flow-integrity.rst b/docs/devel/control-flow-integrity.rst
index e6b73a4..3d5702f 100644
--- a/docs/devel/control-flow-integrity.rst
+++ b/docs/devel/control-flow-integrity.rst
@@ -1,3 +1,5 @@
+.. _cfi:
+
============================
Control-Flow Integrity (CFI)
============================
diff --git a/docs/devel/decodetree.rst b/docs/devel/decodetree.rst
index e3392aa..98ad33a 100644
--- a/docs/devel/decodetree.rst
+++ b/docs/devel/decodetree.rst
@@ -1,3 +1,5 @@
+.. _decodetree:
+
========================
Decodetree Specification
========================
diff --git a/docs/devel/ebpf_rss.rst b/docs/devel/ebpf_rss.rst
index 4a68682..ed5d337 100644
--- a/docs/devel/ebpf_rss.rst
+++ b/docs/devel/ebpf_rss.rst
@@ -1,3 +1,5 @@
+.. _ebpf-rss:
+
===========================
eBPF RSS virtio-net support
===========================
diff --git a/docs/devel/index-build.rst b/docs/devel/index-build.rst
index 0023953..0745c81 100644
--- a/docs/devel/index-build.rst
+++ b/docs/devel/index-build.rst
@@ -8,6 +8,7 @@
:maxdepth: 3
build-system
+ build-environment
kconfig
docs
qapi-code-gen
diff --git a/docs/devel/index-internals.rst b/docs/devel/index-internals.rst
index ab9fbc4..bca597c 100644
--- a/docs/devel/index-internals.rst
+++ b/docs/devel/index-internals.rst
@@ -1,3 +1,5 @@
+.. _internal-subsystem:
+
Internal Subsystem Information
------------------------------
diff --git a/docs/devel/index.rst b/docs/devel/index.rst
index a53f1bf..29f032d 100644
--- a/docs/devel/index.rst
+++ b/docs/devel/index.rst
@@ -35,3 +35,4 @@
index-api
index-internals
index-tcg
+ codebase
diff --git a/docs/devel/migration/main.rst b/docs/devel/migration/main.rst
index c2857fc..cdd4f4a 100644
--- a/docs/devel/migration/main.rst
+++ b/docs/devel/migration/main.rst
@@ -1,3 +1,5 @@
+.. _migration:
+
===================
Migration framework
===================
diff --git a/docs/devel/multi-thread-tcg.rst b/docs/devel/multi-thread-tcg.rst
index d706c27..7fd0a07 100644
--- a/docs/devel/multi-thread-tcg.rst
+++ b/docs/devel/multi-thread-tcg.rst
@@ -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
==================
diff --git a/docs/devel/qapi-code-gen.rst b/docs/devel/qapi-code-gen.rst
index 583207a..3e26d2d 100644
--- a/docs/devel/qapi-code-gen.rst
+++ b/docs/devel/qapi-code-gen.rst
@@ -9,6 +9,7 @@
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
============
diff --git a/docs/devel/style.rst b/docs/devel/style.rst
index 2f68b50..d025933 100644
--- a/docs/devel/style.rst
+++ b/docs/devel/style.rst
@@ -416,6 +416,26 @@
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
----------------------------------
diff --git a/docs/devel/submitting-a-patch.rst b/docs/devel/submitting-a-patch.rst
index 03b2ac2..65c6407 100644
--- a/docs/devel/submitting-a-patch.rst
+++ b/docs/devel/submitting-a-patch.rst
@@ -235,6 +235,31 @@
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 @@
.. _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
----------------------------
diff --git a/docs/devel/testing/main.rst b/docs/devel/testing/main.rst
index 91f4dc6..9869bcf 100644
--- a/docs/devel/testing/main.rst
+++ b/docs/devel/testing/main.rst
@@ -39,6 +39,8 @@
expect the executables to exist and will fail with obscure messages if they
cannot find them.
+.. _unit-tests:
+
Unit tests
~~~~~~~~~~
@@ -126,6 +128,8 @@
#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 @@
are in the "auto" group).
See the "QEMU iotests" section below for more information.
+.. _qemu-iotests:
+
QEMU iotests
------------
@@ -679,6 +685,8 @@
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 @@
See :ref:`checkavocado-ref` for more details.
-
.. _checktcg-ref:
Testing with "make check-tcg"
diff --git a/docs/devel/testing/qtest.rst b/docs/devel/testing/qtest.rst
index c5b8546..73ef770 100644
--- a/docs/devel/testing/qtest.rst
+++ b/docs/devel/testing/qtest.rst
@@ -1,3 +1,5 @@
+.. _qtest:
+
========================================
QTest Device Emulation Testing Framework
========================================
diff --git a/docs/glossary.rst b/docs/glossary.rst
new file mode 100644
index 0000000..693d985
--- /dev/null
+++ b/docs/glossary.rst
@@ -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.
diff --git a/docs/index.rst b/docs/index.rst
index 0b9ee99..5665de8 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -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 @@
interop/index
specs/index
devel/index
+ glossary
diff --git a/docs/interop/qemu-ga.rst b/docs/interop/qemu-ga.rst
index 11f7bae..d16cc1b 100644
--- a/docs/interop/qemu-ga.rst
+++ b/docs/interop/qemu-ga.rst
@@ -1,3 +1,5 @@
+.. _qemu-ga:
+
QEMU Guest Agent
================
diff --git a/docs/sphinx/depfile.py b/docs/sphinx/depfile.py
index e74be6a..d3c774d 100644
--- a/docs/sphinx/depfile.py
+++ b/docs/sphinx/depfile.py
@@ -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:
diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst
index 766a745..0c9c2ce 100644
--- a/docs/system/arm/virt.rst
+++ b/docs/system/arm/virt.rst
@@ -1,3 +1,5 @@
+.. _arm-virt:
+
'virt' generic virtual platform (``virt``)
==========================================
diff --git a/docs/system/images.rst b/docs/system/images.rst
index d000bd6..a555117 100644
--- a/docs/system/images.rst
+++ b/docs/system/images.rst
@@ -82,4 +82,6 @@
- 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
diff --git a/docs/system/qemu-block-drivers.rst.inc b/docs/system/qemu-block-drivers.rst.inc
index 384e95b..cfe1acb 100644
--- a/docs/system/qemu-block-drivers.rst.inc
+++ b/docs/system/qemu-block-drivers.rst.inc
@@ -500,6 +500,8 @@
- 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
~~~~~~~~~~
diff --git a/docs/tools/qemu-nbd.rst b/docs/tools/qemu-nbd.rst
index 329f44d..4f21b79 100644
--- a/docs/tools/qemu-nbd.rst
+++ b/docs/tools/qemu-nbd.rst
@@ -1,3 +1,5 @@
+.. _qemu-nbd:
+
=====================================
QEMU Disk Network Block Device Server
=====================================
diff --git a/docs/tools/qemu-storage-daemon.rst b/docs/tools/qemu-storage-daemon.rst
index ea00149..35ab2d7 100644
--- a/docs/tools/qemu-storage-daemon.rst
+++ b/docs/tools/qemu-storage-daemon.rst
@@ -1,3 +1,5 @@
+.. _storage-daemon:
+
===================
QEMU Storage Daemon
===================
diff --git a/docs/user/main.rst b/docs/user/main.rst
index 7a126ee..80a77f0 100644
--- a/docs/user/main.rst
+++ b/docs/user/main.rst
@@ -1,3 +1,5 @@
+.. _user-mode:
+
QEMU User space emulator
========================
@@ -42,6 +44,8 @@
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 @@
* ``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
-----------------------
diff --git a/gdbstub/system.c b/gdbstub/system.c
index 2d9fdff..8ce79fa 100644
--- a/gdbstub/system.c
+++ b/gdbstub/system.c
@@ -330,26 +330,27 @@
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 @@
*/
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 @@
gdbserver_system_state.mon_chr = mon_chr;
gdb_syscall_reset();
- return 0;
+ return true;
}
static void register_types(void)
diff --git a/gdbstub/user.c b/gdbstub/user.c
index 0b4bfa9..c2bdfc3 100644
--- a/gdbstub/user.c
+++ b/gdbstub/user.c
@@ -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 @@
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 @@
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 @@
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)
diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c
index 1edc16f..cb79566 100644
--- a/hw/core/cpu-common.c
+++ b/hw/core/cpu-common.c
@@ -243,7 +243,6 @@
cpu->cluster_index = UNASSIGNED_CLUSTER_INDEX;
/* user-mode doesn't have configurable SMP topology */
/* the default value is changed by qemu_init_vcpu() for system-mode */
- cpu->nr_cores = 1;
cpu->nr_threads = 1;
cpu->cflags_next_tb = -1;
diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c
index 63be508..1744355 100644
--- a/hw/i386/kvm/clock.c
+++ b/hw/i386/kvm/clock.c
@@ -27,7 +27,6 @@
#include "qapi/error.h"
#include <linux/kvm.h>
-#include "standard-headers/asm-x86/kvm_para.h"
#include "qom/object.h"
#define TYPE_KVM_CLOCK "kvmclock"
@@ -333,8 +332,8 @@
assert(kvm_enabled());
if (create_always ||
- cpu->env.features[FEAT_KVM] & ((1ULL << KVM_FEATURE_CLOCKSOURCE) |
- (1ULL << KVM_FEATURE_CLOCKSOURCE2))) {
+ cpu->env.features[FEAT_KVM] & (CPUID_KVM_CLOCK |
+ CPUID_KVM_CLOCK2)) {
sysbus_create_simple(TYPE_KVM_CLOCK, -1, NULL);
}
}
diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c
index 97b4f7d..008496b 100644
--- a/hw/i386/x86-common.c
+++ b/hw/i386/x86-common.c
@@ -248,9 +248,7 @@
CPUX86State *env = &cpu->env;
MachineState *ms = MACHINE(hotplug_dev);
X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
- unsigned int smp_cores = ms->smp.cores;
- unsigned int smp_threads = ms->smp.threads;
- X86CPUTopoInfo topo_info;
+ X86CPUTopoInfo *topo_info = &env->topo_info;
if (!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) {
error_setg(errp, "Invalid CPU type, expected cpu type: '%s'",
@@ -269,15 +267,13 @@
}
}
- init_topo_info(&topo_info, x86ms);
+ init_topo_info(topo_info, x86ms);
if (ms->smp.modules > 1) {
- env->nr_modules = ms->smp.modules;
set_bit(CPU_TOPOLOGY_LEVEL_MODULE, env->avail_cpu_topo);
}
if (ms->smp.dies > 1) {
- env->nr_dies = ms->smp.dies;
set_bit(CPU_TOPOLOGY_LEVEL_DIE, env->avail_cpu_topo);
}
@@ -329,17 +325,17 @@
if (cpu->core_id < 0) {
error_setg(errp, "CPU core-id is not set");
return;
- } else if (cpu->core_id > (smp_cores - 1)) {
+ } else if (cpu->core_id > (ms->smp.cores - 1)) {
error_setg(errp, "Invalid CPU core-id: %u must be in range 0:%u",
- cpu->core_id, smp_cores - 1);
+ cpu->core_id, ms->smp.cores - 1);
return;
}
if (cpu->thread_id < 0) {
error_setg(errp, "CPU thread-id is not set");
return;
- } else if (cpu->thread_id > (smp_threads - 1)) {
+ } else if (cpu->thread_id > (ms->smp.threads - 1)) {
error_setg(errp, "Invalid CPU thread-id: %u must be in range 0:%u",
- cpu->thread_id, smp_threads - 1);
+ cpu->thread_id, ms->smp.threads - 1);
return;
}
@@ -348,12 +344,12 @@
topo_ids.module_id = cpu->module_id;
topo_ids.core_id = cpu->core_id;
topo_ids.smt_id = cpu->thread_id;
- cpu->apic_id = x86_apicid_from_topo_ids(&topo_info, &topo_ids);
+ cpu->apic_id = x86_apicid_from_topo_ids(topo_info, &topo_ids);
}
cpu_slot = x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, &idx);
if (!cpu_slot) {
- x86_topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids);
+ x86_topo_ids_from_apicid(cpu->apic_id, topo_info, &topo_ids);
error_setg(errp,
"Invalid CPU [socket: %u, die: %u, module: %u, core: %u, thread: %u]"
@@ -376,7 +372,7 @@
/* TODO: move socket_id/core_id/thread_id checks into x86_cpu_realizefn()
* once -smp refactoring is complete and there will be CPU private
* CPUState::nr_cores and CPUState::nr_threads fields instead of globals */
- x86_topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids);
+ x86_topo_ids_from_apicid(cpu->apic_id, topo_info, &topo_ids);
if (cpu->socket_id != -1 && cpu->socket_id != topo_ids.pkg_id) {
error_setg(errp, "property socket-id: %u doesn't match set apic-id:"
" 0x%x (socket-id: %u)", cpu->socket_id, cpu->apic_id,
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index d73f424..0675b0b 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -49,12 +49,18 @@
/**
* 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.
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 9458e28..3ee1901 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -784,7 +784,6 @@
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 @@
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 @@
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
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index c3ca0ba..fb397cd 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -407,7 +407,6 @@
* Under TCG this value is propagated to @tcg_cflags.
* See TranslationBlock::TCG CF_CLUSTER_MASK.
* @tcg_cflags: Pre-computed cflags for this cpu.
- * @nr_cores: Number of cores within this CPU package.
* @nr_threads: Number of threads within this CPU core.
* @thread: Host thread details, only live once @created is #true
* @sem: WIN32 only semaphore used only for qtest
@@ -466,7 +465,6 @@
CPUClass *cc;
/*< public >*/
- int nr_cores;
int nr_threads;
struct QemuThread *thread;
diff --git a/include/hw/i386/topology.h b/include/hw/i386/topology.h
index b2c8bf2..f6380f1 100644
--- a/include/hw/i386/topology.h
+++ b/include/hw/i386/topology.h
@@ -121,9 +121,10 @@
}
/*
- * Make APIC ID for the CPU based on Pkg_ID, Core_ID, SMT_ID
+ * Make APIC ID for the CPU based on topology and IDs of each topology level.
*
- * The caller must make sure core_id < nr_cores and smt_id < nr_threads.
+ * The caller must make sure the ID of each level doesn't exceed the width of
+ * the level.
*/
static inline apic_id_t x86_apicid_from_topo_ids(X86CPUTopoInfo *topo_info,
const X86CPUTopoIDs *topo_ids)
@@ -202,4 +203,29 @@
test_bit(CPU_TOPOLOGY_LEVEL_DIE, topo_bitmap);
}
+static inline unsigned x86_module_per_pkg(X86CPUTopoInfo *topo_info)
+{
+ return topo_info->modules_per_die * topo_info->dies_per_pkg;
+}
+
+static inline unsigned x86_cores_per_pkg(X86CPUTopoInfo *topo_info)
+{
+ return topo_info->cores_per_module * x86_module_per_pkg(topo_info);
+}
+
+static inline unsigned x86_threads_per_pkg(X86CPUTopoInfo *topo_info)
+{
+ return topo_info->threads_per_core * x86_cores_per_pkg(topo_info);
+}
+
+static inline unsigned x86_threads_per_module(X86CPUTopoInfo *topo_info)
+{
+ return topo_info->threads_per_core * topo_info->cores_per_module;
+}
+
+static inline unsigned x86_threads_per_die(X86CPUTopoInfo *topo_info)
+{
+ return x86_threads_per_module(topo_info) * topo_info->modules_per_die;
+}
+
#endif /* HW_I386_TOPOLOGY_H */
diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h
index c06954c..d904408 100644
--- a/include/qemu/compiler.h
+++ b/include/qemu/compiler.h
@@ -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
diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
index 0fba36a..3a850aa 100644
--- a/include/qemu/qemu-plugin.h
+++ b/include/qemu/qemu-plugin.h
@@ -583,7 +583,7 @@
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
diff --git a/include/semihosting/console.h b/include/semihosting/console.h
index bd78e5f..1c12e17 100644
--- a/include/semihosting/console.h
+++ b/include/semihosting/console.h
@@ -9,8 +9,6 @@
#ifndef SEMIHOST_CONSOLE_H
#define SEMIHOST_CONSOLE_H
-#include "cpu.h"
-
/**
* qemu_semihosting_console_read:
* @cs: CPUState
diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
index b5937c6..6627c45 100644
--- a/include/semihosting/syscalls.h
+++ b/include/semihosting/syscalls.h
@@ -9,6 +9,7 @@
#ifndef SEMIHOSTING_SYSCALLS_H
#define SEMIHOSTING_SYSCALLS_H
+#include "exec/cpu-defs.h"
#include "gdbstub/syscalls.h"
/*
diff --git a/include/semihosting/uaccess.h b/include/semihosting/uaccess.h
index c2fa5a6..6bc90b1 100644
--- a/include/semihosting/uaccess.h
+++ b/include/semihosting/uaccess.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,
diff --git a/linux-user/main.c b/linux-user/main.c
index b97634a..7198fa0 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -1023,11 +1023,7 @@
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);
}
diff --git a/meson.build b/meson.build
index d06f590..15a06604 100644
--- a/meson.build
+++ b/meson.build
@@ -378,9 +378,9 @@
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
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index 80b2e5f..0aa22e1 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -285,7 +285,7 @@
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) {
diff --git a/plugins/meson.build b/plugins/meson.build
index 98542e9..d60be2a 100644
--- a/plugins/meson.build
+++ b/plugins/meson.build
@@ -17,14 +17,15 @@
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 @@
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(
diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs
index 18cc122..994c2fc 100644
--- a/rust/hw/char/pl011/src/device.rs
+++ b/rust/hw/char/pl011/src/device.rs
@@ -5,7 +5,7 @@
use core::ptr::{addr_of_mut, NonNull};
use std::{
ffi::CStr,
- os::raw::{c_int, c_uchar, c_uint, c_void},
+ os::raw::{c_int, c_uint, c_void},
};
use qemu_api::{
@@ -14,7 +14,7 @@
irq::InterruptSource,
prelude::*,
qdev::DeviceImpl,
- qom::ObjectImpl,
+ qom::{ClassInitImpl, ObjectImpl, ParentField},
};
use crate::{
@@ -33,27 +33,20 @@
/// QEMU sourced constant.
pub const PL011_FIFO_DEPTH: u32 = 16;
-#[derive(Clone, Copy, Debug)]
-enum DeviceId {
- #[allow(dead_code)]
- Arm = 0,
- Luminary,
-}
+#[derive(Clone, Copy)]
+struct DeviceId(&'static [u8; 8]);
impl std::ops::Index<hwaddr> for DeviceId {
- type Output = c_uchar;
+ type Output = u8;
fn index(&self, idx: hwaddr) -> &Self::Output {
- match self {
- Self::Arm => &Self::PL011_ID_ARM[idx as usize],
- Self::Luminary => &Self::PL011_ID_LUMINARY[idx as usize],
- }
+ &self.0[idx as usize]
}
}
impl DeviceId {
- const PL011_ID_ARM: [c_uchar; 8] = [0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1];
- const PL011_ID_LUMINARY: [c_uchar; 8] = [0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1];
+ const ARM: Self = Self(&[0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1]);
+ const LUMINARY: Self = Self(&[0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1]);
}
// FIFOs use 32-bit indices instead of usize, for compatibility with
@@ -86,7 +79,7 @@ fn index(&self, idx: u32) -> &Self::Output {
#[derive(Debug, qemu_api_macros::Object, qemu_api_macros::offsets)]
/// PL011 Device Model in QEMU
pub struct PL011State {
- pub parent_obj: SysBusDevice,
+ pub parent_obj: ParentField<SysBusDevice>,
pub iomem: MemoryRegion,
#[doc(alias = "fr")]
pub flags: registers::Flags,
@@ -126,21 +119,33 @@ pub struct PL011State {
pub clock: NonNull<Clock>,
#[doc(alias = "migrate_clk")]
pub migrate_clock: bool,
- /// The byte string that identifies the device.
- device_id: DeviceId,
}
qom_isa!(PL011State : SysBusDevice, DeviceState, Object);
+pub struct PL011Class {
+ parent_class: <SysBusDevice as ObjectType>::Class,
+ /// The byte string that identifies the device.
+ device_id: DeviceId,
+}
+
unsafe impl ObjectType for PL011State {
- type Class = <SysBusDevice as ObjectType>::Class;
+ type Class = PL011Class;
const TYPE_NAME: &'static CStr = crate::TYPE_PL011;
}
+impl ClassInitImpl<PL011Class> for PL011State {
+ fn class_init(klass: &mut PL011Class) {
+ klass.device_id = DeviceId::ARM;
+ <Self as ClassInitImpl<SysBusDeviceClass>>::class_init(&mut klass.parent_class);
+ }
+}
+
impl ObjectImpl for PL011State {
type ParentType = SysBusDevice;
const INSTANCE_INIT: Option<unsafe fn(&mut Self)> = Some(Self::init);
+ const INSTANCE_POST_INIT: Option<fn(&Self)> = Some(Self::post_init);
}
impl DeviceImpl for PL011State {
@@ -179,14 +184,6 @@ unsafe fn init(&mut self) {
Self::TYPE_NAME.as_ptr(),
0x1000,
);
-
- let sbd: &mut SysBusDevice = self.upcast_mut();
- sysbus_init_mmio(sbd, addr_of_mut!(self.iomem));
- }
-
- for irq in self.interrupts.iter() {
- let sbd: &SysBusDevice = self.upcast();
- sbd.init_irq(irq);
}
// SAFETY:
@@ -209,12 +206,20 @@ unsafe fn init(&mut self) {
}
}
+ fn post_init(&self) {
+ self.init_mmio(&self.iomem);
+ for irq in self.interrupts.iter() {
+ self.init_irq(irq);
+ }
+ }
+
pub fn read(&mut self, offset: hwaddr, _size: c_uint) -> std::ops::ControlFlow<u64, u64> {
use RegisterOffset::*;
let value = match RegisterOffset::try_from(offset) {
Err(v) if (0x3f8..0x400).contains(&(v >> 2)) => {
- u32::from(self.device_id[(offset - 0xfe0) >> 2])
+ let device_id = self.get_class().device_id;
+ u32::from(device_id[(offset - 0xfe0) >> 2])
}
Err(_) => {
// qemu_log_mask(LOG_GUEST_ERROR, "pl011_read: Bad offset 0x%x\n", (int)offset);
@@ -645,19 +650,13 @@ pub fn post_load(&mut self, _version_id: u32) -> Result<(), ()> {
#[derive(Debug, qemu_api_macros::Object)]
/// PL011 Luminary device model.
pub struct PL011Luminary {
- parent_obj: PL011State,
+ parent_obj: ParentField<PL011State>,
}
-impl PL011Luminary {
- /// Initializes a pre-allocated, unitialized instance of `PL011Luminary`.
- ///
- /// # Safety
- ///
- /// We expect the FFI user of this function to pass a valid pointer, that
- /// has the same size as [`PL011Luminary`]. We also expect the device is
- /// readable/writeable from one thread at any time.
- unsafe fn init(&mut self) {
- self.parent_obj.device_id = DeviceId::Luminary;
+impl ClassInitImpl<PL011Class> for PL011Luminary {
+ fn class_init(klass: &mut PL011Class) {
+ klass.device_id = DeviceId::LUMINARY;
+ <Self as ClassInitImpl<SysBusDeviceClass>>::class_init(&mut klass.parent_class);
}
}
@@ -670,8 +669,6 @@ unsafe impl ObjectType for PL011Luminary {
impl ObjectImpl for PL011Luminary {
type ParentType = PL011State;
-
- const INSTANCE_INIT: Option<unsafe fn(&mut Self)> = Some(Self::init);
}
impl DeviceImpl for PL011Luminary {}
diff --git a/rust/hw/char/pl011/src/lib.rs b/rust/hw/char/pl011/src/lib.rs
index 69064d6..0a89d39 100644
--- a/rust/hw/char/pl011/src/lib.rs
+++ b/rust/hw/char/pl011/src/lib.rs
@@ -45,7 +45,7 @@
#[doc(alias = "offset")]
#[allow(non_camel_case_types)]
#[repr(u64)]
-#[derive(Debug)]
+#[derive(Debug, qemu_api_macros::TryInto)]
pub enum RegisterOffset {
/// Data Register
///
@@ -102,32 +102,6 @@ pub enum RegisterOffset {
//Reserved = 0x04C,
}
-impl core::convert::TryFrom<u64> for RegisterOffset {
- type Error = u64;
-
- fn try_from(value: u64) -> Result<Self, Self::Error> {
- macro_rules! case {
- ($($discriminant:ident),*$(,)*) => {
- /* check that matching on all macro arguments compiles, which means we are not
- * missing any enum value; if the type definition ever changes this will stop
- * compiling.
- */
- const fn _assert_exhaustive(val: RegisterOffset) {
- match val {
- $(RegisterOffset::$discriminant => (),)*
- }
- }
-
- match value {
- $(x if x == Self::$discriminant as u64 => Ok(Self::$discriminant),)*
- _ => Err(value),
- }
- }
- }
- case! { DR, RSR, FR, FBRD, ILPR, IBRD, LCR_H, CR, FLS, IMSC, RIS, MIS, ICR, DMACR }
- }
-}
-
pub mod registers {
//! Device registers exposed as typed structs which are backed by arbitrary
//! integer bitmaps. [`Data`], [`Control`], [`LineControl`], etc.
diff --git a/rust/qemu-api-macros/src/lib.rs b/rust/qemu-api-macros/src/lib.rs
index 74a8bc7..7ec2182 100644
--- a/rust/qemu-api-macros/src/lib.rs
+++ b/rust/qemu-api-macros/src/lib.rs
@@ -3,75 +3,81 @@
// SPDX-License-Identifier: GPL-2.0-or-later
use proc_macro::TokenStream;
-use proc_macro2::Span;
-use quote::{quote, quote_spanned};
+use quote::quote;
use syn::{
- parse_macro_input, parse_quote, punctuated::Punctuated, token::Comma, Data, DeriveInput, Field,
- Fields, Ident, Type, Visibility,
+ parse_macro_input, parse_quote, punctuated::Punctuated, spanned::Spanned, token::Comma, Data,
+ DeriveInput, Field, Fields, Ident, Meta, Path, Token, Type, Variant, Visibility,
};
-struct CompileError(String, Span);
+mod utils;
+use utils::MacroError;
-impl From<CompileError> for proc_macro2::TokenStream {
- fn from(err: CompileError) -> Self {
- let CompileError(msg, span) = err;
- quote_spanned! { span => compile_error!(#msg); }
+fn get_fields<'a>(
+ input: &'a DeriveInput,
+ msg: &str,
+) -> Result<&'a Punctuated<Field, Comma>, MacroError> {
+ if let Data::Struct(s) = &input.data {
+ if let Fields::Named(fs) = &s.fields {
+ Ok(&fs.named)
+ } else {
+ Err(MacroError::Message(
+ format!("Named fields required for {}", msg),
+ input.ident.span(),
+ ))
+ }
+ } else {
+ Err(MacroError::Message(
+ format!("Struct required for {}", msg),
+ input.ident.span(),
+ ))
}
}
-fn is_c_repr(input: &DeriveInput, msg: &str) -> Result<(), CompileError> {
+fn is_c_repr(input: &DeriveInput, msg: &str) -> Result<(), MacroError> {
let expected = parse_quote! { #[repr(C)] };
if input.attrs.iter().any(|attr| attr == &expected) {
Ok(())
} else {
- Err(CompileError(
+ Err(MacroError::Message(
format!("#[repr(C)] required for {}", msg),
input.ident.span(),
))
}
}
-#[proc_macro_derive(Object)]
-pub fn derive_object(input: TokenStream) -> TokenStream {
- let input = parse_macro_input!(input as DeriveInput);
- let name = input.ident;
+fn derive_object_or_error(input: DeriveInput) -> Result<proc_macro2::TokenStream, MacroError> {
+ is_c_repr(&input, "#[derive(Object)]")?;
- let expanded = quote! {
+ let name = &input.ident;
+ let parent = &get_fields(&input, "#[derive(Object)]")?[0].ident;
+
+ Ok(quote! {
+ ::qemu_api::assert_field_type!(#name, #parent,
+ ::qemu_api::qom::ParentField<<#name as ::qemu_api::qom::ObjectImpl>::ParentType>);
+
::qemu_api::module_init! {
MODULE_INIT_QOM => unsafe {
::qemu_api::bindings::type_register_static(&<#name as ::qemu_api::qom::ObjectImpl>::TYPE_INFO);
}
}
- };
+ })
+}
+
+#[proc_macro_derive(Object)]
+pub fn derive_object(input: TokenStream) -> TokenStream {
+ let input = parse_macro_input!(input as DeriveInput);
+ let expanded = derive_object_or_error(input).unwrap_or_else(Into::into);
TokenStream::from(expanded)
}
-fn get_fields(input: &DeriveInput) -> Result<&Punctuated<Field, Comma>, CompileError> {
- if let Data::Struct(s) = &input.data {
- if let Fields::Named(fs) = &s.fields {
- Ok(&fs.named)
- } else {
- Err(CompileError(
- "Cannot generate offsets for unnamed fields.".to_string(),
- input.ident.span(),
- ))
- }
- } else {
- Err(CompileError(
- "Cannot generate offsets for union or enum.".to_string(),
- input.ident.span(),
- ))
- }
-}
-
#[rustfmt::skip::macros(quote)]
-fn derive_offsets_or_error(input: DeriveInput) -> Result<proc_macro2::TokenStream, CompileError> {
+fn derive_offsets_or_error(input: DeriveInput) -> Result<proc_macro2::TokenStream, MacroError> {
is_c_repr(&input, "#[derive(offsets)]")?;
let name = &input.ident;
- let fields = get_fields(&input)?;
+ let fields = get_fields(&input, "#[derive(offsets)]")?;
let field_names: Vec<&Ident> = fields.iter().map(|f| f.ident.as_ref().unwrap()).collect();
let field_types: Vec<&Type> = fields.iter().map(|f| &f.ty).collect();
let field_vis: Vec<&Visibility> = fields.iter().map(|f| &f.vis).collect();
@@ -92,3 +98,73 @@ pub fn derive_offsets(input: TokenStream) -> TokenStream {
TokenStream::from(expanded)
}
+
+#[allow(non_snake_case)]
+fn get_repr_uN(input: &DeriveInput, msg: &str) -> Result<Path, MacroError> {
+ let repr = input.attrs.iter().find(|attr| attr.path().is_ident("repr"));
+ if let Some(repr) = repr {
+ let nested = repr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)?;
+ for meta in nested {
+ match meta {
+ Meta::Path(path) if path.is_ident("u8") => return Ok(path),
+ Meta::Path(path) if path.is_ident("u16") => return Ok(path),
+ Meta::Path(path) if path.is_ident("u32") => return Ok(path),
+ Meta::Path(path) if path.is_ident("u64") => return Ok(path),
+ _ => {}
+ }
+ }
+ }
+
+ Err(MacroError::Message(
+ format!("#[repr(u8/u16/u32/u64) required for {}", msg),
+ input.ident.span(),
+ ))
+}
+
+fn get_variants(input: &DeriveInput) -> Result<&Punctuated<Variant, Comma>, MacroError> {
+ if let Data::Enum(e) = &input.data {
+ if let Some(v) = e.variants.iter().find(|v| v.fields != Fields::Unit) {
+ return Err(MacroError::Message(
+ "Cannot derive TryInto for enum with non-unit variants.".to_string(),
+ v.fields.span(),
+ ));
+ }
+ Ok(&e.variants)
+ } else {
+ Err(MacroError::Message(
+ "Cannot derive TryInto for union or struct.".to_string(),
+ input.ident.span(),
+ ))
+ }
+}
+
+#[rustfmt::skip::macros(quote)]
+fn derive_tryinto_or_error(input: DeriveInput) -> Result<proc_macro2::TokenStream, MacroError> {
+ let repr = get_repr_uN(&input, "#[derive(TryInto)]")?;
+
+ let name = &input.ident;
+ let variants = get_variants(&input)?;
+ let discriminants: Vec<&Ident> = variants.iter().map(|f| &f.ident).collect();
+
+ Ok(quote! {
+ impl core::convert::TryFrom<#repr> for #name {
+ type Error = #repr;
+
+ fn try_from(value: #repr) -> Result<Self, Self::Error> {
+ #(const #discriminants: #repr = #name::#discriminants as #repr;)*;
+ match value {
+ #(#discriminants => Ok(Self::#discriminants),)*
+ _ => Err(value),
+ }
+ }
+ }
+ })
+}
+
+#[proc_macro_derive(TryInto)]
+pub fn derive_tryinto(input: TokenStream) -> TokenStream {
+ let input = parse_macro_input!(input as DeriveInput);
+ let expanded = derive_tryinto_or_error(input).unwrap_or_else(Into::into);
+
+ TokenStream::from(expanded)
+}
diff --git a/rust/qemu-api-macros/src/utils.rs b/rust/qemu-api-macros/src/utils.rs
new file mode 100644
index 0000000..02c91ae
--- /dev/null
+++ b/rust/qemu-api-macros/src/utils.rs
@@ -0,0 +1,26 @@
+// Procedural macro utilities.
+// Author(s): Paolo Bonzini <pbonzini@redhat.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+use proc_macro2::Span;
+use quote::quote_spanned;
+
+pub enum MacroError {
+ Message(String, Span),
+ ParseError(syn::Error),
+}
+
+impl From<syn::Error> for MacroError {
+ fn from(err: syn::Error) -> Self {
+ MacroError::ParseError(err)
+ }
+}
+
+impl From<MacroError> for proc_macro2::TokenStream {
+ fn from(err: MacroError) -> Self {
+ match err {
+ MacroError::Message(msg, span) => quote_spanned! { span => compile_error!(#msg); },
+ MacroError::ParseError(err) => err.into_compile_error(),
+ }
+ }
+}
diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build
index ccb20f3..60944a6 100644
--- a/rust/qemu-api/meson.build
+++ b/rust/qemu-api/meson.build
@@ -7,7 +7,7 @@
_qemu_api_cfg += ['--cfg', 'has_offset_of']
endif
if get_option('debug_mutex')
- _qemu_api_cfg += ['--feature', 'debug_cell']
+ _qemu_api_cfg += ['--cfg', 'feature="debug_cell"']
endif
_qemu_api_rs = static_library(
@@ -15,6 +15,7 @@
structured_sources(
[
'src/lib.rs',
+ 'src/assertions.rs',
'src/bindings.rs',
'src/bitops.rs',
'src/callbacks.rs',
diff --git a/rust/qemu-api/src/assertions.rs b/rust/qemu-api/src/assertions.rs
new file mode 100644
index 0000000..6e42046
--- /dev/null
+++ b/rust/qemu-api/src/assertions.rs
@@ -0,0 +1,90 @@
+// Copyright 2024, Red Hat Inc.
+// Author(s): Paolo Bonzini <pbonzini@redhat.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+//! This module provides macros to check the equality of types and
+//! the type of `struct` fields. This can be useful to ensure that
+//! types match the expectations of C code.
+
+// Based on https://stackoverflow.com/questions/64251852/x/70978292#70978292
+// (stackoverflow answers are released under MIT license).
+
+#[doc(hidden)]
+pub trait EqType {
+ type Itself;
+}
+
+impl<T> EqType for T {
+ type Itself = T;
+}
+
+/// Assert that two types are the same.
+///
+/// # Examples
+///
+/// ```
+/// # use qemu_api::assert_same_type;
+/// # use std::ops::Deref;
+/// assert_same_type!(u32, u32);
+/// assert_same_type!(<Box<u32> as Deref>::Target, u32);
+/// ```
+///
+/// Different types will cause a compile failure
+///
+/// ```compile_fail
+/// # use qemu_api::assert_same_type;
+/// assert_same_type!(&Box<u32>, &u32);
+/// ```
+#[macro_export]
+macro_rules! assert_same_type {
+ ($t1:ty, $t2:ty) => {
+ const _: () = {
+ #[allow(unused)]
+ fn assert_same_type(v: $t1) {
+ fn types_must_be_equal<T, U>(_: T)
+ where
+ T: $crate::assertions::EqType<Itself = U>,
+ {
+ }
+ types_must_be_equal::<_, $t2>(v);
+ }
+ };
+ };
+}
+
+/// Assert that a field of a struct has the given type.
+///
+/// # Examples
+///
+/// ```
+/// # use qemu_api::assert_field_type;
+/// pub struct A {
+/// field1: u32,
+/// }
+///
+/// assert_field_type!(A, field1, u32);
+/// ```
+///
+/// Different types will cause a compile failure
+///
+/// ```compile_fail
+/// # use qemu_api::assert_field_type;
+/// # pub struct A { field1: u32 }
+/// assert_field_type!(A, field1, i32);
+/// ```
+#[macro_export]
+macro_rules! assert_field_type {
+ ($t:ty, $i:tt, $ti:ty) => {
+ const _: () = {
+ #[allow(unused)]
+ fn assert_field_type(v: $t) {
+ fn types_must_be_equal<T, U>(_: T)
+ where
+ T: $crate::assertions::EqType<Itself = U>,
+ {
+ }
+ types_must_be_equal::<_, $ti>(v.$i);
+ }
+ };
+ };
+}
diff --git a/rust/qemu-api/src/irq.rs b/rust/qemu-api/src/irq.rs
index 6258141..378e520 100644
--- a/rust/qemu-api/src/irq.rs
+++ b/rust/qemu-api/src/irq.rs
@@ -24,8 +24,7 @@
///
/// Interrupts are implemented as a pointer to the interrupt "sink", which has
/// type [`IRQState`]. A device exposes its source as a QOM link property using
-/// a function such as
-/// [`SysBusDevice::init_irq`](crate::sysbus::SysBusDevice::init_irq), and
+/// a function such as [`SysBusDeviceMethods::init_irq`], and
/// initially leaves the pointer to a NULL value, representing an unconnected
/// interrupt. To connect it, whoever creates the device fills the pointer with
/// the sink's `IRQState *`, for example using `sysbus_connect_irq`. Because
diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs
index 4b43e02..83c6a98 100644
--- a/rust/qemu-api/src/lib.rs
+++ b/rust/qemu-api/src/lib.rs
@@ -12,6 +12,7 @@
#[rustfmt::skip]
pub mod prelude;
+pub mod assertions;
pub mod bitops;
pub mod c_str;
pub mod callbacks;
diff --git a/rust/qemu-api/src/prelude.rs b/rust/qemu-api/src/prelude.rs
index 6f32dee..4ea70b9 100644
--- a/rust/qemu-api/src/prelude.rs
+++ b/rust/qemu-api/src/prelude.rs
@@ -16,3 +16,5 @@
pub use crate::qom::ObjectType;
pub use crate::qom_isa;
+
+pub use crate::sysbus::SysBusDeviceMethods;
diff --git a/rust/qemu-api/src/qom.rs b/rust/qemu-api/src/qom.rs
index 7d5fbef..97901fb 100644
--- a/rust/qemu-api/src/qom.rs
+++ b/rust/qemu-api/src/qom.rs
@@ -55,6 +55,7 @@
use std::{
ffi::CStr,
+ fmt,
ops::{Deref, DerefMut},
os::raw::c_void,
};
@@ -105,6 +106,52 @@ fn as_ref(&self) -> &$parent {
};
}
+/// This is the same as [`ManuallyDrop<T>`](std::mem::ManuallyDrop), though
+/// it hides the standard methods of `ManuallyDrop`.
+///
+/// The first field of an `ObjectType` must be of type `ParentField<T>`.
+/// (Technically, this is only necessary if there is at least one Rust
+/// superclass in the hierarchy). This is to ensure that the parent field is
+/// dropped after the subclass; this drop order is enforced by the C
+/// `object_deinit` function.
+///
+/// # Examples
+///
+/// ```ignore
+/// #[repr(C)]
+/// #[derive(qemu_api_macros::Object)]
+/// pub struct MyDevice {
+/// parent: ParentField<DeviceState>,
+/// ...
+/// }
+/// ```
+#[derive(Debug)]
+#[repr(transparent)]
+pub struct ParentField<T: ObjectType>(std::mem::ManuallyDrop<T>);
+
+impl<T: ObjectType> Deref for ParentField<T> {
+ type Target = T;
+
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+impl<T: ObjectType> DerefMut for ParentField<T> {
+ #[inline(always)]
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.0
+ }
+}
+
+impl<T: fmt::Display + ObjectType> fmt::Display for ParentField<T> {
+ #[inline(always)]
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ self.0.fmt(f)
+ }
+}
+
unsafe extern "C" fn rust_instance_init<T: ObjectImpl>(obj: *mut Object) {
// SAFETY: obj is an instance of T, since rust_instance_init<T>
// is called from QOM core as the instance_init function
@@ -116,11 +163,7 @@ fn as_ref(&self) -> &$parent {
// SAFETY: obj is an instance of T, since rust_instance_post_init<T>
// is called from QOM core as the instance_post_init function
// for class T
- //
- // FIXME: it's not really guaranteed that there are no backpointers to
- // obj; it's quite possible that they have been created by instance_init().
- // The receiver should be &self, not &mut self.
- T::INSTANCE_POST_INIT.unwrap()(unsafe { &mut *obj.cast::<T>() })
+ T::INSTANCE_POST_INIT.unwrap()(unsafe { &*obj.cast::<T>() })
}
unsafe extern "C" fn rust_class_init<T: ObjectType + ClassInitImpl<T::Class>>(
@@ -133,6 +176,16 @@ fn as_ref(&self) -> &$parent {
T::class_init(unsafe { &mut *klass.cast::<T::Class>() })
}
+unsafe extern "C" fn drop_object<T: ObjectImpl>(obj: *mut Object) {
+ // SAFETY: obj is an instance of T, since drop_object<T> is called
+ // from the QOM core function object_deinit() as the instance_finalize
+ // function for class T. Note that while object_deinit() will drop the
+ // superclass field separately after this function returns, `T` must
+ // implement the unsafe trait ObjectType; the safety rules for the
+ // trait mandate that the parent field is manually dropped.
+ unsafe { std::ptr::drop_in_place(obj.cast::<T>()) }
+}
+
/// Trait exposed by all structs corresponding to QOM objects.
///
/// # Safety
@@ -151,11 +204,16 @@ fn as_ref(&self) -> &$parent {
///
/// - the struct must be `#[repr(C)]`;
///
-/// - the first field of the struct must be of the instance struct corresponding
-/// to the superclass, which is `ObjectImpl::ParentType`
+/// - the first field of the struct must be of type
+/// [`ParentField<T>`](ParentField), where `T` is the parent type
+/// [`ObjectImpl::ParentType`]
///
-/// - likewise, the first field of the `Class` must be of the class struct
-/// corresponding to the superclass, which is `ObjectImpl::ParentType::Class`.
+/// - the first field of the `Class` must be of the class struct corresponding
+/// to the superclass, which is `ObjectImpl::ParentType::Class`. `ParentField`
+/// is not needed here.
+///
+/// In both cases, having a separate class type is not necessary if the subclass
+/// does not add any field.
pub unsafe trait ObjectType: Sized {
/// The QOM class object corresponding to this struct. This is used
/// to automatically generate a `class_init` method.
@@ -384,13 +442,12 @@ impl<T: ObjectType> ObjectCastMut for &mut T {}
/// Trait a type must implement to be registered with QEMU.
pub trait ObjectImpl: ObjectType + ClassInitImpl<Self::Class> {
- /// The parent of the type. This should match the first field of
- /// the struct that implements `ObjectImpl`:
+ /// The parent of the type. This should match the first field of the
+ /// struct that implements `ObjectImpl`, minus the `ParentField<_>` wrapper.
type ParentType: ObjectType;
/// Whether the object can be instantiated
const ABSTRACT: bool = false;
- const INSTANCE_FINALIZE: Option<unsafe extern "C" fn(obj: *mut Object)> = None;
/// Function that is called to initialize an object. The parent class will
/// have already been initialized so the type is only responsible for
@@ -402,7 +459,7 @@ pub trait ObjectImpl: ObjectType + ClassInitImpl<Self::Class> {
/// Function that is called to finish initialization of an object, once
/// `INSTANCE_INIT` functions have been called.
- const INSTANCE_POST_INIT: Option<fn(&mut Self)> = None;
+ const INSTANCE_POST_INIT: Option<fn(&Self)> = None;
/// Called on descendent classes after all parent class initialization
/// has occurred, but before the class itself is initialized. This
@@ -426,7 +483,7 @@ pub trait ObjectImpl: ObjectType + ClassInitImpl<Self::Class> {
None => None,
Some(_) => Some(rust_instance_post_init::<Self>),
},
- instance_finalize: Self::INSTANCE_FINALIZE,
+ instance_finalize: Some(drop_object::<Self>),
abstract_: Self::ABSTRACT,
class_size: core::mem::size_of::<Self::Class>(),
class_init: Some(rust_class_init::<Self>),
diff --git a/rust/qemu-api/src/sysbus.rs b/rust/qemu-api/src/sysbus.rs
index 8193734..e6762b5 100644
--- a/rust/qemu-api/src/sysbus.rs
+++ b/rust/qemu-api/src/sysbus.rs
@@ -32,20 +32,33 @@ fn class_init(sdc: &mut SysBusDeviceClass) {
}
}
-impl SysBusDevice {
- /// Return `self` cast to a mutable pointer, for use in calls to C code.
- const fn as_mut_ptr(&self) -> *mut SysBusDevice {
- addr_of!(*self) as *mut _
+/// Trait for methods of [`SysBusDevice`] and its subclasses.
+pub trait SysBusDeviceMethods: ObjectDeref
+where
+ Self::Target: IsA<SysBusDevice>,
+{
+ /// Expose a memory region to the board so that it can give it an address
+ /// in guest memory. Note that the ordering of calls to `init_mmio` is
+ /// important, since whoever creates the sysbus device will refer to the
+ /// region with a number that corresponds to the order of calls to
+ /// `init_mmio`.
+ fn init_mmio(&self, iomem: &bindings::MemoryRegion) {
+ assert!(bql_locked());
+ unsafe {
+ bindings::sysbus_init_mmio(self.as_mut_ptr(), addr_of!(*iomem) as *mut _);
+ }
}
/// Expose an interrupt source outside the device as a qdev GPIO output.
/// Note that the ordering of calls to `init_irq` is important, since
/// whoever creates the sysbus device will refer to the interrupts with
/// a number that corresponds to the order of calls to `init_irq`.
- pub fn init_irq(&self, irq: &InterruptSource) {
+ fn init_irq(&self, irq: &InterruptSource) {
assert!(bql_locked());
unsafe {
bindings::sysbus_init_irq(self.as_mut_ptr(), irq.as_ptr());
}
}
}
+
+impl<R: ObjectDeref> SysBusDeviceMethods for R where R::Target: IsA<SysBusDevice> {}
diff --git a/rust/qemu-api/tests/tests.rs b/rust/qemu-api/tests/tests.rs
index 1d2825b..526c3f4 100644
--- a/rust/qemu-api/tests/tests.rs
+++ b/rust/qemu-api/tests/tests.rs
@@ -15,7 +15,7 @@
declare_properties, define_property,
prelude::*,
qdev::{DeviceImpl, DeviceState, Property},
- qom::ObjectImpl,
+ qom::{ObjectImpl, ParentField},
vmstate::VMStateDescription,
zeroable::Zeroable,
};
@@ -31,7 +31,7 @@
#[repr(C)]
#[derive(qemu_api_macros::Object)]
pub struct DummyState {
- parent: DeviceState,
+ parent: ParentField<DeviceState>,
migrate_clock: bool,
}
diff --git a/scripts/cocci-macro-file.h b/scripts/cocci-macro-file.h
index d247a50..c64831d 100644
--- a/scripts/cocci-macro-file.h
+++ b/scripts/cocci-macro-file.h
@@ -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)
diff --git a/scripts/make-release b/scripts/make-release
index 8dc9391..2885e872 100755
--- a/scripts/make-release
+++ b/scripts/make-release
@@ -10,6 +10,27 @@
# This work is licensed under the terms of the GNU GPLv2 or later.
# See the COPYING file in the top-level directory.
+function subproject_dir() {
+ if test ! -f "subprojects/$1.wrap"; then
+ error "scripts/archive-source.sh should only process wrap subprojects"
+ fi
+
+ # Print the directory key of the wrap file, defaulting to the
+ # subproject name. The wrap file is in ini format and should
+ # have a single section only. There should be only one section
+ # named "[wrap-*]", which helps keeping the script simple.
+ local dir
+ dir=$(sed -n \
+ -e '/^\[wrap-[a-z][a-z]*\]$/,/^\[/{' \
+ -e '/^directory *= */!b' \
+ -e 's///p' \
+ -e 'q' \
+ -e '}' \
+ "subprojects/$1.wrap")
+
+ echo "${dir:-$1}"
+}
+
if [ $# -ne 2 ]; then
echo "Usage:"
echo " $0 gitrepo version"
@@ -51,5 +72,13 @@
CryptoPkg/Library/OpensslLib/openssl \
MdeModulePkg/Library/BrotliCustomDecompressLib/brotli)
popd
-tar --exclude=.git -cJf ${destination}.tar.xz ${destination}
+
+exclude=(--exclude=.git)
+# include the tarballs in subprojects/packagecache but not their expansion
+for sp in $SUBPROJECTS; do
+ if grep -xqF "[wrap-file]" subprojects/$sp.wrap; then
+ exclude+=(--exclude=subprojects/"$(subproject_dir $sp)")
+ fi
+done
+tar "${exclude[@]}" -cJf ${destination}.tar.xz ${destination}
rm -rf ${destination}
diff --git a/scripts/nsis.py b/scripts/nsis.py
index 03ed760..af4e064 100644
--- a/scripts/nsis.py
+++ b/scripts/nsis.py
@@ -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)
diff --git a/scripts/rust/rustc_args.py b/scripts/rust/rustc_args.py
index 5525b38..2633157 100644
--- a/scripts/rust/rustc_args.py
+++ b/scripts/rust/rustc_args.py
@@ -215,6 +215,8 @@ def main() -> None:
if rustc_version >= (1, 80):
if args.lints:
+ print("--check-cfg")
+ print("cfg(test)")
for cfg in sorted(cargo_toml.check_cfg):
print("--check-cfg")
print(cfg)
diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index d78c642..86e5260 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -166,6 +166,7 @@
#endif
+#include "cpu.h"
#include "common-semi-target.h"
/*
diff --git a/semihosting/console.c b/semihosting/console.c
index 60102bb..c3683a1 100644
--- a/semihosting/console.c
+++ b/semihosting/console.c
@@ -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 {
diff --git a/semihosting/meson.build b/semihosting/meson.build
index 34933e5..86f5004 100644
--- a/semihosting/meson.build
+++ b/semihosting/meson.build
@@ -4,13 +4,16 @@
))
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'))
diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
index c40348f..f6451d9 100644
--- a/semihosting/syscalls.c
+++ b/semihosting/syscalls.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 @@
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();
diff --git a/semihosting/uaccess.c b/semihosting/uaccess.c
index dc587d7..382a366 100644
--- a/semihosting/uaccess.c
+++ b/semihosting/uaccess.c
@@ -8,6 +8,7 @@
*/
#include "qemu/osdep.h"
+#include "exec/cpu-all.h"
#include "exec/exec-all.h"
#include "semihosting/uaccess.h"
diff --git a/subprojects/arbitrary-int-1-rs.wrap b/subprojects/arbitrary-int-1-rs.wrap
index e580538..a1838b2 100644
--- a/subprojects/arbitrary-int-1-rs.wrap
+++ b/subprojects/arbitrary-int-1-rs.wrap
@@ -5,3 +5,6 @@
source_hash = c84fc003e338a6f69fbd4f7fe9f92b535ff13e9af8997f3b14b6ddff8b1df46d
#method = cargo
patch_directory = arbitrary-int-1-rs
+
+# bump this version number on every change to meson.build or the patches:
+# v2
diff --git a/subprojects/bilge-0.2-rs.wrap b/subprojects/bilge-0.2-rs.wrap
index 7a4339d..900bb14 100644
--- a/subprojects/bilge-0.2-rs.wrap
+++ b/subprojects/bilge-0.2-rs.wrap
@@ -5,3 +5,6 @@
source_hash = dc707ed8ebf81de5cd6c7f48f54b4c8621760926cdf35a57000747c512e67b57
#method = cargo
patch_directory = bilge-0.2-rs
+
+# bump this version number on every change to meson.build or the patches:
+# v2
diff --git a/subprojects/bilge-impl-0.2-rs.wrap b/subprojects/bilge-impl-0.2-rs.wrap
index b24c34a..d14c3dc 100644
--- a/subprojects/bilge-impl-0.2-rs.wrap
+++ b/subprojects/bilge-impl-0.2-rs.wrap
@@ -6,3 +6,6 @@
#method = cargo
patch_directory = bilge-impl-0.2-rs
diff_files = bilge-impl-1.63.0.patch
+
+# bump this version number on every change to meson.build or the patches:
+# v2
diff --git a/subprojects/either-1-rs.wrap b/subprojects/either-1-rs.wrap
index 6046712..352e11c 100644
--- a/subprojects/either-1-rs.wrap
+++ b/subprojects/either-1-rs.wrap
@@ -5,3 +5,6 @@
source_hash = 3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b
#method = cargo
patch_directory = either-1-rs
+
+# bump this version number on every change to meson.build or the patches:
+# v2
diff --git a/subprojects/itertools-0.11-rs.wrap b/subprojects/itertools-0.11-rs.wrap
index 66b0525..ee12d00 100644
--- a/subprojects/itertools-0.11-rs.wrap
+++ b/subprojects/itertools-0.11-rs.wrap
@@ -5,3 +5,6 @@
source_hash = b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57
#method = cargo
patch_directory = itertools-0.11-rs
+
+# bump this version number on every change to meson.build or the patches:
+# v2
diff --git a/subprojects/libvhost-user/libvhost-user.h b/subprojects/libvhost-user/libvhost-user.h
index deb40e7..2ffc58c 100644
--- a/subprojects/libvhost-user/libvhost-user.h
+++ b/subprojects/libvhost-user/libvhost-user.h
@@ -186,11 +186,7 @@
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;
diff --git a/subprojects/packagefiles/arbitrary-int-1-rs/meson.build b/subprojects/packagefiles/arbitrary-int-1-rs/meson.build
index cff3f62..00733d1 100644
--- a/subprojects/packagefiles/arbitrary-int-1-rs/meson.build
+++ b/subprojects/packagefiles/arbitrary-int-1-rs/meson.build
@@ -9,6 +9,7 @@
files('src/lib.rs'),
gnu_symbol_visibility: 'hidden',
override_options: ['rust_std=2021', 'build.rust_std=2021'],
+ rust_args: ['--cap-lints', 'allow'],
rust_abi: 'rust',
dependencies: [],
)
diff --git a/subprojects/packagefiles/bilge-0.2-rs/meson.build b/subprojects/packagefiles/bilge-0.2-rs/meson.build
index e69bac9..ce13d0f 100644
--- a/subprojects/packagefiles/bilge-0.2-rs/meson.build
+++ b/subprojects/packagefiles/bilge-0.2-rs/meson.build
@@ -17,6 +17,7 @@
'src/lib.rs',
override_options : ['rust_std=2021', 'build.rust_std=2021'],
rust_abi : 'rust',
+ rust_args: ['--cap-lints', 'allow'],
dependencies: [
arbitrary_int_dep,
bilge_impl_dep,
diff --git a/subprojects/packagefiles/bilge-impl-0.2-rs/meson.build b/subprojects/packagefiles/bilge-impl-0.2-rs/meson.build
index f8f3486..42b03dc 100644
--- a/subprojects/packagefiles/bilge-impl-0.2-rs/meson.build
+++ b/subprojects/packagefiles/bilge-impl-0.2-rs/meson.build
@@ -25,6 +25,7 @@
files('src/lib.rs'),
override_options: ['rust_std=2021', 'build.rust_std=2021'],
rust_args: [
+ '--cap-lints', 'allow',
'--cfg', 'use_fallback',
'--cfg', 'feature="syn-error"',
'--cfg', 'feature="proc-macro"',
diff --git a/subprojects/packagefiles/either-1-rs/meson.build b/subprojects/packagefiles/either-1-rs/meson.build
index 608e64e..04c96cc 100644
--- a/subprojects/packagefiles/either-1-rs/meson.build
+++ b/subprojects/packagefiles/either-1-rs/meson.build
@@ -11,6 +11,7 @@
override_options: ['rust_std=2018', 'build.rust_std=2018'],
rust_abi: 'rust',
rust_args: [
+ '--cap-lints', 'allow',
'--cfg', 'feature="use_std"',
'--cfg', 'feature="use_alloc"',
],
diff --git a/subprojects/packagefiles/itertools-0.11-rs/meson.build b/subprojects/packagefiles/itertools-0.11-rs/meson.build
index 30982a4..2a3fbe9 100644
--- a/subprojects/packagefiles/itertools-0.11-rs/meson.build
+++ b/subprojects/packagefiles/itertools-0.11-rs/meson.build
@@ -15,6 +15,7 @@
override_options: ['rust_std=2018', 'build.rust_std=2018'],
rust_abi: 'rust',
rust_args: [
+ '--cap-lints', 'allow',
'--cfg', 'feature="use_std"',
'--cfg', 'feature="use_alloc"',
],
diff --git a/subprojects/packagefiles/proc-macro-error-1-rs/meson.build b/subprojects/packagefiles/proc-macro-error-1-rs/meson.build
index ae27a69..10c2741 100644
--- a/subprojects/packagefiles/proc-macro-error-1-rs/meson.build
+++ b/subprojects/packagefiles/proc-macro-error-1-rs/meson.build
@@ -20,6 +20,7 @@
override_options: ['rust_std=2018', 'build.rust_std=2018'],
rust_abi: 'rust',
rust_args: [
+ '--cap-lints', 'allow',
'--cfg', 'use_fallback',
'--cfg', 'feature="syn-error"',
'--cfg', 'feature="proc-macro"',
diff --git a/subprojects/packagefiles/proc-macro-error-attr-1-rs/meson.build b/subprojects/packagefiles/proc-macro-error-attr-1-rs/meson.build
index 3281b26..c4c4c5e 100644
--- a/subprojects/packagefiles/proc-macro-error-attr-1-rs/meson.build
+++ b/subprojects/packagefiles/proc-macro-error-attr-1-rs/meson.build
@@ -16,6 +16,7 @@
files('src/lib.rs'),
override_options: ['rust_std=2018', 'build.rust_std=2018'],
rust_args: [
+ '--cap-lints', 'allow',
'--cfg', 'use_fallback',
'--cfg', 'feature="syn-error"',
'--cfg', 'feature="proc-macro"'
diff --git a/subprojects/packagefiles/proc-macro2-1-rs/meson.build b/subprojects/packagefiles/proc-macro2-1-rs/meson.build
index f9c8675..5759df3 100644
--- a/subprojects/packagefiles/proc-macro2-1-rs/meson.build
+++ b/subprojects/packagefiles/proc-macro2-1-rs/meson.build
@@ -15,6 +15,7 @@
override_options: ['rust_std=2021', 'build.rust_std=2021'],
rust_abi: 'rust',
rust_args: [
+ '--cap-lints', 'allow',
'--cfg', 'feature="proc-macro"',
'--cfg', 'no_literal_byte_character',
'--cfg', 'no_literal_c_string',
diff --git a/subprojects/packagefiles/quote-1-rs/meson.build b/subprojects/packagefiles/quote-1-rs/meson.build
index 7f77925..bf41fad 100644
--- a/subprojects/packagefiles/quote-1-rs/meson.build
+++ b/subprojects/packagefiles/quote-1-rs/meson.build
@@ -15,6 +15,7 @@
override_options: ['rust_std=2021', 'build.rust_std=2021'],
rust_abi: 'rust',
rust_args: [
+ '--cap-lints', 'allow',
'--cfg', 'feature="proc-macro"',
],
dependencies: [
diff --git a/subprojects/packagefiles/syn-2-rs/meson.build b/subprojects/packagefiles/syn-2-rs/meson.build
index 2c62cf7..a009417 100644
--- a/subprojects/packagefiles/syn-2-rs/meson.build
+++ b/subprojects/packagefiles/syn-2-rs/meson.build
@@ -19,6 +19,7 @@
override_options: ['rust_std=2021', 'build.rust_std=2021'],
rust_abi: 'rust',
rust_args: [
+ '--cap-lints', 'allow',
'--cfg', 'feature="full"',
'--cfg', 'feature="derive"',
'--cfg', 'feature="parsing"',
diff --git a/subprojects/packagefiles/unicode-ident-1-rs/meson.build b/subprojects/packagefiles/unicode-ident-1-rs/meson.build
index 9d76ebb..11a5dab 100644
--- a/subprojects/packagefiles/unicode-ident-1-rs/meson.build
+++ b/subprojects/packagefiles/unicode-ident-1-rs/meson.build
@@ -10,6 +10,7 @@
gnu_symbol_visibility: 'hidden',
override_options: ['rust_std=2021', 'build.rust_std=2021'],
rust_abi: 'rust',
+ rust_args: ['--cap-lints', 'allow'],
dependencies: [],
native: true,
)
diff --git a/subprojects/proc-macro-error-1-rs.wrap b/subprojects/proc-macro-error-1-rs.wrap
index b7db03b..59f892f 100644
--- a/subprojects/proc-macro-error-1-rs.wrap
+++ b/subprojects/proc-macro-error-1-rs.wrap
@@ -5,3 +5,6 @@
source_hash = da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c
#method = cargo
patch_directory = proc-macro-error-1-rs
+
+# bump this version number on every change to meson.build or the patches:
+# v2
diff --git a/subprojects/proc-macro-error-attr-1-rs.wrap b/subprojects/proc-macro-error-attr-1-rs.wrap
index d13d8a2..5aeb224 100644
--- a/subprojects/proc-macro-error-attr-1-rs.wrap
+++ b/subprojects/proc-macro-error-attr-1-rs.wrap
@@ -5,3 +5,6 @@
source_hash = a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869
#method = cargo
patch_directory = proc-macro-error-attr-1-rs
+
+# bump this version number on every change to meson.build or the patches:
+# v2
diff --git a/subprojects/proc-macro2-1-rs.wrap b/subprojects/proc-macro2-1-rs.wrap
index 7053e2c..6c9369f 100644
--- a/subprojects/proc-macro2-1-rs.wrap
+++ b/subprojects/proc-macro2-1-rs.wrap
@@ -5,3 +5,6 @@
source_hash = ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6
#method = cargo
patch_directory = proc-macro2-1-rs
+
+# bump this version number on every change to meson.build or the patches:
+# v2
diff --git a/subprojects/quote-1-rs.wrap b/subprojects/quote-1-rs.wrap
index 6e7ea69..8b721df 100644
--- a/subprojects/quote-1-rs.wrap
+++ b/subprojects/quote-1-rs.wrap
@@ -5,3 +5,6 @@
source_hash = 0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7
#method = cargo
patch_directory = quote-1-rs
+
+# bump this version number on every change to meson.build or the patches:
+# v2
diff --git a/subprojects/syn-2-rs.wrap b/subprojects/syn-2-rs.wrap
index 13ffdac..d79cf75 100644
--- a/subprojects/syn-2-rs.wrap
+++ b/subprojects/syn-2-rs.wrap
@@ -5,3 +5,6 @@
source_hash = c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5
#method = cargo
patch_directory = syn-2-rs
+
+# bump this version number on every change to meson.build or the patches:
+# v2
diff --git a/subprojects/unicode-ident-1-rs.wrap b/subprojects/unicode-ident-1-rs.wrap
index 4609f96..50988f6 100644
--- a/subprojects/unicode-ident-1-rs.wrap
+++ b/subprojects/unicode-ident-1-rs.wrap
@@ -5,3 +5,6 @@
source_hash = 3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b
#method = cargo
patch_directory = unicode-ident-1-rs
+
+# bump this version number on every change to meson.build or the patches:
+# v2
diff --git a/subprojects/unicode-ident-1-rs/meson.build b/subprojects/unicode-ident-1-rs/meson.build
deleted file mode 100644
index 54f2376..0000000
--- a/subprojects/unicode-ident-1-rs/meson.build
+++ /dev/null
@@ -1,20 +0,0 @@
-project('unicode-ident-1-rs', 'rust',
- version: '1.0.12',
- license: '(MIT OR Apache-2.0) AND Unicode-DFS-2016',
- default_options: [])
-
-_unicode_ident_rs = static_library(
- 'unicode_ident',
- files('src/lib.rs'),
- gnu_symbol_visibility: 'hidden',
- override_options: ['rust_std=2021', 'build.rust_std=2021'],
- rust_abi: 'rust',
- dependencies: [],
- native: true,
-)
-
-unicode_ident_dep = declare_dependency(
- link_with: _unicode_ident_rs,
-)
-
-meson.override_dependency('unicode-ident-1-rs', unicode_ident_dep, native: true)
diff --git a/system/cpus.c b/system/cpus.c
index 99f8380..37e5892 100644
--- a/system/cpus.c
+++ b/system/cpus.c
@@ -687,7 +687,6 @@
{
MachineState *ms = MACHINE(qdev_get_machine());
- cpu->nr_cores = machine_topo_get_cores_per_socket(ms);
cpu->nr_threads = ms->smp.threads;
cpu->stopped = true;
cpu->random_seed = qemu_guest_random_seed_thread_part1();
diff --git a/system/vl.c b/system/vl.c
index be029c5..c567826 100644
--- a/system/vl.c
+++ b/system/vl.c
@@ -811,29 +811,15 @@
/***********************************************************/
/* 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 @@
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 int serial_parse(const char *devname)
+static bool serial_parse(const char *devname, Error **errp)
{
int index = num_serial_hds;
@@ -1467,13 +1458,13 @@
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 @@
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 @@
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 @@
/* 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 @@
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 "
diff --git a/target/i386/confidential-guest.h b/target/i386/confidential-guest.h
index 0afb831..164be76 100644
--- a/target/i386/confidential-guest.h
+++ b/target/i386/confidential-guest.h
@@ -46,7 +46,7 @@
/**
* x86_confidential_guest_kvm_type:
*
- * Calls #X86ConfidentialGuestClass.unplug callback of @plug_handler.
+ * Calls #X86ConfidentialGuestClass.kvm_type() callback.
*/
static inline int x86_confidential_guest_kvm_type(X86ConfidentialGuest *cg)
{
diff --git a/target/i386/cpu-system.c b/target/i386/cpu-system.c
index 9d007af..b56a282 100644
--- a/target/i386/cpu-system.c
+++ b/target/i386/cpu-system.c
@@ -309,3 +309,14 @@
errp);
qapi_free_GuestPanicInformation(panic_info);
}
+
+uint64_t cpu_x86_get_msr_core_thread_count(X86CPU *cpu)
+{
+ CPUX86State *env = &cpu->env;
+ uint64_t val;
+
+ val = x86_threads_per_pkg(&env->topo_info); /* thread count, bits 15..0 */
+ val |= x86_cores_per_pkg(&env->topo_info) << 16; /* core count, bits 31..16 */
+
+ return val;
+}
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 0b63984..1b9c110 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -312,13 +312,11 @@
case CPU_TOPOLOGY_LEVEL_CORE:
return topo_info->threads_per_core;
case CPU_TOPOLOGY_LEVEL_MODULE:
- return topo_info->threads_per_core * topo_info->cores_per_module;
+ return x86_threads_per_module(topo_info);
case CPU_TOPOLOGY_LEVEL_DIE:
- return topo_info->threads_per_core * topo_info->cores_per_module *
- topo_info->modules_per_die;
+ return x86_threads_per_die(topo_info);
case CPU_TOPOLOGY_LEVEL_SOCKET:
- return topo_info->threads_per_core * topo_info->cores_per_module *
- topo_info->modules_per_die * topo_info->dies_per_pkg;
+ return x86_threads_per_pkg(topo_info);
default:
g_assert_not_reached();
}
@@ -6498,18 +6496,10 @@
CPUState *cs = env_cpu(env);
uint32_t limit;
uint32_t signature[3];
- X86CPUTopoInfo topo_info;
- uint32_t cores_per_pkg;
+ X86CPUTopoInfo *topo_info = &env->topo_info;
uint32_t threads_per_pkg;
- topo_info.dies_per_pkg = env->nr_dies;
- topo_info.modules_per_die = env->nr_modules;
- topo_info.cores_per_module = cs->nr_cores / env->nr_dies / env->nr_modules;
- topo_info.threads_per_core = cs->nr_threads;
-
- cores_per_pkg = topo_info.cores_per_module * topo_info.modules_per_die *
- topo_info.dies_per_pkg;
- threads_per_pkg = cores_per_pkg * topo_info.threads_per_core;
+ threads_per_pkg = x86_threads_per_pkg(topo_info);
/* Calculate & apply limits for different index ranges */
if (index >= 0xC0000000) {
@@ -6548,7 +6538,6 @@
*edx = env->features[FEAT_1_EDX];
if (threads_per_pkg > 1) {
*ebx |= threads_per_pkg << 16;
- *edx |= CPUID_HT;
}
if (!cpu->enable_pmu) {
*ecx &= ~CPUID_EXT_PDCM;
@@ -6586,12 +6575,12 @@
int host_vcpus_per_cache = 1 + ((*eax & 0x3FFC000) >> 14);
*eax &= ~0xFC000000;
- *eax |= max_core_ids_in_package(&topo_info) << 26;
+ *eax |= max_core_ids_in_package(topo_info) << 26;
if (host_vcpus_per_cache > threads_per_pkg) {
*eax &= ~0x3FFC000;
/* Share the cache at package level. */
- *eax |= max_thread_ids_for_cache(&topo_info,
+ *eax |= max_thread_ids_for_cache(topo_info,
CPU_TOPOLOGY_LEVEL_SOCKET) << 14;
}
}
@@ -6603,7 +6592,7 @@
switch (count) {
case 0: /* L1 dcache info */
encode_cache_cpuid4(env->cache_info_cpuid4.l1d_cache,
- &topo_info,
+ topo_info,
eax, ebx, ecx, edx);
if (!cpu->l1_cache_per_core) {
*eax &= ~MAKE_64BIT_MASK(14, 12);
@@ -6611,7 +6600,7 @@
break;
case 1: /* L1 icache info */
encode_cache_cpuid4(env->cache_info_cpuid4.l1i_cache,
- &topo_info,
+ topo_info,
eax, ebx, ecx, edx);
if (!cpu->l1_cache_per_core) {
*eax &= ~MAKE_64BIT_MASK(14, 12);
@@ -6619,13 +6608,13 @@
break;
case 2: /* L2 cache info */
encode_cache_cpuid4(env->cache_info_cpuid4.l2_cache,
- &topo_info,
+ topo_info,
eax, ebx, ecx, edx);
break;
case 3: /* L3 cache info */
if (cpu->enable_l3_cache) {
encode_cache_cpuid4(env->cache_info_cpuid4.l3_cache,
- &topo_info,
+ topo_info,
eax, ebx, ecx, edx);
break;
}
@@ -6708,12 +6697,12 @@
switch (count) {
case 0:
- *eax = apicid_core_offset(&topo_info);
- *ebx = topo_info.threads_per_core;
+ *eax = apicid_core_offset(topo_info);
+ *ebx = topo_info->threads_per_core;
*ecx |= CPUID_B_ECX_TOPO_LEVEL_SMT << 8;
break;
case 1:
- *eax = apicid_pkg_offset(&topo_info);
+ *eax = apicid_pkg_offset(topo_info);
*ebx = threads_per_pkg;
*ecx |= CPUID_B_ECX_TOPO_LEVEL_CORE << 8;
break;
@@ -6739,7 +6728,7 @@
break;
}
- encode_topo_cpuid1f(env, count, &topo_info, eax, ebx, ecx, edx);
+ encode_topo_cpuid1f(env, count, topo_info, eax, ebx, ecx, edx);
break;
case 0xD: {
/* Processor Extended State */
@@ -6964,17 +6953,6 @@
*ecx = env->features[FEAT_8000_0001_ECX];
*edx = env->features[FEAT_8000_0001_EDX];
- /* The Linux kernel checks for the CMPLegacy bit and
- * discards multiple thread information if it is set.
- * So don't set it here for Intel to make Linux guests happy.
- */
- if (threads_per_pkg > 1) {
- if (env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1 ||
- env->cpuid_vendor2 != CPUID_VENDOR_INTEL_2 ||
- env->cpuid_vendor3 != CPUID_VENDOR_INTEL_3) {
- *ecx |= 1 << 1; /* CmpLegacy bit */
- }
- }
if (tcg_enabled() && env->cpuid_vendor1 == CPUID_VENDOR_INTEL_1 &&
!(env->hflags & HF_LMA_MASK)) {
*edx &= ~CPUID_EXT2_SYSCALL;
@@ -7042,7 +7020,7 @@
* thread ID within a package".
* Bits 7:0 is "The number of threads in the package is NC+1"
*/
- *ecx = (apicid_pkg_offset(&topo_info) << 12) |
+ *ecx = (apicid_pkg_offset(topo_info) << 12) |
(threads_per_pkg - 1);
} else {
*ecx = 0;
@@ -7071,19 +7049,19 @@
switch (count) {
case 0: /* L1 dcache info */
encode_cache_cpuid8000001d(env->cache_info_amd.l1d_cache,
- &topo_info, eax, ebx, ecx, edx);
+ topo_info, eax, ebx, ecx, edx);
break;
case 1: /* L1 icache info */
encode_cache_cpuid8000001d(env->cache_info_amd.l1i_cache,
- &topo_info, eax, ebx, ecx, edx);
+ topo_info, eax, ebx, ecx, edx);
break;
case 2: /* L2 cache info */
encode_cache_cpuid8000001d(env->cache_info_amd.l2_cache,
- &topo_info, eax, ebx, ecx, edx);
+ topo_info, eax, ebx, ecx, edx);
break;
case 3: /* L3 cache info */
encode_cache_cpuid8000001d(env->cache_info_amd.l3_cache,
- &topo_info, eax, ebx, ecx, edx);
+ topo_info, eax, ebx, ecx, edx);
break;
default: /* end of info */
*eax = *ebx = *ecx = *edx = 0;
@@ -7095,7 +7073,7 @@
break;
case 0x8000001E:
if (cpu->core_id <= 255) {
- encode_topo_cpuid8000001e(cpu, &topo_info, eax, ebx, ecx, edx);
+ encode_topo_cpuid8000001e(cpu, topo_info, eax, ebx, ecx, edx);
} else {
*eax = 0;
*ebx = 0;
@@ -7539,6 +7517,19 @@
}
}
+ if (x86_threads_per_pkg(&env->topo_info) > 1) {
+ env->features[FEAT_1_EDX] |= CPUID_HT;
+
+ /*
+ * The Linux kernel checks for the CMPLegacy bit and
+ * discards multiple thread information if it is set.
+ * So don't set it here for Intel to make Linux guests happy.
+ */
+ if (!IS_INTEL_CPU(env)) {
+ env->features[FEAT_8000_0001_ECX] |= CPUID_EXT3_CMP_LEG;
+ }
+ }
+
for (i = 0; i < ARRAY_SIZE(feature_dependencies); i++) {
FeatureDep *d = &feature_dependencies[i];
if (!(env->features[d->from.index] & d->from.mask)) {
@@ -7719,8 +7710,10 @@
env->avx10_version = version;
have_filtered_features = true;
}
- } else if (env->avx10_version && prefix) {
- warn_report("%s: avx10.%d.", prefix, env->avx10_version);
+ } else if (env->avx10_version) {
+ if (prefix) {
+ warn_report("%s: avx10.%d.", prefix, env->avx10_version);
+ }
have_filtered_features = true;
}
@@ -7891,6 +7884,21 @@
*/
cpu->mwait.ecx |= CPUID_MWAIT_EMX | CPUID_MWAIT_IBE;
+ /*
+ * Most Intel and certain AMD CPUs support hyperthreading. Even though QEMU
+ * fixes this issue by adjusting CPUID_0000_0001_EBX and CPUID_8000_0008_ECX
+ * based on inputs (sockets,cores,threads), it is still better to give
+ * users a warning.
+ */
+ if (IS_AMD_CPU(env) &&
+ !(env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_TOPOEXT) &&
+ env->topo_info.threads_per_core > 1) {
+ warn_report_once("This family of AMD CPU doesn't support "
+ "hyperthreading(%d). Please configure -smp "
+ "options properly or try enabling topoext "
+ "feature.", env->topo_info.threads_per_core);
+ }
+
/* For 64bit systems think about the number of physical bits to present.
* ideally this should be the same as the host; anything other than matching
* the host can cause incorrect guest behaviour.
@@ -7995,24 +8003,6 @@
x86_cpu_gdb_init(cs);
qemu_init_vcpu(cs);
- /*
- * Most Intel and certain AMD CPUs support hyperthreading. Even though QEMU
- * fixes this issue by adjusting CPUID_0000_0001_EBX and CPUID_8000_0008_ECX
- * based on inputs (sockets,cores,threads), it is still better to give
- * users a warning.
- *
- * NOTE: the following code has to follow qemu_init_vcpu(). Otherwise
- * cs->nr_threads hasn't be populated yet and the checking is incorrect.
- */
- if (IS_AMD_CPU(env) &&
- !(env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_TOPOEXT) &&
- cs->nr_threads > 1) {
- warn_report_once("This family of AMD CPU doesn't support "
- "hyperthreading(%d). Please configure -smp "
- "options properly or try enabling topoext "
- "feature.", cs->nr_threads);
- }
-
#ifndef CONFIG_USER_ONLY
x86_cpu_apic_realize(cpu, &local_err);
if (local_err != NULL) {
@@ -8171,8 +8161,7 @@
{
CPUX86State *env = &cpu->env;
- env->nr_modules = 1;
- env->nr_dies = 1;
+ env->topo_info = (X86CPUTopoInfo) {1, 1, 1, 1};
/* thread, core and socket levels are set by default. */
set_bit(CPU_TOPOLOGY_LEVEL_THREAD, env->avail_cpu_topo);
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index dbd8f1f..b26e25b 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -29,6 +29,7 @@
#include "qapi/qapi-types-common.h"
#include "qemu/cpu-float.h"
#include "qemu/timer.h"
+#include "standard-headers/asm-x86/kvm_para.h"
#define XEN_NR_VIRQS 24
@@ -1010,6 +1011,28 @@
#define CPUID_8000_0007_EBX_OVERFLOW_RECOV (1U << 0)
#define CPUID_8000_0007_EBX_SUCCOR (1U << 1)
+/* (Old) KVM paravirtualized clocksource */
+#define CPUID_KVM_CLOCK (1U << KVM_FEATURE_CLOCKSOURCE)
+/* (New) KVM specific paravirtualized clocksource */
+#define CPUID_KVM_CLOCK2 (1U << KVM_FEATURE_CLOCKSOURCE2)
+/* KVM asynchronous page fault */
+#define CPUID_KVM_ASYNCPF (1U << KVM_FEATURE_ASYNC_PF)
+/* KVM stolen (when guest vCPU is not running) time accounting */
+#define CPUID_KVM_STEAL_TIME (1U << KVM_FEATURE_STEAL_TIME)
+/* KVM paravirtualized end-of-interrupt signaling */
+#define CPUID_KVM_PV_EOI (1U << KVM_FEATURE_PV_EOI)
+/* KVM paravirtualized spinlocks support */
+#define CPUID_KVM_PV_UNHALT (1U << KVM_FEATURE_PV_UNHALT)
+/* KVM host-side polling on HLT control from the guest */
+#define CPUID_KVM_POLL_CONTROL (1U << KVM_FEATURE_POLL_CONTROL)
+/* KVM interrupt based asynchronous page fault*/
+#define CPUID_KVM_ASYNCPF_INT (1U << KVM_FEATURE_ASYNC_PF_INT)
+/* KVM 'Extended Destination ID' support for external interrupts */
+#define CPUID_KVM_MSI_EXT_DEST_ID (1U << KVM_FEATURE_MSI_EXT_DEST_ID)
+
+/* Hint to KVM that vCPUs expect never preempted for an unlimited time */
+#define CPUID_KVM_HINTS_REALTIME (1U << KVM_HINTS_REALTIME)
+
/* CLZERO instruction */
#define CPUID_8000_0008_EBX_CLZERO (1U << 0)
/* Always save/restore FP error pointers */
@@ -2045,11 +2068,7 @@
TPRAccess tpr_access_type;
- /* Number of dies within this CPU package. */
- unsigned nr_dies;
-
- /* Number of modules within one die. */
- unsigned nr_modules;
+ X86CPUTopoInfo topo_info;
/* Bitmap of available CPU topology levels for this CPU. */
DECLARE_BITMAP(avail_cpu_topo, CPU_TOPOLOGY_LEVEL__MAX);
@@ -2390,6 +2409,8 @@
cs->halted = 0;
}
+uint64_t cpu_x86_get_msr_core_thread_count(X86CPU *cpu);
+
int cpu_x86_get_descr_debug(CPUX86State *env, unsigned int selector,
target_ulong *base, unsigned int *limit,
unsigned int *flags);
diff --git a/target/i386/hvf/x86_emu.c b/target/i386/hvf/x86_emu.c
index 015f760..69c61c9 100644
--- a/target/i386/hvf/x86_emu.c
+++ b/target/i386/hvf/x86_emu.c
@@ -765,8 +765,7 @@
val = env->mtrr_deftype;
break;
case MSR_CORE_THREAD_COUNT:
- val = cs->nr_threads * cs->nr_cores; /* thread count, bits 15..0 */
- val |= ((uint32_t)cs->nr_cores << 16); /* core count, bits 31..16 */
+ val = cpu_x86_get_msr_core_thread_count(cpu);
break;
default:
/* fprintf(stderr, "%s: unknown msr 0x%x\n", __func__, msr); */
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 2f66e63..6c749d4 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -95,9 +95,6 @@
#define KVM_APIC_BUS_CYCLE_NS 1
#define KVM_APIC_BUS_FREQUENCY (1000000000ULL / KVM_APIC_BUS_CYCLE_NS)
-#define MSR_KVM_WALL_CLOCK 0x11
-#define MSR_KVM_SYSTEM_TIME 0x12
-
/* A 4096-byte buffer can hold the 8-byte kvm_msrs header, plus
* 255 kvm_msr_entry structs */
#define MSR_BUF_SIZE 4096
@@ -111,8 +108,8 @@
} KVMMSRHandlers;
static void kvm_init_msrs(X86CPU *cpu);
-static bool kvm_filter_msr(KVMState *s, uint32_t msr, QEMURDMSRHandler *rdmsr,
- QEMUWRMSRHandler *wrmsr);
+static int kvm_filter_msr(KVMState *s, uint32_t msr, QEMURDMSRHandler *rdmsr,
+ QEMUWRMSRHandler *wrmsr);
const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
KVM_CAP_INFO(SET_TSS_ADDR),
@@ -564,13 +561,13 @@
* be enabled without the in-kernel irqchip
*/
if (!kvm_irqchip_in_kernel()) {
- ret &= ~(1U << KVM_FEATURE_PV_UNHALT);
+ ret &= ~CPUID_KVM_PV_UNHALT;
}
if (kvm_irqchip_is_split()) {
- ret |= 1U << KVM_FEATURE_MSI_EXT_DEST_ID;
+ ret |= CPUID_KVM_MSI_EXT_DEST_ID;
}
} else if (function == KVM_CPUID_FEATURES && reg == R_EDX) {
- ret |= 1U << KVM_HINTS_REALTIME;
+ ret |= CPUID_KVM_HINTS_REALTIME;
}
if (current_machine->cgs) {
@@ -2617,10 +2614,7 @@
uint32_t msr,
uint64_t *val)
{
- CPUState *cs = CPU(cpu);
-
- *val = cs->nr_threads * cs->nr_cores; /* thread count, bits 15..0 */
- *val |= ((uint32_t)cs->nr_cores << 16); /* core count, bits 31..16 */
+ *val = cpu_x86_get_msr_core_thread_count(cpu);
return true;
}
@@ -2939,7 +2933,6 @@
{
MachineClass *mc = MACHINE_GET_CLASS(ms);
struct KVMMsrEnergy *r = &s->msr_energy;
- int ret = 0;
/*
* Sanity check
@@ -2949,13 +2942,11 @@
if (!is_host_cpu_intel()) {
error_report("The RAPL feature can only be enabled on hosts "
"with Intel CPU models");
- ret = 1;
- goto out;
+ return -1;
}
if (!is_rapl_enabled()) {
- ret = 1;
- goto out;
+ return -1;
}
/* Retrieve the virtual topology */
@@ -2977,16 +2968,14 @@
r->host_topo.maxcpus = vmsr_get_maxcpus();
if (r->host_topo.maxcpus == 0) {
error_report("host max cpus = 0");
- ret = 1;
- goto out;
+ return -1;
}
/* Max number of packages on the host */
r->host_topo.maxpkgs = vmsr_get_max_physical_package(r->host_topo.maxcpus);
if (r->host_topo.maxpkgs == 0) {
error_report("host max pkgs = 0");
- ret = 1;
- goto out;
+ return -1;
}
/* Allocate memory for each package on the host */
@@ -2998,8 +2987,7 @@
for (int i = 0; i < r->host_topo.maxpkgs; i++) {
if (r->host_topo.pkg_cpu_count[i] == 0) {
error_report("cpu per packages = 0 on package_%d", i);
- ret = 1;
- goto out;
+ return -1;
}
}
@@ -3016,8 +3004,7 @@
if (s->msr_energy.sioc == NULL) {
error_report("vmsr socket opening failed");
- ret = 1;
- goto out;
+ return -1;
}
/* Those MSR values should not change */
@@ -3029,15 +3016,13 @@
s->msr_energy.sioc);
if (r->msr_unit == 0 || r->msr_limit == 0 || r->msr_info == 0) {
error_report("can't read any virtual msr");
- ret = 1;
- goto out;
+ return -1;
}
qemu_thread_create(&r->msr_thr, "kvm-msr",
kvm_msr_energy_thread,
s, QEMU_THREAD_JOINABLE);
-out:
- return ret;
+ return 0;
}
int kvm_arch_get_default_type(MachineState *ms)
@@ -3103,10 +3088,7 @@
static int kvm_vm_enable_disable_exits(KVMState *s)
{
int disable_exits = kvm_check_extension(s, KVM_CAP_X86_DISABLE_EXITS);
-/* Work around for kernel header with a typo. TODO: fix header and drop. */
-#if defined(KVM_X86_DISABLE_EXITS_HTL) && !defined(KVM_X86_DISABLE_EXITS_HLT)
-#define KVM_X86_DISABLE_EXITS_HLT KVM_X86_DISABLE_EXITS_HTL
-#endif
+
if (disable_exits) {
disable_exits &= (KVM_X86_DISABLE_EXITS_MWAIT |
KVM_X86_DISABLE_EXITS_HLT |
@@ -3156,59 +3138,64 @@
static int kvm_vm_enable_userspace_msr(KVMState *s)
{
- int ret = kvm_vm_enable_cap(s, KVM_CAP_X86_USER_SPACE_MSR, 0,
- KVM_MSR_EXIT_REASON_FILTER);
+ int ret;
+
+ ret = kvm_vm_enable_cap(s, KVM_CAP_X86_USER_SPACE_MSR, 0,
+ KVM_MSR_EXIT_REASON_FILTER);
if (ret < 0) {
error_report("Could not enable user space MSRs: %s",
strerror(-ret));
exit(1);
}
- if (!kvm_filter_msr(s, MSR_CORE_THREAD_COUNT,
- kvm_rdmsr_core_thread_count, NULL)) {
- error_report("Could not install MSR_CORE_THREAD_COUNT handler!");
+ ret = kvm_filter_msr(s, MSR_CORE_THREAD_COUNT,
+ kvm_rdmsr_core_thread_count, NULL);
+ if (ret < 0) {
+ error_report("Could not install MSR_CORE_THREAD_COUNT handler: %s",
+ strerror(-ret));
exit(1);
}
return 0;
}
-static void kvm_vm_enable_energy_msrs(KVMState *s)
+static int kvm_vm_enable_energy_msrs(KVMState *s)
{
- bool r;
+ int ret;
+
if (s->msr_energy.enable == true) {
- r = kvm_filter_msr(s, MSR_RAPL_POWER_UNIT,
- kvm_rdmsr_rapl_power_unit, NULL);
- if (!r) {
- error_report("Could not install MSR_RAPL_POWER_UNIT \
- handler");
- exit(1);
+ ret = kvm_filter_msr(s, MSR_RAPL_POWER_UNIT,
+ kvm_rdmsr_rapl_power_unit, NULL);
+ if (ret < 0) {
+ error_report("Could not install MSR_RAPL_POWER_UNIT handler: %s",
+ strerror(-ret));
+ return ret;
}
- r = kvm_filter_msr(s, MSR_PKG_POWER_LIMIT,
- kvm_rdmsr_pkg_power_limit, NULL);
- if (!r) {
- error_report("Could not install MSR_PKG_POWER_LIMIT \
- handler");
- exit(1);
+ ret = kvm_filter_msr(s, MSR_PKG_POWER_LIMIT,
+ kvm_rdmsr_pkg_power_limit, NULL);
+ if (ret < 0) {
+ error_report("Could not install MSR_PKG_POWER_LIMIT handler: %s",
+ strerror(-ret));
+ return ret;
}
- r = kvm_filter_msr(s, MSR_PKG_POWER_INFO,
- kvm_rdmsr_pkg_power_info, NULL);
- if (!r) {
- error_report("Could not install MSR_PKG_POWER_INFO \
- handler");
- exit(1);
+ ret = kvm_filter_msr(s, MSR_PKG_POWER_INFO,
+ kvm_rdmsr_pkg_power_info, NULL);
+ if (ret < 0) {
+ error_report("Could not install MSR_PKG_POWER_INFO handler: %s",
+ strerror(-ret));
+ return ret;
}
- r = kvm_filter_msr(s, MSR_PKG_ENERGY_STATUS,
- kvm_rdmsr_pkg_energy_status, NULL);
- if (!r) {
- error_report("Could not install MSR_PKG_ENERGY_STATUS \
- handler");
- exit(1);
+ ret = kvm_filter_msr(s, MSR_PKG_ENERGY_STATUS,
+ kvm_rdmsr_pkg_energy_status, NULL);
+ if (ret < 0) {
+ error_report("Could not install MSR_PKG_ENERGY_STATUS handler: %s",
+ strerror(-ret));
+ return ret;
}
}
- return;
+ return 0;
}
int kvm_arch_init(MachineState *ms, KVMState *s)
@@ -3275,7 +3262,10 @@
return ret;
}
- kvm_get_supported_feature_msrs(s);
+ ret = kvm_get_supported_feature_msrs(s);
+ if (ret < 0) {
+ return ret;
+ }
uname(&utsname);
lm_capable_kernel = strcmp(utsname.machine, "x86_64") == 0;
@@ -3311,6 +3301,7 @@
if (ret < 0) {
error_report("kvm: guest stopping CPU not supported: %s",
strerror(-ret));
+ return ret;
}
}
@@ -3342,10 +3333,15 @@
}
if (s->msr_energy.enable == true) {
- kvm_vm_enable_energy_msrs(s);
- if (kvm_msr_energy_thread_init(s, ms)) {
+ ret = kvm_vm_enable_energy_msrs(s);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = kvm_msr_energy_thread_init(s, ms);
+ if (ret < 0) {
error_report("kvm : error RAPL feature requirement not met");
- exit(1);
+ return ret;
}
}
}
@@ -3976,22 +3972,24 @@
*/
if (level >= KVM_PUT_RESET_STATE) {
kvm_msr_entry_add(cpu, MSR_IA32_TSC, env->tsc);
- kvm_msr_entry_add(cpu, MSR_KVM_SYSTEM_TIME, env->system_time_msr);
- kvm_msr_entry_add(cpu, MSR_KVM_WALL_CLOCK, env->wall_clock_msr);
- if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_ASYNC_PF_INT)) {
+ if (env->features[FEAT_KVM] & (CPUID_KVM_CLOCK | CPUID_KVM_CLOCK2)) {
+ kvm_msr_entry_add(cpu, MSR_KVM_SYSTEM_TIME, env->system_time_msr);
+ kvm_msr_entry_add(cpu, MSR_KVM_WALL_CLOCK, env->wall_clock_msr);
+ }
+ if (env->features[FEAT_KVM] & CPUID_KVM_ASYNCPF_INT) {
kvm_msr_entry_add(cpu, MSR_KVM_ASYNC_PF_INT, env->async_pf_int_msr);
}
- if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_ASYNC_PF)) {
+ if (env->features[FEAT_KVM] & CPUID_KVM_ASYNCPF) {
kvm_msr_entry_add(cpu, MSR_KVM_ASYNC_PF_EN, env->async_pf_en_msr);
}
- if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_PV_EOI)) {
+ if (env->features[FEAT_KVM] & CPUID_KVM_PV_EOI) {
kvm_msr_entry_add(cpu, MSR_KVM_PV_EOI_EN, env->pv_eoi_en_msr);
}
- if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_STEAL_TIME)) {
+ if (env->features[FEAT_KVM] & CPUID_KVM_STEAL_TIME) {
kvm_msr_entry_add(cpu, MSR_KVM_STEAL_TIME, env->steal_time_msr);
}
- if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_POLL_CONTROL)) {
+ if (env->features[FEAT_KVM] & CPUID_KVM_POLL_CONTROL) {
kvm_msr_entry_add(cpu, MSR_KVM_POLL_CONTROL, env->poll_control_msr);
}
@@ -4454,21 +4452,23 @@
}
}
#endif
- kvm_msr_entry_add(cpu, MSR_KVM_SYSTEM_TIME, 0);
- kvm_msr_entry_add(cpu, MSR_KVM_WALL_CLOCK, 0);
- if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_ASYNC_PF_INT)) {
+ if (env->features[FEAT_KVM] & (CPUID_KVM_CLOCK | CPUID_KVM_CLOCK2)) {
+ kvm_msr_entry_add(cpu, MSR_KVM_SYSTEM_TIME, 0);
+ kvm_msr_entry_add(cpu, MSR_KVM_WALL_CLOCK, 0);
+ }
+ if (env->features[FEAT_KVM] & CPUID_KVM_ASYNCPF_INT) {
kvm_msr_entry_add(cpu, MSR_KVM_ASYNC_PF_INT, 0);
}
- if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_ASYNC_PF)) {
+ if (env->features[FEAT_KVM] & CPUID_KVM_ASYNCPF) {
kvm_msr_entry_add(cpu, MSR_KVM_ASYNC_PF_EN, 0);
}
- if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_PV_EOI)) {
+ if (env->features[FEAT_KVM] & CPUID_KVM_PV_EOI) {
kvm_msr_entry_add(cpu, MSR_KVM_PV_EOI_EN, 0);
}
- if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_STEAL_TIME)) {
+ if (env->features[FEAT_KVM] & CPUID_KVM_STEAL_TIME) {
kvm_msr_entry_add(cpu, MSR_KVM_STEAL_TIME, 0);
}
- if (env->features[FEAT_KVM] & (1 << KVM_FEATURE_POLL_CONTROL)) {
+ if (env->features[FEAT_KVM] & CPUID_KVM_POLL_CONTROL) {
kvm_msr_entry_add(cpu, MSR_KVM_POLL_CONTROL, 1);
}
if (has_architectural_pmu_version > 0) {
@@ -5843,15 +5843,16 @@
}
}
-static bool kvm_install_msr_filters(KVMState *s)
+static int kvm_install_msr_filters(KVMState *s)
{
uint64_t zero = 0;
struct kvm_msr_filter filter = {
.flags = KVM_MSR_FILTER_DEFAULT_ALLOW,
};
- int r, i, j = 0;
+ int i, j = 0;
- for (i = 0; i < KVM_MSR_FILTER_MAX_RANGES; i++) {
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(msr_handlers) != ARRAY_SIZE(filter.ranges));
+ for (i = 0; i < ARRAY_SIZE(msr_handlers); i++) {
KVMMSRHandlers *handler = &msr_handlers[i];
if (handler->msr) {
struct kvm_msr_filter_range *range = &filter.ranges[j++];
@@ -5873,18 +5874,13 @@
}
}
- r = kvm_vm_ioctl(s, KVM_X86_SET_MSR_FILTER, &filter);
- if (r) {
- return false;
- }
-
- return true;
+ return kvm_vm_ioctl(s, KVM_X86_SET_MSR_FILTER, &filter);
}
-static bool kvm_filter_msr(KVMState *s, uint32_t msr, QEMURDMSRHandler *rdmsr,
- QEMUWRMSRHandler *wrmsr)
+static int kvm_filter_msr(KVMState *s, uint32_t msr, QEMURDMSRHandler *rdmsr,
+ QEMUWRMSRHandler *wrmsr)
{
- int i;
+ int i, ret;
for (i = 0; i < ARRAY_SIZE(msr_handlers); i++) {
if (!msr_handlers[i].msr) {
@@ -5894,16 +5890,17 @@
.wrmsr = wrmsr,
};
- if (!kvm_install_msr_filters(s)) {
+ ret = kvm_install_msr_filters(s);
+ if (ret) {
msr_handlers[i] = (KVMMSRHandlers) { };
- return false;
+ return ret;
}
- return true;
+ return 0;
}
}
- return false;
+ return -EINVAL;
}
static int kvm_handle_rdmsr(X86CPU *cpu, struct kvm_run *run)
@@ -6195,7 +6192,7 @@
return address;
}
env = &X86_CPU(first_cpu)->env;
- if (!(env->features[FEAT_KVM] & (1 << KVM_FEATURE_MSI_EXT_DEST_ID))) {
+ if (!(env->features[FEAT_KVM] & CPUID_KVM_MSI_EXT_DEST_ID)) {
return address;
}
diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc
index 785ff63..c4cc5f4 100644
--- a/target/i386/tcg/emit.c.inc
+++ b/target/i386/tcg/emit.c.inc
@@ -286,24 +286,25 @@
gen_op_ld_v(s, op->ot, v, s->A0);
}
- } else if (op->ot == MO_8 && byte_reg_is_xH(s, op->n)) {
- if (v == s->T0 && decode->e.special == X86_SPECIAL_SExtT0) {
- tcg_gen_sextract_tl(v, cpu_regs[op->n - 4], 8, 8);
- } else {
- tcg_gen_extract_tl(v, cpu_regs[op->n - 4], 8, 8);
- }
-
} else if (op->ot < MO_TL && v == s->T0 &&
(decode->e.special == X86_SPECIAL_SExtT0 ||
decode->e.special == X86_SPECIAL_ZExtT0)) {
- if (decode->e.special == X86_SPECIAL_SExtT0) {
- tcg_gen_ext_tl(v, cpu_regs[op->n], op->ot | MO_SIGN);
+ if (op->ot == MO_8 && byte_reg_is_xH(s, op->n)) {
+ if (decode->e.special == X86_SPECIAL_SExtT0) {
+ tcg_gen_sextract_tl(v, cpu_regs[op->n - 4], 8, 8);
+ } else {
+ tcg_gen_extract_tl(v, cpu_regs[op->n - 4], 8, 8);
+ }
} else {
- tcg_gen_ext_tl(v, cpu_regs[op->n], op->ot);
+ if (decode->e.special == X86_SPECIAL_SExtT0) {
+ tcg_gen_ext_tl(v, cpu_regs[op->n], op->ot | MO_SIGN);
+ } else {
+ tcg_gen_ext_tl(v, cpu_regs[op->n], op->ot);
+ }
}
} else {
- tcg_gen_mov_tl(v, cpu_regs[op->n]);
+ gen_op_mov_v_reg(s, op->ot, v, op->n);
}
break;
case X86_OP_IMM:
@@ -1443,8 +1444,9 @@
return mask;
}
-/* Expects truncated bit index in s->T1, 1 << s->T1 in MASK. */
-static void gen_bt_flags(DisasContext *s, X86DecodedInsn *decode, TCGv src, TCGv mask)
+/* Expects truncated bit index in COUNT, 1 << COUNT in MASK. */
+static void gen_bt_flags(DisasContext *s, X86DecodedInsn *decode, TCGv src,
+ TCGv count, TCGv mask)
{
TCGv cf;
@@ -1467,15 +1469,34 @@
decode->cc_src = tcg_temp_new();
decode->cc_dst = cpu_cc_dst;
decode->cc_op = CC_OP_SARB + cc_op_size(s->cc_op);
- tcg_gen_shr_tl(decode->cc_src, src, s->T1);
+ tcg_gen_shr_tl(decode->cc_src, src, count);
}
}
static void gen_BT(DisasContext *s, X86DecodedInsn *decode)
{
- TCGv mask = gen_bt_mask(s, decode);
+ TCGv count = s->T1;
+ TCGv mask;
- gen_bt_flags(s, decode, s->T0, mask);
+ /*
+ * Try to ensure that the rhs of the TSTNE condition is a constant (and a
+ * power of two), as that is more readily available on most TCG backends.
+ *
+ * For immediate bit number gen_bt_mask()'s output is already a constant;
+ * for register bit number, shift the source right and check bit 0.
+ */
+ if (decode->e.op2 == X86_TYPE_I) {
+ mask = gen_bt_mask(s, decode);
+ } else {
+ MemOp ot = decode->op[1].ot;
+
+ tcg_gen_andi_tl(s->T1, s->T1, (8 << ot) - 1);
+ tcg_gen_shr_tl(s->T0, s->T0, s->T1);
+
+ count = tcg_constant_tl(0);
+ mask = tcg_constant_tl(1);
+ }
+ gen_bt_flags(s, decode, s->T0, count, mask);
}
static void gen_BTC(DisasContext *s, X86DecodedInsn *decode)
@@ -1491,7 +1512,7 @@
tcg_gen_xor_tl(s->T0, s->T0, mask);
}
- gen_bt_flags(s, decode, old, mask);
+ gen_bt_flags(s, decode, old, s->T1, mask);
}
static void gen_BTR(DisasContext *s, X86DecodedInsn *decode)
@@ -1509,7 +1530,7 @@
tcg_gen_andc_tl(s->T0, s->T0, mask);
}
- gen_bt_flags(s, decode, old, mask);
+ gen_bt_flags(s, decode, old, s->T1, mask);
}
static void gen_BTS(DisasContext *s, X86DecodedInsn *decode)
@@ -1525,7 +1546,7 @@
tcg_gen_or_tl(s->T0, s->T0, mask);
}
- gen_bt_flags(s, decode, old, mask);
+ gen_bt_flags(s, decode, old, s->T1, mask);
}
static void gen_BZHI(DisasContext *s, X86DecodedInsn *decode)
diff --git a/target/i386/tcg/system/misc_helper.c b/target/i386/tcg/system/misc_helper.c
index ffed8a3..c9c4d42 100644
--- a/target/i386/tcg/system/misc_helper.c
+++ b/target/i386/tcg/system/misc_helper.c
@@ -468,8 +468,7 @@
val = x86_cpu->ucode_rev;
break;
case MSR_CORE_THREAD_COUNT: {
- CPUState *cs = CPU(x86_cpu);
- val = (cs->nr_threads * cs->nr_cores) | (cs->nr_cores << 16);
+ val = cpu_x86_get_msr_core_thread_count(x86_cpu);
break;
}
case MSR_APIC_START ... MSR_APIC_END: {
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 834aea1..dbc9d63 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -486,7 +486,7 @@
void gen_op_mov_v_reg(DisasContext *s, MemOp ot, TCGv t0, int reg)
{
if (ot == MO_8 && byte_reg_is_xH(s, reg)) {
- tcg_gen_extract_tl(t0, cpu_regs[reg - 4], 8, 8);
+ tcg_gen_shri_tl(t0, cpu_regs[reg - 4], 8);
} else {
tcg_gen_mov_tl(t0, cpu_regs[reg]);
}
diff --git a/tests/qtest/libqos/qgraph.h b/tests/qtest/libqos/qgraph.h
index 1b5de02..81fbfdd 100644
--- a/tests/qtest/libqos/qgraph.h
+++ b/tests/qtest/libqos/qgraph.h
@@ -355,7 +355,7 @@
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.
diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h
index 8f3bde5..ce88d23 100644
--- a/tests/qtest/libqtest.h
+++ b/tests/qtest/libqtest.h
@@ -382,7 +382,7 @@
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
@@ -935,7 +935,7 @@
#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
@@ -952,7 +952,7 @@
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
diff --git a/tests/tcg/plugins/insn.c b/tests/tcg/plugins/insn.c
index baf2d07..0c723cb 100644
--- a/tests/tcg/plugins/insn.c
+++ b/tests/tcg/plugins/insn.c
@@ -150,10 +150,8 @@
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) {
diff --git a/tests/tcg/plugins/mem.c b/tests/tcg/plugins/mem.c
index b0fa8a9..d87d662 100644
--- a/tests/tcg/plugins/mem.c
+++ b/tests/tcg/plugins/mem.c
@@ -135,14 +135,14 @@
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 @@
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));
diff --git a/tests/tcg/plugins/meson.build b/tests/tcg/plugins/meson.build
index f847849..87a17d6 100644
--- a/tests/tcg/plugins/meson.build
+++ b/tests/tcg/plugins/meson.build
@@ -5,9 +5,8 @@
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',
diff --git a/tests/tcg/plugins/syscall.c b/tests/tcg/plugins/syscall.c
index ff45217..47aad55 100644
--- a/tests/tcg/plugins/syscall.c
+++ b/tests/tcg/plugins/syscall.c
@@ -76,12 +76,12 @@
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 @@
}
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) {