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:
commit
2f77ec7390
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -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
|
||||
|
3
Makefile
3
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
|
||||
|
2
configure
vendored
2
configure
vendored
@ -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
6
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);
|
||||
|
8
cputlb.c
8
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. */
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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). */
|
||||
|
@ -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()) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
BIN
pc-bios/qemu_vga.ndrv
Normal file
Binary file not shown.
1
roms/QemuMacDrivers
Submodule
1
roms/QemuMacDrivers
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit d4e7d7ac663fcb55f1b93575445fcbca372f17a7
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
259
target/ppc/mmu-radix64.c
Normal 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
72
target/ppc/mmu-radix64.h
Normal 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 */
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user