Search
lxdream.org :: lxdream/src/bios.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/bios.c
changeset 1103:de9ad2c0cf56
prev1102:957b76b312cc
next1107:7b279d10f46f
author nkeynes
date Sun Feb 21 11:19:59 2010 +1000 (14 years ago)
permissions -rw-r--r--
last change Update sh4r.pc before doing the syscall - mainly so that debugging etc
statements come out with a useful PC value rather than the syscall id
file annotate diff log raw
nkeynes@87
     1
/**
nkeynes@561
     2
 * $Id$
nkeynes@87
     3
 * 
nkeynes@87
     4
 * "Fake" BIOS functions, for operation without the actual BIOS.
nkeynes@87
     5
 *
nkeynes@1100
     6
 * Copyright (c) 2005-2010 Nathan Keynes.
nkeynes@87
     7
 *
nkeynes@87
     8
 * This program is free software; you can redistribute it and/or modify
nkeynes@87
     9
 * it under the terms of the GNU General Public License as published by
nkeynes@87
    10
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@87
    11
 * (at your option) any later version.
nkeynes@87
    12
 *
nkeynes@87
    13
 * This program is distributed in the hope that it will be useful,
nkeynes@87
    14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@87
    15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@87
    16
 * GNU General Public License for more details.
nkeynes@87
    17
 */
nkeynes@87
    18
nkeynes@87
    19
#include "dream.h"
nkeynes@87
    20
#include "mem.h"
nkeynes@102
    21
#include "syscall.h"
nkeynes@1100
    22
#include "asic.h"
nkeynes@422
    23
#include "dreamcast.h"
nkeynes@1099
    24
#include "bootstrap.h"
nkeynes@564
    25
#include "sh4/sh4.h"
nkeynes@1099
    26
#include "drivers/cdrom/cdrom.h"
nkeynes@1099
    27
#include "drivers/cdrom/isoread.h"
nkeynes@1099
    28
#include "gdrom/gdrom.h"
nkeynes@87
    29
nkeynes@1103
    30
gboolean bios_boot_gdrom_disc( void );
nkeynes@1103
    31
nkeynes@1100
    32
/* Definitions from KOS */
nkeynes@87
    33
#define COMMAND_QUEUE_LENGTH 16
nkeynes@87
    34
nkeynes@1100
    35
#define GD_CMD_PIOREAD     16  /* readcd */
nkeynes@1100
    36
#define GD_CMD_DMAREAD     17  /* readcd */
nkeynes@87
    37
#define GD_CMD_GETTOC      18
nkeynes@1100
    38
#define GD_CMD_GETTOC2     19  /* toc2 */
nkeynes@1100
    39
#define GD_CMD_PLAY        20  /* playcd */
nkeynes@1100
    40
#define GD_CMD_PLAY2       21  /* playcd */
nkeynes@1100
    41
#define GD_CMD_PAUSE       22  /* No params */
nkeynes@1100
    42
#define GD_CMD_RELEASE     23  /* No params */
nkeynes@1100
    43
#define GD_CMD_INIT        24  /* No params */
nkeynes@87
    44
#define GD_CMD_SEEK        27
nkeynes@87
    45
#define GD_CMD_READ        28
nkeynes@1100
    46
#define GD_CMD_STOP        33  /* No params */
nkeynes@87
    47
#define GD_CMD_GETSCD      34
nkeynes@87
    48
#define GD_CMD_GETSES      35
nkeynes@87
    49
nkeynes@1100
    50
#define GD_CMD_STATUS_NONE   0
nkeynes@87
    51
#define GD_CMD_STATUS_ACTIVE 1
nkeynes@1100
    52
#define GD_CMD_STATUS_DONE   2
nkeynes@1100
    53
#define GD_CMD_STATUS_ABORT  3
nkeynes@1100
    54
#define GD_CMD_STATUS_ERROR  4
nkeynes@87
    55
nkeynes@87
    56
#define GD_ERROR_OK          0
nkeynes@87
    57
#define GD_ERROR_NO_DISC     2
nkeynes@87
    58
#define GD_ERROR_DISC_CHANGE 6
nkeynes@87
    59
