aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS6
-rw-r--r--Makefile9
-rw-r--r--VERSION2
-rw-r--r--accel/kvm/kvm-all.c15
-rw-r--r--accel/tcg/translator.c47
-rw-r--r--backends/cryptodev-builtin.c4
-rw-r--r--disas/nanomips.c194
-rw-r--r--hw/audio/virtio-snd.c8
-rw-r--r--hw/block/nand.c55
-rw-r--r--hw/char/virtio-serial-bus.c3
-rw-r--r--hw/display/virtio-gpu.c6
-rw-r--r--hw/misc/applesmc.c2
-rw-r--r--hw/net/lan9118.c28
-rw-r--r--hw/net/net_tx_pkt.c4
-rw-r--r--hw/sd/sdhci.c8
-rw-r--r--hw/virtio/virtio-crypto.c4
-rw-r--r--hw/virtio/virtio.c10
-rw-r--r--include/exec/translator.h4
-rw-r--r--include/hw/virtio/virtio.h7
-rw-r--r--include/tcg/tcg.h6
-rw-r--r--linux-user/main.c6
-rw-r--r--linux-user/signal.c12
-rw-r--r--linux-user/syscall.c22
-rw-r--r--meson.build6
-rw-r--r--migration/savevm.c21
-rw-r--r--pc-bios/edk2-aarch64-code.fd.bz2bin1589310 -> 1588976 bytes
-rw-r--r--pc-bios/edk2-arm-code.fd.bz2bin1571693 -> 1571639 bytes
-rw-r--r--pc-bios/edk2-i386-code.fd.bz2bin1775832 -> 1775230 bytes
-rw-r--r--pc-bios/edk2-i386-secure-code.fd.bz2bin1876986 -> 1877268 bytes
-rw-r--r--pc-bios/edk2-riscv-code.fd.bz2bin1289160 -> 1289337 bytes
-rw-r--r--pc-bios/edk2-x86_64-code.fd.bz2bin1892372 -> 1892766 bytes
-rw-r--r--pc-bios/edk2-x86_64-microvm.fd.bz2bin1785258 -> 1785290 bytes
-rw-r--r--pc-bios/edk2-x86_64-secure-code.fd.bz2bin2214892 -> 1969096 bytes
-rw-r--r--qemu-options.hx6
-rw-r--r--roms/Makefile25
-rw-r--r--roms/edk2-version2
-rw-r--r--target/arm/helper.c10
-rw-r--r--target/arm/tcg/translate-a64.c2
-rw-r--r--target/arm/tcg/translate.c2
-rw-r--r--target/arm/tcg/translate.h12
-rw-r--r--target/hppa/int_helper.c20
-rw-r--r--target/hppa/sys_helper.c18
-rw-r--r--target/hppa/translate.c10
-rw-r--r--target/i386/tcg/translate.c3
-rw-r--r--target/m68k/cpu.c12
-rw-r--r--target/m68k/cpu.h3
-rw-r--r--target/m68k/fpu_helper.c72
-rw-r--r--target/m68k/helper.c4
-rw-r--r--target/m68k/helper.h2
-rw-r--r--target/m68k/translate.c4
-rw-r--r--target/microblaze/translate.c8
-rw-r--r--target/riscv/translate.c11
-rw-r--r--target/s390x/tcg/translate.c4
-rw-r--r--target/sh4/cpu.h14
-rw-r--r--target/sh4/helper.h4
-rw-r--r--target/sh4/op_helper.c51
-rw-r--r--target/sh4/translate.c7
-rw-r--r--target/sparc/helper.h3
-rw-r--r--target/sparc/ldst_helper.c65
-rw-r--r--target/sparc/translate.c48
-rw-r--r--tcg/optimize.c17
-rw-r--r--tcg/tcg.c14
-rw-r--r--tests/tcg/aarch64/Makefile.target2
-rw-r--r--tests/tcg/aarch64/test-2150.c12
-rw-r--r--tests/tcg/sh4/Makefile.target8
-rw-r--r--tests/tcg/sh4/test-macl.c67
-rw-r--r--tests/tcg/sh4/test-macw.c61
67 files changed, 787 insertions, 305 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 249b678..f1f6922 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2170,7 +2170,7 @@ S: Supported
F: hw/vfio/*
F: include/hw/vfio/
F: docs/igd-assign.txt
-F: docs/devel/vfio-migration.rst
+F: docs/devel/migration/vfio.rst
vfio-ccw
M: Eric Farman <farman@linux.ibm.com>
@@ -2231,6 +2231,7 @@ F: qapi/virtio.json
F: net/vhost-user.c
F: include/hw/virtio/
F: docs/devel/virtio*
+F: docs/devel/migration/virtio.rst
virtio-balloon
M: Michael S. Tsirkin <mst@redhat.com>
@@ -3417,7 +3418,7 @@ F: migration/
F: scripts/vmstate-static-checker.py
F: tests/vmstate-static-checker-data/
F: tests/qtest/migration-test.c
-F: docs/devel/migration.rst
+F: docs/devel/migration/
F: qapi/migration.json
F: tests/migration/
F: util/userfaultfd.c
@@ -3437,6 +3438,7 @@ F: include/sysemu/dirtylimit.h
F: migration/dirtyrate.c
F: migration/dirtyrate.h
F: include/sysemu/dirtyrate.h
+F: docs/devel/migration/dirty-limit.rst
Detached LUKS header
M: Hyman Huang <yong.huang@smartx.com>
diff --git a/Makefile b/Makefile
index 8f36990..02a2575 100644
--- a/Makefile
+++ b/Makefile
@@ -141,8 +141,13 @@ MAKE.n = $(findstring n,$(firstword $(filter-out --%,$(MAKEFLAGS))))
MAKE.k = $(findstring k,$(firstword $(filter-out --%,$(MAKEFLAGS))))
MAKE.q = $(findstring q,$(firstword $(filter-out --%,$(MAKEFLAGS))))
MAKE.nq = $(if $(word 2, $(MAKE.n) $(MAKE.q)),nq)
-NINJAFLAGS = $(if $V,-v) $(if $(MAKE.n), -n) $(if $(MAKE.k), -k0) \
- $(filter-out -j, $(lastword -j1 $(filter -l% -j%, $(MAKEFLAGS)))) \
+NINJAFLAGS = \
+ $(if $V,-v) \
+ $(if $(MAKE.n), -n) \
+ $(if $(MAKE.k), -k0) \
+ $(filter-out -j, \
+ $(or $(filter -l% -j%, $(MAKEFLAGS)), \
+ $(if $(filter --jobserver-auth=%, $(MAKEFLAGS)),, -j1))) \
-d keepdepfile
ninja-cmd-goals = $(or $(MAKECMDGOALS), all)
ninja-cmd-goals += $(foreach g, $(MAKECMDGOALS), $(.ninja-goals.$g))
diff --git a/VERSION b/VERSION
index 5ed3832..34ecc37 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-8.2.92
+8.2.93
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index a8cecd0..931f742 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -1999,12 +1999,17 @@ int kvm_irqchip_add_msi_route(KVMRouteChange *c, int vector, PCIDevice *dev)
return -EINVAL;
}
- trace_kvm_irqchip_add_msi_route(dev ? dev->name : (char *)"N/A",
- vector, virq);
+ if (s->irq_routes->nr < s->gsi_count) {
+ trace_kvm_irqchip_add_msi_route(dev ? dev->name : (char *)"N/A",
+ vector, virq);
- kvm_add_routing_entry(s, &kroute);
- kvm_arch_add_msi_route_post(&kroute, vector, dev);
- c->changes++;
+ kvm_add_routing_entry(s, &kroute);
+ kvm_arch_add_msi_route_post(&kroute, vector, dev);
+ c->changes++;
+ } else {
+ kvm_irqchip_release_virq(s, virq);
+ return -ENOSPC;
+ }
return virq;
}
diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c
index 38c3400..9de0bc3 100644
--- a/accel/tcg/translator.c
+++ b/accel/tcg/translator.c
@@ -18,20 +18,14 @@
static void set_can_do_io(DisasContextBase *db, bool val)
{
- if (db->saved_can_do_io != val) {
- db->saved_can_do_io = val;
-
- QEMU_BUILD_BUG_ON(sizeof_field(CPUState, neg.can_do_io) != 1);
- tcg_gen_st8_i32(tcg_constant_i32(val), tcg_env,
- offsetof(ArchCPU, parent_obj.neg.can_do_io) -
- offsetof(ArchCPU, env));
- }
+ QEMU_BUILD_BUG_ON(sizeof_field(CPUState, neg.can_do_io) != 1);
+ tcg_gen_st8_i32(tcg_constant_i32(val), tcg_env,
+ offsetof(ArchCPU, parent_obj.neg.can_do_io) -
+ offsetof(ArchCPU, env));
}
bool translator_io_start(DisasContextBase *db)
{
- set_can_do_io(db, true);
-
/*
* Ensure that this instruction will be the last in the TB.
* The target may override this to something more forceful.
@@ -84,13 +78,6 @@ static TCGOp *gen_tb_start(DisasContextBase *db, uint32_t cflags)
- offsetof(ArchCPU, env));
}
- /*
- * cpu->neg.can_do_io is set automatically here at the beginning of
- * each translation block. The cost is minimal, plus it would be
- * very easy to forget doing it in the translator.
- */
- set_can_do_io(db, db->max_insns == 1);
-
return icount_start_insn;
}
@@ -129,6 +116,7 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
{
uint32_t cflags = tb_cflags(tb);
TCGOp *icount_start_insn;
+ TCGOp *first_insn_start = NULL;
bool plugin_enabled;
/* Initialize DisasContext */
@@ -139,7 +127,7 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
db->num_insns = 0;
db->max_insns = *max_insns;
db->singlestep_enabled = cflags & CF_SINGLE_STEP;
- db->saved_can_do_io = -1;
+ db->insn_start = NULL;
db->host_addr[0] = host_pc;
db->host_addr[1] = NULL;
@@ -157,6 +145,10 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
while (true) {
*max_insns = ++db->num_insns;
ops->insn_start(db, cpu);
+ db->insn_start = tcg_last_op();
+ if (first_insn_start == NULL) {
+ first_insn_start = db->insn_start;
+ }
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
if (plugin_enabled) {
@@ -169,10 +161,6 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
* done next -- either exiting this loop or locate the start of
* the next instruction.
*/
- if (db->num_insns == db->max_insns) {
- /* Accept I/O on the last instruction. */
- set_can_do_io(db, true);
- }
ops->translate_insn(db, cpu);
/*
@@ -205,6 +193,21 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
ops->tb_stop(db, cpu);
gen_tb_end(tb, cflags, icount_start_insn, db->num_insns);
+ /*
+ * Manage can_do_io for the translation block: set to false before
+ * the first insn and set to true before the last insn.
+ */
+ if (db->num_insns == 1) {
+ tcg_debug_assert(first_insn_start == db->insn_start);
+ } else {
+ tcg_debug_assert(first_insn_start != db->insn_start);
+ tcg_ctx->emit_before_op = first_insn_start;
+ set_can_do_io(db, false);
+ }
+ tcg_ctx->emit_before_op = db->insn_start;
+ set_can_do_io(db, true);
+ tcg_ctx->emit_before_op = NULL;
+
if (plugin_enabled) {
plugin_gen_tb_end(cpu, db->num_insns);
}
diff --git a/backends/cryptodev-builtin.c b/backends/cryptodev-builtin.c
index 39d0455..a514bbb 100644
--- a/backends/cryptodev-builtin.c
+++ b/backends/cryptodev-builtin.c
@@ -427,7 +427,9 @@ static int cryptodev_builtin_close_session(
CRYPTODEV_BACKEND_BUILTIN(backend);
CryptoDevBackendBuiltinSession *session;
- assert(session_id < MAX_NUM_SESSIONS && builtin->sessions[session_id]);
+ if (session_id >= MAX_NUM_SESSIONS || !builtin->sessions[session_id]) {
+ return -VIRTIO_CRYPTO_INVSESS;
+ }
session = builtin->sessions[session_id];
if (session->cipher) {
diff --git a/disas/nanomips.c b/disas/nanomips.c
index a025359..db0c297 100644
--- a/disas/nanomips.c
+++ b/disas/nanomips.c
@@ -36,35 +36,6 @@ typedef uint32_t uint32;
typedef uint16_t uint16;
typedef uint64_t img_address;
-typedef enum {
- instruction,
- call_instruction,
- branch_instruction,
- return_instruction,
- reserved_block,
- pool,
-} TABLE_ENTRY_TYPE;
-
-typedef enum {
- MIPS64_ = 0x00000001,
- XNP_ = 0x00000002,
- XMMS_ = 0x00000004,
- EVA_ = 0x00000008,
- DSP_ = 0x00000010,
- MT_ = 0x00000020,
- EJTAG_ = 0x00000040,
- TLBINV_ = 0x00000080,
- CP0_ = 0x00000100,
- CP1_ = 0x00000200,
- CP2_ = 0x00000400,
- UDI_ = 0x00000800,
- MCU_ = 0x00001000,
- VZ_ = 0x00002000,
- TLB_ = 0x00004000,
- MVH_ = 0x00008000,
- ALL_ATTRIBUTES = 0xffffffffull,
-} TABLE_ATTRIBUTE_TYPE;
-
typedef struct Dis_info {
img_address m_pc;
fprintf_function fprintf_func;
@@ -72,22 +43,6 @@ typedef struct Dis_info {
sigjmp_buf buf;
} Dis_info;
-typedef bool (*conditional_function)(uint64 instruction);
-typedef char * (*disassembly_function)(uint64 instruction,
- Dis_info *info);
-
-typedef struct Pool {
- TABLE_ENTRY_TYPE type;
- const struct Pool *next_table;
- int next_table_size;
- int instructions_size;
- uint64 mask;
- uint64 value;
- disassembly_function disassembly;
- conditional_function condition;
- uint64 attributes;
-} Pool;
-
#define IMGASSERTONCE(test)
@@ -544,58 +499,6 @@ static uint64 extract_op_code_value(const uint16 *data, int size)
}
-/*
- * Recurse through tables until the instruction is found then return
- * the string and size
- *
- * inputs:
- * pointer to a word stream,
- * disassember table and size
- * returns:
- * instruction size - negative is error
- * disassembly string - on error will constain error string
- */
-static int Disassemble(const uint16 *data, char **dis,
- TABLE_ENTRY_TYPE *type, const Pool *table,
- int table_size, Dis_info *info)
-{
- for (int i = 0; i < table_size; i++) {
- uint64 op_code = extract_op_code_value(data,
- table[i].instructions_size);
- if ((op_code & table[i].mask) == table[i].value) {
- /* possible match */
- conditional_function cond = table[i].condition;
- if ((cond == NULL) || cond(op_code)) {
- if (table[i].type == pool) {
- return Disassemble(data, dis, type,
- table[i].next_table,
- table[i].next_table_size,
- info);
- } else if ((table[i].type == instruction) ||
- (table[i].type == call_instruction) ||
- (table[i].type == branch_instruction) ||
- (table[i].type == return_instruction)) {
- disassembly_function dis_fn = table[i].disassembly;
- if (dis_fn == 0) {
- *dis = g_strdup(
- "disassembler failure - bad table entry");
- return -6;
- }
- *type = table[i].type;
- *dis = dis_fn(op_code, info);
- return table[i].instructions_size;
- } else {
- *dis = g_strdup("reserved instruction");
- return -2;
- }
- }
- }
- }
- *dis = g_strdup("failed to disassemble");
- return -1; /* failed to disassemble */
-}
-
-
static uint64 extract_code_18_to_0(uint64 instruction)
{
uint64 value = 0;
@@ -16213,6 +16116,51 @@ static char *YIELD(uint64 instruction, Dis_info *info)
*
*/
+typedef enum {
+ instruction,
+ call_instruction,
+ branch_instruction,
+ return_instruction,
+ reserved_block,
+ pool,
+} TABLE_ENTRY_TYPE;
+
+typedef enum {
+ MIPS64_ = 0x00000001,
+ XNP_ = 0x00000002,
+ XMMS_ = 0x00000004,
+ EVA_ = 0x00000008,
+ DSP_ = 0x00000010,
+ MT_ = 0x00000020,
+ EJTAG_ = 0x00000040,
+ TLBINV_ = 0x00000080,
+ CP0_ = 0x00000100,
+ CP1_ = 0x00000200,
+ CP2_ = 0x00000400,
+ UDI_ = 0x00000800,
+ MCU_ = 0x00001000,
+ VZ_ = 0x00002000,
+ TLB_ = 0x00004000,
+ MVH_ = 0x00008000,
+ ALL_ATTRIBUTES = 0xffffffffull,
+} TABLE_ATTRIBUTE_TYPE;
+
+typedef bool (*conditional_function)(uint64 instruction);
+typedef char * (*disassembly_function)(uint64 instruction,
+ Dis_info *info);
+
+typedef struct Pool {
+ TABLE_ENTRY_TYPE type;
+ const struct Pool *next_table;
+ int next_table_size;
+ int instructions_size;
+ uint64 mask;
+ uint64 value;
+ disassembly_function disassembly;
+ conditional_function condition;
+ uint64 attributes;
+} Pool;
+
static const Pool P_SYSCALL[2] = {
{ instruction , 0 , 0 , 32,
0xfffc0000, 0x00080000, &SYSCALL_32_ , 0,
@@ -21907,6 +21855,58 @@ static const Pool MAJOR[2] = {
0x0 }, /* P16 */
};
+/*
+ * Recurse through tables until the instruction is found then return
+ * the string and size
+ *
+ * inputs:
+ * pointer to a word stream,
+ * disassember table and size
+ * returns:
+ * instruction size - negative is error
+ * disassembly string - on error will constain error string
+ */
+static int Disassemble(const uint16 *data, char **dis,
+ TABLE_ENTRY_TYPE *type, const Pool *table,
+ int table_size, Dis_info *info)
+{
+ for (int i = 0; i < table_size; i++) {
+ uint64 op_code = extract_op_code_value(data,
+ table[i].instructions_size);
+ if ((op_code & table[i].mask) == table[i].value) {
+ /* possible match */
+ conditional_function cond = table[i].condition;
+ if ((cond == NULL) || cond(op_code)) {
+ if (table[i].type == pool) {
+ return Disassemble(data, dis, type,
+ table[i].next_table,
+ table[i].next_table_size,
+ info);
+ } else if ((table[i].type == instruction) ||
+ (table[i].type == call_instruction) ||
+ (table[i].type == branch_instruction) ||
+ (table[i].type == return_instruction)) {
+ disassembly_function dis_fn = table[i].disassembly;
+ if (dis_fn == 0) {
+ *dis = g_strdup(
+ "disassembler failure - bad table entry");
+ return -6;
+ }
+ *type = table[i].type;
+ *dis = dis_fn(op_code, info);
+ return table[i].instructions_size;
+ } else {
+ *dis = g_strdup("reserved instruction");
+ return -2;
+ }
+ }
+ }
+ }
+ *dis = g_strdup("failed to disassemble");
+ return -1; /* failed to disassemble */
+}
+
+
static bool nanomips_dis(const uint16_t *data, char **buf, Dis_info *info)
{
TABLE_ENTRY_TYPE type;
diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 90d9a27..c80b58b 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -885,7 +885,9 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, VirtQueue *vq)
}
trace_virtio_snd_handle_tx_xfer();
- for (VirtIOSoundPCMStream *stream = NULL;; stream = NULL) {
+ for (;;) {
+ VirtIOSoundPCMStream *stream;
+
elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
if (!elem) {
break;
@@ -964,7 +966,9 @@ static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, VirtQueue *vq)
}
trace_virtio_snd_handle_rx_xfer();
- for (VirtIOSoundPCMStream *stream = NULL;; stream = NULL) {
+ for (;;) {
+ VirtIOSoundPCMStream *stream;
+
elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
if (!elem) {
break;
diff --git a/hw/block/nand.c b/hw/block/nand.c
index d1435f2..e2433c2 100644
--- a/hw/block/nand.c
+++ b/hw/block/nand.c
@@ -84,7 +84,11 @@ struct NANDFlashState {
void (*blk_write)(NANDFlashState *s);
void (*blk_erase)(NANDFlashState *s);
- void (*blk_load)(NANDFlashState *s, uint64_t addr, int offset);
+ /*
+ * Returns %true when block containing (@addr + @offset) is
+ * successfully loaded, otherwise %false.
+ */
+ bool (*blk_load)(NANDFlashState *s, uint64_t addr, unsigned offset);
uint32_t ioaddr_vmstate;
};
@@ -243,9 +247,30 @@ static inline void nand_pushio_byte(NANDFlashState *s, uint8_t value)
}
}
+/*
+ * nand_load_block: Load block containing (s->addr + @offset).
+ * Returns length of data available at @offset in this block.
+ */
+static unsigned nand_load_block(NANDFlashState *s, unsigned offset)
+{
+ unsigned iolen;
+
+ if (!s->blk_load(s, s->addr, offset)) {
+ return 0;
+ }
+
+ iolen = (1 << s->page_shift);
+ if (s->gnd) {
+ iolen += 1 << s->oob_shift;
+ }
+ assert(offset <= iolen);
+ iolen -= offset;
+
+ return iolen;
+}
+
static void nand_command(NANDFlashState *s)
{
- unsigned int offset;
switch (s->cmd) {
case NAND_CMD_READ0:
s->iolen = 0;
@@ -271,12 +296,7 @@ static void nand_command(NANDFlashState *s)
case NAND_CMD_NOSERIALREAD2:
if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP))
break;
- offset = s->addr & ((1 << s->addr_shift) - 1);
- s->blk_load(s, s->addr, offset);
- if (s->gnd)
- s->iolen = (1 << s->page_shift) - offset;
- else
- s->iolen = (1 << s->page_shift) + (1 << s->oob_shift) - offset;
+ s->iolen = nand_load_block(s, s->addr & ((1 << s->addr_shift) - 1));
break;
case NAND_CMD_RESET:
@@ -597,12 +617,7 @@ uint32_t nand_getio(DeviceState *dev)
if (!s->iolen && s->cmd == NAND_CMD_READ0) {
offset = (int) (s->addr & ((1 << s->addr_shift) - 1)) + s->offset;
s->offset = 0;
-
- s->blk_load(s, s->addr, offset);
- if (s->gnd)
- s->iolen = (1 << s->page_shift) - offset;
- else
- s->iolen = (1 << s->page_shift) + (1 << s->oob_shift) - offset;
+ s->iolen = nand_load_block(s, offset);
}
if (s->ce || s->iolen <= 0) {
@@ -763,11 +778,15 @@ static void glue(nand_blk_erase_, NAND_PAGE_SIZE)(NANDFlashState *s)
}
}
-static void glue(nand_blk_load_, NAND_PAGE_SIZE)(NANDFlashState *s,
- uint64_t addr, int offset)
+static bool glue(nand_blk_load_, NAND_PAGE_SIZE)(NANDFlashState *s,
+ uint64_t addr, unsigned offset)
{
if (PAGE(addr) >= s->pages) {
- return;
+ return false;
+ }
+
+ if (offset > NAND_PAGE_SIZE + OOB_SIZE) {
+ return false;
}
if (s->blk) {
@@ -795,6 +814,8 @@ static void glue(nand_blk_load_, NAND_PAGE_SIZE)(NANDFlashState *s,
offset, NAND_PAGE_SIZE + OOB_SIZE - offset);
s->ioaddr = s->io;
}
+
+ return true;
}
static void glue(nand_init_, NAND_PAGE_SIZE)(NANDFlashState *s)
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index 016aba6..2094d21 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -985,8 +985,7 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp)
return;
}
- port->bh = qemu_bh_new_guarded(flush_queued_data_bh, port,
- &dev->mem_reentrancy_guard);
+ port->bh = virtio_bh_new_guarded(dev, flush_queued_data_bh, port);
port->elem = NULL;
}
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 78d5a4f..ae831b6 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -1492,10 +1492,8 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
g->ctrl_vq = virtio_get_queue(vdev, 0);
g->cursor_vq = virtio_get_queue(vdev, 1);
- g->ctrl_bh = qemu_bh_new_guarded(virtio_gpu_ctrl_bh, g,
- &qdev->mem_reentrancy_guard);
- g->cursor_bh = qemu_bh_new_guarded(virtio_gpu_cursor_bh, g,
- &qdev->mem_reentrancy_guard);
+ g->ctrl_bh = virtio_bh_new_guarded(qdev, virtio_gpu_ctrl_bh, g);
+ g->cursor_bh = virtio_bh_new_guarded(qdev, virtio_gpu_cursor_bh, g);
g->reset_bh = qemu_bh_new(virtio_gpu_reset_bh, g);
qemu_cond_init(&g->reset_cond);
QTAILQ_INIT(&g->reslist);
diff --git a/hw/misc/applesmc.c b/hw/misc/applesmc.c
index 72300d0..14e3ef6 100644
--- a/hw/misc/applesmc.c
+++ b/hw/misc/applesmc.c
@@ -274,6 +274,7 @@ static void qdev_applesmc_isa_reset(DeviceState *dev)
/* Remove existing entries */
QLIST_FOREACH_SAFE(d, &s->data_def, node, next) {
QLIST_REMOVE(d, node);
+ g_free(d);
}
s->status = 0x00;
s->status_1e = 0x00;
@@ -342,7 +343,6 @@ static void applesmc_isa_realize(DeviceState *dev, Error **errp)
}
QLIST_INIT(&s->data_def);
- qdev_applesmc_isa_reset(dev);
}
static Property applesmc_isa_properties[] = {
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
index 47ff25b..91d81b4 100644
--- a/hw/net/lan9118.c
+++ b/hw/net/lan9118.c
@@ -150,6 +150,12 @@ do { printf("lan9118: " fmt , ## __VA_ARGS__); } while (0)
#define GPT_TIMER_EN 0x20000000
+/*
+ * The MAC Interface Layer (MIL), within the MAC, contains a 2K Byte transmit
+ * and a 128 Byte receive FIFO which is separate from the TX and RX FIFOs.
+ */
+#define MIL_TXFIFO_SIZE 2048
+
enum tx_state {
TX_IDLE,
TX_B,
@@ -166,7 +172,7 @@ typedef struct {
int32_t pad;
int32_t fifo_used;
int32_t len;
- uint8_t data[2048];
+ uint8_t data[MIL_TXFIFO_SIZE];
} LAN9118Packet;
static const VMStateDescription vmstate_lan9118_packet = {
@@ -182,7 +188,7 @@ static const VMStateDescription vmstate_lan9118_packet = {
VMSTATE_INT32(pad, LAN9118Packet),
VMSTATE_INT32(fifo_used, LAN9118Packet),
VMSTATE_INT32(len, LAN9118Packet),
- VMSTATE_UINT8_ARRAY(data, LAN9118Packet, 2048),
+ VMSTATE_UINT8_ARRAY(data, LAN9118Packet, MIL_TXFIFO_SIZE),
VMSTATE_END_OF_LIST()
}
};
@@ -544,7 +550,7 @@ static ssize_t lan9118_receive(NetClientState *nc, const uint8_t *buf,
return -1;
}
- if (size >= 2048 || size < 14) {
+ if (size >= MIL_TXFIFO_SIZE || size < 14) {
return -1;
}
@@ -793,8 +799,22 @@ static void tx_fifo_push(lan9118_state *s, uint32_t val)
/* Documentation is somewhat unclear on the ordering of bytes
in FIFO words. Empirical results show it to be little-endian.
*/
- /* TODO: FIFO overflow checking. */
while (n--) {
+ if (s->txp->len == MIL_TXFIFO_SIZE) {
+ /*
+ * No more space in the FIFO. The datasheet is not
+ * precise about this case. We choose what is easiest
+ * to model: the packet is truncated, and TXE is raised.
+ *
+ * Note, it could be a fragmented packet, but we currently
+ * do not handle that (see earlier TX_B case).
+ */
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "MIL TX FIFO overrun, discarding %u byte%s\n",
+ n, n > 1 ? "s" : "");
+ s->int_sts |= TXE_INT;
+ break;
+ }
s->txp->data[s->txp->len] = val & 0xff;
s->txp->len++;
val >>= 8;
diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c
index 2134a18..b7b1de8 100644
--- a/hw/net/net_tx_pkt.c
+++ b/hw/net/net_tx_pkt.c
@@ -141,6 +141,10 @@ bool net_tx_pkt_update_sctp_checksum(struct NetTxPkt *pkt)
uint32_t csum = 0;
struct iovec *pl_start_frag = pkt->vec + NET_TX_PKT_PL_START_FRAG;
+ if (iov_size(pl_start_frag, pkt->payload_frags) < 8 + sizeof(csum)) {
+ return false;
+ }
+
if (iov_from_buf(pl_start_frag, pkt->payload_frags, 8, &csum, sizeof(csum)) < sizeof(csum)) {
return false;
}
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index c5e0bc0..27673e1 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -473,6 +473,7 @@ static uint32_t sdhci_read_dataport(SDHCIState *s, unsigned size)
}
for (i = 0; i < size; i++) {
+ assert(s->data_count < s->buf_maxsz);
value |= s->fifo_buffer[s->data_count] << i * 8;
s->data_count++;
/* check if we've read all valid data (blksize bytes) from buffer */
@@ -561,6 +562,7 @@ static void sdhci_write_dataport(SDHCIState *s, uint32_t value, unsigned size)
}
for (i = 0; i < size; i++) {
+ assert(s->data_count < s->buf_maxsz);
s->fifo_buffer[s->data_count] = value & 0xFF;
s->data_count++;
value >>= 8;
@@ -1208,6 +1210,12 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
if (!(s->capareg & R_SDHC_CAPAB_SDMA_MASK)) {
value &= ~SDHC_TRNS_DMA;
}
+
+ /* TRNMOD writes are inhibited while Command Inhibit (DAT) is true */
+ if (s->prnsts & SDHC_DATA_INHIBIT) {
+ mask |= 0xffff;
+ }
+
MASKED_WRITE(s->trnmod, mask, value & SDHC_TRNMOD_MASK);
MASKED_WRITE(s->cmdreg, mask >> 16, value >> 16);
diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c
index fe1313f..bbe8aa4 100644
--- a/hw/virtio/virtio-crypto.c
+++ b/hw/virtio/virtio-crypto.c
@@ -1080,8 +1080,8 @@ static void virtio_crypto_device_realize(DeviceState *dev, Error **errp)
vcrypto->vqs[i].dataq =
virtio_add_queue(vdev, 1024, virtio_crypto_handle_dataq_bh);
vcrypto->vqs[i].dataq_bh =
- qemu_bh_new_guarded(virtio_crypto_dataq_bh, &vcrypto->vqs[i],
- &dev->mem_reentrancy_guard);
+ virtio_bh_new_guarded(dev, virtio_crypto_dataq_bh,
+ &vcrypto->vqs[i]);
vcrypto->vqs[i].vcrypto = vcrypto;
}
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index c5bedca..871674f 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -4145,3 +4145,13 @@ static void virtio_register_types(void)
}
type_init(virtio_register_types)
+
+QEMUBH *virtio_bh_new_guarded_full(DeviceState *dev,
+ QEMUBHFunc *cb, void *opaque,
+ const char *name)
+{
+ DeviceState *transport = qdev_get_parent_bus(dev)->parent;
+
+ return qemu_bh_new_full(cb, opaque, name,
+ &transport->mem_reentrancy_guard);
+}
diff --git a/include/exec/translator.h b/include/exec/translator.h
index 51624fe..2c4fb81 100644
--- a/include/exec/translator.h
+++ b/include/exec/translator.h
@@ -74,6 +74,8 @@ typedef enum DisasJumpType {
* @singlestep_enabled: "Hardware" single stepping enabled.
* @saved_can_do_io: Known value of cpu->neg.can_do_io, or -1 for unknown.
* @plugin_enabled: TCG plugin enabled in this TB.
+ * @insn_start: The last op emitted by the insn_start hook,
+ * which is expected to be INDEX_op_insn_start.
*
* Architecture-agnostic disassembly context.
*/
@@ -85,8 +87,8 @@ typedef struct DisasContextBase {
int num_insns;
int max_insns;
bool singlestep_enabled;
- int8_t saved_can_do_io;
bool plugin_enabled;
+ struct TCGOp *insn_start;
void *host_addr[2];
} DisasContextBase;
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index c8f7285..7d5ffdc 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -22,6 +22,7 @@
#include "standard-headers/linux/virtio_config.h"
#include "standard-headers/linux/virtio_ring.h"
#include "qom/object.h"
+#include "block/aio.h"
/*
* A guest should never accept this. It implies negotiation is broken
@@ -508,4 +509,10 @@ static inline bool virtio_device_disabled(VirtIODevice *vdev)
bool virtio_legacy_allowed(VirtIODevice *vdev);
bool virtio_legacy_check_disabled(VirtIODevice *vdev);
+QEMUBH *virtio_bh_new_guarded_full(DeviceState *dev,
+ QEMUBHFunc *cb, void *opaque,
+ const char *name);
+#define virtio_bh_new_guarded(dev, cb, opaque) \
+ virtio_bh_new_guarded_full((dev), (cb), (opaque), (stringify(cb)))
+
#endif
diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
index 451f3fe..05a1912 100644
--- a/include/tcg/tcg.h
+++ b/include/tcg/tcg.h
@@ -553,6 +553,12 @@ struct TCGContext {
QTAILQ_HEAD(, TCGOp) ops, free_ops;
QSIMPLEQ_HEAD(, TCGLabel) labels;
+ /*
+ * When clear, new ops are added to the tail of @ops.
+ * When set, new ops are added in front of @emit_before_op.
+ */
+ TCGOp *emit_before_op;
+
/* Tells which temporary holds a given register.
It does not take into account fixed registers */
TCGTemp *reg_to_temp[TCG_TARGET_NB_REGS];
diff --git a/linux-user/main.c b/linux-user/main.c
index 9277df2..149e354 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -928,11 +928,7 @@ int main(int argc, char **argv, char **envp)
* Prepare copy of argv vector for target.
*/
target_argc = argc - optind;
- target_argv = calloc(target_argc + 1, sizeof (char *));
- if (target_argv == NULL) {
- (void) fprintf(stderr, "Unable to allocate memory for target_argv\n");
- exit(EXIT_FAILURE);
- }
+ target_argv = g_new0(char *, target_argc + 1);
/*
* If argv0 is specified (using '-0' switch) we replace
diff --git a/linux-user/signal.c b/linux-user/signal.c
index a93148a..05dc4af 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -1173,6 +1173,7 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig,
CPUState *cpu = env_cpu(cpu_env);
abi_ulong handler;
sigset_t set;
+ target_siginfo_t unswapped;
target_sigset_t target_old_set;
struct target_sigaction *sa;
TaskState *ts = get_task_state(cpu);
@@ -1182,9 +1183,14 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig,
k->pending = 0;
/*
- * Writes out siginfo values byteswapped, accordingly to the target. It also
- * cleans the si_type from si_code making it correct for the target.
+ * Writes out siginfo values byteswapped, accordingly to the target.
+ * It also cleans the si_type from si_code making it correct for
+ * the target. We must hold on to the original unswapped copy for
+ * strace below, because si_type is still required there.
*/
+ if (unlikely(qemu_loglevel_mask(LOG_STRACE))) {
+ unswapped = k->info;
+ }
tswap_siginfo(&k->info, &k->info);
sig = gdb_handlesig(cpu, sig, NULL, &k->info, sizeof(k->info));
@@ -1197,7 +1203,7 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig,
}
if (unlikely(qemu_loglevel_mask(LOG_STRACE))) {
- print_taken_signal(sig, &k->info);
+ print_taken_signal(sig, &unswapped);
}
if (handler == TARGET_SIG_DFL) {
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index e12d969..3df2b94 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -9272,14 +9272,24 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
#ifdef TARGET_NR_waitid
case TARGET_NR_waitid:
{
+ struct rusage ru;
siginfo_t info;
- info.si_pid = 0;
- ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL));
- if (!is_error(ret) && arg3 && info.si_pid != 0) {
- if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
+
+ ret = get_errno(safe_waitid(arg1, arg2, (arg3 ? &info : NULL),
+ arg4, (arg5 ? &ru : NULL)));
+ if (!is_error(ret)) {
+ if (arg3) {
+ p = lock_user(VERIFY_WRITE, arg3,
+ sizeof(target_siginfo_t), 0);
+ if (!p) {
+ return -TARGET_EFAULT;
+ }
+ host_to_target_siginfo(p, &info);
+ unlock_user(p, arg3, sizeof(target_siginfo_t));
+ }
+ if (arg5 && host_to_target_rusage(arg5, &ru)) {
return -TARGET_EFAULT;
- host_to_target_siginfo(p, &info);
- unlock_user(p, arg3, sizeof(target_siginfo_t));
+ }
}
}
return ret;
diff --git a/meson.build b/meson.build
index c9c3217..91a0aa6 100644
--- a/meson.build
+++ b/meson.build
@@ -562,7 +562,11 @@ hardening_flags = [
#
# NB: Clang 17 is broken and SEGVs
# https://github.com/llvm/llvm-project/issues/75168
-if cc.compiles('extern struct { void (*cb)(void); } s; void f(void) { s.cb(); }',
+#
+# NB2: This clashes with the "retguard" extension of OpenBSD's Clang
+# https://gitlab.com/qemu-project/qemu/-/issues/2278
+if host_os != 'openbsd' and \
+ cc.compiles('extern struct { void (*cb)(void); } s; void f(void) { s.cb(); }',
name: '-fzero-call-used-regs=used-gpr',
args: ['-O2', '-fzero-call-used-regs=used-gpr'])
hardening_flags += '-fzero-call-used-regs=used-gpr'
diff --git a/migration/savevm.c b/migration/savevm.c
index 388d7af..e7c1215 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2342,6 +2342,27 @@ static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis)
QEMUFile *packf = qemu_file_new_input(QIO_CHANNEL(bioc));
+ /*
+ * Before loading the guest states, ensure that the preempt channel has
+ * been ready to use, as some of the states (e.g. via virtio_load) might
+ * trigger page faults that will be handled through the preempt channel.
+ * So yield to the main thread in the case that the channel create event
+ * hasn't been dispatched.
+ *
+ * TODO: if we can move migration loadvm out of main thread, then we
+ * won't block main thread from polling the accept() fds. We can drop
+ * this as a whole when that is done.
+ */
+ do {
+ if (!migrate_postcopy_preempt() || !qemu_in_coroutine() ||
+ mis->postcopy_qemufile_dst) {
+ break;
+ }
+
+ aio_co_schedule(qemu_get_current_aio_context(), qemu_coroutine_self());
+ qemu_coroutine_yield();
+ } while (1);
+
ret = qemu_loadvm_state_main(packf, mis);
trace_loadvm_handle_cmd_packaged_main(ret);
qemu_fclose(packf);
diff --git a/pc-bios/edk2-aarch64-code.fd.bz2 b/pc-bios/edk2-aarch64-code.fd.bz2
index 3204e28..e763982 100644
--- a/pc-bios/edk2-aarch64-code.fd.bz2
+++ b/pc-bios/edk2-aarch64-code.fd.bz2
Binary files differ
diff --git a/pc-bios/edk2-arm-code.fd.bz2 b/pc-bios/edk2-arm-code.fd.bz2
index de916e9..329646d 100644
--- a/pc-bios/edk2-arm-code.fd.bz2
+++ b/pc-bios/edk2-arm-code.fd.bz2
Binary files differ
diff --git a/pc-bios/edk2-i386-code.fd.bz2 b/pc-bios/edk2-i386-code.fd.bz2
index ecd0c6b..271ce65 100644
--- a/pc-bios/edk2-i386-code.fd.bz2
+++ b/pc-bios/edk2-i386-code.fd.bz2
Binary files differ
diff --git a/pc-bios/edk2-i386-secure-code.fd.bz2 b/pc-bios/edk2-i386-secure-code.fd.bz2
index 925a7d1..00335cd 100644
--- a/pc-bios/edk2-i386-secure-code.fd.bz2
+++ b/pc-bios/edk2-i386-secure-code.fd.bz2
Binary files differ
diff --git a/pc-bios/edk2-riscv-code.fd.bz2 b/pc-bios/edk2-riscv-code.fd.bz2
index 4461170..f3a98d6 100644
--- a/pc-bios/edk2-riscv-code.fd.bz2
+++ b/pc-bios/edk2-riscv-code.fd.bz2
Binary files differ
diff --git a/pc-bios/edk2-x86_64-code.fd.bz2 b/pc-bios/edk2-x86_64-code.fd.bz2
index 8707f69..a1a8c05 100644
--- a/pc-bios/edk2-x86_64-code.fd.bz2
+++ b/pc-bios/edk2-x86_64-code.fd.bz2
Binary files differ
diff --git a/pc-bios/edk2-x86_64-microvm.fd.bz2 b/pc-bios/edk2-x86_64-microvm.fd.bz2
index 334da49..6b7cd54 100644
--- a/pc-bios/edk2-x86_64-microvm.fd.bz2
+++ b/pc-bios/edk2-x86_64-microvm.fd.bz2
Binary files differ
diff --git a/pc-bios/edk2-x86_64-secure-code.fd.bz2 b/pc-bios/edk2-x86_64-secure-code.fd.bz2
index abeb60b..ef40a8b 100644
--- a/pc-bios/edk2-x86_64-secure-code.fd.bz2
+++ b/pc-bios/edk2-x86_64-secure-code.fd.bz2
Binary files differ
diff --git a/qemu-options.hx b/qemu-options.hx
index 7fd1713..8ce85d4 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -151,14 +151,14 @@ SRST
platform and configuration dependent.
``interleave-granularity=granularity`` sets the granularity of
- interleave. Default 256KiB. Only 256KiB, 512KiB, 1024KiB, 2048KiB
- 4096KiB, 8192KiB and 16384KiB granularities supported.
+ interleave. Default 256 (bytes). Only 256, 512, 1k, 2k,
+ 4k, 8k and 16k granularities supported.
Example:
::
- -machine cxl-fmw.0.targets.0=cxl.0,cxl-fmw.0.targets.1=cxl.1,cxl-fmw.0.size=128G,cxl-fmw.0.interleave-granularity=512k
+ -machine cxl-fmw.0.targets.0=cxl.0,cxl-fmw.0.targets.1=cxl.1,cxl-fmw.0.size=128G,cxl-fmw.0.interleave-granularity=512
ERST
DEF("M", HAS_ARG, QEMU_OPTION_M,
diff --git a/roms/Makefile b/roms/Makefile
index edc234a..dfed2b2 100644
--- a/roms/Makefile
+++ b/roms/Makefile
@@ -41,8 +41,8 @@ x86_64_cross_prefix := $(call find-cross-prefix,x86_64)
riscv32_cross_prefix := $(call find-cross-prefix,riscv32)
riscv64_cross_prefix := $(call find-cross-prefix,riscv64)
-# tag our seabios builds
-SEABIOS_EXTRAVERSION="-prebuilt.qemu.org"
+# tag our firmware builds
+FIRMWARE_EXTRAVERSION = -prebuilt.qemu.org
#
# EfiRom utility is shipped with edk2 / tianocore, in BaseTools/
@@ -52,6 +52,8 @@ SEABIOS_EXTRAVERSION="-prebuilt.qemu.org"
#
EDK2_EFIROM = edk2/BaseTools/Source/C/bin/EfiRom
+-include edk2-version
+
default help:
@echo "nothing is build by default"
@echo "available build targets:"
@@ -91,12 +93,12 @@ build-seabios-config-%: config.%
mkdir -p seabios/builds/$*
cp $< seabios/builds/$*/.config
$(MAKE) -C seabios \
- EXTRAVERSION=$(SEABIOS_EXTRAVERSION) \
+ EXTRAVERSION=$(FIRMWARE_EXTRAVERSION) \
CROSS_PREFIX=$(x86_64_cross_prefix) \
KCONFIG_CONFIG=$(CURDIR)/seabios/builds/$*/.config \
OUT=$(CURDIR)/seabios/builds/$*/ oldnoconfig
$(MAKE) -C seabios \
- EXTRAVERSION=$(SEABIOS_EXTRAVERSION) \
+ EXTRAVERSION=$(FIRMWARE_EXTRAVERSION) \
CROSS_PREFIX=$(x86_64_cross_prefix) \
KCONFIG_CONFIG=$(CURDIR)/seabios/builds/$*/.config \
OUT=$(CURDIR)/seabios/builds/$*/ all
@@ -147,10 +149,19 @@ skiboot:
$(MAKE) -C skiboot CROSS=$(powerpc64_cross_prefix)
cp skiboot/skiboot.lid ../pc-bios/skiboot.lid
-efi:
+edk2-version: edk2
+ if test -e edk2/.git; then \
+ echo "EDK2_STABLE = $$(cd edk2; git describe --tags --match 'edk2-stable*')" > $@; \
+ echo "EDK2_DATE = $$(cd edk2; git log -1 --pretty='format:%cd' --date='format:%m/%d/%Y')" >> $@; \
+ else \
+ touch $@; \
+ fi
+
+efi: edk2-version
$(PYTHON) edk2-build.py --config edk2-build.config \
- --version-override "edk2-stable202302-for-qemu" \
- --release-date "03/01/2023"
+ --version-override "$(EDK2_STABLE)$(FIRMWARE_EXTRAVERSION)" \
+ --release-date "$(EDK2_DATE)" \
+ --silent --no-logs
rm -f ../pc-bios/edk2-*.fd.bz2
bzip2 --verbose ../pc-bios/edk2-*.fd
diff --git a/roms/edk2-version b/roms/edk2-version
new file mode 100644
index 0000000..1594ed8
--- /dev/null
+++ b/roms/edk2-version
@@ -0,0 +1,2 @@
+EDK2_STABLE = edk2-stable202402
+EDK2_DATE = 02/14/2024
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 3f3a5b5..a620481 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -3452,7 +3452,8 @@ static CPAccessResult gt_cntpoff_access(CPUARMState *env,
const ARMCPRegInfo *ri,
bool isread)
{
- if (arm_current_el(env) == 2 && !(env->cp15.scr_el3 & SCR_ECVEN)) {
+ if (arm_current_el(env) == 2 && arm_feature(env, ARM_FEATURE_EL3) &&
+ !(env->cp15.scr_el3 & SCR_ECVEN)) {
return CP_ACCESS_TRAP_EL3;
}
return CP_ACCESS_OK;
@@ -3878,6 +3879,8 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri,
ARMMMUIdx mmu_idx;
uint64_t hcr_el2 = arm_hcr_el2_eff(env);
bool regime_e20 = (hcr_el2 & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE);
+ bool for_el3 = false;
+ ARMSecuritySpace ss;
switch (ri->opc2 & 6) {
case 0:
@@ -3895,6 +3898,7 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri,
break;
case 6: /* AT S1E3R, AT S1E3W */
mmu_idx = ARMMMUIdx_E3;
+ for_el3 = true;
break;
default:
g_assert_not_reached();
@@ -3913,8 +3917,8 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri,
g_assert_not_reached();
}
- env->cp15.par_el[1] = do_ats_write(env, value, access_type,
- mmu_idx, arm_security_space(env));
+ ss = for_el3 ? arm_security_space(env) : arm_security_space_below_el3(env);
+ env->cp15.par_el[1] = do_ats_write(env, value, access_type, mmu_idx, ss);
#else
/* Handled by hardware accelerator. */
g_assert_not_reached();
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 340265b..2666d52 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -14179,7 +14179,7 @@ static void aarch64_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
pc_arg &= ~TARGET_PAGE_MASK;
}
tcg_gen_insn_start(pc_arg, 0, 0);
- dc->insn_start = tcg_last_op();
+ dc->insn_start_updated = false;
}
static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c
index 69585e6..dc49a8d 100644
--- a/target/arm/tcg/translate.c
+++ b/target/arm/tcg/translate.c
@@ -9273,7 +9273,7 @@ static void arm_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
condexec_bits = (dc->condexec_cond << 4) | (dc->condexec_mask >> 1);
}
tcg_gen_insn_start(pc_arg, condexec_bits, 0);
- dc->insn_start = tcg_last_op();
+ dc->insn_start_updated = false;
}
static bool arm_check_kernelpage(DisasContext *dc)
diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h
index 93be745..dc66ff2 100644
--- a/target/arm/tcg/translate.h
+++ b/target/arm/tcg/translate.h
@@ -165,10 +165,10 @@ typedef struct DisasContext {
uint8_t gm_blocksize;
/* True if this page is guarded. */
bool guarded_page;
+ /* True if the current insn_start has been updated. */
+ bool insn_start_updated;
/* Bottom two bits of XScale c15_cpar coprocessor access control reg */
int c15_cpar;
- /* TCG op of the current insn_start. */
- TCGOp *insn_start;
/* Offset from VNCR_EL2 when FEAT_NV2 redirects this reg to memory */
uint32_t nv2_redirect_offset;
} DisasContext;
@@ -276,10 +276,10 @@ static inline void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
syn &= ARM_INSN_START_WORD2_MASK;
syn >>= ARM_INSN_START_WORD2_SHIFT;
- /* We check and clear insn_start_idx to catch multiple updates. */
- assert(s->insn_start != NULL);
- tcg_set_insn_start_param(s->insn_start, 2, syn);
- s->insn_start = NULL;
+ /* Check for multiple updates. */
+ assert(!s->insn_start_updated);
+ s->insn_start_updated = true;
+ tcg_set_insn_start_param(s->base.insn_start, 2, syn);
}
static inline int curr_insn_len(DisasContext *s)
diff --git a/target/hppa/int_helper.c b/target/hppa/int_helper.c
index 90437a9..a667ee3 100644
--- a/target/hppa/int_helper.c
+++ b/target/hppa/int_helper.c
@@ -107,14 +107,10 @@ void hppa_cpu_do_interrupt(CPUState *cs)
/* step 3 */
/*
- * For pa1.x, IIASQ is simply a copy of IASQ.
- * For pa2.0, IIASQ is the top bits of the virtual address,
- * or zero if translation is disabled.
+ * IIASQ is the top bits of the virtual address, or zero if translation
+ * is disabled -- with PSW_W == 0, this will reduce to the space.
*/
- if (!hppa_is_pa20(env)) {
- env->cr[CR_IIASQ] = env->iasq_f >> 32;
- env->cr_back[0] = env->iasq_b >> 32;
- } else if (old_psw & PSW_C) {
+ if (old_psw & PSW_C) {
env->cr[CR_IIASQ] =
hppa_form_gva_psw(old_psw, env->iasq_f, env->iaoq_f) >> 32;
env->cr_back[0] =
@@ -123,8 +119,14 @@ void hppa_cpu_do_interrupt(CPUState *cs)
env->cr[CR_IIASQ] = 0;
env->cr_back[0] = 0;
}
- env->cr[CR_IIAOQ] = env->iaoq_f;
- env->cr_back[1] = env->iaoq_b;
+ /* IIAOQ is the full offset for wide mode, or 32 bits for narrow mode. */
+ if (old_psw & PSW_W) {
+ env->cr[CR_IIAOQ] = env->iaoq_f;
+ env->cr_back[1] = env->iaoq_b;
+ } else {
+ env->cr[CR_IIAOQ] = (uint32_t)env->iaoq_f;
+ env->cr_back[1] = (uint32_t)env->iaoq_b;
+ }
if (old_psw & PSW_Q) {
/* step 5 */
diff --git a/target/hppa/sys_helper.c b/target/hppa/sys_helper.c
index 208e51c..22d6c89 100644
--- a/target/hppa/sys_helper.c
+++ b/target/hppa/sys_helper.c
@@ -78,21 +78,21 @@ target_ulong HELPER(swap_system_mask)(CPUHPPAState *env, target_ulong nsm)
void HELPER(rfi)(CPUHPPAState *env)
{
- env->iasq_f = (uint64_t)env->cr[CR_IIASQ] << 32;
- env->iasq_b = (uint64_t)env->cr_back[0] << 32;
- env->iaoq_f = env->cr[CR_IIAOQ];
- env->iaoq_b = env->cr_back[1];
+ uint64_t mask;
+
+ cpu_hppa_put_psw(env, env->cr[CR_IPSW]);
/*
* For pa2.0, IIASQ is the top bits of the virtual address.
* To recreate the space identifier, remove the offset bits.
+ * For pa1.x, the mask reduces to no change to space.
*/
- if (hppa_is_pa20(env)) {
- env->iasq_f &= ~env->iaoq_f;
- env->iasq_b &= ~env->iaoq_b;
- }
+ mask = gva_offset_mask(env->psw);
- cpu_hppa_put_psw(env, env->cr[CR_IPSW]);
+ env->iaoq_f = env->cr[CR_IIAOQ];
+ env->iaoq_b = env->cr_back[1];
+ env->iasq_f = (env->cr[CR_IIASQ] << 32) & ~(env->iaoq_f & mask);
+ env->iasq_b = (env->cr_back[0] << 32) & ~(env->iaoq_b & mask);
}
static void getshadowregs(CPUHPPAState *env)
diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index 8a1a8bc..42fa480 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -44,7 +44,6 @@ typedef struct DisasCond {
typedef struct DisasContext {
DisasContextBase base;
CPUState *cs;
- TCGOp *insn_start;
uint64_t iaoq_f;
uint64_t iaoq_b;
@@ -62,6 +61,7 @@ typedef struct DisasContext {
int privilege;
bool psw_n_nonzero;
bool is_pa20;
+ bool insn_start_updated;
#ifdef CONFIG_USER_ONLY
MemOp unalign;
@@ -300,9 +300,9 @@ void hppa_translate_init(void)
static void set_insn_breg(DisasContext *ctx, int breg)
{
- assert(ctx->insn_start != NULL);
- tcg_set_insn_start_param(ctx->insn_start, 2, breg);
- ctx->insn_start = NULL;
+ assert(!ctx->insn_start_updated);
+ ctx->insn_start_updated = true;
+ tcg_set_insn_start_param(ctx->base.insn_start, 2, breg);
}
static DisasCond cond_make_f(void)
@@ -4694,7 +4694,7 @@ static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
DisasContext *ctx = container_of(dcbase, DisasContext, base);
tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b, 0);
- ctx->insn_start = tcg_last_op();
+ ctx->insn_start_updated = false;
}
static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 07f642d..76a42c6 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -139,6 +139,7 @@ typedef struct DisasContext {
TCGv_i64 tmp1_i64;
sigjmp_buf jmpbuf;
+ TCGOp *prev_insn_start;
TCGOp *prev_insn_end;
} DisasContext;
@@ -3123,6 +3124,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
/* END TODO */
s->base.num_insns--;
tcg_remove_ops_after(s->prev_insn_end);
+ s->base.insn_start = s->prev_insn_start;
s->base.is_jmp = DISAS_TOO_MANY;
return false;
default:
@@ -6995,6 +6997,7 @@ static void i386_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
DisasContext *dc = container_of(dcbase, DisasContext, base);
target_ulong pc_arg = dc->base.pc_next;
+ dc->prev_insn_start = dc->base.insn_start;
dc->prev_insn_end = tcg_last_op();
if (tb_cflags(dcbase->tb) & CF_PCREL) {
pc_arg &= ~TARGET_PAGE_MASK;
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
index 7c8efbb..df49ff1 100644
--- a/target/m68k/cpu.c
+++ b/target/m68k/cpu.c
@@ -390,12 +390,19 @@ static const VMStateDescription vmstate_freg = {
}
};
-static int fpu_post_load(void *opaque, int version)
+static int fpu_pre_save(void *opaque)
{
M68kCPU *s = opaque;
- cpu_m68k_restore_fp_status(&s->env);
+ s->env.fpsr = cpu_m68k_get_fpsr(&s->env);
+ return 0;
+}
+
+static int fpu_post_load(void *opaque, int version)
+{
+ M68kCPU *s = opaque;
+ cpu_m68k_set_fpsr(&s->env, s->env.fpsr);
return 0;
}
@@ -404,6 +411,7 @@ const VMStateDescription vmmstate_fpu = {
.version_id = 1,
.minimum_version_id = 1,
.needed = fpu_needed,
+ .pre_save = fpu_pre_save,
.post_load = fpu_post_load,
.fields = (const VMStateField[]) {
VMSTATE_UINT32(env.fpcr, M68kCPU),
diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h
index 346427e..e184239 100644
--- a/target/m68k/cpu.h
+++ b/target/m68k/cpu.h
@@ -199,7 +199,8 @@ void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t);
void cpu_m68k_set_sr(CPUM68KState *env, uint32_t);
void cpu_m68k_restore_fp_status(CPUM68KState *env);
void cpu_m68k_set_fpcr(CPUM68KState *env, uint32_t val);
-
+uint32_t cpu_m68k_get_fpsr(CPUM68KState *env);
+void cpu_m68k_set_fpsr(CPUM68KState *env, uint32_t val);
/*
* Instead of computing the condition codes after each m68k instruction,
diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
index ab120b5..8314791 100644
--- a/target/m68k/fpu_helper.c
+++ b/target/m68k/fpu_helper.c
@@ -164,6 +164,78 @@ void HELPER(set_fpcr)(CPUM68KState *env, uint32_t val)
cpu_m68k_set_fpcr(env, val);
}
+/* Convert host exception flags to cpu_m68k form. */
+static int cpu_m68k_exceptbits_from_host(int host_bits)
+{
+ int target_bits = 0;
+
+ if (host_bits & float_flag_invalid) {
+ target_bits |= 0x80;
+ }
+ if (host_bits & float_flag_overflow) {
+ target_bits |= 0x40;
+ }
+ if (host_bits & (float_flag_underflow | float_flag_output_denormal)) {
+ target_bits |= 0x20;
+ }
+ if (host_bits & float_flag_divbyzero) {
+ target_bits |= 0x10;
+ }
+ if (host_bits & float_flag_inexact) {
+ target_bits |= 0x08;
+ }
+ return target_bits;
+}
+
+/* Convert cpu_m68k exception flags to target form. */
+static int cpu_m68k_exceptbits_to_host(int target_bits)
+{
+ int host_bits = 0;
+
+ if (target_bits & 0x80) {
+ host_bits |= float_flag_invalid;
+ }
+ if (target_bits & 0x40) {
+ host_bits |= float_flag_overflow;
+ }
+ if (target_bits & 0x20) {
+ host_bits |= float_flag_underflow;
+ }
+ if (target_bits & 0x10) {
+ host_bits |= float_flag_divbyzero;
+ }
+ if (target_bits & 0x08) {
+ host_bits |= float_flag_inexact;
+ }
+ return host_bits;
+}
+
+uint32_t cpu_m68k_get_fpsr(CPUM68KState *env)
+{
+ int host_flags = get_float_exception_flags(&env->fp_status);
+ int target_flags = cpu_m68k_exceptbits_from_host(host_flags);
+ int except = (env->fpsr & ~(0xf8)) | target_flags;
+ return except;
+}
+
+uint32_t HELPER(get_fpsr)(CPUM68KState *env)
+{
+ return cpu_m68k_get_fpsr(env);
+}
+
+void cpu_m68k_set_fpsr(CPUM68KState *env, uint32_t val)
+{
+ env->fpsr = val;
+
+ int host_flags = cpu_m68k_exceptbits_to_host((int) env->fpsr);
+ set_float_exception_flags(host_flags, &env->fp_status);
+}
+
+void HELPER(set_fpsr)(CPUM68KState *env, uint32_t val)
+{
+ cpu_m68k_set_fpsr(env, val);
+}
+
#define PREC_BEGIN(prec) \
do { \
FloatX80RoundPrec old = \
diff --git a/target/m68k/helper.c b/target/m68k/helper.c
index 1a475f0..7a91f33 100644
--- a/target/m68k/helper.c
+++ b/target/m68k/helper.c
@@ -87,7 +87,7 @@ static int m68k_fpu_gdb_get_reg(CPUState *cs, GByteArray *mem_buf, int n)
case 8: /* fpcontrol */
return gdb_get_reg32(mem_buf, env->fpcr);
case 9: /* fpstatus */
- return gdb_get_reg32(mem_buf, env->fpsr);
+ return gdb_get_reg32(mem_buf, cpu_m68k_get_fpsr(env));
case 10: /* fpiar, not implemented */
return gdb_get_reg32(mem_buf, 0);
}
@@ -109,7 +109,7 @@ static int m68k_fpu_gdb_set_reg(CPUState *cs, uint8_t *mem_buf, int n)
cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
return 4;
case 9: /* fpstatus */
- env->fpsr = ldl_p(mem_buf);
+ cpu_m68k_set_fpsr(env, ldl_p(mem_buf));
return 4;
case 10: /* fpiar, not implemented */
return 4;
diff --git a/target/m68k/helper.h b/target/m68k/helper.h
index 2bbe0dc..95aa5e5 100644
--- a/target/m68k/helper.h
+++ b/target/m68k/helper.h
@@ -54,6 +54,8 @@ DEF_HELPER_4(fsdiv, void, env, fp, fp, fp)
DEF_HELPER_4(fddiv, void, env, fp, fp, fp)
DEF_HELPER_4(fsgldiv, void, env, fp, fp, fp)
DEF_HELPER_FLAGS_3(fcmp, TCG_CALL_NO_RWG, void, env, fp, fp)
+DEF_HELPER_2(set_fpsr, void, env, i32)
+DEF_HELPER_1(get_fpsr, i32, env)
DEF_HELPER_FLAGS_2(set_fpcr, TCG_CALL_NO_RWG, void, env, i32)
DEF_HELPER_FLAGS_2(ftst, TCG_CALL_NO_RWG, void, env, fp)
DEF_HELPER_3(fconst, void, env, fp, i32)
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 6ae3df4..8a194f2 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -4686,7 +4686,7 @@ static void gen_load_fcr(DisasContext *s, TCGv res, int reg)
tcg_gen_movi_i32(res, 0);
break;
case M68K_FPSR:
- tcg_gen_ld_i32(res, tcg_env, offsetof(CPUM68KState, fpsr));
+ gen_helper_get_fpsr(res, tcg_env);
break;
case M68K_FPCR:
tcg_gen_ld_i32(res, tcg_env, offsetof(CPUM68KState, fpcr));
@@ -4700,7 +4700,7 @@ static void gen_store_fcr(DisasContext *s, TCGv val, int reg)
case M68K_FPIAR:
break;
case M68K_FPSR:
- tcg_gen_st_i32(val, tcg_env, offsetof(CPUM68KState, fpsr));
+ gen_helper_set_fpsr(tcg_env, val);
break;
case M68K_FPCR:
gen_helper_set_fpcr(tcg_env, val);
diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c
index 4e52ef3..fc451be 100644
--- a/target/microblaze/translate.c
+++ b/target/microblaze/translate.c
@@ -62,9 +62,6 @@ typedef struct DisasContext {
DisasContextBase base;
const MicroBlazeCPUConfig *cfg;
- /* TCG op of the current insn_start. */
- TCGOp *insn_start;
-
TCGv_i32 r0;
bool r0_set;
@@ -699,14 +696,14 @@ static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb)
static void record_unaligned_ess(DisasContext *dc, int rd,
MemOp size, bool store)
{
- uint32_t iflags = tcg_get_insn_start_param(dc->insn_start, 1);
+ uint32_t iflags = tcg_get_insn_start_param(dc->base.insn_start, 1);
iflags |= ESR_ESS_FLAG;
iflags |= rd << 5;
iflags |= store * ESR_S;
iflags |= (size == MO_32) * ESR_W;
- tcg_set_insn_start_param(dc->insn_start, 1, iflags);
+ tcg_set_insn_start_param(dc->base.insn_start, 1, iflags);
}
#endif
@@ -1624,7 +1621,6 @@ static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs)
DisasContext *dc = container_of(dcb, DisasContext, base);
tcg_gen_insn_start(dc->base.pc_next, dc->tb_flags & ~MSR_TB_MASK);
- dc->insn_start = tcg_last_op();
}
static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs)
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 9d57089..9ff09eb 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -115,8 +115,7 @@ typedef struct DisasContext {
bool itrigger;
/* FRM is known to contain a valid value. */
bool frm_valid;
- /* TCG of the current insn_start */
- TCGOp *insn_start;
+ bool insn_start_updated;
} DisasContext;
static inline bool has_ext(DisasContext *ctx, uint32_t ext)
@@ -207,9 +206,9 @@ static void gen_check_nanbox_s(TCGv_i64 out, TCGv_i64 in)
static void decode_save_opc(DisasContext *ctx)
{
- assert(ctx->insn_start != NULL);
- tcg_set_insn_start_param(ctx->insn_start, 1, ctx->opcode);
- ctx->insn_start = NULL;
+ assert(!ctx->insn_start_updated);
+ ctx->insn_start_updated = true;
+ tcg_set_insn_start_param(ctx->base.insn_start, 1, ctx->opcode);
}
static void gen_pc_plus_diff(TCGv target, DisasContext *ctx,
@@ -1224,7 +1223,7 @@ static void riscv_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
}
tcg_gen_insn_start(pc_next, 0);
- ctx->insn_start = tcg_last_op();
+ ctx->insn_start_updated = false;
}
static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c
index 57b7db1..90a74ee 100644
--- a/target/s390x/tcg/translate.c
+++ b/target/s390x/tcg/translate.c
@@ -141,7 +141,6 @@ struct DisasFields {
struct DisasContext {
DisasContextBase base;
const DisasInsn *insn;
- TCGOp *insn_start;
DisasFields fields;
uint64_t ex_value;
/*
@@ -6314,7 +6313,7 @@ static DisasJumpType translate_one(CPUS390XState *env, DisasContext *s)
insn = extract_insn(env, s);
/* Update insn_start now that we know the ILEN. */
- tcg_set_insn_start_param(s->insn_start, 2, s->ilen);
+ tcg_set_insn_start_param(s->base.insn_start, 2, s->ilen);
/* Not found means unimplemented/illegal opcode. */
if (insn == NULL) {
@@ -6468,7 +6467,6 @@ static void s390x_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
/* Delay the set of ilen until we've read the insn. */
tcg_gen_insn_start(dc->base.pc_next, dc->cc_op, 0);
- dc->insn_start = tcg_last_op();
}
static target_ulong get_next_pc(CPUS390XState *env, DisasContext *s,
diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h
index 9211da6..d928bcf 100644
--- a/target/sh4/cpu.h
+++ b/target/sh4/cpu.h
@@ -155,12 +155,22 @@ typedef struct CPUArchState {
uint32_t pc; /* program counter */
uint32_t delayed_pc; /* target of delayed branch */
uint32_t delayed_cond; /* condition of delayed branch */
- uint32_t mach; /* multiply and accumulate high */
- uint32_t macl; /* multiply and accumulate low */
uint32_t pr; /* procedure register */
uint32_t fpscr; /* floating point status/control register */
uint32_t fpul; /* floating point communication register */
+ /* multiply and accumulate: high, low and combined. */
+ union {
+ uint64_t mac;
+ struct {
+#if HOST_BIG_ENDIAN
+ uint32_t mach, macl;
+#else
+ uint32_t macl, mach;
+#endif
+ };
+ };
+
/* float point status register */
float_status fp_status;
diff --git a/target/sh4/helper.h b/target/sh4/helper.h
index 8d792f6..29011d3 100644
--- a/target/sh4/helper.h
+++ b/target/sh4/helper.h
@@ -11,8 +11,8 @@ DEF_HELPER_3(movcal, void, env, i32, i32)
DEF_HELPER_1(discard_movcal_backup, void, env)
DEF_HELPER_2(ocbi, void, env, i32)
-DEF_HELPER_3(macl, void, env, i32, i32)
-DEF_HELPER_3(macw, void, env, i32, i32)
+DEF_HELPER_3(macl, void, env, s32, s32)
+DEF_HELPER_3(macw, void, env, s32, s32)
DEF_HELPER_2(ld_fpscr, void, env, i32)
diff --git a/target/sh4/op_helper.c b/target/sh4/op_helper.c
index 4559d0d..99394b7 100644
--- a/target/sh4/op_helper.c
+++ b/target/sh4/op_helper.c
@@ -158,38 +158,47 @@ void helper_ocbi(CPUSH4State *env, uint32_t address)
}
}
-void helper_macl(CPUSH4State *env, uint32_t arg0, uint32_t arg1)
+void helper_macl(CPUSH4State *env, int32_t arg0, int32_t arg1)
{
+ const int64_t min = -(1ll << 47);
+ const int64_t max = (1ll << 47) - 1;
+ int64_t mul = (int64_t)arg0 * arg1;
+ int64_t mac = env->mac;
int64_t res;
- res = ((uint64_t) env->mach << 32) | env->macl;
- res += (int64_t) (int32_t) arg0 *(int64_t) (int32_t) arg1;
- env->mach = (res >> 32) & 0xffffffff;
- env->macl = res & 0xffffffff;
- if (env->sr & (1u << SR_S)) {
- if (res < 0)
- env->mach |= 0xffff0000;
- else
- env->mach &= 0x00007fff;
+ if (!(env->sr & (1u << SR_S))) {
+ res = mac + mul;
+ } else if (sadd64_overflow(mac, mul, &res)) {
+ res = mac < 0 ? min : max;
+ } else {
+ res = MIN(MAX(res, min), max);
}
+
+ env->mac = res;
}
-void helper_macw(CPUSH4State *env, uint32_t arg0, uint32_t arg1)
+void helper_macw(CPUSH4State *env, int32_t arg0, int32_t arg1)
{
- int64_t res;
+ /* Inputs are already sign-extended from 16 bits. */
+ int32_t mul = arg0 * arg1;
- res = ((uint64_t) env->mach << 32) | env->macl;
- res += (int64_t) (int16_t) arg0 *(int64_t) (int16_t) arg1;
- env->mach = (res >> 32) & 0xffffffff;
- env->macl = res & 0xffffffff;
if (env->sr & (1u << SR_S)) {
- if (res < -0x80000000) {
- env->mach = 1;
- env->macl = 0x80000000;
- } else if (res > 0x000000007fffffff) {
+ /*
+ * In saturation arithmetic mode, the accumulator is 32-bit
+ * with carry. MACH is not considered during the addition
+ * operation nor the 32-bit saturation logic.
+ */
+ int32_t res, macl = env->macl;
+
+ if (sadd32_overflow(macl, mul, &res)) {
+ res = macl < 0 ? INT32_MIN : INT32_MAX;
+ /* If overflow occurs, the MACH register is set to 1. */
env->mach = 1;
- env->macl = 0x7fffffff;
}
+ env->macl = res;
+ } else {
+ /* In non-saturation arithmetic mode, the accumulator is 64-bit */
+ env->mac += mul;
}
}
diff --git a/target/sh4/translate.c b/target/sh4/translate.c
index a9b1bc7..ebb6c90 100644
--- a/target/sh4/translate.c
+++ b/target/sh4/translate.c
@@ -523,6 +523,7 @@ static void _decode_opc(DisasContext * ctx)
tcg_gen_movi_i32(REG(B11_8), B7_0s);
return;
case 0x9000: /* mov.w @(disp,PC),Rn */
+ CHECK_NOT_DELAY_SLOT
{
TCGv addr = tcg_constant_i32(ctx->base.pc_next + 4 + B7_0 * 2);
tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx,
@@ -530,6 +531,7 @@ static void _decode_opc(DisasContext * ctx)
}
return;
case 0xd000: /* mov.l @(disp,PC),Rn */
+ CHECK_NOT_DELAY_SLOT
{
TCGv addr = tcg_constant_i32((ctx->base.pc_next + 4 + B7_0 * 4) & ~3);
tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx,
@@ -816,10 +818,10 @@ static void _decode_opc(DisasContext * ctx)
TCGv arg0, arg1;
arg0 = tcg_temp_new();
tcg_gen_qemu_ld_i32(arg0, REG(B7_4), ctx->memidx,
- MO_TESL | MO_ALIGN);
+ MO_TESW | MO_ALIGN);
arg1 = tcg_temp_new();
tcg_gen_qemu_ld_i32(arg1, REG(B11_8), ctx->memidx,
- MO_TESL | MO_ALIGN);
+ MO_TESW | MO_ALIGN);
gen_helper_macw(tcg_env, arg0, arg1);
tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 2);
tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 2);
@@ -1236,6 +1238,7 @@ static void _decode_opc(DisasContext * ctx)
}
return;
case 0xc700: /* mova @(disp,PC),R0 */
+ CHECK_NOT_DELAY_SLOT
tcg_gen_movi_i32(REG(0), ((ctx->base.pc_next & 0xfffffffc) +
4 + B7_0 * 4) & ~3);
return;
diff --git a/target/sparc/helper.h b/target/sparc/helper.h
index e55fad5..b8087d0 100644
--- a/target/sparc/helper.h
+++ b/target/sparc/helper.h
@@ -32,6 +32,9 @@ DEF_HELPER_FLAGS_3(udiv, TCG_CALL_NO_WG, i64, env, tl, tl)
DEF_HELPER_FLAGS_3(sdiv, TCG_CALL_NO_WG, i64, env, tl, tl)
DEF_HELPER_3(taddcctv, tl, env, tl, tl)
DEF_HELPER_3(tsubcctv, tl, env, tl, tl)
+#if !defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64)
+DEF_HELPER_FLAGS_3(ld_code, TCG_CALL_NO_WG, i64, env, tl, i32)
+#endif
#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
DEF_HELPER_FLAGS_4(ld_asi, TCG_CALL_NO_WG, i64, env, tl, int, i32)
DEF_HELPER_FLAGS_5(st_asi, TCG_CALL_NO_WG, void, env, tl, i64, int, i32)
diff --git a/target/sparc/ldst_helper.c b/target/sparc/ldst_helper.c
index e581bb4..2846a86 100644
--- a/target/sparc/ldst_helper.c
+++ b/target/sparc/ldst_helper.c
@@ -585,7 +585,6 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr,
#if defined(DEBUG_MXCC) || defined(DEBUG_ASI)
uint32_t last_addr = addr;
#endif
- MemOpIdx oi;
do_check_align(env, addr, size - 1, GETPC());
switch (asi) {
@@ -684,24 +683,6 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr,
case ASI_M_DIAGS: /* Turbosparc DTLB Diagnostic */
case ASI_M_IODIAG: /* Turbosparc IOTLB Diagnostic */
break;
- case ASI_KERNELTXT: /* Supervisor code access */
- oi = make_memop_idx(memop, cpu_mmu_index(env_cpu(env), true));
- switch (size) {
- case 1:
- ret = cpu_ldb_code_mmu(env, addr, oi, GETPC());
- break;
- case 2:
- ret = cpu_ldw_code_mmu(env, addr, oi, GETPC());
- break;
- default:
- case 4:
- ret = cpu_ldl_code_mmu(env, addr, oi, GETPC());
- break;
- case 8:
- ret = cpu_ldq_code_mmu(env, addr, oi, GETPC());
- break;
- }
- break;
case ASI_M_TXTC_TAG: /* SparcStation 5 I-cache tag */
case ASI_M_TXTC_DATA: /* SparcStation 5 I-cache data */
case ASI_M_DATAC_TAG: /* SparcStation 5 D-cache tag */
@@ -779,7 +760,6 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr,
case 0x4c: /* SuperSPARC MMU Breakpoint Action */
ret = env->mmubpaction;
break;
- case ASI_USERTXT: /* User code access, XXX */
default:
sparc_raise_mmu_fault(cs, addr, false, false, asi, size, GETPC());
ret = 0;
@@ -787,6 +767,8 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr,
case ASI_USERDATA: /* User data access */
case ASI_KERNELDATA: /* Supervisor data access */
+ case ASI_USERTXT: /* User code access */
+ case ASI_KERNELTXT: /* Supervisor code access */
case ASI_P: /* Implicit primary context data access (v9 only?) */
case ASI_M_BYPASS: /* MMU passthrough */
case ASI_LEON_BYPASS: /* LEON MMU passthrough */
@@ -1161,6 +1143,49 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val,
#endif
}
+uint64_t helper_ld_code(CPUSPARCState *env, target_ulong addr, uint32_t oi)
+{
+ MemOp mop = get_memop(oi);
+ uintptr_t ra = GETPC();
+ uint64_t ret;
+
+ switch (mop & MO_SIZE) {
+ case MO_8:
+ ret = cpu_ldb_code_mmu(env, addr, oi, ra);
+ if (mop & MO_SIGN) {
+ ret = (int8_t)ret;
+ }
+ break;
+ case MO_16:
+ ret = cpu_ldw_code_mmu(env, addr, oi, ra);
+ if ((mop & MO_BSWAP) != MO_TE) {
+ ret = bswap16(ret);
+ }
+ if (mop & MO_SIGN) {
+ ret = (int16_t)ret;
+ }
+ break;
+ case MO_32:
+ ret = cpu_ldl_code_mmu(env, addr, oi, ra);
+ if ((mop & MO_BSWAP) != MO_TE) {
+ ret = bswap32(ret);
+ }
+ if (mop & MO_SIGN) {
+ ret = (int32_t)ret;
+ }
+ break;
+ case MO_64:
+ ret = cpu_ldq_code_mmu(env, addr, oi, ra);
+ if ((mop & MO_BSWAP) != MO_TE) {
+ ret = bswap64(ret);
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ return ret;
+}
+
#endif /* CONFIG_USER_ONLY */
#else /* TARGET_SPARC64 */
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index 319934d..571b3e3 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -1117,6 +1117,7 @@ typedef enum {
GET_ASI_EXCP,
GET_ASI_DIRECT,
GET_ASI_DTWINX,
+ GET_ASI_CODE,
GET_ASI_BLOCK,
GET_ASI_SHORT,
GET_ASI_BCOPY,
@@ -1159,14 +1160,22 @@ static DisasASI resolve_asi(DisasContext *dc, int asi, MemOp memop)
|| (asi == ASI_USERDATA
&& (dc->def->features & CPU_FEATURE_CASA))) {
switch (asi) {
- case ASI_USERDATA: /* User data access */
+ case ASI_USERDATA: /* User data access */
mem_idx = MMU_USER_IDX;
type = GET_ASI_DIRECT;
break;
- case ASI_KERNELDATA: /* Supervisor data access */
+ case ASI_KERNELDATA: /* Supervisor data access */
mem_idx = MMU_KERNEL_IDX;
type = GET_ASI_DIRECT;
break;
+ case ASI_USERTXT: /* User text access */
+ mem_idx = MMU_USER_IDX;
+ type = GET_ASI_CODE;
+ break;
+ case ASI_KERNELTXT: /* Supervisor text access */
+ mem_idx = MMU_KERNEL_IDX;
+ type = GET_ASI_CODE;
+ break;
case ASI_M_BYPASS: /* MMU passthrough */
case ASI_LEON_BYPASS: /* LEON MMU passthrough */
mem_idx = MMU_PHYS_IDX;
@@ -1379,6 +1388,21 @@ static void gen_ld_asi(DisasContext *dc, DisasASI *da, TCGv dst, TCGv addr)
case GET_ASI_DIRECT:
tcg_gen_qemu_ld_tl(dst, addr, da->mem_idx, da->memop | MO_ALIGN);
break;
+
+ case GET_ASI_CODE:
+#if !defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64)
+ {
+ MemOpIdx oi = make_memop_idx(da->memop, da->mem_idx);
+ TCGv_i64 t64 = tcg_temp_new_i64();
+
+ gen_helper_ld_code(t64, tcg_env, addr, tcg_constant_i32(oi));
+ tcg_gen_trunc_i64_tl(dst, t64);
+ }
+ break;
+#else
+ g_assert_not_reached();
+#endif
+
default:
{
TCGv_i32 r_asi = tcg_constant_i32(da->asi);
@@ -1791,6 +1815,26 @@ static void gen_ldda_asi(DisasContext *dc, DisasASI *da, TCGv addr, int rd)
}
break;
+ case GET_ASI_CODE:
+#if !defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64)
+ {
+ MemOpIdx oi = make_memop_idx(da->memop, da->mem_idx);
+ TCGv_i64 tmp = tcg_temp_new_i64();
+
+ gen_helper_ld_code(tmp, tcg_env, addr, tcg_constant_i32(oi));
+
+ /* See above. */
+ if ((da->memop & MO_BSWAP) == MO_TE) {
+ tcg_gen_extr_i64_tl(lo, hi, tmp);
+ } else {
+ tcg_gen_extr_i64_tl(hi, lo, tmp);
+ }
+ }
+ break;
+#else
+ g_assert_not_reached();
+#endif
+
default:
/* ??? In theory we've handled all of the ASIs that are valid
for ldda, and this should raise DAE_invalid_asi. However,
diff --git a/tcg/optimize.c b/tcg/optimize.c
index 275db77..2e9e572 100644
--- a/tcg/optimize.c
+++ b/tcg/optimize.c
@@ -1990,16 +1990,10 @@ static bool fold_nand(OptContext *ctx, TCGOp *op)
return false;
}
-static bool fold_neg(OptContext *ctx, TCGOp *op)
+static bool fold_neg_no_const(OptContext *ctx, TCGOp *op)
{
- uint64_t z_mask;
-
- if (fold_const1(ctx, op)) {
- return true;
- }
-
/* Set to 1 all bits to the left of the rightmost. */
- z_mask = arg_info(op->args[1])->z_mask;
+ uint64_t z_mask = arg_info(op->args[1])->z_mask;
ctx->z_mask = -(z_mask & -z_mask);
/*
@@ -2010,6 +2004,11 @@ static bool fold_neg(OptContext *ctx, TCGOp *op)
return true;
}
+static bool fold_neg(OptContext *ctx, TCGOp *op)
+{
+ return fold_const1(ctx, op) || fold_neg_no_const(ctx, op);
+}
+
static bool fold_nor(OptContext *ctx, TCGOp *op)
{
if (fold_const2_commutative(ctx, op) ||
@@ -2418,7 +2417,7 @@ static bool fold_sub_to_neg(OptContext *ctx, TCGOp *op)
if (have_neg) {
op->opc = neg_op;
op->args[1] = op->args[2];
- return fold_neg(ctx, op);
+ return fold_neg_no_const(ctx, op);
}
return false;
}
diff --git a/tcg/tcg.c b/tcg/tcg.c
index d667023..0c0bb9d 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -1521,6 +1521,7 @@ void tcg_func_start(TCGContext *s)
QTAILQ_INIT(&s->ops);
QTAILQ_INIT(&s->free_ops);
+ s->emit_before_op = NULL;
QSIMPLEQ_INIT(&s->labels);
tcg_debug_assert(s->addr_type == TCG_TYPE_I32 ||
@@ -2332,7 +2333,11 @@ static void tcg_gen_callN(TCGHelperInfo *info, TCGTemp *ret, TCGTemp **args)
op->args[pi++] = (uintptr_t)info;
tcg_debug_assert(pi == total_args);
- QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
+ if (tcg_ctx->emit_before_op) {
+ QTAILQ_INSERT_BEFORE(tcg_ctx->emit_before_op, op, link);
+ } else {
+ QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
+ }
tcg_debug_assert(n_extend < ARRAY_SIZE(extend_free));
for (i = 0; i < n_extend; ++i) {
@@ -3215,7 +3220,12 @@ static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs)
TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs)
{
TCGOp *op = tcg_op_alloc(opc, nargs);
- QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
+
+ if (tcg_ctx->emit_before_op) {
+ QTAILQ_INSERT_BEFORE(tcg_ctx->emit_before_op, op, link);
+ } else {
+ QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link);
+ }
return op;
}
diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
index 0efd565..70d728a 100644
--- a/tests/tcg/aarch64/Makefile.target
+++ b/tests/tcg/aarch64/Makefile.target
@@ -10,7 +10,7 @@ VPATH += $(AARCH64_SRC)
# Base architecture tests
AARCH64_TESTS=fcvt pcalign-a64 lse2-fault
-AARCH64_TESTS += test-2248
+AARCH64_TESTS += test-2248 test-2150
fcvt: LDFLAGS+=-lm
diff --git a/tests/tcg/aarch64/test-2150.c b/tests/tcg/aarch64/test-2150.c
new file mode 100644
index 0000000..fb86c11
--- /dev/null
+++ b/tests/tcg/aarch64/test-2150.c
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* See https://gitlab.com/qemu-project/qemu/-/issues/2150 */
+
+int main()
+{
+ asm volatile(
+ "movi v6.4s, #1\n"
+ "movi v7.4s, #0\n"
+ "sub v6.2d, v7.2d, v6.2d\n"
+ : : : "v6", "v7");
+ return 0;
+}
diff --git a/tests/tcg/sh4/Makefile.target b/tests/tcg/sh4/Makefile.target
index 16eaa85..4d09291c 100644
--- a/tests/tcg/sh4/Makefile.target
+++ b/tests/tcg/sh4/Makefile.target
@@ -9,3 +9,11 @@ run-signals: signals
$(call skip-test, $<, "BROKEN")
run-plugin-signals-with-%:
$(call skip-test, $<, "BROKEN")
+
+VPATH += $(SRC_PATH)/tests/tcg/sh4
+
+test-macl: CFLAGS += -O -g
+TESTS += test-macl
+
+test-macw: CFLAGS += -O -g
+TESTS += test-macw
diff --git a/tests/tcg/sh4/test-macl.c b/tests/tcg/sh4/test-macl.c
new file mode 100644
index 0000000..b66c854
--- /dev/null
+++ b/tests/tcg/sh4/test-macl.c
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define MACL_S_MIN (-(1ll << 47))
+#define MACL_S_MAX ((1ll << 47) - 1)
+
+int64_t mac_l(int64_t mac, const int32_t *a, const int32_t *b)
+{
+ register uint32_t macl __asm__("macl") = mac;
+ register uint32_t mach __asm__("mach") = mac >> 32;
+
+ asm volatile("mac.l @%0+,@%1+"
+ : "+r"(a), "+r"(b), "+x"(macl), "+x"(mach));
+
+ return ((uint64_t)mach << 32) | macl;
+}
+
+typedef struct {
+ int64_t mac;
+ int32_t a, b;
+ int64_t res[2];
+} Test;
+
+__attribute__((noinline))
+void test(const Test *t, int sat)
+{
+ int64_t res;
+
+ if (sat) {
+ asm volatile("sets");
+ } else {
+ asm volatile("clrs");
+ }
+ res = mac_l(t->mac, &t->a, &t->b);
+
+ if (res != t->res[sat]) {
+ fprintf(stderr, "%#llx + (%#x * %#x) = %#llx -- got %#llx\n",
+ t->mac, t->a, t->b, t->res[sat], res);
+ abort();
+ }
+}
+
+int main()
+{
+ static const Test tests[] = {
+ { 0x00007fff12345678ll, INT32_MAX, INT32_MAX,
+ { 0x40007ffe12345679ll, MACL_S_MAX } },
+ { MACL_S_MIN, -1, 1,
+ { 0xffff7fffffffffffll, MACL_S_MIN } },
+ { INT64_MIN, -1, 1,
+ { INT64_MAX, MACL_S_MIN } },
+ { 0x00007fff00000000ll, INT32_MAX, INT32_MAX,
+ { 0x40007ffe00000001ll, MACL_S_MAX } },
+ { 4, 1, 2, { 6, 6 } },
+ { -4, -1, -2, { -2, -2 } },
+ };
+
+ for (int i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i) {
+ for (int j = 0; j < 2; ++j) {
+ test(&tests[i], j);
+ }
+ }
+ return 0;
+}
diff --git a/tests/tcg/sh4/test-macw.c b/tests/tcg/sh4/test-macw.c
new file mode 100644
index 0000000..4eceec8
--- /dev/null
+++ b/tests/tcg/sh4/test-macw.c
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int64_t mac_w(int64_t mac, const int16_t *a, const int16_t *b)
+{
+ register uint32_t macl __asm__("macl") = mac;
+ register uint32_t mach __asm__("mach") = mac >> 32;
+
+ asm volatile("mac.w @%0+,@%1+"
+ : "+r"(a), "+r"(b), "+x"(macl), "+x"(mach));
+
+ return ((uint64_t)mach << 32) | macl;
+}
+
+typedef struct {
+ int64_t mac;
+ int16_t a, b;
+ int64_t res[2];
+} Test;
+
+__attribute__((noinline))
+void test(const Test *t, int sat)
+{
+ int64_t res;
+
+ if (sat) {
+ asm volatile("sets");
+ } else {
+ asm volatile("clrs");
+ }
+ res = mac_w(t->mac, &t->a, &t->b);
+
+ if (res != t->res[sat]) {
+ fprintf(stderr, "%#llx + (%#x * %#x) = %#llx -- got %#llx\n",
+ t->mac, t->a, t->b, t->res[sat], res);
+ abort();
+ }
+}
+
+int main()
+{
+ static const Test tests[] = {
+ { 0, 2, 3, { 6, 6 } },
+ { 0x123456787ffffffell, 2, -3,
+ { 0x123456787ffffff8ll, 0x123456787ffffff8ll } },
+ { 0xabcdef127ffffffall, 2, 3,
+ { 0xabcdef1280000000ll, 0x000000017fffffffll } },
+ { 0xfffffffffll, INT16_MAX, INT16_MAX,
+ { 0x103fff0000ll, 0xf3fff0000ll } },
+ };
+
+ for (int i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i) {
+ for (int j = 0; j < 2; ++j) {
+ test(&tests[i], j);
+ }
+ }
+ return 0;
+}