diff options
author | Anthony Liguori <aliguori@amazon.com> | 2013-12-19 17:03:17 -0800 |
---|---|---|
committer | Anthony Liguori <aliguori@amazon.com> | 2013-12-19 17:03:17 -0800 |
commit | f8251db121c3f051b22a7536b97d160c30bcccd4 (patch) | |
tree | 093964c9d5d8dbb5e597c95f347f176ab57c3428 | |
parent | 3dc7e2a3fedafc2f951bd62300b342c84e3606f8 (diff) | |
parent | 5fe269b16c6dc8f19da3e8c13d4c66958b00d2f0 (diff) |
Merge remote-tracking branch 'agraf/tags/signed-ppc-for-upstream' into staging
Patch queue for ppc - 2013-12-20
Alexander Graf (3):
PPC: Use default pci bus name for grackle and heathrow
roms: Flush icache when writing roms to guest memory
PPC: Add VSX to hflags
Alexey Kardashevskiy (5):
powerpc: add PVR mask support
target-ppc: move POWER7+ to a separate family
spapr-rtas: replace return code constants with macros
spapr-rtas: add ibm, (get|set)-system-parameter
spapr: make sure RMA is in first mode of first memory node
Greg Kurz (1):
target-ppc: add stubs for KVM breakpoints
Paolo Bonzini (1):
spapr: tie spapr-nvram to -pflash
Paul Mackerras (1):
spapr: limit numa memory regions by ram size
Peter Crosthwaite (2):
device_tree: s/qemu_devtree/qemu_fdt globally
device_tree: qemu_fdt_setprop: Rename val_array arg
Tom Musta (19):
Declare and Enable VSX
Add MSR VSX and Associated Exception
Add VSX Instruction Decoders
Add VSR to Global Registers
Add lxvd2x
Add stxvd2x
Add xxpermdi
Add lxsdx
Add lxvdsx
Add lxvw4x
Add stxsdx
Add stxvw4x
Add VSX Scalar Move Instructions
Add VSX Vector Move Instructions
Add Power7 VSX Logical Instructions
Add xxmrgh/xxmrgl
Add xxsel
Add xxspltw
Add xxsldwi
* agraf/tags/signed-ppc-for-upstream: (32 commits)
spapr: limit numa memory regions by ram size
spapr: make sure RMA is in first mode of first memory node
device_tree: qemu_fdt_setprop: Rename val_array arg
device_tree: s/qemu_devtree/qemu_fdt globally
PPC: Add VSX to hflags
Add xxsldwi
Add xxspltw
Add xxsel
Add xxmrgh/xxmrgl
Add Power7 VSX Logical Instructions
Add VSX Vector Move Instructions
Add VSX Scalar Move Instructions
roms: Flush icache when writing roms to guest memory
spapr: tie spapr-nvram to -pflash
PPC: Use default pci bus name for grackle and heathrow
spapr-rtas: add ibm, (get|set)-system-parameter
spapr-rtas: replace return code constants with macros
target-ppc: move POWER7+ to a separate family
Add stxvw4x
Add stxsdx
...
33 files changed, 1237 insertions, 387 deletions
diff --git a/device_tree.c b/device_tree.c index 391da8c45e..ca83504819 100644 --- a/device_tree.c +++ b/device_tree.c @@ -131,12 +131,12 @@ static int findnode_nofail(void *fdt, const char *node_path) return offset; } -int qemu_devtree_setprop(void *fdt, const char *node_path, - const char *property, const void *val_array, int size) +int qemu_fdt_setprop(void *fdt, const char *node_path, + const char *property, const void *val, int size) { int r; - r = fdt_setprop(fdt, findnode_nofail(fdt, node_path), property, val_array, size); + r = fdt_setprop(fdt, findnode_nofail(fdt, node_path), property, val, size); if (r < 0) { fprintf(stderr, "%s: Couldn't set %s/%s: %s\n", __func__, node_path, property, fdt_strerror(r)); @@ -146,8 +146,8 @@ int qemu_devtree_setprop(void *fdt, const char *node_path, return r; } -int qemu_devtree_setprop_cell(void *fdt, const char *node_path, - const char *property, uint32_t val) +int qemu_fdt_setprop_cell(void *fdt, const char *node_path, + const char *property, uint32_t val) { int r; @@ -161,15 +161,15 @@ int qemu_devtree_setprop_cell(void *fdt, const char *node_path, return r; } -int qemu_devtree_setprop_u64(void *fdt, const char *node_path, - const char *property, uint64_t val) +int qemu_fdt_setprop_u64(void *fdt, const char *node_path, + const char *property, uint64_t val) { val = cpu_to_be64(val); - return qemu_devtree_setprop(fdt, node_path, property, &val, sizeof(val)); + return qemu_fdt_setprop(fdt, node_path, property, &val, sizeof(val)); } -int qemu_devtree_setprop_string(void *fdt, const char *node_path, - const char *property, const char *string) +int qemu_fdt_setprop_string(void *fdt, const char *node_path, + const char *property, const char *string) { int r; @@ -183,8 +183,8 @@ int qemu_devtree_setprop_string(void *fdt, const char *node_path, return r; } -const void *qemu_devtree_getprop(void *fdt, const char *node_path, - const char *property, int *lenp) +const void *qemu_fdt_getprop(void *fdt, const char *node_path, + const char *property, int *lenp) { int len; const void *r; @@ -200,11 +200,11 @@ const void *qemu_devtree_getprop(void *fdt, const char *node_path, return r; } -uint32_t qemu_devtree_getprop_cell(void *fdt, const char *node_path, - const char *property) +uint32_t qemu_fdt_getprop_cell(void *fdt, const char *node_path, + const char *property) { int len; - const uint32_t *p = qemu_devtree_getprop(fdt, node_path, property, &len); + const uint32_t *p = qemu_fdt_getprop(fdt, node_path, property, &len); if (len != 4) { fprintf(stderr, "%s: %s/%s not 4 bytes long (not a cell?)\n", __func__, node_path, property); @@ -213,7 +213,7 @@ uint32_t qemu_devtree_getprop_cell(void *fdt, const char *node_path, return be32_to_cpu(*p); } -uint32_t qemu_devtree_get_phandle(void *fdt, const char *path) +uint32_t qemu_fdt_get_phandle(void *fdt, const char *path) { uint32_t r; @@ -227,15 +227,15 @@ uint32_t qemu_devtree_get_phandle(void *fdt, const char *path) return r; } -int qemu_devtree_setprop_phandle(void *fdt, const char *node_path, - const char *property, - const char *target_node_path) +int qemu_fdt_setprop_phandle(void *fdt, const char *node_path, + const char *property, + const char *target_node_path) { - uint32_t phandle = qemu_devtree_get_phandle(fdt, target_node_path); - return qemu_devtree_setprop_cell(fdt, node_path, property, phandle); + uint32_t phandle = qemu_fdt_get_phandle(fdt, target_node_path); + return qemu_fdt_setprop_cell(fdt, node_path, property, phandle); } -uint32_t qemu_devtree_alloc_phandle(void *fdt) +uint32_t qemu_fdt_alloc_phandle(void *fdt) { static int phandle = 0x0; @@ -259,7 +259,7 @@ uint32_t qemu_devtree_alloc_phandle(void *fdt) return phandle++; } -int qemu_devtree_nop_node(void *fdt, const char *node_path) +int qemu_fdt_nop_node(void *fdt, const char *node_path) { int r; @@ -273,7 +273,7 @@ int qemu_devtree_nop_node(void *fdt, const char *node_path) return r; } -int qemu_devtree_add_subnode(void *fdt, const char *name) +int qemu_fdt_add_subnode(void *fdt, const char *name) { char *dupname = g_strdup(name); char *basename = strrchr(dupname, '/'); @@ -303,7 +303,7 @@ int qemu_devtree_add_subnode(void *fdt, const char *name) return retval; } -void qemu_devtree_dumpdtb(void *fdt, int size) +void qemu_fdt_dumpdtb(void *fdt, int size) { const char *dumpdtb = qemu_opt_get(qemu_get_machine_opts(), "dumpdtb"); @@ -313,11 +313,11 @@ void qemu_devtree_dumpdtb(void *fdt, int size) } } -int qemu_devtree_setprop_sized_cells_from_array(void *fdt, - const char *node_path, - const char *property, - int numvalues, - uint64_t *values) +int qemu_fdt_setprop_sized_cells_from_array(void *fdt, + const char *node_path, + const char *property, + int numvalues, + uint64_t *values) { uint32_t *propcells; uint64_t value; @@ -342,6 +342,6 @@ int qemu_devtree_setprop_sized_cells_from_array(void *fdt, propcells[cellnum++] = cpu_to_be32(value); } - return qemu_devtree_setprop(fdt, node_path, property, propcells, - cellnum * sizeof(uint32_t)); + return qemu_fdt_setprop(fdt, node_path, property, propcells, + cellnum * sizeof(uint32_t)); } @@ -50,6 +50,7 @@ #include "translate-all.h" #include "exec/memory-internal.h" +#include "qemu/cache-utils.h" #include "qemu/range.h" @@ -2070,9 +2071,13 @@ void cpu_physical_memory_rw(hwaddr addr, uint8_t *buf, address_space_rw(&address_space_memory, addr, buf, len, is_write); } -/* used for ROM loading : can write in RAM and ROM */ -void cpu_physical_memory_write_rom(hwaddr addr, - const uint8_t *buf, int len) +enum write_rom_type { + WRITE_DATA, + FLUSH_CACHE, +}; + +static inline void cpu_physical_memory_write_rom_internal( + hwaddr addr, const uint8_t *buf, int len, enum write_rom_type type) { hwaddr l; uint8_t *ptr; @@ -2091,8 +2096,15 @@ void cpu_physical_memory_write_rom(hwaddr addr, addr1 += memory_region_get_ram_addr(mr); /* ROM/RAM case */ ptr = qemu_get_ram_ptr(addr1); - memcpy(ptr, buf, l); - invalidate_and_set_dirty(addr1, l); + switch (type) { + case WRITE_DATA: + memcpy(ptr, buf, l); + invalidate_and_set_dirty(addr1, l); + break; + case FLUSH_CACHE: + flush_icache_range((uintptr_t)ptr, (uintptr_t)ptr + l); + break; + } } len -= l; buf += l; @@ -2100,6 +2112,28 @@ void cpu_physical_memory_write_rom(hwaddr addr, } } +/* used for ROM loading : can write in RAM and ROM */ +void cpu_physical_memory_write_rom(hwaddr addr, + const uint8_t *buf, int len) +{ + cpu_physical_memory_write_rom_internal(addr, buf, len, WRITE_DATA); +} + +void cpu_flush_icache_range(hwaddr start, int len) +{ + /* + * This function should do the same thing as an icache flush that was + * triggered from within the guest. For TCG we are always cache coherent, + * so there is no need to flush anything. For KVM / Xen we need to flush + * the host's instruction cache at least. + */ + if (tcg_enabled()) { + return; + } + + cpu_physical_memory_write_rom_internal(start, NULL, len, FLUSH_CACHE); +} + typedef struct { MemoryRegion *mr; void *buffer; diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 90e95341d7..1c1b0e5258 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -335,8 +335,8 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo) } } - acells = qemu_devtree_getprop_cell(fdt, "/", "#address-cells"); - scells = qemu_devtree_getprop_cell(fdt, "/", "#size-cells"); + acells = qemu_fdt_getprop_cell(fdt, "/", "#address-cells"); + scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells"); if (acells == 0 || scells == 0) { fprintf(stderr, "dtb file invalid (#address-cells or #size-cells 0)\n"); goto fail; @@ -351,17 +351,17 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo) goto fail; } - rc = qemu_devtree_setprop_sized_cells(fdt, "/memory", "reg", - acells, binfo->loader_start, - scells, binfo->ram_size); + rc = qemu_fdt_setprop_sized_cells(fdt, "/memory", "reg", + acells, binfo->loader_start, + scells, binfo->ram_size); if (rc < 0) { fprintf(stderr, "couldn't set /memory/reg\n"); goto fail; } if (binfo->kernel_cmdline && *binfo->kernel_cmdline) { - rc = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", - binfo->kernel_cmdline); + rc = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", + binfo->kernel_cmdline); if (rc < 0) { fprintf(stderr, "couldn't set /chosen/bootargs\n"); goto fail; @@ -369,15 +369,15 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo) } if (binfo->initrd_size) { - rc = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start", - binfo->initrd_start); + rc = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start", + binfo->initrd_start); if (rc < 0) { fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); goto fail; } - rc = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end", - binfo->initrd_start + binfo->initrd_size); + rc = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", + binfo->initrd_start + binfo->initrd_size); if (rc < 0) { fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); goto fail; @@ -388,7 +388,7 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo) binfo->modify_dtb(binfo, fdt); } - qemu_devtree_dumpdtb(fdt, size); + qemu_fdt_dumpdtb(fdt, size); cpu_physical_memory_write(addr, fdt, size); diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index aaa863e481..ef1707aef0 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -419,13 +419,13 @@ static int add_virtio_mmio_node(void *fdt, uint32_t acells, uint32_t scells, int rc; char *nodename = g_strdup_printf("/virtio_mmio@%" PRIx64, addr); - rc = qemu_devtree_add_subnode(fdt, nodename); - rc |= qemu_devtree_setprop_string(fdt, nodename, - "compatible", "virtio,mmio"); - rc |= qemu_devtree_setprop_sized_cells(fdt, nodename, "reg", - acells, addr, scells, size); - qemu_devtree_setprop_cells(fdt, nodename, "interrupt-parent", intc); - qemu_devtree_setprop_cells(fdt, nodename, "interrupts", 0, irq, 1); + rc = qemu_fdt_add_subnode(fdt, nodename); + rc |= qemu_fdt_setprop_string(fdt, nodename, + "compatible", "virtio,mmio"); + rc |= qemu_fdt_setprop_sized_cells(fdt, nodename, "reg", + acells, addr, scells, size); + qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", intc); + qemu_fdt_setprop_cells(fdt, nodename, "interrupts", 0, irq, 1); g_free(nodename); if (rc) { return -1; @@ -456,8 +456,8 @@ static void vexpress_modify_dtb(const struct arm_boot_info *info, void *fdt) uint32_t acells, scells, intc; const VEDBoardInfo *daughterboard = (const VEDBoardInfo *)info; - acells = qemu_devtree_getprop_cell(fdt, "/", "#address-cells"); - scells = qemu_devtree_getprop_cell(fdt, "/", "#size-cells"); + acells = qemu_fdt_getprop_cell(fdt, "/", "#address-cells"); + scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells"); intc = find_int_controller(fdt); if (!intc) { /* Not fatal, we just won't provide virtio. This will diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 9531b5a574..517f2fe30f 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -156,42 +156,42 @@ static void create_fdt(VirtBoardInfo *vbi) vbi->fdt = fdt; /* Header */ - qemu_devtree_setprop_string(fdt, "/", "compatible", "linux,dummy-virt"); - qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 0x2); - qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 0x2); + qemu_fdt_setprop_string(fdt, "/", "compatible", "linux,dummy-virt"); + qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2); + qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2); /* * /chosen and /memory nodes must exist for load_dtb * to fill in necessary properties later */ - qemu_devtree_add_subnode(fdt, "/chosen"); - qemu_devtree_add_subnode(fdt, "/memory"); - qemu_devtree_setprop_string(fdt, "/memory", "device_type", "memory"); + qemu_fdt_add_subnode(fdt, "/chosen"); + qemu_fdt_add_subnode(fdt, "/memory"); + qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory"); /* Clock node, for the benefit of the UART. The kernel device tree * binding documentation claims the PL011 node clock properties are * optional but in practice if you omit them the kernel refuses to * probe for the device. */ - vbi->clock_phandle = qemu_devtree_alloc_phandle(fdt); - qemu_devtree_add_subnode(fdt, "/apb-pclk"); - qemu_devtree_setprop_string(fdt, "/apb-pclk", "compatible", "fixed-clock"); - qemu_devtree_setprop_cell(fdt, "/apb-pclk", "#clock-cells", 0x0); - qemu_devtree_setprop_cell(fdt, "/apb-pclk", "clock-frequency", 24000000); - qemu_devtree_setprop_string(fdt, "/apb-pclk", "clock-output-names", + vbi->clock_phandle = qemu_fdt_alloc_phandle(fdt); + qemu_fdt_add_subnode(fdt, "/apb-pclk"); + qemu_fdt_setprop_string(fdt, "/apb-pclk", "compatible", "fixed-clock"); + qemu_fdt_setprop_cell(fdt, "/apb-pclk", "#clock-cells", 0x0); + qemu_fdt_setprop_cell(fdt, "/apb-pclk", "clock-frequency", 24000000); + qemu_fdt_setprop_string(fdt, "/apb-pclk", "clock-output-names", "clk24mhz"); - qemu_devtree_setprop_cell(fdt, "/apb-pclk", "phandle", vbi->clock_phandle); + qemu_fdt_setprop_cell(fdt, "/apb-pclk", "phandle", vbi->clock_phandle); /* No PSCI for TCG yet */ if (kvm_enabled()) { - qemu_devtree_add_subnode(fdt, "/psci"); - qemu_devtree_setprop_string(fdt, "/psci", "compatible", "arm,psci"); - qemu_devtree_setprop_string(fdt, "/psci", "method", "hvc"); - qemu_devtree_setprop_cell(fdt, "/psci", "cpu_suspend", + qemu_fdt_add_subnode(fdt, "/psci"); + qemu_fdt_setprop_string(fdt, "/psci", "compatible", "arm,psci"); + qemu_fdt_setprop_string(fdt, "/psci", "method", "hvc"); + qemu_fdt_setprop_cell(fdt, "/psci", "cpu_suspend", PSCI_FN_CPU_SUSPEND); - qemu_devtree_setprop_cell(fdt, "/psci", "cpu_off", PSCI_FN_CPU_OFF); - qemu_devtree_setprop_cell(fdt, "/psci", "cpu_on", PSCI_FN_CPU_ON); - qemu_devtree_setprop_cell(fdt, "/psci", "migrate", PSCI_FN_MIGRATE); + qemu_fdt_setprop_cell(fdt, "/psci", "cpu_off", PSCI_FN_CPU_OFF); + qemu_fdt_setprop_cell(fdt, "/psci", "cpu_on", PSCI_FN_CPU_ON); + qemu_fdt_setprop_cell(fdt, "/psci", "migrate", PSCI_FN_MIGRATE); } } @@ -206,10 +206,10 @@ static void fdt_add_timer_nodes(const VirtBoardInfo *vbi) irqflags = deposit32(irqflags, GIC_FDT_IRQ_PPI_CPU_START, GIC_FDT_IRQ_PPI_CPU_WIDTH, (1 << vbi->smp_cpus) - 1); - qemu_devtree_add_subnode(vbi->fdt, "/timer"); - qemu_devtree_setprop_string(vbi->fdt, "/timer", + qemu_fdt_add_subnode(vbi->fdt, "/timer"); + qemu_fdt_setprop_string(vbi->fdt, "/timer", "compatible", "arm,armv7-timer"); - qemu_devtree_setprop_cells(vbi->fdt, "/timer", "interrupts", + qemu_fdt_setprop_cells(vbi->fdt, "/timer", "interrupts", GIC_FDT_IRQ_TYPE_PPI, 13, irqflags, GIC_FDT_IRQ_TYPE_PPI, 14, irqflags, GIC_FDT_IRQ_TYPE_PPI, 11, irqflags, @@ -220,25 +220,25 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi) { int cpu; - qemu_devtree_add_subnode(vbi->fdt, "/cpus"); - qemu_devtree_setprop_cell(vbi->fdt, "/cpus", "#address-cells", 0x1); - qemu_devtree_setprop_cell(vbi->fdt, "/cpus", "#size-cells", 0x0); + qemu_fdt_add_subnode(vbi->fdt, "/cpus"); + qemu_fdt_setprop_cell(vbi->fdt, "/cpus", "#address-cells", 0x1); + qemu_fdt_setprop_cell(vbi->fdt, "/cpus", "#size-cells", 0x0); for (cpu = vbi->smp_cpus - 1; cpu >= 0; cpu--) { char *nodename = g_strdup_printf("/cpus/cpu@%d", cpu); ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu)); - qemu_devtree_add_subnode(vbi->fdt, nodename); - qemu_devtree_setprop_string(vbi->fdt, nodename, "device_type", "cpu"); - qemu_devtree_setprop_string(vbi->fdt, nodename, "compatible", + qemu_fdt_add_subnode(vbi->fdt, nodename); + qemu_fdt_setprop_string(vbi->fdt, nodename, "device_type", "cpu"); + qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", armcpu->dtb_compatible); if (vbi->smp_cpus > 1) { - qemu_devtree_setprop_string(vbi->fdt, nodename, + qemu_fdt_setprop_string(vbi->fdt, nodename, "enable-method", "psci"); } - qemu_devtree_setprop_cell(vbi->fdt, nodename, "reg", cpu); + qemu_fdt_setprop_cell(vbi->fdt, nodename, "reg", cpu); g_free(nodename); } } @@ -247,20 +247,20 @@ static void fdt_add_gic_node(const VirtBoardInfo *vbi) { uint32_t gic_phandle; - gic_phandle = qemu_devtree_alloc_phandle(vbi->fdt); - qemu_devtree_setprop_cell(vbi->fdt, "/", "interrupt-parent", gic_phandle); + gic_phandle = qemu_fdt_alloc_phandle(vbi->fdt); + qemu_fdt_setprop_cell(vbi->fdt, "/", "interrupt-parent", gic_phandle); - qemu_devtree_add_subnode(vbi->fdt, "/intc"); - qemu_devtree_setprop_string(vbi->fdt, "/intc", "compatible", + qemu_fdt_add_subnode(vbi->fdt, "/intc"); + qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible", vbi->gic_compatible); - qemu_devtree_setprop_cell(vbi->fdt, "/intc", "#interrupt-cells", 3); - qemu_devtree_setprop(vbi->fdt, "/intc", "interrupt-controller", NULL, 0); - qemu_devtree_setprop_sized_cells(vbi->fdt, "/intc", "reg", + qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#interrupt-cells", 3); + qemu_fdt_setprop(vbi->fdt, "/intc", "interrupt-controller", NULL, 0); + qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg", 2, vbi->memmap[VIRT_GIC_DIST].base, 2, vbi->memmap[VIRT_GIC_DIST].size, 2, vbi->memmap[VIRT_GIC_CPU].base, 2, vbi->memmap[VIRT_GIC_CPU].size); - qemu_devtree_setprop_cell(vbi->fdt, "/intc", "phandle", gic_phandle); + qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", gic_phandle); } static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic) @@ -275,18 +275,18 @@ static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic) sysbus_create_simple("pl011", base, pic[irq]); nodename = g_strdup_printf("/pl011@%" PRIx64, base); - qemu_devtree_add_subnode(vbi->fdt, nodename); + qemu_fdt_add_subnode(vbi->fdt, nodename); /* Note that we can't use setprop_string because of the embedded NUL */ - qemu_devtree_setprop(vbi->fdt, nodename, "compatible", + qemu_fdt_setprop(vbi->fdt, nodename, "compatible", compat, sizeof(compat)); - qemu_devtree_setprop_sized_cells(vbi->fdt, nodename, "reg", + qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", 2, base, 2, size); - qemu_devtree_setprop_cells(vbi->fdt, nodename, "interrupts", + qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts", GIC_FDT_IRQ_TYPE_SPI, irq, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI); - qemu_devtree_setprop_cells(vbi->fdt, nodename, "clocks", + qemu_fdt_setprop_cells(vbi->fdt, nodename, "clocks", vbi->clock_phandle, vbi->clock_phandle); - qemu_devtree_setprop(vbi->fdt, nodename, "clock-names", + qemu_fdt_setprop(vbi->fdt, nodename, "clock-names", clocknames, sizeof(clocknames)); g_free(nodename); } @@ -314,14 +314,14 @@ static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic) hwaddr base = vbi->memmap[VIRT_MMIO].base + i * size; nodename = g_strdup_printf("/virtio_mmio@%" PRIx64, base); - qemu_devtree_add_subnode(vbi->fdt, nodename); - qemu_devtree_setprop_string(vbi->fdt, nodename, - "compatible", "virtio,mmio"); - qemu_devtree_setprop_sized_cells(vbi->fdt, nodename, "reg", - 2, base, 2, size); - qemu_devtree_setprop_cells(vbi->fdt, nodename, "interrupts", - GIC_FDT_IRQ_TYPE_SPI, irq, - GIC_FDT_IRQ_FLAGS_EDGE_LO_HI); + qemu_fdt_add_subnode(vbi->fdt, nodename); + qemu_fdt_setprop_string(vbi->fdt, nodename, + "compatible", "virtio,mmio"); + qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", + 2, base, 2, size); + qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts", + GIC_FDT_IRQ_TYPE_SPI, irq, + GIC_FDT_IRQ_FLAGS_EDGE_LO_HI); g_free(nodename); } } diff --git a/hw/core/loader.c b/hw/core/loader.c index 60d2ebd4ac..0634bee20c 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -785,6 +785,13 @@ static void rom_reset(void *unused) g_free(rom->data); rom->data = NULL; } + /* + * The rom loader is really on the same level as firmware in the guest + * shadowing a ROM into RAM. Such a shadowing mechanism needs to ensure + * that the instruction cache for that new region is clear, so that the + * CPU definitely fetches its instructions from the just written data. + */ + cpu_flush_icache_range(rom->addr, rom->datasize); } } diff --git a/hw/intc/xics.c b/hw/intc/xics.c index a333305d3d..b437563fb9 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -723,7 +723,7 @@ static void rtas_set_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t nr, server, priority; if ((nargs != 3) || (nret != 1)) { - rtas_st(rets, 0, -3); + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } @@ -733,13 +733,13 @@ static void rtas_set_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr, if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers) || (priority > 0xff)) { - rtas_st(rets, 0, -3); + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } ics_write_xive(ics, nr, server, priority, priority); - rtas_st(rets, 0, 0); /* Success */ + rtas_st(rets, 0, RTAS_OUT_SUCCESS); } static void rtas_get_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr, @@ -751,18 +751,18 @@ static void rtas_get_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t nr; if ((nargs != 1) || (nret != 3)) { - rtas_st(rets, 0, -3); + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } nr = rtas_ld(args, 0); if (!ics_valid_irq(ics, nr)) { - rtas_st(rets, 0, -3); + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } - rtas_st(rets, 0, 0); /* Success */ + rtas_st(rets, 0, RTAS_OUT_SUCCESS); rtas_st(rets, 1, ics->irqs[nr - ics->offset].server); rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority); } @@ -776,21 +776,21 @@ static void rtas_int_off(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t nr; if ((nargs != 1) || (nret != 1)) { - rtas_st(rets, 0, -3); + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } nr = rtas_ld(args, 0); if (!ics_valid_irq(ics, nr)) { - rtas_st(rets, 0, -3); + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff, ics->irqs[nr - ics->offset].priority); - rtas_st(rets, 0, 0); /* Success */ + rtas_st(rets, 0, RTAS_OUT_SUCCESS); } static void rtas_int_on(PowerPCCPU *cpu, sPAPREnvironment *spapr, @@ -802,14 +802,14 @@ static void rtas_int_on(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t nr; if ((nargs != 1) || (nret != 1)) { - rtas_st(rets, 0, -3); + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } nr = rtas_ld(args, 0); if (!ics_valid_irq(ics, nr)) { - rtas_st(rets, 0, -3); + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } @@ -817,7 +817,7 @@ static void rtas_int_on(PowerPCCPU *cpu, sPAPREnvironment *spapr, ics->irqs[nr - ics->offset].saved_priority, ics->irqs[nr - ics->offset].saved_priority); - rtas_st(rets, 0, 0); /* Success */ + rtas_st(rets, 0, RTAS_OUT_SUCCESS); } /* diff --git a/hw/microblaze/boot.c b/hw/microblaze/boot.c index 2a7ea5c0f9..48d9e7afa4 100644 --- a/hw/microblaze/boot.c +++ b/hw/microblaze/boot.c @@ -79,19 +79,19 @@ static int microblaze_load_dtb(hwaddr addr, } if (kernel_cmdline) { - r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", - kernel_cmdline); + r = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", + kernel_cmdline); if (r < 0) { fprintf(stderr, "couldn't set /chosen/bootargs\n"); } } if (initrd_start) { - qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start", - initrd_start); + qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start", + initrd_start); - qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end", - initrd_end); + qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", + initrd_end); } cpu_physical_memory_write(addr, fdt, fdt_size); diff --git a/hw/nvram/spapr_nvram.c b/hw/nvram/spapr_nvram.c index beaad682ac..635713e766 100644 --- a/hw/nvram/spapr_nvram.c +++ b/hw/nvram/spapr_nvram.c @@ -55,12 +55,12 @@ static void rtas_nvram_fetch(PowerPCCPU *cpu, sPAPREnvironment *spapr, void *membuf; if ((nargs != 3) || (nret != 2)) { - rtas_st(rets, 0, -3); + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } if (!nvram) { - rtas_st(rets, 0, -1); + rtas_st(rets, 0, RTAS_OUT_HW_ERROR); rtas_st(rets, 1, 0); return; } @@ -71,7 +71,7 @@ static void rtas_nvram_fetch(PowerPCCPU *cpu, sPAPREnvironment *spapr, if (((offset + len) < offset) || ((offset + len) > nvram->size)) { - rtas_st(rets, 0, -3); + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); rtas_st(rets, 1, 0); return; } @@ -87,7 +87,7 @@ static void rtas_nvram_fetch(PowerPCCPU *cpu, sPAPREnvironment *spapr, } cpu_physical_memory_unmap(membuf, len, 1, len); - rtas_st(rets, 0, (alen < len) ? -1 : 0); + rtas_st(rets, 0, (alen < len) ? RTAS_OUT_HW_ERROR : RTAS_OUT_SUCCESS); rtas_st(rets, 1, (alen < 0) ? 0 : alen); } @@ -102,12 +102,12 @@ static void rtas_nvram_store(PowerPCCPU *cpu, sPAPREnvironment *spapr, void *membuf; if ((nargs != 3) || (nret != 2)) { - rtas_st(rets, 0, -3); + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } if (!nvram) { - rtas_st(rets, 0, -1); + rtas_st(rets, 0, RTAS_OUT_HW_ERROR); return; } @@ -117,7 +117,7 @@ static void rtas_nvram_store(PowerPCCPU *cpu, sPAPREnvironment *spapr, if (((offset + len) < offset) || ((offset + len) > nvram->size)) { - rtas_st(rets, 0, -3); + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } @@ -132,7 +132,7 @@ static void rtas_nvram_store(PowerPCCPU *cpu, sPAPREnvironment *spapr, } cpu_physical_memory_unmap(membuf, len, 0, len); - rtas_st(rets, 0, (alen < len) ? -1 : 0); + rtas_st(rets, 0, (alen < len) ? RTAS_OUT_HW_ERROR : RTAS_OUT_SUCCESS); rtas_st(rets, 1, (alen < 0) ? 0 : alen); } diff --git a/hw/pci-host/grackle.c b/hw/pci-host/grackle.c index 4991ec44b0..75b60d36ac 100644 --- a/hw/pci-host/grackle.c +++ b/hw/pci-host/grackle.c @@ -82,7 +82,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic, memory_region_add_subregion(address_space_mem, 0x80000000ULL, &d->pci_hole); - phb->bus = pci_register_bus(dev, "pci", + phb->bus = pci_register_bus(dev, NULL, pci_grackle_set_irq, pci_grackle_map_irq, pic, diff --git a/hw/pci-host/uninorth.c b/hw/pci-host/uninorth.c index 91530cdd04..adc1d89010 100644 --- a/hw/pci-host/uninorth.c +++ b/hw/pci-host/uninorth.c @@ -234,7 +234,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic, memory_region_add_subregion(address_space_mem, 0x80000000ULL, &d->pci_hole); - h->bus = pci_register_bus(dev, "pci", + h->bus = pci_register_bus(dev, NULL, pci_unin_set_irq, pci_unin_map_irq, pic, &d->pci_mmio, @@ -300,7 +300,7 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic, memory_region_add_subregion(address_space_mem, 0x80000000ULL, &d->pci_hole); - h->bus = pci_register_bus(dev, "pci", + h->bus = pci_register_bus(dev, NULL, pci_unin_set_irq, pci_unin_map_irq, pic, &d->pci_mmio, diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index cfdd84b969..b37ce9d633 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -108,18 +108,18 @@ static void dt_serial_create(void *fdt, unsigned long long offset, char ser[128]; snprintf(ser, sizeof(ser), "%s/serial@%llx", soc, offset); - qemu_devtree_add_subnode(fdt, ser); - qemu_devtree_setprop_string(fdt, ser, "device_type", "serial"); - qemu_devtree_setprop_string(fdt, ser, "compatible", "ns16550"); - qemu_devtree_setprop_cells(fdt, ser, "reg", offset, 0x100); - qemu_devtree_setprop_cell(fdt, ser, "cell-index", idx); - qemu_devtree_setprop_cell(fdt, ser, "clock-frequency", 0); - qemu_devtree_setprop_cells(fdt, ser, "interrupts", 42, 2); - qemu_devtree_setprop_phandle(fdt, ser, "interrupt-parent", mpic); - qemu_devtree_setprop_string(fdt, "/aliases", alias, ser); + qemu_fdt_add_subnode(fdt, ser); + qemu_fdt_setprop_string(fdt, ser, "device_type", "serial"); + qemu_fdt_setprop_string(fdt, ser, "compatible", "ns16550"); + qemu_fdt_setprop_cells(fdt, ser, "reg", offset, 0x100); + qemu_fdt_setprop_cell(fdt, ser, "cell-index", idx); + qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", 0); + qemu_fdt_setprop_cells(fdt, ser, "interrupts", 42, 2); + qemu_fdt_setprop_phandle(fdt, ser, "interrupt-parent", mpic); + qemu_fdt_setprop_string(fdt, "/aliases", alias, ser); if (defcon) { - qemu_devtree_setprop_string(fdt, "/chosen", "linux,stdout-path", ser); + qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser); } } @@ -183,30 +183,30 @@ static int ppce500_load_device_tree(QEMUMachineInitArgs *args, } /* Manipulate device tree in memory. */ - qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 2); - qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 2); + qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 2); + qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 2); - qemu_devtree_add_subnode(fdt, "/memory"); - qemu_devtree_setprop_string(fdt, "/memory", "device_type", "memory"); - qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property, - sizeof(mem_reg_property)); + qemu_fdt_add_subnode(fdt, "/memory"); + qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory"); + qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property, + sizeof(mem_reg_property)); - qemu_devtree_add_subnode(fdt, "/chosen"); + qemu_fdt_add_subnode(fdt, "/chosen"); if (initrd_size) { - ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start", - initrd_base); + ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start", + initrd_base); if (ret < 0) { fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); } - ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end", - (initrd_base + initrd_size)); + ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", + (initrd_base + initrd_size)); if (ret < 0) { fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); } } - ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", + ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", args->kernel_cmdline); if (ret < 0) fprintf(stderr, "couldn't set /chosen/bootargs\n"); @@ -217,22 +217,22 @@ static int ppce500_load_device_tree(QEMUMachineInitArgs *args, tb_freq = kvmppc_get_tbfreq(); /* indicate KVM hypercall interface */ - qemu_devtree_add_subnode(fdt, "/hypervisor"); - qemu_devtree_setprop_string(fdt, "/hypervisor", "compatible", - "linux,kvm"); + qemu_fdt_add_subnode(fdt, "/hypervisor"); + qemu_fdt_setprop_string(fdt, "/hypervisor", "compatible", + "linux,kvm"); kvmppc_get_hypercall(env, hypercall, sizeof(hypercall)); - qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions", - hypercall, sizeof(hypercall)); + qemu_fdt_setprop(fdt, "/hypervisor", "hcall-instructions", + hypercall, sizeof(hypercall)); /* if KVM supports the idle hcall, set property indicating this */ if (kvmppc_get_hasidle(env)) { - qemu_devtree_setprop(fdt, "/hypervisor", "has-idle", NULL, 0); + qemu_fdt_setprop(fdt, "/hypervisor", "has-idle", NULL, 0); } } /* Create CPU nodes */ - qemu_devtree_add_subnode(fdt, "/cpus"); - qemu_devtree_setprop_cell(fdt, "/cpus", "#address-cells", 1); - qemu_devtree_setprop_cell(fdt, "/cpus", "#size-cells", 0); + qemu_fdt_add_subnode(fdt, "/cpus"); + qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 1); + qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0); /* We need to generate the cpu nodes in reverse order, so Linux can pick the first node as boot node and be happy */ @@ -249,55 +249,56 @@ static int ppce500_load_device_tree(QEMUMachineInitArgs *args, snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", cpu->cpu_index); - qemu_devtree_add_subnode(fdt, cpu_name); - qemu_devtree_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq); - qemu_devtree_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq); - qemu_devtree_setprop_string(fdt, cpu_name, "device_type", "cpu"); - qemu_devtree_setprop_cell(fdt, cpu_name, "reg", cpu->cpu_index); - qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-line-size", - env->dcache_line_size); - qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-line-size", - env->icache_line_size); - qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000); - qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000); - qemu_devtree_setprop_cell(fdt, cpu_name, "bus-frequency", 0); + qemu_fdt_add_subnode(fdt, cpu_name); + qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq); + qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq); + qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu"); + qemu_fdt_setprop_cell(fdt, cpu_name, "reg", cpu->cpu_index); + qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size", + env->dcache_line_size); + qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size", + env->icache_line_size); + qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000); + qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000); + qemu_fdt_setprop_cell(fdt, cpu_name, "bus-frequency", 0); if (cpu->cpu_index) { - qemu_devtree_setprop_string(fdt, cpu_name, "status", "disabled"); - qemu_devtree_setprop_string(fdt, cpu_name, "enable-method", "spin-table"); - qemu_devtree_setprop_u64(fdt, cpu_name, "cpu-release-addr", - cpu_release_addr); + qemu_fdt_setprop_string(fdt, cpu_name, "status", "disabled"); + qemu_fdt_setprop_string(fdt, cpu_name, "enable-method", + "spin-table"); + qemu_fdt_setprop_u64(fdt, cpu_name, "cpu-release-addr", + cpu_release_addr); } else { - qemu_devtree_setprop_string(fdt, cpu_name, "status", "okay"); + qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay"); } } - qemu_devtree_add_subnode(fdt, "/aliases"); + qemu_fdt_add_subnode(fdt, "/aliases"); /* XXX These should go into their respective devices' code */ snprintf(soc, sizeof(soc), "/soc@%llx", MPC8544_CCSRBAR_BASE); - qemu_devtree_add_subnode(fdt, soc); - qemu_devtree_setprop_string(fdt, soc, "device_type", "soc"); - qemu_devtree_setprop(fdt, soc, "compatible", compatible_sb, - sizeof(compatible_sb)); - qemu_devtree_setprop_cell(fdt, soc, "#address-cells", 1); - qemu_devtree_setprop_cell(fdt, soc, "#size-cells", 1); - qemu_devtree_setprop_cells(fdt, soc, "ranges", 0x0, - MPC8544_CCSRBAR_BASE >> 32, MPC8544_CCSRBAR_BASE, - MPC8544_CCSRBAR_SIZE); + qemu_fdt_add_subnode(fdt, soc); + qemu_fdt_setprop_string(fdt, soc, "device_type", "soc"); + qemu_fdt_setprop(fdt, soc, "compatible", compatible_sb, + sizeof(compatible_sb)); + qemu_fdt_setprop_cell(fdt, soc, "#address-cells", 1); + qemu_fdt_setprop_cell(fdt, soc, "#size-cells", 1); + qemu_fdt_setprop_cells(fdt, soc, "ranges", 0x0, + MPC8544_CCSRBAR_BASE >> 32, MPC8544_CCSRBAR_BASE, + MPC8544_CCSRBAR_SIZE); /* XXX should contain a reasonable value */ - qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0); + qemu_fdt_setprop_cell(fdt, soc, "bus-frequency", 0); snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET); - qemu_devtree_add_subnode(fdt, mpic); - qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic"); - qemu_devtree_setprop_string(fdt, mpic, "compatible", "fsl,mpic"); - qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET, - 0x40000); - qemu_devtree_setprop_cell(fdt, mpic, "#address-cells", 0); - qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 2); - mpic_ph = qemu_devtree_alloc_phandle(fdt); - qemu_devtree_setprop_cell(fdt, mpic, "phandle", mpic_ph); - qemu_devtree_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph); - qemu_devtree_setprop(fdt, mpic, "interrupt-controller", NULL, 0); + qemu_fdt_add_subnode(fdt, mpic); + qemu_fdt_setprop_string(fdt, mpic, "device_type", "open-pic"); + qemu_fdt_setprop_string(fdt, mpic, "compatible", "fsl,mpic"); + qemu_fdt_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET, + 0x40000); + qemu_fdt_setprop_cell(fdt, mpic, "#address-cells", 0); + qemu_fdt_setprop_cell(fdt, mpic, "#interrupt-cells", 2); + mpic_ph = qemu_fdt_alloc_phandle(fdt); + qemu_fdt_setprop_cell(fdt, mpic, "phandle", mpic_ph); + qemu_fdt_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph); + qemu_fdt_setprop(fdt, mpic, "interrupt-controller", NULL, 0); /* * We have to generate ser1 first, because Linux takes the first @@ -311,19 +312,19 @@ static int ppce500_load_device_tree(QEMUMachineInitArgs *args, snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc, MPC8544_UTIL_OFFSET); - qemu_devtree_add_subnode(fdt, gutil); - qemu_devtree_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts"); - qemu_devtree_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000); - qemu_devtree_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0); + qemu_fdt_add_subnode(fdt, gutil); + qemu_fdt_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts"); + qemu_fdt_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000); + qemu_fdt_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0); snprintf(msi, sizeof(msi), "/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET); - qemu_devtree_add_subnode(fdt, msi); - qemu_devtree_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi"); - qemu_devtree_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200); - msi_ph = qemu_devtree_alloc_phandle(fdt); - qemu_devtree_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100); - qemu_devtree_setprop_phandle(fdt, msi, "interrupt-parent", mpic); - qemu_devtree_setprop_cells(fdt, msi, "interrupts", + qemu_fdt_add_subnode(fdt, msi); + qemu_fdt_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi"); + qemu_fdt_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200); + msi_ph = qemu_fdt_alloc_phandle(fdt); + qemu_fdt_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100); + qemu_fdt_setprop_phandle(fdt, msi, "interrupt-parent", mpic); + qemu_fdt_setprop_cells(fdt, msi, "interrupts", 0xe0, 0x0, 0xe1, 0x0, 0xe2, 0x0, @@ -332,46 +333,46 @@ static int ppce500_load_device_tree(QEMUMachineInitArgs *args, 0xe5, 0x0, 0xe6, 0x0, 0xe7, 0x0); - qemu_devtree_setprop_cell(fdt, msi, "phandle", msi_ph); - qemu_devtree_setprop_cell(fdt, msi, "linux,phandle", msi_ph); + qemu_fdt_setprop_cell(fdt, msi, "phandle", msi_ph); + qemu_fdt_setprop_cell(fdt, msi, "linux,phandle", msi_ph); snprintf(pci, sizeof(pci), "/pci@%llx", MPC8544_PCI_REGS_BASE); - qemu_devtree_add_subnode(fdt, pci); - qemu_devtree_setprop_cell(fdt, pci, "cell-index", 0); - qemu_devtree_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci"); - qemu_devtree_setprop_string(fdt, pci, "device_type", "pci"); - qemu_devtree_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0, - 0x0, 0x7); - pci_map = pci_map_create(fdt, qemu_devtree_get_phandle(fdt, mpic), + qemu_fdt_add_subnode(fdt, pci); + qemu_fdt_setprop_cell(fdt, pci, "cell-index", 0); + qemu_fdt_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci"); + qemu_fdt_setprop_string(fdt, pci, "device_type", "pci"); + qemu_fdt_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0, + 0x0, 0x7); + pci_map = pci_map_create(fdt, qemu_fdt_get_phandle(fdt, mpic), params->pci_first_slot, params->pci_nr_slots, &len); - qemu_devtree_setprop(fdt, pci, "interrupt-map", pci_map, len); - qemu_devtree_setprop_phandle(fdt, pci, "interrupt-parent", mpic); - qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2); - qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255); + qemu_fdt_setprop(fdt, pci, "interrupt-map", pci_map, len); + qemu_fdt_setprop_phandle(fdt, pci, "interrupt-parent", mpic); + qemu_fdt_setprop_cells(fdt, pci, "interrupts", 24, 2); + qemu_fdt_setprop_cells(fdt, pci, "bus-range", 0, 255); for (i = 0; i < 14; i++) { pci_ranges[i] = cpu_to_be32(pci_ranges[i]); } - qemu_devtree_setprop_cell(fdt, pci, "fsl,msi", msi_ph); - qemu_devtree_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges)); - qemu_devtree_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32, - MPC8544_PCI_REGS_BASE, 0, 0x1000); - qemu_devtree_setprop_cell(fdt, pci, "clock-frequency", 66666666); - qemu_devtree_setprop_cell(fdt, pci, "#interrupt-cells", 1); - qemu_devtree_setprop_cell(fdt, pci, "#size-cells", 2); - qemu_devtree_setprop_cell(fdt, pci, "#address-cells", 3); - qemu_devtree_setprop_string(fdt, "/aliases", "pci0", pci); + qemu_fdt_setprop_cell(fdt, pci, "fsl,msi", msi_ph); + qemu_fdt_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges)); + qemu_fdt_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32, + MPC8544_PCI_REGS_BASE, 0, 0x1000); + qemu_fdt_setprop_cell(fdt, pci, "clock-frequency", 66666666); + qemu_fdt_setprop_cell(fdt, pci, "#interrupt-cells", 1); + qemu_fdt_setprop_cell(fdt, pci, "#size-cells", 2); + qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3); + qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci); params->fixup_devtree(params, fdt); if (toplevel_compat) { - qemu_devtree_setprop(fdt, "/", "compatible", toplevel_compat, - strlen(toplevel_compat) + 1); + qemu_fdt_setprop(fdt, "/", "compatible", toplevel_compat, + strlen(toplevel_compat) + 1); } done: if (!dry_run) { - qemu_devtree_dumpdtb(fdt, fdt_size); + qemu_fdt_dumpdtb(fdt, fdt_size); cpu_physical_memory_write(addr, fdt, fdt_size); } ret = fdt_size; diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c index 2e964b2474..7d5357e83b 100644 --- a/hw/ppc/e500plat.c +++ b/hw/ppc/e500plat.c @@ -23,9 +23,9 @@ static void e500plat_fixup_devtree(PPCE500Params *params, void *fdt) const char model[] = "QEMU ppce500"; const char compatible[] = "fsl,qemu-e500"; - qemu_devtree_setprop(fdt, "/", "model", model, sizeof(model)); - qemu_devtree_setprop(fdt, "/", "compatible", compatible, - sizeof(compatible)); + qemu_fdt_setprop(fdt, "/", "model", model, sizeof(model)); + qemu_fdt_setprop(fdt, "/", "compatible", compatible, + sizeof(compatible)); } static void e500plat_init(QEMUMachineInitArgs *args) diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c index edcc0be5f7..292c70953b 100644 --- a/hw/ppc/mpc8544ds.c +++ b/hw/ppc/mpc8544ds.c @@ -21,9 +21,9 @@ static void mpc8544ds_fixup_devtree(PPCE500Params *params, void *fdt) const char model[] = "MPC8544DS"; const char compatible[] = "MPC8544DS\0MPC85xxDS"; - qemu_devtree_setprop(fdt, "/", "model", model, sizeof(model)); - qemu_devtree_setprop(fdt, "/", "compatible", compatible, - sizeof(compatible)); + qemu_fdt_setprop(fdt, "/", "model", model, sizeof(model)); + qemu_fdt_setprop(fdt, "/", "compatible", compatible, + sizeof(compatible)); } static void mpc8544ds_init(QEMUMachineInitArgs *args) diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c index 67597dfb88..ec15bab0b5 100644 --- a/hw/ppc/ppc440_bamboo.c +++ b/hw/ppc/ppc440_bamboo.c @@ -77,23 +77,23 @@ static int bamboo_load_device_tree(hwaddr addr, /* Manipulate device tree in memory. */ - ret = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property, - sizeof(mem_reg_property)); + ret = qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property, + sizeof(mem_reg_property)); if (ret < 0) fprintf(stderr, "couldn't set /memory/reg\n"); - ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start", - initrd_base); + ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start", + initrd_base); if (ret < 0) fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); - ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end", - (initrd_base + initrd_size)); + ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", + (initrd_base + initrd_size)); if (ret < 0) fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); - ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", - kernel_cmdline); + ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", + kernel_cmdline); if (ret < 0) fprintf(stderr, "couldn't set /chosen/bootargs\n"); @@ -105,10 +105,10 @@ static int bamboo_load_device_tree(hwaddr addr, clock_freq = kvmppc_get_clockfreq(); } - qemu_devtree_setprop_cell(fdt, "/cpus/cpu@0", "clock-frequency", - clock_freq); - qemu_devtree_setprop_cell(fdt, "/cpus/cpu@0", "timebase-frequency", - tb_freq); + qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "clock-frequency", + clock_freq); + qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "timebase-frequency", + tb_freq); rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); g_free(fdt); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 7e53a5f977..93d02c1e50 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -526,14 +526,15 @@ static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt) cpu_to_be32(0x0), cpu_to_be32(0x0), cpu_to_be32(0x0)}; char mem_name[32]; - hwaddr node0_size, mem_start; + hwaddr node0_size, mem_start, node_size; uint64_t mem_reg_property[2]; int i, off; /* memory node(s) */ - node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size; - if (spapr->rma_size > node0_size) { - spapr->rma_size = node0_size; + if (nb_numa_nodes > 1 && node_mem[0] < ram_size) { + node0_size = node_mem[0]; + } else { + node0_size = ram_size; } /* RMA */ @@ -566,7 +567,15 @@ static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt) mem_start = node0_size; for (i = 1; i < nb_numa_nodes; i++) { mem_reg_property[0] = cpu_to_be64(mem_start); - mem_reg_property[1] = cpu_to_be64(node_mem[i]); + if (mem_start >= ram_size) { + node_size = 0; + } else { + node_size = node_mem[i]; + if (node_size > ram_size - mem_start) { + node_size = ram_size - mem_start; + } + } + mem_reg_property[1] = cpu_to_be64(node_size); associativity[3] = associativity[4] = cpu_to_be32(i); sprintf(mem_name, "memory@" TARGET_FMT_lx, mem_start); off = fdt_add_subnode(fdt, 0, mem_name); @@ -576,7 +585,7 @@ static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt) sizeof(mem_reg_property)))); _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity, sizeof(associativity)))); - mem_start += node_mem[i]; + mem_start += node_size; } return 0; @@ -688,7 +697,8 @@ static void spapr_reset_htab(sPAPREnvironment *spapr) /* Update the RMA size if necessary */ if (spapr->vrma_adjust) { - spapr->rma_size = kvmppc_rma_size(ram_size, spapr->htab_shift); + hwaddr node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size; + spapr->rma_size = kvmppc_rma_size(node0_size, spapr->htab_shift); } } @@ -739,18 +749,10 @@ static void spapr_cpu_reset(void *opaque) static void spapr_create_nvram(sPAPREnvironment *spapr) { DeviceState *dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram"); - const char *drivename = qemu_opt_get(qemu_get_machine_opts(), "nvram"); - - if (drivename) { - BlockDriverState *bs; + DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0); - bs = bdrv_find(drivename); - if (!bs) { - fprintf(stderr, "No such block device \"%s\" for nvram\n", - drivename); - exit(1); - } - qdev_prop_set_drive_nofail(dev, "drive", bs); + if (dinfo) { + qdev_prop_set_drive_nofail(dev, "drive", dinfo->bdrv); } qdev_init_nofail(dev); @@ -1113,6 +1115,7 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); hwaddr rma_alloc_size; + hwaddr node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size; uint32_t initrd_base = 0; long kernel_size = 0, initrd_size = 0; long load_limit, rtas_limit, fw_size; @@ -1134,10 +1137,10 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) exit(1); } - if (rma_alloc_size && (rma_alloc_size < ram_size)) { + if (rma_alloc_size && (rma_alloc_size < node0_size)) { spapr->rma_size = rma_alloc_size; } else { - spapr->rma_size = ram_size; + 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 @@ -1154,6 +1157,12 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) } } + if (spapr->rma_size > node0_size) { + fprintf(stderr, "Error: Numa node 0 has to span the RMA (%#08"HWADDR_PRIx")\n", + spapr->rma_size); + exit(1); + } + /* We place the device tree and RTAS just below either the top of the RMA, * or just below 2GB, whichever is lowere, so that it can be * processed with 32-bit real mode code if necessary */ diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c index a69390e54e..16fa49e886 100644 --- a/hw/ppc/spapr_events.c +++ b/hw/ppc/spapr_events.c @@ -286,7 +286,7 @@ static void check_exception(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint64_t xinfo; if ((nargs < 6) || (nargs > 7) || nret != 1) { - rtas_st(rets, 0, -3); + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } @@ -306,9 +306,9 @@ static void check_exception(PowerPCCPU *cpu, sPAPREnvironment *spapr, cpu_physical_memory_write(buf, pending_epow, len); g_free(pending_epow); pending_epow = NULL; - rtas_st(rets, 0, 0); + rtas_st(rets, 0, RTAS_OUT_SUCCESS); } else { - rtas_st(rets, 0, 1); + rtas_st(rets, 0, RTAS_OUT_NO_ERRORS_FOUND); } } diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 2beedd45e9..ec00300884 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -90,7 +90,7 @@ static void finish_read_pci_config(sPAPREnvironment *spapr, uint64_t buid, if ((size != 1) && (size != 2) && (size != 4)) { /* access must be 1, 2 or 4 bytes */ - rtas_st(rets, 0, -1); + rtas_st(rets, 0, RTAS_OUT_HW_ERROR); return; } @@ -100,14 +100,14 @@ static void finish_read_pci_config(sPAPREnvironment *spapr, uint64_t buid, if (!pci_dev || (addr % size) || (addr >= pci_config_size(pci_dev))) { /* Access must be to a valid device, within bounds and * naturally aligned */ - rtas_st(rets, 0, -1); + rtas_st(rets, 0, RTAS_OUT_HW_ERROR); return; } val = pci_host_config_read_common(pci_dev, addr, pci_config_size(pci_dev), size); - rtas_st(rets, 0, 0); + rtas_st(rets, 0, RTAS_OUT_SUCCESS); rtas_st(rets, 1, val); } @@ -120,7 +120,7 @@ static void rtas_ibm_read_pci_config(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t size, addr; if ((nargs != 4) || (nret != 2)) { - rtas_st(rets, 0, -1); + rtas_st(rets, 0, RTAS_OUT_HW_ERROR); return; } @@ -139,7 +139,7 @@ static void rtas_read_pci_config(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t size, addr; if ((nargs != 2) || (nret != 2)) { - rtas_st(rets, 0, -1); + rtas_st(rets, 0, RTAS_OUT_HW_ERROR); return; } @@ -157,7 +157,7 @@ static void finish_write_pci_config(sPAPREnvironment *spapr, uint64_t buid, if ((size != 1) && (size != 2) && (size != 4)) { /* access must be 1, 2 or 4 bytes */ - rtas_st(rets, 0, -1); + rtas_st(rets, 0, RTAS_OUT_HW_ERROR); return; } @@ -167,14 +167,14 @@ static void finish_write_pci_config(sPAPREnvironment *spapr, uint64_t buid, if (!pci_dev || (addr % size) || (addr >= pci_config_size(pci_dev))) { /* Access must be to a valid device, within bounds and * naturally aligned */ - rtas_st(rets, 0, -1); + rtas_st(rets, 0, RTAS_OUT_HW_ERROR); return; } pci_host_config_write_common(pci_dev, addr, pci_config_size(pci_dev), val, size); - rtas_st(rets, 0, 0); + rtas_st(rets, 0, RTAS_OUT_SUCCESS); } static void rtas_ibm_write_pci_config(PowerPCCPU *cpu, sPAPREnvironment *spapr, @@ -186,7 +186,7 @@ static void rtas_ibm_write_pci_config(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t val, size, addr; if ((nargs != 5) || (nret != 1)) { - rtas_st(rets, 0, -1); + rtas_st(rets, 0, RTAS_OUT_HW_ERROR); return; } @@ -206,7 +206,7 @@ static void rtas_write_pci_config(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t val, size, addr; if ((nargs != 3) || (nret != 1)) { - rtas_st(rets, 0, -1); + rtas_st(rets, 0, RTAS_OUT_HW_ERROR); return; } @@ -293,7 +293,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr, break; default: fprintf(stderr, "rtas_ibm_change_msi(%u) is not implemented\n", func); - rtas_st(rets, 0, -3); /* Parameter error */ + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } @@ -303,7 +303,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr, pdev = find_dev(spapr, buid, config_addr); } if (!phb || !pdev) { - rtas_st(rets, 0, -3); /* Parameter error */ + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } @@ -312,11 +312,11 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr, ndev = spapr_msicfg_find(phb, config_addr, false); if (ndev < 0) { trace_spapr_pci_msi("MSI has not been enabled", -1, config_addr); - rtas_st(rets, 0, -1); /* Hardware error */ + rtas_st(rets, 0, RTAS_OUT_HW_ERROR); return; } trace_spapr_pci_msi("Released MSIs", ndev, config_addr); - rtas_st(rets, 0, 0); + rtas_st(rets, 0, RTAS_OUT_SUCCESS); rtas_st(rets, 1, 0); return; } @@ -327,7 +327,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr, ndev = spapr_msicfg_find(phb, config_addr, true); if (ndev >= SPAPR_MSIX_MAX_DEVS || ndev < 0) { fprintf(stderr, "No free entry for a new MSI device\n"); - rtas_st(rets, 0, -1); /* Hardware error */ + rtas_st(rets, 0, RTAS_OUT_HW_ERROR); return; } trace_spapr_pci_msi("Configuring MSI", ndev, config_addr); @@ -336,7 +336,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr, if (phb->msi_table[ndev].nvec && (req_num != phb->msi_table[ndev].nvec)) { /* Unexpected behaviour */ fprintf(stderr, "Cannot reuse MSI config for device#%d", ndev); - rtas_st(rets, 0, -1); /* Hardware error */ + rtas_st(rets, 0, RTAS_OUT_HW_ERROR); return; } @@ -346,7 +346,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr, ret_intr_type == RTAS_TYPE_MSI); if (irq < 0) { fprintf(stderr, "Cannot allocate MSIs for device#%d", ndev); - rtas_st(rets, 0, -1); /* Hardware error */ + rtas_st(rets, 0, RTAS_OUT_HW_ERROR); return; } phb->msi_table[ndev].irq = irq; @@ -358,7 +358,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr, spapr_msi_setmsg(pdev, spapr->msi_win_addr, ret_intr_type == RTAS_TYPE_MSIX, phb->msi_table[ndev].irq, req_num); - rtas_st(rets, 0, 0); + rtas_st(rets, 0, RTAS_OUT_SUCCESS); rtas_st(rets, 1, req_num); rtas_st(rets, 2, ++seq_num); rtas_st(rets, 3, ret_intr_type); @@ -383,7 +383,7 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu, /* Fins sPAPRPHBState */ phb = find_phb(spapr, buid); if (!phb) { - rtas_st(rets, 0, -3); /* Parameter error */ + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } @@ -391,7 +391,7 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu, ndev = spapr_msicfg_find(phb, config_addr, false); if (ndev < 0) { trace_spapr_pci_msi("MSI has not been enabled", -1, config_addr); - rtas_st(rets, 0, -1); /* Hardware error */ + rtas_st(rets, 0, RTAS_OUT_HW_ERROR); return; } @@ -399,7 +399,7 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu, trace_spapr_pci_rtas_ibm_query_interrupt_source_number(ioa_intr_num, intr_src_num); - rtas_st(rets, 0, 0); + rtas_st(rets, 0, RTAS_OUT_SUCCESS); rtas_st(rets, 1, intr_src_num); rtas_st(rets, 2, 1);/* 0 == level; 1 == edge */ } diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index eb542f218a..1cb276de05 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -47,10 +47,10 @@ static void rtas_display_character(PowerPCCPU *cpu, sPAPREnvironment *spapr, VIOsPAPRDevice *sdev = vty_lookup(spapr, 0); if (!sdev) { - rtas_st(rets, 0, -1); + rtas_st(rets, 0, RTAS_OUT_HW_ERROR); } else { vty_putchars(sdev, &c, sizeof(c)); - rtas_st(rets, 0, 0); + rtas_st(rets, 0, RTAS_OUT_SUCCESS); } } @@ -62,13 +62,13 @@ static void rtas_get_time_of_day(PowerPCCPU *cpu, sPAPREnvironment *spapr, struct tm tm; if (nret != 8) { - rtas_st(rets, 0, -3); + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } qemu_get_timedate(&tm, spapr->rtc_offset); - rtas_st(rets, 0, 0); /* Success */ + rtas_st(rets, 0, RTAS_OUT_SUCCESS); rtas_st(rets, 1, tm.tm_year + 1900); rtas_st(rets, 2, tm.tm_mon + 1); rtas_st(rets, 3, tm.tm_mday); @@ -96,7 +96,7 @@ static void rtas_set_time_of_day(PowerPCCPU *cpu, sPAPREnvironment *spapr, rtc_change_mon_event(&tm); spapr->rtc_offset = qemu_timedate_diff(&tm); - rtas_st(rets, 0, 0); /* Success */ + rtas_st(rets, 0, RTAS_OUT_SUCCESS); } static void rtas_power_off(PowerPCCPU *cpu, sPAPREnvironment *spapr, @@ -104,11 +104,11 @@ static void rtas_power_off(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t nret, target_ulong rets) { if (nargs != 2 || nret != 1) { - rtas_st(rets, 0, -3); + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } qemu_system_shutdown_request(); - rtas_st(rets, 0, 0); + rtas_st(rets, 0, RTAS_OUT_SUCCESS); } static void rtas_system_reboot(PowerPCCPU *cpu, sPAPREnvironment *spapr, @@ -117,11 +117,11 @@ static void rtas_system_reboot(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t nret, target_ulong rets) { if (nargs != 0 || nret != 1) { - rtas_st(rets, 0, -3); + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } qemu_system_reset_request(); - rtas_st(rets, 0, 0); + rtas_st(rets, 0, RTAS_OUT_SUCCESS); } static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_, @@ -134,7 +134,7 @@ static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_, CPUState *cpu; if (nargs != 1 || nret != 2) { - rtas_st(rets, 0, -3); + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } @@ -147,12 +147,12 @@ static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_, rtas_st(rets, 1, 2); } - rtas_st(rets, 0, 0); + rtas_st(rets, 0, RTAS_OUT_SUCCESS); return; } /* Didn't find a matching cpu */ - rtas_st(rets, 0, -3); + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); } static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPREnvironment *spapr, @@ -164,7 +164,7 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPREnvironment *spapr, CPUState *cs; if (nargs != 3 || nret != 1) { - rtas_st(rets, 0, -3); + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } @@ -178,7 +178,7 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPREnvironment *spapr, CPUPPCState *env = &cpu->env; if (!cs->halted) { - rtas_st(rets, 0, -1); + rtas_st(rets, 0, RTAS_OUT_HW_ERROR); return; } @@ -194,12 +194,12 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPREnvironment *spapr, qemu_cpu_kick(cs); - rtas_st(rets, 0, 0); + rtas_st(rets, 0, RTAS_OUT_SUCCESS); return; } /* Didn't find a matching cpu */ - rtas_st(rets, 0, -3); + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); } static void rtas_stop_self(PowerPCCPU *cpu, sPAPREnvironment *spapr, @@ -224,6 +224,49 @@ static void rtas_stop_self(PowerPCCPU *cpu, sPAPREnvironment *spapr, env->msr = 0; } +#define DIAGNOSTICS_RUN_MODE 42 + +static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu, + sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + target_ulong parameter = rtas_ld(args, 0); + target_ulong buffer = rtas_ld(args, 1); + target_ulong length = rtas_ld(args, 2); + target_ulong ret = RTAS_OUT_NOT_SUPPORTED; + + switch (parameter) { + case DIAGNOSTICS_RUN_MODE: + if (length == 1) { + rtas_st(buffer, 0, 0); + ret = RTAS_OUT_SUCCESS; + } + break; + } + + rtas_st(rets, 0, ret); +} + +static void rtas_ibm_set_system_parameter(PowerPCCPU *cpu, + sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + target_ulong parameter = rtas_ld(args, 0); + target_ulong ret = RTAS_OUT_NOT_SUPPORTED; + + switch (parameter) { + case DIAGNOSTICS_RUN_MODE: + ret = RTAS_OUT_NOT_AUTHORIZED; + break; + } + + rtas_st(rets, 0, ret); +} + static struct rtas_call { const char *name; spapr_rtas_fn fn; @@ -255,7 +298,7 @@ target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPREnvironment *spapr, } hcall_dprintf("Unknown RTAS token 0x%x\n", token); - rtas_st(rets, 0, -3); + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return H_PARAMETER; } @@ -291,24 +334,24 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr, return ret; } - ret = qemu_devtree_setprop_cell(fdt, "/rtas", "linux,rtas-base", - rtas_addr); + ret = qemu_fdt_setprop_cell(fdt, "/rtas", "linux,rtas-base", + rtas_addr); if (ret < 0) { fprintf(stderr, "Couldn't add linux,rtas-base property: %s\n", fdt_strerror(ret)); return ret; } - ret = qemu_devtree_setprop_cell(fdt, "/rtas", "linux,rtas-entry", - rtas_addr); + ret = qemu_fdt_setprop_cell(fdt, "/rtas", "linux,rtas-entry", + rtas_addr); if (ret < 0) { fprintf(stderr, "Couldn't add linux,rtas-entry property: %s\n", fdt_strerror(ret)); return ret; } - ret = qemu_devtree_setprop_cell(fdt, "/rtas", "rtas-size", - rtas_size); + ret = qemu_fdt_setprop_cell(fdt, "/rtas", "rtas-size", + rtas_size); if (ret < 0) { fprintf(stderr, "Couldn't add rtas-size property: %s\n", fdt_strerror(ret)); @@ -322,8 +365,8 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr, continue; } - ret = qemu_devtree_setprop_cell(fdt, "/rtas", call->name, - i + TOKEN_BASE); + ret = qemu_fdt_setprop_cell(fdt, "/rtas", call->name, + i + TOKEN_BASE); if (ret < 0) { fprintf(stderr, "Couldn't add rtas token for %s: %s\n", call->name, fdt_strerror(ret)); @@ -345,6 +388,10 @@ static void core_rtas_register_types(void) rtas_query_cpu_stopped_state); spapr_rtas_register("start-cpu", rtas_start_cpu); spapr_rtas_register("stop-self", rtas_stop_self); + spapr_rtas_register("ibm,get-system-parameter", + rtas_ibm_get_system_parameter); + spapr_rtas_register("ibm,set-system-parameter", + rtas_ibm_set_system_parameter); } type_init(core_rtas_register_types) diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index a6a0a5113c..fee6195f95 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -331,25 +331,25 @@ static void rtas_set_tce_bypass(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t unit, enable; if (nargs != 2) { - rtas_st(rets, 0, -3); + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } unit = rtas_ld(args, 0); enable = rtas_ld(args, 1); dev = spapr_vio_find_by_reg(bus, unit); if (!dev) { - rtas_st(rets, 0, -3); + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } if (!dev->tcet) { - rtas_st(rets, 0, -3); + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } spapr_tce_set_bypass(dev->tcet, !!enable); - rtas_st(rets, 0, 0); + rtas_st(rets, 0, RTAS_OUT_SUCCESS); } static void rtas_quiesce(PowerPCCPU *cpu, sPAPREnvironment *spapr, @@ -362,7 +362,7 @@ static void rtas_quiesce(PowerPCCPU *cpu, sPAPREnvironment *spapr, VIOsPAPRDevice *dev = NULL; if (nargs != 0) { - rtas_st(rets, 0, -3); + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } @@ -371,7 +371,7 @@ static void rtas_quiesce(PowerPCCPU *cpu, sPAPREnvironment *spapr, spapr_vio_quiesce_one(dev); } - rtas_st(rets, 0, 0); + rtas_st(rets, 0, RTAS_OUT_SUCCESS); } static VIOsPAPRDevice *reg_conflict(VIOsPAPRDevice *dev) diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c index fcfa678344..bdb057e36c 100644 --- a/hw/ppc/virtex_ml507.c +++ b/hw/ppc/virtex_ml507.c @@ -166,7 +166,7 @@ static int xilinx_load_device_tree(hwaddr addr, if (!fdt) { return 0; } - r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline); + r = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline); if (r < 0) fprintf(stderr, "couldn't set /chosen/bootargs\n"); cpu_physical_memory_write(addr, fdt, fdt_size); diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index e4996e19c3..8f33122c9f 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -110,6 +110,7 @@ void stq_phys(hwaddr addr, uint64_t val); void cpu_physical_memory_write_rom(hwaddr addr, const uint8_t *buf, int len); +void cpu_flush_icache_range(hwaddr start, int len); extern struct MemoryRegion io_mem_rom; extern struct MemoryRegion io_mem_notdirty; diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index fdaab2de52..b2f11e9a2c 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -332,6 +332,15 @@ static inline int spapr_allocate_lsi(int hint) return spapr_allocate_irq(hint, true); } +/* RTAS return codes */ +#define RTAS_OUT_SUCCESS 0 +#define RTAS_OUT_NO_ERRORS_FOUND 1 +#define RTAS_OUT_HW_ERROR -1 +#define RTAS_OUT_BUSY -2 +#define RTAS_OUT_PARAM_ERROR -3 +#define RTAS_OUT_NOT_SUPPORTED -3 +#define RTAS_OUT_NOT_AUTHORIZED -9002 + static inline uint64_t ppc64_phys_to_real(uint64_t addr) { return addr & ~0xF000000000000000ULL; diff --git a/include/sysemu/device_tree.h b/include/sysemu/device_tree.h index 2b58baf8b1..899f05c138 100644 --- a/include/sysemu/device_tree.h +++ b/include/sysemu/device_tree.h @@ -17,27 +17,27 @@ void *create_device_tree(int *sizep); void *load_device_tree(const char *filename_path, int *sizep); -int qemu_devtree_setprop(void *fdt, const char *node_path, - const char *property, const void *val_array, int size); -int qemu_devtree_setprop_cell(void *fdt, const char *node_path, - const char *property, uint32_t val); -int qemu_devtree_setprop_u64(void *fdt, const char *node_path, - const char *property, uint64_t val); -int qemu_devtree_setprop_string(void *fdt, const char *node_path, - const char *property, const char *string); -int qemu_devtree_setprop_phandle(void *fdt, const char *node_path, - const char *property, - const char *target_node_path); -const void *qemu_devtree_getprop(void *fdt, const char *node_path, - const char *property, int *lenp); -uint32_t qemu_devtree_getprop_cell(void *fdt, const char *node_path, - const char *property); -uint32_t qemu_devtree_get_phandle(void *fdt, const char *path); -uint32_t qemu_devtree_alloc_phandle(void *fdt); -int qemu_devtree_nop_node(void *fdt, const char *node_path); -int qemu_devtree_add_subnode(void *fdt, const char *name); +int qemu_fdt_setprop(void *fdt, const char *node_path, + const char *property, const void *val, int size); +int qemu_fdt_setprop_cell(void *fdt, const char *node_path, + const char *property, uint32_t val); +int qemu_fdt_setprop_u64(void *fdt, const char *node_path, + const char *property, uint64_t val); +int qemu_fdt_setprop_string(void *fdt, const char *node_path, + const char *property, const char *string); +int qemu_fdt_setprop_phandle(void *fdt, const char *node_path, + const char *property, + const char *target_node_path); +const void *qemu_fdt_getprop(void *fdt, const char *node_path, + const char *property, int *lenp); +uint32_t qemu_fdt_getprop_cell(void *fdt, const char *node_path, + const char *property); +uint32_t qemu_fdt_get_phandle(void *fdt, const char *path); +uint32_t qemu_fdt_alloc_phandle(void *fdt); +int qemu_fdt_nop_node(void *fdt, const char *node_path); +int qemu_fdt_add_subnode(void *fdt, const char *name); -#define qemu_devtree_setprop_cells(fdt, node_path, property, ...) \ +#define qemu_fdt_setprop_cells(fdt, node_path, property, ...) \ do { \ uint32_t qdt_tmp[] = { __VA_ARGS__ }; \ int i; \ @@ -45,14 +45,14 @@ int qemu_devtree_add_subnode(void *fdt, const char *name); for (i = 0; i < ARRAY_SIZE(qdt_tmp); i++) { \ qdt_tmp[i] = cpu_to_be32(qdt_tmp[i]); \ } \ - qemu_devtree_setprop(fdt, node_path, property, qdt_tmp, \ - sizeof(qdt_tmp)); \ + qemu_fdt_setprop(fdt, node_path, property, qdt_tmp, \ + sizeof(qdt_tmp)); \ } while (0) -void qemu_devtree_dumpdtb(void *fdt, int size); +void qemu_fdt_dumpdtb(void *fdt, int size); /** - * qemu_devtree_setprop_sized_cells_from_array: + * qemu_fdt_setprop_sized_cells_from_array: * @fdt: device tree blob * @node_path: node to set property on * @property: property to set @@ -72,20 +72,20 @@ void qemu_devtree_dumpdtb(void *fdt, int size); * the number of cells used for each element vary depending on the * #address-cells and #size-cells properties of their parent node. * If you know all your cell elements are one cell wide you can use the - * simpler qemu_devtree_setprop_cells(). If you're not setting up the - * array programmatically, qemu_devtree_setprop_sized_cells may be more + * simpler qemu_fdt_setprop_cells(). If you're not setting up the + * array programmatically, qemu_fdt_setprop_sized_cells may be more * convenient. * * Return value: 0 on success, <0 on error. */ -int qemu_devtree_setprop_sized_cells_from_array(void *fdt, - const char *node_path, - const char *property, - int numvalues, - uint64_t *values); +int qemu_fdt_setprop_sized_cells_from_array(void *fdt, + const char *node_path, + const char *property, + int numvalues, + uint64_t *values); /** - * qemu_devtree_setprop_sized_cells: + * qemu_fdt_setprop_sized_cells: * @fdt: device tree blob * @node_path: node to set property on * @property: property to set @@ -97,17 +97,17 @@ int qemu_devtree_setprop_sized_cells_from_array(void *fdt, * used by this value" and "value". * * This is a convenience wrapper for the function - * qemu_devtree_setprop_sized_cells_from_array(). + * qemu_fdt_setprop_sized_cells_from_array(). * * Return value: 0 on success, <0 on error. */ -#define qemu_devtree_setprop_sized_cells(fdt, node_path, property, ...) \ - ({ \ - uint64_t qdt_tmp[] = { __VA_ARGS__ }; \ - qemu_devtree_setprop_sized_cells_from_array(fdt, node_path, \ - property, \ - ARRAY_SIZE(qdt_tmp) / 2, \ - qdt_tmp); \ +#define qemu_fdt_setprop_sized_cells(fdt, node_path, property, ...) \ + ({ \ + uint64_t qdt_tmp[] = { __VA_ARGS__ }; \ + qemu_fdt_setprop_sized_cells_from_array(fdt, node_path, \ + property, \ + ARRAY_SIZE(qdt_tmp) / 2, \ + qdt_tmp); \ }) #endif /* __DEVICE_TREE_H__ */ diff --git a/target-ppc/cpu-models.c b/target-ppc/cpu-models.c index 8dea560383..7c9466fc07 100644 --- a/target-ppc/cpu-models.c +++ b/target-ppc/cpu-models.c @@ -44,6 +44,7 @@ PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); \ \ pcc->pvr = _pvr; \ + pcc->pvr_mask = CPU_POWERPC_DEFAULT_MASK; \ pcc->svr = _svr; \ dc->desc = _desc; \ } \ @@ -1139,7 +1140,7 @@ "POWER7 v2.1") POWERPC_DEF("POWER7_v2.3", CPU_POWERPC_POWER7_v23, POWER7, "POWER7 v2.3") - POWERPC_DEF("POWER7+_v2.1", CPU_POWERPC_POWER7P_v21, POWER7, + POWERPC_DEF("POWER7+_v2.1", CPU_POWERPC_POWER7P_v21, POWER7P, "POWER7+ v2.1") POWERPC_DEF("POWER8_v1.0", CPU_POWERPC_POWER8_v10, POWER8, "POWER8 v1.0") diff --git a/target-ppc/cpu-models.h b/target-ppc/cpu-models.h index d9145d147f..49ba4a4522 100644 --- a/target-ppc/cpu-models.h +++ b/target-ppc/cpu-models.h @@ -39,6 +39,7 @@ extern PowerPCCPUAlias ppc_cpu_aliases[]; /*****************************************************************************/ /* PVR definitions for most known PowerPC */ enum { + CPU_POWERPC_DEFAULT_MASK = 0xFFFFFFFF, /* PowerPC 401 family */ /* Generic PowerPC 401 */ #define CPU_POWERPC_401 CPU_POWERPC_401G2 @@ -552,10 +553,16 @@ enum { CPU_POWERPC_POWER6 = 0x003E0000, CPU_POWERPC_POWER6_5 = 0x0F000001, /* POWER6 in POWER5 mode */ CPU_POWERPC_POWER6A = 0x0F000002, + CPU_POWERPC_POWER7_BASE = 0x003F0000, + CPU_POWERPC_POWER7_MASK = 0xFFFF0000, CPU_POWERPC_POWER7_v20 = 0x003F0200, CPU_POWERPC_POWER7_v21 = 0x003F0201, CPU_POWERPC_POWER7_v23 = 0x003F0203, + CPU_POWERPC_POWER7P_BASE = 0x004A0000, + CPU_POWERPC_POWER7P_MASK = 0xFFFF0000, CPU_POWERPC_POWER7P_v21 = 0x004A0201, + CPU_POWERPC_POWER8_BASE = 0x004B0000, + CPU_POWERPC_POWER8_MASK = 0xFFFF0000, CPU_POWERPC_POWER8_v10 = 0x004B0100, CPU_POWERPC_970 = 0x00390202, CPU_POWERPC_970FX_v10 = 0x00391100, diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h index 827e5dd0e1..72b22329b0 100644 --- a/target-ppc/cpu-qom.h +++ b/target-ppc/cpu-qom.h @@ -54,6 +54,7 @@ typedef struct PowerPCCPUClass { void (*parent_reset)(CPUState *cpu); uint32_t pvr; + uint32_t pvr_mask; uint32_t svr; uint64_t insns_flags; uint64_t insns_flags2; @@ -99,6 +100,7 @@ static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env) #define ENV_OFFSET offsetof(PowerPCCPU, env) PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr); +PowerPCCPUClass *ppc_cpu_class_by_pvr_mask(uint32_t pvr); void ppc_cpu_do_interrupt(CPUState *cpu); void ppc_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 26acdba847..bb847676a5 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -236,6 +236,8 @@ enum { POWERPC_EXCP_NMEXTBR = 91, /* Non maskable external breakpoint */ POWERPC_EXCP_ITLBE = 92, /* Instruction TLB error */ POWERPC_EXCP_DTLBE = 93, /* Data TLB error */ + /* VSX Unavailable (Power ISA 2.06 and later) */ + POWERPC_EXCP_VSXU = 94, /* VSX Unavailable */ /* EOL */ POWERPC_EXCP_NB = 96, /* QEMU exceptions: used internally during code translation */ @@ -427,6 +429,7 @@ struct ppc_slb_t { #define MSR_VR 25 /* altivec available x hflags */ #define MSR_SPE 25 /* SPE enable for BookE x hflags */ #define MSR_AP 23 /* Access privilege state on 602 hflags */ +#define MSR_VSX 23 /* Vector Scalar Extension (ISA 2.06 and later) x hflags */ #define MSR_SA 22 /* Supervisor access mode on 602 hflags */ #define MSR_KEY 19 /* key bit on 603e */ #define MSR_POW 18 /* Power management */ @@ -467,6 +470,7 @@ struct ppc_slb_t { #define msr_vr ((env->msr >> MSR_VR) & 1) #define msr_spe ((env->msr >> MSR_SPE) & 1) #define msr_ap ((env->msr >> MSR_AP) & 1) +#define msr_vsx ((env->msr >> MSR_VSX) & 1) #define msr_sa ((env->msr >> MSR_SA) & 1) #define msr_key ((env->msr >> MSR_KEY) & 1) #define msr_pow ((env->msr >> MSR_POW) & 1) @@ -549,6 +553,8 @@ enum { POWERPC_FLAG_BUS_CLK = 0x00020000, /* Has CFAR */ POWERPC_FLAG_CFAR = 0x00040000, + /* Has VSX */ + POWERPC_FLAG_VSX = 0x00080000, }; /*****************************************************************************/ @@ -1870,7 +1876,8 @@ enum { /* Book I 2.05 PowerPC specification */ PPC2_ISA205 = 0x0000000000000020ULL, -#define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_PRCNTL | PPC2_DBRX | PPC2_ISA205) +#define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_VSX | PPC2_PRCNTL | PPC2_DBRX | \ + PPC2_ISA205) }; /*****************************************************************************/ diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c index c959460f70..26c57d9a34 100644 --- a/target-ppc/excp_helper.c +++ b/target-ppc/excp_helper.c @@ -390,6 +390,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) new_msr |= (target_ulong)MSR_HVB; } goto store_current; + case POWERPC_EXCP_VSXU: /* VSX unavailable exception */ + if (lpes1 == 0) { + new_msr |= (target_ulong)MSR_HVB; + } + goto store_current; case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ LOG_EXCP("PIT exception\n"); goto store_next; diff --git a/target-ppc/helper_regs.h b/target-ppc/helper_regs.h index a6d5e2fe2f..c02e8da4e4 100644 --- a/target-ppc/helper_regs.h +++ b/target-ppc/helper_regs.h @@ -56,7 +56,7 @@ static inline void hreg_compute_hflags(CPUPPCState *env) /* We 'forget' FE0 & FE1: we'll never generate imprecise exceptions */ hflags_mask = (1 << MSR_VR) | (1 << MSR_AP) | (1 << MSR_SA) | (1 << MSR_PR) | (1 << MSR_FP) | (1 << MSR_SE) | (1 << MSR_BE) | - (1 << MSR_LE); + (1 << MSR_LE) | (1 << MSR_VSX); hflags_mask |= (1ULL << MSR_CM) | (1ULL << MSR_SF) | MSR_HVB; hreg_compute_mem_idx(env); env->hflags = env->msr & hflags_mask; diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index b77ce5e94c..781b72f1ea 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -1745,6 +1745,7 @@ static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data) uint32_t icache_size = kvmppc_read_int_cpu_dt("i-cache-size"); /* Now fix up the class with information we can query from the host */ + pcc->pvr = mfpvr(); if (vmx != -1) { /* Only override when we know what the host supports */ @@ -1795,6 +1796,9 @@ static int kvm_ppc_register_host_cpu_type(void) pvr_pcc = ppc_cpu_class_by_pvr(host_pvr); if (pvr_pcc == NULL) { + pvr_pcc = ppc_cpu_class_by_pvr_mask(host_pvr); + } + if (pvr_pcc == NULL) { return -1; } type_info.parent = object_class_get_name(OBJECT_CLASS(pvr_pcc)); @@ -1902,3 +1906,31 @@ int kvm_arch_on_sigbus(int code, void *addr) void kvm_arch_init_irq_routing(KVMState *s) { } + +int kvm_arch_insert_sw_breakpoint(CPUState *cpu, struct kvm_sw_breakpoint *bp) +{ + return -EINVAL; +} + +int kvm_arch_remove_sw_breakpoint(CPUState *cpu, struct kvm_sw_breakpoint *bp) +{ + return -EINVAL; +} + +int kvm_arch_insert_hw_breakpoint(target_ulong addr, target_ulong len, int type) +{ + return -EINVAL; +} + +int kvm_arch_remove_hw_breakpoint(target_ulong addr, target_ulong len, int type) +{ + return -EINVAL; +} + +void kvm_arch_remove_all_hw_breakpoints(void) +{ +} + +void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg) +{ +} diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 66c777174c..ea58dc90d5 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -51,6 +51,7 @@ static char cpu_reg_names[10*3 + 22*4 /* GPR */ #endif + 10*4 + 22*5 /* FPR */ + 2*(10*6 + 22*7) /* AVRh, AVRl */ + + 10*5 + 22*6 /* VSR */ + 8*5 /* CRF */]; static TCGv cpu_gpr[32]; #if !defined(TARGET_PPC64) @@ -58,6 +59,7 @@ static TCGv cpu_gprh[32]; #endif static TCGv_i64 cpu_fpr[32]; static TCGv_i64 cpu_avrh[32], cpu_avrl[32]; +static TCGv_i64 cpu_vsr[32]; static TCGv_i32 cpu_crf[8]; static TCGv cpu_nip; static TCGv cpu_msr; @@ -137,6 +139,11 @@ void ppc_translate_init(void) #endif p += (i < 10) ? 6 : 7; cpu_reg_names_size -= (i < 10) ? 6 : 7; + snprintf(p, cpu_reg_names_size, "vsr%d", i); + cpu_vsr[i] = tcg_global_mem_new_i64(TCG_AREG0, + offsetof(CPUPPCState, vsr[i]), p); + p += (i < 10) ? 5 : 6; + cpu_reg_names_size -= (i < 10) ? 5 : 6; } cpu_nip = tcg_global_mem_new(TCG_AREG0, @@ -195,6 +202,7 @@ typedef struct DisasContext { #endif int fpu_enabled; int altivec_enabled; + int vsx_enabled; int spe_enabled; ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */ int singlestep_enabled; @@ -365,6 +373,12 @@ static inline int32_t name(uint32_t opcode) \ return (int16_t)((opcode >> (shift)) & ((1 << (nb)) - 1)); \ } +#define EXTRACT_HELPER_SPLIT(name, shift1, nb1, shift2, nb2) \ +static inline uint32_t name(uint32_t opcode) \ +{ \ + return (((opcode >> (shift1)) & ((1 << (nb1)) - 1)) << nb2) | \ + ((opcode >> (shift2)) & ((1 << (nb2)) - 1)); \ +} /* Opcode part 1 */ EXTRACT_HELPER(opc1, 26, 6); /* Opcode part 2 */ @@ -479,6 +493,14 @@ static inline target_ulong MASK(uint32_t start, uint32_t end) return ret; } +EXTRACT_HELPER_SPLIT(xT, 0, 1, 21, 5); +EXTRACT_HELPER_SPLIT(xS, 0, 1, 21, 5); +EXTRACT_HELPER_SPLIT(xA, 2, 1, 16, 5); +EXTRACT_HELPER_SPLIT(xB, 1, 1, 11, 5); +EXTRACT_HELPER_SPLIT(xC, 3, 1, 6, 5); +EXTRACT_HELPER(DM, 8, 2); +EXTRACT_HELPER(UIM, 16, 2); +EXTRACT_HELPER(SHW, 8, 2); /*****************************************************************************/ /* PowerPC instructions table */ @@ -6964,10 +6986,473 @@ GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20) GEN_VAFORM_PAIRED(vsel, vperm, 21) GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23) +/*** VSX extension ***/ + +static inline TCGv_i64 cpu_vsrh(int n) +{ + if (n < 32) { + return cpu_fpr[n]; + } else { + return cpu_avrh[n-32]; + } +} + +static inline TCGv_i64 cpu_vsrl(int n) +{ + if (n < 32) { + return cpu_vsr[n]; + } else { + return cpu_avrl[n-32]; + } +} + +static void gen_lxsdx(DisasContext *ctx) +{ + TCGv EA; + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + gen_set_access_type(ctx, ACCESS_INT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + gen_qemu_ld64(ctx, cpu_vsrh(xT(ctx->opcode)), EA); + /* NOTE: cpu_vsrl is undefined */ + tcg_temp_free(EA); +} + +static void gen_lxvd2x(DisasContext *ctx) +{ + TCGv EA; + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + gen_set_access_type(ctx, ACCESS_INT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + gen_qemu_ld64(ctx, cpu_vsrh(xT(ctx->opcode)), EA); + tcg_gen_addi_tl(EA, EA, 8); + gen_qemu_ld64(ctx, cpu_vsrl(xT(ctx->opcode)), EA); + tcg_temp_free(EA); +} + +static void gen_lxvdsx(DisasContext *ctx) +{ + TCGv EA; + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + gen_set_access_type(ctx, ACCESS_INT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + gen_qemu_ld64(ctx, cpu_vsrh(xT(ctx->opcode)), EA); + tcg_gen_mov_tl(cpu_vsrl(xT(ctx->opcode)), cpu_vsrh(xT(ctx->opcode))); + tcg_temp_free(EA); +} + +static void gen_lxvw4x(DisasContext *ctx) +{ + TCGv EA, tmp; + TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode)); + TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode)); + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + gen_set_access_type(ctx, ACCESS_INT); + EA = tcg_temp_new(); + tmp = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + gen_qemu_ld32u(ctx, tmp, EA); + tcg_gen_addi_tl(EA, EA, 4); + gen_qemu_ld32u(ctx, xth, EA); + tcg_gen_deposit_i64(xth, xth, tmp, 32, 32); + + tcg_gen_addi_tl(EA, EA, 4); + gen_qemu_ld32u(ctx, tmp, EA); + tcg_gen_addi_tl(EA, EA, 4); + gen_qemu_ld32u(ctx, xtl, EA); + tcg_gen_deposit_i64(xtl, xtl, tmp, 32, 32); + + tcg_temp_free(EA); + tcg_temp_free(tmp); +} + +static void gen_stxsdx(DisasContext *ctx) +{ + TCGv EA; + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + gen_set_access_type(ctx, ACCESS_INT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + gen_qemu_st64(ctx, cpu_vsrh(xS(ctx->opcode)), EA); + tcg_temp_free(EA); +} + +static void gen_stxvd2x(DisasContext *ctx) +{ + TCGv EA; + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + gen_set_access_type(ctx, ACCESS_INT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + gen_qemu_st64(ctx, cpu_vsrh(xS(ctx->opcode)), EA); + tcg_gen_addi_tl(EA, EA, 8); + gen_qemu_st64(ctx, cpu_vsrl(xS(ctx->opcode)), EA); + tcg_temp_free(EA); +} + +static void gen_stxvw4x(DisasContext *ctx) +{ + TCGv EA, tmp; + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + gen_set_access_type(ctx, ACCESS_INT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + tmp = tcg_temp_new(); + + tcg_gen_shri_i64(tmp, cpu_vsrh(xS(ctx->opcode)), 32); + gen_qemu_st32(ctx, tmp, EA); + tcg_gen_addi_tl(EA, EA, 4); + gen_qemu_st32(ctx, cpu_vsrh(xS(ctx->opcode)), EA); + + tcg_gen_shri_i64(tmp, cpu_vsrl(xS(ctx->opcode)), 32); + tcg_gen_addi_tl(EA, EA, 4); + gen_qemu_st32(ctx, tmp, EA); + tcg_gen_addi_tl(EA, EA, 4); + gen_qemu_st32(ctx, cpu_vsrl(xS(ctx->opcode)), EA); + + tcg_temp_free(EA); + tcg_temp_free(tmp); +} + +static void gen_xxpermdi(DisasContext *ctx) +{ + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + + if ((DM(ctx->opcode) & 2) == 0) { + tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_vsrh(xA(ctx->opcode))); + } else { + tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_vsrl(xA(ctx->opcode))); + } + if ((DM(ctx->opcode) & 1) == 0) { + tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrh(xB(ctx->opcode))); + } else { + tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrl(xB(ctx->opcode))); + } +} + +#define OP_ABS 1 +#define OP_NABS 2 +#define OP_NEG 3 +#define OP_CPSGN 4 +#define SGN_MASK_DP 0x8000000000000000ul +#define SGN_MASK_SP 0x8000000080000000ul + +#define VSX_SCALAR_MOVE(name, op, sgn_mask) \ +static void glue(gen_, name)(DisasContext * ctx) \ + { \ + TCGv_i64 xb, sgm; \ + if (unlikely(!ctx->vsx_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VSXU); \ + return; \ + } \ + xb = tcg_temp_new(); \ + sgm = tcg_temp_new(); \ + tcg_gen_mov_i64(xb, cpu_vsrh(xB(ctx->opcode))); \ + tcg_gen_movi_i64(sgm, sgn_mask); \ + switch (op) { \ + case OP_ABS: { \ + tcg_gen_andc_i64(xb, xb, sgm); \ + break; \ + } \ + case OP_NABS: { \ + tcg_gen_or_i64(xb, xb, sgm); \ + break; \ + } \ + case OP_NEG: { \ + tcg_gen_xor_i64(xb, xb, sgm); \ + break; \ + } \ + case OP_CPSGN: { \ + TCGv_i64 xa = tcg_temp_new(); \ + tcg_gen_mov_i64(xa, cpu_vsrh(xA(ctx->opcode))); \ + tcg_gen_and_i64(xa, xa, sgm); \ + tcg_gen_andc_i64(xb, xb, sgm); \ + tcg_gen_or_i64(xb, xb, xa); \ + tcg_temp_free(xa); \ + break; \ + } \ + } \ + tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xb); \ + tcg_temp_free(xb); \ + tcg_temp_free(sgm); \ + } + +VSX_SCALAR_MOVE(xsabsdp, OP_ABS, SGN_MASK_DP) +VSX_SCALAR_MOVE(xsnabsdp, OP_NABS, SGN_MASK_DP) +VSX_SCALAR_MOVE(xsnegdp, OP_NEG, SGN_MASK_DP) +VSX_SCALAR_MOVE(xscpsgndp, OP_CPSGN, SGN_MASK_DP) + +#define VSX_VECTOR_MOVE(name, op, sgn_mask) \ +static void glue(gen_, name)(DisasContext * ctx) \ + { \ + TCGv_i64 xbh, xbl, sgm; \ + if (unlikely(!ctx->vsx_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VSXU); \ + return; \ + } \ + xbh = tcg_temp_new(); \ + xbl = tcg_temp_new(); \ + sgm = tcg_temp_new(); \ + tcg_gen_mov_i64(xbh, cpu_vsrh(xB(ctx->opcode))); \ + tcg_gen_mov_i64(xbl, cpu_vsrl(xB(ctx->opcode))); \ + tcg_gen_movi_i64(sgm, sgn_mask); \ + switch (op) { \ + case OP_ABS: { \ + tcg_gen_andc_i64(xbh, xbh, sgm); \ + tcg_gen_andc_i64(xbl, xbl, sgm); \ + break; \ + } \ + case OP_NABS: { \ + tcg_gen_or_i64(xbh, xbh, sgm); \ + tcg_gen_or_i64(xbl, xbl, sgm); \ + break; \ + } \ + case OP_NEG: { \ + tcg_gen_xor_i64(xbh, xbh, sgm); \ + tcg_gen_xor_i64(xbl, xbl, sgm); \ + break; \ + } \ + case OP_CPSGN: { \ + TCGv_i64 xah = tcg_temp_new(); \ + TCGv_i64 xal = tcg_temp_new(); \ + tcg_gen_mov_i64(xah, cpu_vsrh(xA(ctx->opcode))); \ + tcg_gen_mov_i64(xal, cpu_vsrl(xA(ctx->opcode))); \ + tcg_gen_and_i64(xah, xah, sgm); \ + tcg_gen_and_i64(xal, xal, sgm); \ + tcg_gen_andc_i64(xbh, xbh, sgm); \ + tcg_gen_andc_i64(xbl, xbl, sgm); \ + tcg_gen_or_i64(xbh, xbh, xah); \ + tcg_gen_or_i64(xbl, xbl, xal); \ + tcg_temp_free(xah); \ + tcg_temp_free(xal); \ + break; \ + } \ + } \ + tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xbh); \ + tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), xbl); \ + tcg_temp_free(xbh); \ + tcg_temp_free(xbl); \ + tcg_temp_free(sgm); \ + } + +VSX_VECTOR_MOVE(xvabsdp, OP_ABS, SGN_MASK_DP) +VSX_VECTOR_MOVE(xvnabsdp, OP_NABS, SGN_MASK_DP) +VSX_VECTOR_MOVE(xvnegdp, OP_NEG, SGN_MASK_DP) +VSX_VECTOR_MOVE(xvcpsgndp, OP_CPSGN, SGN_MASK_DP) +VSX_VECTOR_MOVE(xvabssp, OP_ABS, SGN_MASK_SP) +VSX_VECTOR_MOVE(xvnabssp, OP_NABS, SGN_MASK_SP) +VSX_VECTOR_MOVE(xvnegsp, OP_NEG, SGN_MASK_SP) +VSX_VECTOR_MOVE(xvcpsgnsp, OP_CPSGN, SGN_MASK_SP) + + +#define VSX_LOGICAL(name, tcg_op) \ +static void glue(gen_, name)(DisasContext * ctx) \ + { \ + if (unlikely(!ctx->vsx_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VSXU); \ + return; \ + } \ + tcg_op(cpu_vsrh(xT(ctx->opcode)), cpu_vsrh(xA(ctx->opcode)), \ + cpu_vsrh(xB(ctx->opcode))); \ + tcg_op(cpu_vsrl(xT(ctx->opcode)), cpu_vsrl(xA(ctx->opcode)), \ + cpu_vsrl(xB(ctx->opcode))); \ + } + +VSX_LOGICAL(xxland, tcg_gen_and_tl) +VSX_LOGICAL(xxlandc, tcg_gen_andc_tl) +VSX_LOGICAL(xxlor, tcg_gen_or_tl) +VSX_LOGICAL(xxlxor, tcg_gen_xor_tl) +VSX_LOGICAL(xxlnor, tcg_gen_nor_tl) + +#define VSX_XXMRG(name, high) \ +static void glue(gen_, name)(DisasContext * ctx) \ + { \ + TCGv_i64 a0, a1, b0, b1; \ + if (unlikely(!ctx->vsx_enabled)) { \ + gen_exception(ctx, POWERPC_EXCP_VSXU); \ + return; \ + } \ + a0 = tcg_temp_new(); \ + a1 = tcg_temp_new(); \ + b0 = tcg_temp_new(); \ + b1 = tcg_temp_new(); \ + if (high) { \ + tcg_gen_mov_i64(a0, cpu_vsrh(xA(ctx->opcode))); \ + tcg_gen_mov_i64(a1, cpu_vsrh(xA(ctx->opcode))); \ + tcg_gen_mov_i64(b0, cpu_vsrh(xB(ctx->opcode))); \ + tcg_gen_mov_i64(b1, cpu_vsrh(xB(ctx->opcode))); \ + } else { \ + tcg_gen_mov_i64(a0, cpu_vsrl(xA(ctx->opcode))); \ + tcg_gen_mov_i64(a1, cpu_vsrl(xA(ctx->opcode))); \ + tcg_gen_mov_i64(b0, cpu_vsrl(xB(ctx->opcode))); \ + tcg_gen_mov_i64(b1, cpu_vsrl(xB(ctx->opcode))); \ + } \ + tcg_gen_shri_i64(a0, a0, 32); \ + tcg_gen_shri_i64(b0, b0, 32); \ + tcg_gen_deposit_i64(cpu_vsrh(xT(ctx->opcode)), \ + b0, a0, 32, 32); \ + tcg_gen_deposit_i64(cpu_vsrl(xT(ctx->opcode)), \ + b1, a1, 32, 32); \ + tcg_temp_free(a0); \ + tcg_temp_free(a1); \ + tcg_temp_free(b0); \ + tcg_temp_free(b1); \ + } + +VSX_XXMRG(xxmrghw, 1) +VSX_XXMRG(xxmrglw, 0) + +static void gen_xxsel(DisasContext * ctx) +{ + TCGv_i64 a, b, c; + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + a = tcg_temp_new(); + b = tcg_temp_new(); + c = tcg_temp_new(); + + tcg_gen_mov_i64(a, cpu_vsrh(xA(ctx->opcode))); + tcg_gen_mov_i64(b, cpu_vsrh(xB(ctx->opcode))); + tcg_gen_mov_i64(c, cpu_vsrh(xC(ctx->opcode))); + + tcg_gen_and_i64(b, b, c); + tcg_gen_andc_i64(a, a, c); + tcg_gen_or_i64(cpu_vsrh(xT(ctx->opcode)), a, b); + + tcg_gen_mov_i64(a, cpu_vsrl(xA(ctx->opcode))); + tcg_gen_mov_i64(b, cpu_vsrl(xB(ctx->opcode))); + tcg_gen_mov_i64(c, cpu_vsrl(xC(ctx->opcode))); + + tcg_gen_and_i64(b, b, c); + tcg_gen_andc_i64(a, a, c); + tcg_gen_or_i64(cpu_vsrl(xT(ctx->opcode)), a, b); + + tcg_temp_free(a); + tcg_temp_free(b); + tcg_temp_free(c); +} + +static void gen_xxspltw(DisasContext *ctx) +{ + TCGv_i64 b, b2; + TCGv_i64 vsr = (UIM(ctx->opcode) & 2) ? + cpu_vsrl(xB(ctx->opcode)) : + cpu_vsrh(xB(ctx->opcode)); + + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + + b = tcg_temp_new(); + b2 = tcg_temp_new(); + + if (UIM(ctx->opcode) & 1) { + tcg_gen_ext32u_i64(b, vsr); + } else { + tcg_gen_shri_i64(b, vsr, 32); + } + + tcg_gen_shli_i64(b2, b, 32); + tcg_gen_or_i64(cpu_vsrh(xT(ctx->opcode)), b, b2); + tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrh(xT(ctx->opcode))); + + tcg_temp_free(b); + tcg_temp_free(b2); +} + +static void gen_xxsldwi(DisasContext *ctx) +{ + TCGv_i64 xth, xtl; + if (unlikely(!ctx->vsx_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VSXU); + return; + } + xth = tcg_temp_new(); + xtl = tcg_temp_new(); + + switch (SHW(ctx->opcode)) { + case 0: { + tcg_gen_mov_i64(xth, cpu_vsrh(xA(ctx->opcode))); + tcg_gen_mov_i64(xtl, cpu_vsrl(xA(ctx->opcode))); + break; + } + case 1: { + TCGv_i64 t0 = tcg_temp_new(); + tcg_gen_mov_i64(xth, cpu_vsrh(xA(ctx->opcode))); + tcg_gen_shli_i64(xth, xth, 32); + tcg_gen_mov_i64(t0, cpu_vsrl(xA(ctx->opcode))); + tcg_gen_shri_i64(t0, t0, 32); + tcg_gen_or_i64(xth, xth, t0); + tcg_gen_mov_i64(xtl, cpu_vsrl(xA(ctx->opcode))); + tcg_gen_shli_i64(xtl, xtl, 32); + tcg_gen_mov_i64(t0, cpu_vsrh(xB(ctx->opcode))); + tcg_gen_shri_i64(t0, t0, 32); + tcg_gen_or_i64(xtl, xtl, t0); + tcg_temp_free(t0); + break; + } + case 2: { + tcg_gen_mov_i64(xth, cpu_vsrl(xA(ctx->opcode))); + tcg_gen_mov_i64(xtl, cpu_vsrh(xB(ctx->opcode))); + break; + } + case 3: { + TCGv_i64 t0 = tcg_temp_new(); + tcg_gen_mov_i64(xth, cpu_vsrl(xA(ctx->opcode))); + tcg_gen_shli_i64(xth, xth, 32); + tcg_gen_mov_i64(t0, cpu_vsrh(xB(ctx->opcode))); + tcg_gen_shri_i64(t0, t0, 32); + tcg_gen_or_i64(xth, xth, t0); + tcg_gen_mov_i64(xtl, cpu_vsrh(xB(ctx->opcode))); + tcg_gen_shli_i64(xtl, xtl, 32); + tcg_gen_mov_i64(t0, cpu_vsrl(xB(ctx->opcode))); + tcg_gen_shri_i64(t0, t0, 32); + tcg_gen_or_i64(xtl, xtl, t0); + tcg_temp_free(t0); + break; + } + } + + tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xth); + tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), xtl); + + tcg_temp_free(xth); + tcg_temp_free(xtl); +} + + /*** SPE extension ***/ /* Register moves */ - static inline void gen_evmra(DisasContext *ctx) { @@ -9413,6 +9898,119 @@ GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20), GEN_VAFORM_PAIRED(vsel, vperm, 21), GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23), +GEN_HANDLER_E(lxsdx, 0x1F, 0x0C, 0x12, 0, PPC_NONE, PPC2_VSX), +GEN_HANDLER_E(lxvd2x, 0x1F, 0x0C, 0x1A, 0, PPC_NONE, PPC2_VSX), +GEN_HANDLER_E(lxvdsx, 0x1F, 0x0C, 0x0A, 0, PPC_NONE, PPC2_VSX), +GEN_HANDLER_E(lxvw4x, 0x1F, 0x0C, 0x18, 0, PPC_NONE, PPC2_VSX), + +GEN_HANDLER_E(stxsdx, 0x1F, 0xC, 0x16, 0, PPC_NONE, PPC2_VSX), +GEN_HANDLER_E(stxvd2x, 0x1F, 0xC, 0x1E, 0, PPC_NONE, PPC2_VSX), +GEN_HANDLER_E(stxvw4x, 0x1F, 0xC, 0x1C, 0, PPC_NONE, PPC2_VSX), + +#undef GEN_XX2FORM +#define GEN_XX2FORM(name, opc2, opc3, fl2) \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0, opc3, 0, PPC_NONE, fl2), \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 0, PPC_NONE, fl2) + +#undef GEN_XX3FORM +#define GEN_XX3FORM(name, opc2, opc3, fl2) \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0, opc3, 0, PPC_NONE, fl2), \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 0, PPC_NONE, fl2), \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 2, opc3, 0, PPC_NONE, fl2), \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 3, opc3, 0, PPC_NONE, fl2) + +#undef GEN_XX3FORM_DM +#define GEN_XX3FORM_DM(name, opc2, opc3) \ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x00, opc3|0x00, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x01, opc3|0x00, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x02, opc3|0x00, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x03, opc3|0x00, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x00, opc3|0x04, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x01, opc3|0x04, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x02, opc3|0x04, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x03, opc3|0x04, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x00, opc3|0x08, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x01, opc3|0x08, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x02, opc3|0x08, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x03, opc3|0x08, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x00, opc3|0x0C, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x01, opc3|0x0C, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x02, opc3|0x0C, 0, PPC_NONE, PPC2_VSX),\ +GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x03, opc3|0x0C, 0, PPC_NONE, PPC2_VSX) + +GEN_XX2FORM(xsabsdp, 0x12, 0x15, PPC2_VSX), +GEN_XX2FORM(xsnabsdp, 0x12, 0x16, PPC2_VSX), +GEN_XX2FORM(xsnegdp, 0x12, 0x17, PPC2_VSX), +GEN_XX3FORM(xscpsgndp, 0x00, 0x16, PPC2_VSX), + +GEN_XX2FORM(xvabsdp, 0x12, 0x1D, PPC2_VSX), +GEN_XX2FORM(xvnabsdp, 0x12, 0x1E, PPC2_VSX), +GEN_XX2FORM(xvnegdp, 0x12, 0x1F, PPC2_VSX), +GEN_XX3FORM(xvcpsgndp, 0x00, 0x1E, PPC2_VSX), +GEN_XX2FORM(xvabssp, 0x12, 0x19, PPC2_VSX), +GEN_XX2FORM(xvnabssp, 0x12, 0x1A, PPC2_VSX), +GEN_XX2FORM(xvnegsp, 0x12, 0x1B, PPC2_VSX), +GEN_XX3FORM(xvcpsgnsp, 0x00, 0x1A, PPC2_VSX), + +#undef VSX_LOGICAL +#define VSX_LOGICAL(name, opc2, opc3, fl2) \ +GEN_XX3FORM(name, opc2, opc3, fl2) + +VSX_LOGICAL(xxland, 0x8, 0x10, PPC2_VSX), +VSX_LOGICAL(xxlandc, 0x8, 0x11, PPC2_VSX), +VSX_LOGICAL(xxlor, 0x8, 0x12, PPC2_VSX), +VSX_LOGICAL(xxlxor, 0x8, 0x13, PPC2_VSX), +VSX_LOGICAL(xxlnor, 0x8, 0x14, PPC2_VSX), +GEN_XX3FORM(xxmrghw, 0x08, 0x02, PPC2_VSX), +GEN_XX3FORM(xxmrglw, 0x08, 0x06, PPC2_VSX), +GEN_XX2FORM(xxspltw, 0x08, 0x0A, PPC2_VSX), +GEN_XX3FORM_DM(xxsldwi, 0x08, 0x00), + +#define GEN_XXSEL_ROW(opc3) \ +GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x18, opc3, 0, PPC_NONE, PPC2_VSX), \ +GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x19, opc3, 0, PPC_NONE, PPC2_VSX), \ +GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1A, opc3, 0, PPC_NONE, PPC2_VSX), \ +GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1B, opc3, 0, PPC_NONE, PPC2_VSX), \ +GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1C, opc3, 0, PPC_NONE, PPC2_VSX), \ +GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1D, opc3, 0, PPC_NONE, PPC2_VSX), \ +GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1E, opc3, 0, PPC_NONE, PPC2_VSX), \ +GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1F, opc3, 0, PPC_NONE, PPC2_VSX), \ + +GEN_XXSEL_ROW(0x00) +GEN_XXSEL_ROW(0x01) +GEN_XXSEL_ROW(0x02) +GEN_XXSEL_ROW(0x03) +GEN_XXSEL_ROW(0x04) +GEN_XXSEL_ROW(0x05) +GEN_XXSEL_ROW(0x06) +GEN_XXSEL_ROW(0x07) +GEN_XXSEL_ROW(0x08) +GEN_XXSEL_ROW(0x09) +GEN_XXSEL_ROW(0x0A) +GEN_XXSEL_ROW(0x0B) +GEN_XXSEL_ROW(0x0C) +GEN_XXSEL_ROW(0x0D) +GEN_XXSEL_ROW(0x0E) +GEN_XXSEL_ROW(0x0F) +GEN_XXSEL_ROW(0x10) +GEN_XXSEL_ROW(0x11) +GEN_XXSEL_ROW(0x12) +GEN_XXSEL_ROW(0x13) +GEN_XXSEL_ROW(0x14) +GEN_XXSEL_ROW(0x15) +GEN_XXSEL_ROW(0x16) +GEN_XXSEL_ROW(0x17) +GEN_XXSEL_ROW(0x18) +GEN_XXSEL_ROW(0x19) +GEN_XXSEL_ROW(0x1A) +GEN_XXSEL_ROW(0x1B) +GEN_XXSEL_ROW(0x1C) +GEN_XXSEL_ROW(0x1D) +GEN_XXSEL_ROW(0x1E) +GEN_XXSEL_ROW(0x1F) + +GEN_XX3FORM_DM(xxpermdi, 0x08, 0x01), + #undef GEN_SPE #define GEN_SPE(name0, name1, opc2, opc3, inval0, inval1, type) \ GEN_OPCODE_DUAL(name0##_##name1, 0x04, opc2, opc3, inval0, inval1, type, PPC_NONE) @@ -9759,6 +10357,11 @@ static inline void gen_intermediate_code_internal(PowerPCCPU *cpu, ctx.altivec_enabled = msr_vr; else ctx.altivec_enabled = 0; + if ((env->flags & POWERPC_FLAG_VSX) && msr_vsx) { + ctx.vsx_enabled = msr_vsx; + } else { + ctx.vsx_enabled = 0; + } if ((env->flags & POWERPC_FLAG_SE) && msr_se) ctx.singlestep_enabled = CPU_SINGLE_STEP; else diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 47825ac543..c030a2032a 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -3061,6 +3061,7 @@ static void init_excp_POWER7 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; env->excp_vectors[POWERPC_EXCP_VPU] = 0x00000F20; + env->excp_vectors[POWERPC_EXCP_VSXU] = 0x00000F40; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_MAINT] = 0x00001600; env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001700; @@ -7221,6 +7222,46 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) dc->fw_name = "PowerPC,POWER7"; dc->desc = "POWER7"; + pcc->pvr = CPU_POWERPC_POWER7_BASE; + pcc->pvr_mask = CPU_POWERPC_POWER7_MASK; + pcc->init_proc = init_proc_POWER7; + pcc->check_pow = check_pow_nocheck; + pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | + PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_64B | PPC_ALTIVEC | + PPC_SEGMENT_64B | PPC_SLBI | + PPC_POPCNTB | PPC_POPCNTWD; + pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX | PPC2_ISA205; + pcc->msr_mask = 0x800000000284FF37ULL; + pcc->mmu_model = POWERPC_MMU_2_06; +#if defined(CONFIG_SOFTMMU) + pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault; +#endif + pcc->excp_model = POWERPC_EXCP_POWER7; + pcc->bus_model = PPC_FLAGS_INPUT_POWER7; + pcc->bfd_mach = bfd_mach_ppc64; + pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | + POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR | + POWERPC_FLAG_VSX; + pcc->l1_dcache_size = 0x8000; + pcc->l1_icache_size = 0x8000; +} + +POWERPC_FAMILY(POWER7P)(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + dc->fw_name = "PowerPC,POWER7+"; + dc->desc = "POWER7+"; + pcc->pvr = CPU_POWERPC_POWER7P_BASE; + pcc->pvr_mask = CPU_POWERPC_POWER7P_MASK; pcc->init_proc = init_proc_POWER7; pcc->check_pow = check_pow_nocheck; pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB | @@ -7244,7 +7285,8 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) pcc->bfd_mach = bfd_mach_ppc64; pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | - POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR; + POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR | + POWERPC_FLAG_VSX; pcc->l1_dcache_size = 0x8000; pcc->l1_icache_size = 0x8000; } @@ -7256,6 +7298,8 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) dc->fw_name = "PowerPC,POWER8"; dc->desc = "POWER8"; + pcc->pvr = CPU_POWERPC_POWER8_BASE; + pcc->pvr_mask = CPU_POWERPC_POWER8_MASK; pcc->init_proc = init_proc_POWER7; pcc->check_pow = check_pow_nocheck; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -7269,7 +7313,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) PPC_SEGMENT_64B | PPC_SLBI | PPC_POPCNTB | PPC_POPCNTWD; pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX; - pcc->msr_mask = 0x800000000204FF36ULL; + pcc->msr_mask = 0x800000000284FF36ULL; pcc->mmu_model = POWERPC_MMU_2_06; #if defined(CONFIG_SOFTMMU) pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault; @@ -7279,7 +7323,8 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) pcc->bfd_mach = bfd_mach_ppc64; pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | - POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR; + POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR | + POWERPC_FLAG_VSX; pcc->l1_dcache_size = 0x8000; pcc->l1_icache_size = 0x8000; } @@ -8188,6 +8233,44 @@ PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr) return pcc; } +static gint ppc_cpu_compare_class_pvr_mask(gconstpointer a, gconstpointer b) +{ + ObjectClass *oc = (ObjectClass *)a; + uint32_t pvr = *(uint32_t *)b; + PowerPCCPUClass *pcc = (PowerPCCPUClass *)a; + gint ret; + + /* -cpu host does a PVR lookup during construction */ + if (unlikely(strcmp(object_class_get_name(oc), + TYPE_HOST_POWERPC_CPU) == 0)) { + return -1; + } + +#if defined(TARGET_PPCEMB) + if (pcc->mmu_model != POWERPC_MMU_BOOKE) { + return -1; + } +#endif + ret = (((pcc->pvr & pcc->pvr_mask) == (pvr & pcc->pvr_mask)) ? 0 : -1); + + return ret; +} + +PowerPCCPUClass *ppc_cpu_class_by_pvr_mask(uint32_t pvr) +{ + GSList *list, *item; + PowerPCCPUClass *pcc = NULL; + + list = object_class_get_list(TYPE_POWERPC_CPU, true); + item = g_slist_find_custom(list, &pvr, ppc_cpu_compare_class_pvr_mask); + if (item != NULL) { + pcc = POWERPC_CPU_CLASS(item->data); + } + g_slist_free(list); + + return pcc; +} + static gint ppc_cpu_compare_class_name(gconstpointer a, gconstpointer b) { ObjectClass *oc = (ObjectClass *)a; @@ -8559,6 +8642,8 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data) DeviceClass *dc = DEVICE_CLASS(oc); pcc->parent_realize = dc->realize; + pcc->pvr = CPU_POWERPC_DEFAULT_MASK; + pcc->pvr_mask = CPU_POWERPC_DEFAULT_MASK; dc->realize = ppc_cpu_realizefn; dc->unrealize = ppc_cpu_unrealizefn; |