Difference between revisions of "BIOS"

From PSXDEV
Jump to: navigation, search
(Big Main)
(Big Main)
Line 342: Line 342:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
== Big Main ==
+
== Bootrom Main ==
  
 
<syntaxhighlight lang="c">
 
<syntaxhighlight lang="c">
 
//
 
//
// Big Main
+
// Bootrom Main
 
//
 
//
 +
 +
// Sometimes we need to re-mute SPU (why?)
  
 
#define MUTE_SPU() \
 
#define MUTE_SPU() \
Line 354: Line 356:
 
word.[0x1F801C00 + 0x182] = 0; \
 
word.[0x1F801C00 + 0x182] = 0; \
 
word.[0x1F801C00 + 0x180] = 0;
 
word.[0x1F801C00 + 0x180] = 0;
 +
 +
typedef struct _SYSTEM_CONFIG
 +
{
 +
    SIZE_R      Tcb;            // Max number of threads
 +
    SIZE_T      Event;          // Max number of events
 +
    PVOID      Stack;          // Initial stack pointer
 +
} SYSTEM_CONFIG, *PSYSTEM_CONFIG;
 +
 +
SYSTEM_CONFIG DefaultConfig = {        // 0xBFC0E14C
 +
    4,
 +
    16,
 +
    0x801FFF00
 +
};
  
 
void Main (char *Config, char *Exec )      // 0xBFC067E8
 
void Main (char *Config, char *Exec )      // 0xBFC067E8
 
