11use core:: sync:: atomic:: { AtomicUsize , Ordering } ;
22
33use align_address:: Align ;
4- use free_list:: { FreeList , PageRange } ;
4+ use free_list:: { FreeList , PageRange , PageRangeError } ;
55use hermit_sync:: InterruptTicketMutex ;
66use memory_addresses:: { PhysAddr , VirtAddr } ;
77
@@ -19,7 +19,7 @@ pub fn total_memory_size() -> usize {
1919 TOTAL_MEMORY . load ( Ordering :: Relaxed )
2020}
2121
22- pub unsafe fn init_frame_range ( frame_range : PageRange ) {
22+ pub unsafe fn map_frame_range ( frame_range : PageRange ) {
2323 cfg_if:: cfg_if! {
2424 if #[ cfg( target_arch = "aarch64" ) ] {
2525 type IdentityPageSize = crate :: arch:: mm:: paging:: BasePageSize ;
@@ -37,10 +37,6 @@ pub unsafe fn init_frame_range(frame_range: PageRange) {
3737 . end ( )
3838 . align_up ( IdentityPageSize :: SIZE . try_into ( ) . unwrap ( ) ) ;
3939
40- unsafe {
41- PHYSICAL_FREE_LIST . lock ( ) . deallocate ( frame_range) . unwrap ( ) ;
42- }
43-
4440 ( start..end)
4541 . step_by ( IdentityPageSize :: SIZE . try_into ( ) . unwrap ( ) )
4642 . map ( |addr| PhysAddr :: new ( addr. try_into ( ) . unwrap ( ) ) )
@@ -61,58 +57,104 @@ pub unsafe fn init_frame_range(frame_range: PageRange) {
6157 paging:: map :: < IdentityPageSize > ( virt_addr, phys_addr, 1 , flags) ;
6258 } ) ;
6359 }
64-
65- TOTAL_MEMORY . fetch_add ( frame_range. len ( ) . get ( ) , Ordering :: Relaxed ) ;
6660}
6761
6862fn detect_from_fdt ( ) -> Result < ( ) , ( ) > {
6963 let fdt = env:: fdt ( ) . ok_or ( ( ) ) ?;
7064
65+ let all_regions = fdt
66+ . find_all_nodes ( "/memory" )
67+ . map ( |m| m. reg ( ) . unwrap ( ) . next ( ) . unwrap ( ) ) ;
68+ if all_regions. count ( ) == 0 {
69+ return Err ( ( ) ) ;
70+ }
7171 let all_regions = fdt
7272 . find_all_nodes ( "/memory" )
7373 . map ( |m| m. reg ( ) . unwrap ( ) . next ( ) . unwrap ( ) ) ;
7474
75- let mut found_ram = false ;
75+ for m in all_regions {
76+ let start_address = m. starting_address as u64 ;
77+ let size = m. size . unwrap ( ) as u64 ;
78+ let end_address = start_address + size;
7679
77- if env:: is_uefi ( ) {
78- let biggest_region = all_regions . max_by_key ( |m| m . size . unwrap ( ) ) . unwrap ( ) ;
79- found_ram = true ;
80+ if end_address <= super :: kernel_end_address ( ) . as_u64 ( ) && ! env:: is_uefi ( ) {
81+ continue ;
82+ }
8083
81- let range = PageRange :: from_start_len (
82- biggest_region. starting_address . addr ( ) ,
83- biggest_region. size . unwrap ( ) ,
84- )
85- . unwrap ( ) ;
84+ let start_address =
85+ if start_address <= super :: kernel_start_address ( ) . as_u64 ( ) && !env:: is_uefi ( ) {
86+ super :: kernel_end_address ( )
87+ } else {
88+ VirtAddr :: new ( start_address)
89+ } ;
8690
91+ let range = PageRange :: new ( start_address. as_usize ( ) , end_address as usize ) . unwrap ( ) ;
8792 unsafe {
88- init_frame_range ( range) ;
93+ PHYSICAL_FREE_LIST . lock ( ) . deallocate ( range) . unwrap ( ) ;
94+ map_frame_range ( range) ;
8995 }
96+ TOTAL_MEMORY . fetch_add ( range. len ( ) . get ( ) , Ordering :: Relaxed ) ;
97+ debug ! ( "Claimed physical memory: {range:#x?}" ) ;
98+ }
99+
100+ let reserve = |reservation : PageRange | {
101+ debug ! ( "Memory reservation: {reservation:#x?}" ) ;
102+ // While there are still overlaps between this reservation and any available ranges,
103+ // allocate that overlap to mark it as not available.
104+ while let Ok ( reserved) = PHYSICAL_FREE_LIST
105+ . lock ( )
106+ . allocate_with ( |range| reservation. and ( range) )
107+ {
108+ debug ! ( "Reserved {reserved:#x?}" ) ;
109+ }
110+ } ;
111+
112+ for reservation in fdt. memory_reservations ( ) {
113+ let start = reservation. address ( ) . addr ( ) ;
114+ let end = start + reservation. size ( ) ;
115+ let reservation = PageRange :: new ( start, end) . unwrap ( ) ;
116+ reserve ( reservation) ;
117+ }
118+
119+ let kernel_start = if env:: is_uefi ( ) {
120+ super :: kernel_start_address ( ) . as_usize ( )
90121 } else {
91- for m in all_regions {
92- let start_address = m. starting_address as u64 ;
93- let size = m. size . unwrap ( ) as u64 ;
94- let end_address = start_address + size;
122+ // FIXME: Memory before the kernel causes trouble on non-uefi systems.
123+ // It is unclear, which exact regions cause problems.
124+ 0
125+ } ;
126+ let kernel_end = super :: kernel_end_address ( ) . as_usize ( ) ;
127+ let kernel_region = PageRange :: new ( kernel_start, kernel_end) . unwrap ( ) ;
128+ reserve ( kernel_region) ;
129+
130+ let fdt_start = env:: boot_info ( ) . hardware_info . device_tree . unwrap ( ) . get ( ) ;
131+ let fdt_start = usize:: try_from ( fdt_start) . unwrap ( ) ;
132+ let fdt_end = fdt_start + fdt. total_size ( ) ;
133+ let fdt_region = PageRange :: containing ( fdt_start, fdt_end) . unwrap ( ) ;
134+ reserve ( fdt_region) ;
95135
96- if end_address <= super :: kernel_end_address ( ) . as_u64 ( ) {
97- continue ;
98- }
136+ Ok ( ( ) )
137+ }
99138
100- found_ram = true ;
139+ // FIXME: upstream these
140+ trait PageRangeExt : Sized {
141+ fn containing ( start : usize , end : usize ) -> Result < Self , PageRangeError > ;
101142
102- let start_address = if start_address <= super :: kernel_start_address ( ) . as_u64 ( ) {
103- super :: kernel_end_address ( )
104- } else {
105- VirtAddr :: new ( start_address)
106- } ;
143+ fn and ( self , rhs : Self ) -> Option < Self > ;
144+ }
107145
108- let range = PageRange :: new ( start_address . as_usize ( ) , end_address as usize ) . unwrap ( ) ;
109- unsafe {
110- init_frame_range ( range ) ;
111- }
112- }
146+ impl PageRangeExt for PageRange {
147+ fn containing ( start : usize , end : usize ) -> Result < Self , PageRangeError > {
148+ let start = start . align_down ( free_list :: PAGE_SIZE ) ;
149+ let end = end . align_up ( free_list :: PAGE_SIZE ) ;
150+ Self :: new ( start , end )
113151 }
114152
115- if found_ram { Ok ( ( ) ) } else { Err ( ( ) ) }
153+ fn and ( self , rhs : Self ) -> Option < Self > {
154+ let start = self . start ( ) . max ( rhs. start ( ) ) ;
155+ let end = self . end ( ) . min ( rhs. end ( ) ) ;
156+ Self :: new ( start, end) . ok ( )
157+ }
116158}
117159
118160#[ cfg( any( target_arch = "aarch64" , target_arch = "riscv64" ) ) ]
@@ -130,8 +172,10 @@ fn detect_from_limits() -> Result<(), ()> {
130172 let range =
131173 PageRange :: new ( super :: kernel_end_address ( ) . as_usize ( ) , ram_address + limit) . unwrap ( ) ;
132174 unsafe {
133- init_frame_range ( range) ;
175+ PHYSICAL_FREE_LIST . lock ( ) . deallocate ( range) . unwrap ( ) ;
176+ map_frame_range ( range) ;
134177 }
178+ TOTAL_MEMORY . fetch_add ( range. len ( ) . get ( ) , Ordering :: Relaxed ) ;
135179
136180 Ok ( ( ) )
137181}
0 commit comments