Search
lxdream.org :: lxdream/src/loader.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/loader.c
changeset 180:e6dcf9b65658
prev171:3542185a8cf9
next294:a5beff9b2b85
author nkeynes
date Wed Jan 03 09:00:17 2007 +0000 (17 years ago)
permissions -rw-r--r--
last change Adjust timers when they're read rather than waiting until the next time
slice. Also temporarily cut the CPU time by 4.
Initialize the FRQCR register to 0x0E0A for convenience
file annotate diff log raw
nkeynes@26
     1
/**
nkeynes@180
     2
 * $Id: loader.c,v 1.14 2006-07-02 04:59:00 nkeynes Exp $
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@1
    20
#include <stdio.h>
nkeynes@1
    21
#include <fcntl.h>
nkeynes@1
    22
#include <sys/stat.h>
nkeynes@1
    23
#include <errno.h>
nkeynes@1
    24
#include <stdint.h>
nkeynes@105
    25
#include <elf.h>
nkeynes@25
    26
#include "gui/gui.h"
nkeynes@26
    27
#include "mem.h"
nkeynes@1
    28
#include "sh4core.h"
nkeynes@26
    29
#include "bootstrap.h"
nkeynes@171
    30
#include "dreamcast.h"
nkeynes@1
    31
nkeynes@26
    32
char bootstrap_magic[32] = "SEGA SEGAKATANA SEGA ENTERPRISES";
nkeynes@1
    33
char iso_magic[6] = "\001CD001";
nkeynes@26
    34
char *file_loader_extensions[][2] = { 
nkeynes@26
    35
    { "sbi", "Self Boot Inducer" },
nkeynes@26
    36
    { "bin", "SH4 Bin file" },
nkeynes@26
    37
    { NULL, NULL } };
nkeynes@26
    38
nkeynes@26
    39
#define BOOTSTRAP_LOAD_ADDR 0x8C008000
nkeynes@26
    40
#define BOOTSTRAP_SIZE 32768
nkeynes@26
    41
nkeynes@26
    42
#define BINARY_LOAD_ADDR 0x8C010000
nkeynes@1
    43
nkeynes@1
    44
#define CDI_V2 0x80000004
nkeynes@1
    45
#define CDI_V3 0x80000005
nkeynes@1
    46
nkeynes@26
    47
gboolean file_load_magic( const gchar *filename )
nkeynes@1
    48
{
nkeynes@1
    49
    char buf[32];
nkeynes@1
    50
    uint32_t tmpa[2];
nkeynes@1
    51
    struct stat st;
nkeynes@1
    52
    
nkeynes@1
    53
    int fd = open( filename, O_RDONLY );
nkeynes@1
    54
    if( fd == -1 ) {
nkeynes@1
    55
        ERROR( "Unable to open file: '%s' (%s)", filename,
nkeynes@1
    56
               strerror(errno) );
nkeynes@26
    57
        return FALSE;
nkeynes@1
    58
    }
nkeynes@88
    59
    
nkeynes@1
    60
    fstat( fd, &st );
nkeynes@88
    61
    /*
nkeynes@1
    62
    if( st.st_size < 32768 ) {
nkeynes@1
    63
        ERROR( "File '%s' too small to be a dreamcast image", filename );
nkeynes@1
    64
        close(fd);
nkeynes@26
    65
        return FALSE;
nkeynes@1
    66
    }
nkeynes@88
    67
    */
nkeynes@1
    68
    
nkeynes@1
    69
    /* begin magic */
nkeynes@1
    70
    if( read( fd, buf, 32 ) != 32 ) {
nkeynes@1
    71
        ERROR( "Unable to read from file '%s'", filename );
nkeynes@1
    72
        close(fd);
nkeynes@26
    73
        return FALSE;
nkeynes@1
    74
    }
nkeynes@26
    75
    if( memcmp( buf, bootstrap_magic, 32 ) == 0 ) {
nkeynes@1
    76
        /* we have a DC bootstrap */
nkeynes@1
    77
        if( st.st_size == BOOTSTRAP_SIZE ) {
nkeynes@1
    78
            char *load = mem_get_region( BOOTSTRAP_LOAD_ADDR );
nkeynes@1
    79
            lseek( fd, 0, SEEK_SET );
nkeynes@1
    80
            read( fd, load, BOOTSTRAP_SIZE );
nkeynes@171
    81
            bootstrap_dump( load, TRUE );
nkeynes@1
    82
            sh4_set_pc( BOOTSTRAP_LOAD_ADDR + 0x300 );
nkeynes@27
    83
            gtk_gui_update();
nkeynes@1
    84
        } else {
nkeynes@1
    85
            /* look for a valid ISO9660 header */
nkeynes@1
    86
            lseek( fd, 32768, SEEK_SET );
nkeynes@1
    87
            read( fd, buf, 8 );
nkeynes@1
    88
            if( memcmp( buf, iso_magic, 6 ) == 0 ) {
nkeynes@1
    89
                /* Alright, got it */
nkeynes@1
    90
                INFO( "Loading ISO9660 filesystem from '%s'",
nkeynes@1
    91
                      filename );
nkeynes@1
    92
            }
nkeynes@1
    93
        }
nkeynes@26
    94
    } else if( memcmp( buf, "PK\x03\x04", 4 ) == 0 ) {
nkeynes@26
    95
	/* ZIP file, aka SBI file */
nkeynes@26
    96
	WARN( "SBI files not supported yet" );
nkeynes@105
    97
    } else if( buf[0] == 0x7F && buf[1] == 'E' && 
nkeynes@105
    98
	       buf[2] == 'L' && buf[3] == 'F' ) {
nkeynes@88
    99
	/* ELF binary */
nkeynes@105
   100
	lseek( fd, 0, SEEK_SET );
nkeynes@105
   101
	file_load_elf_fd( fd );
nkeynes@1
   102
    } else {
nkeynes@26
   103
	/* Assume raw binary */
nkeynes@26
   104
	file_load_binary( filename );
nkeynes@26
   105
    } 
