Compare commits
76 Commits
pull-vnc-2
...
prep-for-2
Author | SHA1 | Date | |
---|---|---|---|
|
f205da688b | ||
|
2403837e67 | ||
|
d16644ec4c | ||
|
1fe9e2626f | ||
|
1ae1dc5ba2 | ||
|
9a1839164c | ||
|
49a4e21251 | ||
|
d1a1451cd3 | ||
|
037b7addb7 | ||
|
abdffd1fb7 | ||
|
39f72ef94b | ||
|
7e4fb26d75 | ||
|
9561fda8d9 | ||
|
c6aed98334 | ||
|
f5ec6704c7 | ||
|
c8897e8eb9 | ||
|
f5946dbab3 | ||
|
f71e769d07 | ||
|
c01a71c1a5 | ||
|
ec864874bd | ||
|
4c8821d134 | ||
|
c1b94a0ed2 | ||
|
319c66d5ab | ||
|
198fd05c35 | ||
|
20fccb187c | ||
|
b7d769c932 | ||
|
a134d90f50 | ||
|
8a15b813e6 | ||
|
d208cc353a | ||
|
6e6507c06b | ||
|
5a8a30db47 | ||
|
09e037354b | ||
|
0a79bc87c3 | ||
|
f72dbf3d26 | ||
|
ce8f0905a5 | ||
|
22709e90a2 | ||
|
bd16430777 | ||
|
059b3527f0 | ||
|
2dda43bacc | ||
|
1ed27a17cd | ||
|
c2fb418e35 | ||
|
5553955eb6 | ||
|
5201c13654 | ||
|
8b092ca9ef | ||
|
b6d4443a7b | ||
|
7baeabce1d | ||
|
2ed3ea110f | ||
|
a847f32c04 | ||
|
14dcdac82f | ||
|
03df01ed9a | ||
|
37a706adbf | ||
|
8f0c6758b0 | ||
|
a566da1b02 | ||
|
931c8cc270 | ||
|
261a5b4dd1 | ||
|
04c7c6c261 | ||
|
73a81d10fd | ||
|
6781fa119f | ||
|
c1b876b2e9 | ||
|
b05c306857 | ||
|
f612537e07 | ||
|
10113b6903 | ||
|
cf4ab1af29 | ||
|
a984e42c91 | ||
|
d6d60581f3 | ||
|
ba7500852d | ||
|
4719ab918a | ||
|
b5a3ca3e30 | ||
|
9948c38bd9 | ||
|
e0eb210ec0 | ||
|
a7ec0f98e3 | ||
|
1c275925bf | ||
|
6b1275ff15 | ||
8d5d30046b | |||
|
3b899ea7d4 | ||
|
7f72cd235f |
28
block.c
28
block.c
@@ -4781,27 +4781,43 @@ flush_parent:
|
||||
return bdrv_co_flush(bs->file);
|
||||
}
|
||||
|
||||
void bdrv_invalidate_cache(BlockDriverState *bs)
|
||||
void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
|
||||
if (!bs->drv) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bs->drv->bdrv_invalidate_cache) {
|
||||
bs->drv->bdrv_invalidate_cache(bs);
|
||||
bs->drv->bdrv_invalidate_cache(bs, &local_err);
|
||||
} else if (bs->file) {
|
||||
bdrv_invalidate_cache(bs->file);
|
||||
bdrv_invalidate_cache(bs->file, &local_err);
|
||||
}
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
refresh_total_sectors(bs, bs->total_sectors);
|
||||
ret = refresh_total_sectors(bs, bs->total_sectors);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not refresh total sector count");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_invalidate_cache_all(void)
|
||||
void bdrv_invalidate_cache_all(Error **errp)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
Error *local_err = NULL;
|
||||
|
||||
QTAILQ_FOREACH(bs, &bdrv_states, device_list) {
|
||||
bdrv_invalidate_cache(bs);
|
||||
bdrv_invalidate_cache(bs, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -112,6 +112,9 @@ nfs_co_generic_cb(int ret, struct nfs_context *nfs, void *data,
|
||||
if (task->ret == 0 && task->st) {
|
||||
memcpy(task->st, data, sizeof(struct stat));
|
||||
}
|
||||
if (task->ret < 0) {
|
||||
error_report("NFS Error: %s", nfs_get_error(nfs));
|
||||
}
|
||||
if (task->co) {
|
||||
task->bh = qemu_bh_new(nfs_co_generic_bh_cb, task);
|
||||
qemu_bh_schedule(task->bh);
|
||||
|
@@ -1383,7 +1383,7 @@ static int write_reftable_entry(BlockDriverState *bs, int rt_index)
|
||||
* does _not_ decrement the reference count for the currently occupied cluster.
|
||||
*
|
||||
* This function prints an informative message to stderr on error (and returns
|
||||
* -errno); on success, 0 is returned.
|
||||
* -errno); on success, the offset of the newly allocated cluster is returned.
|
||||
*/
|
||||
static int64_t realloc_refcount_block(BlockDriverState *bs, int reftable_index,
|
||||
uint64_t offset)
|
||||
@@ -1399,14 +1399,14 @@ static int64_t realloc_refcount_block(BlockDriverState *bs, int reftable_index,
|
||||
fprintf(stderr, "Could not allocate new cluster: %s\n",
|
||||
strerror(-new_offset));
|
||||
ret = new_offset;
|
||||
goto fail;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* fetch current refcount block content */
|
||||
ret = qcow2_cache_get(bs, s->refcount_block_cache, offset, &refcount_block);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Could not fetch refcount block: %s\n", strerror(-ret));
|
||||
goto fail;
|
||||
goto fail_free_cluster;
|
||||
}
|
||||
|
||||
/* new block has not yet been entered into refcount table, therefore it is
|
||||
@@ -1417,8 +1417,7 @@ static int64_t realloc_refcount_block(BlockDriverState *bs, int reftable_index,
|
||||
"check failed: %s\n", strerror(-ret));
|
||||
/* the image will be marked corrupt, so don't even attempt on freeing
|
||||
* the cluster */
|
||||
new_offset = 0;
|
||||
goto fail;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* write to new block */
|
||||
@@ -1426,7 +1425,7 @@ static int64_t realloc_refcount_block(BlockDriverState *bs, int reftable_index,
|
||||
s->cluster_sectors);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Could not write refcount block: %s\n", strerror(-ret));
|
||||
goto fail;
|
||||
goto fail_free_cluster;
|
||||
}
|
||||
|
||||
/* update refcount table */
|
||||
@@ -1436,24 +1435,27 @@ static int64_t realloc_refcount_block(BlockDriverState *bs, int reftable_index,
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Could not update refcount table: %s\n",
|
||||
strerror(-ret));
|
||||
goto fail;
|
||||
goto fail_free_cluster;
|
||||
}
|
||||
|
||||
fail:
|
||||
if (new_offset && (ret < 0)) {
|
||||
qcow2_free_clusters(bs, new_offset, s->cluster_size,
|
||||
QCOW2_DISCARD_ALWAYS);
|
||||
}
|
||||
goto done;
|
||||
|
||||
fail_free_cluster:
|
||||
qcow2_free_clusters(bs, new_offset, s->cluster_size, QCOW2_DISCARD_OTHER);
|
||||
|
||||
done:
|
||||
if (refcount_block) {
|
||||
if (ret < 0) {
|
||||
qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
|
||||
} else {
|
||||
ret = qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
|
||||
}
|
||||
/* This should never fail, as it would only do so if the given refcount
|
||||
* block cannot be found in the cache. As this is impossible as long as
|
||||
* there are no bugs, assert the success. */
|
||||
int tmp = qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
|
||||
assert(tmp == 0);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return new_offset;
|
||||
}
|
||||
|
||||
|
@@ -1156,7 +1156,7 @@ static void qcow2_close(BlockDriverState *bs)
|
||||
qcow2_free_snapshots(bs);
|
||||
}
|
||||
|
||||
static void qcow2_invalidate_cache(BlockDriverState *bs)
|
||||
static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int flags = s->flags;
|
||||
@@ -1164,6 +1164,8 @@ static void qcow2_invalidate_cache(BlockDriverState *bs)
|
||||
AES_KEY aes_decrypt_key;
|
||||
uint32_t crypt_method = 0;
|
||||
QDict *options;
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Backing files are read-only which makes all of their metadata immutable,
|
||||
@@ -1178,11 +1180,25 @@ static void qcow2_invalidate_cache(BlockDriverState *bs)
|
||||
|
||||
qcow2_close(bs);
|
||||
|
||||
bdrv_invalidate_cache(bs->file);
|
||||
bdrv_invalidate_cache(bs->file, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(s, 0, sizeof(BDRVQcowState));
|
||||
options = qdict_clone_shallow(bs->options);
|
||||
qcow2_open(bs, options, flags, NULL);
|
||||
|
||||
ret = qcow2_open(bs, options, flags, &local_err);
|
||||
if (local_err) {
|
||||
error_setg(errp, "Could not reopen qcow2 layer: %s",
|
||||
error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
return;
|
||||
} else if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not reopen qcow2 layer");
|
||||
return;
|
||||
}
|
||||
|
||||
QDECREF(options);
|
||||
|
||||
|
21
block/qed.c
21
block/qed.c
@@ -1558,16 +1558,31 @@ static int bdrv_qed_change_backing_file(BlockDriverState *bs,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void bdrv_qed_invalidate_cache(BlockDriverState *bs)
|
||||
static void bdrv_qed_invalidate_cache(BlockDriverState *bs, Error **errp)
|
||||
{
|
||||
BDRVQEDState *s = bs->opaque;
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
|
||||
bdrv_qed_close(bs);
|
||||
|
||||
bdrv_invalidate_cache(bs->file);
|
||||
bdrv_invalidate_cache(bs->file, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(s, 0, sizeof(BDRVQEDState));
|
||||
bdrv_qed_open(bs, NULL, bs->open_flags, NULL);
|
||||
ret = bdrv_qed_open(bs, NULL, bs->open_flags, &local_err);
|
||||
if (local_err) {
|
||||
error_setg(errp, "Could not reopen qed layer: %s",
|
||||
error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
return;
|
||||
} else if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not reopen qed layer");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int bdrv_qed_check(BlockDriverState *bs, BdrvCheckResult *result,
|
||||
|
@@ -625,13 +625,18 @@ static int64_t quorum_getlength(BlockDriverState *bs)
|
||||
return result;
|
||||
}
|
||||
|
||||
static void quorum_invalidate_cache(BlockDriverState *bs)
|
||||
static void quorum_invalidate_cache(BlockDriverState *bs, Error **errp)
|
||||
{
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
Error *local_err = NULL;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
bdrv_invalidate_cache(s->bs[i]);
|
||||
bdrv_invalidate_cache(s->bs[i], &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
2
configure
vendored
2
configure
vendored
@@ -3868,7 +3868,7 @@ fi
|
||||
##########################################
|
||||
# Do we have libnfs
|
||||
if test "$libnfs" != "no" ; then
|
||||
if $pkg_config --atleast-version=1.9.2 libnfs; then
|
||||
if $pkg_config --atleast-version=1.9.3 libnfs; then
|
||||
libnfs="yes"
|
||||
libnfs_libs=$($pkg_config --libs libnfs)
|
||||
LIBS="$LIBS $libnfs_libs"
|
||||
|
2
exec.c
2
exec.c
@@ -420,7 +420,7 @@ static int cpu_common_post_load(void *opaque, int version_id)
|
||||
/* 0x01 was CPU_INTERRUPT_EXIT. This line can be removed when the
|
||||
version_id is increased. */
|
||||
cpu->interrupt_request &= ~0x01;
|
||||
tlb_flush(cpu->env_ptr, 1);
|
||||
tlb_flush(cpu, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -288,7 +288,7 @@ INLINE flag extractFloat32Sign( float32 a )
|
||||
| If `a' is denormal and we are in flush-to-zero mode then set the
|
||||
| input-denormal exception and return zero. Otherwise just return the value.
|
||||
*----------------------------------------------------------------------------*/
|
||||
static float32 float32_squash_input_denormal(float32 a STATUS_PARAM)
|
||||
float32 float32_squash_input_denormal(float32 a STATUS_PARAM)
|
||||
{
|
||||
if (STATUS(flush_inputs_to_zero)) {
|
||||
if (extractFloat32Exp(a) == 0 && extractFloat32Frac(a) != 0) {
|
||||
@@ -473,7 +473,7 @@ INLINE flag extractFloat64Sign( float64 a )
|
||||
| If `a' is denormal and we are in flush-to-zero mode then set the
|
||||
| input-denormal exception and return zero. Otherwise just return the value.
|
||||
*----------------------------------------------------------------------------*/
|
||||
static float64 float64_squash_input_denormal(float64 a STATUS_PARAM)
|
||||
float64 float64_squash_input_denormal(float64 a STATUS_PARAM)
|
||||
{
|
||||
if (STATUS(flush_inputs_to_zero)) {
|
||||
if (extractFloat64Exp(a) == 0 && extractFloat64Frac(a) != 0) {
|
||||
|
@@ -143,11 +143,21 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
|
||||
unsigned long mem_size;
|
||||
DeviceState *dev;
|
||||
SysBusDevice *busdev;
|
||||
ObjectClass *cpu_oc;
|
||||
|
||||
cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, "cortex-a9");
|
||||
assert(cpu_oc);
|
||||
|
||||
for (n = 0; n < EXYNOS4210_NCPUS; n++) {
|
||||
s->cpu[n] = cpu_arm_init("cortex-a9");
|
||||
if (!s->cpu[n]) {
|
||||
fprintf(stderr, "Unable to find CPU %d definition\n", n);
|
||||
Object *cpuobj = object_new(object_class_get_name(cpu_oc));
|
||||
Error *err = NULL;
|
||||
|
||||
s->cpu[n] = ARM_CPU(cpuobj);
|
||||
object_property_set_int(cpuobj, EXYNOS4210_SMP_PRIVATE_BASE_ADDR,
|
||||
"reset-cbar", &error_abort);
|
||||
object_property_set_bool(cpuobj, true, "realized", &err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#include "hw/i2c/i2c.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
#define SMP_BOOT_ADDR 0xe0000000
|
||||
#define SMP_BOOTREG_ADDR 0x10000030
|
||||
@@ -49,6 +50,7 @@ static void realview_init(QEMUMachineInitArgs *args,
|
||||
{
|
||||
ARMCPU *cpu = NULL;
|
||||
CPUARMState *env;
|
||||
ObjectClass *cpu_oc;
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
MemoryRegion *ram_lo = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *ram_hi = g_new(MemoryRegion, 1);
|
||||
@@ -70,12 +72,14 @@ static void realview_init(QEMUMachineInitArgs *args,
|
||||
uint32_t sys_id;
|
||||
ram_addr_t low_ram_size;
|
||||
ram_addr_t ram_size = args->ram_size;
|
||||
hwaddr periphbase = 0;
|
||||
|
||||
switch (board_type) {
|
||||
case BOARD_EB:
|
||||
break;
|
||||
case BOARD_EB_MPCORE:
|
||||
is_mpcore = 1;
|
||||
periphbase = 0x10100000;
|
||||
break;
|
||||
case BOARD_PB_A8:
|
||||
is_pb = 1;
|
||||
@@ -83,16 +87,37 @@ static void realview_init(QEMUMachineInitArgs *args,
|
||||
case BOARD_PBX_A9:
|
||||
is_mpcore = 1;
|
||||
is_pb = 1;
|
||||
periphbase = 0x1f000000;
|
||||
break;
|
||||
}
|
||||
|
||||
cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, args->cpu_model);
|
||||
if (!cpu_oc) {
|
||||
fprintf(stderr, "Unable to find CPU definition\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (n = 0; n < smp_cpus; n++) {
|
||||
cpu = cpu_arm_init(args->cpu_model);
|
||||
if (!cpu) {
|
||||
fprintf(stderr, "Unable to find CPU definition\n");
|
||||
Object *cpuobj = object_new(object_class_get_name(cpu_oc));
|
||||
Error *err = NULL;
|
||||
|
||||
if (is_pb && is_mpcore) {
|
||||
object_property_set_int(cpuobj, periphbase, "reset-cbar", &err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
object_property_set_bool(cpuobj, true, "realized", &err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
exit(1);
|
||||
}
|
||||
cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ);
|
||||
|
||||
cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpuobj), ARM_CPU_IRQ);
|
||||
}
|
||||
cpu = ARM_CPU(first_cpu);
|
||||
env = &cpu->env;
|
||||
if (arm_feature(env, ARM_FEATURE_V7)) {
|
||||
if (is_mpcore) {
|
||||
@@ -141,16 +166,10 @@ static void realview_init(QEMUMachineInitArgs *args,
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000);
|
||||
|
||||
if (is_mpcore) {
|
||||
hwaddr periphbase;
|
||||
dev = qdev_create(NULL, is_pb ? "a9mpcore_priv": "realview_mpcore");
|
||||
qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
|
||||
qdev_init_nofail(dev);
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
if (is_pb) {
|
||||
periphbase = 0x1f000000;
|
||||
} else {
|
||||
periphbase = 0x10100000;
|
||||
}
|
||||
sysbus_mmio_map(busdev, 0, periphbase);
|
||||
for (n = 0; n < smp_cpus; n++) {
|
||||
sysbus_connect_irq(busdev, n, cpu_irq[n]);
|
||||
|
@@ -32,6 +32,7 @@
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "sysemu/device_tree.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include <libfdt.h>
|
||||
|
||||
#define VEXPRESS_BOARD_ID 0x8e0
|
||||
@@ -173,6 +174,64 @@ struct VEDBoardInfo {
|
||||
DBoardInitFn *init;
|
||||
};
|
||||
|
||||
static void init_cpus(const char *cpu_model, const char *privdev,
|
||||
hwaddr periphbase, qemu_irq *pic)
|
||||
{
|
||||
ObjectClass *cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
|
||||
DeviceState *dev;
|
||||
SysBusDevice *busdev;
|
||||
int n;
|
||||
|
||||
if (!cpu_oc) {
|
||||
fprintf(stderr, "Unable to find CPU definition\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Create the actual CPUs */
|
||||
for (n = 0; n < smp_cpus; n++) {
|
||||
Object *cpuobj = object_new(object_class_get_name(cpu_oc));
|
||||
Error *err = NULL;
|
||||
|
||||
object_property_set_int(cpuobj, periphbase, "reset-cbar", &err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
exit(1);
|
||||
}
|
||||
object_property_set_bool(cpuobj, true, "realized", &err);
|
||||
if (err) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the private peripheral devices (including the GIC);
|
||||
* this must happen after the CPUs are created because a15mpcore_priv
|
||||
* wires itself up to the CPU's generic_timer gpio out lines.
|
||||
*/
|
||||
dev = qdev_create(NULL, privdev);
|
||||
qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
|
||||
qdev_init_nofail(dev);
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
sysbus_mmio_map(busdev, 0, periphbase);
|
||||
|
||||
/* Interrupts [42:0] are from the motherboard;
|
||||
* [47:43] are reserved; [63:48] are daughterboard
|
||||
* peripherals. Note that some documentation numbers
|
||||
* external interrupts starting from 32 (because there
|
||||
* are internal interrupts 0..31).
|
||||
*/
|
||||
for (n = 0; n < 64; n++) {
|
||||
pic[n] = qdev_get_gpio_in(dev, n);
|
||||
}
|
||||
|
||||
/* Connect the CPUs to the GIC */
|
||||
for (n = 0; n < smp_cpus; n++) {
|
||||
DeviceState *cpudev = DEVICE(qemu_get_cpu(n));
|
||||
|
||||
sysbus_connect_irq(busdev, n, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
|
||||
}
|
||||
}
|
||||
|
||||
static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
|
||||
ram_addr_t ram_size,
|
||||
const char *cpu_model,
|
||||
@@ -181,25 +240,12 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *lowram = g_new(MemoryRegion, 1);
|
||||
DeviceState *dev;
|
||||
SysBusDevice *busdev;
|
||||
int n;
|
||||
qemu_irq cpu_irq[4];
|
||||
ram_addr_t low_ram_size;
|
||||
|
||||
if (!cpu_model) {
|
||||
cpu_model = "cortex-a9";
|
||||
}
|
||||
|
||||
for (n = 0; n < smp_cpus; n++) {
|
||||
ARMCPU *cpu = cpu_arm_init(cpu_model);
|
||||
if (!cpu) {
|
||||
fprintf(stderr, "Unable to find CPU definition\n");
|
||||
exit(1);
|
||||
}
|
||||
cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ);
|
||||
}
|
||||
|
||||
if (ram_size > 0x40000000) {
|
||||
/* 1GB is the maximum the address space permits */
|
||||
fprintf(stderr, "vexpress-a9: cannot model more than 1GB RAM\n");
|
||||
@@ -221,23 +267,7 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard,
|
||||
memory_region_add_subregion(sysmem, 0x60000000, ram);
|
||||
|
||||
/* 0x1e000000 A9MPCore (SCU) private memory region */
|
||||
dev = qdev_create(NULL, "a9mpcore_priv");
|
||||
qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
|
||||
qdev_init_nofail(dev);
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
sysbus_mmio_map(busdev, 0, 0x1e000000);
|
||||
for (n = 0; n < smp_cpus; n++) {
|
||||
sysbus_connect_irq(busdev, n, cpu_irq[n]);
|
||||
}
|
||||
/* Interrupts [42:0] are from the motherboard;
|
||||
* [47:43] are reserved; [63:48] are daughterboard
|
||||
* peripherals. Note that some documentation numbers
|
||||
* external interrupts starting from 32 (because the
|
||||
* A9MP has internal interrupts 0..31).
|
||||
*/
|
||||
for (n = 0; n < 64; n++) {
|
||||
pic[n] = qdev_get_gpio_in(dev, n);
|
||||
}
|
||||
init_cpus(cpu_model, "a9mpcore_priv", 0x1e000000, pic);
|
||||
|
||||
/* Daughterboard peripherals : 0x10020000 .. 0x20000000 */
|
||||
|
||||
@@ -296,29 +326,14 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard,
|
||||
const char *cpu_model,
|
||||
qemu_irq *pic)
|
||||
{
|
||||
int n;
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *sram = g_new(MemoryRegion, 1);
|
||||
qemu_irq cpu_irq[4];
|
||||
DeviceState *dev;
|
||||
SysBusDevice *busdev;
|
||||
|
||||
if (!cpu_model) {
|
||||
cpu_model = "cortex-a15";
|
||||
}
|
||||
|
||||
for (n = 0; n < smp_cpus; n++) {
|
||||
ARMCPU *cpu;
|
||||
|
||||
cpu = cpu_arm_init(cpu_model);
|
||||
if (!cpu) {
|
||||
fprintf(stderr, "Unable to find CPU definition\n");
|
||||
exit(1);
|
||||
}
|
||||
cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ);
|
||||
}
|
||||
|
||||
{
|
||||
/* We have to use a separate 64 bit variable here to avoid the gcc
|
||||
* "comparison is always false due to limited range of data type"
|
||||
@@ -337,23 +352,7 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard,
|
||||
memory_region_add_subregion(sysmem, 0x80000000, ram);
|
||||
|
||||
/* 0x2c000000 A15MPCore private memory region (GIC) */
|
||||
dev = qdev_create(NULL, "a15mpcore_priv");
|
||||
qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
|
||||
qdev_init_nofail(dev);
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
sysbus_mmio_map(busdev, 0, 0x2c000000);
|
||||
for (n = 0; n < smp_cpus; n++) {
|
||||
sysbus_connect_irq(busdev, n, cpu_irq[n]);
|
||||
}
|
||||
/* Interrupts [42:0] are from the motherboard;
|
||||
* [47:43] are reserved; [63:48] are daughterboard
|
||||
* peripherals. Note that some documentation numbers
|
||||
* external interrupts starting from 32 (because there
|
||||
* are internal interrupts 0..31).
|
||||
*/
|
||||
for (n = 0; n < 64; n++) {
|
||||
pic[n] = qdev_get_gpio_in(dev, n);
|
||||
}
|
||||
init_cpus(cpu_model, "a15mpcore_priv", 0x2c000000, pic);
|
||||
|
||||
/* A15 daughterboard peripherals: */
|
||||
|
||||
|
@@ -390,6 +390,12 @@ static void machvirt_init(QEMUMachineInitArgs *args)
|
||||
if (n > 0) {
|
||||
object_property_set_bool(cpuobj, true, "start-powered-off", NULL);
|
||||
}
|
||||
|
||||
if (object_property_find(cpuobj, "reset-cbar", NULL)) {
|
||||
object_property_set_int(cpuobj, vbi->memmap[VIRT_CPUPERIPHS].base,
|
||||
"reset-cbar", &error_abort);
|
||||
}
|
||||
|
||||
object_property_set_bool(cpuobj, true, "realized", NULL);
|
||||
}
|
||||
fdt_add_cpu_nodes(vbi);
|
||||
|
@@ -393,7 +393,6 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
|
||||
if (blk->iothread) {
|
||||
s->internal_iothread = false;
|
||||
s->iothread = blk->iothread;
|
||||
object_ref(OBJECT(s->iothread));
|
||||
} else {
|
||||
/* Create per-device IOThread if none specified */
|
||||
Error *local_err = NULL;
|
||||
@@ -408,6 +407,7 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
|
||||
s->iothread = iothread_find(vdev->name);
|
||||
assert(s->iothread);
|
||||
}
|
||||
object_ref(OBJECT(s->iothread));
|
||||
s->ctx = iothread_get_aio_context(s->iothread);
|
||||
|
||||
/* Prevent block operations that conflict with data plane thread */
|
||||
|
@@ -20,6 +20,7 @@ typedef struct PL011State {
|
||||
uint32_t readbuff;
|
||||
uint32_t flags;
|
||||
uint32_t lcr;
|
||||
uint32_t rsr;
|
||||
uint32_t cr;
|
||||
uint32_t dmacr;
|
||||
uint32_t int_enabled;
|
||||
@@ -81,13 +82,14 @@ static uint64_t pl011_read(void *opaque, hwaddr offset,
|
||||
}
|
||||
if (s->read_count == s->read_trigger - 1)
|
||||
s->int_level &= ~ PL011_INT_RX;
|
||||
s->rsr = c >> 8;
|
||||
pl011_update(s);
|
||||
if (s->chr) {
|
||||
qemu_chr_accept_input(s->chr);
|
||||
}
|
||||
return c;
|
||||
case 1: /* UARTCR */
|
||||
return 0;
|
||||
case 1: /* UARTRSR */
|
||||
return s->rsr;
|
||||
case 6: /* UARTFR */
|
||||
return s->flags;
|
||||
case 8: /* UARTILPR */
|
||||
@@ -146,8 +148,8 @@ static void pl011_write(void *opaque, hwaddr offset,
|
||||
s->int_level |= PL011_INT_TX;
|
||||
pl011_update(s);
|
||||
break;
|
||||
case 1: /* UARTCR */
|
||||
s->cr = value;
|
||||
case 1: /* UARTRSR/UARTECR */
|
||||
s->rsr = 0;
|
||||
break;
|
||||
case 6: /* UARTFR */
|
||||
/* Writes to Flag register are ignored. */
|
||||
@@ -162,6 +164,11 @@ static void pl011_write(void *opaque, hwaddr offset,
|
||||
s->fbrd = value;
|
||||
break;
|
||||
case 11: /* UARTLCR_H */
|
||||
/* Reset the FIFO state on FIFO enable or disable */
|
||||
if ((s->lcr ^ value) & 0x10) {
|
||||
s->read_count = 0;
|
||||
s->read_pos = 0;
|
||||
}
|
||||
s->lcr = value;
|
||||
pl011_set_read_trigger(s);
|
||||
break;
|
||||
@@ -214,7 +221,7 @@ static void pl011_put_fifo(void *opaque, uint32_t value)
|
||||
s->read_fifo[slot] = value;
|
||||
s->read_count++;
|
||||
s->flags &= ~PL011_FLAG_RXFE;
|
||||
if (s->cr & 0x10 || s->read_count == 16) {
|
||||
if (!(s->lcr & 0x10) || s->read_count == 16) {
|
||||
s->flags |= PL011_FLAG_RXFF;
|
||||
}
|
||||
if (s->read_count == s->read_trigger) {
|
||||
@@ -242,13 +249,14 @@ static const MemoryRegionOps pl011_ops = {
|
||||
|
||||
static const VMStateDescription vmstate_pl011 = {
|
||||
.name = "pl011",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.minimum_version_id_old = 2,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(readbuff, PL011State),
|
||||
VMSTATE_UINT32(flags, PL011State),
|
||||
VMSTATE_UINT32(lcr, PL011State),
|
||||
VMSTATE_UINT32(rsr, PL011State),
|
||||
VMSTATE_UINT32(cr, PL011State),
|
||||
VMSTATE_UINT32(dmacr, PL011State),
|
||||
VMSTATE_UINT32(int_enabled, PL011State),
|
||||
|
@@ -21,6 +21,18 @@ void qdev_prop_set_after_realize(DeviceState *dev, const char *name,
|
||||
}
|
||||
}
|
||||
|
||||
void qdev_prop_allow_set_link_before_realize(Object *obj, const char *name,
|
||||
Object *val, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
|
||||
if (dev->realized) {
|
||||
error_setg(errp, "Attempt to set link property '%s' on device '%s' "
|
||||
"(type '%s') after it was realized",
|
||||
name, dev->id, object_get_typename(obj));
|
||||
}
|
||||
}
|
||||
|
||||
void *qdev_get_prop_ptr(DeviceState *dev, Property *prop)
|
||||
{
|
||||
void *ptr = dev;
|
||||
|
@@ -98,6 +98,8 @@ static void bus_add_child(BusState *bus, DeviceState *child)
|
||||
object_property_add_link(OBJECT(bus), name,
|
||||
object_get_typename(OBJECT(child)),
|
||||
(Object **)&kid->child,
|
||||
NULL, /* read-only property */
|
||||
0, /* return ownership on prop deletion */
|
||||
NULL);
|
||||
}
|
||||
|
||||
@@ -824,7 +826,8 @@ static void device_initfn(Object *obj)
|
||||
} while (class != object_class_by_name(TYPE_DEVICE));
|
||||
|
||||
object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS,
|
||||
(Object **)&dev->parent_bus, &error_abort);
|
||||
(Object **)&dev->parent_bus, NULL, 0,
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
static void device_post_init(Object *obj)
|
||||
@@ -944,7 +947,10 @@ static void qbus_initfn(Object *obj)
|
||||
QTAILQ_INIT(&bus->children);
|
||||
object_property_add_link(obj, QDEV_HOTPLUG_HANDLER_PROPERTY,
|
||||
TYPE_HOTPLUG_HANDLER,
|
||||
(Object **)&bus->hotplug_handler, NULL);
|
||||
(Object **)&bus->hotplug_handler,
|
||||
object_property_allow_set_link,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||
NULL);
|
||||
object_property_add_bool(obj, "realized",
|
||||
bus_get_realized, bus_set_realized, NULL);
|
||||
}
|
||||
|
@@ -537,9 +537,15 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp)
|
||||
Error *local_errp = NULL;
|
||||
|
||||
object_property_add_link(OBJECT(ds), "dma", TYPE_XILINX_AXI_DMA,
|
||||
(Object **)&ds->dma, &local_errp);
|
||||
(Object **)&ds->dma,
|
||||
object_property_allow_set_link,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||
&local_errp);
|
||||
object_property_add_link(OBJECT(cs), "dma", TYPE_XILINX_AXI_DMA,
|
||||
(Object **)&cs->dma, &local_errp);
|
||||
(Object **)&cs->dma,
|
||||
object_property_allow_set_link,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||
&local_errp);
|
||||
if (local_errp) {
|
||||
goto xilinx_axidma_realize_fail;
|
||||
}
|
||||
@@ -571,10 +577,16 @@ static void xilinx_axidma_init(Object *obj)
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
|
||||
(Object **)&s->tx_data_dev, &error_abort);
|
||||
(Object **)&s->tx_data_dev,
|
||||
qdev_prop_allow_set_link_before_realize,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||
&error_abort);
|
||||
object_property_add_link(obj, "axistream-control-connected",
|
||||
TYPE_STREAM_SLAVE,
|
||||
(Object **)&s->tx_control_dev, &error_abort);
|
||||
(Object **)&s->tx_control_dev,
|
||||
qdev_prop_allow_set_link_before_realize,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||
&error_abort);
|
||||
|
||||
object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev),
|
||||
TYPE_XILINX_AXI_DMA_DATA_STREAM);
|
||||
|
@@ -118,11 +118,12 @@ static uint32_t ahci_port_read(AHCIState *s, int port, int offset)
|
||||
static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev)
|
||||
{
|
||||
AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
|
||||
PCIDevice *pci_dev = PCI_DEVICE(d);
|
||||
PCIDevice *pci_dev =
|
||||
(PCIDevice *)object_dynamic_cast(OBJECT(d), TYPE_PCI_DEVICE);
|
||||
|
||||
DPRINTF(0, "raise irq\n");
|
||||
|
||||
if (msi_enabled(pci_dev)) {
|
||||
if (pci_dev && msi_enabled(pci_dev)) {
|
||||
msi_notify(pci_dev, 0);
|
||||
} else {
|
||||
qemu_irq_raise(s->irq);
|
||||
@@ -132,10 +133,12 @@ static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev)
|
||||
static void ahci_irq_lower(AHCIState *s, AHCIDevice *dev)
|
||||
{
|
||||
AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
|
||||
PCIDevice *pci_dev =
|
||||
(PCIDevice *)object_dynamic_cast(OBJECT(d), TYPE_PCI_DEVICE);
|
||||
|
||||
DPRINTF(0, "lower irq\n");
|
||||
|
||||
if (!msi_enabled(PCI_DEVICE(d))) {
|
||||
if (!pci_dev || !msi_enabled(pci_dev)) {
|
||||
qemu_irq_lower(s->irq);
|
||||
}
|
||||
}
|
||||
@@ -1311,7 +1314,7 @@ static const VMStateDescription vmstate_sysbus_ahci = {
|
||||
.name = "sysbus-ahci",
|
||||
.unmigratable = 1, /* Still buggy under I/O load */
|
||||
.fields = (VMStateField []) {
|
||||
VMSTATE_AHCI(ahci, AHCIPCIState),
|
||||
VMSTATE_AHCI(ahci, SysbusAHCIState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
@@ -1328,7 +1331,7 @@ static void sysbus_ahci_realize(DeviceState *dev, Error **errp)
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
SysbusAHCIState *s = SYSBUS_AHCI(dev);
|
||||
|
||||
ahci_init(&s->ahci, dev, NULL, s->num_ports);
|
||||
ahci_init(&s->ahci, dev, &address_space_memory, s->num_ports);
|
||||
|
||||
sysbus_init_mmio(sbd, &s->ahci.mem);
|
||||
sysbus_init_irq(sbd, &s->ahci.irq);
|
||||
|
@@ -945,9 +945,15 @@ static void xilinx_enet_realize(DeviceState *dev, Error **errp)
|
||||
Error *local_errp = NULL;
|
||||
|
||||
object_property_add_link(OBJECT(ds), "enet", "xlnx.axi-ethernet",
|
||||
(Object **) &ds->enet, &local_errp);
|
||||
(Object **) &ds->enet,
|
||||
object_property_allow_set_link,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||
&local_errp);
|
||||
object_property_add_link(OBJECT(cs), "enet", "xlnx.axi-ethernet",
|
||||
(Object **) &cs->enet, &local_errp);
|
||||
(Object **) &cs->enet,
|
||||
object_property_allow_set_link,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||
&local_errp);
|
||||
if (local_errp) {
|
||||
goto xilinx_enet_realize_fail;
|
||||
}
|
||||
@@ -982,10 +988,16 @@ static void xilinx_enet_init(Object *obj)
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
|
||||
(Object **) &s->tx_data_dev, &error_abort);
|
||||
(Object **) &s->tx_data_dev,
|
||||
qdev_prop_allow_set_link_before_realize,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||
&error_abort);
|
||||
object_property_add_link(obj, "axistream-control-connected",
|
||||
TYPE_STREAM_SLAVE,
|
||||
(Object **) &s->tx_control_dev, &error_abort);
|
||||
(Object **) &s->tx_control_dev,
|
||||
qdev_prop_allow_set_link_before_realize,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||
&error_abort);
|
||||
|
||||
object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev),
|
||||
TYPE_XILINX_AXI_ENET_DATA_STREAM);
|
||||
|
@@ -52,15 +52,25 @@ typedef struct RavenPCIState {
|
||||
typedef struct PRePPCIState {
|
||||
PCIHostState parent_obj;
|
||||
|
||||
MemoryRegion intack;
|
||||
qemu_irq irq[PCI_NUM_PINS];
|
||||
PCIBus pci_bus;
|
||||
AddressSpace pci_io_as;
|
||||
MemoryRegion pci_io;
|
||||
MemoryRegion pci_io_non_contiguous;
|
||||
MemoryRegion pci_memory;
|
||||
MemoryRegion pci_intack;
|
||||
MemoryRegion bm;
|
||||
MemoryRegion bm_ram_alias;
|
||||
MemoryRegion bm_pci_memory_alias;
|
||||
AddressSpace bm_as;
|
||||
RavenPCIState pci_dev;
|
||||
|
||||
int contiguous_map;
|
||||
} PREPPCIState;
|
||||
|
||||
#define BIOS_SIZE (1024 * 1024)
|
||||
|
||||
static inline uint32_t PPC_PCIIO_config(hwaddr addr)
|
||||
static inline uint32_t raven_pci_io_config(hwaddr addr)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -72,53 +82,133 @@ static inline uint32_t PPC_PCIIO_config(hwaddr addr)
|
||||
return (addr & 0x7ff) | (i << 11);
|
||||
}
|
||||
|
||||
static void ppc_pci_io_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned int size)
|
||||
static void raven_pci_io_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned int size)
|
||||
{
|
||||
PREPPCIState *s = opaque;
|
||||
PCIHostState *phb = PCI_HOST_BRIDGE(s);
|
||||
pci_data_write(phb->bus, PPC_PCIIO_config(addr), val, size);
|
||||
pci_data_write(phb->bus, raven_pci_io_config(addr), val, size);
|
||||
}
|
||||
|
||||
static uint64_t ppc_pci_io_read(void *opaque, hwaddr addr,
|
||||
unsigned int size)
|
||||
static uint64_t raven_pci_io_read(void *opaque, hwaddr addr,
|
||||
unsigned int size)
|
||||
{
|
||||
PREPPCIState *s = opaque;
|
||||
PCIHostState *phb = PCI_HOST_BRIDGE(s);
|
||||
return pci_data_read(phb->bus, PPC_PCIIO_config(addr), size);
|
||||
return pci_data_read(phb->bus, raven_pci_io_config(addr), size);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps PPC_PCIIO_ops = {
|
||||
.read = ppc_pci_io_read,
|
||||
.write = ppc_pci_io_write,
|
||||
static const MemoryRegionOps raven_pci_io_ops = {
|
||||
.read = raven_pci_io_read,
|
||||
.write = raven_pci_io_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static uint64_t ppc_intack_read(void *opaque, hwaddr addr,
|
||||
unsigned int size)
|
||||
static uint64_t raven_intack_read(void *opaque, hwaddr addr,
|
||||
unsigned int size)
|
||||
{
|
||||
return pic_read_irq(isa_pic);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps PPC_intack_ops = {
|
||||
.read = ppc_intack_read,
|
||||
static const MemoryRegionOps raven_intack_ops = {
|
||||
.read = raven_intack_read,
|
||||
.valid = {
|
||||
.max_access_size = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static int prep_map_irq(PCIDevice *pci_dev, int irq_num)
|
||||
static inline hwaddr raven_io_address(PREPPCIState *s,
|
||||
hwaddr addr)
|
||||
{
|
||||
if (s->contiguous_map == 0) {
|
||||
/* 64 KB contiguous space for IOs */
|
||||
addr &= 0xFFFF;
|
||||
} else {
|
||||
/* 8 MB non-contiguous space for IOs */
|
||||
addr = (addr & 0x1F) | ((addr & 0x007FFF000) >> 7);
|
||||
}
|
||||
|
||||
/* FIXME: handle endianness switch */
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
static uint64_t raven_io_read(void *opaque, hwaddr addr,
|
||||
unsigned int size)
|
||||
{
|
||||
PREPPCIState *s = opaque;
|
||||
uint8_t buf[4];
|
||||
|
||||
addr = raven_io_address(s, addr);
|
||||
address_space_read(&s->pci_io_as, addr + 0x80000000, buf, size);
|
||||
|
||||
if (size == 1) {
|
||||
return buf[0];
|
||||
} else if (size == 2) {
|
||||
return lduw_p(buf);
|
||||
} else if (size == 4) {
|
||||
return ldl_p(buf);
|
||||
} else {
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static void raven_io_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned int size)
|
||||
{
|
||||
PREPPCIState *s = opaque;
|
||||
uint8_t buf[4];
|
||||
|
||||
addr = raven_io_address(s, addr);
|
||||
|
||||
if (size == 1) {
|
||||
buf[0] = val;
|
||||
} else if (size == 2) {
|
||||
stw_p(buf, val);
|
||||
} else if (size == 4) {
|
||||
stl_p(buf, val);
|
||||
} else {
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
address_space_write(&s->pci_io_as, addr + 0x80000000, buf, size);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps raven_io_ops = {
|
||||
.read = raven_io_read,
|
||||
.write = raven_io_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.impl.max_access_size = 4,
|
||||
.valid.unaligned = true,
|
||||
};
|
||||
|
||||
static int raven_map_irq(PCIDevice *pci_dev, int irq_num)
|
||||
{
|
||||
return (irq_num + (pci_dev->devfn >> 3)) & 1;
|
||||
}
|
||||
|
||||
static void prep_set_irq(void *opaque, int irq_num, int level)
|
||||
static void raven_set_irq(void *opaque, int irq_num, int level)
|
||||
{
|
||||
qemu_irq *pic = opaque;
|
||||
|
||||
qemu_set_irq(pic[irq_num] , level);
|
||||
}
|
||||
|
||||
static AddressSpace *raven_pcihost_set_iommu(PCIBus *bus, void *opaque,
|
||||
int devfn)
|
||||
{
|
||||
PREPPCIState *s = opaque;
|
||||
|
||||
return &s->bm_as;
|
||||
}
|
||||
|
||||
static void raven_change_gpio(void *opaque, int n, int level)
|
||||
{
|
||||
PREPPCIState *s = opaque;
|
||||
|
||||
s->contiguous_map = level;
|
||||
}
|
||||
|
||||
static void raven_pcihost_realizefn(DeviceState *d, Error **errp)
|
||||
{
|
||||
SysBusDevice *dev = SYS_BUS_DEVICE(d);
|
||||
@@ -127,29 +217,30 @@ static void raven_pcihost_realizefn(DeviceState *d, Error **errp)
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
int i;
|
||||
|
||||
isa_mem_base = 0xc0000000;
|
||||
|
||||
for (i = 0; i < PCI_NUM_PINS; i++) {
|
||||
sysbus_init_irq(dev, &s->irq[i]);
|
||||
}
|
||||
|
||||
pci_bus_irqs(&s->pci_bus, prep_set_irq, prep_map_irq, s->irq, PCI_NUM_PINS);
|
||||
qdev_init_gpio_in(d, raven_change_gpio, 1);
|
||||
|
||||
memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_be_ops, s,
|
||||
"pci-conf-idx", 1);
|
||||
sysbus_add_io(dev, 0xcf8, &h->conf_mem);
|
||||
sysbus_init_ioports(&h->busdev, 0xcf8, 1);
|
||||
pci_bus_irqs(&s->pci_bus, raven_set_irq, raven_map_irq, s->irq,
|
||||
PCI_NUM_PINS);
|
||||
|
||||
memory_region_init_io(&h->data_mem, OBJECT(h), &pci_host_data_be_ops, s,
|
||||
"pci-conf-data", 1);
|
||||
sysbus_add_io(dev, 0xcfc, &h->data_mem);
|
||||
sysbus_init_ioports(&h->busdev, 0xcfc, 1);
|
||||
memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_le_ops, s,
|
||||
"pci-conf-idx", 4);
|
||||
memory_region_add_subregion(&s->pci_io, 0xcf8, &h->conf_mem);
|
||||
|
||||
memory_region_init_io(&h->mmcfg, OBJECT(s), &PPC_PCIIO_ops, s, "pciio", 0x00400000);
|
||||
memory_region_init_io(&h->data_mem, OBJECT(h), &pci_host_data_le_ops, s,
|
||||
"pci-conf-data", 4);
|
||||
memory_region_add_subregion(&s->pci_io, 0xcfc, &h->data_mem);
|
||||
|
||||
memory_region_init_io(&h->mmcfg, OBJECT(s), &raven_pci_io_ops, s,
|
||||
"pciio", 0x00400000);
|
||||
memory_region_add_subregion(address_space_mem, 0x80800000, &h->mmcfg);
|
||||
|
||||
memory_region_init_io(&s->intack, OBJECT(s), &PPC_intack_ops, s, "pci-intack", 1);
|
||||
memory_region_add_subregion(address_space_mem, 0xbffffff0, &s->intack);
|
||||
memory_region_init_io(&s->pci_intack, OBJECT(s), &raven_intack_ops, s,
|
||||
"pci-intack", 1);
|
||||
memory_region_add_subregion(address_space_mem, 0xbffffff0, &s->pci_intack);
|
||||
|
||||
/* TODO Remove once realize propagates to child devices. */
|
||||
object_property_set_bool(OBJECT(&s->pci_dev), true, "realized", errp);
|
||||
@@ -160,11 +251,36 @@ static void raven_pcihost_initfn(Object *obj)
|
||||
PCIHostState *h = PCI_HOST_BRIDGE(obj);
|
||||
PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(obj);
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
MemoryRegion *address_space_io = get_system_io();
|
||||
DeviceState *pci_dev;
|
||||
|
||||
memory_region_init(&s->pci_io, obj, "pci-io", 0x3f800000);
|
||||
memory_region_init_io(&s->pci_io_non_contiguous, obj, &raven_io_ops, s,
|
||||
"pci-io-non-contiguous", 0x00800000);
|
||||
/* Open Hack'Ware hack: real size should be only 0x3f000000 bytes */
|
||||
memory_region_init(&s->pci_memory, obj, "pci-memory",
|
||||
0x3f000000 + 0xc0000000ULL);
|
||||
address_space_init(&s->pci_io_as, &s->pci_io, "raven-io");
|
||||
|
||||
/* CPU address space */
|
||||
memory_region_add_subregion(address_space_mem, 0x80000000, &s->pci_io);
|
||||
memory_region_add_subregion_overlap(address_space_mem, 0x80000000,
|
||||
&s->pci_io_non_contiguous, 1);
|
||||
memory_region_add_subregion(address_space_mem, 0xc0000000, &s->pci_memory);
|
||||
pci_bus_new_inplace(&s->pci_bus, sizeof(s->pci_bus), DEVICE(obj), NULL,
|
||||
address_space_mem, address_space_io, 0, TYPE_PCI_BUS);
|
||||
&s->pci_memory, &s->pci_io, 0, TYPE_PCI_BUS);
|
||||
|
||||
/* Bus master address space */
|
||||
memory_region_init(&s->bm, obj, "bm-raven", UINT32_MAX);
|
||||
memory_region_init_alias(&s->bm_pci_memory_alias, obj, "bm-pci-memory",
|
||||
&s->pci_memory, 0,
|
||||
memory_region_size(&s->pci_memory));
|
||||
memory_region_init_alias(&s->bm_ram_alias, obj, "bm-system",
|
||||
get_system_memory(), 0, 0x80000000);
|
||||
memory_region_add_subregion(&s->bm, 0 , &s->bm_pci_memory_alias);
|
||||
memory_region_add_subregion(&s->bm, 0x80000000, &s->bm_ram_alias);
|
||||
address_space_init(&s->bm_as, &s->bm, "raven-bm");
|
||||
pci_setup_iommu(&s->pci_bus, raven_pcihost_set_iommu, s);
|
||||
|
||||
h->bus = &s->pci_bus;
|
||||
|
||||
object_initialize(&s->pci_dev, sizeof(s->pci_dev), TYPE_RAVEN_PCI_DEVICE);
|
||||
|
@@ -198,7 +198,9 @@ static void pxa2xx_pcmcia_initfn(Object *obj)
|
||||
s->slot.irq = qemu_allocate_irqs(pxa2xx_pcmcia_set_irq, s, 1)[0];
|
||||
|
||||
object_property_add_link(obj, "card", TYPE_PCMCIA_CARD,
|
||||
(Object **)&s->card, NULL);
|
||||
(Object **)&s->card,
|
||||
NULL, /* read-only property */
|
||||
0, NULL);
|
||||
}
|
||||
|
||||
/* Insert a new card into a slot */
|
||||
|
103
hw/ppc/prep.c
103
hw/ppc/prep.c
@@ -185,6 +185,7 @@ typedef struct sysctrl_t {
|
||||
uint8_t state;
|
||||
uint8_t syscontrol;
|
||||
int contiguous_map;
|
||||
qemu_irq contiguous_map_irq;
|
||||
int endian;
|
||||
} sysctrl_t;
|
||||
|
||||
@@ -253,6 +254,7 @@ static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val)
|
||||
case 0x0850:
|
||||
/* I/O map type register */
|
||||
sysctrl->contiguous_map = val & 0x01;
|
||||
qemu_set_irq(sysctrl->contiguous_map_irq, sysctrl->contiguous_map);
|
||||
break;
|
||||
default:
|
||||
printf("ERROR: unaffected IO port write: %04" PRIx32
|
||||
@@ -327,91 +329,6 @@ static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr)
|
||||
return retval;
|
||||
}
|
||||
|
||||
static inline hwaddr prep_IO_address(sysctrl_t *sysctrl,
|
||||
hwaddr addr)
|
||||
{
|
||||
if (sysctrl->contiguous_map == 0) {
|
||||
/* 64 KB contiguous space for IOs */
|
||||
addr &= 0xFFFF;
|
||||
} else {
|
||||
/* 8 MB non-contiguous space for IOs */
|
||||
addr = (addr & 0x1F) | ((addr & 0x007FFF000) >> 7);
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
static void PPC_prep_io_writeb (void *opaque, hwaddr addr,
|
||||
uint32_t value)
|
||||
{
|
||||
sysctrl_t *sysctrl = opaque;
|
||||
|
||||
addr = prep_IO_address(sysctrl, addr);
|
||||
cpu_outb(addr, value);
|
||||
}
|
||||
|
||||
static uint32_t PPC_prep_io_readb (void *opaque, hwaddr addr)
|
||||
{
|
||||
sysctrl_t *sysctrl = opaque;
|
||||
uint32_t ret;
|
||||
|
||||
addr = prep_IO_address(sysctrl, addr);
|
||||
ret = cpu_inb(addr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void PPC_prep_io_writew (void *opaque, hwaddr addr,
|
||||
uint32_t value)
|
||||
{
|
||||
sysctrl_t *sysctrl = opaque;
|
||||
|
||||
addr = prep_IO_address(sysctrl, addr);
|
||||
PPC_IO_DPRINTF("0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", addr, value);
|
||||
cpu_outw(addr, value);
|
||||
}
|
||||
|
||||
static uint32_t PPC_prep_io_readw (void *opaque, hwaddr addr)
|
||||
{
|
||||
sysctrl_t *sysctrl = opaque;
|
||||
uint32_t ret;
|
||||
|
||||
addr = prep_IO_address(sysctrl, addr);
|
||||
ret = cpu_inw(addr);
|
||||
PPC_IO_DPRINTF("0x" TARGET_FMT_plx " <= 0x%08" PRIx32 "\n", addr, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void PPC_prep_io_writel (void *opaque, hwaddr addr,
|
||||
uint32_t value)
|
||||
{
|
||||
sysctrl_t *sysctrl = opaque;
|
||||
|
||||
addr = prep_IO_address(sysctrl, addr);
|
||||
PPC_IO_DPRINTF("0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", addr, value);
|
||||
cpu_outl(addr, value);
|
||||
}
|
||||
|
||||
static uint32_t PPC_prep_io_readl (void *opaque, hwaddr addr)
|
||||
{
|
||||
sysctrl_t *sysctrl = opaque;
|
||||
uint32_t ret;
|
||||
|
||||
addr = prep_IO_address(sysctrl, addr);
|
||||
ret = cpu_inl(addr);
|
||||
PPC_IO_DPRINTF("0x" TARGET_FMT_plx " <= 0x%08" PRIx32 "\n", addr, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps PPC_prep_io_ops = {
|
||||
.old_mmio = {
|
||||
.read = { PPC_prep_io_readb, PPC_prep_io_readw, PPC_prep_io_readl },
|
||||
.write = { PPC_prep_io_writeb, PPC_prep_io_writew, PPC_prep_io_writel },
|
||||
},
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
#define NVRAM_SIZE 0x2000
|
||||
|
||||
@@ -458,13 +375,13 @@ static void ppc_prep_init(QEMUMachineInitArgs *args)
|
||||
CPUPPCState *env = NULL;
|
||||
nvram_t nvram;
|
||||
M48t59State *m48t59;
|
||||
MemoryRegion *PPC_io_memory = g_new(MemoryRegion, 1);
|
||||
PortioList *port_list = g_new(PortioList, 1);
|
||||
#if 0
|
||||
MemoryRegion *xcsr = g_new(MemoryRegion, 1);
|
||||
#endif
|
||||
int linux_boot, i, nb_nics1;
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *vga = g_new(MemoryRegion, 1);
|
||||
uint32_t kernel_base, initrd_base;
|
||||
long kernel_size, initrd_size;
|
||||
DeviceState *dev;
|
||||
@@ -567,6 +484,7 @@ static void ppc_prep_init(QEMUMachineInitArgs *args)
|
||||
fprintf(stderr, "Couldn't create PCI host controller.\n");
|
||||
exit(1);
|
||||
}
|
||||
sysctrl->contiguous_map_irq = qdev_get_gpio_in(dev, 0);
|
||||
|
||||
/* PCI -> ISA bridge */
|
||||
pci = pci_create_simple(pci_bus, PCI_DEVFN(1, 0), "i82378");
|
||||
@@ -587,13 +505,16 @@ static void ppc_prep_init(QEMUMachineInitArgs *args)
|
||||
qdev_prop_set_uint8(dev, "config", 13); /* fdc, ser0, ser1, par0 */
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
/* Register 8 MB of ISA IO space (needed for non-contiguous map) */
|
||||
memory_region_init_io(PPC_io_memory, NULL, &PPC_prep_io_ops, sysctrl,
|
||||
"ppc-io", 0x00800000);
|
||||
memory_region_add_subregion(sysmem, 0x80000000, PPC_io_memory);
|
||||
|
||||
/* init basic PC hardware */
|
||||
pci_vga_init(pci_bus);
|
||||
/* Open Hack'Ware hack: PCI BAR#0 is programmed to 0xf0000000.
|
||||
* While bios will access framebuffer at 0xf0000000, real physical
|
||||
* address is 0xf0000000 + 0xc0000000 (PCI memory base).
|
||||
* Alias the wrong memory accesses to the right place.
|
||||
*/
|
||||
memory_region_init_alias(vga, NULL, "vga-alias", pci_address_space(pci),
|
||||
0xf0000000, 0x1000000);
|
||||
memory_region_add_subregion_overlap(sysmem, 0xf0000000, vga, 10);
|
||||
|
||||
nb_nics1 = nb_nics;
|
||||
if (nb_nics1 > NE2000_NB_MAX)
|
||||
|
@@ -313,7 +313,9 @@ static void s390_virtio_rng_instance_init(Object *obj)
|
||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG);
|
||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||
object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
|
||||
(Object **)&dev->vdev.conf.rng, NULL);
|
||||
(Object **)&dev->vdev.conf.rng,
|
||||
qdev_prop_allow_set_link_before_realize,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
|
||||
}
|
||||
|
||||
static uint64_t s390_virtio_device_vq_token(VirtIOS390Device *dev, int vq)
|
||||
|
@@ -1272,7 +1272,9 @@ static void virtio_ccw_rng_instance_init(Object *obj)
|
||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG);
|
||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||
object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
|
||||
(Object **)&dev->vdev.conf.rng, NULL);
|
||||
(Object **)&dev->vdev.conf.rng,
|
||||
qdev_prop_allow_set_link_before_realize,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
|
||||
}
|
||||
|
||||
static Property virtio_ccw_rng_properties[] = {
|
||||
|
@@ -1517,7 +1517,9 @@ static void virtio_rng_initfn(Object *obj)
|
||||
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG);
|
||||
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
|
||||
object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
|
||||
(Object **)&dev->vdev.conf.rng, NULL);
|
||||
(Object **)&dev->vdev.conf.rng,
|
||||
qdev_prop_allow_set_link_before_realize,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
|
||||
|
||||
}
|
||||
|
||||
|
@@ -162,6 +162,9 @@ static void virtio_rng_device_realize(DeviceState *dev, Error **errp)
|
||||
OBJECT(vrng->conf.default_backend),
|
||||
NULL);
|
||||
|
||||
/* The child property took a reference, we can safely drop ours now */
|
||||
object_unref(OBJECT(vrng->conf.default_backend));
|
||||
|
||||
object_property_set_link(OBJECT(dev),
|
||||
OBJECT(vrng->conf.default_backend),
|
||||
"rng", NULL);
|
||||
@@ -223,7 +226,9 @@ static void virtio_rng_initfn(Object *obj)
|
||||
VirtIORNG *vrng = VIRTIO_RNG(obj);
|
||||
|
||||
object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
|
||||
(Object **)&vrng->conf.rng, NULL);
|
||||
(Object **)&vrng->conf.rng,
|
||||
qdev_prop_allow_set_link_before_realize,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
|
||||
}
|
||||
|
||||
static const TypeInfo virtio_rng_info = {
|
||||
|
@@ -329,8 +329,8 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
|
||||
BlockDriverCompletionFunc *cb, void *opaque);
|
||||
|
||||
/* Invalidate any cached metadata used by image formats */
|
||||
void bdrv_invalidate_cache(BlockDriverState *bs);
|
||||
void bdrv_invalidate_cache_all(void);
|
||||
void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp);
|
||||
void bdrv_invalidate_cache_all(Error **errp);
|
||||
|
||||
void bdrv_clear_incoming_migration_all(void);
|
||||
|
||||
|
@@ -153,7 +153,7 @@ struct BlockDriver {
|
||||
/*
|
||||
* Invalidate any cached meta-data.
|
||||
*/
|
||||
void (*bdrv_invalidate_cache)(BlockDriverState *bs);
|
||||
void (*bdrv_invalidate_cache)(BlockDriverState *bs, Error **errp);
|
||||
|
||||
/*
|
||||
* Flushes all data that was already written to the OS all the way down to
|
||||
|
@@ -44,7 +44,7 @@ struct TranslationBlock;
|
||||
typedef struct TranslationBlock TranslationBlock;
|
||||
|
||||
/* XXX: make safe guess about sizes */
|
||||
#define MAX_OP_PER_INSTR 208
|
||||
#define MAX_OP_PER_INSTR 266
|
||||
|
||||
#if HOST_LONG_BITS == 32
|
||||
#define MAX_OPC_PARAM_PER_ARG 2
|
||||
|
@@ -244,6 +244,13 @@ INLINE flag get_default_nan_mode(float_status *status)
|
||||
*----------------------------------------------------------------------------*/
|
||||
void float_raise( int8 flags STATUS_PARAM);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| If `a' is denormal and we are in flush-to-zero mode then set the
|
||||
| input-denormal exception and return zero. Otherwise just return the value.
|
||||
*----------------------------------------------------------------------------*/
|
||||
float32 float32_squash_input_denormal(float32 a STATUS_PARAM);
|
||||
float64 float64_squash_input_denormal(float64 a STATUS_PARAM);
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Options to indicate which negations to perform in float*_muladd()
|
||||
| Using these differs from negating an input or output before calling
|
||||
|
@@ -54,6 +54,7 @@ struct QEMUMachine {
|
||||
int qemu_register_machine(QEMUMachine *m);
|
||||
|
||||
#define TYPE_MACHINE "machine"
|
||||
#undef MACHINE /* BSD defines it and QEMU does not use it */
|
||||
#define MACHINE(obj) \
|
||||
OBJECT_CHECK(MachineState, (obj), TYPE_MACHINE)
|
||||
#define MACHINE_GET_CLASS(obj) \
|
||||
|
@@ -204,4 +204,15 @@ void qdev_property_add_static(DeviceState *dev, Property *prop, Error **errp);
|
||||
*/
|
||||
void qdev_prop_set_after_realize(DeviceState *dev, const char *name,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* qdev_prop_allow_set_link_before_realize:
|
||||
*
|
||||
* Set the #Error object if an attempt is made to set the link after realize.
|
||||
* This function should be used as the check() argument to
|
||||
* object_property_add_link().
|
||||
*/
|
||||
void qdev_prop_allow_set_link_before_realize(Object *obj, const char *name,
|
||||
Object *val, Error **errp);
|
||||
|
||||
#endif
|
||||
|
@@ -227,7 +227,6 @@ struct CPUState {
|
||||
bool stop;
|
||||
bool stopped;
|
||||
volatile sig_atomic_t exit_request;
|
||||
volatile sig_atomic_t tcg_exit_req;
|
||||
uint32_t interrupt_request;
|
||||
int singlestep_enabled;
|
||||
int64_t icount_extra;
|
||||
@@ -272,6 +271,12 @@ struct CPUState {
|
||||
} icount_decr;
|
||||
uint32_t can_do_io;
|
||||
int32_t exception_index; /* used by m68k TCG */
|
||||
|
||||
/* Note that this is accessed at the start of every TB via a negative
|
||||
offset from AREG0. Leave this field at the end so as to make the
|
||||
(absolute value) offset as small as possible. This reduces code
|
||||
size, especially for hosts without large memory offsets. */
|
||||
volatile sig_atomic_t tcg_exit_req;
|
||||
};
|
||||
|
||||
QTAILQ_HEAD(CPUTailQ, CPUState);
|
||||
|
@@ -1067,12 +1067,29 @@ Object *object_resolve_path_component(Object *parent, const gchar *part);
|
||||
void object_property_add_child(Object *obj, const char *name,
|
||||
Object *child, Error **errp);
|
||||
|
||||
typedef enum {
|
||||
/* Unref the link pointer when the property is deleted */
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE = 0x1,
|
||||
} ObjectPropertyLinkFlags;
|
||||
|
||||
/**
|
||||
* object_property_allow_set_link:
|
||||
*
|
||||
* The default implementation of the object_property_add_link() check()
|
||||
* callback function. It allows the link property to be set and never returns
|
||||
* an error.
|
||||
*/
|
||||
void object_property_allow_set_link(Object *, const char *,
|
||||
Object *, Error **);
|
||||
|
||||
/**
|
||||
* object_property_add_link:
|
||||
* @obj: the object to add a property to
|
||||
* @name: the name of the property
|
||||
* @type: the qobj type of the link
|
||||
* @child: a pointer to where the link object reference is stored
|
||||
* @check: callback to veto setting or NULL if the property is read-only
|
||||
* @flags: additional options for the link
|
||||
* @errp: if an error occurs, a pointer to an area to store the area
|
||||
*
|
||||
* Links establish relationships between objects. Links are unidirectional
|
||||
@@ -1081,13 +1098,23 @@ void object_property_add_child(Object *obj, const char *name,
|
||||
*
|
||||
* Links form the graph in the object model.
|
||||
*
|
||||
* The <code>@check()</code> callback is invoked when
|
||||
* object_property_set_link() is called and can raise an error to prevent the
|
||||
* link being set. If <code>@check</code> is NULL, the property is read-only
|
||||
* and cannot be set.
|
||||
*
|
||||
* Ownership of the pointer that @child points to is transferred to the
|
||||
* link property. The reference count for <code>*@child</code> is
|
||||
* managed by the property from after the function returns till the
|
||||
* property is deleted with object_property_del().
|
||||
* property is deleted with object_property_del(). If the
|
||||
* <code>@flags</code> <code>OBJ_PROP_LINK_UNREF_ON_RELEASE</code> bit is set,
|
||||
* the reference count is decremented when the property is deleted.
|
||||
*/
|
||||
void object_property_add_link(Object *obj, const char *name,
|
||||
const char *type, Object **child,
|
||||
void (*check)(Object *obj, const char *name,
|
||||
Object *val, Error **errp),
|
||||
ObjectPropertyLinkFlags flags,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
|
@@ -352,6 +352,9 @@ enum
|
||||
ARM_HWCAP_ARM_VFPv3D16 = 1 << 13,
|
||||
};
|
||||
|
||||
#ifndef TARGET_AARCH64
|
||||
/* The commpage only exists for 32 bit kernels */
|
||||
|
||||
#define TARGET_HAS_VALIDATE_GUEST_SPACE
|
||||
/* Return 1 if the proposed guest space is suitable for the guest.
|
||||
* Return 0 if the proposed guest space isn't suitable, but another
|
||||
@@ -411,7 +414,7 @@ static int validate_guest_space(unsigned long guest_base,
|
||||
|
||||
return 1; /* All good */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define ELF_HWCAP get_elf_hwcap()
|
||||
|
||||
|
@@ -126,6 +126,7 @@ typedef struct TaskState {
|
||||
#endif
|
||||
uint32_t stack_base;
|
||||
int used; /* non zero if used */
|
||||
bool sigsegv_blocked; /* SIGSEGV blocked by guest */
|
||||
struct image_info *info;
|
||||
struct linux_binprm *bprm;
|
||||
|
||||
@@ -235,6 +236,7 @@ int host_to_target_signal(int sig);
|
||||
long do_sigreturn(CPUArchState *env);
|
||||
long do_rt_sigreturn(CPUArchState *env);
|
||||
abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp);
|
||||
int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
|
||||
|
||||
#ifdef TARGET_I386
|
||||
/* vm86.c */
|
||||
|
@@ -197,6 +197,55 @@ void target_to_host_old_sigset(sigset_t *sigset,
|
||||
target_to_host_sigset(sigset, &d);
|
||||
}
|
||||
|
||||
/* Wrapper for sigprocmask function
|
||||
* Emulates a sigprocmask in a safe way for the guest. Note that set and oldset
|
||||
* are host signal set, not guest ones. This wraps the sigprocmask host calls
|
||||
* that should be protected (calls originated from guest)
|
||||
*/
|
||||
int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
|
||||
{
|
||||
int ret;
|
||||
sigset_t val;
|
||||
sigset_t *temp = NULL;
|
||||
CPUState *cpu = thread_cpu;
|
||||
TaskState *ts = (TaskState *)cpu->opaque;
|
||||
bool segv_was_blocked = ts->sigsegv_blocked;
|
||||
|
||||
if (set) {
|
||||
bool has_sigsegv = sigismember(set, SIGSEGV);
|
||||
val = *set;
|
||||
temp = &val;
|
||||
|
||||
sigdelset(temp, SIGSEGV);
|
||||
|
||||
switch (how) {
|
||||
case SIG_BLOCK:
|
||||
if (has_sigsegv) {
|
||||
ts->sigsegv_blocked = true;
|
||||
}
|
||||
break;
|
||||
case SIG_UNBLOCK:
|
||||
if (has_sigsegv) {
|
||||
ts->sigsegv_blocked = false;
|
||||
}
|
||||
break;
|
||||
case SIG_SETMASK:
|
||||
ts->sigsegv_blocked = has_sigsegv;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
ret = sigprocmask(how, temp, oldset);
|
||||
|
||||
if (oldset && segv_was_blocked) {
|
||||
sigaddset(oldset, SIGSEGV);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* siginfo conversion */
|
||||
|
||||
static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
|
||||
@@ -458,6 +507,19 @@ int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info)
|
||||
k = &ts->sigtab[sig - 1];
|
||||
queue = gdb_queuesig ();
|
||||
handler = sigact_table[sig - 1]._sa_handler;
|
||||
|
||||
if (ts->sigsegv_blocked && sig == TARGET_SIGSEGV) {
|
||||
/* Guest has blocked SIGSEGV but we got one anyway. Assume this
|
||||
* is a forced SIGSEGV (ie one the kernel handles via force_sig_info
|
||||
* because it got a real MMU fault). A blocked SIGSEGV in that
|
||||
* situation is treated as if using the default handler. This is
|
||||
* not correct if some other process has randomly sent us a SIGSEGV
|
||||
* via kill(), but that is not easy to distinguish at this point,
|
||||
* so we assume it doesn't happen.
|
||||
*/
|
||||
handler = TARGET_SIG_DFL;
|
||||
}
|
||||
|
||||
if (!queue && handler == TARGET_SIG_DFL) {
|
||||
if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
|
||||
kill(getpid(),SIGSTOP);
|
||||
@@ -1056,7 +1118,7 @@ long do_sigreturn(CPUX86State *env)
|
||||
}
|
||||
|
||||
target_to_host_sigset_internal(&set, &target_set);
|
||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
do_sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
|
||||
/* restore registers */
|
||||
if (restore_sigcontext(env, &frame->sc, &eax))
|
||||
@@ -1081,7 +1143,7 @@ long do_rt_sigreturn(CPUX86State *env)
|
||||
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
|
||||
goto badframe;
|
||||
target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
|
||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
do_sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
|
||||
if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
|
||||
goto badframe;
|
||||
@@ -1220,7 +1282,7 @@ static int target_restore_sigframe(CPUARMState *env,
|
||||
uint64_t pstate;
|
||||
|
||||
target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
|
||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
do_sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
|
||||
for (i = 0; i < 31; i++) {
|
||||
__get_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
|
||||
@@ -1340,7 +1402,7 @@ static void setup_frame(int sig, struct target_sigaction *ka,
|
||||
|
||||
long do_rt_sigreturn(CPUARMState *env)
|
||||
{
|
||||
struct target_rt_sigframe *frame;
|
||||
struct target_rt_sigframe *frame = NULL;
|
||||
abi_ulong frame_addr = env->xregs[31];
|
||||
|
||||
if (frame_addr & 15) {
|
||||
@@ -1861,7 +1923,7 @@ static long do_sigreturn_v1(CPUARMState *env)
|
||||
}
|
||||
|
||||
target_to_host_sigset_internal(&host_set, &set);
|
||||
sigprocmask(SIG_SETMASK, &host_set, NULL);
|
||||
do_sigprocmask(SIG_SETMASK, &host_set, NULL);
|
||||
|
||||
if (restore_sigcontext(env, &frame->sc))
|
||||
goto badframe;
|
||||
@@ -1942,7 +2004,7 @@ static int do_sigframe_return_v2(CPUARMState *env, target_ulong frame_addr,
|
||||
abi_ulong *regspace;
|
||||
|
||||
target_to_host_sigset(&host_set, &uc->tuc_sigmask);
|
||||
sigprocmask(SIG_SETMASK, &host_set, NULL);
|
||||
do_sigprocmask(SIG_SETMASK, &host_set, NULL);
|
||||
|
||||
if (restore_sigcontext(env, &uc->tuc_mcontext))
|
||||
return 1;
|
||||
@@ -2033,7 +2095,7 @@ static long do_rt_sigreturn_v1(CPUARMState *env)
|
||||
goto badframe;
|
||||
|
||||
target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
|
||||
sigprocmask(SIG_SETMASK, &host_set, NULL);
|
||||
do_sigprocmask(SIG_SETMASK, &host_set, NULL);
|
||||
|
||||
if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
|
||||
goto badframe;
|
||||
@@ -2444,7 +2506,7 @@ long do_sigreturn(CPUSPARCState *env)
|
||||
}
|
||||
|
||||
target_to_host_sigset_internal(&host_set, &set);
|
||||
sigprocmask(SIG_SETMASK, &host_set, NULL);
|
||||
do_sigprocmask(SIG_SETMASK, &host_set, NULL);
|
||||
|
||||
if (err)
|
||||
goto segv_and_exit;
|
||||
@@ -2567,7 +2629,7 @@ void sparc64_set_context(CPUSPARCState *env)
|
||||
goto do_sigsegv;
|
||||
}
|
||||
target_to_host_sigset_internal(&set, &target_set);
|
||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
do_sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
}
|
||||
env->pc = pc;
|
||||
env->npc = npc;
|
||||
@@ -2656,7 +2718,7 @@ void sparc64_get_context(CPUSPARCState *env)
|
||||
|
||||
err = 0;
|
||||
|
||||
sigprocmask(0, NULL, &set);
|
||||
do_sigprocmask(0, NULL, &set);
|
||||
host_to_target_sigset_internal(&target_set, &set);
|
||||
if (TARGET_NSIG_WORDS == 1) {
|
||||
err |= __put_user(target_set.sig[0],
|
||||
@@ -2991,7 +3053,7 @@ long do_sigreturn(CPUMIPSState *regs)
|
||||
}
|
||||
|
||||
target_to_host_sigset_internal(&blocked, &target_set);
|
||||
sigprocmask(SIG_SETMASK, &blocked, NULL);
|
||||
do_sigprocmask(SIG_SETMASK, &blocked, NULL);
|
||||
|
||||
if (restore_sigcontext(regs, &frame->sf_sc))
|
||||
goto badframe;
|
||||
@@ -3095,7 +3157,7 @@ long do_rt_sigreturn(CPUMIPSState *env)
|
||||
goto badframe;
|
||||
|
||||
target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
|
||||
sigprocmask(SIG_SETMASK, &blocked, NULL);
|
||||
do_sigprocmask(SIG_SETMASK, &blocked, NULL);
|
||||
|
||||
if (restore_sigcontext(env, &frame->rs_uc.tuc_mcontext))
|
||||
goto badframe;
|
||||
@@ -3385,7 +3447,7 @@ long do_sigreturn(CPUSH4State *regs)
|
||||
goto badframe;
|
||||
|
||||
target_to_host_sigset_internal(&blocked, &target_set);
|
||||
sigprocmask(SIG_SETMASK, &blocked, NULL);
|
||||
do_sigprocmask(SIG_SETMASK, &blocked, NULL);
|
||||
|
||||
if (restore_sigcontext(regs, &frame->sc, &r0))
|
||||
goto badframe;
|
||||
@@ -3414,7 +3476,7 @@ long do_rt_sigreturn(CPUSH4State *regs)
|
||||
goto badframe;
|
||||
|
||||
target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
|
||||
sigprocmask(SIG_SETMASK, &blocked, NULL);
|
||||
do_sigprocmask(SIG_SETMASK, &blocked, NULL);
|
||||
|
||||
if (restore_sigcontext(regs, &frame->uc.tuc_mcontext, &r0))
|
||||
goto badframe;
|
||||
@@ -3644,7 +3706,7 @@ long do_sigreturn(CPUMBState *env)
|
||||
goto badframe;
|
||||
}
|
||||
target_to_host_sigset_internal(&set, &target_set);
|
||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
do_sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
|
||||
restore_sigcontext(&frame->uc.tuc_mcontext, env);
|
||||
/* We got here through a sigreturn syscall, our path back is via an
|
||||
@@ -3819,7 +3881,7 @@ long do_sigreturn(CPUCRISState *env)
|
||||
goto badframe;
|
||||
}
|
||||
target_to_host_sigset_internal(&set, &target_set);
|
||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
do_sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
|
||||
restore_sigcontext(&frame->sc, env);
|
||||
unlock_user_struct(frame, frame_addr, 0);
|
||||
@@ -4350,7 +4412,7 @@ long do_sigreturn(CPUS390XState *env)
|
||||
}
|
||||
|
||||
target_to_host_sigset_internal(&set, &target_set);
|
||||
sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
|
||||
do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
|
||||
|
||||
if (restore_sigregs(env, &frame->sregs)) {
|
||||
goto badframe;
|
||||
@@ -4378,7 +4440,7 @@ long do_rt_sigreturn(CPUS390XState *env)
|
||||
}
|
||||
target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
|
||||
|
||||
sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
|
||||
do_sigprocmask(SIG_SETMASK, &set, NULL); /* ~_BLOCKABLE? */
|
||||
|
||||
if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
|
||||
goto badframe;
|
||||
@@ -4906,7 +4968,7 @@ long do_sigreturn(CPUPPCState *env)
|
||||
goto sigsegv;
|
||||
#endif
|
||||
target_to_host_sigset_internal(&blocked, &set);
|
||||
sigprocmask(SIG_SETMASK, &blocked, NULL);
|
||||
do_sigprocmask(SIG_SETMASK, &blocked, NULL);
|
||||
|
||||
if (__get_user(sr_addr, &sc->regs))
|
||||
goto sigsegv;
|
||||
@@ -4950,7 +5012,7 @@ static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
|
||||
return 1;
|
||||
|
||||
target_to_host_sigset_internal(&blocked, &set);
|
||||
sigprocmask(SIG_SETMASK, &blocked, NULL);
|
||||
do_sigprocmask(SIG_SETMASK, &blocked, NULL);
|
||||
if (restore_user_regs(env, mcp, sig))
|
||||
goto sigsegv;
|
||||
|
||||
@@ -5324,7 +5386,7 @@ long do_sigreturn(CPUM68KState *env)
|
||||
}
|
||||
|
||||
target_to_host_sigset_internal(&set, &target_set);
|
||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
do_sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
|
||||
/* restore registers */
|
||||
|
||||
@@ -5352,7 +5414,7 @@ long do_rt_sigreturn(CPUM68KState *env)
|
||||
goto badframe;
|
||||
|
||||
target_to_host_sigset_internal(&set, &target_set);
|
||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
do_sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
|
||||
/* restore registers */
|
||||
|
||||
@@ -5599,7 +5661,7 @@ long do_sigreturn(CPUAlphaState *env)
|
||||
}
|
||||
|
||||
target_to_host_sigset_internal(&set, &target_set);
|
||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
do_sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
|
||||
if (restore_sigcontext(env, sc)) {
|
||||
goto badframe;
|
||||
@@ -5622,7 +5684,7 @@ long do_rt_sigreturn(CPUAlphaState *env)
|
||||
goto badframe;
|
||||
}
|
||||
target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
|
||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
do_sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
|
||||
if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
|
||||
goto badframe;
|
||||
@@ -5716,6 +5778,14 @@ void process_pending_signals(CPUArchState *cpu_env)
|
||||
handler = sa->_sa_handler;
|
||||
}
|
||||
|
||||
if (ts->sigsegv_blocked && sig == TARGET_SIGSEGV) {
|
||||
/* Guest has blocked SIGSEGV but we got one anyway. Assume this
|
||||
* is a forced SIGSEGV (ie one the kernel handles via force_sig_info
|
||||
* because it got a real MMU fault), and treat as if default handler.
|
||||
*/
|
||||
handler = TARGET_SIG_DFL;
|
||||
}
|
||||
|
||||
if (handler == TARGET_SIG_DFL) {
|
||||
/* default handler : ignore some signal. The other are job control or fatal */
|
||||
if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
|
||||
@@ -5739,7 +5809,7 @@ void process_pending_signals(CPUArchState *cpu_env)
|
||||
sigaddset(&set, target_to_host_signal(sig));
|
||||
|
||||
/* block signals in the handler using Linux */
|
||||
sigprocmask(SIG_BLOCK, &set, &old_set);
|
||||
do_sigprocmask(SIG_BLOCK, &set, &old_set);
|
||||
/* save the previous blocked signal state to restore it at the
|
||||
end of the signal execution (see do_sigreturn) */
|
||||
host_to_target_sigset_internal(&target_old_set, &old_set);
|
||||
|
@@ -43,6 +43,7 @@
|
||||
#include <sys/resource.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/swap.h>
|
||||
#include <linux/capability.h>
|
||||
#include <signal.h>
|
||||
#include <sched.h>
|
||||
#ifdef __ia64__
|
||||
@@ -243,6 +244,10 @@ _syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
|
||||
unsigned long *, user_mask_ptr);
|
||||
_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
|
||||
void *, arg);
|
||||
_syscall2(int, capget, struct __user_cap_header_struct *, header,
|
||||
struct __user_cap_data_struct *, data);
|
||||
_syscall2(int, capset, struct __user_cap_header_struct *, header,
|
||||
struct __user_cap_data_struct *, data);
|
||||
|
||||
static bitmask_transtbl fcntl_flags_tbl[] = {
|
||||
{ TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
|
||||
@@ -4421,6 +4426,14 @@ static int target_to_host_fcntl_cmd(int cmd)
|
||||
#endif
|
||||
case TARGET_F_NOTIFY:
|
||||
return F_NOTIFY;
|
||||
#ifdef F_GETOWN_EX
|
||||
case TARGET_F_GETOWN_EX:
|
||||
return F_GETOWN_EX;
|
||||
#endif
|
||||
#ifdef F_SETOWN_EX
|
||||
case TARGET_F_SETOWN_EX:
|
||||
return F_SETOWN_EX;
|
||||
#endif
|
||||
default:
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
@@ -4443,6 +4456,10 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
|
||||
struct target_flock *target_fl;
|
||||
struct flock64 fl64;
|
||||
struct target_flock64 *target_fl64;
|
||||
#ifdef F_GETOWN_EX
|
||||
struct f_owner_ex fox;
|
||||
struct target_f_owner_ex *target_fox;
|
||||
#endif
|
||||
abi_long ret;
|
||||
int host_cmd = target_to_host_fcntl_cmd(cmd);
|
||||
|
||||
@@ -4536,6 +4553,30 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
|
||||
ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
|
||||
break;
|
||||
|
||||
#ifdef F_GETOWN_EX
|
||||
case TARGET_F_GETOWN_EX:
|
||||
ret = get_errno(fcntl(fd, host_cmd, &fox));
|
||||
if (ret >= 0) {
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
|
||||
return -TARGET_EFAULT;
|
||||
target_fox->type = tswap32(fox.type);
|
||||
target_fox->pid = tswap32(fox.pid);
|
||||
unlock_user_struct(target_fox, arg, 1);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef F_SETOWN_EX
|
||||
case TARGET_F_SETOWN_EX:
|
||||
if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
|
||||
return -TARGET_EFAULT;
|
||||
fox.type = tswap32(target_fox->type);
|
||||
fox.pid = tswap32(target_fox->pid);
|
||||
unlock_user_struct(target_fox, arg, 0);
|
||||
ret = get_errno(fcntl(fd, host_cmd, &fox));
|
||||
break;
|
||||
#endif
|
||||
|
||||
case TARGET_F_SETOWN:
|
||||
case TARGET_F_GETOWN:
|
||||
case TARGET_F_SETSIG:
|
||||
@@ -5993,7 +6034,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
{
|
||||
sigset_t cur_set;
|
||||
abi_ulong target_set;
|
||||
sigprocmask(0, NULL, &cur_set);
|
||||
do_sigprocmask(0, NULL, &cur_set);
|
||||
host_to_target_old_sigset(&target_set, &cur_set);
|
||||
ret = target_set;
|
||||
}
|
||||
@@ -6004,10 +6045,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
{
|
||||
sigset_t set, oset, cur_set;
|
||||
abi_ulong target_set = arg1;
|
||||
sigprocmask(0, NULL, &cur_set);
|
||||
do_sigprocmask(0, NULL, &cur_set);
|
||||
target_to_host_old_sigset(&set, &target_set);
|
||||
sigorset(&set, &set, &cur_set);
|
||||
sigprocmask(SIG_SETMASK, &set, &oset);
|
||||
do_sigprocmask(SIG_SETMASK, &set, &oset);
|
||||
host_to_target_old_sigset(&target_set, &oset);
|
||||
ret = target_set;
|
||||
}
|
||||
@@ -6038,7 +6079,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
mask = arg2;
|
||||
target_to_host_old_sigset(&set, &mask);
|
||||
|
||||
ret = get_errno(sigprocmask(how, &set, &oldset));
|
||||
ret = get_errno(do_sigprocmask(how, &set, &oldset));
|
||||
if (!is_error(ret)) {
|
||||
host_to_target_old_sigset(&mask, &oldset);
|
||||
ret = mask;
|
||||
@@ -6072,7 +6113,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
how = 0;
|
||||
set_ptr = NULL;
|
||||
}
|
||||
ret = get_errno(sigprocmask(how, set_ptr, &oldset));
|
||||
ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
|
||||
if (!is_error(ret) && arg3) {
|
||||
if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
|
||||
goto efault;
|
||||
@@ -6112,7 +6153,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
how = 0;
|
||||
set_ptr = NULL;
|
||||
}
|
||||
ret = get_errno(sigprocmask(how, set_ptr, &oldset));
|
||||
ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
|
||||
if (!is_error(ret) && arg3) {
|
||||
if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
|
||||
goto efault;
|
||||
@@ -7641,9 +7682,75 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
unlock_user(p, arg1, ret);
|
||||
break;
|
||||
case TARGET_NR_capget:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_capset:
|
||||
goto unimplemented;
|
||||
{
|
||||
struct target_user_cap_header *target_header;
|
||||
struct target_user_cap_data *target_data = NULL;
|
||||
struct __user_cap_header_struct header;
|
||||
struct __user_cap_data_struct data[2];
|
||||
struct __user_cap_data_struct *dataptr = NULL;
|
||||
int i, target_datalen;
|
||||
int data_items = 1;
|
||||
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
|
||||
goto efault;
|
||||
}
|
||||
header.version = tswap32(target_header->version);
|
||||
header.pid = tswap32(target_header->pid);
|
||||
|
||||
if (header.version != _LINUX_CAPABILITY_VERSION) {
|
||||
/* Version 2 and up takes pointer to two user_data structs */
|
||||
data_items = 2;
|
||||
}
|
||||
|
||||
target_datalen = sizeof(*target_data) * data_items;
|
||||
|
||||
if (arg2) {
|
||||
if (num == TARGET_NR_capget) {
|
||||
target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
|
||||
} else {
|
||||
target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
|
||||
}
|
||||
if (!target_data) {
|
||||
unlock_user_struct(target_header, arg1, 0);
|
||||
goto efault;
|
||||
}
|
||||
|
||||
if (num == TARGET_NR_capset) {
|
||||
for (i = 0; i < data_items; i++) {
|
||||
data[i].effective = tswap32(target_data[i].effective);
|
||||
data[i].permitted = tswap32(target_data[i].permitted);
|
||||
data[i].inheritable = tswap32(target_data[i].inheritable);
|
||||
}
|
||||
}
|
||||
|
||||
dataptr = data;
|
||||
}
|
||||
|
||||
if (num == TARGET_NR_capget) {
|
||||
ret = get_errno(capget(&header, dataptr));
|
||||
} else {
|
||||
ret = get_errno(capset(&header, dataptr));
|
||||
}
|
||||
|
||||
/* The kernel always updates version for both capget and capset */
|
||||
target_header->version = tswap32(header.version);
|
||||
unlock_user_struct(target_header, arg1, 1);
|
||||
|
||||
if (arg2) {
|
||||
if (num == TARGET_NR_capget) {
|
||||
for (i = 0; i < data_items; i++) {
|
||||
target_data[i].effective = tswap32(data[i].effective);
|
||||
target_data[i].permitted = tswap32(data[i].permitted);
|
||||
target_data[i].inheritable = tswap32(data[i].inheritable);
|
||||
}
|
||||
unlock_user(target_data, arg2, target_datalen);
|
||||
} else {
|
||||
unlock_user(target_data, arg2, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TARGET_NR_sigaltstack:
|
||||
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
|
||||
defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
|
||||
@@ -8125,7 +8232,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
}
|
||||
mask = arg2;
|
||||
target_to_host_old_sigset(&set, &mask);
|
||||
sigprocmask(how, &set, &oldset);
|
||||
do_sigprocmask(how, &set, &oldset);
|
||||
host_to_target_old_sigset(&mask, &oldset);
|
||||
ret = mask;
|
||||
}
|
||||
@@ -9148,6 +9255,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
case TARGET_NR_atomic_barrier:
|
||||
{
|
||||
/* Like the kernel implementation and the qemu arm barrier, no-op this? */
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
@@ -2123,6 +2123,8 @@ struct target_statfs64 {
|
||||
#define TARGET_F_SETOWN 8 /* for sockets. */
|
||||
#define TARGET_F_GETOWN 9 /* for sockets. */
|
||||
#endif
|
||||
#define TARGET_F_SETOWN_EX 15
|
||||
#define TARGET_F_GETOWN_EX 16
|
||||
|
||||
#ifndef TARGET_F_RDLCK
|
||||
#define TARGET_F_RDLCK 0
|
||||
@@ -2305,6 +2307,11 @@ struct target_eabi_flock64 {
|
||||
} QEMU_PACKED;
|
||||
#endif
|
||||
|
||||
struct target_f_owner_ex {
|
||||
int type; /* Owner type of ID. */
|
||||
int pid; /* ID of owner. */
|
||||
};
|
||||
|
||||
/* soundcard defines */
|
||||
/* XXX: convert them all to arch indepedent entries */
|
||||
#define TARGET_SNDCTL_COPR_HALT TARGET_IOWR('C', 7, int);
|
||||
@@ -2559,3 +2566,14 @@ struct target_sigevent {
|
||||
} _sigev_thread;
|
||||
} _sigev_un;
|
||||
};
|
||||
|
||||
struct target_user_cap_header {
|
||||
uint32_t version;
|
||||
int pid;
|
||||
};
|
||||
|
||||
struct target_user_cap_data {
|
||||
uint32_t effective;
|
||||
uint32_t permitted;
|
||||
uint32_t inheritable;
|
||||
};
|
||||
|
@@ -101,6 +101,7 @@ void qemu_start_incoming_migration(const char *uri, Error **errp)
|
||||
static void process_incoming_migration_co(void *opaque)
|
||||
{
|
||||
QEMUFile *f = opaque;
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
|
||||
ret = qemu_loadvm_state(f);
|
||||
@@ -115,7 +116,12 @@ static void process_incoming_migration_co(void *opaque)
|
||||
|
||||
bdrv_clear_incoming_migration_all();
|
||||
/* Make sure all file formats flush their mutable metadata */
|
||||
bdrv_invalidate_cache_all();
|
||||
bdrv_invalidate_cache_all(&local_err);
|
||||
if (local_err) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (autostart) {
|
||||
vm_start();
|
||||
|
@@ -1087,7 +1087,7 @@ writev_help(void)
|
||||
" writes a range of bytes from the given offset source from multiple buffers\n"
|
||||
"\n"
|
||||
" Example:\n"
|
||||
" 'write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
|
||||
" 'writev 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
|
||||
"\n"
|
||||
" Writes into a segment of the currently open file, using a buffer\n"
|
||||
" filled with a set pattern (0xcdcdcdcd).\n"
|
||||
|
@@ -193,10 +193,11 @@ static const cmdinfo_t quit_cmd = {
|
||||
static void usage(const char *name)
|
||||
{
|
||||
printf(
|
||||
"Usage: %s [-h] [-V] [-rsnm] [-c cmd] ... [file]\n"
|
||||
"Usage: %s [-h] [-V] [-rsnm] [-c STRING] ... [file]\n"
|
||||
"QEMU Disk exerciser\n"
|
||||
"\n"
|
||||
" -c, --cmd command to execute\n"
|
||||
" -c, --cmd STRING execute command with its arguments\n"
|
||||
" from the given string\n"
|
||||
" -r, --read-only export read-only\n"
|
||||
" -s, --snapshot use snapshot file\n"
|
||||
" -n, --nocache disable host cache\n"
|
||||
@@ -207,8 +208,10 @@ static void usage(const char *name)
|
||||
" -T, --trace FILE enable trace events listed in the given file\n"
|
||||
" -h, --help display this help and exit\n"
|
||||
" -V, --version output version information and exit\n"
|
||||
"\n"
|
||||
"See '%s -c help' for information on available commands."
|
||||
"\n",
|
||||
name);
|
||||
name, name);
|
||||
}
|
||||
|
||||
static char *get_prompt(void)
|
||||
|
139
qom/object.c
139
qom/object.c
@@ -1023,10 +1023,23 @@ out:
|
||||
g_free(type);
|
||||
}
|
||||
|
||||
void object_property_allow_set_link(Object *obj, const char *name,
|
||||
Object *val, Error **errp)
|
||||
{
|
||||
/* Allow the link to be set, always */
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
Object **child;
|
||||
void (*check)(Object *, const char *, Object *, Error **);
|
||||
ObjectPropertyLinkFlags flags;
|
||||
} LinkProperty;
|
||||
|
||||
static void object_get_link_property(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
Object **child = opaque;
|
||||
LinkProperty *lprop = opaque;
|
||||
Object **child = lprop->child;
|
||||
gchar *path;
|
||||
|
||||
if (*child) {
|
||||
@@ -1039,65 +1052,119 @@ static void object_get_link_property(Object *obj, Visitor *v, void *opaque,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* object_resolve_link:
|
||||
*
|
||||
* Lookup an object and ensure its type matches the link property type. This
|
||||
* is similar to object_resolve_path() except type verification against the
|
||||
* link property is performed.
|
||||
*
|
||||
* Returns: The matched object or NULL on path lookup failures.
|
||||
*/
|
||||
static Object *object_resolve_link(Object *obj, const char *name,
|
||||
const char *path, Error **errp)
|
||||
{
|
||||
const char *type;
|
||||
gchar *target_type;
|
||||
bool ambiguous = false;
|
||||
Object *target;
|
||||
|
||||
/* Go from link<FOO> to FOO. */
|
||||
type = object_property_get_type(obj, name, NULL);
|
||||
target_type = g_strndup(&type[5], strlen(type) - 6);
|
||||
target = object_resolve_path_type(path, target_type, &ambiguous);
|
||||
|
||||
if (ambiguous) {
|
||||
error_set(errp, QERR_AMBIGUOUS_PATH, path);
|
||||
} else if (!target) {
|
||||
target = object_resolve_path(path, &ambiguous);
|
||||
if (target || ambiguous) {
|
||||
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type);
|
||||
} else {
|
||||
error_set(errp, QERR_DEVICE_NOT_FOUND, path);
|
||||
}
|
||||
target = NULL;
|
||||
}
|
||||
g_free(target_type);
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
Object **child = opaque;
|
||||
Object *old_target;
|
||||
bool ambiguous = false;
|
||||
const char *type;
|
||||
char *path;
|
||||
gchar *target_type;
|
||||
Error *local_err = NULL;
|
||||
LinkProperty *prop = opaque;
|
||||
Object **child = prop->child;
|
||||
Object *old_target = *child;
|
||||
Object *new_target = NULL;
|
||||
char *path = NULL;
|
||||
|
||||
type = object_property_get_type(obj, name, NULL);
|
||||
visit_type_str(v, &path, name, &local_err);
|
||||
|
||||
visit_type_str(v, &path, name, errp);
|
||||
|
||||
old_target = *child;
|
||||
*child = NULL;
|
||||
|
||||
if (strcmp(path, "") != 0) {
|
||||
Object *target;
|
||||
|
||||
/* Go from link<FOO> to FOO. */
|
||||
target_type = g_strndup(&type[5], strlen(type) - 6);
|
||||
target = object_resolve_path_type(path, target_type, &ambiguous);
|
||||
|
||||
if (ambiguous) {
|
||||
error_set(errp, QERR_AMBIGUOUS_PATH, path);
|
||||
} else if (target) {
|
||||
object_ref(target);
|
||||
*child = target;
|
||||
} else {
|
||||
target = object_resolve_path(path, &ambiguous);
|
||||
if (target || ambiguous) {
|
||||
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, target_type);
|
||||
} else {
|
||||
error_set(errp, QERR_DEVICE_NOT_FOUND, path);
|
||||
}
|
||||
}
|
||||
g_free(target_type);
|
||||
if (!local_err && strcmp(path, "") != 0) {
|
||||
new_target = object_resolve_link(obj, name, path, &local_err);
|
||||
}
|
||||
|
||||
g_free(path);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
prop->check(obj, name, new_target, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (new_target) {
|
||||
object_ref(new_target);
|
||||
}
|
||||
*child = new_target;
|
||||
if (old_target != NULL) {
|
||||
object_unref(old_target);
|
||||
}
|
||||
}
|
||||
|
||||
static void object_release_link_property(Object *obj, const char *name,
|
||||
void *opaque)
|
||||
{
|
||||
LinkProperty *prop = opaque;
|
||||
|
||||
if ((prop->flags & OBJ_PROP_LINK_UNREF_ON_RELEASE) && *prop->child) {
|
||||
object_unref(*prop->child);
|
||||
}
|
||||
g_free(prop);
|
||||
}
|
||||
|
||||
void object_property_add_link(Object *obj, const char *name,
|
||||
const char *type, Object **child,
|
||||
void (*check)(Object *, const char *,
|
||||
Object *, Error **),
|
||||
ObjectPropertyLinkFlags flags,
|
||||
Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
LinkProperty *prop = g_malloc(sizeof(*prop));
|
||||
gchar *full_type;
|
||||
|
||||
prop->child = child;
|
||||
prop->check = check;
|
||||
prop->flags = flags;
|
||||
|
||||
full_type = g_strdup_printf("link<%s>", type);
|
||||
|
||||
object_property_add(obj, name, full_type,
|
||||
object_get_link_property,
|
||||
object_set_link_property,
|
||||
NULL, child, errp);
|
||||
check ? object_set_link_property : NULL,
|
||||
object_release_link_property,
|
||||
prop,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
g_free(prop);
|
||||
}
|
||||
|
||||
g_free(full_type);
|
||||
}
|
||||
|
@@ -41,6 +41,9 @@ if [ $cpu != "arm" ] ; then
|
||||
echo ':arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-arm:' > /proc/sys/fs/binfmt_misc/register
|
||||
echo ':armeb:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-armeb:' > /proc/sys/fs/binfmt_misc/register
|
||||
fi
|
||||
if [ $cpu != "aarch64" ] ; then
|
||||
echo ':aarch64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-aarch64:' > /proc/sys/fs/binfmt_misc/register
|
||||
fi
|
||||
if [ $cpu != "sparc" ] ; then
|
||||
echo ':sparc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-sparc:' > /proc/sys/fs/binfmt_misc/register
|
||||
fi
|
||||
|
@@ -60,6 +60,11 @@ uint32_t HELPER(cls32)(uint32_t x)
|
||||
return clrsb32(x);
|
||||
}
|
||||
|
||||
uint32_t HELPER(clz32)(uint32_t x)
|
||||
{
|
||||
return clz32(x);
|
||||
}
|
||||
|
||||
uint64_t HELPER(rbit64)(uint64_t x)
|
||||
{
|
||||
/* assign the correct byte position */
|
||||
@@ -180,6 +185,36 @@ uint64_t HELPER(simd_tbl)(CPUARMState *env, uint64_t result, uint64_t indices,
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Helper function for 64 bit polynomial multiply case:
|
||||
* perform PolynomialMult(op1, op2) and return either the top or
|
||||
* bottom half of the 128 bit result.
|
||||
*/
|
||||
uint64_t HELPER(neon_pmull_64_lo)(uint64_t op1, uint64_t op2)
|
||||
{
|
||||
int bitnum;
|
||||
uint64_t res = 0;
|
||||
|
||||
for (bitnum = 0; bitnum < 64; bitnum++) {
|
||||
if (op1 & (1ULL << bitnum)) {
|
||||
res ^= op2 << bitnum;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
uint64_t HELPER(neon_pmull_64_hi)(uint64_t op1, uint64_t op2)
|
||||
{
|
||||
int bitnum;
|
||||
uint64_t res = 0;
|
||||
|
||||
/* bit 0 of op1 can't influence the high 64 bits at all */
|
||||
for (bitnum = 1; bitnum < 64; bitnum++) {
|
||||
if (op1 & (1ULL << bitnum)) {
|
||||
res ^= op2 >> (64 - bitnum);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* 64bit/double versions of the neon float compare functions */
|
||||
uint64_t HELPER(neon_ceq_f64)(float64 a, float64 b, void *fpstp)
|
||||
{
|
||||
@@ -258,3 +293,146 @@ float64 HELPER(rsqrtsf_f64)(float64 a, float64 b, void *fpstp)
|
||||
}
|
||||
return float64_muladd(a, b, float64_three, float_muladd_halve_result, fpst);
|
||||
}
|
||||
|
||||
/* Pairwise long add: add pairs of adjacent elements into
|
||||
* double-width elements in the result (eg _s8 is an 8x8->16 op)
|
||||
*/
|
||||
uint64_t HELPER(neon_addlp_s8)(uint64_t a)
|
||||
{
|
||||
uint64_t nsignmask = 0x0080008000800080ULL;
|
||||
uint64_t wsignmask = 0x8000800080008000ULL;
|
||||
uint64_t elementmask = 0x00ff00ff00ff00ffULL;
|
||||
uint64_t tmp1, tmp2;
|
||||
uint64_t res, signres;
|
||||
|
||||
/* Extract odd elements, sign extend each to a 16 bit field */
|
||||
tmp1 = a & elementmask;
|
||||
tmp1 ^= nsignmask;
|
||||
tmp1 |= wsignmask;
|
||||
tmp1 = (tmp1 - nsignmask) ^ wsignmask;
|
||||
/* Ditto for the even elements */
|
||||
tmp2 = (a >> 8) & elementmask;
|
||||
tmp2 ^= nsignmask;
|
||||
tmp2 |= wsignmask;
|
||||
tmp2 = (tmp2 - nsignmask) ^ wsignmask;
|
||||
|
||||
/* calculate the result by summing bits 0..14, 16..22, etc,
|
||||
* and then adjusting the sign bits 15, 23, etc manually.
|
||||
* This ensures the addition can't overflow the 16 bit field.
|
||||
*/
|
||||
signres = (tmp1 ^ tmp2) & wsignmask;
|
||||
res = (tmp1 & ~wsignmask) + (tmp2 & ~wsignmask);
|
||||
res ^= signres;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
uint64_t HELPER(neon_addlp_u8)(uint64_t a)
|
||||
{
|
||||
uint64_t tmp;
|
||||
|
||||
tmp = a & 0x00ff00ff00ff00ffULL;
|
||||
tmp += (a >> 8) & 0x00ff00ff00ff00ffULL;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
uint64_t HELPER(neon_addlp_s16)(uint64_t a)
|
||||
{
|
||||
int32_t reslo, reshi;
|
||||
|
||||
reslo = (int32_t)(int16_t)a + (int32_t)(int16_t)(a >> 16);
|
||||
reshi = (int32_t)(int16_t)(a >> 32) + (int32_t)(int16_t)(a >> 48);
|
||||
|
||||
return (uint32_t)reslo | (((uint64_t)reshi) << 32);
|
||||
}
|
||||
|
||||
uint64_t HELPER(neon_addlp_u16)(uint64_t a)
|
||||
{
|
||||
uint64_t tmp;
|
||||
|
||||
tmp = a & 0x0000ffff0000ffffULL;
|
||||
tmp += (a >> 16) & 0x0000ffff0000ffffULL;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/* Floating-point reciprocal exponent - see FPRecpX in ARM ARM */
|
||||
float32 HELPER(frecpx_f32)(float32 a, void *fpstp)
|
||||
{
|
||||
float_status *fpst = fpstp;
|
||||
uint32_t val32, sbit;
|
||||
int32_t exp;
|
||||
|
||||
if (float32_is_any_nan(a)) {
|
||||
float32 nan = a;
|
||||
if (float32_is_signaling_nan(a)) {
|
||||
float_raise(float_flag_invalid, fpst);
|
||||
nan = float32_maybe_silence_nan(a);
|
||||
}
|
||||
if (fpst->default_nan_mode) {
|
||||
nan = float32_default_nan;
|
||||
}
|
||||
return nan;
|
||||
}
|
||||
|
||||
val32 = float32_val(a);
|
||||
sbit = 0x80000000ULL & val32;
|
||||
exp = extract32(val32, 23, 8);
|
||||
|
||||
if (exp == 0) {
|
||||
return make_float32(sbit | (0xfe << 23));
|
||||
} else {
|
||||
return make_float32(sbit | (~exp & 0xff) << 23);
|
||||
}
|
||||
}
|
||||
|
||||
float64 HELPER(frecpx_f64)(float64 a, void *fpstp)
|
||||
{
|
||||
float_status *fpst = fpstp;
|
||||
uint64_t val64, sbit;
|
||||
int64_t exp;
|
||||
|
||||
if (float64_is_any_nan(a)) {
|
||||
float64 nan = a;
|
||||
if (float64_is_signaling_nan(a)) {
|
||||
float_raise(float_flag_invalid, fpst);
|
||||
nan = float64_maybe_silence_nan(a);
|
||||
}
|
||||
if (fpst->default_nan_mode) {
|
||||
nan = float64_default_nan;
|
||||
}
|
||||
return nan;
|
||||
}
|
||||
|
||||
val64 = float64_val(a);
|
||||
sbit = 0x8000000000000000ULL & val64;
|
||||
exp = extract64(float64_val(a), 52, 11);
|
||||
|
||||
if (exp == 0) {
|
||||
return make_float64(sbit | (0x7feULL << 52));
|
||||
} else {
|
||||
return make_float64(sbit | (~exp & 0x7ffULL) << 52);
|
||||
}
|
||||
}
|
||||
|
||||
float32 HELPER(fcvtx_f64_to_f32)(float64 a, CPUARMState *env)
|
||||
{
|
||||
/* Von Neumann rounding is implemented by using round-to-zero
|
||||
* and then setting the LSB of the result if Inexact was raised.
|
||||
*/
|
||||
float32 r;
|
||||
float_status *fpst = &env->vfp.fp_status;
|
||||
float_status tstat = *fpst;
|
||||
int exflags;
|
||||
|
||||
set_float_rounding_mode(float_round_to_zero, &tstat);
|
||||
set_float_exception_flags(0, &tstat);
|
||||
r = float64_to_float32(a, &tstat);
|
||||
r = float32_maybe_silence_nan(r);
|
||||
exflags = get_float_exception_flags(&tstat);
|
||||
if (exflags & float_flag_inexact) {
|
||||
r = make_float32(float32_val(r) | 1);
|
||||
}
|
||||
exflags |= get_float_exception_flags(fpst);
|
||||
set_float_exception_flags(exflags, fpst);
|
||||
return r;
|
||||
}
|
||||
|
@@ -21,12 +21,15 @@ DEF_HELPER_FLAGS_2(sdiv64, TCG_CALL_NO_RWG_SE, s64, s64, s64)
|
||||
DEF_HELPER_FLAGS_1(clz64, TCG_CALL_NO_RWG_SE, i64, i64)
|
||||
DEF_HELPER_FLAGS_1(cls64, TCG_CALL_NO_RWG_SE, i64, i64)
|
||||
DEF_HELPER_FLAGS_1(cls32, TCG_CALL_NO_RWG_SE, i32, i32)
|
||||
DEF_HELPER_FLAGS_1(clz32, TCG_CALL_NO_RWG_SE, i32, i32)
|
||||
DEF_HELPER_FLAGS_1(rbit64, TCG_CALL_NO_RWG_SE, i64, i64)
|
||||
DEF_HELPER_3(vfp_cmps_a64, i64, f32, f32, ptr)
|
||||
DEF_HELPER_3(vfp_cmpes_a64, i64, f32, f32, ptr)
|
||||
DEF_HELPER_3(vfp_cmpd_a64, i64, f64, f64, ptr)
|
||||
DEF_HELPER_3(vfp_cmped_a64, i64, f64, f64, ptr)
|
||||
DEF_HELPER_FLAGS_5(simd_tbl, TCG_CALL_NO_RWG_SE, i64, env, i64, i64, i32, i32)
|
||||
DEF_HELPER_FLAGS_2(neon_pmull_64_lo, TCG_CALL_NO_RWG_SE, i64, i64, i64)
|
||||
DEF_HELPER_FLAGS_2(neon_pmull_64_hi, TCG_CALL_NO_RWG_SE, i64, i64, i64)
|
||||
DEF_HELPER_FLAGS_3(vfp_mulxs, TCG_CALL_NO_RWG, f32, f32, f32, ptr)
|
||||
DEF_HELPER_FLAGS_3(vfp_mulxd, TCG_CALL_NO_RWG, f64, f64, f64, ptr)
|
||||
DEF_HELPER_FLAGS_3(neon_ceq_f64, TCG_CALL_NO_RWG, i64, i64, i64, ptr)
|
||||
@@ -36,3 +39,10 @@ DEF_HELPER_FLAGS_3(recpsf_f32, TCG_CALL_NO_RWG, f32, f32, f32, ptr)
|
||||
DEF_HELPER_FLAGS_3(recpsf_f64, TCG_CALL_NO_RWG, f64, f64, f64, ptr)
|
||||
DEF_HELPER_FLAGS_3(rsqrtsf_f32, TCG_CALL_NO_RWG, f32, f32, f32, ptr)
|
||||
DEF_HELPER_FLAGS_3(rsqrtsf_f64, TCG_CALL_NO_RWG, f64, f64, f64, ptr)
|
||||
DEF_HELPER_FLAGS_1(neon_addlp_s8, TCG_CALL_NO_RWG_SE, i64, i64)
|
||||
DEF_HELPER_FLAGS_1(neon_addlp_u8, TCG_CALL_NO_RWG_SE, i64, i64)
|
||||
DEF_HELPER_FLAGS_1(neon_addlp_s16, TCG_CALL_NO_RWG_SE, i64, i64)
|
||||
DEF_HELPER_FLAGS_1(neon_addlp_u16, TCG_CALL_NO_RWG_SE, i64, i64)
|
||||
DEF_HELPER_FLAGS_2(frecpx_f64, TCG_CALL_NO_RWG, f64, f64, ptr)
|
||||
DEF_HELPER_FLAGS_2(frecpx_f32, TCG_CALL_NO_RWG, f32, f32, ptr)
|
||||
DEF_HELPER_FLAGS_2(fcvtx_f64_to_f32, TCG_CALL_NO_RWG, f32, f64, env)
|
||||
|
@@ -1983,6 +1983,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||
ARMCPRegInfo pmcr = {
|
||||
.name = "PMCR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 0,
|
||||
.access = PL0_RW, .resetvalue = cpu->midr & 0xff000000,
|
||||
.type = ARM_CP_IO,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c9_pmcr),
|
||||
.accessfn = pmreg_access, .writefn = pmcr_write,
|
||||
.raw_writefn = raw_write,
|
||||
@@ -4519,16 +4520,21 @@ float32 HELPER(rsqrts_f32)(float32 a, float32 b, CPUARMState *env)
|
||||
* int->float conversions at run-time. */
|
||||
#define float64_256 make_float64(0x4070000000000000LL)
|
||||
#define float64_512 make_float64(0x4080000000000000LL)
|
||||
#define float32_maxnorm make_float32(0x7f7fffff)
|
||||
#define float64_maxnorm make_float64(0x7fefffffffffffffLL)
|
||||
|
||||
/* The algorithm that must be used to calculate the estimate
|
||||
* is specified by the ARM ARM.
|
||||
/* Reciprocal functions
|
||||
*
|
||||
* The algorithm that must be used to calculate the estimate
|
||||
* is specified by the ARM ARM, see FPRecipEstimate()
|
||||
*/
|
||||
static float64 recip_estimate(float64 a, CPUARMState *env)
|
||||
|
||||
static float64 recip_estimate(float64 a, float_status *real_fp_status)
|
||||
{
|
||||
/* These calculations mustn't set any fp exception flags,
|
||||
* so we use a local copy of the fp_status.
|
||||
*/
|
||||
float_status dummy_status = env->vfp.standard_fp_status;
|
||||
float_status dummy_status = *real_fp_status;
|
||||
float_status *s = &dummy_status;
|
||||
/* q = (int)(a * 512.0) */
|
||||
float64 q = float64_mul(float64_512, a, s);
|
||||
@@ -4549,56 +4555,178 @@ static float64 recip_estimate(float64 a, CPUARMState *env)
|
||||
return float64_div(int64_to_float64(q_int, s), float64_256, s);
|
||||
}
|
||||
|
||||
float32 HELPER(recpe_f32)(float32 a, CPUARMState *env)
|
||||
/* Common wrapper to call recip_estimate */
|
||||
static float64 call_recip_estimate(float64 num, int off, float_status *fpst)
|
||||
{
|
||||
float_status *s = &env->vfp.standard_fp_status;
|
||||
float64 f64;
|
||||
uint32_t val32 = float32_val(a);
|
||||
uint64_t val64 = float64_val(num);
|
||||
uint64_t frac = extract64(val64, 0, 52);
|
||||
int64_t exp = extract64(val64, 52, 11);
|
||||
uint64_t sbit;
|
||||
float64 scaled, estimate;
|
||||
|
||||
int result_exp;
|
||||
int a_exp = (val32 & 0x7f800000) >> 23;
|
||||
int sign = val32 & 0x80000000;
|
||||
|
||||
if (float32_is_any_nan(a)) {
|
||||
if (float32_is_signaling_nan(a)) {
|
||||
float_raise(float_flag_invalid, s);
|
||||
/* Generate the scaled number for the estimate function */
|
||||
if (exp == 0) {
|
||||
if (extract64(frac, 51, 1) == 0) {
|
||||
exp = -1;
|
||||
frac = extract64(frac, 0, 50) << 2;
|
||||
} else {
|
||||
frac = extract64(frac, 0, 51) << 1;
|
||||
}
|
||||
return float32_default_nan;
|
||||
} else if (float32_is_infinity(a)) {
|
||||
return float32_set_sign(float32_zero, float32_is_neg(a));
|
||||
} else if (float32_is_zero_or_denormal(a)) {
|
||||
if (!float32_is_zero(a)) {
|
||||
float_raise(float_flag_input_denormal, s);
|
||||
}
|
||||
float_raise(float_flag_divbyzero, s);
|
||||
return float32_set_sign(float32_infinity, float32_is_neg(a));
|
||||
} else if (a_exp >= 253) {
|
||||
float_raise(float_flag_underflow, s);
|
||||
return float32_set_sign(float32_zero, float32_is_neg(a));
|
||||
}
|
||||
|
||||
f64 = make_float64((0x3feULL << 52)
|
||||
| ((int64_t)(val32 & 0x7fffff) << 29));
|
||||
/* scaled = '0' : '01111111110' : fraction<51:44> : Zeros(44); */
|
||||
scaled = make_float64((0x3feULL << 52)
|
||||
| extract64(frac, 44, 8) << 44);
|
||||
|
||||
result_exp = 253 - a_exp;
|
||||
estimate = recip_estimate(scaled, fpst);
|
||||
|
||||
f64 = recip_estimate(f64, env);
|
||||
/* Build new result */
|
||||
val64 = float64_val(estimate);
|
||||
sbit = 0x8000000000000000ULL & val64;
|
||||
exp = off - exp;
|
||||
frac = extract64(val64, 0, 52);
|
||||
|
||||
val32 = sign
|
||||
| ((result_exp & 0xff) << 23)
|
||||
| ((float64_val(f64) >> 29) & 0x7fffff);
|
||||
return make_float32(val32);
|
||||
if (exp == 0) {
|
||||
frac = 1ULL << 51 | extract64(frac, 1, 51);
|
||||
} else if (exp == -1) {
|
||||
frac = 1ULL << 50 | extract64(frac, 2, 50);
|
||||
exp = 0;
|
||||
}
|
||||
|
||||
return make_float64(sbit | (exp << 52) | frac);
|
||||
}
|
||||
|
||||
static bool round_to_inf(float_status *fpst, bool sign_bit)
|
||||
{
|
||||
switch (fpst->float_rounding_mode) {
|
||||
case float_round_nearest_even: /* Round to Nearest */
|
||||
return true;
|
||||
case float_round_up: /* Round to +Inf */
|
||||
return !sign_bit;
|
||||
case float_round_down: /* Round to -Inf */
|
||||
return sign_bit;
|
||||
case float_round_to_zero: /* Round to Zero */
|
||||
return false;
|
||||
}
|
||||
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
float32 HELPER(recpe_f32)(float32 input, void *fpstp)
|
||||
{
|
||||
float_status *fpst = fpstp;
|
||||
float32 f32 = float32_squash_input_denormal(input, fpst);
|
||||
uint32_t f32_val = float32_val(f32);
|
||||
uint32_t f32_sbit = 0x80000000ULL & f32_val;
|
||||
int32_t f32_exp = extract32(f32_val, 23, 8);
|
||||
uint32_t f32_frac = extract32(f32_val, 0, 23);
|
||||
float64 f64, r64;
|
||||
uint64_t r64_val;
|
||||
int64_t r64_exp;
|
||||
uint64_t r64_frac;
|
||||
|
||||
if (float32_is_any_nan(f32)) {
|
||||
float32 nan = f32;
|
||||
if (float32_is_signaling_nan(f32)) {
|
||||
float_raise(float_flag_invalid, fpst);
|
||||
nan = float32_maybe_silence_nan(f32);
|
||||
}
|
||||
if (fpst->default_nan_mode) {
|
||||
nan = float32_default_nan;
|
||||
}
|
||||
return nan;
|
||||
} else if (float32_is_infinity(f32)) {
|
||||
return float32_set_sign(float32_zero, float32_is_neg(f32));
|
||||
} else if (float32_is_zero(f32)) {
|
||||
float_raise(float_flag_divbyzero, fpst);
|
||||
return float32_set_sign(float32_infinity, float32_is_neg(f32));
|
||||
} else if ((f32_val & ~(1ULL << 31)) < (1ULL << 21)) {
|
||||
/* Abs(value) < 2.0^-128 */
|
||||
float_raise(float_flag_overflow | float_flag_inexact, fpst);
|
||||
if (round_to_inf(fpst, f32_sbit)) {
|
||||
return float32_set_sign(float32_infinity, float32_is_neg(f32));
|
||||
} else {
|
||||
return float32_set_sign(float32_maxnorm, float32_is_neg(f32));
|
||||
}
|
||||
} else if (f32_exp >= 253 && fpst->flush_to_zero) {
|
||||
float_raise(float_flag_underflow, fpst);
|
||||
return float32_set_sign(float32_zero, float32_is_neg(f32));
|
||||
}
|
||||
|
||||
|
||||
f64 = make_float64(((int64_t)(f32_exp) << 52) | (int64_t)(f32_frac) << 29);
|
||||
r64 = call_recip_estimate(f64, 253, fpst);
|
||||
r64_val = float64_val(r64);
|
||||
r64_exp = extract64(r64_val, 52, 11);
|
||||
r64_frac = extract64(r64_val, 0, 52);
|
||||
|
||||
/* result = sign : result_exp<7:0> : fraction<51:29>; */
|
||||
return make_float32(f32_sbit |
|
||||
(r64_exp & 0xff) << 23 |
|
||||
extract64(r64_frac, 29, 24));
|
||||
}
|
||||
|
||||
float64 HELPER(recpe_f64)(float64 input, void *fpstp)
|
||||
{
|
||||
float_status *fpst = fpstp;
|
||||
float64 f64 = float64_squash_input_denormal(input, fpst);
|
||||
uint64_t f64_val = float64_val(f64);
|
||||
uint64_t f64_sbit = 0x8000000000000000ULL & f64_val;
|
||||
int64_t f64_exp = extract64(f64_val, 52, 11);
|
||||
float64 r64;
|
||||
uint64_t r64_val;
|
||||
int64_t r64_exp;
|
||||
uint64_t r64_frac;
|
||||
|
||||
/* Deal with any special cases */
|
||||
if (float64_is_any_nan(f64)) {
|
||||
float64 nan = f64;
|
||||
if (float64_is_signaling_nan(f64)) {
|
||||
float_raise(float_flag_invalid, fpst);
|
||||
nan = float64_maybe_silence_nan(f64);
|
||||
}
|
||||
if (fpst->default_nan_mode) {
|
||||
nan = float64_default_nan;
|
||||
}
|
||||
return nan;
|
||||
} else if (float64_is_infinity(f64)) {
|
||||
return float64_set_sign(float64_zero, float64_is_neg(f64));
|
||||
} else if (float64_is_zero(f64)) {
|
||||
float_raise(float_flag_divbyzero, fpst);
|
||||
return float64_set_sign(float64_infinity, float64_is_neg(f64));
|
||||
} else if ((f64_val & ~(1ULL << 63)) < (1ULL << 50)) {
|
||||
/* Abs(value) < 2.0^-1024 */
|
||||
float_raise(float_flag_overflow | float_flag_inexact, fpst);
|
||||
if (round_to_inf(fpst, f64_sbit)) {
|
||||
return float64_set_sign(float64_infinity, float64_is_neg(f64));
|
||||
} else {
|
||||
return float64_set_sign(float64_maxnorm, float64_is_neg(f64));
|
||||
}
|
||||
} else if (f64_exp >= 1023 && fpst->flush_to_zero) {
|
||||
float_raise(float_flag_underflow, fpst);
|
||||
return float64_set_sign(float64_zero, float64_is_neg(f64));
|
||||
}
|
||||
|
||||
r64 = call_recip_estimate(f64, 2045, fpst);
|
||||
r64_val = float64_val(r64);
|
||||
r64_exp = extract64(r64_val, 52, 11);
|
||||
r64_frac = extract64(r64_val, 0, 52);
|
||||
|
||||
/* result = sign : result_exp<10:0> : fraction<51:0> */
|
||||
return make_float64(f64_sbit |
|
||||
((r64_exp & 0x7ff) << 52) |
|
||||
r64_frac);
|
||||
}
|
||||
|
||||
/* The algorithm that must be used to calculate the estimate
|
||||
* is specified by the ARM ARM.
|
||||
*/
|
||||
static float64 recip_sqrt_estimate(float64 a, CPUARMState *env)
|
||||
static float64 recip_sqrt_estimate(float64 a, float_status *real_fp_status)
|
||||
{
|
||||
/* These calculations mustn't set any fp exception flags,
|
||||
* so we use a local copy of the fp_status.
|
||||
*/
|
||||
float_status dummy_status = env->vfp.standard_fp_status;
|
||||
float_status dummy_status = *real_fp_status;
|
||||
float_status *s = &dummy_status;
|
||||
float64 q;
|
||||
int64_t q_int;
|
||||
@@ -4645,49 +4773,64 @@ static float64 recip_sqrt_estimate(float64 a, CPUARMState *env)
|
||||
return float64_div(int64_to_float64(q_int, s), float64_256, s);
|
||||
}
|
||||
|
||||
float32 HELPER(rsqrte_f32)(float32 a, CPUARMState *env)
|
||||
float32 HELPER(rsqrte_f32)(float32 input, void *fpstp)
|
||||
{
|
||||
float_status *s = &env->vfp.standard_fp_status;
|
||||
float_status *s = fpstp;
|
||||
float32 f32 = float32_squash_input_denormal(input, s);
|
||||
uint32_t val = float32_val(f32);
|
||||
uint32_t f32_sbit = 0x80000000 & val;
|
||||
int32_t f32_exp = extract32(val, 23, 8);
|
||||
uint32_t f32_frac = extract32(val, 0, 23);
|
||||
uint64_t f64_frac;
|
||||
uint64_t val64;
|
||||
int result_exp;
|
||||
float64 f64;
|
||||
uint32_t val;
|
||||
uint64_t val64;
|
||||
|
||||
val = float32_val(a);
|
||||
|
||||
if (float32_is_any_nan(a)) {
|
||||
if (float32_is_signaling_nan(a)) {
|
||||
if (float32_is_any_nan(f32)) {
|
||||
float32 nan = f32;
|
||||
if (float32_is_signaling_nan(f32)) {
|
||||
float_raise(float_flag_invalid, s);
|
||||
nan = float32_maybe_silence_nan(f32);
|
||||
}
|
||||
return float32_default_nan;
|
||||
} else if (float32_is_zero_or_denormal(a)) {
|
||||
if (!float32_is_zero(a)) {
|
||||
float_raise(float_flag_input_denormal, s);
|
||||
if (s->default_nan_mode) {
|
||||
nan = float32_default_nan;
|
||||
}
|
||||
return nan;
|
||||
} else if (float32_is_zero(f32)) {
|
||||
float_raise(float_flag_divbyzero, s);
|
||||
return float32_set_sign(float32_infinity, float32_is_neg(a));
|
||||
} else if (float32_is_neg(a)) {
|
||||
return float32_set_sign(float32_infinity, float32_is_neg(f32));
|
||||
} else if (float32_is_neg(f32)) {
|
||||
float_raise(float_flag_invalid, s);
|
||||
return float32_default_nan;
|
||||
} else if (float32_is_infinity(a)) {
|
||||
} else if (float32_is_infinity(f32)) {
|
||||
return float32_zero;
|
||||
}
|
||||
|
||||
/* Normalize to a double-precision value between 0.25 and 1.0,
|
||||
/* Scale and normalize to a double-precision value between 0.25 and 1.0,
|
||||
* preserving the parity of the exponent. */
|
||||
if ((val & 0x800000) == 0) {
|
||||
f64 = make_float64(((uint64_t)(val & 0x80000000) << 32)
|
||||
| (0x3feULL << 52)
|
||||
| ((uint64_t)(val & 0x7fffff) << 29));
|
||||
} else {
|
||||
f64 = make_float64(((uint64_t)(val & 0x80000000) << 32)
|
||||
| (0x3fdULL << 52)
|
||||
| ((uint64_t)(val & 0x7fffff) << 29));
|
||||
|
||||
f64_frac = ((uint64_t) f32_frac) << 29;
|
||||
if (f32_exp == 0) {
|
||||
while (extract64(f64_frac, 51, 1) == 0) {
|
||||
f64_frac = f64_frac << 1;
|
||||
f32_exp = f32_exp-1;
|
||||
}
|
||||
f64_frac = extract64(f64_frac, 0, 51) << 1;
|
||||
}
|
||||
|
||||
result_exp = (380 - ((val & 0x7f800000) >> 23)) / 2;
|
||||
if (extract64(f32_exp, 0, 1) == 0) {
|
||||
f64 = make_float64(((uint64_t) f32_sbit) << 32
|
||||
| (0x3feULL << 52)
|
||||
| f64_frac);
|
||||
} else {
|
||||
f64 = make_float64(((uint64_t) f32_sbit) << 32
|
||||
| (0x3fdULL << 52)
|
||||
| f64_frac);
|
||||
}
|
||||
|
||||
f64 = recip_sqrt_estimate(f64, env);
|
||||
result_exp = (380 - f32_exp) / 2;
|
||||
|
||||
f64 = recip_sqrt_estimate(f64, s);
|
||||
|
||||
val64 = float64_val(f64);
|
||||
|
||||
@@ -4696,8 +4839,72 @@ float32 HELPER(rsqrte_f32)(float32 a, CPUARMState *env)
|
||||
return make_float32(val);
|
||||
}
|
||||
|
||||
uint32_t HELPER(recpe_u32)(uint32_t a, CPUARMState *env)
|
||||
float64 HELPER(rsqrte_f64)(float64 input, void *fpstp)
|
||||
{
|
||||
float_status *s = fpstp;
|
||||
float64 f64 = float64_squash_input_denormal(input, s);
|
||||
uint64_t val = float64_val(f64);
|
||||
uint64_t f64_sbit = 0x8000000000000000ULL & val;
|
||||
int64_t f64_exp = extract64(val, 52, 11);
|
||||
uint64_t f64_frac = extract64(val, 0, 52);
|
||||
int64_t result_exp;
|
||||
uint64_t result_frac;
|
||||
|
||||
if (float64_is_any_nan(f64)) {
|
||||
float64 nan = f64;
|
||||
if (float64_is_signaling_nan(f64)) {
|
||||
float_raise(float_flag_invalid, s);
|
||||
nan = float64_maybe_silence_nan(f64);
|
||||
}
|
||||
if (s->default_nan_mode) {
|
||||
nan = float64_default_nan;
|
||||
}
|
||||
return nan;
|
||||
} else if (float64_is_zero(f64)) {
|
||||
float_raise(float_flag_divbyzero, s);
|
||||
return float64_set_sign(float64_infinity, float64_is_neg(f64));
|
||||
} else if (float64_is_neg(f64)) {
|
||||
float_raise(float_flag_invalid, s);
|
||||
return float64_default_nan;
|
||||
} else if (float64_is_infinity(f64)) {
|
||||
return float64_zero;
|
||||
}
|
||||
|
||||
/* Scale and normalize to a double-precision value between 0.25 and 1.0,
|
||||
* preserving the parity of the exponent. */
|
||||
|
||||
if (f64_exp == 0) {
|
||||
while (extract64(f64_frac, 51, 1) == 0) {
|
||||
f64_frac = f64_frac << 1;
|
||||
f64_exp = f64_exp - 1;
|
||||
}
|
||||
f64_frac = extract64(f64_frac, 0, 51) << 1;
|
||||
}
|
||||
|
||||
if (extract64(f64_exp, 0, 1) == 0) {
|
||||
f64 = make_float64(f64_sbit
|
||||
| (0x3feULL << 52)
|
||||
| f64_frac);
|
||||
} else {
|
||||
f64 = make_float64(f64_sbit
|
||||
| (0x3fdULL << 52)
|
||||
| f64_frac);
|
||||
}
|
||||
|
||||
result_exp = (3068 - f64_exp) / 2;
|
||||
|
||||
f64 = recip_sqrt_estimate(f64, s);
|
||||
|
||||
result_frac = extract64(float64_val(f64), 0, 52);
|
||||
|
||||
return make_float64(f64_sbit |
|
||||
((result_exp & 0x7ff) << 52) |
|
||||
result_frac);
|
||||
}
|
||||
|
||||
uint32_t HELPER(recpe_u32)(uint32_t a, void *fpstp)
|
||||
{
|
||||
float_status *s = fpstp;
|
||||
float64 f64;
|
||||
|
||||
if ((a & 0x80000000) == 0) {
|
||||
@@ -4707,13 +4914,14 @@ uint32_t HELPER(recpe_u32)(uint32_t a, CPUARMState *env)
|
||||
f64 = make_float64((0x3feULL << 52)
|
||||
| ((int64_t)(a & 0x7fffffff) << 21));
|
||||
|
||||
f64 = recip_estimate (f64, env);
|
||||
f64 = recip_estimate(f64, s);
|
||||
|
||||
return 0x80000000 | ((float64_val(f64) >> 21) & 0x7fffffff);
|
||||
}
|
||||
|
||||
uint32_t HELPER(rsqrte_u32)(uint32_t a, CPUARMState *env)
|
||||
uint32_t HELPER(rsqrte_u32)(uint32_t a, void *fpstp)
|
||||
{
|
||||
float_status *fpst = fpstp;
|
||||
float64 f64;
|
||||
|
||||
if ((a & 0xc0000000) == 0) {
|
||||
@@ -4728,7 +4936,7 @@ uint32_t HELPER(rsqrte_u32)(uint32_t a, CPUARMState *env)
|
||||
| ((uint64_t)(a & 0x3fffffff) << 22));
|
||||
}
|
||||
|
||||
f64 = recip_sqrt_estimate(f64, env);
|
||||
f64 = recip_sqrt_estimate(f64, fpst);
|
||||
|
||||
return 0x80000000 | ((float64_val(f64) >> 21) & 0x7fffffff);
|
||||
}
|
||||
|
@@ -167,10 +167,12 @@ DEF_HELPER_4(vfp_muladds, f32, f32, f32, f32, ptr)
|
||||
|
||||
DEF_HELPER_3(recps_f32, f32, f32, f32, env)
|
||||
DEF_HELPER_3(rsqrts_f32, f32, f32, f32, env)
|
||||
DEF_HELPER_2(recpe_f32, f32, f32, env)
|
||||
DEF_HELPER_2(rsqrte_f32, f32, f32, env)
|
||||
DEF_HELPER_2(recpe_u32, i32, i32, env)
|
||||
DEF_HELPER_2(rsqrte_u32, i32, i32, env)
|
||||
DEF_HELPER_FLAGS_2(recpe_f32, TCG_CALL_NO_RWG, f32, f32, ptr)
|
||||
DEF_HELPER_FLAGS_2(recpe_f64, TCG_CALL_NO_RWG, f64, f64, ptr)
|
||||
DEF_HELPER_FLAGS_2(rsqrte_f32, TCG_CALL_NO_RWG, f32, f32, ptr)
|
||||
DEF_HELPER_FLAGS_2(rsqrte_f64, TCG_CALL_NO_RWG, f64, f64, ptr)
|
||||
DEF_HELPER_2(recpe_u32, i32, i32, ptr)
|
||||
DEF_HELPER_FLAGS_2(rsqrte_u32, TCG_CALL_NO_RWG, i32, i32, ptr)
|
||||
DEF_HELPER_5(neon_tbl, i32, env, i32, i32, i32, i32)
|
||||
|
||||
DEF_HELPER_3(shl_cc, i32, env, i32, i32)
|
||||
@@ -184,12 +186,20 @@ DEF_HELPER_FLAGS_2(rints, TCG_CALL_NO_RWG, f32, f32, ptr)
|
||||
DEF_HELPER_FLAGS_2(rintd, TCG_CALL_NO_RWG, f64, f64, ptr)
|
||||
|
||||
/* neon_helper.c */
|
||||
DEF_HELPER_3(neon_qadd_u8, i32, env, i32, i32)
|
||||
DEF_HELPER_3(neon_qadd_s8, i32, env, i32, i32)
|
||||
DEF_HELPER_3(neon_qadd_u16, i32, env, i32, i32)
|
||||
DEF_HELPER_3(neon_qadd_s16, i32, env, i32, i32)
|
||||
DEF_HELPER_3(neon_qadd_u32, i32, env, i32, i32)
|
||||
DEF_HELPER_3(neon_qadd_s32, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(neon_qadd_u8, TCG_CALL_NO_RWG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(neon_qadd_s8, TCG_CALL_NO_RWG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(neon_qadd_u16, TCG_CALL_NO_RWG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(neon_qadd_s16, TCG_CALL_NO_RWG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(neon_qadd_u32, TCG_CALL_NO_RWG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(neon_qadd_s32, TCG_CALL_NO_RWG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(neon_uqadd_s8, TCG_CALL_NO_RWG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(neon_uqadd_s16, TCG_CALL_NO_RWG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(neon_uqadd_s32, TCG_CALL_NO_RWG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(neon_uqadd_s64, TCG_CALL_NO_RWG, i64, env, i64, i64)
|
||||
DEF_HELPER_FLAGS_3(neon_sqadd_u8, TCG_CALL_NO_RWG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(neon_sqadd_u16, TCG_CALL_NO_RWG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(neon_sqadd_u32, TCG_CALL_NO_RWG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(neon_sqadd_u64, TCG_CALL_NO_RWG, i64, env, i64, i64)
|
||||
DEF_HELPER_3(neon_qsub_u8, i32, env, i32, i32)
|
||||
DEF_HELPER_3(neon_qsub_s8, i32, env, i32, i32)
|
||||
DEF_HELPER_3(neon_qsub_u16, i32, env, i32, i32)
|
||||
@@ -373,12 +383,14 @@ DEF_HELPER_2(neon_mull_s16, i64, i32, i32)
|
||||
DEF_HELPER_1(neon_negl_u16, i64, i64)
|
||||
DEF_HELPER_1(neon_negl_u32, i64, i64)
|
||||
|
||||
DEF_HELPER_2(neon_qabs_s8, i32, env, i32)
|
||||
DEF_HELPER_2(neon_qabs_s16, i32, env, i32)
|
||||
DEF_HELPER_2(neon_qabs_s32, i32, env, i32)
|
||||
DEF_HELPER_2(neon_qneg_s8, i32, env, i32)
|
||||
DEF_HELPER_2(neon_qneg_s16, i32, env, i32)
|
||||
DEF_HELPER_2(neon_qneg_s32, i32, env, i32)
|
||||
DEF_HELPER_FLAGS_2(neon_qabs_s8, TCG_CALL_NO_RWG, i32, env, i32)
|
||||
DEF_HELPER_FLAGS_2(neon_qabs_s16, TCG_CALL_NO_RWG, i32, env, i32)
|
||||
DEF_HELPER_FLAGS_2(neon_qabs_s32, TCG_CALL_NO_RWG, i32, env, i32)
|
||||
DEF_HELPER_FLAGS_2(neon_qabs_s64, TCG_CALL_NO_RWG, i64, env, i64)
|
||||
DEF_HELPER_FLAGS_2(neon_qneg_s8, TCG_CALL_NO_RWG, i32, env, i32)
|
||||
DEF_HELPER_FLAGS_2(neon_qneg_s16, TCG_CALL_NO_RWG, i32, env, i32)
|
||||
DEF_HELPER_FLAGS_2(neon_qneg_s32, TCG_CALL_NO_RWG, i32, env, i32)
|
||||
DEF_HELPER_FLAGS_2(neon_qneg_s64, TCG_CALL_NO_RWG, i64, env, i64)
|
||||
|
||||
DEF_HELPER_3(neon_abd_f32, i32, i32, i32, ptr)
|
||||
DEF_HELPER_3(neon_ceq_f32, i32, i32, i32, ptr)
|
||||
|
@@ -236,6 +236,171 @@ uint64_t HELPER(neon_qadd_s64)(CPUARMState *env, uint64_t src1, uint64_t src2)
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Unsigned saturating accumulate of signed value
|
||||
*
|
||||
* Op1/Rn is treated as signed
|
||||
* Op2/Rd is treated as unsigned
|
||||
*
|
||||
* Explicit casting is used to ensure the correct sign extension of
|
||||
* inputs. The result is treated as a unsigned value and saturated as such.
|
||||
*
|
||||
* We use a macro for the 8/16 bit cases which expects signed integers of va,
|
||||
* vb, and vr for interim calculation and an unsigned 32 bit result value r.
|
||||
*/
|
||||
|
||||
#define USATACC(bits, shift) \
|
||||
do { \
|
||||
va = sextract32(a, shift, bits); \
|
||||
vb = extract32(b, shift, bits); \
|
||||
vr = va + vb; \
|
||||
if (vr > UINT##bits##_MAX) { \
|
||||
SET_QC(); \
|
||||
vr = UINT##bits##_MAX; \
|
||||
} else if (vr < 0) { \
|
||||
SET_QC(); \
|
||||
vr = 0; \
|
||||
} \
|
||||
r = deposit32(r, shift, bits, vr); \
|
||||
} while (0)
|
||||
|
||||
uint32_t HELPER(neon_uqadd_s8)(CPUARMState *env, uint32_t a, uint32_t b)
|
||||
{
|
||||
int16_t va, vb, vr;
|
||||
uint32_t r = 0;
|
||||
|
||||
USATACC(8, 0);
|
||||
USATACC(8, 8);
|
||||
USATACC(8, 16);
|
||||
USATACC(8, 24);
|
||||
return r;
|
||||
}
|
||||
|
||||
uint32_t HELPER(neon_uqadd_s16)(CPUARMState *env, uint32_t a, uint32_t b)
|
||||
{
|
||||
int32_t va, vb, vr;
|
||||
uint64_t r = 0;
|
||||
|
||||
USATACC(16, 0);
|
||||
USATACC(16, 16);
|
||||
return r;
|
||||
}
|
||||
|
||||
#undef USATACC
|
||||
|
||||
uint32_t HELPER(neon_uqadd_s32)(CPUARMState *env, uint32_t a, uint32_t b)
|
||||
{
|
||||
int64_t va = (int32_t)a;
|
||||
int64_t vb = (uint32_t)b;
|
||||
int64_t vr = va + vb;
|
||||
if (vr > UINT32_MAX) {
|
||||
SET_QC();
|
||||
vr = UINT32_MAX;
|
||||
} else if (vr < 0) {
|
||||
SET_QC();
|
||||
vr = 0;
|
||||
}
|
||||
return vr;
|
||||
}
|
||||
|
||||
uint64_t HELPER(neon_uqadd_s64)(CPUARMState *env, uint64_t a, uint64_t b)
|
||||
{
|
||||
uint64_t res;
|
||||
res = a + b;
|
||||
/* We only need to look at the pattern of SIGN bits to detect
|
||||
* +ve/-ve saturation
|
||||
*/
|
||||
if (~a & b & ~res & SIGNBIT64) {
|
||||
SET_QC();
|
||||
res = UINT64_MAX;
|
||||
} else if (a & ~b & res & SIGNBIT64) {
|
||||
SET_QC();
|
||||
res = 0;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Signed saturating accumulate of unsigned value
|
||||
*
|
||||
* Op1/Rn is treated as unsigned
|
||||
* Op2/Rd is treated as signed
|
||||
*
|
||||
* The result is treated as a signed value and saturated as such
|
||||
*
|
||||
* We use a macro for the 8/16 bit cases which expects signed integers of va,
|
||||
* vb, and vr for interim calculation and an unsigned 32 bit result value r.
|
||||
*/
|
||||
|
||||
#define SSATACC(bits, shift) \
|
||||
do { \
|
||||
va = extract32(a, shift, bits); \
|
||||
vb = sextract32(b, shift, bits); \
|
||||
vr = va + vb; \
|
||||
if (vr > INT##bits##_MAX) { \
|
||||
SET_QC(); \
|
||||
vr = INT##bits##_MAX; \
|
||||
} else if (vr < INT##bits##_MIN) { \
|
||||
SET_QC(); \
|
||||
vr = INT##bits##_MIN; \
|
||||
} \
|
||||
r = deposit32(r, shift, bits, vr); \
|
||||
} while (0)
|
||||
|
||||
uint32_t HELPER(neon_sqadd_u8)(CPUARMState *env, uint32_t a, uint32_t b)
|
||||
{
|
||||
int16_t va, vb, vr;
|
||||
uint32_t r = 0;
|
||||
|
||||
SSATACC(8, 0);
|
||||
SSATACC(8, 8);
|
||||
SSATACC(8, 16);
|
||||
SSATACC(8, 24);
|
||||
return r;
|
||||
}
|
||||
|
||||
uint32_t HELPER(neon_sqadd_u16)(CPUARMState *env, uint32_t a, uint32_t b)
|
||||
{
|
||||
int32_t va, vb, vr;
|
||||
uint32_t r = 0;
|
||||
|
||||
SSATACC(16, 0);
|
||||
SSATACC(16, 16);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#undef SSATACC
|
||||
|
||||
uint32_t HELPER(neon_sqadd_u32)(CPUARMState *env, uint32_t a, uint32_t b)
|
||||
{
|
||||
int64_t res;
|
||||
int64_t op1 = (uint32_t)a;
|
||||
int64_t op2 = (int32_t)b;
|
||||
res = op1 + op2;
|
||||
if (res > INT32_MAX) {
|
||||
SET_QC();
|
||||
res = INT32_MAX;
|
||||
} else if (res < INT32_MIN) {
|
||||
SET_QC();
|
||||
res = INT32_MIN;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
uint64_t HELPER(neon_sqadd_u64)(CPUARMState *env, uint64_t a, uint64_t b)
|
||||
{
|
||||
uint64_t res;
|
||||
res = a + b;
|
||||
/* We only need to look at the pattern of SIGN bits to detect an overflow */
|
||||
if (((a & res)
|
||||
| (~b & res)
|
||||
| (a & ~b)) & SIGNBIT64) {
|
||||
SET_QC();
|
||||
res = INT64_MAX;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
#define NEON_USAT(dest, src1, src2, type) do { \
|
||||
uint32_t tmp = (uint32_t)src1 - (uint32_t)src2; \
|
||||
if (tmp != (type)tmp) { \
|
||||
@@ -1776,6 +1941,28 @@ uint32_t HELPER(neon_qneg_s32)(CPUARMState *env, uint32_t x)
|
||||
return x;
|
||||
}
|
||||
|
||||
uint64_t HELPER(neon_qabs_s64)(CPUARMState *env, uint64_t x)
|
||||
{
|
||||
if (x == SIGNBIT64) {
|
||||
SET_QC();
|
||||
x = ~SIGNBIT64;
|
||||
} else if ((int64_t)x < 0) {
|
||||
x = -x;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
uint64_t HELPER(neon_qneg_s64)(CPUARMState *env, uint64_t x)
|
||||
{
|
||||
if (x == SIGNBIT64) {
|
||||
SET_QC();
|
||||
x = ~SIGNBIT64;
|
||||
} else {
|
||||
x = -x;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/* NEON Float helpers. */
|
||||
uint32_t HELPER(neon_abd_f32)(uint32_t a, uint32_t b, void *fpstp)
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -6682,17 +6682,33 @@ static int disas_neon_data_insn(CPUARMState * env, DisasContext *s, uint32_t ins
|
||||
break;
|
||||
}
|
||||
case NEON_2RM_VRECPE:
|
||||
gen_helper_recpe_u32(tmp, tmp, cpu_env);
|
||||
{
|
||||
TCGv_ptr fpstatus = get_fpstatus_ptr(1);
|
||||
gen_helper_recpe_u32(tmp, tmp, fpstatus);
|
||||
tcg_temp_free_ptr(fpstatus);
|
||||
break;
|
||||
}
|
||||
case NEON_2RM_VRSQRTE:
|
||||
gen_helper_rsqrte_u32(tmp, tmp, cpu_env);
|
||||
{
|
||||
TCGv_ptr fpstatus = get_fpstatus_ptr(1);
|
||||
gen_helper_rsqrte_u32(tmp, tmp, fpstatus);
|
||||
tcg_temp_free_ptr(fpstatus);
|
||||
break;
|
||||
}
|
||||
case NEON_2RM_VRECPE_F:
|
||||
gen_helper_recpe_f32(cpu_F0s, cpu_F0s, cpu_env);
|
||||
{
|
||||
TCGv_ptr fpstatus = get_fpstatus_ptr(1);
|
||||
gen_helper_recpe_f32(cpu_F0s, cpu_F0s, fpstatus);
|
||||
tcg_temp_free_ptr(fpstatus);
|
||||
break;
|
||||
}
|
||||
case NEON_2RM_VRSQRTE_F:
|
||||
gen_helper_rsqrte_f32(cpu_F0s, cpu_F0s, cpu_env);
|
||||
{
|
||||
TCGv_ptr fpstatus = get_fpstatus_ptr(1);
|
||||
gen_helper_rsqrte_f32(cpu_F0s, cpu_F0s, fpstatus);
|
||||
tcg_temp_free_ptr(fpstatus);
|
||||
break;
|
||||
}
|
||||
case NEON_2RM_VCVT_FS: /* VCVT.F32.S32 */
|
||||
gen_vfp_sito(0, 1);
|
||||
break;
|
||||
@@ -10654,6 +10670,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
|
||||
dc->vec_stride = ARM_TBFLAG_VECSTRIDE(tb->flags);
|
||||
dc->cp_regs = cpu->cp_regs;
|
||||
dc->current_pl = arm_current_pl(env);
|
||||
dc->features = env->features;
|
||||
|
||||
cpu_F0s = tcg_temp_new_i32();
|
||||
cpu_F1s = tcg_temp_new_i32();
|
||||
|
@@ -26,6 +26,7 @@ typedef struct DisasContext {
|
||||
int aarch64;
|
||||
int current_pl;
|
||||
GHashTable *cp_regs;
|
||||
uint64_t features; /* CPU features bits */
|
||||
#define TMP_A64_MAX 16
|
||||
int tmp_a64_count;
|
||||
TCGv_i64 tmp_a64[TMP_A64_MAX];
|
||||
@@ -33,6 +34,11 @@ typedef struct DisasContext {
|
||||
|
||||
extern TCGv_ptr cpu_env;
|
||||
|
||||
static inline int arm_dc_feature(DisasContext *dc, int feature)
|
||||
{
|
||||
return (dc->features & (1ULL << feature)) != 0;
|
||||
}
|
||||
|
||||
/* target-specific extra values for is_jmp */
|
||||
/* These instructions trap after executing, so the A32/T32 decoder must
|
||||
* defer them until after the conditional execution state has been updated.
|
||||
|
@@ -1180,7 +1180,10 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type)
|
||||
obj = object_new(TYPE_QEMU_CONSOLE);
|
||||
s = QEMU_CONSOLE(obj);
|
||||
object_property_add_link(obj, "device", TYPE_DEVICE,
|
||||
(Object **)&s->device, &local_err);
|
||||
(Object **)&s->device,
|
||||
object_property_allow_set_link,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||
&local_err);
|
||||
object_property_add_uint32_ptr(obj, "head",
|
||||
&s->head, &local_err);
|
||||
|
||||
|
6
vl.c
6
vl.c
@@ -58,6 +58,7 @@ int main(int argc, char **argv)
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "qemu/sockets.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/usb.h"
|
||||
@@ -103,7 +104,6 @@ int main(int argc, char **argv)
|
||||
|
||||
#include "disas/disas.h"
|
||||
|
||||
#include "qemu/sockets.h"
|
||||
|
||||
#include "slirp/libslirp.h"
|
||||
|
||||
@@ -1587,14 +1587,16 @@ static void machine_class_init(ObjectClass *oc, void *data)
|
||||
|
||||
int qemu_register_machine(QEMUMachine *m)
|
||||
{
|
||||
char *name = g_strconcat(m->name, TYPE_MACHINE_SUFFIX, NULL);
|
||||
TypeInfo ti = {
|
||||
.name = g_strconcat(m->name, TYPE_MACHINE_SUFFIX, NULL),
|
||||
.name = name,
|
||||
.parent = TYPE_MACHINE,
|
||||
.class_init = machine_class_init,
|
||||
.class_data = (void *)m,
|
||||
};
|
||||
|
||||
type_register(&ti);
|
||||
g_free(name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user