Skip to content

Commit 54c8319

Browse files
committed
backport lab4 to ch5
1 parent f97386c commit 54c8319

File tree

6 files changed

+140
-31
lines changed

6 files changed

+140
-31
lines changed

os/src/mm/address.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,15 @@ impl VirtAddr {
113113
pub fn aligned(&self) -> bool {
114114
self.page_offset() == 0
115115
}
116+
117+
/// Check if the virtual address is valid
118+
/// 在启用 SV39 分页模式下,只有低 39 位是真正有意义的。SV39 分页模式规定 64 位虚拟地址的
119+
/// 这 25 位必须和第 38 位相同,否则 MMU 会直接认定它是一个 不合法的虚拟地址。也就是说,
120+
/// 所有 2^{64} 个虚拟地址中,只有最低的 256GiB(当第 38 位为 0 时)以及最高的(当第 38
121+
/// 位为 1 时)是合法的虚拟地址。
122+
pub fn is_valid(addr: usize) -> bool {
123+
addr <= 0x3F_FF_FF_FF_FF_usize || addr >= 0xFF_FF_FF_C0_00_00_00_00_usize
124+
}
116125
}
117126
impl From<VirtAddr> for VirtPageNum {
118127
fn from(v: VirtAddr) -> Self {
@@ -204,7 +213,7 @@ impl StepByOne for VirtPageNum {
204213
}
205214
}
206215

207-
#[derive(Copy, Clone)]
216+
#[derive(Copy, Clone, PartialEq)]
208217
/// a simple range structure for type T
209218
pub struct SimpleRange<T>
210219
where
@@ -227,6 +236,9 @@ where
227236
pub fn get_end(&self) -> T {
228237
self.r
229238
}
239+
pub fn has_intersection(&self, other: &Self) -> bool {
240+
!(self.r <= other.l || self.l >= other.r)
241+
}
230242
}
231243
impl<T> IntoIterator for SimpleRange<T>
232244
where