#define GD_ERROR_SYSTEM      1
nkeynes@87
    60
nkeynes@1101
    61
struct gdrom_toc2_params {
nkeynes@1101
    62
    uint32_t session;
nkeynes@1101
    63
    sh4addr_t buffer;
nkeynes@1101
    64
};
nkeynes@1101
    65
nkeynes@1101
    66
struct gdrom_readcd_params {
nkeynes@1101
    67
    cdrom_lba_t lba;
nkeynes@1101
    68
    cdrom_count_t count;
nkeynes@1101
    69
    sh4addr_t buffer;
nkeynes@1101
    70
    uint32_t unknown;
nkeynes@1101
    71
};
nkeynes@1101
    72
nkeynes@1101
    73
struct gdrom_playcd_params {
nkeynes@1101
    74
    cdrom_lba_t start;
nkeynes@1101
    75
    cdrom_lba_t end;
nkeynes@1101
    76
    uint32_t repeat;
nkeynes@1101
    77
};
nkeynes@1101
    78
nkeynes@1100
    79
typedef union gdrom_cmd_params {
nkeynes@1101
    80
    struct gdrom_toc2_params toc2;
nkeynes@1101
    81
    struct gdrom_readcd_params readcd;
nkeynes@1101
    82
    struct gdrom_playcd_params playcd;
nkeynes@1100
    83
} *gdrom_cmd_params_t;
nkeynes@1100
    84
nkeynes@1100
    85
nkeynes@1100
    86
nkeynes@1100
    87
nkeynes@1100
    88
typedef struct gdrom_queue_entry {
nkeynes@87
    89
    int status;
nkeynes@87
    90
    uint32_t cmd_code;
nkeynes@1101
    91
    union gdrom_cmd_params params;
nkeynes@87
    92
    uint32_t result[4];
nkeynes@1100
    93
} *gdrom_queue_entry_t;
nkeynes@87
    94
nkeynes@1100
    95
static struct gdrom_queue_entry gdrom_cmd_queue[COMMAND_QUEUE_LENGTH];
nkeynes@87
    96
nkeynes@87
    97
static struct bios_gdrom_status {
nkeynes@87
    98
    uint32_t status;
nkeynes@87
    99
    uint32_t disk_type;
nkeynes@87
   100
} bios_gdrom_status;
nkeynes@87
   101
nkeynes@1101
   102
void bios_gdrom_init( void )
nkeynes@1101
   103
{
nkeynes@1101
   104
    memset( &gdrom_cmd_queue, 0, sizeof(gdrom_cmd_queue) );
nkeynes@1101
   105
}
nkeynes@1101
   106
nkeynes@1100
   107
