Search
lxdream.org :: lxdream/src/bios.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/bios.c
changeset 1298:d0eb2307b847
prev1107:7b279d10f46f
author nkeynes
date Wed Feb 04 08:38:23 2015 +1000 (9 years ago)
permissions -rw-r--r--
last change Fix assorted compile warnings reported by Clang
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@1107
    27
#include "drivers/cdrom/isofs.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@1298
   216
static sh4ptr_t bios_find_flash_config( sh4addr_t segment, uint32_t length )
nkeynes@1102
   217
{
nkeynes@1298
   218
    sh4ptr_t start = mem_get_region(segment);
nkeynes@1298
   219
    sh4ptr_t p = start + 0x80;
nkeynes@1298
   220
    sh4ptr_t end = p + length;
nkeynes@1298
   221
    sh4ptr_t 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@1298
   239
    sh4ptr_t flash_segment, flash_config;
nkeynes@1298
   240
    sh4ptr_t 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
    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
   273
nkeynes@1102
   274
    switch( sh4r.r[7] ) {
nkeynes@1102
   275
    case 0: /* FLASHROM_INFO */
nkeynes@1102
   276
        break;
nkeynes@1102
   277
    case 1: /* FLASHROM_READ */
nkeynes@1102
   278
nkeynes@1102
   279
        break;
nkeynes@1102
   280
    case 2: /* FLASHROM_WRITE */
nkeynes@1102
   281
        break;
nkeynes@1102
   282
    case 3: /* FLASHROM_DELETE */
nkeynes@1102
   283
        break;
nkeynes@1102
   284
    }
nkeynes@1102
   285
}
nkeynes@1102
   286
nkeynes@1102
   287
static void bios_romfont_vector( uint32_t syscallid )
nkeynes@1102
   288
{
nkeynes@1102
   289
    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
   290
    /* Not implemented */
nkeynes@1102
   291
}
nkeynes@1102
   292
nkeynes@1102
   293
static void bios_gdrom_vector( uint32_t syscallid )
nkeynes@87
   294
{
nkeynes@1100
   295
    gdrom_queue_entry_t cmd;
nkeynes@87
   296
nkeynes@1102
   297
    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
   298
nkeynes@1102
   299
    switch( sh4r.r[6] ) {
nkeynes@1102
   300
    case 0: /* GD-Rom */
nkeynes@1102
   301
        switch( sh4r.r[7] ) {
nkeynes@1102
   302
        case 0: /* Send command */
nkeynes@1102
   303
            sh4r.r[0] = bios_gdrom_enqueue( sh4r.r[4], sh4r.r[5] );
nkeynes@1102
   304
            break;
nkeynes@1102
   305
        case 1:  /* Check command */
nkeynes@1102
   306
            cmd = bios_gdrom_get_command( sh4r.r[4] );
nkeynes@1102
   307
            if( cmd == NULL ) {
nkeynes@1102
   308
                sh4r.r[0] = GD_CMD_STATUS_NONE;
nkeynes@1102
   309
            } else {
nkeynes@1102
   310
                sh4r.r[0] = cmd->status;
nkeynes@1102
   311
                if( cmd->status == GD_CMD_STATUS_ERROR &&
nkeynes@1102
   312
                        sh4r.r[5] != 0 ) {
nkeynes@1102
   313
                    mem_copy_to_sh4( sh4r.r[5], (sh4ptr_t)&cmd->result, sizeof(cmd->result) );
nkeynes@736
   314
                }
nkeynes@736
   315
            }
nkeynes@736
   316
            break;
nkeynes@1102
   317
        case 2: /* Mainloop */
nkeynes@1102
   318
            bios_gdrom_run_queue();
nkeynes@736
   319
            break;
nkeynes@1102
   320
        case 3: /* Init */
nkeynes@1102
   321
            bios_gdrom_init();
nkeynes@1102
   322
            break;
nkeynes@1102
   323
        case 4: /* Drive status */
nkeynes@1102
   324
            if( sh4r.r[4] != 0 ) {
nkeynes@1102
   325
                mem_copy_to_sh4( sh4r.r[4], (sh4ptr_t)&bios_gdrom_status,
nkeynes@1102
   326
                        sizeof(bios_gdrom_status) );
nkeynes@1102
   327
            }
nkeynes@1102
   328
            sh4r.r[0] = 0;
nkeynes@1102
   329
            break;
nkeynes@1102
   330
        case 8: /* Abort command */
nkeynes@1102
   331
            cmd = bios_gdrom_get_command( sh4r.r[4] );
nkeynes@1102
   332
            if( cmd == NULL || cmd->status != GD_CMD_STATUS_ACTIVE ) {
nkeynes@1102
   333
                sh4r.r[0] = -1;
nkeynes@1102
   334
            } else {
nkeynes@1102
   335
                cmd->status = GD_CMD_STATUS_ABORT;
nkeynes@1102
   336
                sh4r.r[0] = 0;
nkeynes@1102
   337
            }
nkeynes@1102
   338
            break;
nkeynes@1102
   339
        case 9: /* Reset */
nkeynes@1102
   340
            break;
nkeynes@1102
   341
        case 10: /* Set mode */
nkeynes@1102
   342
            sh4r.r[0] = 0;
nkeynes@1102
   343
            break;
nkeynes@736
   344
        }
nkeynes@736
   345
        break;
nkeynes@1102
   346
        case -1: /* Misc */
nkeynes@1102
   347
        break;
nkeynes@1102
   348
        default: /* ??? */
nkeynes@1102
   349
            break;
nkeynes@1102
   350
    }
nkeynes@1102
   351
}
nkeynes@1102
   352
