1 // arch/x64/mem.cc -- x64 misc. memory management
3 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
5 // This software is provided 'as-is', without any express or implied warranty.
6 // In no event will the authors or contributors be held liable for any damages
7 // arising from the use of this software.
9 // Permission is hereby granted to everyone, free of charge, to use, copy,
10 // modify, prepare derivative works of, publish, distribute, perform,
11 // sublicense, and/or sell copies of the Software, provided that the above
12 // copyright notice and disclaimer of warranty be included in all copies or
13 // substantial portions of this software.
15 #include <kern/kernel.h>
17 #include <kern/pagealloc.h>
18 #include <kern/libc.h>
20 // Initial page tables have the first 4 MiB mapped, using large pages.
22 __attribute__((aligned(4096))) u64 x64_init_ptbl_l2[512] = {
27 // The ORing of 7 into these entries will be done in entry.S;
28 // doing it here causes the compiler to emit runtime code
31 __attribute__((aligned(4096))) u64 x64_init_ptbl_l3[512] = {
32 reinterpret_cast<u64>(x64_init_ptbl_l2) - KERNEL_START
35 __attribute__((aligned(4096))) u64 x64_init_ptbl_l4[512] = {
36 reinterpret_cast<u64>(x64_init_ptbl_l3) - KERNEL_START
41 using Mem::PageAllocZone;
46 PageAllocZone *pagezones[3];
49 PageAllocZone isadmazone, dma32zone, highzone;
51 PageAllocZone *isadmazonelist[2] = { &isadmazone, NULL };
52 PageAllocZone *dma32zonelist[3];
53 PageAllocZone *normalzonelist[4];
56 PageAllocZone **pagezonelists[3] = { Priv::normalzonelist,
58 Priv::isadmazonelist };
60 uintptr_t next_free_bootmem = reinterpret_cast<uintptr_t>(&_end) -
61 KERNEL_START + PHYSMEM_START;
64 void early_adjust_mappings()
66 using Mem::get_bootmem;
68 // Clear low-address mappings and invalidate TLB
69 x64_init_ptbl_l4[0] = 0;
70 x64_init_ptbl_l3[0] = 0;
71 asm volatile("movq %0, %%cr3" : : "r" (kvirt_to_phys(x64_init_ptbl_l4)));
73 // Mark the ktext mapping global now that it's not mapped at address
76 x64_init_ptbl_l2[0] |= 0x100;
77 x64_init_ptbl_l2[1] |= 0x100;
79 u64 l3phys = kvirt_to_phys(get_bootmem(page_size, page_size));
80 u64 *l3 = static_cast<u64 *>(phys_to_ktext(l3phys));
82 x64_init_ptbl_l4[0x100] = l3phys | 7;
84 u64 l2phys = kvirt_to_phys(get_bootmem(page_size, page_size));
85 u64 *l2 = static_cast<u64 *>(phys_to_ktext(l2phys));
89 // Map at least as much as is mapped in ktext, so that
90 // things like the VGA driver can use it early without
91 // having to know about phys_to_ktext, and so map_physmem
92 // doesn't need to special-case the use of phys_to_ktext
93 // for the first couple pages.
101 using Mem::get_bootmem;
103 // phys_to_ktext can be used for the first
104 // 2MiB-minus-size-of-kernel of bootmem allocations.
106 for (uintptr_t physpage = 2; physpage <= (mem_end - 1) / 512; physpage++)
108 uintptr_t virtpage = physpage + (PHYSMEM_START >> 21);
111 u64 l3phys = x64_init_ptbl_l4[(virtpage >> 18) & 511] &
115 l3 = static_cast<u64 *>(get_bootmem(page_size, page_size));
116 bzero(l3, page_size);
117 x64_init_ptbl_l4[(virtpage >> 18) & 511] =
118 kvirt_to_phys(l3) | 7;
120 l3 = static_cast<u64 *>(phys_to_kvirt(l3phys));
124 u64 l2phys = l3[(virtpage >> 9) & 511] & ~(page_size - 1);
127 l2 = static_cast<u64 *>(get_bootmem(page_size, page_size));
128 bzero(l2, page_size);
129 l3[(virtpage >> 9) & 511] = kvirt_to_phys(l2) | 7;
131 l2 = static_cast<u64 *>(phys_to_kvirt(l2phys));
134 l2[virtpage & 511] = (physpage << 21) | 0x187;
137 size_t pages_size = mem_end * sizeof(Mem::Page);
138 Mem::pages = static_cast<Mem::Page *>(get_bootmem(pages_size, 8));
139 Mem::last_page = Mem::pages + pages_size - 1;
140 bzero(Mem::pages, pages_size);
142 int normal = 0, dma = 0;
143 uintptr_t highstart = highzonestart;
144 uintptr_t dma32start = dma32zonestart;
146 if (mem_end > highstart) {
147 normalzonelist[normal++] = &highzone;
148 highzone.init(highstart, mem_end - highstart);
153 if (mem_end > dma32start) {
154 normalzonelist[normal++] = &dma32zone;
155 dma32zonelist[dma++] = &dma32zone;
156 dma32zone.init(dma32start, highstart - dma32start);
158 dma32start = mem_end;
161 normalzonelist[normal++] = &isadmazone;
162 dma32zonelist[dma++] = &isadmazone;
164 isadmazone.init(mem_start, dma32start);