From f43e35255cffb6ac6230dd09d308f7909f823f96 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Fri, 1 Apr 2011 15:15:22 +1100 Subject: Virtual hash page table handling on pSeries machine On pSeries logical partitions, excepting the old POWER4-style full system partitions, the guest does not have direct access to the hardware page table. Instead, the pagetable exists in hypervisor memory, and the guest must manipulate it with hypercalls. However, our current pSeries emulation more closely resembles the old style where the guest must set up and handle the pagetables itself. This patch converts it to act like a modern partition. This involves two things: first, the hash translation path is modified to permit the has table to be stored externally to the emulated machine's RAM. The pSeries machine init code configures the CPUs to use this mode. Secondly, we emulate the PAPR hypercalls for manipulating the external hashed page table. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 2 ++ target-ppc/helper.c | 36 ++++++++++++++++++++++++++++-------- 2 files changed, 30 insertions(+), 8 deletions(-) (limited to 'target-ppc') diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 25d0658..b4c2555 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -670,6 +670,8 @@ struct CPUPPCState { target_phys_addr_t htab_base; target_phys_addr_t htab_mask; target_ulong sr[32]; + /* externally stored hash table */ + uint8_t *external_htab; /* BATs */ int nb_BATs; target_ulong DBAT[2][8]; diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 278bee4..5e4030b 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -589,8 +589,13 @@ static inline int _find_pte(CPUState *env, mmu_ctx_t *ctx, int is_64b, int h, for (i = 0; i < 8; i++) { #if defined(TARGET_PPC64) if (is_64b) { - pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16)); - pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8); + if (env->external_htab) { + pte0 = ldq_p(env->external_htab + pteg_off + (i * 16)); + pte1 = ldq_p(env->external_htab + pteg_off + (i * 16) + 8); + } else { + pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16)); + pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8); + } /* We have a TLB that saves 4K pages, so let's * split a huge page to 4k chunks */ @@ -606,8 +611,13 @@ static inline int _find_pte(CPUState *env, mmu_ctx_t *ctx, int is_64b, int h, } else #endif { - pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8)); - pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4); + if (env->external_htab) { + pte0 = ldl_p(env->external_htab + pteg_off + (i * 8)); + pte1 = ldl_p(env->external_htab + pteg_off + (i * 8) + 4); + } else { + pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8)); + pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4); + } r = pte32_check(ctx, pte0, pte1, h, rw, type); LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " " TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n", @@ -647,13 +657,23 @@ static inline int _find_pte(CPUState *env, mmu_ctx_t *ctx, int is_64b, int h, if (pte_update_flags(ctx, &pte1, ret, rw) == 1) { #if defined(TARGET_PPC64) if (is_64b) { - stq_phys_notdirty(env->htab_base + pteg_off + (good * 16) + 8, - pte1); + if (env->external_htab) { + stq_p(env->external_htab + pteg_off + (good * 16) + 8, + pte1); + } else { + stq_phys_notdirty(env->htab_base + pteg_off + + (good * 16) + 8, pte1); + } } else #endif { - stl_phys_notdirty(env->htab_base + pteg_off + (good * 8) + 4, - pte1); + if (env->external_htab) { + stl_p(env->external_htab + pteg_off + (good * 8) + 4, + pte1); + } else { + stl_phys_notdirty(env->htab_base + pteg_off + + (good * 8) + 4, pte1); + } } } } -- cgit v1.1