{
 
{
     //
+
     int File;
     // 1
+
     long Bytes;
    //
+
  
    TraceStep (1);
+
//
 +
// Disable all interupts, External (level 3) interrupts are disabled
 +
//
  
    v0 = sub_BFC03968 ();
+
TraceStep (1);
  
    sub_BFC03978 ( v0 & 0xFFFFFBFE );
+
SetSr ( GetSr () & 0xFFFFFBFE );
  
    MUTE_SPU ();
+
MUTE_SPU ();
  
    //
+
//
    // 2
+
// Copy kernel image from Bootrom and run its initialization code.
    //
+
//
  
    TraceStep (2);
+
TraceStep (2);
  
    sub_BFC00420 ();
+
LoadInitKernel ();
  
    //
+
//
    // 3
+
// Initialize kernel traps
    //
+
//
  
    TraceStep (3);
+
TraceStep (3);
  
    sub_BFC042D0 ();
+
CopyBootapiTable ();       // Copy BIOS shared procedure callbacks at 0x200
  
    sub_BFC042A0 ();
+
InitSyscall ();       // Copy 0xA0, 0xB0 and 0xC0 syscall stubs from kernel image
  
    sub_BFC0DB10 ();
+
PatchA0Table ();
  
    sub_BFC0DB20 ();
+
InstallExceptionHandlers ();
  
    sub_BFC0D9A0 ();
+
ResetEntryInt ();
  
    //
+
//
    // 4
+
// Init device drivers
    //
+
//
  
    TraceStep (4);
+
TraceStep (4);
  
    MUTE_SPU ();
+
MUTE_SPU ();
  
    dword.0x1F801074 = 0;
+
dword.0x1F801074 = 0;     // int_mask
    dword.0x1F801070 = 0;
+
dword.0x1F801070 = 0;     // int_reg
  
    sub_BFC0DB30 ( dword_B9B0 );
+
InstallDevices ( dword_B9B0 );
  
    //
+
//
    // 5
+
// Shout out first printf
    //
+
//
  
    TraceStep (5);
+
TraceStep (5);
  
    printf ( "\n"  
+
printf ( "\n"  
    "PS-X Realtime Kernel Ver.2.5\n"
+
"PS-X Realtime Kernel Ver.2.5\n"
    "Copyright 1993,1994 (C) Sony Computer Entertainment Inc. \n" );
+
"Copyright 1993,1994 (C) Sony Computer Entertainment Inc. \n" );
  
    //
+
//
    // 6
+
// Init Kernel executive
    //
+
//
  
    TraceStep (6);
+
TraceStep (6);
  
    MUTE_SPU ();
+
MUTE_SPU ();
  
    sub_BFC02B50 ( 0xA000B940, 0xBFC0E14C, 0xC );
+
memcpy ( 0xA000B940, &DefaultConfig, sizeof(SYSTEM_CONFIG) );
  
    printf ( "KERNEL SETUP!\n" );
+
printf ( "KERNEL SETUP!\n" );
  
    sub_BFC0DB40 ( 0xA000E000, 0x2000 );
+
SysInitMemory ( 0xA000E000, 0x2000 );     // Kernel heap
  
    sub_BFC04610 (4);
+
InitEventHandlers (4);
  
    sub_BFC0DB50 (0)
+
InitException (0)
  
    sub_BFC0DB60 (3);
+
InitDefInt (3);
  
    sub_BFC04678 ( dword_B944 );
+
InitEvents ( dword_B944 );
  
    sub_BFC0472C ( 1, dword_B940 );
+
InitThreads ( 1, dword_B940 );
  
    sub_BFC0DB70 (1);
+
InitRCnt (1);
  
    MUTE_SPU ();
+
MUTE_SPU ();
  
    v0 = sub_BFC02240 ( 0xA000B980 );
+
if ( setjmp ( 0xA000B980 ) )
 +
SystemHalt (901);
  
    if ( v0 )
+
//
    sub_BFC06FA4 ( 0x385 );
+
// Run Shell
 +
//
 +
 
 +
TraceStep (7);
 +
 
 +
LoadRunShell (a0);
 +
 
 +
//
 +
// 8
 +
//
 +
 
 +
TraceStep (8);
 +
 
 +
dword.0x1F801074 = 0;      // int_mask
 +
dword.0x1F801070 = 0;      // int_reg
 +
 
 +
sub_BFC073A0 ();
 +
 
 +
if ( setjmp ( 0xA000B980 ) )
 +
SystemHalt (921);
  
 
     //
 
     //
     // 7
+
     // PIO Shell
 
     //
 
     //
  
    TraceStep (7);
+
if ( CheckPIO2 () == 1 )
 +
BootPIO ();
 +
 
 +
printf ( "\n"
 +
"BOOTSTRAP LOADER Type C Ver 2.1  03-JUL-1994\n"
 +
"Copyright 1993,1994 (C) Sony Computer Entertainment Inc.\n" );
 +
 
 +
if ( setjmp ( 0xA000B980 ) )
 +
SystemHalt (902);
 +
 
 +
//
 +
// Load executable from external media.
 +
//
 +
 
 +
TraceStep (9);
  
    sub_BFC06FF0 ();
+
if ( setjmp ( 0xA000B980) )
 +
SystemHalt (903);
  
 
     //
 
     //
     // 8
+
     // Try to open system config file.
 +
    // If config file is missing fall back to plain EXE loading
 
     //
 
     //
  
    TraceStep (8);
+
File = open ( Config, O_RDONLY );
  
    dword.0x1F801074 = 0;
+
if ( File >= 0 )
    dword.0x1F801070 = 0;
+
{
 +
        //
 +
        // Read and parse config file parameters
 +
        //
  
    sub_BFC073A0 ();
+
printf ( "setup file    : %s\n", Config );
  
    v0 = sub_BFC02240 ( 0xA000B980 );
+
if ( setjmp ( 0xA000B980 ) )
 +
SystemHalt (911);
  
    if ( v0 )
+
Bytes = read ( File, 0xA000B070, 0x800 );
    sub_BFC06FA4 ( 0x399 );
+
  
    v0 = sub_BFC070AC ();
+
if ( Bytes )
 +
{
 +
0xA000B070[Bytes] = 0;   // Terminate string
  
    if ( v0 == 1 )
+
close ( File );
    sub_BFC07148 ();
+
  
    printf ( "\n"
+
if ( setjmp ( 0xA000B980 ) )
    "BOOTSTRAP LOADER Type C Ver 2.1  03-JUL-1994\n"
+
SystemHalt ( 912 );
    "Copyright 1993,1994 (C) Sony Computer Entertainment Inc.\n" );
+
  
    v0 = sub_BFC02240 ( 0xA000B980 );
+
ParseConfig ( 0xA000B070, 0xA000B940, 0xA000B8B0 );
 +
}
 +
else
 +
{
 +
            //
 +
            // Set default config, fall back to plain EXE loading
 +
            //
  
    if ( v0 )
+
memcpy ( 0xA000B940, &DefaultConfig, sizeof(SYSTEM_CONFIG) );
    sub_BFC06FA4 ( 0x386 );
+
strcpy ( 0xA000B8B0, Exec );
 +
}
 +
}
 +
else
 +
{
 +
        //
 +
        // Use plain executable
 +
        //
  
 +
if ( setjmp ( 0xA000B980 ) )
 +
SystemHalt (913);
 +
 +
byte.0x180 = 0;  // Version number
 +
memcpy ( 0xA000B940, &DefaultConfig, sizeof(SYSTEM_CONFIG) );
 +
strcpy ( 0xA000B8B0, Exec );
 +
}
 +
 +
//
 +
// Load executable
 +
//
 +
 +
if ( setjmp ( 0xA000B980 ) )
 +
SystemHalt (904);
 +
 +
ReinitKernel ();
 +
 +
printf ( "boot file    : %s\n", 0xA000B8B0 );
 +
 +
if ( setjmp ( 0xA000B980 ) )
 +
SystemHalt (905);
 +
 +
ClearStack ();
 +
 +
if ( LoadExec (0xA000B8B0, 0xA000B870 ) == 0 )
 +
SystemHalt (906);
 +
 +
printf ( "EXEC:PC0(%08x)  T_ADDR(%08x)  T_SIZE(%08x)\n", dword_B870, dword_B878, dword_B87C );
 +
 +
printf ( "boot address  : %08x %08x\n"
 +
"Execute !\n\n", dword_B870, dword_B948 );
 +
 +
dword_B890 = dword_B948;
 +
dword_B894 = 0;
 +
 +
printf ( "                S_ADDR(%08x)  S_SIZE(%08)\n", dword_B948, 0 );
 +
 +
EnterCriticalSection ();
 +
 +
if ( setjmp ( 0xA000B980 ) )
 +
SystemHalt (907);
 +
 +
sub_BFC0D570 (0xA000B870, 1, 0 );
 +
 +
printf ( "End of Main\n" );
 +
 +
SystemHalt (908);
 +
}
 +
 +
//
 +
// Support
 +
//
 +
 +
// Written in asm.
 +
int setjmp ( jmp_buf * Buffer )      // 0xBFC02240
 +
{
 +
    Buffer[JB_PC] = ra;
 +
    Buffer[JB_GP] = gp;
 +
    Buffer[JB_SP] = sp;
 +
    Buffer[JB_FP] = fp;
 +
    Buffer[JB_S0] = s0;
 +
    Buffer[JB_S1] = s1;
 +
    Buffer[JB_S2] = s2;
 +
    Buffer[JB_S3] = s3;
 +
    Buffer[JB_S4] = s4;
 +
    Buffer[JB_S5] = s5;
 +
    Buffer[JB_S6] = s6;
 +
    Buffer[JB_S7] = s7;
 +
    return 0;
 +
}
 +
 +
void SystemHalt (int Code)      // 0xBFC06FA4
 +
{
 +
    TraceStep (0xF);
 +
    SystemError ( 'B', Code );
 +
}
 +
 +
ULONG GetSr (void)          // 0xBFC03968
 +
{
 +
    return COP0.SR;
 +
}
 +
 +
void SetSr (ULONG Value)        // 0xBFC03978
 +
{
 +
    COP0.SR = Value;
 +
}
 +
 +
void LoadInitKernel ()        // 0xBFC00420
 +
{
 +
    memcpy ( 0xA0000500, 0xBFC10000, 0x8BF0 );
 +
 +
    0xA0000500 ();      // Run kernel initialization
 +
}
 +
 +
CopyBootapiTable ()        // 0xBFC042D0
 +
{
 +
    memcpy ( 0x200, 0xBFC04300, 0x304 );
 +
}
 +
 +
InitSyscall ()        // 0xBFC042A0
 +
{
 
     //
 
     //
     // 9
+
     // Copy 0xA0, 0xB0 and 0xC0 syscall stubs from kernel image
 
     //
 
     //
  
     TraceStep (9);
+
     memcpy ( 0xA0, 0xA0000510, 0x30 );
 +
}
  
     v0 = sub_BFC02240 ( 0xA000B980);
+
ClearStack ()        // 0xBFC0D850
 +
{
 +
     PVOID StartAddress;
 +
    PVOID EndAddress;
 +
    StartAddress = 0xA0010000;
 +
    EndAddress = sp | 0xA0000000;
 +
    memset ( StartAddress, 0, EndAddress - StartAddress );
 +
}
  
    if ( v0 )
+
ReinitKernel ()     // 0xBFC06F28
    sub_BFC06FA4 (0x387);
+
{
 +
    printf ( "KERNEL SETUP!\n" );
  
     var_4 = sub_BFC0D890 ( Config, 1 );
+
     SysInitMemory ( 0xA000E000, 0x2000 );       // Kernel heap
  
     if ( var_4 >= 0 )
+
     InitEventHandlers (4);
    {
+
    printf ( "setup file    : %s\n", Config );
+
  
    v0 = sub_BFC02240 ( 0xA000B980 );
+
    InitException (0);
  
    if ( v0 )
+
    InitDefInt (3);
    sub_BFC06FA4 ( 0x38F );
+
  
    v1 = sub_BFC0D8B0 ( var_4, 0xA000B070, 0x800 );
+
    InitEvents ( dword_B944 );
  
    if ( v1 )
+
    InitThreads ( 1, dword_B940 );
    {
+
    0xA000B070[v1] = 0;
+
  
    sub_BFC0D8A0 ( var_4 );
+
    InitRCnt (1);
  
    v0 = sub_BFC02240 ( 0xA000B980 );
+
    sub_BFC071A0 ();
    if ( v0 )
+
}
    sub_BFC06FA4 ( 0x390 );
+
  
    sub_BFC008A0 ( 0xA000B070, 0xA000B940, 0xA000B8B0 );
+
char Licensed[] = "Licensed by Sony Computer Entertainment Inc.";       // 0xBFC0E288
    }
+
    else
+
    {
+
    sub_BFC02B50 ( 0xA000B940, 0xBFC0E14C, 0xC );
+
  
    strcpy ( 0xA000B8B0, Exec );
+
int CheckPIO2 ()         // 0xBFC070AC
    }
+
{
     }
+
     char * Source = Licensed;
     else
+
     char * Dest = 0x1F000004;      // PIO Header 2
 +
 
 +
    while ( *Source )
 
     {
 
     {
    v0 = sub_BFC02240 ( 0xA000B980 );
+
        if ( *Source != *Dest ) break;
    if ( v0 )
+
    sub_BFC06FA4 (0x391);
+
  
    byte.0x180 = 0;
+
        Source++;
 +
        Dest++;
 +
    }
  
    sub_BFC02B50 ( 0xA000B940, 0xBFC0E14C, 0xC );
+
    if ( *Source ) return 0;
 +
    else return 1;   
 +
}
  
    strcpy ( 0xA000B8B0, Exec );
+
BootPIO ()      // 0xBFC07148
 +
{
 +
    printf ( "PIO SHELL for PlayStation(tm)\n" );
 +
 
 +
    printf ( "%s\n", 0x1F000004 );
 +
 
 +
    dword.0x1F000000 ();        // Jump by pointer.
 +
}
 +
 
 +
void ParseConfig (char *Text, PSYSTEM_CONFIG Config, char *Exec )     // 0xBFC008A0
 +
{
 +
    Config->Tcb = 0;
 +
    Config->Event = 0;
 +
    Config->Stack = 0;
 +
 
 +
    Exec[0] = '\0';
 +
    byte.0x180 = 0;        // Version number
 +
 
 +
    ParseConfigInt ( Text, &Config->Tcb, "TCB" );
 +
 
 +
    ParseConfigInt ( Text, &Config->Event, "EVENT" );
 +
 
 +
    ParseConfigInt ( Text, &Config->Stack, "STACK" );
 +
 
 +
    ParseConfigString ( Text, Exec, 0x180, "BOOT" );
 +
}
 +
 
 +
LoadRunShell (a0)    // 0xBFC06FF0
 +
{
 +
    memcpy ( 0x80030000, 0xBFC18000, 0x67FF0 );
 +
 
 +
    FlushCache ();
 +
 
 +
    0x80030000 (a0);
 +
}
 +
 
 +
//
 +
// Executive init
 +
//
 +
 
 +
int InitEventHandlers (int Num)  // 0xBFC04610
 +
{
 +
    int Bytes = Num * 8;
 +
    Pointer = SysMalloc ( Bytes );
 +
 
 +
    if ( Pointer )
 +
    {
 +
        memclr ( Pointer, Bytes );
 +
        dword_100 = Pointer;
 +
        dword_104 = Bytes;
 +
        return Bytes;
 
     }
 
     }
 +
    else return 0;
 +
}
  
    //
+
PVOID InitEvents (int Num)    // 0xBFC04678
     //
+
{
     //
+
     int Bytes;
 +
     int n;
 +
    PVOID Pointer;
 +
    EvCB * Event;
  
     v0 = sub_BFC02240 ( 0xA000B980 );
+
     printf ( "\nConfiguration : EvCB\t0x%02x\t\t", Num );
    if ( v0 )
+
    sub_BFC06FA4 ( 0x388 );
+
  
     sub_BFC06F28 ();
+
     Bytes = Num * sizeof (EvCB);
 +
    Pointer = SysMalloc (Bytes);
  
     printf ( "boot file    : %s\n", 0xA000B8B0 );
+
     if ( Pointer )
 +
    {
 +
        dword_124 = Pointer;
 +
        dword_120 = Bytes;
  
    v0 = sub_BFC02240 ( 0xA000B980 );
+
        //
    if ( v0 )
+
        // Clear "status" field for all event CBs.
    sub_BFC06FA4 ( 0x389 );
+
        //
  
    sub_BFC0D850 ();
+
        for (n=0; n<Num; n++)
 +
        {
 +
            Event = &dword_124[n];
 +
            Event->status = 0;
 +
        }
  
     v0 = sub_BFC03A18 (0xA000B8B0, 0xA000B870 );
+
        return Pointer;
 +
    }
 +
     else return 0;
 +
}
  
    if ( v0 == 0 )
+
int InitThreads (int Tcbh, int Tcb)     // 0xBFC0472C
    sub_BFC06FA4 ( 0x38A );
+
{
 +
    TCBH * TCBH_Ptr;
 +
    TCB * TCB_Ptr;
 +
    TCBH * TcbhEntry;
 +
    TCBH * TcbEntry;
 +
    int n;
  
     printf ( "EXEC:PC0(%08x)  T_ADDR(%08x)  T_SIZE(%08x)\n", dword_B870, dword_B878, dword_B87C );
+
     printf ( "TCB\t0x%02x\n", Num );
  
     printf ( "boot address  : %08x %08x\n"
+
     dword_10C = Tcbh * 4;      // BUGCHECK: Should be actually 8, since TCBH has additional "flag" field deinfed in KERNEL.H
    "Execute !\n\n", dword_B870, dword_B948 );
+
    dword_114 = Tcb * 192;
  
     dword_B890 = dword_B948;
+
     TCBH_Ptr = SysMalloc ( dword_10C );
     dword_B894 = 0;
+
     if ( TCBH_Ptr == NULL )
 +
        return 0;
  
     printf ( "                S_ADDR(%08x) S_SIZE(%08)\n", dword_B948, 0 );
+
     TCB_Ptr = SysMalloc ( dword_114 );
 +
    if ( TCB_Ptr == NULL )
 +
        return 0;
  
     sub_BFC0D960 ();
+
     //
 +
    // Clear TCBH
 +
    //
  
     v0 = sub_BFC02240 ( 0xA000B980 );
+
     for (n=0; n<Tcbh; n++)
     if ( v0 )
+
     {
    sub_BFC06FA4 ( 0x38B );
+
        TcbhEntry = &TCBH_Ptr[n];
 +
        TcbhEntry->entry = NULL;
 +
    }
  
     sub_BFC0D570 (0xA000B870, 1, 0 );
+
     //
 +
    // Clear TCB
 +
    //
 +
 
 +
    for (n=0; n<Tcb; n++)
 +
    {
 +
        TcbEntry = &TCB_Ptr[n];
 +
        TcbEntry->status = TcbStUNUSED;
 +
    }
 +
 
 +
    //
 +
    // Set active first TCB entry
 +
    //
 +
 
 +
    TCB_Ptr[0].status = TcbStACTIVE;
 +
    TCBH_Ptr[0].entry = TCB_Ptr;
 +
 
 +
    //
 +
    // Update ToT
 +
    //
  
     printf ( "End of Main\n" );
+
     dword_108 = TCBH_Ptr;
 +
    dword_110 = TCB_Ptr;
  
     sub_BFC06FA4 (0x38C);
+
     return dword_10C + dword_114;       // Total size of TCBH and TCB tables
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>

Revision as of 17:40, 5 June 2015

512 KB ROM содержит стартовый загрузчик BIOS, копию ядра (kernel) PlayStation OS, а также "оболочку" (shell), которая открывается, если в консоль не вставлен игровой диск и содержит менеджер карт памяти и CD-проигрыватель.

Типичный ROM BIOS выглядит примерно вот так :

400px

  • У BIOS PU-7 и старых PU-8 микросхема 40 выводов.
  • Начиная с новых версий PU-8 (и далее) микросхема 32 вывода (в том числе и у PSOne)

Внутри скорее всего ROM с ионной имплантацией по маске.

Contents

Тайминги

Версии BIOS

Вот это сложный вопрос, потому что версии BIOS во-первых отличаются от региона, во вторых они отличаются между моделями материнских плат. И даже внутри одной модели материнки могут быть разные версии BIOS, в зависимости от ревизии материнской платы одной модели.

Эталонной версией BIOS почти все эмуляторы считают SCPH1001.BIN. Этот BIOS был подробно дизассемблирован и считается "стабильным" для работы в эмуляторах.

Boot

Программа начальной загрузки (RESET)

Исполнение начинается с адреса 0xBFC00000

  • Инициализирует недокументированные аппаратные регистры CPU (тайминг и пр.)
  • Очищает память и регистры CPU
  • Если в PSX присутствует устройство PIO - выполняет его программу загрузки
  • Загружает kernel
  • Воспроизводит заставку (логотип SONY на белом фоне)
  • Запускает процедуру Main, которая либо загружает диск (если он вставлен), либо запускает SHELL

Some reversing of SCPH-1001 BIOS :

//
// SCPH1001 Reset
// Written likely on assembler
//
 
Reset ()        // 0xBFC00000
{
 
    dword.0x1F801010 = 0x13243F;
 
    dword.0x1F801060 = 0xB88;       // ram_size?
 
    //
    // 20 nops (pipeline reset?)
    //
 
    nop x 20;
 
    goto Reset2;
}    
 
Reset2 ()       // 0xBFC00150
{
    //
    // More registers
    //
 
    dword.0x1F801020 = 0x31125;
 
    dword.0x1F801000 = 0x1F000000;
 
    dword.0x1F801004 = 0x1F802000;
 
    dword.0x1F801008 = 0x13243F;
 
    dword.0x1F801014 = 0x200931E1;
 
    dword.0x1F801018 = 0x20843;
 
    dword.0x1F80100C = 0x3022;
 
    dword.0x1F80101C = 0x70777;
 
    //
    // Clear CPU registers
    //
 
    gpr[1...31] = 0;
 
    //
    // B/U Control (Lock ICache?)
    //
 
    dword.0xFFFE0130 = 0x804;       // Enable I-Cache + Tag Test Mode
 
    //
    // COP0
    //
 
    COP0.SR = 0x10000;      // Isolate cache from bus
 
    //
    // Clear instruction cache Tag memory (Cache line = 16 bytes)
    //
 
    for ( int Addr=0; Addr<0x1000; Addr += 0x80 )
    {
        dword.[Addr] = 0;
        dword.[Addr + 0x10] = 0;
        dword.[Addr + 0x20] = 0;
        dword.[Addr + 0x30] = 0;
        dword.[Addr + 0x40] = 0;
        dword.[Addr + 0x50] = 0;
        dword.[Addr + 0x60] = 0;
        dword.[Addr + 0x70] = 0;
    }
 
    //
    // COP0
    //
 
    COP0.SR = 0;
 
    //
    // BIU/Cache configuration
    //
 
    dword.0xFFFE0130 = 0x800;       // Enable I-Cache
 
    //
    // COP0
    //
 
    COP0.SR = 0x10000;          // Isolate cache from bus
 
    //
    // Clear instruction cache lines
    //
 
    for ( int Addr=0; Addr<0x1000; Addr += 0x80 )
    {
        dword.[Addr] = 0;
        dword.[Addr + 0x4] = 0;
        dword.[Addr + 0x8] = 0;
        dword.[Addr + 0xC] = 0;
        dword.[Addr + 0x10] = 0;
        dword.[Addr + 0x14] = 0;
        dword.[Addr + 0x18] = 0;
        dword.[Addr + 0x1C] = 0;
        dword.[Addr + 0x20] = 0;
        dword.[Addr + 0x24] = 0;
        dword.[Addr + 0x28] = 0;
        dword.[Addr + 0x2C] = 0;
        dword.[Addr + 0x30] = 0;
        dword.[Addr + 0x34] = 0;
        dword.[Addr + 0x38] = 0;
        dword.[Addr + 0x3C] = 0;
        dword.[Addr + 0x40] = 0;
        dword.[Addr + 0x44] = 0;
        dword.[Addr + 0x48] = 0;
        dword.[Addr + 0x4C] = 0;
        dword.[Addr + 0x50] = 0;
        dword.[Addr + 0x54] = 0;
        dword.[Addr + 0x58] = 0;
        dword.[Addr + 0x5C] = 0;
        dword.[Addr + 0x60] = 0;
        dword.[Addr + 0x64] = 0;
        dword.[Addr + 0x68] = 0;
        dword.[Addr + 0x6C] = 0;
        dword.[Addr + 0x70] = 0;
        dword.[Addr + 0x74] = 0;
        dword.[Addr + 0x78] = 0;
        dword.[Addr + 0x7C] = 0;                                
    }
 
    //
    // COP0
    //
 
    COP0.SR = 0;
 
    //
    // Read memory 8 times
    //
 
    t1 = dword.0xA0000000;
    t1 = dword.0xA0000000;
    t1 = dword.0xA0000000;
    t1 = dword.0xA0000000;
    t1 = dword.0xA0000000;
    t1 = dword.0xA0000000;
    t1 = dword.0xA0000000;
    t1 = dword.0xA0000000;
 
    //
    // BIU/Cache default configuration
    //
 
    dword.0xFFFE0130 = 0x1E988;         // D-Cache as Scratchpad
                                        // Enable D-Cache
                                        // Enable I-Cache 
                                        // Enable Bus Grant
                                        // No wait state
                                        // Enable Read Priority
                                        // Enable Load Scheduling
 
    //
    // Reset COP0 regs
    //
 
    COP0.Reg7 = 0;
    COP0.EntryLo1 = 0;
    COP0.PageMask = 0;
    COP0.Wired = 0;
    COP0.Count = 0;
    COP0.Compare = 0;
    COP0.SR = 0;
    COP0.Cause = 0;
 
    //
    // Clear 0xA0009000
    //
 
    memset ( 0xA0009000, 0, 0x3160 );
 
    //
    // Set initial context
    //
 
    CPU.SP = 0x801FFF00;
    CPU.GP = 0xA0010FF0;
    CPU.FP = CPU.SP;
 
    //
    // ram_size ?
    //
 
    dword.0x1F801060 = 0xB88;
 
    dword.0x60 = 2;
    dword.0x64 = 0;
    dword.0x68 = 0xff;
 
    //
    // Mute SPU
    //
 
    word.[0x1F801C00 + 0x180] = 0;      // Mainvolume Left
    word.[0x1F801C00 + 0x182] = 0;      // Mainvolume Right
    word.[0x1F801C00 + 0x184] = 0;      // Reverb depth left
    word.[0x1F801C00 + 0x186] = 0;      // Reverb depth right
 
    goto Reset3;
}
 
//
// Following boot code written on C for sure (has C prolog/epilog in code)
//
 
Reset3 ()   // 0xBFC06EC4
{
    int Present;
 
    TraceStep (0xF);
 
    word.[0x1F801C00 + 0x186] = 0;
    word.[0x1F801C00 + 0x184] = 0;
    word.[0x1F801C00 + 0x182] = 0;
    word.[0x1F801C00 + 0x180] = 0;
 
    Present = CheckPIO ();
 
    if ( Present )
        ResetPIO ();
 
    TraceStep (0xE);
 
    dword.0xA000B9B0 = 0;
 
    StartKernel ();
}
 
TraceStep (a0)      // 0xBFC01A60
{
    Bogus1 ();
 
    byte.0x1F802041 = a0 & 0xFF;
}
 
Bogus1 ()       // 0xBFC03990
{
    dword.0xA000B068 = 0;
    dword.0xA000B068 = 0;
    dword.0xA000B068 = 0;
    dword.0xA000B068 = 0;
}
 
//
// PIO Support
//
 
char Licensed[] = "Licensed by Sony Computer Entertainment Inc.";       // 0xBFC0E288
 
int CheckPIO (void)         // 0xBFC0703C
{
    char * Source = Licensed;
    char * Dest = 0x1F000084;       // PIO Header
 
    while ( *Source )
    {
        if ( *Source != *Dest ) break;
 
        Source++;
        Dest++;
    }
 
    if ( *Source ) return 0;
    else return 1;
}
 
void ResetPIO (void)        // 0xBFC0711C
{
    //
    // Run init code in PIO Space
    //
 
    dword.0x1F000080 ();
}
 
void StartKernel ()      // 0xBFC06784
{
    char Config[0x50];
    char Exec[0x50];
 
    strcpy ( Config, "cdrom:" );
    strcat ( Config, "SYSTEM.CNF;1" );
 
    strcpy ( Exec, "cdrom:" );
    strcat ( Exec, "PSX.EXE;1" );
 
    Main ( Config, Exec );
}

Bootrom Main

//
// Bootrom Main
//
 
// Sometimes we need to re-mute SPU (why?)
 
#define MUTE_SPU() \
	word.[0x1F801C00 + 0x186] = 0; 	\
	word.[0x1F801C00 + 0x184] = 0;	\
	word.[0x1F801C00 + 0x182] = 0;	\
	word.[0x1F801C00 + 0x180] = 0;
 
typedef struct _SYSTEM_CONFIG
{
    SIZE_R      Tcb;            // Max number of threads
    SIZE_T      Event;          // Max number of events
    PVOID       Stack;          // Initial stack pointer
} SYSTEM_CONFIG, *PSYSTEM_CONFIG;
 
SYSTEM_CONFIG DefaultConfig = {         // 0xBFC0E14C
    4, 
    16,
    0x801FFF00
};
 
void Main (char *Config, char *Exec )       // 0xBFC067E8
{
    int File;
    long Bytes;
 
	//
	// Disable all interupts, External (level 3) interrupts are disabled
	//
 
	TraceStep (1);
 
	SetSr ( GetSr () & 0xFFFFFBFE );
 
	MUTE_SPU ();
 
	//
	// Copy kernel image from Bootrom and run its initialization code.
	//
 
	TraceStep (2);
 
	LoadInitKernel ();
 
	//
	// Initialize kernel traps
	//
 
	TraceStep (3);
 
	CopyBootapiTable ();       // Copy BIOS shared procedure callbacks at 0x200
 
	InitSyscall ();        // Copy 0xA0, 0xB0 and 0xC0 syscall stubs from kernel image
 
	PatchA0Table ();
 
	InstallExceptionHandlers ();
 
	ResetEntryInt ();
 
	//
	// Init device drivers
	//
 
	TraceStep (4);
 
	MUTE_SPU ();
 
	dword.0x1F801074 = 0;      // int_mask
	dword.0x1F801070 = 0;      // int_reg
 
	InstallDevices ( dword_B9B0 );
 
	//
	// Shout out first printf
	//
 
	TraceStep (5);
 
	printf ( "\n" 
			 "PS-X Realtime Kernel Ver.2.5\n"
			 "Copyright 1993,1994 (C) Sony Computer Entertainment Inc. \n" );
 
	//
	// Init Kernel executive
	//
 
	TraceStep (6);
 
	MUTE_SPU ();
 
	memcpy ( 0xA000B940, &DefaultConfig, sizeof(SYSTEM_CONFIG) );
 
	printf ( "KERNEL SETUP!\n" );
 
	SysInitMemory ( 0xA000E000, 0x2000 );      // Kernel heap
 
	InitEventHandlers (4);
 
	InitException (0)
 
	InitDefInt (3);
 
	InitEvents ( dword_B944 );
 
	InitThreads ( 1, dword_B940 );
 
	InitRCnt (1);
 
	MUTE_SPU ();
 
	if ( setjmp ( 0xA000B980 ) )
		SystemHalt (901);
 
	//
	// Run Shell
	//
 
	TraceStep (7);
 
	LoadRunShell (a0);
 
	//
	// 8
	//
 
	TraceStep (8);
 
	dword.0x1F801074 = 0;      // int_mask
	dword.0x1F801070 = 0;      // int_reg
 
	sub_BFC073A0 ();
 
	if ( setjmp ( 0xA000B980 ) )
		SystemHalt (921);
 
    //
    // PIO Shell
    //
 
	if ( CheckPIO2 () == 1 )
		BootPIO ();
 
	printf ( "\n" 
			 "BOOTSTRAP LOADER Type C Ver 2.1   03-JUL-1994\n"
			 "Copyright 1993,1994 (C) Sony Computer Entertainment Inc.\n" );
 
	if ( setjmp ( 0xA000B980 ) )
		SystemHalt (902);
 
	//
	// Load executable from external media.
	//
 
	TraceStep (9);
 
	if ( setjmp ( 0xA000B980) )
		SystemHalt (903);
 
    //
    // Try to open system config file.
    // If config file is missing fall back to plain EXE loading
    //
 
	File = open ( Config, O_RDONLY );
 
	if ( File >= 0 )
	{
        //
        // Read and parse config file parameters
        //
 
		printf ( "setup file    : %s\n", Config );
 
		if ( setjmp ( 0xA000B980 ) )
			SystemHalt (911);
 
		Bytes = read ( File, 0xA000B070, 0x800 );
 
		if ( Bytes )
		{
			0xA000B070[Bytes] = 0;   // Terminate string
 
			close ( File );
 
			if ( setjmp ( 0xA000B980 ) )
				SystemHalt ( 912 );
 
			ParseConfig ( 0xA000B070, 0xA000B940, 0xA000B8B0 );
		}
		else
		{
            //
            // Set default config, fall back to plain EXE loading
            //
 
			memcpy ( 0xA000B940, &DefaultConfig, sizeof(SYSTEM_CONFIG) );
			strcpy ( 0xA000B8B0, Exec );
		}
	}
	else
	{
        //
        // Use plain executable
        //
 
		if ( setjmp ( 0xA000B980 ) )
			SystemHalt (913);
 
		byte.0x180 = 0;   // Version number
		memcpy ( 0xA000B940, &DefaultConfig, sizeof(SYSTEM_CONFIG) );
		strcpy ( 0xA000B8B0, Exec );
	}
 
	//
	// Load executable
	//
 
	if ( setjmp ( 0xA000B980 ) )
		SystemHalt (904);
 
	ReinitKernel ();
 
	printf ( "boot file     : %s\n", 0xA000B8B0 );
 
	if ( setjmp ( 0xA000B980 ) )
		SystemHalt (905);
 
	ClearStack ();
 
	if ( LoadExec (0xA000B8B0, 0xA000B870 ) == 0 )
		SystemHalt (906);
 
	printf ( "EXEC:PC0(%08x)  T_ADDR(%08x)  T_SIZE(%08x)\n", dword_B870, dword_B878, dword_B87C );
 
	printf ( "boot address  : %08x %08x\n"
			 "Execute !\n\n", dword_B870, dword_B948 );
 
	dword_B890 = dword_B948;
	dword_B894 = 0;
 
	printf ( "                S_ADDR(%08x)  S_SIZE(%08)\n", dword_B948, 0 );
 
	EnterCriticalSection ();
 
	if ( setjmp ( 0xA000B980 ) )
		SystemHalt (907);
 
	sub_BFC0D570 (0xA000B870, 1, 0 );
 
	printf ( "End of Main\n" );
 
	SystemHalt (908);
}
 
//
// Support
//
 
// Written in asm.
int setjmp ( jmp_buf * Buffer )       // 0xBFC02240
{
    Buffer[JB_PC] = ra;
    Buffer[JB_GP] = gp;
    Buffer[JB_SP] = sp;
    Buffer[JB_FP] = fp;
    Buffer[JB_S0] = s0;
    Buffer[JB_S1] = s1;
    Buffer[JB_S2] = s2;
    Buffer[JB_S3] = s3;
    Buffer[JB_S4] = s4;
    Buffer[JB_S5] = s5;
    Buffer[JB_S6] = s6;
    Buffer[JB_S7] = s7;
    return 0;
}
 
void SystemHalt (int Code)      // 0xBFC06FA4
{
    TraceStep (0xF);
    SystemError ( 'B', Code );
}
 
ULONG GetSr (void)          // 0xBFC03968
{
    return COP0.SR;
}
 
void SetSr (ULONG Value)        // 0xBFC03978
{
    COP0.SR = Value;
}
 
void LoadInitKernel ()         // 0xBFC00420
{
    memcpy ( 0xA0000500, 0xBFC10000, 0x8BF0 );
 
    0xA0000500 ();      // Run kernel initialization
}
 
CopyBootapiTable ()         // 0xBFC042D0
{
    memcpy ( 0x200, 0xBFC04300, 0x304 );
}
 
InitSyscall ()         // 0xBFC042A0
{
    //
    // Copy 0xA0, 0xB0 and 0xC0 syscall stubs from kernel image
    //
 
    memcpy ( 0xA0, 0xA0000510, 0x30 );
}
 
ClearStack ()         // 0xBFC0D850
{
    PVOID StartAddress;
    PVOID EndAddress;
    StartAddress = 0xA0010000;
    EndAddress = sp | 0xA0000000;
    memset ( StartAddress, 0, EndAddress - StartAddress );
}
 
ReinitKernel ()     // 0xBFC06F28
{
    printf ( "KERNEL SETUP!\n" );
 
    SysInitMemory ( 0xA000E000, 0x2000 );       // Kernel heap
 
    InitEventHandlers (4);
 
    InitException (0);
 
    InitDefInt (3);
 
    InitEvents ( dword_B944 );
 
    InitThreads ( 1, dword_B940 );
 
    InitRCnt (1);
 
    sub_BFC071A0 ();
}
 
char Licensed[] = "Licensed by Sony Computer Entertainment Inc.";       // 0xBFC0E288
 
int CheckPIO2 ()         // 0xBFC070AC
{
    char * Source = Licensed;
    char * Dest = 0x1F000004;       // PIO Header 2
 
    while ( *Source )
    {
        if ( *Source != *Dest ) break;
 
        Source++;
        Dest++;
    }
 
    if ( *Source ) return 0;
    else return 1;    
}
 
BootPIO ()      // 0xBFC07148
{
    printf ( "PIO SHELL for PlayStation(tm)\n" );
 
    printf ( "%s\n", 0x1F000004 );
 
    dword.0x1F000000 ();        // Jump by pointer.
}
 
void ParseConfig (char *Text, PSYSTEM_CONFIG Config, char *Exec )     // 0xBFC008A0
{
    Config->Tcb = 0;
    Config->Event = 0;
    Config->Stack = 0;
 
    Exec[0] = '\0';
    byte.0x180 = 0;         // Version number
 
    ParseConfigInt ( Text, &Config->Tcb, "TCB" );
 
    ParseConfigInt ( Text, &Config->Event, "EVENT" );
 
    ParseConfigInt ( Text, &Config->Stack, "STACK" );
 
    ParseConfigString ( Text, Exec, 0x180, "BOOT" );
}
 
LoadRunShell (a0)     // 0xBFC06FF0
{
    memcpy ( 0x80030000, 0xBFC18000, 0x67FF0 );
 
    FlushCache ();
 
    0x80030000 (a0);
}
 
//
// Executive init
//
 
int InitEventHandlers (int Num)   // 0xBFC04610
{
    int Bytes = Num * 8;
    Pointer = SysMalloc ( Bytes );
 
    if ( Pointer )
    {
        memclr ( Pointer, Bytes );
        dword_100 = Pointer;
        dword_104 = Bytes;
        return Bytes;
    }
    else return 0;
}
 
PVOID InitEvents (int Num)    // 0xBFC04678
{
    int Bytes;
    int n;
    PVOID Pointer;
    EvCB * Event;
 
    printf ( "\nConfiguration : EvCB\t0x%02x\t\t", Num );
 
    Bytes = Num * sizeof (EvCB);
    Pointer = SysMalloc (Bytes);
 
    if ( Pointer )
    {
        dword_124 = Pointer;
        dword_120 = Bytes;
 
        //
        // Clear "status" field for all event CBs.
        //
 
        for (n=0; n<Num; n++)
        {
            Event = &dword_124[n];
            Event->status = 0;
        }
 
        return Pointer;
    }
    else return 0;
}
 
int InitThreads (int Tcbh, int Tcb)     // 0xBFC0472C
{
    TCBH * TCBH_Ptr;
    TCB * TCB_Ptr;
    TCBH * TcbhEntry;
    TCBH * TcbEntry;
    int n;
 
    printf ( "TCB\t0x%02x\n", Num );
 
    dword_10C = Tcbh * 4;       // BUGCHECK: Should be actually 8, since TCBH has additional "flag" field deinfed in KERNEL.H
    dword_114 = Tcb * 192;
 
    TCBH_Ptr = SysMalloc ( dword_10C );
    if ( TCBH_Ptr == NULL )
        return 0;
 
    TCB_Ptr = SysMalloc ( dword_114 );
    if ( TCB_Ptr == NULL )
        return 0;
 
    //
    // Clear TCBH
    //
 
    for (n=0; n<Tcbh; n++)
    {
        TcbhEntry = &TCBH_Ptr[n];
        TcbhEntry->entry = NULL;
    }
 
    //
    // Clear TCB
    //
 
    for (n=0; n<Tcb; n++)
    {
        TcbEntry = &TCB_Ptr[n];
        TcbEntry->status = TcbStUNUSED;
    }
 
    //
    // Set active first TCB entry
    //
 
    TCB_Ptr[0].status = TcbStACTIVE;
    TCBH_Ptr[0].entry = TCB_Ptr;
 
    //
    // Update ToT
    //
 
    dword_108 = TCBH_Ptr;
    dword_110 = TCB_Ptr;
 
    return dword_10C + dword_114;       // Total size of TCBH and TCB tables
}

Kernel (PlayStation OS)

Ядро PS OS резидентно находится в памяти. Доступ к процедурам ядра производится через специальные таблицы (которые находятся по адресам 0xA0, 0xB0, 0xC0).

Второй способ вызова некоторых механизмов ядра - это инструкция Syscall (но набор её функций ограничен, по сути используется только для EnterCriticalSection / ExitCriticalSection)

Также приложениям доступна специальная "Таблица Таблиц" ядра (ToT), через которую программа может получить различные системные описатели и пр.

Выполнение пользовательских программ происходит в режиме CPU Kernel Mode, поскольку одновременно может быть запущен только один "процесс" (исполняемый файл игры).

Shell

Оболочка BIOS - это специальным образом запакованный исполняемый файл формата PS-X EXE, который находится внутри ROM.

Программа начальной загрузки распаковывает его и загружает на лету в RAM перед запуском.

Оболочка запускается если в привод не вставлен игровой диск.