From dc44548e43b8cc9dcd8e32061c67ed84073a8631 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Tue, 2 Nov 2021 20:28:17 -0400 Subject: [PATCH] Sync libgcnmultiboot --- src/libgcnmultiboot.s | 429 +++++++++++++++++++++++++----------------- 1 file changed, 260 insertions(+), 169 deletions(-) diff --git a/src/libgcnmultiboot.s b/src/libgcnmultiboot.s index dbf70ccf8..5ecc7d2f9 100644 --- a/src/libgcnmultiboot.s +++ b/src/libgcnmultiboot.s @@ -4,11 +4,36 @@ .include "asm/macros.inc" .include "constants/constants.inc" + .equiv GCMB_STRUCT_COUNTER1, 0x00 + .equiv GCMB_STRUCT_COUNTER2, 0x01 + .equiv GCMB_STRUCT_MBPROGRESS, 0x02 + .equiv GCMB_STRUCT_SAVEDVCOUNT, 0x03 + .equiv GCMB_STRUCT_KEYA, 0x04 + .equiv GCMB_STRUCT_KEYB, 0x08 + .equiv GCMB_STRUCT_KEYC, 0x0C + .equiv GCMB_STRUCT_BOOT_KEY, 0x10 + .equiv GCMB_STRUCT_IMAGE_SIZE, 0x12 + .equiv GCMB_STRUCT_SESSION_KEY, 0x14 + .equiv GCMB_STRUCT_HASH_VAL, 0x18 + .equiv GCMB_STRUCT_KEYC_DERIVATION, 0x1C .equiv GCMB_STRUCT_BASE_DEST_PTR, 0x20 .equiv GCMB_STRUCT_CUR_DEST_PTR, 0x24 .equiv GCMB_STRUCT_SERIAL_INTR_HANDLER, 0x28 - .equiv ROM_HEADER_NINTENDO_LOGO_OFFSET, 0x4 + .equiv ROM_HEADER_NINTENDO_LOGO_OFFSET, 0x04 + .equiv ROM_HEADER_NINTENDO_LOGO_LENGTH, 0x98 + .equiv ROM_HEADER_NINTENDO_LOGO_END, 0xA0 + + .equiv MBPROGRESS_NONE, 0x00 + .equiv MBPROGRESS_LOGO_CORRECT, 0x01 + .equiv MBPROGRESS_READY_TO_BOOT, 0x02 + + .equiv GCMB_MAGIC_BOOTKEY_HASHVAL, 0xBB + .equiv GCMB_MAGIC_BOOTKEY, 0xBB + .equiv GCMB_MAGIC_COUNTER2, 0xCC + .equiv GCMB_MAGIC_KEYA, 0xDD + .equiv GCMB_MAGIC_KEYB, 0xEE + .equiv GCMB_MAGIC_KEYCDERIVATION, 0xFF .syntax unified @@ -22,7 +47,7 @@ GameCubeMultiBoot_Hash: @ 82DED70 movs r2, 0x20 GameCubeMultiBoot_Hash_Loop: - lsrs r3, #1 + lsrs r3, 1 bcc GameCubeMultiBoot_Hash_SkipEor eors r3, r4 @@ -37,137 +62,177 @@ GameCubeMultiBoot_Hash_SkipEor: thumb_func_start GameCubeMultiBoot_Main @ void GameCubeMultiBoot_Main(struct GameCubeMultiBoot *mb); GameCubeMultiBoot_Main: @ 82DED84 - ldr r1, [r0, #GCMB_STRUCT_SERIAL_INTR_HANDLER] - cmp r1, #0 - beq _082DEDAA - ldrb r1, [r0, 0x1] - adds r1, 0x1 - strb r1, [r0, 0x1] - ldrb r1, [r0, 0x2] - cmp r1, 0x2 - beq _082DEDF4 - ldr r3, pool_InterruptRegs - ldrh r2, [r3, #OFFSET_REG_IME - 0x200] - movs r1, 0 - strh r1, [r3, #OFFSET_REG_IME - 0x200] - ldrb r1, [r0] - cmp r1, 0xA - bgt _082DEDA8 - adds r1, 0x1 - strb r1, [r0] -_082DEDA8: - strh r2, [r3, #OFFSET_REG_IME - 0x200] -_082DEDAA: - bcs GameCubeMultiBoot_Init - ldrb r1, [r0, 0x2] + @ If there is no interrupt handler, skip counter manipulation + ldr r1, [r0, GCMB_STRUCT_SERIAL_INTR_HANDLER] cmp r1, 0 - bne _082DEDF6 - ldr r1, [r0, #GCMB_STRUCT_CUR_DEST_PTR] - ldr r2, [r0, #GCMB_STRUCT_BASE_DEST_PTR] + beq GameCubeMultiBoot_Main_SkipCounters + @ Increment the second counter + ldrb r1, [r0, GCMB_STRUCT_COUNTER2] + adds r1, 0x1 + strb r1, [r0, GCMB_STRUCT_COUNTER2] + @ If there is nothing more to do, bail out + ldrb r1, [r0, GCMB_STRUCT_MBPROGRESS] + cmp r1, MBPROGRESS_READY_TO_BOOT + beq GameCubeMultiBoot_Main_Return + @ Save current interrupt master register value + ldr r3, pool_InterruptRegs + ldrh r2, [r3, OFFSET_REG_IME - 0x200] + @ Disable all interrupts + movs r1, 0 + strh r1, [r3, OFFSET_REG_IME - 0x200] + @ Increment the first counter, if it's less than or equal to 10. + ldrb r1, [r0, GCMB_STRUCT_COUNTER1] + cmp r1, 0xA + bgt GameCubeMultiBoot_Main_SkipCounter1Inc + adds r1, 0x1 + strb r1, [r0, GCMB_STRUCT_COUNTER1] +GameCubeMultiBoot_Main_SkipCounter1Inc: + @ Load the saved interrupt master register value (re-enables interrupts if they were enabled before) + strh r2, [r3, OFFSET_REG_IME - 0x200] +GameCubeMultiBoot_Main_SkipCounters: + @ Initialise multiboot structures if required + bcs GameCubeMultiBoot_Init + @ Skip this section (check Nintendo logo) if the check has already passed + ldrb r1, [r0, GCMB_STRUCT_MBPROGRESS] + cmp r1, MBPROGRESS_NONE + bne GameCubeMultiBoot_Main_SkipLogoCheck + @ Bail out if no multiboot image data has been transferred yet + ldr r1, [r0, GCMB_STRUCT_CUR_DEST_PTR] + ldr r2, [r0, GCMB_STRUCT_BASE_DEST_PTR] subs r1, r2 - beq _082DEE76 - cmp r1, 0xA0 - bcc _082DEE76 + beq GameCubeMultiBoot_Main_Return2 + @ Also bail out if not enough data has been transferred + cmp r1, ROM_HEADER_NINTENDO_LOGO_END + bcc GameCubeMultiBoot_Main_Return2 + @ Compare the Nintendo logo of the transferred multiboot image header, with the one in the ROM image of the inserted cart push {r4-r6} - movs r1, 0x98 - adds r2, #ROM_HEADER_NINTENDO_LOGO_OFFSET + movs r1, ROM_HEADER_NINTENDO_LOGO_LENGTH + adds r2, ROM_HEADER_NINTENDO_LOGO_OFFSET ldr r4, pool_NintendoLogo -_082DEDC6: +GameCubeMultiBoot_Main_LogoCmpLoop: ldm r2!, {r5} ldm r4!, {r6} cmp r5, r6 - bne _082DEDDC + bne GameCubeMultiBoot_Main_LogoCmpEnd subs r1, 0x4 - bne _082DEDC6 + bne GameCubeMultiBoot_Main_LogoCmpLoop ldm r2!, {r5} ldm r4!, {r6} eors r5, r6 - lsrs r5, #8 - str r2, [r0, #GCMB_STRUCT_BASE_DEST_PTR] -_082DEDDC: + lsrs r5, 8 + str r2, [r0, GCMB_STRUCT_BASE_DEST_PTR] +GameCubeMultiBoot_Main_LogoCmpEnd: pop {r4-r6} + @ Throw everything away if the logo data didn't match bne GameCubeMultiBoot_Init - movs r1, 0x1 - strb r1, [r0, 0x2] - ldr r1, [r0, 0x4] - ldr r2, [r0, 0x8] + @ Logo matched, set the relevent multiboot progress bit + movs r1, MBPROGRESS_LOGO_CORRECT + strb r1, [r0, GCMB_STRUCT_MBPROGRESS] + @ XOR together KeyA and KeyB to get the initial multiboot image checksum value + ldr r1, [r0, GCMB_STRUCT_KEYA] + ldr r2, [r0, GCMB_STRUCT_KEYB] eors r1, r2 - str r1, [r0, 0x18] + str r1, [r0, GCMB_STRUCT_HASH_VAL] + @ ...also use it as the initial value for the image encryption session key. Algorithm is the same as the GBA BIOS multiboot: sessionkey = (initialvalue * 0x6177614b) + 1 ldr r2, pool_Kawa muls r1, r2 adds r1, 0x1 - str r1, [r0, 0x14] -_082DEDF4: + str r1, [r0, GCMB_STRUCT_SESSION_KEY] +GameCubeMultiBoot_Main_Return: bx lr -_082DEDF6: - ldr r1, [r0, #GCMB_STRUCT_CUR_DEST_PTR] +GameCubeMultiBoot_Main_SkipLogoCheck: + @ If this code is executed, then the logo check has passed, and the data being transferred in is encrypted. + @ Set up registers. + ldr r1, [r0, GCMB_STRUCT_CUR_DEST_PTR] mov r12, r1 - ldr r3, [r0, 0x18] + ldr r3, [r0, GCMB_STRUCT_HASH_VAL] push {r4-r7} - ldr r4, [r0, #GCMB_STRUCT_BASE_DEST_PTR] + ldr r4, [r0, GCMB_STRUCT_BASE_DEST_PTR] ldr r5, pool_Kawa - ldr r6, [r0, 0x14] + ldr r6, [r0, GCMB_STRUCT_SESSION_KEY] ldr r7, pool_HashVal -_082DEE06: +GameCubeMultiBoot_Main_ImageDecryptHashLoop: + @ If there's no more data, break out of the loop cmp r4, r12 - bcs _082DEE26 + bcs GameCubeMultiBoot_Main_ImageDecryptHashEnd + @ Get the next uint32 ldr r1, [r4] + @ Decrypt the ciphertext: plaintext = (ciphertext ^ sessionkey) + hashval eors r1, r6 adds r1, r3 + @ Save the current uint32 of plaintext and advance the pointer stm r4!, {r1} + @ Advance the hashval with this uint32 of plaintext -- this is the same code as GameCubeMultiBoot_Hash. eors r3, r1 movs r2, 0x20 -_082DEE16: - lsrs r3, #1 - bcc _082DEE1C +GameCubeMultiBoot_Main_HashLoop: + lsrs r3, 1 + bcc GameCubeMultiBoot_Main_HashSkipEor eors r3, r7 -_082DEE1C: +GameCubeMultiBoot_Main_HashSkipEor: subs r2, 0x1 - bne _082DEE16 + bne GameCubeMultiBoot_Main_HashLoop + @ Advance the sessionkey with the usual algorithm: sessionkey = (sessionkey * 0x6177614b) + 1 muls r6, r5 adds r6, 0x1 - b _082DEE06 -_082DEE26: - str r4, [r0, #GCMB_STRUCT_BASE_DEST_PTR] - str r6, [r0, 0x14] + b GameCubeMultiBoot_Main_ImageDecryptHashLoop +GameCubeMultiBoot_Main_ImageDecryptHashEnd: + @ Save the new pointer, sessionkey, hashval + str r4, [r0, GCMB_STRUCT_BASE_DEST_PTR] + str r6, [r0, GCMB_STRUCT_SESSION_KEY] pop {r4-r7} - str r3, [r0, 0x18] - ldrh r1, [r0, 0x12] - cmp r1, #0 - bne _082DEE76 - ldr r1, [r0, #GCMB_STRUCT_CUR_DEST_PTR] - ldr r2, [r0, #GCMB_STRUCT_BASE_DEST_PTR] + str r3, [r0, GCMB_STRUCT_HASH_VAL] + @ Bail out if the image size is unknown + ldrh r1, [r0, GCMB_STRUCT_IMAGE_SIZE] + cmp r1, 0 + bne GameCubeMultiBoot_Main_Return2 + @ Bail out if no image data has been transferred + ldr r1, [r0, GCMB_STRUCT_CUR_DEST_PTR] + ldr r2, [r0, GCMB_STRUCT_BASE_DEST_PTR] cmp r1, r2 - bne _082DEE76 - ldr r1, [r0, 0xC] - cmp r1, #0 - beq _082DEE60 - ldrh r1, [r0, 0x10] - cmp r1, #0 - beq _082DEDF4 + bne GameCubeMultiBoot_Main_Return2 + @ If KeyC hasn't been generated yet, go generate it + ldr r1, [r0, GCMB_STRUCT_KEYC] + cmp r1, 0 + beq GameCubeMultiBoot_Main_GenerateKeyC + @ If the other side hasn't sent its boot key yet, bail out + ldrh r1, [r0, GCMB_STRUCT_BOOT_KEY] + cmp r1, 0 + beq GameCubeMultiBoot_Main_Return + @ Save off LR so it doesn't get clobbered by the upcoming function call mov r12, lr - movs r1, 0xBB - ldr r3, [r0, 0xC] + @ Generate the real boot key, which is the checksum of a hardcoded value and KeyC + movs r1, GCMB_MAGIC_BOOTKEY_HASHVAL + ldr r3, [r0, GCMB_STRUCT_KEYC] bl GameCubeMultiBoot_Hash - ldrh r1, [r0, 0x10] + ldrh r1, [r0, GCMB_STRUCT_BOOT_KEY] + @ Restore the saved LR value mov lr, r12 + @ Compare the two boot keys (real and passed in), if they don't match then throw everything away subs r1, r3 bne GameCubeMultiBoot_Init - movs r1, 0x2 - strb r1, [r0, 0x2] + @ The two boot keys matched, tell the caller that the image is ready to boot + movs r1, MBPROGRESS_READY_TO_BOOT + strb r1, [r0, GCMB_STRUCT_MBPROGRESS] + @ Nothing more to do, return. bx lr -_082DEE60: +GameCubeMultiBoot_Main_GenerateKeyC: + @ Save off LR so it doesn't get clobbered by the upcoming function call mov r12, lr - ldrb r1, [r0, 0x3] - lsls r1, #24 + @ KeyC = (SavedVCount << 24) - 1 + ldrb r1, [r0, GCMB_STRUCT_SAVEDVCOUNT] + lsls r1, 24 subs r1, 0x1 - str r1, [r0, 0xC] + str r1, [r0, GCMB_STRUCT_KEYC] + @ Hash the KeyC with the multiboot image checksum to generate the KeyC derivation material to be sent to the other side of the link bl GameCubeMultiBoot_Hash - lsls r3, #8 - adds r3, 0xFF - str r3, [r0, 0x1C] + @ Make sure the sent KeyC derivation material contains a magic value so that the other side can detect it + lsls r3, 8 + adds r3, GCMB_MAGIC_KEYCDERIVATION + @ Save off the KeyC derivation material and return to caller + str r3, [r0, GCMB_STRUCT_KEYC_DERIVATION] bx r12 -_082DEE76: +GameCubeMultiBoot_Main_Return2: bx lr thumb_func_end GameCubeMultiBoot_Main @@ -182,12 +247,15 @@ pool_NintendoLogo: .4byte RomHeaderNintendoLogo thumb_func_start GameCubeMultiBoot_ExecuteProgram @ void GameCubeMultiBoot_ExecuteProgram(struct GameCubeMultiBoot *mb); GameCubeMultiBoot_ExecuteProgram: @ 82DEE84 - ldrb r1, [r0, 0x2] - cmp r1, 0x2 + @ If there's no multiboot image ready, just return to caller + ldrb r1, [r0, GCMB_STRUCT_MBPROGRESS] + cmp r1, MBPROGRESS_READY_TO_BOOT bne GameCubeMultiBoot_ExecuteProgram_Fail + @ Disable interrupts ldr r3, pool_InterruptRegs - movs r1, #0 - strh r1, [r3, #OFFSET_REG_IME - 0x200] + movs r1, 0 + strh r1, [r3, OFFSET_REG_IME - 0x200] + @ Jump to the real entry point of the multiboot image (past the image header), in ARM mode ldr r1, pool_MultiBootLoadAddr adds r1, 0xC0 bx r1 @@ -201,25 +269,25 @@ GameCubeMultiBoot_Init: @ 82DEE98 ldr r3, pool_InterruptRegs @ Save IME register. - ldrh r2, [r3, #OFFSET_REG_IME - 0x200] + ldrh r2, [r3, OFFSET_REG_IME - 0x200] @ Disable interrupts. movs r1, 0 - strh r1, [r3, #OFFSET_REG_IME - 0x200] + strh r1, [r3, OFFSET_REG_IME - 0x200] @ Set the handler to the "Stop" routine. @ Unless the first command that is received is a device reset command, the @ "Stop" routine will be executed and no further commands will be processed. adr r3, GcMbIntrHandler_Stop - str r3, [r0, #GCMB_STRUCT_SERIAL_INTR_HANDLER] + str r3, [r0, GCMB_STRUCT_SERIAL_INTR_HANDLER] ldrb r3, [r0, 0x3] push {r3} ldrb r3, [r0, 0x1] push {r0,r3} - adds r3, r0, #0 - adds r3, #GCMB_STRUCT_BASE_DEST_PTR + adds r3, r0, 0 + adds r3, GCMB_STRUCT_BASE_DEST_PTR @ clear all but the last 3 fields of the struct GameCubeMultiBoot_Init_ClearStructLoop: @@ -261,7 +329,7 @@ GameCubeMultiBoot_Init_ClearStructLoop: strh r1, [r3, OFFSET_REG_IE - 0x200] @ Restore IME register. - strh r2, [r3, #OFFSET_REG_IME - 0x200] + strh r2, [r3, OFFSET_REG_IME - 0x200] bx lr thumb_func_end GameCubeMultiBoot_Init @@ -275,11 +343,11 @@ GameCubeMultiBoot_HandleSerialInterrupt: @ 82DEEE2 ldrh r1, [r3, OFFSET_REG_JOYCNT - 0x120] strh r1, [r3, OFFSET_REG_JOYCNT - 0x120] - movs r2, #0 + movs r2, 0 strb r2, [r0] - ldr r2, [r0, #GCMB_STRUCT_SERIAL_INTR_HANDLER] - cmp r2, #0 + ldr r2, [r0, GCMB_STRUCT_SERIAL_INTR_HANDLER] + cmp r2, 0 beq GameCubeMultiBoot_HandleSerialInterruptDone lsrs r1, 1 @ was a device reset command received? @@ -297,7 +365,7 @@ GcMbIntrHandler_Stop: strh r2, [r3, OFFSET_REG_JOYSTAT - 0x120] GameCubeMultiBoot_SetInterruptHandler: - str r2, [r0, #GCMB_STRUCT_SERIAL_INTR_HANDLER] + str r2, [r0, GCMB_STRUCT_SERIAL_INTR_HANDLER] GameCubeMultiBoot_ReadVCount: ldr r3, pool_RegDispstat @@ -308,19 +376,25 @@ GameCubeMultiBoot_HandleSerialInterruptDone: bx lr GameCubeMultiBoot_BeginHandshake: + @ Throw away anything that got sent ldr r1, [r3, OFFSET_REG_JOY_RECV - 0x120] + @ Send the game code, the other side of the link must send back the same game code ldr r1, pool_RubyUSAGameCode str r1, [r3, OFFSET_REG_JOY_TRANS - 0x120] movs r1, 0x10 strh r1, [r3, OFFSET_REG_JOYSTAT - 0x120] - ldrb r1, [r0, 0x3] - strb r1, [r0, 0x9] - ldrb r1, [r0, 0x2] + @ Use the saved VCount value to provide 8 bits of entropy for KeyB + ldrb r1, [r0, GCMB_STRUCT_SAVEDVCOUNT] + strb r1, [r0, GCMB_STRUCT_KEYB + 1] + @ If a multiboot image has been transferred at least enough such that the Nintendo logo check has passed, stop everything. + ldrb r1, [r0, GCMB_STRUCT_MBPROGRESS] cmp r1, 0 bne GcMbIntrHandler_Stop + @ Set the image destination pointers. ldr r1, pool_MultiBootLoadAddr - str r1, [r0, #GCMB_STRUCT_BASE_DEST_PTR] - str r1, [r0, #GCMB_STRUCT_CUR_DEST_PTR] + str r1, [r0, GCMB_STRUCT_BASE_DEST_PTR] + str r1, [r0, GCMB_STRUCT_CUR_DEST_PTR] + @ Set the new interrupt handler. adr r2, GcMbIntrHandler_CheckGameCodeSent b GameCubeMultiBoot_SetInterruptHandler @@ -347,149 +421,166 @@ GameCubeMultiBoot_CheckHandshakeResponse: ldr r2, pool_RubyUSAGameCode cmp r1, r2 bne GcMbIntrHandler_Stop @ stop if the GameCube didn't reply with the same game code - ldrb r1, [r0, 0x3] - strb r1, [r0, 0xB] - adr r2, GcMbIntrHandler_82DEF44 + @ Use the saved VCount value to provide another 8 bits of entropy for KeyB. + ldrb r1, [r0, GCMB_STRUCT_SAVEDVCOUNT] + strb r1, [r0, GCMB_STRUCT_KEYB + 3] + adr r2, GcMbIntrHandler_ReceiveKeyA b GameCubeMultiBoot_SetInterruptHandler .align 2, 0 -GcMbIntrHandler_82DEF44: @ 82DEF44 +GcMbIntrHandler_ReceiveKeyA: @ 82DEF44 lsrs r1, 1 @ is receive complete? bcc GcMbIntrHandler_Stop @ branch if not ldr r1, [r3, OFFSET_REG_JOY_RECV - 0x120] + @ make sure top 8 bits of the received value is the KeyA magic number, stop if KeyA is invalid lsrs r2, r1, 24 - cmp r2, 0xDD + cmp r2, GCMB_MAGIC_KEYA bne GcMbIntrHandler_Stop - str r1, [r0, 0x4] - ldrb r1, [r0, 0x1] - strb r1, [r0, 0xA] + @ save received KeyA + str r1, [r0, GCMB_STRUCT_KEYA] + @ use the second GameCubeMultiBoot_Main() counter as another 8 bits of entropy for KeyB + ldrb r1, [r0, GCMB_STRUCT_COUNTER2] + strb r1, [r0, GCMB_STRUCT_KEYB + 2] movs r2, 0 movs r3, 0 - ldr r1, [r0, 0x8] + ldr r1, [r0, GCMB_STRUCT_KEYB] lsrs r1, 8 -_082DEF5E: + @ make sure KeyB is valid (other side of the link is supposed to check KeyB too), if it's not then change the byte that was just set so it is +GameCubeMultiBoot_KeyBCheckLoop: lsrs r1, 1 adcs r2, r3 cmp r1, 0 - bne _082DEF5E + bne GameCubeMultiBoot_KeyBCheckLoop cmp r2, 0xE - bgt _082DEF70 + bgt GameCubeMultiBoot_KeyBSaveNewByte cmp r2, 0x7 - bge _082DEF72 + bge GameCubeMultiBoot_KeyBCheckEnd movs r1, 0xFF -_082DEF70: - strb r1, [r0, 0xA] -_082DEF72: - ldr r1, [r0, 0x8] - adds r1, 0xEE +GameCubeMultiBoot_KeyBSaveNewByte: + strb r1, [r0, GCMB_STRUCT_KEYB + 2] +GameCubeMultiBoot_KeyBCheckEnd: + @ add in the KeyB magic number and send off KeyB + ldr r1, [r0, GCMB_STRUCT_KEYB] + adds r1, GCMB_MAGIC_KEYB ldr r3, pool_SerialRegs str r1, [r3, OFFSET_REG_JOY_TRANS - 0x120] movs r1, 0x30 strh r1, [r3, OFFSET_REG_JOYSTAT - 0x120] - adr r2, GcMbIntrHandler_82DEF84 + @ set new interrupt handler + adr r2, GcMbIntrHandler_CheckKeyBSent b GameCubeMultiBoot_SetInterruptHandler .align 2, 0 -GcMbIntrHandler_82DEF84: @ 82DEF84 +GcMbIntrHandler_CheckKeyBSent: @ 82DEF84 lsls r1, 31 bcc GcMbIntrHandler_Stop @ stop if send failed - bmi _082DEF94 @ branch if receive is complete - adr r2, GcMbIntrHandler_82DEF90 + bmi GameCubeMultiBoot_CheckImageSizeResponse @ branch if receive is complete + adr r2, GcMbIntrHandler_CheckImageSizeResponse b GameCubeMultiBoot_SetInterruptHandler .align 2, 0 -GcMbIntrHandler_82DEF90: @ 82DEF90 +GcMbIntrHandler_CheckImageSizeResponse: @ 82DEF90 lsrs r1, 1 @ is receive complete? bcc GcMbIntrHandler_Stop @ branch if not -_082DEF94: +GameCubeMultiBoot_CheckImageSizeResponse: ldr r1, [r3, OFFSET_REG_JOY_RECV - 0x120] - ldr r2, _082DF034 + ldr r2, GameCubeMultiBoot_MaximumImageSizeUInt32s cmp r1, r2 bhs GcMbIntrHandler_Stop adds r1, 0x1 adds r1, r1 - strh r1, [r0, 0x12] - ldrb r1, [r0, 0x2] + strh r1, [r0, GCMB_STRUCT_IMAGE_SIZE] + ldrb r1, [r0, GCMB_STRUCT_MBPROGRESS] cmp r1, 0 -_082DEFA6: +GcMbIntrHandler_StopIfNotEqual: bne GcMbIntrHandler_Stop ldr r1, pool_MultiBootLoadAddr - str r1, [r0, #GCMB_STRUCT_BASE_DEST_PTR] - str r1, [r0, #GCMB_STRUCT_CUR_DEST_PTR] - adr r2, GcMbIntrHandler_82DEFB4 + str r1, [r0, GCMB_STRUCT_BASE_DEST_PTR] + str r1, [r0, GCMB_STRUCT_CUR_DEST_PTR] + adr r2, GcMbIntrHandler_CheckImageResponse b GameCubeMultiBoot_SetInterruptHandler .align 2, 0 -GcMbIntrHandler_82DEFB4: @ 82DEFB4 +GcMbIntrHandler_CheckImageResponse: @ 82DEFB4 lsrs r1, 1 @ is receive complete? bcc GcMbIntrHandler_Stop @ branch if not - ldr r2, [r0, #GCMB_STRUCT_CUR_DEST_PTR] + ldr r2, [r0, GCMB_STRUCT_CUR_DEST_PTR] movs r1, 0x4 ands r1, r2 adds r1, 0x8 lsls r1, 2 strh r1, [r3, OFFSET_REG_JOYSTAT - 0x120] + @ get the recieved uint32 ldr r1, [r3, OFFSET_REG_JOY_RECV - 0x120] + @ put it in the current destination pointer and advance that pointer stm r2!, {r1} - str r2, [r0, #GCMB_STRUCT_CUR_DEST_PTR] - ldrh r1, [r0, 0x12] + @ save off the advanced pointer + str r2, [r0, GCMB_STRUCT_CUR_DEST_PTR] + @ decrease the image size (in uint32s) + ldrh r1, [r0, GCMB_STRUCT_IMAGE_SIZE] subs r1, 0x1 - strh r1, [r0, 0x12] + strh r1, [r0, GCMB_STRUCT_IMAGE_SIZE] + @ branch away if the transfer is not yet complete bne GameCubeMultiBoot_ReadVCount -_082DEFD2: - ldrb r1, [r0, 0x1] +GcMbIntrHandler_SendCounter2: + @ send counter2 with magic number + ldrb r1, [r0, GCMB_STRUCT_COUNTER2] lsls r1, 8 - adds r1, 0xCC + adds r1, GCMB_MAGIC_COUNTER2 str r1, [r3, OFFSET_REG_JOY_TRANS - 0x120] - adr r2, _082DEFE0 + adr r2, GcMbIntrHandler_CheckCounter2Sent b GameCubeMultiBoot_SetInterruptHandler .align 2, 0 -_082DEFE0: +GcMbIntrHandler_CheckCounter2Sent: lsls r1, 31 -_082DEFE2: - bcc GcMbIntrHandler_Stop - ldr r1, [r0, 0x1C] +GcMbIntrHandler_StopIfSendFailed: + bcc GcMbIntrHandler_Stop @ stop if send failed + @ if KeyC derivation value has not yet been generated, send Counter2 again, otherwise, send KeyC derivation + ldr r1, [r0, GCMB_STRUCT_KEYC_DERIVATION] cmp r1, 0 - beq _082DEFD2 + beq GcMbIntrHandler_SendCounter2 str r1, [r3, OFFSET_REG_JOY_TRANS - 0x120] - adr r2, GcMbIntrHandler_82DEFF0 + adr r2, GcMbIntrHandler_CheckKeyCDerivationSent b GameCubeMultiBoot_SetInterruptHandler .align 2, 0 -GcMbIntrHandler_82DEFF0: @ 82DEFF0 +GcMbIntrHandler_CheckKeyCDerivationSent: @ 82DEFF0 lsls r1, 31 - bcc _082DEFE2 @ branch if send failed - bmi _082DF000 @ branch if receive is complete - adr r2, GcMbIntrHandler_82DEFFC + bcc GcMbIntrHandler_StopIfSendFailed @ branch if send failed + bmi GameCubeMultiBoot_CheckBootKeyResponse @ branch if receive is complete + adr r2, GcMbIntrHandler_CheckBootKeyResponse b GameCubeMultiBoot_SetInterruptHandler .align 2, 0 -GcMbIntrHandler_82DEFFC: @ 82DEFFC +GcMbIntrHandler_CheckBootKeyResponse: @ 82DEFFC lsrs r1, 1 @ is receive complete? - bcc _082DEFE2 @ branch if not + bcc GcMbIntrHandler_StopIfSendFailed @ branch if not -_082DF000: +GameCubeMultiBoot_CheckBootKeyResponse: ldr r1, [r3, OFFSET_REG_JOY_RECV - 0x120] + @ make sure received boot key contains expected magic number, stop if not lsrs r2, r1, 24 - cmp r2, 0xBB - bne _082DEFA6 - strh r1, [r0, 0x10] - adr r2, GcMbIntrHandler_82DF010 + cmp r2, GCMB_MAGIC_BOOTKEY + bne GcMbIntrHandler_StopIfNotEqual + @ save received bootkey to be checked in GameCubeMultiBoot_Main() + strh r1, [r0, GCMB_STRUCT_BOOT_KEY] + @ stop if anything more gets sent + adr r2, GcMbIntrHandler_StopUnconditionally b GameCubeMultiBoot_SetInterruptHandler .align 2, 0 -GcMbIntrHandler_82DF010: @ 82DF010 +GcMbIntrHandler_StopUnconditionally: @ 82DF010 b GcMbIntrHandler_Stop thumb_func_end GameCubeMultiBoot_HandleSerialInterrupt @@ -500,11 +591,11 @@ GameCubeMultiBoot_Quit: @ 82DF012 ldr r3, pool_InterruptRegs @ Save IME register. - ldrh r2, [r3, #OFFSET_REG_IME - 0x200] + ldrh r2, [r3, OFFSET_REG_IME - 0x200] @ Disable interrupts. movs r1, 0 - strh r1, [r3, #OFFSET_REG_IME - 0x200] + strh r1, [r3, OFFSET_REG_IME - 0x200] ldr r3, pool_SerialRegs @@ -528,14 +619,14 @@ GameCubeMultiBoot_Quit: @ 82DF012 strh r1, [r3, OFFSET_REG_IE - 0x200] @ Restore IME register. - strh r2, [r3, #OFFSET_REG_IME - 0x200] + strh r2, [r3, OFFSET_REG_IME - 0x200] bx lr thumb_func_end GameCubeMultiBoot_Quit .align 2, 0 -_082DF034: .4byte 0x4000 +GameCubeMultiBoot_MaximumImageSizeUInt32s: .4byte 0x4000 pool_InterruptRegs: .4byte REG_BASE + 0x200