@@ -207,17 +207,20 @@ where
207207 . expect ( "no entry point" ) ;
208208 log:: info!( "Entry point at: {:#x}" , entry_point. as_u64( ) ) ;
209209 // 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
220220 } ;
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 ) ;
221224 for page in Page :: range_inclusive ( stack_start, stack_end) {
222225 let frame = frame_allocator
223226 . allocate_frame ( )
@@ -265,13 +268,12 @@ where
265268 let framebuffer_start_frame: PhysFrame = PhysFrame :: containing_address ( framebuffer. addr ) ;
266269 let framebuffer_end_frame =
267270 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 (
269272 config. mappings . framebuffer ,
270273 u64:: from_usize ( framebuffer. info . byte_len ) ,
271- Size4KiB :: SIZE ,
272274 & mut used_entries,
273- ) )
274- . expect ( "the framebuffer address must be page aligned" ) ;
275+ "framebuffer" ,
276+ ) ;
275277 for ( i, frame) in
276278 PhysFrame :: range_inclusive ( framebuffer_start_frame, framebuffer_end_frame) . enumerate ( )
277279 {
@@ -292,19 +294,17 @@ where
292294 } ;
293295 let ramdisk_slice_len = system_info. ramdisk_len ;
294296 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 (
296298 config. mappings . ramdisk_memory ,
297299 system_info. ramdisk_len ,
298- Size4KiB :: SIZE ,
299300 & mut used_entries,
301+ "ramdisk start" ,
300302 ) ;
301303 let physical_address = PhysAddr :: new ( ramdisk_address) ;
302304 let ramdisk_physical_start_page: PhysFrame < Size4KiB > =
303305 PhysFrame :: containing_address ( physical_address) ;
304306 let ramdisk_page_count = ( system_info. ramdisk_len - 1 ) / Size4KiB :: SIZE ;
305307 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" ) ;
308308
309309 let flags = PageTableFlags :: PRESENT | PageTableFlags :: WRITABLE ;
310310 for ( i, frame) in
@@ -320,7 +320,7 @@ where
320320 ) ,
321321 } ;
322322 }
323- Some ( ramdisk_address_start )
323+ Some ( start_page . start_address ( ) )
324324 } else {
325325 None
326326 } ;
@@ -334,7 +334,8 @@ where
334334
335335 let size = max_phys. as_u64 ( ) ;
336336 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" ) ;
338339
339340 for frame in PhysFrame :: range_inclusive ( start_frame, end_frame) {
340341 let page = Page :: containing_address ( offset + frame. start_address ( ) . as_u64 ( ) ) ;
@@ -390,7 +391,10 @@ where
390391 Mappings {
391392 framebuffer : framebuffer_virt_addr,
392393 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 ) ,
394398 used_entries,
395399 physical_memory_offset,
396400 recursive_index,
@@ -407,8 +411,8 @@ where
407411pub struct Mappings {
408412 /// The entry point address of the kernel.
409413 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 ,
412416 /// Keeps track of used entries in the level 4 page table, useful for finding a free
413417 /// virtual memory when needed.
414418 pub used_entries : UsedLevel4Entries ,
@@ -462,11 +466,8 @@ where
462466 u64:: from_usize ( combined. size ( ) ) ,
463467 u64:: from_usize ( combined. align ( ) ) ,
464468 & 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" ) ;
470471
471472 let memory_map_regions_addr = boot_info_addr + memory_regions_offset;
472473 let memory_map_regions_end = boot_info_addr + combined. size ( ) ;
@@ -561,7 +562,7 @@ pub fn switch_to_kernel(
561562 } = page_tables;
562563 let addresses = Addresses {
563564 page_table : kernel_level_4_frame,
564- stack_top : mappings. stack_end . start_address ( ) ,
565+ stack_top : mappings. stack_top ,
565566 entry_point : mappings. entry_point ,
566567 boot_info,
567568 } ;
@@ -612,15 +613,32 @@ struct Addresses {
612613 boot_info : & ' static mut BootInfo ,
613614}
614615
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+
615628fn mapping_addr (
616629 mapping : Mapping ,
617630 size : u64 ,
618631 alignment : u64 ,
619632 used_entries : & mut UsedLevel4Entries ,
620- ) -> VirtAddr {
621- match mapping {
633+ ) -> Result < VirtAddr , VirtAddr > {
634+ let addr = match mapping {
622635 Mapping :: FixedAddress ( addr) => VirtAddr :: new ( addr) ,
623636 Mapping :: Dynamic => used_entries. get_free_address ( size, alignment) ,
637+ } ;
638+ if addr. is_aligned ( alignment) {
639+ Ok ( addr)
640+ } else {
641+ Err ( addr)
624642 }
625643}
626644
0 commit comments