obkrnl/vm/phys.rs
1use super::{MemAffinity, VmPage};
2use alloc::collections::vec_deque::VecDeque;
3use alloc::sync::Arc;
4use alloc::vec::Vec;
5
6/// Provides methods to allocate physical memory.
7pub struct PhysAllocator {
8 segs: Vec<PhysSeg>, // vm_phys_segs + vm_phys_nsegs
9 nfree: usize, // vm_nfreelists
10 #[allow(clippy::type_complexity)] // TODO: Remove this.
11 lookup_lists: [Arc<[[[VecDeque<VmPage>; 13]; 3]; 2]>; 2], // vm_phys_lookup_lists
12}
13
14impl PhysAllocator {
15 /// See `vm_phys_init` on the Orbis for a reference.
16 ///
17 /// # Reference offsets
18 /// | Version | Offset |
19 /// |---------|--------|
20 /// |PS4 11.00|0x15F410|
21 pub fn new(phys_avail: &[u64; 61], ma: Option<&MemAffinity>) -> Self {
22 // Create segments.
23 let mut segs = Vec::new();
24 let mut nfree = 0;
25
26 for i in (0..).step_by(2) {
27 // Check if end entry.
28 let mut addr = phys_avail[i];
29 let end = phys_avail[i + 1];
30
31 if end == 0 {
32 break;
33 }
34
35 // TODO: Why Orbis need to create 16MB segment here?
36 if addr < 16777216 {
37 let unk = end < 0x1000001;
38
39 if !unk {
40 Self::create_seg(&mut segs, ma, addr, 0x1000000);
41
42 // The Orbis also update end address here but it seems like the value is always
43 // the same as current value.
44 addr = 0x1000000;
45 }
46
47 Self::create_seg(&mut segs, ma, addr, end);
48
49 nfree = 1;
50 } else {
51 Self::create_seg(&mut segs, ma, addr, end);
52 }
53 }
54
55 // Populate vm_phys_free_queues. Do not use Clone to construct the array here since it will
56 // refer to the same object.
57 let free_queues = [
58 Arc::<[[[VecDeque<VmPage>; 13]; 3]; 2]>::default(),
59 Arc::<[[[VecDeque<VmPage>; 13]; 3]; 2]>::default(),
60 ];
61
62 // Populate vm_phys_lookup_lists.
63 let lookup_lists = [free_queues[0].clone(), free_queues[1].clone()];
64
65 Self {
66 segs,
67 nfree,
68 lookup_lists,
69 }
70 }
71
72 /// See `vm_phys_paddr_to_vm_page` on the Orbis for a reference.
73 pub fn page_for(&mut self, pa: u64) -> Option<&mut VmPage> {
74 for s in &mut self.segs {
75 if s.start > pa || s.end <= pa {
76 continue;
77 }
78
79 todo!()
80 }
81
82 None
83 }
84
85 /// See `vm_phys_alloc_pages` on the Orbis for a reference.
86 ///
87 /// # Reference offsets
88 /// | Version | Offset |
89 /// |---------|--------|
90 /// |PS4 11.00|0x160520|
91 pub fn alloc_page(&self, vm: usize, pool: usize, order: usize) -> Option<VmPage> {
92 // TODO: There is an increasement on unknown variable here.
93 let mut i = 0;
94
95 loop {
96 let l = &self.lookup_lists[i];
97
98 if let Some(v) = self.alloc_freelist(&l[vm], pool, order) {
99 return Some(v);
100 }
101
102 i += 1;
103
104 if i >= (self.nfree + 1) {
105 break;
106 }
107 }
108
109 None
110 }
111
112 /// See `vm_phys_alloc_freelist_pages` on the Orbis for a reference.
113 ///
114 /// # Reference offsets
115 /// | Version | Offset |
116 /// |---------|--------|
117 /// |PS4 11.00|0x1605D0|
118 fn alloc_freelist(
119 &self,
120 list: &[[VecDeque<VmPage>; 13]; 3],
121 pool: usize,
122 order: usize,
123 ) -> Option<VmPage> {
124 if order >= 13 {
125 return None;
126 }
127
128 let mut i = 0;
129
130 loop {
131 match list[pool][order + i].front() {
132 Some(v) => v,
133 None => match (order + i) < 12 {
134 true => {
135 i += 1;
136 continue;
137 }
138 false => break,
139 },
140 };
141
142 todo!()
143 }
144
145 let mut next = 11;
146
147 loop {
148 let mut found = None;
149
150 for f in list {
151 found = f[next + 1].front();
152
153 if found.is_some() {
154 break;
155 }
156 }
157
158 match found {
159 Some(_) => todo!(),
160 None => {
161 if next < order || next == 0 {
162 break;
163 }
164
165 next -= 1;
166 }
167 }
168 }
169
170 None
171 }
172
173 /// See `vm_phys_create_seg` on the Orbis for a reference.
174 ///
175 /// # Reference offsets
176 /// | Version | Offset |
177 /// |---------|--------|
178 /// |PS4 11.00|0x15F8A0|
179 fn create_seg(segs: &mut Vec<PhysSeg>, ma: Option<&MemAffinity>, start: u64, end: u64) {
180 match ma {
181 Some(_) => todo!(),
182 None => segs.push(PhysSeg { start, end }),
183 }
184 }
185}
186
187/// Implementation of `vm_phys_seg` structure.
188struct PhysSeg {
189 start: u64,
190 end: u64,
191}