summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS8
-rw-r--r--hw/9pfs/9p.c5
-rw-r--r--hw/9pfs/trace-events2
-rw-r--r--hw/m68k/mcf5208.c2
-rw-r--r--hw/misc/macio/macio.c39
-rw-r--r--hw/pci-host/trace-events2
-rw-r--r--hw/pci-host/uninorth.c58
-rw-r--r--hw/ppc/mac.h9
-rw-r--r--hw/ppc/mac_newworld.c56
-rw-r--r--hw/ppc/spapr.c84
-rw-r--r--hw/ppc/spapr_cpu_core.c47
-rw-r--r--hw/ppc/spapr_hcall.c50
-rw-r--r--hw/ppc/spapr_rtas.c108
-rw-r--r--hw/ppc/trace-events4
-rw-r--r--hw/rdma/rdma_backend.c2
-rw-r--r--hw/rdma/rdma_rm.c2
-rw-r--r--hw/rdma/rdma_rm_defs.h9
-rw-r--r--hw/rdma/vmw/pvrdma.h6
-rw-r--r--hw/rdma/vmw/pvrdma_cmd.c10
-rw-r--r--hw/rdma/vmw/pvrdma_main.c19
-rw-r--r--hw/rdma/vmw/pvrdma_qp_ops.c1
-rw-r--r--include/elf.h1
-rw-r--r--include/exec/user/abitypes.h2
-rw-r--r--include/hw/misc/macio/macio.h1
-rw-r--r--include/hw/pci-host/uninorth.h11
-rw-r--r--include/hw/ppc/spapr_cpu_core.h3
-rw-r--r--linux-user/Makefile.objs3
-rw-r--r--linux-user/aarch64/cpu_loop.c182
-rw-r--r--linux-user/aarch64/signal.c577
-rw-r--r--linux-user/aarch64/target_signal.h1
-rw-r--r--linux-user/alpha/cpu_loop.c225
-rw-r--r--linux-user/alpha/signal.c275
-rw-r--r--linux-user/alpha/target_signal.h1
-rw-r--r--linux-user/arm/cpu_loop.c459
-rw-r--r--linux-user/arm/signal.c836
-rw-r--r--linux-user/arm/target_signal.h2
-rw-r--r--linux-user/arm/target_structs.h7
-rw-r--r--linux-user/arm/target_syscall.h1
-rw-r--r--linux-user/cpu_loop-common.h37
-rw-r--r--linux-user/cris/cpu_loop.c115
-rw-r--r--linux-user/cris/signal.c189
-rw-r--r--linux-user/cris/target_signal.h2
-rw-r--r--linux-user/elfload.c54
-rw-r--r--linux-user/hppa/cpu_loop.c211
-rw-r--r--linux-user/hppa/signal.c204
-rw-r--r--linux-user/hppa/target_signal.h1
-rw-r--r--linux-user/i386/cpu_loop.c369
-rw-r--r--linux-user/i386/signal.c596
-rw-r--r--linux-user/i386/target_signal.h1
-rw-r--r--linux-user/m68k/cpu_loop.c170
-rw-r--r--linux-user/m68k/signal.c419
-rw-r--r--linux-user/m68k/target_signal.h2
-rw-r--r--linux-user/main.c4334
-rw-r--r--linux-user/microblaze/cpu_loop.c176
-rw-r--r--linux-user/microblaze/signal.c246
-rw-r--r--linux-user/microblaze/target_signal.h2
-rw-r--r--linux-user/mips/cpu_loop.c749
-rw-r--r--linux-user/mips/signal.c389
-rw-r--r--linux-user/mips/target_signal.h5
-rw-r--r--linux-user/mips64/cpu_loop.c20
-rw-r--r--linux-user/mips64/signal.c20
-rw-r--r--linux-user/mips64/target_signal.h2
-rw-r--r--linux-user/nios2/cpu_loop.c152
-rw-r--r--linux-user/nios2/signal.c237
-rw-r--r--linux-user/nios2/target_signal.h1
-rw-r--r--linux-user/openrisc/cpu_loop.c115
-rw-r--r--linux-user/openrisc/signal.c223
-rw-r--r--linux-user/openrisc/target_signal.h2
-rw-r--r--linux-user/ppc/cpu_loop.c579
-rw-r--r--linux-user/ppc/signal.c678
-rw-r--r--linux-user/ppc/target_signal.h4
-rw-r--r--linux-user/qemu.h13
-rw-r--r--linux-user/riscv/cpu_loop.c118
-rw-r--r--linux-user/riscv/signal.c208
-rw-r--r--linux-user/riscv/target_signal.h1
-rw-r--r--linux-user/riscv/target_syscall.h2
-rw-r--r--linux-user/s390x/cpu_loop.c165
-rw-r--r--linux-user/s390x/signal.c321
-rw-r--r--linux-user/s390x/target_signal.h2
-rw-r--r--linux-user/sh4/cpu_loop.c111
-rw-r--r--linux-user/sh4/signal.c343
-rw-r--r--linux-user/sh4/target_signal.h2
-rw-r--r--linux-user/signal-common.h50
-rw-r--r--linux-user/signal.c6574
-rw-r--r--linux-user/sparc/cpu_loop.c306
-rw-r--r--linux-user/sparc/signal.c634
-rw-r--r--linux-user/sparc/target_signal.h2
-rw-r--r--linux-user/sparc64/cpu_loop.c20
-rw-r--r--linux-user/sparc64/signal.c20
-rw-r--r--linux-user/sparc64/target_signal.h2
-rw-r--r--linux-user/syscall.c32
-rw-r--r--linux-user/syscall_defs.h25
-rw-r--r--linux-user/tilegx/cpu_loop.c286
-rw-r--r--linux-user/tilegx/signal.c179
-rw-r--r--linux-user/tilegx/target_signal.h2
-rw-r--r--linux-user/x86_64/cpu_loop.c20
-rw-r--r--linux-user/x86_64/signal.c20
-rw-r--r--linux-user/x86_64/target_signal.h1
-rw-r--r--linux-user/xtensa/cpu_loop.c267
-rw-r--r--linux-user/xtensa/signal.c261
-rw-r--r--linux-user/xtensa/target_signal.h1
-rw-r--r--target/hppa/translate.c16
-rw-r--r--target/m68k/softfloat.c46
-rw-r--r--target/m68k/translate.c4
-rw-r--r--target/microblaze/mmu.c9
-rw-r--r--target/microblaze/translate.c6
-rw-r--r--target/ppc/cpu.h4
-rw-r--r--target/ppc/helper.h1
-rw-r--r--target/ppc/kvm.c46
-rw-r--r--target/ppc/kvm_ppc.h6
-rw-r--r--target/ppc/machine.c5
-rw-r--r--target/ppc/misc_helper.c12
-rw-r--r--target/ppc/mmu-book3s-v3.h6
-rw-r--r--target/ppc/mmu-hash64.c15
-rw-r--r--target/ppc/mmu-hash64.h6
-rw-r--r--target/ppc/mmu_helper.c29
-rw-r--r--target/ppc/translate.c3
-rw-r--r--target/ppc/translate_init.c80
-rw-r--r--tcg/README8
-rw-r--r--tcg/arm/tcg-target.inc.c4
-rw-r--r--tcg/tcg-ldst.inc.c8
-rw-r--r--tcg/tcg-op-vec.c8
-rw-r--r--tcg/tcg-op.h91
-rw-r--r--tcg/tcg.c33
-rw-r--r--tcg/tcg.h88
125 files changed, 12503 insertions, 11433 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 24b70169bc..459e3594e1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -909,7 +909,7 @@ X86 Machines
------------
PC
M: Michael S. Tsirkin <mst@redhat.com>
-M: Marcel Apfelbaum <marcel@redhat.com>
+M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
S: Supported
F: include/hw/i386/
F: hw/i386/
@@ -959,7 +959,7 @@ F: include/hw/timer/mc146818rtc*
Machine core
M: Eduardo Habkost <ehabkost@redhat.com>
-M: Marcel Apfelbaum <marcel@redhat.com>
+M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
S: Supported
F: hw/core/machine.c
F: hw/core/null-machine.c
@@ -1033,7 +1033,7 @@ F: hw/ipack/
PCI
M: Michael S. Tsirkin <mst@redhat.com>
-M: Marcel Apfelbaum <marcel@redhat.com>
+M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
S: Supported
F: include/hw/pci/*
F: hw/misc/pci-testdev.c
@@ -2075,7 +2075,7 @@ F: docs/block-replication.txt
PVRDMA
M: Yuval Shaia <yuval.shaia@oracle.com>
-M: Marcel Apfelbaum <marcel@redhat.com>
+M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
S: Maintained
F: hw/rdma/*
F: hw/rdma/vmw/*
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index 48fa48e720..d74302deeb 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -1195,6 +1195,10 @@ static void coroutine_fn v9fs_setattr(void *opaque)
goto out_nofid;
}
+ trace_v9fs_setattr(pdu->tag, pdu->id, fid,
+ v9iattr.valid, v9iattr.mode, v9iattr.uid, v9iattr.gid,
+ v9iattr.size, v9iattr.atime_sec, v9iattr.mtime_sec);
+
fidp = get_fid(pdu, fid);
if (fidp == NULL) {
err = -EINVAL;
@@ -1259,6 +1263,7 @@ static void coroutine_fn v9fs_setattr(void *opaque)
}
}
err = offset;
+ trace_v9fs_setattr_return(pdu->tag, pdu->id);
out:
put_fid(pdu, fidp);
out_nofid:
diff --git a/hw/9pfs/trace-events b/hw/9pfs/trace-events
index 1aee350c42..881e4c4dd8 100644
--- a/hw/9pfs/trace-events
+++ b/hw/9pfs/trace-events
@@ -46,3 +46,5 @@ v9fs_xattrwalk_return(uint16_t tag, uint8_t id, int64_t size) "tag %d id %d size
v9fs_xattrcreate(uint16_t tag, uint8_t id, int32_t fid, char* name, uint64_t size, int flags) "tag %d id %d fid %d name %s size %"PRIu64" flags %d"
v9fs_readlink(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d"
v9fs_readlink_return(uint16_t tag, uint8_t id, char* target) "tag %d id %d name %s"
+v9fs_setattr(uint16_t tag, uint8_t id, int32_t fid, int32_t valid, int32_t mode, int32_t uid, int32_t gid, int64_t size, int64_t atime_sec, int64_t mtime_sec) "tag %u id %u fid %d iattr={valid %d mode %d uid %d gid %d size %"PRId64" atime=%"PRId64" mtime=%"PRId64" }"
+v9fs_setattr_return(uint16_t tag, uint8_t id) "tag %u id %u"
diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c
index 7aca58542e..ae3dcc98c3 100644
--- a/hw/m68k/mcf5208.c
+++ b/hw/m68k/mcf5208.c
@@ -315,7 +315,7 @@ static void mcf5208evb_init(MachineState *machine)
static void mcf5208evb_machine_init(MachineClass *mc)
{
- mc->desc = "MCF5206EVB";
+ mc->desc = "MCF5208EVB";
mc->init = mcf5208evb_init;
mc->is_default = 1;
mc->default_cpu_type = M68K_CPU_TYPE_NAME("m5208");
diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c
index dac7bcd15e..79621eb879 100644
--- a/hw/misc/macio/macio.c
+++ b/hw/misc/macio/macio.c
@@ -279,11 +279,10 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp)
{
MacIOState *s = MACIO(d);
NewWorldMacIOState *ns = NEWWORLD_MACIO(d);
+ DeviceState *pic_dev = DEVICE(ns->pic);
Error *err = NULL;
SysBusDevice *sysbus_dev;
MemoryRegion *timer_memory = NULL;
- int i;
- int cur_irq = 0;
macio_common_realize(d, &err);
if (err) {
@@ -292,11 +291,14 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp)
}
sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
- sysbus_connect_irq(sysbus_dev, 0, ns->irqs[cur_irq++]);
+ sysbus_connect_irq(sysbus_dev, 0, qdev_get_gpio_in(pic_dev,
+ NEWWORLD_CUDA_IRQ));
sysbus_dev = SYS_BUS_DEVICE(&s->escc);
- sysbus_connect_irq(sysbus_dev, 0, ns->irqs[cur_irq++]);
- sysbus_connect_irq(sysbus_dev, 1, ns->irqs[cur_irq++]);
+ sysbus_connect_irq(sysbus_dev, 0, qdev_get_gpio_in(pic_dev,
+ NEWWORLD_ESCCB_IRQ));
+ sysbus_connect_irq(sysbus_dev, 1, qdev_get_gpio_in(pic_dev,
+ NEWWORLD_ESCCA_IRQ));
/* OpenPIC */
sysbus_dev = SYS_BUS_DEVICE(ns->pic);
@@ -304,15 +306,22 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp)
sysbus_mmio_get_region(sysbus_dev, 0));
/* IDE buses */
- for (i = 0; i < ARRAY_SIZE(ns->ide); i++) {
- qemu_irq irq0 = ns->irqs[cur_irq++];
- qemu_irq irq1 = ns->irqs[cur_irq++];
-
- macio_realize_ide(s, &ns->ide[i], irq0, irq1, 0x16 + (i * 4), &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
+ macio_realize_ide(s, &ns->ide[0],
+ qdev_get_gpio_in(pic_dev, NEWWORLD_IDE0_IRQ),
+ qdev_get_gpio_in(pic_dev, NEWWORLD_IDE0_DMA_IRQ),
+ 0x16, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ macio_realize_ide(s, &ns->ide[1],
+ qdev_get_gpio_in(pic_dev, NEWWORLD_IDE1_IRQ),
+ qdev_get_gpio_in(pic_dev, NEWWORLD_IDE1_DMA_IRQ),
+ 0x1a, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
}
/* Timer */
@@ -328,8 +337,6 @@ static void macio_newworld_init(Object *obj)
NewWorldMacIOState *ns = NEWWORLD_MACIO(obj);
int i;
- qdev_init_gpio_out(DEVICE(obj), ns->irqs, ARRAY_SIZE(ns->irqs));
-
object_property_add_link(obj, "pic", TYPE_OPENPIC,
(Object **) &ns->pic,
qdev_prop_allow_set_link_before_realize,
diff --git a/hw/pci-host/trace-events b/hw/pci-host/trace-events
index 341a87a702..dd7a398e96 100644
--- a/hw/pci-host/trace-events
+++ b/hw/pci-host/trace-events
@@ -18,3 +18,5 @@ unin_set_irq(int irq_num, int level) "setting INT %d = %d"
unin_get_config_reg(uint32_t reg, uint32_t addr, uint32_t retval) "converted config space accessor 0x%"PRIx32 "/0x%"PRIx32 " -> 0x%"PRIx32
unin_data_write(uint64_t addr, unsigned len, uint64_t val) "write addr 0x%"PRIx64 " len %d val 0x%"PRIx64
unin_data_read(uint64_t addr, unsigned len, uint64_t val) "read addr 0x%"PRIx64 " len %d val 0x%"PRIx64
+unin_write(uint64_t addr, uint64_t value) "addr=0x%" PRIx64 " val=0x%"PRIx64
+unin_read(uint64_t addr, uint64_t value) "addr=0x%" PRIx64 " val=0x%"PRIx64
diff --git a/hw/pci-host/uninorth.c b/hw/pci-host/uninorth.c
index fada0ffd5f..ba76b84dbc 100644
--- a/hw/pci-host/uninorth.c
+++ b/hw/pci-host/uninorth.c
@@ -519,6 +519,62 @@ static const TypeInfo pci_unin_internal_info = {
.class_init = pci_unin_internal_class_init,
};
+/* UniN device */
+static void unin_write(void *opaque, hwaddr addr, uint64_t value,
+ unsigned size)
+{
+ trace_unin_write(addr, value);
+ if (addr == 0x0) {
+ *(int *)opaque = value;
+ }
+}
+
+static uint64_t unin_read(void *opaque, hwaddr addr, unsigned size)
+{
+ uint32_t value;
+
+ value = 0;
+ switch (addr) {
+ case 0:
+ value = *(int *)opaque;
+ }
+
+ trace_unin_read(addr, value);
+
+ return value;
+}
+
+static const MemoryRegionOps unin_ops = {
+ .read = unin_read,
+ .write = unin_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static void unin_init(Object *obj)
+{
+ UNINState *s = UNI_NORTH(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+
+ memory_region_init_io(&s->mem, obj, &unin_ops, &s->token, "unin", 0x1000);
+
+ sysbus_init_mmio(sbd, &s->mem);
+}
+
+static void unin_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+}
+
+static const TypeInfo unin_info = {
+ .name = TYPE_UNI_NORTH,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(UNINState),
+ .instance_init = unin_init,
+ .class_init = unin_class_init,
+};
+
static void unin_register_types(void)
{
type_register_static(&unin_main_pci_host_info);
@@ -530,6 +586,8 @@ static void unin_register_types(void)
type_register_static(&pci_u3_agp_info);
type_register_static(&pci_unin_agp_info);
type_register_static(&pci_unin_internal_info);
+
+ type_register_static(&unin_info);
}
type_init(unin_register_types)
diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h
index 892dd03789..22a7efbed6 100644
--- a/hw/ppc/mac.h
+++ b/hw/ppc/mac.h
@@ -56,6 +56,15 @@
#define OLDWORLD_IDE1_IRQ 0xe
#define OLDWORLD_IDE1_DMA_IRQ 0x3
+/* New World IRQs */
+#define NEWWORLD_CUDA_IRQ 0x19
+#define NEWWORLD_ESCCB_IRQ 0x24
+#define NEWWORLD_ESCCA_IRQ 0x25
+#define NEWWORLD_IDE0_IRQ 0xd
+#define NEWWORLD_IDE0_DMA_IRQ 0x2
+#define NEWWORLD_IDE1_IRQ 0xe
+#define NEWWORLD_IDE1_DMA_IRQ 0x3
+
/* MacIO */
#define TYPE_MACIO_IDE "macio-ide"
#define MACIO_IDE(obj) OBJECT_CHECK(MACIOIDEState, (obj), TYPE_MACIO_IDE)
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index 29bd3838bf..744acdfd2e 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -82,36 +82,6 @@
#define NDRV_VGA_FILENAME "qemu_vga.ndrv"
-/* UniN device */
-static void unin_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- trace_mac99_uninorth_write(addr, value);
- if (addr == 0x0) {
- *(int*)opaque = value;
- }
-}
-
-static uint64_t unin_read(void *opaque, hwaddr addr, unsigned size)
-{
- uint32_t value;
-
- value = 0;
- switch (addr) {
- case 0:
- value = *(int*)opaque;
- }
-
- trace_mac99_uninorth_read(addr, value);
-
- return value;
-}
-
-static const MemoryRegionOps unin_ops = {
- .read = unin_read,
- .write = unin_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
static void fw_cfg_boot_set(void *opaque, const char *boot_device,
Error **errp)
@@ -144,8 +114,7 @@ static void ppc_core99_init(MachineState *machine)
PowerPCCPU *cpu = NULL;
CPUPPCState *env = NULL;
char *filename;
- qemu_irq *pic, **openpic_irqs;
- MemoryRegion *unin_memory = g_new(MemoryRegion, 1);
+ qemu_irq **openpic_irqs;
int linux_boot, i, j, k;
MemoryRegion *ram = g_new(MemoryRegion, 1), *bios = g_new(MemoryRegion, 1);
hwaddr kernel_base, initrd_base, cmdline_base = 0;
@@ -164,7 +133,6 @@ static void ppc_core99_init(MachineState *machine)
int machine_arch;
SysBusDevice *s;
DeviceState *dev, *pic_dev;
- int *token = g_new(int, 1);
hwaddr nvram_addr = 0xFFF04000;
uint64_t tbfreq;
@@ -272,9 +240,12 @@ static void ppc_core99_init(MachineState *machine)
}
}
- /* UniN init: XXX should be a real device */
- memory_region_init_io(unin_memory, NULL, &unin_ops, token, "unin", 0x1000);
- memory_region_add_subregion(get_system_memory(), 0xf8000000, unin_memory);
+ /* UniN init */
+ dev = qdev_create(NULL, TYPE_UNI_NORTH);
+ qdev_init_nofail(dev);
+ s = SYS_BUS_DEVICE(dev);
+ memory_region_add_subregion(get_system_memory(), 0xf8000000,
+ sysbus_mmio_get_region(s, 0));
openpic_irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
openpic_irqs[0] =
@@ -320,8 +291,6 @@ static void ppc_core99_init(MachineState *machine)
}
}
- pic = g_new0(qemu_irq, 64);
-
pic_dev = qdev_create(NULL, TYPE_OPENPIC);
qdev_prop_set_uint32(pic_dev, "model", OPENPIC_MODEL_KEYLARGO);
qdev_init_nofail(pic_dev);
@@ -333,10 +302,6 @@ static void ppc_core99_init(MachineState *machine)
}
}
- for (i = 0; i < 64; i++) {
- pic[i] = qdev_get_gpio_in(pic_dev, i);
- }
-
if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) {
/* 970 gets a U3 bus */
/* Uninorth AGP bus */
@@ -410,13 +375,6 @@ static void ppc_core99_init(MachineState *machine)
/* MacIO */
macio = NEWWORLD_MACIO(pci_create(pci_bus, -1, TYPE_NEWWORLD_MACIO));
dev = DEVICE(macio);
- qdev_connect_gpio_out(dev, 0, pic[0x19]); /* CUDA */
- qdev_connect_gpio_out(dev, 1, pic[0x24]); /* ESCC-B */
- qdev_connect_gpio_out(dev, 2, pic[0x25]); /* ESCC-A */
- qdev_connect_gpio_out(dev, 3, pic[0x0d]); /* IDE */
- qdev_connect_gpio_out(dev, 4, pic[0x02]); /* IDE DMA */
- qdev_connect_gpio_out(dev, 5, pic[0x0e]); /* IDE */
- qdev_connect_gpio_out(dev, 6, pic[0x03]); /* IDE DMA */
qdev_prop_set_uint64(dev, "frequency", tbfreq);
object_property_set_link(OBJECT(macio), OBJECT(pic_dev), "pic",
&error_abort);
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index b35aff5d81..32ab3c43b6 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1668,10 +1668,8 @@ static void spapr_machine_reset(void)
g_free(fdt);
/* Set up the entry state */
- first_ppc_cpu->env.gpr[3] = fdt_addr;
+ spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT, fdt_addr);
first_ppc_cpu->env.gpr[5] = 0;
- first_cpu->halted = 0;
- first_ppc_cpu->env.nip = SPAPR_ENTRY_POINT;
spapr->cas_reboot = false;
}
@@ -1851,10 +1849,12 @@ static bool spapr_ov5_cas_needed(void *opaque)
*
* Thus, for any cases where the set of available CAS-negotiatable
* options extends beyond OV5_FORM1_AFFINITY and OV5_DRCONF_MEMORY, we
- * include the CAS-negotiated options in the migration stream.
+ * include the CAS-negotiated options in the migration stream, unless
+ * if they affect boot time behaviour only.
*/
spapr_ovec_set(ov5_mask, OV5_FORM1_AFFINITY);
spapr_ovec_set(ov5_mask, OV5_DRCONF_MEMORY);
+ spapr_ovec_set(ov5_mask, OV5_DRMEM_V2);
/* spapr_ovec_diff returns true if bits were removed. we avoid using
* the mask itself since in the future it's possible "legacy" bits may be
@@ -2508,13 +2508,11 @@ static void spapr_machine_init(MachineState *machine)
int i;
MemoryRegion *sysmem = get_system_memory();
MemoryRegion *ram = g_new(MemoryRegion, 1);
- MemoryRegion *rma_region;
- void *rma = NULL;
- hwaddr rma_alloc_size;
hwaddr node0_size = spapr_node0_size(machine);
long load_limit, fw_size;
char *filename;
Error *resize_hpt_err = NULL;
+ PowerPCCPU *first_ppc_cpu;
msi_nonbroken = true;
@@ -2549,40 +2547,28 @@ static void spapr_machine_init(MachineState *machine)
exit(1);
}
- /* Allocate RMA if necessary */
- rma_alloc_size = kvmppc_alloc_rma(&rma);
+ spapr->rma_size = node0_size;
- if (rma_alloc_size == -1) {
- error_report("Unable to create RMA");
- exit(1);
+ /* With KVM, we don't actually know whether KVM supports an
+ * unbounded RMA (PR KVM) or is limited by the hash table size
+ * (HV KVM using VRMA), so we always assume the latter
+ *
+ * In that case, we also limit the initial allocations for RTAS
+ * etc... to 256M since we have no way to know what the VRMA size
+ * is going to be as it depends on the size of the hash table
+ * which isn't determined yet.
+ */
+ if (kvm_enabled()) {
+ spapr->vrma_adjust = 1;
+ spapr->rma_size = MIN(spapr->rma_size, 0x10000000);
}
- if (rma_alloc_size && (rma_alloc_size < node0_size)) {
- spapr->rma_size = rma_alloc_size;
- } else {
- spapr->rma_size = node0_size;
-
- /* With KVM, we don't actually know whether KVM supports an
- * unbounded RMA (PR KVM) or is limited by the hash table size
- * (HV KVM using VRMA), so we always assume the latter
- *
- * In that case, we also limit the initial allocations for RTAS
- * etc... to 256M since we have no way to know what the VRMA size
- * is going to be as it depends on the size of the hash table
- * isn't determined yet.
- */
- if (kvm_enabled()) {
- spapr->vrma_adjust = 1;
- spapr->rma_size = MIN(spapr->rma_size, 0x10000000);
- }
-
- /* Actually we don't support unbounded RMA anymore since we
- * added proper emulation of HV mode. The max we can get is
- * 16G which also happens to be what we configure for PAPR
- * mode so make sure we don't do anything bigger than that
- */
- spapr->rma_size = MIN(spapr->rma_size, 0x400000000ull);
- }
+ /* Actually we don't support unbounded RMA anymore since we added
+ * proper emulation of HV mode. The max we can get is 16G which
+ * also happens to be what we configure for PAPR mode so make sure
+ * we don't do anything bigger than that
+ */
+ spapr->rma_size = MIN(spapr->rma_size, 0x400000000ull);
if (spapr->rma_size > node0_size) {
error_report("Numa node 0 has to span the RMA (%#08"HWADDR_PRIx")",
@@ -2607,11 +2593,6 @@ static void spapr_machine_init(MachineState *machine)
}
spapr_ovec_set(spapr->ov5, OV5_FORM1_AFFINITY);
- if (!kvm_enabled() || kvmppc_has_cap_mmu_radix()) {
- /* KVM and TCG always allow GTSE with radix... */
- spapr_ovec_set(spapr->ov5, OV5_MMU_RADIX_GTSE);
- }
- /* ... but not with hash (currently). */
/* advertise support for dedicated HP event source to guests */
if (spapr->use_hotplug_event_source) {
@@ -2629,6 +2610,15 @@ static void spapr_machine_init(MachineState *machine)
/* init CPUs */
spapr_init_cpus(spapr);
+ first_ppc_cpu = POWERPC_CPU(first_cpu);
+ if ((!kvm_enabled() || kvmppc_has_cap_mmu_radix()) &&
+ ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0,
+ spapr->max_compat_pvr)) {
+ /* KVM and TCG always allow GTSE with radix... */
+ spapr_ovec_set(spapr->ov5, OV5_MMU_RADIX_GTSE);
+ }
+ /* ... but not with hash (currently). */
+
if (kvm_enabled()) {
/* Enable H_LOGICAL_CI_* so SLOF can talk to in-kernel devices */
kvmppc_enable_logical_ci_hcalls();
@@ -2643,14 +2633,6 @@ static void spapr_machine_init(MachineState *machine)
machine->ram_size);
memory_region_add_subregion(sysmem, 0, ram);
- if (rma_alloc_size && rma) {
- rma_region = g_new(MemoryRegion, 1);
- memory_region_init_ram_ptr(rma_region, NULL, "ppc_spapr.rma",
- rma_alloc_size, rma);
- vmstate_register_ram_global(rma_region);
- memory_region_add_subregion(sysmem, 0, rma_region);
- }
-
/* initialize hotplug memory address space */
if (machine->ram_size < machine->maxram_size) {
ram_addr_t hotplug_mem_size = machine->maxram_size - machine->ram_size;
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 01dbc69424..f3e9b879b2 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -28,6 +28,7 @@ static void spapr_cpu_reset(void *opaque)
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+ target_ulong lpcr;
cpu_reset(cs);
@@ -43,13 +44,43 @@ static void spapr_cpu_reset(void *opaque)
env->spr[SPR_HIOR] = 0;
- /* Disable Power-saving mode Exit Cause exceptions for the CPU.
- * This can cause issues when rebooting the guest if a secondary
- * is awaken */
- if (cs != first_cpu) {
- env->spr[SPR_LPCR] &= ~pcc->lpcr_pm;
- }
+ lpcr = env->spr[SPR_LPCR];
+
+ /* Set emulated LPCR to not send interrupts to hypervisor. Note that
+ * under KVM, the actual HW LPCR will be set differently by KVM itself,
+ * the settings below ensure proper operations with TCG in absence of
+ * a real hypervisor.
+ *
+ * Clearing VPM0 will also cause us to use RMOR in mmu-hash64.c for
+ * real mode accesses, which thankfully defaults to 0 and isn't
+ * accessible in guest mode.
+ *
+ * Disable Power-saving mode Exit Cause exceptions for the CPU, so
+ * we don't get spurious wakups before an RTAS start-cpu call.
+ */
+ lpcr &= ~(LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_KBV | pcc->lpcr_pm);
+ lpcr |= LPCR_LPES0 | LPCR_LPES1;
+
+ /* Set RMLS to the max (ie, 16G) */
+ lpcr &= ~LPCR_RMLS;
+ lpcr |= 1ull << LPCR_RMLS_SHIFT;
+
+ ppc_store_lpcr(cpu, lpcr);
+
+ /* Set a full AMOR so guest can use the AMR as it sees fit */
+ env->spr[SPR_AMOR] = 0xffffffffffffffffull;
+}
+
+void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip, target_ulong r3)
+{
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+ CPUPPCState *env = &cpu->env;
+ env->nip = nip;
+ env->gpr[3] = r3;
+ CPU(cpu)->halted = 0;
+ /* Enable Power-saving mode Exit Cause exceptions */
+ ppc_store_lpcr(cpu, env->spr[SPR_LPCR] | pcc->lpcr_pm);
}
static void spapr_cpu_destroy(PowerPCCPU *cpu)
@@ -65,8 +96,8 @@ static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu,
/* Set time-base frequency to 512 MHz */
cpu_ppc_tb_init(env, SPAPR_TIMEBASE_FREQ);
- /* Enable PAPR mode in TCG or KVM */
- cpu_ppc_set_papr(cpu, PPC_VIRTUAL_HYPERVISOR(spapr));
+ cpu_ppc_set_vhyp(cpu, PPC_VIRTUAL_HYPERVISOR(spapr));
+ kvmppc_set_papr(cpu);
qemu_register_reset(spapr_cpu_reset, cpu);
spapr_cpu_reset(cpu);
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 16bccdd5c0..ca9702e667 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -15,32 +15,35 @@
#include "hw/ppc/spapr_ovec.h"
#include "mmu-book3s-v3.h"
-struct SPRSyncState {
- int spr;
+struct LPCRSyncState {
target_ulong value;
target_ulong mask;
};
-static void do_spr_sync(CPUState *cs, run_on_cpu_data arg)
+static void do_lpcr_sync(CPUState *cs, run_on_cpu_data arg)
{
- struct SPRSyncState *s = arg.host_ptr;
+ struct LPCRSyncState *s = arg.host_ptr;
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = &cpu->env;
+ target_ulong lpcr;
cpu_synchronize_state(cs);
- env->spr[s->spr] &= ~s->mask;
- env->spr[s->spr] |= s->value;
+ lpcr = env->spr[SPR_LPCR];
+ lpcr &= ~s->mask;
+ lpcr |= s->value;
+ ppc_store_lpcr(cpu, lpcr);
}
-static void set_spr(CPUState *cs, int spr, target_ulong value,
- target_ulong mask)
+static void set_all_lpcrs(target_ulong value, target_ulong mask)
{
- struct SPRSyncState s = {
- .spr = spr,
+ CPUState *cs;
+ struct LPCRSyncState s = {
.value = value,
.mask = mask
};
- run_on_cpu(cs, do_spr_sync, RUN_ON_CPU_HOST_PTR(&s));
+ CPU_FOREACH(cs) {
+ run_on_cpu(cs, do_lpcr_sync, RUN_ON_CPU_HOST_PTR(&s));
+ }
}
static bool has_spr(PowerPCCPU *cpu, int spr)
@@ -1235,8 +1238,6 @@ static target_ulong h_set_mode_resource_le(PowerPCCPU *cpu,
target_ulong value1,
target_ulong value2)
{
- CPUState *cs;
-
if (value1) {
return H_P3;
}
@@ -1246,16 +1247,12 @@ static target_ulong h_set_mode_resource_le(PowerPCCPU *cpu,
switch (mflags) {
case H_SET_MODE_ENDIAN_BIG:
- CPU_FOREACH(cs) {
- set_spr(cs, SPR_LPCR, 0, LPCR_ILE);
- }
+ set_all_lpcrs(0, LPCR_ILE);
spapr_pci_switch_vga(true);
return H_SUCCESS;
case H_SET_MODE_ENDIAN_LITTLE:
- CPU_FOREACH(cs) {
- set_spr(cs, SPR_LPCR, LPCR_ILE, LPCR_ILE);
- }
+ set_all_lpcrs(LPCR_ILE, LPCR_ILE);
spapr_pci_switch_vga(false);
return H_SUCCESS;
}
@@ -1268,7 +1265,6 @@ static target_ulong h_set_mode_resource_addr_trans_mode(PowerPCCPU *cpu,
target_ulong value1,
target_ulong value2)
{
- CPUState *cs;
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
if (!(pcc->insns_flags2 & PPC2_ISA207S)) {
@@ -1285,9 +1281,7 @@ static target_ulong h_set_mode_resource_addr_trans_mode(PowerPCCPU *cpu,
return H_UNSUPPORTED_FLAG;
}
- CPU_FOREACH(cs) {
- set_spr(cs, SPR_LPCR, mflags << LPCR_AIL_SHIFT, LPCR_AIL);
- }
+ set_all_lpcrs(mflags << LPCR_AIL_SHIFT, LPCR_AIL);
return H_SUCCESS;
}
@@ -1364,7 +1358,6 @@ static target_ulong h_register_process_table(PowerPCCPU *cpu,
target_ulong opcode,
target_ulong *args)
{
- CPUState *cs;
target_ulong flags = args[0];
target_ulong proc_tbl = args[1];
target_ulong page_size = args[2];
@@ -1422,12 +1415,9 @@ static target_ulong h_register_process_table(PowerPCCPU *cpu,
spapr->patb_entry = cproc; /* Save new process table */
/* Update the UPRT and GTSE bits in the LPCR for all cpus */
- CPU_FOREACH(cs) {
- set_spr(cs, SPR_LPCR,
- ((flags & (FLAG_RADIX | FLAG_HASH_PROC_TBL)) ? LPCR_UPRT : 0) |
- ((flags & FLAG_GTSE) ? LPCR_GTSE : 0),
- LPCR_UPRT | LPCR_GTSE);
- }
+ set_all_lpcrs(((flags & (FLAG_RADIX | FLAG_HASH_PROC_TBL)) ? LPCR_UPRT : 0) |
+ ((flags & FLAG_GTSE) ? LPCR_GTSE : 0),
+ LPCR_UPRT | LPCR_GTSE);
if (kvm_enabled()) {
return kvmppc_configure_v3_mmu(cpu, flags & FLAG_RADIX,
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index 0ec5fa4cfe..7f9738daed 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -32,11 +32,12 @@
#include "hw/qdev.h"
#include "sysemu/device_tree.h"
#include "sysemu/cpus.h"
-#include "sysemu/kvm.h"
+#include "sysemu/hw_accel.h"
#include "hw/ppc/spapr.h"
#include "hw/ppc/spapr_vio.h"
#include "hw/ppc/spapr_rtas.h"
+#include "hw/ppc/spapr_cpu_core.h"
#include "hw/ppc/ppc.h"
#include "hw/boards.h"
@@ -45,6 +46,8 @@
#include "qemu/cutils.h"
#include "trace.h"
#include "hw/ppc/fdt.h"
+#include "target/ppc/mmu-hash64.h"
+#include "target/ppc/mmu-book3s-v3.h"
static void rtas_display_character(PowerPCCPU *cpu, sPAPRMachineState *spapr,
uint32_t token, uint32_t nargs,
@@ -119,34 +122,16 @@ static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_,
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
}
-/*
- * Set the timebase offset of the CPU to that of first CPU.
- * This helps hotplugged CPU to have the correct timebase offset.
- */
-static void spapr_cpu_update_tb_offset(PowerPCCPU *cpu)
-{
- PowerPCCPU *fcpu = POWERPC_CPU(first_cpu);
-
- cpu->env.tb_env->tb_offset = fcpu->env.tb_env->tb_offset;
-}
-
-static void spapr_cpu_set_endianness(PowerPCCPU *cpu)
-{
- PowerPCCPU *fcpu = POWERPC_CPU(first_cpu);
- PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(fcpu);
-
- if (!pcc->interrupts_big_endian(fcpu)) {
- cpu->env.spr[SPR_LPCR] |= LPCR_ILE;
- }
-}
-
-static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr,
+static void rtas_start_cpu(PowerPCCPU *callcpu, sPAPRMachineState *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
uint32_t nret, target_ulong rets)
{
target_ulong id, start, r3;
- PowerPCCPU *cpu;
+ PowerPCCPU *newcpu;
+ CPUPPCState *env;
+ PowerPCCPUClass *pcc;
+ target_ulong lpcr;
if (nargs != 3 || nret != 1) {
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
@@ -157,41 +142,55 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr,
start = rtas_ld(args, 1);
r3 = rtas_ld(args, 2);
- cpu = spapr_find_cpu(id);
- if (cpu != NULL) {
- CPUState *cs = CPU(cpu);
- CPUPPCState *env = &cpu->env;
- PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+ newcpu = spapr_find_cpu(id);
+ if (!newcpu) {
+ /* Didn't find a matching cpu */
+ rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
+ return;
+ }
- if (!cs->halted) {
- rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
- return;
- }
+ env = &newcpu->env;
+ pcc = POWERPC_CPU_GET_CLASS(newcpu);
+
+ if (!CPU(newcpu)->halted) {
+ rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
+ return;
+ }
- /* This will make sure qemu state is up to date with kvm, and
- * mark it dirty so our changes get flushed back before the
- * new cpu enters */
- kvm_cpu_synchronize_state(cs);
+ cpu_synchronize_state(CPU(newcpu));
- env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME);
+ env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME);
- /* Enable Power-saving mode Exit Cause exceptions for the new CPU */
- env->spr[SPR_LPCR] |= pcc->lpcr_pm;
+ /* Enable Power-saving mode Exit Cause exceptions for the new CPU */
+ lpcr = env->spr[SPR_LPCR];
+ if (!pcc->interrupts_big_endian(callcpu)) {
+ lpcr |= LPCR_ILE;
+ }
+ if (env->mmu_model == POWERPC_MMU_3_00) {
+ /*
+ * New cpus are expected to start in the same radix/hash mode
+ * as the existing CPUs
+ */
+ if (ppc64_radix_guest(callcpu)) {
+ lpcr |= LPCR_UPRT | LPCR_GTSE;
+ } else {
+ lpcr &= ~(LPCR_UPRT | LPCR_GTSE);
+ }
+ }
+ ppc_store_lpcr(newcpu, lpcr);
- env->nip = start;
- env->gpr[3] = r3;
- cs->halted = 0;
- spapr_cpu_set_endianness(cpu);
- spapr_cpu_update_tb_offset(cpu);
+ /*
+ * Set the timebase offset of the new CPU to that of the invoking
+ * CPU. This helps hotplugged CPU to have the correct timebase
+ * offset.
+ */
+ newcpu->env.tb_env->tb_offset = callcpu->env.tb_env->tb_offset;
- qemu_cpu_kick(cs);
+ spapr_cpu_set_entry_state(newcpu, start, r3);
- rtas_st(rets, 0, RTAS_OUT_SUCCESS);
- return;
- }
+ qemu_cpu_kick(CPU(newcpu));
- /* Didn't find a matching cpu */
- rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
+ rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
static void rtas_stop_self(PowerPCCPU *cpu, sPAPRMachineState *spapr,
@@ -203,13 +202,12 @@ static void rtas_stop_self(PowerPCCPU *cpu, sPAPRMachineState *spapr,
CPUPPCState *env = &cpu->env;
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
- cs->halted = 1;
- qemu_cpu_kick(cs);
-
/* Disable Power-saving mode Exit Cause exceptions for the CPU.
* This could deliver an interrupt on a dying CPU and crash the
* guest */
- env->spr[SPR_LPCR] &= ~pcc->lpcr_pm;
+ ppc_store_lpcr(cpu, env->spr[SPR_LPCR] & ~pcc->lpcr_pm);
+ cs->halted = 1;
+ qemu_cpu_kick(cs);
}
static inline int sysparm_st(target_ulong addr, target_ulong len,
diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events
index 66ec7eda6e..dc5e65aee9 100644
--- a/hw/ppc/trace-events
+++ b/hw/ppc/trace-events
@@ -92,10 +92,6 @@ rs6000mc_size_read(uint32_t addr, uint32_t val) "read addr=0x%x val=0x%x"
rs6000mc_size_write(uint32_t addr, uint32_t val) "write addr=0x%x val=0x%x"
rs6000mc_parity_read(uint32_t addr, uint32_t val) "read addr=0x%x val=0x%x"
-# hw/ppc/mac_newworld.c
-mac99_uninorth_write(uint64_t addr, uint64_t value) "addr=0x%" PRIx64 " val=0x%"PRIx64
-mac99_uninorth_read(uint64_t addr, uint64_t value) "addr=0x%" PRIx64 " val=0x%"PRIx64
-
# hw/ppc/ppc4xx_pci.c
ppc4xx_pci_map_irq(int32_t devfn, int irq_num, int slot) "devfn 0x%x irq %d -> %d"
ppc4xx_pci_set_irq(int irq_num) "PCI irq %d"
diff --git a/hw/rdma/rdma_backend.c b/hw/rdma/rdma_backend.c
index 5c7b3d8949..e9ced6f9ef 100644
--- a/hw/rdma/rdma_backend.c
+++ b/hw/rdma/rdma_backend.c
@@ -774,7 +774,7 @@ int rdma_backend_init(RdmaBackendDev *backend_dev,
goto out_destroy_comm_channel;
}
- if (backend_dev->backend_gid_idx > port_attr.gid_tbl_len) {
+ if (backend_dev->backend_gid_idx >= port_attr.gid_tbl_len) {
error_setg(errp, "Invalid backend_gid_idx, should be less than %d",
port_attr.gid_tbl_len);
goto out_destroy_comm_channel;
diff --git a/hw/rdma/rdma_rm.c b/hw/rdma/rdma_rm.c
index 51a47d7292..415da15efe 100644
--- a/hw/rdma/rdma_rm.c
+++ b/hw/rdma/rdma_rm.c
@@ -21,8 +21,6 @@
#include "rdma_backend.h"
#include "rdma_rm.h"
-#define MAX_RM_TBL_NAME 16
-
/* Page directory and page tables */
#define PG_DIR_SZ { TARGET_PAGE_SIZE / sizeof(__u64) }
#define PG_TBL_SZ { TARGET_PAGE_SIZE / sizeof(__u64) }
diff --git a/hw/rdma/rdma_rm_defs.h b/hw/rdma/rdma_rm_defs.h
index fc646da61f..226011176d 100644
--- a/hw/rdma/rdma_rm_defs.h
+++ b/hw/rdma/rdma_rm_defs.h
@@ -20,9 +20,9 @@
#define MAX_PORTS 1
#define MAX_PORT_GIDS 1
+#define MAX_GIDS MAX_PORT_GIDS
#define MAX_PORT_PKEYS 1
-#define MAX_PKEYS 1
-#define MAX_GIDS 2048
+#define MAX_PKEYS MAX_PORT_PKEYS
#define MAX_UCS 512
#define MAX_MR_SIZE (1UL << 27)
#define MAX_QP 1024
@@ -34,9 +34,9 @@
#define MAX_QP_INIT_RD_ATOM 16
#define MAX_AH 64
-#define MAX_RMRESTBL_NAME_SZ 16
+#define MAX_RM_TBL_NAME 16
typedef struct RdmaRmResTbl {
- char name[MAX_RMRESTBL_NAME_SZ];
+ char name[MAX_RM_TBL_NAME];
QemuMutex lock;
unsigned long *bitmap;
size_t tbl_sz;
@@ -87,7 +87,6 @@ typedef struct RdmaRmQP {
typedef struct RdmaRmPort {
union ibv_gid gid_tbl[MAX_PORT_GIDS];
enum ibv_port_state state;
- int *pkey_tbl; /* TODO: Not yet supported */
} RdmaRmPort;
typedef struct RdmaDeviceResources {
diff --git a/hw/rdma/vmw/pvrdma.h b/hw/rdma/vmw/pvrdma.h
index 8c173cb824..0b46dc5a9b 100644
--- a/hw/rdma/vmw/pvrdma.h
+++ b/hw/rdma/vmw/pvrdma.h
@@ -31,7 +31,7 @@
#define RDMA_REG_BAR_IDX 1
#define RDMA_UAR_BAR_IDX 2
#define RDMA_BAR0_MSIX_SIZE (16 * 1024)
-#define RDMA_BAR1_REGS_SIZE 256
+#define RDMA_BAR1_REGS_SIZE 64
#define RDMA_BAR2_UAR_SIZE (0x1000 * MAX_UCS) /* each uc gets page */
/* MSIX */
@@ -86,7 +86,7 @@ static inline int get_reg_val(PVRDMADev *dev, hwaddr addr, uint32_t *val)
{
int idx = addr >> 2;
- if (idx > RDMA_BAR1_REGS_SIZE) {
+ if (idx >= RDMA_BAR1_REGS_SIZE) {
return -EINVAL;
}
@@ -99,7 +99,7 @@ static inline int set_reg_val(PVRDMADev *dev, hwaddr addr, uint32_t val)
{
int idx = addr >> 2;
- if (idx > RDMA_BAR1_REGS_SIZE) {
+ if (idx >= RDMA_BAR1_REGS_SIZE) {
return -EINVAL;
}
diff --git a/hw/rdma/vmw/pvrdma_cmd.c b/hw/rdma/vmw/pvrdma_cmd.c
index 99019d8741..14255d609f 100644
--- a/hw/rdma/vmw/pvrdma_cmd.c
+++ b/hw/rdma/vmw/pvrdma_cmd.c
@@ -232,7 +232,7 @@ static int create_mr(PVRDMADev *dev, union pvrdma_cmd_req *req,
cmd->start, cmd->length, host_virt,
cmd->access_flags, &resp->mr_handle,
&resp->lkey, &resp->rkey);
- if (!resp->hdr.err) {
+ if (host_virt && !resp->hdr.err) {
munmap(host_virt, cmd->length);
}
@@ -576,7 +576,7 @@ static int create_bind(PVRDMADev *dev, union pvrdma_cmd_req *req,
pr_dbg("index=%d\n", cmd->index);
- if (cmd->index > MAX_PORT_GIDS) {
+ if (cmd->index >= MAX_PORT_GIDS) {
return -EINVAL;
}
@@ -603,7 +603,11 @@ static int destroy_bind(PVRDMADev *dev, union pvrdma_cmd_req *req,
{
struct pvrdma_cmd_destroy_bind *cmd = &req->destroy_bind;
- pr_dbg("clear index %d\n", cmd->index);
+ pr_dbg("index=%d\n", cmd->index);
+
+ if (cmd->index >= MAX_PORT_GIDS) {
+ return -EINVAL;
+ }
memset(dev->rdma_dev_res.ports[0].gid_tbl[cmd->index].raw, 0,
sizeof(dev->rdma_dev_res.ports[0].gid_tbl[cmd->index].raw));
diff --git a/hw/rdma/vmw/pvrdma_main.c b/hw/rdma/vmw/pvrdma_main.c
index c552248c90..3ed7409763 100644
--- a/hw/rdma/vmw/pvrdma_main.c
+++ b/hw/rdma/vmw/pvrdma_main.c
@@ -275,15 +275,6 @@ static void init_dsr_dev_caps(PVRDMADev *dev)
pr_dbg("Initialized\n");
}
-static void free_ports(PVRDMADev *dev)
-{
- int i;
-
- for (i = 0; i < MAX_PORTS; i++) {
- g_free(dev->rdma_dev_res.ports[i].gid_tbl);
- }
-}
-
static void init_ports(PVRDMADev *dev, Error **errp)
{
int i;
@@ -292,10 +283,6 @@ static void init_ports(PVRDMADev *dev, Error **errp)
for (i = 0; i < MAX_PORTS; i++) {
dev->rdma_dev_res.ports[i].state = IBV_PORT_DOWN;
-
- dev->rdma_dev_res.ports[i].pkey_tbl =
- g_malloc0(sizeof(*dev->rdma_dev_res.ports[i].pkey_tbl) *
- MAX_PORT_PKEYS);
}
}
@@ -462,14 +449,14 @@ static void init_bars(PCIDevice *pdev)
/* BAR 1 - Registers */
memset(&dev->regs_data, 0, sizeof(dev->regs_data));
memory_region_init_io(&dev->regs, OBJECT(dev), &regs_ops, dev,
- "pvrdma-regs", RDMA_BAR1_REGS_SIZE);
+ "pvrdma-regs", sizeof(dev->regs_data));
pci_register_bar(pdev, RDMA_REG_BAR_IDX, PCI_BASE_ADDRESS_SPACE_MEMORY,
&dev->regs);
/* BAR 2 - UAR */
memset(&dev->uar_data, 0, sizeof(dev->uar_data));
memory_region_init_io(&dev->uar, OBJECT(dev), &uar_ops, dev, "rdma-uar",
- RDMA_BAR2_UAR_SIZE);
+ sizeof(dev->uar_data));
pci_register_bar(pdev, RDMA_UAR_BAR_IDX, PCI_BASE_ADDRESS_SPACE_MEMORY,
&dev->uar);
}
@@ -622,8 +609,6 @@ static void pvrdma_exit(PCIDevice *pdev)
pvrdma_qp_ops_fini();
- free_ports(dev);
-
rdma_rm_fini(&dev->rdma_dev_res);
rdma_backend_fini(&dev->backend_dev);
diff --git a/hw/rdma/vmw/pvrdma_qp_ops.c b/hw/rdma/vmw/pvrdma_qp_ops.c
index 750ade6c31..99bb51111e 100644
--- a/hw/rdma/vmw/pvrdma_qp_ops.c
+++ b/hw/rdma/vmw/pvrdma_qp_ops.c
@@ -216,6 +216,7 @@ void pvrdma_cq_poll(RdmaDeviceResources *dev_res, uint32_t cq_handle)
cq = rdma_rm_get_cq(dev_res, cq_handle);
if (!cq) {
pr_dbg("Invalid CQ# %d\n", cq_handle);
+ return;
}
rdma_backend_poll_cq(dev_res, &cq->backend_cq);
diff --git a/include/elf.h b/include/elf.h
index c0dc9bb5fd..934dbbd6b3 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -1483,6 +1483,7 @@ typedef struct elf64_shdr {
#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */
#define ELFOSABI_MODESTO 11 /* Novell Modesto. */
#define ELFOSABI_OPENBSD 12 /* OpenBSD. */
+#define ELFOSABI_ARM_FDPIC 65 /* ARM FDPIC */
#define ELFOSABI_ARM 97 /* ARM */
#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */
diff --git a/include/exec/user/abitypes.h b/include/exec/user/abitypes.h
index ba188608c2..743b8bb9ea 100644
--- a/include/exec/user/abitypes.h
+++ b/include/exec/user/abitypes.h
@@ -15,7 +15,7 @@
#define ABI_LLONG_ALIGNMENT 2
#endif
-#if defined(TARGET_I386) && !defined(TARGET_X86_64)
+#if (defined(TARGET_I386) && !defined(TARGET_X86_64)) || defined(TARGET_SH4)
#define ABI_LLONG_ALIGNMENT 4
#endif
diff --git a/include/hw/misc/macio/macio.h b/include/hw/misc/macio/macio.h
index 64a2584a77..838eaf1db0 100644
--- a/include/hw/misc/macio/macio.h
+++ b/include/hw/misc/macio/macio.h
@@ -71,7 +71,6 @@ typedef struct NewWorldMacIOState {
/*< public >*/
OpenPICState *pic;
- qemu_irq irqs[7];
MACIOIDEState ide[2];
} NewWorldMacIOState;
diff --git a/include/hw/pci-host/uninorth.h b/include/hw/pci-host/uninorth.h
index f0e6836c76..f6654bad9b 100644
--- a/include/hw/pci-host/uninorth.h
+++ b/include/hw/pci-host/uninorth.h
@@ -53,4 +53,15 @@ typedef struct UNINHostState {
MemoryRegion pci_io;
} UNINHostState;
+typedef struct UNINState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion mem;
+ int token[1];
+} UNINState;
+
+#define TYPE_UNI_NORTH "uni-north"
+#define UNI_NORTH(obj) \
+ OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH)
+
#endif /* UNINORTH_H */
diff --git a/include/hw/ppc/spapr_cpu_core.h b/include/hw/ppc/spapr_cpu_core.h
index 1129f344aa..47dcfda12b 100644
--- a/include/hw/ppc/spapr_cpu_core.h
+++ b/include/hw/ppc/spapr_cpu_core.h
@@ -12,6 +12,7 @@
#include "hw/qdev.h"
#include "hw/cpu/core.h"
#include "target/ppc/cpu-qom.h"
+#include "target/ppc/cpu.h"
#define TYPE_SPAPR_CPU_CORE "spapr-cpu-core"
#define SPAPR_CPU_CORE(obj) \
@@ -38,4 +39,6 @@ typedef struct sPAPRCPUCoreClass {
} sPAPRCPUCoreClass;
const char *spapr_get_cpu_core_type(const char *cpu_type);
+void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip, target_ulong r3);
+
#endif
diff --git a/linux-user/Makefile.objs b/linux-user/Makefile.objs
index 8c93058100..59a5c17354 100644
--- a/linux-user/Makefile.objs
+++ b/linux-user/Makefile.objs
@@ -1,6 +1,7 @@
obj-y = main.o syscall.o strace.o mmap.o signal.o \
elfload.o linuxload.o uaccess.o uname.o \
- safe-syscall.o
+ safe-syscall.o $(TARGET_ABI_DIR)/signal.o \
+ $(TARGET_ABI_DIR)/cpu_loop.o
obj-$(TARGET_HAS_BFLT) += flatload.o
obj-$(TARGET_I386) += vm86.o
diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c
new file mode 100644
index 0000000000..c97a646546
--- /dev/null
+++ b/linux-user/aarch64/cpu_loop.c
@@ -0,0 +1,182 @@
+/*
+ * qemu user cpu loop
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "cpu_loop-common.h"
+
+#define get_user_code_u32(x, gaddr, env) \
+ ({ abi_long __r = get_user_u32((x), (gaddr)); \
+ if (!__r && bswap_code(arm_sctlr_b(env))) { \
+ (x) = bswap32(x); \
+ } \
+ __r; \
+ })
+
+#define get_user_code_u16(x, gaddr, env) \
+ ({ abi_long __r = get_user_u16((x), (gaddr)); \
+ if (!__r && bswap_code(arm_sctlr_b(env))) { \
+ (x) = bswap16(x); \
+ } \
+ __r; \
+ })
+
+#define get_user_data_u32(x, gaddr, env) \
+ ({ abi_long __r = get_user_u32((x), (gaddr)); \
+ if (!__r && arm_cpu_bswap_data(env)) { \
+ (x) = bswap32(x); \
+ } \
+ __r; \
+ })
+
+#define get_user_data_u16(x, gaddr, env) \
+ ({ abi_long __r = get_user_u16((x), (gaddr)); \
+ if (!__r && arm_cpu_bswap_data(env)) { \
+ (x) = bswap16(x); \
+ } \
+ __r; \
+ })
+
+#define put_user_data_u32(x, gaddr, env) \
+ ({ typeof(x) __x = (x); \
+ if (arm_cpu_bswap_data(env)) { \
+ __x = bswap32(__x); \
+ } \
+ put_user_u32(__x, (gaddr)); \
+ })
+
+#define put_user_data_u16(x, gaddr, env) \
+ ({ typeof(x) __x = (x); \
+ if (arm_cpu_bswap_data(env)) { \
+ __x = bswap16(__x); \
+ } \
+ put_user_u16(__x, (gaddr)); \
+ })
+
+/* AArch64 main loop */
+void cpu_loop(CPUARMState *env)
+{
+ CPUState *cs = CPU(arm_env_get_cpu(env));
+ int trapnr, sig;
+ abi_long ret;
+ target_siginfo_t info;
+
+ for (;;) {
+ cpu_exec_start(cs);
+ trapnr = cpu_exec(cs);
+ cpu_exec_end(cs);
+ process_queued_cpu_work(cs);
+
+ switch (trapnr) {
+ case EXCP_SWI:
+ ret = do_syscall(env,
+ env->xregs[8],
+ env->xregs[0],
+ env->xregs[1],
+ env->xregs[2],
+ env->xregs[3],
+ env->xregs[4],
+ env->xregs[5],
+ 0, 0);
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->pc -= 4;
+ } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+ env->xregs[0] = ret;
+ }
+ break;
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+ case EXCP_UDEF:
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_ILLOPN;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_PREFETCH_ABORT:
+ case EXCP_DATA_ABORT:
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ /* XXX: check env->error_code */
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = env->exception.vaddress;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_DEBUG:
+ case EXCP_BKPT:
+ sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+ if (sig) {
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+ break;
+ case EXCP_SEMIHOST:
+ env->xregs[0] = do_arm_semihosting(env);
+ break;
+ case EXCP_YIELD:
+ /* nothing to do here for user-mode, just resume guest code */
+ break;
+ case EXCP_ATOMIC:
+ cpu_exec_step_atomic(cs);
+ break;
+ default:
+ EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
+ abort();
+ }
+ process_pending_signals(env);
+ /* Exception return on AArch64 always clears the exclusive monitor,
+ * so any return to running guest code implies this.
+ */
+ env->exclusive_addr = -1;
+ }
+}
+
+void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
+{
+ CPUState *cpu = ENV_GET_CPU(env);
+ TaskState *ts = cpu->opaque;
+ struct image_info *info = ts->info;
+ int i;
+
+ if (!(arm_feature(env, ARM_FEATURE_AARCH64))) {
+ fprintf(stderr,
+ "The selected ARM CPU does not support 64 bit mode\n");
+ exit(EXIT_FAILURE);
+ }
+
+ for (i = 0; i < 31; i++) {
+ env->xregs[i] = regs->regs[i];
+ }
+ env->pc = regs->pc;
+ env->xregs[31] = regs->sp;
+#ifdef TARGET_WORDS_BIGENDIAN
+ env->cp15.sctlr_el[1] |= SCTLR_E0E;
+ for (i = 1; i < 4; ++i) {
+ env->cp15.sctlr_el[i] |= SCTLR_EE;
+ }
+#endif
+
+ ts->stack_base = info->start_stack;
+ ts->heap_base = info->brk;
+ /* This will be filled in on the first SYS_HEAPINFO call. */
+ ts->heap_limit = 0;
+}
diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c
new file mode 100644
index 0000000000..f95dc61dfb
--- /dev/null
+++ b/linux-user/aarch64/signal.c
@@ -0,0 +1,577 @@
+/*
+ * Emulation of Linux signals
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "target_signal.h"
+#include "signal-common.h"
+#include "linux-user/trace.h"
+
+struct target_sigcontext {
+ uint64_t fault_address;
+ /* AArch64 registers */
+ uint64_t regs[31];
+ uint64_t sp;
+ uint64_t pc;
+ uint64_t pstate;
+ /* 4K reserved for FP/SIMD state and future expansion */
+ char __reserved[4096] __attribute__((__aligned__(16)));
+};
+
+struct target_ucontext {
+ abi_ulong tuc_flags;
+ abi_ulong tuc_link;
+ target_stack_t tuc_stack;
+ target_sigset_t tuc_sigmask;
+ /* glibc uses a 1024-bit sigset_t */
+ char __unused[1024 / 8 - sizeof(target_sigset_t)];
+ /* last for future expansion */
+ struct target_sigcontext tuc_mcontext;
+};
+
+/*
+ * Header to be used at the beginning of structures extending the user
+ * context. Such structures must be placed after the rt_sigframe on the stack
+ * and be 16-byte aligned. The last structure must be a dummy one with the
+ * magic and size set to 0.
+ */
+struct target_aarch64_ctx {
+ uint32_t magic;
+ uint32_t size;
+};
+
+#define TARGET_FPSIMD_MAGIC 0x46508001
+
+struct target_fpsimd_context {
+ struct target_aarch64_ctx head;
+ uint32_t fpsr;
+ uint32_t fpcr;
+ uint64_t vregs[32 * 2]; /* really uint128_t vregs[32] */
+};
+
+#define TARGET_EXTRA_MAGIC 0x45585401
+
+struct target_extra_context {
+ struct target_aarch64_ctx head;
+ uint64_t datap; /* 16-byte aligned pointer to extra space cast to __u64 */
+ uint32_t size; /* size in bytes of the extra space */
+ uint32_t reserved[3];
+};
+
+#define TARGET_SVE_MAGIC 0x53564501
+
+struct target_sve_context {
+ struct target_aarch64_ctx head;
+ uint16_t vl;
+ uint16_t reserved[3];
+ /* The actual SVE data immediately follows. It is layed out
+ * according to TARGET_SVE_SIG_{Z,P}REG_OFFSET, based off of
+ * the original struct pointer.
+ */
+};
+
+#define TARGET_SVE_VQ_BYTES 16
+
+#define TARGET_SVE_SIG_ZREG_SIZE(VQ) ((VQ) * TARGET_SVE_VQ_BYTES)
+#define TARGET_SVE_SIG_PREG_SIZE(VQ) ((VQ) * (TARGET_SVE_VQ_BYTES / 8))
+
+#define TARGET_SVE_SIG_REGS_OFFSET \
+ QEMU_ALIGN_UP(sizeof(struct target_sve_context), TARGET_SVE_VQ_BYTES)
+#define TARGET_SVE_SIG_ZREG_OFFSET(VQ, N) \
+ (TARGET_SVE_SIG_REGS_OFFSET + TARGET_SVE_SIG_ZREG_SIZE(VQ) * (N))
+#define TARGET_SVE_SIG_PREG_OFFSET(VQ, N) \
+ (TARGET_SVE_SIG_ZREG_OFFSET(VQ, 32) + TARGET_SVE_SIG_PREG_SIZE(VQ) * (N))
+#define TARGET_SVE_SIG_FFR_OFFSET(VQ) \
+ (TARGET_SVE_SIG_PREG_OFFSET(VQ, 16))
+#define TARGET_SVE_SIG_CONTEXT_SIZE(VQ) \
+ (TARGET_SVE_SIG_PREG_OFFSET(VQ, 17))
+
+struct target_rt_sigframe {
+ struct target_siginfo info;
+ struct target_ucontext uc;
+};
+
+struct target_rt_frame_record {
+ uint64_t fp;
+ uint64_t lr;
+ uint32_t tramp[2];
+};
+
+static void target_setup_general_frame(struct target_rt_sigframe *sf,
+ CPUARMState *env, target_sigset_t *set)
+{
+ int i;
+
+ __put_user(0, &sf->uc.tuc_flags);
+ __put_user(0, &sf->uc.tuc_link);
+
+ target_save_altstack(&sf->uc.tuc_stack, env);
+
+ for (i = 0; i < 31; i++) {
+ __put_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
+ }
+ __put_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
+ __put_user(env->pc, &sf->uc.tuc_mcontext.pc);
+ __put_user(pstate_read(env), &sf->uc.tuc_mcontext.pstate);
+
+ __put_user(env->exception.vaddress, &sf->uc.tuc_mcontext.fault_address);
+
+ for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+ __put_user(set->sig[i], &sf->uc.tuc_sigmask.sig[i]);
+ }
+}
+
+static void target_setup_fpsimd_record(struct target_fpsimd_context *fpsimd,
+ CPUARMState *env)
+{
+ int i;
+
+ __put_user(TARGET_FPSIMD_MAGIC, &fpsimd->head.magic);
+ __put_user(sizeof(struct target_fpsimd_context), &fpsimd->head.size);
+ __put_user(vfp_get_fpsr(env), &fpsimd->fpsr);
+ __put_user(vfp_get_fpcr(env), &fpsimd->fpcr);
+
+ for (i = 0; i < 32; i++) {
+ uint64_t *q = aa64_vfp_qreg(env, i);
+#ifdef TARGET_WORDS_BIGENDIAN
+ __put_user(q[0], &fpsimd->vregs[i * 2 + 1]);
+ __put_user(q[1], &fpsimd->vregs[i * 2]);
+#else
+ __put_user(q[0], &fpsimd->vregs[i * 2]);
+ __put_user(q[1], &fpsimd->vregs[i * 2 + 1]);
+#endif
+ }
+}
+
+static void target_setup_extra_record(struct target_extra_context *extra,
+ uint64_t datap, uint32_t extra_size)
+{
+ __put_user(TARGET_EXTRA_MAGIC, &extra->head.magic);
+ __put_user(sizeof(struct target_extra_context), &extra->head.size);
+ __put_user(datap, &extra->datap);
+ __put_user(extra_size, &extra->size);
+}
+
+static void target_setup_end_record(struct target_aarch64_ctx *end)
+{
+ __put_user(0, &end->magic);
+ __put_user(0, &end->size);
+}
+
+static void target_setup_sve_record(struct target_sve_context *sve,
+ CPUARMState *env, int vq, int size)
+{
+ int i, j;
+
+ __put_user(TARGET_SVE_MAGIC, &sve->head.magic);
+ __put_user(size, &sve->head.size);
+ __put_user(vq * TARGET_SVE_VQ_BYTES, &sve->vl);
+
+ /* Note that SVE regs are stored as a byte stream, with each byte element
+ * at a subsequent address. This corresponds to a little-endian store
+ * of our 64-bit hunks.
+ */
+ for (i = 0; i < 32; ++i) {
+ uint64_t *z = (void *)sve + TARGET_SVE_SIG_ZREG_OFFSET(vq, i);
+ for (j = 0; j < vq * 2; ++j) {
+ __put_user_e(env->vfp.zregs[i].d[j], z + j, le);
+ }
+ }
+ for (i = 0; i <= 16; ++i) {
+ uint16_t *p = (void *)sve + TARGET_SVE_SIG_PREG_OFFSET(vq, i);
+ for (j = 0; j < vq; ++j) {
+ uint64_t r = env->vfp.pregs[i].p[j >> 2];
+ __put_user_e(r >> ((j & 3) * 16), p + j, le);
+ }
+ }
+}
+
+static void target_restore_general_frame(CPUARMState *env,
+ struct target_rt_sigframe *sf)
+{
+ sigset_t set;
+ uint64_t pstate;
+ int i;
+
+ target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
+ set_sigmask(&set);
+
+ for (i = 0; i < 31; i++) {
+ __get_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
+ }
+
+ __get_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
+ __get_user(env->pc, &sf->uc.tuc_mcontext.pc);
+ __get_user(pstate, &sf->uc.tuc_mcontext.pstate);
+ pstate_write(env, pstate);
+}
+
+static void target_restore_fpsimd_record(CPUARMState *env,
+ struct target_fpsimd_context *fpsimd)
+{
+ uint32_t fpsr, fpcr;
+ int i;
+
+ __get_user(fpsr, &fpsimd->fpsr);
+ vfp_set_fpsr(env, fpsr);
+ __get_user(fpcr, &fpsimd->fpcr);
+ vfp_set_fpcr(env, fpcr);
+
+ for (i = 0; i < 32; i++) {
+ uint64_t *q = aa64_vfp_qreg(env, i);
+#ifdef TARGET_WORDS_BIGENDIAN
+ __get_user(q[0], &fpsimd->vregs[i * 2 + 1]);
+ __get_user(q[1], &fpsimd->vregs[i * 2]);
+#else
+ __get_user(q[0], &fpsimd->vregs[i * 2]);
+ __get_user(q[1], &fpsimd->vregs[i * 2 + 1]);
+#endif
+ }
+}
+
+static void target_restore_sve_record(CPUARMState *env,
+ struct target_sve_context *sve, int vq)
+{
+ int i, j;
+
+ /* Note that SVE regs are stored as a byte stream, with each byte element
+ * at a subsequent address. This corresponds to a little-endian load
+ * of our 64-bit hunks.
+ */
+ for (i = 0; i < 32; ++i) {
+ uint64_t *z = (void *)sve + TARGET_SVE_SIG_ZREG_OFFSET(vq, i);
+ for (j = 0; j < vq * 2; ++j) {
+ __get_user_e(env->vfp.zregs[i].d[j], z + j, le);
+ }
+ }
+ for (i = 0; i <= 16; ++i) {
+ uint16_t *p = (void *)sve + TARGET_SVE_SIG_PREG_OFFSET(vq, i);
+ for (j = 0; j < vq; ++j) {
+ uint16_t r;
+ __get_user_e(r, p + j, le);
+ if (j & 3) {
+ env->vfp.pregs[i].p[j >> 2] |= (uint64_t)r << ((j & 3) * 16);
+ } else {
+ env->vfp.pregs[i].p[j >> 2] = r;
+ }
+ }
+ }
+}
+
+static int target_restore_sigframe(CPUARMState *env,
+ struct target_rt_sigframe *sf)
+{
+ struct target_aarch64_ctx *ctx, *extra = NULL;
+ struct target_fpsimd_context *fpsimd = NULL;
+ struct target_sve_context *sve = NULL;
+ uint64_t extra_datap = 0;
+ bool used_extra = false;
+ bool err = false;
+ int vq = 0, sve_size = 0;
+
+ target_restore_general_frame(env, sf);
+
+ ctx = (struct target_aarch64_ctx *)sf->uc.tuc_mcontext.__reserved;
+ while (ctx) {
+ uint32_t magic, size, extra_size;
+
+ __get_user(magic, &ctx->magic);
+ __get_user(size, &ctx->size);
+ switch (magic) {
+ case 0:
+ if (size != 0) {
+ err = true;
+ goto exit;
+ }
+ if (used_extra) {
+ ctx = NULL;
+ } else {
+ ctx = extra;
+ used_extra = true;
+ }
+ continue;
+
+ case TARGET_FPSIMD_MAGIC:
+ if (fpsimd || size != sizeof(struct target_fpsimd_context)) {
+ err = true;
+ goto exit;
+ }
+ fpsimd = (struct target_fpsimd_context *)ctx;
+ break;
+
+ case TARGET_SVE_MAGIC:
+ if (arm_feature(env, ARM_FEATURE_SVE)) {
+ vq = (env->vfp.zcr_el[1] & 0xf) + 1;
+ sve_size = QEMU_ALIGN_UP(TARGET_SVE_SIG_CONTEXT_SIZE(vq), 16);
+ if (!sve && size == sve_size) {
+ sve = (struct target_sve_context *)ctx;
+ break;
+ }
+ }
+ err = true;
+ goto exit;
+
+ case TARGET_EXTRA_MAGIC:
+ if (extra || size != sizeof(struct target_extra_context)) {
+ err = true;
+ goto exit;
+ }
+ __get_user(extra_datap,
+ &((struct target_extra_context *)ctx)->datap);
+ __get_user(extra_size,
+ &((struct target_extra_context *)ctx)->size);
+ extra = lock_user(VERIFY_READ, extra_datap, extra_size, 0);
+ break;
+
+ default:
+ /* Unknown record -- we certainly didn't generate it.
+ * Did we in fact get out of sync?
+ */
+ err = true;
+ goto exit;
+ }
+ ctx = (void *)ctx + size;
+ }
+
+ /* Require FPSIMD always. */
+ if (fpsimd) {
+ target_restore_fpsimd_record(env, fpsimd);
+ } else {
+ err = true;
+ }
+
+ /* SVE data, if present, overwrites FPSIMD data. */
+ if (sve) {
+ target_restore_sve_record(env, sve, vq);
+ }
+
+ exit:
+ unlock_user(extra, extra_datap, 0);
+ return err;
+}
+
+static abi_ulong get_sigframe(struct target_sigaction *ka,
+ CPUARMState *env, int size)
+{
+ abi_ulong sp;
+
+ sp = target_sigsp(get_sp_from_cpustate(env), ka);
+
+ sp = (sp - size) & ~15;
+
+ return sp;
+}
+
+typedef struct {
+ int total_size;
+ int extra_base;
+ int extra_size;
+ int std_end_ofs;
+ int extra_ofs;
+ int extra_end_ofs;
+} target_sigframe_layout;
+
+static int alloc_sigframe_space(int this_size, target_sigframe_layout *l)
+{
+ /* Make sure there will always be space for the end marker. */
+ const int std_size = sizeof(struct target_rt_sigframe)
+ - sizeof(struct target_aarch64_ctx);
+ int this_loc = l->total_size;
+
+ if (l->extra_base) {
+ /* Once we have begun an extra space, all allocations go there. */
+ l->extra_size += this_size;
+ } else if (this_size + this_loc > std_size) {
+ /* This allocation does not fit in the standard space. */
+ /* Allocate the extra record. */
+ l->extra_ofs = this_loc;
+ l->total_size += sizeof(struct target_extra_context);
+
+ /* Allocate the standard end record. */
+ l->std_end_ofs = l->total_size;
+ l->total_size += sizeof(struct target_aarch64_ctx);
+
+ /* Allocate the requested record. */
+ l->extra_base = this_loc = l->total_size;
+ l->extra_size = this_size;
+ }
+ l->total_size += this_size;
+
+ return this_loc;
+}
+
+static void target_setup_frame(int usig, struct target_sigaction *ka,
+ target_siginfo_t *info, target_sigset_t *set,
+ CPUARMState *env)
+{
+ target_sigframe_layout layout = {
+ /* Begin with the size pointing to the reserved space. */
+ .total_size = offsetof(struct target_rt_sigframe,
+ uc.tuc_mcontext.__reserved),
+ };
+ int fpsimd_ofs, fr_ofs, sve_ofs = 0, vq = 0, sve_size = 0;
+ struct target_rt_sigframe *frame;
+ struct target_rt_frame_record *fr;
+ abi_ulong frame_addr, return_addr;
+
+ /* FPSIMD record is always in the standard space. */
+ fpsimd_ofs = alloc_sigframe_space(sizeof(struct target_fpsimd_context),
+ &layout);
+
+ /* SVE state needs saving only if it exists. */
+ if (arm_feature(env, ARM_FEATURE_SVE)) {
+ vq = (env->vfp.zcr_el[1] & 0xf) + 1;
+ sve_size = QEMU_ALIGN_UP(TARGET_SVE_SIG_CONTEXT_SIZE(vq), 16);
+ sve_ofs = alloc_sigframe_space(sve_size, &layout);
+ }
+
+ if (layout.extra_ofs) {
+ /* Reserve space for the extra end marker. The standard end marker
+ * will have been allocated when we allocated the extra record.
+ */
+ layout.extra_end_ofs
+ = alloc_sigframe_space(sizeof(struct target_aarch64_ctx), &layout);
+ } else {
+ /* Reserve space for the standard end marker.
+ * Do not use alloc_sigframe_space because we cheat
+ * std_size therein to reserve space for this.
+ */
+ layout.std_end_ofs = layout.total_size;
+ layout.total_size += sizeof(struct target_aarch64_ctx);
+ }
+
+ /* We must always provide at least the standard 4K reserved space,
+ * even if we don't use all of it (this is part of the ABI)
+ */
+ layout.total_size = MAX(layout.total_size,
+ sizeof(struct target_rt_sigframe));
+
+ /* Reserve space for the return code. On a real system this would
+ * be within the VDSO. So, despite the name this is not a "real"
+ * record within the frame.
+ */
+ fr_ofs = layout.total_size;
+ layout.total_size += sizeof(struct target_rt_frame_record);
+
+ frame_addr = get_sigframe(ka, env, layout.total_size);
+ trace_user_setup_frame(env, frame_addr);
+ frame = lock_user(VERIFY_WRITE, frame_addr, layout.total_size, 0);
+ if (!frame) {
+ goto give_sigsegv;
+ }
+
+ target_setup_general_frame(frame, env, set);
+ target_setup_fpsimd_record((void *)frame + fpsimd_ofs, env);
+ target_setup_end_record((void *)frame + layout.std_end_ofs);
+ if (layout.extra_ofs) {
+ target_setup_extra_record((void *)frame + layout.extra_ofs,
+ frame_addr + layout.extra_base,
+ layout.extra_size);
+ target_setup_end_record((void *)frame + layout.extra_end_ofs);
+ }
+ if (sve_ofs) {
+ target_setup_sve_record((void *)frame + sve_ofs, env, vq, sve_size);
+ }
+
+ /* Set up the stack frame for unwinding. */
+ fr = (void *)frame + fr_ofs;
+ __put_user(env->xregs[29], &fr->fp);
+ __put_user(env->xregs[30], &fr->lr);
+
+ if (ka->sa_flags & TARGET_SA_RESTORER) {
+ return_addr = ka->sa_restorer;
+ } else {
+ /*
+ * mov x8,#__NR_rt_sigreturn; svc #0
+ * Since these are instructions they need to be put as little-endian
+ * regardless of target default or current CPU endianness.
+ */
+ __put_user_e(0xd2801168, &fr->tramp[0], le);
+ __put_user_e(0xd4000001, &fr->tramp[1], le);
+ return_addr = frame_addr + fr_ofs
+ + offsetof(struct target_rt_frame_record, tramp);
+ }
+ env->xregs[0] = usig;
+ env->xregs[31] = frame_addr;
+ env->xregs[29] = frame_addr + fr_ofs;
+ env->pc = ka->_sa_handler;
+ env->xregs[30] = return_addr;
+ if (info) {
+ tswap_siginfo(&frame->info, info);
+ env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
+ env->xregs[2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
+ }
+
+ unlock_user(frame, frame_addr, layout.total_size);
+ return;
+
+ give_sigsegv:
+ unlock_user(frame, frame_addr, layout.total_size);
+ force_sigsegv(usig);
+}
+
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+ target_siginfo_t *info, target_sigset_t *set,
+ CPUARMState *env)
+{
+ target_setup_frame(sig, ka, info, set, env);
+}
+
+void setup_frame(int sig, struct target_sigaction *ka,
+ target_sigset_t *set, CPUARMState *env)
+{
+ target_setup_frame(sig, ka, 0, set, env);
+}
+
+long do_rt_sigreturn(CPUARMState *env)
+{
+ struct target_rt_sigframe *frame = NULL;
+ abi_ulong frame_addr = env->xregs[31];
+
+ trace_user_do_rt_sigreturn(env, frame_addr);
+ if (frame_addr & 15) {
+ goto badframe;
+ }
+
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+ goto badframe;
+ }
+
+ if (target_restore_sigframe(env, frame)) {
+ goto badframe;
+ }
+
+ if (do_sigaltstack(frame_addr +
+ offsetof(struct target_rt_sigframe, uc.tuc_stack),
+ 0, get_sp_from_cpustate(env)) == -EFAULT) {
+ goto badframe;
+ }
+
+ unlock_user_struct(frame, frame_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+
+ badframe:
+ unlock_user_struct(frame, frame_addr, 0);
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
+
+long do_sigreturn(CPUARMState *env)
+{
+ return do_rt_sigreturn(env);
+}
diff --git a/linux-user/aarch64/target_signal.h b/linux-user/aarch64/target_signal.h
index e66367cac1..0b7ae25120 100644
--- a/linux-user/aarch64/target_signal.h
+++ b/linux-user/aarch64/target_signal.h
@@ -26,4 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUARMState *state)
return state->xregs[31];
}
+#define TARGET_ARCH_HAS_SETUP_FRAME
#endif /* AARCH64_TARGET_SIGNAL_H */
diff --git a/linux-user/alpha/cpu_loop.c b/linux-user/alpha/cpu_loop.c
new file mode 100644
index 0000000000..b87fcaea87
--- /dev/null
+++ b/linux-user/alpha/cpu_loop.c
@@ -0,0 +1,225 @@
+/*
+ * qemu user cpu loop
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "cpu_loop-common.h"
+
+void cpu_loop(CPUAlphaState *env)
+{
+ CPUState *cs = CPU(alpha_env_get_cpu(env));
+ int trapnr;
+ target_siginfo_t info;
+ abi_long sysret;
+
+ while (1) {
+ bool arch_interrupt = true;
+
+ cpu_exec_start(cs);
+ trapnr = cpu_exec(cs);
+ cpu_exec_end(cs);
+ process_queued_cpu_work(cs);
+
+ switch (trapnr) {
+ case EXCP_RESET:
+ fprintf(stderr, "Reset requested. Exit\n");
+ exit(EXIT_FAILURE);
+ break;
+ case EXCP_MCHK:
+ fprintf(stderr, "Machine check exception. Exit\n");
+ exit(EXIT_FAILURE);
+ break;
+ case EXCP_SMP_INTERRUPT:
+ case EXCP_CLK_INTERRUPT:
+ case EXCP_DEV_INTERRUPT:
+ fprintf(stderr, "External interrupt. Exit\n");
+ exit(EXIT_FAILURE);
+ break;
+ case EXCP_MMFAULT:
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = (page_get_flags(env->trap_arg0) & PAGE_VALID
+ ? TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR);
+ info._sifields._sigfault._addr = env->trap_arg0;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_UNALIGN:
+ info.si_signo = TARGET_SIGBUS;
+ info.si_errno = 0;
+ info.si_code = TARGET_BUS_ADRALN;
+ info._sifields._sigfault._addr = env->trap_arg0;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_OPCDEC:
+ do_sigill:
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_ILLOPC;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_ARITH:
+ info.si_signo = TARGET_SIGFPE;
+ info.si_errno = 0;
+ info.si_code = TARGET_FPE_FLTINV;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_FEN:
+ /* No-op. Linux simply re-enables the FPU. */
+ break;
+ case EXCP_CALL_PAL:
+ switch (env->error_code) {
+ case 0x80:
+ /* BPT */
+ info.si_signo = TARGET_SIGTRAP;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case 0x81:
+ /* BUGCHK */
+ info.si_signo = TARGET_SIGTRAP;
+ info.si_errno = 0;
+ info.si_code = 0;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case 0x83:
+ /* CALLSYS */
+ trapnr = env->ir[IR_V0];
+ sysret = do_syscall(env, trapnr,
+ env->ir[IR_A0], env->ir[IR_A1],
+ env->ir[IR_A2], env->ir[IR_A3],
+ env->ir[IR_A4], env->ir[IR_A5],
+ 0, 0);
+ if (sysret == -TARGET_ERESTARTSYS) {
+ env->pc -= 4;
+ break;
+ }
+ if (sysret == -TARGET_QEMU_ESIGRETURN) {
+ break;
+ }
+ /* Syscall writes 0 to V0 to bypass error check, similar
+ to how this is handled internal to Linux kernel.
+ (Ab)use trapnr temporarily as boolean indicating error. */
+ trapnr = (env->ir[IR_V0] != 0 && sysret < 0);
+ env->ir[IR_V0] = (trapnr ? -sysret : sysret);
+ env->ir[IR_A3] = trapnr;
+ break;
+ case 0x86:
+ /* IMB */
+ /* ??? We can probably elide the code using page_unprotect
+ that is checking for self-modifying code. Instead we
+ could simply call tb_flush here. Until we work out the
+ changes required to turn off the extra write protection,
+ this can be a no-op. */
+ break;
+ case 0x9E:
+ /* RDUNIQUE */
+ /* Handled in the translator for usermode. */
+ abort();
+ case 0x9F:
+ /* WRUNIQUE */
+ /* Handled in the translator for usermode. */
+ abort();
+ case 0xAA:
+ /* GENTRAP */
+ info.si_signo = TARGET_SIGFPE;
+ switch (env->ir[IR_A0]) {
+ case TARGET_GEN_INTOVF:
+ info.si_code = TARGET_FPE_INTOVF;
+ break;
+ case TARGET_GEN_INTDIV:
+ info.si_code = TARGET_FPE_INTDIV;
+ break;
+ case TARGET_GEN_FLTOVF:
+ info.si_code = TARGET_FPE_FLTOVF;
+ break;
+ case TARGET_GEN_FLTUND:
+ info.si_code = TARGET_FPE_FLTUND;
+ break;
+ case TARGET_GEN_FLTINV:
+ info.si_code = TARGET_FPE_FLTINV;
+ break;
+ case TARGET_GEN_FLTINE:
+ info.si_code = TARGET_FPE_FLTRES;
+ break;
+ case TARGET_GEN_ROPRAND:
+ info.si_code = 0;
+ break;
+ default:
+ info.si_signo = TARGET_SIGTRAP;
+ info.si_code = 0;
+ break;
+ }
+ info.si_errno = 0;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ default:
+ goto do_sigill;
+ }
+ break;
+ case EXCP_DEBUG:
+ info.si_signo = gdb_handlesig(cs, TARGET_SIGTRAP);
+ if (info.si_signo) {
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ } else {
+ arch_interrupt = false;
+ }
+ break;
+ case EXCP_INTERRUPT:
+ /* Just indicate that signals should be handled asap. */
+ break;
+ case EXCP_ATOMIC:
+ cpu_exec_step_atomic(cs);
+ arch_interrupt = false;
+ break;
+ default:
+ printf ("Unhandled trap: 0x%x\n", trapnr);
+ cpu_dump_state(cs, stderr, fprintf, 0);
+ exit(EXIT_FAILURE);
+ }
+ process_pending_signals (env);
+
+ /* Most of the traps imply a transition through PALcode, which
+ implies an REI instruction has been executed. Which means
+ that RX and LOCK_ADDR should be cleared. But there are a
+ few exceptions for traps internal to QEMU. */
+ if (arch_interrupt) {
+ env->flags &= ~ENV_FLAG_RX_FLAG;
+ env->lock_addr = -1;
+ }
+ }
+}
+
+void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
+{
+ int i;
+
+ for(i = 0; i < 28; i++) {
+ env->ir[i] = ((abi_ulong *)regs)[i];
+ }
+ env->ir[IR_SP] = regs->usp;
+ env->pc = regs->pc;
+}
diff --git a/linux-user/alpha/signal.c b/linux-user/alpha/signal.c
new file mode 100644
index 0000000000..f24de02c6f
--- /dev/null
+++ b/linux-user/alpha/signal.c
@@ -0,0 +1,275 @@
+/*
+ * Emulation of Linux signals
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "target_signal.h"
+#include "signal-common.h"
+#include "linux-user/trace.h"
+
+struct target_sigcontext {
+ abi_long sc_onstack;
+ abi_long sc_mask;
+ abi_long sc_pc;
+ abi_long sc_ps;
+ abi_long sc_regs[32];
+ abi_long sc_ownedfp;
+ abi_long sc_fpregs[32];
+ abi_ulong sc_fpcr;
+ abi_ulong sc_fp_control;
+ abi_ulong sc_reserved1;
+ abi_ulong sc_reserved2;
+ abi_ulong sc_ssize;
+ abi_ulong sc_sbase;
+ abi_ulong sc_traparg_a0;
+ abi_ulong sc_traparg_a1;
+ abi_ulong sc_traparg_a2;
+ abi_ulong sc_fp_trap_pc;
+ abi_ulong sc_fp_trigger_sum;
+ abi_ulong sc_fp_trigger_inst;
+};
+
+struct target_ucontext {
+ abi_ulong tuc_flags;
+ abi_ulong tuc_link;
+ abi_ulong tuc_osf_sigmask;
+ target_stack_t tuc_stack;
+ struct target_sigcontext tuc_mcontext;
+ target_sigset_t tuc_sigmask;
+};
+
+struct target_sigframe {
+ struct target_sigcontext sc;
+ unsigned int retcode[3];
+};
+
+struct target_rt_sigframe {
+ target_siginfo_t info;
+ struct target_ucontext uc;
+ unsigned int retcode[3];
+};
+
+#define INSN_MOV_R30_R16 0x47fe0410
+#define INSN_LDI_R0 0x201f0000
+#define INSN_CALLSYS 0x00000083
+
+static void setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env,
+ abi_ulong frame_addr, target_sigset_t *set)
+{
+ int i;
+
+ __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
+ __put_user(set->sig[0], &sc->sc_mask);
+ __put_user(env->pc, &sc->sc_pc);
+ __put_user(8, &sc->sc_ps);
+
+ for (i = 0; i < 31; ++i) {
+ __put_user(env->ir[i], &sc->sc_regs[i]);
+ }
+ __put_user(0, &sc->sc_regs[31]);
+
+ for (i = 0; i < 31; ++i) {
+ __put_user(env->fir[i], &sc->sc_fpregs[i]);
+ }
+ __put_user(0, &sc->sc_fpregs[31]);
+ __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
+
+ __put_user(0, &sc->sc_traparg_a0); /* FIXME */
+ __put_user(0, &sc->sc_traparg_a1); /* FIXME */
+ __put_user(0, &sc->sc_traparg_a2); /* FIXME */
+}
+
+static void restore_sigcontext(CPUAlphaState *env,
+ struct target_sigcontext *sc)
+{
+ uint64_t fpcr;
+ int i;
+
+ __get_user(env->pc, &sc->sc_pc);
+
+ for (i = 0; i < 31; ++i) {
+ __get_user(env->ir[i], &sc->sc_regs[i]);
+ }
+ for (i = 0; i < 31; ++i) {
+ __get_user(env->fir[i], &sc->sc_fpregs[i]);
+ }
+
+ __get_user(fpcr, &sc->sc_fpcr);
+ cpu_alpha_store_fpcr(env, fpcr);
+}
+
+static inline abi_ulong get_sigframe(struct target_sigaction *sa,
+ CPUAlphaState *env,
+ unsigned long framesize)
+{
+ abi_ulong sp;
+
+ sp = target_sigsp(get_sp_from_cpustate(env), sa);
+
+ return (sp - framesize) & -32;
+}
+
+void setup_frame(int sig, struct target_sigaction *ka,
+ target_sigset_t *set, CPUAlphaState *env)
+{
+ abi_ulong frame_addr, r26;
+ struct target_sigframe *frame;
+ int err = 0;
+
+ frame_addr = get_sigframe(ka, env, sizeof(*frame));
+ trace_user_setup_frame(env, frame_addr);
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+ goto give_sigsegv;
+ }
+
+ setup_sigcontext(&frame->sc, env, frame_addr, set);
+
+ if (ka->sa_restorer) {
+ r26 = ka->sa_restorer;
+ } else {
+ __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
+ __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
+ &frame->retcode[1]);
+ __put_user(INSN_CALLSYS, &frame->retcode[2]);
+ /* imb() */
+ r26 = frame_addr + offsetof(struct target_sigframe, retcode);
+ }
+
+ unlock_user_struct(frame, frame_addr, 1);
+
+ if (err) {
+give_sigsegv:
+ force_sigsegv(sig);
+ return;
+ }
+
+ env->ir[IR_RA] = r26;
+ env->ir[IR_PV] = env->pc = ka->_sa_handler;
+ env->ir[IR_A0] = sig;
+ env->ir[IR_A1] = 0;
+ env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
+ env->ir[IR_SP] = frame_addr;
+}
+
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPUAlphaState *env)
+{
+ abi_ulong frame_addr, r26;
+ struct target_rt_sigframe *frame;
+ int i, err = 0;
+
+ frame_addr = get_sigframe(ka, env, sizeof(*frame));
+ trace_user_setup_rt_frame(env, frame_addr);
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+ goto give_sigsegv;
+ }
+
+ tswap_siginfo(&frame->info, info);
+
+ __put_user(0, &frame->uc.tuc_flags);
+ __put_user(0, &frame->uc.tuc_link);
+ __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
+
+ target_save_altstack(&frame->uc.tuc_stack, env);
+
+ setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
+ for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
+ __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
+ }
+
+ if (ka->sa_restorer) {
+ r26 = ka->sa_restorer;
+ } else {
+ __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
+ __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
+ &frame->retcode[1]);
+ __put_user(INSN_CALLSYS, &frame->retcode[2]);
+ /* imb(); */
+ r26 = frame_addr + offsetof(struct target_sigframe, retcode);
+ }
+
+ if (err) {
+give_sigsegv:
+ force_sigsegv(sig);
+ return;
+ }
+
+ env->ir[IR_RA] = r26;
+ env->ir[IR_PV] = env->pc = ka->_sa_handler;
+ env->ir[IR_A0] = sig;
+ env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
+ env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
+ env->ir[IR_SP] = frame_addr;
+}
+
+long do_sigreturn(CPUAlphaState *env)
+{
+ struct target_sigcontext *sc;
+ abi_ulong sc_addr = env->ir[IR_A0];
+ target_sigset_t target_set;
+ sigset_t set;
+
+ if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
+ goto badframe;
+ }
+
+ target_sigemptyset(&target_set);
+ __get_user(target_set.sig[0], &sc->sc_mask);
+
+ target_to_host_sigset_internal(&set, &target_set);
+ set_sigmask(&set);
+
+ restore_sigcontext(env, sc);
+ unlock_user_struct(sc, sc_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+
+badframe:
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
+
+long do_rt_sigreturn(CPUAlphaState *env)
+{
+ abi_ulong frame_addr = env->ir[IR_A0];
+ struct target_rt_sigframe *frame;
+ sigset_t set;
+
+ trace_user_do_rt_sigreturn(env, frame_addr);
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+ goto badframe;
+ }
+ target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
+ set_sigmask(&set);
+
+ restore_sigcontext(env, &frame->uc.tuc_mcontext);
+ if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
+ uc.tuc_stack),
+ 0, env->ir[IR_SP]) == -EFAULT) {
+ goto badframe;
+ }
+
+ unlock_user_struct(frame, frame_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+
+
+badframe:
+ unlock_user_struct(frame, frame_addr, 0);
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
diff --git a/linux-user/alpha/target_signal.h b/linux-user/alpha/target_signal.h
index f1ed00d50e..4e912e1cf9 100644
--- a/linux-user/alpha/target_signal.h
+++ b/linux-user/alpha/target_signal.h
@@ -55,4 +55,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUAlphaState *state)
#define TARGET_GEN_SUBRNG6 -24
#define TARGET_GEN_SUBRNG7 -25
+#define TARGET_ARCH_HAS_SETUP_FRAME
#endif /* ALPHA_TARGET_SIGNAL_H */
diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c
new file mode 100644
index 0000000000..26928fbbb2
--- /dev/null
+++ b/linux-user/arm/cpu_loop.c
@@ -0,0 +1,459 @@
+/*
+ * qemu user cpu loop
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "elf.h"
+#include "cpu_loop-common.h"
+
+#define get_user_code_u32(x, gaddr, env) \
+ ({ abi_long __r = get_user_u32((x), (gaddr)); \
+ if (!__r && bswap_code(arm_sctlr_b(env))) { \
+ (x) = bswap32(x); \
+ } \
+ __r; \
+ })
+
+#define get_user_code_u16(x, gaddr, env) \
+ ({ abi_long __r = get_user_u16((x), (gaddr)); \
+ if (!__r && bswap_code(arm_sctlr_b(env))) { \
+ (x) = bswap16(x); \
+ } \
+ __r; \
+ })
+
+#define get_user_data_u32(x, gaddr, env) \
+ ({ abi_long __r = get_user_u32((x), (gaddr)); \
+ if (!__r && arm_cpu_bswap_data(env)) { \
+ (x) = bswap32(x); \
+ } \
+ __r; \
+ })
+
+#define get_user_data_u16(x, gaddr, env) \
+ ({ abi_long __r = get_user_u16((x), (gaddr)); \
+ if (!__r && arm_cpu_bswap_data(env)) { \
+ (x) = bswap16(x); \
+ } \
+ __r; \
+ })
+
+#define put_user_data_u32(x, gaddr, env) \
+ ({ typeof(x) __x = (x); \
+ if (arm_cpu_bswap_data(env)) { \
+ __x = bswap32(__x); \
+ } \
+ put_user_u32(__x, (gaddr)); \
+ })
+
+#define put_user_data_u16(x, gaddr, env) \
+ ({ typeof(x) __x = (x); \
+ if (arm_cpu_bswap_data(env)) { \
+ __x = bswap16(__x); \
+ } \
+ put_user_u16(__x, (gaddr)); \
+ })
+
+/* Commpage handling -- there is no commpage for AArch64 */
+
+/*
+ * See the Linux kernel's Documentation/arm/kernel_user_helpers.txt
+ * Input:
+ * r0 = pointer to oldval
+ * r1 = pointer to newval
+ * r2 = pointer to target value
+ *
+ * Output:
+ * r0 = 0 if *ptr was changed, non-0 if no exchange happened
+ * C set if *ptr was changed, clear if no exchange happened
+ *
+ * Note segv's in kernel helpers are a bit tricky, we can set the
+ * data address sensibly but the PC address is just the entry point.
+ */
+static void arm_kernel_cmpxchg64_helper(CPUARMState *env)
+{
+ uint64_t oldval, newval, val;
+ uint32_t addr, cpsr;
+ target_siginfo_t info;
+
+ /* Based on the 32 bit code in do_kernel_trap */
+
+ /* XXX: This only works between threads, not between processes.
+ It's probably possible to implement this with native host
+ operations. However things like ldrex/strex are much harder so
+ there's not much point trying. */
+ start_exclusive();
+ cpsr = cpsr_read(env);
+ addr = env->regs[2];
+
+ if (get_user_u64(oldval, env->regs[0])) {
+ env->exception.vaddress = env->regs[0];
+ goto segv;
+ };
+
+ if (get_user_u64(newval, env->regs[1])) {
+ env->exception.vaddress = env->regs[1];
+ goto segv;
+ };
+
+ if (get_user_u64(val, addr)) {
+ env->exception.vaddress = addr;
+ goto segv;
+ }
+
+ if (val == oldval) {
+ val = newval;
+
+ if (put_user_u64(val, addr)) {
+ env->exception.vaddress = addr;
+ goto segv;
+ };
+
+ env->regs[0] = 0;
+ cpsr |= CPSR_C;
+ } else {
+ env->regs[0] = -1;
+ cpsr &= ~CPSR_C;
+ }
+ cpsr_write(env, cpsr, CPSR_C, CPSRWriteByInstr);
+ end_exclusive();
+ return;
+
+segv:
+ end_exclusive();
+ /* We get the PC of the entry address - which is as good as anything,
+ on a real kernel what you get depends on which mode it uses. */
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ /* XXX: check env->error_code */
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = env->exception.vaddress;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+}
+
+/* Handle a jump to the kernel code page. */
+static int
+do_kernel_trap(CPUARMState *env)
+{
+ uint32_t addr;
+ uint32_t cpsr;
+ uint32_t val;
+
+ switch (env->regs[15]) {
+ case 0xffff0fa0: /* __kernel_memory_barrier */
+ /* ??? No-op. Will need to do better for SMP. */
+ break;
+ case 0xffff0fc0: /* __kernel_cmpxchg */
+ /* XXX: This only works between threads, not between processes.
+ It's probably possible to implement this with native host
+ operations. However things like ldrex/strex are much harder so
+ there's not much point trying. */
+ start_exclusive();
+ cpsr = cpsr_read(env);
+ addr = env->regs[2];
+ /* FIXME: This should SEGV if the access fails. */
+ if (get_user_u32(val, addr))
+ val = ~env->regs[0];
+ if (val == env->regs[0]) {
+ val = env->regs[1];
+ /* FIXME: Check for segfaults. */
+ put_user_u32(val, addr);
+ env->regs[0] = 0;
+ cpsr |= CPSR_C;
+ } else {
+ env->regs[0] = -1;
+ cpsr &= ~CPSR_C;
+ }
+ cpsr_write(env, cpsr, CPSR_C, CPSRWriteByInstr);
+ end_exclusive();
+ break;
+ case 0xffff0fe0: /* __kernel_get_tls */
+ env->regs[0] = cpu_get_tls(env);
+ break;
+ case 0xffff0f60: /* __kernel_cmpxchg64 */
+ arm_kernel_cmpxchg64_helper(env);
+ break;
+
+ default:
+ return 1;
+ }
+ /* Jump back to the caller. */
+ addr = env->regs[14];
+ if (addr & 1) {
+ env->thumb = 1;
+ addr &= ~1;
+ }
+ env->regs[15] = addr;
+
+ return 0;
+}
+
+void cpu_loop(CPUARMState *env)
+{
+ CPUState *cs = CPU(arm_env_get_cpu(env));
+ int trapnr;
+ unsigned int n, insn;
+ target_siginfo_t info;
+ uint32_t addr;
+ abi_ulong ret;
+
+ for(;;) {
+ cpu_exec_start(cs);
+ trapnr = cpu_exec(cs);
+ cpu_exec_end(cs);
+ process_queued_cpu_work(cs);
+
+ switch(trapnr) {
+ case EXCP_UDEF:
+ case EXCP_NOCP:
+ case EXCP_INVSTATE:
+ {
+ TaskState *ts = cs->opaque;
+ uint32_t opcode;
+ int rc;
+
+ /* we handle the FPU emulation here, as Linux */
+ /* we get the opcode */
+ /* FIXME - what to do if get_user() fails? */
+ get_user_code_u32(opcode, env->regs[15], env);
+
+ rc = EmulateAll(opcode, &ts->fpa, env);
+ if (rc == 0) { /* illegal instruction */
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_ILLOPN;
+ info._sifields._sigfault._addr = env->regs[15];
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ } else if (rc < 0) { /* FP exception */
+ int arm_fpe=0;
+
+ /* translate softfloat flags to FPSR flags */
+ if (-rc & float_flag_invalid)
+ arm_fpe |= BIT_IOC;
+ if (-rc & float_flag_divbyzero)
+ arm_fpe |= BIT_DZC;
+ if (-rc & float_flag_overflow)
+ arm_fpe |= BIT_OFC;
+ if (-rc & float_flag_underflow)
+ arm_fpe |= BIT_UFC;
+ if (-rc & float_flag_inexact)
+ arm_fpe |= BIT_IXC;
+
+ FPSR fpsr = ts->fpa.fpsr;
+ //printf("fpsr 0x%x, arm_fpe 0x%x\n",fpsr,arm_fpe);
+
+ if (fpsr & (arm_fpe << 16)) { /* exception enabled? */
+ info.si_signo = TARGET_SIGFPE;
+ info.si_errno = 0;
+
+ /* ordered by priority, least first */
+ if (arm_fpe & BIT_IXC) info.si_code = TARGET_FPE_FLTRES;
+ if (arm_fpe & BIT_UFC) info.si_code = TARGET_FPE_FLTUND;
+ if (arm_fpe & BIT_OFC) info.si_code = TARGET_FPE_FLTOVF;
+ if (arm_fpe & BIT_DZC) info.si_code = TARGET_FPE_FLTDIV;
+ if (arm_fpe & BIT_IOC) info.si_code = TARGET_FPE_FLTINV;
+
+ info._sifields._sigfault._addr = env->regs[15];
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ } else {
+ env->regs[15] += 4;
+ }
+
+ /* accumulate unenabled exceptions */
+ if ((!(fpsr & BIT_IXE)) && (arm_fpe & BIT_IXC))
+ fpsr |= BIT_IXC;
+ if ((!(fpsr & BIT_UFE)) && (arm_fpe & BIT_UFC))
+ fpsr |= BIT_UFC;
+ if ((!(fpsr & BIT_OFE)) && (arm_fpe & BIT_OFC))
+ fpsr |= BIT_OFC;
+ if ((!(fpsr & BIT_DZE)) && (arm_fpe & BIT_DZC))
+ fpsr |= BIT_DZC;
+ if ((!(fpsr & BIT_IOE)) && (arm_fpe & BIT_IOC))
+ fpsr |= BIT_IOC;
+ ts->fpa.fpsr=fpsr;
+ } else { /* everything OK */
+ /* increment PC */
+ env->regs[15] += 4;
+ }
+ }
+ break;
+ case EXCP_SWI:
+ case EXCP_BKPT:
+ {
+ env->eabi = 1;
+ /* system call */
+ if (trapnr == EXCP_BKPT) {
+ if (env->thumb) {
+ /* FIXME - what to do if get_user() fails? */
+ get_user_code_u16(insn, env->regs[15], env);
+ n = insn & 0xff;
+ env->regs[15] += 2;
+ } else {
+ /* FIXME - what to do if get_user() fails? */
+ get_user_code_u32(insn, env->regs[15], env);
+ n = (insn & 0xf) | ((insn >> 4) & 0xff0);
+ env->regs[15] += 4;
+ }
+ } else {
+ if (env->thumb) {
+ /* FIXME - what to do if get_user() fails? */
+ get_user_code_u16(insn, env->regs[15] - 2, env);
+ n = insn & 0xff;
+ } else {
+ /* FIXME - what to do if get_user() fails? */
+ get_user_code_u32(insn, env->regs[15] - 4, env);
+ n = insn & 0xffffff;
+ }
+ }
+
+ if (n == ARM_NR_cacheflush) {
+ /* nop */
+ } else if (n == ARM_NR_semihosting
+ || n == ARM_NR_thumb_semihosting) {
+ env->regs[0] = do_arm_semihosting (env);
+ } else if (n == 0 || n >= ARM_SYSCALL_BASE || env->thumb) {
+ /* linux syscall */
+ if (env->thumb || n == 0) {
+ n = env->regs[7];
+ } else {
+ n -= ARM_SYSCALL_BASE;
+ env->eabi = 0;
+ }
+ if ( n > ARM_NR_BASE) {
+ switch (n) {
+ case ARM_NR_cacheflush:
+ /* nop */
+ break;
+ case ARM_NR_set_tls:
+ cpu_set_tls(env, env->regs[0]);
+ env->regs[0] = 0;
+ break;
+ case ARM_NR_breakpoint:
+ env->regs[15] -= env->thumb ? 2 : 4;
+ goto excp_debug;
+ case ARM_NR_get_tls:
+ env->regs[0] = cpu_get_tls(env);
+ break;
+ default:
+ gemu_log("qemu: Unsupported ARM syscall: 0x%x\n",
+ n);
+ env->regs[0] = -TARGET_ENOSYS;
+ break;
+ }
+ } else {
+ ret = do_syscall(env,
+ n,
+ env->regs[0],
+ env->regs[1],
+ env->regs[2],
+ env->regs[3],
+ env->regs[4],
+ env->regs[5],
+ 0, 0);
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->regs[15] -= env->thumb ? 2 : 4;
+ } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+ env->regs[0] = ret;
+ }
+ }
+ } else {
+ goto error;
+ }
+ }
+ break;
+ case EXCP_SEMIHOST:
+ env->regs[0] = do_arm_semihosting(env);
+ break;
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+ case EXCP_PREFETCH_ABORT:
+ case EXCP_DATA_ABORT:
+ addr = env->exception.vaddress;
+ {
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ /* XXX: check env->error_code */
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = addr;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+ break;
+ case EXCP_DEBUG:
+ excp_debug:
+ {
+ int sig;
+
+ sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+ if (sig)
+ {
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+ }
+ break;
+ case EXCP_KERNEL_TRAP:
+ if (do_kernel_trap(env))
+ goto error;
+ break;
+ case EXCP_YIELD:
+ /* nothing to do here for user-mode, just resume guest code */
+ break;
+ case EXCP_ATOMIC:
+ cpu_exec_step_atomic(cs);
+ break;
+ default:
+ error:
+ EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
+ abort();
+ }
+ process_pending_signals(env);
+ }
+}
+
+void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
+{
+ CPUState *cpu = ENV_GET_CPU(env);
+ TaskState *ts = cpu->opaque;
+ struct image_info *info = ts->info;
+ int i;
+
+ cpsr_write(env, regs->uregs[16], CPSR_USER | CPSR_EXEC,
+ CPSRWriteByInstr);
+ for(i = 0; i < 16; i++) {
+ env->regs[i] = regs->uregs[i];
+ }
+#ifdef TARGET_WORDS_BIGENDIAN
+ /* Enable BE8. */
+ if (EF_ARM_EABI_VERSION(info->elf_flags) >= EF_ARM_EABI_VER4
+ && (info->elf_flags & EF_ARM_BE8)) {
+ env->uncached_cpsr |= CPSR_E;
+ env->cp15.sctlr_el[1] |= SCTLR_E0E;
+ } else {
+ env->cp15.sctlr_el[1] |= SCTLR_B;
+ }
+#endif
+
+ ts->stack_base = info->start_stack;
+ ts->heap_base = info->brk;
+ /* This will be filled in on the first SYS_HEAPINFO call. */
+ ts->heap_limit = 0;
+}
diff --git a/linux-user/arm/signal.c b/linux-user/arm/signal.c
new file mode 100644
index 0000000000..59b5b65ed1
--- /dev/null
+++ b/linux-user/arm/signal.c
@@ -0,0 +1,836 @@
+/*
+ * Emulation of Linux signals
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "target_signal.h"
+#include "signal-common.h"
+#include "linux-user/trace.h"
+
+struct target_sigcontext {
+ abi_ulong trap_no;
+ abi_ulong error_code;
+ abi_ulong oldmask;
+ abi_ulong arm_r0;
+ abi_ulong arm_r1;
+ abi_ulong arm_r2;
+ abi_ulong arm_r3;
+ abi_ulong arm_r4;
+ abi_ulong arm_r5;
+ abi_ulong arm_r6;
+ abi_ulong arm_r7;
+ abi_ulong arm_r8;
+ abi_ulong arm_r9;
+ abi_ulong arm_r10;
+ abi_ulong arm_fp;
+ abi_ulong arm_ip;
+ abi_ulong arm_sp;
+ abi_ulong arm_lr;
+ abi_ulong arm_pc;
+ abi_ulong arm_cpsr;
+ abi_ulong fault_address;
+};
+
+struct target_ucontext_v1 {
+ abi_ulong tuc_flags;
+ abi_ulong tuc_link;
+ target_stack_t tuc_stack;
+ struct target_sigcontext tuc_mcontext;
+ target_sigset_t tuc_sigmask; /* mask last for extensibility */
+};
+
+struct target_ucontext_v2 {
+ abi_ulong tuc_flags;
+ abi_ulong tuc_link;
+ target_stack_t tuc_stack;
+ struct target_sigcontext tuc_mcontext;
+ target_sigset_t tuc_sigmask; /* mask last for extensibility */
+ char __unused[128 - sizeof(target_sigset_t)];
+ abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
+};
+
+struct target_user_vfp {
+ uint64_t fpregs[32];
+ abi_ulong fpscr;
+};
+
+struct target_user_vfp_exc {
+ abi_ulong fpexc;
+ abi_ulong fpinst;
+ abi_ulong fpinst2;
+};
+
+struct target_vfp_sigframe {
+ abi_ulong magic;
+ abi_ulong size;
+ struct target_user_vfp ufp;
+ struct target_user_vfp_exc ufp_exc;
+} __attribute__((__aligned__(8)));
+
+struct target_iwmmxt_sigframe {
+ abi_ulong magic;
+ abi_ulong size;
+ uint64_t regs[16];
+ /* Note that not all the coprocessor control registers are stored here */
+ uint32_t wcssf;
+ uint32_t wcasf;
+ uint32_t wcgr0;
+ uint32_t wcgr1;
+ uint32_t wcgr2;
+ uint32_t wcgr3;
+} __attribute__((__aligned__(8)));
+
+#define TARGET_VFP_MAGIC 0x56465001
+#define TARGET_IWMMXT_MAGIC 0x12ef842a
+
+struct sigframe_v1
+{
+ struct target_sigcontext sc;
+ abi_ulong extramask[TARGET_NSIG_WORDS-1];
+ abi_ulong retcode[4];
+};
+
+struct sigframe_v2
+{
+ struct target_ucontext_v2 uc;
+ abi_ulong retcode[4];
+};
+
+struct rt_sigframe_v1
+{
+ abi_ulong pinfo;
+ abi_ulong puc;
+ struct target_siginfo info;
+ struct target_ucontext_v1 uc;
+ abi_ulong retcode[4];
+};
+
+struct rt_sigframe_v2
+{
+ struct target_siginfo info;
+ struct target_ucontext_v2 uc;
+ abi_ulong retcode[4];
+};
+
+#define TARGET_CONFIG_CPU_32 1
+
+/*
+ * For ARM syscalls, we encode the syscall number into the instruction.
+ */
+#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
+#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
+
+/*
+ * For Thumb syscalls, we pass the syscall number via r7. We therefore
+ * need two 16-bit instructions.
+ */
+#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
+#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
+
+static const abi_ulong retcodes[4] = {
+ SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
+ SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
+};
+
+/*
+ * Stub needed to make sure the FD register (r9) contains the right
+ * value.
+ */
+static const unsigned long sigreturn_fdpic_codes[3] = {
+ 0xe59fc004, /* ldr r12, [pc, #4] to read function descriptor */
+ 0xe59c9004, /* ldr r9, [r12, #4] to setup GOT */
+ 0xe59cf000 /* ldr pc, [r12] to jump into restorer */
+};
+
+static const unsigned long sigreturn_fdpic_thumb_codes[3] = {
+ 0xc008f8df, /* ldr r12, [pc, #8] to read function descriptor */
+ 0x9004f8dc, /* ldr r9, [r12, #4] to setup GOT */
+ 0xf000f8dc /* ldr pc, [r12] to jump into restorer */
+};
+
+static inline int valid_user_regs(CPUARMState *regs)
+{
+ return 1;
+}
+
+static void
+setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
+ CPUARMState *env, abi_ulong mask)
+{
+ __put_user(env->regs[0], &sc->arm_r0);
+ __put_user(env->regs[1], &sc->arm_r1);
+ __put_user(env->regs[2], &sc->arm_r2);
+ __put_user(env->regs[3], &sc->arm_r3);
+ __put_user(env->regs[4], &sc->arm_r4);
+ __put_user(env->regs[5], &sc->arm_r5);
+ __put_user(env->regs[6], &sc->arm_r6);
+ __put_user(env->regs[7], &sc->arm_r7);
+ __put_user(env->regs[8], &sc->arm_r8);
+ __put_user(env->regs[9], &sc->arm_r9);
+ __put_user(env->regs[10], &sc->arm_r10);
+ __put_user(env->regs[11], &sc->arm_fp);
+ __put_user(env->regs[12], &sc->arm_ip);
+ __put_user(env->regs[13], &sc->arm_sp);
+ __put_user(env->regs[14], &sc->arm_lr);
+ __put_user(env->regs[15], &sc->arm_pc);
+#ifdef TARGET_CONFIG_CPU_32
+ __put_user(cpsr_read(env), &sc->arm_cpsr);
+#endif
+
+ __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
+ __put_user(/* current->thread.error_code */ 0, &sc->error_code);
+ __put_user(/* current->thread.address */ 0, &sc->fault_address);
+ __put_user(mask, &sc->oldmask);
+}
+
+static inline abi_ulong
+get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
+{
+ unsigned long sp;
+
+ sp = target_sigsp(get_sp_from_cpustate(regs), ka);
+ /*
+ * ATPCS B01 mandates 8-byte alignment
+ */
+ return (sp - framesize) & ~7;
+}
+
+static int
+setup_return(CPUARMState *env, struct target_sigaction *ka,
+ abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
+{
+ abi_ulong handler = 0;
+ abi_ulong handler_fdpic_GOT = 0;
+ abi_ulong retcode;
+
+ int thumb;
+ int is_fdpic = info_is_fdpic(((TaskState *)thread_cpu->opaque)->info);
+
+ if (is_fdpic) {
+ /* In FDPIC mode, ka->_sa_handler points to a function
+ * descriptor (FD). The first word contains the address of the
+ * handler. The second word contains the value of the PIC
+ * register (r9). */
+ abi_ulong funcdesc_ptr = ka->_sa_handler;
+ if (get_user_ual(handler, funcdesc_ptr)
+ || get_user_ual(handler_fdpic_GOT, funcdesc_ptr + 4)) {
+ return 1;
+ }
+ } else {
+ handler = ka->_sa_handler;
+ }
+
+ thumb = handler & 1;
+
+ uint32_t cpsr = cpsr_read(env);
+
+ cpsr &= ~CPSR_IT;
+ if (thumb) {
+ cpsr |= CPSR_T;
+ } else {
+ cpsr &= ~CPSR_T;
+ }
+
+ if (ka->sa_flags & TARGET_SA_RESTORER) {
+ if (is_fdpic) {
+ /* For FDPIC we ensure that the restorer is called with a
+ * correct r9 value. For that we need to write code on
+ * the stack that sets r9 and jumps back to restorer
+ * value.
+ */
+ if (thumb) {
+ __put_user(sigreturn_fdpic_thumb_codes[0], rc);
+ __put_user(sigreturn_fdpic_thumb_codes[1], rc + 1);
+ __put_user(sigreturn_fdpic_thumb_codes[2], rc + 2);
+ __put_user((abi_ulong)ka->sa_restorer, rc + 3);
+ } else {
+ __put_user(sigreturn_fdpic_codes[0], rc);
+ __put_user(sigreturn_fdpic_codes[1], rc + 1);
+ __put_user(sigreturn_fdpic_codes[2], rc + 2);
+ __put_user((abi_ulong)ka->sa_restorer, rc + 3);
+ }
+
+ retcode = rc_addr + thumb;
+ } else {
+ retcode = ka->sa_restorer;
+ }
+ } else {
+ unsigned int idx = thumb;
+
+ if (ka->sa_flags & TARGET_SA_SIGINFO) {
+ idx += 2;
+ }
+
+ __put_user(retcodes[idx], rc);
+
+ retcode = rc_addr + thumb;
+ }
+
+ env->regs[0] = usig;
+ if (is_fdpic) {
+ env->regs[9] = handler_fdpic_GOT;
+ }
+ env->regs[13] = frame_addr;
+ env->regs[14] = retcode;
+ env->regs[15] = handler & (thumb ? ~1 : ~3);
+ cpsr_write(env, cpsr, CPSR_IT | CPSR_T, CPSRWriteByInstr);
+
+ return 0;
+}
+
+static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
+{
+ int i;
+ struct target_vfp_sigframe *vfpframe;
+ vfpframe = (struct target_vfp_sigframe *)regspace;
+ __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
+ __put_user(sizeof(*vfpframe), &vfpframe->size);
+ for (i = 0; i < 32; i++) {
+ __put_user(*aa32_vfp_dreg(env, i), &vfpframe->ufp.fpregs[i]);
+ }
+ __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
+ __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
+ __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
+ __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
+ return (abi_ulong*)(vfpframe+1);
+}
+
+static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
+ CPUARMState *env)
+{
+ int i;
+ struct target_iwmmxt_sigframe *iwmmxtframe;
+ iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
+ __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
+ __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
+ for (i = 0; i < 16; i++) {
+ __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
+ }
+ __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
+ __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
+ __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
+ __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
+ __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
+ __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
+ return (abi_ulong*)(iwmmxtframe+1);
+}
+
+static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
+ target_sigset_t *set, CPUARMState *env)
+{
+ struct target_sigaltstack stack;
+ int i;
+ abi_ulong *regspace;
+
+ /* Clear all the bits of the ucontext we don't use. */
+ memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
+
+ memset(&stack, 0, sizeof(stack));
+ target_save_altstack(&stack, env);
+ memcpy(&uc->tuc_stack, &stack, sizeof(stack));
+
+ setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
+ /* Save coprocessor signal frame. */
+ regspace = uc->tuc_regspace;
+ if (arm_feature(env, ARM_FEATURE_VFP)) {
+ regspace = setup_sigframe_v2_vfp(regspace, env);
+ }
+ if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+ regspace = setup_sigframe_v2_iwmmxt(regspace, env);
+ }
+
+ /* Write terminating magic word */
+ __put_user(0, regspace);
+
+ for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+ __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
+ }
+}
+
+/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
+static void setup_frame_v1(int usig, struct target_sigaction *ka,
+ target_sigset_t *set, CPUARMState *regs)
+{
+ struct sigframe_v1 *frame;
+ abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
+ int i;
+
+ trace_user_setup_frame(regs, frame_addr);
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+ goto sigsegv;
+ }
+
+ setup_sigcontext(&frame->sc, regs, set->sig[0]);
+
+ for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+ __put_user(set->sig[i], &frame->extramask[i - 1]);
+ }
+
+ if (setup_return(regs, ka, frame->retcode, frame_addr, usig,
+ frame_addr + offsetof(struct sigframe_v1, retcode))) {
+ goto sigsegv;
+ }
+
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+sigsegv:
+ unlock_user_struct(frame, frame_addr, 1);
+ force_sigsegv(usig);
+}
+
+static void setup_frame_v2(int usig, struct target_sigaction *ka,
+ target_sigset_t *set, CPUARMState *regs)
+{
+ struct sigframe_v2 *frame;
+ abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
+
+ trace_user_setup_frame(regs, frame_addr);
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+ goto sigsegv;
+ }
+
+ setup_sigframe_v2(&frame->uc, set, regs);
+
+ if (setup_return(regs, ka, frame->retcode, frame_addr, usig,
+ frame_addr + offsetof(struct sigframe_v2, retcode))) {
+ goto sigsegv;
+ }
+
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+sigsegv:
+ unlock_user_struct(frame, frame_addr, 1);
+ force_sigsegv(usig);
+}
+
+void setup_frame(int usig, struct target_sigaction *ka,
+ target_sigset_t *set, CPUARMState *regs)
+{
+ if (get_osversion() >= 0x020612) {
+ setup_frame_v2(usig, ka, set, regs);
+ } else {
+ setup_frame_v1(usig, ka, set, regs);
+ }
+}
+
+/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
+static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPUARMState *env)
+{
+ struct rt_sigframe_v1 *frame;
+ abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
+ struct target_sigaltstack stack;
+ int i;
+ abi_ulong info_addr, uc_addr;
+
+ trace_user_setup_rt_frame(env, frame_addr);
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+ goto sigsegv;
+ }
+
+ info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
+ __put_user(info_addr, &frame->pinfo);
+ uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
+ __put_user(uc_addr, &frame->puc);
+ tswap_siginfo(&frame->info, info);
+
+ /* Clear all the bits of the ucontext we don't use. */
+ memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
+
+ memset(&stack, 0, sizeof(stack));
+ target_save_altstack(&stack, env);
+ memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
+
+ setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
+ for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+ __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
+ }
+
+ if (setup_return(env, ka, frame->retcode, frame_addr, usig,
+ frame_addr + offsetof(struct rt_sigframe_v1, retcode))) {
+ goto sigsegv;
+ }
+
+ env->regs[1] = info_addr;
+ env->regs[2] = uc_addr;
+
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+sigsegv:
+ unlock_user_struct(frame, frame_addr, 1);
+ force_sigsegv(usig);
+}
+
+static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPUARMState *env)
+{
+ struct rt_sigframe_v2 *frame;
+ abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
+ abi_ulong info_addr, uc_addr;
+
+ trace_user_setup_rt_frame(env, frame_addr);
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+ goto sigsegv;
+ }
+
+ info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
+ uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
+ tswap_siginfo(&frame->info, info);
+
+ setup_sigframe_v2(&frame->uc, set, env);
+
+ if (setup_return(env, ka, frame->retcode, frame_addr, usig,
+ frame_addr + offsetof(struct rt_sigframe_v2, retcode))) {
+ goto sigsegv;
+ }
+
+ env->regs[1] = info_addr;
+ env->regs[2] = uc_addr;
+
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+sigsegv:
+ unlock_user_struct(frame, frame_addr, 1);
+ force_sigsegv(usig);
+}
+
+void setup_rt_frame(int usig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPUARMState *env)
+{
+ if (get_osversion() >= 0x020612) {
+ setup_rt_frame_v2(usig, ka, info, set, env);
+ } else {
+ setup_rt_frame_v1(usig, ka, info, set, env);
+ }
+}
+
+static int
+restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
+{
+ int err = 0;
+ uint32_t cpsr;
+
+ __get_user(env->regs[0], &sc->arm_r0);
+ __get_user(env->regs[1], &sc->arm_r1);
+ __get_user(env->regs[2], &sc->arm_r2);
+ __get_user(env->regs[3], &sc->arm_r3);
+ __get_user(env->regs[4], &sc->arm_r4);
+ __get_user(env->regs[5], &sc->arm_r5);
+ __get_user(env->regs[6], &sc->arm_r6);
+ __get_user(env->regs[7], &sc->arm_r7);
+ __get_user(env->regs[8], &sc->arm_r8);
+ __get_user(env->regs[9], &sc->arm_r9);
+ __get_user(env->regs[10], &sc->arm_r10);
+ __get_user(env->regs[11], &sc->arm_fp);
+ __get_user(env->regs[12], &sc->arm_ip);
+ __get_user(env->regs[13], &sc->arm_sp);
+ __get_user(env->regs[14], &sc->arm_lr);
+ __get_user(env->regs[15], &sc->arm_pc);
+#ifdef TARGET_CONFIG_CPU_32
+ __get_user(cpsr, &sc->arm_cpsr);
+ cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC, CPSRWriteByInstr);
+#endif
+
+ err |= !valid_user_regs(env);
+
+ return err;
+}
+
+static long do_sigreturn_v1(CPUARMState *env)
+{
+ abi_ulong frame_addr;
+ struct sigframe_v1 *frame = NULL;
+ target_sigset_t set;
+ sigset_t host_set;
+ int i;
+
+ /*
+ * Since we stacked the signal on a 64-bit boundary,
+ * then 'sp' should be word aligned here. If it's
+ * not, then the user is trying to mess with us.
+ */
+ frame_addr = env->regs[13];
+ trace_user_do_sigreturn(env, frame_addr);
+ if (frame_addr & 7) {
+ goto badframe;
+ }
+
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+ goto badframe;
+ }
+
+ __get_user(set.sig[0], &frame->sc.oldmask);
+ for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+ __get_user(set.sig[i], &frame->extramask[i - 1]);
+ }
+
+ target_to_host_sigset_internal(&host_set, &set);
+ set_sigmask(&host_set);
+
+ if (restore_sigcontext(env, &frame->sc)) {
+ goto badframe;
+ }
+
+#if 0
+ /* Send SIGTRAP if we're single-stepping */
+ if (ptrace_cancel_bpt(current))
+ send_sig(SIGTRAP, current, 1);
+#endif
+ unlock_user_struct(frame, frame_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+
+badframe:
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
+
+static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
+{
+ int i;
+ abi_ulong magic, sz;
+ uint32_t fpscr, fpexc;
+ struct target_vfp_sigframe *vfpframe;
+ vfpframe = (struct target_vfp_sigframe *)regspace;
+
+ __get_user(magic, &vfpframe->magic);
+ __get_user(sz, &vfpframe->size);
+ if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) {
+ return 0;
+ }
+ for (i = 0; i < 32; i++) {
+ __get_user(*aa32_vfp_dreg(env, i), &vfpframe->ufp.fpregs[i]);
+ }
+ __get_user(fpscr, &vfpframe->ufp.fpscr);
+ vfp_set_fpscr(env, fpscr);
+ __get_user(fpexc, &vfpframe->ufp_exc.fpexc);
+ /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid
+ * and the exception flag is cleared
+ */
+ fpexc |= (1 << 30);
+ fpexc &= ~((1 << 31) | (1 << 28));
+ env->vfp.xregs[ARM_VFP_FPEXC] = fpexc;
+ __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
+ __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
+ return (abi_ulong*)(vfpframe + 1);
+}
+
+static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
+ abi_ulong *regspace)
+{
+ int i;
+ abi_ulong magic, sz;
+ struct target_iwmmxt_sigframe *iwmmxtframe;
+ iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
+
+ __get_user(magic, &iwmmxtframe->magic);
+ __get_user(sz, &iwmmxtframe->size);
+ if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
+ return 0;
+ }
+ for (i = 0; i < 16; i++) {
+ __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
+ }
+ __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
+ __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
+ __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
+ __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
+ __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
+ __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
+ return (abi_ulong*)(iwmmxtframe + 1);
+}
+
+static int do_sigframe_return_v2(CPUARMState *env,
+ target_ulong context_addr,
+ struct target_ucontext_v2 *uc)
+{
+ sigset_t host_set;
+ abi_ulong *regspace;
+
+ target_to_host_sigset(&host_set, &uc->tuc_sigmask);
+ set_sigmask(&host_set);
+
+ if (restore_sigcontext(env, &uc->tuc_mcontext))
+ return 1;
+
+ /* Restore coprocessor signal frame */
+ regspace = uc->tuc_regspace;
+ if (arm_feature(env, ARM_FEATURE_VFP)) {
+ regspace = restore_sigframe_v2_vfp(env, regspace);
+ if (!regspace) {
+ return 1;
+ }
+ }
+ if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+ regspace = restore_sigframe_v2_iwmmxt(env, regspace);
+ if (!regspace) {
+ return 1;
+ }
+ }
+
+ if (do_sigaltstack(context_addr
+ + offsetof(struct target_ucontext_v2, tuc_stack),
+ 0, get_sp_from_cpustate(env)) == -EFAULT) {
+ return 1;
+ }
+
+#if 0
+ /* Send SIGTRAP if we're single-stepping */
+ if (ptrace_cancel_bpt(current))
+ send_sig(SIGTRAP, current, 1);
+#endif
+
+ return 0;
+}
+
+static long do_sigreturn_v2(CPUARMState *env)
+{
+ abi_ulong frame_addr;
+ struct sigframe_v2 *frame = NULL;
+
+ /*
+ * Since we stacked the signal on a 64-bit boundary,
+ * then 'sp' should be word aligned here. If it's
+ * not, then the user is trying to mess with us.
+ */
+ frame_addr = env->regs[13];
+ trace_user_do_sigreturn(env, frame_addr);
+ if (frame_addr & 7) {
+ goto badframe;
+ }
+
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+ goto badframe;
+ }
+
+ if (do_sigframe_return_v2(env,
+ frame_addr
+ + offsetof(struct sigframe_v2, uc),
+ &frame->uc)) {
+ goto badframe;
+ }
+
+ unlock_user_struct(frame, frame_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+
+badframe:
+ unlock_user_struct(frame, frame_addr, 0);
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
+
+long do_sigreturn(CPUARMState *env)
+{
+ if (get_osversion() >= 0x020612) {
+ return do_sigreturn_v2(env);
+ } else {
+ return do_sigreturn_v1(env);
+ }
+}
+
+static long do_rt_sigreturn_v1(CPUARMState *env)
+{
+ abi_ulong frame_addr;
+ struct rt_sigframe_v1 *frame = NULL;
+ sigset_t host_set;
+
+ /*
+ * Since we stacked the signal on a 64-bit boundary,
+ * then 'sp' should be word aligned here. If it's
+ * not, then the user is trying to mess with us.
+ */
+ frame_addr = env->regs[13];
+ trace_user_do_rt_sigreturn(env, frame_addr);
+ if (frame_addr & 7) {
+ goto badframe;
+ }
+
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+ goto badframe;
+ }
+
+ target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
+ set_sigmask(&host_set);
+
+ if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
+ goto badframe;
+ }
+
+ if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v1, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
+ goto badframe;
+
+#if 0
+ /* Send SIGTRAP if we're single-stepping */
+ if (ptrace_cancel_bpt(current))
+ send_sig(SIGTRAP, current, 1);
+#endif
+ unlock_user_struct(frame, frame_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+
+badframe:
+ unlock_user_struct(frame, frame_addr, 0);
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
+
+static long do_rt_sigreturn_v2(CPUARMState *env)
+{
+ abi_ulong frame_addr;
+ struct rt_sigframe_v2 *frame = NULL;
+
+ /*
+ * Since we stacked the signal on a 64-bit boundary,
+ * then 'sp' should be word aligned here. If it's
+ * not, then the user is trying to mess with us.
+ */
+ frame_addr = env->regs[13];
+ trace_user_do_rt_sigreturn(env, frame_addr);
+ if (frame_addr & 7) {
+ goto badframe;
+ }
+
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+ goto badframe;
+ }
+
+ if (do_sigframe_return_v2(env,
+ frame_addr
+ + offsetof(struct rt_sigframe_v2, uc),
+ &frame->uc)) {
+ goto badframe;
+ }
+
+ unlock_user_struct(frame, frame_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+
+badframe:
+ unlock_user_struct(frame, frame_addr, 0);
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
+
+long do_rt_sigreturn(CPUARMState *env)
+{
+ if (get_osversion() >= 0x020612) {
+ return do_rt_sigreturn_v2(env);
+ } else {
+ return do_rt_sigreturn_v1(env);
+ }
+}
diff --git a/linux-user/arm/target_signal.h b/linux-user/arm/target_signal.h
index cbbeb09f4d..d6a03ec87d 100644
--- a/linux-user/arm/target_signal.h
+++ b/linux-user/arm/target_signal.h
@@ -26,5 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUARMState *state)
return state->regs[13];
}
-
+#define TARGET_ARCH_HAS_SETUP_FRAME
#endif /* ARM_TARGET_SIGNAL_H */
diff --git a/linux-user/arm/target_structs.h b/linux-user/arm/target_structs.h
index 0bf034cc25..9a3dbce03d 100644
--- a/linux-user/arm/target_structs.h
+++ b/linux-user/arm/target_structs.h
@@ -49,4 +49,11 @@ struct target_shmid_ds {
abi_ulong __unused5;
};
+struct target_oabi_flock64 {
+ abi_short l_type;
+ abi_short l_whence;
+ abi_llong l_start;
+ abi_llong l_len;
+ abi_int l_pid;
+} QEMU_PACKED;
#endif
diff --git a/linux-user/arm/target_syscall.h b/linux-user/arm/target_syscall.h
index 94e2a42cb2..afc0772e19 100644
--- a/linux-user/arm/target_syscall.h
+++ b/linux-user/arm/target_syscall.h
@@ -16,6 +16,7 @@ struct target_pt_regs {
#define ARM_NR_breakpoint (ARM_NR_BASE + 1)
#define ARM_NR_cacheflush (ARM_NR_BASE + 2)
#define ARM_NR_set_tls (ARM_NR_BASE + 5)
+#define ARM_NR_get_tls (ARM_NR_BASE + 6)
#define ARM_NR_semihosting 0x123456
#define ARM_NR_thumb_semihosting 0xAB
diff --git a/linux-user/cpu_loop-common.h b/linux-user/cpu_loop-common.h
new file mode 100644
index 0000000000..ffe3fe9ad5
--- /dev/null
+++ b/linux-user/cpu_loop-common.h
@@ -0,0 +1,37 @@
+/*
+ * qemu user cpu loop
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CPU_LOOP_COMMON_H
+#define CPU_LOOP_COMMON_H
+
+#include "exec/log.h"
+
+#define EXCP_DUMP(env, fmt, ...) \
+do { \
+ CPUState *cs = ENV_GET_CPU(env); \
+ fprintf(stderr, fmt , ## __VA_ARGS__); \
+ cpu_dump_state(cs, stderr, fprintf, 0); \
+ if (qemu_log_separate()) { \
+ qemu_log(fmt, ## __VA_ARGS__); \
+ log_cpu_state(cs, 0); \
+ } \
+} while (0)
+
+void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs);
+#endif
diff --git a/linux-user/cris/cpu_loop.c b/linux-user/cris/cpu_loop.c
new file mode 100644
index 0000000000..1c5eca9f83
--- /dev/null
+++ b/linux-user/cris/cpu_loop.c
@@ -0,0 +1,115 @@
+/*
+ * qemu user cpu loop
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "cpu_loop-common.h"
+
+void cpu_loop(CPUCRISState *env)
+{
+ CPUState *cs = CPU(cris_env_get_cpu(env));
+ int trapnr, ret;
+ target_siginfo_t info;
+
+ while (1) {
+ cpu_exec_start(cs);
+ trapnr = cpu_exec(cs);
+ cpu_exec_end(cs);
+ process_queued_cpu_work(cs);
+
+ switch (trapnr) {
+ case 0xaa:
+ {
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ /* XXX: check env->error_code */
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = env->pregs[PR_EDA];
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+ break;
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+ case EXCP_BREAK:
+ ret = do_syscall(env,
+ env->regs[9],
+ env->regs[10],
+ env->regs[11],
+ env->regs[12],
+ env->regs[13],
+ env->pregs[7],
+ env->pregs[11],
+ 0, 0);
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->pc -= 2;
+ } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+ env->regs[10] = ret;
+ }
+ break;
+ case EXCP_DEBUG:
+ {
+ int sig;
+
+ sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+ if (sig)
+ {
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+ }
+ break;
+ case EXCP_ATOMIC:
+ cpu_exec_step_atomic(cs);
+ break;
+ default:
+ printf ("Unhandled trap: 0x%x\n", trapnr);
+ cpu_dump_state(cs, stderr, fprintf, 0);
+ exit(EXIT_FAILURE);
+ }
+ process_pending_signals (env);
+ }
+}
+
+void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
+{
+ CPUState *cpu = ENV_GET_CPU(env);
+ TaskState *ts = cpu->opaque;
+ struct image_info *info = ts->info;
+
+ env->regs[0] = regs->r0;
+ env->regs[1] = regs->r1;
+ env->regs[2] = regs->r2;
+ env->regs[3] = regs->r3;
+ env->regs[4] = regs->r4;
+ env->regs[5] = regs->r5;
+ env->regs[6] = regs->r6;
+ env->regs[7] = regs->r7;
+ env->regs[8] = regs->r8;
+ env->regs[9] = regs->r9;
+ env->regs[10] = regs->r10;
+ env->regs[11] = regs->r11;
+ env->regs[12] = regs->r12;
+ env->regs[13] = regs->r13;
+ env->regs[14] = info->start_stack;
+ env->regs[15] = regs->acr;
+ env->pc = regs->erp;
+}
diff --git a/linux-user/cris/signal.c b/linux-user/cris/signal.c
new file mode 100644
index 0000000000..322d9db1a7
--- /dev/null
+++ b/linux-user/cris/signal.c
@@ -0,0 +1,189 @@
+/*
+ * Emulation of Linux signals
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "target_signal.h"
+#include "signal-common.h"
+#include "linux-user/trace.h"
+
+struct target_sigcontext {
+ struct target_pt_regs regs; /* needs to be first */
+ uint32_t oldmask;
+ uint32_t usp; /* usp before stacking this gunk on it */
+};
+
+/* Signal frames. */
+struct target_signal_frame {
+ struct target_sigcontext sc;
+ uint32_t extramask[TARGET_NSIG_WORDS - 1];
+ uint16_t retcode[4]; /* Trampoline code. */
+};
+
+struct rt_signal_frame {
+ siginfo_t *pinfo;
+ void *puc;
+ siginfo_t info;
+ ucontext_t uc;
+ uint16_t retcode[4]; /* Trampoline code. */
+};
+
+static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
+{
+ __put_user(env->regs[0], &sc->regs.r0);
+ __put_user(env->regs[1], &sc->regs.r1);
+ __put_user(env->regs[2], &sc->regs.r2);
+ __put_user(env->regs[3], &sc->regs.r3);
+ __put_user(env->regs[4], &sc->regs.r4);
+ __put_user(env->regs[5], &sc->regs.r5);
+ __put_user(env->regs[6], &sc->regs.r6);
+ __put_user(env->regs[7], &sc->regs.r7);
+ __put_user(env->regs[8], &sc->regs.r8);
+ __put_user(env->regs[9], &sc->regs.r9);
+ __put_user(env->regs[10], &sc->regs.r10);
+ __put_user(env->regs[11], &sc->regs.r11);
+ __put_user(env->regs[12], &sc->regs.r12);
+ __put_user(env->regs[13], &sc->regs.r13);
+ __put_user(env->regs[14], &sc->usp);
+ __put_user(env->regs[15], &sc->regs.acr);
+ __put_user(env->pregs[PR_MOF], &sc->regs.mof);
+ __put_user(env->pregs[PR_SRP], &sc->regs.srp);
+ __put_user(env->pc, &sc->regs.erp);
+}
+
+static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
+{
+ __get_user(env->regs[0], &sc->regs.r0);
+ __get_user(env->regs[1], &sc->regs.r1);
+ __get_user(env->regs[2], &sc->regs.r2);
+ __get_user(env->regs[3], &sc->regs.r3);
+ __get_user(env->regs[4], &sc->regs.r4);
+ __get_user(env->regs[5], &sc->regs.r5);
+ __get_user(env->regs[6], &sc->regs.r6);
+ __get_user(env->regs[7], &sc->regs.r7);
+ __get_user(env->regs[8], &sc->regs.r8);
+ __get_user(env->regs[9], &sc->regs.r9);
+ __get_user(env->regs[10], &sc->regs.r10);
+ __get_user(env->regs[11], &sc->regs.r11);
+ __get_user(env->regs[12], &sc->regs.r12);
+ __get_user(env->regs[13], &sc->regs.r13);
+ __get_user(env->regs[14], &sc->usp);
+ __get_user(env->regs[15], &sc->regs.acr);
+ __get_user(env->pregs[PR_MOF], &sc->regs.mof);
+ __get_user(env->pregs[PR_SRP], &sc->regs.srp);
+ __get_user(env->pc, &sc->regs.erp);
+}
+
+static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
+{
+ abi_ulong sp;
+ /* Align the stack downwards to 4. */
+ sp = (env->regs[R_SP] & ~3);
+ return sp - framesize;
+}
+
+void setup_frame(int sig, struct target_sigaction *ka,
+ target_sigset_t *set, CPUCRISState *env)
+{
+ struct target_signal_frame *frame;
+ abi_ulong frame_addr;
+ int i;
+
+ frame_addr = get_sigframe(env, sizeof *frame);
+ trace_user_setup_frame(env, frame_addr);
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+ goto badframe;
+
+ /*
+ * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
+ * use this trampoline anymore but it sets it up for GDB.
+ * In QEMU, using the trampoline simplifies things a bit so we use it.
+ *
+ * This is movu.w __NR_sigreturn, r9; break 13;
+ */
+ __put_user(0x9c5f, frame->retcode+0);
+ __put_user(TARGET_NR_sigreturn,
+ frame->retcode + 1);
+ __put_user(0xe93d, frame->retcode + 2);
+
+ /* Save the mask. */
+ __put_user(set->sig[0], &frame->sc.oldmask);
+
+ for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+ __put_user(set->sig[i], &frame->extramask[i - 1]);
+ }
+
+ setup_sigcontext(&frame->sc, env);
+
+ /* Move the stack and setup the arguments for the handler. */
+ env->regs[R_SP] = frame_addr;
+ env->regs[10] = sig;
+ env->pc = (unsigned long) ka->_sa_handler;
+ /* Link SRP so the guest returns through the trampoline. */
+ env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
+
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+badframe:
+ force_sigsegv(sig);
+}
+
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPUCRISState *env)
+{
+ fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
+}
+
+long do_sigreturn(CPUCRISState *env)
+{
+ struct target_signal_frame *frame;
+ abi_ulong frame_addr;
+ target_sigset_t target_set;
+ sigset_t set;
+ int i;
+
+ frame_addr = env->regs[R_SP];
+ trace_user_do_sigreturn(env, frame_addr);
+ /* Make sure the guest isn't playing games. */
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1)) {
+ goto badframe;
+ }
+
+ /* Restore blocked signals */
+ __get_user(target_set.sig[0], &frame->sc.oldmask);
+ for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+ __get_user(target_set.sig[i], &frame->extramask[i - 1]);
+ }
+ target_to_host_sigset_internal(&set, &target_set);
+ set_sigmask(&set);
+
+ restore_sigcontext(&frame->sc, env);
+ unlock_user_struct(frame, frame_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+badframe:
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
+
+long do_rt_sigreturn(CPUCRISState *env)
+{
+ trace_user_do_rt_sigreturn(env, 0);
+ fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
+ return -TARGET_ENOSYS;
+}
diff --git a/linux-user/cris/target_signal.h b/linux-user/cris/target_signal.h
index 664621bbcd..74ff2f3382 100644
--- a/linux-user/cris/target_signal.h
+++ b/linux-user/cris/target_signal.h
@@ -26,5 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUCRISState *state)
return state->regs[14];
}
-
+#define TARGET_ARCH_HAS_SETUP_FRAME
#endif /* CRIS_TARGET_SIGNAL_H */
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index c77ed1bb01..36d52194bc 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -78,6 +78,11 @@ enum {
*/
#define personality(pers) (pers & PER_MASK)
+int info_is_fdpic(struct image_info *info)
+{
+ return info->personality == PER_LINUX_FDPIC;
+}
+
/* this flag is uneffective under linux too, should be deleted */
#ifndef MAP_DENYWRITE
#define MAP_DENYWRITE 0
@@ -287,6 +292,25 @@ static inline void init_thread(struct target_pt_regs *regs,
/* For uClinux PIC binaries. */
/* XXX: Linux does this only on ARM with no MMU (do we care ?) */
regs->uregs[10] = infop->start_data;
+
+ /* Support ARM FDPIC. */
+ if (info_is_fdpic(infop)) {
+ /* As described in the ABI document, r7 points to the loadmap info
+ * prepared by the kernel. If an interpreter is needed, r8 points
+ * to the interpreter loadmap and r9 points to the interpreter
+ * PT_DYNAMIC info. If no interpreter is needed, r8 is zero, and
+ * r9 points to the main program PT_DYNAMIC info.
+ */
+ regs->uregs[7] = infop->loadmap_addr;
+ if (infop->interpreter_loadmap_addr) {
+ /* Executable is dynamically loaded. */
+ regs->uregs[8] = infop->interpreter_loadmap_addr;
+ regs->uregs[9] = infop->interpreter_pt_dynamic_addr;
+ } else {
+ regs->uregs[8] = 0;
+ regs->uregs[9] = infop->pt_dynamic_addr;
+ }
+ }
}
#define ELF_NREG 18
@@ -1681,7 +1705,19 @@ static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot)
}
}
-#ifdef CONFIG_USE_FDPIC
+#ifdef TARGET_ARM
+static int elf_is_fdpic(struct elfhdr *exec)
+{
+ return exec->e_ident[EI_OSABI] == ELFOSABI_ARM_FDPIC;
+}
+#else
+/* Default implementation, always false. */
+static int elf_is_fdpic(struct elfhdr *exec)
+{
+ return 0;
+}
+#endif
+
static abi_ulong loader_build_fdpic_loadmap(struct image_info *info, abi_ulong sp)
{
uint16_t n;
@@ -1706,7 +1742,6 @@ static abi_ulong loader_build_fdpic_loadmap(struct image_info *info, abi_ulong s
return sp;
}
-#endif
static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
struct elfhdr *exec,
@@ -1725,7 +1760,6 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
sp = p;
-#ifdef CONFIG_USE_FDPIC
/* Needs to be before we load the env/argc/... */
if (elf_is_fdpic(exec)) {
/* Need 4 byte alignment for these structs */
@@ -1735,9 +1769,13 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
if (interp_info) {
interp_info->other_info = info;
sp = loader_build_fdpic_loadmap(interp_info, sp);
+ info->interpreter_loadmap_addr = interp_info->loadmap_addr;
+ info->interpreter_pt_dynamic_addr = interp_info->pt_dynamic_addr;
+ } else {
+ info->interpreter_loadmap_addr = 0;
+ info->interpreter_pt_dynamic_addr = 0;
}
}
-#endif
u_platform = 0;
k_platform = ELF_PLATFORM;
@@ -2153,10 +2191,8 @@ static void load_elf_image(const char *image_name, int image_fd,
}
bswap_phdr(phdr, ehdr->e_phnum);
-#ifdef CONFIG_USE_FDPIC
info->nsegs = 0;
info->pt_dynamic_addr = 0;
-#endif
mmap_lock();
@@ -2173,9 +2209,7 @@ static void load_elf_image(const char *image_name, int image_fd,
if (a > hiaddr) {
hiaddr = a;
}
-#ifdef CONFIG_USE_FDPIC
++info->nsegs;
-#endif
}
}
@@ -2200,8 +2234,7 @@ static void load_elf_image(const char *image_name, int image_fd,
}
load_bias = load_addr - loaddr;
-#ifdef CONFIG_USE_FDPIC
- {
+ if (elf_is_fdpic(ehdr)) {
struct elf32_fdpic_loadseg *loadsegs = info->loadsegs =
g_malloc(sizeof(*loadsegs) * info->nsegs);
@@ -2219,7 +2252,6 @@ static void load_elf_image(const char *image_name, int image_fd,
}
}
}
-#endif
info->load_bias = load_bias;
info->load_addr = load_addr;
diff --git a/linux-user/hppa/cpu_loop.c b/linux-user/hppa/cpu_loop.c
new file mode 100644
index 0000000000..0301c766c6
--- /dev/null
+++ b/linux-user/hppa/cpu_loop.c
@@ -0,0 +1,211 @@
+/*
+ * qemu user cpu loop
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "cpu_loop-common.h"
+
+static abi_ulong hppa_lws(CPUHPPAState *env)
+{
+ uint32_t which = env->gr[20];
+ abi_ulong addr = env->gr[26];
+ abi_ulong old = env->gr[25];
+ abi_ulong new = env->gr[24];
+ abi_ulong size, ret;
+
+ switch (which) {
+ default:
+ return -TARGET_ENOSYS;
+
+ case 0: /* elf32 atomic 32bit cmpxchg */
+ if ((addr & 3) || !access_ok(VERIFY_WRITE, addr, 4)) {
+ return -TARGET_EFAULT;
+ }
+ old = tswap32(old);
+ new = tswap32(new);
+ ret = atomic_cmpxchg((uint32_t *)g2h(addr), old, new);
+ ret = tswap32(ret);
+ break;
+
+ case 2: /* elf32 atomic "new" cmpxchg */
+ size = env->gr[23];
+ if (size >= 4) {
+ return -TARGET_ENOSYS;
+ }
+ if (((addr | old | new) & ((1 << size) - 1))
+ || !access_ok(VERIFY_WRITE, addr, 1 << size)
+ || !access_ok(VERIFY_READ, old, 1 << size)
+ || !access_ok(VERIFY_READ, new, 1 << size)) {
+ return -TARGET_EFAULT;
+ }
+ /* Note that below we use host-endian loads so that the cmpxchg
+ can be host-endian as well. */
+ switch (size) {
+ case 0:
+ old = *(uint8_t *)g2h(old);
+ new = *(uint8_t *)g2h(new);
+ ret = atomic_cmpxchg((uint8_t *)g2h(addr), old, new);
+ ret = ret != old;
+ break;
+ case 1:
+ old = *(uint16_t *)g2h(old);
+ new = *(uint16_t *)g2h(new);
+ ret = atomic_cmpxchg((uint16_t *)g2h(addr), old, new);
+ ret = ret != old;
+ break;
+ case 2:
+ old = *(uint32_t *)g2h(old);
+ new = *(uint32_t *)g2h(new);
+ ret = atomic_cmpxchg((uint32_t *)g2h(addr), old, new);
+ ret = ret != old;
+ break;
+ case 3:
+ {
+ uint64_t o64, n64, r64;
+ o64 = *(uint64_t *)g2h(old);
+ n64 = *(uint64_t *)g2h(new);
+#ifdef CONFIG_ATOMIC64
+ r64 = atomic_cmpxchg__nocheck((uint64_t *)g2h(addr), o64, n64);
+ ret = r64 != o64;
+#else
+ start_exclusive();
+ r64 = *(uint64_t *)g2h(addr);
+ ret = 1;
+ if (r64 == o64) {
+ *(uint64_t *)g2h(addr) = n64;
+ ret = 0;
+ }
+ end_exclusive();
+#endif
+ }
+ break;
+ }
+ break;
+ }
+
+ env->gr[28] = ret;
+ return 0;
+}
+
+void cpu_loop(CPUHPPAState *env)
+{
+ CPUState *cs = CPU(hppa_env_get_cpu(env));
+ target_siginfo_t info;
+ abi_ulong ret;
+ int trapnr;
+
+ while (1) {
+ cpu_exec_start(cs);
+ trapnr = cpu_exec(cs);
+ cpu_exec_end(cs);
+ process_queued_cpu_work(cs);
+
+ switch (trapnr) {
+ case EXCP_SYSCALL:
+ ret = do_syscall(env, env->gr[20],
+ env->gr[26], env->gr[25],
+ env->gr[24], env->gr[23],
+ env->gr[22], env->gr[21], 0, 0);
+ switch (ret) {
+ default:
+ env->gr[28] = ret;
+ /* We arrived here by faking the gateway page. Return. */
+ env->iaoq_f = env->gr[31];
+ env->iaoq_b = env->gr[31] + 4;
+ break;
+ case -TARGET_ERESTARTSYS:
+ case -TARGET_QEMU_ESIGRETURN:
+ break;
+ }
+ break;
+ case EXCP_SYSCALL_LWS:
+ env->gr[21] = hppa_lws(env);
+ /* We arrived here by faking the gateway page. Return. */
+ env->iaoq_f = env->gr[31];
+ env->iaoq_b = env->gr[31] + 4;
+ break;
+ case EXCP_ITLB_MISS:
+ case EXCP_DTLB_MISS:
+ case EXCP_NA_ITLB_MISS:
+ case EXCP_NA_DTLB_MISS:
+ case EXCP_IMP:
+ case EXCP_DMP:
+ case EXCP_DMB:
+ case EXCP_PAGE_REF:
+ case EXCP_DMAR:
+ case EXCP_DMPI:
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_ACCERR;
+ info._sifields._sigfault._addr = env->cr[CR_IOR];
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_UNALIGN:
+ info.si_signo = TARGET_SIGBUS;
+ info.si_errno = 0;
+ info.si_code = 0;
+ info._sifields._sigfault._addr = env->cr[CR_IOR];
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_ILL:
+ case EXCP_PRIV_OPR:
+ case EXCP_PRIV_REG:
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_ILLOPN;
+ info._sifields._sigfault._addr = env->iaoq_f;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_OVERFLOW:
+ case EXCP_COND:
+ case EXCP_ASSIST:
+ info.si_signo = TARGET_SIGFPE;
+ info.si_errno = 0;
+ info.si_code = 0;
+ info._sifields._sigfault._addr = env->iaoq_f;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_DEBUG:
+ trapnr = gdb_handlesig(cs, TARGET_SIGTRAP);
+ if (trapnr) {
+ info.si_signo = trapnr;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ queue_signal(env, trapnr, QEMU_SI_FAULT, &info);
+ }
+ break;
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ process_pending_signals(env);
+ }
+}
+
+void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
+{
+ int i;
+ for (i = 1; i < 32; i++) {
+ env->gr[i] = regs->gr[i];
+ }
+ env->iaoq_f = regs->iaoq[0];
+ env->iaoq_b = regs->iaoq[1];
+}
diff --git a/linux-user/hppa/signal.c b/linux-user/hppa/signal.c
new file mode 100644
index 0000000000..6e7a295aee
--- /dev/null
+++ b/linux-user/hppa/signal.c
@@ -0,0 +1,204 @@
+/*
+ * Emulation of Linux signals
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "target_signal.h"
+#include "signal-common.h"
+#include "linux-user/trace.h"
+
+struct target_sigcontext {
+ abi_ulong sc_flags;
+ abi_ulong sc_gr[32];
+ uint64_t sc_fr[32];
+ abi_ulong sc_iasq[2];
+ abi_ulong sc_iaoq[2];
+ abi_ulong sc_sar;
+};
+
+struct target_ucontext {
+ abi_uint tuc_flags;
+ abi_ulong tuc_link;
+ target_stack_t tuc_stack;
+ abi_uint pad[1];
+ struct target_sigcontext tuc_mcontext;
+ target_sigset_t tuc_sigmask;
+};
+
+struct target_rt_sigframe {
+ abi_uint tramp[9];
+ target_siginfo_t info;
+ struct target_ucontext uc;
+ /* hidden location of upper halves of pa2.0 64-bit gregs */
+};
+
+static void setup_sigcontext(struct target_sigcontext *sc, CPUArchState *env)
+{
+ int flags = 0;
+ int i;
+
+ /* ??? if on_sig_stack, flags |= 1 (PARISC_SC_FLAG_ONSTACK). */
+
+ if (env->iaoq_f < TARGET_PAGE_SIZE) {
+ /* In the gateway page, executing a syscall. */
+ flags |= 2; /* PARISC_SC_FLAG_IN_SYSCALL */
+ __put_user(env->gr[31], &sc->sc_iaoq[0]);
+ __put_user(env->gr[31] + 4, &sc->sc_iaoq[1]);
+ } else {
+ __put_user(env->iaoq_f, &sc->sc_iaoq[0]);
+ __put_user(env->iaoq_b, &sc->sc_iaoq[1]);
+ }
+ __put_user(0, &sc->sc_iasq[0]);
+ __put_user(0, &sc->sc_iasq[1]);
+ __put_user(flags, &sc->sc_flags);
+
+ __put_user(cpu_hppa_get_psw(env), &sc->sc_gr[0]);
+ for (i = 1; i < 32; ++i) {
+ __put_user(env->gr[i], &sc->sc_gr[i]);
+ }
+
+ __put_user((uint64_t)env->fr0_shadow << 32, &sc->sc_fr[0]);
+ for (i = 1; i < 32; ++i) {
+ __put_user(env->fr[i], &sc->sc_fr[i]);
+ }
+
+ __put_user(env->cr[CR_SAR], &sc->sc_sar);
+}
+
+static void restore_sigcontext(CPUArchState *env, struct target_sigcontext *sc)
+{
+ target_ulong psw;
+ int i;
+
+ __get_user(psw, &sc->sc_gr[0]);
+ cpu_hppa_put_psw(env, psw);
+
+ for (i = 1; i < 32; ++i) {
+ __get_user(env->gr[i], &sc->sc_gr[i]);
+ }
+ for (i = 0; i < 32; ++i) {
+ __get_user(env->fr[i], &sc->sc_fr[i]);
+ }
+ cpu_hppa_loaded_fr0(env);
+
+ __get_user(env->iaoq_f, &sc->sc_iaoq[0]);
+ __get_user(env->iaoq_b, &sc->sc_iaoq[1]);
+ __get_user(env->cr[CR_SAR], &sc->sc_sar);
+}
+
+/* No, this doesn't look right, but it's copied straight from the kernel. */
+#define PARISC_RT_SIGFRAME_SIZE32 \
+ ((sizeof(struct target_rt_sigframe) + 48 + 64) & -64)
+
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPUArchState *env)
+{
+ abi_ulong frame_addr, sp, haddr;
+ struct target_rt_sigframe *frame;
+ int i;
+
+ sp = get_sp_from_cpustate(env);
+ if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
+ sp = (target_sigaltstack_used.ss_sp + 0x7f) & ~0x3f;
+ }
+ frame_addr = QEMU_ALIGN_UP(sp, 64);
+ sp = frame_addr + PARISC_RT_SIGFRAME_SIZE32;
+
+ trace_user_setup_rt_frame(env, frame_addr);
+
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+ goto give_sigsegv;
+ }
+
+ tswap_siginfo(&frame->info, info);
+ frame->uc.tuc_flags = 0;
+ frame->uc.tuc_link = 0;
+
+ target_save_altstack(&frame->uc.tuc_stack, env);
+
+ for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+ __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
+ }
+
+ setup_sigcontext(&frame->uc.tuc_mcontext, env);
+
+ __put_user(0x34190000, frame->tramp + 0); /* ldi 0,%r25 */
+ __put_user(0x3414015a, frame->tramp + 1); /* ldi __NR_rt_sigreturn,%r20 */
+ __put_user(0xe4008200, frame->tramp + 2); /* be,l 0x100(%sr2,%r0) */
+ __put_user(0x08000240, frame->tramp + 3); /* nop */
+
+ unlock_user_struct(frame, frame_addr, 1);
+
+ env->gr[2] = h2g(frame->tramp);
+ env->gr[30] = sp;
+ env->gr[26] = sig;
+ env->gr[25] = h2g(&frame->info);
+ env->gr[24] = h2g(&frame->uc);
+
+ haddr = ka->_sa_handler;
+ if (haddr & 2) {
+ /* Function descriptor. */
+ target_ulong *fdesc, dest;
+
+ haddr &= -4;
+ if (!lock_user_struct(VERIFY_READ, fdesc, haddr, 1)) {
+ goto give_sigsegv;
+ }
+ __get_user(dest, fdesc);
+ __get_user(env->gr[19], fdesc + 1);
+ unlock_user_struct(fdesc, haddr, 1);
+ haddr = dest;
+ }
+ env->iaoq_f = haddr;
+ env->iaoq_b = haddr + 4;
+ return;
+
+ give_sigsegv:
+ force_sigsegv(sig);
+}
+
+long do_rt_sigreturn(CPUArchState *env)
+{
+ abi_ulong frame_addr = env->gr[30] - PARISC_RT_SIGFRAME_SIZE32;
+ struct target_rt_sigframe *frame;
+ sigset_t set;
+
+ trace_user_do_rt_sigreturn(env, frame_addr);
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+ goto badframe;
+ }
+ target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
+ set_sigmask(&set);
+
+ restore_sigcontext(env, &frame->uc.tuc_mcontext);
+ unlock_user_struct(frame, frame_addr, 0);
+
+ if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
+ uc.tuc_stack),
+ 0, env->gr[30]) == -EFAULT) {
+ goto badframe;
+ }
+
+ unlock_user_struct(frame, frame_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+
+ badframe:
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
diff --git a/linux-user/hppa/target_signal.h b/linux-user/hppa/target_signal.h
index e115890b48..f28b4bf6e8 100644
--- a/linux-user/hppa/target_signal.h
+++ b/linux-user/hppa/target_signal.h
@@ -25,5 +25,4 @@ static inline abi_ulong get_sp_from_cpustate(CPUHPPAState *state)
{
return state->gr[30];
}
-
#endif /* HPPA_TARGET_SIGNAL_H */
diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c
new file mode 100644
index 0000000000..2374abfd0b
--- /dev/null
+++ b/linux-user/i386/cpu_loop.c
@@ -0,0 +1,369 @@
+/*
+ * qemu user cpu loop
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "cpu_loop-common.h"
+
+/***********************************************************/
+/* CPUX86 core interface */
+
+uint64_t cpu_get_tsc(CPUX86State *env)
+{
+ return cpu_get_host_ticks();
+}
+
+static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
+ int flags)
+{
+ unsigned int e1, e2;
+ uint32_t *p;
+ e1 = (addr << 16) | (limit & 0xffff);
+ e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
+ e2 |= flags;
+ p = ptr;
+ p[0] = tswap32(e1);
+ p[1] = tswap32(e2);
+}
+
+static uint64_t *idt_table;
+#ifdef TARGET_X86_64
+static void set_gate64(void *ptr, unsigned int type, unsigned int dpl,
+ uint64_t addr, unsigned int sel)
+{
+ uint32_t *p, e1, e2;
+ e1 = (addr & 0xffff) | (sel << 16);
+ e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
+ p = ptr;
+ p[0] = tswap32(e1);
+ p[1] = tswap32(e2);
+ p[2] = tswap32(addr >> 32);
+ p[3] = 0;
+}
+/* only dpl matters as we do only user space emulation */
+static void set_idt(int n, unsigned int dpl)
+{
+ set_gate64(idt_table + n * 2, 0, dpl, 0, 0);
+}
+#else
+static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
+ uint32_t addr, unsigned int sel)
+{
+ uint32_t *p, e1, e2;
+ e1 = (addr & 0xffff) | (sel << 16);
+ e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
+ p = ptr;
+ p[0] = tswap32(e1);
+ p[1] = tswap32(e2);
+}
+
+/* only dpl matters as we do only user space emulation */
+static void set_idt(int n, unsigned int dpl)
+{
+ set_gate(idt_table + n, 0, dpl, 0, 0);
+}
+#endif
+
+void cpu_loop(CPUX86State *env)
+{
+ CPUState *cs = CPU(x86_env_get_cpu(env));
+ int trapnr;
+ abi_ulong pc;
+ abi_ulong ret;
+ target_siginfo_t info;
+
+ for(;;) {
+ cpu_exec_start(cs);
+ trapnr = cpu_exec(cs);
+ cpu_exec_end(cs);
+ process_queued_cpu_work(cs);
+
+ switch(trapnr) {
+ case 0x80:
+ /* linux syscall from int $0x80 */
+ ret = do_syscall(env,
+ env->regs[R_EAX],
+ env->regs[R_EBX],
+ env->regs[R_ECX],
+ env->regs[R_EDX],
+ env->regs[R_ESI],
+ env->regs[R_EDI],
+ env->regs[R_EBP],
+ 0, 0);
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->eip -= 2;
+ } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+ env->regs[R_EAX] = ret;
+ }
+ break;
+#ifndef TARGET_ABI32
+ case EXCP_SYSCALL:
+ /* linux syscall from syscall instruction */
+ ret = do_syscall(env,
+ env->regs[R_EAX],
+ env->regs[R_EDI],
+ env->regs[R_ESI],
+ env->regs[R_EDX],
+ env->regs[10],
+ env->regs[8],
+ env->regs[9],
+ 0, 0);
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->eip -= 2;
+ } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+ env->regs[R_EAX] = ret;
+ }
+ break;
+#endif
+ case EXCP0B_NOSEG:
+ case EXCP0C_STACK:
+ info.si_signo = TARGET_SIGBUS;
+ info.si_errno = 0;
+ info.si_code = TARGET_SI_KERNEL;
+ info._sifields._sigfault._addr = 0;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP0D_GPF:
+ /* XXX: potential problem if ABI32 */
+#ifndef TARGET_X86_64
+ if (env->eflags & VM_MASK) {
+ handle_vm86_fault(env);
+ } else
+#endif
+ {
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SI_KERNEL;
+ info._sifields._sigfault._addr = 0;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+ break;
+ case EXCP0E_PAGE:
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ if (!(env->error_code & 1))
+ info.si_code = TARGET_SEGV_MAPERR;
+ else
+ info.si_code = TARGET_SEGV_ACCERR;
+ info._sifields._sigfault._addr = env->cr[2];
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP00_DIVZ:
+#ifndef TARGET_X86_64
+ if (env->eflags & VM_MASK) {
+ handle_vm86_trap(env, trapnr);
+ } else
+#endif
+ {
+ /* division by zero */
+ info.si_signo = TARGET_SIGFPE;
+ info.si_errno = 0;
+ info.si_code = TARGET_FPE_INTDIV;
+ info._sifields._sigfault._addr = env->eip;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+ break;
+ case EXCP01_DB:
+ case EXCP03_INT3:
+#ifndef TARGET_X86_64
+ if (env->eflags & VM_MASK) {
+ handle_vm86_trap(env, trapnr);
+ } else
+#endif
+ {
+ info.si_signo = TARGET_SIGTRAP;
+ info.si_errno = 0;
+ if (trapnr == EXCP01_DB) {
+ info.si_code = TARGET_TRAP_BRKPT;
+ info._sifields._sigfault._addr = env->eip;
+ } else {
+ info.si_code = TARGET_SI_KERNEL;
+ info._sifields._sigfault._addr = 0;
+ }
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+ break;
+ case EXCP04_INTO:
+ case EXCP05_BOUND:
+#ifndef TARGET_X86_64
+ if (env->eflags & VM_MASK) {
+ handle_vm86_trap(env, trapnr);
+ } else
+#endif
+ {
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SI_KERNEL;
+ info._sifields._sigfault._addr = 0;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+ break;
+ case EXCP06_ILLOP:
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_ILLOPN;
+ info._sifields._sigfault._addr = env->eip;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+ case EXCP_DEBUG:
+ {
+ int sig;
+
+ sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+ if (sig)
+ {
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+ }
+ break;
+ case EXCP_ATOMIC:
+ cpu_exec_step_atomic(cs);
+ break;
+ default:
+ pc = env->segs[R_CS].base + env->eip;
+ EXCP_DUMP(env, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
+ (long)pc, trapnr);
+ abort();
+ }
+ process_pending_signals(env);
+ }
+}
+
+void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
+{
+ env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
+ env->hflags |= HF_PE_MASK | HF_CPL_MASK;
+ if (env->features[FEAT_1_EDX] & CPUID_SSE) {
+ env->cr[4] |= CR4_OSFXSR_MASK;
+ env->hflags |= HF_OSFXSR_MASK;
+ }
+#ifndef TARGET_ABI32
+ /* enable 64 bit mode if possible */
+ if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) {
+ fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
+ exit(EXIT_FAILURE);
+ }
+ env->cr[4] |= CR4_PAE_MASK;
+ env->efer |= MSR_EFER_LMA | MSR_EFER_LME;
+ env->hflags |= HF_LMA_MASK;
+#endif
+
+ /* flags setup : we activate the IRQs by default as in user mode */
+ env->eflags |= IF_MASK;
+
+ /* linux register setup */
+#ifndef TARGET_ABI32
+ env->regs[R_EAX] = regs->rax;
+ env->regs[R_EBX] = regs->rbx;
+ env->regs[R_ECX] = regs->rcx;
+ env->regs[R_EDX] = regs->rdx;
+ env->regs[R_ESI] = regs->rsi;
+ env->regs[R_EDI] = regs->rdi;
+ env->regs[R_EBP] = regs->rbp;
+ env->regs[R_ESP] = regs->rsp;
+ env->eip = regs->rip;
+#else
+ env->regs[R_EAX] = regs->eax;
+ env->regs[R_EBX] = regs->ebx;
+ env->regs[R_ECX] = regs->ecx;
+ env->regs[R_EDX] = regs->edx;
+ env->regs[R_ESI] = regs->esi;
+ env->regs[R_EDI] = regs->edi;
+ env->regs[R_EBP] = regs->ebp;
+ env->regs[R_ESP] = regs->esp;
+ env->eip = regs->eip;
+#endif
+
+ /* linux interrupt setup */
+#ifndef TARGET_ABI32
+ env->idt.limit = 511;
+#else
+ env->idt.limit = 255;
+#endif
+ env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
+ PROT_READ|PROT_WRITE,
+ MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ idt_table = g2h(env->idt.base);
+ set_idt(0, 0);
+ set_idt(1, 0);
+ set_idt(2, 0);
+ set_idt(3, 3);
+ set_idt(4, 3);
+ set_idt(5, 0);
+ set_idt(6, 0);
+ set_idt(7, 0);
+ set_idt(8, 0);
+ set_idt(9, 0);
+ set_idt(10, 0);
+ set_idt(11, 0);
+ set_idt(12, 0);
+ set_idt(13, 0);
+ set_idt(14, 0);
+ set_idt(15, 0);
+ set_idt(16, 0);
+ set_idt(17, 0);
+ set_idt(18, 0);
+ set_idt(19, 0);
+ set_idt(0x80, 3);
+
+ /* linux segment setup */
+ {
+ uint64_t *gdt_table;
+ env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
+ PROT_READ|PROT_WRITE,
+ MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
+ gdt_table = g2h(env->gdt.base);
+#ifdef TARGET_ABI32
+ write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+ (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
+#else
+ /* 64 bit code segment */
+ write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+ DESC_L_MASK |
+ (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
+#endif
+ write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+ (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
+ }
+ cpu_x86_load_seg(env, R_CS, __USER_CS);
+ cpu_x86_load_seg(env, R_SS, __USER_DS);
+#ifdef TARGET_ABI32
+ cpu_x86_load_seg(env, R_DS, __USER_DS);
+ cpu_x86_load_seg(env, R_ES, __USER_DS);
+ cpu_x86_load_seg(env, R_FS, __USER_DS);
+ cpu_x86_load_seg(env, R_GS, __USER_DS);
+ /* This hack makes Wine work... */
+ env->segs[R_FS].selector = 0;
+#else
+ cpu_x86_load_seg(env, R_DS, 0);
+ cpu_x86_load_seg(env, R_ES, 0);
+ cpu_x86_load_seg(env, R_FS, 0);
+ cpu_x86_load_seg(env, R_GS, 0);
+#endif
+}
diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c
new file mode 100644
index 0000000000..e9a23a2dec
--- /dev/null
+++ b/linux-user/i386/signal.c
@@ -0,0 +1,596 @@
+/*
+ * Emulation of Linux signals
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "target_signal.h"
+#include "signal-common.h"
+#include "linux-user/trace.h"
+
+/* from the Linux kernel - /arch/x86/include/uapi/asm/sigcontext.h */
+
+struct target_fpreg {
+ uint16_t significand[4];
+ uint16_t exponent;
+};
+
+struct target_fpxreg {
+ uint16_t significand[4];
+ uint16_t exponent;
+ uint16_t padding[3];
+};
+
+struct target_xmmreg {
+ uint32_t element[4];
+};
+
+struct target_fpstate_32 {
+ /* Regular FPU environment */
+ uint32_t cw;
+ uint32_t sw;
+ uint32_t tag;
+ uint32_t ipoff;
+ uint32_t cssel;
+ uint32_t dataoff;
+ uint32_t datasel;
+ struct target_fpreg st[8];
+ uint16_t status;
+ uint16_t magic; /* 0xffff = regular FPU data only */
+
+ /* FXSR FPU environment */
+ uint32_t _fxsr_env[6]; /* FXSR FPU env is ignored */
+ uint32_t mxcsr;
+ uint32_t reserved;
+ struct target_fpxreg fxsr_st[8]; /* FXSR FPU reg data is ignored */
+ struct target_xmmreg xmm[8];
+ uint32_t padding[56];
+};
+
+struct target_fpstate_64 {
+ /* FXSAVE format */
+ uint16_t cw;
+ uint16_t sw;
+ uint16_t twd;
+ uint16_t fop;
+ uint64_t rip;
+ uint64_t rdp;
+ uint32_t mxcsr;
+ uint32_t mxcsr_mask;
+ uint32_t st_space[32];
+ uint32_t xmm_space[64];
+ uint32_t reserved[24];
+};
+
+#ifndef TARGET_X86_64
+# define target_fpstate target_fpstate_32
+#else
+# define target_fpstate target_fpstate_64
+#endif
+
+struct target_sigcontext_32 {
+ uint16_t gs, __gsh;
+ uint16_t fs, __fsh;
+ uint16_t es, __esh;
+ uint16_t ds, __dsh;
+ uint32_t edi;
+ uint32_t esi;
+ uint32_t ebp;
+ uint32_t esp;
+ uint32_t ebx;
+ uint32_t edx;
+ uint32_t ecx;
+ uint32_t eax;
+ uint32_t trapno;
+ uint32_t err;
+ uint32_t eip;
+ uint16_t cs, __csh;
+ uint32_t eflags;
+ uint32_t esp_at_signal;
+ uint16_t ss, __ssh;
+ uint32_t fpstate; /* pointer */
+ uint32_t oldmask;
+ uint32_t cr2;
+};
+
+struct target_sigcontext_64 {
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+
+ uint64_t rdi;
+ uint64_t rsi;
+ uint64_t rbp;
+ uint64_t rbx;
+ uint64_t rdx;
+ uint64_t rax;
+ uint64_t rcx;
+ uint64_t rsp;
+ uint64_t rip;
+
+ uint64_t eflags;
+
+ uint16_t cs;
+ uint16_t gs;
+ uint16_t fs;
+ uint16_t ss;
+
+ uint64_t err;
+ uint64_t trapno;
+ uint64_t oldmask;
+ uint64_t cr2;
+
+ uint64_t fpstate; /* pointer */
+ uint64_t padding[8];
+};
+
+#ifndef TARGET_X86_64
+# define target_sigcontext target_sigcontext_32
+#else
+# define target_sigcontext target_sigcontext_64
+#endif
+
+/* see Linux/include/uapi/asm-generic/ucontext.h */
+struct target_ucontext {
+ abi_ulong tuc_flags;
+ abi_ulong tuc_link;
+ target_stack_t tuc_stack;
+ struct target_sigcontext tuc_mcontext;
+ target_sigset_t tuc_sigmask; /* mask last for extensibility */
+};
+
+#ifndef TARGET_X86_64
+struct sigframe {
+ abi_ulong pretcode;
+ int sig;
+ struct target_sigcontext sc;
+ struct target_fpstate fpstate;
+ abi_ulong extramask[TARGET_NSIG_WORDS-1];
+ char retcode[8];
+};
+
+struct rt_sigframe {
+ abi_ulong pretcode;
+ int sig;
+ abi_ulong pinfo;
+ abi_ulong puc;
+ struct target_siginfo info;
+ struct target_ucontext uc;
+ struct target_fpstate fpstate;
+ char retcode[8];
+};
+
+#else
+
+struct rt_sigframe {
+ abi_ulong pretcode;
+ struct target_ucontext uc;
+ struct target_siginfo info;
+ struct target_fpstate fpstate;
+};
+
+#endif
+
+/*
+ * Set up a signal frame.
+ */
+
+/* XXX: save x87 state */
+static void setup_sigcontext(struct target_sigcontext *sc,
+ struct target_fpstate *fpstate, CPUX86State *env, abi_ulong mask,
+ abi_ulong fpstate_addr)
+{
+ CPUState *cs = CPU(x86_env_get_cpu(env));
+#ifndef TARGET_X86_64
+ uint16_t magic;
+
+ /* already locked in setup_frame() */
+ __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
+ __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
+ __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
+ __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
+ __put_user(env->regs[R_EDI], &sc->edi);
+ __put_user(env->regs[R_ESI], &sc->esi);
+ __put_user(env->regs[R_EBP], &sc->ebp);
+ __put_user(env->regs[R_ESP], &sc->esp);
+ __put_user(env->regs[R_EBX], &sc->ebx);
+ __put_user(env->regs[R_EDX], &sc->edx);
+ __put_user(env->regs[R_ECX], &sc->ecx);
+ __put_user(env->regs[R_EAX], &sc->eax);
+ __put_user(cs->exception_index, &sc->trapno);
+ __put_user(env->error_code, &sc->err);
+ __put_user(env->eip, &sc->eip);
+ __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
+ __put_user(env->eflags, &sc->eflags);
+ __put_user(env->regs[R_ESP], &sc->esp_at_signal);
+ __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
+
+ cpu_x86_fsave(env, fpstate_addr, 1);
+ fpstate->status = fpstate->sw;
+ magic = 0xffff;
+ __put_user(magic, &fpstate->magic);
+ __put_user(fpstate_addr, &sc->fpstate);
+
+ /* non-iBCS2 extensions.. */
+ __put_user(mask, &sc->oldmask);
+ __put_user(env->cr[2], &sc->cr2);
+#else
+ __put_user(env->regs[R_EDI], &sc->rdi);
+ __put_user(env->regs[R_ESI], &sc->rsi);
+ __put_user(env->regs[R_EBP], &sc->rbp);
+ __put_user(env->regs[R_ESP], &sc->rsp);
+ __put_user(env->regs[R_EBX], &sc->rbx);
+ __put_user(env->regs[R_EDX], &sc->rdx);
+ __put_user(env->regs[R_ECX], &sc->rcx);
+ __put_user(env->regs[R_EAX], &sc->rax);
+
+ __put_user(env->regs[8], &sc->r8);
+ __put_user(env->regs[9], &sc->r9);
+ __put_user(env->regs[10], &sc->r10);
+ __put_user(env->regs[11], &sc->r11);
+ __put_user(env->regs[12], &sc->r12);
+ __put_user(env->regs[13], &sc->r13);
+ __put_user(env->regs[14], &sc->r14);
+ __put_user(env->regs[15], &sc->r15);
+
+ __put_user(cs->exception_index, &sc->trapno);
+ __put_user(env->error_code, &sc->err);
+ __put_user(env->eip, &sc->rip);
+
+ __put_user(env->eflags, &sc->eflags);
+ __put_user(env->segs[R_CS].selector, &sc->cs);
+ __put_user((uint16_t)0, &sc->gs);
+ __put_user((uint16_t)0, &sc->fs);
+ __put_user(env->segs[R_SS].selector, &sc->ss);
+
+ __put_user(mask, &sc->oldmask);
+ __put_user(env->cr[2], &sc->cr2);
+
+ /* fpstate_addr must be 16 byte aligned for fxsave */
+ assert(!(fpstate_addr & 0xf));
+
+ cpu_x86_fxsave(env, fpstate_addr);
+ __put_user(fpstate_addr, &sc->fpstate);
+#endif
+}
+
+/*
+ * Determine which stack to use..
+ */
+
+static inline abi_ulong
+get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
+{
+ unsigned long esp;
+
+ /* Default to using normal stack */
+ esp = get_sp_from_cpustate(env);
+#ifdef TARGET_X86_64
+ esp -= 128; /* this is the redzone */
+#endif
+
+ /* This is the X/Open sanctioned signal stack switching. */
+ if (ka->sa_flags & TARGET_SA_ONSTACK) {
+ esp = target_sigsp(esp, ka);
+ } else {
+#ifndef TARGET_X86_64
+ /* This is the legacy signal stack switching. */
+ if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
+ !(ka->sa_flags & TARGET_SA_RESTORER) &&
+ ka->sa_restorer) {
+ esp = (unsigned long) ka->sa_restorer;
+ }
+#endif
+ }
+
+#ifndef TARGET_X86_64
+ return (esp - frame_size) & -8ul;
+#else
+ return ((esp - frame_size) & (~15ul)) - 8;
+#endif
+}
+
+#ifndef TARGET_X86_64
+/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
+void setup_frame(int sig, struct target_sigaction *ka,
+ target_sigset_t *set, CPUX86State *env)
+{
+ abi_ulong frame_addr;
+ struct sigframe *frame;
+ int i;
+
+ frame_addr = get_sigframe(ka, env, sizeof(*frame));
+ trace_user_setup_frame(env, frame_addr);
+
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+ goto give_sigsegv;
+
+ __put_user(sig, &frame->sig);
+
+ setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
+ frame_addr + offsetof(struct sigframe, fpstate));
+
+ for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+ __put_user(set->sig[i], &frame->extramask[i - 1]);
+ }
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ if (ka->sa_flags & TARGET_SA_RESTORER) {
+ __put_user(ka->sa_restorer, &frame->pretcode);
+ } else {
+ uint16_t val16;
+ abi_ulong retcode_addr;
+ retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
+ __put_user(retcode_addr, &frame->pretcode);
+ /* This is popl %eax ; movl $,%eax ; int $0x80 */
+ val16 = 0xb858;
+ __put_user(val16, (uint16_t *)(frame->retcode+0));
+ __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
+ val16 = 0x80cd;
+ __put_user(val16, (uint16_t *)(frame->retcode+6));
+ }
+
+ /* Set up registers for signal handler */
+ env->regs[R_ESP] = frame_addr;
+ env->eip = ka->_sa_handler;
+
+ cpu_x86_load_seg(env, R_DS, __USER_DS);
+ cpu_x86_load_seg(env, R_ES, __USER_DS);
+ cpu_x86_load_seg(env, R_SS, __USER_DS);
+ cpu_x86_load_seg(env, R_CS, __USER_CS);
+ env->eflags &= ~TF_MASK;
+
+ unlock_user_struct(frame, frame_addr, 1);
+
+ return;
+
+give_sigsegv:
+ force_sigsegv(sig);
+}
+#endif
+
+/* compare linux/arch/x86/kernel/signal.c:setup_rt_frame() */
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPUX86State *env)
+{
+ abi_ulong frame_addr;
+#ifndef TARGET_X86_64
+ abi_ulong addr;
+#endif
+ struct rt_sigframe *frame;
+ int i;
+
+ frame_addr = get_sigframe(ka, env, sizeof(*frame));
+ trace_user_setup_rt_frame(env, frame_addr);
+
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+ goto give_sigsegv;
+
+ /* These fields are only in rt_sigframe on 32 bit */
+#ifndef TARGET_X86_64
+ __put_user(sig, &frame->sig);
+ addr = frame_addr + offsetof(struct rt_sigframe, info);
+ __put_user(addr, &frame->pinfo);
+ addr = frame_addr + offsetof(struct rt_sigframe, uc);
+ __put_user(addr, &frame->puc);
+#endif
+ if (ka->sa_flags & TARGET_SA_SIGINFO) {
+ tswap_siginfo(&frame->info, info);
+ }
+
+ /* Create the ucontext. */
+ __put_user(0, &frame->uc.tuc_flags);
+ __put_user(0, &frame->uc.tuc_link);
+ target_save_altstack(&frame->uc.tuc_stack, env);
+ setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env,
+ set->sig[0], frame_addr + offsetof(struct rt_sigframe, fpstate));
+
+ for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+ __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
+ }
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+#ifndef TARGET_X86_64
+ if (ka->sa_flags & TARGET_SA_RESTORER) {
+ __put_user(ka->sa_restorer, &frame->pretcode);
+ } else {
+ uint16_t val16;
+ addr = frame_addr + offsetof(struct rt_sigframe, retcode);
+ __put_user(addr, &frame->pretcode);
+ /* This is movl $,%eax ; int $0x80 */
+ __put_user(0xb8, (char *)(frame->retcode+0));
+ __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
+ val16 = 0x80cd;
+ __put_user(val16, (uint16_t *)(frame->retcode+5));
+ }
+#else
+ /* XXX: Would be slightly better to return -EFAULT here if test fails
+ assert(ka->sa_flags & TARGET_SA_RESTORER); */
+ __put_user(ka->sa_restorer, &frame->pretcode);
+#endif
+
+ /* Set up registers for signal handler */
+ env->regs[R_ESP] = frame_addr;
+ env->eip = ka->_sa_handler;
+
+#ifndef TARGET_X86_64
+ env->regs[R_EAX] = sig;
+ env->regs[R_EDX] = (unsigned long)&frame->info;
+ env->regs[R_ECX] = (unsigned long)&frame->uc;
+#else
+ env->regs[R_EAX] = 0;
+ env->regs[R_EDI] = sig;
+ env->regs[R_ESI] = (unsigned long)&frame->info;
+ env->regs[R_EDX] = (unsigned long)&frame->uc;
+#endif
+
+ cpu_x86_load_seg(env, R_DS, __USER_DS);
+ cpu_x86_load_seg(env, R_ES, __USER_DS);
+ cpu_x86_load_seg(env, R_CS, __USER_CS);
+ cpu_x86_load_seg(env, R_SS, __USER_DS);
+ env->eflags &= ~TF_MASK;
+
+ unlock_user_struct(frame, frame_addr, 1);
+
+ return;
+
+give_sigsegv:
+ force_sigsegv(sig);
+}
+
+static int
+restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc)
+{
+ unsigned int err = 0;
+ abi_ulong fpstate_addr;
+ unsigned int tmpflags;
+
+#ifndef TARGET_X86_64
+ cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
+ cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
+ cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
+ cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
+
+ env->regs[R_EDI] = tswapl(sc->edi);
+ env->regs[R_ESI] = tswapl(sc->esi);
+ env->regs[R_EBP] = tswapl(sc->ebp);
+ env->regs[R_ESP] = tswapl(sc->esp);
+ env->regs[R_EBX] = tswapl(sc->ebx);
+ env->regs[R_EDX] = tswapl(sc->edx);
+ env->regs[R_ECX] = tswapl(sc->ecx);
+ env->regs[R_EAX] = tswapl(sc->eax);
+
+ env->eip = tswapl(sc->eip);
+#else
+ env->regs[8] = tswapl(sc->r8);
+ env->regs[9] = tswapl(sc->r9);
+ env->regs[10] = tswapl(sc->r10);
+ env->regs[11] = tswapl(sc->r11);
+ env->regs[12] = tswapl(sc->r12);
+ env->regs[13] = tswapl(sc->r13);
+ env->regs[14] = tswapl(sc->r14);
+ env->regs[15] = tswapl(sc->r15);
+
+ env->regs[R_EDI] = tswapl(sc->rdi);
+ env->regs[R_ESI] = tswapl(sc->rsi);
+ env->regs[R_EBP] = tswapl(sc->rbp);
+ env->regs[R_EBX] = tswapl(sc->rbx);
+ env->regs[R_EDX] = tswapl(sc->rdx);
+ env->regs[R_EAX] = tswapl(sc->rax);
+ env->regs[R_ECX] = tswapl(sc->rcx);
+ env->regs[R_ESP] = tswapl(sc->rsp);
+
+ env->eip = tswapl(sc->rip);
+#endif
+
+ cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
+ cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
+
+ tmpflags = tswapl(sc->eflags);
+ env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
+ // regs->orig_eax = -1; /* disable syscall checks */
+
+ fpstate_addr = tswapl(sc->fpstate);
+ if (fpstate_addr != 0) {
+ if (!access_ok(VERIFY_READ, fpstate_addr,
+ sizeof(struct target_fpstate)))
+ goto badframe;
+#ifndef TARGET_X86_64
+ cpu_x86_frstor(env, fpstate_addr, 1);
+#else
+ cpu_x86_fxrstor(env, fpstate_addr);
+#endif
+ }
+
+ return err;
+badframe:
+ return 1;
+}
+
+/* Note: there is no sigreturn on x86_64, there is only rt_sigreturn */
+#ifndef TARGET_X86_64
+long do_sigreturn(CPUX86State *env)
+{
+ struct sigframe *frame;
+ abi_ulong frame_addr = env->regs[R_ESP] - 8;
+ target_sigset_t target_set;
+ sigset_t set;
+ int i;
+
+ trace_user_do_sigreturn(env, frame_addr);
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
+ goto badframe;
+ /* set blocked signals */
+ __get_user(target_set.sig[0], &frame->sc.oldmask);
+ for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+ __get_user(target_set.sig[i], &frame->extramask[i - 1]);
+ }
+
+ target_to_host_sigset_internal(&set, &target_set);
+ set_sigmask(&set);
+
+ /* restore registers */
+ if (restore_sigcontext(env, &frame->sc))
+ goto badframe;
+ unlock_user_struct(frame, frame_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+
+badframe:
+ unlock_user_struct(frame, frame_addr, 0);
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
+#endif
+
+long do_rt_sigreturn(CPUX86State *env)
+{
+ abi_ulong frame_addr;
+ struct rt_sigframe *frame;
+ sigset_t set;
+
+ frame_addr = env->regs[R_ESP] - sizeof(abi_ulong);
+ trace_user_do_rt_sigreturn(env, frame_addr);
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
+ goto badframe;
+ target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
+ set_sigmask(&set);
+
+ if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
+ goto badframe;
+ }
+
+ if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
+ get_sp_from_cpustate(env)) == -EFAULT) {
+ goto badframe;
+ }
+
+ unlock_user_struct(frame, frame_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+
+badframe:
+ unlock_user_struct(frame, frame_addr, 0);
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
diff --git a/linux-user/i386/target_signal.h b/linux-user/i386/target_signal.h
index 837e90fc4c..6ad4089482 100644
--- a/linux-user/i386/target_signal.h
+++ b/linux-user/i386/target_signal.h
@@ -26,4 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
return state->regs[R_ESP];
}
+#define TARGET_ARCH_HAS_SETUP_FRAME
#endif /* I386_TARGET_SIGNAL_H */
diff --git a/linux-user/m68k/cpu_loop.c b/linux-user/m68k/cpu_loop.c
new file mode 100644
index 0000000000..b4d3d8af3d
--- /dev/null
+++ b/linux-user/m68k/cpu_loop.c
@@ -0,0 +1,170 @@
+/*
+ * qemu user cpu loop
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "cpu_loop-common.h"
+
+void cpu_loop(CPUM68KState *env)
+{
+ CPUState *cs = CPU(m68k_env_get_cpu(env));
+ int trapnr;
+ unsigned int n;
+ target_siginfo_t info;
+ TaskState *ts = cs->opaque;
+
+ for(;;) {
+ cpu_exec_start(cs);
+ trapnr = cpu_exec(cs);
+ cpu_exec_end(cs);
+ process_queued_cpu_work(cs);
+
+ switch(trapnr) {
+ case EXCP_ILLEGAL:
+ {
+ if (ts->sim_syscalls) {
+ uint16_t nr;
+ get_user_u16(nr, env->pc + 2);
+ env->pc += 4;
+ do_m68k_simcall(env, nr);
+ } else {
+ goto do_sigill;
+ }
+ }
+ break;
+ case EXCP_HALT_INSN:
+ /* Semihosing syscall. */
+ env->pc += 4;
+ do_m68k_semihosting(env, env->dregs[0]);
+ break;
+ case EXCP_LINEA:
+ case EXCP_LINEF:
+ case EXCP_UNSUPPORTED:
+ do_sigill:
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_ILLOPN;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_CHK:
+ info.si_signo = TARGET_SIGFPE;
+ info.si_errno = 0;
+ info.si_code = TARGET_FPE_INTOVF;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_DIV0:
+ info.si_signo = TARGET_SIGFPE;
+ info.si_errno = 0;
+ info.si_code = TARGET_FPE_INTDIV;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_TRAP0:
+ {
+ abi_long ret;
+ ts->sim_syscalls = 0;
+ n = env->dregs[0];
+ env->pc += 2;
+ ret = do_syscall(env,
+ n,
+ env->dregs[1],
+ env->dregs[2],
+ env->dregs[3],
+ env->dregs[4],
+ env->dregs[5],
+ env->aregs[0],
+ 0, 0);
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->pc -= 2;
+ } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+ env->dregs[0] = ret;
+ }
+ }
+ break;
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+ case EXCP_ACCESS:
+ {
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ /* XXX: check env->error_code */
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = env->mmu.ar;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+ break;
+ case EXCP_DEBUG:
+ {
+ int sig;
+
+ sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+ if (sig)
+ {
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+ }
+ break;
+ case EXCP_ATOMIC:
+ cpu_exec_step_atomic(cs);
+ break;
+ default:
+ EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
+ abort();
+ }
+ process_pending_signals(env);
+ }
+}
+
+void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
+{
+ CPUState *cpu = ENV_GET_CPU(env);
+ TaskState *ts = cpu->opaque;
+ struct image_info *info = ts->info;
+
+ env->pc = regs->pc;
+ env->dregs[0] = regs->d0;
+ env->dregs[1] = regs->d1;
+ env->dregs[2] = regs->d2;
+ env->dregs[3] = regs->d3;
+ env->dregs[4] = regs->d4;
+ env->dregs[5] = regs->d5;
+ env->dregs[6] = regs->d6;
+ env->dregs[7] = regs->d7;
+ env->aregs[0] = regs->a0;
+ env->aregs[1] = regs->a1;
+ env->aregs[2] = regs->a2;
+ env->aregs[3] = regs->a3;
+ env->aregs[4] = regs->a4;
+ env->aregs[5] = regs->a5;
+ env->aregs[6] = regs->a6;
+ env->aregs[7] = regs->usp;
+ env->sr = regs->sr;
+
+ ts->sim_syscalls = 1;
+ ts->stack_base = info->start_stack;
+ ts->heap_base = info->brk;
+ /* This will be filled in on the first SYS_HEAPINFO call. */
+ ts->heap_limit = 0;
+}
diff --git a/linux-user/m68k/signal.c b/linux-user/m68k/signal.c
new file mode 100644
index 0000000000..5dd8bb5f99
--- /dev/null
+++ b/linux-user/m68k/signal.c
@@ -0,0 +1,419 @@
+/*
+ * Emulation of Linux signals
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "target_signal.h"
+#include "signal-common.h"
+#include "linux-user/trace.h"
+
+struct target_sigcontext {
+ abi_ulong sc_mask;
+ abi_ulong sc_usp;
+ abi_ulong sc_d0;
+ abi_ulong sc_d1;
+ abi_ulong sc_a0;
+ abi_ulong sc_a1;
+ unsigned short sc_sr;
+ abi_ulong sc_pc;
+};
+
+struct target_sigframe
+{
+ abi_ulong pretcode;
+ int sig;
+ int code;
+ abi_ulong psc;
+ char retcode[8];
+ abi_ulong extramask[TARGET_NSIG_WORDS-1];
+ struct target_sigcontext sc;
+};
+
+typedef int target_greg_t;
+#define TARGET_NGREG 18
+typedef target_greg_t target_gregset_t[TARGET_NGREG];
+
+typedef struct target_fpregset {
+ int f_fpcntl[3];
+ int f_fpregs[8*3];
+} target_fpregset_t;
+
+struct target_mcontext {
+ int version;
+ target_gregset_t gregs;
+ target_fpregset_t fpregs;
+};
+
+#define TARGET_MCONTEXT_VERSION 2
+
+struct target_ucontext {
+ abi_ulong tuc_flags;
+ abi_ulong tuc_link;
+ target_stack_t tuc_stack;
+ struct target_mcontext tuc_mcontext;
+ abi_long tuc_filler[80];
+ target_sigset_t tuc_sigmask;
+};
+
+struct target_rt_sigframe
+{
+ abi_ulong pretcode;
+ int sig;
+ abi_ulong pinfo;
+ abi_ulong puc;
+ char retcode[8];
+ struct target_siginfo info;
+ struct target_ucontext uc;
+};
+
+static void setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
+ abi_ulong mask)
+{
+ uint32_t sr = (env->sr & 0xff00) | cpu_m68k_get_ccr(env);
+ __put_user(mask, &sc->sc_mask);
+ __put_user(env->aregs[7], &sc->sc_usp);
+ __put_user(env->dregs[0], &sc->sc_d0);
+ __put_user(env->dregs[1], &sc->sc_d1);
+ __put_user(env->aregs[0], &sc->sc_a0);
+ __put_user(env->aregs[1], &sc->sc_a1);
+ __put_user(sr, &sc->sc_sr);
+ __put_user(env->pc, &sc->sc_pc);
+}
+
+static void
+restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc)
+{
+ int temp;
+
+ __get_user(env->aregs[7], &sc->sc_usp);
+ __get_user(env->dregs[0], &sc->sc_d0);
+ __get_user(env->dregs[1], &sc->sc_d1);
+ __get_user(env->aregs[0], &sc->sc_a0);
+ __get_user(env->aregs[1], &sc->sc_a1);
+ __get_user(env->pc, &sc->sc_pc);
+ __get_user(temp, &sc->sc_sr);
+ cpu_m68k_set_ccr(env, temp);
+}
+
+/*
+ * Determine which stack to use..
+ */
+static inline abi_ulong
+get_sigframe(struct target_sigaction *ka, CPUM68KState *regs,
+ size_t frame_size)
+{
+ abi_ulong sp;
+
+ sp = target_sigsp(get_sp_from_cpustate(regs), ka);
+
+
+ return ((sp - frame_size) & -8UL);
+}
+
+void setup_frame(int sig, struct target_sigaction *ka,
+ target_sigset_t *set, CPUM68KState *env)
+{
+ struct target_sigframe *frame;
+ abi_ulong frame_addr;
+ abi_ulong retcode_addr;
+ abi_ulong sc_addr;
+ int i;
+
+ frame_addr = get_sigframe(ka, env, sizeof *frame);
+ trace_user_setup_frame(env, frame_addr);
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+ goto give_sigsegv;
+ }
+
+ __put_user(sig, &frame->sig);
+
+ sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
+ __put_user(sc_addr, &frame->psc);
+
+ setup_sigcontext(&frame->sc, env, set->sig[0]);
+
+ for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+ __put_user(set->sig[i], &frame->extramask[i - 1]);
+ }
+
+ /* Set up to return from userspace. */
+
+ retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
+ __put_user(retcode_addr, &frame->pretcode);
+
+ /* moveq #,d0; trap #0 */
+
+ __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
+ (uint32_t *)(frame->retcode));
+
+ /* Set up to return from userspace */
+
+ env->aregs[7] = frame_addr;
+ env->pc = ka->_sa_handler;
+
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+
+give_sigsegv:
+ force_sigsegv(sig);
+}
+
+static inline void target_rt_save_fpu_state(struct target_ucontext *uc,
+ CPUM68KState *env)
+{
+ int i;
+ target_fpregset_t *fpregs = &uc->tuc_mcontext.fpregs;
+
+ __put_user(env->fpcr, &fpregs->f_fpcntl[0]);
+ __put_user(env->fpsr, &fpregs->f_fpcntl[1]);
+ /* fpiar is not emulated */
+
+ for (i = 0; i < 8; i++) {
+ uint32_t high = env->fregs[i].d.high << 16;
+ __put_user(high, &fpregs->f_fpregs[i * 3]);
+ __put_user(env->fregs[i].d.low,
+ (uint64_t *)&fpregs->f_fpregs[i * 3 + 1]);
+ }
+}
+
+static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
+ CPUM68KState *env)
+{
+ target_greg_t *gregs = uc->tuc_mcontext.gregs;
+ uint32_t sr = (env->sr & 0xff00) | cpu_m68k_get_ccr(env);
+
+ __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
+ __put_user(env->dregs[0], &gregs[0]);
+ __put_user(env->dregs[1], &gregs[1]);
+ __put_user(env->dregs[2], &gregs[2]);
+ __put_user(env->dregs[3], &gregs[3]);
+ __put_user(env->dregs[4], &gregs[4]);
+ __put_user(env->dregs[5], &gregs[5]);
+ __put_user(env->dregs[6], &gregs[6]);
+ __put_user(env->dregs[7], &gregs[7]);
+ __put_user(env->aregs[0], &gregs[8]);
+ __put_user(env->aregs[1], &gregs[9]);
+ __put_user(env->aregs[2], &gregs[10]);
+ __put_user(env->aregs[3], &gregs[11]);
+ __put_user(env->aregs[4], &gregs[12]);
+ __put_user(env->aregs[5], &gregs[13]);
+ __put_user(env->aregs[6], &gregs[14]);
+ __put_user(env->aregs[7], &gregs[15]);
+ __put_user(env->pc, &gregs[16]);
+ __put_user(sr, &gregs[17]);
+
+ target_rt_save_fpu_state(uc, env);
+
+ return 0;
+}
+
+static inline void target_rt_restore_fpu_state(CPUM68KState *env,
+ struct target_ucontext *uc)
+{
+ int i;
+ target_fpregset_t *fpregs = &uc->tuc_mcontext.fpregs;
+ uint32_t fpcr;
+
+ __get_user(fpcr, &fpregs->f_fpcntl[0]);
+ cpu_m68k_set_fpcr(env, fpcr);
+ __get_user(env->fpsr, &fpregs->f_fpcntl[1]);
+ /* fpiar is not emulated */
+
+ for (i = 0; i < 8; i++) {
+ uint32_t high;
+ __get_user(high, &fpregs->f_fpregs[i * 3]);
+ env->fregs[i].d.high = high >> 16;
+ __get_user(env->fregs[i].d.low,
+ (uint64_t *)&fpregs->f_fpregs[i * 3 + 1]);
+ }
+}
+
+static inline int target_rt_restore_ucontext(CPUM68KState *env,
+ struct target_ucontext *uc)
+{
+ int temp;
+ target_greg_t *gregs = uc->tuc_mcontext.gregs;
+
+ __get_user(temp, &uc->tuc_mcontext.version);
+ if (temp != TARGET_MCONTEXT_VERSION)
+ goto badframe;
+
+ /* restore passed registers */
+ __get_user(env->dregs[0], &gregs[0]);
+ __get_user(env->dregs[1], &gregs[1]);
+ __get_user(env->dregs[2], &gregs[2]);
+ __get_user(env->dregs[3], &gregs[3]);
+ __get_user(env->dregs[4], &gregs[4]);
+ __get_user(env->dregs[5], &gregs[5]);
+ __get_user(env->dregs[6], &gregs[6]);
+ __get_user(env->dregs[7], &gregs[7]);
+ __get_user(env->aregs[0], &gregs[8]);
+ __get_user(env->aregs[1], &gregs[9]);
+ __get_user(env->aregs[2], &gregs[10]);
+ __get_user(env->aregs[3], &gregs[11]);
+ __get_user(env->aregs[4], &gregs[12]);
+ __get_user(env->aregs[5], &gregs[13]);
+ __get_user(env->aregs[6], &gregs[14]);
+ __get_user(env->aregs[7], &gregs[15]);
+ __get_user(env->pc, &gregs[16]);
+ __get_user(temp, &gregs[17]);
+ cpu_m68k_set_ccr(env, temp);
+
+ target_rt_restore_fpu_state(env, uc);
+
+ return 0;
+
+badframe:
+ return 1;
+}
+
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPUM68KState *env)
+{
+ struct target_rt_sigframe *frame;
+ abi_ulong frame_addr;
+ abi_ulong retcode_addr;
+ abi_ulong info_addr;
+ abi_ulong uc_addr;
+ int err = 0;
+ int i;
+
+ frame_addr = get_sigframe(ka, env, sizeof *frame);
+ trace_user_setup_rt_frame(env, frame_addr);
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+ goto give_sigsegv;
+ }
+
+ __put_user(sig, &frame->sig);
+
+ info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
+ __put_user(info_addr, &frame->pinfo);
+
+ uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
+ __put_user(uc_addr, &frame->puc);
+
+ tswap_siginfo(&frame->info, info);
+
+ /* Create the ucontext */
+
+ __put_user(0, &frame->uc.tuc_flags);
+ __put_user(0, &frame->uc.tuc_link);
+ target_save_altstack(&frame->uc.tuc_stack, env);
+ err |= target_rt_setup_ucontext(&frame->uc, env);
+
+ if (err)
+ goto give_sigsegv;
+
+ for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+ __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
+ }
+
+ /* Set up to return from userspace. */
+
+ retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
+ __put_user(retcode_addr, &frame->pretcode);
+
+ /* moveq #,d0; notb d0; trap #0 */
+
+ __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
+ (uint32_t *)(frame->retcode + 0));
+ __put_user(0x4e40, (uint16_t *)(frame->retcode + 4));
+
+ if (err)
+ goto give_sigsegv;
+
+ /* Set up to return from userspace */
+
+ env->aregs[7] = frame_addr;
+ env->pc = ka->_sa_handler;
+
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+
+give_sigsegv:
+ unlock_user_struct(frame, frame_addr, 1);
+ force_sigsegv(sig);
+}
+
+long do_sigreturn(CPUM68KState *env)
+{
+ struct target_sigframe *frame;
+ abi_ulong frame_addr = env->aregs[7] - 4;
+ target_sigset_t target_set;
+ sigset_t set;
+ int i;
+
+ trace_user_do_sigreturn(env, frame_addr);
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
+ goto badframe;
+
+ /* set blocked signals */
+
+ __get_user(target_set.sig[0], &frame->sc.sc_mask);
+
+ for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+ __get_user(target_set.sig[i], &frame->extramask[i - 1]);
+ }
+
+ target_to_host_sigset_internal(&set, &target_set);
+ set_sigmask(&set);
+
+ /* restore registers */
+
+ restore_sigcontext(env, &frame->sc);
+
+ unlock_user_struct(frame, frame_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+
+badframe:
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
+
+long do_rt_sigreturn(CPUM68KState *env)
+{
+ struct target_rt_sigframe *frame;
+ abi_ulong frame_addr = env->aregs[7] - 4;
+ sigset_t set;
+
+ trace_user_do_rt_sigreturn(env, frame_addr);
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
+ goto badframe;
+
+ target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
+ set_sigmask(&set);
+
+ /* restore registers */
+
+ if (target_rt_restore_ucontext(env, &frame->uc))
+ goto badframe;
+
+ if (do_sigaltstack(frame_addr +
+ offsetof(struct target_rt_sigframe, uc.tuc_stack),
+ 0, get_sp_from_cpustate(env)) == -EFAULT)
+ goto badframe;
+
+ unlock_user_struct(frame, frame_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+
+badframe:
+ unlock_user_struct(frame, frame_addr, 0);
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
diff --git a/linux-user/m68k/target_signal.h b/linux-user/m68k/target_signal.h
index 9d2d7343f8..ff303f2b3c 100644
--- a/linux-user/m68k/target_signal.h
+++ b/linux-user/m68k/target_signal.h
@@ -26,5 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUM68KState *state)
return state->aregs[7];
}
-
+#define TARGET_ARCH_HAS_SETUP_FRAME
#endif /* M68K_TARGET_SIGNAL_H */
diff --git a/linux-user/main.c b/linux-user/main.c
index 8907a84114..32347545c9 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -33,9 +33,9 @@
#include "qemu/timer.h"
#include "qemu/envlist.h"
#include "elf.h"
-#include "exec/log.h"
#include "trace/control.h"
#include "target_elf.h"
+#include "cpu_loop-common.h"
char *exec_path;
@@ -50,17 +50,6 @@ unsigned long mmap_min_addr;
unsigned long guest_base;
int have_guest_base;
-#define EXCP_DUMP(env, fmt, ...) \
-do { \
- CPUState *cs = ENV_GET_CPU(env); \
- fprintf(stderr, fmt , ## __VA_ARGS__); \
- cpu_dump_state(cs, stderr, fprintf, 0); \
- if (qemu_log_separate()) { \
- qemu_log(fmt, ## __VA_ARGS__); \
- log_cpu_state(cs, 0); \
- } \
-} while (0)
-
/*
* When running 32-on-64 we should make sure we can fit all of the possible
* guest address space into a contiguous chunk of virtual host memory.
@@ -160,3927 +149,6 @@ void fork_end(int child)
}
}
-#ifdef TARGET_I386
-/***********************************************************/
-/* CPUX86 core interface */
-
-uint64_t cpu_get_tsc(CPUX86State *env)
-{
- return cpu_get_host_ticks();
-}
-
-static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
- int flags)
-{
- unsigned int e1, e2;
- uint32_t *p;
- e1 = (addr << 16) | (limit & 0xffff);
- e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
- e2 |= flags;
- p = ptr;
- p[0] = tswap32(e1);
- p[1] = tswap32(e2);
-}
-
-static uint64_t *idt_table;
-#ifdef TARGET_X86_64
-static void set_gate64(void *ptr, unsigned int type, unsigned int dpl,
- uint64_t addr, unsigned int sel)
-{
- uint32_t *p, e1, e2;
- e1 = (addr & 0xffff) | (sel << 16);
- e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
- p = ptr;
- p[0] = tswap32(e1);
- p[1] = tswap32(e2);
- p[2] = tswap32(addr >> 32);
- p[3] = 0;
-}
-/* only dpl matters as we do only user space emulation */
-static void set_idt(int n, unsigned int dpl)
-{
- set_gate64(idt_table + n * 2, 0, dpl, 0, 0);
-}
-#else
-static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
- uint32_t addr, unsigned int sel)
-{
- uint32_t *p, e1, e2;
- e1 = (addr & 0xffff) | (sel << 16);
- e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
- p = ptr;
- p[0] = tswap32(e1);
- p[1] = tswap32(e2);
-}
-
-/* only dpl matters as we do only user space emulation */
-static void set_idt(int n, unsigned int dpl)
-{
- set_gate(idt_table + n, 0, dpl, 0, 0);
-}
-#endif
-
-void cpu_loop(CPUX86State *env)
-{
- CPUState *cs = CPU(x86_env_get_cpu(env));
- int trapnr;
- abi_ulong pc;
- abi_ulong ret;
- target_siginfo_t info;
-
- for(;;) {
- cpu_exec_start(cs);
- trapnr = cpu_exec(cs);
- cpu_exec_end(cs);
- process_queued_cpu_work(cs);
-
- switch(trapnr) {
- case 0x80:
- /* linux syscall from int $0x80 */
- ret = do_syscall(env,
- env->regs[R_EAX],
- env->regs[R_EBX],
- env->regs[R_ECX],
- env->regs[R_EDX],
- env->regs[R_ESI],
- env->regs[R_EDI],
- env->regs[R_EBP],
- 0, 0);
- if (ret == -TARGET_ERESTARTSYS) {
- env->eip -= 2;
- } else if (ret != -TARGET_QEMU_ESIGRETURN) {
- env->regs[R_EAX] = ret;
- }
- break;
-#ifndef TARGET_ABI32
- case EXCP_SYSCALL:
- /* linux syscall from syscall instruction */
- ret = do_syscall(env,
- env->regs[R_EAX],
- env->regs[R_EDI],
- env->regs[R_ESI],
- env->regs[R_EDX],
- env->regs[10],
- env->regs[8],
- env->regs[9],
- 0, 0);
- if (ret == -TARGET_ERESTARTSYS) {
- env->eip -= 2;
- } else if (ret != -TARGET_QEMU_ESIGRETURN) {
- env->regs[R_EAX] = ret;
- }
- break;
-#endif
- case EXCP0B_NOSEG:
- case EXCP0C_STACK:
- info.si_signo = TARGET_SIGBUS;
- info.si_errno = 0;
- info.si_code = TARGET_SI_KERNEL;
- info._sifields._sigfault._addr = 0;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP0D_GPF:
- /* XXX: potential problem if ABI32 */
-#ifndef TARGET_X86_64
- if (env->eflags & VM_MASK) {
- handle_vm86_fault(env);
- } else
-#endif
- {
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SI_KERNEL;
- info._sifields._sigfault._addr = 0;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- break;
- case EXCP0E_PAGE:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- if (!(env->error_code & 1))
- info.si_code = TARGET_SEGV_MAPERR;
- else
- info.si_code = TARGET_SEGV_ACCERR;
- info._sifields._sigfault._addr = env->cr[2];
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP00_DIVZ:
-#ifndef TARGET_X86_64
- if (env->eflags & VM_MASK) {
- handle_vm86_trap(env, trapnr);
- } else
-#endif
- {
- /* division by zero */
- info.si_signo = TARGET_SIGFPE;
- info.si_errno = 0;
- info.si_code = TARGET_FPE_INTDIV;
- info._sifields._sigfault._addr = env->eip;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- break;
- case EXCP01_DB:
- case EXCP03_INT3:
-#ifndef TARGET_X86_64
- if (env->eflags & VM_MASK) {
- handle_vm86_trap(env, trapnr);
- } else
-#endif
- {
- info.si_signo = TARGET_SIGTRAP;
- info.si_errno = 0;
- if (trapnr == EXCP01_DB) {
- info.si_code = TARGET_TRAP_BRKPT;
- info._sifields._sigfault._addr = env->eip;
- } else {
- info.si_code = TARGET_SI_KERNEL;
- info._sifields._sigfault._addr = 0;
- }
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- break;
- case EXCP04_INTO:
- case EXCP05_BOUND:
-#ifndef TARGET_X86_64
- if (env->eflags & VM_MASK) {
- handle_vm86_trap(env, trapnr);
- } else
-#endif
- {
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SI_KERNEL;
- info._sifields._sigfault._addr = 0;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- break;
- case EXCP06_ILLOP:
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLOPN;
- info._sifields._sigfault._addr = env->eip;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP_INTERRUPT:
- /* just indicate that signals should be handled asap */
- break;
- case EXCP_DEBUG:
- {
- int sig;
-
- sig = gdb_handlesig(cs, TARGET_SIGTRAP);
- if (sig)
- {
- info.si_signo = sig;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- }
- break;
- case EXCP_ATOMIC:
- cpu_exec_step_atomic(cs);
- break;
- default:
- pc = env->segs[R_CS].base + env->eip;
- EXCP_DUMP(env, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
- (long)pc, trapnr);
- abort();
- }
- process_pending_signals(env);
- }
-}
-#endif
-
-#ifdef TARGET_ARM
-
-#define get_user_code_u32(x, gaddr, env) \
- ({ abi_long __r = get_user_u32((x), (gaddr)); \
- if (!__r && bswap_code(arm_sctlr_b(env))) { \
- (x) = bswap32(x); \
- } \
- __r; \
- })
-
-#define get_user_code_u16(x, gaddr, env) \
- ({ abi_long __r = get_user_u16((x), (gaddr)); \
- if (!__r && bswap_code(arm_sctlr_b(env))) { \
- (x) = bswap16(x); \
- } \
- __r; \
- })
-
-#define get_user_data_u32(x, gaddr, env) \
- ({ abi_long __r = get_user_u32((x), (gaddr)); \
- if (!__r && arm_cpu_bswap_data(env)) { \
- (x) = bswap32(x); \
- } \
- __r; \
- })
-
-#define get_user_data_u16(x, gaddr, env) \
- ({ abi_long __r = get_user_u16((x), (gaddr)); \
- if (!__r && arm_cpu_bswap_data(env)) { \
- (x) = bswap16(x); \
- } \
- __r; \
- })
-
-#define put_user_data_u32(x, gaddr, env) \
- ({ typeof(x) __x = (x); \
- if (arm_cpu_bswap_data(env)) { \
- __x = bswap32(__x); \
- } \
- put_user_u32(__x, (gaddr)); \
- })
-
-#define put_user_data_u16(x, gaddr, env) \
- ({ typeof(x) __x = (x); \
- if (arm_cpu_bswap_data(env)) { \
- __x = bswap16(__x); \
- } \
- put_user_u16(__x, (gaddr)); \
- })
-
-#ifdef TARGET_ABI32
-/* Commpage handling -- there is no commpage for AArch64 */
-
-/*
- * See the Linux kernel's Documentation/arm/kernel_user_helpers.txt
- * Input:
- * r0 = pointer to oldval
- * r1 = pointer to newval
- * r2 = pointer to target value
- *
- * Output:
- * r0 = 0 if *ptr was changed, non-0 if no exchange happened
- * C set if *ptr was changed, clear if no exchange happened
- *
- * Note segv's in kernel helpers are a bit tricky, we can set the
- * data address sensibly but the PC address is just the entry point.
- */
-static void arm_kernel_cmpxchg64_helper(CPUARMState *env)
-{
- uint64_t oldval, newval, val;
- uint32_t addr, cpsr;
- target_siginfo_t info;
-
- /* Based on the 32 bit code in do_kernel_trap */
-
- /* XXX: This only works between threads, not between processes.
- It's probably possible to implement this with native host
- operations. However things like ldrex/strex are much harder so
- there's not much point trying. */
- start_exclusive();
- cpsr = cpsr_read(env);
- addr = env->regs[2];
-
- if (get_user_u64(oldval, env->regs[0])) {
- env->exception.vaddress = env->regs[0];
- goto segv;
- };
-
- if (get_user_u64(newval, env->regs[1])) {
- env->exception.vaddress = env->regs[1];
- goto segv;
- };
-
- if (get_user_u64(val, addr)) {
- env->exception.vaddress = addr;
- goto segv;
- }
-
- if (val == oldval) {
- val = newval;
-
- if (put_user_u64(val, addr)) {
- env->exception.vaddress = addr;
- goto segv;
- };
-
- env->regs[0] = 0;
- cpsr |= CPSR_C;
- } else {
- env->regs[0] = -1;
- cpsr &= ~CPSR_C;
- }
- cpsr_write(env, cpsr, CPSR_C, CPSRWriteByInstr);
- end_exclusive();
- return;
-
-segv:
- end_exclusive();
- /* We get the PC of the entry address - which is as good as anything,
- on a real kernel what you get depends on which mode it uses. */
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = env->exception.vaddress;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
-}
-
-/* Handle a jump to the kernel code page. */
-static int
-do_kernel_trap(CPUARMState *env)
-{
- uint32_t addr;
- uint32_t cpsr;
- uint32_t val;
-
- switch (env->regs[15]) {
- case 0xffff0fa0: /* __kernel_memory_barrier */
- /* ??? No-op. Will need to do better for SMP. */
- break;
- case 0xffff0fc0: /* __kernel_cmpxchg */
- /* XXX: This only works between threads, not between processes.
- It's probably possible to implement this with native host
- operations. However things like ldrex/strex are much harder so
- there's not much point trying. */
- start_exclusive();
- cpsr = cpsr_read(env);
- addr = env->regs[2];
- /* FIXME: This should SEGV if the access fails. */
- if (get_user_u32(val, addr))
- val = ~env->regs[0];
- if (val == env->regs[0]) {
- val = env->regs[1];
- /* FIXME: Check for segfaults. */
- put_user_u32(val, addr);
- env->regs[0] = 0;
- cpsr |= CPSR_C;
- } else {
- env->regs[0] = -1;
- cpsr &= ~CPSR_C;
- }
- cpsr_write(env, cpsr, CPSR_C, CPSRWriteByInstr);
- end_exclusive();
- break;
- case 0xffff0fe0: /* __kernel_get_tls */
- env->regs[0] = cpu_get_tls(env);
- break;
- case 0xffff0f60: /* __kernel_cmpxchg64 */
- arm_kernel_cmpxchg64_helper(env);
- break;
-
- default:
- return 1;
- }
- /* Jump back to the caller. */
- addr = env->regs[14];
- if (addr & 1) {
- env->thumb = 1;
- addr &= ~1;
- }
- env->regs[15] = addr;
-
- return 0;
-}
-
-void cpu_loop(CPUARMState *env)
-{
- CPUState *cs = CPU(arm_env_get_cpu(env));
- int trapnr;
- unsigned int n, insn;
- target_siginfo_t info;
- uint32_t addr;
- abi_ulong ret;
-
- for(;;) {
- cpu_exec_start(cs);
- trapnr = cpu_exec(cs);
- cpu_exec_end(cs);
- process_queued_cpu_work(cs);
-
- switch(trapnr) {
- case EXCP_UDEF:
- case EXCP_NOCP:
- case EXCP_INVSTATE:
- {
- TaskState *ts = cs->opaque;
- uint32_t opcode;
- int rc;
-
- /* we handle the FPU emulation here, as Linux */
- /* we get the opcode */
- /* FIXME - what to do if get_user() fails? */
- get_user_code_u32(opcode, env->regs[15], env);
-
- rc = EmulateAll(opcode, &ts->fpa, env);
- if (rc == 0) { /* illegal instruction */
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLOPN;
- info._sifields._sigfault._addr = env->regs[15];
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- } else if (rc < 0) { /* FP exception */
- int arm_fpe=0;
-
- /* translate softfloat flags to FPSR flags */
- if (-rc & float_flag_invalid)
- arm_fpe |= BIT_IOC;
- if (-rc & float_flag_divbyzero)
- arm_fpe |= BIT_DZC;
- if (-rc & float_flag_overflow)
- arm_fpe |= BIT_OFC;
- if (-rc & float_flag_underflow)
- arm_fpe |= BIT_UFC;
- if (-rc & float_flag_inexact)
- arm_fpe |= BIT_IXC;
-
- FPSR fpsr = ts->fpa.fpsr;
- //printf("fpsr 0x%x, arm_fpe 0x%x\n",fpsr,arm_fpe);
-
- if (fpsr & (arm_fpe << 16)) { /* exception enabled? */
- info.si_signo = TARGET_SIGFPE;
- info.si_errno = 0;
-
- /* ordered by priority, least first */
- if (arm_fpe & BIT_IXC) info.si_code = TARGET_FPE_FLTRES;
- if (arm_fpe & BIT_UFC) info.si_code = TARGET_FPE_FLTUND;
- if (arm_fpe & BIT_OFC) info.si_code = TARGET_FPE_FLTOVF;
- if (arm_fpe & BIT_DZC) info.si_code = TARGET_FPE_FLTDIV;
- if (arm_fpe & BIT_IOC) info.si_code = TARGET_FPE_FLTINV;
-
- info._sifields._sigfault._addr = env->regs[15];
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- } else {
- env->regs[15] += 4;
- }
-
- /* accumulate unenabled exceptions */
- if ((!(fpsr & BIT_IXE)) && (arm_fpe & BIT_IXC))
- fpsr |= BIT_IXC;
- if ((!(fpsr & BIT_UFE)) && (arm_fpe & BIT_UFC))
- fpsr |= BIT_UFC;
- if ((!(fpsr & BIT_OFE)) && (arm_fpe & BIT_OFC))
- fpsr |= BIT_OFC;
- if ((!(fpsr & BIT_DZE)) && (arm_fpe & BIT_DZC))
- fpsr |= BIT_DZC;
- if ((!(fpsr & BIT_IOE)) && (arm_fpe & BIT_IOC))
- fpsr |= BIT_IOC;
- ts->fpa.fpsr=fpsr;
- } else { /* everything OK */
- /* increment PC */
- env->regs[15] += 4;
- }
- }
- break;
- case EXCP_SWI:
- case EXCP_BKPT:
- {
- env->eabi = 1;
- /* system call */
- if (trapnr == EXCP_BKPT) {
- if (env->thumb) {
- /* FIXME - what to do if get_user() fails? */
- get_user_code_u16(insn, env->regs[15], env);
- n = insn & 0xff;
- env->regs[15] += 2;
- } else {
- /* FIXME - what to do if get_user() fails? */
- get_user_code_u32(insn, env->regs[15], env);
- n = (insn & 0xf) | ((insn >> 4) & 0xff0);
- env->regs[15] += 4;
- }
- } else {
- if (env->thumb) {
- /* FIXME - what to do if get_user() fails? */
- get_user_code_u16(insn, env->regs[15] - 2, env);
- n = insn & 0xff;
- } else {
- /* FIXME - what to do if get_user() fails? */
- get_user_code_u32(insn, env->regs[15] - 4, env);
- n = insn & 0xffffff;
- }
- }
-
- if (n == ARM_NR_cacheflush) {
- /* nop */
- } else if (n == ARM_NR_semihosting
- || n == ARM_NR_thumb_semihosting) {
- env->regs[0] = do_arm_semihosting (env);
- } else if (n == 0 || n >= ARM_SYSCALL_BASE || env->thumb) {
- /* linux syscall */
- if (env->thumb || n == 0) {
- n = env->regs[7];
- } else {
- n -= ARM_SYSCALL_BASE;
- env->eabi = 0;
- }
- if ( n > ARM_NR_BASE) {
- switch (n) {
- case ARM_NR_cacheflush:
- /* nop */
- break;
- case ARM_NR_set_tls:
- cpu_set_tls(env, env->regs[0]);
- env->regs[0] = 0;
- break;
- case ARM_NR_breakpoint:
- env->regs[15] -= env->thumb ? 2 : 4;
- goto excp_debug;
- default:
- gemu_log("qemu: Unsupported ARM syscall: 0x%x\n",
- n);
- env->regs[0] = -TARGET_ENOSYS;
- break;
- }
- } else {
- ret = do_syscall(env,
- n,
- env->regs[0],
- env->regs[1],
- env->regs[2],
- env->regs[3],
- env->regs[4],
- env->regs[5],
- 0, 0);
- if (ret == -TARGET_ERESTARTSYS) {
- env->regs[15] -= env->thumb ? 2 : 4;
- } else if (ret != -TARGET_QEMU_ESIGRETURN) {
- env->regs[0] = ret;
- }
- }
- } else {
- goto error;
- }
- }
- break;
- case EXCP_SEMIHOST:
- env->regs[0] = do_arm_semihosting(env);
- break;
- case EXCP_INTERRUPT:
- /* just indicate that signals should be handled asap */
- break;
- case EXCP_PREFETCH_ABORT:
- case EXCP_DATA_ABORT:
- addr = env->exception.vaddress;
- {
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = addr;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- break;
- case EXCP_DEBUG:
- excp_debug:
- {
- int sig;
-
- sig = gdb_handlesig(cs, TARGET_SIGTRAP);
- if (sig)
- {
- info.si_signo = sig;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- }
- break;
- case EXCP_KERNEL_TRAP:
- if (do_kernel_trap(env))
- goto error;
- break;
- case EXCP_YIELD:
- /* nothing to do here for user-mode, just resume guest code */
- break;
- case EXCP_ATOMIC:
- cpu_exec_step_atomic(cs);
- break;
- default:
- error:
- EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
- abort();
- }
- process_pending_signals(env);
- }
-}
-
-#else
-
-/* AArch64 main loop */
-void cpu_loop(CPUARMState *env)
-{
- CPUState *cs = CPU(arm_env_get_cpu(env));
- int trapnr, sig;
- abi_long ret;
- target_siginfo_t info;
-
- for (;;) {
- cpu_exec_start(cs);
- trapnr = cpu_exec(cs);
- cpu_exec_end(cs);
- process_queued_cpu_work(cs);
-
- switch (trapnr) {
- case EXCP_SWI:
- ret = do_syscall(env,
- env->xregs[8],
- env->xregs[0],
- env->xregs[1],
- env->xregs[2],
- env->xregs[3],
- env->xregs[4],
- env->xregs[5],
- 0, 0);
- if (ret == -TARGET_ERESTARTSYS) {
- env->pc -= 4;
- } else if (ret != -TARGET_QEMU_ESIGRETURN) {
- env->xregs[0] = ret;
- }
- break;
- case EXCP_INTERRUPT:
- /* just indicate that signals should be handled asap */
- break;
- case EXCP_UDEF:
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLOPN;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP_PREFETCH_ABORT:
- case EXCP_DATA_ABORT:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = env->exception.vaddress;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP_DEBUG:
- case EXCP_BKPT:
- sig = gdb_handlesig(cs, TARGET_SIGTRAP);
- if (sig) {
- info.si_signo = sig;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- break;
- case EXCP_SEMIHOST:
- env->xregs[0] = do_arm_semihosting(env);
- break;
- case EXCP_YIELD:
- /* nothing to do here for user-mode, just resume guest code */
- break;
- case EXCP_ATOMIC:
- cpu_exec_step_atomic(cs);
- break;
- default:
- EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
- abort();
- }
- process_pending_signals(env);
- /* Exception return on AArch64 always clears the exclusive monitor,
- * so any return to running guest code implies this.
- */
- env->exclusive_addr = -1;
- }
-}
-#endif /* ndef TARGET_ABI32 */
-
-#endif
-
-#ifdef TARGET_SPARC
-#define SPARC64_STACK_BIAS 2047
-
-//#define DEBUG_WIN
-
-/* WARNING: dealing with register windows _is_ complicated. More info
- can be found at http://www.sics.se/~psm/sparcstack.html */
-static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
-{
- index = (index + cwp * 16) % (16 * env->nwindows);
- /* wrap handling : if cwp is on the last window, then we use the
- registers 'after' the end */
- if (index < 8 && env->cwp == env->nwindows - 1)
- index += 16 * env->nwindows;
- return index;
-}
-
-/* save the register window 'cwp1' */
-static inline void save_window_offset(CPUSPARCState *env, int cwp1)
-{
- unsigned int i;
- abi_ulong sp_ptr;
-
- sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
-#ifdef TARGET_SPARC64
- if (sp_ptr & 3)
- sp_ptr += SPARC64_STACK_BIAS;
-#endif
-#if defined(DEBUG_WIN)
- printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
- sp_ptr, cwp1);
-#endif
- for(i = 0; i < 16; i++) {
- /* FIXME - what to do if put_user() fails? */
- put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
- sp_ptr += sizeof(abi_ulong);
- }
-}
-
-static void save_window(CPUSPARCState *env)
-{
-#ifndef TARGET_SPARC64
- unsigned int new_wim;
- new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) &
- ((1LL << env->nwindows) - 1);
- save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
- env->wim = new_wim;
-#else
- save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
- env->cansave++;
- env->canrestore--;
-#endif
-}
-
-static void restore_window(CPUSPARCState *env)
-{
-#ifndef TARGET_SPARC64
- unsigned int new_wim;
-#endif
- unsigned int i, cwp1;
- abi_ulong sp_ptr;
-
-#ifndef TARGET_SPARC64
- new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) &
- ((1LL << env->nwindows) - 1);
-#endif
-
- /* restore the invalid window */
- cwp1 = cpu_cwp_inc(env, env->cwp + 1);
- sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
-#ifdef TARGET_SPARC64
- if (sp_ptr & 3)
- sp_ptr += SPARC64_STACK_BIAS;
-#endif
-#if defined(DEBUG_WIN)
- printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
- sp_ptr, cwp1);
-#endif
- for(i = 0; i < 16; i++) {
- /* FIXME - what to do if get_user() fails? */
- get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
- sp_ptr += sizeof(abi_ulong);
- }
-#ifdef TARGET_SPARC64
- env->canrestore++;
- if (env->cleanwin < env->nwindows - 1)
- env->cleanwin++;
- env->cansave--;
-#else
- env->wim = new_wim;
-#endif
-}
-
-static void flush_windows(CPUSPARCState *env)
-{
- int offset, cwp1;
-
- offset = 1;
- for(;;) {
- /* if restore would invoke restore_window(), then we can stop */
- cwp1 = cpu_cwp_inc(env, env->cwp + offset);
-#ifndef TARGET_SPARC64
- if (env->wim & (1 << cwp1))
- break;
-#else
- if (env->canrestore == 0)
- break;
- env->cansave++;
- env->canrestore--;
-#endif
- save_window_offset(env, cwp1);
- offset++;
- }
- cwp1 = cpu_cwp_inc(env, env->cwp + 1);
-#ifndef TARGET_SPARC64
- /* set wim so that restore will reload the registers */
- env->wim = 1 << cwp1;
-#endif
-#if defined(DEBUG_WIN)
- printf("flush_windows: nb=%d\n", offset - 1);
-#endif
-}
-
-void cpu_loop (CPUSPARCState *env)
-{
- CPUState *cs = CPU(sparc_env_get_cpu(env));
- int trapnr;
- abi_long ret;
- target_siginfo_t info;
-
- while (1) {
- cpu_exec_start(cs);
- trapnr = cpu_exec(cs);
- cpu_exec_end(cs);
- process_queued_cpu_work(cs);
-
- /* Compute PSR before exposing state. */
- if (env->cc_op != CC_OP_FLAGS) {
- cpu_get_psr(env);
- }
-
- switch (trapnr) {
-#ifndef TARGET_SPARC64
- case 0x88:
- case 0x90:
-#else
- case 0x110:
- case 0x16d:
-#endif
- ret = do_syscall (env, env->gregs[1],
- env->regwptr[0], env->regwptr[1],
- env->regwptr[2], env->regwptr[3],
- env->regwptr[4], env->regwptr[5],
- 0, 0);
- if (ret == -TARGET_ERESTARTSYS || ret == -TARGET_QEMU_ESIGRETURN) {
- break;
- }
- if ((abi_ulong)ret >= (abi_ulong)(-515)) {
-#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
- env->xcc |= PSR_CARRY;
-#else
- env->psr |= PSR_CARRY;
-#endif
- ret = -ret;
- } else {
-#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
- env->xcc &= ~PSR_CARRY;
-#else
- env->psr &= ~PSR_CARRY;
-#endif
- }
- env->regwptr[0] = ret;
- /* next instruction */
- env->pc = env->npc;
- env->npc = env->npc + 4;
- break;
- case 0x83: /* flush windows */
-#ifdef TARGET_ABI32
- case 0x103:
-#endif
- flush_windows(env);
- /* next instruction */
- env->pc = env->npc;
- env->npc = env->npc + 4;
- break;
-#ifndef TARGET_SPARC64
- case TT_WIN_OVF: /* window overflow */
- save_window(env);
- break;
- case TT_WIN_UNF: /* window underflow */
- restore_window(env);
- break;
- case TT_TFAULT:
- case TT_DFAULT:
- {
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = env->mmuregs[4];
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- break;
-#else
- case TT_SPILL: /* window overflow */
- save_window(env);
- break;
- case TT_FILL: /* window underflow */
- restore_window(env);
- break;
- case TT_TFAULT:
- case TT_DFAULT:
- {
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
- if (trapnr == TT_DFAULT)
- info._sifields._sigfault._addr = env->dmmu.mmuregs[4];
- else
- info._sifields._sigfault._addr = cpu_tsptr(env)->tpc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- break;
-#ifndef TARGET_ABI32
- case 0x16e:
- flush_windows(env);
- sparc64_get_context(env);
- break;
- case 0x16f:
- flush_windows(env);
- sparc64_set_context(env);
- break;
-#endif
-#endif
- case EXCP_INTERRUPT:
- /* just indicate that signals should be handled asap */
- break;
- case TT_ILL_INSN:
- {
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLOPC;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- break;
- case EXCP_DEBUG:
- {
- int sig;
-
- sig = gdb_handlesig(cs, TARGET_SIGTRAP);
- if (sig)
- {
- info.si_signo = sig;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- }
- break;
- case EXCP_ATOMIC:
- cpu_exec_step_atomic(cs);
- break;
- default:
- printf ("Unhandled trap: 0x%x\n", trapnr);
- cpu_dump_state(cs, stderr, fprintf, 0);
- exit(EXIT_FAILURE);
- }
- process_pending_signals (env);
- }
-}
-
-#endif
-
-#ifdef TARGET_PPC
-static inline uint64_t cpu_ppc_get_tb(CPUPPCState *env)
-{
- return cpu_get_host_ticks();
-}
-
-uint64_t cpu_ppc_load_tbl(CPUPPCState *env)
-{
- return cpu_ppc_get_tb(env);
-}
-
-uint32_t cpu_ppc_load_tbu(CPUPPCState *env)
-{
- return cpu_ppc_get_tb(env) >> 32;
-}
-
-uint64_t cpu_ppc_load_atbl(CPUPPCState *env)
-{
- return cpu_ppc_get_tb(env);
-}
-
-uint32_t cpu_ppc_load_atbu(CPUPPCState *env)
-{
- return cpu_ppc_get_tb(env) >> 32;
-}
-
-uint32_t cpu_ppc601_load_rtcu(CPUPPCState *env)
-__attribute__ (( alias ("cpu_ppc_load_tbu") ));
-
-uint32_t cpu_ppc601_load_rtcl(CPUPPCState *env)
-{
- return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
-}
-
-/* XXX: to be fixed */
-int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
-{
- return -1;
-}
-
-int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
-{
- return -1;
-}
-
-static int do_store_exclusive(CPUPPCState *env)
-{
- target_ulong addr;
- target_ulong page_addr;
- target_ulong val, val2 __attribute__((unused)) = 0;
- int flags;
- int segv = 0;
-
- addr = env->reserve_ea;
- page_addr = addr & TARGET_PAGE_MASK;
- start_exclusive();
- mmap_lock();
- flags = page_get_flags(page_addr);
- if ((flags & PAGE_READ) == 0) {
- segv = 1;
- } else {
- int reg = env->reserve_info & 0x1f;
- int size = env->reserve_info >> 5;
- int stored = 0;
-
- if (addr == env->reserve_addr) {
- switch (size) {
- case 1: segv = get_user_u8(val, addr); break;
- case 2: segv = get_user_u16(val, addr); break;
- case 4: segv = get_user_u32(val, addr); break;
-#if defined(TARGET_PPC64)
- case 8: segv = get_user_u64(val, addr); break;
- case 16: {
- segv = get_user_u64(val, addr);
- if (!segv) {
- segv = get_user_u64(val2, addr + 8);
- }
- break;
- }
-#endif
- default: abort();
- }
- if (!segv && val == env->reserve_val) {
- val = env->gpr[reg];
- switch (size) {
- case 1: segv = put_user_u8(val, addr); break;
- case 2: segv = put_user_u16(val, addr); break;
- case 4: segv = put_user_u32(val, addr); break;
-#if defined(TARGET_PPC64)
- case 8: segv = put_user_u64(val, addr); break;
- case 16: {
- if (val2 == env->reserve_val2) {
- if (msr_le) {
- val2 = val;
- val = env->gpr[reg+1];
- } else {
- val2 = env->gpr[reg+1];
- }
- segv = put_user_u64(val, addr);
- if (!segv) {
- segv = put_user_u64(val2, addr + 8);
- }
- }
- break;
- }
-#endif
- default: abort();
- }
- if (!segv) {
- stored = 1;
- }
- }
- }
- env->crf[0] = (stored << 1) | xer_so;
- env->reserve_addr = (target_ulong)-1;
- }
- if (!segv) {
- env->nip += 4;
- }
- mmap_unlock();
- end_exclusive();
- return segv;
-}
-
-void cpu_loop(CPUPPCState *env)
-{
- CPUState *cs = CPU(ppc_env_get_cpu(env));
- target_siginfo_t info;
- int trapnr;
- target_ulong ret;
-
- for(;;) {
- cpu_exec_start(cs);
- trapnr = cpu_exec(cs);
- cpu_exec_end(cs);
- process_queued_cpu_work(cs);
-
- switch(trapnr) {
- case POWERPC_EXCP_NONE:
- /* Just go on */
- break;
- case POWERPC_EXCP_CRITICAL: /* Critical input */
- cpu_abort(cs, "Critical interrupt while in user mode. "
- "Aborting\n");
- break;
- case POWERPC_EXCP_MCHECK: /* Machine check exception */
- cpu_abort(cs, "Machine check exception while in user mode. "
- "Aborting\n");
- break;
- case POWERPC_EXCP_DSI: /* Data storage exception */
- /* XXX: check this. Seems bugged */
- switch (env->error_code & 0xFF000000) {
- case 0x40000000:
- case 0x42000000:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_MAPERR;
- break;
- case 0x04000000:
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLADR;
- break;
- case 0x08000000:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_ACCERR;
- break;
- default:
- /* Let's send a regular segfault... */
- EXCP_DUMP(env, "Invalid segfault errno (%02x)\n",
- env->error_code);
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_MAPERR;
- break;
- }
- info._sifields._sigfault._addr = env->spr[SPR_DAR];
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case POWERPC_EXCP_ISI: /* Instruction storage exception */
- /* XXX: check this */
- switch (env->error_code & 0xFF000000) {
- case 0x40000000:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_MAPERR;
- break;
- case 0x10000000:
- case 0x08000000:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_ACCERR;
- break;
- default:
- /* Let's send a regular segfault... */
- EXCP_DUMP(env, "Invalid segfault errno (%02x)\n",
- env->error_code);
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_MAPERR;
- break;
- }
- info._sifields._sigfault._addr = env->nip - 4;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case POWERPC_EXCP_EXTERNAL: /* External input */
- cpu_abort(cs, "External interrupt while in user mode. "
- "Aborting\n");
- break;
- case POWERPC_EXCP_ALIGN: /* Alignment exception */
- /* XXX: check this */
- info.si_signo = TARGET_SIGBUS;
- info.si_errno = 0;
- info.si_code = TARGET_BUS_ADRALN;
- info._sifields._sigfault._addr = env->nip;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case POWERPC_EXCP_PROGRAM: /* Program exception */
- case POWERPC_EXCP_HV_EMU: /* HV emulation */
- /* XXX: check this */
- switch (env->error_code & ~0xF) {
- case POWERPC_EXCP_FP:
- info.si_signo = TARGET_SIGFPE;
- info.si_errno = 0;
- switch (env->error_code & 0xF) {
- case POWERPC_EXCP_FP_OX:
- info.si_code = TARGET_FPE_FLTOVF;
- break;
- case POWERPC_EXCP_FP_UX:
- info.si_code = TARGET_FPE_FLTUND;
- break;
- case POWERPC_EXCP_FP_ZX:
- case POWERPC_EXCP_FP_VXZDZ:
- info.si_code = TARGET_FPE_FLTDIV;
- break;
- case POWERPC_EXCP_FP_XX:
- info.si_code = TARGET_FPE_FLTRES;
- break;
- case POWERPC_EXCP_FP_VXSOFT:
- info.si_code = TARGET_FPE_FLTINV;
- break;
- case POWERPC_EXCP_FP_VXSNAN:
- case POWERPC_EXCP_FP_VXISI:
- case POWERPC_EXCP_FP_VXIDI:
- case POWERPC_EXCP_FP_VXIMZ:
- case POWERPC_EXCP_FP_VXVC:
- case POWERPC_EXCP_FP_VXSQRT:
- case POWERPC_EXCP_FP_VXCVI:
- info.si_code = TARGET_FPE_FLTSUB;
- break;
- default:
- EXCP_DUMP(env, "Unknown floating point exception (%02x)\n",
- env->error_code);
- break;
- }
- break;
- case POWERPC_EXCP_INVAL:
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- switch (env->error_code & 0xF) {
- case POWERPC_EXCP_INVAL_INVAL:
- info.si_code = TARGET_ILL_ILLOPC;
- break;
- case POWERPC_EXCP_INVAL_LSWX:
- info.si_code = TARGET_ILL_ILLOPN;
- break;
- case POWERPC_EXCP_INVAL_SPR:
- info.si_code = TARGET_ILL_PRVREG;
- break;
- case POWERPC_EXCP_INVAL_FP:
- info.si_code = TARGET_ILL_COPROC;
- break;
- default:
- EXCP_DUMP(env, "Unknown invalid operation (%02x)\n",
- env->error_code & 0xF);
- info.si_code = TARGET_ILL_ILLADR;
- break;
- }
- break;
- case POWERPC_EXCP_PRIV:
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- switch (env->error_code & 0xF) {
- case POWERPC_EXCP_PRIV_OPC:
- info.si_code = TARGET_ILL_PRVOPC;
- break;
- case POWERPC_EXCP_PRIV_REG:
- info.si_code = TARGET_ILL_PRVREG;
- break;
- default:
- EXCP_DUMP(env, "Unknown privilege violation (%02x)\n",
- env->error_code & 0xF);
- info.si_code = TARGET_ILL_PRVOPC;
- break;
- }
- break;
- case POWERPC_EXCP_TRAP:
- cpu_abort(cs, "Tried to call a TRAP\n");
- break;
- default:
- /* Should not happen ! */
- cpu_abort(cs, "Unknown program exception (%02x)\n",
- env->error_code);
- break;
- }
- info._sifields._sigfault._addr = env->nip;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_COPROC;
- info._sifields._sigfault._addr = env->nip;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case POWERPC_EXCP_SYSCALL: /* System call exception */
- cpu_abort(cs, "Syscall exception while in user mode. "
- "Aborting\n");
- break;
- case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_COPROC;
- info._sifields._sigfault._addr = env->nip;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case POWERPC_EXCP_DECR: /* Decrementer exception */
- cpu_abort(cs, "Decrementer interrupt while in user mode. "
- "Aborting\n");
- break;
- case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
- cpu_abort(cs, "Fix interval timer interrupt while in user mode. "
- "Aborting\n");
- break;
- case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
- cpu_abort(cs, "Watchdog timer interrupt while in user mode. "
- "Aborting\n");
- break;
- case POWERPC_EXCP_DTLB: /* Data TLB error */
- cpu_abort(cs, "Data TLB exception while in user mode. "
- "Aborting\n");
- break;
- case POWERPC_EXCP_ITLB: /* Instruction TLB error */
- cpu_abort(cs, "Instruction TLB exception while in user mode. "
- "Aborting\n");
- break;
- case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavail. */
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_COPROC;
- info._sifields._sigfault._addr = env->nip;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case POWERPC_EXCP_EFPDI: /* Embedded floating-point data IRQ */
- cpu_abort(cs, "Embedded floating-point data IRQ not handled\n");
- break;
- case POWERPC_EXCP_EFPRI: /* Embedded floating-point round IRQ */
- cpu_abort(cs, "Embedded floating-point round IRQ not handled\n");
- break;
- case POWERPC_EXCP_EPERFM: /* Embedded performance monitor IRQ */
- cpu_abort(cs, "Performance monitor exception not handled\n");
- break;
- case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
- cpu_abort(cs, "Doorbell interrupt while in user mode. "
- "Aborting\n");
- break;
- case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
- cpu_abort(cs, "Doorbell critical interrupt while in user mode. "
- "Aborting\n");
- break;
- case POWERPC_EXCP_RESET: /* System reset exception */
- cpu_abort(cs, "Reset interrupt while in user mode. "
- "Aborting\n");
- break;
- case POWERPC_EXCP_DSEG: /* Data segment exception */
- cpu_abort(cs, "Data segment exception while in user mode. "
- "Aborting\n");
- break;
- case POWERPC_EXCP_ISEG: /* Instruction segment exception */
- cpu_abort(cs, "Instruction segment exception "
- "while in user mode. Aborting\n");
- break;
- /* PowerPC 64 with hypervisor mode support */
- case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
- cpu_abort(cs, "Hypervisor decrementer interrupt "
- "while in user mode. Aborting\n");
- break;
- case POWERPC_EXCP_TRACE: /* Trace exception */
- /* Nothing to do:
- * we use this exception to emulate step-by-step execution mode.
- */
- break;
- /* PowerPC 64 with hypervisor mode support */
- case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
- cpu_abort(cs, "Hypervisor data storage exception "
- "while in user mode. Aborting\n");
- break;
- case POWERPC_EXCP_HISI: /* Hypervisor instruction storage excp */
- cpu_abort(cs, "Hypervisor instruction storage exception "
- "while in user mode. Aborting\n");
- break;
- case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */
- cpu_abort(cs, "Hypervisor data segment exception "
- "while in user mode. Aborting\n");
- break;
- case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment excp */
- cpu_abort(cs, "Hypervisor instruction segment exception "
- "while in user mode. Aborting\n");
- break;
- case POWERPC_EXCP_VPU: /* Vector unavailable exception */
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_COPROC;
- info._sifields._sigfault._addr = env->nip;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case POWERPC_EXCP_PIT: /* Programmable interval timer IRQ */
- cpu_abort(cs, "Programmable interval timer interrupt "
- "while in user mode. Aborting\n");
- break;
- case POWERPC_EXCP_IO: /* IO error exception */
- cpu_abort(cs, "IO error exception while in user mode. "
- "Aborting\n");
- break;
- case POWERPC_EXCP_RUNM: /* Run mode exception */
- cpu_abort(cs, "Run mode exception while in user mode. "
- "Aborting\n");
- break;
- case POWERPC_EXCP_EMUL: /* Emulation trap exception */
- cpu_abort(cs, "Emulation trap exception not handled\n");
- break;
- case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
- cpu_abort(cs, "Instruction fetch TLB exception "
- "while in user-mode. Aborting");
- break;
- case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
- cpu_abort(cs, "Data load TLB exception while in user-mode. "
- "Aborting");
- break;
- case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
- cpu_abort(cs, "Data store TLB exception while in user-mode. "
- "Aborting");
- break;
- case POWERPC_EXCP_FPA: /* Floating-point assist exception */
- cpu_abort(cs, "Floating-point assist exception not handled\n");
- break;
- case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
- cpu_abort(cs, "Instruction address breakpoint exception "
- "not handled\n");
- break;
- case POWERPC_EXCP_SMI: /* System management interrupt */
- cpu_abort(cs, "System management interrupt while in user mode. "
- "Aborting\n");
- break;
- case POWERPC_EXCP_THERM: /* Thermal interrupt */
- cpu_abort(cs, "Thermal interrupt interrupt while in user mode. "
- "Aborting\n");
- break;
- case POWERPC_EXCP_PERFM: /* Embedded performance monitor IRQ */
- cpu_abort(cs, "Performance monitor exception not handled\n");
- break;
- case POWERPC_EXCP_VPUA: /* Vector assist exception */
- cpu_abort(cs, "Vector assist exception not handled\n");
- break;
- case POWERPC_EXCP_SOFTP: /* Soft patch exception */
- cpu_abort(cs, "Soft patch exception not handled\n");
- break;
- case POWERPC_EXCP_MAINT: /* Maintenance exception */
- cpu_abort(cs, "Maintenance exception while in user mode. "
- "Aborting\n");
- break;
- case POWERPC_EXCP_STOP: /* stop translation */
- /* We did invalidate the instruction cache. Go on */
- break;
- case POWERPC_EXCP_BRANCH: /* branch instruction: */
- /* We just stopped because of a branch. Go on */
- break;
- case POWERPC_EXCP_SYSCALL_USER:
- /* system call in user-mode emulation */
- /* WARNING:
- * PPC ABI uses overflow flag in cr0 to signal an error
- * in syscalls.
- */
- env->crf[0] &= ~0x1;
- env->nip += 4;
- ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
- env->gpr[5], env->gpr[6], env->gpr[7],
- env->gpr[8], 0, 0);
- if (ret == -TARGET_ERESTARTSYS) {
- env->nip -= 4;
- break;
- }
- if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
- /* Returning from a successful sigreturn syscall.
- Avoid corrupting register state. */
- break;
- }
- if (ret > (target_ulong)(-515)) {
- env->crf[0] |= 0x1;
- ret = -ret;
- }
- env->gpr[3] = ret;
- break;
- case POWERPC_EXCP_STCX:
- if (do_store_exclusive(env)) {
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = env->nip;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- break;
- case EXCP_DEBUG:
- {
- int sig;
-
- sig = gdb_handlesig(cs, TARGET_SIGTRAP);
- if (sig) {
- info.si_signo = sig;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- }
- break;
- case EXCP_INTERRUPT:
- /* just indicate that signals should be handled asap */
- break;
- case EXCP_ATOMIC:
- cpu_exec_step_atomic(cs);
- break;
- default:
- cpu_abort(cs, "Unknown exception 0x%x. Aborting\n", trapnr);
- break;
- }
- process_pending_signals(env);
- }
-}
-#endif
-
-#ifdef TARGET_MIPS
-
-# ifdef TARGET_ABI_MIPSO32
-# define MIPS_SYS(name, args) args,
-static const uint8_t mips_syscall_args[] = {
- MIPS_SYS(sys_syscall , 8) /* 4000 */
- MIPS_SYS(sys_exit , 1)
- MIPS_SYS(sys_fork , 0)
- MIPS_SYS(sys_read , 3)
- MIPS_SYS(sys_write , 3)
- MIPS_SYS(sys_open , 3) /* 4005 */
- MIPS_SYS(sys_close , 1)
- MIPS_SYS(sys_waitpid , 3)
- MIPS_SYS(sys_creat , 2)
- MIPS_SYS(sys_link , 2)
- MIPS_SYS(sys_unlink , 1) /* 4010 */
- MIPS_SYS(sys_execve , 0)
- MIPS_SYS(sys_chdir , 1)
- MIPS_SYS(sys_time , 1)
- MIPS_SYS(sys_mknod , 3)
- MIPS_SYS(sys_chmod , 2) /* 4015 */
- MIPS_SYS(sys_lchown , 3)
- MIPS_SYS(sys_ni_syscall , 0)
- MIPS_SYS(sys_ni_syscall , 0) /* was sys_stat */
- MIPS_SYS(sys_lseek , 3)
- MIPS_SYS(sys_getpid , 0) /* 4020 */
- MIPS_SYS(sys_mount , 5)
- MIPS_SYS(sys_umount , 1)
- MIPS_SYS(sys_setuid , 1)
- MIPS_SYS(sys_getuid , 0)
- MIPS_SYS(sys_stime , 1) /* 4025 */
- MIPS_SYS(sys_ptrace , 4)
- MIPS_SYS(sys_alarm , 1)
- MIPS_SYS(sys_ni_syscall , 0) /* was sys_fstat */
- MIPS_SYS(sys_pause , 0)
- MIPS_SYS(sys_utime , 2) /* 4030 */
- MIPS_SYS(sys_ni_syscall , 0)
- MIPS_SYS(sys_ni_syscall , 0)
- MIPS_SYS(sys_access , 2)
- MIPS_SYS(sys_nice , 1)
- MIPS_SYS(sys_ni_syscall , 0) /* 4035 */
- MIPS_SYS(sys_sync , 0)
- MIPS_SYS(sys_kill , 2)
- MIPS_SYS(sys_rename , 2)
- MIPS_SYS(sys_mkdir , 2)
- MIPS_SYS(sys_rmdir , 1) /* 4040 */
- MIPS_SYS(sys_dup , 1)
- MIPS_SYS(sys_pipe , 0)
- MIPS_SYS(sys_times , 1)
- MIPS_SYS(sys_ni_syscall , 0)
- MIPS_SYS(sys_brk , 1) /* 4045 */
- MIPS_SYS(sys_setgid , 1)
- MIPS_SYS(sys_getgid , 0)
- MIPS_SYS(sys_ni_syscall , 0) /* was signal(2) */
- MIPS_SYS(sys_geteuid , 0)
- MIPS_SYS(sys_getegid , 0) /* 4050 */
- MIPS_SYS(sys_acct , 0)
- MIPS_SYS(sys_umount2 , 2)
- MIPS_SYS(sys_ni_syscall , 0)
- MIPS_SYS(sys_ioctl , 3)
- MIPS_SYS(sys_fcntl , 3) /* 4055 */
- MIPS_SYS(sys_ni_syscall , 2)
- MIPS_SYS(sys_setpgid , 2)
- MIPS_SYS(sys_ni_syscall , 0)
- MIPS_SYS(sys_olduname , 1)
- MIPS_SYS(sys_umask , 1) /* 4060 */
- MIPS_SYS(sys_chroot , 1)
- MIPS_SYS(sys_ustat , 2)
- MIPS_SYS(sys_dup2 , 2)
- MIPS_SYS(sys_getppid , 0)
- MIPS_SYS(sys_getpgrp , 0) /* 4065 */
- MIPS_SYS(sys_setsid , 0)
- MIPS_SYS(sys_sigaction , 3)
- MIPS_SYS(sys_sgetmask , 0)
- MIPS_SYS(sys_ssetmask , 1)
- MIPS_SYS(sys_setreuid , 2) /* 4070 */
- MIPS_SYS(sys_setregid , 2)
- MIPS_SYS(sys_sigsuspend , 0)
- MIPS_SYS(sys_sigpending , 1)
- MIPS_SYS(sys_sethostname , 2)
- MIPS_SYS(sys_setrlimit , 2) /* 4075 */
- MIPS_SYS(sys_getrlimit , 2)
- MIPS_SYS(sys_getrusage , 2)
- MIPS_SYS(sys_gettimeofday, 2)
- MIPS_SYS(sys_settimeofday, 2)
- MIPS_SYS(sys_getgroups , 2) /* 4080 */
- MIPS_SYS(sys_setgroups , 2)
- MIPS_SYS(sys_ni_syscall , 0) /* old_select */
- MIPS_SYS(sys_symlink , 2)
- MIPS_SYS(sys_ni_syscall , 0) /* was sys_lstat */
- MIPS_SYS(sys_readlink , 3) /* 4085 */
- MIPS_SYS(sys_uselib , 1)
- MIPS_SYS(sys_swapon , 2)
- MIPS_SYS(sys_reboot , 3)
- MIPS_SYS(old_readdir , 3)
- MIPS_SYS(old_mmap , 6) /* 4090 */
- MIPS_SYS(sys_munmap , 2)
- MIPS_SYS(sys_truncate , 2)
- MIPS_SYS(sys_ftruncate , 2)
- MIPS_SYS(sys_fchmod , 2)
- MIPS_SYS(sys_fchown , 3) /* 4095 */
- MIPS_SYS(sys_getpriority , 2)
- MIPS_SYS(sys_setpriority , 3)
- MIPS_SYS(sys_ni_syscall , 0)
- MIPS_SYS(sys_statfs , 2)
- MIPS_SYS(sys_fstatfs , 2) /* 4100 */
- MIPS_SYS(sys_ni_syscall , 0) /* was ioperm(2) */
- MIPS_SYS(sys_socketcall , 2)
- MIPS_SYS(sys_syslog , 3)
- MIPS_SYS(sys_setitimer , 3)
- MIPS_SYS(sys_getitimer , 2) /* 4105 */
- MIPS_SYS(sys_newstat , 2)
- MIPS_SYS(sys_newlstat , 2)
- MIPS_SYS(sys_newfstat , 2)
- MIPS_SYS(sys_uname , 1)
- MIPS_SYS(sys_ni_syscall , 0) /* 4110 was iopl(2) */
- MIPS_SYS(sys_vhangup , 0)
- MIPS_SYS(sys_ni_syscall , 0) /* was sys_idle() */
- MIPS_SYS(sys_ni_syscall , 0) /* was sys_vm86 */
- MIPS_SYS(sys_wait4 , 4)
- MIPS_SYS(sys_swapoff , 1) /* 4115 */
- MIPS_SYS(sys_sysinfo , 1)
- MIPS_SYS(sys_ipc , 6)
- MIPS_SYS(sys_fsync , 1)
- MIPS_SYS(sys_sigreturn , 0)
- MIPS_SYS(sys_clone , 6) /* 4120 */
- MIPS_SYS(sys_setdomainname, 2)
- MIPS_SYS(sys_newuname , 1)
- MIPS_SYS(sys_ni_syscall , 0) /* sys_modify_ldt */
- MIPS_SYS(sys_adjtimex , 1)
- MIPS_SYS(sys_mprotect , 3) /* 4125 */
- MIPS_SYS(sys_sigprocmask , 3)
- MIPS_SYS(sys_ni_syscall , 0) /* was create_module */
- MIPS_SYS(sys_init_module , 5)
- MIPS_SYS(sys_delete_module, 1)
- MIPS_SYS(sys_ni_syscall , 0) /* 4130 was get_kernel_syms */
- MIPS_SYS(sys_quotactl , 0)
- MIPS_SYS(sys_getpgid , 1)
- MIPS_SYS(sys_fchdir , 1)
- MIPS_SYS(sys_bdflush , 2)
- MIPS_SYS(sys_sysfs , 3) /* 4135 */
- MIPS_SYS(sys_personality , 1)
- MIPS_SYS(sys_ni_syscall , 0) /* for afs_syscall */
- MIPS_SYS(sys_setfsuid , 1)
- MIPS_SYS(sys_setfsgid , 1)
- MIPS_SYS(sys_llseek , 5) /* 4140 */
- MIPS_SYS(sys_getdents , 3)
- MIPS_SYS(sys_select , 5)
- MIPS_SYS(sys_flock , 2)
- MIPS_SYS(sys_msync , 3)
- MIPS_SYS(sys_readv , 3) /* 4145 */
- MIPS_SYS(sys_writev , 3)
- MIPS_SYS(sys_cacheflush , 3)
- MIPS_SYS(sys_cachectl , 3)
- MIPS_SYS(sys_sysmips , 4)
- MIPS_SYS(sys_ni_syscall , 0) /* 4150 */
- MIPS_SYS(sys_getsid , 1)
- MIPS_SYS(sys_fdatasync , 0)
- MIPS_SYS(sys_sysctl , 1)
- MIPS_SYS(sys_mlock , 2)
- MIPS_SYS(sys_munlock , 2) /* 4155 */
- MIPS_SYS(sys_mlockall , 1)
- MIPS_SYS(sys_munlockall , 0)
- MIPS_SYS(sys_sched_setparam, 2)
- MIPS_SYS(sys_sched_getparam, 2)
- MIPS_SYS(sys_sched_setscheduler, 3) /* 4160 */
- MIPS_SYS(sys_sched_getscheduler, 1)
- MIPS_SYS(sys_sched_yield , 0)
- MIPS_SYS(sys_sched_get_priority_max, 1)
- MIPS_SYS(sys_sched_get_priority_min, 1)
- MIPS_SYS(sys_sched_rr_get_interval, 2) /* 4165 */
- MIPS_SYS(sys_nanosleep, 2)
- MIPS_SYS(sys_mremap , 5)
- MIPS_SYS(sys_accept , 3)
- MIPS_SYS(sys_bind , 3)
- MIPS_SYS(sys_connect , 3) /* 4170 */
- MIPS_SYS(sys_getpeername , 3)
- MIPS_SYS(sys_getsockname , 3)
- MIPS_SYS(sys_getsockopt , 5)
- MIPS_SYS(sys_listen , 2)
- MIPS_SYS(sys_recv , 4) /* 4175 */
- MIPS_SYS(sys_recvfrom , 6)
- MIPS_SYS(sys_recvmsg , 3)
- MIPS_SYS(sys_send , 4)
- MIPS_SYS(sys_sendmsg , 3)
- MIPS_SYS(sys_sendto , 6) /* 4180 */
- MIPS_SYS(sys_setsockopt , 5)
- MIPS_SYS(sys_shutdown , 2)
- MIPS_SYS(sys_socket , 3)
- MIPS_SYS(sys_socketpair , 4)
- MIPS_SYS(sys_setresuid , 3) /* 4185 */
- MIPS_SYS(sys_getresuid , 3)
- MIPS_SYS(sys_ni_syscall , 0) /* was sys_query_module */
- MIPS_SYS(sys_poll , 3)
- MIPS_SYS(sys_nfsservctl , 3)
- MIPS_SYS(sys_setresgid , 3) /* 4190 */
- MIPS_SYS(sys_getresgid , 3)
- MIPS_SYS(sys_prctl , 5)
- MIPS_SYS(sys_rt_sigreturn, 0)
- MIPS_SYS(sys_rt_sigaction, 4)
- MIPS_SYS(sys_rt_sigprocmask, 4) /* 4195 */
- MIPS_SYS(sys_rt_sigpending, 2)
- MIPS_SYS(sys_rt_sigtimedwait, 4)
- MIPS_SYS(sys_rt_sigqueueinfo, 3)
- MIPS_SYS(sys_rt_sigsuspend, 0)
- MIPS_SYS(sys_pread64 , 6) /* 4200 */
- MIPS_SYS(sys_pwrite64 , 6)
- MIPS_SYS(sys_chown , 3)
- MIPS_SYS(sys_getcwd , 2)
- MIPS_SYS(sys_capget , 2)
- MIPS_SYS(sys_capset , 2) /* 4205 */
- MIPS_SYS(sys_sigaltstack , 2)
- MIPS_SYS(sys_sendfile , 4)
- MIPS_SYS(sys_ni_syscall , 0)
- MIPS_SYS(sys_ni_syscall , 0)
- MIPS_SYS(sys_mmap2 , 6) /* 4210 */
- MIPS_SYS(sys_truncate64 , 4)
- MIPS_SYS(sys_ftruncate64 , 4)
- MIPS_SYS(sys_stat64 , 2)
- MIPS_SYS(sys_lstat64 , 2)
- MIPS_SYS(sys_fstat64 , 2) /* 4215 */
- MIPS_SYS(sys_pivot_root , 2)
- MIPS_SYS(sys_mincore , 3)
- MIPS_SYS(sys_madvise , 3)
- MIPS_SYS(sys_getdents64 , 3)
- MIPS_SYS(sys_fcntl64 , 3) /* 4220 */
- MIPS_SYS(sys_ni_syscall , 0)
- MIPS_SYS(sys_gettid , 0)
- MIPS_SYS(sys_readahead , 5)
- MIPS_SYS(sys_setxattr , 5)
- MIPS_SYS(sys_lsetxattr , 5) /* 4225 */
- MIPS_SYS(sys_fsetxattr , 5)
- MIPS_SYS(sys_getxattr , 4)
- MIPS_SYS(sys_lgetxattr , 4)
- MIPS_SYS(sys_fgetxattr , 4)
- MIPS_SYS(sys_listxattr , 3) /* 4230 */
- MIPS_SYS(sys_llistxattr , 3)
- MIPS_SYS(sys_flistxattr , 3)
- MIPS_SYS(sys_removexattr , 2)
- MIPS_SYS(sys_lremovexattr, 2)
- MIPS_SYS(sys_fremovexattr, 2) /* 4235 */
- MIPS_SYS(sys_tkill , 2)
- MIPS_SYS(sys_sendfile64 , 5)
- MIPS_SYS(sys_futex , 6)
- MIPS_SYS(sys_sched_setaffinity, 3)
- MIPS_SYS(sys_sched_getaffinity, 3) /* 4240 */
- MIPS_SYS(sys_io_setup , 2)
- MIPS_SYS(sys_io_destroy , 1)
- MIPS_SYS(sys_io_getevents, 5)
- MIPS_SYS(sys_io_submit , 3)
- MIPS_SYS(sys_io_cancel , 3) /* 4245 */
- MIPS_SYS(sys_exit_group , 1)
- MIPS_SYS(sys_lookup_dcookie, 3)
- MIPS_SYS(sys_epoll_create, 1)
- MIPS_SYS(sys_epoll_ctl , 4)
- MIPS_SYS(sys_epoll_wait , 3) /* 4250 */
- MIPS_SYS(sys_remap_file_pages, 5)
- MIPS_SYS(sys_set_tid_address, 1)
- MIPS_SYS(sys_restart_syscall, 0)
- MIPS_SYS(sys_fadvise64_64, 7)
- MIPS_SYS(sys_statfs64 , 3) /* 4255 */
- MIPS_SYS(sys_fstatfs64 , 2)
- MIPS_SYS(sys_timer_create, 3)
- MIPS_SYS(sys_timer_settime, 4)
- MIPS_SYS(sys_timer_gettime, 2)
- MIPS_SYS(sys_timer_getoverrun, 1) /* 4260 */
- MIPS_SYS(sys_timer_delete, 1)
- MIPS_SYS(sys_clock_settime, 2)
- MIPS_SYS(sys_clock_gettime, 2)
- MIPS_SYS(sys_clock_getres, 2)
- MIPS_SYS(sys_clock_nanosleep, 4) /* 4265 */
- MIPS_SYS(sys_tgkill , 3)
- MIPS_SYS(sys_utimes , 2)
- MIPS_SYS(sys_mbind , 4)
- MIPS_SYS(sys_ni_syscall , 0) /* sys_get_mempolicy */
- MIPS_SYS(sys_ni_syscall , 0) /* 4270 sys_set_mempolicy */
- MIPS_SYS(sys_mq_open , 4)
- MIPS_SYS(sys_mq_unlink , 1)
- MIPS_SYS(sys_mq_timedsend, 5)
- MIPS_SYS(sys_mq_timedreceive, 5)
- MIPS_SYS(sys_mq_notify , 2) /* 4275 */
- MIPS_SYS(sys_mq_getsetattr, 3)
- MIPS_SYS(sys_ni_syscall , 0) /* sys_vserver */
- MIPS_SYS(sys_waitid , 4)
- MIPS_SYS(sys_ni_syscall , 0) /* available, was setaltroot */
- MIPS_SYS(sys_add_key , 5)
- MIPS_SYS(sys_request_key, 4)
- MIPS_SYS(sys_keyctl , 5)
- MIPS_SYS(sys_set_thread_area, 1)
- MIPS_SYS(sys_inotify_init, 0)
- MIPS_SYS(sys_inotify_add_watch, 3) /* 4285 */
- MIPS_SYS(sys_inotify_rm_watch, 2)
- MIPS_SYS(sys_migrate_pages, 4)
- MIPS_SYS(sys_openat, 4)
- MIPS_SYS(sys_mkdirat, 3)
- MIPS_SYS(sys_mknodat, 4) /* 4290 */
- MIPS_SYS(sys_fchownat, 5)
- MIPS_SYS(sys_futimesat, 3)
- MIPS_SYS(sys_fstatat64, 4)
- MIPS_SYS(sys_unlinkat, 3)
- MIPS_SYS(sys_renameat, 4) /* 4295 */
- MIPS_SYS(sys_linkat, 5)
- MIPS_SYS(sys_symlinkat, 3)
- MIPS_SYS(sys_readlinkat, 4)
- MIPS_SYS(sys_fchmodat, 3)
- MIPS_SYS(sys_faccessat, 3) /* 4300 */
- MIPS_SYS(sys_pselect6, 6)
- MIPS_SYS(sys_ppoll, 5)
- MIPS_SYS(sys_unshare, 1)
- MIPS_SYS(sys_splice, 6)
- MIPS_SYS(sys_sync_file_range, 7) /* 4305 */
- MIPS_SYS(sys_tee, 4)
- MIPS_SYS(sys_vmsplice, 4)
- MIPS_SYS(sys_move_pages, 6)
- MIPS_SYS(sys_set_robust_list, 2)
- MIPS_SYS(sys_get_robust_list, 3) /* 4310 */
- MIPS_SYS(sys_kexec_load, 4)
- MIPS_SYS(sys_getcpu, 3)
- MIPS_SYS(sys_epoll_pwait, 6)
- MIPS_SYS(sys_ioprio_set, 3)
- MIPS_SYS(sys_ioprio_get, 2)
- MIPS_SYS(sys_utimensat, 4)
- MIPS_SYS(sys_signalfd, 3)
- MIPS_SYS(sys_ni_syscall, 0) /* was timerfd */
- MIPS_SYS(sys_eventfd, 1)
- MIPS_SYS(sys_fallocate, 6) /* 4320 */
- MIPS_SYS(sys_timerfd_create, 2)
- MIPS_SYS(sys_timerfd_gettime, 2)
- MIPS_SYS(sys_timerfd_settime, 4)
- MIPS_SYS(sys_signalfd4, 4)
- MIPS_SYS(sys_eventfd2, 2) /* 4325 */
- MIPS_SYS(sys_epoll_create1, 1)
- MIPS_SYS(sys_dup3, 3)
- MIPS_SYS(sys_pipe2, 2)
- MIPS_SYS(sys_inotify_init1, 1)
- MIPS_SYS(sys_preadv, 5) /* 4330 */
- MIPS_SYS(sys_pwritev, 5)
- MIPS_SYS(sys_rt_tgsigqueueinfo, 4)
- MIPS_SYS(sys_perf_event_open, 5)
- MIPS_SYS(sys_accept4, 4)
- MIPS_SYS(sys_recvmmsg, 5) /* 4335 */
- MIPS_SYS(sys_fanotify_init, 2)
- MIPS_SYS(sys_fanotify_mark, 6)
- MIPS_SYS(sys_prlimit64, 4)
- MIPS_SYS(sys_name_to_handle_at, 5)
- MIPS_SYS(sys_open_by_handle_at, 3) /* 4340 */
- MIPS_SYS(sys_clock_adjtime, 2)
- MIPS_SYS(sys_syncfs, 1)
- MIPS_SYS(sys_sendmmsg, 4)
- MIPS_SYS(sys_setns, 2)
- MIPS_SYS(sys_process_vm_readv, 6) /* 345 */
- MIPS_SYS(sys_process_vm_writev, 6)
- MIPS_SYS(sys_kcmp, 5)
- MIPS_SYS(sys_finit_module, 3)
- MIPS_SYS(sys_sched_setattr, 2)
- MIPS_SYS(sys_sched_getattr, 3) /* 350 */
- MIPS_SYS(sys_renameat2, 5)
- MIPS_SYS(sys_seccomp, 3)
- MIPS_SYS(sys_getrandom, 3)
- MIPS_SYS(sys_memfd_create, 2)
- MIPS_SYS(sys_bpf, 3) /* 355 */
- MIPS_SYS(sys_execveat, 5)
- MIPS_SYS(sys_userfaultfd, 1)
- MIPS_SYS(sys_membarrier, 2)
- MIPS_SYS(sys_mlock2, 3)
- MIPS_SYS(sys_copy_file_range, 6) /* 360 */
- MIPS_SYS(sys_preadv2, 6)
- MIPS_SYS(sys_pwritev2, 6)
-};
-# undef MIPS_SYS
-# endif /* O32 */
-
-static int do_store_exclusive(CPUMIPSState *env)
-{
- target_ulong addr;
- target_ulong page_addr;
- target_ulong val;
- int flags;
- int segv = 0;
- int reg;
- int d;
-
- addr = env->lladdr;
- page_addr = addr & TARGET_PAGE_MASK;
- start_exclusive();
- mmap_lock();
- flags = page_get_flags(page_addr);
- if ((flags & PAGE_READ) == 0) {
- segv = 1;
- } else {
- reg = env->llreg & 0x1f;
- d = (env->llreg & 0x20) != 0;
- if (d) {
- segv = get_user_s64(val, addr);
- } else {
- segv = get_user_s32(val, addr);
- }
- if (!segv) {
- if (val != env->llval) {
- env->active_tc.gpr[reg] = 0;
- } else {
- if (d) {
- segv = put_user_u64(env->llnewval, addr);
- } else {
- segv = put_user_u32(env->llnewval, addr);
- }
- if (!segv) {
- env->active_tc.gpr[reg] = 1;
- }
- }
- }
- }
- env->lladdr = -1;
- if (!segv) {
- env->active_tc.PC += 4;
- }
- mmap_unlock();
- end_exclusive();
- return segv;
-}
-
-/* Break codes */
-enum {
- BRK_OVERFLOW = 6,
- BRK_DIVZERO = 7
-};
-
-static int do_break(CPUMIPSState *env, target_siginfo_t *info,
- unsigned int code)
-{
- int ret = -1;
-
- switch (code) {
- case BRK_OVERFLOW:
- case BRK_DIVZERO:
- info->si_signo = TARGET_SIGFPE;
- info->si_errno = 0;
- info->si_code = (code == BRK_OVERFLOW) ? FPE_INTOVF : FPE_INTDIV;
- queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info);
- ret = 0;
- break;
- default:
- info->si_signo = TARGET_SIGTRAP;
- info->si_errno = 0;
- queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info);
- ret = 0;
- break;
- }
-
- return ret;
-}
-
-void cpu_loop(CPUMIPSState *env)
-{
- CPUState *cs = CPU(mips_env_get_cpu(env));
- target_siginfo_t info;
- int trapnr;
- abi_long ret;
-# ifdef TARGET_ABI_MIPSO32
- unsigned int syscall_num;
-# endif
-
- for(;;) {
- cpu_exec_start(cs);
- trapnr = cpu_exec(cs);
- cpu_exec_end(cs);
- process_queued_cpu_work(cs);
-
- switch(trapnr) {
- case EXCP_SYSCALL:
- env->active_tc.PC += 4;
-# ifdef TARGET_ABI_MIPSO32
- syscall_num = env->active_tc.gpr[2] - 4000;
- if (syscall_num >= sizeof(mips_syscall_args)) {
- ret = -TARGET_ENOSYS;
- } else {
- int nb_args;
- abi_ulong sp_reg;
- abi_ulong arg5 = 0, arg6 = 0, arg7 = 0, arg8 = 0;
-
- nb_args = mips_syscall_args[syscall_num];
- sp_reg = env->active_tc.gpr[29];
- switch (nb_args) {
- /* these arguments are taken from the stack */
- case 8:
- if ((ret = get_user_ual(arg8, sp_reg + 28)) != 0) {
- goto done_syscall;
- }
- case 7:
- if ((ret = get_user_ual(arg7, sp_reg + 24)) != 0) {
- goto done_syscall;
- }
- case 6:
- if ((ret = get_user_ual(arg6, sp_reg + 20)) != 0) {
- goto done_syscall;
- }
- case 5:
- if ((ret = get_user_ual(arg5, sp_reg + 16)) != 0) {
- goto done_syscall;
- }
- default:
- break;
- }
- ret = do_syscall(env, env->active_tc.gpr[2],
- env->active_tc.gpr[4],
- env->active_tc.gpr[5],
- env->active_tc.gpr[6],
- env->active_tc.gpr[7],
- arg5, arg6, arg7, arg8);
- }
-done_syscall:
-# else
- ret = do_syscall(env, env->active_tc.gpr[2],
- env->active_tc.gpr[4], env->active_tc.gpr[5],
- env->active_tc.gpr[6], env->active_tc.gpr[7],
- env->active_tc.gpr[8], env->active_tc.gpr[9],
- env->active_tc.gpr[10], env->active_tc.gpr[11]);
-# endif /* O32 */
- if (ret == -TARGET_ERESTARTSYS) {
- env->active_tc.PC -= 4;
- break;
- }
- if (ret == -TARGET_QEMU_ESIGRETURN) {
- /* Returning from a successful sigreturn syscall.
- Avoid clobbering register state. */
- break;
- }
- if ((abi_ulong)ret >= (abi_ulong)-1133) {
- env->active_tc.gpr[7] = 1; /* error flag */
- ret = -ret;
- } else {
- env->active_tc.gpr[7] = 0; /* error flag */
- }
- env->active_tc.gpr[2] = ret;
- break;
- case EXCP_TLBL:
- case EXCP_TLBS:
- case EXCP_AdEL:
- case EXCP_AdES:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = env->CP0_BadVAddr;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP_CpU:
- case EXCP_RI:
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = 0;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP_INTERRUPT:
- /* just indicate that signals should be handled asap */
- break;
- case EXCP_DEBUG:
- {
- int sig;
-
- sig = gdb_handlesig(cs, TARGET_SIGTRAP);
- if (sig)
- {
- info.si_signo = sig;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- }
- break;
- case EXCP_SC:
- if (do_store_exclusive(env)) {
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = env->active_tc.PC;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- break;
- case EXCP_DSPDIS:
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLOPC;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- /* The code below was inspired by the MIPS Linux kernel trap
- * handling code in arch/mips/kernel/traps.c.
- */
- case EXCP_BREAK:
- {
- abi_ulong trap_instr;
- unsigned int code;
-
- if (env->hflags & MIPS_HFLAG_M16) {
- if (env->insn_flags & ASE_MICROMIPS) {
- /* microMIPS mode */
- ret = get_user_u16(trap_instr, env->active_tc.PC);
- if (ret != 0) {
- goto error;
- }
-
- if ((trap_instr >> 10) == 0x11) {
- /* 16-bit instruction */
- code = trap_instr & 0xf;
- } else {
- /* 32-bit instruction */
- abi_ulong instr_lo;
-
- ret = get_user_u16(instr_lo,
- env->active_tc.PC + 2);
- if (ret != 0) {
- goto error;
- }
- trap_instr = (trap_instr << 16) | instr_lo;
- code = ((trap_instr >> 6) & ((1 << 20) - 1));
- /* Unfortunately, microMIPS also suffers from
- the old assembler bug... */
- if (code >= (1 << 10)) {
- code >>= 10;
- }
- }
- } else {
- /* MIPS16e mode */
- ret = get_user_u16(trap_instr, env->active_tc.PC);
- if (ret != 0) {
- goto error;
- }
- code = (trap_instr >> 6) & 0x3f;
- }
- } else {
- ret = get_user_u32(trap_instr, env->active_tc.PC);
- if (ret != 0) {
- goto error;
- }
-
- /* As described in the original Linux kernel code, the
- * below checks on 'code' are to work around an old
- * assembly bug.
- */
- code = ((trap_instr >> 6) & ((1 << 20) - 1));
- if (code >= (1 << 10)) {
- code >>= 10;
- }
- }
-
- if (do_break(env, &info, code) != 0) {
- goto error;
- }
- }
- break;
- case EXCP_TRAP:
- {
- abi_ulong trap_instr;
- unsigned int code = 0;
-
- if (env->hflags & MIPS_HFLAG_M16) {
- /* microMIPS mode */
- abi_ulong instr[2];
-
- ret = get_user_u16(instr[0], env->active_tc.PC) ||
- get_user_u16(instr[1], env->active_tc.PC + 2);
-
- trap_instr = (instr[0] << 16) | instr[1];
- } else {
- ret = get_user_u32(trap_instr, env->active_tc.PC);
- }
-
- if (ret != 0) {
- goto error;
- }
-
- /* The immediate versions don't provide a code. */
- if (!(trap_instr & 0xFC000000)) {
- if (env->hflags & MIPS_HFLAG_M16) {
- /* microMIPS mode */
- code = ((trap_instr >> 12) & ((1 << 4) - 1));
- } else {
- code = ((trap_instr >> 6) & ((1 << 10) - 1));
- }
- }
-
- if (do_break(env, &info, code) != 0) {
- goto error;
- }
- }
- break;
- case EXCP_ATOMIC:
- cpu_exec_step_atomic(cs);
- break;
- default:
-error:
- EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
- abort();
- }
- process_pending_signals(env);
- }
-}
-#endif
-
-#ifdef TARGET_NIOS2
-
-void cpu_loop(CPUNios2State *env)
-{
- CPUState *cs = ENV_GET_CPU(env);
- Nios2CPU *cpu = NIOS2_CPU(cs);
- target_siginfo_t info;
- int trapnr, gdbsig, ret;
-
- for (;;) {
- cpu_exec_start(cs);
- trapnr = cpu_exec(cs);
- cpu_exec_end(cs);
- gdbsig = 0;
-
- switch (trapnr) {
- case EXCP_INTERRUPT:
- /* just indicate that signals should be handled asap */
- break;
- case EXCP_TRAP:
- if (env->regs[R_AT] == 0) {
- abi_long ret;
- qemu_log_mask(CPU_LOG_INT, "\nSyscall\n");
-
- ret = do_syscall(env, env->regs[2],
- env->regs[4], env->regs[5], env->regs[6],
- env->regs[7], env->regs[8], env->regs[9],
- 0, 0);
-
- if (env->regs[2] == 0) { /* FIXME: syscall 0 workaround */
- ret = 0;
- }
-
- env->regs[2] = abs(ret);
- /* Return value is 0..4096 */
- env->regs[7] = (ret > 0xfffffffffffff000ULL);
- env->regs[CR_ESTATUS] = env->regs[CR_STATUS];
- env->regs[CR_STATUS] &= ~0x3;
- env->regs[R_EA] = env->regs[R_PC] + 4;
- env->regs[R_PC] += 4;
- break;
- } else {
- qemu_log_mask(CPU_LOG_INT, "\nTrap\n");
-
- env->regs[CR_ESTATUS] = env->regs[CR_STATUS];
- env->regs[CR_STATUS] &= ~0x3;
- env->regs[R_EA] = env->regs[R_PC] + 4;
- env->regs[R_PC] = cpu->exception_addr;
-
- gdbsig = TARGET_SIGTRAP;
- break;
- }
- case 0xaa:
- switch (env->regs[R_PC]) {
- /*case 0x1000:*/ /* TODO:__kuser_helper_version */
- case 0x1004: /* __kuser_cmpxchg */
- start_exclusive();
- if (env->regs[4] & 0x3) {
- goto kuser_fail;
- }
- ret = get_user_u32(env->regs[2], env->regs[4]);
- if (ret) {
- end_exclusive();
- goto kuser_fail;
- }
- env->regs[2] -= env->regs[5];
- if (env->regs[2] == 0) {
- put_user_u32(env->regs[6], env->regs[4]);
- }
- end_exclusive();
- env->regs[R_PC] = env->regs[R_RA];
- break;
- /*case 0x1040:*/ /* TODO:__kuser_sigtramp */
- default:
- ;
-kuser_fail:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- /* TODO: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = env->regs[R_PC];
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- break;
- default:
- EXCP_DUMP(env, "\nqemu: unhandled CPU exception %#x - aborting\n",
- trapnr);
- gdbsig = TARGET_SIGILL;
- break;
- }
- if (gdbsig) {
- gdb_handlesig(cs, gdbsig);
- if (gdbsig != TARGET_SIGTRAP) {
- exit(EXIT_FAILURE);
- }
- }
-
- process_pending_signals(env);
- }
-}
-
-#endif /* TARGET_NIOS2 */
-
-#ifdef TARGET_OPENRISC
-
-void cpu_loop(CPUOpenRISCState *env)
-{
- CPUState *cs = CPU(openrisc_env_get_cpu(env));
- int trapnr;
- abi_long ret;
- target_siginfo_t info;
-
- for (;;) {
- cpu_exec_start(cs);
- trapnr = cpu_exec(cs);
- cpu_exec_end(cs);
- process_queued_cpu_work(cs);
-
- switch (trapnr) {
- case EXCP_SYSCALL:
- env->pc += 4; /* 0xc00; */
- ret = do_syscall(env,
- cpu_get_gpr(env, 11), /* return value */
- cpu_get_gpr(env, 3), /* r3 - r7 are params */
- cpu_get_gpr(env, 4),
- cpu_get_gpr(env, 5),
- cpu_get_gpr(env, 6),
- cpu_get_gpr(env, 7),
- cpu_get_gpr(env, 8), 0, 0);
- if (ret == -TARGET_ERESTARTSYS) {
- env->pc -= 4;
- } else if (ret != -TARGET_QEMU_ESIGRETURN) {
- cpu_set_gpr(env, 11, ret);
- }
- break;
- case EXCP_DPF:
- case EXCP_IPF:
- case EXCP_RANGE:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP_ALIGN:
- info.si_signo = TARGET_SIGBUS;
- info.si_errno = 0;
- info.si_code = TARGET_BUS_ADRALN;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP_ILLEGAL:
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLOPC;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP_FPE:
- info.si_signo = TARGET_SIGFPE;
- info.si_errno = 0;
- info.si_code = 0;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP_INTERRUPT:
- /* We processed the pending cpu work above. */
- break;
- case EXCP_DEBUG:
- trapnr = gdb_handlesig(cs, TARGET_SIGTRAP);
- if (trapnr) {
- info.si_signo = trapnr;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- break;
- case EXCP_ATOMIC:
- cpu_exec_step_atomic(cs);
- break;
- default:
- g_assert_not_reached();
- }
- process_pending_signals(env);
- }
-}
-
-#endif /* TARGET_OPENRISC */
-
-#ifdef TARGET_SH4
-void cpu_loop(CPUSH4State *env)
-{
- CPUState *cs = CPU(sh_env_get_cpu(env));
- int trapnr, ret;
- target_siginfo_t info;
-
- while (1) {
- bool arch_interrupt = true;
-
- cpu_exec_start(cs);
- trapnr = cpu_exec(cs);
- cpu_exec_end(cs);
- process_queued_cpu_work(cs);
-
- switch (trapnr) {
- case 0x160:
- env->pc += 2;
- ret = do_syscall(env,
- env->gregs[3],
- env->gregs[4],
- env->gregs[5],
- env->gregs[6],
- env->gregs[7],
- env->gregs[0],
- env->gregs[1],
- 0, 0);
- if (ret == -TARGET_ERESTARTSYS) {
- env->pc -= 2;
- } else if (ret != -TARGET_QEMU_ESIGRETURN) {
- env->gregs[0] = ret;
- }
- break;
- case EXCP_INTERRUPT:
- /* just indicate that signals should be handled asap */
- break;
- case EXCP_DEBUG:
- {
- int sig;
-
- sig = gdb_handlesig(cs, TARGET_SIGTRAP);
- if (sig) {
- info.si_signo = sig;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- } else {
- arch_interrupt = false;
- }
- }
- break;
- case 0xa0:
- case 0xc0:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = env->tea;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP_ATOMIC:
- cpu_exec_step_atomic(cs);
- arch_interrupt = false;
- break;
- default:
- printf ("Unhandled trap: 0x%x\n", trapnr);
- cpu_dump_state(cs, stderr, fprintf, 0);
- exit(EXIT_FAILURE);
- }
- process_pending_signals (env);
-
- /* Most of the traps imply an exception or interrupt, which
- implies an REI instruction has been executed. Which means
- that LDST (aka LOK_ADDR) should be cleared. But there are
- a few exceptions for traps internal to QEMU. */
- if (arch_interrupt) {
- env->lock_addr = -1;
- }
- }
-}
-#endif
-
-#ifdef TARGET_CRIS
-void cpu_loop(CPUCRISState *env)
-{
- CPUState *cs = CPU(cris_env_get_cpu(env));
- int trapnr, ret;
- target_siginfo_t info;
-
- while (1) {
- cpu_exec_start(cs);
- trapnr = cpu_exec(cs);
- cpu_exec_end(cs);
- process_queued_cpu_work(cs);
-
- switch (trapnr) {
- case 0xaa:
- {
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = env->pregs[PR_EDA];
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- break;
- case EXCP_INTERRUPT:
- /* just indicate that signals should be handled asap */
- break;
- case EXCP_BREAK:
- ret = do_syscall(env,
- env->regs[9],
- env->regs[10],
- env->regs[11],
- env->regs[12],
- env->regs[13],
- env->pregs[7],
- env->pregs[11],
- 0, 0);
- if (ret == -TARGET_ERESTARTSYS) {
- env->pc -= 2;
- } else if (ret != -TARGET_QEMU_ESIGRETURN) {
- env->regs[10] = ret;
- }
- break;
- case EXCP_DEBUG:
- {
- int sig;
-
- sig = gdb_handlesig(cs, TARGET_SIGTRAP);
- if (sig)
- {
- info.si_signo = sig;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- }
- break;
- case EXCP_ATOMIC:
- cpu_exec_step_atomic(cs);
- break;
- default:
- printf ("Unhandled trap: 0x%x\n", trapnr);
- cpu_dump_state(cs, stderr, fprintf, 0);
- exit(EXIT_FAILURE);
- }
- process_pending_signals (env);
- }
-}
-#endif
-
-#ifdef TARGET_MICROBLAZE
-void cpu_loop(CPUMBState *env)
-{
- CPUState *cs = CPU(mb_env_get_cpu(env));
- int trapnr, ret;
- target_siginfo_t info;
-
- while (1) {
- cpu_exec_start(cs);
- trapnr = cpu_exec(cs);
- cpu_exec_end(cs);
- process_queued_cpu_work(cs);
-
- switch (trapnr) {
- case 0xaa:
- {
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = 0;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- break;
- case EXCP_INTERRUPT:
- /* just indicate that signals should be handled asap */
- break;
- case EXCP_BREAK:
- /* Return address is 4 bytes after the call. */
- env->regs[14] += 4;
- env->sregs[SR_PC] = env->regs[14];
- ret = do_syscall(env,
- env->regs[12],
- env->regs[5],
- env->regs[6],
- env->regs[7],
- env->regs[8],
- env->regs[9],
- env->regs[10],
- 0, 0);
- if (ret == -TARGET_ERESTARTSYS) {
- /* Wind back to before the syscall. */
- env->sregs[SR_PC] -= 4;
- } else if (ret != -TARGET_QEMU_ESIGRETURN) {
- env->regs[3] = ret;
- }
- /* All syscall exits result in guest r14 being equal to the
- * PC we return to, because the kernel syscall exit "rtbd" does
- * this. (This is true even for sigreturn(); note that r14 is
- * not a userspace-usable register, as the kernel may clobber it
- * at any point.)
- */
- env->regs[14] = env->sregs[SR_PC];
- break;
- case EXCP_HW_EXCP:
- env->regs[17] = env->sregs[SR_PC] + 4;
- if (env->iflags & D_FLAG) {
- env->sregs[SR_ESR] |= 1 << 12;
- env->sregs[SR_PC] -= 4;
- /* FIXME: if branch was immed, replay the imm as well. */
- }
-
- env->iflags &= ~(IMM_FLAG | D_FLAG);
-
- switch (env->sregs[SR_ESR] & 31) {
- case ESR_EC_DIVZERO:
- info.si_signo = TARGET_SIGFPE;
- info.si_errno = 0;
- info.si_code = TARGET_FPE_FLTDIV;
- info._sifields._sigfault._addr = 0;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case ESR_EC_FPU:
- info.si_signo = TARGET_SIGFPE;
- info.si_errno = 0;
- if (env->sregs[SR_FSR] & FSR_IO) {
- info.si_code = TARGET_FPE_FLTINV;
- }
- if (env->sregs[SR_FSR] & FSR_DZ) {
- info.si_code = TARGET_FPE_FLTDIV;
- }
- info._sifields._sigfault._addr = 0;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- default:
- printf ("Unhandled hw-exception: 0x%x\n",
- env->sregs[SR_ESR] & ESR_EC_MASK);
- cpu_dump_state(cs, stderr, fprintf, 0);
- exit(EXIT_FAILURE);
- break;
- }
- break;
- case EXCP_DEBUG:
- {
- int sig;
-
- sig = gdb_handlesig(cs, TARGET_SIGTRAP);
- if (sig)
- {
- info.si_signo = sig;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- }
- break;
- case EXCP_ATOMIC:
- cpu_exec_step_atomic(cs);
- break;
- default:
- printf ("Unhandled trap: 0x%x\n", trapnr);
- cpu_dump_state(cs, stderr, fprintf, 0);
- exit(EXIT_FAILURE);
- }
- process_pending_signals (env);
- }
-}
-#endif
-
-#ifdef TARGET_M68K
-
-void cpu_loop(CPUM68KState *env)
-{
- CPUState *cs = CPU(m68k_env_get_cpu(env));
- int trapnr;
- unsigned int n;
- target_siginfo_t info;
- TaskState *ts = cs->opaque;
-
- for(;;) {
- cpu_exec_start(cs);
- trapnr = cpu_exec(cs);
- cpu_exec_end(cs);
- process_queued_cpu_work(cs);
-
- switch(trapnr) {
- case EXCP_ILLEGAL:
- {
- if (ts->sim_syscalls) {
- uint16_t nr;
- get_user_u16(nr, env->pc + 2);
- env->pc += 4;
- do_m68k_simcall(env, nr);
- } else {
- goto do_sigill;
- }
- }
- break;
- case EXCP_HALT_INSN:
- /* Semihosing syscall. */
- env->pc += 4;
- do_m68k_semihosting(env, env->dregs[0]);
- break;
- case EXCP_LINEA:
- case EXCP_LINEF:
- case EXCP_UNSUPPORTED:
- do_sigill:
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLOPN;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP_CHK:
- info.si_signo = TARGET_SIGFPE;
- info.si_errno = 0;
- info.si_code = TARGET_FPE_INTOVF;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP_DIV0:
- info.si_signo = TARGET_SIGFPE;
- info.si_errno = 0;
- info.si_code = TARGET_FPE_INTDIV;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP_TRAP0:
- {
- abi_long ret;
- ts->sim_syscalls = 0;
- n = env->dregs[0];
- env->pc += 2;
- ret = do_syscall(env,
- n,
- env->dregs[1],
- env->dregs[2],
- env->dregs[3],
- env->dregs[4],
- env->dregs[5],
- env->aregs[0],
- 0, 0);
- if (ret == -TARGET_ERESTARTSYS) {
- env->pc -= 2;
- } else if (ret != -TARGET_QEMU_ESIGRETURN) {
- env->dregs[0] = ret;
- }
- }
- break;
- case EXCP_INTERRUPT:
- /* just indicate that signals should be handled asap */
- break;
- case EXCP_ACCESS:
- {
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = env->mmu.ar;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- break;
- case EXCP_DEBUG:
- {
- int sig;
-
- sig = gdb_handlesig(cs, TARGET_SIGTRAP);
- if (sig)
- {
- info.si_signo = sig;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- }
- break;
- case EXCP_ATOMIC:
- cpu_exec_step_atomic(cs);
- break;
- default:
- EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
- abort();
- }
- process_pending_signals(env);
- }
-}
-#endif /* TARGET_M68K */
-
-#ifdef TARGET_ALPHA
-void cpu_loop(CPUAlphaState *env)
-{
- CPUState *cs = CPU(alpha_env_get_cpu(env));
- int trapnr;
- target_siginfo_t info;
- abi_long sysret;
-
- while (1) {
- bool arch_interrupt = true;
-
- cpu_exec_start(cs);
- trapnr = cpu_exec(cs);
- cpu_exec_end(cs);
- process_queued_cpu_work(cs);
-
- switch (trapnr) {
- case EXCP_RESET:
- fprintf(stderr, "Reset requested. Exit\n");
- exit(EXIT_FAILURE);
- break;
- case EXCP_MCHK:
- fprintf(stderr, "Machine check exception. Exit\n");
- exit(EXIT_FAILURE);
- break;
- case EXCP_SMP_INTERRUPT:
- case EXCP_CLK_INTERRUPT:
- case EXCP_DEV_INTERRUPT:
- fprintf(stderr, "External interrupt. Exit\n");
- exit(EXIT_FAILURE);
- break;
- case EXCP_MMFAULT:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = (page_get_flags(env->trap_arg0) & PAGE_VALID
- ? TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR);
- info._sifields._sigfault._addr = env->trap_arg0;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP_UNALIGN:
- info.si_signo = TARGET_SIGBUS;
- info.si_errno = 0;
- info.si_code = TARGET_BUS_ADRALN;
- info._sifields._sigfault._addr = env->trap_arg0;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP_OPCDEC:
- do_sigill:
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLOPC;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP_ARITH:
- info.si_signo = TARGET_SIGFPE;
- info.si_errno = 0;
- info.si_code = TARGET_FPE_FLTINV;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP_FEN:
- /* No-op. Linux simply re-enables the FPU. */
- break;
- case EXCP_CALL_PAL:
- switch (env->error_code) {
- case 0x80:
- /* BPT */
- info.si_signo = TARGET_SIGTRAP;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case 0x81:
- /* BUGCHK */
- info.si_signo = TARGET_SIGTRAP;
- info.si_errno = 0;
- info.si_code = 0;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case 0x83:
- /* CALLSYS */
- trapnr = env->ir[IR_V0];
- sysret = do_syscall(env, trapnr,
- env->ir[IR_A0], env->ir[IR_A1],
- env->ir[IR_A2], env->ir[IR_A3],
- env->ir[IR_A4], env->ir[IR_A5],
- 0, 0);
- if (sysret == -TARGET_ERESTARTSYS) {
- env->pc -= 4;
- break;
- }
- if (sysret == -TARGET_QEMU_ESIGRETURN) {
- break;
- }
- /* Syscall writes 0 to V0 to bypass error check, similar
- to how this is handled internal to Linux kernel.
- (Ab)use trapnr temporarily as boolean indicating error. */
- trapnr = (env->ir[IR_V0] != 0 && sysret < 0);
- env->ir[IR_V0] = (trapnr ? -sysret : sysret);
- env->ir[IR_A3] = trapnr;
- break;
- case 0x86:
- /* IMB */
- /* ??? We can probably elide the code using page_unprotect
- that is checking for self-modifying code. Instead we
- could simply call tb_flush here. Until we work out the
- changes required to turn off the extra write protection,
- this can be a no-op. */
- break;
- case 0x9E:
- /* RDUNIQUE */
- /* Handled in the translator for usermode. */
- abort();
- case 0x9F:
- /* WRUNIQUE */
- /* Handled in the translator for usermode. */
- abort();
- case 0xAA:
- /* GENTRAP */
- info.si_signo = TARGET_SIGFPE;
- switch (env->ir[IR_A0]) {
- case TARGET_GEN_INTOVF:
- info.si_code = TARGET_FPE_INTOVF;
- break;
- case TARGET_GEN_INTDIV:
- info.si_code = TARGET_FPE_INTDIV;
- break;
- case TARGET_GEN_FLTOVF:
- info.si_code = TARGET_FPE_FLTOVF;
- break;
- case TARGET_GEN_FLTUND:
- info.si_code = TARGET_FPE_FLTUND;
- break;
- case TARGET_GEN_FLTINV:
- info.si_code = TARGET_FPE_FLTINV;
- break;
- case TARGET_GEN_FLTINE:
- info.si_code = TARGET_FPE_FLTRES;
- break;
- case TARGET_GEN_ROPRAND:
- info.si_code = 0;
- break;
- default:
- info.si_signo = TARGET_SIGTRAP;
- info.si_code = 0;
- break;
- }
- info.si_errno = 0;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- default:
- goto do_sigill;
- }
- break;
- case EXCP_DEBUG:
- info.si_signo = gdb_handlesig(cs, TARGET_SIGTRAP);
- if (info.si_signo) {
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- } else {
- arch_interrupt = false;
- }
- break;
- case EXCP_INTERRUPT:
- /* Just indicate that signals should be handled asap. */
- break;
- case EXCP_ATOMIC:
- cpu_exec_step_atomic(cs);
- arch_interrupt = false;
- break;
- default:
- printf ("Unhandled trap: 0x%x\n", trapnr);
- cpu_dump_state(cs, stderr, fprintf, 0);
- exit(EXIT_FAILURE);
- }
- process_pending_signals (env);
-
- /* Most of the traps imply a transition through PALcode, which
- implies an REI instruction has been executed. Which means
- that RX and LOCK_ADDR should be cleared. But there are a
- few exceptions for traps internal to QEMU. */
- if (arch_interrupt) {
- env->flags &= ~ENV_FLAG_RX_FLAG;
- env->lock_addr = -1;
- }
- }
-}
-#endif /* TARGET_ALPHA */
-
-#ifdef TARGET_S390X
-
-/* s390x masks the fault address it reports in si_addr for SIGSEGV and SIGBUS */
-#define S390X_FAIL_ADDR_MASK -4096LL
-
-void cpu_loop(CPUS390XState *env)
-{
- CPUState *cs = CPU(s390_env_get_cpu(env));
- int trapnr, n, sig;
- target_siginfo_t info;
- target_ulong addr;
- abi_long ret;
-
- while (1) {
- cpu_exec_start(cs);
- trapnr = cpu_exec(cs);
- cpu_exec_end(cs);
- process_queued_cpu_work(cs);
-
- switch (trapnr) {
- case EXCP_INTERRUPT:
- /* Just indicate that signals should be handled asap. */
- break;
-
- case EXCP_SVC:
- n = env->int_svc_code;
- if (!n) {
- /* syscalls > 255 */
- n = env->regs[1];
- }
- env->psw.addr += env->int_svc_ilen;
- ret = do_syscall(env, n, env->regs[2], env->regs[3],
- env->regs[4], env->regs[5],
- env->regs[6], env->regs[7], 0, 0);
- if (ret == -TARGET_ERESTARTSYS) {
- env->psw.addr -= env->int_svc_ilen;
- } else if (ret != -TARGET_QEMU_ESIGRETURN) {
- env->regs[2] = ret;
- }
- break;
-
- case EXCP_DEBUG:
- sig = gdb_handlesig(cs, TARGET_SIGTRAP);
- if (sig) {
- n = TARGET_TRAP_BRKPT;
- goto do_signal_pc;
- }
- break;
- case EXCP_PGM:
- n = env->int_pgm_code;
- switch (n) {
- case PGM_OPERATION:
- case PGM_PRIVILEGED:
- sig = TARGET_SIGILL;
- n = TARGET_ILL_ILLOPC;
- goto do_signal_pc;
- case PGM_PROTECTION:
- case PGM_ADDRESSING:
- sig = TARGET_SIGSEGV;
- /* XXX: check env->error_code */
- n = TARGET_SEGV_MAPERR;
- addr = env->__excp_addr & S390X_FAIL_ADDR_MASK;
- goto do_signal;
- case PGM_EXECUTE:
- case PGM_SPECIFICATION:
- case PGM_SPECIAL_OP:
- case PGM_OPERAND:
- do_sigill_opn:
- sig = TARGET_SIGILL;
- n = TARGET_ILL_ILLOPN;
- goto do_signal_pc;
-
- case PGM_FIXPT_OVERFLOW:
- sig = TARGET_SIGFPE;
- n = TARGET_FPE_INTOVF;
- goto do_signal_pc;
- case PGM_FIXPT_DIVIDE:
- sig = TARGET_SIGFPE;
- n = TARGET_FPE_INTDIV;
- goto do_signal_pc;
-
- case PGM_DATA:
- n = (env->fpc >> 8) & 0xff;
- if (n == 0xff) {
- /* compare-and-trap */
- goto do_sigill_opn;
- } else {
- /* An IEEE exception, simulated or otherwise. */
- if (n & 0x80) {
- n = TARGET_FPE_FLTINV;
- } else if (n & 0x40) {
- n = TARGET_FPE_FLTDIV;
- } else if (n & 0x20) {
- n = TARGET_FPE_FLTOVF;
- } else if (n & 0x10) {
- n = TARGET_FPE_FLTUND;
- } else if (n & 0x08) {
- n = TARGET_FPE_FLTRES;
- } else {
- /* ??? Quantum exception; BFP, DFP error. */
- goto do_sigill_opn;
- }
- sig = TARGET_SIGFPE;
- goto do_signal_pc;
- }
-
- default:
- fprintf(stderr, "Unhandled program exception: %#x\n", n);
- cpu_dump_state(cs, stderr, fprintf, 0);
- exit(EXIT_FAILURE);
- }
- break;
-
- do_signal_pc:
- addr = env->psw.addr;
- do_signal:
- info.si_signo = sig;
- info.si_errno = 0;
- info.si_code = n;
- info._sifields._sigfault._addr = addr;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
-
- case EXCP_ATOMIC:
- cpu_exec_step_atomic(cs);
- break;
- default:
- fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr);
- cpu_dump_state(cs, stderr, fprintf, 0);
- exit(EXIT_FAILURE);
- }
- process_pending_signals (env);
- }
-}
-
-#endif /* TARGET_S390X */
-
-#ifdef TARGET_TILEGX
-
-static void gen_sigill_reg(CPUTLGState *env)
-{
- target_siginfo_t info;
-
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_PRVREG;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
-}
-
-static void do_signal(CPUTLGState *env, int signo, int sigcode)
-{
- target_siginfo_t info;
-
- info.si_signo = signo;
- info.si_errno = 0;
- info._sifields._sigfault._addr = env->pc;
-
- if (signo == TARGET_SIGSEGV) {
- /* The passed in sigcode is a dummy; check for a page mapping
- and pass either MAPERR or ACCERR. */
- target_ulong addr = env->excaddr;
- info._sifields._sigfault._addr = addr;
- if (page_check_range(addr, 1, PAGE_VALID) < 0) {
- sigcode = TARGET_SEGV_MAPERR;
- } else {
- sigcode = TARGET_SEGV_ACCERR;
- }
- }
- info.si_code = sigcode;
-
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
-}
-
-static void gen_sigsegv_maperr(CPUTLGState *env, target_ulong addr)
-{
- env->excaddr = addr;
- do_signal(env, TARGET_SIGSEGV, 0);
-}
-
-static void set_regval(CPUTLGState *env, uint8_t reg, uint64_t val)
-{
- if (unlikely(reg >= TILEGX_R_COUNT)) {
- switch (reg) {
- case TILEGX_R_SN:
- case TILEGX_R_ZERO:
- return;
- case TILEGX_R_IDN0:
- case TILEGX_R_IDN1:
- case TILEGX_R_UDN0:
- case TILEGX_R_UDN1:
- case TILEGX_R_UDN2:
- case TILEGX_R_UDN3:
- gen_sigill_reg(env);
- return;
- default:
- g_assert_not_reached();
- }
- }
- env->regs[reg] = val;
-}
-
-/*
- * Compare the 8-byte contents of the CmpValue SPR with the 8-byte value in
- * memory at the address held in the first source register. If the values are
- * not equal, then no memory operation is performed. If the values are equal,
- * the 8-byte quantity from the second source register is written into memory
- * at the address held in the first source register. In either case, the result
- * of the instruction is the value read from memory. The compare and write to
- * memory are atomic and thus can be used for synchronization purposes. This
- * instruction only operates for addresses aligned to a 8-byte boundary.
- * Unaligned memory access causes an Unaligned Data Reference interrupt.
- *
- * Functional Description (64-bit)
- * uint64_t memVal = memoryReadDoubleWord (rf[SrcA]);
- * rf[Dest] = memVal;
- * if (memVal == SPR[CmpValueSPR])
- * memoryWriteDoubleWord (rf[SrcA], rf[SrcB]);
- *
- * Functional Description (32-bit)
- * uint64_t memVal = signExtend32 (memoryReadWord (rf[SrcA]));
- * rf[Dest] = memVal;
- * if (memVal == signExtend32 (SPR[CmpValueSPR]))
- * memoryWriteWord (rf[SrcA], rf[SrcB]);
- *
- *
- * This function also processes exch and exch4 which need not process SPR.
- */
-static void do_exch(CPUTLGState *env, bool quad, bool cmp)
-{
- target_ulong addr;
- target_long val, sprval;
-
- start_exclusive();
-
- addr = env->atomic_srca;
- if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) {
- goto sigsegv_maperr;
- }
-
- if (cmp) {
- if (quad) {
- sprval = env->spregs[TILEGX_SPR_CMPEXCH];
- } else {
- sprval = sextract64(env->spregs[TILEGX_SPR_CMPEXCH], 0, 32);
- }
- }
-
- if (!cmp || val == sprval) {
- target_long valb = env->atomic_srcb;
- if (quad ? put_user_u64(valb, addr) : put_user_u32(valb, addr)) {
- goto sigsegv_maperr;
- }
- }
-
- set_regval(env, env->atomic_dstr, val);
- end_exclusive();
- return;
-
- sigsegv_maperr:
- end_exclusive();
- gen_sigsegv_maperr(env, addr);
-}
-
-static void do_fetch(CPUTLGState *env, int trapnr, bool quad)
-{
- int8_t write = 1;
- target_ulong addr;
- target_long val, valb;
-
- start_exclusive();
-
- addr = env->atomic_srca;
- valb = env->atomic_srcb;
- if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) {
- goto sigsegv_maperr;
- }
-
- switch (trapnr) {
- case TILEGX_EXCP_OPCODE_FETCHADD:
- case TILEGX_EXCP_OPCODE_FETCHADD4:
- valb += val;
- break;
- case TILEGX_EXCP_OPCODE_FETCHADDGEZ:
- valb += val;
- if (valb < 0) {
- write = 0;
- }
- break;
- case TILEGX_EXCP_OPCODE_FETCHADDGEZ4:
- valb += val;
- if ((int32_t)valb < 0) {
- write = 0;
- }
- break;
- case TILEGX_EXCP_OPCODE_FETCHAND:
- case TILEGX_EXCP_OPCODE_FETCHAND4:
- valb &= val;
- break;
- case TILEGX_EXCP_OPCODE_FETCHOR:
- case TILEGX_EXCP_OPCODE_FETCHOR4:
- valb |= val;
- break;
- default:
- g_assert_not_reached();
- }
-
- if (write) {
- if (quad ? put_user_u64(valb, addr) : put_user_u32(valb, addr)) {
- goto sigsegv_maperr;
- }
- }
-
- set_regval(env, env->atomic_dstr, val);
- end_exclusive();
- return;
-
- sigsegv_maperr:
- end_exclusive();
- gen_sigsegv_maperr(env, addr);
-}
-
-void cpu_loop(CPUTLGState *env)
-{
- CPUState *cs = CPU(tilegx_env_get_cpu(env));
- int trapnr;
-
- while (1) {
- cpu_exec_start(cs);
- trapnr = cpu_exec(cs);
- cpu_exec_end(cs);
- process_queued_cpu_work(cs);
-
- switch (trapnr) {
- case TILEGX_EXCP_SYSCALL:
- {
- abi_ulong ret = do_syscall(env, env->regs[TILEGX_R_NR],
- env->regs[0], env->regs[1],
- env->regs[2], env->regs[3],
- env->regs[4], env->regs[5],
- env->regs[6], env->regs[7]);
- if (ret == -TARGET_ERESTARTSYS) {
- env->pc -= 8;
- } else if (ret != -TARGET_QEMU_ESIGRETURN) {
- env->regs[TILEGX_R_RE] = ret;
- env->regs[TILEGX_R_ERR] = TILEGX_IS_ERRNO(ret) ? -ret : 0;
- }
- break;
- }
- case TILEGX_EXCP_OPCODE_EXCH:
- do_exch(env, true, false);
- break;
- case TILEGX_EXCP_OPCODE_EXCH4:
- do_exch(env, false, false);
- break;
- case TILEGX_EXCP_OPCODE_CMPEXCH:
- do_exch(env, true, true);
- break;
- case TILEGX_EXCP_OPCODE_CMPEXCH4:
- do_exch(env, false, true);
- break;
- case TILEGX_EXCP_OPCODE_FETCHADD:
- case TILEGX_EXCP_OPCODE_FETCHADDGEZ:
- case TILEGX_EXCP_OPCODE_FETCHAND:
- case TILEGX_EXCP_OPCODE_FETCHOR:
- do_fetch(env, trapnr, true);
- break;
- case TILEGX_EXCP_OPCODE_FETCHADD4:
- case TILEGX_EXCP_OPCODE_FETCHADDGEZ4:
- case TILEGX_EXCP_OPCODE_FETCHAND4:
- case TILEGX_EXCP_OPCODE_FETCHOR4:
- do_fetch(env, trapnr, false);
- break;
- case TILEGX_EXCP_SIGNAL:
- do_signal(env, env->signo, env->sigcode);
- break;
- case TILEGX_EXCP_REG_IDN_ACCESS:
- case TILEGX_EXCP_REG_UDN_ACCESS:
- gen_sigill_reg(env);
- break;
- case EXCP_ATOMIC:
- cpu_exec_step_atomic(cs);
- break;
- default:
- fprintf(stderr, "trapnr is %d[0x%x].\n", trapnr, trapnr);
- g_assert_not_reached();
- }
- process_pending_signals(env);
- }
-}
-
-#endif
-
-#ifdef TARGET_RISCV
-
-void cpu_loop(CPURISCVState *env)
-{
- CPUState *cs = CPU(riscv_env_get_cpu(env));
- int trapnr, signum, sigcode;
- target_ulong sigaddr;
- target_ulong ret;
-
- for (;;) {
- cpu_exec_start(cs);
- trapnr = cpu_exec(cs);
- cpu_exec_end(cs);
- process_queued_cpu_work(cs);
-
- signum = 0;
- sigcode = 0;
- sigaddr = 0;
-
- switch (trapnr) {
- case EXCP_INTERRUPT:
- /* just indicate that signals should be handled asap */
- break;
- case EXCP_ATOMIC:
- cpu_exec_step_atomic(cs);
- break;
- case RISCV_EXCP_U_ECALL:
- env->pc += 4;
- if (env->gpr[xA7] == TARGET_NR_arch_specific_syscall + 15) {
- /* riscv_flush_icache_syscall is a no-op in QEMU as
- self-modifying code is automatically detected */
- ret = 0;
- } else {
- ret = do_syscall(env,
- env->gpr[xA7],
- env->gpr[xA0],
- env->gpr[xA1],
- env->gpr[xA2],
- env->gpr[xA3],
- env->gpr[xA4],
- env->gpr[xA5],
- 0, 0);
- }
- if (ret == -TARGET_ERESTARTSYS) {
- env->pc -= 4;
- } else if (ret != -TARGET_QEMU_ESIGRETURN) {
- env->gpr[xA0] = ret;
- }
- if (cs->singlestep_enabled) {
- goto gdbstep;
- }
- break;
- case RISCV_EXCP_ILLEGAL_INST:
- signum = TARGET_SIGILL;
- sigcode = TARGET_ILL_ILLOPC;
- break;
- case RISCV_EXCP_BREAKPOINT:
- signum = TARGET_SIGTRAP;
- sigcode = TARGET_TRAP_BRKPT;
- sigaddr = env->pc;
- break;
- case RISCV_EXCP_INST_PAGE_FAULT:
- case RISCV_EXCP_LOAD_PAGE_FAULT:
- case RISCV_EXCP_STORE_PAGE_FAULT:
- signum = TARGET_SIGSEGV;
- sigcode = TARGET_SEGV_MAPERR;
- break;
- case EXCP_DEBUG:
- gdbstep:
- signum = gdb_handlesig(cs, TARGET_SIGTRAP);
- sigcode = TARGET_TRAP_BRKPT;
- break;
- default:
- EXCP_DUMP(env, "\nqemu: unhandled CPU exception %#x - aborting\n",
- trapnr);
- exit(EXIT_FAILURE);
- }
-
- if (signum) {
- target_siginfo_t info = {
- .si_signo = signum,
- .si_errno = 0,
- .si_code = sigcode,
- ._sifields._sigfault._addr = sigaddr
- };
- queue_signal(env, info.si_signo, QEMU_SI_KILL, &info);
- }
-
- process_pending_signals(env);
- }
-}
-
-#endif /* TARGET_RISCV */
-
-#ifdef TARGET_HPPA
-
-static abi_ulong hppa_lws(CPUHPPAState *env)
-{
- uint32_t which = env->gr[20];
- abi_ulong addr = env->gr[26];
- abi_ulong old = env->gr[25];
- abi_ulong new = env->gr[24];
- abi_ulong size, ret;
-
- switch (which) {
- default:
- return -TARGET_ENOSYS;
-
- case 0: /* elf32 atomic 32bit cmpxchg */
- if ((addr & 3) || !access_ok(VERIFY_WRITE, addr, 4)) {
- return -TARGET_EFAULT;
- }
- old = tswap32(old);
- new = tswap32(new);
- ret = atomic_cmpxchg((uint32_t *)g2h(addr), old, new);
- ret = tswap32(ret);
- break;
-
- case 2: /* elf32 atomic "new" cmpxchg */
- size = env->gr[23];
- if (size >= 4) {
- return -TARGET_ENOSYS;
- }
- if (((addr | old | new) & ((1 << size) - 1))
- || !access_ok(VERIFY_WRITE, addr, 1 << size)
- || !access_ok(VERIFY_READ, old, 1 << size)
- || !access_ok(VERIFY_READ, new, 1 << size)) {
- return -TARGET_EFAULT;
- }
- /* Note that below we use host-endian loads so that the cmpxchg
- can be host-endian as well. */
- switch (size) {
- case 0:
- old = *(uint8_t *)g2h(old);
- new = *(uint8_t *)g2h(new);
- ret = atomic_cmpxchg((uint8_t *)g2h(addr), old, new);
- ret = ret != old;
- break;
- case 1:
- old = *(uint16_t *)g2h(old);
- new = *(uint16_t *)g2h(new);
- ret = atomic_cmpxchg((uint16_t *)g2h(addr), old, new);
- ret = ret != old;
- break;
- case 2:
- old = *(uint32_t *)g2h(old);
- new = *(uint32_t *)g2h(new);
- ret = atomic_cmpxchg((uint32_t *)g2h(addr), old, new);
- ret = ret != old;
- break;
- case 3:
- {
- uint64_t o64, n64, r64;
- o64 = *(uint64_t *)g2h(old);
- n64 = *(uint64_t *)g2h(new);
-#ifdef CONFIG_ATOMIC64
- r64 = atomic_cmpxchg__nocheck((uint64_t *)g2h(addr), o64, n64);
- ret = r64 != o64;
-#else
- start_exclusive();
- r64 = *(uint64_t *)g2h(addr);
- ret = 1;
- if (r64 == o64) {
- *(uint64_t *)g2h(addr) = n64;
- ret = 0;
- }
- end_exclusive();
-#endif
- }
- break;
- }
- break;
- }
-
- env->gr[28] = ret;
- return 0;
-}
-
-void cpu_loop(CPUHPPAState *env)
-{
- CPUState *cs = CPU(hppa_env_get_cpu(env));
- target_siginfo_t info;
- abi_ulong ret;
- int trapnr;
-
- while (1) {
- cpu_exec_start(cs);
- trapnr = cpu_exec(cs);
- cpu_exec_end(cs);
- process_queued_cpu_work(cs);
-
- switch (trapnr) {
- case EXCP_SYSCALL:
- ret = do_syscall(env, env->gr[20],
- env->gr[26], env->gr[25],
- env->gr[24], env->gr[23],
- env->gr[22], env->gr[21], 0, 0);
- switch (ret) {
- default:
- env->gr[28] = ret;
- /* We arrived here by faking the gateway page. Return. */
- env->iaoq_f = env->gr[31];
- env->iaoq_b = env->gr[31] + 4;
- break;
- case -TARGET_ERESTARTSYS:
- case -TARGET_QEMU_ESIGRETURN:
- break;
- }
- break;
- case EXCP_SYSCALL_LWS:
- env->gr[21] = hppa_lws(env);
- /* We arrived here by faking the gateway page. Return. */
- env->iaoq_f = env->gr[31];
- env->iaoq_b = env->gr[31] + 4;
- break;
- case EXCP_ITLB_MISS:
- case EXCP_DTLB_MISS:
- case EXCP_NA_ITLB_MISS:
- case EXCP_NA_DTLB_MISS:
- case EXCP_IMP:
- case EXCP_DMP:
- case EXCP_DMB:
- case EXCP_PAGE_REF:
- case EXCP_DMAR:
- case EXCP_DMPI:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_ACCERR;
- info._sifields._sigfault._addr = env->cr[CR_IOR];
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP_UNALIGN:
- info.si_signo = TARGET_SIGBUS;
- info.si_errno = 0;
- info.si_code = 0;
- info._sifields._sigfault._addr = env->cr[CR_IOR];
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP_ILL:
- case EXCP_PRIV_OPR:
- case EXCP_PRIV_REG:
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLOPN;
- info._sifields._sigfault._addr = env->iaoq_f;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP_OVERFLOW:
- case EXCP_COND:
- case EXCP_ASSIST:
- info.si_signo = TARGET_SIGFPE;
- info.si_errno = 0;
- info.si_code = 0;
- info._sifields._sigfault._addr = env->iaoq_f;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
- case EXCP_DEBUG:
- trapnr = gdb_handlesig(cs, TARGET_SIGTRAP);
- if (trapnr) {
- info.si_signo = trapnr;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, trapnr, QEMU_SI_FAULT, &info);
- }
- break;
- case EXCP_INTERRUPT:
- /* just indicate that signals should be handled asap */
- break;
- default:
- g_assert_not_reached();
- }
- process_pending_signals(env);
- }
-}
-
-#endif /* TARGET_HPPA */
-
-#ifdef TARGET_XTENSA
-
-static void xtensa_rfw(CPUXtensaState *env)
-{
- xtensa_restore_owb(env);
- env->pc = env->sregs[EPC1];
-}
-
-static void xtensa_rfwu(CPUXtensaState *env)
-{
- env->sregs[WINDOW_START] |= (1 << env->sregs[WINDOW_BASE]);
- xtensa_rfw(env);
-}
-
-static void xtensa_rfwo(CPUXtensaState *env)
-{
- env->sregs[WINDOW_START] &= ~(1 << env->sregs[WINDOW_BASE]);
- xtensa_rfw(env);
-}
-
-static void xtensa_overflow4(CPUXtensaState *env)
-{
- put_user_ual(env->regs[0], env->regs[5] - 16);
- put_user_ual(env->regs[1], env->regs[5] - 12);
- put_user_ual(env->regs[2], env->regs[5] - 8);
- put_user_ual(env->regs[3], env->regs[5] - 4);
- xtensa_rfwo(env);
-}
-
-static void xtensa_underflow4(CPUXtensaState *env)
-{
- get_user_ual(env->regs[0], env->regs[5] - 16);
- get_user_ual(env->regs[1], env->regs[5] - 12);
- get_user_ual(env->regs[2], env->regs[5] - 8);
- get_user_ual(env->regs[3], env->regs[5] - 4);
- xtensa_rfwu(env);
-}
-
-static void xtensa_overflow8(CPUXtensaState *env)
-{
- put_user_ual(env->regs[0], env->regs[9] - 16);
- get_user_ual(env->regs[0], env->regs[1] - 12);
- put_user_ual(env->regs[1], env->regs[9] - 12);
- put_user_ual(env->regs[2], env->regs[9] - 8);
- put_user_ual(env->regs[3], env->regs[9] - 4);
- put_user_ual(env->regs[4], env->regs[0] - 32);
- put_user_ual(env->regs[5], env->regs[0] - 28);
- put_user_ual(env->regs[6], env->regs[0] - 24);
- put_user_ual(env->regs[7], env->regs[0] - 20);
- xtensa_rfwo(env);
-}
-
-static void xtensa_underflow8(CPUXtensaState *env)
-{
- get_user_ual(env->regs[0], env->regs[9] - 16);
- get_user_ual(env->regs[1], env->regs[9] - 12);
- get_user_ual(env->regs[2], env->regs[9] - 8);
- get_user_ual(env->regs[7], env->regs[1] - 12);
- get_user_ual(env->regs[3], env->regs[9] - 4);
- get_user_ual(env->regs[4], env->regs[7] - 32);
- get_user_ual(env->regs[5], env->regs[7] - 28);
- get_user_ual(env->regs[6], env->regs[7] - 24);
- get_user_ual(env->regs[7], env->regs[7] - 20);
- xtensa_rfwu(env);
-}
-
-static void xtensa_overflow12(CPUXtensaState *env)
-{
- put_user_ual(env->regs[0], env->regs[13] - 16);
- get_user_ual(env->regs[0], env->regs[1] - 12);
- put_user_ual(env->regs[1], env->regs[13] - 12);
- put_user_ual(env->regs[2], env->regs[13] - 8);
- put_user_ual(env->regs[3], env->regs[13] - 4);
- put_user_ual(env->regs[4], env->regs[0] - 48);
- put_user_ual(env->regs[5], env->regs[0] - 44);
- put_user_ual(env->regs[6], env->regs[0] - 40);
- put_user_ual(env->regs[7], env->regs[0] - 36);
- put_user_ual(env->regs[8], env->regs[0] - 32);
- put_user_ual(env->regs[9], env->regs[0] - 28);
- put_user_ual(env->regs[10], env->regs[0] - 24);
- put_user_ual(env->regs[11], env->regs[0] - 20);
- xtensa_rfwo(env);
-}
-
-static void xtensa_underflow12(CPUXtensaState *env)
-{
- get_user_ual(env->regs[0], env->regs[13] - 16);
- get_user_ual(env->regs[1], env->regs[13] - 12);
- get_user_ual(env->regs[2], env->regs[13] - 8);
- get_user_ual(env->regs[11], env->regs[1] - 12);
- get_user_ual(env->regs[3], env->regs[13] - 4);
- get_user_ual(env->regs[4], env->regs[11] - 48);
- get_user_ual(env->regs[5], env->regs[11] - 44);
- get_user_ual(env->regs[6], env->regs[11] - 40);
- get_user_ual(env->regs[7], env->regs[11] - 36);
- get_user_ual(env->regs[8], env->regs[11] - 32);
- get_user_ual(env->regs[9], env->regs[11] - 28);
- get_user_ual(env->regs[10], env->regs[11] - 24);
- get_user_ual(env->regs[11], env->regs[11] - 20);
- xtensa_rfwu(env);
-}
-
-void cpu_loop(CPUXtensaState *env)
-{
- CPUState *cs = CPU(xtensa_env_get_cpu(env));
- target_siginfo_t info;
- abi_ulong ret;
- int trapnr;
-
- while (1) {
- cpu_exec_start(cs);
- trapnr = cpu_exec(cs);
- cpu_exec_end(cs);
- process_queued_cpu_work(cs);
-
- env->sregs[PS] &= ~PS_EXCM;
- switch (trapnr) {
- case EXCP_INTERRUPT:
- break;
-
- case EXC_WINDOW_OVERFLOW4:
- xtensa_overflow4(env);
- break;
- case EXC_WINDOW_UNDERFLOW4:
- xtensa_underflow4(env);
- break;
- case EXC_WINDOW_OVERFLOW8:
- xtensa_overflow8(env);
- break;
- case EXC_WINDOW_UNDERFLOW8:
- xtensa_underflow8(env);
- break;
- case EXC_WINDOW_OVERFLOW12:
- xtensa_overflow12(env);
- break;
- case EXC_WINDOW_UNDERFLOW12:
- xtensa_underflow12(env);
- break;
-
- case EXC_USER:
- switch (env->sregs[EXCCAUSE]) {
- case ILLEGAL_INSTRUCTION_CAUSE:
- case PRIVILEGED_CAUSE:
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code =
- env->sregs[EXCCAUSE] == ILLEGAL_INSTRUCTION_CAUSE ?
- TARGET_ILL_ILLOPC : TARGET_ILL_PRVOPC;
- info._sifields._sigfault._addr = env->sregs[EPC1];
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
-
- case SYSCALL_CAUSE:
- env->pc += 3;
- ret = do_syscall(env, env->regs[2],
- env->regs[6], env->regs[3],
- env->regs[4], env->regs[5],
- env->regs[8], env->regs[9], 0, 0);
- switch (ret) {
- default:
- env->regs[2] = ret;
- break;
-
- case -TARGET_ERESTARTSYS:
- env->pc -= 3;
- break;
-
- case -TARGET_QEMU_ESIGRETURN:
- break;
- }
- break;
-
- case ALLOCA_CAUSE:
- env->sregs[PS] = deposit32(env->sregs[PS],
- PS_OWB_SHIFT,
- PS_OWB_LEN,
- env->sregs[WINDOW_BASE]);
-
- switch (env->regs[0] & 0xc0000000) {
- case 0x00000000:
- case 0x40000000:
- xtensa_rotate_window(env, -1);
- xtensa_underflow4(env);
- break;
-
- case 0x80000000:
- xtensa_rotate_window(env, -2);
- xtensa_underflow8(env);
- break;
-
- case 0xc0000000:
- xtensa_rotate_window(env, -3);
- xtensa_underflow12(env);
- break;
- }
- break;
-
- case INTEGER_DIVIDE_BY_ZERO_CAUSE:
- info.si_signo = TARGET_SIGFPE;
- info.si_errno = 0;
- info.si_code = TARGET_FPE_INTDIV;
- info._sifields._sigfault._addr = env->sregs[EPC1];
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
-
- case LOAD_PROHIBITED_CAUSE:
- case STORE_PROHIBITED_CAUSE:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_ACCERR;
- info._sifields._sigfault._addr = env->sregs[EXCVADDR];
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- break;
-
- default:
- fprintf(stderr, "exccause = %d\n", env->sregs[EXCCAUSE]);
- g_assert_not_reached();
- }
- break;
- case EXCP_DEBUG:
- trapnr = gdb_handlesig(cs, TARGET_SIGTRAP);
- if (trapnr) {
- info.si_signo = trapnr;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, trapnr, QEMU_SI_FAULT, &info);
- }
- break;
- case EXC_DEBUG:
- default:
- fprintf(stderr, "trapnr = %d\n", trapnr);
- g_assert_not_reached();
- }
- process_pending_signals(env);
- }
-}
-
-#endif /* TARGET_XTENSA */
-
__thread CPUState *thread_cpu;
bool qemu_cpu_is_self(CPUState *cpu)
@@ -4736,405 +804,7 @@ int main(int argc, char **argv, char **envp)
tcg_prologue_init(tcg_ctx);
tcg_region_init();
-#if defined(TARGET_I386)
- env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
- env->hflags |= HF_PE_MASK | HF_CPL_MASK;
- if (env->features[FEAT_1_EDX] & CPUID_SSE) {
- env->cr[4] |= CR4_OSFXSR_MASK;
- env->hflags |= HF_OSFXSR_MASK;
- }
-#ifndef TARGET_ABI32
- /* enable 64 bit mode if possible */
- if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) {
- fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
- exit(EXIT_FAILURE);
- }
- env->cr[4] |= CR4_PAE_MASK;
- env->efer |= MSR_EFER_LMA | MSR_EFER_LME;
- env->hflags |= HF_LMA_MASK;
-#endif
-
- /* flags setup : we activate the IRQs by default as in user mode */
- env->eflags |= IF_MASK;
-
- /* linux register setup */
-#ifndef TARGET_ABI32
- env->regs[R_EAX] = regs->rax;
- env->regs[R_EBX] = regs->rbx;
- env->regs[R_ECX] = regs->rcx;
- env->regs[R_EDX] = regs->rdx;
- env->regs[R_ESI] = regs->rsi;
- env->regs[R_EDI] = regs->rdi;
- env->regs[R_EBP] = regs->rbp;
- env->regs[R_ESP] = regs->rsp;
- env->eip = regs->rip;
-#else
- env->regs[R_EAX] = regs->eax;
- env->regs[R_EBX] = regs->ebx;
- env->regs[R_ECX] = regs->ecx;
- env->regs[R_EDX] = regs->edx;
- env->regs[R_ESI] = regs->esi;
- env->regs[R_EDI] = regs->edi;
- env->regs[R_EBP] = regs->ebp;
- env->regs[R_ESP] = regs->esp;
- env->eip = regs->eip;
-#endif
-
- /* linux interrupt setup */
-#ifndef TARGET_ABI32
- env->idt.limit = 511;
-#else
- env->idt.limit = 255;
-#endif
- env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
- PROT_READ|PROT_WRITE,
- MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
- idt_table = g2h(env->idt.base);
- set_idt(0, 0);
- set_idt(1, 0);
- set_idt(2, 0);
- set_idt(3, 3);
- set_idt(4, 3);
- set_idt(5, 0);
- set_idt(6, 0);
- set_idt(7, 0);
- set_idt(8, 0);
- set_idt(9, 0);
- set_idt(10, 0);
- set_idt(11, 0);
- set_idt(12, 0);
- set_idt(13, 0);
- set_idt(14, 0);
- set_idt(15, 0);
- set_idt(16, 0);
- set_idt(17, 0);
- set_idt(18, 0);
- set_idt(19, 0);
- set_idt(0x80, 3);
-
- /* linux segment setup */
- {
- uint64_t *gdt_table;
- env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
- PROT_READ|PROT_WRITE,
- MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
- env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
- gdt_table = g2h(env->gdt.base);
-#ifdef TARGET_ABI32
- write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
- (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
-#else
- /* 64 bit code segment */
- write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
- DESC_L_MASK |
- (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
-#endif
- write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
- (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
- }
- cpu_x86_load_seg(env, R_CS, __USER_CS);
- cpu_x86_load_seg(env, R_SS, __USER_DS);
-#ifdef TARGET_ABI32
- cpu_x86_load_seg(env, R_DS, __USER_DS);
- cpu_x86_load_seg(env, R_ES, __USER_DS);
- cpu_x86_load_seg(env, R_FS, __USER_DS);
- cpu_x86_load_seg(env, R_GS, __USER_DS);
- /* This hack makes Wine work... */
- env->segs[R_FS].selector = 0;
-#else
- cpu_x86_load_seg(env, R_DS, 0);
- cpu_x86_load_seg(env, R_ES, 0);
- cpu_x86_load_seg(env, R_FS, 0);
- cpu_x86_load_seg(env, R_GS, 0);
-#endif
-#elif defined(TARGET_AARCH64)
- {
- int i;
-
- if (!(arm_feature(env, ARM_FEATURE_AARCH64))) {
- fprintf(stderr,
- "The selected ARM CPU does not support 64 bit mode\n");
- exit(EXIT_FAILURE);
- }
-
- for (i = 0; i < 31; i++) {
- env->xregs[i] = regs->regs[i];
- }
- env->pc = regs->pc;
- env->xregs[31] = regs->sp;
-#ifdef TARGET_WORDS_BIGENDIAN
- env->cp15.sctlr_el[1] |= SCTLR_E0E;
- for (i = 1; i < 4; ++i) {
- env->cp15.sctlr_el[i] |= SCTLR_EE;
- }
-#endif
- }
-#elif defined(TARGET_ARM)
- {
- int i;
- cpsr_write(env, regs->uregs[16], CPSR_USER | CPSR_EXEC,
- CPSRWriteByInstr);
- for(i = 0; i < 16; i++) {
- env->regs[i] = regs->uregs[i];
- }
-#ifdef TARGET_WORDS_BIGENDIAN
- /* Enable BE8. */
- if (EF_ARM_EABI_VERSION(info->elf_flags) >= EF_ARM_EABI_VER4
- && (info->elf_flags & EF_ARM_BE8)) {
- env->uncached_cpsr |= CPSR_E;
- env->cp15.sctlr_el[1] |= SCTLR_E0E;
- } else {
- env->cp15.sctlr_el[1] |= SCTLR_B;
- }
-#endif
- }
-#elif defined(TARGET_SPARC)
- {
- int i;
- env->pc = regs->pc;
- env->npc = regs->npc;
- env->y = regs->y;
- for(i = 0; i < 8; i++)
- env->gregs[i] = regs->u_regs[i];
- for(i = 0; i < 8; i++)
- env->regwptr[i] = regs->u_regs[i + 8];
- }
-#elif defined(TARGET_PPC)
- {
- int i;
-
-#if defined(TARGET_PPC64)
- int flag = (env->insns_flags2 & PPC2_BOOKE206) ? MSR_CM : MSR_SF;
-#if defined(TARGET_ABI32)
- env->msr &= ~((target_ulong)1 << flag);
-#else
- env->msr |= (target_ulong)1 << flag;
-#endif
-#endif
- env->nip = regs->nip;
- for(i = 0; i < 32; i++) {
- env->gpr[i] = regs->gpr[i];
- }
- }
-#elif defined(TARGET_M68K)
- {
- env->pc = regs->pc;
- env->dregs[0] = regs->d0;
- env->dregs[1] = regs->d1;
- env->dregs[2] = regs->d2;
- env->dregs[3] = regs->d3;
- env->dregs[4] = regs->d4;
- env->dregs[5] = regs->d5;
- env->dregs[6] = regs->d6;
- env->dregs[7] = regs->d7;
- env->aregs[0] = regs->a0;
- env->aregs[1] = regs->a1;
- env->aregs[2] = regs->a2;
- env->aregs[3] = regs->a3;
- env->aregs[4] = regs->a4;
- env->aregs[5] = regs->a5;
- env->aregs[6] = regs->a6;
- env->aregs[7] = regs->usp;
- env->sr = regs->sr;
- ts->sim_syscalls = 1;
- }
-#elif defined(TARGET_MICROBLAZE)
- {
- env->regs[0] = regs->r0;
- env->regs[1] = regs->r1;
- env->regs[2] = regs->r2;
- env->regs[3] = regs->r3;
- env->regs[4] = regs->r4;
- env->regs[5] = regs->r5;
- env->regs[6] = regs->r6;
- env->regs[7] = regs->r7;
- env->regs[8] = regs->r8;
- env->regs[9] = regs->r9;
- env->regs[10] = regs->r10;
- env->regs[11] = regs->r11;
- env->regs[12] = regs->r12;
- env->regs[13] = regs->r13;
- env->regs[14] = regs->r14;
- env->regs[15] = regs->r15;
- env->regs[16] = regs->r16;
- env->regs[17] = regs->r17;
- env->regs[18] = regs->r18;
- env->regs[19] = regs->r19;
- env->regs[20] = regs->r20;
- env->regs[21] = regs->r21;
- env->regs[22] = regs->r22;
- env->regs[23] = regs->r23;
- env->regs[24] = regs->r24;
- env->regs[25] = regs->r25;
- env->regs[26] = regs->r26;
- env->regs[27] = regs->r27;
- env->regs[28] = regs->r28;
- env->regs[29] = regs->r29;
- env->regs[30] = regs->r30;
- env->regs[31] = regs->r31;
- env->sregs[SR_PC] = regs->pc;
- }
-#elif defined(TARGET_MIPS)
- {
- int i;
-
- for(i = 0; i < 32; i++) {
- env->active_tc.gpr[i] = regs->regs[i];
- }
- env->active_tc.PC = regs->cp0_epc & ~(target_ulong)1;
- if (regs->cp0_epc & 1) {
- env->hflags |= MIPS_HFLAG_M16;
- }
- if (((info->elf_flags & EF_MIPS_NAN2008) != 0) !=
- ((env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) != 0)) {
- if ((env->active_fpu.fcr31_rw_bitmask &
- (1 << FCR31_NAN2008)) == 0) {
- fprintf(stderr, "ELF binary's NaN mode not supported by CPU\n");
- exit(1);
- }
- if ((info->elf_flags & EF_MIPS_NAN2008) != 0) {
- env->active_fpu.fcr31 |= (1 << FCR31_NAN2008);
- } else {
- env->active_fpu.fcr31 &= ~(1 << FCR31_NAN2008);
- }
- restore_snan_bit_mode(env);
- }
- }
-#elif defined(TARGET_NIOS2)
- {
- env->regs[0] = 0;
- env->regs[1] = regs->r1;
- env->regs[2] = regs->r2;
- env->regs[3] = regs->r3;
- env->regs[4] = regs->r4;
- env->regs[5] = regs->r5;
- env->regs[6] = regs->r6;
- env->regs[7] = regs->r7;
- env->regs[8] = regs->r8;
- env->regs[9] = regs->r9;
- env->regs[10] = regs->r10;
- env->regs[11] = regs->r11;
- env->regs[12] = regs->r12;
- env->regs[13] = regs->r13;
- env->regs[14] = regs->r14;
- env->regs[15] = regs->r15;
- /* TODO: unsigned long orig_r2; */
- env->regs[R_RA] = regs->ra;
- env->regs[R_FP] = regs->fp;
- env->regs[R_SP] = regs->sp;
- env->regs[R_GP] = regs->gp;
- env->regs[CR_ESTATUS] = regs->estatus;
- env->regs[R_EA] = regs->ea;
- /* TODO: unsigned long orig_r7; */
-
- /* Emulate eret when starting thread. */
- env->regs[R_PC] = regs->ea;
- }
-#elif defined(TARGET_OPENRISC)
- {
- int i;
-
- for (i = 0; i < 32; i++) {
- cpu_set_gpr(env, i, regs->gpr[i]);
- }
- env->pc = regs->pc;
- cpu_set_sr(env, regs->sr);
- }
-#elif defined(TARGET_RISCV)
- {
- env->pc = regs->sepc;
- env->gpr[xSP] = regs->sp;
- }
-#elif defined(TARGET_SH4)
- {
- int i;
-
- for(i = 0; i < 16; i++) {
- env->gregs[i] = regs->regs[i];
- }
- env->pc = regs->pc;
- }
-#elif defined(TARGET_ALPHA)
- {
- int i;
-
- for(i = 0; i < 28; i++) {
- env->ir[i] = ((abi_ulong *)regs)[i];
- }
- env->ir[IR_SP] = regs->usp;
- env->pc = regs->pc;
- }
-#elif defined(TARGET_CRIS)
- {
- env->regs[0] = regs->r0;
- env->regs[1] = regs->r1;
- env->regs[2] = regs->r2;
- env->regs[3] = regs->r3;
- env->regs[4] = regs->r4;
- env->regs[5] = regs->r5;
- env->regs[6] = regs->r6;
- env->regs[7] = regs->r7;
- env->regs[8] = regs->r8;
- env->regs[9] = regs->r9;
- env->regs[10] = regs->r10;
- env->regs[11] = regs->r11;
- env->regs[12] = regs->r12;
- env->regs[13] = regs->r13;
- env->regs[14] = info->start_stack;
- env->regs[15] = regs->acr;
- env->pc = regs->erp;
- }
-#elif defined(TARGET_S390X)
- {
- int i;
- for (i = 0; i < 16; i++) {
- env->regs[i] = regs->gprs[i];
- }
- env->psw.mask = regs->psw.mask;
- env->psw.addr = regs->psw.addr;
- }
-#elif defined(TARGET_TILEGX)
- {
- int i;
- for (i = 0; i < TILEGX_R_COUNT; i++) {
- env->regs[i] = regs->regs[i];
- }
- for (i = 0; i < TILEGX_SPR_COUNT; i++) {
- env->spregs[i] = 0;
- }
- env->pc = regs->pc;
- }
-#elif defined(TARGET_HPPA)
- {
- int i;
- for (i = 1; i < 32; i++) {
- env->gr[i] = regs->gr[i];
- }
- env->iaoq_f = regs->iaoq[0];
- env->iaoq_b = regs->iaoq[1];
- }
-#elif defined(TARGET_XTENSA)
- {
- int i;
- for (i = 0; i < 16; ++i) {
- env->regs[i] = regs->areg[i];
- }
- env->sregs[WINDOW_START] = regs->windowstart;
- env->pc = regs->pc;
- }
-#else
-#error unsupported target CPU
-#endif
-
-#if defined(TARGET_ARM) || defined(TARGET_M68K)
- ts->stack_base = info->start_stack;
- ts->heap_base = info->brk;
- /* This will be filled in on the first SYS_HEAPINFO call. */
- ts->heap_limit = 0;
-#endif
+ target_cpu_copy_regs(env, regs);
if (gdbstub_port) {
if (gdbserver_start(gdbstub_port) < 0) {
diff --git a/linux-user/microblaze/cpu_loop.c b/linux-user/microblaze/cpu_loop.c
new file mode 100644
index 0000000000..5ffb83dea2
--- /dev/null
+++ b/linux-user/microblaze/cpu_loop.c
@@ -0,0 +1,176 @@
+/*
+ * qemu user cpu loop
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "cpu_loop-common.h"
+
+void cpu_loop(CPUMBState *env)
+{
+ CPUState *cs = CPU(mb_env_get_cpu(env));
+ int trapnr, ret;
+ target_siginfo_t info;
+
+ while (1) {
+ cpu_exec_start(cs);
+ trapnr = cpu_exec(cs);
+ cpu_exec_end(cs);
+ process_queued_cpu_work(cs);
+
+ switch (trapnr) {
+ case 0xaa:
+ {
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ /* XXX: check env->error_code */
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = 0;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+ break;
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+ case EXCP_BREAK:
+ /* Return address is 4 bytes after the call. */
+ env->regs[14] += 4;
+ env->sregs[SR_PC] = env->regs[14];
+ ret = do_syscall(env,
+ env->regs[12],
+ env->regs[5],
+ env->regs[6],
+ env->regs[7],
+ env->regs[8],
+ env->regs[9],
+ env->regs[10],
+ 0, 0);
+ if (ret == -TARGET_ERESTARTSYS) {
+ /* Wind back to before the syscall. */
+ env->sregs[SR_PC] -= 4;
+ } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+ env->regs[3] = ret;
+ }
+ /* All syscall exits result in guest r14 being equal to the
+ * PC we return to, because the kernel syscall exit "rtbd" does
+ * this. (This is true even for sigreturn(); note that r14 is
+ * not a userspace-usable register, as the kernel may clobber it
+ * at any point.)
+ */
+ env->regs[14] = env->sregs[SR_PC];
+ break;
+ case EXCP_HW_EXCP:
+ env->regs[17] = env->sregs[SR_PC] + 4;
+ if (env->iflags & D_FLAG) {
+ env->sregs[SR_ESR] |= 1 << 12;
+ env->sregs[SR_PC] -= 4;
+ /* FIXME: if branch was immed, replay the imm as well. */
+ }
+
+ env->iflags &= ~(IMM_FLAG | D_FLAG);
+
+ switch (env->sregs[SR_ESR] & 31) {
+ case ESR_EC_DIVZERO:
+ info.si_signo = TARGET_SIGFPE;
+ info.si_errno = 0;
+ info.si_code = TARGET_FPE_FLTDIV;
+ info._sifields._sigfault._addr = 0;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case ESR_EC_FPU:
+ info.si_signo = TARGET_SIGFPE;
+ info.si_errno = 0;
+ if (env->sregs[SR_FSR] & FSR_IO) {
+ info.si_code = TARGET_FPE_FLTINV;
+ }
+ if (env->sregs[SR_FSR] & FSR_DZ) {
+ info.si_code = TARGET_FPE_FLTDIV;
+ }
+ info._sifields._sigfault._addr = 0;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ default:
+ printf ("Unhandled hw-exception: 0x%x\n",
+ env->sregs[SR_ESR] & ESR_EC_MASK);
+ cpu_dump_state(cs, stderr, fprintf, 0);
+ exit(EXIT_FAILURE);
+ break;
+ }
+ break;
+ case EXCP_DEBUG:
+ {
+ int sig;
+
+ sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+ if (sig)
+ {
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+ }
+ break;
+ case EXCP_ATOMIC:
+ cpu_exec_step_atomic(cs);
+ break;
+ default:
+ printf ("Unhandled trap: 0x%x\n", trapnr);
+ cpu_dump_state(cs, stderr, fprintf, 0);
+ exit(EXIT_FAILURE);
+ }
+ process_pending_signals (env);
+ }
+}
+
+void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
+{
+ env->regs[0] = regs->r0;
+ env->regs[1] = regs->r1;
+ env->regs[2] = regs->r2;
+ env->regs[3] = regs->r3;
+ env->regs[4] = regs->r4;
+ env->regs[5] = regs->r5;
+ env->regs[6] = regs->r6;
+ env->regs[7] = regs->r7;
+ env->regs[8] = regs->r8;
+ env->regs[9] = regs->r9;
+ env->regs[10] = regs->r10;
+ env->regs[11] = regs->r11;
+ env->regs[12] = regs->r12;
+ env->regs[13] = regs->r13;
+ env->regs[14] = regs->r14;
+ env->regs[15] = regs->r15;
+ env->regs[16] = regs->r16;
+ env->regs[17] = regs->r17;
+ env->regs[18] = regs->r18;
+ env->regs[19] = regs->r19;
+ env->regs[20] = regs->r20;
+ env->regs[21] = regs->r21;
+ env->regs[22] = regs->r22;
+ env->regs[23] = regs->r23;
+ env->regs[24] = regs->r24;
+ env->regs[25] = regs->r25;
+ env->regs[26] = regs->r26;
+ env->regs[27] = regs->r27;
+ env->regs[28] = regs->r28;
+ env->regs[29] = regs->r29;
+ env->regs[30] = regs->r30;
+ env->regs[31] = regs->r31;
+ env->sregs[SR_PC] = regs->pc;
+}
diff --git a/linux-user/microblaze/signal.c b/linux-user/microblaze/signal.c
new file mode 100644
index 0000000000..fada0f1495
--- /dev/null
+++ b/linux-user/microblaze/signal.c
@@ -0,0 +1,246 @@
+/*
+ * Emulation of Linux signals
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "target_signal.h"
+#include "signal-common.h"
+#include "linux-user/trace.h"
+
+struct target_sigcontext {
+ struct target_pt_regs regs; /* needs to be first */
+ uint32_t oldmask;
+};
+
+struct target_stack_t {
+ abi_ulong ss_sp;
+ int ss_flags;
+ unsigned int ss_size;
+};
+
+struct target_ucontext {
+ abi_ulong tuc_flags;
+ abi_ulong tuc_link;
+ struct target_stack_t tuc_stack;
+ struct target_sigcontext tuc_mcontext;
+ uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
+};
+
+/* Signal frames. */
+struct target_signal_frame {
+ struct target_ucontext uc;
+ uint32_t extramask[TARGET_NSIG_WORDS - 1];
+ uint32_t tramp[2];
+};
+
+struct rt_signal_frame {
+ siginfo_t info;
+ ucontext_t uc;
+ uint32_t tramp[2];
+};
+
+static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
+{
+ __put_user(env->regs[0], &sc->regs.r0);
+ __put_user(env->regs[1], &sc->regs.r1);
+ __put_user(env->regs[2], &sc->regs.r2);
+ __put_user(env->regs[3], &sc->regs.r3);
+ __put_user(env->regs[4], &sc->regs.r4);
+ __put_user(env->regs[5], &sc->regs.r5);
+ __put_user(env->regs[6], &sc->regs.r6);
+ __put_user(env->regs[7], &sc->regs.r7);
+ __put_user(env->regs[8], &sc->regs.r8);
+ __put_user(env->regs[9], &sc->regs.r9);
+ __put_user(env->regs[10], &sc->regs.r10);
+ __put_user(env->regs[11], &sc->regs.r11);
+ __put_user(env->regs[12], &sc->regs.r12);
+ __put_user(env->regs[13], &sc->regs.r13);
+ __put_user(env->regs[14], &sc->regs.r14);
+ __put_user(env->regs[15], &sc->regs.r15);
+ __put_user(env->regs[16], &sc->regs.r16);
+ __put_user(env->regs[17], &sc->regs.r17);
+ __put_user(env->regs[18], &sc->regs.r18);
+ __put_user(env->regs[19], &sc->regs.r19);
+ __put_user(env->regs[20], &sc->regs.r20);
+ __put_user(env->regs[21], &sc->regs.r21);
+ __put_user(env->regs[22], &sc->regs.r22);
+ __put_user(env->regs[23], &sc->regs.r23);
+ __put_user(env->regs[24], &sc->regs.r24);
+ __put_user(env->regs[25], &sc->regs.r25);
+ __put_user(env->regs[26], &sc->regs.r26);
+ __put_user(env->regs[27], &sc->regs.r27);
+ __put_user(env->regs[28], &sc->regs.r28);
+ __put_user(env->regs[29], &sc->regs.r29);
+ __put_user(env->regs[30], &sc->regs.r30);
+ __put_user(env->regs[31], &sc->regs.r31);
+ __put_user(env->sregs[SR_PC], &sc->regs.pc);
+}
+
+static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
+{
+ __get_user(env->regs[0], &sc->regs.r0);
+ __get_user(env->regs[1], &sc->regs.r1);
+ __get_user(env->regs[2], &sc->regs.r2);
+ __get_user(env->regs[3], &sc->regs.r3);
+ __get_user(env->regs[4], &sc->regs.r4);
+ __get_user(env->regs[5], &sc->regs.r5);
+ __get_user(env->regs[6], &sc->regs.r6);
+ __get_user(env->regs[7], &sc->regs.r7);
+ __get_user(env->regs[8], &sc->regs.r8);
+ __get_user(env->regs[9], &sc->regs.r9);
+ __get_user(env->regs[10], &sc->regs.r10);
+ __get_user(env->regs[11], &sc->regs.r11);
+ __get_user(env->regs[12], &sc->regs.r12);
+ __get_user(env->regs[13], &sc->regs.r13);
+ __get_user(env->regs[14], &sc->regs.r14);
+ __get_user(env->regs[15], &sc->regs.r15);
+ __get_user(env->regs[16], &sc->regs.r16);
+ __get_user(env->regs[17], &sc->regs.r17);
+ __get_user(env->regs[18], &sc->regs.r18);
+ __get_user(env->regs[19], &sc->regs.r19);
+ __get_user(env->regs[20], &sc->regs.r20);
+ __get_user(env->regs[21], &sc->regs.r21);
+ __get_user(env->regs[22], &sc->regs.r22);
+ __get_user(env->regs[23], &sc->regs.r23);
+ __get_user(env->regs[24], &sc->regs.r24);
+ __get_user(env->regs[25], &sc->regs.r25);
+ __get_user(env->regs[26], &sc->regs.r26);
+ __get_user(env->regs[27], &sc->regs.r27);
+ __get_user(env->regs[28], &sc->regs.r28);
+ __get_user(env->regs[29], &sc->regs.r29);
+ __get_user(env->regs[30], &sc->regs.r30);
+ __get_user(env->regs[31], &sc->regs.r31);
+ __get_user(env->sregs[SR_PC], &sc->regs.pc);
+}
+
+static abi_ulong get_sigframe(struct target_sigaction *ka,
+ CPUMBState *env, int frame_size)
+{
+ abi_ulong sp = env->regs[1];
+
+ sp = target_sigsp(sp, ka);
+
+ return ((sp - frame_size) & -8UL);
+}
+
+void setup_frame(int sig, struct target_sigaction *ka,
+ target_sigset_t *set, CPUMBState *env)
+{
+ struct target_signal_frame *frame;
+ abi_ulong frame_addr;
+ int i;
+
+ frame_addr = get_sigframe(ka, env, sizeof *frame);
+ trace_user_setup_frame(env, frame_addr);
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+ goto badframe;
+
+ /* Save the mask. */
+ __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
+
+ for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+ __put_user(set->sig[i], &frame->extramask[i - 1]);
+ }
+
+ setup_sigcontext(&frame->uc.tuc_mcontext, env);
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ /* minus 8 is offset to cater for "rtsd r15,8" offset */
+ if (ka->sa_flags & TARGET_SA_RESTORER) {
+ env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
+ } else {
+ uint32_t t;
+ /* Note, these encodings are _big endian_! */
+ /* addi r12, r0, __NR_sigreturn */
+ t = 0x31800000UL | TARGET_NR_sigreturn;
+ __put_user(t, frame->tramp + 0);
+ /* brki r14, 0x8 */
+ t = 0xb9cc0008UL;
+ __put_user(t, frame->tramp + 1);
+
+ /* Return from sighandler will jump to the tramp.
+ Negative 8 offset because return is rtsd r15, 8 */
+ env->regs[15] = frame_addr + offsetof(struct target_signal_frame, tramp)
+ - 8;
+ }
+
+ /* Set up registers for signal handler */
+ env->regs[1] = frame_addr;
+ /* Signal handler args: */
+ env->regs[5] = sig; /* Arg 0: signum */
+ env->regs[6] = 0;
+ /* arg 1: sigcontext */
+ env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
+
+ /* Offset of 4 to handle microblaze rtid r14, 0 */
+ env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
+
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+badframe:
+ force_sigsegv(sig);
+}
+
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPUMBState *env)
+{
+ fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n");
+}
+
+long do_sigreturn(CPUMBState *env)
+{
+ struct target_signal_frame *frame;
+ abi_ulong frame_addr;
+ target_sigset_t target_set;
+ sigset_t set;
+ int i;
+
+ frame_addr = env->regs[R_SP];
+ trace_user_do_sigreturn(env, frame_addr);
+ /* Make sure the guest isn't playing games. */
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
+ goto badframe;
+
+ /* Restore blocked signals */
+ __get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask);
+ for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+ __get_user(target_set.sig[i], &frame->extramask[i - 1]);
+ }
+ target_to_host_sigset_internal(&set, &target_set);
+ set_sigmask(&set);
+
+ restore_sigcontext(&frame->uc.tuc_mcontext, env);
+ /* We got here through a sigreturn syscall, our path back is via an
+ rtb insn so setup r14 for that. */
+ env->regs[14] = env->sregs[SR_PC];
+
+ unlock_user_struct(frame, frame_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+badframe:
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
+
+long do_rt_sigreturn(CPUMBState *env)
+{
+ trace_user_do_rt_sigreturn(env, 0);
+ fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n");
+ return -TARGET_ENOSYS;
+}
diff --git a/linux-user/microblaze/target_signal.h b/linux-user/microblaze/target_signal.h
index 642865f12e..9fe4048292 100644
--- a/linux-user/microblaze/target_signal.h
+++ b/linux-user/microblaze/target_signal.h
@@ -26,5 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUMBState *state)
return state->regs[1];
}
-
+#define TARGET_ARCH_HAS_SETUP_FRAME
#endif /* MICROBLAZE_TARGET_SIGNAL_H */
diff --git a/linux-user/mips/cpu_loop.c b/linux-user/mips/cpu_loop.c
new file mode 100644
index 0000000000..084ad6a041
--- /dev/null
+++ b/linux-user/mips/cpu_loop.c
@@ -0,0 +1,749 @@
+/*
+ * qemu user cpu loop
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "cpu_loop-common.h"
+#include "elf.h"
+
+# ifdef TARGET_ABI_MIPSO32
+# define MIPS_SYS(name, args) args,
+static const uint8_t mips_syscall_args[] = {
+ MIPS_SYS(sys_syscall , 8) /* 4000 */
+ MIPS_SYS(sys_exit , 1)
+ MIPS_SYS(sys_fork , 0)
+ MIPS_SYS(sys_read , 3)
+ MIPS_SYS(sys_write , 3)
+ MIPS_SYS(sys_open , 3) /* 4005 */
+ MIPS_SYS(sys_close , 1)
+ MIPS_SYS(sys_waitpid , 3)
+ MIPS_SYS(sys_creat , 2)
+ MIPS_SYS(sys_link , 2)
+ MIPS_SYS(sys_unlink , 1) /* 4010 */
+ MIPS_SYS(sys_execve , 0)
+ MIPS_SYS(sys_chdir , 1)
+ MIPS_SYS(sys_time , 1)
+ MIPS_SYS(sys_mknod , 3)
+ MIPS_SYS(sys_chmod , 2) /* 4015 */
+ MIPS_SYS(sys_lchown , 3)
+ MIPS_SYS(sys_ni_syscall , 0)
+ MIPS_SYS(sys_ni_syscall , 0) /* was sys_stat */
+ MIPS_SYS(sys_lseek , 3)
+ MIPS_SYS(sys_getpid , 0) /* 4020 */
+ MIPS_SYS(sys_mount , 5)
+ MIPS_SYS(sys_umount , 1)
+ MIPS_SYS(sys_setuid , 1)
+ MIPS_SYS(sys_getuid , 0)
+ MIPS_SYS(sys_stime , 1) /* 4025 */
+ MIPS_SYS(sys_ptrace , 4)
+ MIPS_SYS(sys_alarm , 1)
+ MIPS_SYS(sys_ni_syscall , 0) /* was sys_fstat */
+ MIPS_SYS(sys_pause , 0)
+ MIPS_SYS(sys_utime , 2) /* 4030 */
+ MIPS_SYS(sys_ni_syscall , 0)
+ MIPS_SYS(sys_ni_syscall , 0)
+ MIPS_SYS(sys_access , 2)
+ MIPS_SYS(sys_nice , 1)
+ MIPS_SYS(sys_ni_syscall , 0) /* 4035 */
+ MIPS_SYS(sys_sync , 0)
+ MIPS_SYS(sys_kill , 2)
+ MIPS_SYS(sys_rename , 2)
+ MIPS_SYS(sys_mkdir , 2)
+ MIPS_SYS(sys_rmdir , 1) /* 4040 */
+ MIPS_SYS(sys_dup , 1)
+ MIPS_SYS(sys_pipe , 0)
+ MIPS_SYS(sys_times , 1)
+ MIPS_SYS(sys_ni_syscall , 0)
+ MIPS_SYS(sys_brk , 1) /* 4045 */
+ MIPS_SYS(sys_setgid , 1)
+ MIPS_SYS(sys_getgid , 0)
+ MIPS_SYS(sys_ni_syscall , 0) /* was signal(2) */
+ MIPS_SYS(sys_geteuid , 0)
+ MIPS_SYS(sys_getegid , 0) /* 4050 */
+ MIPS_SYS(sys_acct , 0)
+ MIPS_SYS(sys_umount2 , 2)
+ MIPS_SYS(sys_ni_syscall , 0)
+ MIPS_SYS(sys_ioctl , 3)
+ MIPS_SYS(sys_fcntl , 3) /* 4055 */
+ MIPS_SYS(sys_ni_syscall , 2)
+ MIPS_SYS(sys_setpgid , 2)
+ MIPS_SYS(sys_ni_syscall , 0)
+ MIPS_SYS(sys_olduname , 1)
+ MIPS_SYS(sys_umask , 1) /* 4060 */
+ MIPS_SYS(sys_chroot , 1)
+ MIPS_SYS(sys_ustat , 2)
+ MIPS_SYS(sys_dup2 , 2)
+ MIPS_SYS(sys_getppid , 0)
+ MIPS_SYS(sys_getpgrp , 0) /* 4065 */
+ MIPS_SYS(sys_setsid , 0)
+ MIPS_SYS(sys_sigaction , 3)
+ MIPS_SYS(sys_sgetmask , 0)
+ MIPS_SYS(sys_ssetmask , 1)
+ MIPS_SYS(sys_setreuid , 2) /* 4070 */
+ MIPS_SYS(sys_setregid , 2)
+ MIPS_SYS(sys_sigsuspend , 0)
+ MIPS_SYS(sys_sigpending , 1)
+ MIPS_SYS(sys_sethostname , 2)
+ MIPS_SYS(sys_setrlimit , 2) /* 4075 */
+ MIPS_SYS(sys_getrlimit , 2)
+ MIPS_SYS(sys_getrusage , 2)
+ MIPS_SYS(sys_gettimeofday, 2)
+ MIPS_SYS(sys_settimeofday, 2)
+ MIPS_SYS(sys_getgroups , 2) /* 4080 */
+ MIPS_SYS(sys_setgroups , 2)
+ MIPS_SYS(sys_ni_syscall , 0) /* old_select */
+ MIPS_SYS(sys_symlink , 2)
+ MIPS_SYS(sys_ni_syscall , 0) /* was sys_lstat */
+ MIPS_SYS(sys_readlink , 3) /* 4085 */
+ MIPS_SYS(sys_uselib , 1)
+ MIPS_SYS(sys_swapon , 2)
+ MIPS_SYS(sys_reboot , 3)
+ MIPS_SYS(old_readdir , 3)
+ MIPS_SYS(old_mmap , 6) /* 4090 */
+ MIPS_SYS(sys_munmap , 2)
+ MIPS_SYS(sys_truncate , 2)
+ MIPS_SYS(sys_ftruncate , 2)
+ MIPS_SYS(sys_fchmod , 2)
+ MIPS_SYS(sys_fchown , 3) /* 4095 */
+ MIPS_SYS(sys_getpriority , 2)
+ MIPS_SYS(sys_setpriority , 3)
+ MIPS_SYS(sys_ni_syscall , 0)
+ MIPS_SYS(sys_statfs , 2)
+ MIPS_SYS(sys_fstatfs , 2) /* 4100 */
+ MIPS_SYS(sys_ni_syscall , 0) /* was ioperm(2) */
+ MIPS_SYS(sys_socketcall , 2)
+ MIPS_SYS(sys_syslog , 3)
+ MIPS_SYS(sys_setitimer , 3)
+ MIPS_SYS(sys_getitimer , 2) /* 4105 */
+ MIPS_SYS(sys_newstat , 2)
+ MIPS_SYS(sys_newlstat , 2)
+ MIPS_SYS(sys_newfstat , 2)
+ MIPS_SYS(sys_uname , 1)
+ MIPS_SYS(sys_ni_syscall , 0) /* 4110 was iopl(2) */
+ MIPS_SYS(sys_vhangup , 0)
+ MIPS_SYS(sys_ni_syscall , 0) /* was sys_idle() */
+ MIPS_SYS(sys_ni_syscall , 0) /* was sys_vm86 */
+ MIPS_SYS(sys_wait4 , 4)
+ MIPS_SYS(sys_swapoff , 1) /* 4115 */
+ MIPS_SYS(sys_sysinfo , 1)
+ MIPS_SYS(sys_ipc , 6)
+ MIPS_SYS(sys_fsync , 1)
+ MIPS_SYS(sys_sigreturn , 0)
+ MIPS_SYS(sys_clone , 6) /* 4120 */
+ MIPS_SYS(sys_setdomainname, 2)
+ MIPS_SYS(sys_newuname , 1)
+ MIPS_SYS(sys_ni_syscall , 0) /* sys_modify_ldt */
+ MIPS_SYS(sys_adjtimex , 1)
+ MIPS_SYS(sys_mprotect , 3) /* 4125 */
+ MIPS_SYS(sys_sigprocmask , 3)
+ MIPS_SYS(sys_ni_syscall , 0) /* was create_module */
+ MIPS_SYS(sys_init_module , 5)
+ MIPS_SYS(sys_delete_module, 1)
+ MIPS_SYS(sys_ni_syscall , 0) /* 4130 was get_kernel_syms */
+ MIPS_SYS(sys_quotactl , 0)
+ MIPS_SYS(sys_getpgid , 1)
+ MIPS_SYS(sys_fchdir , 1)
+ MIPS_SYS(sys_bdflush , 2)
+ MIPS_SYS(sys_sysfs , 3) /* 4135 */
+ MIPS_SYS(sys_personality , 1)
+ MIPS_SYS(sys_ni_syscall , 0) /* for afs_syscall */
+ MIPS_SYS(sys_setfsuid , 1)
+ MIPS_SYS(sys_setfsgid , 1)
+ MIPS_SYS(sys_llseek , 5) /* 4140 */
+ MIPS_SYS(sys_getdents , 3)
+ MIPS_SYS(sys_select , 5)
+ MIPS_SYS(sys_flock , 2)
+ MIPS_SYS(sys_msync , 3)
+ MIPS_SYS(sys_readv , 3) /* 4145 */
+ MIPS_SYS(sys_writev , 3)
+ MIPS_SYS(sys_cacheflush , 3)
+ MIPS_SYS(sys_cachectl , 3)
+ MIPS_SYS(sys_sysmips , 4)
+ MIPS_SYS(sys_ni_syscall , 0) /* 4150 */
+ MIPS_SYS(sys_getsid , 1)
+ MIPS_SYS(sys_fdatasync , 0)
+ MIPS_SYS(sys_sysctl , 1)
+ MIPS_SYS(sys_mlock , 2)
+ MIPS_SYS(sys_munlock , 2) /* 4155 */
+ MIPS_SYS(sys_mlockall , 1)
+ MIPS_SYS(sys_munlockall , 0)
+ MIPS_SYS(sys_sched_setparam, 2)
+ MIPS_SYS(sys_sched_getparam, 2)
+ MIPS_SYS(sys_sched_setscheduler, 3) /* 4160 */
+ MIPS_SYS(sys_sched_getscheduler, 1)
+ MIPS_SYS(sys_sched_yield , 0)
+ MIPS_SYS(sys_sched_get_priority_max, 1)
+ MIPS_SYS(sys_sched_get_priority_min, 1)
+ MIPS_SYS(sys_sched_rr_get_interval, 2) /* 4165 */
+ MIPS_SYS(sys_nanosleep, 2)
+ MIPS_SYS(sys_mremap , 5)
+ MIPS_SYS(sys_accept , 3)
+ MIPS_SYS(sys_bind , 3)
+ MIPS_SYS(sys_connect , 3) /* 4170 */
+ MIPS_SYS(sys_getpeername , 3)
+ MIPS_SYS(sys_getsockname , 3)
+ MIPS_SYS(sys_getsockopt , 5)
+ MIPS_SYS(sys_listen , 2)
+ MIPS_SYS(sys_recv , 4) /* 4175 */
+ MIPS_SYS(sys_recvfrom , 6)
+ MIPS_SYS(sys_recvmsg , 3)
+ MIPS_SYS(sys_send , 4)
+ MIPS_SYS(sys_sendmsg , 3)
+ MIPS_SYS(sys_sendto , 6) /* 4180 */
+ MIPS_SYS(sys_setsockopt , 5)
+ MIPS_SYS(sys_shutdown , 2)
+ MIPS_SYS(sys_socket , 3)
+ MIPS_SYS(sys_socketpair , 4)
+ MIPS_SYS(sys_setresuid , 3) /* 4185 */
+ MIPS_SYS(sys_getresuid , 3)
+ MIPS_SYS(sys_ni_syscall , 0) /* was sys_query_module */
+ MIPS_SYS(sys_poll , 3)
+ MIPS_SYS(sys_nfsservctl , 3)
+ MIPS_SYS(sys_setresgid , 3) /* 4190 */
+ MIPS_SYS(sys_getresgid , 3)
+ MIPS_SYS(sys_prctl , 5)
+ MIPS_SYS(sys_rt_sigreturn, 0)
+ MIPS_SYS(sys_rt_sigaction, 4)
+ MIPS_SYS(sys_rt_sigprocmask, 4) /* 4195 */
+ MIPS_SYS(sys_rt_sigpending, 2)
+ MIPS_SYS(sys_rt_sigtimedwait, 4)
+ MIPS_SYS(sys_rt_sigqueueinfo, 3)
+ MIPS_SYS(sys_rt_sigsuspend, 0)
+ MIPS_SYS(sys_pread64 , 6) /* 4200 */
+ MIPS_SYS(sys_pwrite64 , 6)
+ MIPS_SYS(sys_chown , 3)
+ MIPS_SYS(sys_getcwd , 2)
+ MIPS_SYS(sys_capget , 2)
+ MIPS_SYS(sys_capset , 2) /* 4205 */
+ MIPS_SYS(sys_sigaltstack , 2)
+ MIPS_SYS(sys_sendfile , 4)
+ MIPS_SYS(sys_ni_syscall , 0)
+ MIPS_SYS(sys_ni_syscall , 0)
+ MIPS_SYS(sys_mmap2 , 6) /* 4210 */
+ MIPS_SYS(sys_truncate64 , 4)
+ MIPS_SYS(sys_ftruncate64 , 4)
+ MIPS_SYS(sys_stat64 , 2)
+ MIPS_SYS(sys_lstat64 , 2)
+ MIPS_SYS(sys_fstat64 , 2) /* 4215 */
+ MIPS_SYS(sys_pivot_root , 2)
+ MIPS_SYS(sys_mincore , 3)
+ MIPS_SYS(sys_madvise , 3)
+ MIPS_SYS(sys_getdents64 , 3)
+ MIPS_SYS(sys_fcntl64 , 3) /* 4220 */
+ MIPS_SYS(sys_ni_syscall , 0)
+ MIPS_SYS(sys_gettid , 0)
+ MIPS_SYS(sys_readahead , 5)
+ MIPS_SYS(sys_setxattr , 5)
+ MIPS_SYS(sys_lsetxattr , 5) /* 4225 */
+ MIPS_SYS(sys_fsetxattr , 5)
+ MIPS_SYS(sys_getxattr , 4)
+ MIPS_SYS(sys_lgetxattr , 4)
+ MIPS_SYS(sys_fgetxattr , 4)
+ MIPS_SYS(sys_listxattr , 3) /* 4230 */
+ MIPS_SYS(sys_llistxattr , 3)
+ MIPS_SYS(sys_flistxattr , 3)
+ MIPS_SYS(sys_removexattr , 2)
+ MIPS_SYS(sys_lremovexattr, 2)
+ MIPS_SYS(sys_fremovexattr, 2) /* 4235 */
+ MIPS_SYS(sys_tkill , 2)
+ MIPS_SYS(sys_sendfile64 , 5)
+ MIPS_SYS(sys_futex , 6)
+ MIPS_SYS(sys_sched_setaffinity, 3)
+ MIPS_SYS(sys_sched_getaffinity, 3) /* 4240 */
+ MIPS_SYS(sys_io_setup , 2)
+ MIPS_SYS(sys_io_destroy , 1)
+ MIPS_SYS(sys_io_getevents, 5)
+ MIPS_SYS(sys_io_submit , 3)
+ MIPS_SYS(sys_io_cancel , 3) /* 4245 */
+ MIPS_SYS(sys_exit_group , 1)
+ MIPS_SYS(sys_lookup_dcookie, 3)
+ MIPS_SYS(sys_epoll_create, 1)
+ MIPS_SYS(sys_epoll_ctl , 4)
+ MIPS_SYS(sys_epoll_wait , 3) /* 4250 */
+ MIPS_SYS(sys_remap_file_pages, 5)
+ MIPS_SYS(sys_set_tid_address, 1)
+ MIPS_SYS(sys_restart_syscall, 0)
+ MIPS_SYS(sys_fadvise64_64, 7)
+ MIPS_SYS(sys_statfs64 , 3) /* 4255 */
+ MIPS_SYS(sys_fstatfs64 , 2)
+ MIPS_SYS(sys_timer_create, 3)
+ MIPS_SYS(sys_timer_settime, 4)
+ MIPS_SYS(sys_timer_gettime, 2)
+ MIPS_SYS(sys_timer_getoverrun, 1) /* 4260 */
+ MIPS_SYS(sys_timer_delete, 1)
+ MIPS_SYS(sys_clock_settime, 2)
+ MIPS_SYS(sys_clock_gettime, 2)
+ MIPS_SYS(sys_clock_getres, 2)
+ MIPS_SYS(sys_clock_nanosleep, 4) /* 4265 */
+ MIPS_SYS(sys_tgkill , 3)
+ MIPS_SYS(sys_utimes , 2)
+ MIPS_SYS(sys_mbind , 4)
+ MIPS_SYS(sys_ni_syscall , 0) /* sys_get_mempolicy */
+ MIPS_SYS(sys_ni_syscall , 0) /* 4270 sys_set_mempolicy */
+ MIPS_SYS(sys_mq_open , 4)
+ MIPS_SYS(sys_mq_unlink , 1)
+ MIPS_SYS(sys_mq_timedsend, 5)
+ MIPS_SYS(sys_mq_timedreceive, 5)
+ MIPS_SYS(sys_mq_notify , 2) /* 4275 */
+ MIPS_SYS(sys_mq_getsetattr, 3)
+ MIPS_SYS(sys_ni_syscall , 0) /* sys_vserver */
+ MIPS_SYS(sys_waitid , 4)
+ MIPS_SYS(sys_ni_syscall , 0) /* available, was setaltroot */
+ MIPS_SYS(sys_add_key , 5)
+ MIPS_SYS(sys_request_key, 4)
+ MIPS_SYS(sys_keyctl , 5)
+ MIPS_SYS(sys_set_thread_area, 1)
+ MIPS_SYS(sys_inotify_init, 0)
+ MIPS_SYS(sys_inotify_add_watch, 3) /* 4285 */
+ MIPS_SYS(sys_inotify_rm_watch, 2)
+ MIPS_SYS(sys_migrate_pages, 4)
+ MIPS_SYS(sys_openat, 4)
+ MIPS_SYS(sys_mkdirat, 3)
+ MIPS_SYS(sys_mknodat, 4) /* 4290 */
+ MIPS_SYS(sys_fchownat, 5)
+ MIPS_SYS(sys_futimesat, 3)
+ MIPS_SYS(sys_fstatat64, 4)
+ MIPS_SYS(sys_unlinkat, 3)
+ MIPS_SYS(sys_renameat, 4) /* 4295 */
+ MIPS_SYS(sys_linkat, 5)
+ MIPS_SYS(sys_symlinkat, 3)
+ MIPS_SYS(sys_readlinkat, 4)
+ MIPS_SYS(sys_fchmodat, 3)
+ MIPS_SYS(sys_faccessat, 3) /* 4300 */
+ MIPS_SYS(sys_pselect6, 6)
+ MIPS_SYS(sys_ppoll, 5)
+ MIPS_SYS(sys_unshare, 1)
+ MIPS_SYS(sys_splice, 6)
+ MIPS_SYS(sys_sync_file_range, 7) /* 4305 */
+ MIPS_SYS(sys_tee, 4)
+ MIPS_SYS(sys_vmsplice, 4)
+ MIPS_SYS(sys_move_pages, 6)
+ MIPS_SYS(sys_set_robust_list, 2)
+ MIPS_SYS(sys_get_robust_list, 3) /* 4310 */
+ MIPS_SYS(sys_kexec_load, 4)
+ MIPS_SYS(sys_getcpu, 3)
+ MIPS_SYS(sys_epoll_pwait, 6)
+ MIPS_SYS(sys_ioprio_set, 3)
+ MIPS_SYS(sys_ioprio_get, 2)
+ MIPS_SYS(sys_utimensat, 4)
+ MIPS_SYS(sys_signalfd, 3)
+ MIPS_SYS(sys_ni_syscall, 0) /* was timerfd */
+ MIPS_SYS(sys_eventfd, 1)
+ MIPS_SYS(sys_fallocate, 6) /* 4320 */
+ MIPS_SYS(sys_timerfd_create, 2)
+ MIPS_SYS(sys_timerfd_gettime, 2)
+ MIPS_SYS(sys_timerfd_settime, 4)
+ MIPS_SYS(sys_signalfd4, 4)
+ MIPS_SYS(sys_eventfd2, 2) /* 4325 */
+ MIPS_SYS(sys_epoll_create1, 1)
+ MIPS_SYS(sys_dup3, 3)
+ MIPS_SYS(sys_pipe2, 2)
+ MIPS_SYS(sys_inotify_init1, 1)
+ MIPS_SYS(sys_preadv, 5) /* 4330 */
+ MIPS_SYS(sys_pwritev, 5)
+ MIPS_SYS(sys_rt_tgsigqueueinfo, 4)
+ MIPS_SYS(sys_perf_event_open, 5)
+ MIPS_SYS(sys_accept4, 4)
+ MIPS_SYS(sys_recvmmsg, 5) /* 4335 */
+ MIPS_SYS(sys_fanotify_init, 2)
+ MIPS_SYS(sys_fanotify_mark, 6)
+ MIPS_SYS(sys_prlimit64, 4)
+ MIPS_SYS(sys_name_to_handle_at, 5)
+ MIPS_SYS(sys_open_by_handle_at, 3) /* 4340 */
+ MIPS_SYS(sys_clock_adjtime, 2)
+ MIPS_SYS(sys_syncfs, 1)
+ MIPS_SYS(sys_sendmmsg, 4)
+ MIPS_SYS(sys_setns, 2)
+ MIPS_SYS(sys_process_vm_readv, 6) /* 345 */
+ MIPS_SYS(sys_process_vm_writev, 6)
+ MIPS_SYS(sys_kcmp, 5)
+ MIPS_SYS(sys_finit_module, 3)
+ MIPS_SYS(sys_sched_setattr, 2)
+ MIPS_SYS(sys_sched_getattr, 3) /* 350 */
+ MIPS_SYS(sys_renameat2, 5)
+ MIPS_SYS(sys_seccomp, 3)
+ MIPS_SYS(sys_getrandom, 3)
+ MIPS_SYS(sys_memfd_create, 2)
+ MIPS_SYS(sys_bpf, 3) /* 355 */
+ MIPS_SYS(sys_execveat, 5)
+ MIPS_SYS(sys_userfaultfd, 1)
+ MIPS_SYS(sys_membarrier, 2)
+ MIPS_SYS(sys_mlock2, 3)
+ MIPS_SYS(sys_copy_file_range, 6) /* 360 */
+ MIPS_SYS(sys_preadv2, 6)
+ MIPS_SYS(sys_pwritev2, 6)
+};
+# undef MIPS_SYS
+# endif /* O32 */
+
+static int do_store_exclusive(CPUMIPSState *env)
+{
+ target_ulong addr;
+ target_ulong page_addr;
+ target_ulong val;
+ int flags;
+ int segv = 0;
+ int reg;
+ int d;
+
+ addr = env->lladdr;
+ page_addr = addr & TARGET_PAGE_MASK;
+ start_exclusive();
+ mmap_lock();
+ flags = page_get_flags(page_addr);
+ if ((flags & PAGE_READ) == 0) {
+ segv = 1;
+ } else {
+ reg = env->llreg & 0x1f;
+ d = (env->llreg & 0x20) != 0;
+ if (d) {
+ segv = get_user_s64(val, addr);
+ } else {
+ segv = get_user_s32(val, addr);
+ }
+ if (!segv) {
+ if (val != env->llval) {
+ env->active_tc.gpr[reg] = 0;
+ } else {
+ if (d) {
+ segv = put_user_u64(env->llnewval, addr);
+ } else {
+ segv = put_user_u32(env->llnewval, addr);
+ }
+ if (!segv) {
+ env->active_tc.gpr[reg] = 1;
+ }
+ }
+ }
+ }
+ env->lladdr = -1;
+ if (!segv) {
+ env->active_tc.PC += 4;
+ }
+ mmap_unlock();
+ end_exclusive();
+ return segv;
+}
+
+/* Break codes */
+enum {
+ BRK_OVERFLOW = 6,
+ BRK_DIVZERO = 7
+};
+
+static int do_break(CPUMIPSState *env, target_siginfo_t *info,
+ unsigned int code)
+{
+ int ret = -1;
+
+ switch (code) {
+ case BRK_OVERFLOW:
+ case BRK_DIVZERO:
+ info->si_signo = TARGET_SIGFPE;
+ info->si_errno = 0;
+ info->si_code = (code == BRK_OVERFLOW) ? FPE_INTOVF : FPE_INTDIV;
+ queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info);
+ ret = 0;
+ break;
+ default:
+ info->si_signo = TARGET_SIGTRAP;
+ info->si_errno = 0;
+ queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info);
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+void cpu_loop(CPUMIPSState *env)
+{
+ CPUState *cs = CPU(mips_env_get_cpu(env));
+ target_siginfo_t info;
+ int trapnr;
+ abi_long ret;
+# ifdef TARGET_ABI_MIPSO32
+ unsigned int syscall_num;
+# endif
+
+ for(;;) {
+ cpu_exec_start(cs);
+ trapnr = cpu_exec(cs);
+ cpu_exec_end(cs);
+ process_queued_cpu_work(cs);
+
+ switch(trapnr) {
+ case EXCP_SYSCALL:
+ env->active_tc.PC += 4;
+# ifdef TARGET_ABI_MIPSO32
+ syscall_num = env->active_tc.gpr[2] - 4000;
+ if (syscall_num >= sizeof(mips_syscall_args)) {
+ ret = -TARGET_ENOSYS;
+ } else {
+ int nb_args;
+ abi_ulong sp_reg;
+ abi_ulong arg5 = 0, arg6 = 0, arg7 = 0, arg8 = 0;
+
+ nb_args = mips_syscall_args[syscall_num];
+ sp_reg = env->active_tc.gpr[29];
+ switch (nb_args) {
+ /* these arguments are taken from the stack */
+ case 8:
+ if ((ret = get_user_ual(arg8, sp_reg + 28)) != 0) {
+ goto done_syscall;
+ }
+ case 7:
+ if ((ret = get_user_ual(arg7, sp_reg + 24)) != 0) {
+ goto done_syscall;
+ }
+ case 6:
+ if ((ret = get_user_ual(arg6, sp_reg + 20)) != 0) {
+ goto done_syscall;
+ }
+ case 5:
+ if ((ret = get_user_ual(arg5, sp_reg + 16)) != 0) {
+ goto done_syscall;
+ }
+ default:
+ break;
+ }
+ ret = do_syscall(env, env->active_tc.gpr[2],
+ env->active_tc.gpr[4],
+ env->active_tc.gpr[5],
+ env->active_tc.gpr[6],
+ env->active_tc.gpr[7],
+ arg5, arg6, arg7, arg8);
+ }
+done_syscall:
+# else
+ ret = do_syscall(env, env->active_tc.gpr[2],
+ env->active_tc.gpr[4], env->active_tc.gpr[5],
+ env->active_tc.gpr[6], env->active_tc.gpr[7],
+ env->active_tc.gpr[8], env->active_tc.gpr[9],
+ env->active_tc.gpr[10], env->active_tc.gpr[11]);
+# endif /* O32 */
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->active_tc.PC -= 4;
+ break;
+ }
+ if (ret == -TARGET_QEMU_ESIGRETURN) {
+ /* Returning from a successful sigreturn syscall.
+ Avoid clobbering register state. */
+ break;
+ }
+ if ((abi_ulong)ret >= (abi_ulong)-1133) {
+ env->active_tc.gpr[7] = 1; /* error flag */
+ ret = -ret;
+ } else {
+ env->active_tc.gpr[7] = 0; /* error flag */
+ }
+ env->active_tc.gpr[2] = ret;
+ break;
+ case EXCP_TLBL:
+ case EXCP_TLBS:
+ case EXCP_AdEL:
+ case EXCP_AdES:
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ /* XXX: check env->error_code */
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = env->CP0_BadVAddr;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_CpU:
+ case EXCP_RI:
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = 0;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+ case EXCP_DEBUG:
+ {
+ int sig;
+
+ sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+ if (sig)
+ {
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+ }
+ break;
+ case EXCP_SC:
+ if (do_store_exclusive(env)) {
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = env->active_tc.PC;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+ break;
+ case EXCP_DSPDIS:
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_ILLOPC;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ /* The code below was inspired by the MIPS Linux kernel trap
+ * handling code in arch/mips/kernel/traps.c.
+ */
+ case EXCP_BREAK:
+ {
+ abi_ulong trap_instr;
+ unsigned int code;
+
+ if (env->hflags & MIPS_HFLAG_M16) {
+ if (env->insn_flags & ASE_MICROMIPS) {
+ /* microMIPS mode */
+ ret = get_user_u16(trap_instr, env->active_tc.PC);
+ if (ret != 0) {
+ goto error;
+ }
+
+ if ((trap_instr >> 10) == 0x11) {
+ /* 16-bit instruction */
+ code = trap_instr & 0xf;
+ } else {
+ /* 32-bit instruction */
+ abi_ulong instr_lo;
+
+ ret = get_user_u16(instr_lo,
+ env->active_tc.PC + 2);
+ if (ret != 0) {
+ goto error;
+ }
+ trap_instr = (trap_instr << 16) | instr_lo;
+ code = ((trap_instr >> 6) & ((1 << 20) - 1));
+ /* Unfortunately, microMIPS also suffers from
+ the old assembler bug... */
+ if (code >= (1 << 10)) {
+ code >>= 10;
+ }
+ }
+ } else {
+ /* MIPS16e mode */
+ ret = get_user_u16(trap_instr, env->active_tc.PC);
+ if (ret != 0) {
+ goto error;
+ }
+ code = (trap_instr >> 6) & 0x3f;
+ }
+ } else {
+ ret = get_user_u32(trap_instr, env->active_tc.PC);
+ if (ret != 0) {
+ goto error;
+ }
+
+ /* As described in the original Linux kernel code, the
+ * below checks on 'code' are to work around an old
+ * assembly bug.
+ */
+ code = ((trap_instr >> 6) & ((1 << 20) - 1));
+ if (code >= (1 << 10)) {
+ code >>= 10;
+ }
+ }
+
+ if (do_break(env, &info, code) != 0) {
+ goto error;
+ }
+ }
+ break;
+ case EXCP_TRAP:
+ {
+ abi_ulong trap_instr;
+ unsigned int code = 0;
+
+ if (env->hflags & MIPS_HFLAG_M16) {
+ /* microMIPS mode */
+ abi_ulong instr[2];
+
+ ret = get_user_u16(instr[0], env->active_tc.PC) ||
+ get_user_u16(instr[1], env->active_tc.PC + 2);
+
+ trap_instr = (instr[0] << 16) | instr[1];
+ } else {
+ ret = get_user_u32(trap_instr, env->active_tc.PC);
+ }
+
+ if (ret != 0) {
+ goto error;
+ }
+
+ /* The immediate versions don't provide a code. */
+ if (!(trap_instr & 0xFC000000)) {
+ if (env->hflags & MIPS_HFLAG_M16) {
+ /* microMIPS mode */
+ code = ((trap_instr >> 12) & ((1 << 4) - 1));
+ } else {
+ code = ((trap_instr >> 6) & ((1 << 10) - 1));
+ }
+ }
+
+ if (do_break(env, &info, code) != 0) {
+ goto error;
+ }
+ }
+ break;
+ case EXCP_ATOMIC:
+ cpu_exec_step_atomic(cs);
+ break;
+ default:
+error:
+ EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
+ abort();
+ }
+ process_pending_signals(env);
+ }
+}
+
+void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
+{
+ CPUState *cpu = ENV_GET_CPU(env);
+ TaskState *ts = cpu->opaque;
+ struct image_info *info = ts->info;
+ int i;
+
+ for(i = 0; i < 32; i++) {
+ env->active_tc.gpr[i] = regs->regs[i];
+ }
+ env->active_tc.PC = regs->cp0_epc & ~(target_ulong)1;
+ if (regs->cp0_epc & 1) {
+ env->hflags |= MIPS_HFLAG_M16;
+ }
+ if (((info->elf_flags & EF_MIPS_NAN2008) != 0) !=
+ ((env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) != 0)) {
+ if ((env->active_fpu.fcr31_rw_bitmask &
+ (1 << FCR31_NAN2008)) == 0) {
+ fprintf(stderr, "ELF binary's NaN mode not supported by CPU\n");
+ exit(1);
+ }
+ if ((info->elf_flags & EF_MIPS_NAN2008) != 0) {
+ env->active_fpu.fcr31 |= (1 << FCR31_NAN2008);
+ } else {
+ env->active_fpu.fcr31 &= ~(1 << FCR31_NAN2008);
+ }
+ restore_snan_bit_mode(env);
+ }
+}
diff --git a/linux-user/mips/signal.c b/linux-user/mips/signal.c
new file mode 100644
index 0000000000..ed9849c7f6
--- /dev/null
+++ b/linux-user/mips/signal.c
@@ -0,0 +1,389 @@
+/*
+ * Emulation of Linux signals
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "target_signal.h"
+#include "signal-common.h"
+#include "linux-user/trace.h"
+
+# if defined(TARGET_ABI_MIPSO32)
+struct target_sigcontext {
+ uint32_t sc_regmask; /* Unused */
+ uint32_t sc_status;
+ uint64_t sc_pc;
+ uint64_t sc_regs[32];
+ uint64_t sc_fpregs[32];
+ uint32_t sc_ownedfp; /* Unused */
+ uint32_t sc_fpc_csr;
+ uint32_t sc_fpc_eir; /* Unused */
+ uint32_t sc_used_math;
+ uint32_t sc_dsp; /* dsp status, was sc_ssflags */
+ uint32_t pad0;
+ uint64_t sc_mdhi;
+ uint64_t sc_mdlo;
+ target_ulong sc_hi1; /* Was sc_cause */
+ target_ulong sc_lo1; /* Was sc_badvaddr */
+ target_ulong sc_hi2; /* Was sc_sigset[4] */
+ target_ulong sc_lo2;
+ target_ulong sc_hi3;
+ target_ulong sc_lo3;
+};
+# else /* N32 || N64 */
+struct target_sigcontext {
+ uint64_t sc_regs[32];
+ uint64_t sc_fpregs[32];
+ uint64_t sc_mdhi;
+ uint64_t sc_hi1;
+ uint64_t sc_hi2;
+ uint64_t sc_hi3;
+ uint64_t sc_mdlo;
+ uint64_t sc_lo1;
+ uint64_t sc_lo2;
+ uint64_t sc_lo3;
+ uint64_t sc_pc;
+ uint32_t sc_fpc_csr;
+ uint32_t sc_used_math;
+ uint32_t sc_dsp;
+ uint32_t sc_reserved;
+};
+# endif /* O32 */
+
+struct sigframe {
+ uint32_t sf_ass[4]; /* argument save space for o32 */
+ uint32_t sf_code[2]; /* signal trampoline */
+ struct target_sigcontext sf_sc;
+ target_sigset_t sf_mask;
+};
+
+struct target_ucontext {
+ target_ulong tuc_flags;
+ target_ulong tuc_link;
+ target_stack_t tuc_stack;
+ target_ulong pad0;
+ struct target_sigcontext tuc_mcontext;
+ target_sigset_t tuc_sigmask;
+};
+
+struct target_rt_sigframe {
+ uint32_t rs_ass[4]; /* argument save space for o32 */
+ uint32_t rs_code[2]; /* signal trampoline */
+ struct target_siginfo rs_info;
+ struct target_ucontext rs_uc;
+};
+
+/* Install trampoline to jump back from signal handler */
+static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
+{
+ int err = 0;
+
+ /*
+ * Set up the return code ...
+ *
+ * li v0, __NR__foo_sigreturn
+ * syscall
+ */
+
+ __put_user(0x24020000 + syscall, tramp + 0);
+ __put_user(0x0000000c , tramp + 1);
+ return err;
+}
+
+static inline void setup_sigcontext(CPUMIPSState *regs,
+ struct target_sigcontext *sc)
+{
+ int i;
+
+ __put_user(exception_resume_pc(regs), &sc->sc_pc);
+ regs->hflags &= ~MIPS_HFLAG_BMASK;
+
+ __put_user(0, &sc->sc_regs[0]);
+ for (i = 1; i < 32; ++i) {
+ __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
+ }
+
+ __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
+ __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
+
+ /* Rather than checking for dsp existence, always copy. The storage
+ would just be garbage otherwise. */
+ __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
+ __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
+ __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
+ __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
+ __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
+ __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
+ {
+ uint32_t dsp = cpu_rddsp(0x3ff, regs);
+ __put_user(dsp, &sc->sc_dsp);
+ }
+
+ __put_user(1, &sc->sc_used_math);
+
+ for (i = 0; i < 32; ++i) {
+ __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
+ }
+}
+
+static inline void
+restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
+{
+ int i;
+
+ __get_user(regs->CP0_EPC, &sc->sc_pc);
+
+ __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
+ __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
+
+ for (i = 1; i < 32; ++i) {
+ __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
+ }
+
+ __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
+ __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
+ __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
+ __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
+ __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
+ __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
+ {
+ uint32_t dsp;
+ __get_user(dsp, &sc->sc_dsp);
+ cpu_wrdsp(dsp, 0x3ff, regs);
+ }
+
+ for (i = 0; i < 32; ++i) {
+ __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
+ }
+}
+
+/*
+ * Determine which stack to use..
+ */
+static inline abi_ulong
+get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
+{
+ unsigned long sp;
+
+ /*
+ * FPU emulator may have its own trampoline active just
+ * above the user stack, 16-bytes before the next lowest
+ * 16 byte boundary. Try to avoid trashing it.
+ */
+ sp = target_sigsp(get_sp_from_cpustate(regs) - 32, ka);
+
+ return (sp - frame_size) & ~7;
+}
+
+static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
+{
+ if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
+ env->hflags &= ~MIPS_HFLAG_M16;
+ env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
+ env->active_tc.PC &= ~(target_ulong) 1;
+ }
+}
+
+# if defined(TARGET_ABI_MIPSO32)
+/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
+void setup_frame(int sig, struct target_sigaction * ka,
+ target_sigset_t *set, CPUMIPSState *regs)
+{
+ struct sigframe *frame;
+ abi_ulong frame_addr;
+ int i;
+
+ frame_addr = get_sigframe(ka, regs, sizeof(*frame));
+ trace_user_setup_frame(regs, frame_addr);
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+ goto give_sigsegv;
+ }
+
+ install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
+
+ setup_sigcontext(regs, &frame->sf_sc);
+
+ for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+ __put_user(set->sig[i], &frame->sf_mask.sig[i]);
+ }
+
+ /*
+ * Arguments to signal handler:
+ *
+ * a0 = signal number
+ * a1 = 0 (should be cause)
+ * a2 = pointer to struct sigcontext
+ *
+ * $25 and PC point to the signal handler, $29 points to the
+ * struct sigframe.
+ */
+ regs->active_tc.gpr[ 4] = sig;
+ regs->active_tc.gpr[ 5] = 0;
+ regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
+ regs->active_tc.gpr[29] = frame_addr;
+ regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
+ /* The original kernel code sets CP0_EPC to the handler
+ * since it returns to userland using eret
+ * we cannot do this here, and we must set PC directly */
+ regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
+ mips_set_hflags_isa_mode_from_pc(regs);
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+
+give_sigsegv:
+ force_sigsegv(sig);
+}
+
+long do_sigreturn(CPUMIPSState *regs)
+{
+ struct sigframe *frame;
+ abi_ulong frame_addr;
+ sigset_t blocked;
+ target_sigset_t target_set;
+ int i;
+
+ frame_addr = regs->active_tc.gpr[29];
+ trace_user_do_sigreturn(regs, frame_addr);
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
+ goto badframe;
+
+ for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+ __get_user(target_set.sig[i], &frame->sf_mask.sig[i]);
+ }
+
+ target_to_host_sigset_internal(&blocked, &target_set);
+ set_sigmask(&blocked);
+
+ restore_sigcontext(regs, &frame->sf_sc);
+
+#if 0
+ /*
+ * Don't let your children do this ...
+ */
+ __asm__ __volatile__(
+ "move\t$29, %0\n\t"
+ "j\tsyscall_exit"
+ :/* no outputs */
+ :"r" (&regs));
+ /* Unreached */
+#endif
+
+ regs->active_tc.PC = regs->CP0_EPC;
+ mips_set_hflags_isa_mode_from_pc(regs);
+ /* I am not sure this is right, but it seems to work
+ * maybe a problem with nested signals ? */
+ regs->CP0_EPC = 0;
+ return -TARGET_QEMU_ESIGRETURN;
+
+badframe:
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
+# endif /* O32 */
+
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPUMIPSState *env)
+{
+ struct target_rt_sigframe *frame;
+ abi_ulong frame_addr;
+ int i;
+
+ frame_addr = get_sigframe(ka, env, sizeof(*frame));
+ trace_user_setup_rt_frame(env, frame_addr);
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+ goto give_sigsegv;
+ }
+
+ install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
+
+ tswap_siginfo(&frame->rs_info, info);
+
+ __put_user(0, &frame->rs_uc.tuc_flags);
+ __put_user(0, &frame->rs_uc.tuc_link);
+ target_save_altstack(&frame->rs_uc.tuc_stack, env);
+
+ setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
+
+ for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+ __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
+ }
+
+ /*
+ * Arguments to signal handler:
+ *
+ * a0 = signal number
+ * a1 = pointer to siginfo_t
+ * a2 = pointer to ucontext_t
+ *
+ * $25 and PC point to the signal handler, $29 points to the
+ * struct sigframe.
+ */
+ env->active_tc.gpr[ 4] = sig;
+ env->active_tc.gpr[ 5] = frame_addr
+ + offsetof(struct target_rt_sigframe, rs_info);
+ env->active_tc.gpr[ 6] = frame_addr
+ + offsetof(struct target_rt_sigframe, rs_uc);
+ env->active_tc.gpr[29] = frame_addr;
+ env->active_tc.gpr[31] = frame_addr
+ + offsetof(struct target_rt_sigframe, rs_code);
+ /* The original kernel code sets CP0_EPC to the handler
+ * since it returns to userland using eret
+ * we cannot do this here, and we must set PC directly */
+ env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
+ mips_set_hflags_isa_mode_from_pc(env);
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+
+give_sigsegv:
+ unlock_user_struct(frame, frame_addr, 1);
+ force_sigsegv(sig);
+}
+
+long do_rt_sigreturn(CPUMIPSState *env)
+{
+ struct target_rt_sigframe *frame;
+ abi_ulong frame_addr;
+ sigset_t blocked;
+
+ frame_addr = env->active_tc.gpr[29];
+ trace_user_do_rt_sigreturn(env, frame_addr);
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+ goto badframe;
+ }
+
+ target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
+ set_sigmask(&blocked);
+
+ restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
+
+ if (do_sigaltstack(frame_addr +
+ offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
+ 0, get_sp_from_cpustate(env)) == -EFAULT)
+ goto badframe;
+
+ env->active_tc.PC = env->CP0_EPC;
+ mips_set_hflags_isa_mode_from_pc(env);
+ /* I am not sure this is right, but it seems to work
+ * maybe a problem with nested signals ? */
+ env->CP0_EPC = 0;
+ return -TARGET_QEMU_ESIGRETURN;
+
+badframe:
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
diff --git a/linux-user/mips/target_signal.h b/linux-user/mips/target_signal.h
index 8dd27cef35..d36f5da0a0 100644
--- a/linux-user/mips/target_signal.h
+++ b/linux-user/mips/target_signal.h
@@ -26,5 +26,8 @@ static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state)
return state->active_tc.gpr[29];
}
-
+#if defined(TARGET_ABI_MIPSO32)
+/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
+#define TARGET_ARCH_HAS_SETUP_FRAME
+#endif
#endif /* MIPS_TARGET_SIGNAL_H */
diff --git a/linux-user/mips64/cpu_loop.c b/linux-user/mips64/cpu_loop.c
new file mode 100644
index 0000000000..858bc5be78
--- /dev/null
+++ b/linux-user/mips64/cpu_loop.c
@@ -0,0 +1,20 @@
+/*
+ * qemu user cpu loop
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "../mips/cpu_loop.c"
diff --git a/linux-user/mips64/signal.c b/linux-user/mips64/signal.c
new file mode 100644
index 0000000000..4ed0ed90b3
--- /dev/null
+++ b/linux-user/mips64/signal.c
@@ -0,0 +1,20 @@
+/*
+ * Emulation of Linux signals
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#define MIPS_TARGET_SIGNAL_H /* to only include mips64/target_signal.h */
+#include "../mips/signal.c"
diff --git a/linux-user/mips64/target_signal.h b/linux-user/mips64/target_signal.h
index 67ef5a18f4..c074e1592f 100644
--- a/linux-user/mips64/target_signal.h
+++ b/linux-user/mips64/target_signal.h
@@ -25,6 +25,4 @@ static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state)
{
return state->active_tc.gpr[29];
}
-
-
#endif /* MIPS64_TARGET_SIGNAL_H */
diff --git a/linux-user/nios2/cpu_loop.c b/linux-user/nios2/cpu_loop.c
new file mode 100644
index 0000000000..dac7a06181
--- /dev/null
+++ b/linux-user/nios2/cpu_loop.c
@@ -0,0 +1,152 @@
+/*
+ * qemu user cpu loop
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "cpu_loop-common.h"
+
+void cpu_loop(CPUNios2State *env)
+{
+ CPUState *cs = ENV_GET_CPU(env);
+ Nios2CPU *cpu = NIOS2_CPU(cs);
+ target_siginfo_t info;
+ int trapnr, gdbsig, ret;
+
+ for (;;) {
+ cpu_exec_start(cs);
+ trapnr = cpu_exec(cs);
+ cpu_exec_end(cs);
+ gdbsig = 0;
+
+ switch (trapnr) {
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+ case EXCP_TRAP:
+ if (env->regs[R_AT] == 0) {
+ abi_long ret;
+ qemu_log_mask(CPU_LOG_INT, "\nSyscall\n");
+
+ ret = do_syscall(env, env->regs[2],
+ env->regs[4], env->regs[5], env->regs[6],
+ env->regs[7], env->regs[8], env->regs[9],
+ 0, 0);
+
+ if (env->regs[2] == 0) { /* FIXME: syscall 0 workaround */
+ ret = 0;
+ }
+
+ env->regs[2] = abs(ret);
+ /* Return value is 0..4096 */
+ env->regs[7] = (ret > 0xfffffffffffff000ULL);
+ env->regs[CR_ESTATUS] = env->regs[CR_STATUS];
+ env->regs[CR_STATUS] &= ~0x3;
+ env->regs[R_EA] = env->regs[R_PC] + 4;
+ env->regs[R_PC] += 4;
+ break;
+ } else {
+ qemu_log_mask(CPU_LOG_INT, "\nTrap\n");
+
+ env->regs[CR_ESTATUS] = env->regs[CR_STATUS];
+ env->regs[CR_STATUS] &= ~0x3;
+ env->regs[R_EA] = env->regs[R_PC] + 4;
+ env->regs[R_PC] = cpu->exception_addr;
+
+ gdbsig = TARGET_SIGTRAP;
+ break;
+ }
+ case 0xaa:
+ switch (env->regs[R_PC]) {
+ /*case 0x1000:*/ /* TODO:__kuser_helper_version */
+ case 0x1004: /* __kuser_cmpxchg */
+ start_exclusive();
+ if (env->regs[4] & 0x3) {
+ goto kuser_fail;
+ }
+ ret = get_user_u32(env->regs[2], env->regs[4]);
+ if (ret) {
+ end_exclusive();
+ goto kuser_fail;
+ }
+ env->regs[2] -= env->regs[5];
+ if (env->regs[2] == 0) {
+ put_user_u32(env->regs[6], env->regs[4]);
+ }
+ end_exclusive();
+ env->regs[R_PC] = env->regs[R_RA];
+ break;
+ /*case 0x1040:*/ /* TODO:__kuser_sigtramp */
+ default:
+ ;
+kuser_fail:
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ /* TODO: check env->error_code */
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = env->regs[R_PC];
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+ break;
+ default:
+ EXCP_DUMP(env, "\nqemu: unhandled CPU exception %#x - aborting\n",
+ trapnr);
+ gdbsig = TARGET_SIGILL;
+ break;
+ }
+ if (gdbsig) {
+ gdb_handlesig(cs, gdbsig);
+ if (gdbsig != TARGET_SIGTRAP) {
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ process_pending_signals(env);
+ }
+}
+
+void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
+{
+ env->regs[0] = 0;
+ env->regs[1] = regs->r1;
+ env->regs[2] = regs->r2;
+ env->regs[3] = regs->r3;
+ env->regs[4] = regs->r4;
+ env->regs[5] = regs->r5;
+ env->regs[6] = regs->r6;
+ env->regs[7] = regs->r7;
+ env->regs[8] = regs->r8;
+ env->regs[9] = regs->r9;
+ env->regs[10] = regs->r10;
+ env->regs[11] = regs->r11;
+ env->regs[12] = regs->r12;
+ env->regs[13] = regs->r13;
+ env->regs[14] = regs->r14;
+ env->regs[15] = regs->r15;
+ /* TODO: unsigned long orig_r2; */
+ env->regs[R_RA] = regs->ra;
+ env->regs[R_FP] = regs->fp;
+ env->regs[R_SP] = regs->sp;
+ env->regs[R_GP] = regs->gp;
+ env->regs[CR_ESTATUS] = regs->estatus;
+ env->regs[R_EA] = regs->ea;
+ /* TODO: unsigned long orig_r7; */
+
+ /* Emulate eret when starting thread. */
+ env->regs[R_PC] = regs->ea;
+}
diff --git a/linux-user/nios2/signal.c b/linux-user/nios2/signal.c
new file mode 100644
index 0000000000..9a0b36e5ad
--- /dev/null
+++ b/linux-user/nios2/signal.c
@@ -0,0 +1,237 @@
+/*
+ * Emulation of Linux signals
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "target_signal.h"
+#include "signal-common.h"
+#include "linux-user/trace.h"
+
+#define MCONTEXT_VERSION 2
+
+struct target_sigcontext {
+ int version;
+ unsigned long gregs[32];
+};
+
+struct target_ucontext {
+ abi_ulong tuc_flags;
+ abi_ulong tuc_link;
+ target_stack_t tuc_stack;
+ struct target_sigcontext tuc_mcontext;
+ target_sigset_t tuc_sigmask; /* mask last for extensibility */
+};
+
+struct target_rt_sigframe {
+ struct target_siginfo info;
+ struct target_ucontext uc;
+};
+
+static int rt_setup_ucontext(struct target_ucontext *uc, CPUNios2State *env)
+{
+ unsigned long *gregs = uc->tuc_mcontext.gregs;
+
+ __put_user(MCONTEXT_VERSION, &uc->tuc_mcontext.version);
+ __put_user(env->regs[1], &gregs[0]);
+ __put_user(env->regs[2], &gregs[1]);
+ __put_user(env->regs[3], &gregs[2]);
+ __put_user(env->regs[4], &gregs[3]);
+ __put_user(env->regs[5], &gregs[4]);
+ __put_user(env->regs[6], &gregs[5]);
+ __put_user(env->regs[7], &gregs[6]);
+ __put_user(env->regs[8], &gregs[7]);
+ __put_user(env->regs[9], &gregs[8]);
+ __put_user(env->regs[10], &gregs[9]);
+ __put_user(env->regs[11], &gregs[10]);
+ __put_user(env->regs[12], &gregs[11]);
+ __put_user(env->regs[13], &gregs[12]);
+ __put_user(env->regs[14], &gregs[13]);
+ __put_user(env->regs[15], &gregs[14]);
+ __put_user(env->regs[16], &gregs[15]);
+ __put_user(env->regs[17], &gregs[16]);
+ __put_user(env->regs[18], &gregs[17]);
+ __put_user(env->regs[19], &gregs[18]);
+ __put_user(env->regs[20], &gregs[19]);
+ __put_user(env->regs[21], &gregs[20]);
+ __put_user(env->regs[22], &gregs[21]);
+ __put_user(env->regs[23], &gregs[22]);
+ __put_user(env->regs[R_RA], &gregs[23]);
+ __put_user(env->regs[R_FP], &gregs[24]);
+ __put_user(env->regs[R_GP], &gregs[25]);
+ __put_user(env->regs[R_EA], &gregs[27]);
+ __put_user(env->regs[R_SP], &gregs[28]);
+
+ return 0;
+}
+
+static int rt_restore_ucontext(CPUNios2State *env, struct target_ucontext *uc,
+ int *pr2)
+{
+ int temp;
+ abi_ulong off, frame_addr = env->regs[R_SP];
+ unsigned long *gregs = uc->tuc_mcontext.gregs;
+ int err;
+
+ /* Always make any pending restarted system calls return -EINTR */
+ /* current->restart_block.fn = do_no_restart_syscall; */
+
+ __get_user(temp, &uc->tuc_mcontext.version);
+ if (temp != MCONTEXT_VERSION) {
+ return 1;
+ }
+
+ /* restore passed registers */
+ __get_user(env->regs[1], &gregs[0]);
+ __get_user(env->regs[2], &gregs[1]);
+ __get_user(env->regs[3], &gregs[2]);
+ __get_user(env->regs[4], &gregs[3]);
+ __get_user(env->regs[5], &gregs[4]);
+ __get_user(env->regs[6], &gregs[5]);
+ __get_user(env->regs[7], &gregs[6]);
+ __get_user(env->regs[8], &gregs[7]);
+ __get_user(env->regs[9], &gregs[8]);
+ __get_user(env->regs[10], &gregs[9]);
+ __get_user(env->regs[11], &gregs[10]);
+ __get_user(env->regs[12], &gregs[11]);
+ __get_user(env->regs[13], &gregs[12]);
+ __get_user(env->regs[14], &gregs[13]);
+ __get_user(env->regs[15], &gregs[14]);
+ __get_user(env->regs[16], &gregs[15]);
+ __get_user(env->regs[17], &gregs[16]);
+ __get_user(env->regs[18], &gregs[17]);
+ __get_user(env->regs[19], &gregs[18]);
+ __get_user(env->regs[20], &gregs[19]);
+ __get_user(env->regs[21], &gregs[20]);
+ __get_user(env->regs[22], &gregs[21]);
+ __get_user(env->regs[23], &gregs[22]);
+ /* gregs[23] is handled below */
+ /* Verify, should this be settable */
+ __get_user(env->regs[R_FP], &gregs[24]);
+ /* Verify, should this be settable */
+ __get_user(env->regs[R_GP], &gregs[25]);
+ /* Not really necessary no user settable bits */
+ __get_user(temp, &gregs[26]);
+ __get_user(env->regs[R_EA], &gregs[27]);
+
+ __get_user(env->regs[R_RA], &gregs[23]);
+ __get_user(env->regs[R_SP], &gregs[28]);
+
+ off = offsetof(struct target_rt_sigframe, uc.tuc_stack);
+ err = do_sigaltstack(frame_addr + off, 0, get_sp_from_cpustate(env));
+ if (err == -EFAULT) {
+ return 1;
+ }
+
+ *pr2 = env->regs[2];
+ return 0;
+}
+
+static void *get_sigframe(struct target_sigaction *ka, CPUNios2State *env,
+ size_t frame_size)
+{
+ unsigned long usp;
+
+ /* This is the X/Open sanctioned signal stack switching. */
+ usp = target_sigsp(get_sp_from_cpustate(env), ka);
+
+ /* Verify, is it 32 or 64 bit aligned */
+ return (void *)((usp - frame_size) & -8UL);
+}
+
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set,
+ CPUNios2State *env)
+{
+ struct target_rt_sigframe *frame;
+ int i, err = 0;
+
+ frame = get_sigframe(ka, env, sizeof(*frame));
+
+ if (ka->sa_flags & SA_SIGINFO) {
+ tswap_siginfo(&frame->info, info);
+ }
+
+ /* Create the ucontext. */
+ __put_user(0, &frame->uc.tuc_flags);
+ __put_user(0, &frame->uc.tuc_link);
+ target_save_altstack(&frame->uc.tuc_stack, env);
+ err |= rt_setup_ucontext(&frame->uc, env);
+ for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+ __put_user((abi_ulong)set->sig[i],
+ (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
+ }
+
+ if (err) {
+ goto give_sigsegv;
+ }
+
+ /* Set up to return from userspace; jump to fixed address sigreturn
+ trampoline on kuser page. */
+ env->regs[R_RA] = (unsigned long) (0x1044);
+
+ /* Set up registers for signal handler */
+ env->regs[R_SP] = (unsigned long) frame;
+ env->regs[4] = (unsigned long) sig;
+ env->regs[5] = (unsigned long) &frame->info;
+ env->regs[6] = (unsigned long) &frame->uc;
+ env->regs[R_EA] = (unsigned long) ka->_sa_handler;
+ return;
+
+give_sigsegv:
+ if (sig == TARGET_SIGSEGV) {
+ ka->_sa_handler = TARGET_SIG_DFL;
+ }
+ force_sigsegv(sig);
+ return;
+}
+
+long do_sigreturn(CPUNios2State *env)
+{
+ trace_user_do_sigreturn(env, 0);
+ fprintf(stderr, "do_sigreturn: not implemented\n");
+ return -TARGET_ENOSYS;
+}
+
+long do_rt_sigreturn(CPUNios2State *env)
+{
+ /* Verify, can we follow the stack back */
+ abi_ulong frame_addr = env->regs[R_SP];
+ struct target_rt_sigframe *frame;
+ sigset_t set;
+ int rval;
+
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+ goto badframe;
+ }
+
+ target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
+ do_sigprocmask(SIG_SETMASK, &set, NULL);
+
+ if (rt_restore_ucontext(env, &frame->uc, &rval)) {
+ goto badframe;
+ }
+
+ unlock_user_struct(frame, frame_addr, 0);
+ return rval;
+
+badframe:
+ unlock_user_struct(frame, frame_addr, 0);
+ force_sig(TARGET_SIGSEGV);
+ return 0;
+}
diff --git a/linux-user/nios2/target_signal.h b/linux-user/nios2/target_signal.h
index 23a8267696..f4db4d6d62 100644
--- a/linux-user/nios2/target_signal.h
+++ b/linux-user/nios2/target_signal.h
@@ -22,5 +22,4 @@ static inline abi_ulong get_sp_from_cpustate(CPUNios2State *state)
{
return state->regs[R_SP];
}
-
#endif /* TARGET_SIGNAL_H */
diff --git a/linux-user/openrisc/cpu_loop.c b/linux-user/openrisc/cpu_loop.c
new file mode 100644
index 0000000000..6c6ea871e1
--- /dev/null
+++ b/linux-user/openrisc/cpu_loop.c
@@ -0,0 +1,115 @@
+/*
+ * qemu user cpu loop
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "cpu_loop-common.h"
+
+void cpu_loop(CPUOpenRISCState *env)
+{
+ CPUState *cs = CPU(openrisc_env_get_cpu(env));
+ int trapnr;
+ abi_long ret;
+ target_siginfo_t info;
+
+ for (;;) {
+ cpu_exec_start(cs);
+ trapnr = cpu_exec(cs);
+ cpu_exec_end(cs);
+ process_queued_cpu_work(cs);
+
+ switch (trapnr) {
+ case EXCP_SYSCALL:
+ env->pc += 4; /* 0xc00; */
+ ret = do_syscall(env,
+ cpu_get_gpr(env, 11), /* return value */
+ cpu_get_gpr(env, 3), /* r3 - r7 are params */
+ cpu_get_gpr(env, 4),
+ cpu_get_gpr(env, 5),
+ cpu_get_gpr(env, 6),
+ cpu_get_gpr(env, 7),
+ cpu_get_gpr(env, 8), 0, 0);
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->pc -= 4;
+ } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+ cpu_set_gpr(env, 11, ret);
+ }
+ break;
+ case EXCP_DPF:
+ case EXCP_IPF:
+ case EXCP_RANGE:
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_ALIGN:
+ info.si_signo = TARGET_SIGBUS;
+ info.si_errno = 0;
+ info.si_code = TARGET_BUS_ADRALN;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_ILLEGAL:
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_ILLOPC;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_FPE:
+ info.si_signo = TARGET_SIGFPE;
+ info.si_errno = 0;
+ info.si_code = 0;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_INTERRUPT:
+ /* We processed the pending cpu work above. */
+ break;
+ case EXCP_DEBUG:
+ trapnr = gdb_handlesig(cs, TARGET_SIGTRAP);
+ if (trapnr) {
+ info.si_signo = trapnr;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+ break;
+ case EXCP_ATOMIC:
+ cpu_exec_step_atomic(cs);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ process_pending_signals(env);
+ }
+}
+
+void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
+{
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ cpu_set_gpr(env, i, regs->gpr[i]);
+ }
+ env->pc = regs->pc;
+ cpu_set_sr(env, regs->sr);
+}
diff --git a/linux-user/openrisc/signal.c b/linux-user/openrisc/signal.c
new file mode 100644
index 0000000000..ecf2897ccd
--- /dev/null
+++ b/linux-user/openrisc/signal.c
@@ -0,0 +1,223 @@
+/*
+ * Emulation of Linux signals
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "target_signal.h"
+#include "signal-common.h"
+#include "linux-user/trace.h"
+
+struct target_sigcontext {
+ struct target_pt_regs regs;
+ abi_ulong oldmask;
+ abi_ulong usp;
+};
+
+struct target_ucontext {
+ abi_ulong tuc_flags;
+ abi_ulong tuc_link;
+ target_stack_t tuc_stack;
+ struct target_sigcontext tuc_mcontext;
+ target_sigset_t tuc_sigmask; /* mask last for extensibility */
+};
+
+struct target_rt_sigframe {
+ abi_ulong pinfo;
+ uint64_t puc;
+ struct target_siginfo info;
+ struct target_sigcontext sc;
+ struct target_ucontext uc;
+ unsigned char retcode[16]; /* trampoline code */
+};
+
+/* This is the asm-generic/ucontext.h version */
+#if 0
+static int restore_sigcontext(CPUOpenRISCState *regs,
+ struct target_sigcontext *sc)
+{
+ unsigned int err = 0;
+ unsigned long old_usp;
+
+ /* Alwys make any pending restarted system call return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+ /* restore the regs from &sc->regs (same as sc, since regs is first)
+ * (sc is already checked for VERIFY_READ since the sigframe was
+ * checked in sys_sigreturn previously)
+ */
+
+ if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) {
+ goto badframe;
+ }
+
+ /* make sure the U-flag is set so user-mode cannot fool us */
+
+ regs->sr &= ~SR_SM;
+
+ /* restore the old USP as it was before we stacked the sc etc.
+ * (we cannot just pop the sigcontext since we aligned the sp and
+ * stuff after pushing it)
+ */
+
+ __get_user(old_usp, &sc->usp);
+ phx_signal("old_usp 0x%lx", old_usp);
+
+ __PHX__ REALLY /* ??? */
+ wrusp(old_usp);
+ regs->gpr[1] = old_usp;
+
+ /* TODO: the other ports use regs->orig_XX to disable syscall checks
+ * after this completes, but we don't use that mechanism. maybe we can
+ * use it now ?
+ */
+
+ return err;
+
+badframe:
+ return 1;
+}
+#endif
+
+/* Set up a signal frame. */
+
+static void setup_sigcontext(struct target_sigcontext *sc,
+ CPUOpenRISCState *regs,
+ unsigned long mask)
+{
+ unsigned long usp = cpu_get_gpr(regs, 1);
+
+ /* copy the regs. they are first in sc so we can use sc directly */
+
+ /*copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/
+
+ /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
+ the signal handler. The frametype will be restored to its previous
+ value in restore_sigcontext. */
+ /*regs->frametype = CRIS_FRAME_NORMAL;*/
+
+ /* then some other stuff */
+ __put_user(mask, &sc->oldmask);
+ __put_user(usp, &sc->usp);
+}
+
+static inline unsigned long align_sigframe(unsigned long sp)
+{
+ return sp & ~3UL;
+}
+
+static inline abi_ulong get_sigframe(struct target_sigaction *ka,
+ CPUOpenRISCState *regs,
+ size_t frame_size)
+{
+ unsigned long sp = get_sp_from_cpustate(regs);
+ int onsigstack = on_sig_stack(sp);
+
+ /* redzone */
+ sp = target_sigsp(sp, ka);
+
+ sp = align_sigframe(sp - frame_size);
+
+ /*
+ * If we are on the alternate signal stack and would overflow it, don't.
+ * Return an always-bogus address instead so we will die with SIGSEGV.
+ */
+
+ if (onsigstack && !likely(on_sig_stack(sp))) {
+ return -1L;
+ }
+
+ return sp;
+}
+
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPUOpenRISCState *env)
+{
+ int err = 0;
+ abi_ulong frame_addr;
+ unsigned long return_ip;
+ struct target_rt_sigframe *frame;
+ abi_ulong info_addr, uc_addr;
+
+ frame_addr = get_sigframe(ka, env, sizeof(*frame));
+ trace_user_setup_rt_frame(env, frame_addr);
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+ goto give_sigsegv;
+ }
+
+ info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
+ __put_user(info_addr, &frame->pinfo);
+ uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
+ __put_user(uc_addr, &frame->puc);
+
+ if (ka->sa_flags & SA_SIGINFO) {
+ tswap_siginfo(&frame->info, info);
+ }
+
+ /*err |= __clear_user(&frame->uc, offsetof(ucontext_t, uc_mcontext));*/
+ __put_user(0, &frame->uc.tuc_flags);
+ __put_user(0, &frame->uc.tuc_link);
+ target_save_altstack(&frame->uc.tuc_stack, env);
+ setup_sigcontext(&frame->sc, env, set->sig[0]);
+
+ /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/
+
+ /* trampoline - the desired return ip is the retcode itself */
+ return_ip = (unsigned long)&frame->retcode;
+ /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
+ __put_user(0xa960, (short *)(frame->retcode + 0));
+ __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2));
+ __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
+ __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
+
+ if (err) {
+ goto give_sigsegv;
+ }
+
+ /* TODO what is the current->exec_domain stuff and invmap ? */
+
+ /* Set up registers for signal handler */
+ env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
+ cpu_set_gpr(env, 9, (unsigned long)return_ip); /* what we enter LATER */
+ cpu_set_gpr(env, 3, (unsigned long)sig); /* arg 1: signo */
+ cpu_set_gpr(env, 4, (unsigned long)&frame->info); /* arg 2: (siginfo_t*) */
+ cpu_set_gpr(env, 5, (unsigned long)&frame->uc); /* arg 3: ucontext */
+
+ /* actually move the usp to reflect the stacked frame */
+ cpu_set_gpr(env, 1, (unsigned long)frame);
+
+ return;
+
+give_sigsegv:
+ unlock_user_struct(frame, frame_addr, 1);
+ force_sigsegv(sig);
+}
+
+long do_sigreturn(CPUOpenRISCState *env)
+{
+ trace_user_do_sigreturn(env, 0);
+ fprintf(stderr, "do_sigreturn: not implemented\n");
+ return -TARGET_ENOSYS;
+}
+
+long do_rt_sigreturn(CPUOpenRISCState *env)
+{
+ trace_user_do_rt_sigreturn(env, 0);
+ fprintf(stderr, "do_rt_sigreturn: not implemented\n");
+ return -TARGET_ENOSYS;
+}
diff --git a/linux-user/openrisc/target_signal.h b/linux-user/openrisc/target_signal.h
index 95a733e15a..2a4e00b035 100644
--- a/linux-user/openrisc/target_signal.h
+++ b/linux-user/openrisc/target_signal.h
@@ -22,6 +22,4 @@ static inline abi_ulong get_sp_from_cpustate(CPUOpenRISCState *state)
{
return cpu_get_gpr(state, 1);
}
-
-
#endif /* OPENRISC_TARGET_SIGNAL_H */
diff --git a/linux-user/ppc/cpu_loop.c b/linux-user/ppc/cpu_loop.c
new file mode 100644
index 0000000000..2fb516cb00
--- /dev/null
+++ b/linux-user/ppc/cpu_loop.c
@@ -0,0 +1,579 @@
+/*
+ * qemu user cpu loop
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "cpu_loop-common.h"
+
+static inline uint64_t cpu_ppc_get_tb(CPUPPCState *env)
+{
+ return cpu_get_host_ticks();
+}
+
+uint64_t cpu_ppc_load_tbl(CPUPPCState *env)
+{
+ return cpu_ppc_get_tb(env);
+}
+
+uint32_t cpu_ppc_load_tbu(CPUPPCState *env)
+{
+ return cpu_ppc_get_tb(env) >> 32;
+}
+
+uint64_t cpu_ppc_load_atbl(CPUPPCState *env)
+{
+ return cpu_ppc_get_tb(env);
+}
+
+uint32_t cpu_ppc_load_atbu(CPUPPCState *env)
+{
+ return cpu_ppc_get_tb(env) >> 32;
+}
+
+uint32_t cpu_ppc601_load_rtcu(CPUPPCState *env)
+__attribute__ (( alias ("cpu_ppc_load_tbu") ));
+
+uint32_t cpu_ppc601_load_rtcl(CPUPPCState *env)
+{
+ return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
+}
+
+/* XXX: to be fixed */
+int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
+{
+ return -1;
+}
+
+int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
+{
+ return -1;
+}
+
+static int do_store_exclusive(CPUPPCState *env)
+{
+ target_ulong addr;
+ target_ulong page_addr;
+ target_ulong val, val2 __attribute__((unused)) = 0;
+ int flags;
+ int segv = 0;
+
+ addr = env->reserve_ea;
+ page_addr = addr & TARGET_PAGE_MASK;
+ start_exclusive();
+ mmap_lock();
+ flags = page_get_flags(page_addr);
+ if ((flags & PAGE_READ) == 0) {
+ segv = 1;
+ } else {
+ int reg = env->reserve_info & 0x1f;
+ int size = env->reserve_info >> 5;
+ int stored = 0;
+
+ if (addr == env->reserve_addr) {
+ switch (size) {
+ case 1: segv = get_user_u8(val, addr); break;
+ case 2: segv = get_user_u16(val, addr); break;
+ case 4: segv = get_user_u32(val, addr); break;
+#if defined(TARGET_PPC64)
+ case 8: segv = get_user_u64(val, addr); break;
+ case 16: {
+ segv = get_user_u64(val, addr);
+ if (!segv) {
+ segv = get_user_u64(val2, addr + 8);
+ }
+ break;
+ }
+#endif
+ default: abort();
+ }
+ if (!segv && val == env->reserve_val) {
+ val = env->gpr[reg];
+ switch (size) {
+ case 1: segv = put_user_u8(val, addr); break;
+ case 2: segv = put_user_u16(val, addr); break;
+ case 4: segv = put_user_u32(val, addr); break;
+#if defined(TARGET_PPC64)
+ case 8: segv = put_user_u64(val, addr); break;
+ case 16: {
+ if (val2 == env->reserve_val2) {
+ if (msr_le) {
+ val2 = val;
+ val = env->gpr[reg+1];
+ } else {
+ val2 = env->gpr[reg+1];
+ }
+ segv = put_user_u64(val, addr);
+ if (!segv) {
+ segv = put_user_u64(val2, addr + 8);
+ }
+ }
+ break;
+ }
+#endif
+ default: abort();
+ }
+ if (!segv) {
+ stored = 1;
+ }
+ }
+ }
+ env->crf[0] = (stored << 1) | xer_so;
+ env->reserve_addr = (target_ulong)-1;
+ }
+ if (!segv) {
+ env->nip += 4;
+ }
+ mmap_unlock();
+ end_exclusive();
+ return segv;
+}
+
+void cpu_loop(CPUPPCState *env)
+{
+ CPUState *cs = CPU(ppc_env_get_cpu(env));
+ target_siginfo_t info;
+ int trapnr;
+ target_ulong ret;
+
+ for(;;) {
+ cpu_exec_start(cs);
+ trapnr = cpu_exec(cs);
+ cpu_exec_end(cs);
+ process_queued_cpu_work(cs);
+
+ switch(trapnr) {
+ case POWERPC_EXCP_NONE:
+ /* Just go on */
+ break;
+ case POWERPC_EXCP_CRITICAL: /* Critical input */
+ cpu_abort(cs, "Critical interrupt while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_MCHECK: /* Machine check exception */
+ cpu_abort(cs, "Machine check exception while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_DSI: /* Data storage exception */
+ /* XXX: check this. Seems bugged */
+ switch (env->error_code & 0xFF000000) {
+ case 0x40000000:
+ case 0x42000000:
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_MAPERR;
+ break;
+ case 0x04000000:
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_ILLADR;
+ break;
+ case 0x08000000:
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_ACCERR;
+ break;
+ default:
+ /* Let's send a regular segfault... */
+ EXCP_DUMP(env, "Invalid segfault errno (%02x)\n",
+ env->error_code);
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_MAPERR;
+ break;
+ }
+ info._sifields._sigfault._addr = env->spr[SPR_DAR];
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case POWERPC_EXCP_ISI: /* Instruction storage exception */
+ /* XXX: check this */
+ switch (env->error_code & 0xFF000000) {
+ case 0x40000000:
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_MAPERR;
+ break;
+ case 0x10000000:
+ case 0x08000000:
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_ACCERR;
+ break;
+ default:
+ /* Let's send a regular segfault... */
+ EXCP_DUMP(env, "Invalid segfault errno (%02x)\n",
+ env->error_code);
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_MAPERR;
+ break;
+ }
+ info._sifields._sigfault._addr = env->nip - 4;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case POWERPC_EXCP_EXTERNAL: /* External input */
+ cpu_abort(cs, "External interrupt while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_ALIGN: /* Alignment exception */
+ /* XXX: check this */
+ info.si_signo = TARGET_SIGBUS;
+ info.si_errno = 0;
+ info.si_code = TARGET_BUS_ADRALN;
+ info._sifields._sigfault._addr = env->nip;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case POWERPC_EXCP_PROGRAM: /* Program exception */
+ case POWERPC_EXCP_HV_EMU: /* HV emulation */
+ /* XXX: check this */
+ switch (env->error_code & ~0xF) {
+ case POWERPC_EXCP_FP:
+ info.si_signo = TARGET_SIGFPE;
+ info.si_errno = 0;
+ switch (env->error_code & 0xF) {
+ case POWERPC_EXCP_FP_OX:
+ info.si_code = TARGET_FPE_FLTOVF;
+ break;
+ case POWERPC_EXCP_FP_UX:
+ info.si_code = TARGET_FPE_FLTUND;
+ break;
+ case POWERPC_EXCP_FP_ZX:
+ case POWERPC_EXCP_FP_VXZDZ:
+ info.si_code = TARGET_FPE_FLTDIV;
+ break;
+ case POWERPC_EXCP_FP_XX:
+ info.si_code = TARGET_FPE_FLTRES;
+ break;
+ case POWERPC_EXCP_FP_VXSOFT:
+ info.si_code = TARGET_FPE_FLTINV;
+ break;
+ case POWERPC_EXCP_FP_VXSNAN:
+ case POWERPC_EXCP_FP_VXISI:
+ case POWERPC_EXCP_FP_VXIDI:
+ case POWERPC_EXCP_FP_VXIMZ:
+ case POWERPC_EXCP_FP_VXVC:
+ case POWERPC_EXCP_FP_VXSQRT:
+ case POWERPC_EXCP_FP_VXCVI:
+ info.si_code = TARGET_FPE_FLTSUB;
+ break;
+ default:
+ EXCP_DUMP(env, "Unknown floating point exception (%02x)\n",
+ env->error_code);
+ break;
+ }
+ break;
+ case POWERPC_EXCP_INVAL:
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ switch (env->error_code & 0xF) {
+ case POWERPC_EXCP_INVAL_INVAL:
+ info.si_code = TARGET_ILL_ILLOPC;
+ break;
+ case POWERPC_EXCP_INVAL_LSWX:
+ info.si_code = TARGET_ILL_ILLOPN;
+ break;
+ case POWERPC_EXCP_INVAL_SPR:
+ info.si_code = TARGET_ILL_PRVREG;
+ break;
+ case POWERPC_EXCP_INVAL_FP:
+ info.si_code = TARGET_ILL_COPROC;
+ break;
+ default:
+ EXCP_DUMP(env, "Unknown invalid operation (%02x)\n",
+ env->error_code & 0xF);
+ info.si_code = TARGET_ILL_ILLADR;
+ break;
+ }
+ break;
+ case POWERPC_EXCP_PRIV:
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ switch (env->error_code & 0xF) {
+ case POWERPC_EXCP_PRIV_OPC:
+ info.si_code = TARGET_ILL_PRVOPC;
+ break;
+ case POWERPC_EXCP_PRIV_REG:
+ info.si_code = TARGET_ILL_PRVREG;
+ break;
+ default:
+ EXCP_DUMP(env, "Unknown privilege violation (%02x)\n",
+ env->error_code & 0xF);
+ info.si_code = TARGET_ILL_PRVOPC;
+ break;
+ }
+ break;
+ case POWERPC_EXCP_TRAP:
+ cpu_abort(cs, "Tried to call a TRAP\n");
+ break;
+ default:
+ /* Should not happen ! */
+ cpu_abort(cs, "Unknown program exception (%02x)\n",
+ env->error_code);
+ break;
+ }
+ info._sifields._sigfault._addr = env->nip;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_COPROC;
+ info._sifields._sigfault._addr = env->nip;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case POWERPC_EXCP_SYSCALL: /* System call exception */
+ cpu_abort(cs, "Syscall exception while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_COPROC;
+ info._sifields._sigfault._addr = env->nip;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case POWERPC_EXCP_DECR: /* Decrementer exception */
+ cpu_abort(cs, "Decrementer interrupt while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
+ cpu_abort(cs, "Fix interval timer interrupt while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
+ cpu_abort(cs, "Watchdog timer interrupt while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_DTLB: /* Data TLB error */
+ cpu_abort(cs, "Data TLB exception while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_ITLB: /* Instruction TLB error */
+ cpu_abort(cs, "Instruction TLB exception while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavail. */
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_COPROC;
+ info._sifields._sigfault._addr = env->nip;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case POWERPC_EXCP_EFPDI: /* Embedded floating-point data IRQ */
+ cpu_abort(cs, "Embedded floating-point data IRQ not handled\n");
+ break;
+ case POWERPC_EXCP_EFPRI: /* Embedded floating-point round IRQ */
+ cpu_abort(cs, "Embedded floating-point round IRQ not handled\n");
+ break;
+ case POWERPC_EXCP_EPERFM: /* Embedded performance monitor IRQ */
+ cpu_abort(cs, "Performance monitor exception not handled\n");
+ break;
+ case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
+ cpu_abort(cs, "Doorbell interrupt while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
+ cpu_abort(cs, "Doorbell critical interrupt while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_RESET: /* System reset exception */
+ cpu_abort(cs, "Reset interrupt while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_DSEG: /* Data segment exception */
+ cpu_abort(cs, "Data segment exception while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_ISEG: /* Instruction segment exception */
+ cpu_abort(cs, "Instruction segment exception "
+ "while in user mode. Aborting\n");
+ break;
+ /* PowerPC 64 with hypervisor mode support */
+ case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
+ cpu_abort(cs, "Hypervisor decrementer interrupt "
+ "while in user mode. Aborting\n");
+ break;
+ case POWERPC_EXCP_TRACE: /* Trace exception */
+ /* Nothing to do:
+ * we use this exception to emulate step-by-step execution mode.
+ */
+ break;
+ /* PowerPC 64 with hypervisor mode support */
+ case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
+ cpu_abort(cs, "Hypervisor data storage exception "
+ "while in user mode. Aborting\n");
+ break;
+ case POWERPC_EXCP_HISI: /* Hypervisor instruction storage excp */
+ cpu_abort(cs, "Hypervisor instruction storage exception "
+ "while in user mode. Aborting\n");
+ break;
+ case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */
+ cpu_abort(cs, "Hypervisor data segment exception "
+ "while in user mode. Aborting\n");
+ break;
+ case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment excp */
+ cpu_abort(cs, "Hypervisor instruction segment exception "
+ "while in user mode. Aborting\n");
+ break;
+ case POWERPC_EXCP_VPU: /* Vector unavailable exception */
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_COPROC;
+ info._sifields._sigfault._addr = env->nip;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case POWERPC_EXCP_PIT: /* Programmable interval timer IRQ */
+ cpu_abort(cs, "Programmable interval timer interrupt "
+ "while in user mode. Aborting\n");
+ break;
+ case POWERPC_EXCP_IO: /* IO error exception */
+ cpu_abort(cs, "IO error exception while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_RUNM: /* Run mode exception */
+ cpu_abort(cs, "Run mode exception while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_EMUL: /* Emulation trap exception */
+ cpu_abort(cs, "Emulation trap exception not handled\n");
+ break;
+ case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
+ cpu_abort(cs, "Instruction fetch TLB exception "
+ "while in user-mode. Aborting");
+ break;
+ case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
+ cpu_abort(cs, "Data load TLB exception while in user-mode. "
+ "Aborting");
+ break;
+ case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
+ cpu_abort(cs, "Data store TLB exception while in user-mode. "
+ "Aborting");
+ break;
+ case POWERPC_EXCP_FPA: /* Floating-point assist exception */
+ cpu_abort(cs, "Floating-point assist exception not handled\n");
+ break;
+ case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
+ cpu_abort(cs, "Instruction address breakpoint exception "
+ "not handled\n");
+ break;
+ case POWERPC_EXCP_SMI: /* System management interrupt */
+ cpu_abort(cs, "System management interrupt while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_THERM: /* Thermal interrupt */
+ cpu_abort(cs, "Thermal interrupt interrupt while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_PERFM: /* Embedded performance monitor IRQ */
+ cpu_abort(cs, "Performance monitor exception not handled\n");
+ break;
+ case POWERPC_EXCP_VPUA: /* Vector assist exception */
+ cpu_abort(cs, "Vector assist exception not handled\n");
+ break;
+ case POWERPC_EXCP_SOFTP: /* Soft patch exception */
+ cpu_abort(cs, "Soft patch exception not handled\n");
+ break;
+ case POWERPC_EXCP_MAINT: /* Maintenance exception */
+ cpu_abort(cs, "Maintenance exception while in user mode. "
+ "Aborting\n");
+ break;
+ case POWERPC_EXCP_STOP: /* stop translation */
+ /* We did invalidate the instruction cache. Go on */
+ break;
+ case POWERPC_EXCP_BRANCH: /* branch instruction: */
+ /* We just stopped because of a branch. Go on */
+ break;
+ case POWERPC_EXCP_SYSCALL_USER:
+ /* system call in user-mode emulation */
+ /* WARNING:
+ * PPC ABI uses overflow flag in cr0 to signal an error
+ * in syscalls.
+ */
+ env->crf[0] &= ~0x1;
+ env->nip += 4;
+ ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
+ env->gpr[5], env->gpr[6], env->gpr[7],
+ env->gpr[8], 0, 0);
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->nip -= 4;
+ break;
+ }
+ if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
+ /* Returning from a successful sigreturn syscall.
+ Avoid corrupting register state. */
+ break;
+ }
+ if (ret > (target_ulong)(-515)) {
+ env->crf[0] |= 0x1;
+ ret = -ret;
+ }
+ env->gpr[3] = ret;
+ break;
+ case POWERPC_EXCP_STCX:
+ if (do_store_exclusive(env)) {
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = env->nip;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+ break;
+ case EXCP_DEBUG:
+ {
+ int sig;
+
+ sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+ if (sig) {
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+ }
+ break;
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+ case EXCP_ATOMIC:
+ cpu_exec_step_atomic(cs);
+ break;
+ default:
+ cpu_abort(cs, "Unknown exception 0x%x. Aborting\n", trapnr);
+ break;
+ }
+ process_pending_signals(env);
+ }
+}
+
+void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
+{
+ int i;
+
+#if defined(TARGET_PPC64)
+ int flag = (env->insns_flags2 & PPC2_BOOKE206) ? MSR_CM : MSR_SF;
+#if defined(TARGET_ABI32)
+ env->msr &= ~((target_ulong)1 << flag);
+#else
+ env->msr |= (target_ulong)1 << flag;
+#endif
+#endif
+ env->nip = regs->nip;
+ for(i = 0; i < 32; i++) {
+ env->gpr[i] = regs->gpr[i];
+ }
+}
diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c
new file mode 100644
index 0000000000..cacc9afb5a
--- /dev/null
+++ b/linux-user/ppc/signal.c
@@ -0,0 +1,678 @@
+/*
+ * Emulation of Linux signals
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "target_signal.h"
+#include "signal-common.h"
+#include "linux-user/trace.h"
+
+/* Size of dummy stack frame allocated when calling signal handler.
+ See arch/powerpc/include/asm/ptrace.h. */
+#if defined(TARGET_PPC64)
+#define SIGNAL_FRAMESIZE 128
+#else
+#define SIGNAL_FRAMESIZE 64
+#endif
+
+/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC;
+ on 64-bit PPC, sigcontext and mcontext are one and the same. */
+struct target_mcontext {
+ target_ulong mc_gregs[48];
+ /* Includes fpscr. */
+ uint64_t mc_fregs[33];
+#if defined(TARGET_PPC64)
+ /* Pointer to the vector regs */
+ target_ulong v_regs;
+#else
+ target_ulong mc_pad[2];
+#endif
+ /* We need to handle Altivec and SPE at the same time, which no
+ kernel needs to do. Fortunately, the kernel defines this bit to
+ be Altivec-register-large all the time, rather than trying to
+ twiddle it based on the specific platform. */
+ union {
+ /* SPE vector registers. One extra for SPEFSCR. */
+ uint32_t spe[33];
+ /* Altivec vector registers. The packing of VSCR and VRSAVE
+ varies depending on whether we're PPC64 or not: PPC64 splits
+ them apart; PPC32 stuffs them together.
+ We also need to account for the VSX registers on PPC64
+ */
+#if defined(TARGET_PPC64)
+#define QEMU_NVRREG (34 + 16)
+ /* On ppc64, this mcontext structure is naturally *unaligned*,
+ * or rather it is aligned on a 8 bytes boundary but not on
+ * a 16 bytes one. This pad fixes it up. This is also why the
+ * vector regs are referenced by the v_regs pointer above so
+ * any amount of padding can be added here
+ */
+ target_ulong pad;
+#else
+ /* On ppc32, we are already aligned to 16 bytes */
+#define QEMU_NVRREG 33
+#endif
+ /* We cannot use ppc_avr_t here as we do *not* want the implied
+ * 16-bytes alignment that would result from it. This would have
+ * the effect of making the whole struct target_mcontext aligned
+ * which breaks the layout of struct target_ucontext on ppc64.
+ */
+ uint64_t altivec[QEMU_NVRREG][2];
+#undef QEMU_NVRREG
+ } mc_vregs;
+};
+
+/* See arch/powerpc/include/asm/sigcontext.h. */
+struct target_sigcontext {
+ target_ulong _unused[4];
+ int32_t signal;
+#if defined(TARGET_PPC64)
+ int32_t pad0;
+#endif
+ target_ulong handler;
+ target_ulong oldmask;
+ target_ulong regs; /* struct pt_regs __user * */
+#if defined(TARGET_PPC64)
+ struct target_mcontext mcontext;
+#endif
+};
+
+/* Indices for target_mcontext.mc_gregs, below.
+ See arch/powerpc/include/asm/ptrace.h for details. */
+enum {
+ TARGET_PT_R0 = 0,
+ TARGET_PT_R1 = 1,
+ TARGET_PT_R2 = 2,
+ TARGET_PT_R3 = 3,
+ TARGET_PT_R4 = 4,
+ TARGET_PT_R5 = 5,
+ TARGET_PT_R6 = 6,
+ TARGET_PT_R7 = 7,
+ TARGET_PT_R8 = 8,
+ TARGET_PT_R9 = 9,
+ TARGET_PT_R10 = 10,
+ TARGET_PT_R11 = 11,
+ TARGET_PT_R12 = 12,
+ TARGET_PT_R13 = 13,
+ TARGET_PT_R14 = 14,
+ TARGET_PT_R15 = 15,
+ TARGET_PT_R16 = 16,
+ TARGET_PT_R17 = 17,
+ TARGET_PT_R18 = 18,
+ TARGET_PT_R19 = 19,
+ TARGET_PT_R20 = 20,
+ TARGET_PT_R21 = 21,
+ TARGET_PT_R22 = 22,
+ TARGET_PT_R23 = 23,
+ TARGET_PT_R24 = 24,
+ TARGET_PT_R25 = 25,
+ TARGET_PT_R26 = 26,
+ TARGET_PT_R27 = 27,
+ TARGET_PT_R28 = 28,
+ TARGET_PT_R29 = 29,
+ TARGET_PT_R30 = 30,
+ TARGET_PT_R31 = 31,
+ TARGET_PT_NIP = 32,
+ TARGET_PT_MSR = 33,
+ TARGET_PT_ORIG_R3 = 34,
+ TARGET_PT_CTR = 35,
+ TARGET_PT_LNK = 36,
+ TARGET_PT_XER = 37,
+ TARGET_PT_CCR = 38,
+ /* Yes, there are two registers with #39. One is 64-bit only. */
+ TARGET_PT_MQ = 39,
+ TARGET_PT_SOFTE = 39,
+ TARGET_PT_TRAP = 40,
+ TARGET_PT_DAR = 41,
+ TARGET_PT_DSISR = 42,
+ TARGET_PT_RESULT = 43,
+ TARGET_PT_REGS_COUNT = 44
+};
+
+
+struct target_ucontext {
+ target_ulong tuc_flags;
+ target_ulong tuc_link; /* ucontext_t __user * */
+ struct target_sigaltstack tuc_stack;
+#if !defined(TARGET_PPC64)
+ int32_t tuc_pad[7];
+ target_ulong tuc_regs; /* struct mcontext __user *
+ points to uc_mcontext field */
+#endif
+ target_sigset_t tuc_sigmask;
+#if defined(TARGET_PPC64)
+ target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
+ struct target_sigcontext tuc_sigcontext;
+#else
+ int32_t tuc_maskext[30];
+ int32_t tuc_pad2[3];
+ struct target_mcontext tuc_mcontext;
+#endif
+};
+
+/* See arch/powerpc/kernel/signal_32.c. */
+struct target_sigframe {
+ struct target_sigcontext sctx;
+ struct target_mcontext mctx;
+ int32_t abigap[56];
+};
+
+#if defined(TARGET_PPC64)
+
+#define TARGET_TRAMP_SIZE 6
+
+struct target_rt_sigframe {
+ /* sys_rt_sigreturn requires the ucontext be the first field */
+ struct target_ucontext uc;
+ target_ulong _unused[2];
+ uint32_t trampoline[TARGET_TRAMP_SIZE];
+ target_ulong pinfo; /* struct siginfo __user * */
+ target_ulong puc; /* void __user * */
+ struct target_siginfo info;
+ /* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
+ char abigap[288];
+} __attribute__((aligned(16)));
+
+#else
+
+struct target_rt_sigframe {
+ struct target_siginfo info;
+ struct target_ucontext uc;
+ int32_t abigap[56];
+};
+
+#endif
+
+#if defined(TARGET_PPC64)
+
+struct target_func_ptr {
+ target_ulong entry;
+ target_ulong toc;
+};
+
+#endif
+
+/* We use the mc_pad field for the signal return trampoline. */
+#define tramp mc_pad
+
+/* See arch/powerpc/kernel/signal.c. */
+static target_ulong get_sigframe(struct target_sigaction *ka,
+ CPUPPCState *env,
+ int frame_size)
+{
+ target_ulong oldsp;
+
+ oldsp = target_sigsp(get_sp_from_cpustate(env), ka);
+
+ return (oldsp - frame_size) & ~0xFUL;
+}
+
+#if ((defined(TARGET_WORDS_BIGENDIAN) && defined(HOST_WORDS_BIGENDIAN)) || \
+ (!defined(HOST_WORDS_BIGENDIAN) && !defined(TARGET_WORDS_BIGENDIAN)))
+#define PPC_VEC_HI 0
+#define PPC_VEC_LO 1
+#else
+#define PPC_VEC_HI 1
+#define PPC_VEC_LO 0
+#endif
+
+
+static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame)
+{
+ target_ulong msr = env->msr;
+ int i;
+ target_ulong ccr = 0;
+
+ /* In general, the kernel attempts to be intelligent about what it
+ needs to save for Altivec/FP/SPE registers. We don't care that
+ much, so we just go ahead and save everything. */
+
+ /* Save general registers. */
+ for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
+ __put_user(env->gpr[i], &frame->mc_gregs[i]);
+ }
+ __put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
+ __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
+ __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
+ __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
+
+ for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
+ ccr |= env->crf[i] << (32 - ((i + 1) * 4));
+ }
+ __put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
+
+ /* Save Altivec registers if necessary. */
+ if (env->insns_flags & PPC_ALTIVEC) {
+ uint32_t *vrsave;
+ for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
+ ppc_avr_t *avr = &env->avr[i];
+ ppc_avr_t *vreg = (ppc_avr_t *)&frame->mc_vregs.altivec[i];
+
+ __put_user(avr->u64[PPC_VEC_HI], &vreg->u64[0]);
+ __put_user(avr->u64[PPC_VEC_LO], &vreg->u64[1]);
+ }
+ /* Set MSR_VR in the saved MSR value to indicate that
+ frame->mc_vregs contains valid data. */
+ msr |= MSR_VR;
+#if defined(TARGET_PPC64)
+ vrsave = (uint32_t *)&frame->mc_vregs.altivec[33];
+ /* 64-bit needs to put a pointer to the vectors in the frame */
+ __put_user(h2g(frame->mc_vregs.altivec), &frame->v_regs);
+#else
+ vrsave = (uint32_t *)&frame->mc_vregs.altivec[32];
+#endif
+ __put_user((uint32_t)env->spr[SPR_VRSAVE], vrsave);
+ }
+
+ /* Save VSX second halves */
+ if (env->insns_flags2 & PPC2_VSX) {
+ uint64_t *vsregs = (uint64_t *)&frame->mc_vregs.altivec[34];
+ for (i = 0; i < ARRAY_SIZE(env->vsr); i++) {
+ __put_user(env->vsr[i], &vsregs[i]);
+ }
+ }
+
+ /* Save floating point registers. */
+ if (env->insns_flags & PPC_FLOAT) {
+ for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
+ __put_user(env->fpr[i], &frame->mc_fregs[i]);
+ }
+ __put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]);
+ }
+
+ /* Save SPE registers. The kernel only saves the high half. */
+ if (env->insns_flags & PPC_SPE) {
+#if defined(TARGET_PPC64)
+ for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
+ __put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i]);
+ }
+#else
+ for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
+ __put_user(env->gprh[i], &frame->mc_vregs.spe[i]);
+ }
+#endif
+ /* Set MSR_SPE in the saved MSR value to indicate that
+ frame->mc_vregs contains valid data. */
+ msr |= MSR_SPE;
+ __put_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
+ }
+
+ /* Store MSR. */
+ __put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
+}
+
+static void encode_trampoline(int sigret, uint32_t *tramp)
+{
+ /* Set up the sigreturn trampoline: li r0,sigret; sc. */
+ if (sigret) {
+ __put_user(0x38000000 | sigret, &tramp[0]);
+ __put_user(0x44000002, &tramp[1]);
+ }
+}
+
+static void restore_user_regs(CPUPPCState *env,
+ struct target_mcontext *frame, int sig)
+{
+ target_ulong save_r2 = 0;
+ target_ulong msr;
+ target_ulong ccr;
+
+ int i;
+
+ if (!sig) {
+ save_r2 = env->gpr[2];
+ }
+
+ /* Restore general registers. */
+ for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
+ __get_user(env->gpr[i], &frame->mc_gregs[i]);
+ }
+ __get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
+ __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
+ __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
+ __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
+ __get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
+
+ for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
+ env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
+ }
+
+ if (!sig) {
+ env->gpr[2] = save_r2;
+ }
+ /* Restore MSR. */
+ __get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
+
+ /* If doing signal return, restore the previous little-endian mode. */
+ if (sig)
+ env->msr = (env->msr & ~(1ull << MSR_LE)) | (msr & (1ull << MSR_LE));
+
+ /* Restore Altivec registers if necessary. */
+ if (env->insns_flags & PPC_ALTIVEC) {
+ ppc_avr_t *v_regs;
+ uint32_t *vrsave;
+#if defined(TARGET_PPC64)
+ uint64_t v_addr;
+ /* 64-bit needs to recover the pointer to the vectors from the frame */
+ __get_user(v_addr, &frame->v_regs);
+ v_regs = g2h(v_addr);
+#else
+ v_regs = (ppc_avr_t *)frame->mc_vregs.altivec;
+#endif
+ for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
+ ppc_avr_t *avr = &env->avr[i];
+ ppc_avr_t *vreg = &v_regs[i];
+
+ __get_user(avr->u64[PPC_VEC_HI], &vreg->u64[0]);
+ __get_user(avr->u64[PPC_VEC_LO], &vreg->u64[1]);
+ }
+ /* Set MSR_VEC in the saved MSR value to indicate that
+ frame->mc_vregs contains valid data. */
+#if defined(TARGET_PPC64)
+ vrsave = (uint32_t *)&v_regs[33];
+#else
+ vrsave = (uint32_t *)&v_regs[32];
+#endif
+ __get_user(env->spr[SPR_VRSAVE], vrsave);
+ }
+
+ /* Restore VSX second halves */
+ if (env->insns_flags2 & PPC2_VSX) {
+ uint64_t *vsregs = (uint64_t *)&frame->mc_vregs.altivec[34];
+ for (i = 0; i < ARRAY_SIZE(env->vsr); i++) {
+ __get_user(env->vsr[i], &vsregs[i]);
+ }
+ }
+
+ /* Restore floating point registers. */
+ if (env->insns_flags & PPC_FLOAT) {
+ uint64_t fpscr;
+ for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
+ __get_user(env->fpr[i], &frame->mc_fregs[i]);
+ }
+ __get_user(fpscr, &frame->mc_fregs[32]);
+ env->fpscr = (uint32_t) fpscr;
+ }
+
+ /* Save SPE registers. The kernel only saves the high half. */
+ if (env->insns_flags & PPC_SPE) {
+#if defined(TARGET_PPC64)
+ for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
+ uint32_t hi;
+
+ __get_user(hi, &frame->mc_vregs.spe[i]);
+ env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
+ }
+#else
+ for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
+ __get_user(env->gprh[i], &frame->mc_vregs.spe[i]);
+ }
+#endif
+ __get_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
+ }
+}
+
+#if !defined(TARGET_PPC64)
+void setup_frame(int sig, struct target_sigaction *ka,
+ target_sigset_t *set, CPUPPCState *env)
+{
+ struct target_sigframe *frame;
+ struct target_sigcontext *sc;
+ target_ulong frame_addr, newsp;
+ int err = 0;
+
+ frame_addr = get_sigframe(ka, env, sizeof(*frame));
+ trace_user_setup_frame(env, frame_addr);
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
+ goto sigsegv;
+ sc = &frame->sctx;
+
+ __put_user(ka->_sa_handler, &sc->handler);
+ __put_user(set->sig[0], &sc->oldmask);
+ __put_user(set->sig[1], &sc->_unused[3]);
+ __put_user(h2g(&frame->mctx), &sc->regs);
+ __put_user(sig, &sc->signal);
+
+ /* Save user regs. */
+ save_user_regs(env, &frame->mctx);
+
+ /* Construct the trampoline code on the stack. */
+ encode_trampoline(TARGET_NR_sigreturn, (uint32_t *)&frame->mctx.tramp);
+
+ /* The kernel checks for the presence of a VDSO here. We don't
+ emulate a vdso, so use a sigreturn system call. */
+ env->lr = (target_ulong) h2g(frame->mctx.tramp);
+
+ /* Turn off all fp exceptions. */
+ env->fpscr = 0;
+
+ /* Create a stack frame for the caller of the handler. */
+ newsp = frame_addr - SIGNAL_FRAMESIZE;
+ err |= put_user(env->gpr[1], newsp, target_ulong);
+
+ if (err)
+ goto sigsegv;
+
+ /* Set up registers for signal handler. */
+ env->gpr[1] = newsp;
+ env->gpr[3] = sig;
+ env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
+
+ env->nip = (target_ulong) ka->_sa_handler;
+
+ /* Signal handlers are entered in big-endian mode. */
+ env->msr &= ~(1ull << MSR_LE);
+
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+
+sigsegv:
+ unlock_user_struct(frame, frame_addr, 1);
+ force_sigsegv(sig);
+}
+#endif /* !defined(TARGET_PPC64) */
+
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPUPPCState *env)
+{
+ struct target_rt_sigframe *rt_sf;
+ uint32_t *trampptr = 0;
+ struct target_mcontext *mctx = 0;
+ target_ulong rt_sf_addr, newsp = 0;
+ int i, err = 0;
+#if defined(TARGET_PPC64)
+ struct target_sigcontext *sc = 0;
+ struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
+#endif
+
+ rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
+ if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
+ goto sigsegv;
+
+ tswap_siginfo(&rt_sf->info, info);
+
+ __put_user(0, &rt_sf->uc.tuc_flags);
+ __put_user(0, &rt_sf->uc.tuc_link);
+ target_save_altstack(&rt_sf->uc.tuc_stack, env);
+#if !defined(TARGET_PPC64)
+ __put_user(h2g (&rt_sf->uc.tuc_mcontext),
+ &rt_sf->uc.tuc_regs);
+#endif
+ for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+ __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
+ }
+
+#if defined(TARGET_PPC64)
+ mctx = &rt_sf->uc.tuc_sigcontext.mcontext;
+ trampptr = &rt_sf->trampoline[0];
+
+ sc = &rt_sf->uc.tuc_sigcontext;
+ __put_user(h2g(mctx), &sc->regs);
+ __put_user(sig, &sc->signal);
+#else
+ mctx = &rt_sf->uc.tuc_mcontext;
+ trampptr = (uint32_t *)&rt_sf->uc.tuc_mcontext.tramp;
+#endif
+
+ save_user_regs(env, mctx);
+ encode_trampoline(TARGET_NR_rt_sigreturn, trampptr);
+
+ /* The kernel checks for the presence of a VDSO here. We don't
+ emulate a vdso, so use a sigreturn system call. */
+ env->lr = (target_ulong) h2g(trampptr);
+
+ /* Turn off all fp exceptions. */
+ env->fpscr = 0;
+
+ /* Create a stack frame for the caller of the handler. */
+ newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
+ err |= put_user(env->gpr[1], newsp, target_ulong);
+
+ if (err)
+ goto sigsegv;
+
+ /* Set up registers for signal handler. */
+ env->gpr[1] = newsp;
+ env->gpr[3] = (target_ulong) sig;
+ env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
+ env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
+ env->gpr[6] = (target_ulong) h2g(rt_sf);
+
+#if defined(TARGET_PPC64)
+ if (get_ppc64_abi(image) < 2) {
+ /* ELFv1 PPC64 function pointers are pointers to OPD entries. */
+ struct target_func_ptr *handler =
+ (struct target_func_ptr *)g2h(ka->_sa_handler);
+ env->nip = tswapl(handler->entry);
+ env->gpr[2] = tswapl(handler->toc);
+ } else {
+ /* ELFv2 PPC64 function pointers are entry points, but R12
+ * must also be set */
+ env->nip = tswapl((target_ulong) ka->_sa_handler);
+ env->gpr[12] = env->nip;
+ }
+#else
+ env->nip = (target_ulong) ka->_sa_handler;
+#endif
+
+ /* Signal handlers are entered in big-endian mode. */
+ env->msr &= ~(1ull << MSR_LE);
+
+ unlock_user_struct(rt_sf, rt_sf_addr, 1);
+ return;
+
+sigsegv:
+ unlock_user_struct(rt_sf, rt_sf_addr, 1);
+ force_sigsegv(sig);
+
+}
+
+#if !defined(TARGET_PPC64)
+long do_sigreturn(CPUPPCState *env)
+{
+ struct target_sigcontext *sc = NULL;
+ struct target_mcontext *sr = NULL;
+ target_ulong sr_addr = 0, sc_addr;
+ sigset_t blocked;
+ target_sigset_t set;
+
+ sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
+ if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
+ goto sigsegv;
+
+#if defined(TARGET_PPC64)
+ set.sig[0] = sc->oldmask + ((uint64_t)(sc->_unused[3]) << 32);
+#else
+ __get_user(set.sig[0], &sc->oldmask);
+ __get_user(set.sig[1], &sc->_unused[3]);
+#endif
+ target_to_host_sigset_internal(&blocked, &set);
+ set_sigmask(&blocked);
+
+ __get_user(sr_addr, &sc->regs);
+ if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
+ goto sigsegv;
+ restore_user_regs(env, sr, 1);
+
+ unlock_user_struct(sr, sr_addr, 1);
+ unlock_user_struct(sc, sc_addr, 1);
+ return -TARGET_QEMU_ESIGRETURN;
+
+sigsegv:
+ unlock_user_struct(sr, sr_addr, 1);
+ unlock_user_struct(sc, sc_addr, 1);
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
+#endif /* !defined(TARGET_PPC64) */
+
+/* See arch/powerpc/kernel/signal_32.c. */
+static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
+{
+ struct target_mcontext *mcp;
+ target_ulong mcp_addr;
+ sigset_t blocked;
+ target_sigset_t set;
+
+ if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, tuc_sigmask),
+ sizeof (set)))
+ return 1;
+
+#if defined(TARGET_PPC64)
+ mcp_addr = h2g(ucp) +
+ offsetof(struct target_ucontext, tuc_sigcontext.mcontext);
+#else
+ __get_user(mcp_addr, &ucp->tuc_regs);
+#endif
+
+ if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
+ return 1;
+
+ target_to_host_sigset_internal(&blocked, &set);
+ set_sigmask(&blocked);
+ restore_user_regs(env, mcp, sig);
+
+ unlock_user_struct(mcp, mcp_addr, 1);
+ return 0;
+}
+
+long do_rt_sigreturn(CPUPPCState *env)
+{
+ struct target_rt_sigframe *rt_sf = NULL;
+ target_ulong rt_sf_addr;
+
+ rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
+ if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
+ goto sigsegv;
+
+ if (do_setcontext(&rt_sf->uc, env, 1))
+ goto sigsegv;
+
+ do_sigaltstack(rt_sf_addr
+ + offsetof(struct target_rt_sigframe, uc.tuc_stack),
+ 0, env->gpr[1]);
+
+ unlock_user_struct(rt_sf, rt_sf_addr, 1);
+ return -TARGET_QEMU_ESIGRETURN;
+
+sigsegv:
+ unlock_user_struct(rt_sf, rt_sf_addr, 1);
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
diff --git a/linux-user/ppc/target_signal.h b/linux-user/ppc/target_signal.h
index 865c52f3e8..e3bf1d2856 100644
--- a/linux-user/ppc/target_signal.h
+++ b/linux-user/ppc/target_signal.h
@@ -26,5 +26,7 @@ static inline abi_ulong get_sp_from_cpustate(CPUPPCState *state)
return state->gpr[1];
}
-
+#if !defined(TARGET_PPC64)
+#define TARGET_ARCH_HAS_SETUP_FRAME
+#endif
#endif /* PPC_TARGET_SIGNAL_H */
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 192a0d2fef..c55c8e294b 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -51,13 +51,15 @@ struct image_info {
abi_ulong file_string;
uint32_t elf_flags;
int personality;
-#ifdef CONFIG_USE_FDPIC
+
+ /* The fields below are used in FDPIC mode. */
abi_ulong loadmap_addr;
uint16_t nsegs;
void *loadsegs;
abi_ulong pt_dynamic_addr;
+ abi_ulong interpreter_loadmap_addr;
+ abi_ulong interpreter_pt_dynamic_addr;
struct image_info *other_info;
-#endif
};
#ifdef TARGET_I386
@@ -183,6 +185,13 @@ int loader_exec(int fdexec, const char *filename, char **argv, char **envp,
struct target_pt_regs * regs, struct image_info *infop,
struct linux_binprm *);
+/* Returns true if the image uses the FDPIC ABI. If this is the case,
+ * we have to provide some information (loadmap, pt_dynamic_info) such
+ * that the program can be relocated adequately. This is also useful
+ * when handling signals.
+ */
+int info_is_fdpic(struct image_info *info);
+
uint32_t get_elf_eflags(int fd);
int load_elf_binary(struct linux_binprm *bprm, struct image_info *info);
int load_flt_binary(struct linux_binprm *bprm, struct image_info *info);
diff --git a/linux-user/riscv/cpu_loop.c b/linux-user/riscv/cpu_loop.c
new file mode 100644
index 0000000000..f137d39d7e
--- /dev/null
+++ b/linux-user/riscv/cpu_loop.c
@@ -0,0 +1,118 @@
+/*
+ * qemu user cpu loop
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "cpu_loop-common.h"
+
+void cpu_loop(CPURISCVState *env)
+{
+ CPUState *cs = CPU(riscv_env_get_cpu(env));
+ int trapnr, signum, sigcode;
+ target_ulong sigaddr;
+ target_ulong ret;
+
+ for (;;) {
+ cpu_exec_start(cs);
+ trapnr = cpu_exec(cs);
+ cpu_exec_end(cs);
+ process_queued_cpu_work(cs);
+
+ signum = 0;
+ sigcode = 0;
+ sigaddr = 0;
+
+ switch (trapnr) {
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+ case EXCP_ATOMIC:
+ cpu_exec_step_atomic(cs);
+ break;
+ case RISCV_EXCP_U_ECALL:
+ env->pc += 4;
+ if (env->gpr[xA7] == TARGET_NR_arch_specific_syscall + 15) {
+ /* riscv_flush_icache_syscall is a no-op in QEMU as
+ self-modifying code is automatically detected */
+ ret = 0;
+ } else {
+ ret = do_syscall(env,
+ env->gpr[xA7],
+ env->gpr[xA0],
+ env->gpr[xA1],
+ env->gpr[xA2],
+ env->gpr[xA3],
+ env->gpr[xA4],
+ env->gpr[xA5],
+ 0, 0);
+ }
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->pc -= 4;
+ } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+ env->gpr[xA0] = ret;
+ }
+ if (cs->singlestep_enabled) {
+ goto gdbstep;
+ }
+ break;
+ case RISCV_EXCP_ILLEGAL_INST:
+ signum = TARGET_SIGILL;
+ sigcode = TARGET_ILL_ILLOPC;
+ break;
+ case RISCV_EXCP_BREAKPOINT:
+ signum = TARGET_SIGTRAP;
+ sigcode = TARGET_TRAP_BRKPT;
+ sigaddr = env->pc;
+ break;
+ case RISCV_EXCP_INST_PAGE_FAULT:
+ case RISCV_EXCP_LOAD_PAGE_FAULT:
+ case RISCV_EXCP_STORE_PAGE_FAULT:
+ signum = TARGET_SIGSEGV;
+ sigcode = TARGET_SEGV_MAPERR;
+ break;
+ case EXCP_DEBUG:
+ gdbstep:
+ signum = gdb_handlesig(cs, TARGET_SIGTRAP);
+ sigcode = TARGET_TRAP_BRKPT;
+ break;
+ default:
+ EXCP_DUMP(env, "\nqemu: unhandled CPU exception %#x - aborting\n",
+ trapnr);
+ exit(EXIT_FAILURE);
+ }
+
+ if (signum) {
+ target_siginfo_t info = {
+ .si_signo = signum,
+ .si_errno = 0,
+ .si_code = sigcode,
+ ._sifields._sigfault._addr = sigaddr
+ };
+ queue_signal(env, info.si_signo, QEMU_SI_KILL, &info);
+ }
+
+ process_pending_signals(env);
+ }
+}
+
+void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
+{
+ env->pc = regs->sepc;
+ env->gpr[xSP] = regs->sp;
+}
diff --git a/linux-user/riscv/signal.c b/linux-user/riscv/signal.c
new file mode 100644
index 0000000000..ef599e319a
--- /dev/null
+++ b/linux-user/riscv/signal.c
@@ -0,0 +1,208 @@
+/*
+ * Emulation of Linux signals
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "target_signal.h"
+#include "signal-common.h"
+#include "linux-user/trace.h"
+
+/* Signal handler invocation must be transparent for the code being
+ interrupted. Complete CPU (hart) state is saved on entry and restored
+ before returning from the handler. Process sigmask is also saved to block
+ signals while the handler is running. The handler gets its own stack,
+ which also doubles as storage for the CPU state and sigmask.
+
+ The code below is qemu re-implementation of arch/riscv/kernel/signal.c */
+
+struct target_sigcontext {
+ abi_long pc;
+ abi_long gpr[31]; /* x0 is not present, so all offsets must be -1 */
+ uint64_t fpr[32];
+ uint32_t fcsr;
+}; /* cf. riscv-linux:arch/riscv/include/uapi/asm/ptrace.h */
+
+struct target_ucontext {
+ unsigned long uc_flags;
+ struct target_ucontext *uc_link;
+ target_stack_t uc_stack;
+ struct target_sigcontext uc_mcontext;
+ target_sigset_t uc_sigmask;
+};
+
+struct target_rt_sigframe {
+ uint32_t tramp[2]; /* not in kernel, which uses VDSO instead */
+ struct target_siginfo info;
+ struct target_ucontext uc;
+};
+
+static abi_ulong get_sigframe(struct target_sigaction *ka,
+ CPURISCVState *regs, size_t framesize)
+{
+ abi_ulong sp = get_sp_from_cpustate(regs);
+
+ /* If we are on the alternate signal stack and would overflow it, don't.
+ Return an always-bogus address instead so we will die with SIGSEGV. */
+ if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize))) {
+ return -1L;
+ }
+
+ /* This is the X/Open sanctioned signal stack switching. */
+ sp = target_sigsp(sp, ka) - framesize;
+
+ /* XXX: kernel aligns with 0xf ? */
+ sp &= ~3UL; /* align sp on 4-byte boundary */
+
+ return sp;
+}
+
+static void setup_sigcontext(struct target_sigcontext *sc, CPURISCVState *env)
+{
+ int i;
+
+ __put_user(env->pc, &sc->pc);
+
+ for (i = 1; i < 32; i++) {
+ __put_user(env->gpr[i], &sc->gpr[i - 1]);
+ }
+ for (i = 0; i < 32; i++) {
+ __put_user(env->fpr[i], &sc->fpr[i]);
+ }
+
+ uint32_t fcsr = csr_read_helper(env, CSR_FCSR); /*riscv_get_fcsr(env);*/
+ __put_user(fcsr, &sc->fcsr);
+}
+
+static void setup_ucontext(struct target_ucontext *uc,
+ CPURISCVState *env, target_sigset_t *set)
+{
+ __put_user(0, &(uc->uc_flags));
+ __put_user(0, &(uc->uc_link));
+
+ target_save_altstack(&uc->uc_stack, env);
+
+ int i;
+ for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+ __put_user(set->sig[i], &(uc->uc_sigmask.sig[i]));
+ }
+
+ setup_sigcontext(&uc->uc_mcontext, env);
+}
+
+static inline void install_sigtramp(uint32_t *tramp)
+{
+ __put_user(0x08b00893, tramp + 0); /* li a7, 139 = __NR_rt_sigreturn */
+ __put_user(0x00000073, tramp + 1); /* ecall */
+}
+
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPURISCVState *env)
+{
+ abi_ulong frame_addr;
+ struct target_rt_sigframe *frame;
+
+ frame_addr = get_sigframe(ka, env, sizeof(*frame));
+ trace_user_setup_rt_frame(env, frame_addr);
+
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+ goto badframe;
+ }
+
+ setup_ucontext(&frame->uc, env, set);
+ tswap_siginfo(&frame->info, info);
+ install_sigtramp(frame->tramp);
+
+ env->pc = ka->_sa_handler;
+ env->gpr[xSP] = frame_addr;
+ env->gpr[xA0] = sig;
+ env->gpr[xA1] = frame_addr + offsetof(struct target_rt_sigframe, info);
+ env->gpr[xA2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
+ env->gpr[xRA] = frame_addr + offsetof(struct target_rt_sigframe, tramp);
+
+ return;
+
+badframe:
+ unlock_user_struct(frame, frame_addr, 1);
+ if (sig == TARGET_SIGSEGV) {
+ ka->_sa_handler = TARGET_SIG_DFL;
+ }
+ force_sig(TARGET_SIGSEGV);
+}
+
+static void restore_sigcontext(CPURISCVState *env, struct target_sigcontext *sc)
+{
+ int i;
+
+ __get_user(env->pc, &sc->pc);
+
+ for (i = 1; i < 32; ++i) {
+ __get_user(env->gpr[i], &sc->gpr[i - 1]);
+ }
+ for (i = 0; i < 32; ++i) {
+ __get_user(env->fpr[i], &sc->fpr[i]);
+ }
+
+ uint32_t fcsr;
+ __get_user(fcsr, &sc->fcsr);
+ csr_write_helper(env, fcsr, CSR_FCSR);
+}
+
+static void restore_ucontext(CPURISCVState *env, struct target_ucontext *uc)
+{
+ sigset_t blocked;
+ target_sigset_t target_set;
+ int i;
+
+ target_sigemptyset(&target_set);
+ for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+ __get_user(target_set.sig[i], &(uc->uc_sigmask.sig[i]));
+ }
+
+ target_to_host_sigset_internal(&blocked, &target_set);
+ set_sigmask(&blocked);
+
+ restore_sigcontext(env, &uc->uc_mcontext);
+}
+
+long do_rt_sigreturn(CPURISCVState *env)
+{
+ struct target_rt_sigframe *frame;
+ abi_ulong frame_addr;
+
+ frame_addr = env->gpr[xSP];
+ trace_user_do_sigreturn(env, frame_addr);
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+ goto badframe;
+ }
+
+ restore_ucontext(env, &frame->uc);
+
+ if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
+ uc.uc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) {
+ goto badframe;
+ }
+
+ unlock_user_struct(frame, frame_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+
+badframe:
+ unlock_user_struct(frame, frame_addr, 0);
+ force_sig(TARGET_SIGSEGV);
+ return 0;
+}
diff --git a/linux-user/riscv/target_signal.h b/linux-user/riscv/target_signal.h
index ce77f752e3..9dac002c0d 100644
--- a/linux-user/riscv/target_signal.h
+++ b/linux-user/riscv/target_signal.h
@@ -19,5 +19,4 @@ static inline abi_ulong get_sp_from_cpustate(CPURISCVState *state)
{
return state->gpr[xSP];
}
-
#endif /* TARGET_SIGNAL_H */
diff --git a/linux-user/riscv/target_syscall.h b/linux-user/riscv/target_syscall.h
index d4e109a27f..ee81d8bc88 100644
--- a/linux-user/riscv/target_syscall.h
+++ b/linux-user/riscv/target_syscall.h
@@ -45,7 +45,7 @@ struct target_pt_regs {
#else
#define UNAME_MACHINE "riscv64"
#endif
-#define UNAME_MINIMUM_RELEASE "3.8.0"
+#define UNAME_MINIMUM_RELEASE "4.15.0"
#define TARGET_MINSIGSTKSZ 2048
#define TARGET_MLOCKALL_MCL_CURRENT 1
diff --git a/linux-user/s390x/cpu_loop.c b/linux-user/s390x/cpu_loop.c
new file mode 100644
index 0000000000..99f5f1594f
--- /dev/null
+++ b/linux-user/s390x/cpu_loop.c
@@ -0,0 +1,165 @@
+/*
+ * qemu user cpu loop
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "cpu_loop-common.h"
+
+/* s390x masks the fault address it reports in si_addr for SIGSEGV and SIGBUS */
+#define S390X_FAIL_ADDR_MASK -4096LL
+
+void cpu_loop(CPUS390XState *env)
+{
+ CPUState *cs = CPU(s390_env_get_cpu(env));
+ int trapnr, n, sig;
+ target_siginfo_t info;
+ target_ulong addr;
+ abi_long ret;
+
+ while (1) {
+ cpu_exec_start(cs);
+ trapnr = cpu_exec(cs);
+ cpu_exec_end(cs);
+ process_queued_cpu_work(cs);
+
+ switch (trapnr) {
+ case EXCP_INTERRUPT:
+ /* Just indicate that signals should be handled asap. */
+ break;
+
+ case EXCP_SVC:
+ n = env->int_svc_code;
+ if (!n) {
+ /* syscalls > 255 */
+ n = env->regs[1];
+ }
+ env->psw.addr += env->int_svc_ilen;
+ ret = do_syscall(env, n, env->regs[2], env->regs[3],
+ env->regs[4], env->regs[5],
+ env->regs[6], env->regs[7], 0, 0);
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->psw.addr -= env->int_svc_ilen;
+ } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+ env->regs[2] = ret;
+ }
+ break;
+
+ case EXCP_DEBUG:
+ sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+ if (sig) {
+ n = TARGET_TRAP_BRKPT;
+ goto do_signal_pc;
+ }
+ break;
+ case EXCP_PGM:
+ n = env->int_pgm_code;
+ switch (n) {
+ case PGM_OPERATION:
+ case PGM_PRIVILEGED:
+ sig = TARGET_SIGILL;
+ n = TARGET_ILL_ILLOPC;
+ goto do_signal_pc;
+ case PGM_PROTECTION:
+ case PGM_ADDRESSING:
+ sig = TARGET_SIGSEGV;
+ /* XXX: check env->error_code */
+ n = TARGET_SEGV_MAPERR;
+ addr = env->__excp_addr & S390X_FAIL_ADDR_MASK;
+ goto do_signal;
+ case PGM_EXECUTE:
+ case PGM_SPECIFICATION:
+ case PGM_SPECIAL_OP:
+ case PGM_OPERAND:
+ do_sigill_opn:
+ sig = TARGET_SIGILL;
+ n = TARGET_ILL_ILLOPN;
+ goto do_signal_pc;
+
+ case PGM_FIXPT_OVERFLOW:
+ sig = TARGET_SIGFPE;
+ n = TARGET_FPE_INTOVF;
+ goto do_signal_pc;
+ case PGM_FIXPT_DIVIDE:
+ sig = TARGET_SIGFPE;
+ n = TARGET_FPE_INTDIV;
+ goto do_signal_pc;
+
+ case PGM_DATA:
+ n = (env->fpc >> 8) & 0xff;
+ if (n == 0xff) {
+ /* compare-and-trap */
+ goto do_sigill_opn;
+ } else {
+ /* An IEEE exception, simulated or otherwise. */
+ if (n & 0x80) {
+ n = TARGET_FPE_FLTINV;
+ } else if (n & 0x40) {
+ n = TARGET_FPE_FLTDIV;
+ } else if (n & 0x20) {
+ n = TARGET_FPE_FLTOVF;
+ } else if (n & 0x10) {
+ n = TARGET_FPE_FLTUND;
+ } else if (n & 0x08) {
+ n = TARGET_FPE_FLTRES;
+ } else {
+ /* ??? Quantum exception; BFP, DFP error. */
+ goto do_sigill_opn;
+ }
+ sig = TARGET_SIGFPE;
+ goto do_signal_pc;
+ }
+
+ default:
+ fprintf(stderr, "Unhandled program exception: %#x\n", n);
+ cpu_dump_state(cs, stderr, fprintf, 0);
+ exit(EXIT_FAILURE);
+ }
+ break;
+
+ do_signal_pc:
+ addr = env->psw.addr;
+ do_signal:
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = n;
+ info._sifields._sigfault._addr = addr;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+
+ case EXCP_ATOMIC:
+ cpu_exec_step_atomic(cs);
+ break;
+ default:
+ fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr);
+ cpu_dump_state(cs, stderr, fprintf, 0);
+ exit(EXIT_FAILURE);
+ }
+ process_pending_signals (env);
+ }
+}
+
+void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
+{
+ int i;
+ for (i = 0; i < 16; i++) {
+ env->regs[i] = regs->gprs[i];
+ }
+ env->psw.mask = regs->psw.mask;
+ env->psw.addr = regs->psw.addr;
+}
diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c
new file mode 100644
index 0000000000..e35cbe6870
--- /dev/null
+++ b/linux-user/s390x/signal.c
@@ -0,0 +1,321 @@
+/*
+ * Emulation of Linux signals
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "target_signal.h"
+#include "signal-common.h"
+#include "linux-user/trace.h"
+
+#define __NUM_GPRS 16
+#define __NUM_FPRS 16
+#define __NUM_ACRS 16
+
+#define S390_SYSCALL_SIZE 2
+#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */
+
+#define _SIGCONTEXT_NSIG 64
+#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */
+#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
+#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
+#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */
+#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
+
+typedef struct {
+ target_psw_t psw;
+ target_ulong gprs[__NUM_GPRS];
+ unsigned int acrs[__NUM_ACRS];
+} target_s390_regs_common;
+
+typedef struct {
+ unsigned int fpc;
+ double fprs[__NUM_FPRS];
+} target_s390_fp_regs;
+
+typedef struct {
+ target_s390_regs_common regs;
+ target_s390_fp_regs fpregs;
+} target_sigregs;
+
+struct target_sigcontext {
+ target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
+ target_sigregs *sregs;
+};
+
+typedef struct {
+ uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
+ struct target_sigcontext sc;
+ target_sigregs sregs;
+ int signo;
+ uint8_t retcode[S390_SYSCALL_SIZE];
+} sigframe;
+
+struct target_ucontext {
+ target_ulong tuc_flags;
+ struct target_ucontext *tuc_link;
+ target_stack_t tuc_stack;
+ target_sigregs tuc_mcontext;
+ target_sigset_t tuc_sigmask; /* mask last for extensibility */
+};
+
+typedef struct {
+ uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
+ uint8_t retcode[S390_SYSCALL_SIZE];
+ struct target_siginfo info;
+ struct target_ucontext uc;
+} rt_sigframe;
+
+static inline abi_ulong
+get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
+{
+ abi_ulong sp;
+
+ /* Default to using normal stack */
+ sp = get_sp_from_cpustate(env);
+
+ /* This is the X/Open sanctioned signal stack switching. */
+ if (ka->sa_flags & TARGET_SA_ONSTACK) {
+ sp = target_sigsp(sp, ka);
+ }
+
+ /* This is the legacy signal stack switching. */
+ else if (/* FIXME !user_mode(regs) */ 0 &&
+ !(ka->sa_flags & TARGET_SA_RESTORER) &&
+ ka->sa_restorer) {
+ sp = (abi_ulong) ka->sa_restorer;
+ }
+
+ return (sp - frame_size) & -8ul;
+}
+
+static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
+{
+ int i;
+ //save_access_regs(current->thread.acrs); FIXME
+
+ /* Copy a 'clean' PSW mask to the user to avoid leaking
+ information about whether PER is currently on. */
+ __put_user(env->psw.mask, &sregs->regs.psw.mask);
+ __put_user(env->psw.addr, &sregs->regs.psw.addr);
+ for (i = 0; i < 16; i++) {
+ __put_user(env->regs[i], &sregs->regs.gprs[i]);
+ }
+ for (i = 0; i < 16; i++) {
+ __put_user(env->aregs[i], &sregs->regs.acrs[i]);
+ }
+ /*
+ * We have to store the fp registers to current->thread.fp_regs
+ * to merge them with the emulated registers.
+ */
+ //save_fp_regs(&current->thread.fp_regs); FIXME
+ for (i = 0; i < 16; i++) {
+ __put_user(get_freg(env, i)->ll, &sregs->fpregs.fprs[i]);
+ }
+}
+
+void setup_frame(int sig, struct target_sigaction *ka,
+ target_sigset_t *set, CPUS390XState *env)
+{
+ sigframe *frame;
+ abi_ulong frame_addr;
+
+ frame_addr = get_sigframe(ka, env, sizeof(*frame));
+ trace_user_setup_frame(env, frame_addr);
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+ goto give_sigsegv;
+ }
+
+ __put_user(set->sig[0], &frame->sc.oldmask[0]);
+
+ save_sigregs(env, &frame->sregs);
+
+ __put_user((abi_ulong)(unsigned long)&frame->sregs,
+ (abi_ulong *)&frame->sc.sregs);
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ if (ka->sa_flags & TARGET_SA_RESTORER) {
+ env->regs[14] = (unsigned long)
+ ka->sa_restorer | PSW_ADDR_AMODE;
+ } else {
+ env->regs[14] = (frame_addr + offsetof(sigframe, retcode))
+ | PSW_ADDR_AMODE;
+ __put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
+ (uint16_t *)(frame->retcode));
+ }
+
+ /* Set up backchain. */
+ __put_user(env->regs[15], (abi_ulong *) frame);
+
+ /* Set up registers for signal handler */
+ env->regs[15] = frame_addr;
+ env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
+
+ env->regs[2] = sig; //map_signal(sig);
+ env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
+
+ /* We forgot to include these in the sigcontext.
+ To avoid breaking binary compatibility, they are passed as args. */
+ env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
+ env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
+
+ /* Place signal number on stack to allow backtrace from handler. */
+ __put_user(env->regs[2], &frame->signo);
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+
+give_sigsegv:
+ force_sigsegv(sig);
+}
+
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPUS390XState *env)
+{
+ int i;
+ rt_sigframe *frame;
+ abi_ulong frame_addr;
+
+ frame_addr = get_sigframe(ka, env, sizeof *frame);
+ trace_user_setup_rt_frame(env, frame_addr);
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+ goto give_sigsegv;
+ }
+
+ tswap_siginfo(&frame->info, info);
+
+ /* Create the ucontext. */
+ __put_user(0, &frame->uc.tuc_flags);
+ __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
+ target_save_altstack(&frame->uc.tuc_stack, env);
+ save_sigregs(env, &frame->uc.tuc_mcontext);
+ for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+ __put_user((abi_ulong)set->sig[i],
+ (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
+ }
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ if (ka->sa_flags & TARGET_SA_RESTORER) {
+ env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
+ } else {
+ env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
+ __put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
+ (uint16_t *)(frame->retcode));
+ }
+
+ /* Set up backchain. */
+ __put_user(env->regs[15], (abi_ulong *) frame);
+
+ /* Set up registers for signal handler */
+ env->regs[15] = frame_addr;
+ env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
+
+ env->regs[2] = sig; //map_signal(sig);
+ env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
+ env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
+ return;
+
+give_sigsegv:
+ force_sigsegv(sig);
+}
+
+static int
+restore_sigregs(CPUS390XState *env, target_sigregs *sc)
+{
+ int err = 0;
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ __get_user(env->regs[i], &sc->regs.gprs[i]);
+ }
+
+ __get_user(env->psw.mask, &sc->regs.psw.mask);
+ trace_user_s390x_restore_sigregs(env, (unsigned long long)sc->regs.psw.addr,
+ (unsigned long long)env->psw.addr);
+ __get_user(env->psw.addr, &sc->regs.psw.addr);
+ /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
+
+ for (i = 0; i < 16; i++) {
+ __get_user(env->aregs[i], &sc->regs.acrs[i]);
+ }
+ for (i = 0; i < 16; i++) {
+ __get_user(get_freg(env, i)->ll, &sc->fpregs.fprs[i]);
+ }
+
+ return err;
+}
+
+long do_sigreturn(CPUS390XState *env)
+{
+ sigframe *frame;
+ abi_ulong frame_addr = env->regs[15];
+ target_sigset_t target_set;
+ sigset_t set;
+
+ trace_user_do_sigreturn(env, frame_addr);
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+ goto badframe;
+ }
+ __get_user(target_set.sig[0], &frame->sc.oldmask[0]);
+
+ target_to_host_sigset_internal(&set, &target_set);
+ set_sigmask(&set); /* ~_BLOCKABLE? */
+
+ if (restore_sigregs(env, &frame->sregs)) {
+ goto badframe;
+ }
+
+ unlock_user_struct(frame, frame_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+
+badframe:
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
+
+long do_rt_sigreturn(CPUS390XState *env)
+{
+ rt_sigframe *frame;
+ abi_ulong frame_addr = env->regs[15];
+ sigset_t set;
+
+ trace_user_do_rt_sigreturn(env, frame_addr);
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+ goto badframe;
+ }
+ target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
+
+ set_sigmask(&set); /* ~_BLOCKABLE? */
+
+ if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
+ goto badframe;
+ }
+
+ if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
+ get_sp_from_cpustate(env)) == -EFAULT) {
+ goto badframe;
+ }
+ unlock_user_struct(frame, frame_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+
+badframe:
+ unlock_user_struct(frame, frame_addr, 0);
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
diff --git a/linux-user/s390x/target_signal.h b/linux-user/s390x/target_signal.h
index 6f7b6abafe..4e99f8fadd 100644
--- a/linux-user/s390x/target_signal.h
+++ b/linux-user/s390x/target_signal.h
@@ -23,5 +23,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUS390XState *state)
return state->regs[15];
}
-
+#define TARGET_ARCH_HAS_SETUP_FRAME
#endif /* S390X_TARGET_SIGNAL_H */
diff --git a/linux-user/sh4/cpu_loop.c b/linux-user/sh4/cpu_loop.c
new file mode 100644
index 0000000000..418833ea25
--- /dev/null
+++ b/linux-user/sh4/cpu_loop.c
@@ -0,0 +1,111 @@
+/*
+ * qemu user cpu loop
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "cpu_loop-common.h"
+
+void cpu_loop(CPUSH4State *env)
+{
+ CPUState *cs = CPU(sh_env_get_cpu(env));
+ int trapnr, ret;
+ target_siginfo_t info;
+
+ while (1) {
+ bool arch_interrupt = true;
+
+ cpu_exec_start(cs);
+ trapnr = cpu_exec(cs);
+ cpu_exec_end(cs);
+ process_queued_cpu_work(cs);
+
+ switch (trapnr) {
+ case 0x160:
+ env->pc += 2;
+ ret = do_syscall(env,
+ env->gregs[3],
+ env->gregs[4],
+ env->gregs[5],
+ env->gregs[6],
+ env->gregs[7],
+ env->gregs[0],
+ env->gregs[1],
+ 0, 0);
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->pc -= 2;
+ } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+ env->gregs[0] = ret;
+ }
+ break;
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+ case EXCP_DEBUG:
+ {
+ int sig;
+
+ sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+ if (sig) {
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ } else {
+ arch_interrupt = false;
+ }
+ }
+ break;
+ case 0xa0:
+ case 0xc0:
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = env->tea;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_ATOMIC:
+ cpu_exec_step_atomic(cs);
+ arch_interrupt = false;
+ break;
+ default:
+ printf ("Unhandled trap: 0x%x\n", trapnr);
+ cpu_dump_state(cs, stderr, fprintf, 0);
+ exit(EXIT_FAILURE);
+ }
+ process_pending_signals (env);
+
+ /* Most of the traps imply an exception or interrupt, which
+ implies an REI instruction has been executed. Which means
+ that LDST (aka LOK_ADDR) should be cleared. But there are
+ a few exceptions for traps internal to QEMU. */
+ if (arch_interrupt) {
+ env->lock_addr = -1;
+ }
+ }
+}
+
+void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
+{
+ int i;
+
+ for(i = 0; i < 16; i++) {
+ env->gregs[i] = regs->regs[i];
+ }
+ env->pc = regs->pc;
+}
diff --git a/linux-user/sh4/signal.c b/linux-user/sh4/signal.c
new file mode 100644
index 0000000000..2a5378e16e
--- /dev/null
+++ b/linux-user/sh4/signal.c
@@ -0,0 +1,343 @@
+/*
+ * Emulation of Linux signals
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "target_signal.h"
+#include "signal-common.h"
+#include "linux-user/trace.h"
+
+/*
+ * code and data structures from linux kernel:
+ * include/asm-sh/sigcontext.h
+ * arch/sh/kernel/signal.c
+ */
+
+struct target_sigcontext {
+ target_ulong oldmask;
+
+ /* CPU registers */
+ target_ulong sc_gregs[16];
+ target_ulong sc_pc;
+ target_ulong sc_pr;
+ target_ulong sc_sr;
+ target_ulong sc_gbr;
+ target_ulong sc_mach;
+ target_ulong sc_macl;
+
+ /* FPU registers */
+ target_ulong sc_fpregs[16];
+ target_ulong sc_xfpregs[16];
+ unsigned int sc_fpscr;
+ unsigned int sc_fpul;
+ unsigned int sc_ownedfp;
+};
+
+struct target_sigframe
+{
+ struct target_sigcontext sc;
+ target_ulong extramask[TARGET_NSIG_WORDS-1];
+ uint16_t retcode[3];
+};
+
+
+struct target_ucontext {
+ target_ulong tuc_flags;
+ struct target_ucontext *tuc_link;
+ target_stack_t tuc_stack;
+ struct target_sigcontext tuc_mcontext;
+ target_sigset_t tuc_sigmask; /* mask last for extensibility */
+};
+
+struct target_rt_sigframe
+{
+ struct target_siginfo info;
+ struct target_ucontext uc;
+ uint16_t retcode[3];
+};
+
+
+#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
+#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
+
+static abi_ulong get_sigframe(struct target_sigaction *ka,
+ unsigned long sp, size_t frame_size)
+{
+ sp = target_sigsp(sp, ka);
+
+ return (sp - frame_size) & -8ul;
+}
+
+/* Notice when we're in the middle of a gUSA region and reset.
+ Note that this will only occur for !parallel_cpus, as we will
+ translate such sequences differently in a parallel context. */
+static void unwind_gusa(CPUSH4State *regs)
+{
+ /* If the stack pointer is sufficiently negative, and we haven't
+ completed the sequence, then reset to the entry to the region. */
+ /* ??? The SH4 kernel checks for and address above 0xC0000000.
+ However, the page mappings in qemu linux-user aren't as restricted
+ and we wind up with the normal stack mapped above 0xF0000000.
+ That said, there is no reason why the kernel should be allowing
+ a gUSA region that spans 1GB. Use a tighter check here, for what
+ can actually be enabled by the immediate move. */
+ if (regs->gregs[15] >= -128u && regs->pc < regs->gregs[0]) {
+ /* Reset the PC to before the gUSA region, as computed from
+ R0 = region end, SP = -(region size), plus one more for the
+ insn that actually initializes SP to the region size. */
+ regs->pc = regs->gregs[0] + regs->gregs[15] - 2;
+
+ /* Reset the SP to the saved version in R1. */
+ regs->gregs[15] = regs->gregs[1];
+ }
+}
+
+static void setup_sigcontext(struct target_sigcontext *sc,
+ CPUSH4State *regs, unsigned long mask)
+{
+ int i;
+
+#define COPY(x) __put_user(regs->x, &sc->sc_##x)
+ COPY(gregs[0]); COPY(gregs[1]);
+ COPY(gregs[2]); COPY(gregs[3]);
+ COPY(gregs[4]); COPY(gregs[5]);
+ COPY(gregs[6]); COPY(gregs[7]);
+ COPY(gregs[8]); COPY(gregs[9]);
+ COPY(gregs[10]); COPY(gregs[11]);
+ COPY(gregs[12]); COPY(gregs[13]);
+ COPY(gregs[14]); COPY(gregs[15]);
+ COPY(gbr); COPY(mach);
+ COPY(macl); COPY(pr);
+ COPY(sr); COPY(pc);
+#undef COPY
+
+ for (i=0; i<16; i++) {
+ __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
+ }
+ __put_user(regs->fpscr, &sc->sc_fpscr);
+ __put_user(regs->fpul, &sc->sc_fpul);
+
+ /* non-iBCS2 extensions.. */
+ __put_user(mask, &sc->oldmask);
+}
+
+static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc)
+{
+ int i;
+
+#define COPY(x) __get_user(regs->x, &sc->sc_##x)
+ COPY(gregs[0]); COPY(gregs[1]);
+ COPY(gregs[2]); COPY(gregs[3]);
+ COPY(gregs[4]); COPY(gregs[5]);
+ COPY(gregs[6]); COPY(gregs[7]);
+ COPY(gregs[8]); COPY(gregs[9]);
+ COPY(gregs[10]); COPY(gregs[11]);
+ COPY(gregs[12]); COPY(gregs[13]);
+ COPY(gregs[14]); COPY(gregs[15]);
+ COPY(gbr); COPY(mach);
+ COPY(macl); COPY(pr);
+ COPY(sr); COPY(pc);
+#undef COPY
+
+ for (i=0; i<16; i++) {
+ __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
+ }
+ __get_user(regs->fpscr, &sc->sc_fpscr);
+ __get_user(regs->fpul, &sc->sc_fpul);
+
+ regs->tra = -1; /* disable syscall checks */
+ regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK);
+}
+
+void setup_frame(int sig, struct target_sigaction *ka,
+ target_sigset_t *set, CPUSH4State *regs)
+{
+ struct target_sigframe *frame;
+ abi_ulong frame_addr;
+ int i;
+
+ unwind_gusa(regs);
+
+ frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
+ trace_user_setup_frame(regs, frame_addr);
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+ goto give_sigsegv;
+ }
+
+ setup_sigcontext(&frame->sc, regs, set->sig[0]);
+
+ for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
+ __put_user(set->sig[i + 1], &frame->extramask[i]);
+ }
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ if (ka->sa_flags & TARGET_SA_RESTORER) {
+ regs->pr = (unsigned long) ka->sa_restorer;
+ } else {
+ /* Generate return code (system call to sigreturn) */
+ abi_ulong retcode_addr = frame_addr +
+ offsetof(struct target_sigframe, retcode);
+ __put_user(MOVW(2), &frame->retcode[0]);
+ __put_user(TRAP_NOARG, &frame->retcode[1]);
+ __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
+ regs->pr = (unsigned long) retcode_addr;
+ }
+
+ /* Set up registers for signal handler */
+ regs->gregs[15] = frame_addr;
+ regs->gregs[4] = sig; /* Arg for signal handler */
+ regs->gregs[5] = 0;
+ regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
+ regs->pc = (unsigned long) ka->_sa_handler;
+ regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK);
+
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+
+give_sigsegv:
+ unlock_user_struct(frame, frame_addr, 1);
+ force_sigsegv(sig);
+}
+
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPUSH4State *regs)
+{
+ struct target_rt_sigframe *frame;
+ abi_ulong frame_addr;
+ int i;
+
+ unwind_gusa(regs);
+
+ frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
+ trace_user_setup_rt_frame(regs, frame_addr);
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+ goto give_sigsegv;
+ }
+
+ tswap_siginfo(&frame->info, info);
+
+ /* Create the ucontext. */
+ __put_user(0, &frame->uc.tuc_flags);
+ __put_user(0, (unsigned long *)&frame->uc.tuc_link);
+ target_save_altstack(&frame->uc.tuc_stack, regs);
+ setup_sigcontext(&frame->uc.tuc_mcontext,
+ regs, set->sig[0]);
+ for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+ __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
+ }
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ if (ka->sa_flags & TARGET_SA_RESTORER) {
+ regs->pr = (unsigned long) ka->sa_restorer;
+ } else {
+ /* Generate return code (system call to sigreturn) */
+ abi_ulong retcode_addr = frame_addr +
+ offsetof(struct target_rt_sigframe, retcode);
+ __put_user(MOVW(2), &frame->retcode[0]);
+ __put_user(TRAP_NOARG, &frame->retcode[1]);
+ __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
+ regs->pr = (unsigned long) retcode_addr;
+ }
+
+ /* Set up registers for signal handler */
+ regs->gregs[15] = frame_addr;
+ regs->gregs[4] = sig; /* Arg for signal handler */
+ regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
+ regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
+ regs->pc = (unsigned long) ka->_sa_handler;
+ regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK);
+
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+
+give_sigsegv:
+ unlock_user_struct(frame, frame_addr, 1);
+ force_sigsegv(sig);
+}
+
+long do_sigreturn(CPUSH4State *regs)
+{
+ struct target_sigframe *frame;
+ abi_ulong frame_addr;
+ sigset_t blocked;
+ target_sigset_t target_set;
+ int i;
+ int err = 0;
+
+ frame_addr = regs->gregs[15];
+ trace_user_do_sigreturn(regs, frame_addr);
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+ goto badframe;
+ }
+
+ __get_user(target_set.sig[0], &frame->sc.oldmask);
+ for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+ __get_user(target_set.sig[i], &frame->extramask[i - 1]);
+ }
+
+ if (err)
+ goto badframe;
+
+ target_to_host_sigset_internal(&blocked, &target_set);
+ set_sigmask(&blocked);
+
+ restore_sigcontext(regs, &frame->sc);
+
+ unlock_user_struct(frame, frame_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+
+badframe:
+ unlock_user_struct(frame, frame_addr, 0);
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
+
+long do_rt_sigreturn(CPUSH4State *regs)
+{
+ struct target_rt_sigframe *frame;
+ abi_ulong frame_addr;
+ sigset_t blocked;
+
+ frame_addr = regs->gregs[15];
+ trace_user_do_rt_sigreturn(regs, frame_addr);
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+ goto badframe;
+ }
+
+ target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
+ set_sigmask(&blocked);
+
+ restore_sigcontext(regs, &frame->uc.tuc_mcontext);
+
+ if (do_sigaltstack(frame_addr +
+ offsetof(struct target_rt_sigframe, uc.tuc_stack),
+ 0, get_sp_from_cpustate(regs)) == -EFAULT) {
+ goto badframe;
+ }
+
+ unlock_user_struct(frame, frame_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+
+badframe:
+ unlock_user_struct(frame, frame_addr, 0);
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
diff --git a/linux-user/sh4/target_signal.h b/linux-user/sh4/target_signal.h
index cbf23b6a31..e7b18a6db4 100644
--- a/linux-user/sh4/target_signal.h
+++ b/linux-user/sh4/target_signal.h
@@ -26,5 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUSH4State *state)
return state->gregs[15];
}
-
+#define TARGET_ARCH_HAS_SETUP_FRAME
#endif /* SH4_TARGET_SIGNAL_H */
diff --git a/linux-user/signal-common.h b/linux-user/signal-common.h
new file mode 100644
index 0000000000..51030a9306
--- /dev/null
+++ b/linux-user/signal-common.h
@@ -0,0 +1,50 @@
+/*
+ * Emulation of Linux signals
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SIGNAL_COMMON_H
+#define SIGNAL_COMMON_H
+extern struct target_sigaltstack target_sigaltstack_used;
+
+int on_sig_stack(unsigned long sp);
+int sas_ss_flags(unsigned long sp);
+abi_ulong target_sigsp(abi_ulong sp, struct target_sigaction *ka);
+void target_save_altstack(target_stack_t *uss, CPUArchState *env);
+
+static inline void target_sigemptyset(target_sigset_t *set)
+{
+ memset(set, 0, sizeof(*set));
+}
+
+void host_to_target_sigset_internal(target_sigset_t *d,
+ const sigset_t *s);
+void target_to_host_sigset_internal(sigset_t *d,
+ const target_sigset_t *s);
+void tswap_siginfo(target_siginfo_t *tinfo,
+ const target_siginfo_t *info);
+void set_sigmask(const sigset_t *set);
+void force_sig(int sig);
+void force_sigsegv(int oldsig);
+#if defined(TARGET_ARCH_HAS_SETUP_FRAME)
+void setup_frame(int sig, struct target_sigaction *ka,
+ target_sigset_t *set, CPUArchState *env);
+#endif
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPUArchState *env);
+#endif
diff --git a/linux-user/signal.c b/linux-user/signal.c
index b283270391..01de433e3a 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -25,8 +25,9 @@
#include "qemu-common.h"
#include "target_signal.h"
#include "trace.h"
+#include "signal-common.h"
-static struct target_sigaltstack target_sigaltstack_used = {
+struct target_sigaltstack target_sigaltstack_used = {
.ss_sp = 0,
.ss_size = 0,
.ss_flags = TARGET_SS_DISABLE,
@@ -82,18 +83,6 @@ static uint8_t host_to_target_signal_table[_NSIG] = {
};
static uint8_t target_to_host_signal_table[_NSIG];
-static inline int on_sig_stack(unsigned long sp)
-{
- return (sp - target_sigaltstack_used.ss_sp
- < target_sigaltstack_used.ss_size);
-}
-
-static inline int sas_ss_flags(unsigned long sp)
-{
- return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
- : on_sig_stack(sp) ? SS_ONSTACK : 0);
-}
-
int host_to_target_signal(int sig)
{
if (sig < 0 || sig >= _NSIG)
@@ -108,11 +97,6 @@ int target_to_host_signal(int sig)
return target_to_host_signal_table[sig];
}
-static inline void target_sigemptyset(target_sigset_t *set)
-{
- memset(set, 0, sizeof(*set));
-}
-
static inline void target_sigaddset(target_sigset_t *set, int signum)
{
signum--;
@@ -127,8 +111,8 @@ static inline int target_sigismember(const target_sigset_t *set, int signum)
return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0);
}
-static void host_to_target_sigset_internal(target_sigset_t *d,
- const sigset_t *s)
+void host_to_target_sigset_internal(target_sigset_t *d,
+ const sigset_t *s)
{
int i;
target_sigemptyset(d);
@@ -149,8 +133,8 @@ void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
d->sig[i] = tswapal(d1.sig[i]);
}
-static void target_to_host_sigset_internal(sigset_t *d,
- const target_sigset_t *s)
+void target_to_host_sigset_internal(sigset_t *d,
+ const target_sigset_t *s)
{
int i;
sigemptyset(d);
@@ -257,7 +241,7 @@ int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
/* Just set the guest's signal mask to the specified value; the
* caller is assumed to have called block_signals() already.
*/
-static void set_sigmask(const sigset_t *set)
+void set_sigmask(const sigset_t *set)
{
TaskState *ts = (TaskState *)thread_cpu->opaque;
@@ -265,6 +249,38 @@ static void set_sigmask(const sigset_t *set)
}
#endif
+/* sigaltstack management */
+
+int on_sig_stack(unsigned long sp)
+{
+ return (sp - target_sigaltstack_used.ss_sp
+ < target_sigaltstack_used.ss_size);
+}
+
+int sas_ss_flags(unsigned long sp)
+{
+ return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
+ : on_sig_stack(sp) ? SS_ONSTACK : 0);
+}
+
+abi_ulong target_sigsp(abi_ulong sp, struct target_sigaction *ka)
+{
+ /*
+ * This is the X/Open sanctioned signal stack switching.
+ */
+ if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
+ return target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
+ }
+ return sp;
+}
+
+void target_save_altstack(target_stack_t *uss, CPUArchState *env)
+{
+ __put_user(target_sigaltstack_used.ss_sp, &uss->ss_sp);
+ __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &uss->ss_flags);
+ __put_user(target_sigaltstack_used.ss_size, &uss->ss_size);
+}
+
/* siginfo conversion */
static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
@@ -344,8 +360,8 @@ static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
tinfo->si_code = deposit32(si_code, 16, 16, si_type);
}
-static void tswap_siginfo(target_siginfo_t *tinfo,
- const target_siginfo_t *info)
+void tswap_siginfo(target_siginfo_t *tinfo,
+ const target_siginfo_t *info)
{
int si_type = extract32(info->si_code, 16, 16);
int si_code = sextract32(info->si_code, 0, 16);
@@ -515,7 +531,7 @@ void signal_init(void)
* also forces the signal to "not blocked, not ignored", but for QEMU
* that work is done in process_pending_signals().
*/
-static void force_sig(int sig)
+void force_sig(int sig)
{
CPUState *cpu = thread_cpu;
CPUArchState *env = cpu->env_ptr;
@@ -534,7 +550,7 @@ static void force_sig(int sig)
* at the point of failure.
*/
#if !defined(TARGET_RISCV)
-static void force_sigsegv(int oldsig)
+void force_sigsegv(int oldsig)
{
if (oldsig == SIGSEGV) {
/* Make sure we don't try to deliver the signal again; this will
@@ -819,6493 +835,6 @@ int do_sigaction(int sig, const struct target_sigaction *act,
return ret;
}
-#if defined(TARGET_I386)
-/* from the Linux kernel - /arch/x86/include/uapi/asm/sigcontext.h */
-
-struct target_fpreg {
- uint16_t significand[4];
- uint16_t exponent;
-};
-
-struct target_fpxreg {
- uint16_t significand[4];
- uint16_t exponent;
- uint16_t padding[3];
-};
-
-struct target_xmmreg {
- uint32_t element[4];
-};
-
-struct target_fpstate_32 {
- /* Regular FPU environment */
- uint32_t cw;
- uint32_t sw;
- uint32_t tag;
- uint32_t ipoff;
- uint32_t cssel;
- uint32_t dataoff;
- uint32_t datasel;
- struct target_fpreg st[8];
- uint16_t status;
- uint16_t magic; /* 0xffff = regular FPU data only */
-
- /* FXSR FPU environment */
- uint32_t _fxsr_env[6]; /* FXSR FPU env is ignored */
- uint32_t mxcsr;
- uint32_t reserved;
- struct target_fpxreg fxsr_st[8]; /* FXSR FPU reg data is ignored */
- struct target_xmmreg xmm[8];
- uint32_t padding[56];
-};
-
-struct target_fpstate_64 {
- /* FXSAVE format */
- uint16_t cw;
- uint16_t sw;
- uint16_t twd;
- uint16_t fop;
- uint64_t rip;
- uint64_t rdp;
- uint32_t mxcsr;
- uint32_t mxcsr_mask;
- uint32_t st_space[32];
- uint32_t xmm_space[64];
- uint32_t reserved[24];
-};
-
-#ifndef TARGET_X86_64
-# define target_fpstate target_fpstate_32
-#else
-# define target_fpstate target_fpstate_64
-#endif
-
-struct target_sigcontext_32 {
- uint16_t gs, __gsh;
- uint16_t fs, __fsh;
- uint16_t es, __esh;
- uint16_t ds, __dsh;
- uint32_t edi;
- uint32_t esi;
- uint32_t ebp;
- uint32_t esp;
- uint32_t ebx;
- uint32_t edx;
- uint32_t ecx;
- uint32_t eax;
- uint32_t trapno;
- uint32_t err;
- uint32_t eip;
- uint16_t cs, __csh;
- uint32_t eflags;
- uint32_t esp_at_signal;
- uint16_t ss, __ssh;
- uint32_t fpstate; /* pointer */
- uint32_t oldmask;
- uint32_t cr2;
-};
-
-struct target_sigcontext_64 {
- uint64_t r8;
- uint64_t r9;
- uint64_t r10;
- uint64_t r11;
- uint64_t r12;
- uint64_t r13;
- uint64_t r14;
- uint64_t r15;
-
- uint64_t rdi;
- uint64_t rsi;
- uint64_t rbp;
- uint64_t rbx;
- uint64_t rdx;
- uint64_t rax;
- uint64_t rcx;
- uint64_t rsp;
- uint64_t rip;
-
- uint64_t eflags;
-
- uint16_t cs;
- uint16_t gs;
- uint16_t fs;
- uint16_t ss;
-
- uint64_t err;
- uint64_t trapno;
- uint64_t oldmask;
- uint64_t cr2;
-
- uint64_t fpstate; /* pointer */
- uint64_t padding[8];
-};
-
-#ifndef TARGET_X86_64
-# define target_sigcontext target_sigcontext_32
-#else
-# define target_sigcontext target_sigcontext_64
-#endif
-
-/* see Linux/include/uapi/asm-generic/ucontext.h */
-struct target_ucontext {
- abi_ulong tuc_flags;
- abi_ulong tuc_link;
- target_stack_t tuc_stack;
- struct target_sigcontext tuc_mcontext;
- target_sigset_t tuc_sigmask; /* mask last for extensibility */
-};
-
-#ifndef TARGET_X86_64
-struct sigframe {
- abi_ulong pretcode;
- int sig;
- struct target_sigcontext sc;
- struct target_fpstate fpstate;
- abi_ulong extramask[TARGET_NSIG_WORDS-1];
- char retcode[8];
-};
-
-struct rt_sigframe {
- abi_ulong pretcode;
- int sig;
- abi_ulong pinfo;
- abi_ulong puc;
- struct target_siginfo info;
- struct target_ucontext uc;
- struct target_fpstate fpstate;
- char retcode[8];
-};
-
-#else
-
-struct rt_sigframe {
- abi_ulong pretcode;
- struct target_ucontext uc;
- struct target_siginfo info;
- struct target_fpstate fpstate;
-};
-
-#endif
-
-/*
- * Set up a signal frame.
- */
-
-/* XXX: save x87 state */
-static void setup_sigcontext(struct target_sigcontext *sc,
- struct target_fpstate *fpstate, CPUX86State *env, abi_ulong mask,
- abi_ulong fpstate_addr)
-{
- CPUState *cs = CPU(x86_env_get_cpu(env));
-#ifndef TARGET_X86_64
- uint16_t magic;
-
- /* already locked in setup_frame() */
- __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
- __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
- __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
- __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
- __put_user(env->regs[R_EDI], &sc->edi);
- __put_user(env->regs[R_ESI], &sc->esi);
- __put_user(env->regs[R_EBP], &sc->ebp);
- __put_user(env->regs[R_ESP], &sc->esp);
- __put_user(env->regs[R_EBX], &sc->ebx);
- __put_user(env->regs[R_EDX], &sc->edx);
- __put_user(env->regs[R_ECX], &sc->ecx);
- __put_user(env->regs[R_EAX], &sc->eax);
- __put_user(cs->exception_index, &sc->trapno);
- __put_user(env->error_code, &sc->err);
- __put_user(env->eip, &sc->eip);
- __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
- __put_user(env->eflags, &sc->eflags);
- __put_user(env->regs[R_ESP], &sc->esp_at_signal);
- __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
-
- cpu_x86_fsave(env, fpstate_addr, 1);
- fpstate->status = fpstate->sw;
- magic = 0xffff;
- __put_user(magic, &fpstate->magic);
- __put_user(fpstate_addr, &sc->fpstate);
-
- /* non-iBCS2 extensions.. */
- __put_user(mask, &sc->oldmask);
- __put_user(env->cr[2], &sc->cr2);
-#else
- __put_user(env->regs[R_EDI], &sc->rdi);
- __put_user(env->regs[R_ESI], &sc->rsi);
- __put_user(env->regs[R_EBP], &sc->rbp);
- __put_user(env->regs[R_ESP], &sc->rsp);
- __put_user(env->regs[R_EBX], &sc->rbx);
- __put_user(env->regs[R_EDX], &sc->rdx);
- __put_user(env->regs[R_ECX], &sc->rcx);
- __put_user(env->regs[R_EAX], &sc->rax);
-
- __put_user(env->regs[8], &sc->r8);
- __put_user(env->regs[9], &sc->r9);
- __put_user(env->regs[10], &sc->r10);
- __put_user(env->regs[11], &sc->r11);
- __put_user(env->regs[12], &sc->r12);
- __put_user(env->regs[13], &sc->r13);
- __put_user(env->regs[14], &sc->r14);
- __put_user(env->regs[15], &sc->r15);
-
- __put_user(cs->exception_index, &sc->trapno);
- __put_user(env->error_code, &sc->err);
- __put_user(env->eip, &sc->rip);
-
- __put_user(env->eflags, &sc->eflags);
- __put_user(env->segs[R_CS].selector, &sc->cs);
- __put_user((uint16_t)0, &sc->gs);
- __put_user((uint16_t)0, &sc->fs);
- __put_user(env->segs[R_SS].selector, &sc->ss);
-
- __put_user(mask, &sc->oldmask);
- __put_user(env->cr[2], &sc->cr2);
-
- /* fpstate_addr must be 16 byte aligned for fxsave */
- assert(!(fpstate_addr & 0xf));
-
- cpu_x86_fxsave(env, fpstate_addr);
- __put_user(fpstate_addr, &sc->fpstate);
-#endif
-}
-
-/*
- * Determine which stack to use..
- */
-
-static inline abi_ulong
-get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
-{
- unsigned long esp;
-
- /* Default to using normal stack */
- esp = env->regs[R_ESP];
-#ifdef TARGET_X86_64
- esp -= 128; /* this is the redzone */
-#endif
-
- /* This is the X/Open sanctioned signal stack switching. */
- if (ka->sa_flags & TARGET_SA_ONSTACK) {
- if (sas_ss_flags(esp) == 0) {
- esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
- }
- } else {
-#ifndef TARGET_X86_64
- /* This is the legacy signal stack switching. */
- if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
- !(ka->sa_flags & TARGET_SA_RESTORER) &&
- ka->sa_restorer) {
- esp = (unsigned long) ka->sa_restorer;
- }
-#endif
- }
-
-#ifndef TARGET_X86_64
- return (esp - frame_size) & -8ul;
-#else
- return ((esp - frame_size) & (~15ul)) - 8;
-#endif
-}
-
-#ifndef TARGET_X86_64
-/* compare linux/arch/i386/kernel/signal.c:setup_frame() */
-static void setup_frame(int sig, struct target_sigaction *ka,
- target_sigset_t *set, CPUX86State *env)
-{
- abi_ulong frame_addr;
- struct sigframe *frame;
- int i;
-
- frame_addr = get_sigframe(ka, env, sizeof(*frame));
- trace_user_setup_frame(env, frame_addr);
-
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
- goto give_sigsegv;
-
- __put_user(sig, &frame->sig);
-
- setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
- frame_addr + offsetof(struct sigframe, fpstate));
-
- for(i = 1; i < TARGET_NSIG_WORDS; i++) {
- __put_user(set->sig[i], &frame->extramask[i - 1]);
- }
-
- /* Set up to return from userspace. If provided, use a stub
- already in userspace. */
- if (ka->sa_flags & TARGET_SA_RESTORER) {
- __put_user(ka->sa_restorer, &frame->pretcode);
- } else {
- uint16_t val16;
- abi_ulong retcode_addr;
- retcode_addr = frame_addr + offsetof(struct sigframe, retcode);
- __put_user(retcode_addr, &frame->pretcode);
- /* This is popl %eax ; movl $,%eax ; int $0x80 */
- val16 = 0xb858;
- __put_user(val16, (uint16_t *)(frame->retcode+0));
- __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
- val16 = 0x80cd;
- __put_user(val16, (uint16_t *)(frame->retcode+6));
- }
-
- /* Set up registers for signal handler */
- env->regs[R_ESP] = frame_addr;
- env->eip = ka->_sa_handler;
-
- cpu_x86_load_seg(env, R_DS, __USER_DS);
- cpu_x86_load_seg(env, R_ES, __USER_DS);
- cpu_x86_load_seg(env, R_SS, __USER_DS);
- cpu_x86_load_seg(env, R_CS, __USER_CS);
- env->eflags &= ~TF_MASK;
-
- unlock_user_struct(frame, frame_addr, 1);
-
- return;
-
-give_sigsegv:
- force_sigsegv(sig);
-}
-#endif
-
-/* compare linux/arch/x86/kernel/signal.c:setup_rt_frame() */
-static void setup_rt_frame(int sig, struct target_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUX86State *env)
-{
- abi_ulong frame_addr;
-#ifndef TARGET_X86_64
- abi_ulong addr;
-#endif
- struct rt_sigframe *frame;
- int i;
-
- frame_addr = get_sigframe(ka, env, sizeof(*frame));
- trace_user_setup_rt_frame(env, frame_addr);
-
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
- goto give_sigsegv;
-
- /* These fields are only in rt_sigframe on 32 bit */
-#ifndef TARGET_X86_64
- __put_user(sig, &frame->sig);
- addr = frame_addr + offsetof(struct rt_sigframe, info);
- __put_user(addr, &frame->pinfo);
- addr = frame_addr + offsetof(struct rt_sigframe, uc);
- __put_user(addr, &frame->puc);
-#endif
- if (ka->sa_flags & TARGET_SA_SIGINFO) {
- tswap_siginfo(&frame->info, info);
- }
-
- /* Create the ucontext. */
- __put_user(0, &frame->uc.tuc_flags);
- __put_user(0, &frame->uc.tuc_link);
- __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
- __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
- &frame->uc.tuc_stack.ss_flags);
- __put_user(target_sigaltstack_used.ss_size,
- &frame->uc.tuc_stack.ss_size);
- setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env,
- set->sig[0], frame_addr + offsetof(struct rt_sigframe, fpstate));
-
- for(i = 0; i < TARGET_NSIG_WORDS; i++) {
- __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
- }
-
- /* Set up to return from userspace. If provided, use a stub
- already in userspace. */
-#ifndef TARGET_X86_64
- if (ka->sa_flags & TARGET_SA_RESTORER) {
- __put_user(ka->sa_restorer, &frame->pretcode);
- } else {
- uint16_t val16;
- addr = frame_addr + offsetof(struct rt_sigframe, retcode);
- __put_user(addr, &frame->pretcode);
- /* This is movl $,%eax ; int $0x80 */
- __put_user(0xb8, (char *)(frame->retcode+0));
- __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
- val16 = 0x80cd;
- __put_user(val16, (uint16_t *)(frame->retcode+5));
- }
-#else
- /* XXX: Would be slightly better to return -EFAULT here if test fails
- assert(ka->sa_flags & TARGET_SA_RESTORER); */
- __put_user(ka->sa_restorer, &frame->pretcode);
-#endif
-
- /* Set up registers for signal handler */
- env->regs[R_ESP] = frame_addr;
- env->eip = ka->_sa_handler;
-
-#ifndef TARGET_X86_64
- env->regs[R_EAX] = sig;
- env->regs[R_EDX] = (unsigned long)&frame->info;
- env->regs[R_ECX] = (unsigned long)&frame->uc;
-#else
- env->regs[R_EAX] = 0;
- env->regs[R_EDI] = sig;
- env->regs[R_ESI] = (unsigned long)&frame->info;
- env->regs[R_EDX] = (unsigned long)&frame->uc;
-#endif
-
- cpu_x86_load_seg(env, R_DS, __USER_DS);
- cpu_x86_load_seg(env, R_ES, __USER_DS);
- cpu_x86_load_seg(env, R_CS, __USER_CS);
- cpu_x86_load_seg(env, R_SS, __USER_DS);
- env->eflags &= ~TF_MASK;
-
- unlock_user_struct(frame, frame_addr, 1);
-
- return;
-
-give_sigsegv:
- force_sigsegv(sig);
-}
-
-static int
-restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc)
-{
- unsigned int err = 0;
- abi_ulong fpstate_addr;
- unsigned int tmpflags;
-
-#ifndef TARGET_X86_64
- cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
- cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
- cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
- cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
-
- env->regs[R_EDI] = tswapl(sc->edi);
- env->regs[R_ESI] = tswapl(sc->esi);
- env->regs[R_EBP] = tswapl(sc->ebp);
- env->regs[R_ESP] = tswapl(sc->esp);
- env->regs[R_EBX] = tswapl(sc->ebx);
- env->regs[R_EDX] = tswapl(sc->edx);
- env->regs[R_ECX] = tswapl(sc->ecx);
- env->regs[R_EAX] = tswapl(sc->eax);
-
- env->eip = tswapl(sc->eip);
-#else
- env->regs[8] = tswapl(sc->r8);
- env->regs[9] = tswapl(sc->r9);
- env->regs[10] = tswapl(sc->r10);
- env->regs[11] = tswapl(sc->r11);
- env->regs[12] = tswapl(sc->r12);
- env->regs[13] = tswapl(sc->r13);
- env->regs[14] = tswapl(sc->r14);
- env->regs[15] = tswapl(sc->r15);
-
- env->regs[R_EDI] = tswapl(sc->rdi);
- env->regs[R_ESI] = tswapl(sc->rsi);
- env->regs[R_EBP] = tswapl(sc->rbp);
- env->regs[R_EBX] = tswapl(sc->rbx);
- env->regs[R_EDX] = tswapl(sc->rdx);
- env->regs[R_EAX] = tswapl(sc->rax);
- env->regs[R_ECX] = tswapl(sc->rcx);
- env->regs[R_ESP] = tswapl(sc->rsp);
-
- env->eip = tswapl(sc->rip);
-#endif
-
- cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
- cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
-
- tmpflags = tswapl(sc->eflags);
- env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
- // regs->orig_eax = -1; /* disable syscall checks */
-
- fpstate_addr = tswapl(sc->fpstate);
- if (fpstate_addr != 0) {
- if (!access_ok(VERIFY_READ, fpstate_addr,
- sizeof(struct target_fpstate)))
- goto badframe;
-#ifndef TARGET_X86_64
- cpu_x86_frstor(env, fpstate_addr, 1);
-#else
- cpu_x86_fxrstor(env, fpstate_addr);
-#endif
- }
-
- return err;
-badframe:
- return 1;
-}
-
-/* Note: there is no sigreturn on x86_64, there is only rt_sigreturn */
-#ifndef TARGET_X86_64
-long do_sigreturn(CPUX86State *env)
-{
- struct sigframe *frame;
- abi_ulong frame_addr = env->regs[R_ESP] - 8;
- target_sigset_t target_set;
- sigset_t set;
- int i;
-
- trace_user_do_sigreturn(env, frame_addr);
- if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
- goto badframe;
- /* set blocked signals */
- __get_user(target_set.sig[0], &frame->sc.oldmask);
- for(i = 1; i < TARGET_NSIG_WORDS; i++) {
- __get_user(target_set.sig[i], &frame->extramask[i - 1]);
- }
-
- target_to_host_sigset_internal(&set, &target_set);
- set_sigmask(&set);
-
- /* restore registers */
- if (restore_sigcontext(env, &frame->sc))
- goto badframe;
- unlock_user_struct(frame, frame_addr, 0);
- return -TARGET_QEMU_ESIGRETURN;
-
-badframe:
- unlock_user_struct(frame, frame_addr, 0);
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-#endif
-
-long do_rt_sigreturn(CPUX86State *env)
-{
- abi_ulong frame_addr;
- struct rt_sigframe *frame;
- sigset_t set;
-
- frame_addr = env->regs[R_ESP] - sizeof(abi_ulong);
- trace_user_do_rt_sigreturn(env, frame_addr);
- if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
- goto badframe;
- target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
- set_sigmask(&set);
-
- if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
- goto badframe;
- }
-
- if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
- get_sp_from_cpustate(env)) == -EFAULT) {
- goto badframe;
- }
-
- unlock_user_struct(frame, frame_addr, 0);
- return -TARGET_QEMU_ESIGRETURN;
-
-badframe:
- unlock_user_struct(frame, frame_addr, 0);
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-
-#elif defined(TARGET_AARCH64)
-
-struct target_sigcontext {
- uint64_t fault_address;
- /* AArch64 registers */
- uint64_t regs[31];
- uint64_t sp;
- uint64_t pc;
- uint64_t pstate;
- /* 4K reserved for FP/SIMD state and future expansion */
- char __reserved[4096] __attribute__((__aligned__(16)));
-};
-
-struct target_ucontext {
- abi_ulong tuc_flags;
- abi_ulong tuc_link;
- target_stack_t tuc_stack;
- target_sigset_t tuc_sigmask;
- /* glibc uses a 1024-bit sigset_t */
- char __unused[1024 / 8 - sizeof(target_sigset_t)];
- /* last for future expansion */
- struct target_sigcontext tuc_mcontext;
-};
-
-/*
- * Header to be used at the beginning of structures extending the user
- * context. Such structures must be placed after the rt_sigframe on the stack
- * and be 16-byte aligned. The last structure must be a dummy one with the
- * magic and size set to 0.
- */
-struct target_aarch64_ctx {
- uint32_t magic;
- uint32_t size;
-};
-
-#define TARGET_FPSIMD_MAGIC 0x46508001
-
-struct target_fpsimd_context {
- struct target_aarch64_ctx head;
- uint32_t fpsr;
- uint32_t fpcr;
- uint64_t vregs[32 * 2]; /* really uint128_t vregs[32] */
-};
-
-#define TARGET_EXTRA_MAGIC 0x45585401
-
-struct target_extra_context {
- struct target_aarch64_ctx head;
- uint64_t datap; /* 16-byte aligned pointer to extra space cast to __u64 */
- uint32_t size; /* size in bytes of the extra space */
- uint32_t reserved[3];
-};
-
-#define TARGET_SVE_MAGIC 0x53564501
-
-struct target_sve_context {
- struct target_aarch64_ctx head;
- uint16_t vl;
- uint16_t reserved[3];
- /* The actual SVE data immediately follows. It is layed out
- * according to TARGET_SVE_SIG_{Z,P}REG_OFFSET, based off of
- * the original struct pointer.
- */
-};
-
-#define TARGET_SVE_VQ_BYTES 16
-
-#define TARGET_SVE_SIG_ZREG_SIZE(VQ) ((VQ) * TARGET_SVE_VQ_BYTES)
-#define TARGET_SVE_SIG_PREG_SIZE(VQ) ((VQ) * (TARGET_SVE_VQ_BYTES / 8))
-
-#define TARGET_SVE_SIG_REGS_OFFSET \
- QEMU_ALIGN_UP(sizeof(struct target_sve_context), TARGET_SVE_VQ_BYTES)
-#define TARGET_SVE_SIG_ZREG_OFFSET(VQ, N) \
- (TARGET_SVE_SIG_REGS_OFFSET + TARGET_SVE_SIG_ZREG_SIZE(VQ) * (N))
-#define TARGET_SVE_SIG_PREG_OFFSET(VQ, N) \
- (TARGET_SVE_SIG_ZREG_OFFSET(VQ, 32) + TARGET_SVE_SIG_PREG_SIZE(VQ) * (N))
-#define TARGET_SVE_SIG_FFR_OFFSET(VQ) \
- (TARGET_SVE_SIG_PREG_OFFSET(VQ, 16))
-#define TARGET_SVE_SIG_CONTEXT_SIZE(VQ) \
- (TARGET_SVE_SIG_PREG_OFFSET(VQ, 17))
-
-struct target_rt_sigframe {
- struct target_siginfo info;
- struct target_ucontext uc;
-};
-
-struct target_rt_frame_record {
- uint64_t fp;
- uint64_t lr;
- uint32_t tramp[2];
-};
-
-static void target_setup_general_frame(struct target_rt_sigframe *sf,
- CPUARMState *env, target_sigset_t *set)
-{
- int i;
-
- __put_user(0, &sf->uc.tuc_flags);
- __put_user(0, &sf->uc.tuc_link);
-
- __put_user(target_sigaltstack_used.ss_sp, &sf->uc.tuc_stack.ss_sp);
- __put_user(sas_ss_flags(env->xregs[31]), &sf->uc.tuc_stack.ss_flags);
- __put_user(target_sigaltstack_used.ss_size, &sf->uc.tuc_stack.ss_size);
-
- for (i = 0; i < 31; i++) {
- __put_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
- }
- __put_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
- __put_user(env->pc, &sf->uc.tuc_mcontext.pc);
- __put_user(pstate_read(env), &sf->uc.tuc_mcontext.pstate);
-
- __put_user(env->exception.vaddress, &sf->uc.tuc_mcontext.fault_address);
-
- for (i = 0; i < TARGET_NSIG_WORDS; i++) {
- __put_user(set->sig[i], &sf->uc.tuc_sigmask.sig[i]);
- }
-}
-
-static void target_setup_fpsimd_record(struct target_fpsimd_context *fpsimd,
- CPUARMState *env)
-{
- int i;
-
- __put_user(TARGET_FPSIMD_MAGIC, &fpsimd->head.magic);
- __put_user(sizeof(struct target_fpsimd_context), &fpsimd->head.size);
- __put_user(vfp_get_fpsr(env), &fpsimd->fpsr);
- __put_user(vfp_get_fpcr(env), &fpsimd->fpcr);
-
- for (i = 0; i < 32; i++) {
- uint64_t *q = aa64_vfp_qreg(env, i);
-#ifdef TARGET_WORDS_BIGENDIAN
- __put_user(q[0], &fpsimd->vregs[i * 2 + 1]);
- __put_user(q[1], &fpsimd->vregs[i * 2]);
-#else
- __put_user(q[0], &fpsimd->vregs[i * 2]);
- __put_user(q[1], &fpsimd->vregs[i * 2 + 1]);
-#endif
- }
-}
-
-static void target_setup_extra_record(struct target_extra_context *extra,
- uint64_t datap, uint32_t extra_size)
-{
- __put_user(TARGET_EXTRA_MAGIC, &extra->head.magic);
- __put_user(sizeof(struct target_extra_context), &extra->head.size);
- __put_user(datap, &extra->datap);
- __put_user(extra_size, &extra->size);
-}
-
-static void target_setup_end_record(struct target_aarch64_ctx *end)
-{
- __put_user(0, &end->magic);
- __put_user(0, &end->size);
-}
-
-static void target_setup_sve_record(struct target_sve_context *sve,
- CPUARMState *env, int vq, int size)
-{
- int i, j;
-
- __put_user(TARGET_SVE_MAGIC, &sve->head.magic);
- __put_user(size, &sve->head.size);
- __put_user(vq * TARGET_SVE_VQ_BYTES, &sve->vl);
-
- /* Note that SVE regs are stored as a byte stream, with each byte element
- * at a subsequent address. This corresponds to a little-endian store
- * of our 64-bit hunks.
- */
- for (i = 0; i < 32; ++i) {
- uint64_t *z = (void *)sve + TARGET_SVE_SIG_ZREG_OFFSET(vq, i);
- for (j = 0; j < vq * 2; ++j) {
- __put_user_e(env->vfp.zregs[i].d[j], z + j, le);
- }
- }
- for (i = 0; i <= 16; ++i) {
- uint16_t *p = (void *)sve + TARGET_SVE_SIG_PREG_OFFSET(vq, i);
- for (j = 0; j < vq; ++j) {
- uint64_t r = env->vfp.pregs[i].p[j >> 2];
- __put_user_e(r >> ((j & 3) * 16), p + j, le);
- }
- }
-}
-
-static void target_restore_general_frame(CPUARMState *env,
- struct target_rt_sigframe *sf)
-{
- sigset_t set;
- uint64_t pstate;
- int i;
-
- target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
- set_sigmask(&set);
-
- for (i = 0; i < 31; i++) {
- __get_user(env->xregs[i], &sf->uc.tuc_mcontext.regs[i]);
- }
-
- __get_user(env->xregs[31], &sf->uc.tuc_mcontext.sp);
- __get_user(env->pc, &sf->uc.tuc_mcontext.pc);
- __get_user(pstate, &sf->uc.tuc_mcontext.pstate);
- pstate_write(env, pstate);
-}
-
-static void target_restore_fpsimd_record(CPUARMState *env,
- struct target_fpsimd_context *fpsimd)
-{
- uint32_t fpsr, fpcr;
- int i;
-
- __get_user(fpsr, &fpsimd->fpsr);
- vfp_set_fpsr(env, fpsr);
- __get_user(fpcr, &fpsimd->fpcr);
- vfp_set_fpcr(env, fpcr);
-
- for (i = 0; i < 32; i++) {
- uint64_t *q = aa64_vfp_qreg(env, i);
-#ifdef TARGET_WORDS_BIGENDIAN
- __get_user(q[0], &fpsimd->vregs[i * 2 + 1]);
- __get_user(q[1], &fpsimd->vregs[i * 2]);
-#else
- __get_user(q[0], &fpsimd->vregs[i * 2]);
- __get_user(q[1], &fpsimd->vregs[i * 2 + 1]);
-#endif
- }
-}
-
-static void target_restore_sve_record(CPUARMState *env,
- struct target_sve_context *sve, int vq)
-{
- int i, j;
-
- /* Note that SVE regs are stored as a byte stream, with each byte element
- * at a subsequent address. This corresponds to a little-endian load
- * of our 64-bit hunks.
- */
- for (i = 0; i < 32; ++i) {
- uint64_t *z = (void *)sve + TARGET_SVE_SIG_ZREG_OFFSET(vq, i);
- for (j = 0; j < vq * 2; ++j) {
- __get_user_e(env->vfp.zregs[i].d[j], z + j, le);
- }
- }
- for (i = 0; i <= 16; ++i) {
- uint16_t *p = (void *)sve + TARGET_SVE_SIG_PREG_OFFSET(vq, i);
- for (j = 0; j < vq; ++j) {
- uint16_t r;
- __get_user_e(r, p + j, le);
- if (j & 3) {
- env->vfp.pregs[i].p[j >> 2] |= (uint64_t)r << ((j & 3) * 16);
- } else {
- env->vfp.pregs[i].p[j >> 2] = r;
- }
- }
- }
-}
-
-static int target_restore_sigframe(CPUARMState *env,
- struct target_rt_sigframe *sf)
-{
- struct target_aarch64_ctx *ctx, *extra = NULL;
- struct target_fpsimd_context *fpsimd = NULL;
- struct target_sve_context *sve = NULL;
- uint64_t extra_datap = 0;
- bool used_extra = false;
- bool err = false;
- int vq = 0, sve_size = 0;
-
- target_restore_general_frame(env, sf);
-
- ctx = (struct target_aarch64_ctx *)sf->uc.tuc_mcontext.__reserved;
- while (ctx) {
- uint32_t magic, size, extra_size;
-
- __get_user(magic, &ctx->magic);
- __get_user(size, &ctx->size);
- switch (magic) {
- case 0:
- if (size != 0) {
- err = true;
- goto exit;
- }
- if (used_extra) {
- ctx = NULL;
- } else {
- ctx = extra;
- used_extra = true;
- }
- continue;
-
- case TARGET_FPSIMD_MAGIC:
- if (fpsimd || size != sizeof(struct target_fpsimd_context)) {
- err = true;
- goto exit;
- }
- fpsimd = (struct target_fpsimd_context *)ctx;
- break;
-
- case TARGET_SVE_MAGIC:
- if (arm_feature(env, ARM_FEATURE_SVE)) {
- vq = (env->vfp.zcr_el[1] & 0xf) + 1;
- sve_size = QEMU_ALIGN_UP(TARGET_SVE_SIG_CONTEXT_SIZE(vq), 16);
- if (!sve && size == sve_size) {
- sve = (struct target_sve_context *)ctx;
- break;
- }
- }
- err = true;
- goto exit;
-
- case TARGET_EXTRA_MAGIC:
- if (extra || size != sizeof(struct target_extra_context)) {
- err = true;
- goto exit;
- }
- __get_user(extra_datap,
- &((struct target_extra_context *)ctx)->datap);
- __get_user(extra_size,
- &((struct target_extra_context *)ctx)->size);
- extra = lock_user(VERIFY_READ, extra_datap, extra_size, 0);
- break;
-
- default:
- /* Unknown record -- we certainly didn't generate it.
- * Did we in fact get out of sync?
- */
- err = true;
- goto exit;
- }
- ctx = (void *)ctx + size;
- }
-
- /* Require FPSIMD always. */
- if (fpsimd) {
- target_restore_fpsimd_record(env, fpsimd);
- } else {
- err = true;
- }
-
- /* SVE data, if present, overwrites FPSIMD data. */
- if (sve) {
- target_restore_sve_record(env, sve, vq);
- }
-
- exit:
- unlock_user(extra, extra_datap, 0);
- return err;
-}
-
-static abi_ulong get_sigframe(struct target_sigaction *ka,
- CPUARMState *env, int size)
-{
- abi_ulong sp;
-
- sp = env->xregs[31];
-
- /*
- * This is the X/Open sanctioned signal stack switching.
- */
- if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
- sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
- }
-
- sp = (sp - size) & ~15;
-
- return sp;
-}
-
-typedef struct {
- int total_size;
- int extra_base;
- int extra_size;
- int std_end_ofs;
- int extra_ofs;
- int extra_end_ofs;
-} target_sigframe_layout;
-
-static int alloc_sigframe_space(int this_size, target_sigframe_layout *l)
-{
- /* Make sure there will always be space for the end marker. */
- const int std_size = sizeof(struct target_rt_sigframe)
- - sizeof(struct target_aarch64_ctx);
- int this_loc = l->total_size;
-
- if (l->extra_base) {
- /* Once we have begun an extra space, all allocations go there. */
- l->extra_size += this_size;
- } else if (this_size + this_loc > std_size) {
- /* This allocation does not fit in the standard space. */
- /* Allocate the extra record. */
- l->extra_ofs = this_loc;
- l->total_size += sizeof(struct target_extra_context);
-
- /* Allocate the standard end record. */
- l->std_end_ofs = l->total_size;
- l->total_size += sizeof(struct target_aarch64_ctx);
-
- /* Allocate the requested record. */
- l->extra_base = this_loc = l->total_size;
- l->extra_size = this_size;
- }
- l->total_size += this_size;
-
- return this_loc;
-}
-
-static void target_setup_frame(int usig, struct target_sigaction *ka,
- target_siginfo_t *info, target_sigset_t *set,
- CPUARMState *env)
-{
- target_sigframe_layout layout = {
- /* Begin with the size pointing to the reserved space. */
- .total_size = offsetof(struct target_rt_sigframe,
- uc.tuc_mcontext.__reserved),
- };
- int fpsimd_ofs, fr_ofs, sve_ofs = 0, vq = 0, sve_size = 0;
- struct target_rt_sigframe *frame;
- struct target_rt_frame_record *fr;
- abi_ulong frame_addr, return_addr;
-
- /* FPSIMD record is always in the standard space. */
- fpsimd_ofs = alloc_sigframe_space(sizeof(struct target_fpsimd_context),
- &layout);
-
- /* SVE state needs saving only if it exists. */
- if (arm_feature(env, ARM_FEATURE_SVE)) {
- vq = (env->vfp.zcr_el[1] & 0xf) + 1;
- sve_size = QEMU_ALIGN_UP(TARGET_SVE_SIG_CONTEXT_SIZE(vq), 16);
- sve_ofs = alloc_sigframe_space(sve_size, &layout);
- }
-
- if (layout.extra_ofs) {
- /* Reserve space for the extra end marker. The standard end marker
- * will have been allocated when we allocated the extra record.
- */
- layout.extra_end_ofs
- = alloc_sigframe_space(sizeof(struct target_aarch64_ctx), &layout);
- } else {
- /* Reserve space for the standard end marker.
- * Do not use alloc_sigframe_space because we cheat
- * std_size therein to reserve space for this.
- */
- layout.std_end_ofs = layout.total_size;
- layout.total_size += sizeof(struct target_aarch64_ctx);
- }
-
- /* We must always provide at least the standard 4K reserved space,
- * even if we don't use all of it (this is part of the ABI)
- */
- layout.total_size = MAX(layout.total_size,
- sizeof(struct target_rt_sigframe));
-
- /* Reserve space for the return code. On a real system this would
- * be within the VDSO. So, despite the name this is not a "real"
- * record within the frame.
- */
- fr_ofs = layout.total_size;
- layout.total_size += sizeof(struct target_rt_frame_record);
-
- frame_addr = get_sigframe(ka, env, layout.total_size);
- trace_user_setup_frame(env, frame_addr);
- frame = lock_user(VERIFY_WRITE, frame_addr, layout.total_size, 0);
- if (!frame) {
- goto give_sigsegv;
- }
-
- target_setup_general_frame(frame, env, set);
- target_setup_fpsimd_record((void *)frame + fpsimd_ofs, env);
- target_setup_end_record((void *)frame + layout.std_end_ofs);
- if (layout.extra_ofs) {
- target_setup_extra_record((void *)frame + layout.extra_ofs,
- frame_addr + layout.extra_base,
- layout.extra_size);
- target_setup_end_record((void *)frame + layout.extra_end_ofs);
- }
- if (sve_ofs) {
- target_setup_sve_record((void *)frame + sve_ofs, env, vq, sve_size);
- }
-
- /* Set up the stack frame for unwinding. */
- fr = (void *)frame + fr_ofs;
- __put_user(env->xregs[29], &fr->fp);
- __put_user(env->xregs[30], &fr->lr);
-
- if (ka->sa_flags & TARGET_SA_RESTORER) {
- return_addr = ka->sa_restorer;
- } else {
- /*
- * mov x8,#__NR_rt_sigreturn; svc #0
- * Since these are instructions they need to be put as little-endian
- * regardless of target default or current CPU endianness.
- */
- __put_user_e(0xd2801168, &fr->tramp[0], le);
- __put_user_e(0xd4000001, &fr->tramp[1], le);
- return_addr = frame_addr + fr_ofs
- + offsetof(struct target_rt_frame_record, tramp);
- }
- env->xregs[0] = usig;
- env->xregs[31] = frame_addr;
- env->xregs[29] = frame_addr + fr_ofs;
- env->pc = ka->_sa_handler;
- env->xregs[30] = return_addr;
- if (info) {
- tswap_siginfo(&frame->info, info);
- env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
- env->xregs[2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
- }
-
- unlock_user(frame, frame_addr, layout.total_size);
- return;
-
- give_sigsegv:
- unlock_user(frame, frame_addr, layout.total_size);
- force_sigsegv(usig);
-}
-
-static void setup_rt_frame(int sig, struct target_sigaction *ka,
- target_siginfo_t *info, target_sigset_t *set,
- CPUARMState *env)
-{
- target_setup_frame(sig, ka, info, set, env);
-}
-
-static void setup_frame(int sig, struct target_sigaction *ka,
- target_sigset_t *set, CPUARMState *env)
-{
- target_setup_frame(sig, ka, 0, set, env);
-}
-
-long do_rt_sigreturn(CPUARMState *env)
-{
- struct target_rt_sigframe *frame = NULL;
- abi_ulong frame_addr = env->xregs[31];
-
- trace_user_do_rt_sigreturn(env, frame_addr);
- if (frame_addr & 15) {
- goto badframe;
- }
-
- if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
- goto badframe;
- }
-
- if (target_restore_sigframe(env, frame)) {
- goto badframe;
- }
-
- if (do_sigaltstack(frame_addr +
- offsetof(struct target_rt_sigframe, uc.tuc_stack),
- 0, get_sp_from_cpustate(env)) == -EFAULT) {
- goto badframe;
- }
-
- unlock_user_struct(frame, frame_addr, 0);
- return -TARGET_QEMU_ESIGRETURN;
-
- badframe:
- unlock_user_struct(frame, frame_addr, 0);
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-
-long do_sigreturn(CPUARMState *env)
-{
- return do_rt_sigreturn(env);
-}
-
-#elif defined(TARGET_ARM)
-
-struct target_sigcontext {
- abi_ulong trap_no;
- abi_ulong error_code;
- abi_ulong oldmask;
- abi_ulong arm_r0;
- abi_ulong arm_r1;
- abi_ulong arm_r2;
- abi_ulong arm_r3;
- abi_ulong arm_r4;
- abi_ulong arm_r5;
- abi_ulong arm_r6;
- abi_ulong arm_r7;
- abi_ulong arm_r8;
- abi_ulong arm_r9;
- abi_ulong arm_r10;
- abi_ulong arm_fp;
- abi_ulong arm_ip;
- abi_ulong arm_sp;
- abi_ulong arm_lr;
- abi_ulong arm_pc;
- abi_ulong arm_cpsr;
- abi_ulong fault_address;
-};
-
-struct target_ucontext_v1 {
- abi_ulong tuc_flags;
- abi_ulong tuc_link;
- target_stack_t tuc_stack;
- struct target_sigcontext tuc_mcontext;
- target_sigset_t tuc_sigmask; /* mask last for extensibility */
-};
-
-struct target_ucontext_v2 {
- abi_ulong tuc_flags;
- abi_ulong tuc_link;
- target_stack_t tuc_stack;
- struct target_sigcontext tuc_mcontext;
- target_sigset_t tuc_sigmask; /* mask last for extensibility */
- char __unused[128 - sizeof(target_sigset_t)];
- abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
-};
-
-struct target_user_vfp {
- uint64_t fpregs[32];
- abi_ulong fpscr;
-};
-
-struct target_user_vfp_exc {
- abi_ulong fpexc;
- abi_ulong fpinst;
- abi_ulong fpinst2;
-};
-
-struct target_vfp_sigframe {
- abi_ulong magic;
- abi_ulong size;
- struct target_user_vfp ufp;
- struct target_user_vfp_exc ufp_exc;
-} __attribute__((__aligned__(8)));
-
-struct target_iwmmxt_sigframe {
- abi_ulong magic;
- abi_ulong size;
- uint64_t regs[16];
- /* Note that not all the coprocessor control registers are stored here */
- uint32_t wcssf;
- uint32_t wcasf;
- uint32_t wcgr0;
- uint32_t wcgr1;
- uint32_t wcgr2;
- uint32_t wcgr3;
-} __attribute__((__aligned__(8)));
-
-#define TARGET_VFP_MAGIC 0x56465001
-#define TARGET_IWMMXT_MAGIC 0x12ef842a
-
-struct sigframe_v1
-{
- struct target_sigcontext sc;
- abi_ulong extramask[TARGET_NSIG_WORDS-1];
- abi_ulong retcode;
-};
-
-struct sigframe_v2
-{
- struct target_ucontext_v2 uc;
- abi_ulong retcode;
-};
-
-struct rt_sigframe_v1
-{
- abi_ulong pinfo;
- abi_ulong puc;
- struct target_siginfo info;
- struct target_ucontext_v1 uc;
- abi_ulong retcode;
-};
-
-struct rt_sigframe_v2
-{
- struct target_siginfo info;
- struct target_ucontext_v2 uc;
- abi_ulong retcode;
-};
-
-#define TARGET_CONFIG_CPU_32 1
-
-/*
- * For ARM syscalls, we encode the syscall number into the instruction.
- */
-#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
-#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
-
-/*
- * For Thumb syscalls, we pass the syscall number via r7. We therefore
- * need two 16-bit instructions.
- */
-#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
-#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
-
-static const abi_ulong retcodes[4] = {
- SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
- SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
-};
-
-
-static inline int valid_user_regs(CPUARMState *regs)
-{
- return 1;
-}
-
-static void
-setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
- CPUARMState *env, abi_ulong mask)
-{
- __put_user(env->regs[0], &sc->arm_r0);
- __put_user(env->regs[1], &sc->arm_r1);
- __put_user(env->regs[2], &sc->arm_r2);
- __put_user(env->regs[3], &sc->arm_r3);
- __put_user(env->regs[4], &sc->arm_r4);
- __put_user(env->regs[5], &sc->arm_r5);
- __put_user(env->regs[6], &sc->arm_r6);
- __put_user(env->regs[7], &sc->arm_r7);
- __put_user(env->regs[8], &sc->arm_r8);
- __put_user(env->regs[9], &sc->arm_r9);
- __put_user(env->regs[10], &sc->arm_r10);
- __put_user(env->regs[11], &sc->arm_fp);
- __put_user(env->regs[12], &sc->arm_ip);
- __put_user(env->regs[13], &sc->arm_sp);
- __put_user(env->regs[14], &sc->arm_lr);
- __put_user(env->regs[15], &sc->arm_pc);
-#ifdef TARGET_CONFIG_CPU_32
- __put_user(cpsr_read(env), &sc->arm_cpsr);
-#endif
-
- __put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
- __put_user(/* current->thread.error_code */ 0, &sc->error_code);
- __put_user(/* current->thread.address */ 0, &sc->fault_address);
- __put_user(mask, &sc->oldmask);
-}
-
-static inline abi_ulong
-get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
-{
- unsigned long sp = regs->regs[13];
-
- /*
- * This is the X/Open sanctioned signal stack switching.
- */
- if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
- sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
- }
- /*
- * ATPCS B01 mandates 8-byte alignment
- */
- return (sp - framesize) & ~7;
-}
-
-static void
-setup_return(CPUARMState *env, struct target_sigaction *ka,
- abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
-{
- abi_ulong handler = ka->_sa_handler;
- abi_ulong retcode;
- int thumb = handler & 1;
- uint32_t cpsr = cpsr_read(env);
-
- cpsr &= ~CPSR_IT;
- if (thumb) {
- cpsr |= CPSR_T;
- } else {
- cpsr &= ~CPSR_T;
- }
-
- if (ka->sa_flags & TARGET_SA_RESTORER) {
- retcode = ka->sa_restorer;
- } else {
- unsigned int idx = thumb;
-
- if (ka->sa_flags & TARGET_SA_SIGINFO) {
- idx += 2;
- }
-
- __put_user(retcodes[idx], rc);
-
- retcode = rc_addr + thumb;
- }
-
- env->regs[0] = usig;
- env->regs[13] = frame_addr;
- env->regs[14] = retcode;
- env->regs[15] = handler & (thumb ? ~1 : ~3);
- cpsr_write(env, cpsr, CPSR_IT | CPSR_T, CPSRWriteByInstr);
-}
-
-static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
-{
- int i;
- struct target_vfp_sigframe *vfpframe;
- vfpframe = (struct target_vfp_sigframe *)regspace;
- __put_user(TARGET_VFP_MAGIC, &vfpframe->magic);
- __put_user(sizeof(*vfpframe), &vfpframe->size);
- for (i = 0; i < 32; i++) {
- __put_user(*aa32_vfp_dreg(env, i), &vfpframe->ufp.fpregs[i]);
- }
- __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr);
- __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc);
- __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
- __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
- return (abi_ulong*)(vfpframe+1);
-}
-
-static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace,
- CPUARMState *env)
-{
- int i;
- struct target_iwmmxt_sigframe *iwmmxtframe;
- iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
- __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic);
- __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size);
- for (i = 0; i < 16; i++) {
- __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
- }
- __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
- __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
- __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
- __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
- __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
- __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
- return (abi_ulong*)(iwmmxtframe+1);
-}
-
-static void setup_sigframe_v2(struct target_ucontext_v2 *uc,
- target_sigset_t *set, CPUARMState *env)
-{
- struct target_sigaltstack stack;
- int i;
- abi_ulong *regspace;
-
- /* Clear all the bits of the ucontext we don't use. */
- memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext));
-
- memset(&stack, 0, sizeof(stack));
- __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
- __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
- __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
- memcpy(&uc->tuc_stack, &stack, sizeof(stack));
-
- setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]);
- /* Save coprocessor signal frame. */
- regspace = uc->tuc_regspace;
- if (arm_feature(env, ARM_FEATURE_VFP)) {
- regspace = setup_sigframe_v2_vfp(regspace, env);
- }
- if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
- regspace = setup_sigframe_v2_iwmmxt(regspace, env);
- }
-
- /* Write terminating magic word */
- __put_user(0, regspace);
-
- for(i = 0; i < TARGET_NSIG_WORDS; i++) {
- __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]);
- }
-}
-
-/* compare linux/arch/arm/kernel/signal.c:setup_frame() */
-static void setup_frame_v1(int usig, struct target_sigaction *ka,
- target_sigset_t *set, CPUARMState *regs)
-{
- struct sigframe_v1 *frame;
- abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
- int i;
-
- trace_user_setup_frame(regs, frame_addr);
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto sigsegv;
- }
-
- setup_sigcontext(&frame->sc, regs, set->sig[0]);
-
- for(i = 1; i < TARGET_NSIG_WORDS; i++) {
- __put_user(set->sig[i], &frame->extramask[i - 1]);
- }
-
- setup_return(regs, ka, &frame->retcode, frame_addr, usig,
- frame_addr + offsetof(struct sigframe_v1, retcode));
-
- unlock_user_struct(frame, frame_addr, 1);
- return;
-sigsegv:
- force_sigsegv(usig);
-}
-
-static void setup_frame_v2(int usig, struct target_sigaction *ka,
- target_sigset_t *set, CPUARMState *regs)
-{
- struct sigframe_v2 *frame;
- abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame));
-
- trace_user_setup_frame(regs, frame_addr);
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto sigsegv;
- }
-
- setup_sigframe_v2(&frame->uc, set, regs);
-
- setup_return(regs, ka, &frame->retcode, frame_addr, usig,
- frame_addr + offsetof(struct sigframe_v2, retcode));
-
- unlock_user_struct(frame, frame_addr, 1);
- return;
-sigsegv:
- force_sigsegv(usig);
-}
-
-static void setup_frame(int usig, struct target_sigaction *ka,
- target_sigset_t *set, CPUARMState *regs)
-{
- if (get_osversion() >= 0x020612) {
- setup_frame_v2(usig, ka, set, regs);
- } else {
- setup_frame_v1(usig, ka, set, regs);
- }
-}
-
-/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */
-static void setup_rt_frame_v1(int usig, struct target_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUARMState *env)
-{
- struct rt_sigframe_v1 *frame;
- abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
- struct target_sigaltstack stack;
- int i;
- abi_ulong info_addr, uc_addr;
-
- trace_user_setup_rt_frame(env, frame_addr);
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto sigsegv;
- }
-
- info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info);
- __put_user(info_addr, &frame->pinfo);
- uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc);
- __put_user(uc_addr, &frame->puc);
- tswap_siginfo(&frame->info, info);
-
- /* Clear all the bits of the ucontext we don't use. */
- memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext));
-
- memset(&stack, 0, sizeof(stack));
- __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
- __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
- __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
- memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
-
- setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]);
- for(i = 0; i < TARGET_NSIG_WORDS; i++) {
- __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
- }
-
- setup_return(env, ka, &frame->retcode, frame_addr, usig,
- frame_addr + offsetof(struct rt_sigframe_v1, retcode));
-
- env->regs[1] = info_addr;
- env->regs[2] = uc_addr;
-
- unlock_user_struct(frame, frame_addr, 1);
- return;
-sigsegv:
- force_sigsegv(usig);
-}
-
-static void setup_rt_frame_v2(int usig, struct target_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUARMState *env)
-{
- struct rt_sigframe_v2 *frame;
- abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame));
- abi_ulong info_addr, uc_addr;
-
- trace_user_setup_rt_frame(env, frame_addr);
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto sigsegv;
- }
-
- info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info);
- uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc);
- tswap_siginfo(&frame->info, info);
-
- setup_sigframe_v2(&frame->uc, set, env);
-
- setup_return(env, ka, &frame->retcode, frame_addr, usig,
- frame_addr + offsetof(struct rt_sigframe_v2, retcode));
-
- env->regs[1] = info_addr;
- env->regs[2] = uc_addr;
-
- unlock_user_struct(frame, frame_addr, 1);
- return;
-sigsegv:
- force_sigsegv(usig);
-}
-
-static void setup_rt_frame(int usig, struct target_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUARMState *env)
-{
- if (get_osversion() >= 0x020612) {
- setup_rt_frame_v2(usig, ka, info, set, env);
- } else {
- setup_rt_frame_v1(usig, ka, info, set, env);
- }
-}
-
-static int
-restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
-{
- int err = 0;
- uint32_t cpsr;
-
- __get_user(env->regs[0], &sc->arm_r0);
- __get_user(env->regs[1], &sc->arm_r1);
- __get_user(env->regs[2], &sc->arm_r2);
- __get_user(env->regs[3], &sc->arm_r3);
- __get_user(env->regs[4], &sc->arm_r4);
- __get_user(env->regs[5], &sc->arm_r5);
- __get_user(env->regs[6], &sc->arm_r6);
- __get_user(env->regs[7], &sc->arm_r7);
- __get_user(env->regs[8], &sc->arm_r8);
- __get_user(env->regs[9], &sc->arm_r9);
- __get_user(env->regs[10], &sc->arm_r10);
- __get_user(env->regs[11], &sc->arm_fp);
- __get_user(env->regs[12], &sc->arm_ip);
- __get_user(env->regs[13], &sc->arm_sp);
- __get_user(env->regs[14], &sc->arm_lr);
- __get_user(env->regs[15], &sc->arm_pc);
-#ifdef TARGET_CONFIG_CPU_32
- __get_user(cpsr, &sc->arm_cpsr);
- cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC, CPSRWriteByInstr);
-#endif
-
- err |= !valid_user_regs(env);
-
- return err;
-}
-
-static long do_sigreturn_v1(CPUARMState *env)
-{
- abi_ulong frame_addr;
- struct sigframe_v1 *frame = NULL;
- target_sigset_t set;
- sigset_t host_set;
- int i;
-
- /*
- * Since we stacked the signal on a 64-bit boundary,
- * then 'sp' should be word aligned here. If it's
- * not, then the user is trying to mess with us.
- */
- frame_addr = env->regs[13];
- trace_user_do_sigreturn(env, frame_addr);
- if (frame_addr & 7) {
- goto badframe;
- }
-
- if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
- goto badframe;
- }
-
- __get_user(set.sig[0], &frame->sc.oldmask);
- for(i = 1; i < TARGET_NSIG_WORDS; i++) {
- __get_user(set.sig[i], &frame->extramask[i - 1]);
- }
-
- target_to_host_sigset_internal(&host_set, &set);
- set_sigmask(&host_set);
-
- if (restore_sigcontext(env, &frame->sc)) {
- goto badframe;
- }
-
-#if 0
- /* Send SIGTRAP if we're single-stepping */
- if (ptrace_cancel_bpt(current))
- send_sig(SIGTRAP, current, 1);
-#endif
- unlock_user_struct(frame, frame_addr, 0);
- return -TARGET_QEMU_ESIGRETURN;
-
-badframe:
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-
-static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
-{
- int i;
- abi_ulong magic, sz;
- uint32_t fpscr, fpexc;
- struct target_vfp_sigframe *vfpframe;
- vfpframe = (struct target_vfp_sigframe *)regspace;
-
- __get_user(magic, &vfpframe->magic);
- __get_user(sz, &vfpframe->size);
- if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) {
- return 0;
- }
- for (i = 0; i < 32; i++) {
- __get_user(*aa32_vfp_dreg(env, i), &vfpframe->ufp.fpregs[i]);
- }
- __get_user(fpscr, &vfpframe->ufp.fpscr);
- vfp_set_fpscr(env, fpscr);
- __get_user(fpexc, &vfpframe->ufp_exc.fpexc);
- /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid
- * and the exception flag is cleared
- */
- fpexc |= (1 << 30);
- fpexc &= ~((1 << 31) | (1 << 28));
- env->vfp.xregs[ARM_VFP_FPEXC] = fpexc;
- __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst);
- __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2);
- return (abi_ulong*)(vfpframe + 1);
-}
-
-static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env,
- abi_ulong *regspace)
-{
- int i;
- abi_ulong magic, sz;
- struct target_iwmmxt_sigframe *iwmmxtframe;
- iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace;
-
- __get_user(magic, &iwmmxtframe->magic);
- __get_user(sz, &iwmmxtframe->size);
- if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) {
- return 0;
- }
- for (i = 0; i < 16; i++) {
- __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]);
- }
- __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf);
- __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf);
- __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0);
- __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1);
- __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2);
- __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3);
- return (abi_ulong*)(iwmmxtframe + 1);
-}
-
-static int do_sigframe_return_v2(CPUARMState *env,
- target_ulong context_addr,
- struct target_ucontext_v2 *uc)
-{
- sigset_t host_set;
- abi_ulong *regspace;
-
- target_to_host_sigset(&host_set, &uc->tuc_sigmask);
- set_sigmask(&host_set);
-
- if (restore_sigcontext(env, &uc->tuc_mcontext))
- return 1;
-
- /* Restore coprocessor signal frame */
- regspace = uc->tuc_regspace;
- if (arm_feature(env, ARM_FEATURE_VFP)) {
- regspace = restore_sigframe_v2_vfp(env, regspace);
- if (!regspace) {
- return 1;
- }
- }
- if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
- regspace = restore_sigframe_v2_iwmmxt(env, regspace);
- if (!regspace) {
- return 1;
- }
- }
-
- if (do_sigaltstack(context_addr
- + offsetof(struct target_ucontext_v2, tuc_stack),
- 0, get_sp_from_cpustate(env)) == -EFAULT) {
- return 1;
- }
-
-#if 0
- /* Send SIGTRAP if we're single-stepping */
- if (ptrace_cancel_bpt(current))
- send_sig(SIGTRAP, current, 1);
-#endif
-
- return 0;
-}
-
-static long do_sigreturn_v2(CPUARMState *env)
-{
- abi_ulong frame_addr;
- struct sigframe_v2 *frame = NULL;
-
- /*
- * Since we stacked the signal on a 64-bit boundary,
- * then 'sp' should be word aligned here. If it's
- * not, then the user is trying to mess with us.
- */
- frame_addr = env->regs[13];
- trace_user_do_sigreturn(env, frame_addr);
- if (frame_addr & 7) {
- goto badframe;
- }
-
- if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
- goto badframe;
- }
-
- if (do_sigframe_return_v2(env,
- frame_addr
- + offsetof(struct sigframe_v2, uc),
- &frame->uc)) {
- goto badframe;
- }
-
- unlock_user_struct(frame, frame_addr, 0);
- return -TARGET_QEMU_ESIGRETURN;
-
-badframe:
- unlock_user_struct(frame, frame_addr, 0);
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-
-long do_sigreturn(CPUARMState *env)
-{
- if (get_osversion() >= 0x020612) {
- return do_sigreturn_v2(env);
- } else {
- return do_sigreturn_v1(env);
- }
-}
-
-static long do_rt_sigreturn_v1(CPUARMState *env)
-{
- abi_ulong frame_addr;
- struct rt_sigframe_v1 *frame = NULL;
- sigset_t host_set;
-
- /*
- * Since we stacked the signal on a 64-bit boundary,
- * then 'sp' should be word aligned here. If it's
- * not, then the user is trying to mess with us.
- */
- frame_addr = env->regs[13];
- trace_user_do_rt_sigreturn(env, frame_addr);
- if (frame_addr & 7) {
- goto badframe;
- }
-
- if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
- goto badframe;
- }
-
- target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
- set_sigmask(&host_set);
-
- if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
- goto badframe;
- }
-
- if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v1, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
- goto badframe;
-
-#if 0
- /* Send SIGTRAP if we're single-stepping */
- if (ptrace_cancel_bpt(current))
- send_sig(SIGTRAP, current, 1);
-#endif
- unlock_user_struct(frame, frame_addr, 0);
- return -TARGET_QEMU_ESIGRETURN;
-
-badframe:
- unlock_user_struct(frame, frame_addr, 0);
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-
-static long do_rt_sigreturn_v2(CPUARMState *env)
-{
- abi_ulong frame_addr;
- struct rt_sigframe_v2 *frame = NULL;
-
- /*
- * Since we stacked the signal on a 64-bit boundary,
- * then 'sp' should be word aligned here. If it's
- * not, then the user is trying to mess with us.
- */
- frame_addr = env->regs[13];
- trace_user_do_rt_sigreturn(env, frame_addr);
- if (frame_addr & 7) {
- goto badframe;
- }
-
- if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
- goto badframe;
- }
-
- if (do_sigframe_return_v2(env,
- frame_addr
- + offsetof(struct rt_sigframe_v2, uc),
- &frame->uc)) {
- goto badframe;
- }
-
- unlock_user_struct(frame, frame_addr, 0);
- return -TARGET_QEMU_ESIGRETURN;
-
-badframe:
- unlock_user_struct(frame, frame_addr, 0);
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-
-long do_rt_sigreturn(CPUARMState *env)
-{
- if (get_osversion() >= 0x020612) {
- return do_rt_sigreturn_v2(env);
- } else {
- return do_rt_sigreturn_v1(env);
- }
-}
-
-#elif defined(TARGET_SPARC)
-
-#define __SUNOS_MAXWIN 31
-
-/* This is what SunOS does, so shall I. */
-struct target_sigcontext {
- abi_ulong sigc_onstack; /* state to restore */
-
- abi_ulong sigc_mask; /* sigmask to restore */
- abi_ulong sigc_sp; /* stack pointer */
- abi_ulong sigc_pc; /* program counter */
- abi_ulong sigc_npc; /* next program counter */
- abi_ulong sigc_psr; /* for condition codes etc */
- abi_ulong sigc_g1; /* User uses these two registers */
- abi_ulong sigc_o0; /* within the trampoline code. */
-
- /* Now comes information regarding the users window set
- * at the time of the signal.
- */
- abi_ulong sigc_oswins; /* outstanding windows */
-
- /* stack ptrs for each regwin buf */
- char *sigc_spbuf[__SUNOS_MAXWIN];
-
- /* Windows to restore after signal */
- struct {
- abi_ulong locals[8];
- abi_ulong ins[8];
- } sigc_wbuf[__SUNOS_MAXWIN];
-};
-/* A Sparc stack frame */
-struct sparc_stackf {
- abi_ulong locals[8];
- abi_ulong ins[8];
- /* It's simpler to treat fp and callers_pc as elements of ins[]
- * since we never need to access them ourselves.
- */
- char *structptr;
- abi_ulong xargs[6];
- abi_ulong xxargs[1];
-};
-
-typedef struct {
- struct {
- abi_ulong psr;
- abi_ulong pc;
- abi_ulong npc;
- abi_ulong y;
- abi_ulong u_regs[16]; /* globals and ins */
- } si_regs;
- int si_mask;
-} __siginfo_t;
-
-typedef struct {
- abi_ulong si_float_regs[32];
- unsigned long si_fsr;
- unsigned long si_fpqdepth;
- struct {
- unsigned long *insn_addr;
- unsigned long insn;
- } si_fpqueue [16];
-} qemu_siginfo_fpu_t;
-
-
-struct target_signal_frame {
- struct sparc_stackf ss;
- __siginfo_t info;
- abi_ulong fpu_save;
- abi_ulong insns[2] __attribute__ ((aligned (8)));
- abi_ulong extramask[TARGET_NSIG_WORDS - 1];
- abi_ulong extra_size; /* Should be 0 */
- qemu_siginfo_fpu_t fpu_state;
-};
-struct target_rt_signal_frame {
- struct sparc_stackf ss;
- siginfo_t info;
- abi_ulong regs[20];
- sigset_t mask;
- abi_ulong fpu_save;
- unsigned int insns[2];
- stack_t stack;
- unsigned int extra_size; /* Should be 0 */
- qemu_siginfo_fpu_t fpu_state;
-};
-
-#define UREG_O0 16
-#define UREG_O6 22
-#define UREG_I0 0
-#define UREG_I1 1
-#define UREG_I2 2
-#define UREG_I3 3
-#define UREG_I4 4
-#define UREG_I5 5
-#define UREG_I6 6
-#define UREG_I7 7
-#define UREG_L0 8
-#define UREG_FP UREG_I6
-#define UREG_SP UREG_O6
-
-static inline abi_ulong get_sigframe(struct target_sigaction *sa,
- CPUSPARCState *env,
- unsigned long framesize)
-{
- abi_ulong sp;
-
- sp = env->regwptr[UREG_FP];
-
- /* This is the X/Open sanctioned signal stack switching. */
- if (sa->sa_flags & TARGET_SA_ONSTACK) {
- if (!on_sig_stack(sp)
- && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7)) {
- sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
- }
- }
- return sp - framesize;
-}
-
-static int
-setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask)
-{
- int err = 0, i;
-
- __put_user(env->psr, &si->si_regs.psr);
- __put_user(env->pc, &si->si_regs.pc);
- __put_user(env->npc, &si->si_regs.npc);
- __put_user(env->y, &si->si_regs.y);
- for (i=0; i < 8; i++) {
- __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
- }
- for (i=0; i < 8; i++) {
- __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
- }
- __put_user(mask, &si->si_mask);
- return err;
-}
-
-#if 0
-static int
-setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
- CPUSPARCState *env, unsigned long mask)
-{
- int err = 0;
-
- __put_user(mask, &sc->sigc_mask);
- __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
- __put_user(env->pc, &sc->sigc_pc);
- __put_user(env->npc, &sc->sigc_npc);
- __put_user(env->psr, &sc->sigc_psr);
- __put_user(env->gregs[1], &sc->sigc_g1);
- __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
-
- return err;
-}
-#endif
-#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
-
-static void setup_frame(int sig, struct target_sigaction *ka,
- target_sigset_t *set, CPUSPARCState *env)
-{
- abi_ulong sf_addr;
- struct target_signal_frame *sf;
- int sigframe_size, err, i;
-
- /* 1. Make sure everything is clean */
- //synchronize_user_stack();
-
- sigframe_size = NF_ALIGNEDSZ;
- sf_addr = get_sigframe(ka, env, sigframe_size);
- trace_user_setup_frame(env, sf_addr);
-
- sf = lock_user(VERIFY_WRITE, sf_addr,
- sizeof(struct target_signal_frame), 0);
- if (!sf) {
- goto sigsegv;
- }
-#if 0
- if (invalid_frame_pointer(sf, sigframe_size))
- goto sigill_and_return;
-#endif
- /* 2. Save the current process state */
- err = setup___siginfo(&sf->info, env, set->sig[0]);
- __put_user(0, &sf->extra_size);
-
- //save_fpu_state(regs, &sf->fpu_state);
- //__put_user(&sf->fpu_state, &sf->fpu_save);
-
- __put_user(set->sig[0], &sf->info.si_mask);
- for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
- __put_user(set->sig[i + 1], &sf->extramask[i]);
- }
-
- for (i = 0; i < 8; i++) {
- __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
- }
- for (i = 0; i < 8; i++) {
- __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
- }
- if (err)
- goto sigsegv;
-
- /* 3. signal handler back-trampoline and parameters */
- env->regwptr[UREG_FP] = sf_addr;
- env->regwptr[UREG_I0] = sig;
- env->regwptr[UREG_I1] = sf_addr +
- offsetof(struct target_signal_frame, info);
- env->regwptr[UREG_I2] = sf_addr +
- offsetof(struct target_signal_frame, info);
-
- /* 4. signal handler */
- env->pc = ka->_sa_handler;
- env->npc = (env->pc + 4);
- /* 5. return to kernel instructions */
- if (ka->ka_restorer) {
- env->regwptr[UREG_I7] = ka->ka_restorer;
- } else {
- uint32_t val32;
-
- env->regwptr[UREG_I7] = sf_addr +
- offsetof(struct target_signal_frame, insns) - 2 * 4;
-
- /* mov __NR_sigreturn, %g1 */
- val32 = 0x821020d8;
- __put_user(val32, &sf->insns[0]);
-
- /* t 0x10 */
- val32 = 0x91d02010;
- __put_user(val32, &sf->insns[1]);
- if (err)
- goto sigsegv;
-
- /* Flush instruction space. */
- // flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
- // tb_flush(env);
- }
- unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
- return;
-#if 0
-sigill_and_return:
- force_sig(TARGET_SIGILL);
-#endif
-sigsegv:
- unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
- force_sigsegv(sig);
-}
-
-static void setup_rt_frame(int sig, struct target_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUSPARCState *env)
-{
- fprintf(stderr, "setup_rt_frame: not implemented\n");
-}
-
-long do_sigreturn(CPUSPARCState *env)
-{
- abi_ulong sf_addr;
- struct target_signal_frame *sf;
- uint32_t up_psr, pc, npc;
- target_sigset_t set;
- sigset_t host_set;
- int err=0, i;
-
- sf_addr = env->regwptr[UREG_FP];
- trace_user_do_sigreturn(env, sf_addr);
- if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1)) {
- goto segv_and_exit;
- }
-
- /* 1. Make sure we are not getting garbage from the user */
-
- if (sf_addr & 3)
- goto segv_and_exit;
-
- __get_user(pc, &sf->info.si_regs.pc);
- __get_user(npc, &sf->info.si_regs.npc);
-
- if ((pc | npc) & 3) {
- goto segv_and_exit;
- }
-
- /* 2. Restore the state */
- __get_user(up_psr, &sf->info.si_regs.psr);
-
- /* User can only change condition codes and FPU enabling in %psr. */
- env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
- | (env->psr & ~(PSR_ICC /* | PSR_EF */));
-
- env->pc = pc;
- env->npc = npc;
- __get_user(env->y, &sf->info.si_regs.y);
- for (i=0; i < 8; i++) {
- __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
- }
- for (i=0; i < 8; i++) {
- __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
- }
-
- /* FIXME: implement FPU save/restore:
- * __get_user(fpu_save, &sf->fpu_save);
- * if (fpu_save)
- * err |= restore_fpu_state(env, fpu_save);
- */
-
- /* This is pretty much atomic, no amount locking would prevent
- * the races which exist anyways.
- */
- __get_user(set.sig[0], &sf->info.si_mask);
- for(i = 1; i < TARGET_NSIG_WORDS; i++) {
- __get_user(set.sig[i], &sf->extramask[i - 1]);
- }
-
- target_to_host_sigset_internal(&host_set, &set);
- set_sigmask(&host_set);
-
- if (err) {
- goto segv_and_exit;
- }
- unlock_user_struct(sf, sf_addr, 0);
- return -TARGET_QEMU_ESIGRETURN;
-
-segv_and_exit:
- unlock_user_struct(sf, sf_addr, 0);
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-
-long do_rt_sigreturn(CPUSPARCState *env)
-{
- trace_user_do_rt_sigreturn(env, 0);
- fprintf(stderr, "do_rt_sigreturn: not implemented\n");
- return -TARGET_ENOSYS;
-}
-
-#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
-#define SPARC_MC_TSTATE 0
-#define SPARC_MC_PC 1
-#define SPARC_MC_NPC 2
-#define SPARC_MC_Y 3
-#define SPARC_MC_G1 4
-#define SPARC_MC_G2 5
-#define SPARC_MC_G3 6
-#define SPARC_MC_G4 7
-#define SPARC_MC_G5 8
-#define SPARC_MC_G6 9
-#define SPARC_MC_G7 10
-#define SPARC_MC_O0 11
-#define SPARC_MC_O1 12
-#define SPARC_MC_O2 13
-#define SPARC_MC_O3 14
-#define SPARC_MC_O4 15
-#define SPARC_MC_O5 16
-#define SPARC_MC_O6 17
-#define SPARC_MC_O7 18
-#define SPARC_MC_NGREG 19
-
-typedef abi_ulong target_mc_greg_t;
-typedef target_mc_greg_t target_mc_gregset_t[SPARC_MC_NGREG];
-
-struct target_mc_fq {
- abi_ulong *mcfq_addr;
- uint32_t mcfq_insn;
-};
-
-struct target_mc_fpu {
- union {
- uint32_t sregs[32];
- uint64_t dregs[32];
- //uint128_t qregs[16];
- } mcfpu_fregs;
- abi_ulong mcfpu_fsr;
- abi_ulong mcfpu_fprs;
- abi_ulong mcfpu_gsr;
- struct target_mc_fq *mcfpu_fq;
- unsigned char mcfpu_qcnt;
- unsigned char mcfpu_qentsz;
- unsigned char mcfpu_enab;
-};
-typedef struct target_mc_fpu target_mc_fpu_t;
-
-typedef struct {
- target_mc_gregset_t mc_gregs;
- target_mc_greg_t mc_fp;
- target_mc_greg_t mc_i7;
- target_mc_fpu_t mc_fpregs;
-} target_mcontext_t;
-
-struct target_ucontext {
- struct target_ucontext *tuc_link;
- abi_ulong tuc_flags;
- target_sigset_t tuc_sigmask;
- target_mcontext_t tuc_mcontext;
-};
-
-/* A V9 register window */
-struct target_reg_window {
- abi_ulong locals[8];
- abi_ulong ins[8];
-};
-
-#define TARGET_STACK_BIAS 2047
-
-/* {set, get}context() needed for 64-bit SparcLinux userland. */
-void sparc64_set_context(CPUSPARCState *env)
-{
- abi_ulong ucp_addr;
- struct target_ucontext *ucp;
- target_mc_gregset_t *grp;
- abi_ulong pc, npc, tstate;
- abi_ulong fp, i7, w_addr;
- unsigned int i;
-
- ucp_addr = env->regwptr[UREG_I0];
- if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1)) {
- goto do_sigsegv;
- }
- grp = &ucp->tuc_mcontext.mc_gregs;
- __get_user(pc, &((*grp)[SPARC_MC_PC]));
- __get_user(npc, &((*grp)[SPARC_MC_NPC]));
- if ((pc | npc) & 3) {
- goto do_sigsegv;
- }
- if (env->regwptr[UREG_I1]) {
- target_sigset_t target_set;
- sigset_t set;
-
- if (TARGET_NSIG_WORDS == 1) {
- __get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]);
- } else {
- abi_ulong *src, *dst;
- src = ucp->tuc_sigmask.sig;
- dst = target_set.sig;
- for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
- __get_user(*dst, src);
- }
- }
- target_to_host_sigset_internal(&set, &target_set);
- set_sigmask(&set);
- }
- env->pc = pc;
- env->npc = npc;
- __get_user(env->y, &((*grp)[SPARC_MC_Y]));
- __get_user(tstate, &((*grp)[SPARC_MC_TSTATE]));
- env->asi = (tstate >> 24) & 0xff;
- cpu_put_ccr(env, tstate >> 32);
- cpu_put_cwp64(env, tstate & 0x1f);
- __get_user(env->gregs[1], (&(*grp)[SPARC_MC_G1]));
- __get_user(env->gregs[2], (&(*grp)[SPARC_MC_G2]));
- __get_user(env->gregs[3], (&(*grp)[SPARC_MC_G3]));
- __get_user(env->gregs[4], (&(*grp)[SPARC_MC_G4]));
- __get_user(env->gregs[5], (&(*grp)[SPARC_MC_G5]));
- __get_user(env->gregs[6], (&(*grp)[SPARC_MC_G6]));
- __get_user(env->gregs[7], (&(*grp)[SPARC_MC_G7]));
- __get_user(env->regwptr[UREG_I0], (&(*grp)[SPARC_MC_O0]));
- __get_user(env->regwptr[UREG_I1], (&(*grp)[SPARC_MC_O1]));
- __get_user(env->regwptr[UREG_I2], (&(*grp)[SPARC_MC_O2]));
- __get_user(env->regwptr[UREG_I3], (&(*grp)[SPARC_MC_O3]));
- __get_user(env->regwptr[UREG_I4], (&(*grp)[SPARC_MC_O4]));
- __get_user(env->regwptr[UREG_I5], (&(*grp)[SPARC_MC_O5]));
- __get_user(env->regwptr[UREG_I6], (&(*grp)[SPARC_MC_O6]));
- __get_user(env->regwptr[UREG_I7], (&(*grp)[SPARC_MC_O7]));
-
- __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
- __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
-
- w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
- if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
- abi_ulong) != 0) {
- goto do_sigsegv;
- }
- if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
- abi_ulong) != 0) {
- goto do_sigsegv;
- }
- /* FIXME this does not match how the kernel handles the FPU in
- * its sparc64_set_context implementation. In particular the FPU
- * is only restored if fenab is non-zero in:
- * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
- */
- __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
- {
- uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
- for (i = 0; i < 64; i++, src++) {
- if (i & 1) {
- __get_user(env->fpr[i/2].l.lower, src);
- } else {
- __get_user(env->fpr[i/2].l.upper, src);
- }
- }
- }
- __get_user(env->fsr,
- &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
- __get_user(env->gsr,
- &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
- unlock_user_struct(ucp, ucp_addr, 0);
- return;
-do_sigsegv:
- unlock_user_struct(ucp, ucp_addr, 0);
- force_sig(TARGET_SIGSEGV);
-}
-
-void sparc64_get_context(CPUSPARCState *env)
-{
- abi_ulong ucp_addr;
- struct target_ucontext *ucp;
- target_mc_gregset_t *grp;
- target_mcontext_t *mcp;
- abi_ulong fp, i7, w_addr;
- int err;
- unsigned int i;
- target_sigset_t target_set;
- sigset_t set;
-
- ucp_addr = env->regwptr[UREG_I0];
- if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0)) {
- goto do_sigsegv;
- }
-
- mcp = &ucp->tuc_mcontext;
- grp = &mcp->mc_gregs;
-
- /* Skip over the trap instruction, first. */
- env->pc = env->npc;
- env->npc += 4;
-
- /* If we're only reading the signal mask then do_sigprocmask()
- * is guaranteed not to fail, which is important because we don't
- * have any way to signal a failure or restart this operation since
- * this is not a normal syscall.
- */
- err = do_sigprocmask(0, NULL, &set);
- assert(err == 0);
- host_to_target_sigset_internal(&target_set, &set);
- if (TARGET_NSIG_WORDS == 1) {
- __put_user(target_set.sig[0],
- (abi_ulong *)&ucp->tuc_sigmask);
- } else {
- abi_ulong *src, *dst;
- src = target_set.sig;
- dst = ucp->tuc_sigmask.sig;
- for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
- __put_user(*src, dst);
- }
- if (err)
- goto do_sigsegv;
- }
-
- /* XXX: tstate must be saved properly */
- // __put_user(env->tstate, &((*grp)[SPARC_MC_TSTATE]));
- __put_user(env->pc, &((*grp)[SPARC_MC_PC]));
- __put_user(env->npc, &((*grp)[SPARC_MC_NPC]));
- __put_user(env->y, &((*grp)[SPARC_MC_Y]));
- __put_user(env->gregs[1], &((*grp)[SPARC_MC_G1]));
- __put_user(env->gregs[2], &((*grp)[SPARC_MC_G2]));
- __put_user(env->gregs[3], &((*grp)[SPARC_MC_G3]));
- __put_user(env->gregs[4], &((*grp)[SPARC_MC_G4]));
- __put_user(env->gregs[5], &((*grp)[SPARC_MC_G5]));
- __put_user(env->gregs[6], &((*grp)[SPARC_MC_G6]));
- __put_user(env->gregs[7], &((*grp)[SPARC_MC_G7]));
- __put_user(env->regwptr[UREG_I0], &((*grp)[SPARC_MC_O0]));
- __put_user(env->regwptr[UREG_I1], &((*grp)[SPARC_MC_O1]));
- __put_user(env->regwptr[UREG_I2], &((*grp)[SPARC_MC_O2]));
- __put_user(env->regwptr[UREG_I3], &((*grp)[SPARC_MC_O3]));
- __put_user(env->regwptr[UREG_I4], &((*grp)[SPARC_MC_O4]));
- __put_user(env->regwptr[UREG_I5], &((*grp)[SPARC_MC_O5]));
- __put_user(env->regwptr[UREG_I6], &((*grp)[SPARC_MC_O6]));
- __put_user(env->regwptr[UREG_I7], &((*grp)[SPARC_MC_O7]));
-
- w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
- fp = i7 = 0;
- if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
- abi_ulong) != 0) {
- goto do_sigsegv;
- }
- if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
- abi_ulong) != 0) {
- goto do_sigsegv;
- }
- __put_user(fp, &(mcp->mc_fp));
- __put_user(i7, &(mcp->mc_i7));
-
- {
- uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
- for (i = 0; i < 64; i++, dst++) {
- if (i & 1) {
- __put_user(env->fpr[i/2].l.lower, dst);
- } else {
- __put_user(env->fpr[i/2].l.upper, dst);
- }
- }
- }
- __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
- __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
- __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
-
- if (err)
- goto do_sigsegv;
- unlock_user_struct(ucp, ucp_addr, 1);
- return;
-do_sigsegv:
- unlock_user_struct(ucp, ucp_addr, 1);
- force_sig(TARGET_SIGSEGV);
-}
-#endif
-#elif defined(TARGET_MIPS) || defined(TARGET_MIPS64)
-
-# if defined(TARGET_ABI_MIPSO32)
-struct target_sigcontext {
- uint32_t sc_regmask; /* Unused */
- uint32_t sc_status;
- uint64_t sc_pc;
- uint64_t sc_regs[32];
- uint64_t sc_fpregs[32];
- uint32_t sc_ownedfp; /* Unused */
- uint32_t sc_fpc_csr;
- uint32_t sc_fpc_eir; /* Unused */
- uint32_t sc_used_math;
- uint32_t sc_dsp; /* dsp status, was sc_ssflags */
- uint32_t pad0;
- uint64_t sc_mdhi;
- uint64_t sc_mdlo;
- target_ulong sc_hi1; /* Was sc_cause */
- target_ulong sc_lo1; /* Was sc_badvaddr */
- target_ulong sc_hi2; /* Was sc_sigset[4] */
- target_ulong sc_lo2;
- target_ulong sc_hi3;
- target_ulong sc_lo3;
-};
-# else /* N32 || N64 */
-struct target_sigcontext {
- uint64_t sc_regs[32];
- uint64_t sc_fpregs[32];
- uint64_t sc_mdhi;
- uint64_t sc_hi1;
- uint64_t sc_hi2;
- uint64_t sc_hi3;
- uint64_t sc_mdlo;
- uint64_t sc_lo1;
- uint64_t sc_lo2;
- uint64_t sc_lo3;
- uint64_t sc_pc;
- uint32_t sc_fpc_csr;
- uint32_t sc_used_math;
- uint32_t sc_dsp;
- uint32_t sc_reserved;
-};
-# endif /* O32 */
-
-struct sigframe {
- uint32_t sf_ass[4]; /* argument save space for o32 */
- uint32_t sf_code[2]; /* signal trampoline */
- struct target_sigcontext sf_sc;
- target_sigset_t sf_mask;
-};
-
-struct target_ucontext {
- target_ulong tuc_flags;
- target_ulong tuc_link;
- target_stack_t tuc_stack;
- target_ulong pad0;
- struct target_sigcontext tuc_mcontext;
- target_sigset_t tuc_sigmask;
-};
-
-struct target_rt_sigframe {
- uint32_t rs_ass[4]; /* argument save space for o32 */
- uint32_t rs_code[2]; /* signal trampoline */
- struct target_siginfo rs_info;
- struct target_ucontext rs_uc;
-};
-
-/* Install trampoline to jump back from signal handler */
-static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
-{
- int err = 0;
-
- /*
- * Set up the return code ...
- *
- * li v0, __NR__foo_sigreturn
- * syscall
- */
-
- __put_user(0x24020000 + syscall, tramp + 0);
- __put_user(0x0000000c , tramp + 1);
- return err;
-}
-
-static inline void setup_sigcontext(CPUMIPSState *regs,
- struct target_sigcontext *sc)
-{
- int i;
-
- __put_user(exception_resume_pc(regs), &sc->sc_pc);
- regs->hflags &= ~MIPS_HFLAG_BMASK;
-
- __put_user(0, &sc->sc_regs[0]);
- for (i = 1; i < 32; ++i) {
- __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
- }
-
- __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
- __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
-
- /* Rather than checking for dsp existence, always copy. The storage
- would just be garbage otherwise. */
- __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
- __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
- __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
- __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
- __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
- __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
- {
- uint32_t dsp = cpu_rddsp(0x3ff, regs);
- __put_user(dsp, &sc->sc_dsp);
- }
-
- __put_user(1, &sc->sc_used_math);
-
- for (i = 0; i < 32; ++i) {
- __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
- }
-}
-
-static inline void
-restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
-{
- int i;
-
- __get_user(regs->CP0_EPC, &sc->sc_pc);
-
- __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
- __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
-
- for (i = 1; i < 32; ++i) {
- __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
- }
-
- __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
- __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
- __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
- __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
- __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
- __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
- {
- uint32_t dsp;
- __get_user(dsp, &sc->sc_dsp);
- cpu_wrdsp(dsp, 0x3ff, regs);
- }
-
- for (i = 0; i < 32; ++i) {
- __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
- }
-}
-
-/*
- * Determine which stack to use..
- */
-static inline abi_ulong
-get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
-{
- unsigned long sp;
-
- /* Default to using normal stack */
- sp = regs->active_tc.gpr[29];
-
- /*
- * FPU emulator may have its own trampoline active just
- * above the user stack, 16-bytes before the next lowest
- * 16 byte boundary. Try to avoid trashing it.
- */
- sp -= 32;
-
- /* This is the X/Open sanctioned signal stack switching. */
- if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
- sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
- }
-
- return (sp - frame_size) & ~7;
-}
-
-static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
-{
- if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
- env->hflags &= ~MIPS_HFLAG_M16;
- env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
- env->active_tc.PC &= ~(target_ulong) 1;
- }
-}
-
-# if defined(TARGET_ABI_MIPSO32)
-/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
-static void setup_frame(int sig, struct target_sigaction * ka,
- target_sigset_t *set, CPUMIPSState *regs)
-{
- struct sigframe *frame;
- abi_ulong frame_addr;
- int i;
-
- frame_addr = get_sigframe(ka, regs, sizeof(*frame));
- trace_user_setup_frame(regs, frame_addr);
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto give_sigsegv;
- }
-
- install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
-
- setup_sigcontext(regs, &frame->sf_sc);
-
- for(i = 0; i < TARGET_NSIG_WORDS; i++) {
- __put_user(set->sig[i], &frame->sf_mask.sig[i]);
- }
-
- /*
- * Arguments to signal handler:
- *
- * a0 = signal number
- * a1 = 0 (should be cause)
- * a2 = pointer to struct sigcontext
- *
- * $25 and PC point to the signal handler, $29 points to the
- * struct sigframe.
- */
- regs->active_tc.gpr[ 4] = sig;
- regs->active_tc.gpr[ 5] = 0;
- regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
- regs->active_tc.gpr[29] = frame_addr;
- regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
- /* The original kernel code sets CP0_EPC to the handler
- * since it returns to userland using eret
- * we cannot do this here, and we must set PC directly */
- regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
- mips_set_hflags_isa_mode_from_pc(regs);
- unlock_user_struct(frame, frame_addr, 1);
- return;
-
-give_sigsegv:
- force_sigsegv(sig);
-}
-
-long do_sigreturn(CPUMIPSState *regs)
-{
- struct sigframe *frame;
- abi_ulong frame_addr;
- sigset_t blocked;
- target_sigset_t target_set;
- int i;
-
- frame_addr = regs->active_tc.gpr[29];
- trace_user_do_sigreturn(regs, frame_addr);
- if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
- goto badframe;
-
- for(i = 0; i < TARGET_NSIG_WORDS; i++) {
- __get_user(target_set.sig[i], &frame->sf_mask.sig[i]);
- }
-
- target_to_host_sigset_internal(&blocked, &target_set);
- set_sigmask(&blocked);
-
- restore_sigcontext(regs, &frame->sf_sc);
-
-#if 0
- /*
- * Don't let your children do this ...
- */
- __asm__ __volatile__(
- "move\t$29, %0\n\t"
- "j\tsyscall_exit"
- :/* no outputs */
- :"r" (&regs));
- /* Unreached */
-#endif
-
- regs->active_tc.PC = regs->CP0_EPC;
- mips_set_hflags_isa_mode_from_pc(regs);
- /* I am not sure this is right, but it seems to work
- * maybe a problem with nested signals ? */
- regs->CP0_EPC = 0;
- return -TARGET_QEMU_ESIGRETURN;
-
-badframe:
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-# endif /* O32 */
-
-static void setup_rt_frame(int sig, struct target_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUMIPSState *env)
-{
- struct target_rt_sigframe *frame;
- abi_ulong frame_addr;
- int i;
-
- frame_addr = get_sigframe(ka, env, sizeof(*frame));
- trace_user_setup_rt_frame(env, frame_addr);
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto give_sigsegv;
- }
-
- install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
-
- tswap_siginfo(&frame->rs_info, info);
-
- __put_user(0, &frame->rs_uc.tuc_flags);
- __put_user(0, &frame->rs_uc.tuc_link);
- __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
- __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
- __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
- &frame->rs_uc.tuc_stack.ss_flags);
-
- setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
-
- for(i = 0; i < TARGET_NSIG_WORDS; i++) {
- __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
- }
-
- /*
- * Arguments to signal handler:
- *
- * a0 = signal number
- * a1 = pointer to siginfo_t
- * a2 = pointer to ucontext_t
- *
- * $25 and PC point to the signal handler, $29 points to the
- * struct sigframe.
- */
- env->active_tc.gpr[ 4] = sig;
- env->active_tc.gpr[ 5] = frame_addr
- + offsetof(struct target_rt_sigframe, rs_info);
- env->active_tc.gpr[ 6] = frame_addr
- + offsetof(struct target_rt_sigframe, rs_uc);
- env->active_tc.gpr[29] = frame_addr;
- env->active_tc.gpr[31] = frame_addr
- + offsetof(struct target_rt_sigframe, rs_code);
- /* The original kernel code sets CP0_EPC to the handler
- * since it returns to userland using eret
- * we cannot do this here, and we must set PC directly */
- env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
- mips_set_hflags_isa_mode_from_pc(env);
- unlock_user_struct(frame, frame_addr, 1);
- return;
-
-give_sigsegv:
- unlock_user_struct(frame, frame_addr, 1);
- force_sigsegv(sig);
-}
-
-long do_rt_sigreturn(CPUMIPSState *env)
-{
- struct target_rt_sigframe *frame;
- abi_ulong frame_addr;
- sigset_t blocked;
-
- frame_addr = env->active_tc.gpr[29];
- trace_user_do_rt_sigreturn(env, frame_addr);
- if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
- goto badframe;
- }
-
- target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
- set_sigmask(&blocked);
-
- restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
-
- if (do_sigaltstack(frame_addr +
- offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
- 0, get_sp_from_cpustate(env)) == -EFAULT)
- goto badframe;
-
- env->active_tc.PC = env->CP0_EPC;
- mips_set_hflags_isa_mode_from_pc(env);
- /* I am not sure this is right, but it seems to work
- * maybe a problem with nested signals ? */
- env->CP0_EPC = 0;
- return -TARGET_QEMU_ESIGRETURN;
-
-badframe:
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-
-#elif defined(TARGET_SH4)
-
-/*
- * code and data structures from linux kernel:
- * include/asm-sh/sigcontext.h
- * arch/sh/kernel/signal.c
- */
-
-struct target_sigcontext {
- target_ulong oldmask;
-
- /* CPU registers */
- target_ulong sc_gregs[16];
- target_ulong sc_pc;
- target_ulong sc_pr;
- target_ulong sc_sr;
- target_ulong sc_gbr;
- target_ulong sc_mach;
- target_ulong sc_macl;
-
- /* FPU registers */
- target_ulong sc_fpregs[16];
- target_ulong sc_xfpregs[16];
- unsigned int sc_fpscr;
- unsigned int sc_fpul;
- unsigned int sc_ownedfp;
-};
-
-struct target_sigframe
-{
- struct target_sigcontext sc;
- target_ulong extramask[TARGET_NSIG_WORDS-1];
- uint16_t retcode[3];
-};
-
-
-struct target_ucontext {
- target_ulong tuc_flags;
- struct target_ucontext *tuc_link;
- target_stack_t tuc_stack;
- struct target_sigcontext tuc_mcontext;
- target_sigset_t tuc_sigmask; /* mask last for extensibility */
-};
-
-struct target_rt_sigframe
-{
- struct target_siginfo info;
- struct target_ucontext uc;
- uint16_t retcode[3];
-};
-
-
-#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
-#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */
-
-static abi_ulong get_sigframe(struct target_sigaction *ka,
- unsigned long sp, size_t frame_size)
-{
- if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
- sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
- }
-
- return (sp - frame_size) & -8ul;
-}
-
-/* Notice when we're in the middle of a gUSA region and reset.
- Note that this will only occur for !parallel_cpus, as we will
- translate such sequences differently in a parallel context. */
-static void unwind_gusa(CPUSH4State *regs)
-{
- /* If the stack pointer is sufficiently negative, and we haven't
- completed the sequence, then reset to the entry to the region. */
- /* ??? The SH4 kernel checks for and address above 0xC0000000.
- However, the page mappings in qemu linux-user aren't as restricted
- and we wind up with the normal stack mapped above 0xF0000000.
- That said, there is no reason why the kernel should be allowing
- a gUSA region that spans 1GB. Use a tighter check here, for what
- can actually be enabled by the immediate move. */
- if (regs->gregs[15] >= -128u && regs->pc < regs->gregs[0]) {
- /* Reset the PC to before the gUSA region, as computed from
- R0 = region end, SP = -(region size), plus one more for the
- insn that actually initializes SP to the region size. */
- regs->pc = regs->gregs[0] + regs->gregs[15] - 2;
-
- /* Reset the SP to the saved version in R1. */
- regs->gregs[15] = regs->gregs[1];
- }
-}
-
-static void setup_sigcontext(struct target_sigcontext *sc,
- CPUSH4State *regs, unsigned long mask)
-{
- int i;
-
-#define COPY(x) __put_user(regs->x, &sc->sc_##x)
- COPY(gregs[0]); COPY(gregs[1]);
- COPY(gregs[2]); COPY(gregs[3]);
- COPY(gregs[4]); COPY(gregs[5]);
- COPY(gregs[6]); COPY(gregs[7]);
- COPY(gregs[8]); COPY(gregs[9]);
- COPY(gregs[10]); COPY(gregs[11]);
- COPY(gregs[12]); COPY(gregs[13]);
- COPY(gregs[14]); COPY(gregs[15]);
- COPY(gbr); COPY(mach);
- COPY(macl); COPY(pr);
- COPY(sr); COPY(pc);
-#undef COPY
-
- for (i=0; i<16; i++) {
- __put_user(regs->fregs[i], &sc->sc_fpregs[i]);
- }
- __put_user(regs->fpscr, &sc->sc_fpscr);
- __put_user(regs->fpul, &sc->sc_fpul);
-
- /* non-iBCS2 extensions.. */
- __put_user(mask, &sc->oldmask);
-}
-
-static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc)
-{
- int i;
-
-#define COPY(x) __get_user(regs->x, &sc->sc_##x)
- COPY(gregs[0]); COPY(gregs[1]);
- COPY(gregs[2]); COPY(gregs[3]);
- COPY(gregs[4]); COPY(gregs[5]);
- COPY(gregs[6]); COPY(gregs[7]);
- COPY(gregs[8]); COPY(gregs[9]);
- COPY(gregs[10]); COPY(gregs[11]);
- COPY(gregs[12]); COPY(gregs[13]);
- COPY(gregs[14]); COPY(gregs[15]);
- COPY(gbr); COPY(mach);
- COPY(macl); COPY(pr);
- COPY(sr); COPY(pc);
-#undef COPY
-
- for (i=0; i<16; i++) {
- __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
- }
- __get_user(regs->fpscr, &sc->sc_fpscr);
- __get_user(regs->fpul, &sc->sc_fpul);
-
- regs->tra = -1; /* disable syscall checks */
- regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK);
-}
-
-static void setup_frame(int sig, struct target_sigaction *ka,
- target_sigset_t *set, CPUSH4State *regs)
-{
- struct target_sigframe *frame;
- abi_ulong frame_addr;
- int i;
-
- unwind_gusa(regs);
-
- frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
- trace_user_setup_frame(regs, frame_addr);
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto give_sigsegv;
- }
-
- setup_sigcontext(&frame->sc, regs, set->sig[0]);
-
- for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
- __put_user(set->sig[i + 1], &frame->extramask[i]);
- }
-
- /* Set up to return from userspace. If provided, use a stub
- already in userspace. */
- if (ka->sa_flags & TARGET_SA_RESTORER) {
- regs->pr = (unsigned long) ka->sa_restorer;
- } else {
- /* Generate return code (system call to sigreturn) */
- abi_ulong retcode_addr = frame_addr +
- offsetof(struct target_sigframe, retcode);
- __put_user(MOVW(2), &frame->retcode[0]);
- __put_user(TRAP_NOARG, &frame->retcode[1]);
- __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
- regs->pr = (unsigned long) retcode_addr;
- }
-
- /* Set up registers for signal handler */
- regs->gregs[15] = frame_addr;
- regs->gregs[4] = sig; /* Arg for signal handler */
- regs->gregs[5] = 0;
- regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc);
- regs->pc = (unsigned long) ka->_sa_handler;
- regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK);
-
- unlock_user_struct(frame, frame_addr, 1);
- return;
-
-give_sigsegv:
- unlock_user_struct(frame, frame_addr, 1);
- force_sigsegv(sig);
-}
-
-static void setup_rt_frame(int sig, struct target_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUSH4State *regs)
-{
- struct target_rt_sigframe *frame;
- abi_ulong frame_addr;
- int i;
-
- unwind_gusa(regs);
-
- frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
- trace_user_setup_rt_frame(regs, frame_addr);
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto give_sigsegv;
- }
-
- tswap_siginfo(&frame->info, info);
-
- /* Create the ucontext. */
- __put_user(0, &frame->uc.tuc_flags);
- __put_user(0, (unsigned long *)&frame->uc.tuc_link);
- __put_user((unsigned long)target_sigaltstack_used.ss_sp,
- &frame->uc.tuc_stack.ss_sp);
- __put_user(sas_ss_flags(regs->gregs[15]),
- &frame->uc.tuc_stack.ss_flags);
- __put_user(target_sigaltstack_used.ss_size,
- &frame->uc.tuc_stack.ss_size);
- setup_sigcontext(&frame->uc.tuc_mcontext,
- regs, set->sig[0]);
- for(i = 0; i < TARGET_NSIG_WORDS; i++) {
- __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
- }
-
- /* Set up to return from userspace. If provided, use a stub
- already in userspace. */
- if (ka->sa_flags & TARGET_SA_RESTORER) {
- regs->pr = (unsigned long) ka->sa_restorer;
- } else {
- /* Generate return code (system call to sigreturn) */
- abi_ulong retcode_addr = frame_addr +
- offsetof(struct target_rt_sigframe, retcode);
- __put_user(MOVW(2), &frame->retcode[0]);
- __put_user(TRAP_NOARG, &frame->retcode[1]);
- __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
- regs->pr = (unsigned long) retcode_addr;
- }
-
- /* Set up registers for signal handler */
- regs->gregs[15] = frame_addr;
- regs->gregs[4] = sig; /* Arg for signal handler */
- regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info);
- regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc);
- regs->pc = (unsigned long) ka->_sa_handler;
- regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK);
-
- unlock_user_struct(frame, frame_addr, 1);
- return;
-
-give_sigsegv:
- unlock_user_struct(frame, frame_addr, 1);
- force_sigsegv(sig);
-}
-
-long do_sigreturn(CPUSH4State *regs)
-{
- struct target_sigframe *frame;
- abi_ulong frame_addr;
- sigset_t blocked;
- target_sigset_t target_set;
- int i;
- int err = 0;
-
- frame_addr = regs->gregs[15];
- trace_user_do_sigreturn(regs, frame_addr);
- if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
- goto badframe;
- }
-
- __get_user(target_set.sig[0], &frame->sc.oldmask);
- for(i = 1; i < TARGET_NSIG_WORDS; i++) {
- __get_user(target_set.sig[i], &frame->extramask[i - 1]);
- }
-
- if (err)
- goto badframe;
-
- target_to_host_sigset_internal(&blocked, &target_set);
- set_sigmask(&blocked);
-
- restore_sigcontext(regs, &frame->sc);
-
- unlock_user_struct(frame, frame_addr, 0);
- return -TARGET_QEMU_ESIGRETURN;
-
-badframe:
- unlock_user_struct(frame, frame_addr, 0);
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-
-long do_rt_sigreturn(CPUSH4State *regs)
-{
- struct target_rt_sigframe *frame;
- abi_ulong frame_addr;
- sigset_t blocked;
-
- frame_addr = regs->gregs[15];
- trace_user_do_rt_sigreturn(regs, frame_addr);
- if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
- goto badframe;
- }
-
- target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask);
- set_sigmask(&blocked);
-
- restore_sigcontext(regs, &frame->uc.tuc_mcontext);
-
- if (do_sigaltstack(frame_addr +
- offsetof(struct target_rt_sigframe, uc.tuc_stack),
- 0, get_sp_from_cpustate(regs)) == -EFAULT) {
- goto badframe;
- }
-
- unlock_user_struct(frame, frame_addr, 0);
- return -TARGET_QEMU_ESIGRETURN;
-
-badframe:
- unlock_user_struct(frame, frame_addr, 0);
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-#elif defined(TARGET_MICROBLAZE)
-
-struct target_sigcontext {
- struct target_pt_regs regs; /* needs to be first */
- uint32_t oldmask;
-};
-
-struct target_stack_t {
- abi_ulong ss_sp;
- int ss_flags;
- unsigned int ss_size;
-};
-
-struct target_ucontext {
- abi_ulong tuc_flags;
- abi_ulong tuc_link;
- struct target_stack_t tuc_stack;
- struct target_sigcontext tuc_mcontext;
- uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1];
-};
-
-/* Signal frames. */
-struct target_signal_frame {
- struct target_ucontext uc;
- uint32_t extramask[TARGET_NSIG_WORDS - 1];
- uint32_t tramp[2];
-};
-
-struct rt_signal_frame {
- siginfo_t info;
- ucontext_t uc;
- uint32_t tramp[2];
-};
-
-static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
-{
- __put_user(env->regs[0], &sc->regs.r0);
- __put_user(env->regs[1], &sc->regs.r1);
- __put_user(env->regs[2], &sc->regs.r2);
- __put_user(env->regs[3], &sc->regs.r3);
- __put_user(env->regs[4], &sc->regs.r4);
- __put_user(env->regs[5], &sc->regs.r5);
- __put_user(env->regs[6], &sc->regs.r6);
- __put_user(env->regs[7], &sc->regs.r7);
- __put_user(env->regs[8], &sc->regs.r8);
- __put_user(env->regs[9], &sc->regs.r9);
- __put_user(env->regs[10], &sc->regs.r10);
- __put_user(env->regs[11], &sc->regs.r11);
- __put_user(env->regs[12], &sc->regs.r12);
- __put_user(env->regs[13], &sc->regs.r13);
- __put_user(env->regs[14], &sc->regs.r14);
- __put_user(env->regs[15], &sc->regs.r15);
- __put_user(env->regs[16], &sc->regs.r16);
- __put_user(env->regs[17], &sc->regs.r17);
- __put_user(env->regs[18], &sc->regs.r18);
- __put_user(env->regs[19], &sc->regs.r19);
- __put_user(env->regs[20], &sc->regs.r20);
- __put_user(env->regs[21], &sc->regs.r21);
- __put_user(env->regs[22], &sc->regs.r22);
- __put_user(env->regs[23], &sc->regs.r23);
- __put_user(env->regs[24], &sc->regs.r24);
- __put_user(env->regs[25], &sc->regs.r25);
- __put_user(env->regs[26], &sc->regs.r26);
- __put_user(env->regs[27], &sc->regs.r27);
- __put_user(env->regs[28], &sc->regs.r28);
- __put_user(env->regs[29], &sc->regs.r29);
- __put_user(env->regs[30], &sc->regs.r30);
- __put_user(env->regs[31], &sc->regs.r31);
- __put_user(env->sregs[SR_PC], &sc->regs.pc);
-}
-
-static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
-{
- __get_user(env->regs[0], &sc->regs.r0);
- __get_user(env->regs[1], &sc->regs.r1);
- __get_user(env->regs[2], &sc->regs.r2);
- __get_user(env->regs[3], &sc->regs.r3);
- __get_user(env->regs[4], &sc->regs.r4);
- __get_user(env->regs[5], &sc->regs.r5);
- __get_user(env->regs[6], &sc->regs.r6);
- __get_user(env->regs[7], &sc->regs.r7);
- __get_user(env->regs[8], &sc->regs.r8);
- __get_user(env->regs[9], &sc->regs.r9);
- __get_user(env->regs[10], &sc->regs.r10);
- __get_user(env->regs[11], &sc->regs.r11);
- __get_user(env->regs[12], &sc->regs.r12);
- __get_user(env->regs[13], &sc->regs.r13);
- __get_user(env->regs[14], &sc->regs.r14);
- __get_user(env->regs[15], &sc->regs.r15);
- __get_user(env->regs[16], &sc->regs.r16);
- __get_user(env->regs[17], &sc->regs.r17);
- __get_user(env->regs[18], &sc->regs.r18);
- __get_user(env->regs[19], &sc->regs.r19);
- __get_user(env->regs[20], &sc->regs.r20);
- __get_user(env->regs[21], &sc->regs.r21);
- __get_user(env->regs[22], &sc->regs.r22);
- __get_user(env->regs[23], &sc->regs.r23);
- __get_user(env->regs[24], &sc->regs.r24);
- __get_user(env->regs[25], &sc->regs.r25);
- __get_user(env->regs[26], &sc->regs.r26);
- __get_user(env->regs[27], &sc->regs.r27);
- __get_user(env->regs[28], &sc->regs.r28);
- __get_user(env->regs[29], &sc->regs.r29);
- __get_user(env->regs[30], &sc->regs.r30);
- __get_user(env->regs[31], &sc->regs.r31);
- __get_user(env->sregs[SR_PC], &sc->regs.pc);
-}
-
-static abi_ulong get_sigframe(struct target_sigaction *ka,
- CPUMBState *env, int frame_size)
-{
- abi_ulong sp = env->regs[1];
-
- if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !on_sig_stack(sp)) {
- sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
- }
-
- return ((sp - frame_size) & -8UL);
-}
-
-static void setup_frame(int sig, struct target_sigaction *ka,
- target_sigset_t *set, CPUMBState *env)
-{
- struct target_signal_frame *frame;
- abi_ulong frame_addr;
- int i;
-
- frame_addr = get_sigframe(ka, env, sizeof *frame);
- trace_user_setup_frame(env, frame_addr);
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
- goto badframe;
-
- /* Save the mask. */
- __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask);
-
- for(i = 1; i < TARGET_NSIG_WORDS; i++) {
- __put_user(set->sig[i], &frame->extramask[i - 1]);
- }
-
- setup_sigcontext(&frame->uc.tuc_mcontext, env);
-
- /* Set up to return from userspace. If provided, use a stub
- already in userspace. */
- /* minus 8 is offset to cater for "rtsd r15,8" offset */
- if (ka->sa_flags & TARGET_SA_RESTORER) {
- env->regs[15] = ((unsigned long)ka->sa_restorer)-8;
- } else {
- uint32_t t;
- /* Note, these encodings are _big endian_! */
- /* addi r12, r0, __NR_sigreturn */
- t = 0x31800000UL | TARGET_NR_sigreturn;
- __put_user(t, frame->tramp + 0);
- /* brki r14, 0x8 */
- t = 0xb9cc0008UL;
- __put_user(t, frame->tramp + 1);
-
- /* Return from sighandler will jump to the tramp.
- Negative 8 offset because return is rtsd r15, 8 */
- env->regs[15] = frame_addr + offsetof(struct target_signal_frame, tramp)
- - 8;
- }
-
- /* Set up registers for signal handler */
- env->regs[1] = frame_addr;
- /* Signal handler args: */
- env->regs[5] = sig; /* Arg 0: signum */
- env->regs[6] = 0;
- /* arg 1: sigcontext */
- env->regs[7] = frame_addr += offsetof(typeof(*frame), uc);
-
- /* Offset of 4 to handle microblaze rtid r14, 0 */
- env->sregs[SR_PC] = (unsigned long)ka->_sa_handler;
-
- unlock_user_struct(frame, frame_addr, 1);
- return;
-badframe:
- force_sigsegv(sig);
-}
-
-static void setup_rt_frame(int sig, struct target_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUMBState *env)
-{
- fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n");
-}
-
-long do_sigreturn(CPUMBState *env)
-{
- struct target_signal_frame *frame;
- abi_ulong frame_addr;
- target_sigset_t target_set;
- sigset_t set;
- int i;
-
- frame_addr = env->regs[R_SP];
- trace_user_do_sigreturn(env, frame_addr);
- /* Make sure the guest isn't playing games. */
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
- goto badframe;
-
- /* Restore blocked signals */
- __get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask);
- for(i = 1; i < TARGET_NSIG_WORDS; i++) {
- __get_user(target_set.sig[i], &frame->extramask[i - 1]);
- }
- target_to_host_sigset_internal(&set, &target_set);
- set_sigmask(&set);
-
- restore_sigcontext(&frame->uc.tuc_mcontext, env);
- /* We got here through a sigreturn syscall, our path back is via an
- rtb insn so setup r14 for that. */
- env->regs[14] = env->sregs[SR_PC];
-
- unlock_user_struct(frame, frame_addr, 0);
- return -TARGET_QEMU_ESIGRETURN;
-badframe:
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-
-long do_rt_sigreturn(CPUMBState *env)
-{
- trace_user_do_rt_sigreturn(env, 0);
- fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n");
- return -TARGET_ENOSYS;
-}
-
-#elif defined(TARGET_CRIS)
-
-struct target_sigcontext {
- struct target_pt_regs regs; /* needs to be first */
- uint32_t oldmask;
- uint32_t usp; /* usp before stacking this gunk on it */
-};
-
-/* Signal frames. */
-struct target_signal_frame {
- struct target_sigcontext sc;
- uint32_t extramask[TARGET_NSIG_WORDS - 1];
- uint16_t retcode[4]; /* Trampoline code. */
-};
-
-struct rt_signal_frame {
- siginfo_t *pinfo;
- void *puc;
- siginfo_t info;
- ucontext_t uc;
- uint16_t retcode[4]; /* Trampoline code. */
-};
-
-static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
-{
- __put_user(env->regs[0], &sc->regs.r0);
- __put_user(env->regs[1], &sc->regs.r1);
- __put_user(env->regs[2], &sc->regs.r2);
- __put_user(env->regs[3], &sc->regs.r3);
- __put_user(env->regs[4], &sc->regs.r4);
- __put_user(env->regs[5], &sc->regs.r5);
- __put_user(env->regs[6], &sc->regs.r6);
- __put_user(env->regs[7], &sc->regs.r7);
- __put_user(env->regs[8], &sc->regs.r8);
- __put_user(env->regs[9], &sc->regs.r9);
- __put_user(env->regs[10], &sc->regs.r10);
- __put_user(env->regs[11], &sc->regs.r11);
- __put_user(env->regs[12], &sc->regs.r12);
- __put_user(env->regs[13], &sc->regs.r13);
- __put_user(env->regs[14], &sc->usp);
- __put_user(env->regs[15], &sc->regs.acr);
- __put_user(env->pregs[PR_MOF], &sc->regs.mof);
- __put_user(env->pregs[PR_SRP], &sc->regs.srp);
- __put_user(env->pc, &sc->regs.erp);
-}
-
-static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
-{
- __get_user(env->regs[0], &sc->regs.r0);
- __get_user(env->regs[1], &sc->regs.r1);
- __get_user(env->regs[2], &sc->regs.r2);
- __get_user(env->regs[3], &sc->regs.r3);
- __get_user(env->regs[4], &sc->regs.r4);
- __get_user(env->regs[5], &sc->regs.r5);
- __get_user(env->regs[6], &sc->regs.r6);
- __get_user(env->regs[7], &sc->regs.r7);
- __get_user(env->regs[8], &sc->regs.r8);
- __get_user(env->regs[9], &sc->regs.r9);
- __get_user(env->regs[10], &sc->regs.r10);
- __get_user(env->regs[11], &sc->regs.r11);
- __get_user(env->regs[12], &sc->regs.r12);
- __get_user(env->regs[13], &sc->regs.r13);
- __get_user(env->regs[14], &sc->usp);
- __get_user(env->regs[15], &sc->regs.acr);
- __get_user(env->pregs[PR_MOF], &sc->regs.mof);
- __get_user(env->pregs[PR_SRP], &sc->regs.srp);
- __get_user(env->pc, &sc->regs.erp);
-}
-
-static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
-{
- abi_ulong sp;
- /* Align the stack downwards to 4. */
- sp = (env->regs[R_SP] & ~3);
- return sp - framesize;
-}
-
-static void setup_frame(int sig, struct target_sigaction *ka,
- target_sigset_t *set, CPUCRISState *env)
-{
- struct target_signal_frame *frame;
- abi_ulong frame_addr;
- int i;
-
- frame_addr = get_sigframe(env, sizeof *frame);
- trace_user_setup_frame(env, frame_addr);
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
- goto badframe;
-
- /*
- * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
- * use this trampoline anymore but it sets it up for GDB.
- * In QEMU, using the trampoline simplifies things a bit so we use it.
- *
- * This is movu.w __NR_sigreturn, r9; break 13;
- */
- __put_user(0x9c5f, frame->retcode+0);
- __put_user(TARGET_NR_sigreturn,
- frame->retcode + 1);
- __put_user(0xe93d, frame->retcode + 2);
-
- /* Save the mask. */
- __put_user(set->sig[0], &frame->sc.oldmask);
-
- for(i = 1; i < TARGET_NSIG_WORDS; i++) {
- __put_user(set->sig[i], &frame->extramask[i - 1]);
- }
-
- setup_sigcontext(&frame->sc, env);
-
- /* Move the stack and setup the arguments for the handler. */
- env->regs[R_SP] = frame_addr;
- env->regs[10] = sig;
- env->pc = (unsigned long) ka->_sa_handler;
- /* Link SRP so the guest returns through the trampoline. */
- env->pregs[PR_SRP] = frame_addr + offsetof(typeof(*frame), retcode);
-
- unlock_user_struct(frame, frame_addr, 1);
- return;
-badframe:
- force_sigsegv(sig);
-}
-
-static void setup_rt_frame(int sig, struct target_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUCRISState *env)
-{
- fprintf(stderr, "CRIS setup_rt_frame: not implemented\n");
-}
-
-long do_sigreturn(CPUCRISState *env)
-{
- struct target_signal_frame *frame;
- abi_ulong frame_addr;
- target_sigset_t target_set;
- sigset_t set;
- int i;
-
- frame_addr = env->regs[R_SP];
- trace_user_do_sigreturn(env, frame_addr);
- /* Make sure the guest isn't playing games. */
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1)) {
- goto badframe;
- }
-
- /* Restore blocked signals */
- __get_user(target_set.sig[0], &frame->sc.oldmask);
- for(i = 1; i < TARGET_NSIG_WORDS; i++) {
- __get_user(target_set.sig[i], &frame->extramask[i - 1]);
- }
- target_to_host_sigset_internal(&set, &target_set);
- set_sigmask(&set);
-
- restore_sigcontext(&frame->sc, env);
- unlock_user_struct(frame, frame_addr, 0);
- return -TARGET_QEMU_ESIGRETURN;
-badframe:
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-
-long do_rt_sigreturn(CPUCRISState *env)
-{
- trace_user_do_rt_sigreturn(env, 0);
- fprintf(stderr, "CRIS do_rt_sigreturn: not implemented\n");
- return -TARGET_ENOSYS;
-}
-
-#elif defined(TARGET_NIOS2)
-
-#define MCONTEXT_VERSION 2
-
-struct target_sigcontext {
- int version;
- unsigned long gregs[32];
-};
-
-struct target_ucontext {
- abi_ulong tuc_flags;
- abi_ulong tuc_link;
- target_stack_t tuc_stack;
- struct target_sigcontext tuc_mcontext;
- target_sigset_t tuc_sigmask; /* mask last for extensibility */
-};
-
-struct target_rt_sigframe {
- struct target_siginfo info;
- struct target_ucontext uc;
-};
-
-static unsigned long sigsp(unsigned long sp, struct target_sigaction *ka)
-{
- if (unlikely((ka->sa_flags & SA_ONSTACK)) && !sas_ss_flags(sp)) {
-#ifdef CONFIG_STACK_GROWSUP
- return target_sigaltstack_used.ss_sp;
-#else
- return target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
-#endif
- }
- return sp;
-}
-
-static int rt_setup_ucontext(struct target_ucontext *uc, CPUNios2State *env)
-{
- unsigned long *gregs = uc->tuc_mcontext.gregs;
-
- __put_user(MCONTEXT_VERSION, &uc->tuc_mcontext.version);
- __put_user(env->regs[1], &gregs[0]);
- __put_user(env->regs[2], &gregs[1]);
- __put_user(env->regs[3], &gregs[2]);
- __put_user(env->regs[4], &gregs[3]);
- __put_user(env->regs[5], &gregs[4]);
- __put_user(env->regs[6], &gregs[5]);
- __put_user(env->regs[7], &gregs[6]);
- __put_user(env->regs[8], &gregs[7]);
- __put_user(env->regs[9], &gregs[8]);
- __put_user(env->regs[10], &gregs[9]);
- __put_user(env->regs[11], &gregs[10]);
- __put_user(env->regs[12], &gregs[11]);
- __put_user(env->regs[13], &gregs[12]);
- __put_user(env->regs[14], &gregs[13]);
- __put_user(env->regs[15], &gregs[14]);
- __put_user(env->regs[16], &gregs[15]);
- __put_user(env->regs[17], &gregs[16]);
- __put_user(env->regs[18], &gregs[17]);
- __put_user(env->regs[19], &gregs[18]);
- __put_user(env->regs[20], &gregs[19]);
- __put_user(env->regs[21], &gregs[20]);
- __put_user(env->regs[22], &gregs[21]);
- __put_user(env->regs[23], &gregs[22]);
- __put_user(env->regs[R_RA], &gregs[23]);
- __put_user(env->regs[R_FP], &gregs[24]);
- __put_user(env->regs[R_GP], &gregs[25]);
- __put_user(env->regs[R_EA], &gregs[27]);
- __put_user(env->regs[R_SP], &gregs[28]);
-
- return 0;
-}
-
-static int rt_restore_ucontext(CPUNios2State *env, struct target_ucontext *uc,
- int *pr2)
-{
- int temp;
- abi_ulong off, frame_addr = env->regs[R_SP];
- unsigned long *gregs = uc->tuc_mcontext.gregs;
- int err;
-
- /* Always make any pending restarted system calls return -EINTR */
- /* current->restart_block.fn = do_no_restart_syscall; */
-
- __get_user(temp, &uc->tuc_mcontext.version);
- if (temp != MCONTEXT_VERSION) {
- return 1;
- }
-
- /* restore passed registers */
- __get_user(env->regs[1], &gregs[0]);
- __get_user(env->regs[2], &gregs[1]);
- __get_user(env->regs[3], &gregs[2]);
- __get_user(env->regs[4], &gregs[3]);
- __get_user(env->regs[5], &gregs[4]);
- __get_user(env->regs[6], &gregs[5]);
- __get_user(env->regs[7], &gregs[6]);
- __get_user(env->regs[8], &gregs[7]);
- __get_user(env->regs[9], &gregs[8]);
- __get_user(env->regs[10], &gregs[9]);
- __get_user(env->regs[11], &gregs[10]);
- __get_user(env->regs[12], &gregs[11]);
- __get_user(env->regs[13], &gregs[12]);
- __get_user(env->regs[14], &gregs[13]);
- __get_user(env->regs[15], &gregs[14]);
- __get_user(env->regs[16], &gregs[15]);
- __get_user(env->regs[17], &gregs[16]);
- __get_user(env->regs[18], &gregs[17]);
- __get_user(env->regs[19], &gregs[18]);
- __get_user(env->regs[20], &gregs[19]);
- __get_user(env->regs[21], &gregs[20]);
- __get_user(env->regs[22], &gregs[21]);
- __get_user(env->regs[23], &gregs[22]);
- /* gregs[23] is handled below */
- /* Verify, should this be settable */
- __get_user(env->regs[R_FP], &gregs[24]);
- /* Verify, should this be settable */
- __get_user(env->regs[R_GP], &gregs[25]);
- /* Not really necessary no user settable bits */
- __get_user(temp, &gregs[26]);
- __get_user(env->regs[R_EA], &gregs[27]);
-
- __get_user(env->regs[R_RA], &gregs[23]);
- __get_user(env->regs[R_SP], &gregs[28]);
-
- off = offsetof(struct target_rt_sigframe, uc.tuc_stack);
- err = do_sigaltstack(frame_addr + off, 0, get_sp_from_cpustate(env));
- if (err == -EFAULT) {
- return 1;
- }
-
- *pr2 = env->regs[2];
- return 0;
-}
-
-static void *get_sigframe(struct target_sigaction *ka, CPUNios2State *env,
- size_t frame_size)
-{
- unsigned long usp;
-
- /* Default to using normal stack. */
- usp = env->regs[R_SP];
-
- /* This is the X/Open sanctioned signal stack switching. */
- usp = sigsp(usp, ka);
-
- /* Verify, is it 32 or 64 bit aligned */
- return (void *)((usp - frame_size) & -8UL);
-}
-
-static void setup_rt_frame(int sig, struct target_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set,
- CPUNios2State *env)
-{
- struct target_rt_sigframe *frame;
- int i, err = 0;
-
- frame = get_sigframe(ka, env, sizeof(*frame));
-
- if (ka->sa_flags & SA_SIGINFO) {
- tswap_siginfo(&frame->info, info);
- }
-
- /* Create the ucontext. */
- __put_user(0, &frame->uc.tuc_flags);
- __put_user(0, &frame->uc.tuc_link);
- __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
- __put_user(sas_ss_flags(env->regs[R_SP]), &frame->uc.tuc_stack.ss_flags);
- __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
- err |= rt_setup_ucontext(&frame->uc, env);
- for (i = 0; i < TARGET_NSIG_WORDS; i++) {
- __put_user((abi_ulong)set->sig[i],
- (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
- }
-
- if (err) {
- goto give_sigsegv;
- }
-
- /* Set up to return from userspace; jump to fixed address sigreturn
- trampoline on kuser page. */
- env->regs[R_RA] = (unsigned long) (0x1044);
-
- /* Set up registers for signal handler */
- env->regs[R_SP] = (unsigned long) frame;
- env->regs[4] = (unsigned long) sig;
- env->regs[5] = (unsigned long) &frame->info;
- env->regs[6] = (unsigned long) &frame->uc;
- env->regs[R_EA] = (unsigned long) ka->_sa_handler;
- return;
-
-give_sigsegv:
- if (sig == TARGET_SIGSEGV) {
- ka->_sa_handler = TARGET_SIG_DFL;
- }
- force_sigsegv(sig);
- return;
-}
-
-long do_sigreturn(CPUNios2State *env)
-{
- trace_user_do_sigreturn(env, 0);
- fprintf(stderr, "do_sigreturn: not implemented\n");
- return -TARGET_ENOSYS;
-}
-
-long do_rt_sigreturn(CPUNios2State *env)
-{
- /* Verify, can we follow the stack back */
- abi_ulong frame_addr = env->regs[R_SP];
- struct target_rt_sigframe *frame;
- sigset_t set;
- int rval;
-
- if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
- goto badframe;
- }
-
- target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
- do_sigprocmask(SIG_SETMASK, &set, NULL);
-
- if (rt_restore_ucontext(env, &frame->uc, &rval)) {
- goto badframe;
- }
-
- unlock_user_struct(frame, frame_addr, 0);
- return rval;
-
-badframe:
- unlock_user_struct(frame, frame_addr, 0);
- force_sig(TARGET_SIGSEGV);
- return 0;
-}
-/* TARGET_NIOS2 */
-
-#elif defined(TARGET_OPENRISC)
-
-struct target_sigcontext {
- struct target_pt_regs regs;
- abi_ulong oldmask;
- abi_ulong usp;
-};
-
-struct target_ucontext {
- abi_ulong tuc_flags;
- abi_ulong tuc_link;
- target_stack_t tuc_stack;
- struct target_sigcontext tuc_mcontext;
- target_sigset_t tuc_sigmask; /* mask last for extensibility */
-};
-
-struct target_rt_sigframe {
- abi_ulong pinfo;
- uint64_t puc;
- struct target_siginfo info;
- struct target_sigcontext sc;
- struct target_ucontext uc;
- unsigned char retcode[16]; /* trampoline code */
-};
-
-/* This is the asm-generic/ucontext.h version */
-#if 0
-static int restore_sigcontext(CPUOpenRISCState *regs,
- struct target_sigcontext *sc)
-{
- unsigned int err = 0;
- unsigned long old_usp;
-
- /* Alwys make any pending restarted system call return -EINTR */
- current_thread_info()->restart_block.fn = do_no_restart_syscall;
-
- /* restore the regs from &sc->regs (same as sc, since regs is first)
- * (sc is already checked for VERIFY_READ since the sigframe was
- * checked in sys_sigreturn previously)
- */
-
- if (copy_from_user(regs, &sc, sizeof(struct target_pt_regs))) {
- goto badframe;
- }
-
- /* make sure the U-flag is set so user-mode cannot fool us */
-
- regs->sr &= ~SR_SM;
-
- /* restore the old USP as it was before we stacked the sc etc.
- * (we cannot just pop the sigcontext since we aligned the sp and
- * stuff after pushing it)
- */
-
- __get_user(old_usp, &sc->usp);
- phx_signal("old_usp 0x%lx", old_usp);
-
- __PHX__ REALLY /* ??? */
- wrusp(old_usp);
- regs->gpr[1] = old_usp;
-
- /* TODO: the other ports use regs->orig_XX to disable syscall checks
- * after this completes, but we don't use that mechanism. maybe we can
- * use it now ?
- */
-
- return err;
-
-badframe:
- return 1;
-}
-#endif
-
-/* Set up a signal frame. */
-
-static void setup_sigcontext(struct target_sigcontext *sc,
- CPUOpenRISCState *regs,
- unsigned long mask)
-{
- unsigned long usp = cpu_get_gpr(regs, 1);
-
- /* copy the regs. they are first in sc so we can use sc directly */
-
- /*copy_to_user(&sc, regs, sizeof(struct target_pt_regs));*/
-
- /* Set the frametype to CRIS_FRAME_NORMAL for the execution of
- the signal handler. The frametype will be restored to its previous
- value in restore_sigcontext. */
- /*regs->frametype = CRIS_FRAME_NORMAL;*/
-
- /* then some other stuff */
- __put_user(mask, &sc->oldmask);
- __put_user(usp, &sc->usp);
-}
-
-static inline unsigned long align_sigframe(unsigned long sp)
-{
- return sp & ~3UL;
-}
-
-static inline abi_ulong get_sigframe(struct target_sigaction *ka,
- CPUOpenRISCState *regs,
- size_t frame_size)
-{
- unsigned long sp = cpu_get_gpr(regs, 1);
- int onsigstack = on_sig_stack(sp);
-
- /* redzone */
- /* This is the X/Open sanctioned signal stack switching. */
- if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !onsigstack) {
- sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
- }
-
- sp = align_sigframe(sp - frame_size);
-
- /*
- * If we are on the alternate signal stack and would overflow it, don't.
- * Return an always-bogus address instead so we will die with SIGSEGV.
- */
-
- if (onsigstack && !likely(on_sig_stack(sp))) {
- return -1L;
- }
-
- return sp;
-}
-
-static void setup_rt_frame(int sig, struct target_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUOpenRISCState *env)
-{
- int err = 0;
- abi_ulong frame_addr;
- unsigned long return_ip;
- struct target_rt_sigframe *frame;
- abi_ulong info_addr, uc_addr;
-
- frame_addr = get_sigframe(ka, env, sizeof(*frame));
- trace_user_setup_rt_frame(env, frame_addr);
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto give_sigsegv;
- }
-
- info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
- __put_user(info_addr, &frame->pinfo);
- uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
- __put_user(uc_addr, &frame->puc);
-
- if (ka->sa_flags & SA_SIGINFO) {
- tswap_siginfo(&frame->info, info);
- }
-
- /*err |= __clear_user(&frame->uc, offsetof(ucontext_t, uc_mcontext));*/
- __put_user(0, &frame->uc.tuc_flags);
- __put_user(0, &frame->uc.tuc_link);
- __put_user(target_sigaltstack_used.ss_sp,
- &frame->uc.tuc_stack.ss_sp);
- __put_user(sas_ss_flags(cpu_get_gpr(env, 1)),
- &frame->uc.tuc_stack.ss_flags);
- __put_user(target_sigaltstack_used.ss_size,
- &frame->uc.tuc_stack.ss_size);
- setup_sigcontext(&frame->sc, env, set->sig[0]);
-
- /*err |= copy_to_user(frame->uc.tuc_sigmask, set, sizeof(*set));*/
-
- /* trampoline - the desired return ip is the retcode itself */
- return_ip = (unsigned long)&frame->retcode;
- /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
- __put_user(0xa960, (short *)(frame->retcode + 0));
- __put_user(TARGET_NR_rt_sigreturn, (short *)(frame->retcode + 2));
- __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
- __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
-
- if (err) {
- goto give_sigsegv;
- }
-
- /* TODO what is the current->exec_domain stuff and invmap ? */
-
- /* Set up registers for signal handler */
- env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
- cpu_set_gpr(env, 9, (unsigned long)return_ip); /* what we enter LATER */
- cpu_set_gpr(env, 3, (unsigned long)sig); /* arg 1: signo */
- cpu_set_gpr(env, 4, (unsigned long)&frame->info); /* arg 2: (siginfo_t*) */
- cpu_set_gpr(env, 5, (unsigned long)&frame->uc); /* arg 3: ucontext */
-
- /* actually move the usp to reflect the stacked frame */
- cpu_set_gpr(env, 1, (unsigned long)frame);
-
- return;
-
-give_sigsegv:
- unlock_user_struct(frame, frame_addr, 1);
- force_sigsegv(sig);
-}
-
-long do_sigreturn(CPUOpenRISCState *env)
-{
- trace_user_do_sigreturn(env, 0);
- fprintf(stderr, "do_sigreturn: not implemented\n");
- return -TARGET_ENOSYS;
-}
-
-long do_rt_sigreturn(CPUOpenRISCState *env)
-{
- trace_user_do_rt_sigreturn(env, 0);
- fprintf(stderr, "do_rt_sigreturn: not implemented\n");
- return -TARGET_ENOSYS;
-}
-/* TARGET_OPENRISC */
-
-#elif defined(TARGET_S390X)
-
-#define __NUM_GPRS 16
-#define __NUM_FPRS 16
-#define __NUM_ACRS 16
-
-#define S390_SYSCALL_SIZE 2
-#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */
-
-#define _SIGCONTEXT_NSIG 64
-#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */
-#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
-#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
-#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */
-#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
-
-typedef struct {
- target_psw_t psw;
- target_ulong gprs[__NUM_GPRS];
- unsigned int acrs[__NUM_ACRS];
-} target_s390_regs_common;
-
-typedef struct {
- unsigned int fpc;
- double fprs[__NUM_FPRS];
-} target_s390_fp_regs;
-
-typedef struct {
- target_s390_regs_common regs;
- target_s390_fp_regs fpregs;
-} target_sigregs;
-
-struct target_sigcontext {
- target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
- target_sigregs *sregs;
-};
-
-typedef struct {
- uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
- struct target_sigcontext sc;
- target_sigregs sregs;
- int signo;
- uint8_t retcode[S390_SYSCALL_SIZE];
-} sigframe;
-
-struct target_ucontext {
- target_ulong tuc_flags;
- struct target_ucontext *tuc_link;
- target_stack_t tuc_stack;
- target_sigregs tuc_mcontext;
- target_sigset_t tuc_sigmask; /* mask last for extensibility */
-};
-
-typedef struct {
- uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
- uint8_t retcode[S390_SYSCALL_SIZE];
- struct target_siginfo info;
- struct target_ucontext uc;
-} rt_sigframe;
-
-static inline abi_ulong
-get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
-{
- abi_ulong sp;
-
- /* Default to using normal stack */
- sp = env->regs[15];
-
- /* This is the X/Open sanctioned signal stack switching. */
- if (ka->sa_flags & TARGET_SA_ONSTACK) {
- if (!sas_ss_flags(sp)) {
- sp = target_sigaltstack_used.ss_sp +
- target_sigaltstack_used.ss_size;
- }
- }
-
- /* This is the legacy signal stack switching. */
- else if (/* FIXME !user_mode(regs) */ 0 &&
- !(ka->sa_flags & TARGET_SA_RESTORER) &&
- ka->sa_restorer) {
- sp = (abi_ulong) ka->sa_restorer;
- }
-
- return (sp - frame_size) & -8ul;
-}
-
-static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
-{
- int i;
- //save_access_regs(current->thread.acrs); FIXME
-
- /* Copy a 'clean' PSW mask to the user to avoid leaking
- information about whether PER is currently on. */
- __put_user(env->psw.mask, &sregs->regs.psw.mask);
- __put_user(env->psw.addr, &sregs->regs.psw.addr);
- for (i = 0; i < 16; i++) {
- __put_user(env->regs[i], &sregs->regs.gprs[i]);
- }
- for (i = 0; i < 16; i++) {
- __put_user(env->aregs[i], &sregs->regs.acrs[i]);
- }
- /*
- * We have to store the fp registers to current->thread.fp_regs
- * to merge them with the emulated registers.
- */
- //save_fp_regs(&current->thread.fp_regs); FIXME
- for (i = 0; i < 16; i++) {
- __put_user(get_freg(env, i)->ll, &sregs->fpregs.fprs[i]);
- }
-}
-
-static void setup_frame(int sig, struct target_sigaction *ka,
- target_sigset_t *set, CPUS390XState *env)
-{
- sigframe *frame;
- abi_ulong frame_addr;
-
- frame_addr = get_sigframe(ka, env, sizeof(*frame));
- trace_user_setup_frame(env, frame_addr);
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto give_sigsegv;
- }
-
- __put_user(set->sig[0], &frame->sc.oldmask[0]);
-
- save_sigregs(env, &frame->sregs);
-
- __put_user((abi_ulong)(unsigned long)&frame->sregs,
- (abi_ulong *)&frame->sc.sregs);
-
- /* Set up to return from userspace. If provided, use a stub
- already in userspace. */
- if (ka->sa_flags & TARGET_SA_RESTORER) {
- env->regs[14] = (unsigned long)
- ka->sa_restorer | PSW_ADDR_AMODE;
- } else {
- env->regs[14] = (frame_addr + offsetof(sigframe, retcode))
- | PSW_ADDR_AMODE;
- __put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
- (uint16_t *)(frame->retcode));
- }
-
- /* Set up backchain. */
- __put_user(env->regs[15], (abi_ulong *) frame);
-
- /* Set up registers for signal handler */
- env->regs[15] = frame_addr;
- env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
-
- env->regs[2] = sig; //map_signal(sig);
- env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
-
- /* We forgot to include these in the sigcontext.
- To avoid breaking binary compatibility, they are passed as args. */
- env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
- env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
-
- /* Place signal number on stack to allow backtrace from handler. */
- __put_user(env->regs[2], &frame->signo);
- unlock_user_struct(frame, frame_addr, 1);
- return;
-
-give_sigsegv:
- force_sigsegv(sig);
-}
-
-static void setup_rt_frame(int sig, struct target_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUS390XState *env)
-{
- int i;
- rt_sigframe *frame;
- abi_ulong frame_addr;
-
- frame_addr = get_sigframe(ka, env, sizeof *frame);
- trace_user_setup_rt_frame(env, frame_addr);
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto give_sigsegv;
- }
-
- tswap_siginfo(&frame->info, info);
-
- /* Create the ucontext. */
- __put_user(0, &frame->uc.tuc_flags);
- __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
- __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
- __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
- &frame->uc.tuc_stack.ss_flags);
- __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
- save_sigregs(env, &frame->uc.tuc_mcontext);
- for (i = 0; i < TARGET_NSIG_WORDS; i++) {
- __put_user((abi_ulong)set->sig[i],
- (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
- }
-
- /* Set up to return from userspace. If provided, use a stub
- already in userspace. */
- if (ka->sa_flags & TARGET_SA_RESTORER) {
- env->regs[14] = (unsigned long) ka->sa_restorer | PSW_ADDR_AMODE;
- } else {
- env->regs[14] = (unsigned long) frame->retcode | PSW_ADDR_AMODE;
- __put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
- (uint16_t *)(frame->retcode));
- }
-
- /* Set up backchain. */
- __put_user(env->regs[15], (abi_ulong *) frame);
-
- /* Set up registers for signal handler */
- env->regs[15] = frame_addr;
- env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
-
- env->regs[2] = sig; //map_signal(sig);
- env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
- env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
- return;
-
-give_sigsegv:
- force_sigsegv(sig);
-}
-
-static int
-restore_sigregs(CPUS390XState *env, target_sigregs *sc)
-{
- int err = 0;
- int i;
-
- for (i = 0; i < 16; i++) {
- __get_user(env->regs[i], &sc->regs.gprs[i]);
- }
-
- __get_user(env->psw.mask, &sc->regs.psw.mask);
- trace_user_s390x_restore_sigregs(env, (unsigned long long)sc->regs.psw.addr,
- (unsigned long long)env->psw.addr);
- __get_user(env->psw.addr, &sc->regs.psw.addr);
- /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
-
- for (i = 0; i < 16; i++) {
- __get_user(env->aregs[i], &sc->regs.acrs[i]);
- }
- for (i = 0; i < 16; i++) {
- __get_user(get_freg(env, i)->ll, &sc->fpregs.fprs[i]);
- }
-
- return err;
-}
-
-long do_sigreturn(CPUS390XState *env)
-{
- sigframe *frame;
- abi_ulong frame_addr = env->regs[15];
- target_sigset_t target_set;
- sigset_t set;
-
- trace_user_do_sigreturn(env, frame_addr);
- if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
- goto badframe;
- }
- __get_user(target_set.sig[0], &frame->sc.oldmask[0]);
-
- target_to_host_sigset_internal(&set, &target_set);
- set_sigmask(&set); /* ~_BLOCKABLE? */
-
- if (restore_sigregs(env, &frame->sregs)) {
- goto badframe;
- }
-
- unlock_user_struct(frame, frame_addr, 0);
- return -TARGET_QEMU_ESIGRETURN;
-
-badframe:
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-
-long do_rt_sigreturn(CPUS390XState *env)
-{
- rt_sigframe *frame;
- abi_ulong frame_addr = env->regs[15];
- sigset_t set;
-
- trace_user_do_rt_sigreturn(env, frame_addr);
- if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
- goto badframe;
- }
- target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
-
- set_sigmask(&set); /* ~_BLOCKABLE? */
-
- if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
- goto badframe;
- }
-
- if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
- get_sp_from_cpustate(env)) == -EFAULT) {
- goto badframe;
- }
- unlock_user_struct(frame, frame_addr, 0);
- return -TARGET_QEMU_ESIGRETURN;
-
-badframe:
- unlock_user_struct(frame, frame_addr, 0);
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-
-#elif defined(TARGET_PPC)
-
-/* Size of dummy stack frame allocated when calling signal handler.
- See arch/powerpc/include/asm/ptrace.h. */
-#if defined(TARGET_PPC64)
-#define SIGNAL_FRAMESIZE 128
-#else
-#define SIGNAL_FRAMESIZE 64
-#endif
-
-/* See arch/powerpc/include/asm/ucontext.h. Only used for 32-bit PPC;
- on 64-bit PPC, sigcontext and mcontext are one and the same. */
-struct target_mcontext {
- target_ulong mc_gregs[48];
- /* Includes fpscr. */
- uint64_t mc_fregs[33];
-#if defined(TARGET_PPC64)
- /* Pointer to the vector regs */
- target_ulong v_regs;
-#else
- target_ulong mc_pad[2];
-#endif
- /* We need to handle Altivec and SPE at the same time, which no
- kernel needs to do. Fortunately, the kernel defines this bit to
- be Altivec-register-large all the time, rather than trying to
- twiddle it based on the specific platform. */
- union {
- /* SPE vector registers. One extra for SPEFSCR. */
- uint32_t spe[33];
- /* Altivec vector registers. The packing of VSCR and VRSAVE
- varies depending on whether we're PPC64 or not: PPC64 splits
- them apart; PPC32 stuffs them together.
- We also need to account for the VSX registers on PPC64
- */
-#if defined(TARGET_PPC64)
-#define QEMU_NVRREG (34 + 16)
- /* On ppc64, this mcontext structure is naturally *unaligned*,
- * or rather it is aligned on a 8 bytes boundary but not on
- * a 16 bytes one. This pad fixes it up. This is also why the
- * vector regs are referenced by the v_regs pointer above so
- * any amount of padding can be added here
- */
- target_ulong pad;
-#else
- /* On ppc32, we are already aligned to 16 bytes */
-#define QEMU_NVRREG 33
-#endif
- /* We cannot use ppc_avr_t here as we do *not* want the implied
- * 16-bytes alignment that would result from it. This would have
- * the effect of making the whole struct target_mcontext aligned
- * which breaks the layout of struct target_ucontext on ppc64.
- */
- uint64_t altivec[QEMU_NVRREG][2];
-#undef QEMU_NVRREG
- } mc_vregs;
-};
-
-/* See arch/powerpc/include/asm/sigcontext.h. */
-struct target_sigcontext {
- target_ulong _unused[4];
- int32_t signal;
-#if defined(TARGET_PPC64)
- int32_t pad0;
-#endif
- target_ulong handler;
- target_ulong oldmask;
- target_ulong regs; /* struct pt_regs __user * */
-#if defined(TARGET_PPC64)
- struct target_mcontext mcontext;
-#endif
-};
-
-/* Indices for target_mcontext.mc_gregs, below.
- See arch/powerpc/include/asm/ptrace.h for details. */
-enum {
- TARGET_PT_R0 = 0,
- TARGET_PT_R1 = 1,
- TARGET_PT_R2 = 2,
- TARGET_PT_R3 = 3,
- TARGET_PT_R4 = 4,
- TARGET_PT_R5 = 5,
- TARGET_PT_R6 = 6,
- TARGET_PT_R7 = 7,
- TARGET_PT_R8 = 8,
- TARGET_PT_R9 = 9,
- TARGET_PT_R10 = 10,
- TARGET_PT_R11 = 11,
- TARGET_PT_R12 = 12,
- TARGET_PT_R13 = 13,
- TARGET_PT_R14 = 14,
- TARGET_PT_R15 = 15,
- TARGET_PT_R16 = 16,
- TARGET_PT_R17 = 17,
- TARGET_PT_R18 = 18,
- TARGET_PT_R19 = 19,
- TARGET_PT_R20 = 20,
- TARGET_PT_R21 = 21,
- TARGET_PT_R22 = 22,
- TARGET_PT_R23 = 23,
- TARGET_PT_R24 = 24,
- TARGET_PT_R25 = 25,
- TARGET_PT_R26 = 26,
- TARGET_PT_R27 = 27,
- TARGET_PT_R28 = 28,
- TARGET_PT_R29 = 29,
- TARGET_PT_R30 = 30,
- TARGET_PT_R31 = 31,
- TARGET_PT_NIP = 32,
- TARGET_PT_MSR = 33,
- TARGET_PT_ORIG_R3 = 34,
- TARGET_PT_CTR = 35,
- TARGET_PT_LNK = 36,
- TARGET_PT_XER = 37,
- TARGET_PT_CCR = 38,
- /* Yes, there are two registers with #39. One is 64-bit only. */
- TARGET_PT_MQ = 39,
- TARGET_PT_SOFTE = 39,
- TARGET_PT_TRAP = 40,
- TARGET_PT_DAR = 41,
- TARGET_PT_DSISR = 42,
- TARGET_PT_RESULT = 43,
- TARGET_PT_REGS_COUNT = 44
-};
-
-
-struct target_ucontext {
- target_ulong tuc_flags;
- target_ulong tuc_link; /* ucontext_t __user * */
- struct target_sigaltstack tuc_stack;
-#if !defined(TARGET_PPC64)
- int32_t tuc_pad[7];
- target_ulong tuc_regs; /* struct mcontext __user *
- points to uc_mcontext field */
-#endif
- target_sigset_t tuc_sigmask;
-#if defined(TARGET_PPC64)
- target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
- struct target_sigcontext tuc_sigcontext;
-#else
- int32_t tuc_maskext[30];
- int32_t tuc_pad2[3];
- struct target_mcontext tuc_mcontext;
-#endif
-};
-
-/* See arch/powerpc/kernel/signal_32.c. */
-struct target_sigframe {
- struct target_sigcontext sctx;
- struct target_mcontext mctx;
- int32_t abigap[56];
-};
-
-#if defined(TARGET_PPC64)
-
-#define TARGET_TRAMP_SIZE 6
-
-struct target_rt_sigframe {
- /* sys_rt_sigreturn requires the ucontext be the first field */
- struct target_ucontext uc;
- target_ulong _unused[2];
- uint32_t trampoline[TARGET_TRAMP_SIZE];
- target_ulong pinfo; /* struct siginfo __user * */
- target_ulong puc; /* void __user * */
- struct target_siginfo info;
- /* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
- char abigap[288];
-} __attribute__((aligned(16)));
-
-#else
-
-struct target_rt_sigframe {
- struct target_siginfo info;
- struct target_ucontext uc;
- int32_t abigap[56];
-};
-
-#endif
-
-#if defined(TARGET_PPC64)
-
-struct target_func_ptr {
- target_ulong entry;
- target_ulong toc;
-};
-
-#endif
-
-/* We use the mc_pad field for the signal return trampoline. */
-#define tramp mc_pad
-
-/* See arch/powerpc/kernel/signal.c. */
-static target_ulong get_sigframe(struct target_sigaction *ka,
- CPUPPCState *env,
- int frame_size)
-{
- target_ulong oldsp;
-
- oldsp = env->gpr[1];
-
- if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
- (sas_ss_flags(oldsp) == 0)) {
- oldsp = (target_sigaltstack_used.ss_sp
- + target_sigaltstack_used.ss_size);
- }
-
- return (oldsp - frame_size) & ~0xFUL;
-}
-
-#if ((defined(TARGET_WORDS_BIGENDIAN) && defined(HOST_WORDS_BIGENDIAN)) || \
- (!defined(HOST_WORDS_BIGENDIAN) && !defined(TARGET_WORDS_BIGENDIAN)))
-#define PPC_VEC_HI 0
-#define PPC_VEC_LO 1
-#else
-#define PPC_VEC_HI 1
-#define PPC_VEC_LO 0
-#endif
-
-
-static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame)
-{
- target_ulong msr = env->msr;
- int i;
- target_ulong ccr = 0;
-
- /* In general, the kernel attempts to be intelligent about what it
- needs to save for Altivec/FP/SPE registers. We don't care that
- much, so we just go ahead and save everything. */
-
- /* Save general registers. */
- for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
- __put_user(env->gpr[i], &frame->mc_gregs[i]);
- }
- __put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
- __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
- __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
- __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
-
- for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
- ccr |= env->crf[i] << (32 - ((i + 1) * 4));
- }
- __put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
-
- /* Save Altivec registers if necessary. */
- if (env->insns_flags & PPC_ALTIVEC) {
- uint32_t *vrsave;
- for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
- ppc_avr_t *avr = &env->avr[i];
- ppc_avr_t *vreg = (ppc_avr_t *)&frame->mc_vregs.altivec[i];
-
- __put_user(avr->u64[PPC_VEC_HI], &vreg->u64[0]);
- __put_user(avr->u64[PPC_VEC_LO], &vreg->u64[1]);
- }
- /* Set MSR_VR in the saved MSR value to indicate that
- frame->mc_vregs contains valid data. */
- msr |= MSR_VR;
-#if defined(TARGET_PPC64)
- vrsave = (uint32_t *)&frame->mc_vregs.altivec[33];
- /* 64-bit needs to put a pointer to the vectors in the frame */
- __put_user(h2g(frame->mc_vregs.altivec), &frame->v_regs);
-#else
- vrsave = (uint32_t *)&frame->mc_vregs.altivec[32];
-#endif
- __put_user((uint32_t)env->spr[SPR_VRSAVE], vrsave);
- }
-
- /* Save VSX second halves */
- if (env->insns_flags2 & PPC2_VSX) {
- uint64_t *vsregs = (uint64_t *)&frame->mc_vregs.altivec[34];
- for (i = 0; i < ARRAY_SIZE(env->vsr); i++) {
- __put_user(env->vsr[i], &vsregs[i]);
- }
- }
-
- /* Save floating point registers. */
- if (env->insns_flags & PPC_FLOAT) {
- for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
- __put_user(env->fpr[i], &frame->mc_fregs[i]);
- }
- __put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]);
- }
-
- /* Save SPE registers. The kernel only saves the high half. */
- if (env->insns_flags & PPC_SPE) {
-#if defined(TARGET_PPC64)
- for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
- __put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i]);
- }
-#else
- for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
- __put_user(env->gprh[i], &frame->mc_vregs.spe[i]);
- }
-#endif
- /* Set MSR_SPE in the saved MSR value to indicate that
- frame->mc_vregs contains valid data. */
- msr |= MSR_SPE;
- __put_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
- }
-
- /* Store MSR. */
- __put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
-}
-
-static void encode_trampoline(int sigret, uint32_t *tramp)
-{
- /* Set up the sigreturn trampoline: li r0,sigret; sc. */
- if (sigret) {
- __put_user(0x38000000 | sigret, &tramp[0]);
- __put_user(0x44000002, &tramp[1]);
- }
-}
-
-static void restore_user_regs(CPUPPCState *env,
- struct target_mcontext *frame, int sig)
-{
- target_ulong save_r2 = 0;
- target_ulong msr;
- target_ulong ccr;
-
- int i;
-
- if (!sig) {
- save_r2 = env->gpr[2];
- }
-
- /* Restore general registers. */
- for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
- __get_user(env->gpr[i], &frame->mc_gregs[i]);
- }
- __get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
- __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
- __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
- __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
- __get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
-
- for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
- env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
- }
-
- if (!sig) {
- env->gpr[2] = save_r2;
- }
- /* Restore MSR. */
- __get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
-
- /* If doing signal return, restore the previous little-endian mode. */
- if (sig)
- env->msr = (env->msr & ~(1ull << MSR_LE)) | (msr & (1ull << MSR_LE));
-
- /* Restore Altivec registers if necessary. */
- if (env->insns_flags & PPC_ALTIVEC) {
- ppc_avr_t *v_regs;
- uint32_t *vrsave;
-#if defined(TARGET_PPC64)
- uint64_t v_addr;
- /* 64-bit needs to recover the pointer to the vectors from the frame */
- __get_user(v_addr, &frame->v_regs);
- v_regs = g2h(v_addr);
-#else
- v_regs = (ppc_avr_t *)frame->mc_vregs.altivec;
-#endif
- for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
- ppc_avr_t *avr = &env->avr[i];
- ppc_avr_t *vreg = &v_regs[i];
-
- __get_user(avr->u64[PPC_VEC_HI], &vreg->u64[0]);
- __get_user(avr->u64[PPC_VEC_LO], &vreg->u64[1]);
- }
- /* Set MSR_VEC in the saved MSR value to indicate that
- frame->mc_vregs contains valid data. */
-#if defined(TARGET_PPC64)
- vrsave = (uint32_t *)&v_regs[33];
-#else
- vrsave = (uint32_t *)&v_regs[32];
-#endif
- __get_user(env->spr[SPR_VRSAVE], vrsave);
- }
-
- /* Restore VSX second halves */
- if (env->insns_flags2 & PPC2_VSX) {
- uint64_t *vsregs = (uint64_t *)&frame->mc_vregs.altivec[34];
- for (i = 0; i < ARRAY_SIZE(env->vsr); i++) {
- __get_user(env->vsr[i], &vsregs[i]);
- }
- }
-
- /* Restore floating point registers. */
- if (env->insns_flags & PPC_FLOAT) {
- uint64_t fpscr;
- for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
- __get_user(env->fpr[i], &frame->mc_fregs[i]);
- }
- __get_user(fpscr, &frame->mc_fregs[32]);
- env->fpscr = (uint32_t) fpscr;
- }
-
- /* Save SPE registers. The kernel only saves the high half. */
- if (env->insns_flags & PPC_SPE) {
-#if defined(TARGET_PPC64)
- for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
- uint32_t hi;
-
- __get_user(hi, &frame->mc_vregs.spe[i]);
- env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
- }
-#else
- for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
- __get_user(env->gprh[i], &frame->mc_vregs.spe[i]);
- }
-#endif
- __get_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
- }
-}
-
-#if !defined(TARGET_PPC64)
-static void setup_frame(int sig, struct target_sigaction *ka,
- target_sigset_t *set, CPUPPCState *env)
-{
- struct target_sigframe *frame;
- struct target_sigcontext *sc;
- target_ulong frame_addr, newsp;
- int err = 0;
-
- frame_addr = get_sigframe(ka, env, sizeof(*frame));
- trace_user_setup_frame(env, frame_addr);
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
- goto sigsegv;
- sc = &frame->sctx;
-
- __put_user(ka->_sa_handler, &sc->handler);
- __put_user(set->sig[0], &sc->oldmask);
- __put_user(set->sig[1], &sc->_unused[3]);
- __put_user(h2g(&frame->mctx), &sc->regs);
- __put_user(sig, &sc->signal);
-
- /* Save user regs. */
- save_user_regs(env, &frame->mctx);
-
- /* Construct the trampoline code on the stack. */
- encode_trampoline(TARGET_NR_sigreturn, (uint32_t *)&frame->mctx.tramp);
-
- /* The kernel checks for the presence of a VDSO here. We don't
- emulate a vdso, so use a sigreturn system call. */
- env->lr = (target_ulong) h2g(frame->mctx.tramp);
-
- /* Turn off all fp exceptions. */
- env->fpscr = 0;
-
- /* Create a stack frame for the caller of the handler. */
- newsp = frame_addr - SIGNAL_FRAMESIZE;
- err |= put_user(env->gpr[1], newsp, target_ulong);
-
- if (err)
- goto sigsegv;
-
- /* Set up registers for signal handler. */
- env->gpr[1] = newsp;
- env->gpr[3] = sig;
- env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
-
- env->nip = (target_ulong) ka->_sa_handler;
-
- /* Signal handlers are entered in big-endian mode. */
- env->msr &= ~(1ull << MSR_LE);
-
- unlock_user_struct(frame, frame_addr, 1);
- return;
-
-sigsegv:
- unlock_user_struct(frame, frame_addr, 1);
- force_sigsegv(sig);
-}
-#endif /* !defined(TARGET_PPC64) */
-
-static void setup_rt_frame(int sig, struct target_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUPPCState *env)
-{
- struct target_rt_sigframe *rt_sf;
- uint32_t *trampptr = 0;
- struct target_mcontext *mctx = 0;
- target_ulong rt_sf_addr, newsp = 0;
- int i, err = 0;
-#if defined(TARGET_PPC64)
- struct target_sigcontext *sc = 0;
- struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
-#endif
-
- rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
- if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
- goto sigsegv;
-
- tswap_siginfo(&rt_sf->info, info);
-
- __put_user(0, &rt_sf->uc.tuc_flags);
- __put_user(0, &rt_sf->uc.tuc_link);
- __put_user((target_ulong)target_sigaltstack_used.ss_sp,
- &rt_sf->uc.tuc_stack.ss_sp);
- __put_user(sas_ss_flags(env->gpr[1]),
- &rt_sf->uc.tuc_stack.ss_flags);
- __put_user(target_sigaltstack_used.ss_size,
- &rt_sf->uc.tuc_stack.ss_size);
-#if !defined(TARGET_PPC64)
- __put_user(h2g (&rt_sf->uc.tuc_mcontext),
- &rt_sf->uc.tuc_regs);
-#endif
- for(i = 0; i < TARGET_NSIG_WORDS; i++) {
- __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
- }
-
-#if defined(TARGET_PPC64)
- mctx = &rt_sf->uc.tuc_sigcontext.mcontext;
- trampptr = &rt_sf->trampoline[0];
-
- sc = &rt_sf->uc.tuc_sigcontext;
- __put_user(h2g(mctx), &sc->regs);
- __put_user(sig, &sc->signal);
-#else
- mctx = &rt_sf->uc.tuc_mcontext;
- trampptr = (uint32_t *)&rt_sf->uc.tuc_mcontext.tramp;
-#endif
-
- save_user_regs(env, mctx);
- encode_trampoline(TARGET_NR_rt_sigreturn, trampptr);
-
- /* The kernel checks for the presence of a VDSO here. We don't
- emulate a vdso, so use a sigreturn system call. */
- env->lr = (target_ulong) h2g(trampptr);
-
- /* Turn off all fp exceptions. */
- env->fpscr = 0;
-
- /* Create a stack frame for the caller of the handler. */
- newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
- err |= put_user(env->gpr[1], newsp, target_ulong);
-
- if (err)
- goto sigsegv;
-
- /* Set up registers for signal handler. */
- env->gpr[1] = newsp;
- env->gpr[3] = (target_ulong) sig;
- env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
- env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
- env->gpr[6] = (target_ulong) h2g(rt_sf);
-
-#if defined(TARGET_PPC64)
- if (get_ppc64_abi(image) < 2) {
- /* ELFv1 PPC64 function pointers are pointers to OPD entries. */
- struct target_func_ptr *handler =
- (struct target_func_ptr *)g2h(ka->_sa_handler);
- env->nip = tswapl(handler->entry);
- env->gpr[2] = tswapl(handler->toc);
- } else {
- /* ELFv2 PPC64 function pointers are entry points, but R12
- * must also be set */
- env->nip = tswapl((target_ulong) ka->_sa_handler);
- env->gpr[12] = env->nip;
- }
-#else
- env->nip = (target_ulong) ka->_sa_handler;
-#endif
-
- /* Signal handlers are entered in big-endian mode. */
- env->msr &= ~(1ull << MSR_LE);
-
- unlock_user_struct(rt_sf, rt_sf_addr, 1);
- return;
-
-sigsegv:
- unlock_user_struct(rt_sf, rt_sf_addr, 1);
- force_sigsegv(sig);
-
-}
-
-#if !defined(TARGET_PPC64)
-long do_sigreturn(CPUPPCState *env)
-{
- struct target_sigcontext *sc = NULL;
- struct target_mcontext *sr = NULL;
- target_ulong sr_addr = 0, sc_addr;
- sigset_t blocked;
- target_sigset_t set;
-
- sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
- if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
- goto sigsegv;
-
-#if defined(TARGET_PPC64)
- set.sig[0] = sc->oldmask + ((uint64_t)(sc->_unused[3]) << 32);
-#else
- __get_user(set.sig[0], &sc->oldmask);
- __get_user(set.sig[1], &sc->_unused[3]);
-#endif
- target_to_host_sigset_internal(&blocked, &set);
- set_sigmask(&blocked);
-
- __get_user(sr_addr, &sc->regs);
- if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
- goto sigsegv;
- restore_user_regs(env, sr, 1);
-
- unlock_user_struct(sr, sr_addr, 1);
- unlock_user_struct(sc, sc_addr, 1);
- return -TARGET_QEMU_ESIGRETURN;
-
-sigsegv:
- unlock_user_struct(sr, sr_addr, 1);
- unlock_user_struct(sc, sc_addr, 1);
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-#endif /* !defined(TARGET_PPC64) */
-
-/* See arch/powerpc/kernel/signal_32.c. */
-static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
-{
- struct target_mcontext *mcp;
- target_ulong mcp_addr;
- sigset_t blocked;
- target_sigset_t set;
-
- if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, tuc_sigmask),
- sizeof (set)))
- return 1;
-
-#if defined(TARGET_PPC64)
- mcp_addr = h2g(ucp) +
- offsetof(struct target_ucontext, tuc_sigcontext.mcontext);
-#else
- __get_user(mcp_addr, &ucp->tuc_regs);
-#endif
-
- if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
- return 1;
-
- target_to_host_sigset_internal(&blocked, &set);
- set_sigmask(&blocked);
- restore_user_regs(env, mcp, sig);
-
- unlock_user_struct(mcp, mcp_addr, 1);
- return 0;
-}
-
-long do_rt_sigreturn(CPUPPCState *env)
-{
- struct target_rt_sigframe *rt_sf = NULL;
- target_ulong rt_sf_addr;
-
- rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
- if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
- goto sigsegv;
-
- if (do_setcontext(&rt_sf->uc, env, 1))
- goto sigsegv;
-
- do_sigaltstack(rt_sf_addr
- + offsetof(struct target_rt_sigframe, uc.tuc_stack),
- 0, env->gpr[1]);
-
- unlock_user_struct(rt_sf, rt_sf_addr, 1);
- return -TARGET_QEMU_ESIGRETURN;
-
-sigsegv:
- unlock_user_struct(rt_sf, rt_sf_addr, 1);
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-
-#elif defined(TARGET_M68K)
-
-struct target_sigcontext {
- abi_ulong sc_mask;
- abi_ulong sc_usp;
- abi_ulong sc_d0;
- abi_ulong sc_d1;
- abi_ulong sc_a0;
- abi_ulong sc_a1;
- unsigned short sc_sr;
- abi_ulong sc_pc;
-};
-
-struct target_sigframe
-{
- abi_ulong pretcode;
- int sig;
- int code;
- abi_ulong psc;
- char retcode[8];
- abi_ulong extramask[TARGET_NSIG_WORDS-1];
- struct target_sigcontext sc;
-};
-
-typedef int target_greg_t;
-#define TARGET_NGREG 18
-typedef target_greg_t target_gregset_t[TARGET_NGREG];
-
-typedef struct target_fpregset {
- int f_fpcntl[3];
- int f_fpregs[8*3];
-} target_fpregset_t;
-
-struct target_mcontext {
- int version;
- target_gregset_t gregs;
- target_fpregset_t fpregs;
-};
-
-#define TARGET_MCONTEXT_VERSION 2
-
-struct target_ucontext {
- abi_ulong tuc_flags;
- abi_ulong tuc_link;
- target_stack_t tuc_stack;
- struct target_mcontext tuc_mcontext;
- abi_long tuc_filler[80];
- target_sigset_t tuc_sigmask;
-};
-
-struct target_rt_sigframe
-{
- abi_ulong pretcode;
- int sig;
- abi_ulong pinfo;
- abi_ulong puc;
- char retcode[8];
- struct target_siginfo info;
- struct target_ucontext uc;
-};
-
-static void setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env,
- abi_ulong mask)
-{
- uint32_t sr = (env->sr & 0xff00) | cpu_m68k_get_ccr(env);
- __put_user(mask, &sc->sc_mask);
- __put_user(env->aregs[7], &sc->sc_usp);
- __put_user(env->dregs[0], &sc->sc_d0);
- __put_user(env->dregs[1], &sc->sc_d1);
- __put_user(env->aregs[0], &sc->sc_a0);
- __put_user(env->aregs[1], &sc->sc_a1);
- __put_user(sr, &sc->sc_sr);
- __put_user(env->pc, &sc->sc_pc);
-}
-
-static void
-restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc)
-{
- int temp;
-
- __get_user(env->aregs[7], &sc->sc_usp);
- __get_user(env->dregs[0], &sc->sc_d0);
- __get_user(env->dregs[1], &sc->sc_d1);
- __get_user(env->aregs[0], &sc->sc_a0);
- __get_user(env->aregs[1], &sc->sc_a1);
- __get_user(env->pc, &sc->sc_pc);
- __get_user(temp, &sc->sc_sr);
- cpu_m68k_set_ccr(env, temp);
-}
-
-/*
- * Determine which stack to use..
- */
-static inline abi_ulong
-get_sigframe(struct target_sigaction *ka, CPUM68KState *regs,
- size_t frame_size)
-{
- unsigned long sp;
-
- sp = regs->aregs[7];
-
- /* This is the X/Open sanctioned signal stack switching. */
- if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
- sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
- }
-
- return ((sp - frame_size) & -8UL);
-}
-
-static void setup_frame(int sig, struct target_sigaction *ka,
- target_sigset_t *set, CPUM68KState *env)
-{
- struct target_sigframe *frame;
- abi_ulong frame_addr;
- abi_ulong retcode_addr;
- abi_ulong sc_addr;
- int i;
-
- frame_addr = get_sigframe(ka, env, sizeof *frame);
- trace_user_setup_frame(env, frame_addr);
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto give_sigsegv;
- }
-
- __put_user(sig, &frame->sig);
-
- sc_addr = frame_addr + offsetof(struct target_sigframe, sc);
- __put_user(sc_addr, &frame->psc);
-
- setup_sigcontext(&frame->sc, env, set->sig[0]);
-
- for(i = 1; i < TARGET_NSIG_WORDS; i++) {
- __put_user(set->sig[i], &frame->extramask[i - 1]);
- }
-
- /* Set up to return from userspace. */
-
- retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
- __put_user(retcode_addr, &frame->pretcode);
-
- /* moveq #,d0; trap #0 */
-
- __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16),
- (uint32_t *)(frame->retcode));
-
- /* Set up to return from userspace */
-
- env->aregs[7] = frame_addr;
- env->pc = ka->_sa_handler;
-
- unlock_user_struct(frame, frame_addr, 1);
- return;
-
-give_sigsegv:
- force_sigsegv(sig);
-}
-
-static inline void target_rt_save_fpu_state(struct target_ucontext *uc,
- CPUM68KState *env)
-{
- int i;
- target_fpregset_t *fpregs = &uc->tuc_mcontext.fpregs;
-
- __put_user(env->fpcr, &fpregs->f_fpcntl[0]);
- __put_user(env->fpsr, &fpregs->f_fpcntl[1]);
- /* fpiar is not emulated */
-
- for (i = 0; i < 8; i++) {
- uint32_t high = env->fregs[i].d.high << 16;
- __put_user(high, &fpregs->f_fpregs[i * 3]);
- __put_user(env->fregs[i].d.low,
- (uint64_t *)&fpregs->f_fpregs[i * 3 + 1]);
- }
-}
-
-static inline int target_rt_setup_ucontext(struct target_ucontext *uc,
- CPUM68KState *env)
-{
- target_greg_t *gregs = uc->tuc_mcontext.gregs;
- uint32_t sr = (env->sr & 0xff00) | cpu_m68k_get_ccr(env);
-
- __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version);
- __put_user(env->dregs[0], &gregs[0]);
- __put_user(env->dregs[1], &gregs[1]);
- __put_user(env->dregs[2], &gregs[2]);
- __put_user(env->dregs[3], &gregs[3]);
- __put_user(env->dregs[4], &gregs[4]);
- __put_user(env->dregs[5], &gregs[5]);
- __put_user(env->dregs[6], &gregs[6]);
- __put_user(env->dregs[7], &gregs[7]);
- __put_user(env->aregs[0], &gregs[8]);
- __put_user(env->aregs[1], &gregs[9]);
- __put_user(env->aregs[2], &gregs[10]);
- __put_user(env->aregs[3], &gregs[11]);
- __put_user(env->aregs[4], &gregs[12]);
- __put_user(env->aregs[5], &gregs[13]);
- __put_user(env->aregs[6], &gregs[14]);
- __put_user(env->aregs[7], &gregs[15]);
- __put_user(env->pc, &gregs[16]);
- __put_user(sr, &gregs[17]);
-
- target_rt_save_fpu_state(uc, env);
-
- return 0;
-}
-
-static inline void target_rt_restore_fpu_state(CPUM68KState *env,
- struct target_ucontext *uc)
-{
- int i;
- target_fpregset_t *fpregs = &uc->tuc_mcontext.fpregs;
- uint32_t fpcr;
-
- __get_user(fpcr, &fpregs->f_fpcntl[0]);
- cpu_m68k_set_fpcr(env, fpcr);
- __get_user(env->fpsr, &fpregs->f_fpcntl[1]);
- /* fpiar is not emulated */
-
- for (i = 0; i < 8; i++) {
- uint32_t high;
- __get_user(high, &fpregs->f_fpregs[i * 3]);
- env->fregs[i].d.high = high >> 16;
- __get_user(env->fregs[i].d.low,
- (uint64_t *)&fpregs->f_fpregs[i * 3 + 1]);
- }
-}
-
-static inline int target_rt_restore_ucontext(CPUM68KState *env,
- struct target_ucontext *uc)
-{
- int temp;
- target_greg_t *gregs = uc->tuc_mcontext.gregs;
-
- __get_user(temp, &uc->tuc_mcontext.version);
- if (temp != TARGET_MCONTEXT_VERSION)
- goto badframe;
-
- /* restore passed registers */
- __get_user(env->dregs[0], &gregs[0]);
- __get_user(env->dregs[1], &gregs[1]);
- __get_user(env->dregs[2], &gregs[2]);
- __get_user(env->dregs[3], &gregs[3]);
- __get_user(env->dregs[4], &gregs[4]);
- __get_user(env->dregs[5], &gregs[5]);
- __get_user(env->dregs[6], &gregs[6]);
- __get_user(env->dregs[7], &gregs[7]);
- __get_user(env->aregs[0], &gregs[8]);
- __get_user(env->aregs[1], &gregs[9]);
- __get_user(env->aregs[2], &gregs[10]);
- __get_user(env->aregs[3], &gregs[11]);
- __get_user(env->aregs[4], &gregs[12]);
- __get_user(env->aregs[5], &gregs[13]);
- __get_user(env->aregs[6], &gregs[14]);
- __get_user(env->aregs[7], &gregs[15]);
- __get_user(env->pc, &gregs[16]);
- __get_user(temp, &gregs[17]);
- cpu_m68k_set_ccr(env, temp);
-
- target_rt_restore_fpu_state(env, uc);
-
- return 0;
-
-badframe:
- return 1;
-}
-
-static void setup_rt_frame(int sig, struct target_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUM68KState *env)
-{
- struct target_rt_sigframe *frame;
- abi_ulong frame_addr;
- abi_ulong retcode_addr;
- abi_ulong info_addr;
- abi_ulong uc_addr;
- int err = 0;
- int i;
-
- frame_addr = get_sigframe(ka, env, sizeof *frame);
- trace_user_setup_rt_frame(env, frame_addr);
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto give_sigsegv;
- }
-
- __put_user(sig, &frame->sig);
-
- info_addr = frame_addr + offsetof(struct target_rt_sigframe, info);
- __put_user(info_addr, &frame->pinfo);
-
- uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc);
- __put_user(uc_addr, &frame->puc);
-
- tswap_siginfo(&frame->info, info);
-
- /* Create the ucontext */
-
- __put_user(0, &frame->uc.tuc_flags);
- __put_user(0, &frame->uc.tuc_link);
- __put_user(target_sigaltstack_used.ss_sp,
- &frame->uc.tuc_stack.ss_sp);
- __put_user(sas_ss_flags(env->aregs[7]),
- &frame->uc.tuc_stack.ss_flags);
- __put_user(target_sigaltstack_used.ss_size,
- &frame->uc.tuc_stack.ss_size);
- err |= target_rt_setup_ucontext(&frame->uc, env);
-
- if (err)
- goto give_sigsegv;
-
- for(i = 0; i < TARGET_NSIG_WORDS; i++) {
- __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
- }
-
- /* Set up to return from userspace. */
-
- retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
- __put_user(retcode_addr, &frame->pretcode);
-
- /* moveq #,d0; notb d0; trap #0 */
-
- __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
- (uint32_t *)(frame->retcode + 0));
- __put_user(0x4e40, (uint16_t *)(frame->retcode + 4));
-
- if (err)
- goto give_sigsegv;
-
- /* Set up to return from userspace */
-
- env->aregs[7] = frame_addr;
- env->pc = ka->_sa_handler;
-
- unlock_user_struct(frame, frame_addr, 1);
- return;
-
-give_sigsegv:
- unlock_user_struct(frame, frame_addr, 1);
- force_sigsegv(sig);
-}
-
-long do_sigreturn(CPUM68KState *env)
-{
- struct target_sigframe *frame;
- abi_ulong frame_addr = env->aregs[7] - 4;
- target_sigset_t target_set;
- sigset_t set;
- int i;
-
- trace_user_do_sigreturn(env, frame_addr);
- if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
- goto badframe;
-
- /* set blocked signals */
-
- __get_user(target_set.sig[0], &frame->sc.sc_mask);
-
- for(i = 1; i < TARGET_NSIG_WORDS; i++) {
- __get_user(target_set.sig[i], &frame->extramask[i - 1]);
- }
-
- target_to_host_sigset_internal(&set, &target_set);
- set_sigmask(&set);
-
- /* restore registers */
-
- restore_sigcontext(env, &frame->sc);
-
- unlock_user_struct(frame, frame_addr, 0);
- return -TARGET_QEMU_ESIGRETURN;
-
-badframe:
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-
-long do_rt_sigreturn(CPUM68KState *env)
-{
- struct target_rt_sigframe *frame;
- abi_ulong frame_addr = env->aregs[7] - 4;
- sigset_t set;
-
- trace_user_do_rt_sigreturn(env, frame_addr);
- if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
- goto badframe;
-
- target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
- set_sigmask(&set);
-
- /* restore registers */
-
- if (target_rt_restore_ucontext(env, &frame->uc))
- goto badframe;
-
- if (do_sigaltstack(frame_addr +
- offsetof(struct target_rt_sigframe, uc.tuc_stack),
- 0, get_sp_from_cpustate(env)) == -EFAULT)
- goto badframe;
-
- unlock_user_struct(frame, frame_addr, 0);
- return -TARGET_QEMU_ESIGRETURN;
-
-badframe:
- unlock_user_struct(frame, frame_addr, 0);
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-
-#elif defined(TARGET_ALPHA)
-
-struct target_sigcontext {
- abi_long sc_onstack;
- abi_long sc_mask;
- abi_long sc_pc;
- abi_long sc_ps;
- abi_long sc_regs[32];
- abi_long sc_ownedfp;
- abi_long sc_fpregs[32];
- abi_ulong sc_fpcr;
- abi_ulong sc_fp_control;
- abi_ulong sc_reserved1;
- abi_ulong sc_reserved2;
- abi_ulong sc_ssize;
- abi_ulong sc_sbase;
- abi_ulong sc_traparg_a0;
- abi_ulong sc_traparg_a1;
- abi_ulong sc_traparg_a2;
- abi_ulong sc_fp_trap_pc;
- abi_ulong sc_fp_trigger_sum;
- abi_ulong sc_fp_trigger_inst;
-};
-
-struct target_ucontext {
- abi_ulong tuc_flags;
- abi_ulong tuc_link;
- abi_ulong tuc_osf_sigmask;
- target_stack_t tuc_stack;
- struct target_sigcontext tuc_mcontext;
- target_sigset_t tuc_sigmask;
-};
-
-struct target_sigframe {
- struct target_sigcontext sc;
- unsigned int retcode[3];
-};
-
-struct target_rt_sigframe {
- target_siginfo_t info;
- struct target_ucontext uc;
- unsigned int retcode[3];
-};
-
-#define INSN_MOV_R30_R16 0x47fe0410
-#define INSN_LDI_R0 0x201f0000
-#define INSN_CALLSYS 0x00000083
-
-static void setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env,
- abi_ulong frame_addr, target_sigset_t *set)
-{
- int i;
-
- __put_user(on_sig_stack(frame_addr), &sc->sc_onstack);
- __put_user(set->sig[0], &sc->sc_mask);
- __put_user(env->pc, &sc->sc_pc);
- __put_user(8, &sc->sc_ps);
-
- for (i = 0; i < 31; ++i) {
- __put_user(env->ir[i], &sc->sc_regs[i]);
- }
- __put_user(0, &sc->sc_regs[31]);
-
- for (i = 0; i < 31; ++i) {
- __put_user(env->fir[i], &sc->sc_fpregs[i]);
- }
- __put_user(0, &sc->sc_fpregs[31]);
- __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr);
-
- __put_user(0, &sc->sc_traparg_a0); /* FIXME */
- __put_user(0, &sc->sc_traparg_a1); /* FIXME */
- __put_user(0, &sc->sc_traparg_a2); /* FIXME */
-}
-
-static void restore_sigcontext(CPUAlphaState *env,
- struct target_sigcontext *sc)
-{
- uint64_t fpcr;
- int i;
-
- __get_user(env->pc, &sc->sc_pc);
-
- for (i = 0; i < 31; ++i) {
- __get_user(env->ir[i], &sc->sc_regs[i]);
- }
- for (i = 0; i < 31; ++i) {
- __get_user(env->fir[i], &sc->sc_fpregs[i]);
- }
-
- __get_user(fpcr, &sc->sc_fpcr);
- cpu_alpha_store_fpcr(env, fpcr);
-}
-
-static inline abi_ulong get_sigframe(struct target_sigaction *sa,
- CPUAlphaState *env,
- unsigned long framesize)
-{
- abi_ulong sp = env->ir[IR_SP];
-
- /* This is the X/Open sanctioned signal stack switching. */
- if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
- sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
- }
- return (sp - framesize) & -32;
-}
-
-static void setup_frame(int sig, struct target_sigaction *ka,
- target_sigset_t *set, CPUAlphaState *env)
-{
- abi_ulong frame_addr, r26;
- struct target_sigframe *frame;
- int err = 0;
-
- frame_addr = get_sigframe(ka, env, sizeof(*frame));
- trace_user_setup_frame(env, frame_addr);
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto give_sigsegv;
- }
-
- setup_sigcontext(&frame->sc, env, frame_addr, set);
-
- if (ka->sa_restorer) {
- r26 = ka->sa_restorer;
- } else {
- __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
- __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
- &frame->retcode[1]);
- __put_user(INSN_CALLSYS, &frame->retcode[2]);
- /* imb() */
- r26 = frame_addr + offsetof(struct target_sigframe, retcode);
- }
-
- unlock_user_struct(frame, frame_addr, 1);
-
- if (err) {
-give_sigsegv:
- force_sigsegv(sig);
- return;
- }
-
- env->ir[IR_RA] = r26;
- env->ir[IR_PV] = env->pc = ka->_sa_handler;
- env->ir[IR_A0] = sig;
- env->ir[IR_A1] = 0;
- env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc);
- env->ir[IR_SP] = frame_addr;
-}
-
-static void setup_rt_frame(int sig, struct target_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUAlphaState *env)
-{
- abi_ulong frame_addr, r26;
- struct target_rt_sigframe *frame;
- int i, err = 0;
-
- frame_addr = get_sigframe(ka, env, sizeof(*frame));
- trace_user_setup_rt_frame(env, frame_addr);
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto give_sigsegv;
- }
-
- tswap_siginfo(&frame->info, info);
-
- __put_user(0, &frame->uc.tuc_flags);
- __put_user(0, &frame->uc.tuc_link);
- __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask);
- __put_user(target_sigaltstack_used.ss_sp,
- &frame->uc.tuc_stack.ss_sp);
- __put_user(sas_ss_flags(env->ir[IR_SP]),
- &frame->uc.tuc_stack.ss_flags);
- __put_user(target_sigaltstack_used.ss_size,
- &frame->uc.tuc_stack.ss_size);
- setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set);
- for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
- __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
- }
-
- if (ka->sa_restorer) {
- r26 = ka->sa_restorer;
- } else {
- __put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
- __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
- &frame->retcode[1]);
- __put_user(INSN_CALLSYS, &frame->retcode[2]);
- /* imb(); */
- r26 = frame_addr + offsetof(struct target_sigframe, retcode);
- }
-
- if (err) {
-give_sigsegv:
- force_sigsegv(sig);
- return;
- }
-
- env->ir[IR_RA] = r26;
- env->ir[IR_PV] = env->pc = ka->_sa_handler;
- env->ir[IR_A0] = sig;
- env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
- env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
- env->ir[IR_SP] = frame_addr;
-}
-
-long do_sigreturn(CPUAlphaState *env)
-{
- struct target_sigcontext *sc;
- abi_ulong sc_addr = env->ir[IR_A0];
- target_sigset_t target_set;
- sigset_t set;
-
- if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) {
- goto badframe;
- }
-
- target_sigemptyset(&target_set);
- __get_user(target_set.sig[0], &sc->sc_mask);
-
- target_to_host_sigset_internal(&set, &target_set);
- set_sigmask(&set);
-
- restore_sigcontext(env, sc);
- unlock_user_struct(sc, sc_addr, 0);
- return -TARGET_QEMU_ESIGRETURN;
-
-badframe:
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-
-long do_rt_sigreturn(CPUAlphaState *env)
-{
- abi_ulong frame_addr = env->ir[IR_A0];
- struct target_rt_sigframe *frame;
- sigset_t set;
-
- trace_user_do_rt_sigreturn(env, frame_addr);
- if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
- goto badframe;
- }
- target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
- set_sigmask(&set);
-
- restore_sigcontext(env, &frame->uc.tuc_mcontext);
- if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
- uc.tuc_stack),
- 0, env->ir[IR_SP]) == -EFAULT) {
- goto badframe;
- }
-
- unlock_user_struct(frame, frame_addr, 0);
- return -TARGET_QEMU_ESIGRETURN;
-
-
-badframe:
- unlock_user_struct(frame, frame_addr, 0);
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-
-#elif defined(TARGET_TILEGX)
-
-struct target_sigcontext {
- union {
- /* General-purpose registers. */
- abi_ulong gregs[56];
- struct {
- abi_ulong __gregs[53];
- abi_ulong tp; /* Aliases gregs[TREG_TP]. */
- abi_ulong sp; /* Aliases gregs[TREG_SP]. */
- abi_ulong lr; /* Aliases gregs[TREG_LR]. */
- };
- };
- abi_ulong pc; /* Program counter. */
- abi_ulong ics; /* In Interrupt Critical Section? */
- abi_ulong faultnum; /* Fault number. */
- abi_ulong pad[5];
-};
-
-struct target_ucontext {
- abi_ulong tuc_flags;
- abi_ulong tuc_link;
- target_stack_t tuc_stack;
- struct target_sigcontext tuc_mcontext;
- target_sigset_t tuc_sigmask; /* mask last for extensibility */
-};
-
-struct target_rt_sigframe {
- unsigned char save_area[16]; /* caller save area */
- struct target_siginfo info;
- struct target_ucontext uc;
- abi_ulong retcode[2];
-};
-
-#define INSN_MOVELI_R10_139 0x00045fe551483000ULL /* { moveli r10, 139 } */
-#define INSN_SWINT1 0x286b180051485000ULL /* { swint1 } */
-
-
-static void setup_sigcontext(struct target_sigcontext *sc,
- CPUArchState *env, int signo)
-{
- int i;
-
- for (i = 0; i < TILEGX_R_COUNT; ++i) {
- __put_user(env->regs[i], &sc->gregs[i]);
- }
-
- __put_user(env->pc, &sc->pc);
- __put_user(0, &sc->ics);
- __put_user(signo, &sc->faultnum);
-}
-
-static void restore_sigcontext(CPUTLGState *env, struct target_sigcontext *sc)
-{
- int i;
-
- for (i = 0; i < TILEGX_R_COUNT; ++i) {
- __get_user(env->regs[i], &sc->gregs[i]);
- }
-
- __get_user(env->pc, &sc->pc);
-}
-
-static abi_ulong get_sigframe(struct target_sigaction *ka, CPUArchState *env,
- size_t frame_size)
-{
- unsigned long sp = env->regs[TILEGX_R_SP];
-
- if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size))) {
- return -1UL;
- }
-
- if ((ka->sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) {
- sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
- }
-
- sp -= frame_size;
- sp &= -16UL;
- return sp;
-}
-
-static void setup_rt_frame(int sig, struct target_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUArchState *env)
-{
- abi_ulong frame_addr;
- struct target_rt_sigframe *frame;
- unsigned long restorer;
-
- frame_addr = get_sigframe(ka, env, sizeof(*frame));
- trace_user_setup_rt_frame(env, frame_addr);
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto give_sigsegv;
- }
-
- /* Always write at least the signal number for the stack backtracer. */
- if (ka->sa_flags & TARGET_SA_SIGINFO) {
- /* At sigreturn time, restore the callee-save registers too. */
- tswap_siginfo(&frame->info, info);
- /* regs->flags |= PT_FLAGS_RESTORE_REGS; FIXME: we can skip it? */
- } else {
- __put_user(info->si_signo, &frame->info.si_signo);
- }
-
- /* Create the ucontext. */
- __put_user(0, &frame->uc.tuc_flags);
- __put_user(0, &frame->uc.tuc_link);
- __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
- __put_user(sas_ss_flags(env->regs[TILEGX_R_SP]),
- &frame->uc.tuc_stack.ss_flags);
- __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size);
- setup_sigcontext(&frame->uc.tuc_mcontext, env, info->si_signo);
-
- if (ka->sa_flags & TARGET_SA_RESTORER) {
- restorer = (unsigned long) ka->sa_restorer;
- } else {
- __put_user(INSN_MOVELI_R10_139, &frame->retcode[0]);
- __put_user(INSN_SWINT1, &frame->retcode[1]);
- restorer = frame_addr + offsetof(struct target_rt_sigframe, retcode);
- }
- env->pc = (unsigned long) ka->_sa_handler;
- env->regs[TILEGX_R_SP] = (unsigned long) frame;
- env->regs[TILEGX_R_LR] = restorer;
- env->regs[0] = (unsigned long) sig;
- env->regs[1] = (unsigned long) &frame->info;
- env->regs[2] = (unsigned long) &frame->uc;
- /* regs->flags |= PT_FLAGS_CALLER_SAVES; FIXME: we can skip it? */
-
- unlock_user_struct(frame, frame_addr, 1);
- return;
-
-give_sigsegv:
- force_sigsegv(sig);
-}
-
-long do_rt_sigreturn(CPUTLGState *env)
-{
- abi_ulong frame_addr = env->regs[TILEGX_R_SP];
- struct target_rt_sigframe *frame;
- sigset_t set;
-
- trace_user_do_rt_sigreturn(env, frame_addr);
- if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
- goto badframe;
- }
- target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
- set_sigmask(&set);
-
- restore_sigcontext(env, &frame->uc.tuc_mcontext);
- if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
- uc.tuc_stack),
- 0, env->regs[TILEGX_R_SP]) == -EFAULT) {
- goto badframe;
- }
-
- unlock_user_struct(frame, frame_addr, 0);
- return -TARGET_QEMU_ESIGRETURN;
-
-
- badframe:
- unlock_user_struct(frame, frame_addr, 0);
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-
-#elif defined(TARGET_RISCV)
-
-/* Signal handler invocation must be transparent for the code being
- interrupted. Complete CPU (hart) state is saved on entry and restored
- before returning from the handler. Process sigmask is also saved to block
- signals while the handler is running. The handler gets its own stack,
- which also doubles as storage for the CPU state and sigmask.
-
- The code below is qemu re-implementation of arch/riscv/kernel/signal.c */
-
-struct target_sigcontext {
- abi_long pc;
- abi_long gpr[31]; /* x0 is not present, so all offsets must be -1 */
- uint64_t fpr[32];
- uint32_t fcsr;
-}; /* cf. riscv-linux:arch/riscv/include/uapi/asm/ptrace.h */
-
-struct target_ucontext {
- unsigned long uc_flags;
- struct target_ucontext *uc_link;
- target_stack_t uc_stack;
- struct target_sigcontext uc_mcontext;
- target_sigset_t uc_sigmask;
-};
-
-struct target_rt_sigframe {
- uint32_t tramp[2]; /* not in kernel, which uses VDSO instead */
- struct target_siginfo info;
- struct target_ucontext uc;
-};
-
-static abi_ulong get_sigframe(struct target_sigaction *ka,
- CPURISCVState *regs, size_t framesize)
-{
- abi_ulong sp = regs->gpr[xSP];
- int onsigstack = on_sig_stack(sp);
-
- /* redzone */
- /* This is the X/Open sanctioned signal stack switching. */
- if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !onsigstack) {
- sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
- }
-
- sp -= framesize;
- sp &= ~3UL; /* align sp on 4-byte boundary */
-
- /* If we are on the alternate signal stack and would overflow it, don't.
- Return an always-bogus address instead so we will die with SIGSEGV. */
- if (onsigstack && !likely(on_sig_stack(sp))) {
- return -1L;
- }
-
- return sp;
-}
-
-static void setup_sigcontext(struct target_sigcontext *sc, CPURISCVState *env)
-{
- int i;
-
- __put_user(env->pc, &sc->pc);
-
- for (i = 1; i < 32; i++) {
- __put_user(env->gpr[i], &sc->gpr[i - 1]);
- }
- for (i = 0; i < 32; i++) {
- __put_user(env->fpr[i], &sc->fpr[i]);
- }
-
- uint32_t fcsr = csr_read_helper(env, CSR_FCSR); /*riscv_get_fcsr(env);*/
- __put_user(fcsr, &sc->fcsr);
-}
-
-static void setup_ucontext(struct target_ucontext *uc,
- CPURISCVState *env, target_sigset_t *set)
-{
- abi_ulong ss_sp = (target_ulong)target_sigaltstack_used.ss_sp;
- abi_ulong ss_flags = sas_ss_flags(env->gpr[xSP]);
- abi_ulong ss_size = target_sigaltstack_used.ss_size;
-
- __put_user(0, &(uc->uc_flags));
- __put_user(0, &(uc->uc_link));
-
- __put_user(ss_sp, &(uc->uc_stack.ss_sp));
- __put_user(ss_flags, &(uc->uc_stack.ss_flags));
- __put_user(ss_size, &(uc->uc_stack.ss_size));
-
- int i;
- for (i = 0; i < TARGET_NSIG_WORDS; i++) {
- __put_user(set->sig[i], &(uc->uc_sigmask.sig[i]));
- }
-
- setup_sigcontext(&uc->uc_mcontext, env);
-}
-
-static inline void install_sigtramp(uint32_t *tramp)
-{
- __put_user(0x08b00893, tramp + 0); /* li a7, 139 = __NR_rt_sigreturn */
- __put_user(0x00000073, tramp + 1); /* ecall */
-}
-
-static void setup_rt_frame(int sig, struct target_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPURISCVState *env)
-{
- abi_ulong frame_addr;
- struct target_rt_sigframe *frame;
-
- frame_addr = get_sigframe(ka, env, sizeof(*frame));
- trace_user_setup_rt_frame(env, frame_addr);
-
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto badframe;
- }
-
- setup_ucontext(&frame->uc, env, set);
- tswap_siginfo(&frame->info, info);
- install_sigtramp(frame->tramp);
-
- env->pc = ka->_sa_handler;
- env->gpr[xSP] = frame_addr;
- env->gpr[xA0] = sig;
- env->gpr[xA1] = frame_addr + offsetof(struct target_rt_sigframe, info);
- env->gpr[xA2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
- env->gpr[xRA] = frame_addr + offsetof(struct target_rt_sigframe, tramp);
-
- return;
-
-badframe:
- unlock_user_struct(frame, frame_addr, 1);
- if (sig == TARGET_SIGSEGV) {
- ka->_sa_handler = TARGET_SIG_DFL;
- }
- force_sig(TARGET_SIGSEGV);
-}
-
-static void restore_sigcontext(CPURISCVState *env, struct target_sigcontext *sc)
-{
- int i;
-
- __get_user(env->pc, &sc->pc);
-
- for (i = 1; i < 32; ++i) {
- __get_user(env->gpr[i], &sc->gpr[i - 1]);
- }
- for (i = 0; i < 32; ++i) {
- __get_user(env->fpr[i], &sc->fpr[i]);
- }
-
- uint32_t fcsr;
- __get_user(fcsr, &sc->fcsr);
- csr_write_helper(env, fcsr, CSR_FCSR);
-}
-
-static void restore_ucontext(CPURISCVState *env, struct target_ucontext *uc)
-{
- sigset_t blocked;
- target_sigset_t target_set;
- int i;
-
- target_sigemptyset(&target_set);
- for (i = 0; i < TARGET_NSIG_WORDS; i++) {
- __get_user(target_set.sig[i], &(uc->uc_sigmask.sig[i]));
- }
-
- target_to_host_sigset_internal(&blocked, &target_set);
- set_sigmask(&blocked);
-
- restore_sigcontext(env, &uc->uc_mcontext);
-}
-
-long do_rt_sigreturn(CPURISCVState *env)
-{
- struct target_rt_sigframe *frame;
- abi_ulong frame_addr;
-
- frame_addr = env->gpr[xSP];
- trace_user_do_sigreturn(env, frame_addr);
- if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
- goto badframe;
- }
-
- restore_ucontext(env, &frame->uc);
-
- if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
- uc.uc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) {
- goto badframe;
- }
-
- unlock_user_struct(frame, frame_addr, 0);
- return -TARGET_QEMU_ESIGRETURN;
-
-badframe:
- unlock_user_struct(frame, frame_addr, 0);
- force_sig(TARGET_SIGSEGV);
- return 0;
-}
-
-#elif defined(TARGET_HPPA)
-
-struct target_sigcontext {
- abi_ulong sc_flags;
- abi_ulong sc_gr[32];
- uint64_t sc_fr[32];
- abi_ulong sc_iasq[2];
- abi_ulong sc_iaoq[2];
- abi_ulong sc_sar;
-};
-
-struct target_ucontext {
- abi_uint tuc_flags;
- abi_ulong tuc_link;
- target_stack_t tuc_stack;
- abi_uint pad[1];
- struct target_sigcontext tuc_mcontext;
- target_sigset_t tuc_sigmask;
-};
-
-struct target_rt_sigframe {
- abi_uint tramp[9];
- target_siginfo_t info;
- struct target_ucontext uc;
- /* hidden location of upper halves of pa2.0 64-bit gregs */
-};
-
-static void setup_sigcontext(struct target_sigcontext *sc, CPUArchState *env)
-{
- int flags = 0;
- int i;
-
- /* ??? if on_sig_stack, flags |= 1 (PARISC_SC_FLAG_ONSTACK). */
-
- if (env->iaoq_f < TARGET_PAGE_SIZE) {
- /* In the gateway page, executing a syscall. */
- flags |= 2; /* PARISC_SC_FLAG_IN_SYSCALL */
- __put_user(env->gr[31], &sc->sc_iaoq[0]);
- __put_user(env->gr[31] + 4, &sc->sc_iaoq[1]);
- } else {
- __put_user(env->iaoq_f, &sc->sc_iaoq[0]);
- __put_user(env->iaoq_b, &sc->sc_iaoq[1]);
- }
- __put_user(0, &sc->sc_iasq[0]);
- __put_user(0, &sc->sc_iasq[1]);
- __put_user(flags, &sc->sc_flags);
-
- __put_user(cpu_hppa_get_psw(env), &sc->sc_gr[0]);
- for (i = 1; i < 32; ++i) {
- __put_user(env->gr[i], &sc->sc_gr[i]);
- }
-
- __put_user((uint64_t)env->fr0_shadow << 32, &sc->sc_fr[0]);
- for (i = 1; i < 32; ++i) {
- __put_user(env->fr[i], &sc->sc_fr[i]);
- }
-
- __put_user(env->cr[CR_SAR], &sc->sc_sar);
-}
-
-static void restore_sigcontext(CPUArchState *env, struct target_sigcontext *sc)
-{
- target_ulong psw;
- int i;
-
- __get_user(psw, &sc->sc_gr[0]);
- cpu_hppa_put_psw(env, psw);
-
- for (i = 1; i < 32; ++i) {
- __get_user(env->gr[i], &sc->sc_gr[i]);
- }
- for (i = 0; i < 32; ++i) {
- __get_user(env->fr[i], &sc->sc_fr[i]);
- }
- cpu_hppa_loaded_fr0(env);
-
- __get_user(env->iaoq_f, &sc->sc_iaoq[0]);
- __get_user(env->iaoq_b, &sc->sc_iaoq[1]);
- __get_user(env->cr[CR_SAR], &sc->sc_sar);
-}
-
-/* No, this doesn't look right, but it's copied straight from the kernel. */
-#define PARISC_RT_SIGFRAME_SIZE32 \
- ((sizeof(struct target_rt_sigframe) + 48 + 64) & -64)
-
-static void setup_rt_frame(int sig, struct target_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUArchState *env)
-{
- abi_ulong frame_addr, sp, haddr;
- struct target_rt_sigframe *frame;
- int i;
-
- sp = env->gr[30];
- if (ka->sa_flags & TARGET_SA_ONSTACK) {
- if (sas_ss_flags(sp) == 0) {
- sp = (target_sigaltstack_used.ss_sp + 0x7f) & ~0x3f;
- }
- }
- frame_addr = QEMU_ALIGN_UP(sp, 64);
- sp = frame_addr + PARISC_RT_SIGFRAME_SIZE32;
-
- trace_user_setup_rt_frame(env, frame_addr);
-
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto give_sigsegv;
- }
-
- tswap_siginfo(&frame->info, info);
- frame->uc.tuc_flags = 0;
- frame->uc.tuc_link = 0;
-
- __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
- __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
- &frame->uc.tuc_stack.ss_flags);
- __put_user(target_sigaltstack_used.ss_size,
- &frame->uc.tuc_stack.ss_size);
-
- for (i = 0; i < TARGET_NSIG_WORDS; i++) {
- __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
- }
-
- setup_sigcontext(&frame->uc.tuc_mcontext, env);
-
- __put_user(0x34190000, frame->tramp + 0); /* ldi 0,%r25 */
- __put_user(0x3414015a, frame->tramp + 1); /* ldi __NR_rt_sigreturn,%r20 */
- __put_user(0xe4008200, frame->tramp + 2); /* be,l 0x100(%sr2,%r0) */
- __put_user(0x08000240, frame->tramp + 3); /* nop */
-
- unlock_user_struct(frame, frame_addr, 1);
-
- env->gr[2] = h2g(frame->tramp);
- env->gr[30] = sp;
- env->gr[26] = sig;
- env->gr[25] = h2g(&frame->info);
- env->gr[24] = h2g(&frame->uc);
-
- haddr = ka->_sa_handler;
- if (haddr & 2) {
- /* Function descriptor. */
- target_ulong *fdesc, dest;
-
- haddr &= -4;
- if (!lock_user_struct(VERIFY_READ, fdesc, haddr, 1)) {
- goto give_sigsegv;
- }
- __get_user(dest, fdesc);
- __get_user(env->gr[19], fdesc + 1);
- unlock_user_struct(fdesc, haddr, 1);
- haddr = dest;
- }
- env->iaoq_f = haddr;
- env->iaoq_b = haddr + 4;
- return;
-
- give_sigsegv:
- force_sigsegv(sig);
-}
-
-long do_rt_sigreturn(CPUArchState *env)
-{
- abi_ulong frame_addr = env->gr[30] - PARISC_RT_SIGFRAME_SIZE32;
- struct target_rt_sigframe *frame;
- sigset_t set;
-
- trace_user_do_rt_sigreturn(env, frame_addr);
- if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
- goto badframe;
- }
- target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
- set_sigmask(&set);
-
- restore_sigcontext(env, &frame->uc.tuc_mcontext);
- unlock_user_struct(frame, frame_addr, 0);
-
- if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
- uc.tuc_stack),
- 0, env->gr[30]) == -EFAULT) {
- goto badframe;
- }
-
- unlock_user_struct(frame, frame_addr, 0);
- return -TARGET_QEMU_ESIGRETURN;
-
- badframe:
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-
-#elif defined(TARGET_XTENSA)
-
-struct target_sigcontext {
- abi_ulong sc_pc;
- abi_ulong sc_ps;
- abi_ulong sc_lbeg;
- abi_ulong sc_lend;
- abi_ulong sc_lcount;
- abi_ulong sc_sar;
- abi_ulong sc_acclo;
- abi_ulong sc_acchi;
- abi_ulong sc_a[16];
- abi_ulong sc_xtregs;
-};
-
-struct target_ucontext {
- abi_ulong tuc_flags;
- abi_ulong tuc_link;
- target_stack_t tuc_stack;
- struct target_sigcontext tuc_mcontext;
- target_sigset_t tuc_sigmask;
-};
-
-struct target_rt_sigframe {
- target_siginfo_t info;
- struct target_ucontext uc;
- /* TODO: xtregs */
- uint8_t retcode[6];
- abi_ulong window[4];
-};
-
-static abi_ulong get_sigframe(struct target_sigaction *sa,
- CPUXtensaState *env,
- unsigned long framesize)
-{
- abi_ulong sp = env->regs[1];
-
- /* This is the X/Open sanctioned signal stack switching. */
- if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) {
- sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
- }
- return (sp - framesize) & -16;
-}
-
-static int flush_window_regs(CPUXtensaState *env)
-{
- uint32_t wb = env->sregs[WINDOW_BASE];
- uint32_t ws = xtensa_replicate_windowstart(env) >> (wb + 1);
- unsigned d = ctz32(ws) + 1;
- unsigned i;
- int ret = 0;
-
- for (i = d; i < env->config->nareg / 4; i += d) {
- uint32_t ssp, osp;
- unsigned j;
-
- ws >>= d;
- xtensa_rotate_window(env, d);
-
- if (ws & 0x1) {
- ssp = env->regs[5];
- d = 1;
- } else if (ws & 0x2) {
- ssp = env->regs[9];
- ret |= get_user_ual(osp, env->regs[1] - 12);
- osp -= 32;
- d = 2;
- } else if (ws & 0x4) {
- ssp = env->regs[13];
- ret |= get_user_ual(osp, env->regs[1] - 12);
- osp -= 48;
- d = 3;
- } else {
- g_assert_not_reached();
- }
-
- for (j = 0; j < 4; ++j) {
- ret |= put_user_ual(env->regs[j], ssp - 16 + j * 4);
- }
- for (j = 4; j < d * 4; ++j) {
- ret |= put_user_ual(env->regs[j], osp - 16 + j * 4);
- }
- }
- xtensa_rotate_window(env, d);
- g_assert(env->sregs[WINDOW_BASE] == wb);
- return ret == 0;
-}
-
-static int setup_sigcontext(struct target_rt_sigframe *frame,
- CPUXtensaState *env)
-{
- struct target_sigcontext *sc = &frame->uc.tuc_mcontext;
- int i;
-
- __put_user(env->pc, &sc->sc_pc);
- __put_user(env->sregs[PS], &sc->sc_ps);
- __put_user(env->sregs[LBEG], &sc->sc_lbeg);
- __put_user(env->sregs[LEND], &sc->sc_lend);
- __put_user(env->sregs[LCOUNT], &sc->sc_lcount);
- if (!flush_window_regs(env)) {
- return 0;
- }
- for (i = 0; i < 16; ++i) {
- __put_user(env->regs[i], sc->sc_a + i);
- }
- __put_user(0, &sc->sc_xtregs);
- /* TODO: xtregs */
- return 1;
-}
-
-static void setup_rt_frame(int sig, struct target_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUXtensaState *env)
-{
- abi_ulong frame_addr;
- struct target_rt_sigframe *frame;
- uint32_t ra;
- int i;
-
- frame_addr = get_sigframe(ka, env, sizeof(*frame));
- trace_user_setup_rt_frame(env, frame_addr);
-
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto give_sigsegv;
- }
-
- if (ka->sa_flags & SA_SIGINFO) {
- tswap_siginfo(&frame->info, info);
- }
-
- __put_user(0, &frame->uc.tuc_flags);
- __put_user(0, &frame->uc.tuc_link);
- __put_user(target_sigaltstack_used.ss_sp,
- &frame->uc.tuc_stack.ss_sp);
- __put_user(sas_ss_flags(env->regs[1]),
- &frame->uc.tuc_stack.ss_flags);
- __put_user(target_sigaltstack_used.ss_size,
- &frame->uc.tuc_stack.ss_size);
- if (!setup_sigcontext(frame, env)) {
- unlock_user_struct(frame, frame_addr, 0);
- goto give_sigsegv;
- }
- for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
- __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
- }
-
- if (ka->sa_flags & TARGET_SA_RESTORER) {
- ra = ka->sa_restorer;
- } else {
- ra = frame_addr + offsetof(struct target_rt_sigframe, retcode);
-#ifdef TARGET_WORDS_BIGENDIAN
- /* Generate instruction: MOVI a2, __NR_rt_sigreturn */
- __put_user(0x22, &frame->retcode[0]);
- __put_user(0x0a, &frame->retcode[1]);
- __put_user(TARGET_NR_rt_sigreturn, &frame->retcode[2]);
- /* Generate instruction: SYSCALL */
- __put_user(0x00, &frame->retcode[3]);
- __put_user(0x05, &frame->retcode[4]);
- __put_user(0x00, &frame->retcode[5]);
-#else
- /* Generate instruction: MOVI a2, __NR_rt_sigreturn */
- __put_user(0x22, &frame->retcode[0]);
- __put_user(0xa0, &frame->retcode[1]);
- __put_user(TARGET_NR_rt_sigreturn, &frame->retcode[2]);
- /* Generate instruction: SYSCALL */
- __put_user(0x00, &frame->retcode[3]);
- __put_user(0x50, &frame->retcode[4]);
- __put_user(0x00, &frame->retcode[5]);
-#endif
- }
- env->sregs[PS] = PS_UM | (3 << PS_RING_SHIFT);
- if (xtensa_option_enabled(env->config, XTENSA_OPTION_WINDOWED_REGISTER)) {
- env->sregs[PS] |= PS_WOE | (1 << PS_CALLINC_SHIFT);
- }
- memset(env->regs, 0, sizeof(env->regs));
- env->pc = ka->_sa_handler;
- env->regs[1] = frame_addr;
- env->sregs[WINDOW_BASE] = 0;
- env->sregs[WINDOW_START] = 1;
-
- env->regs[4] = (ra & 0x3fffffff) | 0x40000000;
- env->regs[6] = sig;
- env->regs[7] = frame_addr + offsetof(struct target_rt_sigframe, info);
- env->regs[8] = frame_addr + offsetof(struct target_rt_sigframe, uc);
- unlock_user_struct(frame, frame_addr, 1);
- return;
-
-give_sigsegv:
- force_sigsegv(sig);
- return;
-}
-
-static void restore_sigcontext(CPUXtensaState *env,
- struct target_rt_sigframe *frame)
-{
- struct target_sigcontext *sc = &frame->uc.tuc_mcontext;
- uint32_t ps;
- int i;
-
- __get_user(env->pc, &sc->sc_pc);
- __get_user(ps, &sc->sc_ps);
- __get_user(env->sregs[LBEG], &sc->sc_lbeg);
- __get_user(env->sregs[LEND], &sc->sc_lend);
- __get_user(env->sregs[LCOUNT], &sc->sc_lcount);
-
- env->sregs[WINDOW_BASE] = 0;
- env->sregs[WINDOW_START] = 1;
- env->sregs[PS] = deposit32(env->sregs[PS],
- PS_CALLINC_SHIFT,
- PS_CALLINC_LEN,
- extract32(ps, PS_CALLINC_SHIFT,
- PS_CALLINC_LEN));
- for (i = 0; i < 16; ++i) {
- __get_user(env->regs[i], sc->sc_a + i);
- }
- /* TODO: xtregs */
-}
-
-long do_rt_sigreturn(CPUXtensaState *env)
-{
- abi_ulong frame_addr = env->regs[1];
- struct target_rt_sigframe *frame;
- sigset_t set;
-
- trace_user_do_rt_sigreturn(env, frame_addr);
- if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
- goto badframe;
- }
- target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
- set_sigmask(&set);
-
- restore_sigcontext(env, frame);
-
- if (do_sigaltstack(frame_addr +
- offsetof(struct target_rt_sigframe, uc.tuc_stack),
- 0, get_sp_from_cpustate(env)) == -TARGET_EFAULT) {
- goto badframe;
- }
- unlock_user_struct(frame, frame_addr, 0);
- return -TARGET_QEMU_ESIGRETURN;
-
-badframe:
- unlock_user_struct(frame, frame_addr, 0);
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-
-#else
-#error Target needs to add support for signal handling
-#endif
-
static void handle_pending_signal(CPUArchState *cpu_env, int sig,
struct emulated_sigtable *k)
{
@@ -7376,18 +905,15 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig,
}
#endif
/* prepare the stack frame of the virtual CPU */
-#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) \
- || defined(TARGET_OPENRISC) || defined(TARGET_TILEGX) \
- || defined(TARGET_PPC64) || defined(TARGET_HPPA) \
- || defined(TARGET_NIOS2) || defined(TARGET_X86_64) \
- || defined(TARGET_RISCV) || defined(TARGET_XTENSA)
- /* These targets do not have traditional signals. */
- setup_rt_frame(sig, sa, &k->info, &target_old_set, cpu_env);
-#else
- if (sa->sa_flags & TARGET_SA_SIGINFO)
+#if defined(TARGET_ARCH_HAS_SETUP_FRAME)
+ if (sa->sa_flags & TARGET_SA_SIGINFO) {
setup_rt_frame(sig, sa, &k->info, &target_old_set, cpu_env);
- else
+ } else {
setup_frame(sig, sa, &target_old_set, cpu_env);
+ }
+#else
+ /* These targets do not have traditional signals. */
+ setup_rt_frame(sig, sa, &k->info, &target_old_set, cpu_env);
#endif
if (sa->sa_flags & TARGET_SA_RESETHAND) {
sa->_sa_handler = TARGET_SIG_DFL;
diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c
new file mode 100644
index 0000000000..7c4796ca23
--- /dev/null
+++ b/linux-user/sparc/cpu_loop.c
@@ -0,0 +1,306 @@
+/*
+ * qemu user cpu loop
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "cpu_loop-common.h"
+
+#define SPARC64_STACK_BIAS 2047
+
+//#define DEBUG_WIN
+
+/* WARNING: dealing with register windows _is_ complicated. More info
+ can be found at http://www.sics.se/~psm/sparcstack.html */
+static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
+{
+ index = (index + cwp * 16) % (16 * env->nwindows);
+ /* wrap handling : if cwp is on the last window, then we use the
+ registers 'after' the end */
+ if (index < 8 && env->cwp == env->nwindows - 1)
+ index += 16 * env->nwindows;
+ return index;
+}
+
+/* save the register window 'cwp1' */
+static inline void save_window_offset(CPUSPARCState *env, int cwp1)
+{
+ unsigned int i;
+ abi_ulong sp_ptr;
+
+ sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
+#ifdef TARGET_SPARC64
+ if (sp_ptr & 3)
+ sp_ptr += SPARC64_STACK_BIAS;
+#endif
+#if defined(DEBUG_WIN)
+ printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
+ sp_ptr, cwp1);
+#endif
+ for(i = 0; i < 16; i++) {
+ /* FIXME - what to do if put_user() fails? */
+ put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
+ sp_ptr += sizeof(abi_ulong);
+ }
+}
+
+static void save_window(CPUSPARCState *env)
+{
+#ifndef TARGET_SPARC64
+ unsigned int new_wim;
+ new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) &
+ ((1LL << env->nwindows) - 1);
+ save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
+ env->wim = new_wim;
+#else
+ save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
+ env->cansave++;
+ env->canrestore--;
+#endif
+}
+
+static void restore_window(CPUSPARCState *env)
+{
+#ifndef TARGET_SPARC64
+ unsigned int new_wim;
+#endif
+ unsigned int i, cwp1;
+ abi_ulong sp_ptr;
+
+#ifndef TARGET_SPARC64
+ new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) &
+ ((1LL << env->nwindows) - 1);
+#endif
+
+ /* restore the invalid window */
+ cwp1 = cpu_cwp_inc(env, env->cwp + 1);
+ sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
+#ifdef TARGET_SPARC64
+ if (sp_ptr & 3)
+ sp_ptr += SPARC64_STACK_BIAS;
+#endif
+#if defined(DEBUG_WIN)
+ printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
+ sp_ptr, cwp1);
+#endif
+ for(i = 0; i < 16; i++) {
+ /* FIXME - what to do if get_user() fails? */
+ get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
+ sp_ptr += sizeof(abi_ulong);
+ }
+#ifdef TARGET_SPARC64
+ env->canrestore++;
+ if (env->cleanwin < env->nwindows - 1)
+ env->cleanwin++;
+ env->cansave--;
+#else
+ env->wim = new_wim;
+#endif
+}
+
+static void flush_windows(CPUSPARCState *env)
+{
+ int offset, cwp1;
+
+ offset = 1;
+ for(;;) {
+ /* if restore would invoke restore_window(), then we can stop */
+ cwp1 = cpu_cwp_inc(env, env->cwp + offset);
+#ifndef TARGET_SPARC64
+ if (env->wim & (1 << cwp1))
+ break;
+#else
+ if (env->canrestore == 0)
+ break;
+ env->cansave++;
+ env->canrestore--;
+#endif
+ save_window_offset(env, cwp1);
+ offset++;
+ }
+ cwp1 = cpu_cwp_inc(env, env->cwp + 1);
+#ifndef TARGET_SPARC64
+ /* set wim so that restore will reload the registers */
+ env->wim = 1 << cwp1;
+#endif
+#if defined(DEBUG_WIN)
+ printf("flush_windows: nb=%d\n", offset - 1);
+#endif
+}
+
+void cpu_loop (CPUSPARCState *env)
+{
+ CPUState *cs = CPU(sparc_env_get_cpu(env));
+ int trapnr;
+ abi_long ret;
+ target_siginfo_t info;
+
+ while (1) {
+ cpu_exec_start(cs);
+ trapnr = cpu_exec(cs);
+ cpu_exec_end(cs);
+ process_queued_cpu_work(cs);
+
+ /* Compute PSR before exposing state. */
+ if (env->cc_op != CC_OP_FLAGS) {
+ cpu_get_psr(env);
+ }
+
+ switch (trapnr) {
+#ifndef TARGET_SPARC64
+ case 0x88:
+ case 0x90:
+#else
+ case 0x110:
+ case 0x16d:
+#endif
+ ret = do_syscall (env, env->gregs[1],
+ env->regwptr[0], env->regwptr[1],
+ env->regwptr[2], env->regwptr[3],
+ env->regwptr[4], env->regwptr[5],
+ 0, 0);
+ if (ret == -TARGET_ERESTARTSYS || ret == -TARGET_QEMU_ESIGRETURN) {
+ break;
+ }
+ if ((abi_ulong)ret >= (abi_ulong)(-515)) {
+#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+ env->xcc |= PSR_CARRY;
+#else
+ env->psr |= PSR_CARRY;
+#endif
+ ret = -ret;
+ } else {
+#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+ env->xcc &= ~PSR_CARRY;
+#else
+ env->psr &= ~PSR_CARRY;
+#endif
+ }
+ env->regwptr[0] = ret;
+ /* next instruction */
+ env->pc = env->npc;
+ env->npc = env->npc + 4;
+ break;
+ case 0x83: /* flush windows */
+#ifdef TARGET_ABI32
+ case 0x103:
+#endif
+ flush_windows(env);
+ /* next instruction */
+ env->pc = env->npc;
+ env->npc = env->npc + 4;
+ break;
+#ifndef TARGET_SPARC64
+ case TT_WIN_OVF: /* window overflow */
+ save_window(env);
+ break;
+ case TT_WIN_UNF: /* window underflow */
+ restore_window(env);
+ break;
+ case TT_TFAULT:
+ case TT_DFAULT:
+ {
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ /* XXX: check env->error_code */
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = env->mmuregs[4];
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+ break;
+#else
+ case TT_SPILL: /* window overflow */
+ save_window(env);
+ break;
+ case TT_FILL: /* window underflow */
+ restore_window(env);
+ break;
+ case TT_TFAULT:
+ case TT_DFAULT:
+ {
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ /* XXX: check env->error_code */
+ info.si_code = TARGET_SEGV_MAPERR;
+ if (trapnr == TT_DFAULT)
+ info._sifields._sigfault._addr = env->dmmu.mmuregs[4];
+ else
+ info._sifields._sigfault._addr = cpu_tsptr(env)->tpc;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+ break;
+#ifndef TARGET_ABI32
+ case 0x16e:
+ flush_windows(env);
+ sparc64_get_context(env);
+ break;
+ case 0x16f:
+ flush_windows(env);
+ sparc64_set_context(env);
+ break;
+#endif
+#endif
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+ case TT_ILL_INSN:
+ {
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_ILLOPC;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+ break;
+ case EXCP_DEBUG:
+ {
+ int sig;
+
+ sig = gdb_handlesig(cs, TARGET_SIGTRAP);
+ if (sig)
+ {
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+ }
+ break;
+ case EXCP_ATOMIC:
+ cpu_exec_step_atomic(cs);
+ break;
+ default:
+ printf ("Unhandled trap: 0x%x\n", trapnr);
+ cpu_dump_state(cs, stderr, fprintf, 0);
+ exit(EXIT_FAILURE);
+ }
+ process_pending_signals (env);
+ }
+}
+
+void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
+{
+ int i;
+ env->pc = regs->pc;
+ env->npc = regs->npc;
+ env->y = regs->y;
+ for(i = 0; i < 8; i++)
+ env->gregs[i] = regs->u_regs[i];
+ for(i = 0; i < 8; i++)
+ env->regwptr[i] = regs->u_regs[i + 8];
+}
diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c
new file mode 100644
index 0000000000..45e922f328
--- /dev/null
+++ b/linux-user/sparc/signal.c
@@ -0,0 +1,634 @@
+/*
+ * Emulation of Linux signals
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "target_signal.h"
+#include "signal-common.h"
+#include "linux-user/trace.h"
+
+#define __SUNOS_MAXWIN 31
+
+/* This is what SunOS does, so shall I. */
+struct target_sigcontext {
+ abi_ulong sigc_onstack; /* state to restore */
+
+ abi_ulong sigc_mask; /* sigmask to restore */
+ abi_ulong sigc_sp; /* stack pointer */
+ abi_ulong sigc_pc; /* program counter */
+ abi_ulong sigc_npc; /* next program counter */
+ abi_ulong sigc_psr; /* for condition codes etc */
+ abi_ulong sigc_g1; /* User uses these two registers */
+ abi_ulong sigc_o0; /* within the trampoline code. */
+
+ /* Now comes information regarding the users window set
+ * at the time of the signal.
+ */
+ abi_ulong sigc_oswins; /* outstanding windows */
+
+ /* stack ptrs for each regwin buf */
+ char *sigc_spbuf[__SUNOS_MAXWIN];
+
+ /* Windows to restore after signal */
+ struct {
+ abi_ulong locals[8];
+ abi_ulong ins[8];
+ } sigc_wbuf[__SUNOS_MAXWIN];
+};
+/* A Sparc stack frame */
+struct sparc_stackf {
+ abi_ulong locals[8];
+ abi_ulong ins[8];
+ /* It's simpler to treat fp and callers_pc as elements of ins[]
+ * since we never need to access them ourselves.
+ */
+ char *structptr;
+ abi_ulong xargs[6];
+ abi_ulong xxargs[1];
+};
+
+typedef struct {
+ struct {
+ abi_ulong psr;
+ abi_ulong pc;
+ abi_ulong npc;
+ abi_ulong y;
+ abi_ulong u_regs[16]; /* globals and ins */
+ } si_regs;
+ int si_mask;
+} __siginfo_t;
+
+typedef struct {
+ abi_ulong si_float_regs[32];
+ unsigned long si_fsr;
+ unsigned long si_fpqdepth;
+ struct {
+ unsigned long *insn_addr;
+ unsigned long insn;
+ } si_fpqueue [16];
+} qemu_siginfo_fpu_t;
+
+
+struct target_signal_frame {
+ struct sparc_stackf ss;
+ __siginfo_t info;
+ abi_ulong fpu_save;
+ abi_ulong insns[2] __attribute__ ((aligned (8)));
+ abi_ulong extramask[TARGET_NSIG_WORDS - 1];
+ abi_ulong extra_size; /* Should be 0 */
+ qemu_siginfo_fpu_t fpu_state;
+};
+struct target_rt_signal_frame {
+ struct sparc_stackf ss;
+ siginfo_t info;
+ abi_ulong regs[20];
+ sigset_t mask;
+ abi_ulong fpu_save;
+ unsigned int insns[2];
+ stack_t stack;
+ unsigned int extra_size; /* Should be 0 */
+ qemu_siginfo_fpu_t fpu_state;
+};
+
+#define UREG_O0 16
+#define UREG_O6 22
+#define UREG_I0 0
+#define UREG_I1 1
+#define UREG_I2 2
+#define UREG_I3 3
+#define UREG_I4 4
+#define UREG_I5 5
+#define UREG_I6 6
+#define UREG_I7 7
+#define UREG_L0 8
+#define UREG_FP UREG_I6
+#define UREG_SP UREG_O6
+
+static inline abi_ulong get_sigframe(struct target_sigaction *sa,
+ CPUSPARCState *env,
+ unsigned long framesize)
+{
+ abi_ulong sp = get_sp_from_cpustate(env);
+
+ /*
+ * If we are on the alternate signal stack and would overflow it, don't.
+ * Return an always-bogus address instead so we will die with SIGSEGV.
+ */
+ if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize))) {
+ return -1;
+ }
+
+ /* This is the X/Open sanctioned signal stack switching. */
+ sp = target_sigsp(sp, sa) - framesize;
+
+ /* Always align the stack frame. This handles two cases. First,
+ * sigaltstack need not be mindful of platform specific stack
+ * alignment. Second, if we took this signal because the stack
+ * is not aligned properly, we'd like to take the signal cleanly
+ * and report that.
+ */
+ sp &= ~15UL;
+
+ return sp;
+}
+
+static int
+setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask)
+{
+ int err = 0, i;
+
+ __put_user(env->psr, &si->si_regs.psr);
+ __put_user(env->pc, &si->si_regs.pc);
+ __put_user(env->npc, &si->si_regs.npc);
+ __put_user(env->y, &si->si_regs.y);
+ for (i=0; i < 8; i++) {
+ __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
+ }
+ for (i=0; i < 8; i++) {
+ __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
+ }
+ __put_user(mask, &si->si_mask);
+ return err;
+}
+
+#if 0
+static int
+setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
+ CPUSPARCState *env, unsigned long mask)
+{
+ int err = 0;
+
+ __put_user(mask, &sc->sigc_mask);
+ __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
+ __put_user(env->pc, &sc->sigc_pc);
+ __put_user(env->npc, &sc->sigc_npc);
+ __put_user(env->psr, &sc->sigc_psr);
+ __put_user(env->gregs[1], &sc->sigc_g1);
+ __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
+
+ return err;
+}
+#endif
+#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
+
+void setup_frame(int sig, struct target_sigaction *ka,
+ target_sigset_t *set, CPUSPARCState *env)
+{
+ abi_ulong sf_addr;
+ struct target_signal_frame *sf;
+ int sigframe_size, err, i;
+
+ /* 1. Make sure everything is clean */
+ //synchronize_user_stack();
+
+ sigframe_size = NF_ALIGNEDSZ;
+ sf_addr = get_sigframe(ka, env, sigframe_size);
+ trace_user_setup_frame(env, sf_addr);
+
+ sf = lock_user(VERIFY_WRITE, sf_addr,
+ sizeof(struct target_signal_frame), 0);
+ if (!sf) {
+ goto sigsegv;
+ }
+#if 0
+ if (invalid_frame_pointer(sf, sigframe_size))
+ goto sigill_and_return;
+#endif
+ /* 2. Save the current process state */
+ err = setup___siginfo(&sf->info, env, set->sig[0]);
+ __put_user(0, &sf->extra_size);
+
+ //save_fpu_state(regs, &sf->fpu_state);
+ //__put_user(&sf->fpu_state, &sf->fpu_save);
+
+ __put_user(set->sig[0], &sf->info.si_mask);
+ for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
+ __put_user(set->sig[i + 1], &sf->extramask[i]);
+ }
+
+ for (i = 0; i < 8; i++) {
+ __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
+ }
+ for (i = 0; i < 8; i++) {
+ __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
+ }
+ if (err)
+ goto sigsegv;
+
+ /* 3. signal handler back-trampoline and parameters */
+ env->regwptr[UREG_FP] = sf_addr;
+ env->regwptr[UREG_I0] = sig;
+ env->regwptr[UREG_I1] = sf_addr +
+ offsetof(struct target_signal_frame, info);
+ env->regwptr[UREG_I2] = sf_addr +
+ offsetof(struct target_signal_frame, info);
+
+ /* 4. signal handler */
+ env->pc = ka->_sa_handler;
+ env->npc = (env->pc + 4);
+ /* 5. return to kernel instructions */
+ if (ka->ka_restorer) {
+ env->regwptr[UREG_I7] = ka->ka_restorer;
+ } else {
+ uint32_t val32;
+
+ env->regwptr[UREG_I7] = sf_addr +
+ offsetof(struct target_signal_frame, insns) - 2 * 4;
+
+ /* mov __NR_sigreturn, %g1 */
+ val32 = 0x821020d8;
+ __put_user(val32, &sf->insns[0]);
+
+ /* t 0x10 */
+ val32 = 0x91d02010;
+ __put_user(val32, &sf->insns[1]);
+ if (err)
+ goto sigsegv;
+
+ /* Flush instruction space. */
+ // flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
+ // tb_flush(env);
+ }
+ unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
+ return;
+#if 0
+sigill_and_return:
+ force_sig(TARGET_SIGILL);
+#endif
+sigsegv:
+ unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
+ force_sigsegv(sig);
+}
+
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPUSPARCState *env)
+{
+ fprintf(stderr, "setup_rt_frame: not implemented\n");
+}
+
+long do_sigreturn(CPUSPARCState *env)
+{
+ abi_ulong sf_addr;
+ struct target_signal_frame *sf;
+ uint32_t up_psr, pc, npc;
+ target_sigset_t set;
+ sigset_t host_set;
+ int err=0, i;
+
+ sf_addr = env->regwptr[UREG_FP];
+ trace_user_do_sigreturn(env, sf_addr);
+ if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1)) {
+ goto segv_and_exit;
+ }
+
+ /* 1. Make sure we are not getting garbage from the user */
+
+ if (sf_addr & 3)
+ goto segv_and_exit;
+
+ __get_user(pc, &sf->info.si_regs.pc);
+ __get_user(npc, &sf->info.si_regs.npc);
+
+ if ((pc | npc) & 3) {
+ goto segv_and_exit;
+ }
+
+ /* 2. Restore the state */
+ __get_user(up_psr, &sf->info.si_regs.psr);
+
+ /* User can only change condition codes and FPU enabling in %psr. */
+ env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
+ | (env->psr & ~(PSR_ICC /* | PSR_EF */));
+
+ env->pc = pc;
+ env->npc = npc;
+ __get_user(env->y, &sf->info.si_regs.y);
+ for (i=0; i < 8; i++) {
+ __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
+ }
+ for (i=0; i < 8; i++) {
+ __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
+ }
+
+ /* FIXME: implement FPU save/restore:
+ * __get_user(fpu_save, &sf->fpu_save);
+ * if (fpu_save)
+ * err |= restore_fpu_state(env, fpu_save);
+ */
+
+ /* This is pretty much atomic, no amount locking would prevent
+ * the races which exist anyways.
+ */
+ __get_user(set.sig[0], &sf->info.si_mask);
+ for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+ __get_user(set.sig[i], &sf->extramask[i - 1]);
+ }
+
+ target_to_host_sigset_internal(&host_set, &set);
+ set_sigmask(&host_set);
+
+ if (err) {
+ goto segv_and_exit;
+ }
+ unlock_user_struct(sf, sf_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+
+segv_and_exit:
+ unlock_user_struct(sf, sf_addr, 0);
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
+
+long do_rt_sigreturn(CPUSPARCState *env)
+{
+ trace_user_do_rt_sigreturn(env, 0);
+ fprintf(stderr, "do_rt_sigreturn: not implemented\n");
+ return -TARGET_ENOSYS;
+}
+
+#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+#define SPARC_MC_TSTATE 0
+#define SPARC_MC_PC 1
+#define SPARC_MC_NPC 2
+#define SPARC_MC_Y 3
+#define SPARC_MC_G1 4
+#define SPARC_MC_G2 5
+#define SPARC_MC_G3 6
+#define SPARC_MC_G4 7
+#define SPARC_MC_G5 8
+#define SPARC_MC_G6 9
+#define SPARC_MC_G7 10
+#define SPARC_MC_O0 11
+#define SPARC_MC_O1 12
+#define SPARC_MC_O2 13
+#define SPARC_MC_O3 14
+#define SPARC_MC_O4 15
+#define SPARC_MC_O5 16
+#define SPARC_MC_O6 17
+#define SPARC_MC_O7 18
+#define SPARC_MC_NGREG 19
+
+typedef abi_ulong target_mc_greg_t;
+typedef target_mc_greg_t target_mc_gregset_t[SPARC_MC_NGREG];
+
+struct target_mc_fq {
+ abi_ulong *mcfq_addr;
+ uint32_t mcfq_insn;
+};
+
+struct target_mc_fpu {
+ union {
+ uint32_t sregs[32];
+ uint64_t dregs[32];
+ //uint128_t qregs[16];
+ } mcfpu_fregs;
+ abi_ulong mcfpu_fsr;
+ abi_ulong mcfpu_fprs;
+ abi_ulong mcfpu_gsr;
+ struct target_mc_fq *mcfpu_fq;
+ unsigned char mcfpu_qcnt;
+ unsigned char mcfpu_qentsz;
+ unsigned char mcfpu_enab;
+};
+typedef struct target_mc_fpu target_mc_fpu_t;
+
+typedef struct {
+ target_mc_gregset_t mc_gregs;
+ target_mc_greg_t mc_fp;
+ target_mc_greg_t mc_i7;
+ target_mc_fpu_t mc_fpregs;
+} target_mcontext_t;
+
+struct target_ucontext {
+ struct target_ucontext *tuc_link;
+ abi_ulong tuc_flags;
+ target_sigset_t tuc_sigmask;
+ target_mcontext_t tuc_mcontext;
+};
+
+/* A V9 register window */
+struct target_reg_window {
+ abi_ulong locals[8];
+ abi_ulong ins[8];
+};
+
+#define TARGET_STACK_BIAS 2047
+
+/* {set, get}context() needed for 64-bit SparcLinux userland. */
+void sparc64_set_context(CPUSPARCState *env)
+{
+ abi_ulong ucp_addr;
+ struct target_ucontext *ucp;
+ target_mc_gregset_t *grp;
+ abi_ulong pc, npc, tstate;
+ abi_ulong fp, i7, w_addr;
+ unsigned int i;
+
+ ucp_addr = env->regwptr[UREG_I0];
+ if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1)) {
+ goto do_sigsegv;
+ }
+ grp = &ucp->tuc_mcontext.mc_gregs;
+ __get_user(pc, &((*grp)[SPARC_MC_PC]));
+ __get_user(npc, &((*grp)[SPARC_MC_NPC]));
+ if ((pc | npc) & 3) {
+ goto do_sigsegv;
+ }
+ if (env->regwptr[UREG_I1]) {
+ target_sigset_t target_set;
+ sigset_t set;
+
+ if (TARGET_NSIG_WORDS == 1) {
+ __get_user(target_set.sig[0], &ucp->tuc_sigmask.sig[0]);
+ } else {
+ abi_ulong *src, *dst;
+ src = ucp->tuc_sigmask.sig;
+ dst = target_set.sig;
+ for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
+ __get_user(*dst, src);
+ }
+ }
+ target_to_host_sigset_internal(&set, &target_set);
+ set_sigmask(&set);
+ }
+ env->pc = pc;
+ env->npc = npc;
+ __get_user(env->y, &((*grp)[SPARC_MC_Y]));
+ __get_user(tstate, &((*grp)[SPARC_MC_TSTATE]));
+ env->asi = (tstate >> 24) & 0xff;
+ cpu_put_ccr(env, tstate >> 32);
+ cpu_put_cwp64(env, tstate & 0x1f);
+ __get_user(env->gregs[1], (&(*grp)[SPARC_MC_G1]));
+ __get_user(env->gregs[2], (&(*grp)[SPARC_MC_G2]));
+ __get_user(env->gregs[3], (&(*grp)[SPARC_MC_G3]));
+ __get_user(env->gregs[4], (&(*grp)[SPARC_MC_G4]));
+ __get_user(env->gregs[5], (&(*grp)[SPARC_MC_G5]));
+ __get_user(env->gregs[6], (&(*grp)[SPARC_MC_G6]));
+ __get_user(env->gregs[7], (&(*grp)[SPARC_MC_G7]));
+ __get_user(env->regwptr[UREG_I0], (&(*grp)[SPARC_MC_O0]));
+ __get_user(env->regwptr[UREG_I1], (&(*grp)[SPARC_MC_O1]));
+ __get_user(env->regwptr[UREG_I2], (&(*grp)[SPARC_MC_O2]));
+ __get_user(env->regwptr[UREG_I3], (&(*grp)[SPARC_MC_O3]));
+ __get_user(env->regwptr[UREG_I4], (&(*grp)[SPARC_MC_O4]));
+ __get_user(env->regwptr[UREG_I5], (&(*grp)[SPARC_MC_O5]));
+ __get_user(env->regwptr[UREG_I6], (&(*grp)[SPARC_MC_O6]));
+ __get_user(env->regwptr[UREG_I7], (&(*grp)[SPARC_MC_O7]));
+
+ __get_user(fp, &(ucp->tuc_mcontext.mc_fp));
+ __get_user(i7, &(ucp->tuc_mcontext.mc_i7));
+
+ w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
+ if (put_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
+ abi_ulong) != 0) {
+ goto do_sigsegv;
+ }
+ if (put_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
+ abi_ulong) != 0) {
+ goto do_sigsegv;
+ }
+ /* FIXME this does not match how the kernel handles the FPU in
+ * its sparc64_set_context implementation. In particular the FPU
+ * is only restored if fenab is non-zero in:
+ * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab));
+ */
+ __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs));
+ {
+ uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
+ for (i = 0; i < 64; i++, src++) {
+ if (i & 1) {
+ __get_user(env->fpr[i/2].l.lower, src);
+ } else {
+ __get_user(env->fpr[i/2].l.upper, src);
+ }
+ }
+ }
+ __get_user(env->fsr,
+ &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr));
+ __get_user(env->gsr,
+ &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr));
+ unlock_user_struct(ucp, ucp_addr, 0);
+ return;
+do_sigsegv:
+ unlock_user_struct(ucp, ucp_addr, 0);
+ force_sig(TARGET_SIGSEGV);
+}
+
+void sparc64_get_context(CPUSPARCState *env)
+{
+ abi_ulong ucp_addr;
+ struct target_ucontext *ucp;
+ target_mc_gregset_t *grp;
+ target_mcontext_t *mcp;
+ abi_ulong fp, i7, w_addr;
+ int err;
+ unsigned int i;
+ target_sigset_t target_set;
+ sigset_t set;
+
+ ucp_addr = env->regwptr[UREG_I0];
+ if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0)) {
+ goto do_sigsegv;
+ }
+
+ mcp = &ucp->tuc_mcontext;
+ grp = &mcp->mc_gregs;
+
+ /* Skip over the trap instruction, first. */
+ env->pc = env->npc;
+ env->npc += 4;
+
+ /* If we're only reading the signal mask then do_sigprocmask()
+ * is guaranteed not to fail, which is important because we don't
+ * have any way to signal a failure or restart this operation since
+ * this is not a normal syscall.
+ */
+ err = do_sigprocmask(0, NULL, &set);
+ assert(err == 0);
+ host_to_target_sigset_internal(&target_set, &set);
+ if (TARGET_NSIG_WORDS == 1) {
+ __put_user(target_set.sig[0],
+ (abi_ulong *)&ucp->tuc_sigmask);
+ } else {
+ abi_ulong *src, *dst;
+ src = target_set.sig;
+ dst = ucp->tuc_sigmask.sig;
+ for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) {
+ __put_user(*src, dst);
+ }
+ if (err)
+ goto do_sigsegv;
+ }
+
+ /* XXX: tstate must be saved properly */
+ // __put_user(env->tstate, &((*grp)[SPARC_MC_TSTATE]));
+ __put_user(env->pc, &((*grp)[SPARC_MC_PC]));
+ __put_user(env->npc, &((*grp)[SPARC_MC_NPC]));
+ __put_user(env->y, &((*grp)[SPARC_MC_Y]));
+ __put_user(env->gregs[1], &((*grp)[SPARC_MC_G1]));
+ __put_user(env->gregs[2], &((*grp)[SPARC_MC_G2]));
+ __put_user(env->gregs[3], &((*grp)[SPARC_MC_G3]));
+ __put_user(env->gregs[4], &((*grp)[SPARC_MC_G4]));
+ __put_user(env->gregs[5], &((*grp)[SPARC_MC_G5]));
+ __put_user(env->gregs[6], &((*grp)[SPARC_MC_G6]));
+ __put_user(env->gregs[7], &((*grp)[SPARC_MC_G7]));
+ __put_user(env->regwptr[UREG_I0], &((*grp)[SPARC_MC_O0]));
+ __put_user(env->regwptr[UREG_I1], &((*grp)[SPARC_MC_O1]));
+ __put_user(env->regwptr[UREG_I2], &((*grp)[SPARC_MC_O2]));
+ __put_user(env->regwptr[UREG_I3], &((*grp)[SPARC_MC_O3]));
+ __put_user(env->regwptr[UREG_I4], &((*grp)[SPARC_MC_O4]));
+ __put_user(env->regwptr[UREG_I5], &((*grp)[SPARC_MC_O5]));
+ __put_user(env->regwptr[UREG_I6], &((*grp)[SPARC_MC_O6]));
+ __put_user(env->regwptr[UREG_I7], &((*grp)[SPARC_MC_O7]));
+
+ w_addr = TARGET_STACK_BIAS+env->regwptr[UREG_I6];
+ fp = i7 = 0;
+ if (get_user(fp, w_addr + offsetof(struct target_reg_window, ins[6]),
+ abi_ulong) != 0) {
+ goto do_sigsegv;
+ }
+ if (get_user(i7, w_addr + offsetof(struct target_reg_window, ins[7]),
+ abi_ulong) != 0) {
+ goto do_sigsegv;
+ }
+ __put_user(fp, &(mcp->mc_fp));
+ __put_user(i7, &(mcp->mc_i7));
+
+ {
+ uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs;
+ for (i = 0; i < 64; i++, dst++) {
+ if (i & 1) {
+ __put_user(env->fpr[i/2].l.lower, dst);
+ } else {
+ __put_user(env->fpr[i/2].l.upper, dst);
+ }
+ }
+ }
+ __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr));
+ __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr));
+ __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs));
+
+ if (err)
+ goto do_sigsegv;
+ unlock_user_struct(ucp, ucp_addr, 1);
+ return;
+do_sigsegv:
+ unlock_user_struct(ucp, ucp_addr, 1);
+ force_sig(TARGET_SIGSEGV);
+}
+#endif
diff --git a/linux-user/sparc/target_signal.h b/linux-user/sparc/target_signal.h
index e445e2b463..467abea49e 100644
--- a/linux-user/sparc/target_signal.h
+++ b/linux-user/sparc/target_signal.h
@@ -33,5 +33,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
return state->regwptr[UREG_FP];
}
-
+#define TARGET_ARCH_HAS_SETUP_FRAME
#endif /* SPARC_TARGET_SIGNAL_H */
diff --git a/linux-user/sparc64/cpu_loop.c b/linux-user/sparc64/cpu_loop.c
new file mode 100644
index 0000000000..4fd44e1b1e
--- /dev/null
+++ b/linux-user/sparc64/cpu_loop.c
@@ -0,0 +1,20 @@
+/*
+ * qemu user cpu loop
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "../sparc/cpu_loop.c"
diff --git a/linux-user/sparc64/signal.c b/linux-user/sparc64/signal.c
new file mode 100644
index 0000000000..c263eb0f08
--- /dev/null
+++ b/linux-user/sparc64/signal.c
@@ -0,0 +1,20 @@
+/*
+ * Emulation of Linux signals
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#define SPARC_TARGET_SIGNAL_H /* to only include sparc64/target_signal.h */
+#include "../sparc/signal.c"
diff --git a/linux-user/sparc64/target_signal.h b/linux-user/sparc64/target_signal.h
index 4449457baf..14b01d9632 100644
--- a/linux-user/sparc64/target_signal.h
+++ b/linux-user/sparc64/target_signal.h
@@ -33,5 +33,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
return state->regwptr[UREG_FP];
}
-
+#define TARGET_ARCH_HAS_SETUP_FRAME
#endif /* SPARC64_TARGET_SIGNAL_H */
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 643b8833de..e4825747f9 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -259,10 +259,22 @@ static int gettid(void) {
return -ENOSYS;
}
#endif
-#if defined(TARGET_NR_getdents) && defined(__NR_getdents)
+
+/* For the 64-bit guest on 32-bit host case we must emulate
+ * getdents using getdents64, because otherwise the host
+ * might hand us back more dirent records than we can fit
+ * into the guest buffer after structure format conversion.
+ * Otherwise we emulate getdents with getdents if the host has it.
+ */
+#if defined(__NR_getdents) && HOST_LONG_BITS >= TARGET_ABI_BITS
+#define EMULATE_GETDENTS_WITH_GETDENTS
+#endif
+
+#if defined(TARGET_NR_getdents) && defined(EMULATE_GETDENTS_WITH_GETDENTS)
_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
#endif
-#if !defined(__NR_getdents) || \
+#if (defined(TARGET_NR_getdents) && \
+ !defined(EMULATE_GETDENTS_WITH_GETDENTS)) || \
(defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
#endif
@@ -6588,10 +6600,10 @@ typedef abi_long from_flock64_fn(struct flock64 *fl, abi_ulong target_addr);
typedef abi_long to_flock64_fn(abi_ulong target_addr, const struct flock64 *fl);
#if defined(TARGET_ARM) && TARGET_ABI_BITS == 32
-static inline abi_long copy_from_user_eabi_flock64(struct flock64 *fl,
+static inline abi_long copy_from_user_oabi_flock64(struct flock64 *fl,
abi_ulong target_flock_addr)
{
- struct target_eabi_flock64 *target_fl;
+ struct target_oabi_flock64 *target_fl;
short l_type;
if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
@@ -6608,10 +6620,10 @@ static inline abi_long copy_from_user_eabi_flock64(struct flock64 *fl,
return 0;
}
-static inline abi_long copy_to_user_eabi_flock64(abi_ulong target_flock_addr,
+static inline abi_long copy_to_user_oabi_flock64(abi_ulong target_flock_addr,
const struct flock64 *fl)
{
- struct target_eabi_flock64 *target_fl;
+ struct target_oabi_flock64 *target_fl;
short l_type;
if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
@@ -10163,7 +10175,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#endif
#ifdef TARGET_NR_getdents
case TARGET_NR_getdents:
-#ifdef __NR_getdents
+#ifdef EMULATE_GETDENTS_WITH_GETDENTS
#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
{
struct target_dirent *target_dirp;
@@ -11617,9 +11629,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
to_flock64_fn *copyto = copy_to_user_flock64;
#ifdef TARGET_ARM
- if (((CPUARMState *)cpu_env)->eabi) {
- copyfrom = copy_from_user_eabi_flock64;
- copyto = copy_to_user_eabi_flock64;
+ if (!((CPUARMState *)cpu_env)->eabi) {
+ copyfrom = copy_from_user_oabi_flock64;
+ copyto = copy_to_user_oabi_flock64;
}
#endif
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 23f5bccf0e..361bb83a29 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -2649,29 +2649,12 @@ struct target_flock {
};
struct target_flock64 {
- short l_type;
- short l_whence;
-#if defined(TARGET_PPC) || defined(TARGET_X86_64) || defined(TARGET_MIPS) \
- || defined(TARGET_SPARC) || defined(TARGET_HPPA) \
- || defined(TARGET_MICROBLAZE) || defined(TARGET_TILEGX) \
- || defined(TARGET_XTENSA)
- int __pad;
-#endif
- abi_llong l_start;
- abi_llong l_len;
- int l_pid;
-} QEMU_PACKED;
-
-#ifdef TARGET_ARM
-struct target_eabi_flock64 {
- short l_type;
- short l_whence;
- int __pad;
+ abi_short l_type;
+ abi_short l_whence;
abi_llong l_start;
abi_llong l_len;
- int l_pid;
-} QEMU_PACKED;
-#endif
+ abi_int l_pid;
+};
struct target_f_owner_ex {
int type; /* Owner type of ID. */
diff --git a/linux-user/tilegx/cpu_loop.c b/linux-user/tilegx/cpu_loop.c
new file mode 100644
index 0000000000..4f39eb9ad3
--- /dev/null
+++ b/linux-user/tilegx/cpu_loop.c
@@ -0,0 +1,286 @@
+/*
+ * qemu user cpu loop
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "cpu_loop-common.h"
+
+static void gen_sigill_reg(CPUTLGState *env)
+{
+ target_siginfo_t info;
+
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_PRVREG;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+}
+
+static void do_signal(CPUTLGState *env, int signo, int sigcode)
+{
+ target_siginfo_t info;
+
+ info.si_signo = signo;
+ info.si_errno = 0;
+ info._sifields._sigfault._addr = env->pc;
+
+ if (signo == TARGET_SIGSEGV) {
+ /* The passed in sigcode is a dummy; check for a page mapping
+ and pass either MAPERR or ACCERR. */
+ target_ulong addr = env->excaddr;
+ info._sifields._sigfault._addr = addr;
+ if (page_check_range(addr, 1, PAGE_VALID) < 0) {
+ sigcode = TARGET_SEGV_MAPERR;
+ } else {
+ sigcode = TARGET_SEGV_ACCERR;
+ }
+ }
+ info.si_code = sigcode;
+
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+}
+
+static void gen_sigsegv_maperr(CPUTLGState *env, target_ulong addr)
+{
+ env->excaddr = addr;
+ do_signal(env, TARGET_SIGSEGV, 0);
+}
+
+static void set_regval(CPUTLGState *env, uint8_t reg, uint64_t val)
+{
+ if (unlikely(reg >= TILEGX_R_COUNT)) {
+ switch (reg) {
+ case TILEGX_R_SN:
+ case TILEGX_R_ZERO:
+ return;
+ case TILEGX_R_IDN0:
+ case TILEGX_R_IDN1:
+ case TILEGX_R_UDN0:
+ case TILEGX_R_UDN1:
+ case TILEGX_R_UDN2:
+ case TILEGX_R_UDN3:
+ gen_sigill_reg(env);
+ return;
+ default:
+ g_assert_not_reached();
+ }
+ }
+ env->regs[reg] = val;
+}
+
+/*
+ * Compare the 8-byte contents of the CmpValue SPR with the 8-byte value in
+ * memory at the address held in the first source register. If the values are
+ * not equal, then no memory operation is performed. If the values are equal,
+ * the 8-byte quantity from the second source register is written into memory
+ * at the address held in the first source register. In either case, the result
+ * of the instruction is the value read from memory. The compare and write to
+ * memory are atomic and thus can be used for synchronization purposes. This
+ * instruction only operates for addresses aligned to a 8-byte boundary.
+ * Unaligned memory access causes an Unaligned Data Reference interrupt.
+ *
+ * Functional Description (64-bit)
+ * uint64_t memVal = memoryReadDoubleWord (rf[SrcA]);
+ * rf[Dest] = memVal;
+ * if (memVal == SPR[CmpValueSPR])
+ * memoryWriteDoubleWord (rf[SrcA], rf[SrcB]);
+ *
+ * Functional Description (32-bit)
+ * uint64_t memVal = signExtend32 (memoryReadWord (rf[SrcA]));
+ * rf[Dest] = memVal;
+ * if (memVal == signExtend32 (SPR[CmpValueSPR]))
+ * memoryWriteWord (rf[SrcA], rf[SrcB]);
+ *
+ *
+ * This function also processes exch and exch4 which need not process SPR.
+ */
+static void do_exch(CPUTLGState *env, bool quad, bool cmp)
+{
+ target_ulong addr;
+ target_long val, sprval;
+
+ start_exclusive();
+
+ addr = env->atomic_srca;
+ if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) {
+ goto sigsegv_maperr;
+ }
+
+ if (cmp) {
+ if (quad) {
+ sprval = env->spregs[TILEGX_SPR_CMPEXCH];
+ } else {
+ sprval = sextract64(env->spregs[TILEGX_SPR_CMPEXCH], 0, 32);
+ }
+ }
+
+ if (!cmp || val == sprval) {
+ target_long valb = env->atomic_srcb;
+ if (quad ? put_user_u64(valb, addr) : put_user_u32(valb, addr)) {
+ goto sigsegv_maperr;
+ }
+ }
+
+ set_regval(env, env->atomic_dstr, val);
+ end_exclusive();
+ return;
+
+ sigsegv_maperr:
+ end_exclusive();
+ gen_sigsegv_maperr(env, addr);
+}
+
+static void do_fetch(CPUTLGState *env, int trapnr, bool quad)
+{
+ int8_t write = 1;
+ target_ulong addr;
+ target_long val, valb;
+
+ start_exclusive();
+
+ addr = env->atomic_srca;
+ valb = env->atomic_srcb;
+ if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) {
+ goto sigsegv_maperr;
+ }
+
+ switch (trapnr) {
+ case TILEGX_EXCP_OPCODE_FETCHADD:
+ case TILEGX_EXCP_OPCODE_FETCHADD4:
+ valb += val;
+ break;
+ case TILEGX_EXCP_OPCODE_FETCHADDGEZ:
+ valb += val;
+ if (valb < 0) {
+ write = 0;
+ }
+ break;
+ case TILEGX_EXCP_OPCODE_FETCHADDGEZ4:
+ valb += val;
+ if ((int32_t)valb < 0) {
+ write = 0;
+ }
+ break;
+ case TILEGX_EXCP_OPCODE_FETCHAND:
+ case TILEGX_EXCP_OPCODE_FETCHAND4:
+ valb &= val;
+ break;
+ case TILEGX_EXCP_OPCODE_FETCHOR:
+ case TILEGX_EXCP_OPCODE_FETCHOR4:
+ valb |= val;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (write) {
+ if (quad ? put_user_u64(valb, addr) : put_user_u32(valb, addr)) {
+ goto sigsegv_maperr;
+ }
+ }
+
+ set_regval(env, env->atomic_dstr, val);
+ end_exclusive();
+ return;
+
+ sigsegv_maperr:
+ end_exclusive();
+ gen_sigsegv_maperr(env, addr);
+}
+
+void cpu_loop(CPUTLGState *env)
+{
+ CPUState *cs = CPU(tilegx_env_get_cpu(env));
+ int trapnr;
+
+ while (1) {
+ cpu_exec_start(cs);
+ trapnr = cpu_exec(cs);
+ cpu_exec_end(cs);
+ process_queued_cpu_work(cs);
+
+ switch (trapnr) {
+ case TILEGX_EXCP_SYSCALL:
+ {
+ abi_ulong ret = do_syscall(env, env->regs[TILEGX_R_NR],
+ env->regs[0], env->regs[1],
+ env->regs[2], env->regs[3],
+ env->regs[4], env->regs[5],
+ env->regs[6], env->regs[7]);
+ if (ret == -TARGET_ERESTARTSYS) {
+ env->pc -= 8;
+ } else if (ret != -TARGET_QEMU_ESIGRETURN) {
+ env->regs[TILEGX_R_RE] = ret;
+ env->regs[TILEGX_R_ERR] = TILEGX_IS_ERRNO(ret) ? -ret : 0;
+ }
+ break;
+ }
+ case TILEGX_EXCP_OPCODE_EXCH:
+ do_exch(env, true, false);
+ break;
+ case TILEGX_EXCP_OPCODE_EXCH4:
+ do_exch(env, false, false);
+ break;
+ case TILEGX_EXCP_OPCODE_CMPEXCH:
+ do_exch(env, true, true);
+ break;
+ case TILEGX_EXCP_OPCODE_CMPEXCH4:
+ do_exch(env, false, true);
+ break;
+ case TILEGX_EXCP_OPCODE_FETCHADD:
+ case TILEGX_EXCP_OPCODE_FETCHADDGEZ:
+ case TILEGX_EXCP_OPCODE_FETCHAND:
+ case TILEGX_EXCP_OPCODE_FETCHOR:
+ do_fetch(env, trapnr, true);
+ break;
+ case TILEGX_EXCP_OPCODE_FETCHADD4:
+ case TILEGX_EXCP_OPCODE_FETCHADDGEZ4:
+ case TILEGX_EXCP_OPCODE_FETCHAND4:
+ case TILEGX_EXCP_OPCODE_FETCHOR4:
+ do_fetch(env, trapnr, false);
+ break;
+ case TILEGX_EXCP_SIGNAL:
+ do_signal(env, env->signo, env->sigcode);
+ break;
+ case TILEGX_EXCP_REG_IDN_ACCESS:
+ case TILEGX_EXCP_REG_UDN_ACCESS:
+ gen_sigill_reg(env);
+ break;
+ case EXCP_ATOMIC:
+ cpu_exec_step_atomic(cs);
+ break;
+ default:
+ fprintf(stderr, "trapnr is %d[0x%x].\n", trapnr, trapnr);
+ g_assert_not_reached();
+ }
+ process_pending_signals(env);
+ }
+}
+
+void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
+{
+ int i;
+ for (i = 0; i < TILEGX_R_COUNT; i++) {
+ env->regs[i] = regs->regs[i];
+ }
+ for (i = 0; i < TILEGX_SPR_COUNT; i++) {
+ env->spregs[i] = 0;
+ }
+ env->pc = regs->pc;
+}
diff --git a/linux-user/tilegx/signal.c b/linux-user/tilegx/signal.c
new file mode 100644
index 0000000000..d0ed3de569
--- /dev/null
+++ b/linux-user/tilegx/signal.c
@@ -0,0 +1,179 @@
+/*
+ * Emulation of Linux signals
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "target_signal.h"
+#include "signal-common.h"
+#include "linux-user/trace.h"
+
+struct target_sigcontext {
+ union {
+ /* General-purpose registers. */
+ abi_ulong gregs[56];
+ struct {
+ abi_ulong __gregs[53];
+ abi_ulong tp; /* Aliases gregs[TREG_TP]. */
+ abi_ulong sp; /* Aliases gregs[TREG_SP]. */
+ abi_ulong lr; /* Aliases gregs[TREG_LR]. */
+ };
+ };
+ abi_ulong pc; /* Program counter. */
+ abi_ulong ics; /* In Interrupt Critical Section? */
+ abi_ulong faultnum; /* Fault number. */
+ abi_ulong pad[5];
+};
+
+struct target_ucontext {
+ abi_ulong tuc_flags;
+ abi_ulong tuc_link;
+ target_stack_t tuc_stack;
+ struct target_sigcontext tuc_mcontext;
+ target_sigset_t tuc_sigmask; /* mask last for extensibility */
+};
+
+struct target_rt_sigframe {
+ unsigned char save_area[16]; /* caller save area */
+ struct target_siginfo info;
+ struct target_ucontext uc;
+ abi_ulong retcode[2];
+};
+
+#define INSN_MOVELI_R10_139 0x00045fe551483000ULL /* { moveli r10, 139 } */
+#define INSN_SWINT1 0x286b180051485000ULL /* { swint1 } */
+
+
+static void setup_sigcontext(struct target_sigcontext *sc,
+ CPUArchState *env, int signo)
+{
+ int i;
+
+ for (i = 0; i < TILEGX_R_COUNT; ++i) {
+ __put_user(env->regs[i], &sc->gregs[i]);
+ }
+
+ __put_user(env->pc, &sc->pc);
+ __put_user(0, &sc->ics);
+ __put_user(signo, &sc->faultnum);
+}
+
+static void restore_sigcontext(CPUTLGState *env, struct target_sigcontext *sc)
+{
+ int i;
+
+ for (i = 0; i < TILEGX_R_COUNT; ++i) {
+ __get_user(env->regs[i], &sc->gregs[i]);
+ }
+
+ __get_user(env->pc, &sc->pc);
+}
+
+static abi_ulong get_sigframe(struct target_sigaction *ka, CPUArchState *env,
+ size_t frame_size)
+{
+ unsigned long sp = get_sp_from_cpustate(env);
+
+ if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size))) {
+ return -1UL;
+ }
+
+ sp = target_sigsp(sp, ka) - frame_size;
+ sp &= -16UL;
+ return sp;
+}
+
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPUArchState *env)
+{
+ abi_ulong frame_addr;
+ struct target_rt_sigframe *frame;
+ unsigned long restorer;
+
+ frame_addr = get_sigframe(ka, env, sizeof(*frame));
+ trace_user_setup_rt_frame(env, frame_addr);
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+ goto give_sigsegv;
+ }
+
+ /* Always write at least the signal number for the stack backtracer. */
+ if (ka->sa_flags & TARGET_SA_SIGINFO) {
+ /* At sigreturn time, restore the callee-save registers too. */
+ tswap_siginfo(&frame->info, info);
+ /* regs->flags |= PT_FLAGS_RESTORE_REGS; FIXME: we can skip it? */
+ } else {
+ __put_user(info->si_signo, &frame->info.si_signo);
+ }
+
+ /* Create the ucontext. */
+ __put_user(0, &frame->uc.tuc_flags);
+ __put_user(0, &frame->uc.tuc_link);
+ target_save_altstack(&frame->uc.tuc_stack, env);
+ setup_sigcontext(&frame->uc.tuc_mcontext, env, info->si_signo);
+
+ if (ka->sa_flags & TARGET_SA_RESTORER) {
+ restorer = (unsigned long) ka->sa_restorer;
+ } else {
+ __put_user(INSN_MOVELI_R10_139, &frame->retcode[0]);
+ __put_user(INSN_SWINT1, &frame->retcode[1]);
+ restorer = frame_addr + offsetof(struct target_rt_sigframe, retcode);
+ }
+ env->pc = (unsigned long) ka->_sa_handler;
+ env->regs[TILEGX_R_SP] = (unsigned long) frame;
+ env->regs[TILEGX_R_LR] = restorer;
+ env->regs[0] = (unsigned long) sig;
+ env->regs[1] = (unsigned long) &frame->info;
+ env->regs[2] = (unsigned long) &frame->uc;
+ /* regs->flags |= PT_FLAGS_CALLER_SAVES; FIXME: we can skip it? */
+
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+
+give_sigsegv:
+ force_sigsegv(sig);
+}
+
+long do_rt_sigreturn(CPUTLGState *env)
+{
+ abi_ulong frame_addr = env->regs[TILEGX_R_SP];
+ struct target_rt_sigframe *frame;
+ sigset_t set;
+
+ trace_user_do_rt_sigreturn(env, frame_addr);
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+ goto badframe;
+ }
+ target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
+ set_sigmask(&set);
+
+ restore_sigcontext(env, &frame->uc.tuc_mcontext);
+ if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
+ uc.tuc_stack),
+ 0, env->regs[TILEGX_R_SP]) == -EFAULT) {
+ goto badframe;
+ }
+
+ unlock_user_struct(frame, frame_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+
+
+ badframe:
+ unlock_user_struct(frame, frame_addr, 0);
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
diff --git a/linux-user/tilegx/target_signal.h b/linux-user/tilegx/target_signal.h
index f64551a8cf..a74fa37aac 100644
--- a/linux-user/tilegx/target_signal.h
+++ b/linux-user/tilegx/target_signal.h
@@ -24,6 +24,4 @@ static inline abi_ulong get_sp_from_cpustate(CPUTLGState *state)
{
return state->regs[TILEGX_R_SP];
}
-
-
#endif /* TILEGX_TARGET_SIGNAL_H */
diff --git a/linux-user/x86_64/cpu_loop.c b/linux-user/x86_64/cpu_loop.c
new file mode 100644
index 0000000000..8b5af8ea1f
--- /dev/null
+++ b/linux-user/x86_64/cpu_loop.c
@@ -0,0 +1,20 @@
+/*
+ * qemu user cpu loop
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "../i386/cpu_loop.c"
diff --git a/linux-user/x86_64/signal.c b/linux-user/x86_64/signal.c
new file mode 100644
index 0000000000..a509a38045
--- /dev/null
+++ b/linux-user/x86_64/signal.c
@@ -0,0 +1,20 @@
+/*
+ * Emulation of Linux signals
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#define I386_TARGET_SIGNAL_H /* to only include x86_64/target_signal.h */
+#include "../i386/signal.c"
diff --git a/linux-user/x86_64/target_signal.h b/linux-user/x86_64/target_signal.h
index 1e95f4a684..6b01b5acb7 100644
--- a/linux-user/x86_64/target_signal.h
+++ b/linux-user/x86_64/target_signal.h
@@ -25,5 +25,4 @@ static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
{
return state->regs[R_ESP];
}
-
#endif /* X86_64_TARGET_SIGNAL_H */
diff --git a/linux-user/xtensa/cpu_loop.c b/linux-user/xtensa/cpu_loop.c
new file mode 100644
index 0000000000..d142988ebe
--- /dev/null
+++ b/linux-user/xtensa/cpu_loop.c
@@ -0,0 +1,267 @@
+/*
+ * qemu user cpu loop
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "cpu_loop-common.h"
+
+static void xtensa_rfw(CPUXtensaState *env)
+{
+ xtensa_restore_owb(env);
+ env->pc = env->sregs[EPC1];
+}
+
+static void xtensa_rfwu(CPUXtensaState *env)
+{
+ env->sregs[WINDOW_START] |= (1 << env->sregs[WINDOW_BASE]);
+ xtensa_rfw(env);
+}
+
+static void xtensa_rfwo(CPUXtensaState *env)
+{
+ env->sregs[WINDOW_START] &= ~(1 << env->sregs[WINDOW_BASE]);
+ xtensa_rfw(env);
+}
+
+static void xtensa_overflow4(CPUXtensaState *env)
+{
+ put_user_ual(env->regs[0], env->regs[5] - 16);
+ put_user_ual(env->regs[1], env->regs[5] - 12);
+ put_user_ual(env->regs[2], env->regs[5] - 8);
+ put_user_ual(env->regs[3], env->regs[5] - 4);
+ xtensa_rfwo(env);
+}
+
+static void xtensa_underflow4(CPUXtensaState *env)
+{
+ get_user_ual(env->regs[0], env->regs[5] - 16);
+ get_user_ual(env->regs[1], env->regs[5] - 12);
+ get_user_ual(env->regs[2], env->regs[5] - 8);
+ get_user_ual(env->regs[3], env->regs[5] - 4);
+ xtensa_rfwu(env);
+}
+
+static void xtensa_overflow8(CPUXtensaState *env)
+{
+ put_user_ual(env->regs[0], env->regs[9] - 16);
+ get_user_ual(env->regs[0], env->regs[1] - 12);
+ put_user_ual(env->regs[1], env->regs[9] - 12);
+ put_user_ual(env->regs[2], env->regs[9] - 8);
+ put_user_ual(env->regs[3], env->regs[9] - 4);
+ put_user_ual(env->regs[4], env->regs[0] - 32);
+ put_user_ual(env->regs[5], env->regs[0] - 28);
+ put_user_ual(env->regs[6], env->regs[0] - 24);
+ put_user_ual(env->regs[7], env->regs[0] - 20);
+ xtensa_rfwo(env);
+}
+
+static void xtensa_underflow8(CPUXtensaState *env)
+{
+ get_user_ual(env->regs[0], env->regs[9] - 16);
+ get_user_ual(env->regs[1], env->regs[9] - 12);
+ get_user_ual(env->regs[2], env->regs[9] - 8);
+ get_user_ual(env->regs[7], env->regs[1] - 12);
+ get_user_ual(env->regs[3], env->regs[9] - 4);
+ get_user_ual(env->regs[4], env->regs[7] - 32);
+ get_user_ual(env->regs[5], env->regs[7] - 28);
+ get_user_ual(env->regs[6], env->regs[7] - 24);
+ get_user_ual(env->regs[7], env->regs[7] - 20);
+ xtensa_rfwu(env);
+}
+
+static void xtensa_overflow12(CPUXtensaState *env)
+{
+ put_user_ual(env->regs[0], env->regs[13] - 16);
+ get_user_ual(env->regs[0], env->regs[1] - 12);
+ put_user_ual(env->regs[1], env->regs[13] - 12);
+ put_user_ual(env->regs[2], env->regs[13] - 8);
+ put_user_ual(env->regs[3], env->regs[13] - 4);
+ put_user_ual(env->regs[4], env->regs[0] - 48);
+ put_user_ual(env->regs[5], env->regs[0] - 44);
+ put_user_ual(env->regs[6], env->regs[0] - 40);
+ put_user_ual(env->regs[7], env->regs[0] - 36);
+ put_user_ual(env->regs[8], env->regs[0] - 32);
+ put_user_ual(env->regs[9], env->regs[0] - 28);
+ put_user_ual(env->regs[10], env->regs[0] - 24);
+ put_user_ual(env->regs[11], env->regs[0] - 20);
+ xtensa_rfwo(env);
+}
+
+static void xtensa_underflow12(CPUXtensaState *env)
+{
+ get_user_ual(env->regs[0], env->regs[13] - 16);
+ get_user_ual(env->regs[1], env->regs[13] - 12);
+ get_user_ual(env->regs[2], env->regs[13] - 8);
+ get_user_ual(env->regs[11], env->regs[1] - 12);
+ get_user_ual(env->regs[3], env->regs[13] - 4);
+ get_user_ual(env->regs[4], env->regs[11] - 48);
+ get_user_ual(env->regs[5], env->regs[11] - 44);
+ get_user_ual(env->regs[6], env->regs[11] - 40);
+ get_user_ual(env->regs[7], env->regs[11] - 36);
+ get_user_ual(env->regs[8], env->regs[11] - 32);
+ get_user_ual(env->regs[9], env->regs[11] - 28);
+ get_user_ual(env->regs[10], env->regs[11] - 24);
+ get_user_ual(env->regs[11], env->regs[11] - 20);
+ xtensa_rfwu(env);
+}
+
+void cpu_loop(CPUXtensaState *env)
+{
+ CPUState *cs = CPU(xtensa_env_get_cpu(env));
+ target_siginfo_t info;
+ abi_ulong ret;
+ int trapnr;
+
+ while (1) {
+ cpu_exec_start(cs);
+ trapnr = cpu_exec(cs);
+ cpu_exec_end(cs);
+ process_queued_cpu_work(cs);
+
+ env->sregs[PS] &= ~PS_EXCM;
+ switch (trapnr) {
+ case EXCP_INTERRUPT:
+ break;
+
+ case EXC_WINDOW_OVERFLOW4:
+ xtensa_overflow4(env);
+ break;
+ case EXC_WINDOW_UNDERFLOW4:
+ xtensa_underflow4(env);
+ break;
+ case EXC_WINDOW_OVERFLOW8:
+ xtensa_overflow8(env);
+ break;
+ case EXC_WINDOW_UNDERFLOW8:
+ xtensa_underflow8(env);
+ break;
+ case EXC_WINDOW_OVERFLOW12:
+ xtensa_overflow12(env);
+ break;
+ case EXC_WINDOW_UNDERFLOW12:
+ xtensa_underflow12(env);
+ break;
+
+ case EXC_USER:
+ switch (env->sregs[EXCCAUSE]) {
+ case ILLEGAL_INSTRUCTION_CAUSE:
+ case PRIVILEGED_CAUSE:
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code =
+ env->sregs[EXCCAUSE] == ILLEGAL_INSTRUCTION_CAUSE ?
+ TARGET_ILL_ILLOPC : TARGET_ILL_PRVOPC;
+ info._sifields._sigfault._addr = env->sregs[EPC1];
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+
+ case SYSCALL_CAUSE:
+ env->pc += 3;
+ ret = do_syscall(env, env->regs[2],
+ env->regs[6], env->regs[3],
+ env->regs[4], env->regs[5],
+ env->regs[8], env->regs[9], 0, 0);
+ switch (ret) {
+ default:
+ env->regs[2] = ret;
+ break;
+
+ case -TARGET_ERESTARTSYS:
+ env->pc -= 3;
+ break;
+
+ case -TARGET_QEMU_ESIGRETURN:
+ break;
+ }
+ break;
+
+ case ALLOCA_CAUSE:
+ env->sregs[PS] = deposit32(env->sregs[PS],
+ PS_OWB_SHIFT,
+ PS_OWB_LEN,
+ env->sregs[WINDOW_BASE]);
+
+ switch (env->regs[0] & 0xc0000000) {
+ case 0x00000000:
+ case 0x40000000:
+ xtensa_rotate_window(env, -1);
+ xtensa_underflow4(env);
+ break;
+
+ case 0x80000000:
+ xtensa_rotate_window(env, -2);
+ xtensa_underflow8(env);
+ break;
+
+ case 0xc0000000:
+ xtensa_rotate_window(env, -3);
+ xtensa_underflow12(env);
+ break;
+ }
+ break;
+
+ case INTEGER_DIVIDE_BY_ZERO_CAUSE:
+ info.si_signo = TARGET_SIGFPE;
+ info.si_errno = 0;
+ info.si_code = TARGET_FPE_INTDIV;
+ info._sifields._sigfault._addr = env->sregs[EPC1];
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+
+ case LOAD_PROHIBITED_CAUSE:
+ case STORE_PROHIBITED_CAUSE:
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_ACCERR;
+ info._sifields._sigfault._addr = env->sregs[EXCVADDR];
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+
+ default:
+ fprintf(stderr, "exccause = %d\n", env->sregs[EXCCAUSE]);
+ g_assert_not_reached();
+ }
+ break;
+ case EXCP_DEBUG:
+ trapnr = gdb_handlesig(cs, TARGET_SIGTRAP);
+ if (trapnr) {
+ info.si_signo = trapnr;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ queue_signal(env, trapnr, QEMU_SI_FAULT, &info);
+ }
+ break;
+ case EXC_DEBUG:
+ default:
+ fprintf(stderr, "trapnr = %d\n", trapnr);
+ g_assert_not_reached();
+ }
+ process_pending_signals(env);
+ }
+}
+
+void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
+{
+ int i;
+ for (i = 0; i < 16; ++i) {
+ env->regs[i] = regs->areg[i];
+ }
+ env->sregs[WINDOW_START] = regs->windowstart;
+ env->pc = regs->pc;
+}
diff --git a/linux-user/xtensa/signal.c b/linux-user/xtensa/signal.c
new file mode 100644
index 0000000000..3e483efc61
--- /dev/null
+++ b/linux-user/xtensa/signal.c
@@ -0,0 +1,261 @@
+/*
+ * Emulation of Linux signals
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "target_signal.h"
+#include "signal-common.h"
+#include "linux-user/trace.h"
+
+struct target_sigcontext {
+ abi_ulong sc_pc;
+ abi_ulong sc_ps;
+ abi_ulong sc_lbeg;
+ abi_ulong sc_lend;
+ abi_ulong sc_lcount;
+ abi_ulong sc_sar;
+ abi_ulong sc_acclo;
+ abi_ulong sc_acchi;
+ abi_ulong sc_a[16];
+ abi_ulong sc_xtregs;
+};
+
+struct target_ucontext {
+ abi_ulong tuc_flags;
+ abi_ulong tuc_link;
+ target_stack_t tuc_stack;
+ struct target_sigcontext tuc_mcontext;
+ target_sigset_t tuc_sigmask;
+};
+
+struct target_rt_sigframe {
+ target_siginfo_t info;
+ struct target_ucontext uc;
+ /* TODO: xtregs */
+ uint8_t retcode[6];
+ abi_ulong window[4];
+};
+
+static abi_ulong get_sigframe(struct target_sigaction *sa,
+ CPUXtensaState *env,
+ unsigned long framesize)
+{
+ abi_ulong sp;
+
+ sp = target_sigsp(get_sp_from_cpustate(env), sa);
+
+ return (sp - framesize) & -16;
+}
+
+static int flush_window_regs(CPUXtensaState *env)
+{
+ uint32_t wb = env->sregs[WINDOW_BASE];
+ uint32_t ws = xtensa_replicate_windowstart(env) >> (wb + 1);
+ unsigned d = ctz32(ws) + 1;
+ unsigned i;
+ int ret = 0;
+
+ for (i = d; i < env->config->nareg / 4; i += d) {
+ uint32_t ssp, osp;
+ unsigned j;
+
+ ws >>= d;
+ xtensa_rotate_window(env, d);
+
+ if (ws & 0x1) {
+ ssp = env->regs[5];
+ d = 1;
+ } else if (ws & 0x2) {
+ ssp = env->regs[9];
+ ret |= get_user_ual(osp, env->regs[1] - 12);
+ osp -= 32;
+ d = 2;
+ } else if (ws & 0x4) {
+ ssp = env->regs[13];
+ ret |= get_user_ual(osp, env->regs[1] - 12);
+ osp -= 48;
+ d = 3;
+ } else {
+ g_assert_not_reached();
+ }
+
+ for (j = 0; j < 4; ++j) {
+ ret |= put_user_ual(env->regs[j], ssp - 16 + j * 4);
+ }
+ for (j = 4; j < d * 4; ++j) {
+ ret |= put_user_ual(env->regs[j], osp - 16 + j * 4);
+ }
+ }
+ xtensa_rotate_window(env, d);
+ g_assert(env->sregs[WINDOW_BASE] == wb);
+ return ret == 0;
+}
+
+static int setup_sigcontext(struct target_rt_sigframe *frame,
+ CPUXtensaState *env)
+{
+ struct target_sigcontext *sc = &frame->uc.tuc_mcontext;
+ int i;
+
+ __put_user(env->pc, &sc->sc_pc);
+ __put_user(env->sregs[PS], &sc->sc_ps);
+ __put_user(env->sregs[LBEG], &sc->sc_lbeg);
+ __put_user(env->sregs[LEND], &sc->sc_lend);
+ __put_user(env->sregs[LCOUNT], &sc->sc_lcount);
+ if (!flush_window_regs(env)) {
+ return 0;
+ }
+ for (i = 0; i < 16; ++i) {
+ __put_user(env->regs[i], sc->sc_a + i);
+ }
+ __put_user(0, &sc->sc_xtregs);
+ /* TODO: xtregs */
+ return 1;
+}
+
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPUXtensaState *env)
+{
+ abi_ulong frame_addr;
+ struct target_rt_sigframe *frame;
+ uint32_t ra;
+ int i;
+
+ frame_addr = get_sigframe(ka, env, sizeof(*frame));
+ trace_user_setup_rt_frame(env, frame_addr);
+
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+ goto give_sigsegv;
+ }
+
+ if (ka->sa_flags & SA_SIGINFO) {
+ tswap_siginfo(&frame->info, info);
+ }
+
+ __put_user(0, &frame->uc.tuc_flags);
+ __put_user(0, &frame->uc.tuc_link);
+ target_save_altstack(&frame->uc.tuc_stack, env);
+ if (!setup_sigcontext(frame, env)) {
+ unlock_user_struct(frame, frame_addr, 0);
+ goto give_sigsegv;
+ }
+ for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
+ __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
+ }
+
+ if (ka->sa_flags & TARGET_SA_RESTORER) {
+ ra = ka->sa_restorer;
+ } else {
+ ra = frame_addr + offsetof(struct target_rt_sigframe, retcode);
+#ifdef TARGET_WORDS_BIGENDIAN
+ /* Generate instruction: MOVI a2, __NR_rt_sigreturn */
+ __put_user(0x22, &frame->retcode[0]);
+ __put_user(0x0a, &frame->retcode[1]);
+ __put_user(TARGET_NR_rt_sigreturn, &frame->retcode[2]);
+ /* Generate instruction: SYSCALL */
+ __put_user(0x00, &frame->retcode[3]);
+ __put_user(0x05, &frame->retcode[4]);
+ __put_user(0x00, &frame->retcode[5]);
+#else
+ /* Generate instruction: MOVI a2, __NR_rt_sigreturn */
+ __put_user(0x22, &frame->retcode[0]);
+ __put_user(0xa0, &frame->retcode[1]);
+ __put_user(TARGET_NR_rt_sigreturn, &frame->retcode[2]);
+ /* Generate instruction: SYSCALL */
+ __put_user(0x00, &frame->retcode[3]);
+ __put_user(0x50, &frame->retcode[4]);
+ __put_user(0x00, &frame->retcode[5]);
+#endif
+ }
+ env->sregs[PS] = PS_UM | (3 << PS_RING_SHIFT);
+ if (xtensa_option_enabled(env->config, XTENSA_OPTION_WINDOWED_REGISTER)) {
+ env->sregs[PS] |= PS_WOE | (1 << PS_CALLINC_SHIFT);
+ }
+ memset(env->regs, 0, sizeof(env->regs));
+ env->pc = ka->_sa_handler;
+ env->regs[1] = frame_addr;
+ env->sregs[WINDOW_BASE] = 0;
+ env->sregs[WINDOW_START] = 1;
+
+ env->regs[4] = (ra & 0x3fffffff) | 0x40000000;
+ env->regs[6] = sig;
+ env->regs[7] = frame_addr + offsetof(struct target_rt_sigframe, info);
+ env->regs[8] = frame_addr + offsetof(struct target_rt_sigframe, uc);
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+
+give_sigsegv:
+ force_sigsegv(sig);
+ return;
+}
+
+static void restore_sigcontext(CPUXtensaState *env,
+ struct target_rt_sigframe *frame)
+{
+ struct target_sigcontext *sc = &frame->uc.tuc_mcontext;
+ uint32_t ps;
+ int i;
+
+ __get_user(env->pc, &sc->sc_pc);
+ __get_user(ps, &sc->sc_ps);
+ __get_user(env->sregs[LBEG], &sc->sc_lbeg);
+ __get_user(env->sregs[LEND], &sc->sc_lend);
+ __get_user(env->sregs[LCOUNT], &sc->sc_lcount);
+
+ env->sregs[WINDOW_BASE] = 0;
+ env->sregs[WINDOW_START] = 1;
+ env->sregs[PS] = deposit32(env->sregs[PS],
+ PS_CALLINC_SHIFT,
+ PS_CALLINC_LEN,
+ extract32(ps, PS_CALLINC_SHIFT,
+ PS_CALLINC_LEN));
+ for (i = 0; i < 16; ++i) {
+ __get_user(env->regs[i], sc->sc_a + i);
+ }
+ /* TODO: xtregs */
+}
+
+long do_rt_sigreturn(CPUXtensaState *env)
+{
+ abi_ulong frame_addr = env->regs[1];
+ struct target_rt_sigframe *frame;
+ sigset_t set;
+
+ trace_user_do_rt_sigreturn(env, frame_addr);
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+ goto badframe;
+ }
+ target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
+ set_sigmask(&set);
+
+ restore_sigcontext(env, frame);
+
+ if (do_sigaltstack(frame_addr +
+ offsetof(struct target_rt_sigframe, uc.tuc_stack),
+ 0, get_sp_from_cpustate(env)) == -TARGET_EFAULT) {
+ goto badframe;
+ }
+ unlock_user_struct(frame, frame_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+
+badframe:
+ unlock_user_struct(frame, frame_addr, 0);
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
diff --git a/linux-user/xtensa/target_signal.h b/linux-user/xtensa/target_signal.h
index c6962e70af..4376b2e538 100644
--- a/linux-user/xtensa/target_signal.h
+++ b/linux-user/xtensa/target_signal.h
@@ -24,5 +24,4 @@ static inline abi_ulong get_sp_from_cpustate(CPUXtensaState *state)
{
return state->regs[1];
}
-
#endif
diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index c532889b1f..cdc397308b 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -151,13 +151,7 @@
#define tcg_gen_qemu_ld_reg tcg_gen_qemu_ld_i64
#define tcg_gen_qemu_st_reg tcg_gen_qemu_st_i64
#define tcg_gen_atomic_xchg_reg tcg_gen_atomic_xchg_i64
-#if UINTPTR_MAX == UINT32_MAX
-# define tcg_gen_trunc_reg_ptr(p, r) \
- tcg_gen_trunc_i64_i32(TCGV_PTR_TO_NAT(p), r)
-#else
-# define tcg_gen_trunc_reg_ptr(p, r) \
- tcg_gen_mov_i64(TCGV_PTR_TO_NAT(p), r)
-#endif
+#define tcg_gen_trunc_reg_ptr tcg_gen_trunc_i64_ptr
#else
#define TCGv_reg TCGv_i32
#define tcg_temp_new tcg_temp_new_i32
@@ -251,13 +245,7 @@
#define tcg_gen_qemu_ld_reg tcg_gen_qemu_ld_i32
#define tcg_gen_qemu_st_reg tcg_gen_qemu_st_i32
#define tcg_gen_atomic_xchg_reg tcg_gen_atomic_xchg_i32
-#if UINTPTR_MAX == UINT32_MAX
-# define tcg_gen_trunc_reg_ptr(p, r) \
- tcg_gen_mov_i32(TCGV_PTR_TO_NAT(p), r)
-#else
-# define tcg_gen_trunc_reg_ptr(p, r) \
- tcg_gen_extu_i32_i64(TCGV_PTR_TO_NAT(p), r)
-#endif
+#define tcg_gen_trunc_reg_ptr tcg_gen_ext_i32_ptr
#endif /* TARGET_REGISTER_BITS */
typedef struct DisasCond {
diff --git a/target/m68k/softfloat.c b/target/m68k/softfloat.c
index dffb371c71..e41b07d042 100644
--- a/target/m68k/softfloat.c
+++ b/target/m68k/softfloat.c
@@ -334,7 +334,8 @@ floatx80 floatx80_lognp1(floatx80 a, float_status *status)
if (aSign && aExp >= one_exp) {
if (aExp == one_exp && aSig == one_sig) {
float_raise(float_flag_divbyzero, status);
- packFloatx80(aSign, floatx80_infinity.high, floatx80_infinity.low);
+ return packFloatx80(aSign, floatx80_infinity.high,
+ floatx80_infinity.low);
}
float_raise(float_flag_invalid, status);
return floatx80_default_nan(status);
@@ -1496,7 +1497,7 @@ floatx80 floatx80_sin(floatx80 a, float_status *status)
int32_t compact, l, n, j;
floatx80 fp0, fp1, fp2, fp3, fp4, fp5, x, invtwopi, twopi1, twopi2;
float32 posneg1, twoto63;
- flag adjn, endflag;
+ flag endflag;
aSig = extractFloatx80Frac(a);
aExp = extractFloatx80Exp(a);
@@ -1514,8 +1515,6 @@ floatx80 floatx80_sin(floatx80 a, float_status *status)
return packFloatx80(aSign, 0, 0);
}
- adjn = 0;
-
user_rnd_mode = status->float_rounding_mode;
user_rnd_prec = status->floatx80_rounding_precision;
status->float_rounding_mode = float_round_nearest_even;
@@ -1590,14 +1589,8 @@ floatx80 floatx80_sin(floatx80 a, float_status *status)
status->float_rounding_mode = user_rnd_mode;
status->floatx80_rounding_precision = user_rnd_prec;
- if (adjn) {
- /* COSTINY */
- a = floatx80_sub(fp0, float32_to_floatx80(
- make_float32(0x00800000), status), status);
- } else {
- /* SINTINY */
- a = floatx80_move(a, status);
- }
+ /* SINTINY */
+ a = floatx80_move(a, status);
float_raise(float_flag_inexact, status);
return a;
@@ -1615,7 +1608,7 @@ floatx80 floatx80_sin(floatx80 a, float_status *status)
status); /* FP0 IS R = (X-Y1)-Y2 */
sincont:
- if ((n + adjn) & 1) {
+ if (n & 1) {
/* COSPOLY */
fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
@@ -1628,7 +1621,7 @@ floatx80 floatx80_sin(floatx80 a, float_status *status)
xExp = extractFloatx80Exp(fp0);
xSig = extractFloatx80Frac(fp0);
- if (((n + adjn) >> 1) & 1) {
+ if ((n >> 1) & 1) {
xSign ^= 1;
posneg1 = make_float32(0xBF800000); /* -1 */
} else {
@@ -1680,7 +1673,7 @@ floatx80 floatx80_sin(floatx80 a, float_status *status)
xExp = extractFloatx80Exp(fp0);
xSig = extractFloatx80Frac(fp0);
- xSign ^= ((n + adjn) >> 1) & 1; /* X IS NOW R'= SGN*R */
+ xSign ^= (n >> 1) & 1; /* X IS NOW R'= SGN*R */
fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
@@ -1743,7 +1736,7 @@ floatx80 floatx80_cos(floatx80 a, float_status *status)
int32_t compact, l, n, j;
floatx80 fp0, fp1, fp2, fp3, fp4, fp5, x, invtwopi, twopi1, twopi2;
float32 posneg1, twoto63;
- flag adjn, endflag;
+ flag endflag;
aSig = extractFloatx80Frac(a);
aExp = extractFloatx80Exp(a);
@@ -1761,8 +1754,6 @@ floatx80 floatx80_cos(floatx80 a, float_status *status)
return packFloatx80(0, one_exp, one_sig);
}
- adjn = 1;
-
user_rnd_mode = status->float_rounding_mode;
user_rnd_prec = status->floatx80_rounding_precision;
status->float_rounding_mode = float_round_nearest_even;
@@ -1836,15 +1827,10 @@ floatx80 floatx80_cos(floatx80 a, float_status *status)
status->float_rounding_mode = user_rnd_mode;
status->floatx80_rounding_precision = user_rnd_prec;
- if (adjn) {
- /* COSTINY */
- a = floatx80_sub(fp0, float32_to_floatx80(
- make_float32(0x00800000), status),
- status);
- } else {
- /* SINTINY */
- a = floatx80_move(a, status);
- }
+ /* COSTINY */
+ a = floatx80_sub(fp0, float32_to_floatx80(
+ make_float32(0x00800000), status),
+ status);
float_raise(float_flag_inexact, status);
return a;
@@ -1862,7 +1848,7 @@ floatx80 floatx80_cos(floatx80 a, float_status *status)
status); /* FP0 IS R = (X-Y1)-Y2 */
sincont:
- if ((n + adjn) & 1) {
+ if ((n + 1) & 1) {
/* COSPOLY */
fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
@@ -1875,7 +1861,7 @@ floatx80 floatx80_cos(floatx80 a, float_status *status)
xExp = extractFloatx80Exp(fp0);
xSig = extractFloatx80Frac(fp0);
- if (((n + adjn) >> 1) & 1) {
+ if (((n + 1) >> 1) & 1) {
xSign ^= 1;
posneg1 = make_float32(0xBF800000); /* -1 */
} else {
@@ -1926,7 +1912,7 @@ floatx80 floatx80_cos(floatx80 a, float_status *status)
xExp = extractFloatx80Exp(fp0);
xSig = extractFloatx80Frac(fp0);
- xSign ^= ((n + adjn) >> 1) & 1; /* X IS NOW R'= SGN*R */
+ xSign ^= ((n + 1) >> 1) & 1; /* X IS NOW R'= SGN*R */
fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 6beaf9ed66..e407ba2db3 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -3166,11 +3166,11 @@ DISAS_INSN(subx_mem)
opsize = insn_opsize(insn);
addr_src = AREG(insn, 0);
- tcg_gen_subi_i32(addr_src, addr_src, opsize);
+ tcg_gen_subi_i32(addr_src, addr_src, opsize_bytes(opsize));
src = gen_load(s, opsize, addr_src, 1, IS_USER(s));
addr_dest = AREG(insn, 9);
- tcg_gen_subi_i32(addr_dest, addr_dest, opsize);
+ tcg_gen_subi_i32(addr_dest, addr_dest, opsize_bytes(opsize));
dest = gen_load(s, opsize, addr_dest, 1, IS_USER(s));
gen_subx(s, src, dest, opsize);
diff --git a/target/microblaze/mmu.c b/target/microblaze/mmu.c
index a0f06758f8..9d5e6aa8a5 100644
--- a/target/microblaze/mmu.c
+++ b/target/microblaze/mmu.c
@@ -182,7 +182,7 @@ done:
uint32_t mmu_read(CPUMBState *env, uint32_t rn)
{
unsigned int i;
- uint32_t r;
+ uint32_t r = 0;
if (env->mmu.c_mmu < 2 || !env->mmu.c_mmu_tlb_access) {
qemu_log_mask(LOG_GUEST_ERROR, "MMU access on MMU-less system\n");
@@ -211,6 +211,9 @@ uint32_t mmu_read(CPUMBState *env, uint32_t rn)
}
r = env->mmu.regs[rn];
break;
+ case MMU_R_TLBSX:
+ qemu_log_mask(LOG_GUEST_ERROR, "TLBSX is write-only.\n");
+ break;
default:
r = env->mmu.regs[rn];
break;
@@ -270,6 +273,10 @@ void mmu_write(CPUMBState *env, uint32_t rn, uint32_t v)
env->mmu.regs[rn] = v;
}
break;
+ case MMU_R_TLBX:
+ /* Bit 31 is read-only. */
+ env->mmu.regs[rn] = deposit32(env->mmu.regs[rn], 0, 31, v);
+ break;
case MMU_R_TLBSX:
{
struct microblaze_mmu_lookup lu;
diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c
index 7628b0e25b..100883e2cc 100644
--- a/target/microblaze/translate.c
+++ b/target/microblaze/translate.c
@@ -424,7 +424,7 @@ static inline void msr_write(DisasContext *dc, TCGv v)
/* PVR bit is not writable. */
tcg_gen_andi_tl(t, v, ~MSR_PVR);
tcg_gen_andi_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], MSR_PVR);
- tcg_gen_or_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], v);
+ tcg_gen_or_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], t);
tcg_temp_free(t);
}
@@ -952,7 +952,6 @@ static void dec_load(DisasContext *dc)
tcg_gen_sub_tl(low, tcg_const_tl(3), low);
tcg_gen_andi_tl(t, t, ~3);
tcg_gen_or_tl(t, t, low);
- tcg_gen_mov_tl(env_imm, t);
tcg_temp_free(low);
break;
}
@@ -1104,7 +1103,6 @@ static void dec_store(DisasContext *dc)
tcg_gen_sub_tl(low, tcg_const_tl(3), low);
tcg_gen_andi_tl(t, t, ~3);
tcg_gen_or_tl(t, t, low);
- tcg_gen_mov_tl(env_imm, t);
tcg_temp_free(low);
break;
}
@@ -1412,7 +1410,7 @@ static void dec_fpu(DisasContext *dc)
if ((dc->tb_flags & MSR_EE_FLAG)
&& (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
- && (dc->cpu->cfg.use_fpu != 1)) {
+ && !dc->cpu->cfg.use_fpu) {
tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
t_gen_raise_exception(dc, EXCP_HW_EXCP);
return;
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 8c9e03f54d..7ccd2f460e 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1295,6 +1295,7 @@ int ppc_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int size, int rw,
#if !defined(CONFIG_USER_ONLY)
void ppc_store_sdr1 (CPUPPCState *env, target_ulong value);
+void ppc_store_ptcr(CPUPPCState *env, target_ulong value);
#endif /* !defined(CONFIG_USER_ONLY) */
void ppc_store_msr (CPUPPCState *env, target_ulong value);
@@ -1331,7 +1332,7 @@ void store_booke_tcr (CPUPPCState *env, target_ulong val);
void store_booke_tsr (CPUPPCState *env, target_ulong val);
void ppc_tlb_invalidate_all (CPUPPCState *env);
void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr);
-void cpu_ppc_set_papr(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp);
+void cpu_ppc_set_vhyp(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp);
#endif
#endif
@@ -1585,6 +1586,7 @@ void ppc_compat_add_property(Object *obj, const char *name,
#define SPR_BOOKE_GIVOR13 (0x1BC)
#define SPR_BOOKE_GIVOR14 (0x1BD)
#define SPR_TIR (0x1BE)
+#define SPR_PTCR (0x1D0)
#define SPR_BOOKE_SPEFSCR (0x200)
#define SPR_Exxx_BBEAR (0x201)
#define SPR_Exxx_BBTAR (0x202)
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index 5b739179b8..19453c6813 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -709,6 +709,7 @@ DEF_HELPER_FLAGS_1(load_601_rtcu, TCG_CALL_NO_RWG, tl, env)
#if !defined(CONFIG_USER_ONLY)
#if defined(TARGET_PPC64)
DEF_HELPER_FLAGS_1(load_purr, TCG_CALL_NO_RWG, tl, env)
+DEF_HELPER_2(store_ptcr, void, env, tl)
#endif
DEF_HELPER_2(store_sdr1, void, env, tl)
DEF_HELPER_2(store_pidr, void, env, tl)
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 6de59c5b21..cbe13b18d1 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -72,7 +72,6 @@ static int cap_segstate;
static int cap_booke_sregs;
static int cap_ppc_smt;
static int cap_ppc_smt_possible;
-static int cap_ppc_rma;
static int cap_spapr_tce;
static int cap_spapr_tce_64;
static int cap_spapr_multitce;
@@ -133,7 +132,6 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
cap_segstate = kvm_check_extension(s, KVM_CAP_PPC_SEGSTATE);
cap_booke_sregs = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_SREGS);
cap_ppc_smt_possible = kvm_vm_check_extension(s, KVM_CAP_PPC_SMT_POSSIBLE);
- cap_ppc_rma = kvm_check_extension(s, KVM_CAP_PPC_RMA);
cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE);
cap_spapr_tce_64 = kvm_check_extension(s, KVM_CAP_SPAPR_TCE_64);
cap_spapr_multitce = kvm_check_extension(s, KVM_CAP_SPAPR_MULTITCE);
@@ -2090,6 +2088,10 @@ void kvmppc_set_papr(PowerPCCPU *cpu)
CPUState *cs = CPU(cpu);
int ret;
+ if (!kvm_enabled()) {
+ return;
+ }
+
ret = kvm_vcpu_enable_cap(cs, KVM_CAP_PPC_PAPR, 0);
if (ret) {
error_report("This vCPU type or KVM version does not support PAPR");
@@ -2159,52 +2161,12 @@ void kvmppc_hint_smt_possible(Error **errp)
#ifdef TARGET_PPC64
-off_t kvmppc_alloc_rma(void **rma)
-{
- off_t size;
- int fd;
- struct kvm_allocate_rma ret;
-
- /* If cap_ppc_rma == 0, contiguous RMA allocation is not supported
- * if cap_ppc_rma == 1, contiguous RMA allocation is supported, but
- * not necessary on this hardware
- * if cap_ppc_rma == 2, contiguous RMA allocation is needed on this hardware
- *
- * FIXME: We should allow the user to force contiguous RMA
- * allocation in the cap_ppc_rma==1 case.
- */
- if (cap_ppc_rma < 2) {
- return 0;
- }
-
- fd = kvm_vm_ioctl(kvm_state, KVM_ALLOCATE_RMA, &ret);
- if (fd < 0) {
- fprintf(stderr, "KVM: Error on KVM_ALLOCATE_RMA: %s\n",
- strerror(errno));
- return -1;
- }
-
- size = MIN(ret.rma_size, 256ul << 20);
-
- *rma = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
- if (*rma == MAP_FAILED) {
- fprintf(stderr, "KVM: Error mapping RMA: %s\n", strerror(errno));
- return -1;
- };
-
- return size;
-}
-
uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift)
{
struct kvm_ppc_smmu_info info;
long rampagesize, best_page_shift;
int i;
- if (cap_ppc_rma >= 2) {
- return current_size;
- }
-
/* Find the largest hardware supported page size that's less than
* or equal to the (logical) backing page size of guest RAM */
kvm_get_smmu_info(POWERPC_CPU(first_cpu), &info);
diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
index 4d2789eef6..e2840e1d33 100644
--- a/target/ppc/kvm_ppc.h
+++ b/target/ppc/kvm_ppc.h
@@ -37,7 +37,6 @@ target_ulong kvmppc_configure_v3_mmu(PowerPCCPU *cpu,
bool radix, bool gtse,
uint64_t proc_tbl);
#ifndef CONFIG_USER_ONLY
-off_t kvmppc_alloc_rma(void **rma);
bool kvmppc_spapr_use_multitce(void);
int kvmppc_spapr_enable_inkernel_multitce(void);
void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t page_shift,
@@ -188,11 +187,6 @@ static inline target_ulong kvmppc_configure_v3_mmu(PowerPCCPU *cpu,
}
#ifndef CONFIG_USER_ONLY
-static inline off_t kvmppc_alloc_rma(void **rma)
-{
- return 0;
-}
-
static inline bool kvmppc_spapr_use_multitce(void)
{
return false;
diff --git a/target/ppc/machine.c b/target/ppc/machine.c
index 3d6434a006..ba1b9e531f 100644
--- a/target/ppc/machine.c
+++ b/target/ppc/machine.c
@@ -212,6 +212,11 @@ static int cpu_pre_save(void *opaque)
;
cpu->mig_msr_mask = env->msr_mask & ~metamask;
cpu->mig_insns_flags = env->insns_flags & insns_compat_mask;
+ /* CPU models supported by old machines all have PPC_MEM_TLBIE,
+ * so we set it unconditionally to allow backward migration from
+ * a POWER9 host to a POWER8 host.
+ */
+ cpu->mig_insns_flags |= PPC_MEM_TLBIE;
cpu->mig_insns_flags2 = env->insns_flags2 & insns_compat_mask2;
cpu->mig_nb_BATs = env->nb_BATs;
}
diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c
index 0e4217821b..8c8cba5cc6 100644
--- a/target/ppc/misc_helper.c
+++ b/target/ppc/misc_helper.c
@@ -88,6 +88,18 @@ void helper_store_sdr1(CPUPPCState *env, target_ulong val)
}
}
+#if defined(TARGET_PPC64)
+void helper_store_ptcr(CPUPPCState *env, target_ulong val)
+{
+ PowerPCCPU *cpu = ppc_env_get_cpu(env);
+
+ if (env->spr[SPR_PTCR] != val) {
+ ppc_store_ptcr(env, val);
+ tlb_flush(CPU(cpu));
+ }
+}
+#endif /* defined(TARGET_PPC64) */
+
void helper_store_pidr(CPUPPCState *env, target_ulong val)
{
PowerPCCPU *cpu = ppc_env_get_cpu(env);
diff --git a/target/ppc/mmu-book3s-v3.h b/target/ppc/mmu-book3s-v3.h
index 56095dab52..fdf80987d7 100644
--- a/target/ppc/mmu-book3s-v3.h
+++ b/target/ppc/mmu-book3s-v3.h
@@ -22,6 +22,12 @@
#ifndef CONFIG_USER_ONLY
+/*
+ * Partition table definitions
+ */
+#define PTCR_PATB 0x0FFFFFFFFFFFF000ULL /* Partition Table Base */
+#define PTCR_PATS 0x000000000000001FULL /* Partition Table Size */
+
/* Partition Table Entry Fields */
#define PATBE1_GR 0x8000000000000000
diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
index 7e0adecfd9..a1db20e3a8 100644
--- a/target/ppc/mmu-hash64.c
+++ b/target/ppc/mmu-hash64.c
@@ -942,7 +942,7 @@ void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu, target_ulong ptex,
cpu->env.tlb_need_flush = TLB_NEED_GLOBAL_FLUSH | TLB_NEED_LOCAL_FLUSH;
}
-void ppc_hash64_update_rmls(PowerPCCPU *cpu)
+static void ppc_hash64_update_rmls(PowerPCCPU *cpu)
{
CPUPPCState *env = &cpu->env;
uint64_t lpcr = env->spr[SPR_LPCR];
@@ -977,7 +977,7 @@ void ppc_hash64_update_rmls(PowerPCCPU *cpu)
}
}
-void ppc_hash64_update_vrma(PowerPCCPU *cpu)
+static void ppc_hash64_update_vrma(PowerPCCPU *cpu)
{
CPUPPCState *env = &cpu->env;
const PPCHash64SegmentPageSizes *sps = NULL;
@@ -1028,9 +1028,9 @@ void ppc_hash64_update_vrma(PowerPCCPU *cpu)
slb->sps = sps;
}
-void helper_store_lpcr(CPUPPCState *env, target_ulong val)
+void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val)
{
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
+ CPUPPCState *env = &cpu->env;
uint64_t lpcr = 0;
/* Filter out bits */
@@ -1096,6 +1096,13 @@ void helper_store_lpcr(CPUPPCState *env, target_ulong val)
ppc_hash64_update_vrma(cpu);
}
+void helper_store_lpcr(CPUPPCState *env, target_ulong val)
+{
+ PowerPCCPU *cpu = ppc_env_get_cpu(env);
+
+ ppc_store_lpcr(cpu, val);
+}
+
void ppc_hash64_init(PowerPCCPU *cpu)
{
CPUPPCState *env = &cpu->env;
diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h
index d5fc03441d..53dcec5b93 100644
--- a/target/ppc/mmu-hash64.h
+++ b/target/ppc/mmu-hash64.h
@@ -17,8 +17,7 @@ void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu,
target_ulong pte0, target_ulong pte1);
unsigned ppc_hash64_hpte_page_shift_noslb(PowerPCCPU *cpu,
uint64_t pte0, uint64_t pte1);
-void ppc_hash64_update_vrma(PowerPCCPU *cpu);
-void ppc_hash64_update_rmls(PowerPCCPU *cpu);
+void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val);
void ppc_hash64_init(PowerPCCPU *cpu);
void ppc_hash64_finalize(PowerPCCPU *cpu);
#endif
@@ -102,6 +101,9 @@ void ppc_hash64_finalize(PowerPCCPU *cpu);
static inline hwaddr ppc_hash64_hpt_base(PowerPCCPU *cpu)
{
+ if (cpu->vhyp) {
+ return 0;
+ }
return cpu->env.spr[SPR_SDR1] & SDR_64_HTABORG;
}
diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c
index 8075b7149a..98ce17985b 100644
--- a/target/ppc/mmu_helper.c
+++ b/target/ppc/mmu_helper.c
@@ -2028,6 +2028,35 @@ void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
env->spr[SPR_SDR1] = value;
}
+#if defined(TARGET_PPC64)
+void ppc_store_ptcr(CPUPPCState *env, target_ulong value)
+{
+ PowerPCCPU *cpu = ppc_env_get_cpu(env);
+ target_ulong ptcr_mask = PTCR_PATB | PTCR_PATS;
+ target_ulong patbsize = value & PTCR_PATS;
+
+ qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);
+
+ assert(!cpu->vhyp);
+ assert(env->mmu_model & POWERPC_MMU_3_00);
+
+ if (value & ~ptcr_mask) {
+ error_report("Invalid bits 0x"TARGET_FMT_lx" set in PTCR",
+ value & ~ptcr_mask);
+ value &= ptcr_mask;
+ }
+
+ if (patbsize > 24) {
+ error_report("Invalid Partition Table size 0x" TARGET_FMT_lx
+ " stored in PTCR", patbsize);
+ return;
+ }
+
+ env->spr[SPR_PTCR] = value;
+}
+
+#endif /* defined(TARGET_PPC64) */
+
/* Segment registers load and store */
target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num)
{
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 3beaa1e2f0..2a4140f420 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -7136,6 +7136,9 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
if (env->spr_cb[SPR_SDR1].name) { /* SDR1 Exists */
cpu_fprintf(f, " SDR1 " TARGET_FMT_lx " ", env->spr[SPR_SDR1]);
}
+ if (env->spr_cb[SPR_PTCR].name) { /* PTCR Exists */
+ cpu_fprintf(f, " PTCR " TARGET_FMT_lx " ", env->spr[SPR_PTCR]);
+ }
cpu_fprintf(f, " DAR " TARGET_FMT_lx " DSISR " TARGET_FMT_lx "\n",
env->spr[SPR_DAR], env->spr[SPR_DSISR]);
break;
diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c
index 808f6c1a08..118631efbe 100644
--- a/target/ppc/translate_init.c
+++ b/target/ppc/translate_init.c
@@ -420,6 +420,11 @@ static void spr_write_hior(DisasContext *ctx, int sprn, int gprn)
tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_prefix));
tcg_temp_free(t0);
}
+static void spr_write_ptcr(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_helper_store_ptcr(cpu_env, cpu_gpr[gprn]);
+}
+
#endif
#endif
@@ -8167,6 +8172,18 @@ static void gen_spr_power8_rpr(CPUPPCState *env)
#endif
}
+static void gen_spr_power9_mmu(CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+ /* Partition Table Control */
+ spr_register_hv(env, SPR_PTCR, "PTCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_ptcr,
+ 0x00000000);
+#endif
+}
+
static void init_proc_book3s_common(CPUPPCState *env)
{
gen_spr_ne_601(env);
@@ -8719,6 +8736,7 @@ static void init_proc_POWER9(CPUPPCState *env)
gen_spr_power8_ic(env);
gen_spr_power8_book4(env);
gen_spr_power8_rpr(env);
+ gen_spr_power9_mmu(env);
/* POWER9 Specific registers */
spr_register_kvm(env, SPR_TIDR, "TIDR", NULL, NULL,
@@ -8864,13 +8882,9 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
}
#if !defined(CONFIG_USER_ONLY)
-void cpu_ppc_set_papr(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp)
+void cpu_ppc_set_vhyp(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp)
{
- PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
CPUPPCState *env = &cpu->env;
- ppc_spr_t *lpcr = &env->spr_cb[SPR_LPCR];
- ppc_spr_t *amor = &env->spr_cb[SPR_AMOR];
- CPUState *cs = CPU(cpu);
cpu->vhyp = vhyp;
@@ -8879,62 +8893,6 @@ void cpu_ppc_set_papr(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp)
* hypervisor mode itself
*/
env->msr_mask &= ~MSR_HVB;
-
- /* Set emulated LPCR to not send interrupts to hypervisor. Note that
- * under KVM, the actual HW LPCR will be set differently by KVM itself,
- * the settings below ensure proper operations with TCG in absence of
- * a real hypervisor.
- *
- * Clearing VPM0 will also cause us to use RMOR in mmu-hash64.c for
- * real mode accesses, which thankfully defaults to 0 and isn't
- * accessible in guest mode.
- */
- lpcr->default_value &= ~(LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_KBV);
- lpcr->default_value |= LPCR_LPES0 | LPCR_LPES1;
-
- /* Set RMLS to the max (ie, 16G) */
- lpcr->default_value &= ~LPCR_RMLS;
- lpcr->default_value |= 1ull << LPCR_RMLS_SHIFT;
-
- if (env->mmu_model == POWERPC_MMU_3_00) {
- /* By default we choose legacy mode and switch to new hash or radix
- * when a register process table hcall is made. So disable process
- * tables and guest translation shootdown by default
- *
- * Hot-plugged CPUs inherit from the guest radix setting under
- * KVM but not under TCG. Update the default LPCR to keep new
- * CPUs in sync when radix is enabled.
- */
- if (ppc64_radix_guest(cpu)) {
- lpcr->default_value |= LPCR_UPRT | LPCR_GTSE;
- } else {
- lpcr->default_value &= ~(LPCR_UPRT | LPCR_GTSE);
- }
- }
-
- /* Only enable Power-saving mode Exit Cause exceptions on the boot
- * CPU. The RTAS command start-cpu will enable them on secondaries.
- */
- if (cs == first_cpu) {
- lpcr->default_value |= pcc->lpcr_pm;
- }
-
- /* We should be followed by a CPU reset but update the active value
- * just in case...
- */
- env->spr[SPR_LPCR] = lpcr->default_value;
-
- /* Set a full AMOR so guest can use the AMR as it sees fit */
- env->spr[SPR_AMOR] = amor->default_value = 0xffffffffffffffffull;
-
- /* Update some env bits based on new LPCR value */
- ppc_hash64_update_rmls(cpu);
- ppc_hash64_update_vrma(cpu);
-
- /* Tell KVM that we're in PAPR mode */
- if (kvm_enabled()) {
- kvmppc_set_papr(cpu);
- }
}
#endif /* !defined(CONFIG_USER_ONLY) */
diff --git a/tcg/README b/tcg/README
index bb2ea5121b..a5237a9edb 100644
--- a/tcg/README
+++ b/tcg/README
@@ -431,6 +431,14 @@ double-word product T0. The later is returned in two single-word outputs.
Similar to mulu2, except the two inputs T1 and T2 are signed.
+* mulsh_i32/i64 t0, t1, t2
+* muluh_i32/i64 t0, t1, t2
+
+Provide the high part of a signed or unsigned multiply, respectively.
+If mulu2/muls2 are not provided by the backend, the tcg-op generator
+can obtain the same results can be obtained by emitting a pair of
+opcodes, mul+muluh/mulsh.
+
********* Memory Barrier support
* mb <$arg>
diff --git a/tcg/arm/tcg-target.inc.c b/tcg/arm/tcg-target.inc.c
index dc83f3e5be..56a32a470f 100644
--- a/tcg/arm/tcg-target.inc.c
+++ b/tcg/arm/tcg-target.inc.c
@@ -159,8 +159,8 @@ typedef enum {
INSN_STRD_IMM = 0x004000f0,
INSN_STRD_REG = 0x000000f0,
- INSN_DMB_ISH = 0x5bf07ff5,
- INSN_DMB_MCR = 0xba0f07ee,
+ INSN_DMB_ISH = 0xf57ff05b,
+ INSN_DMB_MCR = 0xee070fba,
/* Architected nop introduced in v6k. */
/* ??? This is an MSR (imm) 0,0,0 insn. Anyone know if this
diff --git a/tcg/tcg-ldst.inc.c b/tcg/tcg-ldst.inc.c
index 0e14cf4357..47f41b921b 100644
--- a/tcg/tcg-ldst.inc.c
+++ b/tcg/tcg-ldst.inc.c
@@ -30,7 +30,7 @@ typedef struct TCGLabelQemuLdst {
TCGReg datahi_reg; /* reg index for high word to be loaded or stored */
tcg_insn_unit *raddr; /* gen code addr of the next IR of qemu_ld/st IR */
tcg_insn_unit *label_ptr[2]; /* label pointers to be updated */
- struct TCGLabelQemuLdst *next;
+ QSIMPLEQ_ENTRY(TCGLabelQemuLdst) next;
} TCGLabelQemuLdst;
@@ -46,7 +46,7 @@ static bool tcg_out_ldst_finalize(TCGContext *s)
TCGLabelQemuLdst *lb;
/* qemu_ld/st slow paths */
- for (lb = s->ldst_labels; lb != NULL; lb = lb->next) {
+ QSIMPLEQ_FOREACH(lb, &s->ldst_labels, next) {
if (lb->is_ld) {
tcg_out_qemu_ld_slow_path(s, lb);
} else {
@@ -72,7 +72,7 @@ static inline TCGLabelQemuLdst *new_ldst_label(TCGContext *s)
{
TCGLabelQemuLdst *l = tcg_malloc(sizeof(*l));
- l->next = s->ldst_labels;
- s->ldst_labels = l;
+ QSIMPLEQ_INSERT_TAIL(&s->ldst_labels, l, next);
+
return l;
}
diff --git a/tcg/tcg-op-vec.c b/tcg/tcg-op-vec.c
index 70ec889bc1..2ca219734d 100644
--- a/tcg/tcg-op-vec.c
+++ b/tcg/tcg-op-vec.c
@@ -355,8 +355,8 @@ void tcg_gen_cmp_vec(TCGCond cond, unsigned vece,
TCGType type = rt->base_type;
int can;
- tcg_debug_assert(at->base_type == type);
- tcg_debug_assert(bt->base_type == type);
+ tcg_debug_assert(at->base_type >= type);
+ tcg_debug_assert(bt->base_type >= type);
can = tcg_can_emit_vec_op(INDEX_op_cmp_vec, type, vece);
if (can > 0) {
vec_gen_4(INDEX_op_cmp_vec, type, vece, ri, ai, bi, cond);
@@ -377,8 +377,8 @@ void tcg_gen_mul_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
TCGType type = rt->base_type;
int can;
- tcg_debug_assert(at->base_type == type);
- tcg_debug_assert(bt->base_type == type);
+ tcg_debug_assert(at->base_type >= type);
+ tcg_debug_assert(bt->base_type >= type);
can = tcg_can_emit_vec_op(INDEX_op_mul_vec, type, vece);
if (can > 0) {
vec_gen_3(INDEX_op_mul_vec, type, vece, ri, ai, bi);
diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h
index 75bb55aeac..5d2c91a1b6 100644
--- a/tcg/tcg-op.h
+++ b/tcg/tcg-op.h
@@ -1137,25 +1137,74 @@ void tcg_gen_stl_vec(TCGv_vec r, TCGv_ptr base, TCGArg offset, TCGType t);
#endif
#if UINTPTR_MAX == UINT32_MAX
-# define tcg_gen_ld_ptr(R, A, O) \
- tcg_gen_ld_i32(TCGV_PTR_TO_NAT(R), (A), (O))
-# define tcg_gen_discard_ptr(A) \
- tcg_gen_discard_i32(TCGV_PTR_TO_NAT(A))
-# define tcg_gen_add_ptr(R, A, B) \
- tcg_gen_add_i32(TCGV_PTR_TO_NAT(R), TCGV_PTR_TO_NAT(A), TCGV_PTR_TO_NAT(B))
-# define tcg_gen_addi_ptr(R, A, B) \
- tcg_gen_addi_i32(TCGV_PTR_TO_NAT(R), TCGV_PTR_TO_NAT(A), (B))
-# define tcg_gen_ext_i32_ptr(R, A) \
- tcg_gen_mov_i32(TCGV_PTR_TO_NAT(R), (A))
+# define PTR i32
+# define NAT TCGv_i32
#else
-# define tcg_gen_ld_ptr(R, A, O) \
- tcg_gen_ld_i64(TCGV_PTR_TO_NAT(R), (A), (O))
-# define tcg_gen_discard_ptr(A) \
- tcg_gen_discard_i64(TCGV_PTR_TO_NAT(A))
-# define tcg_gen_add_ptr(R, A, B) \
- tcg_gen_add_i64(TCGV_PTR_TO_NAT(R), TCGV_PTR_TO_NAT(A), TCGV_PTR_TO_NAT(B))
-# define tcg_gen_addi_ptr(R, A, B) \
- tcg_gen_addi_i64(TCGV_PTR_TO_NAT(R), TCGV_PTR_TO_NAT(A), (B))
-# define tcg_gen_ext_i32_ptr(R, A) \
- tcg_gen_ext_i32_i64(TCGV_PTR_TO_NAT(R), (A))
-#endif /* UINTPTR_MAX == UINT32_MAX */
+# define PTR i64
+# define NAT TCGv_i64
+#endif
+
+static inline void tcg_gen_ld_ptr(TCGv_ptr r, TCGv_ptr a, intptr_t o)
+{
+ glue(tcg_gen_ld_,PTR)((NAT)r, a, o);
+}
+
+static inline void tcg_gen_discard_ptr(TCGv_ptr a)
+{
+ glue(tcg_gen_discard_,PTR)((NAT)a);
+}
+
+static inline void tcg_gen_add_ptr(TCGv_ptr r, TCGv_ptr a, TCGv_ptr b)
+{
+ glue(tcg_gen_add_,PTR)((NAT)r, (NAT)a, (NAT)b);
+}
+
+static inline void tcg_gen_addi_ptr(TCGv_ptr r, TCGv_ptr a, intptr_t b)
+{
+ glue(tcg_gen_addi_,PTR)((NAT)r, (NAT)a, b);
+}
+
+static inline void tcg_gen_brcondi_ptr(TCGCond cond, TCGv_ptr a,
+ intptr_t b, TCGLabel *label)
+{
+ glue(tcg_gen_brcondi_,PTR)(cond, (NAT)a, b, label);
+}
+
+static inline void tcg_gen_ext_i32_ptr(TCGv_ptr r, TCGv_i32 a)
+{
+#if UINTPTR_MAX == UINT32_MAX
+ tcg_gen_mov_i32((NAT)r, a);
+#else
+ tcg_gen_ext_i32_i64((NAT)r, a);
+#endif
+}
+
+static inline void tcg_gen_trunc_i64_ptr(TCGv_ptr r, TCGv_i64 a)
+{
+#if UINTPTR_MAX == UINT32_MAX
+ tcg_gen_extrl_i64_i32((NAT)r, a);
+#else
+ tcg_gen_mov_i64((NAT)r, a);
+#endif
+}
+
+static inline void tcg_gen_extu_ptr_i64(TCGv_i64 r, TCGv_ptr a)
+{
+#if UINTPTR_MAX == UINT32_MAX
+ tcg_gen_extu_i32_i64(r, (NAT)a);
+#else
+ tcg_gen_mov_i64(r, (NAT)a);
+#endif
+}
+
+static inline void tcg_gen_trunc_ptr_i32(TCGv_i32 r, TCGv_ptr a)
+{
+#if UINTPTR_MAX == UINT32_MAX
+ tcg_gen_mov_i32(r, (NAT)a);
+#else
+ tcg_gen_extrl_i64_i32(r, (NAT)a);
+#endif
+}
+
+#undef PTR
+#undef NAT
diff --git a/tcg/tcg.c b/tcg/tcg.c
index bb24526c93..551caf1c53 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -980,7 +980,7 @@ TCGTemp *tcg_global_mem_new_internal(TCGType type, TCGv_ptr base,
return ts;
}
-static TCGTemp *tcg_temp_new_internal(TCGType type, int temp_local)
+TCGTemp *tcg_temp_new_internal(TCGType type, bool temp_local)
{
TCGContext *s = tcg_ctx;
TCGTemp *ts;
@@ -1025,18 +1025,6 @@ static TCGTemp *tcg_temp_new_internal(TCGType type, int temp_local)
return ts;
}
-TCGv_i32 tcg_temp_new_internal_i32(int temp_local)
-{
- TCGTemp *t = tcg_temp_new_internal(TCG_TYPE_I32, temp_local);
- return temp_tcgv_i32(t);
-}
-
-TCGv_i64 tcg_temp_new_internal_i64(int temp_local)
-{
- TCGTemp *t = tcg_temp_new_internal(TCG_TYPE_I64, temp_local);
- return temp_tcgv_i64(t);
-}
-
TCGv_vec tcg_temp_new_vec(TCGType type)
{
TCGTemp *t;
@@ -1072,7 +1060,7 @@ TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match)
return temp_tcgv_vec(t);
}
-static void tcg_temp_free_internal(TCGTemp *ts)
+void tcg_temp_free_internal(TCGTemp *ts)
{
TCGContext *s = tcg_ctx;
int k, idx;
@@ -1093,21 +1081,6 @@ static void tcg_temp_free_internal(TCGTemp *ts)
set_bit(idx, s->free_temps[k].l);
}
-void tcg_temp_free_i32(TCGv_i32 arg)
-{
- tcg_temp_free_internal(tcgv_i32_temp(arg));
-}
-
-void tcg_temp_free_i64(TCGv_i64 arg)
-{
- tcg_temp_free_internal(tcgv_i64_temp(arg));
-}
-
-void tcg_temp_free_vec(TCGv_vec arg)
-{
- tcg_temp_free_internal(tcgv_vec_temp(arg));
-}
-
TCGv_i32 tcg_const_i32(int32_t val)
{
TCGv_i32 t0;
@@ -3324,7 +3297,7 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
s->code_ptr = tb->tc.ptr;
#ifdef TCG_TARGET_NEED_LDST_LABELS
- s->ldst_labels = NULL;
+ QSIMPLEQ_INIT(&s->ldst_labels);
#endif
#ifdef TCG_TARGET_NEED_POOL_LABELS
s->pool_labels = NULL;
diff --git a/tcg/tcg.h b/tcg/tcg.h
index 30896ca304..75fbad128b 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -699,7 +699,7 @@ struct TCGContext {
/* These structures are private to tcg-target.inc.c. */
#ifdef TCG_TARGET_NEED_LDST_LABELS
- struct TCGLabelQemuLdst *ldst_labels;
+ QSIMPLEQ_HEAD(ldst_labels, TCGLabelQemuLdst) ldst_labels;
#endif
#ifdef TCG_TARGET_NEED_POOL_LABELS
struct TCGLabelPoolData *pool_labels;
@@ -890,15 +890,30 @@ void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size);
TCGTemp *tcg_global_mem_new_internal(TCGType, TCGv_ptr,
intptr_t, const char *);
-
-TCGv_i32 tcg_temp_new_internal_i32(int temp_local);
-TCGv_i64 tcg_temp_new_internal_i64(int temp_local);
+TCGTemp *tcg_temp_new_internal(TCGType, bool);
+void tcg_temp_free_internal(TCGTemp *);
TCGv_vec tcg_temp_new_vec(TCGType type);
TCGv_vec tcg_temp_new_vec_matching(TCGv_vec match);
-void tcg_temp_free_i32(TCGv_i32 arg);
-void tcg_temp_free_i64(TCGv_i64 arg);
-void tcg_temp_free_vec(TCGv_vec arg);
+static inline void tcg_temp_free_i32(TCGv_i32 arg)
+{
+ tcg_temp_free_internal(tcgv_i32_temp(arg));
+}
+
+static inline void tcg_temp_free_i64(TCGv_i64 arg)
+{
+ tcg_temp_free_internal(tcgv_i64_temp(arg));
+}
+
+static inline void tcg_temp_free_ptr(TCGv_ptr arg)
+{
+ tcg_temp_free_internal(tcgv_ptr_temp(arg));
+}
+
+static inline void tcg_temp_free_vec(TCGv_vec arg)
+{
+ tcg_temp_free_internal(tcgv_vec_temp(arg));
+}
static inline TCGv_i32 tcg_global_mem_new_i32(TCGv_ptr reg, intptr_t offset,
const char *name)
@@ -909,12 +924,14 @@ static inline TCGv_i32 tcg_global_mem_new_i32(TCGv_ptr reg, intptr_t offset,
static inline TCGv_i32 tcg_temp_new_i32(void)
{
- return tcg_temp_new_internal_i32(0);
+ TCGTemp *t = tcg_temp_new_internal(TCG_TYPE_I32, false);
+ return temp_tcgv_i32(t);
}
static inline TCGv_i32 tcg_temp_local_new_i32(void)
{
- return tcg_temp_new_internal_i32(1);
+ TCGTemp *t = tcg_temp_new_internal(TCG_TYPE_I32, true);
+ return temp_tcgv_i32(t);
}
static inline TCGv_i64 tcg_global_mem_new_i64(TCGv_ptr reg, intptr_t offset,
@@ -926,12 +943,33 @@ static inline TCGv_i64 tcg_global_mem_new_i64(TCGv_ptr reg, intptr_t offset,
static inline TCGv_i64 tcg_temp_new_i64(void)
{
- return tcg_temp_new_internal_i64(0);
+ TCGTemp *t = tcg_temp_new_internal(TCG_TYPE_I64, false);
+ return temp_tcgv_i64(t);
}
static inline TCGv_i64 tcg_temp_local_new_i64(void)
{
- return tcg_temp_new_internal_i64(1);
+ TCGTemp *t = tcg_temp_new_internal(TCG_TYPE_I64, true);
+ return temp_tcgv_i64(t);
+}
+
+static inline TCGv_ptr tcg_global_mem_new_ptr(TCGv_ptr reg, intptr_t offset,
+ const char *name)
+{
+ TCGTemp *t = tcg_global_mem_new_internal(TCG_TYPE_PTR, reg, offset, name);
+ return temp_tcgv_ptr(t);
+}
+
+static inline TCGv_ptr tcg_temp_new_ptr(void)
+{
+ TCGTemp *t = tcg_temp_new_internal(TCG_TYPE_PTR, false);
+ return temp_tcgv_ptr(t);
+}
+
+static inline TCGv_ptr tcg_temp_local_new_ptr(void)
+{
+ TCGTemp *t = tcg_temp_new_internal(TCG_TYPE_PTR, true);
+ return temp_tcgv_ptr(t);
}
#if defined(CONFIG_DEBUG_TCG)
@@ -1009,26 +1047,6 @@ do {\
abort();\
} while (0)
-#if UINTPTR_MAX == UINT32_MAX
-static inline TCGv_ptr TCGV_NAT_TO_PTR(TCGv_i32 n) { return (TCGv_ptr)n; }
-static inline TCGv_i32 TCGV_PTR_TO_NAT(TCGv_ptr n) { return (TCGv_i32)n; }
-
-#define tcg_const_ptr(V) TCGV_NAT_TO_PTR(tcg_const_i32((intptr_t)(V)))
-#define tcg_global_mem_new_ptr(R, O, N) \
- TCGV_NAT_TO_PTR(tcg_global_mem_new_i32((R), (O), (N)))
-#define tcg_temp_new_ptr() TCGV_NAT_TO_PTR(tcg_temp_new_i32())
-#define tcg_temp_free_ptr(T) tcg_temp_free_i32(TCGV_PTR_TO_NAT(T))
-#else
-static inline TCGv_ptr TCGV_NAT_TO_PTR(TCGv_i64 n) { return (TCGv_ptr)n; }
-static inline TCGv_i64 TCGV_PTR_TO_NAT(TCGv_ptr n) { return (TCGv_i64)n; }
-
-#define tcg_const_ptr(V) TCGV_NAT_TO_PTR(tcg_const_i64((intptr_t)(V)))
-#define tcg_global_mem_new_ptr(R, O, N) \
- TCGV_NAT_TO_PTR(tcg_global_mem_new_i64((R), (O), (N)))
-#define tcg_temp_new_ptr() TCGV_NAT_TO_PTR(tcg_temp_new_i64())
-#define tcg_temp_free_ptr(T) tcg_temp_free_i64(TCGV_PTR_TO_NAT(T))
-#endif
-
bool tcg_op_supported(TCGOpcode op);
void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args);
@@ -1052,6 +1070,14 @@ TCGv_vec tcg_const_ones_vec(TCGType);
TCGv_vec tcg_const_zeros_vec_matching(TCGv_vec);
TCGv_vec tcg_const_ones_vec_matching(TCGv_vec);
+#if UINTPTR_MAX == UINT32_MAX
+# define tcg_const_ptr(x) ((TCGv_ptr)tcg_const_i32((intptr_t)(x)))
+# define tcg_const_local_ptr(x) ((TCGv_ptr)tcg_const_local_i32((intptr_t)(x)))
+#else
+# define tcg_const_ptr(x) ((TCGv_ptr)tcg_const_i64((intptr_t)(x)))
+# define tcg_const_local_ptr(x) ((TCGv_ptr)tcg_const_local_i64((intptr_t)(x)))
+#endif
+
TCGLabel *gen_new_label(void);
/**