]> git.buserror.net Git - polintos/scott/priv.git/blob - kernel/arch/x86/multiboot.cc
minor doc updates
[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 // This software is provided 'as-is', without any express or implied warranty.
7 // In no event will the authors or contributors be held liable for any damages
8 // arising from the use of this software.
9 // 
10 // Permission is hereby granted to everyone, free of charge, to use, copy,
11 // modify, prepare derivative works of, publish, distribute, perform,
12 // sublicense, and/or sell copies of the Software, provided that the above
13 // copyright notice and disclaimer of warranty be included in all copies or
14 // substantial portions of this software.
15
16 #include <kern/libc.h>
17 #include <kern/pagealloc.h>
18
19 #include <arch/multiboot.h>
20 #include <arch/addrs.h>
21 #include <arch/paging.h>
22 #include <arch/mem.h>
23
24 #include <util/misc.h>
25 #include <limits.h>
26
27 u32 x86_boot_info_phys;
28 extern int _start;
29
30 namespace Arch {
31 namespace Priv {
32 namespace MultiBoot {
33         BootInfo *boot_info;
34
35         void parse_mmap()
36         {
37         }
38         
39         using Util::round_up;
40         using Util::round_down;
41         
42         void make_mem_avail(u64 start, u64 end)
43         {
44                 using Mem::pages;
45                 
46                 if (start > end)
47                         return;
48                 
49                 for (int i = 0; i < num_zones; i++) {
50                         u64 rstart = mem_zone_regions[i].start;
51                         u64 rend = mem_zone_regions[i].end;
52                 
53                         if (start <= rend && end >= rstart) {
54                                 if (rstart < start)
55                                         rstart = start;
56                                 if (rend > end)
57                                         rend = end;
58                                 
59                                 ulong page_len = (rend - rstart + 1) / page_size;
60                                 pagezones[i].free(Mem::phys_to_page(rstart), page_len);
61                         }
62                 }
63         }
64
65         void process_info()
66         {
67                 if (x86_boot_info_phys > max_ktext_map) {
68                         printf("Cannot access boot info at %#.8x\n", x86_boot_info_phys);
69                         for(;;);
70                 }
71                 
72                 boot_info = (BootInfo *)phys_to_kvirt(x86_boot_info_phys);
73                 mem_end = 0;
74                 
75                 if (!(boot_info->flags & (1 << BootInfo::flag_mmap))) {
76                         // FIXME: use mem_lower and mem_upper in this case.
77                         printf("MultiBoot info does not contain a memory map.\n");
78                         for(;;);
79                 }
80         
81                 printf("BIOS Memory Map:\n");
82
83                 uint off = 0;
84                 while (off < boot_info->mmap_length) {
85                         u32 phys = boot_info->mmap_addr + off;
86                 
87                         if (phys > max_ktext_map) {
88                                 printf("Cannot access BIOS memory map entry at %#.8x\n", phys);
89                                 for(;;);
90                         }
91                         
92                         MemMap *mmap = (MemMap *)phys_to_kvirt(phys);
93                         
94                         printf("0x%016llx - 0x%016llx, type %d\n",
95                                mmap->base, mmap->base + mmap->len - 1, mmap->type);
96                 
97                         off += mmap->size + 4;
98                         
99                         if (mmap->type == MemMap::Available) {
100                                 u64 end = mmap->base + mmap->len;
101                                 
102                                 if (end > mem_end)
103                                         mem_end = end;
104                         }
105                 }
106                 
107                 map_physmem();
108
109                 // Don't make available any pages that overlap the
110                 // kernel text/data or bootmem allocations.
111                         
112                 u64 kernelstart = round_down(kvirt_to_phys(&_start), page_shift);
113                 u64 kernelend = round_up(kvirt_to_phys((void *)next_free_bootmem),
114                                          page_shift) - 1;
115                                 
116                 off = 0;
117                 while (off < boot_info->mmap_length) {
118                         u32 phys = boot_info->mmap_addr + off;
119                         MemMap *mmap = (MemMap *)phys_to_kvirt(phys);
120                         off += mmap->size + 4;
121                         
122                         if (mmap->type == MemMap::Available) {
123                                 // Don't use any page that isn't fully in this entry.
124
125                                 u64 start = round_up(mmap->base, page_shift);
126                                 u64 end = round_down(mmap->base + mmap->len, page_shift) - 1;
127                                 
128                                 // Don't overwrite page 1; the BIOS will need it for later calls in
129                                 // emulation, and at least the BIOS I'm testing on doesn't mark
130                                 // it as reserved.
131                 
132                                 if (start < page_size)
133                                         start = page_size;
134                                 
135                                 if (start <= kernelend && end >= kernelstart) {
136                                         if (start < kernelstart)
137                                                 make_mem_avail(start, kernelstart - 1);
138                                         
139                                         if (end > kernelend)
140                                                 make_mem_avail(kernelend + 1, end);
141                                 } else {
142                                         make_mem_avail(start, end);
143                                 }
144                         }
145                 }
146         }
147 }
148 }
149 }