void bios_gdrom_run_command( gdrom_queue_entry_t cmd )
nkeynes@87
   108
{
nkeynes@87
   109
    DEBUG( "BIOS GD command %d", cmd->cmd_code );
nkeynes@1101
   110
    cdrom_error_t status = CDROM_ERROR_OK;
nkeynes@1101
   111
    sh4ptr_t ptr;
nkeynes@87
   112
    switch( cmd->cmd_code ) {
nkeynes@87
   113
    case GD_CMD_INIT:
nkeynes@736
   114
        /* *shrug* */
nkeynes@736
   115
        cmd->status = GD_CMD_STATUS_DONE;
nkeynes@736
   116
        break;
nkeynes@1101
   117
    case GD_CMD_GETTOC2:
nkeynes@1101
   118
        ptr = mem_get_region( cmd->params.toc2.buffer );
nkeynes@1101
   119
        status = gdrom_read_toc( ptr );
nkeynes@1101
   120
        if( status == CDROM_ERROR_OK ) {
nkeynes@1101
   121
            /* Convert data to little-endian */
nkeynes@1101
   122
            struct gdrom_toc *toc = (struct gdrom_toc *)ptr;
nkeynes@1101
   123
            for( unsigned i=0; i<99; i++ ) {
nkeynes@1101
   124
                toc->track[i] = ntohl(toc->track[i]);
nkeynes@1101
   125
            }
nkeynes@1101
   126
            toc->first = ntohl(toc->first);
nkeynes@1101
   127
            toc->last = ntohl(toc->last);
nkeynes@1101
   128
            toc->leadout = ntohl(toc->leadout);
nkeynes@1101
   129
        }
nkeynes@1101
   130
        break;
nkeynes@1101
   131
    case GD_CMD_PIOREAD:
nkeynes@1101
   132
    case GD_CMD_DMAREAD:
nkeynes@1101
   133
        ptr = mem_get_region( cmd->params.readcd.buffer );
nkeynes@1101
   134
        status = gdrom_read_cd( cmd->params.readcd.lba,
nkeynes@1101
   135
                cmd->params.readcd.count, 0x28, ptr, NULL );
nkeynes@1101
   136
        break;
nkeynes@1101
   137
    default:
nkeynes@1101
   138
        WARN( "Unknown BIOS GD command %d\n", cmd->cmd_code );
nkeynes@1101
   139
        cmd->status = GD_CMD_STATUS_ERROR;
nkeynes@1101
   140
        cmd->result[0] = GD_ERROR_SYSTEM;
nkeynes@1101
   141
        return;
nkeynes@1101
   142
    }
nkeynes@1101
   143
nkeynes@1101
   144
    switch( status ) {
nkeynes@1101
   145
    case CDROM_ERROR_OK:
nkeynes@1101
   146
        cmd->status = GD_CMD_STATUS_DONE;
nkeynes@1101
   147
        cmd->result[0] = GD_ERROR_OK;
nkeynes@1101
   148
        break;
nkeynes@1101
   149
    case CDROM_ERROR_NODISC:
nkeynes@1101
   150
        cmd->status = GD_CMD_STATUS_ERROR;
nkeynes@1101
   151
        cmd->result[0] = GD_ERROR_NO_DISC;
nkeynes@1101
   152
        break;
nkeynes@87
   153
    default:
nkeynes@736
   154
        cmd->status = GD_CMD_STATUS_ERROR;
nkeynes@736
   155
        cmd->result[0] = GD_ERROR_SYSTEM;
nkeynes@87
   156
    }
nkeynes@87
   157
}
nkeynes@87
   158
nkeynes@1101
   159
uint32_t bios_gdrom_enqueue( uint32_t cmd, sh4addr_t data )
nkeynes@87
   160
{
nkeynes@87
   161
    int i;
nkeynes@87
   162
    for( i=0; i<COMMAND_QUEUE_LENGTH; i++ ) {
nkeynes@736
   163
        if( gdrom_cmd_queue[i].status != GD_CMD_STATUS_ACTIVE ) {
nkeynes@736
   164
            gdrom_cmd_queue[i].status = GD_CMD_STATUS_ACTIVE;
nkeynes@736
   165
            gdrom_cmd_queue[i].cmd_code = cmd;
nkeynes@1101
   166
            switch( cmd ) {
nkeynes@1101
   167
            case GD_CMD_PIOREAD:
nkeynes@1101
   168
            case GD_CMD_DMAREAD:
nkeynes@1101
   169
                mem_copy_from_sh4( (unsigned char *)&gdrom_cmd_queue[i].params.readcd, data, sizeof(struct gdrom_readcd_params) );
nkeynes@1101
   170
                break;
nkeynes@1101
   171
            case GD_CMD_GETTOC2:
nkeynes@1101
   172
                mem_copy_from_sh4( (unsigned char *)&gdrom_cmd_queue[i].params.toc2, data, sizeof(struct gdrom_toc2_params) );
nkeynes@1101
   173
                break;
nkeynes@1101
   174
            case GD_CMD_PLAY:
nkeynes@1101
   175
            case GD_CMD_PLAY2:
nkeynes@1101
   176
                mem_copy_from_sh4( (unsigned char *)&gdrom_cmd_queue[i].params.playcd, data, sizeof(struct gdrom_playcd_params) );
nkeynes@1101
   177
                break;
nkeynes@1101
   178
            }
nkeynes@736
   179
            return i;
nkeynes@736
   180
        }
nkeynes@87
   181
    }
nkeynes@87
   182
    return -1;
nkeynes@87
   183
}
nkeynes@87
   184
