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 struct i960exec; 223e12c5d1SDavid du Colombier } e; 233e12c5d1SDavid du Colombier long dummy; /* padding to ensure extra long */ 243e12c5d1SDavid du Colombier } ExecHdr; 253e12c5d1SDavid du Colombier 267dd7cddfSDavid du Colombier static int i960boot(int, Fhdr*, ExecHdr*); 277dd7cddfSDavid du Colombier static int nextboot(int, Fhdr*, ExecHdr*); 287dd7cddfSDavid du Colombier static int sparcboot(int, Fhdr*, ExecHdr*); 297dd7cddfSDavid du Colombier static int mipsboot(int, Fhdr*, ExecHdr*); 307dd7cddfSDavid du Colombier static int mips4kboot(int, Fhdr*, ExecHdr*); 317dd7cddfSDavid du Colombier static int common(int, Fhdr*, ExecHdr*); 327dd7cddfSDavid du Colombier static int adotout(int, Fhdr*, ExecHdr*); 337dd7cddfSDavid du Colombier static int elfdotout(int, Fhdr*, ExecHdr*); 347dd7cddfSDavid du Colombier static int armdotout(int, Fhdr*, ExecHdr*); 357dd7cddfSDavid du Colombier static int alphadotout(int, Fhdr*, ExecHdr*); 363e12c5d1SDavid du Colombier static void setsym(Fhdr*, long, long, long, long); 373e12c5d1SDavid du Colombier static void setdata(Fhdr*, long, long, long, long); 383e12c5d1SDavid du Colombier static void settext(Fhdr*, long, long, long, long); 393e12c5d1SDavid du Colombier static void hswal(long*, int, long(*)(long)); 40219b2ee8SDavid du Colombier static long _round(long, long); 413e12c5d1SDavid du Colombier 423e12c5d1SDavid du Colombier /* 433e12c5d1SDavid du Colombier * definition of per-executable file type structures 443e12c5d1SDavid du Colombier */ 453e12c5d1SDavid du Colombier 463e12c5d1SDavid du Colombier typedef struct Exectable{ 473e12c5d1SDavid du Colombier long magic; /* big-endian magic number of file */ 483e12c5d1SDavid du Colombier char *name; /* executable 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; 623e12c5d1SDavid du Colombier extern Mach mi960; 63219b2ee8SDavid du Colombier extern Mach m3210; 647dd7cddfSDavid du Colombier extern Mach m29000; 657dd7cddfSDavid du Colombier extern Mach marm; 667dd7cddfSDavid du Colombier extern Mach mpower; 677dd7cddfSDavid du Colombier extern Mach malpha; 683e12c5d1SDavid du Colombier 693e12c5d1SDavid du Colombier ExecTable exectab[] = 703e12c5d1SDavid du Colombier { 713e12c5d1SDavid du Colombier { V_MAGIC, /* Mips v.out */ 723e12c5d1SDavid du Colombier "mips plan 9 executable", 733e12c5d1SDavid du Colombier FMIPS, 743e12c5d1SDavid du Colombier &mmips, 753e12c5d1SDavid du Colombier sizeof(Exec), 763e12c5d1SDavid du Colombier beswal, 773e12c5d1SDavid du Colombier adotout }, 787dd7cddfSDavid du Colombier { M_MAGIC, /* Mips 4.out */ 797dd7cddfSDavid du Colombier "mips 4k plan 9 executable BE", 807dd7cddfSDavid du Colombier FMIPS2BE, 817dd7cddfSDavid du Colombier &mmips2be, 827dd7cddfSDavid du Colombier sizeof(Exec), 837dd7cddfSDavid du Colombier beswal, 847dd7cddfSDavid du Colombier adotout }, 857dd7cddfSDavid du Colombier { N_MAGIC, /* Mips 0.out */ 867dd7cddfSDavid du Colombier "mips 4k plan 9 executable 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", 943e12c5d1SDavid du Colombier FMIPSB, 953e12c5d1SDavid du Colombier &mmips, 963e12c5d1SDavid du Colombier sizeof(struct mipsexec), 973e12c5d1SDavid du Colombier beswal, 983e12c5d1SDavid du Colombier mipsboot }, 99219b2ee8SDavid du Colombier { (0x160<<16)|3, /* Mips boot image */ 100219b2ee8SDavid du Colombier "mips 4k plan 9 boot image", 101219b2ee8SDavid du Colombier FMIPSB, 10280ee5cbfSDavid du Colombier &mmips2be, 103219b2ee8SDavid du Colombier sizeof(struct mips4kexec), 1043e12c5d1SDavid du Colombier beswal, 105219b2ee8SDavid du Colombier mips4kboot }, 1063e12c5d1SDavid du Colombier { K_MAGIC, /* Sparc k.out */ 1073e12c5d1SDavid du Colombier "sparc plan 9 executable", 1083e12c5d1SDavid du Colombier FSPARC, 1093e12c5d1SDavid du Colombier &msparc, 1103e12c5d1SDavid du Colombier sizeof(Exec), 1113e12c5d1SDavid du Colombier beswal, 1123e12c5d1SDavid du Colombier adotout }, 1133e12c5d1SDavid du Colombier { 0x01030107, /* Sparc boot image */ 1143e12c5d1SDavid du Colombier "sparc plan 9 boot image", 1153e12c5d1SDavid du Colombier FSPARCB, 1163e12c5d1SDavid du Colombier &msparc, 1173e12c5d1SDavid du Colombier sizeof(struct sparcexec), 1183e12c5d1SDavid du Colombier beswal, 1193e12c5d1SDavid du Colombier sparcboot }, 1203e12c5d1SDavid du Colombier { A_MAGIC, /* 68020 2.out & boot image */ 1213e12c5d1SDavid du Colombier "68020 plan 9 executable", 1223e12c5d1SDavid du Colombier F68020, 1233e12c5d1SDavid du Colombier &m68020, 1243e12c5d1SDavid du Colombier sizeof(Exec), 1253e12c5d1SDavid du Colombier beswal, 1263e12c5d1SDavid du Colombier common }, 1273e12c5d1SDavid du Colombier { 0xFEEDFACE, /* Next boot image */ 1283e12c5d1SDavid du Colombier "next plan 9 boot image", 1293e12c5d1SDavid du Colombier FNEXTB, 1303e12c5d1SDavid du Colombier &m68020, 1313e12c5d1SDavid du Colombier sizeof(struct nextexec), 1323e12c5d1SDavid du Colombier beswal, 1333e12c5d1SDavid du Colombier nextboot }, 1343e12c5d1SDavid du Colombier { I_MAGIC, /* I386 8.out & boot image */ 1353e12c5d1SDavid du Colombier "386 plan 9 executable", 1363e12c5d1SDavid du Colombier FI386, 1373e12c5d1SDavid du Colombier &mi386, 1383e12c5d1SDavid du Colombier sizeof(Exec), 1393e12c5d1SDavid du Colombier beswal, 1403e12c5d1SDavid du Colombier common }, 141*9a747e4fSDavid du Colombier { I_MAGIC|DYN_MAGIC, /* I386 dynamic load module */ 142*9a747e4fSDavid du Colombier "386 plan 9 dynamically loaded module", 143*9a747e4fSDavid du Colombier FI386, 144*9a747e4fSDavid du Colombier &mi386, 145*9a747e4fSDavid du Colombier sizeof(Exec), 146*9a747e4fSDavid du Colombier beswal, 147*9a747e4fSDavid du Colombier common }, 1483e12c5d1SDavid du Colombier { J_MAGIC, /* I960 6.out (big-endian) */ 1493e12c5d1SDavid du Colombier "960 plan 9 executable", 1503e12c5d1SDavid du Colombier FI960, 1513e12c5d1SDavid du Colombier &mi960, 1523e12c5d1SDavid du Colombier sizeof(Exec), 1533e12c5d1SDavid du Colombier beswal, 1543e12c5d1SDavid du Colombier adotout }, 1553e12c5d1SDavid du Colombier { 0x61010200, /* I960 boot image (little endian) */ 1563e12c5d1SDavid du Colombier "960 plan 9 boot image", 1573e12c5d1SDavid du Colombier FI960B, 1583e12c5d1SDavid du Colombier &mi960, 1593e12c5d1SDavid du Colombier sizeof(struct i960exec), 1603e12c5d1SDavid du Colombier leswal, 1613e12c5d1SDavid du Colombier i960boot }, 162219b2ee8SDavid du Colombier { X_MAGIC, /* 3210 x.out */ 163219b2ee8SDavid du Colombier "3210 plan 9 executable", 164219b2ee8SDavid du Colombier F3210, 165219b2ee8SDavid du Colombier &m3210, 1663e12c5d1SDavid du Colombier sizeof(Exec), 1673e12c5d1SDavid du Colombier beswal, 1683e12c5d1SDavid du Colombier adotout }, 1697dd7cddfSDavid du Colombier { D_MAGIC, /* 29000 9.out */ 1707dd7cddfSDavid du Colombier "29000 plan 9 executable", 1717dd7cddfSDavid du Colombier F29000, 1727dd7cddfSDavid du Colombier &m29000, 1737dd7cddfSDavid du Colombier sizeof(Exec), 1747dd7cddfSDavid du Colombier beswal, 1757dd7cddfSDavid du Colombier adotout }, 176*9a747e4fSDavid du Colombier { Q_MAGIC, /* PowerPC q.out & boot image */ 1777dd7cddfSDavid du Colombier "power plan 9 executable", 1787dd7cddfSDavid du Colombier FPOWER, 1797dd7cddfSDavid du Colombier &mpower, 1807dd7cddfSDavid du Colombier sizeof(Exec), 1817dd7cddfSDavid du Colombier beswal, 1827dd7cddfSDavid du Colombier common }, 1837dd7cddfSDavid du Colombier { ELF_MAG, 1847dd7cddfSDavid du Colombier "Irix 5.X Elf executable", 1857dd7cddfSDavid du Colombier FMIPS, 1867dd7cddfSDavid du Colombier &mmips, 1877dd7cddfSDavid du Colombier sizeof(Ehdr), 1887dd7cddfSDavid du Colombier beswal, 1897dd7cddfSDavid du Colombier elfdotout }, 1907dd7cddfSDavid du Colombier { E_MAGIC, /* Arm 5.out */ 1917dd7cddfSDavid du Colombier "Arm plan 9 executable", 1927dd7cddfSDavid du Colombier FARM, 1937dd7cddfSDavid du Colombier &marm, 1947dd7cddfSDavid du Colombier sizeof(Exec), 1957dd7cddfSDavid du Colombier beswal, 1967dd7cddfSDavid du Colombier common }, 1977dd7cddfSDavid du Colombier { (143<<16)|0413, /* (Free|Net)BSD Arm */ 1987dd7cddfSDavid du Colombier "Arm *BSD executable", 1997dd7cddfSDavid du Colombier FARM, 2007dd7cddfSDavid du Colombier &marm, 2017dd7cddfSDavid du Colombier sizeof(Exec), 2027dd7cddfSDavid du Colombier leswal, 2037dd7cddfSDavid du Colombier armdotout }, 2047dd7cddfSDavid du Colombier { L_MAGIC, /* alpha 7.out */ 2057dd7cddfSDavid du Colombier "alpha plan 9 executable", 2067dd7cddfSDavid du Colombier FALPHA, 2077dd7cddfSDavid du Colombier &malpha, 2087dd7cddfSDavid du Colombier sizeof(Exec), 2097dd7cddfSDavid du Colombier beswal, 2107dd7cddfSDavid du Colombier common }, 2117dd7cddfSDavid du Colombier { 0x0700e0c3, /* alpha boot image */ 2127dd7cddfSDavid du Colombier "alpha plan 9 boot image", 2137dd7cddfSDavid du Colombier FALPHAB, 2147dd7cddfSDavid du Colombier &malpha, 2157dd7cddfSDavid du Colombier sizeof(Exec), 2167dd7cddfSDavid du Colombier beswal, 2177dd7cddfSDavid du Colombier alphadotout }, 2183e12c5d1SDavid du Colombier { 0 }, 2193e12c5d1SDavid du Colombier }; 2203e12c5d1SDavid du Colombier 2217dd7cddfSDavid du Colombier Mach *mach = &mi386; /* Global current machine table */ 2227dd7cddfSDavid du Colombier 2237dd7cddfSDavid du Colombier static ExecTable* 2247dd7cddfSDavid du Colombier couldbe4k(ExecTable *mp) 2257dd7cddfSDavid du Colombier { 226*9a747e4fSDavid du Colombier Dir *d; 2277dd7cddfSDavid du Colombier ExecTable *f; 2287dd7cddfSDavid du Colombier 229*9a747e4fSDavid du Colombier if((d=dirstat("/proc/1/regs")) == nil) 2307dd7cddfSDavid du Colombier return mp; 231*9a747e4fSDavid du Colombier if(d->length < 32*8){ /* R3000 */ 232*9a747e4fSDavid du Colombier free(d); 2337dd7cddfSDavid du Colombier return mp; 234*9a747e4fSDavid du Colombier } 235*9a747e4fSDavid du Colombier free(d); 2367dd7cddfSDavid du Colombier for (f = exectab; f->magic; f++) 2377dd7cddfSDavid du Colombier if(f->magic == M_MAGIC) { 2387dd7cddfSDavid du Colombier f->name = "mips plan 9 executable on mips2 kernel"; 2397dd7cddfSDavid du Colombier return f; 2407dd7cddfSDavid du Colombier } 2417dd7cddfSDavid du Colombier return mp; 2427dd7cddfSDavid du Colombier } 2437dd7cddfSDavid du Colombier 2443e12c5d1SDavid du Colombier 2453e12c5d1SDavid du Colombier int 2463e12c5d1SDavid du Colombier crackhdr(int fd, Fhdr *fp) 2473e12c5d1SDavid du Colombier { 2483e12c5d1SDavid du Colombier ExecTable *mp; 2493e12c5d1SDavid du Colombier ExecHdr d; 2507dd7cddfSDavid du Colombier int nb, magic, ret; 2513e12c5d1SDavid du Colombier 2523e12c5d1SDavid du Colombier fp->type = FNONE; 2537dd7cddfSDavid du Colombier nb = read(fd, (char *)&d.e, sizeof(d.e)); 2547dd7cddfSDavid du Colombier if (nb <= 0) 2553e12c5d1SDavid du Colombier return 0; 2567dd7cddfSDavid du Colombier 2577dd7cddfSDavid du Colombier ret = 0; 2583e12c5d1SDavid du Colombier fp->magic = magic = beswal(d.e.magic); /* big-endian */ 2593e12c5d1SDavid du Colombier for (mp = exectab; mp->magic; mp++) { 2603e12c5d1SDavid du Colombier if (mp->magic == magic && nb >= mp->hsize) { 2617dd7cddfSDavid du Colombier if(mp->magic == V_MAGIC) 2627dd7cddfSDavid du Colombier mp = couldbe4k(mp); 2637dd7cddfSDavid du Colombier 2643e12c5d1SDavid du Colombier hswal((long *) &d, sizeof(d.e)/sizeof(long), mp->swal); 2653e12c5d1SDavid du Colombier fp->type = mp->type; 2663e12c5d1SDavid du Colombier fp->name = mp->name; 267219b2ee8SDavid du Colombier fp->hdrsz = mp->hsize; /* zero on bootables */ 2683e12c5d1SDavid du Colombier mach = mp->mach; 2697dd7cddfSDavid du Colombier ret = mp->hparse(fd, fp, &d); 2703e12c5d1SDavid du Colombier seek(fd, mp->hsize, 0); /* seek to end of header */ 2717dd7cddfSDavid du Colombier break; 2723e12c5d1SDavid du Colombier } 2733e12c5d1SDavid du Colombier } 2747dd7cddfSDavid du Colombier if(mp->magic == 0) 2757dd7cddfSDavid du Colombier werrstr("unknown header type"); 2767dd7cddfSDavid du Colombier return ret; 2773e12c5d1SDavid du Colombier } 2783e12c5d1SDavid du Colombier /* 2793e12c5d1SDavid du Colombier * Convert header to canonical form 2803e12c5d1SDavid du Colombier */ 2813e12c5d1SDavid du Colombier static void 2823e12c5d1SDavid du Colombier hswal(long *lp, int n, long (*swap) (long)) 2833e12c5d1SDavid du Colombier { 2843e12c5d1SDavid du Colombier while (n--) { 2853e12c5d1SDavid du Colombier *lp = (*swap) (*lp); 2863e12c5d1SDavid du Colombier lp++; 2873e12c5d1SDavid du Colombier } 2883e12c5d1SDavid du Colombier } 2893e12c5d1SDavid du Colombier /* 2903e12c5d1SDavid du Colombier * Crack a normal a.out-type header 2913e12c5d1SDavid du Colombier */ 2927dd7cddfSDavid du Colombier static int 2937dd7cddfSDavid du Colombier adotout(int fd, Fhdr *fp, ExecHdr *hp) 2943e12c5d1SDavid du Colombier { 2957dd7cddfSDavid du Colombier long pgsize; 2963e12c5d1SDavid du Colombier 2977dd7cddfSDavid du Colombier USED(fd); 2987dd7cddfSDavid du Colombier pgsize = mach->pgsize; 299219b2ee8SDavid du Colombier settext(fp, hp->e.entry, pgsize+sizeof(Exec), 300219b2ee8SDavid du Colombier hp->e.text, sizeof(Exec)); 301219b2ee8SDavid du Colombier setdata(fp, _round(pgsize+fp->txtsz+sizeof(Exec), pgsize), 302219b2ee8SDavid du Colombier hp->e.data, fp->txtsz+sizeof(Exec), hp->e.bss); 3033e12c5d1SDavid du Colombier setsym(fp, hp->e.syms, hp->e.spsz, hp->e.pcsz, fp->datoff+fp->datsz); 3047dd7cddfSDavid du Colombier return 1; 3053e12c5d1SDavid du Colombier } 3063e12c5d1SDavid du Colombier 3073e12c5d1SDavid du Colombier /* 3083e12c5d1SDavid du Colombier * 68020 2.out and 68020 bootable images 3093e12c5d1SDavid du Colombier * 386I 8.out and 386I bootable images 3107dd7cddfSDavid du Colombier * alpha plan9-style bootable images for axp "headerless" boot 3113e12c5d1SDavid du Colombier * 3123e12c5d1SDavid du Colombier */ 3137dd7cddfSDavid du Colombier static int 3147dd7cddfSDavid du Colombier common(int fd, Fhdr *fp, ExecHdr *hp) 3153e12c5d1SDavid du Colombier { 3167dd7cddfSDavid du Colombier long kbase; 3173e12c5d1SDavid du Colombier 3187dd7cddfSDavid du Colombier adotout(fd, fp, hp); 319*9a747e4fSDavid du Colombier if(hp->e.magic & DYN_MAGIC) { 320*9a747e4fSDavid du Colombier fp->txtaddr = 0; 321*9a747e4fSDavid du Colombier fp->dataddr = fp->txtsz; 322*9a747e4fSDavid du Colombier return 1; 323*9a747e4fSDavid du Colombier } 3247dd7cddfSDavid du Colombier kbase = mach->kbase; 3257dd7cddfSDavid du Colombier if ((fp->entry & kbase) == kbase) { /* Boot image */ 3263e12c5d1SDavid du Colombier switch(fp->type) { 3273e12c5d1SDavid du Colombier case F68020: 3283e12c5d1SDavid du Colombier fp->type = F68020B; 3293e12c5d1SDavid du Colombier fp->name = "68020 plan 9 boot image"; 330219b2ee8SDavid du Colombier fp->hdrsz = 0; /* header stripped */ 3313e12c5d1SDavid du Colombier break; 3323e12c5d1SDavid du Colombier case FI386: 3333e12c5d1SDavid du Colombier fp->type = FI386B; 334219b2ee8SDavid du Colombier fp->txtaddr = sizeof(Exec); 3353e12c5d1SDavid du Colombier fp->name = "386 plan 9 boot image"; 336219b2ee8SDavid du Colombier fp->hdrsz = 0; /* header stripped */ 337219b2ee8SDavid du Colombier fp->dataddr = fp->txtaddr+fp->txtsz; 3383e12c5d1SDavid du Colombier break; 3397dd7cddfSDavid du Colombier case FARM: 34080ee5cbfSDavid du Colombier fp->txtaddr = kbase+0x8010; 3417dd7cddfSDavid du Colombier fp->name = "ARM plan 9 boot image"; 3427dd7cddfSDavid du Colombier fp->hdrsz = 0; /* header stripped */ 3437dd7cddfSDavid du Colombier fp->dataddr = fp->txtaddr+fp->txtsz; 3447dd7cddfSDavid du Colombier return 1; 3457dd7cddfSDavid du Colombier case FALPHA: 3467dd7cddfSDavid du Colombier fp->type = FALPHAB; 3477dd7cddfSDavid du Colombier fp->txtaddr = fp->entry; 348*9a747e4fSDavid du Colombier fp->name = "alpha plan 9 boot image?"; 3497dd7cddfSDavid du Colombier fp->hdrsz = 0; /* header stripped */ 3507dd7cddfSDavid du Colombier fp->dataddr = fp->txtaddr+fp->txtsz; 3517dd7cddfSDavid du Colombier break; 352*9a747e4fSDavid du Colombier case FPOWER: 353*9a747e4fSDavid du Colombier fp->type = FPOWERB; 354*9a747e4fSDavid du Colombier fp->txtaddr = fp->entry; 355*9a747e4fSDavid du Colombier fp->name = "power plan 9 boot image"; 3567dd7cddfSDavid du Colombier fp->hdrsz = 0; /* header stripped */ 357*9a747e4fSDavid du Colombier fp->dataddr = fp->txtaddr+fp->txtsz; 358*9a747e4fSDavid du Colombier break; 3593e12c5d1SDavid du Colombier default: 3603e12c5d1SDavid du Colombier break; 3613e12c5d1SDavid du Colombier } 3623e12c5d1SDavid du Colombier fp->txtaddr |= kbase; 3633e12c5d1SDavid du Colombier fp->entry |= kbase; 3643e12c5d1SDavid du Colombier fp->dataddr |= kbase; 3653e12c5d1SDavid du Colombier } 3667dd7cddfSDavid du Colombier return 1; 3673e12c5d1SDavid du Colombier } 3683e12c5d1SDavid du Colombier 3693e12c5d1SDavid du Colombier /* 3703e12c5d1SDavid du Colombier * mips bootable image. 3713e12c5d1SDavid du Colombier */ 3727dd7cddfSDavid du Colombier static int 3737dd7cddfSDavid du Colombier mipsboot(int fd, Fhdr *fp, ExecHdr *hp) 3743e12c5d1SDavid du Colombier { 3757dd7cddfSDavid du Colombier USED(fd); 3763e12c5d1SDavid du Colombier switch(hp->e.amagic) { 3773e12c5d1SDavid du Colombier default: 3783e12c5d1SDavid du Colombier case 0407: /* some kind of mips */ 3793e12c5d1SDavid du Colombier fp->type = FMIPSB; 3803e12c5d1SDavid du Colombier settext(fp, hp->e.mentry, hp->e.text_start, hp->e.tsize, 3813e12c5d1SDavid du Colombier sizeof(struct mipsexec)+4); 3823e12c5d1SDavid du Colombier setdata(fp, hp->e.data_start, hp->e.dsize, 3833e12c5d1SDavid du Colombier fp->txtoff+hp->e.tsize, hp->e.bsize); 3843e12c5d1SDavid du Colombier break; 3853e12c5d1SDavid du Colombier case 0413: /* some kind of mips */ 3863e12c5d1SDavid du Colombier fp->type = FMIPSB; 3873e12c5d1SDavid du Colombier settext(fp, hp->e.mentry, hp->e.text_start, hp->e.tsize, 0); 3883e12c5d1SDavid du Colombier setdata(fp, hp->e.data_start, hp->e.dsize, hp->e.tsize, 3893e12c5d1SDavid du Colombier hp->e.bsize); 3903e12c5d1SDavid du Colombier break; 3913e12c5d1SDavid du Colombier } 3923e12c5d1SDavid du Colombier setsym(fp, hp->e.nsyms, 0, hp->e.pcsize, hp->e.symptr); 393219b2ee8SDavid du Colombier fp->hdrsz = 0; /* header stripped */ 3947dd7cddfSDavid du Colombier return 1; 3953e12c5d1SDavid du Colombier } 396219b2ee8SDavid du Colombier 3973e12c5d1SDavid du Colombier /* 398219b2ee8SDavid du Colombier * mips4k bootable image. 3993e12c5d1SDavid du Colombier */ 4007dd7cddfSDavid du Colombier static int 4017dd7cddfSDavid du Colombier mips4kboot(int fd, Fhdr *fp, ExecHdr *hp) 4023e12c5d1SDavid du Colombier { 4037dd7cddfSDavid du Colombier USED(fd); 404219b2ee8SDavid du Colombier switch(hp->e.h.amagic) { 405219b2ee8SDavid du Colombier default: 406219b2ee8SDavid du Colombier case 0407: /* some kind of mips */ 407219b2ee8SDavid du Colombier fp->type = FMIPSB; 408219b2ee8SDavid du Colombier settext(fp, hp->e.h.mentry, hp->e.h.text_start, hp->e.h.tsize, 409219b2ee8SDavid du Colombier sizeof(struct mips4kexec)); 410219b2ee8SDavid du Colombier setdata(fp, hp->e.h.data_start, hp->e.h.dsize, 411219b2ee8SDavid du Colombier fp->txtoff+hp->e.h.tsize, hp->e.h.bsize); 412219b2ee8SDavid du Colombier break; 413219b2ee8SDavid du Colombier case 0413: /* some kind of mips */ 414219b2ee8SDavid du Colombier fp->type = FMIPSB; 415219b2ee8SDavid du Colombier settext(fp, hp->e.h.mentry, hp->e.h.text_start, hp->e.h.tsize, 0); 416219b2ee8SDavid du Colombier setdata(fp, hp->e.h.data_start, hp->e.h.dsize, hp->e.h.tsize, 417219b2ee8SDavid du Colombier hp->e.h.bsize); 418219b2ee8SDavid du Colombier break; 4193e12c5d1SDavid du Colombier } 420219b2ee8SDavid du Colombier setsym(fp, hp->e.h.nsyms, 0, hp->e.h.pcsize, hp->e.h.symptr); 421219b2ee8SDavid du Colombier fp->hdrsz = 0; /* header stripped */ 4227dd7cddfSDavid du Colombier return 1; 423219b2ee8SDavid du Colombier } 424219b2ee8SDavid du Colombier 4253e12c5d1SDavid du Colombier /* 4263e12c5d1SDavid du Colombier * sparc bootable image 4273e12c5d1SDavid du Colombier */ 4287dd7cddfSDavid du Colombier static int 4297dd7cddfSDavid du Colombier sparcboot(int fd, Fhdr *fp, ExecHdr *hp) 4303e12c5d1SDavid du Colombier { 4317dd7cddfSDavid du Colombier USED(fd); 4323e12c5d1SDavid du Colombier fp->type = FSPARCB; 4333e12c5d1SDavid du Colombier settext(fp, hp->e.sentry, hp->e.sentry, hp->e.stext, 4343e12c5d1SDavid du Colombier sizeof(struct sparcexec)); 4353e12c5d1SDavid du Colombier setdata(fp, hp->e.sentry+hp->e.stext, hp->e.sdata, 4363e12c5d1SDavid du Colombier fp->txtoff+hp->e.stext, hp->e.sbss); 4373e12c5d1SDavid du Colombier setsym(fp, hp->e.ssyms, 0, hp->e.sdrsize, fp->datoff+hp->e.sdata); 438219b2ee8SDavid du Colombier fp->hdrsz = 0; /* header stripped */ 4397dd7cddfSDavid du Colombier return 1; 4403e12c5d1SDavid du Colombier } 4413e12c5d1SDavid du Colombier 4423e12c5d1SDavid du Colombier /* 4433e12c5d1SDavid du Colombier * next bootable image 4443e12c5d1SDavid du Colombier */ 4457dd7cddfSDavid du Colombier static int 4467dd7cddfSDavid du Colombier nextboot(int fd, Fhdr *fp, ExecHdr *hp) 4473e12c5d1SDavid du Colombier { 4487dd7cddfSDavid du Colombier USED(fd); 4493e12c5d1SDavid du Colombier fp->type = FNEXTB; 4503e12c5d1SDavid du Colombier settext(fp, hp->e.textc.vmaddr, hp->e.textc.vmaddr, 4513e12c5d1SDavid du Colombier hp->e.texts.size, hp->e.texts.offset); 4523e12c5d1SDavid du Colombier setdata(fp, hp->e.datac.vmaddr, hp->e.datas.size, 4533e12c5d1SDavid du Colombier hp->e.datas.offset, hp->e.bsss.size); 4543e12c5d1SDavid du Colombier setsym(fp, hp->e.symc.nsyms, hp->e.symc.spoff, hp->e.symc.pcoff, 4553e12c5d1SDavid du Colombier hp->e.symc.symoff); 456219b2ee8SDavid du Colombier fp->hdrsz = 0; /* header stripped */ 4577dd7cddfSDavid du Colombier return 1; 4583e12c5d1SDavid du Colombier } 4593e12c5d1SDavid du Colombier 4603e12c5d1SDavid du Colombier /* 4613e12c5d1SDavid du Colombier * I960 bootable image 4623e12c5d1SDavid du Colombier */ 4637dd7cddfSDavid du Colombier static int 4647dd7cddfSDavid du Colombier i960boot(int fd, Fhdr *fp, ExecHdr *hp) 4653e12c5d1SDavid du Colombier { 4663e12c5d1SDavid du Colombier /* long n = hp->e.i6comments.fptrlineno-hp->e.i6comments.fptrreloc; */ 4673e12c5d1SDavid du Colombier 4687dd7cddfSDavid du Colombier USED(fd); 4693e12c5d1SDavid du Colombier settext(fp, hp->e.i6entry, hp->e.i6texts.virt, hp->e.i6texts.size, 4703e12c5d1SDavid du Colombier hp->e.i6texts.fptr); 4713e12c5d1SDavid du Colombier setdata(fp, hp->e.i6datas.virt, hp->e.i6datas.size, 4723e12c5d1SDavid du Colombier hp->e.i6datas.fptr, hp->e.i6bsssize); 4733e12c5d1SDavid du Colombier setsym(fp, 0, 0, 0, 0); 4743e12c5d1SDavid du Colombier /*setsym(fp, n, 0, hp->e.i6comments.size-n, hp->e.i6comments.fptr); */ 475219b2ee8SDavid du Colombier fp->hdrsz = 0; /* header stripped */ 4767dd7cddfSDavid du Colombier return 1; 4773e12c5d1SDavid du Colombier } 4783e12c5d1SDavid du Colombier 4797dd7cddfSDavid du Colombier static Shdr* 4807dd7cddfSDavid du Colombier elfsectbyname(int fd, Ehdr *hp, Shdr *sp, char *name) 4817dd7cddfSDavid du Colombier { 4827dd7cddfSDavid du Colombier int i, offset, n; 4837dd7cddfSDavid du Colombier char s[64]; 4847dd7cddfSDavid du Colombier 4857dd7cddfSDavid du Colombier offset = sp[hp->shstrndx].offset; 4867dd7cddfSDavid du Colombier for(i = 1; i < hp->shnum; i++) { 4877dd7cddfSDavid du Colombier seek(fd, offset+sp[i].name, 0); 4887dd7cddfSDavid du Colombier n = read(fd, s, sizeof(s)-1); 4897dd7cddfSDavid du Colombier if(n < 0) 4907dd7cddfSDavid du Colombier continue; 4917dd7cddfSDavid du Colombier s[n] = 0; 4927dd7cddfSDavid du Colombier if(strcmp(s, name) == 0) 4937dd7cddfSDavid du Colombier return &sp[i]; 4947dd7cddfSDavid du Colombier } 4957dd7cddfSDavid du Colombier return 0; 4967dd7cddfSDavid du Colombier } 4977dd7cddfSDavid du Colombier /* 4987dd7cddfSDavid du Colombier * Decode an Irix 5.x ELF header 4997dd7cddfSDavid du Colombier */ 5007dd7cddfSDavid du Colombier static int 5017dd7cddfSDavid du Colombier elfdotout(int fd, Fhdr *fp, ExecHdr *hp) 5027dd7cddfSDavid du Colombier { 5037dd7cddfSDavid du Colombier 5047dd7cddfSDavid du Colombier Ehdr *ep; 5057dd7cddfSDavid du Colombier Shdr *es, *txt, *init, *s; 5067dd7cddfSDavid du Colombier long addr, size, offset, bsize; 5077dd7cddfSDavid du Colombier 5087dd7cddfSDavid du Colombier ep = &hp->e; 5097dd7cddfSDavid du Colombier if(ep->type != 8 || ep->machine != 2 || ep->version != 1) 5107dd7cddfSDavid du Colombier return 0; 5117dd7cddfSDavid du Colombier 5127dd7cddfSDavid du Colombier fp->magic = ELF_MAG; 5137dd7cddfSDavid du Colombier fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15; 5147dd7cddfSDavid du Colombier 5157dd7cddfSDavid du Colombier if(ep->shnum <= 0) { 5167dd7cddfSDavid du Colombier werrstr("no ELF header sections"); 5177dd7cddfSDavid du Colombier return 0; 5187dd7cddfSDavid du Colombier } 5197dd7cddfSDavid du Colombier es = malloc(sizeof(Shdr)*ep->shnum); 5207dd7cddfSDavid du Colombier if(es == 0) 5217dd7cddfSDavid du Colombier return 0; 5227dd7cddfSDavid du Colombier 5237dd7cddfSDavid du Colombier seek(fd, ep->shoff, 0); 5247dd7cddfSDavid du Colombier if(read(fd, es, sizeof(Shdr)*ep->shnum) < 0){ 5257dd7cddfSDavid du Colombier free(es); 5267dd7cddfSDavid du Colombier return 0; 5277dd7cddfSDavid du Colombier } 5287dd7cddfSDavid du Colombier 5297dd7cddfSDavid du Colombier txt = elfsectbyname(fd, ep, es, ".text"); 5307dd7cddfSDavid du Colombier init = elfsectbyname(fd, ep, es, ".init"); 5317dd7cddfSDavid du Colombier if(txt == 0 || init == 0 || init != txt+1) 5327dd7cddfSDavid du Colombier goto bad; 5337dd7cddfSDavid du Colombier if(txt->addr+txt->size != init->addr) 5347dd7cddfSDavid du Colombier goto bad; 5357dd7cddfSDavid du Colombier settext(fp, ep->elfentry, txt->addr, txt->size+init->size, txt->offset); 5367dd7cddfSDavid du Colombier 5377dd7cddfSDavid du Colombier addr = 0; 5387dd7cddfSDavid du Colombier offset = 0; 5397dd7cddfSDavid du Colombier size = 0; 5407dd7cddfSDavid du Colombier s = elfsectbyname(fd, ep, es, ".data"); 5417dd7cddfSDavid du Colombier if(s) { 5427dd7cddfSDavid du Colombier addr = s->addr; 5437dd7cddfSDavid du Colombier size = s->size; 5447dd7cddfSDavid du Colombier offset = s->offset; 5457dd7cddfSDavid du Colombier } 5467dd7cddfSDavid du Colombier 5477dd7cddfSDavid du Colombier s = elfsectbyname(fd, ep, es, ".rodata"); 5487dd7cddfSDavid du Colombier if(s) { 5497dd7cddfSDavid du Colombier if(addr){ 5507dd7cddfSDavid du Colombier if(addr+size != s->addr) 5517dd7cddfSDavid du Colombier goto bad; 5527dd7cddfSDavid du Colombier } else { 5537dd7cddfSDavid du Colombier addr = s->addr; 5547dd7cddfSDavid du Colombier offset = s->offset; 5557dd7cddfSDavid du Colombier } 5567dd7cddfSDavid du Colombier size += s->size; 5577dd7cddfSDavid du Colombier } 5587dd7cddfSDavid du Colombier 5597dd7cddfSDavid du Colombier s = elfsectbyname(fd, ep, es, ".got"); 5607dd7cddfSDavid du Colombier if(s) { 5617dd7cddfSDavid du Colombier if(addr){ 5627dd7cddfSDavid du Colombier if(addr+size != s->addr) 5637dd7cddfSDavid du Colombier goto bad; 5647dd7cddfSDavid du Colombier } else { 5657dd7cddfSDavid du Colombier addr = s->addr; 5667dd7cddfSDavid du Colombier offset = s->offset; 5677dd7cddfSDavid du Colombier } 5687dd7cddfSDavid du Colombier size += s->size; 5697dd7cddfSDavid du Colombier } 5707dd7cddfSDavid du Colombier 5717dd7cddfSDavid du Colombier bsize = 0; 5727dd7cddfSDavid du Colombier s = elfsectbyname(fd, ep, es, ".bss"); 5737dd7cddfSDavid du Colombier if(s) { 5747dd7cddfSDavid du Colombier if(addr){ 5757dd7cddfSDavid du Colombier if(addr+size != s->addr) 5767dd7cddfSDavid du Colombier goto bad; 5777dd7cddfSDavid du Colombier } else { 5787dd7cddfSDavid du Colombier addr = s->addr; 5797dd7cddfSDavid du Colombier offset = s->offset; 5807dd7cddfSDavid du Colombier } 5817dd7cddfSDavid du Colombier bsize = s->size; 5827dd7cddfSDavid du Colombier } 5837dd7cddfSDavid du Colombier 5847dd7cddfSDavid du Colombier if(addr == 0) 5857dd7cddfSDavid du Colombier goto bad; 5867dd7cddfSDavid du Colombier 5877dd7cddfSDavid du Colombier setdata(fp, addr, size, offset, bsize); 5887dd7cddfSDavid du Colombier fp->name = "IRIX Elf a.out executable"; 5897dd7cddfSDavid du Colombier free(es); 5907dd7cddfSDavid du Colombier return 1; 5917dd7cddfSDavid du Colombier bad: 5927dd7cddfSDavid du Colombier free(es); 5937dd7cddfSDavid du Colombier werrstr("ELF sections scrambled"); 5947dd7cddfSDavid du Colombier return 0; 5957dd7cddfSDavid du Colombier } 5967dd7cddfSDavid du Colombier 5977dd7cddfSDavid du Colombier /* 5987dd7cddfSDavid du Colombier * alpha bootable 5997dd7cddfSDavid du Colombier */ 6007dd7cddfSDavid du Colombier static int 6017dd7cddfSDavid du Colombier alphadotout(int fd, Fhdr *fp, ExecHdr *hp) 6027dd7cddfSDavid du Colombier { 6037dd7cddfSDavid du Colombier long kbase; 6047dd7cddfSDavid du Colombier 6057dd7cddfSDavid du Colombier USED(fd); 6067dd7cddfSDavid du Colombier settext(fp, hp->e.entry, sizeof(Exec), hp->e.text, sizeof(Exec)); 6077dd7cddfSDavid du Colombier setdata(fp, fp->txtsz+sizeof(Exec), hp->e.data, fp->txtsz+sizeof(Exec), hp->e.bss); 6087dd7cddfSDavid du Colombier setsym(fp, hp->e.syms, hp->e.spsz, hp->e.pcsz, fp->datoff+fp->datsz); 6097dd7cddfSDavid du Colombier 6107dd7cddfSDavid du Colombier /* 6117dd7cddfSDavid du Colombier * Boot images have some of bits <31:28> set: 6127dd7cddfSDavid du Colombier * 0x80400000 kernel 6137dd7cddfSDavid du Colombier * 0x20000000 secondary bootstrap 6147dd7cddfSDavid du Colombier */ 6157dd7cddfSDavid du Colombier kbase = 0xF0000000; 6167dd7cddfSDavid du Colombier if (fp->entry & kbase) { 6177dd7cddfSDavid du Colombier fp->txtaddr = fp->entry; 6187dd7cddfSDavid du Colombier fp->name = "alpha plan 9 boot image"; 6197dd7cddfSDavid du Colombier fp->hdrsz = 0; /* header stripped */ 6207dd7cddfSDavid du Colombier fp->dataddr = fp->entry+fp->txtsz; 6217dd7cddfSDavid du Colombier } 6227dd7cddfSDavid du Colombier return 1; 6237dd7cddfSDavid du Colombier } 6247dd7cddfSDavid du Colombier 6257dd7cddfSDavid du Colombier /* 6267dd7cddfSDavid du Colombier * (Free|Net)BSD ARM header. 6277dd7cddfSDavid du Colombier */ 6287dd7cddfSDavid du Colombier static int 6297dd7cddfSDavid du Colombier armdotout(int fd, Fhdr *fp, ExecHdr *hp) 6307dd7cddfSDavid du Colombier { 6317dd7cddfSDavid du Colombier long kbase; 6327dd7cddfSDavid du Colombier 6337dd7cddfSDavid du Colombier USED(fd); 6347dd7cddfSDavid du Colombier settext(fp, hp->e.entry, sizeof(Exec), hp->e.text, sizeof(Exec)); 6357dd7cddfSDavid du Colombier setdata(fp, fp->txtsz, hp->e.data, fp->txtsz, hp->e.bss); 6367dd7cddfSDavid du Colombier setsym(fp, hp->e.syms, hp->e.spsz, hp->e.pcsz, fp->datoff+fp->datsz); 6377dd7cddfSDavid du Colombier 6387dd7cddfSDavid du Colombier kbase = 0xF0000000; 6397dd7cddfSDavid du Colombier if ((fp->entry & kbase) == kbase) { /* Boot image */ 6407dd7cddfSDavid du Colombier fp->txtaddr = kbase+sizeof(Exec); 6417dd7cddfSDavid du Colombier fp->name = "ARM *BSD boot image"; 6427dd7cddfSDavid du Colombier fp->hdrsz = 0; /* header stripped */ 6437dd7cddfSDavid du Colombier fp->dataddr = kbase+fp->txtsz; 6447dd7cddfSDavid du Colombier } 6457dd7cddfSDavid du Colombier return 1; 6467dd7cddfSDavid du Colombier } 6473e12c5d1SDavid du Colombier 6483e12c5d1SDavid du Colombier static void 6493e12c5d1SDavid du Colombier settext(Fhdr *fp, long e, long a, long s, long off) 6503e12c5d1SDavid du Colombier { 6513e12c5d1SDavid du Colombier fp->txtaddr = a; 6523e12c5d1SDavid du Colombier fp->entry = e; 6533e12c5d1SDavid du Colombier fp->txtsz = s; 6543e12c5d1SDavid du Colombier fp->txtoff = off; 6553e12c5d1SDavid du Colombier } 6563e12c5d1SDavid du Colombier static void 6573e12c5d1SDavid du Colombier setdata(Fhdr *fp, long a, long s, long off, long bss) 6583e12c5d1SDavid du Colombier { 6593e12c5d1SDavid du Colombier fp->dataddr = a; 6603e12c5d1SDavid du Colombier fp->datsz = s; 6613e12c5d1SDavid du Colombier fp->datoff = off; 6623e12c5d1SDavid du Colombier fp->bsssz = bss; 6633e12c5d1SDavid du Colombier } 6643e12c5d1SDavid du Colombier static void 6653e12c5d1SDavid du Colombier setsym(Fhdr *fp, long sy, long sppc, long lnpc, long symoff) 6663e12c5d1SDavid du Colombier { 6673e12c5d1SDavid du Colombier fp->symsz = sy; 6683e12c5d1SDavid du Colombier fp->symoff = symoff; 6693e12c5d1SDavid du Colombier fp->sppcsz = sppc; 6703e12c5d1SDavid du Colombier fp->sppcoff = fp->symoff+fp->symsz; 6713e12c5d1SDavid du Colombier fp->lnpcsz = lnpc; 6723e12c5d1SDavid du Colombier fp->lnpcoff = fp->sppcoff+fp->sppcsz; 6733e12c5d1SDavid du Colombier } 6743e12c5d1SDavid du Colombier 675219b2ee8SDavid du Colombier 676219b2ee8SDavid du Colombier static long 677219b2ee8SDavid du Colombier _round(long a, long b) 678219b2ee8SDavid du Colombier { 679219b2ee8SDavid du Colombier long w; 680219b2ee8SDavid du Colombier 681219b2ee8SDavid du Colombier w = (a/b)*b; 682219b2ee8SDavid du Colombier if (a!=w) 683219b2ee8SDavid du Colombier w += b; 684219b2ee8SDavid du Colombier return(w); 685219b2ee8SDavid du Colombier } 686