diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index dac7bcd15e..79621eb879 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -279,11 +279,10 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp) { MacIOState *s = MACIO(d); NewWorldMacIOState *ns = NEWWORLD_MACIO(d); + DeviceState *pic_dev = DEVICE(ns->pic); Error *err = NULL; SysBusDevice *sysbus_dev; MemoryRegion *timer_memory = NULL; - int i; - int cur_irq = 0; macio_common_realize(d, &err); if (err) { @@ -292,11 +291,14 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp) } sysbus_dev = SYS_BUS_DEVICE(&s->cuda); - sysbus_connect_irq(sysbus_dev, 0, ns->irqs[cur_irq++]); + sysbus_connect_irq(sysbus_dev, 0, qdev_get_gpio_in(pic_dev, + NEWWORLD_CUDA_IRQ)); sysbus_dev = SYS_BUS_DEVICE(&s->escc); - sysbus_connect_irq(sysbus_dev, 0, ns->irqs[cur_irq++]); - sysbus_connect_irq(sysbus_dev, 1, ns->irqs[cur_irq++]); + sysbus_connect_irq(sysbus_dev, 0, qdev_get_gpio_in(pic_dev, + NEWWORLD_ESCCB_IRQ)); + sysbus_connect_irq(sysbus_dev, 1, qdev_get_gpio_in(pic_dev, + NEWWORLD_ESCCA_IRQ)); /* OpenPIC */ sysbus_dev = SYS_BUS_DEVICE(ns->pic); @@ -304,15 +306,22 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp) sysbus_mmio_get_region(sysbus_dev, 0)); /* IDE buses */ - for (i = 0; i < ARRAY_SIZE(ns->ide); i++) { - qemu_irq irq0 = ns->irqs[cur_irq++]; - qemu_irq irq1 = ns->irqs[cur_irq++]; + macio_realize_ide(s, &ns->ide[0], + qdev_get_gpio_in(pic_dev, NEWWORLD_IDE0_IRQ), + qdev_get_gpio_in(pic_dev, NEWWORLD_IDE0_DMA_IRQ), + 0x16, &err); + if (err) { + error_propagate(errp, err); + return; + } - macio_realize_ide(s, &ns->ide[i], irq0, irq1, 0x16 + (i * 4), &err); - if (err) { - error_propagate(errp, err); - return; - } + macio_realize_ide(s, &ns->ide[1], + qdev_get_gpio_in(pic_dev, NEWWORLD_IDE1_IRQ), + qdev_get_gpio_in(pic_dev, NEWWORLD_IDE1_DMA_IRQ), + 0x1a, &err); + if (err) { + error_propagate(errp, err); + return; } /* Timer */ @@ -328,8 +337,6 @@ static void macio_newworld_init(Object *obj) NewWorldMacIOState *ns = NEWWORLD_MACIO(obj); int i; - qdev_init_gpio_out(DEVICE(obj), ns->irqs, ARRAY_SIZE(ns->irqs)); - object_property_add_link(obj, "pic", TYPE_OPENPIC, (Object **) &ns->pic, qdev_prop_allow_set_link_before_realize, diff --git a/hw/pci-host/trace-events b/hw/pci-host/trace-events index 341a87a702..dd7a398e96 100644 --- a/hw/pci-host/trace-events +++ b/hw/pci-host/trace-events @@ -18,3 +18,5 @@ unin_set_irq(int irq_num, int level) "setting INT %d = %d" unin_get_config_reg(uint32_t reg, uint32_t addr, uint32_t retval) "converted config space accessor 0x%"PRIx32 "/0x%"PRIx32 " -> 0x%"PRIx32 unin_data_write(uint64_t addr, unsigned len, uint64_t val) "write addr 0x%"PRIx64 " len %d val 0x%"PRIx64 unin_data_read(uint64_t addr, unsigned len, uint64_t val) "read addr 0x%"PRIx64 " len %d val 0x%"PRIx64 +unin_write(uint64_t addr, uint64_t value) "addr=0x%" PRIx64 " val=0x%"PRIx64 +unin_read(uint64_t addr, uint64_t value) "addr=0x%" PRIx64 " val=0x%"PRIx64 diff --git a/hw/pci-host/uninorth.c b/hw/pci-host/uninorth.c index fada0ffd5f..ba76b84dbc 100644 --- a/hw/pci-host/uninorth.c +++ b/hw/pci-host/uninorth.c @@ -519,6 +519,62 @@ static const TypeInfo pci_unin_internal_info = { .class_init = pci_unin_internal_class_init, }; +/* UniN device */ +static void unin_write(void *opaque, hwaddr addr, uint64_t value, + unsigned size) +{ + trace_unin_write(addr, value); + if (addr == 0x0) { + *(int *)opaque = value; + } +} + +static uint64_t unin_read(void *opaque, hwaddr addr, unsigned size) +{ + uint32_t value; + + value = 0; + switch (addr) { + case 0: + value = *(int *)opaque; + } + + trace_unin_read(addr, value); + + return value; +} + +static const MemoryRegionOps unin_ops = { + .read = unin_read, + .write = unin_write, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static void unin_init(Object *obj) +{ + UNINState *s = UNI_NORTH(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->mem, obj, &unin_ops, &s->token, "unin", 0x1000); + + sysbus_init_mmio(sbd, &s->mem); +} + +static void unin_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); +} + +static const TypeInfo unin_info = { + .name = TYPE_UNI_NORTH, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(UNINState), + .instance_init = unin_init, + .class_init = unin_class_init, +}; + static void unin_register_types(void) { type_register_static(&unin_main_pci_host_info); @@ -530,6 +586,8 @@ static void unin_register_types(void) type_register_static(&pci_u3_agp_info); type_register_static(&pci_unin_agp_info); type_register_static(&pci_unin_internal_info); + + type_register_static(&unin_info); } type_init(unin_register_types) diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h index 892dd03789..22a7efbed6 100644 --- a/hw/ppc/mac.h +++ b/hw/ppc/mac.h @@ -56,6 +56,15 @@ #define OLDWORLD_IDE1_IRQ 0xe #define OLDWORLD_IDE1_DMA_IRQ 0x3 +/* New World IRQs */ +#define NEWWORLD_CUDA_IRQ 0x19 +#define NEWWORLD_ESCCB_IRQ 0x24 +#define NEWWORLD_ESCCA_IRQ 0x25 +#define NEWWORLD_IDE0_IRQ 0xd +#define NEWWORLD_IDE0_DMA_IRQ 0x2 +#define NEWWORLD_IDE1_IRQ 0xe +#define NEWWORLD_IDE1_DMA_IRQ 0x3 + /* MacIO */ #define TYPE_MACIO_IDE "macio-ide" #define MACIO_IDE(obj) OBJECT_CHECK(MACIOIDEState, (obj), TYPE_MACIO_IDE) diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 29bd3838bf..744acdfd2e 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -82,36 +82,6 @@ #define NDRV_VGA_FILENAME "qemu_vga.ndrv" -/* UniN device */ -static void unin_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - trace_mac99_uninorth_write(addr, value); - if (addr == 0x0) { - *(int*)opaque = value; - } -} - -static uint64_t unin_read(void *opaque, hwaddr addr, unsigned size) -{ - uint32_t value; - - value = 0; - switch (addr) { - case 0: - value = *(int*)opaque; - } - - trace_mac99_uninorth_read(addr, value); - - return value; -} - -static const MemoryRegionOps unin_ops = { - .read = unin_read, - .write = unin_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; static void fw_cfg_boot_set(void *opaque, const char *boot_device, Error **errp) @@ -144,8 +114,7 @@ static void ppc_core99_init(MachineState *machine) PowerPCCPU *cpu = NULL; CPUPPCState *env = NULL; char *filename; - qemu_irq *pic, **openpic_irqs; - MemoryRegion *unin_memory = g_new(MemoryRegion, 1); + qemu_irq **openpic_irqs; int linux_boot, i, j, k; MemoryRegion *ram = g_new(MemoryRegion, 1), *bios = g_new(MemoryRegion, 1); hwaddr kernel_base, initrd_base, cmdline_base = 0; @@ -164,7 +133,6 @@ static void ppc_core99_init(MachineState *machine) int machine_arch; SysBusDevice *s; DeviceState *dev, *pic_dev; - int *token = g_new(int, 1); hwaddr nvram_addr = 0xFFF04000; uint64_t tbfreq; @@ -272,9 +240,12 @@ static void ppc_core99_init(MachineState *machine) } } - /* UniN init: XXX should be a real device */ - memory_region_init_io(unin_memory, NULL, &unin_ops, token, "unin", 0x1000); - memory_region_add_subregion(get_system_memory(), 0xf8000000, unin_memory); + /* UniN init */ + dev = qdev_create(NULL, TYPE_UNI_NORTH); + qdev_init_nofail(dev); + s = SYS_BUS_DEVICE(dev); + memory_region_add_subregion(get_system_memory(), 0xf8000000, + sysbus_mmio_get_region(s, 0)); openpic_irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *)); openpic_irqs[0] = @@ -320,8 +291,6 @@ static void ppc_core99_init(MachineState *machine) } } - pic = g_new0(qemu_irq, 64); - pic_dev = qdev_create(NULL, TYPE_OPENPIC); qdev_prop_set_uint32(pic_dev, "model", OPENPIC_MODEL_KEYLARGO); qdev_init_nofail(pic_dev); @@ -333,10 +302,6 @@ static void ppc_core99_init(MachineState *machine) } } - for (i = 0; i < 64; i++) { - pic[i] = qdev_get_gpio_in(pic_dev, i); - } - if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) { /* 970 gets a U3 bus */ /* Uninorth AGP bus */ @@ -410,13 +375,6 @@ static void ppc_core99_init(MachineState *machine) /* MacIO */ macio = NEWWORLD_MACIO(pci_create(pci_bus, -1, TYPE_NEWWORLD_MACIO)); dev = DEVICE(macio); - qdev_connect_gpio_out(dev, 0, pic[0x19]); /* CUDA */ - qdev_connect_gpio_out(dev, 1, pic[0x24]); /* ESCC-B */ - qdev_connect_gpio_out(dev, 2, pic[0x25]); /* ESCC-A */ - qdev_connect_gpio_out(dev, 3, pic[0x0d]); /* IDE */ - qdev_connect_gpio_out(dev, 4, pic[0x02]); /* IDE DMA */ - qdev_connect_gpio_out(dev, 5, pic[0x0e]); /* IDE */ - qdev_connect_gpio_out(dev, 6, pic[0x03]); /* IDE DMA */ qdev_prop_set_uint64(dev, "frequency", tbfreq); object_property_set_link(OBJECT(macio), OBJECT(pic_dev), "pic", &error_abort); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index b35aff5d81..32ab3c43b6 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1668,10 +1668,8 @@ static void spapr_machine_reset(void) g_free(fdt); /* Set up the entry state */ - first_ppc_cpu->env.gpr[3] = fdt_addr; + spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT, fdt_addr); first_ppc_cpu->env.gpr[5] = 0; - first_cpu->halted = 0; - first_ppc_cpu->env.nip = SPAPR_ENTRY_POINT; spapr->cas_reboot = false; } @@ -1851,10 +1849,12 @@ static bool spapr_ov5_cas_needed(void *opaque) * * Thus, for any cases where the set of available CAS-negotiatable * options extends beyond OV5_FORM1_AFFINITY and OV5_DRCONF_MEMORY, we - * include the CAS-negotiated options in the migration stream. + * include the CAS-negotiated options in the migration stream, unless + * if they affect boot time behaviour only. */ spapr_ovec_set(ov5_mask, OV5_FORM1_AFFINITY); spapr_ovec_set(ov5_mask, OV5_DRCONF_MEMORY); + spapr_ovec_set(ov5_mask, OV5_DRMEM_V2); /* spapr_ovec_diff returns true if bits were removed. we avoid using * the mask itself since in the future it's possible "legacy" bits may be @@ -2508,13 +2508,11 @@ static void spapr_machine_init(MachineState *machine) int i; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); - MemoryRegion *rma_region; - void *rma = NULL; - hwaddr rma_alloc_size; hwaddr node0_size = spapr_node0_size(machine); long load_limit, fw_size; char *filename; Error *resize_hpt_err = NULL; + PowerPCCPU *first_ppc_cpu; msi_nonbroken = true; @@ -2549,40 +2547,28 @@ static void spapr_machine_init(MachineState *machine) exit(1); } - /* Allocate RMA if necessary */ - rma_alloc_size = kvmppc_alloc_rma(&rma); + spapr->rma_size = node0_size; - if (rma_alloc_size == -1) { - error_report("Unable to create RMA"); - exit(1); + /* With KVM, we don't actually know whether KVM supports an + * unbounded RMA (PR KVM) or is limited by the hash table size + * (HV KVM using VRMA), so we always assume the latter + * + * In that case, we also limit the initial allocations for RTAS + * etc... to 256M since we have no way to know what the VRMA size + * is going to be as it depends on the size of the hash table + * which isn't determined yet. + */ + if (kvm_enabled()) { + spapr->vrma_adjust = 1; + spapr->rma_size = MIN(spapr->rma_size, 0x10000000); } - if (rma_alloc_size && (rma_alloc_size < node0_size)) { - spapr->rma_size = rma_alloc_size; - } else { - spapr->rma_size = node0_size; - - /* With KVM, we don't actually know whether KVM supports an - * unbounded RMA (PR KVM) or is limited by the hash table size - * (HV KVM using VRMA), so we always assume the latter - * - * In that case, we also limit the initial allocations for RTAS - * etc... to 256M since we have no way to know what the VRMA size - * is going to be as it depends on the size of the hash table - * isn't determined yet. - */ - if (kvm_enabled()) { - spapr->vrma_adjust = 1; - spapr->rma_size = MIN(spapr->rma_size, 0x10000000); - } - - /* Actually we don't support unbounded RMA anymore since we - * added proper emulation of HV mode. The max we can get is - * 16G which also happens to be what we configure for PAPR - * mode so make sure we don't do anything bigger than that - */ - spapr->rma_size = MIN(spapr->rma_size, 0x400000000ull); - } + /* Actually we don't support unbounded RMA anymore since we added + * proper emulation of HV mode. The max we can get is 16G which + * also happens to be what we configure for PAPR mode so make sure + * we don't do anything bigger than that + */ + spapr->rma_size = MIN(spapr->rma_size, 0x400000000ull); if (spapr->rma_size > node0_size) { error_report("Numa node 0 has to span the RMA (%#08"HWADDR_PRIx")", @@ -2607,11 +2593,6 @@ static void spapr_machine_init(MachineState *machine) } spapr_ovec_set(spapr->ov5, OV5_FORM1_AFFINITY); - if (!kvm_enabled() || kvmppc_has_cap_mmu_radix()) { - /* KVM and TCG always allow GTSE with radix... */ - spapr_ovec_set(spapr->ov5, OV5_MMU_RADIX_GTSE); - } - /* ... but not with hash (currently). */ /* advertise support for dedicated HP event source to guests */ if (spapr->use_hotplug_event_source) { @@ -2629,6 +2610,15 @@ static void spapr_machine_init(MachineState *machine) /* init CPUs */ spapr_init_cpus(spapr); + first_ppc_cpu = POWERPC_CPU(first_cpu); + if ((!kvm_enabled() || kvmppc_has_cap_mmu_radix()) && + ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0, + spapr->max_compat_pvr)) { + /* KVM and TCG always allow GTSE with radix... */ + spapr_ovec_set(spapr->ov5, OV5_MMU_RADIX_GTSE); + } + /* ... but not with hash (currently). */ + if (kvm_enabled()) { /* Enable H_LOGICAL_CI_* so SLOF can talk to in-kernel devices */ kvmppc_enable_logical_ci_hcalls(); @@ -2643,14 +2633,6 @@ static void spapr_machine_init(MachineState *machine) machine->ram_size); memory_region_add_subregion(sysmem, 0, ram); - if (rma_alloc_size && rma) { - rma_region = g_new(MemoryRegion, 1); - memory_region_init_ram_ptr(rma_region, NULL, "ppc_spapr.rma", - rma_alloc_size, rma); - vmstate_register_ram_global(rma_region); - memory_region_add_subregion(sysmem, 0, rma_region); - } - /* initialize hotplug memory address space */ if (machine->ram_size < machine->maxram_size) { ram_addr_t hotplug_mem_size = machine->maxram_size - machine->ram_size; diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 01dbc69424..f3e9b879b2 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -28,6 +28,7 @@ static void spapr_cpu_reset(void *opaque) CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + target_ulong lpcr; cpu_reset(cs); @@ -43,13 +44,43 @@ static void spapr_cpu_reset(void *opaque) env->spr[SPR_HIOR] = 0; - /* Disable Power-saving mode Exit Cause exceptions for the CPU. - * This can cause issues when rebooting the guest if a secondary - * is awaken */ - if (cs != first_cpu) { - env->spr[SPR_LPCR] &= ~pcc->lpcr_pm; - } + lpcr = env->spr[SPR_LPCR]; + /* Set emulated LPCR to not send interrupts to hypervisor. Note that + * under KVM, the actual HW LPCR will be set differently by KVM itself, + * the settings below ensure proper operations with TCG in absence of + * a real hypervisor. + * + * Clearing VPM0 will also cause us to use RMOR in mmu-hash64.c for + * real mode accesses, which thankfully defaults to 0 and isn't + * accessible in guest mode. + * + * Disable Power-saving mode Exit Cause exceptions for the CPU, so + * we don't get spurious wakups before an RTAS start-cpu call. + */ + lpcr &= ~(LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_KBV | pcc->lpcr_pm); + lpcr |= LPCR_LPES0 | LPCR_LPES1; + + /* Set RMLS to the max (ie, 16G) */ + lpcr &= ~LPCR_RMLS; + lpcr |= 1ull << LPCR_RMLS_SHIFT; + + ppc_store_lpcr(cpu, lpcr); + + /* Set a full AMOR so guest can use the AMR as it sees fit */ + env->spr[SPR_AMOR] = 0xffffffffffffffffull; +} + +void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip, target_ulong r3) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + CPUPPCState *env = &cpu->env; + + env->nip = nip; + env->gpr[3] = r3; + CPU(cpu)->halted = 0; + /* Enable Power-saving mode Exit Cause exceptions */ + ppc_store_lpcr(cpu, env->spr[SPR_LPCR] | pcc->lpcr_pm); } static void spapr_cpu_destroy(PowerPCCPU *cpu) @@ -65,8 +96,8 @@ static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, /* Set time-base frequency to 512 MHz */ cpu_ppc_tb_init(env, SPAPR_TIMEBASE_FREQ); - /* Enable PAPR mode in TCG or KVM */ - cpu_ppc_set_papr(cpu, PPC_VIRTUAL_HYPERVISOR(spapr)); + cpu_ppc_set_vhyp(cpu, PPC_VIRTUAL_HYPERVISOR(spapr)); + kvmppc_set_papr(cpu); qemu_register_reset(spapr_cpu_reset, cpu); spapr_cpu_reset(cpu); diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 16bccdd5c0..ca9702e667 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -15,32 +15,35 @@ #include "hw/ppc/spapr_ovec.h" #include "mmu-book3s-v3.h" -struct SPRSyncState { - int spr; +struct LPCRSyncState { target_ulong value; target_ulong mask; }; -static void do_spr_sync(CPUState *cs, run_on_cpu_data arg) +static void do_lpcr_sync(CPUState *cs, run_on_cpu_data arg) { - struct SPRSyncState *s = arg.host_ptr; + struct LPCRSyncState *s = arg.host_ptr; PowerPCCPU *cpu = POWERPC_CPU(cs); CPUPPCState *env = &cpu->env; + target_ulong lpcr; cpu_synchronize_state(cs); - env->spr[s->spr] &= ~s->mask; - env->spr[s->spr] |= s->value; + lpcr = env->spr[SPR_LPCR]; + lpcr &= ~s->mask; + lpcr |= s->value; + ppc_store_lpcr(cpu, lpcr); } -static void set_spr(CPUState *cs, int spr, target_ulong value, - target_ulong mask) +static void set_all_lpcrs(target_ulong value, target_ulong mask) { - struct SPRSyncState s = { - .spr = spr, + CPUState *cs; + struct LPCRSyncState s = { .value = value, .mask = mask }; - run_on_cpu(cs, do_spr_sync, RUN_ON_CPU_HOST_PTR(&s)); + CPU_FOREACH(cs) { + run_on_cpu(cs, do_lpcr_sync, RUN_ON_CPU_HOST_PTR(&s)); + } } static bool has_spr(PowerPCCPU *cpu, int spr) @@ -1235,8 +1238,6 @@ static target_ulong h_set_mode_resource_le(PowerPCCPU *cpu, target_ulong value1, target_ulong value2) { - CPUState *cs; - if (value1) { return H_P3; } @@ -1246,16 +1247,12 @@ static target_ulong h_set_mode_resource_le(PowerPCCPU *cpu, switch (mflags) { case H_SET_MODE_ENDIAN_BIG: - CPU_FOREACH(cs) { - set_spr(cs, SPR_LPCR, 0, LPCR_ILE); - } + set_all_lpcrs(0, LPCR_ILE); spapr_pci_switch_vga(true); return H_SUCCESS; case H_SET_MODE_ENDIAN_LITTLE: - CPU_FOREACH(cs) { - set_spr(cs, SPR_LPCR, LPCR_ILE, LPCR_ILE); - } + set_all_lpcrs(LPCR_ILE, LPCR_ILE); spapr_pci_switch_vga(false); return H_SUCCESS; } @@ -1268,7 +1265,6 @@ static target_ulong h_set_mode_resource_addr_trans_mode(PowerPCCPU *cpu, target_ulong value1, target_ulong value2) { - CPUState *cs; PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); if (!(pcc->insns_flags2 & PPC2_ISA207S)) { @@ -1285,9 +1281,7 @@ static target_ulong h_set_mode_resource_addr_trans_mode(PowerPCCPU *cpu, return H_UNSUPPORTED_FLAG; } - CPU_FOREACH(cs) { - set_spr(cs, SPR_LPCR, mflags << LPCR_AIL_SHIFT, LPCR_AIL); - } + set_all_lpcrs(mflags << LPCR_AIL_SHIFT, LPCR_AIL); return H_SUCCESS; } @@ -1364,7 +1358,6 @@ static target_ulong h_register_process_table(PowerPCCPU *cpu, target_ulong opcode, target_ulong *args) { - CPUState *cs; target_ulong flags = args[0]; target_ulong proc_tbl = args[1]; target_ulong page_size = args[2]; @@ -1422,12 +1415,9 @@ static target_ulong h_register_process_table(PowerPCCPU *cpu, spapr->patb_entry = cproc; /* Save new process table */ /* Update the UPRT and GTSE bits in the LPCR for all cpus */ - CPU_FOREACH(cs) { - set_spr(cs, SPR_LPCR, - ((flags & (FLAG_RADIX | FLAG_HASH_PROC_TBL)) ? LPCR_UPRT : 0) | - ((flags & FLAG_GTSE) ? LPCR_GTSE : 0), - LPCR_UPRT | LPCR_GTSE); - } + set_all_lpcrs(((flags & (FLAG_RADIX | FLAG_HASH_PROC_TBL)) ? LPCR_UPRT : 0) | + ((flags & FLAG_GTSE) ? LPCR_GTSE : 0), + LPCR_UPRT | LPCR_GTSE); if (kvm_enabled()) { return kvmppc_configure_v3_mmu(cpu, flags & FLAG_RADIX, diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index 0ec5fa4cfe..7f9738daed 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -32,11 +32,12 @@ #include "hw/qdev.h" #include "sysemu/device_tree.h" #include "sysemu/cpus.h" -#include "sysemu/kvm.h" +#include "sysemu/hw_accel.h" #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" #include "hw/ppc/spapr_rtas.h" +#include "hw/ppc/spapr_cpu_core.h" #include "hw/ppc/ppc.h" #include "hw/boards.h" @@ -45,6 +46,8 @@ #include "qemu/cutils.h" #include "trace.h" #include "hw/ppc/fdt.h" +#include "target/ppc/mmu-hash64.h" +#include "target/ppc/mmu-book3s-v3.h" static void rtas_display_character(PowerPCCPU *cpu, sPAPRMachineState *spapr, uint32_t token, uint32_t nargs, @@ -119,34 +122,16 @@ static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_, rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); } -/* - * Set the timebase offset of the CPU to that of first CPU. - * This helps hotplugged CPU to have the correct timebase offset. - */ -static void spapr_cpu_update_tb_offset(PowerPCCPU *cpu) -{ - PowerPCCPU *fcpu = POWERPC_CPU(first_cpu); - - cpu->env.tb_env->tb_offset = fcpu->env.tb_env->tb_offset; -} - -static void spapr_cpu_set_endianness(PowerPCCPU *cpu) -{ - PowerPCCPU *fcpu = POWERPC_CPU(first_cpu); - PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(fcpu); - - if (!pcc->interrupts_big_endian(fcpu)) { - cpu->env.spr[SPR_LPCR] |= LPCR_ILE; - } -} - -static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr, +static void rtas_start_cpu(PowerPCCPU *callcpu, sPAPRMachineState *spapr, uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { target_ulong id, start, r3; - PowerPCCPU *cpu; + PowerPCCPU *newcpu; + CPUPPCState *env; + PowerPCCPUClass *pcc; + target_ulong lpcr; if (nargs != 3 || nret != 1) { rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); @@ -157,41 +142,55 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr, start = rtas_ld(args, 1); r3 = rtas_ld(args, 2); - cpu = spapr_find_cpu(id); - if (cpu != NULL) { - CPUState *cs = CPU(cpu); - CPUPPCState *env = &cpu->env; - PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); - - if (!cs->halted) { - rtas_st(rets, 0, RTAS_OUT_HW_ERROR); - return; - } - - /* This will make sure qemu state is up to date with kvm, and - * mark it dirty so our changes get flushed back before the - * new cpu enters */ - kvm_cpu_synchronize_state(cs); - - env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME); - - /* Enable Power-saving mode Exit Cause exceptions for the new CPU */ - env->spr[SPR_LPCR] |= pcc->lpcr_pm; - - env->nip = start; - env->gpr[3] = r3; - cs->halted = 0; - spapr_cpu_set_endianness(cpu); - spapr_cpu_update_tb_offset(cpu); - - qemu_cpu_kick(cs); - - rtas_st(rets, 0, RTAS_OUT_SUCCESS); + newcpu = spapr_find_cpu(id); + if (!newcpu) { + /* Didn't find a matching cpu */ + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; } - /* Didn't find a matching cpu */ - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); + env = &newcpu->env; + pcc = POWERPC_CPU_GET_CLASS(newcpu); + + if (!CPU(newcpu)->halted) { + rtas_st(rets, 0, RTAS_OUT_HW_ERROR); + return; + } + + cpu_synchronize_state(CPU(newcpu)); + + env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME); + + /* Enable Power-saving mode Exit Cause exceptions for the new CPU */ + lpcr = env->spr[SPR_LPCR]; + if (!pcc->interrupts_big_endian(callcpu)) { + lpcr |= LPCR_ILE; + } + if (env->mmu_model == POWERPC_MMU_3_00) { + /* + * New cpus are expected to start in the same radix/hash mode + * as the existing CPUs + */ + if (ppc64_radix_guest(callcpu)) { + lpcr |= LPCR_UPRT | LPCR_GTSE; + } else { + lpcr &= ~(LPCR_UPRT | LPCR_GTSE); + } + } + ppc_store_lpcr(newcpu, lpcr); + + /* + * Set the timebase offset of the new CPU to that of the invoking + * CPU. This helps hotplugged CPU to have the correct timebase + * offset. + */ + newcpu->env.tb_env->tb_offset = callcpu->env.tb_env->tb_offset; + + spapr_cpu_set_entry_state(newcpu, start, r3); + + qemu_cpu_kick(CPU(newcpu)); + + rtas_st(rets, 0, RTAS_OUT_SUCCESS); } static void rtas_stop_self(PowerPCCPU *cpu, sPAPRMachineState *spapr, @@ -203,13 +202,12 @@ static void rtas_stop_self(PowerPCCPU *cpu, sPAPRMachineState *spapr, CPUPPCState *env = &cpu->env; PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); - cs->halted = 1; - qemu_cpu_kick(cs); - /* Disable Power-saving mode Exit Cause exceptions for the CPU. * This could deliver an interrupt on a dying CPU and crash the * guest */ - env->spr[SPR_LPCR] &= ~pcc->lpcr_pm; + ppc_store_lpcr(cpu, env->spr[SPR_LPCR] & ~pcc->lpcr_pm); + cs->halted = 1; + qemu_cpu_kick(cs); } static inline int sysparm_st(target_ulong addr, target_ulong len, diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events index 66ec7eda6e..dc5e65aee9 100644 --- a/hw/ppc/trace-events +++ b/hw/ppc/trace-events @@ -92,10 +92,6 @@ rs6000mc_size_read(uint32_t addr, uint32_t val) "read addr=0x%x val=0x%x" rs6000mc_size_write(uint32_t addr, uint32_t val) "write addr=0x%x val=0x%x" rs6000mc_parity_read(uint32_t addr, uint32_t val) "read addr=0x%x val=0x%x" -# hw/ppc/mac_newworld.c -mac99_uninorth_write(uint64_t addr, uint64_t value) "addr=0x%" PRIx64 " val=0x%"PRIx64 -mac99_uninorth_read(uint64_t addr, uint64_t value) "addr=0x%" PRIx64 " val=0x%"PRIx64 - # hw/ppc/ppc4xx_pci.c ppc4xx_pci_map_irq(int32_t devfn, int irq_num, int slot) "devfn 0x%x irq %d -> %d" ppc4xx_pci_set_irq(int irq_num) "PCI irq %d" diff --git a/include/hw/misc/macio/macio.h b/include/hw/misc/macio/macio.h index 64a2584a77..838eaf1db0 100644 --- a/include/hw/misc/macio/macio.h +++ b/include/hw/misc/macio/macio.h @@ -71,7 +71,6 @@ typedef struct NewWorldMacIOState { /*< public >*/ OpenPICState *pic; - qemu_irq irqs[7]; MACIOIDEState ide[2]; } NewWorldMacIOState; diff --git a/include/hw/pci-host/uninorth.h b/include/hw/pci-host/uninorth.h index f0e6836c76..f6654bad9b 100644 --- a/include/hw/pci-host/uninorth.h +++ b/include/hw/pci-host/uninorth.h @@ -53,4 +53,15 @@ typedef struct UNINHostState { MemoryRegion pci_io; } UNINHostState; +typedef struct UNINState { + SysBusDevice parent_obj; + + MemoryRegion mem; + int token[1]; +} UNINState; + +#define TYPE_UNI_NORTH "uni-north" +#define UNI_NORTH(obj) \ + OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH) + #endif /* UNINORTH_H */ diff --git a/include/hw/ppc/spapr_cpu_core.h b/include/hw/ppc/spapr_cpu_core.h index 1129f344aa..47dcfda12b 100644 --- a/include/hw/ppc/spapr_cpu_core.h +++ b/include/hw/ppc/spapr_cpu_core.h @@ -12,6 +12,7 @@ #include "hw/qdev.h" #include "hw/cpu/core.h" #include "target/ppc/cpu-qom.h" +#include "target/ppc/cpu.h" #define TYPE_SPAPR_CPU_CORE "spapr-cpu-core" #define SPAPR_CPU_CORE(obj) \ @@ -38,4 +39,6 @@ typedef struct sPAPRCPUCoreClass { } sPAPRCPUCoreClass; const char *spapr_get_cpu_core_type(const char *cpu_type); +void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip, target_ulong r3); + #endif diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 8c9e03f54d..7ccd2f460e 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1295,6 +1295,7 @@ int ppc_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int size, int rw, #if !defined(CONFIG_USER_ONLY) void ppc_store_sdr1 (CPUPPCState *env, target_ulong value); +void ppc_store_ptcr(CPUPPCState *env, target_ulong value); #endif /* !defined(CONFIG_USER_ONLY) */ void ppc_store_msr (CPUPPCState *env, target_ulong value); @@ -1331,7 +1332,7 @@ void store_booke_tcr (CPUPPCState *env, target_ulong val); void store_booke_tsr (CPUPPCState *env, target_ulong val); void ppc_tlb_invalidate_all (CPUPPCState *env); void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr); -void cpu_ppc_set_papr(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp); +void cpu_ppc_set_vhyp(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp); #endif #endif @@ -1585,6 +1586,7 @@ void ppc_compat_add_property(Object *obj, const char *name, #define SPR_BOOKE_GIVOR13 (0x1BC) #define SPR_BOOKE_GIVOR14 (0x1BD) #define SPR_TIR (0x1BE) +#define SPR_PTCR (0x1D0) #define SPR_BOOKE_SPEFSCR (0x200) #define SPR_Exxx_BBEAR (0x201) #define SPR_Exxx_BBTAR (0x202) diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 5b739179b8..19453c6813 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -709,6 +709,7 @@ DEF_HELPER_FLAGS_1(load_601_rtcu, TCG_CALL_NO_RWG, tl, env) #if !defined(CONFIG_USER_ONLY) #if defined(TARGET_PPC64) DEF_HELPER_FLAGS_1(load_purr, TCG_CALL_NO_RWG, tl, env) +DEF_HELPER_2(store_ptcr, void, env, tl) #endif DEF_HELPER_2(store_sdr1, void, env, tl) DEF_HELPER_2(store_pidr, void, env, tl) diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 6de59c5b21..cbe13b18d1 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -72,7 +72,6 @@ static int cap_segstate; static int cap_booke_sregs; static int cap_ppc_smt; static int cap_ppc_smt_possible; -static int cap_ppc_rma; static int cap_spapr_tce; static int cap_spapr_tce_64; static int cap_spapr_multitce; @@ -133,7 +132,6 @@ int kvm_arch_init(MachineState *ms, KVMState *s) cap_segstate = kvm_check_extension(s, KVM_CAP_PPC_SEGSTATE); cap_booke_sregs = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_SREGS); cap_ppc_smt_possible = kvm_vm_check_extension(s, KVM_CAP_PPC_SMT_POSSIBLE); - cap_ppc_rma = kvm_check_extension(s, KVM_CAP_PPC_RMA); cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE); cap_spapr_tce_64 = kvm_check_extension(s, KVM_CAP_SPAPR_TCE_64); cap_spapr_multitce = kvm_check_extension(s, KVM_CAP_SPAPR_MULTITCE); @@ -2090,6 +2088,10 @@ void kvmppc_set_papr(PowerPCCPU *cpu) CPUState *cs = CPU(cpu); int ret; + if (!kvm_enabled()) { + return; + } + ret = kvm_vcpu_enable_cap(cs, KVM_CAP_PPC_PAPR, 0); if (ret) { error_report("This vCPU type or KVM version does not support PAPR"); @@ -2159,52 +2161,12 @@ void kvmppc_hint_smt_possible(Error **errp) #ifdef TARGET_PPC64 -off_t kvmppc_alloc_rma(void **rma) -{ - off_t size; - int fd; - struct kvm_allocate_rma ret; - - /* If cap_ppc_rma == 0, contiguous RMA allocation is not supported - * if cap_ppc_rma == 1, contiguous RMA allocation is supported, but - * not necessary on this hardware - * if cap_ppc_rma == 2, contiguous RMA allocation is needed on this hardware - * - * FIXME: We should allow the user to force contiguous RMA - * allocation in the cap_ppc_rma==1 case. - */ - if (cap_ppc_rma < 2) { - return 0; - } - - fd = kvm_vm_ioctl(kvm_state, KVM_ALLOCATE_RMA, &ret); - if (fd < 0) { - fprintf(stderr, "KVM: Error on KVM_ALLOCATE_RMA: %s\n", - strerror(errno)); - return -1; - } - - size = MIN(ret.rma_size, 256ul << 20); - - *rma = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); - if (*rma == MAP_FAILED) { - fprintf(stderr, "KVM: Error mapping RMA: %s\n", strerror(errno)); - return -1; - }; - - return size; -} - uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift) { struct kvm_ppc_smmu_info info; long rampagesize, best_page_shift; int i; - if (cap_ppc_rma >= 2) { - return current_size; - } - /* Find the largest hardware supported page size that's less than * or equal to the (logical) backing page size of guest RAM */ kvm_get_smmu_info(POWERPC_CPU(first_cpu), &info); diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h index 4d2789eef6..e2840e1d33 100644 --- a/target/ppc/kvm_ppc.h +++ b/target/ppc/kvm_ppc.h @@ -37,7 +37,6 @@ target_ulong kvmppc_configure_v3_mmu(PowerPCCPU *cpu, bool radix, bool gtse, uint64_t proc_tbl); #ifndef CONFIG_USER_ONLY -off_t kvmppc_alloc_rma(void **rma); bool kvmppc_spapr_use_multitce(void); int kvmppc_spapr_enable_inkernel_multitce(void); void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t page_shift, @@ -188,11 +187,6 @@ static inline target_ulong kvmppc_configure_v3_mmu(PowerPCCPU *cpu, } #ifndef CONFIG_USER_ONLY -static inline off_t kvmppc_alloc_rma(void **rma) -{ - return 0; -} - static inline bool kvmppc_spapr_use_multitce(void) { return false; diff --git a/target/ppc/machine.c b/target/ppc/machine.c index 3d6434a006..ba1b9e531f 100644 --- a/target/ppc/machine.c +++ b/target/ppc/machine.c @@ -212,6 +212,11 @@ static int cpu_pre_save(void *opaque) ; cpu->mig_msr_mask = env->msr_mask & ~metamask; cpu->mig_insns_flags = env->insns_flags & insns_compat_mask; + /* CPU models supported by old machines all have PPC_MEM_TLBIE, + * so we set it unconditionally to allow backward migration from + * a POWER9 host to a POWER8 host. + */ + cpu->mig_insns_flags |= PPC_MEM_TLBIE; cpu->mig_insns_flags2 = env->insns_flags2 & insns_compat_mask2; cpu->mig_nb_BATs = env->nb_BATs; } diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c index 0e4217821b..8c8cba5cc6 100644 --- a/target/ppc/misc_helper.c +++ b/target/ppc/misc_helper.c @@ -88,6 +88,18 @@ void helper_store_sdr1(CPUPPCState *env, target_ulong val) } } +#if defined(TARGET_PPC64) +void helper_store_ptcr(CPUPPCState *env, target_ulong val) +{ + PowerPCCPU *cpu = ppc_env_get_cpu(env); + + if (env->spr[SPR_PTCR] != val) { + ppc_store_ptcr(env, val); + tlb_flush(CPU(cpu)); + } +} +#endif /* defined(TARGET_PPC64) */ + void helper_store_pidr(CPUPPCState *env, target_ulong val) { PowerPCCPU *cpu = ppc_env_get_cpu(env); diff --git a/target/ppc/mmu-book3s-v3.h b/target/ppc/mmu-book3s-v3.h index 56095dab52..fdf80987d7 100644 --- a/target/ppc/mmu-book3s-v3.h +++ b/target/ppc/mmu-book3s-v3.h @@ -22,6 +22,12 @@ #ifndef CONFIG_USER_ONLY +/* + * Partition table definitions + */ +#define PTCR_PATB 0x0FFFFFFFFFFFF000ULL /* Partition Table Base */ +#define PTCR_PATS 0x000000000000001FULL /* Partition Table Size */ + /* Partition Table Entry Fields */ #define PATBE1_GR 0x8000000000000000 diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c index 7e0adecfd9..a1db20e3a8 100644 --- a/target/ppc/mmu-hash64.c +++ b/target/ppc/mmu-hash64.c @@ -942,7 +942,7 @@ void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu, target_ulong ptex, cpu->env.tlb_need_flush = TLB_NEED_GLOBAL_FLUSH | TLB_NEED_LOCAL_FLUSH; } -void ppc_hash64_update_rmls(PowerPCCPU *cpu) +static void ppc_hash64_update_rmls(PowerPCCPU *cpu) { CPUPPCState *env = &cpu->env; uint64_t lpcr = env->spr[SPR_LPCR]; @@ -977,7 +977,7 @@ void ppc_hash64_update_rmls(PowerPCCPU *cpu) } } -void ppc_hash64_update_vrma(PowerPCCPU *cpu) +static void ppc_hash64_update_vrma(PowerPCCPU *cpu) { CPUPPCState *env = &cpu->env; const PPCHash64SegmentPageSizes *sps = NULL; @@ -1028,9 +1028,9 @@ void ppc_hash64_update_vrma(PowerPCCPU *cpu) slb->sps = sps; } -void helper_store_lpcr(CPUPPCState *env, target_ulong val) +void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val) { - PowerPCCPU *cpu = ppc_env_get_cpu(env); + CPUPPCState *env = &cpu->env; uint64_t lpcr = 0; /* Filter out bits */ @@ -1096,6 +1096,13 @@ void helper_store_lpcr(CPUPPCState *env, target_ulong val) ppc_hash64_update_vrma(cpu); } +void helper_store_lpcr(CPUPPCState *env, target_ulong val) +{ + PowerPCCPU *cpu = ppc_env_get_cpu(env); + + ppc_store_lpcr(cpu, val); +} + void ppc_hash64_init(PowerPCCPU *cpu) { CPUPPCState *env = &cpu->env; diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h index d5fc03441d..53dcec5b93 100644 --- a/target/ppc/mmu-hash64.h +++ b/target/ppc/mmu-hash64.h @@ -17,8 +17,7 @@ void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu, target_ulong pte0, target_ulong pte1); unsigned ppc_hash64_hpte_page_shift_noslb(PowerPCCPU *cpu, uint64_t pte0, uint64_t pte1); -void ppc_hash64_update_vrma(PowerPCCPU *cpu); -void ppc_hash64_update_rmls(PowerPCCPU *cpu); +void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val); void ppc_hash64_init(PowerPCCPU *cpu); void ppc_hash64_finalize(PowerPCCPU *cpu); #endif @@ -102,6 +101,9 @@ void ppc_hash64_finalize(PowerPCCPU *cpu); static inline hwaddr ppc_hash64_hpt_base(PowerPCCPU *cpu) { + if (cpu->vhyp) { + return 0; + } return cpu->env.spr[SPR_SDR1] & SDR_64_HTABORG; } diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c index 8075b7149a..98ce17985b 100644 --- a/target/ppc/mmu_helper.c +++ b/target/ppc/mmu_helper.c @@ -2028,6 +2028,35 @@ void ppc_store_sdr1(CPUPPCState *env, target_ulong value) env->spr[SPR_SDR1] = value; } +#if defined(TARGET_PPC64) +void ppc_store_ptcr(CPUPPCState *env, target_ulong value) +{ + PowerPCCPU *cpu = ppc_env_get_cpu(env); + target_ulong ptcr_mask = PTCR_PATB | PTCR_PATS; + target_ulong patbsize = value & PTCR_PATS; + + qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value); + + assert(!cpu->vhyp); + assert(env->mmu_model & POWERPC_MMU_3_00); + + if (value & ~ptcr_mask) { + error_report("Invalid bits 0x"TARGET_FMT_lx" set in PTCR", + value & ~ptcr_mask); + value &= ptcr_mask; + } + + if (patbsize > 24) { + error_report("Invalid Partition Table size 0x" TARGET_FMT_lx + " stored in PTCR", patbsize); + return; + } + + env->spr[SPR_PTCR] = value; +} + +#endif /* defined(TARGET_PPC64) */ + /* Segment registers load and store */ target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num) { diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 3beaa1e2f0..2a4140f420 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -7136,6 +7136,9 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, if (env->spr_cb[SPR_SDR1].name) { /* SDR1 Exists */ cpu_fprintf(f, " SDR1 " TARGET_FMT_lx " ", env->spr[SPR_SDR1]); } + if (env->spr_cb[SPR_PTCR].name) { /* PTCR Exists */ + cpu_fprintf(f, " PTCR " TARGET_FMT_lx " ", env->spr[SPR_PTCR]); + } cpu_fprintf(f, " DAR " TARGET_FMT_lx " DSISR " TARGET_FMT_lx "\n", env->spr[SPR_DAR], env->spr[SPR_DSISR]); break; diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c index 808f6c1a08..118631efbe 100644 --- a/target/ppc/translate_init.c +++ b/target/ppc/translate_init.c @@ -420,6 +420,11 @@ static void spr_write_hior(DisasContext *ctx, int sprn, int gprn) tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_prefix)); tcg_temp_free(t0); } +static void spr_write_ptcr(DisasContext *ctx, int sprn, int gprn) +{ + gen_helper_store_ptcr(cpu_env, cpu_gpr[gprn]); +} + #endif #endif @@ -8167,6 +8172,18 @@ static void gen_spr_power8_rpr(CPUPPCState *env) #endif } +static void gen_spr_power9_mmu(CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + /* Partition Table Control */ + spr_register_hv(env, SPR_PTCR, "PTCR", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_ptcr, + 0x00000000); +#endif +} + static void init_proc_book3s_common(CPUPPCState *env) { gen_spr_ne_601(env); @@ -8719,6 +8736,7 @@ static void init_proc_POWER9(CPUPPCState *env) gen_spr_power8_ic(env); gen_spr_power8_book4(env); gen_spr_power8_rpr(env); + gen_spr_power9_mmu(env); /* POWER9 Specific registers */ spr_register_kvm(env, SPR_TIDR, "TIDR", NULL, NULL, @@ -8864,13 +8882,9 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data) } #if !defined(CONFIG_USER_ONLY) -void cpu_ppc_set_papr(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp) +void cpu_ppc_set_vhyp(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp) { - PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); CPUPPCState *env = &cpu->env; - ppc_spr_t *lpcr = &env->spr_cb[SPR_LPCR]; - ppc_spr_t *amor = &env->spr_cb[SPR_AMOR]; - CPUState *cs = CPU(cpu); cpu->vhyp = vhyp; @@ -8879,62 +8893,6 @@ void cpu_ppc_set_papr(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp) * hypervisor mode itself */ env->msr_mask &= ~MSR_HVB; - - /* Set emulated LPCR to not send interrupts to hypervisor. Note that - * under KVM, the actual HW LPCR will be set differently by KVM itself, - * the settings below ensure proper operations with TCG in absence of - * a real hypervisor. - * - * Clearing VPM0 will also cause us to use RMOR in mmu-hash64.c for - * real mode accesses, which thankfully defaults to 0 and isn't - * accessible in guest mode. - */ - lpcr->default_value &= ~(LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_KBV); - lpcr->default_value |= LPCR_LPES0 | LPCR_LPES1; - - /* Set RMLS to the max (ie, 16G) */ - lpcr->default_value &= ~LPCR_RMLS; - lpcr->default_value |= 1ull << LPCR_RMLS_SHIFT; - - if (env->mmu_model == POWERPC_MMU_3_00) { - /* By default we choose legacy mode and switch to new hash or radix - * when a register process table hcall is made. So disable process - * tables and guest translation shootdown by default - * - * Hot-plugged CPUs inherit from the guest radix setting under - * KVM but not under TCG. Update the default LPCR to keep new - * CPUs in sync when radix is enabled. - */ - if (ppc64_radix_guest(cpu)) { - lpcr->default_value |= LPCR_UPRT | LPCR_GTSE; - } else { - lpcr->default_value &= ~(LPCR_UPRT | LPCR_GTSE); - } - } - - /* Only enable Power-saving mode Exit Cause exceptions on the boot - * CPU. The RTAS command start-cpu will enable them on secondaries. - */ - if (cs == first_cpu) { - lpcr->default_value |= pcc->lpcr_pm; - } - - /* We should be followed by a CPU reset but update the active value - * just in case... - */ - env->spr[SPR_LPCR] = lpcr->default_value; - - /* Set a full AMOR so guest can use the AMR as it sees fit */ - env->spr[SPR_AMOR] = amor->default_value = 0xffffffffffffffffull; - - /* Update some env bits based on new LPCR value */ - ppc_hash64_update_rmls(cpu); - ppc_hash64_update_vrma(cpu); - - /* Tell KVM that we're in PAPR mode */ - if (kvm_enabled()) { - kvmppc_set_papr(cpu); - } } #endif /* !defined(CONFIG_USER_ONLY) */