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