PlayStation имеет прошивку, встроенную в плату - так называемый Kernel или BIOS (или просто OS в официальной документации). Код BIOS имеет объем в 512 KiB и находится по адресу 0xbfc00000 - так называемый вектор сброса, фиксированный адрес, куда CPU переходит для получения первой инструкции после включения.
BIOS стартует при включении питания. Под его данные зарезервированы нижние 64 KiB оперативной памяти, там же расположены таблицы и служебные структуры.
Примечание: в этой статье все адреса в памяти указаны в пространстве пользователя (KUSEG).
Чтобы загрузить игру, BIOS проверяет CD-ROM и, если обнаруживает диск, первым делом ищет в корне диска конфигурационный файл SYSTEM.CNF со строками вида <KEY> = <VALUE>. Строки разделяются парами CR-LF (0x0D, 0x0A). Поддерживаются следующие ключи:
Максимальное количество TCB-блоков и EvCB-блоков вычисляется по следующей формуле:
TCB * 192 + EVENT * 32 + 544 < 4096
Имя файла загрузочного образа во многих играх выглядит как XXXX_NNN.NN, например SLUS_123.45. Это соглашение о наименовании Sony для лицензионных дисков, оно не является требованием оборудования - можно назвать файл как угодно.
Если загрузочный образ не указан, или если SYSTEM.CNF отсутствует, то BIOS автоматически попытается загрузить файл PSX.EXE.
BIOS содержит множество функций, доступных для вызова программами.
Аргументы должны быть в [$a0 … $a3] (и в [$sp + 0x10, $sp + 0x14…] если их больше четырех).
Обязательно выделять на стеке место под нужное количество параметров! Хотя первые 4 параметра передаются через регистры, функция BIOS может модифицировать параметры на стеке [$sp+0..$sp+N-1].
Функции BIOS (и колбеки) могут перезаписывать регистры $1-$15 (переменные, аргументы, возвратные значения), $24-$25 (временные значения), $31 (адрес возврата), и hi/lo (результаты умножения и деления). Регистры $16-$23 (статические переменные), $29 (sp) и $30 (fp) сохраняются на стеке.
Возвратное значение функции, если оно есть, сохраняется в регистре $2.
A-Функции (вызов по адресу 0x00a0 с номером функции в регистре $t1):
0x00a0 - 0x0000 - int open(char* name, int mode) 0x00a0 - 0x0001 - int lseek(int fd, int offset, int whence) 0x00a0 - 0x0002 - int read(int fd, char* buf, int nbytes) 0x00a0 - 0x0003 - int write(int fd, char *buf, int nbytes) 0x00a0 - 0x0004 - close(int fd) 0x00a0 - 0x0005 - int ioctl(int fd, int cmd, int arg) 0x00a0 - 0x0006 - exit() 0x00a0 - 0x0007 - sys_b0_39() 0x00a0 - 0x0008 - char getc(int fd) 0x00a0 - 0x0009 - putc(char c , int fd) 0x00a0 - 0x000a - todigit 0x00a0 - 0x000b - double atof(char *s) 0x00a0 - 0x000c - long strtoul(char *s , char **ptr , int base) 0x00a0 - 0x000d - unsigned long strtol(char *s , char **ptr , int base) 0x00a0 - 0x000e - int abs(int val) 0x00a0 - 0x000f - long labs(long lval) 0x00a0 - 0x0010 - long atoi(char *s) 0x00a0 - 0x0011 - int atol(char *s) 0x00a0 - 0x0012 - atob 0x00a0 - 0x0013 - int setjmp(jmp_buf *ctx) 0x00a0 - 0x0014 - longjmp(jmp_buf *ctx , int value) 0x00a0 - 0x0015 - char *strcat(char *dst , char *src) 0x00a0 - 0x0016 - char *strncat(char *dst , char *src , int n) 0x00a0 - 0x0017 - int strcmp(char *dst , char *src) 0x00a0 - 0x0018 - int strncmp(char *dst , char *src , int n) 0x00a0 - 0x0019 - char *strcpy(char *dst , char *src) 0x00a0 - 0x001a - char *strncpy(char *dst , char *src , int n)) 0x00a0 - 0x001b - int strlen(char *s) 0x00a0 - 0x001c - int index(char *s , int c) 0x00a0 - 0x001d - int rindex(char *s , int c) 0x00a0 - 0x001e - char *strchr(char *c , int c) 0x00a0 - 0x001f - char *strrchr(char *c , int c) 0x00a0 - 0x0020 - char *strpbrk(char *dst , *src) 0x00a0 - 0x0021 - int strspn(char *s , char *set) 0x00a0 - 0x0022 - int strcspn(char *s , char *set) 0x00a0 - 0x0023 - strtok(char *s , char *set) 0x00a0 - 0x0024 - strstr(char *s , char *set) 0x00a0 - 0x0025 - int toupper(int c) 0x00a0 - 0x0026 - int tolower(int c) 0x00a0 - 0x0027 - void bcopy(void *src , void *dst , int len) 0x00a0 - 0x0028 - void bzero(void *ptr , int len) 0x00a0 - 0x0029 - int bcmp(void *ptr1 , void *ptr2 , int len) 0x00a0 - 0x002a - memcpy(void *dst , void *src , int n) 0x00a0 - 0x002b - memset(void *dst , char c , int n) 0x00a0 - 0x002c - memmove(void *dst , void *src , int n) 0x00a0 - 0x002d - memcmp(void *dst , void *src , int n) 0x00a0 - 0x002e - memchr(void *s , int c , int n) 0x00a0 - 0x002f - int rand() 0x00a0 - 0x0030 - void srand(unsigned int seed) 0x00a0 - 0x0031 - void qsort(void *base , int nel , int width , int (*cmp)*void *,void *)) 0x00a0 - 0x0032 - double strtod(char *s , char *endptr) 0x00a0 - 0x0033 - void *malloc(int size) 0x00a0 - 0x0034 - free(void *buf) 0x00a0 - 0x0035 - void *lsearch(void *key , void *base , int belp , int width , int (*cmp)(void * , void *)) 0x00a0 - 0x0036 - void *bsearch( void *key , void *base , int nel , int size , int (*cmp)(void * , void *)) 0x00a0 - 0x0037 - void *calloc(int size , int n) 0x00a0 - 0x0038 - void *realloc(void *buf , int n) 0x00a0 - 0x0039 - InitHeap(void *block , int n) 0x00a0 - 0x003a - _exit() 0x00a0 - 0x003b - char getchar(int fd) 0x00a0 - 0x003c - putchar(char c , int fd) 0x00a0 - 0x003d - char *gets(char *s) 0x00a0 - 0x003e - puts(char *s) 0x00a0 - 0x003f - printf(char *fmt , ...) 0x00a0 - 0x0041 - LoadTest(char *name , XF_HDR *header) 0x00a0 - 0x0042 - Load(char *name , XF_HDR *header) 0x00a0 - 0x0043 - Exec(struct EXEC *header , int argc , char **argc) 0x00a0 - 0x0044 - FlushCache() 0x00a0 - 0x0045 - void InstallInterruptHandler() 0x00a0 - 0x0046 - GPU_dw 0x00a0 - 0x0048 - int SetGPUStatus(int status) 0x00a0 - 0x0049 - GPU_cw 0x00a0 - 0x004a - GPU_cwb (not sure) 0x00a0 - 0x004d - int GetGPUStatus() 0x00a0 - 0x0049 - GPU_sync 0x00a0 - 0x0051 - LoadExec(char *name , int , int) 0x00x0 - 0x0052 - GetSysSp() 0x00a0 - 0x0054 - _96_init() 0x00a0 - 0x0055 - _bu_init() 0x00a0 - 0x0056 - _96_remove() 0x00a0 - 0x0057 - return 0 (it only does this) 0x00a0 - 0x0058 - return 0 (it only does this) 0x00a0 - 0x0059 - return 0 (it only does this) 0x00a0 - 0x005a - return 0 (it only does this) 0x00a0 - 0x005b - dev_tty_init 0x00a0 - 0x005c - dev_tty_open 0x00a0 - 0x005e - dev_tty_ioctl 0x00a0 - 0x005f - dev_cd_open 0x00a0 - 0x0060 - dev_cd_read 0x00a0 - 0x0061 - dev_cd_close 0x00a0 - 0x0062 - dev_cd_firstfile 0x00a0 - 0x0063 - dev_cd_nextfile 0x00a0 - 0x0064 - dev_cd_chdir 0x00a0 - 0x0065 - dev_card_open 0x00a0 - 0x0066 - dev_card_read 0x00a0 - 0x0067 - dev_card_write 0x00a0 - 0x0068 - dev_card_close 0x00a0 - 0x0069 - dev_card_firstfile 0x00a0 - 0x006a - dev_card_nextfile 0x00a0 - 0x006b - dev_card_erase 0x00a0 - 0x006c - dev_card_undelete 0x00a0 - 0x006d - dev_card_format 0x00a0 - 0x006e - dev_card_rename 0x00a0 - 0x0070 - _bu_init 0x00a0 - 0x0071 - _96_init 0x00a0 - 0x0072 - _96_remove 0x00a0 - 0x0078 - _96_CdSeekL 0x00a0 - 0x007c - _96_CdGetStatus 0x00a0 - 0x007e - _96_CdRead 0x00a0 - 0x0085 - _96_CdStop 0x00a0 - 0x0096 - AddCDROMDevice() 0x00a0 - 0x0097 - AddMemCardDevice() 0x00a0 - 0x0098 - DisableKernelIORedirection() 0x00a0 - 0x0099 - EnableKernelIORedirection() 0x00a0 - 0x009c - GetConf(int Event , int TCB , int Stack) 0x00a0 - 0x009d - GetConf(int *Event , int *TCB , int *Stack) 0x00a0 - 0x009f - SetMem(int size)
Следующие A-функции не поддерживаются на девборде DTL-H2000:
0x00a0 - 0x00a0 - _boot 0x00a0 - 0x00a1 - SystemError 0x00a0 - 0x00a2 - EnqueueCdIntr 0x00a0 - 0x00a3 - DequeueCdIntr 0x00a0 - 0x00a5 - ReadSector(count,sector,buffer) 0x00a0 - 0x00a6 - get_cd_status 0x00a0 - 0x00a7 - bufs_cb_0 0x00a0 - 0x00a8 - bufs_cb_1 0x00a0 - 0x00a9 - bufs_cb_2 0x00a0 - 0x00aa - bufs_cb_3 0x00a0 - 0x00ab - _card_info 0x00a0 - 0x00ac - _card_load 0x00a0 - 0x00ad - _card_auto 0x00a0 - 0x00ae - bufs_cb_4 0x00a0 - 0x00af - card_write_test(port) ;CEX-1000: jump_to_00000000h 0x00a0 - 0x00b0 - return 0 ;CEX-1000: jump_to_00000000h 0x00a0 - 0x00b1 - return 0 ;CEX-1000: jump_to_00000000h 0x00a0 - 0x00b2 - ioabort_raw(param) ;CEX-1000: jump_to_00000000h 0x00a0 - 0x00b3 - return 0 ;CEX-1000: jump_to_00000000h 0x00a0 - 0x00b4 - GetSystemInfo(index) ;CEX-1000: jump_to_00000000h
B-Функции(вызов по адресу 0x00b0 с номером функции в регистре $t1):
0x00b0 - 0x0000 - SysMalloc (to malloc kernel memory) 0x00b0 - 0x0007 - DeliverEvent(class , event) 0x00b0 - 0x0008 - OpenEvent(class , spec , mode , func) (source code is corrected) 0x00b0 - 0x0009 - CloseEvent(event) 0x00b0 - 0x000a - WaitEvent(event) 0x00b0 - 0x000b - TestEvent(event) 0x00b0 - 0x000c - EnableEvent(event) 0x00b0 - 0x000d - DisableEvent(event) 0x00b0 - 0x000e - OpenTh(reg_PC,reg_SP_FP,reg_GP) 0x00b0 - 0x000f - CloseTh(handle) 0x00b0 - 0x0010 - ChangeTh(handle) 0x00b0 - 0x0011 - jump_to_00000000h 0x00b0 - 0x0012 - InitPad2(buf1,siz1,buf2,siz2) 0x00b0 - 0x0013 - StartPad2() 0x00b0 - 0x0014 - StopPad2() 0x00b0 - 0x0015 - pad_init(type,button_dest,unused,unused) 0x00b0 - 0x0016 - u_long pad_dr() 0x00b0 - 0x0017 - ReturnFromException() 0x00b0 - 0x0018 - ResetEntryInt() 0x00b0 - 0x0019 - HookEntryInt(addr) 0x00b0 - 0x001a - SystemError ;PS2: return 0 0x00b0 - 0x001b - SystemError ;PS2: return 0 0x00b0 - 0x001c - SystemError ;PS2: return 0 0x00b0 - 0x001d - SystemError ;PS2: return 0 0x00b0 - 0x001e - SystemError ;PS2: return 0 0x00b0 - 0x001f - SystemError ;PS2: return 0 0x00b0 - 0x0020 - UnDeliverEvent(class, event) 0x00b0 - 0x0021 - SystemError ;PS2: return 0 0x00b0 - 0x0022 - SystemError ;PS2: return 0 0x00b0 - 0x0023 - SystemError ;PS2: return 0 0x00b0 - 0x0024 - jump_to_00000000h 0x00b0 - 0x0025 - jump_to_00000000h 0x00b0 - 0x0026 - jump_to_00000000h 0x00b0 - 0x0027 - jump_to_00000000h 0x00b0 - 0x0028 - jump_to_00000000h 0x00b0 - 0x0029 - 9jump_to_00000000h 0x00b0 - 0x002a - SystemError ;PS2: return 0 0x00b0 - 0x002b - SystemError ;PS2: return 0 0x00b0 - 0x002c - jump_to_00000000h 0x00b0 - 0x002d - jump_to_00000000h 0x00b0 - 0x002e - jump_to_00000000h 0x00b0 - 0x002f - jump_to_00000000h 0x00b0 - 0x0030 - jump_to_00000000h 0x00b0 - 0x0031 - jump_to_00000000h 0x00b0 - 0x0032 - int open(char *name,int access) 0x00b0 - 0x0033 - int lseek(int fd,long pos,int seektype) 0x00b0 - 0x0034 - int read(int fd,void *buf,int nbytes) 0x00b0 - 0x0035 - int write(int fd,void *buf,int nbytes) 0x00b0 - 0x0036 - close(int fd) 0x00b0 - 0x0037 - int ioctl(int fd , int cmd , int arg) 0x00b0 - 0x0038 - exit(int exitcode) 0x00b0 - 0x003a - char getc(int fd) 0x00b0 - 0x003b - putc(int fd,char ch) 0x00b0 - 0x003c - char getchar() 0x00b0 - 0x003d - putchar(char ch) 0x00b0 - 0x003e - char *gets(char *s) 0x00b0 - 0x003f - puts(char *s) 0x00b0 - 0x0040 - cd(name) 0x00b0 - 0x0041 - format(devicename) 0x00b0 - 0x0042 - firstfile2(filename,direntry) 0x00b0 - 0x0043 - nextfile(direntry) 0x00b0 - 0x0044 - rename(old_filename,new_filename) 0x00b0 - 0x0045 - delete(filename) 0x00b0 - 0x0046 - undelete(filename) 0x00b0 - 0x0047 - AddDrv(device_info) ;subfunction for AddXxxDevice functions 0x00b0 - 0x0048 - DelDrv(device_name_lowercase) 0x00b0 - 0x0049 - PrintInstalledDevices()
Следующие B-функции не поддерживаются на девборде DTL-H2000:
0x00b0 - 0x004a - InitCARD 0x00b0 - 0x004b - StartCARD 0x00b0 - 0x004c - StopCARD 0x00b0 - 0x004e - _card_write 0x00b0 - 0x004f - _card_read 0x00b0 - 0x0050 - _new_card 0x00b0 - 0x0051 - Krom2RawAdd 0x00b0 - 0x0054 - long _get_errno(void) 0x00b0 - 0x0055 - long _get_error(long fd) 0x00b0 - 0x0056 - GetC0Table 0x00b0 - 0x0057 - GetB0Table 0x00b0 - 0x0058 - _card_chan 0x00b0 - 0x005b - ChangeClearPad(int) 0x00b0 - 0x005c - _card_status 0x00b0 - 0x005d - _card_wait 0x00b0 - 0x005e..0x00ff = N/A ;jump_to_00000000h
C-Функции(вызов по адресу 0x00c0 с номером функции в регистре $t1):
0x00c0 - 0x0000 - EnqueueTimerAndVblankIrqs(priority) ;used with prio=1 0x00c0 - 0x0001 - EnqueueSyscallHandler(priority) ;used with prio=0 0x00c0 - 0x0002 - SysEnqIntRP(int index , long *queue) 0x00c0 - 0x0003 - SysDeqIntRP(int index , long *queue) 0x00c0 - 0x0004 - get_free_EvCB_slot() 0x00c0 - 0x0005 - get_free_TCB_slot() 0x00c0 - 0x0006 - ExceptionHandler() 0x00c0 - 0x0007 - InstallExceptionHandlers() ;destroys/uses k0/k1 0x00c0 - 0x0008 - SysInitMemory(addr,size) 0x00c0 - 0x0009 - SysInitKernelVariables() 0x00c0 - 0x000a - ChangeClearRCnt(t,flag) 0x00c0 - 0x000b - SystemError 0x00c0 - 0x000c - InitDefInt(priority) ;used with prio=3 0x00c0 - 0x000d - SetIrqAutoAck(irq,flag) 0x00c0 - 0x000e - return 0 ;DTL-H2000: dev_sio_init 0x00c0 - 0x000f - return 0 ;DTL-H2000: dev_sio_open 0x00c0 - 0x0010 - return 0 ;DTL-H2000: dev_sio_in_out 0x00c0 - 0x0011 - return 0 ;DTL-H2000: dev_sio_ioctl 0x00c0 - 0x0012 - InstallDevices(ttyflag) 0x00c0 - 0x0013 - FlushStdInOutPut() 0x00c0 - 0x0014 - return 0 ;DTL-H2000: SystemError 0x00c0 - 0x0015 - _cdevinput(circ,char) 0x00c0 - 0x0016 - _cdevscan() 0x00c0 - 0x0017 - char _circgetc(struct device_buf* circ) ;uses r5 as garbage txt for _ioabort 0x00c0 - 0x0018 - _circputc(char c, struct device_buf* circ) 0x00c0 - 0x0019 - ioabort(char* txt1, char* txt2) 0x00c0 - 0x001a - set_card_find_mode(mode) ;0=normal, 1=find deleted files 0x00c0 - 0x001b - KernelRedirect(int ttyflag) ;PS2: ttyflag=1 causes SystemError 0x00c0 - 0x001c - AdjustA0Table() 0x00c0 - 0x001d - get_card_find_mode() 0x00c0 - 0x001e..0x007f - N/A ;jump_to_00000000h
SYS-Функции - вызываются инструкцией syscall с номером функции в регистре $a0:
li $a0, 0x00 syscall
syscall 0x00 - NoFunction() syscall 0x01 - EnterCriticalSection() syscall 0x02 - ExitCriticalSection() syscall 0x03 - ChangeThreadSubFunction(addr) ;syscall with r4=03h, r5=addr syscall 0x04 и выше - DeliverEvent(0xF0000010, 0x4000)