Update of /cvsroot/gc-linux/ipl/load
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5953/load
Added Files:
dol.c dolup.c elf.c loadapp.c
Log Message:
Sorted all source files int / into the following directories: io, lowlevel, loadand ipl
Did some cleaning in the source files, but there is still much to be done
--- NEW FILE: dol.c ---
#include <linux/string.h>
#include <console.h>
#include <processor.h>
#include <exception.h>
void load_dol(void *dol, int size)
{
void (*entrypoint)();
if ((*(unsigned long*)dol) > 0x1000)
{
printf("loading binary file..\n");
memcpy((void*)0x80003100, dol, size);
entrypoint = (void(*)())0x80003100;
} else
{
struct dol_s
{
unsigned long sec_pos[18];
unsigned long sec_address[18];
unsigned long sec_size[18];
unsigned long bss_address, bss_size, entry_point;
} *d = (struct dol_s*)dol;
int i;
for (i=0; i<18; ++i)
{
if (!d->sec_size[i])
continue;
printf("relocating %08lx to %08lx (%ld bytes)\n", d->sec_pos[i], d->sec_address[i], d->sec_size[i]);
memcpy((void*)d->sec_address[i], ((unsigned char*)dol)+d->sec_pos[i], d->sec_size[i]);
}
printf("clearing BSS (at %08lx, %lu bytes...)\n", d->bss_address, d->bss_size);
memset((void*)d->bss_address, 0, d->bss_size);
entrypoint = (void(*)())d->entry_point;
}
mtmsr((mfmsr() | 2) & ~0x8000);
printf("jumping to %p\n", entrypoint);
flush_code(0x80000000, 0x1800000);
exception_close();
entrypoint();
printf("returned from entrypoint - should never happen. but happens.\n");
while(1);
}
--- NEW FILE: dolup.c ---
/*
* DOL loader over tcp/ip
* Receives a DOL on port 4000 and executes it
*/
#include "lwip/debug.h"
#include "lwip/stats.h"
#include "lwip/tcp.h"
#include <console.h>
#include <types.h>
#include <processor.h>
#include <elf.h>
// ELF is read into a fixed buffer
//#define FILE_BUFFER ((u8*)0x80800000)
#include <memlayout.h>
#define TYPE_UNKNOWN 0
#define TYPE_DOL 1
#define TYPE_ELF 2
struct dolup_state {
struct dol_s {
u32 sec_pos[18];
u32 sec_address[18];
u32 sec_size[18];
u32 bss_address, bss_size, entry_point;
u32 dummy[7];
} dolhdr;
u32 filepos;
u32 filesize;
int type;
int retries;
};
/*-----------------------------------------------------------------------------------*/
static void
conn_err(void *arg, err_t err)
{
struct dolup_state *hs;
hs = arg;
mem_free(hs);
}
/*-----------------------------------------------------------------------------------*/
static void
close_conn(struct tcp_pcb *pcb, struct dolup_state *hs)
{
void (*entrypoint)();
printf("DOLUP: connection CLOSE\n");
tcp_arg(pcb, NULL);
tcp_sent(pcb, NULL);
tcp_recv(pcb, NULL);
tcp_close(pcb);
entrypoint = NULL;
switch (hs->type) {
case TYPE_DOL:
entrypoint = (void(*)())hs->dolhdr.entry_point;
break;
case TYPE_ELF:
entrypoint = (void(*)(void))load_elf_image((unsigned long)ELF_FILE_BUFFER);
break;
default:
printf("unknown file type\n");
}
mem_free(hs);
if (entrypoint != NULL) {
// clear interrupt mask
*(volatile unsigned long*)0xCC003004 = 0;
exception_close();
printf("starting execution at %p\n", entrypoint);
entrypoint();
}
}
/*-----------------------------------------------------------------------------------*/
static err_t
dolup_poll(void *arg, struct tcp_pcb *pcb)
{
struct dolup_state *hs;
hs = arg;
// printf("Polll\n");
if (hs == NULL) {
printf("Null, close\n");
tcp_abort(pcb);
return ERR_ABRT;
} else {
++hs->retries;
if (hs->retries == 40) {
tcp_abort(pcb);
return ERR_ABRT;
}
// send_data(pcb, hs);
}
return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
#if 0
static err_t
dolup_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
{
return ERR_OK;
}
#endif
/*-----------------------------------------------------------------------------------*/
static err_t
dolup_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
struct dolup_state *hs;
hs = arg;
if (err == ERR_OK && p != NULL) {
// Inform TCP that we have taken the data.
tcp_recved(pcb, p->tot_len);
u8 * data = p->payload;
int len = p->tot_len;
while (len > 0) {
if (hs->filepos < 256) {
// copy data into header
u8 *header = (u8 *)(&hs->dolhdr);
int tmp_len = len;
if (hs->filepos + tmp_len > 256)
tmp_len = 256 - hs->filepos;
memcpy(header+hs->filepos, data, tmp_len);
hs->filepos+=tmp_len;
if (hs->filepos == 256) {
// check for elf
if ( valid_elf_image((u32)header) ) {
hs->type = TYPE_ELF;
hs->filesize = 0; // no decoding
memcpy( ELF_FILE_BUFFER, header, 256);
} else {
int i;
// calculate dol size
hs->type = TYPE_DOL;
hs->filesize = 256;
for (i=0; i<18; i++) {
u32 sec_end = hs->dolhdr.sec_pos[i] + hs->dolhdr.sec_size[i];
if (sec_end > hs->filesize) {
hs->filesize = sec_end;
}
}
}
}
data+=tmp_len;
len-=tmp_len;
} else {
switch (hs->type) {
case TYPE_DOL: {
// write dol into memory
int i, found=0;
for (i=0; i<18 && !found ; i++) {
if ((hs->dolhdr.sec_pos[i] <= hs->filepos) && (hs->dolhdr.sec_pos[i]+hs->dolhdr.sec_size[i] > hs->filepos)) {
u32 tmp_offset = hs->filepos - hs->dolhdr.sec_pos[i];
u32 tmp_len = len;
if ( tmp_offset + tmp_len > hs->dolhdr.sec_size[i] ) {
tmp_len = hs->dolhdr.sec_size[i] - tmp_offset;
}
memcpy((void*)(hs->dolhdr.sec_address[i] + tmp_offset), data, tmp_len);
flush_code((void*)(hs->dolhdr.sec_address[i] + tmp_offset), tmp_len);
data+=tmp_len;
len-=tmp_len;
hs->filepos+=tmp_len;
found=1;
}
}
if (!found) {
// if the filepos was not found in the dol header, advance the file pointer by one byte. there could be some
// alignment between sections, for example for DVD reads
data++;
len--;
hs->filepos++;
}
break;
}
default: {
// copy others into buffer
memcpy(ELF_FILE_BUFFER + hs->filepos, data, len);
hs->filepos += len;
data += len;
len = 0;
break;
}
}
}
}
}
if (p != NULL) {
pbuf_free(p);
}
if (err == ERR_OK) {
if ((hs->filepos >= hs->filesize && hs->filesize > 0) || (hs->type == TYPE_ELF && p == NULL)) {
printf("\n");
close_conn(pcb, hs);
} else {
printf(".");
}
}
return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
static err_t
dolup_accept(void *arg, struct tcp_pcb *pcb, err_t err)
{
struct dolup_state *hs;
tcp_setprio(pcb, TCP_PRIO_MIN);
/* Allocate memory for the structure that holds the state of the connection. */
hs = mem_malloc(sizeof(struct dolup_state));
if (hs == NULL) {
printf("dolup_accept: Out of memory\n");
return ERR_MEM;
}
printf("dolup: accept\n");
hs->filepos = 0;
hs->filesize = 0;
hs->type = TYPE_UNKNOWN;
/* Tell TCP that this is the structure we wish to be passed for our
callbacks. */
tcp_arg(pcb, hs);
/* Tell TCP that we wish to be informed of incoming data by a call
to the dolup_recv() function. */
tcp_recv(pcb, dolup_recv);
tcp_err(pcb, conn_err);
tcp_poll(pcb, dolup_poll, 4);
return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
void
dolup_init(void)
{
struct tcp_pcb *pcb;
pcb = tcp_new();
tcp_bind(pcb, IP_ADDR_ANY, 4000);
pcb = tcp_listen(pcb);
tcp_accept(pcb, dolup_accept);
}
--- NEW FILE: elf.c ---
/*
* Copyright (c) 2001 William L. Pitts
* Modifications (c) 2004 Felix Domke
* All rights reserved.
*
* Redistribution and use in source and binary forms are freely
* permitted provided that the above copyright notice and this
* paragraph and the following disclaimer are duplicated in all
* such forms.
*
* This software is provided "AS IS" and without any express or
* implied warranties, including, without limitation, the implied
* warranties of merchantability and fitness for a particular
* purpose.
*/
#include <linux/types.h>
#include <elf_abi.h>
#include <linux/string.h>
#include <console.h>
#include <cache.h>
#ifndef MAX
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#endif
/* ======================================================================
* Determine if a valid ELF image exists at the given memory location.
* First looks at the ELF header magic field, the makes sure that it is
* executable and makes sure that it is for a PowerPC.
* ====================================================================== */
int valid_elf_image (unsigned long addr)
{
Elf32_Ehdr *ehdr; /* Elf header structure pointer */
/* -------------------------------------------------- */
ehdr = (Elf32_Ehdr *) addr;
if (!IS_ELF (*ehdr)) {
printf ("## No elf image at address 0x%08lx\n", addr);
return 0;
}
if (ehdr->e_type != ET_EXEC) {
printf ("## Not a 32-bit elf image at address 0x%08lx\n",
addr);
return 0;
}
#if 0
if (ehdr->e_machine != EM_PPC) {
printf ("## Not a PowerPC elf image at address 0x%08lx\n",
addr);
return 0;
}
#endif
return 1;
}
/* ======================================================================
* A very simple elf loader, assumes the image is valid, returns the
* entry point address.
* ====================================================================== */
unsigned long load_elf_image (unsigned long addr)
{
Elf32_Ehdr *ehdr;
Elf32_Shdr *shdr;
unsigned char *strtab = 0;
unsigned char *image;
int i;
ehdr = (Elf32_Ehdr *) addr;
/* Find the section header string table for output info */
shdr = (Elf32_Shdr *) (addr + ehdr->e_shoff +
(ehdr->e_shstrndx * sizeof (Elf32_Shdr)));
if (shdr->sh_type == SHT_STRTAB)
strtab = (unsigned char *) (addr + shdr->sh_offset);
/* Load each appropriate section */
for (i = 0; i < ehdr->e_shnum; ++i) {
shdr = (Elf32_Shdr *) (addr + ehdr->e_shoff +
(i * sizeof (Elf32_Shdr)));
if (!(shdr->sh_flags & SHF_ALLOC)
|| shdr->sh_addr == 0 || shdr->sh_size == 0) {
continue;
}
shdr->sh_addr &= 0x3FFFFFFF;
shdr->sh_addr |= 0x80000000;
if (strtab) {
printf ("%sing %s @ 0x%08lx (%ld bytes)\n",
(shdr->sh_type == SHT_NOBITS) ?
"Clear" : "Load",
&strtab[shdr->sh_name],
(unsigned long) shdr->sh_addr,
(long) shdr->sh_size);
}
if (shdr->sh_type == SHT_NOBITS) {
memset ((void *)shdr->sh_addr, 0, shdr->sh_size);
} else {
image = (unsigned char *) addr + shdr->sh_offset;
memcpy ((void *) shdr->sh_addr,
(const void *) image,
shdr->sh_size);
}
flush_code ((void*)shdr->sh_addr, shdr->sh_size);
}
printf("loading elf done!\n");
return (ehdr->e_entry & 0x3FFFFFFF) | 0x80000000;
}
--- NEW FILE: loadapp.c ---
#include <dvd.h>
#include <console.h>
#include <linux/string.h>
#include <pad.h>
#include <processor.h>
#include <cache.h>
#include "lowmem.h"
#include "ipl.h"
typedef int my_dvd_read(void *, int, int);
static char *ccodes[]={"JPN", "USA", "PAL", "???"};
void load_app(my_dvd_read *dvd_read)
{
char *buffer = (char*)0xC0100000;
void (*app_init)(void (*report)(const char *fmt, ...));
int (*app_main)(void **dst, int *size, int *offset);
void *(*app_final)();
void (*entrypoint)();
void (*app_entry)(void(**init)(const char *fmt, ...), int (**main)(), void *(**final)());
/* now we initialize the dvdrom. this will read the disc id. */
printf("init dvd..\n");
if (dvd_init())
{
printf("dvd init failed (%s)!\n", dvd_get_error_message());
return;
}
ipl_set_config(2); /* disable modified bios */
/* we need to disable external IRQs */
exception_close();
dvd_set_streaming();
/* we check if we have a fitting video mode selected, otherwise the */
/* game *will* OSFatal because it can't change PAL <-> NTSC. */
/* we ignore the fact that there are different hardwares out there */
/* and hope the user's tvset is able to cope with that. good luck. */
printf("checking countrycode...");
dvd_read(buffer, 0x20, 0x440);
int ccode = *(int*)(buffer + 0x18);
if (ccode >= 3)
ccode = 3;
printf(" found %s.\n", ccodes[ccode]);
int current_mode = lowmem_current_video_mode & 1; /* 0, 2, 4 are NTSC-styled modes, 1, 3, 5 are PAL-styled modes. */
int required_mode = (ccode == 2) ? 1 : 0; /* pal for PAL, otherwise NTSC */
if (current_mode != required_mode)
{
printf("adjusting video mode to %s\n", required_mode ? "PAL" : "NTSC");
lowmem_current_video_mode = required_mode;
}
video_init((*(unsigned long*)0x800000cc) & 1);
/* load the apploader-header. */
printf("reading apploader!\n");
memset(buffer, 0, 0x20);
printf("dvd_read\n");
dvd_read(buffer, 0x20, 0x2440);
printf("apploader date: %s\n", buffer);
printf("apploader entry point: %08lx\n", *(unsigned long*)(buffer+0x10));
printf("apploader size: %08lx\n", *(unsigned long*)(buffer+0x14));
/* read the apploader */
dvd_read((void*)0x81200000, ((*(unsigned long*)(buffer+0x14)) + 31) &~31, 0x2460);
/* call abbloader entry */
app_entry = *(unsigned long*)(buffer+0x10);
app_entry(&app_init, &app_main, &app_final);
/* intialize it with our debug printf */
app_init(printf);
/* call the apploader until it's done. */
while (1)
{
void *dst=0;
int len=0, offset=0;
printf(".");
int res = app_main(&dst, &len, &offset);
if (!res)
break;
if (dvd_read(dst, len, offset))
printf("DVD READ ERROR: %s\n", dvd_get_error_message());
flush_code(dst, len);
}
entrypoint = app_final();
entrypoint();
while (1);
}
|