mirror of
https://github.com/xcat2/xNBA.git
synced 2024-12-15 07:41:45 +00:00
145 lines
3.8 KiB
C
145 lines
3.8 KiB
C
/* a.out */
|
|
struct exec {
|
|
unsigned long a_midmag; /* flags<<26 | mid<<16 | magic */
|
|
unsigned long a_text; /* text segment size */
|
|
unsigned long a_data; /* initialized data size */
|
|
unsigned long a_bss; /* uninitialized data size */
|
|
unsigned long a_syms; /* symbol table size */
|
|
unsigned long a_entry; /* entry point */
|
|
unsigned long a_trsize; /* text relocation size */
|
|
unsigned long a_drsize; /* data relocation size */
|
|
};
|
|
|
|
struct aout_state {
|
|
struct exec head;
|
|
unsigned long curaddr;
|
|
int segment; /* current segment number, -1 for none */
|
|
unsigned long loc; /* start offset of current block */
|
|
unsigned long skip; /* padding to be skipped to current segment */
|
|
unsigned long toread; /* remaining data to be read in the segment */
|
|
};
|
|
|
|
static struct aout_state astate;
|
|
|
|
static sector_t aout_download(unsigned char *data, unsigned int len, int eof);
|
|
static inline os_download_t aout_probe(unsigned char *data, unsigned int len)
|
|
{
|
|
unsigned long start, mid, end, istart, iend;
|
|
if (len < sizeof(astate.head)) {
|
|
return 0;
|
|
}
|
|
memcpy(&astate.head, data, sizeof(astate.head));
|
|
if ((astate.head.a_midmag & 0xffff) != 0x010BL) {
|
|
return 0;
|
|
}
|
|
|
|
printf("(a.out");
|
|
aout_freebsd_probe();
|
|
printf(")... ");
|
|
/* Check the aout image */
|
|
start = astate.head.a_entry;
|
|
mid = (((start + astate.head.a_text) + 4095) & ~4095) + astate.head.a_data;
|
|
end = ((mid + 4095) & ~4095) + astate.head.a_bss;
|
|
istart = 4096;
|
|
iend = istart + (mid - start);
|
|
if (!prep_segment(start, mid, end, istart, iend))
|
|
return dead_download;
|
|
astate.segment = -1;
|
|
astate.loc = 0;
|
|
astate.skip = 0;
|
|
astate.toread = 0;
|
|
return aout_download;
|
|
}
|
|
|
|
static sector_t aout_download(unsigned char *data, unsigned int len, int eof)
|
|
{
|
|
unsigned int offset; /* working offset in the current data block */
|
|
|
|
offset = 0;
|
|
|
|
#ifdef AOUT_LYNX_KDI
|
|
astate.segment++;
|
|
if (astate.segment == 0) {
|
|
astate.curaddr = 0x100000;
|
|
astate.head.a_entry = astate.curaddr + 0x20;
|
|
}
|
|
memcpy(phys_to_virt(astate.curaddr), data, len);
|
|
astate.curaddr += len;
|
|
return 0;
|
|
#endif
|
|
|
|
do {
|
|
if (astate.segment != -1) {
|
|
if (astate.skip) {
|
|
if (astate.skip >= len - offset) {
|
|
astate.skip -= len - offset;
|
|
break;
|
|
}
|
|
offset += astate.skip;
|
|
astate.skip = 0;
|
|
}
|
|
|
|
if (astate.toread) {
|
|
if (astate.toread >= len - offset) {
|
|
memcpy(phys_to_virt(astate.curaddr), data+offset,
|
|
len - offset);
|
|
astate.curaddr += len - offset;
|
|
astate.toread -= len - offset;
|
|
break;
|
|
}
|
|
memcpy(phys_to_virt(astate.curaddr), data+offset, astate.toread);
|
|
offset += astate.toread;
|
|
astate.toread = 0;
|
|
}
|
|
}
|
|
|
|
/* Data left, but current segment finished - look for the next
|
|
* segment. This is quite simple for a.out files. */
|
|
astate.segment++;
|
|
switch (astate.segment) {
|
|
case 0:
|
|
/* read text */
|
|
astate.curaddr = astate.head.a_entry;
|
|
astate.skip = 4096;
|
|
astate.toread = astate.head.a_text;
|
|
break;
|
|
case 1:
|
|
/* read data */
|
|
/* skip and curaddr may be wrong, but I couldn't find
|
|
* examples where this failed. There is no reasonable
|
|
* documentation for a.out available. */
|
|
astate.skip = ((astate.curaddr + 4095) & ~4095) - astate.curaddr;
|
|
astate.curaddr = (astate.curaddr + 4095) & ~4095;
|
|
astate.toread = astate.head.a_data;
|
|
break;
|
|
case 2:
|
|
/* initialize bss and start kernel */
|
|
astate.curaddr = (astate.curaddr + 4095) & ~4095;
|
|
astate.skip = 0;
|
|
astate.toread = 0;
|
|
memset(phys_to_virt(astate.curaddr), '\0', astate.head.a_bss);
|
|
goto aout_startkernel;
|
|
default:
|
|
break;
|
|
}
|
|
} while (offset < len);
|
|
|
|
astate.loc += len;
|
|
|
|
if (eof) {
|
|
unsigned long entry;
|
|
|
|
aout_startkernel:
|
|
entry = astate.head.a_entry;
|
|
done(1);
|
|
|
|
aout_freebsd_boot();
|
|
#ifdef AOUT_LYNX_KDI
|
|
xstart32(entry);
|
|
#endif
|
|
printf("unexpected a.out variant\n");
|
|
longjmp(restart_etherboot, -2);
|
|
}
|
|
return 0;
|
|
}
|