nkeynes@87
   185
void bios_gdrom_run_queue( void ) 
nkeynes@87
   186
{
nkeynes@87
   187
    int i;
nkeynes@87
   188
    for( i=0; i<COMMAND_QUEUE_LENGTH; i++ ) {
nkeynes@736
   189
        if( gdrom_cmd_queue[i].status == GD_CMD_STATUS_ACTIVE ) {
nkeynes@736
   190
            bios_gdrom_run_command( &gdrom_cmd_queue[i] );
nkeynes@736
   191
        }
nkeynes@87
   192
    }
nkeynes@87
   193
}
nkeynes@87
   194
nkeynes@1100
   195
gdrom_queue_entry_t bios_gdrom_get_command( uint32_t id )
nkeynes@87
   196
{
nkeynes@87
   197
    if( id >= COMMAND_QUEUE_LENGTH ||
nkeynes@736
   198
            gdrom_cmd_queue[id].status == GD_CMD_STATUS_NONE )
nkeynes@736
   199
        return NULL;
nkeynes@87
   200
    return &gdrom_cmd_queue[id];
nkeynes@87
   201
}
nkeynes@87
   202
nkeynes@87
   203
/**
nkeynes@1102
   204
 * Address of the system information block (in the flash rom). Also repeats
nkeynes@1102
   205
 * at FLASH_SYSINFO_SEGMENT+0xA0
nkeynes@87
   206
 */
nkeynes@1102
   207
#define FLASH_SYSINFO_SEGMENT 0x0021a000
nkeynes@1102
   208
#define FLASH_CONFIG_SEGMENT  0x0021c000
nkeynes@1102
   209
#define FLASH_CONFIG_LENGTH   0x00004000
nkeynes@1102
   210
#define FLASH_PARTITION_MAGIC "KATANA_FLASH____"
nkeynes@87
   211
nkeynes@1102
   212
/**
nkeynes@1102
   213
 * Locate the active config block. FIXME: This isn't completely correct, but it works
nkeynes@1102
   214
 * under at least some circumstances. 
nkeynes@1102
   215
 */
nkeynes@1102
   216
static char *bios_find_flash_config( sh4addr_t segment, uint32_t length )
nkeynes@1102
   217
{
nkeynes@1102
   218
    char *start = mem_get_region(segment);
nkeynes@1102
   219
    char *p = start + 0x80;
nkeynes@1102
   220
    char *end = p + length;
nkeynes@1102
   221
    char *result = NULL;
nkeynes@1102
   222
nkeynes@1102
   223
    if( memcmp( start, FLASH_PARTITION_MAGIC, 16 ) != 0 )
nkeynes@1102
   224
        return NULL; /* Missing magic */
nkeynes@1102
   225
    while( p < end ) {
nkeynes@1102
   226
        if( p[0] == 0x05 && p[1] == 0 ) {
nkeynes@1102
   227
            result = p;
nkeynes@1102
   228
        }
nkeynes@1102
   229
        p += 0x40;
nkeynes@1102
   230
    }
nkeynes@1102
   231
    return result;
nkeynes@1102
   232
}
nkeynes@1102
   233
nkeynes@1102
   234
/**
nkeynes@1102
   235
 * Syscall information courtesy of Marcus Comstedt
nkeynes@1102
   236
 */
nkeynes@1102
   237
