Switch to a simple X11-style license.
[polintos/scott/priv.git] / kernel / arch / x64 / multiboot.cc
1 // arch/x64/multiboot.cc -- Code to interpret multiboot data and initialize
2 //                          free memory regions based thereupon.
3 //
4 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
5 // 
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:
12 // 
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
15 // 
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
22 // SOFTWARE.
23
24 #include <kern/libc.h>
25 #include <kern/pagealloc.h>
26
27 #include <arch/multiboot.h>
28 #include <arch/addrs.h>
29 #include <arch/paging.h>
30 #include <arch/mem.h>
31
32 #include <limits.h>
33
34 u32 x64_boot_info_phys;
35
36 namespace Arch {
37 namespace Priv {
38 namespace MultiBoot {
39         BootInfo *boot_info;
40
41         void parse_mmap()
42         {
43         }
44         
45         void make_mem_avail(uintptr_t page_start, uintptr_t page_end)
46         {
47                 using Mem::pages;
48                         
49                 if (page_start < dma32zonestart) {
50                         size_t len;
51                         
52                         if (page_end <= dma32zonestart)
53                                 len = page_end - page_start;
54                         else
55                                 len = dma32zonestart - page_start;
56                         
57                         isadmazone.free(&pages[page_start], len);
58                         page_start = dma32zonestart;
59                 }
60
61                 if (page_start < highzonestart && page_end > dma32zonestart) {
62                         size_t len;
63                         
64                         if (page_end <= highzonestart)
65                                 len = page_end - page_start;
66                         else
67                                 len = highzonestart - page_start;
68                         
69                         dma32zone.free(&pages[page_start], len);
70                         page_start = highzonestart;
71                 }
72
73                 if (page_end > highzonestart)
74                         dma32zone.free(&pages[page_start], page_end - highzonestart);
75         }
76
77         void process_info()
78         {
79                 if (x64_boot_info_phys > max_ktext_map) {
80                         printf("Cannot access boot info at %#.8x\n", x64_boot_info_phys);
81                         for(;;);
82                 }
83                 
84                 boot_info = (BootInfo *)phys_to_ktext(x64_boot_info_phys);
85                 mem_end = 0;
86
87                 if (!(boot_info->flags & (1 << BootInfo::flag_mmap))) {
88                         // FIXME: use mem_lower and mem_upper in this case.
89                         printf("MultiBoot info does not contain a memory map.\n");
90                         for(;;);
91                 }
92
93                 printf("BIOS Memory Map:\n");
94
95                 uint off = 0;
96                 while (off < boot_info->mmap_length) {
97                         u32 phys = boot_info->mmap_addr + off;
98                 
99                         if (phys > max_ktext_map) {
100                                 printf("Cannot access BIOS memory map entry at %#.8x\n", phys);
101                                 for(;;);
102                         }
103                         
104                         MemMap *mmap = (MemMap *)phys_to_ktext(phys);
105                         
106                         printf("0x%016llx - 0x%016llx, type %d\n",
107                                mmap->base, mmap->base + mmap->len - 1, mmap->type);
108                 
109                         off += mmap->size + 4;
110                         
111                         if (mmap->type == MemMap::Available) {
112                                 size_t page_end = (mmap->base + mmap->len) / page_size;
113                                 
114                                 if (page_end > mem_end)
115                                         mem_end = page_end;
116                         }
117                 }
118                 
119                 map_physmem();
120                 
121                 off = 0;
122                 while (off < boot_info->mmap_length) {
123                         u32 phys = boot_info->mmap_addr + off;
124                         MemMap *mmap = (MemMap *)phys_to_ktext(phys);
125                         off += mmap->size + 4;
126                         
127                         if (mmap->type == MemMap::Available) {
128                                 // Don't use any page that isn't fully in this entry.
129
130                                 size_t page_start = (mmap->base + page_size - 1) / page_size;
131                                 size_t page_end = (mmap->base + mmap->len) / page_size;
132                                 
133
134                                 // Don't make available any pages that overlap the
135                                 // kernel text/data or bootmem allocations.
136                                 
137                                 uintptr_t kernelendpage = 
138                                         (kvirt_to_phys((void *)next_free_bootmem) + page_size - 1) /
139                                         page_size;
140                                 
141                                 // Don't overwrite page 1; the BIOS will need it for later calls in
142                                 // emulation, and at least the BIOS I'm testing on doesn't mark
143                                 // it as reserved.
144                 
145                                 if (page_start == 0)
146                                         page_start = 1;
147                                 if (page_start >= page_end)
148                                         continue;
149                                 
150                                 if (page_start <= kernelendpage && page_end >= 512) {
151                                         if (page_start < 512)
152                                                 make_mem_avail(page_start, 512);
153                                         
154                                         if (page_end > kernelendpage)
155                                                 make_mem_avail(kernelendpage + 1, page_end);
156                                 } else {
157                                         make_mem_avail(page_start, page_end);
158                                 }
159                         }
160                 }
161         }
162 }
163 }
164 }