boot.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. #include "u.h"
  2. #include "lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "io.h"
  7. #include "/sys/src/libmach/elf.h"
  8. static uchar elfident[7] = {
  9. '\177', 'E', 'L', 'F', '\1', '\1', '\1'
  10. };
  11. static Ehdr ehdr, rehdr;
  12. static Phdr *phdr;
  13. static int curphdr;
  14. static ulong curoff;
  15. static ulong elftotal;
  16. static long (*swal)(long);
  17. static ushort (*swab)(ushort);
  18. /*
  19. * big-endian short
  20. */
  21. ushort
  22. beswab(ushort s)
  23. {
  24. uchar *p;
  25. p = (uchar*)&s;
  26. return (p[0]<<8) | p[1];
  27. }
  28. /*
  29. * big-endian long
  30. */
  31. long
  32. beswal(long l)
  33. {
  34. uchar *p;
  35. p = (uchar*)&l;
  36. return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
  37. }
  38. /*
  39. * little-endian short
  40. */
  41. ushort
  42. leswab(ushort s)
  43. {
  44. uchar *p;
  45. p = (uchar*)&s;
  46. return (p[1]<<8) | p[0];
  47. }
  48. /*
  49. * little-endian long
  50. */
  51. long
  52. leswal(long l)
  53. {
  54. uchar *p;
  55. p = (uchar*)&l;
  56. return (p[3]<<24) | (p[2]<<16) | (p[1]<<8) | p[0];
  57. }
  58. /*
  59. * Convert header to canonical form
  60. */
  61. static void
  62. hswal(long *lp, int n, long (*swap) (long))
  63. {
  64. while (n--) {
  65. *lp = (*swap) (*lp);
  66. lp++;
  67. }
  68. }
  69. static int
  70. readehdr(Boot *b)
  71. {
  72. int i;
  73. /* bitswap the header according to the DATA format */
  74. if(ehdr.ident[CLASS] != ELFCLASS32) {
  75. print("bad ELF class - not 32 bit\n");
  76. return 0;
  77. }
  78. if(ehdr.ident[DATA] == ELFDATA2LSB) {
  79. swab = leswab;
  80. swal = leswal;
  81. } else if(ehdr.ident[DATA] == ELFDATA2MSB) {
  82. swab = beswab;
  83. swal = beswal;
  84. } else {
  85. print("bad ELF encoding - not big or little endian\n");
  86. return 0;
  87. }
  88. memmove(&rehdr, &ehdr, sizeof(Ehdr));
  89. ehdr.type = swab(ehdr.type);
  90. ehdr.machine = swab(ehdr.machine);
  91. ehdr.version = swal(ehdr.version);
  92. ehdr.elfentry = swal(ehdr.elfentry);
  93. ehdr.phoff = swal(ehdr.phoff);
  94. ehdr.shoff = swal(ehdr.shoff);
  95. ehdr.flags = swal(ehdr.flags);
  96. ehdr.ehsize = swab(ehdr.ehsize);
  97. ehdr.phentsize = swab(ehdr.phentsize);
  98. ehdr.phnum = swab(ehdr.phnum);
  99. ehdr.shentsize = swab(ehdr.shentsize);
  100. ehdr.shnum = swab(ehdr.shnum);
  101. ehdr.shstrndx = swab(ehdr.shstrndx);
  102. if(ehdr.type != EXEC || ehdr.version != CURRENT)
  103. return 0;
  104. if(ehdr.phentsize != sizeof(Phdr))
  105. return 0;
  106. if(debug)
  107. print("readehdr OK entry 0x%lux\n", ehdr.elfentry);
  108. curoff = sizeof(Ehdr);
  109. i = ehdr.phoff+ehdr.phentsize*ehdr.phnum - curoff;
  110. b->state = READPHDR;
  111. b->bp = (char*)malloc(i);
  112. b->wp = b->bp;
  113. b->ep = b->wp + i;
  114. phdr = (Phdr*)(b->bp + ehdr.phoff-sizeof(Ehdr));
  115. if(debug)
  116. print("phdr...");
  117. return 1;
  118. }
  119. static int
  120. nextphdr(Boot *b)
  121. {
  122. Phdr *php;
  123. ulong entry, offset;
  124. char *paddr;
  125. if(debug)
  126. print("readedata %d\n", curphdr);
  127. for(; curphdr < ehdr.phnum; curphdr++){
  128. php = phdr+curphdr;
  129. if(php->type != LOAD)
  130. continue;
  131. offset = php->offset;
  132. paddr = (char*)PADDR(php->paddr);
  133. if(offset < curoff){
  134. /*
  135. * Can't (be bothered to) rewind the
  136. * input, it might be from tftp. If we
  137. * did then we could boot FreeBSD kernels
  138. * too maybe.
  139. */
  140. return 0;
  141. }
  142. if(php->offset > curoff){
  143. b->state = READEPAD;
  144. b->bp = (char*)malloc(offset - curoff);
  145. b->wp = b->bp;
  146. b->ep = b->wp + offset - curoff;
  147. if(debug)
  148. print("nextphdr %lud...\n", offset - curoff);
  149. return 1;
  150. }
  151. b->state = READEDATA;
  152. b->bp = paddr;
  153. b->wp = b->bp;
  154. b->ep = b->wp+php->filesz;
  155. print("%ud+", php->filesz);
  156. elftotal += php->filesz;
  157. if(debug)
  158. print("nextphdr %ud@0x%p\n", php->filesz, paddr);
  159. return 1;
  160. }
  161. if(curphdr != 0){
  162. print("=%lud\n", elftotal);
  163. b->state = TRYBOOT;
  164. entry = ehdr.elfentry & ~0xF0000000;
  165. PLLONG(b->exec.entry, entry);
  166. return 1;
  167. }
  168. return 0;
  169. }
  170. static int
  171. readepad(Boot *b)
  172. {
  173. Phdr *php;
  174. php = phdr+curphdr;
  175. if(debug)
  176. print("readepad %d\n", curphdr);
  177. curoff = php->offset;
  178. return nextphdr(b);
  179. }
  180. static int
  181. readedata(Boot *b)
  182. {
  183. Phdr *php;
  184. php = phdr+curphdr;
  185. if(debug)
  186. print("readedata %d\n", curphdr);
  187. if(php->filesz < php->memsz){
  188. print("%lud", php->memsz-php->filesz);
  189. elftotal += php->memsz-php->filesz;
  190. memset((char*)(PADDR(php->paddr)+php->filesz), 0, php->memsz-php->filesz);
  191. }
  192. curoff = php->offset+php->filesz;
  193. curphdr++;
  194. return nextphdr(b);
  195. }
  196. static int
  197. readphdr(Boot *b)
  198. {
  199. Phdr *php;
  200. php = phdr;
  201. hswal((long*)php, ehdr.phentsize*ehdr.phnum/sizeof(long), swal);
  202. if(debug)
  203. print("phdr curoff %lud vaddr 0x%lux paddr 0x%lux\n",
  204. curoff, php->vaddr, php->paddr);
  205. curoff = ehdr.phoff+ehdr.phentsize*ehdr.phnum;
  206. curphdr = 0;
  207. return nextphdr(b);
  208. }
  209. static int
  210. addbytes(char **dbuf, char *edbuf, char **sbuf, char *esbuf)
  211. {
  212. int n;
  213. n = edbuf - *dbuf;
  214. if(n <= 0)
  215. return 0;
  216. if(n > esbuf - *sbuf)
  217. n = esbuf - *sbuf;
  218. if(n <= 0)
  219. return -1;
  220. memmove(*dbuf, *sbuf, n);
  221. *sbuf += n;
  222. *dbuf += n;
  223. return edbuf - *dbuf;
  224. }
  225. int
  226. bootpass(Boot *b, void *vbuf, int nbuf)
  227. {
  228. char *buf, *ebuf;
  229. Exec *ep;
  230. ulong entry, data, text, bss;
  231. if(b->state == FAILED)
  232. return FAIL;
  233. if(nbuf == 0)
  234. goto Endofinput;
  235. buf = vbuf;
  236. ebuf = buf+nbuf;
  237. while(addbytes(&b->wp, b->ep, &buf, ebuf) == 0) {
  238. switch(b->state) {
  239. case INITKERNEL:
  240. b->state = READEXEC;
  241. b->bp = (char*)&b->exec;
  242. b->wp = b->bp;
  243. b->ep = b->bp+sizeof(Exec);
  244. break;
  245. case READEXEC:
  246. ep = &b->exec;
  247. if(GLLONG(ep->magic) == I_MAGIC) {
  248. b->state = READ9TEXT;
  249. b->bp = (char*)PADDR(GLLONG(ep->entry));
  250. b->wp = b->bp;
  251. b->ep = b->wp+GLLONG(ep->text);
  252. print("%lud", GLLONG(ep->text));
  253. break;
  254. }
  255. /* check for gzipped kernel */
  256. if(b->bp[0] == 0x1F && (uchar)b->bp[1] == 0x8B && b->bp[2] == 0x08) {
  257. b->state = READGZIP;
  258. b->bp = (char*)malloc(1440*1024);
  259. b->wp = b->bp;
  260. b->ep = b->wp + 1440*1024;
  261. memmove(b->bp, &b->exec, sizeof(Exec));
  262. b->wp += sizeof(Exec);
  263. print("gz...");
  264. break;
  265. }
  266. /*
  267. * Check for ELF.
  268. */
  269. if(memcmp(b->bp, elfident, 4) == 0){
  270. b->state = READEHDR;
  271. b->bp = (char*)&ehdr;
  272. b->wp = b->bp;
  273. b->ep = b->wp + sizeof(Ehdr);
  274. memmove(b->bp, &b->exec, sizeof(Exec));
  275. b->wp += sizeof(Exec);
  276. print("elf...");
  277. break;
  278. }
  279. print("bad kernel format\n");
  280. b->state = FAILED;
  281. return FAIL;
  282. case READ9TEXT:
  283. ep = &b->exec;
  284. b->state = READ9DATA;
  285. b->bp = (char*)PGROUND(PADDR(GLLONG(ep->entry))+GLLONG(ep->text));
  286. b->wp = b->bp;
  287. b->ep = b->wp + GLLONG(ep->data);
  288. print("+%ld", GLLONG(ep->data));
  289. break;
  290. case READ9DATA:
  291. ep = &b->exec;
  292. bss = GLLONG(ep->bss);
  293. print("+%ld=%ld\n",
  294. bss, GLLONG(ep->text)+GLLONG(ep->data)+bss);
  295. b->state = TRYBOOT;
  296. return ENOUGH;
  297. case READEHDR:
  298. if(!readehdr(b)){
  299. print("readehdr failed\n");
  300. b->state = FAILED;
  301. return FAIL;
  302. }
  303. break;
  304. case READPHDR:
  305. if(!readphdr(b)){
  306. b->state = FAILED;
  307. return FAIL;
  308. }
  309. break;
  310. case READEPAD:
  311. if(!readepad(b)){
  312. b->state = FAILED;
  313. return FAIL;
  314. }
  315. break;
  316. case READEDATA:
  317. if(!readedata(b)){
  318. b->state = FAILED;
  319. return FAIL;
  320. }
  321. if(b->state == TRYBOOT)
  322. return ENOUGH;
  323. break;
  324. case TRYBOOT:
  325. case READGZIP:
  326. return ENOUGH;
  327. case READ9LOAD:
  328. case INIT9LOAD:
  329. panic("9load");
  330. default:
  331. panic("bootstate");
  332. }
  333. }
  334. return MORE;
  335. Endofinput:
  336. /* end of input */
  337. switch(b->state) {
  338. case INITKERNEL:
  339. case READEXEC:
  340. case READ9TEXT:
  341. case READ9DATA:
  342. case READEHDR:
  343. case READPHDR:
  344. case READEPAD:
  345. case READEDATA:
  346. print("premature EOF\n");
  347. b->state = FAILED;
  348. return FAIL;
  349. case TRYBOOT:
  350. entry = GLLONG(b->exec.entry);
  351. print("entry: 0x%lux\n", entry);
  352. warp9(PADDR(entry));
  353. b->state = FAILED;
  354. return FAIL;
  355. case READGZIP:
  356. ep = &b->exec;
  357. if(b->bp[0] != 0x1F || (uchar)b->bp[1] != 0x8B || b->bp[2] != 0x08)
  358. print("lost magic\n");
  359. print("%ld => ", b->wp - b->bp);
  360. if(gunzip((uchar*)ep, sizeof(*ep), (uchar*)b->bp, b->wp - b->bp) < sizeof(*ep)) {
  361. print("badly compressed kernel\n");
  362. return FAIL;
  363. }
  364. entry = GLLONG(ep->entry);
  365. text = GLLONG(ep->text);
  366. data = GLLONG(ep->data);
  367. bss = GLLONG(ep->bss);
  368. print("%lud+%lud+%lud=%lud\n", text, data, bss, text+data+bss);
  369. if(gunzip((uchar*)PADDR(entry)-sizeof(Exec), sizeof(Exec)+text+data,
  370. (uchar*)b->bp, b->wp-b->bp) < sizeof(Exec)+text+data) {
  371. print("error uncompressing kernel\n");
  372. return FAIL;
  373. }
  374. /* relocate data to start at page boundary */
  375. memmove((void*)PGROUND(PADDR(entry+text)), (void*)(PADDR(entry+text)), data);
  376. print("entry: %lux\n", entry);
  377. warp9(PADDR(entry));
  378. b->state = FAILED;
  379. return FAIL;
  380. case INIT9LOAD:
  381. case READ9LOAD:
  382. panic("end 9load");
  383. default:
  384. panic("bootdone");
  385. }
  386. b->state = FAILED;
  387. return FAIL;
  388. }