1- use core:: convert:: TryInto ;
1+ use crate :: BootInfo ;
2+ use bootloader_api:: { config, info:: MemoryRegion , BootloaderConfig } ;
3+ use core:: { alloc:: Layout , convert:: TryInto } ;
4+ use usize_conversions:: IntoUsize ;
25use x86_64:: {
3- structures:: paging:: { Page , PageTableIndex } ,
4- VirtAddr ,
6+ structures:: paging:: { Page , PageTableIndex , Size4KiB } ,
7+ PhysAddr , VirtAddr ,
58} ;
69use xmas_elf:: program:: ProgramHeader ;
710
@@ -13,35 +16,92 @@ pub struct UsedLevel4Entries {
1316}
1417
1518impl UsedLevel4Entries {
16- /// Initializes a new instance from the given ELF program segments .
19+ /// Initializes a new instance.
1720 ///
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 ,
21+ /// Marks the statically configured virtual address ranges from the config as used.
22+ pub fn new (
23+ max_phys_addr : PhysAddr ,
24+ regions_len : usize ,
25+ framebuffer_size : usize ,
26+ config : & BootloaderConfig ,
2227 ) -> Self {
2328 let mut used = UsedLevel4Entries {
2429 entry_state : [ false ; 512 ] ,
2530 } ;
2631
2732 used. entry_state [ 0 ] = true ; // TODO: Can we do this dynamically?
2833
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- ) ) ;
36-
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 ;
39- }
34+ // Mark the statically configured ranges from the config as used.
35+
36+ if let Some ( config:: Mapping :: FixedAddress ( physical_memory_offset) ) =
37+ config. mappings . physical_memory
38+ {
39+ used. mark_range_as_used ( physical_memory_offset, max_phys_addr. as_u64 ( ) . into_usize ( ) ) ;
40+ }
41+
42+ if let Some ( config:: Mapping :: FixedAddress ( recursive_address) ) =
43+ config. mappings . page_table_recursive
44+ {
45+ let recursive_index = VirtAddr :: new ( recursive_address) . p4_index ( ) ;
46+ used. mark_p4_index_as_used ( recursive_index) ;
47+ }
48+
49+ if let config:: Mapping :: FixedAddress ( kernel_stack_address) = config. mappings . kernel_stack {
50+ used. mark_range_as_used ( kernel_stack_address, config. kernel_stack_size ) ;
51+ }
52+
53+ if let config:: Mapping :: FixedAddress ( boot_info_address) = config. mappings . boot_info {
54+ let boot_info_layout = Layout :: new :: < BootInfo > ( ) ;
55+ let regions = regions_len + 1 ; // one region might be split into used/unused
56+ let memory_regions_layout = Layout :: array :: < MemoryRegion > ( regions) . unwrap ( ) ;
57+ let ( combined, _) = boot_info_layout. extend ( memory_regions_layout) . unwrap ( ) ;
58+
59+ used. mark_range_as_used ( boot_info_address, combined. size ( ) ) ;
60+ }
61+
62+ if let config:: Mapping :: FixedAddress ( framebuffer_address) = config. mappings . framebuffer {
63+ used. mark_range_as_used ( framebuffer_address, framebuffer_size) ;
4064 }
4165
4266 used
4367 }
4468
69+ /// Mark all p4 entries in the range `[address..address+size)` as used.
70+ ///
71+ /// `size` can be a `u64` or `usize`.
72+ fn mark_range_as_used < S > ( & mut self , address : u64 , size : S )
73+ where
74+ VirtAddr : core:: ops:: Add < S , Output = VirtAddr > ,
75+ {
76+ let start = VirtAddr :: new ( address) ;
77+ let end_inclusive = ( start + size) - 1usize ;
78+ let start_page = Page :: < Size4KiB > :: containing_address ( start) ;
79+ let end_page_inclusive = Page :: < Size4KiB > :: containing_address ( end_inclusive) ;
80+
81+ for p4_index in u16:: from ( start_page. p4_index ( ) ) ..=u16:: from ( end_page_inclusive. p4_index ( ) )
82+ {
83+ self . mark_p4_index_as_used ( PageTableIndex :: new ( p4_index) ) ;
84+ }
85+ }
86+
87+ fn mark_p4_index_as_used ( & mut self , p4_index : PageTableIndex ) {
88+ self . entry_state [ usize:: from ( p4_index) ] = true ;
89+ }
90+
91+ /// Marks the virtual address range of all segments as used.
92+ pub fn mark_segments < ' a > (
93+ & mut self ,
94+ segments : impl Iterator < Item = ProgramHeader < ' a > > ,
95+ virtual_address_offset : u64 ,
96+ ) {
97+ for segment in segments. filter ( |s| s. mem_size ( ) > 0 ) {
98+ self . mark_range_as_used (
99+ segment. virtual_addr ( ) + virtual_address_offset,
100+ segment. mem_size ( ) ,
101+ ) ;
102+ }
103+ }
104+
45105 /// Returns a unused level 4 entry and marks it as used.
46106 ///
47107 /// Since this method marks each returned index as used, it can be used multiple times
0 commit comments