Search
lxdream.org :: lxdream/src/loader.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/loader.c
changeset 1075:1a21750d300c
prev1036:af7b0c5905dd
next1095:a8b798030464
author nkeynes
date Fri Jul 31 13:45:32 2009 +1000 (11 years ago)
permissions -rw-r--r--
last change Remove or change the level of a bunch of INFO messages that shouldn't really
be INFO level
file annotate diff log raw
nkeynes@26
     1
/**
nkeynes@561
     2
 * $Id$
nkeynes@1
     3
 *
nkeynes@26
     4
 * File loading routines, mostly for loading demos without going through the
nkeynes@26
     5
 * whole procedure of making a CD image for them.
nkeynes@26
     6
 *
nkeynes@26
     7
 * Copyright (c) 2005 Nathan Keynes.
nkeynes@26
     8
 *
nkeynes@26
     9
 * This program is free software; you can redistribute it and/or modify
nkeynes@26
    10
 * it under the terms of the GNU General Public License as published by
nkeynes@26
    11
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@26
    12
 * (at your option) any later version.
nkeynes@26
    13
 *
nkeynes@26
    14
 * This program is distributed in the hope that it will be useful,
nkeynes@26
    15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@26
    16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@26
    17
 * GNU General Public License for more details.
nkeynes@1
    18
 */
nkeynes@1
    19
nkeynes@481
    20
#include <unistd.h>
nkeynes@1
    21
#include <stdio.h>
nkeynes@736
    22
#include <string.h>
nkeynes@1
    23
#include <fcntl.h>
nkeynes@1
    24
#include <sys/stat.h>
nkeynes@1
    25
#include <errno.h>
nkeynes@1
    26
#include <stdint.h>
nkeynes@105
    27
#include <elf.h>
nkeynes@26
    28
#include "mem.h"
nkeynes@26
    29
#include "bootstrap.h"
nkeynes@171
    30
#include "dreamcast.h"
nkeynes@450
    31
#include "config.h"
nkeynes@427
    32
#include "loader.h"
nkeynes@481
    33
nkeynes@26
    34
char bootstrap_magic[32] = "SEGA SEGAKATANA SEGA ENTERPRISES";
nkeynes@1
    35
char iso_magic[6] = "\001CD001";
nkeynes@26
    36
char *file_loader_extensions[][2] = { 
nkeynes@736
    37
        { "sbi", "Self Boot Inducer" },
nkeynes@736
    38
        { "bin", "SH4 Bin file" },
nkeynes@736
    39
        { NULL, NULL } };
nkeynes@26
    40
nkeynes@26
    41
#define BOOTSTRAP_LOAD_ADDR 0x8C008000
nkeynes@26
    42
#define BOOTSTRAP_SIZE 32768
nkeynes@26
    43
nkeynes@26
    44
#define BINARY_LOAD_ADDR 0x8C010000
nkeynes@1
    45
nkeynes@1
    46
#define CDI_V2 0x80000004
nkeynes@1
    47
#define CDI_V3 0x80000005
nkeynes@1
    48
nkeynes@543
    49
gboolean file_load_elf_fd( const gchar *filename, int fd );
nkeynes@427
    50
nkeynes@427
    51
nkeynes@26
    52
gboolean file_load_magic( const gchar *filename )
nkeynes@1
    53
{
nkeynes@1
    54
    char buf[32];
nkeynes@1
    55
    struct stat st;
nkeynes@446
    56
    gboolean result = TRUE;
nkeynes@736
    57
nkeynes@1
    58
    int fd = open( filename, O_RDONLY );
nkeynes@1
    59
    if( fd == -1 ) {
nkeynes@26
    60
        return FALSE;
nkeynes@1
    61
    }
nkeynes@736
    62
nkeynes@1
    63
    fstat( fd, &st );
nkeynes@736
    64
nkeynes@1
    65
    /* begin magic */
nkeynes@1
    66
    if( read( fd, buf, 32 ) != 32 ) {
nkeynes@1
    67
        ERROR( "Unable to read from file '%s'", filename );
nkeynes@1
    68
        close(fd);
nkeynes@26
    69
        return FALSE;
nkeynes@1
    70
    }
nkeynes@26
    71
    if( memcmp( buf, bootstrap_magic, 32 ) == 0 ) {
nkeynes@1
    72
        /* we have a DC bootstrap */
nkeynes@1
    73
        if( st.st_size == BOOTSTRAP_SIZE ) {
nkeynes@502
    74
            sh4ptr_t load = mem_get_region( BOOTSTRAP_LOAD_ADDR );
nkeynes@1
    75
            lseek( fd, 0, SEEK_SET );
nkeynes@1
    76
            read( fd, load, BOOTSTRAP_SIZE );
nkeynes@171
    77
            bootstrap_dump( load, TRUE );
nkeynes@736
    78
            dreamcast_program_loaded( filename, BOOTSTRAP_LOAD_ADDR + 0x300 );
nkeynes@1
    79
        } else {
nkeynes@1
    80
            /* look for a valid ISO9660 header */
nkeynes@1
    81
            lseek( fd, 32768, SEEK_SET );
nkeynes@1
    82
            read( fd, buf, 8 );
nkeynes@1
    83
            if( memcmp( buf, iso_magic, 6 ) == 0 ) {
nkeynes@1
    84
                /* Alright, got it */
nkeynes@1075
    85
                WARN( "ISO images not supported yet" );
nkeynes@1
    86
            }
nkeynes@1
    87
        }
nkeynes@26
    88
    } else if( memcmp( buf, "PK\x03\x04", 4 ) == 0 ) {
nkeynes@736
    89
        /* ZIP file, aka SBI file */
nkeynes@736
    90
        WARN( "SBI files not supported yet" );
nkeynes@736
    91
        result = FALSE;
nkeynes@294
    92
    } else if( memcmp( buf, DREAMCAST_SAVE_MAGIC, 16 ) == 0 ) {
nkeynes@736
    93
        /* Save state */
nkeynes@736
    94
        result = (dreamcast_load_state( filename )==0);
nkeynes@105
    95
    } else if( buf[0] == 0x7F && buf[1] == 'E' && 
nkeynes@736
    96
            buf[2] == 'L' && buf[3] == 'F' ) {
nkeynes@736
    97
        /* ELF binary */
nkeynes@736
    98
        lseek( fd, 0, SEEK_SET );
nkeynes@736
    99
        result = file_load_elf_fd( filename, fd );
nkeynes@1
   100
    } else {
nkeynes@736
   101
        result = FALSE;
nkeynes@446
   102
    }
nkeynes@1
   103
    close(fd);
nkeynes@446
   104
    return result;
nkeynes@1
   105
}
nkeynes@19
   106