os/src/mm/frame_allocator.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ impl StackFrameAllocator {
5555
self.end = r.0;
5656
// trace!("last {} Physical Frames.", self.end - self.current);
5757
}
58+
pub fn free_page_count(&self) -> usize {
59+
self.recycled.len() + (self.end - self.current)
60+
}
5861
}
5962
impl FrameAllocator for StackFrameAllocator {
6063
fn new() -> Self {

os/src/mm/memory_set.rs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@ lazy_static! {
3232
}
3333
/// address space
3434
pub struct MemorySet {
35-
page_table: PageTable,
36-
areas: Vec<MapArea>,
35+
/// page table for this address space
36+
pub page_table: PageTable,
37+
/// collection of contiguous mapped areas
38+
pub areas: Vec<MapArea>,
3739
}
3840

3941
impl MemorySet {
@@ -60,6 +62,28 @@ impl MemorySet {
6062
None,
6163
);
6264
}
65+
66+
/// Remove a framed area
67+
pub fn remove_framed_area(
68+
&mut self,
69+
start_va: VirtAddr,
70+
end_va: VirtAddr,
71+
) -> Option<MapArea> {
72+
let start_vpn = start_va.floor();
73+
let end_vpn = end_va.ceil();
74+
if let Some(index) = self
75+
.areas
76+
.iter()
77+
.position(|area| area.vpn_range.get_start() == start_vpn && area.vpn_range.get_end() == end_vpn)
78+
{
79+
let mut area = self.areas.remove(index);
80+
area.unmap(&mut self.page_table);
81+
Some(area)
82+
} else {
83+
None
84+
}
85+
}
86+
6387
/// remove a area
6488
pub fn remove_area_with_start_vpn(&mut self, start_vpn: VirtPageNum) {
6589
if let Some((idx, area)) = self
@@ -103,6 +127,7 @@ impl MemorySet {
103127
".bss [{:#x}, {:#x})",
104128
sbss_with_stack as usize, ebss as usize
105129
);
130+
info!("physical memory [{:#x}, {:#x})", ekernel as usize, MEMORY_END);
106131
info!("mapping .text section");
107132
memory_set.push(
108133
MapArea::new(
@@ -303,7 +328,7 @@ impl MemorySet {
303328
}
304329
/// map area structure, controls a contiguous piece of virtual memory
305330
pub struct MapArea {
306-
vpn_range: VPNRange,
331+
pub vpn_range: VPNRange,
307332
data_frames: BTreeMap<VirtPageNum, FrameTracker>,
308333
map_type: MapType,
309334
map_perm: MapPermission,

os/src/mm/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ mod heap_allocator;
1111
mod memory_set;
1212
mod page_table;
1313

14-
pub use address::{PhysAddr, PhysPageNum, VirtAddr, VirtPageNum};
15-
use address::{StepByOne, VPNRange};
16-
pub use frame_allocator::{frame_alloc, FrameTracker};
14+
pub use address::{PhysAddr, PhysPageNum, VirtAddr, VirtPageNum, VPNRange};
15+
use address::{StepByOne};
16+
pub use frame_allocator::{frame_alloc, FrameTracker, FRAME_ALLOCATOR};
1717
pub use memory_set::remap_test;
1818
pub use memory_set::{MapPermission, MemorySet, KERNEL_SPACE};
1919
pub use page_table::{translated_byte_buffer, translated_refmut, translated_str, PageTableEntry};

os/src/mm/page_table.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,21 @@ use bitflags::*;
88
bitflags! {
99
/// page table entry flags
1010
pub struct PTEFlags: u8 {
11+
/// Valid
1112
const V = 1 << 0;
13+
/// Readable
1214
const R = 1 << 1;
15+
/// Writable
1316
const W = 1 << 2;
17+
/// Executable
1418
const X = 1 << 3;
19+
/// User
1520
const U = 1 << 4;
21+
/// Global
1622
const G = 1 << 5;
23+
/// Accessed
1724
const A = 1 << 6;
25+
/// Dirty
1826
const D = 1 << 7;
1927
}
2028
}

os/src/syscall/process.rs

Lines changed: 85 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@ use alloc::sync::Arc;
33

44
use crate::{
55
loader::get_app_data_by_name,
6-
mm::{translated_refmut, translated_str},
6+
mm::{translated_byte_buffer, translated_refmut, translated_str, MapPermission, VPNRange, VirtAddr, VirtPageNum, FRAME_ALLOCATOR},
77
task::{
8-
add_task, current_task, current_user_token, exit_current_and_run_next,
9-
suspend_current_and_run_next,
10-
},
8+
add_task, current_task, current_user_token, exit_current_and_run_next, suspend_current_and_run_next
9+
}, timer::get_time_us,
1110
};
1211

1312
#[repr(C)]
@@ -105,30 +104,92 @@ pub fn sys_waitpid(pid: isize, exit_code_ptr: *mut i32) -> isize {
105104
/// YOUR JOB: get time with second and microsecond
106105
/// HINT: You might reimplement it with virtual memory management.
107106
/// HINT: What if [`TimeVal`] is splitted by two pages ?
108-
pub fn sys_get_time(_ts: *mut TimeVal, _tz: usize) -> isize {
109-
trace!(
110-
"kernel:pid[{}] sys_get_time NOT IMPLEMENTED",
111-
current_task().unwrap().pid.0
112-
);
113-
-1
107+
pub fn sys_get_time(ts: *mut TimeVal, _tz: usize) -> isize {
108+
trace!("kernel: sys_get_time");
109+
// let token = current_user_token();
110+
// let page_table = PageTable::from_token(token);
111+
// let va = VirtAddr::from(ts as usize);
112+
// let vpn = va.floor();
113+
// let ppn = page_table.translate(vpn).unwrap().ppn();
114+
// let offset = va.page_offset();
115+
// let pa: PhysAddr = (Into::<usize>::into(Into::<PhysAddr>::into(ppn)) + offset).into();
116+
// let ts: &mut TimeVal = pa.get_mut();
117+
// let us = get_time_us();
118+
// *ts = TimeVal {
119+
// sec: us / 1_000_000,
120+
// usec: us % 1_000_000,
121+
// };
122+
// 上面这个实现并不完美,无法处理跨页的情况
123+
let token = current_user_token();
124+
let buf = translated_byte_buffer(token, ts as *const u8, core::mem::size_of::<TimeVal>());
125+
let us = get_time_us();
126+
let ts = TimeVal {
127+
sec: us / 1_000_000,
128+
usec: us % 1_000_000,
129+
};
130+
let src = unsafe {
131+
core::slice::from_raw_parts(&ts as *const TimeVal as *const u8, core::mem::size_of::<TimeVal>())
132+
};
133+
let mut offset = 0;
134+
for dst in buf {
135+
let len = dst.len();
136+
dst.copy_from_slice(&src[offset..offset + len]);
137+
offset += len;
138+
}
139+
0
114140
}
115141

116-
/// YOUR JOB: Implement mmap.
117-
pub fn sys_mmap(_start: usize, _len: usize, _port: usize) -> isize {
118-
trace!(
119-
"kernel:pid[{}] sys_mmap NOT IMPLEMENTED",
120-
current_task().unwrap().pid.0
121-
);
122-
-1
142+
// YOUR JOB: Implement mmap.
143+
pub fn sys_mmap(start: usize, len: usize, prot: usize) -> isize {
144+
trace!("kernel: sys_mmap");
145+
let start_va = VirtAddr::from(start);
146+
if !start_va.aligned() || (prot & !0x7 != 0) || (prot & 0x7 == 0) {
147+
trace!("kernel: sys_mmap failed, invalid parameters!");
148+
return -1;
149+
}
150+
let end_va: VirtAddr = VirtAddr::from(start + len).ceil().into();
151+
let start_vpn: VirtPageNum = start_va.into();
152+
let end_vpn: VirtPageNum = end_va.into();
153+
154+
// Check if there are enough free pages
155+
if end_vpn.0 - start_vpn.0 > FRAME_ALLOCATOR.exclusive_access().free_page_count() {
156+
trace!("kernel: sys_mmap failed, not enough free pages!");
157+
return -1;
158+
}
159+
160+
// Check if the new memory area overlaps with existing areas
161+
let current = current_task().unwrap();
162+
let mut inner = current.inner_exclusive_access();
163+
let new_vpn_range = VPNRange::new(start_vpn, end_vpn);
164+
for area in inner.memory_set.areas.iter() {
165+
if area.vpn_range.has_intersection(&new_vpn_range) {
166+
trace!("kernel: sys_mmap failed, overlapping memory area!");
167+
return -1;
168+
}
169+
}
170+
171+
let mut permission = MapPermission::U;
172+
permission |= MapPermission::from_bits((prot << 1) as u8).unwrap();
173+
inner.memory_set.insert_framed_area(start_va, end_va, permission);
174+
0
123175
}
124176

125-
/// YOUR JOB: Implement munmap.
126-
pub fn sys_munmap(_start: usize, _len: usize) -> isize {
127-
trace!(
128-
"kernel:pid[{}] sys_munmap NOT IMPLEMENTED",
129-
current_task().unwrap().pid.0
130-
);
131-
-1
177+
// YOUR JOB: Implement munmap.
178+
pub fn sys_munmap(start: usize, len: usize) -> isize {
179+
trace!("kernel: sys_munmap");
180+
let start_va = VirtAddr::from(start);
181+
if !start_va.aligned() {
182+
trace!("kernel: sys_munmap failed, invalid parameters!");
183+
return -1;
184+
}
185+
let end_va: VirtAddr = VirtAddr::from(start + len).ceil().into();
186+
187+
let current = current_task().unwrap();
188+
let mut inner = current.inner_exclusive_access();
189+
match inner.memory_set.remove_framed_area(start_va, end_va) {
190+
Some(_) => 0,
191+
None => -1
192+
}
132193
}
133194

134195
/// change data segment size

0 commit comments

Comments
 (0)