static void bios_sysinfo_vector( uint32_t syscallid )
nkeynes@1102
   238
{
nkeynes@1102
   239
    char *flash_segment, *flash_config;
nkeynes@1102
   240
    char *dest;
nkeynes@1102
   241
    DEBUG( "BIOS SYSINFO: r4 = %08X, r5 = %08X, r6 = %08x, r7= %08X", sh4r.r[4], sh4r.r[5], sh4r.r[6], sh4r.r[7] );
nkeynes@1102
   242
nkeynes@1102
   243
    switch( sh4r.r[7] ) {
nkeynes@1102
   244
    case 0: /* SYSINFO_INIT */
nkeynes@1102
   245
        /* Initialize the region 8c000068 .. 8c00007f from the flash rom
nkeynes@1102
   246
         *   uint64_t system_id;
nkeynes@1102
   247
         *   char [5] system_props;
nkeynes@1102
   248
         *   char [3] zero_pad (?)
nkeynes@1102
   249
         *   char [8] settings;
nkeynes@1102
   250
         **/
nkeynes@1102
   251
        flash_segment = mem_get_region(FLASH_SYSINFO_SEGMENT);
nkeynes@1102
   252
        flash_config = bios_find_flash_config(FLASH_CONFIG_SEGMENT,FLASH_CONFIG_LENGTH);
nkeynes@1102
   253
        dest = mem_get_region( 0x8c000068 );
nkeynes@1102
   254
        memset( dest, 0, 24 );
nkeynes@1102
   255
        memcpy( dest, flash_segment + 0x56, 8 );
nkeynes@1102
   256
        memcpy( dest + 8, flash_segment, 5 );
nkeynes@1102
   257
        if( flash_config != NULL ) {
nkeynes@1102
   258
            memcpy( dest+16, flash_config+2, 8 );
nkeynes@1102
   259
        }
nkeynes@1102
   260
        break;
nkeynes@1102
   261
    case 2: /* SYSINFO_ICON */
nkeynes@1102
   262
        /* Not supported yet */
nkeynes@1102
   263
        break;
nkeynes@1102
   264
    case 3: /* SYSINFO_ID */
nkeynes@1102
   265
        sh4r.r[0] = 0x8c000068;
nkeynes@1102
   266
        break;
nkeynes@1102
   267
    }
nkeynes@1102
   268
}
nkeynes@1102
   269
nkeynes@1102
   270
static void bios_flashrom_vector( uint32_t syscallid )
nkeynes@1102
   271
{
nkeynes@1102
   272
    char *dest;
nkeynes@1102
   273
    DEBUG( "BIOS FLASHROM: r4 = %08X, r5 = %08X, r6 = %08x, r7= %08X", sh4r.r[4], sh4r.r[5], sh4r.r[6], sh4r.r[7] );
nkeynes@1102
   274
nkeynes@1102
   275
    switch( sh4r.r[7] ) {
nkeynes@1102
   276
    case 0: /* FLASHROM_INFO */
nkeynes@1102
   277
        break;
nkeynes@1102
   278
    case 1: /* FLASHROM_READ */
nkeynes@1102
   279
nkeynes@1102
   280
        break;
nkeynes@1102
   281
    case 2: /* FLASHROM_WRITE */
nkeynes@1102
   282
        break;
nkeynes@1102
   283
    case 3: /* FLASHROM_DELETE */
nkeynes@1102
   284
        break;
nkeynes@1102
   285
    }
nkeynes@1102
   286
}
nkeynes@1102
   287
nkeynes@1102
   288
static void bios_romfont_vector( uint32_t syscallid )
nkeynes@1102
   289
{
nkeynes@1102
   290
    DEBUG( "BIOS ROMFONT: r4 = %08X, r5 = %08X, r6 = %08x, r7= %08X", sh4r.r[4], sh4r.r[5], sh4r.r[6], sh4r.r[7] );
nkeynes@1102
   291
    /* Not implemented */
nkeynes@1102
   292
}
nkeynes@1102
   293
nkeynes@1102
   294
