858 lines · 16.7 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * load kernel into memory */#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"io.h"#include	"ureg.h"#include	"pool.h"#include	"../port/netif.h"#include	"../ip/ip.h"#include	"pxe.h" #include	<a.out.h>#include 	"/sys/src/libmach/elf.h" #undef KADDR#undef PADDR #define KADDR(a)	((void*)((ulong)(a) | KZERO))#define PADDR(a)	((ulong)(a) & ~KSEGM) extern int debug; extern void pagingoff(ulong); static uchar elfident[] = {	'\177', 'E', 'L', 'F',};static Ehdr ehdr, rehdr;static E64hdr e64hdr;static Phdr *phdr;static P64hdr *p64hdr; static int curphdr;static ulong curoff;static ulong elftotal; static uvlong (*swav)(uvlong);static long (*swal)(long);static ushort (*swab)(ushort); /* * big-endian short */ushortbeswab(ushort s){	uchar *p; 	p = (uchar*)&s;	return (p[0]<<8) | p[1];} /* * big-endian long */longbeswal(long l){	uchar *p; 	p = (uchar*)&l;	return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];} /* * big-endian vlong */uvlongbeswav(uvlong v){	uchar *p; 	p = (uchar*)&v;	return ((uvlong)p[0]<<56) | ((uvlong)p[1]<<48) | ((uvlong)p[2]<<40)				  | ((uvlong)p[3]<<32) | ((uvlong)p[4]<<24)				  | ((uvlong)p[5]<<16) | ((uvlong)p[6]<<8)				  | (uvlong)p[7];} /* * little-endian short */ushortleswab(ushort s){	uchar *p; 	p = (uchar*)&s;	return (p[1]<<8) | p[0];} /* * little-endian long */longleswal(long l){	uchar *p; 	p = (uchar*)&l;	return (p[3]<<24) | (p[2]<<16) | (p[1]<<8) | p[0];} /* * little-endian vlong */uvlongleswav(uvlong v){	uchar *p; 	p = (uchar*)&v;	return ((uvlong)p[7]<<56) | ((uvlong)p[6]<<48) | ((uvlong)p[5]<<40)				  | ((uvlong)p[4]<<32) | ((uvlong)p[3]<<24)				  | ((uvlong)p[2]<<16) | ((uvlong)p[1]<<8)				  | (uvlong)p[0];} /* * Convert header to canonical form */static voidhswal(long *lp, int n, long (*swap) (long)){	while (n--) {		*lp = (*swap) (*lp);		lp++;	}} static voidhswav(uvlong *lp, int n, uvlong (*swap)(uvlong)){	while (n--) {		*lp = (*swap)(*lp);		lp++;	}} static intreadehdr(Boot *b){	int i; 	/* bitswap the header according to the DATA format */	if(ehdr.ident[CLASS] != ELFCLASS32) {		print("bad ELF class - not 32 bit\n");		return 0;	}	if(ehdr.ident[DATA] == ELFDATA2LSB) {		swab = leswab;		swal = leswal;	} else if(ehdr.ident[DATA] == ELFDATA2MSB) {		swab = beswab;		swal = beswal;	} else {		print("bad ELF encoding - not big or little endian\n");		return 0;	}	memmove(&rehdr, &ehdr, sizeof(Ehdr));	/* copy; never used */ 	ehdr.type = swab(ehdr.type);	ehdr.machine = swab(ehdr.machine);	ehdr.version = swal(ehdr.version);	ehdr.elfentry = swal(ehdr.elfentry);	ehdr.phoff = swal(ehdr.phoff);	ehdr.shoff = swal(ehdr.shoff);	ehdr.flags = swal(ehdr.flags);	ehdr.ehsize = swab(ehdr.ehsize);	ehdr.phentsize = swab(ehdr.phentsize);	ehdr.phnum = swab(ehdr.phnum);	ehdr.shentsize = swab(ehdr.shentsize);	ehdr.shnum = swab(ehdr.shnum);	ehdr.shstrndx = swab(ehdr.shstrndx);	if(ehdr.type != EXEC || ehdr.version != CURRENT)		return 0;	if(ehdr.phentsize != sizeof(Phdr))		return 0; 	if(debug)		print("readehdr OK entry %#lux\n", ehdr.elfentry); 	curoff = sizeof(Ehdr);	i = ehdr.phoff+ehdr.phentsize*ehdr.phnum - curoff;	b->state = READPHDR;	b->bp = (char*)smalloc(i);	b->wp = b->bp;	b->ep = b->wp + i;	elftotal = 0;	phdr = (Phdr*)(b->bp + ehdr.phoff-sizeof(Ehdr));	if(debug)		print("phdr..."); 	return 1;} static intreade64hdr(Boot *b){	int i; 	/* bitswap the header according to the DATA format */	if(e64hdr.ident[CLASS] != ELFCLASS64) {		print("bad ELF class - not 64 bit\n");		return 0;	}	if(e64hdr.ident[DATA] == ELFDATA2LSB) {		swab = leswab;		swal = leswal;		swav = leswav;	} else if(e64hdr.ident[DATA] == ELFDATA2MSB) {		swab = beswab;		swal = beswal;		swav = beswav;	} else {		print("bad ELF encoding - not big or little endian\n");		return 0;	}//	memmove(&rehdr, &ehdr, sizeof(Ehdr));	/* copy; never used */ 	e64hdr.type = swab(e64hdr.type);	e64hdr.machine = swab(e64hdr.machine);	e64hdr.version = swal(e64hdr.version);	e64hdr.elfentry = swav(e64hdr.elfentry);	e64hdr.phoff = swav(e64hdr.phoff);	e64hdr.shoff = swav(e64hdr.shoff);	e64hdr.flags = swal(e64hdr.flags);	e64hdr.ehsize = swab(e64hdr.ehsize);	e64hdr.phentsize = swab(e64hdr.phentsize);	e64hdr.phnum = swab(e64hdr.phnum);	e64hdr.shentsize = swab(e64hdr.shentsize);	e64hdr.shnum = swab(e64hdr.shnum);	e64hdr.shstrndx = swab(e64hdr.shstrndx);	if(e64hdr.type != EXEC || e64hdr.version != CURRENT)		return 0;	if(e64hdr.phentsize != sizeof(P64hdr))		return 0; 	if(debug)		print("reade64hdr OK entry %#llux\n", e64hdr.elfentry); 	curoff = sizeof(E64hdr);	i = e64hdr.phoff + e64hdr.phentsize*e64hdr.phnum - curoff;	b->state = READ64PHDR;	b->bp = (char*)smalloc(i);	b->wp = b->bp;	b->ep = b->wp + i;	elftotal = 0;	p64hdr = (P64hdr*)(b->bp + e64hdr.phoff-sizeof(E64hdr));	if(debug)		print("p64hdr..."); 	return 1;} static intnextphdr(Boot *b){	Phdr *php;	ulong offset;	char *physaddr; 	if(debug)		print("readedata %d\n", curphdr); 	for(; curphdr < ehdr.phnum; curphdr++){		php = phdr+curphdr;		if(php->type != LOAD)			continue;		offset = php->offset;		physaddr = (char*)KADDR(PADDR(php->paddr));		if(offset < curoff){			/*			 * Can't (be bothered to) rewind the			 * input, it might be from tftp. If we			 * did then we could boot FreeBSD kernels			 * too maybe.			 */			return 0;		}		if(php->offset > curoff){			b->state = READEPAD;			b->bp = (char*)smalloc(offset - curoff);			b->wp = b->bp;			b->ep = b->wp + offset - curoff;			if(debug)				print("nextphdr %lud...\n", offset - curoff);			return 1;		}		b->state = READEDATA;		b->bp = physaddr;		b->wp = b->bp;		b->ep = b->wp+php->filesz;		print("%ud+", php->filesz);		elftotal += php->filesz;		if(debug)			print("nextphdr %ud@%#p\n", php->filesz, physaddr); 		return 1;	} 	if(curphdr != 0){		print("=%lud\n", elftotal);		b->state = TRYEBOOT;		b->entry = ehdr.elfentry;		// PLLONG(b->hdr.entry, b->entry);		return 1;	} 	return 0;} static intnextp64hdr(Boot *b){	P64hdr *php;	uvlong offset;	char *physaddr; 	if(debug)		print("reade64data %d\n", curphdr); 	for(; curphdr < e64hdr.phnum; curphdr++){		php = p64hdr+curphdr;		if(php->type != LOAD)			continue;		offset = php->offset;		physaddr = (char*)KADDR(PADDR(php->paddr));		if(offset < curoff){			/*			 * Can't (be bothered to) rewind the			 * input, it might be from tftp. If we			 * did then we could boot FreeBSD kernels			 * too maybe.			 */			return 0;		}		if(php->offset > curoff){			b->state = READE64PAD;			b->bp = (char*)smalloc(offset - curoff);			b->wp = b->bp;			b->ep = b->wp + offset - curoff;			if(debug)				print("nextp64hdr %llud...\n", offset - curoff);			return 1;		}		b->state = READE64DATA;		b->bp = physaddr;		b->wp = b->bp;		b->ep = b->wp+php->filesz;		print("%llud+", php->filesz);		elftotal += php->filesz;		if(debug)			print("nextp64hdr %llud@%#p\n", php->filesz, physaddr); 		return 1;	} 	if(curphdr != 0){		print("=%lud\n", elftotal);		b->state = TRYE64BOOT;		b->entry = e64hdr.elfentry;		return 1;	} 	return 0;} static intreadepad(Boot *b){	Phdr *php; 	php = phdr+curphdr;	if(debug)		print("readepad %d\n", curphdr);	curoff = php->offset; 	return nextphdr(b);} static intreade64pad(Boot *b){	P64hdr *php; 	php = p64hdr+curphdr;	if(debug)		print("reade64pad %d\n", curphdr);	curoff = php->offset; 	return nextp64hdr(b);} static intreadedata(Boot *b){	Phdr *php; 	php = phdr+curphdr;	if(debug)		print("readedata %d\n", curphdr);	if(php->filesz < php->memsz){		print("%lud",  php->memsz-php->filesz);		elftotal += php->memsz-php->filesz;		memset((char*)KADDR(PADDR(php->paddr)+php->filesz), 0,			php->memsz-php->filesz);	}	curoff = php->offset+php->filesz;	curphdr++; 	return nextphdr(b);} static intreade64data(Boot *b){	P64hdr *php; 	php = p64hdr+curphdr;	if(debug)		print("reade64data %d\n", curphdr);	if(php->filesz < php->memsz){		print("%llud",  php->memsz - php->filesz);		elftotal += php->memsz - php->filesz;		memset((char*)KADDR(PADDR(php->paddr) + php->filesz), 0,			php->memsz - php->filesz);	}	curoff = php->offset + php->filesz;	curphdr++; 	return nextp64hdr(b);} static intreadphdr(Boot *b){	Phdr *php; 	php = phdr;	hswal((long*)php, ehdr.phentsize*ehdr.phnum/sizeof(long), swal);	if(debug)		print("phdr curoff %lud vaddr %#lux paddr %#lux\n",			curoff, php->vaddr, php->paddr); 	curoff = ehdr.phoff+ehdr.phentsize*ehdr.phnum;	curphdr = 0; 	return nextphdr(b);} static intreadp64hdr(Boot *b){	int hdr;	P64hdr *php, *p; 	php = p = p64hdr;	for (hdr = 0; hdr < e64hdr.phnum; hdr++, p++) {		hswal((long*)p, 2, swal);		hswav((uvlong*)&p->offset, 6, swav);	}	if(debug)		print("p64hdr curoff %lud vaddr %#llux paddr %#llux\n",			curoff, php->vaddr, php->paddr); 	curoff = e64hdr.phoff + e64hdr.phentsize*e64hdr.phnum;	curphdr = 0; 	return nextp64hdr(b);} static intaddbytes(char **dbuf, char *edbuf, char **sbuf, char *esbuf){	int n; 	n = edbuf - *dbuf;	if(n <= 0)		return 0;			/* dest buffer is full */	if(n > esbuf - *sbuf)		n = esbuf - *sbuf;	if(n <= 0)		return -1;			/* src buffer is empty */ 	memmove(*dbuf, *sbuf, n);	*sbuf += n;

Lines 1–500 of 858.