/* Load the first part the file and check if it's Linux */ static uint32_t load_linux_header(struct linux_header *hdr) { int load_high; uint32_t kern_addr; if (lfile_read(hdr, sizeof *hdr) != sizeof *hdr) { debug("Can't read Linux header\n"); return 0; } if (hdr->boot_sector_magic != 0xaa55) { debug("Not a Linux kernel image\n"); return 0; } /* Linux is found. Print some information */ if (memcmp(hdr->header_magic, "HdrS", 4) != 0) { /* This may be floppy disk image or something. * Perform a simple (incomplete) sanity check. */ if (hdr->setup_sects >= 16 || file_size() - (hdr->setup_sects<<9) >= 512<<10) { debug("This looks like a bootdisk image but not like Linux...\n"); return 0; } printf("Possible very old Linux"); /* This kernel does not even have a protocol version. * Force the value. */ hdr->protocol_version = 0; /* pre-2.00 */ } else printf("Found Linux"); if (hdr->protocol_version >= 0x200 && hdr->kver_addr) { char kver[256]; file_seek(hdr->kver_addr + 0x200); if (lfile_read(kver, sizeof kver) != 0) { kver[255] = 0; printf(" version %s", kver); } } debug(" (protocol %#x)", hdr->protocol_version); load_high = 0; if (hdr->protocol_version >= 0x200) { debug(" (loadflags %#x)", hdr->loadflags); load_high = hdr->loadflags & 1; } if (load_high) { printf(" bzImage"); kern_addr = 0x100000; } else { printf(" zImage or Image"); kern_addr = 0x1000; } printf(".\n"); return kern_addr; }
/* Load 32-bit part of kernel */ static int load_linux_kernel(struct linux_header *hdr, uint32_t kern_addr) { uint32_t kern_offset, kern_size; if (hdr->setup_sects == 0) hdr->setup_sects = 4; kern_offset = (hdr->setup_sects + 1) * 512; file_seek(kern_offset); kern_size = file_size() - kern_offset; debug("offset=%#x addr=%#x size=%#x\n", kern_offset, kern_addr, kern_size); #if 0 if (using_devsize) { printf("Attempt to load up to end of device as kernel; " "specify the image size\n"); return 0; } #endif printf("Loading kernel... "); if (lfile_read(phys_to_virt(kern_addr), kern_size) != kern_size) { printf("Can't read kernel\n"); return 0; } printf("ok\n"); return kern_size; }
static unsigned long process_image_notes(Elf_phdr *phdr, int phnum, unsigned short *sum_ptr, unsigned int offset) { int i; char *buf = NULL; int retval = 0; unsigned long addr, end; Elf_Nhdr *nhdr; const char *name; void *desc; for (i = 0; i < phnum; i++) { if (phdr[i].p_type != PT_NOTE) continue; buf = malloc(phdr[i].p_filesz); file_seek(offset + phdr[i].p_offset); if ((uint64_t)lfile_read(buf, phdr[i].p_filesz) != phdr[i].p_filesz) { printf("Can't read note segment\n"); goto out; } addr = (unsigned long) buf; end = addr + phdr[i].p_filesz; while (addr < end) { nhdr = (Elf_Nhdr *) addr; addr += sizeof(Elf_Nhdr); name = (const char *) addr; addr += (nhdr->n_namesz+3) & ~3; desc = (void *) addr; addr += (nhdr->n_descsz+3) & ~3; if (nhdr->n_namesz==sizeof(ELF_NOTE_BOOT) && memcmp(name, ELF_NOTE_BOOT, sizeof(ELF_NOTE_BOOT))==0) { if (nhdr->n_type == EIN_PROGRAM_NAME) { image_name = calloc(1, nhdr->n_descsz + 1); memcpy(image_name, desc, nhdr->n_descsz); } if (nhdr->n_type == EIN_PROGRAM_VERSION) { image_version = calloc(1, nhdr->n_descsz + 1); memcpy(image_version, desc, nhdr->n_descsz); } if (nhdr->n_type == EIN_PROGRAM_CHECKSUM) { *sum_ptr = *(unsigned short *) desc; debug("Image checksum: %#04x\n", *sum_ptr); /* Where in the file */ retval = phdr[i].p_offset + (unsigned long) desc - (unsigned long) buf; } } } } out: file_close(); if (buf) free(buf); return retval; }
int forth_load(const char *filename) { char magic[2]; unsigned long forthsize; int retval = -1; if (!file_open(filename)) goto out; if (lfile_read(magic, 2) != 2) { debug("Can't read magic header\n"); retval = LOADER_NOT_SUPPORT; goto out; } if (magic[0] != '\\' || magic[1] != ' ') { debug("No forth source image\n"); retval = LOADER_NOT_SUPPORT; goto out; } forthsize = file_size(); forthtext = malloc(forthsize+1); file_seek(0); printk("Loading forth source ..."); if ((unsigned long)lfile_read(forthtext, forthsize) != forthsize) { printk("Can't read forth text\n"); goto out; } forthtext[forthsize]=0; printk("ok\n"); PUSH ( (ucell)forthtext ); PUSH ( (ucell)forthsize ); fword("eval2"); retval=0; out: //if (forthtext) // free(forthtext); return retval; }
static int load_segments(Elf_phdr *phdr, int phnum, unsigned long checksum_offset, unsigned int offset) { unsigned long bytes; //unsigned int start_time, time; int i; bytes = 0; // start_time = currticks(); for (i = 0; i < phnum; i++) { if (phdr[i].p_type != PT_LOAD) continue; debug("segment %d addr:%#llx file:%#llx mem:%#llx ", i, addr_fixup(phdr[i].p_paddr), phdr[i].p_filesz, phdr[i].p_memsz); file_seek(offset + phdr[i].p_offset); debug("loading... "); if ((uint64_t)lfile_read(phys_to_virt(addr_fixup(phdr[i].p_paddr)), phdr[i].p_filesz) != phdr[i].p_filesz) { printf("Can't read program segment %d\n", i); return 0; } bytes += phdr[i].p_filesz; debug("clearing... "); memset(phys_to_virt(addr_fixup(phdr[i].p_paddr) + phdr[i].p_filesz), 0, phdr[i].p_memsz - phdr[i].p_filesz); if (phdr[i].p_offset <= checksum_offset && phdr[i].p_offset + phdr[i].p_filesz >= checksum_offset+2) { debug("clearing checksum... "); memset(phys_to_virt(addr_fixup(phdr[i].p_paddr) + checksum_offset - phdr[i].p_offset), 0, 2); } debug("ok\n"); } // time = currticks() - start_time; //debug("Loaded %lu bytes in %ums (%luKB/s)\n", bytes, time, // time? bytes/time : 0); debug("Loaded %lu bytes \n", bytes); return 1; }
int elf_load(struct sys_info *info, const char *filename, const char *cmdline) { Elf_ehdr ehdr; Elf_phdr *phdr = NULL; unsigned long phdr_size; unsigned long checksum_offset; unsigned short checksum = 0; Elf_Bhdr *boot_notes = NULL; int retval = -1; int image_retval; image_name = image_version = NULL; if (!file_open(filename)) goto out; if (lfile_read(&ehdr, sizeof ehdr) != sizeof ehdr) { debug("Can't read ELF header\n"); retval = LOADER_NOT_SUPPORT; goto out; } if (ehdr.e_ident[EI_MAG0] != ELFMAG0 || ehdr.e_ident[EI_MAG1] != ELFMAG1 || ehdr.e_ident[EI_MAG2] != ELFMAG2 || ehdr.e_ident[EI_MAG3] != ELFMAG3 || ehdr.e_ident[EI_CLASS] != ARCH_ELF_CLASS || ehdr.e_ident[EI_DATA] != ARCH_ELF_DATA || ehdr.e_ident[EI_VERSION] != EV_CURRENT || ehdr.e_type != ET_EXEC || !ARCH_ELF_MACHINE_OK(ehdr.e_machine) || ehdr.e_version != EV_CURRENT || ehdr.e_phentsize != sizeof(Elf_phdr)) { debug("Not a bootable ELF image\n"); retval = LOADER_NOT_SUPPORT; goto out; } phdr_size = ehdr.e_phnum * sizeof *phdr; phdr = malloc(phdr_size); file_seek(ehdr.e_phoff); if (lfile_read(phdr, phdr_size) != phdr_size) { printk("Can't read program header\n"); goto out; } if (!check_mem_ranges(info, phdr, ehdr.e_phnum)) goto out; checksum_offset = process_image_notes(phdr, ehdr.e_phnum, &checksum); printk("Loading %s", image_name ? image_name : "image"); if (image_version) printk(" version %s", image_version); printk("...\n"); if (!load_segments(phdr, ehdr.e_phnum, checksum_offset)) goto out; if (checksum_offset) { if (!verify_image(&ehdr, phdr, ehdr.e_phnum, checksum)) goto out; } boot_notes = build_boot_notes(info, cmdline); //debug("current time: %lu\n", currticks()); debug("entry point is %#x\n", ehdr.e_entry); printk("Jumping to entry point...\n"); image_retval = start_elf(ehdr.e_entry & ADDRMASK, virt_to_phys(boot_notes)); // console_init(); FIXME printk("Image returned with return value %#x\n", image_retval); retval = 0; out: if (phdr) free(phdr); if (boot_notes) free(boot_notes); if (image_name) free(image_name); if (image_version) free(image_version); return retval; }
static int load_initrd(struct linux_header *hdr, struct sys_info *info, uint32_t kern_end, struct linux_params *params, const char *initrd_file) { uint32_t max; uint32_t start, end, size; uint64_t forced; extern char _start[], _end[]; if (!file_open(initrd_file)) { printf("Can't open initrd: %s\n", initrd_file); return -1; } #if 0 if (using_devsize) { printf("Attempt to load up to end of device as initrd; " "specify the image size\n"); return -1; } #endif size = file_size(); /* Find out the kernel's restriction on how high the initrd can be * placed */ if (hdr->protocol_version >= 0x203) max = hdr->initrd_addr_max; else max = 0x38000000; /* Hardcoded value for older kernels */ /* FILO itself is at the top of RAM. (relocated) * So, try putting initrd just below us. */ end = virt_to_phys(_start); if (end > max) end = max; /* If "mem=" option is given, we have to put the initrd within * the specified range. */ if (forced_memsize) { forced = forced_memsize; if (forced > max) forced = max; /* If the "mem=" is lower, it's easy */ if (forced <= end) end = forced; else { /* Otherwise, see if we can put it above us */ if (virt_to_phys(_end) + size <= forced) end = forced; /* Ok */ } } start = end - size; start &= ~0xfff; /* page align */ end = start + size; debug("start=%#x end=%#x\n", start, end); if (start < kern_end) { printf("Initrd is too big to fit in memory\n"); return -1; } printf("Loading initrd... "); if (lfile_read(phys_to_virt(start), size) != size) { printf("Can't read initrd\n"); return -1; } printf("ok\n"); params->initrd_start = start; params->initrd_size = size; return 0; }
int elf_load(struct sys_info *info, const char *filename, const char *cmdline) { Elf_ehdr ehdr; Elf_phdr *phdr = NULL; unsigned long phdr_size; unsigned long checksum_offset; unsigned short checksum = 0; Elf_Bhdr *boot_notes = NULL; int retval = -1; int image_retval; unsigned int offset; image_name = image_version = NULL; if (!file_open(filename)) goto out; for (offset = 0; offset < 16 * 512; offset += 512) { if ((size_t)lfile_read(&ehdr, sizeof ehdr) != sizeof ehdr) { debug("Can't read ELF header\n"); retval = LOADER_NOT_SUPPORT; goto out; } if (ehdr.e_ident[EI_MAG0] == ELFMAG0) break; file_seek(offset); } if (ehdr.e_ident[EI_MAG0] != ELFMAG0 || ehdr.e_ident[EI_MAG1] != ELFMAG1 || ehdr.e_ident[EI_MAG2] != ELFMAG2 || ehdr.e_ident[EI_MAG3] != ELFMAG3 || ehdr.e_ident[EI_CLASS] != ARCH_ELF_CLASS || ehdr.e_ident[EI_DATA] != ARCH_ELF_DATA || ehdr.e_ident[EI_VERSION] != EV_CURRENT || ehdr.e_type != ET_EXEC || !ARCH_ELF_MACHINE_OK(ehdr.e_machine) || ehdr.e_version != EV_CURRENT || ehdr.e_phentsize != sizeof(Elf_phdr)) { debug("Not a bootable ELF image\n"); retval = LOADER_NOT_SUPPORT; goto out; } phdr_size = ehdr.e_phnum * sizeof *phdr; phdr = malloc(phdr_size); file_seek(offset + ehdr.e_phoff); if ((unsigned long)lfile_read(phdr, phdr_size) != phdr_size) { printf("Can't read program header\n"); goto out; } if (!check_mem_ranges(info, phdr, ehdr.e_phnum)) goto out; checksum_offset = process_image_notes(phdr, ehdr.e_phnum, &checksum, offset); printf("Loading %s", image_name ? image_name : "image"); if (image_version) printf(" version %s", image_version); printf("...\n"); if (!load_segments(phdr, ehdr.e_phnum, checksum_offset, offset)) goto out; if (checksum_offset) { if (!verify_image(&ehdr, phdr, ehdr.e_phnum, checksum)) goto out; } boot_notes = build_boot_notes(info, cmdline); //debug("current time: %lu\n", currticks()); debug("entry point is %#llx\n", addr_fixup(ehdr.e_entry)); printf("Jumping to entry point...\n"); #if 0 { extern unsigned int qemu_mem_size; extern char boot_device; void *init_openprom(unsigned long memsize, const char *cmdline, char boot_device); int (*entry)(const void *romvec, int p2, int p3, int p4, int p5); const void *romvec; romvec = init_openprom(qemu_mem_size, cmdline, boot_device); entry = (void *) addr_fixup(ehdr.e_entry); image_retval = entry(romvec, 0, 0, 0, 0); } #else image_retval = start_elf(addr_fixup(ehdr.e_entry), virt_to_phys(boot_notes)); #endif // console_init(); FIXME printf("Image returned with return value %#x\n", image_retval); retval = 0; out: file_close(); if (phdr) free(phdr); if (boot_notes) free(boot_notes); if (image_name) free(image_name); if (image_version) free(image_version); return retval; }