11
11
compile_error ! ( "The bootloader crate must be compiled for the `x86_64-bootloader.json` target" ) ;
12
12
13
13
use bootloader:: bootinfo:: { BootInfo , FrameRange } ;
14
+ use core:: convert:: TryInto ;
14
15
use core:: panic:: PanicInfo ;
15
16
use core:: { mem, slice} ;
16
17
use fixedvec:: alloc_stack;
17
18
use usize_conversions:: usize_from;
19
+ use x86_64:: instructions:: tlb;
18
20
use x86_64:: structures:: paging:: {
19
- frame:: PhysFrameRange , Mapper , Page , PageTableFlags , PhysFrame , RecursivePageTable , Size2MiB ,
20
- Size4KiB ,
21
+ frame:: PhysFrameRange , page_table :: PageTableEntry , Mapper , Page , PageTable , PageTableFlags ,
22
+ PhysFrame , RecursivePageTable , Size2MiB , Size4KiB ,
21
23
} ;
22
24
use x86_64:: ux:: u9;
23
25
use x86_64:: { PhysAddr , VirtAddr } ;
@@ -26,6 +28,9 @@ use x86_64::{PhysAddr, VirtAddr};
26
28
// the `map_physical_memory` is activated. Set by the build script.
27
29
include ! ( concat!( env!( "OUT_DIR" ) , "/physical_memory_offset.rs" ) ) ;
28
30
31
+ // The virtual address of the kernel stack. Set by the build script.
32
+ include ! ( concat!( env!( "OUT_DIR" ) , "/kernel_stack_address.rs" ) ) ;
33
+
29
34
global_asm ! ( include_str!( "stage_1.s" ) ) ;
30
35
global_asm ! ( include_str!( "stage_2.s" ) ) ;
31
36
global_asm ! ( include_str!( "e820.s" ) ) ;
@@ -44,6 +49,7 @@ unsafe fn context_switch(boot_info: VirtAddr, entry_point: VirtAddr, stack_point
44
49
45
50
mod boot_info;
46
51
mod frame_allocator;
52
+ mod level4_entries;
47
53
mod page_table;
48
54
mod printer;
49
55
@@ -74,6 +80,7 @@ extern "C" {
74
80
static __page_table_end: usize ;
75
81
static __bootloader_end: usize ;
76
82
static __bootloader_start: usize ;
83
+ static _p4: usize ;
77
84
}
78
85
79
86
#[ no_mangle]
@@ -90,6 +97,7 @@ pub unsafe extern "C" fn stage_4() -> ! {
90
97
let page_table_end = & __page_table_end as * const _ as u64 ;
91
98
let bootloader_start = & __bootloader_start as * const _ as u64 ;
92
99
let bootloader_end = & __bootloader_end as * const _ as u64 ;
100
+ let p4_physical = & _p4 as * const _ as u64 ;
93
101
94
102
load_elf (
95
103
IdentityMappedAddr ( PhysAddr :: new ( kernel_start) ) ,
@@ -100,6 +108,7 @@ pub unsafe extern "C" fn stage_4() -> ! {
100
108
PhysAddr :: new ( page_table_end) ,
101
109
PhysAddr :: new ( bootloader_start) ,
102
110
PhysAddr :: new ( bootloader_end) ,
111
+ PhysAddr :: new ( p4_physical) ,
103
112
)
104
113
}
105
114
@@ -112,6 +121,7 @@ fn load_elf(
112
121
page_table_end : PhysAddr ,
113
122
bootloader_start : PhysAddr ,
114
123
bootloader_end : PhysAddr ,
124
+ p4_physical : PhysAddr ,
115
125
) -> ! {
116
126
use bootloader:: bootinfo:: { MemoryRegion , MemoryRegionType } ;
117
127
use fixedvec:: FixedVec ;
@@ -149,11 +159,25 @@ fn load_elf(
149
159
}
150
160
}
151
161
162
+ // Mark used virtual addresses
163
+ let mut level4_entries = level4_entries:: UsedLevel4Entries :: new ( & segments) ;
164
+
152
165
// Enable support for the no-execute bit in page tables.
153
166
enable_nxe_bit ( ) ;
154
167
155
- // Create a RecursivePageTable
156
- let recursive_index = u9:: new ( 511 ) ;
168
+ // Create a recursive page table entry
169
+ let recursive_index = u9:: new ( level4_entries. get_free_entry ( ) . try_into ( ) . unwrap ( ) ) ;
170
+ let mut entry = PageTableEntry :: new ( ) ;
171
+ entry. set_addr (
172
+ p4_physical,
173
+ PageTableFlags :: PRESENT | PageTableFlags :: WRITABLE ,
174
+ ) ;
175
+
176
+ // Write the recursive entry into the page table
177
+ let page_table = unsafe { & mut * ( p4_physical. as_u64 ( ) as * mut PageTable ) } ;
178
+ page_table[ recursive_index] = entry;
179
+ tlb:: flush_all ( ) ;
180
+
157
181
let recursive_page_table_addr = Page :: from_page_table_indices (
158
182
recursive_index,
159
183
recursive_index,
@@ -211,18 +235,14 @@ fn load_elf(
211
235
rec_page_table. unmap ( page) . expect ( "dealloc error" ) . 1 . flush ( ) ;
212
236
}
213
237
214
- // Map kernel segments.
215
- let stack_end = page_table:: map_kernel (
216
- kernel_start. phys ( ) ,
217
- & segments,
218
- & mut rec_page_table,
219
- & mut frame_allocator,
220
- )
221
- . expect ( "kernel mapping failed" ) ;
222
-
223
238
// Map a page for the boot info structure
224
239
let boot_info_page = {
225
- let page: Page = Page :: containing_address ( VirtAddr :: new ( 0xb0071f0000 ) ) ;
240
+ let page: Page = Page :: from_page_table_indices (
241
+ level4_entries. get_free_entry ( ) ,
242
+ u9:: new ( 0 ) ,
243
+ u9:: new ( 0 ) ,
244
+ u9:: new ( 0 ) ,
245
+ ) ;
226
246
let frame = frame_allocator
227
247
. allocate_frame ( MemoryRegionType :: BootInfo )
228
248
. expect ( "frame allocation failed" ) ;
@@ -241,13 +261,38 @@ fn load_elf(
241
261
page
242
262
} ;
243
263
244
- if cfg ! ( feature = "map_physical_memory" ) {
245
- fn virt_for_phys ( phys : PhysAddr ) -> VirtAddr {
246
- VirtAddr :: new ( phys. as_u64 ( ) + PHYSICAL_MEMORY_OFFSET )
247
- }
264
+ // If no kernel stack address is provided, map the kernel stack after the boot info page
265
+ let kernel_stack_address = match KERNEL_STACK_ADDRESS {
266
+ Some ( addr) => Page :: containing_address ( VirtAddr :: new ( addr) ) ,
267
+ None => boot_info_page + 1 ,
268
+ } ;
269
+
270
+ // Map kernel segments.
271
+ let stack_end = page_table:: map_kernel (
272
+ kernel_start. phys ( ) ,
273
+ kernel_stack_address,
274
+ & segments,
275
+ & mut rec_page_table,
276
+ & mut frame_allocator,
277
+ )
278
+ . expect ( "kernel mapping failed" ) ;
279
+
280
+ let physical_memory_offset = if cfg ! ( feature = "map_physical_memory" ) {
281
+ let physical_memory_offset = PHYSICAL_MEMORY_OFFSET . unwrap_or_else ( || {
282
+ // If offset not manually provided, find a free p4 entry and map memory here.
283
+ // One level 4 entry spans 2^48/512 bytes (over 500gib) so this should suffice.
284
+ assert ! ( max_phys_addr < ( 1 << 48 ) / 512 ) ;
285
+ Page :: from_page_table_indices_1gib ( level4_entries. get_free_entry ( ) , u9:: new ( 0 ) )
286
+ . start_address ( )
287
+ . as_u64 ( )
288
+ } ) ;
289
+
290
+ let virt_for_phys =
291
+ |phys : PhysAddr | -> VirtAddr { VirtAddr :: new ( phys. as_u64 ( ) + physical_memory_offset) } ;
248
292
249
293
let start_frame = PhysFrame :: < Size2MiB > :: containing_address ( PhysAddr :: new ( 0 ) ) ;
250
294
let end_frame = PhysFrame :: < Size2MiB > :: containing_address ( PhysAddr :: new ( max_phys_addr) ) ;
295
+
251
296
for frame in PhysFrame :: range_inclusive ( start_frame, end_frame) {
252
297
let page = Page :: containing_address ( virt_for_phys ( frame. start_address ( ) ) ) ;
253
298
let flags = PageTableFlags :: PRESENT | PageTableFlags :: WRITABLE ;
@@ -263,13 +308,17 @@ fn load_elf(
263
308
. expect ( "Mapping of bootinfo page failed" )
264
309
. flush ( ) ;
265
310
}
266
- }
311
+
312
+ physical_memory_offset
313
+ } else {
314
+ 0 // Value is unused by BootInfo::new, so this doesn't matter
315
+ } ;
267
316
268
317
// Construct boot info structure.
269
318
let mut boot_info = BootInfo :: new (
270
319
memory_map,
271
320
recursive_page_table_addr. as_u64 ( ) ,
272
- PHYSICAL_MEMORY_OFFSET ,
321
+ physical_memory_offset ,
273
322
) ;
274
323
boot_info. memory_map . sort ( ) ;
275
324
0 commit comments