@@ -207,17 +207,20 @@ where
207
207
. expect ( "no entry point" ) ;
208
208
log:: info!( "Entry point at: {:#x}" , entry_point. as_u64( ) ) ;
209
209
// create a stack
210
- let stack_start_addr = mapping_addr (
211
- config . mappings . kernel_stack ,
212
- config . kernel_stack_size ,
213
- 16 ,
214
- & mut used_entries ,
215
- ) ;
216
- let stack_start : Page = Page :: containing_address ( stack_start_addr ) ;
217
- let stack_end = {
218
- let end_addr = stack_start_addr + config . kernel_stack_size ;
219
- Page :: containing_address ( end_addr - 1u64 )
210
+ let stack_start = {
211
+ // we need page-alignment because we want a guard page directly below the stack
212
+ let guard_page = mapping_addr_page_aligned (
213
+ config . mappings . kernel_stack ,
214
+ // allocate an additional page as a guard page
215
+ Size4KiB :: SIZE + config . kernel_stack_size ,
216
+ & mut used_entries ,
217
+ "kernel stack start" ,
218
+ ) ;
219
+ guard_page + 1
220
220
} ;
221
+ let stack_end_addr = stack_start. start_address ( ) + config. kernel_stack_size ;
222
+
223
+ let stack_end = Page :: containing_address ( stack_end_addr - 1u64 ) ;
221
224
for page in Page :: range_inclusive ( stack_start, stack_end) {
222
225
let frame = frame_allocator
223
226
. allocate_frame ( )
@@ -265,13 +268,12 @@ where
265
268
let framebuffer_start_frame: PhysFrame = PhysFrame :: containing_address ( framebuffer. addr ) ;
266
269
let framebuffer_end_frame =
267
270
PhysFrame :: containing_address ( framebuffer. addr + framebuffer. info . byte_len - 1u64 ) ;
268
- let start_page = Page :: from_start_address ( mapping_addr (
271
+ let start_page = mapping_addr_page_aligned (
269
272
config. mappings . framebuffer ,
270
273
u64:: from_usize ( framebuffer. info . byte_len ) ,
271
- Size4KiB :: SIZE ,
272
274
& mut used_entries,
273
- ) )
274
- . expect ( "the framebuffer address must be page aligned" ) ;
275
+ "framebuffer" ,
276
+ ) ;
275
277
for ( i, frame) in
276
278
PhysFrame :: range_inclusive ( framebuffer_start_frame, framebuffer_end_frame) . enumerate ( )
277
279
{
@@ -292,19 +294,17 @@ where
292
294
} ;
293
295
let ramdisk_slice_len = system_info. ramdisk_len ;
294
296
let ramdisk_slice_start = if let Some ( ramdisk_address) = system_info. ramdisk_addr {
295
- let ramdisk_address_start = mapping_addr (
297
+ let start_page = mapping_addr_page_aligned (
296
298
config. mappings . ramdisk_memory ,
297
299
system_info. ramdisk_len ,
298
- Size4KiB :: SIZE ,
299
300
& mut used_entries,
301
+ "ramdisk start" ,
300
302
) ;
301
303
let physical_address = PhysAddr :: new ( ramdisk_address) ;
302
304
let ramdisk_physical_start_page: PhysFrame < Size4KiB > =
303
305
PhysFrame :: containing_address ( physical_address) ;
304
306
let ramdisk_page_count = ( system_info. ramdisk_len - 1 ) / Size4KiB :: SIZE ;
305
307
let ramdisk_physical_end_page = ramdisk_physical_start_page + ramdisk_page_count;
306
- let start_page = Page :: from_start_address ( ramdisk_address_start)
307
- . expect ( "the ramdisk start address must be page aligned" ) ;
308
308
309
309
let flags = PageTableFlags :: PRESENT | PageTableFlags :: WRITABLE ;
310
310
for ( i, frame) in
@@ -320,7 +320,7 @@ where
320
320
) ,
321
321
} ;
322
322
}
323
- Some ( ramdisk_address_start )
323
+ Some ( start_page . start_address ( ) )
324
324
} else {
325
325
None
326
326
} ;
@@ -334,7 +334,8 @@ where
334
334
335
335
let size = max_phys. as_u64 ( ) ;
336
336
let alignment = Size2MiB :: SIZE ;
337
- let offset = mapping_addr ( mapping, size, alignment, & mut used_entries) ;
337
+ let offset = mapping_addr ( mapping, size, alignment, & mut used_entries)
338
+ . expect ( "start address for physical memory mapping must be 2MiB-page-aligned" ) ;
338
339
339
340
for frame in PhysFrame :: range_inclusive ( start_frame, end_frame) {
340
341
let page = Page :: containing_address ( offset + frame. start_address ( ) . as_u64 ( ) ) ;
@@ -390,7 +391,10 @@ where
390
391
Mappings {
391
392
framebuffer : framebuffer_virt_addr,
392
393
entry_point,
393
- stack_end,
394
+ // Use the configured stack size, even if it's not page-aligned. However, we
395
+ // need to align it down to the next 16-byte boundary because the System V
396
+ // ABI requires a 16-byte stack alignment.
397
+ stack_top : stack_end_addr. align_down ( 16u8 ) ,
394
398
used_entries,
395
399
physical_memory_offset,
396
400
recursive_index,
@@ -407,8 +411,8 @@ where
407
411
pub struct Mappings {
408
412
/// The entry point address of the kernel.
409
413
pub entry_point : VirtAddr ,
410
- /// The stack end page of the kernel.
411
- pub stack_end : Page ,
414
+ /// The (exclusive) end address of the kernel stack .
415
+ pub stack_top : VirtAddr ,
412
416
/// Keeps track of used entries in the level 4 page table, useful for finding a free
413
417
/// virtual memory when needed.
414
418
pub used_entries : UsedLevel4Entries ,
@@ -462,11 +466,8 @@ where
462
466
u64:: from_usize ( combined. size ( ) ) ,
463
467
u64:: from_usize ( combined. align ( ) ) ,
464
468
& mut mappings. used_entries ,
465
- ) ;
466
- assert ! (
467
- boot_info_addr. is_aligned( u64 :: from_usize( combined. align( ) ) ) ,
468
- "boot info addr is not properly aligned"
469
- ) ;
469
+ )
470
+ . expect ( "boot info addr is not properly aligned" ) ;
470
471
471
472
let memory_map_regions_addr = boot_info_addr + memory_regions_offset;
472
473
let memory_map_regions_end = boot_info_addr + combined. size ( ) ;
@@ -561,7 +562,7 @@ pub fn switch_to_kernel(
561
562
} = page_tables;
562
563
let addresses = Addresses {
563
564
page_table : kernel_level_4_frame,
564
- stack_top : mappings. stack_end . start_address ( ) ,
565
+ stack_top : mappings. stack_top ,
565
566
entry_point : mappings. entry_point ,
566
567
boot_info,
567
568
} ;
@@ -612,15 +613,32 @@ struct Addresses {
612
613
boot_info : & ' static mut BootInfo ,
613
614
}
614
615
616
+ fn mapping_addr_page_aligned (
617
+ mapping : Mapping ,
618
+ size : u64 ,
619
+ used_entries : & mut UsedLevel4Entries ,
620
+ kind : & str ,
621
+ ) -> Page {
622
+ match mapping_addr ( mapping, size, Size4KiB :: SIZE , used_entries) {
623
+ Ok ( addr) => Page :: from_start_address ( addr) . unwrap ( ) ,
624
+ Err ( addr) => panic ! ( "{kind} address must be page-aligned (is `{addr:?})`" ) ,
625
+ }
626
+ }
627
+
615
628
fn mapping_addr (
616
629
mapping : Mapping ,
617
630
size : u64 ,
618
631
alignment : u64 ,
619
632
used_entries : & mut UsedLevel4Entries ,
620
- ) -> VirtAddr {
621
- match mapping {
633
+ ) -> Result < VirtAddr , VirtAddr > {
634
+ let addr = match mapping {
622
635
Mapping :: FixedAddress ( addr) => VirtAddr :: new ( addr) ,
623
636
Mapping :: Dynamic => used_entries. get_free_address ( size, alignment) ,
637
+ } ;
638
+ if addr. is_aligned ( alignment) {
639
+ Ok ( addr)
640
+ } else {
641
+ Err ( addr)
624
642
}
625
643
}
626
644
0 commit comments