aboutsummaryrefslogtreecommitdiff
path: root/examples/lowlevel/cartrom/rom.S
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi92@disroot.org>2025-07-05 02:34:11 +0200
committerXavier Del Campo Romero <xavi92@disroot.org>2025-07-05 02:34:11 +0200
commitbeb76e4dd362374b8f42cd971d394bba1074cd8d (patch)
tree3ea4cc342737afb9225c01160c92647ba66c78bd /examples/lowlevel/cartrom/rom.S
parent5d9aa2d3dfc7d6e51c2eb942ab4cdbae5571a40a (diff)
downloadpsn00bsdk-fix-include.tar.gz
Replace .include with #includefix-include
For some reason, both mipsel-unknown-elf-gcc 8.2.0 and mipsel-non-elf 15.1.0 were unable to resolve .include assembler directives. As a workaround, it is still possible to use the preprocessor, and therefore the usual #include preprocessor directive. However, this requires the assembly files to use the uppercase .S file extension.
Diffstat (limited to 'examples/lowlevel/cartrom/rom.S')
-rw-r--r--examples/lowlevel/cartrom/rom.S402
1 files changed, 402 insertions, 0 deletions
diff --git a/examples/lowlevel/cartrom/rom.S b/examples/lowlevel/cartrom/rom.S
new file mode 100644
index 0000000..587ba6f
--- /dev/null
+++ b/examples/lowlevel/cartrom/rom.S
@@ -0,0 +1,402 @@
+# LibPSn00b Example Programs
+# Part of the PSn00bSDk project
+#
+# TurboBoot Example by Lameguy64
+#
+# Note: This example is being obsoleted as GAS is not ideal for making
+# ROM firmwares. Use ARMIPS instead, but it cannot build this example
+# as it is not GAS syntax compatible.
+
+
+# Uncomment either PAR or XPLORER depending on the cartridge
+# you're going to use (makes disabling turbo boot via switch to work)
+
+#.set PAR, 0
+#.set XPLORER, 1
+
+
+.set noreorder
+
+.include "cop0.inc" # Contains definitions for cop0 registers
+
+.set SP_base, 0x801ffff0
+.set BREAK_ADDR, 0xa0000040 # cop0 breakpoint vector address
+
+
+.set RAM_buff, 2048
+.set RAM_handle, 2052
+.set RAM_tcb, 2056
+.set RAM_evcb, 2060
+.set RAM_stack, 2064
+.set RAM_psexe, 2068
+
+
+.set EXE_pc0, 0 # PS-EXE header offsets
+.set EXE_gp0, 4
+.set EXE_taddr, 8
+.set EXE_tsize, 12
+.set EXE_daddr, 16
+.set EXE_dsize, 20
+.set EXE_baddr, 24
+.set EXE_bsize, 28
+.set EXE_spaddr, 32
+.set EXE_sp_size, 36
+.set EXE_sp, 40
+.set EXE_fp, 44
+.set EXE_gp, 48
+.set EXE_ret, 52
+.set EXE_base, 56
+.set EXE_datapos, 60
+
+
+.section .text
+
+
+# ROM header
+#
+# The Licensed by... strings are essential otherwise the BIOS will not
+# execute the boot vectors. Always make sure the tty message fields (string
+# after Licensed by) must be no more than 80 bytes long and must have a null
+# terminating byte.
+#
+# Postboot vector isn't particularly practical as its only executed in between
+# the PS boot logo and the point where game execution occurs.
+#
+header:
+ # Postboot vector
+ .word 0
+ .ascii "Licensed by Sony Computer Entertainment Inc."
+ .ascii "Not officially licensed or endorsed by Sony Computer Entertainment Inc."
+
+ .balign 0x80 # This keeps things in the header aligned
+
+ # Preboot vector
+ .word preboot
+ .ascii "Licensed by Sony Computer Entertainment Inc."
+ .ascii "Cart ROM example for PSn00bSDK https://github.com/lameguy64/psn00bsdk"
+
+ .balign 0x80 # This keeps things in the header aligned
+
+
+# Preboot vector
+#
+# All it does is it initializes a breakpoint vector at 0x40
+# and sets a cop0 breakpoint at 0x80030000 to perform a midboot
+# exploit as preboot doesn't have the kernel area initialized.
+#
+preboot:
+
+ li $v0, 1
+
+.ifdef XPLORER
+ lui $a0, 0x1f06 # Read switch status for Xplorer
+ lbu $v0, 0($a0)
+.endif
+
+.ifdef PAR
+ lui $a0, 0x1f02 # Read switch status for PAR/GS devices
+ lbu $v0, 0x18($a0)
+.endif
+
+ nop
+ andi $v0, 0x1
+ beqz $v0, .no_rom # If switch is off don't install hook
+ nop # and effectively disables the cartridge
+
+ li $v0, BREAK_ADDR # Patch a jump at cop0 breakpoint vector
+
+ li $a0, 0x3c1a1f00 # lui $k0, $1f00
+ sw $a0, 0($v0)
+ la $a1, entry # ori $k0, < address to code entrypoint >
+ andi $a1, 0xffff
+ lui $a0, 0x375a
+ or $a0, $a1
+ sw $a0, 4($v0)
+ li $a0, 0x03400008 # jr $k0
+ sw $a0, 8($v0)
+ sw $0 , 12($v0) # nop
+
+ lui $v0, 0xffff # Set BPCM and BDAM masks
+ ori $v0, 0xffff
+ mtc0 $v0, BDAM
+ mtc0 $v0, BPCM
+
+
+ li $v0, 0x80030000 # Set break on PC and data-write address
+
+ mtc0 $v0, BDA # BPC break is for compatibility with no$psx
+ mtc0 $v0, BPC # as it does not emulate break on BDA
+
+ lui $v0, 0xeb80 # Enable break on data-write and and break
+ mtc0 $v0, DCIC # on PC to DCIC control register
+
+.no_rom:
+
+ jr $ra # Return to BIOS
+ nop
+
+
+# Actual ROM entrypoint
+.global entry
+entry:
+
+ mtc0 $0 , DCIC # Clear DCIC register
+
+ la $sp, SP_base # Set stack base
+ la $gp, 0x8000c000 # Set GP address as RAM base addr in this case
+
+ jal SetDefaultExitFromException # Set default exit handler just in case
+ nop
+ jal ExitCriticalSection # Exit out of critical section (brings back interrupts)
+ nop
+
+ # Beyond this point, the PS1 is in full control to the ROM
+
+ la $a0, m_banner # Print out program banner
+ jal printf
+ addiu $sp, -4
+ addiu $sp, 4
+
+ la $a0, m_cdinit
+ jal printf
+ addiu $sp, -4
+ addiu $sp, 4
+
+ jal _96_init # Initialize the CD
+ nop
+
+ la $a0, m_ok # Print OK message if init didn't crash
+ jal printf
+ addiu $sp, -4
+ addiu $sp, 4
+
+ la $a0, m_readfile
+ la $a1, s_systemcnf
+ jal printf
+ addiu $sp, -8
+ addiu $sp, 8
+
+ la $a0, s_systemcnf # Attempt to open the SYSTEM.CNF file on CD
+ li $a1, 1
+ jal open
+ addiu $sp, -8
+ addiu $sp, 8
+
+ bltz $v0, .no_systemcnf # Fallback to loading PSX.EXE if not found
+ nop
+
+ sw $v0, RAM_handle($gp) # Save file handle
+
+ move $a0, $v0 # Read file contents of SYSTEM.CNF
+ move $a1, $gp
+ li $a2, 0x0800
+ jal read
+ addiu $sp, -12
+ addiu $sp, 12
+
+ lw $a0, RAM_handle($gp) # Close file
+ jal close
+ addiu $sp, -4
+ addiu $sp, 4
+
+ la $a0, m_ok # Output ok message
+ jal printf
+ addiu $sp, -4
+ addiu $sp, 4
+
+ # Parse CNF file
+
+ la $a0, m_parsecnf
+ jal printf
+ nop
+
+ la $a1, s_tcb # Get TCB number
+ jal strcasestr
+ move $a0, $gp
+ jal skipspace # Skip spaces
+ addiu $a0, $v0, 3
+ addiu $a0, $v0, -2 # Step two charactters back and inject '0x'
+ li $v0, '0'
+ sb $v0, 0($a0)
+ li $v0, 'x'
+ sb $v0, 1($a0)
+ jal atoi
+ addiu $sp, -4
+ addiu $sp, 4
+ move $s1, $v0
+
+ la $a1, s_evcb # Get EVCB number
+ jal strcasestr
+ move $a0, $gp
+ jal skipspace
+ addiu $a0, $v0, 5
+ addiu $a0, $v0, -2
+ li $v0, '0'
+ sb $v0, 0($a0)
+ li $v0, 'x'
+ sb $v0, 1($a0)
+ jal atoi
+ addiu $sp, -4
+ addiu $sp, 4
+ move $s0, $v0
+
+ la $a1, s_stack # Get STACK address
+ jal strcasestr
+ move $a0, $gp
+ jal skipspace
+ addiu $a0, $v0, 5
+ addiu $a0, $v0, -2
+ li $v0, '0'
+ sb $v0, 0($a0)
+ li $v0, 'x'
+ sb $v0, 1($a0)
+ jal atoi
+ addiu $sp, -4
+ addiu $sp, 4
+ move $s2, $v0
+
+ la $a1, s_boot # Get the PS-EXE file name
+ jal strcasestr
+ move $a0, $gp
+
+ jal skipspace # Skip spaces
+ addiu $a0, $v0, 4
+
+ addiu $a0, $gp, RAM_psexe # Extract the line
+ jal getline
+ move $a1, $v0
+
+ la $a0, m_ok # Print successful parsing
+ jal printf
+ addiu $sp, -4
+ addiu $sp, 4
+
+ la $a0, m_readfile
+ addiu $a1, $gp, RAM_psexe
+ jal printf
+ addiu $sp, -8
+ addiu $sp, 8
+
+ b .do_load # Proceed loading PS-EXE
+ addiu $a0, $gp, RAM_psexe
+
+.no_systemcnf: # Load fallback
+
+ la $a0, m_notfound
+ jal printf
+ addiu $sp, -4
+ addiu $sp, 4
+
+ la $a0, m_fallback
+ jal printf
+ addiu $sp, -4
+ addiu $sp, 4
+
+ li $s0, 0x10 # Default EvCBs and TCBs
+ li $s1, 0x04
+ li $s2, SP_base # Default stack
+ la $a0, s_psxexe # Attempt loading PSX.EXE
+
+.do_load:
+
+ jal LoadExe # Load PS-EXE
+ move $a1, $gp
+
+ beqz $v0, load_fail
+ nop
+
+ la $a0, m_ok
+ jal printf
+ addiu $sp, -4
+ addiu $sp, 4
+
+ sw $s2, EXE_sp($gp) # Patch the header
+ sw $s2, EXE_spaddr($gp)
+
+ la $a0, m_boot
+ jal printf
+ addiu $sp, -4
+ addiu $sp, 4
+
+ jal EnterCriticalSection # Disable interrupt handling
+ nop
+
+ move $a0, $s0 # Set configuration (EvCBs and TCBs)
+ move $a1, $s1
+ move $a2, $s2
+ jal SetConf
+ addiu $sp, -12
+ addiu $sp, 12
+
+ move $a0, $gp # Transfer execution
+ move $a1, $0
+ move $a2, $0
+ jal DoExec
+ addiu $sp, -12
+ addiu $sp, 12
+
+
+load_fail: # Fail state
+ la $a0, m_loadfail
+ jal printf
+ nop
+.fail_loop:
+ b .fail_loop
+ nop
+
+
+.include "parse.inc"
+.include "bios.inc"
+
+
+# Strings
+
+s_boot:
+ .asciz "BOOT"
+ .balign 4
+s_tcb:
+ .asciz "TCB"
+ .balign 4
+s_evcb:
+ .asciz "EVENT"
+ .balign 4
+s_stack:
+ .asciz "STACK"
+ .balign 4
+s_systemcnf:
+ .asciz "cdrom:SYSTEM.CNF;1"
+ .balign 4
+s_psxexe:
+ .asciz "cdrom:PSX.EXE;1"
+ .balign 4
+
+
+# Message strings
+
+m_banner:
+ .asciz "\nCARTROM Bootstrap Example by Lameguy64\nPart of the PSn00bSDK Project\n\n"
+ .balign 4
+m_cdinit:
+ .asciz "Initializing CD-ROM (BIOS)... "
+ .balign 4
+m_readfile:
+ .asciz "Attempting to read %s... "
+ .balign 4
+m_parsecnf:
+ .asciz "Parsing CNF file... "
+ .balign 4
+m_fallback:
+ .asciz "Falling back to loading PSX.EXE... "
+ .balign 4
+m_notfound:
+ .asciiz "Not found.\n"
+ .balign 4
+m_ok:
+ .asciz "Ok.\n"
+ .balign 4
+m_boot:
+ .asciz "Boot!\n"
+ .balign 4
+m_loadfail:
+ .asciz "Failed to load PS-EXE file.\n"
+ .balign 4