#include "sysemu/hw_accel.h"
#include "sysemu/sysemu.h"
#include "qemu/log.h"
+#include "qemu/module.h"
#include "qemu/error-report.h"
#include "cpu.h"
#include "exec/exec-all.h"
#include "helper_regs.h"
#include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_cpu_core.h"
#include "mmu-hash64.h"
#include "cpu-models.h"
#include "trace.h"
#include "kvm_ppc.h"
#include "hw/ppc/spapr_ovec.h"
#include "mmu-book3s-v3.h"
-
-struct SPRSyncState {
- int spr;
- target_ulong value;
- target_ulong mask;
-};
-
-static void do_spr_sync(CPUState *cs, run_on_cpu_data arg)
-{
- struct SPRSyncState *s = arg.host_ptr;
- PowerPCCPU *cpu = POWERPC_CPU(cs);
- CPUPPCState *env = &cpu->env;
-
- cpu_synchronize_state(cs);
- env->spr[s->spr] &= ~s->mask;
- env->spr[s->spr] |= s->value;
-}
-
-static void set_spr(CPUState *cs, int spr, target_ulong value,
- target_ulong mask)
-{
- struct SPRSyncState s = {
- .spr = spr,
- .value = value,
- .mask = mask
- };
- run_on_cpu(cs, do_spr_sync, RUN_ON_CPU_HOST_PTR(&s));
-}
+#include "hw/mem/memory-device.h"
static bool has_spr(PowerPCCPU *cpu, int spr)
{
return true;
}
-static bool is_ram_address(sPAPRMachineState *spapr, hwaddr addr)
+static bool is_ram_address(SpaprMachineState *spapr, hwaddr addr)
{
MachineState *machine = MACHINE(spapr);
- MemoryHotplugState *hpms = &spapr->hotplug_memory;
+ DeviceMemoryState *dms = machine->device_memory;
if (addr < machine->ram_size) {
return true;
}
- if ((addr >= hpms->base)
- && ((addr - hpms->base) < memory_region_size(&hpms->mr))) {
+ if ((addr >= dms->base)
+ && ((addr - dms->base) < memory_region_size(&dms->mr))) {
return true;
}
return false;
}
-static target_ulong h_enter(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_enter(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong flags = args[0];
ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
}
- ppc_hash64_store_hpte(cpu, ptex + slot, pteh | HPTE64_V_HPTE_DIRTY, ptel);
+ spapr_store_hpte(cpu, ptex + slot, pteh | HPTE64_V_HPTE_DIRTY, ptel);
args[0] = ptex + slot;
return H_SUCCESS;
REMOVE_HW = 3,
} RemoveResult;
-static RemoveResult remove_hpte(PowerPCCPU *cpu, target_ulong ptex,
+static RemoveResult remove_hpte(PowerPCCPU *cpu
+ , target_ulong ptex,
target_ulong avpn,
target_ulong flags,
target_ulong *vp, target_ulong *rp)
}
*vp = v;
*rp = r;
- ppc_hash64_store_hpte(cpu, ptex, HPTE64_V_HPTE_DIRTY, 0);
+ spapr_store_hpte(cpu, ptex, HPTE64_V_HPTE_DIRTY, 0);
ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r);
return REMOVE_SUCCESS;
}
-static target_ulong h_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_remove(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
CPUPPCState *env = &cpu->env;
#define H_BULK_REMOVE_MAX_BATCH 4
-static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_bulk_remove(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
CPUPPCState *env = &cpu->env;
return rc;
}
-static target_ulong h_protect(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_protect(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
CPUPPCState *env = &cpu->env;
r |= (flags << 55) & HPTE64_R_PP0;
r |= (flags << 48) & HPTE64_R_KEY_HI;
r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
- ppc_hash64_store_hpte(cpu, ptex,
- (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0);
+ spapr_store_hpte(cpu, ptex,
+ (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0);
ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r);
/* Flush the tlb */
check_tlb_flush(env, true);
/* Don't need a memory barrier, due to qemu's global lock */
- ppc_hash64_store_hpte(cpu, ptex, v | HPTE64_V_HPTE_DIRTY, r);
+ spapr_store_hpte(cpu, ptex, v | HPTE64_V_HPTE_DIRTY, r);
return H_SUCCESS;
}
-static target_ulong h_read(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_read(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong flags = args[0];
target_ulong ptex = args[1];
- uint8_t *hpte;
int i, ridx, n_entries = 1;
+ const ppc_hash_pte64_t *hptes;
if (!valid_ptex(cpu, ptex)) {
return H_PARAMETER;
n_entries = 4;
}
- hpte = spapr->htab + (ptex * HASH_PTE_SIZE_64);
-
+ hptes = ppc_hash64_map_hptes(cpu, ptex, n_entries);
for (i = 0, ridx = 0; i < n_entries; i++) {
- args[ridx++] = ldq_p(hpte);
- args[ridx++] = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
- hpte += HASH_PTE_SIZE_64;
+ args[ridx++] = ppc_hash64_hpte0(cpu, hptes, i);
+ args[ridx++] = ppc_hash64_hpte1(cpu, hptes, i);
}
+ ppc_hash64_unmap_hptes(cpu, hptes, ptex, n_entries);
return H_SUCCESS;
}
-struct sPAPRPendingHPT {
+struct SpaprPendingHpt {
/* These fields are read-only after initialization */
int shift;
QemuThread thread;
void *hpt;
};
-static void free_pending_hpt(sPAPRPendingHPT *pending)
+static void free_pending_hpt(SpaprPendingHpt *pending)
{
if (pending->hpt) {
qemu_vfree(pending->hpt);
static void *hpt_prepare_thread(void *opaque)
{
- sPAPRPendingHPT *pending = opaque;
+ SpaprPendingHpt *pending = opaque;
size_t size = 1ULL << pending->shift;
pending->hpt = qemu_memalign(size, size);
}
/* Must be called with BQL held */
-static void cancel_hpt_prepare(sPAPRMachineState *spapr)
+static void cancel_hpt_prepare(SpaprMachineState *spapr)
{
- sPAPRPendingHPT *pending = spapr->pending_hpt;
+ SpaprPendingHpt *pending = spapr->pending_hpt;
/* Let the thread know it's cancelled */
spapr->pending_hpt = NULL;
}
static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
target_ulong flags = args[0];
int shift = args[1];
- sPAPRPendingHPT *pending = spapr->pending_hpt;
+ SpaprPendingHpt *pending = spapr->pending_hpt;
uint64_t current_ram_size;
int rc;
/* start new prepare */
- pending = g_new0(sPAPRPendingHPT, 1);
+ pending = g_new0(SpaprPendingHpt, 1);
pending->shift = shift;
pending->ret = H_HARDWARE;
}
}
-static void push_sregs_to_kvm_pr(sPAPRMachineState *spapr)
+static void push_sregs_to_kvm_pr(SpaprMachineState *spapr)
{
CPUState *cs;
}
static target_ulong h_resize_hpt_commit(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
target_ulong flags = args[0];
target_ulong shift = args[1];
- sPAPRPendingHPT *pending = spapr->pending_hpt;
+ SpaprPendingHpt *pending = spapr->pending_hpt;
int rc;
size_t newsize;
return H_AUTHORITY;
}
+ if (!spapr->htab_shift) {
+ /* Radix guest, no HPT */
+ return H_NOT_AVAILABLE;
+ }
+
trace_spapr_h_resize_hpt_commit(flags, shift);
rc = kvmppc_resize_hpt_commit(cpu, flags, shift);
if (rc != -ENOSYS) {
- return resize_hpt_convert_rc(rc);
+ rc = resize_hpt_convert_rc(rc);
+ if (rc == H_SUCCESS) {
+ /* Need to set the new htab_shift in the machine state */
+ spapr->htab_shift = shift;
+ }
+ return rc;
}
if (flags != 0) {
return rc;
}
-static target_ulong h_set_sprg0(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_set_sprg0(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
cpu_synchronize_state(CPU(cpu));
return H_SUCCESS;
}
-static target_ulong h_set_dabr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_set_dabr(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
if (!has_spr(cpu, SPR_DABR)) {
return H_SUCCESS;
}
-static target_ulong h_set_xdabr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_set_xdabr(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong dabrx = args[1];
return H_SUCCESS;
}
-static target_ulong h_page_init(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_page_init(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong flags = args[0];
#define VPA_SHARED_PROC_OFFSET 0x9
#define VPA_SHARED_PROC_VAL 0x2
-static target_ulong register_vpa(CPUPPCState *env, target_ulong vpa)
+static target_ulong register_vpa(PowerPCCPU *cpu, target_ulong vpa)
{
- CPUState *cs = CPU(ppc_env_get_cpu(env));
+ CPUState *cs = CPU(cpu);
+ CPUPPCState *env = &cpu->env;
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
uint16_t size;
uint8_t tmp;
return H_PARAMETER;
}
- env->vpa_addr = vpa;
+ spapr_cpu->vpa_addr = vpa;
- tmp = ldub_phys(cs->as, env->vpa_addr + VPA_SHARED_PROC_OFFSET);
+ tmp = ldub_phys(cs->as, spapr_cpu->vpa_addr + VPA_SHARED_PROC_OFFSET);
tmp |= VPA_SHARED_PROC_VAL;
- stb_phys(cs->as, env->vpa_addr + VPA_SHARED_PROC_OFFSET, tmp);
+ stb_phys(cs->as, spapr_cpu->vpa_addr + VPA_SHARED_PROC_OFFSET, tmp);
return H_SUCCESS;
}
-static target_ulong deregister_vpa(CPUPPCState *env, target_ulong vpa)
+static target_ulong deregister_vpa(PowerPCCPU *cpu, target_ulong vpa)
{
- if (env->slb_shadow_addr) {
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
+
+ if (spapr_cpu->slb_shadow_addr) {
return H_RESOURCE;
}
- if (env->dtl_addr) {
+ if (spapr_cpu->dtl_addr) {
return H_RESOURCE;
}
- env->vpa_addr = 0;
+ spapr_cpu->vpa_addr = 0;
return H_SUCCESS;
}
-static target_ulong register_slb_shadow(CPUPPCState *env, target_ulong addr)
+static target_ulong register_slb_shadow(PowerPCCPU *cpu, target_ulong addr)
{
- CPUState *cs = CPU(ppc_env_get_cpu(env));
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
uint32_t size;
if (addr == 0) {
return H_HARDWARE;
}
- size = ldl_be_phys(cs->as, addr + 0x4);
+ size = ldl_be_phys(CPU(cpu)->as, addr + 0x4);
if (size < 0x8) {
return H_PARAMETER;
}
return H_PARAMETER;
}
- if (!env->vpa_addr) {
+ if (!spapr_cpu->vpa_addr) {
return H_RESOURCE;
}
- env->slb_shadow_addr = addr;
- env->slb_shadow_size = size;
+ spapr_cpu->slb_shadow_addr = addr;
+ spapr_cpu->slb_shadow_size = size;
return H_SUCCESS;
}
-static target_ulong deregister_slb_shadow(CPUPPCState *env, target_ulong addr)
+static target_ulong deregister_slb_shadow(PowerPCCPU *cpu, target_ulong addr)
{
- env->slb_shadow_addr = 0;
- env->slb_shadow_size = 0;
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
+
+ spapr_cpu->slb_shadow_addr = 0;
+ spapr_cpu->slb_shadow_size = 0;
return H_SUCCESS;
}
-static target_ulong register_dtl(CPUPPCState *env, target_ulong addr)
+static target_ulong register_dtl(PowerPCCPU *cpu, target_ulong addr)
{
- CPUState *cs = CPU(ppc_env_get_cpu(env));
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
uint32_t size;
if (addr == 0) {
return H_HARDWARE;
}
- size = ldl_be_phys(cs->as, addr + 0x4);
+ size = ldl_be_phys(CPU(cpu)->as, addr + 0x4);
if (size < 48) {
return H_PARAMETER;
}
- if (!env->vpa_addr) {
+ if (!spapr_cpu->vpa_addr) {
return H_RESOURCE;
}
- env->dtl_addr = addr;
- env->dtl_size = size;
+ spapr_cpu->dtl_addr = addr;
+ spapr_cpu->dtl_size = size;
return H_SUCCESS;
}
-static target_ulong deregister_dtl(CPUPPCState *env, target_ulong addr)
+static target_ulong deregister_dtl(PowerPCCPU *cpu, target_ulong addr)
{
- env->dtl_addr = 0;
- env->dtl_size = 0;
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
+
+ spapr_cpu->dtl_addr = 0;
+ spapr_cpu->dtl_size = 0;
return H_SUCCESS;
}
-static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_register_vpa(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong flags = args[0];
target_ulong procno = args[1];
target_ulong vpa = args[2];
target_ulong ret = H_PARAMETER;
- CPUPPCState *tenv;
PowerPCCPU *tcpu;
tcpu = spapr_find_cpu(procno);
if (!tcpu) {
return H_PARAMETER;
}
- tenv = &tcpu->env;
switch (flags) {
case FLAGS_REGISTER_VPA:
- ret = register_vpa(tenv, vpa);
+ ret = register_vpa(tcpu, vpa);
break;
case FLAGS_DEREGISTER_VPA:
- ret = deregister_vpa(tenv, vpa);
+ ret = deregister_vpa(tcpu, vpa);
break;
case FLAGS_REGISTER_SLBSHADOW:
- ret = register_slb_shadow(tenv, vpa);
+ ret = register_slb_shadow(tcpu, vpa);
break;
case FLAGS_DEREGISTER_SLBSHADOW:
- ret = deregister_slb_shadow(tenv, vpa);
+ ret = deregister_slb_shadow(tcpu, vpa);
break;
case FLAGS_REGISTER_DTL:
- ret = register_dtl(tenv, vpa);
+ ret = register_dtl(tcpu, vpa);
break;
case FLAGS_DEREGISTER_DTL:
- ret = deregister_dtl(tenv, vpa);
+ ret = deregister_dtl(tcpu, vpa);
break;
}
return ret;
}
-static target_ulong h_cede(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_cede(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
CPUPPCState *env = &cpu->env;
return H_SUCCESS;
}
-static target_ulong h_rtas(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_rtas(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong rtas_r3 = args[0];
nret, rtas_r3 + 12 + 4*nargs);
}
-static target_ulong h_logical_load(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_logical_load(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
CPUState *cs = CPU(cpu);
return H_PARAMETER;
}
-static target_ulong h_logical_store(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_logical_store(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
CPUState *cs = CPU(cpu);
return H_PARAMETER;
}
-static target_ulong h_logical_memop(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_logical_memop(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
CPUState *cs = CPU(cpu);
return H_SUCCESS;
}
-static target_ulong h_logical_icbi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_logical_icbi(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
/* Nothing to do on emulation, KVM will trap this in the kernel */
return H_SUCCESS;
}
-static target_ulong h_logical_dcbf(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_logical_dcbf(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
/* Nothing to do on emulation, KVM will trap this in the kernel */
target_ulong value1,
target_ulong value2)
{
- CPUState *cs;
-
if (value1) {
return H_P3;
}
switch (mflags) {
case H_SET_MODE_ENDIAN_BIG:
- CPU_FOREACH(cs) {
- set_spr(cs, SPR_LPCR, 0, LPCR_ILE);
- }
+ spapr_set_all_lpcrs(0, LPCR_ILE);
spapr_pci_switch_vga(true);
return H_SUCCESS;
case H_SET_MODE_ENDIAN_LITTLE:
- CPU_FOREACH(cs) {
- set_spr(cs, SPR_LPCR, LPCR_ILE, LPCR_ILE);
- }
+ spapr_set_all_lpcrs(LPCR_ILE, LPCR_ILE);
spapr_pci_switch_vga(false);
return H_SUCCESS;
}
target_ulong value1,
target_ulong value2)
{
- CPUState *cs;
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
if (!(pcc->insns_flags2 & PPC2_ISA207S)) {
return H_UNSUPPORTED_FLAG;
}
- CPU_FOREACH(cs) {
- set_spr(cs, SPR_LPCR, mflags << LPCR_AIL_SHIFT, LPCR_AIL);
- }
+ spapr_set_all_lpcrs(mflags << LPCR_AIL_SHIFT, LPCR_AIL);
return H_SUCCESS;
}
-static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_set_mode(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong resource = args[1];
return ret;
}
-static target_ulong h_clean_slb(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_clean_slb(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
qemu_log_mask(LOG_UNIMP, "Unimplemented SPAPR hcall 0x"TARGET_FMT_lx"%s\n",
return H_FUNCTION;
}
-static target_ulong h_invalidate_pid(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_invalidate_pid(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
qemu_log_mask(LOG_UNIMP, "Unimplemented SPAPR hcall 0x"TARGET_FMT_lx"%s\n",
return H_FUNCTION;
}
-static void spapr_check_setup_free_hpt(sPAPRMachineState *spapr,
+static void spapr_check_setup_free_hpt(SpaprMachineState *spapr,
uint64_t patbe_old, uint64_t patbe_new)
{
/*
* later and so assumed radix and now it's called H_REG_PROC_TBL
*/
- if ((patbe_old & PATBE1_GR) == (patbe_new & PATBE1_GR)) {
+ if ((patbe_old & PATE1_GR) == (patbe_new & PATE1_GR)) {
/* We assume RADIX, so this catches all the "Do Nothing" cases */
- } else if (!(patbe_old & PATBE1_GR)) {
+ } else if (!(patbe_old & PATE1_GR)) {
/* HASH->RADIX : Free HPT */
spapr_free_hpt(spapr);
- } else if (!(patbe_new & PATBE1_GR)) {
+ } else if (!(patbe_new & PATE1_GR)) {
/* RADIX->HASH || NOTHING->HASH : Allocate HPT */
spapr_setup_hpt_and_vrma(spapr);
}
#define FLAG_GTSE 0x01
static target_ulong h_register_process_table(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
- CPUState *cs;
target_ulong flags = args[0];
target_ulong proc_tbl = args[1];
target_ulong page_size = args[2];
target_ulong table_size = args[3];
+ target_ulong update_lpcr = 0;
uint64_t cproc;
if (flags & ~FLAGS_MASK) { /* Check no reserved bits are set */
} else if (table_size > 24) {
return H_P4;
}
- cproc = PATBE1_GR | proc_tbl | table_size;
+ cproc = PATE1_GR | proc_tbl | table_size;
} else { /* Register new HPT process table */
if (flags & FLAG_HASH_PROC_TBL) { /* Hash with Segment Tables */
/* TODO - Not Supported */
}
} else { /* Deregister current process table */
- /* Set to benign value: (current GR) | 0. This allows
- * deregistration in KVM to succeed even if the radix bit in flags
- * doesn't match the radix bit in the old PATB. */
- cproc = spapr->patb_entry & PATBE1_GR;
+ /*
+ * Set to benign value: (current GR) | 0. This allows
+ * deregistration in KVM to succeed even if the radix bit
+ * in flags doesn't match the radix bit in the old PATE.
+ */
+ cproc = spapr->patb_entry & PATE1_GR;
}
} else { /* Maintain current registration */
- if (!(flags & FLAG_RADIX) != !(spapr->patb_entry & PATBE1_GR)) {
+ if (!(flags & FLAG_RADIX) != !(spapr->patb_entry & PATE1_GR)) {
/* Technically caused by flag bits => H_PARAMETER */
return H_PARAMETER; /* Existing Process Table Mismatch */
}
spapr->patb_entry = cproc; /* Save new process table */
- /* Update the UPRT and GTSE bits in the LPCR for all cpus */
- CPU_FOREACH(cs) {
- set_spr(cs, SPR_LPCR,
- ((flags & (FLAG_RADIX | FLAG_HASH_PROC_TBL)) ? LPCR_UPRT : 0) |
- ((flags & FLAG_GTSE) ? LPCR_GTSE : 0),
- LPCR_UPRT | LPCR_GTSE);
- }
+ /* Update the UPRT, HR and GTSE bits in the LPCR for all cpus */
+ if (flags & FLAG_RADIX) /* Radix must use process tables, also set HR */
+ update_lpcr |= (LPCR_UPRT | LPCR_HR);
+ else if (flags & FLAG_HASH_PROC_TBL) /* Hash with process tables */
+ update_lpcr |= LPCR_UPRT;
+ if (flags & FLAG_GTSE) /* Guest translation shootdown enable */
+ update_lpcr |= LPCR_GTSE;
+
+ spapr_set_all_lpcrs(update_lpcr, LPCR_UPRT | LPCR_HR | LPCR_GTSE);
if (kvm_enabled()) {
return kvmppc_configure_v3_mmu(cpu, flags & FLAG_RADIX,
#define H_SIGNAL_SYS_RESET_ALLBUTSELF -2
static target_ulong h_signal_sys_reset(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
target_long target = args[0];
}
}
-static uint32_t cas_check_pvr(sPAPRMachineState *spapr, PowerPCCPU *cpu,
+static uint32_t cas_check_pvr(SpaprMachineState *spapr, PowerPCCPU *cpu,
target_ulong *addr, bool *raw_mode_supported,
Error **errp)
{
}
static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
target_ulong addr = ppc64_phys_to_real(args[0]);
target_ulong ov_table;
uint32_t cas_pvr;
- sPAPROptionVector *ov1_guest, *ov5_guest, *ov5_cas_old, *ov5_updates;
+ SpaprOptionVector *ov1_guest, *ov5_guest, *ov5_cas_old, *ov5_updates;
bool guest_radix;
Error *local_err = NULL;
bool raw_mode_supported = false;
+ bool guest_xive;
cas_pvr = cas_check_pvr(spapr, cpu, &addr, &raw_mode_supported, &local_err);
if (local_err) {
error_report_err(local_err);
return H_HARDWARE;
}
+ error_free(local_err);
local_err = NULL;
}
}
error_report("guest requested hash and radix MMU, which is invalid.");
exit(EXIT_FAILURE);
}
+ if (spapr_ovec_test(ov5_guest, OV5_XIVE_BOTH)) {
+ error_report("guest requested an invalid interrupt mode");
+ exit(EXIT_FAILURE);
+ }
+
/* The radix/hash bit in byte 24 requires special handling: */
guest_radix = spapr_ovec_test(ov5_guest, OV5_MMU_RADIX_300);
spapr_ovec_clear(ov5_guest, OV5_MMU_RADIX_300);
+ guest_xive = spapr_ovec_test(ov5_guest, OV5_XIVE_EXPLOIT);
+
/*
* HPT resizing is a bit of a special case, because when enabled
* we assume an HPT guest will support it until it says it
if (!spapr->cas_reboot) {
/* If spapr_machine_reset() did not set up a HPT but one is necessary
* (because the guest isn't going to use radix) then set it up here. */
- if ((spapr->patb_entry & PATBE1_GR) && !guest_radix) {
+ if ((spapr->patb_entry & PATE1_GR) && !guest_radix) {
/* legacy hash or new hash: */
spapr_setup_hpt_and_vrma(spapr);
}
(spapr_h_cas_compose_response(spapr, args[1], args[2],
ov5_updates) != 0);
}
+
+ /*
+ * Ensure the guest asks for an interrupt mode we support; otherwise
+ * terminate the boot.
+ */
+ if (guest_xive) {
+ if (spapr->irq->ov5 == SPAPR_OV5_XIVE_LEGACY) {
+ error_report(
+"Guest requested unavailable interrupt mode (XIVE), try the ic-mode=xive or ic-mode=dual machine property");
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ if (spapr->irq->ov5 == SPAPR_OV5_XIVE_EXPLOIT) {
+ error_report(
+"Guest requested unavailable interrupt mode (XICS), either don't set the ic-mode machine property or try ic-mode=xics or ic-mode=dual");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /*
+ * Generate a machine reset when we have an update of the
+ * interrupt mode. Only required when the machine supports both
+ * modes.
+ */
+ if (!spapr->cas_reboot) {
+ spapr->cas_reboot = spapr_ovec_test(ov5_updates, OV5_XIVE_EXPLOIT)
+ && spapr->irq->ov5 & SPAPR_OV5_XIVE_BOTH;
+ }
+
spapr_ovec_cleanup(ov5_updates);
if (spapr->cas_reboot) {
return H_SUCCESS;
}
+static target_ulong h_home_node_associativity(PowerPCCPU *cpu,
+ SpaprMachineState *spapr,
+ target_ulong opcode,
+ target_ulong *args)
+{
+ target_ulong flags = args[0];
+ target_ulong procno = args[1];
+ PowerPCCPU *tcpu;
+ int idx;
+
+ /* only support procno from H_REGISTER_VPA */
+ if (flags != 0x1) {
+ return H_FUNCTION;
+ }
+
+ tcpu = spapr_find_cpu(procno);
+ if (tcpu == NULL) {
+ return H_P2;
+ }
+
+ /* sequence is the same as in the "ibm,associativity" property */
+
+ idx = 0;
+#define ASSOCIATIVITY(a, b) (((uint64_t)(a) << 32) | \
+ ((uint64_t)(b) & 0xffffffff))
+ args[idx++] = ASSOCIATIVITY(0, 0);
+ args[idx++] = ASSOCIATIVITY(0, tcpu->node_id);
+ args[idx++] = ASSOCIATIVITY(procno, -1);
+ for ( ; idx < 6; idx++) {
+ args[idx] = -1;
+ }
+#undef ASSOCIATIVITY
+
+ return H_SUCCESS;
+}
+
static target_ulong h_get_cpu_characteristics(PowerPCCPU *cpu,
- sPAPRMachineState *spapr,
+ SpaprMachineState *spapr,
target_ulong opcode,
target_ulong *args)
{
uint8_t safe_cache = spapr_get_cap(spapr, SPAPR_CAP_CFPC);
uint8_t safe_bounds_check = spapr_get_cap(spapr, SPAPR_CAP_SBBC);
uint8_t safe_indirect_branch = spapr_get_cap(spapr, SPAPR_CAP_IBS);
+ uint8_t count_cache_flush_assist = spapr_get_cap(spapr,
+ SPAPR_CAP_CCF_ASSIST);
switch (safe_cache) {
case SPAPR_CAP_WORKAROUND:
}
switch (safe_indirect_branch) {
- case SPAPR_CAP_FIXED:
+ case SPAPR_CAP_FIXED_NA:
+ break;
+ case SPAPR_CAP_FIXED_CCD:
+ characteristics |= H_CPU_CHAR_CACHE_COUNT_DIS;
+ break;
+ case SPAPR_CAP_FIXED_IBS:
characteristics |= H_CPU_CHAR_BCCTRL_SERIALISED;
break;
+ case SPAPR_CAP_WORKAROUND:
+ behaviour |= H_CPU_BEHAV_FLUSH_COUNT_CACHE;
+ if (count_cache_flush_assist) {
+ characteristics |= H_CPU_CHAR_BCCTR_FLUSH_ASSIST;
+ }
+ break;
default: /* broken */
assert(safe_indirect_branch == SPAPR_CAP_BROKEN);
break;
args[0] = characteristics;
args[1] = behaviour;
+ return H_SUCCESS;
+}
+
+static target_ulong h_update_dt(PowerPCCPU *cpu, SpaprMachineState *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ target_ulong dt = ppc64_phys_to_real(args[0]);
+ struct fdt_header hdr = { 0 };
+ unsigned cb;
+ SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
+ void *fdt;
+
+ cpu_physical_memory_read(dt, &hdr, sizeof(hdr));
+ cb = fdt32_to_cpu(hdr.totalsize);
+
+ if (!smc->update_dt_enabled) {
+ return H_SUCCESS;
+ }
+
+ /* Check that the fdt did not grow out of proportion */
+ if (cb > spapr->fdt_initial_size * 2) {
+ trace_spapr_update_dt_failed_size(spapr->fdt_initial_size, cb,
+ fdt32_to_cpu(hdr.magic));
+ return H_PARAMETER;
+ }
+
+ fdt = g_malloc0(cb);
+ cpu_physical_memory_read(dt, fdt, cb);
+
+ /* Check the fdt consistency */
+ if (fdt_check_full(fdt, cb)) {
+ trace_spapr_update_dt_failed_check(spapr->fdt_initial_size, cb,
+ fdt32_to_cpu(hdr.magic));
+ return H_PARAMETER;
+ }
+
+ g_free(spapr->fdt_blob);
+ spapr->fdt_size = cb;
+ spapr->fdt_blob = fdt;
+ trace_spapr_update_dt(cb);
return H_SUCCESS;
}
target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
target_ulong *args)
{
- sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
+ SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
if ((opcode <= MAX_HCALL_OPCODE)
&& ((opcode & 0x3) == 0)) {
/* ibm,client-architecture-support support */
spapr_register_hypercall(KVMPPC_H_CAS, h_client_architecture_support);
+
+ spapr_register_hypercall(KVMPPC_H_UPDATE_DT, h_update_dt);
+
+ /* Virtual Processor Home Node */
+ spapr_register_hypercall(H_HOME_NODE_ASSOCIATIVITY,
+ h_home_node_associativity);
}
type_init(hypercall_register_types)