nkeynes@1
   106
    close(fd);
nkeynes@26
   107
    return TRUE;
nkeynes@1
   108
}
nkeynes@19
   109
nkeynes@110
   110
int file_load_postload( int pc )
nkeynes@110
   111
{
nkeynes@171
   112
    const gchar *bootstrap_file = dreamcast_get_config_value(CONFIG_BOOTSTRAP);
nkeynes@88
   113
    if( bootstrap_file != NULL ) {
nkeynes@88
   114
	/* Load in a bootstrap before the binary, to initialize everything
nkeynes@88
   115
	 * correctly
nkeynes@88
   116
	 */
nkeynes@180
   117
	if( mem_load_block( bootstrap_file, BOOTSTRAP_LOAD_ADDR, BOOTSTRAP_SIZE ) != 0 ) {
nkeynes@180
   118
	    /* Try it without the bootstrap */
nkeynes@180
   119
	    sh4_set_pc( pc );
nkeynes@180
   120
	} else {
nkeynes@180
   121
	    sh4_set_pc( BOOTSTRAP_LOAD_ADDR + 0x300 );
nkeynes@180
   122
	}
nkeynes@88
   123
    } else {
nkeynes@110
   124
	sh4_set_pc( pc );
nkeynes@88
   125
    }
nkeynes@93
   126
    bios_install();
nkeynes@110
   127
    dcload_install();
nkeynes@27
   128
    gtk_gui_update();
nkeynes@110
   129
}    
nkeynes@110
   130
nkeynes@110
   131
nkeynes@110
   132
int file_load_binary( const gchar *filename )
nkeynes@110
   133
{
nkeynes@110
   134
    /* Load the binary itself */
nkeynes@110
   135
    mem_load_block( filename, BINARY_LOAD_ADDR, -1 );
nkeynes@110
   136
    file_load_postload( BINARY_LOAD_ADDR );
nkeynes@19
   137
}
nkeynes@105
   138
nkeynes@105
   139
int file_load_elf_fd( int fd ) 
nkeynes@105
   140
{
nkeynes@105
   141
    Elf32_Ehdr head;
nkeynes@105
   142
    Elf32_Phdr phdr;
nkeynes@105
   143
    int i;
nkeynes@105
   144
nkeynes@105
   145
    if( read( fd, &head, sizeof(head) ) != sizeof(head) )
nkeynes@105
   146
	return -1;
nkeynes@105
   147
    if( head.e_ident[EI_CLASS] != ELFCLASS32 ||
nkeynes@105
   148
	head.e_ident[EI_DATA] != ELFDATA2LSB ||
nkeynes@105
   149
	head.e_ident[EI_VERSION] != 1 ||
nkeynes@105
   150
	head.e_type != ET_EXEC ||
nkeynes@105
   151
	head.e_machine != EM_SH ||
nkeynes@105
   152
	head.e_version != 1 ) {
nkeynes@105
   153
	ERROR( "File is not an SH4 ELF executable file" );
nkeynes@105
   154
	return -1;
nkeynes@105
   155
    }
nkeynes@105
   156
nkeynes@105
   157
    /* Program headers */
nkeynes@105
   158
    for( i=0; i<head.e_phnum; i++ ) {
nkeynes@105
   159
	lseek( fd, head.e_phoff + i*head.e_phentsize, SEEK_SET );
nkeynes@105
   160
	read( fd, &phdr, sizeof(phdr) );
nkeynes@105
   161
	if( phdr.p_type == PT_LOAD ) {
nkeynes@105
   162
	    lseek( fd, phdr.p_offset, SEEK_SET );
nkeynes@105
   163
	    char *target = mem_get_region( phdr.p_vaddr );
nkeynes@105
   164
	    read( fd, target, phdr.p_filesz );
nkeynes@105
   165
	    if( phdr.p_memsz > phdr.p_filesz ) {
nkeynes@105
   166
		memset( target + phdr.p_filesz, 0, phdr.p_memsz - phdr.p_filesz );
nkeynes@105
   167
	    }
nkeynes@105
   168
	    INFO( "Loaded %d bytes to %08X", phdr.p_filesz, phdr.p_vaddr );
nkeynes@105
   169
	}
nkeynes@105
   170
    }
nkeynes@110
   171
    
nkeynes@180
   172
    return file_load_postload( head.e_entry );
nkeynes@105
   173
}
.