Merge pull request #5662 from blubberdiblub/improve_mmu_mask_checks

Improve MMU mask checks
This commit is contained in:
Tilka 2017-06-22 20:47:36 +01:00 committed by GitHub
commit 4e39a42e6b
3 changed files with 59 additions and 14 deletions

View file

@ -99,4 +99,26 @@ constexpr Result ExtractBits(const T src) noexcept
return ExtractBits<T, Result>(src, begin, end);
}
///
/// Verifies whether the supplied value is a valid bit mask of the form 0b00...0011...11.
/// Both edge cases of all zeros and all ones are considered valid masks, too.
///
/// @param mask The mask value to test for validity.
///
/// @tparam T The type of the value.
///
/// @return A bool indicating whether the mask is valid.
///
template <typename T>
constexpr bool IsValidLowMask(const T mask) noexcept
{
static_assert(std::is_integral<T>::value, "Mask must be an integral type.");
static_assert(std::is_unsigned<T>::value, "Signed masks can introduce hard to find bugs.");
// Can be efficiently determined without looping or bit counting. It's the counterpart
// to https://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2
// and doesn't require special casing either edge case.
return (mask & (mask + 1)) == 0;
}
} // namespace Common

View file

@ -7,7 +7,7 @@
#include <string>
#include "Common/Atomic.h"
#include "Common/BitSet.h"
#include "Common/BitUtils.h"
#include "Common/CommonTypes.h"
#include "Core/ConfigManager.h"
@ -947,26 +947,17 @@ static void GenerateISIException(u32 _EffectiveAddress)
void SDRUpdated()
{
u32 htabmask = SDR1_HTABMASK(PowerPC::ppcState.spr[SPR_SDR]);
u32 x = 1;
u32 xx = 0;
int n = 0;
while ((htabmask & x) && (n < 9))
{
n++;
xx |= x;
x <<= 1;
}
if (htabmask & ~xx)
if (!Common::IsValidLowMask(htabmask))
{
return;
}
u32 htaborg = SDR1_HTABORG(PowerPC::ppcState.spr[SPR_SDR]);
if (htaborg & xx)
if (htaborg & htabmask)
{
return;
}
PowerPC::ppcState.pagetable_base = htaborg << 16;
PowerPC::ppcState.pagetable_hashmask = ((xx << 10) | 0x3ff);
PowerPC::ppcState.pagetable_hashmask = ((htabmask << 10) | 0x3ff);
}
enum TLBLookupResult
@ -1175,7 +1166,7 @@ static void UpdateBATs(BatTable& bat_table, u32 base_spr)
// implemented this way for invalid BATs as well.
WARN_LOG(POWERPC, "Bad BAT setup: BPRN overlaps BL");
}
if (CountSetBits((u32)(batu.BL + 1)) != 1)
if (!Common::IsValidLowMask((u32)batu.BL))
{
// With a valid BAT, the simplest way of masking is
// (input & ~BL_mask) for matching and (input & BL_mask) for

View file

@ -57,3 +57,35 @@ TEST(BitUtils, ExtractBits)
// Ensure bit extraction with type overriding works as expected
EXPECT_EQ((Common::ExtractBits<0, 31, s32, s32>(negative_one)), -1);
}
TEST(BitUtils, IsValidLowMask)
{
EXPECT_TRUE(Common::IsValidLowMask(0b0u));
EXPECT_TRUE(Common::IsValidLowMask(0b1u));
EXPECT_FALSE(Common::IsValidLowMask(0b10u));
EXPECT_TRUE(Common::IsValidLowMask(0b11u));
EXPECT_FALSE(Common::IsValidLowMask(0b1110u));
EXPECT_TRUE(Common::IsValidLowMask(0b1111u));
EXPECT_FALSE(Common::IsValidLowMask(0b10000u));
EXPECT_FALSE(Common::IsValidLowMask(0b101111u));
EXPECT_TRUE(Common::IsValidLowMask((u8)~0b0));
EXPECT_FALSE(Common::IsValidLowMask((u8)(~0b0 - 1)));
EXPECT_FALSE(Common::IsValidLowMask((u8)~(0b10000)));
EXPECT_FALSE(Common::IsValidLowMask((u8)(~((u8)(~0b0) >> 1) | 0b1111)));
EXPECT_TRUE(Common::IsValidLowMask((u16)~0b0));
EXPECT_FALSE(Common::IsValidLowMask((u16)(~0b0 - 1)));
EXPECT_FALSE(Common::IsValidLowMask((u16)~(0b10000)));
EXPECT_FALSE(Common::IsValidLowMask((u16)(~((u16)(~0b0) >> 1) | 0b1111)));
EXPECT_TRUE(Common::IsValidLowMask((u32)~0b0));
EXPECT_FALSE(Common::IsValidLowMask((u32)(~0b0 - 1)));
EXPECT_FALSE(Common::IsValidLowMask((u32)~(0b10000)));
EXPECT_FALSE(Common::IsValidLowMask((u32)(~((u32)(~0b0) >> 1) | 0b1111)));
EXPECT_TRUE(Common::IsValidLowMask((u64)~0b0));
EXPECT_FALSE(Common::IsValidLowMask((u64)(~0b0 - 1)));
EXPECT_FALSE(Common::IsValidLowMask((u64)~(0b10000)));
EXPECT_FALSE(Common::IsValidLowMask((u64)(~((u64)(~0b0) >> 1) | 0b1111)));
}