1 // arch/x64/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 conditions:
13 // * Redistributions of source code must retain the above copyright notice,
14 // this list of conditions and the following disclaimers.
16 // * Redistributions in binary form must reproduce the above copyright notice,
17 // this list of conditions and the following disclaimers in the
18 // documentation and/or other materials provided with the distribution.
20 // * The names of the Software's authors and/or contributors
21 // may not be used to endorse or promote products derived from
22 // this Software without specific prior written permission.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
26 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
32 #include <kern/libc.h>
33 #include <kern/pagealloc.h>
35 #include <arch/multiboot.h>
36 #include <arch/addrs.h>
37 #include <arch/paging.h>
42 u32 x64_boot_info_phys;
53 void make_mem_avail(uintptr_t page_start, uintptr_t page_end)
57 if (page_start < dma32zonestart) {
60 if (page_end <= dma32zonestart)
61 len = page_end - page_start;
63 len = dma32zonestart - page_start;
65 isadmazone.free(&pages[page_start], len);
66 page_start = dma32zonestart;
69 if (page_start < highzonestart && page_end > dma32zonestart) {
72 if (page_end <= highzonestart)
73 len = page_end - page_start;
75 len = highzonestart - page_start;
77 dma32zone.free(&pages[page_start], len);
78 page_start = highzonestart;
81 if (page_end > highzonestart)
82 dma32zone.free(&pages[page_start], page_end - highzonestart);
87 if (x64_boot_info_phys > max_ktext_map) {
88 printf("Cannot access boot info at %#.8x\n", x64_boot_info_phys);
92 boot_info = (BootInfo *)phys_to_ktext(x64_boot_info_phys);
95 if (!(boot_info->flags & (1 << BootInfo::flag_mmap))) {
96 // FIXME: use mem_lower and mem_upper in this case.
97 printf("MultiBoot info does not contain a memory map.\n");
101 printf("BIOS Memory Map:\n");
104 while (off < boot_info->mmap_length) {
105 u32 phys = boot_info->mmap_addr + off;
107 if (phys > max_ktext_map) {
108 printf("Cannot access BIOS memory map entry at %#.8x\n", phys);
112 MemMap *mmap = (MemMap *)phys_to_ktext(phys);
114 printf("0x%016llx - 0x%016llx, type %d\n",
115 mmap->base, mmap->base + mmap->len - 1, mmap->type);
117 off += mmap->size + 4;
119 if (mmap->type == MemMap::Available) {
120 size_t page_end = (mmap->base + mmap->len) / page_size;
122 if (page_end > mem_end)
130 while (off < boot_info->mmap_length) {
131 u32 phys = boot_info->mmap_addr + off;
132 MemMap *mmap = (MemMap *)phys_to_ktext(phys);
133 off += mmap->size + 4;
135 if (mmap->type == MemMap::Available) {
136 // Don't use any page that isn't fully in this entry.
138 size_t page_start = (mmap->base + page_size - 1) / page_size;
139 size_t page_end = (mmap->base + mmap->len) / page_size;
142 // Don't make available any pages that overlap the
143 // kernel text/data or bootmem allocations.
145 uintptr_t kernelendpage =
146 (kvirt_to_phys((void *)next_free_bootmem) + page_size - 1) /
149 // Don't overwrite page 1; the BIOS will need it for later calls in
150 // emulation, and at least the BIOS I'm testing on doesn't mark
155 if (page_start >= page_end)
158 if (page_start <= kernelendpage && page_end >= 512) {
159 if (page_start < 512)
160 make_mem_avail(page_start, 512);
162 if (page_end > kernelendpage)
163 make_mem_avail(kernelendpage + 1, page_end);
165 make_mem_avail(page_start, page_end);