nkeynes@543
   107
void file_load_postload( const gchar *filename, int pc )
nkeynes@110
   108
{
nkeynes@1036
   109
    gchar *bootstrap_file = lxdream_get_global_config_path_value(CONFIG_BOOTSTRAP);
nkeynes@825
   110
    if( bootstrap_file != NULL && bootstrap_file[0] != '\0' ) {
nkeynes@736
   111
        /* Load in a bootstrap before the binary, to initialize everything
nkeynes@736
   112
         * correctly
nkeynes@736
   113
         */
nkeynes@543
   114
        if( mem_load_block( bootstrap_file, BOOTSTRAP_LOAD_ADDR, BOOTSTRAP_SIZE ) == 0 ) {
nkeynes@736
   115
            dreamcast_program_loaded( filename, BOOTSTRAP_LOAD_ADDR+0x300 );
nkeynes@1036
   116
            g_free(bootstrap_file);
nkeynes@736
   117
            return;
nkeynes@736
   118
        }
nkeynes@88
   119
    }
nkeynes@543
   120
    dreamcast_program_loaded( filename, pc );
nkeynes@1036
   121
    g_free(bootstrap_file);
nkeynes@110
   122
}    
nkeynes@110
   123
nkeynes@110
   124
nkeynes@427
   125
gboolean file_load_binary( const gchar *filename )
nkeynes@110
   126
{
nkeynes@110
   127
    /* Load the binary itself */
nkeynes@427
   128
    if(  mem_load_block( filename, BINARY_LOAD_ADDR, -1 ) == 0 ) {
nkeynes@736
   129
        file_load_postload( filename, BINARY_LOAD_ADDR );
nkeynes@736
   130
        return TRUE;
nkeynes@427
   131
    } else {
nkeynes@736
   132
        return FALSE;
nkeynes@427
   133
    }
nkeynes@19
   134
}
nkeynes@105
   135
nkeynes@543
   136
gboolean file_load_elf_fd( const gchar *filename, int fd ) 
nkeynes@105
   137
{
nkeynes@105
   138
    Elf32_Ehdr head;
nkeynes@105
   139
    Elf32_Phdr phdr;
nkeynes@105
   140
    int i;
nkeynes@105
   141
nkeynes@105
   142
    if( read( fd, &head, sizeof(head) ) != sizeof(head) )
nkeynes@736
   143
        return FALSE;
nkeynes@105
   144
    if( head.e_ident[EI_CLASS] != ELFCLASS32 ||
nkeynes@736
   145
            head.e_ident[EI_DATA] != ELFDATA2LSB ||
nkeynes@736
   146
            head.e_ident[EI_VERSION] != 1 ||
nkeynes@736
   147
            head.e_type != ET_EXEC ||
nkeynes@736
   148
            head.e_machine != EM_SH ||
nkeynes@736
   149
            head.e_version != 1 ) {
nkeynes@736
   150
        ERROR( "File is not an SH4 ELF executable file" );
nkeynes@736
   151
        return FALSE;
nkeynes@105
   152
    }
nkeynes@105
   153
nkeynes@105
   154
    /* Program headers */
nkeynes@105
   155
    for( i=0; i<head.e_phnum; i++ ) {
nkeynes@736
   156
        lseek( fd, head.e_phoff + i*head.e_phentsize, SEEK_SET );
nkeynes@736
   157
        read( fd, &phdr, sizeof(phdr) );
nkeynes@736
   158
        if( phdr.p_type == PT_LOAD ) {
nkeynes@736
   159
            lseek( fd, phdr.p_offset, SEEK_SET );
nkeynes@736
   160
            sh4ptr_t target = mem_get_region( phdr.p_vaddr );
nkeynes@736
   161
            read( fd, target, phdr.p_filesz );
nkeynes@736
   162
            if( phdr.p_memsz > phdr.p_filesz ) {
nkeynes@736
   163
                memset( target + phdr.p_filesz, 0, phdr.p_memsz - phdr.p_filesz );
nkeynes@736
   164
            }
nkeynes@736
   165
            INFO( "Loaded %d bytes to %08X", phdr.p_filesz, phdr.p_vaddr );
nkeynes@736
   166
        }
nkeynes@105
   167
    }
nkeynes@736
   168
nkeynes@543
   169
    file_load_postload( filename, head.e_entry );
nkeynes@446
   170
    return TRUE;
nkeynes@105
   171
}
.