From: <rob...@us...> - 2005-01-09 11:40:56
|
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); } |