target/arm: Correctly handle overlapping small MPU regions
To correctly handle small (less than TARGET_PAGE_SIZE) MPU regions, we must correctly handle the case where the address being looked up hits in an MPU region that is not small but the address is in the same page as a small region. For instance if MPU region 1 covers an entire page from 0x2000 to 0x2400 and MPU region 2 is small and covers only 0x2200 to 0x2280, then for an access to 0x2000 we must not return a result covering the full page even though we hit the page-sized region 1. Otherwise we will then cache that result in the TLB and accesses that should hit region 2 will incorrectly find the region 1 information. Check for the case where we miss an MPU region but it is still within the same page, and in that case narrow the size we will pass to tlb_set_page_with_attrs() for whatever the final outcome is of the MPU lookup. Reported-by: Adithya Baglody <adithya.nagaraj.baglody@intel.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20180716133302.25989-1-peter.maydell@linaro.org
This commit is contained in:
parent
03a31776e8
commit
9d2b5a58f8
@ -17,6 +17,7 @@
|
||||
#include "exec/semihost.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "fpu/softfloat.h"
|
||||
#include "qemu/range.h"
|
||||
|
||||
#define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */
|
||||
|
||||
@ -9669,6 +9670,20 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address,
|
||||
}
|
||||
|
||||
if (address < base || address > base + rmask) {
|
||||
/*
|
||||
* Address not in this region. We must check whether the
|
||||
* region covers addresses in the same page as our address.
|
||||
* In that case we must not report a size that covers the
|
||||
* whole page for a subsequent hit against a different MPU
|
||||
* region or the background region, because it would result in
|
||||
* incorrect TLB hits for subsequent accesses to addresses that
|
||||
* are in this MPU region.
|
||||
*/
|
||||
if (ranges_overlap(base, rmask,
|
||||
address & TARGET_PAGE_MASK,
|
||||
TARGET_PAGE_SIZE)) {
|
||||
*page_size = 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -9888,6 +9903,22 @@ static void v8m_security_lookup(CPUARMState *env, uint32_t address,
|
||||
sattrs->srvalid = true;
|
||||
sattrs->sregion = r;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Address not in this region. We must check whether the
|
||||
* region covers addresses in the same page as our address.
|
||||
* In that case we must not report a size that covers the
|
||||
* whole page for a subsequent hit against a different MPU
|
||||
* region or the background region, because it would result
|
||||
* in incorrect TLB hits for subsequent accesses to
|
||||
* addresses that are in this MPU region.
|
||||
*/
|
||||
if (limit >= base &&
|
||||
ranges_overlap(base, limit - base + 1,
|
||||
addr_page_base,
|
||||
TARGET_PAGE_SIZE)) {
|
||||
sattrs->subpage = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9963,6 +9994,21 @@ static bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
|
||||
}
|
||||
|
||||
if (address < base || address > limit) {
|
||||
/*
|
||||
* Address not in this region. We must check whether the
|
||||
* region covers addresses in the same page as our address.
|
||||
* In that case we must not report a size that covers the
|
||||
* whole page for a subsequent hit against a different MPU
|
||||
* region or the background region, because it would result in
|
||||
* incorrect TLB hits for subsequent accesses to addresses that
|
||||
* are in this MPU region.
|
||||
*/
|
||||
if (limit >= base &&
|
||||
ranges_overlap(base, limit - base + 1,
|
||||
addr_page_base,
|
||||
TARGET_PAGE_SIZE)) {
|
||||
*is_subpage = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user