static void bios_gdrom_vector( uint32_t syscallid )
nkeynes@87
   295
{
nkeynes@1100
   296
    gdrom_queue_entry_t cmd;
nkeynes@87
   297
nkeynes@1102
   298
    DEBUG( "BIOS GDROM: r4 = %08X, r5 = %08X, r6 = %08x, r7= %08X", sh4r.r[4], sh4r.r[5], sh4r.r[6], sh4r.r[7] );
nkeynes@1102
   299
nkeynes@1102
   300
    switch( sh4r.r[6] ) {
nkeynes@1102
   301
    case 0: /* GD-Rom */
nkeynes@1102
   302
        switch( sh4r.r[7] ) {
nkeynes@1102
   303
        case 0: /* Send command */
nkeynes@1102
   304
            sh4r.r[0] = bios_gdrom_enqueue( sh4r.r[4], sh4r.r[5] );
nkeynes@1102
   305
            break;
nkeynes@1102
   306
        case 1:  /* Check command */
nkeynes@1102
   307
            cmd = bios_gdrom_get_command( sh4r.r[4] );
nkeynes@1102
   308
            if( cmd == NULL ) {
nkeynes@1102
   309
                sh4r.r[0] = GD_CMD_STATUS_NONE;
nkeynes@1102
   310
            } else {
nkeynes@1102
   311
                sh4r.r[0] = cmd->status;
nkeynes@1102
   312
                if( cmd->status == GD_CMD_STATUS_ERROR &&
nkeynes@1102
   313
                        sh4r.r[5] != 0 ) {
nkeynes@1102
   314
                    mem_copy_to_sh4( sh4r.r[5], (sh4ptr_t)&cmd->result, sizeof(cmd->result) );
nkeynes@736
   315
                }
nkeynes@736
   316
            }
nkeynes@736
   317
            break;
nkeynes@1102
   318
        case 2: /* Mainloop */
nkeynes@1102
   319
            bios_gdrom_run_queue();
nkeynes@736
   320
            break;
nkeynes@1102
   321
        case 3: /* Init */
nkeynes@1102
   322
            bios_gdrom_init();
nkeynes@1102
   323
            break;
nkeynes@1102
   324
        case 4: /* Drive status */
nkeynes@1102
   325
            if( sh4r.r[4] != 0 ) {
nkeynes@1102
   326
                mem_copy_to_sh4( sh4r.r[4], (sh4ptr_t)&bios_gdrom_status,
nkeynes@1102
   327
                        sizeof(bios_gdrom_status) );
nkeynes@1102
   328
            }
nkeynes@1102
   329
            sh4r.r[0] = 0;
nkeynes@1102
   330
            break;
nkeynes@1102
   331
        case 8: /* Abort command */
nkeynes@1102
   332
            cmd = bios_gdrom_get_command( sh4r.r[4] );
nkeynes@1102
   333
            if( cmd == NULL || cmd->status != GD_CMD_STATUS_ACTIVE ) {
nkeynes@1102
   334
                sh4r.r[0] = -1;
nkeynes@1102
   335
            } else {
nkeynes@1102
   336
                cmd->status = GD_CMD_STATUS_ABORT;
nkeynes@1102
   337
                sh4r.r[0] = 0;
nkeynes@1102
   338
            }
nkeynes@1102
   339
            break;
nkeynes@1102
   340
        case 9: /* Reset */
nkeynes@1102
   341
            break;
nkeynes@1102
   342
        case 10: /* Set mode */
nkeynes@1102
   343
            sh4r.r[0] = 0;
nkeynes@1102
   344
            break;
nkeynes@736
   345
        }
nkeynes@736
   346
        break;
nkeynes@1102
   347
        case -1: /* Misc */
nkeynes@1102
   348
        break;
nkeynes@1102
   349
        default: /* ??? */
nkeynes@1102
   350
            break;
nkeynes@1102
   351
    }
nkeynes@1102
   352
}
nkeynes@1102
   353
nkeynes@1102
   354
static void bios_menu_vector( uint32_t syscallid )
nkeynes@1102
   355
{
nkeynes@1102
   356
    DEBUG( "BIOS MENU: r4 = %08X, r5 = %08X, r6 = %08x, r7= %08X", sh4r.r[4], sh4r.r[5], sh4r.r[6], sh4r.r[7] );
nkeynes@1102
   357
nkeynes@1102
   358
    switch( sh4r.r[4] ) {
nkeynes@1102
   359
    case 0:
nkeynes@1102
   360
        WARN( "Entering main program" );
nkeynes@1102
   361
        break;
nkeynes@1102
   362
    case 1:
nkeynes@1102
   363
        WARN( "Program aborted to DC menu");
nkeynes@1102
   364
        dreamcast_stop();
nkeynes@1102
   365
        break;
nkeynes@87
   366
    }
nkeynes@87
   367
}
nkeynes@102
   368
nkeynes@1099
   369
