/* * 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 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); }
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); }