Compare commits

...

10 commits

Author SHA1 Message Date
3a57c25f66 add easyfs fuse mac test
Some checks are pending
Build Rust Doc And Run tests / run-tests (push) Waiting to run
Build Rust Doc And Run tests / build-doc (push) Waiting to run
2025-08-13 15:08:05 +08:00
b7612e38d7 FS init 2025-08-13 14:46:46 +08:00
saying
cec2f15896 fix(scripts): get correct major version 2025-04-25 21:29:26 +08:00
lxc
493e373bcd Update efs.rs
--------

Cherry-picked from #160.
2025-04-05 01:41:47 +08:00
Luv-Ray
1f2b9a2faf alignment 512
--------

Cherry-picked from #158.
2025-04-05 01:41:43 +08:00
Luv-Ray
f9fc2a538c fix alignment
--------

Cherry-picked from #158.
2025-04-05 01:41:39 +08:00
Yifan Wu
5b846fce6a Bump Rust version to nightly-2025-02-18(2024 Edition) 2025-02-26 22:49:56 +08:00
Yifan Wu
123595601d Update doc-and-test.yml 2025-02-12 00:40:45 +08:00
Yifan Wu
6699e80a30 logging: bugfix #137: Init log module to enable logging macros 2025-02-10 23:12:22 +08:00
Yifan Wu
fcf104f124 buildtools: feat #135: Check the version of QEMU ahead 2024-07-14 21:04:15 +08:00
50 changed files with 337 additions and 123 deletions

View file

@ -4,7 +4,7 @@ on: [push]
env: env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
rust_toolchain: nightly-2024-01-18 rust_toolchain: nightly-2025-02-18
jobs: jobs:
build-doc: build-doc:
@ -49,7 +49,10 @@ jobs:
- name: Install QEMU - name: Install QEMU
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install ninja-build -y sudo apt-get install autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev \
gawk build-essential bison flex texinfo gperf libtool patchutils bc \
zlib1g-dev libexpat-dev pkg-config libglib2.0-dev libpixman-1-dev libsdl2-dev libslirp-dev \
python3 python3-pip ninja-build -y
if [ ! -d qemu-7.0.0 ]; then if [ ! -d qemu-7.0.0 ]; then
wget https://download.qemu.org/qemu-7.0.0.tar.xz wget https://download.qemu.org/qemu-7.0.0.tar.xz
tar -xf qemu-7.0.0.tar.xz tar -xf qemu-7.0.0.tar.xz

View file

@ -149,3 +149,59 @@ fn efs_test() -> std::io::Result<()> {
Ok(()) Ok(())
} }
#[test]
fn mac_test() -> std::io::Result<()> {
const BLOCK_SZ: usize = 512;
let block_file = Arc::new(BlockFile(Mutex::new({
let f = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open("target/fs_mac.img")?;
f.set_len(8192 * BLOCK_SZ).unwrap();
f
})));
EasyFileSystem::create(block_file.clone(), 4096, 1);
let efs = EasyFileSystem::open(block_file.clone());
let root_inode = EasyFileSystem::root_inode(&efs);
root_inode.create("root_file");
root_inode.create("public_file");
let secret_inode = root_inode.find("root_file").unwrap();
secret_inode.write_at(0, b"TOP SECRET: root only!");
let public_inode = root_inode.find("public_file").unwrap();
public_inode.write_at(0, b"This file is public.");
let check_permission = |user: &str, filename: &str| -> bool {
if filename == "root_file" && user != "root" {
false
} else {
true
}
};
let users = ["root", "nonroot"];
for user in users.iter() {
println!("{} task:", user);
for filename in ["root_file", "public_file"].iter() {
if check_permission(user, filename) {
let inode = root_inode.find(filename).unwrap();
let mut buf = [0u8; 128];
let len = inode.read_at(0, &mut buf);
let content = core::str::from_utf8(&buf[..len]).unwrap();
println!("{}: Opened successfully");
} else {
println!("{}: Permission denied");
}
}
println!();
}
Ok(())
}

View file

