summaryrefslogtreecommitdiffstats
path: root/hw/ppc/spapr.c
diff options
context:
space:
mode:
authorNicholas Piggin2022-02-18 08:34:14 +0100
committerCédric Le Goater2022-02-18 08:34:14 +0100
commit120f738a4671977481546ff3027232f0c911127d (patch)
tree4e17367bc9a85f66d681be31052e2bc9d270dbc7 /hw/ppc/spapr.c
parenttarget/ppc: Introduce a vhyp framework for nested HV support (diff)
downloadqemu-120f738a4671977481546ff3027232f0c911127d.tar.gz
qemu-120f738a4671977481546ff3027232f0c911127d.tar.xz
qemu-120f738a4671977481546ff3027232f0c911127d.zip
spapr: implement nested-hv capability for the virtual hypervisor
This implements the Nested KVM HV hcall API for spapr under TCG. The L2 is switched in when the H_ENTER_NESTED hcall is made, and the L1 is switched back in returned from the hcall when a HV exception is sent to the vhyp. Register state is copied in and out according to the nested KVM HV hcall API specification. The hdecr timer is started when the L2 is switched in, and it provides the HDEC / 0x980 return to L1. The MMU re-uses the bare metal radix 2-level page table walker by using the get_pate method to point the MMU to the nested partition table entry. MMU faults due to partition scope errors raise HV exceptions and accordingly are routed back to the L1. The MMU does not tag translations for the L1 (direct) vs L2 (nested) guests, so the TLB is flushed on any L1<->L2 transition (hcall entry and exit). Reviewed-by: Fabiano Rosas <farosas@linux.ibm.com> Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Reviewed-by: Cédric Le Goater <clg@kaod.org> [ clg: checkpatch fixes ] Message-Id: <20220216102545.1808018-10-npiggin@gmail.com> Signed-off-by: Cédric Le Goater <clg@kaod.org>
Diffstat (limited to 'hw/ppc/spapr.c')
-rw-r--r--hw/ppc/spapr.c37
1 files changed, 32 insertions, 5 deletions
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 51ba8615f2..f0b75b22bb 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1270,6 +1270,8 @@ static void emulate_spapr_hypercall(PPCVirtualHypervisor *vhyp,
/* The TCG path should also be holding the BQL at this point */
g_assert(qemu_mutex_iothread_locked());
+ g_assert(!vhyp_cpu_in_nested(cpu));
+
if (msr_pr) {
hcall_dprintf("Hypercall made with MSR[PR]=1\n");
env->gpr[3] = H_PRIVILEGE;
@@ -1313,12 +1315,34 @@ static bool spapr_get_pate(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu,
target_ulong lpid, ppc_v3_pate_t *entry)
{
SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
- assert(lpid == 0);
+ if (!spapr_cpu->in_nested) {
+ assert(lpid == 0);
- /* Copy PATE1:GR into PATE0:HR */
- entry->dw0 = spapr->patb_entry & PATE0_HR;
- entry->dw1 = spapr->patb_entry;
+ /* Copy PATE1:GR into PATE0:HR */
+ entry->dw0 = spapr->patb_entry & PATE0_HR;
+ entry->dw1 = spapr->patb_entry;
+
+ } else {
+ uint64_t patb, pats;
+
+ assert(lpid != 0);
+
+ patb = spapr->nested_ptcr & PTCR_PATB;
+ pats = spapr->nested_ptcr & PTCR_PATS;
+
+ /* Calculate number of entries */
+ pats = 1ull << (pats + 12 - 4);
+ if (pats <= lpid) {
+ return false;
+ }
+
+ /* Grab entry */
+ patb += 16 * lpid;
+ entry->dw0 = ldq_phys(CPU(cpu)->as, patb);
+ entry->dw1 = ldq_phys(CPU(cpu)->as, patb + 8);
+ }
return true;
}
@@ -4474,7 +4498,9 @@ PowerPCCPU *spapr_find_cpu(int vcpu_id)
static bool spapr_cpu_in_nested(PowerPCCPU *cpu)
{
- return false;
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
+
+ return spapr_cpu->in_nested;
}
static void spapr_cpu_exec_enter(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
@@ -4586,6 +4612,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
nc->nmi_monitor_handler = spapr_nmi;
smc->phb_placement = spapr_phb_placement;
vhc->cpu_in_nested = spapr_cpu_in_nested;
+ vhc->deliver_hv_excp = spapr_exit_nested;
vhc->hypercall = emulate_spapr_hypercall;
vhc->hpt_mask = spapr_hpt_mask;
vhc->map_hptes = spapr_map_hptes;