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 // Permission is hereby granted, free of charge, to any person obtaining a copy of
7 // this software and associated documentation files (the "Software"), to deal with
8 // the Software without restriction, including without limitation the rights to
9 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
10 // of the Software, and to permit persons to whom the Software is furnished to do
11 // so, subject to the following condition:
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
18 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
24 #include <kern/libc.h>
25 #include <kern/pagealloc.h>
27 #include <arch/multiboot.h>
28 #include <arch/addrs.h>
29 #include <arch/paging.h>
32 #include <util/misc.h>
35 u32 x86_boot_info_phys;
48 using Util::round_down;
50 void make_mem_avail(u64 start, u64 end)
57 for (int i = 0; i < num_zones; i++) {
58 u64 rstart = mem_zone_regions[i].start;
59 u64 rend = mem_zone_regions[i].end;
61 if (start <= rend && end >= rstart) {
67 ulong page_len = (rend - rstart + 1) / page_size;
68 pagezones[i].free(Mem::phys_to_page(rstart), page_len);
75 if (x86_boot_info_phys > max_ktext_map) {
76 printf("Cannot access boot info at %#.8x\n", x86_boot_info_phys);
80 boot_info = (BootInfo *)phys_to_kvirt(x86_boot_info_phys);
83 if (!(boot_info->flags & (1 << BootInfo::flag_mmap))) {
84 // FIXME: use mem_lower and mem_upper in this case.
85 printf("MultiBoot info does not contain a memory map.\n");
89 printf("BIOS Memory Map:\n");
92 while (off < boot_info->mmap_length) {
93 u32 phys = boot_info->mmap_addr + off;
95 if (phys > max_ktext_map) {
96 printf("Cannot access BIOS memory map entry at %#.8x\n", phys);
100 MemMap *mmap = (MemMap *)phys_to_kvirt(phys);
102 printf("0x%016llx - 0x%016llx, type %d\n",
103 mmap->base, mmap->base + mmap->len - 1, mmap->type);
105 off += mmap->size + 4;
107 if (mmap->type == MemMap::Available) {
108 u64 end = mmap->base + mmap->len;
117 // Don't make available any pages that overlap the
118 // kernel text/data or bootmem allocations.
120 u64 kernelstart = round_down(kvirt_to_phys(&_start), page_shift);
121 u64 kernelend = round_up(kvirt_to_phys((void *)next_free_bootmem),
125 while (off < boot_info->mmap_length) {
126 u32 phys = boot_info->mmap_addr + off;
127 MemMap *mmap = (MemMap *)phys_to_kvirt(phys);
128 off += mmap->size + 4;
130 if (mmap->type == MemMap::Available) {
131 // Don't use any page that isn't fully in this entry.
133 u64 start = round_up(mmap->base, page_shift);
134 u64 end = round_down(mmap->base + mmap->len, page_shift) - 1;
136 // Don't overwrite page 1; the BIOS will need it for later calls in
137 // emulation, and at least the BIOS I'm testing on doesn't mark
140 if (start < page_size)
143 if (start <= kernelend && end >= kernelstart) {
144 if (start < kernelstart)
145 make_mem_avail(start, kernelstart - 1);
148 make_mem_avail(kernelend + 1, end);
150 make_mem_avail(start, end);