diff options
| author | lameguy64 <lameguy64@gmail.com> | 2019-05-23 22:24:56 +0800 |
|---|---|---|
| committer | lameguy64 <lameguy64@gmail.com> | 2019-05-23 22:24:56 +0800 |
| commit | 3ffebff2aad2ca438cf76db51fb3459c5639cd67 (patch) | |
| tree | a234fc6158d3c09904c4c1fb2feee09afb479a4c /examples | |
| parent | e70cd149f41ea71f9ca9ee86c03d1e59005dad2a (diff) | |
| download | psn00bsdk-3ffebff2aad2ca438cf76db51fb3459c5639cd67.tar.gz | |
Added BIOS Controller, BIOS CD, 2 new examples and custom exit handler in the works
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/cartrom/bios.inc | 67 | ||||
| -rw-r--r-- | examples/cartrom/cop0.inc | 11 | ||||
| -rw-r--r-- | examples/cartrom/makefile | 14 | ||||
| -rw-r--r-- | examples/cartrom/parse.inc | 113 | ||||
| -rw-r--r-- | examples/cartrom/readme.txt | 74 | ||||
| -rw-r--r-- | examples/cartrom/rom.ld | 11 | ||||
| -rw-r--r-- | examples/cartrom/rom.s | 399 | ||||
| -rw-r--r-- | examples/rgb24/bunpattern.tim | bin | 0 -> 921620 bytes | |||
| -rw-r--r-- | examples/rgb24/main.c | 52 | ||||
| -rw-r--r-- | examples/rgb24/makefile | 41 | ||||
| -rw-r--r-- | examples/rgb24/tim.s | 7 |
11 files changed, 789 insertions, 0 deletions
diff --git a/examples/cartrom/bios.inc b/examples/cartrom/bios.inc new file mode 100644 index 0000000..1c0201d --- /dev/null +++ b/examples/cartrom/bios.inc @@ -0,0 +1,67 @@ +printf: + addiu $t2, $0, 0xA0 + jr $t2 + addiu $t1, $0, 0x3F + +atoi: + addiu $t2, $0, 0xA0 + jr $t2 + addiu $t1, $0, 0x10 + +toupper: + addiu $t2, $0, 0xA0 + jr $t2 + addiu $t1, $0, 0x25 + +open: + addiu $t2, $0, 0xB0 + jr $t2 + addiu $t1, $0, 0x32 + +read: + addiu $t2, $0, 0xB0 + jr $t2 + addiu $t1, $0, 0x34 + +close: + addiu $t2, $0, 0xB0 + jr $t2 + addiu $t1, $0, 0x36 + +_96_init: + addiu $t2, $0, 0xA0 + jr $t2 + addiu $t1, $0, 0x71 + +LoadExe: + addiu $t2, $0, 0xA0 + jr $t2 + addiu $t1, $0, 0x42 + +DoExec: + addiu $t2, $0, 0xA0 + jr $t2 + addiu $t1, $0, 0x43 + +SetConf: + addiu $t2, $0, 0xA0 + jr $t2 + addiu $t1, $0, 0x9C + +SetDefaultExitFromException: + addiu $t2, $0, 0xB0 + jr $t2 + addiu $t1, $0, 0x18 + +EnterCriticalSection: + addiu $a0, $0, 1 + syscall 0 + jr $ra + nop + +ExitCriticalSection: + addiu $a0, $0, 2 + syscall 0 + jr $ra + nop +
\ No newline at end of file diff --git a/examples/cartrom/cop0.inc b/examples/cartrom/cop0.inc new file mode 100644 index 0000000..620fa44 --- /dev/null +++ b/examples/cartrom/cop0.inc @@ -0,0 +1,11 @@ +.set BPC, $3 +.set BDA, $5 +.set JUMPDEST, $6 +.set DCIC, $7 +.set BADVADDR, $8 +.set BDAM, $9 +.set BPCM, $11 +.set SR, $12 +.set CAUSE, $13 +.set EPC, $14 +.set PRID, $15 diff --git a/examples/cartrom/makefile b/examples/cartrom/makefile new file mode 100644 index 0000000..2434685 --- /dev/null +++ b/examples/cartrom/makefile @@ -0,0 +1,14 @@ +PREFIX = mipsel-unknown-elf- + +CC = $(PREFIX)gcc +AS = $(PREFIX)as +LD = $(PREFIX)ld + +all: rom.o + $(LD) --oformat binary -T rom.ld -o cartrom.rom rom.o + +%.o: %.s + $(AS) -msoft-float --warn $< -o $@ + +clean: + rm -f rom.o cartrom.rom
\ No newline at end of file diff --git a/examples/cartrom/parse.inc b/examples/cartrom/parse.inc new file mode 100644 index 0000000..b1190f7 --- /dev/null +++ b/examples/cartrom/parse.inc @@ -0,0 +1,113 @@ +# Skips spaces and equal signs (used by CNF parser) +skipspace: + # a0 - Input string + # Return: v0 - Address to first non-space character. + lbu $v1, 0($a0) + nop + beq $v1, ' ', .skip + nop + beq $v1, '=', .skip + nop + jr $ra + move $v0, $a0 +.skip: + b skipspace + addiu $a0, 1 + + +# Copies a string until a CR/LF or space is encountered +getline: + # a0 - Output address + # a1 - String to copy from + lbu $v0, 0($a1) + addiu $a1, 1 + beqz $v0, .end + nop + beq $v0, 0x0D, .end + nop + beq $v0, 0x0A, .end + nop + beq $v0, ' ', .end + nop + sb $v0, 0($a0) + b getline + addiu $a0, 1 +.end: + jr $ra + sb $0, 0($a0) + + +# strcasestr implementation +strcasestr: + # a0 - String to search + # a1 - String to find + addiu $sp, -24 + sw $ra, 0($sp) + sw $s0, 4($sp) + sw $s1, 8($sp) + sw $a1, 16($sp) + +.scan_start: + + sw $a0, 12($sp) + +.comp_loop: + + lbu $s0, 0($a0) # Load character from A and B + lbu $s1, 0($a1) + + beqz $s0, .end_strcasestr + nop + beqz $s1, .found + nop + + sw $a0, 20($sp) # Save a0 parameter + + jal toupper # tolower character A + move $a0, $s0 + move $s0, $v0 + + jal toupper # tolower character B + move $a0, $s1 + move $s1, $v0 + + lw $a0, 20($sp) # Restore a0 parameter + + addiu $a1, 1 + addiu $a0, 1 + + beq $s0, $s1, .comp_loop # If value matches continue compare + nop + +.end_strcasestr: + + lw $a0, 12($sp) # Rescan from next character of string A + lw $a1, 16($sp) + addiu $a0, 1 + + lbu $v0, 0($a0) + nop + beqz $v0, .not_found # If terminator is reached, string is not found + nop + + b .scan_start + nop + +.not_found: + + b .quit + move $v0, $0 + +.found: + + lw $v0, 12($sp) # Return address of string match + +.quit: + + lw $ra, 0($sp) + lw $s0, 4($sp) + lw $s1, 8($sp) + jr $ra + addiu $sp, 24 + + diff --git a/examples/cartrom/readme.txt b/examples/cartrom/readme.txt new file mode 100644 index 0000000..8d11a7f --- /dev/null +++ b/examples/cartrom/readme.txt @@ -0,0 +1,74 @@ +LibPSn00b Example Programs +Part of the PSn00bSDK Poject + +TurboBoot Example by Lameguy64 + + +Explanation: + +This example demonstrates how to create a ROM program to be used on a cheat +cartridge such as an Action Replay or Xplorer using GNU assembler. The program +stored in ROM is executed pretty much instantly on power-on. + +The PS1 BIOS can execute code from a ROM chip connected to the expansion port +(or Parallel I/O port) such as a cheat cartridge provided the valid headers +are present. However, the boot vectors are somewhat limited as it only +provides a preboot vector and a postboot vector. + +The preboot vector is executed at the earliest point of the BIOS start-up +sequence which means the RAM is almost completely blank and you can't execute +PS-EXEs from this point whearas the postboot vector is only executed between +the PS logo and game execution. To get around this limitation, the preboot +vector is used to execute code that places a breakpoint to a desired point +in memory and returns execution to the BIOS. This will effectively intercept +execution once it reaches the breakpoint allowing to run code from ROM with +an initialized kernel allowing for bootstrapping PS-EXEs from ROM, CD or +from a comms interface such as serial. + +The Xplorer and later Pro Action Replay cheat devices use this so called +'midboot' trick in their firmwares. + +In this TurboBoot example, the ROM program attempts to boot a PS-EXE from +CD using BIOS CD-ROM and file functions. It will also parse through the +SYSTEM.CNF to retrieve the file name of executable as well as some boot +parameters such as stack addres and number of TCBs and EvCBs. The ROM +program can fallback to attempting to load a PS-EXE named PSX.EXE if the +SYSTEM.CNF file does not exist like in the official BIOS. + +This example can also be used as a turbo boot utility as it boots straight +to the game, skipping the start-up animation altogether. It cannot be used +as a way to bypass the authentication check of an unmodified console however +(though it would help with bypassing the license data check on older Japanese +consoles) as the CD-ROM would only read data discs correctly IF the elusive +wobble groove containing the SCE string of the disc is present or when a +modchip is installed. It is possible to circumvent this by issuing special +'CD Unlock' commands (see nocash's psx-spx document) to the CD-ROM controller +which would effectively turn this into a chipless modchip solution that plugs +to the expansion port. However, the unlock commands only works on US and EU +consoles. + +It is possible and pretty trivial to boot a PS-EXE straight from ROM by +simply copying the program text from ROM to its desired location in RAM and +transferring execution to it. Such an example may be created in the future. + +This ROM program example had to be written entirely in assembly as C cannot +be used to write a ROM program even though it should be possible with some +assembly code to take care of the bootstrapping. GNU ld would complain about +'relocation truncation of R_MIPS_GPREL16' when you map program text to ROM +starting at 0x1f000000 (EXP ROM segment) and program data and bss sections +to RAM. Unknown how to get around this as all methods I've tried so far +either don't work or it just produces a massive binary file. + + +Building: + +To build this example, simply run make and a file named cartrom.rom should +be created. Run the ROM in no$psx (make sure a ISO image has been opened +first) or burn it to an Xplorer/PAR EEPROM (I recommend modding a PAR with +a DIP32 socket if you wish to program the chip externally which in many +cases would be easier). + + +Changelog: + +May 23, 2019 - Initial version. diff --git a/examples/cartrom/rom.ld b/examples/cartrom/rom.ld new file mode 100644 index 0000000..f3f9cd3 --- /dev/null +++ b/examples/cartrom/rom.ld @@ -0,0 +1,11 @@ +MEMORY { + ROM : ORIGIN = 0x1f000000, LENGTH = 256K +} + +ENTRY (entry) + +SECTIONS { + .text :{ + *(.text) + } >ROM +} diff --git a/examples/cartrom/rom.s b/examples/cartrom/rom.s new file mode 100644 index 0000000..14c1167 --- /dev/null +++ b/examples/cartrom/rom.s @@ -0,0 +1,399 @@ +# LibPSn00b Example Programs +# Part of the PSn00bSDk project +# +# TurboBoot Example by Lameguy64 +# + + +# 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 diff --git a/examples/rgb24/bunpattern.tim b/examples/rgb24/bunpattern.tim Binary files differnew file mode 100644 index 0000000..f233453 --- /dev/null +++ b/examples/rgb24/bunpattern.tim diff --git a/examples/rgb24/main.c b/examples/rgb24/main.c new file mode 100644 index 0000000..178ece2 --- /dev/null +++ b/examples/rgb24/main.c @@ -0,0 +1,52 @@ +/* LibPSn00b Example Programs + * Part of the PSn00bSDK Project + * + * RGB24 Example by Lameguy64 + * + * + * This example demonstrates the 24-bit color mode of the PS1. This mode is + * not practical for gameplay as the GPU can only draw graphics primitives + * in 16-bit color depth so this feature would normally be used only for + * fullscreen graphic illustrations or FMV sequences. + * + * + * Changelog: + * + * 05-03-2019 - Initial version. + * + */ + +#include <stdio.h> +#include <psxgte.h> +#include <psxgpu.h> + +// So data from tim.s can be accessed +extern unsigned int tim_image[]; + +int main() { + + DISPENV disp; + TIM_IMAGE tim; + + // Reset GPU + ResetGraph(0); + + // Setup 640x480 24-bit video mode + SetDefDispEnv(&disp, 0, 0, 640, 480); + disp.isrgb24 = 1; + disp.isinter = 1; + + // Apply and enable display + PutDispEnv(&disp); + SetDispMask(1); + + // Upload image to VRAM + GetTimInfo(tim_image, &tim); + LoadImage(tim.prect, tim.paddr); + DrawSync(); + + while(1) { + } + + return 0; +}
\ No newline at end of file diff --git a/examples/rgb24/makefile b/examples/rgb24/makefile new file mode 100644 index 0000000..ada9fbb --- /dev/null +++ b/examples/rgb24/makefile @@ -0,0 +1,41 @@ +include ../sdk-common.mk + +TARGET = rgb24.elf + +CFILES = $(notdir $(wildcard *.c)) +CPPFILES = $(notdir $(wildcard *.cpp)) +AFILES = $(notdir $(wildcard *.s)) + +OFILES = $(addprefix build/,$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) $(AFILES:.s=.o)) + +INCLUDE += +LIBDIRS += + +LIBS = -lc -lpsxgpu -lpsxapi -lgcc + +CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections +CPPFLAGS = $(CFLAGS) -fno-exceptions +AFLAGS = -g -msoft-float +LDFLAGS = -g -Ttext=0x80010000 -gc-sections + +CC = $(PREFIX)gcc +CXX = $(PREFIX)g++ +AS = $(PREFIX)as +LD = $(PREFIX)ld + +all: $(OFILES) + $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET) + elf2x -q $(TARGET) + +build/%.o: %.c + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +build/%.o: %.s + @mkdir -p $(dir $@) + $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@ + +build/%.o: %.tim + +clean: + rm -rf build $(TARGET) $(TARGET:.elf=.exe) diff --git a/examples/rgb24/tim.s b/examples/rgb24/tim.s new file mode 100644 index 0000000..a4432d9 --- /dev/null +++ b/examples/rgb24/tim.s @@ -0,0 +1,7 @@ +.section .data + +.global tim_image +.type tim_image, @object +tim_image: + .incbin "bunpattern.tim" +
\ No newline at end of file |
