1 // arch/x86/mem.cc -- x86 paging and misc. memory management
3 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
5 // Permission is hereby granted, free of charge, to any person obtaining a copy of
6 // this software and associated documentation files (the "Software"), to deal with
7 // the Software without restriction, including without limitation the rights to
8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 // of the Software, and to permit persons to whom the Software is furnished to do
10 // so, subject to the following condition:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
23 #include <kern/kernel.h>
25 #include <kern/pagealloc.h>
26 #include <kern/libc.h>
28 // Initial page tables have the first 4 MiB mapped, using large pages.
30 __attribute__((aligned(4096))) u32 x86_init_ptbl_l2[1024] = {
36 using Mem::PageAllocZone;
42 #define zonelist(x) ((x) * ((x) + 1) / 2 - 1)
44 PageAllocZone pagezones[num_zones];
45 PageAllocZone *pagezonelists_real[zonelist(num_zones + 1)];
48 PageAllocZone **pagezonelists[Priv::num_zones];
50 uintptr_t next_free_bootmem = reinterpret_cast<uintptr_t>(&_end);
55 void early_adjust_mappings()
57 using Mem::get_bootmem;
59 // Clear low-address mapping and invalidate TLB
60 x86_init_ptbl_l2[0] = 0;
61 asm volatile("movl %0, %%cr3" : : "r" (kvirt_to_phys(x86_init_ptbl_l2)));
63 // Mark the ktext mapping global now that it's not mapped at address
64 // zero. FIXME: check for and enable PGE
66 x86_init_ptbl_l2[0x200] |= 0x100;
71 using Mem::get_bootmem;
73 // phys_to_ktext can be used for the first
74 // 4MiB-minus-size-of-kernel of bootmem allocations.
76 for (uintptr_t physpage = 1; physpage <= (mem_end - 1) / (4096*1024);
79 uintptr_t virtpage = physpage + (PHYSMEM_START >> 22);
80 x86_init_ptbl_l2[virtpage & 1023] = (physpage << 22) | 0x187;
83 size_t pages_size = (mem_end / page_size) * sizeof(Mem::Page);
84 Mem::pages = static_cast<Mem::Page *>(get_bootmem(pages_size, 4));
85 Mem::last_page = Mem::pages + pages_size - 1;
86 bzero(Mem::pages, pages_size);
88 int listpos[num_zones];
90 for (int i = num_zones - 1; i >= 0; i--) {
91 listpos[i] = zonelist(i);
92 pagezonelists[num_zones - 1 - i] = &pagezonelists_real[listpos[i]];
94 u64 rstart = mem_zone_regions[i].start;
95 u64 rend = mem_zone_regions[i].end;
97 if (mem_start <= rend && mem_end >= rstart) {
98 if (rstart < mem_start)
103 ulong page_start = rstart / page_size;
104 ulong page_len = (rend - rstart + 1) / page_size;
106 pagezones[i].init(page_start, page_len);
108 for (int j = i; j < num_zones; j++) {
109 assert(listpos[j] < zonelist(j + 1));
110 pagezonelists_real[listpos[j]++] = &pagezones[i];