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:
commit
5be9ae7775
@ -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)
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
108
crate/memory/src/memory_set/handler/file.rs
Normal file
108
crate/memory/src/memory_set/handler/file.rs
Normal 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()
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
1
docs/rcore-structures.drawio
Normal file
1
docs/rcore-structures.drawio
Normal file
File diff suppressed because one or more lines are too long
13
kernel/Cargo.lock
generated
13
kernel/Cargo.lock
generated
@ -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"
|
||||
|
@ -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" }
|
||||
|
@ -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)
|
||||
|
@ -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!");
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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!");
|
||||
}
|
||||
|
@ -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!");
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
49
kernel/src/arch/riscv32/board/k210/linker.ld
Normal file
49
kernel/src/arch/riscv32/board/k210/linker.ld
Normal 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 = .);
|
||||
}
|
49
kernel/src/arch/riscv32/board/u540/linker.ld
Normal file
49
kernel/src/arch/riscv32/board/u540/linker.ld
Normal 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 = .);
|
||||
}
|
@ -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:
|
||||
|
||||
|
@ -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:
|
||||
|
||||
|
30
kernel/src/arch/riscv32/boot/entry_k210.asm
Normal file
30
kernel/src/arch/riscv32/boot/entry_k210.asm
Normal 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:
|
@ -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 ???
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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"));
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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
36
kernel/src/fs/ioctl.rs
Normal 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;
|
@ -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")]
|
||||
{
|
||||
|
@ -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
78
kernel/src/fs/pseudo.rs
Normal 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!();
|
||||
}
|
@ -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(())
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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>;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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! {
|
||||
|
@ -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 */
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
pub enum ConsoleColor {
|
||||
Black,
|
||||
|
@ -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
1
tests/.gitignore
vendored
@ -1 +1,2 @@
|
||||
stdout
|
||||
stdout.new
|
||||
|
@ -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
0
tools/addr2line.py
Normal file → Executable file
829
tools/k210/kflash.py
Executable file
829
tools/k210/kflash.py
Executable file
File diff suppressed because one or more lines are too long
@ -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
BIN
tools/opensbi/k210.elf
Executable file
Binary file not shown.
2
user
2
user
@ -1 +1 @@
|
||||
Subproject commit 8dbc0edb935a62d748aaac39258d4a985de0ae17
|
||||
Subproject commit bb73d6ecce1ab0e6fae692c51e4335772b0335d4
|
Loading…
Reference in New Issue
Block a user