1
- use core:: convert:: TryInto ;
1
+ use core:: { alloc:: Layout , convert:: TryInto } ;
2
+ use usize_conversions:: IntoUsize ;
2
3
use x86_64:: {
3
- structures:: paging:: { Page , PageTableIndex } ,
4
- VirtAddr ,
4
+ structures:: paging:: { Page , PageTableIndex , Size4KiB } ,
5
+ PhysAddr , VirtAddr ,
5
6
} ;
6
7
use xmas_elf:: program:: ProgramHeader ;
7
8
9
+ use crate :: {
10
+ binary:: { MemoryRegion , CONFIG } ,
11
+ BootInfo ,
12
+ } ;
13
+
8
14
/// Keeps track of used entries in a level 4 page table.
9
15
///
10
16
/// Useful for determining a free virtual memory block, e.g. for mapping additional data.
@@ -13,35 +19,86 @@ pub struct UsedLevel4Entries {
13
19
}
14
20
15
21
impl UsedLevel4Entries {
16
- /// Initializes a new instance from the given ELF program segments .
22
+ /// Initializes a new instance.
17
23
///
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 {
23
26
let mut used = UsedLevel4Entries {
24
27
entry_state : [ false ; 512 ] ,
25
28
} ;
26
29
27
30
used. entry_state [ 0 ] = true ; // TODO: Can we do this dynamically?
28
31
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
+ }
36
56
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) ;
39
60
}
40
61
}
41
62
42
63
used
43
64
}
44
65
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
+
45
102
/// Returns a unused level 4 entry and marks it as used.
46
103
///
47
104
/// Since this method marks each returned index as used, it can be used multiple times
0 commit comments