1
0
mirror of https://github.com/rcore-os/rCore.git synced 2024-11-23 00:16:17 +04:00

Merge branch 'dev' into geminilab

This commit is contained in:
BenjaminPMLovegood 2019-05-05 03:40:18 +08:00
commit 5be9ae7775
83 changed files with 4052 additions and 2699 deletions

View File

@ -8,7 +8,7 @@ Going to be the next generation teaching operating system.
Supported architectures: x86_64, RISCV32/64, AArch64, MIPS32
Tested boards: QEMU, HiFive Unleashed, x86_64 PC (i5/i7), Raspberry Pi 3B+
Tested boards: QEMU, HiFive Unleashed, x86_64 PC (i5/i7), Raspberry Pi 3B+, Kendryte K210 and FPGA running Rocket Chip
![demo](./docs/2_OSLab/os2atc/demo.png)

View File

@ -22,6 +22,20 @@ impl<T: FrameAllocator> MemoryHandler for ByFrame<T> {
pt.unmap(addr);
}
fn clone_map(
&self,
pt: &mut PageTable,
with: &Fn(&mut FnMut()),
addr: VirtAddr,
attr: &MemoryAttr,
) {
let data = Vec::from(pt.get_page_slice_mut(addr));
with(&mut || {
self.map(pt, addr, attr);
pt.get_page_slice_mut(addr).copy_from_slice(&data);
});
}
fn handle_page_fault(&self, _pt: &mut PageTable, _addr: VirtAddr) -> bool {
false
}

View File

@ -16,13 +16,6 @@ impl<T: FrameAllocator> MemoryHandler for Delay<T> {
attr.apply(entry);
}
fn map_eager(&self, pt: &mut PageTable, addr: VirtAddr, attr: &MemoryAttr) {
let target = self.allocator.alloc().expect("failed to alloc frame");
let entry = pt.map(addr, target);
entry.set_present(true);
attr.apply(entry);
}
fn unmap(&self, pt: &mut PageTable, addr: VirtAddr) {
let entry = pt.get_entry(addr).expect("failed to get entry");
if entry.present() {
@ -34,6 +27,30 @@ impl<T: FrameAllocator> MemoryHandler for Delay<T> {
pt.unmap(addr);
}
fn clone_map(
&self,
pt: &mut PageTable,
with: &Fn(&mut FnMut()),
addr: VirtAddr,
attr: &MemoryAttr,
) {
let entry = pt.get_entry(addr).expect("failed to get entry");
if entry.present() {
// eager map and copy data
let data = Vec::from(pt.get_page_slice_mut(addr));
with(&mut || {
let target = self.allocator.alloc().expect("failed to alloc frame");
let target_data = pt.get_page_slice_mut(addr);
let entry = pt.map(addr, target);
target_data.copy_from_slice(&data);
attr.apply(entry);
});
} else {
// delay map
with(&mut || self.map(pt, addr, attr));
}
}
fn handle_page_fault(&self, pt: &mut PageTable, addr: VirtAddr) -> bool {
let entry = pt.get_entry(addr).expect("failed to get entry");
if entry.present() {
@ -44,6 +61,11 @@ impl<T: FrameAllocator> MemoryHandler for Delay<T> {
entry.set_target(frame);
entry.set_present(true);
entry.update();
//init with zero for delay mmap mode
let data = pt.get_page_slice_mut(addr);
for x in data {
*x = 0;
}
true
}
}

View File

@ -0,0 +1,108 @@
use super::*;
/// Delay mapping a page to an area of a file.
#[derive(Clone)]
pub struct File<F, T> {
pub file: F,
pub mem_start: usize,
pub file_start: usize,
pub file_end: usize,
pub allocator: T,
}
pub trait Read: Clone + Send + Sync + 'static {
fn read_at(&self, offset: usize, buf: &mut [u8]) -> usize;
}
impl<F: Read, T: FrameAllocator> MemoryHandler for File<F, T> {
fn box_clone(&self) -> Box<MemoryHandler> {
Box::new(self.clone())
}
fn map(&self, pt: &mut PageTable, addr: usize, attr: &MemoryAttr) {
let entry = pt.map(addr, 0);
entry.set_present(false);
attr.apply(entry);
}
fn unmap(&self, pt: &mut PageTable, addr: usize) {
let entry = pt.get_entry(addr).expect("failed to get entry");
if entry.present() {
self.allocator.dealloc(entry.target());
}
// PageTable::unmap requires page to be present
entry.set_present(true);
pt.unmap(addr);
}
fn clone_map(
&self,
pt: &mut PageTable,
with: &Fn(&mut FnMut()),
addr: usize,
attr: &MemoryAttr,
) {
let entry = pt.get_entry(addr).expect("failed to get entry");
if entry.present() && !attr.readonly {
// eager map and copy data
let data = Vec::from(pt.get_page_slice_mut(addr));
with(&mut || {
let target = self.allocator.alloc().expect("failed to alloc frame");
let target_data = pt.get_page_slice_mut(addr);
let entry = pt.map(addr, target);
target_data.copy_from_slice(&data);
attr.apply(entry);
});
} else {
// delay map
with(&mut || self.map(pt, addr, attr));
}
}
fn handle_page_fault(&self, pt: &mut PageTable, addr: usize) -> bool {
let addr = addr & !(PAGE_SIZE - 1);
let entry = pt.get_entry(addr).expect("failed to get entry");
if entry.present() {
return false;
}
let frame = self.allocator.alloc().expect("failed to alloc frame");
entry.set_target(frame);
entry.set_present(true);
let writable = entry.writable();
entry.set_writable(true);
entry.update();
self.fill_data(pt, addr);
let entry = pt.get_entry(addr).expect("failed to get entry");
entry.set_writable(writable);
entry.update();
true
}
}
impl<F: Read, T: FrameAllocator> File<F, T> {
fn fill_data(&self, pt: &mut PageTable, addr: VirtAddr) {
let data = pt.get_page_slice_mut(addr);
let file_offset = addr + self.file_start - self.mem_start;
let read_size = (self.file_end as isize - file_offset as isize)
.min(PAGE_SIZE as isize)
.max(0) as usize;
let read_size = self.file.read_at(file_offset, &mut data[..read_size]);
if read_size != PAGE_SIZE {
data[read_size..].iter_mut().for_each(|x| *x = 0);
}
}
}
impl<F, T> Debug for File<F, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
f.debug_struct("FileHandler")
.field("mem_start", &self.mem_start)
.field("file_start", &self.file_start)
.field("file_end", &self.file_end)
.finish()
}
}

View File

@ -20,6 +20,16 @@ impl MemoryHandler for Linear {
pt.unmap(addr);
}
fn clone_map(
&self,
pt: &mut PageTable,
with: &Fn(&mut FnMut()),
addr: VirtAddr,
attr: &MemoryAttr,
) {
with(&mut || self.map(pt, addr, attr));
}
fn handle_page_fault(&self, _pt: &mut PageTable, _addr: VirtAddr) -> bool {
false
}

View File

@ -1,23 +1,28 @@
use super::*;
// here may be a interesting part for lab
pub trait MemoryHandler: Debug + 'static {
pub trait MemoryHandler: Debug + Send + Sync + 'static {
fn box_clone(&self) -> Box<MemoryHandler>;
/// Map `addr` in the page table
/// Should set page flags here instead of in page_fault_handler
fn map(&self, pt: &mut PageTable, addr: VirtAddr, attr: &MemoryAttr);
/// Map `addr` in the page table eagerly (i.e. no delay allocation)
/// Should set page flags here instead of in page_fault_handler
fn map_eager(&self, pt: &mut PageTable, addr: VirtAddr, attr: &MemoryAttr) {
// override this when pages are allocated lazily
self.map(pt, addr, attr);
}
/// Unmap `addr` in the page table
fn unmap(&self, pt: &mut PageTable, addr: VirtAddr);
/// Clone map `addr` from one page table to another.
/// `pt` is the current active page table.
/// `with` is the `InactivePageTable::with` function.
/// Call `with` then use `pt` as target page table inside.
fn clone_map(
&self,
pt: &mut PageTable,
with: &Fn(&mut FnMut()),
addr: VirtAddr,
attr: &MemoryAttr,
);
/// Handle page fault on `addr`
/// Return true if success, false if error
fn handle_page_fault(&self, pt: &mut PageTable, addr: VirtAddr) -> bool;
@ -29,16 +34,18 @@ impl Clone for Box<MemoryHandler> {
}
}
pub trait FrameAllocator: Debug + Clone + 'static {
pub trait FrameAllocator: Debug + Clone + Send + Sync + 'static {
fn alloc(&self) -> Option<PhysAddr>;
fn dealloc(&self, target: PhysAddr);
}
mod byframe;
mod delay;
mod file;
mod linear;
//mod swap;
pub use self::byframe::ByFrame;
pub use self::delay::Delay;
pub use self::file::{File, Read};
pub use self::linear::Linear;

View File

