1*43108a21Smanu /* $NetBSD: multiboot.c,v 1.26 2019/10/18 01:38:28 manu Exp $ */
20b879f1cSjmmv
30b879f1cSjmmv /*-
40b879f1cSjmmv * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc.
50b879f1cSjmmv * All rights reserved.
60b879f1cSjmmv *
70b879f1cSjmmv * This code is derived from software contributed to The NetBSD Foundation
80b879f1cSjmmv * by Julio M. Merino Vidal.
90b879f1cSjmmv *
100b879f1cSjmmv * Redistribution and use in source and binary forms, with or without
110b879f1cSjmmv * modification, are permitted provided that the following conditions
120b879f1cSjmmv * are met:
130b879f1cSjmmv * 1. Redistributions of source code must retain the above copyright
140b879f1cSjmmv * notice, this list of conditions and the following disclaimer.
150b879f1cSjmmv * 2. Redistributions in binary form must reproduce the above copyright
160b879f1cSjmmv * notice, this list of conditions and the following disclaimer in the
170b879f1cSjmmv * documentation and/or other materials provided with the distribution.
180b879f1cSjmmv *
190b879f1cSjmmv * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
200b879f1cSjmmv * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
210b879f1cSjmmv * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
220b879f1cSjmmv * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
230b879f1cSjmmv * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
240b879f1cSjmmv * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
250b879f1cSjmmv * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
260b879f1cSjmmv * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
270b879f1cSjmmv * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
280b879f1cSjmmv * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
290b879f1cSjmmv * POSSIBILITY OF SUCH DAMAGE.
300b879f1cSjmmv */
310b879f1cSjmmv
320b879f1cSjmmv #include <sys/cdefs.h>
33*43108a21Smanu __KERNEL_RCSID(0, "$NetBSD: multiboot.c,v 1.26 2019/10/18 01:38:28 manu Exp $");
349bb39d02Sjoerg
359bb39d02Sjoerg #include "opt_multiboot.h"
360b879f1cSjmmv
370b879f1cSjmmv #include <sys/param.h>
380b879f1cSjmmv #include <sys/systm.h>
390b879f1cSjmmv #include <sys/cdefs_elf.h>
400b879f1cSjmmv #include <sys/boot_flag.h>
410b879f1cSjmmv #include <sys/exec.h>
420b879f1cSjmmv #include <sys/exec_elf.h>
430b879f1cSjmmv #include <sys/optstr.h>
448d30a464Sjmmv #include <sys/ksyms.h>
450b879f1cSjmmv
460b879f1cSjmmv #include <machine/bootinfo.h>
470b879f1cSjmmv #include <machine/multiboot.h>
480b879f1cSjmmv
490b879f1cSjmmv #if !defined(MULTIBOOT)
500b879f1cSjmmv # error "MULTIBOOT not defined; this cannot happen."
510b879f1cSjmmv #endif
520b879f1cSjmmv
530b879f1cSjmmv /* --------------------------------------------------------------------- */
540b879f1cSjmmv
550b879f1cSjmmv /*
568d30a464Sjmmv * Symbol and string table for the loaded kernel.
578d30a464Sjmmv */
588d30a464Sjmmv
598d30a464Sjmmv struct multiboot_symbols {
6053524e44Schristos void * s_symstart;
618d30a464Sjmmv size_t s_symsize;
6253524e44Schristos void * s_strstart;
638d30a464Sjmmv size_t s_strsize;
648d30a464Sjmmv };
658d30a464Sjmmv
668d30a464Sjmmv /* --------------------------------------------------------------------- */
678d30a464Sjmmv
688d30a464Sjmmv /*
690b879f1cSjmmv * External variables. All of them, with the exception of 'end', must
700b879f1cSjmmv * be set at some point within this file.
7195543a8eSmrg *
7295543a8eSmrg * XXX these should be found in a header file!
730b879f1cSjmmv */
740b879f1cSjmmv extern int biosbasemem;
750b879f1cSjmmv extern int biosextmem;
7695543a8eSmrg extern int biosmem_implicit;
770b879f1cSjmmv extern int boothowto;
780b879f1cSjmmv extern struct bootinfo bootinfo;
790b879f1cSjmmv extern int end;
800b879f1cSjmmv extern int * esym;
810b879f1cSjmmv
820b879f1cSjmmv /* --------------------------------------------------------------------- */
830b879f1cSjmmv
840b879f1cSjmmv /*
850b879f1cSjmmv * Copy of the Multiboot information structure passed to us by the boot
860b879f1cSjmmv * loader. The Multiboot_Info structure has some pointers adjusted to the
87*43108a21Smanu * other variables -- see multiboot1_pre_reloc() -- so you oughtn't access
880b879f1cSjmmv * them directly. In other words, always access them through the
890b879f1cSjmmv * Multiboot_Info variable.
900b879f1cSjmmv */
910b879f1cSjmmv static char Multiboot_Cmdline[255];
920b879f1cSjmmv static uint8_t Multiboot_Drives[255];
930b879f1cSjmmv static struct multiboot_info Multiboot_Info;
94f00c5400Sthorpej static bool Multiboot_Loader = false;
950b879f1cSjmmv static char Multiboot_Loader_Name[255];
960b879f1cSjmmv static uint8_t Multiboot_Mmap[1024];
978d30a464Sjmmv static struct multiboot_symbols Multiboot_Symbols;
980b879f1cSjmmv
990b879f1cSjmmv /* --------------------------------------------------------------------- */
1000b879f1cSjmmv
1010b879f1cSjmmv /*
1020b879f1cSjmmv * Prototypes for private functions.
1030b879f1cSjmmv */
1040b879f1cSjmmv static void bootinfo_add(struct btinfo_common *, int, int);
1050b879f1cSjmmv static void copy_syms(struct multiboot_info *);
1060b879f1cSjmmv static void setup_biosgeom(struct multiboot_info *);
1070b879f1cSjmmv static void setup_bootdisk(struct multiboot_info *);
1080b879f1cSjmmv static void setup_bootpath(struct multiboot_info *);
1090b879f1cSjmmv static void setup_console(struct multiboot_info *);
1100b879f1cSjmmv static void setup_howto(struct multiboot_info *);
1110b879f1cSjmmv static void setup_memory(struct multiboot_info *);
1120b879f1cSjmmv static void setup_memmap(struct multiboot_info *);
1130b879f1cSjmmv
1140b879f1cSjmmv /* --------------------------------------------------------------------- */
1150b879f1cSjmmv
1160b879f1cSjmmv /*
1170b879f1cSjmmv * Sets up the kernel if it was booted by a Multiboot-compliant boot
1180b879f1cSjmmv * loader. This is executed before the kernel has relocated itself.
1190b879f1cSjmmv * The main purpose of this function is to copy all the information
1200b879f1cSjmmv * passed in by the boot loader to a safe place, so that it is available
1210b879f1cSjmmv * after it has been relocated.
1220b879f1cSjmmv *
1230b879f1cSjmmv * WARNING: Because the kernel has not yet relocated itself to KERNBASE,
1240b879f1cSjmmv * special care has to be taken when accessing memory because absolute
1250b879f1cSjmmv * addresses (referring to kernel symbols) do not work. So:
1260b879f1cSjmmv *
1270b879f1cSjmmv * 1) Avoid jumps to absolute addresses (such as gotos and switches).
1280b879f1cSjmmv * 2) To access global variables use their physical address, which
1290b879f1cSjmmv * can be obtained using the RELOC macro.
1300b879f1cSjmmv */
1310b879f1cSjmmv void
multiboot1_pre_reloc(struct multiboot_info * mi)132*43108a21Smanu multiboot1_pre_reloc(struct multiboot_info *mi)
1330b879f1cSjmmv {
1340b879f1cSjmmv #define RELOC(type, x) ((type)((vaddr_t)(x) - KERNBASE))
1350b879f1cSjmmv struct multiboot_info *midest =
1360b879f1cSjmmv RELOC(struct multiboot_info *, &Multiboot_Info);
1370b879f1cSjmmv
138f00c5400Sthorpej *RELOC(bool *, &Multiboot_Loader) = true;
1390b879f1cSjmmv memcpy(midest, mi, sizeof(Multiboot_Info));
1400b879f1cSjmmv
1410b879f1cSjmmv if (mi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE) {
1420b879f1cSjmmv strncpy(RELOC(void *, Multiboot_Cmdline), mi->mi_cmdline,
1430b879f1cSjmmv sizeof(Multiboot_Cmdline));
1440b879f1cSjmmv midest->mi_cmdline = (char *)&Multiboot_Cmdline;
1450b879f1cSjmmv }
1460b879f1cSjmmv
1470b879f1cSjmmv if (mi->mi_flags & MULTIBOOT_INFO_HAS_LOADER_NAME) {
1480b879f1cSjmmv strncpy(RELOC(void *, Multiboot_Loader_Name),
1490b879f1cSjmmv mi->mi_loader_name, sizeof(Multiboot_Loader_Name));
1500b879f1cSjmmv midest->mi_loader_name = (char *)&Multiboot_Loader_Name;
1510b879f1cSjmmv }
1520b879f1cSjmmv
1530b879f1cSjmmv if (mi->mi_flags & MULTIBOOT_INFO_HAS_MMAP) {
1540b879f1cSjmmv memcpy(RELOC(void *, Multiboot_Mmap),
1550b879f1cSjmmv (void *)mi->mi_mmap_addr, mi->mi_mmap_length);
1560b879f1cSjmmv midest->mi_mmap_addr = (vaddr_t)&Multiboot_Mmap;
1570b879f1cSjmmv }
1580b879f1cSjmmv
1590b879f1cSjmmv if (mi->mi_flags & MULTIBOOT_INFO_HAS_DRIVES) {
1600b879f1cSjmmv memcpy(RELOC(void *, Multiboot_Drives),
1610b879f1cSjmmv (void *)mi->mi_drives_addr, mi->mi_drives_length);
1620b879f1cSjmmv midest->mi_drives_addr = (vaddr_t)&Multiboot_Drives;
1630b879f1cSjmmv }
1640b879f1cSjmmv
1650b879f1cSjmmv copy_syms(mi);
1660b879f1cSjmmv #undef RELOC
1670b879f1cSjmmv }
1680b879f1cSjmmv
1690b879f1cSjmmv /* --------------------------------------------------------------------- */
1700b879f1cSjmmv
1710b879f1cSjmmv /*
1720b879f1cSjmmv * Sets up the kernel if it was booted by a Multiboot-compliant boot
1730b879f1cSjmmv * loader. This is executed just after the kernel has relocated itself.
1740b879f1cSjmmv * At this point, executing any kind of code is safe, keeping in mind
1750b879f1cSjmmv * that no devices have been initialized yet (not even the console!).
1760b879f1cSjmmv */
1770b879f1cSjmmv void
multiboot1_post_reloc(void)178*43108a21Smanu multiboot1_post_reloc(void)
1790b879f1cSjmmv {
1800b879f1cSjmmv struct multiboot_info *mi;
1810b879f1cSjmmv
1820b879f1cSjmmv if (! Multiboot_Loader)
1830b879f1cSjmmv return;
1840b879f1cSjmmv
1850b879f1cSjmmv mi = &Multiboot_Info;
1860b879f1cSjmmv bootinfo.bi_nentries = 0;
1870b879f1cSjmmv
1880b879f1cSjmmv setup_memory(mi);
1890b879f1cSjmmv setup_console(mi);
1900b879f1cSjmmv setup_howto(mi);
1910b879f1cSjmmv setup_bootpath(mi);
1920b879f1cSjmmv setup_biosgeom(mi);
1936cf8f1a5Sjmmv setup_bootdisk(mi);
1940b879f1cSjmmv setup_memmap(mi);
1950b879f1cSjmmv }
1960b879f1cSjmmv
1970b879f1cSjmmv /* --------------------------------------------------------------------- */
1980b879f1cSjmmv
1990b879f1cSjmmv /*
2000b879f1cSjmmv * Prints a summary of the information collected in the Multiboot
2010b879f1cSjmmv * information header (if present). Done as a separate function because
2020b879f1cSjmmv * the console has to be available.
2030b879f1cSjmmv */
2040b879f1cSjmmv void
multiboot1_print_info(void)205*43108a21Smanu multiboot1_print_info(void)
2060b879f1cSjmmv {
2070b879f1cSjmmv struct multiboot_info *mi = &Multiboot_Info;
2088d30a464Sjmmv struct multiboot_symbols *ms = &Multiboot_Symbols;
2090b879f1cSjmmv
2100b879f1cSjmmv if (! Multiboot_Loader)
2110b879f1cSjmmv return;
2120b879f1cSjmmv
2130b879f1cSjmmv printf("multiboot: Information structure flags: 0x%08x\n",
2140b879f1cSjmmv mi->mi_flags);
2150b879f1cSjmmv
2160b879f1cSjmmv if (mi->mi_flags & MULTIBOOT_INFO_HAS_LOADER_NAME)
2170b879f1cSjmmv printf("multiboot: Boot loader: %s\n", mi->mi_loader_name);
2180b879f1cSjmmv
2190b879f1cSjmmv if (mi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE)
2200b879f1cSjmmv printf("multiboot: Command line: %s\n", mi->mi_cmdline);
2210b879f1cSjmmv
2220b879f1cSjmmv if (mi->mi_flags & MULTIBOOT_INFO_HAS_MEMORY)
2230b879f1cSjmmv printf("multiboot: %u KB lower memory, %u KB upper memory\n",
2240b879f1cSjmmv mi->mi_mem_lower, mi->mi_mem_upper);
2250b879f1cSjmmv
2268d30a464Sjmmv if (mi->mi_flags & MULTIBOOT_INFO_HAS_ELF_SYMS) {
2278d30a464Sjmmv KASSERT(esym != 0);
2288d30a464Sjmmv printf("multiboot: Symbol table at %p, length %d bytes\n",
2298d30a464Sjmmv ms->s_symstart, ms->s_symsize);
2308d30a464Sjmmv printf("multiboot: String table at %p, length %d bytes\n",
2318d30a464Sjmmv ms->s_strstart, ms->s_strsize);
2328d30a464Sjmmv }
2330b879f1cSjmmv }
2340b879f1cSjmmv
2350b879f1cSjmmv /* --------------------------------------------------------------------- */
2360b879f1cSjmmv
2370b879f1cSjmmv /*
2380b879f1cSjmmv * Adds the bootinfo entry given in 'item' to the bootinfo tables.
2390b879f1cSjmmv * Sets the item type to 'type' and its length to 'len'.
2400b879f1cSjmmv */
2410b879f1cSjmmv static void
bootinfo_add(struct btinfo_common * item,int type,int len)2420b879f1cSjmmv bootinfo_add(struct btinfo_common *item, int type, int len)
2430b879f1cSjmmv {
2440b879f1cSjmmv int i;
2450b879f1cSjmmv struct bootinfo *bip = (struct bootinfo *)&bootinfo;
2460b879f1cSjmmv vaddr_t data;
2470b879f1cSjmmv
2480b879f1cSjmmv item->type = type;
2490b879f1cSjmmv item->len = len;
2500b879f1cSjmmv
2510b879f1cSjmmv data = (vaddr_t)&bip->bi_data;
2520b879f1cSjmmv for (i = 0; i < bip->bi_nentries; i++) {
2530b879f1cSjmmv struct btinfo_common *tmp;
2540b879f1cSjmmv
2550b879f1cSjmmv tmp = (struct btinfo_common *)data;
2560b879f1cSjmmv data += tmp->len;
2570b879f1cSjmmv }
2580b879f1cSjmmv if (data + len < (vaddr_t)&bip->bi_data + sizeof(bip->bi_data)) {
2590b879f1cSjmmv memcpy((void *)data, item, len);
2600b879f1cSjmmv bip->bi_nentries++;
2610b879f1cSjmmv }
2620b879f1cSjmmv }
2630b879f1cSjmmv
2640b879f1cSjmmv /* --------------------------------------------------------------------- */
2650b879f1cSjmmv
2660b879f1cSjmmv /*
2670b879f1cSjmmv * Copies the symbol table and the strings table passed in by the boot
2680b879f1cSjmmv * loader after the kernel's image, and sets up 'esym' accordingly so
2690b879f1cSjmmv * that this data is properly copied into upper memory during relocation.
2700b879f1cSjmmv *
2710b879f1cSjmmv * WARNING: This code runs before the kernel has relocated itself. See
272*43108a21Smanu * the note in multiboot1_pre_reloc() for more information.
2730b879f1cSjmmv */
2740b879f1cSjmmv static void
copy_syms(struct multiboot_info * mi)2750b879f1cSjmmv copy_syms(struct multiboot_info *mi)
2760b879f1cSjmmv {
2770b879f1cSjmmv #define RELOC(type, x) ((type)((vaddr_t)(x) - KERNBASE))
2780b879f1cSjmmv int i;
2798d30a464Sjmmv struct multiboot_symbols *ms;
280d9474223Sjym Elf32_Shdr *symtabp, *strtabp;
281d9474223Sjym Elf32_Word symsize, strsize;
282d9474223Sjym Elf32_Addr symaddr, straddr;
283d9474223Sjym Elf32_Addr symstart, strstart;
2840b879f1cSjmmv
2850b879f1cSjmmv /*
2860b879f1cSjmmv * Check if the Multiboot information header has symbols or not.
2870b879f1cSjmmv */
2880b879f1cSjmmv if (!(mi->mi_flags & MULTIBOOT_INFO_HAS_ELF_SYMS))
2890b879f1cSjmmv return;
2900b879f1cSjmmv
2918d30a464Sjmmv ms = RELOC(struct multiboot_symbols *, &Multiboot_Symbols);
2928d30a464Sjmmv
2930b879f1cSjmmv /*
2940b879f1cSjmmv * Locate a symbol table and its matching string table in the
2950b879f1cSjmmv * section headers passed in by the boot loader. Set 'symtabp'
2960b879f1cSjmmv * and 'strtabp' with pointers to the matching entries.
2970b879f1cSjmmv */
2980b879f1cSjmmv symtabp = strtabp = NULL;
2990b879f1cSjmmv for (i = 0; i < mi->mi_elfshdr_num && symtabp == NULL &&
3000b879f1cSjmmv strtabp == NULL; i++) {
3010b879f1cSjmmv Elf32_Shdr *shdrp;
3020b879f1cSjmmv
3030b879f1cSjmmv shdrp = &((Elf32_Shdr *)mi->mi_elfshdr_addr)[i];
3040b879f1cSjmmv
30548082eb6Smanu if ((shdrp->sh_type == SHT_SYMTAB) &&
3060b879f1cSjmmv shdrp->sh_link != SHN_UNDEF) {
3070b879f1cSjmmv Elf32_Shdr *shdrp2;
3080b879f1cSjmmv
3090b879f1cSjmmv shdrp2 = &((Elf32_Shdr *)mi->mi_elfshdr_addr)
3100b879f1cSjmmv [shdrp->sh_link];
3110b879f1cSjmmv
31248082eb6Smanu if (shdrp2->sh_type == SHT_STRTAB) {
3130b879f1cSjmmv symtabp = shdrp;
3140b879f1cSjmmv strtabp = shdrp2;
3150b879f1cSjmmv }
3160b879f1cSjmmv }
3170b879f1cSjmmv }
3180b879f1cSjmmv if (symtabp == NULL || strtabp == NULL)
3190b879f1cSjmmv return;
3200b879f1cSjmmv
3218d30a464Sjmmv symaddr = symtabp->sh_addr;
3228d30a464Sjmmv straddr = strtabp->sh_addr;
3238d30a464Sjmmv symsize = symtabp->sh_size;
3248d30a464Sjmmv strsize = strtabp->sh_size;
3250b879f1cSjmmv
3260b879f1cSjmmv /*
3278d30a464Sjmmv * Copy the symbol and string tables just after the kernel's
3288d30a464Sjmmv * end address, in this order. Only the contents of these ELF
3298d30a464Sjmmv * sections are copied; headers are discarded. esym is later
3308d30a464Sjmmv * updated to point to the lowest "free" address after the tables
3318d30a464Sjmmv * so that they are mapped appropriately when enabling paging.
3320b879f1cSjmmv *
3338d30a464Sjmmv * We need to be careful to not overwrite valid data doing the
3348d30a464Sjmmv * copies, hence all the different cases below. We can assume
3358d30a464Sjmmv * that if the tables start before the kernel's end address,
3368d30a464Sjmmv * they will not grow over this address.
3370b879f1cSjmmv */
338d9474223Sjym if ((void *)symtabp < RELOC(void *, &end) &&
339d9474223Sjym (void *)strtabp < RELOC(void *, &end)) {
340d9474223Sjym symstart = RELOC(Elf32_Addr, &end);
3418d30a464Sjmmv strstart = symstart + symsize;
342542717e7Sgsutre memcpy((void *)symstart, (void *)symaddr, symsize);
343542717e7Sgsutre memcpy((void *)strstart, (void *)straddr, strsize);
344d9474223Sjym } else if ((void *)symtabp > RELOC(void *, &end) &&
345d9474223Sjym (void *)strtabp < RELOC(void *, &end)) {
346d9474223Sjym symstart = RELOC(Elf32_Addr, &end);
3478d30a464Sjmmv strstart = symstart + symsize;
348542717e7Sgsutre memcpy((void *)symstart, (void *)symaddr, symsize);
349542717e7Sgsutre memcpy((void *)strstart, (void *)straddr, strsize);
350d9474223Sjym } else if ((void *)symtabp < RELOC(void *, &end) &&
351d9474223Sjym (void *)strtabp > RELOC(void *, &end)) {
352d9474223Sjym strstart = RELOC(Elf32_Addr, &end);
3538d30a464Sjmmv symstart = strstart + strsize;
354542717e7Sgsutre memcpy((void *)strstart, (void *)straddr, strsize);
355542717e7Sgsutre memcpy((void *)symstart, (void *)symaddr, symsize);
3568d30a464Sjmmv } else {
3578d30a464Sjmmv /* symtabp and strtabp are both over end */
358d9474223Sjym if (symtabp < strtabp) {
359d9474223Sjym symstart = RELOC(Elf32_Addr, &end);
3608d30a464Sjmmv strstart = symstart + symsize;
361542717e7Sgsutre memcpy((void *)symstart, (void *)symaddr, symsize);
362542717e7Sgsutre memcpy((void *)strstart, (void *)straddr, strsize);
3638d30a464Sjmmv } else {
364d9474223Sjym strstart = RELOC(Elf32_Addr, &end);
3658d30a464Sjmmv symstart = strstart + strsize;
3668d30a464Sjmmv memcpy((void *)strstart, (void *)straddr, strsize);
3678d30a464Sjmmv memcpy((void *)symstart, (void *)symaddr, symsize);
368542717e7Sgsutre }
369542717e7Sgsutre }
370d9474223Sjym
371bf266e55Sjmmv *RELOC(int *, &esym) =
372bf266e55Sjmmv (int)(symstart + symsize + strsize + KERNBASE);
3730b879f1cSjmmv
37453524e44Schristos ms->s_symstart = (void *)(symstart + KERNBASE);
3758d30a464Sjmmv ms->s_symsize = symsize;
37653524e44Schristos ms->s_strstart = (void *)(strstart + KERNBASE);
3778d30a464Sjmmv ms->s_strsize = strsize;
3780b879f1cSjmmv #undef RELOC
3790b879f1cSjmmv }
3800b879f1cSjmmv
3810b879f1cSjmmv /* --------------------------------------------------------------------- */
3820b879f1cSjmmv
3830b879f1cSjmmv /*
3840b879f1cSjmmv * Sets up the biosgeom bootinfo structure if the Multiboot information
3850b879f1cSjmmv * structure provides information about disk drives.
3860b879f1cSjmmv */
3870b879f1cSjmmv static void
setup_biosgeom(struct multiboot_info * mi)3880b879f1cSjmmv setup_biosgeom(struct multiboot_info *mi)
3890b879f1cSjmmv {
3900b879f1cSjmmv size_t pos;
3910b879f1cSjmmv uint8_t bidata[1024];
3920b879f1cSjmmv struct btinfo_biosgeom *bi;
3930b879f1cSjmmv
3940b879f1cSjmmv if (!(mi->mi_flags & MULTIBOOT_INFO_HAS_DRIVES))
3950b879f1cSjmmv return;
3960b879f1cSjmmv
3970b879f1cSjmmv memset(bidata, 0, sizeof(bidata));
3980b879f1cSjmmv bi = (struct btinfo_biosgeom *)bidata;
3990b879f1cSjmmv pos = 0;
4000b879f1cSjmmv
4010b879f1cSjmmv while (pos < mi->mi_drives_length) {
4020b879f1cSjmmv struct multiboot_drive *md;
4030b879f1cSjmmv struct bi_biosgeom_entry bbe;
4040b879f1cSjmmv
4050b879f1cSjmmv md = (struct multiboot_drive *)
4060b879f1cSjmmv &((uint8_t *)mi->mi_drives_addr)[pos];
4070b879f1cSjmmv
4080b879f1cSjmmv memset(&bbe, 0, sizeof(bbe));
4090b879f1cSjmmv bbe.sec = md->md_sectors;
4100b879f1cSjmmv bbe.head = md->md_heads;
4110b879f1cSjmmv bbe.cyl = md->md_cylinders;
4120b879f1cSjmmv bbe.dev = md->md_number;
4130b879f1cSjmmv
4140b879f1cSjmmv memcpy(&bi->disk[bi->num], &bbe, sizeof(bbe));
4150b879f1cSjmmv bi->num++;
4160b879f1cSjmmv
4170b879f1cSjmmv pos += md->md_length;
4180b879f1cSjmmv }
4190b879f1cSjmmv
4200b879f1cSjmmv bootinfo_add((struct btinfo_common *)bi, BTINFO_BIOSGEOM,
4210b879f1cSjmmv sizeof(struct btinfo_biosgeom) +
4220b879f1cSjmmv bi->num * sizeof(struct bi_biosgeom_entry));
4230b879f1cSjmmv }
4240b879f1cSjmmv
4250b879f1cSjmmv /* --------------------------------------------------------------------- */
4260b879f1cSjmmv
4270b879f1cSjmmv /*
4280b879f1cSjmmv * Sets up the default root device if the Multiboot information
4290b879f1cSjmmv * structure provides information about the boot drive (where the kernel
4300b879f1cSjmmv * image was loaded from) or if the user gave a 'root' parameter on the
4310b879f1cSjmmv * boot command line.
4320b879f1cSjmmv */
4330b879f1cSjmmv static void
setup_bootdisk(struct multiboot_info * mi)4340b879f1cSjmmv setup_bootdisk(struct multiboot_info *mi)
4350b879f1cSjmmv {
436712239e3Sthorpej bool found;
4370b879f1cSjmmv struct btinfo_rootdevice bi;
4380b879f1cSjmmv
439f00c5400Sthorpej found = false;
4400b879f1cSjmmv
4410b879f1cSjmmv if (mi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE)
4420b879f1cSjmmv found = optstr_get(mi->mi_cmdline, "root", bi.devname,
4430b879f1cSjmmv sizeof(bi.devname));
4440b879f1cSjmmv
4450b879f1cSjmmv if (!found && (mi->mi_flags & MULTIBOOT_INFO_HAS_BOOT_DEVICE)) {
4460b879f1cSjmmv const char *devprefix;
4470b879f1cSjmmv
4489485c8d2Sjmmv /* Attempt to match the BIOS boot disk to a device. There
4499485c8d2Sjmmv * is not much we can do to get it right. (Well, strictly
4509485c8d2Sjmmv * speaking, we could, but it is certainly not worth the
4519485c8d2Sjmmv * extra effort.) */
4520b879f1cSjmmv switch (mi->mi_boot_device_drive) {
4530b879f1cSjmmv case 0x00: devprefix = "fd0"; break;
4540b879f1cSjmmv case 0x01: devprefix = "fd1"; break;
4556cf8f1a5Sjmmv case 0x80: devprefix = "wd0"; break;
4566cf8f1a5Sjmmv case 0x81: devprefix = "wd1"; break;
4576cf8f1a5Sjmmv case 0x82: devprefix = "wd2"; break;
4586cf8f1a5Sjmmv case 0x83: devprefix = "wd3"; break;
4599485c8d2Sjmmv default: devprefix = "wd0";
4600b879f1cSjmmv }
4610b879f1cSjmmv
4620b879f1cSjmmv strcpy(bi.devname, devprefix);
4630b879f1cSjmmv if (mi->mi_boot_device_part2 != 0xFF)
4640b879f1cSjmmv bi.devname[3] = mi->mi_boot_device_part2 + 'a';
4650b879f1cSjmmv else
4660b879f1cSjmmv bi.devname[3] = 'a';
4670b879f1cSjmmv bi.devname[4] = '\0';
4680b879f1cSjmmv
469f00c5400Sthorpej found = true;
4700b879f1cSjmmv }
4710b879f1cSjmmv
4720b879f1cSjmmv if (found) {
4730b879f1cSjmmv bootinfo_add((struct btinfo_common *)&bi, BTINFO_ROOTDEVICE,
4740b879f1cSjmmv sizeof(struct btinfo_rootdevice));
4750b879f1cSjmmv }
4760b879f1cSjmmv }
4770b879f1cSjmmv
4780b879f1cSjmmv /* --------------------------------------------------------------------- */
4790b879f1cSjmmv
4800b879f1cSjmmv /*
4810b879f1cSjmmv * Sets up the bootpath bootinfo structure with an appropriate kernel
4820b879f1cSjmmv * name derived from the boot command line. The Multiboot information
4830b879f1cSjmmv * structure does not provide this detail directly, so we try to derive
4840b879f1cSjmmv * it from the command line setting.
4850b879f1cSjmmv */
4860b879f1cSjmmv static void
setup_bootpath(struct multiboot_info * mi)4870b879f1cSjmmv setup_bootpath(struct multiboot_info *mi)
4880b879f1cSjmmv {
4890b879f1cSjmmv struct btinfo_bootpath bi;
4900b879f1cSjmmv char *cl, *cl2, old;
4910b879f1cSjmmv int len;
4920b879f1cSjmmv
4930b879f1cSjmmv if (strncmp(Multiboot_Loader_Name, "GNU GRUB ",
4940b879f1cSjmmv sizeof(Multiboot_Loader_Name)) > 0) {
4950b879f1cSjmmv cl = mi->mi_cmdline;
4960b879f1cSjmmv while (*cl != '\0' && *cl != '/')
4970b879f1cSjmmv cl++;
4980b879f1cSjmmv cl2 = cl;
4990b879f1cSjmmv len = 0;
5000b879f1cSjmmv while (*cl2 != '\0' && *cl2 != ' ') {
5010b879f1cSjmmv len++;
5020b879f1cSjmmv cl2++;
5030b879f1cSjmmv }
5040b879f1cSjmmv
5050b879f1cSjmmv old = *cl2;
5060b879f1cSjmmv *cl2 = '\0';
5070b879f1cSjmmv memcpy(bi.bootpath, cl, MIN(sizeof(bi.bootpath), len));
5080b879f1cSjmmv *cl2 = old;
5093c18863aSmsaitoh bi.bootpath[MIN(sizeof(bi.bootpath) - 1, len)] = '\0';
5100b879f1cSjmmv
5110b879f1cSjmmv bootinfo_add((struct btinfo_common *)&bi, BTINFO_BOOTPATH,
5120b879f1cSjmmv sizeof(struct btinfo_bootpath));
5130b879f1cSjmmv }
5140b879f1cSjmmv }
5150b879f1cSjmmv
5160b879f1cSjmmv /* --------------------------------------------------------------------- */
5170b879f1cSjmmv
5180b879f1cSjmmv /*
5190b879f1cSjmmv * Sets up the console bootinfo structure if the user gave a 'console'
5200b879f1cSjmmv * argument on the boot command line. The Multiboot information
5210b879f1cSjmmv * structure gives no hint about this, so the only way to know where the
52238106bafSmsaitoh * console is to let the user specify it.
5230b879f1cSjmmv *
5240b879f1cSjmmv * If there wasn't any 'console' argument, this does not generate any
5250b879f1cSjmmv * bootinfo entry, falling back to the kernel's default console.
5260b879f1cSjmmv *
5270b879f1cSjmmv * If there weren't any of 'console_speed' or 'console_addr' arguments,
5280b879f1cSjmmv * this falls back to the default values for the serial port.
5290b879f1cSjmmv */
5300b879f1cSjmmv static void
setup_console(struct multiboot_info * mi)5310b879f1cSjmmv setup_console(struct multiboot_info *mi)
5320b879f1cSjmmv {
5330b879f1cSjmmv struct btinfo_console bi;
534712239e3Sthorpej bool found;
5350b879f1cSjmmv
536f00c5400Sthorpej found = false;
5370b879f1cSjmmv
5380b879f1cSjmmv if (mi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE)
5390b879f1cSjmmv found = optstr_get(mi->mi_cmdline, "console", bi.devname,
5400b879f1cSjmmv sizeof(bi.devname));
5410b879f1cSjmmv
5420b879f1cSjmmv if (found) {
543a0228be4Sjmmv bool valid;
544a0228be4Sjmmv
5450b879f1cSjmmv if (strncmp(bi.devname, "com", sizeof(bi.devname)) == 0) {
5460b879f1cSjmmv char tmp[10];
5470b879f1cSjmmv
5480b879f1cSjmmv found = optstr_get(mi->mi_cmdline, "console_speed",
5490b879f1cSjmmv tmp, sizeof(tmp));
5500b879f1cSjmmv if (found)
5510b879f1cSjmmv bi.speed = strtoul(tmp, NULL, 10);
5520b879f1cSjmmv else
5530b879f1cSjmmv bi.speed = 0; /* Use default speed. */
5540b879f1cSjmmv
5550b879f1cSjmmv found = optstr_get(mi->mi_cmdline, "console_addr",
5560b879f1cSjmmv tmp, sizeof(tmp));
5570b879f1cSjmmv if (found) {
5580b879f1cSjmmv if (tmp[0] == '0' && tmp[1] == 'x')
5590b879f1cSjmmv bi.addr = strtoul(tmp + 2, NULL, 16);
5600b879f1cSjmmv else
5610b879f1cSjmmv bi.addr = strtoul(tmp, NULL, 10);
5620b879f1cSjmmv } else
5630b879f1cSjmmv bi.addr = 0; /* Use default address. */
5640b879f1cSjmmv
565a0228be4Sjmmv valid = true;
566a0228be4Sjmmv } else if (strncmp(bi.devname, "pc", sizeof(bi.devname)) == 0)
567a0228be4Sjmmv valid = true;
568a0228be4Sjmmv else
569a0228be4Sjmmv valid = false;
570a0228be4Sjmmv
571a0228be4Sjmmv if (valid)
572a0228be4Sjmmv bootinfo_add((struct btinfo_common *)&bi,
573a0228be4Sjmmv BTINFO_CONSOLE, sizeof(struct btinfo_console));
5740b879f1cSjmmv }
5750b879f1cSjmmv }
5760b879f1cSjmmv
5770b879f1cSjmmv /* --------------------------------------------------------------------- */
5780b879f1cSjmmv
5790b879f1cSjmmv /*
5800b879f1cSjmmv * Sets up the 'boothowto' variable based on the options given in the
5810b879f1cSjmmv * boot command line, if any.
5820b879f1cSjmmv */
5830b879f1cSjmmv static void
setup_howto(struct multiboot_info * mi)5840b879f1cSjmmv setup_howto(struct multiboot_info *mi)
5850b879f1cSjmmv {
5860b879f1cSjmmv char *cl;
5870b879f1cSjmmv
5880b879f1cSjmmv if (!(mi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE))
5890b879f1cSjmmv return;
5900b879f1cSjmmv
5910b879f1cSjmmv cl = mi->mi_cmdline;
5920b879f1cSjmmv
5930b879f1cSjmmv /* Skip kernel file name. */
5940b879f1cSjmmv while (*cl != '\0' && *cl != ' ')
5950b879f1cSjmmv cl++;
5965959d669Sdholland while (*cl == ' ')
5970b879f1cSjmmv cl++;
5980b879f1cSjmmv
5990b879f1cSjmmv /* Check if there are flags and set 'howto' accordingly. */
6000b879f1cSjmmv if (*cl == '-') {
6010b879f1cSjmmv int howto = 0;
6020b879f1cSjmmv
6030b879f1cSjmmv cl++;
6040b879f1cSjmmv while (*cl != '\0' && *cl != ' ') {
6050b879f1cSjmmv BOOT_FLAG(*cl, howto);
6060b879f1cSjmmv cl++;
6070b879f1cSjmmv }
6080b879f1cSjmmv if (*cl == ' ')
6090b879f1cSjmmv cl++;
6100b879f1cSjmmv
6110b879f1cSjmmv boothowto = howto;
6120b879f1cSjmmv }
6130b879f1cSjmmv }
6140b879f1cSjmmv
6150b879f1cSjmmv /* --------------------------------------------------------------------- */
6160b879f1cSjmmv
6170b879f1cSjmmv /*
6180b879f1cSjmmv * Sets up the memmap bootinfo structure to describe available memory as
6190b879f1cSjmmv * given by the BIOS.
6200b879f1cSjmmv */
6210b879f1cSjmmv static void
setup_memmap(struct multiboot_info * mi)6220b879f1cSjmmv setup_memmap(struct multiboot_info *mi)
6230b879f1cSjmmv {
6240b879f1cSjmmv char data[1024];
6250b879f1cSjmmv size_t i;
6260b879f1cSjmmv struct btinfo_memmap *bi;
6270b879f1cSjmmv
6280b879f1cSjmmv if (!(mi->mi_flags & MULTIBOOT_INFO_HAS_MMAP))
6290b879f1cSjmmv return;
6300b879f1cSjmmv
6310b879f1cSjmmv bi = (struct btinfo_memmap *)data;
6320b879f1cSjmmv bi->num = 0;
6330b879f1cSjmmv
6340b879f1cSjmmv i = 0;
6350b879f1cSjmmv while (i < mi->mi_mmap_length) {
6360b879f1cSjmmv struct multiboot_mmap *mm;
6370b879f1cSjmmv struct bi_memmap_entry *bie;
6380b879f1cSjmmv
6390b879f1cSjmmv bie = &bi->entry[bi->num];
6400b879f1cSjmmv
6410b879f1cSjmmv mm = (struct multiboot_mmap *)(mi->mi_mmap_addr + i);
6420b879f1cSjmmv bie->addr = mm->mm_base_addr;
6430b879f1cSjmmv bie->size = mm->mm_length;
6440b879f1cSjmmv if (mm->mm_type == 1)
6450b879f1cSjmmv bie->type = BIM_Memory;
6460b879f1cSjmmv else
6470b879f1cSjmmv bie->type = BIM_Reserved;
6480b879f1cSjmmv
6490b879f1cSjmmv bi->num++;
6500b879f1cSjmmv i += mm->mm_size + 4;
6510b879f1cSjmmv }
6520b879f1cSjmmv
6530b879f1cSjmmv bootinfo_add((struct btinfo_common *)bi, BTINFO_MEMMAP,
6540b879f1cSjmmv sizeof(data));
6550b879f1cSjmmv }
6560b879f1cSjmmv
6570b879f1cSjmmv /* --------------------------------------------------------------------- */
6580b879f1cSjmmv
6590b879f1cSjmmv /*
6600b879f1cSjmmv * Sets up the 'biosbasemem' and 'biosextmem' variables if the
6610b879f1cSjmmv * Multiboot information structure provides information about memory.
6620b879f1cSjmmv */
6630b879f1cSjmmv static void
setup_memory(struct multiboot_info * mi)6640b879f1cSjmmv setup_memory(struct multiboot_info *mi)
6650b879f1cSjmmv {
66695543a8eSmrg
6670b879f1cSjmmv if (!(mi->mi_flags & MULTIBOOT_INFO_HAS_MEMORY))
6680b879f1cSjmmv return;
6690b879f1cSjmmv
67095543a8eSmrg /* Make sure we don't override user-set variables. */
67195543a8eSmrg if (biosbasemem == 0) {
6720b879f1cSjmmv biosbasemem = mi->mi_mem_lower;
67395543a8eSmrg biosmem_implicit = 1;
67495543a8eSmrg }
67595543a8eSmrg if (biosextmem == 0) {
6760b879f1cSjmmv biosextmem = mi->mi_mem_upper;
67795543a8eSmrg biosmem_implicit = 1;
67895543a8eSmrg }
6790b879f1cSjmmv }
6800b879f1cSjmmv
6810b879f1cSjmmv /* --------------------------------------------------------------------- */
6820b879f1cSjmmv
6830b879f1cSjmmv /*
6848d30a464Sjmmv * Sets up the initial kernel symbol table. Returns true if this was
6858d30a464Sjmmv * passed in by Multiboot; false otherwise.
6860b879f1cSjmmv */
687712239e3Sthorpej bool
multiboot1_ksyms_addsyms_elf(void)688*43108a21Smanu multiboot1_ksyms_addsyms_elf(void)
6890b879f1cSjmmv {
6908d30a464Sjmmv struct multiboot_info *mi = &Multiboot_Info;
6918d30a464Sjmmv struct multiboot_symbols *ms = &Multiboot_Symbols;
6920b879f1cSjmmv
693*43108a21Smanu if (! Multiboot_Loader)
694*43108a21Smanu return false;
695*43108a21Smanu
6968d30a464Sjmmv if (mi->mi_flags & MULTIBOOT_INFO_HAS_ELF_SYMS) {
697c3429f80Sjmmv Elf32_Ehdr ehdr;
698c3429f80Sjmmv
6998d30a464Sjmmv KASSERT(esym != 0);
7000b879f1cSjmmv
701c3429f80Sjmmv memcpy(ehdr.e_ident, ELFMAG, SELFMAG);
702c3429f80Sjmmv ehdr.e_ident[EI_CLASS] = ELFCLASS32;
703c3429f80Sjmmv ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
704c3429f80Sjmmv ehdr.e_ident[EI_VERSION] = EV_CURRENT;
705c3429f80Sjmmv ehdr.e_type = ET_EXEC;
706c3429f80Sjmmv ehdr.e_machine = EM_386;
707c3429f80Sjmmv ehdr.e_version = 1;
708c3429f80Sjmmv ehdr.e_ehsize = sizeof(ehdr);
709c3429f80Sjmmv
710719a906eSmartin ksyms_addsyms_explicit((void *)&ehdr,
711c3429f80Sjmmv ms->s_symstart, ms->s_symsize,
7128d30a464Sjmmv ms->s_strstart, ms->s_strsize);
7138d30a464Sjmmv }
7140b879f1cSjmmv
7158d30a464Sjmmv return mi->mi_flags & MULTIBOOT_INFO_HAS_ELF_SYMS;
7160b879f1cSjmmv }
717