====== BIOS ====== PlayStation имеет прошивку, встроенную в плату - так называемый Kernel или BIOS (или просто OS в официальной документации). Код BIOS имеет объем в 512 KiB и находится по адресу 0xbfc00000 - так называемый вектор сброса, фиксированный адрес, куда [[mips_r3000|CPU]] переходит для получения первой инструкции после включения. BIOS стартует при включении питания. Под его данные зарезервированы нижние 64 KiB оперативной памяти, там же расположены таблицы и служебные структуры. Примечание: в этой статье все адреса в памяти указаны в пространстве пользователя (KUSEG). ===== Порядок загрузки ===== Чтобы загрузить игру, BIOS проверяет CD-ROM и, если обнаруживает диск, первым делом ищет в корне диска конфигурационный файл SYSTEM.CNF со строками вида = . Строки разделяются парами CR-LF (0x0D, 0x0A). Поддерживаются следующие ключи: * BOOT - [[psx_exe|загрузочный образ]]. Значение должно быть в формате Device:\Product;Version Argument. Значение по умолчанию: cdrom:\PSX.EXE;1. Version - это ISO9660 уровень, для CD это всегда 1. Значение Argument (128 байт) опционально; оно копируется в адрес 0x00000180, откуда можно его прочитать, но чаще всего это не используется; * STACK - адрес начала стека в формате 0xXXXXXXXX. Это значение приоритетом выше, чем то, что задано в заголовке загрузочного образа (см. далее). Значение по умолчанию: 0x801FFF00; * TCB - количество контрольных блоков задач ([[tcb|TCB]]). Число в шестнадцатеричном формате. Значение по умолчанию: 4. Минимум: 1; * EVENT - количество блоков обработки событий ([[evcb|EvCB]]). Число в шестнадцатеричном формате. Значение по умолчанию: 0x10. Минимум: 0. Максимальное количество 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 ===== * SCPH-1000 - Оригинальный японский BIOS. Выпущен в Японии 12/3/94. * SCPH-1001 - Оригинальный североамериканский BIOS. Выпущен в Северной Америке 9/9/95. Нет выхода S-Video. * SCPH-1002 - Оригинальный европейский BIOS. Как и в SCPH-1001, нет выхода S-Video. * SCPH-3000 - Японская ревизия. * SCPH-3500 - Японская ревизия. Убран выход S-Video. * SCPH-5003 - Азиатская ревизия. * SCPH-5500 / ps-30j.bin (MD5: 8DD7D5296A650FAC7319BCE665A6A53C) - Японская ревизия. Механизм дисковода был перемещен, электроника на плате уменьшена примерно на 20%, отдельные порты для композитного A/V вывода были заменены портом A/V Multi Out. * SCPH-5501 / ps-30a.bin (MD5: 490F666E1AFB15B7362B406ED1CEA246) - Североамериканская версия 5500. * SCPH-5502 / ps-30e.bin (MD5: md5 32736f17079d0b2b7024407c39bd3050) - Европейская версия 5500. * SCPH-5552 - Европейская ревизия. * SCPH-5903 - Специальное бело-цветное издание PlayStation "Video CD", выпущенное только в большей части Азии. * SCPH-7000 - Первая японская аппаратная ревизия с Dual Shock. В комплект входил один контроллер Dual Shock (SCPH-1200), имеется программа светомузыки под названием SoundScope в меню CD-плеера (на самом деле это урезанная версия Baby Universe). * SCPH-7001 - Североамериканская 7000. * SCPH-7002 - Европейская 7000. * SCPH-7003 - Азиатская 7000. * SCPH-7500 - Японская ревизия. Дальнейшее уменьшение размеров материнской платы, переработанный системный BIOS. Sony выпустила это как "защищенную от модов" систему, но её довольно быстро взломали. * SCPH-7501 - Североамериканская 7500. * SCPH-7502 - Европейская 7500. * SCPH-7503 - Обновленная японская 7500. * SCPH-9000 - Японская ревизия. Дальнейшее уменьшение размеров материнской платы, плюс полное удаление параллельного I/O порта, чтобы попытаться помешать тем, кто делает чит-устройства и другие подобные продукты, которые подключаются к этому порту. Последняя серия аппаратных ревизий PS до SCPH-100 redesign. * SCPH-9001 - Североамериканская 9000. * SCPH-9002 - Европейская 9000. * SCPH-9003 - Азиатская 9000. * SCPH-100 - Также известна как PS one. Размер устройства уменьшен на треть, питание осуществляется от внешнего адаптера переменного тока, а не от внутреннего блока питания. Обновленный интерфейс BIOS. Оригинальная японская версия. * SCPH-101 - Североамериканская 100. * SCPH-102 - Европейская 100. * PSXONPSP660.bin (MD5: C53CA5908936D412331790F4426C6C33) - BIOS PSX, включенный в прошивку PSP 6.60. Он был доработан Sony по сравнению с традиционными версиями BIOS, извлеченными из аппаратного обеспечения PSX. Этот BIOS обеспечивает повышенную производительность и совместимость во всех эмуляторах и не зависит от региона.