add: memory area
This commit is contained in:
parent
2bac1464a1
commit
bfaf29e5d4
25
os/Cargo.lock
generated
25
os/Cargo.lock
generated
|
@ -8,6 +8,21 @@ version = "0.10.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
|
checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "2.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "buddy_system_allocator"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b4e85e760e105b46ae0bd1236578793c6c147ae7463fe95c8350296b8bfcb830"
|
||||||
|
dependencies = [
|
||||||
|
"spin 0.7.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "critical-section"
|
name = "critical-section"
|
||||||
version = "1.1.2"
|
version = "1.1.2"
|
||||||
|
@ -30,7 +45,7 @@ version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"spin",
|
"spin 0.9.8",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -52,6 +67,8 @@ checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
|
||||||
name = "os"
|
name = "os"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"buddy_system_allocator",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"riscv",
|
"riscv",
|
||||||
"sbi-rt",
|
"sbi-rt",
|
||||||
|
@ -86,6 +103,12 @@ dependencies = [
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13287b4da9d1207a4f4929ac390916d64eacfe236a487e9a9f5b3be392be5162"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spin"
|
name = "spin"
|
||||||
version = "0.9.8"
|
version = "0.9.8"
|
||||||
|
|
|
@ -7,3 +7,5 @@ edition = "2021"
|
||||||
sbi-rt = { version = "0.0.2", features = ["legacy"] }
|
sbi-rt = { version = "0.0.2", features = ["legacy"] }
|
||||||
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
|
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
|
||||||
riscv = { version = "0.10.0" }
|
riscv = { version = "0.10.0" }
|
||||||
|
buddy_system_allocator = {version = "0.6"}
|
||||||
|
bitflags = {version = "2.6"}
|
||||||
|
|
|
@ -1 +1,5 @@
|
||||||
pub const CLOCK_FREQUENCY: usize = 10000000;
|
pub const CLOCK_FREQUENCY: usize = 10000000;
|
||||||
|
pub const MEMORY_END: usize = 0x8800_0000;
|
||||||
|
pub const MMIO: &[(usize, usize)] = &[
|
||||||
|
(0x0010_0000, 0x00_2000)
|
||||||
|
];
|
||||||
|
|
|
@ -1,8 +1,17 @@
|
||||||
pub const USER_STACK_SIZE: usize = 4096;
|
pub const USER_STACK_SIZE: usize = 4096;
|
||||||
pub const KERNEL_STACK_SIZE: usize = 4096 * 2;
|
pub const KERNEL_STACK_SIZE: usize = 4096 * 2;
|
||||||
|
pub const KERNEL_HEAP_SIZE: usize = 0x30_0000;
|
||||||
|
pub const PAGE_SIZE: usize = 0x1000;
|
||||||
|
pub const PAGE_SIZE_BITS: usize = 0xc;
|
||||||
|
|
||||||
pub const MAX_APP_NUM: usize = 4;
|
pub const TRAMPOLINE: usize = usize::MAX - PAGE_SIZE + 1;
|
||||||
pub const APP_BASE_ADDRESS: usize = 0x80400000;
|
pub const TRAP_CONTEXT: usize = TRAMPOLINE - PAGE_SIZE;
|
||||||
pub const APP_SIZE_LIMIT: usize = 0x20000;
|
|
||||||
|
|
||||||
pub use crate::boards::qemu::CLOCK_FREQUENCY;
|
/// Return (bottom, top) of a kernel stack in kernel space
|
||||||
|
pub fn kernel_stack_position(app_id: usize) -> (usize, usize) {
|
||||||
|
let top = TRAMPOLINE - app_id * (KERNEL_STACK_SIZE + PAGE_SIZE);
|
||||||
|
let bottom = top - KERNEL_STACK_SIZE;
|
||||||
|
(bottom, top)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use crate::boards::qemu::{CLOCK_FREQUENCY, MEMORY_END, MMIO};
|
||||||
|
|
100
os/src/loader.rs
100
os/src/loader.rs
|
@ -1,100 +0,0 @@
|
||||||
use crate::config::{
|
|
||||||
APP_BASE_ADDRESS, APP_SIZE_LIMIT, KERNEL_STACK_SIZE, MAX_APP_NUM, USER_STACK_SIZE,
|
|
||||||
};
|
|
||||||
use crate::log_information;
|
|
||||||
use crate::trap::context::TrapContext;
|
|
||||||
use core::arch::asm;
|
|
||||||
|
|
||||||
#[repr(align(4096))]
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
struct KernelStack {
|
|
||||||
data: [u8; KERNEL_STACK_SIZE],
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(align(4096))]
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
struct UserStack {
|
|
||||||
data: [u8; USER_STACK_SIZE],
|
|
||||||
}
|
|
||||||
|
|
||||||
static KERNEL_STACK: [KernelStack; MAX_APP_NUM] = [KernelStack {
|
|
||||||
data: [0; KERNEL_STACK_SIZE],
|
|
||||||
}; MAX_APP_NUM];
|
|
||||||
|
|
||||||
static USER_STACK: [UserStack; MAX_APP_NUM] = [UserStack {
|
|
||||||
data: [0; USER_STACK_SIZE],
|
|
||||||
}; MAX_APP_NUM];
|
|
||||||
|
|
||||||
impl KernelStack {
|
|
||||||
fn get_sp(&self) -> usize {
|
|
||||||
self.data.as_ptr() as usize + KERNEL_STACK_SIZE
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push_context(&self, trap_context: TrapContext) -> usize {
|
|
||||||
let pointer = (self.get_sp() - size_of::<TrapContext>()) as *mut TrapContext;
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
*pointer = trap_context;
|
|
||||||
}
|
|
||||||
|
|
||||||
pointer as usize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UserStack {
|
|
||||||
fn get_sp(&self) -> usize {
|
|
||||||
self.data.as_ptr() as usize + USER_STACK_SIZE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_app_num() -> usize {
|
|
||||||
extern "C" {
|
|
||||||
fn _num_app();
|
|
||||||
}
|
|
||||||
|
|
||||||
let app_num_ptr = _num_app as usize as *const usize;
|
|
||||||
|
|
||||||
unsafe { app_num_ptr.read_volatile() }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load_apps() {
|
|
||||||
extern "C" {
|
|
||||||
fn _num_app();
|
|
||||||
}
|
|
||||||
|
|
||||||
let app_num_ptr = _num_app as usize as *const usize;
|
|
||||||
let app_num = unsafe { app_num_ptr.read_volatile() };
|
|
||||||
let app_start = unsafe { core::slice::from_raw_parts(app_num_ptr.add(1), app_num + 1) };
|
|
||||||
|
|
||||||
for i in 0..app_num {
|
|
||||||
let base_address = APP_BASE_ADDRESS + i * APP_SIZE_LIMIT;
|
|
||||||
|
|
||||||
// 清除目标的内存区域
|
|
||||||
for address in base_address..base_address + APP_SIZE_LIMIT {
|
|
||||||
unsafe {
|
|
||||||
(address as *mut u8).write_volatile(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将程序从数据段复制过来
|
|
||||||
let source = unsafe {
|
|
||||||
core::slice::from_raw_parts(app_start[i] as *const u8, app_start[i + 1] - app_start[i])
|
|
||||||
};
|
|
||||||
let destination =
|
|
||||||
unsafe { core::slice::from_raw_parts_mut(base_address as *mut u8, source.len()) };
|
|
||||||
|
|
||||||
destination.copy_from_slice(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
log_information!("Load {} applications in memory.", app_num);
|
|
||||||
unsafe {
|
|
||||||
asm!("fence.i");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn initialize_app_context(app_id: usize) -> usize {
|
|
||||||
KERNEL_STACK[app_id].push_context(TrapContext::init_application_context(
|
|
||||||
APP_BASE_ADDRESS + app_id * APP_SIZE_LIMIT,
|
|
||||||
USER_STACK[app_id].get_sp(),
|
|
||||||
))
|
|
||||||
}
|
|
|
@ -1,5 +1,7 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
#![feature(alloc_error_handler)]
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
use crate::utils::clear_bss;
|
use crate::utils::clear_bss;
|
||||||
use core::arch::global_asm;
|
use core::arch::global_asm;
|
||||||
|
@ -7,7 +9,6 @@ use core::arch::global_asm;
|
||||||
mod boards;
|
mod boards;
|
||||||
mod config;
|
mod config;
|
||||||
mod console;
|
mod console;
|
||||||
mod loader;
|
|
||||||
mod sbi;
|
mod sbi;
|
||||||
mod sync;
|
mod sync;
|
||||||
mod syscall;
|
mod syscall;
|
||||||
|
@ -15,6 +16,7 @@ mod task;
|
||||||
mod timer;
|
mod timer;
|
||||||
mod trap;
|
mod trap;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
mod memory;
|
||||||
|
|
||||||
global_asm!(include_str!("entry.asm"));
|
global_asm!(include_str!("entry.asm"));
|
||||||
global_asm!(include_str!("link_app.asm"));
|
global_asm!(include_str!("link_app.asm"));
|
||||||
|
@ -24,8 +26,6 @@ fn rust_main() -> ! {
|
||||||
clear_bss();
|
clear_bss();
|
||||||
log_information!("Hello, rCore!");
|
log_information!("Hello, rCore!");
|
||||||
trap::init();
|
trap::init();
|
||||||
loader::load_apps();
|
|
||||||
task::run_first_task();
|
|
||||||
|
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
5
os/src/memory.rs
Normal file
5
os/src/memory.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
mod heap_allocator;
|
||||||
|
mod address;
|
||||||
|
mod page_table;
|
||||||
|
mod frame_allocator;
|
||||||
|
mod memory_set;
|
256
os/src/memory/address.rs
Normal file
256
os/src/memory/address.rs
Normal file
|
@ -0,0 +1,256 @@
|
||||||
|
use crate::config::{PAGE_SIZE, PAGE_SIZE_BITS};
|
||||||
|
use core::fmt::{Debug, Formatter};
|
||||||
|
use core::slice::from_raw_parts_mut;
|
||||||
|
use crate::memory::page_table::PageTableEntry;
|
||||||
|
|
||||||
|
// 在SV39模式下,物理地址的宽度为56,虚拟地址的宽度为39
|
||||||
|
pub const PHYSICAL_ADDRESS_WIDTH: usize = 56;
|
||||||
|
pub const PHYSICAL_PAGE_NUMBER_WIDTH: usize = PHYSICAL_ADDRESS_WIDTH - PAGE_SIZE_BITS;
|
||||||
|
pub const VIRTUAL_ADDRESS_WIDTH: usize = 39;
|
||||||
|
pub const VIRTUAL_PAGE_NUMBER_WIDTH: usize = VIRTUAL_ADDRESS_WIDTH - PAGE_SIZE_BITS;
|
||||||
|
|
||||||
|
/// 物理地址
|
||||||
|
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||||
|
pub struct PhysicalAddress(pub usize);
|
||||||
|
|
||||||
|
impl PhysicalAddress {
|
||||||
|
pub fn page_offset(&self) -> usize {
|
||||||
|
self.0 & (PAGE_SIZE - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn floor(&self) -> PhysicalPageNumber {
|
||||||
|
PhysicalPageNumber(self.0 / PAGE_SIZE)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ceil(&self) -> PhysicalPageNumber {
|
||||||
|
if self.0 == 0 {
|
||||||
|
PhysicalPageNumber(0)
|
||||||
|
} else {
|
||||||
|
PhysicalPageNumber((self.0 - 1 + PAGE_SIZE) / PAGE_SIZE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_aligned(&self) -> bool {
|
||||||
|
self.page_offset() == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for PhysicalAddress {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||||
|
f.write_fmt(format_args!("Physical address: {:#x}.", self.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<usize> for PhysicalAddress {
|
||||||
|
fn from(value: usize) -> Self {
|
||||||
|
Self(value & ((1 << PHYSICAL_ADDRESS_WIDTH) - 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PhysicalAddress> for usize {
|
||||||
|
fn from(value: PhysicalAddress) -> Self {
|
||||||
|
value.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PhysicalAddress> for PhysicalPageNumber {
|
||||||
|
fn from(value: PhysicalAddress) -> Self {
|
||||||
|
assert_eq!(value.page_offset(), 0);
|
||||||
|
value.floor()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PhysicalPageNumber> for PhysicalAddress {
|
||||||
|
fn from(value: PhysicalPageNumber) -> Self {
|
||||||
|
Self(value.0 << PAGE_SIZE_BITS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 物理页号
|
||||||
|
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||||
|
pub struct PhysicalPageNumber(pub usize);
|
||||||
|
|
||||||
|
// 这里的unsafe只是为了绕过编译器的生命周期检查
|
||||||
|
impl PhysicalPageNumber {
|
||||||
|
pub fn get_page_table_entry_array(&self) -> &'static mut [PageTableEntry] {
|
||||||
|
let address: PhysicalAddress = (*self).into();
|
||||||
|
unsafe {
|
||||||
|
// 一个页表的大小是2^12 byte
|
||||||
|
// 页表项的大小是8 byte
|
||||||
|
// 所有一共有2^9
|
||||||
|
from_raw_parts_mut(address.0 as *mut PageTableEntry, 512)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_bytes_array(&self) -> &'static mut [u8] {
|
||||||
|
let address: PhysicalAddress = (*self).into();
|
||||||
|
unsafe {
|
||||||
|
from_raw_parts_mut(address.0 as *mut u8, PAGE_SIZE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mut<T>(&self) ->&'static mut T {
|
||||||
|
let address: PhysicalAddress = (*self).into();
|
||||||
|
unsafe {
|
||||||
|
(address.0 as *mut T).as_mut().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for PhysicalPageNumber {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||||
|
f.write_fmt(format_args!("Physical page number: {:#x}.", self.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<usize> for PhysicalPageNumber {
|
||||||
|
fn from(value: usize) -> Self {
|
||||||
|
Self(value & ((1 << PHYSICAL_PAGE_NUMBER_WIDTH) - 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PhysicalPageNumber> for usize {
|
||||||
|
fn from(value: PhysicalPageNumber) -> Self {
|
||||||
|
value.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 虚拟地址
|
||||||
|
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||||
|
pub struct VirtualAddress(pub usize);
|
||||||
|
|
||||||
|
impl VirtualAddress {
|
||||||
|
pub fn page_offset(&self) -> usize {
|
||||||
|
self.0 & (PAGE_SIZE - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_aligned(&self) -> bool {
|
||||||
|
self.page_offset() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn floor(&self) -> VirtualPageNumber {
|
||||||
|
VirtualPageNumber(self.0 / PAGE_SIZE)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ceil(&self) -> VirtualPageNumber {
|
||||||
|
VirtualPageNumber((self.0 - 1 + PAGE_SIZE) / PAGE_SIZE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for VirtualAddress {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||||
|
f.write_fmt(format_args!("Virtual address: {:#x}.", self.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<usize> for VirtualAddress {
|
||||||
|
fn from(value: usize) -> Self {
|
||||||
|
Self(value & ((1 << VIRTUAL_ADDRESS_WIDTH) - 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<VirtualAddress> for usize {
|
||||||
|
fn from(value: VirtualAddress) -> Self {
|
||||||
|
value.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 虚拟页号
|
||||||
|
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||||
|
pub struct VirtualPageNumber(pub usize);
|
||||||
|
|
||||||
|
impl VirtualPageNumber {
|
||||||
|
pub fn get_indexes(&self) -> [usize; 3] {
|
||||||
|
let mut number = self.0;
|
||||||
|
let mut indexes = [0usize; 3];
|
||||||
|
|
||||||
|
for i in 0..3 {
|
||||||
|
indexes[i] = number & (1 << 9 - 1);
|
||||||
|
number = number >> 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
indexes
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn step(&mut self) {
|
||||||
|
self.0 += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for VirtualPageNumber {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||||
|
f.write_fmt(format_args!("Virtual page number: {:#x}.", self.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<usize> for VirtualPageNumber {
|
||||||
|
fn from(value: usize) -> Self {
|
||||||
|
Self(value & ((1 << VIRTUAL_PAGE_NUMBER_WIDTH) - 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<VirtualPageNumber> for usize {
|
||||||
|
fn from(value: VirtualPageNumber) -> Self {
|
||||||
|
value.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct VirtualPageSpan {
|
||||||
|
left: VirtualPageNumber,
|
||||||
|
right: VirtualPageNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VirtualPageSpan {
|
||||||
|
pub fn new(start: VirtualPageNumber, end: VirtualPageNumber) -> Self {
|
||||||
|
Self {
|
||||||
|
left: start,
|
||||||
|
right: end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_start(&self) -> VirtualPageNumber {
|
||||||
|
self.left
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_end(&self) -> VirtualPageNumber {
|
||||||
|
self.right
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoIterator for VirtualPageSpan {
|
||||||
|
type Item = VirtualPageNumber;
|
||||||
|
type IntoIter = VirtualPageSpanIterator;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
VirtualPageSpanIterator::new(&self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct VirtualPageSpanIterator {
|
||||||
|
current: VirtualPageNumber,
|
||||||
|
end: VirtualPageNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VirtualPageSpanIterator {
|
||||||
|
fn new(span: &VirtualPageSpan) -> Self {
|
||||||
|
Self {
|
||||||
|
current: span.left,
|
||||||
|
end: span.right
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for VirtualPageSpanIterator {
|
||||||
|
type Item = VirtualPageNumber;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.current == self.end {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let t = self.current;
|
||||||
|
self.current.step();
|
||||||
|
Some(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
110
os/src/memory/frame_allocator.rs
Normal file
110
os/src/memory/frame_allocator.rs
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
use crate::config::MEMORY_END;
|
||||||
|
use crate::memory::address::{PhysicalAddress, PhysicalPageNumber};
|
||||||
|
use crate::sync::single_cell::SingleCell;
|
||||||
|
use alloc::vec;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
|
trait FrameAllocator {
|
||||||
|
fn new() -> Self;
|
||||||
|
|
||||||
|
fn alloc(&mut self) -> Option<PhysicalPageNumber>;
|
||||||
|
|
||||||
|
fn dealloc(&mut self, page_number: PhysicalPageNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct StackedFrameAllocator {
|
||||||
|
current: usize,
|
||||||
|
end: usize,
|
||||||
|
recycled: Vec<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FrameAllocator for StackedFrameAllocator {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
current: 0,
|
||||||
|
end: 0,
|
||||||
|
recycled: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alloc(&mut self) -> Option<PhysicalPageNumber> {
|
||||||
|
if let Some(page_num) = self.recycled.pop() {
|
||||||
|
Some(page_num.into())
|
||||||
|
} else {
|
||||||
|
if self.current == self.end {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
self.current += 1;
|
||||||
|
Some((self.current - 1).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dealloc(&mut self, page_number: PhysicalPageNumber) {
|
||||||
|
let page_number = page_number.0;
|
||||||
|
|
||||||
|
if page_number >= self.current
|
||||||
|
|| self.recycled.iter().find(|&p| *p == page_number).is_some()
|
||||||
|
{
|
||||||
|
panic!(
|
||||||
|
"Frame physical page number={:#x} has not been allocated.",
|
||||||
|
page_number
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.recycled.push(page_number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StackedFrameAllocator {
|
||||||
|
pub fn init(&mut self, l: PhysicalPageNumber, r: PhysicalPageNumber) {
|
||||||
|
self.current = l.0;
|
||||||
|
self.end = r.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FrameTracker {
|
||||||
|
pub page_number: PhysicalPageNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FrameTracker {
|
||||||
|
fn new(page_number: PhysicalPageNumber) -> Self {
|
||||||
|
// 清空页帧中的内容
|
||||||
|
let byte_array = page_number.get_bytes_array();
|
||||||
|
for i in byte_array.as_mut() {
|
||||||
|
*i = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
page_number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for FrameTracker {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
FRAME_ALLOCATOR.exclusive_borrow().dealloc(self.page_number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref FRAME_ALLOCATOR: SingleCell<StackedFrameAllocator> =
|
||||||
|
SingleCell::new(StackedFrameAllocator::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initialize_frame_allocator() {
|
||||||
|
extern "C" {
|
||||||
|
fn ekernel();
|
||||||
|
}
|
||||||
|
|
||||||
|
FRAME_ALLOCATOR.exclusive_borrow().init(
|
||||||
|
PhysicalAddress::from(ekernel as usize).ceil(),
|
||||||
|
PhysicalAddress::from(MEMORY_END).floor(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn allocate_frame() -> Option<FrameTracker> {
|
||||||
|
FRAME_ALLOCATOR.exclusive_borrow().alloc().map(|p| FrameTracker::new(p))
|
||||||
|
}
|
||||||
|
|
20
os/src/memory/heap_allocator.rs
Normal file
20
os/src/memory/heap_allocator.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
use buddy_system_allocator::LockedHeap;
|
||||||
|
use crate::config::KERNEL_HEAP_SIZE;
|
||||||
|
|
||||||
|
#[global_allocator]
|
||||||
|
static HEAP_ALLOCATOR: LockedHeap = LockedHeap::empty();
|
||||||
|
|
||||||
|
static mut HEAP_SPACE: [u8; KERNEL_HEAP_SIZE] = [0; KERNEL_HEAP_SIZE];
|
||||||
|
|
||||||
|
pub fn init_heap() {
|
||||||
|
unsafe {
|
||||||
|
HEAP_ALLOCATOR
|
||||||
|
.lock()
|
||||||
|
.init(HEAP_SPACE.as_ptr() as usize, KERNEL_HEAP_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[alloc_error_handler]
|
||||||
|
pub fn handle_alloc_error(layout: core::alloc::Layout) -> ! {
|
||||||
|
panic!("Heap allocation failed, layout: {:?}", layout);
|
||||||
|
}
|
145
os/src/memory/memory_set.rs
Normal file
145
os/src/memory/memory_set.rs
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
use alloc::collections::BTreeMap;
|
||||||
|
use alloc::vec;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use bitflags::bitflags;
|
||||||
|
use crate::config::PAGE_SIZE;
|
||||||
|
use crate::memory::address::{PhysicalPageNumber, VirtualAddress, VirtualPageNumber, VirtualPageSpan};
|
||||||
|
use crate::memory::frame_allocator::{allocate_frame, FrameTracker};
|
||||||
|
use crate::memory::page_table::{PageTable, PageTableEntryFlags};
|
||||||
|
|
||||||
|
/// 虚拟地址的映射方式
|
||||||
|
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||||
|
pub enum MapType {
|
||||||
|
/// 恒等映射
|
||||||
|
Identical,
|
||||||
|
/// 新分配物理页帧
|
||||||
|
Framed
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
/// 逻辑段的权限控制
|
||||||
|
/// 只是PageTableEntryFlags的子集
|
||||||
|
/// 其他的标志位对于权限控制无用,只和地址转换有关
|
||||||
|
pub struct MapPermission: u8 {
|
||||||
|
const R = 1 << 1;
|
||||||
|
const W = 1 << 2;
|
||||||
|
const X = 1 << 3;
|
||||||
|
const U = 1 << 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 一段地址连续的虚拟内存
|
||||||
|
pub struct MapArea {
|
||||||
|
virtual_page_span: VirtualPageSpan,
|
||||||
|
data_frames: BTreeMap<VirtualPageNumber, FrameTracker>,
|
||||||
|
map_type: MapType,
|
||||||
|
map_permission: MapPermission
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MapArea {
|
||||||
|
pub fn new(
|
||||||
|
start: VirtualAddress,
|
||||||
|
end: VirtualAddress,
|
||||||
|
map_type: MapType,
|
||||||
|
map_permission: MapPermission
|
||||||
|
) -> Self {
|
||||||
|
let start = start.floor();
|
||||||
|
let end = end.ceil();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
virtual_page_span: VirtualPageSpan::new(start, end),
|
||||||
|
data_frames: BTreeMap::new(),
|
||||||
|
map_type,
|
||||||
|
map_permission
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map(&mut self, page_table: &mut PageTable) {
|
||||||
|
for page_number in self.virtual_page_span {
|
||||||
|
self.map_one(page_table, page_number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unmap(&mut self, page_table: &mut PageTable) {
|
||||||
|
for page_number in self.virtual_page_span {
|
||||||
|
self.unmap_one(page_table, page_number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Copy data into this MapArea
|
||||||
|
/// The data is start-aligned and shorter than MapArea!
|
||||||
|
pub fn copy_data(&mut self, page_table: &mut PageTable, data: &[u8]) {
|
||||||
|
assert_eq!(self.map_type, MapType::Framed);
|
||||||
|
let mut start = 0;
|
||||||
|
let mut current_page_number = self.virtual_page_span.get_start();
|
||||||
|
let length = data.len();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let source = &data[start..length.min(start + PAGE_SIZE)];
|
||||||
|
let destination = &mut page_table
|
||||||
|
.translate(current_page_number)
|
||||||
|
.unwrap()
|
||||||
|
.physical_page_numer()
|
||||||
|
.get_bytes_array()[..source.len()];
|
||||||
|
|
||||||
|
destination.copy_from_slice(source);
|
||||||
|
start += PAGE_SIZE;
|
||||||
|
if start >= length {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自增
|
||||||
|
current_page_number.step()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_one(&mut self, page_table: &mut PageTable, virtual_page_number: VirtualPageNumber) {
|
||||||
|
let physical_page_number = match self.map_type {
|
||||||
|
MapType::Identical => {
|
||||||
|
// 使用和虚拟页号一样的物理页号
|
||||||
|
PhysicalPageNumber(virtual_page_number.0)
|
||||||
|
},
|
||||||
|
MapType::Framed => {
|
||||||
|
// 分配新的物理页帧
|
||||||
|
let frame = allocate_frame().unwrap();
|
||||||
|
let frame_number = frame.page_number;
|
||||||
|
self.data_frames.insert(virtual_page_number, frame);
|
||||||
|
frame_number
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let flags = PageTableEntryFlags::from_bits(self.map_permission.bits()).unwrap();
|
||||||
|
page_table.map(virtual_page_number, physical_page_number, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unmap_one(&mut self, page_table: &mut PageTable, virtual_page_number: VirtualPageNumber) {
|
||||||
|
match self.map_type {
|
||||||
|
MapType::Framed => {
|
||||||
|
self.data_frames.remove(&virtual_page_number);
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
page_table.unmap(virtual_page_number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MemorySet {
|
||||||
|
page_table: PageTable,
|
||||||
|
areas: Vec<MapArea>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemorySet {
|
||||||
|
pub fn new_bare() -> Self {
|
||||||
|
Self {
|
||||||
|
page_table: PageTable::new(),
|
||||||
|
areas: vec![]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push(&mut self, mut map_area: MapArea, data: Option<&[u8]>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
161
os/src/memory/page_table.rs
Normal file
161
os/src/memory/page_table.rs
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
use crate::memory::address::{PhysicalPageNumber, VirtualPageNumber, PHYSICAL_PAGE_NUMBER_WIDTH};
|
||||||
|
use crate::memory::frame_allocator::{allocate_frame, FrameTracker};
|
||||||
|
use alloc::vec;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use bitflags::bitflags;
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub struct PageTableEntryFlags: u8 {
|
||||||
|
/// Valid
|
||||||
|
const V = 1 << 0;
|
||||||
|
///Read
|
||||||
|
const R = 1 << 1;
|
||||||
|
/// Write
|
||||||
|
const W = 1 << 2;
|
||||||
|
/// Execute
|
||||||
|
const X = 1 << 3;
|
||||||
|
/// User
|
||||||
|
const U = 1 << 4;
|
||||||
|
/// unknown
|
||||||
|
const G = 1 << 5;
|
||||||
|
/// Accessed
|
||||||
|
const A = 1 << 6;
|
||||||
|
/// Dirty
|
||||||
|
const D = 1 << 7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PageTableEntry {
|
||||||
|
pub bits: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PageTableEntry {
|
||||||
|
pub fn new(page_num: PhysicalPageNumber, flags: PageTableEntryFlags) -> Self {
|
||||||
|
Self {
|
||||||
|
bits: page_num.0 << 10 | flags.bits() as usize,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn empty() -> Self {
|
||||||
|
Self { bits: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn physical_page_numer(&self) -> PhysicalPageNumber {
|
||||||
|
(self.bits >> 10 & (1usize << PHYSICAL_PAGE_NUMBER_WIDTH - 1)).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn flags(&self) -> PageTableEntryFlags {
|
||||||
|
PageTableEntryFlags::from_bits(self.bits as u8).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_valid(&self) -> bool {
|
||||||
|
(self.flags() & PageTableEntryFlags::V) != PageTableEntryFlags::empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn readable(&self) -> bool {
|
||||||
|
(self.flags() & PageTableEntryFlags::R) != PageTableEntryFlags::empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn writable(&self) -> bool {
|
||||||
|
(self.flags() & PageTableEntryFlags::W) != PageTableEntryFlags::empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn executable(&self) -> bool {
|
||||||
|
(self.flags() & PageTableEntryFlags::X) != PageTableEntryFlags::empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PageTable {
|
||||||
|
root_page_number: PhysicalPageNumber,
|
||||||
|
frames: Vec<FrameTracker>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PageTable {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let frame = allocate_frame().unwrap();
|
||||||
|
Self {
|
||||||
|
root_page_number: frame.page_number,
|
||||||
|
frames: vec![frame],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map(
|
||||||
|
&mut self,
|
||||||
|
virtual_page_number: VirtualPageNumber,
|
||||||
|
physical_page_number: PhysicalPageNumber,
|
||||||
|
flags: PageTableEntryFlags,
|
||||||
|
) {
|
||||||
|
let entry = self.find_entry_or_create(virtual_page_number);
|
||||||
|
assert!(
|
||||||
|
!entry.is_valid(),
|
||||||
|
"Virtual page number {:?} is mapped before mapping.",
|
||||||
|
virtual_page_number
|
||||||
|
);
|
||||||
|
*entry = PageTableEntry::new(physical_page_number, flags | PageTableEntryFlags::V);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unmap(&mut self, virtual_page_number: VirtualPageNumber) {
|
||||||
|
let entry = self.find_entry(virtual_page_number).unwrap();
|
||||||
|
assert!(
|
||||||
|
entry.is_valid(),
|
||||||
|
"Virtual page number {:?} is invalid before unmapping",
|
||||||
|
virtual_page_number
|
||||||
|
);
|
||||||
|
*entry = PageTableEntry::empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 从satp寄存器创建临时的页表
|
||||||
|
/// 方便在用户空间时手动查看页表
|
||||||
|
pub fn from_token(satp: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
root_page_number: PhysicalPageNumber::from(
|
||||||
|
satp & ((1usize << PHYSICAL_PAGE_NUMBER_WIDTH) - 1),
|
||||||
|
),
|
||||||
|
frames: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn translate(&self, virtual_page_number: VirtualPageNumber) -> Option<PageTableEntry> {
|
||||||
|
self.find_entry(virtual_page_number).map(|e| e.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_entry_or_create(&mut self, page_number: VirtualPageNumber) -> &mut PageTableEntry {
|
||||||
|
let indexes = page_number.get_indexes();
|
||||||
|
let mut physical_page_number = self.root_page_number;
|
||||||
|
|
||||||
|
for i in 0..2 {
|
||||||
|
let entry = &mut physical_page_number.get_page_table_entry_array()[indexes[i]];
|
||||||
|
|
||||||
|
// 当V是1,其他都是0的页帧就是页表
|
||||||
|
if !entry.is_valid() {
|
||||||
|
let frame = allocate_frame().unwrap();
|
||||||
|
*entry = PageTableEntry::new(frame.page_number, PageTableEntryFlags::V);
|
||||||
|
self.frames.push(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
physical_page_number = entry.physical_page_numer();
|
||||||
|
}
|
||||||
|
|
||||||
|
&mut physical_page_number.get_page_table_entry_array()[indexes[2]]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_entry(&self, page_number: VirtualPageNumber) -> Option<&mut PageTableEntry> {
|
||||||
|
let indexes = page_number.get_indexes();
|
||||||
|
let mut physical_page_number = self.root_page_number;
|
||||||
|
|
||||||
|
for i in 0..2 {
|
||||||
|
let entry = &mut physical_page_number.get_page_table_entry_array()[indexes[i]];
|
||||||
|
|
||||||
|
if !entry.is_valid() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
physical_page_number = entry.physical_page_numer();
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(&mut physical_page_number.get_page_table_entry_array()[indexes[2]])
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,5 @@
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
use crate::config::MAX_APP_NUM;
|
|
||||||
use crate::loader::{get_app_num, initialize_app_context};
|
|
||||||
use crate::log_information;
|
use crate::log_information;
|
||||||
use crate::sbi::shutdown;
|
use crate::sbi::shutdown;
|
||||||
use crate::sync::single_cell::SingleCell;
|
use crate::sync::single_cell::SingleCell;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user