From 2d90f0b85a9b56f1c71949c1c5d3d424d8c49907 Mon Sep 17 00:00:00 2001 From: Josh Mcguigan Date: Sun, 25 May 2025 18:33:39 -0700 Subject: [PATCH] Fix framebuffer configuration race Previously the arm9 tried to use the framebuffer configuration passed in from the previous bootloader stage. However, the arm11 reconfigured the framebuffer to a new location shortly after power up. This led to the arm9 writing to a memory area which no longer displayed anything on the screen. And since the arm9 was no longer initializing the actual framebuffer random data was displayed on screen. The fix was to introduce another synchronization point between the arm9 and arm11. The arm9 start.S now waits for the arm11 to have reconfigured the framebuffer before entering main. This still left a minor flicker of unitialized data between the time that the arm11 moved the framebuffer memory location and when the arm9 initialized that memory - so an additional change in this commit is to have the arm11 initialize that memory before updating the framebuffer location. --- arm11/source/start.S | 61 +++++++++++++++++++++++++++---------------- arm9/source/draw.c | 28 +++++++------------- arm9/source/main.c | 2 +- arm9/source/start.S | 11 ++++++++ common/linux_config.h | 23 ++++++++++++++++ 5 files changed, 82 insertions(+), 43 deletions(-) diff --git a/arm11/source/start.S b/arm11/source/start.S index fae977c..82141bb 100644 --- a/arm11/source/start.S +++ b/arm11/source/start.S @@ -1,32 +1,17 @@ #include "linux_config.h" #include "scu.h" -@ LCD Frambuffers stuff (Physical Addresses) -#define LCD_FB_PDC0 (0x10400400) -#define LCD_FB_PDC1 (0x10400500) -#define LCD_FB_A_ADDR_OFFSET (0x68) -#define LCD_FB_FORMAT_OFFSET (0x70) -#define LCD_FB_PDC0_FORMAT (0x80341) -#define LCD_FB_SELECT_OFFSET (0x78) -#define LCD_FB_STRIDE_OFFSET (0x90) -#define LCD_FB_PDC0_STRIDE (0x2D0) -#define LCD_FB_B_ADDR_OFFSET (0x94) -#define FB_TOP_SIZE (400 * 240 * 3) -#define FB_BOT_SIZE (320 * 240 * 3) -#define FB_BASE_PA (VRAM_BASE) -#define FB_TOP_LEFT1 (FB_BASE_PA) -#define FB_TOP_LEFT2 (FB_TOP_LEFT1 + FB_TOP_SIZE) -#define FB_TOP_RIGHT1 (FB_TOP_LEFT2 + FB_TOP_SIZE) -#define FB_TOP_RIGHT2 (FB_TOP_RIGHT1 + FB_TOP_SIZE) -#define FB_BOT_1 (FB_TOP_RIGHT2 + FB_TOP_SIZE) -#define FB_BOT_2 (FB_BOT_1 + FB_BOT_SIZE) - .arm .section .text.start .cpu mpcore .global _start _start: + @ Initialize RAM value used to sync with arm9 + ldr r0, =SYNC_ADDR + mov r1, #SYNC_INIT + str r1, [r0] + @ Disable FIQs, IRQs, imprecise aborts @ and enter SVC mode cpsid aif, #0x13 @@ -91,6 +76,32 @@ _start: @@@@@ Map Framebuffers @@@@@ + @@@ Zero framebuffer region @@@ + ldr r0, =FB_TOP_LEFT1 @ address of buffer + mov r1, #0 @ value to set + ldr r2, =FB_TOP_SIZE @ number of bytes + bl memset + ldr r0, =FB_TOP_LEFT2 + mov r1, #0 + ldr r2, =FB_TOP_SIZE + bl memset + ldr r0, =FB_TOP_RIGHT1 + mov r1, #0 + ldr r2, =FB_TOP_SIZE + bl memset + ldr r0, =FB_TOP_RIGHT2 + mov r1, #0 + ldr r2, =FB_TOP_SIZE + bl memset + ldr r0, =FB_BOT_1 + mov r1, #0 + ldr r2, =FB_BOT_SIZE + bl memset + ldr r0, =FB_BOT_2 + mov r1, #0 + ldr r2, =FB_BOT_SIZE + bl memset + @@@ Top screen @@@ ldr r0, =LCD_FB_PDC0 @@ -125,15 +136,19 @@ _start: @ Select framebuffer 0 mov r1, #0 str r1, [r0, #LCD_FB_SELECT_OFFSET] + + ldr r0, =SYNC_ADDR + mov r1, #SYNC_FB_RDY + str r1, [r0] @@@@@ Jump to the kernel @@@@@ - + @ Wait until ARM9 tells Linux address... ldr r0, =SYNC_ADDR wait_arm9: ldr r1, [r0] - cmp r1, #0 - beq wait_arm9 + cmp r1, #SYNC_BOOT_RDY + bne wait_arm9 @ Setup the registers before @ jumping to the kernel entry diff --git a/arm9/source/draw.c b/arm9/source/draw.c index ac6c9db..15b76d5 100644 --- a/arm9/source/draw.c +++ b/arm9/source/draw.c @@ -10,6 +10,7 @@ #include "font.h" #include "draw.h" #include "fs.h" +#include "linux_config.h" static u8 *top_screen0 = NULL; static u8 *top_screen1 = NULL; @@ -19,26 +20,15 @@ static u8 *bot_screen1 = NULL; static char debugstr[DBG_N_CHARS_X * DBG_N_CHARS_Y] = { 0 }; static u32 debugcol[DBG_N_CHARS_Y] = { DBG_COLOR_FONT }; -void InitScreenFbs(int argc, char *argv[]) +void InitScreenFbs(int _argc, char *_argv[]) { - if (argc >= 2) { - /* newer entrypoints */ - struct { - u8 *top_left; - u8 *top_right; - u8 *bottom; - } *fb = (void *)argv[1]; - top_screen0 = fb[0].top_left; - top_screen1 = fb[1].top_left; - bot_screen0 = fb[0].bottom; - bot_screen1 = fb[1].bottom; - } else { - /* outdated entrypoints */ - top_screen0 = (u8 *)(*(u32 *)0x23FFFE00); - top_screen1 = (u8 *)(*(u32 *)0x23FFFE00); - bot_screen0 = (u8 *)(*(u32 *)0x23FFFE08); - bot_screen1 = (u8 *)(*(u32 *)0x23FFFE08); - } + // The arm11 start.S remaps the frame buffers to new + // locations, so we don't use the values which come + // from args. + top_screen0 = (u8 *) FB_TOP_LEFT1; + top_screen1 = (u8 *) FB_TOP_LEFT2; + bot_screen0 = (u8 *) FB_BOT_1; + bot_screen1 = (u8 *) FB_BOT_2; } void ClearScreen(u8 *screen, int width, int color) diff --git a/arm9/source/main.c b/arm9/source/main.c index d507e75..25fba0e 100644 --- a/arm9/source/main.c +++ b/arm9/source/main.c @@ -100,7 +100,7 @@ int main(int argc, char *argv[]) DeinitFS(); /* Make the ARM11 jump to the Linux payload */ - *(vu32 *)SYNC_ADDR = 1; + *(vu32 *)SYNC_ADDR = SYNC_BOOT_RDY; flushCaches(); diff --git a/arm9/source/start.S b/arm9/source/start.S index 575bbf2..91517a1 100644 --- a/arm9/source/start.S +++ b/arm9/source/start.S @@ -1,3 +1,5 @@ +#include "linux_config.h" + .section .text.start .global _start _start: @@ -59,6 +61,15 @@ _start: ldr r0, =0x10000020 mov r1, #0x340 str r1, [r0] + + @ wait for arm11 + ldr r0, =SYNC_ADDR +wait_arm11: + ldr r1, [r0] + cmp r1, #SYNC_FB_RDY + bne wait_arm11 + + @@@ Jump to main @@@ mov r0, r9 mov r1, r10 diff --git a/common/linux_config.h b/common/linux_config.h index f5f08c0..d6b9ec8 100644 --- a/common/linux_config.h +++ b/common/linux_config.h @@ -5,6 +5,9 @@ #define MACHINE_NUMBER (0xFFFFFFFF) #define ARM9LINUXFW_ADDR (0x08080000) #define SYNC_ADDR (0x1FFFFFF0) +#define SYNC_INIT (0) +#define SYNC_FB_RDY (1) +#define SYNC_BOOT_RDY (2) #define LINUXIMAGE_FILENAME "linux/zImage" #define INITRAMFS_FILENAME "linux/initramfs.cpio.gz" @@ -19,3 +22,23 @@ #define AXI_WRAM_SIZE (0x00080000) #define FCRAM_BASE (0x20000000) #define FCRAM_SIZE (0x08000000) + +/* LCD Frambuffers stuff (Physical Addresses) */ +#define LCD_FB_PDC0 (0x10400400) +#define LCD_FB_PDC1 (0x10400500) +#define LCD_FB_A_ADDR_OFFSET (0x68) +#define LCD_FB_FORMAT_OFFSET (0x70) +#define LCD_FB_PDC0_FORMAT (0x80341) +#define LCD_FB_SELECT_OFFSET (0x78) +#define LCD_FB_STRIDE_OFFSET (0x90) +#define LCD_FB_PDC0_STRIDE (0x2D0) +#define LCD_FB_B_ADDR_OFFSET (0x94) +#define FB_TOP_SIZE (400 * 240 * 3) +#define FB_BOT_SIZE (320 * 240 * 3) +#define FB_BASE_PA (VRAM_BASE) +#define FB_TOP_LEFT1 (FB_BASE_PA) +#define FB_TOP_LEFT2 (FB_TOP_LEFT1 + FB_TOP_SIZE) +#define FB_TOP_RIGHT1 (FB_TOP_LEFT2 + FB_TOP_SIZE) +#define FB_TOP_RIGHT2 (FB_TOP_RIGHT1 + FB_TOP_SIZE) +#define FB_BOT_1 (FB_TOP_RIGHT2 + FB_BOT_SIZE) +#define FB_BOT_2 (FB_BOT_1 + FB_BOT_SIZE) \ No newline at end of file