zImage.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:9k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (C) Paul Mackerras 1997.
  3.  *
  4.  * Updates for PPC64 by Todd Inglett, Dave Engebretsen & Peter Bergner.
  5.  *
  6.  * This program is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU General Public License
  8.  * as published by the Free Software Foundation; either version
  9.  * 2 of the License, or (at your option) any later version.
  10.  */
  11. #define __KERNEL__
  12. #include "ppc32-types.h"
  13. #include "zlib.h"
  14. #include <linux/elf.h>
  15. #include <asm/processor.h>
  16. #include <asm/page.h>
  17. #include <asm/bootinfo.h>
  18. void memmove(void *dst, void *im, int len);
  19. extern void *finddevice(const char *);
  20. extern int getprop(void *, const char *, void *, int);
  21. extern void printk(char *fmt, ...);
  22. extern void printf(const char *fmt, ...);
  23. extern int sprintf(char *buf, const char *fmt, ...);
  24. void gunzip(void *, int, unsigned char *, int *);
  25. void *claim(unsigned int, unsigned int, unsigned int);
  26. void flush_cache(void *, unsigned long);
  27. void pause(void);
  28. extern void exit(void);
  29. static struct bi_record *make_bi_recs(unsigned long);
  30. #define RAM_START 0x00000000
  31. #define RAM_END (64<<20)
  32. /* Value picked to match that used by yaboot */
  33. #define PROG_START 0x01400000
  34. char *avail_ram;
  35. char *begin_avail, *end_avail;
  36. char *avail_high;
  37. unsigned int heap_use;
  38. unsigned int heap_max;
  39. extern char _end[];
  40. extern char _vmlinux_start[];
  41. extern char _vmlinux_end[];
  42. extern char _sysmap_start[];
  43. extern char _sysmap_end[];
  44. extern char _initrd_start[];
  45. extern char _initrd_end[];
  46. extern unsigned long vmlinux_filesize;
  47. extern unsigned long vmlinux_memsize;
  48. struct addr_range {
  49. unsigned long addr;
  50. unsigned long size;
  51. unsigned long memsize;
  52. };
  53. struct addr_range vmlinux = {0, 0, 0};
  54. struct addr_range vmlinuz = {0, 0, 0};
  55. struct addr_range sysmap  = {0, 0, 0};
  56. struct addr_range initrd  = {0, 0, 0};
  57. static char scratch[128<<10]; /* 128kB of scratch space for gunzip */
  58. typedef void (*kernel_entry_t)( unsigned long,
  59.                                 unsigned long,
  60.                                 void *,
  61. struct bi_record *);
  62. int (*prom)(void *);
  63. void *chosen_handle;
  64. void *stdin;
  65. void *stdout;
  66. void *stderr;
  67. void
  68. start(unsigned long a1, unsigned long a2, void *promptr)
  69. {
  70. unsigned long i, claim_addr, claim_size;
  71. extern char _start;
  72. struct bi_record *bi_recs;
  73. kernel_entry_t kernel_entry;
  74. Elf64_Ehdr *elf64;
  75. Elf64_Phdr *elf64ph;
  76. prom = (int (*)(void *)) promptr;
  77. chosen_handle = finddevice("/chosen");
  78. if (chosen_handle == (void *) -1)
  79. exit();
  80. if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4)
  81. exit();
  82. stderr = stdout;
  83. if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4)
  84. exit();
  85. printf("zImage starting: loaded at 0x%xnr", (unsigned)&_start);
  86. #if 0
  87. sysmap.size = (unsigned long)(_sysmap_end - _sysmap_start);
  88. sysmap.memsize = sysmap.size;
  89. if ( sysmap.size > 0 ) {
  90. sysmap.addr = (RAM_END - sysmap.size) & ~0xFFF;
  91. claim(sysmap.addr, RAM_END - sysmap.addr, 0);
  92. printf("initial ramdisk moving 0x%lx <- 0x%lx (%lx bytes)nr",
  93.        sysmap.addr, (unsigned long)_sysmap_start, sysmap.size);
  94. memcpy((void *)sysmap.addr, (void *)_sysmap_start, sysmap.size);
  95. }
  96. #endif
  97. initrd.size = (unsigned long)(_initrd_end - _initrd_start);
  98. initrd.memsize = initrd.size;
  99. if ( initrd.size > 0 ) {
  100. initrd.addr = (RAM_END - initrd.size) & ~0xFFF;
  101. a1 = a2 = 0;
  102. claim(initrd.addr, RAM_END - initrd.addr, 0);
  103. printf("initial ramdisk moving 0x%lx <- 0x%lx (%lx bytes)nr",
  104.        initrd.addr, (unsigned long)_initrd_start, initrd.size);
  105. memcpy((void *)initrd.addr, (void *)_initrd_start, initrd.size);
  106. }
  107. vmlinuz.addr = (unsigned long)_vmlinux_start;
  108. vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start);
  109. vmlinux.addr = (unsigned long)(void *)-1;
  110. vmlinux.size = PAGE_ALIGN(vmlinux_filesize);
  111. vmlinux.memsize = vmlinux_memsize;
  112. claim_size = vmlinux.memsize /* PPPBBB: + fudge for bi_recs */;
  113. for(claim_addr = PROG_START; 
  114.     claim_addr <= PROG_START * 8; 
  115.     claim_addr += 0x100000) {
  116. printf("    trying: 0x%08lxnr", claim_addr);
  117. vmlinux.addr = (unsigned long)claim(claim_addr, claim_size, 0);
  118. if ((void *)vmlinux.addr != (void *)-1) break;
  119. }
  120. if ((void *)vmlinux.addr == (void *)-1) {
  121. printf("claim error, can't allocate kernel memorynr");
  122. exit();
  123. }
  124. /* PPPBBB: should kernel always be gziped? */
  125. if (*(unsigned short *)vmlinuz.addr == 0x1f8b) {
  126. avail_ram = scratch;
  127. begin_avail = avail_high = avail_ram;
  128. end_avail = scratch + sizeof(scratch);
  129. printf("gunzipping (0x%lx <- 0x%lx:0x%0lx)...",
  130.        vmlinux.addr, vmlinuz.addr, vmlinuz.addr+vmlinuz.size);
  131. gunzip((void *)vmlinux.addr, vmlinux.size,
  132. (unsigned char *)vmlinuz.addr, (int *)&vmlinuz.size);
  133. printf("done %lu bytesnr", vmlinuz.size);
  134. printf("%u bytes of heap consumed, max in use %unr",
  135.        (unsigned)(avail_high - begin_avail), heap_max);
  136. } else {
  137. memmove((void *)vmlinux.addr,(void *)vmlinuz.addr,vmlinuz.size);
  138. }
  139. /* Skip over the ELF header */
  140. elf64 = (Elf64_Ehdr *)vmlinux.addr;
  141. if ( elf64->e_ident[EI_MAG0]  != ELFMAG0 ||
  142.      elf64->e_ident[EI_MAG1]  != ELFMAG1 ||
  143.      elf64->e_ident[EI_MAG2]  != ELFMAG2 ||
  144.      elf64->e_ident[EI_MAG3]  != ELFMAG3 ||
  145.      elf64->e_ident[EI_CLASS] != ELFCLASS64 ||
  146.      elf64->e_ident[EI_DATA]  != ELFDATA2MSB ||
  147.      elf64->e_type            != ET_EXEC ||
  148.      elf64->e_machine         != EM_PPC64 )
  149. {
  150. printf("Error: not a valid PPC64 ELF file!nr");
  151. exit();
  152. }
  153. elf64ph = (Elf64_Phdr *)((unsigned long)elf64 +
  154. (unsigned long)elf64->e_phoff);
  155. for(i=0; i < (unsigned int)elf64->e_phnum ;i++,elf64ph++) {
  156. if (elf64ph->p_type == PT_LOAD && elf64ph->p_offset != 0)
  157. break;
  158. }
  159. printf("... skipping 0x%lx bytes of ELF headernr",
  160. (unsigned long)elf64ph->p_offset);
  161. vmlinux.addr += (unsigned long)elf64ph->p_offset;
  162. vmlinux.size -= (unsigned long)elf64ph->p_offset;
  163. flush_cache((void *)vmlinux.addr, vmlinux.memsize);
  164. bi_recs = make_bi_recs(vmlinux.addr + vmlinux.memsize);
  165. kernel_entry = (kernel_entry_t)vmlinux.addr;
  166. printf( "kernel:nr"
  167. "        entry addr = 0x%lxnr"
  168. "        a1         = 0x%lx,nr"
  169. "        a2         = 0x%lx,nr"
  170. "        prom       = 0x%lx,nr"
  171. "        bi_recs    = 0x%lx,nr",
  172. (unsigned long)kernel_entry, a1, a2,
  173. (unsigned long)prom, (unsigned long)bi_recs);
  174. kernel_entry( a1, a2, prom, bi_recs );
  175. printf("Error: Linux kernel returned to zImage bootloader!nr");
  176. exit();
  177. }
  178. static struct bi_record *
  179. make_bi_recs(unsigned long addr)
  180. {
  181. struct bi_record *bi_recs;
  182. struct bi_record *rec;
  183. bi_recs = rec = bi_rec_init(addr);
  184. rec = bi_rec_alloc(rec, 2);
  185. rec->tag = BI_FIRST;
  186. /* rec->data[0] = ...; # Written below before return */
  187. /* rec->data[1] = ...; # Written below before return */
  188. rec = bi_rec_alloc_bytes(rec, strlen("chrpboot")+1);
  189. rec->tag = BI_BOOTLOADER_ID;
  190. sprintf( (char *)rec->data, "chrpboot");
  191. rec = bi_rec_alloc(rec, 2);
  192. rec->tag = BI_MACHTYPE;
  193. rec->data[0] = PLATFORM_PSERIES;
  194. rec->data[1] = 1;
  195. if ( initrd.size > 0 ) {
  196. rec = bi_rec_alloc(rec, 2);
  197. rec->tag = BI_INITRD;
  198. rec->data[0] = initrd.addr;
  199. rec->data[1] = initrd.size;
  200. }
  201. if ( sysmap.size > 0 ) {
  202. rec = bi_rec_alloc(rec, 2);
  203. rec->tag = BI_SYSMAP;
  204. rec->data[0] = (unsigned long)sysmap.addr;
  205. rec->data[1] = (unsigned long)sysmap.size;
  206. }
  207. rec = bi_rec_alloc(rec, 1);
  208. rec->tag = BI_LAST;
  209. rec->data[0] = (bi_rec_field)bi_recs;
  210. /* Save the _end_ address of the bi_rec's in the first bi_rec
  211.  * data field for easy access by the kernel.
  212.  */
  213. bi_recs->data[0] = (bi_rec_field)rec;
  214. bi_recs->data[1] = (bi_rec_field)rec + rec->size - (bi_rec_field)bi_recs;
  215. return bi_recs;
  216. }
  217. struct memchunk {
  218. unsigned int size;
  219. unsigned int pad;
  220. struct memchunk *next;
  221. };
  222. static struct memchunk *freechunks;
  223. void *zalloc(void *x, unsigned items, unsigned size)
  224. {
  225. void *p;
  226. struct memchunk **mpp, *mp;
  227. size *= items;
  228. size = _ALIGN(size, sizeof(struct memchunk));
  229. heap_use += size;
  230. if (heap_use > heap_max)
  231. heap_max = heap_use;
  232. for (mpp = &freechunks; (mp = *mpp) != 0; mpp = &mp->next) {
  233. if (mp->size == size) {
  234. *mpp = mp->next;
  235. return mp;
  236. }
  237. }
  238. p = avail_ram;
  239. avail_ram += size;
  240. if (avail_ram > avail_high)
  241. avail_high = avail_ram;
  242. if (avail_ram > end_avail) {
  243. printf("oops... out of memorynr");
  244. pause();
  245. }
  246. return p;
  247. }
  248. void zfree(void *x, void *addr, unsigned nb)
  249. {
  250. struct memchunk *mp = addr;
  251. nb = _ALIGN(nb, sizeof(struct memchunk));
  252. heap_use -= nb;
  253. if (avail_ram == addr + nb) {
  254. avail_ram = addr;
  255. return;
  256. }
  257. mp->size = nb;
  258. mp->next = freechunks;
  259. freechunks = mp;
  260. }
  261. #define HEAD_CRC 2
  262. #define EXTRA_FIELD 4
  263. #define ORIG_NAME 8
  264. #define COMMENT 0x10
  265. #define RESERVED 0xe0
  266. #define DEFLATED 8
  267. void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
  268. {
  269. z_stream s;
  270. int r, i, flags;
  271. /* skip header */
  272. i = 10;
  273. flags = src[3];
  274. if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
  275. printf("bad gzipped datanr");
  276. exit();
  277. }
  278. if ((flags & EXTRA_FIELD) != 0)
  279. i = 12 + src[10] + (src[11] << 8);
  280. if ((flags & ORIG_NAME) != 0)
  281. while (src[i++] != 0)
  282. ;
  283. if ((flags & COMMENT) != 0)
  284. while (src[i++] != 0)
  285. ;
  286. if ((flags & HEAD_CRC) != 0)
  287. i += 2;
  288. if (i >= *lenp) {
  289. printf("gunzip: ran out of data in headernr");
  290. exit();
  291. }
  292. s.zalloc = zalloc;
  293. s.zfree = zfree;
  294. r = inflateInit2(&s, -MAX_WBITS);
  295. if (r != Z_OK) {
  296. printf("inflateInit2 returned %dnr", r);
  297. exit();
  298. }
  299. s.next_in = src + i;
  300. s.avail_in = *lenp - i;
  301. s.next_out = dst;
  302. s.avail_out = dstlen;
  303. r = inflate(&s, Z_FINISH);
  304. if (r != Z_OK && r != Z_STREAM_END) {
  305. printf("inflate returned %d msg: %snr", r, s.msg);
  306. exit();
  307. }
  308. *lenp = s.next_out - (unsigned char *) dst;
  309. inflateEnd(&s);
  310. }