1 // arch/x86/multiboot.cc -- Code to interpret multiboot data and initialize
2 // free memory regions based thereupon.
4 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
6 // This software is provided 'as-is', without any express or implied warranty.
7 // In no event will the authors or contributors be held liable for any damages
8 // arising from the use of this software.
10 // Permission is hereby granted to everyone, free of charge, to use, copy,
11 // modify, prepare derivative works of, publish, distribute, perform,
12 // sublicense, and/or sell copies of the Software, provided that the above
13 // copyright notice and disclaimer of warranty be included in all copies or
14 // substantial portions of this software.
16 #include <kern/libc.h>
17 #include <kern/pagealloc.h>
19 #include <arch/multiboot.h>
20 #include <arch/addrs.h>
21 #include <arch/paging.h>
24 #include <util/misc.h>
27 u32 x86_boot_info_phys;
40 using Util::round_down;
42 void make_mem_avail(u64 start, u64 end)
49 for (int i = 0; i < num_zones; i++) {
50 u64 rstart = mem_zone_regions[i].start;
51 u64 rend = mem_zone_regions[i].end;
53 if (start <= rend && end >= rstart) {
59 ulong page_len = (rend - rstart + 1) / page_size;
60 pagezones[i].free(Mem::phys_to_page(rstart), page_len);
67 if (x86_boot_info_phys > max_ktext_map) {
68 printf("Cannot access boot info at %#.8x\n", x86_boot_info_phys);
72 boot_info = (BootInfo *)phys_to_kvirt(x86_boot_info_phys);
75 if (!(boot_info->flags & (1 << BootInfo::flag_mmap))) {
76 // FIXME: use mem_lower and mem_upper in this case.
77 printf("MultiBoot info does not contain a memory map.\n");
81 printf("BIOS Memory Map:\n");
84 while (off < boot_info->mmap_length) {
85 u32 phys = boot_info->mmap_addr + off;
87 if (phys > max_ktext_map) {
88 printf("Cannot access BIOS memory map entry at %#.8x\n", phys);
92 MemMap *mmap = (MemMap *)phys_to_kvirt(phys);
94 printf("0x%016llx - 0x%016llx, type %d\n",
95 mmap->base, mmap->base + mmap->len - 1, mmap->type);
97 off += mmap->size + 4;
99 if (mmap->type == MemMap::Available) {
100 u64 end = mmap->base + mmap->len;
109 // Don't make available any pages that overlap the
110 // kernel text/data or bootmem allocations.
112 u64 kernelstart = round_down(kvirt_to_phys(&_start), page_shift);
113 u64 kernelend = round_up(kvirt_to_phys((void *)next_free_bootmem),
117 while (off < boot_info->mmap_length) {
118 u32 phys = boot_info->mmap_addr + off;
119 MemMap *mmap = (MemMap *)phys_to_kvirt(phys);
120 off += mmap->size + 4;
122 if (mmap->type == MemMap::Available) {
123 // Don't use any page that isn't fully in this entry.
125 u64 start = round_up(mmap->base, page_shift);
126 u64 end = round_down(mmap->base + mmap->len, page_shift) - 1;
128 // Don't overwrite page 1; the BIOS will need it for later calls in
129 // emulation, and at least the BIOS I'm testing on doesn't mark
132 if (start < page_size)
135 if (start <= kernelend && end >= kernelstart) {
136 if (start < kernelstart)
137 make_mem_avail(start, kernelstart - 1);
140 make_mem_avail(kernelend + 1, end);
142 make_mem_avail(start, end);