From a1a636b8b444acacf8c4299923c907ed2475811f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 28 Apr 2017 10:26:31 +0200 Subject: [PATCH 01/23] ppc/pnv: restrict BMC object to the BMC simulator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Today, when a PowerNV guest runs, it uses the sensor definitions of the BMC simulator to populate the device tree. But an external IPMI BMC could also be used and, in that case, it is not (yet) possible to retrieve the sensor list. Generating the OEM SEL event for shutdown or reboot also does not make sense as it should be generated on the BMC side. This change allows a guest to use an 'ipmi-bmc-extern' backend to the 'isa-ipmi-bt' device and a 'chardev' for transport such as : -chardev socket,id=ipmi0,host=localhost,port=9002,reconnect=10 \ -device ipmi-bmc-extern,id=bmc0,chardev=ipmi0 \ -device isa-ipmi-bt,bmc=bmc0,irq=10 and connect to a BMC simulator, the OpenIPMI ipmi_sim simulator for instance. Signed-off-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/ppc/pnv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index d4bcdb027f..251baea5d6 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -511,7 +511,7 @@ static void ppc_powernv_reset(void) * This is the internal simulator but it could also be an external * BMC. */ - obj = object_resolve_path_type("", TYPE_IPMI_BMC, NULL); + obj = object_resolve_path_type("", "ipmi-bmc-sim", NULL); if (obj) { pnv->bmc = IPMI_BMC(obj); } From 253ce7b2cfc0bccc3470335b0d7282457926087d Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Thu, 27 Apr 2017 10:48:19 +0530 Subject: [PATCH 02/23] target/ppc: Emulate LL/SC using cmpxchg helpers Emulating LL/SC with cmpxchg is not correct, since it can suffer from the ABA problem. However, portable parallel code is written assuming only cmpxchg which means that in practice this is a viable alternative. Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target/ppc/translate.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/target/ppc/translate.c b/target/ppc/translate.c index f40b5a1abf..50b6d4dcd8 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -73,6 +73,7 @@ static TCGv cpu_cfar; #endif static TCGv cpu_xer, cpu_so, cpu_ov, cpu_ca, cpu_ov32, cpu_ca32; static TCGv cpu_reserve; +static TCGv cpu_reserve_val; static TCGv cpu_fpscr; static TCGv_i32 cpu_access_type; @@ -181,6 +182,9 @@ void ppc_translate_init(void) cpu_reserve = tcg_global_mem_new(cpu_env, offsetof(CPUPPCState, reserve_addr), "reserve_addr"); + cpu_reserve_val = tcg_global_mem_new(cpu_env, + offsetof(CPUPPCState, reserve_val), + "reserve_val"); cpu_fpscr = tcg_global_mem_new(cpu_env, offsetof(CPUPPCState, fpscr), "fpscr"); @@ -3023,7 +3027,7 @@ static void gen_##name(DisasContext *ctx) \ } \ tcg_gen_qemu_ld_tl(gpr, t0, ctx->mem_idx, memop); \ tcg_gen_mov_tl(cpu_reserve, t0); \ - tcg_gen_st_tl(gpr, cpu_env, offsetof(CPUPPCState, reserve_val)); \ + tcg_gen_mov_tl(cpu_reserve_val, gpr); \ tcg_temp_free(t0); \ } @@ -3155,14 +3159,27 @@ static void gen_conditional_store(DisasContext *ctx, TCGv EA, static void gen_conditional_store(DisasContext *ctx, TCGv EA, int reg, int memop) { - TCGLabel *l1; + TCGLabel *l1 = gen_new_label(); + TCGLabel *l2 = gen_new_label(); + TCGv t0; - tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so); - l1 = gen_new_label(); tcg_gen_brcond_tl(TCG_COND_NE, EA, cpu_reserve, l1); - tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], CRF_EQ); - tcg_gen_qemu_st_tl(cpu_gpr[reg], EA, ctx->mem_idx, memop); + + t0 = tcg_temp_new(); + tcg_gen_atomic_cmpxchg_tl(t0, cpu_reserve, cpu_reserve_val, + cpu_gpr[reg], ctx->mem_idx, + DEF_MEMOP(memop) | MO_ALIGN); + tcg_gen_setcond_tl(TCG_COND_EQ, t0, t0, cpu_reserve_val); + tcg_gen_shli_tl(t0, t0, CRF_EQ_BIT); + tcg_gen_or_tl(t0, t0, cpu_so); + tcg_gen_trunc_tl_i32(cpu_crf[0], t0); + tcg_temp_free(t0); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so); + + gen_set_label(l2); tcg_gen_movi_tl(cpu_reserve, -1); } #endif From 7f9af1abdcc69fd1d3d8d2be68464329600616d6 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Thu, 27 Apr 2017 10:48:20 +0530 Subject: [PATCH 03/23] cputlb: handle first atomic write to the page In case where the conditional write is the first write to the page, TLB_NOTDIRTY will be set and stop_the_world is triggered. Handle this as a special case and set the dirty bit. After that fall through to the actual atomic instruction below. Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- cputlb.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cputlb.c b/cputlb.c index f5d056cc08..743776ae19 100644 --- a/cputlb.c +++ b/cputlb.c @@ -930,7 +930,13 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, tlb_addr = tlbe->addr_write; } - /* Notice an IO access, or a notdirty page. */ + /* Check notdirty */ + if (unlikely(tlb_addr & TLB_NOTDIRTY)) { + tlb_set_dirty(ENV_GET_CPU(env), addr); + tlb_addr = tlb_addr & ~TLB_NOTDIRTY; + } + + /* Notice an IO access */ if (unlikely(tlb_addr & ~TARGET_PAGE_MASK)) { /* There's really nothing that can be done to support this apart from stop-the-world. */ From 4771df23ed6a2b13927030d5933147d85785f5d5 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Thu, 27 Apr 2017 10:48:21 +0530 Subject: [PATCH 04/23] target/ppc: Generate fence operations Signed-off-by: Nikunj A Dadhania Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target/ppc/translate.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 50b6d4dcd8..4a1f24a54f 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -2971,6 +2971,7 @@ static void gen_stswx(DisasContext *ctx) /* eieio */ static void gen_eieio(DisasContext *ctx) { + tcg_gen_mb(TCG_MO_LD_ST | TCG_BAR_SC); } #if !defined(CONFIG_USER_ONLY) @@ -3008,6 +3009,7 @@ static void gen_isync(DisasContext *ctx) if (!ctx->pr) { gen_check_tlb_flush(ctx, false); } + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC); gen_stop_exception(ctx); } @@ -3028,6 +3030,7 @@ static void gen_##name(DisasContext *ctx) \ tcg_gen_qemu_ld_tl(gpr, t0, ctx->mem_idx, memop); \ tcg_gen_mov_tl(cpu_reserve, t0); \ tcg_gen_mov_tl(cpu_reserve_val, gpr); \ + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); \ tcg_temp_free(t0); \ } @@ -3177,6 +3180,10 @@ static void gen_conditional_store(DisasContext *ctx, TCGv EA, tcg_gen_br(l2); gen_set_label(l1); + + /* Address mismatch implies failure. But we still need to provide the + memory barrier semantics of the instruction. */ + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so); gen_set_label(l2); @@ -3308,6 +3315,7 @@ static void gen_sync(DisasContext *ctx) if (((l == 2) || !(ctx->insns_flags & PPC_64B)) && !ctx->pr) { gen_check_tlb_flush(ctx, true); } + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC); } /* wait */ From a3e53273ad52551b61c0cdb8f48a19eb22c05831 Mon Sep 17 00:00:00 2001 From: Bharata B Rao Date: Thu, 27 Apr 2017 10:48:22 +0530 Subject: [PATCH 05/23] cpus: Fix CPU unplug for MTTCG Ensure that the unplugged CPU thread is destroyed and the waiting thread is notified about it. This is needed for CPU unplug to work correctly in MTTCG mode. Signed-off-by: Bharata B Rao Signed-off-by: Nikunj A Dadhania Signed-off-by: David Gibson --- cpus.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cpus.c b/cpus.c index 740b8dc3f8..79f780b654 100644 --- a/cpus.c +++ b/cpus.c @@ -1483,6 +1483,12 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) /* Ignore everything else? */ break; } + } else if (cpu->unplug) { + qemu_tcg_destroy_vcpu(cpu); + cpu->created = false; + qemu_cond_signal(&qemu_cpu_cond); + qemu_mutex_unlock_iothread(); + return NULL; } atomic_mb_set(&cpu->exit_request, 0); From f0b0685d6694a28c66018f438e822596243b1250 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Thu, 27 Apr 2017 10:48:23 +0530 Subject: [PATCH 06/23] tcg: enable MTTCG by default for PPC64 on x86 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This enables the multi-threaded system emulation by default for PPC64 guests using the x86_64 TCG back-end. Signed-off-by: Nikunj A Dadhania Reviewed-by: Alex Bennée Signed-off-by: David Gibson --- configure | 2 ++ target/ppc/cpu.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/configure b/configure index 7c020c076b..84c37d4115 100755 --- a/configure +++ b/configure @@ -6110,12 +6110,14 @@ case "$target_name" in ppc64) TARGET_BASE_ARCH=ppc TARGET_ABI_DIR=ppc + mttcg=yes gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml power-vsx.xml" ;; ppc64le) TARGET_ARCH=ppc64 TARGET_BASE_ARCH=ppc TARGET_ABI_DIR=ppc + mttcg=yes gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml power-vsx.xml" ;; ppc64abi32) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index e0ff0412d6..ece535d611 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -30,6 +30,8 @@ #define TARGET_LONG_BITS 64 #define TARGET_PAGE_BITS 12 +#define TCG_GUEST_DEFAULT_MO 0 + /* Note that the official physical address space bits is 62-M where M is implementation dependent. I've not looked up M for the set of cpus we emulate at the system level. */ From 139d9023f1410591726bbe35908dcfd9d127aad2 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Thu, 27 Apr 2017 10:48:24 +0530 Subject: [PATCH 07/23] target/ppc: do not reset reserve_addr in exec_enter In case when atomic operation is not supported, exit_atomic is called and we stop the world and execute the atomic operation. This results in a following call chain: tcg_gen_atomic_cmpxchg_tl() -> gen_helper_exit_atomic() -> HELPER(exit_atomic) -> cpu_loop_exit_atomic() -> EXCP_ATOMIC -> qemu_tcg_cpu_thread_fn() => case EXCP_ATOMIC -> cpu_exec_step_atomic() -> cpu_step_atomic() -> cc->cpu_exec_enter() = ppc_cpu_exec_enter() Sets env->reserve_addr = -1; But by the time it return back, the reservation is erased and the code fails, this continues forever and the lock is never taken. Instead set this in powerpc_excp() Now that ppc_cpu_exec_enter() doesn't have anything meaningful to do, let us get rid of the function. Signed-off-by: Nikunj A Dadhania Signed-off-by: David Gibson --- target/ppc/excp_helper.c | 3 +++ target/ppc/translate_init.c | 9 --------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index f4ee7aacd2..a6bcb47aa2 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -728,6 +728,9 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) cs->exception_index = POWERPC_EXCP_NONE; env->error_code = 0; + /* Reset the reservation */ + env->reserve_addr = -1; + /* Any interrupt is context synchronizing, check if TCG TLB * needs a delayed flush on ppc64 */ diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c index e82e3e65e1..9b048cd1f3 100644 --- a/target/ppc/translate_init.c +++ b/target/ppc/translate_init.c @@ -10436,14 +10436,6 @@ static bool ppc_cpu_has_work(CPUState *cs) return msr_ee && (cs->interrupt_request & CPU_INTERRUPT_HARD); } -static void ppc_cpu_exec_enter(CPUState *cs) -{ - PowerPCCPU *cpu = POWERPC_CPU(cs); - CPUPPCState *env = &cpu->env; - - env->reserve_addr = -1; -} - /* CPUClass::reset() */ static void ppc_cpu_reset(CPUState *s) { @@ -10660,7 +10652,6 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data) cc->get_phys_page_debug = ppc_cpu_get_phys_page_debug; cc->vmsd = &vmstate_ppc_cpu; #endif - cc->cpu_exec_enter = ppc_cpu_exec_enter; #if defined(CONFIG_SOFTMMU) cc->write_elf64_note = ppc64_cpu_write_elf64_note; cc->write_elf32_note = ppc32_cpu_write_elf32_note; From 063cb7cbc9f65ff4095df884cfcd7eaf3a160555 Mon Sep 17 00:00:00 2001 From: Sam Bobroff Date: Thu, 27 Apr 2017 16:31:53 +1000 Subject: [PATCH 08/23] ppc/xics: Fix stale irq->status bits after get ics_get_kvm_state() "or"s set bits into irq->status but does not mask out clear bits. Correct this by initializing the IRQ status to zero before adding bits to it. Signed-off-by: Sam Bobroff Signed-off-by: David Gibson --- hw/intc/xics_kvm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index 42e0e0ef84..03c1fc77cb 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -213,6 +213,7 @@ static void ics_get_kvm_state(ICSState *ics) irq->priority = irq->saved_priority; } + irq->status = 0; if (state & KVM_XICS_PENDING) { if (state & KVM_XICS_LEVEL_SENSITIVE) { irq->status |= XICS_STATUS_ASSERTED; From 229e16fd247c7d39822627916d18b52f733cbfa1 Mon Sep 17 00:00:00 2001 From: Sam Bobroff Date: Thu, 27 Apr 2017 16:32:03 +1000 Subject: [PATCH 09/23] ppc/xics: preserve P and Q bits for KVM IRQs Kernel commit 17d48610ae0f ("KVM: PPC: Book 3S: XICS: Implement ICS P/Q states") added new bits to the state used by KVM IRQs. Currently, QEMU does not preserve these bits, so migrating (or otherwise saving and restoring) the guest state causes the P and Q bits to be cleared. Clearing the P bit has no effect, because the kernel will set it based on other data, but the loss of a set Q bit will cause a lost interrupt. This patch preserves the P and Q bits, correcting the problem. Signed-off-by: Sam Bobroff Signed-off-by: David Gibson --- hw/intc/xics_kvm.c | 12 ++++++++++++ include/hw/ppc/xics.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index 03c1fc77cb..dd93531ae3 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -229,6 +229,12 @@ static void ics_get_kvm_state(ICSState *ics) | XICS_STATUS_REJECTED; } } + if (state & KVM_XICS_PRESENTED) { + irq->status |= XICS_STATUS_PRESENTED; + } + if (state & KVM_XICS_QUEUED) { + irq->status |= XICS_STATUS_QUEUED; + } } } @@ -266,6 +272,12 @@ static int ics_set_kvm_state(ICSState *ics, int version_id) state |= KVM_XICS_PENDING; } } + if (irq->status & XICS_STATUS_PRESENTED) { + state |= KVM_XICS_PRESENTED; + } + if (irq->status & XICS_STATUS_QUEUED) { + state |= KVM_XICS_QUEUED; + } ret = ioctl(kernel_xics_fd, KVM_SET_DEVICE_ATTR, &attr); if (ret != 0) { diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index c215dc72a4..68525c80d1 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -144,6 +144,8 @@ struct ICSIRQState { #define XICS_STATUS_SENT 0x2 #define XICS_STATUS_REJECTED 0x4 #define XICS_STATUS_MASKED_PENDING 0x8 +#define XICS_STATUS_PRESENTED 0x10 +#define XICS_STATUS_QUEUED 0x20 uint8_t status; /* (flags & XICS_FLAGS_IRQ_MASK) == 0 means the interrupt is not allocated */ #define XICS_FLAGS_IRQ_LSI 0x1 From 0806b30c8dff64e944456aa15bdc6957384e29a8 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 1 May 2017 14:43:30 +0100 Subject: [PATCH 10/23] Add QemuMacDrivers as submodule The QemuMacDrivers project provides virtualisation drivers for PPC MacOS guests. Signed-off-by: Mark Cave-Ayland Signed-off-by: David Gibson --- .gitmodules | 3 +++ pc-bios/README | 3 +++ roms/QemuMacDrivers | 1 + 3 files changed, 7 insertions(+) create mode 160000 roms/QemuMacDrivers diff --git a/.gitmodules b/.gitmodules index ca323b4d87..5b0c212622 100644 --- a/.gitmodules +++ b/.gitmodules @@ -34,3 +34,6 @@ [submodule "roms/skiboot"] path = roms/skiboot url = git://git.qemu.org/skiboot.git +[submodule "roms/QemuMacDrivers"] + path = roms/QemuMacDrivers + url = git://git.qemu.org/QemuMacDrivers.git diff --git a/pc-bios/README b/pc-bios/README index dcead369bf..ebc699d322 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -47,3 +47,6 @@ (OpenPower Abstraction Layer) firmware for OpenPOWER systems. It can run an hypervisor OS or simply a host OS on the "baremetal" platform, also known as the PowerNV (Non-Virtualized) platform. + +- QemuMacDrivers (https://github.com/ozbenh/QemuMacDrivers) is a project to + provide virtualised drivers for PPC MacOS guests. diff --git a/roms/QemuMacDrivers b/roms/QemuMacDrivers new file mode 160000 index 0000000000..d4e7d7ac66 --- /dev/null +++ b/roms/QemuMacDrivers @@ -0,0 +1 @@ +Subproject commit d4e7d7ac663fcb55f1b93575445fcbca372f17a7 From fbe9214318a41f8a201052f3ed63cca5a247408e Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 1 May 2017 14:43:31 +0100 Subject: [PATCH 11/23] Add QemuMacDrivers qemu_vga.ndrv revision d4e7d7a built as submodule Signed-off-by: Mark Cave-Ayland Signed-off-by: David Gibson --- Makefile | 3 ++- pc-bios/qemu_vga.ndrv | Bin 0 -> 14752 bytes 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 pc-bios/qemu_vga.ndrv diff --git a/Makefile b/Makefile index 31d41a7eae..c830d7a46c 100644 --- a/Makefile +++ b/Makefile @@ -552,7 +552,8 @@ multiboot.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin \ s390-ccw.img \ spapr-rtas.bin slof.bin skiboot.lid \ palcode-clipper \ -u-boot.e500 +u-boot.e500 \ +qemu_vga.ndrv else BLOBS= endif diff --git a/pc-bios/qemu_vga.ndrv b/pc-bios/qemu_vga.ndrv new file mode 100644 index 0000000000000000000000000000000000000000..6e02f74d61e01c87cf50b10e174a6626bee13677 GIT binary patch literal 14752 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 literal 0 HcmV?d00001 From b50de5cd77e3ee8ce21fbd715307319aa388b703 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 1 May 2017 14:43:32 +0100 Subject: [PATCH 12/23] ppc: add qemu_vga.ndrv ROM to fw_cfg interface for OldWorld Macs Signed-off-by: Mark Cave-Ayland Signed-off-by: David Gibson --- hw/ppc/mac_oldworld.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 5df94e239b..97bb8541d7 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -53,6 +53,8 @@ #define CLOCKFREQ 266000000UL #define BUSFREQ 66000000UL +#define NDRV_VGA_FILENAME "qemu_vga.ndrv" + static void fw_cfg_boot_set(void *opaque, const char *boot_device, Error **errp) { @@ -99,7 +101,8 @@ static void ppc_heathrow_init(MachineState *machine) MACIOIDEState *macio_ide; DeviceState *dev; BusState *adb_bus; - int bios_size; + int bios_size, ndrv_size; + uint8_t *ndrv_file; MemoryRegion *pic_mem; MemoryRegion *escc_mem, *escc_bar = g_new(MemoryRegion, 1); uint16_t ppc_boot_device; @@ -355,6 +358,19 @@ static void ppc_heathrow_init(MachineState *machine) fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_CLOCKFREQ, CLOCKFREQ); fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_BUSFREQ, BUSFREQ); + /* MacOS NDRV VGA driver */ + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, NDRV_VGA_FILENAME); + if (filename) { + ndrv_size = get_image_size(filename); + if (ndrv_size != -1) { + ndrv_file = g_malloc(ndrv_size); + ndrv_size = load_image(filename, ndrv_file); + + fw_cfg_add_file(fw_cfg, "ndrv/qemu_vga.ndrv", ndrv_file, ndrv_size); + } + g_free(filename); + } + qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); } From 53ecf09df3179203950ca6af16d9420deedcc4f3 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 1 May 2017 14:43:33 +0100 Subject: [PATCH 13/23] ppc: add qemu_vga.ndrv ROM to fw_cfg interface for NewWorld Macs Signed-off-by: Mark Cave-Ayland Signed-off-by: David Gibson --- hw/ppc/mac_newworld.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 68aaedc06d..bae1c0ac99 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -80,6 +80,8 @@ #define CLOCKFREQ (266UL * 1000UL * 1000UL) #define BUSFREQ (100UL * 1000UL * 1000UL) +#define NDRV_VGA_FILENAME "qemu_vga.ndrv" + /* UniN device */ static void unin_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) @@ -160,7 +162,8 @@ static void ppc_core99_init(MachineState *machine) MACIOIDEState *macio_ide; BusState *adb_bus; MacIONVRAMState *nvr; - int bios_size; + int bios_size, ndrv_size; + uint8_t *ndrv_file; MemoryRegion *pic_mem, *escc_mem; MemoryRegion *escc_bar = g_new(MemoryRegion, 1); int ppc_boot_device; @@ -494,6 +497,19 @@ static void ppc_core99_init(MachineState *machine) fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_BUSFREQ, BUSFREQ); fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_NVRAM_ADDR, nvram_addr); + /* MacOS NDRV VGA driver */ + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, NDRV_VGA_FILENAME); + if (filename) { + ndrv_size = get_image_size(filename); + if (ndrv_size != -1) { + ndrv_file = g_malloc(ndrv_size); + ndrv_size = load_image(filename, ndrv_file); + + fw_cfg_add_file(fw_cfg, "ndrv/qemu_vga.ndrv", ndrv_file, ndrv_size); + } + g_free(filename); + } + qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); } From 6de833070ca25874541f633e5d3ecad3fa6db2e1 Mon Sep 17 00:00:00 2001 From: Suraj Jitindar Singh Date: Tue, 2 May 2017 16:37:14 +1000 Subject: [PATCH 14/23] target/ppc: Set UPRT and GTSE on all cpus in H_REGISTER_PROCESS_TABLE The UPRT and GTSE bits are set when a guest calls H_REGISTER_PROCESS_TABLE to choose determine how address translation is performed. Currently these bits in the LPCR are only set for the cpu which handles the H_CALL, however they need to be set for all cpus for that guest as address translation cannot be performed differently on a per cpu basis. Update the H_CALL handler to set these bits in the LPCR correctly for all cpus of the guest. Note it is the reponsibility of the guest to ensure that any secondary cpus are suspended when the H_CALL is made and thus we can safely update these values here. Signed-off-by: Suraj Jitindar Singh Signed-off-by: David Gibson --- hw/ppc/spapr_hcall.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 9f18f75b88..0d608d6e28 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -936,7 +936,7 @@ static target_ulong h_register_process_table(PowerPCCPU *cpu, target_ulong opcode, target_ulong *args) { - CPUPPCState *env = &cpu->env; + CPUState *cs; target_ulong flags = args[0]; target_ulong proc_tbl = args[1]; target_ulong page_size = args[2]; @@ -992,16 +992,12 @@ static target_ulong h_register_process_table(PowerPCCPU *cpu, spapr_check_setup_free_hpt(spapr, spapr->patb_entry, cproc); spapr->patb_entry = cproc; /* Save new process table */ - if ((flags & FLAG_RADIX) || (flags & FLAG_HASH_PROC_TBL)) { - /* Use Process TBL */ - env->spr[SPR_LPCR] |= LPCR_UPRT; - } else { - env->spr[SPR_LPCR] &= ~LPCR_UPRT; - } - if (flags & FLAG_GTSE) { /* Partition Uses Guest Translation Shootdwn */ - env->spr[SPR_LPCR] |= LPCR_GTSE; - } else { - env->spr[SPR_LPCR] &= ~LPCR_GTSE; + + /* Update the UPRT and GTSE bits in the LPCR for all cpus */ + CPU_FOREACH(cs) { + set_spr(cs, SPR_LPCR, LPCR_UPRT | LPCR_GTSE, + ((flags & (FLAG_RADIX | FLAG_HASH_PROC_TBL)) ? LPCR_UPRT : 0) | + ((flags & FLAG_GTSE) ? LPCR_GTSE : 0)); } if (kvm_enabled()) { From c6fd28fd573d69938e4da6ab3348b0695cad4f42 Mon Sep 17 00:00:00 2001 From: Suraj Jitindar Singh Date: Tue, 2 May 2017 16:37:15 +1000 Subject: [PATCH 15/23] target/ppc: Update tlbie to check privilege level based on GTSE The Guest Translation Shootdown Enable (GTSE) bit in the Logical Partition Control Register (LPCR) can be set to enable a guest to use the tlbie instruction directly to invalidate translations. When the GTSE bit is set then the tlbie instruction is supervisor privileged, otherwise it is hypervisor privileged. Add a guest translation shootdown enable (gtse) field to the diassembly context and use this to check the correct privilege level at code generation time. Signed-off-by: Suraj Jitindar Singh Reviewed-by: David Gibson Signed-off-by: David Gibson --- target/ppc/translate.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 4a1f24a54f..1ce6ab19f8 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -218,6 +218,7 @@ struct DisasContext { bool vsx_enabled; bool spe_enabled; bool tm_enabled; + bool gtse; ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */ int singlestep_enabled; uint64_t insns_flags; @@ -4538,7 +4539,12 @@ static void gen_tlbie(DisasContext *ctx) GEN_PRIV; #else TCGv_i32 t1; - CHK_HV; + + if (ctx->gtse) { + CHK_SV; /* If gtse is set then tblie is supervisor privileged */ + } else { + CHK_HV; /* Else hypervisor privileged */ + } if (NARROW_MODE(ctx)) { TCGv t0 = tcg_temp_new(); @@ -7252,6 +7258,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb) ctx.tm_enabled = false; } #endif + ctx.gtse = !!(env->spr[SPR_LPCR] & LPCR_GTSE); if ((env->flags & POWERPC_FLAG_SE) && msr_se) ctx.singlestep_enabled = CPU_SINGLE_STEP; else From c88305027d5a8dbeaacf04ad2ceba79a5c5fb91e Mon Sep 17 00:00:00 2001 From: Suraj Jitindar Singh Date: Tue, 2 May 2017 16:37:16 +1000 Subject: [PATCH 16/23] target/ppc: Change tlbie invalid fields for POWER9 support The tlbie[l] instructions are used to invalidate TLB entries used to cache address translations. In ISAv3.00 (POWER9) more fields were added to the tblie[l] instructions which were previously invalid. We don't care about any of these new fields since we just invalidate the whole world anyway but we need to not cause an illegal instruction exception when the instructions are called. We also don't want to allow an older processor to have these fields set since that would be invalid. Add a new GEN_HANDLER for the ISAv3 instructions with the correct invalid mask. These will only be generated to a POWER9 processor for now based on the instruction flag. Also remove the PPC_MEM_TLBIE instruction flag from the POWER9 processor definition to ensure the old tlbie isn't generated. Signed-off-by: Suraj Jitindar Singh Reviewed-by: David Gibson Signed-off-by: David Gibson --- target/ppc/translate.c | 2 ++ target/ppc/translate_init.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 1ce6ab19f8..c0cd64d927 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -6578,6 +6578,8 @@ GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA), * different ISA versions */ GEN_HANDLER(tlbiel, 0x1F, 0x12, 0x08, 0x001F0001, PPC_MEM_TLBIE), GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x001F0001, PPC_MEM_TLBIE), +GEN_HANDLER_E(tlbiel, 0x1F, 0x12, 0x08, 0x00100001, PPC_NONE, PPC2_ISA300), +GEN_HANDLER_E(tlbie, 0x1F, 0x12, 0x09, 0x00100001, PPC_NONE, PPC2_ISA300), GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC), #if defined(TARGET_PPC64) GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x031FFC01, PPC_SLBI), diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c index 9b048cd1f3..fda30b0e1a 100644 --- a/target/ppc/translate_init.c +++ b/target/ppc/translate_init.c @@ -8960,7 +8960,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data) PPC_FLOAT_EXT | PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | PPC_MEM_SYNC | PPC_MEM_EIEIO | - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_MEM_TLBSYNC | PPC_64B | PPC_64BX | PPC_ALTIVEC | PPC_SEGMENT_64B | PPC_SLBI | PPC_POPCNTB | PPC_POPCNTWD | From d5fee0bbe68d5e61e2d2beb5ff6de0b9c1cfd182 Mon Sep 17 00:00:00 2001 From: Suraj Jitindar Singh Date: Tue, 2 May 2017 16:37:17 +1000 Subject: [PATCH 17/23] target/ppc: Implement ISA V3.00 radix page fault handler ISA V3.00 introduced a new radix mmu model. Implement the page fault handler for this so we can run a tcg guest in radix mode and perform address translation correctly. In real mode (mmu turned off) addresses are masked to remove the top 4 bits and then are subject to partition scoped translation, since we only support pseries at this stage it is only necessary to perform the masking and then we're done. In virtual mode (mmu turned on) address translation if performed as follows: 1. Use the quadrant to determine the fully qualified address. The fully qualified address is defined as the combination of the effective address, the effective logical partition id (LPID) and the effective process id (PID). Based on the quadrant (EA63:62) we set the pid and lpid like so: quadrant 0: lpid = LPIDR, pid = PIDR quadrant 1: HV only (not allowed in pseries) quadrant 2: HV only (not allowed in pseries) quadrant 3: lpid = LPIDR, pid = 0 If we can't get the fully qualified address we raise a segment interrupt. 2. Find the guest radix tree We ask the virtual hypervisor for the partition table which was registered with H_REGISTER_PROC_TBL which points us to the process table in guest memory. We then index this table by pid to get the process table entry which points us to the appropriate radix tree to translate the address. If the process table isn't big enough to contain an entry for the current pid then we raise a storage interrupt. 3. Walk the radix tree Next we walk the radix tree where each level is a table of page directory entries indexed by some number of bits from the effective address, where the number of bits is determined by the table size. We continue to walk the tree (while entries are valid and the table is of minimum size) until we reach a table of page table entries, indicated by having the leaf bit set. The appropriate pte is then checked for sufficient access permissions, the reference and change bits are updated and the real address is calculated from the real page number bits of the pte and the low bits of the effective address. If we can't find an entry or can't access the entry bacause of permissions then we raise a storage interrupt. Signed-off-by: Suraj Jitindar Singh [dwg: Add missing parentheses to macro] Signed-off-by: David Gibson --- target/ppc/Makefile.objs | 1 + target/ppc/cpu.h | 2 + target/ppc/mmu-book3s-v3.c | 6 +- target/ppc/mmu-book3s-v3.h | 5 + target/ppc/mmu-radix64.c | 259 +++++++++++++++++++++++++++++++++++++ target/ppc/mmu-radix64.h | 72 +++++++++++ 6 files changed, 341 insertions(+), 4 deletions(-) create mode 100644 target/ppc/mmu-radix64.c create mode 100644 target/ppc/mmu-radix64.h diff --git a/target/ppc/Makefile.objs b/target/ppc/Makefile.objs index f963777277..f92ba67ebd 100644 --- a/target/ppc/Makefile.objs +++ b/target/ppc/Makefile.objs @@ -4,6 +4,7 @@ obj-y += translate.o ifeq ($(CONFIG_SOFTMMU),y) obj-y += machine.o mmu_helper.o mmu-hash32.o monitor.o arch_dump.o obj-$(TARGET_PPC64) += mmu-hash64.o mmu-book3s-v3.o compat.o +obj-$(TARGET_PPC64) += mmu-radix64.o endif obj-$(CONFIG_KVM) += kvm.o obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index ece535d611..c0f63f6436 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -482,6 +482,8 @@ struct ppc_slb_t { #define DSISR_ISSTORE 0x02000000 /* Not permitted by virtual page class key protection */ #define DSISR_AMR 0x00200000 +/* Unsupported Radix Tree Configuration */ +#define DSISR_R_BADCONFIG 0x00080000 /* SRR1 error code fields */ diff --git a/target/ppc/mmu-book3s-v3.c b/target/ppc/mmu-book3s-v3.c index 005c96340a..e7798b3582 100644 --- a/target/ppc/mmu-book3s-v3.c +++ b/target/ppc/mmu-book3s-v3.c @@ -22,15 +22,13 @@ #include "cpu.h" #include "mmu-hash64.h" #include "mmu-book3s-v3.h" -#include "qemu/error-report.h" +#include "mmu-radix64.h" int ppc64_v3_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, int mmu_idx) { if (ppc64_radix_guest(cpu)) { /* Guest uses radix */ - /* TODO - Unsupported */ - error_report("Guest Radix Support Unimplemented"); - exit(1); + return ppc_radix64_handle_mmu_fault(cpu, eaddr, rwx, mmu_idx); } else { /* Guest uses hash */ return ppc_hash64_handle_mmu_fault(cpu, eaddr, rwx, mmu_idx); } diff --git a/target/ppc/mmu-book3s-v3.h b/target/ppc/mmu-book3s-v3.h index 636f6ab95f..56095dab52 100644 --- a/target/ppc/mmu-book3s-v3.h +++ b/target/ppc/mmu-book3s-v3.h @@ -25,6 +25,11 @@ /* Partition Table Entry Fields */ #define PATBE1_GR 0x8000000000000000 +/* Process Table Entry */ +struct prtb_entry { + uint64_t prtbe0, prtbe1; +}; + #ifdef TARGET_PPC64 static inline bool ppc64_use_proc_tbl(PowerPCCPU *cpu) diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c new file mode 100644 index 0000000000..de18c0b69e --- /dev/null +++ b/target/ppc/mmu-radix64.c @@ -0,0 +1,259 @@ +/* + * PowerPC Radix MMU mulation helpers for QEMU. + * + * Copyright (c) 2016 Suraj Jitindar Singh, IBM Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "exec/helper-proto.h" +#include "qemu/error-report.h" +#include "sysemu/kvm.h" +#include "kvm_ppc.h" +#include "exec/log.h" +#include "mmu-radix64.h" +#include "mmu-book3s-v3.h" + +static bool ppc_radix64_get_fully_qualified_addr(CPUPPCState *env, vaddr eaddr, + uint64_t *lpid, uint64_t *pid) +{ + /* We don't have HV support yet and shouldn't get here with it set anyway */ + assert(!msr_hv); + + if (!msr_hv) { /* !MSR[HV] -> Guest */ + switch (eaddr & R_EADDR_QUADRANT) { + case R_EADDR_QUADRANT0: /* Guest application */ + *lpid = env->spr[SPR_LPIDR]; + *pid = env->spr[SPR_BOOKS_PID]; + break; + case R_EADDR_QUADRANT1: /* Illegal */ + case R_EADDR_QUADRANT2: + return false; + case R_EADDR_QUADRANT3: /* Guest OS */ + *lpid = env->spr[SPR_LPIDR]; + *pid = 0; /* pid set to 0 -> addresses guest operating system */ + break; + } + } + + return true; +} + +static void ppc_radix64_raise_segi(PowerPCCPU *cpu, int rwx, vaddr eaddr) +{ + CPUState *cs = CPU(cpu); + CPUPPCState *env = &cpu->env; + + if (rwx == 2) { /* Instruction Segment Interrupt */ + cs->exception_index = POWERPC_EXCP_ISEG; + } else { /* Data Segment Interrupt */ + cs->exception_index = POWERPC_EXCP_DSEG; + env->spr[SPR_DAR] = eaddr; + } + env->error_code = 0; +} + +static void ppc_radix64_raise_si(PowerPCCPU *cpu, int rwx, vaddr eaddr, + uint32_t cause) +{ + CPUState *cs = CPU(cpu); + CPUPPCState *env = &cpu->env; + + if (rwx == 2) { /* Instruction Storage Interrupt */ + cs->exception_index = POWERPC_EXCP_ISI; + env->error_code = cause; + } else { /* Data Storage Interrupt */ + cs->exception_index = POWERPC_EXCP_DSI; + if (rwx == 1) { /* Write -> Store */ + cause |= DSISR_ISSTORE; + } + env->spr[SPR_DSISR] = cause; + env->spr[SPR_DAR] = eaddr; + env->error_code = 0; + } +} + + +static bool ppc_radix64_check_prot(PowerPCCPU *cpu, int rwx, uint64_t pte, + int *fault_cause, int *prot) +{ + CPUPPCState *env = &cpu->env; + const int need_prot[] = { PAGE_READ, PAGE_WRITE, PAGE_EXEC }; + + /* Check Page Attributes (pte58:59) */ + if (((pte & R_PTE_ATT) == R_PTE_ATT_NI_IO) && (rwx == 2)) { + /* + * Radix PTE entries with the non-idempotent I/O attribute are treated + * as guarded storage + */ + *fault_cause |= SRR1_NOEXEC_GUARD; + return true; + } + + /* Determine permissions allowed by Encoded Access Authority */ + if ((pte & R_PTE_EAA_PRIV) && msr_pr) { /* Insufficient Privilege */ + *prot = 0; + } else if (msr_pr || (pte & R_PTE_EAA_PRIV)) { + *prot = ppc_radix64_get_prot_eaa(pte); + } else { /* !msr_pr && !(pte & R_PTE_EAA_PRIV) */ + *prot = ppc_radix64_get_prot_eaa(pte); + *prot &= ppc_radix64_get_prot_amr(cpu); /* Least combined permissions */ + } + + /* Check if requested access type is allowed */ + if (need_prot[rwx] & ~(*prot)) { /* Page Protected for that Access */ + *fault_cause |= DSISR_PROTFAULT; + return true; + } + + return false; +} + +static void ppc_radix64_set_rc(PowerPCCPU *cpu, int rwx, uint64_t pte, + hwaddr pte_addr, int *prot) +{ + CPUState *cs = CPU(cpu); + uint64_t npte; + + npte = pte | R_PTE_R; /* Always set reference bit */ + + if (rwx == 1) { /* Store/Write */ + npte |= R_PTE_C; /* Set change bit */ + } else { + /* + * Treat the page as read-only for now, so that a later write + * will pass through this function again to set the C bit. + */ + *prot &= ~PAGE_WRITE; + } + + if (pte ^ npte) { /* If pte has changed then write it back */ + stq_phys(cs->as, pte_addr, npte); + } +} + +static uint64_t ppc_radix64_walk_tree(PowerPCCPU *cpu, int rwx, vaddr eaddr, + uint64_t base_addr, uint64_t nls, + hwaddr *raddr, int *psize, + int *fault_cause, int *prot, + hwaddr *pte_addr) +{ + CPUState *cs = CPU(cpu); + uint64_t index, pde; + + if (nls < 5) { /* Directory maps less than 2**5 entries */ + *fault_cause |= DSISR_R_BADCONFIG; + return 0; + } + + /* Read page entry from guest address space */ + index = eaddr >> (*psize - nls); /* Shift */ + index &= ((1UL << nls) - 1); /* Mask */ + pde = ldq_phys(cs->as, base_addr + (index * sizeof(pde))); + if (!(pde & R_PTE_VALID)) { /* Invalid Entry */ + *fault_cause |= DSISR_NOPTE; + return 0; + } + + *psize -= nls; + + /* Check if Leaf Entry -> Page Table Entry -> Stop the Search */ + if (pde & R_PTE_LEAF) { + uint64_t rpn = pde & R_PTE_RPN; + uint64_t mask = (1UL << *psize) - 1; + + if (ppc_radix64_check_prot(cpu, rwx, pde, fault_cause, prot)) { + return 0; /* Protection Denied Access */ + } + + /* Or high bits of rpn and low bits to ea to form whole real addr */ + *raddr = (rpn & ~mask) | (eaddr & mask); + *pte_addr = base_addr + (index * sizeof(pde)); + return pde; + } + + /* Next Level of Radix Tree */ + return ppc_radix64_walk_tree(cpu, rwx, eaddr, pde & R_PDE_NLB, + pde & R_PDE_NLS, raddr, psize, + fault_cause, prot, pte_addr); +} + +int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, + int mmu_idx) +{ + CPUState *cs = CPU(cpu); + CPUPPCState *env = &cpu->env; + PPCVirtualHypervisorClass *vhc = + PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); + hwaddr raddr, pte_addr; + uint64_t lpid = 0, pid = 0, offset, size, patbe, prtbe0, pte; + int page_size, prot, fault_cause = 0; + + assert((rwx == 0) || (rwx == 1) || (rwx == 2)); + assert(!msr_hv); /* For now there is no Radix PowerNV Support */ + assert(cpu->vhyp); + assert(ppc64_use_proc_tbl(cpu)); + + /* Real Mode Access */ + if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) { + /* In real mode top 4 effective addr bits (mostly) ignored */ + raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL; + + tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK, + PAGE_READ | PAGE_WRITE | PAGE_EXEC, mmu_idx, + TARGET_PAGE_SIZE); + return 0; + } + + /* Virtual Mode Access - get the fully qualified address */ + if (!ppc_radix64_get_fully_qualified_addr(env, eaddr, &lpid, &pid)) { + ppc_radix64_raise_segi(cpu, rwx, eaddr); + return 1; + } + + /* Get Process Table */ + patbe = vhc->get_patbe(cpu->vhyp); + + /* Index Process Table by PID to Find Corresponding Process Table Entry */ + offset = pid * sizeof(struct prtb_entry); + size = 1ULL << ((patbe & PATBE1_R_PRTS) + 12); + if (offset >= size) { + /* offset exceeds size of the process table */ + ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE); + return 1; + } + prtbe0 = ldq_phys(cs->as, (patbe & PATBE1_R_PRTB) + offset); + + /* Walk Radix Tree from Process Table Entry to Convert EA to RA */ + page_size = PRTBE_R_GET_RTS(prtbe0); + pte = ppc_radix64_walk_tree(cpu, rwx, eaddr & R_EADDR_MASK, + prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS, + &raddr, &page_size, &fault_cause, &prot, + &pte_addr); + if (!pte) { + ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause); + return 1; + } + + /* Update Reference and Change Bits */ + ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, &prot); + + tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK, + prot, mmu_idx, 1UL << page_size); + return 1; +} diff --git a/target/ppc/mmu-radix64.h b/target/ppc/mmu-radix64.h new file mode 100644 index 0000000000..1d5c7cfea5 --- /dev/null +++ b/target/ppc/mmu-radix64.h @@ -0,0 +1,72 @@ +#ifndef MMU_RADIX64_H +#define MMU_RADIX64_H + +#ifndef CONFIG_USER_ONLY + +/* Radix Quadrants */ +#define R_EADDR_MASK 0x3FFFFFFFFFFFFFFF +#define R_EADDR_QUADRANT 0xC000000000000000 +#define R_EADDR_QUADRANT0 0x0000000000000000 +#define R_EADDR_QUADRANT1 0x4000000000000000 +#define R_EADDR_QUADRANT2 0x8000000000000000 +#define R_EADDR_QUADRANT3 0xC000000000000000 + +/* Radix Partition Table Entry Fields */ +#define PATBE1_R_PRTB 0x0FFFFFFFFFFFF000 +#define PATBE1_R_PRTS 0x000000000000001F + +/* Radix Process Table Entry Fields */ +#define PRTBE_R_GET_RTS(rts) \ + ((((rts >> 58) & 0x18) | ((rts >> 5) & 0x7)) + 31) +#define PRTBE_R_RPDB 0x0FFFFFFFFFFFFF00 +#define PRTBE_R_RPDS 0x000000000000001F + +/* Radix Page Directory/Table Entry Fields */ +#define R_PTE_VALID 0x8000000000000000 +#define R_PTE_LEAF 0x4000000000000000 +#define R_PTE_SW0 0x2000000000000000 +#define R_PTE_RPN 0x01FFFFFFFFFFF000 +#define R_PTE_SW1 0x0000000000000E00 +#define R_GET_SW(sw) (((sw >> 58) & 0x8) | ((sw >> 9) & 0x7)) +#define R_PTE_R 0x0000000000000100 +#define R_PTE_C 0x0000000000000080 +#define R_PTE_ATT 0x0000000000000030 +#define R_PTE_ATT_NORMAL 0x0000000000000000 +#define R_PTE_ATT_SAO 0x0000000000000010 +#define R_PTE_ATT_NI_IO 0x0000000000000020 +#define R_PTE_ATT_TOLERANT_IO 0x0000000000000030 +#define R_PTE_EAA_PRIV 0x0000000000000008 +#define R_PTE_EAA_R 0x0000000000000004 +#define R_PTE_EAA_RW 0x0000000000000002 +#define R_PTE_EAA_X 0x0000000000000001 +#define R_PDE_NLB PRTBE_R_RPDB +#define R_PDE_NLS PRTBE_R_RPDS + +#ifdef TARGET_PPC64 + +int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, + int mmu_idx); + +static inline int ppc_radix64_get_prot_eaa(uint64_t pte) +{ + return (pte & R_PTE_EAA_R ? PAGE_READ : 0) | + (pte & R_PTE_EAA_RW ? PAGE_READ | PAGE_WRITE : 0) | + (pte & R_PTE_EAA_X ? PAGE_EXEC : 0); +} + +static inline int ppc_radix64_get_prot_amr(PowerPCCPU *cpu) +{ + CPUPPCState *env = &cpu->env; + int amr = env->spr[SPR_AMR] >> 62; /* We only care about key0 AMR63:62 */ + int iamr = env->spr[SPR_IAMR] >> 62; /* We only care about key0 IAMR63:62 */ + + return (amr & 0x2 ? 0 : PAGE_WRITE) | /* Access denied if bit is set */ + (amr & 0x1 ? 0 : PAGE_READ) | + (iamr & 0x1 ? 0 : PAGE_EXEC); +} + +#endif /* TARGET_PPC64 */ + +#endif /* CONFIG_USER_ONLY */ + +#endif /* MMU_RADIX64_H */ From 545d6e2b5c1e5fd321792bce0ad136c3a192c37b Mon Sep 17 00:00:00 2001 From: Suraj Jitindar Singh Date: Tue, 2 May 2017 16:37:18 +1000 Subject: [PATCH 18/23] target/ppc: Enable RADIX mmu mode for pseries TCG guest Now that we have added all the infrastructure we can enable a pseries TCG guest to use radix. In order to do this we have to add the appropriate bits to the ibm,arch-vec-5-platform-support vector to represent that we support both hash and radix mmu models. A radix guest can now be booted in pseries tcg mode by specifying: -cpu POWER9 Note that we assume hash, that is we allocate a hpt, until a guest tells us otherwise via a H_REGISTER_PROCESS_TABLE call with radix specified - in which case we free the hpt. If we were right and the guest is hash then there's nothing for us to do. Signed-off-by: Suraj Jitindar Singh Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/ppc/spapr.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 80d12d005c..e2dc77c2c9 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -855,6 +855,8 @@ static void spapr_dt_rtas(sPAPRMachineState *spapr, void *fdt) * option vector 5: */ static void spapr_dt_ov5_platform_support(void *fdt, int chosen) { + PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); + char val[2 * 3] = { 24, 0x00, /* Hash/Radix, filled in below. */ 25, 0x00, /* Hash options: Segment Tables == no, GTSE == no. */ @@ -870,8 +872,13 @@ static void spapr_dt_ov5_platform_support(void *fdt, int chosen) val[1] = 0x00; /* Hash */ } } else { - /* TODO: TCG case, hash */ - val[1] = 0x00; + if (first_ppc_cpu->env.mmu_model & POWERPC_MMU_V3) { + /* V3 MMU supports both hash and radix (with dynamic switching) */ + val[1] = 0xC0; + } else { + /* Otherwise we can only do hash */ + val[1] = 0x00; + } } _FDT(fdt_setprop(fdt, chosen, "ibm,arch-vec-5-platform-support", val, sizeof(val))); @@ -2101,8 +2108,8 @@ static void ppc_spapr_init(MachineState *machine) } spapr_ovec_set(spapr->ov5, OV5_FORM1_AFFINITY); - if (kvmppc_has_cap_mmu_radix()) { - /* KVM always allows GTSE with radix... */ + 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). */ From 5c6b487d673f1f5e5a30f6168bad3bc5cef40180 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 5 May 2017 11:48:50 +0200 Subject: [PATCH 19/23] ppc: xics: fix compilation with CentOS 6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PowerPCCPU typedef is included twice if a file includes both hw/ppc/xics.h and target/ppc/cpu-qom.h. Signed-off-by: Paolo Bonzini Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: David Gibson --- include/hw/ppc/xics.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index 68525c80d1..05e6acbb35 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -29,6 +29,7 @@ #define XICS_H #include "hw/qdev.h" +#include "target/ppc/cpu-qom.h" #define XICS_IPI 0x2 #define XICS_BUID 0x1 @@ -46,7 +47,6 @@ typedef struct ICSStateClass ICSStateClass; typedef struct ICSState ICSState; typedef struct ICSIRQState ICSIRQState; typedef struct XICSFabric XICSFabric; -typedef struct PowerPCCPU PowerPCCPU; #define TYPE_ICP "icp" #define ICP(obj) OBJECT_CHECK(ICPState, (obj), TYPE_ICP) From 9bf502fe127f04e393cacae9f2666e0c98c6df4f Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 9 May 2017 15:03:12 +1000 Subject: [PATCH 20/23] spapr: Don't accidentally advertise HTM support on POWER9 Logic in spapr_populate_pa_features() enables the bit advertising Hardware Transactional Memory (HTM) in the guest's device tree only when KVM advertises its availability with the KVM_CAP_PPC_HTM feature. However, this assumes that the HTM bit is off in the base template used for the device tree value. That is true for POWER8, but not for POWER9. It looks like that was accidentally changed in 9fb4541 "spapr: Enable ISA 3.0 MMU mode selection via CAS". Fixes: 9fb4541f5803f8d2ba116b12113386e26482ba30 Signed-off-by: David Gibson Reviewed-by: Thomas Huth --- hw/ppc/spapr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index e2dc77c2c9..1b7cadab0c 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -219,7 +219,7 @@ static void spapr_populate_pa_features(CPUPPCState *env, void *fdt, int offset, /* 16: Vector */ 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, /* 12 - 17 */ /* 18: Vec. Scalar, 20: Vec. XOR, 22: HTM */ - 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 18 - 23 */ + 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, /* 18 - 23 */ /* 24: Ext. Dec, 26: 64 bit ftrs, 28: PM ftrs */ 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, /* 24 - 29 */ /* 30: MMR, 32: LE atomic, 34: EBB + ext EBB */ From 5f3066d8b1063b364cd42d64bc011a56fae9c086 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 10 May 2017 11:19:16 +1000 Subject: [PATCH 21/23] target/ppc: Allow workarounds for POWER9 DD1 POWER9 DD1 silicon has some bugs which mean it a) isn't really compliant with the ISA v3.00 and b) require a number of special workarounds in the kernel. At the moment, qemu isn't aware of DD1. For TCG we don't really want it to be (why bother emulating buggy silicon). But with KVM, the guest does need to be aware of DD1 so it can apply the necessary workarounds. Meanwhile, the feature negotiation between qemu and the guest strongly favours architected compatibility modes to "raw" CPU modes. In combination with the above, this means the guest sees architected POWER9 mode, and doesn't apply the DD1 workarounds. Well, unless it has yet another workaround to partially ignore what qemu tells it. This patch addresses this by disabling support for compatibility modes when using KVM on a POWER9 DD1 host. Signed-off-by: David Gibson --- target/ppc/cpu-models.h | 1 + target/ppc/kvm.c | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/target/ppc/cpu-models.h b/target/ppc/cpu-models.h index d587e69bbc..b563c45b68 100644 --- a/target/ppc/cpu-models.h +++ b/target/ppc/cpu-models.h @@ -561,6 +561,7 @@ enum { CPU_POWERPC_POWER8NVL_BASE = 0x004C0000, CPU_POWERPC_POWER8NVL_v10 = 0x004C0100, CPU_POWERPC_POWER9_BASE = 0x004E0000, + CPU_POWERPC_POWER9_DD1 = 0x004E0100, CPU_POWERPC_970_v22 = 0x00390202, CPU_POWERPC_970FX_v10 = 0x00391100, CPU_POWERPC_970FX_v20 = 0x003C0200, diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 8574c369e6..cb2cf2b107 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -2380,6 +2380,17 @@ static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data) #if defined(TARGET_PPC64) pcc->radix_page_info = kvm_get_radix_page_info(); + + if ((pcc->pvr & 0xffffff00) == CPU_POWERPC_POWER9_DD1) { + /* + * POWER9 DD1 has some bugs which make it not really ISA 3.00 + * compliant. More importantly, advertising ISA 3.00 + * architected mode may prevent guests from activating + * necessary DD1 workarounds. + */ + pcc->pcr_supported &= ~(PCR_COMPAT_3_00 | PCR_COMPAT_2_07 + | PCR_COMPAT_2_06 | PCR_COMPAT_2_05); + } #endif /* defined(TARGET_PPC64) */ } From eaf87a3976fbdd96b2cf813d4e13cb5b2b839d88 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 10 May 2017 16:46:01 +1000 Subject: [PATCH 22/23] pnv: Fix build failures on some host platforms This makes some changes to fix build failures on the 'min-glib' docker image, and maybe other platforms with a buildchain that's less tolerant about duplicated typedefs. Signed-off-by: David Gibson --- include/hw/ppc/pnv.h | 3 +-- include/hw/ppc/pnv_lpc.h | 4 ++-- include/hw/ppc/pnv_occ.h | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h index c1288f974d..9c5437dabc 100644 --- a/include/hw/ppc/pnv.h +++ b/include/hw/ppc/pnv.h @@ -21,6 +21,7 @@ #include "hw/boards.h" #include "hw/sysbus.h" +#include "hw/ipmi/ipmi.h" #include "hw/ppc/pnv_lpc.h" #include "hw/ppc/pnv_psi.h" #include "hw/ppc/pnv_occ.h" @@ -118,8 +119,6 @@ typedef struct PnvChipClass { #define POWERNV_MACHINE(obj) \ OBJECT_CHECK(PnvMachineState, (obj), TYPE_POWERNV_MACHINE) -typedef struct IPMIBmc IPMIBmc; - typedef struct PnvMachineState { /*< private >*/ MachineState parent_obj; diff --git a/include/hw/ppc/pnv_lpc.h b/include/hw/ppc/pnv_lpc.h index ccf969af94..023b4f0fec 100644 --- a/include/hw/ppc/pnv_lpc.h +++ b/include/hw/ppc/pnv_lpc.h @@ -19,12 +19,12 @@ #ifndef _PPC_PNV_LPC_H #define _PPC_PNV_LPC_H +#include "hw/ppc/pnv_psi.h" + #define TYPE_PNV_LPC "pnv-lpc" #define PNV_LPC(obj) \ OBJECT_CHECK(PnvLpcController, (obj), TYPE_PNV_LPC) -typedef struct PnvPsi PnvPsi; - typedef struct PnvLpcController { DeviceState parent; diff --git a/include/hw/ppc/pnv_occ.h b/include/hw/ppc/pnv_occ.h index f8ec330abf..82f299dc76 100644 --- a/include/hw/ppc/pnv_occ.h +++ b/include/hw/ppc/pnv_occ.h @@ -19,11 +19,11 @@ #ifndef _PPC_PNV_OCC_H #define _PPC_PNV_OCC_H +#include "hw/ppc/pnv_psi.h" + #define TYPE_PNV_OCC "pnv-occ" #define PNV_OCC(obj) OBJECT_CHECK(PnvOCC, (obj), TYPE_PNV_OCC) -typedef struct PnvPsi PnvPsi; - typedef struct PnvOCC { DeviceState xd; From e9edd931eb1b7e4be2274a8d9b3e5d5c4b7d1aad Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 10 May 2017 06:19:32 +0200 Subject: [PATCH 23/23] target/ppc: Avoid printing wrong aliases in CPU help text When running with KVM, we update the "family" CPU alias to point to the right host CPU type, so that it for example possible to use "-cpu POWER8" on a POWER8NVL host. However, the function for printing the list of available CPU models is called earlier than the KVM setup code, so the output of "-cpu help" is wrong in that case. Since it would be somewhat ugly anyway to have different help texts depending on whether "-enable-kvm" has been specified or not, we should better always print the same text, so fix this issue by printing "alias for preferred XXX CPU" instead. Reviewed-by: Eduardo Habkost Signed-off-by: Thomas Huth Signed-off-by: David Gibson --- target/ppc/cpu.h | 1 + target/ppc/kvm.c | 12 ------------ target/ppc/translate_init.c | 27 +++++++++++++++++++++++++-- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index c0f63f6436..401e10e7da 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1225,6 +1225,7 @@ static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env) PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr); PowerPCCPUClass *ppc_cpu_class_by_pvr_mask(uint32_t pvr); +PowerPCCPUClass *ppc_cpu_get_family_class(PowerPCCPUClass *pcc); struct PPCVirtualHypervisor { Object parent; diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index cb2cf2b107..51249ce79e 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -2424,18 +2424,6 @@ bool kvmppc_has_cap_mmu_hash_v3(void) return cap_mmu_hash_v3; } -static PowerPCCPUClass *ppc_cpu_get_family_class(PowerPCCPUClass *pcc) -{ - ObjectClass *oc = OBJECT_CLASS(pcc); - - while (oc && !object_class_is_abstract(oc)) { - oc = object_class_get_parent(oc); - } - assert(oc); - - return POWERPC_CPU_CLASS(oc); -} - PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void) { uint32_t host_pvr = mfpvr(); diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c index fda30b0e1a..56a0ab22cf 100644 --- a/target/ppc/translate_init.c +++ b/target/ppc/translate_init.c @@ -10285,6 +10285,18 @@ PowerPCCPU *cpu_ppc_init(const char *cpu_model) return POWERPC_CPU(cpu_generic_init(TYPE_POWERPC_CPU, cpu_model)); } +PowerPCCPUClass *ppc_cpu_get_family_class(PowerPCCPUClass *pcc) +{ + ObjectClass *oc = OBJECT_CLASS(pcc); + + while (oc && !object_class_is_abstract(oc)) { + oc = object_class_get_parent(oc); + } + assert(oc); + + return POWERPC_CPU_CLASS(oc); +} + /* Sort by PVR, ordering special case "host" last. */ static gint ppc_cpu_list_compare(gconstpointer a, gconstpointer b) { @@ -10316,6 +10328,7 @@ static void ppc_cpu_list_entry(gpointer data, gpointer user_data) ObjectClass *oc = data; CPUListState *s = user_data; PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + DeviceClass *family = DEVICE_CLASS(ppc_cpu_get_family_class(pcc)); const char *typename = object_class_get_name(oc); char *name; int i; @@ -10338,8 +10351,18 @@ static void ppc_cpu_list_entry(gpointer data, gpointer user_data) if (alias_oc != oc) { continue; } - (*s->cpu_fprintf)(s->file, "PowerPC %-16s (alias for %s)\n", - alias->alias, name); + /* + * If running with KVM, we might update the family alias later, so + * avoid printing the wrong alias here and use "preferred" instead + */ + if (strcmp(alias->alias, family->desc) == 0) { + (*s->cpu_fprintf)(s->file, + "PowerPC %-16s (alias for preferred %s CPU)\n", + alias->alias, family->desc); + } else { + (*s->cpu_fprintf)(s->file, "PowerPC %-16s (alias for %s)\n", + alias->alias, name); + } } g_free(name); }