X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fboot%2Fselfboot.c;h=99b1493ed7c39d0d6ed3db78a7845bb6bf41ed5c;hb=c5fc7db3559e080858461b724251f87be6faa2cd;hp=bedb719808fee2acf924c4bf17c8d621a591c643;hpb=26dd71c2d766f0630216aa5b8055b1f3b1e339ed;p=coreboot.git diff --git a/src/boot/selfboot.c b/src/boot/selfboot.c index bedb71980..99b1493ed 100644 --- a/src/boot/selfboot.c +++ b/src/boot/selfboot.c @@ -18,39 +18,33 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA */ +#include #include -#include +#include #include #include #include -#include -#include #include #include #include #include +#include -#ifndef CONFIG_BIG_ENDIAN -#define ntohl(x) ( ((x&0xff)<<24) | ((x&0xff00)<<8) | \ - ((x&0xff0000) >> 8) | ((x&0xff000000) >> 24) ) -#else -#define ntohl(x) (x) -#endif - -/* Maximum physical address we can use for the coreboot bounce buffer. - */ +/* Maximum physical address we can use for the coreboot bounce buffer. */ #ifndef MAX_ADDR #define MAX_ADDR -1UL #endif +/* from coreboot_ram.ld: */ extern unsigned char _ram_seg; extern unsigned char _eram_seg; +static const unsigned long lb_start = (unsigned long)&_ram_seg; +static const unsigned long lb_end = (unsigned long)&_eram_seg; + struct segment { struct segment *next; struct segment *prev; - struct segment *phdr_next; - struct segment *phdr_prev; unsigned long s_dstaddr; unsigned long s_srcaddr; unsigned long s_memsz; @@ -58,37 +52,7 @@ struct segment { int compression; }; -struct verify_callback { - struct verify_callback *next; - int (*callback)(struct verify_callback *vcb, - Elf_ehdr *ehdr, Elf_phdr *phdr, struct segment *head); - unsigned long desc_offset; - unsigned long desc_addr; -}; - -struct ip_checksum_vcb { - struct verify_callback data; - unsigned short ip_checksum; -}; - -static int selfboot(struct lb_memory *mem, struct cbfs_payload *payload); - -void * cbfs_load_payload(struct lb_memory *lb_mem, const char *name) -{ - struct cbfs_payload *payload; - - payload = (struct cbfs_payload *)cbfs_find_file(name, CBFS_TYPE_PAYLOAD); - if (payload == NULL) - return (void *) -1; - printk_debug("Got a payload\n"); - - selfboot(lb_mem, payload); - printk_emerg("SELFBOOT RETURNED!\n"); - - return (void *) -1; -} - -/* The problem: +/* The problem: * Static executables all want to share the same addresses * in memory because only a few addresses are reliably present on * a machine, and implementing general relocation is hard. @@ -97,16 +61,15 @@ void * cbfs_load_payload(struct lb_memory *lb_mem, const char *name) * - Allocate a buffer the size of the coreboot image plus additional * required space. * - Anything that would overwrite coreboot copy into the lower part of - * the buffer. + * the buffer. * - After loading an ELF image copy coreboot to the top of the buffer. * - Then jump to the loaded image. - * + * * Benefits: * - Nearly arbitrary standalone executables can be loaded. * - Coreboot is preserved, so it can be returned to. * - The implementation is still relatively simple, - * and much simpler then the general case implemented in kexec. - * + * and much simpler than the general case implemented in kexec. */ static unsigned long bounce_size, bounce_buffer; @@ -117,10 +80,12 @@ static void get_bounce_buffer(struct lb_memory *mem, unsigned long req_size) unsigned long mem_entries; unsigned long buffer; int i; - lb_size = (unsigned long)(&_eram_seg - &_ram_seg); - /* Double coreboot size so I have somewhere to place a copy to return to */ + lb_size = lb_end - lb_start; + /* Plus coreboot size so I have somewhere + * to place a copy to return to. + */ lb_size = req_size + lb_size; - mem_entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]); + mem_entries = (mem->size - sizeof(*mem)) / sizeof(mem->map[0]); buffer = 0; for(i = 0; i < mem_entries; i++) { unsigned long mstart, mend; @@ -138,7 +103,7 @@ static void get_bounce_buffer(struct lb_memory *mem, unsigned long req_size) msize = unpack_lb64(mem->map[i].size); mend = mstart + msize; tbuffer = mend - lb_size; - if (tbuffer < buffer) + if (tbuffer < buffer) continue; buffer = tbuffer; } @@ -155,7 +120,8 @@ static int valid_area(struct lb_memory *mem, unsigned long buffer, */ int i; unsigned long end = start + len; - unsigned long mem_entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]); + unsigned long mem_entries = (mem->size - sizeof(*mem)) / + sizeof(mem->map[0]); /* See if I conflict with the bounce buffer */ if (end >= buffer) { @@ -171,37 +137,35 @@ static int valid_area(struct lb_memory *mem, unsigned long buffer, mtype = mem->map[i].type; mstart = unpack_lb64(mem->map[i].start); mend = mstart + unpack_lb64(mem->map[i].size); - if ((mtype == LB_MEM_RAM) && (start < mend) && (end > mstart)) { + if ((mtype == LB_MEM_RAM) && (start >= mstart) && (end < mend)) { break; } - if ((mtype == LB_MEM_TABLE) && (start < mend) && (end > mstart)) { - printk_err("Payload is overwriting Coreboot tables.\n"); + if ((mtype == LB_MEM_TABLE) && (start >= mstart) && (end < mend)) { + printk(BIOS_ERR, "Payload is overwriting coreboot tables.\n"); break; } } if (i == mem_entries) { - printk_err("No matching ram area found for range:\n"); - printk_err(" [0x%016lx, 0x%016lx)\n", start, end); - printk_err("Ram areas\n"); + printk(BIOS_ERR, "No matching ram area found for range:\n"); + printk(BIOS_ERR, " [0x%016lx, 0x%016lx)\n", start, end); + printk(BIOS_ERR, "Ram areas\n"); for(i = 0; i < mem_entries; i++) { uint64_t mstart, mend; uint32_t mtype; mtype = mem->map[i].type; mstart = unpack_lb64(mem->map[i].start); mend = mstart + unpack_lb64(mem->map[i].size); - printk_err(" [0x%016lx, 0x%016lx) %s\n", - (unsigned long)mstart, - (unsigned long)mend, + printk(BIOS_ERR, " [0x%016lx, 0x%016lx) %s\n", + (unsigned long)mstart, + (unsigned long)mend, (mtype == LB_MEM_RAM)?"RAM":"Reserved"); - + } return 0; } return 1; } -static const unsigned long lb_start = (unsigned long)&_ram_seg; -static const unsigned long lb_end = (unsigned long)&_eram_seg; static int overlaps_coreboot(struct segment *seg) { @@ -211,25 +175,28 @@ static int overlaps_coreboot(struct segment *seg) return !((end <= lb_start) || (start >= lb_end)); } -static void relocate_segment(unsigned long buffer, struct segment *seg) +static int relocate_segment(unsigned long buffer, struct segment *seg) { /* Modify all segments that want to load onto coreboot * to load onto the bounce buffer instead. */ - unsigned long start, middle, end; + /* ret: 1 : A new segment is inserted before the seg. + * 0 : A new segment is inserted after the seg, or no new one. + */ + unsigned long start, middle, end, ret = 0; - printk_spew("lb: [0x%016lx, 0x%016lx)\n", + printk(BIOS_SPEW, "lb: [0x%016lx, 0x%016lx)\n", lb_start, lb_end); /* I don't conflict with coreboot so get out of here */ if (!overlaps_coreboot(seg)) - return; + return 0; start = seg->s_dstaddr; middle = start + seg->s_filesz; end = start + seg->s_memsz; - printk_spew("segment: [0x%016lx, 0x%016lx, 0x%016lx)\n", + printk(BIOS_SPEW, "segment: [0x%016lx, 0x%016lx, 0x%016lx)\n", start, middle, end); if (seg->compression == CBFS_COMPRESS_NONE) { @@ -257,23 +224,20 @@ static void relocate_segment(unsigned long buffer, struct segment *seg) new->prev = seg->prev; seg->prev->next = new; seg->prev = new; - /* Order by original program header order */ - new->phdr_next = seg; - new->phdr_prev = seg->phdr_prev; - seg->phdr_prev->phdr_next = new; - seg->phdr_prev = new; /* compute the new value of start */ start = seg->s_dstaddr; - - printk_spew(" early: [0x%016lx, 0x%016lx, 0x%016lx)\n", - new->s_dstaddr, + + printk(BIOS_SPEW, " early: [0x%016lx, 0x%016lx, 0x%016lx)\n", + new->s_dstaddr, new->s_dstaddr + new->s_filesz, new->s_dstaddr + new->s_memsz); + + ret = 1; } - - /* Slice off a piece at the end - * that doesn't conflict with coreboot + + /* Slice off a piece at the end + * that doesn't conflict with coreboot */ if (end > lb_end) { unsigned long len = lb_end - start; @@ -295,35 +259,32 @@ static void relocate_segment(unsigned long buffer, struct segment *seg) new->prev = seg; seg->next->prev = new; seg->next = new; - /* Order by original program header order */ - new->phdr_next = seg->phdr_next; - new->phdr_prev = seg; - seg->phdr_next->phdr_prev = new; - seg->phdr_next = new; - - printk_spew(" late: [0x%016lx, 0x%016lx, 0x%016lx)\n", - new->s_dstaddr, + + printk(BIOS_SPEW, " late: [0x%016lx, 0x%016lx, 0x%016lx)\n", + new->s_dstaddr, new->s_dstaddr + new->s_filesz, new->s_dstaddr + new->s_memsz); } } /* Now retarget this segment onto the bounce buffer */ - /* sort of explanation: the buffer is a 1:1 mapping to coreboot. + /* sort of explanation: the buffer is a 1:1 mapping to coreboot. * so you will make the dstaddr be this buffer, and it will get copied * later to where coreboot lives. */ seg->s_dstaddr = buffer + (seg->s_dstaddr - lb_start); - printk_spew(" bounce: [0x%016lx, 0x%016lx, 0x%016lx)\n", - seg->s_dstaddr, - seg->s_dstaddr + seg->s_filesz, + printk(BIOS_SPEW, " bounce: [0x%016lx, 0x%016lx, 0x%016lx)\n", + seg->s_dstaddr, + seg->s_dstaddr + seg->s_filesz, seg->s_dstaddr + seg->s_memsz); + + return ret; } static int build_self_segment_list( - struct segment *head, + struct segment *head, struct lb_memory *mem, struct cbfs_payload *payload, u32 *entry) { @@ -331,52 +292,53 @@ static int build_self_segment_list( struct segment *ptr; struct cbfs_payload_segment *segment, *first_segment; memset(head, 0, sizeof(*head)); - head->phdr_next = head->phdr_prev = head; head->next = head->prev = head; first_segment = segment = &payload->segments; while(1) { - printk_debug("Loading segment from rom address 0x%p\n", segment); + printk(BIOS_DEBUG, "Loading segment from rom address 0x%p\n", segment); switch(segment->type) { case PAYLOAD_SEGMENT_PARAMS: - printk_debug(" parameter section (skipped)\n"); + printk(BIOS_DEBUG, " parameter section (skipped)\n"); segment++; continue; case PAYLOAD_SEGMENT_CODE: case PAYLOAD_SEGMENT_DATA: - printk_debug(" %s (compression=%x)\n", + printk(BIOS_DEBUG, " %s (compression=%x)\n", segment->type == PAYLOAD_SEGMENT_CODE ? "code" : "data", ntohl(segment->compression)); new = malloc(sizeof(*new)); - new->s_dstaddr = ntohl((u32) segment->load_addr); + new->s_dstaddr = ntohll(segment->load_addr); new->s_memsz = ntohl(segment->mem_len); new->compression = ntohl(segment->compression); - new->s_srcaddr = (u32) ((unsigned char *) first_segment) + ntohl(segment->offset); + new->s_srcaddr = (u32) ((unsigned char *)first_segment) + + ntohl(segment->offset); new->s_filesz = ntohl(segment->len); - printk_debug(" New segment dstaddr 0x%lx memsize 0x%lx srcaddr 0x%lx filesize 0x%lx\n", + printk(BIOS_DEBUG, " New segment dstaddr 0x%lx memsize 0x%lx srcaddr 0x%lx filesize 0x%lx\n", new->s_dstaddr, new->s_memsz, new->s_srcaddr, new->s_filesz); /* Clean up the values */ if (new->s_filesz > new->s_memsz) { new->s_filesz = new->s_memsz; } - printk_debug(" (cleaned up) New segment addr 0x%lx size 0x%lx offset 0x%lx filesize 0x%lx\n", + printk(BIOS_DEBUG, " (cleaned up) New segment addr 0x%lx size 0x%lx offset 0x%lx filesize 0x%lx\n", new->s_dstaddr, new->s_memsz, new->s_srcaddr, new->s_filesz); break; case PAYLOAD_SEGMENT_BSS: - printk_debug(" BSS 0x%p (%d byte)\n", (void *) ntohl((u32) segment->load_addr), - ntohl(segment->mem_len)); + printk(BIOS_DEBUG, " BSS 0x%p (%d byte)\n", (void *) + (intptr_t)ntohll(segment->load_addr), + ntohl(segment->mem_len)); new = malloc(sizeof(*new)); new->s_filesz = 0; - new->s_dstaddr = ntohl((u32) segment->load_addr); + new->s_dstaddr = ntohll(segment->load_addr); new->s_memsz = ntohl(segment->mem_len); break; case PAYLOAD_SEGMENT_ENTRY: - printk_debug(" Entry Point 0x%p\n", (void *) ntohl((u32) segment->load_addr)); - *entry = ntohl((u32) segment->load_addr); + printk(BIOS_DEBUG, " Entry Point 0x%p\n", (void *) ntohl((u32) segment->load_addr)); + *entry = ntohll(segment->load_addr); /* Per definition, a payload always has the entry point * as last segment. Thus, we use the occurence of the * entry point as break condition for the loop. @@ -388,15 +350,16 @@ static int build_self_segment_list( /* We found something that we don't know about. Throw * hands into the sky and run away! */ - printk_emerg("Bad segment type %x\n", segment->type); + printk(BIOS_EMERG, "Bad segment type %x\n", segment->type); return -1; } + /* We have found another CODE, DATA or BSS segment */ segment++; - // FIXME: Explain what this is + /* Find place where to insert our segment */ for(ptr = head->next; ptr != head; ptr = ptr->next) { - if (new->s_srcaddr < ntohl((u32) segment->load_addr)) + if (new->s_srcaddr < ntohll(segment->load_addr)) break; } @@ -405,12 +368,6 @@ static int build_self_segment_list( new->prev = ptr->prev; ptr->prev->next = new; ptr->prev = new; - - /* Order by original program header order */ - new->phdr_next = head; - new->phdr_prev = head->phdr_prev; - head->phdr_prev->phdr_next = new; - head->phdr_prev = new; } return 1; @@ -422,16 +379,17 @@ static int load_self_segments( struct cbfs_payload *payload) { struct segment *ptr; - + unsigned long bounce_high = lb_end; for(ptr = head->next; ptr != head; ptr = ptr->next) { - if (!overlaps_coreboot(ptr)) continue; + if (!overlaps_coreboot(ptr)) + continue; if (ptr->s_dstaddr + ptr->s_memsz > bounce_high) bounce_high = ptr->s_dstaddr + ptr->s_memsz; } get_bounce_buffer(mem, bounce_high - lb_start); if (!bounce_buffer) { - printk_err("Could not find a bounce buffer...\n"); + printk(BIOS_ERR, "Could not find a bounce buffer...\n"); return 0; } for(ptr = head->next; ptr != head; ptr = ptr->next) { @@ -441,20 +399,23 @@ static int load_self_segments( } for(ptr = head->next; ptr != head; ptr = ptr->next) { unsigned char *dest, *src; - printk_debug("Loading Segment: addr: 0x%016lx memsz: 0x%016lx filesz: 0x%016lx\n", + printk(BIOS_DEBUG, "Loading Segment: addr: 0x%016lx memsz: 0x%016lx filesz: 0x%016lx\n", ptr->s_dstaddr, ptr->s_memsz, ptr->s_filesz); - + /* Modify the segment to load onto the bounce_buffer if necessary. */ - relocate_segment(bounce_buffer, ptr); + if (relocate_segment(bounce_buffer, ptr)) { + ptr = (ptr->prev)->prev; + continue; + } - printk_debug("Post relocation: addr: 0x%016lx memsz: 0x%016lx filesz: 0x%016lx\n", + printk(BIOS_DEBUG, "Post relocation: addr: 0x%016lx memsz: 0x%016lx filesz: 0x%016lx\n", ptr->s_dstaddr, ptr->s_memsz, ptr->s_filesz); /* Compute the boundaries of the segment */ dest = (unsigned char *)(ptr->s_dstaddr); src = (unsigned char *)(ptr->s_srcaddr); - + /* Copy data from the initial buffer */ if (ptr->s_filesz) { unsigned char *middle, *end; @@ -462,14 +423,15 @@ static int load_self_segments( len = ptr->s_filesz; switch(ptr->compression) { case CBFS_COMPRESS_LZMA: { - printk_debug("using LZMA\n"); - unsigned long ulzma(unsigned char *src, unsigned char *dst); + printk(BIOS_DEBUG, "using LZMA\n"); len = ulzma(src, dest); + if (!len) /* Decompression Error. */ + return 0; break; } -#if CONFIG_COMPRESSED_PAYLOAD_NRV2B==1 +#if CONFIG_COMPRESSED_PAYLOAD_NRV2B case CBFS_COMPRESS_NRV2B: { - printk_debug("using NRV2B\n"); + printk(BIOS_DEBUG, "using NRV2B\n"); unsigned long unrv2b(u8 *src, u8 *dst, unsigned long *ilen_p); unsigned long tmp; len = unrv2b(src, dest, &tmp); @@ -477,17 +439,17 @@ static int load_self_segments( } #endif case CBFS_COMPRESS_NONE: { - printk_debug("it's not compressed!\n"); + printk(BIOS_DEBUG, "it's not compressed!\n"); memcpy(dest, src, len); break; } default: - printk_info( "CBFS: Unknown compression type %d\n", ptr->compression); + printk(BIOS_INFO, "CBFS: Unknown compression type %d\n", ptr->compression); return -1; } end = dest + ptr->s_memsz; middle = dest + len; - printk_spew("[ 0x%016lx, %016lx, 0x%016lx) <- %016lx\n", + printk(BIOS_SPEW, "[ 0x%08lx, %08lx, 0x%08lx) <- %08lx\n", (unsigned long)dest, (unsigned long)middle, (unsigned long)end, @@ -495,28 +457,28 @@ static int load_self_segments( /* Zero the extra bytes between middle & end */ if (middle < end) { - printk_debug("Clearing Segment: addr: 0x%016lx memsz: 0x%016lx\n", + printk(BIOS_DEBUG, "Clearing Segment: addr: 0x%016lx memsz: 0x%016lx\n", (unsigned long)middle, (unsigned long)(end - middle)); - + /* Zero the extra bytes */ memset(middle, 0, end - middle); } /* Copy the data that's outside the area that shadows coreboot_ram */ - printk_debug("dest %lx, end %lx, bouncebuffer %lx\n", dest, end, bounce_buffer); + printk(BIOS_DEBUG, "dest %p, end %p, bouncebuffer %lx\n", dest, end, bounce_buffer); if ((unsigned long)end > bounce_buffer) { if ((unsigned long)dest < bounce_buffer) { - unsigned long from = dest; - unsigned long to = lb_start-(bounce_buffer-(unsigned long)dest); + unsigned char *from = dest; + unsigned char *to = (unsigned char*)(lb_start-(bounce_buffer-(unsigned long)dest)); unsigned long amount = bounce_buffer-(unsigned long)dest; - printk_debug("move prefix around: from %lx, to %lx, amount: %lx\n", from, to, amount); + printk(BIOS_DEBUG, "move prefix around: from %p, to %p, amount: %lx\n", from, to, amount); memcpy(to, from, amount); } if ((unsigned long)end > bounce_buffer + (lb_end - lb_start)) { unsigned long from = bounce_buffer + (lb_end - lb_start); unsigned long to = lb_end; - unsigned long amount = end - from; - printk_debug("move suffix around: from %lx, to %lx, amount: %lx\n", from, to, amount); - memcpy(to, from, amount); + unsigned long amount = (unsigned long)end - from; + printk(BIOS_DEBUG, "move suffix around: from %lx, to %lx, amount: %lx\n", from, to, amount); + memcpy((char*)to, (char*)from, amount); } } } @@ -537,19 +499,34 @@ static int selfboot(struct lb_memory *mem, struct cbfs_payload *payload) if (!load_self_segments(&head, mem, payload)) goto out; - printk_spew("Loaded segments\n"); + printk(BIOS_SPEW, "Loaded segments\n"); /* Reset to booting from this image as late as possible */ boot_successful(); - printk_debug("Jumping to boot code at %x\n", entry); - post_code(0xfe); + printk(BIOS_DEBUG, "Jumping to boot code at %x\n", entry); + post_code(POST_ENTER_ELF_BOOT); /* Jump to kernel */ jmp_to_elf_entry((void*)entry, bounce_buffer, bounce_size); return 1; - out: +out: return 0; } +void *cbfs_load_payload(struct lb_memory *lb_mem, const char *name) +{ + struct cbfs_payload *payload; + + payload = (struct cbfs_payload *)cbfs_find_file(name, CBFS_TYPE_PAYLOAD); + if (payload == NULL) + return (void *) -1; + printk(BIOS_DEBUG, "Got a payload\n"); + + selfboot(lb_mem, payload); + printk(BIOS_EMERG, "SELFBOOT RETURNED!\n"); + + return (void *) -1; +} +