Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
bfaf29e5d4 | |||
2bac1464a1 |
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"
|
||||
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]]
|
||||
name = "critical-section"
|
||||
version = "1.1.2"
|
||||
|
@ -30,7 +45,7 @@ version = "1.5.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
dependencies = [
|
||||
"spin",
|
||||
"spin 0.9.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -52,6 +67,8 @@ checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
|
|||
name = "os"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"buddy_system_allocator",
|
||||
"lazy_static",
|
||||
"riscv",
|
||||
"sbi-rt",
|
||||
|
@ -86,6 +103,12 @@ dependencies = [
|
|||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13287b4da9d1207a4f4929ac390916d64eacfe236a487e9a9f5b3be392be5162"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.8"
|
||||
|
|
|
@ -7,3 +7,5 @@ edition = "2021"
|
|||
sbi-rt = { version = "0.0.2", features = ["legacy"] }
|
||||
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
|
||||
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 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 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 APP_BASE_ADDRESS: usize = 0x80400000;
|
||||
pub const APP_SIZE_LIMIT: usize = 0x20000;
|
||||
pub const TRAMPOLINE: usize = usize::MAX - PAGE_SIZE + 1;
|
||||
pub const TRAP_CONTEXT: usize = TRAMPOLINE - PAGE_SIZE;
|
||||
|
||||
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_main]
|
||||
#![feature(alloc_error_handler)]
|
||||
extern crate alloc;
|
||||
|
||||
use crate::utils::clear_bss;
|
||||
use core::arch::global_asm;
|
||||
|
@ -7,7 +9,6 @@ use core::arch::global_asm;
|
|||
mod boards;
|
||||
mod config;
|
||||
mod console;
|
||||
mod loader;
|
||||
mod sbi;
|
||||
mod sync;
|
||||
mod syscall;
|
||||
|
@ -15,6 +16,7 @@ mod task;
|
|||
mod timer;
|
||||
mod trap;
|
||||
mod utils;
|
||||
mod memory;
|
||||
|
||||
global_asm!(include_str!("entry.asm"));
|
||||
global_asm!(include_str!("link_app.asm"));
|
||||
|
@ -24,8 +26,6 @@ fn rust_main() -> ! {
|
|||
clear_bss();
|
||||
log_information!("Hello, rCore!");
|
||||
trap::init();
|
||||
loader::load_apps();
|
||||
task::run_first_task();
|
||||
|
||||
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 crate::config::MAX_APP_NUM;
|
||||
use crate::loader::{get_app_num, initialize_app_context};
|
||||
use crate::log_information;
|
||||
use crate::sbi::shutdown;
|
||||
use crate::sync::single_cell::SingleCell;
|
||||
|
|
23
user/Makefile
Normal file
23
user/Makefile
Normal file
|
@ -0,0 +1,23 @@
|
|||
TARGET := riscv64gc-unknown-none-elf
|
||||
MODE := release
|
||||
APP_DIR := src/bin
|
||||
TARGET_DIR := target/$(TARGET)/$(MODE)
|
||||
APPS := $(wildcard $(APP_DIR)/*.rs)
|
||||
ELFS := $(patsubst $(APP_DIR)/%.rs, $(TARGET_DIR)/%, $(APPS))
|
||||
BINS := $(patsubst $(APP_DIR)/%.rs, $(TARGET_DIR)/%.bin, $(APPS))
|
||||
|
||||
OBJDUMP := rust-objdump --arch-name=riscv64
|
||||
OBJCOPY := rust-objcopy --binary-architecture=riscv64
|
||||
|
||||
elf: $(APPS)
|
||||
@cargo build --release
|
||||
|
||||
binary: elf
|
||||
@$(foreach elf, $(ELFS), $(OBJCOPY) $(elf) --strip-all -O binary $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.bin, $(elf));)
|
||||
|
||||
build: binary
|
||||
|
||||
clean:
|
||||
@cargo clean
|
||||
|
||||
.PHONY: elf binary build clean
|
|
@ -1,30 +0,0 @@
|
|||
#!/bin/python3
|
||||
import os
|
||||
|
||||
base_address = 0x80400000
|
||||
step = 0x20000
|
||||
linker = 'src/linker.ld'
|
||||
target_dir = "target/riscv64gc-unknown-none-elf/release/"
|
||||
|
||||
app_id = 0
|
||||
apps = os.listdir('src/bin')
|
||||
apps.sort()
|
||||
for app in apps:
|
||||
app = app[:app.find('.')]
|
||||
lines = []
|
||||
lines_before = []
|
||||
with open(linker, 'r') as f:
|
||||
for line in f.readlines():
|
||||
lines_before.append(line)
|
||||
line = line.replace(hex(base_address), hex(base_address+step * app_id))
|
||||
lines.append(line)
|
||||
with open(linker, 'w+') as f:
|
||||
f.writelines(lines)
|
||||
os.system('cargo build --bin %s --release' % app)
|
||||
source_name = target_dir + app
|
||||
dest_name = target_dir + app + ".bin"
|
||||
os.system("rust-objcopy %s --binary-architecture=riscv64 --strip-all -O binary %s" %(source_name, dest_name))
|
||||
print('[build.py] application %s start with address %s' %(app, hex(base_address+step*app_id)))
|
||||
with open(linker, 'w+') as f:
|
||||
f.writelines(lines_before)
|
||||
app_id = app_id + 1
|
17
user/src/bin/load_fault.rs
Normal file
17
user/src/bin/load_fault.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
|
||||
use core::ptr::{null_mut, read_volatile};
|
||||
|
||||
#[no_mangle]
|
||||
fn main() -> i32 {
|
||||
println!("Application 'load_fault' is running...");
|
||||
println!("Kernel should kill this application!");
|
||||
unsafe {
|
||||
let _ = read_volatile(null_mut::<u8>());
|
||||
}
|
||||
0
|
||||
}
|
56
user/src/bin/set_break.rs
Normal file
56
user/src/bin/set_break.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
|
||||
use core::ptr::slice_from_raw_parts_mut;
|
||||
use user_lib::sys_set_break;
|
||||
|
||||
#[no_mangle]
|
||||
fn main() -> i32 {
|
||||
println!("Test set break start...");
|
||||
const PAGE_SIZE: usize = 0x1000;
|
||||
|
||||
let origin_break = sys_set_break(0);
|
||||
println!("Origin break address is {:x}.", origin_break);
|
||||
|
||||
let break_address = sys_set_break(PAGE_SIZE as i32);
|
||||
if origin_break != break_address {
|
||||
return -1;
|
||||
}
|
||||
|
||||
let break_address = sys_set_break(0);
|
||||
println!("Now break address is {:x}.", break_address);
|
||||
|
||||
println!("Try to write into allocated page.");
|
||||
let new_page = unsafe {
|
||||
&mut *slice_from_raw_parts_mut(origin_break as usize as *const u8 as *mut u8, PAGE_SIZE)
|
||||
};
|
||||
for pos in 0..PAGE_SIZE {
|
||||
new_page[pos] = 0;
|
||||
}
|
||||
println!("Write successfully.");
|
||||
|
||||
sys_set_break(PAGE_SIZE as i32 * 10);
|
||||
let break_address = sys_set_break(0);
|
||||
println!("Allocated 10 more pages, break address is {:x}.", break_address);
|
||||
|
||||
sys_set_break(PAGE_SIZE as i32 * -11);
|
||||
let break_address = sys_set_break(0);
|
||||
println!("Deallocated all 11 pages, break address is {:x}.", break_address);
|
||||
|
||||
println!("Try to deallocated one more page, which should fail.");
|
||||
let result = sys_set_break(PAGE_SIZE as i32 * -1);
|
||||
if result == -1 {
|
||||
println!("But succeed, exit!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
println!("Try to write into deallocated pages, which should make this application killed by kernel.");
|
||||
for pos in 0..PAGE_SIZE {
|
||||
new_page[pos] = 0;
|
||||
}
|
||||
|
||||
0
|
||||
}
|
|
@ -11,7 +11,6 @@ pub mod console;
|
|||
#[no_mangle]
|
||||
#[link_section = ".text.entry"]
|
||||
pub extern "C" fn _start() -> ! {
|
||||
utils::clear_bss();
|
||||
exit(main());
|
||||
panic!("Unreachable after exit main!");
|
||||
}
|
||||
|
@ -36,3 +35,7 @@ pub fn get_time() -> isize {
|
|||
pub fn sys_yield() -> isize {
|
||||
syscall::sys_yield()
|
||||
}
|
||||
|
||||
pub fn sys_set_break(size: i32) -> isize {
|
||||
syscall::sys_set_break(size)
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
OUTPUT_ARCH(riscv)
|
||||
ENTRY(_start)
|
||||
|
||||
BASE_ADDRESS = 0x80400000;
|
||||
BASE_ADDRESS = 0x10000;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
|
@ -10,19 +10,19 @@ SECTIONS
|
|||
*(.text.entry)
|
||||
*(.text .text.*)
|
||||
}
|
||||
. = ALIGN(4K);
|
||||
.rodata : {
|
||||
*(.rodata .rodata.*)
|
||||
*(.srodata .srodata.*)
|
||||
}
|
||||
. = ALIGN(4K);
|
||||
.data : {
|
||||
*(.data .data.*)
|
||||
*(.sdata .sdata.*)
|
||||
}
|
||||
.bss : {
|
||||
start_bss = .;
|
||||
*(.bss .bss.*)
|
||||
*(.sbss .sbss.*)
|
||||
end_bss = .;
|
||||
}
|
||||
/DISCARD/ : {
|
||||
*(.eh_frame)
|
||||
|
|
|
@ -4,6 +4,7 @@ const SYSCALL_WRITE: usize = 64;
|
|||
const SYSCALL_EXIT: usize = 93;
|
||||
const SYSCALL_YIELD: usize = 124;
|
||||
const SYSCALL_GET_TIME: usize = 169;
|
||||
const SYSCALL_SET_BREAK: usize = 214;
|
||||
|
||||
fn syscall(id: usize, args: [usize; 3]) -> isize {
|
||||
let mut result: isize;
|
||||
|
@ -36,3 +37,7 @@ pub fn sys_yield() -> isize {
|
|||
pub fn sys_get_time() -> isize {
|
||||
syscall(SYSCALL_GET_TIME, [0, 0, 0])
|
||||
}
|
||||
|
||||
pub fn sys_set_break(size: i32) -> isize {
|
||||
syscall(SYSCALL_SET_BREAK, [size as usize, 0, 0])
|
||||
}
|
||||
|
|
|
@ -1,18 +1,6 @@
|
|||
use crate::println;
|
||||
use core::panic::PanicInfo;
|
||||
|
||||
pub fn clear_bss() {
|
||||
extern "C" {
|
||||
fn start_bss();
|
||||
|
||||
fn end_bss();
|
||||
}
|
||||
|
||||
for i in start_bss as usize..end_bss as usize {
|
||||
unsafe { (i as *mut u8).write_volatile(0) }
|
||||
}
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic_handler(info: &PanicInfo) -> ! {
|
||||
let message = info.message();
|
||||
|
|
Loading…
Reference in New Issue
Block a user