void bios_boot( uint32_t syscallid )
nkeynes@1099
   370
{
nkeynes@1099
   371
    /* Initialize hardware */
nkeynes@1099
   372
    /* Boot disc if present */
nkeynes@1103
   373
    if( !bios_boot_gdrom_disc() ) {
nkeynes@1100
   374
        dreamcast_stop();
nkeynes@1100
   375
    }
nkeynes@1099
   376
}
nkeynes@1099
   377
nkeynes@102
   378
void bios_install( void ) 
nkeynes@102
   379
{
nkeynes@102
   380
    bios_gdrom_init();
nkeynes@1102
   381
    syscall_add_hook_vector( 0xB0, 0x8C0000B0, bios_sysinfo_vector );
nkeynes@1102
   382
    syscall_add_hook_vector( 0xB4, 0x8C0000B4, bios_romfont_vector );
nkeynes@1102
   383
    syscall_add_hook_vector( 0xB8, 0x8C0000B8, bios_flashrom_vector );
nkeynes@1102
   384
    syscall_add_hook_vector( 0xBC, 0x8C0000BC, bios_gdrom_vector );
nkeynes@1102
   385
    syscall_add_hook_vector( 0xE0, 0x8C0000E0, bios_menu_vector );
nkeynes@102
   386
}
nkeynes@1099
   387
nkeynes@1099
   388
#define MIN_ISO_SECTORS 32
nkeynes@1099
   389
nkeynes@1099
   390
