1- use core:: convert:: TryInto ;
1+ use core:: { alloc:: Layout , convert:: TryInto } ;
2+ use usize_conversions:: IntoUsize ;
23use x86_64:: {
3- structures:: paging:: { Page , PageTableIndex } ,
4- VirtAddr ,
4+ structures:: paging:: { Page , PageTableIndex , Size4KiB } ,
5+ PhysAddr , VirtAddr ,
56} ;
67use xmas_elf:: program:: ProgramHeader ;
78
9+ use crate :: {
10+ binary:: { MemoryRegion , CONFIG } ,
11+ BootInfo ,
12+ } ;
13+
814/// Keeps track of used entries in a level 4 page table.
915///
1016/// Useful for determining a free virtual memory block, e.g. for mapping additional data.
@@ -13,35 +19,86 @@ pub struct UsedLevel4Entries {
1319}
1420
1521impl UsedLevel4Entries {
16- /// Initializes a new instance from the given ELF program segments .
22+ /// Initializes a new instance.
1723 ///
18- /// Marks the virtual address range of all segments as used.
19- pub fn new < ' a > (
20- segments : impl Iterator < Item = ProgramHeader < ' a > > ,
21- virtual_address_offset : u64 ,
22- ) -> Self {
24+ /// Marks the statically configured virtual address ranges from the config as used.
25+ pub fn new ( max_phys_addr : PhysAddr , regions_len : usize , framebuffer_size : usize ) -> Self {
2326 let mut used = UsedLevel4Entries {
2427 entry_state : [ false ; 512 ] ,
2528 } ;
2629
2730 used. entry_state [ 0 ] = true ; // TODO: Can we do this dynamically?
2831
29- for segment in segments {
30- let start_page: Page = Page :: containing_address ( VirtAddr :: new (
31- segment. virtual_addr ( ) + virtual_address_offset,
32- ) ) ;
33- let end_page: Page = Page :: containing_address ( VirtAddr :: new (
34- segment. virtual_addr ( ) + virtual_address_offset + segment. mem_size ( ) ,
35- ) ) ;
32+ // Mark the statically configured ranges from the config as used.
33+
34+ if let Some ( physical_memory_offset) = CONFIG . physical_memory_offset {
35+ used. mark_range_as_used ( physical_memory_offset, max_phys_addr. as_u64 ( ) . into_usize ( ) ) ;
36+ }
37+
38+ if CONFIG . map_page_table_recursively {
39+ if let Some ( recursive_index) = CONFIG . recursive_index {
40+ used. mark_p4_index_as_used ( PageTableIndex :: new ( recursive_index) ) ;
41+ }
42+ }
43+
44+ if let Some ( kernel_stack_address) = CONFIG . kernel_stack_address {
45+ used. mark_range_as_used ( kernel_stack_address, CONFIG . kernel_stack_size ( ) ) ;
46+ }
47+
48+ if let Some ( boot_info_address) = CONFIG . boot_info_address {
49+ let boot_info_layout = Layout :: new :: < BootInfo > ( ) ;
50+ let regions = regions_len + 1 ; // one region might be split into used/unused
51+ let memory_regions_layout = Layout :: array :: < MemoryRegion > ( regions) . unwrap ( ) ;
52+ let ( combined, _) = boot_info_layout. extend ( memory_regions_layout) . unwrap ( ) ;
53+
54+ used. mark_range_as_used ( boot_info_address, combined. size ( ) ) ;
55+ }
3656
37- for p4_index in u64:: from ( start_page. p4_index ( ) ) ..=u64:: from ( end_page. p4_index ( ) ) {
38- used. entry_state [ p4_index as usize ] = true ;
57+ if CONFIG . map_framebuffer {
58+ if let Some ( framebuffer_address) = CONFIG . framebuffer_address {
59+ used. mark_range_as_used ( framebuffer_address, framebuffer_size) ;
3960 }
4061 }
4162
4263 used
4364 }
4465
66+ /// Mark all p4 entries in the range `[address..address+size)` as used.
67+ ///
68+ /// `size` can be a `u64` or `usize`.
69+ fn mark_range_as_used < S > ( & mut self , address : u64 , size : S )
70+ where
71+ VirtAddr : core:: ops:: Add < S , Output = VirtAddr > ,
72+ {
73+ let start = VirtAddr :: new ( address) ;
74+ let end_inclusive = ( start + size) - 1usize ;
75+ let start_page = Page :: < Size4KiB > :: containing_address ( start) ;
76+ let end_page_inclusive = Page :: < Size4KiB > :: containing_address ( end_inclusive) ;
77+
78+ for p4_index in u16:: from ( start_page. p4_index ( ) ) ..=u16:: from ( end_page_inclusive. p4_index ( ) )
79+ {
80+ self . mark_p4_index_as_used ( PageTableIndex :: new ( p4_index) ) ;
81+ }
82+ }
83+
84+ fn mark_p4_index_as_used ( & mut self , p4_index : PageTableIndex ) {
85+ self . entry_state [ usize:: from ( p4_index) ] = true ;
86+ }
87+
88+ /// Marks the virtual address range of all segments as used.
89+ pub fn mark_segments < ' a > (
90+ & mut self ,
91+ segments : impl Iterator < Item = ProgramHeader < ' a > > ,
92+ virtual_address_offset : u64 ,
93+ ) {
94+ for segment in segments. filter ( |s| s. mem_size ( ) > 0 ) {
95+ self . mark_range_as_used (
96+ segment. virtual_addr ( ) + virtual_address_offset,
97+ segment. mem_size ( ) ,
98+ ) ;
99+ }
100+ }
101+
45102 /// Returns a unused level 4 entry and marks it as used.
46103 ///
47104 /// Since this method marks each returned index as used, it can be used multiple times
0 commit comments