pcsx2/fps2bios/kernel/iopload/loadcore/loadcore.c

1045 lines
28 KiB
C

#include <tamtypes.h>
#include "ksysmem.h"
#include "kloadcore.h"
#include "iopdebug.h"
#include "iopelf.h"
#include "romdir.h"
#include "irx.h" // ps2sdk file for IMPORT_MAGIC
#define BOOTMODE_START *((volatile u32**)0x3F0)
#define BOOTMODE_END *((volatile u32**)0x3F4)
void _start(BOOT_PARAMS *init); // has to be declared first!
struct tag_LC_internals {
struct export* let_next, *let_prev;
struct export* mda_next, *mda_prev;//.prev==free
imageInfo *image_info; // 0x800?0x830?
int module_count;
int module_index;
} lc_internals;
u32 free;
u32 sysmem_00;
u32 modules_count;
u32 module_index;
u32 *place; // addr of 8 * 31 = 8 * linesInIopbtconf //place[2][31]
u32 bootmodes[17]; // was 16?
u32 bootmodes_size;
int debug=0;
u32 bm_end;
#define _dprintf(fmt, args...) \
if (debug > 0) __printf("loadcore:%d: " fmt, __LINE__, ## args)
void retonly();
struct tag_LC_internals* GetLibraryEntryTable();
void FlushIcache();
void FlushDcache();
int RegisterLibraryEntries(struct export *es);
int ReleaseLibraryEntries(struct export *e);
int _LinkImports(u32 *addr, int size);
int _UnlinkImports(void *addr, int size);
int RegisterNonAutoLinkEntries(struct export *e);
int QueryLibraryEntryTable(struct export *e);
u32 *QueryBootMode(int id);
void RegisterBootMode(struct bootmode *b);
int SetNonAutoLinkFlag(struct export *e);
int UnsetNonAutoLinkFlag(struct export *e);
void _LinkModule(imageInfo *ii);
void _UnlinkModule(imageInfo *ii);
int _RegisterBootupCBFunc(int (*function)(int *, int), int priority, int *result);
void _SetCacheCtrl(u32 val);
int _ReadModuleHeader(void *image, fileInfo *result);
int _LoadModule(void *image, fileInfo *fi);
u32 _FindImageInfo(void *addr);
struct export loadcore_stub __attribute__((section(".text"))) ={
EXPORT_MAGIC,
0,
VER(1, 1), // 1.1 => 0x101
0,
"loadcore",
(func)_start, // entrypoint
(func)retonly,
(func)retonly,
(func)GetLibraryEntryTable,
(func)FlushIcache,
(func)FlushDcache,
(func)RegisterLibraryEntries,
(func)ReleaseLibraryEntries,
(func)_LinkImports,
(func)_UnlinkImports,
(func)RegisterNonAutoLinkEntries,
(func)QueryLibraryEntryTable,
(func)QueryBootMode,
(func)RegisterBootMode,
(func)SetNonAutoLinkFlag,
(func)UnsetNonAutoLinkFlag,
(func)_LinkModule,
(func)_UnlinkModule,
(func)retonly,
(func)retonly,
(func)_RegisterBootupCBFunc,
(func)_SetCacheCtrl,
(func)_ReadModuleHeader,
(func)_LoadModule,
(func)_FindImageInfo,
0
};
///////////////////////////////////////////////////////////////////////
void retonly(){}
///////////////////////////////////////////////////////////////////////
void RegisterBootMode(struct bootmode *b) {
int i;
_dprintf("%s\n", __FUNCTION__);
if (((b->len + 1) * 4) < (16-bootmodes_size)) {
u32 *p = &bootmodes[bootmodes_size];
for (i=0; i<b->len + 1; i++) p[i]=((u32*)b)[i];
p[i]=0;
bootmodes_size+= b->len + 1;
}
}
///////////////////////////////////////////////////////////////////////
u32 *QueryBootMode(int id) {
u32 *b;
for (b = (u32*)&bootmodes[0]; *b; b += ((struct bootmode*)b)->len + 1)
if (id == ((struct bootmode*)b)->id)
return b;
return NULL;
}
///////////////////////////////////////////////////////////////////////
int match_name(struct export *src, struct export *dst){
return (*(int*)(src->name+0) == *(int*)(dst->name+0)) &&
(*(int*)(src->name+4) == *(int*)(dst->name+4));
}
///////////////////////////////////////////////////////////////////////
int match_version_major(struct export *src, struct export *dst){
return ((src->version>>8) - (dst->version>>8));
}
///////////////////////////////////////////////////////////////////////
int match_version_minor(struct export *src, struct export *dst){
return ((unsigned char)src->version - (unsigned char)dst->version);
}
///////////////////////////////////////////////////////////////////////
int fix_imports(struct import *imp, struct export *exp){
func *ef;
struct func_stub *fs;
int count=0, ordinal;
for (ef=exp->func; *ef; ef++){
count++; //count number of exported functions
}
_dprintf("%s (%d functions)\n", __FUNCTION__, count);
for (fs=imp->func; fs->jr_ra; fs++) {
if ((fs->addiu0 >> 26) != INS_ADDIU) break;
ordinal = fs->addiu0 & 0xFFFF;
if (ordinal < count) {
// _dprintf("%s linking ordinal %d to %x\n", __FUNCTION__, ordinal, exp->func[ordinal]);
fs->jr_ra=(((u32)exp->func[ordinal]>>2) & 0x3FFFFFF) | INS_J;
} else {
fs->jr_ra=INS_JR_RA;
}
}
imp->flags |=FLAG_IMPORT_QUEUED;
return 0;
}
///////////////////////////////////////////////////////////////////////
// Check the structure of the import table.
// Return 0 if a bad or empty import table is detected.
// Return a non-zero value if a valid import table is detected.
//
int check_import_table(struct import* imp){
struct func_stub *f;
if (imp->magic != IMPORT_MAGIC)
return 0;
for (f=imp->func; f->jr_ra; f++){
if (f->addiu0 >> 26 != INS_ADDIU)
return 0;
if ((f->jr_ra!=INS_JR_RA) && (f->jr_ra>26!=INS_JR))
return 0;
}
if (f->addiu0)
return 0;
return (imp->func < f);
}
///////////////////////////////////////////////////////////////////////[OK]
// Return 0 if successful
int link_client(struct import *imp){
struct export *e;
// _dprintf("%s\n", __FUNCTION__);
for (e=lc_internals.let_next; e; e=(struct export*)e->magic_link) {
if (debug > 0){
// Zero terminate the name before printing it
char ename[9], iname[9];
*(int*)ename = *(int*)e->name; *(int*)(ename+4) = *(int*)(e->name+4); ename[8] = 0;
*(int*)iname = *(int*)imp->name; *(int*)(iname+4) = *(int*)(imp->name+4);iname[8] = 0;
//__printf("loadcore: %s: %s, %s\n", __FUNCTION__, ename, iname);
}
if (!(e->flags & FLAG_NO_AUTO_LINK)){
if ( match_name(e, (struct export*)imp)){
if (match_version_major(e, (struct export*)imp)==0) {
fix_imports(imp, e);
imp->next=(struct import*)e->next;
e->next=(struct export*)imp;
FlushIcache();
return 0;
} else {
// _dprintf("%s: version does not match\n", __FUNCTION__);
}
} else {
// _dprintf("%s: name does not match\n", __FUNCTION__);
}
} else {
// _dprintf("%s: e->flags bit 0 is 0\n", __FUNCTION__);
}
}
_dprintf("%s: FAILED to find a match\n", __FUNCTION__);
return -1;
}
///////////////////////////////////////////////////////////////////////[OK]
int _LinkImports(u32 *addr, int size)
{
struct import *p;
int i;
_dprintf("%s: %x, %d\n", __FUNCTION__, addr, size);
for (i=0; i<size/4; i++, addr++) {
p = (struct import *)addr;
if ((p->magic == IMPORT_MAGIC) &&
check_import_table(p) &&
((p->flags & 7) == 0) &&
link_client(p)) {
_UnlinkImports(p, size);
return -1;
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////[OK]
int unlink_client(struct import *i1, struct import *i2){
struct import *i, *tmp;
if (i1->next == i2){
i1->next=i2->next;
return 0;
}
for (i = i1->next; i->next;) {
tmp=i->next;
if (tmp==i2) {
i->next=tmp->next;
tmp->next=NULL;
return 0;
}
i=tmp;
}
return -1;
}
///////////////////////////////////////////////////////////////////////[OK]
void restore_imports(struct import* imp){
struct func_stub *f;
for (f=imp->func; (f->jr_ra) && ((f->addiu0 >> 26) == INS_ADDIU); f++)
f->jr_ra=INS_JR_RA;
}
///////////////////////////////////////////////////////////////////////[OK]
int _UnlinkImports(void *addr, int size)
{
struct export *e;
struct export *i;
struct export *tmp;
void *limit = addr + (size & ~0x3);
for (e = (struct export*)lc_internals.let_next; e; e=(struct export*)e->magic_link){
for (i = e->next; i; i=i->next) {
if (((u32)i >= (u32)addr) && ((u32)i < (u32)limit)) {
if (unlink_client((struct import*)e, (struct import*)i))
return -1;
i->flags &= ~0x7;
restore_imports((struct import*)i);
}
}
if (((u32)e >= (u32)addr) && ((u32)e < (u32)limit))
ReleaseLibraryEntries(e);
}
/*
for (i=let.mda; i->next; )
if ((i->next >= addr) && (i->next < limit)){
i->next->flags &= ~0x7;
restore_imports(i->next);
tmp = i->next->next;
i->next->next=NULL;
i->next=tmp;
}else
i=i->next;
*/
return 0;
}
///////////////////////////////////////////////////////////////////////
int SetNonAutoLinkFlag(struct export *e)
{
return (e->flags |= FLAG_NO_AUTO_LINK);
}
///////////////////////////////////////////////////////////////////////
int UnsetNonAutoLinkFlag(struct export *e)
{
return (e->flags &= ~FLAG_NO_AUTO_LINK);
}
///////////////////////////////////////////////////////////////////////
int _RegisterBootupCBFunc(int (*function)(int *, int), int priority, int *result)
{
int x;
register int r;
if (place==NULL){
x=1;
r=function(&x, 0);
if (result) *result=r;
return 0;
}
__asm__("move %0, $gp\n" : "=r"(x) : );
place[0]=(u32)function + (priority & 3);
place[1]=x;
place[2]=0;
place+=2;
return 1;
}
///////////////////////////////////////////////////////////////////////
void _LinkModule(imageInfo *ii)
{
imageInfo* p;
for (p=lc_internals.image_info; p->next && (p->next < (u32)ii); p=(imageInfo*)p->next);
ii->next=p->next;
p->next=(u32)ii;
ii->modid=module_index++;
modules_count++;
}
///////////////////////////////////////////////////////////////////////
void _UnlinkModule(imageInfo *ii)
{
imageInfo *p;
if (ii)
for (p=lc_internals.image_info; p->next; p=(imageInfo*)p->next)
if (p->next == (u32)ii){
p->next=((imageInfo*)p->next)->next;
modules_count--;
return;
}
}
u32 _FindImageInfo(void *addr)
{
register imageInfo *ii;
for (ii=lc_internals.image_info; ii; ii=(imageInfo*)ii->next)
if(((u32)addr>=ii->p1_vaddr) &&
((u32)addr <ii->p1_vaddr + ii->text_size + ii->data_size + ii->bss_size))
return (u32)ii;
return 0;
}
///////////////////////////////////////////////////////////////////////
int RegisterLibraryEntries(struct export *es){
struct export *p;
struct export *plast;
struct export *pnext;
struct export *tmp;
struct export *snext;
if ((es == NULL) || (es->magic_link != EXPORT_MAGIC))
return -1;
if (debug > 0){
// Zero terminate the name before printing it
char ename[9];
*(int*)ename = *(int*)es->name;
*(int*)(ename+4) = *(int*)(es->name+4);
ename[8] = 0;
__printf("loadcore: %s (%x): %s, %x\n", __FUNCTION__, es, es->name, es->version);
}
plast=NULL;
for (p=(struct export*)lc_internals.let_next; p; p=(struct export*)p->magic_link) {
if (match_name(es, p) == 0 ||
match_version_major(es, p) == 0) continue;
if (match_version_minor(es, p) == 0)
return -1;
_dprintf("%s: found match\n", __FUNCTION__);
pnext = p->next;
p->next = NULL;
for (tmp = pnext; tmp; ) {
if (tmp->flags & FLAG_NO_AUTO_LINK) {
pnext->magic_link = (u32)tmp;
pnext = tmp->next;
tmp->next = NULL;
} else {
tmp->next=plast;
plast=tmp;
}
tmp=tmp->next;
}
}
if( lc_internals.mda_next ) {
for (tmp = lc_internals.mda_next; tmp->next; tmp=tmp->next) { //free
if ((match_name(es, tmp->next)) &&
(match_version_major(es, tmp->next)==0)){
_dprintf("%s: freeing module\n", __FUNCTION__);
snext=tmp->next->next;
tmp->next->next=plast;
plast=tmp->next;
tmp->next=snext;
} else tmp=tmp->next;
}
}
es->next=0;
while (plast) {
snext=plast->next;
fix_imports((struct import*)plast, es);
plast->next=es->next;
es->next=plast;
plast=snext;
}
es->flags &= ~FLAG_NO_AUTO_LINK;
es->magic_link=(u32)lc_internals.let_next;
lc_internals.let_next=es;
FlushIcache();
return 0;
}
///////////////////////////////////////////////////////////////////////
int ReleaseLibraryEntries(struct export *e)
{
register struct export *n, *p, *next, *prev;
p = lc_internals.let_next;
while ((p) && (p!=e)){
prev=p;
p=(struct export*)prev->magic_link;
}
if (p != e) // if (0 != e)
return -1; //japanese BUG for e==p==0
n =e->next;
e ->next =0;
prev->magic_link=e->magic_link;
e ->magic_link=0x41C00000;
while(n) {
next = n->next;
if (link_client((struct import*)n)){
restore_imports((struct import*)n);
n->flags=(n->flags & ~2) | 4;
n->next = lc_internals.mda_prev;
lc_internals.mda_prev=n;
}
n=next;
}
return 0;
}
///////////////////////////////////////////////////////////////////////
int RegisterNonAutoLinkEntries(struct export *e)
{
if ((e == NULL) || (e->magic_link != EXPORT_MAGIC)){
return -1;
}
e->flags |= FLAG_NO_AUTO_LINK;
e->magic_link = (u32)lc_internals.let_next; // --add as first
lc_internals.let_next = e; // /
FlushIcache();
return 0;
}
///////////////////////////////////////////////////////////////////////
int QueryLibraryEntryTable(struct export *e)
{
struct export *p = lc_internals.let_next;
while (p){
if ((match_name(p, e)) && (match_version_major(p, e)==0)){
return (int)p->func;
}
p=(struct export*)p->magic_link;
}
return 0;
}
///////////////////////////////////////////////////////////////////////
struct tag_LC_internals* GetLibraryEntryTable(){
return &lc_internals;
}
///////////////////////////////////////////////////////////////////////
void _FlushIcache() {
u32 status;
u32 s1450;
u32 s1578;
u32 icache;
u32 *p;
__asm__ ("mfc0 %0, $12\n" : "=r"(status) : );
__asm__ ("mtc0 %0, $12\n" :: "r"(0));
s1450 = *(int*)0xBF801450;
*(int*)0xBF801450&= ~1;
*(int*)0xBF801450;
s1578 = *(int*)0xBF801578;
*(int*)0xBF801578 = 0;
*(int*)0xBF801578;
icache = *(int*)0xFFFE0130;
*(int*)0xFFFE0130 = 0xC04;
*(int*)0xFFFE0130;
__asm__ ("mtc0 %0, $12\n" :: "r"(0x10000));
for (p=0; p<(u32*)0x400; p+=4) // 4KB instruction cache
*p=0;
__asm__ ("mtc0 %0, $12\n" :: "r"(0));
*(int*)0xFFFE0130 = icache;
*(int*)0xFFFE0130;
*(int*)0xBF801578 = s1578;
*(int*)0xBF801578;
*(int*)0xBF801450 = s1450;
*(int*)0xBF801450;
__asm__ ("mtc0 %0, $12\n" : : "r"(status) );
}
void FlushIcache() {
__asm__ (
"la $26, %0\n"
"lui $27, 0xA000\n"
"or $26, $27\n"
"jr $26\n"
"nop\n"
: : "i"(_FlushIcache)
);
}
///////////////////////////////////////////////////////////////////////
void _FlushDcache() {
u32 status;
u32 s1450;
u32 s1578;
u32 icache;
u32 *p;
__asm__ ("mfc0 %0, $12\n" : "=r"(status) : );
__asm__ ("mtc0 %0, $12\n" :: "r"(0));
s1450 = *(int*)0xBF801450;
*(int*)0xBF801450&= ~1;
*(int*)0xBF801450;
s1578 = *(int*)0xBF801578;
*(int*)0xBF801578 = 0;
*(int*)0xBF801578;
icache = *(int*)0xFFFE0130;
*(int*)0xFFFE0130 = 0xC4;
*(int*)0xFFFE0130;
__asm__ ("mtc0 %0, $12\n" :: "r"(0x10000));
for (p=0; p<(u32*)0x100; p+=4) // 1KB data cache
*p=0;
__asm__ ("mtc0 %0, $12\n" :: "r"(0));
*(int*)0xFFFE0130 = icache;
*(int*)0xFFFE0130;
*(int*)0xBF801578 = s1578;
*(int*)0xBF801578;
*(int*)0xBF801450 = s1450;
*(int*)0xBF801450;
__asm__ ("mtc0 %0, $12\n" : : "r"(status) );
}
void FlushDcache(){
__asm__ (
"la $26, %0\n"
"lui $27, 0xA000\n"
"or $26, $27\n"
"jr $26\n"
"nop\n"
: : "i"(_FlushDcache)
);
}
///////////////////////////////////////////////////////////////////////
void _SetIcache(u32 val) {
u32 status;
__asm__ ("mfc0 %0, $12\n" : "=r"(status) : );
__asm__ ("mtc0 %0, $12\n" :: "r"(0));
*(int*)0xFFFE0130 = val;
*(int*)0xFFFE0130;
__asm__ ("mtc0 %0, $12\n" : : "r"(status) );
}
void _SetCacheCtrl(u32 val)
{
__asm__ (
"la $26, %0\n"
"lui $27, 0xA000\n"
"or $26, $27\n"
"jr $26\n"
"nop\n"
: : "i"(_SetIcache)
);
}
///////////////////////////////////////////////////////////////////////
int _ReadModuleHeader(void *image, fileInfo *result)
{
COFF_HEADER *coffhdr = image;
COFF_scnhdr *section = (COFF_scnhdr*)((char*)image+sizeof(COFF_HEADER));//0x4C
if ((coffhdr->f_magic==0x162) && //COFF loading
(coffhdr->opthdr.magic == 0x107) &&
(coffhdr->f_nscns < 32) &&
((coffhdr->f_opthdr & 0x2FFFF) == 0x20038) &&
(section->s_paddr == coffhdr->opthdr.text_start)){
if (coffhdr->opthdr.vstamp == 0x7001)
return -1;
result->type =1;
result->entry =coffhdr->opthdr.entry;
result->gp_value =coffhdr->opthdr.gp_value;
result->p1_vaddr =coffhdr->opthdr.text_start;
result->text_size =coffhdr->opthdr.tsize;
result->data_size =coffhdr->opthdr.dsize;
result->bss_size =coffhdr->opthdr.bsize;
result->p1_memsz =coffhdr->opthdr.bss_start+coffhdr->opthdr.bsize-coffhdr->opthdr.text_start;
result->moduleinfo =(moduleInfo*)coffhdr->opthdr.moduleinfo;
return result->type;
}else{
ELF_HEADER* eh = (ELF_HEADER*)image;
ELF_PHR* ph= (ELF_PHR*)((char*)eh +eh->e_phoff);
//if ((eh->e_ident[EI_CLASS] != ELFCLASS32) ||
//(eh->e_ident[EI_DATA]) != ELFDATA2LSB)) return -1;//break
if( *(u16*)(eh->e_ident+4) != 0x101 )
return -1;
if (eh->e_machine != EM_MIPS)
return -1;//break
if (eh->e_phentsize != sizeof(ELF_PHR))
return -1;//break
if (eh->e_phnum != 2)
return -1;//break
if (ph[0].p_type != PT_SCE_IOPMOD)
return -1;//break
if (eh->e_type != ET_SCE_IOPRELEXEC){
if (eh->e_type != eh->e_phnum )//ET_EXEC)
return -1;//only
result->type=3;
}else
result->type=4;
ELF_IOPMOD* im= (ELF_IOPMOD*)((char*)image + ph[0].p_offset);
result->entry =im->entry;
result->gp_value=im->gp_value;
result->p1_vaddr=ph[1].p_vaddr;
result->text_size=im->text_size;
result->data_size=im->data_size;
result->bss_size=im->bss_size;
result->p1_memsz=ph[1].p_memsz;
result->moduleinfo=( moduleInfo*)im->moduleinfo;
return result->type;
}
return result->type=-1;
}
#define MODULE_TYPE_COFF 1
#define MODULE_TYPE_2 2
#define MODULE_TYPE_EXEC 3
#define MODULE_TYPE_IOPRELEXEC 4
///////////////////////////////////////////////////////////////////////
void setImageInfo(fileInfo *fi, imageInfo *ii)
{
ii->next =0;
ii->name =NULL;
ii->version =0;
ii->flags =0;
ii->modid =0;
if ((int)fi->moduleinfo != -1){
ii->name =fi->moduleinfo->name;
ii->version =fi->moduleinfo->version;
}
ii->entry =fi->entry;
ii->gp_value =fi->gp_value;
ii->p1_vaddr =fi->p1_vaddr;
ii->text_size =fi->text_size;
ii->data_size =fi->data_size;
ii->bss_size =fi->bss_size;
}
///////////////////////////////////////////////////////////////////////
void load_type_1(COFF_HEADER *image){
SHDR* s0=(SHDR*)( (char*)image + *(int*)((char*)image+0x60) );
lc_memcpy(s0, image->opthdr.text_start, image->opthdr.tsize);
lc_memcpy((char*)s0+image->opthdr.tsize, image->opthdr.data_start, image->opthdr.dsize);
if (image->opthdr.bss_start && image->opthdr.bsize)
lc_zeromem((void*)image->opthdr.bss_start, image->opthdr.bsize/4);
}
///////////////////////////////////////////////////////////////////////
void load_type_3(void *image){
ELF_PHR *ph=(ELF_PHR*)((char*)image+((ELF_HEADER*)image)->e_phoff);
lc_memcpy(image+ph[1].p_offset, ph[1].p_vaddr, ph[1].p_filesz);
if (ph[1].p_filesz < ph[1].p_memsz)
lc_zeromem(ph[1].p_vaddr+ph[1].p_filesz,
(ph[1].p_memsz-ph[1].p_filesz)/4);
}
///////////////////////////////////////////////////////////////////////
#define R_MIPS_32 2
#define R_MIPS_26 4
#define R_MIPS_HI16 5
#define R_MIPS_LO16 6
void load_type_4(ELF_HEADER *image, fileInfo *fi)
{
ELF_PHR *ph=(ELF_PHR*)((char*)image+image->e_phoff);
ELF_SHR* sh = (ELF_SHR*)((char*)image+image->e_shoff);
ELF_REL* rel;
int i,j,scount;
u32* b, *b2, tmp;
//ph[0] - .iopmod, skip
fi->entry += fi->p1_vaddr;
fi->gp_value += fi->p1_vaddr;
if ((int)fi->moduleinfo != -1)
fi->moduleinfo = (moduleInfo*)((int)fi->moduleinfo + fi->p1_vaddr);
lc_memcpy((char*)image+ph[1].p_offset, fi->p1_vaddr, ph[1].p_filesz);
if (ph[1].p_filesz < ph[1].p_memsz) {
lc_zeromem(ph[1].p_vaddr+ph[1].p_filesz+fi->p1_vaddr, (ph[1].p_memsz-ph[1].p_filesz));
}
for (i=1; i<image->e_shnum; i++) {
if (sh[i].sh_type==SHT_REL) {
ELF_REL* rel =(ELF_REL*)(sh[i].sh_offset + (char*)image);
scount=sh[i].sh_size / sh[i].sh_entsize;
for (j=0; j<scount; j++) {
b=(u32*)(fi->p1_vaddr + rel[j].r_offset);
switch((u8)rel[j].r_info){
case R_MIPS_LO16:
*b=(*b & 0xFFFF0000) | (((*b & 0x0000FFFF) + fi->p1_vaddr) & 0xFFFF);
break;
case R_MIPS_32:
*b+=fi->p1_vaddr;
break;
case R_MIPS_26:
*b = (*b & 0xfc000000) | (((*b & 0x03ffffff) + (fi->p1_vaddr >> 2)) & 0x03ffffff);
break;
case R_MIPS_HI16:
b2 =(u32*)(rel[j+1].r_offset + fi->p1_vaddr);
++j;
tmp = (*b << 16) + (int)(*(s16*)b2) + fi->p1_vaddr;
*b = (*b&0xffff0000) | ((((tmp>>15)+1)>>1)&0xffff);
*b2 = (*b2&0xffff0000) | (tmp&0xffff);
break;
}
}
}
}
}
int _LoadModule(void *image, fileInfo *fi)
{
u32* ptr;
int i;
switch (fi->type){
case MODULE_TYPE_COFF: load_type_1(image); break;
case MODULE_TYPE_EXEC: load_type_3(image); break;
case MODULE_TYPE_IOPRELEXEC: load_type_4(image, fi); break;
default: return -1;
}
setImageInfo(fi, (imageInfo*)(fi->p1_vaddr-0x30));
return 0;
}
///////////////////////////////////////////////////////////////////////[OK]
int lc_memcpy(void *src,void *dest,int len){
char* _src = (char*)src;
char* _dst = (char*)dest;
for (len=len; len>0; len--)
*_dst++=*_src++;
}
///////////////////////////////////////////////////////////////////////[OK]
int lc_zeromem(void *addr,int len){
for (; len>0; len--) *(char*)addr++=0;
}
int lc_strlen(char *s)
{
int len;
if (s==NULL) return 0;
for (len=0; *s++; len++);
return len;
}
int recursive_set_a2(int* start, int* end, int val)
{
*start++ = val;
if( start < end )
return recursive_set_a2(start, end, val);
return 0;
}
void* lc_memcpy_overlapping(char *dst,char *src,int len){
if (dst==NULL) return 0;
if (dst>=src)
while(--len>=0)
*(dst+len)=*(src+len);
else
while (len-->0)
*dst++=*src++;
return dst;
}
//////////////////////////////entrypoint///////////////////////////////
void _start(BOOT_PARAMS *init) {
*(int*)0xFFFE0130 = 0x1e988;
__asm__ (
"addiu $26, $0, 0\n"
"mtc0 $26, $12\n");
//"move $fp, %0\n"
//"move $sp, %0\n"
//: : "r"((init->ramMBSize << 20) - 0x40));
__asm__ (
"j loadcore_start\n"
);
}
extern void* _ftext, *_etext, *_end;
typedef int (*IopEntryFn)(u32,void*,void*,void*);
void loadcore_start(BOOT_PARAMS *pInitParams)
{
fileInfo fi;
void (*entry)();
u32 offset;
u32 status = 0x401;
int bm;
int i;
void** s0; // pointer in module list to current module?
BOOT_PARAMS params;
u32 s1, s2, s3, sp, a2;
_dprintf("%s\n", __FUNCTION__);
// Write 0x401 into the co-processor status register?
// This enables interrupts generally, and disables (masks) them all except hardware interrupt 0?
lc_memcpy(pInitParams,&params,sizeof(BOOT_PARAMS));
BOOTMODE_END = BOOTMODE_START = bootmodes;
//_dprintf("module: %x\n", params.firstModuleAddr);
lc_internals.let_next = (struct export*)params.firstModuleAddr;
lc_internals.let_prev = (struct export*)params.firstModuleAddr;
lc_internals.let_next->next = 0;
lc_internals.module_count = 2; // SYSMEM + LOADCORE
lc_internals.mda_prev = lc_internals.mda_next = NULL;
lc_internals.module_index = 3; // next available index
for (i=0; i<17; i++){
bootmodes[i]=0;
}
bootmodes_size=0;
bm = params.bootInfo | 0x00040000;
RegisterBootMode((struct bootmode*)&bm);
lc_internals.image_info = (imageInfo*)((u32)lc_internals.let_prev - 0x30);
lc_internals.image_info->modid = 1; // SYSMEM is the first module
lc_internals.image_info->next = (u32)&_ftext - 0x30;
((imageInfo*)lc_internals.image_info->next)->modid = 2; // LOADCORE is the second module
// find & fix LOADCORE imports (to SYSMEM)
_LinkImports((u32*)&_ftext, (u32)&_etext - (u32)&_ftext);
RegisterLibraryEntries(&loadcore_stub);
// reserve LOADCORE memory
AllocSysMemory(2, (u32)((u32)&_end - (((u32)&_ftext - 0x30) >> 8 << 8)), (void*)((((u32)&_ftext - 0x30) >> 8 << 8) & 0x1FFFFFFF));
if (params.pos)
params.pos = (u32)AllocSysMemory(2, params.size, (void*)params.pos);
sp=(u32)alloca(0x10);
s0 = (void**)((sp - 0xDF0) & 0x1FFFFF00);//=0x001ff100
recursive_set_a2((int*)s0, (void*)(sp+0x10), 0x11111111);
if ((u32)s0 < QueryMemSize())
AllocSysMemory(2, QueryMemSize() - (u32)s0, s0);
if (params.udnlString){
int v0 = lc_strlen(params.udnlString);
int* v1 = (int*)alloca((v0 + 8 + 8) >> 3 << 3);
lc_memcpy_overlapping((char*)&v1[6], params.udnlString, v0+1);
params.udnlString = (char*)&v1[6];
v1[4] = 0x01050000;
v1[5] = (int)&v1[6];
RegisterBootMode((struct bootmode*)&v1[4]); // BTUPDATER bootmode 5
}
a2 = (params.numConfLines+1) * 4;
s0 = alloca((a2 + 7) >> 3 << 3) + 0x10;
lc_memcpy_overlapping((char*)s0, (char*)params.moduleAddrs, a2); //0x30020
s1 = 0;
params.moduleAddrs = (u32**)s0;
s2 = (u32)alloca(params.numConfLines << 3) + 0x10;
place = (u32*)s2;
*place = 0;
i = -1;
s3 = 1;
_dprintf("loading modules: %d\n", params.numConfLines);
s0 += 2; // skip first two: SYSMEM, LOADCORE
for (; *s0; s0+=1) {
if ((u32)*s0 & 1){
if (((u32)*s0 & 0xF) == s3)
s1 = (u32)*s0>>2;
}else{
i += 1;
i &= 0xF;
_dprintf("load module from %x\n", *s0);
switch(_ReadModuleHeader(*s0, &fi)){
case MODULE_TYPE_COFF:
case MODULE_TYPE_EXEC:
a2 = ((fi.p1_vaddr - 0x30) >> 8 << 8) & 0x1FFFFFFF;
if (NULL == AllocSysMemory(2, fi.p1_memsz + fi.p1_vaddr - a2, (void*)a2))
goto HALT;
break;
case MODULE_TYPE_2:
case MODULE_TYPE_IOPRELEXEC:
if (fi.p1_vaddr = (u32)((s1 == 0) ?
AllocSysMemory(0, fi.p1_memsz+0x30, 0) :
AllocSysMemory(2, fi.p1_memsz+0x30, (void*)s1)) )
fi.p1_vaddr += 0x30;
else
goto HALT;
break;
default:
_dprintf("could not find module at %x\n", *s0);
goto HALT;
}
_LoadModule(*s0, &fi);
_dprintf("loading module %s: at offset %x, memsz=%x, type=%x, entry=%x\n", fi.moduleinfo->name, fi.p1_vaddr, fi.p1_memsz, fi.type, fi.entry);
if (0 == _LinkImports((u32*)fi.p1_vaddr, fi.text_size)) {
FlushIcache();
__asm__("move $gp, %0\n" : : "r"(fi.gp_value));
// call the entry point
s1 = ((IopEntryFn)fi.entry)(0, NULL, s0, NULL);
if ((s1 & 3) == 0){
_LinkModule((imageInfo*)(fi.p1_vaddr - 0x30));
if (s1 & ~3)
_RegisterBootupCBFunc((int (*)(int *, int))(s1 & ~3), BOOTUPCB_NORMAL, 0);
}else{
_UnlinkImports((void*)fi.p1_vaddr, fi.text_size);
FreeSysMemory((void*)((fi.p1_vaddr - 0x30) >> 8 << 8));
}
}else {
FreeSysMemory((void*)((fi.p1_vaddr - 0x30) >> 8 << 8));
}
s1 = 0;
}
}
if (params.pos)
FreeSysMemory((void*)params.pos);
for (i=BOOTUPCB_FIRST; i<BOOTUPCB_PRIORITIES; i++){
if (i == BOOTUPCB_LAST)
place = 0;
for (s0=(void**)s2; *s0; s0+=2)
if (((u32)*s0 & 3) == i){
__asm__("move $gp, %0\n" : : "r"(s0[1]));
((int (*)(int *, int))((u32)*s0 & ~3))(((u32)*s0 & 3) == BOOTUPCB_LAST ? (int*)&s0[2] : (int*)s0, 1);
}
if (i == BOOTUPCB_NORMAL){
while ((u32)s2 < (u32)s0){
s0-=2; // -8 bytes
if (((u32)*s0 & 3) == BOOTUPCB_LAST)
break;
*s0 = 0;
}
}
}
HALT:
*(char*)0x80000000 = 2;
goto HALT;
}