Содержание

BIOS

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)

Список версий BIOS