10 static uchar hdr[8192];
14 extern char **bootmod;
16 extern char **cmdlinev;
17 extern VgaMode *curmode, textmode;
18 extern uintptr fbaddr, fbsz;
25 return r->type >> 8 & 0xff;
29 pack(void *v, char *fmt, ...)
36 for(; *fmt != 0; fmt++)
39 case 's': PUT16(p, 0, va_arg(va, int)); p += 2; break;
40 case 'i': PUT32(p, 0, va_arg(va, u32int)); p += 4; break;
41 case 'v': PUT64(p, 0, va_arg(va, u64int)); p += 8; break;
42 case 'z': if(elf64) {PUT64(p, 0, va_arg(va, uintptr)); p += 8;} else {PUT32(p, 0, va_arg(va, uintptr)); p += 4;} break;
43 default: sysfatal("pack: unknown fmt character %c", *fmt);
57 for(r = mmap; r != nil; r = r->next){
60 if(gavail(p) < 24) sysfatal("out of guest memory");
61 p = pack(p, "ivvi", 20, (uvlong) r->start, (uvlong)(r->end - r->start), t);
63 return (uchar *) p - p0;
72 if(cmdlinen == 0) return 0;
76 for(i = 0; i < cmdlinen; i++){
77 p = strecpy(p, e, cmdlinev[i]);
78 if(i != cmdlinen - 1) *p++ = ' ';
80 return p - (char*)p0 + 1;
91 if(bootmodn == 0) return 0;
93 q = (uchar*)(p + 4 * bootmodn);
94 for(i = 0; i < bootmodn; i++){
95 q = gptr(-(-gpa(q) & -BY2PG), 1);
96 if(q == nil) sysfatal("out of guest memory");
97 fd = open(bootmod[i], OREAD);
98 if(fd == -1) sysfatal("module open: %r");
100 rc = readn(fd, q, gavail(q));
101 if(rc < 0) sysfatal("module read: %r");
102 if(read(fd, &dummy, 1) == 1) sysfatal("out of guest memory");
110 bootmodn = ((uchar*)p - p0) / 16;
118 u32int header, load, loadend, bssend, entry;
125 for(p = (u32int*)hdr; p < (u32int*)hdr + sizeof(hdr)/4; p++)
128 if(p == (u32int*)hdr + sizeof(hdr)/4)
130 if((u32int)(p[0] + p[1] + p[2]) != 0)
131 sysfatal("invalid multiboot checksum");
133 if((flags & 1<<16) == 0)
134 sysfatal("no size info in multiboot header");
140 filestart = (uchar*)p - hdr - (header - load);
141 gp = gptr(load, bssend != 0 ? bssend - load : loadend != 0 ? loadend - load : BY2PG);
143 sysfatal("kernel image out of bounds");
144 seek(fd, filestart, 0);
146 rc = readn(fd, gp, gavail(gp));
147 if(rc <= 0) sysfatal("readn: %r");
150 rc = readn(fd, gp, loadend - load);
151 if(rc < 0) sysfatal("readn: %r");
152 if(rc < loadend - load) sysfatal("short kernel image");
154 if(bssend == 0) bssend = loadend;
155 bssend = -(-bssend & -BY2PG);
156 p = gptr(bssend, 128);
157 if(p == nil) sysfatal("no space for multiboot structure");
160 p[1] = gavail(gptr(0, 0)) >> 10;
161 if(p[1] > 640) p[1] = 640;
162 p[2] = gavail(gptr(1048576, 0)) >> 10;
163 modp = gptr(bssend + 128, 1);
164 if(modp == nil) sysfatal("out of guest memory");
172 len = putcmdline(modp);
176 modp += len + 7 & -8;
183 modp += len + 7 & -8;
186 if(curmode != nil && curmode != &textmode){
192 for(i = 0; i < 4; i++){
193 n = curmode->chan >> 8*i & 0xf;
195 switch(curmode->chan >> 4 + 8*i & 0xf){
196 case CRed: r = o | n<<8; break;
197 case CGreen: g = o | n<<8; break;
198 case CBlue: b = o | n<<8; break;
203 pack(&p[22], "viiiisss", (u64int)fbaddr,
204 curmode->hbytes, curmode->w, curmode->h,
205 chantodepth(curmode->chan) | 1<<8, r, g, b);
210 rset(RAX, 0x2badb002);
215 typedef struct ELFHeader ELFHeader;
217 uintptr entry, phoff, shoff;
220 u16int phentsize, phnum;
221 u16int shentsize, shnum, shstrndx;
223 typedef struct ELFPHeader ELFPHeader;
226 uintptr offset, vaddr, paddr, filesz, memsz, align;
229 PT_NULL, PT_LOAD, PT_DYNAMIC, PT_INTERP, PT_NOTE,
230 PT_SHLIB, PT_PHDR, PT_TLS,
231 PT_GNU_EH_FRAME = 0x6474e550,
232 PT_GNU_RELRO = 0x6474e552,
233 PT_OPENBSD_RANDOMIZE = 0x65a3dbe6,
235 typedef struct ELFSHeader ELFSHeader;
238 uintptr flags, addr, offset, size;
240 uintptr addralign, entsize;
248 typedef struct ELFSymbol ELFSymbol;
257 static ELFPHeader *ph;
258 static ELFSHeader *sh;
259 static ELFSymbol *sym;
261 static uintptr elfmax;
264 elff(uchar **p, uchar *e, int sz)
271 fprint(2, "out of bounds: %#p > %#p", *p + sz, e);
275 case 1: rc = GET8(*p, 0); break;
276 case 2: rc = GET16(*p, 0); break;
277 case 3: case 4: rc = GET32(*p, 0); break;
278 default: rc = GET64(*p, 0); break;
285 elfheader(ELFHeader *eh, uchar *p, uchar *e)
287 eh->entry = elff(&p, e, -1);
288 eh->phoff = elff(&p, e, -1);
289 eh->shoff = elff(&p, e, -1);
290 eh->flags = elff(&p, e, 4);
291 eh->ehsize = elff(&p, e, 2);
292 eh->phentsize = elff(&p, e, 2);
293 eh->phnum = elff(&p, e, 2);
294 eh->shentsize = elff(&p, e, 2);
295 eh->shnum = elff(&p, e, 2);
296 eh->shstrndx = elff(&p, e, 2);
300 elfpheader(ELFPHeader *ph, uchar *p, uchar *e)
302 ph->type = elff(&p, e, 4);
303 if(elf64) ph->flags = elff(&p, e, 4);
304 ph->offset = elff(&p, e, -1);
305 ph->vaddr = elff(&p, e, -1);
306 ph->paddr = elff(&p, e, -1);
307 ph->filesz = elff(&p, e, -1);
308 ph->memsz = elff(&p, e, -1);
309 if(!elf64) ph->flags = elff(&p, e, 4);
310 ph->align = elff(&p, e, -1);
314 elfsheader(ELFSHeader *sh, uchar *p, uchar *e)
316 sh->iname = elff(&p, e, 4);
317 sh->type = elff(&p, e, 4);
318 sh->flags = elff(&p, e, -1);
319 sh->addr = elff(&p, e, -1);
320 sh->offset = elff(&p, e, -1);
321 sh->size = elff(&p, e, -1);
322 sh->link = elff(&p, e, 4);
323 sh->info = elff(&p, e, 4);
324 sh->addralign = elff(&p, e, -1);
325 sh->entsize = elff(&p, e, -1);
329 elfsymbol(ELFSymbol *s, uchar *p, uchar *e)
331 s->iname = elff(&p, e, 4);
333 s->info = elff(&p, e, 1);
334 s->other = elff(&p, e, 1);
335 s->shndx = elff(&p, e, 2);
336 s->addr = elff(&p, e, -1);
337 s->size = elff(&p, e, -1);
339 s->addr = elff(&p, e, -1);
340 s->size = elff(&p, e, -1);
341 s->info = elff(&p, e, 1);
342 s->other = elff(&p, e, 1);
343 s->shndx = elff(&p, e, 2);
348 epreadn(void *buf, ulong sz, vlong off, char *fn)
352 if(readn(fd, buf, sz) < sz)
353 sysfatal("%s: read: %r", fn);
363 if(GET32(hdr, 0) != 0x464c457f) return 0;
364 if(hdr[5] != 1 || hdr[6] != 1 || hdr[0x14] != 1) return 0;
366 case 1: elf64 = 0; break;
367 case 2: elf64 = 1; if(sizeof(uintptr) == 4) sysfatal("64-bit binaries not supported on 32-bit host"); break;
370 elfheader(&eh, hdr + 0x18, hdr + sizeof(hdr));
371 buf = emalloc(eh.phentsize > eh.shentsize ? eh.phentsize : eh.shentsize);
372 ph = emalloc(sizeof(ELFPHeader) * eh.phnum);
373 for(i = 0; i < eh.phnum; i++){
374 epreadn(buf, eh.phentsize, eh.phoff + i * eh.phentsize, "elfheaders");
375 elfpheader(&ph[i], buf, buf + eh.phentsize);
377 sh = emalloc(sizeof(ELFSHeader) * eh.shnum);
378 for(i = 0; i < eh.shnum; i++){
379 epreadn(buf, eh.shentsize, eh.shoff + i * eh.shentsize, "elfheaders");
380 elfsheader(&sh[i], buf, buf + eh.shentsize);
384 if(eh.shstrndx != 0 && eh.shstrndx < eh.shnum){
385 s = &sh[eh.shstrndx];
386 if(s->type != SHT_STRTAB)
387 sysfatal("elfheaders: section string table is not a string table");
388 buf = emalloc(s->size + 1);
389 epreadn(buf, s->size, s->offset, "elfheaders");
390 for(i = 0; i < eh.shnum; i++){
391 if(sh[i].iname < s->size)
392 sh[i].name = (char *) &buf[sh[i].iname];
405 for(i = 0; i < eh.phnum; i++){
413 sysfatal("elf: dynamically linked");
415 sysfatal("elf: unknown program header type %#ux", (int)ph[i].type);
418 case PT_OPENBSD_RANDOMIZE:
421 v = gptr(ph[i].paddr, ph[i].memsz);
423 sysfatal("invalid address %#p (length=%#p) in elf", (void*)ph[i].paddr, (void*)ph[i].memsz);
424 if(ph[i].type == PT_OPENBSD_RANDOMIZE)
425 genrandom(v, ph[i].memsz);
427 if(ph[i].filesz > ph[i].memsz)
428 sysfatal("elf: header entry shorter in memory than in the file (%#p < %#p)", (void*)ph[i].memsz, (void*)ph[i].filesz);
429 if(ph[i].filesz != 0)
430 epreadn(v, ph[i].filesz, ph[i].offset, "elfdata");
431 if(ph[i].filesz < ph[i].memsz)
432 memset((uchar*)v + ph[i].filesz, 0, ph[i].memsz - ph[i].filesz);
434 if(ph[i].paddr + ph[i].memsz > elfmax)
435 elfmax = ph[i].paddr + ph[i].memsz;
442 ELFSHeader *s, *sy, *st;
449 for(s = sh; s < sh + eh.shnum; s++){
450 if(s->type == SHT_SYMTAB && s->name != nil && strcmp(s->name, ".symtab") == 0)
452 if(s->type == SHT_STRTAB && s->name != nil && strcmp(s->name, ".strtab") == 0)
455 if(sy == nil || st == nil)
457 if(sy->entsize == 0 || (sy->size % sy->entsize) != 0)
458 sysfatal("symbol section: invalid headers");
459 str = emalloc(st->size);
460 epreadn(str, st->size, st->offset, "elfsymbols");
461 buf = emalloc(sy->size);
462 epreadn(buf, sy->size, sy->offset, "elfsymbols");
463 nsym = sy->size / sy->entsize;
464 sym = emalloc(sizeof(ELFSymbol) * nsym);
465 for(i = 0; i < nsym; i++){
466 p = buf + i * sy->entsize;
467 elfsymbol(sym + i, p, p + sy->entsize);
468 if(sym[i].iname < st->size)
469 sym[i].name = &str[sym[i].iname];
480 for(s = sym; s < sym + nsym; s++)
481 if(s->name != nil && strcmp(s->name, n) == 0)
487 symaddr(ELFSymbol *s)
491 if(s == nil) return nil;
492 for(p = ph; p < ph + eh.phnum; p++)
493 if(s->addr >= p->vaddr && s->addr < p->vaddr + p->memsz)
494 return gptr(p->paddr + (s->addr - p->vaddr), s->size);
498 static uchar *obsdarg, *obsdarg0, *obsdargnext;
499 static int obsdarglen;
500 static int obsdconsdev = 12 << 8, obsddbcons = -1, obsdbootdev;
521 void *v, *w, *hdrfix;
527 saddr = elf64 ? 8 : 4;
528 elfmax = -(-elfmax & -saddr);
529 v = gptr(elfmax, eh.ehsize);
531 space: sysfatal("out of space for kernel");
532 epreadn(v, eh.ehsize, 0, "obsdelfload");
533 elfmax += -(-eh.ehsize & -saddr);
534 hdrfix = (uchar*)v + (elf64 ? 0x20 : 0x1c);
536 shentsize = 40 + 24*elf64;
537 v = gptr(elfmax, shentsize * eh.shnum);
538 if(v == nil) goto space;
539 off = shentsize * eh.shnum;
541 off += -(-eh.ehsize & -saddr);
542 for(s = sh; s < sh + eh.shnum; s++)
543 if(s->type == SHT_SYMTAB || s->type == SHT_STRTAB ||
544 s->name != nil && (strcmp(s->name, ".debug_line") == 0 || strcmp(s->name, ".SUNW_ctf") == 0)){
545 w = gptr(elfmax, s->size);
546 if(w == nil) goto space;
547 epreadn(w, s->size, s->offset, "obsdelfload");
548 v = pack(v, "iizzzziizz",
549 s->iname, s->type, s->flags | SHF_ALLOC, (uintptr)0,
550 off, s->size, s->link, s->info, s->addralign, s->entsize);
551 elfmax += -(-s->size & -saddr);
552 off += -(-s->size & -saddr);
554 memset(v, 0, shentsize);
555 v = (uchar*)v + shentsize;
557 pack(hdrfix, "zz......sss", (uintptr)0, -(-eh.ehsize & -saddr), 0, 0, shentsize);
560 #define obsdpack(...) (obsdarg = pack(obsdarg, __VA_ARGS__))
566 PUT32(obsdarg, 0, type);
567 PUT32(obsdarg, 8, 0); /* next */
574 if(obsdarg == obsdarg0 + 12) obsdarg += 4;
575 PUT32(obsdarg0, 4, obsdarg - obsdarg0); /* size */
576 obsdarglen += obsdarg - obsdarg0;
577 PUT32(obsdargnext, 0, gpa(obsdarg0));
578 obsdargnext = obsdarg0 + 8;
586 u32int r, g, b, a, m;
588 if(curmode == nil || curmode == &textmode) return;
589 p = r = g = b = a = 0;
590 for(i = 0; i < 4; i++){
591 s = curmode->chan >> 8 * i & 0xf;
595 switch(curmode->chan >> 4 + 8 * i & 0xf){
596 case CRed: r |= m; break;
597 case CGreen: g |= m; break;
598 case CBlue: b |= m; break;
599 case CAlpha: case CIgnore: a |= m; break;
603 obsdstart(BOOTARG_EFIINFO);
604 obsdpack("vvvviiiiiii", 0ULL, 0ULL, (uvlong)fbaddr, (uvlong)fbsz, curmode->h, curmode->w, curmode->w, r, g, b, a);
614 obsdstart(BOOTARG_MEMMAP);
615 for(r = mmap; r != nil; r = r->next){
618 obsdpack("vvi", (uvlong)r->start, (uvlong)(r->end - r->start), t);
620 obsdpack("vvi", 0ULL, 0ULL, 0);
622 obsdstart(BOOTARG_CONSDEV); obsdpack("iiii", obsdconsdev, -1, -1, 0); obsdend();
623 if(obsddbcons != -1){
624 obsdstart(BOOTARG_DDB); obsdpack("i", obsddbcons); obsdend();
627 obsdstart(BOOTARG_END); obsdend();
631 obsdcmdline(int argc, char **argv)
643 case 'a': howto |= 0x0001; break; /* RB_ASKNAME */
644 case 's': howto |= 0x0002; break; /* RB_SINGLE */
645 case 'd': howto |= 0x0040; break; /* RB_DDB */
646 case 'c': howto |= 0x0400; break; /* RB_CONFIG */
652 if(q == nil) goto usage;
654 if(strcmp(p, "device") == 0){
658 case 'f': obsdbootdev = 2; break;
659 case 's': obsdbootdev = 4; break;
660 case 'c': obsdbootdev = 6; break;
661 case 'r': obsdbootdev = 17; break;
662 case 'v': obsdbootdev = 14; if(*++q != 'n') goto nodev; break;
663 default: nodev: sysfatal("invalid device");
665 if(*++q != 'd') goto nodev;
666 obsdbootdev |= strtoul(++q, &r, 10) << 16;
667 if(r == q || (obsdbootdev & 0xfff00000) != 0) goto nodev;
668 if(*r < 'a' || *r > 'p') goto nodev;
669 obsdbootdev |= *r - 'a' << 8;
670 if(*++r != 0) goto nodev;
671 obsdbootdev |= 0xa0000000;
672 }else if(strcmp(p, "tty") == 0){
673 if(strcmp(q, "com0") == 0)
674 obsdconsdev = 8 << 8;
675 else if(strcmp(q, "com1") == 0)
676 obsdconsdev = 8 << 8 | 1;
677 else if(strcmp(q, "pc0") == 0)
678 obsdconsdev = 12 << 8;
680 sysfatal("tty must be one of com0, com1, pc0");
681 }else if(strcmp(p, "db_console") == 0){
682 if(strcmp(q, "on") == 0)
684 else if(strcmp(q, "off") == 0)
687 sysfatal("db_console must be one of on, off");
692 fprint(2, "openbsd cmdline usage: kernel [-asdc] [var=value ...]\nsupported vars: device tty db_console\n");
693 threadexitsall("usage");
708 howto = obsdcmdline(cmdlinen, cmdlinev);
710 PUT32(v, 4, howto); /* howto */
711 PUT32(v, 8, obsdbootdev); /* bootdev */
712 PUT32(v, 12, 0xa); /* bootapiver */
713 PUT32(v, 16, elfmax); /* esym */
714 PUT32(v, 20, 0); /* extmem */
715 PUT32(v, 24, 0); /* cnvmem */
716 PUT32(v, 32, 0); /* bootargv */
717 obsdarg = gptr(0x10000, 4096);
718 assert(obsdarg != nil);
719 obsdargnext = &v[32]; /* bootargv */
721 assert(obsdarg0 == nil);
722 PUT32(v, 28, obsdarglen); /* bootargc */
724 rset(RPC, (u32int)eh.entry & 0x0fffffff);
733 if(!elfheaders()) return 0;
735 if(!elfsymbols()) return 0;
736 s = symaddr(elfsym("ostype"));
737 if(s != nil && strcmp(s, "OpenBSD") == 0)
743 linuxbootmod(char *fn, void *zp, u32int kend)
752 fd = open(fn, OREAD);
753 if(fd < 0) sysfatal("linux: initrd: open: %r");
755 if(sz < 0) sysfatal("linux: initrd: seek: %r");
756 if(sz == 0) sysfatal("linux: empty initrd");
757 addr = GET32(zp, 0x22c);
758 memend = (1<<20) + gavail(gptr(1<<20, 0));
759 if(addr >= memend) addr = memend - 1;
760 if((addr - (sz - 1) & -4) < kend) sysfatal("linux: no room for initrd");
761 addr = addr - (sz - 1) & -4;
763 if(v == nil) sysfatal("linux: initrd: gptr failed");
765 rc = readn(fd, v, sz);
766 if(rc < 0) sysfatal("linux: initrd: read: %r");
767 if(rc < sz) sysfatal("linux: initrd: short read");
769 PUT32(zp, 0x218, addr);
770 PUT32(zp, 0x21C, sz);
774 linuxscreeninfo(void *zp)
776 extern VgaMode *curmode, textmode;
777 extern uintptr fbaddr, fbsz;
781 extmem = gavail(gptr(1<<20, 0)) >> 10;
782 if(extmem >= 65535) extmem = 65535;
783 PUT16(zp, 0x02, extmem);
785 if(curmode == nil) return;
786 if(curmode == &textmode){
787 PUT8(zp, 0x06, 3); /* mode 3 */
788 PUT8(zp, 0x07, 80); /* 80 cols */
789 PUT8(zp, 0x0e, 25); /* 25 rows */
790 PUT8(zp, 0x0f, 0x22); /* VGA */
791 PUT16(zp, 0x10, 16); /* characters are 16 pixels high */
793 PUT8(zp, 0x0f, 0x23); /* VESA linear framebuffer */
794 PUT16(zp, 0x12, curmode->w);
795 PUT16(zp, 0x14, curmode->h);
796 PUT16(zp, 0x16, chantodepth(curmode->chan));
797 PUT32(zp, 0x18, fbaddr);
798 PUT32(zp, 0x1C, fbsz);
799 PUT16(zp, 0x24, curmode->hbytes);
800 for(i = 0, p = 0; i < 4; i++){
801 s = curmode->chan >> 8 * i & 15;
803 switch(curmode->chan >> 8 * i + 4 & 15){
804 case CRed: PUT16(zp, 0x26, s | p << 8); break;
805 case CGreen: PUT16(zp, 0x28, s | p << 8); break;
806 case CBlue: PUT16(zp, 0x2a, s | p << 8); break;
807 case CAlpha: case CIgnore: PUT16(zp, 0x2c, s | p << 8); ; break;
811 PUT16(zp, 0x34, 1<<0|1<<1|1<<3|1<<4|1<<5|1<<6|1<<7); /* attributes */
821 rset("gdtrbase", base);
822 v = pack(v, "vvvv", 0, 0,
823 GDTBASE(0) | GDTLIM(-1) | GDTRX | GDTG | GDTP | GDT32,
824 GDTBASE(0) | GDTLIM(-1) | GDTRW | GDTG | GDTP | GDT32
826 rset("gdtrlimit", gpa(v) - base - 1);
843 for(r = mmap; r != nil; r = r->next){
846 v = pack(v, "vvi", r->start, r->end - r->start, t);
860 u32int ncmdline, cmdlinemax, syssize, setupsects;
863 if(readn(fd, buf, sizeof(buf)) < 1024) return 0;
864 if(GET16(buf, 0x1FE) != 0xAA55 || GET32(buf, 0x202) != 0x53726448) return 0;
865 version = GET16(buf, 0x206);
867 vmerror("linux: kernel too old (boot protocol version %d.%.2d, needs to be 2.06 or newer)", version >> 8, version & 0xff);
870 loadflags = GET8(buf, 0x211);
871 if((loadflags & 1) == 0){
872 vmerror("linux: zImage is not supported");
875 zp = gptr(0x1000, 0x1000);
876 if(zp == nil) sysfatal("linux: gptr for zeropage failed");
878 memset(zp, 0, 0x1000);
879 memmove(zp + 0x1f1, buf + 0x1f1, 0x202 + GET8(buf, 0x201) - 0x1f1);
880 setupsects = GET8(zp, 0x1F1);
881 if(setupsects == 0) setupsects = 4;
882 syssize = GET32(zp, 0x1F4);
883 cmdlinemax = GET32(zp, 0x238);
885 v = gptr(1<<20, syssize << 4);
886 if(v == nil) sysfatal("linux: not enough room for kernel");
887 epreadn(v, syssize << 4, (setupsects + 1) * 512, "trylinux");
889 v = gptr(0x20000, 1);
890 if(v == nil) sysfatal("linux: gptr for cmdline failed");
891 ncmdline = putcmdline(v);
895 if(ncmdline - 1 > cmdlinemax) sysfatal("linux: cmdline too long (%d > %d)", ncmdline, cmdlinemax);
896 PUT32(zp, 0x228, 0x20000);
901 vmerror("linux: ignoring extra boot modules (only one supported)");
904 linuxbootmod(*bootmod, zp, (1<<20) + (syssize << 4));
908 v = gptr(0x3000, 256);
909 if(v == nil) sysfatal("linux: gptr for gdt failed");
914 PUT16(zp, 0x1FA, 0xffff);
915 PUT8(zp, 0x210, 0xFF); /* bootloader ID */
916 PUT8(zp, 0x211, loadflags | 0x80); /* kernel can use heap */
918 PUT32(zp, 0x224, 0xfe00); /* kernel can use full segment */
919 rset(RPC, GET32(zp, 0x214));
930 fd = open(fn, OREAD);
931 if(fd < 0) sysfatal("open: %r");
932 if(readn(fd, hdr, sizeof(hdr)) <= 0)
933 sysfatal("readn: %r");
940 sysfatal("%s: unknown format", fn);