diff --git a/arch/x86/archelfboot.c b/arch/x86/archelfboot.c index d9a8314fd8..519272e3df 100644 --- a/arch/x86/archelfboot.c +++ b/arch/x86/archelfboot.c @@ -67,114 +67,14 @@ int elf_check_arch(Elf_ehdr *ehdr) } +/* there used to be lots of complexity here to deal with the fact that this code ran in + * RAM. The code was awesome in its power, incomprehensible to most. + * But this code runs in ROM now, so the complexity went away + */ void jmp_to_elf_entry(void *entry) { -#ifdef NOTYET - extern unsigned char _ram_seg, _eram_seg; - unsigned long lb_start, lb_size; - unsigned long adjusted_boot_notes; - unsigned long type; - - elf_boot_notes.hdr.b_checksum = - compute_ip_checksum(&elf_boot_notes, sizeof(elf_boot_notes)); - - type = 0x0E1FB007; - lb_start = (unsigned long)&_ram_seg; - lb_size = (unsigned long)(&_eram_seg - &_ram_seg); - - adjusted_boot_notes = (unsigned long)&elf_boot_notes; - - printk(BIOS_SPEW, "entry = 0x%08lx\n", (unsigned long)entry); - printk(BIOS_SPEW, "lb_start = 0x%08lx\n", lb_start); - printk(BIOS_SPEW, "lb_size = 0x%08lx\n", lb_size); - printk(BIOS_SPEW, " elf_boot_notes = 0x%08lx\n", (unsigned long)&elf_boot_notes); - printk(BIOS_SPEW, "adjusted_boot_notes = 0x%08lx\n", adjusted_boot_notes); - - /* Jump to kernel */ - __asm__ __volatile__( - " cld \n\t" - /* Save the callee save registers... */ - " pushl %%esi\n\t" - " pushl %%edi\n\t" - " pushl %%ebx\n\t" - /* Save the parameters I was passed */ - " pushl $0\n\t" /* 20 adjust */ - " pushl %0\n\t" /* 16 lb_start */ - " pushl %1\n\t" /* 12 buffer */ - " pushl %2\n\t" /* 8 lb_size */ - " pushl %3\n\t" /* 4 entry */ - " pushl %4\n\t" /* 0 elf_boot_notes */ - /* Compute the adjustment */ - " xorl %%eax, %%eax\n\t" - " subl 16(%%esp), %%eax\n\t" - " addl 12(%%esp), %%eax\n\t" - " addl 8(%%esp), %%eax\n\t" - " movl %%eax, 20(%%esp)\n\t" - /* Place a copy of linuxBIOS in it's new location */ - /* Move ``longs'' the linuxBIOS size is 4 byte aligned */ - " movl 12(%%esp), %%edi\n\t" - " addl 8(%%esp), %%edi\n\t" - " movl 16(%%esp), %%esi\n\t" - " movl 8(%%esp), %%ecx\n\n" - " shrl $2, %%ecx\n\t" - " rep movsl\n\t" - - /* Adjust the stack pointer to point into the new linuxBIOS image */ - " addl 20(%%esp), %%esp\n\t" - /* Adjust the instruction pointer to point into the new linuxBIOS image */ - " movl $1f, %%eax\n\t" - " addl 20(%%esp), %%eax\n\t" - " jmp *%%eax\n\t" - "1: \n\t" - - /* Copy the linuxBIOS bounce buffer over linuxBIOS */ - /* Move ``longs'' the linuxBIOS size is 4 byte aligned */ - " movl 16(%%esp), %%edi\n\t" - " movl 12(%%esp), %%esi\n\t" - " movl 8(%%esp), %%ecx\n\t" - " shrl $2, %%ecx\n\t" - " rep movsl\n\t" - - /* Now jump to the loaded image */ - " movl $0x0E1FB007, %%eax\n\t" - " movl 0(%%esp), %%ebx\n\t" - " call *4(%%esp)\n\t" - - /* The loaded image returned? */ - " cli \n\t" - " cld \n\t" - - /* Copy the saved copy of linuxBIOS where linuxBIOS runs */ - /* Move ``longs'' the linuxBIOS size is 4 byte aligned */ - " movl 16(%%esp), %%edi\n\t" - " movl 12(%%esp), %%esi\n\t" - " addl 8(%%esp), %%esi\n\t" - " movl 8(%%esp), %%ecx\n\t" - " shrl $2, %%ecx\n\t" - " rep movsl\n\t" - - /* Adjust the stack pointer to point into the old linuxBIOS image */ - " subl 20(%%esp), %%esp\n\t" - - /* Adjust the instruction pointer to point into the old linuxBIOS image */ - " movl $1f, %%eax\n\t" - " subl 20(%%esp), %%eax\n\t" - " jmp *%%eax\n\t" - "1: \n\t" - - /* Drop the parameters I was passed */ - " addl $24, %%esp\n\t" - - /* Restore the callee save registers */ - " popl %%ebx\n\t" - " popl %%edi\n\t" - " popl %%esi\n\t" - - :: - "g" (lb_start), "g" (buffer), "g" (lb_size), - "g" (entry), "g"(adjusted_boot_notes) - ); -#endif + int (*v)() = entry; + v(); } diff --git a/lib/newelfboot.c b/lib/newelfboot.c index b6391ccae9..2f88dd0450 100644 --- a/lib/newelfboot.c +++ b/lib/newelfboot.c @@ -53,12 +53,17 @@ static int valid_area(struct lb_memory *mem, return 1; } -static int load_elf_segments(struct lb_memory *mem,Elf_phdr *phdr, int headers) +static int load_elf_segments(struct lb_memory *mem,unsigned char *header, int headers) { + Elf_ehdr *ehdr; + Elf_phdr *phdr; + + ehdr = (Elf_ehdr *)header; + phdr = (Elf_phdr *)(&header[ehdr->e_phoff]); + struct segment *ptr; int i; int size; - unsigned char *header = (unsigned char *) phdr; for(i = 0; i < headers; i++) { struct segment *new; /* Ignore data that I don't need to handle */ @@ -101,21 +106,18 @@ static int load_elf_segments(struct lb_memory *mem,Elf_phdr *phdr, int headers) -int elfload(struct lb_memory *mem, - unsigned char *header, unsigned long header_size) +int elfload(struct lb_memory *mem, unsigned char *header, unsigned long header_size) { Elf_ehdr *ehdr; - Elf_phdr *phdr; void *entry; void (*v)(void); struct verify_callback *cb_chain; ehdr = (Elf_ehdr *)header; entry = (void *)(ehdr->e_entry); - phdr = (Elf_phdr *)(&header[ehdr->e_phoff]); /* Load the segments */ - if (!load_elf_segments(mem, phdr, header_size)) + if (!load_elf_segments(mem, header, header_size)) goto out; printk(BIOS_SPEW, "Loaded segments\n"); @@ -129,9 +131,11 @@ int elfload(struct lb_memory *mem, post_code(0xfe); /* Jump to kernel */ - /* just call it as a function. If it wants to return, it will. */ - v = entry; - v(); + /* most of the time, jmp_to_elf_entry is just a call. But this hook gives us + * a handy way to get architecture-dependent operations done, if needed + * jmp_to_elf_entry is in arch//archelfboot.c + */ + jmp_to_elf_entry(entry); return 1; out: @@ -180,7 +184,7 @@ int elfboot_mem(struct lb_memory *mem, void *where, int size) } printk(BIOS_SPEW, "Try to load at offset 0x%x %d phdr\n", header_offset, ehdr->e_phnum); - result = elfload(mem, header + header_offset , ehdr->e_phnum); + result = elfload(mem, header, ehdr->e_phnum); out: if (!result) {