Skip to content

Commit 8e25d63

Browse files
author
Jiajie Chen
committed
Add rv39 and rv64 page tables
1 parent 58b3c27 commit 8e25d63

File tree

2 files changed

+233
-6
lines changed

2 files changed

+233
-6
lines changed

src/addr.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,6 @@ impl Page {
218218
p2_index: usize,
219219
p1_index: usize,
220220
) -> Self {
221-
use bit_field::BitField;
222221
let mut addr: usize = 0;
223222
addr.set_bits(39..48, p4_index);
224223
addr.set_bits(30..39, p3_index);
@@ -234,7 +233,6 @@ impl Page {
234233

235234
#[cfg(riscv32)]
236235
pub fn from_page_table_indices(p2_index: usize, p1_index: usize) -> Self {
237-
use bit_field::BitField;
238236
let mut addr: usize = 0;
239237
addr.set_bits(22..32, p2_index);
240238
addr.set_bits(12..22, p1_index);

src/paging/multi_level.rs

Lines changed: 233 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@ use super::recursive::*;
44
use crate::addr::*;
55

66
/// This struct is a two level page table with `Mapper` trait implemented.
7-
pub struct TwoLevelPageTable<'a> {
7+
#[cfg(riscv32)]
8+
pub struct Rv32PageTable<'a> {
89
root_table: &'a mut PageTable,
910
linear_offset: usize, // VA = PA + linear_offset
1011
}
1112

12-
impl<'a> TwoLevelPageTable<'a> {
13+
#[cfg(riscv32)]
14+
impl<'a> Rv32PageTable<'a> {
1315
pub fn new(table: &'a mut PageTable, linear_offset: usize) -> Self {
14-
TwoLevelPageTable {
16+
Rv32PageTable {
1517
root_table: table,
1618
linear_offset,
1719
}
@@ -36,7 +38,8 @@ impl<'a> TwoLevelPageTable<'a> {
3638
}
3739
}
3840

39-
impl<'a> Mapper for TwoLevelPageTable<'a> {
41+
#[cfg(riscv32)]
42+
impl<'a> Mapper for Rv32PageTable<'a> {
4043
fn map_to(
4144
&mut self,
4245
page: Page,
@@ -76,3 +79,229 @@ impl<'a> Mapper for TwoLevelPageTable<'a> {
7679
Ok(&mut p1_table[page.p1_index()])
7780
}
7881
}
82+
83+
84+
/// This struct is a three level page table with `Mapper` trait implemented.
85+
#[cfg(riscv64)]
86+
pub struct Rv39PageTable<'a> {
87+
root_table: &'a mut PageTable,
88+
linear_offset: usize, // VA = PA + linear_offset
89+
}
90+
91+
#[cfg(riscv64)]
92+
impl<'a> Rv39PageTable<'a> {
93+
pub fn new(table: &'a mut PageTable, linear_offset: usize) -> Self {
94+
Rv39PageTable {
95+
root_table: table,
96+
linear_offset,
97+
}
98+
}
99+
100+
fn create_p1_if_not_exist(
101+
&mut self,
102+
p3_index: usize,
103+
p2_index: usize,
104+
allocator: &mut impl FrameAllocator,
105+
) -> Result<&mut PageTable, MapToError> {
106+
let p2_table = if self.root_table[p3_index].is_unused() {
107+
let frame = allocator.alloc().ok_or(MapToError::FrameAllocationFailed)?;
108+
self.root_table[p3_index].set(frame.clone(), F::VALID);
109+
let p2_table: &mut PageTable = unsafe { frame.as_kernel_mut(self.linear_offset) };
110+
p2_table.zero();
111+
p2_table
112+
} else {
113+
let frame = self.root_table[p3_index].frame();
114+
unsafe { frame.as_kernel_mut(self.linear_offset) }
115+
};
116+
if p2_table[p2_index].is_unused() {
117+
let frame = allocator.alloc().ok_or(MapToError::FrameAllocationFailed)?;
118+
p2_table[p2_index].set(frame.clone(), F::VALID);
119+
let p1_table: &mut PageTable = unsafe { frame.as_kernel_mut(self.linear_offset) };
120+
p1_table.zero();
121+
Ok(p1_table)
122+
} else {
123+
let frame = p2_table[p2_index].frame();
124+
let p1_table: &mut PageTable = unsafe { frame.as_kernel_mut(self.linear_offset) };
125+
Ok(p1_table)
126+
}
127+
}
128+
}
129+
130+
#[cfg(riscv64)]
131+
impl<'a> Mapper for Rv39PageTable<'a> {
132+
fn map_to(
133+
&mut self,
134+
page: Page,
135+
frame: Frame,
136+
flags: PageTableFlags,
137+
allocator: &mut impl FrameAllocator,
138+
) -> Result<MapperFlush, MapToError> {
139+
let p1_table = self.create_p1_if_not_exist(page.p3_index(), page.p2_index(), allocator)?;
140+
if !p1_table[page.p1_index()].is_unused() {
141+
return Err(MapToError::PageAlreadyMapped);
142+
}
143+
p1_table[page.p1_index()].set(frame, flags);
144+
Ok(MapperFlush::new(page))
145+
}
146+
147+
fn unmap(&mut self, page: Page) -> Result<(Frame, MapperFlush), UnmapError> {
148+
if self.root_table[page.p3_index()].is_unused() {
149+
return Err(UnmapError::PageNotMapped);
150+
}
151+
let p2_frame = self.root_table[page.p3_index()].frame();
152+
let p2_table: &mut PageTable = unsafe { p2_frame.as_kernel_mut(self.linear_offset) };
153+
154+
if p2_table[page.p2_index()].is_unused() {
155+
return Err(UnmapError::PageNotMapped);
156+
}
157+
let p1_frame = p2_table[page.p2_index()].frame();
158+
let p1_table: &mut PageTable = unsafe { p1_frame.as_kernel_mut(self.linear_offset) };
159+
let p1_entry = &mut p1_table[page.p1_index()];
160+
if !p1_entry.flags().contains(F::VALID) {
161+
return Err(UnmapError::PageNotMapped);
162+
}
163+
let frame = p1_entry.frame();
164+
p1_entry.set_unused();
165+
Ok((frame, MapperFlush::new(page)))
166+
}
167+
168+
fn ref_entry(&mut self, page: Page) -> Result<&mut PageTableEntry, FlagUpdateError> {
169+
if self.root_table[page.p3_index()].is_unused() {
170+
return Err(FlagUpdateError::PageNotMapped);
171+
}
172+
let p2_frame = self.root_table[page.p3_index()].frame();
173+
let p2_table: &mut PageTable = unsafe { p2_frame.as_kernel_mut(self.linear_offset) };
174+
if p2_table[page.p2_index()].is_unused() {
175+
return Err(FlagUpdateError::PageNotMapped);
176+
}
177+
178+
let p1_frame = p2_table[page.p2_index()].frame();
179+
let p1_table: &mut PageTable = unsafe { p1_frame.as_kernel_mut(self.linear_offset) };
180+
Ok(&mut p1_table[page.p1_index()])
181+
}
182+
}
183+
184+
/// This struct is a four level page table with `Mapper` trait implemented.
185+
#[cfg(riscv64)]
186+
pub struct Rv48PageTable<'a> {
187+
root_table: &'a mut PageTable,
188+
linear_offset: usize, // VA = PA + linear_offset
189+
}
190+
191+
#[cfg(riscv64)]
192+
impl<'a> Rv48PageTable<'a> {
193+
pub fn new(table: &'a mut PageTable, linear_offset: usize) -> Self {
194+
Rv48PageTable {
195+
root_table: table,
196+
linear_offset,
197+
}
198+
}
199+
200+
fn create_p1_if_not_exist(
201+
&mut self,
202+
p4_index: usize,
203+
p3_index: usize,
204+
p2_index: usize,
205+
allocator: &mut impl FrameAllocator,
206+
) -> Result<&mut PageTable, MapToError> {
207+
let p3_table = if self.root_table[p4_index].is_unused() {
208+
let frame = allocator.alloc().ok_or(MapToError::FrameAllocationFailed)?;
209+
self.root_table[p4_index].set(frame.clone(), F::VALID);
210+
let p3_table: &mut PageTable = unsafe { frame.as_kernel_mut(self.linear_offset) };
211+
p3_table.zero();
212+
p3_table
213+
} else {
214+
let frame = self.root_table[p4_index].frame();
215+
unsafe { frame.as_kernel_mut(self.linear_offset) }
216+
};
217+
218+
let p2_table = if p3_table[p3_index].is_unused() {
219+
let frame = allocator.alloc().ok_or(MapToError::FrameAllocationFailed)?;
220+
self.root_table[p3_index].set(frame.clone(), F::VALID);
221+
let p2_table: &mut PageTable = unsafe { frame.as_kernel_mut(self.linear_offset) };
222+
p2_table.zero();
223+
p2_table
224+
} else {
225+
let frame = self.root_table[p3_index].frame();
226+
unsafe { frame.as_kernel_mut(self.linear_offset) }
227+
};
228+
229+
if p2_table[p2_index].is_unused() {
230+
let frame = allocator.alloc().ok_or(MapToError::FrameAllocationFailed)?;
231+
p2_table[p2_index].set(frame.clone(), F::VALID);
232+
let p1_table: &mut PageTable = unsafe { frame.as_kernel_mut(self.linear_offset) };
233+
p1_table.zero();
234+
Ok(p1_table)
235+
} else {
236+
let frame = p2_table[p2_index].frame();
237+
let p1_table: &mut PageTable = unsafe { frame.as_kernel_mut(self.linear_offset) };
238+
Ok(p1_table)
239+
}
240+
}
241+
}
242+
243+
#[cfg(riscv64)]
244+
impl<'a> Mapper for Rv48PageTable<'a> {
245+
fn map_to(
246+
&mut self,
247+
page: Page,
248+
frame: Frame,
249+
flags: PageTableFlags,
250+
allocator: &mut impl FrameAllocator,
251+
) -> Result<MapperFlush, MapToError> {
252+
let p1_table = self.create_p1_if_not_exist(page.p4_index(), page.p3_index(), page.p2_index(), allocator)?;
253+
if !p1_table[page.p1_index()].is_unused() {
254+
return Err(MapToError::PageAlreadyMapped);
255+
}
256+
p1_table[page.p1_index()].set(frame, flags);
257+
Ok(MapperFlush::new(page))
258+
}
259+
260+
fn unmap(&mut self, page: Page) -> Result<(Frame, MapperFlush), UnmapError> {
261+
if self.root_table[page.p4_index()].is_unused() {
262+
return Err(UnmapError::PageNotMapped);
263+
}
264+
let p3_frame = self.root_table[page.p4_index()].frame();
265+
let p3_table: &mut PageTable = unsafe { p3_frame.as_kernel_mut(self.linear_offset) };
266+
267+
if p3_table[page.p3_index()].is_unused() {
268+
return Err(UnmapError::PageNotMapped);
269+
}
270+
let p2_frame = p3_table[page.p3_index()].frame();
271+
let p2_table: &mut PageTable = unsafe { p2_frame.as_kernel_mut(self.linear_offset) };
272+
273+
if p2_table[page.p2_index()].is_unused() {
274+
return Err(UnmapError::PageNotMapped);
275+
}
276+
let p1_frame = p2_table[page.p2_index()].frame();
277+
let p1_table: &mut PageTable = unsafe { p1_frame.as_kernel_mut(self.linear_offset) };
278+
let p1_entry = &mut p1_table[page.p1_index()];
279+
if !p1_entry.flags().contains(F::VALID) {
280+
return Err(UnmapError::PageNotMapped);
281+
}
282+
let frame = p1_entry.frame();
283+
p1_entry.set_unused();
284+
Ok((frame, MapperFlush::new(page)))
285+
}
286+
287+
fn ref_entry(&mut self, page: Page) -> Result<&mut PageTableEntry, FlagUpdateError> {
288+
if self.root_table[page.p4_index()].is_unused() {
289+
return Err(FlagUpdateError::PageNotMapped);
290+
}
291+
let p3_frame = self.root_table[page.p4_index()].frame();
292+
let p3_table: &mut PageTable = unsafe { p3_frame.as_kernel_mut(self.linear_offset) };
293+
294+
if p3_table[page.p3_index()].is_unused() {
295+
return Err(FlagUpdateError::PageNotMapped);
296+
}
297+
let p2_frame = p3_table[page.p3_index()].frame();
298+
let p2_table: &mut PageTable = unsafe { p2_frame.as_kernel_mut(self.linear_offset) };
299+
if p2_table[page.p2_index()].is_unused() {
300+
return Err(FlagUpdateError::PageNotMapped);
301+
}
302+
303+
let p1_frame = p2_table[page.p2_index()].frame();
304+
let p1_table: &mut PageTable = unsafe { p1_frame.as_kernel_mut(self.linear_offset) };
305+
Ok(&mut p1_table[page.p1_index()])
306+
}
307+
}

0 commit comments

Comments
 (0)