@ -3,6 +3,7 @@
use alloc::{boxed::Box, string::String, vec::Vec};
use core::fmt::{Debug, Error, Formatter};
use core::mem::size_of;
use crate::paging::*;
@ -23,8 +24,6 @@ pub struct MemoryArea {
name: &'static str,
}
unsafe impl Send for MemoryArea {}
impl MemoryArea {
/*
** @brief get slice of the content in the memory area
@ -54,15 +53,27 @@ impl MemoryArea {
pub fn contains(&self, addr: VirtAddr) -> bool {
addr >= self.start_addr && addr < self.end_addr
}
/// Check the array is within the readable memory
fn check_read_array<S>(&self, ptr: *const S, count: usize) -> bool {
/// Check the array is within the readable memory.
/// Return the size of space covered in the area.
fn check_read_array<S>(&self, ptr: *const S, count: usize) -> usize {
// page align
ptr as usize >= Page::of_addr(self.start_addr).start_address()
&& unsafe { ptr.add(count) as usize } < Page::of_addr(self.end_addr + PAGE_SIZE - 1).start_address()
let min_bound = (ptr as usize).max(Page::of_addr(self.start_addr).start_address());
let max_bound = unsafe { ptr.add(count) as usize }
.min(Page::of_addr(self.end_addr + PAGE_SIZE - 1).start_address());
if max_bound >= min_bound {
max_bound - min_bound
} else {
0
}
}
/// Check the array is within the writable memory
fn check_write_array<S>(&self, ptr: *mut S, count: usize) -> bool {
!self.attr.readonly && self.check_read_array(ptr, count)
/// Check the array is within the writable memory.
/// Return the size of space covered in the area.
fn check_write_array<S>(&self, ptr: *mut S, count: usize) -> usize {
if self.attr.readonly {
0
} else {
self.check_read_array(ptr, count)
}
}
/// Check the null-end C string is within the readable memory, and is valid.
/// If so, clone it to a String.
@ -86,31 +97,13 @@ impl MemoryArea {
let p3 = Page::of_addr(end_addr - 1) + 1;
!(p1 <= p2 || p0 >= p3)
}
/*
** @brief map the memory area to the physice address in a page table
** @param pt: &mut T::Active the page table to use
** @retval none
*/
/// Map all pages in the area to page table `pt`
fn map(&self, pt: &mut PageTable) {
for page in Page::range_of(self.start_addr, self.end_addr) {
self.handler.map(pt, page.start_address(), &self.attr);
}
}
/*
** @brief map the memory area to the physice address in a page table eagerly
** @param pt: &mut T::Active the page table to use
** @retval none
*/
fn map_eager(&self, pt: &mut PageTable) {
for page in Page::range_of(self.start_addr, self.end_addr) {
self.handler.map_eager(pt, page.start_address(), &self.attr);
}
}
/*
** @brief unmap the memory area from the physice address in a page table
** @param pt: &mut T::Active the page table to use
** @retval none
*/
/// Unmap all pages in the area from page table `pt`
fn unmap(&self, pt: &mut PageTable) {
for page in Page::range_of(self.start_addr, self.end_addr) {
self.handler.unmap(pt, page.start_address());
@ -204,28 +197,60 @@ impl<T: InactivePageTable> MemorySet<T> {
}
}
/// Check the pointer is within the readable memory
pub fn check_read_ptr<S>(&self, ptr: *const S) -> VMResult<()> {
self.check_read_array(ptr, 1)
pub unsafe fn check_read_ptr<S>(&self, ptr: *const S) -> VMResult<&'static S> {
self.check_read_array(ptr, 1).map(|s| &s[0])
}
/// Check the pointer is within the writable memory
pub fn check_write_ptr<S>(&self, ptr: *mut S) -> VMResult<()> {
self.check_write_array(ptr, 1)
pub unsafe fn check_write_ptr<S>(&self, ptr: *mut S) -> VMResult<&'static mut S> {
self.check_write_array(ptr, 1).map(|s| &mut s[0])
}
/// Check the array is within the readable memory
pub fn check_read_array<S>(&self, ptr: *const S, count: usize) -> VMResult<()> {
self.areas
.iter()
.find(|area| area.check_read_array(ptr, count))
.map(|_| ())
.ok_or(VMError::InvalidPtr)
pub unsafe fn check_read_array<S>(
&self,
ptr: *const S,
count: usize,
) -> VMResult<&'static [S]> {
let mut valid_size = 0;
for area in self.areas.iter() {
valid_size += area.check_read_array(ptr, count);
if valid_size == size_of::<S>() * count {
return Ok(core::slice::from_raw_parts(ptr, count));
}
}
Err(VMError::InvalidPtr)
}
/// Check the array is within the writable memory
pub fn check_write_array<S>(&self, ptr: *mut S, count: usize) -> VMResult<()> {
self.areas
.iter()
.find(|area| area.check_write_array(ptr, count))
.map(|_| ())
.ok_or(VMError::InvalidPtr)
pub unsafe fn check_write_array<S>(
&self,
ptr: *mut S,
count: usize,
) -> VMResult<&'static mut [S]> {
let mut valid_size = 0;
for area in self.areas.iter() {
valid_size += area.check_write_array(ptr, count);
if valid_size == size_of::<S>() * count {
return Ok(core::slice::from_raw_parts_mut(ptr, count));
}
}
Err(VMError::InvalidPtr)
}
/// Check the null-end C string pointer array
/// Used for getting argv & envp
pub unsafe fn check_and_clone_cstr_array(
&self,
mut argv: *const *const u8,
) -> VMResult<Vec<String>> {
let mut args = Vec::new();
loop {
let cstr = *self.check_read_ptr(argv)?;
if cstr.is_null() {
break;
}
let arg = self.check_and_clone_cstr(cstr)?;
args.push(arg);
argv = argv.add(1);
}
Ok(args)
}
/// Check the null-end C string is within the readable memory, and is valid.
/// If so, clone it to a String.
@ -283,7 +308,15 @@ impl<T: InactivePageTable> MemorySet<T> {
name,
};
self.page_table.edit(|pt| area.map(pt));
self.areas.push(area);
// keep order by start address
let idx = self
.areas
.iter()
.enumerate()
.find(|(_, other)| start_addr < other.start_addr)
.map(|(i, _)| i)
.unwrap_or(self.areas.len());
self.areas.insert(idx, area);
}
/*
@ -474,20 +507,29 @@ impl<T: InactivePageTable> MemorySet<T> {
None => false,
}
}
}
impl<T: InactivePageTable> Clone for MemorySet<T> {
fn clone(&self) -> Self {
let mut page_table = T::new();
pub fn clone(&mut self) -> Self {
let new_page_table = T::new();
let Self {
ref mut page_table,
ref areas,
..
} = self;
page_table.edit(|pt| {
// without CoW, we should allocate the pages eagerly
for area in self.areas.iter() {
area.map_eager(pt);
for area in areas.iter() {
for page in Page::range_of(area.start_addr, area.end_addr) {
area.handler.clone_map(
pt,
&|f| unsafe { new_page_table.with(f) },
page.start_address(),
&area.attr,
);
}
}
});
MemorySet {
areas: self.areas.clone(),
page_table,
areas: areas.clone(),
page_table: new_page_table,
}
}
}

File diff suppressed because one or more lines are too long

13
kernel/Cargo.lock generated
View File

@ -111,7 +111,7 @@ dependencies = [
[[package]]
name = "buddy_system_allocator"
version = "0.1.2"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -271,11 +271,6 @@ name = "nodrop"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "once"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "os_bootinfo"
version = "0.2.1"
@ -395,7 +390,7 @@ dependencies = [
"bitmap-allocator 0.1.0 (git+https://github.com/rcore-os/bitmap-allocator)",
"bitvec 0.11.0 (git+https://github.com/myrrlyn/bitvec.git?rev=ed2aec38bfb5b1116e3585b1574c50655b9c85ec)",
"bootloader 0.4.0 (git+https://github.com/rcore-os/bootloader)",
"buddy_system_allocator 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"buddy_system_allocator 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)",
"console-traits 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"device_tree 1.0.3 (git+https://github.com/rcore-os/device_tree-rs)",
@ -404,7 +399,6 @@ dependencies = [
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mips 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"once 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"paste 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"pc-keyboard 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pci 0.0.1 (git+https://github.com/rcore-os/pci-rs)",
@ -699,7 +693,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum bitvec 0.11.0 (git+https://github.com/myrrlyn/bitvec.git?rev=ed2aec38bfb5b1116e3585b1574c50655b9c85ec)" = "<none>"
"checksum bitvec 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cfadef5c4e2c2e64067b9ecc061179f12ac7ec65ba613b1f60f3972bbada1f5b"
"checksum bootloader 0.4.0 (git+https://github.com/rcore-os/bootloader)" = "<none>"
"checksum buddy_system_allocator 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2ed828f1e227d6e32b998d6375b67fd63ac5389d50b23f258ce151d22b6cc595"
"checksum buddy_system_allocator 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "94a6c0143a07fea0db2f4b43cb9540dcc7c17af8a7beafdf2184e5e4e35aae91"
"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
"checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427"
"checksum cc 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a0c56216487bb80eec9c4516337b2588a4f2a2290d72a1416d930e4dcdb0c90d"
@ -723,7 +717,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum managed 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fdcec5e97041c7f0f1c5b7d93f12e57293c831c646f4cc7a5db59460c7ea8de6"
"checksum mips 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4cbf449a63e4db77af9f662d6b42068c0925e779a3a7c70ad02f191cf1e6c802"
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
"checksum once 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "931fb7a4cf34610cf6cbe58d52a8ca5ef4c726d4e2e178abd0dc13a6551c6d73"
"checksum os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "66481dbeb5e773e7bd85b63cd6042c30786f834338288c5ec4f3742673db360a"
"checksum paste 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4a4a1c555c6505821f9d58b8779d0f630a6b7e4e1be24ba718610acf01fa79"
"checksum paste-impl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "26e796e623b8b257215f27e6c80a5478856cae305f5b59810ff9acdaa34570e6"

View File

@ -23,6 +23,8 @@ default = ["sv39"]
# Page table sv39 or sv48 (for riscv64)
sv39 = []
board_u540 = ["sv39", "link_user"]
board_k210 = ["sv39", "link_user"]
board_rocket_chip = ["sv39", "link_user"]
# (for aarch64 RaspberryPi3)
nographic = []
board_raspi3 = ["bcm2837", "link_user"]
@ -38,6 +40,8 @@ board_pc = ["link_user"]
link_user = []
# Run cmdline instead of user shell, useful for automatic testing
run_cmdline = []
# Add performance profiling
profile = []
[profile.dev]
# MUST >= 2 : Enable RVO to avoid stack overflow
@ -46,7 +50,6 @@ opt-level = 2
[dependencies]
log = "0.4"
spin = "0.5"
once = "0.3"
xmas-elf = "0.6"
bitflags = "1.0"
bit_field = "0.9"
@ -54,7 +57,7 @@ volatile = "0.2"
heapless = "0.4"
bitvec = { git = "https://github.com/myrrlyn/bitvec.git", rev = "ed2aec38bfb5b1116e3585b1574c50655b9c85ec", default-features = false, features = ["alloc"] }
console-traits = "0.3"
buddy_system_allocator = "0.1"
buddy_system_allocator = "0.3"
pci = { git = "https://github.com/rcore-os/pci-rs" }
device_tree = { git = "https://github.com/rcore-os/device_tree-rs" }
isomorphic_drivers = { git = "https://github.com/rcore-os/isomorphic_drivers" }

View File

@ -23,13 +23,16 @@
# smp = 1 | 2 | ... SMP core number
# graphic = on | off Enable/disable qemu graphical output
# board = none Running on QEMU
# | pc Only available on x86_64, run on real pc
# | pc Only available on x86_64, run on real pc
# | u540 Only available on riscv64, run on HiFive U540, use Sv39
# | k210 Only available on riscv64, run on K210, use Sv39
# | rocket_chip Only available on riscv64, run on Rocket Chip, use Sv39
# | raspi3 Only available on aarch64, run on Raspberry Pi 3 Model B/B+
# pci_passthru = 0000:00:00.1 Only available on x86_64, passthrough the specified PCI device
# init = /bin/ls Only available on riscv64, run specified program instead of user shell
# extra_nic = on | off Only available on x86_64, add an additional e1000 nic
# u_boot = /path/to/u-boot.bin Only available on aarch64, use u-boot to boot rcore
# . extra_features = profile | ... Add additional features
arch ?= riscv64
board ?= none
@ -59,7 +62,7 @@ ifeq ($(arch), $(filter $(arch), aarch64 mipsel))
export SFSIMG = $(user_dir)/build/$(arch).img
else
# board is pc or qemu?
ifeq ($(board), pc)
ifeq ($(board), $(filter $(board), pc u540 k210 rocket_chip))
#link user img, so use original image
export SFSIMG = $(user_dir)/build/$(arch).img
else
@ -124,6 +127,7 @@ endif
else ifeq ($(arch), riscv32)
qemu_opts += \
-machine virt \
-serial mon:stdio \
-kernel ../tools/opensbi/virt_rv32.elf \
-device loader,addr=0x80400000,file=$(kernel_img) \
-drive file=$(SFSIMG),format=qcow2,id=sfs \
@ -136,11 +140,13 @@ else ifeq ($(arch), riscv64)
ifeq ($(board), u540)
qemu_opts += \
-machine virt \
-serial mon:stdio \
-kernel ../tools/opensbi/fu540.elf \
-device loader,addr=0x80200000,file=$(kernel_img)
else
qemu_opts += \
-machine virt \
-serial mon:stdio \
-kernel ../tools/opensbi/virt_rv64.elf \
-device loader,addr=0x80200000,file=$(kernel_img) \
-drive file=$(SFSIMG),format=qcow2,id=sfs \
@ -201,15 +207,12 @@ features += raspi3_use_generic_timer
endif
endif
ifeq ($(board), u540)
features += sv39
riscv_pk_args += --enable-sv39
endif
ifneq ($(board), none)
features += board_$(board)
endif
features += $(extra_features)
build_args := --target targets/$(target).json --features "$(features)"
ifeq ($(mode), release)
@ -270,7 +273,7 @@ justrunui: build
-device virtio-mouse-device
justruntest: build
@qemu-system-$(arch) $(qemu_opts) --append $(init) -serial file:../tests/stdout -monitor null
@qemu-system-$(arch) $(filter-out -serial mon:stdio, $(qemu_opts)) --append $(init) -serial file:../tests/stdout -monitor null
debug: $(kernel) $(kernel_img)
@qemu-system-$(arch) $(qemu_opts) -s -S &
@ -325,6 +328,11 @@ ifeq ($(arch), x86_64)
@bootimage build $(build_args)
@mv target/x86_64/bootimage.bin $(bootimage)
else ifeq ($(arch), $(filter $(arch), riscv32 riscv64))
ifeq ($(board), k210)
@cp src/arch/riscv32/board/k210/linker.ld src/arch/riscv32/boot/linker64.ld
else
@cp src/arch/riscv32/board/u540/linker.ld src/arch/riscv32/boot/linker64.ld
endif
@-patch -p0 -N -b \
$(shell rustc --print sysroot)/lib/rustlib/src/rust/src/libcore/sync/atomic.rs \
src/arch/riscv32/atomic.patch
@ -367,10 +375,18 @@ ifeq ($(board), u540)
.PHONY:
install: $(kernel_img)
@$(objcopy) -S -O binary ../tools/opensbi/fu540.elf $(build_path)/bin
@dd if=$< of=$(build_path)/bin bs=131072 seek=16
@../tools/u540/mkimg.sh $(build_path)/bin $(build_path)/sd.img
@dd if=$< of=$(build_path)/bin bs=0x20000 seek=16
@../tools/u540/mkimg.sh $(build_path)/bin $(build_path)/u540.img
endif
ifeq ($(board), k210)
.PHONY:
install: $(kernel_img)
@$(objcopy) -S -O binary ../tools/opensbi/k210.elf $(build_path)/k210.img
@dd if=$< of=$(build_path)/k210.img bs=0x10000 seek=1
@python3 ../tools/k210/kflash.py -b 600000 $(build_path)/k210.img
endif
.PHONY:
addr2line:
@python3 ../tools/addr2line.py $(prefix)addr2line $(arch) $(mode)
@python3.7 ../tools/addr2line.py $(prefix)addr2line $(arch) $(mode)

View File

@ -2,7 +2,6 @@
use alloc::string::String;
use bcm2837::atags::Atags;
use once::*;
#[path = "../../../../drivers/gpu/fb.rs"]
pub mod fb;
@ -18,10 +17,7 @@ pub const IO_REMAP_END: usize = bcm2837::consts::KERNEL_OFFSET + 0x4000_1000;
/// Initialize serial port before other initializations.
pub fn init_serial_early() {
assert_has_not_been_called!("board::init must be called only once");
serial::init();
println!("Hello Raspberry Pi!");
}

View File

@ -1,7 +1,6 @@
use bcm2837::mini_uart::{MiniUart, MiniUartInterruptId};
use core::fmt;
use lazy_static::lazy_static;
use once::*;
use spin::Mutex;
/// Struct to get a global SerialPort interface
@ -23,8 +22,6 @@ impl SerialPort {
/// Init a newly created SerialPort, can only be called once.
fn init(&mut self) {
assert_has_not_been_called!("SerialPort::init must be called only once");
self.mu.init();
super::irq::register_irq(super::irq::Interrupt::Aux, handle_serial_irq);
}

View File

@ -1,7 +1,6 @@
//! ARM64 drivers
use super::board;
use once::*;
pub use self::board::fb;
pub use self::board::serial;
@ -10,8 +9,6 @@ pub mod console;
/// Initialize ARM64 common drivers
pub fn init() {
assert_has_not_been_called!("driver::init must be called only once");
board::init_driver();
console::init();
}

View File

@ -32,7 +32,7 @@ impl TrapFrame {
tf.spsr = 0b1101_00_0101; // To EL 1, enable IRQ
tf
}
fn new_user_thread(entry_addr: usize, sp: usize) -> Self {
pub fn new_user_thread(entry_addr: usize, sp: usize) -> Self {
use core::mem::zeroed;
let mut tf: Self = unsafe { zeroed() };
tf.sp = sp;
@ -40,9 +40,6 @@ impl TrapFrame {
tf.spsr = 0b1101_00_0000; // To EL 0, enable IRQ
tf
}
pub fn is_user(&self) -> bool {
unimplemented!()
}
}
/// 新线程的内核栈初始内容
@ -201,11 +198,6 @@ impl Context {
}
.push_at(kstack_top, ttbr)
}
/// Called at a new user context
/// To get the init TrapFrame in sys_exec
pub unsafe fn get_init_tf(&self) -> TrapFrame {
(*(self.stack_top as *const InitStack)).tf.clone()
}
}
const ASID_MASK: u16 = 0xffff;

View File

@ -1,7 +1,6 @@
use crate::drivers::bus::pci;
use alloc::string::String;
use mips::registers::cp0;
use once::*;
#[path = "../../../../drivers/console/mod.rs"]
pub mod console;
@ -17,7 +16,6 @@ use fb::FramebufferInfo;
/// Initialize serial port first
pub fn init_serial_early() {
assert_has_not_been_called!("board::init must be called only once");
// initialize serial driver
serial::init(0xbf000900);
// Enable serial interrupt

View File

@ -1,5 +1,4 @@
use alloc::string::String;
use once::*;
#[path = "../../../../drivers/console/mod.rs"]
pub mod console;
@ -11,7 +10,6 @@ pub mod serial;
/// Initialize serial port first
pub fn init_serial_early() {
assert_has_not_been_called!("board::init must be called only once");
serial::init(0xbfd003f8);
println!("Hello QEMU MIPSSIM!");
}

View File

@ -1,5 +1,4 @@
use alloc::string::String;
use once::*;
#[path = "../../../../drivers/console/mod.rs"]
pub mod console;
@ -14,7 +13,6 @@ use fb::FramebufferResult;
/// Initialize serial port first
pub fn init_serial_early() {
assert_has_not_been_called!("board::init must be called only once");
serial::init(0xa3000000);
println!("Hello ThinPad!");
}

View File

@ -76,7 +76,7 @@ impl TrapFrame {
///
/// The new thread starts at `entry_addr`.
/// The stack pointer will be set to `sp`.
fn new_user_thread(entry_addr: usize, sp: usize) -> Self {
pub fn new_user_thread(entry_addr: usize, sp: usize) -> Self {
use core::mem::zeroed;
let mut tf: Self = unsafe { zeroed() };
tf.sp = sp;
@ -269,9 +269,4 @@ impl Context {
}
.push_at(kstack_top)
}
/// Used for getting the init TrapFrame of a new user context in `sys_exec`.
pub unsafe fn get_init_tf(&self) -> TrapFrame {
(*(self.sp as *const InitStack)).tf.clone()
}
}

View File

@ -1,7 +1,6 @@
//! mipsel drivers
use super::board;
use once::*;
pub use self::board::fb;
pub use self::board::serial;
@ -10,7 +9,6 @@ pub mod console;
/// Initialize common drivers
pub fn init() {
assert_has_not_been_called!("driver::init must be called only once");
board::init_driver();
console::init();
}

View File

@ -0,0 +1,49 @@
/* Copy from bbl-ucore : https://ring00.github.io/bbl-ucore */
/* Simple linker script for the ucore kernel.
See the GNU ld 'info' manual ("info ld") to learn the syntax. */
OUTPUT_ARCH(riscv)
ENTRY(_start)
BASE_ADDRESS = 0xffffffffc0010000;
SECTIONS
{
/* Load the kernel at this address: "." means the current address */
. = BASE_ADDRESS;
start = .;
.text : {
stext = .;
*(.text.entry)
*(.text .text.*)
. = ALIGN(4K);
etext = .;
}
.rodata : {
srodata = .;
*(.rodata .rodata.*)
. = ALIGN(4K);
erodata = .;
}
.data : {
sdata = .;
*(.data .data.*)
edata = .;
}
.stack : {
*(.bss.stack)
}
.bss : {
sbss = .;
*(.bss .bss.*)
ebss = .;
}
PROVIDE(end = .);
}

View File

@ -0,0 +1,49 @@
/* Copy from bbl-ucore : https://ring00.github.io/bbl-ucore */
/* Simple linker script for the ucore kernel.
See the GNU ld 'info' manual ("info ld") to learn the syntax. */
OUTPUT_ARCH(riscv)
ENTRY(_start)
BASE_ADDRESS = 0xffffffffc0200000;
SECTIONS
{
/* Load the kernel at this address: "." means the current address */
. = BASE_ADDRESS;
start = .;
.text : {
stext = .;
*(.text.entry)
*(.text .text.*)
. = ALIGN(4K);
etext = .;
}
.rodata : {
srodata = .;
*(.rodata .rodata.*)
. = ALIGN(4K);
erodata = .;
}
.data : {
sdata = .;
*(.data .data.*)
edata = .;
}
.stack : {
*(.bss.stack)
}
.bss : {
sbss = .;
*(.bss .bss.*)
ebss = .;
}
PROVIDE(end = .);
}

View File

@ -8,7 +8,7 @@ _start:
# 1. set sp
# sp = bootstack + (hartid + 1) * 0x10000
add t0, a0, 1
slli t0, t0, 16
slli t0, t0, 14
lui sp, %hi(bootstack)
add sp, sp, t0
@ -32,7 +32,7 @@ _start:
.align 12 # page align
.global bootstack
bootstack:
.space 4096 * 16 * 8
.space 4096 * 4 * 8
.global bootstacktop
bootstacktop:

View File

@ -8,7 +8,7 @@ _start:
# 1. set sp
# sp = bootstack + (hartid + 1) * 0x10000
add t0, a0, 1
slli t0, t0, 16
slli t0, t0, 14
lui sp, %hi(bootstack)
add sp, sp, t0
@ -32,7 +32,7 @@ _start:
.align 12 # page align
.global bootstack
bootstack:
.space 4096 * 16 * 8
.space 4096 * 4 * 8
.global bootstacktop
bootstacktop:

View File

@ -0,0 +1,30 @@
.section .text.entry
.globl _start
_start:
# a0 == hartid
# pc == 0x80010000
# sp == 0x8000xxxx
# 1. set sp
# sp = bootstack + (hartid + 1) * 0x10000
add t0, a0, 1
slli t0, t0, 14
lui sp, %hi(bootstack)
add sp, sp, t0
# 1.1 set device tree paddr
# OpenSBI give me 0 ???
li a1, 0x800003b0
# 2. jump to rust_main (absolute address)
lui t0, %hi(rust_main)
addi t0, t0, %lo(rust_main)
jr t0
.section .bss.stack
.align 12 # page align
.global bootstack
bootstack:
.space 4096 * 4 * 2
.global bootstacktop
bootstacktop:

View File

@ -22,10 +22,16 @@ pub const KERNEL_P2_INDEX: usize = (KERNEL_OFFSET >> 12 >> 10) & 0x3ff;
#[cfg(target_arch = "riscv64")]
pub const KERNEL_P4_INDEX: usize = (KERNEL_OFFSET >> 12 >> 9 >> 9 >> 9) & 0o777;
#[cfg(feature = "board_k210")]
pub const KERNEL_HEAP_SIZE: usize = 0x0020_0000;
#[cfg(not(feature = "board_k210"))]
pub const KERNEL_HEAP_SIZE: usize = 0x0080_0000;
pub const MEMORY_OFFSET: usize = 0x8000_0000;
// TODO: get memory end from device tree
#[cfg(feature = "board_k210")]
pub const MEMORY_END: usize = 0x8060_0000;
#[cfg(not(feature = "board_k210"))]
pub const MEMORY_END: usize = 0x8800_0000;
// FIXME: rv64 `sh` and `ls` will crash if stack top > 0x80000000 ???

View File

@ -40,7 +40,7 @@ impl TrapFrame {
///
/// The new thread starts at `entry_addr`.
/// The stack pointer will be set to `sp`.
fn new_user_thread(entry_addr: usize, sp: usize) -> Self {
pub fn new_user_thread(entry_addr: usize, sp: usize) -> Self {
use core::mem::zeroed;
let mut tf: Self = unsafe { zeroed() };
tf.x[2] = sp;
@ -289,9 +289,4 @@ impl Context {
}
.push_at(kstack_top)
}
/// Used for getting the init TrapFrame of a new user context in `sys_exec`.
pub unsafe fn get_init_tf(&self) -> TrapFrame {
(*(self.sp as *const InitStack)).tf.clone()
}
}

View File

@ -9,6 +9,8 @@ use riscv::{addr::*, register::sstatus};
/// Initialize the memory management module
pub fn init(dtb: usize) {
// allow user memory access
// NOTE: In K210 priv v1.9.1, sstatus.SUM is PUM which has opposite meaning!
#[cfg(not(feature = "board_k210"))]
unsafe {
sstatus::set_sum();
}
@ -90,6 +92,8 @@ fn remap_the_kernel(dtb: usize) {
Linear::new(offset),
"bss",
);
// TODO: dtb on rocket chip
#[cfg(not(feature = "board_rocket_chip"))]
ms.push(
dtb,
dtb + super::consts::MAX_DTB_SIZE,

View File

@ -53,9 +53,11 @@ pub extern "C" fn rust_main(hartid: usize, device_tree_paddr: usize) -> ! {
memory::init(device_tree_vaddr);
timer::init();
// FIXME: init driver on u540
#[cfg(not(feature = "board_u540"))]
#[cfg(not(any(feature = "board_u540", feature = "board_rocket_chip")))]
crate::drivers::init(device_tree_vaddr);
#[cfg(not(feature = "board_k210"))]
unsafe {
#[cfg(not(feature = "board_rocket_chip"))]
board::enable_serial_interrupt();
board::init_external_interrupt();
}
@ -108,6 +110,8 @@ global_asm!(
);
#[cfg(target_arch = "riscv32")]
global_asm!(include_str!("boot/entry32.asm"));
#[cfg(target_arch = "riscv64")]
#[cfg(all(target_arch = "riscv64", not(feature = "board_k210")))]
global_asm!(include_str!("boot/entry64.asm"));
#[cfg(feature = "board_k210")]
global_asm!(include_str!("boot/entry_k210.asm"));
global_asm!(include_str!("boot/trap.asm"));

View File

@ -1,96 +1,6 @@
// Copy from Redox consts.rs:
// Because the memory map is so important to not be aliased, it is defined here, in one place
// The lower 256 PML4 entries are reserved for userspace
// Each PML4 entry references up to 512 GB of memory
// The top (511) PML4 is reserved for recursive mapping
// The second from the top (510) PML4 is reserved for the kernel
/// The size of a single PML4
pub const PML4_SIZE: usize = 0x0000_0080_0000_0000;
pub const PML4_MASK: usize = 0x0000_ff80_0000_0000;
/// Offset of recursive paging
pub const RECURSIVE_PAGE_OFFSET: usize = (-(PML4_SIZE as isize)) as usize;
pub const RECURSIVE_PAGE_PML4: usize = (RECURSIVE_PAGE_OFFSET & PML4_MASK) / PML4_SIZE;
/// Offset of kernel
pub const KERNEL_OFFSET: usize = RECURSIVE_PAGE_OFFSET - PML4_SIZE;
pub const KERNEL_PML4: usize = (KERNEL_OFFSET & PML4_MASK) / PML4_SIZE;
pub const KERNEL_SIZE: usize = PML4_SIZE;
/// Offset to kernel heap
pub const KERNEL_HEAP_OFFSET: usize = KERNEL_OFFSET - PML4_SIZE;
pub const KERNEL_HEAP_PML4: usize = (KERNEL_HEAP_OFFSET & PML4_MASK) / PML4_SIZE;
/// Size of kernel heap
pub const KERNEL_HEAP_SIZE: usize = 32 * 1024 * 1024; // 32 MB
pub const MEMORY_OFFSET: usize = 0;
pub const KERNEL_OFFSET: usize = 0xffffff00_00000000;
pub const KERNEL_HEAP_SIZE: usize = 8 * 1024 * 1024; // 8 MB
/// Offset to kernel percpu variables
//TODO: Use 64-bit fs offset to enable this pub const KERNEL_PERCPU_OFFSET: usize = KERNEL_HEAP_OFFSET - PML4_SIZE;
pub const KERNEL_PERCPU_OFFSET: usize = 0xC000_0000;
/// Size of kernel percpu variables
pub const KERNEL_PERCPU_SIZE: usize = 64 * 1024; // 64 KB
/// Offset to user image
pub const USER_OFFSET: usize = 0;
pub const USER_PML4: usize = (USER_OFFSET & PML4_MASK) / PML4_SIZE;
/// Offset to user TCB
pub const USER_TCB_OFFSET: usize = 0xB000_0000;
/// Offset to user arguments
pub const USER_ARG_OFFSET: usize = USER_OFFSET + PML4_SIZE / 2;
/// Offset to user heap
pub const USER_HEAP_OFFSET: usize = USER_OFFSET + PML4_SIZE;
pub const USER_HEAP_PML4: usize = (USER_HEAP_OFFSET & PML4_MASK) / PML4_SIZE;
/// Offset to user grants
pub const USER_GRANT_OFFSET: usize = USER_HEAP_OFFSET + PML4_SIZE;
pub const USER_GRANT_PML4: usize = (USER_GRANT_OFFSET & PML4_MASK) / PML4_SIZE;
/// Offset to user stack
pub const USER_STACK_OFFSET: usize = USER_GRANT_OFFSET + PML4_SIZE;
pub const USER_STACK_PML4: usize = (USER_STACK_OFFSET & PML4_MASK) / PML4_SIZE;
/// Size of user stack
pub const USER_STACK_OFFSET: usize = 0x00008000_00000000 - USER_STACK_SIZE;
pub const USER_STACK_SIZE: usize = 8 * 1024 * 1024; // 8 MB, the default config of Linux
/// Offset to user sigstack
pub const USER_SIGSTACK_OFFSET: usize = USER_STACK_OFFSET + PML4_SIZE;
pub const USER_SIGSTACK_PML4: usize = (USER_SIGSTACK_OFFSET & PML4_MASK) / PML4_SIZE;
/// Size of user sigstack
pub const USER_SIGSTACK_SIZE: usize = 256 * 1024; // 256 KB
/// Offset to user TLS
pub const USER_TLS_OFFSET: usize = USER_SIGSTACK_OFFSET + PML4_SIZE;
pub const USER_TLS_PML4: usize = (USER_TLS_OFFSET & PML4_MASK) / PML4_SIZE;
/// Offset to user temporary image (used when cloning)
pub const USER_TMP_OFFSET: usize = USER_TLS_OFFSET + PML4_SIZE;
pub const USER_TMP_PML4: usize = (USER_TMP_OFFSET & PML4_MASK) / PML4_SIZE;
/// Offset to user temporary heap (used when cloning)
pub const USER_TMP_HEAP_OFFSET: usize = USER_TMP_OFFSET + PML4_SIZE;
pub const USER_TMP_HEAP_PML4: usize = (USER_TMP_HEAP_OFFSET & PML4_MASK) / PML4_SIZE;
/// Offset to user temporary page for grants
pub const USER_TMP_GRANT_OFFSET: usize = USER_TMP_HEAP_OFFSET + PML4_SIZE;
pub const USER_TMP_GRANT_PML4: usize = (USER_TMP_GRANT_OFFSET & PML4_MASK) / PML4_SIZE;
/// Offset to user temporary stack (used when cloning)
pub const USER_TMP_STACK_OFFSET: usize = USER_TMP_GRANT_OFFSET + PML4_SIZE;
pub const USER_TMP_STACK_PML4: usize = (USER_TMP_STACK_OFFSET & PML4_MASK) / PML4_SIZE;
/// Offset to user temporary sigstack (used when cloning)
pub const USER_TMP_SIGSTACK_OFFSET: usize = USER_TMP_STACK_OFFSET + PML4_SIZE;
pub const USER_TMP_SIGSTACK_PML4: usize = (USER_TMP_SIGSTACK_OFFSET & PML4_MASK) / PML4_SIZE;
/// Offset to user temporary tls (used when cloning)
pub const USER_TMP_TLS_OFFSET: usize = USER_TMP_SIGSTACK_OFFSET + PML4_SIZE;
pub const USER_TMP_TLS_PML4: usize = (USER_TMP_TLS_OFFSET & PML4_MASK) / PML4_SIZE;
/// Offset for usage in other temporary pages
pub const USER_TMP_MISC_OFFSET: usize = USER_TMP_TLS_OFFSET + PML4_SIZE;
pub const USER_TMP_MISC_PML4: usize = (USER_TMP_MISC_OFFSET & PML4_MASK) / PML4_SIZE;

View File

@ -1,5 +1,3 @@
use once::*;
pub mod ide;
pub mod keyboard;
pub mod pic;
@ -9,8 +7,6 @@ pub mod serial;
pub mod vga;
pub fn init() {
assert_has_not_been_called!();
// Use IOAPIC instead of PIC
pic::disable();

View File

@ -1,7 +1,6 @@
// Copy from Redox
use log::*;
use once::*;
use spin::Mutex;
use x86_64::instructions::port::Port;
@ -18,8 +17,6 @@ pub fn disable() {
}
pub unsafe fn init() {
assert_has_not_been_called!("pic::init must be called only once");
let mut master = MASTER.lock();
let mut slave = SLAVE.lock();

View File

@ -1,9 +1,7 @@
use log::*;
use once::*;
use x86_64::instructions::port::Port;
pub fn init() {
assert_has_not_been_called!("pit::init must be called only once");
Pit::new(0x40).init(100);
info!("pit: init end");
}

View File

@ -1,4 +1,3 @@
use once::*;
use spin::Mutex;
use uart_16550::SerialPort;
use x86_64::instructions::port::Port;
@ -9,8 +8,6 @@ pub static COM1: Mutex<SerialPort> = Mutex::new(unsafe { SerialPort::new(0x3F8)
pub static COM2: Mutex<SerialPort> = Mutex::new(unsafe { SerialPort::new(0x2F8) });
pub fn init() {
assert_has_not_been_called!("serial::init must be called only once");
COM1.lock().init();
COM2.lock().init();
enable_irq(consts::COM1);

View File

@ -39,10 +39,6 @@ pub struct Cpu {
}
impl Cpu {
pub fn current() -> &'static mut Self {
unsafe { CPUS[super::cpu::id()].as_mut().unwrap() }
}
fn new() -> Self {
Cpu {
gdt: GlobalDescriptorTable::new(),
@ -72,18 +68,9 @@ impl Cpu {
set_cs(KCODE_SELECTOR);
// load TSS
load_tss(TSS_SELECTOR);
// for fast syscall:
// store address of TSS to kernel_gsbase
let mut kernel_gsbase = Msr::new(0xC0000102);
kernel_gsbase.write(&self.tss as *const _ as u64);
}
/// 设置从Ring3跳到Ring0时自动切换栈的地址
///
/// 每次进入用户态前,都要调用此函数,才能保证正确返回内核态
pub fn set_ring0_rsp(&mut self, rsp: usize) {
trace!("gdt.set_ring0_rsp: {:#x}", rsp);
self.tss.privilege_stack_table[0] = VirtAddr::new(rsp as u64);
// store address of TSS to GSBase
let mut gsbase = Msr::new(0xC0000101);
gsbase.write(&self.tss as *const _ as u64);
}
}

View File

@ -10,9 +10,9 @@ pub fn init() {
*flags |= EferFlags::SYSTEM_CALL_EXTENSIONS;
});
let mut star = Msr::new(0xC0000081);
let mut lstar = Msr::new(0xC0000082);
let mut sfmask = Msr::new(0xC0000084);
let mut star = Msr::new(0xC0000081); // legacy mode SYSCALL target
let mut lstar = Msr::new(0xC0000082); // long mode SYSCALL target
let mut sfmask = Msr::new(0xC0000084); // EFLAGS mask for syscall
// flags to clear on syscall
// copy from Linux 5.0

View File

@ -213,9 +213,3 @@ fn invalid_opcode(tf: &mut TrapFrame) {
fn error(tf: &TrapFrame) {
crate::trap::error(tf);
}
#[no_mangle]
pub unsafe extern "C" fn set_return_rsp(tf: *const TrapFrame) {
use crate::arch::gdt::Cpu;
Cpu::current().set_ring0_rsp(tf.add(1) as usize);
}

View File

@ -49,8 +49,10 @@ __alltraps:
.global trap_ret
trap_ret:
# store kernel rsp -> TSS.sp0
mov rdi, rsp
call set_return_rsp
add rdi, 720
mov gs:[4], rdi
# pop fp state offset
pop rcx
@ -104,8 +106,6 @@ syscall_entry:
# - store rip -> rcx
# - load rip
# swap in kernel gs
swapgs
# store user rsp -> scratch at TSS.sp1
mov gs:[12], rsp
# load kernel rsp <- TSS.sp0
@ -119,11 +119,8 @@ syscall_entry:
push 0 # error_code (dummy)
push 0 # trap_num (dummy)
# swap out kernel gs
swapgs
# enable interrupt
# sti
sti
push rax
push rcx
@ -173,8 +170,10 @@ syscall_return:
# disable interrupt
cli
# store kernel rsp -> TSS.sp0
mov rdi, rsp
call set_return_rsp
add rdi, 720
mov gs:[4], rdi
# pop fp state offset
pop rcx

View File

@ -73,7 +73,7 @@ impl TrapFrame {
tf.fpstate_offset = 16; // skip restoring for first time
tf
}
fn new_user_thread(entry_addr: usize, rsp: usize) -> Self {
pub fn new_user_thread(entry_addr: usize, rsp: usize) -> Self {
use crate::arch::gdt;
let mut tf = TrapFrame::default();
tf.cs = gdt::UCODE_SELECTOR.0 as usize;
@ -234,9 +234,4 @@ impl Context {
}
.push_at(kstack_top)
}
/// Called at a new user context
/// To get the init TrapFrame in sys_exec
pub unsafe fn get_init_tf(&self) -> TrapFrame {
(*(self.0 as *const InitStack)).tf.clone()
}
}

View File

@ -2,20 +2,15 @@ use crate::consts::KERNEL_OFFSET;
use bitmap_allocator::BitAlloc;
// Depends on kernel
use super::{BootInfo, MemoryRegionType};
use crate::memory::{active_table, alloc_frame, init_heap, FRAME_ALLOCATOR};
use crate::HEAP_ALLOCATOR;
use alloc::vec::Vec;
use crate::memory::{active_table, init_heap, FRAME_ALLOCATOR};
use log::*;
use once::*;
use rcore_memory::paging::*;
use rcore_memory::PAGE_SIZE;
pub fn init(boot_info: &BootInfo) {
assert_has_not_been_called!("memory::init must be called only once");
init_frame_allocator(boot_info);
init_device_vm_map();
init_heap();
enlarge_heap();
info!("memory: init end");
}
@ -42,30 +37,3 @@ fn init_device_vm_map() {
.map(KERNEL_OFFSET + 0xfee00000, 0xfee00000)
.update();
}
fn enlarge_heap() {
let mut page_table = active_table();
let mut addrs = Vec::new();
let va_offset = KERNEL_OFFSET + 0xe0000000;
for i in 0..16384 {
let page = alloc_frame().unwrap();
let va = KERNEL_OFFSET + 0xe0000000 + page;
if let Some((ref mut addr, ref mut len)) = addrs.last_mut() {
if *addr - PAGE_SIZE == va {
*len += PAGE_SIZE;
*addr -= PAGE_SIZE;
continue;
}
}
addrs.push((va, PAGE_SIZE));
}
for (addr, len) in addrs.into_iter() {
for va in (addr..(addr + len)).step_by(PAGE_SIZE) {
page_table.map(va, va - va_offset).update();
}
info!("Adding {:#X} {:#X} to heap", addr, len);
unsafe {
HEAP_ALLOCATOR.lock().init(addr, len);
}
}
}

View File

@ -15,7 +15,7 @@ pub mod rand;
pub mod syscall;
pub mod timer;
static AP_CAN_INIT: AtomicBool = ATOMIC_BOOL_INIT;
static AP_CAN_INIT: AtomicBool = AtomicBool::new(false);
/// The entry point of kernel
#[no_mangle] // don't mangle the name of this function
@ -40,26 +40,33 @@ pub extern "C" fn _start(boot_info: &'static BootInfo) -> ! {
memory::init(boot_info);
// Now heap is available
// Init GDT
gdt::init();
//get local apic id of cpu
cpu::init();
// Use IOAPIC instead of PIC, use APIC Timer instead of PIT, init serial&keyboard in x86_64
driver::init();
// init pci/bus-based devices ,e.g. Intel 10Gb NIC, ...
crate::drivers::init();
// init cpu scheduler and process manager, and add user shell app in process manager
crate::process::init();
//wake up other CPUs
AP_CAN_INIT.store(true, Ordering::Relaxed);
//call the first main function in kernel.
crate::kmain();
}
/// The entry point for other processors
fn other_start() -> ! {
// Init trap handling.
idt::init();
// init gdt
gdt::init();
// init local apic
cpu::init();
// setup fast syscall in xv6-64
interrupt::fast_syscall::init();
//call the first main function in kernel.
crate::kmain();
}

View File

@ -47,23 +47,21 @@ impl PageTable for ActivePageTable {
fn map(&mut self, addr: usize, target: usize) -> &mut Entry {
let flags = EF::PRESENT | EF::WRITABLE | EF::NO_EXECUTE;
unsafe {
if let Ok(flush) = self.0.map_to(
Page::of_addr(addr),
Frame::of_addr(target),
flags,
&mut FrameAllocatorForX86,
) {
flush.flush();
}
self.0
.map_to(
Page::of_addr(addr),
Frame::of_addr(target),
flags,
&mut FrameAllocatorForX86,
)
.unwrap()
.flush();
}
unsafe { &mut *(get_entry_ptr(addr, 1)) }
}
fn unmap(&mut self, addr: usize) {
// unmap and flush if it is mapped
if let Ok((_, flush)) = self.0.unmap(Page::of_addr(addr)) {
flush.flush();
}
self.0.unmap(Page::of_addr(addr)).unwrap().1.flush();
}
fn get_entry(&mut self, addr: usize) -> Option<&mut Entry> {
@ -238,6 +236,9 @@ impl InactivePageTable for InactivePageTable0 {
fn edit<T>(&mut self, f: impl FnOnce(&mut Self::Active) -> T) -> T {
let target = Cr3::read().0.start_address().as_u64() as usize;
if self.p4_frame == Cr3::read().0 {
return f(&mut active_table());
}
active_table().with_temporary_map(target, |active_table, p4_table: &mut x86PageTable| {
let backup = p4_table[0o777].clone();

View File

@ -48,8 +48,6 @@ pub fn init(_irq: Option<u32>, header: usize, size: usize) -> Arc<AHCIDriver> {
let ahci = AHCI::new(header, size);
let driver = Arc::new(AHCIDriver(Mutex::new(ahci)));
DRIVERS.write().push(driver.clone());
BLK_DRIVERS
.write()
.push(Arc::new(BlockDriver(driver.clone())));
BLK_DRIVERS.write().push(driver.clone());
driver
}

View File

@ -12,8 +12,6 @@ use rcore_memory::paging::PageTable;
use rcore_memory::PAGE_SIZE;
use volatile::Volatile;
use rcore_fs::dev::BlockDevice;
use crate::drivers::BlockDriver;
use crate::memory::active_table;
use crate::sync::SpinNoIrqLock as Mutex;
@ -224,5 +222,5 @@ pub fn virtio_blk_init(node: &Node) {
let driver = Arc::new(driver);
DRIVERS.write().push(driver.clone());
BLK_DRIVERS.write().push(Arc::new(BlockDriver(driver)));
BLK_DRIVERS.write().push(driver);
}

View File

@ -5,7 +5,6 @@ use crate::drivers::{Driver, DRIVERS, NET_DRIVERS};
use crate::memory::active_table;
use alloc::collections::BTreeMap;
use alloc::sync::Arc;
use core::cmp::Ordering;
use pci::*;
use rcore_memory::{paging::PageTable, PAGE_SIZE};
use spin::Mutex;
@ -201,7 +200,7 @@ pub fn detach_driver(loc: &Location) -> bool {
}
pub fn init() {
let mut pci_iter = unsafe { scan_bus(&PortOpsImpl, CSpaceAccessMethod::IO) };
let pci_iter = unsafe { scan_bus(&PortOpsImpl, CSpaceAccessMethod::IO) };
for dev in pci_iter {
info!(
"pci: {:02x}:{:02x}.{} {:#x} {:#x} ({} {}) irq: {}:{:?}",
@ -220,7 +219,7 @@ pub fn init() {
}
pub fn find_device(vendor: u16, product: u16) -> Option<Location> {
let mut pci_iter = unsafe { scan_bus(&PortOpsImpl, CSpaceAccessMethod::IO) };
let pci_iter = unsafe { scan_bus(&PortOpsImpl, CSpaceAccessMethod::IO) };
for dev in pci_iter {
if dev.id.vendor_id == vendor && dev.id.device_id == product {
return Some(dev.loc);

View File

@ -4,7 +4,6 @@ use alloc::string::String;
use core::fmt;
use lazy_static::lazy_static;
use log::*;
use once::*;
use spin::Mutex;
/// Framebuffer information
@ -134,8 +133,6 @@ impl fmt::Debug for Framebuffer {
impl Framebuffer {
fn new(width: u32, height: u32, depth: u32) -> Result<Framebuffer, String> {
assert_has_not_been_called!("Framebuffer::new must be called only once");
let probed_info = super::probe_fb_info(width, height, depth);
match probed_info {

View File

@ -7,7 +7,7 @@ use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address};
use spin::RwLock;
use crate::sync::Condvar;
use rcore_fs::dev::BlockDevice;
use rcore_fs::dev::{self, BlockDevice, DevError};
#[allow(dead_code)]
pub mod block;
@ -72,21 +72,21 @@ pub trait Driver: Send + Sync {
}
// send an ethernet frame, only use it when necessary
fn send(&self, data: &[u8]) -> Option<usize> {
fn send(&self, _data: &[u8]) -> Option<usize> {
unimplemented!("not a net driver")
}
// get mac address from ip address in arp table
fn get_arp(&self, ip: IpAddress) -> Option<EthernetAddress> {
fn get_arp(&self, _ip: IpAddress) -> Option<EthernetAddress> {
unimplemented!("not a net driver")
}
// block related drivers should implement these
fn read_block(&self, block_id: usize, buf: &mut [u8]) -> bool {
fn read_block(&self, _block_id: usize, _buf: &mut [u8]) -> bool {
unimplemented!("not a block driver")
}
fn write_block(&self, block_id: usize, buf: &[u8]) -> bool {
fn write_block(&self, _block_id: usize, _buf: &[u8]) -> bool {
unimplemented!("not a block driver")
}
}
@ -95,19 +95,29 @@ lazy_static! {
// NOTE: RwLock only write when initializing drivers
pub static ref DRIVERS: RwLock<Vec<Arc<Driver>>> = RwLock::new(Vec::new());
pub static ref NET_DRIVERS: RwLock<Vec<Arc<Driver>>> = RwLock::new(Vec::new());
pub static ref BLK_DRIVERS: RwLock<Vec<Arc<BlockDriver>>> = RwLock::new(Vec::new());
pub static ref BLK_DRIVERS: RwLock<Vec<Arc<Driver>>> = RwLock::new(Vec::new());
}
pub struct BlockDriver(Arc<Driver>);
pub struct BlockDriver(pub Arc<Driver>);
impl BlockDevice for BlockDriver {
const BLOCK_SIZE_LOG2: u8 = 9; // 512
fn read_at(&self, block_id: usize, buf: &mut [u8]) -> bool {
self.0.read_block(block_id, buf)
fn read_at(&self, block_id: usize, buf: &mut [u8]) -> dev::Result<()> {
match self.0.read_block(block_id, buf) {
true => Ok(()),
false => Err(DevError),
}
}
fn write_at(&self, block_id: usize, buf: &[u8]) -> bool {
self.0.write_block(block_id, buf)
fn write_at(&self, block_id: usize, buf: &[u8]) -> dev::Result<()> {
match self.0.write_block(block_id, buf) {
true => Ok(()),
false => Err(DevError),
}
}
fn sync(&self) -> dev::Result<()> {
Ok(())
}
}

View File

@ -15,7 +15,6 @@ use smoltcp::wire::EthernetAddress;
use smoltcp::wire::*;
use smoltcp::Result;
use crate::memory::active_table;
use crate::net::SOCKETS;
use crate::sync::FlagsGuard;
use crate::sync::SpinNoIrqLock as Mutex;
@ -203,7 +202,7 @@ pub fn ixgbe_init(
let ip_addrs = [IpCidr::new(IpAddress::v4(10, 0, index as u8, 2), 24)];
let neighbor_cache = NeighborCache::new(BTreeMap::new());
let routes = Routes::new(BTreeMap::new());
let mut iface = EthernetInterfaceBuilder::new(net_driver.clone())
let iface = EthernetInterfaceBuilder::new(net_driver.clone())
.ethernet_addr(ethernet_addr)
.ip_addrs(ip_addrs)
.neighbor_cache(neighbor_cache)

View File

@ -2,7 +2,6 @@ use alloc::alloc::{GlobalAlloc, Layout};
use alloc::format;
use alloc::string::String;
use alloc::sync::Arc;
use alloc::vec::Vec;
use core::mem::size_of;
use core::slice;

View File

@ -19,34 +19,42 @@ impl MemBuf {
}
impl Device for MemBuf {
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Option<usize> {
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
let slice = self.0.read();
let len = buf.len().min(slice.len() - offset);
buf[..len].copy_from_slice(&slice[offset..offset + len]);
Some(len)
Ok(len)
}
fn write_at(&self, offset: usize, buf: &[u8]) -> Option<usize> {
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
let mut slice = self.0.write();
let len = buf.len().min(slice.len() - offset);
slice[offset..offset + len].copy_from_slice(&buf[..len]);
Some(len)
Ok(len)
}
fn sync(&self) -> Result<()> {
Ok(())
}
}
#[cfg(target_arch = "x86_64")]
impl BlockDevice for ide::IDE {
const BLOCK_SIZE_LOG2: u8 = 9;
fn read_at(&self, block_id: usize, buf: &mut [u8]) -> bool {
fn read_at(&self, block_id: usize, buf: &mut [u8]) -> Result<()> {
use core::slice;
assert!(buf.len() >= ide::BLOCK_SIZE);
let buf =
unsafe { slice::from_raw_parts_mut(buf.as_ptr() as *mut u32, ide::BLOCK_SIZE / 4) };
self.read(block_id as u64, 1, buf).is_ok()
self.read(block_id as u64, 1, buf).map_err(|_| DevError)?;
Ok(())
}
fn write_at(&self, block_id: usize, buf: &[u8]) -> bool {
fn write_at(&self, block_id: usize, buf: &[u8]) -> Result<()> {
use core::slice;
assert!(buf.len() >= ide::BLOCK_SIZE);
let buf = unsafe { slice::from_raw_parts(buf.as_ptr() as *mut u32, ide::BLOCK_SIZE / 4) };
self.write(block_id as u64, 1, buf).is_ok()
self.write(block_id as u64, 1, buf).map_err(|_| DevError)?;
Ok(())
}
fn sync(&self) -> Result<()> {
Ok(())
}
}

View File

@ -1,6 +1,7 @@
//! File handle for process
use alloc::{string::String, sync::Arc};
use core::fmt;
use rcore_fs::vfs::{FsError, INode, Metadata, PollStatus, Result};
@ -9,6 +10,7 @@ pub struct FileHandle {
inode: Arc<INode>,
offset: u64,
options: OpenOptions,
pub path: String,
}
#[derive(Debug, Clone)]
@ -27,12 +29,13 @@ pub enum SeekFrom {
}
impl FileHandle {
pub fn new(inode: Arc<INode>, options: OpenOptions) -> Self {
FileHandle {
pub fn new(inode: Arc<INode>, options: OpenOptions, path: String) -> Self {
return FileHandle {
inode,
offset: 0,
options,
}
path,
};
}
pub fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
@ -116,4 +119,19 @@ impl FileHandle {
pub fn io_control(&self, cmd: u32, arg: usize) -> Result<()> {
self.inode.io_control(cmd, arg)
}
pub fn inode(&self) -> Arc<INode> {
self.inode.clone()
}
}
impl fmt::Debug for FileHandle {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
return f
.debug_struct("FileHandle")
.field("offset", &self.offset)
.field("options", &self.options)
.field("path", &self.path)
.finish();
}
}

View File

@ -1,5 +1,6 @@
use core::fmt;
use super::ioctl::*;
use super::FileHandle;
use crate::net::Socket;
use crate::syscall::{SysError, SysResult};
@ -30,13 +31,19 @@ impl FileLike {
Ok(len)
}
pub fn ioctl(&mut self, request: usize, arg1: usize, arg2: usize, arg3: usize) -> SysResult {
match self {
FileLike::File(file) => file.io_control(request as u32, arg1)?,
FileLike::Socket(socket) => {
socket.ioctl(request, arg1, arg2, arg3)?;
match request {
// TODO: place flags & path in FileLike in stead of FileHandle/Socket
FIOCLEX => Ok(0),
_ => {
match self {
FileLike::File(file) => file.io_control(request as u32, arg1)?,
FileLike::Socket(socket) => {
socket.ioctl(request, arg1, arg2, arg3)?;
}
}
Ok(0)
}
}
Ok(0)
}
pub fn poll(&self) -> Result<PollStatus, SysError> {
let status = match self {
@ -53,8 +60,8 @@ impl FileLike {
impl fmt::Debug for FileLike {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
FileLike::File(_) => write!(f, "File"),
FileLike::Socket(_) => write!(f, "Socket"),
FileLike::File(file) => write!(f, "File({:?})", file),
FileLike::Socket(socket) => write!(f, "Socket({:?})", socket),
}
}
}

36
kernel/src/fs/ioctl.rs Normal file
View File

@ -0,0 +1,36 @@
// for IOR and IOW:
// 32bits total, command in lower 16bits, size of the parameter structure in the lower 14 bits of the upper 16 bits
// higher 2 bits: 01 = write, 10 = read
#[cfg(not(target_arch = "mips"))]
pub const TCGETS: usize = 0x5401;
#[cfg(target_arch = "mips")]
pub const TCGETS: usize = 0x540D;
#[cfg(not(target_arch = "mips"))]
pub const TIOCGPGRP: usize = 0x540F;
// _IOR('t', 119, int)
#[cfg(target_arch = "mips")]
pub const TIOCGPGRP: usize = 0x4_004_74_77;
#[cfg(not(target_arch = "mips"))]
pub const TIOCSPGRP: usize = 0x5410;
// _IOW('t', 118, int)
#[cfg(target_arch = "mips")]
pub const TIOCSPGRP: usize = 0x8_004_74_76;
#[cfg(not(target_arch = "mips"))]
pub const TIOCGWINSZ: usize = 0x5413;
// _IOR('t', 104, struct winsize)
#[cfg(target_arch = "mips")]
pub const TIOCGWINSZ: usize = 0x4_008_74_68;
#[cfg(not(target_arch = "mips"))]
pub const FIONCLEX: usize = 0x5450;
#[cfg(target_arch = "mips")]
pub const FIONCLEX: usize = 0x6602;
#[cfg(not(target_arch = "mips"))]
pub const FIOCLEX: usize = 0x5451;
#[cfg(target_arch = "mips")]
pub const FIOCLEX: usize = 0x6601;

View File

@ -1,20 +1,23 @@
use alloc::{sync::Arc, vec::Vec};
use rcore_fs::dev::block_cache::BlockCache;
use rcore_fs::vfs::*;
use rcore_fs_sfs::SimpleFileSystem;
#[cfg(target_arch = "x86_64")]
use crate::arch::driver::ide;
use crate::drivers::BlockDriver;
pub use self::file::*;
pub use self::file_like::*;
pub use self::pipe::Pipe;
pub use self::pseudo::*;
pub use self::stdio::{STDIN, STDOUT};
mod device;
mod file;
mod file_like;
mod ioctl;
mod pipe;
mod pseudo;
mod stdio;
/// Hard link user programs
@ -39,9 +42,15 @@ lazy_static! {
let device = {
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64", target_arch = "x86_64"))]
{
crate::drivers::BLK_DRIVERS.read().iter()
.next().expect("Block device not found")
.clone()
let driver = BlockDriver(
crate::drivers::BLK_DRIVERS
.read().iter()
.next().expect("Block device not found")
.clone()
);
// enable block cache
Arc::new(BlockCache::new(driver, 0x100))
// Arc::new(driver)
}
#[cfg(target_arch = "aarch64")]
{

View File

@ -57,7 +57,6 @@ impl Pipe {
// TODO: better way to provide default impl?
macro_rules! impl_inode {
() => {
fn poll(&self) -> Result<PollStatus> { Err(FsError::NotSupported) }
fn metadata(&self) -> Result<Metadata> { Err(FsError::NotSupported) }
fn set_metadata(&self, _metadata: &Metadata) -> Result<()> { Ok(()) }
fn sync_all(&self) -> Result<()> { Ok(()) }
@ -104,5 +103,41 @@ impl INode for Pipe {
Ok(0)
}
}
fn poll(&self) -> Result<PollStatus> {
let data = self.data.lock();
match self.direction {
PipeEnd::Read => {
if data.buf.len() > 0 {
Ok(PollStatus {
read: true,
write: false,
error: false,
})
} else {
Ok(PollStatus {
read: false,
write: false,
error: false,
})
}
}
PipeEnd::Write => {
if data.buf.len() > 0 {
Ok(PollStatus {
read: false,
write: true,
error: false,
})
} else {
Ok(PollStatus {
read: false,
write: false,
error: false,
})
}
}
}
}
impl_inode!();
}

78
kernel/src/fs/pseudo.rs Normal file
View File

@ -0,0 +1,78 @@
//! Pseudo file system INode
use alloc::{string::String, sync::Arc, vec::Vec};
use core::any::Any;
use rcore_fs::vfs::*;
pub struct Pseudo {
content: Vec<u8>,
type_: FileType,
}
impl Pseudo {
pub fn new(s: &str, type_: FileType) -> Self {
Pseudo {
content: Vec::from(s.as_bytes()),
type_,
}
}
}
// TODO: better way to provide default impl?
macro_rules! impl_inode {
() => {
fn set_metadata(&self, _metadata: &Metadata) -> Result<()> { Ok(()) }
fn sync_all(&self) -> Result<()> { Ok(()) }
fn sync_data(&self) -> Result<()> { Ok(()) }
fn resize(&self, _len: usize) -> Result<()> { Err(FsError::NotSupported) }
fn create(&self, _name: &str, _type_: FileType, _mode: u32) -> Result<Arc<INode>> { Err(FsError::NotDir) }
fn unlink(&self, _name: &str) -> Result<()> { Err(FsError::NotDir) }
fn link(&self, _name: &str, _other: &Arc<INode>) -> Result<()> { Err(FsError::NotDir) }
fn move_(&self, _old_name: &str, _target: &Arc<INode>, _new_name: &str) -> Result<()> { Err(FsError::NotDir) }
fn find(&self, _name: &str) -> Result<Arc<INode>> { Err(FsError::NotDir) }
fn get_entry(&self, _id: usize) -> Result<String> { Err(FsError::NotDir) }
fn io_control(&self, cmd: u32, data: usize) -> Result<()> { Err(FsError::NotSupported) }
fn fs(&self) -> Arc<FileSystem> { unimplemented!() }
fn as_any_ref(&self) -> &Any { self }
};
}
impl INode for Pseudo {
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
if offset >= self.content.len() {
return Ok(0);
}
let len = (self.content.len() - offset).min(buf.len());
buf[..len].copy_from_slice(&self.content[offset..offset + len]);
Ok(len)
}
fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize> {
Err(FsError::NotSupported)
}
fn poll(&self) -> Result<PollStatus> {
Ok(PollStatus {
read: true,
write: false,
error: false,
})
}
fn metadata(&self) -> Result<Metadata> {
Ok(Metadata {
dev: 0,
inode: 0,
size: self.content.len(),
blk_size: 0,
blocks: 0,
atime: Timespec { sec: 0, nsec: 0 },
mtime: Timespec { sec: 0, nsec: 0 },
ctime: Timespec { sec: 0, nsec: 0 },
type_: self.type_,
mode: 0,
nlinks: 0,
uid: 0,
gid: 0,
})
}
impl_inode!();
}

View File

@ -5,6 +5,7 @@ use core::any::Any;
use rcore_fs::vfs::*;
use super::ioctl::*;
use crate::sync::Condvar;
use crate::sync::SpinNoIrqLock as Mutex;
@ -20,16 +21,39 @@ impl Stdin {
self.pushed.notify_one();
}
pub fn pop(&self) -> char {
#[cfg(feature = "board_k210")]
loop {
let ret = self.buf.lock().pop_front();
match ret {
// polling
let c = crate::arch::io::getchar();
if c != '\0' {
return c;
}
}
#[cfg(feature = "board_rocket_chip")]
loop {
let c = crate::arch::io::getchar();
if c != '\0' && c as u8 != 254 {
return c;
}
}
#[cfg(not(any(feature = "board_k210", feature = "board_rocket_chip")))]
loop {
let mut buf_lock = self.buf.lock();
match buf_lock.pop_front() {
Some(c) => return c,
None => self.pushed._wait(),
None => {
self.pushed.wait(buf_lock);
}
}
}
}
pub fn can_read(&self) -> bool {
self.buf.lock().len() > 0
// Currently, rocket-chip implementation rely on htif interface, the serial interrupt DO
// NOT work, so return true always
#[cfg(feature = "board_rocket_chip")]
return true;
#[cfg(not(feature = "board_rocket_chip"))]
return self.buf.lock().len() > 0;
}
}
@ -41,32 +65,6 @@ lazy_static! {
pub static ref STDOUT: Arc<Stdout> = Arc::new(Stdout::default());
}
// 32bits total, command in lower 16bits, size of the parameter structure in the lower 14 bits of the upper 16 bits
// higher 2 bits: 01 = write, 10 = read
#[cfg(not(target_arch = "mips"))]
const TCGETS: u32 = 0x5401;
#[cfg(target_arch = "mips")]
const TCGETS: u32 = 0x540D;
#[cfg(not(target_arch = "mips"))]
const TIOCGPGRP: u32 = 0x540F;
// _IOR('t', 119, int)
#[cfg(target_arch = "mips")]
const TIOCGPGRP: u32 = 0x4_004_74_77;
#[cfg(not(target_arch = "mips"))]
const TIOCSPGRP: u32 = 0x5410;
// _IOW('t', 118, int)
#[cfg(target_arch = "mips")]
const TIOCSPGRP: u32 = 0x8_004_74_76;
#[cfg(not(target_arch = "mips"))]
const TIOCGWINSZ: u32 = 0x5413;
// _IOR('t', 104, struct winsize)
#[cfg(target_arch = "mips")]
const TIOCGWINSZ: u32 = 0x4_008_74_68;
// TODO: better way to provide default impl?
macro_rules! impl_inode {
() => {
@ -82,7 +80,7 @@ macro_rules! impl_inode {
fn find(&self, _name: &str) -> Result<Arc<INode>> { Err(FsError::NotDir) }
fn get_entry(&self, _id: usize) -> Result<String> { Err(FsError::NotDir) }
fn io_control(&self, cmd: u32, data: usize) -> Result<()> {
match cmd {
match cmd as usize {
TCGETS | TIOCGWINSZ | TIOCSPGRP => {
// pretend to be tty
Ok(())

View File

@ -18,7 +18,7 @@ extern crate log;
extern crate lazy_static;
pub use crate::process::{new_kernel_context, processor};
use buddy_system_allocator::LockedHeap;
use buddy_system_allocator::LockedHeapWithRescue;
use rcore_thread::std_thread as thread;
#[macro_use] // print!
@ -65,4 +65,5 @@ pub fn kmain() -> ! {
///
/// It should be defined in memory mod, but in Rust `global_allocator` must be in root mod.
#[global_allocator]
static HEAP_ALLOCATOR: LockedHeap = LockedHeap::empty();
static HEAP_ALLOCATOR: LockedHeapWithRescue =
LockedHeapWithRescue::new(crate::memory::enlarge_heap);

View File

@ -1,14 +1,30 @@
//! Define the FrameAllocator for physical memory
//! x86_64 -- 64GB
//! AARCH64/MIPS/RV -- 1GB
//! K210(rv64) -- 8MB
//! NOTICE:
//! type FrameAlloc = bitmap_allocator::BitAllocXXX
//! KSTACK_SIZE -- 16KB
//!
//! KERNEL_HEAP_SIZE:
//! x86-64 -- 32MB
//! AARCH64/RV64 -- 8MB
//! MIPS/RV32 -- 2MB
//! mipssim/malta(MIPS) -- 10MB
use super::HEAP_ALLOCATOR;
pub use crate::arch::paging::*;
use crate::consts::MEMORY_OFFSET;
use crate::process::process_unsafe;
use crate::consts::{KERNEL_OFFSET, MEMORY_OFFSET};
use crate::sync::SpinNoIrqLock;
use alloc::boxed::Box;
use bitmap_allocator::BitAlloc;
use buddy_system_allocator::LockedHeap;
use buddy_system_allocator::Heap;
use lazy_static::*;
use log::*;
pub use rcore_memory::memory_set::{handler::*, MemoryArea, MemoryAttr};
use rcore_memory::paging::PageTable;
use rcore_memory::*;
use crate::process::current_thread;
pub type MemorySet = rcore_memory::memory_set::MemorySet<InactivePageTable0>;
@ -16,13 +32,21 @@ pub type MemorySet = rcore_memory::memory_set::MemorySet<InactivePageTable0>;
#[cfg(target_arch = "x86_64")]
pub type FrameAlloc = bitmap_allocator::BitAlloc16M;
// RISCV has 1G memory
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
// RISCV, ARM, MIPS has 1G memory
#[cfg(all(
any(
target_arch = "riscv32",
target_arch = "riscv64",
target_arch = "aarch64",
target_arch = "mips"
),
not(feature = "board_k210")
))]
pub type FrameAlloc = bitmap_allocator::BitAlloc1M;
// Raspberry Pi 3 has 1G memory
#[cfg(any(target_arch = "aarch64", target_arch = "mips"))]
pub type FrameAlloc = bitmap_allocator::BitAlloc1M;
// K210 has 8M memory
#[cfg(feature = "board_k210")]
pub type FrameAlloc = bitmap_allocator::BitAlloc4K;
lazy_static! {
pub static ref FRAME_ALLOCATOR: SpinNoIrqLock<FrameAlloc> =
@ -77,17 +101,17 @@ pub fn dealloc_frame(target: usize) {
}
pub struct KernelStack(usize);
const STACK_SIZE: usize = 0x8000;
const KSTACK_SIZE: usize = 0x4000; //16KB
impl KernelStack {
pub fn new() -> Self {
use alloc::alloc::{alloc, Layout};
let bottom =
unsafe { alloc(Layout::from_size_align(STACK_SIZE, STACK_SIZE).unwrap()) } as usize;
unsafe { alloc(Layout::from_size_align(KSTACK_SIZE, KSTACK_SIZE).unwrap()) } as usize;
KernelStack(bottom)
}
pub fn top(&self) -> usize {
self.0 + STACK_SIZE
self.0 + KSTACK_SIZE
}
}
@ -97,7 +121,7 @@ impl Drop for KernelStack {
unsafe {
dealloc(
self.0 as _,
Layout::from_size_align(STACK_SIZE, STACK_SIZE).unwrap(),
Layout::from_size_align(KSTACK_SIZE, KSTACK_SIZE).unwrap(),
);
}
}
@ -108,8 +132,8 @@ impl Drop for KernelStack {
pub fn handle_page_fault(addr: usize) -> bool {
// debug!("page fault @ {:#x}", addr);
// This is safe as long as page fault never happens in page fault handler
unsafe { process_unsafe().vm.handle_page_fault(addr) }
let thread = unsafe { current_thread() };
thread.vm.lock().handle_page_fault(addr)
}
pub fn init_heap() {
@ -123,5 +147,37 @@ pub fn init_heap() {
info!("heap init end");
}
/// Allocator for the rest memory space on NO-MMU case.
pub static MEMORY_ALLOCATOR: LockedHeap = LockedHeap::empty();
pub fn enlarge_heap(heap: &mut Heap) {
info!("Enlarging heap to avoid oom");
let mut page_table = active_table();
let mut addrs = [(0, 0); 32];
let mut addr_len = 0;
#[cfg(target_arch = "x86_64")]
let va_offset = KERNEL_OFFSET + 0xe0000000;
#[cfg(not(target_arch = "x86_64"))]
let va_offset = KERNEL_OFFSET + 0x00e00000;
for i in 0..16384 {
let page = alloc_frame().unwrap();
let va = va_offset + page;
if addr_len > 0 {
let (ref mut addr, ref mut len) = addrs[addr_len - 1];
if *addr - PAGE_SIZE == va {
*len += PAGE_SIZE;
*addr -= PAGE_SIZE;
continue;
}
}
addrs[addr_len] = (va, PAGE_SIZE);
addr_len += 1;
}
for (addr, len) in addrs[..addr_len].into_iter() {
for va in (*addr..(*addr + *len)).step_by(PAGE_SIZE) {
page_table.map(va, va - va_offset).update();
}
info!("Adding {:#X} {:#X} to heap", addr, len);
unsafe {
heap.init(*addr, *len);
}
}
}

View File

@ -4,6 +4,7 @@ use crate::sync::SpinNoIrqLock as Mutex;
use crate::syscall::*;
use crate::util;
use alloc::boxed::Box;
use alloc::fmt::Debug;
use alloc::sync::Arc;
use alloc::vec::Vec;
use bitflags::*;
@ -50,12 +51,12 @@ pub enum Endpoint {
}
/// Common methods that a socket must have
pub trait Socket: Send + Sync {
pub trait Socket: Send + Sync + Debug {
fn read(&self, data: &mut [u8]) -> (SysResult, Endpoint);
fn write(&self, data: &[u8], sendto_endpoint: Option<Endpoint>) -> SysResult;
fn poll(&self) -> (bool, bool, bool); // (in, out, err)
fn connect(&mut self, endpoint: Endpoint) -> SysResult;
fn bind(&mut self, endpoint: Endpoint) -> SysResult {
fn bind(&mut self, _endpoint: Endpoint) -> SysResult {
Err(SysError::EINVAL)
}
fn listen(&mut self) -> SysResult {
@ -73,11 +74,11 @@ pub trait Socket: Send + Sync {
fn remote_endpoint(&self) -> Option<Endpoint> {
None
}
fn setsockopt(&mut self, level: usize, opt: usize, data: &[u8]) -> SysResult {
fn setsockopt(&mut self, _level: usize, _opt: usize, _data: &[u8]) -> SysResult {
warn!("setsockopt is unimplemented");
Ok(0)
}
fn ioctl(&mut self, request: usize, arg1: usize, arg2: usize, arg3: usize) -> SysResult {
fn ioctl(&mut self, _request: usize, _arg1: usize, _arg2: usize, _arg3: usize) -> SysResult {
warn!("ioctl is unimplemented for this socket");
Ok(0)
}
@ -265,9 +266,8 @@ impl Socket for TcpSocketState {
TcpState::SynSent => {
// still connecting
drop(socket);
drop(sockets);
debug!("poll for connection wait");
SOCKET_ACTIVITY._wait();
SOCKET_ACTIVITY.wait(sockets);
}
TcpState::Established => {
break Ok(0);
@ -285,7 +285,7 @@ impl Socket for TcpSocketState {
}
}
fn bind(&mut self, mut endpoint: Endpoint) -> SysResult {
fn bind(&mut self, endpoint: Endpoint) -> SysResult {
if let Endpoint::Ip(mut ip) = endpoint {
if ip.port == 0 {
ip.port = get_ephemeral_port();
@ -357,10 +357,8 @@ impl Socket for TcpSocketState {
return Ok((new_socket, Endpoint::Ip(remote_endpoint)));
}
// avoid deadlock
drop(socket);
drop(sockets);
SOCKET_ACTIVITY._wait();
SOCKET_ACTIVITY.wait(sockets);
}
}
@ -447,9 +445,8 @@ impl Socket for UdpSocketState {
);
}
// avoid deadlock
drop(socket);
SOCKET_ACTIVITY._wait()
SOCKET_ACTIVITY.wait(sockets);
}
}
@ -626,10 +623,8 @@ impl Socket for RawSocketState {
);
}
// avoid deadlock
drop(socket);
drop(sockets);
SOCKET_ACTIVITY._wait()
SOCKET_ACTIVITY.wait(sockets);
}
}
@ -941,7 +936,7 @@ impl Socket for NetlinkSocketState {
let ifaces = NET_DRIVERS.read();
for i in 0..ifaces.len() {
let mut msg = Vec::new();
let mut new_header = NetlinkMessageHeader {
let new_header = NetlinkMessageHeader {
nlmsg_len: 0, // to be determined later
nlmsg_type: NetlinkMessageType::NewLink.into(),
nlmsg_flags: NetlinkMessageFlags::MULTI,
@ -999,7 +994,7 @@ impl Socket for NetlinkSocketState {
let ip_addrs = ifaces[i].get_ip_addresses();
for j in 0..ip_addrs.len() {
let mut msg = Vec::new();
let mut new_header = NetlinkMessageHeader {
let new_header = NetlinkMessageHeader {
nlmsg_len: 0, // to be determined later
nlmsg_type: NetlinkMessageType::NewAddr.into(),
nlmsg_flags: NetlinkMessageFlags::MULTI,
@ -1045,7 +1040,7 @@ impl Socket for NetlinkSocketState {
_ => {}
}
let mut msg = Vec::new();
let mut new_header = NetlinkMessageHeader {
let new_header = NetlinkMessageHeader {
nlmsg_len: 0, // to be determined later
nlmsg_type: NetlinkMessageType::Done.into(),
nlmsg_flags: NetlinkMessageFlags::MULTI,

View File

@ -20,7 +20,7 @@ pub fn init() {
}
}
crate::shell::run_user_shell();
crate::shell::add_user_shell();
info!("process: init end");
}
@ -109,25 +109,13 @@ static PROCESSORS: [Processor; MAX_CPU_NUM] = [
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
];
/// Get current process
pub fn process() -> MutexGuard<'static, Process, SpinNoIrq> {
current_thread().proc.lock()
}
/// Get current process, ignoring its lock
/// Only use this when necessary
pub unsafe fn process_unsafe() -> MutexGuard<'static, Process, SpinNoIrq> {
let thread = current_thread();
thread.proc.force_unlock();
thread.proc.lock()
}
/// Get current thread
///
/// FIXME: It's obviously unsafe to get &mut !
pub fn current_thread() -> &'static mut Thread {
use core::mem::transmute;
let (process, _): (&mut Thread, *const ()) = unsafe { transmute(processor().context()) };
/// `Thread` is a thread-local object.
/// It is safe to call this once, and pass `&mut Thread` as a function argument.
pub unsafe fn current_thread() -> &'static mut Thread {
// trick: force downcast from trait object
let (process, _): (&mut Thread, *const ()) = core::mem::transmute(processor().context());
process
}

View File

@ -13,68 +13,55 @@ use xmas_elf::{
};
use crate::arch::interrupt::{Context, TrapFrame};
use crate::fs::{FileHandle, FileLike, INodeExt, OpenOptions, FOLLOW_MAX_DEPTH};
use crate::memory::{ByFrame, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet};
use crate::net::SOCKETS;
use crate::fs::{FileHandle, FileLike, OpenOptions, FOLLOW_MAX_DEPTH};
use crate::memory::{
ByFrame, Delay, File, GlobalFrameAlloc, KernelStack, MemoryAttr, MemorySet, Read,
};
use crate::sync::{Condvar, SpinNoIrqLock as Mutex};
use super::abi::{self, ProcInitInfo};
use core::mem::uninitialized;
use rcore_fs::vfs::INode;
// TODO: avoid pub
pub struct Thread {
pub context: Context,
pub kstack: KernelStack,
context: Context,
kstack: KernelStack,
/// Kernel performs futex wake when thread exits.
/// Ref: [http://man7.org/linux/man-pages/man2/set_tid_address.2.html]
pub clear_child_tid: usize,
// This is same as `proc.vm`
pub vm: Arc<Mutex<MemorySet>>,
pub proc: Arc<Mutex<Process>>,
}
/// Pid type
/// For strong type separation
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Pid(Option<usize>);
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Pid(usize);
impl Pid {
pub fn uninitialized() -> Self {
Pid(None)
}
/// Return if it was uninitialized before this call
/// When returning true, it usually means this is the first thread
pub fn set_if_uninitialized(&mut self, tid: Tid) -> bool {
if self.0 == None {
self.0 = Some(tid as usize);
true
} else {
false
}
}
pub fn get(&self) -> usize {
self.0.unwrap()
self.0
}
/// Return whether this pid represents the init process
pub fn is_init(&self) -> bool {
self.0 == Some(0)
self.0 == 0
}
}
impl fmt::Display for Pid {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.0 {
Some(pid) => write!(f, "{}", pid),
None => write!(f, "None"),
}
write!(f, "{}", self.0)
}
}
pub struct Process {
// resources
pub vm: MemorySet,
pub vm: Arc<Mutex<MemorySet>>,
pub files: BTreeMap<usize, FileLike>,
pub cwd: String,
pub exec_path: String,
futexes: BTreeMap<usize, Arc<Condvar>>,
// relationship
@ -103,21 +90,9 @@ impl rcore_thread::Context for Thread {
}
fn set_tid(&mut self, tid: Tid) {
// set pid=tid if unspecified
let mut proc = self.proc.lock();
if proc.pid.set_if_uninitialized(tid) {
// first thread in the process
// link to its ppid
if let Some(parent) = &proc.parent {
let mut parent = parent.lock();
parent.children.push(Arc::downgrade(&self.proc));
}
}
// add it to threads
proc.threads.push(tid);
PROCESSES
.write()
.insert(proc.pid.get(), Arc::downgrade(&self.proc));
}
}
@ -126,52 +101,63 @@ impl Thread {
pub unsafe fn new_init() -> Box<Thread> {
Box::new(Thread {
context: Context::null(),
kstack: KernelStack::new(),
clear_child_tid: 0,
// safety: this field will never be used
proc: core::mem::uninitialized(),
// safety: other fields will never be used
..core::mem::uninitialized()
})
}
/// Make a new kernel thread starting from `entry` with `arg`
pub fn new_kernel(entry: extern "C" fn(usize) -> !, arg: usize) -> Box<Thread> {
let vm = MemorySet::new();
let vm_token = vm.token();
let vm = Arc::new(Mutex::new(vm));
let kstack = KernelStack::new();
Box::new(Thread {
context: unsafe { Context::new_kernel_thread(entry, arg, kstack.top(), vm.token()) },
context: unsafe { Context::new_kernel_thread(entry, arg, kstack.top(), vm_token) },
kstack,
clear_child_tid: 0,
vm: vm.clone(),
// TODO: kernel thread should not have a process
proc: Arc::new(Mutex::new(Process {
proc: Process {
vm,
files: BTreeMap::default(),
cwd: String::from("/"),
exec_path: String::new(),
futexes: BTreeMap::default(),
pid: Pid::uninitialized(),
pid: Pid(0),
parent: None,
children: Vec::new(),
threads: Vec::new(),
child_exit: Arc::new(Condvar::new()),
child_exit_code: BTreeMap::new(),
})),
}
.add_to_table(),
})
}
/// Make a new user process from ELF `data`
pub fn new_user(
data: &[u8],
/// Construct virtual memory of a new user process from ELF `data`.
/// Return `(MemorySet, entry_point, ustack_top)`
pub fn new_user_vm(
inode: &Arc<INode>,
exec_path: &str,
mut args: Vec<String>,
envs: Vec<String>,
) -> Box<Thread> {
) -> Result<(MemorySet, usize, usize), &'static str> {
// Read ELF header
// 0x3c0: magic number from ld-musl.so
let mut data: [u8; 0x3c0] = unsafe { uninitialized() };
inode
.read_at(0, &mut data)
.map_err(|_| "failed to read from INode")?;
// Parse ELF
let elf = ElfFile::new(data).expect("failed to read elf");
let elf = ElfFile::new(&data)?;
// Check ELF type
match elf.header.pt2.type_().as_type() {
header::Type::Executable => {}
header::Type::SharedObject => {}
_ => panic!("ELF is not executable or shared object"),
_ => return Err("ELF is not executable or shared object"),
}
// Check ELF arch
@ -184,31 +170,25 @@ impl Thread {
header::Machine::Other(243) => {}
#[cfg(target_arch = "mips")]
header::Machine::Mips => {}
machine @ _ => panic!("invalid elf arch: {:?}", machine),
_ => return Err("invalid ELF arch"),
}
// Check interpreter (for dynamic link)
if let Ok(loader_path) = elf.get_interpreter() {
// assuming absolute path
if let Ok(inode) = crate::fs::ROOT_INODE.lookup_follow(loader_path, FOLLOW_MAX_DEPTH) {
if let Ok(buf) = inode.read_as_vec() {
// Elf loader should not have INTERP
// No infinite loop
args.insert(0, loader_path.into());
args.insert(1, exec_path.into());
args.remove(2);
info!("loader args: {:?}", args);
return Thread::new_user(buf.as_slice(), exec_path, args, envs);
} else {
warn!("loader specified as {} but failed to read", &loader_path);
}
} else {
warn!("loader specified as {} but not found", &loader_path);
}
let inode = crate::fs::ROOT_INODE
.lookup_follow(loader_path, FOLLOW_MAX_DEPTH)
.map_err(|_| "interpreter not found")?;
// modify args for loader
args[0] = exec_path.into();
args.insert(0, loader_path.into());
// Elf loader should not have INTERP
// No infinite loop
return Thread::new_user_vm(&inode, exec_path, args, envs);
}
// Make page table
let mut vm = elf.make_memory_set();
let mut vm = elf.make_memory_set(inode);
// User stack
use crate::consts::{USER_STACK_OFFSET, USER_STACK_SIZE};
@ -217,6 +197,14 @@ impl Thread {
let ustack_top = USER_STACK_OFFSET + USER_STACK_SIZE;
vm.push(
ustack_buttom,
ustack_top - PAGE_SIZE * 4,
MemoryAttr::default().user(),
Delay::new(GlobalFrameAlloc),
"user_stack_delay",
);
// We are going to write init info now. So map the last 4 pages eagerly.
vm.push(
ustack_top - PAGE_SIZE * 4,
ustack_top,
MemoryAttr::default().user(),
ByFrame::new(GlobalFrameAlloc),
@ -246,6 +234,21 @@ impl Thread {
trace!("{:#x?}", vm);
let entry_addr = elf.header.pt2.entry_point() as usize;
Ok((vm, entry_addr, ustack_top))
}
/// Make a new user process from ELF `data`
pub fn new_user(
inode: &Arc<INode>,
exec_path: &str,
args: Vec<String>,
envs: Vec<String>,
) -> Box<Thread> {
let (vm, entry_addr, ustack_top) = Self::new_user_vm(inode, exec_path, args, envs).unwrap();
let vm_token = vm.token();
let vm = Arc::new(Mutex::new(vm));
let kstack = KernelStack::new();
let mut files = BTreeMap::new();
@ -258,6 +261,7 @@ impl Thread {
write: false,
append: false,
},
String::from("stdin"),
)),
);
files.insert(
@ -269,6 +273,7 @@ impl Thread {
write: true,
append: false,
},
String::from("stdout"),
)),
);
files.insert(
@ -280,69 +285,66 @@ impl Thread {
write: true,
append: false,
},
String::from("stderr"),
)),
);
let entry_addr = elf.header.pt2.entry_point() as usize;
Box::new(Thread {
context: unsafe {
Context::new_user_thread(entry_addr, ustack_top, kstack.top(), vm.token())
Context::new_user_thread(entry_addr, ustack_top, kstack.top(), vm_token)
},
kstack,
clear_child_tid: 0,
proc: Arc::new(Mutex::new(Process {
vm: vm.clone(),
proc: Process {
vm,
files,
cwd: String::from("/"),
exec_path: String::from(exec_path),
futexes: BTreeMap::default(),
pid: Pid::uninitialized(),
pid: Pid(0),
parent: None,
children: Vec::new(),
threads: Vec::new(),
child_exit: Arc::new(Condvar::new()),
child_exit_code: BTreeMap::new(),
})),
}
.add_to_table(),
})
}
/// Fork a new process from current one
pub fn fork(&self, tf: &TrapFrame) -> Box<Thread> {
// Clone memory set, make a new page table
let proc = self.proc.lock();
let vm = proc.vm.clone();
let files = proc.files.clone();
let cwd = proc.cwd.clone();
drop(proc);
let parent = Some(self.proc.clone());
debug!("fork: finish clone MemorySet");
// MMU: copy data to the new space
// NoMMU: coping data has been done in `vm.clone()`
for area in vm.iter() {
let data = Vec::<u8>::from(unsafe { area.as_slice() });
unsafe { vm.with(|| area.as_slice_mut().copy_from_slice(data.as_slice())) }
}
debug!("fork: temporary copy data!");
let kstack = KernelStack::new();
let vm = self.vm.lock().clone();
let vm_token = vm.token();
let vm = Arc::new(Mutex::new(vm));
let context = unsafe { Context::new_fork(tf, kstack.top(), vm_token) };
let mut proc = self.proc.lock();
let new_proc = Process {
vm: vm.clone(),
files: proc.files.clone(),
cwd: proc.cwd.clone(),
exec_path: proc.exec_path.clone(),
futexes: BTreeMap::default(),
pid: Pid(0),
parent: Some(self.proc.clone()),
children: Vec::new(),
threads: Vec::new(),
child_exit: Arc::new(Condvar::new()),
child_exit_code: BTreeMap::new(),
}
.add_to_table();
// link to parent
proc.children.push(Arc::downgrade(&new_proc));
Box::new(Thread {
context: unsafe { Context::new_fork(tf, kstack.top(), vm.token()) },
context,
kstack,
clear_child_tid: 0,
proc: Arc::new(Mutex::new(Process {
vm,
files,
cwd,
futexes: BTreeMap::default(),
pid: Pid::uninitialized(),
parent,
children: Vec::new(),
threads: Vec::new(),
child_exit: Arc::new(Condvar::new()),
child_exit_code: BTreeMap::new(),
})),
vm,
proc: new_proc,
})
}
@ -355,33 +357,52 @@ impl Thread {
clear_child_tid: usize,
) -> Box<Thread> {
let kstack = KernelStack::new();
let token = self.proc.lock().vm.token();
let vm_token = self.vm.lock().token();
Box::new(Thread {
context: unsafe { Context::new_clone(tf, stack_top, kstack.top(), token, tls) },
context: unsafe { Context::new_clone(tf, stack_top, kstack.top(), vm_token, tls) },
kstack,
clear_child_tid,
vm: self.vm.clone(),
proc: self.proc.clone(),
})
}
}
impl Process {
pub fn get_free_fd(&self) -> usize {
/// Assign a pid and put itself to global process table.
fn add_to_table(mut self) -> Arc<Mutex<Self>> {
let mut process_table = PROCESSES.write();
// assign pid
let pid = (0..)
.find(|i| match process_table.get(i) {
Some(p) if p.upgrade().is_some() => false,
_ => true,
})
.unwrap();
self.pid = Pid(pid);
// put to process table
let self_ref = Arc::new(Mutex::new(self));
process_table.insert(pid, Arc::downgrade(&self_ref));
self_ref
}
fn get_free_fd(&self) -> usize {
(0..).find(|i| !self.files.contains_key(i)).unwrap()
}
/// Add a file to the process, return its fd.
pub fn add_file(&mut self, file_like: FileLike) -> usize {
let fd = self.get_free_fd();
self.files.insert(fd, file_like);
fd
}
pub fn get_futex(&mut self, uaddr: usize) -> Arc<Condvar> {
if !self.futexes.contains_key(&uaddr) {
self.futexes.insert(uaddr, Arc::new(Condvar::new()));
}
self.futexes.get(&uaddr).unwrap().clone()
}
pub fn clone_for_exec(&mut self, other: &Self) {
self.files = other.files.clone();
self.cwd = other.cwd.clone();
self.pid = other.pid.clone();
self.parent = other.parent.clone();
self.threads = other.threads.clone();
}
}
trait ToMemoryAttr {
@ -391,10 +412,12 @@ trait ToMemoryAttr {
impl ToMemoryAttr for Flags {
fn to_attr(&self) -> MemoryAttr {
let mut flags = MemoryAttr::default().user();
// FIXME: handle readonly
if self.is_execute() {
flags = flags.execute();
}
if !self.is_write() {
flags = flags.readonly();
}
flags
}
}
@ -402,7 +425,7 @@ impl ToMemoryAttr for Flags {
/// Helper functions to process ELF file
trait ElfExt {
/// Generate a MemorySet according to the ELF file.
fn make_memory_set(&self) -> MemorySet;
fn make_memory_set(&self, inode: &Arc<INode>) -> MemorySet;
/// Get interpreter string if it has.
fn get_interpreter(&self) -> Result<&str, &str>;
@ -412,7 +435,7 @@ trait ElfExt {
}
impl ElfExt for ElfFile<'_> {
fn make_memory_set(&self) -> MemorySet {
fn make_memory_set(&self, inode: &Arc<INode>) -> MemorySet {
debug!("creating MemorySet from ELF");
let mut ms = MemorySet::new();
@ -420,33 +443,19 @@ impl ElfExt for ElfFile<'_> {
if ph.get_type() != Ok(Type::Load) {
continue;
}
let virt_addr = ph.virtual_addr() as usize;
let mem_size = ph.mem_size() as usize;
let data = match ph.get_data(self).unwrap() {
SegmentData::Undefined(data) => data,
_ => unreachable!(),
};
// Get target slice
let target = {
ms.push(
virt_addr,
virt_addr + mem_size,
ph.flags().to_attr(),
ByFrame::new(GlobalFrameAlloc),
"elf",
);
unsafe { ::core::slice::from_raw_parts_mut(virt_addr as *mut u8, mem_size) }
};
// Copy data
unsafe {
ms.with(|| {
if data.len() != 0 {
target[..data.len()].copy_from_slice(data);
}
target[data.len()..].iter_mut().for_each(|x| *x = 0);
});
}
ms.push(
ph.virtual_addr() as usize,
ph.virtual_addr() as usize + ph.mem_size() as usize,
ph.flags().to_attr(),
File {
file: INodeForMap(inode.clone()),
mem_start: ph.virtual_addr() as usize,
file_start: ph.offset() as usize,
file_end: ph.offset() as usize + ph.file_size() as usize,
allocator: GlobalFrameAlloc,
},
"elf",
);
}
ms
}
@ -488,3 +497,12 @@ impl ElfExt for ElfFile<'_> {
}
}
}
#[derive(Clone)]
pub struct INodeForMap(pub Arc<INode>);
impl Read for INodeForMap {
fn read_at(&self, offset: usize, buf: &mut [u8]) -> usize {
self.0.read_at(offset, buf).unwrap()
}
}

View File

@ -1,33 +1,51 @@
//! Kernel shell
use crate::drivers::CMDLINE;
use crate::fs::{INodeExt, ROOT_INODE};
use crate::arch::io;
use crate::fs::ROOT_INODE;
use crate::process::*;
use alloc::string::String;
use alloc::vec::Vec;
#[cfg(not(feature = "run_cmdline"))]
pub fn run_user_shell() {
if let Ok(inode) = ROOT_INODE.lookup("busybox") {
let data = inode.read_as_vec().unwrap();
processor().manager().add(Thread::new_user(
data.as_slice(),
"busybox",
vec!["busybox".into(), "sh".into()],
Vec::new(),
));
pub fn add_user_shell() {
// the busybox of alpine linux can not transfer env vars into child process
// Now we use busybox from
// https://raw.githubusercontent.com/docker-library/busybox/82bc0333a9ae148fbb4246bcbff1487b3fc0c510/musl/busybox.tar.xz -O busybox.tar.xz
// This one can transfer env vars!
// Why???
// #[cfg(target_arch = "x86_64")]
// let init_shell="/bin/busybox"; // from alpine linux
//
// #[cfg(not(target_arch = "x86_64"))]
let init_shell = "/busybox"; //from docker-library
#[cfg(target_arch = "x86_64")]
let init_envs =
vec!["PATH=/usr/sbin:/usr/bin:/sbin:/bin:/usr/x86_64-alpine-linux-musl/bin".into()];
#[cfg(not(target_arch = "x86_64"))]
let init_envs = Vec::new();
let init_args = vec!["busybox".into(), "ash".into()];
if let Ok(inode) = ROOT_INODE.lookup(init_shell) {
processor()
.manager()
.add(Thread::new_user(&inode, init_shell, init_args, init_envs));
} else {
processor().manager().add(Thread::new_kernel(shell, 0));
}
}
#[cfg(feature = "run_cmdline")]
pub fn run_user_shell() {
pub fn add_user_shell() {
use crate::drivers::CMDLINE;
let cmdline = CMDLINE.read();
let inode = ROOT_INODE.lookup(&cmdline).unwrap();
let data = inode.read_as_vec().unwrap();
processor().manager().add(Thread::new_user(
data.as_slice(),
&inode,
&cmdline,
cmdline.split(' ').map(|s| s.into()).collect(),
Vec::new(),
));
@ -45,16 +63,14 @@ pub extern "C" fn shell(_arg: usize) -> ! {
continue;
}
let name = cmd.trim().split(' ').next().unwrap();
if let Ok(file) = ROOT_INODE.lookup(name) {
let data = file.read_as_vec().unwrap();
let _pid = processor().manager().add(Thread::new_user(
data.as_slice(),
if let Ok(inode) = ROOT_INODE.lookup(name) {
let _tid = processor().manager().add(Thread::new_user(
&inode,
&cmd,
cmd.split(' ').map(|s| s.into()).collect(),
Vec::new(),
));
// TODO: wait until process exits, or use user land shell completely
//unsafe { thread::JoinHandle::<()>::_of(pid) }.join().unwrap();
} else {
println!("Program not exist");
}

View File

@ -15,6 +15,7 @@ impl Condvar {
}
/// Park current thread and wait for this condvar to be notified.
#[deprecated(note = "this may leads to lost wakeup problem. please use `wait` instead.")]
pub fn _wait(&self) {
// The condvar might be notified between adding to queue and thread parking.
// So park current thread before wait queue lock is freed.
@ -25,6 +26,7 @@ impl Condvar {
});
}
#[deprecated(note = "this may leads to lost wakeup problem. please use `wait` instead.")]
pub fn wait_any(condvars: &[&Condvar]) {
let token = Arc::new(thread::current());
// Avoid racing in the same way as the function above
@ -40,19 +42,23 @@ impl Condvar {
});
}
pub fn add_to_wait_queue(&self) -> MutexGuard<VecDeque<Arc<thread::Thread>>, SpinNoIrq> {
fn add_to_wait_queue(&self) -> MutexGuard<VecDeque<Arc<thread::Thread>>, SpinNoIrq> {
let mut lock = self.wait_queue.lock();
lock.push_back(Arc::new(thread::current()));
return lock;
}
/// Park current thread and wait for this condvar to be notified.
pub fn wait<'a, T, S>(&self, guard: MutexGuard<'a, T, S>) -> MutexGuard<'a, T, S>
where
S: MutexSupport,
{
let mutex = guard.mutex;
drop(guard);
self._wait();
let lock = self.add_to_wait_queue();
thread::park_action(move || {
drop(lock);
drop(guard);
});
mutex.lock()
}
@ -80,7 +86,4 @@ impl Condvar {
}
count
}
pub fn _clear(&self) {
self.wait_queue.lock().clear();
}
}

View File

@ -3,53 +3,56 @@ use super::*;
use rcore_memory::memory_set::handler::Linear;
use rcore_memory::memory_set::MemoryAttr;
/// Allocate this PCI device to user space
/// The kernel driver using the PCI device will be unloaded
#[cfg(target_arch = "x86_64")]
pub fn sys_map_pci_device(vendor: usize, product: usize) -> SysResult {
use crate::drivers::bus::pci;
info!(
"map_pci_device: vendor: {:x}, product: {:x}",
vendor, product
);
impl Syscall<'_> {
/// Allocate this PCI device to user space
/// The kernel driver using the PCI device will be unloaded
#[cfg(target_arch = "x86_64")]
pub fn sys_map_pci_device(&mut self, vendor: usize, product: usize) -> SysResult {
use crate::drivers::bus::pci;
info!(
"map_pci_device: vendor: {:x}, product: {:x}",
vendor, product
);
let tag = pci::find_device(vendor as u16, product as u16).ok_or(SysError::ENOENT)?;
if pci::detach_driver(&tag) {
info!("Kernel driver detached");
let tag = pci::find_device(vendor as u16, product as u16).ok_or(SysError::ENOENT)?;
if pci::detach_driver(&tag) {
info!("Kernel driver detached");
}
// Get BAR0 memory
let (base, len) = pci::get_bar0_mem(tag).ok_or(SysError::ENOENT)?;
let virt_addr = self.vm().find_free_area(0, len);
let attr = MemoryAttr::default().user();
self.vm().push(
virt_addr,
virt_addr + len,
attr,
Linear::new(base as isize - virt_addr as isize),
"pci",
);
Ok(virt_addr)
}
// Get BAR0 memory
let (base, len) = pci::get_bar0_mem(tag).ok_or(SysError::ENOENT)?;
let mut proc = process();
let virt_addr = proc.vm.find_free_area(0, len);
let attr = MemoryAttr::default().user();
proc.vm.push(
virt_addr,
virt_addr + len,
attr,
Linear::new(base as isize - virt_addr as isize),
"pci",
);
Ok(virt_addr)
}
#[cfg(not(target_arch = "x86_64"))]
pub fn sys_map_pci_device(vendor: usize, product: usize) -> SysResult {
Err(SysError::ENOSYS)
}
/// Get start physical addresses of frames
/// mapped to a list of virtual addresses.
pub fn sys_get_paddr(vaddrs: *const u64, paddrs: *mut u64, count: usize) -> SysResult {
let mut proc = process();
proc.vm.check_read_array(vaddrs, count)?;
proc.vm.check_write_array(paddrs, count)?;
let vaddrs = unsafe { slice::from_raw_parts(vaddrs, count) };
let paddrs = unsafe { slice::from_raw_parts_mut(paddrs, count) };
for i in 0..count {
let paddr = proc.vm.translate(vaddrs[i] as usize).unwrap_or(0);
paddrs[i] = paddr as u64;
#[cfg(not(target_arch = "x86_64"))]
pub fn sys_map_pci_device(&mut self, vendor: usize, product: usize) -> SysResult {
Err(SysError::ENOSYS)
}
/// Get start physical addresses of frames
/// mapped to a list of virtual addresses.
pub fn sys_get_paddr(
&mut self,
vaddrs: *const u64,
paddrs: *mut u64,
count: usize,
) -> SysResult {
let vaddrs = unsafe { self.vm().check_read_array(vaddrs, count)? };
let paddrs = unsafe { self.vm().check_write_array(paddrs, count)? };
for i in 0..count {
let paddr = self.vm().translate(vaddrs[i] as usize).unwrap_or(0);
paddrs[i] = paddr as u64;
}
Ok(0)
}
Ok(0)
}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
use rcore_memory::memory_set::handler::{ByFrame, Delay};
use rcore_memory::memory_set::handler::{Delay, File};
use rcore_memory::memory_set::MemoryAttr;
use rcore_memory::paging::PageTable;
use rcore_memory::Page;
@ -8,108 +8,95 @@ use crate::memory::GlobalFrameAlloc;
use super::*;
pub fn sys_mmap(
mut addr: usize,
len: usize,
prot: usize,
flags: usize,
fd: usize,
offset: usize,
) -> SysResult {
let prot = MmapProt::from_bits_truncate(prot);
let flags = MmapFlags::from_bits_truncate(flags);
info!(
"mmap: addr={:#x}, size={:#x}, prot={:?}, flags={:?}, fd={}, offset={:#x}",
addr, len, prot, flags, fd, offset
);
let mut proc = process();
if addr == 0 {
// although NULL can be a valid address
// but in C, NULL is regarded as allocation failure
// so just skip it
addr = PAGE_SIZE;
}
if flags.contains(MmapFlags::FIXED) {
// we have to map it to addr, so remove the old mapping first
proc.vm.pop_with_split(addr, addr + len);
} else {
addr = proc.vm.find_free_area(addr, len);
}
if flags.contains(MmapFlags::ANONYMOUS) {
if flags.contains(MmapFlags::SHARED) {
return Err(SysError::EINVAL);
}
proc.vm.push(
addr,
addr + len,
prot.to_attr(),
Delay::new(GlobalFrameAlloc),
"mmap_anon",
impl Syscall<'_> {
pub fn sys_mmap(
&mut self,
mut addr: usize,
len: usize,
prot: usize,
flags: usize,
fd: usize,
offset: usize,
) -> SysResult {
let prot = MmapProt::from_bits_truncate(prot);
let flags = MmapFlags::from_bits_truncate(flags);
info!(
"mmap: addr={:#x}, size={:#x}, prot={:?}, flags={:?}, fd={}, offset={:#x}",
addr, len, prot, flags, fd, offset
);
return Ok(addr);
} else {
// only check
let _ = proc.get_file(fd)?;
// TODO: delay mmap file
proc.vm.push(
addr,
addr + len,
prot.to_attr(),
ByFrame::new(GlobalFrameAlloc),
"mmap_file",
let mut proc = self.process();
if addr == 0 {
// although NULL can be a valid address
// but in C, NULL is regarded as allocation failure
// so just skip it
addr = PAGE_SIZE;
}
if flags.contains(MmapFlags::FIXED) {
// we have to map it to addr, so remove the old mapping first
self.vm().pop_with_split(addr, addr + len);
} else {
addr = self.vm().find_free_area(addr, len);
}
if flags.contains(MmapFlags::ANONYMOUS) {
if flags.contains(MmapFlags::SHARED) {
return Err(SysError::EINVAL);
}
self.vm().push(
addr,
addr + len,
prot.to_attr(),
Delay::new(GlobalFrameAlloc),
"mmap_anon",
);
return Ok(addr);
} else {
let inode = proc.get_file(fd)?.inode();
self.vm().push(
addr,
addr + len,
prot.to_attr(),
File {
file: INodeForMap(inode),
mem_start: addr,
file_start: offset,
file_end: offset + len,
allocator: GlobalFrameAlloc,
},
"mmap_file",
);
return Ok(addr);
}
}
pub fn sys_mprotect(&mut self, addr: usize, len: usize, prot: usize) -> SysResult {
let prot = MmapProt::from_bits_truncate(prot);
info!(
"mprotect: addr={:#x}, size={:#x}, prot={:?}",
addr, len, prot
);
let data = unsafe { slice::from_raw_parts_mut(addr as *mut u8, len) };
let file = proc.get_file(fd)?;
let read_len = file.read_at(offset, data)?;
if read_len != data.len() {
// use count() to consume the iterator
data[read_len..].iter_mut().map(|x| *x = 0).count();
let attr = prot.to_attr();
// FIXME: properly set the attribute of the area
// now some mut ptr check is fault
let vm = self.vm();
let memory_area = vm
.iter()
.find(|area| area.is_overlap_with(addr, addr + len));
if memory_area.is_none() {
return Err(SysError::ENOMEM);
}
return Ok(addr);
Ok(0)
}
pub fn sys_munmap(&mut self, addr: usize, len: usize) -> SysResult {
info!("munmap addr={:#x}, size={:#x}", addr, len);
self.vm().pop_with_split(addr, addr + len);
Ok(0)
}
}
pub fn sys_mprotect(addr: usize, len: usize, prot: usize) -> SysResult {
let prot = MmapProt::from_bits_truncate(prot);
info!(
"mprotect: addr={:#x}, size={:#x}, prot={:?}",
addr, len, prot
);
let mut proc = process();
let attr = prot.to_attr();
// FIXME: properly set the attribute of the area
// now some mut ptr check is fault
let memory_area = proc
.vm
.iter()
.find(|area| area.is_overlap_with(addr, addr + len));
if memory_area.is_none() {
return Err(SysError::ENOMEM);
}
proc.vm.edit(|pt| {
for page in Page::range_of(addr, addr + len) {
let entry = pt
.get_entry(page.start_address())
.expect("failed to get entry");
attr.apply(entry);
}
});
Ok(0)
}
pub fn sys_munmap(addr: usize, len: usize) -> SysResult {
info!("munmap addr={:#x}, size={:#x}", addr, len);
let mut proc = process();
proc.vm.pop_with_split(addr, addr + len);
Ok(0)
}
bitflags! {
pub struct MmapProt: usize {
/// Data cannot be accessed

View File

@ -4,121 +4,185 @@ use crate::consts::USER_STACK_SIZE;
use core::mem::size_of;
use core::sync::atomic::{AtomicI32, Ordering};
pub fn sys_arch_prctl(code: i32, addr: usize, tf: &mut TrapFrame) -> SysResult {
const ARCH_SET_FS: i32 = 0x1002;
match code {
#[cfg(target_arch = "x86_64")]
ARCH_SET_FS => {
info!("sys_arch_prctl: set FS to {:#x}", addr);
tf.fsbase = addr;
Ok(0)
}
_ => Err(SysError::EINVAL),
}
}
pub fn sys_uname(buf: *mut u8) -> SysResult {
info!("sched_uname: buf: {:?}", buf);
let offset = 65;
let strings = ["rCore", "orz", "0.1.0", "1", "machine", "domain"];
let proc = process();
proc.vm.check_write_array(buf, strings.len() * offset)?;
for i in 0..strings.len() {
unsafe {
util::write_cstr(buf.add(i * offset), &strings[i]);
}
}
Ok(0)
}
pub fn sys_sched_getaffinity(pid: usize, size: usize, mask: *mut u32) -> SysResult {
info!(
"sched_getaffinity: pid: {}, size: {}, mask: {:?}",
pid, size, mask
);
let proc = process();
proc.vm.check_write_array(mask, size / size_of::<u32>())?;
// we only have 4 cpu at most.
// so just set it.
unsafe {
*mask = 0b1111;
}
Ok(0)
}
pub fn sys_sysinfo(sys_info: *mut SysInfo) -> SysResult {
let proc = process();
proc.vm.check_write_ptr(sys_info)?;
let sysinfo = SysInfo::default();
unsafe { *sys_info = sysinfo };
Ok(0)
}
pub fn sys_futex(uaddr: usize, op: u32, val: i32, timeout: *const TimeSpec) -> SysResult {
info!(
"futex: [{}] uaddr: {:#x}, op: {:#x}, val: {}, timeout_ptr: {:?}",
thread::current().id(),
uaddr,
op,
val,
timeout
);
// if op & OP_PRIVATE == 0 {
// unimplemented!("futex only support process-private");
// return Err(SysError::ENOSYS);
// }
if uaddr % size_of::<u32>() != 0 {
return Err(SysError::EINVAL);
}
process().vm.check_write_ptr(uaddr as *mut AtomicI32)?;
let atomic = unsafe { &mut *(uaddr as *mut AtomicI32) };
let _timeout = if timeout.is_null() {
None
} else {
process().vm.check_read_ptr(timeout)?;
Some(unsafe { *timeout })
};
const OP_WAIT: u32 = 0;
const OP_WAKE: u32 = 1;
const OP_PRIVATE: u32 = 128;
let queue = process().get_futex(uaddr);
match op & 0xf {
OP_WAIT => {
if atomic.load(Ordering::Acquire) != val {
return Err(SysError::EAGAIN);
impl Syscall<'_> {
#[cfg(target_arch = "x86_64")]
pub fn sys_arch_prctl(&mut self, code: i32, addr: usize) -> SysResult {
const ARCH_SET_FS: i32 = 0x1002;
match code {
ARCH_SET_FS => {
info!("sys_arch_prctl: set FSBASE to {:#x}", addr);
self.tf.fsbase = addr;
Ok(0)
}
// FIXME: support timeout
queue._wait();
Ok(0)
_ => Err(SysError::EINVAL),
}
OP_WAKE => {
let woken_up_count = queue.notify_n(val as usize);
Ok(woken_up_count)
}
pub fn sys_uname(&mut self, buf: *mut u8) -> SysResult {
info!("uname: buf: {:?}", buf);
let offset = 65;
let strings = ["rCore", "orz", "0.1.0", "1", "machine", "domain"];
let buf = unsafe { self.vm().check_write_array(buf, strings.len() * offset)? };
for i in 0..strings.len() {
unsafe {
util::write_cstr(&mut buf[i * offset], &strings[i]);
}
}
_ => {
warn!("unsupported futex operation: {}", op);
Err(SysError::ENOSYS)
Ok(0)
}
pub fn sys_sched_getaffinity(&mut self, pid: usize, size: usize, mask: *mut u32) -> SysResult {
info!(
"sched_getaffinity: pid: {}, size: {}, mask: {:?}",
pid, size, mask
);
let mask = unsafe { self.vm().check_write_array(mask, size / size_of::<u32>())? };
// we only have 4 cpu at most.
// so just set it.
mask[0] = 0b1111;
Ok(0)
}
pub fn sys_sysinfo(&mut self, sys_info: *mut SysInfo) -> SysResult {
let sys_info = unsafe { self.vm().check_write_ptr(sys_info)? };
let sysinfo = SysInfo::default();
*sys_info = sysinfo;
Ok(0)
}
pub fn sys_futex(
&mut self,
uaddr: usize,
op: u32,
val: i32,
timeout: *const TimeSpec,
) -> SysResult {
info!(
"futex: [{}] uaddr: {:#x}, op: {:#x}, val: {}, timeout_ptr: {:?}",
thread::current().id(),
uaddr,
op,
val,
timeout
);
// if op & OP_PRIVATE == 0 {
// unimplemented!("futex only support process-private");
// return Err(SysError::ENOSYS);
// }
if uaddr % size_of::<u32>() != 0 {
return Err(SysError::EINVAL);
}
let atomic = unsafe { self.vm().check_write_ptr(uaddr as *mut AtomicI32)? };
let _timeout = if timeout.is_null() {
None
} else {
Some(unsafe { *self.vm().check_read_ptr(timeout)? })
};
const OP_WAIT: u32 = 0;
const OP_WAKE: u32 = 1;
const OP_PRIVATE: u32 = 128;
let mut proc = self.process();
let queue = proc.get_futex(uaddr);
match op & 0xf {
OP_WAIT => {
if atomic.load(Ordering::Acquire) != val {
return Err(SysError::EAGAIN);
}
// FIXME: support timeout
queue.wait(proc);
Ok(0)
}
OP_WAKE => {
let woken_up_count = queue.notify_n(val as usize);
Ok(woken_up_count)
}
_ => {
warn!("unsupported futex operation: {}", op);
Err(SysError::ENOSYS)
}
}
}
pub fn sys_reboot(&mut self, _magic: u32, _magic2: u32, cmd: u32, _arg: *const u8) -> SysResult {
// we will skip verifying magic
if cmd == LINUX_REBOOT_CMD_HALT {
unsafe {
cpu::exit_in_qemu(1);
}
}
Ok(0)
}
pub fn sys_prlimit64(
&mut self,
pid: usize,
resource: usize,
new_limit: *const RLimit,
old_limit: *mut RLimit,
) -> SysResult {
info!(
"prlimit64: pid: {}, resource: {}, new_limit: {:x?}, old_limit: {:x?}",
pid, resource, new_limit, old_limit
);
match resource {
RLIMIT_STACK => {
if !old_limit.is_null() {
let old_limit = unsafe { self.vm().check_write_ptr(old_limit)? };
*old_limit = RLimit {
cur: USER_STACK_SIZE as u64,
max: USER_STACK_SIZE as u64,
};
}
Ok(0)
}
RLIMIT_NOFILE => {
if !old_limit.is_null() {
let old_limit = unsafe { self.vm().check_write_ptr(old_limit)? };
*old_limit = RLimit {
cur: 1024,
max: 1024,
};
}
Ok(0)
}
RLIMIT_RSS | RLIMIT_AS => {
if !old_limit.is_null() {
let old_limit = unsafe { self.vm().check_write_ptr(old_limit)? };
// 1GB
*old_limit = RLimit {
cur: 1024 * 1024 * 1024,
max: 1024 * 1024 * 1024,
};
}
Ok(0)
}
_ => Err(SysError::ENOSYS),
}
}
pub fn sys_getrandom(&mut self, buf: *mut u8, len: usize, _flag: u32) -> SysResult {
//info!("getrandom: buf: {:?}, len: {:?}, falg {:?}", buf, len,flag);
let slice = unsafe { self.vm().check_write_array(buf, len)? };
let mut i = 0;
for elm in slice {
unsafe {
*elm = i + crate::trap::TICK as u8;
}
i += 1;
}
Ok(len)
}
}
const LINUX_REBOOT_CMD_HALT: u32 = 0xcdef0123;
pub fn sys_reboot(_magic: u32, magic2: u32, cmd: u32, _arg: *const u8) -> SysResult {
// we will skip verifying magic
if cmd == LINUX_REBOOT_CMD_HALT {
unsafe {
cpu::exit_in_qemu(1);
}
}
Ok(0)
}
#[repr(C)]
#[derive(Debug, Default)]
@ -142,59 +206,6 @@ const RLIMIT_RSS: usize = 5;
const RLIMIT_NOFILE: usize = 7;
const RLIMIT_AS: usize = 9;
pub fn sys_prlimit64(
pid: usize,
resource: usize,
new_limit: *const RLimit,
old_limit: *mut RLimit,
) -> SysResult {
let proc = process();
info!(
"prlimit64: pid: {}, resource: {}, new_limit: {:x?}, old_limit: {:x?}",
pid, resource, new_limit, old_limit
);
match resource {
RLIMIT_STACK => {
if !old_limit.is_null() {
proc.vm.check_write_ptr(old_limit)?;
unsafe {
*old_limit = RLimit {
cur: USER_STACK_SIZE as u64,
max: USER_STACK_SIZE as u64,
};
}
}
Ok(0)
}
RLIMIT_NOFILE => {
if !old_limit.is_null() {
proc.vm.check_write_ptr(old_limit)?;
unsafe {
*old_limit = RLimit {
cur: 1024,
max: 1024,
};
}
}
Ok(0)
}
RLIMIT_RSS | RLIMIT_AS => {
if !old_limit.is_null() {
proc.vm.check_write_ptr(old_limit)?;
unsafe {
// 1GB
*old_limit = RLimit {
cur: 1024 * 1024 * 1024,
max: 1024 * 1024 * 1024,
};
}
}
Ok(0)
}
_ => Err(SysError::ENOSYS),
}
}
#[repr(C)]
#[derive(Debug, Default)]
pub struct RLimit {

View File

@ -10,8 +10,9 @@ use rcore_memory::VMError;
use crate::arch::cpu;
use crate::arch::interrupt::TrapFrame;
use crate::arch::syscall::*;
use crate::memory::MemorySet;
use crate::process::*;
use crate::sync::Condvar;
use crate::sync::{Condvar, MutexGuard, SpinNoIrq};
use crate::thread;
use crate::util;
@ -31,428 +32,382 @@ mod net;
mod proc;
mod time;
use alloc::collections::BTreeMap;
use spin::Mutex;
#[cfg(feature = "profile")]
lazy_static! {
static ref SYSCALL_TIMING: Mutex<BTreeMap<usize, i64>> = Mutex::new(BTreeMap::new());
}
/// System call dispatcher
// This #[deny(unreachable_patterns)] checks if each match arm is defined
// See discussion in https://github.com/oscourse-tsinghua/rcore_plus/commit/17e644e54e494835f1a49b34b80c2c4f15ed0dbe.
#[deny(unreachable_patterns)]
pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
let cid = cpu::id();
let pid = { process().pid.clone() };
let tid = processor().tid();
if !pid.is_init() {
// we trust pid 0 process
debug!("{}:{}:{} syscall id {} begin", cid, pid, tid, id);
}
// use platform-specific syscal numbers
// See https://filippo.io/linux-syscall-table/
// And https://fedora.juszkiewicz.com.pl/syscalls.html.
let ret = match id {
// 0
SYS_READ => sys_read(args[0], args[1] as *mut u8, args[2]),
SYS_WRITE => sys_write(args[0], args[1] as *const u8, args[2]),
SYS_CLOSE => sys_close(args[0]),
SYS_FSTAT => sys_fstat(args[0], args[1] as *mut Stat),
SYS_LSEEK => sys_lseek(args[0], args[1] as i64, args[2] as u8),
SYS_MMAP => sys_mmap(args[0], args[1], args[2], args[3], args[4], args[5]),
// 10
SYS_MPROTECT => sys_mprotect(args[0], args[1], args[2]),
SYS_MUNMAP => sys_munmap(args[0], args[1]),
SYS_BRK => {
warn!("sys_brk is unimplemented, return -1");
Err(SysError::ENOMEM)
}
SYS_RT_SIGACTION => {
warn!("sys_sigaction is unimplemented");
Ok(0)
}
SYS_RT_SIGPROCMASK => {
warn!("sys_sigprocmask is unimplemented");
Ok(0)
}
SYS_IOCTL => sys_ioctl(args[0], args[1], args[2], args[3], args[4]),
SYS_PREAD64 => sys_pread(args[0], args[1] as *mut u8, args[2], args[3]),
SYS_PWRITE64 => sys_pwrite(args[0], args[1] as *const u8, args[2], args[3]),
SYS_READV => sys_readv(args[0], args[1] as *const IoVec, args[2]),
// 20
SYS_WRITEV => sys_writev(args[0], args[1] as *const IoVec, args[2]),
SYS_SCHED_YIELD => sys_yield(),
SYS_MADVISE => {
warn!("sys_madvise is unimplemented");
Ok(0)
}
SYS_NANOSLEEP => sys_nanosleep(args[0] as *const TimeSpec),
SYS_SETITIMER => {
warn!("sys_setitimer is unimplemented");
Ok(0)
}
SYS_GETPID => sys_getpid(),
// 40
SYS_SENDFILE => sys_sendfile(args[0], args[1], args[2] as *mut usize, args[3]),
SYS_SOCKET => sys_socket(args[0], args[1], args[2]),
SYS_CONNECT => sys_connect(args[0], args[1] as *const SockAddr, args[2]),
SYS_ACCEPT => sys_accept(args[0], args[1] as *mut SockAddr, args[2] as *mut u32),
SYS_SENDTO => sys_sendto(
args[0],
args[1] as *const u8,
args[2],
args[3],
args[4] as *const SockAddr,
args[5],
),
SYS_RECVFROM => sys_recvfrom(
args[0],
args[1] as *mut u8,
args[2],
args[3],
args[4] as *mut SockAddr,
args[5] as *mut u32,
),
// SYS_SENDMSG => sys_sendmsg(),
SYS_RECVMSG => sys_recvmsg(args[0], args[1] as *mut MsgHdr, args[2]),
SYS_SHUTDOWN => sys_shutdown(args[0], args[1]),
SYS_BIND => sys_bind(args[0], args[1] as *const SockAddr, args[2]),
// 50
SYS_LISTEN => sys_listen(args[0], args[1]),
SYS_GETSOCKNAME => sys_getsockname(args[0], args[1] as *mut SockAddr, args[2] as *mut u32),
SYS_GETPEERNAME => sys_getpeername(args[0], args[1] as *mut SockAddr, args[2] as *mut u32),
SYS_SETSOCKOPT => sys_setsockopt(args[0], args[1], args[2], args[3] as *const u8, args[4]),
SYS_GETSOCKOPT => sys_getsockopt(
args[0],
args[1],
args[2],
args[3] as *mut u8,
args[4] as *mut u32,
),
SYS_CLONE => sys_clone(
args[0],
args[1],
args[2] as *mut u32,
args[3] as *mut u32,
args[4],
tf,
),
SYS_EXECVE => sys_exec(
args[0] as *const u8,
args[1] as *const *const u8,
args[2] as *const *const u8,
tf,
),
// 60
SYS_EXIT => sys_exit(args[0] as usize),
SYS_WAIT4 => sys_wait4(args[0] as isize, args[1] as *mut i32), // TODO: wait4
SYS_KILL => sys_kill(args[0], args[1]),
SYS_UNAME => sys_uname(args[0] as *mut u8),
SYS_FCNTL => {
warn!("sys_fcntl is unimplemented");
Ok(0)
}
SYS_FLOCK => {
warn!("sys_flock is unimplemented");
Ok(0)
}
SYS_FSYNC => sys_fsync(args[0]),
SYS_FDATASYNC => sys_fdatasync(args[0]),
SYS_TRUNCATE => sys_truncate(args[0] as *const u8, args[1]),
SYS_FTRUNCATE => sys_ftruncate(args[0], args[1]),
SYS_GETCWD => sys_getcwd(args[0] as *mut u8, args[1]),
// 80
SYS_CHDIR => sys_chdir(args[0] as *const u8),
SYS_FCHMOD => {
warn!("sys_fchmod is unimplemented");
Ok(0)
}
SYS_FCHOWN => {
warn!("sys_fchown is unimplemented");
Ok(0)
}
SYS_UMASK => {
warn!("sys_umask is unimplemented");
Ok(0o777)
}
SYS_GETTIMEOFDAY => sys_gettimeofday(args[0] as *mut TimeVal, args[1] as *const u8),
// SYS_GETRLIMIT => sys_getrlimit(),
SYS_GETRUSAGE => sys_getrusage(args[0], args[1] as *mut RUsage),
SYS_SYSINFO => sys_sysinfo(args[0] as *mut SysInfo),
SYS_TIMES => sys_times(args[0] as *mut Tms),
SYS_GETUID => {
warn!("sys_getuid is unimplemented");
Ok(0)
}
SYS_GETGID => {
warn!("sys_getgid is unimplemented");
Ok(0)
}
SYS_SETUID => {
warn!("sys_setuid is unimplemented");
Ok(0)
}
SYS_GETEUID => {
warn!("sys_geteuid is unimplemented");
Ok(0)
}
SYS_GETEGID => {
warn!("sys_getegid is unimplemented");
Ok(0)
}
SYS_SETPGID => {
warn!("sys_setpgid is unimplemented");
Ok(0)
}
// 110
SYS_GETPPID => sys_getppid(),
SYS_SETSID => {
warn!("sys_setsid is unimplemented");
Ok(0)
}
SYS_GETPGID => {
warn!("sys_getpgid is unimplemented");
Ok(0)
}
SYS_GETGROUPS => {
warn!("sys_getgroups is unimplemented");
Ok(0)
}
SYS_SETGROUPS => {
warn!("sys_setgroups is unimplemented");
Ok(0)
}
SYS_SIGALTSTACK => {
warn!("sys_sigaltstack is unimplemented");
Ok(0)
}
SYS_STATFS => {
warn!("statfs is unimplemented");
Err(SysError::EACCES)
}
SYS_FSTATFS => {
warn!("fstatfs is unimplemented");
Err(SysError::EACCES)
}
SYS_SETPRIORITY => sys_set_priority(args[0]),
SYS_PRCTL => {
warn!("prctl is unimplemented");
Ok(0)
}
// SYS_SETRLIMIT => sys_setrlimit(),
SYS_SYNC => sys_sync(),
SYS_MOUNT => {
warn!("mount is unimplemented");
Err(SysError::EACCES)
}
SYS_UMOUNT2 => {
warn!("umount2 is unimplemented");
Err(SysError::EACCES)
}
SYS_REBOOT => sys_reboot(
args[0] as u32,
args[1] as u32,
args[2] as u32,
args[3] as *const u8,
),
SYS_GETTID => sys_gettid(),
SYS_FUTEX => sys_futex(
args[0],
args[1] as u32,
args[2] as i32,
args[3] as *const TimeSpec,
),
SYS_SCHED_GETAFFINITY => sys_sched_getaffinity(args[0], args[1], args[2] as *mut u32),
SYS_GETDENTS64 => sys_getdents64(args[0], args[1] as *mut LinuxDirent64, args[2]),
SYS_SET_TID_ADDRESS => {
warn!("sys_set_tid_address is unimplemented");
Ok(thread::current().id())
}
SYS_CLOCK_GETTIME => sys_clock_gettime(args[0], args[1] as *mut TimeSpec),
SYS_EXIT_GROUP => sys_exit_group(args[0]),
SYS_OPENAT => sys_openat(args[0], args[1] as *const u8, args[2], args[3]),
SYS_MKDIRAT => sys_mkdirat(args[0], args[1] as *const u8, args[2]),
// SYS_MKNODAT => sys_mknod(),
// 260
SYS_FCHOWNAT => {
warn!("sys_fchownat is unimplemented");
Ok(0)
}
SYS_NEWFSTATAT => sys_fstatat(args[0], args[1] as *const u8, args[2] as *mut Stat, args[3]),
SYS_UNLINKAT => sys_unlinkat(args[0], args[1] as *const u8, args[2]),
SYS_RENAMEAT => sys_renameat(args[0], args[1] as *const u8, args[2], args[3] as *const u8),
SYS_LINKAT => sys_linkat(
args[0],
args[1] as *const u8,
args[2],
args[3] as *const u8,
args[4],
),
SYS_SYMLINKAT => Err(SysError::EACCES),
SYS_READLINKAT => {
sys_readlinkat(args[0], args[1] as *const u8, args[2] as *mut u8, args[3])
}
SYS_FCHMODAT => {
warn!("sys_fchmodat is unimplemented");
Ok(0)
}
SYS_FACCESSAT => sys_faccessat(args[0], args[1] as *const u8, args[2], args[3]),
SYS_PPOLL => sys_ppoll(args[0] as *mut PollFd, args[1], args[2] as *const TimeSpec), // ignore sigmask
// 280
SYS_UTIMENSAT => {
warn!("sys_utimensat is unimplemented");
Ok(0)
}
SYS_ACCEPT4 => sys_accept(args[0], args[1] as *mut SockAddr, args[2] as *mut u32), // use accept for accept4
SYS_EPOLL_CREATE1 => {
warn!("sys_epoll_create1 is unimplemented");
Err(SysError::ENOSYS)
}
SYS_DUP3 => sys_dup2(args[0], args[1]), // TODO: handle `flags`
SYS_PIPE2 => sys_pipe(args[0] as *mut u32), // TODO: handle `flags`
SYS_PRLIMIT64 => sys_prlimit64(
args[0],
args[1],
args[2] as *const RLimit,
args[3] as *mut RLimit,
),
// custom temporary syscall
SYS_MAP_PCI_DEVICE => sys_map_pci_device(args[0], args[1]),
SYS_GET_PADDR => sys_get_paddr(args[0] as *const u64, args[1] as *mut u64, args[2]),
_ => {
#[cfg(target_arch = "x86_64")]
let x86_64_ret = x86_64_syscall(id, args, tf);
#[cfg(not(target_arch = "x86_64"))]
let x86_64_ret = None;
#[cfg(target_arch = "mips")]
let mips_ret = mips_syscall(id, args, tf);
#[cfg(not(target_arch = "mips"))]
let mips_ret = None;
if let Some(ret) = x86_64_ret {
ret
} else if let Some(ret) = mips_ret {
ret
} else {
error!("unknown syscall id: {}, args: {:x?}", id, args);
crate::trap::error(tf);
}
}
};
if !pid.is_init() {
// we trust pid 0 process
debug!(
"{}:{}:{} syscall id {} ret with {:x?}",
cid, pid, tid, id, ret
);
}
match ret {
Ok(code) => code as isize,
Err(err) => -(err as isize),
}
let thread = unsafe { current_thread() };
let mut syscall = Syscall { thread, tf };
syscall.syscall(id, args)
}
#[cfg(target_arch = "mips")]
fn mips_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option<SysResult> {
let ret = match id {
SYS_OPEN => sys_open(args[0] as *const u8, args[1], args[2]),
SYS_POLL => sys_poll(args[0] as *mut PollFd, args[1], args[2]),
SYS_DUP2 => sys_dup2(args[0], args[1]),
SYS_FORK => sys_fork(tf),
SYS_MMAP2 => sys_mmap(args[0], args[1], args[2], args[3], args[4], args[5] * 4096),
SYS_FSTAT64 => sys_fstat(args[0], args[1] as *mut Stat),
SYS_LSTAT64 => sys_lstat(args[0] as *const u8, args[1] as *mut Stat),
SYS_STAT64 => sys_stat(args[0] as *const u8, args[1] as *mut Stat),
SYS_PIPE => {
let fd_ptr = args[0] as *mut u32;
match sys_pipe(fd_ptr) {
Ok(code) => {
unsafe {
tf.v0 = *fd_ptr as usize;
tf.v1 = *(fd_ptr.add(1)) as usize;
}
Ok(tf.v0)
/// All context needed for syscall
struct Syscall<'a> {
thread: &'a mut Thread,
tf: &'a mut TrapFrame,
}
impl Syscall<'_> {
/// Get current process
pub fn process(&self) -> MutexGuard<'_, Process, SpinNoIrq> {
self.thread.proc.lock()
}
/// Get current virtual memory
pub fn vm(&self) -> MutexGuard<'_, MemorySet, SpinNoIrq> {
self.thread.vm.lock()
}
/// System call dispatcher
// This #[deny(unreachable_patterns)] checks if each match arm is defined
// See discussion in https://github.com/oscourse-tsinghua/rcore_plus/commit/17e644e54e494835f1a49b34b80c2c4f15ed0dbe.
#[deny(unreachable_patterns)]
fn syscall(&mut self, id: usize, args: [usize; 6]) -> isize {
#[cfg(feature = "profile")]
let begin_time = unsafe { core::arch::x86_64::_rdtsc() };
let cid = cpu::id();
let pid = self.process().pid.clone();
let tid = processor().tid();
if !pid.is_init() {
// we trust pid 0 process
debug!("{}:{}:{} syscall id {} begin", cid, pid, tid, id);
}
// use platform-specific syscal numbers
// See https://filippo.io/linux-syscall-table/
// And https://fedora.juszkiewicz.com.pl/syscalls.html.
let ret = match id {
// file
SYS_READ => self.sys_read(args[0], args[1] as *mut u8, args[2]),
SYS_WRITE => self.sys_write(args[0], args[1] as *const u8, args[2]),
SYS_OPENAT => self.sys_openat(args[0], args[1] as *const u8, args[2], args[3]),
SYS_CLOSE => self.sys_close(args[0]),
SYS_FSTAT => self.sys_fstat(args[0], args[1] as *mut Stat),
SYS_NEWFSTATAT => {
self.sys_fstatat(args[0], args[1] as *const u8, args[2] as *mut Stat, args[3])
}
SYS_LSEEK => self.sys_lseek(args[0], args[1] as i64, args[2] as u8),
SYS_IOCTL => self.sys_ioctl(args[0], args[1], args[2], args[3], args[4]),
SYS_PREAD64 => self.sys_pread(args[0], args[1] as *mut u8, args[2], args[3]),
SYS_PWRITE64 => self.sys_pwrite(args[0], args[1] as *const u8, args[2], args[3]),
SYS_READV => self.sys_readv(args[0], args[1] as *const IoVec, args[2]),
SYS_WRITEV => self.sys_writev(args[0], args[1] as *const IoVec, args[2]),
SYS_SENDFILE => self.sys_sendfile(args[0], args[1], args[2] as *mut usize, args[3]),
SYS_FCNTL => self.unimplemented("fcntl", Ok(0)),
SYS_FLOCK => self.unimplemented("flock", Ok(0)),
SYS_FSYNC => self.sys_fsync(args[0]),
SYS_FDATASYNC => self.sys_fdatasync(args[0]),
SYS_TRUNCATE => self.sys_truncate(args[0] as *const u8, args[1]),
SYS_FTRUNCATE => self.sys_ftruncate(args[0], args[1]),
SYS_GETDENTS64 => self.sys_getdents64(args[0], args[1] as *mut LinuxDirent64, args[2]),
SYS_GETCWD => self.sys_getcwd(args[0] as *mut u8, args[1]),
SYS_CHDIR => self.sys_chdir(args[0] as *const u8),
SYS_RENAMEAT => {
self.sys_renameat(args[0], args[1] as *const u8, args[2], args[3] as *const u8)
}
SYS_MKDIRAT => self.sys_mkdirat(args[0], args[1] as *const u8, args[2]),
SYS_LINKAT => self.sys_linkat(
args[0],
args[1] as *const u8,
args[2],
args[3] as *const u8,
args[4],
),
SYS_UNLINKAT => self.sys_unlinkat(args[0], args[1] as *const u8, args[2]),
SYS_SYMLINKAT => self.unimplemented("symlinkat", Err(SysError::EACCES)),
SYS_READLINKAT => {
self.sys_readlinkat(args[0], args[1] as *const u8, args[2] as *mut u8, args[3])
}
SYS_FCHMOD => self.unimplemented("fchmod", Ok(0)),
SYS_FCHMODAT => self.unimplemented("fchmodat", Ok(0)),
SYS_FCHOWN => self.unimplemented("fchown", Ok(0)),
SYS_FCHOWNAT => self.unimplemented("fchownat", Ok(0)),
SYS_FACCESSAT => self.sys_faccessat(args[0], args[1] as *const u8, args[2], args[3]),
SYS_DUP3 => self.sys_dup2(args[0], args[1]), // TODO: handle `flags`
SYS_PIPE2 => self.sys_pipe(args[0] as *mut u32), // TODO: handle `flags`
SYS_UTIMENSAT => self.unimplemented("utimensat", Ok(0)),
// io multiplexing
SYS_PPOLL => {
self.sys_ppoll(args[0] as *mut PollFd, args[1], args[2] as *const TimeSpec)
} // ignore sigmask
SYS_EPOLL_CREATE1 => self.unimplemented("epoll_create1", Err(SysError::ENOSYS)),
// file system
SYS_STATFS => self.unimplemented("statfs", Err(SysError::EACCES)),
SYS_FSTATFS => self.unimplemented("fstatfs", Err(SysError::EACCES)),
SYS_SYNC => self.sys_sync(),
SYS_MOUNT => self.unimplemented("mount", Err(SysError::EACCES)),
SYS_UMOUNT2 => self.unimplemented("umount2", Err(SysError::EACCES)),
// memory
SYS_BRK => self.unimplemented("brk", Err(SysError::ENOMEM)),
SYS_MMAP => self.sys_mmap(args[0], args[1], args[2], args[3], args[4], args[5]),
SYS_MPROTECT => self.sys_mprotect(args[0], args[1], args[2]),
SYS_MUNMAP => self.sys_munmap(args[0], args[1]),
SYS_MADVISE => self.unimplemented("madvise", Ok(0)),
// signal
SYS_RT_SIGACTION => self.unimplemented("sigaction", Ok(0)),
SYS_RT_SIGPROCMASK => self.unimplemented("sigprocmask", Ok(0)),
SYS_SIGALTSTACK => self.unimplemented("sigaltstack", Ok(0)),
SYS_KILL => self.sys_kill(args[0], args[1]),
// schedule
SYS_SCHED_YIELD => self.sys_yield(),
SYS_SCHED_GETAFFINITY => {
self.sys_sched_getaffinity(args[0], args[1], args[2] as *mut u32)
}
// socket
SYS_SOCKET => self.sys_socket(args[0], args[1], args[2]),
SYS_CONNECT => self.sys_connect(args[0], args[1] as *const SockAddr, args[2]),
SYS_ACCEPT => self.sys_accept(args[0], args[1] as *mut SockAddr, args[2] as *mut u32),
SYS_ACCEPT4 => self.sys_accept(args[0], args[1] as *mut SockAddr, args[2] as *mut u32), // use accept for accept4
SYS_SENDTO => self.sys_sendto(
args[0],
args[1] as *const u8,
args[2],
args[3],
args[4] as *const SockAddr,
args[5],
),
SYS_RECVFROM => self.sys_recvfrom(
args[0],
args[1] as *mut u8,
args[2],
args[3],
args[4] as *mut SockAddr,
args[5] as *mut u32,
),
// SYS_SENDMSG => self.sys_sendmsg(),
SYS_RECVMSG => self.sys_recvmsg(args[0], args[1] as *mut MsgHdr, args[2]),
SYS_SHUTDOWN => self.sys_shutdown(args[0], args[1]),
SYS_BIND => self.sys_bind(args[0], args[1] as *const SockAddr, args[2]),
SYS_LISTEN => self.sys_listen(args[0], args[1]),
SYS_GETSOCKNAME => {
self.sys_getsockname(args[0], args[1] as *mut SockAddr, args[2] as *mut u32)
}
SYS_GETPEERNAME => {
self.sys_getpeername(args[0], args[1] as *mut SockAddr, args[2] as *mut u32)
}
SYS_SETSOCKOPT => {
self.sys_setsockopt(args[0], args[1], args[2], args[3] as *const u8, args[4])
}
SYS_GETSOCKOPT => self.sys_getsockopt(
args[0],
args[1],
args[2],
args[3] as *mut u8,
args[4] as *mut u32,
),
// process
SYS_CLONE => self.sys_clone(
args[0],
args[1],
args[2] as *mut u32,
args[3] as *mut u32,
args[4],
),
SYS_EXECVE => self.sys_exec(
args[0] as *const u8,
args[1] as *const *const u8,
args[2] as *const *const u8,
),
SYS_EXIT => self.sys_exit(args[0] as usize),
SYS_EXIT_GROUP => self.sys_exit_group(args[0]),
SYS_WAIT4 => self.sys_wait4(args[0] as isize, args[1] as *mut i32), // TODO: wait4
SYS_SET_TID_ADDRESS => self.sys_set_tid_address(args[0] as *mut u32),
SYS_FUTEX => self.sys_futex(
args[0],
args[1] as u32,
args[2] as i32,
args[3] as *const TimeSpec,
),
// time
SYS_NANOSLEEP => self.sys_nanosleep(args[0] as *const TimeSpec),
SYS_SETITIMER => self.unimplemented("setitimer", Ok(0)),
SYS_GETTIMEOFDAY => {
self.sys_gettimeofday(args[0] as *mut TimeVal, args[1] as *const u8)
}
SYS_CLOCK_GETTIME => self.sys_clock_gettime(args[0], args[1] as *mut TimeSpec),
// system
SYS_GETPID => self.sys_getpid(),
SYS_GETTID => self.sys_gettid(),
SYS_UNAME => self.sys_uname(args[0] as *mut u8),
SYS_UMASK => self.unimplemented("umask", Ok(0o777)),
// SYS_GETRLIMIT => self.sys_getrlimit(),
// SYS_SETRLIMIT => self.sys_setrlimit(),
SYS_GETRUSAGE => self.sys_getrusage(args[0], args[1] as *mut RUsage),
SYS_SYSINFO => self.sys_sysinfo(args[0] as *mut SysInfo),
SYS_TIMES => self.sys_times(args[0] as *mut Tms),
SYS_GETUID => self.unimplemented("getuid", Ok(0)),
SYS_GETGID => self.unimplemented("getgid", Ok(0)),
SYS_SETUID => self.unimplemented("setuid", Ok(0)),
SYS_GETEUID => self.unimplemented("geteuid", Ok(0)),
SYS_GETEGID => self.unimplemented("getegid", Ok(0)),
SYS_SETPGID => self.unimplemented("setpgid", Ok(0)),
SYS_GETPPID => self.sys_getppid(),
SYS_SETSID => self.unimplemented("setsid", Ok(0)),
SYS_GETPGID => self.unimplemented("getpgid", Ok(0)),
SYS_GETGROUPS => self.unimplemented("getgroups", Ok(0)),
SYS_SETGROUPS => self.unimplemented("setgroups", Ok(0)),
SYS_SETPRIORITY => self.sys_set_priority(args[0]),
SYS_PRCTL => self.unimplemented("prctl", Ok(0)),
SYS_PRLIMIT64 => self.sys_prlimit64(
args[0],
args[1],
args[2] as *const RLimit,
args[3] as *mut RLimit,
),
SYS_REBOOT => self.sys_reboot(
args[0] as u32,
args[1] as u32,
args[2] as u32,
args[3] as *const u8,
),
// custom
SYS_MAP_PCI_DEVICE => self.sys_map_pci_device(args[0], args[1]),
SYS_GET_PADDR => {
self.sys_get_paddr(args[0] as *const u64, args[1] as *mut u64, args[2])
}
//SYS_GETRANDOM => self.unimplemented("getrandom", Err(SysError::EINVAL)),
SYS_GETRANDOM => {
self.sys_getrandom(args[0] as *mut u8, args[1] as usize, args[2] as u32)
}
SYS_TKILL => self.unimplemented("tkill", Ok(0)),
_ => {
let ret = match () {
#[cfg(target_arch = "x86_64")]
() => self.x86_64_syscall(id, args),
#[cfg(target_arch = "mips")]
() => self.mips_syscall(id, args),
#[cfg(all(not(target_arch = "x86_64"), not(target_arch = "mips")))]
() => None,
};
if let Some(ret) = ret {
ret
} else {
error!("unknown syscall id: {}, args: {:x?}", id, args);
crate::trap::error(self.tf);
}
}
};
if !pid.is_init() {
// we trust pid 0 process
info!("=> {:x?}", ret);
}
#[cfg(feature = "profile")]
{
let end_time = unsafe { core::arch::x86_64::_rdtsc() };
*SYSCALL_TIMING.lock().entry(id).or_insert(0) += end_time - begin_time;
if end_time % 1000 == 0 {
let timing = SYSCALL_TIMING.lock();
let mut count_vec: Vec<(&usize, &i64)> = timing.iter().collect();
count_vec.sort_by(|a, b| b.1.cmp(a.1));
for (id, time) in count_vec.iter().take(5) {
warn!("timing {:03} time {:012}", id, time);
}
Err(err) => Err(err),
}
}
SYS_GETPGID => {
warn!("sys_getpgid is unimplemented");
Ok(0)
match ret {
Ok(code) => code as isize,
Err(err) => -(err as isize),
}
SYS_SETPGID => {
warn!("sys_setpgid is unimplemented");
Ok(0)
}
SYS_FCNTL64 => {
warn!("sys_fcntl64 is unimplemented");
Ok(0)
}
SYS_SET_THREAD_AREA => {
info!("set_thread_area: tls: 0x{:x}", args[0]);
extern "C" {
fn _cur_tls();
}
}
unsafe {
asm!("mtc0 $0, $$4, 2": :"r"(args[0]));
*(_cur_tls as *mut usize) = args[0];
}
Ok(0)
}
_ => {
return None;
}
};
Some(ret)
}
fn unimplemented(&self, name: &str, ret: SysResult) -> SysResult {
warn!("{} is unimplemented", name);
ret
}
#[cfg(target_arch = "x86_64")]
fn x86_64_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option<SysResult> {
let ret = match id {
SYS_OPEN => sys_open(args[0] as *const u8, args[1], args[2]),
SYS_STAT => sys_stat(args[0] as *const u8, args[1] as *mut Stat),
SYS_LSTAT => sys_lstat(args[0] as *const u8, args[1] as *mut Stat),
SYS_POLL => sys_poll(args[0] as *mut PollFd, args[1], args[2]),
SYS_ACCESS => sys_access(args[0] as *const u8, args[1]),
SYS_PIPE => sys_pipe(args[0] as *mut u32),
SYS_SELECT => sys_select(
args[0],
args[1] as *mut u32,
args[2] as *mut u32,
args[3] as *mut u32,
args[4] as *const TimeVal,
),
SYS_DUP2 => sys_dup2(args[0], args[1]),
SYS_ALARM => {
warn!("sys_alarm is unimplemented");
Ok(0)
}
SYS_FORK => sys_fork(tf),
// use fork for vfork
SYS_VFORK => sys_fork(tf),
SYS_RENAME => sys_rename(args[0] as *const u8, args[1] as *const u8),
SYS_MKDIR => sys_mkdir(args[0] as *const u8, args[1]),
SYS_RMDIR => sys_rmdir(args[0] as *const u8),
SYS_LINK => sys_link(args[0] as *const u8, args[1] as *const u8),
SYS_UNLINK => sys_unlink(args[0] as *const u8),
SYS_READLINK => sys_readlink(args[0] as *const u8, args[1] as *mut u8, args[2]),
// 90
SYS_CHMOD => {
warn!("sys_chmod is unimplemented");
Ok(0)
}
SYS_CHOWN => {
warn!("sys_chown is unimplemented");
Ok(0)
}
SYS_ARCH_PRCTL => sys_arch_prctl(args[0] as i32, args[1], tf),
SYS_TIME => sys_time(args[0] as *mut u64),
SYS_EPOLL_CREATE => {
warn!("sys_epoll_create is unimplemented");
Err(SysError::ENOSYS)
}
_ => {
return None;
}
};
Some(ret)
#[cfg(target_arch = "mips")]
fn mips_syscall(&mut self, id: usize, args: [usize; 6]) -> Option<SysResult> {
let ret = match id {
SYS_OPEN => self.sys_open(args[0] as *const u8, args[1], args[2]),
SYS_POLL => self.sys_poll(args[0] as *mut PollFd, args[1], args[2]),
SYS_DUP2 => self.sys_dup2(args[0], args[1]),
SYS_FORK => self.sys_fork(),
SYS_MMAP2 => self.sys_mmap(args[0], args[1], args[2], args[3], args[4], args[5] * 4096),
SYS_FSTAT64 => self.sys_fstat(args[0], args[1] as *mut Stat),
SYS_LSTAT64 => self.sys_lstat(args[0] as *const u8, args[1] as *mut Stat),
SYS_STAT64 => self.sys_stat(args[0] as *const u8, args[1] as *mut Stat),
SYS_PIPE => {
let fd_ptr = args[0] as *mut u32;
match self.sys_pipe(fd_ptr) {
Ok(code) => {
unsafe {
tf.v0 = *fd_ptr as usize;
tf.v1 = *(fd_ptr.add(1)) as usize;
}
Ok(tf.v0)
}
Err(err) => Err(err),
}
}
SYS_FCNTL64 => self.unimplemented("fcntl64", Ok(0)),
SYS_SET_THREAD_AREA => {
info!("set_thread_area: tls: 0x{:x}", args[0]);
extern "C" {
fn _cur_tls();
}
unsafe {
asm!("mtc0 $0, $$4, 2": :"r"(args[0]));
*(_cur_tls as *mut usize) = args[0];
}
Ok(0)
}
_ => return None,
};
Some(ret)
}
#[cfg(target_arch = "x86_64")]
fn x86_64_syscall(&mut self, id: usize, args: [usize; 6]) -> Option<SysResult> {
let ret = match id {
SYS_OPEN => self.sys_open(args[0] as *const u8, args[1], args[2]),
SYS_STAT => self.sys_stat(args[0] as *const u8, args[1] as *mut Stat),
SYS_LSTAT => self.sys_lstat(args[0] as *const u8, args[1] as *mut Stat),
SYS_POLL => self.sys_poll(args[0] as *mut PollFd, args[1], args[2]),
SYS_ACCESS => self.sys_access(args[0] as *const u8, args[1]),
SYS_PIPE => self.sys_pipe(args[0] as *mut u32),
SYS_SELECT => self.sys_select(
args[0],
args[1] as *mut u32,
args[2] as *mut u32,
args[3] as *mut u32,
args[4] as *const TimeVal,
),
SYS_DUP2 => self.sys_dup2(args[0], args[1]),
SYS_ALARM => self.unimplemented("alarm", Ok(0)),
SYS_FORK => self.sys_fork(),
SYS_VFORK => self.sys_vfork(),
SYS_RENAME => self.sys_rename(args[0] as *const u8, args[1] as *const u8),
SYS_MKDIR => self.sys_mkdir(args[0] as *const u8, args[1]),
SYS_RMDIR => self.sys_rmdir(args[0] as *const u8),
SYS_LINK => self.sys_link(args[0] as *const u8, args[1] as *const u8),
SYS_UNLINK => self.sys_unlink(args[0] as *const u8),
SYS_READLINK => self.sys_readlink(args[0] as *const u8, args[1] as *mut u8, args[2]),
SYS_CHMOD => self.unimplemented("chmod", Ok(0)),
SYS_CHOWN => self.unimplemented("chown", Ok(0)),
SYS_ARCH_PRCTL => self.sys_arch_prctl(args[0] as i32, args[1]),
SYS_TIME => self.sys_time(args[0] as *mut u64),
SYS_EPOLL_CREATE => self.unimplemented("epoll_create", Err(SysError::ENOSYS)),
_ => return None,
};
Some(ret)
}
}
pub type SysResult = Result<usize, SysError>;

View File

@ -2,295 +2,300 @@
use super::fs::IoVecs;
use super::*;
use crate::drivers::SOCKET_ACTIVITY;
use crate::fs::FileLike;
use crate::memory::MemorySet;
use crate::net::{
Endpoint, LinkLevelEndpoint, NetlinkEndpoint, NetlinkSocketState, PacketSocketState,
RawSocketState, Socket, TcpSocketState, UdpSocketState, SOCKETS,
};
use crate::sync::{MutexGuard, SpinNoIrq, SpinNoIrqLock as Mutex};
use alloc::boxed::Box;
use core::cmp::min;
use core::mem::size_of;
use smoltcp::wire::*;
pub fn sys_socket(domain: usize, socket_type: usize, protocol: usize) -> SysResult {
let domain = AddressFamily::from(domain as u16);
let socket_type = SocketType::from(socket_type as u8 & SOCK_TYPE_MASK);
info!(
"socket: domain: {:?}, socket_type: {:?}, protocol: {}",
domain, socket_type, protocol
);
let mut proc = process();
let socket: Box<dyn Socket> = match domain {
AddressFamily::Internet | AddressFamily::Unix => match socket_type {
SocketType::Stream => Box::new(TcpSocketState::new()),
SocketType::Datagram => Box::new(UdpSocketState::new()),
SocketType::Raw => Box::new(RawSocketState::new(protocol as u8)),
_ => return Err(SysError::EINVAL),
},
AddressFamily::Packet => match socket_type {
SocketType::Raw => Box::new(PacketSocketState::new()),
_ => return Err(SysError::EINVAL),
},
AddressFamily::Netlink => match socket_type {
SocketType::Raw => Box::new(NetlinkSocketState::new()),
_ => return Err(SysError::EINVAL),
},
_ => return Err(SysError::EAFNOSUPPORT),
};
let fd = proc.get_free_fd();
proc.files.insert(fd, FileLike::Socket(socket));
Ok(fd)
}
pub fn sys_setsockopt(
fd: usize,
level: usize,
optname: usize,
optval: *const u8,
optlen: usize,
) -> SysResult {
info!(
"setsockopt: fd: {}, level: {}, optname: {}",
fd, level, optname
);
let mut proc = process();
proc.vm.check_read_array(optval, optlen)?;
let data = unsafe { slice::from_raw_parts(optval, optlen) };
let socket = proc.get_socket(fd)?;
socket.setsockopt(level, optname, data)
}
pub fn sys_getsockopt(
fd: usize,
level: usize,
optname: usize,
optval: *mut u8,
optlen: *mut u32,
) -> SysResult {
info!(
"getsockopt: fd: {}, level: {}, optname: {} optval: {:?} optlen: {:?}",
fd, level, optname, optval, optlen
);
let proc = process();
proc.vm.check_write_ptr(optlen)?;
match level {
SOL_SOCKET => match optname {
SO_SNDBUF => {
proc.vm.check_write_array(optval, 4)?;
unsafe {
*(optval as *mut u32) = crate::net::TCP_SENDBUF as u32;
*optlen = 4;
}
Ok(0)
}
SO_RCVBUF => {
proc.vm.check_write_array(optval, 4)?;
unsafe {
*(optval as *mut u32) = crate::net::TCP_RECVBUF as u32;
*optlen = 4;
}
Ok(0)
}
_ => Err(SysError::ENOPROTOOPT),
},
IPPROTO_TCP => match optname {
TCP_CONGESTION => Ok(0),
_ => Err(SysError::ENOPROTOOPT),
},
_ => Err(SysError::ENOPROTOOPT),
impl Syscall<'_> {
pub fn sys_socket(&mut self, domain: usize, socket_type: usize, protocol: usize) -> SysResult {
let domain = AddressFamily::from(domain as u16);
let socket_type = SocketType::from(socket_type as u8 & SOCK_TYPE_MASK);
info!(
"socket: domain: {:?}, socket_type: {:?}, protocol: {}",
domain, socket_type, protocol
);
let mut proc = self.process();
let socket: Box<dyn Socket> = match domain {
AddressFamily::Internet | AddressFamily::Unix => match socket_type {
SocketType::Stream => Box::new(TcpSocketState::new()),
SocketType::Datagram => Box::new(UdpSocketState::new()),
SocketType::Raw => Box::new(RawSocketState::new(protocol as u8)),
_ => return Err(SysError::EINVAL),
},
AddressFamily::Packet => match socket_type {
SocketType::Raw => Box::new(PacketSocketState::new()),
_ => return Err(SysError::EINVAL),
},
AddressFamily::Netlink => match socket_type {
SocketType::Raw => Box::new(NetlinkSocketState::new()),
_ => return Err(SysError::EINVAL),
},
_ => return Err(SysError::EAFNOSUPPORT),
};
let fd = proc.add_file(FileLike::Socket(socket));
Ok(fd)
}
}
pub fn sys_connect(fd: usize, addr: *const SockAddr, addr_len: usize) -> SysResult {
info!(
"sys_connect: fd: {}, addr: {:?}, addr_len: {}",
fd, addr, addr_len
);
pub fn sys_setsockopt(
&mut self,
fd: usize,
level: usize,
optname: usize,
optval: *const u8,
optlen: usize,
) -> SysResult {
info!(
"setsockopt: fd: {}, level: {}, optname: {}",
fd, level, optname
);
let mut proc = self.process();
let data = unsafe { self.vm().check_read_array(optval, optlen)? };
let socket = proc.get_socket(fd)?;
socket.setsockopt(level, optname, data)
}
let mut proc = process();
let endpoint = sockaddr_to_endpoint(&mut proc, addr, addr_len)?;
let socket = proc.get_socket(fd)?;
socket.connect(endpoint)?;
Ok(0)
}
pub fn sys_sendto(
fd: usize,
base: *const u8,
len: usize,
_flags: usize,
addr: *const SockAddr,
addr_len: usize,
) -> SysResult {
info!(
"sys_sendto: fd: {} base: {:?} len: {} addr: {:?} addr_len: {}",
fd, base, len, addr, addr_len
);
let mut proc = process();
proc.vm.check_read_array(base, len)?;
let slice = unsafe { slice::from_raw_parts(base, len) };
let endpoint = if addr.is_null() {
None
} else {
let endpoint = sockaddr_to_endpoint(&mut proc, addr, addr_len)?;
info!("sys_sendto: sending to endpoint {:?}", endpoint);
Some(endpoint)
};
let socket = proc.get_socket(fd)?;
socket.write(&slice, endpoint)
}
pub fn sys_recvfrom(
fd: usize,
base: *mut u8,
len: usize,
flags: usize,
addr: *mut SockAddr,
addr_len: *mut u32,
) -> SysResult {
info!(
"sys_recvfrom: fd: {} base: {:?} len: {} flags: {} addr: {:?} addr_len: {:?}",
fd, base, len, flags, addr, addr_len
);
let mut proc = process();
proc.vm.check_write_array(base, len)?;
let socket = proc.get_socket(fd)?;
let mut slice = unsafe { slice::from_raw_parts_mut(base, len) };
let (result, endpoint) = socket.read(&mut slice);
if result.is_ok() && !addr.is_null() {
let sockaddr_in = SockAddr::from(endpoint);
unsafe {
sockaddr_in.write_to(&mut proc, addr, addr_len)?;
pub fn sys_getsockopt(
&mut self,
fd: usize,
level: usize,
optname: usize,
optval: *mut u8,
optlen: *mut u32,
) -> SysResult {
info!(
"getsockopt: fd: {}, level: {}, optname: {} optval: {:?} optlen: {:?}",
fd, level, optname, optval, optlen
);
let optlen = unsafe { self.vm().check_write_ptr(optlen)? };
match level {
SOL_SOCKET => match optname {
SO_SNDBUF => {
let optval = unsafe { self.vm().check_write_ptr(optval as *mut u32)? };
*optval = crate::net::TCP_SENDBUF as u32;
*optlen = 4;
Ok(0)
}
SO_RCVBUF => {
let optval = unsafe { self.vm().check_write_ptr(optval as *mut u32)? };
*optval = crate::net::TCP_RECVBUF as u32;
*optlen = 4;
Ok(0)
}
_ => Err(SysError::ENOPROTOOPT),
},
IPPROTO_TCP => match optname {
TCP_CONGESTION => Ok(0),
_ => Err(SysError::ENOPROTOOPT),
},
_ => Err(SysError::ENOPROTOOPT),
}
}
result
}
pub fn sys_connect(&mut self, fd: usize, addr: *const SockAddr, addr_len: usize) -> SysResult {
info!(
"sys_connect: fd: {}, addr: {:?}, addr_len: {}",
fd, addr, addr_len
);
pub fn sys_recvmsg(fd: usize, msg: *mut MsgHdr, flags: usize) -> SysResult {
info!("recvmsg: fd: {}, msg: {:?}, flags: {}", fd, msg, flags);
let mut proc = process();
proc.vm.check_read_ptr(msg)?;
let hdr = unsafe { &mut *msg };
let mut iovs = IoVecs::check_and_new(hdr.msg_iov, hdr.msg_iovlen, &proc.vm, true)?;
let mut proc = self.process();
let endpoint = sockaddr_to_endpoint(&mut self.vm(), addr, addr_len)?;
let socket = proc.get_socket(fd)?;
socket.connect(endpoint)?;
Ok(0)
}
let mut buf = iovs.new_buf(true);
let socket = proc.get_socket(fd)?;
let (result, endpoint) = socket.read(&mut buf);
pub fn sys_sendto(
&mut self,
fd: usize,
base: *const u8,
len: usize,
_flags: usize,
addr: *const SockAddr,
addr_len: usize,
) -> SysResult {
info!(
"sys_sendto: fd: {} base: {:?} len: {} addr: {:?} addr_len: {}",
fd, base, len, addr, addr_len
);
if let Ok(len) = result {
// copy data to user
iovs.write_all_from_slice(&buf[..len]);
let mut proc = self.process();
let slice = unsafe { self.vm().check_read_array(base, len)? };
let endpoint = if addr.is_null() {
None
} else {
let endpoint = sockaddr_to_endpoint(&mut self.vm(), addr, addr_len)?;
info!("sys_sendto: sending to endpoint {:?}", endpoint);
Some(endpoint)
};
let socket = proc.get_socket(fd)?;
socket.write(&slice, endpoint)
}
pub fn sys_recvfrom(
&mut self,
fd: usize,
base: *mut u8,
len: usize,
flags: usize,
addr: *mut SockAddr,
addr_len: *mut u32,
) -> SysResult {
info!(
"sys_recvfrom: fd: {} base: {:?} len: {} flags: {} addr: {:?} addr_len: {:?}",
fd, base, len, flags, addr, addr_len
);
let mut proc = self.process();
let mut slice = unsafe { self.vm().check_write_array(base, len)? };
let socket = proc.get_socket(fd)?;
let (result, endpoint) = socket.read(&mut slice);
if result.is_ok() && !addr.is_null() {
let sockaddr_in = SockAddr::from(endpoint);
unsafe {
sockaddr_in.write_to(&mut self.vm(), addr, addr_len)?;
}
}
result
}
pub fn sys_recvmsg(&mut self, fd: usize, msg: *mut MsgHdr, flags: usize) -> SysResult {
info!("recvmsg: fd: {}, msg: {:?}, flags: {}", fd, msg, flags);
let mut proc = self.process();
let hdr = unsafe { self.vm().check_write_ptr(msg)? };
let mut iovs =
unsafe { IoVecs::check_and_new(hdr.msg_iov, hdr.msg_iovlen, &self.vm(), true)? };
let mut buf = iovs.new_buf(true);
let socket = proc.get_socket(fd)?;
let (result, endpoint) = socket.read(&mut buf);
if let Ok(len) = result {
// copy data to user
iovs.write_all_from_slice(&buf[..len]);
let sockaddr_in = SockAddr::from(endpoint);
unsafe {
sockaddr_in.write_to(&mut self.vm(), hdr.msg_name, &mut hdr.msg_namelen as *mut u32)?;
}
}
result
}
pub fn sys_bind(&mut self, fd: usize, addr: *const SockAddr, addr_len: usize) -> SysResult {
info!("sys_bind: fd: {} addr: {:?} len: {}", fd, addr, addr_len);
let mut proc = self.process();
let endpoint = sockaddr_to_endpoint(&mut self.vm(), addr, addr_len)?;
info!("sys_bind: fd: {} bind to {:?}", fd, endpoint);
let socket = proc.get_socket(fd)?;
socket.bind(endpoint)
}
pub fn sys_listen(&mut self, fd: usize, backlog: usize) -> SysResult {
info!("sys_listen: fd: {} backlog: {}", fd, backlog);
// smoltcp tcp sockets do not support backlog
// open multiple sockets for each connection
let mut proc = self.process();
let socket = proc.get_socket(fd)?;
socket.listen()
}
pub fn sys_shutdown(&mut self, fd: usize, how: usize) -> SysResult {
info!("sys_shutdown: fd: {} how: {}", fd, how);
let mut proc = self.process();
let socket = proc.get_socket(fd)?;
socket.shutdown()
}
pub fn sys_accept(&mut self, fd: usize, addr: *mut SockAddr, addr_len: *mut u32) -> SysResult {
info!(
"sys_accept: fd: {} addr: {:?} addr_len: {:?}",
fd, addr, addr_len
);
// smoltcp tcp sockets do not support backlog
// open multiple sockets for each connection
let mut proc = self.process();
let socket = proc.get_socket(fd)?;
let (new_socket, remote_endpoint) = socket.accept()?;
let new_fd = proc.add_file(FileLike::Socket(new_socket));
if !addr.is_null() {
let sockaddr_in = SockAddr::from(remote_endpoint);
unsafe {
sockaddr_in.write_to(&mut self.vm(), addr, addr_len)?;
}
}
Ok(new_fd)
}
pub fn sys_getsockname(
&mut self,
fd: usize,
addr: *mut SockAddr,
addr_len: *mut u32,
) -> SysResult {
info!(
"sys_getsockname: fd: {} addr: {:?} addr_len: {:?}",
fd, addr, addr_len
);
let mut proc = self.process();
if addr.is_null() {
return Err(SysError::EINVAL);
}
let socket = proc.get_socket(fd)?;
let endpoint = socket.endpoint().ok_or(SysError::EINVAL)?;
let sockaddr_in = SockAddr::from(endpoint);
unsafe {
sockaddr_in.write_to(&mut proc, hdr.msg_name, &mut hdr.msg_namelen as *mut u32)?;
sockaddr_in.write_to(&mut self.vm(), addr, addr_len)?;
}
Ok(0)
}
result
}
pub fn sys_bind(fd: usize, addr: *const SockAddr, addr_len: usize) -> SysResult {
info!("sys_bind: fd: {} addr: {:?} len: {}", fd, addr, addr_len);
let mut proc = process();
pub fn sys_getpeername(
&mut self,
fd: usize,
addr: *mut SockAddr,
addr_len: *mut u32,
) -> SysResult {
info!(
"sys_getpeername: fd: {} addr: {:?} addr_len: {:?}",
fd, addr, addr_len
);
let mut endpoint = sockaddr_to_endpoint(&mut proc, addr, addr_len)?;
info!("sys_bind: fd: {} bind to {:?}", fd, endpoint);
// smoltcp tcp sockets do not support backlog
// open multiple sockets for each connection
let mut proc = self.process();
let socket = proc.get_socket(fd)?;
socket.bind(endpoint)
}
if addr as usize == 0 {
return Err(SysError::EINVAL);
}
pub fn sys_listen(fd: usize, backlog: usize) -> SysResult {
info!("sys_listen: fd: {} backlog: {}", fd, backlog);
// smoltcp tcp sockets do not support backlog
// open multiple sockets for each connection
let mut proc = process();
let socket = proc.get_socket(fd)?;
socket.listen()
}
pub fn sys_shutdown(fd: usize, how: usize) -> SysResult {
info!("sys_shutdown: fd: {} how: {}", fd, how);
let mut proc = process();
let socket = proc.get_socket(fd)?;
socket.shutdown()
}
pub fn sys_accept(fd: usize, addr: *mut SockAddr, addr_len: *mut u32) -> SysResult {
info!(
"sys_accept: fd: {} addr: {:?} addr_len: {:?}",
fd, addr, addr_len
);
// smoltcp tcp sockets do not support backlog
// open multiple sockets for each connection
let mut proc = process();
let socket = proc.get_socket(fd)?;
let (new_socket, remote_endpoint) = socket.accept()?;
let new_fd = proc.get_free_fd();
proc.files.insert(new_fd, FileLike::Socket(new_socket));
if !addr.is_null() {
let socket = proc.get_socket(fd)?;
let remote_endpoint = socket.remote_endpoint().ok_or(SysError::EINVAL)?;
let sockaddr_in = SockAddr::from(remote_endpoint);
unsafe {
sockaddr_in.write_to(&mut proc, addr, addr_len)?;
sockaddr_in.write_to(&mut self.vm(), addr, addr_len)?;
}
Ok(0)
}
Ok(new_fd)
}
pub fn sys_getsockname(fd: usize, addr: *mut SockAddr, addr_len: *mut u32) -> SysResult {
info!(
"sys_getsockname: fd: {} addr: {:?} addr_len: {:?}",
fd, addr, addr_len
);
let mut proc = process();
if addr.is_null() {
return Err(SysError::EINVAL);
}
let socket = proc.get_socket(fd)?;
let endpoint = socket.endpoint().ok_or(SysError::EINVAL)?;
let sockaddr_in = SockAddr::from(endpoint);
unsafe {
sockaddr_in.write_to(&mut proc, addr, addr_len)?;
}
Ok(0)
}
pub fn sys_getpeername(fd: usize, addr: *mut SockAddr, addr_len: *mut u32) -> SysResult {
info!(
"sys_getpeername: fd: {} addr: {:?} addr_len: {:?}",
fd, addr, addr_len
);
// smoltcp tcp sockets do not support backlog
// open multiple sockets for each connection
let mut proc = process();
if addr as usize == 0 {
return Err(SysError::EINVAL);
}
let socket = proc.get_socket(fd)?;
let remote_endpoint = socket.remote_endpoint().ok_or(SysError::EINVAL)?;
let sockaddr_in = SockAddr::from(remote_endpoint);
unsafe {
sockaddr_in.write_to(&mut proc, addr, addr_len)?;
}
Ok(0)
}
impl Process {
@ -401,42 +406,36 @@ impl From<Endpoint> for SockAddr {
/// Convert sockaddr to endpoint
// Check len is long enough
fn sockaddr_to_endpoint(
proc: &mut Process,
vm: &MemorySet,
addr: *const SockAddr,
len: usize,
) -> Result<Endpoint, SysError> {
if len < size_of::<u16>() {
return Err(SysError::EINVAL);
}
proc.vm.check_read_array(addr as *const u8, len)?;
let addr = unsafe { vm.check_read_ptr(addr)? };
if len < addr.len()? {
return Err(SysError::EINVAL);
}
unsafe {
match AddressFamily::from((*addr).family) {
match AddressFamily::from(addr.family) {
AddressFamily::Internet => {
if len < size_of::<SockAddrIn>() {
return Err(SysError::EINVAL);
}
let port = u16::from_be((*addr).addr_in.sin_port);
let port = u16::from_be(addr.addr_in.sin_port);
let addr = IpAddress::from(Ipv4Address::from_bytes(
&u32::from_be((*addr).addr_in.sin_addr).to_be_bytes()[..],
&u32::from_be(addr.addr_in.sin_addr).to_be_bytes()[..],
));
Ok(Endpoint::Ip((addr, port).into()))
}
AddressFamily::Unix => Err(SysError::EINVAL),
AddressFamily::Packet => {
if len < size_of::<SockAddrLl>() {
return Err(SysError::EINVAL);
}
Ok(Endpoint::LinkLevel(LinkLevelEndpoint::new(
(*addr).addr_ll.sll_ifindex as usize,
addr.addr_ll.sll_ifindex as usize,
)))
}
AddressFamily::Netlink => {
if len < size_of::<SockAddrNl>() {
return Err(SysError::EINVAL);
}
Ok(Endpoint::Netlink(NetlinkEndpoint::new(
(*addr).addr_nl.nl_pid,
(*addr).addr_nl.nl_groups,
addr.addr_nl.nl_pid,
addr.addr_nl.nl_groups,
)))
}
_ => Err(SysError::EINVAL),
@ -445,11 +444,21 @@ fn sockaddr_to_endpoint(
}
impl SockAddr {
fn len(&self) -> Result<usize, SysError> {
match AddressFamily::from(unsafe { self.family }) {
AddressFamily::Internet => Ok(size_of::<SockAddrIn>()),
AddressFamily::Packet => Ok(size_of::<SockAddrLl>()),
AddressFamily::Netlink => Ok(size_of::<SockAddrNl>()),
AddressFamily::Unix => Err(SysError::EINVAL),
_ => Err(SysError::EINVAL),
}
}
/// Write to user sockaddr
/// Check mutability for user
unsafe fn write_to(
self,
proc: &mut Process,
vm: &MemorySet,
addr: *mut SockAddr,
addr_len: *mut u32,
) -> SysResult {
@ -458,24 +467,17 @@ impl SockAddr {
return Ok(0);
}
proc.vm.check_write_ptr(addr_len)?;
let addr_len = unsafe { vm.check_write_ptr(addr_len)? };
let max_addr_len = *addr_len as usize;
let full_len = match AddressFamily::from(self.family) {
AddressFamily::Internet => size_of::<SockAddrIn>(),
AddressFamily::Packet => size_of::<SockAddrLl>(),
AddressFamily::Netlink => size_of::<SockAddrNl>(),
AddressFamily::Unix => return Err(SysError::EINVAL),
_ => return Err(SysError::EINVAL),
};
let full_len = self.len()?;
let written_len = min(max_addr_len, full_len);
if written_len > 0 {
proc.vm.check_write_array(addr as *mut u8, written_len)?;
let target = unsafe { vm.check_write_array(addr as *mut u8, written_len)? };
let source = slice::from_raw_parts(&self as *const SockAddr as *const u8, written_len);
let target = slice::from_raw_parts_mut(addr as *mut u8, written_len);
target.copy_from_slice(source);
}
addr_len.write(full_len as u32);
*addr_len = full_len as u32;
return Ok(0);
}
}

View File

@ -3,343 +3,349 @@
use super::*;
use crate::fs::INodeExt;
/// Fork the current process. Return the child's PID.
pub fn sys_fork(tf: &TrapFrame) -> SysResult {
let new_thread = current_thread().fork(tf);
let pid = processor().manager().add(new_thread);
info!("fork: {} -> {}", thread::current().id(), pid);
Ok(pid)
}
impl Syscall<'_> {
/// Fork the current process. Return the child's PID.
pub fn sys_fork(&mut self) -> SysResult {
let new_thread = self.thread.fork(self.tf);
let pid = new_thread.proc.lock().pid.get();
let tid = processor().manager().add(new_thread);
processor().manager().detach(tid);
info!("fork: {} -> {}", thread::current().id(), pid);
Ok(pid)
}
/// Create a new thread in the current process.
/// The new thread's stack pointer will be set to `newsp`,
/// and thread pointer will be set to `newtls`.
/// The child tid will be stored at both `parent_tid` and `child_tid`.
/// This is partially implemented for musl only.
pub fn sys_clone(
flags: usize,
newsp: usize,
parent_tid: *mut u32,
child_tid: *mut u32,
newtls: usize,
tf: &TrapFrame,
) -> SysResult {
let clone_flags = CloneFlags::from_bits_truncate(flags);
info!(
"clone: flags: {:?} == {:#x}, newsp: {:#x}, parent_tid: {:?}, child_tid: {:?}, newtls: {:#x}",
clone_flags, flags, newsp, parent_tid, child_tid, newtls
);
if flags == 0x4111 || flags == 0x11 {
warn!("sys_clone is calling sys_fork instead, ignoring other args");
return sys_fork(tf);
pub fn sys_vfork(&mut self) -> SysResult {
self.sys_fork()
}
if (flags != 0x7d0f00) && (flags != 0x5d0f00) {
//0x5d0f00 is the args from gcc of alpine linux
//warn!("sys_clone only support musl pthread_create");
panic!(
"sys_clone only support sys_fork OR musl pthread_create without flags{:x}",
flags
);
//return Err(SysError::ENOSYS);
}
{
let proc = process();
proc.vm.check_write_ptr(parent_tid)?;
proc.vm.check_write_ptr(child_tid)?;
}
let new_thread = current_thread().clone(tf, newsp, newtls, child_tid as usize);
// FIXME: parent pid
let tid = processor().manager().add(new_thread);
info!("clone: {} -> {}", thread::current().id(), tid);
unsafe {
parent_tid.write(tid as u32);
child_tid.write(tid as u32);
}
Ok(tid)
}
/// Wait for the process exit.
/// Return the PID. Store exit code to `wstatus` if it's not null.
pub fn sys_wait4(pid: isize, wstatus: *mut i32) -> SysResult {
info!("wait4: pid: {}, code: {:?}", pid, wstatus);
if !wstatus.is_null() {
process().vm.check_write_ptr(wstatus)?;
}
#[derive(Debug)]
enum WaitFor {
AnyChild,
Pid(usize),
}
let target = match pid {
-1 | 0 => WaitFor::AnyChild,
p if p > 0 => WaitFor::Pid(p as usize),
_ => unimplemented!(),
};
loop {
let mut proc = process();
// check child_exit_code
let find = match target {
WaitFor::AnyChild => proc
.child_exit_code
.iter()
.next()
.map(|(&pid, &code)| (pid, code)),
WaitFor::Pid(pid) => proc.child_exit_code.get(&pid).map(|&code| (pid, code)),
};
// if found, return
if let Some((pid, exit_code)) = find {
proc.child_exit_code.remove(&pid);
if !wstatus.is_null() {
unsafe {
wstatus.write(exit_code as i32);
}
}
return Ok(pid);
}
// if not, check pid
let children: Vec<_> = proc
.children
.iter()
.filter_map(|weak| weak.upgrade())
.collect();
let invalid = match target {
WaitFor::AnyChild => children.len() == 0,
WaitFor::Pid(pid) => children
.iter()
.find(|p| p.lock().pid.get() == pid)
.is_none(),
};
if invalid {
return Err(SysError::ECHILD);
}
/// Create a new thread in the current process.
/// The new thread's stack pointer will be set to `newsp`,
/// and thread pointer will be set to `newtls`.
/// The child tid will be stored at both `parent_tid` and `child_tid`.
/// This is partially implemented for musl only.
pub fn sys_clone(
&mut self,
flags: usize,
newsp: usize,
parent_tid: *mut u32,
child_tid: *mut u32,
newtls: usize,
) -> SysResult {
let clone_flags = CloneFlags::from_bits_truncate(flags);
info!(
"wait: thread {} -> {:?}, sleep",
thread::current().id(),
target
"clone: flags: {:?} == {:#x}, newsp: {:#x}, parent_tid: {:?}, child_tid: {:?}, newtls: {:#x}",
clone_flags, flags, newsp, parent_tid, child_tid, newtls
);
let condvar = proc.child_exit.clone();
drop(proc); // must release lock of current process
condvar._wait();
}
}
pub fn sys_exec(
name: *const u8,
argv: *const *const u8,
envp: *const *const u8,
tf: &mut TrapFrame,
) -> SysResult {
info!("exec: name: {:?}, argv: {:?}, envp: {:?}", name, argv, envp);
let proc = process();
let exec_name = if name.is_null() {
String::from("")
} else {
unsafe { proc.vm.check_and_clone_cstr(name)? }
};
if argv.is_null() {
return Err(SysError::EINVAL);
}
// Check and copy args to kernel
let mut args = Vec::new();
unsafe {
let mut current_argv = argv as *const *const u8;
proc.vm.check_read_ptr(current_argv)?;
while !(*current_argv).is_null() {
let arg = proc.vm.check_and_clone_cstr(*current_argv)?;
args.push(arg);
current_argv = current_argv.add(1);
if flags == 0x4111 || flags == 0x11 {
warn!("sys_clone is calling sys_fork instead, ignoring other args");
return self.sys_fork();
}
}
// Check and copy envs to kernel
let mut envs = Vec::new();
unsafe {
let mut current_env = envp as *const *const u8;
if !current_env.is_null() {
proc.vm.check_read_ptr(current_env)?;
while !(*current_env).is_null() {
let env = proc.vm.check_and_clone_cstr(*current_env)?;
envs.push(env);
current_env = current_env.add(1);
}
if (flags != 0x7d0f00) && (flags != 0x5d0f00) {
//0x5d0f00 is the args from gcc of alpine linux
//warn!("sys_clone only support musl pthread_create");
panic!(
"sys_clone only support sys_fork OR musl pthread_create without flags{:x}",
flags
);
//return Err(SysError::ENOSYS);
}
let parent_tid_ref = unsafe { self.vm().check_write_ptr(parent_tid)? };
let child_tid_ref = unsafe { self.vm().check_write_ptr(child_tid)? };
let new_thread = self
.thread
.clone(self.tf, newsp, newtls, child_tid as usize);
// FIXME: parent pid
let tid = processor().manager().add(new_thread);
processor().manager().detach(tid);
info!("clone: {} -> {}", thread::current().id(), tid);
*parent_tid_ref = tid as u32;
*child_tid_ref = tid as u32;
Ok(tid)
}
if args.is_empty() {
return Err(SysError::EINVAL);
}
info!(
"exec: name: {:?}, args: {:?}, envp: {:?}",
exec_name, args, envs
);
// Read program file
//let path = args[0].as_str();
let exec_path = exec_name.as_str();
let inode = proc.lookup_inode(exec_path)?;
let buf = inode.read_as_vec()?;
// Make new Thread
let mut thread = Thread::new_user(buf.as_slice(), exec_path, args, envs);
thread.proc.lock().clone_for_exec(&proc);
// Activate new page table
unsafe {
thread.proc.lock().vm.activate();
}
// Modify the TrapFrame
*tf = unsafe { thread.context.get_init_tf() };
// Swap Context but keep KStack
::core::mem::swap(&mut current_thread().kstack, &mut thread.kstack);
::core::mem::swap(current_thread(), &mut *thread);
Ok(0)
}
pub fn sys_yield() -> SysResult {
thread::yield_now();
Ok(0)
}
/// Kill the process
pub fn sys_kill(pid: usize, sig: usize) -> SysResult {
info!(
"kill: {} killed: {} with sig {}",
thread::current().id(),
pid,
sig
);
let current_pid = process().pid.get().clone();
if current_pid == pid {
// killing myself
sys_exit_group(sig);
} else {
if let Some(proc_arc) = PROCESSES.read().get(&pid).and_then(|weak| weak.upgrade()) {
let proc = proc_arc.lock();
// quit all threads
for tid in proc.threads.iter() {
processor().manager().exit(*tid, sig);
}
// notify parent and fill exit code
// avoid deadlock
let proc_parent = proc.parent.clone();
let pid = proc.pid.get();
drop(proc);
if let Some(parent) = proc_parent {
let mut parent = parent.lock();
parent.child_exit_code.insert(pid, sig);
parent.child_exit.notify_one();
}
Ok(0)
/// Wait for the process exit.
/// Return the PID. Store exit code to `wstatus` if it's not null.
pub fn sys_wait4(&mut self, pid: isize, wstatus: *mut i32) -> SysResult {
//info!("wait4: pid: {}, code: {:?}", pid, wstatus);
let wstatus = if !wstatus.is_null() {
Some(unsafe { self.vm().check_write_ptr(wstatus)? })
} else {
Err(SysError::EINVAL)
None
};
#[derive(Debug)]
enum WaitFor {
AnyChild,
Pid(usize),
}
let target = match pid {
-1 | 0 => WaitFor::AnyChild,
p if p > 0 => WaitFor::Pid(p as usize),
_ => unimplemented!(),
};
loop {
let mut proc = self.process();
// check child_exit_code
let find = match target {
WaitFor::AnyChild => proc
.child_exit_code
.iter()
.next()
.map(|(&pid, &code)| (pid, code)),
WaitFor::Pid(pid) => proc.child_exit_code.get(&pid).map(|&code| (pid, code)),
};
// if found, return
if let Some((pid, exit_code)) = find {
proc.child_exit_code.remove(&pid);
if let Some(wstatus) = wstatus {
*wstatus = exit_code as i32;
}
return Ok(pid);
}
// if not, check pid
let children: Vec<_> = proc
.children
.iter()
.filter_map(|weak| weak.upgrade())
.collect();
let invalid = match target {
WaitFor::AnyChild => children.len() == 0,
WaitFor::Pid(pid) => children
.iter()
.find(|p| p.lock().pid.get() == pid)
.is_none(),
};
if invalid {
return Err(SysError::ECHILD);
}
info!(
"wait: thread {} -> {:?}, sleep",
thread::current().id(),
target
);
let condvar = proc.child_exit.clone();
condvar.wait(proc);
}
}
}
/// Get the current process id
pub fn sys_getpid() -> SysResult {
info!("getpid");
Ok(process().pid.get())
}
/// Replaces the current ** process ** with a new process image
///
/// `argv` is an array of argument strings passed to the new program.
/// `envp` is an array of strings, conventionally of the form `key=value`,
/// which are passed as environment to the new program.
///
/// NOTICE: `argv` & `envp` can not be NULL (different from Linux)
///
/// NOTICE: for multi-thread programs
/// A call to any exec function from a process with more than one thread
/// shall result in all threads being terminated and the new executable image
/// being loaded and executed.
pub fn sys_exec(
&mut self,
path: *const u8,
argv: *const *const u8,
envp: *const *const u8,
) -> SysResult {
info!(
"exec:BEG: path: {:?}, argv: {:?}, envp: {:?}",
path, argv, envp
);
let mut proc = self.process();
let path = unsafe { self.vm().check_and_clone_cstr(path)? };
let args = unsafe { self.vm().check_and_clone_cstr_array(argv)? };
let envs = unsafe { self.vm().check_and_clone_cstr_array(envp)? };
/// Get the current thread id
pub fn sys_gettid() -> SysResult {
info!("gettid");
// use pid as tid for now
Ok(thread::current().id())
}
if args.is_empty() {
error!("exec: args is null");
return Err(SysError::EINVAL);
}
/// Get the parent process id
pub fn sys_getppid() -> SysResult {
if let Some(ref parent) = process().parent.as_ref() {
Ok(parent.lock().pid.get())
} else {
info!(
"exec:STEP2: path: {:?}, args: {:?}, envs: {:?}",
path, args, envs
);
// Kill other threads
proc.threads.retain(|&tid| {
if tid != processor().tid() {
processor().manager().exit(tid, 1);
}
tid == processor().tid()
});
// Read program file
let inode = proc.lookup_inode(&path)?;
// Make new Thread
let (mut vm, entry_addr, ustack_top) =
Thread::new_user_vm(&inode, &path, args, envs).map_err(|_| SysError::EINVAL)?;
// Activate new page table
core::mem::swap(&mut *self.vm(), &mut vm);
unsafe {
self.vm().activate();
}
// Modify exec path
proc.exec_path = path.clone();
drop(proc);
// Modify the TrapFrame
*self.tf = TrapFrame::new_user_thread(entry_addr, ustack_top);
info!("exec:END: path: {:?}", path);
Ok(0)
}
}
/// Exit the current thread
pub fn sys_exit(exit_code: usize) -> ! {
let tid = thread::current().id();
info!("exit: {}, code: {}", tid, exit_code);
let mut proc = process();
proc.threads.retain(|&id| id != tid);
pub fn sys_yield(&mut self) -> SysResult {
thread::yield_now();
Ok(0)
}
// for last thread,
// notify parent and fill exit code
// avoid deadlock
let exit = proc.threads.len() == 0;
let proc_parent = proc.parent.clone();
let pid = proc.pid.get();
drop(proc);
if exit {
/// Kill the process
pub fn sys_kill(&mut self, pid: usize, sig: usize) -> SysResult {
info!(
"kill: {} killed: {} with sig {}",
thread::current().id(),
pid,
sig
);
let current_pid = self.process().pid.get().clone();
if current_pid == pid {
// killing myself
self.sys_exit_group(sig);
} else {
if let Some(proc_arc) = PROCESSES.read().get(&pid).and_then(|weak| weak.upgrade()) {
let proc = proc_arc.lock();
// quit all threads
for tid in proc.threads.iter() {
processor().manager().exit(*tid, sig);
}
// notify parent and fill exit code
// avoid deadlock
let proc_parent = proc.parent.clone();
let pid = proc.pid.get();
drop(proc);
if let Some(parent) = proc_parent {
let mut parent = parent.lock();
parent.child_exit_code.insert(pid, sig);
parent.child_exit.notify_one();
}
Ok(0)
} else {
Err(SysError::EINVAL)
}
}
}
/// Get the current process id
pub fn sys_getpid(&mut self) -> SysResult {
info!("getpid");
Ok(self.process().pid.get())
}
/// Get the current thread id
pub fn sys_gettid(&mut self) -> SysResult {
info!("gettid");
// use pid as tid for now
Ok(thread::current().id())
}
/// Get the parent process id
pub fn sys_getppid(&mut self) -> SysResult {
if let Some(parent) = self.process().parent.as_ref() {
Ok(parent.lock().pid.get())
} else {
Ok(0)
}
}
/// Exit the current thread
pub fn sys_exit(&mut self, exit_code: usize) -> ! {
let tid = thread::current().id();
info!("exit: {}, code: {}", tid, exit_code);
let mut proc = self.process();
proc.threads.retain(|&id| id != tid);
// for last thread,
// notify parent and fill exit code
// avoid deadlock
let exit = proc.threads.len() == 0;
let proc_parent = proc.parent.clone();
let pid = proc.pid.get();
drop(proc);
if exit {
if let Some(parent) = proc_parent {
let mut parent = parent.lock();
parent.child_exit_code.insert(pid, exit_code);
parent.child_exit.notify_one();
}
}
// perform futex wake 1
// ref: http://man7.org/linux/man-pages/man2/set_tid_address.2.html
// FIXME: do it in all possible ways a thread can exit
// it has memory access so we can't move it to Thread::drop?
let mut proc = self.process();
let clear_child_tid = self.thread.clear_child_tid as *mut u32;
if !clear_child_tid.is_null() {
info!("exit: futex {:#?} wake 1", clear_child_tid);
if let Ok(clear_child_tid_ref) = unsafe { self.vm().check_write_ptr(clear_child_tid) } {
*clear_child_tid_ref = 0;
let queue = proc.get_futex(clear_child_tid as usize);
queue.notify_one();
}
}
drop(proc);
processor().manager().exit(tid, exit_code as usize);
processor().yield_now();
unreachable!();
}
/// Exit the current thread group (i.e. process)
pub fn sys_exit_group(&mut self, exit_code: usize) -> ! {
let proc = self.process();
info!("exit_group: {}, code: {}", proc.pid, exit_code);
// quit all threads
for tid in proc.threads.iter() {
processor().manager().exit(*tid, exit_code);
}
// notify parent and fill exit code
// avoid deadlock
let proc_parent = proc.parent.clone();
let pid = proc.pid.get();
drop(proc);
if let Some(parent) = proc_parent {
let mut parent = parent.lock();
parent.child_exit_code.insert(pid, exit_code);
parent.child_exit.notify_one();
}
processor().yield_now();
unreachable!();
}
// perform futex wake 1
// ref: http://man7.org/linux/man-pages/man2/set_tid_address.2.html
// FIXME: do it in all possible ways a thread can exit
// it has memory access so we can't move it to Thread::drop?
let clear_child_tid = current_thread().clear_child_tid;
if clear_child_tid != 0 {
unsafe {
(clear_child_tid as *mut u32).write(0);
}
let queue = process().get_futex(clear_child_tid);
queue.notify_one();
pub fn sys_nanosleep(&mut self, req: *const TimeSpec) -> SysResult {
let time = unsafe { *self.vm().check_read_ptr(req)? };
info!("nanosleep: time: {:#?}", time);
// TODO: handle spurious wakeup
thread::sleep(time.to_duration());
Ok(0)
}
processor().manager().exit(tid, exit_code as usize);
processor().yield_now();
unreachable!();
}
/// Exit the current thread group (i.e. process)
pub fn sys_exit_group(exit_code: usize) -> ! {
let proc = process();
info!("exit_group: {}, code: {}", proc.pid, exit_code);
// quit all threads
for tid in proc.threads.iter() {
processor().manager().exit(*tid, exit_code);
pub fn sys_set_priority(&mut self, priority: usize) -> SysResult {
let pid = thread::current().id();
processor().manager().set_priority(pid, priority as u8);
Ok(0)
}
// notify parent and fill exit code
// avoid deadlock
let proc_parent = proc.parent.clone();
let pid = proc.pid.get();
drop(proc);
if let Some(parent) = proc_parent {
let mut parent = parent.lock();
parent.child_exit_code.insert(pid, exit_code);
parent.child_exit.notify_one();
pub fn sys_set_tid_address(&mut self, tidptr: *mut u32) -> SysResult {
info!("set_tid_address: {:?}", tidptr);
self.thread.clear_child_tid = tidptr as usize;
Ok(thread::current().id())
}
processor().yield_now();
unreachable!();
}
pub fn sys_nanosleep(req: *const TimeSpec) -> SysResult {
process().vm.check_read_ptr(req)?;
let time = unsafe { req.read() };
info!("nanosleep: time: {:#?}", time);
// TODO: handle spurious wakeup
thread::sleep(time.to_duration());
Ok(0)
}
pub fn sys_set_priority(priority: usize) -> SysResult {
let pid = thread::current().id();
processor().manager().set_priority(pid, priority as u8);
Ok(0)
}
bitflags! {

View File

@ -5,6 +5,80 @@ use crate::consts::USEC_PER_TICK;
use core::time::Duration;
use lazy_static::lazy_static;
impl Syscall<'_> {
pub fn sys_gettimeofday(&mut self, tv: *mut TimeVal, tz: *const u8) -> SysResult {
info!("gettimeofday: tv: {:?}, tz: {:?}", tv, tz);
if tz as usize != 0 {
return Err(SysError::EINVAL);
}
let tv = unsafe { self.vm().check_write_ptr(tv)? };
let timeval = TimeVal::get_epoch();
*tv = timeval;
Ok(0)
}
pub fn sys_clock_gettime(&mut self, clock: usize, ts: *mut TimeSpec) -> SysResult {
info!("clock_gettime: clock: {:?}, ts: {:?}", clock, ts);
let ts = unsafe { self.vm().check_write_ptr(ts)? };
let timespec = TimeSpec::get_epoch();
*ts = timespec;
Ok(0)
}
pub fn sys_time(&mut self, time: *mut u64) -> SysResult {
let sec = get_epoch_usec() / USEC_PER_SEC;
if time as usize != 0 {
let time = unsafe { self.vm().check_write_ptr(time)? };
*time = sec as u64;
}
Ok(sec as usize)
}
pub fn sys_getrusage(&mut self, who: usize, rusage: *mut RUsage) -> SysResult {
info!("getrusage: who: {}, rusage: {:?}", who, rusage);
let rusage = unsafe { self.vm().check_write_ptr(rusage)? };
let tick_base = *TICK_BASE;
let tick = unsafe { crate::trap::TICK as u64 };
let usec = (tick - tick_base) * USEC_PER_TICK as u64;
let new_rusage = RUsage {
utime: TimeVal {
sec: (usec / USEC_PER_SEC) as usize,
usec: (usec % USEC_PER_SEC) as usize,
},
stime: TimeVal {
sec: (usec / USEC_PER_SEC) as usize,
usec: (usec % USEC_PER_SEC) as usize,
},
};
*rusage = new_rusage;
Ok(0)
}
pub fn sys_times(&mut self, buf: *mut Tms) -> SysResult {
info!("times: buf: {:?}", buf);
let buf = unsafe { self.vm().check_write_ptr(buf)? };
let tick_base = *TICK_BASE;
let tick = unsafe { crate::trap::TICK as u64 };
let new_buf = Tms {
tms_utime: 0,
tms_stime: 0,
tms_cutime: 0,
tms_cstime: 0,
};
*buf = new_buf;
Ok(tick as usize)
}
}
/// should be initialized together
lazy_static! {
pub static ref EPOCH_BASE: u64 = crate::arch::timer::read_epoch();
@ -76,47 +150,6 @@ impl TimeSpec {
}
}
pub fn sys_gettimeofday(tv: *mut TimeVal, tz: *const u8) -> SysResult {
info!("gettimeofday: tv: {:?}, tz: {:?}", tv, tz);
if tz as usize != 0 {
return Err(SysError::EINVAL);
}
let proc = process();
proc.vm.check_write_ptr(tv)?;
let timeval = TimeVal::get_epoch();
unsafe {
*tv = timeval;
}
Ok(0)
}
pub fn sys_clock_gettime(clock: usize, ts: *mut TimeSpec) -> SysResult {
info!("clock_gettime: clock: {:?}, ts: {:?}", clock, ts);
let proc = process();
proc.vm.check_write_ptr(ts)?;
let timespec = TimeSpec::get_epoch();
unsafe {
*ts = timespec;
}
Ok(0)
}
pub fn sys_time(time: *mut u64) -> SysResult {
let sec = get_epoch_usec() / USEC_PER_SEC;
if time as usize != 0 {
let proc = process();
proc.vm.check_write_ptr(time)?;
unsafe {
time.write(sec as u64);
}
}
Ok(sec as usize)
}
// ignore other fields for now
#[repr(C)]
pub struct RUsage {
@ -124,27 +157,13 @@ pub struct RUsage {
stime: TimeVal,
}
pub fn sys_getrusage(who: usize, rusage: *mut RUsage) -> SysResult {
info!("getrusage: who: {}, rusage: {:?}", who, rusage);
let proc = process();
proc.vm.check_write_ptr(rusage)?;
let tick_base = *TICK_BASE;
let tick = unsafe { crate::trap::TICK as u64 };
let usec = (tick - tick_base) * USEC_PER_TICK as u64;
let new_rusage = RUsage {
utime: TimeVal {
sec: (usec / USEC_PER_SEC) as usize,
usec: (usec % USEC_PER_SEC) as usize,
},
stime: TimeVal {
sec: (usec / USEC_PER_SEC) as usize,
usec: (usec % USEC_PER_SEC) as usize,
},
};
unsafe { *rusage = new_rusage };
Ok(0)
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Tms {
tms_utime: u64, /* user time */
tms_stime: u64, /* system time */
tms_cutime: u64, /* user time of children */
tms_cstime: u64, /* system time of children */
}

View File

@ -1,3 +1,4 @@
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum ConsoleColor {
Black,

View File

@ -1,6 +1,8 @@
//! ANSI escape sequences parser
//! (ref: https://en.wikipedia.org/wiki/ANSI_escape_code)
#![allow(dead_code)]
use super::color::ConsoleColor;
use heapless::consts::U8;
use heapless::Vec;

1
tests/.gitignore vendored
View File

@ -1 +1,2 @@
stdout
stdout.new

View File

@ -13,7 +13,9 @@ do
wait $pid
diff -I 'bbl loader' -I 'Hello RISCV! in hart' -u ${f%.cmd}.out stdout || { echo 'testing failed for' $f; exit 1; }
awk 'NR > 25 { print }' < stdout > stdout.new
diff -u ${f%.cmd}.out stdout.new || { echo 'testing failed for' $f; exit 1; }
echo testing $f pass
done

0
tools/addr2line.py Normal file → Executable file
View File

829
tools/k210/kflash.py Executable file

File diff suppressed because one or more lines are too long

View File

@ -2,8 +2,12 @@
These are binary release of OpenSBI on this [commit](https://github.com/riscv/opensbi/tree/194dbbe5a13dff2255411c26d249f3ad4ef42c0b) at 2019.04.15.
- fu540.elf: opensbi-0.3-rv64-bin/platform/sifive/fu540/firmware/fw_jump.elf
- virt_rv32.elf: opensbi-0.3-rv32-bin/platform/qemu/virt/firmware/fw_jump.elf
- virt_rv64.elf: opensbi-0.3-rv64-bin/platform/qemu/virt/firmware/fw_jump.elf
NOTE: The [official v0.3 release](https://github.com/riscv/opensbi/releases/tag/v0.3) has bug on serial interrupt.
NOTE: The [official v0.3 release](https://github.com/riscv/opensbi/releases/tag/v0.3) has bug on serial interrupt. Also, Rocket-Chip based CPUs (including SiFive Unleashed) seem to have unintended behavior on
For K210 & SiFive Unleashed: It needs some modification. The binary is from this [commit](https://github.com/rcore-os/opensbi/commit/a9638d092756975ceb50073d736a17cef439c7b6).
* k210.elf: build/platform/kendryte/k210/firmware/fw_payload.elf
* fu540.elf: build/platform/sifive/fu540/firmware/fw_jump.elf

Binary file not shown.

BIN
tools/opensbi/k210.elf Executable file

Binary file not shown.

2
user

@ -1 +1 @@
Subproject commit 8dbc0edb935a62d748aaac39258d4a985de0ae17
Subproject commit bb73d6ecce1ab0e6fae692c51e4335772b0335d4