nkeynes@1102
   353
static void bios_menu_vector( uint32_t syscallid )
nkeynes@1102
   354
{
nkeynes@1102
   355
    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
   356
nkeynes@1102
   357
    switch( sh4r.r[4] ) {
nkeynes@1102
   358
    case 0:
nkeynes@1102
   359
        WARN( "Entering main program" );
nkeynes@1102
   360
        break;
nkeynes@1102
   361
    case 1:
nkeynes@1102
   362
        WARN( "Program aborted to DC menu");
nkeynes@1102
   363
        dreamcast_stop();
nkeynes@1102
   364
        break;
nkeynes@87
   365
    }
nkeynes@87
   366
}
nkeynes@102
   367
nkeynes@1099
   368
void bios_boot( uint32_t syscallid )
nkeynes@1099
   369
{
nkeynes@1099
   370
    /* Initialize hardware */
nkeynes@1099
   371
    /* Boot disc if present */
nkeynes@1103
   372
    if( !bios_boot_gdrom_disc() ) {
nkeynes@1100
   373
        dreamcast_stop();
nkeynes@1100
   374
    }
nkeynes@1099
   375
}
nkeynes@1099
   376
nkeynes@102
   377
void bios_install( void ) 
nkeynes@102
   378
{
nkeynes@102
   379
    bios_gdrom_init();
nkeynes@1102
   380
    syscall_add_hook_vector( 0xB0, 0x8C0000B0, bios_sysinfo_vector );
nkeynes@1102
   381
    syscall_add_hook_vector( 0xB4, 0x8C0000B4, bios_romfont_vector );
nkeynes@1102
   382
    syscall_add_hook_vector( 0xB8, 0x8C0000B8, bios_flashrom_vector );
nkeynes@1102
   383
    syscall_add_hook_vector( 0xBC, 0x8C0000BC, bios_gdrom_vector );
nkeynes@1102
   384
    syscall_add_hook_vector( 0xE0, 0x8C0000E0, bios_menu_vector );
nkeynes@102
   385
}
nkeynes@1099
   386
nkeynes@1099
   387
#define MIN_ISO_SECTORS 32
nkeynes@1099
   388
nkeynes@1107
   389
static gboolean bios_load_ipl( cdrom_disc_t disc, cdrom_track_t track, const char *program_name,
nkeynes@1107
   390
                               unsigned char *buffer, gboolean unscramble )
nkeynes@1107
   391
{
nkeynes@1107
   392
    gboolean rv = TRUE;
nkeynes@1107
   393
nkeynes@1107
   394
    IsoImageFilesystem *iso = iso_filesystem_new_from_track( disc, track, NULL );
nkeynes@1107
   395
    if( iso == NULL ) {
nkeynes@1107
   396
        ERROR( "Disc is not bootable (invalid ISO9660 filesystem)" );
nkeynes@1107
   397
        return FALSE;
nkeynes@1107
   398
    }
nkeynes@1107
   399
    IsoFileSource *file = NULL;
nkeynes@1107
   400
    int status = iso->get_by_path(iso, program_name, &file );
nkeynes@1107
   401
    if( status != 1 ) {
nkeynes@1107
   402
        ERROR( "Disc is not bootable (initial program '%s' not found)", program_name );
nkeynes@1107
   403
        iso_filesystem_unref(iso);
nkeynes@1107
   404
        return FALSE;
nkeynes@1107
   405
    }
nkeynes@1107
   406
nkeynes@1107
   407
    struct stat st;
nkeynes@1107
   408
    if( iso_file_source_stat(file, &st) == 1 ) {
nkeynes@1107
   409
        if( st.st_size > (0x8D000000 - BINARY_LOAD_ADDR) ) {
nkeynes@1107
   410
            ERROR( "Disc is not bootable (Initial program is too large to fit into memory)" );
nkeynes@1107
   411
            rv = FALSE;
nkeynes@1107
   412
        } else if( iso_file_source_open(file) == 1 ) {
nkeynes@1107
   413
            size_t len;
nkeynes@1107
   414
            if( unscramble ) {
nkeynes@1298
   415
                unsigned char *tmp = g_malloc(st.st_size);
nkeynes@1107
   416
                len = iso_file_source_read(file, tmp, st.st_size);
nkeynes@1107
   417
                bootprogram_unscramble(buffer, tmp, st.st_size);
nkeynes@1107
   418
                g_free(tmp);
nkeynes@1107
   419
            } else {
nkeynes@1107
   420
                len = iso_file_source_read(file, buffer, st.st_size);
nkeynes@1107
   421
            }
nkeynes@1107
   422
nkeynes@1107
   423
            if( len != st.st_size ) {
nkeynes@1107
   424
                ERROR( "Disc is not bootable (Unable to read initial program '%s')", program_name );
nkeynes@1107
   425
                rv = FALSE;
nkeynes@1107
   426
            }
nkeynes@1107
   427
            iso_file_source_close(file);
nkeynes@1107
   428
        }
nkeynes@1107
   429
    } else {
nkeynes@1107
   430
        ERROR( "Disc is not bootable (Unable to get size of initial program '%s')", program_name );
nkeynes@1107
   431
        rv = FALSE;
nkeynes@1107
   432
    }
nkeynes@1107
   433
nkeynes@1107
   434
    iso_file_source_unref(file);
nkeynes@1107
   435
    iso_filesystem_unref(iso);
nkeynes@1107
   436
    return rv;
nkeynes@1107
   437
}
nkeynes@1107
   438
