mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-15 17:39:28 +00:00
thermosphere: trap set/way dcache access
note: qemu does not implement the trap
This commit is contained in:
parent
72d1992eec
commit
6b8a843ffb
6 changed files with 92 additions and 4 deletions
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include "caches.h"
|
#include "caches.h"
|
||||||
#include "preprocessor.h"
|
#include "preprocessor.h"
|
||||||
|
#include "core_ctx.h"
|
||||||
|
|
||||||
#define DEFINE_CACHE_RANGE_FUNC(isn, name, cache, post)\
|
#define DEFINE_CACHE_RANGE_FUNC(isn, name, cache, post)\
|
||||||
void name(const void *addr, size_t size)\
|
void name(const void *addr, size_t size)\
|
||||||
|
@ -47,14 +48,35 @@ static inline ALINLINE void cacheInvalidateDataCacheLevel(u32 level)
|
||||||
u32 setShift = (ccsidr & 7) + 4;
|
u32 setShift = (ccsidr & 7) + 4;
|
||||||
u32 lbits = (level & 7) << 1;
|
u32 lbits = (level & 7) << 1;
|
||||||
|
|
||||||
for (u32 way = 0; way <= numWays; way++) {
|
for (u32 way = 0; way < numWays; way++) {
|
||||||
for (u32 set = 0; set <= numSets; set++) {
|
for (u32 set = 0; set < numSets; set++) {
|
||||||
u64 val = ((u64)way << wayShift) | ((u64)set << setShift) | lbits;
|
u64 val = ((u64)way << wayShift) | ((u64)set << setShift) | lbits;
|
||||||
__asm__ __volatile__ ("dc isw, %0" :: "r"(val) : "memory");
|
__asm__ __volatile__ ("dc isw, %0" :: "r"(val) : "memory");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline ALINLINE void cacheCleanInvalidateDataCacheLevel(u32 level)
|
||||||
|
{
|
||||||
|
cacheSelectByLevel(false, level);
|
||||||
|
u32 ccsidr = (u32)GET_SYSREG(ccsidr_el1);
|
||||||
|
u32 numWays = 1 + ((ccsidr >> 3) & 0x3FF);
|
||||||
|
u32 numSets = 1 + ((ccsidr >> 13) & 0x7FFF);
|
||||||
|
u32 wayShift = __builtin_clz(numWays);
|
||||||
|
u32 setShift = (ccsidr & 7) + 4;
|
||||||
|
u32 lbits = (level & 7) << 1;
|
||||||
|
|
||||||
|
for (u32 way = 0; way < numWays; way++) {
|
||||||
|
for (u32 set = 0; set < numSets; set++) {
|
||||||
|
u64 val = ((u64)way << wayShift) | ((u64)set << setShift) | lbits;
|
||||||
|
__asm__ __volatile__ ("dc cisw, %0" :: "r"(val) : "memory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__dsb_sy();
|
||||||
|
__isb();
|
||||||
|
}
|
||||||
|
|
||||||
static inline ALINLINE void cacheInvalidateDataCacheLevels(u32 from, u32 to)
|
static inline ALINLINE void cacheInvalidateDataCacheLevels(u32 from, u32 to)
|
||||||
{
|
{
|
||||||
// Let's hope it doesn't generate a stack frame...
|
// Let's hope it doesn't generate a stack frame...
|
||||||
|
@ -97,3 +119,48 @@ void cacheClearLocalDataCacheOnBoot(void)
|
||||||
u32 louis = (clidr >> 21) & 7;
|
u32 louis = (clidr >> 21) & 7;
|
||||||
cacheInvalidateDataCacheLevels(0, louis);
|
cacheInvalidateDataCacheLevels(0, louis);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Ok so:
|
||||||
|
- cache set/way ops can't really be virtualized
|
||||||
|
- since we have only one guest OS & don't care about security (for space limitations),
|
||||||
|
we do the following:
|
||||||
|
- ignore all cache s/w ops applying before the Level Of Unification Inner Shareable (L1, typically).
|
||||||
|
These clearly break coherency and should only be done once, on power on/off/suspend/resume only. And we already
|
||||||
|
do it ourselves...
|
||||||
|
- allow ops after the LoUIS, but do it ourselves and ignore the next (numSets*numWay - 1) requests. This is because
|
||||||
|
we have to handle Nintendo's dodgy code
|
||||||
|
- ignore "invalidate only" ops by the guest. Should only be done on power on/resume and we already did it ourselves...
|
||||||
|
- transform "clean only" into "clean and invalidate"
|
||||||
|
*/
|
||||||
|
void cacheHandleTrappedSetWayOperation(bool invalidateOnly)
|
||||||
|
{
|
||||||
|
DEBUG("hello");
|
||||||
|
if (invalidateOnly) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 clidr = (u32)GET_SYSREG(clidr_el1);
|
||||||
|
u32 louis = (clidr >> 21) & 7;
|
||||||
|
|
||||||
|
u32 csselr = (u32)GET_SYSREG(csselr_el1);
|
||||||
|
u32 level = (csselr >> 1) & 7;
|
||||||
|
if (csselr & BIT(0)) {
|
||||||
|
// Icache, ignore
|
||||||
|
return;
|
||||||
|
} else if (level < louis) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
u32 ccsidr = (u32)GET_SYSREG(ccsidr_el1);
|
||||||
|
u32 numWays = 1 + ((ccsidr >> 3) & 0x3FF);
|
||||||
|
u32 numSets = 1 + ((ccsidr >> 13) & 0x7FFF);
|
||||||
|
if (currentCoreCtx->setWayCounter++ == 0) {
|
||||||
|
cacheCleanInvalidateDataCacheLevel(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentCoreCtx->setWayCounter >= numSets * numWays) {
|
||||||
|
currentCoreCtx->setWayCounter = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -56,3 +56,5 @@ void cacheHandleSelfModifyingCodePoU(const void *addr, size_t size);
|
||||||
|
|
||||||
void cacheClearSharedDataCachesOnBoot(void);
|
void cacheClearSharedDataCachesOnBoot(void);
|
||||||
void cacheClearLocalDataCacheOnBoot(void);
|
void cacheClearLocalDataCacheOnBoot(void);
|
||||||
|
|
||||||
|
void cacheHandleTrappedSetWayOperation(bool invalidateOnly);
|
||||||
|
|
|
@ -41,6 +41,9 @@ typedef struct CoreCtx {
|
||||||
void *executedFunctionArgs; // @0x48
|
void *executedFunctionArgs; // @0x48
|
||||||
Barrier executedFunctionBarrier; // @0x50
|
Barrier executedFunctionBarrier; // @0x50
|
||||||
bool executedFunctionSync; // @0x54
|
bool executedFunctionSync; // @0x54
|
||||||
|
|
||||||
|
// Cache stuff
|
||||||
|
u32 setWayCounter; // @0x58
|
||||||
} CoreCtx;
|
} CoreCtx;
|
||||||
|
|
||||||
static_assert(offsetof(CoreCtx, warmboot) == 0x2E, "Wrong definition for CoreCtx");
|
static_assert(offsetof(CoreCtx, warmboot) == 0x2E, "Wrong definition for CoreCtx");
|
||||||
|
|
|
@ -24,6 +24,10 @@
|
||||||
#define BITL(n) (1ull << (n))
|
#define BITL(n) (1ull << (n))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define TUP_DC_ISW (1, 0, 7, 6, 2)
|
||||||
|
#define TUP_DC_CSW (1, 0, 7, 10, 2)
|
||||||
|
#define TUP_DC_CISW (1, 0, 7, 14, 2)
|
||||||
|
|
||||||
#define TUP_OSDTRRX_EL1 (2, 0, 0, 0, 2)
|
#define TUP_OSDTRRX_EL1 (2, 0, 0, 0, 2)
|
||||||
#define TUP_MDCCINT_EL1 (2, 0, 0, 2, 0)
|
#define TUP_MDCCINT_EL1 (2, 0, 0, 2, 0)
|
||||||
#define TUP_MDSCR_EL1 (2, 0, 0, 2, 2)
|
#define TUP_MDSCR_EL1 (2, 0, 0, 2, 2)
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
#include "sysreg_traps.h"
|
#include "sysreg_traps.h"
|
||||||
#include "guest_timers.h"
|
#include "guest_timers.h"
|
||||||
#include "software_breakpoints.h"
|
#include "caches.h"
|
||||||
|
|
||||||
static inline u64 doSystemRegisterRead(const ExceptionStackFrame *frame, u32 normalizedIss)
|
static inline u64 doSystemRegisterRead(const ExceptionStackFrame *frame, u32 normalizedIss)
|
||||||
{
|
{
|
||||||
|
@ -43,7 +43,7 @@ static inline u64 doSystemRegisterRead(const ExceptionStackFrame *frame, u32 nor
|
||||||
val = currentCoreCtx->emulPtimerCval;
|
val = currentCoreCtx->emulPtimerCval;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// NOTE: We should trap ID_AA64* register to lie to the guest about e.g. MemTag but it would take too much space
|
||||||
default: {
|
default: {
|
||||||
// We shouldn't have trapped on other registers other than debug regs
|
// We shouldn't have trapped on other registers other than debug regs
|
||||||
// and we want the latter as RA0/WI
|
// and we want the latter as RA0/WI
|
||||||
|
@ -74,6 +74,15 @@ static inline void doSystemRegisterWrite(ExceptionStackFrame *frame, u32 normali
|
||||||
writeEmulatedPhysicalCompareValue(frame, val);
|
writeEmulatedPhysicalCompareValue(frame, val);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ENCODE_SYSREG_ISS(DC_CSW):
|
||||||
|
case ENCODE_SYSREG_ISS(DC_CISW): {
|
||||||
|
cacheHandleTrappedSetWayOperation(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ENCODE_SYSREG_ISS(DC_ISW): {
|
||||||
|
cacheHandleTrappedSetWayOperation(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
// We shouldn't have trapped on other registers other than debug regs
|
// We shouldn't have trapped on other registers other than debug regs
|
||||||
|
|
|
@ -44,6 +44,9 @@ void enableTraps(void)
|
||||||
// Trap SMC instructions
|
// Trap SMC instructions
|
||||||
hcr |= HCR_TSC;
|
hcr |= HCR_TSC;
|
||||||
|
|
||||||
|
// Trap set/way isns
|
||||||
|
hcr |= HCR_TSW;
|
||||||
|
|
||||||
// Reroute physical IRQs to EL2
|
// Reroute physical IRQs to EL2
|
||||||
hcr |= HCR_IMO;
|
hcr |= HCR_IMO;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue