summaryrefslogtreecommitdiff
path: root/asm/libgcnmultiboot.s
diff options
context:
space:
mode:
Diffstat (limited to 'asm/libgcnmultiboot.s')
-rw-r--r--asm/libgcnmultiboot.s641
1 files changed, 0 insertions, 641 deletions
diff --git a/asm/libgcnmultiboot.s b/asm/libgcnmultiboot.s
deleted file mode 100644
index 91bc1890c..000000000
--- a/asm/libgcnmultiboot.s
+++ /dev/null
@@ -1,641 +0,0 @@
-@ This library can be used to download and execute a multi-boot image from
-@ a GameCube using the JOY Bus protocol over the link cable.
-
- .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, 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
-
- .text
-
- thumb_func_start GameCubeMultiBoot_Hash
-GameCubeMultiBoot_Hash: @ 81DCB38
- push {r4,lr}
- ldr r4, pool_HashVal
- eors r3, r1
- movs r2, 0x20
-
-GameCubeMultiBoot_Hash_Loop:
- lsrs r3, 1
- bcc GameCubeMultiBoot_Hash_SkipEor
-
- eors r3, r4
-
-GameCubeMultiBoot_Hash_SkipEor:
- subs r2, 0x1
- bne GameCubeMultiBoot_Hash_Loop
-
- pop {r4,pc}
- thumb_func_end GameCubeMultiBoot_Hash
-
- thumb_func_start GameCubeMultiBoot_Main
-@ void GameCubeMultiBoot_Main(struct GameCubeMultiBoot *mb)@
-GameCubeMultiBoot_Main: @ 81DCB4C
- @ If there is no interrupt handler, skip counter manipulation
- ldr r1, [r0, GCMB_STRUCT_SERIAL_INTR_HANDLER]
- cmp r1, 0
- 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 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, ROM_HEADER_NINTENDO_LOGO_LENGTH
- adds r2, ROM_HEADER_NINTENDO_LOGO_OFFSET
- ldr r4, pool_NintendoLogo
-GameCubeMultiBoot_Main_LogoCmpLoop:
- ldm r2!, {r5}
- ldm r4!, {r6}
- cmp r5, r6
- bne GameCubeMultiBoot_Main_LogoCmpEnd
- subs r1, 0x4
- bne GameCubeMultiBoot_Main_LogoCmpLoop
- ldm r2!, {r5}
- ldm r4!, {r6}
- eors r5, r6
- 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
- @ 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, 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, GCMB_STRUCT_SESSION_KEY]
-GameCubeMultiBoot_Main_Return:
- bx lr
-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, GCMB_STRUCT_HASH_VAL]
- push {r4-r7}
- ldr r4, [r0, GCMB_STRUCT_BASE_DEST_PTR]
- ldr r5, pool_Kawa
- ldr r6, [r0, GCMB_STRUCT_SESSION_KEY]
- ldr r7, pool_HashVal
-GameCubeMultiBoot_Main_ImageDecryptHashLoop:
- @ If there's no more data, break out of the loop
- cmp r4, r12
- 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
-GameCubeMultiBoot_Main_HashLoop:
- lsrs r3, 1
- bcc GameCubeMultiBoot_Main_HashSkipEor
- eors r3, r7
-GameCubeMultiBoot_Main_HashSkipEor:
- subs r2, 0x1
- bne GameCubeMultiBoot_Main_HashLoop
- @ Advance the sessionkey with the usual algorithm: sessionkey = (sessionkey * 0x6177614b) + 1
- muls r6, r5
- adds r6, 0x1
- 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, 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 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
- @ 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, 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
- @ 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
-GameCubeMultiBoot_Main_GenerateKeyC:
- @ Save off LR so it doesn't get clobbered by the upcoming function call
- mov r12, lr
- @ KeyC = (SavedVCount << 24) - 1
- ldrb r1, [r0, GCMB_STRUCT_SAVEDVCOUNT]
- lsls r1, 24
- subs r1, 0x1
- 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
- @ 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
-GameCubeMultiBoot_Main_Return2:
- bx lr
- thumb_func_end GameCubeMultiBoot_Main
-
- .align 2, 0
-
-pool_HashVal: .4byte 0xa1c1
-
-pool_Kawa: .ascii "Kawa" @ name of BIOS developer
-
-pool_NintendoLogo: .4byte RomHeaderNintendoLogo
-
- thumb_func_start GameCubeMultiBoot_ExecuteProgram
-@ void GameCubeMultiBoot_ExecuteProgram(struct GameCubeMultiBoot *mb)@
-GameCubeMultiBoot_ExecuteProgram: @ 81DCC4C
- @ 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]
- @ 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
-GameCubeMultiBoot_ExecuteProgram_Fail:
- bx lr
- thumb_func_end GameCubeMultiBoot_ExecuteProgram
-
- thumb_func_start GameCubeMultiBoot_Init
-@ void GameCubeMultiBoot_Init(struct GameCubeMultiBoot *mb)@
-GameCubeMultiBoot_Init: @ 81DCC60
- ldr r3, pool_InterruptRegs
-
-@ Save IME register.
- ldrh r2, [r3, OFFSET_REG_IME - 0x200]
-
-@ Disable interrupts.
- movs r1, 0
- 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]
-
- ldrb r3, [r0, 0x3]
- push {r3}
- ldrb r3, [r0, 0x1]
- push {r0,r3}
-
- adds r3, r0, 0
- adds r3, GCMB_STRUCT_BASE_DEST_PTR
-
-@ clear all but the last 3 fields of the struct
-GameCubeMultiBoot_Init_ClearStructLoop:
- stm r0!, {r1}
- cmp r0, r3
- blo GameCubeMultiBoot_Init_ClearStructLoop
-
- pop {r0,r3}
- lsrs r3, 1
- strb r3, [r0, 0x3]
- pop {r3}
- strb r3, [r0, 0x1]
-
- ldr r3, pool_SerialRegs
-
-@ Turn off JOY Bus mode.
- lsls r0, r3, 10
- strh r0, [r3, OFFSET_REG_RCNT - 0x120]
-
-@ Turn on JOY Bus mode.
- movs r0, 0xC0
- lsls r0, 8
- strh r0, [r3, OFFSET_REG_RCNT - 0x120]
-
-@ Init JOY Bus registers.
- movs r0, 0x47
- strh r0, [r3, OFFSET_REG_JOYCNT - 0x120]
- strh r1, [r3, OFFSET_REG_JOYSTAT - 0x120]
-
- ldr r3, pool_InterruptRegs
-
-@ Acknowledge serial interrupt.
- movs r0, INTR_FLAG_SERIAL
- strh r0, [r3, OFFSET_REG_IF - 0x200]
-
-@ Enable serial interrupt.
- ldrh r1, [r3, OFFSET_REG_IE - 0x200]
- orrs r1, r0
- strh r1, [r3, OFFSET_REG_IE - 0x200]
-
-@ Restore IME register.
- strh r2, [r3, OFFSET_REG_IME - 0x200]
-
- bx lr
- thumb_func_end GameCubeMultiBoot_Init
-
- non_word_aligned_thumb_func_start GameCubeMultiBoot_HandleSerialInterrupt
-@ void GameCubeMultiBoot_HandleSerialInterrupt(struct GameCubeMultiBoot *mb)@
-GameCubeMultiBoot_HandleSerialInterrupt: @ 81DCCAA
- ldr r3, pool_SerialRegs
-
-@ Acknowledge reset/receive/send flags.
- ldrh r1, [r3, OFFSET_REG_JOYCNT - 0x120]
- strh r1, [r3, OFFSET_REG_JOYCNT - 0x120]
-
- movs r2, 0
- strb r2, [r0]
-
- ldr r2, [r0, GCMB_STRUCT_SERIAL_INTR_HANDLER]
- cmp r2, 0
- beq GameCubeMultiBoot_HandleSerialInterruptDone
-
- lsrs r1, 1 @ was a device reset command received?
- bcs GameCubeMultiBoot_BeginHandshake @ branch if so
-
- mov pc, r2
-
- .align 2, 0
-
-@ Zero the status and the interrupt handler pointer.
-@ Commands from the GameCube will not be processed after this is executed
-@ unless GameCubeMultiBoot_Init() is called again.
-GcMbIntrHandler_Stop:
- movs r2, 0
- strh r2, [r3, OFFSET_REG_JOYSTAT - 0x120]
-
-GameCubeMultiBoot_SetInterruptHandler:
- str r2, [r0, GCMB_STRUCT_SERIAL_INTR_HANDLER]
-
-GameCubeMultiBoot_ReadVCount:
- ldr r3, pool_RegDispstat
- ldrh r1, [r3, OFFSET_REG_VCOUNT - OFFSET_REG_DISPSTAT]
- strb r1, [r0, 0x3]
-
-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]
- @ 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]
- @ Set the new interrupt handler.
- adr r2, GcMbIntrHandler_CheckGameCodeSent
- b GameCubeMultiBoot_SetInterruptHandler
-
- .align 2, 0
-
-GcMbIntrHandler_CheckGameCodeSent: @ 81DCCEC
- lsls r1, 31
- bcc GcMbIntrHandler_Stop @ stop if send failed
- bmi GameCubeMultiBoot_CheckHandshakeResponse @ branch if receive is complete
-
-@ If the response hasn't been fully received yet,
-@ check again upon the next interrupt.
- adr r2, GcMbIntrHandler_CheckHandshakeResponse
- b GameCubeMultiBoot_SetInterruptHandler
-
- .align 2, 0
-
-GcMbIntrHandler_CheckHandshakeResponse: @ 81DCCF8
- lsrs r1, 1 @ is receive complete?
- bcc GcMbIntrHandler_Stop @ stop if not
-
-GameCubeMultiBoot_CheckHandshakeResponse:
- ldr r1, [r3, OFFSET_REG_JOY_RECV - 0x120]
- ldr r2, pool_RubyUSAGameCode
- cmp r1, r2
- bne GcMbIntrHandler_Stop @ stop if the GameCube didn't reply with the same game code
- @ 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_ReceiveKeyA: @ 81DCD0C
- 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, GCMB_MAGIC_KEYA
- bne GcMbIntrHandler_Stop
- @ 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, GCMB_STRUCT_KEYB]
- lsrs r1, 8
- @ 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 GameCubeMultiBoot_KeyBCheckLoop
- cmp r2, 0xE
- bgt GameCubeMultiBoot_KeyBSaveNewByte
- cmp r2, 0x7
- bge GameCubeMultiBoot_KeyBCheckEnd
- movs r1, 0xFF
-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]
- @ set new interrupt handler
- adr r2, GcMbIntrHandler_CheckKeyBSent
- b GameCubeMultiBoot_SetInterruptHandler
-
- .align 2, 0
-
-GcMbIntrHandler_CheckKeyBSent: @ 81DCD4C
- lsls r1, 31
- bcc GcMbIntrHandler_Stop @ stop if send failed
- bmi GameCubeMultiBoot_CheckImageSizeResponse @ branch if receive is complete
- adr r2, GcMbIntrHandler_CheckImageSizeResponse
- b GameCubeMultiBoot_SetInterruptHandler
-
- .align 2, 0
-
-GcMbIntrHandler_CheckImageSizeResponse: @ 81DCD58
- lsrs r1, 1 @ is receive complete?
- bcc GcMbIntrHandler_Stop @ branch if not
-GameCubeMultiBoot_CheckImageSizeResponse:
- ldr r1, [r3, OFFSET_REG_JOY_RECV - 0x120]
- ldr r2, GameCubeMultiBoot_MaximumImageSizeUInt32s
- cmp r1, r2
- bhs GcMbIntrHandler_Stop
- adds r1, 0x1
- adds r1, r1
- strh r1, [r0, GCMB_STRUCT_IMAGE_SIZE]
- ldrb r1, [r0, GCMB_STRUCT_MBPROGRESS]
- cmp r1, 0
-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_CheckImageResponse
- b GameCubeMultiBoot_SetInterruptHandler
-
- .align 2, 0
-
-GcMbIntrHandler_CheckImageResponse: @ 81DCD7C
- lsrs r1, 1 @ is receive complete?
- bcc GcMbIntrHandler_Stop @ branch if not
- 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}
- @ 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, GCMB_STRUCT_IMAGE_SIZE]
- @ branch away if the transfer is not yet complete
- bne GameCubeMultiBoot_ReadVCount
-
-GcMbIntrHandler_SendCounter2:
- @ send counter2 with magic number
- ldrb r1, [r0, GCMB_STRUCT_COUNTER2]
- lsls r1, 8
- adds r1, GCMB_MAGIC_COUNTER2
- str r1, [r3, OFFSET_REG_JOY_TRANS - 0x120]
- adr r2, GcMbIntrHandler_CheckCounter2Sent
- b GameCubeMultiBoot_SetInterruptHandler
-
- .align 2, 0
-
-GcMbIntrHandler_CheckCounter2Sent:
- lsls r1, 31
-
-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 GcMbIntrHandler_SendCounter2
- str r1, [r3, OFFSET_REG_JOY_TRANS - 0x120]
- adr r2, GcMbIntrHandler_CheckKeyCDerivationSent
- b GameCubeMultiBoot_SetInterruptHandler
-
- .align 2, 0
-
-GcMbIntrHandler_CheckKeyCDerivationSent: @ 81DCDB8
- lsls r1, 31
- 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_CheckBootKeyResponse: @ 81DCDC4
- lsrs r1, 1 @ is receive complete?
- bcc GcMbIntrHandler_StopIfSendFailed @ branch if not
-
-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, 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_StopUnconditionally: @ 81DCDD8
- b GcMbIntrHandler_Stop
-
- thumb_func_end GameCubeMultiBoot_HandleSerialInterrupt
-
- non_word_aligned_thumb_func_start GameCubeMultiBoot_Quit
-@ void GameCubeMultiBoot_Quit()@
-GameCubeMultiBoot_Quit: @ 81DCDDA
- ldr r3, pool_InterruptRegs
-
-@ Save IME register.
- ldrh r2, [r3, OFFSET_REG_IME - 0x200]
-
-@ Disable interrupts.
- movs r1, 0
- strh r1, [r3, OFFSET_REG_IME - 0x200]
-
- ldr r3, pool_SerialRegs
-
-@ Acknowledge all JOYCNT flags.
- movs r0, 0x7
- strh r0, [r3, OFFSET_REG_JOYCNT - 0x120]
-
-@ Turn off JOY Bus mode.
- lsls r0, r3, 10
- strh r0, [r3, OFFSET_REG_RCNT - 0x120] @ store 0x8000
-
- ldr r3, pool_InterruptRegs
-
-@ Acknowledge serial interrupt.
- movs r0, INTR_FLAG_SERIAL
- strh r0, [r3, OFFSET_REG_IF - 0x200]
-
-@ Disable serial interrupt.
- ldrh r1, [r3, OFFSET_REG_IE - 0x200]
- bics r1, r0
- strh r1, [r3, OFFSET_REG_IE - 0x200]
-
-@ Restore IME register.
- strh r2, [r3, OFFSET_REG_IME - 0x200]
-
- bx lr
- thumb_func_end GameCubeMultiBoot_Quit
-
- .align 2, 0
-
-GameCubeMultiBoot_MaximumImageSizeUInt32s: .4byte 0x00004000
-
-pool_InterruptRegs: .4byte REG_BASE + 0x200
-
-pool_SerialRegs: .4byte REG_BASE + 0x120
-
-pool_RegDispstat: .4byte REG_DISPSTAT
-
-pool_RubyUSAGameCode: .ascii "AXVE"
-
-pool_MultiBootLoadAddr: .4byte EWRAM_START
-
- .align 2, 0 @ Don't pad with nop.