nkeynes@1099
   439
gboolean bios_boot_gdrom_disc( void )
nkeynes@1099
   440
{
nkeynes@1099
   441
    cdrom_disc_t disc = gdrom_get_current_disc();
nkeynes@1099
   442
nkeynes@1099
   443
    int status = gdrom_get_drive_status();
nkeynes@1099
   444
    if( status == CDROM_DISC_NONE ) {
nkeynes@1099
   445
        ERROR( "No disc in drive" );
nkeynes@1099
   446
        return FALSE;
nkeynes@1099
   447
    }
nkeynes@1099
   448
nkeynes@1099
   449
    /* Find the bootable data track (if present) */
nkeynes@1099
   450
    cdrom_track_t track = gdrom_disc_get_boot_track(disc);
nkeynes@1099
   451
    if( track == NULL ) {
nkeynes@1099
   452
        ERROR( "Disc is not bootable" );
nkeynes@1099
   453
        return FALSE;
nkeynes@1099
   454
    }
nkeynes@1099
   455
    uint32_t sectors = cdrom_disc_get_track_size(disc,track);
nkeynes@1099
   456
    if( sectors < MIN_ISO_SECTORS ) {
nkeynes@1099
   457
        ERROR( "Disc is not bootable" );
nkeynes@1099
   458
        return FALSE;
nkeynes@1099
   459
    }
nkeynes@1099
   460
    /* Load the initial bootstrap into DC ram at 8c008000 */
nkeynes@1099
   461
    size_t length = BOOTSTRAP_SIZE;
nkeynes@1099
   462
    unsigned char *bootstrap = mem_get_region(BOOTSTRAP_LOAD_ADDR);
nkeynes@1099
   463
    if( cdrom_disc_read_sectors( disc, track->lba, BOOTSTRAP_SIZE/2048,
nkeynes@1099
   464
            CDROM_READ_DATA|CDROM_READ_MODE2_FORM1, bootstrap, &length ) !=
nkeynes@1099
   465
            CDROM_ERROR_OK ) {
nkeynes@1099
   466
        ERROR( "Disc is not bootable" );
nkeynes@1099
   467
        return FALSE;
nkeynes@1099
   468
    }
nkeynes@1099
   469
nkeynes@1099
   470
    /* Check the magic just to be sure */
nkeynes@1099
   471
    dc_bootstrap_head_t metadata = (dc_bootstrap_head_t)bootstrap;
nkeynes@1099
   472
    if( memcmp( metadata->magic, BOOTSTRAP_MAGIC, BOOTSTRAP_MAGIC_SIZE ) != 0 ) {
nkeynes@1099
   473
        ERROR( "Disc is not bootable (missing dreamcast bootstrap)" );
nkeynes@1099
   474
        return FALSE;
nkeynes@1099
   475
    }
nkeynes@1099
   476
nkeynes@1099
   477
    /* Get the initial program from the bootstrap (usually 1ST_READ.BIN) */
nkeynes@1107
   478
    char program_name[18] = "/";
nkeynes@1107
   479
    memcpy(program_name+1, metadata->boot_file, 16);
nkeynes@1107
   480
    program_name[17] = '\0';
nkeynes@1107
   481
    for( int i=16; i >= 0 && program_name[i] == ' '; i-- ) {
nkeynes@1099
   482
        program_name[i] = '\0';
nkeynes@1099
   483
    }
nkeynes@1099
   484
nkeynes@1099
   485
    /* Bootstrap is good. Now find the program in the actual filesystem... */
nkeynes@1107
   486
    unsigned char *program = mem_get_region(BINARY_LOAD_ADDR);
nkeynes@1107
   487
    gboolean isGDROM = (disc->disc_type == CDROM_DISC_GDROM );
nkeynes@1107
   488
    if( !bios_load_ipl( disc, track, program_name, program, !isGDROM ) )
nkeynes@1099
   489
        return FALSE;
nkeynes@1107
   490
    asic_enable_ide_interface(isGDROM);
nkeynes@1100
   491
    dreamcast_program_loaded( "", BOOTSTRAP_ENTRY_ADDR );
nkeynes@1100
   492
    return TRUE;
nkeynes@1099
   493
}
.