1 /*        $NetBSD: multiboot.c,v 1.26 2019/10/18 01:38:28 manu Exp $  */
2 
3 /*-
4  * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Julio M. Merino Vidal.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: multiboot.c,v 1.26 2019/10/18 01:38:28 manu Exp $");
34 
35 #include "opt_multiboot.h"
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/cdefs_elf.h>
40 #include <sys/boot_flag.h>
41 #include <sys/exec.h>
42 #include <sys/exec_elf.h>
43 #include <sys/optstr.h>
44 #include <sys/ksyms.h>
45 
46 #include <machine/bootinfo.h>
47 #include <machine/multiboot.h>
48 
49 #if !defined(MULTIBOOT)
50 #  error "MULTIBOOT not defined; this cannot happen."
51 #endif
52 
53 /* --------------------------------------------------------------------- */
54 
55 /*
56  * Symbol and string table for the loaded kernel.
57  */
58 
59 struct multiboot_symbols {
60           void *              s_symstart;
61           size_t              s_symsize;
62           void *              s_strstart;
63           size_t              s_strsize;
64 };
65 
66 /* --------------------------------------------------------------------- */
67 
68 /*
69  * External variables.  All of them, with the exception of 'end', must
70  * be set at some point within this file.
71  *
72  * XXX these should be found in a header file!
73  */
74 extern int                    biosbasemem;
75 extern int                    biosextmem;
76 extern int                    biosmem_implicit;
77 extern int                    boothowto;
78 extern struct bootinfo        bootinfo;
79 extern int                    end;
80 extern int *                  esym;
81 
82 /* --------------------------------------------------------------------- */
83 
84 /*
85  * Copy of the Multiboot information structure passed to us by the boot
86  * loader.  The Multiboot_Info structure has some pointers adjusted to the
87  * other variables -- see multiboot1_pre_reloc() -- so you oughtn't access
88  * them directly.  In other words, always access them through the
89  * Multiboot_Info variable.
90  */
91 static char                             Multiboot_Cmdline[255];
92 static uint8_t                          Multiboot_Drives[255];
93 static struct multiboot_info  Multiboot_Info;
94 static bool                             Multiboot_Loader = false;
95 static char                             Multiboot_Loader_Name[255];
96 static uint8_t                          Multiboot_Mmap[1024];
97 static struct multiboot_symbols         Multiboot_Symbols;
98 
99 /* --------------------------------------------------------------------- */
100 
101 /*
102  * Prototypes for private functions.
103  */
104 static void         bootinfo_add(struct btinfo_common *, int, int);
105 static void         copy_syms(struct multiboot_info *);
106 static void         setup_biosgeom(struct multiboot_info *);
107 static void         setup_bootdisk(struct multiboot_info *);
108 static void         setup_bootpath(struct multiboot_info *);
109 static void         setup_console(struct multiboot_info *);
110 static void         setup_howto(struct multiboot_info *);
111 static void         setup_memory(struct multiboot_info *);
112 static void         setup_memmap(struct multiboot_info *);
113 
114 /* --------------------------------------------------------------------- */
115 
116 /*
117  * Sets up the kernel if it was booted by a Multiboot-compliant boot
118  * loader.  This is executed before the kernel has relocated itself.
119  * The main purpose of this function is to copy all the information
120  * passed in by the boot loader to a safe place, so that it is available
121  * after it has been relocated.
122  *
123  * WARNING: Because the kernel has not yet relocated itself to KERNBASE,
124  * special care has to be taken when accessing memory because absolute
125  * addresses (referring to kernel symbols) do not work.  So:
126  *
127  *     1) Avoid jumps to absolute addresses (such as gotos and switches).
128  *     2) To access global variables use their physical address, which
129  *        can be obtained using the RELOC macro.
130  */
131 void
multiboot1_pre_reloc(struct multiboot_info * mi)132 multiboot1_pre_reloc(struct multiboot_info *mi)
133 {
134 #define RELOC(type, x) ((type)((vaddr_t)(x) - KERNBASE))
135           struct multiboot_info *midest =
136               RELOC(struct multiboot_info *, &Multiboot_Info);
137 
138           *RELOC(bool *, &Multiboot_Loader) = true;
139           memcpy(midest, mi, sizeof(Multiboot_Info));
140 
141           if (mi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE) {
142                     strncpy(RELOC(void *, Multiboot_Cmdline), mi->mi_cmdline,
143                         sizeof(Multiboot_Cmdline));
144                     midest->mi_cmdline = (char *)&Multiboot_Cmdline;
145           }
146 
147           if (mi->mi_flags & MULTIBOOT_INFO_HAS_LOADER_NAME) {
148                     strncpy(RELOC(void *, Multiboot_Loader_Name),
149                         mi->mi_loader_name, sizeof(Multiboot_Loader_Name));
150                     midest->mi_loader_name = (char *)&Multiboot_Loader_Name;
151           }
152 
153           if (mi->mi_flags & MULTIBOOT_INFO_HAS_MMAP) {
154                     memcpy(RELOC(void *, Multiboot_Mmap),
155                         (void *)mi->mi_mmap_addr, mi->mi_mmap_length);
156                     midest->mi_mmap_addr = (vaddr_t)&Multiboot_Mmap;
157           }
158 
159           if (mi->mi_flags & MULTIBOOT_INFO_HAS_DRIVES) {
160                     memcpy(RELOC(void *, Multiboot_Drives),
161                         (void *)mi->mi_drives_addr, mi->mi_drives_length);
162                     midest->mi_drives_addr = (vaddr_t)&Multiboot_Drives;
163           }
164 
165           copy_syms(mi);
166 #undef RELOC
167 }
168 
169 /* --------------------------------------------------------------------- */
170 
171 /*
172  * Sets up the kernel if it was booted by a Multiboot-compliant boot
173  * loader.  This is executed just after the kernel has relocated itself.
174  * At this point, executing any kind of code is safe, keeping in mind
175  * that no devices have been initialized yet (not even the console!).
176  */
177 void
multiboot1_post_reloc(void)178 multiboot1_post_reloc(void)
179 {
180           struct multiboot_info *mi;
181 
182           if (! Multiboot_Loader)
183                     return;
184 
185           mi = &Multiboot_Info;
186           bootinfo.bi_nentries = 0;
187 
188           setup_memory(mi);
189           setup_console(mi);
190           setup_howto(mi);
191           setup_bootpath(mi);
192           setup_biosgeom(mi);
193           setup_bootdisk(mi);
194           setup_memmap(mi);
195 }
196 
197 /* --------------------------------------------------------------------- */
198 
199 /*
200  * Prints a summary of the information collected in the Multiboot
201  * information header (if present).  Done as a separate function because
202  * the console has to be available.
203  */
204 void
multiboot1_print_info(void)205 multiboot1_print_info(void)
206 {
207           struct multiboot_info *mi = &Multiboot_Info;
208           struct multiboot_symbols *ms = &Multiboot_Symbols;
209 
210           if (! Multiboot_Loader)
211                     return;
212 
213           printf("multiboot: Information structure flags: 0x%08x\n",
214               mi->mi_flags);
215 
216           if (mi->mi_flags & MULTIBOOT_INFO_HAS_LOADER_NAME)
217                     printf("multiboot: Boot loader: %s\n", mi->mi_loader_name);
218 
219           if (mi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE)
220                     printf("multiboot: Command line: %s\n", mi->mi_cmdline);
221 
222           if (mi->mi_flags & MULTIBOOT_INFO_HAS_MEMORY)
223                     printf("multiboot: %u KB lower memory, %u KB upper memory\n",
224                         mi->mi_mem_lower, mi->mi_mem_upper);
225 
226           if (mi->mi_flags & MULTIBOOT_INFO_HAS_ELF_SYMS) {
227                     KASSERT(esym != 0);
228                     printf("multiboot: Symbol table at %p, length %d bytes\n",
229                         ms->s_symstart, ms->s_symsize);
230                     printf("multiboot: String table at %p, length %d bytes\n",
231                         ms->s_strstart, ms->s_strsize);
232           }
233 }
234 
235 /* --------------------------------------------------------------------- */
236 
237 /*
238  * Adds the bootinfo entry given in 'item' to the bootinfo tables.
239  * Sets the item type to 'type' and its length to 'len'.
240  */
241 static void
bootinfo_add(struct btinfo_common * item,int type,int len)242 bootinfo_add(struct btinfo_common *item, int type, int len)
243 {
244           int i;
245           struct bootinfo *bip = (struct bootinfo *)&bootinfo;
246           vaddr_t data;
247 
248           item->type = type;
249           item->len = len;
250 
251           data = (vaddr_t)&bip->bi_data;
252           for (i = 0; i < bip->bi_nentries; i++) {
253                     struct btinfo_common *tmp;
254 
255                     tmp = (struct btinfo_common *)data;
256                     data += tmp->len;
257           }
258           if (data + len < (vaddr_t)&bip->bi_data + sizeof(bip->bi_data)) {
259                     memcpy((void *)data, item, len);
260                     bip->bi_nentries++;
261           }
262 }
263 
264 /* --------------------------------------------------------------------- */
265 
266 /*
267  * Copies the symbol table and the strings table passed in by the boot
268  * loader after the kernel's image, and sets up 'esym' accordingly so
269  * that this data is properly copied into upper memory during relocation.
270  *
271  * WARNING: This code runs before the kernel has relocated itself.  See
272  * the note in multiboot1_pre_reloc() for more information.
273  */
274 static void
copy_syms(struct multiboot_info * mi)275 copy_syms(struct multiboot_info *mi)
276 {
277 #define RELOC(type, x) ((type)((vaddr_t)(x) - KERNBASE))
278           int i;
279           struct multiboot_symbols *ms;
280           Elf32_Shdr *symtabp, *strtabp;
281           Elf32_Word symsize, strsize;
282           Elf32_Addr symaddr, straddr;
283           Elf32_Addr symstart, strstart;
284 
285           /*
286            * Check if the Multiboot information header has symbols or not.
287            */
288           if (!(mi->mi_flags & MULTIBOOT_INFO_HAS_ELF_SYMS))
289                     return;
290 
291           ms = RELOC(struct multiboot_symbols *, &Multiboot_Symbols);
292 
293           /*
294            * Locate a symbol table and its matching string table in the
295            * section headers passed in by the boot loader.  Set 'symtabp'
296            * and 'strtabp' with pointers to the matching entries.
297            */
298           symtabp = strtabp = NULL;
299           for (i = 0; i < mi->mi_elfshdr_num && symtabp == NULL &&
300               strtabp == NULL; i++) {
301                     Elf32_Shdr *shdrp;
302 
303                     shdrp = &((Elf32_Shdr *)mi->mi_elfshdr_addr)[i];
304 
305                     if ((shdrp->sh_type == SHT_SYMTAB) &&
306                         shdrp->sh_link != SHN_UNDEF) {
307                               Elf32_Shdr *shdrp2;
308 
309                               shdrp2 = &((Elf32_Shdr *)mi->mi_elfshdr_addr)
310                                   [shdrp->sh_link];
311 
312                               if (shdrp2->sh_type == SHT_STRTAB) {
313                                         symtabp = shdrp;
314                                         strtabp = shdrp2;
315                               }
316                     }
317           }
318           if (symtabp == NULL || strtabp == NULL)
319                     return;
320 
321           symaddr = symtabp->sh_addr;
322           straddr = strtabp->sh_addr;
323           symsize = symtabp->sh_size;
324           strsize = strtabp->sh_size;
325 
326           /*
327            * Copy the symbol and string tables just after the kernel's
328            * end address, in this order.  Only the contents of these ELF
329            * sections are copied; headers are discarded.  esym is later
330            * updated to point to the lowest "free" address after the tables
331            * so that they are mapped appropriately when enabling paging.
332            *
333            * We need to be careful to not overwrite valid data doing the
334            * copies, hence all the different cases below.  We can assume
335            * that if the tables start before the kernel's end address,
336            * they will not grow over this address.
337            */
338         if ((void *)symtabp < RELOC(void *, &end) &&
339               (void *)strtabp < RELOC(void *, &end)) {
340                     symstart = RELOC(Elf32_Addr, &end);
341                     strstart = symstart + symsize;
342                     memcpy((void *)symstart, (void *)symaddr, symsize);
343                     memcpy((void *)strstart, (void *)straddr, strsize);
344         } else if ((void *)symtabp > RELOC(void *, &end) &&
345                      (void *)strtabp < RELOC(void *, &end)) {
346                     symstart = RELOC(Elf32_Addr, &end);
347                     strstart = symstart + symsize;
348                     memcpy((void *)symstart, (void *)symaddr, symsize);
349                     memcpy((void *)strstart, (void *)straddr, strsize);
350         } else if ((void *)symtabp < RELOC(void *, &end) &&
351                      (void *)strtabp > RELOC(void *, &end)) {
352                     strstart = RELOC(Elf32_Addr, &end);
353                     symstart = strstart + strsize;
354                     memcpy((void *)strstart, (void *)straddr, strsize);
355                     memcpy((void *)symstart, (void *)symaddr, symsize);
356           } else {
357                     /* symtabp and strtabp are both over end */
358                     if (symtabp < strtabp) {
359                               symstart = RELOC(Elf32_Addr, &end);
360                               strstart = symstart + symsize;
361                               memcpy((void *)symstart, (void *)symaddr, symsize);
362                               memcpy((void *)strstart, (void *)straddr, strsize);
363                     } else {
364                               strstart = RELOC(Elf32_Addr, &end);
365                               symstart = strstart + strsize;
366                               memcpy((void *)strstart, (void *)straddr, strsize);
367                               memcpy((void *)symstart, (void *)symaddr, symsize);
368                     }
369           }
370 
371           *RELOC(int *, &esym) =
372               (int)(symstart + symsize + strsize + KERNBASE);
373 
374           ms->s_symstart = (void *)(symstart + KERNBASE);
375           ms->s_symsize  = symsize;
376           ms->s_strstart = (void *)(strstart + KERNBASE);
377           ms->s_strsize  = strsize;
378 #undef RELOC
379 }
380 
381 /* --------------------------------------------------------------------- */
382 
383 /*
384  * Sets up the biosgeom bootinfo structure if the Multiboot information
385  * structure provides information about disk drives.
386  */
387 static void
setup_biosgeom(struct multiboot_info * mi)388 setup_biosgeom(struct multiboot_info *mi)
389 {
390           size_t pos;
391           uint8_t bidata[1024];
392           struct btinfo_biosgeom *bi;
393 
394           if (!(mi->mi_flags & MULTIBOOT_INFO_HAS_DRIVES))
395                     return;
396 
397           memset(bidata, 0, sizeof(bidata));
398           bi = (struct btinfo_biosgeom *)bidata;
399           pos = 0;
400 
401           while (pos < mi->mi_drives_length) {
402                     struct multiboot_drive *md;
403                     struct bi_biosgeom_entry bbe;
404 
405                     md = (struct multiboot_drive *)
406                         &((uint8_t *)mi->mi_drives_addr)[pos];
407 
408                     memset(&bbe, 0, sizeof(bbe));
409                     bbe.sec = md->md_sectors;
410                     bbe.head = md->md_heads;
411                     bbe.cyl = md->md_cylinders;
412                     bbe.dev = md->md_number;
413 
414                     memcpy(&bi->disk[bi->num], &bbe, sizeof(bbe));
415                     bi->num++;
416 
417                     pos += md->md_length;
418           }
419 
420           bootinfo_add((struct btinfo_common *)bi, BTINFO_BIOSGEOM,
421               sizeof(struct btinfo_biosgeom) +
422               bi->num * sizeof(struct bi_biosgeom_entry));
423 }
424 
425 /* --------------------------------------------------------------------- */
426 
427 /*
428  * Sets up the default root device if the Multiboot information
429  * structure provides information about the boot drive (where the kernel
430  * image was loaded from) or if the user gave a 'root' parameter on the
431  * boot command line.
432  */
433 static void
setup_bootdisk(struct multiboot_info * mi)434 setup_bootdisk(struct multiboot_info *mi)
435 {
436           bool found;
437           struct btinfo_rootdevice bi;
438 
439           found = false;
440 
441           if (mi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE)
442                     found = optstr_get(mi->mi_cmdline, "root", bi.devname,
443                         sizeof(bi.devname));
444 
445           if (!found && (mi->mi_flags & MULTIBOOT_INFO_HAS_BOOT_DEVICE)) {
446                     const char *devprefix;
447 
448                     /* Attempt to match the BIOS boot disk to a device.  There
449                      * is not much we can do to get it right.  (Well, strictly
450                      * speaking, we could, but it is certainly not worth the
451                      * extra effort.) */
452                     switch (mi->mi_boot_device_drive) {
453                     case 0x00:          devprefix = "fd0";  break;
454                     case 0x01:          devprefix = "fd1";  break;
455                     case 0x80:          devprefix = "wd0";  break;
456                     case 0x81:          devprefix = "wd1";  break;
457                     case 0x82:          devprefix = "wd2";  break;
458                     case 0x83:          devprefix = "wd3";  break;
459                     default:  devprefix = "wd0";
460                     }
461 
462                     strcpy(bi.devname, devprefix);
463                     if (mi->mi_boot_device_part2 != 0xFF)
464                               bi.devname[3] = mi->mi_boot_device_part2 + 'a';
465                     else
466                               bi.devname[3] = 'a';
467                     bi.devname[4] = '\0';
468 
469                     found = true;
470           }
471 
472           if (found) {
473                     bootinfo_add((struct btinfo_common *)&bi, BTINFO_ROOTDEVICE,
474                         sizeof(struct btinfo_rootdevice));
475           }
476 }
477 
478 /* --------------------------------------------------------------------- */
479 
480 /*
481  * Sets up the bootpath bootinfo structure with an appropriate kernel
482  * name derived from the boot command line.  The Multiboot information
483  * structure does not provide this detail directly, so we try to derive
484  * it from the command line setting.
485  */
486 static void
setup_bootpath(struct multiboot_info * mi)487 setup_bootpath(struct multiboot_info *mi)
488 {
489           struct btinfo_bootpath bi;
490           char *cl, *cl2, old;
491           int len;
492 
493           if (strncmp(Multiboot_Loader_Name, "GNU GRUB ",
494               sizeof(Multiboot_Loader_Name)) > 0) {
495                     cl = mi->mi_cmdline;
496                     while (*cl != '\0' && *cl != '/')
497                               cl++;
498                     cl2 = cl;
499                     len = 0;
500                     while (*cl2 != '\0' && *cl2 != ' ') {
501                               len++;
502                               cl2++;
503                     }
504 
505                     old = *cl2;
506                     *cl2 = '\0';
507                     memcpy(bi.bootpath, cl, MIN(sizeof(bi.bootpath), len));
508                     *cl2 = old;
509                     bi.bootpath[MIN(sizeof(bi.bootpath) - 1, len)] = '\0';
510 
511                     bootinfo_add((struct btinfo_common *)&bi, BTINFO_BOOTPATH,
512                         sizeof(struct btinfo_bootpath));
513           }
514 }
515 
516 /* --------------------------------------------------------------------- */
517 
518 /*
519  * Sets up the console bootinfo structure if the user gave a 'console'
520  * argument on the boot command line.  The Multiboot information
521  * structure gives no hint about this, so the only way to know where the
522  * console is to let the user specify it.
523  *
524  * If there wasn't any 'console' argument, this does not generate any
525  * bootinfo entry, falling back to the kernel's default console.
526  *
527  * If there weren't any of 'console_speed' or 'console_addr' arguments,
528  * this falls back to the default values for the serial port.
529  */
530 static void
setup_console(struct multiboot_info * mi)531 setup_console(struct multiboot_info *mi)
532 {
533           struct btinfo_console bi;
534           bool found;
535 
536           found = false;
537 
538           if (mi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE)
539                     found = optstr_get(mi->mi_cmdline, "console", bi.devname,
540                         sizeof(bi.devname));
541 
542           if (found) {
543                     bool valid;
544 
545                     if (strncmp(bi.devname, "com", sizeof(bi.devname)) == 0) {
546                               char tmp[10];
547 
548                               found = optstr_get(mi->mi_cmdline, "console_speed",
549                                   tmp, sizeof(tmp));
550                               if (found)
551                                         bi.speed = strtoul(tmp, NULL, 10);
552                               else
553                                         bi.speed = 0; /* Use default speed. */
554 
555                               found = optstr_get(mi->mi_cmdline, "console_addr",
556                                   tmp, sizeof(tmp));
557                               if (found) {
558                                         if (tmp[0] == '0' && tmp[1] == 'x')
559                                                   bi.addr = strtoul(tmp + 2, NULL, 16);
560                                         else
561                                                   bi.addr = strtoul(tmp, NULL, 10);
562                               } else
563                                         bi.addr = 0; /* Use default address. */
564 
565                               valid = true;
566                     } else if (strncmp(bi.devname, "pc", sizeof(bi.devname)) == 0)
567                               valid = true;
568                     else
569                               valid = false;
570 
571                     if (valid)
572                               bootinfo_add((struct btinfo_common *)&bi,
573                                   BTINFO_CONSOLE, sizeof(struct btinfo_console));
574           }
575 }
576 
577 /* --------------------------------------------------------------------- */
578 
579 /*
580  * Sets up the 'boothowto' variable based on the options given in the
581  * boot command line, if any.
582  */
583 static void
setup_howto(struct multiboot_info * mi)584 setup_howto(struct multiboot_info *mi)
585 {
586           char *cl;
587 
588           if (!(mi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE))
589                     return;
590 
591           cl = mi->mi_cmdline;
592 
593           /* Skip kernel file name. */
594           while (*cl != '\0' && *cl != ' ')
595                     cl++;
596           while (*cl == ' ')
597                     cl++;
598 
599           /* Check if there are flags and set 'howto' accordingly. */
600           if (*cl == '-') {
601                     int howto = 0;
602 
603                     cl++;
604                     while (*cl != '\0' && *cl != ' ') {
605                               BOOT_FLAG(*cl, howto);
606                               cl++;
607                     }
608                     if (*cl == ' ')
609                               cl++;
610 
611                     boothowto = howto;
612           }
613 }
614 
615 /* --------------------------------------------------------------------- */
616 
617 /*
618  * Sets up the memmap bootinfo structure to describe available memory as
619  * given by the BIOS.
620  */
621 static void
setup_memmap(struct multiboot_info * mi)622 setup_memmap(struct multiboot_info *mi)
623 {
624           char data[1024];
625           size_t i;
626           struct btinfo_memmap *bi;
627 
628           if (!(mi->mi_flags & MULTIBOOT_INFO_HAS_MMAP))
629                     return;
630 
631           bi = (struct btinfo_memmap *)data;
632           bi->num = 0;
633 
634           i = 0;
635           while (i < mi->mi_mmap_length) {
636                     struct multiboot_mmap *mm;
637                     struct bi_memmap_entry *bie;
638 
639                     bie = &bi->entry[bi->num];
640 
641                     mm = (struct multiboot_mmap *)(mi->mi_mmap_addr + i);
642                     bie->addr = mm->mm_base_addr;
643                     bie->size = mm->mm_length;
644                     if (mm->mm_type == 1)
645                               bie->type = BIM_Memory;
646                     else
647                               bie->type = BIM_Reserved;
648 
649                     bi->num++;
650                     i += mm->mm_size + 4;
651           }
652 
653           bootinfo_add((struct btinfo_common *)bi, BTINFO_MEMMAP,
654               sizeof(data));
655 }
656 
657 /* --------------------------------------------------------------------- */
658 
659 /*
660  * Sets up the 'biosbasemem' and 'biosextmem' variables if the
661  * Multiboot information structure provides information about memory.
662  */
663 static void
setup_memory(struct multiboot_info * mi)664 setup_memory(struct multiboot_info *mi)
665 {
666 
667           if (!(mi->mi_flags & MULTIBOOT_INFO_HAS_MEMORY))
668                     return;
669 
670           /* Make sure we don't override user-set variables. */
671           if (biosbasemem == 0) {
672                     biosbasemem = mi->mi_mem_lower;
673                     biosmem_implicit = 1;
674           }
675           if (biosextmem == 0) {
676                     biosextmem = mi->mi_mem_upper;
677                     biosmem_implicit = 1;
678           }
679 }
680 
681 /* --------------------------------------------------------------------- */
682 
683 /*
684  * Sets up the initial kernel symbol table.  Returns true if this was
685  * passed in by Multiboot; false otherwise.
686  */
687 bool
multiboot1_ksyms_addsyms_elf(void)688 multiboot1_ksyms_addsyms_elf(void)
689 {
690           struct multiboot_info *mi = &Multiboot_Info;
691           struct multiboot_symbols *ms = &Multiboot_Symbols;
692 
693           if (! Multiboot_Loader)
694                     return false;
695 
696           if (mi->mi_flags & MULTIBOOT_INFO_HAS_ELF_SYMS) {
697                     Elf32_Ehdr ehdr;
698 
699                     KASSERT(esym != 0);
700 
701                     memcpy(ehdr.e_ident, ELFMAG, SELFMAG);
702                     ehdr.e_ident[EI_CLASS] = ELFCLASS32;
703                     ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
704                     ehdr.e_ident[EI_VERSION] = EV_CURRENT;
705                     ehdr.e_type = ET_EXEC;
706                     ehdr.e_machine = EM_386;
707                     ehdr.e_version = 1;
708                     ehdr.e_ehsize = sizeof(ehdr);
709 
710                     ksyms_addsyms_explicit((void *)&ehdr,
711                         ms->s_symstart, ms->s_symsize,
712                         ms->s_strstart, ms->s_strsize);
713           }
714 
715           return mi->mi_flags & MULTIBOOT_INFO_HAS_ELF_SYMS;
716 }
717