@ -1,12 +1,56 @@
use super::{BlockDevice, BLOCK_SZ}; use super::{BlockDevice, BLOCK_SZ};
use alloc::boxed::Box;
use alloc::collections::VecDeque; use alloc::collections::VecDeque;
use alloc::sync::Arc; use alloc::sync::Arc;
use core::alloc::Layout;
use core::mem::ManuallyDrop;
use core::ptr::{addr_of, addr_of_mut};
use core::slice;
use lazy_static::*; use lazy_static::*;
use spin::Mutex; use spin::Mutex;
/// Use `ManuallyDrop` to ensure data is deallocated with an alignment of `BLOCK_SZ`
struct CacheData(ManuallyDrop<Box<[u8; BLOCK_SZ]>>);
impl CacheData {
pub fn new() -> Self {
let data = unsafe {
let raw = alloc::alloc::alloc(Self::layout());
Box::from_raw(raw as *mut [u8; BLOCK_SZ])
};
Self(ManuallyDrop::new(data))
}
fn layout() -> Layout {
Layout::from_size_align(BLOCK_SZ, BLOCK_SZ).unwrap()
}
}
impl Drop for CacheData {
fn drop(&mut self) {
let ptr = self.0.as_mut_ptr();
unsafe { alloc::alloc::dealloc(ptr, Self::layout()) };
}
}
impl AsRef<[u8]> for CacheData {
fn as_ref(&self) -> &[u8] {
let ptr = self.0.as_ptr() as *const u8;
unsafe { slice::from_raw_parts(ptr, BLOCK_SZ) }
}
}
impl AsMut<[u8]> for CacheData {
fn as_mut(&mut self) -> &mut [u8] {
let ptr = self.0.as_mut_ptr() as *mut u8;
unsafe { slice::from_raw_parts_mut(ptr, BLOCK_SZ) }
}
}
/// Cached block inside memory /// Cached block inside memory
pub struct BlockCache { pub struct BlockCache {
/// cached block data /// cached block data
cache: [u8; BLOCK_SZ], cache: CacheData,
/// underlying block id /// underlying block id
block_id: usize, block_id: usize,
/// underlying block device /// underlying block device
@ -18,8 +62,9 @@ pub struct BlockCache {
impl BlockCache { impl BlockCache {
/// Load a new BlockCache from disk. /// Load a new BlockCache from disk.
pub fn new(block_id: usize, block_device: Arc<dyn BlockDevice>) -> Self { pub fn new(block_id: usize, block_device: Arc<dyn BlockDevice>) -> Self {
let mut cache = [0u8; BLOCK_SZ]; // for alignment and move effciency
block_device.read_block(block_id, &mut cache); let mut cache = CacheData::new();
block_device.read_block(block_id, cache.as_mut());
Self { Self {
cache, cache,
block_id, block_id,
@ -28,8 +73,12 @@ impl BlockCache {
} }
} }
/// Get the address of an offset inside the cached block data /// Get the address of an offset inside the cached block data
fn addr_of_offset(&self, offset: usize) -> usize { fn addr_of_offset(&self, offset: usize) -> *const u8 {
&self.cache[offset] as *const _ as usize addr_of!(self.cache.as_ref()[offset])
}
fn addr_of_offset_mut(&mut self, offset: usize) -> *mut u8 {
addr_of_mut!(self.cache.as_mut()[offset])
} }
pub fn get_ref<T>(&self, offset: usize) -> &T pub fn get_ref<T>(&self, offset: usize) -> &T
@ -38,8 +87,8 @@ impl BlockCache {
{ {
let type_size = core::mem::size_of::<T>(); let type_size = core::mem::size_of::<T>();
assert!(offset + type_size <= BLOCK_SZ); assert!(offset + type_size <= BLOCK_SZ);
let addr = self.addr_of_offset(offset); let addr = self.addr_of_offset(offset) as *const T;
unsafe { &*(addr as *const T) } unsafe { &*addr }
} }
pub fn get_mut<T>(&mut self, offset: usize) -> &mut T pub fn get_mut<T>(&mut self, offset: usize) -> &mut T
@ -49,8 +98,8 @@ impl BlockCache {
let type_size = core::mem::size_of::<T>(); let type_size = core::mem::size_of::<T>();
assert!(offset + type_size <= BLOCK_SZ); assert!(offset + type_size <= BLOCK_SZ);
self.modified = true; self.modified = true;
let addr = self.addr_of_offset(offset); let addr = self.addr_of_offset_mut(offset) as *mut T;
unsafe { &mut *(addr as *mut T) } unsafe { &mut *addr }
} }
pub fn read<T, V>(&self, offset: usize, f: impl FnOnce(&T) -> V) -> V { pub fn read<T, V>(&self, offset: usize, f: impl FnOnce(&T) -> V) -> V {
@ -64,7 +113,8 @@ impl BlockCache {
pub fn sync(&mut self) { pub fn sync(&mut self) {
if self.modified { if self.modified {
self.modified = false; self.modified = false;
self.block_device.write_block(self.block_id, &self.cache); self.block_device
.write_block(self.block_id, self.cache.as_ref());
} }
} }
} }

View file

@ -36,7 +36,7 @@ impl EasyFileSystem {
let data_bitmap_blocks = (data_total_blocks + 4096) / 4097; let data_bitmap_blocks = (data_total_blocks + 4096) / 4097;
let data_area_blocks = data_total_blocks - data_bitmap_blocks; let data_area_blocks = data_total_blocks - data_bitmap_blocks;
let data_bitmap = Bitmap::new( let data_bitmap = Bitmap::new(
(1 + inode_bitmap_blocks + inode_area_blocks) as usize, (1 + inode_total_blocks) as usize,
data_bitmap_blocks as usize, data_bitmap_blocks as usize,
); );
let mut efs = Self { let mut efs = Self {

View file

@ -2,7 +2,7 @@
name = "os" name = "os"
version = "0.1.0" version = "0.1.0"
authors = ["Yifan Wu <shinbokuow@163.com>"] authors = ["Yifan Wu <shinbokuow@163.com>"]
edition = "2021" edition = "2024"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View file

@ -74,20 +74,23 @@ QEMU_ARGS := -machine virt \
-drive file=$(FS_IMG),if=none,format=raw,id=x0 \ -drive file=$(FS_IMG),if=none,format=raw,id=x0 \
-device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0 -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0
run-inner: build QEMU_NAME := qemu-system-riscv64
qemu-version-check:
@sh scripts/qemu-ver-check.sh $(QEMU_NAME)
run-inner: qemu-version-check build
@qemu-system-riscv64 $(QEMU_ARGS) @qemu-system-riscv64 $(QEMU_ARGS)
debug: build debug: qemu-version-check build
@tmux new-session -d \ @tmux new-session -d \
"qemu-system-riscv64 $(QEMU_ARGS) -s -S" && \ "qemu-system-riscv64 $(QEMU_ARGS) -s -S" && \
tmux split-window -h "riscv64-unknown-elf-gdb -ex 'file $(KERNEL_ELF)' -ex 'set arch riscv:rv64' -ex 'target remote localhost:1234'" && \ tmux split-window -h "riscv64-unknown-elf-gdb -ex 'file $(KERNEL_ELF)' -ex 'set arch riscv:rv64' -ex 'target remote localhost:1234'" && \
tmux -2 attach-session -d tmux -2 attach-session -d
gdbserver: qemu-version-check build
gdbserver: build
@qemu-system-riscv64 $(QEMU_ARGS) -s -S @qemu-system-riscv64 $(QEMU_ARGS) -s -S
gdbclient: gdbclient:
@riscv64-unknown-elf-gdb -ex 'file $(KERNEL_ELF)' -ex 'set arch riscv:rv64' -ex 'target remote localhost:1234' @riscv64-unknown-elf-gdb -ex 'file $(KERNEL_ELF)' -ex 'set arch riscv:rv64' -ex 'target remote localhost:1234'
.PHONY: build env kernel clean disasm disasm-vim run-inner fs-img gdbserver gdbclient .PHONY: build env kernel clean disasm disasm-vim run-inner fs-img gdbserver gdbclient qemu-version-check

26
os/scripts/qemu-ver-check.sh Executable file
View file

@ -0,0 +1,26 @@
#!/bin/sh
# Argument1: The filename of qemu executable, e.g. qemu-system-riscv64
QEMU_PATH=$(which $1)
RET=$?
MINIMUM_MAJOR_VERSION=7
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'
if [ $RET != 0 ]
then
echo "$1 not found"
exit 1
else
QEMU_VERSION=$($1 --version|head -n 1|awk '{print $4}')
MAJOR_VERSION=$(echo $QEMU_VERSION | awk -F '.' '{print $1}')
if [ $MAJOR_VERSION -lt $MINIMUM_MAJOR_VERSION ]
then
echo "${RED}Error: Required major version of QEMU is ${MINIMUM_MAJOR_VERSION}, " \
"but current is ${QEMU_VERSION}.${NC}"
exit 1
else
echo "${GREEN}QEMU version is ${QEMU_VERSION}(>=${MINIMUM_MAJOR_VERSION}), OK!${NC}"
exit 0
fi
fi

View file

@ -1,7 +1,7 @@
use super::BlockDevice; use super::BlockDevice;
use crate::mm::{ use crate::mm::{
frame_alloc, frame_dealloc, kernel_token, FrameTracker, PageTable, PhysAddr, PhysPageNum, FrameTracker, PageTable, PhysAddr, PhysPageNum, StepByOne, VirtAddr, frame_alloc,
StepByOne, VirtAddr, frame_dealloc, kernel_token,
}; };
use crate::sync::UPSafeCell; use crate::sync::UPSafeCell;
use alloc::vec::Vec; use alloc::vec::Vec;

View file

@ -15,5 +15,5 @@ pub trait File: Send + Sync {
fn write(&self, buf: UserBuffer) -> usize; fn write(&self, buf: UserBuffer) -> usize;
} }
pub use inode::{list_apps, open_file, OSInode, OpenFlags}; pub use inode::{OSInode, OpenFlags, list_apps, open_file};
pub use stdio::{Stdin, Stdout}; pub use stdio::{Stdin, Stdout};

View file

@ -10,10 +10,10 @@ fn panic(info: &PanicInfo) -> ! {
"[kernel] Panicked at {}:{} {}", "[kernel] Panicked at {}:{} {}",
location.file(), location.file(),
location.line(), location.line(),
info.message().unwrap() info.message()
); );
} else { } else {
error!("[kernel] Panicked: {}", info.message().unwrap()); error!("[kernel] Panicked: {}", info.message());
} }
shutdown(true) shutdown(true)
} }

47
os/src/logging.rs Normal file
View file

@ -0,0 +1,47 @@
/*
log crate 使 main.rs.
*/
use log::{self, Level, LevelFilter, Log, Metadata, Record};
struct SimpleLogger;
impl Log for SimpleLogger {
fn enabled(&self, _metadata: &Metadata) -> bool {
true
}
fn log(&self, record: &Record) {
if !self.enabled(record.metadata()) {
return;
}
let color = match record.level() {
Level::Error => 31, // Red
Level::Warn => 93, // BrightYellow
Level::Info => 34, // Blue
Level::Debug => 32, // Green
Level::Trace => 90, // BrightBlack
};
println!(
"\u{1B}[{}m[{:>5}] {}\u{1B}[0m",
color,
record.level(),
record.args(),
);
}
fn flush(&self) {}
}
pub fn init() {
static LOGGER: SimpleLogger = SimpleLogger;
log::set_logger(&LOGGER).unwrap();
log::set_max_level(match option_env!("LOG") {
Some("ERROR") => LevelFilter::Error,
Some("WARN") => LevelFilter::Warn,
Some("INFO") => LevelFilter::Info,
Some("DEBUG") => LevelFilter::Debug,
Some("TRACE") => LevelFilter::Trace,
_ => LevelFilter::Info,
});
}

View file

@ -23,7 +23,6 @@
#![allow(unused_imports)] #![allow(unused_imports)]
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(panic_info_message)]
#![feature(alloc_error_handler)] #![feature(alloc_error_handler)]
extern crate alloc; extern crate alloc;
@ -31,6 +30,8 @@ extern crate alloc;
#[macro_use] #[macro_use]
extern crate bitflags; extern crate bitflags;
use log::*;
#[path = "boards/qemu.rs"] #[path = "boards/qemu.rs"]
mod board; mod board;
@ -40,6 +41,7 @@ mod config;
mod drivers; mod drivers;
pub mod fs; pub mod fs;
pub mod lang_items; pub mod lang_items;
mod logging;
pub mod mm; pub mod mm;
pub mod sbi; pub mod sbi;
pub mod sync; pub mod sync;
@ -53,9 +55,9 @@ use core::arch::global_asm;
global_asm!(include_str!("entry.asm")); global_asm!(include_str!("entry.asm"));
/// clear BSS segment /// clear BSS segment
fn clear_bss() { fn clear_bss() {
extern "C" { unsafe extern "C" {
fn sbss(); safe fn sbss();
fn ebss(); safe fn ebss();
} }
unsafe { unsafe {
core::slice::from_raw_parts_mut(sbss as usize as *mut u8, ebss as usize - sbss as usize) core::slice::from_raw_parts_mut(sbss as usize as *mut u8, ebss as usize - sbss as usize)
@ -63,11 +65,12 @@ fn clear_bss() {
} }
} }
#[no_mangle]
/// the rust entry-point of os /// the rust entry-point of os
#[unsafe(no_mangle)]
pub fn rust_main() -> ! { pub fn rust_main() -> ! {
clear_bss(); clear_bss();
println!("[kernel] Hello, world!"); logging::init();
info!("[kernel] Hello, world!");
mm::init(); mm::init();
mm::remap_test(); mm::remap_test();
trap::init(); trap::init();

View file

@ -94,8 +94,8 @@ lazy_static! {
} }
/// initiate the frame allocator using `ekernel` and `MEMORY_END` /// initiate the frame allocator using `ekernel` and `MEMORY_END`
pub fn init_frame_allocator() { pub fn init_frame_allocator() {
extern "C" { unsafe extern "C" {
fn ekernel(); safe fn ekernel();
} }
FRAME_ALLOCATOR.exclusive_access().init( FRAME_ALLOCATOR.exclusive_access().init(
PhysAddr::from(ekernel as usize).ceil(), PhysAddr::from(ekernel as usize).ceil(),

View file

@ -1,6 +1,7 @@
//! The global allocator //! The global allocator
use crate::config::KERNEL_HEAP_SIZE; use crate::config::KERNEL_HEAP_SIZE;
use buddy_system_allocator::LockedHeap; use buddy_system_allocator::LockedHeap;
use core::ptr::addr_of_mut;
#[global_allocator] #[global_allocator]
/// heap allocator instance /// heap allocator instance
@ -18,7 +19,7 @@ pub fn init_heap() {
unsafe { unsafe {
HEAP_ALLOCATOR HEAP_ALLOCATOR
.lock() .lock()
.init(HEAP_SPACE.as_ptr() as usize, KERNEL_HEAP_SIZE); .init(addr_of_mut!(HEAP_SPACE) as usize, KERNEL_HEAP_SIZE);
} }
} }
@ -26,9 +27,9 @@ pub fn init_heap() {
pub fn heap_test() { pub fn heap_test() {
use alloc::boxed::Box; use alloc::boxed::Box;
use alloc::vec::Vec; use alloc::vec::Vec;
extern "C" { unsafe extern "C" {
fn sbss(); safe fn sbss();
fn ebss(); safe fn ebss();
} }
let bss_range = sbss as usize..ebss as usize; let bss_range = sbss as usize..ebss as usize;
let a = Box::new(5); let a = Box::new(5);

View file

@ -1,5 +1,6 @@
//! Implementation of [`MapArea`] and [`MemorySet`]. //! Implementation of [`MapArea`] and [`MemorySet`].
use super::{frame_alloc, FrameTracker};
use super::{FrameTracker, frame_alloc};
use super::{PTEFlags, PageTable, PageTableEntry}; use super::{PTEFlags, PageTable, PageTableEntry};
use super::{PhysAddr, PhysPageNum, VirtAddr, VirtPageNum}; use super::{PhysAddr, PhysPageNum, VirtAddr, VirtPageNum};
use super::{StepByOne, VPNRange}; use super::{StepByOne, VPNRange};
@ -12,17 +13,17 @@ use core::arch::asm;
use lazy_static::*; use lazy_static::*;
use riscv::register::satp; use riscv::register::satp;
extern "C" { unsafe extern "C" {
fn stext(); safe fn stext();
fn etext(); safe fn etext();
fn srodata(); safe fn srodata();
fn erodata(); safe fn erodata();
fn sdata(); safe fn sdata();
fn edata(); safe fn edata();
fn sbss_with_stack(); safe fn sbss_with_stack();
fn ebss(); safe fn ebss();
fn ekernel(); safe fn ekernel();
fn strampoline(); safe fn strampoline();
} }
lazy_static! { lazy_static! {
@ -389,20 +390,26 @@ pub fn remap_test() {
let mid_text: VirtAddr = ((stext as usize + etext as usize) / 2).into(); let mid_text: VirtAddr = ((stext as usize + etext as usize) / 2).into();
let mid_rodata: VirtAddr = ((srodata as usize + erodata as usize) / 2).into(); let mid_rodata: VirtAddr = ((srodata as usize + erodata as usize) / 2).into();
let mid_data: VirtAddr = ((sdata as usize + edata as usize) / 2).into(); let mid_data: VirtAddr = ((sdata as usize + edata as usize) / 2).into();
assert!(!kernel_space assert!(
.page_table !kernel_space
.translate(mid_text.floor()) .page_table
.unwrap() .translate(mid_text.floor())
.writable(),); .unwrap()
assert!(!kernel_space .writable(),
.page_table );
.translate(mid_rodata.floor()) assert!(
.unwrap() !kernel_space
.writable(),); .page_table
assert!(!kernel_space .translate(mid_rodata.floor())
.page_table .unwrap()
.translate(mid_data.floor()) .writable(),
.unwrap() );
.executable(),); assert!(
!kernel_space
.page_table
.translate(mid_data.floor())
.unwrap()
.executable(),
);
println!("remap_test passed!"); println!("remap_test passed!");
} }

View file

@ -13,13 +13,13 @@ mod page_table;
use address::VPNRange; use address::VPNRange;
pub use address::{PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum}; pub use address::{PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum};
pub use frame_allocator::{frame_alloc, frame_dealloc, FrameTracker}; pub use frame_allocator::{FrameTracker, frame_alloc, frame_dealloc};
pub use memory_set::remap_test; pub use memory_set::remap_test;
pub use memory_set::{kernel_token, MapPermission, MemorySet, KERNEL_SPACE}; pub use memory_set::{KERNEL_SPACE, MapPermission, MemorySet, kernel_token};
use page_table::PTEFlags; use page_table::PTEFlags;
pub use page_table::{ pub use page_table::{
translated_byte_buffer, translated_ref, translated_refmut, translated_str, PageTable, PageTable, PageTableEntry, UserBuffer, UserBufferIterator, translated_byte_buffer,
PageTableEntry, UserBuffer, UserBufferIterator, translated_ref, translated_refmut, translated_str,
}; };
/// initiate heap allocator, frame allocator and kernel space /// initiate heap allocator, frame allocator and kernel space
pub fn init() { pub fn init() {

View file

@ -1,5 +1,6 @@
//! Implementation of [`PageTableEntry`] and [`PageTable`]. //! Implementation of [`PageTableEntry`] and [`PageTable`].
use super::{frame_alloc, FrameTracker, PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum};
use super::{FrameTracker, PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum, frame_alloc};
use alloc::string::String; use alloc::string::String;
use alloc::vec; use alloc::vec;
use alloc::vec::Vec; use alloc::vec::Vec;

View file

@ -20,7 +20,7 @@ pub fn set_timer(timer: usize) {
/// use sbi call to shutdown the kernel /// use sbi call to shutdown the kernel
pub fn shutdown(failure: bool) -> ! { pub fn shutdown(failure: bool) -> ! {
use sbi_rt::{system_reset, NoReason, Shutdown, SystemFailure}; use sbi_rt::{NoReason, Shutdown, SystemFailure, system_reset};
if !failure { if !failure {
system_reset(Shutdown, NoReason); system_reset(Shutdown, NoReason);
} else { } else {

View file

@ -1,6 +1,6 @@
//! File and filesystem-related syscalls //! File and filesystem-related syscalls
use crate::fs::{open_file, OpenFlags}; use crate::fs::{OpenFlags, open_file};
use crate::mm::{translated_byte_buffer, translated_str, UserBuffer}; use crate::mm::{UserBuffer, translated_byte_buffer, translated_str};
use crate::task::{current_task, current_user_token}; use crate::task::{current_task, current_user_token};
pub fn sys_write(fd: usize, buf: *const u8, len: usize) -> isize { pub fn sys_write(fd: usize, buf: *const u8, len: usize) -> isize {
@ -47,6 +47,13 @@ pub fn sys_open(path: *const u8, flags: u32) -> isize {
let task = current_task().unwrap(); let task = current_task().unwrap();
let token = current_user_token(); let token = current_user_token();
let path = translated_str(token, path); let path = translated_str(token, path);
// 简单用户检查示例:非 root 用户不能打开 /root 下文件
let username = task.inner_exclusive_access().user.clone();
if path.starts_with("/root") && username != "root" {
return -1; // Permission denied
}
if let Some(inode) = open_file(path.as_str(), OpenFlags::from_bits(flags).unwrap()) { if let Some(inode) = open_file(path.as_str(), OpenFlags::from_bits(flags).unwrap()) {
let mut inner = task.inner_exclusive_access(); let mut inner = task.inner_exclusive_access();
let fd = inner.alloc_fd(); let fd = inner.alloc_fd();
@ -57,6 +64,7 @@ pub fn sys_open(path: *const u8, flags: u32) -> isize {
} }
} }
pub fn sys_close(fd: usize) -> isize { pub fn sys_close(fd: usize) -> isize {
let task = current_task().unwrap(); let task = current_task().unwrap();
let mut inner = task.inner_exclusive_access(); let mut inner = task.inner_exclusive_access();

View file

@ -1,4 +1,4 @@
use crate::fs::{open_file, OpenFlags}; use crate::fs::{OpenFlags, open_file};
use crate::mm::{translated_refmut, translated_str}; use crate::mm::{translated_refmut, translated_str};
use crate::task::{ use crate::task::{
add_task, current_task, current_user_token, exit_current_and_run_next, add_task, current_task, current_user_token, exit_current_and_run_next,

View file

@ -23,20 +23,20 @@ mod switch;
#[allow(rustdoc::private_intra_doc_links)] #[allow(rustdoc::private_intra_doc_links)]
mod task; mod task;
use crate::fs::{open_file, OpenFlags}; use crate::fs::{OpenFlags, open_file};
use crate::sbi::shutdown; use crate::sbi::shutdown;
use alloc::sync::Arc; use alloc::sync::Arc;
pub use context::TaskContext; pub use context::TaskContext;
use lazy_static::*; use lazy_static::*;
pub use manager::{fetch_task, TaskManager}; pub use manager::{TaskManager, fetch_task};
use switch::__switch; use switch::__switch;
use task::{TaskControlBlock, TaskStatus}; use task::{TaskControlBlock, TaskStatus};
pub use manager::add_task; pub use manager::add_task;
pub use pid::{pid_alloc, KernelStack, PidAllocator, PidHandle}; pub use pid::{KernelStack, PidAllocator, PidHandle, pid_alloc};
pub use processor::{ pub use processor::{
current_task, current_trap_cx, current_user_token, run_tasks, schedule, take_current_task, Processor, current_task, current_trap_cx, current_user_token, run_tasks, schedule,
Processor, take_current_task,
}; };
/// Suspend the current 'Running' task and run the next task in task list. /// Suspend the current 'Running' task and run the next task in task list.
pub fn suspend_current_and_run_next() { pub fn suspend_current_and_run_next() {

View file

@ -1,6 +1,6 @@
//!Implementation of [`PidAllocator`] //!Implementation of [`PidAllocator`]
use crate::config::{KERNEL_STACK_SIZE, PAGE_SIZE, TRAMPOLINE}; use crate::config::{KERNEL_STACK_SIZE, PAGE_SIZE, TRAMPOLINE};
use crate::mm::{MapPermission, VirtAddr, KERNEL_SPACE}; use crate::mm::{KERNEL_SPACE, MapPermission, VirtAddr};
use crate::sync::UPSafeCell; use crate::sync::UPSafeCell;
use alloc::vec::Vec; use alloc::vec::Vec;
use lazy_static::*; use lazy_static::*;

View file

@ -1,7 +1,7 @@
//!Implementation of [`Processor`] and Intersection of control flow //!Implementation of [`Processor`] and Intersection of control flow
use super::__switch; use super::__switch;
use super::{fetch_task, TaskStatus};
use super::{TaskContext, TaskControlBlock}; use super::{TaskContext, TaskControlBlock};
use super::{TaskStatus, fetch_task};
use crate::sync::UPSafeCell; use crate::sync::UPSafeCell;
use crate::trap::TrapContext; use crate::trap::TrapContext;
use alloc::sync::Arc; use alloc::sync::Arc;

View file

@ -4,6 +4,11 @@ use core::arch::global_asm;
global_asm!(include_str!("switch.S")); global_asm!(include_str!("switch.S"));
extern "C" { unsafe extern "C" {
pub fn __switch(current_task_cx_ptr: *mut TaskContext, next_task_cx_ptr: *const TaskContext); /// Switch to the context of `next_task_cx_ptr`, saving the current context
/// in `current_task_cx_ptr`.
pub unsafe fn __switch(
current_task_cx_ptr: *mut TaskContext,
next_task_cx_ptr: *const TaskContext,
);
} }

View file

@ -1,11 +1,11 @@
//!Implementation of [`TaskControlBlock`] //!Implementation of [`TaskControlBlock`]
use super::TaskContext; use super::TaskContext;
use super::{pid_alloc, KernelStack, PidHandle}; use super::{KernelStack, PidHandle, pid_alloc};
use crate::config::TRAP_CONTEXT; use crate::config::TRAP_CONTEXT;
use crate::fs::{File, Stdin, Stdout}; use crate::fs::{File, Stdin, Stdout};
use crate::mm::{MemorySet, PhysPageNum, VirtAddr, KERNEL_SPACE}; use crate::mm::{KERNEL_SPACE, MemorySet, PhysPageNum, VirtAddr};
use crate::sync::UPSafeCell; use crate::sync::UPSafeCell;
use crate::trap::{trap_handler, TrapContext}; use crate::trap::{TrapContext, trap_handler};
use alloc::sync::{Arc, Weak}; use alloc::sync::{Arc, Weak};
use alloc::vec; use alloc::vec;
use alloc::vec::Vec; use alloc::vec::Vec;
@ -30,6 +30,9 @@ pub struct TaskControlBlockInner {
pub children: Vec<Arc<TaskControlBlock>>, pub children: Vec<Arc<TaskControlBlock>>,
pub exit_code: i32, pub exit_code: i32,
pub fd_table: Vec<Option<Arc<dyn File + Send + Sync>>>, pub fd_table: Vec<Option<Arc<dyn File + Send + Sync>>>,
// New: User
pub user: String,
} }
impl TaskControlBlockInner { impl TaskControlBlockInner {
@ -166,6 +169,7 @@ impl TaskControlBlock {
children: Vec::new(), children: Vec::new(),
exit_code: 0, exit_code: 0,
fd_table: new_fd_table, fd_table: new_fd_table,
user: username.to_string(), // Init User name
}) })
}, },
}); });

View file

@ -1,5 +1,5 @@
//! Implementation of [`TrapContext`] //! Implementation of [`TrapContext`]
use riscv::register::sstatus::{self, Sstatus, SPP}; use riscv::register::sstatus::{self, SPP, Sstatus};
#[repr(C)] #[repr(C)]
#[derive(Debug)] #[derive(Debug)]

View file

@ -50,7 +50,7 @@ pub fn enable_timer_interrupt() {
} }
} }
#[no_mangle] #[unsafe(no_mangle)]
/// handle an interrupt, exception, or system call from user space /// handle an interrupt, exception, or system call from user space
pub fn trap_handler() -> ! { pub fn trap_handler() -> ! {
set_kernel_trap_entry(); set_kernel_trap_entry();
@ -103,7 +103,7 @@ pub fn trap_handler() -> ! {
trap_return(); trap_return();
} }
#[no_mangle] #[unsafe(no_mangle)]
/// set the new addr of __restore asm function in TRAMPOLINE page, /// set the new addr of __restore asm function in TRAMPOLINE page,
/// set the reg a0 = trap_cx_ptr, reg a1 = phy addr of usr page table, /// set the reg a0 = trap_cx_ptr, reg a1 = phy addr of usr page table,
/// finally, jump to new addr of __restore asm function /// finally, jump to new addr of __restore asm function
@ -111,9 +111,9 @@ pub fn trap_return() -> ! {
set_user_trap_entry(); set_user_trap_entry();
let trap_cx_ptr = TRAP_CONTEXT; let trap_cx_ptr = TRAP_CONTEXT;
let user_satp = current_user_token(); let user_satp = current_user_token();
extern "C" { unsafe extern "C" {
fn __alltraps(); unsafe fn __alltraps();
fn __restore(); unsafe fn __restore();
} }
let restore_va = __restore as usize - __alltraps as usize + TRAMPOLINE; let restore_va = __restore as usize - __alltraps as usize + TRAMPOLINE;
unsafe { unsafe {
@ -128,7 +128,7 @@ pub fn trap_return() -> ! {
} }
} }
#[no_mangle] #[unsafe(no_mangle)]
/// Unimplement: traps/interrupts/exceptions from kernel mode /// Unimplement: traps/interrupts/exceptions from kernel mode
/// Todo: Chapter 9: I/O device /// Todo: Chapter 9: I/O device
pub fn trap_from_kernel() -> ! { pub fn trap_from_kernel() -> ! {

View file

@ -1,6 +1,6 @@
[toolchain] [toolchain]
profile = "minimal" profile = "minimal"
# use the nightly version of the last stable toolchain, see <https://forge.rust-lang.org/> # use the nightly version of the last stable toolchain, see <https://forge.rust-lang.org/>
channel = "nightly-2024-05-01" channel = "nightly-2025-02-18"
components = ["rust-src", "llvm-tools", "rustfmt", "clippy"] components = ["rust-src", "llvm-tools", "rustfmt", "clippy"]
targets = ["riscv64gc-unknown-none-elf"] targets = ["riscv64gc-unknown-none-elf"]

View file

@ -2,7 +2,7 @@
name = "user_lib" name = "user_lib"
version = "0.1.0" version = "0.1.0"
authors = ["Yifan Wu <shinbokuow@163.com>"] authors = ["Yifan Wu <shinbokuow@163.com>"]
edition = "2018" edition = "2024"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View file

@ -5,9 +5,9 @@
extern crate user_lib; extern crate user_lib;
extern crate alloc; extern crate alloc;
use user_lib::{close, open, read, OpenFlags}; use user_lib::{OpenFlags, close, open, read};
#[no_mangle] #[unsafe(no_mangle)]
pub fn main() -> i32 { pub fn main() -> i32 {
let fd = open("filea\0", OpenFlags::RDONLY); let fd = open("filea\0", OpenFlags::RDONLY);
if fd == -1 { if fd == -1 {

View file

@ -7,7 +7,7 @@ use user_lib::{exit, fork, wait, waitpid, yield_};
const MAGIC: i32 = -0x10384; const MAGIC: i32 = -0x10384;
#[no_mangle] #[unsafe(no_mangle)]
pub fn main() -> i32 { pub fn main() -> i32 {
println!("I am the parent. Forking the child..."); println!("I am the parent. Forking the child...");
let pid = fork(); let pid = fork();

View file

@ -5,12 +5,12 @@
extern crate user_lib; extern crate user_lib;
macro_rules! color_text { macro_rules! color_text {
($text:expr, $color:expr) => {{ ($text:expr, $color:expr) => {
format_args!("\x1b[{}m{}\x1b[0m", $color, $text) format_args!("\x1b[{}m{}\x1b[0m", $color, $text)
}}; };
} }
#[no_mangle] #[unsafe(no_mangle)]
pub fn main() -> i32 { pub fn main() -> i32 {
println!( println!(
"{}{}{}{}{} {}{}{}{} {}{}{}{}{}{}", "{}{}{}{}{} {}{}{}{} {}{}{}{}{}{}",

View file

@ -4,9 +4,9 @@
#[macro_use] #[macro_use]
extern crate user_lib; extern crate user_lib;
use user_lib::{close, open, read, write, OpenFlags}; use user_lib::{OpenFlags, close, open, read, write};
#[no_mangle] #[unsafe(no_mangle)]
pub fn main() -> i32 { pub fn main() -> i32 {
let test_str = "Hello, world!"; let test_str = "Hello, world!";
let filea = "filea\0"; let filea = "filea\0";

View file

@ -8,7 +8,7 @@ use user_lib::{exit, fork, wait};
const MAX_CHILD: usize = 30; const MAX_CHILD: usize = 30;
#[no_mangle] #[unsafe(no_mangle)]
pub fn main() -> i32 { pub fn main() -> i32 {
for i in 0..MAX_CHILD { for i in 0..MAX_CHILD {
let pid = fork(); let pid = fork();

View file

@ -8,7 +8,7 @@ use user_lib::{exit, fork, get_time, getpid, sleep, wait};
static NUM: usize = 30; static NUM: usize = 30;
#[no_mangle] #[unsafe(no_mangle)]
pub fn main() -> i32 { pub fn main() -> i32 {
for _ in 0..NUM { for _ in 0..NUM {
let pid = fork(); let pid = fork();

View file

@ -6,7 +6,7 @@ extern crate user_lib;
use user_lib::{fork, getpid, wait}; use user_lib::{fork, getpid, wait};
#[no_mangle] #[unsafe(no_mangle)]
pub fn main() -> i32 { pub fn main() -> i32 {
assert_eq!(wait(&mut 0i32), -1); assert_eq!(wait(&mut 0i32), -1);
println!("sys_wait without child process test passed!"); println!("sys_wait without child process test passed!");

View file

@ -29,7 +29,7 @@ fn fork_tree(cur: &str) {
fork_child(cur, '1'); fork_child(cur, '1');
} }
#[no_mangle] #[unsafe(no_mangle)]
pub fn main() -> i32 { pub fn main() -> i32 {
fork_tree(""); fork_tree("");
sleep(3000); sleep(3000);

View file

@ -4,7 +4,7 @@
#[macro_use] #[macro_use]
extern crate user_lib; extern crate user_lib;
#[no_mangle] #[unsafe(no_mangle)]
pub fn main() -> i32 { pub fn main() -> i32 {
println!("Hello world from user mode program!"); println!("Hello world from user mode program!");
0 0

View file

@ -4,9 +4,9 @@
#[macro_use] #[macro_use]
extern crate user_lib; extern crate user_lib;
use user_lib::{close, get_time, open, write, OpenFlags}; use user_lib::{OpenFlags, close, get_time, open, write};
#[no_mangle] #[unsafe(no_mangle)]
pub fn main() -> i32 { pub fn main() -> i32 {
let mut buffer = [0u8; 1024]; // 1KiB let mut buffer = [0u8; 1024]; // 1KiB
for (i, ch) in buffer.iter_mut().enumerate() { for (i, ch) in buffer.iter_mut().enumerate() {

View file

@ -6,7 +6,7 @@ extern crate user_lib;
use user_lib::{exec, fork, wait, yield_}; use user_lib::{exec, fork, wait, yield_};
#[no_mangle] #[unsafe(no_mangle)]
fn main() -> i32 { fn main() -> i32 {
if fork() == 0 { if fork() == 0 {
exec("user_shell\0"); exec("user_shell\0");

View file

@ -44,7 +44,7 @@ fn work(times: isize) {
exit(0); exit(0);
} }
#[no_mangle] #[unsafe(no_mangle)]
pub fn main() -> i32 { pub fn main() -> i32 {
for _ in 0..NUM { for _ in 0..NUM {
let pid = fork(); let pid = fork();

View file

@ -15,7 +15,7 @@ fn sleepy() {
exit(0); exit(0);
} }
#[no_mangle] #[unsafe(no_mangle)]
pub fn main() -> i32 { pub fn main() -> i32 {
let current_time = get_time(); let current_time = get_time();
let pid = fork(); let pid = fork();

View file

@ -6,7 +6,7 @@ extern crate user_lib;
use user_lib::{get_time, sleep}; use user_lib::{get_time, sleep};
#[no_mangle] #[unsafe(no_mangle)]
pub fn main() -> i32 { pub fn main() -> i32 {
println!("into sleep test!"); println!("into sleep test!");
let start = get_time(); let start = get_time();

View file

@ -12,7 +12,7 @@ fn f(depth: usize) {
f(depth + 1); f(depth + 1);
} }
#[no_mangle] #[unsafe(no_mangle)]
pub fn main() -> i32 { pub fn main() -> i32 {
println!("It should trigger segmentation fault!"); println!("It should trigger segmentation fault!");
f(0); f(0);

View file

@ -16,7 +16,7 @@ use alloc::string::String;
use user_lib::console::getchar; use user_lib::console::getchar;
use user_lib::{exec, fork, waitpid}; use user_lib::{exec, fork, waitpid};
#[no_mangle] #[unsafe(no_mangle)]
pub fn main() -> i32 { pub fn main() -> i32 {
println!("Rust user shell"); println!("Rust user shell");
let mut line: String = String::new(); let mut line: String = String::new();

View file

@ -84,7 +84,7 @@ fn run_tests(tests: &[(&str, &str, &str, &str, i32)]) -> i32 {
pass_num pass_num
} }
#[no_mangle] #[unsafe(no_mangle)]
pub fn main() -> i32 { pub fn main() -> i32 {
let succ_num = run_tests(SUCC_TESTS); let succ_num = run_tests(SUCC_TESTS);
let err_num = run_tests(FAIL_TESTS); let err_num = run_tests(FAIL_TESTS);

View file

@ -20,7 +20,7 @@ static TESTS: &[&str] = &[
use user_lib::{exec, fork, waitpid}; use user_lib::{exec, fork, waitpid};
#[no_mangle] #[unsafe(no_mangle)]
pub fn main() -> i32 { pub fn main() -> i32 {
for test in TESTS { for test in TESTS {
println!("Usertests: Running {}", test); println!("Usertests: Running {}", test);

View file

@ -5,7 +5,7 @@
extern crate user_lib; extern crate user_lib;
use user_lib::{getpid, yield_}; use user_lib::{getpid, yield_};
#[no_mangle] #[unsafe(no_mangle)]
pub fn main() -> i32 { pub fn main() -> i32 {
println!("Hello, I am process {}.", getpid()); println!("Hello, I am process {}.", getpid());
for i in 0..5 { for i in 0..5 {

View file

@ -2,7 +2,7 @@ use super::exit;
#[panic_handler] #[panic_handler]
fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! { fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! {
let err = panic_info.message().unwrap(); let err = panic_info.message();
if let Some(location) = panic_info.location() { if let Some(location) = panic_info.location() {
println!( println!(
"Panicked at {}:{}, {}", "Panicked at {}:{}, {}",

View file

@ -1,6 +1,5 @@
#![no_std] #![no_std]
#![feature(linkage)] #![feature(linkage)]
#![feature(panic_info_message)]
#![feature(alloc_error_handler)] #![feature(alloc_error_handler)]
#[macro_use] #[macro_use]
@ -13,6 +12,7 @@ extern crate alloc;
extern crate bitflags; extern crate bitflags;
use buddy_system_allocator::LockedHeap; use buddy_system_allocator::LockedHeap;
use core::ptr::addr_of_mut;
use syscall::*; use syscall::*;
const USER_HEAP_SIZE: usize = 32768; const USER_HEAP_SIZE: usize = 32768;
@ -27,18 +27,18 @@ pub fn handle_alloc_error(layout: core::alloc::Layout) -> ! {
panic!("Heap allocation error, layout = {:?}", layout); panic!("Heap allocation error, layout = {:?}", layout);
} }
#[no_mangle] #[unsafe(no_mangle)]
#[link_section = ".text.entry"] #[unsafe(link_section = ".text.entry")]
pub extern "C" fn _start() -> ! { pub extern "C" fn _start() -> ! {
unsafe { unsafe {
HEAP.lock() HEAP.lock()
.init(HEAP_SPACE.as_ptr() as usize, USER_HEAP_SIZE); .init(addr_of_mut!(HEAP_SPACE) as usize, USER_HEAP_SIZE);
} }
exit(main()); exit(main());
} }
#[linkage = "weak"] #[linkage = "weak"]
#[no_mangle] #[unsafe(no_mangle)]
fn main() -> i32 { fn main() -> i32 {
panic!("Cannot find main!"); panic!("Cannot find main!");
} }