ppc/hash64: Rework R and C bit updates
With MT-TCG, we are now running translation in a racy way, thus we need to mimic hardware when it comes to updating the R and C bits, by doing byte stores. The current "store_hpte" abstraction is ill suited for this, we replace it with two separate callbacks for setting R and C. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Cédric Le Goater <clg@kaod.org> Message-Id: <20190411080004.8690-4-clg@kaod.org> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
parent
993aaf0c00
commit
a2dd4e83e7
@ -1520,10 +1520,10 @@ static void spapr_unmap_hptes(PPCVirtualHypervisor *vhyp,
|
|||||||
/* Nothing to do for qemu managed HPT */
|
/* Nothing to do for qemu managed HPT */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spapr_store_hpte(PPCVirtualHypervisor *vhyp, hwaddr ptex,
|
void spapr_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
|
||||||
uint64_t pte0, uint64_t pte1)
|
uint64_t pte0, uint64_t pte1)
|
||||||
{
|
{
|
||||||
SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
|
SpaprMachineState *spapr = SPAPR_MACHINE(cpu->vhyp);
|
||||||
hwaddr offset = ptex * HASH_PTE_SIZE_64;
|
hwaddr offset = ptex * HASH_PTE_SIZE_64;
|
||||||
|
|
||||||
if (!spapr->htab) {
|
if (!spapr->htab) {
|
||||||
@ -1551,6 +1551,38 @@ static void spapr_store_hpte(PPCVirtualHypervisor *vhyp, hwaddr ptex,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void spapr_hpte_set_c(PPCVirtualHypervisor *vhyp, hwaddr ptex,
|
||||||
|
uint64_t pte1)
|
||||||
|
{
|
||||||
|
hwaddr offset = ptex * HASH_PTE_SIZE_64 + 15;
|
||||||
|
SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
|
||||||
|
|
||||||
|
if (!spapr->htab) {
|
||||||
|
/* There should always be a hash table when this is called */
|
||||||
|
error_report("spapr_hpte_set_c called with no hash table !");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The HW performs a non-atomic byte update */
|
||||||
|
stb_p(spapr->htab + offset, (pte1 & 0xff) | 0x80);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spapr_hpte_set_r(PPCVirtualHypervisor *vhyp, hwaddr ptex,
|
||||||
|
uint64_t pte1)
|
||||||
|
{
|
||||||
|
hwaddr offset = ptex * HASH_PTE_SIZE_64 + 14;
|
||||||
|
SpaprMachineState *spapr = SPAPR_MACHINE(vhyp);
|
||||||
|
|
||||||
|
if (!spapr->htab) {
|
||||||
|
/* There should always be a hash table when this is called */
|
||||||
|
error_report("spapr_hpte_set_r called with no hash table !");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The HW performs a non-atomic byte update */
|
||||||
|
stb_p(spapr->htab + offset, ((pte1 >> 8) & 0xff) | 0x01);
|
||||||
|
}
|
||||||
|
|
||||||
int spapr_hpt_shift_for_ramsize(uint64_t ramsize)
|
int spapr_hpt_shift_for_ramsize(uint64_t ramsize)
|
||||||
{
|
{
|
||||||
int shift;
|
int shift;
|
||||||
@ -4291,7 +4323,8 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
|
|||||||
vhc->hpt_mask = spapr_hpt_mask;
|
vhc->hpt_mask = spapr_hpt_mask;
|
||||||
vhc->map_hptes = spapr_map_hptes;
|
vhc->map_hptes = spapr_map_hptes;
|
||||||
vhc->unmap_hptes = spapr_unmap_hptes;
|
vhc->unmap_hptes = spapr_unmap_hptes;
|
||||||
vhc->store_hpte = spapr_store_hpte;
|
vhc->hpte_set_c = spapr_hpte_set_c;
|
||||||
|
vhc->hpte_set_r = spapr_hpte_set_r;
|
||||||
vhc->get_pate = spapr_get_pate;
|
vhc->get_pate = spapr_get_pate;
|
||||||
vhc->encode_hpt_for_kvm_pr = spapr_encode_hpt_for_kvm_pr;
|
vhc->encode_hpt_for_kvm_pr = spapr_encode_hpt_for_kvm_pr;
|
||||||
xic->ics_get = spapr_ics_get;
|
xic->ics_get = spapr_ics_get;
|
||||||
|
@ -118,7 +118,7 @@ static target_ulong h_enter(PowerPCCPU *cpu, SpaprMachineState *spapr,
|
|||||||
ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
|
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;
|
args[0] = ptex + slot;
|
||||||
return H_SUCCESS;
|
return H_SUCCESS;
|
||||||
@ -131,7 +131,8 @@ typedef enum {
|
|||||||
REMOVE_HW = 3,
|
REMOVE_HW = 3,
|
||||||
} RemoveResult;
|
} RemoveResult;
|
||||||
|
|
||||||
static RemoveResult remove_hpte(PowerPCCPU *cpu, target_ulong ptex,
|
static RemoveResult remove_hpte(PowerPCCPU *cpu
|
||||||
|
, target_ulong ptex,
|
||||||
target_ulong avpn,
|
target_ulong avpn,
|
||||||
target_ulong flags,
|
target_ulong flags,
|
||||||
target_ulong *vp, target_ulong *rp)
|
target_ulong *vp, target_ulong *rp)
|
||||||
@ -155,7 +156,7 @@ static RemoveResult remove_hpte(PowerPCCPU *cpu, target_ulong ptex,
|
|||||||
}
|
}
|
||||||
*vp = v;
|
*vp = v;
|
||||||
*rp = r;
|
*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);
|
ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r);
|
||||||
return REMOVE_SUCCESS;
|
return REMOVE_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -289,13 +290,13 @@ static target_ulong h_protect(PowerPCCPU *cpu, SpaprMachineState *spapr,
|
|||||||
r |= (flags << 55) & HPTE64_R_PP0;
|
r |= (flags << 55) & HPTE64_R_PP0;
|
||||||
r |= (flags << 48) & HPTE64_R_KEY_HI;
|
r |= (flags << 48) & HPTE64_R_KEY_HI;
|
||||||
r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
|
r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
|
||||||
ppc_hash64_store_hpte(cpu, ptex,
|
spapr_store_hpte(cpu, ptex,
|
||||||
(v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0);
|
(v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0);
|
||||||
ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r);
|
ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r);
|
||||||
/* Flush the tlb */
|
/* Flush the tlb */
|
||||||
check_tlb_flush(env, true);
|
check_tlb_flush(env, true);
|
||||||
/* Don't need a memory barrier, due to qemu's global lock */
|
/* 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;
|
return H_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -784,6 +784,8 @@ void spapr_reallocate_hpt(SpaprMachineState *spapr, int shift,
|
|||||||
Error **errp);
|
Error **errp);
|
||||||
void spapr_clear_pending_events(SpaprMachineState *spapr);
|
void spapr_clear_pending_events(SpaprMachineState *spapr);
|
||||||
int spapr_max_server_number(SpaprMachineState *spapr);
|
int spapr_max_server_number(SpaprMachineState *spapr);
|
||||||
|
void spapr_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
|
||||||
|
uint64_t pte0, uint64_t pte1);
|
||||||
|
|
||||||
/* DRC callbacks. */
|
/* DRC callbacks. */
|
||||||
void spapr_core_release(DeviceState *dev);
|
void spapr_core_release(DeviceState *dev);
|
||||||
|
@ -1265,8 +1265,8 @@ struct PPCVirtualHypervisorClass {
|
|||||||
void (*unmap_hptes)(PPCVirtualHypervisor *vhyp,
|
void (*unmap_hptes)(PPCVirtualHypervisor *vhyp,
|
||||||
const ppc_hash_pte64_t *hptes,
|
const ppc_hash_pte64_t *hptes,
|
||||||
hwaddr ptex, int n);
|
hwaddr ptex, int n);
|
||||||
void (*store_hpte)(PPCVirtualHypervisor *vhyp, hwaddr ptex,
|
void (*hpte_set_c)(PPCVirtualHypervisor *vhyp, hwaddr ptex, uint64_t pte1);
|
||||||
uint64_t pte0, uint64_t pte1);
|
void (*hpte_set_r)(PPCVirtualHypervisor *vhyp, hwaddr ptex, uint64_t pte1);
|
||||||
void (*get_pate)(PPCVirtualHypervisor *vhyp, ppc_v3_pate_t *entry);
|
void (*get_pate)(PPCVirtualHypervisor *vhyp, ppc_v3_pate_t *entry);
|
||||||
target_ulong (*encode_hpt_for_kvm_pr)(PPCVirtualHypervisor *vhyp);
|
target_ulong (*encode_hpt_for_kvm_pr)(PPCVirtualHypervisor *vhyp);
|
||||||
};
|
};
|
||||||
|
@ -725,6 +725,39 @@ static void ppc_hash64_set_dsi(CPUState *cs, uint64_t dar, uint64_t dsisr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ppc_hash64_set_r(PowerPCCPU *cpu, hwaddr ptex, uint64_t pte1)
|
||||||
|
{
|
||||||
|
hwaddr base, offset = ptex * HASH_PTE_SIZE_64 + 16;
|
||||||
|
|
||||||
|
if (cpu->vhyp) {
|
||||||
|
PPCVirtualHypervisorClass *vhc =
|
||||||
|
PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
|
||||||
|
vhc->hpte_set_r(cpu->vhyp, ptex, pte1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
base = ppc_hash64_hpt_base(cpu);
|
||||||
|
|
||||||
|
|
||||||
|
/* The HW performs a non-atomic byte update */
|
||||||
|
stb_phys(CPU(cpu)->as, base + offset, ((pte1 >> 8) & 0xff) | 0x01);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ppc_hash64_set_c(PowerPCCPU *cpu, hwaddr ptex, uint64_t pte1)
|
||||||
|
{
|
||||||
|
hwaddr base, offset = ptex * HASH_PTE_SIZE_64 + 15;
|
||||||
|
|
||||||
|
if (cpu->vhyp) {
|
||||||
|
PPCVirtualHypervisorClass *vhc =
|
||||||
|
PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
|
||||||
|
vhc->hpte_set_c(cpu->vhyp, ptex, pte1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
base = ppc_hash64_hpt_base(cpu);
|
||||||
|
|
||||||
|
/* The HW performs a non-atomic byte update */
|
||||||
|
stb_phys(CPU(cpu)->as, base + offset, (pte1 & 0xff) | 0x80);
|
||||||
|
}
|
||||||
|
|
||||||
int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
|
int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
|
||||||
int rwx, int mmu_idx)
|
int rwx, int mmu_idx)
|
||||||
{
|
{
|
||||||
@ -735,7 +768,6 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
|
|||||||
hwaddr ptex;
|
hwaddr ptex;
|
||||||
ppc_hash_pte64_t pte;
|
ppc_hash_pte64_t pte;
|
||||||
int exec_prot, pp_prot, amr_prot, prot;
|
int exec_prot, pp_prot, amr_prot, prot;
|
||||||
uint64_t new_pte1;
|
|
||||||
const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
|
const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
|
||||||
hwaddr raddr;
|
hwaddr raddr;
|
||||||
|
|
||||||
@ -883,9 +915,12 @@ skip_slb_search:
|
|||||||
|
|
||||||
/* 6. Update PTE referenced and changed bits if necessary */
|
/* 6. Update PTE referenced and changed bits if necessary */
|
||||||
|
|
||||||
new_pte1 = pte.pte1 | HPTE64_R_R; /* set referenced bit */
|
if (!(pte.pte1 & HPTE64_R_R)) {
|
||||||
|
ppc_hash64_set_r(cpu, ptex, pte.pte1);
|
||||||
|
}
|
||||||
|
if (!(pte.pte1 & HPTE64_R_C)) {
|
||||||
if (rwx == 1) {
|
if (rwx == 1) {
|
||||||
new_pte1 |= HPTE64_R_C; /* set changed (dirty) bit */
|
ppc_hash64_set_c(cpu, ptex, pte.pte1);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Treat the page as read-only for now, so that a later write
|
* Treat the page as read-only for now, so that a later write
|
||||||
@ -893,9 +928,6 @@ skip_slb_search:
|
|||||||
*/
|
*/
|
||||||
prot &= ~PAGE_WRITE;
|
prot &= ~PAGE_WRITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_pte1 != pte.pte1) {
|
|
||||||
ppc_hash64_store_hpte(cpu, ptex, pte.pte0, new_pte1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 7. Determine the real address from the PTE */
|
/* 7. Determine the real address from the PTE */
|
||||||
@ -954,24 +986,6 @@ hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr)
|
|||||||
& TARGET_PAGE_MASK;
|
& TARGET_PAGE_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ppc_hash64_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
|
|
||||||
uint64_t pte0, uint64_t pte1)
|
|
||||||
{
|
|
||||||
hwaddr base;
|
|
||||||
hwaddr offset = ptex * HASH_PTE_SIZE_64;
|
|
||||||
|
|
||||||
if (cpu->vhyp) {
|
|
||||||
PPCVirtualHypervisorClass *vhc =
|
|
||||||
PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
|
|
||||||
vhc->store_hpte(cpu->vhyp, ptex, pte0, pte1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
base = ppc_hash64_hpt_base(cpu);
|
|
||||||
|
|
||||||
stq_phys(CPU(cpu)->as, base + offset, pte0);
|
|
||||||
stq_phys(CPU(cpu)->as, base + offset + HASH_PTE_SIZE_64 / 2, pte1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu, target_ulong ptex,
|
void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu, target_ulong ptex,
|
||||||
target_ulong pte0, target_ulong pte1)
|
target_ulong pte0, target_ulong pte1)
|
||||||
{
|
{
|
||||||
|
@ -10,8 +10,6 @@ int ppc_store_slb(PowerPCCPU *cpu, target_ulong slot,
|
|||||||
hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr);
|
hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr);
|
||||||
int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr address, int rw,
|
int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr address, int rw,
|
||||||
int mmu_idx);
|
int mmu_idx);
|
||||||
void ppc_hash64_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
|
|
||||||
uint64_t pte0, uint64_t pte1);
|
|
||||||
void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu,
|
void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu,
|
||||||
target_ulong pte_index,
|
target_ulong pte_index,
|
||||||
target_ulong pte0, target_ulong pte1);
|
target_ulong pte0, target_ulong pte1);
|
||||||
|
Loading…
Reference in New Issue
Block a user