ppc patch queue for 2017-05-11

This pull request supersedes the one from yesterday (20170510), fixing
 an important style bug in one patch, and adding an extra couple of
 simple patches.
 
 Highlights of this set:
   * Some fixes for POWER9
   * TCG support for POWER9 radix MMU
   * VGA rom for Mac machine types
   * Fixes for the XICS interrupt controller
   * MTTCG support for ppc targets
 
 As suggested by Paolo, I've tried to add the Docker tests to my
 standard pre-pull-request tests.  I haven't wholly suceeded; this has
 been tested with some of the Docker images, but others I haven't
 managed due to problems that as best I can tell are not due to
 problems in this patch series.  I'll continue working on this for
 future pull requests.  Specifically, 'travis', 'fedora', and 'centos6'
 seem to work.  'min-glib' jammed while gtesting moxie, which seems
 very unlikely to be caused by this series.  'ubuntu', 'debian' and
 'debian-bootstrap' hit build errors almost immediately that look like
 problems with the container configuration, and 'debian-*-cross' hit
 build errors later on which also look like missing dependencies from
 the container.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQIcBAABCAAGBQJZE+T6AAoJEGw4ysog2bOSgSYQAMszDZ+HCYlp6iVlJqDoy55S
 u8krYwkS9MnzrmbMjPVzGiFmH6IEuOd3zAx0aM1wZtcXjprUKsr6jHZOEtk7Frv5
 vzIwzcP85vkVegPX+fNUAo+1+T3OHix9RAI3BF5rHdyCC2OmJriPyvyOQ76uVORJ
 9ouSAeG/dCyjkVRYAlTQPidGqc/OQUaMFwZdLvhTJHeDqcdlqziCzP1YnDjN78UQ
 BRpsYOYFnGSzaqjNj16edF/yM4NiW/4tLd700mvGkvPUHrFEiyQur0Lm0bc1iZs5
 JZwcgAxhivI6CiWt57y/OpC6pWsasVhlBY00aWBcEExAh6j+Kp20g0C6MYB4JdwX
 jVJUOzWGWuMFkS65S/nHmdngUWvrSpn1xzPr0KQihLRFpoYK3btaS2TcekQocnZc
 mF3NFvKXeS/F6ZYLDWkLF/9VVEjz2mJNRvimhMWljuFyLmxlQxQSvzNXZ7Lt/maj
 D4nFaOWf5eG0O0Em54hLizM6r6vnt2qkLVSjPmOFO2gQvDsu10G/5ociqkYNRYvz
 srJUfo2xMjzaM0lvJTJT3VOWfbX1Wq4A8zyjLuoi1xpqI1Yb95zEycFvc0Eszzh1
 OByIuHLNynu+W2w08dAA8vU1tlh+Yf0yld2LOgY3Cn2gjgHQRFtmyrIsPgYsptC1
 63Y0PbTnGdbaEdlAJu8I
 =D0Hk
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'dgibson/tags/ppc-for-2.10-20170511' into staging

ppc patch queue for 2017-05-11

This pull request supersedes the one from yesterday (20170510), fixing
an important style bug in one patch, and adding an extra couple of
simple patches.

Highlights of this set:
  * Some fixes for POWER9
  * TCG support for POWER9 radix MMU
  * VGA rom for Mac machine types
  * Fixes for the XICS interrupt controller
  * MTTCG support for ppc targets

As suggested by Paolo, I've tried to add the Docker tests to my
standard pre-pull-request tests.  I haven't wholly suceeded; this has
been tested with some of the Docker images, but others I haven't
managed due to problems that as best I can tell are not due to
problems in this patch series.  I'll continue working on this for
future pull requests.  Specifically, 'travis', 'fedora', and 'centos6'
seem to work.  'min-glib' jammed while gtesting moxie, which seems
very unlikely to be caused by this series.  'ubuntu', 'debian' and
'debian-bootstrap' hit build errors almost immediately that look like
problems with the container configuration, and 'debian-*-cross' hit
build errors later on which also look like missing dependencies from
the container.

# gpg: Signature made Thu 11 May 2017 05:13:46 AM BST
# gpg:                using RSA key 0x6C38CACA20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>"
# gpg:                 aka "David Gibson (kernel.org) <dwg@kernel.org>"
# gpg:                 aka "David Gibson (Red Hat) <dgibson@redhat.com>"
# gpg:                 aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>"
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E  87DC 6C38 CACA 20D9 B392

* dgibson/tags/ppc-for-2.10-20170511: (23 commits)
  target/ppc: Avoid printing wrong aliases in CPU help text
  pnv: Fix build failures on some host platforms
  target/ppc: Allow workarounds for POWER9 DD1
  spapr: Don't accidentally advertise HTM support on POWER9
  ppc: xics: fix compilation with CentOS 6
  target/ppc: Enable RADIX mmu mode for pseries TCG guest
  target/ppc: Implement ISA V3.00 radix page fault handler
  target/ppc: Change tlbie invalid fields for POWER9 support
  target/ppc: Update tlbie to check privilege level based on GTSE
  target/ppc: Set UPRT and GTSE on all cpus in H_REGISTER_PROCESS_TABLE
  ppc: add qemu_vga.ndrv ROM to fw_cfg interface for NewWorld Macs
  ppc: add qemu_vga.ndrv ROM to fw_cfg interface for OldWorld Macs
  Add QemuMacDrivers qemu_vga.ndrv revision d4e7d7a built as submodule
  Add QemuMacDrivers as submodule
  ppc/xics: preserve P and Q bits for KVM IRQs
  ppc/xics: Fix stale irq->status bits after get
  target/ppc: do not reset reserve_addr in exec_enter
  tcg: enable MTTCG by default for PPC64 on x86
  cpus: Fix CPU unplug for MTTCG
  target/ppc: Generate fence operations
  ...

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2017-05-15 14:00:06 +01:00
commit 2f77ec7390
29 changed files with 525 additions and 63 deletions

3
.gitmodules vendored
View File

@ -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

View File

@ -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

2
configure vendored
View File

@ -6101,12 +6101,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)

6
cpus.c
View File

@ -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);

View File

@ -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. */

View File

@ -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;
@ -228,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;
}
}
}
@ -265,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) {

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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 */
@ -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). */

View File

@ -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()) {

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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)
@ -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

View File

@ -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.

BIN
pc-bios/qemu_vga.ndrv Normal file

Binary file not shown.

1
roms/QemuMacDrivers Submodule

@ -0,0 +1 @@
Subproject commit d4e7d7ac663fcb55f1b93575445fcbca372f17a7

View File

@ -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

View File

@ -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,

View File

@ -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. */
@ -480,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 */
@ -1221,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;

View File

@ -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
*/

View File

@ -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) */
}
@ -2413,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();

View File

@ -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);
}

View File

@ -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)

259
target/ppc/mmu-radix64.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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 <directory/table> 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;
}

72
target/ppc/mmu-radix64.h Normal file
View File

@ -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 */

View File

@ -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");
@ -214,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;
@ -2967,6 +2972,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)
@ -3004,6 +3010,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);
}
@ -3023,7 +3030,8 @@ 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_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); \
tcg_temp_free(t0); \
}
@ -3155,14 +3163,31 @@ 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);
/* 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);
tcg_gen_movi_tl(cpu_reserve, -1);
}
#endif
@ -3291,6 +3316,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 */
@ -4513,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();
@ -6547,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),
@ -7227,6 +7260,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

View File

@ -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 |
@ -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);
}
@ -10436,14 +10459,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 +10675,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;