diff --git a/source/cache.h b/source/cache.h new file mode 100644 index 0000000..5cd225d --- /dev/null +++ b/source/cache.h @@ -0,0 +1,18 @@ +/* +* cache.h +* by TuxSH +*/ + +#pragma once +#include "types.h" + +/*** + The following functions flush the data cache, then waits for all memory transfers to be finished. + The data cache MUST be flushed before doing one of the following: + - rebooting + - powering down + - setting the ARM11 entrypoint to execute a function +***/ + +void flushEntireDCache(void); +void flushDCacheRange(void *startAddress, u32 size); \ No newline at end of file diff --git a/source/cache.s b/source/cache.s new file mode 100644 index 0000000..f7af2bc --- /dev/null +++ b/source/cache.s @@ -0,0 +1,51 @@ +@ +@ cache.s +@ by TuxSH +@ +@ This is part of Luma3DS, see LICENSE.txt for details +@ + +.text +.arm +.align 4 + +.global flushEntireDCache +.type flushEntireDCache, %function +flushEntireDCache: + @ Adpated from http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0155a/ch03s03s05.html , + @ and https://github.com/gemarcano/libctr9_io/blob/master/src/ctr_system_ARM.c#L39 as well + @ Note: ARM's example is actually for a 8KB DCache (which is what the 3DS has) + + mov r1, #0 @ segment counter + outer_loop: + mov r0, #0 @ line counter + + inner_loop: + orr r2, r1, r0 @ generate segment and line address + mcr p15, 0, r2, c7, c14, 2 @ clean and flush the line + add r0, #0x20 @ increment to next line + cmp r0, #0x400 + bne inner_loop + + add r1, #0x40000000 + cmp r1, #0 + bne outer_loop + + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer + bx lr + +.global flushDCacheRange +.type flushDCacheRange, %function +flushDCacheRange: + add r1, r0, r1 @ end address + bic r0, #0x1f @ align source address to cache line size (32 bytes) + + flush_range_loop: + mcr p15, 0, r0, c7, c14, 1 @ clean and flush the line corresponding to the address r0 is holding + add r0, #0x20 + cmp r0, r1 + bls flush_range_loop + + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer + bx lr + \ No newline at end of file diff --git a/source/firm.c b/source/firm.c index a09454b..95ad043 100755 --- a/source/firm.c +++ b/source/firm.c @@ -8,6 +8,7 @@ #include "fs.h" #include "patches.h" #include "memory.h" +#include "cache.h" #include "emunand.h" #include "crypto.h" #include "draw.h" @@ -378,7 +379,7 @@ static inline void launchFirm(FirmwareType firmType, u32 isFirmlaunch) arm11 = (u32 *)0x1FFFFFF8; } - cleanInvalidateDCacheAndDMB(); //Ensure that all memory transfers have completed and that the data cache has been flushed + flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed //Set ARM11 kernel entrypoint *arm11 = (u32)firm->arm11Entry; diff --git a/source/memory.c b/source/memory.c index e6b2e56..b5027bd 100644 --- a/source/memory.c +++ b/source/memory.c @@ -60,9 +60,4 @@ u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize) } return NULL; -} - -void cleanInvalidateDCacheAndDMB(void) -{ - ((void (*)())0xFFFF0830)(); //Why write our own code when it's well implemented in the unprotected bootROM? } \ No newline at end of file diff --git a/source/memory.h b/source/memory.h index c120581..2982a0f 100644 --- a/source/memory.h +++ b/source/memory.h @@ -11,13 +11,4 @@ void memcpy(void *dest, const void *src, u32 size); void memset32(void *dest, u32 filler, u32 size); int memcmp(const void *buf1, const void *buf2, u32 size); -u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize); - -/*** - Cleans and invalidates the data cache, then waits for all memory transfers to be finished. - This function MUST be called before doing the following: - - rebooting - - powering down - - setting the ARM11 entrypoint to execute a function -***/ -void cleanInvalidateDCacheAndDMB(void); \ No newline at end of file +u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize); \ No newline at end of file diff --git a/source/screen.c b/source/screen.c index e55c4bb..d0d5cc6 100644 --- a/source/screen.c +++ b/source/screen.c @@ -8,6 +8,7 @@ #include "screen.h" #include "config.h" #include "memory.h" +#include "cache.h" #include "draw.h" #include "i2c.h" @@ -30,9 +31,11 @@ void __attribute__((naked)) arm11Stub(void) static inline void invokeArm11Function(void (*func)()) { static u32 hasCopiedStub = 0; - if(!hasCopiedStub++) memcpy((void *)ARM11_STUB_ADDRESS, arm11Stub, 0x40); - - cleanInvalidateDCacheAndDMB(); + if(!hasCopiedStub++) + { + memcpy((void *)ARM11_STUB_ADDRESS, arm11Stub, 0x40); + flushDCacheRange((void *)ARM11_STUB_ADDRESS, 0x40); + } *arm11Entry = (u32)func; while(*arm11Entry); @@ -77,6 +80,7 @@ void updateBrightness(u32 brightnessLevel) WAIT_FOR_ARM9(); } + flushDCacheRange(&brightnessValue, 4); invokeArm11Function(ARM11); } @@ -116,6 +120,7 @@ void clearScreens(void) WAIT_FOR_ARM9(); } + flushDCacheRange(fb, sizeof(struct fb)); invokeArm11Function(ARM11); } @@ -223,6 +228,8 @@ u32 initScreens(void) if(needToInit) { + flushDCacheRange(&config, 4); + flushDCacheRange(fb, sizeof(struct fb)); invokeArm11Function(ARM11); //Turn on backlight diff --git a/source/utils.c b/source/utils.c index b1cd2fe..9a56a31 100644 --- a/source/utils.c +++ b/source/utils.c @@ -6,6 +6,7 @@ #include "i2c.h" #include "buttons.h" #include "memory.h" +#include "cache.h" u32 waitInput(void) { @@ -36,7 +37,7 @@ u32 waitInput(void) void mcuReboot(void) { - cleanInvalidateDCacheAndDMB(); //Ensure that all memory transfers have completed and that the data cache has been flushed + flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2); while(1);