aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml3
-rw-r--r--accel/tcg/tcg-runtime-gvec.c298
-rw-r--r--block/monitor/block-hmp-cmds.c4
-rwxr-xr-xconfigure65
-rw-r--r--docs/devel/qapi-code-gen.txt81
-rw-r--r--docs/system/deprecated.rst55
-rw-r--r--gdbstub.c936
-rw-r--r--hw/alpha/dp264.c11
-rw-r--r--hw/block/xen-block.c10
-rw-r--r--hw/core/cpu.c2
-rw-r--r--hw/hppa/hppa_sys.h1
-rw-r--r--hw/hppa/machine.c1
-rw-r--r--hw/i386/pc_piix.c18
-rw-r--r--hw/ide/ahci_internal.h1
-rw-r--r--hw/ide/cmd646.c21
-rw-r--r--hw/ide/pci.c11
-rw-r--r--hw/ide/piix.c31
-rw-r--r--hw/ide/via.c21
-rw-r--r--hw/intc/spapr_xive.c4
-rw-r--r--hw/isa/piix4.c23
-rw-r--r--hw/mips/mips_fulong2e.c8
-rw-r--r--hw/mips/mips_malta.c2
-rw-r--r--hw/mips/mips_r4k.c1
-rw-r--r--hw/misc/ivshmem.c7
-rw-r--r--hw/pci/pci.c5
-rw-r--r--hw/ppc/mac_newworld.c1
-rw-r--r--hw/ppc/mac_oldworld.c1
-rw-r--r--hw/ppc/pnv_lpc.c2
-rw-r--r--hw/ppc/prep.c1
-rw-r--r--hw/ppc/spapr.c848
-rw-r--r--hw/ppc/spapr_caps.c19
-rw-r--r--hw/ppc/spapr_cpu_core.c16
-rw-r--r--hw/ppc/spapr_events.c51
-rw-r--r--hw/ppc/spapr_hcall.c15
-rw-r--r--hw/ppc/spapr_nvdimm.c7
-rw-r--r--hw/ppc/spapr_ovec.c4
-rw-r--r--hw/ppc/spapr_rtas.c45
-rw-r--r--hw/scsi/spapr_vscsi.c72
-rw-r--r--hw/scsi/trace-events1
-rw-r--r--hw/scsi/viosrp.h3
-rw-r--r--hw/sd/ssi-sd.c16
-rw-r--r--hw/sparc64/sun4u.c6
-rw-r--r--include/exec/gdbstub.h62
-rw-r--r--include/hw/core/cpu.h2
-rw-r--r--include/hw/ide.h9
-rw-r--r--include/hw/ide/internal.h2
-rw-r--r--include/hw/ide/pci.h3
-rw-r--r--include/hw/misc/macio/macio.h1
-rw-r--r--include/hw/ppc/spapr.h34
-rw-r--r--include/hw/ppc/spapr_cpu_core.h4
-rw-r--r--include/hw/ppc/spapr_ovec.h4
-rw-r--r--include/hw/southbridge/piix.h3
-rw-r--r--include/net/net.h2
-rw-r--r--include/qapi/qmp/dispatch.h9
-rw-r--r--monitor/misc.c6
-rw-r--r--monitor/monitor-internal.h2
-rw-r--r--monitor/qmp-cmds-control.c2
-rw-r--r--net/net.c39
-rw-r--r--pc-bios/README2
-rw-r--r--pc-bios/slof.binbin931032 -> 965008 bytes
-rw-r--r--python/qemu/machine.py3
-rw-r--r--python/qemu/qmp.py5
-rw-r--r--qapi/block-core.json48
-rw-r--r--qapi/block.json30
-rw-r--r--qapi/char.json1
-rw-r--r--qapi/control.json11
-rw-r--r--qapi/introspect.json26
-rw-r--r--qapi/machine.json34
-rw-r--r--qapi/migration.json36
-rw-r--r--qapi/misc.json13
-rw-r--r--qapi/net.json14
-rw-r--r--qapi/qmp-dispatch.c134
-rw-r--r--qapi/qmp-registry.c6
-rw-r--r--qga/commands.c2
-rw-r--r--qga/main.c6
m---------roms/SLOF0
-rw-r--r--scripts/qapi/commands.py6
-rw-r--r--scripts/qapi/doc.py16
-rw-r--r--scripts/qapi/events.py2
-rw-r--r--scripts/qapi/expr.py14
-rw-r--r--scripts/qapi/introspect.py106
-rw-r--r--scripts/qapi/schema.py460
-rw-r--r--scripts/qapi/types.py8
-rw-r--r--scripts/qapi/visit.py8
-rw-r--r--target/alpha/cpu.h2
-rw-r--r--target/alpha/gdbstub.c2
-rw-r--r--target/arm/cpu.c7
-rw-r--r--target/arm/cpu.h31
-rw-r--r--target/arm/gdbstub.c173
-rw-r--r--target/arm/gdbstub64.c2
-rw-r--r--target/arm/helper.c186
-rw-r--r--target/arm/monitor.c8
-rw-r--r--target/cris/cpu.h4
-rw-r--r--target/cris/gdbstub.c4
-rw-r--r--target/hppa/cpu.h2
-rw-r--r--target/hppa/gdbstub.c2
-rw-r--r--target/i386/cpu.h2
-rw-r--r--target/i386/gdbstub.c29
-rw-r--r--target/lm32/cpu.h2
-rw-r--r--target/lm32/gdbstub.c2
-rw-r--r--target/m68k/cpu.h2
-rw-r--r--target/m68k/gdbstub.c2
-rw-r--r--target/m68k/helper.c33
-rw-r--r--target/microblaze/cpu.h2
-rw-r--r--target/microblaze/gdbstub.c2
-rw-r--r--target/mips/gdbstub.c2
-rw-r--r--target/mips/internal.h2
-rw-r--r--target/nios2/cpu.c2
-rw-r--r--target/openrisc/cpu.h2
-rw-r--r--target/openrisc/gdbstub.c2
-rw-r--r--target/ppc/cpu-qom.h1
-rw-r--r--target/ppc/cpu.h32
-rw-r--r--target/ppc/excp_helper.c79
-rw-r--r--target/ppc/gdbstub.c48
-rw-r--r--target/ppc/kvm.c5
-rw-r--r--target/ppc/kvm_ppc.h7
-rw-r--r--target/ppc/mmu-hash64.c319
-rw-r--r--target/ppc/translate.c20
-rw-r--r--target/ppc/translate_init.inc.c170
-rw-r--r--target/riscv/cpu.h2
-rw-r--r--target/riscv/gdbstub.c20
-rw-r--r--target/s390x/gdbstub.c30
-rw-r--r--target/s390x/internal.h2
-rw-r--r--target/sh4/cpu.h2
-rw-r--r--target/sh4/gdbstub.c2
-rw-r--r--target/sparc/cpu.h2
-rw-r--r--target/sparc/gdbstub.c2
-rw-r--r--target/xtensa/cpu.h2
-rw-r--r--target/xtensa/gdbstub.c2
-rw-r--r--tcg/i386/tcg-target.inc.c9
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/Makefile.include21
-rw-r--r--tests/acceptance/avocado_qemu/__init__.py25
-rw-r--r--tests/acceptance/boot_linux.py222
-rw-r--r--tests/docker/dockerfiles/centos8.docker32
-rw-r--r--tests/docker/dockerfiles/debian-amd64.docker6
-rw-r--r--tests/docker/dockerfiles/debian-win32-cross.docker2
-rw-r--r--tests/docker/dockerfiles/debian10.docker3
-rw-r--r--tests/docker/dockerfiles/debian9.docker3
-rwxr-xr-xtests/guest-debug/run-test.py57
-rw-r--r--tests/qapi-schema/alternate-base.err2
-rw-r--r--tests/qapi-schema/doc-good.json22
-rw-r--r--tests/qapi-schema/doc-good.out18
-rw-r--r--tests/qapi-schema/doc-good.texi32
-rw-r--r--tests/qapi-schema/features-deprecated-type.err2
-rw-r--r--tests/qapi-schema/features-deprecated-type.json3
-rw-r--r--tests/qapi-schema/features-deprecated-type.out0
-rw-r--r--tests/qapi-schema/qapi-schema-test.json33
-rw-r--r--tests/qapi-schema/qapi-schema-test.out30
-rwxr-xr-xtests/qapi-schema/test-qapi.py26
-rw-r--r--tests/qtest/fuzz/qos_fuzz.c7
-rw-r--r--tests/qtest/hd-geo-test.c6
-rw-r--r--tests/qtest/libqos/libqos-spapr.h3
-rw-r--r--tests/requirements.txt1
-rw-r--r--tests/tcg/aarch64/Makefile.target32
-rw-r--r--tests/tcg/aarch64/gdbstub/test-sve-ioctl.py85
-rw-r--r--tests/tcg/aarch64/gdbstub/test-sve.py84
-rw-r--r--tests/tcg/aarch64/sve-ioctls.c70
-rw-r--r--tests/tcg/aarch64/sysregs.c172
-rw-r--r--tests/test-qmp-cmds.c152
-rw-r--r--tests/test-qmp-event.c168
161 files changed, 3776 insertions, 2712 deletions
diff --git a/.travis.yml b/.travis.yml
index b92798ac3b..5672d129ec 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -79,6 +79,7 @@ env:
- MAIN_SOFTMMU_TARGETS="aarch64-softmmu,mips64-softmmu,ppc64-softmmu,riscv64-softmmu,s390x-softmmu,x86_64-softmmu"
- CCACHE_SLOPPINESS="include_file_ctime,include_file_mtime"
- CCACHE_MAXSIZE=1G
+ - G_MESSAGES_DEBUG=error
git:
@@ -315,7 +316,7 @@ jobs:
- name: "GCC check-acceptance"
dist: bionic
env:
- - CONFIG="--target-list=aarch64-softmmu,alpha-softmmu,arm-softmmu,m68k-softmmu,microblaze-softmmu,mips-softmmu,mips64el-softmmu,nios2-softmmu,or1k-softmmu,ppc-softmmu,ppc64-softmmu,s390x-softmmu,sparc-softmmu,x86_64-softmmu,xtensa-softmmu"
+ - CONFIG="--enable-tools --target-list=aarch64-softmmu,alpha-softmmu,arm-softmmu,m68k-softmmu,microblaze-softmmu,mips-softmmu,mips64el-softmmu,nios2-softmmu,or1k-softmmu,ppc-softmmu,ppc64-softmmu,s390x-softmmu,sparc-softmmu,x86_64-softmmu,xtensa-softmmu"
- TEST_CMD="make check-acceptance"
after_script:
- python3 -c 'import json; r = json.load(open("tests/results/latest/results.json")); [print(t["logfile"]) for t in r["tests"] if t["status"] not in ("PASS", "SKIP")]' | xargs cat
diff --git a/accel/tcg/tcg-runtime-gvec.c b/accel/tcg/tcg-runtime-gvec.c
index 5b1902d591..ca449702e6 100644
--- a/accel/tcg/tcg-runtime-gvec.c
+++ b/accel/tcg/tcg-runtime-gvec.c
@@ -24,48 +24,6 @@
#include "tcg/tcg-gvec-desc.h"
-/* Virtually all hosts support 16-byte vectors. Those that don't can emulate
- * them via GCC's generic vector extension. This turns out to be simpler and
- * more reliable than getting the compiler to autovectorize.
- *
- * In tcg-op-gvec.c, we asserted that both the size and alignment of the data
- * are multiples of 16.
- *
- * When the compiler does not support all of the operations we require, the
- * loops are written so that we can always fall back on the base types.
- */
-#ifdef CONFIG_VECTOR16
-typedef uint8_t vec8 __attribute__((vector_size(16)));
-typedef uint16_t vec16 __attribute__((vector_size(16)));
-typedef uint32_t vec32 __attribute__((vector_size(16)));
-typedef uint64_t vec64 __attribute__((vector_size(16)));
-
-typedef int8_t svec8 __attribute__((vector_size(16)));
-typedef int16_t svec16 __attribute__((vector_size(16)));
-typedef int32_t svec32 __attribute__((vector_size(16)));
-typedef int64_t svec64 __attribute__((vector_size(16)));
-
-#define DUP16(X) { X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X }
-#define DUP8(X) { X, X, X, X, X, X, X, X }
-#define DUP4(X) { X, X, X, X }
-#define DUP2(X) { X, X }
-#else
-typedef uint8_t vec8;
-typedef uint16_t vec16;
-typedef uint32_t vec32;
-typedef uint64_t vec64;
-
-typedef int8_t svec8;
-typedef int16_t svec16;
-typedef int32_t svec32;
-typedef int64_t svec64;
-
-#define DUP16(X) X
-#define DUP8(X) X
-#define DUP4(X) X
-#define DUP2(X) X
-#endif /* CONFIG_VECTOR16 */
-
static inline void clear_high(void *d, intptr_t oprsz, uint32_t desc)
{
intptr_t maxsz = simd_maxsz(desc);
@@ -83,8 +41,8 @@ void HELPER(gvec_add8)(void *d, void *a, void *b, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec8)) {
- *(vec8 *)(d + i) = *(vec8 *)(a + i) + *(vec8 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
+ *(uint8_t *)(d + i) = *(uint8_t *)(a + i) + *(uint8_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
@@ -94,8 +52,8 @@ void HELPER(gvec_add16)(void *d, void *a, void *b, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec16)) {
- *(vec16 *)(d + i) = *(vec16 *)(a + i) + *(vec16 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+ *(uint16_t *)(d + i) = *(uint16_t *)(a + i) + *(uint16_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
@@ -105,8 +63,8 @@ void HELPER(gvec_add32)(void *d, void *a, void *b, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec32)) {
- *(vec32 *)(d + i) = *(vec32 *)(a + i) + *(vec32 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
+ *(uint32_t *)(d + i) = *(uint32_t *)(a + i) + *(uint32_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
@@ -116,8 +74,8 @@ void HELPER(gvec_add64)(void *d, void *a, void *b, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) + *(vec64 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) + *(uint64_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
@@ -125,11 +83,10 @@ void HELPER(gvec_add64)(void *d, void *a, void *b, uint32_t desc)
void HELPER(gvec_adds8)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec8 vecb = (vec8)DUP16(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec8)) {
- *(vec8 *)(d + i) = *(vec8 *)(a + i) + vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
+ *(uint8_t *)(d + i) = *(uint8_t *)(a + i) + (uint8_t)b;
}
clear_high(d, oprsz, desc);
}
@@ -137,11 +94,10 @@ void HELPER(gvec_adds8)(void *d, void *a, uint64_t b, uint32_t desc)
void HELPER(gvec_adds16)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec16 vecb = (vec16)DUP8(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec16)) {
- *(vec16 *)(d + i) = *(vec16 *)(a + i) + vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+ *(uint16_t *)(d + i) = *(uint16_t *)(a + i) + (uint16_t)b;
}
clear_high(d, oprsz, desc);
}
@@ -149,11 +105,10 @@ void HELPER(gvec_adds16)(void *d, void *a, uint64_t b, uint32_t desc)
void HELPER(gvec_adds32)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec32 vecb = (vec32)DUP4(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec32)) {
- *(vec32 *)(d + i) = *(vec32 *)(a + i) + vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
+ *(uint32_t *)(d + i) = *(uint32_t *)(a + i) + (uint32_t)b;
}
clear_high(d, oprsz, desc);
}
@@ -161,11 +116,10 @@ void HELPER(gvec_adds32)(void *d, void *a, uint64_t b, uint32_t desc)
void HELPER(gvec_adds64)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec64 vecb = (vec64)DUP2(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) + vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) + b;
}
clear_high(d, oprsz, desc);
}
@@ -175,8 +129,8 @@ void HELPER(gvec_sub8)(void *d, void *a, void *b, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec8)) {
- *(vec8 *)(d + i) = *(vec8 *)(a + i) - *(vec8 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
+ *(uint8_t *)(d + i) = *(uint8_t *)(a + i) - *(uint8_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
@@ -186,8 +140,8 @@ void HELPER(gvec_sub16)(void *d, void *a, void *b, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec16)) {
- *(vec16 *)(d + i) = *(vec16 *)(a + i) - *(vec16 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+ *(uint16_t *)(d + i) = *(uint16_t *)(a + i) - *(uint16_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
@@ -197,8 +151,8 @@ void HELPER(gvec_sub32)(void *d, void *a, void *b, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec32)) {
- *(vec32 *)(d + i) = *(vec32 *)(a + i) - *(vec32 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
+ *(uint32_t *)(d + i) = *(uint32_t *)(a + i) - *(uint32_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
@@ -208,8 +162,8 @@ void HELPER(gvec_sub64)(void *d, void *a, void *b, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) - *(vec64 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) - *(uint64_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
@@ -217,11 +171,10 @@ void HELPER(gvec_sub64)(void *d, void *a, void *b, uint32_t desc)
void HELPER(gvec_subs8)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec8 vecb = (vec8)DUP16(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec8)) {
- *(vec8 *)(d + i) = *(vec8 *)(a + i) - vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
+ *(uint8_t *)(d + i) = *(uint8_t *)(a + i) - (uint8_t)b;
}
clear_high(d, oprsz, desc);
}
@@ -229,11 +182,10 @@ void HELPER(gvec_subs8)(void *d, void *a, uint64_t b, uint32_t desc)
void HELPER(gvec_subs16)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec16 vecb = (vec16)DUP8(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec16)) {
- *(vec16 *)(d + i) = *(vec16 *)(a + i) - vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+ *(uint16_t *)(d + i) = *(uint16_t *)(a + i) - (uint16_t)b;
}
clear_high(d, oprsz, desc);
}
@@ -241,11 +193,10 @@ void HELPER(gvec_subs16)(void *d, void *a, uint64_t b, uint32_t desc)
void HELPER(gvec_subs32)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec32 vecb = (vec32)DUP4(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec32)) {
- *(vec32 *)(d + i) = *(vec32 *)(a + i) - vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
+ *(uint32_t *)(d + i) = *(uint32_t *)(a + i) - (uint32_t)b;
}
clear_high(d, oprsz, desc);
}
@@ -253,11 +204,10 @@ void HELPER(gvec_subs32)(void *d, void *a, uint64_t b, uint32_t desc)
void HELPER(gvec_subs64)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec64 vecb = (vec64)DUP2(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) - vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) - b;
}
clear_high(d, oprsz, desc);
}
@@ -267,8 +217,8 @@ void HELPER(gvec_mul8)(void *d, void *a, void *b, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec8)) {
- *(vec8 *)(d + i) = *(vec8 *)(a + i) * *(vec8 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
+ *(uint8_t *)(d + i) = *(uint8_t *)(a + i) * *(uint8_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
@@ -278,8 +228,8 @@ void HELPER(gvec_mul16)(void *d, void *a, void *b, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec16)) {
- *(vec16 *)(d + i) = *(vec16 *)(a + i) * *(vec16 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+ *(uint16_t *)(d + i) = *(uint16_t *)(a + i) * *(uint16_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
@@ -289,8 +239,8 @@ void HELPER(gvec_mul32)(void *d, void *a, void *b, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec32)) {
- *(vec32 *)(d + i) = *(vec32 *)(a + i) * *(vec32 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
+ *(uint32_t *)(d + i) = *(uint32_t *)(a + i) * *(uint32_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
@@ -300,8 +250,8 @@ void HELPER(gvec_mul64)(void *d, void *a, void *b, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) * *(vec64 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) * *(uint64_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
@@ -309,11 +259,10 @@ void HELPER(gvec_mul64)(void *d, void *a, void *b, uint32_t desc)
void HELPER(gvec_muls8)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec8 vecb = (vec8)DUP16(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec8)) {
- *(vec8 *)(d + i) = *(vec8 *)(a + i) * vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
+ *(uint8_t *)(d + i) = *(uint8_t *)(a + i) * (uint8_t)b;
}
clear_high(d, oprsz, desc);
}
@@ -321,11 +270,10 @@ void HELPER(gvec_muls8)(void *d, void *a, uint64_t b, uint32_t desc)
void HELPER(gvec_muls16)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec16 vecb = (vec16)DUP8(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec16)) {
- *(vec16 *)(d + i) = *(vec16 *)(a + i) * vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+ *(uint16_t *)(d + i) = *(uint16_t *)(a + i) * (uint16_t)b;
}
clear_high(d, oprsz, desc);
}
@@ -333,11 +281,10 @@ void HELPER(gvec_muls16)(void *d, void *a, uint64_t b, uint32_t desc)
void HELPER(gvec_muls32)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec32 vecb = (vec32)DUP4(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec32)) {
- *(vec32 *)(d + i) = *(vec32 *)(a + i) * vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
+ *(uint32_t *)(d + i) = *(uint32_t *)(a + i) * (uint32_t)b;
}
clear_high(d, oprsz, desc);
}
@@ -345,11 +292,10 @@ void HELPER(gvec_muls32)(void *d, void *a, uint64_t b, uint32_t desc)
void HELPER(gvec_muls64)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec64 vecb = (vec64)DUP2(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) * vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) * b;
}
clear_high(d, oprsz, desc);
}
@@ -359,8 +305,8 @@ void HELPER(gvec_neg8)(void *d, void *a, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec8)) {
- *(vec8 *)(d + i) = -*(vec8 *)(a + i);
+ for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
+ *(uint8_t *)(d + i) = -*(uint8_t *)(a + i);
}
clear_high(d, oprsz, desc);
}
@@ -370,8 +316,8 @@ void HELPER(gvec_neg16)(void *d, void *a, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec16)) {
- *(vec16 *)(d + i) = -*(vec16 *)(a + i);
+ for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+ *(uint16_t *)(d + i) = -*(uint16_t *)(a + i);
}
clear_high(d, oprsz, desc);
}
@@ -381,8 +327,8 @@ void HELPER(gvec_neg32)(void *d, void *a, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec32)) {
- *(vec32 *)(d + i) = -*(vec32 *)(a + i);
+ for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
+ *(uint32_t *)(d + i) = -*(uint32_t *)(a + i);
}
clear_high(d, oprsz, desc);
}
@@ -392,8 +338,8 @@ void HELPER(gvec_neg64)(void *d, void *a, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = -*(vec64 *)(a + i);
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = -*(uint64_t *)(a + i);
}
clear_high(d, oprsz, desc);
}
@@ -499,8 +445,8 @@ void HELPER(gvec_not)(void *d, void *a, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = ~*(vec64 *)(a + i);
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = ~*(uint64_t *)(a + i);
}
clear_high(d, oprsz, desc);
}
@@ -510,8 +456,8 @@ void HELPER(gvec_and)(void *d, void *a, void *b, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) & *(vec64 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) & *(uint64_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
@@ -521,8 +467,8 @@ void HELPER(gvec_or)(void *d, void *a, void *b, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) | *(vec64 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) | *(uint64_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
@@ -532,8 +478,8 @@ void HELPER(gvec_xor)(void *d, void *a, void *b, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) ^ *(vec64 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) ^ *(uint64_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
@@ -543,8 +489,8 @@ void HELPER(gvec_andc)(void *d, void *a, void *b, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) &~ *(vec64 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) &~ *(uint64_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
@@ -554,8 +500,8 @@ void HELPER(gvec_orc)(void *d, void *a, void *b, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) |~ *(vec64 *)(b + i);
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) |~ *(uint64_t *)(b + i);
}
clear_high(d, oprsz, desc);
}
@@ -565,8 +511,8 @@ void HELPER(gvec_nand)(void *d, void *a, void *b, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = ~(*(vec64 *)(a + i) & *(vec64 *)(b + i));
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = ~(*(uint64_t *)(a + i) & *(uint64_t *)(b + i));
}
clear_high(d, oprsz, desc);
}
@@ -576,8 +522,8 @@ void HELPER(gvec_nor)(void *d, void *a, void *b, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = ~(*(vec64 *)(a + i) | *(vec64 *)(b + i));
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = ~(*(uint64_t *)(a + i) | *(uint64_t *)(b + i));
}
clear_high(d, oprsz, desc);
}
@@ -587,8 +533,8 @@ void HELPER(gvec_eqv)(void *d, void *a, void *b, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = ~(*(vec64 *)(a + i) ^ *(vec64 *)(b + i));
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = ~(*(uint64_t *)(a + i) ^ *(uint64_t *)(b + i));
}
clear_high(d, oprsz, desc);
}
@@ -596,11 +542,10 @@ void HELPER(gvec_eqv)(void *d, void *a, void *b, uint32_t desc)
void HELPER(gvec_ands)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec64 vecb = (vec64)DUP2(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) & vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) & b;
}
clear_high(d, oprsz, desc);
}
@@ -608,11 +553,10 @@ void HELPER(gvec_ands)(void *d, void *a, uint64_t b, uint32_t desc)
void HELPER(gvec_xors)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec64 vecb = (vec64)DUP2(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) ^ vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) ^ b;
}
clear_high(d, oprsz, desc);
}
@@ -620,11 +564,10 @@ void HELPER(gvec_xors)(void *d, void *a, uint64_t b, uint32_t desc)
void HELPER(gvec_ors)(void *d, void *a, uint64_t b, uint32_t desc)
{
intptr_t oprsz = simd_oprsz(desc);
- vec64 vecb = (vec64)DUP2(b);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) | vecb;
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) | b;
}
clear_high(d, oprsz, desc);
}
@@ -635,8 +578,8 @@ void HELPER(gvec_shl8i)(void *d, void *a, uint32_t desc)
int shift = simd_data(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec8)) {
- *(vec8 *)(d + i) = *(vec8 *)(a + i) << shift;
+ for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
+ *(uint8_t *)(d + i) = *(uint8_t *)(a + i) << shift;
}
clear_high(d, oprsz, desc);
}
@@ -647,8 +590,8 @@ void HELPER(gvec_shl16i)(void *d, void *a, uint32_t desc)
int shift = simd_data(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec16)) {
- *(vec16 *)(d + i) = *(vec16 *)(a + i) << shift;
+ for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+ *(uint16_t *)(d + i) = *(uint16_t *)(a + i) << shift;
}
clear_high(d, oprsz, desc);
}
@@ -659,8 +602,8 @@ void HELPER(gvec_shl32i)(void *d, void *a, uint32_t desc)
int shift = simd_data(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec32)) {
- *(vec32 *)(d + i) = *(vec32 *)(a + i) << shift;
+ for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
+ *(uint32_t *)(d + i) = *(uint32_t *)(a + i) << shift;
}
clear_high(d, oprsz, desc);
}
@@ -671,8 +614,8 @@ void HELPER(gvec_shl64i)(void *d, void *a, uint32_t desc)
int shift = simd_data(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) << shift;
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) << shift;
}
clear_high(d, oprsz, desc);
}
@@ -683,8 +626,8 @@ void HELPER(gvec_shr8i)(void *d, void *a, uint32_t desc)
int shift = simd_data(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec8)) {
- *(vec8 *)(d + i) = *(vec8 *)(a + i) >> shift;
+ for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
+ *(uint8_t *)(d + i) = *(uint8_t *)(a + i) >> shift;
}
clear_high(d, oprsz, desc);
}
@@ -695,8 +638,8 @@ void HELPER(gvec_shr16i)(void *d, void *a, uint32_t desc)
int shift = simd_data(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec16)) {
- *(vec16 *)(d + i) = *(vec16 *)(a + i) >> shift;
+ for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+ *(uint16_t *)(d + i) = *(uint16_t *)(a + i) >> shift;
}
clear_high(d, oprsz, desc);
}
@@ -707,8 +650,8 @@ void HELPER(gvec_shr32i)(void *d, void *a, uint32_t desc)
int shift = simd_data(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec32)) {
- *(vec32 *)(d + i) = *(vec32 *)(a + i) >> shift;
+ for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
+ *(uint32_t *)(d + i) = *(uint32_t *)(a + i) >> shift;
}
clear_high(d, oprsz, desc);
}
@@ -719,8 +662,8 @@ void HELPER(gvec_shr64i)(void *d, void *a, uint32_t desc)
int shift = simd_data(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(vec64 *)(d + i) = *(vec64 *)(a + i) >> shift;
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(uint64_t *)(d + i) = *(uint64_t *)(a + i) >> shift;
}
clear_high(d, oprsz, desc);
}
@@ -731,8 +674,8 @@ void HELPER(gvec_sar8i)(void *d, void *a, uint32_t desc)
int shift = simd_data(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec8)) {
- *(svec8 *)(d + i) = *(svec8 *)(a + i) >> shift;
+ for (i = 0; i < oprsz; i += sizeof(uint8_t)) {
+ *(int8_t *)(d + i) = *(int8_t *)(a + i) >> shift;
}
clear_high(d, oprsz, desc);
}
@@ -743,8 +686,8 @@ void HELPER(gvec_sar16i)(void *d, void *a, uint32_t desc)
int shift = simd_data(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec16)) {
- *(svec16 *)(d + i) = *(svec16 *)(a + i) >> shift;
+ for (i = 0; i < oprsz; i += sizeof(uint16_t)) {
+ *(int16_t *)(d + i) = *(int16_t *)(a + i) >> shift;
}
clear_high(d, oprsz, desc);
}
@@ -755,8 +698,8 @@ void HELPER(gvec_sar32i)(void *d, void *a, uint32_t desc)
int shift = simd_data(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec32)) {
- *(svec32 *)(d + i) = *(svec32 *)(a + i) >> shift;
+ for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
+ *(int32_t *)(d + i) = *(int32_t *)(a + i) >> shift;
}
clear_high(d, oprsz, desc);
}
@@ -767,8 +710,8 @@ void HELPER(gvec_sar64i)(void *d, void *a, uint32_t desc)
int shift = simd_data(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- *(svec64 *)(d + i) = *(svec64 *)(a + i) >> shift;
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ *(int64_t *)(d + i) = *(int64_t *)(a + i) >> shift;
}
clear_high(d, oprsz, desc);
}
@@ -917,39 +860,30 @@ void HELPER(gvec_sar64v)(void *d, void *a, void *b, uint32_t desc)
clear_high(d, oprsz, desc);
}
-/* If vectors are enabled, the compiler fills in -1 for true.
- Otherwise, we must take care of this by hand. */
-#ifdef CONFIG_VECTOR16
-# define DO_CMP0(X) X
-#else
-# define DO_CMP0(X) -(X)
-#endif
-
#define DO_CMP1(NAME, TYPE, OP) \
void HELPER(NAME)(void *d, void *a, void *b, uint32_t desc) \
{ \
intptr_t oprsz = simd_oprsz(desc); \
intptr_t i; \
for (i = 0; i < oprsz; i += sizeof(TYPE)) { \
- *(TYPE *)(d + i) = DO_CMP0(*(TYPE *)(a + i) OP *(TYPE *)(b + i)); \
+ *(TYPE *)(d + i) = -(*(TYPE *)(a + i) OP *(TYPE *)(b + i)); \
} \
clear_high(d, oprsz, desc); \
}
#define DO_CMP2(SZ) \
- DO_CMP1(gvec_eq##SZ, vec##SZ, ==) \
- DO_CMP1(gvec_ne##SZ, vec##SZ, !=) \
- DO_CMP1(gvec_lt##SZ, svec##SZ, <) \
- DO_CMP1(gvec_le##SZ, svec##SZ, <=) \
- DO_CMP1(gvec_ltu##SZ, vec##SZ, <) \
- DO_CMP1(gvec_leu##SZ, vec##SZ, <=)
+ DO_CMP1(gvec_eq##SZ, uint##SZ##_t, ==) \
+ DO_CMP1(gvec_ne##SZ, uint##SZ##_t, !=) \
+ DO_CMP1(gvec_lt##SZ, int##SZ##_t, <) \
+ DO_CMP1(gvec_le##SZ, int##SZ##_t, <=) \
+ DO_CMP1(gvec_ltu##SZ, uint##SZ##_t, <) \
+ DO_CMP1(gvec_leu##SZ, uint##SZ##_t, <=)
DO_CMP2(8)
DO_CMP2(16)
DO_CMP2(32)
DO_CMP2(64)
-#undef DO_CMP0
#undef DO_CMP1
#undef DO_CMP2
@@ -1450,11 +1384,11 @@ void HELPER(gvec_bitsel)(void *d, void *a, void *b, void *c, uint32_t desc)
intptr_t oprsz = simd_oprsz(desc);
intptr_t i;
- for (i = 0; i < oprsz; i += sizeof(vec64)) {
- vec64 aa = *(vec64 *)(a + i);
- vec64 bb = *(vec64 *)(b + i);
- vec64 cc = *(vec64 *)(c + i);
- *(vec64 *)(d + i) = (bb & aa) | (cc & ~aa);
+ for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
+ uint64_t aa = *(uint64_t *)(a + i);
+ uint64_t bb = *(uint64_t *)(b + i);
+ uint64_t cc = *(uint64_t *)(c + i);
+ *(uint64_t *)(d + i) = (bb & aa) | (cc & ~aa);
}
clear_high(d, oprsz, desc);
}
diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
index c3a6368dfc..4c8c375172 100644
--- a/block/monitor/block-hmp-cmds.c
+++ b/block/monitor/block-hmp-cmds.c
@@ -838,10 +838,8 @@ void hmp_info_blockstats(Monitor *mon, const QDict *qdict)
void hmp_info_block_jobs(Monitor *mon, const QDict *qdict)
{
BlockJobInfoList *list;
- Error *err = NULL;
- list = qmp_query_block_jobs(&err);
- assert(!err);
+ list = qmp_query_block_jobs(&error_abort);
if (!list) {
monitor_printf(mon, "No active jobs\n");
diff --git a/configure b/configure
index 06fcd070fb..206d22c515 100755
--- a/configure
+++ b/configure
@@ -303,6 +303,7 @@ libs_qga=""
debug_info="yes"
stack_protector=""
use_containers="yes"
+gdb_bin=$(command -v "gdb")
if test -e "$source_path/.git"
then
@@ -1598,6 +1599,8 @@ for opt do
;;
--disable-fuzzing) fuzzing=no
;;
+ --gdb=*) gdb_bin="$optarg"
+ ;;
*)
echo "ERROR: unknown option $opt"
echo "Try '$0 --help' for more information"
@@ -1783,6 +1786,7 @@ Advanced options (experts only):
--enable-plugins
enable plugins via shared library loading
--disable-containers don't use containers for cross-building
+ --gdb=GDB-path gdb to use for gdbstub tests [$gdb_bin]
Optional features, enabled with --enable-FEATURE and
disabled with --disable-FEATURE, default is enabled if available:
@@ -5761,58 +5765,6 @@ if test "$plugins" = "yes" &&
fi
########################################
-# See if 16-byte vector operations are supported.
-# Even without a vector unit the compiler may expand these.
-# There is a bug in old GCC for PPC that crashes here.
-# Unfortunately it's the system compiler for Centos 7.
-
-cat > $TMPC << EOF
-typedef unsigned char U1 __attribute__((vector_size(16)));
-typedef unsigned short U2 __attribute__((vector_size(16)));
-typedef unsigned int U4 __attribute__((vector_size(16)));
-typedef unsigned long long U8 __attribute__((vector_size(16)));
-typedef signed char S1 __attribute__((vector_size(16)));
-typedef signed short S2 __attribute__((vector_size(16)));
-typedef signed int S4 __attribute__((vector_size(16)));
-typedef signed long long S8 __attribute__((vector_size(16)));
-static U1 a1, b1;
-static U2 a2, b2;
-static U4 a4, b4;
-static U8 a8, b8;
-static S1 c1;
-static S2 c2;
-static S4 c4;
-static S8 c8;
-static int i;
-void helper(void *d, void *a, int shift, int i);
-void helper(void *d, void *a, int shift, int i)
-{
- *(U1 *)(d + i) = *(U1 *)(a + i) << shift;
- *(U2 *)(d + i) = *(U2 *)(a + i) << shift;
- *(U4 *)(d + i) = *(U4 *)(a + i) << shift;
- *(U8 *)(d + i) = *(U8 *)(a + i) << shift;
-}
-int main(void)
-{
- a1 += b1; a2 += b2; a4 += b4; a8 += b8;
- a1 -= b1; a2 -= b2; a4 -= b4; a8 -= b8;
- a1 *= b1; a2 *= b2; a4 *= b4; a8 *= b8;
- a1 &= b1; a2 &= b2; a4 &= b4; a8 &= b8;
- a1 |= b1; a2 |= b2; a4 |= b4; a8 |= b8;
- a1 ^= b1; a2 ^= b2; a4 ^= b4; a8 ^= b8;
- a1 <<= i; a2 <<= i; a4 <<= i; a8 <<= i;
- a1 >>= i; a2 >>= i; a4 >>= i; a8 >>= i;
- c1 >>= i; c2 >>= i; c4 >>= i; c8 >>= i;
- return 0;
-}
-EOF
-
-vector16=no
-if compile_prog "" "" ; then
- vector16=yes
-fi
-
-########################################
# See if __attribute__((alias)) is supported.
# This false for Xcode 9, but has been remedied for Xcode 10.
# Unfortunately, travis uses Xcode 9 by default.
@@ -6785,6 +6737,7 @@ echo "libudev $libudev"
echo "default devices $default_devices"
echo "plugin support $plugins"
echo "fuzzing support $fuzzing"
+echo "gdb $gdb_bin"
if test "$supported_cpu" = "no"; then
echo
@@ -7441,10 +7394,6 @@ if test "$atomic64" = "yes" ; then
echo "CONFIG_ATOMIC64=y" >> $config_host_mak
fi
-if test "$vector16" = "yes" ; then
- echo "CONFIG_VECTOR16=y" >> $config_host_mak
-fi
-
if test "$attralias" = "yes" ; then
echo "CONFIG_ATTRIBUTE_ALIAS=y" >> $config_host_mak
fi
@@ -7666,6 +7615,10 @@ if test "$plugins" = "yes" ; then
fi
fi
+if test -n "$gdb_bin" ; then
+ echo "HAVE_GDB_BIN=$gdb_bin" >> $config_host_mak
+fi
+
if test "$tcg_interpreter" = "yes"; then
QEMU_INCLUDES="-iquote \$(SRC_PATH)/tcg/tci $QEMU_INCLUDES"
elif test "$ARCH" = "sparc64" ; then
diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
index 59d6973e1e..1967adfa92 100644
--- a/docs/devel/qapi-code-gen.txt
+++ b/docs/devel/qapi-code-gen.txt
@@ -172,7 +172,8 @@ Syntax:
ENUM = { 'enum': STRING,
'data': [ ENUM-VALUE, ... ],
'*prefix': STRING,
- '*if': COND }
+ '*if': COND,
+ '*features': FEATURES }
ENUM-VALUE = STRING
| { 'name': STRING, '*if': COND }
@@ -207,6 +208,9 @@ the job satisfactorily.
The optional 'if' member specifies a conditional. See "Configuring
the schema" below for more on this.
+The optional 'features' member specifies features. See "Features"
+below for more on this.
+
=== Type references and array types ===
@@ -230,7 +234,9 @@ Syntax:
'*features': FEATURES }
MEMBERS = { MEMBER, ... }
MEMBER = STRING : TYPE-REF
- | STRING : { 'type': TYPE-REF, '*if': COND }
+ | STRING : { 'type': TYPE-REF,
+ '*if': COND,
+ '*features': FEATURES }
Member 'struct' names the struct type.
@@ -279,12 +285,14 @@ below for more on this.
Syntax:
UNION = { 'union': STRING,
'data': BRANCHES,
- '*if': COND }
+ '*if': COND,
+ '*features': FEATURES }
| { 'union': STRING,
'data': BRANCHES,
'base': ( MEMBERS | STRING ),
'discriminator': STRING,
- '*if': COND }
+ '*if': COND,
+ '*features': FEATURES }
BRANCHES = { BRANCH, ... }
BRANCH = STRING : TYPE-REF
| STRING : { 'type': TYPE-REF, '*if': COND }
@@ -391,15 +399,19 @@ is identical on the wire to:
The optional 'if' member specifies a conditional. See "Configuring
the schema" below for more on this.
+The optional 'features' member specifies features. See "Features"
+below for more on this.
+
=== Alternate types ===
Syntax:
ALTERNATE = { 'alternate': STRING,
'data': ALTERNATIVES,
- '*if': COND }
+ '*if': COND,
+ '*features': FEATURES }
ALTERNATIVES = { ALTERNATIVE, ... }
- ALTERNATIVE = STRING : TYPE-REF
+ ALTERNATIVE = STRING : STRING
| STRING : { 'type': STRING, '*if': COND }
Member 'alternate' names the alternate type.
@@ -441,6 +453,9 @@ following example objects:
The optional 'if' member specifies a conditional. See "Configuring
the schema" below for more on this.
+The optional 'features' member specifies features. See "Features"
+below for more on this.
+
=== Commands ===
@@ -584,6 +599,9 @@ started with --preconfig.
The optional 'if' member specifies a conditional. See "Configuring
the schema" below for more on this.
+The optional 'features' member specifies features. See "Features"
+below for more on this.
+
=== Events ===
@@ -595,7 +613,8 @@ Syntax:
'data': STRING,
'boxed': true,
)
- '*if': COND }
+ '*if': COND,
+ '*features': FEATURES }
Member 'event' names the event. This is the event name used in the
Client JSON Protocol.
@@ -628,6 +647,9 @@ complex type. See section "Code generated for events" for examples.
The optional 'if' member specifies a conditional. See "Configuring
the schema" below for more on this.
+The optional 'features' member specifies features. See "Features"
+below for more on this.
+
=== Features ===
@@ -642,13 +664,8 @@ that previously resulted in an error). QMP clients may still need to
know whether the extension is available.
For this purpose, a list of features can be specified for a command or
-struct type. This is exposed to the client as a list of strings,
-where each string signals that this build of QEMU shows a certain
-behaviour.
-
-Each member of the 'features' array defines a feature. It can either
-be { 'name': STRING, '*if': COND }, or STRING, which is shorthand for
-{ 'name': STRING }.
+struct type. Each list member can either be { 'name': STRING, '*if':
+COND }, or STRING, which is shorthand for { 'name': STRING }.
The optional 'if' member specifies a conditional. See "Configuring
the schema" below for more on this.
@@ -659,6 +676,18 @@ Example:
'data': { 'number': 'int' },
'features': [ 'allow-negative-numbers' ] }
+The feature strings are exposed to clients in introspection, as
+explained in section "Client JSON Protocol introspection".
+
+Intended use is to have each feature string signal that this build of
+QEMU shows a certain behaviour.
+
+
+==== Special features ====
+
+Feature "deprecated" marks a command, event, or struct member as
+deprecated. It is not supported elsewhere so far.
+
=== Naming rules and reserved names ===
@@ -965,8 +994,9 @@ schema, along with the SchemaInfo type. This text attempts to give an
overview how things work. For details you need to consult the QAPI
schema.
-SchemaInfo objects have common members "name" and "meta-type", and
-additional variant members depending on the value of meta-type.
+SchemaInfo objects have common members "name", "meta-type",
+"features", and additional variant members depending on the value of
+meta-type.
Each SchemaInfo object describes a wire ABI entity of a certain
meta-type: a command, event or one of several kinds of type.
@@ -979,6 +1009,9 @@ not. Therefore, the SchemaInfo for types have auto-generated
meaningless names. For readability, the examples in this section use
meaningful type names instead.
+Optional member "features" exposes the entity's feature strings as a
+JSON array of strings.
+
To examine a type, start with a command or event using it, then follow
references by name.
@@ -988,9 +1021,9 @@ The SchemaInfo for a command has meta-type "command", and variant
members "arg-type", "ret-type" and "allow-oob". On the wire, the
"arguments" member of a client's "execute" command must conform to the
object type named by "arg-type". The "return" member that the server
-passes in a success response conforms to the type named by
-"ret-type". When "allow-oob" is set, it means the command supports
-out-of-band execution.
+passes in a success response conforms to the type named by "ret-type".
+When "allow-oob" is true, it means the command supports out-of-band
+execution. It defaults to false.
If the command takes no arguments, "arg-type" names an object type
without members. Likewise, if the command returns nothing, "ret-type"
@@ -1047,6 +1080,16 @@ Example: the SchemaInfo for MyType from section Struct types
{ "name": "member2", "type": "int" },
{ "name": "member3", "type": "str", "default": null } ] }
+"features" exposes the command's feature strings as a JSON array of
+strings.
+
+Example: the SchemaInfo for TestType from section Features:
+
+ { "name": "TestType", "meta-type": "object",
+ "members": [
+ { "name": "number", "type": "int" } ],
+ "features": ["allow-negative-numbers"] }
+
"tag" is the name of the common member serving as type tag.
"variants" is a JSON array describing the object's variant members.
Each element is a JSON object with members "case" (the value of type
diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst
index 0838338d8f..c633fe2bef 100644
--- a/docs/system/deprecated.rst
+++ b/docs/system/deprecated.rst
@@ -180,27 +180,67 @@ QEMU Machine Protocol (QMP) commands
Use ``blockdev-change-medium`` or ``change-vnc-password`` instead.
+``blockdev-open-tray``, ``blockdev-close-tray`` argument ``device`` (since 2.8.0)
+'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+Use argument ``id`` instead.
+
+``eject`` argument ``device`` (since 2.8.0)
+'''''''''''''''''''''''''''''''''''''''''''
+
+Use argument ``id`` instead.
+
+``blockdev-change-medium`` argument ``device`` (since 2.8.0)
+''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+Use argument ``id`` instead.
+
+``block_set_io_throttle`` argument ``device`` (since 2.8.0)
+'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+Use argument ``id`` instead.
+
``migrate_set_downtime`` and ``migrate_set_speed`` (since 2.8.0)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Use ``migrate-set-parameters`` instead.
+``query-named-block-nodes`` result ``encryption_key_missing`` (since 2.10.0)
+''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+Always false.
+
+``query-block`` result ``inserted.encryption_key_missing`` (since 2.10.0)
+'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+Always false.
+
+``blockdev-add`` empty string argument ``backing`` (since 2.10.0)
+'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+Use argument value ``null`` instead.
+
``migrate-set-cache-size`` and ``query-migrate-cache-size`` (since 2.11.0)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Use ``migrate-set-parameters`` and ``query-migrate-parameters`` instead.
+``block-commit`` arguments ``base`` and ``top`` (since 3.1.0)
+'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+Use arguments ``base-node`` and ``top-node`` instead.
+
``object-add`` option ``props`` (since 5.0)
'''''''''''''''''''''''''''''''''''''''''''
Specify the properties for the object as top-level arguments instead.
-``query-block`` result field ``dirty-bitmaps[i].status`` (since 4.0)
-''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+``query-named-block-nodes`` and ``query-block`` result dirty-bitmaps[i].status (since 4.0)
+''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
The ``status`` field of the ``BlockDirtyInfo`` structure, returned by
-the query-block command is deprecated. Two new boolean fields,
-``recording`` and ``busy`` effectively replace it.
+these commands is deprecated. Two new boolean fields, ``recording`` and
+``busy`` effectively replace it.
``query-block`` result field ``dirty-bitmaps`` (Since 4.2)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
@@ -289,6 +329,13 @@ The RISC-V no MMU cpus have been depcreated. The two CPUs: ``rv32imacu-nommu`` a
``rv64imacu-nommu`` should no longer be used. Instead the MMU status can be specified
via the CPU ``mmu`` option when using the ``rv32`` or ``rv64`` CPUs.
+``compat`` property of server class POWER CPUs (since 5.0)
+''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+The ``compat`` property used to set backwards compatibility modes for
+the processor has been deprecated. The ``max-cpu-compat`` property of
+the ``pseries`` machine type should be used instead.
+
System emulator devices
-----------------------
diff --git a/gdbstub.c b/gdbstub.c
index 22a2d630cd..013fb1ac0f 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -319,8 +319,8 @@ static int gdb_signal_to_target (int sig)
typedef struct GDBRegisterState {
int base_reg;
int num_regs;
- gdb_reg_cb get_reg;
- gdb_reg_cb set_reg;
+ gdb_get_reg_cb get_reg;
+ gdb_set_reg_cb set_reg;
const char *xml;
struct GDBRegisterState *next;
} GDBRegisterState;
@@ -342,6 +342,7 @@ enum RSState {
RS_CHKSUM2,
};
typedef struct GDBState {
+ bool init; /* have we been initialised? */
CPUState *c_cpu; /* current CPU for step/continue ops */
CPUState *g_cpu; /* current CPU for other ops */
CPUState *query_cpu; /* for q{f|s}ThreadInfo */
@@ -350,8 +351,7 @@ typedef struct GDBState {
int line_buf_index;
int line_sum; /* running checksum */
int line_csum; /* checksum at the end of the packet */
- uint8_t last_packet[MAX_PACKET_LENGTH + 4];
- int last_packet_len;
+ GByteArray *last_packet;
int signal;
#ifdef CONFIG_USER_ONLY
int fd;
@@ -365,6 +365,8 @@ typedef struct GDBState {
int process_num;
char syscall_buf[256];
gdb_syscall_complete_cb current_syscall_cb;
+ GString *str_buf;
+ GByteArray *mem_buf;
} GDBState;
/* By default use no IRQs and no timers while single stepping so as to
@@ -372,7 +374,26 @@ typedef struct GDBState {
*/
static int sstep_flags = SSTEP_ENABLE|SSTEP_NOIRQ|SSTEP_NOTIMER;
-static GDBState *gdbserver_state;
+static GDBState gdbserver_state;
+
+static void init_gdbserver_state(void)
+{
+ g_assert(!gdbserver_state.init);
+ memset(&gdbserver_state, 0, sizeof(GDBState));
+ gdbserver_state.init = true;
+ gdbserver_state.str_buf = g_string_new(NULL);
+ gdbserver_state.mem_buf = g_byte_array_sized_new(MAX_PACKET_LENGTH);
+ gdbserver_state.last_packet = g_byte_array_sized_new(MAX_PACKET_LENGTH + 4);
+}
+
+#ifndef CONFIG_USER_ONLY
+static void reset_gdbserver_state(void)
+{
+ g_free(gdbserver_state.processes);
+ gdbserver_state.processes = NULL;
+ gdbserver_state.process_num = 0;
+}
+#endif
bool gdb_has_xml;
@@ -380,21 +401,21 @@ bool gdb_has_xml;
/* XXX: This is not thread safe. Do we care? */
static int gdbserver_fd = -1;
-static int get_char(GDBState *s)
+static int get_char(void)
{
uint8_t ch;
int ret;
for(;;) {
- ret = qemu_recv(s->fd, &ch, 1, 0);
+ ret = qemu_recv(gdbserver_state.fd, &ch, 1, 0);
if (ret < 0) {
if (errno == ECONNRESET)
- s->fd = -1;
+ gdbserver_state.fd = -1;
if (errno != EINTR)
return -1;
} else if (ret == 0) {
- close(s->fd);
- s->fd = -1;
+ close(gdbserver_state.fd);
+ gdbserver_state.fd = -1;
return -1;
} else {
break;
@@ -425,18 +446,18 @@ int use_gdb_syscalls(void)
/* -semihosting-config target=auto */
/* On the first call check if gdb is connected and remember. */
if (gdb_syscall_mode == GDB_SYS_UNKNOWN) {
- gdb_syscall_mode = (gdbserver_state ? GDB_SYS_ENABLED
- : GDB_SYS_DISABLED);
+ gdb_syscall_mode = gdbserver_state.init ?
+ GDB_SYS_ENABLED : GDB_SYS_DISABLED;
}
return gdb_syscall_mode == GDB_SYS_ENABLED;
}
/* Resume execution. */
-static inline void gdb_continue(GDBState *s)
+static inline void gdb_continue(void)
{
#ifdef CONFIG_USER_ONLY
- s->running_state = 1;
+ gdbserver_state.running_state = 1;
trace_gdbstub_op_continue();
#else
if (!runstate_needs_reset()) {
@@ -450,7 +471,7 @@ static inline void gdb_continue(GDBState *s)
* Resume execution, per CPU actions. For user-mode emulation it's
* equivalent to gdb_continue.
*/
-static int gdb_continue_partial(GDBState *s, char *newstates)
+static int gdb_continue_partial(char *newstates)
{
CPUState *cpu;
int res = 0;
@@ -465,7 +486,7 @@ static int gdb_continue_partial(GDBState *s, char *newstates)
cpu_single_step(cpu, sstep_flags);
}
}
- s->running_state = 1;
+ gdbserver_state.running_state = 1;
#else
int flag = 0;
@@ -503,13 +524,13 @@ static int gdb_continue_partial(GDBState *s, char *newstates)
return res;
}
-static void put_buffer(GDBState *s, const uint8_t *buf, int len)
+static void put_buffer(const uint8_t *buf, int len)
{
#ifdef CONFIG_USER_ONLY
int ret;
while (len > 0) {
- ret = send(s->fd, buf, len, 0);
+ ret = send(gdbserver_state.fd, buf, len, 0);
if (ret < 0) {
if (errno != EINTR)
return;
@@ -521,7 +542,7 @@ static void put_buffer(GDBState *s, const uint8_t *buf, int len)
#else
/* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */
- qemu_chr_fe_write_all(&s->chr, buf, len);
+ qemu_chr_fe_write_all(&gdbserver_state.chr, buf, len);
#endif
}
@@ -546,25 +567,24 @@ static inline int tohex(int v)
}
/* writes 2*len+1 bytes in buf */
-static void memtohex(char *buf, const uint8_t *mem, int len)
+static void memtohex(GString *buf, const uint8_t *mem, int len)
{
int i, c;
- char *q;
- q = buf;
for(i = 0; i < len; i++) {
c = mem[i];
- *q++ = tohex(c >> 4);
- *q++ = tohex(c & 0xf);
+ g_string_append_c(buf, tohex(c >> 4));
+ g_string_append_c(buf, tohex(c & 0xf));
}
- *q = '\0';
+ g_string_append_c(buf, '\0');
}
-static void hextomem(uint8_t *mem, const char *buf, int len)
+static void hextomem(GByteArray *mem, const char *buf, int len)
{
int i;
for(i = 0; i < len; i++) {
- mem[i] = (fromhex(buf[0]) << 4) | fromhex(buf[1]);
+ guint8 byte = fromhex(buf[0]) << 4 | fromhex(buf[1]);
+ g_byte_array_append(mem, &byte, 1);
buf += 2;
}
}
@@ -603,33 +623,35 @@ static void hexdump(const char *buf, int len,
}
/* return -1 if error, 0 if OK */
-static int put_packet_binary(GDBState *s, const char *buf, int len, bool dump)
+static int put_packet_binary(const char *buf, int len, bool dump)
{
int csum, i;
- uint8_t *p;
+ uint8_t footer[3];
if (dump && trace_event_get_state_backends(TRACE_GDBSTUB_IO_BINARYREPLY)) {
hexdump(buf, len, trace_gdbstub_io_binaryreply);
}
for(;;) {
- p = s->last_packet;
- *(p++) = '$';
- memcpy(p, buf, len);
- p += len;
+ g_byte_array_set_size(gdbserver_state.last_packet, 0);
+ g_byte_array_append(gdbserver_state.last_packet,
+ (const uint8_t *) "$", 1);
+ g_byte_array_append(gdbserver_state.last_packet,
+ (const uint8_t *) buf, len);
csum = 0;
for(i = 0; i < len; i++) {
csum += buf[i];
}
- *(p++) = '#';
- *(p++) = tohex((csum >> 4) & 0xf);
- *(p++) = tohex((csum) & 0xf);
+ footer[0] = '#';
+ footer[1] = tohex((csum >> 4) & 0xf);
+ footer[2] = tohex((csum) & 0xf);
+ g_byte_array_append(gdbserver_state.last_packet, footer, 3);
- s->last_packet_len = p - s->last_packet;
- put_buffer(s, (uint8_t *)s->last_packet, s->last_packet_len);
+ put_buffer(gdbserver_state.last_packet->data,
+ gdbserver_state.last_packet->len);
#ifdef CONFIG_USER_ONLY
- i = get_char(s);
+ i = get_char();
if (i < 0)
return -1;
if (i == '+')
@@ -642,65 +664,69 @@ static int put_packet_binary(GDBState *s, const char *buf, int len, bool dump)
}
/* return -1 if error, 0 if OK */
-static int put_packet(GDBState *s, const char *buf)
+static int put_packet(const char *buf)
{
trace_gdbstub_io_reply(buf);
- return put_packet_binary(s, buf, strlen(buf), false);
+ return put_packet_binary(buf, strlen(buf), false);
+}
+
+static void put_strbuf(void)
+{
+ put_packet(gdbserver_state.str_buf->str);
}
/* Encode data using the encoding for 'x' packets. */
-static int memtox(char *buf, const char *mem, int len)
+static void memtox(GString *buf, const char *mem, int len)
{
- char *p = buf;
char c;
while (len--) {
c = *(mem++);
switch (c) {
case '#': case '$': case '*': case '}':
- *(p++) = '}';
- *(p++) = c ^ 0x20;
+ g_string_append_c(buf, '}');
+ g_string_append_c(buf, c ^ 0x20);
break;
default:
- *(p++) = c;
+ g_string_append_c(buf, c);
break;
}
}
- return p - buf;
}
-static uint32_t gdb_get_cpu_pid(const GDBState *s, CPUState *cpu)
+static uint32_t gdb_get_cpu_pid(CPUState *cpu)
{
/* TODO: In user mode, we should use the task state PID */
if (cpu->cluster_index == UNASSIGNED_CLUSTER_INDEX) {
/* Return the default process' PID */
- return s->processes[s->process_num - 1].pid;
+ int index = gdbserver_state.process_num - 1;
+ return gdbserver_state.processes[index].pid;
}
return cpu->cluster_index + 1;
}
-static GDBProcess *gdb_get_process(const GDBState *s, uint32_t pid)
+static GDBProcess *gdb_get_process(uint32_t pid)
{
int i;
if (!pid) {
/* 0 means any process, we take the first one */
- return &s->processes[0];
+ return &gdbserver_state.processes[0];
}
- for (i = 0; i < s->process_num; i++) {
- if (s->processes[i].pid == pid) {
- return &s->processes[i];
+ for (i = 0; i < gdbserver_state.process_num; i++) {
+ if (gdbserver_state.processes[i].pid == pid) {
+ return &gdbserver_state.processes[i];
}
}
return NULL;
}
-static GDBProcess *gdb_get_cpu_process(const GDBState *s, CPUState *cpu)
+static GDBProcess *gdb_get_cpu_process(CPUState *cpu)
{
- return gdb_get_process(s, gdb_get_cpu_pid(s, cpu));
+ return gdb_get_process(gdb_get_cpu_pid(cpu));
}
static CPUState *find_cpu(uint32_t thread_id)
@@ -716,13 +742,12 @@ static CPUState *find_cpu(uint32_t thread_id)
return NULL;
}
-static CPUState *get_first_cpu_in_process(const GDBState *s,
- GDBProcess *process)
+static CPUState *get_first_cpu_in_process(GDBProcess *process)
{
CPUState *cpu;
CPU_FOREACH(cpu) {
- if (gdb_get_cpu_pid(s, cpu) == process->pid) {
+ if (gdb_get_cpu_pid(cpu) == process->pid) {
return cpu;
}
}
@@ -730,13 +755,13 @@ static CPUState *get_first_cpu_in_process(const GDBState *s,
return NULL;
}
-static CPUState *gdb_next_cpu_in_process(const GDBState *s, CPUState *cpu)
+static CPUState *gdb_next_cpu_in_process(CPUState *cpu)
{
- uint32_t pid = gdb_get_cpu_pid(s, cpu);
+ uint32_t pid = gdb_get_cpu_pid(cpu);
cpu = CPU_NEXT(cpu);
while (cpu) {
- if (gdb_get_cpu_pid(s, cpu) == pid) {
+ if (gdb_get_cpu_pid(cpu) == pid) {
break;
}
@@ -747,12 +772,12 @@ static CPUState *gdb_next_cpu_in_process(const GDBState *s, CPUState *cpu)
}
/* Return the cpu following @cpu, while ignoring unattached processes. */
-static CPUState *gdb_next_attached_cpu(const GDBState *s, CPUState *cpu)
+static CPUState *gdb_next_attached_cpu(CPUState *cpu)
{
cpu = CPU_NEXT(cpu);
while (cpu) {
- if (gdb_get_cpu_process(s, cpu)->attached) {
+ if (gdb_get_cpu_process(cpu)->attached) {
break;
}
@@ -763,29 +788,29 @@ static CPUState *gdb_next_attached_cpu(const GDBState *s, CPUState *cpu)
}
/* Return the first attached cpu */
-static CPUState *gdb_first_attached_cpu(const GDBState *s)
+static CPUState *gdb_first_attached_cpu(void)
{
CPUState *cpu = first_cpu;
- GDBProcess *process = gdb_get_cpu_process(s, cpu);
+ GDBProcess *process = gdb_get_cpu_process(cpu);
if (!process->attached) {
- return gdb_next_attached_cpu(s, cpu);
+ return gdb_next_attached_cpu(cpu);
}
return cpu;
}
-static CPUState *gdb_get_cpu(const GDBState *s, uint32_t pid, uint32_t tid)
+static CPUState *gdb_get_cpu(uint32_t pid, uint32_t tid)
{
GDBProcess *process;
CPUState *cpu;
if (!pid && !tid) {
/* 0 means any process/thread, we take the first attached one */
- return gdb_first_attached_cpu(s);
+ return gdb_first_attached_cpu();
} else if (pid && !tid) {
/* any thread in a specific process */
- process = gdb_get_process(s, pid);
+ process = gdb_get_process(pid);
if (process == NULL) {
return NULL;
@@ -795,7 +820,7 @@ static CPUState *gdb_get_cpu(const GDBState *s, uint32_t pid, uint32_t tid)
return NULL;
}
- return get_first_cpu_in_process(s, process);
+ return get_first_cpu_in_process(process);
} else {
/* a specific thread */
cpu = find_cpu(tid);
@@ -804,7 +829,7 @@ static CPUState *gdb_get_cpu(const GDBState *s, uint32_t pid, uint32_t tid)
return NULL;
}
- process = gdb_get_cpu_process(s, cpu);
+ process = gdb_get_cpu_process(cpu);
if (pid && process->pid != pid) {
return NULL;
@@ -818,13 +843,13 @@ static CPUState *gdb_get_cpu(const GDBState *s, uint32_t pid, uint32_t tid)
}
}
-static const char *get_feature_xml(const GDBState *s, const char *p,
- const char **newp, GDBProcess *process)
+static const char *get_feature_xml(const char *p, const char **newp,
+ GDBProcess *process)
{
size_t len;
int i;
const char *name;
- CPUState *cpu = get_first_cpu_in_process(s, process);
+ CPUState *cpu = get_first_cpu_in_process(process);
CPUClass *cc = CPU_GET_CLASS(cpu);
len = 0;
@@ -881,19 +906,19 @@ static const char *get_feature_xml(const GDBState *s, const char *p,
return name ? xml_builtin[i][1] : NULL;
}
-static int gdb_read_register(CPUState *cpu, uint8_t *mem_buf, int reg)
+static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
{
CPUClass *cc = CPU_GET_CLASS(cpu);
CPUArchState *env = cpu->env_ptr;
GDBRegisterState *r;
if (reg < cc->gdb_num_core_regs) {
- return cc->gdb_read_register(cpu, mem_buf, reg);
+ return cc->gdb_read_register(cpu, buf, reg);
}
for (r = cpu->gdb_regs; r; r = r->next) {
if (r->base_reg <= reg && reg < r->base_reg + r->num_regs) {
- return r->get_reg(env, mem_buf, reg - r->base_reg);
+ return r->get_reg(env, buf, reg - r->base_reg);
}
}
return 0;
@@ -924,7 +949,7 @@ static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg)
*/
void gdb_register_coprocessor(CPUState *cpu,
- gdb_reg_cb get_reg, gdb_reg_cb set_reg,
+ gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
int num_regs, const char *xml, int g_pos)
{
GDBRegisterState *s;
@@ -984,7 +1009,7 @@ static int gdb_breakpoint_insert(int type, target_ulong addr, target_ulong len)
int err = 0;
if (kvm_enabled()) {
- return kvm_insert_breakpoint(gdbserver_state->c_cpu, addr, len, type);
+ return kvm_insert_breakpoint(gdbserver_state.c_cpu, addr, len, type);
}
switch (type) {
@@ -1021,7 +1046,7 @@ static int gdb_breakpoint_remove(int type, target_ulong addr, target_ulong len)
int err = 0;
if (kvm_enabled()) {
- return kvm_remove_breakpoint(gdbserver_state->c_cpu, addr, len, type);
+ return kvm_remove_breakpoint(gdbserver_state.c_cpu, addr, len, type);
}
switch (type) {
@@ -1059,13 +1084,13 @@ static inline void gdb_cpu_breakpoint_remove_all(CPUState *cpu)
#endif
}
-static void gdb_process_breakpoint_remove_all(const GDBState *s, GDBProcess *p)
+static void gdb_process_breakpoint_remove_all(GDBProcess *p)
{
- CPUState *cpu = get_first_cpu_in_process(s, p);
+ CPUState *cpu = get_first_cpu_in_process(p);
while (cpu) {
gdb_cpu_breakpoint_remove_all(cpu);
- cpu = gdb_next_cpu_in_process(s, cpu);
+ cpu = gdb_next_cpu_in_process(cpu);
}
}
@@ -1074,7 +1099,7 @@ static void gdb_breakpoint_remove_all(void)
CPUState *cpu;
if (kvm_enabled()) {
- kvm_remove_all_breakpoints(gdbserver_state->c_cpu);
+ kvm_remove_all_breakpoints(gdbserver_state.c_cpu);
return;
}
@@ -1083,25 +1108,22 @@ static void gdb_breakpoint_remove_all(void)
}
}
-static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
+static void gdb_set_cpu_pc(target_ulong pc)
{
- CPUState *cpu = s->c_cpu;
+ CPUState *cpu = gdbserver_state.c_cpu;
cpu_synchronize_state(cpu);
cpu_set_pc(cpu, pc);
}
-static char *gdb_fmt_thread_id(const GDBState *s, CPUState *cpu,
- char *buf, size_t buf_size)
+static void gdb_append_thread_id(CPUState *cpu, GString *buf)
{
- if (s->multiprocess) {
- snprintf(buf, buf_size, "p%02x.%02x",
- gdb_get_cpu_pid(s, cpu), cpu_gdb_index(cpu));
+ if (gdbserver_state.multiprocess) {
+ g_string_append_printf(buf, "p%02x.%02x",
+ gdb_get_cpu_pid(cpu), cpu_gdb_index(cpu));
} else {
- snprintf(buf, buf_size, "%02x", cpu_gdb_index(cpu));
+ g_string_append_printf(buf, "%02x", cpu_gdb_index(cpu));
}
-
- return buf;
}
typedef enum GDBThreadIdKind {
@@ -1163,7 +1185,7 @@ static GDBThreadIdKind read_thread_id(const char *buf, const char **end_buf,
* returns -ENOTSUP if a command is unsupported, -EINVAL or -ERANGE if there is
* a format error, 0 on success.
*/
-static int gdb_handle_vcont(GDBState *s, const char *p)
+static int gdb_handle_vcont(const char *p)
{
int res, signal = 0;
char cur_action;
@@ -1238,36 +1260,36 @@ static int gdb_handle_vcont(GDBState *s, const char *p)
goto out;
case GDB_ALL_PROCESSES:
- cpu = gdb_first_attached_cpu(s);
+ cpu = gdb_first_attached_cpu();
while (cpu) {
if (newstates[cpu->cpu_index] == 1) {
newstates[cpu->cpu_index] = cur_action;
}
- cpu = gdb_next_attached_cpu(s, cpu);
+ cpu = gdb_next_attached_cpu(cpu);
}
break;
case GDB_ALL_THREADS:
- process = gdb_get_process(s, pid);
+ process = gdb_get_process(pid);
if (!process->attached) {
res = -EINVAL;
goto out;
}
- cpu = get_first_cpu_in_process(s, process);
+ cpu = get_first_cpu_in_process(process);
while (cpu) {
if (newstates[cpu->cpu_index] == 1) {
newstates[cpu->cpu_index] = cur_action;
}
- cpu = gdb_next_cpu_in_process(s, cpu);
+ cpu = gdb_next_cpu_in_process(cpu);
}
break;
case GDB_ONE_THREAD:
- cpu = gdb_get_cpu(s, pid, tid);
+ cpu = gdb_get_cpu(pid, tid);
/* invalid CPU/thread specified */
if (!cpu) {
@@ -1282,8 +1304,8 @@ static int gdb_handle_vcont(GDBState *s, const char *p)
break;
}
}
- s->signal = signal;
- gdb_continue_partial(s, newstates);
+ gdbserver_state.signal = signal;
+ gdb_continue_partial(newstates);
out:
g_free(newstates);
@@ -1392,11 +1414,8 @@ static int cmd_parse_params(const char *data, const char *schema,
}
typedef struct GdbCmdContext {
- GDBState *s;
GdbCmdVariant *params;
int num_params;
- uint8_t mem_buf[MAX_PACKET_LENGTH];
- char str_buf[MAX_PACKET_LENGTH + 1];
} GdbCmdContext;
typedef void (*GdbCmdHandler)(GdbCmdContext *gdb_ctx, void *user_ctx);
@@ -1436,7 +1455,7 @@ static inline int startswith(const char *string, const char *pattern)
return !strncmp(string, pattern, strlen(pattern));
}
-static int process_string_cmd(GDBState *s, void *user_ctx, const char *data,
+static int process_string_cmd(void *user_ctx, const char *data,
const GdbCmdParseEntry *cmds, int num_cmds)
{
int i, schema_len, max_num_params = 0;
@@ -1473,7 +1492,6 @@ static int process_string_cmd(GDBState *s, void *user_ctx, const char *data,
return -1;
}
- gdb_ctx.s = s;
cmd->handler(&gdb_ctx, user_ctx);
return 0;
}
@@ -1481,53 +1499,54 @@ static int process_string_cmd(GDBState *s, void *user_ctx, const char *data,
return -1;
}
-static void run_cmd_parser(GDBState *s, const char *data,
- const GdbCmdParseEntry *cmd)
+static void run_cmd_parser(const char *data, const GdbCmdParseEntry *cmd)
{
if (!data) {
return;
}
+ g_string_set_size(gdbserver_state.str_buf, 0);
+ g_byte_array_set_size(gdbserver_state.mem_buf, 0);
+
/* In case there was an error during the command parsing we must
* send a NULL packet to indicate the command is not supported */
- if (process_string_cmd(s, NULL, data, cmd, 1)) {
- put_packet(s, "");
+ if (process_string_cmd(NULL, data, cmd, 1)) {
+ put_packet("");
}
}
static void handle_detach(GdbCmdContext *gdb_ctx, void *user_ctx)
{
GDBProcess *process;
- GDBState *s = gdb_ctx->s;
uint32_t pid = 1;
- if (s->multiprocess) {
+ if (gdbserver_state.multiprocess) {
if (!gdb_ctx->num_params) {
- put_packet(s, "E22");
+ put_packet("E22");
return;
}
pid = gdb_ctx->params[0].val_ul;
}
- process = gdb_get_process(s, pid);
- gdb_process_breakpoint_remove_all(s, process);
+ process = gdb_get_process(pid);
+ gdb_process_breakpoint_remove_all(process);
process->attached = false;
- if (pid == gdb_get_cpu_pid(s, s->c_cpu)) {
- s->c_cpu = gdb_first_attached_cpu(s);
+ if (pid == gdb_get_cpu_pid(gdbserver_state.c_cpu)) {
+ gdbserver_state.c_cpu = gdb_first_attached_cpu();
}
- if (pid == gdb_get_cpu_pid(s, s->g_cpu)) {
- s->g_cpu = gdb_first_attached_cpu(s);
+ if (pid == gdb_get_cpu_pid(gdbserver_state.g_cpu)) {
+ gdbserver_state.g_cpu = gdb_first_attached_cpu();
}
- if (!s->c_cpu) {
+ if (!gdbserver_state.c_cpu) {
/* No more process attached */
gdb_syscall_mode = GDB_SYS_DISABLED;
- gdb_continue(s);
+ gdb_continue();
}
- put_packet(s, "OK");
+ put_packet("OK");
}
static void handle_thread_alive(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -1535,33 +1554,33 @@ static void handle_thread_alive(GdbCmdContext *gdb_ctx, void *user_ctx)
CPUState *cpu;
if (!gdb_ctx->num_params) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
if (gdb_ctx->params[0].thread_id.kind == GDB_READ_THREAD_ERR) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
- cpu = gdb_get_cpu(gdb_ctx->s, gdb_ctx->params[0].thread_id.pid,
+ cpu = gdb_get_cpu(gdb_ctx->params[0].thread_id.pid,
gdb_ctx->params[0].thread_id.tid);
if (!cpu) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
- put_packet(gdb_ctx->s, "OK");
+ put_packet("OK");
}
static void handle_continue(GdbCmdContext *gdb_ctx, void *user_ctx)
{
if (gdb_ctx->num_params) {
- gdb_set_cpu_pc(gdb_ctx->s, gdb_ctx->params[0].val_ull);
+ gdb_set_cpu_pc(gdb_ctx->params[0].val_ull);
}
- gdb_ctx->s->signal = 0;
- gdb_continue(gdb_ctx->s);
+ gdbserver_state.signal = 0;
+ gdb_continue();
}
static void handle_cont_with_sig(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -1576,11 +1595,11 @@ static void handle_cont_with_sig(GdbCmdContext *gdb_ctx, void *user_ctx)
signal = gdb_ctx->params[0].val_ul;
}
- gdb_ctx->s->signal = gdb_signal_to_target(signal);
- if (gdb_ctx->s->signal == -1) {
- gdb_ctx->s->signal = 0;
+ gdbserver_state.signal = gdb_signal_to_target(signal);
+ if (gdbserver_state.signal == -1) {
+ gdbserver_state.signal = 0;
}
- gdb_continue(gdb_ctx->s);
+ gdb_continue();
}
static void handle_set_thread(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -1588,24 +1607,24 @@ static void handle_set_thread(GdbCmdContext *gdb_ctx, void *user_ctx)
CPUState *cpu;
if (gdb_ctx->num_params != 2) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
if (gdb_ctx->params[1].thread_id.kind == GDB_READ_THREAD_ERR) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
if (gdb_ctx->params[1].thread_id.kind != GDB_ONE_THREAD) {
- put_packet(gdb_ctx->s, "OK");
+ put_packet("OK");
return;
}
- cpu = gdb_get_cpu(gdb_ctx->s, gdb_ctx->params[1].thread_id.pid,
+ cpu = gdb_get_cpu(gdb_ctx->params[1].thread_id.pid,
gdb_ctx->params[1].thread_id.tid);
if (!cpu) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
@@ -1615,15 +1634,15 @@ static void handle_set_thread(GdbCmdContext *gdb_ctx, void *user_ctx)
*/
switch (gdb_ctx->params[0].opcode) {
case 'c':
- gdb_ctx->s->c_cpu = cpu;
- put_packet(gdb_ctx->s, "OK");
+ gdbserver_state.c_cpu = cpu;
+ put_packet("OK");
break;
case 'g':
- gdb_ctx->s->g_cpu = cpu;
- put_packet(gdb_ctx->s, "OK");
+ gdbserver_state.g_cpu = cpu;
+ put_packet("OK");
break;
default:
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
break;
}
}
@@ -1633,7 +1652,7 @@ static void handle_insert_bp(GdbCmdContext *gdb_ctx, void *user_ctx)
int res;
if (gdb_ctx->num_params != 3) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
@@ -1641,14 +1660,14 @@ static void handle_insert_bp(GdbCmdContext *gdb_ctx, void *user_ctx)
gdb_ctx->params[1].val_ull,
gdb_ctx->params[2].val_ull);
if (res >= 0) {
- put_packet(gdb_ctx->s, "OK");
+ put_packet("OK");
return;
} else if (res == -ENOSYS) {
- put_packet(gdb_ctx->s, "");
+ put_packet("");
return;
}
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
}
static void handle_remove_bp(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -1656,7 +1675,7 @@ static void handle_remove_bp(GdbCmdContext *gdb_ctx, void *user_ctx)
int res;
if (gdb_ctx->num_params != 3) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
@@ -1664,14 +1683,14 @@ static void handle_remove_bp(GdbCmdContext *gdb_ctx, void *user_ctx)
gdb_ctx->params[1].val_ull,
gdb_ctx->params[2].val_ull);
if (res >= 0) {
- put_packet(gdb_ctx->s, "OK");
+ put_packet("OK");
return;
} else if (res == -ENOSYS) {
- put_packet(gdb_ctx->s, "");
+ put_packet("");
return;
}
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
}
/*
@@ -1690,20 +1709,20 @@ static void handle_set_reg(GdbCmdContext *gdb_ctx, void *user_ctx)
int reg_size;
if (!gdb_has_xml) {
- put_packet(gdb_ctx->s, "");
+ put_packet("");
return;
}
if (gdb_ctx->num_params != 2) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
reg_size = strlen(gdb_ctx->params[1].data) / 2;
- hextomem(gdb_ctx->mem_buf, gdb_ctx->params[1].data, reg_size);
- gdb_write_register(gdb_ctx->s->g_cpu, gdb_ctx->mem_buf,
+ hextomem(gdbserver_state.mem_buf, gdb_ctx->params[1].data, reg_size);
+ gdb_write_register(gdbserver_state.g_cpu, gdbserver_state.mem_buf->data,
gdb_ctx->params[0].val_ull);
- put_packet(gdb_ctx->s, "OK");
+ put_packet("OK");
}
static void handle_get_reg(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -1711,73 +1730,79 @@ static void handle_get_reg(GdbCmdContext *gdb_ctx, void *user_ctx)
int reg_size;
if (!gdb_has_xml) {
- put_packet(gdb_ctx->s, "");
+ put_packet("");
return;
}
if (!gdb_ctx->num_params) {
- put_packet(gdb_ctx->s, "E14");
+ put_packet("E14");
return;
}
- reg_size = gdb_read_register(gdb_ctx->s->g_cpu, gdb_ctx->mem_buf,
+ reg_size = gdb_read_register(gdbserver_state.g_cpu,
+ gdbserver_state.mem_buf,
gdb_ctx->params[0].val_ull);
if (!reg_size) {
- put_packet(gdb_ctx->s, "E14");
+ put_packet("E14");
return;
+ } else {
+ g_byte_array_set_size(gdbserver_state.mem_buf, reg_size);
}
- memtohex(gdb_ctx->str_buf, gdb_ctx->mem_buf, reg_size);
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ memtohex(gdbserver_state.str_buf, gdbserver_state.mem_buf->data, reg_size);
+ put_strbuf();
}
static void handle_write_mem(GdbCmdContext *gdb_ctx, void *user_ctx)
{
if (gdb_ctx->num_params != 3) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
/* hextomem() reads 2*len bytes */
if (gdb_ctx->params[1].val_ull > strlen(gdb_ctx->params[2].data) / 2) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
- hextomem(gdb_ctx->mem_buf, gdb_ctx->params[2].data,
+ hextomem(gdbserver_state.mem_buf, gdb_ctx->params[2].data,
gdb_ctx->params[1].val_ull);
- if (target_memory_rw_debug(gdb_ctx->s->g_cpu, gdb_ctx->params[0].val_ull,
- gdb_ctx->mem_buf,
- gdb_ctx->params[1].val_ull, true)) {
- put_packet(gdb_ctx->s, "E14");
+ if (target_memory_rw_debug(gdbserver_state.g_cpu, gdb_ctx->params[0].val_ull,
+ gdbserver_state.mem_buf->data,
+ gdbserver_state.mem_buf->len, true)) {
+ put_packet("E14");
return;
}
- put_packet(gdb_ctx->s, "OK");
+ put_packet("OK");
}
static void handle_read_mem(GdbCmdContext *gdb_ctx, void *user_ctx)
{
if (gdb_ctx->num_params != 2) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
/* memtohex() doubles the required space */
if (gdb_ctx->params[1].val_ull > MAX_PACKET_LENGTH / 2) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
- if (target_memory_rw_debug(gdb_ctx->s->g_cpu, gdb_ctx->params[0].val_ull,
- gdb_ctx->mem_buf,
- gdb_ctx->params[1].val_ull, false)) {
- put_packet(gdb_ctx->s, "E14");
+ g_byte_array_set_size(gdbserver_state.mem_buf, gdb_ctx->params[1].val_ull);
+
+ if (target_memory_rw_debug(gdbserver_state.g_cpu, gdb_ctx->params[0].val_ull,
+ gdbserver_state.mem_buf->data,
+ gdbserver_state.mem_buf->len, false)) {
+ put_packet("E14");
return;
}
- memtohex(gdb_ctx->str_buf, gdb_ctx->mem_buf, gdb_ctx->params[1].val_ull);
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ memtohex(gdbserver_state.str_buf, gdbserver_state.mem_buf->data,
+ gdbserver_state.mem_buf->len);
+ put_strbuf();
}
static void handle_write_all_regs(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -1790,37 +1815,40 @@ static void handle_write_all_regs(GdbCmdContext *gdb_ctx, void *user_ctx)
return;
}
- cpu_synchronize_state(gdb_ctx->s->g_cpu);
- registers = gdb_ctx->mem_buf;
+ cpu_synchronize_state(gdbserver_state.g_cpu);
len = strlen(gdb_ctx->params[0].data) / 2;
- hextomem(registers, gdb_ctx->params[0].data, len);
- for (addr = 0; addr < gdb_ctx->s->g_cpu->gdb_num_g_regs && len > 0;
+ hextomem(gdbserver_state.mem_buf, gdb_ctx->params[0].data, len);
+ registers = gdbserver_state.mem_buf->data;
+ for (addr = 0; addr < gdbserver_state.g_cpu->gdb_num_g_regs && len > 0;
addr++) {
- reg_size = gdb_write_register(gdb_ctx->s->g_cpu, registers, addr);
+ reg_size = gdb_write_register(gdbserver_state.g_cpu, registers, addr);
len -= reg_size;
registers += reg_size;
}
- put_packet(gdb_ctx->s, "OK");
+ put_packet("OK");
}
static void handle_read_all_regs(GdbCmdContext *gdb_ctx, void *user_ctx)
{
target_ulong addr, len;
- cpu_synchronize_state(gdb_ctx->s->g_cpu);
+ cpu_synchronize_state(gdbserver_state.g_cpu);
+ g_byte_array_set_size(gdbserver_state.mem_buf, 0);
len = 0;
- for (addr = 0; addr < gdb_ctx->s->g_cpu->gdb_num_g_regs; addr++) {
- len += gdb_read_register(gdb_ctx->s->g_cpu, gdb_ctx->mem_buf + len,
+ for (addr = 0; addr < gdbserver_state.g_cpu->gdb_num_g_regs; addr++) {
+ len += gdb_read_register(gdbserver_state.g_cpu,
+ gdbserver_state.mem_buf,
addr);
}
+ g_assert(len == gdbserver_state.mem_buf->len);
- memtohex(gdb_ctx->str_buf, gdb_ctx->mem_buf, len);
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ memtohex(gdbserver_state.str_buf, gdbserver_state.mem_buf->data, len);
+ put_strbuf();
}
static void handle_file_io(GdbCmdContext *gdb_ctx, void *user_ctx)
{
- if (gdb_ctx->num_params >= 1 && gdb_ctx->s->current_syscall_cb) {
+ if (gdb_ctx->num_params >= 1 && gdbserver_state.current_syscall_cb) {
target_ulong ret, err;
ret = (target_ulong)gdb_ctx->params[0].val_ull;
@@ -1829,31 +1857,31 @@ static void handle_file_io(GdbCmdContext *gdb_ctx, void *user_ctx)
} else {
err = 0;
}
- gdb_ctx->s->current_syscall_cb(gdb_ctx->s->c_cpu, ret, err);
- gdb_ctx->s->current_syscall_cb = NULL;
+ gdbserver_state.current_syscall_cb(gdbserver_state.c_cpu, ret, err);
+ gdbserver_state.current_syscall_cb = NULL;
}
if (gdb_ctx->num_params >= 3 && gdb_ctx->params[2].opcode == (uint8_t)'C') {
- put_packet(gdb_ctx->s, "T02");
+ put_packet("T02");
return;
}
- gdb_continue(gdb_ctx->s);
+ gdb_continue();
}
static void handle_step(GdbCmdContext *gdb_ctx, void *user_ctx)
{
if (gdb_ctx->num_params) {
- gdb_set_cpu_pc(gdb_ctx->s, (target_ulong)gdb_ctx->params[0].val_ull);
+ gdb_set_cpu_pc((target_ulong)gdb_ctx->params[0].val_ull);
}
- cpu_single_step(gdb_ctx->s->c_cpu, sstep_flags);
- gdb_continue(gdb_ctx->s);
+ cpu_single_step(gdbserver_state.c_cpu, sstep_flags);
+ gdb_continue();
}
static void handle_v_cont_query(GdbCmdContext *gdb_ctx, void *user_ctx)
{
- put_packet(gdb_ctx->s, "vCont;c;C;s;S");
+ put_packet("vCont;c;C;s;S");
}
static void handle_v_cont(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -1864,11 +1892,11 @@ static void handle_v_cont(GdbCmdContext *gdb_ctx, void *user_ctx)
return;
}
- res = gdb_handle_vcont(gdb_ctx->s, gdb_ctx->params[0].data);
+ res = gdb_handle_vcont(gdb_ctx->params[0].data);
if ((res == -EINVAL) || (res == -ERANGE)) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
} else if (res) {
- put_packet(gdb_ctx->s, "");
+ put_packet("");
}
}
@@ -1876,38 +1904,37 @@ static void handle_v_attach(GdbCmdContext *gdb_ctx, void *user_ctx)
{
GDBProcess *process;
CPUState *cpu;
- char thread_id[16];
- pstrcpy(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "E22");
+ g_string_assign(gdbserver_state.str_buf, "E22");
if (!gdb_ctx->num_params) {
goto cleanup;
}
- process = gdb_get_process(gdb_ctx->s, gdb_ctx->params[0].val_ul);
+ process = gdb_get_process(gdb_ctx->params[0].val_ul);
if (!process) {
goto cleanup;
}
- cpu = get_first_cpu_in_process(gdb_ctx->s, process);
+ cpu = get_first_cpu_in_process(process);
if (!cpu) {
goto cleanup;
}
process->attached = true;
- gdb_ctx->s->g_cpu = cpu;
- gdb_ctx->s->c_cpu = cpu;
+ gdbserver_state.g_cpu = cpu;
+ gdbserver_state.c_cpu = cpu;
- gdb_fmt_thread_id(gdb_ctx->s, cpu, thread_id, sizeof(thread_id));
- snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "T%02xthread:%s;",
- GDB_SIGNAL_TRAP, thread_id);
+ g_string_printf(gdbserver_state.str_buf, "T%02xthread:", GDB_SIGNAL_TRAP);
+ gdb_append_thread_id(cpu, gdbserver_state.str_buf);
+ g_string_append_c(gdbserver_state.str_buf, ';');
cleanup:
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ put_strbuf();
}
static void handle_v_kill(GdbCmdContext *gdb_ctx, void *user_ctx)
{
/* Kill the target */
- put_packet(gdb_ctx->s, "OK");
+ put_packet("OK");
error_report("QEMU: Terminated via GDBstub");
exit(0);
}
@@ -1944,19 +1971,18 @@ static void handle_v_commands(GdbCmdContext *gdb_ctx, void *user_ctx)
return;
}
- if (process_string_cmd(gdb_ctx->s, NULL, gdb_ctx->params[0].data,
+ if (process_string_cmd(NULL, gdb_ctx->params[0].data,
gdb_v_commands_table,
ARRAY_SIZE(gdb_v_commands_table))) {
- put_packet(gdb_ctx->s, "");
+ put_packet("");
}
}
static void handle_query_qemu_sstepbits(GdbCmdContext *gdb_ctx, void *user_ctx)
{
- snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf),
- "ENABLE=%x,NOIRQ=%x,NOTIMER=%x", SSTEP_ENABLE,
- SSTEP_NOIRQ, SSTEP_NOTIMER);
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ g_string_printf(gdbserver_state.str_buf, "ENABLE=%x,NOIRQ=%x,NOTIMER=%x",
+ SSTEP_ENABLE, SSTEP_NOIRQ, SSTEP_NOTIMER);
+ put_strbuf();
}
static void handle_set_qemu_sstep(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -1966,68 +1992,63 @@ static void handle_set_qemu_sstep(GdbCmdContext *gdb_ctx, void *user_ctx)
}
sstep_flags = gdb_ctx->params[0].val_ul;
- put_packet(gdb_ctx->s, "OK");
+ put_packet("OK");
}
static void handle_query_qemu_sstep(GdbCmdContext *gdb_ctx, void *user_ctx)
{
- snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "0x%x", sstep_flags);
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ g_string_printf(gdbserver_state.str_buf, "0x%x", sstep_flags);
+ put_strbuf();
}
static void handle_query_curr_tid(GdbCmdContext *gdb_ctx, void *user_ctx)
{
CPUState *cpu;
GDBProcess *process;
- char thread_id[16];
/*
* "Current thread" remains vague in the spec, so always return
* the first thread of the current process (gdb returns the
* first thread).
*/
- process = gdb_get_cpu_process(gdb_ctx->s, gdb_ctx->s->g_cpu);
- cpu = get_first_cpu_in_process(gdb_ctx->s, process);
- gdb_fmt_thread_id(gdb_ctx->s, cpu, thread_id, sizeof(thread_id));
- snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "QC%s", thread_id);
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ process = gdb_get_cpu_process(gdbserver_state.g_cpu);
+ cpu = get_first_cpu_in_process(process);
+ g_string_assign(gdbserver_state.str_buf, "QC");
+ gdb_append_thread_id(cpu, gdbserver_state.str_buf);
+ put_strbuf();
}
static void handle_query_threads(GdbCmdContext *gdb_ctx, void *user_ctx)
{
- char thread_id[16];
-
- if (!gdb_ctx->s->query_cpu) {
- put_packet(gdb_ctx->s, "l");
+ if (!gdbserver_state.query_cpu) {
+ put_packet("l");
return;
}
- gdb_fmt_thread_id(gdb_ctx->s, gdb_ctx->s->query_cpu, thread_id,
- sizeof(thread_id));
- snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "m%s", thread_id);
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
- gdb_ctx->s->query_cpu =
- gdb_next_attached_cpu(gdb_ctx->s, gdb_ctx->s->query_cpu);
+ g_string_assign(gdbserver_state.str_buf, "m");
+ gdb_append_thread_id(gdbserver_state.query_cpu, gdbserver_state.str_buf);
+ put_strbuf();
+ gdbserver_state.query_cpu = gdb_next_attached_cpu(gdbserver_state.query_cpu);
}
static void handle_query_first_threads(GdbCmdContext *gdb_ctx, void *user_ctx)
{
- gdb_ctx->s->query_cpu = gdb_first_attached_cpu(gdb_ctx->s);
+ gdbserver_state.query_cpu = gdb_first_attached_cpu();
handle_query_threads(gdb_ctx, user_ctx);
}
static void handle_query_thread_extra(GdbCmdContext *gdb_ctx, void *user_ctx)
{
+ g_autoptr(GString) rs = g_string_new(NULL);
CPUState *cpu;
- int len;
if (!gdb_ctx->num_params ||
gdb_ctx->params[0].thread_id.kind == GDB_READ_THREAD_ERR) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
- cpu = gdb_get_cpu(gdb_ctx->s, gdb_ctx->params[0].thread_id.pid,
+ cpu = gdb_get_cpu(gdb_ctx->params[0].thread_id.pid,
gdb_ctx->params[0].thread_id.tid);
if (!cpu) {
return;
@@ -2035,24 +2056,21 @@ static void handle_query_thread_extra(GdbCmdContext *gdb_ctx, void *user_ctx)
cpu_synchronize_state(cpu);
- if (gdb_ctx->s->multiprocess && (gdb_ctx->s->process_num > 1)) {
+ if (gdbserver_state.multiprocess && (gdbserver_state.process_num > 1)) {
/* Print the CPU model and name in multiprocess mode */
ObjectClass *oc = object_get_class(OBJECT(cpu));
const char *cpu_model = object_class_get_name(oc);
- char *cpu_name = object_get_canonical_path_component(OBJECT(cpu));
- len = snprintf((char *)gdb_ctx->mem_buf, sizeof(gdb_ctx->str_buf) / 2,
- "%s %s [%s]", cpu_model, cpu_name,
- cpu->halted ? "halted " : "running");
- g_free(cpu_name);
+ g_autofree char *cpu_name;
+ cpu_name = object_get_canonical_path_component(OBJECT(cpu));
+ g_string_printf(rs, "%s %s [%s]", cpu_model, cpu_name,
+ cpu->halted ? "halted " : "running");
} else {
- /* memtohex() doubles the required space */
- len = snprintf((char *)gdb_ctx->mem_buf, sizeof(gdb_ctx->str_buf) / 2,
- "CPU#%d [%s]", cpu->cpu_index,
+ g_string_printf(rs, "CPU#%d [%s]", cpu->cpu_index,
cpu->halted ? "halted " : "running");
}
- trace_gdbstub_op_extra_info((char *)gdb_ctx->mem_buf);
- memtohex(gdb_ctx->str_buf, gdb_ctx->mem_buf, len);
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ trace_gdbstub_op_extra_info(rs->str);
+ memtohex(gdbserver_state.str_buf, (uint8_t *)rs->str, rs->len);
+ put_strbuf();
}
#ifdef CONFIG_USER_ONLY
@@ -2060,37 +2078,40 @@ static void handle_query_offsets(GdbCmdContext *gdb_ctx, void *user_ctx)
{
TaskState *ts;
- ts = gdb_ctx->s->c_cpu->opaque;
- snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf),
- "Text=" TARGET_ABI_FMT_lx ";Data=" TARGET_ABI_FMT_lx
- ";Bss=" TARGET_ABI_FMT_lx,
- ts->info->code_offset,
- ts->info->data_offset,
- ts->info->data_offset);
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ ts = gdbserver_state.c_cpu->opaque;
+ g_string_printf(gdbserver_state.str_buf,
+ "Text=" TARGET_ABI_FMT_lx
+ ";Data=" TARGET_ABI_FMT_lx
+ ";Bss=" TARGET_ABI_FMT_lx,
+ ts->info->code_offset,
+ ts->info->data_offset,
+ ts->info->data_offset);
+ put_strbuf();
}
#else
static void handle_query_rcmd(GdbCmdContext *gdb_ctx, void *user_ctx)
{
+ const guint8 zero = 0;
int len;
if (!gdb_ctx->num_params) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
len = strlen(gdb_ctx->params[0].data);
if (len % 2) {
- put_packet(gdb_ctx->s, "E01");
+ put_packet("E01");
return;
}
+ g_assert(gdbserver_state.mem_buf->len == 0);
len = len / 2;
- hextomem(gdb_ctx->mem_buf, gdb_ctx->params[0].data, len);
- gdb_ctx->mem_buf[len++] = 0;
- qemu_chr_be_write(gdb_ctx->s->mon_chr, gdb_ctx->mem_buf, len);
- put_packet(gdb_ctx->s, "OK");
-
+ hextomem(gdbserver_state.mem_buf, gdb_ctx->params[0].data, len);
+ g_byte_array_append(gdbserver_state.mem_buf, &zero, 1);
+ qemu_chr_be_write(gdbserver_state.mon_chr, gdbserver_state.mem_buf->data,
+ gdbserver_state.mem_buf->len);
+ put_packet("OK");
}
#endif
@@ -2098,21 +2119,19 @@ static void handle_query_supported(GdbCmdContext *gdb_ctx, void *user_ctx)
{
CPUClass *cc;
- snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "PacketSize=%x",
- MAX_PACKET_LENGTH);
+ g_string_printf(gdbserver_state.str_buf, "PacketSize=%x", MAX_PACKET_LENGTH);
cc = CPU_GET_CLASS(first_cpu);
if (cc->gdb_core_xml_file) {
- pstrcat(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf),
- ";qXfer:features:read+");
+ g_string_append(gdbserver_state.str_buf, ";qXfer:features:read+");
}
if (gdb_ctx->num_params &&
strstr(gdb_ctx->params[0].data, "multiprocess+")) {
- gdb_ctx->s->multiprocess = true;
+ gdbserver_state.multiprocess = true;
}
- pstrcat(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), ";multiprocess+");
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ g_string_append(gdbserver_state.str_buf, ";vContSupported+;multiprocess+");
+ put_strbuf();
}
static void handle_query_xfer_features(GdbCmdContext *gdb_ctx, void *user_ctx)
@@ -2124,22 +2143,22 @@ static void handle_query_xfer_features(GdbCmdContext *gdb_ctx, void *user_ctx)
const char *p;
if (gdb_ctx->num_params < 3) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
- process = gdb_get_cpu_process(gdb_ctx->s, gdb_ctx->s->g_cpu);
- cc = CPU_GET_CLASS(gdb_ctx->s->g_cpu);
+ process = gdb_get_cpu_process(gdbserver_state.g_cpu);
+ cc = CPU_GET_CLASS(gdbserver_state.g_cpu);
if (!cc->gdb_core_xml_file) {
- put_packet(gdb_ctx->s, "");
+ put_packet("");
return;
}
gdb_has_xml = true;
p = gdb_ctx->params[0].data;
- xml = get_feature_xml(gdb_ctx->s, p, &p, process);
+ xml = get_feature_xml(p, &p, process);
if (!xml) {
- put_packet(gdb_ctx->s, "E00");
+ put_packet("E00");
return;
}
@@ -2147,7 +2166,7 @@ static void handle_query_xfer_features(GdbCmdContext *gdb_ctx, void *user_ctx)
len = gdb_ctx->params[2].val_ul;
total_len = strlen(xml);
if (addr > total_len) {
- put_packet(gdb_ctx->s, "E00");
+ put_packet("E00");
return;
}
@@ -2156,42 +2175,43 @@ static void handle_query_xfer_features(GdbCmdContext *gdb_ctx, void *user_ctx)
}
if (len < total_len - addr) {
- gdb_ctx->str_buf[0] = 'm';
- len = memtox(gdb_ctx->str_buf + 1, xml + addr, len);
+ g_string_assign(gdbserver_state.str_buf, "m");
+ memtox(gdbserver_state.str_buf, xml + addr, len);
} else {
- gdb_ctx->str_buf[0] = 'l';
- len = memtox(gdb_ctx->str_buf + 1, xml + addr, total_len - addr);
+ g_string_assign(gdbserver_state.str_buf, "l");
+ memtox(gdbserver_state.str_buf, xml + addr, total_len - addr);
}
- put_packet_binary(gdb_ctx->s, gdb_ctx->str_buf, len + 1, true);
+ put_packet_binary(gdbserver_state.str_buf->str,
+ gdbserver_state.str_buf->len, true);
}
static void handle_query_attached(GdbCmdContext *gdb_ctx, void *user_ctx)
{
- put_packet(gdb_ctx->s, GDB_ATTACHED);
+ put_packet(GDB_ATTACHED);
}
static void handle_query_qemu_supported(GdbCmdContext *gdb_ctx, void *user_ctx)
{
- snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "sstepbits;sstep");
+ g_string_printf(gdbserver_state.str_buf, "sstepbits;sstep");
#ifndef CONFIG_USER_ONLY
- pstrcat(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), ";PhyMemMode");
+ g_string_append(gdbserver_state.str_buf, ";PhyMemMode");
#endif
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ put_strbuf();
}
#ifndef CONFIG_USER_ONLY
static void handle_query_qemu_phy_mem_mode(GdbCmdContext *gdb_ctx,
void *user_ctx)
{
- snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "%d", phy_memory_mode);
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ g_string_printf(gdbserver_state.str_buf, "%d", phy_memory_mode);
+ put_strbuf();
}
static void handle_set_qemu_phy_mem_mode(GdbCmdContext *gdb_ctx, void *user_ctx)
{
if (!gdb_ctx->num_params) {
- put_packet(gdb_ctx->s, "E22");
+ put_packet("E22");
return;
}
@@ -2200,7 +2220,7 @@ static void handle_set_qemu_phy_mem_mode(GdbCmdContext *gdb_ctx, void *user_ctx)
} else {
phy_memory_mode = 1;
}
- put_packet(gdb_ctx->s, "OK");
+ put_packet("OK");
}
#endif
@@ -2316,16 +2336,16 @@ static void handle_gen_query(GdbCmdContext *gdb_ctx, void *user_ctx)
return;
}
- if (!process_string_cmd(gdb_ctx->s, NULL, gdb_ctx->params[0].data,
+ if (!process_string_cmd(NULL, gdb_ctx->params[0].data,
gdb_gen_query_set_common_table,
ARRAY_SIZE(gdb_gen_query_set_common_table))) {
return;
}
- if (process_string_cmd(gdb_ctx->s, NULL, gdb_ctx->params[0].data,
+ if (process_string_cmd(NULL, gdb_ctx->params[0].data,
gdb_gen_query_table,
ARRAY_SIZE(gdb_gen_query_table))) {
- put_packet(gdb_ctx->s, "");
+ put_packet("");
}
}
@@ -2335,28 +2355,25 @@ static void handle_gen_set(GdbCmdContext *gdb_ctx, void *user_ctx)
return;
}
- if (!process_string_cmd(gdb_ctx->s, NULL, gdb_ctx->params[0].data,
+ if (!process_string_cmd(NULL, gdb_ctx->params[0].data,
gdb_gen_query_set_common_table,
ARRAY_SIZE(gdb_gen_query_set_common_table))) {
return;
}
- if (process_string_cmd(gdb_ctx->s, NULL, gdb_ctx->params[0].data,
+ if (process_string_cmd(NULL, gdb_ctx->params[0].data,
gdb_gen_set_table,
ARRAY_SIZE(gdb_gen_set_table))) {
- put_packet(gdb_ctx->s, "");
+ put_packet("");
}
}
static void handle_target_halt(GdbCmdContext *gdb_ctx, void *user_ctx)
{
- char thread_id[16];
-
- gdb_fmt_thread_id(gdb_ctx->s, gdb_ctx->s->c_cpu, thread_id,
- sizeof(thread_id));
- snprintf(gdb_ctx->str_buf, sizeof(gdb_ctx->str_buf), "T%02xthread:%s;",
- GDB_SIGNAL_TRAP, thread_id);
- put_packet(gdb_ctx->s, gdb_ctx->str_buf);
+ g_string_printf(gdbserver_state.str_buf, "T%02xthread:", GDB_SIGNAL_TRAP);
+ gdb_append_thread_id(gdbserver_state.c_cpu, gdbserver_state.str_buf);
+ g_string_append_c(gdbserver_state.str_buf, ';');
+ put_strbuf();
/*
* Remove all the breakpoints when this query is issued,
* because gdb is doing an initial connect and the state
@@ -2365,7 +2382,7 @@ static void handle_target_halt(GdbCmdContext *gdb_ctx, void *user_ctx)
gdb_breakpoint_remove_all();
}
-static int gdb_handle_packet(GDBState *s, const char *line_buf)
+static int gdb_handle_packet(const char *line_buf)
{
const GdbCmdParseEntry *cmd_parser = NULL;
@@ -2373,7 +2390,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
switch (line_buf[0]) {
case '!':
- put_packet(s, "OK");
+ put_packet("OK");
break;
case '?':
{
@@ -2588,12 +2605,12 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
break;
default:
/* put empty packet */
- put_packet(s, "");
+ put_packet("");
break;
}
if (cmd_parser) {
- run_cmd_parser(s, line_buf, cmd_parser);
+ run_cmd_parser(line_buf, cmd_parser);
}
return RS_IDLE;
@@ -2601,7 +2618,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
void gdb_set_stop_cpu(CPUState *cpu)
{
- GDBProcess *p = gdb_get_cpu_process(gdbserver_state, cpu);
+ GDBProcess *p = gdb_get_cpu_process(cpu);
if (!p->attached) {
/*
@@ -2611,26 +2628,25 @@ void gdb_set_stop_cpu(CPUState *cpu)
return;
}
- gdbserver_state->c_cpu = cpu;
- gdbserver_state->g_cpu = cpu;
+ gdbserver_state.c_cpu = cpu;
+ gdbserver_state.g_cpu = cpu;
}
#ifndef CONFIG_USER_ONLY
static void gdb_vm_state_change(void *opaque, int running, RunState state)
{
- GDBState *s = gdbserver_state;
- CPUState *cpu = s->c_cpu;
- char buf[256];
- char thread_id[16];
+ CPUState *cpu = gdbserver_state.c_cpu;
+ g_autoptr(GString) buf = g_string_new(NULL);
+ g_autoptr(GString) tid = g_string_new(NULL);
const char *type;
int ret;
- if (running || s->state == RS_INACTIVE) {
+ if (running || gdbserver_state.state == RS_INACTIVE) {
return;
}
/* Is there a GDB syscall waiting to be sent? */
- if (s->current_syscall_cb) {
- put_packet(s, s->syscall_buf);
+ if (gdbserver_state.current_syscall_cb) {
+ put_packet(gdbserver_state.syscall_buf);
return;
}
@@ -2639,7 +2655,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
return;
}
- gdb_fmt_thread_id(s, cpu, thread_id, sizeof(thread_id));
+ gdb_append_thread_id(cpu, tid);
switch (state) {
case RUN_STATE_DEBUG:
@@ -2657,10 +2673,9 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
}
trace_gdbstub_hit_watchpoint(type, cpu_gdb_index(cpu),
(target_ulong)cpu->watchpoint_hit->vaddr);
- snprintf(buf, sizeof(buf),
- "T%02xthread:%s;%swatch:" TARGET_FMT_lx ";",
- GDB_SIGNAL_TRAP, thread_id, type,
- (target_ulong)cpu->watchpoint_hit->vaddr);
+ g_string_printf(buf, "T%02xthread:%s;%swatch:" TARGET_FMT_lx ";",
+ GDB_SIGNAL_TRAP, tid->str, type,
+ (target_ulong)cpu->watchpoint_hit->vaddr);
cpu->watchpoint_hit = NULL;
goto send_packet;
} else {
@@ -2701,10 +2716,10 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
break;
}
gdb_set_stop_cpu(cpu);
- snprintf(buf, sizeof(buf), "T%02xthread:%s;", ret, thread_id);
+ g_string_printf(buf, "T%02xthread:%s;", ret, tid->str);
send_packet:
- put_packet(s, buf);
+ put_packet(buf->str);
/* disable single step if it was enabled */
cpu_single_step(cpu, 0);
@@ -2722,17 +2737,17 @@ void gdb_do_syscallv(gdb_syscall_complete_cb cb, const char *fmt, va_list va)
char *p_end;
target_ulong addr;
uint64_t i64;
- GDBState *s;
- s = gdbserver_state;
- if (!s)
+ if (!gdbserver_state.init) {
return;
- s->current_syscall_cb = cb;
+ }
+
+ gdbserver_state.current_syscall_cb = cb;
#ifndef CONFIG_USER_ONLY
vm_stop(RUN_STATE_DEBUG);
#endif
- p = s->syscall_buf;
- p_end = &s->syscall_buf[sizeof(s->syscall_buf)];
+ p = &gdbserver_state.syscall_buf[0];
+ p_end = &gdbserver_state.syscall_buf[sizeof(gdbserver_state.syscall_buf)];
*(p++) = 'F';
while (*fmt) {
if (*fmt == '%') {
@@ -2765,14 +2780,14 @@ void gdb_do_syscallv(gdb_syscall_complete_cb cb, const char *fmt, va_list va)
}
*p = 0;
#ifdef CONFIG_USER_ONLY
- put_packet(s, s->syscall_buf);
+ put_packet(gdbserver_state.syscall_buf);
/* Return control to gdb for it to process the syscall request.
* Since the protocol requires that gdb hands control back to us
* using a "here are the results" F packet, we don't need to check
* gdb_handlesig's return value (which is the signal to deliver if
* execution was resumed via a continue packet).
*/
- gdb_handlesig(s->c_cpu, 0);
+ gdb_handlesig(gdbserver_state.c_cpu, 0);
#else
/* In this case wait to send the syscall packet until notification that
the CPU has stopped. This must be done because if the packet is sent
@@ -2780,7 +2795,7 @@ void gdb_do_syscallv(gdb_syscall_complete_cb cb, const char *fmt, va_list va)
is still in the running state, which can cause packets to be dropped
and state transition 'T' packets to be sent while the syscall is still
being processed. */
- qemu_cpu_kick(s->c_cpu);
+ qemu_cpu_kick(gdbserver_state.c_cpu);
#endif
}
@@ -2793,25 +2808,27 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
va_end(va);
}
-static void gdb_read_byte(GDBState *s, uint8_t ch)
+static void gdb_read_byte(uint8_t ch)
{
uint8_t reply;
#ifndef CONFIG_USER_ONLY
- if (s->last_packet_len) {
+ if (gdbserver_state.last_packet->len) {
/* Waiting for a response to the last packet. If we see the start
of a new command then abandon the previous response. */
if (ch == '-') {
trace_gdbstub_err_got_nack();
- put_buffer(s, (uint8_t *)s->last_packet, s->last_packet_len);
+ put_buffer(gdbserver_state.last_packet->data,
+ gdbserver_state.last_packet->len);
} else if (ch == '+') {
trace_gdbstub_io_got_ack();
} else {
trace_gdbstub_io_got_unexpected(ch);
}
- if (ch == '+' || ch == '$')
- s->last_packet_len = 0;
+ if (ch == '+' || ch == '$') {
+ g_byte_array_set_size(gdbserver_state.last_packet, 0);
+ }
if (ch != '$')
return;
}
@@ -2822,13 +2839,13 @@ static void gdb_read_byte(GDBState *s, uint8_t ch)
} else
#endif
{
- switch(s->state) {
+ switch(gdbserver_state.state) {
case RS_IDLE:
if (ch == '$') {
/* start of command packet */
- s->line_buf_index = 0;
- s->line_sum = 0;
- s->state = RS_GETLINE;
+ gdbserver_state.line_buf_index = 0;
+ gdbserver_state.line_sum = 0;
+ gdbserver_state.state = RS_GETLINE;
} else {
trace_gdbstub_err_garbage(ch);
}
@@ -2836,37 +2853,37 @@ static void gdb_read_byte(GDBState *s, uint8_t ch)
case RS_GETLINE:
if (ch == '}') {
/* start escape sequence */
- s->state = RS_GETLINE_ESC;
- s->line_sum += ch;
+ gdbserver_state.state = RS_GETLINE_ESC;
+ gdbserver_state.line_sum += ch;
} else if (ch == '*') {
/* start run length encoding sequence */
- s->state = RS_GETLINE_RLE;
- s->line_sum += ch;
+ gdbserver_state.state = RS_GETLINE_RLE;
+ gdbserver_state.line_sum += ch;
} else if (ch == '#') {
/* end of command, start of checksum*/
- s->state = RS_CHKSUM1;
- } else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
+ gdbserver_state.state = RS_CHKSUM1;
+ } else if (gdbserver_state.line_buf_index >= sizeof(gdbserver_state.line_buf) - 1) {
trace_gdbstub_err_overrun();
- s->state = RS_IDLE;
+ gdbserver_state.state = RS_IDLE;
} else {
/* unescaped command character */
- s->line_buf[s->line_buf_index++] = ch;
- s->line_sum += ch;
+ gdbserver_state.line_buf[gdbserver_state.line_buf_index++] = ch;
+ gdbserver_state.line_sum += ch;
}
break;
case RS_GETLINE_ESC:
if (ch == '#') {
/* unexpected end of command in escape sequence */
- s->state = RS_CHKSUM1;
- } else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
+ gdbserver_state.state = RS_CHKSUM1;
+ } else if (gdbserver_state.line_buf_index >= sizeof(gdbserver_state.line_buf) - 1) {
/* command buffer overrun */
trace_gdbstub_err_overrun();
- s->state = RS_IDLE;
+ gdbserver_state.state = RS_IDLE;
} else {
/* parse escaped character and leave escape state */
- s->line_buf[s->line_buf_index++] = ch ^ 0x20;
- s->line_sum += ch;
- s->state = RS_GETLINE;
+ gdbserver_state.line_buf[gdbserver_state.line_buf_index++] = ch ^ 0x20;
+ gdbserver_state.line_sum += ch;
+ gdbserver_state.state = RS_GETLINE;
}
break;
case RS_GETLINE_RLE:
@@ -2877,25 +2894,25 @@ static void gdb_read_byte(GDBState *s, uint8_t ch)
if (ch < ' ' || ch == '#' || ch == '$' || ch > 126) {
/* invalid RLE count encoding */
trace_gdbstub_err_invalid_repeat(ch);
- s->state = RS_GETLINE;
+ gdbserver_state.state = RS_GETLINE;
} else {
/* decode repeat length */
int repeat = ch - ' ' + 3;
- if (s->line_buf_index + repeat >= sizeof(s->line_buf) - 1) {
+ if (gdbserver_state.line_buf_index + repeat >= sizeof(gdbserver_state.line_buf) - 1) {
/* that many repeats would overrun the command buffer */
trace_gdbstub_err_overrun();
- s->state = RS_IDLE;
- } else if (s->line_buf_index < 1) {
+ gdbserver_state.state = RS_IDLE;
+ } else if (gdbserver_state.line_buf_index < 1) {
/* got a repeat but we have nothing to repeat */
trace_gdbstub_err_invalid_rle();
- s->state = RS_GETLINE;
+ gdbserver_state.state = RS_GETLINE;
} else {
/* repeat the last character */
- memset(s->line_buf + s->line_buf_index,
- s->line_buf[s->line_buf_index - 1], repeat);
- s->line_buf_index += repeat;
- s->line_sum += ch;
- s->state = RS_GETLINE;
+ memset(gdbserver_state.line_buf + gdbserver_state.line_buf_index,
+ gdbserver_state.line_buf[gdbserver_state.line_buf_index - 1], repeat);
+ gdbserver_state.line_buf_index += repeat;
+ gdbserver_state.line_sum += ch;
+ gdbserver_state.state = RS_GETLINE;
}
}
break;
@@ -2903,33 +2920,33 @@ static void gdb_read_byte(GDBState *s, uint8_t ch)
/* get high hex digit of checksum */
if (!isxdigit(ch)) {
trace_gdbstub_err_checksum_invalid(ch);
- s->state = RS_GETLINE;
+ gdbserver_state.state = RS_GETLINE;
break;
}
- s->line_buf[s->line_buf_index] = '\0';
- s->line_csum = fromhex(ch) << 4;
- s->state = RS_CHKSUM2;
+ gdbserver_state.line_buf[gdbserver_state.line_buf_index] = '\0';
+ gdbserver_state.line_csum = fromhex(ch) << 4;
+ gdbserver_state.state = RS_CHKSUM2;
break;
case RS_CHKSUM2:
/* get low hex digit of checksum */
if (!isxdigit(ch)) {
trace_gdbstub_err_checksum_invalid(ch);
- s->state = RS_GETLINE;
+ gdbserver_state.state = RS_GETLINE;
break;
}
- s->line_csum |= fromhex(ch);
+ gdbserver_state.line_csum |= fromhex(ch);
- if (s->line_csum != (s->line_sum & 0xff)) {
- trace_gdbstub_err_checksum_incorrect(s->line_sum, s->line_csum);
+ if (gdbserver_state.line_csum != (gdbserver_state.line_sum & 0xff)) {
+ trace_gdbstub_err_checksum_incorrect(gdbserver_state.line_sum, gdbserver_state.line_csum);
/* send NAK reply */
reply = '-';
- put_buffer(s, &reply, 1);
- s->state = RS_IDLE;
+ put_buffer(&reply, 1);
+ gdbserver_state.state = RS_IDLE;
} else {
/* send ACK reply */
reply = '+';
- put_buffer(s, &reply, 1);
- s->state = gdb_handle_packet(s, s->line_buf);
+ put_buffer(&reply, 1);
+ gdbserver_state.state = gdb_handle_packet(gdbserver_state.line_buf);
}
break;
default:
@@ -2941,15 +2958,13 @@ static void gdb_read_byte(GDBState *s, uint8_t ch)
/* Tell the remote gdb that the process has exited. */
void gdb_exit(CPUArchState *env, int code)
{
- GDBState *s;
char buf[4];
- s = gdbserver_state;
- if (!s) {
+ if (!gdbserver_state.init) {
return;
}
#ifdef CONFIG_USER_ONLY
- if (gdbserver_fd < 0 || s->fd < 0) {
+ if (gdbserver_fd < 0 || gdbserver_state.fd < 0) {
return;
}
#endif
@@ -2957,10 +2972,10 @@ void gdb_exit(CPUArchState *env, int code)
trace_gdbstub_op_exiting((uint8_t)code);
snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code);
- put_packet(s, buf);
+ put_packet(buf);
#ifndef CONFIG_USER_ONLY
- qemu_chr_fe_deinit(&s->chr, true);
+ qemu_chr_fe_deinit(&gdbserver_state.chr, true);
#endif
}
@@ -2974,7 +2989,7 @@ static void create_default_process(GDBState *s)
GDBProcess *process;
int max_pid = 0;
- if (s->process_num) {
+ if (gdbserver_state.process_num) {
max_pid = s->processes[s->process_num - 1].pid;
}
@@ -2993,12 +3008,10 @@ static void create_default_process(GDBState *s)
int
gdb_handlesig(CPUState *cpu, int sig)
{
- GDBState *s;
char buf[256];
int n;
- s = gdbserver_state;
- if (gdbserver_fd < 0 || s->fd < 0) {
+ if (gdbserver_fd < 0 || gdbserver_state.fd < 0) {
return sig;
}
@@ -3008,58 +3021,55 @@ gdb_handlesig(CPUState *cpu, int sig)
if (sig != 0) {
snprintf(buf, sizeof(buf), "S%02x", target_signal_to_gdb(sig));
- put_packet(s, buf);
+ put_packet(buf);
}
/* put_packet() might have detected that the peer terminated the
connection. */
- if (s->fd < 0) {
+ if (gdbserver_state.fd < 0) {
return sig;
}
sig = 0;
- s->state = RS_IDLE;
- s->running_state = 0;
- while (s->running_state == 0) {
- n = read(s->fd, buf, 256);
+ gdbserver_state.state = RS_IDLE;
+ gdbserver_state.running_state = 0;
+ while (gdbserver_state.running_state == 0) {
+ n = read(gdbserver_state.fd, buf, 256);
if (n > 0) {
int i;
for (i = 0; i < n; i++) {
- gdb_read_byte(s, buf[i]);
+ gdb_read_byte(buf[i]);
}
} else {
/* XXX: Connection closed. Should probably wait for another
connection before continuing. */
if (n == 0) {
- close(s->fd);
+ close(gdbserver_state.fd);
}
- s->fd = -1;
+ gdbserver_state.fd = -1;
return sig;
}
}
- sig = s->signal;
- s->signal = 0;
+ sig = gdbserver_state.signal;
+ gdbserver_state.signal = 0;
return sig;
}
/* Tell the remote gdb that the process has exited due to SIG. */
void gdb_signalled(CPUArchState *env, int sig)
{
- GDBState *s;
char buf[4];
- s = gdbserver_state;
- if (gdbserver_fd < 0 || s->fd < 0) {
+ if (gdbserver_fd < 0 || gdbserver_state.fd < 0) {
return;
}
snprintf(buf, sizeof(buf), "X%02x", target_signal_to_gdb(sig));
- put_packet(s, buf);
+ put_packet(buf);
}
static bool gdb_accept(void)
{
- GDBState *s;
struct sockaddr_in sockaddr;
socklen_t len;
int fd;
@@ -3083,15 +3093,13 @@ static bool gdb_accept(void)
return false;
}
- s = g_malloc0(sizeof(GDBState));
- create_default_process(s);
- s->processes[0].attached = true;
- s->c_cpu = gdb_first_attached_cpu(s);
- s->g_cpu = s->c_cpu;
- s->fd = fd;
+ init_gdbserver_state();
+ create_default_process(&gdbserver_state);
+ gdbserver_state.processes[0].attached = true;
+ gdbserver_state.c_cpu = gdb_first_attached_cpu();
+ gdbserver_state.g_cpu = gdbserver_state.c_cpu;
+ gdbserver_state.fd = fd;
gdb_has_xml = false;
-
- gdbserver_state = s;
return true;
}
@@ -3144,13 +3152,11 @@ int gdbserver_start(int port)
/* Disable gdb stub for child processes. */
void gdbserver_fork(CPUState *cpu)
{
- GDBState *s = gdbserver_state;
-
- if (gdbserver_fd < 0 || s->fd < 0) {
+ if (gdbserver_fd < 0 || gdbserver_state.fd < 0) {
return;
}
- close(s->fd);
- s->fd = -1;
+ close(gdbserver_state.fd);
+ gdbserver_state.fd = -1;
cpu_breakpoint_remove_all(cpu, BP_GDB);
cpu_watchpoint_remove_all(cpu, BP_GDB);
}
@@ -3167,7 +3173,7 @@ static void gdb_chr_receive(void *opaque, const uint8_t *buf, int size)
int i;
for (i = 0; i < size; i++) {
- gdb_read_byte(gdbserver_state, buf[i]);
+ gdb_read_byte(buf[i]);
}
}
@@ -3183,7 +3189,7 @@ static void gdb_chr_event(void *opaque, QEMUChrEvent event)
s->processes[i].attached = !i;
}
- s->c_cpu = gdb_first_attached_cpu(s);
+ s->c_cpu = gdb_first_attached_cpu();
s->g_cpu = s->c_cpu;
vm_stop(RUN_STATE_PAUSED);
@@ -3194,32 +3200,11 @@ static void gdb_chr_event(void *opaque, QEMUChrEvent event)
}
}
-static void gdb_monitor_output(GDBState *s, const char *msg, int len)
-{
- char buf[MAX_PACKET_LENGTH];
-
- buf[0] = 'O';
- if (len > (MAX_PACKET_LENGTH/2) - 1)
- len = (MAX_PACKET_LENGTH/2) - 1;
- memtohex(buf + 1, (uint8_t *)msg, len);
- put_packet(s, buf);
-}
-
static int gdb_monitor_write(Chardev *chr, const uint8_t *buf, int len)
{
- const char *p = (const char *)buf;
- int max_sz;
-
- max_sz = (sizeof(gdbserver_state->last_packet) - 2) / 2;
- for (;;) {
- if (len <= max_sz) {
- gdb_monitor_output(gdbserver_state, p, len);
- break;
- }
- gdb_monitor_output(gdbserver_state, p, max_sz);
- p += max_sz;
- len -= max_sz;
- }
+ g_autoptr(GString) hex_buf = g_string_new("O");
+ memtohex(hex_buf, buf, len);
+ put_packet(hex_buf->str);
return len;
}
@@ -3300,26 +3285,18 @@ static void create_processes(GDBState *s)
{
object_child_foreach(object_get_root(), find_cpu_clusters, s);
- if (s->processes) {
+ if (gdbserver_state.processes) {
/* Sort by PID */
- qsort(s->processes, s->process_num, sizeof(s->processes[0]), pid_order);
+ qsort(gdbserver_state.processes, gdbserver_state.process_num, sizeof(gdbserver_state.processes[0]), pid_order);
}
create_default_process(s);
}
-static void cleanup_processes(GDBState *s)
-{
- g_free(s->processes);
- s->process_num = 0;
- s->processes = NULL;
-}
-
int gdbserver_start(const char *device)
{
trace_gdbstub_op_start(device);
- GDBState *s;
char gdbstub_device_name[128];
Chardev *chr = NULL;
Chardev *mon_chr;
@@ -3357,10 +3334,8 @@ int gdbserver_start(const char *device)
return -1;
}
- s = gdbserver_state;
- if (!s) {
- s = g_malloc0(sizeof(GDBState));
- gdbserver_state = s;
+ if (!gdbserver_state.init) {
+ init_gdbserver_state();
qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL);
@@ -3369,31 +3344,30 @@ int gdbserver_start(const char *device)
NULL, NULL, &error_abort);
monitor_init_hmp(mon_chr, false, &error_abort);
} else {
- qemu_chr_fe_deinit(&s->chr, true);
- mon_chr = s->mon_chr;
- cleanup_processes(s);
- memset(s, 0, sizeof(GDBState));
- s->mon_chr = mon_chr;
+ qemu_chr_fe_deinit(&gdbserver_state.chr, true);
+ mon_chr = gdbserver_state.mon_chr;
+ reset_gdbserver_state();
}
- create_processes(s);
+ create_processes(&gdbserver_state);
if (chr) {
- qemu_chr_fe_init(&s->chr, chr, &error_abort);
- qemu_chr_fe_set_handlers(&s->chr, gdb_chr_can_receive, gdb_chr_receive,
- gdb_chr_event, NULL, s, NULL, true);
+ qemu_chr_fe_init(&gdbserver_state.chr, chr, &error_abort);
+ qemu_chr_fe_set_handlers(&gdbserver_state.chr, gdb_chr_can_receive,
+ gdb_chr_receive, gdb_chr_event,
+ NULL, &gdbserver_state, NULL, true);
}
- s->state = chr ? RS_IDLE : RS_INACTIVE;
- s->mon_chr = mon_chr;
- s->current_syscall_cb = NULL;
+ gdbserver_state.state = chr ? RS_IDLE : RS_INACTIVE;
+ gdbserver_state.mon_chr = mon_chr;
+ gdbserver_state.current_syscall_cb = NULL;
return 0;
}
void gdbserver_cleanup(void)
{
- if (gdbserver_state) {
- put_packet(gdbserver_state, "W00");
+ if (gdbserver_state.init) {
+ put_packet("W00");
}
}
diff --git a/hw/alpha/dp264.c b/hw/alpha/dp264.c
index e5350a287f..f7751b18f6 100644
--- a/hw/alpha/dp264.c
+++ b/hw/alpha/dp264.c
@@ -15,7 +15,7 @@
#include "qemu/error-report.h"
#include "sysemu/sysemu.h"
#include "hw/rtc/mc146818rtc.h"
-#include "hw/ide.h"
+#include "hw/ide/pci.h"
#include "hw/timer/i8254.h"
#include "hw/isa/superio.h"
#include "hw/dma/i8257.h"
@@ -57,6 +57,7 @@ static void clipper_init(MachineState *machine)
const char *initrd_filename = machine->initrd_filename;
AlphaCPU *cpus[4];
PCIBus *pci_bus;
+ PCIDevice *pci_dev;
ISABus *isa_bus;
qemu_irq rtc_irq;
long size, i;
@@ -99,12 +100,8 @@ static void clipper_init(MachineState *machine)
isa_create_simple(isa_bus, TYPE_SMC37C669_SUPERIO);
/* IDE disk setup. */
- {
- DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
- ide_drive_get(hd, ARRAY_SIZE(hd));
-
- pci_cmd646_ide_init(pci_bus, hd, 0);
- }
+ pci_dev = pci_create_simple(pci_bus, -1, "cmd646-ide");
+ pci_ide_create_devs(pci_dev);
/* Load PALcode. Given that this is not "real" cpu palcode,
but one explicitly written for the emulation, we might as
diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c
index 3885464513..07bb32e22b 100644
--- a/hw/block/xen-block.c
+++ b/hw/block/xen-block.c
@@ -998,29 +998,27 @@ static void xen_block_device_destroy(XenBackendInstance *backend,
XenBlockVdev *vdev = &blockdev->props.vdev;
XenBlockDrive *drive = blockdev->drive;
XenBlockIOThread *iothread = blockdev->iothread;
+ Error *local_err = NULL;
trace_xen_block_device_destroy(vdev->number);
object_unparent(OBJECT(xendev));
if (iothread) {
- Error *local_err = NULL;
-
xen_block_iothread_destroy(iothread, &local_err);
if (local_err) {
error_propagate_prepend(errp, local_err,
- "failed to destroy iothread: ");
+ "failed to destroy iothread: ");
return;
}
}
if (drive) {
- Error *local_err = NULL;
-
xen_block_drive_destroy(drive, &local_err);
if (local_err) {
error_propagate_prepend(errp, local_err,
- "failed to destroy drive: ");
+ "failed to destroy drive: ");
+ return;
}
}
}
diff --git a/hw/core/cpu.c b/hw/core/cpu.c
index b889878f3c..786a1bec8a 100644
--- a/hw/core/cpu.c
+++ b/hw/core/cpu.c
@@ -177,7 +177,7 @@ static int cpu_common_write_elf64_note(WriteCoreDumpFunction f,
}
-static int cpu_common_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg)
+static int cpu_common_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
{
return 0;
}
diff --git a/hw/hppa/hppa_sys.h b/hw/hppa/hppa_sys.h
index 4d08501464..0b18271cc9 100644
--- a/hw/hppa/hppa_sys.h
+++ b/hw/hppa/hppa_sys.h
@@ -5,7 +5,6 @@
#include "hw/pci/pci.h"
#include "hw/pci/pci_host.h"
-#include "hw/ide.h"
#include "hw/boards.h"
#include "hw/intc/i8259.h"
diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c
index 9175f4b790..00dd9f58d6 100644
--- a/hw/hppa/machine.c
+++ b/hw/hppa/machine.c
@@ -13,7 +13,6 @@
#include "sysemu/reset.h"
#include "sysemu/sysemu.h"
#include "hw/rtc/mc146818rtc.h"
-#include "hw/ide.h"
#include "hw/timer/i8254.h"
#include "hw/char/serial.h"
#include "hw/net/lasi_82596.h"
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index e2d98243bc..e6756216f9 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -38,7 +38,7 @@
#include "hw/pci/pci_ids.h"
#include "hw/usb.h"
#include "net/net.h"
-#include "hw/ide.h"
+#include "hw/ide/pci.h"
#include "hw/irq.h"
#include "sysemu/kvm.h"
#include "hw/kvm/clock.h"
@@ -85,7 +85,6 @@ static void pc_init1(MachineState *machine,
int piix3_devfn = -1;
qemu_irq smi_irq;
GSIState *gsi_state;
- DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
BusState *idebus[MAX_IDE_BUS];
ISADevice *rtc_state;
MemoryRegion *ram_memory;
@@ -239,21 +238,22 @@ static void pc_init1(MachineState *machine,
pc_nic_init(pcmc, isa_bus, pci_bus);
- ide_drive_get(hd, ARRAY_SIZE(hd));
if (pcmc->pci_enabled) {
PCIDevice *dev;
- if (xen_enabled()) {
- dev = pci_piix3_xen_ide_init(pci_bus, hd, piix3_devfn + 1);
- } else {
- dev = pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1);
- }
+
+ dev = pci_create_simple(pci_bus, piix3_devfn + 1,
+ xen_enabled() ? "piix3-ide-xen" : "piix3-ide");
+ pci_ide_create_devs(dev);
idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0");
idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1");
pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state);
}
#ifdef CONFIG_IDE_ISA
-else {
+ else {
+ DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
int i;
+
+ ide_drive_get(hd, ARRAY_SIZE(hd));
for (i = 0; i < MAX_IDE_BUS; i++) {
ISADevice *dev;
char busname[] = "ide.0";
diff --git a/hw/ide/ahci_internal.h b/hw/ide/ahci_internal.h
index 73424516da..bab0459774 100644
--- a/hw/ide/ahci_internal.h
+++ b/hw/ide/ahci_internal.h
@@ -27,6 +27,7 @@
#include "hw/ide/ahci.h"
#include "hw/ide/internal.h"
#include "hw/sysbus.h"
+#include "hw/pci/pci.h"
#define AHCI_MEM_BAR_SIZE 0x1000
#define AHCI_MAX_PORTS 32
diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index 335c060673..699f25824d 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -207,9 +207,9 @@ static void cmd646_set_irq(void *opaque, int channel, int level)
cmd646_update_irq(pd);
}
-static void cmd646_reset(void *opaque)
+static void cmd646_reset(DeviceState *dev)
{
- PCIIDEState *d = opaque;
+ PCIIDEState *d = PCI_IDE(dev);
unsigned int i;
for (i = 0; i < 2; i++) {
@@ -301,9 +301,6 @@ static void pci_cmd646_ide_realize(PCIDevice *dev, Error **errp)
ide_register_restart_cb(&d->bus[i]);
}
g_free(irq);
-
- vmstate_register(VMSTATE_IF(dev), 0, &vmstate_ide_pci, d);
- qemu_register_reset(cmd646_reset, d);
}
static void pci_cmd646_ide_exitfn(PCIDevice *dev)
@@ -317,18 +314,6 @@ static void pci_cmd646_ide_exitfn(PCIDevice *dev)
}
}
-void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
- int secondary_ide_enabled)
-{
- PCIDevice *dev;
-
- dev = pci_create(bus, -1, "cmd646-ide");
- qdev_prop_set_uint32(&dev->qdev, "secondary", secondary_ide_enabled);
- qdev_init_nofail(&dev->qdev);
-
- pci_ide_create_devs(dev, hd_table);
-}
-
static Property cmd646_ide_properties[] = {
DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0),
DEFINE_PROP_END_OF_LIST(),
@@ -339,6 +324,8 @@ static void cmd646_ide_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ dc->reset = cmd646_reset;
+ dc->vmsd = &vmstate_ide_pci;
k->realize = pci_cmd646_ide_realize;
k->exit = pci_cmd646_ide_exitfn;
k->vendor_id = PCI_VENDOR_ID_CMD;
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index 1a6a287e76..97347f07f1 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -476,17 +476,20 @@ const VMStateDescription vmstate_ide_pci = {
}
};
-void pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table)
+/* hd_table must contain 4 block drivers */
+void pci_ide_create_devs(PCIDevice *dev)
{
PCIIDEState *d = PCI_IDE(dev);
+ DriveInfo *hd_table[2 * MAX_IDE_DEVS];
static const int bus[4] = { 0, 0, 1, 1 };
static const int unit[4] = { 0, 1, 0, 1 };
int i;
+ ide_drive_get(hd_table, ARRAY_SIZE(hd_table));
for (i = 0; i < 4; i++) {
- if (hd_table[i] == NULL)
- continue;
- ide_create_drive(d->bus+bus[i], unit[i], hd_table[i]);
+ if (hd_table[i]) {
+ ide_create_drive(d->bus + bus[i], unit[i], hd_table[i]);
+ }
}
}
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index bc575b4d70..3b2de4c312 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -197,15 +197,6 @@ int pci_piix3_xen_ide_unplug(DeviceState *dev, bool aux)
return 0;
}
-PCIDevice *pci_piix3_xen_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
-{
- PCIDevice *dev;
-
- dev = pci_create_simple(bus, devfn, "piix3-ide-xen");
- pci_ide_create_devs(dev, hd_table);
- return dev;
-}
-
static void pci_piix_ide_exitfn(PCIDevice *dev)
{
PCIIDEState *d = PCI_IDE(dev);
@@ -217,28 +208,7 @@ static void pci_piix_ide_exitfn(PCIDevice *dev)
}
}
-/* hd_table must contain 4 block drivers */
/* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */
-PCIDevice *pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
-{
- PCIDevice *dev;
-
- dev = pci_create_simple(bus, devfn, "piix3-ide");
- pci_ide_create_devs(dev, hd_table);
- return dev;
-}
-
-/* hd_table must contain 4 block drivers */
-/* NOTE: for the PIIX4, the IRQs and IOports are hardcoded */
-PCIDevice *pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
-{
- PCIDevice *dev;
-
- dev = pci_create_simple(bus, devfn, "piix4-ide");
- pci_ide_create_devs(dev, hd_table);
- return dev;
-}
-
static void piix3_ide_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -266,6 +236,7 @@ static const TypeInfo piix3_ide_xen_info = {
.class_init = piix3_ide_class_init,
};
+/* NOTE: for the PIIX4, the IRQs and IOports are hardcoded */
static void piix4_ide_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/ide/via.c b/hw/ide/via.c
index 096de8dba0..8de4945cc1 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -113,10 +113,7 @@ static void via_ide_set_irq(void *opaque, int n, int level)
}
level = (d->config[0x70] & 0x80) || (d->config[0x78] & 0x80);
- n = pci_get_byte(d->config + PCI_INTERRUPT_LINE);
- if (n) {
- qemu_set_irq(isa_get_irq(NULL, n), level);
- }
+ qemu_set_irq(isa_get_irq(NULL, 14 + n), level);
}
static void via_ide_reset(DeviceState *dev)
@@ -167,9 +164,10 @@ static void via_ide_realize(PCIDevice *dev, Error **errp)
uint8_t *pci_conf = dev->config;
int i;
- pci_config_set_prog_interface(pci_conf, 0x8f); /* native PCI ATA mode */
+ pci_config_set_prog_interface(pci_conf, 0x8a); /* legacy mode */
pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0);
- dev->wmask[PCI_INTERRUPT_LINE] = 0xf;
+ dev->wmask[PCI_INTERRUPT_LINE] = 0;
+ dev->wmask[PCI_CLASS_PROG] = 5;
memory_region_init_io(&d->data_bar[0], OBJECT(d), &pci_ide_data_le_ops,
&d->bus[0], "via-ide0-data", 8);
@@ -190,8 +188,6 @@ static void via_ide_realize(PCIDevice *dev, Error **errp)
bmdma_setup_bar(d);
pci_register_bar(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar);
- vmstate_register(VMSTATE_IF(dev), 0, &vmstate_ide_pci, d);
-
for (i = 0; i < 2; i++) {
ide_bus_new(&d->bus[i], sizeof(d->bus[i]), DEVICE(d), i, 2);
ide_init2(&d->bus[i], qemu_allocate_irq(via_ide_set_irq, d, i));
@@ -213,20 +209,13 @@ static void via_ide_exitfn(PCIDevice *dev)
}
}
-void via_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
-{
- PCIDevice *dev;
-
- dev = pci_create_simple(bus, devfn, "via-ide");
- pci_ide_create_devs(dev, hd_table);
-}
-
static void via_ide_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
dc->reset = via_ide_reset;
+ dc->vmsd = &vmstate_ide_pci;
k->realize = via_ide_realize;
k->exit = via_ide_exitfn;
k->vendor_id = PCI_VENDOR_ID_VIA;
diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c
index 20c8155557..6608d7220a 100644
--- a/hw/intc/spapr_xive.c
+++ b/hw/intc/spapr_xive.c
@@ -677,8 +677,8 @@ static void spapr_xive_dt(SpaprInterruptController *intc, uint32_t nr_servers,
uint64_t timas[2 * 2];
/* Interrupt number ranges for the IPIs */
uint32_t lisn_ranges[] = {
- cpu_to_be32(0),
- cpu_to_be32(nr_servers),
+ cpu_to_be32(SPAPR_IRQ_IPI),
+ cpu_to_be32(SPAPR_IRQ_IPI + nr_servers),
};
/*
* EQ size - the sizes of pages supported by the system 4K, 64K,
diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c
index 7edec5e149..9a10fb9b3c 100644
--- a/hw/isa/piix4.c
+++ b/hw/isa/piix4.c
@@ -34,7 +34,7 @@
#include "hw/dma/i8257.h"
#include "hw/timer/i8254.h"
#include "hw/rtc/mc146818rtc.h"
-#include "hw/ide.h"
+#include "hw/ide/pci.h"
#include "migration/vmstate.h"
#include "sysemu/reset.h"
#include "sysemu/runstate.h"
@@ -240,28 +240,25 @@ static void piix4_register_types(void)
type_init(piix4_register_types)
-DeviceState *piix4_create(PCIBus *pci_bus, ISABus **isa_bus,
- I2CBus **smbus, size_t ide_buses)
+DeviceState *piix4_create(PCIBus *pci_bus, ISABus **isa_bus, I2CBus **smbus)
{
- size_t ide_drives = ide_buses * MAX_IDE_DEVS;
- DriveInfo **hd;
PCIDevice *pci;
DeviceState *dev;
+ int devfn = PCI_DEVFN(10, 0);
- pci = pci_create_simple_multifunction(pci_bus, PCI_DEVFN(10, 0),
- true, TYPE_PIIX4_PCI_DEVICE);
+ pci = pci_create_simple_multifunction(pci_bus, devfn, true,
+ TYPE_PIIX4_PCI_DEVICE);
dev = DEVICE(pci);
if (isa_bus) {
*isa_bus = ISA_BUS(qdev_get_child_bus(dev, "isa.0"));
}
- hd = g_new(DriveInfo *, ide_drives);
- ide_drive_get(hd, ide_drives);
- pci_piix4_ide_init(pci_bus, hd, pci->devfn + 1);
- g_free(hd);
- pci_create_simple(pci_bus, pci->devfn + 2, "piix4-usb-uhci");
+ pci = pci_create_simple(pci_bus, devfn + 1, "piix4-ide");
+ pci_ide_create_devs(pci);
+
+ pci_create_simple(pci_bus, devfn + 2, "piix4-usb-uhci");
if (smbus) {
- *smbus = piix4_pm_init(pci_bus, pci->devfn + 3, 0x1100,
+ *smbus = piix4_pm_init(pci_bus, devfn + 3, 0x1100,
isa_get_irq(NULL, 9), NULL, 0, NULL);
}
diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c
index 4727b1d3a4..5040afd581 100644
--- a/hw/mips/mips_fulong2e.c
+++ b/hw/mips/mips_fulong2e.c
@@ -36,7 +36,7 @@
#include "audio/audio.h"
#include "qemu/log.h"
#include "hw/loader.h"
-#include "hw/ide.h"
+#include "hw/ide/pci.h"
#include "elf.h"
#include "hw/isa/vt82c686.h"
#include "hw/rtc/mc146818rtc.h"
@@ -238,7 +238,7 @@ static void vt82c686b_southbridge_init(PCIBus *pci_bus, int slot, qemu_irq intc,
{
qemu_irq *i8259;
ISABus *isa_bus;
- DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+ PCIDevice *dev;
isa_bus = vt82c686b_isa_init(pci_bus, PCI_DEVFN(slot, 0));
if (!isa_bus) {
@@ -256,8 +256,8 @@ static void vt82c686b_southbridge_init(PCIBus *pci_bus, int slot, qemu_irq intc,
/* Super I/O */
isa_create_simple(isa_bus, TYPE_VT82C686B_SUPERIO);
- ide_drive_get(hd, ARRAY_SIZE(hd));
- via_ide_init(pci_bus, hd, PCI_DEVFN(slot, 1));
+ dev = pci_create_simple(pci_bus, PCI_DEVFN(slot, 1), "via-ide");
+ pci_ide_create_devs(dev);
pci_create_simple(pci_bus, PCI_DEVFN(slot, 2), "vt82c686b-usb-uhci");
pci_create_simple(pci_bus, PCI_DEVFN(slot, 3), "vt82c686b-usb-uhci");
diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index d380f73d7b..e4c4de1b4e 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -1403,7 +1403,7 @@ void mips_malta_init(MachineState *machine)
pci_bus = gt64120_register(s->i8259);
/* Southbridge */
- dev = piix4_create(pci_bus, &isa_bus, &smbus, MAX_IDE_BUS);
+ dev = piix4_create(pci_bus, &isa_bus, &smbus);
/* Interrupt controller */
qdev_connect_gpio_out_named(dev, "intr", 0, i8259_irq);
diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c
index ad8b75e286..3487013a4a 100644
--- a/hw/mips/mips_r4k.c
+++ b/hw/mips/mips_r4k.c
@@ -26,6 +26,7 @@
#include "qemu/log.h"
#include "hw/mips/bios.h"
#include "hw/ide.h"
+#include "hw/ide/internal.h"
#include "hw/loader.h"
#include "elf.h"
#include "hw/rtc/mc146818rtc.h"
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 1a0fad74e1..a8dc9b377d 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -832,7 +832,6 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
IVShmemState *s = IVSHMEM_COMMON(dev);
Error *err = NULL;
uint8_t *pci_conf;
- Error *local_err = NULL;
/* IRQFD requires MSI */
if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) &&
@@ -899,9 +898,9 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
if (!ivshmem_is_master(s)) {
error_setg(&s->migration_blocker,
"Migration is disabled when using feature 'peer mode' in device 'ivshmem'");
- migrate_add_blocker(s->migration_blocker, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ migrate_add_blocker(s->migration_blocker, &err);
+ if (err) {
+ error_propagate(errp, err);
error_free(s->migration_blocker);
return;
}
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index e1ed6677e1..b5bc842fac 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -302,8 +302,11 @@ static void pci_do_device_reset(PCIDevice *dev)
pci_word_test_and_clear_mask(dev->config + PCI_STATUS,
pci_get_word(dev->wmask + PCI_STATUS) |
pci_get_word(dev->w1cmask + PCI_STATUS));
+ /* Some devices make bits of PCI_INTERRUPT_LINE read only */
+ pci_byte_test_and_clear_mask(dev->config + PCI_INTERRUPT_LINE,
+ pci_get_word(dev->wmask + PCI_INTERRUPT_LINE) |
+ pci_get_word(dev->w1cmask + PCI_INTERRUPT_LINE));
dev->config[PCI_CACHE_LINE_SIZE] = 0x0;
- dev->config[PCI_INTERRUPT_LINE] = 0x0;
for (r = 0; r < PCI_NUM_REGIONS; ++r) {
PCIIORegion *region = &dev->io_regions[r];
if (!region->size) {
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index b2ec372958..428cf63578 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -62,7 +62,6 @@
#include "hw/char/escc.h"
#include "hw/misc/macio/macio.h"
#include "hw/ppc/openpic.h"
-#include "hw/ide.h"
#include "hw/loader.h"
#include "hw/fw-path-provider.h"
#include "elf.h"
diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c
index faaa165f3f..101bdc5c4d 100644
--- a/hw/ppc/mac_oldworld.c
+++ b/hw/ppc/mac_oldworld.c
@@ -41,7 +41,6 @@
#include "hw/nvram/fw_cfg.h"
#include "hw/char/escc.h"
#include "hw/misc/macio/macio.h"
-#include "hw/ide.h"
#include "hw/loader.h"
#include "hw/fw-path-provider.h"
#include "elf.h"
diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c
index f150deca34..b5ffa48dac 100644
--- a/hw/ppc/pnv_lpc.c
+++ b/hw/ppc/pnv_lpc.c
@@ -829,7 +829,7 @@ ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp)
bool hostboot_mode = !!pnv->fw_load_addr;
/* let isa_bus_new() create its own bridge on SysBus otherwise
- * devices speficied on the command line won't find the bus and
+ * devices specified on the command line won't find the bus and
* will fail to create.
*/
isa_bus = isa_bus_new(NULL, &lpc->isa_mem, &lpc->isa_io, &local_err);
diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c
index 111cc80867..44be9d25a2 100644
--- a/hw/ppc/prep.c
+++ b/hw/ppc/prep.c
@@ -37,7 +37,6 @@
#include "hw/boards.h"
#include "qemu/error-report.h"
#include "qemu/log.h"
-#include "hw/ide.h"
#include "hw/irq.h"
#include "hw/loader.h"
#include "hw/rtc/mc146818rtc.h"
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 41c0f2401f..9a2bd501aa 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -103,7 +103,7 @@
#define FW_OVERHEAD 0x2800000
#define KERNEL_LOAD_ADDR FW_MAX_SIZE
-#define MIN_RMA_SLOF 128UL
+#define MIN_RMA_SLOF (128 * MiB)
#define PHANDLE_INTC 0x00001111
@@ -217,10 +217,9 @@ static int spapr_fixup_cpu_numa_dt(void *fdt, int offset, PowerPCCPU *cpu)
sizeof(associativity));
}
-/* Populate the "ibm,pa-features" property */
-static void spapr_populate_pa_features(SpaprMachineState *spapr,
- PowerPCCPU *cpu,
- void *fdt, int offset)
+static void spapr_dt_pa_features(SpaprMachineState *spapr,
+ PowerPCCPU *cpu,
+ void *fdt, int offset)
{
uint8_t pa_features_206[] = { 6, 0,
0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 };
@@ -315,8 +314,8 @@ static void add_str(GString *s, const gchar *s1)
g_string_append_len(s, s1, strlen(s1) + 1);
}
-static int spapr_populate_memory_node(void *fdt, int nodeid, hwaddr start,
- hwaddr size)
+static int spapr_dt_memory_node(void *fdt, int nodeid, hwaddr start,
+ hwaddr size)
{
uint32_t associativity[] = {
cpu_to_be32(0x4), /* length */
@@ -341,257 +340,6 @@ static int spapr_populate_memory_node(void *fdt, int nodeid, hwaddr start,
return off;
}
-static int spapr_populate_memory(SpaprMachineState *spapr, void *fdt)
-{
- MachineState *machine = MACHINE(spapr);
- hwaddr mem_start, node_size;
- int i, nb_nodes = machine->numa_state->num_nodes;
- NodeInfo *nodes = machine->numa_state->nodes;
-
- for (i = 0, mem_start = 0; i < nb_nodes; ++i) {
- if (!nodes[i].node_mem) {
- continue;
- }
- if (mem_start >= machine->ram_size) {
- node_size = 0;
- } else {
- node_size = nodes[i].node_mem;
- if (node_size > machine->ram_size - mem_start) {
- node_size = machine->ram_size - mem_start;
- }
- }
- if (!mem_start) {
- /* spapr_machine_init() checks for rma_size <= node0_size
- * already */
- spapr_populate_memory_node(fdt, i, 0, spapr->rma_size);
- mem_start += spapr->rma_size;
- node_size -= spapr->rma_size;
- }
- for ( ; node_size; ) {
- hwaddr sizetmp = pow2floor(node_size);
-
- /* mem_start != 0 here */
- if (ctzl(mem_start) < ctzl(sizetmp)) {
- sizetmp = 1ULL << ctzl(mem_start);
- }
-
- spapr_populate_memory_node(fdt, i, mem_start, sizetmp);
- node_size -= sizetmp;
- mem_start += sizetmp;
- }
- }
-
- return 0;
-}
-
-static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
- SpaprMachineState *spapr)
-{
- MachineState *ms = MACHINE(spapr);
- PowerPCCPU *cpu = POWERPC_CPU(cs);
- CPUPPCState *env = &cpu->env;
- PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
- int index = spapr_get_vcpu_id(cpu);
- uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
- 0xffffffff, 0xffffffff};
- uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq()
- : SPAPR_TIMEBASE_FREQ;
- uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
- uint32_t page_sizes_prop[64];
- size_t page_sizes_prop_size;
- unsigned int smp_threads = ms->smp.threads;
- uint32_t vcpus_per_socket = smp_threads * ms->smp.cores;
- uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
- int compat_smt = MIN(smp_threads, ppc_compat_max_vthreads(cpu));
- SpaprDrc *drc;
- int drc_index;
- uint32_t radix_AP_encodings[PPC_PAGE_SIZES_MAX_SZ];
- int i;
-
- drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, index);
- if (drc) {
- drc_index = spapr_drc_index(drc);
- _FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index)));
- }
-
- _FDT((fdt_setprop_cell(fdt, offset, "reg", index)));
- _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
-
- _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
- _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
- env->dcache_line_size)));
- _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
- env->dcache_line_size)));
- _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
- env->icache_line_size)));
- _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
- env->icache_line_size)));
-
- if (pcc->l1_dcache_size) {
- _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
- pcc->l1_dcache_size)));
- } else {
- warn_report("Unknown L1 dcache size for cpu");
- }
- if (pcc->l1_icache_size) {
- _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
- pcc->l1_icache_size)));
- } else {
- warn_report("Unknown L1 icache size for cpu");
- }
-
- _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
- _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
- _FDT((fdt_setprop_cell(fdt, offset, "slb-size", cpu->hash64_opts->slb_size)));
- _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->slb_size)));
- _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
- _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
-
- if (env->spr_cb[SPR_PURR].oea_read) {
- _FDT((fdt_setprop_cell(fdt, offset, "ibm,purr", 1)));
- }
- if (env->spr_cb[SPR_SPURR].oea_read) {
- _FDT((fdt_setprop_cell(fdt, offset, "ibm,spurr", 1)));
- }
-
- if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) {
- _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
- segs, sizeof(segs))));
- }
-
- /* Advertise VSX (vector extensions) if available
- * 1 == VMX / Altivec available
- * 2 == VSX available
- *
- * Only CPUs for which we create core types in spapr_cpu_core.c
- * are possible, and all of those have VMX */
- if (spapr_get_cap(spapr, SPAPR_CAP_VSX) != 0) {
- _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 2)));
- } else {
- _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 1)));
- }
-
- /* Advertise DFP (Decimal Floating Point) if available
- * 0 / no property == no DFP
- * 1 == DFP available */
- if (spapr_get_cap(spapr, SPAPR_CAP_DFP) != 0) {
- _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
- }
-
- page_sizes_prop_size = ppc_create_page_sizes_prop(cpu, page_sizes_prop,
- sizeof(page_sizes_prop));
- if (page_sizes_prop_size) {
- _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
- page_sizes_prop, page_sizes_prop_size)));
- }
-
- spapr_populate_pa_features(spapr, cpu, fdt, offset);
-
- _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
- cs->cpu_index / vcpus_per_socket)));
-
- _FDT((fdt_setprop(fdt, offset, "ibm,pft-size",
- pft_size_prop, sizeof(pft_size_prop))));
-
- if (ms->numa_state->num_nodes > 1) {
- _FDT(spapr_fixup_cpu_numa_dt(fdt, offset, cpu));
- }
-
- _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt));
-
- if (pcc->radix_page_info) {
- for (i = 0; i < pcc->radix_page_info->count; i++) {
- radix_AP_encodings[i] =
- cpu_to_be32(pcc->radix_page_info->entries[i]);
- }
- _FDT((fdt_setprop(fdt, offset, "ibm,processor-radix-AP-encodings",
- radix_AP_encodings,
- pcc->radix_page_info->count *
- sizeof(radix_AP_encodings[0]))));
- }
-
- /*
- * We set this property to let the guest know that it can use the large
- * decrementer and its width in bits.
- */
- if (spapr_get_cap(spapr, SPAPR_CAP_LARGE_DECREMENTER) != SPAPR_CAP_OFF)
- _FDT((fdt_setprop_u32(fdt, offset, "ibm,dec-bits",
- pcc->lrg_decr_bits)));
-}
-
-static void spapr_populate_cpus_dt_node(void *fdt, SpaprMachineState *spapr)
-{
- CPUState **rev;
- CPUState *cs;
- int n_cpus;
- int cpus_offset;
- char *nodename;
- int i;
-
- cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
- _FDT(cpus_offset);
- _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
- _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
-
- /*
- * We walk the CPUs in reverse order to ensure that CPU DT nodes
- * created by fdt_add_subnode() end up in the right order in FDT
- * for the guest kernel the enumerate the CPUs correctly.
- *
- * The CPU list cannot be traversed in reverse order, so we need
- * to do extra work.
- */
- n_cpus = 0;
- rev = NULL;
- CPU_FOREACH(cs) {
- rev = g_renew(CPUState *, rev, n_cpus + 1);
- rev[n_cpus++] = cs;
- }
-
- for (i = n_cpus - 1; i >= 0; i--) {
- CPUState *cs = rev[i];
- PowerPCCPU *cpu = POWERPC_CPU(cs);
- int index = spapr_get_vcpu_id(cpu);
- DeviceClass *dc = DEVICE_GET_CLASS(cs);
- int offset;
-
- if (!spapr_is_thread0_in_vcore(spapr, cpu)) {
- continue;
- }
-
- nodename = g_strdup_printf("%s@%x", dc->fw_name, index);
- offset = fdt_add_subnode(fdt, cpus_offset, nodename);
- g_free(nodename);
- _FDT(offset);
- spapr_populate_cpu_dt(cs, fdt, offset, spapr);
- }
-
- g_free(rev);
-}
-
-static int spapr_rng_populate_dt(void *fdt)
-{
- int node;
- int ret;
-
- node = qemu_fdt_add_subnode(fdt, "/ibm,platform-facilities");
- if (node <= 0) {
- return -1;
- }
- ret = fdt_setprop_string(fdt, node, "device_type",
- "ibm,platform-facilities");
- ret |= fdt_setprop_cell(fdt, node, "#address-cells", 0x1);
- ret |= fdt_setprop_cell(fdt, node, "#size-cells", 0x0);
-
- node = fdt_add_subnode(fdt, node, "ibm,random-v1");
- if (node <= 0) {
- return -1;
- }
- ret |= fdt_setprop_string(fdt, node, "compatible", "ibm,random");
-
- return ret ? -1 : 0;
-}
-
static uint32_t spapr_pc_dimm_node(MemoryDeviceInfoList *list, ram_addr_t addr)
{
MemoryDeviceInfoList *info;
@@ -642,9 +390,8 @@ spapr_get_drconf_cell(uint32_t seq_lmbs, uint64_t base_addr,
return elem;
}
-/* ibm,dynamic-memory-v2 */
-static int spapr_populate_drmem_v2(SpaprMachineState *spapr, void *fdt,
- int offset, MemoryDeviceInfoList *dimms)
+static int spapr_dt_dynamic_memory_v2(SpaprMachineState *spapr, void *fdt,
+ int offset, MemoryDeviceInfoList *dimms)
{
MachineState *machine = MACHINE(spapr);
uint8_t *int_buf, *cur_index;
@@ -735,8 +482,7 @@ static int spapr_populate_drmem_v2(SpaprMachineState *spapr, void *fdt,
return 0;
}
-/* ibm,dynamic-memory */
-static int spapr_populate_drmem_v1(SpaprMachineState *spapr, void *fdt,
+static int spapr_dt_dynamic_memory(SpaprMachineState *spapr, void *fdt,
int offset, MemoryDeviceInfoList *dimms)
{
MachineState *machine = MACHINE(spapr);
@@ -805,7 +551,8 @@ static int spapr_populate_drmem_v1(SpaprMachineState *spapr, void *fdt,
* Refer to docs/specs/ppc-spapr-hotplug.txt for the documentation
* of this device tree node.
*/
-static int spapr_populate_drconf_memory(SpaprMachineState *spapr, void *fdt)
+static int spapr_dt_dynamic_reconfiguration_memory(SpaprMachineState *spapr,
+ void *fdt)
{
MachineState *machine = MACHINE(spapr);
int nb_numa_nodes = machine->numa_state->num_nodes;
@@ -844,9 +591,9 @@ static int spapr_populate_drconf_memory(SpaprMachineState *spapr, void *fdt)
/* ibm,dynamic-memory or ibm,dynamic-memory-v2 */
dimms = qmp_memory_device_list();
if (spapr_ovec_test(spapr->ov5_cas, OV5_DRMEM_V2)) {
- ret = spapr_populate_drmem_v2(spapr, fdt, offset, dimms);
+ ret = spapr_dt_dynamic_memory_v2(spapr, fdt, offset, dimms);
} else {
- ret = spapr_populate_drmem_v1(spapr, fdt, offset, dimms);
+ ret = spapr_dt_dynamic_memory(spapr, fdt, offset, dimms);
}
qapi_free_MemoryDeviceInfoList(dimms);
@@ -877,30 +624,267 @@ static int spapr_populate_drconf_memory(SpaprMachineState *spapr, void *fdt)
return ret;
}
-static int spapr_dt_cas_updates(SpaprMachineState *spapr, void *fdt,
- SpaprOptionVector *ov5_updates)
+static int spapr_dt_memory(SpaprMachineState *spapr, void *fdt)
{
+ MachineState *machine = MACHINE(spapr);
SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
- int ret = 0, offset;
+ hwaddr mem_start, node_size;
+ int i, nb_nodes = machine->numa_state->num_nodes;
+ NodeInfo *nodes = machine->numa_state->nodes;
+
+ for (i = 0, mem_start = 0; i < nb_nodes; ++i) {
+ if (!nodes[i].node_mem) {
+ continue;
+ }
+ if (mem_start >= machine->ram_size) {
+ node_size = 0;
+ } else {
+ node_size = nodes[i].node_mem;
+ if (node_size > machine->ram_size - mem_start) {
+ node_size = machine->ram_size - mem_start;
+ }
+ }
+ if (!mem_start) {
+ /* spapr_machine_init() checks for rma_size <= node0_size
+ * already */
+ spapr_dt_memory_node(fdt, i, 0, spapr->rma_size);
+ mem_start += spapr->rma_size;
+ node_size -= spapr->rma_size;
+ }
+ for ( ; node_size; ) {
+ hwaddr sizetmp = pow2floor(node_size);
+
+ /* mem_start != 0 here */
+ if (ctzl(mem_start) < ctzl(sizetmp)) {
+ sizetmp = 1ULL << ctzl(mem_start);
+ }
+
+ spapr_dt_memory_node(fdt, i, mem_start, sizetmp);
+ node_size -= sizetmp;
+ mem_start += sizetmp;
+ }
+ }
/* Generate ibm,dynamic-reconfiguration-memory node if required */
- if (spapr_ovec_test(ov5_updates, OV5_DRCONF_MEMORY)) {
+ if (spapr_ovec_test(spapr->ov5_cas, OV5_DRCONF_MEMORY)) {
+ int ret;
+
g_assert(smc->dr_lmb_enabled);
- ret = spapr_populate_drconf_memory(spapr, fdt);
+ ret = spapr_dt_dynamic_reconfiguration_memory(spapr, fdt);
if (ret) {
return ret;
}
}
- offset = fdt_path_offset(fdt, "/chosen");
- if (offset < 0) {
- offset = fdt_add_subnode(fdt, 0, "chosen");
- if (offset < 0) {
- return offset;
+ return 0;
+}
+
+static void spapr_dt_cpu(CPUState *cs, void *fdt, int offset,
+ SpaprMachineState *spapr)
+{
+ MachineState *ms = MACHINE(spapr);
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
+ int index = spapr_get_vcpu_id(cpu);
+ uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
+ 0xffffffff, 0xffffffff};
+ uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq()
+ : SPAPR_TIMEBASE_FREQ;
+ uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
+ uint32_t page_sizes_prop[64];
+ size_t page_sizes_prop_size;
+ unsigned int smp_threads = ms->smp.threads;
+ uint32_t vcpus_per_socket = smp_threads * ms->smp.cores;
+ uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
+ int compat_smt = MIN(smp_threads, ppc_compat_max_vthreads(cpu));
+ SpaprDrc *drc;
+ int drc_index;
+ uint32_t radix_AP_encodings[PPC_PAGE_SIZES_MAX_SZ];
+ int i;
+
+ drc = spapr_drc_by_id(TYPE_SPAPR_DRC_CPU, index);
+ if (drc) {
+ drc_index = spapr_drc_index(drc);
+ _FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index)));
+ }
+
+ _FDT((fdt_setprop_cell(fdt, offset, "reg", index)));
+ _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
+
+ _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
+ _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
+ env->dcache_line_size)));
+ _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
+ env->dcache_line_size)));
+ _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
+ env->icache_line_size)));
+ _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
+ env->icache_line_size)));
+
+ if (pcc->l1_dcache_size) {
+ _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
+ pcc->l1_dcache_size)));
+ } else {
+ warn_report("Unknown L1 dcache size for cpu");
+ }
+ if (pcc->l1_icache_size) {
+ _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
+ pcc->l1_icache_size)));
+ } else {
+ warn_report("Unknown L1 icache size for cpu");
+ }
+
+ _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
+ _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
+ _FDT((fdt_setprop_cell(fdt, offset, "slb-size", cpu->hash64_opts->slb_size)));
+ _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->slb_size)));
+ _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
+ _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
+
+ if (env->spr_cb[SPR_PURR].oea_read) {
+ _FDT((fdt_setprop_cell(fdt, offset, "ibm,purr", 1)));
+ }
+ if (env->spr_cb[SPR_SPURR].oea_read) {
+ _FDT((fdt_setprop_cell(fdt, offset, "ibm,spurr", 1)));
+ }
+
+ if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)) {
+ _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
+ segs, sizeof(segs))));
+ }
+
+ /* Advertise VSX (vector extensions) if available
+ * 1 == VMX / Altivec available
+ * 2 == VSX available
+ *
+ * Only CPUs for which we create core types in spapr_cpu_core.c
+ * are possible, and all of those have VMX */
+ if (spapr_get_cap(spapr, SPAPR_CAP_VSX) != 0) {
+ _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 2)));
+ } else {
+ _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", 1)));
+ }
+
+ /* Advertise DFP (Decimal Floating Point) if available
+ * 0 / no property == no DFP
+ * 1 == DFP available */
+ if (spapr_get_cap(spapr, SPAPR_CAP_DFP) != 0) {
+ _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
+ }
+
+ page_sizes_prop_size = ppc_create_page_sizes_prop(cpu, page_sizes_prop,
+ sizeof(page_sizes_prop));
+ if (page_sizes_prop_size) {
+ _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
+ page_sizes_prop, page_sizes_prop_size)));
+ }
+
+ spapr_dt_pa_features(spapr, cpu, fdt, offset);
+
+ _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
+ cs->cpu_index / vcpus_per_socket)));
+
+ _FDT((fdt_setprop(fdt, offset, "ibm,pft-size",
+ pft_size_prop, sizeof(pft_size_prop))));
+
+ if (ms->numa_state->num_nodes > 1) {
+ _FDT(spapr_fixup_cpu_numa_dt(fdt, offset, cpu));
+ }
+
+ _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt));
+
+ if (pcc->radix_page_info) {
+ for (i = 0; i < pcc->radix_page_info->count; i++) {
+ radix_AP_encodings[i] =
+ cpu_to_be32(pcc->radix_page_info->entries[i]);
}
+ _FDT((fdt_setprop(fdt, offset, "ibm,processor-radix-AP-encodings",
+ radix_AP_encodings,
+ pcc->radix_page_info->count *
+ sizeof(radix_AP_encodings[0]))));
}
- return spapr_ovec_populate_dt(fdt, offset, spapr->ov5_cas,
- "ibm,architecture-vec-5");
+
+ /*
+ * We set this property to let the guest know that it can use the large
+ * decrementer and its width in bits.
+ */
+ if (spapr_get_cap(spapr, SPAPR_CAP_LARGE_DECREMENTER) != SPAPR_CAP_OFF)
+ _FDT((fdt_setprop_u32(fdt, offset, "ibm,dec-bits",
+ pcc->lrg_decr_bits)));
+}
+
+static void spapr_dt_cpus(void *fdt, SpaprMachineState *spapr)
+{
+ CPUState **rev;
+ CPUState *cs;
+ int n_cpus;
+ int cpus_offset;
+ char *nodename;
+ int i;
+
+ cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
+ _FDT(cpus_offset);
+ _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
+ _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
+
+ /*
+ * We walk the CPUs in reverse order to ensure that CPU DT nodes
+ * created by fdt_add_subnode() end up in the right order in FDT
+ * for the guest kernel the enumerate the CPUs correctly.
+ *
+ * The CPU list cannot be traversed in reverse order, so we need
+ * to do extra work.
+ */
+ n_cpus = 0;
+ rev = NULL;
+ CPU_FOREACH(cs) {
+ rev = g_renew(CPUState *, rev, n_cpus + 1);
+ rev[n_cpus++] = cs;
+ }
+
+ for (i = n_cpus - 1; i >= 0; i--) {
+ CPUState *cs = rev[i];
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ int index = spapr_get_vcpu_id(cpu);
+ DeviceClass *dc = DEVICE_GET_CLASS(cs);
+ int offset;
+
+ if (!spapr_is_thread0_in_vcore(spapr, cpu)) {
+ continue;
+ }
+
+ nodename = g_strdup_printf("%s@%x", dc->fw_name, index);
+ offset = fdt_add_subnode(fdt, cpus_offset, nodename);
+ g_free(nodename);
+ _FDT(offset);
+ spapr_dt_cpu(cs, fdt, offset, spapr);
+ }
+
+ g_free(rev);
+}
+
+static int spapr_dt_rng(void *fdt)
+{
+ int node;
+ int ret;
+
+ node = qemu_fdt_add_subnode(fdt, "/ibm,platform-facilities");
+ if (node <= 0) {
+ return -1;
+ }
+ ret = fdt_setprop_string(fdt, node, "device_type",
+ "ibm,platform-facilities");
+ ret |= fdt_setprop_cell(fdt, node, "#address-cells", 0x1);
+ ret |= fdt_setprop_cell(fdt, node, "#size-cells", 0x0);
+
+ node = fdt_add_subnode(fdt, node, "ibm,random-v1");
+ if (node <= 0) {
+ return -1;
+ }
+ ret |= fdt_setprop_string(fdt, node, "compatible", "ibm,random");
+
+ return ret ? -1 : 0;
}
static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt)
@@ -967,6 +951,29 @@ static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt)
_FDT(fdt_setprop(fdt, rtas, "ibm,max-associativity-domains",
maxdomains, sizeof(maxdomains)));
+ /*
+ * FWNMI reserves RTAS_ERROR_LOG_MAX for the machine check error log,
+ * and 16 bytes per CPU for system reset error log plus an extra 8 bytes.
+ *
+ * The system reset requirements are driven by existing Linux and PowerVM
+ * implementation which (contrary to PAPR) saves r3 in the error log
+ * structure like machine check, so Linux expects to find the saved r3
+ * value at the address in r3 upon FWNMI-enabled sreset interrupt (and
+ * does not look at the error value).
+ *
+ * System reset interrupts are not subject to interlock like machine
+ * check, so this memory area could be corrupted if the sreset is
+ * interrupted by a machine check (or vice versa) if it was shared. To
+ * prevent this, system reset uses per-CPU areas for the sreset save
+ * area. A system reset that interrupts a system reset handler could
+ * still overwrite this area, but Linux doesn't try to recover in that
+ * case anyway.
+ *
+ * The extra 8 bytes is required because Linux's FWNMI error log check
+ * is off-by-one.
+ */
+ _FDT(fdt_setprop_cell(fdt, rtas, "rtas-size", RTAS_ERROR_LOG_MAX +
+ ms->smp.max_cpus * sizeof(uint64_t)*2 + sizeof(uint64_t)));
_FDT(fdt_setprop_cell(fdt, rtas, "rtas-error-log-max",
RTAS_ERROR_LOG_MAX));
_FDT(fdt_setprop_cell(fdt, rtas, "rtas-event-scan-rate",
@@ -1040,81 +1047,91 @@ static void spapr_dt_ov5_platform_support(SpaprMachineState *spapr, void *fdt,
val, sizeof(val)));
}
-static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt)
+static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt, bool reset)
{
MachineState *machine = MACHINE(spapr);
SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
int chosen;
- const char *boot_device = machine->boot_order;
- char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus);
- size_t cb = 0;
- char *bootlist = get_boot_devices_list(&cb);
_FDT(chosen = fdt_add_subnode(fdt, 0, "chosen"));
- if (machine->kernel_cmdline && machine->kernel_cmdline[0]) {
- _FDT(fdt_setprop_string(fdt, chosen, "bootargs",
- machine->kernel_cmdline));
- }
- if (spapr->initrd_size) {
- _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-start",
- spapr->initrd_base));
- _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-end",
- spapr->initrd_base + spapr->initrd_size));
- }
+ if (reset) {
+ const char *boot_device = machine->boot_order;
+ char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus);
+ size_t cb = 0;
+ char *bootlist = get_boot_devices_list(&cb);
+
+ if (machine->kernel_cmdline && machine->kernel_cmdline[0]) {
+ _FDT(fdt_setprop_string(fdt, chosen, "bootargs",
+ machine->kernel_cmdline));
+ }
- if (spapr->kernel_size) {
- uint64_t kprop[2] = { cpu_to_be64(spapr->kernel_addr),
- cpu_to_be64(spapr->kernel_size) };
+ if (spapr->initrd_size) {
+ _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-start",
+ spapr->initrd_base));
+ _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-end",
+ spapr->initrd_base + spapr->initrd_size));
+ }
+
+ if (spapr->kernel_size) {
+ uint64_t kprop[2] = { cpu_to_be64(spapr->kernel_addr),
+ cpu_to_be64(spapr->kernel_size) };
- _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel",
+ _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel",
&kprop, sizeof(kprop)));
- if (spapr->kernel_le) {
- _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel-le", NULL, 0));
+ if (spapr->kernel_le) {
+ _FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel-le", NULL, 0));
+ }
}
- }
- if (boot_menu) {
- _FDT((fdt_setprop_cell(fdt, chosen, "qemu,boot-menu", boot_menu)));
- }
- _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-width", graphic_width));
- _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-height", graphic_height));
- _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-depth", graphic_depth));
+ if (boot_menu) {
+ _FDT((fdt_setprop_cell(fdt, chosen, "qemu,boot-menu", boot_menu)));
+ }
+ _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-width", graphic_width));
+ _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-height", graphic_height));
+ _FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-depth", graphic_depth));
- if (cb && bootlist) {
- int i;
+ if (cb && bootlist) {
+ int i;
- for (i = 0; i < cb; i++) {
- if (bootlist[i] == '\n') {
- bootlist[i] = ' ';
+ for (i = 0; i < cb; i++) {
+ if (bootlist[i] == '\n') {
+ bootlist[i] = ' ';
+ }
}
+ _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-list", bootlist));
}
- _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-list", bootlist));
- }
- if (boot_device && strlen(boot_device)) {
- _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-device", boot_device));
- }
+ if (boot_device && strlen(boot_device)) {
+ _FDT(fdt_setprop_string(fdt, chosen, "qemu,boot-device", boot_device));
+ }
+
+ if (!spapr->has_graphics && stdout_path) {
+ /*
+ * "linux,stdout-path" and "stdout" properties are
+ * deprecated by linux kernel. New platforms should only
+ * use the "stdout-path" property. Set the new property
+ * and continue using older property to remain compatible
+ * with the existing firmware.
+ */
+ _FDT(fdt_setprop_string(fdt, chosen, "linux,stdout-path", stdout_path));
+ _FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path));
+ }
- if (!spapr->has_graphics && stdout_path) {
/*
- * "linux,stdout-path" and "stdout" properties are deprecated by linux
- * kernel. New platforms should only use the "stdout-path" property. Set
- * the new property and continue using older property to remain
- * compatible with the existing firmware.
+ * We can deal with BAR reallocation just fine, advertise it
+ * to the guest
*/
- _FDT(fdt_setprop_string(fdt, chosen, "linux,stdout-path", stdout_path));
- _FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path));
- }
+ if (smc->linux_pci_probe) {
+ _FDT(fdt_setprop_cell(fdt, chosen, "linux,pci-probe-only", 0));
+ }
- /* We can deal with BAR reallocation just fine, advertise it to the guest */
- if (smc->linux_pci_probe) {
- _FDT(fdt_setprop_cell(fdt, chosen, "linux,pci-probe-only", 0));
- }
+ spapr_dt_ov5_platform_support(spapr, fdt, chosen);
- spapr_dt_ov5_platform_support(spapr, fdt, chosen);
+ g_free(stdout_path);
+ g_free(bootlist);
+ }
- g_free(stdout_path);
- g_free(bootlist);
+ _FDT(spapr_dt_ovec(fdt, chosen, spapr->ov5_cas, "ibm,architecture-vec-5"));
}
static void spapr_dt_hypervisor(SpaprMachineState *spapr, void *fdt)
@@ -1192,7 +1209,7 @@ void *spapr_build_fdt(SpaprMachineState *spapr, bool reset, size_t space)
/* /interrupt controller */
spapr_irq_dt(spapr, spapr_max_server_number(spapr), fdt, PHANDLE_INTC);
- ret = spapr_populate_memory(spapr, fdt);
+ ret = spapr_dt_memory(spapr, fdt);
if (ret < 0) {
error_report("couldn't setup memory nodes in fdt");
exit(1);
@@ -1202,7 +1219,7 @@ void *spapr_build_fdt(SpaprMachineState *spapr, bool reset, size_t space)
spapr_dt_vdevice(spapr->vio_bus, fdt);
if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL)) {
- ret = spapr_rng_populate_dt(fdt);
+ ret = spapr_dt_rng(fdt);
if (ret < 0) {
error_report("could not set up rng device in the fdt");
exit(1);
@@ -1217,8 +1234,7 @@ void *spapr_build_fdt(SpaprMachineState *spapr, bool reset, size_t space)
}
}
- /* cpus */
- spapr_populate_cpus_dt_node(fdt, spapr);
+ spapr_dt_cpus(fdt, spapr);
if (smc->dr_lmb_enabled) {
_FDT(spapr_dt_drc(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_LMB));
@@ -1240,9 +1256,7 @@ void *spapr_build_fdt(SpaprMachineState *spapr, bool reset, size_t space)
spapr_dt_rtas(spapr, fdt);
/* /chosen */
- if (reset) {
- spapr_dt_chosen(spapr, fdt);
- }
+ spapr_dt_chosen(spapr, fdt, reset);
/* /hypervisor */
if (kvm_enabled()) {
@@ -1261,13 +1275,6 @@ void *spapr_build_fdt(SpaprMachineState *spapr, bool reset, size_t space)
}
}
- /* ibm,client-architecture-support updates */
- ret = spapr_dt_cas_updates(spapr, fdt, spapr->ov5_cas);
- if (ret < 0) {
- error_report("couldn't setup CAS properties fdt");
- exit(1);
- }
-
if (smc->dr_phb_enabled) {
ret = spapr_dt_drc(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_PHB);
if (ret < 0) {
@@ -1569,7 +1576,7 @@ void spapr_reallocate_hpt(SpaprMachineState *spapr, int shift,
spapr_set_all_lpcrs(0, LPCR_HR | LPCR_UPRT);
}
-void spapr_setup_hpt_and_vrma(SpaprMachineState *spapr)
+void spapr_setup_hpt(SpaprMachineState *spapr)
{
int hpt_shift;
@@ -1585,9 +1592,16 @@ void spapr_setup_hpt_and_vrma(SpaprMachineState *spapr)
}
spapr_reallocate_hpt(spapr, hpt_shift, &error_fatal);
- if (spapr->vrma_adjust) {
- spapr->rma_size = kvmppc_rma_size(spapr_node0_size(MACHINE(spapr)),
- spapr->htab_shift);
+ if (kvm_enabled()) {
+ hwaddr vrma_limit = kvmppc_vrma_limit(spapr->htab_shift);
+
+ /* Check our RMA fits in the possible VRMA */
+ if (vrma_limit < spapr->rma_size) {
+ error_report("Unable to create %" HWADDR_PRIu
+ "MiB RMA (VRMA only allows %" HWADDR_PRIu "MiB",
+ spapr->rma_size / MiB, vrma_limit / MiB);
+ exit(EXIT_FAILURE);
+ }
}
}
@@ -1627,7 +1641,7 @@ static void spapr_machine_reset(MachineState *machine)
spapr->patb_entry = PATE1_GR;
spapr_set_all_lpcrs(LPCR_HR | LPCR_UPRT, LPCR_HR | LPCR_UPRT);
} else {
- spapr_setup_hpt_and_vrma(spapr);
+ spapr_setup_hpt(spapr);
}
qemu_devices_reset();
@@ -1691,16 +1705,17 @@ static void spapr_machine_reset(MachineState *machine)
spapr->fdt_blob = fdt;
/* Set up the entry state */
- spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT, fdt_addr);
+ spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT, 0, fdt_addr, 0);
first_ppc_cpu->env.gpr[5] = 0;
spapr->cas_reboot = false;
- spapr->mc_status = -1;
- spapr->guest_machine_check_addr = -1;
+ spapr->fwnmi_system_reset_addr = -1;
+ spapr->fwnmi_machine_check_addr = -1;
+ spapr->fwnmi_machine_check_interlock = -1;
/* Signal all vCPUs waiting on this condition */
- qemu_cond_broadcast(&spapr->mc_delivery_cond);
+ qemu_cond_broadcast(&spapr->fwnmi_machine_check_interlock_cond);
migrate_del_blocker(spapr->fwnmi_migration_blocker);
}
@@ -1989,7 +2004,7 @@ static bool spapr_fwnmi_needed(void *opaque)
{
SpaprMachineState *spapr = (SpaprMachineState *)opaque;
- return spapr->guest_machine_check_addr != -1;
+ return spapr->fwnmi_machine_check_addr != -1;
}
static int spapr_fwnmi_pre_save(void *opaque)
@@ -2000,7 +2015,7 @@ static int spapr_fwnmi_pre_save(void *opaque)
* Check if machine check handling is in progress and print a
* warning message.
*/
- if (spapr->mc_status != -1) {
+ if (spapr->fwnmi_machine_check_interlock != -1) {
warn_report("A machine check is being handled during migration. The"
"handler may run and log hardware error on the destination");
}
@@ -2008,15 +2023,16 @@ static int spapr_fwnmi_pre_save(void *opaque)
return 0;
}
-static const VMStateDescription vmstate_spapr_machine_check = {
- .name = "spapr_machine_check",
+static const VMStateDescription vmstate_spapr_fwnmi = {
+ .name = "spapr_fwnmi",
.version_id = 1,
.minimum_version_id = 1,
.needed = spapr_fwnmi_needed,
.pre_save = spapr_fwnmi_pre_save,
.fields = (VMStateField[]) {
- VMSTATE_UINT64(guest_machine_check_addr, SpaprMachineState),
- VMSTATE_INT32(mc_status, SpaprMachineState),
+ VMSTATE_UINT64(fwnmi_system_reset_addr, SpaprMachineState),
+ VMSTATE_UINT64(fwnmi_machine_check_addr, SpaprMachineState),
+ VMSTATE_INT32(fwnmi_machine_check_interlock, SpaprMachineState),
VMSTATE_END_OF_LIST()
},
};
@@ -2055,7 +2071,7 @@ static const VMStateDescription vmstate_spapr = {
&vmstate_spapr_cap_large_decr,
&vmstate_spapr_cap_ccf_assist,
&vmstate_spapr_cap_fwnmi,
- &vmstate_spapr_machine_check,
+ &vmstate_spapr_fwnmi,
NULL
}
};
@@ -2641,6 +2657,42 @@ static PCIHostState *spapr_create_default_phb(void)
return PCI_HOST_BRIDGE(dev);
}
+static hwaddr spapr_rma_size(SpaprMachineState *spapr, Error **errp)
+{
+ MachineState *machine = MACHINE(spapr);
+ SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
+ hwaddr rma_size = machine->ram_size;
+ hwaddr node0_size = spapr_node0_size(machine);
+
+ /* RMA has to fit in the first NUMA node */
+ rma_size = MIN(rma_size, node0_size);
+
+ /*
+ * VRMA access is via a special 1TiB SLB mapping, so the RMA can
+ * never exceed that
+ */
+ rma_size = MIN(rma_size, 1 * TiB);
+
+ /*
+ * Clamp the RMA size based on machine type. This is for
+ * migration compatibility with older qemu versions, which limited
+ * the RMA size for complicated and mostly bad reasons.
+ */
+ if (smc->rma_limit) {
+ rma_size = MIN(rma_size, smc->rma_limit);
+ }
+
+ if (rma_size < MIN_RMA_SLOF) {
+ error_setg(errp,
+ "pSeries SLOF firmware requires >= %" HWADDR_PRIx
+ "ldMiB guest RMA (Real Mode Area memory)",
+ MIN_RMA_SLOF / MiB);
+ return 0;
+ }
+
+ return rma_size;
+}
+
/* pSeries LPAR / sPAPR hardware init */
static void spapr_machine_init(MachineState *machine)
{
@@ -2652,7 +2704,6 @@ static void spapr_machine_init(MachineState *machine)
PCIHostState *phb;
int i;
MemoryRegion *sysmem = get_system_memory();
- hwaddr node0_size = spapr_node0_size(machine);
long load_limit, fw_size;
char *filename;
Error *resize_hpt_err = NULL;
@@ -2692,34 +2743,7 @@ static void spapr_machine_init(MachineState *machine)
exit(1);
}
- spapr->rma_size = node0_size;
-
- /* With KVM, we don't actually know whether KVM supports an
- * unbounded RMA (PR KVM) or is limited by the hash table size
- * (HV KVM using VRMA), so we always assume the latter
- *
- * In that case, we also limit the initial allocations for RTAS
- * etc... to 256M since we have no way to know what the VRMA size
- * is going to be as it depends on the size of the hash table
- * which isn't determined yet.
- */
- if (kvm_enabled()) {
- spapr->vrma_adjust = 1;
- spapr->rma_size = MIN(spapr->rma_size, 0x10000000);
- }
-
- /* Actually we don't support unbounded RMA anymore since we added
- * proper emulation of HV mode. The max we can get is 16G which
- * also happens to be what we configure for PAPR mode so make sure
- * we don't do anything bigger than that
- */
- spapr->rma_size = MIN(spapr->rma_size, 0x400000000ull);
-
- if (spapr->rma_size > node0_size) {
- error_report("Numa node 0 has to span the RMA (%#08"HWADDR_PRIx")",
- spapr->rma_size);
- exit(1);
- }
+ spapr->rma_size = spapr_rma_size(spapr, &error_fatal);
/* Setup a load limit for the ramdisk leaving room for SLOF and FDT */
load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD;
@@ -2869,7 +2893,7 @@ static void spapr_machine_init(MachineState *machine)
spapr_create_lmb_dr_connectors(spapr);
}
- if (spapr_get_cap(spapr, SPAPR_CAP_FWNMI_MCE) == SPAPR_CAP_ON) {
+ if (spapr_get_cap(spapr, SPAPR_CAP_FWNMI) == SPAPR_CAP_ON) {
/* Create the error string for live migration blocker */
error_setg(&spapr->fwnmi_migration_blocker,
"A machine check is being handled during migration. The handler"
@@ -2956,13 +2980,6 @@ static void spapr_machine_init(MachineState *machine)
}
}
- if (spapr->rma_size < (MIN_RMA_SLOF * MiB)) {
- error_report(
- "pSeries SLOF firmware requires >= %ldM guest RMA (Real Mode Area memory)",
- MIN_RMA_SLOF);
- exit(1);
- }
-
if (kernel_filename) {
uint64_t lowaddr = 0;
@@ -3045,7 +3062,7 @@ static void spapr_machine_init(MachineState *machine)
kvmppc_spapr_enable_inkernel_multitce();
}
- qemu_cond_init(&spapr->mc_delivery_cond);
+ qemu_cond_init(&spapr->fwnmi_machine_check_interlock_cond);
}
static int spapr_kvm_type(MachineState *machine, const char *vm_type)
@@ -3367,8 +3384,28 @@ static void spapr_machine_finalizefn(Object *obj)
void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg)
{
+ SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
+
cpu_synchronize_state(cs);
- ppc_cpu_do_system_reset(cs);
+ /* If FWNMI is inactive, addr will be -1, which will deliver to 0x100 */
+ if (spapr->fwnmi_system_reset_addr != -1) {
+ uint64_t rtas_addr, addr;
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+
+ /* get rtas addr from fdt */
+ rtas_addr = spapr_get_rtas_addr();
+ if (!rtas_addr) {
+ qemu_system_guest_panicked(NULL);
+ return;
+ }
+
+ addr = rtas_addr + RTAS_ERROR_LOG_MAX + cs->cpu_index * sizeof(uint64_t)*2;
+ stq_be_phys(&address_space_memory, addr, env->gpr[3]);
+ stq_be_phys(&address_space_memory, addr + sizeof(uint64_t), 0);
+ env->gpr[3] = addr;
+ }
+ ppc_cpu_do_system_reset(cs, spapr->fwnmi_system_reset_addr);
}
static void spapr_nmi(NMIState *n, int cpu_index, Error **errp)
@@ -3389,8 +3426,8 @@ int spapr_lmb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
addr = spapr_drc_index(drc) * SPAPR_MEMORY_BLOCK_SIZE;
node = object_property_get_uint(OBJECT(drc->dev), PC_DIMM_NODE_PROP,
&error_abort);
- *fdt_start_offset = spapr_populate_memory_node(fdt, node, addr,
- SPAPR_MEMORY_BLOCK_SIZE);
+ *fdt_start_offset = spapr_dt_memory_node(fdt, node, addr,
+ SPAPR_MEMORY_BLOCK_SIZE);
return 0;
}
@@ -3791,7 +3828,7 @@ int spapr_core_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
offset = fdt_add_subnode(fdt, 0, nodename);
g_free(nodename);
- spapr_populate_cpu_dt(cs, fdt, offset, spapr);
+ spapr_dt_cpu(cs, fdt, offset, spapr);
*fdt_start_offset = offset;
return 0;
@@ -4504,7 +4541,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
smc->default_caps.caps[SPAPR_CAP_NESTED_KVM_HV] = SPAPR_CAP_OFF;
smc->default_caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_ON;
smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_ON;
- smc->default_caps.caps[SPAPR_CAP_FWNMI_MCE] = SPAPR_CAP_ON;
+ smc->default_caps.caps[SPAPR_CAP_FWNMI] = SPAPR_CAP_ON;
spapr_caps_add_properties(smc, &error_abort);
smc->irq = &spapr_irq_dual;
smc->dr_phb_enabled = true;
@@ -4582,7 +4619,8 @@ static void spapr_machine_4_2_class_options(MachineClass *mc)
spapr_machine_5_0_class_options(mc);
compat_props_add(mc->compat_props, hw_compat_4_2, hw_compat_4_2_len);
smc->default_caps.caps[SPAPR_CAP_CCF_ASSIST] = SPAPR_CAP_OFF;
- smc->default_caps.caps[SPAPR_CAP_FWNMI_MCE] = SPAPR_CAP_OFF;
+ smc->default_caps.caps[SPAPR_CAP_FWNMI] = SPAPR_CAP_OFF;
+ smc->rma_limit = 16 * GiB;
mc->nvdimm_supported = false;
}
diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
index 8b27d3ac09..679ae7959f 100644
--- a/hw/ppc/spapr_caps.c
+++ b/hw/ppc/spapr_caps.c
@@ -509,17 +509,14 @@ static void cap_ccf_assist_apply(SpaprMachineState *spapr, uint8_t val,
}
}
-static void cap_fwnmi_mce_apply(SpaprMachineState *spapr, uint8_t val,
+static void cap_fwnmi_apply(SpaprMachineState *spapr, uint8_t val,
Error **errp)
{
if (!val) {
return; /* Disabled by default */
}
- if (tcg_enabled()) {
- warn_report("Firmware Assisted Non-Maskable Interrupts(FWNMI) not "
- "supported in TCG");
- } else if (kvm_enabled()) {
+ if (kvm_enabled()) {
if (kvmppc_set_fwnmi() < 0) {
error_setg(errp, "Firmware Assisted Non-Maskable Interrupts(FWNMI) "
"not supported by KVM");
@@ -626,14 +623,14 @@ SpaprCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
.type = "bool",
.apply = cap_ccf_assist_apply,
},
- [SPAPR_CAP_FWNMI_MCE] = {
- .name = "fwnmi-mce",
- .description = "Handle fwnmi machine check exceptions",
- .index = SPAPR_CAP_FWNMI_MCE,
+ [SPAPR_CAP_FWNMI] = {
+ .name = "fwnmi",
+ .description = "Implements PAPR FWNMI option",
+ .index = SPAPR_CAP_FWNMI,
.get = spapr_cap_get_bool,
.set = spapr_cap_set_bool,
.type = "bool",
- .apply = cap_fwnmi_mce_apply,
+ .apply = cap_fwnmi_apply,
},
};
@@ -774,7 +771,7 @@ SPAPR_CAP_MIG_STATE(hpt_maxpagesize, SPAPR_CAP_HPT_MAXPAGESIZE);
SPAPR_CAP_MIG_STATE(nested_kvm_hv, SPAPR_CAP_NESTED_KVM_HV);
SPAPR_CAP_MIG_STATE(large_decr, SPAPR_CAP_LARGE_DECREMENTER);
SPAPR_CAP_MIG_STATE(ccf_assist, SPAPR_CAP_CCF_ASSIST);
-SPAPR_CAP_MIG_STATE(fwnmi, SPAPR_CAP_FWNMI_MCE);
+SPAPR_CAP_MIG_STATE(fwnmi, SPAPR_CAP_FWNMI);
void spapr_caps_init(SpaprMachineState *spapr)
{
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index d09125d9af..ac1c109427 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -50,22 +50,14 @@ static void spapr_reset_vcpu(PowerPCCPU *cpu)
* the settings below ensure proper operations with TCG in absence of
* a real hypervisor.
*
- * Clearing VPM0 will also cause us to use RMOR in mmu-hash64.c for
- * real mode accesses, which thankfully defaults to 0 and isn't
- * accessible in guest mode.
- *
* Disable Power-saving mode Exit Cause exceptions for the CPU, so
* we don't get spurious wakups before an RTAS start-cpu call.
* For the same reason, set PSSCR_EC.
*/
- lpcr &= ~(LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_KBV | pcc->lpcr_pm);
+ lpcr &= ~(LPCR_VPM1 | LPCR_ISL | LPCR_KBV | pcc->lpcr_pm);
lpcr |= LPCR_LPES0 | LPCR_LPES1;
env->spr[SPR_PSSCR] |= PSSCR_EC;
- /* Set RMLS to the max (ie, 16G) */
- lpcr &= ~LPCR_RMLS;
- lpcr |= 1ull << LPCR_RMLS_SHIFT;
-
ppc_store_lpcr(cpu, lpcr);
/* Set a full AMOR so guest can use the AMR as it sees fit */
@@ -84,13 +76,17 @@ static void spapr_reset_vcpu(PowerPCCPU *cpu)
spapr_irq_cpu_intc_reset(spapr, cpu);
}
-void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip, target_ulong r3)
+void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip,
+ target_ulong r1, target_ulong r3,
+ target_ulong r4)
{
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
CPUPPCState *env = &cpu->env;
env->nip = nip;
+ env->gpr[1] = r1;
env->gpr[3] = r3;
+ env->gpr[4] = r4;
kvmppc_set_reg_ppc_online(cpu, 1);
CPU(cpu)->halted = 0;
/* Enable Power-saving mode Exit Cause exceptions */
diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c
index 8b32b7eea5..323fcef4aa 100644
--- a/hw/ppc/spapr_events.c
+++ b/hw/ppc/spapr_events.c
@@ -786,28 +786,12 @@ static void spapr_mce_dispatch_elog(PowerPCCPU *cpu, bool recovered)
{
SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
CPUState *cs = CPU(cpu);
- uint64_t rtas_addr;
CPUPPCState *env = &cpu->env;
- PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
- target_ulong msr = 0;
+ uint64_t rtas_addr;
struct rtas_error_log log;
struct mc_extended_log *ext_elog;
uint32_t summary;
- /*
- * Properly set bits in MSR before we invoke the handler.
- * SRR0/1, DAR and DSISR are properly set by KVM
- */
- if (!(*pcc->interrupts_big_endian)(cpu)) {
- msr |= (1ULL << MSR_LE);
- }
-
- if (env->msr & (1ULL << MSR_SF)) {
- msr |= (1ULL << MSR_SF);
- }
-
- msr |= (1ULL << MSR_ME);
-
ext_elog = g_malloc0(sizeof(*ext_elog));
summary = spapr_mce_get_elog_type(cpu, recovered, ext_elog);
@@ -823,8 +807,7 @@ static void spapr_mce_dispatch_elog(PowerPCCPU *cpu, bool recovered)
/* get rtas addr from fdt */
rtas_addr = spapr_get_rtas_addr();
if (!rtas_addr) {
- /* Unable to fetch rtas_addr. Hence reset the guest */
- ppc_cpu_do_system_reset(cs);
+ qemu_system_guest_panicked(NULL);
g_free(ext_elog);
return;
}
@@ -836,12 +819,11 @@ static void spapr_mce_dispatch_elog(PowerPCCPU *cpu, bool recovered)
cpu_physical_memory_write(rtas_addr + RTAS_ERROR_LOG_OFFSET +
sizeof(env->gpr[3]) + sizeof(log), ext_elog,
sizeof(*ext_elog));
+ g_free(ext_elog);
env->gpr[3] = rtas_addr + RTAS_ERROR_LOG_OFFSET;
- env->msr = msr;
- env->nip = spapr->guest_machine_check_addr;
- g_free(ext_elog);
+ ppc_cpu_do_fwnmi_machine_check(cs, spapr->fwnmi_machine_check_addr);
}
void spapr_mce_req_event(PowerPCCPU *cpu, bool recovered)
@@ -851,7 +833,7 @@ void spapr_mce_req_event(PowerPCCPU *cpu, bool recovered)
int ret;
Error *local_err = NULL;
- if (spapr->guest_machine_check_addr == -1) {
+ if (spapr->fwnmi_machine_check_addr == -1) {
/*
* This implies that we have hit a machine check either when the
* guest has not registered FWNMI (i.e., "ibm,nmi-register" not
@@ -863,19 +845,19 @@ void spapr_mce_req_event(PowerPCCPU *cpu, bool recovered)
return;
}
- while (spapr->mc_status != -1) {
+ while (spapr->fwnmi_machine_check_interlock != -1) {
/*
* Check whether the same CPU got machine check error
* while still handling the mc error (i.e., before
* that CPU called "ibm,nmi-interlock")
*/
- if (spapr->mc_status == cpu->vcpu_id) {
+ if (spapr->fwnmi_machine_check_interlock == cpu->vcpu_id) {
qemu_system_guest_panicked(NULL);
return;
}
- qemu_cond_wait_iothread(&spapr->mc_delivery_cond);
+ qemu_cond_wait_iothread(&spapr->fwnmi_machine_check_interlock_cond);
/* Meanwhile if the system is reset, then just return */
- if (spapr->guest_machine_check_addr == -1) {
+ if (spapr->fwnmi_machine_check_addr == -1) {
return;
}
}
@@ -891,7 +873,7 @@ void spapr_mce_req_event(PowerPCCPU *cpu, bool recovered)
warn_report("Received a fwnmi while migration was in progress");
}
- spapr->mc_status = cpu->vcpu_id;
+ spapr->fwnmi_machine_check_interlock = cpu->vcpu_id;
spapr_mce_dispatch_elog(cpu, recovered);
}
@@ -983,6 +965,19 @@ void spapr_clear_pending_events(SpaprMachineState *spapr)
}
}
+void spapr_clear_pending_hotplug_events(SpaprMachineState *spapr)
+{
+ SpaprEventLogEntry *entry = NULL, *next_entry;
+
+ QTAILQ_FOREACH_SAFE(entry, &spapr->pending_events, next, next_entry) {
+ if (spapr_event_log_entry_type(entry) == RTAS_LOG_TYPE_HOTPLUG) {
+ QTAILQ_REMOVE(&spapr->pending_events, entry, next);
+ g_free(entry->extended_log);
+ g_free(entry);
+ }
+ }
+}
+
void spapr_events_init(SpaprMachineState *spapr)
{
int epow_irq = SPAPR_IRQ_EPOW;
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 934eb12d27..40c86e91eb 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -1458,7 +1458,7 @@ static void spapr_check_setup_free_hpt(SpaprMachineState *spapr,
spapr_free_hpt(spapr);
} else if (!(patbe_new & PATE1_GR)) {
/* RADIX->HASH || NOTHING->HASH : Allocate HPT */
- spapr_setup_hpt_and_vrma(spapr);
+ spapr_setup_hpt(spapr);
}
return;
}
@@ -1640,7 +1640,7 @@ static uint32_t cas_check_pvr(SpaprMachineState *spapr, PowerPCCPU *cpu,
return best_compat;
}
-static bool spapr_transient_dev_before_cas(void)
+static void spapr_handle_transient_dev_before_cas(SpaprMachineState *spapr)
{
Object *drc_container;
ObjectProperty *prop;
@@ -1658,10 +1658,11 @@ static bool spapr_transient_dev_before_cas(void)
prop->name, NULL));
if (spapr_drc_transient(drc)) {
- return true;
+ spapr_drc_reset(drc);
}
}
- return false;
+
+ spapr_clear_pending_hotplug_events(spapr);
}
static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
@@ -1834,9 +1835,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
spapr_irq_update_active_intc(spapr);
- if (spapr_transient_dev_before_cas()) {
- spapr->cas_reboot = true;
- }
+ spapr_handle_transient_dev_before_cas(spapr);
if (!spapr->cas_reboot) {
void *fdt;
@@ -1846,7 +1845,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
* (because the guest isn't going to use radix) then set it up here. */
if ((spapr->patb_entry & PATE1_GR) && !guest_radix) {
/* legacy hash or new hash: */
- spapr_setup_hpt_and_vrma(spapr);
+ spapr_setup_hpt(spapr);
}
if (fdt_bufsize < sizeof(hdr)) {
diff --git a/hw/ppc/spapr_nvdimm.c b/hw/ppc/spapr_nvdimm.c
index 74eeb8bb74..25be8082d7 100644
--- a/hw/ppc/spapr_nvdimm.c
+++ b/hw/ppc/spapr_nvdimm.c
@@ -35,6 +35,7 @@ void spapr_nvdimm_validate_opts(NVDIMMDevice *nvdimm, uint64_t size,
{
char *uuidstr = NULL;
QemuUUID uuid;
+ int ret;
if (size % SPAPR_MINIMUM_SCM_BLOCK_SIZE) {
error_setg(errp, "NVDIMM memory size excluding the label area"
@@ -43,8 +44,10 @@ void spapr_nvdimm_validate_opts(NVDIMMDevice *nvdimm, uint64_t size,
return;
}
- uuidstr = object_property_get_str(OBJECT(nvdimm), NVDIMM_UUID_PROP, NULL);
- qemu_uuid_parse(uuidstr, &uuid);
+ uuidstr = object_property_get_str(OBJECT(nvdimm), NVDIMM_UUID_PROP,
+ &error_abort);
+ ret = qemu_uuid_parse(uuidstr, &uuid);
+ g_assert(!ret);
g_free(uuidstr);
if (qemu_uuid_is_null(&uuid)) {
diff --git a/hw/ppc/spapr_ovec.c b/hw/ppc/spapr_ovec.c
index 0ff6d1aeae..dd003f1763 100644
--- a/hw/ppc/spapr_ovec.c
+++ b/hw/ppc/spapr_ovec.c
@@ -200,8 +200,8 @@ SpaprOptionVector *spapr_ovec_parse_vector(target_ulong table_addr, int vector)
return ov;
}
-int spapr_ovec_populate_dt(void *fdt, int fdt_offset,
- SpaprOptionVector *ov, const char *name)
+int spapr_dt_ovec(void *fdt, int fdt_offset,
+ SpaprOptionVector *ov, const char *name)
{
uint8_t vec[OV_MAXBYTES + 1];
uint16_t vec_len;
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index 656fdd2216..9fb8c8632a 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -190,7 +190,7 @@ static void rtas_start_cpu(PowerPCCPU *callcpu, SpaprMachineState *spapr,
*/
newcpu->env.tb_env->tb_offset = callcpu->env.tb_env->tb_offset;
- spapr_cpu_set_entry_state(newcpu, start, r3);
+ spapr_cpu_set_entry_state(newcpu, start, 0, r3, 0);
qemu_cpu_kick(CPU(newcpu));
@@ -414,8 +414,9 @@ static void rtas_ibm_nmi_register(PowerPCCPU *cpu,
uint32_t nret, target_ulong rets)
{
hwaddr rtas_addr;
+ target_ulong sreset_addr, mce_addr;
- if (spapr_get_cap(spapr, SPAPR_CAP_FWNMI_MCE) == SPAPR_CAP_OFF) {
+ if (spapr_get_cap(spapr, SPAPR_CAP_FWNMI) == SPAPR_CAP_OFF) {
rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED);
return;
}
@@ -426,7 +427,19 @@ static void rtas_ibm_nmi_register(PowerPCCPU *cpu,
return;
}
- spapr->guest_machine_check_addr = rtas_ld(args, 1);
+ sreset_addr = rtas_ld(args, 0);
+ mce_addr = rtas_ld(args, 1);
+
+ /* PAPR requires these are in the first 32M of memory and within RMA */
+ if (sreset_addr >= 32 * MiB || sreset_addr >= spapr->rma_size ||
+ mce_addr >= 32 * MiB || mce_addr >= spapr->rma_size) {
+ rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
+ return;
+ }
+
+ spapr->fwnmi_system_reset_addr = sreset_addr;
+ spapr->fwnmi_machine_check_addr = mce_addr;
+
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
@@ -436,29 +449,39 @@ static void rtas_ibm_nmi_interlock(PowerPCCPU *cpu,
target_ulong args,
uint32_t nret, target_ulong rets)
{
- if (spapr_get_cap(spapr, SPAPR_CAP_FWNMI_MCE) == SPAPR_CAP_OFF) {
+ if (spapr_get_cap(spapr, SPAPR_CAP_FWNMI) == SPAPR_CAP_OFF) {
rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED);
return;
}
- if (spapr->guest_machine_check_addr == -1) {
+ if (spapr->fwnmi_machine_check_addr == -1) {
/* NMI register not called */
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return;
}
- if (spapr->mc_status != cpu->vcpu_id) {
- /* The vCPU that hit the NMI should invoke "ibm,nmi-interlock" */
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
+ if (spapr->fwnmi_machine_check_interlock != cpu->vcpu_id) {
+ /*
+ * The vCPU that hit the NMI should invoke "ibm,nmi-interlock"
+ * This should be PARAM_ERROR, but Linux calls "ibm,nmi-interlock"
+ * for system reset interrupts, despite them not being interlocked.
+ * PowerVM silently ignores this and returns success here. Returning
+ * failure causes Linux to print the error "FWNMI: nmi-interlock
+ * failed: -3", although no other apparent ill effects, this is a
+ * regression for the user when enabling FWNMI. So for now, match
+ * PowerVM. When most Linux clients are fixed, this could be
+ * changed.
+ */
+ rtas_st(rets, 0, RTAS_OUT_SUCCESS);
return;
}
/*
* vCPU issuing "ibm,nmi-interlock" is done with NMI handling,
- * hence unset mc_status.
+ * hence unset fwnmi_machine_check_interlock.
*/
- spapr->mc_status = -1;
- qemu_cond_signal(&spapr->mc_delivery_cond);
+ spapr->fwnmi_machine_check_interlock = -1;
+ qemu_cond_signal(&spapr->fwnmi_machine_check_interlock_cond);
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
migrate_del_blocker(spapr->fwnmi_migration_blocker);
}
diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
index 7d584e7732..923488beb2 100644
--- a/hw/scsi/spapr_vscsi.c
+++ b/hw/scsi/spapr_vscsi.c
@@ -55,6 +55,8 @@
#define VSCSI_MAX_SECTORS 4096
#define VSCSI_REQ_LIMIT 24
+/* Maximum size of a IU payload */
+#define SRP_MAX_IU_DATA_LEN (SRP_MAX_IU_LEN - sizeof(union srp_iu))
#define SRP_RSP_SENSE_DATA_LEN 18
#define SRP_REPORT_LUNS_WLUN 0xc10100000000000ULL
@@ -66,7 +68,7 @@ typedef union vscsi_crq {
typedef struct vscsi_req {
vscsi_crq crq;
- union viosrp_iu iu;
+ uint8_t viosrp_iu_buf[SRP_MAX_IU_LEN];
/* SCSI request tracking */
SCSIRequest *sreq;
@@ -97,6 +99,11 @@ typedef struct {
vscsi_req reqs[VSCSI_REQ_LIMIT];
} VSCSIState;
+static union viosrp_iu *req_iu(vscsi_req *req)
+{
+ return (union viosrp_iu *)req->viosrp_iu_buf;
+}
+
static struct vscsi_req *vscsi_get_req(VSCSIState *s)
{
vscsi_req *req;
@@ -121,7 +128,7 @@ static struct vscsi_req *vscsi_find_req(VSCSIState *s, uint64_t srp_tag)
for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
req = &s->reqs[i];
- if (req->iu.srp.cmd.tag == srp_tag) {
+ if (req_iu(req)->srp.cmd.tag == srp_tag) {
return req;
}
}
@@ -176,9 +183,11 @@ static int vscsi_send_iu(VSCSIState *s, vscsi_req *req,
{
long rc, rc1;
+ assert(length <= SRP_MAX_IU_LEN);
+
/* First copy the SRP */
rc = spapr_vio_dma_write(&s->vdev, req->crq.s.IU_data_ptr,
- &req->iu, length);
+ &req->viosrp_iu_buf, length);
if (rc) {
fprintf(stderr, "vscsi_send_iu: DMA write failure !\n");
}
@@ -188,7 +197,7 @@ static int vscsi_send_iu(VSCSIState *s, vscsi_req *req,
req->crq.s.reserved = 0x00;
req->crq.s.timeout = cpu_to_be16(0x0000);
req->crq.s.IU_length = cpu_to_be16(length);
- req->crq.s.IU_data_ptr = req->iu.srp.rsp.tag; /* right byte order */
+ req->crq.s.IU_data_ptr = req_iu(req)->srp.rsp.tag; /* right byte order */
if (rc == 0) {
req->crq.s.status = VIOSRP_OK;
@@ -224,7 +233,7 @@ static void vscsi_makeup_sense(VSCSIState *s, vscsi_req *req,
static int vscsi_send_rsp(VSCSIState *s, vscsi_req *req,
uint8_t status, int32_t res_in, int32_t res_out)
{
- union viosrp_iu *iu = &req->iu;
+ union viosrp_iu *iu = req_iu(req);
uint64_t tag = iu->srp.rsp.tag;
int total_len = sizeof(iu->srp.rsp);
uint8_t sol_not = iu->srp.cmd.sol_not;
@@ -261,10 +270,12 @@ static int vscsi_send_rsp(VSCSIState *s, vscsi_req *req,
if (status) {
iu->srp.rsp.sol_not = (sol_not & 0x04) >> 2;
if (req->senselen) {
- req->iu.srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID;
- req->iu.srp.rsp.sense_data_len = cpu_to_be32(req->senselen);
- memcpy(req->iu.srp.rsp.data, req->sense, req->senselen);
- total_len += req->senselen;
+ int sense_data_len = MIN(req->senselen, SRP_MAX_IU_DATA_LEN);
+
+ iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID;
+ iu->srp.rsp.sense_data_len = cpu_to_be32(sense_data_len);
+ memcpy(iu->srp.rsp.data, req->sense, sense_data_len);
+ total_len += sense_data_len;
}
} else {
iu->srp.rsp.sol_not = (sol_not & 0x02) >> 1;
@@ -285,7 +296,7 @@ static int vscsi_fetch_desc(VSCSIState *s, struct vscsi_req *req,
unsigned n, unsigned buf_offset,
struct srp_direct_buf *ret)
{
- struct srp_cmd *cmd = &req->iu.srp.cmd;
+ struct srp_cmd *cmd = &req_iu(req)->srp.cmd;
switch (req->dma_fmt) {
case SRP_NO_DATA_DESC: {
@@ -473,7 +484,7 @@ static int data_out_desc_size(struct srp_cmd *cmd)
static int vscsi_preprocess_desc(vscsi_req *req)
{
- struct srp_cmd *cmd = &req->iu.srp.cmd;
+ struct srp_cmd *cmd = &req_iu(req)->srp.cmd;
req->cdb_offset = cmd->add_cdb_len & ~3;
@@ -597,7 +608,7 @@ static const VMStateDescription vmstate_spapr_vscsi_req = {
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_BUFFER(crq.raw, vscsi_req),
- VMSTATE_BUFFER(iu.srp.reserved, vscsi_req),
+ VMSTATE_BUFFER(viosrp_iu_buf, vscsi_req),
VMSTATE_UINT32(qtag, vscsi_req),
VMSTATE_BOOL(active, vscsi_req),
VMSTATE_UINT32(data_len, vscsi_req),
@@ -655,7 +666,7 @@ static void *vscsi_load_request(QEMUFile *f, SCSIRequest *sreq)
static void vscsi_process_login(VSCSIState *s, vscsi_req *req)
{
- union viosrp_iu *iu = &req->iu;
+ union viosrp_iu *iu = req_iu(req);
struct srp_login_rsp *rsp = &iu->srp.login_rsp;
uint64_t tag = iu->srp.rsp.tag;
@@ -671,8 +682,8 @@ static void vscsi_process_login(VSCSIState *s, vscsi_req *req)
*/
rsp->req_lim_delta = cpu_to_be32(VSCSI_REQ_LIMIT-2);
rsp->tag = tag;
- rsp->max_it_iu_len = cpu_to_be32(sizeof(union srp_iu));
- rsp->max_ti_iu_len = cpu_to_be32(sizeof(union srp_iu));
+ rsp->max_it_iu_len = cpu_to_be32(SRP_MAX_IU_LEN);
+ rsp->max_ti_iu_len = cpu_to_be32(SRP_MAX_IU_LEN);
/* direct and indirect */
rsp->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT);
@@ -681,7 +692,7 @@ static void vscsi_process_login(VSCSIState *s, vscsi_req *req)
static void vscsi_inquiry_no_target(VSCSIState *s, vscsi_req *req)
{
- uint8_t *cdb = req->iu.srp.cmd.cdb;
+ uint8_t *cdb = req_iu(req)->srp.cmd.cdb;
uint8_t resp_data[36];
int rc, len, alen;
@@ -770,7 +781,7 @@ static void vscsi_report_luns(VSCSIState *s, vscsi_req *req)
static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
{
- union srp_iu *srp = &req->iu.srp;
+ union srp_iu *srp = &req_iu(req)->srp;
SCSIDevice *sdev;
int n, lun;
@@ -821,17 +832,16 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req)
{
- union viosrp_iu *iu = &req->iu;
+ union viosrp_iu *iu = req_iu(req);
vscsi_req *tmpreq;
int i, lun = 0, resp = SRP_TSK_MGMT_COMPLETE;
SCSIDevice *d;
uint64_t tag = iu->srp.rsp.tag;
uint8_t sol_not = iu->srp.cmd.sol_not;
- fprintf(stderr, "vscsi_process_tsk_mgmt %02x\n",
- iu->srp.tsk_mgmt.tsk_mgmt_func);
-
- d = vscsi_device_find(&s->bus, be64_to_cpu(req->iu.srp.tsk_mgmt.lun), &lun);
+ trace_spapr_vscsi_process_tsk_mgmt(iu->srp.tsk_mgmt.tsk_mgmt_func);
+ d = vscsi_device_find(&s->bus,
+ be64_to_cpu(req_iu(req)->srp.tsk_mgmt.lun), &lun);
if (!d) {
resp = SRP_TSK_MGMT_FIELDS_INVALID;
} else {
@@ -842,7 +852,7 @@ static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req)
break;
}
- tmpreq = vscsi_find_req(s, req->iu.srp.tsk_mgmt.task_tag);
+ tmpreq = vscsi_find_req(s, req_iu(req)->srp.tsk_mgmt.task_tag);
if (tmpreq && tmpreq->sreq) {
assert(tmpreq->sreq->hba_private);
scsi_req_cancel(tmpreq->sreq);
@@ -867,7 +877,8 @@ static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req)
for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
tmpreq = &s->reqs[i];
- if (tmpreq->iu.srp.cmd.lun != req->iu.srp.tsk_mgmt.lun) {
+ if (req_iu(tmpreq)->srp.cmd.lun
+ != req_iu(req)->srp.tsk_mgmt.lun) {
continue;
}
if (!tmpreq->active || !tmpreq->sreq) {
@@ -889,6 +900,7 @@ static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req)
}
/* Compose the response here as */
+ QEMU_BUILD_BUG_ON(SRP_MAX_IU_DATA_LEN < 4);
memset(iu, 0, sizeof(struct srp_rsp) + 4);
iu->srp.rsp.opcode = SRP_RSP;
iu->srp.rsp.req_lim_delta = cpu_to_be32(1);
@@ -911,7 +923,7 @@ static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req)
static int vscsi_handle_srp_req(VSCSIState *s, vscsi_req *req)
{
- union srp_iu *srp = &req->iu.srp;
+ union srp_iu *srp = &req_iu(req)->srp;
int done = 1;
uint8_t opcode = srp->rsp.opcode;
@@ -948,7 +960,7 @@ static int vscsi_send_adapter_info(VSCSIState *s, vscsi_req *req)
struct mad_adapter_info_data info;
int rc;
- sinfo = &req->iu.mad.adapter_info;
+ sinfo = &req_iu(req)->mad.adapter_info;
#if 0 /* What for ? */
rc = spapr_vio_dma_read(&s->vdev, be64_to_cpu(sinfo->buffer),
@@ -984,7 +996,7 @@ static int vscsi_send_capabilities(VSCSIState *s, vscsi_req *req)
uint64_t buffer;
int rc;
- vcap = &req->iu.mad.capabilities;
+ vcap = &req_iu(req)->mad.capabilities;
req_len = len = be16_to_cpu(vcap->common.length);
buffer = be64_to_cpu(vcap->buffer);
if (len > sizeof(cap)) {
@@ -1029,7 +1041,7 @@ static int vscsi_send_capabilities(VSCSIState *s, vscsi_req *req)
static int vscsi_handle_mad_req(VSCSIState *s, vscsi_req *req)
{
- union mad_iu *mad = &req->iu.mad;
+ union mad_iu *mad = &req_iu(req)->mad;
bool request_handled = false;
uint64_t retlen = 0;
@@ -1088,7 +1100,7 @@ static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq)
* in our 256 bytes IUs. If not we'll have to increase the size
* of the structure.
*/
- if (crq->s.IU_length > sizeof(union viosrp_iu)) {
+ if (crq->s.IU_length > SRP_MAX_IU_LEN) {
fprintf(stderr, "VSCSI: SRP IU too long (%d bytes) !\n",
crq->s.IU_length);
vscsi_put_req(req);
@@ -1096,7 +1108,7 @@ static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq)
}
/* XXX Handle failure differently ? */
- if (spapr_vio_dma_read(&s->vdev, crq->s.IU_data_ptr, &req->iu,
+ if (spapr_vio_dma_read(&s->vdev, crq->s.IU_data_ptr, &req->viosrp_iu_buf,
crq->s.IU_length)) {
fprintf(stderr, "vscsi_got_payload: DMA read failure !\n");
vscsi_put_req(req);
diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events
index b0820052f8..9a4a60ca63 100644
--- a/hw/scsi/trace-events
+++ b/hw/scsi/trace-events
@@ -227,6 +227,7 @@ spapr_vscsi_command_complete_status(uint32_t status) "Command complete err=%"PRI
spapr_vscsi_save_request(uint32_t qtag, unsigned desc, unsigned offset) "saving tag=%"PRIu32", current desc#%u, offset=0x%x"
spapr_vscsi_load_request(uint32_t qtag, unsigned desc, unsigned offset) "restoring tag=%"PRIu32", current desc#%u, offset=0x%x"
spapr_vscsi_process_login(void) "Got login, sending response !"
+spapr_vscsi_process_tsk_mgmt(uint8_t func) "tsk_mgmt_func 0x%02x"
spapr_vscsi_queue_cmd_no_drive(uint64_t lun) "Command for lun 0x%08" PRIx64 " with no drive"
spapr_vscsi_queue_cmd(uint32_t qtag, unsigned cdb, const char *cmd, int lun, int ret) "Queued command tag 0x%"PRIx32" CMD 0x%x=%s LUN %d ret: %d"
spapr_vscsi_do_crq(unsigned c0, unsigned c1) "crq: %02x %02x ..."
diff --git a/hw/scsi/viosrp.h b/hw/scsi/viosrp.h
index d8e365db1e..e5f9768e8f 100644
--- a/hw/scsi/viosrp.h
+++ b/hw/scsi/viosrp.h
@@ -34,6 +34,8 @@
#ifndef PPC_VIOSRP_H
#define PPC_VIOSRP_H
+#include "hw/scsi/srp.h"
+
#define SRP_VERSION "16.a"
#define SRP_MAX_IU_LEN 256
#define SRP_MAX_LOC_LEN 32
@@ -47,7 +49,6 @@ union srp_iu {
struct srp_tsk_mgmt tsk_mgmt;
struct srp_cmd cmd;
struct srp_rsp rsp;
- uint8_t reserved[SRP_MAX_IU_LEN];
};
enum viosrp_crq_formats {
diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c
index 91db069212..829797b597 100644
--- a/hw/sd/ssi-sd.c
+++ b/hw/sd/ssi-sd.c
@@ -255,13 +255,25 @@ static void ssi_sd_realize(SSISlave *d, Error **errp)
carddev = qdev_create(BUS(&s->sdbus), TYPE_SD_CARD);
if (dinfo) {
qdev_prop_set_drive(carddev, "drive", blk_by_legacy_dinfo(dinfo), &err);
+ if (err) {
+ goto fail;
+ }
}
+
object_property_set_bool(OBJECT(carddev), true, "spi", &err);
+ if (err) {
+ goto fail;
+ }
+
object_property_set_bool(OBJECT(carddev), true, "realized", &err);
if (err) {
- error_setg(errp, "failed to init SD card: %s", error_get_pretty(err));
- return;
+ goto fail;
}
+
+ return;
+
+fail:
+ error_propagate_prepend(errp, err, "failed to init SD card: ");
}
static void ssi_sd_reset(DeviceState *dev)
diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
index d33e84f831..6abfcb30f8 100644
--- a/hw/sparc64/sun4u.c
+++ b/hw/sparc64/sun4u.c
@@ -50,7 +50,6 @@
#include "hw/sparc/sparc64.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/sysbus.h"
-#include "hw/ide.h"
#include "hw/ide/pci.h"
#include "hw/loader.h"
#include "hw/fw-path-provider.h"
@@ -563,7 +562,6 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
PCIBus *pci_bus, *pci_busA, *pci_busB;
PCIDevice *ebus, *pci_dev;
SysBusDevice *s;
- DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
DeviceState *iommu, *dev;
FWCfgState *fw_cfg;
NICInfo *nd;
@@ -663,12 +661,10 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
qemu_macaddr_default_if_unset(&macaddr);
}
- ide_drive_get(hd, ARRAY_SIZE(hd));
-
pci_dev = pci_create(pci_busA, PCI_DEVFN(3, 0), "cmd646-ide");
qdev_prop_set_uint32(&pci_dev->qdev, "secondary", 1);
qdev_init_nofail(&pci_dev->qdev);
- pci_ide_create_devs(pci_dev, hd);
+ pci_ide_create_devs(pci_dev);
/* Map NVRAM into I/O (ebus) space */
nvram = m48t59_init(NULL, 0, 0, NVRAM_SIZE, 1968, 59);
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index 08363969c1..30b909ebd2 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -68,40 +68,76 @@ void gdb_signalled(CPUArchState *, int);
void gdbserver_fork(CPUState *);
#endif
/* Get or set a register. Returns the size of the register. */
-typedef int (*gdb_reg_cb)(CPUArchState *env, uint8_t *buf, int reg);
+typedef int (*gdb_get_reg_cb)(CPUArchState *env, GByteArray *buf, int reg);
+typedef int (*gdb_set_reg_cb)(CPUArchState *env, uint8_t *buf, int reg);
void gdb_register_coprocessor(CPUState *cpu,
- gdb_reg_cb get_reg, gdb_reg_cb set_reg,
+ gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
int num_regs, const char *xml, int g_pos);
-/* The GDB remote protocol transfers values in target byte order. This means
- * we can use the raw memory access routines to access the value buffer.
- * Conveniently, these also handle the case where the buffer is mis-aligned.
+/*
+ * The GDB remote protocol transfers values in target byte order. As
+ * the gdbstub may be batching up several register values we always
+ * append to the array.
*/
-static inline int gdb_get_reg8(uint8_t *mem_buf, uint8_t val)
+static inline int gdb_get_reg8(GByteArray *buf, uint8_t val)
{
- stb_p(mem_buf, val);
+ g_byte_array_append(buf, &val, 1);
return 1;
}
-static inline int gdb_get_reg16(uint8_t *mem_buf, uint16_t val)
+static inline int gdb_get_reg16(GByteArray *buf, uint16_t val)
{
- stw_p(mem_buf, val);
+ uint16_t to_word = tswap16(val);
+ g_byte_array_append(buf, (uint8_t *) &to_word, 2);
return 2;
}
-static inline int gdb_get_reg32(uint8_t *mem_buf, uint32_t val)
+static inline int gdb_get_reg32(GByteArray *buf, uint32_t val)
{
- stl_p(mem_buf, val);
+ uint32_t to_long = tswap32(val);
+ g_byte_array_append(buf, (uint8_t *) &to_long, 4);
return 4;
}
-static inline int gdb_get_reg64(uint8_t *mem_buf, uint64_t val)
+static inline int gdb_get_reg64(GByteArray *buf, uint64_t val)
{
- stq_p(mem_buf, val);
+ uint64_t to_quad = tswap64(val);
+ g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
return 8;
}
+static inline int gdb_get_reg128(GByteArray *buf, uint64_t val_hi,
+ uint64_t val_lo)
+{
+ uint64_t to_quad;
+#ifdef TARGET_WORDS_BIGENDIAN
+ to_quad = tswap64(val_hi);
+ g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
+ to_quad = tswap64(val_lo);
+ g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
+#else
+ to_quad = tswap64(val_lo);
+ g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
+ to_quad = tswap64(val_hi);
+ g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
+#endif
+ return 16;
+}
+
+/**
+ * gdb_get_reg_ptr: get pointer to start of last element
+ * @len: length of element
+ *
+ * This is a helper function to extract the pointer to the last
+ * element for additional processing. Some front-ends do additional
+ * dynamic swapping of the elements based on CPU state.
+ */
+static inline uint8_t * gdb_get_reg_ptr(GByteArray *buf, int len)
+{
+ return buf->data + buf->len - len;
+}
+
#if TARGET_LONG_BITS == 64
#define gdb_get_regl(buf, val) gdb_get_reg64(buf, val)
#define ldtul_p(addr) ldq_p(addr)
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index 88ee543722..5bf94d28cf 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -193,7 +193,7 @@ typedef struct CPUClass {
hwaddr (*get_phys_page_attrs_debug)(CPUState *cpu, vaddr addr,
MemTxAttrs *attrs);
int (*asidx_from_attrs)(CPUState *cpu, MemTxAttrs attrs);
- int (*gdb_read_register)(CPUState *cpu, uint8_t *buf, int reg);
+ int (*gdb_read_register)(CPUState *cpu, GByteArray *buf, int reg);
int (*gdb_write_register)(CPUState *cpu, uint8_t *buf, int reg);
bool (*debug_check_watchpoint)(CPUState *cpu, CPUWatchpoint *wp);
void (*debug_excp_handler)(CPUState *cpu);
diff --git a/include/hw/ide.h b/include/hw/ide.h
index 28d8a06439..c5ce5da4f4 100644
--- a/include/hw/ide.h
+++ b/include/hw/ide.h
@@ -2,23 +2,14 @@
#define HW_IDE_H
#include "hw/isa/isa.h"
-#include "hw/pci/pci.h"
#include "exec/memory.h"
-#define MAX_IDE_DEVS 2
-
/* ide-isa.c */
ISADevice *isa_ide_init(ISABus *bus, int iobase, int iobase2, int isairq,
DriveInfo *hd0, DriveInfo *hd1);
/* ide-pci.c */
-void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
- int secondary_ide_enabled);
-PCIDevice *pci_piix3_xen_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
-PCIDevice *pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
-PCIDevice *pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
int pci_piix3_xen_ide_unplug(DeviceState *dev, bool aux);
-void via_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
/* ide-mmio.c */
void mmio_ide_init_drives(DeviceState *dev, DriveInfo *hd0, DriveInfo *hd1);
diff --git a/include/hw/ide/internal.h b/include/hw/ide/internal.h
index 1bc1fc73e5..55da35d768 100644
--- a/include/hw/ide/internal.h
+++ b/include/hw/ide/internal.h
@@ -27,6 +27,8 @@ typedef struct IDEDMAOps IDEDMAOps;
#define TYPE_IDE_BUS "IDE"
#define IDE_BUS(obj) OBJECT_CHECK(IDEBus, (obj), TYPE_IDE_BUS)
+#define MAX_IDE_DEVS 2
+
/* Bits of HD_STATUS */
#define ERR_STAT 0x01
#define INDEX_STAT 0x02
diff --git a/include/hw/ide/pci.h b/include/hw/ide/pci.h
index a9f2c33e68..dd504e5a0b 100644
--- a/include/hw/ide/pci.h
+++ b/include/hw/ide/pci.h
@@ -2,6 +2,7 @@
#define HW_IDE_PCI_H
#include "hw/ide/internal.h"
+#include "hw/pci/pci.h"
#define BM_STATUS_DMAING 0x01
#define BM_STATUS_ERROR 0x02
@@ -62,7 +63,7 @@ static inline IDEState *bmdma_active_if(BMDMAState *bmdma)
void bmdma_init(IDEBus *bus, BMDMAState *bm, PCIIDEState *d);
void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val);
extern MemoryRegionOps bmdma_addr_ioport_ops;
-void pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table);
+void pci_ide_create_devs(PCIDevice *dev);
extern const VMStateDescription vmstate_ide_pci;
extern const MemoryRegionOps pci_ide_cmd_le_ops;
diff --git a/include/hw/misc/macio/macio.h b/include/hw/misc/macio/macio.h
index 070a694eb5..87335a991c 100644
--- a/include/hw/misc/macio/macio.h
+++ b/include/hw/misc/macio/macio.h
@@ -27,6 +27,7 @@
#define MACIO_H
#include "hw/char/escc.h"
+#include "hw/pci/pci.h"
#include "hw/ide/internal.h"
#include "hw/intc/heathrow_pic.h"
#include "hw/misc/macio/cuda.h"
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index 09110961a5..42d64a0368 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -79,10 +79,10 @@ typedef enum {
#define SPAPR_CAP_LARGE_DECREMENTER 0x08
/* Count Cache Flush Assist HW Instruction */
#define SPAPR_CAP_CCF_ASSIST 0x09
-/* FWNMI machine check handling */
-#define SPAPR_CAP_FWNMI_MCE 0x0A
+/* Implements PAPR FWNMI option */
+#define SPAPR_CAP_FWNMI 0x0A
/* Num Caps */
-#define SPAPR_CAP_NUM (SPAPR_CAP_FWNMI_MCE + 1)
+#define SPAPR_CAP_NUM (SPAPR_CAP_FWNMI + 1)
/*
* Capability Values
@@ -126,6 +126,7 @@ struct SpaprMachineClass {
bool pre_4_1_migration; /* don't migrate hpt-max-page-size */
bool linux_pci_probe;
bool smp_threads_vsmt; /* set VSMT to smp_threads by default */
+ hwaddr rma_limit; /* clamp the RMA to this size */
void (*phb_placement)(SpaprMachineState *spapr, uint32_t index,
uint64_t *buid, hwaddr *pio,
@@ -156,7 +157,6 @@ struct SpaprMachineState {
SpaprPendingHpt *pending_hpt; /* in-progress resize */
hwaddr rma_size;
- int vrma_adjust;
uint32_t fdt_size;
uint32_t fdt_initial_size;
void *fdt_blob;
@@ -192,14 +192,22 @@ struct SpaprMachineState {
* occurs during the unplug process. */
QTAILQ_HEAD(, SpaprDimmState) pending_dimm_unplugs;
- /* State related to "ibm,nmi-register" and "ibm,nmi-interlock" calls */
- target_ulong guest_machine_check_addr;
- /*
- * mc_status is set to -1 if mc is not in progress, else is set to the CPU
- * handling the mc.
+ /* State related to FWNMI option */
+
+ /* System Reset and Machine Check Notification Routine addresses
+ * registered by "ibm,nmi-register" RTAS call.
+ */
+ target_ulong fwnmi_system_reset_addr;
+ target_ulong fwnmi_machine_check_addr;
+
+ /* Machine Check FWNMI synchronization, fwnmi_machine_check_interlock is
+ * set to -1 if a FWNMI machine check is not in progress, else is set to
+ * the CPU that was delivered the machine check, and is set back to -1
+ * when that CPU makes an "ibm,nmi-interlock" RTAS call. The cond is used
+ * to synchronize other CPUs.
*/
- int mc_status;
- QemuCond mc_delivery_cond;
+ int fwnmi_machine_check_interlock;
+ QemuCond fwnmi_machine_check_interlock_cond;
/*< public >*/
char *kvm_type;
@@ -736,6 +744,7 @@ void spapr_load_rtas(SpaprMachineState *spapr, void *fdt, hwaddr addr);
#define SPAPR_IS_PCI_LIOBN(liobn) (!!((liobn) & 0x80000000))
#define SPAPR_PCI_DMA_WINDOW_NUM(liobn) ((liobn) & 0xff)
+#define RTAS_SIZE 2048
#define RTAS_ERROR_LOG_MAX 2048
/* Offset from rtas-base where error log is placed */
@@ -795,7 +804,7 @@ void *spapr_build_fdt(SpaprMachineState *spapr, bool reset, size_t space);
void spapr_events_init(SpaprMachineState *sm);
void spapr_dt_events(SpaprMachineState *sm, void *fdt);
void close_htab_fd(SpaprMachineState *spapr);
-void spapr_setup_hpt_and_vrma(SpaprMachineState *spapr);
+void spapr_setup_hpt(SpaprMachineState *spapr);
void spapr_free_hpt(SpaprMachineState *spapr);
SpaprTceTable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn);
void spapr_tce_table_enable(SpaprTceTable *tcet,
@@ -824,6 +833,7 @@ int spapr_hpt_shift_for_ramsize(uint64_t ramsize);
void spapr_reallocate_hpt(SpaprMachineState *spapr, int shift,
Error **errp);
void spapr_clear_pending_events(SpaprMachineState *spapr);
+void spapr_clear_pending_hotplug_events(SpaprMachineState *spapr);
int spapr_max_server_number(SpaprMachineState *spapr);
void spapr_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
uint64_t pte0, uint64_t pte1);
diff --git a/include/hw/ppc/spapr_cpu_core.h b/include/hw/ppc/spapr_cpu_core.h
index 1c4cc6559c..7aed8f555b 100644
--- a/include/hw/ppc/spapr_cpu_core.h
+++ b/include/hw/ppc/spapr_cpu_core.h
@@ -40,7 +40,9 @@ typedef struct SpaprCpuCoreClass {
} SpaprCpuCoreClass;
const char *spapr_get_cpu_core_type(const char *cpu_type);
-void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip, target_ulong r3);
+void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip,
+ target_ulong r1, target_ulong r3,
+ target_ulong r4);
typedef struct SpaprCpuState {
uint64_t vpa_addr;
diff --git a/include/hw/ppc/spapr_ovec.h b/include/hw/ppc/spapr_ovec.h
index 2bed517a2b..d4dee9e06a 100644
--- a/include/hw/ppc/spapr_ovec.h
+++ b/include/hw/ppc/spapr_ovec.h
@@ -72,8 +72,8 @@ void spapr_ovec_set(SpaprOptionVector *ov, long bitnr);
void spapr_ovec_clear(SpaprOptionVector *ov, long bitnr);
bool spapr_ovec_test(SpaprOptionVector *ov, long bitnr);
SpaprOptionVector *spapr_ovec_parse_vector(target_ulong table_addr, int vector);
-int spapr_ovec_populate_dt(void *fdt, int fdt_offset,
- SpaprOptionVector *ov, const char *name);
+int spapr_dt_ovec(void *fdt, int fdt_offset,
+ SpaprOptionVector *ov, const char *name);
/* migration */
extern const VMStateDescription vmstate_spapr_ovec;
diff --git a/include/hw/southbridge/piix.h b/include/hw/southbridge/piix.h
index 152628c6d9..02bd741209 100644
--- a/include/hw/southbridge/piix.h
+++ b/include/hw/southbridge/piix.h
@@ -68,7 +68,6 @@ extern PCIDevice *piix4_dev;
PIIX3State *piix3_create(PCIBus *pci_bus, ISABus **isa_bus);
-DeviceState *piix4_create(PCIBus *pci_bus, ISABus **isa_bus,
- I2CBus **smbus, size_t ide_buses);
+DeviceState *piix4_create(PCIBus *pci_bus, ISABus **isa_bus, I2CBus **smbus);
#endif
diff --git a/include/net/net.h b/include/net/net.h
index e175ba9677..094e966af9 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -98,6 +98,7 @@ struct NetClientState {
unsigned rxfilter_notify_enabled:1;
int vring_enable;
int vnet_hdr_len;
+ bool is_netdev;
QTAILQ_HEAD(, NetFilterState) filters;
};
@@ -203,7 +204,6 @@ void net_cleanup(void);
void hmp_host_net_add(Monitor *mon, const QDict *qdict);
void hmp_host_net_remove(Monitor *mon, const QDict *qdict);
void netdev_add(QemuOpts *opts, Error **errp);
-void qmp_netdev_add(QDict *qdict, QObject **ret, Error **errp);
int net_hub_id_for_client(NetClientState *nc, int *id);
NetClientState *net_hub_port_find(int hub_id);
diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index 9aa426a398..5a9cf82472 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -39,7 +39,8 @@ typedef QTAILQ_HEAD(QmpCommandList, QmpCommand) QmpCommandList;
void qmp_register_command(QmpCommandList *cmds, const char *name,
QmpCommandFunc *fn, QmpCommandOptions options);
-QmpCommand *qmp_find_command(QmpCommandList *cmds, const char *name);
+const QmpCommand *qmp_find_command(const QmpCommandList *cmds,
+ const char *name);
void qmp_disable_command(QmpCommandList *cmds, const char *name);
void qmp_enable_command(QmpCommandList *cmds, const char *name);
@@ -47,13 +48,13 @@ bool qmp_command_is_enabled(const QmpCommand *cmd);
const char *qmp_command_name(const QmpCommand *cmd);
bool qmp_has_success_response(const QmpCommand *cmd);
QDict *qmp_error_response(Error *err);
-QDict *qmp_dispatch(QmpCommandList *cmds, QObject *request,
+QDict *qmp_dispatch(const QmpCommandList *cmds, QObject *request,
bool allow_oob);
bool qmp_is_oob(const QDict *dict);
-typedef void (*qmp_cmd_callback_fn)(QmpCommand *cmd, void *opaque);
+typedef void (*qmp_cmd_callback_fn)(const QmpCommand *cmd, void *opaque);
-void qmp_for_each_command(QmpCommandList *cmds, qmp_cmd_callback_fn fn,
+void qmp_for_each_command(const QmpCommandList *cmds, qmp_cmd_callback_fn fn,
void *opaque);
#endif
diff --git a/monitor/misc.c b/monitor/misc.c
index c3bc34c099..6c45fa490f 100644
--- a/monitor/misc.c
+++ b/monitor/misc.c
@@ -247,8 +247,6 @@ static void monitor_init_qmp_commands(void)
qmp_query_qmp_schema, QCO_ALLOW_PRECONFIG);
qmp_register_command(&qmp_commands, "device_add", qmp_device_add,
QCO_NO_OPTIONS);
- qmp_register_command(&qmp_commands, "netdev_add", qmp_netdev_add,
- QCO_NO_OPTIONS);
qmp_register_command(&qmp_commands, "object-add", qmp_object_add,
QCO_NO_OPTIONS);
@@ -2037,13 +2035,11 @@ void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str)
count = qemu_find_net_clients_except(NULL, ncs, NET_CLIENT_DRIVER_NIC,
MAX_QUEUE_NUM);
for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) {
- QemuOpts *opts;
const char *name = ncs[i]->name;
if (strncmp(str, name, len)) {
continue;
}
- opts = qemu_opts_find(qemu_find_opts_err("netdev", NULL), name);
- if (opts) {
+ if (ncs[i]->is_netdev) {
readline_add_completion(rs, name);
}
}
diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h
index 3e6baba88f..8f60ccc70a 100644
--- a/monitor/monitor-internal.h
+++ b/monitor/monitor-internal.h
@@ -133,7 +133,7 @@ typedef struct {
* qmp_capabilities succeeds, we go into command mode, and
* @command becomes &qmp_commands.
*/
- QmpCommandList *commands;
+ const QmpCommandList *commands;
bool capab_offered[QMP_CAPABILITY__MAX]; /* capabilities offered */
bool capab[QMP_CAPABILITY__MAX]; /* offered and accepted */
/*
diff --git a/monitor/qmp-cmds-control.c b/monitor/qmp-cmds-control.c
index 5cd9bb817c..8f04cfa6e6 100644
--- a/monitor/qmp-cmds-control.c
+++ b/monitor/qmp-cmds-control.c
@@ -101,7 +101,7 @@ VersionInfo *qmp_query_version(Error **errp)
return info;
}
-static void query_commands_cb(QmpCommand *cmd, void *opaque)
+static void query_commands_cb(const QmpCommand *cmd, void *opaque)
{
CommandInfoList *info, **list = opaque;
diff --git a/net/net.c b/net/net.c
index 9e93c3f8a1..38778e831d 100644
--- a/net/net.c
+++ b/net/net.c
@@ -1060,6 +1060,15 @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp)
}
return -1;
}
+
+ if (is_netdev) {
+ NetClientState *nc;
+
+ nc = qemu_find_netdev(netdev->id);
+ assert(nc);
+ nc->is_netdev = true;
+ }
+
return 0;
}
@@ -1170,36 +1179,14 @@ void netdev_add(QemuOpts *opts, Error **errp)
net_client_init(opts, true, errp);
}
-void qmp_netdev_add(QDict *qdict, QObject **ret, Error **errp)
+void qmp_netdev_add(Netdev *netdev, Error **errp)
{
- Error *local_err = NULL;
- QemuOptsList *opts_list;
- QemuOpts *opts;
-
- opts_list = qemu_find_opts_err("netdev", &local_err);
- if (local_err) {
- goto out;
- }
-
- opts = qemu_opts_from_qdict(opts_list, qdict, &local_err);
- if (local_err) {
- goto out;
- }
-
- netdev_add(opts, &local_err);
- if (local_err) {
- qemu_opts_del(opts);
- goto out;
- }
-
-out:
- error_propagate(errp, local_err);
+ net_client_init1(netdev, true, errp);
}
void qmp_netdev_del(const char *id, Error **errp)
{
NetClientState *nc;
- QemuOpts *opts;
nc = qemu_find_netdev(id);
if (!nc) {
@@ -1208,14 +1195,12 @@ void qmp_netdev_del(const char *id, Error **errp)
return;
}
- opts = qemu_opts_find(qemu_find_opts_err("netdev", NULL), id);
- if (!opts) {
+ if (!nc->is_netdev) {
error_setg(errp, "Device '%s' is not a netdev", id);
return;
}
qemu_del_net_client(nc);
- qemu_opts_del(opts);
}
static void netfilter_print_info(Monitor *mon, NetFilterState *nf)
diff --git a/pc-bios/README b/pc-bios/README
index d6d33d237f..f54c2743d0 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -14,7 +14,7 @@
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
implementation for certain IBM POWER hardware. The sources are at
https://github.com/aik/SLOF, and the image currently in qemu is
- built from git tag qemu-slof-20191217.
+ built from git tag qemu-slof-20200317.
- sgabios (the Serial Graphics Adapter option ROM) provides a means for
legacy x86 software to communicate with an attached serial console as
diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin
index 78d8b26cbb..40499a1451 100644
--- a/pc-bios/slof.bin
+++ b/pc-bios/slof.bin
Binary files differ
diff --git a/python/qemu/machine.py b/python/qemu/machine.py
index 183d8f3d38..f53abfa492 100644
--- a/python/qemu/machine.py
+++ b/python/qemu/machine.py
@@ -270,7 +270,8 @@ class QEMUMachine(object):
self._vm_monitor = os.path.join(self._sock_dir,
self._name + "-monitor.sock")
self._remove_files.append(self._vm_monitor)
- self._qmp = qmp.QEMUMonitorProtocol(self._vm_monitor, server=True)
+ self._qmp = qmp.QEMUMonitorProtocol(self._vm_monitor, server=True,
+ nickname=self._name)
def _post_launch(self):
if self._qmp:
diff --git a/python/qemu/qmp.py b/python/qemu/qmp.py
index f40586eedd..d6c9b2f4b1 100644
--- a/python/qemu/qmp.py
+++ b/python/qemu/qmp.py
@@ -46,7 +46,7 @@ class QEMUMonitorProtocol:
#: Logger object for debugging messages
logger = logging.getLogger('QMP')
- def __init__(self, address, server=False):
+ def __init__(self, address, server=False, nickname=None):
"""
Create a QEMUMonitorProtocol class.
@@ -62,6 +62,9 @@ class QEMUMonitorProtocol:
self.__address = address
self.__sock = self.__get_sock()
self.__sockfile = None
+ self._nickname = nickname
+ if self._nickname:
+ self.logger = logging.getLogger('QMP').getChild(self._nickname)
if server:
self.__sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.__sock.bind(self.__address)
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 91586fb1fb..943df1926a 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -297,7 +297,7 @@
#
# @encrypted: true if the backing device is encrypted
#
-# @encryption_key_missing: Deprecated; always false
+# @encryption_key_missing: always false
#
# @detect_zeroes: detect and optimize zero writes (Since 2.1)
#
@@ -363,13 +363,19 @@
# @dirty-bitmaps: dirty bitmaps information (only present if node
# has one or more dirty bitmaps) (Since 4.2)
#
+# Features:
+# @deprecated: Member @encryption_key_missing is deprecated. It is
+# always false.
+#
# Since: 0.14.0
#
##
{ 'struct': 'BlockDeviceInfo',
'data': { 'file': 'str', '*node-name': 'str', 'ro': 'bool', 'drv': 'str',
'*backing_file': 'str', 'backing_file_depth': 'int',
- 'encrypted': 'bool', 'encryption_key_missing': 'bool',
+ 'encrypted': 'bool',
+ 'encryption_key_missing': { 'type': 'bool',
+ 'features': [ 'deprecated' ] },
'detect_zeroes': 'BlockdevDetectZeroesOptions',
'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int',
@@ -475,7 +481,7 @@
#
# @granularity: granularity of the dirty bitmap in bytes (since 1.4)
#
-# @status: Deprecated in favor of @recording and @locked. (since 2.4)
+# @status: current status of the dirty bitmap (since 2.4)
#
# @recording: true if the bitmap is recording new writes from the guest.
# Replaces `active` and `disabled` statuses. (since 4.0)
@@ -492,11 +498,17 @@
# @busy to be false. This bitmap cannot be used. To remove
# it, use @block-dirty-bitmap-remove. (Since 4.0)
#
+# Features:
+# @deprecated: Member @status is deprecated. Use @recording and
+# @locked instead.
+#
# Since: 1.3
##
{ 'struct': 'BlockDirtyInfo',
'data': {'*name': 'str', 'count': 'int', 'granularity': 'uint32',
- 'recording': 'bool', 'busy': 'bool', 'status': 'DirtyBitmapStatus',
+ 'recording': 'bool', 'busy': 'bool',
+ 'status': { 'type': 'DirtyBitmapStatus',
+ 'features': [ 'deprecated' ] },
'persistent': 'bool', '*inconsistent': 'bool' } }
##
@@ -587,7 +599,6 @@
#
# @dirty-bitmaps: dirty bitmaps information (only present if the
# driver has one or more dirty bitmaps) (Since 2.0)
-# Deprecated in 4.2; see BlockDeviceInfo instead.
#
# @io-status: @BlockDeviceIoStatus. Only present if the device
# supports it and the VM is configured to stop on errors
@@ -597,13 +608,18 @@
# @inserted: @BlockDeviceInfo describing the device if media is
# present
#
+# Features:
+# @deprecated: Member @dirty-bitmaps is deprecated. Use @inserted
+# member @dirty-bitmaps instead.
+#
# Since: 0.14.0
##
{ 'struct': 'BlockInfo',
'data': {'device': 'str', '*qdev': 'str', 'type': 'str', 'removable': 'bool',
'locked': 'bool', '*inserted': 'BlockDeviceInfo',
'*tray_open': 'bool', '*io-status': 'BlockDeviceIoStatus',
- '*dirty-bitmaps': ['BlockDirtyInfo'] } }
+ '*dirty-bitmaps': { 'type': ['BlockDirtyInfo'],
+ 'features': [ 'deprecated' ] } } }
##
# @BlockMeasureInfo:
@@ -1551,7 +1567,7 @@
# @base: Same as @base-node, except that it is a file name rather than a node
# name. This must be the exact filename string that was used to open the
# node; other strings, even if addressing the same file, are not
-# accepted (deprecated, use @base-node instead)
+# accepted
#
# @top-node: The node name of the backing image within the image chain
# which contains the topmost data to be committed down. If
@@ -1560,7 +1576,7 @@
# @top: Same as @top-node, except that it is a file name rather than a node
# name. This must be the exact filename string that was used to open the
# node; other strings, even if addressing the same file, are not
-# accepted (deprecated, use @base-node instead)
+# accepted
#
# @backing-file: The backing file string to write into the overlay
# image of 'top'. If 'top' is the active layer,
@@ -1614,6 +1630,10 @@
# list without user intervention.
# Defaults to true. (Since 3.1)
#
+# Features:
+# @deprecated: Members @base and @top are deprecated. Use @base-node
+# and @top-node instead.
+#
# Returns: - Nothing on success
# - If @device does not exist, DeviceNotFound
# - Any other error returns a GenericError.
@@ -1630,7 +1650,9 @@
##
{ 'command': 'block-commit',
'data': { '*job-id': 'str', 'device': 'str', '*base-node': 'str',
- '*base': 'str', '*top-node': 'str', '*top': 'str',
+ '*base': { 'type': 'str', 'features': [ 'deprecated' ] },
+ '*top-node': 'str',
+ '*top': { 'type': 'str', 'features': [ 'deprecated' ] },
'*backing-file': 'str', '*speed': 'int',
'*on-error': 'BlockdevOnError',
'*filter-node-name': 'str',
@@ -2296,7 +2318,7 @@
#
# A set of parameters describing block throttling.
#
-# @device: Block device name (deprecated, use @id instead)
+# @device: Block device name
#
# @id: The name or QOM path of the guest device (since: 2.8)
#
@@ -2364,10 +2386,14 @@
#
# @group: throttle group name (Since 2.4)
#
+# Features:
+# @deprecated: Member @device is deprecated. Use @id instead.
+#
# Since: 1.1
##
{ 'struct': 'BlockIOThrottle',
- 'data': { '*device': 'str', '*id': 'str', 'bps': 'int', 'bps_rd': 'int',
+ 'data': { '*device': { 'type': 'str', 'features': [ 'deprecated' ] },
+ '*id': 'str', 'bps': 'int', 'bps_rd': 'int',
'bps_wr': 'int', 'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int',
'*bps_max': 'int', '*bps_rd_max': 'int',
'*bps_wr_max': 'int', '*iops_max': 'int',
diff --git a/qapi/block.json b/qapi/block.json
index 97bf52b7c7..2ddbfa8306 100644
--- a/qapi/block.json
+++ b/qapi/block.json
@@ -90,15 +90,18 @@
##
# @eject:
#
-# Ejects a device from a removable drive.
+# Ejects the medium from a removable drive.
#
-# @device: Block device name (deprecated, use @id instead)
+# @device: Block device name
#
# @id: The name or QOM path of the guest device (since: 2.8)
#
# @force: If true, eject regardless of whether the drive is locked.
# If not specified, the default value is false.
#
+# Features:
+# @deprecated: Member @device is deprecated. Use @id instead.
+#
# Returns: - Nothing on success
# - If @device is not a valid block device, DeviceNotFound
# Notes: Ejecting a device with no media results in success
@@ -111,7 +114,7 @@
# <- { "return": {} }
##
{ 'command': 'eject',
- 'data': { '*device': 'str',
+ 'data': { '*device': { 'type': 'str', 'features': [ 'deprecated' ] },
'*id': 'str',
'*force': 'bool' } }
@@ -134,7 +137,7 @@
# to it
# - if the guest device does not have an actual tray
#
-# @device: Block device name (deprecated, use @id instead)
+# @device: Block device name
#
# @id: The name or QOM path of the guest device (since: 2.8)
#
@@ -143,6 +146,9 @@
# immediately); if true, the tray will be opened regardless of whether
# it is locked
#
+# Features:
+# @deprecated: Member @device is deprecated. Use @id instead.
+#
# Since: 2.5
#
# Example:
@@ -161,7 +167,7 @@
#
##
{ 'command': 'blockdev-open-tray',
- 'data': { '*device': 'str',
+ 'data': { '*device': { 'type': 'str', 'features': [ 'deprecated' ] },
'*id': 'str',
'*force': 'bool' } }
@@ -174,10 +180,13 @@
#
# If the tray was already closed before, this will be a no-op.
#
-# @device: Block device name (deprecated, use @id instead)
+# @device: Block device name
#
# @id: The name or QOM path of the guest device (since: 2.8)
#
+# Features:
+# @deprecated: Member @device is deprecated. Use @id instead.
+#
# Since: 2.5
#
# Example:
@@ -196,7 +205,7 @@
#
##
{ 'command': 'blockdev-close-tray',
- 'data': { '*device': 'str',
+ 'data': { '*device': { 'type': 'str', 'features': [ 'deprecated' ] },
'*id': 'str' } }
##
@@ -303,7 +312,7 @@
# combines blockdev-open-tray, blockdev-remove-medium, blockdev-insert-medium
# and blockdev-close-tray).
#
-# @device: Block device name (deprecated, use @id instead)
+# @device: Block device name
#
# @id: The name or QOM path of the guest device
# (since: 2.8)
@@ -316,6 +325,9 @@
# @read-only-mode: change the read-only mode of the device; defaults
# to 'retain'
#
+# Features:
+# @deprecated: Member @device is deprecated. Use @id instead.
+#
# Since: 2.5
#
# Examples:
@@ -350,7 +362,7 @@
#
##
{ 'command': 'blockdev-change-medium',
- 'data': { '*device': 'str',
+ 'data': { '*device': { 'type': 'str', 'features': [ 'deprecated' ] },
'*id': 'str',
'filename': 'str',
'*format': 'str',
diff --git a/qapi/char.json b/qapi/char.json
index 6907b2bfdb..daceb20f84 100644
--- a/qapi/char.json
+++ b/qapi/char.json
@@ -258,6 +258,7 @@
# @server: create server socket (default: true)
# @wait: wait for incoming connection on server
# sockets (default: false).
+# Silently ignored with server: false. This use is deprecated.
# @nodelay: set TCP_NODELAY socket option (default: false)
# @telnet: enable telnet protocol on server
# sockets (default: false)
diff --git a/qapi/control.json b/qapi/control.json
index 85b12fe0fb..6b816bb61f 100644
--- a/qapi/control.json
+++ b/qapi/control.json
@@ -174,13 +174,15 @@
#
# Return information on QMP events.
#
+# Features:
+# @deprecated: This command is deprecated, because its output doesn't
+# reflect compile-time configuration. Use 'query-qmp-schema'
+# instead.
+#
# Returns: A list of @EventInfo.
#
# Since: 1.2.0
#
-# Note: This command is deprecated, because its output doesn't reflect
-# compile-time configuration. Use query-qmp-schema instead.
-#
# Example:
#
# -> { "execute": "query-events" }
@@ -198,7 +200,8 @@
# Note: This example has been shortened as the real response is too long.
#
##
-{ 'command': 'query-events', 'returns': ['EventInfo'] }
+{ 'command': 'query-events', 'returns': ['EventInfo'],
+ 'features': [ 'deprecated' ] }
##
# @quit:
diff --git a/qapi/introspect.json b/qapi/introspect.json
index 8756e7920e..b1aabd4cfd 100644
--- a/qapi/introspect.json
+++ b/qapi/introspect.json
@@ -89,12 +89,18 @@
#
# @meta-type: the entity's meta type, inherited from @base.
#
+# @features: names of features associated with the entity, in no
+# particular order.
+# (since 4.1 for object types, 4.2 for commands, 5.0 for
+# the rest)
+#
# Additional members depend on the value of @meta-type.
#
# Since: 2.5
##
{ 'union': 'SchemaInfo',
- 'base': { 'name': 'str', 'meta-type': 'SchemaMetaType' },
+ 'base': { 'name': 'str', 'meta-type': 'SchemaMetaType',
+ '*features': [ 'str' ] },
'discriminator': 'meta-type',
'data': {
'builtin': 'SchemaInfoBuiltin',
@@ -174,9 +180,6 @@
# and may even differ from the order of the values of the
# enum type of the @tag.
#
-# @features: names of features associated with the type, in no particular
-# order. (since: 4.1)
-#
# Values of this type are JSON object on the wire.
#
# Since: 2.5
@@ -184,8 +187,7 @@
{ 'struct': 'SchemaInfoObject',
'data': { 'members': [ 'SchemaInfoObjectMember' ],
'*tag': 'str',
- '*variants': [ 'SchemaInfoObjectVariant' ],
- '*features': [ 'str' ] } }
+ '*variants': [ 'SchemaInfoObjectVariant' ] } }
##
# @SchemaInfoObjectMember:
@@ -204,11 +206,15 @@
# Future extension: if present and non-null, the parameter
# is optional, and defaults to this value.
#
+# @features: names of features associated with the member, in no
+# particular order. (since 5.0)
+#
# Since: 2.5
##
{ 'struct': 'SchemaInfoObjectMember',
- 'data': { 'name': 'str', 'type': 'str', '*default': 'any' } }
+ 'data': { 'name': 'str', 'type': 'str', '*default': 'any',
# @default's type must be null or match @type
+ '*features': [ 'str' ] } }
##
# @SchemaInfoObjectVariant:
@@ -266,17 +272,13 @@
# @allow-oob: whether the command allows out-of-band execution,
# defaults to false (Since: 2.12)
#
-# @features: names of features associated with the command, in no particular
-# order. (since 4.2)
-#
# TODO: @success-response (currently irrelevant, because it's QGA, not QMP)
#
# Since: 2.5
##
{ 'struct': 'SchemaInfoCommand',
'data': { 'arg-type': 'str', 'ret-type': 'str',
- '*allow-oob': 'bool',
- '*features': [ 'str' ] } }
+ '*allow-oob': 'bool' } }
##
# @SchemaInfoEvent:
diff --git a/qapi/machine.json b/qapi/machine.json
index 6c11e3cf3a..0da3f3adc4 100644
--- a/qapi/machine.json
+++ b/qapi/machine.json
@@ -184,8 +184,11 @@
# This command causes vCPU threads to exit to userspace, which causes
# a small interruption to guest CPU execution. This will have a negative
# impact on realtime guests and other latency sensitive guest workloads.
-# It is recommended to use @query-cpus-fast instead of this command to
-# avoid the vCPU interruption.
+#
+# Features:
+# @deprecated: This command is deprecated, because it interferes with
+# the guest. Use 'query-cpus-fast' instead to avoid the vCPU
+# interruption.
#
# Returns: a list of @CpuInfo for each virtual CPU
#
@@ -216,12 +219,9 @@
# ]
# }
#
-# Notes: This interface is deprecated (since 2.12.0), and it is strongly
-# recommended that you avoid using it. Use @query-cpus-fast to
-# obtain information about virtual CPUs.
-#
##
-{ 'command': 'query-cpus', 'returns': ['CpuInfo'] }
+{ 'command': 'query-cpus', 'returns': ['CpuInfo'],
+ 'features': [ 'deprecated' ] }
##
# @CpuInfoFast:
@@ -237,12 +237,14 @@
# @props: properties describing to which node/socket/core/thread
# virtual CPU belongs to, provided if supported by board
#
-# @arch: base architecture of the cpu; deprecated since 3.0.0 in favor
-# of @target
+# @arch: base architecture of the cpu
#
# @target: the QEMU system emulation target, which determines which
# additional fields will be listed (since 3.0)
#
+# Features:
+# @deprecated: Member @arch is deprecated. Use @target instead.
+#
# Since: 2.12
#
##
@@ -251,7 +253,8 @@
'qom-path' : 'str',
'thread-id' : 'int',
'*props' : 'CpuInstanceProperties',
- 'arch' : 'CpuInfoArch',
+ 'arch' : { 'type': 'CpuInfoArch',
+ 'features': [ 'deprecated' ] },
'target' : 'SysEmuTarget' },
'discriminator' : 'target',
'data' : { 's390x' : 'CpuInfoS390' } }
@@ -307,21 +310,22 @@
#
# @id: ID of CPU to be created, valid values [0..max_cpus)
#
+# Features:
+# @deprecated: This command is deprecated. Use `device_add` instead.
+# See the `query-hotpluggable-cpus` command for details.
+#
# Returns: Nothing on success
#
# Since: 1.5
#
-# Note: This command is deprecated. The `device_add` command should be
-# used instead. See the `query-hotpluggable-cpus` command for
-# details.
-#
# Example:
#
# -> { "execute": "cpu-add", "arguments": { "id": 2 } }
# <- { "return": {} }
#
##
-{ 'command': 'cpu-add', 'data': {'id': 'int'} }
+{ 'command': 'cpu-add', 'data': {'id': 'int'},
+ 'features': [ 'deprecated' ] }
##
# @MachineInfo:
diff --git a/qapi/migration.json b/qapi/migration.json
index 0d1c0712ca..eca2981d0a 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -1210,9 +1210,11 @@
#
# @value: maximum downtime in seconds
#
-# Returns: nothing on success
+# Features:
+# @deprecated: This command is deprecated. Use
+# 'migrate-set-parameters' instead.
#
-# Notes: This command is deprecated in favor of 'migrate-set-parameters'
+# Returns: nothing on success
#
# Since: 0.14.0
#
@@ -1222,7 +1224,8 @@
# <- { "return": {} }
#
##
-{ 'command': 'migrate_set_downtime', 'data': {'value': 'number'} }
+{ 'command': 'migrate_set_downtime', 'data': {'value': 'number'},
+ 'features': [ 'deprecated' ] }
##
# @migrate_set_speed:
@@ -1231,9 +1234,11 @@
#
# @value: maximum speed in bytes per second.
#
-# Returns: nothing on success
+# Features:
+# @deprecated: This command is deprecated. Use
+# 'migrate-set-parameters' instead.
#
-# Notes: This command is deprecated in favor of 'migrate-set-parameters'
+# Returns: nothing on success
#
# Since: 0.14.0
#
@@ -1243,7 +1248,8 @@
# <- { "return": {} }
#
##
-{ 'command': 'migrate_set_speed', 'data': {'value': 'int'} }
+{ 'command': 'migrate_set_speed', 'data': {'value': 'int'},
+ 'features': [ 'deprecated' ] }
##
# @migrate-set-cache-size:
@@ -1252,13 +1258,15 @@
#
# @value: cache size in bytes
#
+# Features:
+# @deprecated: This command is deprecated. Use
+# 'migrate-set-parameters' instead.
+#
# The size will be rounded down to the nearest power of 2.
# The cache size can be modified before and during ongoing migration
#
# Returns: nothing on success
#
-# Notes: This command is deprecated in favor of 'migrate-set-parameters'
-#
# Since: 1.2
#
# Example:
@@ -1268,16 +1276,19 @@
# <- { "return": {} }
#
##
-{ 'command': 'migrate-set-cache-size', 'data': {'value': 'int'} }
+{ 'command': 'migrate-set-cache-size', 'data': {'value': 'int'},
+ 'features': [ 'deprecated' ] }
##
# @query-migrate-cache-size:
#
# Query migration XBZRLE cache size
#
-# Returns: XBZRLE cache size in bytes
+# Features:
+# @deprecated: This command is deprecated. Use
+# 'query-migrate-parameters' instead.
#
-# Notes: This command is deprecated in favor of 'query-migrate-parameters'
+# Returns: XBZRLE cache size in bytes
#
# Since: 1.2
#
@@ -1287,7 +1298,8 @@
# <- { "return": 67108864 }
#
##
-{ 'command': 'query-migrate-cache-size', 'returns': 'int' }
+{ 'command': 'query-migrate-cache-size', 'returns': 'int',
+ 'features': [ 'deprecated' ] }
##
# @migrate:
diff --git a/qapi/misc.json b/qapi/misc.json
index c18fe681fb..99b90ac80b 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -872,14 +872,14 @@
# If @device is 'vnc' and @target is 'password', this is the new VNC
# password to set. See change-vnc-password for additional notes.
#
+# Features:
+# @deprecated: This command is deprecated. For changing block
+# devices, use 'blockdev-change-medium' instead; for changing VNC
+# parameters, use 'change-vnc-password' instead.
+#
# Returns: - Nothing on success.
# - If @device is not a valid block device, DeviceNotFound
#
-# Notes: This interface is deprecated, and it is strongly recommended that you
-# avoid using it. For changing block devices, use
-# blockdev-change-medium; for changing VNC parameters, use
-# change-vnc-password.
-#
# Since: 0.14.0
#
# Example:
@@ -900,7 +900,8 @@
#
##
{ 'command': 'change',
- 'data': {'device': 'str', 'target': 'str', '*arg': 'str'} }
+ 'data': {'device': 'str', 'target': 'str', '*arg': 'str'},
+ 'features': [ 'deprecated' ] }
##
# @xen-set-global-dirty-log:
diff --git a/qapi/net.json b/qapi/net.json
index 1cb9a7d782..cebb1b52e3 100644
--- a/qapi/net.json
+++ b/qapi/net.json
@@ -39,18 +39,8 @@
#
# Add a network backend.
#
-# @type: the type of network backend. Possible values are listed in
-# NetClientDriver (excluding 'none' and 'nic')
-#
-# @id: the name of the new network backend
-#
# Additional arguments depend on the type.
#
-# TODO: This command effectively bypasses QAPI completely due to its
-# "additional arguments" business. It shouldn't have been added to
-# the schema in this form. It should be qapified properly, or
-# replaced by a properly qapified command.
-#
# Since: 0.14.0
#
# Returns: Nothing on success
@@ -64,9 +54,7 @@
# <- { "return": {} }
#
##
-{ 'command': 'netdev_add',
- 'data': {'type': 'str', 'id': 'str'},
- 'gen': false } # so we can get the additional arguments
+{ 'command': 'netdev_add', 'data': 'Netdev', 'boxed': true }
##
# @netdev_del:
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index bc264b3c9b..c30c7ff9e1 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -19,20 +19,13 @@
#include "sysemu/runstate.h"
#include "qapi/qmp/qbool.h"
-static QDict *qmp_dispatch_check_obj(const QObject *request, bool allow_oob,
+static QDict *qmp_dispatch_check_obj(QDict *dict, bool allow_oob,
Error **errp)
{
const char *exec_key = NULL;
const QDictEntry *ent;
const char *arg_name;
const QObject *arg_obj;
- QDict *dict;
-
- dict = qobject_to(QDict, request);
- if (!dict) {
- error_setg(errp, "QMP input must be a JSON object");
- return NULL;
- }
for (ent = qdict_first(dict); ent;
ent = qdict_next(dict, ent)) {
@@ -75,19 +68,50 @@ static QDict *qmp_dispatch_check_obj(const QObject *request, bool allow_oob,
return dict;
}
-static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request,
- bool allow_oob, Error **errp)
+QDict *qmp_error_response(Error *err)
+{
+ QDict *rsp;
+
+ rsp = qdict_from_jsonf_nofail("{ 'error': { 'class': %s, 'desc': %s } }",
+ QapiErrorClass_str(error_get_class(err)),
+ error_get_pretty(err));
+ error_free(err);
+ return rsp;
+}
+
+/*
+ * Does @qdict look like a command to be run out-of-band?
+ */
+bool qmp_is_oob(const QDict *dict)
+{
+ return qdict_haskey(dict, "exec-oob")
+ && !qdict_haskey(dict, "execute");
+}
+
+QDict *qmp_dispatch(const QmpCommandList *cmds, QObject *request,
+ bool allow_oob)
{
- Error *local_err = NULL;
+ Error *err = NULL;
bool oob;
const char *command;
- QDict *args, *dict;
- QmpCommand *cmd;
+ QDict *args;
+ const QmpCommand *cmd;
+ QDict *dict;
+ QObject *id;
QObject *ret = NULL;
+ QDict *rsp = NULL;
- dict = qmp_dispatch_check_obj(request, allow_oob, errp);
+ dict = qobject_to(QDict, request);
if (!dict) {
- return NULL;
+ id = NULL;
+ error_setg(&err, "QMP input must be a JSON object");
+ goto out;
+ }
+
+ id = qdict_get(dict, "id");
+
+ if (!qmp_dispatch_check_obj(dict, allow_oob, &err)) {
+ goto out;
}
command = qdict_get_try_str(dict, "execute");
@@ -99,27 +123,27 @@ static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request,
}
cmd = qmp_find_command(cmds, command);
if (cmd == NULL) {
- error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
+ error_set(&err, ERROR_CLASS_COMMAND_NOT_FOUND,
"The command %s has not been found", command);
- return NULL;
+ goto out;
}
if (!cmd->enabled) {
- error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
+ error_set(&err, ERROR_CLASS_COMMAND_NOT_FOUND,
"The command %s has been disabled for this instance",
command);
- return NULL;
+ goto out;
}
if (oob && !(cmd->options & QCO_ALLOW_OOB)) {
- error_setg(errp, "The command %s does not support OOB",
+ error_setg(&err, "The command %s does not support OOB",
command);
- return NULL;
+ goto out;
}
if (runstate_check(RUN_STATE_PRECONFIG) &&
!(cmd->options & QCO_ALLOW_PRECONFIG)) {
- error_setg(errp, "The command '%s' isn't permitted in '%s' state",
+ error_setg(&err, "The command '%s' isn't permitted in '%s' state",
cmd->name, RunState_str(RUN_STATE_PRECONFIG));
- return NULL;
+ goto out;
}
if (!qdict_haskey(dict, "arguments")) {
@@ -128,62 +152,36 @@ static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request,
args = qdict_get_qdict(dict, "arguments");
qobject_ref(args);
}
+ cmd->fn(args, &ret, &err);
+ qobject_unref(args);
+ if (err) {
+ goto out;
+ }
- cmd->fn(args, &ret, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- } else if (cmd->options & QCO_NO_SUCCESS_RESP) {
+ if (cmd->options & QCO_NO_SUCCESS_RESP) {
g_assert(!ret);
+ return NULL;
} else if (!ret) {
- /* TODO turn into assertion */
+ /*
+ * When the command's schema has no 'returns', cmd->fn()
+ * leaves @ret null. The QMP spec calls for an empty object
+ * then; supply it.
+ */
ret = QOBJECT(qdict_new());
}
- qobject_unref(args);
-
- return ret;
-}
-
-QDict *qmp_error_response(Error *err)
-{
- QDict *rsp;
-
- rsp = qdict_from_jsonf_nofail("{ 'error': { 'class': %s, 'desc': %s } }",
- QapiErrorClass_str(error_get_class(err)),
- error_get_pretty(err));
- error_free(err);
- return rsp;
-}
-
-/*
- * Does @qdict look like a command to be run out-of-band?
- */
-bool qmp_is_oob(const QDict *dict)
-{
- return qdict_haskey(dict, "exec-oob")
- && !qdict_haskey(dict, "execute");
-}
-
-QDict *qmp_dispatch(QmpCommandList *cmds, QObject *request,
- bool allow_oob)
-{
- Error *err = NULL;
- QDict *dict = qobject_to(QDict, request);
- QObject *ret, *id = dict ? qdict_get(dict, "id") : NULL;
- QDict *rsp;
+ rsp = qdict_new();
+ qdict_put_obj(rsp, "return", ret);
- ret = do_qmp_dispatch(cmds, request, allow_oob, &err);
+out:
if (err) {
+ assert(!rsp);
rsp = qmp_error_response(err);
- } else if (ret) {
- rsp = qdict_new();
- qdict_put_obj(rsp, "return", ret);
- } else {
- /* Can only happen for commands with QCO_NO_SUCCESS_RESP */
- rsp = NULL;
}
- if (rsp && id) {
+ assert(rsp);
+
+ if (id) {
qdict_put_obj(rsp, "id", qobject_ref(id));
}
diff --git a/qapi/qmp-registry.c b/qapi/qmp-registry.c
index ca00f74795..d0f9a1d3e3 100644
--- a/qapi/qmp-registry.c
+++ b/qapi/qmp-registry.c
@@ -27,7 +27,7 @@ void qmp_register_command(QmpCommandList *cmds, const char *name,
QTAILQ_INSERT_TAIL(cmds, cmd, node);
}
-QmpCommand *qmp_find_command(QmpCommandList *cmds, const char *name)
+const QmpCommand *qmp_find_command(const QmpCommandList *cmds, const char *name)
{
QmpCommand *cmd;
@@ -77,10 +77,10 @@ bool qmp_has_success_response(const QmpCommand *cmd)
return !(cmd->options & QCO_NO_SUCCESS_RESP);
}
-void qmp_for_each_command(QmpCommandList *cmds, qmp_cmd_callback_fn fn,
+void qmp_for_each_command(const QmpCommandList *cmds, qmp_cmd_callback_fn fn,
void *opaque)
{
- QmpCommand *cmd;
+ const QmpCommand *cmd;
QTAILQ_FOREACH(cmd, cmds, node) {
fn(cmd, opaque);
diff --git a/qga/commands.c b/qga/commands.c
index 43c323cead..f8852beb9c 100644
--- a/qga/commands.c
+++ b/qga/commands.c
@@ -54,7 +54,7 @@ void qmp_guest_ping(Error **errp)
slog("guest-ping called");
}
-static void qmp_command_info(QmpCommand *cmd, void *opaque)
+static void qmp_command_info(const QmpCommand *cmd, void *opaque)
{
GuestAgentInfo *info = opaque;
GuestAgentCommandInfo *cmd_info;
diff --git a/qga/main.c b/qga/main.c
index e5c39c189a..8ee2736f8e 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -359,7 +359,7 @@ static gint ga_strcmp(gconstpointer str1, gconstpointer str2)
}
/* disable commands that aren't safe for fsfreeze */
-static void ga_disable_non_whitelisted(QmpCommand *cmd, void *opaque)
+static void ga_disable_non_whitelisted(const QmpCommand *cmd, void *opaque)
{
bool whitelisted = false;
int i = 0;
@@ -378,7 +378,7 @@ static void ga_disable_non_whitelisted(QmpCommand *cmd, void *opaque)
}
/* [re-]enable all commands, except those explicitly blacklisted by user */
-static void ga_enable_non_blacklisted(QmpCommand *cmd, void *opaque)
+static void ga_enable_non_blacklisted(const QmpCommand *cmd, void *opaque)
{
GList *blacklist = opaque;
const char *name = qmp_command_name(cmd);
@@ -918,7 +918,7 @@ int64_t ga_get_fd_handle(GAState *s, Error **errp)
return handle;
}
-static void ga_print_cmd(QmpCommand *cmd, void *opaque)
+static void ga_print_cmd(const QmpCommand *cmd, void *opaque)
{
printf("%s\n", qmp_command_name(cmd));
}
diff --git a/roms/SLOF b/roms/SLOF
-Subproject 9546892a80d5a4c73deea6719de46372f007f4a
+Subproject ab6984f5a6d054e1f634dda855b32e535711197
diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
index 0e13e82989..bc30876c88 100644
--- a/scripts/qapi/commands.py
+++ b/scripts/qapi/commands.py
@@ -283,9 +283,9 @@ void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
prefix=self._prefix))
self._genc.add(gen_registry(self._regy.get_content(), self._prefix))
- def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
- success_response, boxed, allow_oob, allow_preconfig,
- features):
+ def visit_command(self, name, info, ifcond, features,
+ arg_type, ret_type, gen, success_response, boxed,
+ allow_oob, allow_preconfig):
if not gen:
return
# FIXME: If T is a user-defined type, the user is responsible
diff --git a/scripts/qapi/doc.py b/scripts/qapi/doc.py
index 1787a53d91..92f584edcf 100644
--- a/scripts/qapi/doc.py
+++ b/scripts/qapi/doc.py
@@ -243,34 +243,34 @@ class QAPISchemaGenDocVisitor(QAPISchemaVisitor):
def write(self, output_dir):
self._gen.write(output_dir)
- def visit_enum_type(self, name, info, ifcond, members, prefix):
+ def visit_enum_type(self, name, info, ifcond, features, members, prefix):
doc = self.cur_doc
self._gen.add(texi_type('Enum', doc, ifcond,
texi_members(doc, 'Values',
member_func=texi_enum_value)))
- def visit_object_type(self, name, info, ifcond, base, members, variants,
- features):
+ def visit_object_type(self, name, info, ifcond, features,
+ base, members, variants):
doc = self.cur_doc
if base and base.is_implicit():
base = None
self._gen.add(texi_type('Object', doc, ifcond,
texi_members(doc, 'Members', base, variants)))
- def visit_alternate_type(self, name, info, ifcond, variants):
+ def visit_alternate_type(self, name, info, ifcond, features, variants):
doc = self.cur_doc
self._gen.add(texi_type('Alternate', doc, ifcond,
texi_members(doc, 'Members')))
- def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
- success_response, boxed, allow_oob, allow_preconfig,
- features):
+ def visit_command(self, name, info, ifcond, features,
+ arg_type, ret_type, gen, success_response, boxed,
+ allow_oob, allow_preconfig):
doc = self.cur_doc
self._gen.add(texi_msg('Command', doc, ifcond,
texi_arguments(doc,
arg_type if boxed else None)))
- def visit_event(self, name, info, ifcond, arg_type, boxed):
+ def visit_event(self, name, info, ifcond, features, arg_type, boxed):
doc = self.cur_doc
self._gen.add(texi_msg('Event', doc, ifcond,
texi_arguments(doc,
diff --git a/scripts/qapi/events.py b/scripts/qapi/events.py
index a98b9f5099..b544af5a1c 100644
--- a/scripts/qapi/events.py
+++ b/scripts/qapi/events.py
@@ -189,7 +189,7 @@ void %(event_emit)s(%(event_enum)s event, QDict *qdict);
event_emit=self._event_emit_name,
event_enum=self._event_enum_name))
- def visit_event(self, name, info, ifcond, arg_type, boxed):
+ def visit_event(self, name, info, ifcond, features, arg_type, boxed):
with ifcontext(ifcond, self._genh, self._genc):
self._genh.add(gen_event_send_decl(name, arg_type, boxed))
self._genc.add(gen_event_send(name, arg_type, boxed,
diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py
index fecf466fa7..2942520399 100644
--- a/scripts/qapi/expr.py
+++ b/scripts/qapi/expr.py
@@ -167,8 +167,9 @@ def check_type(value, info, source,
allow_optional=True, permit_upper=permit_upper)
if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
raise QAPISemError(info, "%s uses reserved name" % key_source)
- check_keys(arg, info, key_source, ['type'], ['if'])
+ check_keys(arg, info, key_source, ['type'], ['if', 'features'])
check_if(arg, info, key_source)
+ check_features(arg.get('features'), info)
check_type(arg['type'], info, key_source, allow_array=True)
@@ -219,7 +220,6 @@ def check_struct(expr, info):
check_type(members, info, "'data'", allow_dict=name)
check_type(expr.get('base'), info, "'base'")
- check_features(expr.get('features'), info)
def check_union(expr, info):
@@ -267,7 +267,6 @@ def check_command(expr, info):
raise QAPISemError(info, "'boxed': true requires 'data'")
check_type(args, info, "'data'", allow_dict=not boxed)
check_type(rets, info, "'returns'", allow_array=True)
- check_features(expr.get('features'), info)
def check_event(expr, info):
@@ -319,18 +318,18 @@ def check_exprs(exprs):
if meta == 'enum':
check_keys(expr, info, meta,
- ['enum', 'data'], ['if', 'prefix'])
+ ['enum', 'data'], ['if', 'features', 'prefix'])
check_enum(expr, info)
elif meta == 'union':
check_keys(expr, info, meta,
['union', 'data'],
- ['base', 'discriminator', 'if'])
+ ['base', 'discriminator', 'if', 'features'])
normalize_members(expr.get('base'))
normalize_members(expr['data'])
check_union(expr, info)
elif meta == 'alternate':
check_keys(expr, info, meta,
- ['alternate', 'data'], ['if'])
+ ['alternate', 'data'], ['if', 'features'])
normalize_members(expr['data'])
check_alternate(expr, info)
elif meta == 'struct':
@@ -348,13 +347,14 @@ def check_exprs(exprs):
check_command(expr, info)
elif meta == 'event':
check_keys(expr, info, meta,
- ['event'], ['data', 'boxed', 'if'])
+ ['event'], ['data', 'boxed', 'if', 'features'])
normalize_members(expr.get('data'))
check_event(expr, info)
else:
assert False, 'unexpected meta type'
check_if(expr, info, meta)
+ check_features(expr.get('features'), info)
check_flags(expr, info)
return exprs
diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py
index b5537eddc0..23652be810 100644
--- a/scripts/qapi/introspect.py
+++ b/scripts/qapi/introspect.py
@@ -16,7 +16,19 @@ from qapi.schema import (QAPISchemaArrayType, QAPISchemaBuiltinType,
QAPISchemaType)
-def to_qlit(obj, level=0, suppress_first_indent=False):
+def _make_tree(obj, ifcond, features, extra=None):
+ if extra is None:
+ extra = {}
+ if ifcond:
+ extra['if'] = ifcond
+ if features:
+ obj['features'] = [(f.name, {'if': f.ifcond}) for f in features]
+ if extra:
+ return (obj, extra)
+ return obj
+
+
+def _tree_to_qlit(obj, level=0, suppress_first_indent=False):
def indent(level):
return level * 4 * ' '
@@ -30,7 +42,7 @@ def to_qlit(obj, level=0, suppress_first_indent=False):
ret += indent(level) + '/* %s */\n' % comment
if ifcond:
ret += gen_if(ifcond)
- ret += to_qlit(ifobj, level)
+ ret += _tree_to_qlit(ifobj, level)
if ifcond:
ret += '\n' + gen_endif(ifcond)
return ret
@@ -43,7 +55,7 @@ def to_qlit(obj, level=0, suppress_first_indent=False):
elif isinstance(obj, str):
ret += 'QLIT_QSTR(' + to_c_string(obj) + ')'
elif isinstance(obj, list):
- elts = [to_qlit(elt, level + 1).strip('\n')
+ elts = [_tree_to_qlit(elt, level + 1).strip('\n')
for elt in obj]
elts.append(indent(level + 1) + "{}")
ret += 'QLIT_QLIST(((QLitObject[]) {\n'
@@ -53,7 +65,8 @@ def to_qlit(obj, level=0, suppress_first_indent=False):
elts = []
for key, value in sorted(obj.items()):
elts.append(indent(level + 1) + '{ %s, %s }' %
- (to_c_string(key), to_qlit(value, level + 1, True)))
+ (to_c_string(key),
+ _tree_to_qlit(value, level + 1, True)))
elts.append(indent(level + 1) + '{}')
ret += 'QLIT_QDICT(((QLitDictEntry[]) {\n'
ret += ',\n'.join(elts) + '\n'
@@ -79,7 +92,7 @@ class QAPISchemaGenIntrospectVisitor(QAPISchemaMonolithicCVisitor):
' * QAPI/QMP schema introspection', __doc__)
self._unmask = unmask
self._schema = None
- self._qlits = []
+ self._trees = []
self._used_types = []
self._name_map = {}
self._genc.add(mcgen('''
@@ -108,9 +121,9 @@ extern const QLitObject %(c_name)s;
const QLitObject %(c_name)s = %(c_string)s;
''',
c_name=c_name(name),
- c_string=to_qlit(self._qlits)))
+ c_string=_tree_to_qlit(self._trees)))
self._schema = None
- self._qlits = []
+ self._trees = []
self._used_types = []
self._name_map = {}
@@ -144,89 +157,78 @@ const QLitObject %(c_name)s = %(c_string)s;
return '[' + self._use_type(typ.element_type) + ']'
return self._name(typ.name)
- def _gen_qlit(self, name, mtype, obj, ifcond):
- extra = {}
+ def _gen_tree(self, name, mtype, obj, ifcond, features):
+ extra = None
if mtype not in ('command', 'event', 'builtin', 'array'):
if not self._unmask:
# Output a comment to make it easy to map masked names
# back to the source when reading the generated output.
- extra['comment'] = '"%s" = %s' % (self._name(name), name)
+ extra = {'comment': '"%s" = %s' % (self._name(name), name)}
name = self._name(name)
obj['name'] = name
obj['meta-type'] = mtype
- if ifcond:
- extra['if'] = ifcond
- if extra:
- self._qlits.append((obj, extra))
- else:
- self._qlits.append(obj)
+ self._trees.append(_make_tree(obj, ifcond, features, extra))
def _gen_member(self, member):
- ret = {'name': member.name, 'type': self._use_type(member.type)}
+ obj = {'name': member.name, 'type': self._use_type(member.type)}
if member.optional:
- ret['default'] = None
- if member.ifcond:
- ret = (ret, {'if': member.ifcond})
- return ret
+ obj['default'] = None
+ return _make_tree(obj, member.ifcond, member.features)
def _gen_variants(self, tag_name, variants):
return {'tag': tag_name,
'variants': [self._gen_variant(v) for v in variants]}
def _gen_variant(self, variant):
- return ({'case': variant.name, 'type': self._use_type(variant.type)},
- {'if': variant.ifcond})
+ obj = {'case': variant.name, 'type': self._use_type(variant.type)}
+ return _make_tree(obj, variant.ifcond, None)
def visit_builtin_type(self, name, info, json_type):
- self._gen_qlit(name, 'builtin', {'json-type': json_type}, [])
+ self._gen_tree(name, 'builtin', {'json-type': json_type}, [], None)
- def visit_enum_type(self, name, info, ifcond, members, prefix):
- self._gen_qlit(name, 'enum',
- {'values':
- [(m.name, {'if': m.ifcond}) for m in members]},
- ifcond)
+ def visit_enum_type(self, name, info, ifcond, features, members, prefix):
+ self._gen_tree(name, 'enum',
+ {'values': [_make_tree(m.name, m.ifcond, None)
+ for m in members]},
+ ifcond, features)
def visit_array_type(self, name, info, ifcond, element_type):
element = self._use_type(element_type)
- self._gen_qlit('[' + element + ']', 'array', {'element-type': element},
- ifcond)
+ self._gen_tree('[' + element + ']', 'array', {'element-type': element},
+ ifcond, None)
- def visit_object_type_flat(self, name, info, ifcond, members, variants,
- features):
+ def visit_object_type_flat(self, name, info, ifcond, features,
+ members, variants):
obj = {'members': [self._gen_member(m) for m in members]}
if variants:
obj.update(self._gen_variants(variants.tag_member.name,
variants.variants))
- if features:
- obj['features'] = [(f.name, {'if': f.ifcond}) for f in features]
- self._gen_qlit(name, 'object', obj, ifcond)
+ self._gen_tree(name, 'object', obj, ifcond, features)
- def visit_alternate_type(self, name, info, ifcond, variants):
- self._gen_qlit(name, 'alternate',
+ def visit_alternate_type(self, name, info, ifcond, features, variants):
+ self._gen_tree(name, 'alternate',
{'members': [
- ({'type': self._use_type(m.type)}, {'if': m.ifcond})
- for m in variants.variants]}, ifcond)
-
- def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
- success_response, boxed, allow_oob, allow_preconfig,
- features):
+ _make_tree({'type': self._use_type(m.type)},
+ m.ifcond, None)
+ for m in variants.variants]},
+ ifcond, features)
+
+ def visit_command(self, name, info, ifcond, features,
+ arg_type, ret_type, gen, success_response, boxed,
+ allow_oob, allow_preconfig):
arg_type = arg_type or self._schema.the_empty_object_type
ret_type = ret_type or self._schema.the_empty_object_type
obj = {'arg-type': self._use_type(arg_type),
'ret-type': self._use_type(ret_type)}
if allow_oob:
obj['allow-oob'] = allow_oob
+ self._gen_tree(name, 'command', obj, ifcond, features)
- if features:
- obj['features'] = [(f.name, {'if': f.ifcond}) for f in features]
-
- self._gen_qlit(name, 'command', obj, ifcond)
-
- def visit_event(self, name, info, ifcond, arg_type, boxed):
+ def visit_event(self, name, info, ifcond, features, arg_type, boxed):
arg_type = arg_type or self._schema.the_empty_object_type
- self._gen_qlit(name, 'event', {'arg-type': self._use_type(arg_type)},
- ifcond)
+ self._gen_tree(name, 'event', {'arg-type': self._use_type(arg_type)},
+ ifcond, features)
def gen_introspect(schema, output_dir, prefix, opt_unmask):
diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py
index d759308b4e..78309a00f0 100644
--- a/scripts/qapi/schema.py
+++ b/scripts/qapi/schema.py
@@ -53,13 +53,13 @@ class QAPISchemaEntity:
seen = {}
for f in self.features:
f.check_clash(self.info, seen)
- if self.doc:
- self.doc.connect_feature(f)
-
self._checked = True
def connect_doc(self, doc=None):
- pass
+ doc = doc or self.doc
+ if doc:
+ for f in self.features:
+ doc.connect_feature(f)
def check_doc(self):
if self.doc:
@@ -109,29 +109,29 @@ class QAPISchemaVisitor:
def visit_builtin_type(self, name, info, json_type):
pass
- def visit_enum_type(self, name, info, ifcond, members, prefix):
+ def visit_enum_type(self, name, info, ifcond, features, members, prefix):
pass
def visit_array_type(self, name, info, ifcond, element_type):
pass
- def visit_object_type(self, name, info, ifcond, base, members, variants,
- features):
+ def visit_object_type(self, name, info, ifcond, features,
+ base, members, variants):
pass
- def visit_object_type_flat(self, name, info, ifcond, members, variants,
- features):
+ def visit_object_type_flat(self, name, info, ifcond, features,
+ members, variants):
pass
- def visit_alternate_type(self, name, info, ifcond, variants):
+ def visit_alternate_type(self, name, info, ifcond, features, variants):
pass
- def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
- success_response, boxed, allow_oob, allow_preconfig,
- features):
+ def visit_command(self, name, info, ifcond, features,
+ arg_type, ret_type, gen, success_response, boxed,
+ allow_oob, allow_preconfig):
pass
- def visit_event(self, name, info, ifcond, arg_type, boxed):
+ def visit_event(self, name, info, ifcond, features, arg_type, boxed):
pass
@@ -193,6 +193,12 @@ class QAPISchemaType(QAPISchemaEntity):
return None
return self.name
+ def check(self, schema):
+ QAPISchemaEntity.check(self, schema)
+ if 'deprecated' in [f.name for f in self.features]:
+ raise QAPISemError(
+ self.info, "feature 'deprecated' is not supported for types")
+
def describe(self):
assert self.meta
return "%s type '%s'" % (self.meta, self.name)
@@ -234,8 +240,8 @@ class QAPISchemaBuiltinType(QAPISchemaType):
class QAPISchemaEnumType(QAPISchemaType):
meta = 'enum'
- def __init__(self, name, info, doc, ifcond, members, prefix):
- super().__init__(name, info, doc, ifcond)
+ def __init__(self, name, info, doc, ifcond, features, members, prefix):
+ super().__init__(name, info, doc, ifcond, features)
for m in members:
assert isinstance(m, QAPISchemaEnumMember)
m.set_defined_in(name)
@@ -250,10 +256,10 @@ class QAPISchemaEnumType(QAPISchemaType):
m.check_clash(self.info, seen)
def connect_doc(self, doc=None):
+ super().connect_doc(doc)
doc = doc or self.doc
- if doc:
- for m in self.members:
- doc.connect_member(m)
+ for m in self.members:
+ m.connect_doc(doc)
def is_implicit(self):
# See QAPISchema._make_implicit_enum_type() and ._def_predefineds()
@@ -270,15 +276,16 @@ class QAPISchemaEnumType(QAPISchemaType):
def visit(self, visitor):
super().visit(visitor)
- visitor.visit_enum_type(self.name, self.info, self.ifcond,
- self.members, self.prefix)
+ visitor.visit_enum_type(
+ self.name, self.info, self.ifcond, self.features,
+ self.members, self.prefix)
class QAPISchemaArrayType(QAPISchemaType):
meta = 'array'
def __init__(self, name, info, element_type):
- super().__init__(name, info, None, None)
+ super().__init__(name, info, None)
assert isinstance(element_type, str)
self._element_type_name = element_type
self.element_type = None
@@ -324,8 +331,8 @@ class QAPISchemaArrayType(QAPISchemaType):
class QAPISchemaObjectType(QAPISchemaType):
- def __init__(self, name, info, doc, ifcond,
- base, local_members, variants, features):
+ def __init__(self, name, info, doc, ifcond, features,
+ base, local_members, variants):
# struct has local_members, optional base, and no variants
# flat union has base, variants, and no local_members
# simple union has local_members, variants, and no base
@@ -336,7 +343,7 @@ class QAPISchemaObjectType(QAPISchemaType):
assert isinstance(m, QAPISchemaObjectTypeMember)
m.set_defined_in(name)
if variants is not None:
- assert isinstance(variants, QAPISchemaObjectTypeVariants)
+ assert isinstance(variants, QAPISchemaVariants)
variants.set_defined_in(name)
self._base_name = base
self.base = None
@@ -392,12 +399,12 @@ class QAPISchemaObjectType(QAPISchemaType):
m.check_clash(info, seen)
def connect_doc(self, doc=None):
+ super().connect_doc(doc)
doc = doc or self.doc
- if doc:
- if self.base and self.base.is_implicit():
- self.base.connect_doc(doc)
- for m in self.local_members:
- doc.connect_member(m)
+ if self.base and self.base.is_implicit():
+ self.base.connect_doc(doc)
+ for m in self.local_members:
+ m.connect_doc(doc)
@property
def ifcond(self):
@@ -433,93 +440,82 @@ class QAPISchemaObjectType(QAPISchemaType):
def visit(self, visitor):
super().visit(visitor)
- visitor.visit_object_type(self.name, self.info, self.ifcond,
- self.base, self.local_members, self.variants,
- self.features)
- visitor.visit_object_type_flat(self.name, self.info, self.ifcond,
- self.members, self.variants,
- self.features)
-
-
-class QAPISchemaMember:
- """ Represents object members, enum members and features """
- role = 'member'
-
- def __init__(self, name, info, ifcond=None):
- assert isinstance(name, str)
- self.name = name
- self.info = info
- self.ifcond = ifcond or []
- self.defined_in = None
-
- def set_defined_in(self, name):
- assert not self.defined_in
- self.defined_in = name
-
- def check_clash(self, info, seen):
- cname = c_name(self.name)
- if cname in seen:
- raise QAPISemError(
- info,
- "%s collides with %s"
- % (self.describe(info), seen[cname].describe(info)))
- seen[cname] = self
+ visitor.visit_object_type(
+ self.name, self.info, self.ifcond, self.features,
+ self.base, self.local_members, self.variants)
+ visitor.visit_object_type_flat(
+ self.name, self.info, self.ifcond, self.features,
+ self.members, self.variants)
- def describe(self, info):
- role = self.role
- defined_in = self.defined_in
- assert defined_in
-
- if defined_in.startswith('q_obj_'):
- # See QAPISchema._make_implicit_object_type() - reverse the
- # mapping there to create a nice human-readable description
- defined_in = defined_in[6:]
- if defined_in.endswith('-arg'):
- # Implicit type created for a command's dict 'data'
- assert role == 'member'
- role = 'parameter'
- elif defined_in.endswith('-base'):
- # Implicit type created for a flat union's dict 'base'
- role = 'base ' + role
- else:
- # Implicit type created for a simple union's branch
- assert defined_in.endswith('-wrapper')
- # Unreachable and not implemented
- assert False
- elif defined_in.endswith('Kind'):
- # See QAPISchema._make_implicit_enum_type()
- # Implicit enum created for simple union's branches
- assert role == 'value'
- role = 'branch'
- elif defined_in != info.defn_name:
- return "%s '%s' of type '%s'" % (role, self.name, defined_in)
- return "%s '%s'" % (role, self.name)
+class QAPISchemaAlternateType(QAPISchemaType):
+ meta = 'alternate'
-class QAPISchemaEnumMember(QAPISchemaMember):
- role = 'value'
+ def __init__(self, name, info, doc, ifcond, features, variants):
+ super().__init__(name, info, doc, ifcond, features)
+ assert isinstance(variants, QAPISchemaVariants)
+ assert variants.tag_member
+ variants.set_defined_in(name)
+ variants.tag_member.set_defined_in(self.name)
+ self.variants = variants
+ def check(self, schema):
+ super().check(schema)
+ self.variants.tag_member.check(schema)
+ # Not calling self.variants.check_clash(), because there's nothing
+ # to clash with
+ self.variants.check(schema, {})
+ # Alternate branch names have no relation to the tag enum values;
+ # so we have to check for potential name collisions ourselves.
+ seen = {}
+ types_seen = {}
+ for v in self.variants.variants:
+ v.check_clash(self.info, seen)
+ qtype = v.type.alternate_qtype()
+ if not qtype:
+ raise QAPISemError(
+ self.info,
+ "%s cannot use %s"
+ % (v.describe(self.info), v.type.describe()))
+ conflicting = set([qtype])
+ if qtype == 'QTYPE_QSTRING':
+ if isinstance(v.type, QAPISchemaEnumType):
+ for m in v.type.members:
+ if m.name in ['on', 'off']:
+ conflicting.add('QTYPE_QBOOL')
+ if re.match(r'[-+0-9.]', m.name):
+ # lazy, could be tightened
+ conflicting.add('QTYPE_QNUM')
+ else:
+ conflicting.add('QTYPE_QNUM')
+ conflicting.add('QTYPE_QBOOL')
+ for qt in conflicting:
+ if qt in types_seen:
+ raise QAPISemError(
+ self.info,
+ "%s can't be distinguished from '%s'"
+ % (v.describe(self.info), types_seen[qt]))
+ types_seen[qt] = v.name
-class QAPISchemaFeature(QAPISchemaMember):
- role = 'feature'
+ def connect_doc(self, doc=None):
+ super().connect_doc(doc)
+ doc = doc or self.doc
+ for v in self.variants.variants:
+ v.connect_doc(doc)
+ def c_type(self):
+ return c_name(self.name) + pointer_suffix
-class QAPISchemaObjectTypeMember(QAPISchemaMember):
- def __init__(self, name, info, typ, optional, ifcond=None):
- super().__init__(name, info, ifcond)
- assert isinstance(typ, str)
- assert isinstance(optional, bool)
- self._type_name = typ
- self.type = None
- self.optional = optional
+ def json_type(self):
+ return 'value'
- def check(self, schema):
- assert self.defined_in
- self.type = schema.resolve_type(self._type_name, self.info,
- self.describe)
+ def visit(self, visitor):
+ super().visit(visitor)
+ visitor.visit_alternate_type(
+ self.name, self.info, self.ifcond, self.features, self.variants)
-class QAPISchemaObjectTypeVariants:
+class QAPISchemaVariants:
def __init__(self, tag_name, info, tag_member, variants):
# Flat unions pass tag_name but not tag_member.
# Simple unions and alternates pass tag_member but not tag_name.
@@ -529,7 +525,7 @@ class QAPISchemaObjectTypeVariants:
assert (isinstance(tag_name, str) or
isinstance(tag_member, QAPISchemaObjectTypeMember))
for v in variants:
- assert isinstance(v, QAPISchemaObjectTypeVariant)
+ assert isinstance(v, QAPISchemaVariant)
self._tag_name = tag_name
self.info = info
self.tag_member = tag_member
@@ -579,8 +575,8 @@ class QAPISchemaObjectTypeVariants:
cases = {v.name for v in self.variants}
for m in self.tag_member.type.members:
if m.name not in cases:
- v = QAPISchemaObjectTypeVariant(m.name, self.info,
- 'q_empty', m.ifcond)
+ v = QAPISchemaVariant(m.name, self.info,
+ 'q_empty', m.ifcond)
v.set_defined_in(self.tag_member.defined_in)
self.variants.append(v)
if not self.variants:
@@ -610,86 +606,114 @@ class QAPISchemaObjectTypeVariants:
v.type.check_clash(info, dict(seen))
-class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
- role = 'branch'
+class QAPISchemaMember:
+ """ Represents object members, enum members and features """
+ role = 'member'
- def __init__(self, name, info, typ, ifcond=None):
- super().__init__(name, info, typ, False, ifcond)
+ def __init__(self, name, info, ifcond=None):
+ assert isinstance(name, str)
+ self.name = name
+ self.info = info
+ self.ifcond = ifcond or []
+ self.defined_in = None
+ def set_defined_in(self, name):
+ assert not self.defined_in
+ self.defined_in = name
-class QAPISchemaAlternateType(QAPISchemaType):
- meta = 'alternate'
+ def check_clash(self, info, seen):
+ cname = c_name(self.name)
+ if cname in seen:
+ raise QAPISemError(
+ info,
+ "%s collides with %s"
+ % (self.describe(info), seen[cname].describe(info)))
+ seen[cname] = self
+
+ def connect_doc(self, doc):
+ if doc:
+ doc.connect_member(self)
+
+ def describe(self, info):
+ role = self.role
+ defined_in = self.defined_in
+ assert defined_in
+
+ if defined_in.startswith('q_obj_'):
+ # See QAPISchema._make_implicit_object_type() - reverse the
+ # mapping there to create a nice human-readable description
+ defined_in = defined_in[6:]
+ if defined_in.endswith('-arg'):
+ # Implicit type created for a command's dict 'data'
+ assert role == 'member'
+ role = 'parameter'
+ elif defined_in.endswith('-base'):
+ # Implicit type created for a flat union's dict 'base'
+ role = 'base ' + role
+ else:
+ # Implicit type created for a simple union's branch
+ assert defined_in.endswith('-wrapper')
+ # Unreachable and not implemented
+ assert False
+ elif defined_in.endswith('Kind'):
+ # See QAPISchema._make_implicit_enum_type()
+ # Implicit enum created for simple union's branches
+ assert role == 'value'
+ role = 'branch'
+ elif defined_in != info.defn_name:
+ return "%s '%s' of type '%s'" % (role, self.name, defined_in)
+ return "%s '%s'" % (role, self.name)
+
+
+class QAPISchemaEnumMember(QAPISchemaMember):
+ role = 'value'
+
+
+class QAPISchemaFeature(QAPISchemaMember):
+ role = 'feature'
- def __init__(self, name, info, doc, ifcond, variants):
- super().__init__(name, info, doc, ifcond)
- assert isinstance(variants, QAPISchemaObjectTypeVariants)
- assert variants.tag_member
- variants.set_defined_in(name)
- variants.tag_member.set_defined_in(self.name)
- self.variants = variants
+
+class QAPISchemaObjectTypeMember(QAPISchemaMember):
+ def __init__(self, name, info, typ, optional, ifcond=None, features=None):
+ super().__init__(name, info, ifcond)
+ assert isinstance(typ, str)
+ assert isinstance(optional, bool)
+ for f in features or []:
+ assert isinstance(f, QAPISchemaFeature)
+ f.set_defined_in(name)
+ self._type_name = typ
+ self.type = None
+ self.optional = optional
+ self.features = features or []
def check(self, schema):
- super().check(schema)
- self.variants.tag_member.check(schema)
- # Not calling self.variants.check_clash(), because there's nothing
- # to clash with
- self.variants.check(schema, {})
- # Alternate branch names have no relation to the tag enum values;
- # so we have to check for potential name collisions ourselves.
+ assert self.defined_in
+ self.type = schema.resolve_type(self._type_name, self.info,
+ self.describe)
seen = {}
- types_seen = {}
- for v in self.variants.variants:
- v.check_clash(self.info, seen)
- qtype = v.type.alternate_qtype()
- if not qtype:
- raise QAPISemError(
- self.info,
- "%s cannot use %s"
- % (v.describe(self.info), v.type.describe()))
- conflicting = set([qtype])
- if qtype == 'QTYPE_QSTRING':
- if isinstance(v.type, QAPISchemaEnumType):
- for m in v.type.members:
- if m.name in ['on', 'off']:
- conflicting.add('QTYPE_QBOOL')
- if re.match(r'[-+0-9.]', m.name):
- # lazy, could be tightened
- conflicting.add('QTYPE_QNUM')
- else:
- conflicting.add('QTYPE_QNUM')
- conflicting.add('QTYPE_QBOOL')
- for qt in conflicting:
- if qt in types_seen:
- raise QAPISemError(
- self.info,
- "%s can't be distinguished from '%s'"
- % (v.describe(self.info), types_seen[qt]))
- types_seen[qt] = v.name
+ for f in self.features:
+ f.check_clash(self.info, seen)
- def connect_doc(self, doc=None):
- doc = doc or self.doc
+ def connect_doc(self, doc):
+ super().connect_doc(doc)
if doc:
- for v in self.variants.variants:
- doc.connect_member(v)
+ for f in self.features:
+ doc.connect_feature(f)
- def c_type(self):
- return c_name(self.name) + pointer_suffix
- def json_type(self):
- return 'value'
+class QAPISchemaVariant(QAPISchemaObjectTypeMember):
+ role = 'branch'
- def visit(self, visitor):
- super().visit(visitor)
- visitor.visit_alternate_type(self.name, self.info, self.ifcond,
- self.variants)
+ def __init__(self, name, info, typ, ifcond=None):
+ super().__init__(name, info, typ, False, ifcond)
class QAPISchemaCommand(QAPISchemaEntity):
meta = 'command'
- def __init__(self, name, info, doc, ifcond, arg_type, ret_type,
- gen, success_response, boxed, allow_oob, allow_preconfig,
- features):
+ def __init__(self, name, info, doc, ifcond, features,
+ arg_type, ret_type,
+ gen, success_response, boxed, allow_oob, allow_preconfig):
super().__init__(name, info, doc, ifcond, features)
assert not arg_type or isinstance(arg_type, str)
assert not ret_type or isinstance(ret_type, str)
@@ -733,6 +757,7 @@ class QAPISchemaCommand(QAPISchemaEntity):
% self.ret_type.describe())
def connect_doc(self, doc=None):
+ super().connect_doc(doc)
doc = doc or self.doc
if doc:
if self.arg_type and self.arg_type.is_implicit():
@@ -740,19 +765,17 @@ class QAPISchemaCommand(QAPISchemaEntity):
def visit(self, visitor):
super().visit(visitor)
- visitor.visit_command(self.name, self.info, self.ifcond,
- self.arg_type, self.ret_type,
- self.gen, self.success_response,
- self.boxed, self.allow_oob,
- self.allow_preconfig,
- self.features)
+ visitor.visit_command(
+ self.name, self.info, self.ifcond, self.features,
+ self.arg_type, self.ret_type, self.gen, self.success_response,
+ self.boxed, self.allow_oob, self.allow_preconfig)
class QAPISchemaEvent(QAPISchemaEntity):
meta = 'event'
- def __init__(self, name, info, doc, ifcond, arg_type, boxed):
- super().__init__(name, info, doc, ifcond)
+ def __init__(self, name, info, doc, ifcond, features, arg_type, boxed):
+ super().__init__(name, info, doc, ifcond, features)
assert not arg_type or isinstance(arg_type, str)
self._arg_type_name = arg_type
self.arg_type = None
@@ -775,6 +798,7 @@ class QAPISchemaEvent(QAPISchemaEntity):
% self.arg_type.describe())
def connect_doc(self, doc=None):
+ super().connect_doc(doc)
doc = doc or self.doc
if doc:
if self.arg_type and self.arg_type.is_implicit():
@@ -782,8 +806,9 @@ class QAPISchemaEvent(QAPISchemaEntity):
def visit(self, visitor):
super().visit(visitor)
- visitor.visit_event(self.name, self.info, self.ifcond,
- self.arg_type, self.boxed)
+ visitor.visit_event(
+ self.name, self.info, self.ifcond, self.features,
+ self.arg_type, self.boxed)
class QAPISchema:
@@ -888,7 +913,7 @@ class QAPISchema:
('null', 'null', 'QNull' + pointer_suffix)]:
self._def_builtin_type(*t)
self.the_empty_object_type = QAPISchemaObjectType(
- 'q_empty', None, None, None, None, [], None, [])
+ 'q_empty', None, None, None, None, None, [], None)
self._def_entity(self.the_empty_object_type)
qtypes = ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist',
@@ -896,10 +921,12 @@ class QAPISchema:
qtype_values = self._make_enum_members(
[{'name': n} for n in qtypes], None)
- self._def_entity(QAPISchemaEnumType('QType', None, None, None,
+ self._def_entity(QAPISchemaEnumType('QType', None, None, None, None,
qtype_values, 'QTYPE'))
def _make_features(self, features, info):
+ if features is None:
+ return []
return [QAPISchemaFeature(f['name'], info, f.get('if'))
for f in features]
@@ -911,7 +938,8 @@ class QAPISchema:
# See also QAPISchemaObjectTypeMember.describe()
name = name + 'Kind' # reserved by check_defn_name_str()
self._def_entity(QAPISchemaEnumType(
- name, info, None, ifcond, self._make_enum_members(values, info),
+ name, info, None, ifcond, None,
+ self._make_enum_members(values, info),
None))
return name
@@ -939,8 +967,8 @@ class QAPISchema:
# TODO kill simple unions or implement the disjunction
assert (ifcond or []) == typ._ifcond # pylint: disable=protected-access
else:
- self._def_entity(QAPISchemaObjectType(name, info, None, ifcond,
- None, members, None, []))
+ self._def_entity(QAPISchemaObjectType(
+ name, info, None, ifcond, None, None, members, None))
return name
def _def_enum_type(self, expr, info, doc):
@@ -948,11 +976,12 @@ class QAPISchema:
data = expr['data']
prefix = expr.get('prefix')
ifcond = expr.get('if')
+ features = self._make_features(expr.get('features'), info)
self._def_entity(QAPISchemaEnumType(
- name, info, doc, ifcond,
+ name, info, doc, ifcond, features,
self._make_enum_members(data, info), prefix))
- def _make_member(self, name, typ, ifcond, info):
+ def _make_member(self, name, typ, ifcond, features, info):
optional = False
if name.startswith('*'):
name = name[1:]
@@ -960,10 +989,12 @@ class QAPISchema:
if isinstance(typ, list):
assert len(typ) == 1
typ = self._make_array_type(typ[0], info)
- return QAPISchemaObjectTypeMember(name, info, typ, optional, ifcond)
+ return QAPISchemaObjectTypeMember(name, info, typ, optional, ifcond,
+ self._make_features(features, info))
def _make_members(self, data, info):
- return [self._make_member(key, value['type'], value.get('if'), info)
+ return [self._make_member(key, value['type'], value.get('if'),
+ value.get('features'), info)
for (key, value) in data.items()]
def _def_struct_type(self, expr, info, doc):
@@ -971,15 +1002,14 @@ class QAPISchema:
base = expr.get('base')
data = expr['data']
ifcond = expr.get('if')
- features = expr.get('features', [])
+ features = self._make_features(expr.get('features'), info)
self._def_entity(QAPISchemaObjectType(
- name, info, doc, ifcond, base,
+ name, info, doc, ifcond, features, base,
self._make_members(data, info),
- None,
- self._make_features(features, info)))
+ None))
def _make_variant(self, case, typ, ifcond, info):
- return QAPISchemaObjectTypeVariant(case, info, typ, ifcond)
+ return QAPISchemaVariant(case, info, typ, ifcond)
def _make_simple_variant(self, case, typ, ifcond, info):
if isinstance(typ, list):
@@ -987,14 +1017,15 @@ class QAPISchema:
typ = self._make_array_type(typ[0], info)
typ = self._make_implicit_object_type(
typ, info, self.lookup_type(typ),
- 'wrapper', [self._make_member('data', typ, None, info)])
- return QAPISchemaObjectTypeVariant(case, info, typ, ifcond)
+ 'wrapper', [self._make_member('data', typ, None, None, info)])
+ return QAPISchemaVariant(case, info, typ, ifcond)
def _def_union_type(self, expr, info, doc):
name = expr['union']
data = expr['data']
base = expr.get('base')
ifcond = expr.get('if')
+ features = self._make_features(expr.get('features'), info)
tag_name = expr.get('discriminator')
tag_member = None
if isinstance(base, dict):
@@ -1015,22 +1046,23 @@ class QAPISchema:
tag_member = QAPISchemaObjectTypeMember('type', info, typ, False)
members = [tag_member]
self._def_entity(
- QAPISchemaObjectType(name, info, doc, ifcond, base, members,
- QAPISchemaObjectTypeVariants(
- tag_name, info, tag_member, variants),
- []))
+ QAPISchemaObjectType(name, info, doc, ifcond, features,
+ base, members,
+ QAPISchemaVariants(
+ tag_name, info, tag_member, variants)))
def _def_alternate_type(self, expr, info, doc):
name = expr['alternate']
data = expr['data']
ifcond = expr.get('if')
+ features = self._make_features(expr.get('features'), info)
variants = [self._make_variant(key, value['type'], value.get('if'),
info)
for (key, value) in data.items()]
tag_member = QAPISchemaObjectTypeMember('type', info, 'QType', False)
self._def_entity(
- QAPISchemaAlternateType(name, info, doc, ifcond,
- QAPISchemaObjectTypeVariants(
+ QAPISchemaAlternateType(name, info, doc, ifcond, features,
+ QAPISchemaVariants(
None, info, tag_member, variants)))
def _def_command(self, expr, info, doc):
@@ -1043,27 +1075,31 @@ class QAPISchema:
allow_oob = expr.get('allow-oob', False)
allow_preconfig = expr.get('allow-preconfig', False)
ifcond = expr.get('if')
- features = expr.get('features', [])
+ features = self._make_features(expr.get('features'), info)
if isinstance(data, OrderedDict):
data = self._make_implicit_object_type(
- name, info, ifcond, 'arg', self._make_members(data, info))
+ name, info, ifcond,
+ 'arg', self._make_members(data, info))
if isinstance(rets, list):
assert len(rets) == 1
rets = self._make_array_type(rets[0], info)
- self._def_entity(QAPISchemaCommand(name, info, doc, ifcond, data, rets,
+ self._def_entity(QAPISchemaCommand(name, info, doc, ifcond, features,
+ data, rets,
gen, success_response,
- boxed, allow_oob, allow_preconfig,
- self._make_features(features, info)))
+ boxed, allow_oob, allow_preconfig))
def _def_event(self, expr, info, doc):
name = expr['event']
data = expr.get('data')
boxed = expr.get('boxed', False)
ifcond = expr.get('if')
+ features = self._make_features(expr.get('features'), info)
if isinstance(data, OrderedDict):
data = self._make_implicit_object_type(
- name, info, ifcond, 'arg', self._make_members(data, info))
- self._def_entity(QAPISchemaEvent(name, info, doc, ifcond, data, boxed))
+ name, info, ifcond,
+ 'arg', self._make_members(data, info))
+ self._def_entity(QAPISchemaEvent(name, info, doc, ifcond, features,
+ data, boxed))
def _def_exprs(self, exprs):
for expr_elem in exprs:
diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py
index 3c83b6e4be..3ad33af4ee 100644
--- a/scripts/qapi/types.py
+++ b/scripts/qapi/types.py
@@ -278,7 +278,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor):
self._genh.add(gen_type_cleanup_decl(name))
self._genc.add(gen_type_cleanup(name))
- def visit_enum_type(self, name, info, ifcond, members, prefix):
+ def visit_enum_type(self, name, info, ifcond, features, members, prefix):
with ifcontext(ifcond, self._genh, self._genc):
self._genh.preamble_add(gen_enum(name, members, prefix))
self._genc.add(gen_enum_lookup(name, members, prefix))
@@ -289,8 +289,8 @@ class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor):
self._genh.add(gen_array(name, element_type))
self._gen_type_cleanup(name)
- def visit_object_type(self, name, info, ifcond, base, members, variants,
- features):
+ def visit_object_type(self, name, info, ifcond, features,
+ base, members, variants):
# Nothing to do for the special empty builtin
if name == 'q_empty':
return
@@ -306,7 +306,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor):
# implicit types won't be directly allocated/freed
self._gen_type_cleanup(name)
- def visit_alternate_type(self, name, info, ifcond, variants):
+ def visit_alternate_type(self, name, info, ifcond, features, variants):
with ifcontext(ifcond, self._genh):
self._genh.preamble_add(gen_fwd_object_or_array(name))
self._genh.add(gen_object(name, ifcond, None,
diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py
index 421e5bd8cd..23d9194aa4 100644
--- a/scripts/qapi/visit.py
+++ b/scripts/qapi/visit.py
@@ -316,7 +316,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor):
''',
types=types))
- def visit_enum_type(self, name, info, ifcond, members, prefix):
+ def visit_enum_type(self, name, info, ifcond, features, members, prefix):
with ifcontext(ifcond, self._genh, self._genc):
self._genh.add(gen_visit_decl(name, scalar=True))
self._genc.add(gen_visit_enum(name))
@@ -326,8 +326,8 @@ class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor):
self._genh.add(gen_visit_decl(name))
self._genc.add(gen_visit_list(name, element_type))
- def visit_object_type(self, name, info, ifcond, base, members, variants,
- features):
+ def visit_object_type(self, name, info, ifcond, features,
+ base, members, variants):
# Nothing to do for the special empty builtin
if name == 'q_empty':
return
@@ -342,7 +342,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor):
self._genh.add(gen_visit_decl(name))
self._genc.add(gen_visit_object(name, base, members, variants))
- def visit_alternate_type(self, name, info, ifcond, variants):
+ def visit_alternate_type(self, name, info, ifcond, features, variants):
with ifcontext(ifcond, self._genh, self._genc):
self._genh.add(gen_visit_decl(name))
self._genc.add(gen_visit_alternate(name, variants))
diff --git a/target/alpha/cpu.h b/target/alpha/cpu.h
index 3f782c0efe..be29bdd530 100644
--- a/target/alpha/cpu.h
+++ b/target/alpha/cpu.h
@@ -280,7 +280,7 @@ void alpha_cpu_do_interrupt(CPUState *cpu);
bool alpha_cpu_exec_interrupt(CPUState *cpu, int int_req);
void alpha_cpu_dump_state(CPUState *cs, FILE *f, int flags);
hwaddr alpha_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int alpha_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int alpha_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int alpha_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void alpha_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
MMUAccessType access_type,
diff --git a/target/alpha/gdbstub.c b/target/alpha/gdbstub.c
index 7f9cc092a9..0cd76ddaa9 100644
--- a/target/alpha/gdbstub.c
+++ b/target/alpha/gdbstub.c
@@ -21,7 +21,7 @@
#include "cpu.h"
#include "exec/gdbstub.h"
-int alpha_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int alpha_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
AlphaCPU *cpu = ALPHA_CPU(cs);
CPUAlphaState *env = &cpu->env;
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 8e5ba619a0..a79f233b17 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -195,9 +195,10 @@ static void arm_cpu_reset(DeviceState *dev)
env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 20, 2, 3);
/* and to the SVE instructions */
env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 16, 2, 3);
- /* with maximum vector length */
- env->vfp.zcr_el[1] = cpu_isar_feature(aa64_sve, cpu) ?
- cpu->sve_max_vq - 1 : 0;
+ /* with reasonable vector length */
+ if (cpu_isar_feature(aa64_sve, cpu)) {
+ env->vfp.zcr_el[1] = MIN(cpu->sve_max_vq - 1, 3);
+ }
/*
* Enable TBI0 and TBI1. While the real kernel only enables TBI0,
* turning on both here will produce smaller code and otherwise
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 4ffd991b6f..8b9f2961ba 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -128,14 +128,20 @@ enum {
/**
* DynamicGDBXMLInfo:
* @desc: Contains the XML descriptions.
- * @num_cpregs: Number of the Coprocessor registers seen by GDB.
- * @cpregs_keys: Array that contains the corresponding Key of
- * a given cpreg with the same order of the cpreg in the XML description.
+ * @num: Number of the registers in this XML seen by GDB.
+ * @data: A union with data specific to the set of registers
+ * @cpregs_keys: Array that contains the corresponding Key of
+ * a given cpreg with the same order of the cpreg
+ * in the XML description.
*/
typedef struct DynamicGDBXMLInfo {
char *desc;
- int num_cpregs;
- uint32_t *cpregs_keys;
+ int num;
+ union {
+ struct {
+ uint32_t *keys;
+ } cpregs;
+ } data;
} DynamicGDBXMLInfo;
/* CPU state for each instance of a generic timer (in cp15 c14) */
@@ -749,7 +755,8 @@ struct ARMCPU {
uint64_t *cpreg_vmstate_values;
int32_t cpreg_vmstate_array_len;
- DynamicGDBXMLInfo dyn_xml;
+ DynamicGDBXMLInfo dyn_sysreg_xml;
+ DynamicGDBXMLInfo dyn_svereg_xml;
/* Timers used by the generic (architected) timer */
QEMUTimer *gt_timer[NUM_GTIMERS];
@@ -968,13 +975,15 @@ bool arm_cpu_exec_interrupt(CPUState *cpu, int int_req);
hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr,
MemTxAttrs *attrs);
-int arm_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int arm_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
-/* Dynamically generates for gdb stub an XML description of the sysregs from
- * the cp_regs hashtable. Returns the registered sysregs number.
+/*
+ * Helpers to dynamically generates XML descriptions of the sysregs
+ * and SVE registers. Returns the number of registers in each set.
*/
-int arm_gen_dynamic_xml(CPUState *cpu);
+int arm_gen_dynamic_sysreg_xml(CPUState *cpu, int base_reg);
+int arm_gen_dynamic_svereg_xml(CPUState *cpu, int base_reg);
/* Returns the dynamically generated XML for the gdb stub.
* Returns a pointer to the XML contents for the specified XML file or NULL
@@ -988,7 +997,7 @@ int arm_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
int cpuid, void *opaque);
#ifdef TARGET_AARCH64
-int aarch64_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int aarch64_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int aarch64_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq);
void aarch64_sve_change_el(CPUARMState *env, int old_el,
diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
index 1239abd984..d9ef7d2187 100644
--- a/target/arm/gdbstub.c
+++ b/target/arm/gdbstub.c
@@ -24,6 +24,7 @@
typedef struct RegisterSysregXmlParam {
CPUState *cs;
GString *s;
+ int n;
} RegisterSysregXmlParam;
/* Old gdb always expect FPA registers. Newer (xml-aware) gdb only expect
@@ -32,7 +33,7 @@ typedef struct RegisterSysregXmlParam {
We hack round this by giving the FPA regs zero size when talking to a
newer gdb. */
-int arm_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int arm_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
@@ -106,15 +107,16 @@ int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
return 0;
}
-static void arm_gen_one_xml_reg_tag(GString *s, DynamicGDBXMLInfo *dyn_xml,
- ARMCPRegInfo *ri, uint32_t ri_key,
- int bitsize)
+static void arm_gen_one_xml_sysreg_tag(GString *s, DynamicGDBXMLInfo *dyn_xml,
+ ARMCPRegInfo *ri, uint32_t ri_key,
+ int bitsize, int regnum)
{
g_string_append_printf(s, "<reg name=\"%s\"", ri->name);
g_string_append_printf(s, " bitsize=\"%d\"", bitsize);
+ g_string_append_printf(s, " regnum=\"%d\"", regnum);
g_string_append_printf(s, " group=\"cp_regs\"/>");
- dyn_xml->num_cpregs++;
- dyn_xml->cpregs_keys[dyn_xml->num_cpregs - 1] = ri_key;
+ dyn_xml->data.cpregs.keys[dyn_xml->num] = ri_key;
+ dyn_xml->num++;
}
static void arm_register_sysreg_for_xml(gpointer key, gpointer value,
@@ -126,12 +128,13 @@ static void arm_register_sysreg_for_xml(gpointer key, gpointer value,
GString *s = param->s;
ARMCPU *cpu = ARM_CPU(param->cs);
CPUARMState *env = &cpu->env;
- DynamicGDBXMLInfo *dyn_xml = &cpu->dyn_xml;
+ DynamicGDBXMLInfo *dyn_xml = &cpu->dyn_sysreg_xml;
if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_NO_GDB))) {
if (arm_feature(env, ARM_FEATURE_AARCH64)) {
if (ri->state == ARM_CP_STATE_AA64) {
- arm_gen_one_xml_reg_tag(s , dyn_xml, ri, ri_key, 64);
+ arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64,
+ param->n++);
}
} else {
if (ri->state == ARM_CP_STATE_AA32) {
@@ -140,38 +143,174 @@ static void arm_register_sysreg_for_xml(gpointer key, gpointer value,
return;
}
if (ri->type & ARM_CP_64BIT) {
- arm_gen_one_xml_reg_tag(s , dyn_xml, ri, ri_key, 64);
+ arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64,
+ param->n++);
} else {
- arm_gen_one_xml_reg_tag(s , dyn_xml, ri, ri_key, 32);
+ arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 32,
+ param->n++);
}
}
}
}
}
-int arm_gen_dynamic_xml(CPUState *cs)
+int arm_gen_dynamic_sysreg_xml(CPUState *cs, int base_reg)
{
ARMCPU *cpu = ARM_CPU(cs);
GString *s = g_string_new(NULL);
- RegisterSysregXmlParam param = {cs, s};
+ RegisterSysregXmlParam param = {cs, s, base_reg};
- cpu->dyn_xml.num_cpregs = 0;
- cpu->dyn_xml.cpregs_keys = g_new(uint32_t, g_hash_table_size(cpu->cp_regs));
+ cpu->dyn_sysreg_xml.num = 0;
+ cpu->dyn_sysreg_xml.data.cpregs.keys = g_new(uint32_t, g_hash_table_size(cpu->cp_regs));
g_string_printf(s, "<?xml version=\"1.0\"?>");
g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
g_string_append_printf(s, "<feature name=\"org.qemu.gdb.arm.sys.regs\">");
g_hash_table_foreach(cpu->cp_regs, arm_register_sysreg_for_xml, &param);
g_string_append_printf(s, "</feature>");
- cpu->dyn_xml.desc = g_string_free(s, false);
- return cpu->dyn_xml.num_cpregs;
+ cpu->dyn_sysreg_xml.desc = g_string_free(s, false);
+ return cpu->dyn_sysreg_xml.num;
}
+struct TypeSize {
+ const char *gdb_type;
+ int size;
+ const char sz, suffix;
+};
+
+static const struct TypeSize vec_lanes[] = {
+ /* quads */
+ { "uint128", 128, 'q', 'u' },
+ { "int128", 128, 'q', 's' },
+ /* 64 bit */
+ { "uint64", 64, 'd', 'u' },
+ { "int64", 64, 'd', 's' },
+ { "ieee_double", 64, 'd', 'f' },
+ /* 32 bit */
+ { "uint32", 32, 's', 'u' },
+ { "int32", 32, 's', 's' },
+ { "ieee_single", 32, 's', 'f' },
+ /* 16 bit */
+ { "uint16", 16, 'h', 'u' },
+ { "int16", 16, 'h', 's' },
+ { "ieee_half", 16, 'h', 'f' },
+ /* bytes */
+ { "uint8", 8, 'b', 'u' },
+ { "int8", 8, 'b', 's' },
+};
+
+
+int arm_gen_dynamic_svereg_xml(CPUState *cs, int base_reg)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ GString *s = g_string_new(NULL);
+ DynamicGDBXMLInfo *info = &cpu->dyn_svereg_xml;
+ g_autoptr(GString) ts = g_string_new("");
+ int i, bits, reg_width = (cpu->sve_max_vq * 128);
+ info->num = 0;
+ g_string_printf(s, "<?xml version=\"1.0\"?>");
+ g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
+ g_string_append_printf(s, "<feature name=\"org.qemu.gdb.aarch64.sve\">");
+
+ /* First define types and totals in a whole VL */
+ for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) {
+ int count = reg_width / vec_lanes[i].size;
+ g_string_printf(ts, "vq%d%c%c", count,
+ vec_lanes[i].sz, vec_lanes[i].suffix);
+ g_string_append_printf(s,
+ "<vector id=\"%s\" type=\"%s\" count=\"%d\"/>",
+ ts->str, vec_lanes[i].gdb_type, count);
+ }
+ /*
+ * Now define a union for each size group containing unsigned and
+ * signed and potentially float versions of each size from 128 to
+ * 8 bits.
+ */
+ for (bits = 128; bits >= 8; bits /= 2) {
+ int count = reg_width / bits;
+ g_string_append_printf(s, "<union id=\"vq%dn\">", count);
+ for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) {
+ if (vec_lanes[i].size == bits) {
+ g_string_append_printf(s, "<field name=\"%c\" type=\"vq%d%c%c\"/>",
+ vec_lanes[i].suffix,
+ count,
+ vec_lanes[i].sz, vec_lanes[i].suffix);
+ }
+ }
+ g_string_append(s, "</union>");
+ }
+ /* And now the final union of unions */
+ g_string_append(s, "<union id=\"vq\">");
+ for (bits = 128; bits >= 8; bits /= 2) {
+ int count = reg_width / bits;
+ for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) {
+ if (vec_lanes[i].size == bits) {
+ g_string_append_printf(s, "<field name=\"%c\" type=\"vq%dn\"/>",
+ vec_lanes[i].sz, count);
+ break;
+ }
+ }
+ }
+ g_string_append(s, "</union>");
+
+ /* Then define each register in parts for each vq */
+ for (i = 0; i < 32; i++) {
+ g_string_append_printf(s,
+ "<reg name=\"z%d\" bitsize=\"%d\""
+ " regnum=\"%d\" group=\"vector\""
+ " type=\"vq\"/>",
+ i, reg_width, base_reg++);
+ info->num++;
+ }
+ /* fpscr & status registers */
+ g_string_append_printf(s, "<reg name=\"fpsr\" bitsize=\"32\""
+ " regnum=\"%d\" group=\"float\""
+ " type=\"int\"/>", base_reg++);
+ g_string_append_printf(s, "<reg name=\"fpcr\" bitsize=\"32\""
+ " regnum=\"%d\" group=\"float\""
+ " type=\"int\"/>", base_reg++);
+ info->num += 2;
+ /*
+ * Predicate registers aren't so big they are worth splitting up
+ * but we do need to define a type to hold the array of quad
+ * references.
+ */
+ g_string_append_printf(s,
+ "<vector id=\"vqp\" type=\"uint16\" count=\"%d\"/>",
+ cpu->sve_max_vq);
+ for (i = 0; i < 16; i++) {
+ g_string_append_printf(s,
+ "<reg name=\"p%d\" bitsize=\"%d\""
+ " regnum=\"%d\" group=\"vector\""
+ " type=\"vqp\"/>",
+ i, cpu->sve_max_vq * 16, base_reg++);
+ info->num++;
+ }
+ g_string_append_printf(s,
+ "<reg name=\"ffr\" bitsize=\"%d\""
+ " regnum=\"%d\" group=\"vector\""
+ " type=\"vqp\"/>",
+ cpu->sve_max_vq * 16, base_reg++);
+ g_string_append_printf(s,
+ "<reg name=\"vg\" bitsize=\"64\""
+ " regnum=\"%d\" group=\"vector\""
+ " type=\"uint32\"/>",
+ base_reg++);
+ info->num += 2;
+ g_string_append_printf(s, "</feature>");
+ cpu->dyn_svereg_xml.desc = g_string_free(s, false);
+
+ return cpu->dyn_svereg_xml.num;
+}
+
+
const char *arm_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname)
{
ARMCPU *cpu = ARM_CPU(cs);
if (strcmp(xmlname, "system-registers.xml") == 0) {
- return cpu->dyn_xml.desc;
+ return cpu->dyn_sysreg_xml.desc;
+ } else if (strcmp(xmlname, "sve-registers.xml") == 0) {
+ return cpu->dyn_svereg_xml.desc;
}
return NULL;
}
diff --git a/target/arm/gdbstub64.c b/target/arm/gdbstub64.c
index 665ebb3ef6..35d0b80c2d 100644
--- a/target/arm/gdbstub64.c
+++ b/target/arm/gdbstub64.c
@@ -20,7 +20,7 @@
#include "cpu.h"
#include "exec/gdbstub.h"
-int aarch64_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int aarch64_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
diff --git a/target/arm/helper.c b/target/arm/helper.c
index b61ee73d18..d2ec2c5351 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -48,30 +48,27 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
static void switch_mode(CPUARMState *env, int mode);
-static int vfp_gdb_get_reg(CPUARMState *env, uint8_t *buf, int reg)
+static int vfp_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg)
{
ARMCPU *cpu = env_archcpu(env);
int nregs = cpu_isar_feature(aa32_simd_r32, cpu) ? 32 : 16;
/* VFP data registers are always little-endian. */
if (reg < nregs) {
- stq_le_p(buf, *aa32_vfp_dreg(env, reg));
- return 8;
+ return gdb_get_reg64(buf, *aa32_vfp_dreg(env, reg));
}
if (arm_feature(env, ARM_FEATURE_NEON)) {
/* Aliases for Q regs. */
nregs += 16;
if (reg < nregs) {
uint64_t *q = aa32_vfp_qreg(env, reg - 32);
- stq_le_p(buf, q[0]);
- stq_le_p(buf + 8, q[1]);
- return 16;
+ return gdb_get_reg128(buf, q[0], q[1]);
}
}
switch (reg - nregs) {
- case 0: stl_p(buf, env->vfp.xregs[ARM_VFP_FPSID]); return 4;
- case 1: stl_p(buf, vfp_get_fpscr(env)); return 4;
- case 2: stl_p(buf, env->vfp.xregs[ARM_VFP_FPEXC]); return 4;
+ case 0: return gdb_get_reg32(buf, env->vfp.xregs[ARM_VFP_FPSID]); break;
+ case 1: return gdb_get_reg32(buf, vfp_get_fpscr(env)); break;
+ case 2: return gdb_get_reg32(buf, env->vfp.xregs[ARM_VFP_FPEXC]); break;
}
return 0;
}
@@ -102,25 +99,21 @@ static int vfp_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg)
return 0;
}
-static int aarch64_fpu_gdb_get_reg(CPUARMState *env, uint8_t *buf, int reg)
+static int aarch64_fpu_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg)
{
switch (reg) {
case 0 ... 31:
- /* 128 bit FP register */
- {
- uint64_t *q = aa64_vfp_qreg(env, reg);
- stq_le_p(buf, q[0]);
- stq_le_p(buf + 8, q[1]);
- return 16;
- }
+ {
+ /* 128 bit FP register - quads are in LE order */
+ uint64_t *q = aa64_vfp_qreg(env, reg);
+ return gdb_get_reg128(buf, q[1], q[0]);
+ }
case 32:
/* FPSR */
- stl_p(buf, vfp_get_fpsr(env));
- return 4;
+ return gdb_get_reg32(buf, vfp_get_fpsr(env));
case 33:
/* FPCR */
- stl_p(buf, vfp_get_fpcr(env));
- return 4;
+ return gdb_get_reg32(buf,vfp_get_fpcr(env));
default:
return 0;
}
@@ -209,13 +202,22 @@ static void write_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri,
}
}
-static int arm_gdb_get_sysreg(CPUARMState *env, uint8_t *buf, int reg)
+/**
+ * arm_get/set_gdb_*: get/set a gdb register
+ * @env: the CPU state
+ * @buf: a buffer to copy to/from
+ * @reg: register number (offset from start of group)
+ *
+ * We return the number of bytes copied
+ */
+
+static int arm_gdb_get_sysreg(CPUARMState *env, GByteArray *buf, int reg)
{
ARMCPU *cpu = env_archcpu(env);
const ARMCPRegInfo *ri;
uint32_t key;
- key = cpu->dyn_xml.cpregs_keys[reg];
+ key = cpu->dyn_sysreg_xml.data.cpregs.keys[reg];
ri = get_arm_cp_reginfo(cpu->cp_regs, key);
if (ri) {
if (cpreg_field_is_64bit(ri)) {
@@ -232,6 +234,102 @@ static int arm_gdb_set_sysreg(CPUARMState *env, uint8_t *buf, int reg)
return 0;
}
+#ifdef TARGET_AARCH64
+static int arm_gdb_get_svereg(CPUARMState *env, GByteArray *buf, int reg)
+{
+ ARMCPU *cpu = env_archcpu(env);
+
+ switch (reg) {
+ /* The first 32 registers are the zregs */
+ case 0 ... 31:
+ {
+ int vq, len = 0;
+ for (vq = 0; vq < cpu->sve_max_vq; vq++) {
+ len += gdb_get_reg128(buf,
+ env->vfp.zregs[reg].d[vq * 2 + 1],
+ env->vfp.zregs[reg].d[vq * 2]);
+ }
+ return len;
+ }
+ case 32:
+ return gdb_get_reg32(buf, vfp_get_fpsr(env));
+ case 33:
+ return gdb_get_reg32(buf, vfp_get_fpcr(env));
+ /* then 16 predicates and the ffr */
+ case 34 ... 50:
+ {
+ int preg = reg - 34;
+ int vq, len = 0;
+ for (vq = 0; vq < cpu->sve_max_vq; vq = vq + 4) {
+ len += gdb_get_reg64(buf, env->vfp.pregs[preg].p[vq / 4]);
+ }
+ return len;
+ }
+ case 51:
+ {
+ /*
+ * We report in Vector Granules (VG) which is 64bit in a Z reg
+ * while the ZCR works in Vector Quads (VQ) which is 128bit chunks.
+ */
+ int vq = sve_zcr_len_for_el(env, arm_current_el(env)) + 1;
+ return gdb_get_reg32(buf, vq * 2);
+ }
+ default:
+ /* gdbstub asked for something out our range */
+ qemu_log_mask(LOG_UNIMP, "%s: out of range register %d", __func__, reg);
+ break;
+ }
+
+ return 0;
+}
+
+static int arm_gdb_set_svereg(CPUARMState *env, uint8_t *buf, int reg)
+{
+ ARMCPU *cpu = env_archcpu(env);
+
+ /* The first 32 registers are the zregs */
+ switch (reg) {
+ /* The first 32 registers are the zregs */
+ case 0 ... 31:
+ {
+ int vq, len = 0;
+ uint64_t *p = (uint64_t *) buf;
+ for (vq = 0; vq < cpu->sve_max_vq; vq++) {
+ env->vfp.zregs[reg].d[vq * 2 + 1] = *p++;
+ env->vfp.zregs[reg].d[vq * 2] = *p++;
+ len += 16;
+ }
+ return len;
+ }
+ case 32:
+ vfp_set_fpsr(env, *(uint32_t *)buf);
+ return 4;
+ case 33:
+ vfp_set_fpcr(env, *(uint32_t *)buf);
+ return 4;
+ case 34 ... 50:
+ {
+ int preg = reg - 34;
+ int vq, len = 0;
+ uint64_t *p = (uint64_t *) buf;
+ for (vq = 0; vq < cpu->sve_max_vq; vq = vq + 4) {
+ env->vfp.pregs[preg].p[vq / 4] = *p++;
+ len += 8;
+ }
+ return len;
+ }
+ case 51:
+ /* cannot set vg via gdbstub */
+ return 0;
+ default:
+ /* gdbstub asked for something out our range */
+ break;
+ }
+
+ return 0;
+}
+#endif /* TARGET_AARCH64 */
+
static bool raw_accessors_invalid(const ARMCPRegInfo *ri)
{
/* Return true if the regdef would cause an assertion if you called
@@ -6599,6 +6697,7 @@ static uint64_t id_pfr1_read(CPUARMState *env, const ARMCPRegInfo *ri)
return pfr1;
}
+#ifndef CONFIG_USER_ONLY
static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
ARMCPU *cpu = env_archcpu(env);
@@ -6609,6 +6708,7 @@ static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri)
}
return pfr0;
}
+#endif
/* Shared logic between LORID and the rest of the LOR* registers.
* Secure state has already been delt with.
@@ -7182,16 +7282,24 @@ void register_cp_regs_for_features(ARMCPU *cpu)
* define new registers here.
*/
ARMCPRegInfo v8_idregs[] = {
- /* ID_AA64PFR0_EL1 is not a plain ARM_CP_CONST because we don't
- * know the right value for the GIC field until after we
- * define these regs.
+ /*
+ * ID_AA64PFR0_EL1 is not a plain ARM_CP_CONST in system
+ * emulation because we don't know the right value for the
+ * GIC field until after we define these regs.
*/
{ .name = "ID_AA64PFR0_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 0,
- .access = PL1_R, .type = ARM_CP_NO_RAW,
+ .access = PL1_R,
+#ifdef CONFIG_USER_ONLY
+ .type = ARM_CP_CONST,
+ .resetvalue = cpu->isar.id_aa64pfr0
+#else
+ .type = ARM_CP_NO_RAW,
.accessfn = access_aa64_tid3,
.readfn = id_aa64pfr0_read,
- .writefn = arm_cp_write_ignore },
+ .writefn = arm_cp_write_ignore
+#endif
+ },
{ .name = "ID_AA64PFR1_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 1,
.access = PL1_R, .type = ARM_CP_CONST,
@@ -7966,9 +8074,22 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
CPUARMState *env = &cpu->env;
if (arm_feature(env, ARM_FEATURE_AARCH64)) {
- gdb_register_coprocessor(cs, aarch64_fpu_gdb_get_reg,
- aarch64_fpu_gdb_set_reg,
- 34, "aarch64-fpu.xml", 0);
+ /*
+ * The lower part of each SVE register aliases to the FPU
+ * registers so we don't need to include both.
+ */
+#ifdef TARGET_AARCH64
+ if (isar_feature_aa64_sve(&cpu->isar)) {
+ gdb_register_coprocessor(cs, arm_gdb_get_svereg, arm_gdb_set_svereg,
+ arm_gen_dynamic_svereg_xml(cs, cs->gdb_num_regs),
+ "sve-registers.xml", 0);
+ } else
+#endif
+ {
+ gdb_register_coprocessor(cs, aarch64_fpu_gdb_get_reg,
+ aarch64_fpu_gdb_set_reg,
+ 34, "aarch64-fpu.xml", 0);
+ }
} else if (arm_feature(env, ARM_FEATURE_NEON)) {
gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg,
51, "arm-neon.xml", 0);
@@ -7980,8 +8101,9 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
19, "arm-vfp.xml", 0);
}
gdb_register_coprocessor(cs, arm_gdb_get_sysreg, arm_gdb_set_sysreg,
- arm_gen_dynamic_xml(cs),
+ arm_gen_dynamic_sysreg_xml(cs, cs->gdb_num_regs),
"system-registers.xml", 0);
+
}
/* Sort alphabetically by type name, except for "any". */
diff --git a/target/arm/monitor.c b/target/arm/monitor.c
index c2dc7908de..ea6598c412 100644
--- a/target/arm/monitor.c
+++ b/target/arm/monitor.c
@@ -206,9 +206,7 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
return NULL;
}
} else {
- Error *err = NULL;
- arm_cpu_finalize_features(ARM_CPU(obj), &err);
- assert(err == NULL);
+ arm_cpu_finalize_features(ARM_CPU(obj), &error_abort);
}
expansion_info = g_new0(CpuModelExpansionInfo, 1);
@@ -221,12 +219,10 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
while ((name = cpu_model_advertised_features[i++]) != NULL) {
ObjectProperty *prop = object_property_find(obj, name, NULL);
if (prop) {
- Error *err = NULL;
QObject *value;
assert(prop->get);
- value = object_property_get_qobject(obj, name, &err);
- assert(!err);
+ value = object_property_get_qobject(obj, name, &error_abort);
qdict_put_obj(qdict_out, name, value);
}
diff --git a/target/cris/cpu.h b/target/cris/cpu.h
index ca240bc788..8f08d7628b 100644
--- a/target/cris/cpu.h
+++ b/target/cris/cpu.h
@@ -195,8 +195,8 @@ void cris_cpu_dump_state(CPUState *cs, FILE *f, int flags);
hwaddr cris_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int crisv10_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
-int cris_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int crisv10_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
+int cris_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int cris_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
/* you can call this signal handler from your SIGBUS and SIGSEGV
diff --git a/target/cris/gdbstub.c b/target/cris/gdbstub.c
index a3d76d2e8c..b01b2aa081 100644
--- a/target/cris/gdbstub.c
+++ b/target/cris/gdbstub.c
@@ -21,7 +21,7 @@
#include "cpu.h"
#include "exec/gdbstub.h"
-int crisv10_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int crisv10_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
CRISCPU *cpu = CRIS_CPU(cs);
CPUCRISState *env = &cpu->env;
@@ -53,7 +53,7 @@ int crisv10_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
return 0;
}
-int cris_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int cris_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
CRISCPU *cpu = CRIS_CPU(cs);
CPUCRISState *env = &cpu->env;
diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h
index 6713d04f11..801a4fb1ba 100644
--- a/target/hppa/cpu.h
+++ b/target/hppa/cpu.h
@@ -321,7 +321,7 @@ void cpu_hppa_change_prot_id(CPUHPPAState *env);
int cpu_hppa_signal_handler(int host_signum, void *pinfo, void *puc);
hwaddr hppa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr);
-int hppa_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int hppa_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int hppa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void hppa_cpu_do_interrupt(CPUState *cpu);
bool hppa_cpu_exec_interrupt(CPUState *cpu, int int_req);
diff --git a/target/hppa/gdbstub.c b/target/hppa/gdbstub.c
index 341888a9da..a6428a2893 100644
--- a/target/hppa/gdbstub.c
+++ b/target/hppa/gdbstub.c
@@ -21,7 +21,7 @@
#include "cpu.h"
#include "exec/gdbstub.h"
-int hppa_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int hppa_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
HPPACPU *cpu = HPPA_CPU(cs);
CPUHPPAState *env = &cpu->env;
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 7e9e963d78..60d797d594 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -1769,7 +1769,7 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f, int flags);
hwaddr x86_cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr,
MemTxAttrs *attrs);
-int x86_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int x86_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int x86_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void x86_cpu_exec_enter(CPUState *cpu);
diff --git a/target/i386/gdbstub.c b/target/i386/gdbstub.c
index 572ead641c..f3d23b614e 100644
--- a/target/i386/gdbstub.c
+++ b/target/i386/gdbstub.c
@@ -79,7 +79,7 @@ static const int gpr_map32[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
#endif
-int x86_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int x86_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
X86CPU *cpu = X86_CPU(cs);
CPUX86State *env = &cpu->env;
@@ -98,26 +98,22 @@ int x86_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
return gdb_get_reg64(mem_buf,
env->regs[gpr_map[n]] & 0xffffffffUL);
} else {
- memset(mem_buf, 0, sizeof(target_ulong));
- return sizeof(target_ulong);
+ return gdb_get_regl(mem_buf, 0);
}
} else {
return gdb_get_reg32(mem_buf, env->regs[gpr_map32[n]]);
}
} else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) {
-#ifdef USE_X86LDOUBLE
- /* FIXME: byteswap float values - after fixing fpregs layout. */
- memcpy(mem_buf, &env->fpregs[n - IDX_FP_REGS], 10);
-#else
- memset(mem_buf, 0, 10);
-#endif
- return 10;
+ floatx80 *fp = (floatx80 *) &env->fpregs[n - IDX_FP_REGS];
+ int len = gdb_get_reg64(mem_buf, cpu_to_le64(fp->low));
+ len += gdb_get_reg16(mem_buf + len, cpu_to_le16(fp->high));
+ return len;
} else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) {
n -= IDX_XMM_REGS;
if (n < CPU_NB_REGS32 || TARGET_LONG_BITS == 64) {
- stq_p(mem_buf, env->xmm_regs[n].ZMM_Q(0));
- stq_p(mem_buf + 8, env->xmm_regs[n].ZMM_Q(1));
- return 16;
+ return gdb_get_reg128(mem_buf,
+ env->xmm_regs[n].ZMM_Q(0),
+ env->xmm_regs[n].ZMM_Q(1));
}
} else {
switch (n) {
@@ -290,10 +286,9 @@ int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
return 4;
}
} else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) {
-#ifdef USE_X86LDOUBLE
- /* FIXME: byteswap float values - after fixing fpregs layout. */
- memcpy(&env->fpregs[n - IDX_FP_REGS], mem_buf, 10);
-#endif
+ floatx80 *fp = (floatx80 *) &env->fpregs[n - IDX_FP_REGS];
+ fp->low = le64_to_cpu(* (uint64_t *) mem_buf);
+ fp->high = le16_to_cpu(* (uint16_t *) (mem_buf + 8));
return 10;
} else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) {
n -= IDX_XMM_REGS;
diff --git a/target/lm32/cpu.h b/target/lm32/cpu.h
index 064c6b1267..01d408eb55 100644
--- a/target/lm32/cpu.h
+++ b/target/lm32/cpu.h
@@ -202,7 +202,7 @@ void lm32_cpu_do_interrupt(CPUState *cpu);
bool lm32_cpu_exec_interrupt(CPUState *cs, int int_req);
void lm32_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
hwaddr lm32_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int lm32_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int lm32_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int lm32_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
typedef enum {
diff --git a/target/lm32/gdbstub.c b/target/lm32/gdbstub.c
index 82ede436e1..b6fe12e1d6 100644
--- a/target/lm32/gdbstub.c
+++ b/target/lm32/gdbstub.c
@@ -22,7 +22,7 @@
#include "exec/gdbstub.h"
#include "hw/lm32/lm32_pic.h"
-int lm32_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int lm32_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
LM32CPU *cpu = LM32_CPU(cs);
CPULM32State *env = &cpu->env;
diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h
index 3de8e06dfe..521ac67cdd 100644
--- a/target/m68k/cpu.h
+++ b/target/m68k/cpu.h
@@ -168,7 +168,7 @@ void m68k_cpu_do_interrupt(CPUState *cpu);
bool m68k_cpu_exec_interrupt(CPUState *cpu, int int_req);
void m68k_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
hwaddr m68k_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int m68k_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int m68k_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int m68k_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void m68k_tcg_init(void);
diff --git a/target/m68k/gdbstub.c b/target/m68k/gdbstub.c
index fdc96f57ff..eb2d030e14 100644
--- a/target/m68k/gdbstub.c
+++ b/target/m68k/gdbstub.c
@@ -21,7 +21,7 @@
#include "cpu.h"
#include "exec/gdbstub.h"
-int m68k_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int m68k_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
M68kCPU *cpu = M68K_CPU(cs);
CPUM68KState *env = &cpu->env;
diff --git a/target/m68k/helper.c b/target/m68k/helper.c
index baf7729af0..014657c637 100644
--- a/target/m68k/helper.c
+++ b/target/m68k/helper.c
@@ -68,23 +68,19 @@ void m68k_cpu_list(void)
g_slist_free(list);
}
-static int cf_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
+static int cf_fpu_gdb_get_reg(CPUM68KState *env, GByteArray *mem_buf, int n)
{
if (n < 8) {
float_status s;
- stfq_p(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
- return 8;
+ return gdb_get_reg64(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
}
switch (n) {
case 8: /* fpcontrol */
- stl_be_p(mem_buf, env->fpcr);
- return 4;
+ return gdb_get_reg32(mem_buf, env->fpcr);
case 9: /* fpstatus */
- stl_be_p(mem_buf, env->fpsr);
- return 4;
+ return gdb_get_reg32(mem_buf, env->fpsr);
case 10: /* fpiar, not implemented */
- memset(mem_buf, 0, 4);
- return 4;
+ return gdb_get_reg32(mem_buf, 0);
}
return 0;
}
@@ -109,24 +105,21 @@ static int cf_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
return 0;
}
-static int m68k_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
+static int m68k_fpu_gdb_get_reg(CPUM68KState *env, GByteArray *mem_buf, int n)
{
if (n < 8) {
- stw_be_p(mem_buf, env->fregs[n].l.upper);
- memset(mem_buf + 2, 0, 2);
- stq_be_p(mem_buf + 4, env->fregs[n].l.lower);
- return 12;
+ int len = gdb_get_reg16(mem_buf, env->fregs[n].l.upper);
+ len += gdb_get_reg16(mem_buf + len, 0);
+ len += gdb_get_reg64(mem_buf + len, env->fregs[n].l.lower);
+ return len;
}
switch (n) {
case 8: /* fpcontrol */
- stl_be_p(mem_buf, env->fpcr);
- return 4;
+ return gdb_get_reg32(mem_buf, env->fpcr);
case 9: /* fpstatus */
- stl_be_p(mem_buf, env->fpsr);
- return 4;
+ return gdb_get_reg32(mem_buf, env->fpsr);
case 10: /* fpiar, not implemented */
- memset(mem_buf, 0, 4);
- return 4;
+ return gdb_get_reg32(mem_buf, 0);
}
return 0;
}
diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h
index 32522f606b..1a700a880c 100644
--- a/target/microblaze/cpu.h
+++ b/target/microblaze/cpu.h
@@ -313,7 +313,7 @@ void mb_cpu_do_interrupt(CPUState *cs);
bool mb_cpu_exec_interrupt(CPUState *cs, int int_req);
void mb_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
hwaddr mb_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int mb_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int mb_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int mb_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void mb_tcg_init(void);
diff --git a/target/microblaze/gdbstub.c b/target/microblaze/gdbstub.c
index 30677b6d1f..f41ebf1f33 100644
--- a/target/microblaze/gdbstub.c
+++ b/target/microblaze/gdbstub.c
@@ -21,7 +21,7 @@
#include "cpu.h"
#include "exec/gdbstub.h"
-int mb_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int mb_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
CPUMBState *env = &cpu->env;
diff --git a/target/mips/gdbstub.c b/target/mips/gdbstub.c
index bbb2544939..98f56e660d 100644
--- a/target/mips/gdbstub.c
+++ b/target/mips/gdbstub.c
@@ -22,7 +22,7 @@
#include "internal.h"
#include "exec/gdbstub.h"
-int mips_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int mips_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
MIPSCPU *cpu = MIPS_CPU(cs);
CPUMIPSState *env = &cpu->env;
diff --git a/target/mips/internal.h b/target/mips/internal.h
index df55f845ba..1bf274b3ef 100644
--- a/target/mips/internal.h
+++ b/target/mips/internal.h
@@ -82,7 +82,7 @@ void mips_cpu_do_interrupt(CPUState *cpu);
bool mips_cpu_exec_interrupt(CPUState *cpu, int int_req);
void mips_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
hwaddr mips_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int mips_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int mips_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int mips_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void mips_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
MMUAccessType access_type,
diff --git a/target/nios2/cpu.c b/target/nios2/cpu.c
index 0a4075949e..8f7011fcb9 100644
--- a/target/nios2/cpu.c
+++ b/target/nios2/cpu.c
@@ -124,7 +124,7 @@ static void nios2_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
#endif
}
-static int nios2_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+static int nios2_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
Nios2CPU *cpu = NIOS2_CPU(cs);
CPUClass *cc = CPU_GET_CLASS(cs);
diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h
index e7fb06445e..f37a52e153 100644
--- a/target/openrisc/cpu.h
+++ b/target/openrisc/cpu.h
@@ -320,7 +320,7 @@ void openrisc_cpu_do_interrupt(CPUState *cpu);
bool openrisc_cpu_exec_interrupt(CPUState *cpu, int int_req);
void openrisc_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int openrisc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int openrisc_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int openrisc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void openrisc_translate_init(void);
bool openrisc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
diff --git a/target/openrisc/gdbstub.c b/target/openrisc/gdbstub.c
index 0fcdb79668..095bf76c12 100644
--- a/target/openrisc/gdbstub.c
+++ b/target/openrisc/gdbstub.c
@@ -21,7 +21,7 @@
#include "cpu.h"
#include "exec/gdbstub.h"
-int openrisc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int openrisc_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
OpenRISCCPU *cpu = OPENRISC_CPU(cs);
CPUOpenRISCState *env = &cpu->env;
diff --git a/target/ppc/cpu-qom.h b/target/ppc/cpu-qom.h
index b528131761..000c7d405b 100644
--- a/target/ppc/cpu-qom.h
+++ b/target/ppc/cpu-qom.h
@@ -177,6 +177,7 @@ typedef struct PowerPCCPUClass {
uint64_t insns_flags;
uint64_t insns_flags2;
uint64_t msr_mask;
+ uint64_t lpcr_mask; /* Available bits in the LPCR */
uint64_t lpcr_pm; /* Power-saving mode Exit Cause Enable bits */
powerpc_mmu_t mmu_model;
powerpc_excp_t excp_model;
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index b283042515..88d9449555 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -24,8 +24,6 @@
#include "exec/cpu-defs.h"
#include "cpu-qom.h"
-/* #define PPC_EMULATE_32BITS_HYPV */
-
#define TCG_GUEST_DEFAULT_MO 0
#define TARGET_PAGE_BITS_64K 16
@@ -300,13 +298,12 @@ typedef struct ppc_v3_pate_t {
#define MSR_SF 63 /* Sixty-four-bit mode hflags */
#define MSR_TAG 62 /* Tag-active mode (POWERx ?) */
#define MSR_ISF 61 /* Sixty-four-bit interrupt mode on 630 */
-#define MSR_SHV 60 /* hypervisor state hflags */
+#define MSR_HV 60 /* hypervisor state hflags */
#define MSR_TS0 34 /* Transactional state, 2 bits (Book3s) */
#define MSR_TS1 33
#define MSR_TM 32 /* Transactional Memory Available (Book3s) */
#define MSR_CM 31 /* Computation mode for BookE hflags */
#define MSR_ICM 30 /* Interrupt computation mode for BookE */
-#define MSR_THV 29 /* hypervisor state for 32 bits PowerPC hflags */
#define MSR_GS 28 /* guest state for BookE */
#define MSR_UCLE 26 /* User-mode cache lock enable for BookE */
#define MSR_VR 25 /* altivec available x hflags */
@@ -401,10 +398,13 @@ typedef struct ppc_v3_pate_t {
#define msr_sf ((env->msr >> MSR_SF) & 1)
#define msr_isf ((env->msr >> MSR_ISF) & 1)
-#define msr_shv ((env->msr >> MSR_SHV) & 1)
+#if defined(TARGET_PPC64)
+#define msr_hv ((env->msr >> MSR_HV) & 1)
+#else
+#define msr_hv (0)
+#endif
#define msr_cm ((env->msr >> MSR_CM) & 1)
#define msr_icm ((env->msr >> MSR_ICM) & 1)
-#define msr_thv ((env->msr >> MSR_THV) & 1)
#define msr_gs ((env->msr >> MSR_GS) & 1)
#define msr_ucle ((env->msr >> MSR_UCLE) & 1)
#define msr_vr ((env->msr >> MSR_VR) & 1)
@@ -449,16 +449,9 @@ typedef struct ppc_v3_pate_t {
/* Hypervisor bit is more specific */
#if defined(TARGET_PPC64)
-#define MSR_HVB (1ULL << MSR_SHV)
-#define msr_hv msr_shv
-#else
-#if defined(PPC_EMULATE_32BITS_HYPV)
-#define MSR_HVB (1ULL << MSR_THV)
-#define msr_hv msr_thv
+#define MSR_HVB (1ULL << MSR_HV)
#else
#define MSR_HVB (0ULL)
-#define msr_hv (0)
-#endif
#endif
/* DSISR */
@@ -1051,10 +1044,6 @@ struct CPUPPCState {
uint32_t flags;
uint64_t insns_flags;
uint64_t insns_flags2;
-#if defined(TARGET_PPC64)
- ppc_slb_t vrma_slb;
- target_ulong rmls;
-#endif
int error_code;
uint32_t pending_interrupts;
@@ -1218,8 +1207,8 @@ bool ppc_cpu_exec_interrupt(CPUState *cpu, int int_req);
void ppc_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
void ppc_cpu_dump_statistics(CPUState *cpu, int flags);
hwaddr ppc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int ppc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
-int ppc_cpu_gdb_read_register_apple(CPUState *cpu, uint8_t *buf, int reg);
+int ppc_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
+int ppc_cpu_gdb_read_register_apple(CPUState *cpu, GByteArray *buf, int reg);
int ppc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
int ppc_cpu_gdb_write_register_apple(CPUState *cpu, uint8_t *buf, int reg);
#ifndef CONFIG_USER_ONLY
@@ -1231,7 +1220,8 @@ int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
int ppc32_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
int cpuid, void *opaque);
#ifndef CONFIG_USER_ONLY
-void ppc_cpu_do_system_reset(CPUState *cs);
+void ppc_cpu_do_system_reset(CPUState *cs, target_ulong vector);
+void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector);
extern const VMStateDescription vmstate_ppc_cpu;
#endif
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 027f54c0ed..08bc885ca6 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -128,6 +128,37 @@ static uint64_t ppc_excp_vector_offset(CPUState *cs, int ail)
return offset;
}
+static inline void powerpc_set_excp_state(PowerPCCPU *cpu,
+ target_ulong vector, target_ulong msr)
+{
+ CPUState *cs = CPU(cpu);
+ CPUPPCState *env = &cpu->env;
+
+ /*
+ * We don't use hreg_store_msr here as already have treated any
+ * special case that could occur. Just store MSR and update hflags
+ *
+ * Note: We *MUST* not use hreg_store_msr() as-is anyway because it
+ * will prevent setting of the HV bit which some exceptions might need
+ * to do.
+ */
+ env->msr = msr & env->msr_mask;
+ hreg_compute_hflags(env);
+ env->nip = vector;
+ /* Reset exception state */
+ cs->exception_index = POWERPC_EXCP_NONE;
+ env->error_code = 0;
+
+ /* Reset the reservation */
+ env->reserve_addr = -1;
+
+ /*
+ * Any interrupt is context synchronizing, check if TCG TLB needs
+ * a delayed flush on ppc64
+ */
+ check_tlb_flush(env, false);
+}
+
/*
* Note that this function should be greatly optimized when called
* with a constant excp, from ppc_hw_interrupt
@@ -768,29 +799,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
}
}
#endif
- /*
- * We don't use hreg_store_msr here as already have treated any
- * special case that could occur. Just store MSR and update hflags
- *
- * Note: We *MUST* not use hreg_store_msr() as-is anyway because it
- * will prevent setting of the HV bit which some exceptions might need
- * to do.
- */
- env->msr = new_msr & env->msr_mask;
- hreg_compute_hflags(env);
- env->nip = vector;
- /* Reset exception state */
- cs->exception_index = POWERPC_EXCP_NONE;
- env->error_code = 0;
- /* Reset the reservation */
- env->reserve_addr = -1;
-
- /*
- * Any interrupt is context synchronizing, check if TCG TLB needs
- * a delayed flush on ppc64
- */
- check_tlb_flush(env, false);
+ powerpc_set_excp_state(cpu, vector, new_msr);
}
void ppc_cpu_do_interrupt(CPUState *cs)
@@ -951,12 +961,35 @@ static void ppc_hw_interrupt(CPUPPCState *env)
}
}
-void ppc_cpu_do_system_reset(CPUState *cs)
+void ppc_cpu_do_system_reset(CPUState *cs, target_ulong vector)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = &cpu->env;
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
+ if (vector != -1) {
+ env->nip = vector;
+ }
+}
+
+void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+ target_ulong msr = 0;
+
+ /*
+ * Set MSR and NIP for the handler, SRR0/1, DAR and DSISR have already
+ * been set by KVM.
+ */
+ msr = (1ULL << MSR_ME);
+ msr |= env->msr & (1ULL << MSR_SF);
+ if (!(*pcc->interrupts_big_endian)(cpu)) {
+ msr |= (1ULL << MSR_LE);
+ }
+
+ powerpc_set_excp_state(cpu, vector, msr);
}
#endif /* !CONFIG_USER_ONLY */
diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c
index 823759c92e..eb362dd9ae 100644
--- a/target/ppc/gdbstub.c
+++ b/target/ppc/gdbstub.c
@@ -114,10 +114,11 @@ void ppc_maybe_bswap_register(CPUPPCState *env, uint8_t *mem_buf, int len)
* the FP regs zero size when talking to a newer gdb.
*/
-int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int ppc_cpu_gdb_read_register(CPUState *cs, GByteArray *buf, int n)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = &cpu->env;
+ uint8_t *mem_buf;
int r = ppc_gdb_register_len(n);
if (!r) {
@@ -126,17 +127,17 @@ int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
if (n < 32) {
/* gprs */
- gdb_get_regl(mem_buf, env->gpr[n]);
+ gdb_get_regl(buf, env->gpr[n]);
} else if (n < 64) {
/* fprs */
- stfq_p(mem_buf, *cpu_fpr_ptr(env, n - 32));
+ gdb_get_reg64(buf, *cpu_fpr_ptr(env, n - 32));
} else {
switch (n) {
case 64:
- gdb_get_regl(mem_buf, env->nip);
+ gdb_get_regl(buf, env->nip);
break;
case 65:
- gdb_get_regl(mem_buf, env->msr);
+ gdb_get_regl(buf, env->msr);
break;
case 66:
{
@@ -145,31 +146,33 @@ int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
for (i = 0; i < 8; i++) {
cr |= env->crf[i] << (32 - ((i + 1) * 4));
}
- gdb_get_reg32(mem_buf, cr);
+ gdb_get_reg32(buf, cr);
break;
}
case 67:
- gdb_get_regl(mem_buf, env->lr);
+ gdb_get_regl(buf, env->lr);
break;
case 68:
- gdb_get_regl(mem_buf, env->ctr);
+ gdb_get_regl(buf, env->ctr);
break;
case 69:
- gdb_get_reg32(mem_buf, env->xer);
+ gdb_get_reg32(buf, env->xer);
break;
case 70:
- gdb_get_reg32(mem_buf, env->fpscr);
+ gdb_get_reg32(buf, env->fpscr);
break;
}
}
+ mem_buf = buf->data + buf->len - r;
ppc_maybe_bswap_register(env, mem_buf, r);
return r;
}
-int ppc_cpu_gdb_read_register_apple(CPUState *cs, uint8_t *mem_buf, int n)
+int ppc_cpu_gdb_read_register_apple(CPUState *cs, GByteArray *buf, int n)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = &cpu->env;
+ uint8_t *mem_buf;
int r = ppc_gdb_register_len_apple(n);
if (!r) {
@@ -178,21 +181,21 @@ int ppc_cpu_gdb_read_register_apple(CPUState *cs, uint8_t *mem_buf, int n)
if (n < 32) {
/* gprs */
- gdb_get_reg64(mem_buf, env->gpr[n]);
+ gdb_get_reg64(buf, env->gpr[n]);
} else if (n < 64) {
/* fprs */
- stfq_p(mem_buf, *cpu_fpr_ptr(env, n - 32));
+ gdb_get_reg64(buf, *cpu_fpr_ptr(env, n - 32));
} else if (n < 96) {
/* Altivec */
- stq_p(mem_buf, n - 64);
- stq_p(mem_buf + 8, 0);
+ gdb_get_reg64(buf, n - 64);
+ gdb_get_reg64(buf, 0);
} else {
switch (n) {
case 64 + 32:
- gdb_get_reg64(mem_buf, env->nip);
+ gdb_get_reg64(buf, env->nip);
break;
case 65 + 32:
- gdb_get_reg64(mem_buf, env->msr);
+ gdb_get_reg64(buf, env->msr);
break;
case 66 + 32:
{
@@ -201,23 +204,24 @@ int ppc_cpu_gdb_read_register_apple(CPUState *cs, uint8_t *mem_buf, int n)
for (i = 0; i < 8; i++) {
cr |= env->crf[i] << (32 - ((i + 1) * 4));
}
- gdb_get_reg32(mem_buf, cr);
+ gdb_get_reg32(buf, cr);
break;
}
case 67 + 32:
- gdb_get_reg64(mem_buf, env->lr);
+ gdb_get_reg64(buf, env->lr);
break;
case 68 + 32:
- gdb_get_reg64(mem_buf, env->ctr);
+ gdb_get_reg64(buf, env->ctr);
break;
case 69 + 32:
- gdb_get_reg32(mem_buf, env->xer);
+ gdb_get_reg32(buf, env->xer);
break;
case 70 + 32:
- gdb_get_reg64(mem_buf, env->fpscr);
+ gdb_get_reg64(buf, env->fpscr);
break;
}
}
+ mem_buf = buf->data + buf->len - r;
ppc_maybe_bswap_register(env, mem_buf, r);
return r;
}
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 7f44b1aa1a..597f72be1b 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -2113,7 +2113,7 @@ void kvmppc_error_append_smt_possible_hint(Error *const *errp)
#ifdef TARGET_PPC64
-uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift)
+uint64_t kvmppc_vrma_limit(unsigned int hash_shift)
{
struct kvm_ppc_smmu_info info;
long rampagesize, best_page_shift;
@@ -2140,8 +2140,7 @@ uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift)
}
}
- return MIN(current_size,
- 1ULL << (best_page_shift + hash_shift - 7));
+ return 1ULL << (best_page_shift + hash_shift - 7);
}
#endif
diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
index 9e4f2357cc..332fa0aa1c 100644
--- a/target/ppc/kvm_ppc.h
+++ b/target/ppc/kvm_ppc.h
@@ -47,7 +47,7 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t page_shift,
int *pfd, bool need_vfio);
int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size);
int kvmppc_reset_htab(int shift_hint);
-uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift);
+uint64_t kvmppc_vrma_limit(unsigned int hash_shift);
bool kvmppc_has_cap_spapr_vfio(void);
#endif /* !CONFIG_USER_ONLY */
bool kvmppc_has_cap_epr(void);
@@ -255,10 +255,9 @@ static inline int kvmppc_reset_htab(int shift_hint)
return 0;
}
-static inline uint64_t kvmppc_rma_size(uint64_t current_size,
- unsigned int hash_shift)
+static inline uint64_t kvmppc_vrma_limit(unsigned int hash_shift)
{
- return ram_size;
+ g_assert_not_reached();
}
static inline bool kvmppc_hpt_needs_host_contiguous_pages(void)
diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
index da8966ccf5..34f6009b1e 100644
--- a/target/ppc/mmu-hash64.c
+++ b/target/ppc/mmu-hash64.c
@@ -18,6 +18,7 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
+#include "qemu/units.h"
#include "cpu.h"
#include "exec/exec-all.h"
#include "exec/helper-proto.h"
@@ -668,6 +669,21 @@ unsigned ppc_hash64_hpte_page_shift_noslb(PowerPCCPU *cpu,
return 0;
}
+static bool ppc_hash64_use_vrma(CPUPPCState *env)
+{
+ switch (env->mmu_model) {
+ case POWERPC_MMU_3_00:
+ /*
+ * ISAv3.0 (POWER9) always uses VRMA, the VPM0 field and RMOR
+ * register no longer exist
+ */
+ return true;
+
+ default:
+ return !!(env->spr[SPR_LPCR] & LPCR_VPM0);
+ }
+}
+
static void ppc_hash64_set_isi(CPUState *cs, uint64_t error_code)
{
CPUPPCState *env = &POWERPC_CPU(cs)->env;
@@ -676,15 +692,7 @@ static void ppc_hash64_set_isi(CPUState *cs, uint64_t error_code)
if (msr_ir) {
vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM1);
} else {
- switch (env->mmu_model) {
- case POWERPC_MMU_3_00:
- /* Field deprecated in ISAv3.00 - interrupts always go to hyperv */
- vpm = true;
- break;
- default:
- vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM0);
- break;
- }
+ vpm = ppc_hash64_use_vrma(env);
}
if (vpm && !msr_hv) {
cs->exception_index = POWERPC_EXCP_HISI;
@@ -702,15 +710,7 @@ static void ppc_hash64_set_dsi(CPUState *cs, uint64_t dar, uint64_t dsisr)
if (msr_dr) {
vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM1);
} else {
- switch (env->mmu_model) {
- case POWERPC_MMU_3_00:
- /* Field deprecated in ISAv3.00 - interrupts always go to hyperv */
- vpm = true;
- break;
- default:
- vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM0);
- break;
- }
+ vpm = ppc_hash64_use_vrma(env);
}
if (vpm && !msr_hv) {
cs->exception_index = POWERPC_EXCP_HDSI;
@@ -758,11 +758,67 @@ static void ppc_hash64_set_c(PowerPCCPU *cpu, hwaddr ptex, uint64_t pte1)
stb_phys(CPU(cpu)->as, base + offset, (pte1 & 0xff) | 0x80);
}
+static target_ulong rmls_limit(PowerPCCPU *cpu)
+{
+ CPUPPCState *env = &cpu->env;
+ /*
+ * In theory the meanings of RMLS values are implementation
+ * dependent. In practice, this seems to have been the set from
+ * POWER4+..POWER8, and RMLS is no longer supported in POWER9.
+ *
+ * Unsupported values mean the OS has shot itself in the
+ * foot. Return a 0-sized RMA in this case, which we expect
+ * to trigger an immediate DSI or ISI
+ */
+ static const target_ulong rma_sizes[16] = {
+ [0] = 256 * GiB,
+ [1] = 16 * GiB,
+ [2] = 1 * GiB,
+ [3] = 64 * MiB,
+ [4] = 256 * MiB,
+ [7] = 128 * MiB,
+ [8] = 32 * MiB,
+ };
+ target_ulong rmls = (env->spr[SPR_LPCR] & LPCR_RMLS) >> LPCR_RMLS_SHIFT;
+
+ return rma_sizes[rmls];
+}
+
+static int build_vrma_slbe(PowerPCCPU *cpu, ppc_slb_t *slb)
+{
+ CPUPPCState *env = &cpu->env;
+ target_ulong lpcr = env->spr[SPR_LPCR];
+ uint32_t vrmasd = (lpcr & LPCR_VRMASD) >> LPCR_VRMASD_SHIFT;
+ target_ulong vsid = SLB_VSID_VRMA | ((vrmasd << 4) & SLB_VSID_LLP_MASK);
+ int i;
+
+ for (i = 0; i < PPC_PAGE_SIZES_MAX_SZ; i++) {
+ const PPCHash64SegmentPageSizes *sps = &cpu->hash64_opts->sps[i];
+
+ if (!sps->page_shift) {
+ break;
+ }
+
+ if ((vsid & SLB_VSID_LLP_MASK) == sps->slb_enc) {
+ slb->esid = SLB_ESID_V;
+ slb->vsid = vsid;
+ slb->sps = sps;
+ return 0;
+ }
+ }
+
+ error_report("Bad page size encoding in LPCR[VRMASD]; LPCR=0x"
+ TARGET_FMT_lx"\n", lpcr);
+
+ return -1;
+}
+
int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
int rwx, int mmu_idx)
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
+ ppc_slb_t vrma_slbe;
ppc_slb_t *slb;
unsigned apshift;
hwaddr ptex;
@@ -789,27 +845,32 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
*/
raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL;
- /* In HV mode, add HRMOR if top EA bit is clear */
- if (msr_hv || !env->has_hv_mode) {
+ if (cpu->vhyp) {
+ /*
+ * In virtual hypervisor mode, there's nothing to do:
+ * EA == GPA == qemu guest address
+ */
+ } else if (msr_hv || !env->has_hv_mode) {
+ /* In HV mode, add HRMOR if top EA bit is clear */
if (!(eaddr >> 63)) {
raddr |= env->spr[SPR_HRMOR];
}
- } else {
- /* Otherwise, check VPM for RMA vs VRMA */
- if (env->spr[SPR_LPCR] & LPCR_VPM0) {
- slb = &env->vrma_slb;
- if (slb->sps) {
- goto skip_slb_search;
- }
- /* Not much else to do here */
+ } else if (ppc_hash64_use_vrma(env)) {
+ /* Emulated VRMA mode */
+ slb = &vrma_slbe;
+ if (build_vrma_slbe(cpu, slb) != 0) {
+ /* Invalid VRMA setup, machine check */
cs->exception_index = POWERPC_EXCP_MCHECK;
env->error_code = 0;
return 1;
- } else if (raddr < env->rmls) {
- /* RMA. Check bounds in RMLS */
- raddr |= env->spr[SPR_RMOR];
- } else {
- /* The access failed, generate the approriate interrupt */
+ }
+
+ goto skip_slb_search;
+ } else {
+ target_ulong limit = rmls_limit(cpu);
+
+ /* Emulated old-style RMO mode, bounds check against RMLS */
+ if (raddr >= limit) {
if (rwx == 2) {
ppc_hash64_set_isi(cs, SRR1_PROTFAULT);
} else {
@@ -821,6 +882,8 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
}
return 1;
}
+
+ raddr |= env->spr[SPR_RMOR];
}
tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
PAGE_READ | PAGE_WRITE | PAGE_EXEC, mmu_idx,
@@ -943,6 +1006,7 @@ skip_slb_search:
hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr)
{
CPUPPCState *env = &cpu->env;
+ ppc_slb_t vrma_slbe;
ppc_slb_t *slb;
hwaddr ptex, raddr;
ppc_hash_pte64_t pte;
@@ -953,22 +1017,29 @@ hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr)
/* In real mode the top 4 effective address bits are ignored */
raddr = addr & 0x0FFFFFFFFFFFFFFFULL;
- /* In HV mode, add HRMOR if top EA bit is clear */
- if ((msr_hv || !env->has_hv_mode) && !(addr >> 63)) {
+ if (cpu->vhyp) {
+ /*
+ * In virtual hypervisor mode, there's nothing to do:
+ * EA == GPA == qemu guest address
+ */
+ return raddr;
+ } else if ((msr_hv || !env->has_hv_mode) && !(addr >> 63)) {
+ /* In HV mode, add HRMOR if top EA bit is clear */
return raddr | env->spr[SPR_HRMOR];
- }
+ } else if (ppc_hash64_use_vrma(env)) {
+ /* Emulated VRMA mode */
+ slb = &vrma_slbe;
+ if (build_vrma_slbe(cpu, slb) != 0) {
+ return -1;
+ }
+ } else {
+ target_ulong limit = rmls_limit(cpu);
- /* Otherwise, check VPM for RMA vs VRMA */
- if (env->spr[SPR_LPCR] & LPCR_VPM0) {
- slb = &env->vrma_slb;
- if (!slb->sps) {
+ /* Emulated old-style RMO mode, bounds check against RMLS */
+ if (raddr >= limit) {
return -1;
}
- } else if (raddr < env->rmls) {
- /* RMA. Check bounds in RMLS */
return raddr | env->spr[SPR_RMOR];
- } else {
- return -1;
}
} else {
slb = slb_lookup(cpu, addr);
@@ -997,168 +1068,12 @@ void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu, target_ulong ptex,
cpu->env.tlb_need_flush = TLB_NEED_GLOBAL_FLUSH | TLB_NEED_LOCAL_FLUSH;
}
-static void ppc_hash64_update_rmls(PowerPCCPU *cpu)
-{
- CPUPPCState *env = &cpu->env;
- uint64_t lpcr = env->spr[SPR_LPCR];
-
- /*
- * This is the full 4 bits encoding of POWER8. Previous
- * CPUs only support a subset of these but the filtering
- * is done when writing LPCR
- */
- switch ((lpcr & LPCR_RMLS) >> LPCR_RMLS_SHIFT) {
- case 0x8: /* 32MB */
- env->rmls = 0x2000000ull;
- break;
- case 0x3: /* 64MB */
- env->rmls = 0x4000000ull;
- break;
- case 0x7: /* 128MB */
- env->rmls = 0x8000000ull;
- break;
- case 0x4: /* 256MB */
- env->rmls = 0x10000000ull;
- break;
- case 0x2: /* 1GB */
- env->rmls = 0x40000000ull;
- break;
- case 0x1: /* 16GB */
- env->rmls = 0x400000000ull;
- break;
- default:
- /* What to do here ??? */
- env->rmls = 0;
- }
-}
-
-static void ppc_hash64_update_vrma(PowerPCCPU *cpu)
-{
- CPUPPCState *env = &cpu->env;
- const PPCHash64SegmentPageSizes *sps = NULL;
- target_ulong esid, vsid, lpcr;
- ppc_slb_t *slb = &env->vrma_slb;
- uint32_t vrmasd;
- int i;
-
- /* First clear it */
- slb->esid = slb->vsid = 0;
- slb->sps = NULL;
-
- /* Is VRMA enabled ? */
- lpcr = env->spr[SPR_LPCR];
- if (!(lpcr & LPCR_VPM0)) {
- return;
- }
-
- /*
- * Make one up. Mostly ignore the ESID which will not be needed
- * for translation
- */
- vsid = SLB_VSID_VRMA;
- vrmasd = (lpcr & LPCR_VRMASD) >> LPCR_VRMASD_SHIFT;
- vsid |= (vrmasd << 4) & (SLB_VSID_L | SLB_VSID_LP);
- esid = SLB_ESID_V;
-
- for (i = 0; i < PPC_PAGE_SIZES_MAX_SZ; i++) {
- const PPCHash64SegmentPageSizes *sps1 = &cpu->hash64_opts->sps[i];
-
- if (!sps1->page_shift) {
- break;
- }
-
- if ((vsid & SLB_VSID_LLP_MASK) == sps1->slb_enc) {
- sps = sps1;
- break;
- }
- }
-
- if (!sps) {
- error_report("Bad page size encoding esid 0x"TARGET_FMT_lx
- " vsid 0x"TARGET_FMT_lx, esid, vsid);
- return;
- }
-
- slb->vsid = vsid;
- slb->esid = esid;
- slb->sps = sps;
-}
-
void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val)
{
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
CPUPPCState *env = &cpu->env;
- uint64_t lpcr = 0;
-
- /* Filter out bits */
- switch (env->mmu_model) {
- case POWERPC_MMU_64B: /* 970 */
- if (val & 0x40) {
- lpcr |= LPCR_LPES0;
- }
- if (val & 0x8000000000000000ull) {
- lpcr |= LPCR_LPES1;
- }
- if (val & 0x20) {
- lpcr |= (0x4ull << LPCR_RMLS_SHIFT);
- }
- if (val & 0x4000000000000000ull) {
- lpcr |= (0x2ull << LPCR_RMLS_SHIFT);
- }
- if (val & 0x2000000000000000ull) {
- lpcr |= (0x1ull << LPCR_RMLS_SHIFT);
- }
- env->spr[SPR_RMOR] = ((lpcr >> 41) & 0xffffull) << 26;
- /*
- * XXX We could also write LPID from HID4 here
- * but since we don't tag any translation on it
- * it doesn't actually matter
- *
- * XXX For proper emulation of 970 we also need
- * to dig HRMOR out of HID5
- */
- break;
- case POWERPC_MMU_2_03: /* P5p */
- lpcr = val & (LPCR_RMLS | LPCR_ILE |
- LPCR_LPES0 | LPCR_LPES1 |
- LPCR_RMI | LPCR_HDICE);
- break;
- case POWERPC_MMU_2_06: /* P7 */
- lpcr = val & (LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_DPFD |
- LPCR_VRMASD | LPCR_RMLS | LPCR_ILE |
- LPCR_P7_PECE0 | LPCR_P7_PECE1 | LPCR_P7_PECE2 |
- LPCR_MER | LPCR_TC |
- LPCR_LPES0 | LPCR_LPES1 | LPCR_HDICE);
- break;
- case POWERPC_MMU_2_07: /* P8 */
- lpcr = val & (LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_KBV |
- LPCR_DPFD | LPCR_VRMASD | LPCR_RMLS | LPCR_ILE |
- LPCR_AIL | LPCR_ONL | LPCR_P8_PECE0 | LPCR_P8_PECE1 |
- LPCR_P8_PECE2 | LPCR_P8_PECE3 | LPCR_P8_PECE4 |
- LPCR_MER | LPCR_TC | LPCR_LPES0 | LPCR_HDICE);
- break;
- case POWERPC_MMU_3_00: /* P9 */
- lpcr = val & (LPCR_VPM1 | LPCR_ISL | LPCR_KBV | LPCR_DPFD |
- (LPCR_PECE_U_MASK & LPCR_HVEE) | LPCR_ILE | LPCR_AIL |
- LPCR_UPRT | LPCR_EVIRT | LPCR_ONL | LPCR_HR | LPCR_LD |
- (LPCR_PECE_L_MASK & (LPCR_PDEE | LPCR_HDEE | LPCR_EEE |
- LPCR_DEE | LPCR_OEE)) | LPCR_MER | LPCR_GTSE | LPCR_TC |
- LPCR_HEIC | LPCR_LPES0 | LPCR_HVICE | LPCR_HDICE);
- /*
- * If we have a virtual hypervisor, we need to bring back RMLS. It
- * doesn't exist on an actual P9 but that's all we know how to
- * configure with softmmu at the moment
- */
- if (cpu->vhyp) {
- lpcr |= (val & LPCR_RMLS);
- }
- break;
- default:
- ;
- }
- env->spr[SPR_LPCR] = lpcr;
- ppc_hash64_update_rmls(cpu);
- ppc_hash64_update_vrma(cpu);
+ env->spr[SPR_LPCR] = val & pcc->lpcr_mask;
}
void helper_store_lpcr(CPUPPCState *env, target_ulong val)
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 36fa27367c..127c82a24e 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -1938,15 +1938,17 @@ static void gen_rlwinm(DisasContext *ctx)
me += 32;
#endif
mask = MASK(mb, me);
- if (sh == 0) {
- tcg_gen_andi_tl(t_ra, t_rs, mask);
- } else if (mask <= 0xffffffffu) {
- TCGv_i32 t0 = tcg_temp_new_i32();
- tcg_gen_trunc_tl_i32(t0, t_rs);
- tcg_gen_rotli_i32(t0, t0, sh);
- tcg_gen_andi_i32(t0, t0, mask);
- tcg_gen_extu_i32_tl(t_ra, t0);
- tcg_temp_free_i32(t0);
+ if (mask <= 0xffffffffu) {
+ if (sh == 0) {
+ tcg_gen_andi_tl(t_ra, t_rs, mask);
+ } else {
+ TCGv_i32 t0 = tcg_temp_new_i32();
+ tcg_gen_trunc_tl_i32(t0, t_rs);
+ tcg_gen_rotli_i32(t0, t0, sh);
+ tcg_gen_andi_i32(t0, t0, mask);
+ tcg_gen_extu_i32_tl(t_ra, t0);
+ tcg_temp_free_i32(t0);
+ }
} else {
#if defined(TARGET_PPC64)
tcg_gen_deposit_i64(t_ra, t_rs, t_rs, 32, 32);
diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c
index 7e9780e875..e853164a86 100644
--- a/target/ppc/translate_init.inc.c
+++ b/target/ppc/translate_init.inc.c
@@ -7895,25 +7895,21 @@ static void spr_write_lpcr(DisasContext *ctx, int sprn, int gprn)
{
gen_helper_store_lpcr(cpu_env, cpu_gpr[gprn]);
}
-
-static void spr_write_970_hid4(DisasContext *ctx, int sprn, int gprn)
-{
-#if defined(TARGET_PPC64)
- spr_write_generic(ctx, sprn, gprn);
- gen_helper_store_lpcr(cpu_env, cpu_gpr[gprn]);
-#endif
-}
-
#endif /* !defined(CONFIG_USER_ONLY) */
static void gen_spr_970_lpar(CPUPPCState *env)
{
#if !defined(CONFIG_USER_ONLY)
- /* Logical partitionning */
- /* PPC970: HID4 is effectively the LPCR */
+ /*
+ * PPC970: HID4 covers things later controlled by the LPCR and
+ * RMOR in later CPUs, but with a different encoding. We only
+ * support the 970 in "Apple mode" which has all hypervisor
+ * facilities disabled by strapping, so we can basically just
+ * ignore it
+ */
spr_register(env, SPR_970_HID4, "HID4",
SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_970_hid4,
+ &spr_read_generic, &spr_write_generic,
0x00000000);
#endif
}
@@ -8019,12 +8015,16 @@ static void gen_spr_book3s_ids(CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
- spr_register_hv(env, SPR_RMOR, "RMOR",
+ spr_register_hv(env, SPR_HRMOR, "HRMOR",
SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
- spr_register_hv(env, SPR_HRMOR, "HRMOR",
+}
+
+static void gen_spr_rmor(CPUPPCState *env)
+{
+ spr_register_hv(env, SPR_RMOR, "RMOR",
SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
@@ -8476,6 +8476,8 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)
(1ull << MSR_DR) |
(1ull << MSR_PMM) |
(1ull << MSR_RI);
+ pcc->lpcr_mask = LPCR_RMLS | LPCR_ILE | LPCR_LPES0 | LPCR_LPES1 |
+ LPCR_RMI | LPCR_HDICE;
pcc->mmu_model = POWERPC_MMU_2_03;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
@@ -8492,44 +8494,6 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)
pcc->l1_icache_size = 0x10000;
}
-/*
- * The CPU used to have a "compat" property which set the
- * compatibility mode PVR. However, this was conceptually broken - it
- * only makes sense on the pseries machine type (otherwise the guest
- * owns the PCR and can control the compatibility mode itself). It's
- * been replaced with the 'max-cpu-compat' property on the pseries
- * machine type. For backwards compatibility, pseries specially
- * parses the -cpu parameter and converts old compat= parameters into
- * the appropriate machine parameters. This stub implementation of
- * the parameter catches any uses on explicitly created CPUs.
- */
-static void getset_compat_deprecated(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- QNull *null = NULL;
-
- if (!qtest_enabled()) {
- warn_report("CPU 'compat' property is deprecated and has no effect; "
- "use max-cpu-compat machine property instead");
- }
- visit_type_null(v, name, &null, NULL);
- qobject_unref(null);
-}
-
-static const PropertyInfo ppc_compat_deprecated_propinfo = {
- .name = "str",
- .description = "compatibility mode (deprecated)",
- .get = getset_compat_deprecated,
- .set = getset_compat_deprecated,
-};
-static Property powerpc_servercpu_properties[] = {
- {
- .name = "compat",
- .info = &ppc_compat_deprecated_propinfo,
- },
- DEFINE_PROP_END_OF_LIST(),
-};
-
static void init_proc_POWER7(CPUPPCState *env)
{
/* Common Registers */
@@ -8539,6 +8503,7 @@ static void init_proc_POWER7(CPUPPCState *env)
/* POWER7 Specific Registers */
gen_spr_book3s_ids(env);
+ gen_spr_rmor(env);
gen_spr_amr(env);
gen_spr_book3s_purr(env);
gen_spr_power5p_common(env);
@@ -8611,7 +8576,6 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
dc->fw_name = "PowerPC,POWER7";
dc->desc = "POWER7";
- device_class_set_props(dc, powerpc_servercpu_properties);
pcc->pvr_match = ppc_pvr_match_power7;
pcc->pcr_mask = PCR_VEC_DIS | PCR_VSX_DIS | PCR_COMPAT_2_05;
pcc->pcr_supported = PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
@@ -8652,6 +8616,12 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
(1ull << MSR_PMM) |
(1ull << MSR_RI) |
(1ull << MSR_LE);
+ pcc->lpcr_mask = LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_DPFD |
+ LPCR_VRMASD | LPCR_RMLS | LPCR_ILE |
+ LPCR_P7_PECE0 | LPCR_P7_PECE1 | LPCR_P7_PECE2 |
+ LPCR_MER | LPCR_TC |
+ LPCR_LPES0 | LPCR_LPES1 | LPCR_HDICE;
+ pcc->lpcr_pm = LPCR_P7_PECE0 | LPCR_P7_PECE1 | LPCR_P7_PECE2;
pcc->mmu_model = POWERPC_MMU_2_06;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
@@ -8668,7 +8638,6 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
pcc->l1_dcache_size = 0x8000;
pcc->l1_icache_size = 0x8000;
pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;
- pcc->lpcr_pm = LPCR_P7_PECE0 | LPCR_P7_PECE1 | LPCR_P7_PECE2;
}
static void init_proc_POWER8(CPUPPCState *env)
@@ -8680,6 +8649,7 @@ static void init_proc_POWER8(CPUPPCState *env)
/* POWER8 Specific Registers */
gen_spr_book3s_ids(env);
+ gen_spr_rmor(env);
gen_spr_amr(env);
gen_spr_iamr(env);
gen_spr_book3s_purr(env);
@@ -8776,7 +8746,6 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
dc->fw_name = "PowerPC,POWER8";
dc->desc = "POWER8";
- device_class_set_props(dc, powerpc_servercpu_properties);
pcc->pvr_match = ppc_pvr_match_power8;
pcc->pcr_mask = PCR_TM_DIS | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
pcc->pcr_supported = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
@@ -8804,7 +8773,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 |
PPC2_TM | PPC2_PM_ISA206;
pcc->msr_mask = (1ull << MSR_SF) |
- (1ull << MSR_SHV) |
+ (1ull << MSR_HV) |
(1ull << MSR_TM) |
(1ull << MSR_VR) |
(1ull << MSR_VSX) |
@@ -8823,6 +8792,13 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
(1ull << MSR_TS0) |
(1ull << MSR_TS1) |
(1ull << MSR_LE);
+ pcc->lpcr_mask = LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_KBV |
+ LPCR_DPFD | LPCR_VRMASD | LPCR_RMLS | LPCR_ILE |
+ LPCR_AIL | LPCR_ONL | LPCR_P8_PECE0 | LPCR_P8_PECE1 |
+ LPCR_P8_PECE2 | LPCR_P8_PECE3 | LPCR_P8_PECE4 |
+ LPCR_MER | LPCR_TC | LPCR_LPES0 | LPCR_HDICE;
+ pcc->lpcr_pm = LPCR_P8_PECE0 | LPCR_P8_PECE1 | LPCR_P8_PECE2 |
+ LPCR_P8_PECE3 | LPCR_P8_PECE4;
pcc->mmu_model = POWERPC_MMU_2_07;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
@@ -8840,8 +8816,6 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
pcc->l1_dcache_size = 0x8000;
pcc->l1_icache_size = 0x8000;
pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;
- pcc->lpcr_pm = LPCR_P8_PECE0 | LPCR_P8_PECE1 | LPCR_P8_PECE2 |
- LPCR_P8_PECE3 | LPCR_P8_PECE4;
}
#ifdef CONFIG_SOFTMMU
@@ -8988,7 +8962,6 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
dc->fw_name = "PowerPC,POWER9";
dc->desc = "POWER9";
- device_class_set_props(dc, powerpc_servercpu_properties);
pcc->pvr_match = ppc_pvr_match_power9;
pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06 | PCR_COMPAT_2_07;
pcc->pcr_supported = PCR_COMPAT_3_00 | PCR_COMPAT_2_07 | PCR_COMPAT_2_06 |
@@ -9017,7 +8990,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 |
PPC2_TM | PPC2_ISA300 | PPC2_PRCNTL;
pcc->msr_mask = (1ull << MSR_SF) |
- (1ull << MSR_SHV) |
+ (1ull << MSR_HV) |
(1ull << MSR_TM) |
(1ull << MSR_VR) |
(1ull << MSR_VSX) |
@@ -9034,6 +9007,14 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
(1ull << MSR_PMM) |
(1ull << MSR_RI) |
(1ull << MSR_LE);
+ pcc->lpcr_mask = LPCR_VPM1 | LPCR_ISL | LPCR_KBV | LPCR_DPFD |
+ (LPCR_PECE_U_MASK & LPCR_HVEE) | LPCR_ILE | LPCR_AIL |
+ LPCR_UPRT | LPCR_EVIRT | LPCR_ONL | LPCR_HR | LPCR_LD |
+ (LPCR_PECE_L_MASK & (LPCR_PDEE | LPCR_HDEE | LPCR_EEE |
+ LPCR_DEE | LPCR_OEE))
+ | LPCR_MER | LPCR_GTSE | LPCR_TC |
+ LPCR_HEIC | LPCR_LPES0 | LPCR_HVICE | LPCR_HDICE;
+ pcc->lpcr_pm = LPCR_PDEE | LPCR_HDEE | LPCR_EEE | LPCR_DEE | LPCR_OEE;
pcc->mmu_model = POWERPC_MMU_3_00;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc64_v3_handle_mmu_fault;
@@ -9053,7 +9034,6 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
pcc->l1_dcache_size = 0x8000;
pcc->l1_icache_size = 0x8000;
pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;
- pcc->lpcr_pm = LPCR_PDEE | LPCR_HDEE | LPCR_EEE | LPCR_DEE | LPCR_OEE;
}
#ifdef CONFIG_SOFTMMU
@@ -9198,7 +9178,6 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
dc->fw_name = "PowerPC,POWER10";
dc->desc = "POWER10";
- device_class_set_props(dc, powerpc_servercpu_properties);
pcc->pvr_match = ppc_pvr_match_power10;
pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06 | PCR_COMPAT_2_07 |
PCR_COMPAT_3_00;
@@ -9228,7 +9207,7 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 |
PPC2_TM | PPC2_ISA300 | PPC2_PRCNTL;
pcc->msr_mask = (1ull << MSR_SF) |
- (1ull << MSR_SHV) |
+ (1ull << MSR_HV) |
(1ull << MSR_TM) |
(1ull << MSR_VR) |
(1ull << MSR_VSX) |
@@ -9245,6 +9224,14 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
(1ull << MSR_PMM) |
(1ull << MSR_RI) |
(1ull << MSR_LE);
+ pcc->lpcr_mask = LPCR_VPM1 | LPCR_ISL | LPCR_KBV | LPCR_DPFD |
+ (LPCR_PECE_U_MASK & LPCR_HVEE) | LPCR_ILE | LPCR_AIL |
+ LPCR_UPRT | LPCR_EVIRT | LPCR_ONL | LPCR_HR | LPCR_LD |
+ (LPCR_PECE_L_MASK & (LPCR_PDEE | LPCR_HDEE | LPCR_EEE |
+ LPCR_DEE | LPCR_OEE))
+ | LPCR_MER | LPCR_GTSE | LPCR_TC |
+ LPCR_HEIC | LPCR_LPES0 | LPCR_HVICE | LPCR_HDICE;
+ pcc->lpcr_pm = LPCR_PDEE | LPCR_HDEE | LPCR_EEE | LPCR_DEE | LPCR_OEE;
pcc->mmu_model = POWERPC_MMU_3_00;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc64_v3_handle_mmu_fault;
@@ -9263,7 +9250,6 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
pcc->l1_dcache_size = 0x8000;
pcc->l1_icache_size = 0x8000;
pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;
- pcc->lpcr_pm = LPCR_PDEE | LPCR_HDEE | LPCR_EEE | LPCR_DEE | LPCR_OEE;
}
#if !defined(CONFIG_USER_ONLY)
@@ -9857,7 +9843,7 @@ static int gdb_find_spr_idx(CPUPPCState *env, int n)
return -1;
}
-static int gdb_get_spr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
+static int gdb_get_spr_reg(CPUPPCState *env, GByteArray *buf, int n)
{
int reg;
int len;
@@ -9868,8 +9854,8 @@ static int gdb_get_spr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
}
len = TARGET_LONG_SIZE;
- stn_p(mem_buf, len, env->spr[reg]);
- ppc_maybe_bswap_register(env, mem_buf, len);
+ gdb_get_regl(buf, env->spr[reg]);
+ ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, len), len);
return len;
}
@@ -9891,15 +9877,18 @@ static int gdb_set_spr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
}
#endif
-static int gdb_get_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
+static int gdb_get_float_reg(CPUPPCState *env, GByteArray *buf, int n)
{
+ uint8_t *mem_buf;
if (n < 32) {
- stfq_p(mem_buf, *cpu_fpr_ptr(env, n));
+ gdb_get_reg64(buf, *cpu_fpr_ptr(env, n));
+ mem_buf = gdb_get_reg_ptr(buf, 8);
ppc_maybe_bswap_register(env, mem_buf, 8);
return 8;
}
if (n == 32) {
- stl_p(mem_buf, env->fpscr);
+ gdb_get_reg32(buf, env->fpscr);
+ mem_buf = gdb_get_reg_ptr(buf, 4);
ppc_maybe_bswap_register(env, mem_buf, 4);
return 4;
}
@@ -9921,28 +9910,31 @@ static int gdb_set_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
return 0;
}
-static int gdb_get_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
+static int gdb_get_avr_reg(CPUPPCState *env, GByteArray *buf, int n)
{
+ uint8_t *mem_buf;
+
if (n < 32) {
ppc_avr_t *avr = cpu_avr_ptr(env, n);
if (!avr_need_swap(env)) {
- stq_p(mem_buf, avr->u64[0]);
- stq_p(mem_buf + 8, avr->u64[1]);
+ gdb_get_reg128(buf, avr->u64[0] , avr->u64[1]);
} else {
- stq_p(mem_buf, avr->u64[1]);
- stq_p(mem_buf + 8, avr->u64[0]);
+ gdb_get_reg128(buf, avr->u64[1] , avr->u64[0]);
}
+ mem_buf = gdb_get_reg_ptr(buf, 16);
ppc_maybe_bswap_register(env, mem_buf, 8);
ppc_maybe_bswap_register(env, mem_buf + 8, 8);
return 16;
}
if (n == 32) {
- stl_p(mem_buf, helper_mfvscr(env));
+ gdb_get_reg32(buf, helper_mfvscr(env));
+ mem_buf = gdb_get_reg_ptr(buf, 4);
ppc_maybe_bswap_register(env, mem_buf, 4);
return 4;
}
if (n == 33) {
- stl_p(mem_buf, (uint32_t)env->spr[SPR_VRSAVE]);
+ gdb_get_reg32(buf, (uint32_t)env->spr[SPR_VRSAVE]);
+ mem_buf = gdb_get_reg_ptr(buf, 4);
ppc_maybe_bswap_register(env, mem_buf, 4);
return 4;
}
@@ -9977,25 +9969,25 @@ static int gdb_set_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
return 0;
}
-static int gdb_get_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
+static int gdb_get_spe_reg(CPUPPCState *env, GByteArray *buf, int n)
{
if (n < 32) {
#if defined(TARGET_PPC64)
- stl_p(mem_buf, env->gpr[n] >> 32);
- ppc_maybe_bswap_register(env, mem_buf, 4);
+ gdb_get_reg32(buf, env->gpr[n] >> 32);
+ ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 4), 4);
#else
- stl_p(mem_buf, env->gprh[n]);
+ gdb_get_reg32(buf, env->gprh[n]);
#endif
return 4;
}
if (n == 32) {
- stq_p(mem_buf, env->spe_acc);
- ppc_maybe_bswap_register(env, mem_buf, 8);
+ gdb_get_reg64(buf, env->spe_acc);
+ ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 8), 8);
return 8;
}
if (n == 33) {
- stl_p(mem_buf, env->spe_fscr);
- ppc_maybe_bswap_register(env, mem_buf, 4);
+ gdb_get_reg32(buf, env->spe_fscr);
+ ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 4), 4);
return 4;
}
return 0;
@@ -10030,11 +10022,11 @@ static int gdb_set_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
return 0;
}
-static int gdb_get_vsx_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
+static int gdb_get_vsx_reg(CPUPPCState *env, GByteArray *buf, int n)
{
if (n < 32) {
- stq_p(mem_buf, *cpu_vsrl_ptr(env, n));
- ppc_maybe_bswap_register(env, mem_buf, 8);
+ gdb_get_reg64(buf, *cpu_vsrl_ptr(env, n));
+ ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 8), 8);
return 8;
}
return 0;
@@ -10486,6 +10478,8 @@ static void ppc_cpu_parse_featurestr(const char *type, char *features,
*s = '\0';
for (i = 0; inpieces[i]; i++) {
if (g_str_has_prefix(inpieces[i], "compat=")) {
+ warn_report_once("CPU 'compat' property is deprecated; "
+ "use max-cpu-compat machine property instead");
compat_str = inpieces[i];
continue;
}
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 078fc83959..7d21addbab 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -293,7 +293,7 @@ extern const char * const riscv_excp_names[];
extern const char * const riscv_intr_names[];
void riscv_cpu_do_interrupt(CPUState *cpu);
-int riscv_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
bool riscv_cpu_fp_enabled(CPURISCVState *env);
diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c
index 2f32750f2f..eba12a86f2 100644
--- a/target/riscv/gdbstub.c
+++ b/target/riscv/gdbstub.c
@@ -270,7 +270,7 @@ static int csr_register_map[] = {
CSR_MHCOUNTEREN,
};
-int riscv_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int riscv_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
RISCVCPU *cpu = RISCV_CPU(cs);
CPURISCVState *env = &cpu->env;
@@ -301,14 +301,14 @@ int riscv_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
return 0;
}
-static int riscv_gdb_get_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
+static int riscv_gdb_get_fpu(CPURISCVState *env, GByteArray *buf, int n)
{
if (n < 32) {
if (env->misa & RVD) {
- return gdb_get_reg64(mem_buf, env->fpr[n]);
+ return gdb_get_reg64(buf, env->fpr[n]);
}
if (env->misa & RVF) {
- return gdb_get_reg32(mem_buf, env->fpr[n]);
+ return gdb_get_reg32(buf, env->fpr[n]);
}
/* there is hole between ft11 and fflags in fpu.xml */
} else if (n < 36 && n > 32) {
@@ -322,7 +322,7 @@ static int riscv_gdb_get_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
result = riscv_csrrw_debug(env, n - 33 + csr_register_map[8], &val,
0, 0);
if (result == 0) {
- return gdb_get_regl(mem_buf, val);
+ return gdb_get_regl(buf, val);
}
}
return 0;
@@ -351,7 +351,7 @@ static int riscv_gdb_set_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
return 0;
}
-static int riscv_gdb_get_csr(CPURISCVState *env, uint8_t *mem_buf, int n)
+static int riscv_gdb_get_csr(CPURISCVState *env, GByteArray *buf, int n)
{
if (n < ARRAY_SIZE(csr_register_map)) {
target_ulong val = 0;
@@ -359,7 +359,7 @@ static int riscv_gdb_get_csr(CPURISCVState *env, uint8_t *mem_buf, int n)
result = riscv_csrrw_debug(env, csr_register_map[n], &val, 0, 0);
if (result == 0) {
- return gdb_get_regl(mem_buf, val);
+ return gdb_get_regl(buf, val);
}
}
return 0;
@@ -379,13 +379,13 @@ static int riscv_gdb_set_csr(CPURISCVState *env, uint8_t *mem_buf, int n)
return 0;
}
-static int riscv_gdb_get_virtual(CPURISCVState *cs, uint8_t *mem_buf, int n)
+static int riscv_gdb_get_virtual(CPURISCVState *cs, GByteArray *buf, int n)
{
if (n == 0) {
#ifdef CONFIG_USER_ONLY
- return gdb_get_regl(mem_buf, 0);
+ return gdb_get_regl(buf, 0);
#else
- return gdb_get_regl(mem_buf, cs->priv);
+ return gdb_get_regl(buf, cs->priv);
#endif
}
return 0;
diff --git a/target/s390x/gdbstub.c b/target/s390x/gdbstub.c
index e24a49f4a9..d6fce5ff1e 100644
--- a/target/s390x/gdbstub.c
+++ b/target/s390x/gdbstub.c
@@ -27,7 +27,7 @@
#include "sysemu/hw_accel.h"
#include "sysemu/tcg.h"
-int s390_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int s390_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
S390CPU *cpu = S390_CPU(cs);
CPUS390XState *env = &cpu->env;
@@ -82,11 +82,11 @@ int s390_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
/* total number of registers in s390-acr.xml */
#define S390_NUM_AC_REGS 16
-static int cpu_read_ac_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
+static int cpu_read_ac_reg(CPUS390XState *env, GByteArray *buf, int n)
{
switch (n) {
case S390_A0_REGNUM ... S390_A15_REGNUM:
- return gdb_get_reg32(mem_buf, env->aregs[n]);
+ return gdb_get_reg32(buf, env->aregs[n]);
default:
return 0;
}
@@ -111,13 +111,13 @@ static int cpu_write_ac_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
/* total number of registers in s390-fpr.xml */
#define S390_NUM_FP_REGS 17
-static int cpu_read_fp_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
+static int cpu_read_fp_reg(CPUS390XState *env, GByteArray *buf, int n)
{
switch (n) {
case S390_FPC_REGNUM:
- return gdb_get_reg32(mem_buf, env->fpc);
+ return gdb_get_reg32(buf, env->fpc);
case S390_F0_REGNUM ... S390_F15_REGNUM:
- return gdb_get_reg64(mem_buf, *get_freg(env, n - S390_F0_REGNUM));
+ return gdb_get_reg64(buf, *get_freg(env, n - S390_F0_REGNUM));
default:
return 0;
}
@@ -145,17 +145,17 @@ static int cpu_write_fp_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
/* total number of registers in s390-vx.xml */
#define S390_NUM_VREGS 32
-static int cpu_read_vreg(CPUS390XState *env, uint8_t *mem_buf, int n)
+static int cpu_read_vreg(CPUS390XState *env, GByteArray *buf, int n)
{
int ret;
switch (n) {
case S390_V0L_REGNUM ... S390_V15L_REGNUM:
- ret = gdb_get_reg64(mem_buf, env->vregs[n][1]);
+ ret = gdb_get_reg64(buf, env->vregs[n][1]);
break;
case S390_V16_REGNUM ... S390_V31_REGNUM:
- ret = gdb_get_reg64(mem_buf, env->vregs[n][0]);
- ret += gdb_get_reg64(mem_buf + 8, env->vregs[n][1]);
+ ret = gdb_get_reg64(buf, env->vregs[n][0]);
+ ret += gdb_get_reg64(buf, env->vregs[n][1]);
break;
default:
ret = 0;
@@ -186,11 +186,11 @@ static int cpu_write_vreg(CPUS390XState *env, uint8_t *mem_buf, int n)
#define S390_NUM_C_REGS 16
#ifndef CONFIG_USER_ONLY
-static int cpu_read_c_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
+static int cpu_read_c_reg(CPUS390XState *env, GByteArray *buf, int n)
{
switch (n) {
case S390_C0_REGNUM ... S390_C15_REGNUM:
- return gdb_get_regl(mem_buf, env->cregs[n]);
+ return gdb_get_regl(buf, env->cregs[n]);
default:
return 0;
}
@@ -223,7 +223,7 @@ static int cpu_write_c_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
/* total number of registers in s390-virt.xml */
#define S390_NUM_VIRT_REGS 8
-static int cpu_read_virt_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
+static int cpu_read_virt_reg(CPUS390XState *env, GByteArray *mem_buf, int n)
{
switch (n) {
case S390_VIRT_CKC_REGNUM:
@@ -296,9 +296,9 @@ static int cpu_write_virt_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
/* total number of registers in s390-gs.xml */
#define S390_NUM_GS_REGS 4
-static int cpu_read_gs_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
+static int cpu_read_gs_reg(CPUS390XState *env, GByteArray *buf, int n)
{
- return gdb_get_regl(mem_buf, env->gscb[n]);
+ return gdb_get_regl(buf, env->gscb[n]);
}
static int cpu_write_gs_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
diff --git a/target/s390x/internal.h b/target/s390x/internal.h
index d37816104d..8c95c734db 100644
--- a/target/s390x/internal.h
+++ b/target/s390x/internal.h
@@ -292,7 +292,7 @@ uint16_t float128_dcmask(CPUS390XState *env, float128 f1);
/* gdbstub.c */
-int s390_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int s390_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int s390_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void s390_cpu_gdb_init(CPUState *cs);
diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h
index 452a596e67..dbe58c7888 100644
--- a/target/sh4/cpu.h
+++ b/target/sh4/cpu.h
@@ -208,7 +208,7 @@ void superh_cpu_do_interrupt(CPUState *cpu);
bool superh_cpu_exec_interrupt(CPUState *cpu, int int_req);
void superh_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
hwaddr superh_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int superh_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int superh_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int superh_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void superh_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
MMUAccessType access_type,
diff --git a/target/sh4/gdbstub.c b/target/sh4/gdbstub.c
index 44c1679e9d..49fc4a0cc6 100644
--- a/target/sh4/gdbstub.c
+++ b/target/sh4/gdbstub.c
@@ -24,7 +24,7 @@
/* Hint: Use "set architecture sh4" in GDB to see fpu registers */
/* FIXME: We should use XML for this. */
-int superh_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int superh_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
SuperHCPU *cpu = SUPERH_CPU(cs);
CPUSH4State *env = &cpu->env;
diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index ae97c7d9f7..b9369398f2 100644
--- a/target/sparc/cpu.h
+++ b/target/sparc/cpu.h
@@ -571,7 +571,7 @@ extern const VMStateDescription vmstate_sparc_cpu;
void sparc_cpu_do_interrupt(CPUState *cpu);
void sparc_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
hwaddr sparc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int sparc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int sparc_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int sparc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void QEMU_NORETURN sparc_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
MMUAccessType access_type,
diff --git a/target/sparc/gdbstub.c b/target/sparc/gdbstub.c
index 8be742b5a3..78dc8dcc98 100644
--- a/target/sparc/gdbstub.c
+++ b/target/sparc/gdbstub.c
@@ -27,7 +27,7 @@
#define gdb_get_rega(buf, val) gdb_get_regl(buf, val)
#endif
-int sparc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int sparc_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
SPARCCPU *cpu = SPARC_CPU(cs);
CPUSPARCState *env = &cpu->env;
diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h
index 493f4fc80c..c0d69fad96 100644
--- a/target/xtensa/cpu.h
+++ b/target/xtensa/cpu.h
@@ -569,7 +569,7 @@ void xtensa_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
void xtensa_count_regs(const XtensaConfig *config,
unsigned *n_regs, unsigned *n_core_regs);
-int xtensa_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int xtensa_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int xtensa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void xtensa_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
MMUAccessType access_type,
diff --git a/target/xtensa/gdbstub.c b/target/xtensa/gdbstub.c
index 54727881f3..0ee3feabe5 100644
--- a/target/xtensa/gdbstub.c
+++ b/target/xtensa/gdbstub.c
@@ -63,7 +63,7 @@ void xtensa_count_regs(const XtensaConfig *config,
}
}
-int xtensa_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+int xtensa_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
XtensaCPU *cpu = XTENSA_CPU(cs);
CPUXtensaState *env = &cpu->env;
diff --git a/tcg/i386/tcg-target.inc.c b/tcg/i386/tcg-target.inc.c
index cdedcb2b25..223dba9c8c 100644
--- a/tcg/i386/tcg-target.inc.c
+++ b/tcg/i386/tcg-target.inc.c
@@ -3391,12 +3391,15 @@ static void expand_vec_sari(TCGType type, unsigned vece,
case MO_64:
if (imm <= 32) {
- /* We can emulate a small sign extend by performing an arithmetic
+ /*
+ * We can emulate a small sign extend by performing an arithmetic
* 32-bit shift and overwriting the high half of a 64-bit logical
- * shift (note that the ISA says shift of 32 is valid).
+ * shift. Note that the ISA says shift of 32 is valid, but TCG
+ * does not, so we have to bound the smaller shift -- we get the
+ * same result in the high half either way.
*/
t1 = tcg_temp_new_vec(type);
- tcg_gen_sari_vec(MO_32, t1, v1, imm);
+ tcg_gen_sari_vec(MO_32, t1, v1, MIN(imm, 31));
tcg_gen_shri_vec(MO_64, v0, v1, imm);
vec_gen_4(INDEX_op_x86_blend_vec, type, MO_32,
tcgv_vec_arg(v0), tcgv_vec_arg(v0),
diff --git a/tests/.gitignore b/tests/.gitignore
index 7306866f21..d03c037d77 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -10,6 +10,7 @@ qht-bench
rcutorture
test-*
!test-*.c
+!test-*.py
!docker/test-*
test-qapi-commands.[ch]
test-qapi-init-commands.[ch]
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 67e8fcddda..51de676298 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -20,6 +20,8 @@ check-help:
@echo " $(MAKE) check-venv Creates a Python venv for tests"
@echo " $(MAKE) check-clean Clean the tests and related data"
@echo
+ @echo " $(MAKE) get-vm-images Downloads all images used by acceptance tests, according to configured targets (~350 MB each, 1.5 GB max)"
+ @echo
@echo
@echo "The variable SPEED can be set to control the gtester speed setting."
@echo "Default options are -k and (for $(MAKE) V=1) --verbose; they can be"
@@ -242,6 +244,7 @@ qapi-schema += event-case.json
qapi-schema += event-member-invalid-dict.json
qapi-schema += event-nest-struct.json
qapi-schema += features-bad-type.json
+qapi-schema += features-deprecated-type.json
qapi-schema += features-duplicate-name.json
qapi-schema += features-if-invalid.json
qapi-schema += features-missing-name.json
@@ -889,7 +892,21 @@ $(TESTS_RESULTS_DIR):
check-venv: $(TESTS_VENV_DIR)
-check-acceptance: check-venv $(TESTS_RESULTS_DIR)
+FEDORA_31_ARCHES_CANDIDATES=$(patsubst ppc64,ppc64le,$(TARGETS))
+FEDORA_31_ARCHES := x86_64 aarch64 ppc64le s390x
+FEDORA_31_DOWNLOAD=$(filter $(FEDORA_31_ARCHES),$(FEDORA_31_ARCHES_CANDIDATES))
+
+# download one specific Fedora 31 image
+get-vm-image-fedora-31-%: check-venv
+ $(call quiet-command, \
+ $(TESTS_VENV_DIR)/bin/python -m avocado vmimage get \
+ --distro=fedora --distro-version=31 --arch=$*, \
+ "AVOCADO", "Downloading acceptance tests VM image for $*")
+
+# download all vm images, according to defined targets
+get-vm-images: check-venv $(patsubst %,get-vm-image-fedora-31-%, $(FEDORA_31_DOWNLOAD))
+
+check-acceptance: check-venv $(TESTS_RESULTS_DIR) get-vm-images
$(call quiet-command, \
$(TESTS_VENV_DIR)/bin/python -m avocado \
--show=$(AVOCADO_SHOW) run --job-results-dir=$(TESTS_RESULTS_DIR) \
@@ -900,7 +917,7 @@ check-acceptance: check-venv $(TESTS_RESULTS_DIR)
# Consolidated targets
-.PHONY: check-block check-qapi-schema check-qtest check-unit check check-clean
+.PHONY: check-block check-qapi-schema check-qtest check-unit check check-clean get-vm-images
check-qapi-schema: check-tests/qapi-schema/frontend check-tests/qapi-schema/doc-good.texi
check-qtest: $(patsubst %,check-qtest-%, $(QTEST_TARGETS))
ifeq ($(CONFIG_TOOLS),y)
diff --git a/tests/acceptance/avocado_qemu/__init__.py b/tests/acceptance/avocado_qemu/__init__.py
index d4358eb431..59e7b4f763 100644
--- a/tests/acceptance/avocado_qemu/__init__.py
+++ b/tests/acceptance/avocado_qemu/__init__.py
@@ -16,8 +16,21 @@ import tempfile
import avocado
-SRC_ROOT_DIR = os.path.join(os.path.dirname(__file__), '..', '..', '..')
-sys.path.append(os.path.join(SRC_ROOT_DIR, 'python'))
+#: The QEMU build root directory. It may also be the source directory
+#: if building from the source dir, but it's safer to use BUILD_DIR for
+#: that purpose. Be aware that if this code is moved outside of a source
+#: and build tree, it will not be accurate.
+BUILD_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
+
+if os.path.islink(os.path.dirname(os.path.dirname(__file__))):
+ # The link to the acceptance tests dir in the source code directory
+ lnk = os.path.dirname(os.path.dirname(__file__))
+ #: The QEMU root source directory
+ SOURCE_DIR = os.path.dirname(os.path.dirname(os.readlink(lnk)))
+else:
+ SOURCE_DIR = BUILD_DIR
+
+sys.path.append(os.path.join(SOURCE_DIR, 'python'))
from qemu.machine import QEMUMachine
@@ -49,10 +62,10 @@ def pick_default_qemu_bin(arch=None):
if is_readable_executable_file(qemu_bin_relative_path):
return qemu_bin_relative_path
- qemu_bin_from_src_dir_path = os.path.join(SRC_ROOT_DIR,
+ qemu_bin_from_bld_dir_path = os.path.join(BUILD_DIR,
qemu_bin_relative_path)
- if is_readable_executable_file(qemu_bin_from_src_dir_path):
- return qemu_bin_from_src_dir_path
+ if is_readable_executable_file(qemu_bin_from_bld_dir_path):
+ return qemu_bin_from_bld_dir_path
def _console_interaction(test, success_message, failure_message,
@@ -153,7 +166,7 @@ class Test(avocado.Test):
self.qemu_bin = self.params.get('qemu_bin',
default=default_qemu_bin)
if self.qemu_bin is None:
- self.cancel("No QEMU binary defined or found in the source tree")
+ self.cancel("No QEMU binary defined or found in the build tree")
def _new_vm(self, *args):
vm = QEMUMachine(self.qemu_bin, sock_dir=tempfile.mkdtemp())
diff --git a/tests/acceptance/boot_linux.py b/tests/acceptance/boot_linux.py
new file mode 100644
index 0000000000..075a386300
--- /dev/null
+++ b/tests/acceptance/boot_linux.py
@@ -0,0 +1,222 @@
+# Functional test that boots a complete Linux system via a cloud image
+#
+# Copyright (c) 2018-2020 Red Hat, Inc.
+#
+# Author:
+# Cleber Rosa <crosa@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+import os
+
+from avocado_qemu import Test, BUILD_DIR
+
+from qemu.accel import kvm_available
+from qemu.accel import tcg_available
+
+from avocado.utils import cloudinit
+from avocado.utils import network
+from avocado.utils import vmimage
+from avocado.utils import datadrainer
+from avocado.utils.path import find_command
+
+ACCEL_NOT_AVAILABLE_FMT = "%s accelerator does not seem to be available"
+KVM_NOT_AVAILABLE = ACCEL_NOT_AVAILABLE_FMT % "KVM"
+TCG_NOT_AVAILABLE = ACCEL_NOT_AVAILABLE_FMT % "TCG"
+
+
+class BootLinux(Test):
+ """
+ Boots a Linux system, checking for a successful initialization
+ """
+
+ timeout = 900
+ chksum = None
+
+ def setUp(self):
+ super(BootLinux, self).setUp()
+ self.vm.add_args('-smp', '2')
+ self.vm.add_args('-m', '1024')
+ self.prepare_boot()
+ self.prepare_cloudinit()
+
+ def prepare_boot(self):
+ self.log.debug('Looking for and selecting a qemu-img binary to be '
+ 'used to create the bootable snapshot image')
+ # If qemu-img has been built, use it, otherwise the system wide one
+ # will be used. If none is available, the test will cancel.
+ qemu_img = os.path.join(BUILD_DIR, 'qemu-img')
+ if not os.path.exists(qemu_img):
+ qemu_img = find_command('qemu-img', False)
+ if qemu_img is False:
+ self.cancel('Could not find "qemu-img", which is required to '
+ 'create the bootable image')
+ vmimage.QEMU_IMG = qemu_img
+
+ self.log.info('Downloading/preparing boot image')
+ # Fedora 31 only provides ppc64le images
+ image_arch = self.arch
+ if image_arch == 'ppc64':
+ image_arch = 'ppc64le'
+ try:
+ self.boot = vmimage.get(
+ 'fedora', arch=image_arch, version='31',
+ checksum=self.chksum,
+ algorithm='sha256',
+ cache_dir=self.cache_dirs[0],
+ snapshot_dir=self.workdir)
+ self.vm.add_args('-drive', 'file=%s' % self.boot.path)
+ except:
+ self.cancel('Failed to download/prepare boot image')
+
+ def prepare_cloudinit(self):
+ self.log.info('Preparing cloudinit image')
+ try:
+ cloudinit_iso = os.path.join(self.workdir, 'cloudinit.iso')
+ self.phone_home_port = network.find_free_port()
+ cloudinit.iso(cloudinit_iso, self.name,
+ username='root',
+ password='password',
+ # QEMU's hard coded usermode router address
+ phone_home_host='10.0.2.2',
+ phone_home_port=self.phone_home_port)
+ self.vm.add_args('-drive', 'file=%s,format=raw' % cloudinit_iso)
+ except Exception:
+ self.cancel('Failed to prepared cloudinit image')
+
+ def launch_and_wait(self):
+ self.vm.set_console()
+ self.vm.launch()
+ console_drainer = datadrainer.LineLogger(self.vm.console_socket.fileno(),
+ logger=self.log.getChild('console'))
+ console_drainer.start()
+ self.log.info('VM launched, waiting for boot confirmation from guest')
+ cloudinit.wait_for_phone_home(('0.0.0.0', self.phone_home_port), self.name)
+
+
+class BootLinuxX8664(BootLinux):
+ """
+ :avocado: tags=arch:x86_64
+ """
+
+ chksum = 'e3c1b309d9203604922d6e255c2c5d098a309c2d46215d8fc026954f3c5c27a0'
+
+ def test_pc_i440fx_tcg(self):
+ """
+ :avocado: tags=machine:pc
+ :avocado: tags=accel:tcg
+ """
+ if not tcg_available(self.qemu_bin):
+ self.cancel(TCG_NOT_AVAILABLE)
+ self.vm.add_args("-accel", "tcg")
+ self.launch_and_wait()
+
+ def test_pc_i440fx_kvm(self):
+ """
+ :avocado: tags=machine:pc
+ :avocado: tags=accel:kvm
+ """
+ if not kvm_available(self.arch, self.qemu_bin):
+ self.cancel(KVM_NOT_AVAILABLE)
+ self.vm.add_args("-accel", "kvm")
+ self.launch_and_wait()
+
+ def test_pc_q35_tcg(self):
+ """
+ :avocado: tags=machine:q35
+ :avocado: tags=accel:tcg
+ """
+ if not tcg_available(self.qemu_bin):
+ self.cancel(TCG_NOT_AVAILABLE)
+ self.vm.add_args("-accel", "tcg")
+ self.launch_and_wait()
+
+ def test_pc_q35_kvm(self):
+ """
+ :avocado: tags=machine:q35
+ :avocado: tags=accel:kvm
+ """
+ if not kvm_available(self.arch, self.qemu_bin):
+ self.cancel(KVM_NOT_AVAILABLE)
+ self.vm.add_args("-accel", "kvm")
+ self.launch_and_wait()
+
+
+class BootLinuxAarch64(BootLinux):
+ """
+ :avocado: tags=arch:aarch64
+ :avocado: tags=machine:virt
+ :avocado: tags=machine:gic-version=2
+ """
+
+ chksum = '1e18d9c0cf734940c4b5d5ec592facaed2af0ad0329383d5639c997fdf16fe49'
+
+ def add_common_args(self):
+ self.vm.add_args('-bios',
+ os.path.join(BUILD_DIR, 'pc-bios',
+ 'edk2-aarch64-code.fd'))
+ self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0')
+ self.vm.add_args('-object', 'rng-random,id=rng0,filename=/dev/urandom')
+
+ def test_virt_tcg(self):
+ """
+ :avocado: tags=accel:tcg
+ :avocado: tags=cpu:max
+ """
+ if not tcg_available(self.qemu_bin):
+ self.cancel(TCG_NOT_AVAILABLE)
+ self.vm.add_args("-accel", "tcg")
+ self.vm.add_args("-cpu", "max")
+ self.vm.add_args("-machine", "virt,gic-version=2")
+ self.add_common_args()
+ self.launch_and_wait()
+
+ def test_virt_kvm(self):
+ """
+ :avocado: tags=accel:kvm
+ :avocado: tags=cpu:host
+ """
+ if not kvm_available(self.arch, self.qemu_bin):
+ self.cancel(KVM_NOT_AVAILABLE)
+ self.vm.add_args("-accel", "kvm")
+ self.vm.add_args("-cpu", "host")
+ self.vm.add_args("-machine", "virt,gic-version=2")
+ self.add_common_args()
+ self.launch_and_wait()
+
+
+class BootLinuxPPC64(BootLinux):
+ """
+ :avocado: tags=arch:ppc64
+ """
+
+ chksum = '7c3528b85a3df4b2306e892199a9e1e43f991c506f2cc390dc4efa2026ad2f58'
+
+ def test_pseries_tcg(self):
+ """
+ :avocado: tags=machine:pseries
+ :avocado: tags=accel:tcg
+ """
+ if not tcg_available(self.qemu_bin):
+ self.cancel(TCG_NOT_AVAILABLE)
+ self.vm.add_args("-accel", "tcg")
+ self.launch_and_wait()
+
+
+class BootLinuxS390X(BootLinux):
+ """
+ :avocado: tags=arch:s390x
+ """
+
+ chksum = '4caaab5a434fd4d1079149a072fdc7891e354f834d355069ca982fdcaf5a122d'
+
+ def test_s390_ccw_virtio_tcg(self):
+ """
+ :avocado: tags=machine:s390-ccw-virtio
+ :avocado: tags=accel:tcg
+ """
+ if not tcg_available(self.qemu_bin):
+ self.cancel(TCG_NOT_AVAILABLE)
+ self.vm.add_args("-accel", "tcg")
+ self.launch_and_wait()
diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker
new file mode 100644
index 0000000000..bfa0d33c9c
--- /dev/null
+++ b/tests/docker/dockerfiles/centos8.docker
@@ -0,0 +1,32 @@
+FROM centos:8.1.1911
+
+RUN dnf -y update
+ENV PACKAGES \
+ SDL-devel \
+ bison \
+ bzip2 \
+ bzip2-devel \
+ dbus-daemon \
+ flex \
+ gcc \
+ gcc-c++ \
+ gettext \
+ git \
+ glib2-devel \
+ libaio-devel \
+ libepoxy-devel \
+ lzo-devel \
+ make \
+ mesa-libEGL-devel \
+ nettle-devel \
+ perl-Test-Harness \
+ pixman-devel \
+ python36 \
+ rdma-core-devel \
+ spice-glib-devel \
+ spice-server \
+ tar \
+ zlib-devel
+
+RUN dnf install -y $PACKAGES
+RUN rpm -q $PACKAGES | sort > /packages.txt
diff --git a/tests/docker/dockerfiles/debian-amd64.docker b/tests/docker/dockerfiles/debian-amd64.docker
index 0456fc7a0c..d4849f509f 100644
--- a/tests/docker/dockerfiles/debian-amd64.docker
+++ b/tests/docker/dockerfiles/debian-amd64.docker
@@ -28,9 +28,9 @@ RUN apt update && \
libegl1-mesa-dev \
libepoxy-dev \
libgbm-dev
-RUN git clone https://anongit.freedesktop.org/git/virglrenderer.git /usr/src/virglrenderer && \
- cd /usr/src/virglrenderer && git checkout virglrenderer-0.7.0
-RUN cd /usr/src/virglrenderer && ./autogen.sh && ./configure --with-glx --disable-tests && make install
+RUN git clone https://gitlab.freedesktop.org/virgl/virglrenderer.git /usr/src/virglrenderer && \
+ cd /usr/src/virglrenderer && git checkout virglrenderer-0.8.0
+RUN cd /usr/src/virglrenderer && ./autogen.sh && ./configure --disable-tests && make install
# netmap
RUN apt update && \
diff --git a/tests/docker/dockerfiles/debian-win32-cross.docker b/tests/docker/dockerfiles/debian-win32-cross.docker
index 9d7053e59d..d16d6431bc 100644
--- a/tests/docker/dockerfiles/debian-win32-cross.docker
+++ b/tests/docker/dockerfiles/debian-win32-cross.docker
@@ -9,7 +9,7 @@ MAINTAINER Philippe Mathieu-Daudé <f4bug@amsat.org>
ENV TARGET i686
-ENV PATH $PATH:/usr/lib/mxe/usr/$TARGET-w64-mingw32.shared/bin
+ENV PATH $PATH:/usr/lib/mxe/usr/bin:/usr/lib/mxe/usr/$TARGET-w64-mingw32.shared/bin
ENV PKG_CONFIG_PATH \
$PKG_CONFIG_PATH:/usr/lib/mxe/usr/$TARGET-w64-mingw32.shared/lib/pkgconfig
diff --git a/tests/docker/dockerfiles/debian10.docker b/tests/docker/dockerfiles/debian10.docker
index 5de79ae552..2fcdc406e8 100644
--- a/tests/docker/dockerfiles/debian10.docker
+++ b/tests/docker/dockerfiles/debian10.docker
@@ -17,14 +17,17 @@ RUN apt update && \
DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \
DEBIAN_FRONTEND=noninteractive eatmydata \
apt install -y --no-install-recommends \
+ bc \
bison \
build-essential \
ca-certificates \
clang \
dbus \
flex \
+ gdb-multiarch \
gettext \
git \
+ libncurses5-dev \
pkg-config \
psmisc \
python3 \
diff --git a/tests/docker/dockerfiles/debian9.docker b/tests/docker/dockerfiles/debian9.docker
index 8cbd742bb5..92edbbf0f4 100644
--- a/tests/docker/dockerfiles/debian9.docker
+++ b/tests/docker/dockerfiles/debian9.docker
@@ -17,13 +17,16 @@ RUN apt update && \
DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \
DEBIAN_FRONTEND=noninteractive eatmydata \
apt install -y --no-install-recommends \
+ bc \
bison \
build-essential \
ca-certificates \
clang \
flex \
+ gdb-multiarch \
gettext \
git \
+ libncurses5-dev \
pkg-config \
psmisc \
python3 \
diff --git a/tests/guest-debug/run-test.py b/tests/guest-debug/run-test.py
new file mode 100755
index 0000000000..8c49ee2f22
--- /dev/null
+++ b/tests/guest-debug/run-test.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3
+#
+# Run a gdbstub test case
+#
+# Copyright (c) 2019 Linaro
+#
+# Author: Alex Bennée <alex.bennee@linaro.org>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later.
+# See the COPYING file in the top-level directory.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import argparse
+import subprocess
+import shutil
+import shlex
+
+def get_args():
+ parser = argparse.ArgumentParser(description="A gdbstub test runner")
+ parser.add_argument("--qemu", help="Qemu binary for test",
+ required=True)
+ parser.add_argument("--qargs", help="Qemu arguments for test")
+ parser.add_argument("--binary", help="Binary to debug",
+ required=True)
+ parser.add_argument("--test", help="GDB test script",
+ required=True)
+ parser.add_argument("--gdb", help="The gdb binary to use", default=None)
+
+ return parser.parse_args()
+
+if __name__ == '__main__':
+ args = get_args()
+
+ # Search for a gdb we can use
+ if not args.gdb:
+ args.gdb = shutil.which("gdb-multiarch")
+ if not args.gdb:
+ args.gdb = shutil.which("gdb")
+ if not args.gdb:
+ print("We need gdb to run the test")
+ exit(-1)
+
+ # Launch QEMU with binary
+ if "system" in args.qemu:
+ cmd = "%s %s %s -s -S" % (args.qemu, args.qargs, args.binary)
+ else:
+ cmd = "%s %s -g 1234 %s" % (args.qemu, args.qargs, args.binary)
+
+ inferior = subprocess.Popen(shlex.split(cmd))
+
+ # Now launch gdb with our test and collect the result
+ gdb_cmd = "%s %s -ex 'target remote localhost:1234' -x %s" % (args.gdb, args.binary, args.test)
+
+ result = subprocess.call(gdb_cmd, shell=True);
+
+ exit(result)
diff --git a/tests/qapi-schema/alternate-base.err b/tests/qapi-schema/alternate-base.err
index 31ebe56bbf..970a08ab26 100644
--- a/tests/qapi-schema/alternate-base.err
+++ b/tests/qapi-schema/alternate-base.err
@@ -1,3 +1,3 @@
alternate-base.json: In alternate 'Alt':
alternate-base.json:4: alternate has unknown key 'base'
-Valid keys are 'alternate', 'data', 'if'.
+Valid keys are 'alternate', 'data', 'features', 'if'.
diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.json
index d992e713d9..ddd89d1233 100644
--- a/tests/qapi-schema/doc-good.json
+++ b/tests/qapi-schema/doc-good.json
@@ -53,10 +53,14 @@
# @Enum:
# @one: The _one_ {and only}
#
+# Features:
+# @enum-feat: Also _one_ {and only}
+#
# @two is undocumented
##
{ 'enum': 'Enum', 'data':
[ { 'name': 'one', 'if': 'defined(IFONE)' }, 'two' ],
+ 'features': [ 'enum-feat' ],
'if': 'defined(IFCOND)' }
##
@@ -74,10 +78,13 @@
#
# Features:
# @variant1-feat: a feature
+# @member-feat: a member feature
##
{ 'struct': 'Variant1',
'features': [ 'variant1-feat' ],
- 'data': { 'var1': { 'type': 'str', 'if': 'defined(IFSTR)' } } }
+ 'data': { 'var1': { 'type': 'str',
+ 'features': [ 'member-feat' ],
+ 'if': 'defined(IFSTR)' } } }
##
# @Variant2:
@@ -86,24 +93,34 @@
##
# @Object:
+# Features:
+# @union-feat1: a feature
##
{ 'union': 'Object',
+ 'features': [ 'union-feat1' ],
'base': 'Base',
'discriminator': 'base1',
'data': { 'one': 'Variant1', 'two': { 'type': 'Variant2', 'if': 'IFTWO' } } }
##
# @SugaredUnion:
+# Features:
+# @union-feat2: a feature
##
{ 'union': 'SugaredUnion',
+ 'features': [ 'union-feat2' ],
'data': { 'one': 'Variant1', 'two': { 'type': 'Variant2', 'if': 'IFTWO' } } }
##
# @Alternate:
# @i: an integer
# @b is undocumented
+#
+# Features:
+# @alt-feat: a feature
##
{ 'alternate': 'Alternate',
+ 'features': [ 'alt-feat' ],
'data': { 'i': 'int', 'b': 'bool' } }
##
@@ -160,6 +177,9 @@
##
# @EVT-BOXED:
+# Features:
+# @feat3: a feature
##
{ 'event': 'EVT-BOXED', 'boxed': true,
+ 'features': [ 'feat3' ],
'data': 'Object' }
diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out
index 4c9406a464..6757dd26a2 100644
--- a/tests/qapi-schema/doc-good.out
+++ b/tests/qapi-schema/doc-good.out
@@ -15,11 +15,13 @@ enum Enum
if ['defined(IFONE)']
member two
if ['defined(IFCOND)']
+ feature enum-feat
object Base
member base1: Enum optional=False
object Variant1
member var1: str optional=False
if ['defined(IFSTR)']
+ feature member-feat
feature variant1-feat
object Variant2
object Object
@@ -28,6 +30,7 @@ object Object
case one: Variant1
case two: Variant2
if ['IFTWO']
+ feature union-feat1
object q_obj_Variant1-wrapper
member data: Variant1 optional=False
object q_obj_Variant2-wrapper
@@ -42,10 +45,12 @@ object SugaredUnion
case one: q_obj_Variant1-wrapper
case two: q_obj_Variant2-wrapper
if ['IFTWO']
+ feature union-feat2
alternate Alternate
tag type
case i: int
case b: bool
+ feature alt-feat
object q_obj_cmd-arg
member arg1: int optional=False
member arg2: str optional=True
@@ -60,6 +65,7 @@ command cmd-boxed Object -> None
feature cmd-feat2
event EVT-BOXED Object
boxed=True
+ feature feat3
doc freeform
body=
= Section
@@ -112,6 +118,8 @@ doc symbol=Enum
The _one_ {and only}
arg=two
+ feature=enum-feat
+Also _one_ {and only}
section=None
@two is undocumented
doc symbol=Base
@@ -128,17 +136,23 @@ Another paragraph (but no @var: line)
feature=variant1-feat
a feature
+ feature=member-feat
+a member feature
doc symbol=Variant2
body=
doc symbol=Object
body=
+ feature=union-feat1
+a feature
doc symbol=SugaredUnion
body=
arg=type
+ feature=union-feat2
+a feature
doc symbol=Alternate
body=
@@ -147,6 +161,8 @@ an integer
@b is undocumented
arg=b
+ feature=alt-feat
+a feature
doc freeform
body=
== Another subsection
@@ -197,3 +213,5 @@ another feature
doc symbol=EVT-BOXED
body=
+ feature=feat3
+a feature
diff --git a/tests/qapi-schema/doc-good.texi b/tests/qapi-schema/doc-good.texi
index d4b15dabf0..7f28fb7a0f 100644
--- a/tests/qapi-schema/doc-good.texi
+++ b/tests/qapi-schema/doc-good.texi
@@ -88,6 +88,12 @@ The @emph{one} @{and only@}
@item @code{two}
Not documented
@end table
+
+@b{Features:}
+@table @asis
+@item @code{enum-feat}
+Also @emph{one} @{and only@}
+@end table
@code{two} is undocumented
@b{If:} @code{defined(IFCOND)}
@@ -126,6 +132,8 @@ Not documented
@table @asis
@item @code{variant1-feat}
a feature
+@item @code{member-feat}
+a member feature
@end table
@end deftp
@@ -151,6 +159,12 @@ a feature
@item The members of @code{Variant2} when @code{base1} is @t{"two"} (@b{If:} @code{IFTWO})
@end table
+@b{Features:}
+@table @asis
+@item @code{union-feat1}
+a feature
+@end table
+
@end deftp
@@ -167,6 +181,12 @@ One of @t{"one"}, @t{"two"}
@item @code{data: Variant2} when @code{type} is @t{"two"} (@b{If:} @code{IFTWO})
@end table
+@b{Features:}
+@table @asis
+@item @code{union-feat2}
+a feature
+@end table
+
@end deftp
@@ -184,6 +204,12 @@ an integer
Not documented
@end table
+@b{Features:}
+@table @asis
+@item @code{alt-feat}
+a feature
+@end table
+
@end deftp
@@ -283,5 +309,11 @@ another feature
@b{Arguments:} the members of @code{Object}
+@b{Features:}
+@table @asis
+@item @code{feat3}
+a feature
+@end table
+
@end deftypefn
diff --git a/tests/qapi-schema/features-deprecated-type.err b/tests/qapi-schema/features-deprecated-type.err
new file mode 100644
index 0000000000..af4ffe20aa
--- /dev/null
+++ b/tests/qapi-schema/features-deprecated-type.err
@@ -0,0 +1,2 @@
+features-deprecated-type.json: In struct 'S':
+features-deprecated-type.json:2: feature 'deprecated' is not supported for types
diff --git a/tests/qapi-schema/features-deprecated-type.json b/tests/qapi-schema/features-deprecated-type.json
new file mode 100644
index 0000000000..4b5bf5b86e
--- /dev/null
+++ b/tests/qapi-schema/features-deprecated-type.json
@@ -0,0 +1,3 @@
+# Feature 'deprecated' is not supported for types
+{ 'struct': 'S', 'data': {},
+ 'features': [ 'deprecated' ] }
diff --git a/tests/qapi-schema/features-deprecated-type.out b/tests/qapi-schema/features-deprecated-type.out
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/qapi-schema/features-deprecated-type.out
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index 9abf175fe0..6b1f05afa7 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -252,13 +252,13 @@
'bar': { 'type': ['TestIfEnum'], 'if': 'defined(TEST_IF_EVT_BAR)' } },
'if': 'defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)' }
-# test 'features' for structs
+# test 'features'
{ 'struct': 'FeatureStruct0',
'data': { 'foo': 'int' },
'features': [] }
{ 'struct': 'FeatureStruct1',
- 'data': { 'foo': 'int' },
+ 'data': { 'foo': { 'type': 'int', 'features': [ 'deprecated' ] } },
'features': [ 'feature1' ] }
{ 'struct': 'FeatureStruct2',
'data': { 'foo': 'int' },
@@ -281,7 +281,22 @@
'data': { 'foo': 'int' },
'features': [ { 'name': 'feature1', 'if': [ 'defined(TEST_IF_COND_1)',
'defined(TEST_IF_COND_2)'] } ] }
-{ 'command': 'test-features',
+
+{ 'enum': 'FeatureEnum1',
+ 'data': [ 'eins', 'zwei', 'drei' ],
+ 'features': [ 'feature1' ] }
+
+{ 'union': 'FeatureUnion1',
+ 'base': { 'tag': 'FeatureEnum1' },
+ 'discriminator': 'tag',
+ 'data': { 'eins': 'FeatureStruct1' },
+ 'features': [ 'feature1' ] }
+
+{ 'alternate': 'FeatureAlternate1',
+ 'data': { 'eins': 'FeatureStruct1' },
+ 'features': [ 'feature1' ] }
+
+{ 'command': 'test-features0',
'data': { 'fs0': 'FeatureStruct0',
'fs1': 'FeatureStruct1',
'fs2': 'FeatureStruct2',
@@ -289,14 +304,11 @@
'fs4': 'FeatureStruct4',
'cfs1': 'CondFeatureStruct1',
'cfs2': 'CondFeatureStruct2',
- 'cfs3': 'CondFeatureStruct3' } }
-
-# test 'features' for command
-
-{ 'command': 'test-command-features0',
+ 'cfs3': 'CondFeatureStruct3' },
'features': [] }
+
{ 'command': 'test-command-features1',
- 'features': [ 'feature1' ] }
+ 'features': [ 'deprecated' ] }
{ 'command': 'test-command-features3',
'features': [ 'feature1', 'feature2' ] }
@@ -308,3 +320,6 @@
{ 'command': 'test-command-cond-features3',
'features': [ { 'name': 'feature1', 'if': [ 'defined(TEST_IF_COND_1)',
'defined(TEST_IF_COND_2)'] } ] }
+
+{ 'event': 'TEST-EVENT-FEATURES1',
+ 'features': [ 'deprecated' ] }
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 9bd3c4a490..891b4101e0 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -359,6 +359,7 @@ object FeatureStruct0
member foo: int optional=False
object FeatureStruct1
member foo: int optional=False
+ feature deprecated
feature feature1
object FeatureStruct2
member foo: int optional=False
@@ -387,7 +388,25 @@ object CondFeatureStruct3
member foo: int optional=False
feature feature1
if ['defined(TEST_IF_COND_1)', 'defined(TEST_IF_COND_2)']
-object q_obj_test-features-arg
+enum FeatureEnum1
+ member eins
+ member zwei
+ member drei
+ feature feature1
+object q_obj_FeatureUnion1-base
+ member tag: FeatureEnum1 optional=False
+object FeatureUnion1
+ base q_obj_FeatureUnion1-base
+ tag tag
+ case eins: FeatureStruct1
+ case zwei: q_empty
+ case drei: q_empty
+ feature feature1
+alternate FeatureAlternate1
+ tag type
+ case eins: FeatureStruct1
+ feature feature1
+object q_obj_test-features0-arg
member fs0: FeatureStruct0 optional=False
member fs1: FeatureStruct1 optional=False
member fs2: FeatureStruct2 optional=False
@@ -396,13 +415,11 @@ object q_obj_test-features-arg
member cfs1: CondFeatureStruct1 optional=False
member cfs2: CondFeatureStruct2 optional=False
member cfs3: CondFeatureStruct3 optional=False
-command test-features q_obj_test-features-arg -> None
- gen=True success_response=True boxed=False oob=False preconfig=False
-command test-command-features0 None -> None
+command test-features0 q_obj_test-features0-arg -> None
gen=True success_response=True boxed=False oob=False preconfig=False
command test-command-features1 None -> None
gen=True success_response=True boxed=False oob=False preconfig=False
- feature feature1
+ feature deprecated
command test-command-features3 None -> None
gen=True success_response=True boxed=False oob=False preconfig=False
feature feature1
@@ -421,6 +438,9 @@ command test-command-cond-features3 None -> None
gen=True success_response=True boxed=False oob=False preconfig=False
feature feature1
if ['defined(TEST_IF_COND_1)', 'defined(TEST_IF_COND_2)']
+event TEST-EVENT-FEATURES1 None
+ boxed=False
+ feature deprecated
module include/sub-module.json
include sub-sub-module.json
object SecondArrayRef
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index bee18ee344..f396b471eb 100755
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -30,7 +30,7 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
def visit_include(self, name, info):
print('include %s' % name)
- def visit_enum_type(self, name, info, ifcond, members, prefix):
+ def visit_enum_type(self, name, info, ifcond, features, members, prefix):
print('enum %s' % name)
if prefix:
print(' prefix %s' % prefix)
@@ -38,6 +38,7 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
print(' member %s' % m.name)
self._print_if(m.ifcond, indent=8)
self._print_if(ifcond)
+ self._print_features(features)
def visit_array_type(self, name, info, ifcond, element_type):
if not info:
@@ -45,8 +46,8 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
print('array %s %s' % (name, element_type.name))
self._print_if(ifcond)
- def visit_object_type(self, name, info, ifcond, base, members, variants,
- features):
+ def visit_object_type(self, name, info, ifcond, features,
+ base, members, variants):
print('object %s' % name)
if base:
print(' base %s' % base.name)
@@ -54,18 +55,20 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
print(' member %s: %s optional=%s'
% (m.name, m.type.name, m.optional))
self._print_if(m.ifcond, 8)
+ self._print_features(m.features, indent=8)
self._print_variants(variants)
self._print_if(ifcond)
self._print_features(features)
- def visit_alternate_type(self, name, info, ifcond, variants):
+ def visit_alternate_type(self, name, info, ifcond, features, variants):
print('alternate %s' % name)
self._print_variants(variants)
self._print_if(ifcond)
+ self._print_features(features)
- def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
- success_response, boxed, allow_oob, allow_preconfig,
- features):
+ def visit_command(self, name, info, ifcond, features,
+ arg_type, ret_type, gen, success_response, boxed,
+ allow_oob, allow_preconfig):
print('command %s %s -> %s'
% (name, arg_type and arg_type.name,
ret_type and ret_type.name))
@@ -74,10 +77,11 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
self._print_if(ifcond)
self._print_features(features)
- def visit_event(self, name, info, ifcond, arg_type, boxed):
+ def visit_event(self, name, info, ifcond, features, arg_type, boxed):
print('event %s %s' % (name, arg_type and arg_type.name))
print(' boxed=%s' % boxed)
self._print_if(ifcond)
+ self._print_features(features)
@staticmethod
def _print_variants(variants):
@@ -93,11 +97,11 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
print('%sif %s' % (' ' * indent, ifcond))
@classmethod
- def _print_features(cls, features):
+ def _print_features(cls, features, indent=4):
if features:
for f in features:
- print(' feature %s' % f.name)
- cls._print_if(f.ifcond, 8)
+ print('%sfeature %s' % (' ' * indent, f.name))
+ cls._print_if(f.ifcond, indent + 4)
def test_frontend(fname):
diff --git a/tests/qtest/fuzz/qos_fuzz.c b/tests/qtest/fuzz/qos_fuzz.c
index 1a99277d60..af28c92866 100644
--- a/tests/qtest/fuzz/qos_fuzz.c
+++ b/tests/qtest/fuzz/qos_fuzz.c
@@ -55,10 +55,8 @@ static void qos_set_machines_devices_available(void)
QObject *response;
QDict *args = qdict_new();
QList *lst;
- Error *err = NULL;
- qmp_marshal_query_machines(NULL, &response, &err);
- assert(!err);
+ qmp_marshal_query_machines(NULL, &response, &error_abort);
lst = qobject_to(QList, response);
apply_to_qlist(lst, true);
@@ -70,8 +68,7 @@ static void qos_set_machines_devices_available(void)
qdict_put_bool(args, "abstract", true);
qdict_put_obj(req, "arguments", (QObject *) args);
- qmp_marshal_qom_list_types(args, &response, &err);
- assert(!err);
+ qmp_marshal_qom_list_types(args, &response, &error_abort);
lst = qobject_to(QList, response);
apply_to_qlist(lst, false);
qobject_unref(response);
diff --git a/tests/qtest/hd-geo-test.c b/tests/qtest/hd-geo-test.c
index a249800544..48e8e02d6e 100644
--- a/tests/qtest/hd-geo-test.c
+++ b/tests/qtest/hd-geo-test.c
@@ -421,7 +421,7 @@ static char *create_qcow2_with_mbr(MBRpartitions mbr, uint64_t sectors)
char *raw_path = strdup(template);
char *qcow2_path = strdup(template);
char cmd[100 + 2 * PATH_MAX];
- uint8_t buf[512];
+ uint8_t buf[512] = {};
int i, ret, fd, offset;
uint64_t qcow2_size = sectors * 512;
uint8_t status, parttype, head, sector, cyl;
@@ -457,8 +457,8 @@ static char *create_qcow2_with_mbr(MBRpartitions mbr, uint64_t sectors)
buf[offset + 0x6] = sector;
buf[offset + 0x7] = cyl;
- (*(uint32_t *)&buf[offset + 0x8]) = cpu_to_le32(mbr[i].start_sect);
- (*(uint32_t *)&buf[offset + 0xc]) = cpu_to_le32(mbr[i].nr_sects);
+ stl_le_p(&buf[offset + 0x8], mbr[i].start_sect);
+ stl_le_p(&buf[offset + 0xc], mbr[i].nr_sects);
offset += 0x10;
}
diff --git a/tests/qtest/libqos/libqos-spapr.h b/tests/qtest/libqos/libqos-spapr.h
index d9c4c22343..49bd72d20b 100644
--- a/tests/qtest/libqos/libqos-spapr.h
+++ b/tests/qtest/libqos/libqos-spapr.h
@@ -12,7 +12,6 @@ void qtest_spapr_shutdown(QOSState *qs);
"cap-cfpc=broken," \
"cap-sbbc=broken," \
"cap-ibs=broken," \
- "cap-ccf-assist=off," \
- "cap-fwnmi-mce=off"
+ "cap-ccf-assist=off,"
#endif
diff --git a/tests/requirements.txt b/tests/requirements.txt
index f4f1736a08..f9c84b4ba1 100644
--- a/tests/requirements.txt
+++ b/tests/requirements.txt
@@ -2,3 +2,4 @@
# in the tests/venv Python virtual environment. For more info,
# refer to: https://pip.pypa.io/en/stable/user_guide/#id1
avocado-framework==76.0
+pycdlib==1.9.0
diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
index 8ed477d0d5..d99b2a9ece 100644
--- a/tests/tcg/aarch64/Makefile.target
+++ b/tests/tcg/aarch64/Makefile.target
@@ -42,4 +42,36 @@ run-semiconsole: semiconsole
run-plugin-semiconsole-with-%:
$(call skip-test, $<, "MANUAL ONLY")
+ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_SVE),)
+# System Registers Tests
+AARCH64_TESTS += sysregs
+sysregs: CFLAGS+=-march=armv8.1-a+sve
+
+# SVE ioctl test
+AARCH64_TESTS += sve-ioctls
+sve-ioctls: CFLAGS+=-march=armv8.1-a+sve
+
+ifneq ($(HAVE_GDB_BIN),)
+GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py
+
+AARCH64_TESTS += gdbstub-sysregs gdbstub-sve-ioctls
+
+.PHONY: gdbstub-sysregs gdbstub-sve-ioctls
+run-gdbstub-sysregs: sysregs
+ $(call run-test, $@, $(GDB_SCRIPT) \
+ --gdb $(HAVE_GDB_BIN) \
+ --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
+ --bin $< --test $(AARCH64_SRC)/gdbstub/test-sve.py, \
+ "basic gdbstub SVE support")
+
+run-gdbstub-sve-ioctls: sve-ioctls
+ $(call run-test, $@, $(GDB_SCRIPT) \
+ --gdb $(HAVE_GDB_BIN) \
+ --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
+ --bin $< --test $(AARCH64_SRC)/gdbstub/test-sve-ioctl.py, \
+ "basic gdbstub SVE ZLEN support")
+endif
+
+endif
+
TESTS += $(AARCH64_TESTS)
diff --git a/tests/tcg/aarch64/gdbstub/test-sve-ioctl.py b/tests/tcg/aarch64/gdbstub/test-sve-ioctl.py
new file mode 100644
index 0000000000..984fbeb277
--- /dev/null
+++ b/tests/tcg/aarch64/gdbstub/test-sve-ioctl.py
@@ -0,0 +1,85 @@
+from __future__ import print_function
+#
+# Test the SVE ZReg reports the right amount of data. It uses the
+# sve-ioctl test and examines the register data each time the
+# __sve_ld_done breakpoint is hit.
+#
+# This is launched via tests/guest-debug/run-test.py
+#
+
+import gdb
+import sys
+
+initial_vlen = 0
+failcount = 0
+
+def report(cond, msg):
+ "Report success/fail of test"
+ if cond:
+ print ("PASS: %s" % (msg))
+ else:
+ print ("FAIL: %s" % (msg))
+ global failcount
+ failcount += 1
+
+class TestBreakpoint(gdb.Breakpoint):
+ def __init__(self, sym_name="__sve_ld_done"):
+ super(TestBreakpoint, self).__init__(sym_name)
+ # self.sym, ok = gdb.lookup_symbol(sym_name)
+
+ def stop(self):
+ val_i = gdb.parse_and_eval('i')
+ global initial_vlen
+ try:
+ for i in range(0, int(val_i)):
+ val_z = gdb.parse_and_eval("$z0.b.u[%d]" % i)
+ report(int(val_z) == i, "z0.b.u[%d] == %d" % (i, i))
+ for i in range(i + 1, initial_vlen):
+ val_z = gdb.parse_and_eval("$z0.b.u[%d]" % i)
+ report(int(val_z) == 0, "z0.b.u[%d] == 0" % (i))
+ except gdb.error:
+ report(False, "checking zregs (out of range)")
+
+
+def run_test():
+ "Run through the tests one by one"
+
+ print ("Setup breakpoint")
+ bp = TestBreakpoint()
+
+ global initial_vlen
+ vg = gdb.parse_and_eval("$vg")
+ initial_vlen = int(vg) * 8
+
+ gdb.execute("c")
+
+#
+# This runs as the script it sourced (via -x, via run-test.py)
+#
+try:
+ inferior = gdb.selected_inferior()
+ if inferior.was_attached == False:
+ print("SKIPPING (failed to attach)", file=sys.stderr)
+ exit(0)
+ arch = inferior.architecture()
+ report(arch.name() == "aarch64", "connected to aarch64")
+except (gdb.error, AttributeError):
+ print("SKIPPING (not connected)", file=sys.stderr)
+ exit(0)
+
+try:
+ # These are not very useful in scripts
+ gdb.execute("set pagination off")
+ gdb.execute("set confirm off")
+
+ # Run the actual tests
+ run_test()
+except:
+ print ("GDB Exception: %s" % (sys.exc_info()[0]))
+ failcount += 1
+ import code
+ code.InteractiveConsole(locals=globals()).interact()
+ raise
+
+print("All tests complete: %d failures" % failcount)
+exit(failcount)
diff --git a/tests/tcg/aarch64/gdbstub/test-sve.py b/tests/tcg/aarch64/gdbstub/test-sve.py
new file mode 100644
index 0000000000..dbe7f2aa93
--- /dev/null
+++ b/tests/tcg/aarch64/gdbstub/test-sve.py
@@ -0,0 +1,84 @@
+from __future__ import print_function
+#
+# Test the SVE registers are visable and changeable via gdbstub
+#
+# This is launched via tests/guest-debug/run-test.py
+#
+
+import gdb
+import sys
+
+MAGIC = 0xDEADBEEF
+
+failcount = 0
+
+def report(cond, msg):
+ "Report success/fail of test"
+ if cond:
+ print ("PASS: %s" % (msg))
+ else:
+ print ("FAIL: %s" % (msg))
+ global failcount
+ failcount += 1
+
+def run_test():
+ "Run through the tests one by one"
+
+ gdb.execute("info registers")
+ report(True, "info registers")
+
+ gdb.execute("info registers vector")
+ report(True, "info registers vector")
+
+ # Now all the zregs
+ frame = gdb.selected_frame()
+ for i in range(0, 32):
+ rname = "z%d" % (i)
+ zreg = frame.read_register(rname)
+ report(True, "Reading %s" % rname)
+ for j in range(0, 4):
+ cmd = "set $%s.q.u[%d] = 0x%x" % (rname, j, MAGIC)
+ gdb.execute(cmd)
+ report(True, "%s" % cmd)
+ for j in range(0, 4):
+ reg = "$%s.q.u[%d]" % (rname, j)
+ v = gdb.parse_and_eval(reg)
+ report(str(v.type) == "uint128_t", "size of %s" % (reg))
+ for j in range(0, 8):
+ cmd = "set $%s.d.u[%d] = 0x%x" % (rname, j, MAGIC)
+ gdb.execute(cmd)
+ report(True, "%s" % cmd)
+ for j in range(0, 8):
+ reg = "$%s.d.u[%d]" % (rname, j)
+ v = gdb.parse_and_eval(reg)
+ report(str(v.type) == "uint64_t", "size of %s" % (reg))
+ report(int(v) == MAGIC, "%s is 0x%x" % (reg, MAGIC))
+
+#
+# This runs as the script it sourced (via -x, via run-test.py)
+#
+try:
+ inferior = gdb.selected_inferior()
+ if inferior.was_attached == False:
+ print("SKIPPING (failed to attach)", file=sys.stderr)
+ exit(0)
+ arch = inferior.architecture()
+ report(arch.name() == "aarch64", "connected to aarch64")
+except (gdb.error, AttributeError):
+ print("SKIPPING (not connected)", file=sys.stderr)
+ exit(0)
+
+try:
+ # These are not very useful in scripts
+ gdb.execute("set pagination off")
+ gdb.execute("set confirm off")
+
+ # Run the actual tests
+ run_test()
+except:
+ print ("GDB Exception: %s" % (sys.exc_info()[0]))
+ failcount += 1
+
+print("All tests complete: %d failures" % failcount)
+
+exit(failcount)
diff --git a/tests/tcg/aarch64/sve-ioctls.c b/tests/tcg/aarch64/sve-ioctls.c
new file mode 100644
index 0000000000..9544dffa0e
--- /dev/null
+++ b/tests/tcg/aarch64/sve-ioctls.c
@@ -0,0 +1,70 @@
+/*
+ * SVE ioctls tests
+ *
+ * Test the SVE width setting ioctls work and provide a base for
+ * testing the gdbstub.
+ *
+ * Copyright (c) 2019 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <sys/prctl.h>
+#include <asm/hwcap.h>
+#include <stdio.h>
+#include <sys/auxv.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#ifndef HWCAP_CPUID
+#define HWCAP_CPUID (1 << 11)
+#endif
+
+#define SVE_MAX_QUADS (2048 / 128)
+#define BYTES_PER_QUAD (128 / 8)
+
+#define get_cpu_reg(id) ({ \
+ unsigned long __val; \
+ asm("mrs %0, "#id : "=r" (__val)); \
+ __val; \
+ })
+
+static int do_sve_ioctl_test(void)
+{
+ int i, res, init_vq;
+
+ res = prctl(PR_SVE_GET_VL, 0, 0, 0, 0);
+ if (res < 0) {
+ printf("FAILED to PR_SVE_GET_VL (%d)", res);
+ return -1;
+ }
+ init_vq = res & PR_SVE_VL_LEN_MASK;
+
+ for (i = init_vq; i > 15; i /= 2) {
+ printf("Checking PR_SVE_SET_VL=%d\n", i);
+ res = prctl(PR_SVE_SET_VL, i, 0, 0, 0, 0);
+ if (res < 0) {
+ printf("FAILED to PR_SVE_SET_VL (%d)", res);
+ return -1;
+ }
+ asm("index z0.b, #0, #1\n"
+ ".global __sve_ld_done\n"
+ "__sve_ld_done:\n"
+ "mov z0.b, #0\n"
+ : /* no outputs kept */
+ : /* no inputs */
+ : "memory", "z0");
+ }
+ printf("PASS\n");
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ /* we also need to probe for the ioctl support */
+ if (getauxval(AT_HWCAP) & HWCAP_SVE) {
+ return do_sve_ioctl_test();
+ } else {
+ printf("SKIP: no HWCAP_SVE on this system\n");
+ return 0;
+ }
+}
diff --git a/tests/tcg/aarch64/sysregs.c b/tests/tcg/aarch64/sysregs.c
new file mode 100644
index 0000000000..40cf8d2877
--- /dev/null
+++ b/tests/tcg/aarch64/sysregs.c
@@ -0,0 +1,172 @@
+/*
+ * Check emulated system register access for linux-user mode.
+ *
+ * See: https://www.kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt
+ *
+ * Copyright (c) 2019 Linaro
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <asm/hwcap.h>
+#include <stdio.h>
+#include <sys/auxv.h>
+#include <signal.h>
+#include <string.h>
+#include <stdbool.h>
+
+#ifndef HWCAP_CPUID
+#define HWCAP_CPUID (1 << 11)
+#endif
+
+int failed_bit_count;
+
+/* Read and print system register `id' value */
+#define get_cpu_reg(id) ({ \
+ unsigned long __val = 0xdeadbeef; \
+ asm("mrs %0, "#id : "=r" (__val)); \
+ printf("%-20s: 0x%016lx\n", #id, __val); \
+ __val; \
+ })
+
+/* As above but also check no bits outside of `mask' are set*/
+#define get_cpu_reg_check_mask(id, mask) ({ \
+ unsigned long __cval = get_cpu_reg(id); \
+ unsigned long __extra = __cval & ~mask; \
+ if (__extra) { \
+ printf("%-20s: 0x%016lx\n", " !!extra bits!!", __extra); \
+ failed_bit_count++; \
+ } \
+})
+
+/* As above but check RAZ */
+#define get_cpu_reg_check_zero(id) ({ \
+ unsigned long __val = 0xdeadbeef; \
+ asm("mrs %0, "#id : "=r" (__val)); \
+ if (__val) { \
+ printf("%-20s: 0x%016lx (not RAZ!)\n", #id, __val); \
+ failed_bit_count++; \
+ } \
+})
+
+/* Chunk up mask into 63:48, 47:32, 31:16, 15:0 to ease counting */
+#define _m(a, b, c, d) (0x ## a ## b ## c ## d ##ULL)
+
+bool should_fail;
+int should_fail_count;
+int should_not_fail_count;
+uintptr_t failed_pc[10];
+
+void sigill_handler(int signo, siginfo_t *si, void *data)
+{
+ ucontext_t *uc = (ucontext_t *)data;
+
+ if (should_fail) {
+ should_fail_count++;
+ } else {
+ uintptr_t pc = (uintptr_t) uc->uc_mcontext.pc;
+ failed_pc[should_not_fail_count++] = pc;
+ }
+ uc->uc_mcontext.pc += 4;
+}
+
+int main(void)
+{
+ struct sigaction sa;
+
+ /* Hook in a SIGILL handler */
+ memset(&sa, 0, sizeof(struct sigaction));
+ sa.sa_flags = SA_SIGINFO;
+ sa.sa_sigaction = &sigill_handler;
+ sigemptyset(&sa.sa_mask);
+
+ if (sigaction(SIGILL, &sa, 0) != 0) {
+ perror("sigaction");
+ return 1;
+ }
+
+ /* Counter values have been exposed since Linux 4.12 */
+ printf("Checking Counter registers\n");
+
+ get_cpu_reg(ctr_el0);
+ get_cpu_reg(cntvct_el0);
+ get_cpu_reg(cntfrq_el0);
+
+ /* HWCAP_CPUID indicates we can read feature registers, since Linux 4.11 */
+ if (!(getauxval(AT_HWCAP) & HWCAP_CPUID)) {
+ printf("CPUID registers unavailable\n");
+ return 1;
+ } else {
+ printf("Checking CPUID registers\n");
+ }
+
+ /*
+ * Some registers only expose some bits to user-space. Anything
+ * that is IMPDEF is exported as 0 to user-space. The _mask checks
+ * assert no extra bits are set.
+ *
+ * This check is *not* comprehensive as some fields are set to
+ * minimum valid fields - for the purposes of this check allowed
+ * to have non-zero values.
+ */
+ get_cpu_reg_check_mask(id_aa64isar0_el1, _m(00ff,ffff,f0ff,fff0));
+ get_cpu_reg_check_mask(id_aa64isar1_el1, _m(0000,00f0,ffff,ffff));
+ /* TGran4 & TGran64 as pegged to -1 */
+ get_cpu_reg_check_mask(id_aa64mmfr0_el1, _m(0000,0000,ff00,0000));
+ get_cpu_reg_check_zero(id_aa64mmfr1_el1);
+ /* EL1/EL0 reported as AA64 only */
+ get_cpu_reg_check_mask(id_aa64pfr0_el1, _m(000f,000f,00ff,0011));
+ get_cpu_reg_check_mask(id_aa64pfr1_el1, _m(0000,0000,0000,00f0));
+ /* all hidden, DebugVer fixed to 0x6 (ARMv8 debug architecture) */
+ get_cpu_reg_check_mask(id_aa64dfr0_el1, _m(0000,0000,0000,0006));
+ get_cpu_reg_check_zero(id_aa64dfr1_el1);
+ get_cpu_reg_check_zero(id_aa64zfr0_el1);
+
+ get_cpu_reg_check_zero(id_aa64afr0_el1);
+ get_cpu_reg_check_zero(id_aa64afr1_el1);
+
+ get_cpu_reg_check_mask(midr_el1, _m(0000,0000,ffff,ffff));
+ /* mpidr sets bit 31, everything else hidden */
+ get_cpu_reg_check_mask(mpidr_el1, _m(0000,0000,8000,0000));
+ /* REVIDR is all IMPDEF so should be all zeros to user-space */
+ get_cpu_reg_check_zero(revidr_el1);
+
+ /*
+ * There are a block of more registers that are RAZ in the rest of
+ * the Op0=3, Op1=0, CRn=0, CRm=0,4,5,6,7 space. However for
+ * brevity we don't check stuff that is currently un-allocated
+ * here. Feel free to add them ;-)
+ */
+
+ printf("Remaining registers should fail\n");
+ should_fail = true;
+
+ /* Unexposed register access causes SIGILL */
+ get_cpu_reg(id_mmfr0_el1);
+ get_cpu_reg(id_mmfr1_el1);
+ get_cpu_reg(id_mmfr2_el1);
+ get_cpu_reg(id_mmfr3_el1);
+
+ get_cpu_reg(mvfr0_el1);
+ get_cpu_reg(mvfr1_el1);
+
+ if (should_not_fail_count > 0) {
+ int i;
+ for (i = 0; i < should_not_fail_count; i++) {
+ uintptr_t pc = failed_pc[i];
+ uint32_t insn = *(uint32_t *) pc;
+ printf("insn %#x @ %#lx unexpected FAIL\n", insn, pc);
+ }
+ return 1;
+ }
+
+ if (failed_bit_count > 0) {
+ printf("Extra information leaked to user-space!\n");
+ return 1;
+ }
+
+ return should_fail_count == 6 ? 0 : 1;
+}
diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c
index 79507d9e54..d12ff47e26 100644
--- a/tests/test-qmp-cmds.c
+++ b/tests/test-qmp-cmds.c
@@ -1,5 +1,6 @@
#include "qemu/osdep.h"
#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qjson.h"
#include "qapi/qmp/qnum.h"
#include "qapi/qmp/qstring.h"
#include "qapi/error.h"
@@ -44,7 +45,7 @@ void qmp_user_def_cmd1(UserDefOne * ud1, Error **errp)
{
}
-void qmp_test_features(FeatureStruct0 *fs0, FeatureStruct1 *fs1,
+void qmp_test_features0(FeatureStruct0 *fs0, FeatureStruct1 *fs1,
FeatureStruct2 *fs2, FeatureStruct3 *fs3,
FeatureStruct4 *fs4, CondFeatureStruct1 *cfs1,
CondFeatureStruct2 *cfs2, CondFeatureStruct3 *cfs3,
@@ -52,10 +53,6 @@ void qmp_test_features(FeatureStruct0 *fs0, FeatureStruct1 *fs1,
{
}
-void qmp_test_command_features0(Error **errp)
-{
-}
-
void qmp_test_command_features1(Error **errp)
{
}
@@ -145,66 +142,87 @@ __org_qemu_x_Union1 *qmp___org_qemu_x_command(__org_qemu_x_EnumList *a,
}
-/* test commands with no input and no return value */
-static void test_dispatch_cmd(void)
+static QObject *do_qmp_dispatch(bool allow_oob, const char *template, ...)
{
- QDict *req = qdict_new();
- QDict *resp;
+ va_list ap;
+ QDict *req, *resp;
+ QObject *ret;
- qdict_put_str(req, "execute", "user_def_cmd");
+ va_start(ap, template);
+ req = qdict_from_vjsonf_nofail(template, ap);
+ va_end(ap);
- resp = qmp_dispatch(&qmp_commands, QOBJECT(req), false);
- assert(resp != NULL);
- assert(!qdict_haskey(resp, "error"));
+ resp = qmp_dispatch(&qmp_commands, QOBJECT(req), allow_oob);
+ g_assert(resp);
+ ret = qdict_get(resp, "return");
+ g_assert(ret);
+ g_assert(qdict_size(resp) == 1);
+ qobject_ref(ret);
qobject_unref(resp);
qobject_unref(req);
+ return ret;
}
-static void test_dispatch_cmd_oob(void)
+static void do_qmp_dispatch_error(bool allow_oob, ErrorClass cls,
+ const char *template, ...)
{
- QDict *req = qdict_new();
- QDict *resp;
-
- qdict_put_str(req, "exec-oob", "test-flags-command");
-
- resp = qmp_dispatch(&qmp_commands, QOBJECT(req), true);
- assert(resp != NULL);
- assert(!qdict_haskey(resp, "error"));
+ va_list ap;
+ QDict *req, *resp;
+ QDict *error;
+
+ va_start(ap, template);
+ req = qdict_from_vjsonf_nofail(template, ap);
+ va_end(ap);
+
+ resp = qmp_dispatch(&qmp_commands, QOBJECT(req), allow_oob);
+ g_assert(resp);
+ error = qdict_get_qdict(resp, "error");
+ g_assert(error);
+ g_assert_cmpstr(qdict_get_try_str(error, "class"),
+ ==, QapiErrorClass_str(cls));
+ g_assert(qdict_get_try_str(error, "desc"));
+ g_assert(qdict_size(error) == 2);
+ g_assert(qdict_size(resp) == 1);
qobject_unref(resp);
qobject_unref(req);
}
-/* test commands that return an error due to invalid parameters */
-static void test_dispatch_cmd_failure(void)
+/* test commands with no input and no return value */
+static void test_dispatch_cmd(void)
{
- QDict *req = qdict_new();
- QDict *args = qdict_new();
- QDict *resp;
-
- qdict_put_str(req, "execute", "user_def_cmd2");
-
- resp = qmp_dispatch(&qmp_commands, QOBJECT(req), false);
- assert(resp != NULL);
- assert(qdict_haskey(resp, "error"));
-
- qobject_unref(resp);
- qobject_unref(req);
+ QDict *ret;
- /* check that with extra arguments it throws an error */
- req = qdict_new();
- qdict_put_int(args, "a", 66);
- qdict_put(req, "arguments", args);
+ ret = qobject_to(QDict,
+ do_qmp_dispatch(false,
+ "{ 'execute': 'user_def_cmd' }"));
+ assert(ret && qdict_size(ret) == 0);
+ qobject_unref(ret);
+}
- qdict_put_str(req, "execute", "user_def_cmd");
+static void test_dispatch_cmd_oob(void)
+{
+ QDict *ret;
- resp = qmp_dispatch(&qmp_commands, QOBJECT(req), false);
- assert(resp != NULL);
- assert(qdict_haskey(resp, "error"));
+ ret = qobject_to(QDict,
+ do_qmp_dispatch(true,
+ "{ 'exec-oob': 'test-flags-command' }"));
+ assert(ret && qdict_size(ret) == 0);
+ qobject_unref(ret);
+}
- qobject_unref(resp);
- qobject_unref(req);
+/* test commands that return an error due to invalid parameters */
+static void test_dispatch_cmd_failure(void)
+{
+ /* missing arguments */
+ do_qmp_dispatch_error(false, ERROR_CLASS_GENERIC_ERROR,
+ "{ 'execute': 'user_def_cmd2' }");
+
+ /* extra arguments */
+ do_qmp_dispatch_error(false, ERROR_CLASS_GENERIC_ERROR,
+ "{ 'execute': 'user_def_cmd',"
+ " 'arguments': { 'a': 66 } }");
}
static void test_dispatch_cmd_success_response(void)
@@ -218,43 +236,18 @@ static void test_dispatch_cmd_success_response(void)
qobject_unref(req);
}
-static QObject *test_qmp_dispatch(QDict *req)
-{
- QDict *resp;
- QObject *ret;
-
- resp = qmp_dispatch(&qmp_commands, QOBJECT(req), false);
- assert(resp && !qdict_haskey(resp, "error"));
- ret = qdict_get(resp, "return");
- assert(ret);
- qobject_ref(ret);
- qobject_unref(resp);
- return ret;
-}
-
/* test commands that involve both input parameters and return values */
static void test_dispatch_cmd_io(void)
{
- QDict *req = qdict_new();
- QDict *args = qdict_new();
- QDict *args3 = qdict_new();
- QDict *ud1a = qdict_new();
- QDict *ud1b = qdict_new();
QDict *ret, *ret_dict, *ret_dict_dict, *ret_dict_dict_userdef;
QDict *ret_dict_dict2, *ret_dict_dict2_userdef;
QNum *ret3;
int64_t val;
- qdict_put_int(ud1a, "integer", 42);
- qdict_put_str(ud1a, "string", "hello");
- qdict_put_int(ud1b, "integer", 422);
- qdict_put_str(ud1b, "string", "hello2");
- qdict_put(args, "ud1a", ud1a);
- qdict_put(args, "ud1b", ud1b);
- qdict_put(req, "arguments", args);
- qdict_put_str(req, "execute", "user_def_cmd2");
-
- ret = qobject_to(QDict, test_qmp_dispatch(req));
+ ret = qobject_to(QDict, do_qmp_dispatch(false,
+ "{ 'execute': 'user_def_cmd2', 'arguments': {"
+ " 'ud1a': { 'integer': 42, 'string': 'hello' },"
+ " 'ud1b': { 'integer': 422, 'string': 'hello2' } } }"));
assert(!strcmp(qdict_get_str(ret, "string0"), "blah1"));
ret_dict = qdict_get_qdict(ret, "dict1");
@@ -271,16 +264,11 @@ static void test_dispatch_cmd_io(void)
assert(!strcmp(qdict_get_str(ret_dict_dict2, "string"), "blah4"));
qobject_unref(ret);
- qdict_put_int(args3, "a", 66);
- qdict_put(req, "arguments", args3);
- qdict_put_str(req, "execute", "guest-get-time");
-
- ret3 = qobject_to(QNum, test_qmp_dispatch(req));
+ ret3 = qobject_to(QNum, do_qmp_dispatch(false,
+ "{ 'execute': 'guest-get-time', 'arguments': { 'a': 66 } }"));
g_assert(qnum_get_try_int(ret3, &val));
g_assert_cmpint(val, ==, 66);
qobject_unref(ret3);
-
- qobject_unref(req);
}
/* test generated dealloc functions for generated types */
diff --git a/tests/test-qmp-event.c b/tests/test-qmp-event.c
index eee7e08ab6..7dd0053190 100644
--- a/tests/test-qmp-event.c
+++ b/tests/test-qmp-event.c
@@ -17,6 +17,7 @@
#include "qapi/error.h"
#include "qapi/qmp/qbool.h"
#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qjson.h"
#include "qapi/qmp/qnum.h"
#include "qapi/qmp/qstring.h"
#include "qapi/qmp-event.h"
@@ -25,75 +26,12 @@
typedef struct TestEventData {
QDict *expect;
+ bool emitted;
} TestEventData;
-typedef struct QDictCmpData {
- QDict *expect;
- bool result;
-} QDictCmpData;
-
TestEventData *test_event_data;
static GMutex test_event_lock;
-/* Only compares bool, int, string */
-static
-void qdict_cmp_do_simple(const char *key, QObject *obj1, void *opaque)
-
-{
- QObject *obj2;
- QDictCmpData d_new, *d = opaque;
- int64_t val1, val2;
-
- if (!d->result) {
- return;
- }
-
- obj2 = qdict_get(d->expect, key);
- if (!obj2) {
- d->result = false;
- return;
- }
-
- if (qobject_type(obj1) != qobject_type(obj2)) {
- d->result = false;
- return;
- }
-
- switch (qobject_type(obj1)) {
- case QTYPE_QBOOL:
- d->result = (qbool_get_bool(qobject_to(QBool, obj1)) ==
- qbool_get_bool(qobject_to(QBool, obj2)));
- return;
- case QTYPE_QNUM:
- g_assert(qnum_get_try_int(qobject_to(QNum, obj1), &val1));
- g_assert(qnum_get_try_int(qobject_to(QNum, obj2), &val2));
- d->result = val1 == val2;
- return;
- case QTYPE_QSTRING:
- d->result = g_strcmp0(qstring_get_str(qobject_to(QString, obj1)),
- qstring_get_str(qobject_to(QString, obj2))) == 0;
- return;
- case QTYPE_QDICT:
- d_new.expect = qobject_to(QDict, obj2);
- d_new.result = true;
- qdict_iter(qobject_to(QDict, obj1), qdict_cmp_do_simple, &d_new);
- d->result = d_new.result;
- return;
- default:
- abort();
- }
-}
-
-static bool qdict_cmp_simple(QDict *a, QDict *b)
-{
- QDictCmpData d;
-
- d.expect = b;
- d.result = true;
- qdict_iter(a, qdict_cmp_do_simple, &d);
- return d.result;
-}
-
void test_qapi_event_emit(test_QAPIEvent event, QDict *d)
{
QDict *t;
@@ -114,8 +52,8 @@ void test_qapi_event_emit(test_QAPIEvent event, QDict *d)
qdict_del(d, "timestamp");
- g_assert(qdict_cmp_simple(d, test_event_data->expect));
-
+ g_assert(qobject_is_equal(QOBJECT(d), QOBJECT(test_event_data->expect)));
+ test_event_data->emitted = true;
}
static void event_prepare(TestEventData *data,
@@ -124,17 +62,13 @@ static void event_prepare(TestEventData *data,
/* Global variable test_event_data was used to pass the expectation, so
test cases can't be executed at same time. */
g_mutex_lock(&test_event_lock);
-
- data->expect = qdict_new();
test_event_data = data;
}
static void event_teardown(TestEventData *data,
const void *unused)
{
- qobject_unref(data->expect);
test_event_data = NULL;
-
g_mutex_unlock(&test_event_lock);
}
@@ -152,90 +86,58 @@ static void event_test_add(const char *testpath,
static void test_event_a(TestEventData *data,
const void *unused)
{
- QDict *d;
- d = data->expect;
- qdict_put_str(d, "event", "EVENT_A");
+ data->expect = qdict_from_jsonf_nofail("{ 'event': 'EVENT_A' }");
qapi_event_send_event_a();
+ g_assert(data->emitted);
+ qobject_unref(data->expect);
}
static void test_event_b(TestEventData *data,
const void *unused)
{
- QDict *d;
- d = data->expect;
- qdict_put_str(d, "event", "EVENT_B");
+ data->expect = qdict_from_jsonf_nofail("{ 'event': 'EVENT_B' }");
qapi_event_send_event_b();
+ g_assert(data->emitted);
+ qobject_unref(data->expect);
}
static void test_event_c(TestEventData *data,
const void *unused)
{
- QDict *d, *d_data, *d_b;
-
- UserDefOne b;
- b.integer = 2;
- b.string = g_strdup("test1");
- b.has_enum1 = false;
-
- d_b = qdict_new();
- qdict_put_int(d_b, "integer", 2);
- qdict_put_str(d_b, "string", "test1");
-
- d_data = qdict_new();
- qdict_put_int(d_data, "a", 1);
- qdict_put(d_data, "b", d_b);
- qdict_put_str(d_data, "c", "test2");
-
- d = data->expect;
- qdict_put_str(d, "event", "EVENT_C");
- qdict_put(d, "data", d_data);
+ UserDefOne b = { .integer = 2, .string = (char *)"test1" };
+ data->expect = qdict_from_jsonf_nofail(
+ "{ 'event': 'EVENT_C', 'data': {"
+ " 'a': 1, 'b': { 'integer': 2, 'string': 'test1' }, 'c': 'test2' } }");
qapi_event_send_event_c(true, 1, true, &b, "test2");
-
- g_free(b.string);
+ g_assert(data->emitted);
+ qobject_unref(data->expect);
}
/* Complex type */
static void test_event_d(TestEventData *data,
const void *unused)
{
- UserDefOne struct1;
- EventStructOne a;
- QDict *d, *d_data, *d_a, *d_struct1;
-
- struct1.integer = 2;
- struct1.string = g_strdup("test1");
- struct1.has_enum1 = true;
- struct1.enum1 = ENUM_ONE_VALUE1;
-
- a.struct1 = &struct1;
- a.string = g_strdup("test2");
- a.has_enum2 = true;
- a.enum2 = ENUM_ONE_VALUE2;
-
- d_struct1 = qdict_new();
- qdict_put_int(d_struct1, "integer", 2);
- qdict_put_str(d_struct1, "string", "test1");
- qdict_put_str(d_struct1, "enum1", "value1");
-
- d_a = qdict_new();
- qdict_put(d_a, "struct1", d_struct1);
- qdict_put_str(d_a, "string", "test2");
- qdict_put_str(d_a, "enum2", "value2");
-
- d_data = qdict_new();
- qdict_put(d_data, "a", d_a);
- qdict_put_str(d_data, "b", "test3");
- qdict_put_str(d_data, "enum3", "value3");
-
- d = data->expect;
- qdict_put_str(d, "event", "EVENT_D");
- qdict_put(d, "data", d_data);
-
+ UserDefOne struct1 = {
+ .integer = 2, .string = (char *)"test1",
+ .has_enum1 = true, .enum1 = ENUM_ONE_VALUE1,
+ };
+ EventStructOne a = {
+ .struct1 = &struct1,
+ .string = (char *)"test2",
+ .has_enum2 = true,
+ .enum2 = ENUM_ONE_VALUE2,
+ };
+
+ data->expect = qdict_from_jsonf_nofail(
+ "{ 'event': 'EVENT_D', 'data': {"
+ " 'a': {"
+ " 'struct1': { 'integer': 2, 'string': 'test1', 'enum1': 'value1' },"
+ " 'string': 'test2', 'enum2': 'value2' },"
+ " 'b': 'test3', 'enum3': 'value3' } }");
qapi_event_send_event_d(&a, "test3", false, NULL, true, ENUM_ONE_VALUE3);
-
- g_free(struct1.string);
- g_free(a.string);
+ g_assert(data->emitted);
+ qobject_unref(data->expect);
}
int main(int argc, char **argv)