int command_boot(int argc, char *argv[]) { struct preloaded_file *fp; /* * See if the user has specified an explicit kernel to boot. */ if ((argc > 1) && (argv[1][0] != '-')) { /* XXX maybe we should discard everything and start again? */ if (file_findfile(NULL, NULL) != NULL) { command_seterr("can't boot '%s', kernel module already loaded", argv[1]); return(CMD_ERROR); } /* find/load the kernel module */ if (file_loadkernel(argv[1], argc - 2, argv + 2) != 0) return(CMD_ERROR); /* we have consumed all arguments */ argc = 1; } /* * See if there is a kernel module already loaded */ if (file_findfile(NULL, NULL) == NULL) if (loadakernel(0, argc - 1, argv + 1)) /* we have consumed all arguments */ argc = 1; /* * Loaded anything yet? */ if ((fp = file_findfile(NULL, NULL)) == NULL) { command_seterr("no bootable kernel"); return(CMD_ERROR); } /* * If we were given arguments, discard any previous. * XXX should we merge arguments? Hard to DWIM. */ if (argc > 1) { if (fp->f_args != NULL) free(fp->f_args); fp->f_args = unargv(argc - 1, argv + 1); } /* Hook for platform-specific autoloading of modules */ if (archsw.arch_autoload() != 0) return(CMD_ERROR); /* Call the exec handler from the loader matching the kernel */ command_seterr("%s", strerror(file_formats[fp->f_loader]->l_exec(fp))); return(CMD_ERROR); }
static int fdt_setup_fdtp() { struct preloaded_file *bfp; int err; /* * Find the device tree blob. */ bfp = file_findfile(NULL, "dtb"); if (bfp == NULL) { command_errmsg = "no device tree blob loaded"; return (CMD_ERROR); } fdtp = (struct fdt_header *)bfp->f_addr; /* * Validate the blob. */ err = fdt_check_header(fdtp); if (err < 0) { if (err == -FDT_ERR_BADVERSION) sprintf(command_errbuf, "incompatible blob version: %d, should be: %d", fdt_version(fdtp), FDT_LAST_SUPPORTED_VERSION); else sprintf(command_errbuf, "error validating blob: %s", fdt_strerror(err)); return (CMD_ERROR); } return (CMD_OK); }
/* * Load specified KLD. If path is omitted, then try to locate it via * search path. */ int file_loadkernel(char *filename, int argc, char *argv[]) { struct preloaded_file *fp, *last_file; int err; /* * Check if KLD already loaded */ fp = file_findfile(filename, NULL); if (fp) { command_seterr("warning: KLD '%s' already loaded", filename); free(filename); return (0); } for (last_file = preloaded_files; last_file != NULL && last_file->f_next != NULL; last_file = last_file->f_next) ; do { err = file_load(filename, loadaddr, &fp); if (err) break; fp->f_args = unargv(argc, argv); loadaddr = fp->f_addr + fp->f_size; file_insert_tail(fp); /* Add to the list of loaded files */ } while(0); if (err == EFTYPE) command_seterr("don't know how to load module '%s'", filename); if (err && fp) file_discard(fp); free(filename); return (err); }
vm_offset_t md_copymodules(vm_offset_t addr, int kern64) { struct preloaded_file *fp; struct file_metadata *md; uint64_t scratch64; int c; c = addr != 0; /* start with the first module on the list, should be the kernel */ for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { MOD_NAME(addr, fp->f_name, c); /* this field must come first */ MOD_TYPE(addr, fp->f_type, c); if (fp->f_args) MOD_ARGS(addr, fp->f_args, c); if (kern64) { scratch64 = fp->f_addr; MOD_ADDR(addr, scratch64, c); scratch64 = fp->f_size; MOD_SIZE(addr, scratch64, c); } else { MOD_ADDR(addr, fp->f_addr, c); MOD_SIZE(addr, fp->f_size, c); } for (md = fp->f_metadata; md != NULL; md = md->md_next) { if (!(md->md_type & MODINFOMD_NOCOPY)) { MOD_METADATA(addr, md, c); } } } MOD_END(addr, c); return(addr); }
static vm_offset_t bi_copymodules64(vm_offset_t addr) { struct preloaded_file *fp; struct file_metadata *md; int c; u_int64_t v; c = addr != 0; /* start with the first module on the list, should be the kernel */ for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { MOD_NAME(addr, fp->f_name, c); /* this field must come first */ MOD_TYPE(addr, fp->f_type, c); if (fp->f_args) MOD_ARGS(addr, fp->f_args, c); v = fp->f_addr; MOD_ADDR(addr, v, c); v = fp->f_size; MOD_SIZE(addr, v, c); for (md = fp->f_metadata; md != NULL; md = md->md_next) if (!(md->md_type & MODINFOMD_NOCOPY)) MOD_METADATA(addr, md, c); } MOD_END(addr, c); return(addr); }
int fdt_load_dtb_file(const char * filename) { struct preloaded_file *bfp, *oldbfp; int err; debugf("fdt_load_dtb_file(%s)\n", filename); oldbfp = file_findfile(NULL, "dtb"); /* Attempt to load and validate a new dtb from a file. */ if ((bfp = file_loadraw(filename, "dtb")) == NULL) { sprintf(command_errbuf, "failed to load file '%s'", filename); return (1); } if ((err = fdt_load_dtb(bfp->f_addr)) != 0) { file_discard(bfp); return (err); } /* A new dtb was validated, discard any previous file. */ if (oldbfp) file_discard(oldbfp); return (0); }
static int fdt_cmd_addr(int argc, char *argv[]) { struct preloaded_file *fp; struct fdt_header *hdr; const char *addr; char *cp; fdt_to_load = NULL; if (argc > 2) addr = argv[2]; else { sprintf(command_errbuf, "no address specified"); return (CMD_ERROR); } hdr = (struct fdt_header *)strtoul(addr, &cp, 16); if (cp == addr) { sprintf(command_errbuf, "Invalid address: %s", addr); return (CMD_ERROR); } while ((fp = file_findfile(NULL, "dtb")) != NULL) { file_discard(fp); } fdt_to_load = hdr; return (CMD_OK); }
static vm_offset_t max_addr(void) { struct preloaded_file *fp; vm_offset_t addr = 0; for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { if (addr < (fp->f_addr + fp->f_size)) addr = fp->f_addr + fp->f_size; } return (addr); }
int fdt_setup_fdtp() { struct preloaded_file *bfp; vm_offset_t va; debugf("fdt_setup_fdtp()\n"); /* If we already loaded a file, use it. */ if ((bfp = file_findfile(NULL, "dtb")) != NULL) { if (fdt_load_dtb(bfp->f_addr) == 0) { printf("Using DTB from loaded file '%s'.\n", bfp->f_name); return (0); } } /* If we were given the address of a valid blob in memory, use it. */ if (fdt_to_load != NULL) { if (fdt_load_dtb_addr(fdt_to_load) == 0) { printf("Using DTB from memory address 0x%08X.\n", (unsigned int)fdt_to_load); return (0); } } if (fdt_platform_load_dtb() == 0) return (0); /* If there is a dtb compiled into the kernel, use it. */ if ((va = fdt_find_static_dtb()) != 0) { if (fdt_load_dtb(va) == 0) { printf("Using DTB compiled into kernel.\n"); return (0); } } command_errmsg = "No device tree blob found!\n"; return (1); }
void ficlFindfile(FICL_VM *pVM) { #ifndef TESTMAIN char *name; #endif char *type, *namep, *typep; struct preloaded_file* fp; int names, types; #if FICL_ROBUST > 1 vmCheckStack(pVM, 4, 1); #endif types = stackPopINT(pVM->pStack); typep = (char*) stackPopPtr(pVM->pStack); names = stackPopINT(pVM->pStack); namep = (char*) stackPopPtr(pVM->pStack); #ifndef TESTMAIN name = (char*) ficlMalloc(names+1); if (!name) vmThrowErr(pVM, "Error: out of memory"); strncpy(name, namep, names); name[names] = '\0'; type = (char*) ficlMalloc(types+1); if (!type) vmThrowErr(pVM, "Error: out of memory"); strncpy(type, typep, types); type[types] = '\0'; fp = file_findfile(name, type); #else fp = NULL; #endif stackPushPtr(pVM->pStack, fp); return; }
vm_offset_t bi_copymodules(vm_offset_t addr) { struct preloaded_file *fp; struct file_metadata *md; /* Start with the first module on the list, should be the kernel. */ for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { /* The name field must come first. */ MOD_NAME(addr, fp->f_name); MOD_TYPE(addr, fp->f_type); if (fp->f_args) MOD_ARGS(addr, fp->f_args); MOD_ADDR(addr, fp->f_addr); MOD_SIZE(addr, fp->f_size); for (md = fp->f_metadata; md != NULL; md = md->md_next) { if (!(md->md_type & MODINFOMD_NOCOPY)) MOD_METADATA(addr, md); } } MOD_END(addr); return(addr); }
static vm_offset_t fdt_find_static_dtb(void) { Elf_Sym sym; vm_offset_t dyntab, esym; uint64_t offs; struct preloaded_file *kfp; struct file_metadata *md; Elf_Sym *symtab; Elf_Dyn *dyn; char *strtab, *strp; int i, sym_count; symtab = NULL; dyntab = esym = 0; strtab = strp = NULL; offs = __elfN(relocation_offset); kfp = file_findfile(NULL, NULL); if (kfp == NULL) return (0); md = file_findmetadata(kfp, MODINFOMD_ESYM); if (md == NULL) return (0); COPYOUT(md->md_data, &esym, sizeof(esym)); md = file_findmetadata(kfp, MODINFOMD_DYNAMIC); if (md == NULL) return (0); COPYOUT(md->md_data, &dyntab, sizeof(dyntab)); dyntab += offs; /* Locate STRTAB and DYNTAB */ for (dyn = (Elf_Dyn *)dyntab; dyn->d_tag != DT_NULL; dyn++) { if (dyn->d_tag == DT_STRTAB) { strtab = (char *)(uintptr_t)(dyn->d_un.d_ptr + offs); continue; } else if (dyn->d_tag == DT_SYMTAB) { symtab = (Elf_Sym *)(uintptr_t) (dyn->d_un.d_ptr + offs); continue; } } if (symtab == NULL || strtab == NULL) { /* * No symtab? No strtab? That should not happen here, * and should have been verified during __elfN(loadimage). * This must be some kind of a bug. */ return (0); } sym_count = (int)((Elf_Sym *)esym - symtab) / sizeof(Elf_Sym); /* * The most efficent way to find a symbol would be to calculate a * hash, find proper bucket and chain, and thus find a symbol. * However, that would involve code duplication (e.g. for hash * function). So we're using simpler and a bit slower way: we're * iterating through symbols, searching for the one which name is * 'equal' to 'fdt_static_dtb'. To speed up the process a little bit, * we are eliminating symbols type of which is not STT_NOTYPE, or(and) * those which binding attribute is not STB_GLOBAL. */ for (i = 0; i < sym_count; i++) { COPYOUT(symtab + i, &sym, sizeof(sym)); if (ELF_ST_BIND(sym.st_info) != STB_GLOBAL || ELF_ST_TYPE(sym.st_info) != STT_NOTYPE) continue; strp = strdupout((vm_offset_t)(strtab + sym.st_name)); if (strcmp(strp, FDT_STATIC_DTB_SYMBOL) == 0) { /* Found a match ! */ free(strp); return ((vm_offset_t)(sym.st_value + offs)); } free(strp); } return (0); }
/* * Load the information expected by a sparc64 kernel. * * - The 'boothowto' argument is constructed * - The 'bootdev' argument is constructed * - The kernel environment is copied into kernel space. * - Module metadata are formatted and placed in kernel space. */ int md_load(char *args, vm_offset_t *modulep, vm_offset_t *dtbp) { struct preloaded_file *kfp; struct preloaded_file *xp; struct file_metadata *md; vm_offset_t kernend; vm_offset_t addr; vm_offset_t envp; vm_offset_t size; char *rootdevname; int howto; howto = md_getboothowto(args); *dtbp = 0; /* * Allow the environment variable 'rootdev' to override the supplied device * This should perhaps go to MI code and/or have $rootdev tested/set by * MI code before launching the kernel. */ if ((rootdevname = getenv("rootdev")) == NULL) rootdevname = getenv("currdev"); getrootmount(rootdevname); /* find the last module in the chain */ addr = 0; for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { if (addr < (xp->f_addr + xp->f_size)) addr = xp->f_addr + xp->f_size; } /* pad to a page boundary */ addr = roundup(addr, PAGE_SIZE); /* copy our environment */ envp = addr; addr = md_copyenv(addr); /* pad to a page boundary */ addr = roundup(addr, PAGE_SIZE); kernend = 0; kfp = file_findfile(NULL, "elf64 kernel"); if (kfp == NULL) kfp = file_findfile(NULL, "elf kernel"); if (kfp == NULL) panic("can't find kernel file"); file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); file_addmetadata(kfp, MODINFOMD_DTLB_SLOTS, sizeof dtlb_slot, &dtlb_slot); file_addmetadata(kfp, MODINFOMD_ITLB_SLOTS, sizeof itlb_slot, &itlb_slot); file_addmetadata(kfp, MODINFOMD_DTLB, dtlb_slot * sizeof(*dtlb_store), dtlb_store); file_addmetadata(kfp, MODINFOMD_ITLB, itlb_slot * sizeof(*itlb_store), itlb_store); *modulep = addr; size = md_copymodules(0); kernend = roundup(addr + size, PAGE_SIZE); md = file_findmetadata(kfp, MODINFOMD_KERNEND); bcopy(&kernend, md->md_data, sizeof kernend); (void)md_copymodules(addr); return(0); }
static int command_boot(int argc, char *argv[]) { struct preloaded_file *fp; char *local_module_path; char *exported_module_path; /* * See if the user has specified an explicit kernel to boot. */ if ((argc > 1) && (argv[1][0] != '-')) { /* XXX maybe we should discard everything and start again? */ if (file_findfile(NULL, NULL) != NULL) { sprintf(command_errbuf, "can't boot '%s', kernel module already loaded", argv[1]); return(CMD_ERROR); } /* find/load the kernel module */ if (mod_loadkld(argv[1], argc - 2, argv + 2) != 0) return(CMD_ERROR); /* we have consumed all arguments */ argc = 1; } /* * See if there is a kernel module already loaded */ if (file_findfile(NULL, NULL) == NULL) if (loadakernel(0, argc - 1, argv + 1)) /* we have consumed all arguments */ argc = 1; /* * Loaded anything yet? */ if ((fp = file_findfile(NULL, NULL)) == NULL) { command_errmsg = "no bootable kernel"; return(CMD_ERROR); } /* * If we were given arguments, discard any previous. * XXX should we merge arguments? Hard to DWIM. */ if (argc > 1) { if (fp->f_args != NULL) free(fp->f_args); fp->f_args = unargv(argc - 1, argv + 1); } /* Hook for platform-specific autoloading of modules */ if (archsw.arch_autoload() != 0) return(CMD_ERROR); /* * Exec the kernel. We have to shift our exported_module_path * (which has the correct /boot prefix for the kernel) over to * module_path. If the exec fails we switch it back. */ exported_module_path = getenv("exported_module_path"); if (exported_module_path) { exported_module_path = strdup(exported_module_path); local_module_path = getenv("module_path"); if (local_module_path) local_module_path = strdup(local_module_path); setenv("module_path", exported_module_path, 1); unsetenv("exported_module_path"); } /* Call the exec handler from the loader matching the kernel */ file_formats[fp->f_loader]->l_exec(fp); if (exported_module_path) { if (local_module_path) { setenv("module_path", local_module_path, 1); free(local_module_path); } else { unsetenv("module_path"); } setenv("exported_module_path", exported_module_path, 1); free(exported_module_path); } return(CMD_ERROR); }
static int multiboot_exec(struct preloaded_file *fp) { vm_offset_t module_start, last_addr, metadata_size; vm_offset_t modulep, kernend, entry; struct file_metadata *md; Elf_Ehdr *ehdr; struct multiboot_info *mb_info = NULL; struct multiboot_mod_list *mb_mod = NULL; char *cmdline = NULL; size_t len; int error, mod_num; /* * Don't pass the memory size found by the bootloader, the memory * available to Dom0 will be lower than that. */ unsetenv("smbios.memory.enabled"); /* Allocate the multiboot struct and fill the basic details. */ mb_info = malloc(sizeof(struct multiboot_info)); if (mb_info == NULL) { error = ENOMEM; goto error; } bzero(mb_info, sizeof(struct multiboot_info)); mb_info->flags = MULTIBOOT_INFO_MEMORY|MULTIBOOT_INFO_BOOT_LOADER_NAME; mb_info->mem_lower = bios_basemem / 1024; mb_info->mem_upper = bios_extmem / 1024; mb_info->boot_loader_name = VTOP(mbl_name); /* Set the Xen command line. */ if (fp->f_args == NULL) { /* Add the Xen command line if it is set. */ cmdline = getenv("xen_cmdline"); if (cmdline != NULL) { fp->f_args = strdup(cmdline); if (fp->f_args == NULL) { error = ENOMEM; goto error; } } } if (fp->f_args != NULL) { len = strlen(fp->f_name) + 1 + strlen(fp->f_args) + 1; cmdline = malloc(len); if (cmdline == NULL) { error = ENOMEM; goto error; } snprintf(cmdline, len, "%s %s", fp->f_name, fp->f_args); mb_info->cmdline = VTOP(cmdline); mb_info->flags |= MULTIBOOT_INFO_CMDLINE; } /* Find the entry point of the Xen kernel and save it for later */ if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) { printf("Unable to find %s entry point\n", fp->f_name); error = EINVAL; goto error; } ehdr = (Elf_Ehdr *)&(md->md_data); entry = ehdr->e_entry & 0xffffff; /* * Prepare the multiboot module list, Xen assumes the first * module is the Dom0 kernel, and the second one is the initramfs. * This is not optimal for FreeBSD, that doesn't have a initramfs * but instead loads modules dynamically and creates the metadata * info on-the-fly. * * As expected, the first multiboot module is going to be the * FreeBSD kernel loaded as a raw file. The second module is going * to contain the metadata info and the loaded modules. * * On native FreeBSD loads all the modules and then places the * metadata info at the end, but this is painful when running on Xen, * because it relocates the second multiboot module wherever it * likes. In order to workaround this limitation the metadata * information is placed at the start of the second module and * the original modulep value is saved together with the other * metadata, so we can relocate everything. * * Native layout: * fp->f_addr + fp->f_size * +---------+----------------+------------+ * | | | | * | Kernel | Modules | Metadata | * | | | | * +---------+----------------+------------+ * fp->f_addr modulep kernend * * Xen layout: * * Initial: * fp->f_addr + fp->f_size * +---------+----------+----------------+------------+ * | | | | | * | Kernel | Reserved | Modules | Metadata | * | | | | dry run | * +---------+----------+----------------+------------+ * fp->f_addr * * After metadata polacement (ie: final): * fp->f_addr + fp->f_size * +-----------+---------+----------+----------------+ * | | | | | * | Kernel | Free | Metadata | Modules | * | | | | | * +-----------+---------+----------+----------------+ * fp->f_addr modulep kernend * \__________/ \__________________________/ * Multiboot module 0 Multiboot module 1 */ fp = file_findfile(NULL, "elf kernel"); if (fp == NULL) { printf("No FreeBSD kernel provided, aborting\n"); error = EINVAL; goto error; } if (fp->f_metadata != NULL) { printf("FreeBSD kernel already contains metadata, aborting\n"); error = EINVAL; goto error; } mb_mod = malloc(sizeof(struct multiboot_mod_list) * NUM_MODULES); if (mb_mod == NULL) { error = ENOMEM; goto error; } bzero(mb_mod, sizeof(struct multiboot_mod_list) * NUM_MODULES); /* * Calculate how much memory is needed for the metatdata. We did * an approximation of the maximum size when loading the kernel, * but now we know the exact size, so we can release some of this * preallocated memory if not needed. */ last_addr = roundup(max_addr(), PAGE_SIZE); mod_num = num_modules(fp); /* * Place the metadata after the last used address in order to * calculate it's size, this will not be used. */ error = bi_load64(fp->f_args, last_addr, &modulep, &kernend, 0); if (error != 0) { printf("bi_load64 failed: %d\n", error); goto error; } metadata_size = roundup(kernend - last_addr, PAGE_SIZE); /* Check that the size is not greater than what we have reserved */ if (metadata_size > METADATA_RESV_SIZE(mod_num)) { printf("Required memory for metadata is greater than reserved " "space, please increase METADATA_FIXED_SIZE and " "METADATA_MODULE_SIZE and rebuild the loader\n"); error = ENOMEM; goto error; } /* Clean the metadata added to the kernel in the bi_load64 dry run */ file_removemetadata(fp); /* * This is the position where the second multiboot module * will be placed. */ module_start = fp->f_addr + fp->f_size - metadata_size; error = bi_load64(fp->f_args, module_start, &modulep, &kernend, 0); if (error != 0) { printf("bi_load64 failed: %d\n", error); goto error; } mb_mod[0].mod_start = fp->f_addr; mb_mod[0].mod_end = fp->f_addr + fp->f_size; mb_mod[0].mod_end -= METADATA_RESV_SIZE(mod_num); mb_mod[1].mod_start = module_start; mb_mod[1].mod_end = last_addr; mb_info->mods_count = NUM_MODULES; mb_info->mods_addr = VTOP(mb_mod); mb_info->flags |= MULTIBOOT_INFO_MODS; dev_cleanup(); __exec((void *)VTOP(multiboot_tramp), (void *)entry, (void *)VTOP(mb_info)); panic("exec returned"); error: if (mb_mod) free(mb_mod); if (mb_info) free(mb_info); if (cmdline) free(cmdline); return (error); }
/* * Load the information expected by an i386 kernel. * * - The 'boothowto' argument is constructed * - The 'bootdev' argument is constructed * - The 'bootinfo' struct is constructed, and copied into the kernel space. * - The kernel environment is copied into kernel space. * - Module metadata are formatted and placed in kernel space. */ int bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t *modulep, vm_offset_t *kernendp) { struct preloaded_file *xp, *kfp; struct i386_devdesc *rootdev; struct file_metadata *md; vm_offset_t addr; vm_offset_t kernend; vm_offset_t envp; vm_offset_t size; vm_offset_t ssym, esym; char *rootdevname; int bootdevnr, i, howto; char *kernelname; const char *kernelpath; howto = bi_getboothowto(args); /* * Allow the environment variable 'rootdev' to override the supplied device * This should perhaps go to MI code and/or have $rootdev tested/set by * MI code before launching the kernel. */ rootdevname = getenv("rootdev"); i386_getdev((void **)(&rootdev), rootdevname, NULL); if (rootdev == NULL) { /* bad $rootdev/$currdev */ printf("can't determine root device\n"); return(EINVAL); } /* Try reading the /etc/fstab file to select the root device */ getrootmount(i386_fmtdev(rootdev)); /* Do legacy rootdev guessing */ /* XXX - use a default bootdev of 0. Is this ok??? */ bootdevnr = 0; switch(rootdev->d_type) { case DEVT_CD: /* Pass in BIOS device number. */ bi.bi_bios_dev = bc_unit2bios(rootdev->d_kind.bioscd.unit); bootdevnr = bc_getdev(rootdev); break; case DEVT_DISK: /* pass in the BIOS device number of the current disk */ bi.bi_bios_dev = bd_unit2bios(rootdev->d_kind.biosdisk.unit); bootdevnr = bd_getdev(rootdev); break; case DEVT_NET: break; default: printf("WARNING - don't know how to boot from device type %d\n", rootdev->d_type); } if (bootdevnr == -1) { printf("root device %s invalid\n", i386_fmtdev(rootdev)); return (EINVAL); } free(rootdev); /* find the last module in the chain */ addr = 0; for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { if (addr < (xp->f_addr + xp->f_size)) addr = xp->f_addr + xp->f_size; } /* pad to a page boundary */ addr = roundup(addr, PAGE_SIZE); /* copy our environment */ envp = addr; addr = bi_copyenv(addr); /* pad to a page boundary */ addr = roundup(addr, PAGE_SIZE); kfp = file_findfile(NULL, "elf kernel"); if (kfp == NULL) kfp = file_findfile(NULL, "elf32 kernel"); if (kfp == NULL) panic("can't find kernel file"); kernend = 0; /* fill it in later */ file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); bios_addsmapdata(kfp); /* Figure out the size and location of the metadata */ *modulep = addr; size = bi_copymodules32(0); kernend = roundup(addr + size, PAGE_SIZE); *kernendp = kernend; /* patch MODINFOMD_KERNEND */ md = file_findmetadata(kfp, MODINFOMD_KERNEND); bcopy(&kernend, md->md_data, sizeof kernend); /* copy module list and metadata */ (void)bi_copymodules32(addr); ssym = esym = 0; md = file_findmetadata(kfp, MODINFOMD_SSYM); if (md != NULL) ssym = *((vm_offset_t *)&(md->md_data)); md = file_findmetadata(kfp, MODINFOMD_ESYM); if (md != NULL) esym = *((vm_offset_t *)&(md->md_data)); if (ssym == 0 || esym == 0) ssym = esym = 0; /* sanity */ /* legacy bootinfo structure */ kernelname = getenv("kernelname"); i386_getdev(NULL, kernelname, &kernelpath); bi.bi_version = BOOTINFO_VERSION; bi.bi_kernelname = 0; /* XXX char * -> kernel name */ bi.bi_nfs_diskless = 0; /* struct nfs_diskless * */ bi.bi_n_bios_used = 0; /* XXX would have to hook biosdisk driver for these */ for (i = 0; i < N_BIOS_GEOM; i++) bi.bi_bios_geom[i] = bd_getbigeom(i); bi.bi_size = sizeof(bi); bi.bi_memsizes_valid = 1; bi.bi_basemem = bios_basemem / 1024; bi.bi_extmem = bios_extmem / 1024; bi.bi_envp = envp; bi.bi_modulep = *modulep; bi.bi_kernend = kernend; bi.bi_kernelname = VTOP(kernelpath); bi.bi_symtab = ssym; /* XXX this is only the primary kernel symtab */ bi.bi_esymtab = esym; /* legacy boot arguments */ *howtop = howto | RB_BOOTINFO; *bootdevp = bootdevnr; *bip = VTOP(&bi); return(0); }
/* * Load the information expected by the kernel. * * - The kernel environment is copied into kernel space. * - Module metadata are formatted and placed in kernel space. */ int ia64_bootinfo(struct preloaded_file *fp, struct bootinfo **res) { struct bootinfo bi; struct preloaded_file *xp; struct file_metadata *md; struct devdesc *rootdev; char *rootdevname; vm_offset_t addr, ssym, esym; int error; *res = NULL; bzero(&bi, sizeof(struct bootinfo)); bi.bi_magic = BOOTINFO_MAGIC; bi.bi_version = 1; bi.bi_boothowto = bi_getboothowto(fp->f_args); /* * Allow the environment variable 'rootdev' to override the supplied * device. This should perhaps go to MI code and/or have $rootdev * tested/set by MI code before launching the kernel. */ rootdevname = getenv("rootdev"); ia64_getdev((void**)&rootdev, rootdevname, NULL); if (rootdev != NULL) { /* Try reading /etc/fstab to select the root device. */ getrootmount(ia64_fmtdev(rootdev)); free(rootdev); } md = file_findmetadata(fp, MODINFOMD_SSYM); ssym = (md != NULL) ? *((vm_offset_t *)&(md->md_data)) : 0; md = file_findmetadata(fp, MODINFOMD_ESYM); esym = (md != NULL) ? *((vm_offset_t *)&(md->md_data)) : 0; if (ssym != 0 && esym != 0) { bi.bi_symtab = ssym; bi.bi_esymtab = esym; } /* Find the last module in the chain. */ addr = 0; for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { if (addr < (xp->f_addr + xp->f_size)) addr = xp->f_addr + xp->f_size; } addr = (addr + 15) & ~15; /* Copy module list and metadata. */ bi.bi_modulep = addr; addr = bi_copymodules(addr); if (addr <= bi.bi_modulep) { addr = bi.bi_modulep; bi.bi_modulep = 0; } addr = (addr + 15) & ~15; /* Copy our environment. */ bi.bi_envp = addr; addr = bi_copyenv(addr); if (addr <= bi.bi_envp) { addr = bi.bi_envp; bi.bi_envp = 0; } addr = (addr + 15) & ~15; bi.bi_kernend = addr; error = ia64_platform_bootinfo(&bi, res); if (error) return (error); if (IS_LEGACY_KERNEL()) { if (*res == NULL) return (EDOOFUS); bcopy(&bi, *res, sizeof(bi)); return (0); } bi.bi_pbvm_pgtbl = (uintptr_t)ia64_pgtbl; bi.bi_pbvm_pgtblsz = ia64_pgtblsz; ia64_copyin((void *)bi.bi_memmap, addr, bi.bi_memmap_size); bi.bi_memmap = addr; addr = (addr + bi.bi_memmap_size + 15) & ~15; bi.bi_kernend = addr + sizeof(bi); ia64_copyin(&bi, addr, sizeof(bi)); *res = (void *)addr; return (0); }
static int command_load(int argc, char *argv[]) { char *typestr; int dofile, dokld, ch, error; dokld = dofile = 0; optind = 1; optreset = 1; typestr = NULL; if (argc == 1) { command_errmsg = "no filename specified"; return (CMD_CRIT); } while ((ch = getopt(argc, argv, "kt:")) != -1) { switch(ch) { case 'k': dokld = 1; break; case 't': typestr = optarg; dofile = 1; break; case '?': default: /* getopt has already reported an error */ return (CMD_OK); } } argv += (optind - 1); argc -= (optind - 1); printf("Loading %s...\n", argv[1]); /* * Request to load a raw file? */ if (dofile) { if ((typestr == NULL) || (*typestr == 0)) { command_errmsg = "invalid load type"; return (CMD_CRIT); } if (file_findfile(argv[1], typestr) != NULL) { snprintf(command_errbuf, sizeof (command_errbuf), "warning: file '%s' already loaded", argv[1]); return (CMD_WARN); } if (file_loadraw(argv[1], typestr, argc - 2, argv + 2, 1) != NULL) return (CMD_OK); /* Failing to load mfs_root is never going to end well! */ if (strcmp("mfs_root", typestr) == 0) return (CMD_FATAL); return (CMD_ERROR); } /* * Do we have explicit KLD load ? */ if (dokld || file_havepath(argv[1])) { error = mod_loadkld(argv[1], argc - 2, argv + 2); if (error == EEXIST) { snprintf(command_errbuf, sizeof (command_errbuf), "warning: KLD '%s' already loaded", argv[1]); return (CMD_WARN); } return (error == 0 ? CMD_OK : CMD_CRIT); } /* * Looks like a request for a module. */ error = mod_load(argv[1], NULL, argc - 2, argv + 2); if (error == EEXIST) { snprintf(command_errbuf, sizeof (command_errbuf), "warning: module '%s' already loaded", argv[1]); return (CMD_WARN); } return (error == 0 ? CMD_OK : CMD_CRIT); }
/* * Attempt to load the file (file) as an ELF module. It will be stored at * (dest), and a pointer to a module structure describing the loaded object * will be saved in (result). */ int __elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result) { struct preloaded_file *fp, *kfp; struct elf_file ef; Elf_Ehdr *ehdr; int err; ssize_t bytes_read; fp = NULL; bzero(&ef, sizeof(struct elf_file)); /* * Open the image, read and validate the ELF header */ if (filename == NULL) /* can't handle nameless */ return(EFTYPE); if ((ef.fd = open(filename, O_RDONLY)) == -1) return(errno); ef.firstpage = malloc(PAGE_SIZE); if (ef.firstpage == NULL) { close(ef.fd); return(ENOMEM); } bytes_read = read(ef.fd, ef.firstpage, PAGE_SIZE); ef.firstlen = (size_t)bytes_read; if (bytes_read < 0 || ef.firstlen <= sizeof(Elf_Ehdr)) { err = EFTYPE; /* could be EIO, but may be small file */ goto oerr; } ehdr = ef.ehdr = (Elf_Ehdr *)ef.firstpage; /* Is it ELF? */ if (!IS_ELF(*ehdr)) { err = EFTYPE; goto oerr; } if (ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */ ehdr->e_ident[EI_DATA] != ELF_TARG_DATA || ehdr->e_ident[EI_VERSION] != EV_CURRENT || /* Version ? */ ehdr->e_version != EV_CURRENT || ehdr->e_machine != ELF_TARG_MACH) { /* Machine ? */ err = EFTYPE; goto oerr; } /* * Check to see what sort of module we are. */ kfp = file_findfile(NULL, NULL); if (ehdr->e_type == ET_DYN) { /* Looks like a kld module */ if (kfp == NULL) { printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module before kernel\n"); err = EPERM; goto oerr; } if (strcmp(__elfN(kerneltype), kfp->f_type)) { printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module with kernel type '%s'\n", kfp->f_type); err = EPERM; goto oerr; } /* Looks OK, got ahead */ ef.kernel = 0; } else if (ehdr->e_type == ET_EXEC) { /* Looks like a kernel */ if (kfp != NULL) { printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: kernel already loaded\n"); err = EPERM; goto oerr; } /* * Calculate destination address based on kernel entrypoint */ dest = (ehdr->e_entry & ~PAGE_MASK); if (dest == 0) { printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: not a kernel (maybe static binary?)\n"); err = EPERM; goto oerr; } ef.kernel = 1; } else { err = EFTYPE; goto oerr; } if (archsw.arch_loadaddr != NULL) dest = archsw.arch_loadaddr(LOAD_ELF, ehdr, dest); else dest = roundup(dest, PAGE_SIZE); /* * Ok, we think we should handle this. */ fp = file_alloc(); if (fp == NULL) { printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: cannot allocate module info\n"); err = EPERM; goto out; } if (ef.kernel) setenv("kernelname", filename, 1); fp->f_name = strdup(filename); fp->f_type = strdup(ef.kernel ? __elfN(kerneltype) : __elfN(moduletype)); #ifdef ELF_VERBOSE if (ef.kernel) printf("%s entry at 0x%jx\n", filename, (uintmax_t)ehdr->e_entry); #else printf("%s ", filename); #endif fp->f_size = __elfN(loadimage)(fp, &ef, dest); if (fp->f_size == 0 || fp->f_addr == 0) goto ioerr; /* save exec header as metadata */ file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*ehdr), ehdr); /* Load OK, return module pointer */ *result = (struct preloaded_file *)fp; err = 0; goto out; ioerr: err = EIO; oerr: file_discard(fp); out: if (ef.firstpage) free(ef.firstpage); close(ef.fd); return(err); }
static vm_offset_t fdt_find_static_dtb() { Elf_Ehdr *ehdr; Elf_Shdr *shdr; Elf_Sym sym; vm_offset_t strtab, symtab, fdt_start; uint64_t offs; struct preloaded_file *kfp; struct file_metadata *md; char *strp; int i, sym_count; debugf("fdt_find_static_dtb()\n"); sym_count = symtab = strtab = 0; strp = NULL; offs = __elfN(relocation_offset); kfp = file_findfile(NULL, NULL); if (kfp == NULL) return (0); /* Locate the dynamic symbols and strtab. */ md = file_findmetadata(kfp, MODINFOMD_ELFHDR); if (md == NULL) return (0); ehdr = (Elf_Ehdr *)md->md_data; md = file_findmetadata(kfp, MODINFOMD_SHDR); if (md == NULL) return (0); shdr = (Elf_Shdr *)md->md_data; for (i = 0; i < ehdr->e_shnum; ++i) { if (shdr[i].sh_type == SHT_DYNSYM && symtab == 0) { symtab = shdr[i].sh_addr + offs; sym_count = shdr[i].sh_size / sizeof(Elf_Sym); } else if (shdr[i].sh_type == SHT_STRTAB && strtab == 0) { strtab = shdr[i].sh_addr + offs; } } /* * The most efficent way to find a symbol would be to calculate a * hash, find proper bucket and chain, and thus find a symbol. * However, that would involve code duplication (e.g. for hash * function). So we're using simpler and a bit slower way: we're * iterating through symbols, searching for the one which name is * 'equal' to 'fdt_static_dtb'. To speed up the process a little bit, * we are eliminating symbols type of which is not STT_NOTYPE, or(and) * those which binding attribute is not STB_GLOBAL. */ fdt_start = 0; while (sym_count > 0 && fdt_start == 0) { COPYOUT(symtab, &sym, sizeof(sym)); symtab += sizeof(sym); --sym_count; if (ELF_ST_BIND(sym.st_info) != STB_GLOBAL || ELF_ST_TYPE(sym.st_info) != STT_NOTYPE) continue; strp = strdupout(strtab + sym.st_name); if (strcmp(strp, FDT_STATIC_DTB_SYMBOL) == 0) fdt_start = (vm_offset_t)sym.st_value + offs; free(strp); } return (fdt_start); }
/* * Attempt to load the file (file) as an ELF module. It will be stored at * (dest), and a pointer to a module structure describing the loaded object * will be saved in (result). */ int __elfN(obj_loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result) { struct preloaded_file *fp, *kfp; struct elf_file ef; Elf_Ehdr *hdr; int err; ssize_t bytes_read; fp = NULL; bzero(&ef, sizeof(struct elf_file)); /* * Open the image, read and validate the ELF header */ if (filename == NULL) /* can't handle nameless */ return(EFTYPE); if ((ef.fd = open(filename, O_RDONLY)) == -1) return(errno); hdr = &ef.hdr; bytes_read = read(ef.fd, hdr, sizeof(*hdr)); if (bytes_read != sizeof(*hdr)) { err = EFTYPE; /* could be EIO, but may be small file */ goto oerr; } /* Is it ELF? */ if (!IS_ELF(*hdr)) { err = EFTYPE; goto oerr; } if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */ hdr->e_ident[EI_DATA] != ELF_TARG_DATA || hdr->e_ident[EI_VERSION] != EV_CURRENT || /* Version ? */ hdr->e_version != EV_CURRENT || hdr->e_machine != ELF_TARG_MACH || /* Machine ? */ hdr->e_type != ET_REL) { err = EFTYPE; goto oerr; } if (hdr->e_shnum * hdr->e_shentsize == 0 || hdr->e_shoff == 0 || hdr->e_shentsize != sizeof(Elf_Shdr)) { err = EFTYPE; goto oerr; } kfp = file_findfile(NULL, NULL); if (kfp == NULL) { printf("elf" __XSTRING(__ELF_WORD_SIZE) "_obj_loadfile: can't load module before kernel\n"); err = EPERM; goto oerr; } if (strcmp(__elfN(obj_kerneltype), kfp->f_type)) { printf("elf" __XSTRING(__ELF_WORD_SIZE) "_obj_loadfile: can't load module with kernel type '%s'\n", kfp->f_type); err = EPERM; goto oerr; } if (archsw.arch_loadaddr != NULL) dest = archsw.arch_loadaddr(LOAD_ELF, hdr, dest); else dest = roundup(dest, PAGE_SIZE); /* * Ok, we think we should handle this. */ fp = file_alloc(); if (fp == NULL) { printf("elf" __XSTRING(__ELF_WORD_SIZE) "_obj_loadfile: cannot allocate module info\n"); err = EPERM; goto out; } fp->f_name = strdup(filename); fp->f_type = strdup(__elfN(obj_moduletype)); printf("%s ", filename); fp->f_size = __elfN(obj_loadimage)(fp, &ef, dest); if (fp->f_size == 0 || fp->f_addr == 0) goto ioerr; /* save exec header as metadata */ file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*hdr), hdr); /* Load OK, return module pointer */ *result = (struct preloaded_file *)fp; err = 0; goto out; ioerr: err = EIO; oerr: file_discard(fp); out: close(ef.fd); if (ef.e_shdr != NULL) free(ef.e_shdr); return(err); }
static int multiboot_obj_loadfile(char *filename, u_int64_t dest, struct preloaded_file **result) { struct preloaded_file *mfp, *kfp, *rfp; int error, mod_num; /* See if there's a aout multiboot kernel loaded */ mfp = file_findfile(NULL, "aout multiboot kernel"); if (mfp != NULL) { /* we have normal kernel loaded, add module */ rfp = file_loadraw(filename, "module", 0, NULL, 0); if (rfp == NULL) { printf( "Unable to load %s as a multiboot payload module\n", filename); return (EINVAL); } rfp->f_size = roundup(rfp->f_size, PAGE_SIZE); *result = rfp; return (0); } /* See if there's a multiboot kernel loaded */ mfp = file_findfile(NULL, "elf multiboot kernel"); if (mfp == NULL) { return (EFTYPE); /* this allows to check other methods */ } /* * We have a multiboot kernel loaded, see if there's a * kernel loaded also. */ kfp = file_findfile(NULL, "elf kernel"); if (kfp == NULL) { /* * No kernel loaded, this must be it. The kernel has to * be loaded as a raw file, it will be processed by * Xen and correctly loaded as an ELF file. */ rfp = file_loadraw(filename, "elf kernel", 0, NULL, 0); if (rfp == NULL) { printf( "Unable to load %s as a multiboot payload kernel\n", filename); return (EINVAL); } /* Load kernel metadata... */ setenv("kernelname", filename, 1); error = elf64_load_modmetadata(rfp, rfp->f_addr + rfp->f_size); if (error) { printf("Unable to load kernel %s metadata error: %d\n", rfp->f_name, error); return (EINVAL); } /* * Save space at the end of the kernel in order to place * the metadata information. We do an approximation of the * max metadata size, this is not optimal but it's probably * the best we can do at this point. Once all modules are * loaded and the size of the metadata is known this * space will be recovered if not used. */ mod_num = num_modules(rfp); rfp->f_size = roundup(rfp->f_size, PAGE_SIZE); rfp->f_size += METADATA_RESV_SIZE(mod_num); *result = rfp; } else { /* The rest should be loaded as regular modules */ error = elf64_obj_loadfile(filename, dest, result); if (error != 0) { printf("Unable to load %s as an object file, error: %d", filename, error); return (error); } } return (0); }
/* * Load the information expected by a powerpc kernel. * * - The 'boothowto' argument is constructed * - The 'bootdev' argument is constructed * - The kernel environment is copied into kernel space. * - Module metadata are formatted and placed in kernel space. */ int md_load_dual(char *args, vm_offset_t *modulep, vm_offset_t *dtb, int kern64) { struct preloaded_file *kfp; struct preloaded_file *xp; struct file_metadata *md; vm_offset_t kernend; vm_offset_t addr; vm_offset_t envp; vm_offset_t fdtp; vm_offset_t size; uint64_t scratch64; char *rootdevname; int howto; align = kern64 ? 8 : 4; howto = md_getboothowto(args); /* * Allow the environment variable 'rootdev' to override the supplied device * This should perhaps go to MI code and/or have $rootdev tested/set by * MI code before launching the kernel. */ rootdevname = getenv("rootdev"); if (rootdevname == NULL) rootdevname = getenv("currdev"); /* Try reading the /etc/fstab file to select the root device */ getrootmount(rootdevname); /* find the last module in the chain */ addr = 0; for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { if (addr < (xp->f_addr + xp->f_size)) addr = xp->f_addr + xp->f_size; } /* pad to a page boundary */ addr = roundup(addr, PAGE_SIZE); /* copy our environment */ envp = addr; addr = md_copyenv(addr); /* pad to a page boundary */ addr = roundup(addr, PAGE_SIZE); /* Copy out FDT */ size = fdt_copy(addr); *dtb = fdtp = addr; addr = roundup(addr + size, PAGE_SIZE); kernend = 0; kfp = file_findfile(NULL, kern64 ? "elf64 kernel" : "elf32 kernel"); if (kfp == NULL) kfp = file_findfile(NULL, "elf kernel"); if (kfp == NULL) panic("can't find kernel file"); file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); if (kern64) { scratch64 = envp; file_addmetadata(kfp, MODINFOMD_ENVP, sizeof scratch64, &scratch64); scratch64 = fdtp; file_addmetadata(kfp, MODINFOMD_DTBP, sizeof scratch64, &scratch64); scratch64 = kernend; file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof scratch64, &scratch64); } else { file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); file_addmetadata(kfp, MODINFOMD_DTBP, sizeof fdtp, &fdtp); file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); } *modulep = addr; size = md_copymodules(0, kern64); kernend = roundup(addr + size, PAGE_SIZE); md = file_findmetadata(kfp, MODINFOMD_KERNEND); if (kern64) { scratch64 = kernend; bcopy(&scratch64, md->md_data, sizeof scratch64); } else { bcopy(&kernend, md->md_data, sizeof kernend); } (void)md_copymodules(addr, kern64); return(0); }
static int multiboot_loadfile(char *filename, u_int64_t dest, struct preloaded_file **result) { uint32_t *magic; int i, error; caddr_t header_search; ssize_t search_size; int fd; struct multiboot_header *header; struct preloaded_file *fp; if (filename == NULL) return (EFTYPE); /* is kernel already loaded? */ fp = file_findfile(NULL, NULL); if (fp != NULL) { return (EFTYPE); } if ((fd = open(filename, O_RDONLY)) == -1) return (errno); /* * Read MULTIBOOT_SEARCH size in order to search for the * multiboot magic header. */ header_search = malloc(MULTIBOOT_SEARCH); if (header_search == NULL) { close(fd); return (ENOMEM); } search_size = read(fd, header_search, MULTIBOOT_SEARCH); magic = (uint32_t *)header_search; header = NULL; for (i = 0; i < (search_size / sizeof(uint32_t)); i++) { if (magic[i] == MULTIBOOT_HEADER_MAGIC) { header = (struct multiboot_header *)&magic[i]; break; } } if (header == NULL) { error = EFTYPE; goto out; } /* Valid multiboot header has been found, validate checksum */ if (header->magic + header->flags + header->checksum != 0) { printf( "Multiboot checksum failed, magic: 0x%x flags: 0x%x checksum: 0x%x\n", header->magic, header->flags, header->checksum); error = EFTYPE; goto out; } if ((header->flags & ~MULTIBOOT_SUPPORTED_FLAGS) != 0) { printf("Unsupported multiboot flags found: 0x%x\n", header->flags); error = EFTYPE; goto out; } /* AOUT KLUDGE means we just load entire flat file as blob */ if (header->flags & MULTIBOOT_AOUT_KLUDGE) { vm_offset_t laddr; int got; dest = header->load_addr; if (lseek(fd, 0, SEEK_SET) == -1) { printf("lseek failed\n"); error = EIO; goto out; } laddr = dest; for (;;) { got = archsw.arch_readin(fd, laddr, 4096); if (got == 0) break; if (got < 0) { printf("error reading: %s", strerror(errno)); error = EIO; goto out; } laddr += got; } fp = file_alloc(); if (fp == NULL) { error = ENOMEM; goto out; } fp->f_name = strdup(filename); fp->f_type = strdup("aout multiboot kernel"); fp->f_addr = header->entry_addr; fp->f_size = laddr - dest; if (fp->f_size == 0) { file_discard(fp); error = EIO; goto out; } fp->f_metadata = NULL; error = 0; } else { error = elf32_loadfile_raw(filename, dest, &fp, 1); if (error != 0) { printf("elf32_loadfile_raw failed: %d unable to " "load multiboot kernel\n", error); goto out; } } setenv("kernelname", fp->f_name, 1); bios_addsmapdata(fp); *result = fp; out: free(header_search); close(fd); return (error); }
/* * Load the information expected by an amd64 kernel. * * - The 'boothowto' argument is constructed * - The 'bootdev' argument is constructed * - The 'bootinfo' struct is constructed, and copied into the kernel space. * - The kernel environment is copied into kernel space. * - Module metadata are formatted and placed in kernel space. */ int bi_load64(char *args, vm_offset_t *modulep, vm_offset_t *kernendp) { struct preloaded_file *xp, *kfp; struct userboot_devdesc *rootdev; struct file_metadata *md; vm_offset_t addr; u_int64_t kernend; u_int64_t envp; vm_offset_t size; char *rootdevname; int howto; if (!bi_checkcpu()) { printf("CPU doesn't support long mode\n"); return (EINVAL); } howto = bi_getboothowto(args); /* * Allow the environment variable 'rootdev' to override the supplied device * This should perhaps go to MI code and/or have $rootdev tested/set by * MI code before launching the kernel. */ rootdevname = getenv("rootdev"); userboot_getdev((void **)(&rootdev), rootdevname, NULL); if (rootdev == NULL) { /* bad $rootdev/$currdev */ printf("can't determine root device\n"); return(EINVAL); } /* Try reading the /etc/fstab file to select the root device */ getrootmount(userboot_fmtdev((void *)rootdev)); /* find the last module in the chain */ addr = 0; for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { if (addr < (xp->f_addr + xp->f_size)) addr = xp->f_addr + xp->f_size; } /* pad to a page boundary */ addr = roundup(addr, PAGE_SIZE); /* copy our environment */ envp = addr; addr = bi_copyenv(addr); /* pad to a page boundary */ addr = roundup(addr, PAGE_SIZE); kfp = file_findfile(NULL, "elf kernel"); if (kfp == NULL) kfp = file_findfile(NULL, "elf64 kernel"); if (kfp == NULL) panic("can't find kernel file"); kernend = 0; /* fill it in later */ file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); bios_addsmapdata(kfp); /* Figure out the size and location of the metadata */ *modulep = addr; size = bi_copymodules64(0); kernend = roundup(addr + size, PAGE_SIZE); *kernendp = kernend; /* patch MODINFOMD_KERNEND */ md = file_findmetadata(kfp, MODINFOMD_KERNEND); bcopy(&kernend, md->md_data, sizeof kernend); /* copy module list and metadata */ (void)bi_copymodules64(addr); return(0); }
/* * Load the information expected by the kernel. * * - The kernel environment is copied into kernel space. * - Module metadata are formatted and placed in kernel space. */ int bi_load(struct bootinfo *bi, struct preloaded_file *fp, UINTN *mapkey, UINTN pages) { char *rootdevname; struct efi_devdesc *rootdev; struct preloaded_file *xp; vaddr_t addr, bootinfo_addr; vaddr_t ssym, esym; struct file_metadata *md; EFI_STATUS status; UINTN bisz, key; /* * Version 1 bootinfo. */ bi->bi_magic = BOOTINFO_MAGIC; bi->bi_version = 1; /* * Calculate boothowto. */ bi->bi_boothowto = bi_getboothowto(fp->f_args); /* * Stash EFI System Table. */ bi->bi_systab = (u_int64_t) ST; /* * Allow the environment variable 'rootdev' to override the supplied * device. This should perhaps go to MI code and/or have $rootdev * tested/set by MI code before launching the kernel. */ rootdevname = getenv("rootdev"); efi_getdev((void **)(&rootdev), rootdevname, NULL); if (rootdev == NULL) { /* bad $rootdev/$currdev */ printf("can't determine root device\n"); return(EINVAL); } /* Try reading the /etc/fstab file to select the root device */ getrootmount(efi_fmtdev((void *)rootdev)); free(rootdev); ssym = esym = 0; ssym = fp->marks[MARK_SYM]; esym = fp->marks[MARK_END]; if (ssym == 0 || esym == 0) ssym = esym = 0; /* sanity */ bi->bi_symtab = ssym; bi->bi_esymtab = esym; bi->bi_hcdp = (uint64_t)efi_get_table(&hcdp); /* DIG64 HCDP table addr. */ fpswa_init(&bi->bi_fpswa); /* find FPSWA interface */ /* find the last module in the chain */ addr = 0; for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { if (addr < (xp->f_addr + xp->f_size)) addr = xp->f_addr + xp->f_size; } /* pad to a page boundary */ addr = (addr + PAGE_MASK) & ~PAGE_MASK; /* copy our environment */ bi->bi_envp = addr; addr = bi_copyenv(addr); /* pad to a page boundary */ addr = (addr + PAGE_MASK) & ~PAGE_MASK; /* all done copying stuff in, save end of loaded object space */ bi->bi_kernend = addr; /* * Read the memory map and stash it after bootinfo. Align the memory map * on a 16-byte boundary (the bootinfo block is page aligned). */ bisz = (sizeof(struct bootinfo) + 0x0f) & ~0x0f; bi->bi_memmap = ((u_int64_t)bi) + bisz; bi->bi_memmap_size = EFI_PAGE_SIZE * pages - bisz; status = BS->GetMemoryMap(&bi->bi_memmap_size, (EFI_MEMORY_DESCRIPTOR *)bi->bi_memmap, &key, &bi->bi_memdesc_size, &bi->bi_memdesc_version); if (EFI_ERROR(status)) { printf("bi_load: Can't read memory map\n"); return EINVAL; } *mapkey = key; return(0); }
/* * Load the information expected by an alpha kernel. * * - The kernel environment is copied into kernel space. * - Module metadata are formatted and placed in kernel space. */ int bi_load(struct bootinfo *bi, struct preloaded_file *fp, char *args) { char *rootdevname; struct ski_devdesc *rootdev; struct preloaded_file *xp; vm_offset_t addr, bootinfo_addr; u_int pad; char *kernelname; vm_offset_t ssym, esym; struct file_metadata *md; EFI_MEMORY_DESCRIPTOR *memp; /* * Version 1 bootinfo. */ bi->bi_magic = BOOTINFO_MAGIC; bi->bi_version = 1; /* * Calculate boothowto. */ bi->bi_boothowto = bi_getboothowto(fp->f_args); /* * Allow the environment variable 'rootdev' to override the supplied device * This should perhaps go to MI code and/or have $rootdev tested/set by * MI code before launching the kernel. */ rootdevname = getenv("rootdev"); ski_getdev((void **)(&rootdev), rootdevname, NULL); if (rootdev == NULL) { /* bad $rootdev/$currdev */ printf("can't determine root device\n"); return(EINVAL); } /* Try reading the /etc/fstab file to select the root device */ getrootmount(ski_fmtdev((void *)rootdev)); free(rootdev); ssym = esym = 0; if ((md = file_findmetadata(fp, MODINFOMD_SSYM)) != NULL) ssym = *((vm_offset_t *)&(md->md_data)); if ((md = file_findmetadata(fp, MODINFOMD_ESYM)) != NULL) esym = *((vm_offset_t *)&(md->md_data)); if (ssym == 0 || esym == 0) ssym = esym = 0; /* sanity */ bi->bi_symtab = ssym; bi->bi_esymtab = esym; /* find the last module in the chain */ addr = 0; for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { if (addr < (xp->f_addr + xp->f_size)) addr = xp->f_addr + xp->f_size; } /* pad to a page boundary */ pad = (u_int)addr & PAGE_MASK; if (pad != 0) { pad = PAGE_SIZE - pad; addr += pad; } /* copy our environment */ bi->bi_envp = addr; addr = bi_copyenv(addr); /* pad to a page boundary */ pad = (u_int)addr & PAGE_MASK; if (pad != 0) { pad = PAGE_SIZE - pad; addr += pad; } /* copy module list and metadata */ bi->bi_modulep = addr; addr = bi_copymodules(addr); /* all done copying stuff in, save end of loaded object space */ bi->bi_kernend = addr; /* Describe the SKI memory map. */ bi->bi_memmap = (u_int64_t)(bi + 1); bi->bi_memmap_size = 2 * sizeof(EFI_MEMORY_DESCRIPTOR); bi->bi_memdesc_size = sizeof(EFI_MEMORY_DESCRIPTOR); bi->bi_memdesc_version = 1; memp = (EFI_MEMORY_DESCRIPTOR *) bi->bi_memmap; memp[0].Type = EfiConventionalMemory; memp[0].PhysicalStart = 2L*1024*1024; memp[0].VirtualStart = 0; memp[0].NumberOfPages = (64L*1024*1024)>>12; memp[0].Attribute = EFI_MEMORY_WB; memp[1].Type = EfiMemoryMappedIOPortSpace; memp[1].PhysicalStart = 0xffffc000000; memp[1].VirtualStart = 0; memp[1].NumberOfPages = (64L*1024*1024)>>12; memp[1].Attribute = EFI_MEMORY_UC; return(0); }
int __elfN(loadfile_raw)(char *filename, u_int64_t dest, struct preloaded_file **result, int multiboot) { struct preloaded_file *fp, *kfp; struct elf_file ef; Elf_Ehdr *ehdr; int err; fp = NULL; bzero(&ef, sizeof(struct elf_file)); ef.fd = -1; err = __elfN(load_elf_header)(filename, &ef); if (err != 0) return (err); ehdr = ef.ehdr; /* * Check to see what sort of module we are. */ kfp = file_findfile(NULL, __elfN(kerneltype)); #ifdef __powerpc__ /* * Kernels can be ET_DYN, so just assume the first loaded object is the * kernel. This assumption will be checked later. */ if (kfp == NULL) ef.kernel = 1; #endif if (ef.kernel || ehdr->e_type == ET_EXEC) { /* Looks like a kernel */ if (kfp != NULL) { printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: kernel already loaded\n"); err = EPERM; goto oerr; } /* * Calculate destination address based on kernel entrypoint. * * For ARM, the destination address is independent of any values in the * elf header (an ARM kernel can be loaded at any 2MB boundary), so we * leave dest set to the value calculated by archsw.arch_loadaddr() and * passed in to this function. */ #ifndef __arm__ if (ehdr->e_type == ET_EXEC) dest = (ehdr->e_entry & ~PAGE_MASK); #endif if ((ehdr->e_entry & ~PAGE_MASK) == 0) { printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: not a kernel (maybe static binary?)\n"); err = EPERM; goto oerr; } ef.kernel = 1; } else if (ehdr->e_type == ET_DYN) { /* Looks like a kld module */ if (multiboot != 0) { printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module as multiboot\n"); err = EPERM; goto oerr; } if (kfp == NULL) { printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module before kernel\n"); err = EPERM; goto oerr; } if (strcmp(__elfN(kerneltype), kfp->f_type)) { printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module with kernel type '%s'\n", kfp->f_type); err = EPERM; goto oerr; } /* Looks OK, got ahead */ ef.kernel = 0; } else { err = EFTYPE; goto oerr; } if (archsw.arch_loadaddr != NULL) dest = archsw.arch_loadaddr(LOAD_ELF, ehdr, dest); else dest = roundup(dest, PAGE_SIZE); /* * Ok, we think we should handle this. */ fp = file_alloc(); if (fp == NULL) { printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: cannot allocate module info\n"); err = EPERM; goto out; } if (ef.kernel == 1 && multiboot == 0) setenv("kernelname", filename, 1); fp->f_name = strdup(filename); if (multiboot == 0) fp->f_type = strdup(ef.kernel ? __elfN(kerneltype) : __elfN(moduletype)); else fp->f_type = strdup("elf multiboot kernel"); #ifdef ELF_VERBOSE if (ef.kernel) printf("%s entry at 0x%jx\n", filename, (uintmax_t)ehdr->e_entry); #else printf("%s ", filename); #endif fp->f_size = __elfN(loadimage)(fp, &ef, dest); if (fp->f_size == 0 || fp->f_addr == 0) goto ioerr; /* save exec header as metadata */ file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*ehdr), ehdr); /* Load OK, return module pointer */ *result = (struct preloaded_file *)fp; err = 0; goto out; ioerr: err = EIO; oerr: file_discard(fp); out: if (ef.firstpage) free(ef.firstpage); if (ef.fd != -1) close(ef.fd); return(err); }
/* * Load the information expected by the kernel. * * - The kernel environment is copied into kernel space. * - Module metadata are formatted and placed in kernel space. */ int bi_load(struct preloaded_file *fp, uint64_t *bi_addr) { struct bootinfo bi; struct preloaded_file *xp; struct file_metadata *md; struct devdesc *rootdev; char *rootdevname; vm_offset_t addr, ssym, esym; bzero(&bi, sizeof(struct bootinfo)); bi.bi_version = 1; // bi.bi_boothowto = bi_getboothowto(fp->f_args); /* * Allow the environment variable 'rootdev' to override the supplied * device. This should perhaps go to MI code and/or have $rootdev * tested/set by MI code before launching the kernel. */ rootdevname = getenv("rootdev"); i386_getdev((void**)&rootdev, rootdevname, NULL); if (rootdev != NULL) { /* Try reading /etc/fstab to select the root device. */ getrootmount(i386_fmtdev(rootdev)); free(rootdev); } md = file_findmetadata(fp, MODINFOMD_SSYM); ssym = (md != NULL) ? *((vm_offset_t *)&(md->md_data)) : 0; md = file_findmetadata(fp, MODINFOMD_ESYM); esym = (md != NULL) ? *((vm_offset_t *)&(md->md_data)) : 0; if (ssym != 0 && esym != 0) { bi.bi_symtab = ssym; bi.bi_esymtab = esym; } /* Find the last module in the chain. */ addr = 0; for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { if (addr < (xp->f_addr + xp->f_size)) addr = xp->f_addr + xp->f_size; } addr = (addr + 15) & ~15; /* Copy module list and metadata. */ bi.bi_modulep = addr; addr = bi_copymodules(addr); if (addr <= bi.bi_modulep) { addr = bi.bi_modulep; bi.bi_modulep = 0; } addr = (addr + 15) & ~15; /* Copy our environment. */ bi.bi_envp = addr; addr = bi_copyenv(addr); if (addr <= bi.bi_envp) { addr = bi.bi_envp; bi.bi_envp = 0; } addr = (addr + PAGE_MASK) & ~PAGE_MASK; bi.bi_kernend = addr; return (ldr_bootinfo(&bi, bi_addr)); }
/* * Load the information expected by a kernel. * * - The 'boothowto' argument is constructed * - The 'bootdev' argument is constructed * - The kernel environment is copied into kernel space. * - Module metadata are formatted and placed in kernel space. */ int md_load(char *args, vm_offset_t *modulep) { struct preloaded_file *kfp, *bfp; struct preloaded_file *xp; struct file_metadata *md; struct bootinfo *bip; vm_offset_t kernend; vm_offset_t addr; vm_offset_t envp; vm_offset_t size; vm_offset_t vaddr; vm_offset_t dtbp; char *rootdevname; int howto; int i; /* * These metadata addreses must be converted for kernel after * relocation. */ uint32_t mdt[] = { MODINFOMD_SSYM, MODINFOMD_ESYM, MODINFOMD_KERNEND, MODINFOMD_ENVP, #if defined(LOADER_FDT_SUPPORT) MODINFOMD_DTBP #endif }; howto = md_getboothowto(args); /* * Allow the environment variable 'rootdev' to override the supplied * device. This should perhaps go to MI code and/or have $rootdev * tested/set by MI code before launching the kernel. */ rootdevname = getenv("rootdev"); if (rootdevname == NULL) rootdevname = getenv("currdev"); /* Try reading the /etc/fstab file to select the root device */ getrootmount(rootdevname); /* Find the last module in the chain */ addr = 0; for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { if (addr < (xp->f_addr + xp->f_size)) addr = xp->f_addr + xp->f_size; } /* Pad to a page boundary */ addr = roundup(addr, PAGE_SIZE); /* Copy our environment */ envp = addr; addr = md_copyenv(addr); /* Pad to a page boundary */ addr = roundup(addr, PAGE_SIZE); kernend = 0; kfp = file_findfile(NULL, "elf32 kernel"); if (kfp == NULL) kfp = file_findfile(NULL, "elf kernel"); if (kfp == NULL) panic("can't find kernel file"); file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); #if defined(LOADER_FDT_SUPPORT) /* Handle device tree blob */ dtbp = fdt_fixup(); if (dtbp != 0) file_addmetadata(kfp, MODINFOMD_DTBP, sizeof dtbp, &dtbp); else pager_output("WARNING! Trying to fire up the kernel, but no " "device tree blob found!\n"); #endif file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); /* Figure out the size and location of the metadata */ *modulep = addr; size = md_copymodules(0); kernend = roundup(addr + size, PAGE_SIZE); /* Provide MODINFOMD_KERNEND */ md = file_findmetadata(kfp, MODINFOMD_KERNEND); bcopy(&kernend, md->md_data, sizeof kernend); /* Convert addresses to the final VA */ *modulep -= __elfN(relocation_offset); for (i = 0; i < sizeof mdt / sizeof mdt[0]; i++) { md = file_findmetadata(kfp, mdt[i]); if (md) { bcopy(md->md_data, &vaddr, sizeof vaddr); vaddr -= __elfN(relocation_offset); bcopy(&vaddr, md->md_data, sizeof vaddr); } } /* Only now copy actual modules and metadata */ (void)md_copymodules(addr); return (0); }