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 ;
2
5
use x86_64:: {
3
- structures:: paging:: { Page , PageTableIndex } ,
4
- VirtAddr ,
6
+ structures:: paging:: { Page , PageTableIndex , Size4KiB } ,
7
+ PhysAddr , VirtAddr ,
5
8
} ;
6
9
use xmas_elf:: program:: ProgramHeader ;
7
10
@@ -13,35 +16,92 @@ pub struct UsedLevel4Entries {
13
16
}
14
17
15
18
impl UsedLevel4Entries {
16
- /// Initializes a new instance from the given ELF program segments .
19
+ /// Initializes a new instance.
17
20
///
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 ,
22
27
) -> Self {
23
28
let mut used = UsedLevel4Entries {
24
29
entry_state : [ false ; 512 ] ,
25
30
} ;
26
31
27
32
used. entry_state [ 0 ] = true ; // TODO: Can we do this dynamically?
28
33
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) ;
40
64
}
41
65
42
66
used
43
67
}
44
68
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
+
45
105
/// Returns a unused level 4 entry and marks it as used.
46
106
///
47
107
/// Since this method marks each returned index as used, it can be used multiple times
0 commit comments