1bd389b36SDavid du Colombier #include <u.h> 2bd389b36SDavid du Colombier #include <libc.h> 3bd389b36SDavid du Colombier #include <bio.h> 4bd389b36SDavid du Colombier #include <bootexec.h> 5bd389b36SDavid du Colombier #include <mach.h> 67dd7cddfSDavid du Colombier #include "elf.h" 73e12c5d1SDavid du Colombier 83e12c5d1SDavid du Colombier /* 93e12c5d1SDavid du Colombier * All a.out header types. The dummy entry allows canonical 103e12c5d1SDavid du Colombier * processing of the union as a sequence of longs 113e12c5d1SDavid du Colombier */ 123e12c5d1SDavid du Colombier 133e12c5d1SDavid du Colombier typedef struct { 143e12c5d1SDavid du Colombier union{ 153e12c5d1SDavid du Colombier Exec; /* in a.out.h */ 167dd7cddfSDavid du Colombier Ehdr; /* in elf.h */ 177dd7cddfSDavid du Colombier struct mipsexec; 18219b2ee8SDavid du Colombier struct mips4kexec; 193e12c5d1SDavid du Colombier struct sparcexec; 203e12c5d1SDavid du Colombier struct nextexec; 213e12c5d1SDavid du Colombier } e; 223e12c5d1SDavid du Colombier long dummy; /* padding to ensure extra long */ 233e12c5d1SDavid du Colombier } ExecHdr; 243e12c5d1SDavid du Colombier 257dd7cddfSDavid du Colombier static int nextboot(int, Fhdr*, ExecHdr*); 267dd7cddfSDavid du Colombier static int sparcboot(int, Fhdr*, ExecHdr*); 277dd7cddfSDavid du Colombier static int mipsboot(int, Fhdr*, ExecHdr*); 287dd7cddfSDavid du Colombier static int mips4kboot(int, Fhdr*, ExecHdr*); 297dd7cddfSDavid du Colombier static int common(int, Fhdr*, ExecHdr*); 307dd7cddfSDavid du Colombier static int adotout(int, Fhdr*, ExecHdr*); 317dd7cddfSDavid du Colombier static int elfdotout(int, Fhdr*, ExecHdr*); 327dd7cddfSDavid du Colombier static int armdotout(int, Fhdr*, ExecHdr*); 337dd7cddfSDavid du Colombier static int alphadotout(int, Fhdr*, ExecHdr*); 343e12c5d1SDavid du Colombier static void setsym(Fhdr*, long, long, long, long); 353e12c5d1SDavid du Colombier static void setdata(Fhdr*, long, long, long, long); 363e12c5d1SDavid du Colombier static void settext(Fhdr*, long, long, long, long); 373e12c5d1SDavid du Colombier static void hswal(long*, int, long(*)(long)); 38*70b8e010SDavid du Colombier static long noswal(long); 39219b2ee8SDavid du Colombier static long _round(long, long); 403e12c5d1SDavid du Colombier 413e12c5d1SDavid du Colombier /* 423e12c5d1SDavid du Colombier * definition of per-executable file type structures 433e12c5d1SDavid du Colombier */ 443e12c5d1SDavid du Colombier 453e12c5d1SDavid du Colombier typedef struct Exectable{ 463e12c5d1SDavid du Colombier long magic; /* big-endian magic number of file */ 473e12c5d1SDavid du Colombier char *name; /* executable identifier */ 4812fd1c83SDavid du Colombier char *dlmname; /* dynamically loadable module identifier */ 493e12c5d1SDavid du Colombier int type; /* Internal code */ 503e12c5d1SDavid du Colombier Mach *mach; /* Per-machine data */ 513e12c5d1SDavid du Colombier ulong hsize; /* header size */ 523e12c5d1SDavid du Colombier long (*swal)(long); /* beswal or leswal */ 537dd7cddfSDavid du Colombier int (*hparse)(int, Fhdr*, ExecHdr*); 543e12c5d1SDavid du Colombier } ExecTable; 553e12c5d1SDavid du Colombier 563e12c5d1SDavid du Colombier extern Mach mmips; 577dd7cddfSDavid du Colombier extern Mach mmips2le; 587dd7cddfSDavid du Colombier extern Mach mmips2be; 593e12c5d1SDavid du Colombier extern Mach msparc; 603e12c5d1SDavid du Colombier extern Mach m68020; 613e12c5d1SDavid du Colombier extern Mach mi386; 627dd7cddfSDavid du Colombier extern Mach marm; 637dd7cddfSDavid du Colombier extern Mach mpower; 647dd7cddfSDavid du Colombier extern Mach malpha; 653e12c5d1SDavid du Colombier 663e12c5d1SDavid du Colombier ExecTable exectab[] = 673e12c5d1SDavid du Colombier { 683e12c5d1SDavid du Colombier { V_MAGIC, /* Mips v.out */ 693e12c5d1SDavid du Colombier "mips plan 9 executable", 7012fd1c83SDavid du Colombier "mips plan 9 dlm", 713e12c5d1SDavid du Colombier FMIPS, 723e12c5d1SDavid du Colombier &mmips, 733e12c5d1SDavid du Colombier sizeof(Exec), 743e12c5d1SDavid du Colombier beswal, 753e12c5d1SDavid du Colombier adotout }, 767dd7cddfSDavid du Colombier { M_MAGIC, /* Mips 4.out */ 777dd7cddfSDavid du Colombier "mips 4k plan 9 executable BE", 7812fd1c83SDavid du Colombier "mips 4k plan 9 dlm BE", 797dd7cddfSDavid du Colombier FMIPS2BE, 807dd7cddfSDavid du Colombier &mmips2be, 817dd7cddfSDavid du Colombier sizeof(Exec), 827dd7cddfSDavid du Colombier beswal, 837dd7cddfSDavid du Colombier adotout }, 847dd7cddfSDavid du Colombier { N_MAGIC, /* Mips 0.out */ 857dd7cddfSDavid du Colombier "mips 4k plan 9 executable LE", 8612fd1c83SDavid du Colombier "mips 4k plan 9 dlm LE", 877dd7cddfSDavid du Colombier FMIPS2LE, 887dd7cddfSDavid du Colombier &mmips2le, 897dd7cddfSDavid du Colombier sizeof(Exec), 907dd7cddfSDavid du Colombier beswal, 917dd7cddfSDavid du Colombier adotout }, 923e12c5d1SDavid du Colombier { 0x160<<16, /* Mips boot image */ 933e12c5d1SDavid du Colombier "mips plan 9 boot image", 9412fd1c83SDavid du Colombier nil, 953e12c5d1SDavid du Colombier FMIPSB, 963e12c5d1SDavid du Colombier &mmips, 973e12c5d1SDavid du Colombier sizeof(struct mipsexec), 983e12c5d1SDavid du Colombier beswal, 993e12c5d1SDavid du Colombier mipsboot }, 100219b2ee8SDavid du Colombier { (0x160<<16)|3, /* Mips boot image */ 101219b2ee8SDavid du Colombier "mips 4k plan 9 boot image", 10212fd1c83SDavid du Colombier nil, 103219b2ee8SDavid du Colombier FMIPSB, 10480ee5cbfSDavid du Colombier &mmips2be, 105219b2ee8SDavid du Colombier sizeof(struct mips4kexec), 1063e12c5d1SDavid du Colombier beswal, 107219b2ee8SDavid du Colombier mips4kboot }, 1083e12c5d1SDavid du Colombier { K_MAGIC, /* Sparc k.out */ 1093e12c5d1SDavid du Colombier "sparc plan 9 executable", 11012fd1c83SDavid du Colombier "sparc plan 9 dlm", 1113e12c5d1SDavid du Colombier FSPARC, 1123e12c5d1SDavid du Colombier &msparc, 1133e12c5d1SDavid du Colombier sizeof(Exec), 1143e12c5d1SDavid du Colombier beswal, 1153e12c5d1SDavid du Colombier adotout }, 1163e12c5d1SDavid du Colombier { 0x01030107, /* Sparc boot image */ 1173e12c5d1SDavid du Colombier "sparc plan 9 boot image", 11812fd1c83SDavid du Colombier nil, 1193e12c5d1SDavid du Colombier FSPARCB, 1203e12c5d1SDavid du Colombier &msparc, 1213e12c5d1SDavid du Colombier sizeof(struct sparcexec), 1223e12c5d1SDavid du Colombier beswal, 1233e12c5d1SDavid du Colombier sparcboot }, 1243e12c5d1SDavid du Colombier { A_MAGIC, /* 68020 2.out & boot image */ 1253e12c5d1SDavid du Colombier "68020 plan 9 executable", 12612fd1c83SDavid du Colombier "68020 plan 9 dlm", 1273e12c5d1SDavid du Colombier F68020, 1283e12c5d1SDavid du Colombier &m68020, 1293e12c5d1SDavid du Colombier sizeof(Exec), 1303e12c5d1SDavid du Colombier beswal, 1313e12c5d1SDavid du Colombier common }, 1323e12c5d1SDavid du Colombier { 0xFEEDFACE, /* Next boot image */ 1333e12c5d1SDavid du Colombier "next plan 9 boot image", 13412fd1c83SDavid du Colombier nil, 1353e12c5d1SDavid du Colombier FNEXTB, 1363e12c5d1SDavid du Colombier &m68020, 1373e12c5d1SDavid du Colombier sizeof(struct nextexec), 1383e12c5d1SDavid du Colombier beswal, 1393e12c5d1SDavid du Colombier nextboot }, 1403e12c5d1SDavid du Colombier { I_MAGIC, /* I386 8.out & boot image */ 1413e12c5d1SDavid du Colombier "386 plan 9 executable", 14212fd1c83SDavid du Colombier "386 plan 9 dlm", 1433e12c5d1SDavid du Colombier FI386, 1443e12c5d1SDavid du Colombier &mi386, 1453e12c5d1SDavid du Colombier sizeof(Exec), 1463e12c5d1SDavid du Colombier beswal, 1473e12c5d1SDavid du Colombier common }, 1489a747e4fSDavid du Colombier { Q_MAGIC, /* PowerPC q.out & boot image */ 1497dd7cddfSDavid du Colombier "power plan 9 executable", 15012fd1c83SDavid du Colombier "power plan 9 dlm", 1517dd7cddfSDavid du Colombier FPOWER, 1527dd7cddfSDavid du Colombier &mpower, 1537dd7cddfSDavid du Colombier sizeof(Exec), 1547dd7cddfSDavid du Colombier beswal, 1557dd7cddfSDavid du Colombier common }, 156*70b8e010SDavid du Colombier { ELF_MAG, /* any elf32 */ 157*70b8e010SDavid du Colombier "Elf executable", 15812fd1c83SDavid du Colombier nil, 159*70b8e010SDavid du Colombier FNONE, 160*70b8e010SDavid du Colombier &mi386, 1617dd7cddfSDavid du Colombier sizeof(Ehdr), 162*70b8e010SDavid du Colombier noswal, 1637dd7cddfSDavid du Colombier elfdotout }, 1647dd7cddfSDavid du Colombier { E_MAGIC, /* Arm 5.out */ 1657dd7cddfSDavid du Colombier "Arm plan 9 executable", 16612fd1c83SDavid du Colombier "Arm plan 9 dlm", 1677dd7cddfSDavid du Colombier FARM, 1687dd7cddfSDavid du Colombier &marm, 1697dd7cddfSDavid du Colombier sizeof(Exec), 1707dd7cddfSDavid du Colombier beswal, 1717dd7cddfSDavid du Colombier common }, 1727dd7cddfSDavid du Colombier { (143<<16)|0413, /* (Free|Net)BSD Arm */ 1737dd7cddfSDavid du Colombier "Arm *BSD executable", 17412fd1c83SDavid du Colombier nil, 1757dd7cddfSDavid du Colombier FARM, 1767dd7cddfSDavid du Colombier &marm, 1777dd7cddfSDavid du Colombier sizeof(Exec), 1787dd7cddfSDavid du Colombier leswal, 1797dd7cddfSDavid du Colombier armdotout }, 1807dd7cddfSDavid du Colombier { L_MAGIC, /* alpha 7.out */ 1817dd7cddfSDavid du Colombier "alpha plan 9 executable", 18212fd1c83SDavid du Colombier "alpha plan 9 dlm", 1837dd7cddfSDavid du Colombier FALPHA, 1847dd7cddfSDavid du Colombier &malpha, 1857dd7cddfSDavid du Colombier sizeof(Exec), 1867dd7cddfSDavid du Colombier beswal, 1877dd7cddfSDavid du Colombier common }, 1887dd7cddfSDavid du Colombier { 0x0700e0c3, /* alpha boot image */ 1897dd7cddfSDavid du Colombier "alpha plan 9 boot image", 19012fd1c83SDavid du Colombier nil, 1917dd7cddfSDavid du Colombier FALPHAB, 1927dd7cddfSDavid du Colombier &malpha, 1937dd7cddfSDavid du Colombier sizeof(Exec), 1947dd7cddfSDavid du Colombier beswal, 1957dd7cddfSDavid du Colombier alphadotout }, 1963e12c5d1SDavid du Colombier { 0 }, 1973e12c5d1SDavid du Colombier }; 1983e12c5d1SDavid du Colombier 1997dd7cddfSDavid du Colombier Mach *mach = &mi386; /* Global current machine table */ 2007dd7cddfSDavid du Colombier 2017dd7cddfSDavid du Colombier static ExecTable* 2027dd7cddfSDavid du Colombier couldbe4k(ExecTable *mp) 2037dd7cddfSDavid du Colombier { 2049a747e4fSDavid du Colombier Dir *d; 2057dd7cddfSDavid du Colombier ExecTable *f; 2067dd7cddfSDavid du Colombier 2079a747e4fSDavid du Colombier if((d=dirstat("/proc/1/regs")) == nil) 2087dd7cddfSDavid du Colombier return mp; 2099a747e4fSDavid du Colombier if(d->length < 32*8){ /* R3000 */ 2109a747e4fSDavid du Colombier free(d); 2117dd7cddfSDavid du Colombier return mp; 2129a747e4fSDavid du Colombier } 2139a747e4fSDavid du Colombier free(d); 2147dd7cddfSDavid du Colombier for (f = exectab; f->magic; f++) 2157dd7cddfSDavid du Colombier if(f->magic == M_MAGIC) { 2167dd7cddfSDavid du Colombier f->name = "mips plan 9 executable on mips2 kernel"; 2177dd7cddfSDavid du Colombier return f; 2187dd7cddfSDavid du Colombier } 2197dd7cddfSDavid du Colombier return mp; 2207dd7cddfSDavid du Colombier } 2217dd7cddfSDavid du Colombier 2223e12c5d1SDavid du Colombier int 2233e12c5d1SDavid du Colombier crackhdr(int fd, Fhdr *fp) 2243e12c5d1SDavid du Colombier { 2253e12c5d1SDavid du Colombier ExecTable *mp; 2263e12c5d1SDavid du Colombier ExecHdr d; 2277dd7cddfSDavid du Colombier int nb, magic, ret; 2283e12c5d1SDavid du Colombier 2293e12c5d1SDavid du Colombier fp->type = FNONE; 2307dd7cddfSDavid du Colombier nb = read(fd, (char *)&d.e, sizeof(d.e)); 2317dd7cddfSDavid du Colombier if (nb <= 0) 2323e12c5d1SDavid du Colombier return 0; 2337dd7cddfSDavid du Colombier 2347dd7cddfSDavid du Colombier ret = 0; 2353e12c5d1SDavid du Colombier fp->magic = magic = beswal(d.e.magic); /* big-endian */ 2363e12c5d1SDavid du Colombier for (mp = exectab; mp->magic; mp++) { 23712fd1c83SDavid du Colombier if (nb < mp->hsize) 23812fd1c83SDavid du Colombier continue; 23912fd1c83SDavid du Colombier if (mp->magic == (magic & ~DYN_MAGIC)) { 2407dd7cddfSDavid du Colombier if(mp->magic == V_MAGIC) 2417dd7cddfSDavid du Colombier mp = couldbe4k(mp); 2427dd7cddfSDavid du Colombier 2433e12c5d1SDavid du Colombier hswal((long *) &d, sizeof(d.e)/sizeof(long), mp->swal); 2443e12c5d1SDavid du Colombier fp->type = mp->type; 24512fd1c83SDavid du Colombier if ((magic & DYN_MAGIC) && mp->dlmname != nil) 24612fd1c83SDavid du Colombier fp->name = mp->dlmname; 24712fd1c83SDavid du Colombier else 2483e12c5d1SDavid du Colombier fp->name = mp->name; 249219b2ee8SDavid du Colombier fp->hdrsz = mp->hsize; /* zero on bootables */ 2503e12c5d1SDavid du Colombier mach = mp->mach; 2517dd7cddfSDavid du Colombier ret = mp->hparse(fd, fp, &d); 2523e12c5d1SDavid du Colombier seek(fd, mp->hsize, 0); /* seek to end of header */ 2537dd7cddfSDavid du Colombier break; 2543e12c5d1SDavid du Colombier } 2553e12c5d1SDavid du Colombier } 2567dd7cddfSDavid du Colombier if(mp->magic == 0) 2577dd7cddfSDavid du Colombier werrstr("unknown header type"); 2587dd7cddfSDavid du Colombier return ret; 2593e12c5d1SDavid du Colombier } 2603e12c5d1SDavid du Colombier /* 2613e12c5d1SDavid du Colombier * Convert header to canonical form 2623e12c5d1SDavid du Colombier */ 2633e12c5d1SDavid du Colombier static void 2643e12c5d1SDavid du Colombier hswal(long *lp, int n, long (*swap) (long)) 2653e12c5d1SDavid du Colombier { 2663e12c5d1SDavid du Colombier while (n--) { 2673e12c5d1SDavid du Colombier *lp = (*swap) (*lp); 2683e12c5d1SDavid du Colombier lp++; 2693e12c5d1SDavid du Colombier } 2703e12c5d1SDavid du Colombier } 2713e12c5d1SDavid du Colombier /* 272*70b8e010SDavid du Colombier * noop 273*70b8e010SDavid du Colombier */ 274*70b8e010SDavid du Colombier static long 275*70b8e010SDavid du Colombier noswal(long x) 276*70b8e010SDavid du Colombier { 277*70b8e010SDavid du Colombier return x; 278*70b8e010SDavid du Colombier } 279*70b8e010SDavid du Colombier /* 2803e12c5d1SDavid du Colombier * Crack a normal a.out-type header 2813e12c5d1SDavid du Colombier */ 2827dd7cddfSDavid du Colombier static int 2837dd7cddfSDavid du Colombier adotout(int fd, Fhdr *fp, ExecHdr *hp) 2843e12c5d1SDavid du Colombier { 2857dd7cddfSDavid du Colombier long pgsize; 2863e12c5d1SDavid du Colombier 2877dd7cddfSDavid du Colombier USED(fd); 2887dd7cddfSDavid du Colombier pgsize = mach->pgsize; 289219b2ee8SDavid du Colombier settext(fp, hp->e.entry, pgsize+sizeof(Exec), 290219b2ee8SDavid du Colombier hp->e.text, sizeof(Exec)); 291219b2ee8SDavid du Colombier setdata(fp, _round(pgsize+fp->txtsz+sizeof(Exec), pgsize), 292219b2ee8SDavid du Colombier hp->e.data, fp->txtsz+sizeof(Exec), hp->e.bss); 2933e12c5d1SDavid du Colombier setsym(fp, hp->e.syms, hp->e.spsz, hp->e.pcsz, fp->datoff+fp->datsz); 2947dd7cddfSDavid du Colombier return 1; 2953e12c5d1SDavid du Colombier } 2963e12c5d1SDavid du Colombier 2973e12c5d1SDavid du Colombier /* 2983e12c5d1SDavid du Colombier * 68020 2.out and 68020 bootable images 2993e12c5d1SDavid du Colombier * 386I 8.out and 386I bootable images 3007dd7cddfSDavid du Colombier * alpha plan9-style bootable images for axp "headerless" boot 3013e12c5d1SDavid du Colombier * 3023e12c5d1SDavid du Colombier */ 3037dd7cddfSDavid du Colombier static int 3047dd7cddfSDavid du Colombier common(int fd, Fhdr *fp, ExecHdr *hp) 3053e12c5d1SDavid du Colombier { 3067dd7cddfSDavid du Colombier long kbase; 3073e12c5d1SDavid du Colombier 3087dd7cddfSDavid du Colombier adotout(fd, fp, hp); 3099a747e4fSDavid du Colombier if(hp->e.magic & DYN_MAGIC) { 3109a747e4fSDavid du Colombier fp->txtaddr = 0; 3119a747e4fSDavid du Colombier fp->dataddr = fp->txtsz; 3129a747e4fSDavid du Colombier return 1; 3139a747e4fSDavid du Colombier } 3147dd7cddfSDavid du Colombier kbase = mach->kbase; 3157dd7cddfSDavid du Colombier if ((fp->entry & kbase) == kbase) { /* Boot image */ 3163e12c5d1SDavid du Colombier switch(fp->type) { 3173e12c5d1SDavid du Colombier case F68020: 3183e12c5d1SDavid du Colombier fp->type = F68020B; 3193e12c5d1SDavid du Colombier fp->name = "68020 plan 9 boot image"; 320219b2ee8SDavid du Colombier fp->hdrsz = 0; /* header stripped */ 3213e12c5d1SDavid du Colombier break; 3223e12c5d1SDavid du Colombier case FI386: 3233e12c5d1SDavid du Colombier fp->type = FI386B; 324219b2ee8SDavid du Colombier fp->txtaddr = sizeof(Exec); 3253e12c5d1SDavid du Colombier fp->name = "386 plan 9 boot image"; 326219b2ee8SDavid du Colombier fp->hdrsz = 0; /* header stripped */ 327219b2ee8SDavid du Colombier fp->dataddr = fp->txtaddr+fp->txtsz; 3283e12c5d1SDavid du Colombier break; 3297dd7cddfSDavid du Colombier case FARM: 33080ee5cbfSDavid du Colombier fp->txtaddr = kbase+0x8010; 3317dd7cddfSDavid du Colombier fp->name = "ARM plan 9 boot image"; 3327dd7cddfSDavid du Colombier fp->hdrsz = 0; /* header stripped */ 3337dd7cddfSDavid du Colombier fp->dataddr = fp->txtaddr+fp->txtsz; 3347dd7cddfSDavid du Colombier return 1; 3357dd7cddfSDavid du Colombier case FALPHA: 3367dd7cddfSDavid du Colombier fp->type = FALPHAB; 3377dd7cddfSDavid du Colombier fp->txtaddr = fp->entry; 3389a747e4fSDavid du Colombier fp->name = "alpha plan 9 boot image?"; 3397dd7cddfSDavid du Colombier fp->hdrsz = 0; /* header stripped */ 3407dd7cddfSDavid du Colombier fp->dataddr = fp->txtaddr+fp->txtsz; 3417dd7cddfSDavid du Colombier break; 3429a747e4fSDavid du Colombier case FPOWER: 3439a747e4fSDavid du Colombier fp->type = FPOWERB; 3449a747e4fSDavid du Colombier fp->txtaddr = fp->entry; 3459a747e4fSDavid du Colombier fp->name = "power plan 9 boot image"; 3467dd7cddfSDavid du Colombier fp->hdrsz = 0; /* header stripped */ 3479a747e4fSDavid du Colombier fp->dataddr = fp->txtaddr+fp->txtsz; 3489a747e4fSDavid du Colombier break; 3493e12c5d1SDavid du Colombier default: 3503e12c5d1SDavid du Colombier break; 3513e12c5d1SDavid du Colombier } 3523e12c5d1SDavid du Colombier fp->txtaddr |= kbase; 3533e12c5d1SDavid du Colombier fp->entry |= kbase; 3543e12c5d1SDavid du Colombier fp->dataddr |= kbase; 3553e12c5d1SDavid du Colombier } 3567dd7cddfSDavid du Colombier return 1; 3573e12c5d1SDavid du Colombier } 3583e12c5d1SDavid du Colombier 3593e12c5d1SDavid du Colombier /* 3603e12c5d1SDavid du Colombier * mips bootable image. 3613e12c5d1SDavid du Colombier */ 3627dd7cddfSDavid du Colombier static int 3637dd7cddfSDavid du Colombier mipsboot(int fd, Fhdr *fp, ExecHdr *hp) 3643e12c5d1SDavid du Colombier { 3657dd7cddfSDavid du Colombier USED(fd); 3663e12c5d1SDavid du Colombier switch(hp->e.amagic) { 3673e12c5d1SDavid du Colombier default: 3683e12c5d1SDavid du Colombier case 0407: /* some kind of mips */ 3693e12c5d1SDavid du Colombier fp->type = FMIPSB; 3703e12c5d1SDavid du Colombier settext(fp, hp->e.mentry, hp->e.text_start, hp->e.tsize, 3713e12c5d1SDavid du Colombier sizeof(struct mipsexec)+4); 3723e12c5d1SDavid du Colombier setdata(fp, hp->e.data_start, hp->e.dsize, 3733e12c5d1SDavid du Colombier fp->txtoff+hp->e.tsize, hp->e.bsize); 3743e12c5d1SDavid du Colombier break; 3753e12c5d1SDavid du Colombier case 0413: /* some kind of mips */ 3763e12c5d1SDavid du Colombier fp->type = FMIPSB; 3773e12c5d1SDavid du Colombier settext(fp, hp->e.mentry, hp->e.text_start, hp->e.tsize, 0); 3783e12c5d1SDavid du Colombier setdata(fp, hp->e.data_start, hp->e.dsize, hp->e.tsize, 3793e12c5d1SDavid du Colombier hp->e.bsize); 3803e12c5d1SDavid du Colombier break; 3813e12c5d1SDavid du Colombier } 3823e12c5d1SDavid du Colombier setsym(fp, hp->e.nsyms, 0, hp->e.pcsize, hp->e.symptr); 383219b2ee8SDavid du Colombier fp->hdrsz = 0; /* header stripped */ 3847dd7cddfSDavid du Colombier return 1; 3853e12c5d1SDavid du Colombier } 386219b2ee8SDavid du Colombier 3873e12c5d1SDavid du Colombier /* 388219b2ee8SDavid du Colombier * mips4k bootable image. 3893e12c5d1SDavid du Colombier */ 3907dd7cddfSDavid du Colombier static int 3917dd7cddfSDavid du Colombier mips4kboot(int fd, Fhdr *fp, ExecHdr *hp) 3923e12c5d1SDavid du Colombier { 3937dd7cddfSDavid du Colombier USED(fd); 394219b2ee8SDavid du Colombier switch(hp->e.h.amagic) { 395219b2ee8SDavid du Colombier default: 396219b2ee8SDavid du Colombier case 0407: /* some kind of mips */ 397219b2ee8SDavid du Colombier fp->type = FMIPSB; 398219b2ee8SDavid du Colombier settext(fp, hp->e.h.mentry, hp->e.h.text_start, hp->e.h.tsize, 399219b2ee8SDavid du Colombier sizeof(struct mips4kexec)); 400219b2ee8SDavid du Colombier setdata(fp, hp->e.h.data_start, hp->e.h.dsize, 401219b2ee8SDavid du Colombier fp->txtoff+hp->e.h.tsize, hp->e.h.bsize); 402219b2ee8SDavid du Colombier break; 403219b2ee8SDavid du Colombier case 0413: /* some kind of mips */ 404219b2ee8SDavid du Colombier fp->type = FMIPSB; 405219b2ee8SDavid du Colombier settext(fp, hp->e.h.mentry, hp->e.h.text_start, hp->e.h.tsize, 0); 406219b2ee8SDavid du Colombier setdata(fp, hp->e.h.data_start, hp->e.h.dsize, hp->e.h.tsize, 407219b2ee8SDavid du Colombier hp->e.h.bsize); 408219b2ee8SDavid du Colombier break; 4093e12c5d1SDavid du Colombier } 410219b2ee8SDavid du Colombier setsym(fp, hp->e.h.nsyms, 0, hp->e.h.pcsize, hp->e.h.symptr); 411219b2ee8SDavid du Colombier fp->hdrsz = 0; /* header stripped */ 4127dd7cddfSDavid du Colombier return 1; 413219b2ee8SDavid du Colombier } 414219b2ee8SDavid du Colombier 4153e12c5d1SDavid du Colombier /* 4163e12c5d1SDavid du Colombier * sparc bootable image 4173e12c5d1SDavid du Colombier */ 4187dd7cddfSDavid du Colombier static int 4197dd7cddfSDavid du Colombier sparcboot(int fd, Fhdr *fp, ExecHdr *hp) 4203e12c5d1SDavid du Colombier { 4217dd7cddfSDavid du Colombier USED(fd); 4223e12c5d1SDavid du Colombier fp->type = FSPARCB; 4233e12c5d1SDavid du Colombier settext(fp, hp->e.sentry, hp->e.sentry, hp->e.stext, 4243e12c5d1SDavid du Colombier sizeof(struct sparcexec)); 4253e12c5d1SDavid du Colombier setdata(fp, hp->e.sentry+hp->e.stext, hp->e.sdata, 4263e12c5d1SDavid du Colombier fp->txtoff+hp->e.stext, hp->e.sbss); 4273e12c5d1SDavid du Colombier setsym(fp, hp->e.ssyms, 0, hp->e.sdrsize, fp->datoff+hp->e.sdata); 428219b2ee8SDavid du Colombier fp->hdrsz = 0; /* header stripped */ 4297dd7cddfSDavid du Colombier return 1; 4303e12c5d1SDavid du Colombier } 4313e12c5d1SDavid du Colombier 4323e12c5d1SDavid du Colombier /* 4333e12c5d1SDavid du Colombier * next bootable image 4343e12c5d1SDavid du Colombier */ 4357dd7cddfSDavid du Colombier static int 4367dd7cddfSDavid du Colombier nextboot(int fd, Fhdr *fp, ExecHdr *hp) 4373e12c5d1SDavid du Colombier { 4387dd7cddfSDavid du Colombier USED(fd); 4393e12c5d1SDavid du Colombier fp->type = FNEXTB; 4403e12c5d1SDavid du Colombier settext(fp, hp->e.textc.vmaddr, hp->e.textc.vmaddr, 4413e12c5d1SDavid du Colombier hp->e.texts.size, hp->e.texts.offset); 4423e12c5d1SDavid du Colombier setdata(fp, hp->e.datac.vmaddr, hp->e.datas.size, 4433e12c5d1SDavid du Colombier hp->e.datas.offset, hp->e.bsss.size); 4443e12c5d1SDavid du Colombier setsym(fp, hp->e.symc.nsyms, hp->e.symc.spoff, hp->e.symc.pcoff, 4453e12c5d1SDavid du Colombier hp->e.symc.symoff); 446219b2ee8SDavid du Colombier fp->hdrsz = 0; /* header stripped */ 4477dd7cddfSDavid du Colombier return 1; 4483e12c5d1SDavid du Colombier } 4493e12c5d1SDavid du Colombier 4507dd7cddfSDavid du Colombier 4517dd7cddfSDavid du Colombier /* 452*70b8e010SDavid du Colombier * Elf32 binaries. 4537dd7cddfSDavid du Colombier */ 4547dd7cddfSDavid du Colombier static int 4557dd7cddfSDavid du Colombier elfdotout(int fd, Fhdr *fp, ExecHdr *hp) 4567dd7cddfSDavid du Colombier { 4577dd7cddfSDavid du Colombier 458*70b8e010SDavid du Colombier long (*swal)(long); 459*70b8e010SDavid du Colombier ushort (*swab)(ushort); 4607dd7cddfSDavid du Colombier Ehdr *ep; 461*70b8e010SDavid du Colombier Phdr *ph; 462*70b8e010SDavid du Colombier int i, it, id, is, phsz; 4637dd7cddfSDavid du Colombier 464*70b8e010SDavid du Colombier /* bitswap the header according to the DATA format */ 4657dd7cddfSDavid du Colombier ep = &hp->e; 466*70b8e010SDavid du Colombier if(ep->ident[CLASS] != ELFCLASS32) { 467*70b8e010SDavid du Colombier werrstr("bad ELF class - not 32 bit"); 468*70b8e010SDavid du Colombier return 0; 469*70b8e010SDavid du Colombier } 470*70b8e010SDavid du Colombier if(ep->ident[DATA] == ELFDATA2LSB) { 471*70b8e010SDavid du Colombier swab = leswab; 472*70b8e010SDavid du Colombier swal = leswal; 473*70b8e010SDavid du Colombier } else if(ep->ident[DATA] == ELFDATA2MSB) { 474*70b8e010SDavid du Colombier swab = beswab; 475*70b8e010SDavid du Colombier swal = beswal; 476*70b8e010SDavid du Colombier } else { 477*70b8e010SDavid du Colombier werrstr("bad ELF encoding - not big or little endian"); 478*70b8e010SDavid du Colombier return 0; 479*70b8e010SDavid du Colombier } 480*70b8e010SDavid du Colombier 481*70b8e010SDavid du Colombier ep->type = swab(ep->type); 482*70b8e010SDavid du Colombier ep->machine = swab(ep->machine); 483*70b8e010SDavid du Colombier ep->version = swal(ep->version); 484*70b8e010SDavid du Colombier ep->elfentry = swal(ep->elfentry); 485*70b8e010SDavid du Colombier ep->phoff = swal(ep->phoff); 486*70b8e010SDavid du Colombier ep->shoff = swal(ep->shoff); 487*70b8e010SDavid du Colombier ep->flags = swal(ep->flags); 488*70b8e010SDavid du Colombier ep->ehsize = swab(ep->ehsize); 489*70b8e010SDavid du Colombier ep->phentsize = swab(ep->phentsize); 490*70b8e010SDavid du Colombier ep->phnum = swab(ep->phnum); 491*70b8e010SDavid du Colombier ep->shentsize = swab(ep->shentsize); 492*70b8e010SDavid du Colombier ep->shnum = swab(ep->shnum); 493*70b8e010SDavid du Colombier ep->shstrndx = swab(ep->shstrndx); 494*70b8e010SDavid du Colombier if(ep->type != EXEC || ep->version != CURRENT) 4957dd7cddfSDavid du Colombier return 0; 4967dd7cddfSDavid du Colombier 497*70b8e010SDavid du Colombier /* we could definitely support a lot more machines here */ 4987dd7cddfSDavid du Colombier fp->magic = ELF_MAG; 4997dd7cddfSDavid du Colombier fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15; 500*70b8e010SDavid du Colombier switch(ep->machine) { 501*70b8e010SDavid du Colombier case I386: 502*70b8e010SDavid du Colombier mach = &mi386; 503*70b8e010SDavid du Colombier fp->type = FI386; 504*70b8e010SDavid du Colombier break; 505*70b8e010SDavid du Colombier case MIPS: 506*70b8e010SDavid du Colombier mach = &mmips; 507*70b8e010SDavid du Colombier fp->type = FMIPS; 508*70b8e010SDavid du Colombier break; 509*70b8e010SDavid du Colombier case POWER: 510*70b8e010SDavid du Colombier mach = &mpower; 511*70b8e010SDavid du Colombier fp->type = FPOWER; 512*70b8e010SDavid du Colombier break; 513*70b8e010SDavid du Colombier default: 5147dd7cddfSDavid du Colombier return 0; 5157dd7cddfSDavid du Colombier } 5167dd7cddfSDavid du Colombier 517*70b8e010SDavid du Colombier if(ep->phentsize != sizeof(Phdr)) { 518*70b8e010SDavid du Colombier werrstr("bad ELF header size"); 519*70b8e010SDavid du Colombier return 0; 520*70b8e010SDavid du Colombier } 521*70b8e010SDavid du Colombier phsz = sizeof(Phdr)*ep->phnum; 522*70b8e010SDavid du Colombier ph = malloc(phsz); 523*70b8e010SDavid du Colombier if(!ph) 524*70b8e010SDavid du Colombier return 0; 525*70b8e010SDavid du Colombier seek(fd, ep->phoff, 0); 526*70b8e010SDavid du Colombier if(read(fd, ph, phsz) < 0) { 527*70b8e010SDavid du Colombier free(ph); 528*70b8e010SDavid du Colombier return 0; 529*70b8e010SDavid du Colombier } 530*70b8e010SDavid du Colombier hswal((long*)ph, phsz/sizeof(long), swal); 5317dd7cddfSDavid du Colombier 532*70b8e010SDavid du Colombier /* find text, data and symbols and install them */ 533*70b8e010SDavid du Colombier it = id = is = -1; 534*70b8e010SDavid du Colombier for(i = 0; i < ep->phnum; i++) { 535*70b8e010SDavid du Colombier if(ph[i].type == LOAD 536*70b8e010SDavid du Colombier && (ph[i].flags & (R|X)) == (R|X) && it == -1) 537*70b8e010SDavid du Colombier it = i; 538*70b8e010SDavid du Colombier else if(ph[i].type == LOAD 539*70b8e010SDavid du Colombier && (ph[i].flags & (R|W)) == (R|W) && id == -1) 540*70b8e010SDavid du Colombier id = i; 541*70b8e010SDavid du Colombier else if(ph[i].type == NOPTYPE && is == -1) 542*70b8e010SDavid du Colombier is = i; 543*70b8e010SDavid du Colombier } 544*70b8e010SDavid du Colombier if(it == -1 || id == -1) { 545*70b8e010SDavid du Colombier werrstr("No TEXT or DATA sections"); 546*70b8e010SDavid du Colombier free(ph); 547*70b8e010SDavid du Colombier return 0; 5487dd7cddfSDavid du Colombier } 5497dd7cddfSDavid du Colombier 550*70b8e010SDavid du Colombier settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset); 551*70b8e010SDavid du Colombier setdata(fp, ph[id].vaddr, ph[id].memsz, ph[id].offset, ph[id].memsz - ph[id].filesz); 552*70b8e010SDavid du Colombier if(is != -1) 553*70b8e010SDavid du Colombier setsym(fp, ph[is].filesz, 0, ph[is].memsz, ph[is].offset); 554*70b8e010SDavid du Colombier free(ph); 5557dd7cddfSDavid du Colombier return 1; 5567dd7cddfSDavid du Colombier } 5577dd7cddfSDavid du Colombier 5587dd7cddfSDavid du Colombier /* 5597dd7cddfSDavid du Colombier * alpha bootable 5607dd7cddfSDavid du Colombier */ 5617dd7cddfSDavid du Colombier static int 5627dd7cddfSDavid du Colombier alphadotout(int fd, Fhdr *fp, ExecHdr *hp) 5637dd7cddfSDavid du Colombier { 5647dd7cddfSDavid du Colombier long kbase; 5657dd7cddfSDavid du Colombier 5667dd7cddfSDavid du Colombier USED(fd); 5677dd7cddfSDavid du Colombier settext(fp, hp->e.entry, sizeof(Exec), hp->e.text, sizeof(Exec)); 5687dd7cddfSDavid du Colombier setdata(fp, fp->txtsz+sizeof(Exec), hp->e.data, fp->txtsz+sizeof(Exec), hp->e.bss); 5697dd7cddfSDavid du Colombier setsym(fp, hp->e.syms, hp->e.spsz, hp->e.pcsz, fp->datoff+fp->datsz); 5707dd7cddfSDavid du Colombier 5717dd7cddfSDavid du Colombier /* 5727dd7cddfSDavid du Colombier * Boot images have some of bits <31:28> set: 5737dd7cddfSDavid du Colombier * 0x80400000 kernel 5747dd7cddfSDavid du Colombier * 0x20000000 secondary bootstrap 5757dd7cddfSDavid du Colombier */ 5767dd7cddfSDavid du Colombier kbase = 0xF0000000; 5777dd7cddfSDavid du Colombier if (fp->entry & kbase) { 5787dd7cddfSDavid du Colombier fp->txtaddr = fp->entry; 5797dd7cddfSDavid du Colombier fp->name = "alpha plan 9 boot image"; 5807dd7cddfSDavid du Colombier fp->hdrsz = 0; /* header stripped */ 5817dd7cddfSDavid du Colombier fp->dataddr = fp->entry+fp->txtsz; 5827dd7cddfSDavid du Colombier } 5837dd7cddfSDavid du Colombier return 1; 5847dd7cddfSDavid du Colombier } 5857dd7cddfSDavid du Colombier 5867dd7cddfSDavid du Colombier /* 5877dd7cddfSDavid du Colombier * (Free|Net)BSD ARM header. 5887dd7cddfSDavid du Colombier */ 5897dd7cddfSDavid du Colombier static int 5907dd7cddfSDavid du Colombier armdotout(int fd, Fhdr *fp, ExecHdr *hp) 5917dd7cddfSDavid du Colombier { 5927dd7cddfSDavid du Colombier long kbase; 5937dd7cddfSDavid du Colombier 5947dd7cddfSDavid du Colombier USED(fd); 5957dd7cddfSDavid du Colombier settext(fp, hp->e.entry, sizeof(Exec), hp->e.text, sizeof(Exec)); 5967dd7cddfSDavid du Colombier setdata(fp, fp->txtsz, hp->e.data, fp->txtsz, hp->e.bss); 5977dd7cddfSDavid du Colombier setsym(fp, hp->e.syms, hp->e.spsz, hp->e.pcsz, fp->datoff+fp->datsz); 5987dd7cddfSDavid du Colombier 5997dd7cddfSDavid du Colombier kbase = 0xF0000000; 6007dd7cddfSDavid du Colombier if ((fp->entry & kbase) == kbase) { /* Boot image */ 6017dd7cddfSDavid du Colombier fp->txtaddr = kbase+sizeof(Exec); 6027dd7cddfSDavid du Colombier fp->name = "ARM *BSD boot image"; 6037dd7cddfSDavid du Colombier fp->hdrsz = 0; /* header stripped */ 6047dd7cddfSDavid du Colombier fp->dataddr = kbase+fp->txtsz; 6057dd7cddfSDavid du Colombier } 6067dd7cddfSDavid du Colombier return 1; 6077dd7cddfSDavid du Colombier } 6083e12c5d1SDavid du Colombier 6093e12c5d1SDavid du Colombier static void 6103e12c5d1SDavid du Colombier settext(Fhdr *fp, long e, long a, long s, long off) 6113e12c5d1SDavid du Colombier { 6123e12c5d1SDavid du Colombier fp->txtaddr = a; 6133e12c5d1SDavid du Colombier fp->entry = e; 6143e12c5d1SDavid du Colombier fp->txtsz = s; 6153e12c5d1SDavid du Colombier fp->txtoff = off; 6163e12c5d1SDavid du Colombier } 6173e12c5d1SDavid du Colombier static void 6183e12c5d1SDavid du Colombier setdata(Fhdr *fp, long a, long s, long off, long bss) 6193e12c5d1SDavid du Colombier { 6203e12c5d1SDavid du Colombier fp->dataddr = a; 6213e12c5d1SDavid du Colombier fp->datsz = s; 6223e12c5d1SDavid du Colombier fp->datoff = off; 6233e12c5d1SDavid du Colombier fp->bsssz = bss; 6243e12c5d1SDavid du Colombier } 6253e12c5d1SDavid du Colombier static void 6263e12c5d1SDavid du Colombier setsym(Fhdr *fp, long sy, long sppc, long lnpc, long symoff) 6273e12c5d1SDavid du Colombier { 6283e12c5d1SDavid du Colombier fp->symsz = sy; 6293e12c5d1SDavid du Colombier fp->symoff = symoff; 6303e12c5d1SDavid du Colombier fp->sppcsz = sppc; 6313e12c5d1SDavid du Colombier fp->sppcoff = fp->symoff+fp->symsz; 6323e12c5d1SDavid du Colombier fp->lnpcsz = lnpc; 6333e12c5d1SDavid du Colombier fp->lnpcoff = fp->sppcoff+fp->sppcsz; 6343e12c5d1SDavid du Colombier } 6353e12c5d1SDavid du Colombier 636219b2ee8SDavid du Colombier 637219b2ee8SDavid du Colombier static long 638219b2ee8SDavid du Colombier _round(long a, long b) 639219b2ee8SDavid du Colombier { 640219b2ee8SDavid du Colombier long w; 641219b2ee8SDavid du Colombier 642219b2ee8SDavid du Colombier w = (a/b)*b; 643219b2ee8SDavid du Colombier if (a!=w) 644219b2ee8SDavid du Colombier w += b; 645219b2ee8SDavid du Colombier return(w); 646219b2ee8SDavid du Colombier } 647