gboolean bios_boot_gdrom_disc( void )
nkeynes@1099
   391
{
nkeynes@1099
   392
    cdrom_disc_t disc = gdrom_get_current_disc();
nkeynes@1099
   393
nkeynes@1099
   394
    int status = gdrom_get_drive_status();
nkeynes@1099
   395
    if( status == CDROM_DISC_NONE ) {
nkeynes@1099
   396
        ERROR( "No disc in drive" );
nkeynes@1099
   397
        return FALSE;
nkeynes@1099
   398
    }
nkeynes@1099
   399
nkeynes@1099
   400
    /* Find the bootable data track (if present) */
nkeynes@1099
   401
    cdrom_track_t track = gdrom_disc_get_boot_track(disc);
nkeynes@1099
   402
    if( track == NULL ) {
nkeynes@1099
   403
        ERROR( "Disc is not bootable" );
nkeynes@1099
   404
        return FALSE;
nkeynes@1099
   405
    }
nkeynes@1099
   406
    uint32_t lba = track->lba;
nkeynes@1099
   407
    uint32_t sectors = cdrom_disc_get_track_size(disc,track);
nkeynes@1099
   408
    if( sectors < MIN_ISO_SECTORS ) {
nkeynes@1099
   409
        ERROR( "Disc is not bootable" );
nkeynes@1099
   410
        return FALSE;
nkeynes@1099
   411
    }
nkeynes@1099
   412
    /* Load the initial bootstrap into DC ram at 8c008000 */
nkeynes@1099
   413
    size_t length = BOOTSTRAP_SIZE;
nkeynes@1099
   414
    unsigned char *bootstrap = mem_get_region(BOOTSTRAP_LOAD_ADDR);
nkeynes@1099
   415
    if( cdrom_disc_read_sectors( disc, track->lba, BOOTSTRAP_SIZE/2048,
nkeynes@1099
   416
            CDROM_READ_DATA|CDROM_READ_MODE2_FORM1, bootstrap, &length ) !=
nkeynes@1099
   417
            CDROM_ERROR_OK ) {
nkeynes@1099
   418
        ERROR( "Disc is not bootable" );
nkeynes@1099
   419
        return FALSE;
nkeynes@1099
   420
    }
nkeynes@1099
   421
nkeynes@1099
   422
    /* Check the magic just to be sure */
nkeynes@1099
   423
    dc_bootstrap_head_t metadata = (dc_bootstrap_head_t)bootstrap;
nkeynes@1099
   424
    if( memcmp( metadata->magic, BOOTSTRAP_MAGIC, BOOTSTRAP_MAGIC_SIZE ) != 0 ) {
nkeynes@1099
   425
        ERROR( "Disc is not bootable (missing dreamcast bootstrap)" );
nkeynes@1099
   426
        return FALSE;
nkeynes@1099
   427
    }
nkeynes@1099
   428
nkeynes@1099
   429
    /* Get the initial program from the bootstrap (usually 1ST_READ.BIN) */
nkeynes@1099
   430
    char program_name[17];
nkeynes@1099
   431
    memcpy(program_name, metadata->boot_file, 16);
nkeynes@1099
   432
    program_name[16] = '\0';
nkeynes@1099
   433
    for( int i=15; i >= 0 && program_name[i] == ' '; i-- ) {
nkeynes@1099
   434
        program_name[i] = '\0';
nkeynes@1099
   435
    }
nkeynes@1099
   436
nkeynes@1099
   437
    /* Bootstrap is good. Now find the program in the actual filesystem... */
nkeynes@1099
   438
    isofs_reader_t iso = isofs_reader_new_from_track( disc, track, NULL );
nkeynes@1099
   439
    if( iso == NULL ) {
nkeynes@1099
   440
        ERROR( "Disc is not bootable" );
nkeynes@1099
   441
        return FALSE;
nkeynes@1099
   442
    }
nkeynes@1099
   443
    isofs_reader_dirent_t ent = isofs_reader_get_file( iso, program_name );
nkeynes@1099
   444
    if( ent == NULL ) {
nkeynes@1099
   445
        ERROR( "Disc is not bootable (initial program '%s' not found)", program_name );
nkeynes@1099
   446
        isofs_reader_destroy(iso);
nkeynes@1099
   447
        return FALSE;
nkeynes@1099
   448
    }
nkeynes@1099
   449
nkeynes@1099
   450
    if( ent->size > (0x8D000000 - BINARY_LOAD_ADDR) ) {
nkeynes@1099
   451
        /* Bootstrap isn't going to fit in memory. Complain and abort */
nkeynes@1099
   452
        ERROR( "Disc is not bootable (initial program too large)" );
nkeynes@1099
   453
        isofs_reader_destroy(iso);
nkeynes@1099
   454
        return FALSE;
nkeynes@1099
   455
    }
nkeynes@1099
   456
    unsigned char *program = mem_get_region(BINARY_LOAD_ADDR);
nkeynes@1099
   457
    int program_sectors = (ent->size+2047)/2048;
nkeynes@1099
   458
    if( disc->disc_type == CDROM_DISC_GDROM ) {
nkeynes@1099
   459
        /* Load the binary directly into RAM */
nkeynes@1099
   460
        if( isofs_reader_read_file( iso, ent, 0, ent->size, program ) !=
nkeynes@1099
   461
                CDROM_ERROR_OK ) {
nkeynes@1099
   462
            ERROR( "Disc is not bootable (failed to read initial program)\n" );
nkeynes@1099
   463
            isofs_reader_destroy(iso);
nkeynes@1099
   464
            return FALSE;
nkeynes@1099
   465
        }
nkeynes@1100
   466
        asic_enable_ide_interface(TRUE);
nkeynes@1099
   467
    } else {
nkeynes@1099
   468
        /* Load the binary into a temp buffer */
nkeynes@1099
   469
        unsigned char tmp[program_sectors*2048];
nkeynes@1099
   470
        if( isofs_reader_read_file( iso, ent, 0, ent->size, tmp ) !=
nkeynes@1099
   471
                CDROM_ERROR_OK ) {
nkeynes@1099
   472
            ERROR( "Disc is not bootable (failed to read initial program)\n" );
nkeynes@1099
   473
            isofs_reader_destroy(iso);
nkeynes@1099
   474
            return FALSE;
nkeynes@1099
   475
        }
nkeynes@1099
   476
        bootprogram_unscramble(program, tmp, ent->size);
nkeynes@1100
   477
        asic_enable_ide_interface(FALSE);
nkeynes@1099
   478
    }
nkeynes@1099
   479
    isofs_reader_destroy(iso);
nkeynes@1100
   480
    dreamcast_program_loaded( "", BOOTSTRAP_ENTRY_ADDR );
nkeynes@1100
   481
    return TRUE;
nkeynes@1099
   482
}
.