aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.shippable.yml19
-rw-r--r--MAINTAINERS13
-rw-r--r--block.c4
-rw-r--r--block/nbd.c2
-rw-r--r--block/nfs.c2
-rw-r--r--block/qapi.c1
-rwxr-xr-xconfigure2
-rw-r--r--default-configs/mips64el-softmmu.mak3
-rw-r--r--fpu/softfloat.c108
-rw-r--r--hmp.c11
-rw-r--r--hw/acpi/cpu.c2
-rw-r--r--hw/core/machine.c31
-rw-r--r--hw/display/cirrus_vga.c8
-rw-r--r--hw/i386/pc.c126
-rw-r--r--hw/mips/Makefile.objs1
-rw-r--r--hw/mips/boston.c577
-rw-r--r--hw/misc/ivshmem.c9
-rw-r--r--hw/net/spapr_llan.c18
-rw-r--r--hw/pci-host/prep.c11
-rw-r--r--hw/pci/pcie_aer.c2
-rw-r--r--hw/ppc/mac_newworld.c15
-rw-r--r--hw/ppc/pnv.c6
-rw-r--r--hw/ppc/ppc405_uc.c6
-rw-r--r--hw/ppc/ppc4xx_pci.c13
-rw-r--r--hw/ppc/spapr.c255
-rw-r--r--hw/ppc/spapr_cpu_core.c137
-rw-r--r--hw/ppc/spapr_ovec.c19
-rw-r--r--hw/ppc/trace-events12
-rw-r--r--hw/usb/bus.c9
-rw-r--r--hw/usb/dev-audio.c4
-rw-r--r--hw/usb/dev-bluetooth.c4
-rw-r--r--hw/usb/dev-hid.c4
-rw-r--r--hw/usb/dev-hub.c4
-rw-r--r--hw/usb/dev-network.c4
-rw-r--r--hw/usb/dev-smartcard-reader.c4
-rw-r--r--hw/usb/dev-uas.c4
-rw-r--r--hw/usb/dev-wacom.c4
-rw-r--r--hw/usb/hcd-ohci.c2
-rw-r--r--hw/usb/hcd-xhci.c29
-rw-r--r--hw/usb/host-libusb.c4
-rw-r--r--hw/usb/redirect.c4
-rw-r--r--hw/vfio/pci-quirks.c65
-rw-r--r--hw/vfio/pci.c37
-rw-r--r--include/fpu/softfloat.h5
-rw-r--r--include/hw/boards.h16
-rw-r--r--include/hw/i386/pc.h1
-rw-r--r--include/hw/ppc/spapr.h1
-rw-r--r--include/hw/ppc/spapr_cpu_core.h6
-rw-r--r--include/hw/usb.h5
-rw-r--r--include/qemu/cutils.h29
-rw-r--r--linux-user/main.c3
-rw-r--r--monitor.c24
-rw-r--r--net/net.c44
-rw-r--r--numa.c4
-rw-r--r--qapi-schema.json21
-rw-r--r--qapi/opts-visitor.c11
-rw-r--r--qapi/qmp-dispatch.c5
-rw-r--r--qemu-img.c62
-rw-r--r--qemu-io-cmds.c16
-rw-r--r--qobject/qdict.c32
-rw-r--r--qtest.c34
-rw-r--r--target/i386/cpu.c9
-rw-r--r--target/ppc/cpu-qom.h5
-rw-r--r--target/ppc/cpu.h20
-rw-r--r--target/ppc/fpu_helper.c312
-rw-r--r--target/ppc/helper.h11
-rw-r--r--target/ppc/internal.h3
-rw-r--r--target/ppc/kvm.c32
-rw-r--r--target/ppc/kvm_ppc.h7
-rw-r--r--target/ppc/mmu-hash64.c44
-rw-r--r--target/ppc/mmu_helper.c4
-rw-r--r--target/ppc/translate.c153
-rw-r--r--target/ppc/translate/vsx-impl.inc.c11
-rw-r--r--target/ppc/translate/vsx-ops.inc.c21
-rw-r--r--target/ppc/translate_init.c27
-rw-r--r--tests/check-qdict.c37
-rw-r--r--tests/check-qjson.c113
-rw-r--r--tests/docker/Makefile.include6
-rwxr-xr-xtests/docker/common.rc2
-rwxr-xr-xtests/docker/docker.py16
-rw-r--r--tests/docker/dockerfiles/debian-arm64-cross.docker15
-rw-r--r--tests/docker/dockerfiles/debian-armhf-cross.docker15
-rw-r--r--tests/docker/dockerfiles/debian.docker25
-rw-r--r--tests/docker/dockerfiles/fedora.docker2
-rw-r--r--tests/libqtest.c4
-rw-r--r--tests/test-cutils.c644
-rw-r--r--tests/test-qemu-opts.c324
-rw-r--r--tests/test-qmp-event.c14
-rw-r--r--tests/test-qobject-output-visitor.c133
-rw-r--r--util/cutils.c247
-rw-r--r--util/log.c4
-rw-r--r--util/qemu-option.c89
-rw-r--r--vl.c2
93 files changed, 2475 insertions, 1790 deletions
diff --git a/.shippable.yml b/.shippable.yml
new file mode 100644
index 0000000000..1a1fd7a91d
--- /dev/null
+++ b/.shippable.yml
@@ -0,0 +1,19 @@
+language: c
+env:
+ matrix:
+ - IMAGE=debian-armhf-cross
+ TARGET_LIST=arm-softmmu,arm-linux-user
+ - IMAGE=debian-arm64-cross
+ TARGET_LIST=aarch64-softmmu,aarch64-linux-user
+build:
+ pre_ci:
+ - make docker-image-${IMAGE}
+ pre_ci_boot:
+ image_name: qemu
+ image_tag: ${IMAGE}
+ pull: false
+ options: "-e HOME=/root"
+ ci:
+ - unset CC
+ - ./configure ${QEMU_CONFIGURE_OPTS} --target-list=${TARGET_LIST}
+ - make -j2
diff --git a/MAINTAINERS b/MAINTAINERS
index 4714df883b..be79f68f46 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1800,9 +1800,14 @@ F: docs/block-replication.txt
Build and test automation
-------------------------
M: Alex Bennée <alex.bennee@linaro.org>
+M: Fam Zheng <famz@redhat.com>
L: qemu-devel@nongnu.org
-S: Supported
+S: Maintained
F: .travis.yml
+F: .shippable.yml
+F: tests/docker/
+W: https://travis-ci.org/qemu/qemu
+W: http://patchew.org/QEMU/
Documentation
-------------
@@ -1811,9 +1816,3 @@ M: Daniel P. Berrange <berrange@redhat.com>
S: Odd Fixes
F: docs/build-system.txt
-Docker testing
---------------
-Docker based testing framework and cases
-M: Fam Zheng <famz@redhat.com>
-S: Maintained
-F: tests/docker/
diff --git a/block.c b/block.c
index 743c349100..3c36af5e76 100644
--- a/block.c
+++ b/block.c
@@ -1169,13 +1169,13 @@ static QDict *parse_json_filename(const char *filename, Error **errp)
return NULL;
}
- if (qobject_type(options_obj) != QTYPE_QDICT) {
+ options = qobject_to_qdict(options_obj);
+ if (!options) {
qobject_decref(options_obj);
error_setg(errp, "Invalid JSON object given");
return NULL;
}
- options = qobject_to_qdict(options_obj);
qdict_flatten(options);
return options;
diff --git a/block/nbd.c b/block/nbd.c
index 35f24be069..a7f9108fe5 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -537,8 +537,6 @@ static void nbd_refresh_filename(BlockDriverState *bs, QDict *options)
visit_type_SocketAddress(ov, NULL, &s->saddr, &error_abort);
visit_complete(ov, &saddr_qdict);
visit_free(ov);
- assert(qobject_type(saddr_qdict) == QTYPE_QDICT);
-
qdict_put_obj(opts, "server", saddr_qdict);
if (s->export) {
diff --git a/block/nfs.c b/block/nfs.c
index 08b43dd189..0cf115e7d6 100644
--- a/block/nfs.c
+++ b/block/nfs.c
@@ -805,8 +805,6 @@ static void nfs_refresh_filename(BlockDriverState *bs, QDict *options)
ov = qobject_output_visitor_new(&server_qdict);
visit_type_NFSServer(ov, NULL, &client->server, &error_abort);
visit_complete(ov, &server_qdict);
- assert(qobject_type(server_qdict) == QTYPE_QDICT);
-
qdict_put_obj(opts, "server", server_qdict);
qdict_put(opts, "path", qstring_from_str(client->path));
diff --git a/block/qapi.c b/block/qapi.c
index ac480aa93c..a40922ea26 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -682,7 +682,6 @@ void bdrv_image_info_specific_dump(fprintf_function func_fprintf, void *f,
visit_type_ImageInfoSpecific(v, NULL, &info_spec, &error_abort);
visit_complete(v, &obj);
- assert(qobject_type(obj) == QTYPE_QDICT);
data = qdict_get(qobject_to_qdict(obj), "data");
dump_qobject(func_fprintf, f, 1, data);
qobject_decref(obj);
diff --git a/configure b/configure
index 8e8f18de1e..4b68861992 100755
--- a/configure
+++ b/configure
@@ -3378,7 +3378,7 @@ fi
fdt_required=no
for target in $target_list; do
case $target in
- aarch64*-softmmu|arm*-softmmu|ppc*-softmmu|microblaze*-softmmu|mips64el-softmmu)
+ aarch64*-softmmu|arm*-softmmu|ppc*-softmmu|microblaze*-softmmu)
fdt_required=yes
;;
esac
diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
index c2ae313f47..485e218cfc 100644
--- a/default-configs/mips64el-softmmu.mak
+++ b/default-configs/mips64el-softmmu.mak
@@ -10,6 +10,3 @@ CONFIG_JAZZ=y
CONFIG_G364FB=y
CONFIG_JAZZ_LED=y
CONFIG_VT82C686=y
-CONFIG_MIPS_BOSTON=y
-CONFIG_FITLOADER=y
-CONFIG_PCI_XILINX=y
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index c295f3183f..485a006aa7 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -623,6 +623,9 @@ static float64 roundAndPackFloat64(flag zSign, int zExp, uint64_t zSig,
case float_round_down:
roundIncrement = zSign ? 0x3ff : 0;
break;
+ case float_round_to_odd:
+ roundIncrement = (zSig & 0x400) ? 0 : 0x3ff;
+ break;
default:
abort();
}
@@ -632,8 +635,10 @@ static float64 roundAndPackFloat64(flag zSign, int zExp, uint64_t zSig,
|| ( ( zExp == 0x7FD )
&& ( (int64_t) ( zSig + roundIncrement ) < 0 ) )
) {
+ bool overflow_to_inf = roundingMode != float_round_to_odd &&
+ roundIncrement != 0;
float_raise(float_flag_overflow | float_flag_inexact, status);
- return packFloat64( zSign, 0x7FF, - ( roundIncrement == 0 ));
+ return packFloat64(zSign, 0x7FF, -(!overflow_to_inf));
}
if ( zExp < 0 ) {
if (status->flush_to_zero) {
@@ -651,6 +656,13 @@ static float64 roundAndPackFloat64(flag zSign, int zExp, uint64_t zSig,
if (isTiny && roundBits) {
float_raise(float_flag_underflow, status);
}
+ if (roundingMode == float_round_to_odd) {
+ /*
+ * For round-to-odd case, the roundIncrement depends on
+ * zSig which just changed.
+ */
+ roundIncrement = (zSig & 0x400) ? 0 : 0x3ff;
+ }
}
}
if (roundBits) {
@@ -1149,6 +1161,9 @@ static float128 roundAndPackFloat128(flag zSign, int32_t zExp,
case float_round_down:
increment = zSign && zSig2;
break;
+ case float_round_to_odd:
+ increment = !(zSig1 & 0x1) && zSig2;
+ break;
default:
abort();
}
@@ -1168,6 +1183,7 @@ static float128 roundAndPackFloat128(flag zSign, int32_t zExp,
if ( ( roundingMode == float_round_to_zero )
|| ( zSign && ( roundingMode == float_round_up ) )
|| ( ! zSign && ( roundingMode == float_round_down ) )
+ || (roundingMode == float_round_to_odd)
) {
return
packFloat128(
@@ -1215,6 +1231,9 @@ static float128 roundAndPackFloat128(flag zSign, int32_t zExp,
case float_round_down:
increment = zSign && zSig2;
break;
+ case float_round_to_odd:
+ increment = !(zSig1 & 0x1) && zSig2;
+ break;
default:
abort();
}
@@ -6109,6 +6128,93 @@ int64_t float128_to_int64_round_to_zero(float128 a, float_status *status)
}
/*----------------------------------------------------------------------------
+| Returns the result of converting the quadruple-precision floating-point value
+| `a' to the 64-bit unsigned integer format. The conversion is
+| performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic---which means in particular that the conversion is rounded
+| according to the current rounding mode. If `a' is a NaN, the largest
+| positive integer is returned. If the conversion overflows, the
+| largest unsigned integer is returned. If 'a' is negative, the value is
+| rounded and zero is returned; negative values that do not round to zero
+| will raise the inexact exception.
+*----------------------------------------------------------------------------*/
+
+uint64_t float128_to_uint64(float128 a, float_status *status)
+{
+ flag aSign;
+ int aExp;
+ int shiftCount;
+ uint64_t aSig0, aSig1;
+
+ aSig0 = extractFloat128Frac0(a);
+ aSig1 = extractFloat128Frac1(a);
+ aExp = extractFloat128Exp(a);
+ aSign = extractFloat128Sign(a);
+ if (aSign && (aExp > 0x3FFE)) {
+ float_raise(float_flag_invalid, status);
+ if (float128_is_any_nan(a)) {
+ return LIT64(0xFFFFFFFFFFFFFFFF);
+ } else {
+ return 0;
+ }
+ }
+ if (aExp) {
+ aSig0 |= LIT64(0x0001000000000000);
+ }
+ shiftCount = 0x402F - aExp;
+ if (shiftCount <= 0) {
+ if (0x403E < aExp) {
+ float_raise(float_flag_invalid, status);
+ return LIT64(0xFFFFFFFFFFFFFFFF);
+ }
+ shortShift128Left(aSig0, aSig1, -shiftCount, &aSig0, &aSig1);
+ } else {
+ shift64ExtraRightJamming(aSig0, aSig1, shiftCount, &aSig0, &aSig1);
+ }
+ return roundAndPackUint64(aSign, aSig0, aSig1, status);
+}
+
+uint64_t float128_to_uint64_round_to_zero(float128 a, float_status *status)
+{
+ uint64_t v;
+ signed char current_rounding_mode = status->float_rounding_mode;
+
+ set_float_rounding_mode(float_round_to_zero, status);
+ v = float128_to_uint64(a, status);
+ set_float_rounding_mode(current_rounding_mode, status);
+
+ return v;
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the quadruple-precision floating-point
+| value `a' to the 32-bit unsigned integer format. The conversion
+| is performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic except that the conversion is always rounded toward zero.
+| If `a' is a NaN, the largest positive integer is returned. Otherwise,
+| if the conversion overflows, the largest unsigned integer is returned.
+| If 'a' is negative, the value is rounded and zero is returned; negative
+| values that do not round to zero will raise the inexact exception.
+*----------------------------------------------------------------------------*/
+
+uint32_t float128_to_uint32_round_to_zero(float128 a, float_status *status)
+{
+ uint64_t v;
+ uint32_t res;
+ int old_exc_flags = get_float_exception_flags(status);
+
+ v = float128_to_uint64_round_to_zero(a, status);
+ if (v > 0xffffffff) {
+ res = 0xffffffff;
+ } else {
+ return v;
+ }
+ set_float_exception_flags(old_exc_flags, status);
+ float_raise(float_flag_invalid, status);
+ return res;
+}
+
+/*----------------------------------------------------------------------------
| Returns the result of converting the quadruple-precision floating-point
| value `a' to the single-precision floating-point format. The conversion
| is performed according to the IEC/IEEE Standard for Binary Floating-Point
diff --git a/hmp.c b/hmp.c
index aba728f0de..83e287e0a4 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1344,12 +1344,11 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
{
const char *param = qdict_get_str(qdict, "parameter");
const char *valuestr = qdict_get_str(qdict, "value");
- int64_t valuebw = 0;
+ uint64_t valuebw = 0;
long valueint = 0;
- char *endp;
Error *err = NULL;
bool use_int_value = false;
- int i;
+ int i, ret;
for (i = 0; i < MIGRATION_PARAMETER__MAX; i++) {
if (strcmp(param, MigrationParameter_lookup[i]) == 0) {
@@ -1385,9 +1384,9 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
break;
case MIGRATION_PARAMETER_MAX_BANDWIDTH:
p.has_max_bandwidth = true;
- valuebw = qemu_strtosz(valuestr, &endp);
- if (valuebw < 0 || (size_t)valuebw != valuebw
- || *endp != '\0') {
+ ret = qemu_strtosz_MiB(valuestr, NULL, &valuebw);
+ if (ret < 0 || valuebw > INT64_MAX
+ || (size_t)valuebw != valuebw) {
error_setg(&err, "Invalid size %s", valuestr);
goto cleanup;
}
diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c
index 6017ca04bf..8c719d3f9d 100644
--- a/hw/acpi/cpu.c
+++ b/hw/acpi/cpu.c
@@ -198,7 +198,7 @@ void cpu_hotplug_hw_init(MemoryRegion *as, Object *owner,
state->dev_count = id_list->len;
state->devs = g_new0(typeof(*state->devs), state->dev_count);
for (i = 0; i < id_list->len; i++) {
- state->devs[i].cpu = id_list->cpus[i].cpu;
+ state->devs[i].cpu = CPU(id_list->cpus[i].cpu);
state->devs[i].arch_id = id_list->cpus[i].arch_id;
}
memory_region_init_io(&state->ctrl_reg, owner, &cpu_hotplug_ops, state,
diff --git a/hw/core/machine.c b/hw/core/machine.c
index b0fd91f6cd..0699750336 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -357,6 +357,37 @@ static void machine_init_notify(Notifier *notifier, void *data)
foreach_dynamic_sysbus_device(error_on_sysbus_device, NULL);
}
+HotpluggableCPUList *machine_query_hotpluggable_cpus(MachineState *machine)
+{
+ int i;
+ Object *cpu;
+ HotpluggableCPUList *head = NULL;
+ const char *cpu_type;
+
+ cpu = machine->possible_cpus->cpus[0].cpu;
+ assert(cpu); /* Boot cpu is always present */
+ cpu_type = object_get_typename(cpu);
+ for (i = 0; i < machine->possible_cpus->len; i++) {
+ HotpluggableCPUList *list_item = g_new0(typeof(*list_item), 1);
+ HotpluggableCPU *cpu_item = g_new0(typeof(*cpu_item), 1);
+
+ cpu_item->type = g_strdup(cpu_type);
+ cpu_item->vcpus_count = machine->possible_cpus->cpus[i].vcpus_count;
+ cpu_item->props = g_memdup(&machine->possible_cpus->cpus[i].props,
+ sizeof(*cpu_item->props));
+
+ cpu = machine->possible_cpus->cpus[i].cpu;
+ if (cpu) {
+ cpu_item->has_qom_path = true;
+ cpu_item->qom_path = object_get_canonical_path(cpu);
+ }
+ list_item->value = cpu_item;
+ list_item->next = head;
+ head = list_item;
+ }
+ return head;
+}
+
static void machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index 1deb52070a..b9e7cb1df1 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -900,6 +900,10 @@ static int cirrus_bitblt_cputovideo(CirrusVGAState * s)
{
int w;
+ if (blit_is_unsafe(s, true)) {
+ return 0;
+ }
+
s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_MEMSYSSRC;
s->cirrus_srcptr = &s->cirrus_bltbuf[0];
s->cirrus_srcptr_end = &s->cirrus_bltbuf[0];
@@ -925,6 +929,10 @@ static int cirrus_bitblt_cputovideo(CirrusVGAState * s)
}
s->cirrus_srccounter = s->cirrus_blt_srcpitch * s->cirrus_blt_height;
}
+
+ /* the blit_is_unsafe call above should catch this */
+ assert(s->cirrus_blt_srcpitch <= CIRRUS_BLTBUFSIZE);
+
s->cirrus_srcptr = s->cirrus_bltbuf;
s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
cirrus_update_memory_access(s);
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 60b0946be3..d24388e05f 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -707,7 +707,8 @@ static void pc_build_smbios(PCMachineState *pcms)
size_t smbios_tables_len, smbios_anchor_len;
struct smbios_phys_mem_area *mem_array;
unsigned i, array_count;
- X86CPU *cpu = X86_CPU(pcms->possible_cpus->cpus[0].cpu);
+ MachineState *ms = MACHINE(pcms);
+ X86CPU *cpu = X86_CPU(ms->possible_cpus->cpus[0].cpu);
/* tell smbios about cpuid version and features */
smbios_set_cpuid(cpu->env.cpuid_version, cpu->env.features[FEAT_1_EDX]);
@@ -1111,7 +1112,7 @@ static void pc_new_cpu(const char *typename, int64_t apic_id, Error **errp)
void pc_hot_add_cpu(const int64_t id, Error **errp)
{
ObjectClass *oc;
- PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
+ MachineState *ms = MACHINE(qdev_get_machine());
int64_t apic_id = x86_cpu_apic_id_from_index(id);
Error *local_err = NULL;
@@ -1127,8 +1128,8 @@ void pc_hot_add_cpu(const int64_t id, Error **errp)
return;
}
- assert(pcms->possible_cpus->cpus[0].cpu); /* BSP is always present */
- oc = OBJECT_CLASS(CPU_GET_CLASS(pcms->possible_cpus->cpus[0].cpu));
+ assert(ms->possible_cpus->cpus[0].cpu); /* BSP is always present */
+ oc = OBJECT_CLASS(CPU_GET_CLASS(ms->possible_cpus->cpus[0].cpu));
pc_new_cpu(object_class_get_name(oc), apic_id, &local_err);
if (local_err) {
error_propagate(errp, local_err);
@@ -1143,7 +1144,9 @@ void pc_cpus_init(PCMachineState *pcms)
ObjectClass *oc;
const char *typename;
gchar **model_pieces;
+ const CPUArchIdList *possible_cpus;
MachineState *machine = MACHINE(pcms);
+ MachineClass *mc = MACHINE_GET_CLASS(pcms);
/* init CPUs */
if (machine->cpu_model == NULL) {
@@ -1178,20 +1181,16 @@ void pc_cpus_init(PCMachineState *pcms)
* This is used for FW_CFG_MAX_CPUS. See comments on bochs_bios_init().
*/
pcms->apic_id_limit = x86_cpu_apic_id_from_index(max_cpus - 1) + 1;
- pcms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
- sizeof(CPUArchId) * max_cpus);
- for (i = 0; i < max_cpus; i++) {
- pcms->possible_cpus->cpus[i].arch_id = x86_cpu_apic_id_from_index(i);
- pcms->possible_cpus->len++;
- if (i < smp_cpus) {
- pc_new_cpu(typename, x86_cpu_apic_id_from_index(i), &error_fatal);
- }
+ possible_cpus = mc->possible_cpu_arch_ids(machine);
+ for (i = 0; i < smp_cpus; i++) {
+ pc_new_cpu(typename, possible_cpus->cpus[i].arch_id, &error_fatal);
}
}
static void pc_build_feature_control_file(PCMachineState *pcms)
{
- X86CPU *cpu = X86_CPU(pcms->possible_cpus->cpus[0].cpu);
+ MachineState *ms = MACHINE(pcms);
+ X86CPU *cpu = X86_CPU(ms->possible_cpus->cpus[0].cpu);
CPUX86State *env = &cpu->env;
uint32_t unused, ecx, edx;
uint64_t feature_control_bits = 0;
@@ -1787,21 +1786,19 @@ static int pc_apic_cmp(const void *a, const void *b)
}
/* returns pointer to CPUArchId descriptor that matches CPU's apic_id
- * in pcms->possible_cpus->cpus, if pcms->possible_cpus->cpus has no
+ * in ms->possible_cpus->cpus, if ms->possible_cpus->cpus has no
* entry corresponding to CPU's apic_id returns NULL.
*/
-static CPUArchId *pc_find_cpu_slot(PCMachineState *pcms, CPUState *cpu,
- int *idx)
+static CPUArchId *pc_find_cpu_slot(MachineState *ms, uint32_t id, int *idx)
{
- CPUClass *cc = CPU_GET_CLASS(cpu);
CPUArchId apic_id, *found_cpu;
- apic_id.arch_id = cc->get_arch_id(CPU(cpu));
- found_cpu = bsearch(&apic_id, pcms->possible_cpus->cpus,
- pcms->possible_cpus->len, sizeof(*pcms->possible_cpus->cpus),
+ apic_id.arch_id = id;
+ found_cpu = bsearch(&apic_id, ms->possible_cpus->cpus,
+ ms->possible_cpus->len, sizeof(*ms->possible_cpus->cpus),
pc_apic_cmp);
if (found_cpu && idx) {
- *idx = found_cpu - pcms->possible_cpus->cpus;
+ *idx = found_cpu - ms->possible_cpus->cpus;
}
return found_cpu;
}
@@ -1812,6 +1809,7 @@ static void pc_cpu_plug(HotplugHandler *hotplug_dev,
CPUArchId *found_cpu;
HotplugHandlerClass *hhc;
Error *local_err = NULL;
+ X86CPU *cpu = X86_CPU(dev);
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
if (pcms->acpi_dev) {
@@ -1831,8 +1829,8 @@ static void pc_cpu_plug(HotplugHandler *hotplug_dev,
fw_cfg_modify_i16(pcms->fw_cfg, FW_CFG_NB_CPUS, pcms->boot_cpus);
}
- found_cpu = pc_find_cpu_slot(pcms, CPU(dev), NULL);
- found_cpu->cpu = CPU(dev);
+ found_cpu = pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, NULL);
+ found_cpu->cpu = OBJECT(dev);
out:
error_propagate(errp, local_err);
}
@@ -1842,9 +1840,10 @@ static void pc_cpu_unplug_request_cb(HotplugHandler *hotplug_dev,
int idx = -1;
HotplugHandlerClass *hhc;
Error *local_err = NULL;
+ X86CPU *cpu = X86_CPU(dev);
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
- pc_find_cpu_slot(pcms, CPU(dev), &idx);
+ pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, &idx);
assert(idx != -1);
if (idx == 0) {
error_setg(&local_err, "Boot CPU is unpluggable");
@@ -1869,6 +1868,7 @@ static void pc_cpu_unplug_cb(HotplugHandler *hotplug_dev,
CPUArchId *found_cpu;
HotplugHandlerClass *hhc;
Error *local_err = NULL;
+ X86CPU *cpu = X86_CPU(dev);
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
hhc = HOTPLUG_HANDLER_GET_CLASS(pcms->acpi_dev);
@@ -1878,7 +1878,7 @@ static void pc_cpu_unplug_cb(HotplugHandler *hotplug_dev,
goto out;
}
- found_cpu = pc_find_cpu_slot(pcms, CPU(dev), NULL);
+ found_cpu = pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, NULL);
found_cpu->cpu = NULL;
object_unparent(OBJECT(dev));
@@ -1936,13 +1936,15 @@ static void pc_cpu_pre_plug(HotplugHandler *hotplug_dev,
cpu->apic_id = apicid_from_topo_ids(smp_cores, smp_threads, &topo);
}
- cpu_slot = pc_find_cpu_slot(pcms, CPU(dev), &idx);
+ cpu_slot = pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, &idx);
if (!cpu_slot) {
+ MachineState *ms = MACHINE(pcms);
+
x86_topo_ids_from_apicid(cpu->apic_id, smp_cores, smp_threads, &topo);
error_setg(errp, "Invalid CPU [socket: %u, core: %u, thread: %u] with"
" APIC ID %" PRIu32 ", valid index range 0:%d",
topo.pkg_id, topo.core_id, topo.smt_id, cpu->apic_id,
- pcms->possible_cpus->len - 1);
+ ms->possible_cpus->len - 1);
return;
}
@@ -1953,7 +1955,7 @@ static void pc_cpu_pre_plug(HotplugHandler *hotplug_dev,
}
/* if 'address' properties socket-id/core-id/thread-id are not set, set them
- * so that query_hotpluggable_cpus would show correct values
+ * so that machine_query_hotpluggable_cpus would show correct values
*/
/* TODO: move socket_id/core_id/thread_id checks into x86_cpu_realizefn()
* once -smp refactoring is complete and there will be CPU private
@@ -2251,55 +2253,37 @@ static unsigned pc_cpu_index_to_socket_id(unsigned cpu_index)
return topo.pkg_id;
}
-static const CPUArchIdList *pc_possible_cpu_arch_ids(MachineState *machine)
-{
- PCMachineState *pcms = PC_MACHINE(machine);
- assert(pcms->possible_cpus);
- return pcms->possible_cpus;
-}
-
-static HotpluggableCPUList *pc_query_hotpluggable_cpus(MachineState *machine)
+static const CPUArchIdList *pc_possible_cpu_arch_ids(MachineState *ms)
{
int i;
- CPUState *cpu;
- HotpluggableCPUList *head = NULL;
- PCMachineState *pcms = PC_MACHINE(machine);
- const char *cpu_type;
- cpu = pcms->possible_cpus->cpus[0].cpu;
- assert(cpu); /* BSP is always present */
- cpu_type = object_class_get_name(OBJECT_CLASS(CPU_GET_CLASS(cpu)));
+ if (ms->possible_cpus) {
+ /*
+ * make sure that max_cpus hasn't changed since the first use, i.e.
+ * -smp hasn't been parsed after it
+ */
+ assert(ms->possible_cpus->len == max_cpus);
+ return ms->possible_cpus;
+ }
- for (i = 0; i < pcms->possible_cpus->len; i++) {
+ ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
+ sizeof(CPUArchId) * max_cpus);
+ ms->possible_cpus->len = max_cpus;
+ for (i = 0; i < ms->possible_cpus->len; i++) {
X86CPUTopoInfo topo;
- HotpluggableCPUList *list_item = g_new0(typeof(*list_item), 1);
- HotpluggableCPU *cpu_item = g_new0(typeof(*cpu_item), 1);
- CpuInstanceProperties *cpu_props = g_new0(typeof(*cpu_props), 1);
- const uint32_t apic_id = pcms->possible_cpus->cpus[i].arch_id;
-
- x86_topo_ids_from_apicid(apic_id, smp_cores, smp_threads, &topo);
-
- cpu_item->type = g_strdup(cpu_type);
- cpu_item->vcpus_count = 1;
- cpu_props->has_socket_id = true;
- cpu_props->socket_id = topo.pkg_id;
- cpu_props->has_core_id = true;
- cpu_props->core_id = topo.core_id;
- cpu_props->has_thread_id = true;
- cpu_props->thread_id = topo.smt_id;
- cpu_item->props = cpu_props;
-
- cpu = pcms->possible_cpus->cpus[i].cpu;
- if (cpu) {
- cpu_item->has_qom_path = true;
- cpu_item->qom_path = object_get_canonical_path(OBJECT(cpu));
- }
- list_item->value = cpu_item;
- list_item->next = head;
- head = list_item;
+ ms->possible_cpus->cpus[i].vcpus_count = 1;
+ ms->possible_cpus->cpus[i].arch_id = x86_cpu_apic_id_from_index(i);
+ x86_topo_ids_from_apicid(ms->possible_cpus->cpus[i].arch_id,
+ smp_cores, smp_threads, &topo);
+ ms->possible_cpus->cpus[i].props.has_socket_id = true;
+ ms->possible_cpus->cpus[i].props.socket_id = topo.pkg_id;
+ ms->possible_cpus->cpus[i].props.has_core_id = true;
+ ms->possible_cpus->cpus[i].props.core_id = topo.core_id;
+ ms->possible_cpus->cpus[i].props.has_thread_id = true;
+ ms->possible_cpus->cpus[i].props.thread_id = topo.smt_id;
}
- return head;
+ return ms->possible_cpus;
}
static void x86_nmi(NMIState *n, int cpu_index, Error **errp)
@@ -2342,7 +2326,7 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
mc->get_hotplug_handler = pc_get_hotpug_handler;
mc->cpu_index_to_socket_id = pc_cpu_index_to_socket_id;
mc->possible_cpu_arch_ids = pc_possible_cpu_arch_ids;
- mc->query_hotpluggable_cpus = pc_query_hotpluggable_cpus;
+ mc->has_hotpluggable_cpus = true;
mc->default_boot_order = "cad";
mc->hot_add_cpu = pc_hot_add_cpu;
mc->block_default_type = IF_IDE;
diff --git a/hw/mips/Makefile.objs b/hw/mips/Makefile.objs
index 48cd2ef50e..9352a1c062 100644
--- a/hw/mips/Makefile.objs
+++ b/hw/mips/Makefile.objs
@@ -4,4 +4,3 @@ obj-$(CONFIG_JAZZ) += mips_jazz.o
obj-$(CONFIG_FULONG) += mips_fulong2e.o
obj-y += gt64xxx_pci.o
obj-$(CONFIG_MIPS_CPS) += cps.o
-obj-$(CONFIG_MIPS_BOSTON) += boston.o
diff --git a/hw/mips/boston.c b/hw/mips/boston.c
deleted file mode 100644
index ce43289ace..0000000000
--- a/hw/mips/boston.c
+++ /dev/null
@@ -1,577 +0,0 @@
-/*
- * MIPS Boston development board emulation.
- *
- * Copyright (c) 2016 Imagination Technologies
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-
-#include "exec/address-spaces.h"
-#include "hw/boards.h"
-#include "hw/char/serial.h"
-#include "hw/hw.h"
-#include "hw/ide/pci.h"
-#include "hw/ide/ahci.h"
-#include "hw/loader.h"
-#include "hw/loader-fit.h"
-#include "hw/mips/cps.h"
-#include "hw/mips/cpudevs.h"
-#include "hw/pci-host/xilinx-pcie.h"
-#include "qapi/error.h"
-#include "qemu/cutils.h"
-#include "qemu/error-report.h"
-#include "qemu/log.h"
-#include "sysemu/char.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/qtest.h"
-
-#include <libfdt.h>
-
-#define TYPE_MIPS_BOSTON "mips-boston"
-#define BOSTON(obj) OBJECT_CHECK(BostonState, (obj), TYPE_MIPS_BOSTON)
-
-typedef struct {
- SysBusDevice parent_obj;
-
- MachineState *mach;
- MIPSCPSState *cps;
- SerialState *uart;
-
- CharBackend lcd_display;
- char lcd_content[8];
- bool lcd_inited;
-
- hwaddr kernel_entry;
- hwaddr fdt_base;
-} BostonState;
-
-enum boston_plat_reg {
- PLAT_FPGA_BUILD = 0x00,
- PLAT_CORE_CL = 0x04,
- PLAT_WRAPPER_CL = 0x08,
- PLAT_SYSCLK_STATUS = 0x0c,
- PLAT_SOFTRST_CTL = 0x10,
-#define PLAT_SOFTRST_CTL_SYSRESET (1 << 4)
- PLAT_DDR3_STATUS = 0x14,
-#define PLAT_DDR3_STATUS_LOCKED (1 << 0)
-#define PLAT_DDR3_STATUS_CALIBRATED (1 << 2)
- PLAT_PCIE_STATUS = 0x18,
-#define PLAT_PCIE_STATUS_PCIE0_LOCKED (1 << 0)
-#define PLAT_PCIE_STATUS_PCIE1_LOCKED (1 << 8)
-#define PLAT_PCIE_STATUS_PCIE2_LOCKED (1 << 16)
- PLAT_FLASH_CTL = 0x1c,
- PLAT_SPARE0 = 0x20,
- PLAT_SPARE1 = 0x24,
- PLAT_SPARE2 = 0x28,
- PLAT_SPARE3 = 0x2c,
- PLAT_MMCM_DIV = 0x30,
-#define PLAT_MMCM_DIV_CLK0DIV_SHIFT 0
-#define PLAT_MMCM_DIV_INPUT_SHIFT 8
-#define PLAT_MMCM_DIV_MUL_SHIFT 16
-#define PLAT_MMCM_DIV_CLK1DIV_SHIFT 24
- PLAT_BUILD_CFG = 0x34,
-#define PLAT_BUILD_CFG_IOCU_EN (1 << 0)
-#define PLAT_BUILD_CFG_PCIE0_EN (1 << 1)
-#define PLAT_BUILD_CFG_PCIE1_EN (1 << 2)
-#define PLAT_BUILD_CFG_PCIE2_EN (1 << 3)
- PLAT_DDR_CFG = 0x38,
-#define PLAT_DDR_CFG_SIZE (0xf << 0)
-#define PLAT_DDR_CFG_MHZ (0xfff << 4)
- PLAT_NOC_PCIE0_ADDR = 0x3c,
- PLAT_NOC_PCIE1_ADDR = 0x40,
- PLAT_NOC_PCIE2_ADDR = 0x44,
- PLAT_SYS_CTL = 0x48,
-};
-
-static void boston_lcd_event(void *opaque, int event)
-{
- BostonState *s = opaque;
- if (event == CHR_EVENT_OPENED && !s->lcd_inited) {
- qemu_chr_fe_printf(&s->lcd_display, " ");
- s->lcd_inited = true;
- }
-}
-
-static uint64_t boston_lcd_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- BostonState *s = opaque;
- uint64_t val = 0;
-
- switch (size) {
- case 8:
- val |= (uint64_t)s->lcd_content[(addr + 7) & 0x7] << 56;
- val |= (uint64_t)s->lcd_content[(addr + 6) & 0x7] << 48;
- val |= (uint64_t)s->lcd_content[(addr + 5) & 0x7] << 40;
- val |= (uint64_t)s->lcd_content[(addr + 4) & 0x7] << 32;
- /* fall through */
- case 4:
- val |= (uint64_t)s->lcd_content[(addr + 3) & 0x7] << 24;
- val |= (uint64_t)s->lcd_content[(addr + 2) & 0x7] << 16;
- /* fall through */
- case 2:
- val |= (uint64_t)s->lcd_content[(addr + 1) & 0x7] << 8;
- /* fall through */
- case 1:
- val |= (uint64_t)s->lcd_content[(addr + 0) & 0x7];
- break;
- }
-
- return val;
-}
-
-static void boston_lcd_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- BostonState *s = opaque;
-
- switch (size) {
- case 8:
- s->lcd_content[(addr + 7) & 0x7] = val >> 56;
- s->lcd_content[(addr + 6) & 0x7] = val >> 48;
- s->lcd_content[(addr + 5) & 0x7] = val >> 40;
- s->lcd_content[(addr + 4) & 0x7] = val >> 32;
- /* fall through */
- case 4:
- s->lcd_content[(addr + 3) & 0x7] = val >> 24;
- s->lcd_content[(addr + 2) & 0x7] = val >> 16;
- /* fall through */
- case 2:
- s->lcd_content[(addr + 1) & 0x7] = val >> 8;
- /* fall through */
- case 1:
- s->lcd_content[(addr + 0) & 0x7] = val;
- break;
- }
-
- qemu_chr_fe_printf(&s->lcd_display,
- "\r%-8.8s", s->lcd_content);
-}
-
-static const MemoryRegionOps boston_lcd_ops = {
- .read = boston_lcd_read,
- .write = boston_lcd_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t boston_platreg_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- BostonState *s = opaque;
- uint32_t gic_freq, val;
-
- if (size != 4) {
- qemu_log_mask(LOG_UNIMP, "%uB platform register read", size);
- return 0;
- }
-
- switch (addr & 0xffff) {
- case PLAT_FPGA_BUILD:
- case PLAT_CORE_CL:
- case PLAT_WRAPPER_CL:
- return 0;
- case PLAT_DDR3_STATUS:
- return PLAT_DDR3_STATUS_LOCKED | PLAT_DDR3_STATUS_CALIBRATED;
- case PLAT_MMCM_DIV:
- gic_freq = mips_gictimer_get_freq(s->cps->gic.gic_timer) / 1000000;
- val = gic_freq << PLAT_MMCM_DIV_INPUT_SHIFT;
- val |= 1 << PLAT_MMCM_DIV_MUL_SHIFT;
- val |= 1 << PLAT_MMCM_DIV_CLK0DIV_SHIFT;
- val |= 1 << PLAT_MMCM_DIV_CLK1DIV_SHIFT;
- return val;
- case PLAT_BUILD_CFG:
- val = PLAT_BUILD_CFG_PCIE0_EN;
- val |= PLAT_BUILD_CFG_PCIE1_EN;
- val |= PLAT_BUILD_CFG_PCIE2_EN;
- return val;
- case PLAT_DDR_CFG:
- val = s->mach->ram_size / G_BYTE;
- assert(!(val & ~PLAT_DDR_CFG_SIZE));
- val |= PLAT_DDR_CFG_MHZ;
- return val;
- default:
- qemu_log_mask(LOG_UNIMP, "Read platform register 0x%" HWADDR_PRIx,
- addr & 0xffff);
- return 0;
- }
-}
-
-static void boston_platreg_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- if (size != 4) {
- qemu_log_mask(LOG_UNIMP, "%uB platform register write", size);
- return;
- }
-
- switch (addr & 0xffff) {
- case PLAT_FPGA_BUILD:
- case PLAT_CORE_CL:
- case PLAT_WRAPPER_CL:
- case PLAT_DDR3_STATUS:
- case PLAT_PCIE_STATUS:
- case PLAT_MMCM_DIV:
- case PLAT_BUILD_CFG:
- case PLAT_DDR_CFG:
- /* read only */
- break;
- case PLAT_SOFTRST_CTL:
- if (val & PLAT_SOFTRST_CTL_SYSRESET) {
- qemu_system_reset_request();
- }
- break;
- default:
- qemu_log_mask(LOG_UNIMP, "Write platform register 0x%" HWADDR_PRIx
- " = 0x%" PRIx64, addr & 0xffff, val);
- break;
- }
-}
-
-static const MemoryRegionOps boston_platreg_ops = {
- .read = boston_platreg_read,
- .write = boston_platreg_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void boston_flash_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
-}
-
-static const MemoryRegionOps boston_flash_ops = {
- .write = boston_flash_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const TypeInfo boston_device = {
- .name = TYPE_MIPS_BOSTON,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(BostonState),
-};
-
-static void boston_register_types(void)
-{
- type_register_static(&boston_device);
-}
-type_init(boston_register_types)
-
-static void gen_firmware(uint32_t *p, hwaddr kernel_entry, hwaddr fdt_addr,
- bool is_64b)
-{
- const uint32_t cm_base = 0x16100000;
- const uint32_t gic_base = 0x16120000;
- const uint32_t cpc_base = 0x16200000;
-
- /* Move CM GCRs */
- if (is_64b) {
- stl_p(p++, 0x40287803); /* dmfc0 $8, CMGCRBase */
- stl_p(p++, 0x00084138); /* dsll $8, $8, 4 */
- } else {
- stl_p(p++, 0x40087803); /* mfc0 $8, CMGCRBase */
- stl_p(p++, 0x00084100); /* sll $8, $8, 4 */
- }
- stl_p(p++, 0x3c09a000); /* lui $9, 0xa000 */
- stl_p(p++, 0x01094025); /* or $8, $9 */
- stl_p(p++, 0x3c0a0000 | (cm_base >> 16)); /* lui $10, cm_base >> 16 */
- if (is_64b) {
- stl_p(p++, 0xfd0a0008); /* sd $10, 0x8($8) */
- } else {
- stl_p(p++, 0xad0a0008); /* sw $10, 0x8($8) */
- }
- stl_p(p++, 0x012a4025); /* or $8, $10 */
-
- /* Move & enable GIC GCRs */
- stl_p(p++, 0x3c090000 | (gic_base >> 16)); /* lui $9, gic_base >> 16 */
- stl_p(p++, 0x35290001); /* ori $9, 0x1 */
- if (is_64b) {
- stl_p(p++, 0xfd090080); /* sd $9, 0x80($8) */
- } else {
- stl_p(p++, 0xad090080); /* sw $9, 0x80($8) */
- }
-
- /* Move & enable CPC GCRs */
- stl_p(p++, 0x3c090000 | (cpc_base >> 16)); /* lui $9, cpc_base >> 16 */
- stl_p(p++, 0x35290001); /* ori $9, 0x1 */
- if (is_64b) {
- stl_p(p++, 0xfd090088); /* sd $9, 0x88($8) */
- } else {
- stl_p(p++, 0xad090088); /* sw $9, 0x88($8) */
- }
-
- /*
- * Setup argument registers to follow the UHI boot protocol:
- *
- * a0/$4 = -2
- * a1/$5 = virtual address of FDT
- * a2/$6 = 0
- * a3/$7 = 0
- */
- stl_p(p++, 0x2404fffe); /* li $4, -2 */
- /* lui $5, hi(fdt_addr) */
- stl_p(p++, 0x3c050000 | ((fdt_addr >> 16) & 0xffff));
- if (fdt_addr & 0xffff) { /* ori $5, lo(fdt_addr) */
- stl_p(p++, 0x34a50000 | (fdt_addr & 0xffff));
- }
- stl_p(p++, 0x34060000); /* li $6, 0 */
- stl_p(p++, 0x34070000); /* li $7, 0 */
-
- /* Load kernel entry address & jump to it */
- /* lui $25, hi(kernel_entry) */
- stl_p(p++, 0x3c190000 | ((kernel_entry >> 16) & 0xffff));
- /* ori $25, lo(kernel_entry) */
- stl_p(p++, 0x37390000 | (kernel_entry & 0xffff));
- stl_p(p++, 0x03200009); /* jr $25 */
-}
-
-static const void *boston_fdt_filter(void *opaque, const void *fdt_orig,
- const void *match_data, hwaddr *load_addr)
-{
- BostonState *s = BOSTON(opaque);
- MachineState *machine = s->mach;
- const char *cmdline;
- int err;
- void *fdt;
- size_t fdt_sz, ram_low_sz, ram_high_sz;
-
- fdt_sz = fdt_totalsize(fdt_orig) * 2;
- fdt = g_malloc0(fdt_sz);
-
- err = fdt_open_into(fdt_orig, fdt, fdt_sz);
- if (err) {
- fprintf(stderr, "unable to open FDT\n");
- return NULL;
- }
-
- cmdline = (machine->kernel_cmdline && machine->kernel_cmdline[0])
- ? machine->kernel_cmdline : " ";
- err = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
- if (err < 0) {
- fprintf(stderr, "couldn't set /chosen/bootargs\n");
- return NULL;
- }
-
- ram_low_sz = MIN(256 * M_BYTE, machine->ram_size);
- ram_high_sz = machine->ram_size - ram_low_sz;
- qemu_fdt_setprop_sized_cells(fdt, "/memory@0", "reg",
- 1, 0x00000000, 1, ram_low_sz,
- 1, 0x90000000, 1, ram_high_sz);
-
- fdt = g_realloc(fdt, fdt_totalsize(fdt));
- qemu_fdt_dumpdtb(fdt, fdt_sz);
-
- s->fdt_base = *load_addr;
-
- return fdt;
-}
-
-static const void *boston_kernel_filter(void *opaque, const void *kernel,
- hwaddr *load_addr, hwaddr *entry_addr)
-{
- BostonState *s = BOSTON(opaque);
-
- s->kernel_entry = *entry_addr;
-
- return kernel;
-}
-
-static const struct fit_loader_match boston_matches[] = {
- { "img,boston" },
- { NULL },
-};
-
-static const struct fit_loader boston_fit_loader = {
- .matches = boston_matches,
- .addr_to_phys = cpu_mips_kseg0_to_phys,
- .fdt_filter = boston_fdt_filter,
- .kernel_filter = boston_kernel_filter,
-};
-
-static inline XilinxPCIEHost *
-xilinx_pcie_init(MemoryRegion *sys_mem, uint32_t bus_nr,
- hwaddr cfg_base, uint64_t cfg_size,
- hwaddr mmio_base, uint64_t mmio_size,
- qemu_irq irq, bool link_up)
-{
- DeviceState *dev;
- MemoryRegion *cfg, *mmio;
-
- dev = qdev_create(NULL, TYPE_XILINX_PCIE_HOST);
-
- qdev_prop_set_uint32(dev, "bus_nr", bus_nr);
- qdev_prop_set_uint64(dev, "cfg_base", cfg_base);
- qdev_prop_set_uint64(dev, "cfg_size", cfg_size);
- qdev_prop_set_uint64(dev, "mmio_base", mmio_base);
- qdev_prop_set_uint64(dev, "mmio_size", mmio_size);
- qdev_prop_set_bit(dev, "link_up", link_up);
-
- qdev_init_nofail(dev);
-
- cfg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
- memory_region_add_subregion_overlap(sys_mem, cfg_base, cfg, 0);
-
- mmio = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
- memory_region_add_subregion_overlap(sys_mem, 0, mmio, 0);
-
- qdev_connect_gpio_out_named(dev, "interrupt_out", 0, irq);
-
- return XILINX_PCIE_HOST(dev);
-}
-
-static void boston_mach_init(MachineState *machine)
-{
- DeviceState *dev;
- BostonState *s;
- Error *err = NULL;
- const char *cpu_model;
- MemoryRegion *flash, *ddr, *ddr_low_alias, *lcd, *platreg;
- MemoryRegion *sys_mem = get_system_memory();
- XilinxPCIEHost *pcie2;
- PCIDevice *ahci;
- DriveInfo *hd[6];
- Chardev *chr;
- int fw_size, fit_err;
- bool is_64b;
-
- if ((machine->ram_size % G_BYTE) ||
- (machine->ram_size > (2 * G_BYTE))) {
- error_report("Memory size must be 1GB or 2GB");
- exit(1);
- }
-
- cpu_model = machine->cpu_model ?: "I6400";
-
- dev = qdev_create(NULL, TYPE_MIPS_BOSTON);
- qdev_init_nofail(dev);
-
- s = BOSTON(dev);
- s->mach = machine;
- s->cps = g_new0(MIPSCPSState, 1);
-
- if (!cpu_supports_cps_smp(cpu_model)) {
- error_report("Boston requires CPUs which support CPS");
- exit(1);
- }
-
- is_64b = cpu_supports_isa(cpu_model, ISA_MIPS64);
-
- object_initialize(s->cps, sizeof(MIPSCPSState), TYPE_MIPS_CPS);
- qdev_set_parent_bus(DEVICE(s->cps), sysbus_get_default());
-
- object_property_set_str(OBJECT(s->cps), cpu_model, "cpu-model", &err);
- object_property_set_int(OBJECT(s->cps), smp_cpus, "num-vp", &err);
- object_property_set_bool(OBJECT(s->cps), true, "realized", &err);
-
- if (err != NULL) {
- error_report("%s", error_get_pretty(err));
- exit(1);
- }
-
- sysbus_mmio_map_overlap(SYS_BUS_DEVICE(s->cps), 0, 0, 1);
-
- flash = g_new(MemoryRegion, 1);
- memory_region_init_rom_device(flash, NULL, &boston_flash_ops, s,
- "boston.flash", 128 * M_BYTE, &err);
- memory_region_add_subregion_overlap(sys_mem, 0x18000000, flash, 0);
-
- ddr = g_new(MemoryRegion, 1);
- memory_region_allocate_system_memory(ddr, NULL, "boston.ddr",
- machine->ram_size);
- memory_region_add_subregion_overlap(sys_mem, 0x80000000, ddr, 0);
-
- ddr_low_alias = g_new(MemoryRegion, 1);
- memory_region_init_alias(ddr_low_alias, NULL, "boston_low.ddr",
- ddr, 0, MIN(machine->ram_size, (256 * M_BYTE)));
- memory_region_add_subregion_overlap(sys_mem, 0, ddr_low_alias, 0);
-
- xilinx_pcie_init(sys_mem, 0,
- 0x10000000, 32 * M_BYTE,
- 0x40000000, 1 * G_BYTE,
- get_cps_irq(s->cps, 2), false);
-
- xilinx_pcie_init(sys_mem, 1,
- 0x12000000, 32 * M_BYTE,
- 0x20000000, 512 * M_BYTE,
- get_cps_irq(s->cps, 1), false);
-
- pcie2 = xilinx_pcie_init(sys_mem, 2,
- 0x14000000, 32 * M_BYTE,
- 0x16000000, 1 * M_BYTE,
- get_cps_irq(s->cps, 0), true);
-
- platreg = g_new(MemoryRegion, 1);
- memory_region_init_io(platreg, NULL, &boston_platreg_ops, s,
- "boston-platregs", 0x1000);
- memory_region_add_subregion_overlap(sys_mem, 0x17ffd000, platreg, 0);
-
- if (!serial_hds[0]) {
- serial_hds[0] = qemu_chr_new("serial0", "null");
- }
-
- s->uart = serial_mm_init(sys_mem, 0x17ffe000, 2,
- get_cps_irq(s->cps, 3), 10000000,
- serial_hds[0], DEVICE_NATIVE_ENDIAN);
-
- lcd = g_new(MemoryRegion, 1);
- memory_region_init_io(lcd, NULL, &boston_lcd_ops, s, "boston-lcd", 0x8);
- memory_region_add_subregion_overlap(sys_mem, 0x17fff000, lcd, 0);
-
- chr = qemu_chr_new("lcd", "vc:320x240");
- qemu_chr_fe_init(&s->lcd_display, chr, NULL);
- qemu_chr_fe_set_handlers(&s->lcd_display, NULL, NULL,
- boston_lcd_event, s, NULL, true);
-
- ahci = pci_create_simple_multifunction(&PCI_BRIDGE(&pcie2->root)->sec_bus,
- PCI_DEVFN(0, 0),
- true, TYPE_ICH9_AHCI);
- g_assert(ARRAY_SIZE(hd) == ICH_AHCI(ahci)->ahci.ports);
- ide_drive_get(hd, ICH_AHCI(ahci)->ahci.ports);
- ahci_ide_create_devs(ahci, hd);
-
- if (machine->firmware) {
- fw_size = load_image_targphys(machine->firmware,
- 0x1fc00000, 4 * M_BYTE);
- if (fw_size == -1) {
- error_printf("unable to load firmware image '%s'\n",
- machine->firmware);
- exit(1);
- }
- } else if (machine->kernel_filename) {
- fit_err = load_fit(&boston_fit_loader, machine->kernel_filename, s);
- if (fit_err) {
- error_printf("unable to load FIT image\n");
- exit(1);
- }
-
- gen_firmware(memory_region_get_ram_ptr(flash) + 0x7c00000,
- s->kernel_entry, s->fdt_base, is_64b);
- } else if (!qtest_enabled()) {
- error_printf("Please provide either a -kernel or -bios argument\n");
- exit(1);
- }
-}
-
-static void boston_mach_class_init(MachineClass *mc)
-{
- mc->desc = "MIPS Boston";
- mc->init = boston_mach_init;
- mc->block_default_type = IF_IDE;
- mc->default_ram_size = 2 * G_BYTE;
- mc->max_cpus = 16;
-}
-
-DEFINE_MACHINE("boston", boston_mach_class_init)
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index bf57e635d6..82ce8378bf 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -1267,10 +1267,11 @@ static void ivshmem_realize(PCIDevice *dev, Error **errp)
if (s->sizearg == NULL) {
s->legacy_size = 4 << 20; /* 4 MB default */
} else {
- char *end;
- int64_t size = qemu_strtosz(s->sizearg, &end);
- if (size < 0 || (size_t)size != size || *end != '\0'
- || !is_power_of_2(size)) {
+ int ret;
+ uint64_t size;
+
+ ret = qemu_strtosz_MiB(s->sizearg, NULL, &size);
+ if (ret < 0 || (size_t)size != size || !is_power_of_2(size)) {
error_setg(errp, "Invalid size %s", s->sizearg);
return;
}
diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c
index 058908d8d7..d239e4bd7d 100644
--- a/hw/net/spapr_llan.c
+++ b/hw/net/spapr_llan.c
@@ -385,18 +385,24 @@ static int spapr_vlan_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
int ret;
/* Some old phyp versions give the mac address in an 8-byte
- * property. The kernel driver has an insane workaround for this;
+ * property. The kernel driver (before 3.10) has an insane workaround;
* rather than doing the obvious thing and checking the property
* length, it checks whether the first byte has 0b10 in the low
* bits. If a correct 6-byte property has a different first byte
* the kernel will get the wrong mac address, overrunning its
* buffer in the process (read only, thank goodness).
*
- * Here we workaround the kernel workaround by always supplying an
- * 8-byte property, with the mac address in the last six bytes */
- memcpy(&padded_mac[2], &vdev->nicconf.macaddr, ETH_ALEN);
- ret = fdt_setprop(fdt, node_off, "local-mac-address",
- padded_mac, sizeof(padded_mac));
+ * Here we return a 6-byte address unless that would break a pre-3.10
+ * driver. In that case we return a padded 8-byte address to allow the old
+ * workaround to succeed. */
+ if ((vdev->nicconf.macaddr.a[0] & 0x3) == 0x2) {
+ ret = fdt_setprop(fdt, node_off, "local-mac-address",
+ &vdev->nicconf.macaddr, ETH_ALEN);
+ } else {
+ memcpy(&padded_mac[2], &vdev->nicconf.macaddr, ETH_ALEN);
+ ret = fdt_setprop(fdt, node_off, "local-mac-address",
+ padded_mac, sizeof(padded_mac));
+ }
if (ret < 0) {
return ret;
}
diff --git a/hw/pci-host/prep.c b/hw/pci-host/prep.c
index 5580293f93..260a119a9e 100644
--- a/hw/pci-host/prep.c
+++ b/hw/pci-host/prep.c
@@ -309,7 +309,6 @@ static void raven_realize(PCIDevice *d, Error **errp)
memory_region_set_readonly(&s->bios, true);
memory_region_add_subregion(get_system_memory(), (uint32_t)(-BIOS_SIZE),
&s->bios);
- vmstate_register_ram_global(&s->bios);
if (s->bios_name) {
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, s->bios_name);
if (filename) {
@@ -328,12 +327,15 @@ static void raven_realize(PCIDevice *d, Error **errp)
}
}
}
+ g_free(filename);
if (bios_size < 0 || bios_size > BIOS_SIZE) {
- /* FIXME should error_setg() */
- hw_error("qemu: could not load bios image '%s'\n", s->bios_name);
+ memory_region_del_subregion(get_system_memory(), &s->bios);
+ error_setg(errp, "Could not load bios image '%s'", s->bios_name);
+ return;
}
- g_free(filename);
}
+
+ vmstate_register_ram_global(&s->bios);
}
static const VMStateDescription vmstate_raven = {
@@ -361,7 +363,6 @@ static void raven_class_init(ObjectClass *klass, void *data)
/*
* Reason: PCI-facing part of the host bridge, not usable without
* the host-facing part, which can't be device_add'ed, yet.
- * Reason: realize() method uses hw_error().
*/
dc->cannot_instantiate_with_device_add_yet = true;
}
diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c
index daf1f65427..a8c18203d6 100644
--- a/hw/pci/pcie_aer.c
+++ b/hw/pci/pcie_aer.c
@@ -1025,8 +1025,8 @@ void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict)
return;
}
- assert(qobject_type(data) == QTYPE_QDICT);
qdict = qobject_to_qdict(data);
+ assert(qdict);
devfn = (int)qdict_get_int(qdict, "devfn");
monitor_printf(mon, "OK id: %s root bus: %s, bus: %x devfn: %x.%x\n",
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index 716aea6852..68aaedc06d 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -72,6 +72,7 @@
#include "exec/address-spaces.h"
#include "hw/sysbus.h"
#include "qemu/cutils.h"
+#include "trace.h"
#define MAX_IDE_BUS 2
#define CFG_ADDR 0xf0000510
@@ -79,21 +80,11 @@
#define CLOCKFREQ (266UL * 1000UL * 1000UL)
#define BUSFREQ (100UL * 1000UL * 1000UL)
-/* debug UniNorth */
-//#define DEBUG_UNIN
-
-#ifdef DEBUG_UNIN
-#define UNIN_DPRINTF(fmt, ...) \
- do { printf("UNIN: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define UNIN_DPRINTF(fmt, ...)
-#endif
-
/* UniN device */
static void unin_write(void *opaque, hwaddr addr, uint64_t value,
unsigned size)
{
- UNIN_DPRINTF("write addr " TARGET_FMT_plx " val %"PRIx64"\n", addr, value);
+ trace_mac99_uninorth_write(addr, value);
if (addr == 0x0) {
*(int*)opaque = value;
}
@@ -109,7 +100,7 @@ static uint64_t unin_read(void *opaque, hwaddr addr, unsigned size)
value = *(int*)opaque;
}
- UNIN_DPRINTF("readl addr " TARGET_FMT_plx " val %x\n", addr, value);
+ trace_mac99_uninorth_read(addr, value);
return value;
}
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 4fab5c0ae7..09f0d22def 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -381,7 +381,7 @@ static void ppc_powernv_init(MachineState *machine)
fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE);
if (fw_size < 0) {
- error_report("qemu: could not load OPAL '%s'", fw_filename);
+ error_report("Could not load OPAL '%s'", fw_filename);
exit(1);
}
g_free(fw_filename);
@@ -393,7 +393,7 @@ static void ppc_powernv_init(MachineState *machine)
kernel_size = load_image_targphys(machine->kernel_filename,
KERNEL_LOAD_ADDR, 0x2000000);
if (kernel_size < 0) {
- error_report("qemu: could not load kernel'%s'",
+ error_report("Could not load kernel '%s'",
machine->kernel_filename);
exit(1);
}
@@ -405,7 +405,7 @@ static void ppc_powernv_init(MachineState *machine)
pnv->initrd_size = load_image_targphys(machine->initrd_filename,
pnv->initrd_base, 0x10000000); /* 128MB max */
if (pnv->initrd_size < 0) {
- error_report("qemu: could not load initial ram disk '%s'",
+ error_report("Could not load initial ram disk '%s'",
machine->initrd_filename);
exit(1);
}
diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c
index d6d3fc2c4a..d5df94aa6e 100644
--- a/hw/ppc/ppc405_uc.c
+++ b/hw/ppc/ppc405_uc.c
@@ -1881,7 +1881,7 @@ static void ppc405cr_clk_setup (ppc405cr_cpc_t *cpc)
D1 = (((cpc->pllmr >> 20) - 1) & 0xF) + 1; /* FBDV */
D2 = 8 - ((cpc->pllmr >> 16) & 0x7); /* FWDVA */
M = D0 * D1 * D2;
- VCO_out = cpc->sysclk * M;
+ VCO_out = (uint64_t)cpc->sysclk * M;
if (VCO_out < 400000000 || VCO_out > 800000000) {
/* PLL cannot lock */
cpc->pllmr &= ~0x80000000;
@@ -1892,7 +1892,7 @@ static void ppc405cr_clk_setup (ppc405cr_cpc_t *cpc)
/* Bypass PLL */
bypass_pll:
M = D0;
- PLL_out = cpc->sysclk * M;
+ PLL_out = (uint64_t)cpc->sysclk * M;
}
CPU_clk = PLL_out;
if (cpc->cr1 & 0x00800000)
@@ -2242,7 +2242,7 @@ static void ppc405ep_compute_clocks (ppc405ep_cpc_t *cpc)
#ifdef DEBUG_CLOCKS_LL
printf("FWDA %01" PRIx32 " %d\n", (cpc->pllmr[1] >> 16) & 0x7, D);
#endif
- VCO_out = cpc->sysclk * M * D;
+ VCO_out = (uint64_t)cpc->sysclk * M * D;
if (VCO_out < 500000000UL || VCO_out > 1000000000UL) {
/* Error - unlock the PLL */
printf("VCO out of range %" PRIu64 "\n", VCO_out);
diff --git a/hw/ppc/ppc4xx_pci.c b/hw/ppc/ppc4xx_pci.c
index 683218e5c5..dc19682970 100644
--- a/hw/ppc/ppc4xx_pci.c
+++ b/hw/ppc/ppc4xx_pci.c
@@ -26,13 +26,7 @@
#include "hw/pci/pci.h"
#include "hw/pci/pci_host.h"
#include "exec/address-spaces.h"
-
-#undef DEBUG
-#ifdef DEBUG
-#define DPRINTF(fmt, ...) do { printf(fmt, ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif /* DEBUG */
+#include "trace.h"
struct PCIMasterMap {
uint32_t la;
@@ -249,8 +243,7 @@ static int ppc4xx_pci_map_irq(PCIDevice *pci_dev, int irq_num)
{
int slot = pci_dev->devfn >> 3;
- DPRINTF("%s: devfn %x irq %d -> %d\n", __func__,
- pci_dev->devfn, irq_num, slot);
+ trace_ppc4xx_pci_map_irq(pci_dev->devfn, irq_num, slot);
return slot - 1;
}
@@ -259,7 +252,7 @@ static void ppc4xx_pci_set_irq(void *opaque, int irq_num, int level)
{
qemu_irq *pci_irqs = opaque;
- DPRINTF("%s: PCI irq %d\n", __func__, irq_num);
+ trace_ppc4xx_pci_set_irq(irq_num);
if (irq_num < 0) {
fprintf(stderr, "%s: PCI irq %d\n", __func__, irq_num);
return;
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index e465d7ac98..5904e6498f 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -958,7 +958,7 @@ static void *spapr_build_fdt(sPAPRMachineState *spapr,
_FDT(spapr_drc_populate_dt(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_LMB));
}
- if (mc->query_hotpluggable_cpus) {
+ if (mc->has_hotpluggable_cpus) {
int offset = fdt_path_offset(fdt, "/cpus");
ret = spapr_drc_populate_dt(fdt, offset, NULL,
SPAPR_DR_CONNECTOR_TYPE_CPU);
@@ -1751,13 +1751,28 @@ static void spapr_validate_node_memory(MachineState *machine, Error **errp)
}
}
+/* find cpu slot in machine->possible_cpus by core_id */
+static CPUArchId *spapr_find_cpu_slot(MachineState *ms, uint32_t id, int *idx)
+{
+ int index = id / smp_threads;
+
+ if (index >= ms->possible_cpus->len) {
+ return NULL;
+ }
+ if (idx) {
+ *idx = index;
+ }
+ return &ms->possible_cpus->cpus[index];
+}
+
static void spapr_init_cpus(sPAPRMachineState *spapr)
{
MachineState *machine = MACHINE(spapr);
MachineClass *mc = MACHINE_GET_CLASS(machine);
char *type = spapr_get_cpu_core_type(machine->cpu_model);
int smt = kvmppc_smt_threads();
- int spapr_max_cores, spapr_cores;
+ const CPUArchIdList *possible_cpus;
+ int boot_cores_nr = smp_cpus / smp_threads;
int i;
if (!type) {
@@ -1765,7 +1780,8 @@ static void spapr_init_cpus(sPAPRMachineState *spapr)
exit(1);
}
- if (mc->query_hotpluggable_cpus) {
+ possible_cpus = mc->possible_cpu_arch_ids(machine);
+ if (mc->has_hotpluggable_cpus) {
if (smp_cpus % smp_threads) {
error_report("smp_cpus (%u) must be multiple of threads (%u)",
smp_cpus, smp_threads);
@@ -1776,24 +1792,18 @@ static void spapr_init_cpus(sPAPRMachineState *spapr)
max_cpus, smp_threads);
exit(1);
}
-
- spapr_max_cores = max_cpus / smp_threads;
- spapr_cores = smp_cpus / smp_threads;
} else {
if (max_cpus != smp_cpus) {
error_report("This machine version does not support CPU hotplug");
exit(1);
}
-
- spapr_max_cores = QEMU_ALIGN_UP(smp_cpus, smp_threads) / smp_threads;
- spapr_cores = spapr_max_cores;
+ boot_cores_nr = possible_cpus->len;
}
- spapr->cores = g_new0(Object *, spapr_max_cores);
- for (i = 0; i < spapr_max_cores; i++) {
+ for (i = 0; i < possible_cpus->len; i++) {
int core_id = i * smp_threads;
- if (mc->query_hotpluggable_cpus) {
+ if (mc->has_hotpluggable_cpus) {
sPAPRDRConnector *drc =
spapr_dr_connector_new(OBJECT(spapr),
SPAPR_DR_CONNECTOR_TYPE_CPU,
@@ -1802,7 +1812,7 @@ static void spapr_init_cpus(sPAPRMachineState *spapr)
qemu_register_reset(spapr_drc_reset, drc);
}
- if (i < spapr_cores) {
+ if (i < boot_cores_nr) {
Object *core = object_new(type);
int nr_threads = smp_threads;
@@ -2357,6 +2367,7 @@ static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
uint64_t align = memory_region_get_alignment(mr);
uint64_t size = memory_region_size(mr);
uint64_t addr;
+ char *mem_dev;
if (size % SPAPR_MEMORY_BLOCK_SIZE) {
error_setg(&local_err, "Hotplugged memory size must be a multiple of "
@@ -2364,6 +2375,13 @@ static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
goto out;
}
+ mem_dev = object_property_get_str(OBJECT(dimm), PC_DIMM_MEMDEV_PROP, NULL);
+ if (mem_dev && !kvmppc_is_mem_backend_page_size_ok(mem_dev)) {
+ error_setg(&local_err, "Memory backend has bad page size. "
+ "Use 'memory-backend-file' with correct mem-path.");
+ goto out;
+ }
+
pc_dimm_memory_plug(dev, &ms->hotplug_memory, mr, align, &local_err);
if (local_err) {
goto out;
@@ -2488,6 +2506,165 @@ void *spapr_populate_hotplug_cpu_dt(CPUState *cs, int *fdt_offset,
return fdt;
}
+static void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp)
+{
+ MachineState *ms = MACHINE(qdev_get_machine());
+ CPUCore *cc = CPU_CORE(dev);
+ CPUArchId *core_slot = spapr_find_cpu_slot(ms, cc->core_id, NULL);
+
+ core_slot->cpu = NULL;
+ object_unparent(OBJECT(dev));
+}
+
+static void spapr_core_release(DeviceState *dev, void *opaque)
+{
+ HotplugHandler *hotplug_ctrl;
+
+ hotplug_ctrl = qdev_get_hotplug_handler(dev);
+ hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
+}
+
+static
+void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp)
+{
+ int index;
+ sPAPRDRConnector *drc;
+ sPAPRDRConnectorClass *drck;
+ Error *local_err = NULL;
+ CPUCore *cc = CPU_CORE(dev);
+ int smt = kvmppc_smt_threads();
+
+ if (!spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index)) {
+ error_setg(errp, "Unable to find CPU core with core-id: %d",
+ cc->core_id);
+ return;
+ }
+ if (index == 0) {
+ error_setg(errp, "Boot CPU core may not be unplugged");
+ return;
+ }
+
+ drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_CPU, index * smt);
+ g_assert(drc);
+
+ drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+ drck->detach(drc, dev, spapr_core_release, NULL, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ spapr_hotplug_req_remove_by_index(drc);
+}
+
+static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp)
+{
+ sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
+ MachineClass *mc = MACHINE_GET_CLASS(spapr);
+ sPAPRCPUCore *core = SPAPR_CPU_CORE(OBJECT(dev));
+ CPUCore *cc = CPU_CORE(dev);
+ CPUState *cs = CPU(core->threads);
+ sPAPRDRConnector *drc;
+ Error *local_err = NULL;
+ void *fdt = NULL;
+ int fdt_offset = 0;
+ int smt = kvmppc_smt_threads();
+ CPUArchId *core_slot;
+ int index;
+
+ core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
+ if (!core_slot) {
+ error_setg(errp, "Unable to find CPU core with core-id: %d",
+ cc->core_id);
+ return;
+ }
+ drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_CPU, index * smt);
+
+ g_assert(drc || !mc->has_hotpluggable_cpus);
+
+ /*
+ * Setup CPU DT entries only for hotplugged CPUs. For boot time or
+ * coldplugged CPUs DT entries are setup in spapr_build_fdt().
+ */
+ if (dev->hotplugged) {
+ fdt = spapr_populate_hotplug_cpu_dt(cs, &fdt_offset, spapr);
+ }
+
+ if (drc) {
+ sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+ drck->attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, &local_err);
+ if (local_err) {
+ g_free(fdt);
+ error_propagate(errp, local_err);
+ return;
+ }
+ }
+
+ if (dev->hotplugged) {
+ /*
+ * Send hotplug notification interrupt to the guest only in case
+ * of hotplugged CPUs.
+ */
+ spapr_hotplug_req_add_by_index(drc);
+ } else {
+ /*
+ * Set the right DRC states for cold plugged CPU.
+ */
+ if (drc) {
+ sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+ drck->set_allocation_state(drc, SPAPR_DR_ALLOCATION_STATE_USABLE);
+ drck->set_isolation_state(drc, SPAPR_DR_ISOLATION_STATE_UNISOLATED);
+ }
+ }
+ core_slot->cpu = OBJECT(dev);
+}
+
+static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp)
+{
+ MachineState *machine = MACHINE(OBJECT(hotplug_dev));
+ MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev);
+ Error *local_err = NULL;
+ CPUCore *cc = CPU_CORE(dev);
+ char *base_core_type = spapr_get_cpu_core_type(machine->cpu_model);
+ const char *type = object_get_typename(OBJECT(dev));
+ CPUArchId *core_slot;
+ int index;
+
+ if (dev->hotplugged && !mc->has_hotpluggable_cpus) {
+ error_setg(&local_err, "CPU hotplug not supported for this machine");
+ goto out;
+ }
+
+ if (strcmp(base_core_type, type)) {
+ error_setg(&local_err, "CPU core type should be %s", base_core_type);
+ goto out;
+ }
+
+ if (cc->core_id % smp_threads) {
+ error_setg(&local_err, "invalid core id %d", cc->core_id);
+ goto out;
+ }
+
+ core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
+ if (!core_slot) {
+ error_setg(&local_err, "core id %d out of range", cc->core_id);
+ goto out;
+ }
+
+ if (core_slot->cpu) {
+ error_setg(&local_err, "core %d already populated", cc->core_id);
+ goto out;
+ }
+
+out:
+ g_free(base_core_type);
+ error_propagate(errp, local_err);
+}
+
static void spapr_machine_device_plug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
@@ -2550,7 +2727,7 @@ static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev,
error_setg(errp, "Memory hot unplug not supported for this guest");
}
} else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
- if (!mc->query_hotpluggable_cpus) {
+ if (!mc->has_hotpluggable_cpus) {
error_setg(errp, "CPU hot unplug not supported on this machine");
return;
}
@@ -2577,11 +2754,11 @@ static void spapr_machine_device_unplug_request(HotplugHandler *hotplug_dev,
error_setg(errp, "Memory hot unplug not supported for this guest");
}
} else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
- if (!mc->query_hotpluggable_cpus) {
+ if (!mc->has_hotpluggable_cpus) {
error_setg(errp, "CPU hot unplug not supported on this machine");
return;
}
- spapr_core_unplug(hotplug_dev, dev, errp);
+ spapr_core_unplug_request(hotplug_dev, dev, errp);
}
}
@@ -2610,35 +2787,34 @@ static unsigned spapr_cpu_index_to_socket_id(unsigned cpu_index)
return cpu_index / smp_threads / smp_cores;
}
-static HotpluggableCPUList *spapr_query_hotpluggable_cpus(MachineState *machine)
+static const CPUArchIdList *spapr_possible_cpu_arch_ids(MachineState *machine)
{
int i;
- HotpluggableCPUList *head = NULL;
- sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
int spapr_max_cores = max_cpus / smp_threads;
+ MachineClass *mc = MACHINE_GET_CLASS(machine);
- for (i = 0; i < spapr_max_cores; i++) {
- HotpluggableCPUList *list_item = g_new0(typeof(*list_item), 1);
- HotpluggableCPU *cpu_item = g_new0(typeof(*cpu_item), 1);
- CpuInstanceProperties *cpu_props = g_new0(typeof(*cpu_props), 1);
+ if (!mc->has_hotpluggable_cpus) {
+ spapr_max_cores = QEMU_ALIGN_UP(smp_cpus, smp_threads) / smp_threads;
+ }
+ if (machine->possible_cpus) {
+ assert(machine->possible_cpus->len == spapr_max_cores);
+ return machine->possible_cpus;
+ }
+
+ machine->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
+ sizeof(CPUArchId) * spapr_max_cores);
+ machine->possible_cpus->len = spapr_max_cores;
+ for (i = 0; i < machine->possible_cpus->len; i++) {
+ int core_id = i * smp_threads;
- cpu_item->type = spapr_get_cpu_core_type(machine->cpu_model);
- cpu_item->vcpus_count = smp_threads;
- cpu_props->has_core_id = true;
- cpu_props->core_id = i * smp_threads;
+ machine->possible_cpus->cpus[i].vcpus_count = smp_threads;
+ machine->possible_cpus->cpus[i].arch_id = core_id;
+ machine->possible_cpus->cpus[i].props.has_core_id = true;
+ machine->possible_cpus->cpus[i].props.core_id = core_id;
/* TODO: add 'has_node/node' here to describe
to which node core belongs */
-
- cpu_item->props = cpu_props;
- if (spapr->cores[i]) {
- cpu_item->has_qom_path = true;
- cpu_item->qom_path = object_get_canonical_path(spapr->cores[i]);
- }
- list_item->value = cpu_item;
- list_item->next = head;
- head = list_item;
}
- return head;
+ return machine->possible_cpus;
}
static void spapr_phb_placement(sPAPRMachineState *spapr, uint32_t index,
@@ -2724,11 +2900,12 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
hc->plug = spapr_machine_device_plug;
hc->unplug = spapr_machine_device_unplug;
mc->cpu_index_to_socket_id = spapr_cpu_index_to_socket_id;
+ mc->possible_cpu_arch_ids = spapr_possible_cpu_arch_ids;
hc->unplug_request = spapr_machine_device_unplug_request;
smc->dr_lmb_enabled = true;
smc->tcg_default_cpu = "POWER8";
- mc->query_hotpluggable_cpus = spapr_query_hotpluggable_cpus;
+ mc->has_hotpluggable_cpus = true;
fwc->get_dev_path = spapr_get_fw_dev_path;
nc->nmi_monitor_handler = spapr_nmi;
smc->phb_placement = spapr_phb_placement;
@@ -2928,7 +3105,7 @@ static void spapr_machine_2_6_instance_options(MachineState *machine)
static void spapr_machine_2_6_class_options(MachineClass *mc)
{
spapr_machine_2_7_class_options(mc);
- mc->query_hotpluggable_cpus = NULL;
+ mc->has_hotpluggable_cpus = false;
SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_6);
}
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 9dddaeb3fa..55cd0456eb 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -109,13 +109,12 @@ char *spapr_get_cpu_core_type(const char *model)
return core_type;
}
-static void spapr_core_release(DeviceState *dev, void *opaque)
+static void spapr_cpu_core_unrealizefn(DeviceState *dev, Error **errp)
{
sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev));
const char *typename = object_class_get_name(scc->cpu_class);
size_t size = object_type_get_instance_size(typename);
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
CPUCore *cc = CPU_CORE(dev);
int i;
@@ -129,140 +128,7 @@ static void spapr_core_release(DeviceState *dev, void *opaque)
cpu_remove_sync(cs);
object_unparent(obj);
}
-
- spapr->cores[cc->core_id / smp_threads] = NULL;
-
g_free(sc->threads);
- object_unparent(OBJECT(dev));
-}
-
-void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
- Error **errp)
-{
- CPUCore *cc = CPU_CORE(dev);
- int smt = kvmppc_smt_threads();
- int index = cc->core_id / smp_threads;
- sPAPRDRConnector *drc =
- spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_CPU, index * smt);
- sPAPRDRConnectorClass *drck;
- Error *local_err = NULL;
-
- if (index == 0) {
- error_setg(errp, "Boot CPU core may not be unplugged");
- return;
- }
-
- g_assert(drc);
-
- drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- drck->detach(drc, dev, spapr_core_release, NULL, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- spapr_hotplug_req_remove_by_index(drc);
-}
-
-void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
- Error **errp)
-{
- sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
- MachineClass *mc = MACHINE_GET_CLASS(spapr);
- sPAPRCPUCore *core = SPAPR_CPU_CORE(OBJECT(dev));
- CPUCore *cc = CPU_CORE(dev);
- CPUState *cs = CPU(core->threads);
- sPAPRDRConnector *drc;
- Error *local_err = NULL;
- void *fdt = NULL;
- int fdt_offset = 0;
- int index = cc->core_id / smp_threads;
- int smt = kvmppc_smt_threads();
-
- drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_CPU, index * smt);
- spapr->cores[index] = OBJECT(dev);
-
- g_assert(drc || !mc->query_hotpluggable_cpus);
-
- /*
- * Setup CPU DT entries only for hotplugged CPUs. For boot time or
- * coldplugged CPUs DT entries are setup in spapr_build_fdt().
- */
- if (dev->hotplugged) {
- fdt = spapr_populate_hotplug_cpu_dt(cs, &fdt_offset, spapr);
- }
-
- if (drc) {
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- drck->attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, &local_err);
- if (local_err) {
- g_free(fdt);
- spapr->cores[index] = NULL;
- error_propagate(errp, local_err);
- return;
- }
- }
-
- if (dev->hotplugged) {
- /*
- * Send hotplug notification interrupt to the guest only in case
- * of hotplugged CPUs.
- */
- spapr_hotplug_req_add_by_index(drc);
- } else {
- /*
- * Set the right DRC states for cold plugged CPU.
- */
- if (drc) {
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- drck->set_allocation_state(drc, SPAPR_DR_ALLOCATION_STATE_USABLE);
- drck->set_isolation_state(drc, SPAPR_DR_ISOLATION_STATE_UNISOLATED);
- }
- }
-}
-
-void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
- Error **errp)
-{
- MachineState *machine = MACHINE(OBJECT(hotplug_dev));
- MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev);
- sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
- int spapr_max_cores = max_cpus / smp_threads;
- int index;
- Error *local_err = NULL;
- CPUCore *cc = CPU_CORE(dev);
- char *base_core_type = spapr_get_cpu_core_type(machine->cpu_model);
- const char *type = object_get_typename(OBJECT(dev));
-
- if (dev->hotplugged && !mc->query_hotpluggable_cpus) {
- error_setg(&local_err, "CPU hotplug not supported for this machine");
- goto out;
- }
-
- if (strcmp(base_core_type, type)) {
- error_setg(&local_err, "CPU core type should be %s", base_core_type);
- goto out;
- }
-
- if (cc->core_id % smp_threads) {
- error_setg(&local_err, "invalid core id %d", cc->core_id);
- goto out;
- }
-
- index = cc->core_id / smp_threads;
- if (index < 0 || index >= spapr_max_cores) {
- error_setg(&local_err, "core id %d out of range", cc->core_id);
- goto out;
- }
-
- if (spapr->cores[index]) {
- error_setg(&local_err, "core %d already populated", cc->core_id);
- goto out;
- }
-
-out:
- g_free(base_core_type);
- error_propagate(errp, local_err);
}
static void spapr_cpu_core_realize_child(Object *child, Error **errp)
@@ -368,6 +234,7 @@ void spapr_cpu_core_class_init(ObjectClass *oc, void *data)
sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_CLASS(oc);
dc->realize = spapr_cpu_core_realize;
+ dc->unrealize = spapr_cpu_core_unrealizefn;
scc->cpu_class = cpu_class_by_name(TYPE_POWERPC_CPU, data);
g_assert(scc->cpu_class);
}
diff --git a/hw/ppc/spapr_ovec.c b/hw/ppc/spapr_ovec.c
index 3eb1d5976f..41df4c35ba 100644
--- a/hw/ppc/spapr_ovec.c
+++ b/hw/ppc/spapr_ovec.c
@@ -16,18 +16,9 @@
#include "qemu/bitmap.h"
#include "exec/address-spaces.h"
#include "qemu/error-report.h"
+#include "trace.h"
#include <libfdt.h>
-/* #define DEBUG_SPAPR_OVEC */
-
-#ifdef DEBUG_SPAPR_OVEC
-#define DPRINTFN(fmt, ...) \
- do { fprintf(stderr, fmt "\n", ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTFN(fmt, ...) \
- do { } while (0)
-#endif
-
#define OV_MAXBYTES 256 /* not including length byte */
#define OV_MAXBITS (OV_MAXBYTES * BITS_PER_BYTE)
@@ -210,8 +201,7 @@ sPAPROptionVector *spapr_ovec_parse_vector(target_ulong table_addr, int vector)
for (i = 0; i < vector_len; i++) {
uint8_t entry = ldub_phys(&address_space_memory, addr + i);
if (entry) {
- DPRINTFN("read guest vector %2d, byte %3d / %3d: 0x%.2x",
- vector, i + 1, vector_len, entry);
+ trace_spapr_ovec_parse_vector(vector, i + 1, vector_len, entry);
guest_byte_to_bitmap(entry, ov->bitmap, i * BITS_PER_BYTE);
}
}
@@ -245,10 +235,9 @@ int spapr_ovec_populate_dt(void *fdt, int fdt_offset,
for (i = 1; i < vec_len + 1; i++) {
vec[i] = guest_byte_from_bitmap(ov->bitmap, (i - 1) * BITS_PER_BYTE);
if (vec[i]) {
- DPRINTFN("encoding guest vector byte %3d / %3d: 0x%.2x",
- i, vec_len, vec[i]);
+ trace_spapr_ovec_populate_dt(i, vec_len, vec[i]);
}
}
- return fdt_setprop(fdt, fdt_offset, name, vec, vec_len);
+ return fdt_setprop(fdt, fdt_offset, name, vec, vec_len + 1);
}
diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events
index f46995cdb2..43d265f351 100644
--- a/hw/ppc/trace-events
+++ b/hw/ppc/trace-events
@@ -56,6 +56,10 @@ spapr_drc_realize_child(uint32_t index, char *childname) "drc: 0x%"PRIx32", chil
spapr_drc_realize_complete(uint32_t index) "drc: 0x%"PRIx32
spapr_drc_unrealize(uint32_t index) "drc: 0x%"PRIx32
+# hw/ppc/spapr_ovec.c
+spapr_ovec_parse_vector(int vector, int byte, uint16_t vec_len, uint8_t entry) "read guest vector %2d, byte %3d / %3d: 0x%.2x"
+spapr_ovec_populate_dt(int byte, uint16_t vec_len, uint8_t entry) "encoding guest vector byte %3d / %3d: 0x%.2x"
+
# hw/ppc/spapr_rtas.c
spapr_rtas_set_indicator_invalid(uint32_t index) "sensor index: 0x%"PRIx32
spapr_rtas_set_indicator_not_supported(uint32_t index, uint32_t type) "sensor index: 0x%"PRIx32", type: %"PRIu32
@@ -85,3 +89,11 @@ rs6000mc_presence_read(uint32_t addr, uint32_t val) "read addr=%x val=%x"
rs6000mc_size_read(uint32_t addr, uint32_t val) "read addr=%x val=%x"
rs6000mc_size_write(uint32_t addr, uint32_t val) "write addr=%x val=%x"
rs6000mc_parity_read(uint32_t addr, uint32_t val) "read addr=%x val=%x"
+
+# hw/ppc/mac_newworld.c
+mac99_uninorth_write(uint64_t addr, uint64_t value) "addr=0x%" PRIx64 " val=0x%"PRIx64
+mac99_uninorth_read(uint64_t addr, uint64_t value) "addr=0x%" PRIx64 " val=0x%"PRIx64
+
+# hw/ppc/ppc4xx_pci.c
+ppc4xx_pci_map_irq(int32_t devfn, int irq_num, int slot) "devfn %x irq %d -> %d"
+ppc4xx_pci_set_irq(int irq_num) "PCI irq %d"
diff --git a/hw/usb/bus.c b/hw/usb/bus.c
index 1dcc35c8f8..efe4b8e1a6 100644
--- a/hw/usb/bus.c
+++ b/hw/usb/bus.c
@@ -136,11 +136,12 @@ USBDevice *usb_device_find_device(USBDevice *dev, uint8_t addr)
return NULL;
}
-static void usb_device_handle_destroy(USBDevice *dev)
+static void usb_device_unrealize(USBDevice *dev, Error **errp)
{
USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
- if (klass->handle_destroy) {
- klass->handle_destroy(dev);
+
+ if (klass->unrealize) {
+ klass->unrealize(dev, errp);
}
}
@@ -291,7 +292,7 @@ static void usb_qdev_unrealize(DeviceState *qdev, Error **errp)
if (dev->attached) {
usb_device_detach(dev);
}
- usb_device_handle_destroy(dev);
+ usb_device_unrealize(dev, errp);
if (dev->port) {
usb_release_port(dev);
}
diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c
index 87cab0a3d1..343345235c 100644
--- a/hw/usb/dev-audio.c
+++ b/hw/usb/dev-audio.c
@@ -617,7 +617,7 @@ static void usb_audio_handle_data(USBDevice *dev, USBPacket *p)
}
}
-static void usb_audio_handle_destroy(USBDevice *dev)
+static void usb_audio_unrealize(USBDevice *dev, Error **errp)
{
USBAudioState *s = USB_AUDIO(dev);
@@ -683,7 +683,7 @@ static void usb_audio_class_init(ObjectClass *klass, void *data)
k->handle_reset = usb_audio_handle_reset;
k->handle_control = usb_audio_handle_control;
k->handle_data = usb_audio_handle_data;
- k->handle_destroy = usb_audio_handle_destroy;
+ k->unrealize = usb_audio_unrealize;
k->set_interface = usb_audio_set_interface;
}
diff --git a/hw/usb/dev-bluetooth.c b/hw/usb/dev-bluetooth.c
index 91a4a0b8b9..443e3c301d 100644
--- a/hw/usb/dev-bluetooth.c
+++ b/hw/usb/dev-bluetooth.c
@@ -496,7 +496,7 @@ static void usb_bt_out_hci_packet_acl(void *opaque,
usb_bt_fifo_enqueue(&s->acl, data, len);
}
-static void usb_bt_handle_destroy(USBDevice *dev)
+static void usb_bt_unrealize(USBDevice *dev, Error **errp)
{
struct USBBtState *s = (struct USBBtState *) dev->opaque;
@@ -559,7 +559,7 @@ static void usb_bt_class_initfn(ObjectClass *klass, void *data)
uc->handle_reset = usb_bt_handle_reset;
uc->handle_control = usb_bt_handle_control;
uc->handle_data = usb_bt_handle_data;
- uc->handle_destroy = usb_bt_handle_destroy;
+ uc->unrealize = usb_bt_unrealize;
dc->vmsd = &vmstate_usb_bt;
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
}
diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c
index dda0bf0df0..c40019df96 100644
--- a/hw/usb/dev-hid.c
+++ b/hw/usb/dev-hid.c
@@ -690,7 +690,7 @@ static void usb_hid_handle_data(USBDevice *dev, USBPacket *p)
}
}
-static void usb_hid_handle_destroy(USBDevice *dev)
+static void usb_hid_unrealize(USBDevice *dev, Error **errp)
{
USBHIDState *us = USB_HID(dev);
@@ -785,7 +785,7 @@ static void usb_hid_class_initfn(ObjectClass *klass, void *data)
uc->handle_reset = usb_hid_handle_reset;
uc->handle_control = usb_hid_handle_control;
uc->handle_data = usb_hid_handle_data;
- uc->handle_destroy = usb_hid_handle_destroy;
+ uc->unrealize = usb_hid_unrealize;
uc->handle_attach = usb_desc_attach;
}
diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c
index a33f21cb38..9fe7333946 100644
--- a/hw/usb/dev-hub.c
+++ b/hw/usb/dev-hub.c
@@ -497,7 +497,7 @@ static void usb_hub_handle_data(USBDevice *dev, USBPacket *p)
}
}
-static void usb_hub_handle_destroy(USBDevice *dev)
+static void usb_hub_unrealize(USBDevice *dev, Error **errp)
{
USBHubState *s = (USBHubState *)dev;
int i;
@@ -575,7 +575,7 @@ static void usb_hub_class_initfn(ObjectClass *klass, void *data)
uc->handle_reset = usb_hub_handle_reset;
uc->handle_control = usb_hub_handle_control;
uc->handle_data = usb_hub_handle_data;
- uc->handle_destroy = usb_hub_handle_destroy;
+ uc->unrealize = usb_hub_unrealize;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->fw_name = "hub";
dc->vmsd = &vmstate_usb_hub;
diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c
index c0f1193ba9..85fc81bf43 100644
--- a/hw/usb/dev-network.c
+++ b/hw/usb/dev-network.c
@@ -1324,7 +1324,7 @@ static void usbnet_cleanup(NetClientState *nc)
s->nic = NULL;
}
-static void usb_net_handle_destroy(USBDevice *dev)
+static void usb_net_unrealize(USBDevice *dev, Error **errp)
{
USBNetState *s = (USBNetState *) dev;
@@ -1428,7 +1428,7 @@ static void usb_net_class_initfn(ObjectClass *klass, void *data)
uc->handle_reset = usb_net_handle_reset;
uc->handle_control = usb_net_handle_control;
uc->handle_data = usb_net_handle_data;
- uc->handle_destroy = usb_net_handle_destroy;
+ uc->unrealize = usb_net_unrealize;
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->fw_name = "network";
dc->vmsd = &vmstate_usb_net;
diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c
index 7cd4ed0d17..757b8b3f5a 100644
--- a/hw/usb/dev-smartcard-reader.c
+++ b/hw/usb/dev-smartcard-reader.c
@@ -1163,7 +1163,7 @@ static void ccid_handle_data(USBDevice *dev, USBPacket *p)
}
}
-static void ccid_handle_destroy(USBDevice *dev)
+static void ccid_unrealize(USBDevice *dev, Error **errp)
{
USBCCIDState *s = USB_CCID_DEV(dev);
@@ -1470,7 +1470,7 @@ static void ccid_class_initfn(ObjectClass *klass, void *data)
uc->handle_reset = ccid_handle_reset;
uc->handle_control = ccid_handle_control;
uc->handle_data = ccid_handle_data;
- uc->handle_destroy = ccid_handle_destroy;
+ uc->unrealize = ccid_unrealize;
dc->desc = "CCID Rev 1.1 smartcard reader";
dc->vmsd = &ccid_vmstate;
dc->props = ccid_properties;
diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c
index da2fb7017e..3b26655889 100644
--- a/hw/usb/dev-uas.c
+++ b/hw/usb/dev-uas.c
@@ -891,7 +891,7 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p)
}
}
-static void usb_uas_handle_destroy(USBDevice *dev)
+static void usb_uas_unrealize(USBDevice *dev, Error **errp)
{
UASDevice *uas = USB_UAS(dev);
@@ -944,7 +944,7 @@ static void usb_uas_class_initfn(ObjectClass *klass, void *data)
uc->handle_reset = usb_uas_handle_reset;
uc->handle_control = usb_uas_handle_control;
uc->handle_data = usb_uas_handle_data;
- uc->handle_destroy = usb_uas_handle_destroy;
+ uc->unrealize = usb_uas_unrealize;
uc->attached_settable = true;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
dc->fw_name = "storage";
diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c
index c4702dbba0..bf70013059 100644
--- a/hw/usb/dev-wacom.c
+++ b/hw/usb/dev-wacom.c
@@ -329,7 +329,7 @@ static void usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
}
}
-static void usb_wacom_handle_destroy(USBDevice *dev)
+static void usb_wacom_unrealize(USBDevice *dev, Error **errp)
{
USBWacomState *s = (USBWacomState *) dev;
@@ -364,7 +364,7 @@ static void usb_wacom_class_init(ObjectClass *klass, void *data)
uc->handle_reset = usb_wacom_handle_reset;
uc->handle_control = usb_wacom_handle_control;
uc->handle_data = usb_wacom_handle_data;
- uc->handle_destroy = usb_wacom_handle_destroy;
+ uc->unrealize = usb_wacom_unrealize;
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
dc->desc = "QEMU PenPartner Tablet";
dc->vmsd = &vmstate_usb_wacom;
diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c
index 21c93e0372..fe8406ac64 100644
--- a/hw/usb/hcd-ohci.c
+++ b/hw/usb/hcd-ohci.c
@@ -1001,7 +1001,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
if (ohci_read_td(ohci, addr, &td)) {
trace_usb_ohci_td_read_error(addr);
ohci_die(ohci);
- return 0;
+ return 1;
}
dir = OHCI_BM(ed->flags, ED_D);
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 28dd2f2c9a..f0af852709 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -635,6 +635,11 @@ static bool xhci_get_flag(XHCIState *xhci, enum xhci_flags bit)
return xhci->flags & (1 << bit);
}
+static void xhci_set_flag(XHCIState *xhci, enum xhci_flags bit)
+{
+ xhci->flags |= (1 << bit);
+}
+
static uint64_t xhci_mfindex_get(XHCIState *xhci)
{
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
@@ -3839,17 +3844,21 @@ static const VMStateDescription vmstate_xhci = {
}
};
-static Property xhci_properties[] = {
+static Property nec_xhci_properties[] = {
DEFINE_PROP_ON_OFF_AUTO("msi", XHCIState, msi, ON_OFF_AUTO_AUTO),
DEFINE_PROP_ON_OFF_AUTO("msix", XHCIState, msix, ON_OFF_AUTO_AUTO),
DEFINE_PROP_BIT("superspeed-ports-first",
XHCIState, flags, XHCI_FLAG_SS_FIRST, true),
DEFINE_PROP_BIT("force-pcie-endcap", XHCIState, flags,
XHCI_FLAG_FORCE_PCIE_ENDCAP, false),
- DEFINE_PROP_BIT("streams", XHCIState, flags,
- XHCI_FLAG_ENABLE_STREAMS, true),
DEFINE_PROP_UINT32("intrs", XHCIState, numintrs, MAXINTRS),
DEFINE_PROP_UINT32("slots", XHCIState, numslots, MAXSLOTS),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static Property xhci_properties[] = {
+ DEFINE_PROP_BIT("streams", XHCIState, flags,
+ XHCI_FLAG_ENABLE_STREAMS, true),
DEFINE_PROP_UINT32("p2", XHCIState, numports_2, 4),
DEFINE_PROP_UINT32("p3", XHCIState, numports_3, 4),
DEFINE_PROP_END_OF_LIST(),
@@ -3881,7 +3890,9 @@ static const TypeInfo xhci_info = {
static void nec_xhci_class_init(ObjectClass *klass, void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ dc->props = nec_xhci_properties;
k->vendor_id = PCI_VENDOR_ID_NEC;
k->device_id = PCI_DEVICE_ID_NEC_UPD720200;
k->revision = 0x03;
@@ -3902,10 +3913,22 @@ static void qemu_xhci_class_init(ObjectClass *klass, void *data)
k->revision = 0x01;
}
+static void qemu_xhci_instance_init(Object *obj)
+{
+ XHCIState *xhci = XHCI(obj);
+
+ xhci->msi = ON_OFF_AUTO_OFF;
+ xhci->msix = ON_OFF_AUTO_AUTO;
+ xhci->numintrs = MAXINTRS;
+ xhci->numslots = MAXSLOTS;
+ xhci_set_flag(xhci, XHCI_FLAG_SS_FIRST);
+}
+
static const TypeInfo qemu_xhci_info = {
.name = TYPE_QEMU_XHCI,
.parent = TYPE_XHCI,
.class_init = qemu_xhci_class_init,
+ .instance_init = qemu_xhci_instance_init,
};
static void xhci_register_types(void)
diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c
index 7791c6d520..c9876a5b0f 100644
--- a/hw/usb/host-libusb.c
+++ b/hw/usb/host-libusb.c
@@ -1065,7 +1065,7 @@ static void usb_host_instance_init(Object *obj)
&udev->qdev, NULL);
}
-static void usb_host_handle_destroy(USBDevice *udev)
+static void usb_host_unrealize(USBDevice *udev, Error **errp)
{
USBHostDevice *s = USB_HOST_DEVICE(udev);
@@ -1568,7 +1568,7 @@ static void usb_host_class_initfn(ObjectClass *klass, void *data)
uc->handle_data = usb_host_handle_data;
uc->handle_control = usb_host_handle_control;
uc->handle_reset = usb_host_handle_reset;
- uc->handle_destroy = usb_host_handle_destroy;
+ uc->unrealize = usb_host_unrealize;
uc->flush_ep_queue = usb_host_flush_ep_queue;
uc->alloc_streams = usb_host_alloc_streams;
uc->free_streams = usb_host_free_streams;
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 860f5c35eb..0efe62f725 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -1427,7 +1427,7 @@ static void usbredir_cleanup_device_queues(USBRedirDevice *dev)
}
}
-static void usbredir_handle_destroy(USBDevice *udev)
+static void usbredir_unrealize(USBDevice *udev, Error **errp)
{
USBRedirDevice *dev = USB_REDIRECT(udev);
Chardev *chr = qemu_chr_fe_get_driver(&dev->cs);
@@ -2513,7 +2513,7 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data)
uc->realize = usbredir_realize;
uc->product_desc = "USB Redirection Device";
- uc->handle_destroy = usbredir_handle_destroy;
+ uc->unrealize = usbredir_unrealize;
uc->cancel_packet = usbredir_cancel_packet;
uc->handle_reset = usbredir_handle_reset;
uc->handle_data = usbredir_handle_data;
diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c
index e9b493b939..e995e32dee 100644
--- a/hw/vfio/pci-quirks.c
+++ b/hw/vfio/pci-quirks.c
@@ -1367,14 +1367,45 @@ static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
uint16_t cmd_orig, cmd;
Error *err = NULL;
+ /* This must be an Intel VGA device. */
+ if (!vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, PCI_ANY_ID) ||
+ !vfio_is_vga(vdev) || nr != 4) {
+ return;
+ }
+
/*
- * This must be an Intel VGA device at address 00:02.0 for us to even
- * consider enabling legacy mode. The vBIOS has dependencies on the
- * PCI bus address.
+ * IGD is not a standard, they like to change their specs often. We
+ * only attempt to support back to SandBridge and we hope that newer
+ * devices maintain compatibility with generation 8.
*/
- if (!vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, PCI_ANY_ID) ||
- !vfio_is_vga(vdev) || nr != 4 ||
- &vdev->pdev != pci_find_device(pci_device_root_bus(&vdev->pdev),
+ gen = igd_gen(vdev);
+ if (gen != 6 && gen != 8) {
+ error_report("IGD device %s is unsupported by IGD quirks, "
+ "try SandyBridge or newer", vdev->vbasedev.name);
+ return;
+ }
+
+ /*
+ * Regardless of running in UPT or legacy mode, the guest graphics
+ * driver may attempt to use stolen memory, however only legacy mode
+ * has BIOS support for reserving stolen memory in the guest VM.
+ * Emulate the GMCH register in all cases and zero out the stolen
+ * memory size here. Legacy mode may request allocation and re-write
+ * this below.
+ */
+ gmch = vfio_pci_read_config(&vdev->pdev, IGD_GMCH, 4);
+ gmch &= ~((gen < 8 ? 0x1f : 0xff) << (gen < 8 ? 3 : 8));
+
+ /* GMCH is read-only, emulated */
+ pci_set_long(vdev->pdev.config + IGD_GMCH, gmch);
+ pci_set_long(vdev->pdev.wmask + IGD_GMCH, 0);
+ pci_set_long(vdev->emulated_config_bits + IGD_GMCH, ~0);
+
+ /*
+ * This must be at address 00:02.0 for us to even onsider enabling
+ * legacy mode. The vBIOS has dependencies on the PCI bus address.
+ */
+ if (&vdev->pdev != pci_find_device(pci_device_root_bus(&vdev->pdev),
0, PCI_DEVFN(0x2, 0))) {
return;
}
@@ -1394,18 +1425,6 @@ static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
}
/*
- * IGD is not a standard, they like to change their specs often. We
- * only attempt to support back to SandBridge and we hope that newer
- * devices maintain compatibility with generation 8.
- */
- gen = igd_gen(vdev);
- if (gen != 6 && gen != 8) {
- error_report("IGD device %s is unsupported in legacy mode, "
- "try SandyBridge or newer", vdev->vbasedev.name);
- return;
- }
-
- /*
* Most of what we're doing here is to enable the ROM to run, so if
* there's no ROM, there's no point in setting up this quirk.
* NB. We only seem to get BIOS ROMs, so a UEFI VM would need CSM support.
@@ -1460,8 +1479,6 @@ static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
goto out;
}
- gmch = vfio_pci_read_config(&vdev->pdev, IGD_GMCH, 4);
-
/*
* If IGD VGA Disable is clear (expected) and VGA is not already enabled,
* try to enable it. Probably shouldn't be using legacy mode without VGA,
@@ -1532,12 +1549,11 @@ static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
* when IVD (IGD VGA Disable) is clear, but the claim is that it's unused,
* so let's not waste VM memory for it.
*/
- gmch &= ~((gen < 8 ? 0x1f : 0xff) << (gen < 8 ? 3 : 8));
-
if (vdev->igd_gms) {
if (vdev->igd_gms <= 0x10) {
gms_mb = vdev->igd_gms * 32;
gmch |= vdev->igd_gms << (gen < 8 ? 3 : 8);
+ pci_set_long(vdev->pdev.config + IGD_GMCH, gmch);
} else {
error_report("Unsupported IGD GMS value 0x%x", vdev->igd_gms);
vdev->igd_gms = 0;
@@ -1557,11 +1573,6 @@ static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
fw_cfg_add_file(fw_cfg_find(), "etc/igd-bdsm-size",
bdsm_size, sizeof(*bdsm_size));
- /* GMCH is read-only, emulated */
- pci_set_long(vdev->pdev.config + IGD_GMCH, gmch);
- pci_set_long(vdev->pdev.wmask + IGD_GMCH, 0);
- pci_set_long(vdev->emulated_config_bits + IGD_GMCH, ~0);
-
/* BDSM is read-write, emulated. The BIOS needs to be able to write it */
pci_set_long(vdev->pdev.config + IGD_BDSM, 0);
pci_set_long(vdev->pdev.wmask + IGD_BDSM, ~0);
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 332f41d662..03a3d01549 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -1880,16 +1880,26 @@ static void vfio_add_ext_cap(VFIOPCIDevice *vdev)
/*
* Extended capabilities are chained with each pointing to the next, so we
* can drop anything other than the head of the chain simply by modifying
- * the previous next pointer. For the head of the chain, we can modify the
- * capability ID to something that cannot match a valid capability. ID
- * 0 is reserved for this since absence of capabilities is indicated by
- * 0 for the ID, version, AND next pointer. However, pcie_add_capability()
- * uses ID 0 as reserved for list management and will incorrectly match and
- * assert if we attempt to pre-load the head of the chain with this ID.
- * Use ID 0xFFFF temporarily since it is also seems to be reserved in
- * part for identifying absence of capabilities in a root complex register
- * block. If the ID still exists after adding capabilities, switch back to
- * zero. We'll mark this entire first dword as emulated for this purpose.
+ * the previous next pointer. Seed the head of the chain here such that
+ * we can simply skip any capabilities we want to drop below, regardless
+ * of their position in the chain. If this stub capability still exists
+ * after we add the capabilities we want to expose, update the capability
+ * ID to zero. Note that we cannot seed with the capability header being
+ * zero as this conflicts with definition of an absent capability chain
+ * and prevents capabilities beyond the head of the list from being added.
+ * By replacing the dummy capability ID with zero after walking the device
+ * chain, we also transparently mark extended capabilities as absent if
+ * no capabilities were added. Note that the PCIe spec defines an absence
+ * of extended capabilities to be determined by a value of zero for the
+ * capability ID, version, AND next pointer. A non-zero next pointer
+ * should be sufficient to indicate additional capabilities are present,
+ * which will occur if we call pcie_add_capability() below. The entire
+ * first dword is emulated to support this.
+ *
+ * NB. The kernel side does similar masking, so be prepared that our
+ * view of the device may also contain a capability ID zero in the head
+ * of the chain. Skip it for the same reason that we cannot seed the
+ * chain with a zero capability.
*/
pci_set_long(pdev->config + PCI_CONFIG_SPACE_SIZE,
PCI_EXT_CAP(0xFFFF, 0, 0));
@@ -1915,6 +1925,7 @@ static void vfio_add_ext_cap(VFIOPCIDevice *vdev)
PCI_EXT_CAP_NEXT_MASK);
switch (cap_id) {
+ case 0: /* kernel masked capability */
case PCI_EXT_CAP_ID_SRIOV: /* Read-only VF BARs confuse OVMF */
case PCI_EXT_CAP_ID_ARI: /* XXX Needs next function virtualization */
trace_vfio_add_ext_cap_dropped(vdev->vbasedev.name, cap_id, next);
@@ -2506,12 +2517,16 @@ static void vfio_unregister_err_notifier(VFIOPCIDevice *vdev)
static void vfio_req_notifier_handler(void *opaque)
{
VFIOPCIDevice *vdev = opaque;
+ Error *err = NULL;
if (!event_notifier_test_and_clear(&vdev->req_notifier)) {
return;
}
- qdev_unplug(&vdev->pdev.qdev, NULL);
+ qdev_unplug(&vdev->pdev.qdev, &err);
+ if (err) {
+ error_reportf_err(err, WARN_PREFIX, vdev->vbasedev.name);
+ }
}
static void vfio_register_req_notifier(VFIOPCIDevice *vdev)
diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h
index 842ec6b22a..f1288efa87 100644
--- a/include/fpu/softfloat.h
+++ b/include/fpu/softfloat.h
@@ -180,6 +180,8 @@ enum {
float_round_up = 2,
float_round_to_zero = 3,
float_round_ties_away = 4,
+ /* Not an IEEE rounding mode: round to the closest odd mantissa value */
+ float_round_to_odd = 5,
};
/*----------------------------------------------------------------------------
@@ -712,6 +714,9 @@ int32_t float128_to_int32(float128, float_status *status);
int32_t float128_to_int32_round_to_zero(float128, float_status *status);
int64_t float128_to_int64(float128, float_status *status);
int64_t float128_to_int64_round_to_zero(float128, float_status *status);
+uint64_t float128_to_uint64(float128, float_status *status);
+uint64_t float128_to_uint64_round_to_zero(float128, float_status *status);
+uint32_t float128_to_uint32_round_to_zero(float128, float_status *status);
float32 float128_to_float32(float128, float_status *status);
float64 float128_to_float64(float128, float_status *status);
floatx80 float128_to_floatx80(float128, float_status *status);
diff --git a/include/hw/boards.h b/include/hw/boards.h
index ac891a828b..269d0ba399 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -41,15 +41,20 @@ int machine_phandle_start(MachineState *machine);
bool machine_dump_guest_core(MachineState *machine);
bool machine_mem_merge(MachineState *machine);
void machine_register_compat_props(MachineState *machine);
+HotpluggableCPUList *machine_query_hotpluggable_cpus(MachineState *machine);
/**
* CPUArchId:
* @arch_id - architecture-dependent CPU ID of present or possible CPU
* @cpu - pointer to corresponding CPU object if it's present on NULL otherwise
+ * @props - CPU object properties, initialized by board
+ * #vcpus_count - number of threads provided by @cpu object
*/
typedef struct {
uint64_t arch_id;
- struct CPUState *cpu;
+ int64_t vcpus_count;
+ CpuInstanceProperties props;
+ Object *cpu;
} CPUArchId;
/**
@@ -82,10 +87,8 @@ typedef struct {
* Returns an array of @CPUArchId architecture-dependent CPU IDs
* which includes CPU IDs for present and possible to hotplug CPUs.
* Caller is responsible for freeing returned list.
- * @query_hotpluggable_cpus:
- * Returns a @HotpluggableCPUList, which describes CPUs objects which
- * could be added with -device/device_add.
- * Caller is responsible for freeing returned list.
+ * @has_hotpluggable_cpus:
+ * If true, board supports CPUs creation with -device/device_add.
* @minimum_page_bits:
* If non-zero, the board promises never to create a CPU with a page size
* smaller than this, so QEMU can use a more efficient larger page
@@ -131,12 +134,12 @@ struct MachineClass {
bool option_rom_has_mr;
bool rom_file_has_mr;
int minimum_page_bits;
+ bool has_hotpluggable_cpus;
HotplugHandler *(*get_hotplug_handler)(MachineState *machine,
DeviceState *dev);
unsigned (*cpu_index_to_socket_id)(unsigned cpu_index);
const CPUArchIdList *(*possible_cpu_arch_ids)(MachineState *machine);
- HotpluggableCPUList *(*query_hotpluggable_cpus)(MachineState *machine);
};
/**
@@ -178,6 +181,7 @@ struct MachineState {
char *initrd_filename;
const char *cpu_model;
AccelState *accelerator;
+ CPUArchIdList *possible_cpus;
};
#define DEFINE_MACHINE(namestr, machine_initfn) \
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 079e8d9393..d1f45540a1 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -73,7 +73,6 @@ struct PCMachineState {
/* CPU and apic information: */
bool apic_xrupt_override;
unsigned apic_id_limit;
- CPUArchIdList *possible_cpus;
uint16_t boot_cpus;
/* NUMA information: */
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index a2d8964f7e..f9b17d860a 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -94,7 +94,6 @@ struct sPAPRMachineState {
/*< public >*/
char *kvm_type;
MemoryHotplugState hotplug_memory;
- Object **cores;
};
#define H_SUCCESS 0
diff --git a/include/hw/ppc/spapr_cpu_core.h b/include/hw/ppc/spapr_cpu_core.h
index 50292f48b1..3c35665221 100644
--- a/include/hw/ppc/spapr_cpu_core.h
+++ b/include/hw/ppc/spapr_cpu_core.h
@@ -34,12 +34,6 @@ typedef struct sPAPRCPUCoreClass {
ObjectClass *cpu_class;
} sPAPRCPUCoreClass;
-void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
- Error **errp);
char *spapr_get_cpu_core_type(const char *model);
-void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
- Error **errp);
-void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
- Error **errp);
void spapr_cpu_core_class_init(ObjectClass *oc, void *data);
#endif
diff --git a/include/hw/usb.h b/include/hw/usb.h
index c42b29c866..eb28655270 100644
--- a/include/hw/usb.h
+++ b/include/hw/usb.h
@@ -291,11 +291,6 @@ typedef struct USBDeviceClass {
void (*cancel_packet)(USBDevice *dev, USBPacket *p);
/*
- * Called when device is destroyed.
- */
- void (*handle_destroy)(USBDevice *dev);
-
- /*
* Attach the device
*/
void (*handle_attach)(USBDevice *dev);
diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h
index 8033929139..f0878eaafa 100644
--- a/include/qemu/cutils.h
+++ b/include/qemu/cutils.h
@@ -130,34 +130,19 @@ int qemu_strtol(const char *nptr, const char **endptr, int base,
long *result);
int qemu_strtoul(const char *nptr, const char **endptr, int base,
unsigned long *result);
-int qemu_strtoll(const char *nptr, const char **endptr, int base,
- int64_t *result);
-int qemu_strtoull(const char *nptr, const char **endptr, int base,
+int qemu_strtoi64(const char *nptr, const char **endptr, int base,
+ int64_t *result);
+int qemu_strtou64(const char *nptr, const char **endptr, int base,
uint64_t *result);
int parse_uint(const char *s, unsigned long long *value, char **endptr,
int base);
int parse_uint_full(const char *s, unsigned long long *value, int base);
-/*
- * qemu_strtosz() suffixes used to specify the default treatment of an
- * argument passed to qemu_strtosz() without an explicit suffix.
- * These should be defined using upper case characters in the range
- * A-Z, as qemu_strtosz() will use qemu_toupper() on the given argument
- * prior to comparison.
- */
-#define QEMU_STRTOSZ_DEFSUFFIX_EB 'E'
-#define QEMU_STRTOSZ_DEFSUFFIX_PB 'P'
-#define QEMU_STRTOSZ_DEFSUFFIX_TB 'T'
-#define QEMU_STRTOSZ_DEFSUFFIX_GB 'G'
-#define QEMU_STRTOSZ_DEFSUFFIX_MB 'M'
-#define QEMU_STRTOSZ_DEFSUFFIX_KB 'K'
-#define QEMU_STRTOSZ_DEFSUFFIX_B 'B'
-int64_t qemu_strtosz(const char *nptr, char **end);
-int64_t qemu_strtosz_suffix(const char *nptr, char **end,
- const char default_suffix);
-int64_t qemu_strtosz_suffix_unit(const char *nptr, char **end,
- const char default_suffix, int64_t unit);
+int qemu_strtosz(const char *nptr, char **end, uint64_t *result);
+int qemu_strtosz_MiB(const char *nptr, char **end, uint64_t *result);
+int qemu_strtosz_metric(const char *nptr, char **end, uint64_t *result);
+
#define K_BYTE (1ULL << 10)
#define M_BYTE (1ULL << 20)
#define G_BYTE (1ULL << 30)
diff --git a/linux-user/main.c b/linux-user/main.c
index 4fd49ce6b6..9645122aa6 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -1712,10 +1712,12 @@ void cpu_loop(CPUPPCState *env)
* in syscalls.
*/
env->crf[0] &= ~0x1;
+ env->nip += 4;
ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
env->gpr[5], env->gpr[6], env->gpr[7],
env->gpr[8], 0, 0);
if (ret == -TARGET_ERESTARTSYS) {
+ env->nip -= 4;
break;
}
if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
@@ -1723,7 +1725,6 @@ void cpu_loop(CPUPPCState *env)
Avoid corrupting register state. */
break;
}
- env->nip += 4;
if (ret > (target_ulong)(-515)) {
env->crf[0] |= 0x1;
ret = -ret;
diff --git a/monitor.c b/monitor.c
index 5953fc984f..f8f4a07cfb 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2799,7 +2799,8 @@ static QDict *monitor_parse_arguments(Monitor *mon,
break;
case 'o':
{
- int64_t val;
+ int ret;
+ uint64_t val;
char *end;
while (qemu_isspace(*p)) {
@@ -2811,8 +2812,8 @@ static QDict *monitor_parse_arguments(Monitor *mon,
break;
}
}
- val = qemu_strtosz(p, &end);
- if (val < 0) {
+ ret = qemu_strtosz_MiB(p, &end, &val);
+ if (ret < 0 || val > INT64_MAX) {
monitor_printf(mon, "invalid size\n");
goto fail;
}
@@ -3712,12 +3713,12 @@ static QDict *qmp_check_input_obj(QObject *input_obj, Error **errp)
int has_exec_key = 0;
QDict *input_dict;
- if (qobject_type(input_obj) != QTYPE_QDICT) {
+ input_dict = qobject_to_qdict(input_obj);
+ if (!input_dict) {
error_setg(errp, QERR_QMP_BAD_INPUT_OBJECT, "object");
return NULL;
}
- input_dict = qobject_to_qdict(input_obj);
for (ent = qdict_first(input_dict); ent; ent = qdict_next(input_dict, ent)){
const char *arg_name = qdict_entry_key(ent);
@@ -3761,10 +3762,11 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
Error *err = NULL;
req = json_parser_parse_err(tokens, NULL, &err);
- if (err || !req || qobject_type(req) != QTYPE_QDICT) {
- if (!err) {
- error_setg(&err, QERR_JSON_PARSING);
- }
+ if (!req && !err) {
+ /* json_parser_parse_err() sucks: can fail without setting @err */
+ error_setg(&err, QERR_JSON_PARSING);
+ }
+ if (err) {
goto err_out;
}
@@ -4181,10 +4183,10 @@ HotpluggableCPUList *qmp_query_hotpluggable_cpus(Error **errp)
MachineState *ms = MACHINE(qdev_get_machine());
MachineClass *mc = MACHINE_GET_CLASS(ms);
- if (!mc->query_hotpluggable_cpus) {
+ if (!mc->has_hotpluggable_cpus) {
error_setg(errp, QERR_FEATURE_DISABLED, "query-hotpluggable-cpus");
return NULL;
}
- return mc->query_hotpluggable_cpus(ms);
+ return machine_query_hotpluggable_cpus(ms);
}
diff --git a/net/net.c b/net/net.c
index fb7af3a432..0ac3b9e80c 100644
--- a/net/net.c
+++ b/net/net.c
@@ -993,47 +993,47 @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp)
/* Map the old options to the new flat type */
switch (opts->type) {
- case NET_LEGACY_OPTIONS_KIND_NONE:
+ case NET_LEGACY_OPTIONS_TYPE_NONE:
return 0; /* nothing to do */
- case NET_LEGACY_OPTIONS_KIND_NIC:
+ case NET_LEGACY_OPTIONS_TYPE_NIC:
legacy.type = NET_CLIENT_DRIVER_NIC;
- legacy.u.nic = *opts->u.nic.data;
+ legacy.u.nic = opts->u.nic;
break;
- case NET_LEGACY_OPTIONS_KIND_USER:
+ case NET_LEGACY_OPTIONS_TYPE_USER:
legacy.type = NET_CLIENT_DRIVER_USER;
- legacy.u.user = *opts->u.user.data;
+ legacy.u.user = opts->u.user;
break;
- case NET_LEGACY_OPTIONS_KIND_TAP:
+ case NET_LEGACY_OPTIONS_TYPE_TAP:
legacy.type = NET_CLIENT_DRIVER_TAP;
- legacy.u.tap = *opts->u.tap.data;
+ legacy.u.tap = opts->u.tap;
break;
- case NET_LEGACY_OPTIONS_KIND_L2TPV3:
+ case NET_LEGACY_OPTIONS_TYPE_L2TPV3:
legacy.type = NET_CLIENT_DRIVER_L2TPV3;
- legacy.u.l2tpv3 = *opts->u.l2tpv3.data;
+ legacy.u.l2tpv3 = opts->u.l2tpv3;
break;
- case NET_LEGACY_OPTIONS_KIND_SOCKET:
+ case NET_LEGACY_OPTIONS_TYPE_SOCKET:
legacy.type = NET_CLIENT_DRIVER_SOCKET;
- legacy.u.socket = *opts->u.socket.data;
+ legacy.u.socket = opts->u.socket;
break;
- case NET_LEGACY_OPTIONS_KIND_VDE:
+ case NET_LEGACY_OPTIONS_TYPE_VDE:
legacy.type = NET_CLIENT_DRIVER_VDE;
- legacy.u.vde = *opts->u.vde.data;
+ legacy.u.vde = opts->u.vde;
break;
- case NET_LEGACY_OPTIONS_KIND_DUMP:
+ case NET_LEGACY_OPTIONS_TYPE_DUMP:
legacy.type = NET_CLIENT_DRIVER_DUMP;
- legacy.u.dump = *opts->u.dump.data;
+ legacy.u.dump = opts->u.dump;
break;
- case NET_LEGACY_OPTIONS_KIND_BRIDGE:
+ case NET_LEGACY_OPTIONS_TYPE_BRIDGE:
legacy.type = NET_CLIENT_DRIVER_BRIDGE;
- legacy.u.bridge = *opts->u.bridge.data;
+ legacy.u.bridge = opts->u.bridge;
break;
- case NET_LEGACY_OPTIONS_KIND_NETMAP:
+ case NET_LEGACY_OPTIONS_TYPE_NETMAP:
legacy.type = NET_CLIENT_DRIVER_NETMAP;
- legacy.u.netmap = *opts->u.netmap.data;
+ legacy.u.netmap = opts->u.netmap;
break;
- case NET_LEGACY_OPTIONS_KIND_VHOST_USER:
+ case NET_LEGACY_OPTIONS_TYPE_VHOST_USER:
legacy.type = NET_CLIENT_DRIVER_VHOST_USER;
- legacy.u.vhost_user = *opts->u.vhost_user.data;
+ legacy.u.vhost_user = opts->u.vhost_user;
break;
default:
abort();
@@ -1048,7 +1048,7 @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp)
/* Do not add to a vlan if it's a nic with a netdev= parameter. */
if (netdev->type != NET_CLIENT_DRIVER_NIC ||
- !opts->u.nic.data->has_netdev) {
+ !opts->u.nic.has_netdev) {
peer = net_hub_add_port(net->has_vlan ? net->vlan : 0, NULL);
}
diff --git a/numa.c b/numa.c
index 9f56be960f..e01cb547a2 100644
--- a/numa.c
+++ b/numa.c
@@ -228,8 +228,8 @@ static int parse_numa(void *opaque, QemuOpts *opts, Error **errp)
}
switch (object->type) {
- case NUMA_OPTIONS_KIND_NODE:
- numa_node_parse(object->u.node.data, opts, &err);
+ case NUMA_OPTIONS_TYPE_NODE:
+ numa_node_parse(&object->u.node, opts, &err);
if (err) {
goto end;
}
diff --git a/qapi-schema.json b/qapi-schema.json
index f6ca18c3be..150ee98e9e 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3972,6 +3972,15 @@
'opts': 'NetLegacyOptions' } }
##
+# @NetLegacyOptionsType:
+#
+# Since: 1.2
+##
+{ 'enum': 'NetLegacyOptionsType',
+ 'data': ['none', 'nic', 'user', 'tap', 'l2tpv3', 'socket', 'vde',
+ 'dump', 'bridge', 'netmap', 'vhost-user'] }
+
+##
# @NetLegacyOptions:
#
# Like Netdev, but for use only by the legacy command line options
@@ -3979,6 +3988,8 @@
# Since: 1.2
##
{ 'union': 'NetLegacyOptions',
+ 'base': { 'type': 'NetLegacyOptionsType' },
+ 'discriminator': 'type',
'data': {
'none': 'NetdevNoneOptions',
'nic': 'NetLegacyNicOptions',
@@ -5584,6 +5595,14 @@
'events' : [ 'InputEvent' ] } }
##
+# @NumaOptionsType:
+#
+# Since: 2.1
+##
+{ 'enum': 'NumaOptionsType',
+ 'data': [ 'node' ] }
+
+##
# @NumaOptions:
#
# A discriminated record of NUMA options. (for OptsVisitor)
@@ -5591,6 +5610,8 @@
# Since: 2.1
##
{ 'union': 'NumaOptions',
+ 'base': { 'type': 'NumaOptionsType' },
+ 'discriminator': 'type',
'data': {
'node': 'NumaNodeOptions' }}
diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c
index 1048bbc84e..a0a7c0e734 100644
--- a/qapi/opts-visitor.c
+++ b/qapi/opts-visitor.c
@@ -481,23 +481,20 @@ opts_type_size(Visitor *v, const char *name, uint64_t *obj, Error **errp)
{
OptsVisitor *ov = to_ov(v);
const QemuOpt *opt;
- int64_t val;
- char *endptr;
+ int err;
opt = lookup_scalar(ov, name, errp);
if (!opt) {
return;
}
- val = qemu_strtosz_suffix(opt->str ? opt->str : "", &endptr,
- QEMU_STRTOSZ_DEFSUFFIX_B);
- if (val < 0 || *endptr) {
+ err = qemu_strtosz(opt->str ? opt->str : "", NULL, obj);
+ if (err < 0) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, opt->name,
- "a size value representible as a non-negative int64");
+ "a size value");
return;
}
- *obj = val;
processed(ov, name);
}
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 505eb418ac..48bec2072b 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -28,14 +28,13 @@ static QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
bool has_exec_key = false;
QDict *dict = NULL;
- if (qobject_type(request) != QTYPE_QDICT) {
+ dict = qobject_to_qdict(request);
+ if (!dict) {
error_setg(errp, QERR_QMP_BAD_INPUT_OBJECT,
"request is not a dictionary");
return NULL;
}
- dict = qobject_to_qdict(request);
-
for (ent = qdict_first(dict); ent;
ent = qdict_next(dict, ent)) {
arg_name = qdict_entry_key(ent);
diff --git a/qemu-img.c b/qemu-img.c
index cff22e3005..df3aefd35a 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -368,6 +368,21 @@ static int add_old_style_options(const char *fmt, QemuOpts *opts,
return 0;
}
+static int64_t cvtnum(const char *s)
+{
+ int err;
+ uint64_t value;
+
+ err = qemu_strtosz(s, NULL, &value);
+ if (err < 0) {
+ return err;
+ }
+ if (value > INT64_MAX) {
+ return -ERANGE;
+ }
+ return value;
+}
+
static int img_create(int argc, char **argv)
{
int c;
@@ -461,10 +476,9 @@ static int img_create(int argc, char **argv)
/* Get image size, if specified */
if (optind < argc) {
int64_t sval;
- char *end;
- sval = qemu_strtosz_suffix(argv[optind++], &end,
- QEMU_STRTOSZ_DEFSUFFIX_B);
- if (sval < 0 || *end) {
+
+ sval = cvtnum(argv[optind++]);
+ if (sval < 0) {
if (sval == -ERANGE) {
error_report("Image size must be less than 8 EiB!");
} else {
@@ -1864,9 +1878,9 @@ static int img_convert(int argc, char **argv)
case 'S':
{
int64_t sval;
- char *end;
- sval = qemu_strtosz_suffix(optarg, &end, QEMU_STRTOSZ_DEFSUFFIX_B);
- if (sval < 0 || *end) {
+
+ sval = cvtnum(optarg);
+ if (sval < 0) {
error_report("Invalid minimum zero buffer size for sparse output specified");
ret = -1;
goto fail_getopt;
@@ -3651,11 +3665,8 @@ static int img_bench(int argc, char **argv)
break;
case 'o':
{
- char *end;
- errno = 0;
- offset = qemu_strtosz_suffix(optarg, &end,
- QEMU_STRTOSZ_DEFSUFFIX_B);
- if (offset < 0|| *end) {
+ offset = cvtnum(optarg);
+ if (offset < 0) {
error_report("Invalid offset specified");
return 1;
}
@@ -3668,10 +3679,9 @@ static int img_bench(int argc, char **argv)
case 's':
{
int64_t sval;
- char *end;
- sval = qemu_strtosz_suffix(optarg, &end, QEMU_STRTOSZ_DEFSUFFIX_B);
- if (sval < 0 || sval > INT_MAX || *end) {
+ sval = cvtnum(optarg);
+ if (sval < 0 || sval > INT_MAX) {
error_report("Invalid buffer size specified");
return 1;
}
@@ -3682,10 +3692,9 @@ static int img_bench(int argc, char **argv)
case 'S':
{
int64_t sval;
- char *end;
- sval = qemu_strtosz_suffix(optarg, &end, QEMU_STRTOSZ_DEFSUFFIX_B);
- if (sval < 0 || sval > INT_MAX || *end) {
+ sval = cvtnum(optarg);
+ if (sval < 0 || sval > INT_MAX) {
error_report("Invalid step size specified");
return 1;
}
@@ -3844,12 +3853,11 @@ static int img_dd_bs(const char *arg,
struct DdIo *in, struct DdIo *out,
struct DdInfo *dd)
{
- char *end;
int64_t res;
- res = qemu_strtosz_suffix(arg, &end, QEMU_STRTOSZ_DEFSUFFIX_B);
+ res = cvtnum(arg);
- if (res <= 0 || res > INT_MAX || *end) {
+ if (res <= 0 || res > INT_MAX) {
error_report("invalid number: '%s'", arg);
return 1;
}
@@ -3862,11 +3870,9 @@ static int img_dd_count(const char *arg,
struct DdIo *in, struct DdIo *out,
struct DdInfo *dd)
{
- char *end;
+ dd->count = cvtnum(arg);
- dd->count = qemu_strtosz_suffix(arg, &end, QEMU_STRTOSZ_DEFSUFFIX_B);
-
- if (dd->count < 0 || *end) {
+ if (dd->count < 0) {
error_report("invalid number: '%s'", arg);
return 1;
}
@@ -3896,11 +3902,9 @@ static int img_dd_skip(const char *arg,
struct DdIo *in, struct DdIo *out,
struct DdInfo *dd)
{
- char *end;
-
- in->offset = qemu_strtosz_suffix(arg, &end, QEMU_STRTOSZ_DEFSUFFIX_B);
+ in->offset = cvtnum(arg);
- if (in->offset < 0 || *end) {
+ if (in->offset < 0) {
error_report("invalid number: '%s'", arg);
return 1;
}
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index e415b03cd0..7ac1576d4c 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -137,15 +137,17 @@ static char **breakline(char *input, int *count)
static int64_t cvtnum(const char *s)
{
- char *end;
- int64_t ret;
+ int err;
+ uint64_t value;
- ret = qemu_strtosz_suffix(s, &end, QEMU_STRTOSZ_DEFSUFFIX_B);
- if (*end != '\0') {
- /* Detritus at the end of the string */
- return -EINVAL;
+ err = qemu_strtosz(s, NULL, &value);
+ if (err < 0) {
+ return err;
}
- return ret;
+ if (value > INT64_MAX) {
+ return -ERANGE;
+ }
+ return value;
}
static void print_cvtnum_err(int64_t rc, const char *arg)
diff --git a/qobject/qdict.c b/qobject/qdict.c
index 197b0fbd47..291eef1a19 100644
--- a/qobject/qdict.c
+++ b/qobject/qdict.c
@@ -178,20 +178,6 @@ size_t qdict_size(const QDict *qdict)
}
/**
- * qdict_get_obj(): Get a QObject of a specific type
- */
-static QObject *qdict_get_obj(const QDict *qdict, const char *key, QType type)
-{
- QObject *obj;
-
- obj = qdict_get(qdict, key);
- assert(obj != NULL);
- assert(qobject_type(obj) == type);
-
- return obj;
-}
-
-/**
* qdict_get_double(): Get an number mapped by 'key'
*
* This function assumes that 'key' exists and it stores a
@@ -241,25 +227,15 @@ bool qdict_get_bool(const QDict *qdict, const char *key)
}
/**
- * qdict_get_qlist(): Get the QList mapped by 'key'
- *
- * This function assumes that 'key' exists and it stores a
- * QList object.
- *
- * Return QList mapped by 'key'.
+ * qdict_get_qlist(): If @qdict maps @key to a QList, return it, else NULL.
*/
QList *qdict_get_qlist(const QDict *qdict, const char *key)
{
- return qobject_to_qlist(qdict_get_obj(qdict, key, QTYPE_QLIST));
+ return qobject_to_qlist(qdict_get(qdict, key));
}
/**
- * qdict_get_qdict(): Get the QDict mapped by 'key'
- *
- * This function assumes that 'key' exists and it stores a
- * QDict object.
- *
- * Return QDict mapped by 'key'.
+ * qdict_get_qdict(): If @qdict maps @key to a QDict, return it, else NULL.
*/
QDict *qdict_get_qdict(const QDict *qdict, const char *key)
{
@@ -767,7 +743,7 @@ static int qdict_is_list(QDict *maybe_list, Error **errp)
for (ent = qdict_first(maybe_list); ent != NULL;
ent = qdict_next(maybe_list, ent)) {
- if (qemu_strtoll(ent->key, NULL, 10, &val) == 0) {
+ if (qemu_strtoi64(ent->key, NULL, 10, &val) == 0) {
if (is_list == -1) {
is_list = 1;
} else if (!is_list) {
diff --git a/qtest.c b/qtest.c
index 1446719e8d..a6858272eb 100644
--- a/qtest.c
+++ b/qtest.c
@@ -373,8 +373,8 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
uint64_t value;
g_assert(words[1] && words[2]);
- g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0);
- g_assert(qemu_strtoull(words[2], NULL, 0, &value) == 0);
+ g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0);
+ g_assert(qemu_strtou64(words[2], NULL, 0, &value) == 0);
if (words[0][5] == 'b') {
uint8_t data = value;
@@ -402,7 +402,7 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
uint64_t value = UINT64_C(-1);
g_assert(words[1]);
- g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0);
+ g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0);
if (words[0][4] == 'b') {
uint8_t data;
@@ -428,8 +428,8 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
char *enc;
g_assert(words[1] && words[2]);
- g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0);
- g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0);
+ g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0);
+ g_assert(qemu_strtou64(words[2], NULL, 0, &len) == 0);
/* We'd send garbage to libqtest if len is 0 */
g_assert(len);
@@ -452,8 +452,8 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
gchar *b64_data;
g_assert(words[1] && words[2]);
- g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0);
- g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0);
+ g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0);
+ g_assert(qemu_strtou64(words[2], NULL, 0, &len) == 0);
data = g_malloc(len);
cpu_physical_memory_read(addr, data, len);
@@ -469,8 +469,8 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
size_t data_len;
g_assert(words[1] && words[2] && words[3]);
- g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0);
- g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0);
+ g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0);
+ g_assert(qemu_strtou64(words[2], NULL, 0, &len) == 0);
data_len = strlen(words[3]);
if (data_len < 3) {
@@ -498,8 +498,8 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
unsigned long pattern;
g_assert(words[1] && words[2] && words[3]);
- g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0);
- g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0);
+ g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0);
+ g_assert(qemu_strtou64(words[2], NULL, 0, &len) == 0);
g_assert(qemu_strtoul(words[3], NULL, 0, &pattern) == 0);
if (len) {
@@ -518,8 +518,8 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
gsize out_len;
g_assert(words[1] && words[2] && words[3]);
- g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0);
- g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0);
+ g_assert(qemu_strtou64(words[1], NULL, 0, &addr) == 0);
+ g_assert(qemu_strtou64(words[2], NULL, 0, &len) == 0);
data_len = strlen(words[3]);
if (data_len < 3) {
@@ -552,9 +552,9 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
unsigned long nargs, nret;
g_assert(qemu_strtoul(words[2], NULL, 0, &nargs) == 0);
- g_assert(qemu_strtoull(words[3], NULL, 0, &args) == 0);
+ g_assert(qemu_strtou64(words[3], NULL, 0, &args) == 0);
g_assert(qemu_strtoul(words[4], NULL, 0, &nret) == 0);
- g_assert(qemu_strtoull(words[5], NULL, 0, &ret) == 0);
+ g_assert(qemu_strtou64(words[5], NULL, 0, &ret) == 0);
res = qtest_rtas_call(words[1], nargs, args, nret, ret);
qtest_send_prefix(chr);
@@ -564,7 +564,7 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
int64_t ns;
if (words[1]) {
- g_assert(qemu_strtoll(words[1], NULL, 0, &ns) == 0);
+ g_assert(qemu_strtoi64(words[1], NULL, 0, &ns) == 0);
} else {
ns = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
}
@@ -576,7 +576,7 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
int64_t ns;
g_assert(words[1]);
- g_assert(qemu_strtoll(words[1], NULL, 0, &ns) == 0);
+ g_assert(qemu_strtoi64(words[1], NULL, 0, &ns) == 0);
qtest_clock_warp(ns);
qtest_send_prefix(chr);
qtest_sendf(chr, "OK %"PRIi64"\n",
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index fd7add2521..b6f157dca3 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -2033,12 +2033,11 @@ static void x86_cpu_parse_featurestr(const char *typename, char *features,
/* Special case: */
if (!strcmp(name, "tsc-freq")) {
- int64_t tsc_freq;
- char *err;
+ int ret;
+ uint64_t tsc_freq;
- tsc_freq = qemu_strtosz_suffix_unit(val, &err,
- QEMU_STRTOSZ_DEFSUFFIX_B, 1000);
- if (tsc_freq < 0 || *err) {
+ ret = qemu_strtosz_metric(val, NULL, &tsc_freq);
+ if (ret < 0 || tsc_freq > INT64_MAX) {
error_setg(errp, "bad numerical value %s", val);
return;
}
diff --git a/target/ppc/cpu-qom.h b/target/ppc/cpu-qom.h
index b7977bad18..4e3132b56b 100644
--- a/target/ppc/cpu-qom.h
+++ b/target/ppc/cpu-qom.h
@@ -86,10 +86,13 @@ enum powerpc_mmu_t {
POWERPC_MMU_2_07 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG
| POWERPC_MMU_64K
| POWERPC_MMU_AMR | 0x00000004,
- /* FIXME Add POWERPC_MMU_3_OO defines */
/* Architecture 2.07 "degraded" (no 1T segments) */
POWERPC_MMU_2_07a = POWERPC_MMU_64 | POWERPC_MMU_AMR
| 0x00000004,
+ /* Architecture 3.00 variant */
+ POWERPC_MMU_3_00 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG
+ | POWERPC_MMU_64K
+ | POWERPC_MMU_AMR | 0x00000005,
};
/*****************************************************************************/
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index bc2a2ce431..425e79d52d 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -381,15 +381,22 @@ struct ppc_slb_t {
#define LPCR_ISL (1ull << (63 - 2))
#define LPCR_KBV (1ull << (63 - 3))
#define LPCR_DPFD_SHIFT (63 - 11)
-#define LPCR_DPFD (0x3ull << LPCR_DPFD_SHIFT)
+#define LPCR_DPFD (0x7ull << LPCR_DPFD_SHIFT)
#define LPCR_VRMASD_SHIFT (63 - 16)
#define LPCR_VRMASD (0x1full << LPCR_VRMASD_SHIFT)
+/* P9: Power-saving mode Exit Cause Enable (Upper Section) Mask */
+#define LPCR_PECE_U_SHIFT (63 - 19)
+#define LPCR_PECE_U_MASK (0x7ull << LPCR_PECE_U_SHIFT)
+#define LPCR_HVEE (1ull << (63 - 17)) /* Hypervisor Virt Exit Enable */
#define LPCR_RMLS_SHIFT (63 - 37)
#define LPCR_RMLS (0xfull << LPCR_RMLS_SHIFT)
#define LPCR_ILE (1ull << (63 - 38))
#define LPCR_AIL_SHIFT (63 - 40) /* Alternate interrupt location */
#define LPCR_AIL (3ull << LPCR_AIL_SHIFT)
+#define LPCR_UPRT (1ull << (63 - 41)) /* Use Process Table */
+#define LPCR_EVIRT (1ull << (63 - 42)) /* Enhanced Virtualisation */
#define LPCR_ONL (1ull << (63 - 45))
+#define LPCR_LD (1ull << (63 - 46)) /* Large Decrementer */
#define LPCR_P7_PECE0 (1ull << (63 - 49))
#define LPCR_P7_PECE1 (1ull << (63 - 50))
#define LPCR_P7_PECE2 (1ull << (63 - 51))
@@ -398,11 +405,22 @@ struct ppc_slb_t {
#define LPCR_P8_PECE2 (1ull << (63 - 49))
#define LPCR_P8_PECE3 (1ull << (63 - 50))
#define LPCR_P8_PECE4 (1ull << (63 - 51))
+/* P9: Power-saving mode Exit Cause Enable (Lower Section) Mask */
+#define LPCR_PECE_L_SHIFT (63 - 51)
+#define LPCR_PECE_L_MASK (0x1full << LPCR_PECE_L_SHIFT)
+#define LPCR_PDEE (1ull << (63 - 47)) /* Privileged Doorbell Exit EN */
+#define LPCR_HDEE (1ull << (63 - 48)) /* Hyperv Doorbell Exit Enable */
+#define LPCR_EEE (1ull << (63 - 49)) /* External Exit Enable */
+#define LPCR_DEE (1ull << (63 - 50)) /* Decrementer Exit Enable */
+#define LPCR_OEE (1ull << (63 - 51)) /* Other Exit Enable */
#define LPCR_MER (1ull << (63 - 52))
+#define LPCR_GTSE (1ull << (63 - 53)) /* Guest Translation Shootdown */
#define LPCR_TC (1ull << (63 - 54))
+#define LPCR_HEIC (1ull << (63 - 59)) /* HV Extern Interrupt Control */
#define LPCR_LPES0 (1ull << (63 - 60))
#define LPCR_LPES1 (1ull << (63 - 61))
#define LPCR_RMI (1ull << (63 - 62))
+#define LPCR_HVICE (1ull << (63 - 62)) /* HV Virtualisation Int Enable */
#define LPCR_HDICE (1ull << (63 - 63))
#define msr_sf ((env->msr >> MSR_SF) & 1)
diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c
index 9f5cafd5ba..58aee640c3 100644
--- a/target/ppc/fpu_helper.c
+++ b/target/ppc/fpu_helper.c
@@ -1850,12 +1850,11 @@ void helper_xsaddqp(CPUPPCState *env, uint32_t opcode)
getVSR(rD(opcode) + 32, &xt, env);
helper_reset_fpstatus(env);
+ tstat = env->fp_status;
if (unlikely(Rc(opcode) != 0)) {
- /* TODO: Support xsadddpo after round-to-odd is implemented */
- abort();
+ tstat.float_rounding_mode = float_round_to_odd;
}
- tstat = env->fp_status;
set_float_exception_flags(0, &tstat);
xt.f128 = float128_add(xa.f128, xb.f128, &tstat);
env->fp_status.float_exception_flags |= tstat.float_exception_flags;
@@ -1930,19 +1929,18 @@ VSX_MUL(xvmulsp, 4, float32, VsrW(i), 0, 0)
void helper_xsmulqp(CPUPPCState *env, uint32_t opcode)
{
ppc_vsr_t xt, xa, xb;
+ float_status tstat;
getVSR(rA(opcode) + 32, &xa, env);
getVSR(rB(opcode) + 32, &xb, env);
getVSR(rD(opcode) + 32, &xt, env);
+ helper_reset_fpstatus(env);
+ tstat = env->fp_status;
if (unlikely(Rc(opcode) != 0)) {
- /* TODO: Support xsmulpo after round-to-odd is implemented */
- abort();
+ tstat.float_rounding_mode = float_round_to_odd;
}
- helper_reset_fpstatus(env);
-
- float_status tstat = env->fp_status;
set_float_exception_flags(0, &tstat);
xt.f128 = float128_mul(xa.f128, xb.f128, &tstat);
env->fp_status.float_exception_flags |= tstat.float_exception_flags;
@@ -2019,18 +2017,18 @@ VSX_DIV(xvdivsp, 4, float32, VsrW(i), 0, 0)
void helper_xsdivqp(CPUPPCState *env, uint32_t opcode)
{
ppc_vsr_t xt, xa, xb;
+ float_status tstat;
getVSR(rA(opcode) + 32, &xa, env);
getVSR(rB(opcode) + 32, &xb, env);
getVSR(rD(opcode) + 32, &xt, env);
+ helper_reset_fpstatus(env);
+ tstat = env->fp_status;
if (unlikely(Rc(opcode) != 0)) {
- /* TODO: Support xsdivqpo after round-to-odd is implemented */
- abort();
+ tstat.float_rounding_mode = float_round_to_odd;
}
- helper_reset_fpstatus(env);
- float_status tstat = env->fp_status;
set_float_exception_flags(0, &tstat);
xt.f128 = float128_div(xa.f128, xb.f128, &tstat);
env->fp_status.float_exception_flags |= tstat.float_exception_flags;
@@ -2679,6 +2677,99 @@ VSX_MAX_MIN(xsmindp, minnum, 1, float64, VsrD(0))
VSX_MAX_MIN(xvmindp, minnum, 2, float64, VsrD(i))
VSX_MAX_MIN(xvminsp, minnum, 4, float32, VsrW(i))
+#define VSX_MAX_MINC(name, max) \
+void helper_##name(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xa, xb; \
+ bool vxsnan_flag = false, vex_flag = false; \
+ \
+ getVSR(rA(opcode) + 32, &xa, env); \
+ getVSR(rB(opcode) + 32, &xb, env); \
+ getVSR(rD(opcode) + 32, &xt, env); \
+ \
+ if (unlikely(float64_is_any_nan(xa.VsrD(0)) || \
+ float64_is_any_nan(xb.VsrD(0)))) { \
+ if (float64_is_signaling_nan(xa.VsrD(0), &env->fp_status) || \
+ float64_is_signaling_nan(xb.VsrD(0), &env->fp_status)) { \
+ vxsnan_flag = true; \
+ } \
+ xt.VsrD(0) = xb.VsrD(0); \
+ } else if ((max && \
+ !float64_lt(xa.VsrD(0), xb.VsrD(0), &env->fp_status)) || \
+ (!max && \
+ float64_lt(xa.VsrD(0), xb.VsrD(0), &env->fp_status))) { \
+ xt.VsrD(0) = xa.VsrD(0); \
+ } else { \
+ xt.VsrD(0) = xb.VsrD(0); \
+ } \
+ \
+ vex_flag = fpscr_ve & vxsnan_flag; \
+ if (vxsnan_flag) { \
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
+ } \
+ if (!vex_flag) { \
+ putVSR(rD(opcode) + 32, &xt, env); \
+ } \
+} \
+
+VSX_MAX_MINC(xsmaxcdp, 1);
+VSX_MAX_MINC(xsmincdp, 0);
+
+#define VSX_MAX_MINJ(name, max) \
+void helper_##name(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xa, xb; \
+ bool vxsnan_flag = false, vex_flag = false; \
+ \
+ getVSR(rA(opcode) + 32, &xa, env); \
+ getVSR(rB(opcode) + 32, &xb, env); \
+ getVSR(rD(opcode) + 32, &xt, env); \
+ \
+ if (unlikely(float64_is_any_nan(xa.VsrD(0)))) { \
+ if (float64_is_signaling_nan(xa.VsrD(0), &env->fp_status)) { \
+ vxsnan_flag = true; \
+ } \
+ xt.VsrD(0) = xa.VsrD(0); \
+ } else if (unlikely(float64_is_any_nan(xb.VsrD(0)))) { \
+ if (float64_is_signaling_nan(xb.VsrD(0), &env->fp_status)) { \
+ vxsnan_flag = true; \
+ } \
+ xt.VsrD(0) = xb.VsrD(0); \
+ } else if (float64_is_zero(xa.VsrD(0)) && float64_is_zero(xb.VsrD(0))) { \
+ if (max) { \
+ if (!float64_is_neg(xa.VsrD(0)) || !float64_is_neg(xb.VsrD(0))) { \
+ xt.VsrD(0) = 0ULL; \
+ } else { \
+ xt.VsrD(0) = 0x8000000000000000ULL; \
+ } \
+ } else { \
+ if (float64_is_neg(xa.VsrD(0)) || float64_is_neg(xb.VsrD(0))) { \
+ xt.VsrD(0) = 0x8000000000000000ULL; \
+ } else { \
+ xt.VsrD(0) = 0ULL; \
+ } \
+ } \
+ } else if ((max && \
+ !float64_lt(xa.VsrD(0), xb.VsrD(0), &env->fp_status)) || \
+ (!max && \
+ float64_lt(xa.VsrD(0), xb.VsrD(0), &env->fp_status))) { \
+ xt.VsrD(0) = xa.VsrD(0); \
+ } else { \
+ xt.VsrD(0) = xb.VsrD(0); \
+ } \
+ \
+ vex_flag = fpscr_ve & vxsnan_flag; \
+ if (vxsnan_flag) { \
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
+ } \
+ if (!vex_flag) { \
+ putVSR(rD(opcode) + 32, &xt, env); \
+ } \
+} \
+
+VSX_MAX_MINJ(xsmaxjdp, 1);
+VSX_MAX_MINJ(xsminjdp, 0);
+
/* VSX_CMP - VSX floating point compare
* op - instruction mnemonic
* nels - number of elements (1, 2 or 4)
@@ -2861,18 +2952,20 @@ VSX_CVT_FP_TO_FP_HP(xvcvhpsp, 4, float16, float32, VsrH(2 * i + 1), VsrW(i), 0)
void helper_xscvqpdp(CPUPPCState *env, uint32_t opcode)
{
ppc_vsr_t xt, xb;
+ float_status tstat;
getVSR(rB(opcode) + 32, &xb, env);
memset(&xt, 0, sizeof(xt));
+ tstat = env->fp_status;
if (unlikely(Rc(opcode) != 0)) {
- /* TODO: Support xscvqpdpo after round-to-odd is implemented */
- abort();
+ tstat.float_rounding_mode = float_round_to_odd;
}
- xt.VsrD(0) = float128_to_float64(xb.f128, &env->fp_status);
+ xt.VsrD(0) = float128_to_float64(xb.f128, &tstat);
+ env->fp_status.float_exception_flags |= tstat.float_exception_flags;
if (unlikely(float128_is_signaling_nan(xb.f128,
- &env->fp_status))) {
+ &tstat))) {
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);
xt.VsrD(0) = float64_snan_to_qnan(xt.VsrD(0));
}
@@ -2993,6 +3086,8 @@ VSX_CVT_FP_TO_INT_VECTOR(xscvqpsdz, float128, int64, f128, VsrD(0), \
VSX_CVT_FP_TO_INT_VECTOR(xscvqpswz, float128, int32, f128, VsrD(0), \
0xffffffff80000000ULL)
+VSX_CVT_FP_TO_INT_VECTOR(xscvqpudz, float128, uint64, f128, VsrD(0), 0x0ULL)
+VSX_CVT_FP_TO_INT_VECTOR(xscvqpuwz, float128, uint32, f128, VsrD(0), 0x0ULL)
/* VSX_CVT_INT_TO_FP - VSX integer to floating point conversion
* op - instruction mnemonic
@@ -3277,3 +3372,188 @@ void helper_xststdcsp(CPUPPCState *env, uint32_t opcode)
env->fpscr |= cc << FPSCR_FPRF;
env->crf[BF(opcode)] = cc;
}
+
+void helper_xsrqpi(CPUPPCState *env, uint32_t opcode)
+{
+ ppc_vsr_t xb;
+ ppc_vsr_t xt;
+ uint8_t r = Rrm(opcode);
+ uint8_t ex = Rc(opcode);
+ uint8_t rmc = RMC(opcode);
+ uint8_t rmode = 0;
+ float_status tstat;
+
+ getVSR(rB(opcode) + 32, &xb, env);
+ memset(&xt, 0, sizeof(xt));
+ helper_reset_fpstatus(env);
+
+ if (r == 0 && rmc == 0) {
+ rmode = float_round_ties_away;
+ } else if (r == 0 && rmc == 0x3) {
+ rmode = fpscr_rn;
+ } else if (r == 1) {
+ switch (rmc) {
+ case 0:
+ rmode = float_round_nearest_even;
+ break;
+ case 1:
+ rmode = float_round_to_zero;
+ break;
+ case 2:
+ rmode = float_round_up;
+ break;
+ case 3:
+ rmode = float_round_down;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ tstat = env->fp_status;
+ set_float_exception_flags(0, &tstat);
+ set_float_rounding_mode(rmode, &tstat);
+ xt.f128 = float128_round_to_int(xb.f128, &tstat);
+ env->fp_status.float_exception_flags |= tstat.float_exception_flags;
+
+ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {
+ if (float128_is_signaling_nan(xb.f128, &tstat)) {
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);
+ xt.f128 = float128_snan_to_qnan(xt.f128);
+ }
+ }
+
+ if (ex == 0 && (tstat.float_exception_flags & float_flag_inexact)) {
+ env->fp_status.float_exception_flags &= ~float_flag_inexact;
+ }
+
+ helper_compute_fprf_float128(env, xt.f128);
+ float_check_status(env);
+ putVSR(rD(opcode) + 32, &xt, env);
+}
+
+void helper_xsrqpxp(CPUPPCState *env, uint32_t opcode)
+{
+ ppc_vsr_t xb;
+ ppc_vsr_t xt;
+ uint8_t r = Rrm(opcode);
+ uint8_t rmc = RMC(opcode);
+ uint8_t rmode = 0;
+ floatx80 round_res;
+ float_status tstat;
+
+ getVSR(rB(opcode) + 32, &xb, env);
+ memset(&xt, 0, sizeof(xt));
+ helper_reset_fpstatus(env);
+
+ if (r == 0 && rmc == 0) {
+ rmode = float_round_ties_away;
+ } else if (r == 0 && rmc == 0x3) {
+ rmode = fpscr_rn;
+ } else if (r == 1) {
+ switch (rmc) {
+ case 0:
+ rmode = float_round_nearest_even;
+ break;
+ case 1:
+ rmode = float_round_to_zero;
+ break;
+ case 2:
+ rmode = float_round_up;
+ break;
+ case 3:
+ rmode = float_round_down;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ tstat = env->fp_status;
+ set_float_exception_flags(0, &tstat);
+ set_float_rounding_mode(rmode, &tstat);
+ round_res = float128_to_floatx80(xb.f128, &tstat);
+ xt.f128 = floatx80_to_float128(round_res, &tstat);
+ env->fp_status.float_exception_flags |= tstat.float_exception_flags;
+
+ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {
+ if (float128_is_signaling_nan(xb.f128, &tstat)) {
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);
+ xt.f128 = float128_snan_to_qnan(xt.f128);
+ }
+ }
+
+ helper_compute_fprf_float128(env, xt.f128);
+ putVSR(rD(opcode) + 32, &xt, env);
+ float_check_status(env);
+}
+
+void helper_xssqrtqp(CPUPPCState *env, uint32_t opcode)
+{
+ ppc_vsr_t xb;
+ ppc_vsr_t xt;
+ float_status tstat;
+
+ getVSR(rB(opcode) + 32, &xb, env);
+ memset(&xt, 0, sizeof(xt));
+ helper_reset_fpstatus(env);
+
+ tstat = env->fp_status;
+ if (unlikely(Rc(opcode) != 0)) {
+ tstat.float_rounding_mode = float_round_to_odd;
+ }
+
+ set_float_exception_flags(0, &tstat);
+ xt.f128 = float128_sqrt(xb.f128, &tstat);
+ env->fp_status.float_exception_flags |= tstat.float_exception_flags;
+
+ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {
+ if (float128_is_signaling_nan(xb.f128, &tstat)) {
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+ xt.f128 = float128_snan_to_qnan(xb.f128);
+ } else if (float128_is_quiet_nan(xb.f128, &tstat)) {
+ xt.f128 = xb.f128;
+ } else if (float128_is_neg(xb.f128) && !float128_is_zero(xb.f128)) {
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
+ set_snan_bit_is_one(0, &env->fp_status);
+ xt.f128 = float128_default_nan(&env->fp_status);
+ }
+ }
+
+ helper_compute_fprf_float128(env, xt.f128);
+ putVSR(rD(opcode) + 32, &xt, env);
+ float_check_status(env);
+}
+
+void helper_xssubqp(CPUPPCState *env, uint32_t opcode)
+{
+ ppc_vsr_t xt, xa, xb;
+ float_status tstat;
+
+ getVSR(rA(opcode) + 32, &xa, env);
+ getVSR(rB(opcode) + 32, &xb, env);
+ getVSR(rD(opcode) + 32, &xt, env);
+ helper_reset_fpstatus(env);
+
+ tstat = env->fp_status;
+ if (unlikely(Rc(opcode) != 0)) {
+ tstat.float_rounding_mode = float_round_to_odd;
+ }
+
+ set_float_exception_flags(0, &tstat);
+ xt.f128 = float128_sub(xa.f128, xb.f128, &tstat);
+ env->fp_status.float_exception_flags |= tstat.float_exception_flags;
+
+ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {
+ if (float128_is_infinity(xa.f128) && float128_is_infinity(xb.f128)) {
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
+ } else if (float128_is_signaling_nan(xa.f128, &tstat) ||
+ float128_is_signaling_nan(xb.f128, &tstat)) {
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+ }
+ }
+
+ helper_compute_fprf_float128(env, xt.f128);
+ putVSR(rD(opcode) + 32, &xt, env);
+ float_check_status(env);
+}
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index 85af9df36d..6d77661f7c 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -431,6 +431,10 @@ DEF_HELPER_2(xscmpoqp, void, env, i32)
DEF_HELPER_2(xscmpuqp, void, env, i32)
DEF_HELPER_2(xsmaxdp, void, env, i32)
DEF_HELPER_2(xsmindp, void, env, i32)
+DEF_HELPER_2(xsmaxcdp, void, env, i32)
+DEF_HELPER_2(xsmincdp, void, env, i32)
+DEF_HELPER_2(xsmaxjdp, void, env, i32)
+DEF_HELPER_2(xsminjdp, void, env, i32)
DEF_HELPER_2(xscvdphp, void, env, i32)
DEF_HELPER_2(xscvdpqp, void, env, i32)
DEF_HELPER_2(xscvdpsp, void, env, i32)
@@ -438,6 +442,8 @@ DEF_HELPER_2(xscvdpspn, i64, env, i64)
DEF_HELPER_2(xscvqpdp, void, env, i32)
DEF_HELPER_2(xscvqpsdz, void, env, i32)
DEF_HELPER_2(xscvqpswz, void, env, i32)
+DEF_HELPER_2(xscvqpudz, void, env, i32)
+DEF_HELPER_2(xscvqpuwz, void, env, i32)
DEF_HELPER_2(xscvhpdp, void, env, i32)
DEF_HELPER_2(xscvsdqp, void, env, i32)
DEF_HELPER_2(xscvspdp, void, env, i32)
@@ -459,6 +465,10 @@ DEF_HELPER_2(xsrdpic, void, env, i32)
DEF_HELPER_2(xsrdpim, void, env, i32)
DEF_HELPER_2(xsrdpip, void, env, i32)
DEF_HELPER_2(xsrdpiz, void, env, i32)
+DEF_HELPER_2(xsrqpi, void, env, i32)
+DEF_HELPER_2(xsrqpxp, void, env, i32)
+DEF_HELPER_2(xssqrtqp, void, env, i32)
+DEF_HELPER_2(xssubqp, void, env, i32)
DEF_HELPER_2(xsaddsp, void, env, i32)
DEF_HELPER_2(xssubsp, void, env, i32)
@@ -661,6 +671,7 @@ DEF_HELPER_2(load_slb_vsid, tl, env, tl)
DEF_HELPER_2(find_slb_vsid, tl, env, tl)
DEF_HELPER_FLAGS_1(slbia, TCG_CALL_NO_RWG, void, env)
DEF_HELPER_FLAGS_2(slbie, TCG_CALL_NO_RWG, void, env, tl)
+DEF_HELPER_FLAGS_2(slbieg, TCG_CALL_NO_RWG, void, env, tl)
#endif
DEF_HELPER_FLAGS_2(load_sr, TCG_CALL_NO_RWG, tl, env, tl)
DEF_HELPER_FLAGS_3(store_sr, TCG_CALL_NO_RWG, void, env, tl, tl)
diff --git a/target/ppc/internal.h b/target/ppc/internal.h
index 5a2fd68427..1f441c6483 100644
--- a/target/ppc/internal.h
+++ b/target/ppc/internal.h
@@ -133,6 +133,8 @@ EXTRACT_HELPER(UIMM4, 16, 4);
EXTRACT_HELPER(NB, 11, 5);
/* Shift count */
EXTRACT_HELPER(SH, 11, 5);
+/* lwat/stwat/ldat/lwat */
+EXTRACT_HELPER(FC, 11, 5);
/* Vector shift count */
EXTRACT_HELPER(VSH, 6, 4);
/* Mask start */
@@ -186,6 +188,7 @@ EXTRACT_HELPER(DCM, 10, 6)
/* DFP Z23-form */
EXTRACT_HELPER(RMC, 9, 2)
+EXTRACT_HELPER(Rrm, 16, 1)
EXTRACT_HELPER_SPLIT(DQxT, 3, 1, 21, 5);
EXTRACT_HELPER_SPLIT(xT, 0, 1, 21, 5);
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 663d2e79c9..52bbea514a 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -438,12 +438,13 @@ static bool kvm_valid_page_size(uint32_t flags, long rampgsize, uint32_t shift)
return (1ul << shift) <= rampgsize;
}
+static long max_cpu_page_size;
+
static void kvm_fixup_page_sizes(PowerPCCPU *cpu)
{
static struct kvm_ppc_smmu_info smmu_info;
static bool has_smmu_info;
CPUPPCState *env = &cpu->env;
- long rampagesize;
int iq, ik, jq, jk;
bool has_64k_pages = false;
@@ -458,7 +459,9 @@ static void kvm_fixup_page_sizes(PowerPCCPU *cpu)
has_smmu_info = true;
}
- rampagesize = getrampagesize();
+ if (!max_cpu_page_size) {
+ max_cpu_page_size = getrampagesize();
+ }
/* Convert to QEMU form */
memset(&env->sps, 0, sizeof(env->sps));
@@ -478,14 +481,14 @@ static void kvm_fixup_page_sizes(PowerPCCPU *cpu)
struct ppc_one_seg_page_size *qsps = &env->sps.sps[iq];
struct kvm_ppc_one_seg_page_size *ksps = &smmu_info.sps[ik];
- if (!kvm_valid_page_size(smmu_info.flags, rampagesize,
+ if (!kvm_valid_page_size(smmu_info.flags, max_cpu_page_size,
ksps->page_shift)) {
continue;
}
qsps->page_shift = ksps->page_shift;
qsps->slb_enc = ksps->slb_enc;
for (jk = jq = 0; jk < KVM_PPC_PAGE_SIZES_MAX_SZ; jk++) {
- if (!kvm_valid_page_size(smmu_info.flags, rampagesize,
+ if (!kvm_valid_page_size(smmu_info.flags, max_cpu_page_size,
ksps->enc[jk].page_shift)) {
continue;
}
@@ -510,12 +513,33 @@ static void kvm_fixup_page_sizes(PowerPCCPU *cpu)
env->mmu_model &= ~POWERPC_MMU_64K;
}
}
+
+bool kvmppc_is_mem_backend_page_size_ok(char *obj_path)
+{
+ Object *mem_obj = object_resolve_path(obj_path, NULL);
+ char *mempath = object_property_get_str(mem_obj, "mem-path", NULL);
+ long pagesize;
+
+ if (mempath) {
+ pagesize = gethugepagesize(mempath);
+ } else {
+ pagesize = getpagesize();
+ }
+
+ return pagesize >= max_cpu_page_size;
+}
+
#else /* defined (TARGET_PPC64) */
static inline void kvm_fixup_page_sizes(PowerPCCPU *cpu)
{
}
+bool kvmppc_is_mem_backend_page_size_ok(char *obj_path)
+{
+ return true;
+}
+
#endif /* !defined (TARGET_PPC64) */
unsigned long kvm_arch_vcpu_id(CPUState *cpu)
diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
index 151c00bac7..8da2ee418a 100644
--- a/target/ppc/kvm_ppc.h
+++ b/target/ppc/kvm_ppc.h
@@ -60,6 +60,8 @@ int kvmppc_enable_hwrng(void);
int kvmppc_put_books_sregs(PowerPCCPU *cpu);
PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void);
+bool kvmppc_is_mem_backend_page_size_ok(char *obj_path);
+
#else
static inline uint32_t kvmppc_get_tbfreq(void)
@@ -192,6 +194,11 @@ static inline uint64_t kvmppc_rma_size(uint64_t current_size,
return ram_size;
}
+static inline bool kvmppc_is_mem_backend_page_size_ok(char *obj_path)
+{
+ return true;
+}
+
#endif /* !CONFIG_USER_ONLY */
static inline bool kvmppc_has_cap_epr(void)
diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
index bb78fb5497..76669ed82c 100644
--- a/target/ppc/mmu-hash64.c
+++ b/target/ppc/mmu-hash64.c
@@ -115,7 +115,8 @@ void helper_slbia(CPUPPCState *env)
}
}
-void helper_slbie(CPUPPCState *env, target_ulong addr)
+static void __helper_slbie(CPUPPCState *env, target_ulong addr,
+ target_ulong global)
{
PowerPCCPU *cpu = ppc_env_get_cpu(env);
ppc_slb_t *slb;
@@ -132,10 +133,21 @@ void helper_slbie(CPUPPCState *env, target_ulong addr)
* and we still don't have a tlb_flush_mask(env, n, mask)
* in QEMU, we just invalidate all TLBs
*/
- env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
+ env->tlb_need_flush |=
+ (global == false ? TLB_NEED_LOCAL_FLUSH : TLB_NEED_GLOBAL_FLUSH);
}
}
+void helper_slbie(CPUPPCState *env, target_ulong addr)
+{
+ __helper_slbie(env, addr, false);
+}
+
+void helper_slbieg(CPUPPCState *env, target_ulong addr)
+{
+ __helper_slbie(env, addr, true);
+}
+
int ppc_store_slb(PowerPCCPU *cpu, target_ulong slot,
target_ulong esid, target_ulong vsid)
{
@@ -640,7 +652,15 @@ static void ppc_hash64_set_isi(CPUState *cs, CPUPPCState *env,
if (msr_ir) {
vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM1);
} else {
- vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM0);
+ 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;
+ }
}
if (vpm && !msr_hv) {
cs->exception_index = POWERPC_EXCP_HISI;
@@ -658,7 +678,15 @@ static void ppc_hash64_set_dsi(CPUState *cs, CPUPPCState *env, uint64_t dar,
if (msr_dr) {
vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM1);
} else {
- vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM0);
+ 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;
+ }
}
if (vpm && !msr_hv) {
cs->exception_index = POWERPC_EXCP_HDSI;
@@ -1050,6 +1078,14 @@ void helper_store_lpcr(CPUPPCState *env, target_ulong val)
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_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);
+ break;
default:
;
}
diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c
index f746f53615..eb2d482ef7 100644
--- a/target/ppc/mmu_helper.c
+++ b/target/ppc/mmu_helper.c
@@ -825,7 +825,7 @@ static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
tlb = &env->tlb.tlbe[i];
ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
access_type, i);
- if (!ret) {
+ if (ret != -1) {
break;
}
}
@@ -1935,6 +1935,7 @@ void ppc_tlb_invalidate_all(CPUPPCState *env)
case POWERPC_MMU_2_06a:
case POWERPC_MMU_2_07:
case POWERPC_MMU_2_07a:
+ case POWERPC_MMU_3_00:
#endif /* defined(TARGET_PPC64) */
env->tlb_need_flush = 0;
tlb_flush(CPU(cpu));
@@ -1974,6 +1975,7 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
case POWERPC_MMU_2_06a:
case POWERPC_MMU_2_07:
case POWERPC_MMU_2_07a:
+ case POWERPC_MMU_3_00:
/* tlbie invalidate TLBs for all segments */
/* XXX: given the fact that there are too many segments to invalidate,
* and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index b48abaedfb..3ba2616b8a 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -2976,6 +2976,113 @@ LARX(lbarx, DEF_MEMOP(MO_UB))
LARX(lharx, DEF_MEMOP(MO_UW))
LARX(lwarx, DEF_MEMOP(MO_UL))
+#define LD_ATOMIC(name, memop, tp, op, eop) \
+static void gen_##name(DisasContext *ctx) \
+{ \
+ int len = MEMOP_GET_SIZE(memop); \
+ uint32_t gpr_FC = FC(ctx->opcode); \
+ TCGv EA = tcg_temp_local_new(); \
+ TCGv_##tp t0, t1; \
+ \
+ gen_addr_register(ctx, EA); \
+ if (len > 1) { \
+ gen_check_align(ctx, EA, len - 1); \
+ } \
+ t0 = tcg_temp_new_##tp(); \
+ t1 = tcg_temp_new_##tp(); \
+ tcg_gen_##op(t0, cpu_gpr[rD(ctx->opcode) + 1]); \
+ \
+ switch (gpr_FC) { \
+ case 0: /* Fetch and add */ \
+ tcg_gen_atomic_fetch_add_##tp(t1, EA, t0, ctx->mem_idx, memop); \
+ break; \
+ case 1: /* Fetch and xor */ \
+ tcg_gen_atomic_fetch_xor_##tp(t1, EA, t0, ctx->mem_idx, memop); \
+ break; \
+ case 2: /* Fetch and or */ \
+ tcg_gen_atomic_fetch_or_##tp(t1, EA, t0, ctx->mem_idx, memop); \
+ break; \
+ case 3: /* Fetch and 'and' */ \
+ tcg_gen_atomic_fetch_and_##tp(t1, EA, t0, ctx->mem_idx, memop); \
+ break; \
+ case 8: /* Swap */ \
+ tcg_gen_atomic_xchg_##tp(t1, EA, t0, ctx->mem_idx, memop); \
+ break; \
+ case 4: /* Fetch and max unsigned */ \
+ case 5: /* Fetch and max signed */ \
+ case 6: /* Fetch and min unsigned */ \
+ case 7: /* Fetch and min signed */ \
+ case 16: /* compare and swap not equal */ \
+ case 24: /* Fetch and increment bounded */ \
+ case 25: /* Fetch and increment equal */ \
+ case 28: /* Fetch and decrement bounded */ \
+ gen_invalid(ctx); \
+ break; \
+ default: \
+ /* invoke data storage error handler */ \
+ gen_exception_err(ctx, POWERPC_EXCP_DSI, POWERPC_EXCP_INVAL); \
+ } \
+ tcg_gen_##eop(cpu_gpr[rD(ctx->opcode)], t1); \
+ tcg_temp_free_##tp(t0); \
+ tcg_temp_free_##tp(t1); \
+ tcg_temp_free(EA); \
+}
+
+LD_ATOMIC(lwat, DEF_MEMOP(MO_UL), i32, trunc_tl_i32, extu_i32_tl)
+#if defined(TARGET_PPC64)
+LD_ATOMIC(ldat, DEF_MEMOP(MO_Q), i64, mov_i64, mov_i64)
+#endif
+
+#define ST_ATOMIC(name, memop, tp, op) \
+static void gen_##name(DisasContext *ctx) \
+{ \
+ int len = MEMOP_GET_SIZE(memop); \
+ uint32_t gpr_FC = FC(ctx->opcode); \
+ TCGv EA = tcg_temp_local_new(); \
+ TCGv_##tp t0, t1; \
+ \
+ gen_addr_register(ctx, EA); \
+ if (len > 1) { \
+ gen_check_align(ctx, EA, len - 1); \
+ } \
+ t0 = tcg_temp_new_##tp(); \
+ t1 = tcg_temp_new_##tp(); \
+ tcg_gen_##op(t0, cpu_gpr[rD(ctx->opcode) + 1]); \
+ \
+ switch (gpr_FC) { \
+ case 0: /* add and Store */ \
+ tcg_gen_atomic_add_fetch_##tp(t1, EA, t0, ctx->mem_idx, memop); \
+ break; \
+ case 1: /* xor and Store */ \
+ tcg_gen_atomic_xor_fetch_##tp(t1, EA, t0, ctx->mem_idx, memop); \
+ break; \
+ case 2: /* Or and Store */ \
+ tcg_gen_atomic_or_fetch_##tp(t1, EA, t0, ctx->mem_idx, memop); \
+ break; \
+ case 3: /* 'and' and Store */ \
+ tcg_gen_atomic_and_fetch_##tp(t1, EA, t0, ctx->mem_idx, memop); \
+ break; \
+ case 4: /* Store max unsigned */ \
+ case 5: /* Store max signed */ \
+ case 6: /* Store min unsigned */ \
+ case 7: /* Store min signed */ \
+ case 24: /* Store twin */ \
+ gen_invalid(ctx); \
+ break; \
+ default: \
+ /* invoke data storage error handler */ \
+ gen_exception_err(ctx, POWERPC_EXCP_DSI, POWERPC_EXCP_INVAL); \
+ } \
+ tcg_temp_free_##tp(t0); \
+ tcg_temp_free_##tp(t1); \
+ tcg_temp_free(EA); \
+}
+
+ST_ATOMIC(stwat, DEF_MEMOP(MO_UL), i32, trunc_tl_i32)
+#if defined(TARGET_PPC64)
+ST_ATOMIC(stdat, DEF_MEMOP(MO_Q), i64, mov_i64)
+#endif
+
#if defined(CONFIG_USER_ONLY)
static void gen_conditional_store(DisasContext *ctx, TCGv EA,
int reg, int memop)
@@ -4377,6 +4484,30 @@ static void gen_slbie(DisasContext *ctx)
gen_helper_slbie(cpu_env, cpu_gpr[rB(ctx->opcode)]);
#endif /* defined(CONFIG_USER_ONLY) */
}
+
+/* slbieg */
+static void gen_slbieg(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+ GEN_PRIV;
+#else
+ CHK_SV;
+
+ gen_helper_slbieg(cpu_env, cpu_gpr[rB(ctx->opcode)]);
+#endif /* defined(CONFIG_USER_ONLY) */
+}
+
+/* slbsync */
+static void gen_slbsync(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+ GEN_PRIV;
+#else
+ CHK_SV;
+ gen_check_tlb_flush(ctx, true);
+#endif /* defined(CONFIG_USER_ONLY) */
+}
+
#endif /* defined(TARGET_PPC64) */
/*** External control ***/
@@ -6025,6 +6156,19 @@ static inline void gen_cp_abort(DisasContext *ctx)
// Do Nothing
}
+#define GEN_CP_PASTE_NOOP(name) \
+static inline void gen_##name(DisasContext *ctx) \
+{ \
+ /* Generate invalid exception until \
+ * we have an implementation of the copy \
+ * paste facility \
+ */ \
+ gen_invalid(ctx); \
+}
+
+GEN_CP_PASTE_NOOP(copy)
+GEN_CP_PASTE_NOOP(paste)
+
static void gen_tcheck(DisasContext *ctx)
{
if (unlikely(!ctx->tm_enabled)) {
@@ -6174,7 +6318,9 @@ GEN_HANDLER2(andi_, "andi.", 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
GEN_HANDLER2(andis_, "andis.", 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
GEN_HANDLER(cntlzw, 0x1F, 0x1A, 0x00, 0x00000000, PPC_INTEGER),
GEN_HANDLER_E(cnttzw, 0x1F, 0x1A, 0x10, 0x00000000, PPC_NONE, PPC2_ISA300),
+GEN_HANDLER_E(copy, 0x1F, 0x06, 0x18, 0x03C00001, PPC_NONE, PPC2_ISA300),
GEN_HANDLER_E(cp_abort, 0x1F, 0x06, 0x1A, 0x03FFF801, PPC_NONE, PPC2_ISA300),
+GEN_HANDLER_E(paste, 0x1F, 0x06, 0x1C, 0x03C00000, PPC_NONE, PPC2_ISA300),
GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER),
GEN_HANDLER(xor, 0x1F, 0x1C, 0x09, 0x00000000, PPC_INTEGER),
GEN_HANDLER(ori, 0x18, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
@@ -6230,10 +6376,14 @@ GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FFF801, PPC_MEM),
GEN_HANDLER_E(lbarx, 0x1F, 0x14, 0x01, 0, PPC_NONE, PPC2_ATOMIC_ISA206),
GEN_HANDLER_E(lharx, 0x1F, 0x14, 0x03, 0, PPC_NONE, PPC2_ATOMIC_ISA206),
GEN_HANDLER(lwarx, 0x1F, 0x14, 0x00, 0x00000000, PPC_RES),
+GEN_HANDLER_E(lwat, 0x1F, 0x06, 0x12, 0x00000001, PPC_NONE, PPC2_ISA300),
+GEN_HANDLER_E(stwat, 0x1F, 0x06, 0x16, 0x00000001, PPC_NONE, PPC2_ISA300),
GEN_HANDLER_E(stbcx_, 0x1F, 0x16, 0x15, 0, PPC_NONE, PPC2_ATOMIC_ISA206),
GEN_HANDLER_E(sthcx_, 0x1F, 0x16, 0x16, 0, PPC_NONE, PPC2_ATOMIC_ISA206),
GEN_HANDLER2(stwcx_, "stwcx.", 0x1F, 0x16, 0x04, 0x00000000, PPC_RES),
#if defined(TARGET_PPC64)
+GEN_HANDLER_E(ldat, 0x1F, 0x06, 0x13, 0x00000001, PPC_NONE, PPC2_ISA300),
+GEN_HANDLER_E(stdat, 0x1F, 0x06, 0x17, 0x00000001, PPC_NONE, PPC2_ISA300),
GEN_HANDLER(ldarx, 0x1F, 0x14, 0x02, 0x00000000, PPC_64B),
GEN_HANDLER_E(lqarx, 0x1F, 0x14, 0x08, 0, PPC_NONE, PPC2_LSQ_ISA207),
GEN_HANDLER2(stdcx_, "stdcx.", 0x1F, 0x16, 0x06, 0x00000000, PPC_64B),
@@ -6241,6 +6391,7 @@ GEN_HANDLER_E(stqcx_, 0x1F, 0x16, 0x05, 0, PPC_NONE, PPC2_LSQ_ISA207),
#endif
GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x039FF801, PPC_MEM_SYNC),
GEN_HANDLER(wait, 0x1F, 0x1E, 0x01, 0x03FFF801, PPC_WAIT),
+GEN_HANDLER_E(wait, 0x1F, 0x1E, 0x00, 0x039FF801, PPC_NONE, PPC2_ISA300),
GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW),
GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW),
GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW),
@@ -6313,6 +6464,8 @@ GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC),
#if defined(TARGET_PPC64)
GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x031FFC01, PPC_SLBI),
GEN_HANDLER(slbie, 0x1F, 0x12, 0x0D, 0x03FF0001, PPC_SLBI),
+GEN_HANDLER_E(slbieg, 0x1F, 0x12, 0x0E, 0x001F0001, PPC_NONE, PPC2_ISA300),
+GEN_HANDLER_E(slbsync, 0x1F, 0x12, 0x0A, 0x03FFF801, PPC_NONE, PPC2_ISA300),
#endif
GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN),
GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN),
diff --git a/target/ppc/translate/vsx-impl.inc.c b/target/ppc/translate/vsx-impl.inc.c
index a44c0034a8..7f12908029 100644
--- a/target/ppc/translate/vsx-impl.inc.c
+++ b/target/ppc/translate/vsx-impl.inc.c
@@ -808,6 +808,10 @@ GEN_VSX_HELPER_2(xscmpoqp, 0x04, 0x04, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xscmpuqp, 0x04, 0x14, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xsmaxdp, 0x00, 0x14, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xsmindp, 0x00, 0x15, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsmaxcdp, 0x00, 0x10, 0, PPC2_ISA300)
+GEN_VSX_HELPER_2(xsmincdp, 0x00, 0x11, 0, PPC2_ISA300)
+GEN_VSX_HELPER_2(xsmaxjdp, 0x00, 0x12, 0, PPC2_ISA300)
+GEN_VSX_HELPER_2(xsminjdp, 0x00, 0x12, 0, PPC2_ISA300)
GEN_VSX_HELPER_2(xscvdphp, 0x16, 0x15, 0x11, PPC2_ISA300)
GEN_VSX_HELPER_2(xscvdpsp, 0x12, 0x10, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xscvdpqp, 0x04, 0x1A, 0x16, PPC2_ISA300)
@@ -815,6 +819,8 @@ GEN_VSX_HELPER_XT_XB_ENV(xscvdpspn, 0x16, 0x10, 0, PPC2_VSX207)
GEN_VSX_HELPER_2(xscvqpdp, 0x04, 0x1A, 0x14, PPC2_ISA300)
GEN_VSX_HELPER_2(xscvqpsdz, 0x04, 0x1A, 0x19, PPC2_ISA300)
GEN_VSX_HELPER_2(xscvqpswz, 0x04, 0x1A, 0x09, PPC2_ISA300)
+GEN_VSX_HELPER_2(xscvqpudz, 0x04, 0x1A, 0x11, PPC2_ISA300)
+GEN_VSX_HELPER_2(xscvqpuwz, 0x04, 0x1A, 0x01, PPC2_ISA300)
GEN_VSX_HELPER_2(xscvhpdp, 0x16, 0x15, 0x10, PPC2_ISA300)
GEN_VSX_HELPER_2(xscvsdqp, 0x04, 0x1A, 0x0A, PPC2_ISA300)
GEN_VSX_HELPER_2(xscvspdp, 0x12, 0x14, 0, PPC2_VSX)
@@ -833,6 +839,11 @@ GEN_VSX_HELPER_2(xsrdpip, 0x12, 0x06, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xsrdpiz, 0x12, 0x05, 0, PPC2_VSX)
GEN_VSX_HELPER_XT_XB_ENV(xsrsp, 0x12, 0x11, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xsrqpi, 0x05, 0x00, 0, PPC2_ISA300)
+GEN_VSX_HELPER_2(xsrqpxp, 0x05, 0x01, 0, PPC2_ISA300)
+GEN_VSX_HELPER_2(xssqrtqp, 0x04, 0x19, 0x1B, PPC2_ISA300)
+GEN_VSX_HELPER_2(xssubqp, 0x04, 0x10, 0, PPC2_ISA300)
+
GEN_VSX_HELPER_2(xsaddsp, 0x00, 0x00, 0, PPC2_VSX207)
GEN_VSX_HELPER_2(xssubsp, 0x00, 0x01, 0, PPC2_VSX207)
GEN_VSX_HELPER_2(xsmulsp, 0x00, 0x02, 0, PPC2_VSX207)
diff --git a/target/ppc/translate/vsx-ops.inc.c b/target/ppc/translate/vsx-ops.inc.c
index 7dc9f6f477..5030c4aceb 100644
--- a/target/ppc/translate/vsx-ops.inc.c
+++ b/target/ppc/translate/vsx-ops.inc.c
@@ -103,6 +103,21 @@ GEN_HANDLER_E(name, 0x3F, opc2, opc3, inval, PPC_NONE, PPC2_ISA300)
#define GEN_VSX_XFORM_300_EO(name, opc2, opc3, opc4, inval) \
GEN_HANDLER_E_2(name, 0x3F, opc2, opc3, opc4, inval, PPC_NONE, PPC2_ISA300)
+#define GEN_VSX_Z23FORM_300(name, opc2, opc3, opc4, inval) \
+GEN_VSX_XFORM_300_EO(name, opc2, opc3 | 0x00, opc4 | 0x0, inval), \
+GEN_VSX_XFORM_300_EO(name, opc2, opc3 | 0x08, opc4 | 0x0, inval), \
+GEN_VSX_XFORM_300_EO(name, opc2, opc3 | 0x10, opc4 | 0x0, inval), \
+GEN_VSX_XFORM_300_EO(name, opc2, opc3 | 0x18, opc4 | 0x0, inval), \
+GEN_VSX_XFORM_300_EO(name, opc2, opc3 | 0x00, opc4 | 0x1, inval), \
+GEN_VSX_XFORM_300_EO(name, opc2, opc3 | 0x08, opc4 | 0x1, inval), \
+GEN_VSX_XFORM_300_EO(name, opc2, opc3 | 0x10, opc4 | 0x1, inval), \
+GEN_VSX_XFORM_300_EO(name, opc2, opc3 | 0x18, opc4 | 0x1, inval)
+
+GEN_VSX_Z23FORM_300(xsrqpi, 0x05, 0x0, 0x0, 0x0),
+GEN_VSX_Z23FORM_300(xsrqpxp, 0x05, 0x1, 0x0, 0x0),
+GEN_VSX_XFORM_300_EO(xssqrtqp, 0x04, 0x19, 0x1B, 0x0),
+GEN_VSX_XFORM_300(xssubqp, 0x04, 0x10, 0x0),
+
GEN_XX2FORM(xsabsdp, 0x12, 0x15, PPC2_VSX),
GEN_XX2FORM(xsnabsdp, 0x12, 0x16, PPC2_VSX),
GEN_XX2FORM(xsnegdp, 0x12, 0x17, PPC2_VSX),
@@ -116,6 +131,8 @@ GEN_VSX_XFORM_300_EO(xscvdpqp, 0x04, 0x1A, 0x16, 0x00000001),
GEN_VSX_XFORM_300_EO(xscvqpdp, 0x04, 0x1A, 0x14, 0x0),
GEN_VSX_XFORM_300_EO(xscvqpsdz, 0x04, 0x1A, 0x19, 0x00000001),
GEN_VSX_XFORM_300_EO(xscvqpswz, 0x04, 0x1A, 0x09, 0x00000001),
+GEN_VSX_XFORM_300_EO(xscvqpudz, 0x04, 0x1A, 0x11, 0x00000001),
+GEN_VSX_XFORM_300_EO(xscvqpuwz, 0x04, 0x1A, 0x01, 0x00000001),
#ifdef TARGET_PPC64
GEN_XX2FORM_EO(xsxexpdp, 0x16, 0x15, 0x00, PPC2_ISA300),
@@ -185,6 +202,10 @@ GEN_VSX_XFORM_300(xscmpoqp, 0x04, 0x04, 0x00600001),
GEN_VSX_XFORM_300(xscmpuqp, 0x04, 0x14, 0x00600001),
GEN_XX3FORM(xsmaxdp, 0x00, 0x14, PPC2_VSX),
GEN_XX3FORM(xsmindp, 0x00, 0x15, PPC2_VSX),
+GEN_XX3FORM(xsmaxcdp, 0x00, 0x10, PPC2_ISA300),
+GEN_XX3FORM(xsmincdp, 0x00, 0x11, PPC2_ISA300),
+GEN_XX3FORM(xsmaxjdp, 0x00, 0x12, PPC2_ISA300),
+GEN_XX3FORM(xsminjdp, 0x00, 0x13, PPC2_ISA300),
GEN_XX2FORM_EO(xscvdphp, 0x16, 0x15, 0x11, PPC2_ISA300),
GEN_XX2FORM(xscvdpsp, 0x12, 0x10, PPC2_VSX),
GEN_XX2FORM(xscvdpspn, 0x16, 0x10, PPC2_VSX207),
diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c
index 76f79fa77b..be35cbd3a2 100644
--- a/target/ppc/translate_init.c
+++ b/target/ppc/translate_init.c
@@ -8816,8 +8816,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
(1ull << MSR_PMM) |
(1ull << MSR_RI) |
(1ull << MSR_LE);
- /* Using 2.07 defines until new radix model is added. */
- pcc->mmu_model = POWERPC_MMU_2_07;
+ pcc->mmu_model = POWERPC_MMU_3_00;
#if defined(CONFIG_SOFTMMU)
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
/* segment page size remain the same */
@@ -8871,12 +8870,24 @@ void cpu_ppc_set_papr(PowerPCCPU *cpu)
lpcr->default_value &= ~LPCR_RMLS;
lpcr->default_value |= 1ull << LPCR_RMLS_SHIFT;
- /* P7 and P8 has slightly different PECE bits, mostly because P8 adds
- * bit 47 and 48 which are reserved on P7. Here we set them all, which
- * will work as expected for both implementations
- */
- lpcr->default_value |= LPCR_P8_PECE0 | LPCR_P8_PECE1 | LPCR_P8_PECE2 |
- LPCR_P8_PECE3 | LPCR_P8_PECE4;
+ switch (env->mmu_model) {
+ case POWERPC_MMU_3_00:
+ /* By default we choose legacy mode and switch to new hash or radix
+ * when a register process table hcall is made. So disable process
+ * tables and guest translation shootdown by default
+ */
+ lpcr->default_value &= ~(LPCR_UPRT | LPCR_GTSE);
+ lpcr->default_value |= LPCR_PDEE | LPCR_HDEE | LPCR_EEE | LPCR_DEE |
+ LPCR_OEE;
+ break;
+ default:
+ /* P7 and P8 has slightly different PECE bits, mostly because P8 adds
+ * bit 47 and 48 which are reserved on P7. Here we set them all, which
+ * will work as expected for both implementations
+ */
+ lpcr->default_value |= LPCR_P8_PECE0 | LPCR_P8_PECE1 | LPCR_P8_PECE2 |
+ LPCR_P8_PECE3 | LPCR_P8_PECE4;
+ }
/* We should be followed by a CPU reset but update the active value
* just in case...
diff --git a/tests/check-qdict.c b/tests/check-qdict.c
index 07b1c798d8..81162ee572 100644
--- a/tests/check-qdict.c
+++ b/tests/check-qdict.c
@@ -591,7 +591,6 @@ static void qdict_join_test(void)
static void qdict_crumple_test_recursive(void)
{
QDict *src, *dst, *rule, *vnc, *acl, *listen;
- QObject *child, *res;
QList *rules;
src = qdict_new();
@@ -605,40 +604,37 @@ static void qdict_crumple_test_recursive(void)
qdict_put(src, "vnc.acl..name", qstring_from_str("acl0"));
qdict_put(src, "vnc.acl.rule..name", qstring_from_str("acl0"));
- res = qdict_crumple(src, &error_abort);
-
- g_assert_cmpint(qobject_type(res), ==, QTYPE_QDICT);
-
- dst = qobject_to_qdict(res);
-
+ dst = qobject_to_qdict(qdict_crumple(src, &error_abort));
+ g_assert(dst);
g_assert_cmpint(qdict_size(dst), ==, 1);
- child = qdict_get(dst, "vnc");
- g_assert_cmpint(qobject_type(child), ==, QTYPE_QDICT);
- vnc = qobject_to_qdict(child);
+ vnc = qdict_get_qdict(dst, "vnc");
+ g_assert(vnc);
+ g_assert_cmpint(qdict_size(vnc), ==, 3);
- child = qdict_get(vnc, "listen");
- g_assert_cmpint(qobject_type(child), ==, QTYPE_QDICT);
- listen = qobject_to_qdict(child);
+ listen = qdict_get_qdict(vnc, "listen");
+ g_assert(listen);
+ g_assert_cmpint(qdict_size(listen), ==, 2);
g_assert_cmpstr("127.0.0.1", ==, qdict_get_str(listen, "addr"));
g_assert_cmpstr("5901", ==, qdict_get_str(listen, "port"));
- child = qdict_get(vnc, "acl");
- g_assert_cmpint(qobject_type(child), ==, QTYPE_QDICT);
- acl = qobject_to_qdict(child);
+ acl = qdict_get_qdict(vnc, "acl");
+ g_assert(acl);
+ g_assert_cmpint(qdict_size(acl), ==, 3);
- child = qdict_get(acl, "rules");
- g_assert_cmpint(qobject_type(child), ==, QTYPE_QLIST);
- rules = qobject_to_qlist(child);
+ rules = qdict_get_qlist(acl, "rules");
+ g_assert(rules);
g_assert_cmpint(qlist_size(rules), ==, 2);
rule = qobject_to_qdict(qlist_pop(rules));
+ g_assert(rule);
g_assert_cmpint(qdict_size(rule), ==, 2);
g_assert_cmpstr("fred", ==, qdict_get_str(rule, "match"));
g_assert_cmpstr("allow", ==, qdict_get_str(rule, "policy"));
QDECREF(rule);
rule = qobject_to_qdict(qlist_pop(rules));
+ g_assert(rule);
g_assert_cmpint(qdict_size(rule), ==, 2);
g_assert_cmpstr("bob", ==, qdict_get_str(rule, "match"));
g_assert_cmpstr("deny", ==, qdict_get_str(rule, "policy"));
@@ -646,9 +642,6 @@ static void qdict_crumple_test_recursive(void)
/* With recursive crumpling, we should see all names unescaped */
g_assert_cmpstr("acl0", ==, qdict_get_str(vnc, "acl.name"));
- child = qdict_get(vnc, "acl");
- g_assert_cmpint(qobject_type(child), ==, QTYPE_QDICT);
- acl = qdict_get_qdict(vnc, "acl");
g_assert_cmpstr("acl0", ==, qdict_get_str(acl, "rule.name"));
QDECREF(src);
diff --git a/tests/check-qjson.c b/tests/check-qjson.c
index 0b21a22e10..e6d6935653 100644
--- a/tests/check-qjson.c
+++ b/tests/check-qjson.c
@@ -54,11 +54,8 @@ static void escaped_string(void)
QString *str;
obj = qobject_from_json(test_cases[i].encoded);
-
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QSTRING);
-
str = qobject_to_qstring(obj);
+ g_assert(str);
g_assert_cmpstr(qstring_get_str(str), ==, test_cases[i].decoded);
if (test_cases[i].skip == 0) {
@@ -89,11 +86,8 @@ static void simple_string(void)
QString *str;
obj = qobject_from_json(test_cases[i].encoded);
-
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QSTRING);
-
str = qobject_to_qstring(obj);
+ g_assert(str);
g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
str = qobject_to_json(obj);
@@ -123,11 +117,8 @@ static void single_quote_string(void)
QString *str;
obj = qobject_from_json(test_cases[i].encoded);
-
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QSTRING);
-
str = qobject_to_qstring(obj);
+ g_assert(str);
g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
QDECREF(str);
@@ -820,9 +811,8 @@ static void utf8_string(void)
obj = qobject_from_json(json_in);
if (utf8_out) {
- g_assert(obj);
- g_assert(qobject_type(obj) == QTYPE_QSTRING);
str = qobject_to_qstring(obj);
+ g_assert(str);
g_assert_cmpstr(qstring_get_str(str), ==, utf8_out);
} else {
g_assert(!obj);
@@ -847,9 +837,8 @@ static void utf8_string(void)
*/
if (0 && json_out != json_in) {
obj = qobject_from_json(json_out);
- g_assert(obj);
- g_assert(qobject_type(obj) == QTYPE_QSTRING);
str = qobject_to_qstring(obj);
+ g_assert(str);
g_assert_cmpstr(qstring_get_str(str), ==, utf8_out);
}
}
@@ -867,15 +856,11 @@ static void vararg_string(void)
};
for (i = 0; test_cases[i].decoded; i++) {
- QObject *obj;
QString *str;
- obj = qobject_from_jsonf("%s", test_cases[i].decoded);
-
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QSTRING);
-
- str = qobject_to_qstring(obj);
+ str = qobject_to_qstring(qobject_from_jsonf("%s",
+ test_cases[i].decoded));
+ g_assert(str);
g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
QDECREF(str);
@@ -899,19 +884,15 @@ static void simple_number(void)
};
for (i = 0; test_cases[i].encoded; i++) {
- QObject *obj;
QInt *qint;
- obj = qobject_from_json(test_cases[i].encoded);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QINT);
-
- qint = qobject_to_qint(obj);
+ qint = qobject_to_qint(qobject_from_json(test_cases[i].encoded));
+ g_assert(qint);
g_assert(qint_get_int(qint) == test_cases[i].decoded);
if (test_cases[i].skip == 0) {
QString *str;
- str = qobject_to_json(obj);
+ str = qobject_to_json(QOBJECT(qint));
g_assert(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
QDECREF(str);
}
@@ -940,10 +921,8 @@ static void float_number(void)
QFloat *qfloat;
obj = qobject_from_json(test_cases[i].encoded);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QFLOAT);
-
qfloat = qobject_to_qfloat(obj);
+ g_assert(qfloat);
g_assert(qfloat_get_double(qfloat) == test_cases[i].decoded);
if (test_cases[i].skip == 0) {
@@ -960,38 +939,22 @@ static void float_number(void)
static void vararg_number(void)
{
- QObject *obj;
QInt *qint;
QFloat *qfloat;
int value = 0x2342;
long long value_ll = 0x2342342343LL;
double valuef = 2.323423423;
- obj = qobject_from_jsonf("%d", value);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QINT);
-
- qint = qobject_to_qint(obj);
+ qint = qobject_to_qint(qobject_from_jsonf("%d", value));
g_assert(qint_get_int(qint) == value);
-
QDECREF(qint);
- obj = qobject_from_jsonf("%lld", value_ll);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QINT);
-
- qint = qobject_to_qint(obj);
+ qint = qobject_to_qint(qobject_from_jsonf("%lld", value_ll));
g_assert(qint_get_int(qint) == value_ll);
-
QDECREF(qint);
- obj = qobject_from_jsonf("%f", valuef);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QFLOAT);
-
- qfloat = qobject_to_qfloat(obj);
+ qfloat = qobject_to_qfloat(qobject_from_jsonf("%f", valuef));
g_assert(qfloat_get_double(qfloat) == valuef);
-
QDECREF(qfloat);
}
@@ -1003,10 +966,8 @@ static void keyword_literal(void)
QString *str;
obj = qobject_from_json("true");
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QBOOL);
-
qbool = qobject_to_qbool(obj);
+ g_assert(qbool);
g_assert(qbool_get_bool(qbool) == true);
str = qobject_to_json(obj);
@@ -1016,10 +977,8 @@ static void keyword_literal(void)
QDECREF(qbool);
obj = qobject_from_json("false");
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QBOOL);
-
qbool = qobject_to_qbool(obj);
+ g_assert(qbool);
g_assert(qbool_get_bool(qbool) == false);
str = qobject_to_json(obj);
@@ -1028,23 +987,15 @@ static void keyword_literal(void)
QDECREF(qbool);
- obj = qobject_from_jsonf("%i", false);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QBOOL);
-
- qbool = qobject_to_qbool(obj);
+ qbool = qobject_to_qbool(qobject_from_jsonf("%i", false));
+ g_assert(qbool);
g_assert(qbool_get_bool(qbool) == false);
-
QDECREF(qbool);
/* Test that non-zero values other than 1 get collapsed to true */
- obj = qobject_from_jsonf("%i", 2);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QBOOL);
-
- qbool = qobject_to_qbool(obj);
+ qbool = qobject_to_qbool(qobject_from_jsonf("%i", 2));
+ g_assert(qbool);
g_assert(qbool_get_bool(qbool) == true);
-
QDECREF(qbool);
obj = qobject_from_json("null");
@@ -1110,7 +1061,7 @@ static void compare_helper(QObject *obj, void *opaque)
static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs)
{
- if (lhs->type != qobject_type(rhs)) {
+ if (!rhs || lhs->type != qobject_type(rhs)) {
return 0;
}
@@ -1184,18 +1135,12 @@ static void simple_dict(void)
QString *str;
obj = qobject_from_json(test_cases[i].encoded);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QDICT);
-
g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
str = qobject_to_json(obj);
qobject_decref(obj);
obj = qobject_from_json(qstring_get_str(str));
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QDICT);
-
g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
qobject_decref(obj);
QDECREF(str);
@@ -1299,18 +1244,12 @@ static void simple_list(void)
QString *str;
obj = qobject_from_json(test_cases[i].encoded);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QLIST);
-
g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
str = qobject_to_json(obj);
qobject_decref(obj);
obj = qobject_from_json(qstring_get_str(str));
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QLIST);
-
g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
qobject_decref(obj);
QDECREF(str);
@@ -1367,18 +1306,12 @@ static void simple_whitespace(void)
QString *str;
obj = qobject_from_json(test_cases[i].encoded);
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QLIST);
-
g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
str = qobject_to_json(obj);
qobject_decref(obj);
obj = qobject_from_json(qstring_get_str(str));
- g_assert(obj != NULL);
- g_assert(qobject_type(obj) == QTYPE_QLIST);
-
g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
qobject_decref(obj);
@@ -1403,8 +1336,6 @@ static void simple_varargs(void)
g_assert(embedded_obj != NULL);
obj = qobject_from_jsonf("[%d, 2, %p]", 1, embedded_obj);
- g_assert(obj != NULL);
-
g_assert(compare_litqobj_to_qobj(&decoded, obj) == 1);
qobject_decref(obj);
diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include
index 3f15d5aea8..03eda37bf4 100644
--- a/tests/docker/Makefile.include
+++ b/tests/docker/Makefile.include
@@ -50,9 +50,14 @@ docker-image-%: $(DOCKER_FILES_DIR)/%.docker
$(call quiet-command,\
$(SRC_PATH)/tests/docker/docker.py build qemu:$* $< \
$(if $V,,--quiet) $(if $(NOCACHE),--no-cache) \
+ $(if $(NOUSER),,--add-current-user) \
$(if $(EXECUTABLE),--include-executable=$(EXECUTABLE)),\
"BUILD","$*")
+# Enforce dependancies for composite images
+docker-image-debian-armhf-cross: docker-image-debian
+docker-image-debian-arm64-cross: docker-image-debian
+
# Expand all the pre-requistes for each docker image and test combination
$(foreach i,$(DOCKER_IMAGES), \
$(foreach t,$(DOCKER_TESTS) $(DOCKER_TOOLS), \
@@ -99,6 +104,7 @@ docker:
@echo ' (default is 1)'
@echo ' DEBUG=1 Stop and drop to shell in the created container'
@echo ' before running the command.'
+ @echo ' NOUSER Define to disable adding current user to containers passwd.'
@echo ' NOCACHE=1 Ignore cache when build images.'
@echo ' EXECUTABLE=<path> Include executable in image.'
diff --git a/tests/docker/common.rc b/tests/docker/common.rc
index 21657e87c6..6865689bb5 100755
--- a/tests/docker/common.rc
+++ b/tests/docker/common.rc
@@ -29,7 +29,7 @@ build_qemu()
config_opts="--enable-werror \
${TARGET_LIST:+--target-list=${TARGET_LIST}} \
--prefix=$PWD/install \
- $EXTRA_CONFIGURE_OPTS \
+ $QEMU_CONFIGURE_OPTS $EXTRA_CONFIGURE_OPTS \
$@"
echo "Configure options:"
echo $config_opts
diff --git a/tests/docker/docker.py b/tests/docker/docker.py
index 37d83199e7..9fd32ab5fa 100755
--- a/tests/docker/docker.py
+++ b/tests/docker/docker.py
@@ -25,6 +25,7 @@ import signal
from tarfile import TarFile, TarInfo
from StringIO import StringIO
from shutil import copy, rmtree
+from pwd import getpwuid
DEVNULL = open(os.devnull, 'wb')
@@ -149,13 +150,21 @@ class Docker(object):
labels = json.loads(resp)[0]["Config"].get("Labels", {})
return labels.get("com.qemu.dockerfile-checksum", "")
- def build_image(self, tag, docker_dir, dockerfile, quiet=True, argv=None):
+ def build_image(self, tag, docker_dir, dockerfile,
+ quiet=True, user=False, argv=None):
if argv == None:
argv = []
tmp_df = tempfile.NamedTemporaryFile(dir=docker_dir, suffix=".docker")
tmp_df.write(dockerfile)
+ if user:
+ uid = os.getuid()
+ uname = getpwuid(uid).pw_name
+ tmp_df.write("\n")
+ tmp_df.write("RUN id %s 2>/dev/null || useradd -u %d -U %s" %
+ (uname, uid, uname))
+
tmp_df.write("\n")
tmp_df.write("LABEL com.qemu.dockerfile-checksum=%s" %
_text_checksum(dockerfile))
@@ -225,6 +234,9 @@ class BuildCommand(SubCommand):
help="""Specify a binary that will be copied to the
container together with all its dependent
libraries""")
+ parser.add_argument("--add-current-user", "-u", dest="user",
+ action="store_true",
+ help="Add the current user to image's passwd")
parser.add_argument("tag",
help="Image Tag")
parser.add_argument("dockerfile",
@@ -261,7 +273,7 @@ class BuildCommand(SubCommand):
docker_dir)
dkr.build_image(tag, docker_dir, dockerfile,
- quiet=args.quiet, argv=argv)
+ quiet=args.quiet, user=args.user, argv=argv)
rmtree(docker_dir)
diff --git a/tests/docker/dockerfiles/debian-arm64-cross.docker b/tests/docker/dockerfiles/debian-arm64-cross.docker
new file mode 100644
index 0000000000..592b5d7055
--- /dev/null
+++ b/tests/docker/dockerfiles/debian-arm64-cross.docker
@@ -0,0 +1,15 @@
+#
+# Docker arm64 cross-compiler target
+#
+# This docker target builds on the base debian image.
+#
+FROM qemu:debian
+
+# Add the foreign architecture we want and install dependencies
+RUN dpkg --add-architecture arm64
+RUN apt update
+RUN apt install -yy crossbuild-essential-arm64
+RUN apt-get build-dep -yy -a arm64 qemu
+
+# Specify the cross prefix for this image (see tests/docker/common.rc)
+ENV QEMU_CONFIGURE_OPTS --cross-prefix=aarch64-linux-gnu-
diff --git a/tests/docker/dockerfiles/debian-armhf-cross.docker b/tests/docker/dockerfiles/debian-armhf-cross.docker
new file mode 100644
index 0000000000..668d60aeb3
--- /dev/null
+++ b/tests/docker/dockerfiles/debian-armhf-cross.docker
@@ -0,0 +1,15 @@
+#
+# Docker armhf cross-compiler target
+#
+# This docker target builds on the base debian image.
+#
+FROM qemu:debian
+
+# Add the foreign architecture we want and install dependencies
+RUN dpkg --add-architecture armhf
+RUN apt update
+RUN apt install -yy crossbuild-essential-armhf
+RUN apt-get build-dep -yy -a armhf qemu
+
+# Specify the cross prefix for this image (see tests/docker/common.rc)
+ENV QEMU_CONFIGURE_OPTS --cross-prefix=arm-linux-gnueabihf-
diff --git a/tests/docker/dockerfiles/debian.docker b/tests/docker/dockerfiles/debian.docker
new file mode 100644
index 0000000000..52bd79938e
--- /dev/null
+++ b/tests/docker/dockerfiles/debian.docker
@@ -0,0 +1,25 @@
+#
+# Docker multiarch cross-compiler target
+#
+# This docker target is builds on Debian and Emdebian's cross compiler targets
+# to build distro with a selection of cross compilers for building test binaries.
+#
+# On its own you can't build much but the docker-foo-cross targets
+# build on top of the base debian image.
+#
+FROM debian:stable-slim
+
+# Setup some basic tools we need
+RUN apt update
+RUN apt install -yy curl aptitude
+
+# Setup Emdebian
+RUN echo "deb http://emdebian.org/tools/debian/ jessie main" >> /etc/apt/sources.list
+RUN curl http://emdebian.org/tools/debian/emdebian-toolchain-archive.key | apt-key add -
+
+# Duplicate deb line as deb-src
+RUN cat /etc/apt/sources.list | sed "s/deb/deb-src/" >> /etc/apt/sources.list
+
+# Install common build utilities
+RUN apt update
+RUN apt install -yy build-essential clang
diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker
index 478163b8d8..c4f80ad3d8 100644
--- a/tests/docker/dockerfiles/fedora.docker
+++ b/tests/docker/dockerfiles/fedora.docker
@@ -1,6 +1,6 @@
FROM fedora:latest
ENV PACKAGES \
- ccache git tar PyYAML sparse flex bison \
+ ccache git tar PyYAML sparse flex bison python2 \
glib2-devel pixman-devel zlib-devel SDL-devel libfdt-devel \
gcc gcc-c++ clang make perl which bc findutils \
mingw32-pixman mingw32-glib2 mingw32-gmp mingw32-SDL mingw32-pkg-config \
diff --git a/tests/libqtest.c b/tests/libqtest.c
index d8fba6647a..e54354de8a 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -379,9 +379,9 @@ static void qmp_response(JSONMessageParser *parser, GQueue *tokens)
exit(1);
}
- g_assert(qobject_type(obj) == QTYPE_QDICT);
g_assert(!qmp->response);
- qmp->response = (QDict *)obj;
+ qmp->response = qobject_to_qdict(obj);
+ g_assert(qmp->response);
}
QDict *qmp_fd_receive(int fd)
diff --git a/tests/test-cutils.c b/tests/test-cutils.c
index 20b0f59ba2..f64a49b7fb 100644
--- a/tests/test-cutils.c
+++ b/tests/test-cutils.c
@@ -262,6 +262,7 @@ static void test_qemu_strtol_empty(void)
err = qemu_strtol(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == str);
}
static void test_qemu_strtol_whitespace(void)
@@ -275,6 +276,7 @@ static void test_qemu_strtol_whitespace(void)
err = qemu_strtol(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == str);
}
static void test_qemu_strtol_invalid(void)
@@ -288,6 +290,7 @@ static void test_qemu_strtol_invalid(void)
err = qemu_strtol(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == str);
}
static void test_qemu_strtol_trailing(void)
@@ -520,7 +523,7 @@ static void test_qemu_strtoul_correct(void)
err = qemu_strtoul(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, 12345);
+ g_assert_cmpuint(res, ==, 12345);
g_assert(endptr == str + 5);
}
@@ -548,6 +551,7 @@ static void test_qemu_strtoul_empty(void)
err = qemu_strtoul(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == str);
}
static void test_qemu_strtoul_whitespace(void)
@@ -561,6 +565,7 @@ static void test_qemu_strtoul_whitespace(void)
err = qemu_strtoul(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == str);
}
static void test_qemu_strtoul_invalid(void)
@@ -574,6 +579,7 @@ static void test_qemu_strtoul_invalid(void)
err = qemu_strtoul(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == str);
}
static void test_qemu_strtoul_trailing(void)
@@ -587,7 +593,7 @@ static void test_qemu_strtoul_trailing(void)
err = qemu_strtoul(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, 123);
+ g_assert_cmpuint(res, ==, 123);
g_assert(endptr == str + 3);
}
@@ -602,7 +608,7 @@ static void test_qemu_strtoul_octal(void)
err = qemu_strtoul(str, &endptr, 8, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, 0123);
+ g_assert_cmpuint(res, ==, 0123);
g_assert(endptr == str + strlen(str));
res = 999;
@@ -610,7 +616,7 @@ static void test_qemu_strtoul_octal(void)
err = qemu_strtoul(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, 0123);
+ g_assert_cmpuint(res, ==, 0123);
g_assert(endptr == str + strlen(str));
}
@@ -625,7 +631,7 @@ static void test_qemu_strtoul_decimal(void)
err = qemu_strtoul(str, &endptr, 10, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, 123);
+ g_assert_cmpuint(res, ==, 123);
g_assert(endptr == str + strlen(str));
str = "123";
@@ -634,7 +640,7 @@ static void test_qemu_strtoul_decimal(void)
err = qemu_strtoul(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, 123);
+ g_assert_cmpuint(res, ==, 123);
g_assert(endptr == str + strlen(str));
}
@@ -649,7 +655,7 @@ static void test_qemu_strtoul_hex(void)
err = qemu_strtoul(str, &endptr, 16, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, 0x123);
+ g_assert_cmphex(res, ==, 0x123);
g_assert(endptr == str + strlen(str));
str = "0x123";
@@ -658,7 +664,7 @@ static void test_qemu_strtoul_hex(void)
err = qemu_strtoul(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, 0x123);
+ g_assert_cmphex(res, ==, 0x123);
g_assert(endptr == str + strlen(str));
}
@@ -673,7 +679,7 @@ static void test_qemu_strtoul_max(void)
err = qemu_strtoul(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, ULONG_MAX);
+ g_assert_cmphex(res, ==, ULONG_MAX);
g_assert(endptr == str + strlen(str));
g_free(str);
}
@@ -689,7 +695,7 @@ static void test_qemu_strtoul_overflow(void)
err = qemu_strtoul(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, -ERANGE);
- g_assert_cmpint(res, ==, ULONG_MAX);
+ g_assert_cmphex(res, ==, ULONG_MAX);
g_assert(endptr == str + strlen(str));
}
@@ -704,7 +710,7 @@ static void test_qemu_strtoul_underflow(void)
err = qemu_strtoul(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, -ERANGE);
- g_assert_cmpint(res, ==, -1ul);
+ g_assert_cmpuint(res, ==, -1ul);
g_assert(endptr == str + strlen(str));
}
@@ -719,7 +725,7 @@ static void test_qemu_strtoul_negative(void)
err = qemu_strtoul(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, -321ul);
+ g_assert_cmpuint(res, ==, -321ul);
g_assert(endptr == str + strlen(str));
}
@@ -732,7 +738,7 @@ static void test_qemu_strtoul_full_correct(void)
err = qemu_strtoul(str, NULL, 0, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, 123);
+ g_assert_cmpuint(res, ==, 123);
}
static void test_qemu_strtoul_full_null(void)
@@ -763,7 +769,7 @@ static void test_qemu_strtoul_full_negative(void)
err = qemu_strtoul(str, NULL, 0, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, -321ul);
+ g_assert_cmpuint(res, ==, -321ul);
}
static void test_qemu_strtoul_full_trailing(void)
@@ -786,11 +792,11 @@ static void test_qemu_strtoul_full_max(void)
err = qemu_strtoul(str, NULL, 0, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, ULONG_MAX);
+ g_assert_cmphex(res, ==, ULONG_MAX);
g_free(str);
}
-static void test_qemu_strtoll_correct(void)
+static void test_qemu_strtoi64_correct(void)
{
const char *str = "12345 foo";
char f = 'X';
@@ -798,27 +804,27 @@ static void test_qemu_strtoll_correct(void)
int64_t res = 999;
int err;
- err = qemu_strtoll(str, &endptr, 0, &res);
+ err = qemu_strtoi64(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, 0);
g_assert_cmpint(res, ==, 12345);
g_assert(endptr == str + 5);
}
-static void test_qemu_strtoll_null(void)
+static void test_qemu_strtoi64_null(void)
{
char f = 'X';
const char *endptr = &f;
int64_t res = 999;
int err;
- err = qemu_strtoll(NULL, &endptr, 0, &res);
+ err = qemu_strtoi64(NULL, &endptr, 0, &res);
g_assert_cmpint(err, ==, -EINVAL);
g_assert(endptr == NULL);
}
-static void test_qemu_strtoll_empty(void)
+static void test_qemu_strtoi64_empty(void)
{
const char *str = "";
char f = 'X';
@@ -826,12 +832,13 @@ static void test_qemu_strtoll_empty(void)
int64_t res = 999;
int err;
- err = qemu_strtoll(str, &endptr, 0, &res);
+ err = qemu_strtoi64(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == str);
}
-static void test_qemu_strtoll_whitespace(void)
+static void test_qemu_strtoi64_whitespace(void)
{
const char *str = " \t ";
char f = 'X';
@@ -839,12 +846,13 @@ static void test_qemu_strtoll_whitespace(void)
int64_t res = 999;
int err;
- err = qemu_strtoll(str, &endptr, 0, &res);
+ err = qemu_strtoi64(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == str);
}
-static void test_qemu_strtoll_invalid(void)
+static void test_qemu_strtoi64_invalid(void)
{
const char *str = " xxxx \t abc";
char f = 'X';
@@ -852,12 +860,13 @@ static void test_qemu_strtoll_invalid(void)
int64_t res = 999;
int err;
- err = qemu_strtoll(str, &endptr, 0, &res);
+ err = qemu_strtoi64(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == str);
}
-static void test_qemu_strtoll_trailing(void)
+static void test_qemu_strtoi64_trailing(void)
{
const char *str = "123xxx";
char f = 'X';
@@ -865,14 +874,14 @@ static void test_qemu_strtoll_trailing(void)
int64_t res = 999;
int err;
- err = qemu_strtoll(str, &endptr, 0, &res);
+ err = qemu_strtoi64(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, 0);
g_assert_cmpint(res, ==, 123);
g_assert(endptr == str + 3);
}
-static void test_qemu_strtoll_octal(void)
+static void test_qemu_strtoi64_octal(void)
{
const char *str = "0123";
char f = 'X';
@@ -880,7 +889,7 @@ static void test_qemu_strtoll_octal(void)
int64_t res = 999;
int err;
- err = qemu_strtoll(str, &endptr, 8, &res);
+ err = qemu_strtoi64(str, &endptr, 8, &res);
g_assert_cmpint(err, ==, 0);
g_assert_cmpint(res, ==, 0123);
@@ -888,14 +897,14 @@ static void test_qemu_strtoll_octal(void)
endptr = &f;
res = 999;
- err = qemu_strtoll(str, &endptr, 0, &res);
+ err = qemu_strtoi64(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, 0);
g_assert_cmpint(res, ==, 0123);
g_assert(endptr == str + strlen(str));
}
-static void test_qemu_strtoll_decimal(void)
+static void test_qemu_strtoi64_decimal(void)
{
const char *str = "0123";
char f = 'X';
@@ -903,7 +912,7 @@ static void test_qemu_strtoll_decimal(void)
int64_t res = 999;
int err;
- err = qemu_strtoll(str, &endptr, 10, &res);
+ err = qemu_strtoi64(str, &endptr, 10, &res);
g_assert_cmpint(err, ==, 0);
g_assert_cmpint(res, ==, 123);
@@ -912,14 +921,14 @@ static void test_qemu_strtoll_decimal(void)
str = "123";
endptr = &f;
res = 999;
- err = qemu_strtoll(str, &endptr, 0, &res);
+ err = qemu_strtoi64(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, 0);
g_assert_cmpint(res, ==, 123);
g_assert(endptr == str + strlen(str));
}
-static void test_qemu_strtoll_hex(void)
+static void test_qemu_strtoi64_hex(void)
{
const char *str = "0123";
char f = 'X';
@@ -927,7 +936,7 @@ static void test_qemu_strtoll_hex(void)
int64_t res = 999;
int err;
- err = qemu_strtoll(str, &endptr, 16, &res);
+ err = qemu_strtoi64(str, &endptr, 16, &res);
g_assert_cmpint(err, ==, 0);
g_assert_cmpint(res, ==, 0x123);
@@ -936,14 +945,14 @@ static void test_qemu_strtoll_hex(void)
str = "0x123";
endptr = &f;
res = 999;
- err = qemu_strtoll(str, &endptr, 0, &res);
+ err = qemu_strtoi64(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, 0);
g_assert_cmpint(res, ==, 0x123);
g_assert(endptr == str + strlen(str));
}
-static void test_qemu_strtoll_max(void)
+static void test_qemu_strtoi64_max(void)
{
char *str = g_strdup_printf("%lld", LLONG_MAX);
char f = 'X';
@@ -951,7 +960,7 @@ static void test_qemu_strtoll_max(void)
int64_t res = 999;
int err;
- err = qemu_strtoll(str, &endptr, 0, &res);
+ err = qemu_strtoi64(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, 0);
g_assert_cmpint(res, ==, LLONG_MAX);
@@ -959,7 +968,7 @@ static void test_qemu_strtoll_max(void)
g_free(str);
}
-static void test_qemu_strtoll_overflow(void)
+static void test_qemu_strtoi64_overflow(void)
{
const char *str = "99999999999999999999999999999999999999999999";
char f = 'X';
@@ -967,14 +976,14 @@ static void test_qemu_strtoll_overflow(void)
int64_t res = 999;
int err;
- err = qemu_strtoll(str, &endptr, 0, &res);
+ err = qemu_strtoi64(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, -ERANGE);
g_assert_cmpint(res, ==, LLONG_MAX);
g_assert(endptr == str + strlen(str));
}
-static void test_qemu_strtoll_underflow(void)
+static void test_qemu_strtoi64_underflow(void)
{
const char *str = "-99999999999999999999999999999999999999999999";
char f = 'X';
@@ -982,14 +991,14 @@ static void test_qemu_strtoll_underflow(void)
int64_t res = 999;
int err;
- err = qemu_strtoll(str, &endptr, 0, &res);
+ err = qemu_strtoi64(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, -ERANGE);
g_assert_cmpint(res, ==, LLONG_MIN);
g_assert(endptr == str + strlen(str));
}
-static void test_qemu_strtoll_negative(void)
+static void test_qemu_strtoi64_negative(void)
{
const char *str = " \t -321";
char f = 'X';
@@ -997,84 +1006,84 @@ static void test_qemu_strtoll_negative(void)
int64_t res = 999;
int err;
- err = qemu_strtoll(str, &endptr, 0, &res);
+ err = qemu_strtoi64(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, 0);
g_assert_cmpint(res, ==, -321);
g_assert(endptr == str + strlen(str));
}
-static void test_qemu_strtoll_full_correct(void)
+static void test_qemu_strtoi64_full_correct(void)
{
const char *str = "123";
int64_t res = 999;
int err;
- err = qemu_strtoll(str, NULL, 0, &res);
+ err = qemu_strtoi64(str, NULL, 0, &res);
g_assert_cmpint(err, ==, 0);
g_assert_cmpint(res, ==, 123);
}
-static void test_qemu_strtoll_full_null(void)
+static void test_qemu_strtoi64_full_null(void)
{
int64_t res = 999;
int err;
- err = qemu_strtoll(NULL, NULL, 0, &res);
+ err = qemu_strtoi64(NULL, NULL, 0, &res);
g_assert_cmpint(err, ==, -EINVAL);
}
-static void test_qemu_strtoll_full_empty(void)
+static void test_qemu_strtoi64_full_empty(void)
{
const char *str = "";
int64_t res = 999;
int err;
- err = qemu_strtoll(str, NULL, 0, &res);
+ err = qemu_strtoi64(str, NULL, 0, &res);
g_assert_cmpint(err, ==, -EINVAL);
}
-static void test_qemu_strtoll_full_negative(void)
+static void test_qemu_strtoi64_full_negative(void)
{
const char *str = " \t -321";
int64_t res = 999;
int err;
- err = qemu_strtoll(str, NULL, 0, &res);
+ err = qemu_strtoi64(str, NULL, 0, &res);
g_assert_cmpint(err, ==, 0);
g_assert_cmpint(res, ==, -321);
}
-static void test_qemu_strtoll_full_trailing(void)
+static void test_qemu_strtoi64_full_trailing(void)
{
const char *str = "123xxx";
int64_t res = 999;
int err;
- err = qemu_strtoll(str, NULL, 0, &res);
+ err = qemu_strtoi64(str, NULL, 0, &res);
g_assert_cmpint(err, ==, -EINVAL);
}
-static void test_qemu_strtoll_full_max(void)
+static void test_qemu_strtoi64_full_max(void)
{
char *str = g_strdup_printf("%lld", LLONG_MAX);
int64_t res;
int err;
- err = qemu_strtoll(str, NULL, 0, &res);
+ err = qemu_strtoi64(str, NULL, 0, &res);
g_assert_cmpint(err, ==, 0);
g_assert_cmpint(res, ==, LLONG_MAX);
g_free(str);
}
-static void test_qemu_strtoull_correct(void)
+static void test_qemu_strtou64_correct(void)
{
const char *str = "12345 foo";
char f = 'X';
@@ -1082,27 +1091,27 @@ static void test_qemu_strtoull_correct(void)
uint64_t res = 999;
int err;
- err = qemu_strtoull(str, &endptr, 0, &res);
+ err = qemu_strtou64(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, 12345);
+ g_assert_cmpuint(res, ==, 12345);
g_assert(endptr == str + 5);
}
-static void test_qemu_strtoull_null(void)
+static void test_qemu_strtou64_null(void)
{
char f = 'X';
const char *endptr = &f;
uint64_t res = 999;
int err;
- err = qemu_strtoull(NULL, &endptr, 0, &res);
+ err = qemu_strtou64(NULL, &endptr, 0, &res);
g_assert_cmpint(err, ==, -EINVAL);
g_assert(endptr == NULL);
}
-static void test_qemu_strtoull_empty(void)
+static void test_qemu_strtou64_empty(void)
{
const char *str = "";
char f = 'X';
@@ -1110,12 +1119,13 @@ static void test_qemu_strtoull_empty(void)
uint64_t res = 999;
int err;
- err = qemu_strtoull(str, &endptr, 0, &res);
+ err = qemu_strtou64(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == str);
}
-static void test_qemu_strtoull_whitespace(void)
+static void test_qemu_strtou64_whitespace(void)
{
const char *str = " \t ";
char f = 'X';
@@ -1123,12 +1133,13 @@ static void test_qemu_strtoull_whitespace(void)
uint64_t res = 999;
int err;
- err = qemu_strtoull(str, &endptr, 0, &res);
+ err = qemu_strtou64(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == str);
}
-static void test_qemu_strtoull_invalid(void)
+static void test_qemu_strtou64_invalid(void)
{
const char *str = " xxxx \t abc";
char f = 'X';
@@ -1136,12 +1147,13 @@ static void test_qemu_strtoull_invalid(void)
uint64_t res = 999;
int err;
- err = qemu_strtoull(str, &endptr, 0, &res);
+ err = qemu_strtou64(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == str);
}
-static void test_qemu_strtoull_trailing(void)
+static void test_qemu_strtou64_trailing(void)
{
const char *str = "123xxx";
char f = 'X';
@@ -1149,14 +1161,14 @@ static void test_qemu_strtoull_trailing(void)
uint64_t res = 999;
int err;
- err = qemu_strtoull(str, &endptr, 0, &res);
+ err = qemu_strtou64(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, 123);
+ g_assert_cmpuint(res, ==, 123);
g_assert(endptr == str + 3);
}
-static void test_qemu_strtoull_octal(void)
+static void test_qemu_strtou64_octal(void)
{
const char *str = "0123";
char f = 'X';
@@ -1164,22 +1176,22 @@ static void test_qemu_strtoull_octal(void)
uint64_t res = 999;
int err;
- err = qemu_strtoull(str, &endptr, 8, &res);
+ err = qemu_strtou64(str, &endptr, 8, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, 0123);
+ g_assert_cmpuint(res, ==, 0123);
g_assert(endptr == str + strlen(str));
endptr = &f;
res = 999;
- err = qemu_strtoull(str, &endptr, 0, &res);
+ err = qemu_strtou64(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, 0123);
+ g_assert_cmpuint(res, ==, 0123);
g_assert(endptr == str + strlen(str));
}
-static void test_qemu_strtoull_decimal(void)
+static void test_qemu_strtou64_decimal(void)
{
const char *str = "0123";
char f = 'X';
@@ -1187,23 +1199,23 @@ static void test_qemu_strtoull_decimal(void)
uint64_t res = 999;
int err;
- err = qemu_strtoull(str, &endptr, 10, &res);
+ err = qemu_strtou64(str, &endptr, 10, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, 123);
+ g_assert_cmpuint(res, ==, 123);
g_assert(endptr == str + strlen(str));
str = "123";
endptr = &f;
res = 999;
- err = qemu_strtoull(str, &endptr, 0, &res);
+ err = qemu_strtou64(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, 123);
+ g_assert_cmpuint(res, ==, 123);
g_assert(endptr == str + strlen(str));
}
-static void test_qemu_strtoull_hex(void)
+static void test_qemu_strtou64_hex(void)
{
const char *str = "0123";
char f = 'X';
@@ -1211,23 +1223,23 @@ static void test_qemu_strtoull_hex(void)
uint64_t res = 999;
int err;
- err = qemu_strtoull(str, &endptr, 16, &res);
+ err = qemu_strtou64(str, &endptr, 16, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, 0x123);
+ g_assert_cmphex(res, ==, 0x123);
g_assert(endptr == str + strlen(str));
str = "0x123";
endptr = &f;
res = 999;
- err = qemu_strtoull(str, &endptr, 0, &res);
+ err = qemu_strtou64(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, 0x123);
+ g_assert_cmphex(res, ==, 0x123);
g_assert(endptr == str + strlen(str));
}
-static void test_qemu_strtoull_max(void)
+static void test_qemu_strtou64_max(void)
{
char *str = g_strdup_printf("%llu", ULLONG_MAX);
char f = 'X';
@@ -1235,15 +1247,15 @@ static void test_qemu_strtoull_max(void)
uint64_t res = 999;
int err;
- err = qemu_strtoull(str, &endptr, 0, &res);
+ err = qemu_strtou64(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, ULLONG_MAX);
+ g_assert_cmphex(res, ==, ULLONG_MAX);
g_assert(endptr == str + strlen(str));
g_free(str);
}
-static void test_qemu_strtoull_overflow(void)
+static void test_qemu_strtou64_overflow(void)
{
const char *str = "99999999999999999999999999999999999999999999";
char f = 'X';
@@ -1251,14 +1263,14 @@ static void test_qemu_strtoull_overflow(void)
uint64_t res = 999;
int err;
- err = qemu_strtoull(str, &endptr, 0, &res);
+ err = qemu_strtou64(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, -ERANGE);
- g_assert_cmpint(res, ==, ULLONG_MAX);
+ g_assert_cmphex(res, ==, ULLONG_MAX);
g_assert(endptr == str + strlen(str));
}
-static void test_qemu_strtoull_underflow(void)
+static void test_qemu_strtou64_underflow(void)
{
const char *str = "-99999999999999999999999999999999999999999999";
char f = 'X';
@@ -1266,14 +1278,14 @@ static void test_qemu_strtoull_underflow(void)
uint64_t res = 999;
int err;
- err = qemu_strtoull(str, &endptr, 0, &res);
+ err = qemu_strtou64(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, -ERANGE);
- g_assert_cmpint(res, ==, -1);
+ g_assert_cmphex(res, ==, -1ull);
g_assert(endptr == str + strlen(str));
}
-static void test_qemu_strtoull_negative(void)
+static void test_qemu_strtou64_negative(void)
{
const char *str = " \t -321";
char f = 'X';
@@ -1281,94 +1293,139 @@ static void test_qemu_strtoull_negative(void)
uint64_t res = 999;
int err;
- err = qemu_strtoull(str, &endptr, 0, &res);
+ err = qemu_strtou64(str, &endptr, 0, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, -321);
+ g_assert_cmpuint(res, ==, -321ull);
g_assert(endptr == str + strlen(str));
}
-static void test_qemu_strtoull_full_correct(void)
+static void test_qemu_strtou64_full_correct(void)
{
const char *str = "18446744073709551614";
uint64_t res = 999;
int err;
- err = qemu_strtoull(str, NULL, 0, &res);
+ err = qemu_strtou64(str, NULL, 0, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, 18446744073709551614LLU);
+ g_assert_cmpuint(res, ==, 18446744073709551614ull);
}
-static void test_qemu_strtoull_full_null(void)
+static void test_qemu_strtou64_full_null(void)
{
uint64_t res = 999;
int err;
- err = qemu_strtoull(NULL, NULL, 0, &res);
+ err = qemu_strtou64(NULL, NULL, 0, &res);
g_assert_cmpint(err, ==, -EINVAL);
}
-static void test_qemu_strtoull_full_empty(void)
+static void test_qemu_strtou64_full_empty(void)
{
const char *str = "";
uint64_t res = 999;
int err;
- err = qemu_strtoull(str, NULL, 0, &res);
+ err = qemu_strtou64(str, NULL, 0, &res);
g_assert_cmpint(err, ==, -EINVAL);
}
-static void test_qemu_strtoull_full_negative(void)
+static void test_qemu_strtou64_full_negative(void)
{
const char *str = " \t -321";
uint64_t res = 999;
int err;
- err = qemu_strtoull(str, NULL, 0, &res);
+ err = qemu_strtou64(str, NULL, 0, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, 18446744073709551295LLU);
+ g_assert_cmpuint(res, ==, -321ull);
}
-static void test_qemu_strtoull_full_trailing(void)
+static void test_qemu_strtou64_full_trailing(void)
{
const char *str = "18446744073709551614xxxxxx";
uint64_t res = 999;
int err;
- err = qemu_strtoull(str, NULL, 0, &res);
+ err = qemu_strtou64(str, NULL, 0, &res);
g_assert_cmpint(err, ==, -EINVAL);
}
-static void test_qemu_strtoull_full_max(void)
+static void test_qemu_strtou64_full_max(void)
{
char *str = g_strdup_printf("%lld", ULLONG_MAX);
uint64_t res = 999;
int err;
- err = qemu_strtoull(str, NULL, 0, &res);
+ err = qemu_strtou64(str, NULL, 0, &res);
g_assert_cmpint(err, ==, 0);
- g_assert_cmpint(res, ==, ULLONG_MAX);
+ g_assert_cmphex(res, ==, ULLONG_MAX);
g_free(str);
}
static void test_qemu_strtosz_simple(void)
{
- const char *str = "12345M";
+ const char *str;
char *endptr = NULL;
- int64_t res;
+ int err;
+ uint64_t res = 0xbaadf00d;
- res = qemu_strtosz(str, &endptr);
- g_assert_cmpint(res, ==, 12345 * M_BYTE);
- g_assert(endptr == str + 6);
+ str = "0";
+ err = qemu_strtosz(str, &endptr, &res);
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpint(res, ==, 0);
+ g_assert(endptr == str + 1);
+
+ str = "12345";
+ err = qemu_strtosz(str, &endptr, &res);
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpint(res, ==, 12345);
+ g_assert(endptr == str + 5);
+
+ err = qemu_strtosz(str, NULL, &res);
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpint(res, ==, 12345);
+
+ /* Note: precision is 53 bits since we're parsing with strtod() */
- res = qemu_strtosz(str, NULL);
- g_assert_cmpint(res, ==, 12345 * M_BYTE);
+ str = "9007199254740991"; /* 2^53-1 */
+ err = qemu_strtosz(str, &endptr, &res);
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpint(res, ==, 0x1fffffffffffff);
+ g_assert(endptr == str + 16);
+
+ str = "9007199254740992"; /* 2^53 */
+ err = qemu_strtosz(str, &endptr, &res);
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpint(res, ==, 0x20000000000000);
+ g_assert(endptr == str + 16);
+
+ str = "9007199254740993"; /* 2^53+1 */
+ err = qemu_strtosz(str, &endptr, &res);
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpint(res, ==, 0x20000000000000); /* rounded to 53 bits */
+ g_assert(endptr == str + 16);
+
+ str = "18446744073709549568"; /* 0xfffffffffffff800 (53 msbs set) */
+ err = qemu_strtosz(str, &endptr, &res);
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpint(res, ==, 0xfffffffffffff800);
+ g_assert(endptr == str + 20);
+
+ str = "18446744073709550591"; /* 0xfffffffffffffbff */
+ err = qemu_strtosz(str, &endptr, &res);
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpint(res, ==, 0xfffffffffffff800); /* rounded to 53 bits */
+ g_assert(endptr == str + 20);
+
+ /* 0x7ffffffffffffe00..0x7fffffffffffffff get rounded to
+ * 0x8000000000000000, thus -ERANGE; see test_qemu_strtosz_erange() */
}
static void test_qemu_strtosz_units(void)
@@ -1381,60 +1438,157 @@ static void test_qemu_strtosz_units(void)
const char *t = "1T";
const char *p = "1P";
const char *e = "1E";
- int64_t res;
+ int err;
+ char *endptr = NULL;
+ uint64_t res = 0xbaadf00d;
/* default is M */
- res = qemu_strtosz(none, NULL);
+ err = qemu_strtosz_MiB(none, &endptr, &res);
+ g_assert_cmpint(err, ==, 0);
g_assert_cmpint(res, ==, M_BYTE);
+ g_assert(endptr == none + 1);
- res = qemu_strtosz(b, NULL);
+ err = qemu_strtosz(b, &endptr, &res);
+ g_assert_cmpint(err, ==, 0);
g_assert_cmpint(res, ==, 1);
+ g_assert(endptr == b + 2);
- res = qemu_strtosz(k, NULL);
+ err = qemu_strtosz(k, &endptr, &res);
+ g_assert_cmpint(err, ==, 0);
g_assert_cmpint(res, ==, K_BYTE);
+ g_assert(endptr == k + 2);
- res = qemu_strtosz(m, NULL);
+ err = qemu_strtosz(m, &endptr, &res);
+ g_assert_cmpint(err, ==, 0);
g_assert_cmpint(res, ==, M_BYTE);
+ g_assert(endptr == m + 2);
- res = qemu_strtosz(g, NULL);
+ err = qemu_strtosz(g, &endptr, &res);
+ g_assert_cmpint(err, ==, 0);
g_assert_cmpint(res, ==, G_BYTE);
+ g_assert(endptr == g + 2);
- res = qemu_strtosz(t, NULL);
+ err = qemu_strtosz(t, &endptr, &res);
+ g_assert_cmpint(err, ==, 0);
g_assert_cmpint(res, ==, T_BYTE);
+ g_assert(endptr == t + 2);
- res = qemu_strtosz(p, NULL);
+ err = qemu_strtosz(p, &endptr, &res);
+ g_assert_cmpint(err, ==, 0);
g_assert_cmpint(res, ==, P_BYTE);
+ g_assert(endptr == p + 2);
- res = qemu_strtosz(e, NULL);
+ err = qemu_strtosz(e, &endptr, &res);
+ g_assert_cmpint(err, ==, 0);
g_assert_cmpint(res, ==, E_BYTE);
+ g_assert(endptr == e + 2);
}
static void test_qemu_strtosz_float(void)
{
const char *str = "12.345M";
- int64_t res;
+ int err;
+ char *endptr = NULL;
+ uint64_t res = 0xbaadf00d;
- res = qemu_strtosz(str, NULL);
+ err = qemu_strtosz(str, &endptr, &res);
+ g_assert_cmpint(err, ==, 0);
g_assert_cmpint(res, ==, 12.345 * M_BYTE);
+ g_assert(endptr == str + 7);
+}
+
+static void test_qemu_strtosz_invalid(void)
+{
+ const char *str;
+ char *endptr = NULL;
+ int err;
+ uint64_t res = 0xbaadf00d;
+
+ str = "";
+ err = qemu_strtosz(str, &endptr, &res);
+ g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == str);
+
+ str = " \t ";
+ err = qemu_strtosz(str, &endptr, &res);
+ g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == str);
+
+ str = "crap";
+ err = qemu_strtosz(str, &endptr, &res);
+ g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == str);
+}
+
+static void test_qemu_strtosz_trailing(void)
+{
+ const char *str;
+ char *endptr = NULL;
+ int err;
+ uint64_t res = 0xbaadf00d;
+
+ str = "123xxx";
+ err = qemu_strtosz_MiB(str, &endptr, &res);
+ g_assert_cmpint(res, ==, 123 * M_BYTE);
+ g_assert(endptr == str + 3);
+
+ err = qemu_strtosz(str, NULL, &res);
+ g_assert_cmpint(err, ==, -EINVAL);
+
+ str = "1kiB";
+ err = qemu_strtosz(str, &endptr, &res);
+ g_assert_cmpint(err, ==, 0);
+ g_assert_cmpint(res, ==, 1024);
+ g_assert(endptr == str + 2);
+
+ err = qemu_strtosz(str, NULL, &res);
+ g_assert_cmpint(err, ==, -EINVAL);
}
static void test_qemu_strtosz_erange(void)
{
- const char *str = "10E";
- int64_t res;
+ const char *str;
+ char *endptr = NULL;
+ int err;
+ uint64_t res = 0xbaadf00d;
+
+ str = "-1";
+ err = qemu_strtosz(str, &endptr, &res);
+ g_assert_cmpint(err, ==, -ERANGE);
+ g_assert(endptr == str + 2);
+
+ str = "18446744073709550592"; /* 0xfffffffffffffc00 */
+ err = qemu_strtosz(str, &endptr, &res);
+ g_assert_cmpint(err, ==, -ERANGE);
+ g_assert(endptr == str + 20);
+
+ str = "18446744073709551615"; /* 2^64-1 */
+ err = qemu_strtosz(str, &endptr, &res);
+ g_assert_cmpint(err, ==, -ERANGE);
+ g_assert(endptr == str + 20);
+
+ str = "18446744073709551616"; /* 2^64 */
+ err = qemu_strtosz(str, &endptr, &res);
+ g_assert_cmpint(err, ==, -ERANGE);
+ g_assert(endptr == str + 20);
- res = qemu_strtosz(str, NULL);
- g_assert_cmpint(res, ==, -ERANGE);
+ str = "20E";
+ err = qemu_strtosz(str, &endptr, &res);
+ g_assert_cmpint(err, ==, -ERANGE);
+ g_assert(endptr == str + 3);
}
-static void test_qemu_strtosz_suffix_unit(void)
+static void test_qemu_strtosz_metric(void)
{
- const char *str = "12345";
- int64_t res;
+ const char *str = "12345k";
+ int err;
+ char *endptr = NULL;
+ uint64_t res = 0xbaadf00d;
- res = qemu_strtosz_suffix_unit(str, NULL,
- QEMU_STRTOSZ_DEFSUFFIX_KB, 1000);
+ err = qemu_strtosz_metric(str, &endptr, &res);
+ g_assert_cmpint(err, ==, 0);
g_assert_cmpint(res, ==, 12345000);
+ g_assert(endptr == str + 6);
}
int main(int argc, char **argv)
@@ -1459,21 +1613,32 @@ int main(int argc, char **argv)
test_parse_uint_full_correct);
/* qemu_strtol() tests */
- g_test_add_func("/cutils/qemu_strtol/correct", test_qemu_strtol_correct);
- g_test_add_func("/cutils/qemu_strtol/null", test_qemu_strtol_null);
- g_test_add_func("/cutils/qemu_strtol/empty", test_qemu_strtol_empty);
+ g_test_add_func("/cutils/qemu_strtol/correct",
+ test_qemu_strtol_correct);
+ g_test_add_func("/cutils/qemu_strtol/null",
+ test_qemu_strtol_null);
+ g_test_add_func("/cutils/qemu_strtol/empty",
+ test_qemu_strtol_empty);
g_test_add_func("/cutils/qemu_strtol/whitespace",
test_qemu_strtol_whitespace);
- g_test_add_func("/cutils/qemu_strtol/invalid", test_qemu_strtol_invalid);
- g_test_add_func("/cutils/qemu_strtol/trailing", test_qemu_strtol_trailing);
- g_test_add_func("/cutils/qemu_strtol/octal", test_qemu_strtol_octal);
- g_test_add_func("/cutils/qemu_strtol/decimal", test_qemu_strtol_decimal);
- g_test_add_func("/cutils/qemu_strtol/hex", test_qemu_strtol_hex);
- g_test_add_func("/cutils/qemu_strtol/max", test_qemu_strtol_max);
- g_test_add_func("/cutils/qemu_strtol/overflow", test_qemu_strtol_overflow);
+ g_test_add_func("/cutils/qemu_strtol/invalid",
+ test_qemu_strtol_invalid);
+ g_test_add_func("/cutils/qemu_strtol/trailing",
+ test_qemu_strtol_trailing);
+ g_test_add_func("/cutils/qemu_strtol/octal",
+ test_qemu_strtol_octal);
+ g_test_add_func("/cutils/qemu_strtol/decimal",
+ test_qemu_strtol_decimal);
+ g_test_add_func("/cutils/qemu_strtol/hex",
+ test_qemu_strtol_hex);
+ g_test_add_func("/cutils/qemu_strtol/max",
+ test_qemu_strtol_max);
+ g_test_add_func("/cutils/qemu_strtol/overflow",
+ test_qemu_strtol_overflow);
g_test_add_func("/cutils/qemu_strtol/underflow",
test_qemu_strtol_underflow);
- g_test_add_func("/cutils/qemu_strtol/negative", test_qemu_strtol_negative);
+ g_test_add_func("/cutils/qemu_strtol/negative",
+ test_qemu_strtol_negative);
g_test_add_func("/cutils/qemu_strtol_full/correct",
test_qemu_strtol_full_correct);
g_test_add_func("/cutils/qemu_strtol_full/null",
@@ -1488,18 +1653,26 @@ int main(int argc, char **argv)
test_qemu_strtol_full_max);
/* qemu_strtoul() tests */
- g_test_add_func("/cutils/qemu_strtoul/correct", test_qemu_strtoul_correct);
- g_test_add_func("/cutils/qemu_strtoul/null", test_qemu_strtoul_null);
- g_test_add_func("/cutils/qemu_strtoul/empty", test_qemu_strtoul_empty);
+ g_test_add_func("/cutils/qemu_strtoul/correct",
+ test_qemu_strtoul_correct);
+ g_test_add_func("/cutils/qemu_strtoul/null",
+ test_qemu_strtoul_null);
+ g_test_add_func("/cutils/qemu_strtoul/empty",
+ test_qemu_strtoul_empty);
g_test_add_func("/cutils/qemu_strtoul/whitespace",
test_qemu_strtoul_whitespace);
- g_test_add_func("/cutils/qemu_strtoul/invalid", test_qemu_strtoul_invalid);
+ g_test_add_func("/cutils/qemu_strtoul/invalid",
+ test_qemu_strtoul_invalid);
g_test_add_func("/cutils/qemu_strtoul/trailing",
test_qemu_strtoul_trailing);
- g_test_add_func("/cutils/qemu_strtoul/octal", test_qemu_strtoul_octal);
- g_test_add_func("/cutils/qemu_strtoul/decimal", test_qemu_strtoul_decimal);
- g_test_add_func("/cutils/qemu_strtoul/hex", test_qemu_strtoul_hex);
- g_test_add_func("/cutils/qemu_strtoul/max", test_qemu_strtoul_max);
+ g_test_add_func("/cutils/qemu_strtoul/octal",
+ test_qemu_strtoul_octal);
+ g_test_add_func("/cutils/qemu_strtoul/decimal",
+ test_qemu_strtoul_decimal);
+ g_test_add_func("/cutils/qemu_strtoul/hex",
+ test_qemu_strtoul_hex);
+ g_test_add_func("/cutils/qemu_strtoul/max",
+ test_qemu_strtoul_max);
g_test_add_func("/cutils/qemu_strtoul/overflow",
test_qemu_strtoul_overflow);
g_test_add_func("/cutils/qemu_strtoul/underflow",
@@ -1519,73 +1692,86 @@ int main(int argc, char **argv)
g_test_add_func("/cutils/qemu_strtoul_full/max",
test_qemu_strtoul_full_max);
- /* qemu_strtoll() tests */
- g_test_add_func("/cutils/qemu_strtoll/correct", test_qemu_strtoll_correct);
- g_test_add_func("/cutils/qemu_strtoll/null", test_qemu_strtoll_null);
- g_test_add_func("/cutils/qemu_strtoll/empty", test_qemu_strtoll_empty);
- g_test_add_func("/cutils/qemu_strtoll/whitespace",
- test_qemu_strtoll_whitespace);
- g_test_add_func("/cutils/qemu_strtoll/invalid", test_qemu_strtoll_invalid);
- g_test_add_func("/cutils/qemu_strtoll/trailing",
- test_qemu_strtoll_trailing);
- g_test_add_func("/cutils/qemu_strtoll/octal", test_qemu_strtoll_octal);
- g_test_add_func("/cutils/qemu_strtoll/decimal", test_qemu_strtoll_decimal);
- g_test_add_func("/cutils/qemu_strtoll/hex", test_qemu_strtoll_hex);
- g_test_add_func("/cutils/qemu_strtoll/max", test_qemu_strtoll_max);
- g_test_add_func("/cutils/qemu_strtoll/overflow",
- test_qemu_strtoll_overflow);
- g_test_add_func("/cutils/qemu_strtoll/underflow",
- test_qemu_strtoll_underflow);
- g_test_add_func("/cutils/qemu_strtoll/negative",
- test_qemu_strtoll_negative);
- g_test_add_func("/cutils/qemu_strtoll_full/correct",
- test_qemu_strtoll_full_correct);
- g_test_add_func("/cutils/qemu_strtoll_full/null",
- test_qemu_strtoll_full_null);
- g_test_add_func("/cutils/qemu_strtoll_full/empty",
- test_qemu_strtoll_full_empty);
- g_test_add_func("/cutils/qemu_strtoll_full/negative",
- test_qemu_strtoll_full_negative);
- g_test_add_func("/cutils/qemu_strtoll_full/trailing",
- test_qemu_strtoll_full_trailing);
- g_test_add_func("/cutils/qemu_strtoll_full/max",
- test_qemu_strtoll_full_max);
-
- /* qemu_strtoull() tests */
- g_test_add_func("/cutils/qemu_strtoull/correct",
- test_qemu_strtoull_correct);
- g_test_add_func("/cutils/qemu_strtoull/null",
- test_qemu_strtoull_null);
- g_test_add_func("/cutils/qemu_strtoull/empty", test_qemu_strtoull_empty);
- g_test_add_func("/cutils/qemu_strtoull/whitespace",
- test_qemu_strtoull_whitespace);
- g_test_add_func("/cutils/qemu_strtoull/invalid",
- test_qemu_strtoull_invalid);
- g_test_add_func("/cutils/qemu_strtoull/trailing",
- test_qemu_strtoull_trailing);
- g_test_add_func("/cutils/qemu_strtoull/octal", test_qemu_strtoull_octal);
- g_test_add_func("/cutils/qemu_strtoull/decimal",
- test_qemu_strtoull_decimal);
- g_test_add_func("/cutils/qemu_strtoull/hex", test_qemu_strtoull_hex);
- g_test_add_func("/cutils/qemu_strtoull/max", test_qemu_strtoull_max);
- g_test_add_func("/cutils/qemu_strtoull/overflow",
- test_qemu_strtoull_overflow);
- g_test_add_func("/cutils/qemu_strtoull/underflow",
- test_qemu_strtoull_underflow);
- g_test_add_func("/cutils/qemu_strtoull/negative",
- test_qemu_strtoull_negative);
- g_test_add_func("/cutils/qemu_strtoull_full/correct",
- test_qemu_strtoull_full_correct);
- g_test_add_func("/cutils/qemu_strtoull_full/null",
- test_qemu_strtoull_full_null);
- g_test_add_func("/cutils/qemu_strtoull_full/empty",
- test_qemu_strtoull_full_empty);
- g_test_add_func("/cutils/qemu_strtoull_full/negative",
- test_qemu_strtoull_full_negative);
- g_test_add_func("/cutils/qemu_strtoull_full/trailing",
- test_qemu_strtoull_full_trailing);
- g_test_add_func("/cutils/qemu_strtoull_full/max",
- test_qemu_strtoull_full_max);
+ /* qemu_strtoi64() tests */
+ g_test_add_func("/cutils/qemu_strtoi64/correct",
+ test_qemu_strtoi64_correct);
+ g_test_add_func("/cutils/qemu_strtoi64/null",
+ test_qemu_strtoi64_null);
+ g_test_add_func("/cutils/qemu_strtoi64/empty",
+ test_qemu_strtoi64_empty);
+ g_test_add_func("/cutils/qemu_strtoi64/whitespace",
+ test_qemu_strtoi64_whitespace);
+ g_test_add_func("/cutils/qemu_strtoi64/invalid"
+ ,
+ test_qemu_strtoi64_invalid);
+ g_test_add_func("/cutils/qemu_strtoi64/trailing",
+ test_qemu_strtoi64_trailing);
+ g_test_add_func("/cutils/qemu_strtoi64/octal",
+ test_qemu_strtoi64_octal);
+ g_test_add_func("/cutils/qemu_strtoi64/decimal",
+ test_qemu_strtoi64_decimal);
+ g_test_add_func("/cutils/qemu_strtoi64/hex",
+ test_qemu_strtoi64_hex);
+ g_test_add_func("/cutils/qemu_strtoi64/max",
+ test_qemu_strtoi64_max);
+ g_test_add_func("/cutils/qemu_strtoi64/overflow",
+ test_qemu_strtoi64_overflow);
+ g_test_add_func("/cutils/qemu_strtoi64/underflow",
+ test_qemu_strtoi64_underflow);
+ g_test_add_func("/cutils/qemu_strtoi64/negative",
+ test_qemu_strtoi64_negative);
+ g_test_add_func("/cutils/qemu_strtoi64_full/correct",
+ test_qemu_strtoi64_full_correct);
+ g_test_add_func("/cutils/qemu_strtoi64_full/null",
+ test_qemu_strtoi64_full_null);
+ g_test_add_func("/cutils/qemu_strtoi64_full/empty",
+ test_qemu_strtoi64_full_empty);
+ g_test_add_func("/cutils/qemu_strtoi64_full/negative",
+ test_qemu_strtoi64_full_negative);
+ g_test_add_func("/cutils/qemu_strtoi64_full/trailing",
+ test_qemu_strtoi64_full_trailing);
+ g_test_add_func("/cutils/qemu_strtoi64_full/max",
+ test_qemu_strtoi64_full_max);
+
+ /* qemu_strtou64() tests */
+ g_test_add_func("/cutils/qemu_strtou64/correct",
+ test_qemu_strtou64_correct);
+ g_test_add_func("/cutils/qemu_strtou64/null",
+ test_qemu_strtou64_null);
+ g_test_add_func("/cutils/qemu_strtou64/empty",
+ test_qemu_strtou64_empty);
+ g_test_add_func("/cutils/qemu_strtou64/whitespace",
+ test_qemu_strtou64_whitespace);
+ g_test_add_func("/cutils/qemu_strtou64/invalid",
+ test_qemu_strtou64_invalid);
+ g_test_add_func("/cutils/qemu_strtou64/trailing",
+ test_qemu_strtou64_trailing);
+ g_test_add_func("/cutils/qemu_strtou64/octal",
+ test_qemu_strtou64_octal);
+ g_test_add_func("/cutils/qemu_strtou64/decimal",
+ test_qemu_strtou64_decimal);
+ g_test_add_func("/cutils/qemu_strtou64/hex",
+ test_qemu_strtou64_hex);
+ g_test_add_func("/cutils/qemu_strtou64/max",
+ test_qemu_strtou64_max);
+ g_test_add_func("/cutils/qemu_strtou64/overflow",
+ test_qemu_strtou64_overflow);
+ g_test_add_func("/cutils/qemu_strtou64/underflow",
+ test_qemu_strtou64_underflow);
+ g_test_add_func("/cutils/qemu_strtou64/negative",
+ test_qemu_strtou64_negative);
+ g_test_add_func("/cutils/qemu_strtou64_full/correct",
+ test_qemu_strtou64_full_correct);
+ g_test_add_func("/cutils/qemu_strtou64_full/null",
+ test_qemu_strtou64_full_null);
+ g_test_add_func("/cutils/qemu_strtou64_full/empty",
+ test_qemu_strtou64_full_empty);
+ g_test_add_func("/cutils/qemu_strtou64_full/negative",
+ test_qemu_strtou64_full_negative);
+ g_test_add_func("/cutils/qemu_strtou64_full/trailing",
+ test_qemu_strtou64_full_trailing);
+ g_test_add_func("/cutils/qemu_strtou64_full/max",
+ test_qemu_strtou64_full_max);
g_test_add_func("/cutils/strtosz/simple",
test_qemu_strtosz_simple);
@@ -1593,10 +1779,14 @@ int main(int argc, char **argv)
test_qemu_strtosz_units);
g_test_add_func("/cutils/strtosz/float",
test_qemu_strtosz_float);
+ g_test_add_func("/cutils/strtosz/invalid",
+ test_qemu_strtosz_invalid);
+ g_test_add_func("/cutils/strtosz/trailing",
+ test_qemu_strtosz_trailing);
g_test_add_func("/cutils/strtosz/erange",
test_qemu_strtosz_erange);
- g_test_add_func("/cutils/strtosz/suffix-unit",
- test_qemu_strtosz_suffix_unit);
+ g_test_add_func("/cutils/strtosz/metric",
+ test_qemu_strtosz_metric);
return g_test_run();
}
diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c
index a505a3e059..c46ef31658 100644
--- a/tests/test-qemu-opts.c
+++ b/tests/test-qemu-opts.c
@@ -8,6 +8,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/cutils.h"
#include "qapi/error.h"
#include "qapi/qmp/qstring.h"
#include "qemu/config-file.h"
@@ -29,6 +30,9 @@ static QemuOptsList opts_list_01 = {
},{
.name = "number1",
.type = QEMU_OPT_NUMBER,
+ },{
+ .name = "number2",
+ .type = QEMU_OPT_NUMBER,
},
{ /* end of list */ }
},
@@ -42,14 +46,23 @@ static QemuOptsList opts_list_02 = {
.name = "str1",
.type = QEMU_OPT_STRING,
},{
+ .name = "str2",
+ .type = QEMU_OPT_STRING,
+ },{
.name = "bool1",
.type = QEMU_OPT_BOOL,
},{
- .name = "str2",
- .type = QEMU_OPT_STRING,
+ .name = "bool2",
+ .type = QEMU_OPT_BOOL,
},{
.name = "size1",
.type = QEMU_OPT_SIZE,
+ },{
+ .name = "size2",
+ .type = QEMU_OPT_SIZE,
+ },{
+ .name = "size3",
+ .type = QEMU_OPT_SIZE,
},
{ /* end of list */ }
},
@@ -57,6 +70,7 @@ static QemuOptsList opts_list_02 = {
static QemuOptsList opts_list_03 = {
.name = "opts_list_03",
+ .implied_opt_name = "implied",
.head = QTAILQ_HEAD_INITIALIZER(opts_list_03.head),
.desc = {
/* no elements => accept any params */
@@ -421,6 +435,308 @@ static void test_qemu_opts_set(void)
g_assert(opts == NULL);
}
+static int opts_count_iter(void *opaque, const char *name, const char *value,
+ Error **errp)
+{
+ (*(size_t *)opaque)++;
+ return 0;
+}
+
+static size_t opts_count(QemuOpts *opts)
+{
+ size_t n = 0;
+
+ qemu_opt_foreach(opts, opts_count_iter, &n, NULL);
+ return n;
+}
+
+static void test_opts_parse(void)
+{
+ Error *err = NULL;
+ QemuOpts *opts;
+ char long_key[129];
+ char *params;
+
+ /* Nothing */
+ opts = qemu_opts_parse(&opts_list_03, "", false, &error_abort);
+ g_assert_cmpuint(opts_count(opts), ==, 0);
+
+ /* Empty key */
+ opts = qemu_opts_parse(&opts_list_03, "=val", false, &error_abort);
+ g_assert_cmpuint(opts_count(opts), ==, 1);
+ g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "val");
+
+ /* Long key */
+ memset(long_key, 'a', 127);
+ long_key[127] = 'z';
+ long_key[128] = 0;
+ params = g_strdup_printf("%s=v", long_key);
+ opts = qemu_opts_parse(&opts_list_03, params + 1, NULL, &error_abort);
+ g_assert_cmpuint(opts_count(opts), ==, 1);
+ g_assert_cmpstr(qemu_opt_get(opts, long_key + 1), ==, "v");
+
+ /* Overlong key gets truncated */
+ opts = qemu_opts_parse(&opts_list_03, params, NULL, &error_abort);
+ g_assert(opts_count(opts) == 1);
+ long_key[127] = 0;
+ g_assert_cmpstr(qemu_opt_get(opts, long_key), ==, "v");
+ g_free(params);
+
+ /* Multiple keys, last one wins */
+ opts = qemu_opts_parse(&opts_list_03, "a=1,b=2,,x,a=3",
+ false, &error_abort);
+ g_assert_cmpuint(opts_count(opts), ==, 3);
+ g_assert_cmpstr(qemu_opt_get(opts, "a"), ==, "3");
+ g_assert_cmpstr(qemu_opt_get(opts, "b"), ==, "2,x");
+
+ /* Except when it doesn't */
+ opts = qemu_opts_parse(&opts_list_03, "id=foo,id=bar",
+ false, &error_abort);
+ g_assert_cmpuint(opts_count(opts), ==, 0);
+ g_assert_cmpstr(qemu_opts_id(opts), ==, "foo");
+
+ /* TODO Cover low-level access to repeated keys */
+
+ /* Trailing comma is ignored */
+ opts = qemu_opts_parse(&opts_list_03, "x=y,", false, &error_abort);
+ g_assert_cmpuint(opts_count(opts), ==, 1);
+ g_assert_cmpstr(qemu_opt_get(opts, "x"), ==, "y");
+
+ /* Except when it isn't */
+ opts = qemu_opts_parse(&opts_list_03, ",", false, &error_abort);
+ g_assert_cmpuint(opts_count(opts), ==, 1);
+ g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "on");
+
+ /* Duplicate ID */
+ opts = qemu_opts_parse(&opts_list_03, "x=y,id=foo", false, &err);
+ error_free_or_abort(&err);
+ g_assert(!opts);
+ /* TODO Cover .merge_lists = true */
+
+ /* Buggy ID recognition */
+ opts = qemu_opts_parse(&opts_list_03, "x=,,id=bar", false, &error_abort);
+ g_assert_cmpuint(opts_count(opts), ==, 1);
+ g_assert_cmpstr(qemu_opts_id(opts), ==, "bar"); /* BUG */
+ g_assert_cmpstr(qemu_opt_get(opts, "x"), ==, ",id=bar");
+
+ /* Anti-social ID */
+ opts = qemu_opts_parse(&opts_list_01, "id=666", false, &err);
+ error_free_or_abort(&err);
+ g_assert(!opts);
+
+ /* Implied value */
+ opts = qemu_opts_parse(&opts_list_03, "an,noaus,noaus=",
+ false, &error_abort);
+ g_assert_cmpuint(opts_count(opts), ==, 3);
+ g_assert_cmpstr(qemu_opt_get(opts, "an"), ==, "on");
+ g_assert_cmpstr(qemu_opt_get(opts, "aus"), ==, "off");
+ g_assert_cmpstr(qemu_opt_get(opts, "noaus"), ==, "");
+
+ /* Implied key */
+ opts = qemu_opts_parse(&opts_list_03, "an,noaus,noaus=", true,
+ &error_abort);
+ g_assert_cmpuint(opts_count(opts), ==, 3);
+ g_assert_cmpstr(qemu_opt_get(opts, "implied"), ==, "an");
+ g_assert_cmpstr(qemu_opt_get(opts, "aus"), ==, "off");
+ g_assert_cmpstr(qemu_opt_get(opts, "noaus"), ==, "");
+
+ /* Implied key with empty value */
+ opts = qemu_opts_parse(&opts_list_03, ",", true, &error_abort);
+ g_assert_cmpuint(opts_count(opts), ==, 1);
+ g_assert_cmpstr(qemu_opt_get(opts, "implied"), ==, "");
+
+ /* Implied key with comma value */
+ opts = qemu_opts_parse(&opts_list_03, ",,,a=1", true, &error_abort);
+ g_assert_cmpuint(opts_count(opts), ==, 2);
+ g_assert_cmpstr(qemu_opt_get(opts, "implied"), ==, ",");
+ g_assert_cmpstr(qemu_opt_get(opts, "a"), ==, "1");
+
+ /* Empty key is not an implied key */
+ opts = qemu_opts_parse(&opts_list_03, "=val", true, &error_abort);
+ g_assert_cmpuint(opts_count(opts), ==, 1);
+ g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "val");
+
+ /* Unknown key */
+ opts = qemu_opts_parse(&opts_list_01, "nonexistent=", false, &err);
+ error_free_or_abort(&err);
+ g_assert(!opts);
+
+ qemu_opts_reset(&opts_list_01);
+ qemu_opts_reset(&opts_list_03);
+}
+
+static void test_opts_parse_bool(void)
+{
+ Error *err = NULL;
+ QemuOpts *opts;
+
+ opts = qemu_opts_parse(&opts_list_02, "bool1=on,bool2=off",
+ false, &error_abort);
+ g_assert_cmpuint(opts_count(opts), ==, 2);
+ g_assert(qemu_opt_get_bool(opts, "bool1", false));
+ g_assert(!qemu_opt_get_bool(opts, "bool2", true));
+
+ opts = qemu_opts_parse(&opts_list_02, "bool1=offer", false, &err);
+ error_free_or_abort(&err);
+ g_assert(!opts);
+
+ qemu_opts_reset(&opts_list_02);
+}
+
+static void test_opts_parse_number(void)
+{
+ Error *err = NULL;
+ QemuOpts *opts;
+
+ /* Lower limit zero */
+ opts = qemu_opts_parse(&opts_list_01, "number1=0", false, &error_abort);
+ g_assert_cmpuint(opts_count(opts), ==, 1);
+ g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 0);
+
+ /* Upper limit 2^64-1 */
+ opts = qemu_opts_parse(&opts_list_01,
+ "number1=18446744073709551615,number2=-1",
+ false, &error_abort);
+ g_assert_cmpuint(opts_count(opts), ==, 2);
+ g_assert_cmphex(qemu_opt_get_number(opts, "number1", 1), ==, UINT64_MAX);
+ g_assert_cmphex(qemu_opt_get_number(opts, "number2", 0), ==, UINT64_MAX);
+
+ /* Above upper limit */
+ opts = qemu_opts_parse(&opts_list_01, "number1=18446744073709551616",
+ false, &err);
+ error_free_or_abort(&err);
+ g_assert(!opts);
+
+ /* Below lower limit */
+ opts = qemu_opts_parse(&opts_list_01, "number1=-18446744073709551616",
+ false, &err);
+ error_free_or_abort(&err);
+ g_assert(!opts);
+
+ /* Hex and octal */
+ opts = qemu_opts_parse(&opts_list_01, "number1=0x2a,number2=052",
+ false, &error_abort);
+ g_assert_cmpuint(opts_count(opts), ==, 2);
+ g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 42);
+ g_assert_cmpuint(qemu_opt_get_number(opts, "number2", 0), ==, 42);
+
+ /* Invalid */
+ opts = qemu_opts_parse(&opts_list_01, "number1=", false, &err);
+ error_free_or_abort(&err);
+ g_assert(!opts);
+ opts = qemu_opts_parse(&opts_list_01, "number1=eins", false, &err);
+ error_free_or_abort(&err);
+ g_assert(!opts);
+
+ /* Leading whitespace */
+ opts = qemu_opts_parse(&opts_list_01, "number1= \t42",
+ false, &error_abort);
+ g_assert_cmpuint(opts_count(opts), ==, 1);
+ g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 42);
+
+ /* Trailing crap */
+ opts = qemu_opts_parse(&opts_list_01, "number1=3.14", false, &err);
+ error_free_or_abort(&err);
+ g_assert(!opts);
+ opts = qemu_opts_parse(&opts_list_01, "number1=08", false, &err);
+ error_free_or_abort(&err);
+ g_assert(!opts);
+ opts = qemu_opts_parse(&opts_list_01, "number1=0 ", false, &err);
+ error_free_or_abort(&err);
+ g_assert(!opts);
+
+ qemu_opts_reset(&opts_list_01);
+}
+
+static void test_opts_parse_size(void)
+{
+ Error *err = NULL;
+ QemuOpts *opts;
+
+ /* Lower limit zero */
+ opts = qemu_opts_parse(&opts_list_02, "size1=0", false, &error_abort);
+ g_assert_cmpuint(opts_count(opts), ==, 1);
+ g_assert_cmpuint(qemu_opt_get_size(opts, "size1", 1), ==, 0);
+
+ /* Note: precision is 53 bits since we're parsing with strtod() */
+
+ /* Around limit of precision: 2^53-1, 2^53, 2^54 */
+ opts = qemu_opts_parse(&opts_list_02,
+ "size1=9007199254740991,"
+ "size2=9007199254740992,"
+ "size3=9007199254740993",
+ false, &error_abort);
+ g_assert_cmpuint(opts_count(opts), ==, 3);
+ g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1),
+ ==, 0x1fffffffffffff);
+ g_assert_cmphex(qemu_opt_get_size(opts, "size2", 1),
+ ==, 0x20000000000000);
+ g_assert_cmphex(qemu_opt_get_size(opts, "size3", 1),
+ ==, 0x20000000000000);
+
+ /* Close to signed upper limit 0x7ffffffffffffc00 (53 msbs set) */
+ opts = qemu_opts_parse(&opts_list_02,
+ "size1=9223372036854774784," /* 7ffffffffffffc00 */
+ "size2=9223372036854775295", /* 7ffffffffffffdff */
+ false, &error_abort);
+ g_assert_cmpuint(opts_count(opts), ==, 2);
+ g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1),
+ ==, 0x7ffffffffffffc00);
+ g_assert_cmphex(qemu_opt_get_size(opts, "size2", 1),
+ ==, 0x7ffffffffffffc00);
+
+ /* Close to actual upper limit 0xfffffffffffff800 (53 msbs set) */
+ opts = qemu_opts_parse(&opts_list_02,
+ "size1=18446744073709549568," /* fffffffffffff800 */
+ "size2=18446744073709550591", /* fffffffffffffbff */
+ false, &error_abort);
+ g_assert_cmpuint(opts_count(opts), ==, 2);
+ g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1),
+ ==, 0xfffffffffffff800);
+ g_assert_cmphex(qemu_opt_get_size(opts, "size2", 1),
+ ==, 0xfffffffffffff800);
+
+ /* Beyond limits */
+ opts = qemu_opts_parse(&opts_list_02, "size1=-1", false, &err);
+ error_free_or_abort(&err);
+ g_assert(!opts);
+ opts = qemu_opts_parse(&opts_list_02,
+ "size1=18446744073709550592", /* fffffffffffffc00 */
+ false, &err);
+ error_free_or_abort(&err);
+ g_assert(!opts);
+
+ /* Suffixes */
+ opts = qemu_opts_parse(&opts_list_02, "size1=8b,size2=1.5k,size3=2M",
+ false, &error_abort);
+ g_assert_cmpuint(opts_count(opts), ==, 3);
+ g_assert_cmphex(qemu_opt_get_size(opts, "size1", 0), ==, 8);
+ g_assert_cmphex(qemu_opt_get_size(opts, "size2", 0), ==, 1536);
+ g_assert_cmphex(qemu_opt_get_size(opts, "size3", 0), ==, 2 * M_BYTE);
+ opts = qemu_opts_parse(&opts_list_02, "size1=0.1G,size2=16777215T",
+ false, &error_abort);
+ g_assert_cmpuint(opts_count(opts), ==, 2);
+ g_assert_cmphex(qemu_opt_get_size(opts, "size1", 0), ==, G_BYTE / 10);
+ g_assert_cmphex(qemu_opt_get_size(opts, "size2", 0),
+ ==, 16777215 * T_BYTE);
+
+ /* Beyond limit with suffix */
+ opts = qemu_opts_parse(&opts_list_02, "size1=16777216T",
+ false, &err);
+ error_free_or_abort(&err);
+ g_assert(!opts);
+
+ /* Trailing crap */
+ opts = qemu_opts_parse(&opts_list_02, "size1=16E", false, &err);
+ error_free_or_abort(&err);
+ g_assert(!opts);
+ opts = qemu_opts_parse(&opts_list_02, "size1=16Gi", false, &err);
+ error_free_or_abort(&err);
+ g_assert(!opts);
+
+ qemu_opts_reset(&opts_list_02);
+}
+
int main(int argc, char *argv[])
{
register_opts();
@@ -435,6 +751,10 @@ int main(int argc, char *argv[])
g_test_add_func("/qemu-opts/opt_unset", test_qemu_opt_unset);
g_test_add_func("/qemu-opts/opts_reset", test_qemu_opts_reset);
g_test_add_func("/qemu-opts/opts_set", test_qemu_opts_set);
+ g_test_add_func("/qemu-opts/opts_parse/general", test_opts_parse);
+ g_test_add_func("/qemu-opts/opts_parse/bool", test_opts_parse_bool);
+ g_test_add_func("/qemu-opts/opts_parse/number", test_opts_parse_number);
+ g_test_add_func("/qemu-opts/opts_parse/size", test_opts_parse_size);
g_test_run();
return 0;
}
diff --git a/tests/test-qmp-event.c b/tests/test-qmp-event.c
index 633dc87402..7bb621b027 100644
--- a/tests/test-qmp-event.c
+++ b/tests/test-qmp-event.c
@@ -95,24 +95,18 @@ static bool qdict_cmp_simple(QDict *a, QDict *b)
correctness. */
static void event_test_emit(test_QAPIEvent event, QDict *d, Error **errp)
{
- QObject *obj;
QDict *t;
int64_t s, ms;
/* Verify that we have timestamp, then remove it to compare other fields */
- obj = qdict_get(d, "timestamp");
- g_assert(obj);
- t = qobject_to_qdict(obj);
+ t = qdict_get_qdict(d, "timestamp");
g_assert(t);
- obj = qdict_get(t, "seconds");
- g_assert(obj && qobject_type(obj) == QTYPE_QINT);
- s = qint_get_int(qobject_to_qint(obj));
- obj = qdict_get(t, "microseconds");
- g_assert(obj && qobject_type(obj) == QTYPE_QINT);
- ms = qint_get_int(qobject_to_qint(obj));
+ s = qdict_get_try_int(t, "seconds", -2);
+ ms = qdict_get_try_int(t, "microseconds", -2);
if (s == -1) {
g_assert(ms == -1);
} else {
+ g_assert(s >= 0);
g_assert(ms >= 0 && ms <= 999999);
}
g_assert(qdict_size(t) == 2);
diff --git a/tests/test-qobject-output-visitor.c b/tests/test-qobject-output-visitor.c
index 4e2d79c5d1..500b452d98 100644
--- a/tests/test-qobject-output-visitor.c
+++ b/tests/test-qobject-output-visitor.c
@@ -58,81 +58,80 @@ static void test_visitor_out_int(TestOutputVisitorData *data,
const void *unused)
{
int64_t value = -42;
- QObject *obj;
+ QInt *qint;
visit_type_int(data->ov, NULL, &value, &error_abort);
- obj = visitor_get(data);
- g_assert(qobject_type(obj) == QTYPE_QINT);
- g_assert_cmpint(qint_get_int(qobject_to_qint(obj)), ==, value);
+ qint = qobject_to_qint(visitor_get(data));
+ g_assert(qint);
+ g_assert_cmpint(qint_get_int(qint), ==, value);
}
static void test_visitor_out_bool(TestOutputVisitorData *data,
const void *unused)
{
bool value = true;
- QObject *obj;
+ QBool *qbool;
visit_type_bool(data->ov, NULL, &value, &error_abort);
- obj = visitor_get(data);
- g_assert(qobject_type(obj) == QTYPE_QBOOL);
- g_assert(qbool_get_bool(qobject_to_qbool(obj)) == value);
+ qbool = qobject_to_qbool(visitor_get(data));
+ g_assert(qbool);
+ g_assert(qbool_get_bool(qbool) == value);
}
static void test_visitor_out_number(TestOutputVisitorData *data,
const void *unused)
{
double value = 3.14;
- QObject *obj;
+ QFloat *qfloat;
visit_type_number(data->ov, NULL, &value, &error_abort);
- obj = visitor_get(data);
- g_assert(qobject_type(obj) == QTYPE_QFLOAT);
- g_assert(qfloat_get_double(qobject_to_qfloat(obj)) == value);
+ qfloat = qobject_to_qfloat(visitor_get(data));
+ g_assert(qfloat);
+ g_assert(qfloat_get_double(qfloat) == value);
}
static void test_visitor_out_string(TestOutputVisitorData *data,
const void *unused)
{
char *string = (char *) "Q E M U";
- QObject *obj;
+ QString *qstr;
visit_type_str(data->ov, NULL, &string, &error_abort);
- obj = visitor_get(data);
- g_assert(qobject_type(obj) == QTYPE_QSTRING);
- g_assert_cmpstr(qstring_get_str(qobject_to_qstring(obj)), ==, string);
+ qstr = qobject_to_qstring(visitor_get(data));
+ g_assert(qstr);
+ g_assert_cmpstr(qstring_get_str(qstr), ==, string);
}
static void test_visitor_out_no_string(TestOutputVisitorData *data,
const void *unused)
{
char *string = NULL;
- QObject *obj;
+ QString *qstr;
/* A null string should return "" */
visit_type_str(data->ov, NULL, &string, &error_abort);
- obj = visitor_get(data);
- g_assert(qobject_type(obj) == QTYPE_QSTRING);
- g_assert_cmpstr(qstring_get_str(qobject_to_qstring(obj)), ==, "");
+ qstr = qobject_to_qstring(visitor_get(data));
+ g_assert(qstr);
+ g_assert_cmpstr(qstring_get_str(qstr), ==, "");
}
static void test_visitor_out_enum(TestOutputVisitorData *data,
const void *unused)
{
- QObject *obj;
EnumOne i;
+ QString *qstr;
for (i = 0; i < ENUM_ONE__MAX; i++) {
visit_type_EnumOne(data->ov, "unused", &i, &error_abort);
- obj = visitor_get(data);
- g_assert(qobject_type(obj) == QTYPE_QSTRING);
- g_assert_cmpstr(qstring_get_str(qobject_to_qstring(obj)), ==,
- EnumOne_lookup[i]);
+ qstr = qobject_to_qstring(visitor_get(data));
+ g_assert(qstr);
+ g_assert_cmpstr(qstring_get_str(qstr), ==, EnumOne_lookup[i]);
visitor_reset(data);
}
}
@@ -160,15 +159,12 @@ static void test_visitor_out_struct(TestOutputVisitorData *data,
.boolean = false,
.string = (char *) "foo"};
TestStruct *p = &test_struct;
- QObject *obj;
QDict *qdict;
visit_type_TestStruct(data->ov, NULL, &p, &error_abort);
- obj = visitor_get(data);
- g_assert(qobject_type(obj) == QTYPE_QDICT);
-
- qdict = qobject_to_qdict(obj);
+ qdict = qobject_to_qdict(visitor_get(data));
+ g_assert(qdict);
g_assert_cmpint(qdict_size(qdict), ==, 3);
g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 42);
g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, false);
@@ -180,7 +176,6 @@ static void test_visitor_out_struct_nested(TestOutputVisitorData *data,
{
int64_t value = 42;
UserDefTwo *ud2;
- QObject *obj;
QDict *qdict, *dict1, *dict2, *dict3, *userdef;
const char *string = "user def string";
const char *strings[] = { "forty two", "forty three", "forty four",
@@ -207,10 +202,8 @@ static void test_visitor_out_struct_nested(TestOutputVisitorData *data,
visit_type_UserDefTwo(data->ov, "unused", &ud2, &error_abort);
- obj = visitor_get(data);
- g_assert(qobject_type(obj) == QTYPE_QDICT);
-
- qdict = qobject_to_qdict(obj);
+ qdict = qobject_to_qdict(visitor_get(data));
+ g_assert(qdict);
g_assert_cmpint(qdict_size(qdict), ==, 2);
g_assert_cmpstr(qdict_get_str(qdict, "string0"), ==, strings[0]);
@@ -267,7 +260,6 @@ static void test_visitor_out_list(TestOutputVisitorData *data,
bool value_bool = true;
int value_int = 10;
QListEntry *entry;
- QObject *obj;
QList *qlist;
int i;
@@ -285,10 +277,8 @@ static void test_visitor_out_list(TestOutputVisitorData *data,
visit_type_TestStructList(data->ov, NULL, &head, &error_abort);
- obj = visitor_get(data);
- g_assert(qobject_type(obj) == QTYPE_QLIST);
-
- qlist = qobject_to_qlist(obj);
+ qlist = qobject_to_qlist(visitor_get(data));
+ g_assert(qlist);
g_assert(!qlist_empty(qlist));
/* ...and ensure that the visitor sees it in order */
@@ -296,8 +286,8 @@ static void test_visitor_out_list(TestOutputVisitorData *data,
QLIST_FOREACH_ENTRY(qlist, entry) {
QDict *qdict;
- g_assert(qobject_type(entry->value) == QTYPE_QDICT);
qdict = qobject_to_qdict(entry->value);
+ g_assert(qdict);
g_assert_cmpint(qdict_size(qdict), ==, 3);
g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, value_int + i);
g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, value_bool);
@@ -345,13 +335,12 @@ static void test_visitor_out_any(TestOutputVisitorData *data,
QBool *qbool;
QString *qstring;
QDict *qdict;
- QObject *obj;
qobj = QOBJECT(qint_from_int(-42));
visit_type_any(data->ov, NULL, &qobj, &error_abort);
- obj = visitor_get(data);
- g_assert(qobject_type(obj) == QTYPE_QINT);
- g_assert_cmpint(qint_get_int(qobject_to_qint(obj)), ==, -42);
+ qint = qobject_to_qint(visitor_get(data));
+ g_assert(qint);
+ g_assert_cmpint(qint_get_int(qint), ==, -42);
qobject_decref(qobj);
visitor_reset(data);
@@ -362,22 +351,15 @@ static void test_visitor_out_any(TestOutputVisitorData *data,
qobj = QOBJECT(qdict);
visit_type_any(data->ov, NULL, &qobj, &error_abort);
qobject_decref(qobj);
- obj = visitor_get(data);
- qdict = qobject_to_qdict(obj);
+ qdict = qobject_to_qdict(visitor_get(data));
g_assert(qdict);
- qobj = qdict_get(qdict, "integer");
- g_assert(qobj);
- qint = qobject_to_qint(qobj);
+ qint = qobject_to_qint(qdict_get(qdict, "integer"));
g_assert(qint);
g_assert_cmpint(qint_get_int(qint), ==, -42);
- qobj = qdict_get(qdict, "boolean");
- g_assert(qobj);
- qbool = qobject_to_qbool(qobj);
+ qbool = qobject_to_qbool(qdict_get(qdict, "boolean"));
g_assert(qbool);
g_assert(qbool_get_bool(qbool) == true);
- qobj = qdict_get(qdict, "string");
- g_assert(qobj);
- qstring = qobject_to_qstring(qobj);
+ qstring = qobject_to_qstring(qdict_get(qdict, "string"));
g_assert(qstring);
g_assert_cmpstr(qstring_get_str(qstring), ==, "foo");
}
@@ -385,7 +367,6 @@ static void test_visitor_out_any(TestOutputVisitorData *data,
static void test_visitor_out_union_flat(TestOutputVisitorData *data,
const void *unused)
{
- QObject *arg;
QDict *qdict;
UserDefFlatUnion *tmp = g_malloc0(sizeof(UserDefFlatUnion));
@@ -395,11 +376,8 @@ static void test_visitor_out_union_flat(TestOutputVisitorData *data,
tmp->u.value1.boolean = true;
visit_type_UserDefFlatUnion(data->ov, NULL, &tmp, &error_abort);
- arg = visitor_get(data);
-
- g_assert(qobject_type(arg) == QTYPE_QDICT);
- qdict = qobject_to_qdict(arg);
-
+ qdict = qobject_to_qdict(visitor_get(data));
+ g_assert(qdict);
g_assert_cmpstr(qdict_get_str(qdict, "enum1"), ==, "value1");
g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "str");
g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 41);
@@ -411,8 +389,9 @@ static void test_visitor_out_union_flat(TestOutputVisitorData *data,
static void test_visitor_out_alternate(TestOutputVisitorData *data,
const void *unused)
{
- QObject *arg;
UserDefAlternate *tmp;
+ QInt *qint;
+ QString *qstr;
QDict *qdict;
tmp = g_new0(UserDefAlternate, 1);
@@ -420,10 +399,9 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data,
tmp->u.i = 42;
visit_type_UserDefAlternate(data->ov, NULL, &tmp, &error_abort);
- arg = visitor_get(data);
-
- g_assert(qobject_type(arg) == QTYPE_QINT);
- g_assert_cmpint(qint_get_int(qobject_to_qint(arg)), ==, 42);
+ qint = qobject_to_qint(visitor_get(data));
+ g_assert(qint);
+ g_assert_cmpint(qint_get_int(qint), ==, 42);
qapi_free_UserDefAlternate(tmp);
@@ -433,10 +411,9 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data,
tmp->u.s = g_strdup("hello");
visit_type_UserDefAlternate(data->ov, NULL, &tmp, &error_abort);
- arg = visitor_get(data);
-
- g_assert(qobject_type(arg) == QTYPE_QSTRING);
- g_assert_cmpstr(qstring_get_str(qobject_to_qstring(arg)), ==, "hello");
+ qstr = qobject_to_qstring(visitor_get(data));
+ g_assert(qstr);
+ g_assert_cmpstr(qstring_get_str(qstr), ==, "hello");
qapi_free_UserDefAlternate(tmp);
@@ -449,10 +426,8 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data,
tmp->u.udfu.u.value1.boolean = true;
visit_type_UserDefAlternate(data->ov, NULL, &tmp, &error_abort);
- arg = visitor_get(data);
-
- g_assert_cmpint(qobject_type(arg), ==, QTYPE_QDICT);
- qdict = qobject_to_qdict(arg);
+ qdict = qobject_to_qdict(visitor_get(data));
+ g_assert(qdict);
g_assert_cmpint(qdict_size(qdict), ==, 4);
g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 1);
g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "str");
@@ -465,7 +440,6 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data,
static void test_visitor_out_null(TestOutputVisitorData *data,
const void *unused)
{
- QObject *arg;
QDict *qdict;
QObject *nil;
@@ -473,9 +447,8 @@ static void test_visitor_out_null(TestOutputVisitorData *data,
visit_type_null(data->ov, "a", &error_abort);
visit_check_struct(data->ov, &error_abort);
visit_end_struct(data->ov, NULL);
- arg = visitor_get(data);
- g_assert(qobject_type(arg) == QTYPE_QDICT);
- qdict = qobject_to_qdict(arg);
+ qdict = qobject_to_qdict(visitor_get(data));
+ g_assert(qdict);
g_assert_cmpint(qdict_size(qdict), ==, 1);
nil = qdict_get(qdict, "a");
g_assert(nil);
@@ -618,8 +591,6 @@ static void check_native_list(QObject *qobj,
QList *qlist;
int i;
- g_assert(qobj);
- g_assert(qobject_type(qobj) == QTYPE_QDICT);
qdict = qobject_to_qdict(qobj);
g_assert(qdict);
g_assert(qdict_haskey(qdict, "data"));
diff --git a/util/cutils.c b/util/cutils.c
index 4fefcf3be3..50ad179dc5 100644
--- a/util/cutils.c
+++ b/util/cutils.c
@@ -181,19 +181,19 @@ int fcntl_setfl(int fd, int flag)
static int64_t suffix_mul(char suffix, int64_t unit)
{
switch (qemu_toupper(suffix)) {
- case QEMU_STRTOSZ_DEFSUFFIX_B:
+ case 'B':
return 1;
- case QEMU_STRTOSZ_DEFSUFFIX_KB:
+ case 'K':
return unit;
- case QEMU_STRTOSZ_DEFSUFFIX_MB:
+ case 'M':
return unit * unit;
- case QEMU_STRTOSZ_DEFSUFFIX_GB:
+ case 'G':
return unit * unit * unit;
- case QEMU_STRTOSZ_DEFSUFFIX_TB:
+ case 'T':
return unit * unit * unit * unit;
- case QEMU_STRTOSZ_DEFSUFFIX_PB:
+ case 'P':
return unit * unit * unit * unit * unit;
- case QEMU_STRTOSZ_DEFSUFFIX_EB:
+ case 'E':
return unit * unit * unit * unit * unit * unit;
}
return -1;
@@ -205,10 +205,11 @@ static int64_t suffix_mul(char suffix, int64_t unit)
* in *end, if not NULL. Return -ERANGE on overflow, Return -EINVAL on
* other error.
*/
-int64_t qemu_strtosz_suffix_unit(const char *nptr, char **end,
- const char default_suffix, int64_t unit)
+static int do_strtosz(const char *nptr, char **end,
+ const char default_suffix, int64_t unit,
+ uint64_t *result)
{
- int64_t retval = -EINVAL;
+ int retval;
char *endptr;
unsigned char c;
int mul_required = 0;
@@ -217,7 +218,8 @@ int64_t qemu_strtosz_suffix_unit(const char *nptr, char **end,
errno = 0;
val = strtod(nptr, &endptr);
if (isnan(val) || endptr == nptr || errno != 0) {
- goto fail;
+ retval = -EINVAL;
+ goto out;
}
fraction = modf(val, &integral);
if (fraction != 0) {
@@ -232,181 +234,204 @@ int64_t qemu_strtosz_suffix_unit(const char *nptr, char **end,
assert(mul >= 0);
}
if (mul == 1 && mul_required) {
- goto fail;
+ retval = -EINVAL;
+ goto out;
}
- if ((val * mul >= INT64_MAX) || val < 0) {
+ /*
+ * Values >= 0xfffffffffffffc00 overflow uint64_t after their trip
+ * through double (53 bits of precision).
+ */
+ if ((val * mul >= 0xfffffffffffffc00) || val < 0) {
retval = -ERANGE;
- goto fail;
+ goto out;
}
- retval = val * mul;
+ *result = val * mul;
+ retval = 0;
-fail:
+out:
if (end) {
*end = endptr;
+ } else if (*endptr) {
+ retval = -EINVAL;
}
return retval;
}
-int64_t qemu_strtosz_suffix(const char *nptr, char **end,
- const char default_suffix)
+int qemu_strtosz(const char *nptr, char **end, uint64_t *result)
+{
+ return do_strtosz(nptr, end, 'B', 1024, result);
+}
+
+int qemu_strtosz_MiB(const char *nptr, char **end, uint64_t *result)
{
- return qemu_strtosz_suffix_unit(nptr, end, default_suffix, 1024);
+ return do_strtosz(nptr, end, 'M', 1024, result);
}
-int64_t qemu_strtosz(const char *nptr, char **end)
+int qemu_strtosz_metric(const char *nptr, char **end, uint64_t *result)
{
- return qemu_strtosz_suffix(nptr, end, QEMU_STRTOSZ_DEFSUFFIX_MB);
+ return do_strtosz(nptr, end, 'B', 1000, result);
}
/**
- * Helper function for qemu_strto*l() functions.
+ * Helper function for error checking after strtol() and the like
*/
-static int check_strtox_error(const char *p, char *endptr, const char **next,
- int err)
+static int check_strtox_error(const char *nptr, char *ep,
+ const char **endptr, int libc_errno)
{
- /* If no conversion was performed, prefer BSD behavior over glibc
- * behavior.
- */
- if (err == 0 && endptr == p) {
- err = EINVAL;
+ if (endptr) {
+ *endptr = ep;
}
- if (!next && *endptr) {
+
+ /* Turn "no conversion" into an error */
+ if (libc_errno == 0 && ep == nptr) {
return -EINVAL;
}
- if (next) {
- *next = endptr;
+
+ /* Fail when we're expected to consume the string, but didn't */
+ if (!endptr && *ep) {
+ return -EINVAL;
}
- return -err;
+
+ return -libc_errno;
}
/**
- * QEMU wrappers for strtol(), strtoll(), strtoul(), strotull() C functions.
- *
- * Convert ASCII string @nptr to a long integer value
- * from the given @base. Parameters @nptr, @endptr, @base
- * follows same semantics as strtol() C function.
- *
- * Unlike from strtol() function, if @endptr is not NULL, this
- * function will return -EINVAL whenever it cannot fully convert
- * the string in @nptr with given @base to a long. This function returns
- * the result of the conversion only through the @result parameter.
- *
- * If NULL is passed in @endptr, then the whole string in @ntpr
- * is a number otherwise it returns -EINVAL.
- *
- * RETURN VALUE
- * Unlike from strtol() function, this wrapper returns either
- * -EINVAL or the errno set by strtol() function (e.g -ERANGE).
- * If the conversion overflows, -ERANGE is returned, and @result
- * is set to the max value of the desired type
- * (e.g. LONG_MAX, LLONG_MAX, ULONG_MAX, ULLONG_MAX). If the case
- * of underflow, -ERANGE is returned, and @result is set to the min
- * value of the desired type. For strtol(), strtoll(), @result is set to
- * LONG_MIN, LLONG_MIN, respectively, and for strtoul(), strtoull() it
- * is set to 0.
+ * Convert string @nptr to a long integer, and store it in @result.
+ *
+ * This is a wrapper around strtol() that is harder to misuse.
+ * Semantics of @nptr, @endptr, @base match strtol() with differences
+ * noted below.
+ *
+ * @nptr may be null, and no conversion is performed then.
+ *
+ * If no conversion is performed, store @nptr in *@endptr and return
+ * -EINVAL.
+ *
+ * If @endptr is null, and the string isn't fully converted, return
+ * -EINVAL. This is the case when the pointer that would be stored in
+ * a non-null @endptr points to a character other than '\0'.
+ *
+ * If the conversion overflows @result, store LONG_MAX in @result,
+ * and return -ERANGE.
+ *
+ * If the conversion underflows @result, store LONG_MIN in @result,
+ * and return -ERANGE.
+ *
+ * Else store the converted value in @result, and return zero.
*/
int qemu_strtol(const char *nptr, const char **endptr, int base,
long *result)
{
- char *p;
- int err = 0;
+ char *ep;
+
if (!nptr) {
if (endptr) {
*endptr = nptr;
}
- err = -EINVAL;
- } else {
- errno = 0;
- *result = strtol(nptr, &p, base);
- err = check_strtox_error(nptr, p, endptr, errno);
+ return -EINVAL;
}
- return err;
+
+ errno = 0;
+ *result = strtol(nptr, &ep, base);
+ return check_strtox_error(nptr, ep, endptr, errno);
}
/**
- * Converts ASCII string to an unsigned long integer.
+ * Convert string @nptr to an unsigned long, and store it in @result.
+ *
+ * This is a wrapper around strtoul() that is harder to misuse.
+ * Semantics of @nptr, @endptr, @base match strtoul() with differences
+ * noted below.
+ *
+ * @nptr may be null, and no conversion is performed then.
*
- * If string contains a negative number, value will be converted to
- * the unsigned representation of the signed value, unless the original
- * (nonnegated) value would overflow, in this case, it will set @result
- * to ULONG_MAX, and return ERANGE.
+ * If no conversion is performed, store @nptr in *@endptr and return
+ * -EINVAL.
*
- * The same behavior holds, for qemu_strtoull() but sets @result to
- * ULLONG_MAX instead of ULONG_MAX.
+ * If @endptr is null, and the string isn't fully converted, return
+ * -EINVAL. This is the case when the pointer that would be stored in
+ * a non-null @endptr points to a character other than '\0'.
*
- * See qemu_strtol() documentation for more info.
+ * If the conversion overflows @result, store ULONG_MAX in @result,
+ * and return -ERANGE.
+ *
+ * Else store the converted value in @result, and return zero.
+ *
+ * Note that a number with a leading minus sign gets converted without
+ * the minus sign, checked for overflow (see above), then negated (in
+ * @result's type). This is exactly how strtoul() works.
*/
int qemu_strtoul(const char *nptr, const char **endptr, int base,
unsigned long *result)
{
- char *p;
- int err = 0;
+ char *ep;
+
if (!nptr) {
if (endptr) {
*endptr = nptr;
}
- err = -EINVAL;
- } else {
- errno = 0;
- *result = strtoul(nptr, &p, base);
- /* Windows returns 1 for negative out-of-range values. */
- if (errno == ERANGE) {
- *result = -1;
- }
- err = check_strtox_error(nptr, p, endptr, errno);
+ return -EINVAL;
+ }
+
+ errno = 0;
+ *result = strtoul(nptr, &ep, base);
+ /* Windows returns 1 for negative out-of-range values. */
+ if (errno == ERANGE) {
+ *result = -1;
}
- return err;
+ return check_strtox_error(nptr, ep, endptr, errno);
}
/**
- * Converts ASCII string to a long long integer.
+ * Convert string @nptr to an int64_t.
*
- * See qemu_strtol() documentation for more info.
+ * Works like qemu_strtol(), except it stores INT64_MAX on overflow,
+ * and INT_MIN on underflow.
*/
-int qemu_strtoll(const char *nptr, const char **endptr, int base,
+int qemu_strtoi64(const char *nptr, const char **endptr, int base,
int64_t *result)
{
- char *p;
- int err = 0;
+ char *ep;
+
if (!nptr) {
if (endptr) {
*endptr = nptr;
}
- err = -EINVAL;
- } else {
- errno = 0;
- *result = strtoll(nptr, &p, base);
- err = check_strtox_error(nptr, p, endptr, errno);
+ return -EINVAL;
}
- return err;
+
+ errno = 0;
+ /* FIXME This assumes int64_t is long long */
+ *result = strtoll(nptr, &ep, base);
+ return check_strtox_error(nptr, ep, endptr, errno);
}
/**
- * Converts ASCII string to an unsigned long long integer.
+ * Convert string @nptr to an uint64_t.
*
- * See qemu_strtol() documentation for more info.
+ * Works like qemu_strtoul(), except it stores UINT64_MAX on overflow.
*/
-int qemu_strtoull(const char *nptr, const char **endptr, int base,
+int qemu_strtou64(const char *nptr, const char **endptr, int base,
uint64_t *result)
{
- char *p;
- int err = 0;
+ char *ep;
+
if (!nptr) {
if (endptr) {
*endptr = nptr;
}
- err = -EINVAL;
- } else {
- errno = 0;
- *result = strtoull(nptr, &p, base);
- /* Windows returns 1 for negative out-of-range values. */
- if (errno == ERANGE) {
- *result = -1;
- }
- err = check_strtox_error(nptr, p, endptr, errno);
+ return -EINVAL;
+ }
+
+ errno = 0;
+ /* FIXME This assumes uint64_t is unsigned long long */
+ *result = strtoull(nptr, &ep, base);
+ /* Windows returns 1 for negative out-of-range values. */
+ if (errno == ERANGE) {
+ *result = -1;
}
- return err;
+ return check_strtox_error(nptr, ep, endptr, errno);
}
/**
diff --git a/util/log.c b/util/log.c
index e077340ae1..96f30dd21a 100644
--- a/util/log.c
+++ b/util/log.c
@@ -183,13 +183,13 @@ void qemu_set_dfilter_ranges(const char *filter_spec, Error **errp)
goto out;
}
- if (qemu_strtoull(r, &e, 0, &r1val)
+ if (qemu_strtou64(r, &e, 0, &r1val)
|| e != range_op) {
error_setg(errp, "Invalid number to the left of %.*s",
(int)(r2 - range_op), range_op);
goto out;
}
- if (qemu_strtoull(r2, NULL, 0, &r2val)) {
+ if (qemu_strtou64(r2, NULL, 0, &r2val)) {
error_setg(errp, "Invalid number to the right of %.*s",
(int)(r2 - range_op), range_op);
goto out;
diff --git a/util/qemu-option.c b/util/qemu-option.c
index d611946333..419f2528b8 100644
--- a/util/qemu-option.c
+++ b/util/qemu-option.c
@@ -128,36 +128,33 @@ int get_param_value(char *buf, int buf_size,
static void parse_option_bool(const char *name, const char *value, bool *ret,
Error **errp)
{
- if (value != NULL) {
- if (!strcmp(value, "on")) {
- *ret = 1;
- } else if (!strcmp(value, "off")) {
- *ret = 0;
- } else {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- name, "'on' or 'off'");
- }
- } else {
+ if (!strcmp(value, "on")) {
*ret = 1;
+ } else if (!strcmp(value, "off")) {
+ *ret = 0;
+ } else {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
+ name, "'on' or 'off'");
}
}
static void parse_option_number(const char *name, const char *value,
uint64_t *ret, Error **errp)
{
- char *postfix;
uint64_t number;
+ int err;
- if (value != NULL) {
- number = strtoull(value, &postfix, 0);
- if (*postfix != '\0') {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, "a number");
- return;
- }
- *ret = number;
- } else {
+ err = qemu_strtou64(value, NULL, 0, &number);
+ if (err == -ERANGE) {
+ error_setg(errp, "Value '%s' is too large for parameter '%s'",
+ value, name);
+ return;
+ }
+ if (err) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, "a number");
+ return;
}
+ *ret = number;
}
static const QemuOptDesc *find_desc_by_name(const QemuOptDesc *desc,
@@ -177,43 +174,24 @@ static const QemuOptDesc *find_desc_by_name(const QemuOptDesc *desc,
void parse_option_size(const char *name, const char *value,
uint64_t *ret, Error **errp)
{
- char *postfix;
- double sizef;
-
- if (value != NULL) {
- sizef = strtod(value, &postfix);
- if (sizef < 0 || sizef > UINT64_MAX) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name,
- "a non-negative number below 2^64");
- return;
- }
- switch (*postfix) {
- case 'T':
- sizef *= 1024;
- /* fall through */
- case 'G':
- sizef *= 1024;
- /* fall through */
- case 'M':
- sizef *= 1024;
- /* fall through */
- case 'K':
- case 'k':
- sizef *= 1024;
- /* fall through */
- case 'b':
- case '\0':
- *ret = (uint64_t) sizef;
- break;
- default:
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, "a size");
- error_append_hint(errp, "You may use k, M, G or T suffixes for "
- "kilobytes, megabytes, gigabytes and terabytes.\n");
- return;
- }
- } else {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, "a size");
+ uint64_t size;
+ int err;
+
+ err = qemu_strtosz(value, NULL, &size);
+ if (err == -ERANGE) {
+ error_setg(errp, "Value '%s' is too large for parameter '%s'",
+ value, name);
+ return;
+ }
+ if (err) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name,
+ "a non-negative number below 2^64");
+ error_append_hint(errp, "Optional suffix k, M, G, T, P or E means"
+ " kilo-, mega-, giga-, tera-, peta-\n"
+ "and exabytes, respectively.\n");
+ return;
}
+ *ret = size;
}
bool has_help_option(const char *param)
@@ -566,6 +544,7 @@ static void opt_set(QemuOpts *opts, const char *name, const char *value,
}
opt->desc = desc;
opt->str = g_strdup(value);
+ assert(opt->str);
qemu_opt_parse(opt, &local_err);
if (local_err) {
error_propagate(errp, local_err);
diff --git a/vl.c b/vl.c
index b5d0a19811..904e34b72c 100644
--- a/vl.c
+++ b/vl.c
@@ -1492,7 +1492,7 @@ MachineInfoList *qmp_query_machines(Error **errp)
info->name = g_strdup(mc->name);
info->cpu_max = !mc->max_cpus ? 1 : mc->max_cpus;
- info->hotpluggable_cpus = !!mc->query_hotpluggable_cpus;
+ info->hotpluggable_cpus = mc->has_hotpluggable_cpus;
entry = g_malloc0(sizeof(*entry));
entry->value = info;