]> git.buserror.net Git - polintos/scott/priv.git/blob - kernel/arch/x86/multiboot.cc
Switch to a simple X11-style license.
[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 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 <util/misc.h>
33 #include <limits.h>
34
35 u32 x86_boot_info_phys;
36 extern int _start;
37
38 namespace Arch {
39 namespace Priv {
40 namespace MultiBoot {
41         BootInfo *boot_info;
42
43         void parse_mmap()
44         {
45         }
46         
47         using Util::round_up;
48         using Util::round_down;
49         
50         void make_mem_avail(u64 start, u64 end)
51         {
52                 using Mem::pages;
53                 
54                 if (start > end)
55                         return;
56                 
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;
60                 
61                         if (start <= rend && end >= rstart) {
62                                 if (rstart < start)
63                                         rstart = start;
64                                 if (rend > end)
65                                         rend = end;
66                                 
67                                 ulong page_len = (rend - rstart + 1) / page_size;
68                                 pagezones[i].free(Mem::phys_to_page(rstart), page_len);
69                         }
70                 }
71         }
72
73         void process_info()
74         {
75                 if (x86_boot_info_phys > max_ktext_map) {
76                         printf("Cannot access boot info at %#.8x\n", x86_boot_info_phys);
77                         for(;;);
78                 }
79                 
80                 boot_info = (BootInfo *)phys_to_kvirt(x86_boot_info_phys);
81                 mem_end = 0;
82                 
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");
86                         for(;;);
87                 }
88         
89                 printf("BIOS Memory Map:\n");
90
91                 uint off = 0;
92                 while (off < boot_info->mmap_length) {
93                         u32 phys = boot_info->mmap_addr + off;
94                 
95                         if (phys > max_ktext_map) {
96                                 printf("Cannot access BIOS memory map entry at %#.8x\n", phys);
97                                 for(;;);
98                         }
99                         
100                         MemMap *mmap = (MemMap *)phys_to_kvirt(phys);
101                         
102                         printf("0x%016llx - 0x%016llx, type %d\n",
103                                mmap->base, mmap->base + mmap->len - 1, mmap->type);
104                 
105                         off += mmap->size + 4;
106                         
107                         if (mmap->type == MemMap::Available) {
108                                 u64 end = mmap->base + mmap->len;
109                                 
110                                 if (end > mem_end)
111                                         mem_end = end;
112                         }
113                 }
114                 
115                 map_physmem();
116
117                 // Don't make available any pages that overlap the
118                 // kernel text/data or bootmem allocations.
119                         
120                 u64 kernelstart = round_down(kvirt_to_phys(&_start), page_shift);
121                 u64 kernelend = round_up(kvirt_to_phys((void *)next_free_bootmem),
122                                          page_shift) - 1;
123                                 
124                 off = 0;
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;
129                         
130                         if (mmap->type == MemMap::Available) {
131                                 // Don't use any page that isn't fully in this entry.
132
133                                 u64 start = round_up(mmap->base, page_shift);
134                                 u64 end = round_down(mmap->base + mmap->len, page_shift) - 1;
135                                 
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
138                                 // it as reserved.
139                 
140                                 if (start < page_size)
141                                         start = page_size;
142                                 
143                                 if (start <= kernelend && end >= kernelstart) {
144                                         if (start < kernelstart)
145                                                 make_mem_avail(start, kernelstart - 1);
146                                         
147                                         if (end > kernelend)
148                                                 make_mem_avail(kernelend + 1, end);
149                                 } else {
150                                         make_mem_avail(start, end);
151                                 }
152                         }
153                 }
154         }
155 }
156 }
157 }