From 7f82aa3d60a1ca0f0b35435d42f875ff1f1bfe0b Mon Sep 17 00:00:00 2001 From: Andreas Sandberg Date: Wed, 16 May 2018 15:27:32 +0100 Subject: arch-arm: Fix page size handling when merging stage 1 and 2 The current code to merge translation entries from stage 1 and stage 2 doesn't handle cases where the page sizes at the different stages differ. This change fixes both the case when the hypervisor has a larger page size and when it has a smaller page size. Change-Id: Icdf289005bf1e4de4d91d54643924a38d9d77796 Signed-off-by: Andreas Sandberg Reviewed-by: Giacomo Travaglini Reviewed-on: https://gem5-review.googlesource.com/10505 Maintainer: Giacomo Travaglini --- src/arch/arm/stage2_lookup.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/arch/arm/stage2_lookup.cc b/src/arch/arm/stage2_lookup.cc index 82a29e84f..00c515df5 100644 --- a/src/arch/arm/stage2_lookup.cc +++ b/src/arch/arm/stage2_lookup.cc @@ -88,23 +88,24 @@ Stage2LookUp::mergeTe(RequestPtr req, BaseTLB::Mode mode) // Now we have the table entries for both stages of translation // merge them and insert the result into the stage 1 TLB. See // CombineS1S2Desc() in pseudocode - stage1Te.N = stage2Te->N; stage1Te.nonCacheable |= stage2Te->nonCacheable; stage1Te.xn |= stage2Te->xn; if (stage1Te.size > stage2Te->size) { // Size mismatch also implies vpn mismatch (this is shifted by // sizebits!). - stage1Te.vpn = s1Req->getVaddr() / (stage2Te->size+1); + stage1Te.vpn = s1Req->getVaddr() >> stage2Te->N; stage1Te.pfn = stage2Te->pfn; stage1Te.size = stage2Te->size; + stage1Te.N = stage2Te->N; } else if (stage1Te.size < stage2Te->size) { // Guest 4K could well be section-backed by host hugepage! In this // case a 4K entry is added but pfn needs to be adjusted. New PFN = // offset into section PFN given by stage2 IPA treated as a stage1 // page size. - stage1Te.pfn = (stage2Te->pfn * ((stage2Te->size+1) / (stage1Te.size+1))) + - (stage2Te->vpn / (stage1Te.size+1)); + const Addr pa = (stage2Te->pfn << stage2Te->N); + const Addr ipa = (stage1Te.pfn << stage1Te.N); + stage1Te.pfn = (pa | (ipa & mask(stage2Te->N))) >> stage1Te.N; // Size remains smaller of the two. } else { // Matching sizes -- cgit v1.2.3