]> git.buserror.net Git - polintos/scott/priv.git/blob - kernel/arch/x86/multiboot.cc
661822f69f3bdf4a043ea2e10551a625d9a618ab
[polintos/scott/priv.git] / kernel / arch / x86 / multiboot.cc
1 // arch/x86/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 conditions:
12 // 
13 //     * Redistributions of source code must retain the above copyright notice,
14 //       this list of conditions and the following disclaimers.
15 // 
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.
19 // 
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.
23 // 
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
30 // SOFTWARE.
31
32 #include <kern/libc.h>
33 #include <kern/pagealloc.h>
34
35 #include <arch/multiboot.h>
36 #include <arch/addrs.h>
37 #include <arch/paging.h>
38 #include <arch/mem.h>
39
40 #include <util/misc.h>
41 #include <limits.h>
42
43 u32 x86_boot_info_phys;
44 extern int _start;
45
46 namespace Arch {
47 namespace Priv {
48 namespace MultiBoot {
49         BootInfo *boot_info;
50
51         void parse_mmap()
52         {
53         }
54         
55         using Util::round_up;
56         using Util::round_down;
57         
58         void make_mem_avail(u64 start, u64 end)
59         {
60                 using Mem::pages;
61                 
62                 if (start > end)
63                         return;
64                 
65                 for (int i = 0; i < num_zones; i++) {
66                         u64 rstart = mem_zone_regions[i].start;
67                         u64 rend = mem_zone_regions[i].end;
68                 
69                         if (start <= rend && end >= rstart) {
70                                 if (rstart < start)
71                                         rstart = start;
72                                 if (rend > end)
73                                         rend = end;
74                                 
75                                 ulong page_len = (rend - rstart + 1) / page_size;
76                                 pagezones[i].free(Mem::phys_to_page(rstart), page_len);
77                         }
78                 }
79         }
80
81         void process_info()
82         {
83                 if (x86_boot_info_phys > max_ktext_map) {
84                         printf("Cannot access boot info at %#.8x\n", x86_boot_info_phys);
85                         for(;;);
86                 }
87                 
88                 boot_info = (BootInfo *)phys_to_kvirt(x86_boot_info_phys);
89                 mem_end = 0;
90                 
91                 if (!(boot_info->flags & (1 << BootInfo::flag_mmap))) {
92                         // FIXME: use mem_lower and mem_upper in this case.
93                         printf("MultiBoot info does not contain a memory map.\n");
94                         for(;;);
95                 }
96         
97                 printf("BIOS Memory Map:\n");
98
99                 uint off = 0;
100                 while (off < boot_info->mmap_length) {
101                         u32 phys = boot_info->mmap_addr + off;
102                 
103                         if (phys > max_ktext_map) {
104                                 printf("Cannot access BIOS memory map entry at %#.8x\n", phys);
105                                 for(;;);
106                         }
107                         
108                         MemMap *mmap = (MemMap *)phys_to_kvirt(phys);
109                         
110                         printf("0x%016llx - 0x%016llx, type %d\n",
111                                mmap->base, mmap->base + mmap->len - 1, mmap->type);
112                 
113                         off += mmap->size + 4;
114                         
115                         if (mmap->type == MemMap::Available) {
116                                 u64 end = mmap->base + mmap->len;
117                                 
118                                 if (end > mem_end)
119                                         mem_end = end;
120                         }
121                 }
122                 
123                 map_physmem();
124
125                 // Don't make available any pages that overlap the
126                 // kernel text/data or bootmem allocations.
127                         
128                 u64 kernelstart = round_down(kvirt_to_phys(&_start), page_shift);
129                 u64 kernelend = round_up(kvirt_to_phys((void *)next_free_bootmem),
130                                          page_shift) - 1;
131                                 
132                 off = 0;
133                 while (off < boot_info->mmap_length) {
134                         u32 phys = boot_info->mmap_addr + off;
135                         MemMap *mmap = (MemMap *)phys_to_kvirt(phys);
136                         off += mmap->size + 4;
137                         
138                         if (mmap->type == MemMap::Available) {
139                                 // Don't use any page that isn't fully in this entry.
140
141                                 u64 start = round_up(mmap->base, page_shift);
142                                 u64 end = round_down(mmap->base + mmap->len, page_shift) - 1;
143                                 
144                                 // Don't overwrite page 1; the BIOS will need it for later calls in
145                                 // emulation, and at least the BIOS I'm testing on doesn't mark
146                                 // it as reserved.
147                 
148                                 if (start < page_size)
149                                         start = page_size;
150                                 
151                                 if (start <= kernelend && end >= kernelstart) {
152                                         if (start < kernelstart)
153                                                 make_mem_avail(start, kernelstart - 1);
154                                         
155                                         if (end > kernelend)
156                                                 make_mem_avail(kernelend + 1, end);
157                                 } else {
158                                         make_mem_avail(start, end);
159                                 }
160                         }
161                 }
162         }
163 }
164 }
165 }