Merge branch 'dev' of github.com:rcore-os/rCore into dev

master
Jackey-Huo 6 years ago
commit 2d047c67be

3
.gitmodules vendored

@ -1,6 +1,3 @@
[submodule "riscv-pk"]
path = riscv-pk
url = https://github.com/rcore-os/riscv-pk.git
[submodule "user"]
path = user
url = https://github.com/rcore-os/rcore-user.git

@ -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
}
}

@ -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,7 +34,7 @@ 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);
}
@ -37,8 +42,10 @@ pub trait FrameAllocator: Debug + Clone + 'static {
mod byframe;
mod delay;
mod linear;
mod file;
//mod swap;
pub use self::byframe::ByFrame;
pub use self::delay::Delay;
pub use self::linear::Linear;
pub use self::file::{File, Read};

@ -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,13 +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 {
ptr as usize >= self.start_addr && unsafe { ptr.add(count) as usize } <= self.end_addr
/// 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
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.
/// 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 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 null-end C string is within the readable memory, and is valid.
/// If so, clone it to a String.
@ -84,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());
@ -202,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.
@ -281,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);
}
/*
@ -472,20 +507,29 @@ impl<T: InactivePageTable> MemorySet<T> {
None => false,
}
}
}
impl<T: InactivePageTable> Clone for MemorySet<T> {
fn clone(&self) -> Self {
let mut page_table = T::new();
pub fn clone(&mut self) -> Self {
let new_page_table = T::new();
let Self {
ref mut page_table,
ref areas,
..
} = self;
page_table.edit(|pt| {
// without CoW, we should allocate the pages eagerly
for area in self.areas.iter() {
area.map_eager(pt);
for area in areas.iter() {
for page in Page::range_of(area.start_addr, area.end_addr) {
area.handler.clone_map(
pt,
&|f| unsafe { new_page_table.with(f) },
page.start_address(),
&area.attr,
);
}
}
});
MemorySet {
areas: self.areas.clone(),
page_table,
areas: areas.clone(),
page_table: new_page_table,
}
}
}

File diff suppressed because one or more lines are too long

6
kernel/Cargo.lock generated

@ -402,12 +402,12 @@ dependencies = [
[[package]]
name = "rcore-fs"
version = "0.1.0"
source = "git+https://github.com/rcore-os/rcore-fs#64d399fe664927f14853c22943a4bdeb34095f99"
source = "git+https://github.com/rcore-os/rcore-fs#6f282baf2fe928d2c9774e526e63125684855221"
[[package]]
name = "rcore-fs-sfs"
version = "0.1.0"
source = "git+https://github.com/rcore-os/rcore-fs#64d399fe664927f14853c22943a4bdeb34095f99"
source = "git+https://github.com/rcore-os/rcore-fs#6f282baf2fe928d2c9774e526e63125684855221"
dependencies = [
"bitvec 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -426,7 +426,7 @@ dependencies = [
[[package]]
name = "rcore-thread"
version = "0.1.0"
source = "git+https://github.com/rcore-os/rcore-thread#7236bfd2e2bde673773214739695bb2925a77ae5"
source = "git+https://github.com/rcore-os/rcore-thread#fd972c7e3aa2b7618f625f143655c16adfd2ca78"
dependencies = [
"deque 0.3.2 (git+https://github.com/rcore-os/deque.git?branch=no_std)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",

@ -19,9 +19,12 @@ authors = [
]
[features]
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"]
@ -37,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

@ -25,16 +25,19 @@
# board = none Running on QEMU
# | 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
mode ?= debug
LOG ?= debug
mode ?= release
LOG ?=
graphic ?= off
smp ?= 4
pci_passthru ?=
@ -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,7 +127,9 @@ endif
else ifeq ($(arch), riscv32)
qemu_opts += \
-machine virt \
-kernel $(kernel_img) \
-serial mon:stdio \
-kernel ../tools/opensbi/virt_rv32.elf \
-device loader,addr=0x80400000,file=$(kernel_img) \
-drive file=$(SFSIMG),format=qcow2,id=sfs \
-device virtio-blk-device,drive=sfs
qemu_net_opts += \
@ -132,11 +137,21 @@ qemu_net_opts += \
-device virtio-net-device,netdev=net0
else ifeq ($(arch), riscv64)
ifeq ($(board), u540)
qemu_opts += \
-machine virt \
-kernel $(kernel_img) \
-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 \
-device virtio-blk-device,drive=sfs
endif
qemu_net_opts += \
-netdev type=tap,id=net0,script=no,downscript=no \
-device virtio-net-device,netdev=net0
@ -192,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)
@ -297,28 +309,8 @@ ifeq ($(need_bootloader), true)
endif
$(kernel_img): kernel $(bootloader)
ifeq ($(arch), riscv32)
@mkdir -p target/$(target)/bbl && \
cd target/$(target)/bbl && \
$(bbl_path)/configure \
$(riscv_pk_args) \
--with-arch=rv32imac \
--disable-fp-emulation \
--host=riscv64-unknown-elf \
--with-payload=$(abspath $(kernel)) && \
make -j && \
cp bbl $(abspath $@)
else ifeq ($(arch), riscv64)
@mkdir -p target/$(target)/bbl && \
cd target/$(target)/bbl && \
$(bbl_path)/configure \
$(riscv_pk_args) \
--with-arch=rv64imac \
--disable-fp-emulation \
--host=riscv64-unknown-elf \
--with-payload=$(abspath $(kernel)) && \
make -j && \
cp bbl $(abspath $@)
ifeq ($(arch), $(filter $(arch), riscv32 riscv64))
@$(objcopy) $(kernel) --strip-all -O binary $@
else ifeq ($(arch), aarch64)
ifneq ($(u_boot), )
@cp $(u_boot) $@
@ -335,13 +327,12 @@ kernel: $(dtb)
ifeq ($(arch), x86_64)
@bootimage build $(build_args)
@mv target/x86_64/bootimage.bin $(bootimage)
else ifeq ($(arch), riscv32)
@-patch -p0 -N -b \
$(shell rustc --print sysroot)/lib/rustlib/src/rust/src/libcore/sync/atomic.rs \
src/arch/riscv32/atomic.patch
@cargo xbuild $(build_args)
else ifeq ($(arch), riscv64)
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
@ -383,10 +374,19 @@ endif
ifeq ($(board), u540)
.PHONY:
install: $(kernel_img)
@$(objcopy) -S -O binary --change-addresses -0x80000000 $< $(build_path)/bin
@../tools/u540/mkimg.sh $(build_path)/bin $(build_path)/sd.img
@$(objcopy) -S -O binary ../tools/opensbi/fu540.elf $(build_path)/bin
@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)

@ -1,62 +0,0 @@
virtqueue_pop
virtio_blk_req_complete
virtio_blk_rw_complete
virtio_blk_submit_multireq
virtio_blk_handle_write
virtio_blk_handle_read
e1000e_link_status
e1000e_mac_set_sw
e1000e_irq_itr_set
e1000e_irq_eitr_set
e1000e_tx_disabled
e1000e_tx_descr
e1000e_rx_descr
#e1000e_rx_has_buffers
e1000e_rx_start_recv
#e1000e_rx_can_recv
e1000e_rx_can_recv_rings_full
e1000_receiver_overrun
#e1000e_rx_receive_iov
e1000e_core_ctrl_sw_reset
e1000e_core_ctrl_phy_reset
e1000e_rx_desc_buff_sizes
e1000e_rx_set_rctl
e1000e_rx_desc_len
e1000e_core_ctrl_write
e1000e_link_status_changed
e1000e_rx_rss_dispatched_to_queue
e1000e_rx_desc_buff_write
e1000e_rx_null_descriptor
e1000e_rx_set_rdt
e1000e_msix_use_vector_fail
e1000e_msix_init_fail
e1000e_msi_init_fail
e1000e_cb_pci_uninit
e1000e_cfg_support_virtio
e1000e_irq_msi_notify_postponed
e1000e_irq_msix_notify_postponed_vec
e1000e_irq_throttling_no_pending_vec
e1000e_irq_msix_notify_vec
e1000e_wrn_msix_vec_wrong
e1000e_wrn_msix_invalid
e1000e_irq_iam_clear_eiame
e1000e_irq_icr_clear_eiac
e1000e_irq_msi_notify
pci_update_mappings_del
pci_update_mappings_add
e1000e_irq_icr_write
e1000e_irq_icr_read_entry
e1000e_irq_legacy_notify
e1000e_irq_add_msi_other
e1000e_irq_pending_interrupts
e1000e_irq_icr_write
e1000e_irq_msix_notify_vec
e1000e_wrn_msix_vec_wrong
e1000e_wrn_msix_invalid
e1000e_irq_iam_clear_eiame
e1000e_irq_icr_clear_eiac
e1000e_irq_postponed_by_xitr
e1000e_intrmgr_rearm_timer
msix_*
#ahci_*
ide_*

@ -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;

@ -7,22 +7,23 @@
.globl switch_context
.extern _root_page_table_ptr
.extern _cur_kstack_ptr
.extern _cur_tls
switch_context:
// save from's registers
addi sp, sp, (-4*14)
sw sp, 0(a0)
sw ra, 0(sp)
sw s0, 2*4(sp)
sw s1, 3*4(sp)
sw s2, 4*4(sp)
sw s3, 5*4(sp)
sw s4, 6*4(sp)
sw s5, 7*4(sp)
sw s6, 8*4(sp)
sw s7, 9*4(sp)
sw s8, 10*4(sp)
sw gp, 11*4(sp)
sw s0, 4*4(sp)
sw s1, 5*4(sp)
sw s2, 6*4(sp)
sw s3, 7*4(sp)
sw s4, 8*4(sp)
sw s5, 9*4(sp)
sw s6, 10*4(sp)
sw s7, 11*4(sp)
sw s8, 12*4(sp)
sw gp, 13*4(sp)
// sw ra, 12*4(sp)
// sw sp, 13*4(sp)
@ -31,27 +32,34 @@ switch_context:
lw s1, 0(s0)
sw s1, 4(sp)
// save TLS
la s2, _cur_tls
lw s1, 0(s2)
sw s1, 2*4(sp)
// restore to's registers
lw sp, 0(a1)
// restore page table address
lw s1, 4(sp)
sw s1, 0(s0)
// restore kstack ptr
// la s0, _cur_kstack_ptr
// addi s1, sp, 4 * 14
// sw s1, 0(s0)
// restore TLS
lw s1, 2*4(sp)
sw s1, 0(s2)
mtc0 s1, $4, 2 // cp0.user_local
lw ra, 0(sp)
lw s0, 2*4(sp)
lw s1, 3*4(sp)
lw s2, 4*4(sp)
lw s3, 5*4(sp)
lw s4, 6*4(sp)
lw s5, 7*4(sp)
lw s6, 8*4(sp)
lw s7, 9*4(sp)
lw s8, 10*4(sp)
lw gp, 11*4(sp)
lw s0, 4*4(sp)
lw s1, 5*4(sp)
lw s2, 6*4(sp)
lw s3, 7*4(sp)
lw s4, 8*4(sp)
lw s5, 9*4(sp)
lw s6, 10*4(sp)
lw s7, 11*4(sp)
lw s8, 12*4(sp)
lw gp, 13*4(sp)
addi sp, sp, (4*14)
sw zero, 0(a1)

@ -177,3 +177,6 @@ _root_page_table_ptr:
.global _cur_kstack_ptr
_cur_kstack_ptr:
.space 4 # 4bytes
.global _cur_tls
_cur_tls:
.space 4 # 4bytes

@ -1,8 +0,0 @@
//! Workaround for missing compiler-builtin symbols
//!
//! [atomic](http://llvm.org/docs/Atomics.html#libcalls-atomic)
#[no_mangle]
pub extern "C" fn abort() {
panic!("abort");
}

@ -6,7 +6,8 @@ pub const KERNEL_OFFSET: usize = 0x80100000;
pub const MEMORY_OFFSET: usize = 0x8000_0000;
pub const USER_STACK_OFFSET: usize = 0x80000000 - USER_STACK_SIZE;
pub const USER_STACK_OFFSET: usize = 0x70000000 - USER_STACK_SIZE;
pub const USER_STACK_SIZE: usize = 0x10000;
pub const USER32_STACK_OFFSET: usize = 0x70000000 - USER_STACK_SIZE;
pub const MAX_DTB_SIZE: usize = 0x2000;

@ -50,8 +50,8 @@ pub struct TrapFrame {
pub sp: usize,
pub fp: usize,
pub ra: usize,
/// Reserve space for hartid
pub _hartid: usize,
/// Reserved
pub reserved: usize,
}
impl TrapFrame {
@ -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;
@ -120,6 +120,7 @@ impl InitStack {
extern "C" {
fn trap_return();
fn _cur_tls();
}
/// Saved registers for kernel context switches.
@ -130,17 +131,21 @@ struct ContextData {
ra: usize,
/// Page table token
satp: usize,
/// Callee-saved registers
/// s[0] = TLS
/// s[1] = reserved
/// s[2..11] = Callee-saved registers
s: [usize; 12],
}
impl ContextData {
fn new(satp: usize) -> Self {
ContextData {
fn new(satp: usize, tls: usize) -> Self {
let mut context = ContextData {
ra: trap_return as usize,
satp,
satp: satp,
..ContextData::default()
}
};
context.s[0] = tls;
context
}
}
@ -191,7 +196,7 @@ impl Context {
);
InitStack {
context: ContextData::new(satp),
context: ContextData::new(satp, 0),
tf: TrapFrame::new_kernel_thread(entry, arg, kstack_top),
}
.push_at(kstack_top)
@ -214,7 +219,7 @@ impl Context {
);
InitStack {
context: ContextData::new(satp),
context: ContextData::new(satp, 0),
tf: TrapFrame::new_user_thread(entry_addr, ustack_top),
}
.push_at(kstack_top)
@ -226,8 +231,9 @@ impl Context {
/// The SATP register will be set to `satp`.
/// All the other registers are same as the original.
pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, satp: usize) -> Self {
let tls = unsafe { *(_cur_tls as *const usize) };
InitStack {
context: ContextData::new(satp),
context: ContextData::new(satp, tls),
tf: {
let mut tf = tf.clone();
// fork function's ret value, the new process is 0
@ -253,20 +259,14 @@ impl Context {
tls: usize,
) -> Self {
InitStack {
context: ContextData::new(satp),
context: ContextData::new(satp, tls),
tf: {
let mut tf = tf.clone();
tf.sp = ustack_top; // sp
tf.v1 = tls;
tf.v0 = 0; // return value
tf
},
}
.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,5 +1,6 @@
use crate::consts::MAX_CPU_NUM;
use core::ptr::{read_volatile, write_volatile};
use mips::instructions;
use mips::registers::cp0;
static mut STARTED: [bool; MAX_CPU_NUM] = [false; MAX_CPU_NUM];
@ -21,7 +22,9 @@ pub unsafe fn start_others(hart_mask: usize) {
}
pub fn halt() {
/* nothing to do */
unsafe {
instructions::wait();
}
}
pub unsafe fn exit_in_qemu(error_code: u8) -> ! {

@ -70,6 +70,17 @@ pub extern "C" fn rust_trap(tf: &mut TrapFrame) {
E::TLBModification => page_fault(tf),
E::TLBLoadMiss => page_fault(tf),
E::TLBStoreMiss => page_fault(tf),
E::ReservedInstruction => {
if !reserved_inst(tf) {
error!("Unhandled Exception @ CPU{}: {:?} ", 0, tf.cause.cause());
crate::trap::error(tf)
} else {
tf.epc = tf.epc + 4;
}
}
E::CoprocessorUnusable => {
tf.epc = tf.epc + 4;
}
_ => {
error!("Unhandled Exception @ CPU{}: {:?} ", 0, tf.cause.cause());
crate::trap::error(tf)
@ -149,6 +160,75 @@ fn syscall(tf: &mut TrapFrame) {
}
}
fn set_trapframe_register(rt: usize, val: usize, tf: &mut TrapFrame) {
match rt {
1 => tf.at = val,
2 => tf.v0 = val,
3 => tf.v1 = val,
4 => tf.a0 = val,
5 => tf.a1 = val,
6 => tf.a2 = val,
7 => tf.a3 = val,
8 => tf.t0 = val,
9 => tf.t1 = val,
10 => tf.t2 = val,
11 => tf.t3 = val,
12 => tf.t4 = val,
13 => tf.t5 = val,
14 => tf.t6 = val,
15 => tf.t7 = val,
16 => tf.s0 = val,
17 => tf.s1 = val,
18 => tf.s2 = val,
19 => tf.s3 = val,
20 => tf.s4 = val,
21 => tf.s5 = val,
22 => tf.s6 = val,
23 => tf.s7 = val,
24 => tf.t8 = val,
25 => tf.t9 = val,
26 => tf.k0 = val,
27 => tf.k1 = val,
28 => tf.gp = val,
29 => tf.sp = val,
30 => tf.fp = val,
31 => tf.ra = val,
_ => {
error!("Unknown register {:?} ", rt);
crate::trap::error(tf)
}
}
}
fn reserved_inst(tf: &mut TrapFrame) -> bool {
let inst = unsafe { *(tf.epc as *const usize) };
let opcode = inst >> 26;
let rt = (inst >> 16) & 0b11111;
let rd = (inst >> 11) & 0b11111;
let sel = (inst >> 6) & 0b111;
let format = inst & 0b111111;
if opcode == 0b011111 && format == 0b111011 {
// RDHWR
if rd == 29 && sel == 0 {
extern "C" {
fn _cur_tls();
}
let tls = unsafe { *(_cur_tls as *const usize) };
set_trapframe_register(rt, tls, tf);
info!("Read TLS by rdhdr {:x} to register {:?}", tls, rt);
return true;
} else {
return false;
}
}
false
}
fn page_fault(tf: &mut TrapFrame) {
// TODO: set access/dirty bit
let addr = tf.vaddr;
@ -164,6 +244,19 @@ fn page_fault(tf: &mut TrapFrame) {
tlb_entry.entry_lo0.get_pfn() << 12,
tlb_entry.entry_lo1.get_pfn() << 12
);
let tlb_valid = if virt_addr.page_number() & 1 == 0 {
tlb_entry.entry_lo0.valid()
} else {
tlb_entry.entry_lo1.valid()
};
if !tlb_valid {
if !crate::memory::handle_page_fault(addr) {
crate::trap::error(tf);
}
}
tlb::write_tlb_random(tlb_entry)
}
Err(()) => {

@ -1,4 +1,3 @@
pub mod compiler_rt;
pub mod consts;
pub mod cpu;
pub mod driver;

@ -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 = .);
}

@ -6,7 +6,7 @@
OUTPUT_ARCH(riscv)
ENTRY(_start)
BASE_ADDRESS = 0xffffffffc0020000;
BASE_ADDRESS = 0xffffffffc0200000;
SECTIONS
{

@ -4,7 +4,7 @@ use super::consts::KERNEL_OFFSET;
pub unsafe fn init_external_interrupt() {
const HART1_S_MODE_INTERRUPT_ENABLES: *mut u64 = (KERNEL_OFFSET + 0x0C00_2100) as *mut u64;
const SERIAL: u64 = 4;
HART1_S_MODE_INTERRUPT_ENABLES.write(1 << SERIAL);
HART1_S_MODE_INTERRUPT_ENABLES.write_volatile(1 << SERIAL);
}
/// Claim and complete external interrupt by reading and writing to
@ -13,7 +13,14 @@ pub unsafe fn handle_external_interrupt() {
const HART1_S_MODE_INTERRUPT_CLAIM_COMPLETE: *mut u32 =
(KERNEL_OFFSET + 0x0C20_2004) as *mut u32;
// claim
let source = HART1_S_MODE_INTERRUPT_CLAIM_COMPLETE.read();
let source = HART1_S_MODE_INTERRUPT_CLAIM_COMPLETE.read_volatile();
// complete
HART1_S_MODE_INTERRUPT_CLAIM_COMPLETE.write(source);
HART1_S_MODE_INTERRUPT_CLAIM_COMPLETE.write_volatile(source);
}
pub unsafe fn enable_serial_interrupt() {
const SERIAL_BASE: *mut u8 = (KERNEL_OFFSET + 0x10010000) as *mut u8;
const UART_REG_IE: usize = 4;
const UART_RXWM: u8 = 0x2;
SERIAL_BASE.add(UART_REG_IE).write_volatile(UART_RXWM);
}

@ -0,0 +1,18 @@
use super::consts::KERNEL_OFFSET;
/// Mask all external interrupt except serial.
pub unsafe fn init_external_interrupt() {
// By default:
// riscv-pk (bbl) enables all S-Mode IRQs (ref: machine/minit.c)
// OpenSBI v0.3 disables all IRQs (ref: platform/common/irqchip/plic.c)
const HART0_S_MODE_INTERRUPT_ENABLES: *mut u32 = (KERNEL_OFFSET + 0x0C00_2080) as *mut u32;
const SERIAL: u32 = 0xa;
HART0_S_MODE_INTERRUPT_ENABLES.write_volatile(1 << SERIAL);
}
pub unsafe fn enable_serial_interrupt() {
const UART16550: *mut u8 = (KERNEL_OFFSET + 0x10000000) as *mut u8;
UART16550.add(4).write_volatile(0x0B);
UART16550.add(1).write_volatile(0x01);
}

@ -1,19 +0,0 @@
.section .text.entry
.globl _start
_start:
add t0, a0, 1
slli t0, t0, 16
lui sp, %hi(bootstack)
addi sp, sp, %lo(bootstack)
add sp, sp, t0
call rust_main
.section .bss.stack
.align 12 #PGSHIFT
.global bootstack
bootstack:
.space 4096 * 16 * 8
.global bootstacktop
bootstacktop:

@ -0,0 +1,55 @@
.section .text.entry
.globl _start
_start:
# a0 == hartid
# pc == 0x80200000
# sp == 0x800xxxxx
# 1. set sp
# sp = bootstack + (hartid + 1) * 0x10000
add t0, a0, 1
slli t0, t0, 14
lui sp, %hi(bootstack)
add sp, sp, t0
# 2. enable paging
# satp = (1 << 31) | PPN(boot_page_table_sv32)
lui t0, %hi(boot_page_table_sv32)
li t1, 0xc0000000 - 0x80000000
sub t0, t0, t1
srli t0, t0, 12
li t1, 1 << 31
or t0, t0, t1
csrw satp, t0
sfence.vma
# 3. 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 * 8
.global bootstacktop
bootstacktop:
.section .data
.align 12 # page align
boot_page_table_sv32:
# NOTE: assume kernel image < 16M
# 0x80000000 -> 0x80000000 (4M * 4)
# 0xc0000000 -> 0x80000000 (4M * 4)
.zero 4 * 512
.word (0x80000 << 10) | 0xcf # VRWXAD
.word (0x80400 << 10) | 0xcf # VRWXAD
.word (0x80800 << 10) | 0xcf # VRWXAD
.word (0x80c00 << 10) | 0xcf # VRWXAD
.zero 4 * 252
.word (0x80000 << 10) | 0xcf # VRWXAD
.word (0x80400 << 10) | 0xcf # VRWXAD
.word (0x80800 << 10) | 0xcf # VRWXAD
.word (0x80c00 << 10) | 0xcf # VRWXAD
.zero 4 * 252

@ -0,0 +1,48 @@
.section .text.entry
.globl _start
_start:
# a0 == hartid
# pc == 0x80200000
# sp == 0x800xxxxx
# 1. set sp
# sp = bootstack + (hartid + 1) * 0x10000
add t0, a0, 1
slli t0, t0, 14
lui sp, %hi(bootstack)
add sp, sp, t0
# 2. enable paging
# satp = (8 << 60) | PPN(boot_page_table_sv39)
lui t0, %hi(boot_page_table_sv39)
li t1, 0xffffffffc0000000 - 0x80000000
sub t0, t0, t1
srli t0, t0, 12
li t1, 8 << 60
or t0, t0, t1
csrw satp, t0
sfence.vma
# 3. 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 * 8
.global bootstacktop
bootstacktop:
.section .data
.align 12 # page align
boot_page_table_sv39:
# 0x00000000_80000000 -> 0x80000000 (1G)
# 0xffffffff_c0000000 -> 0x80000000 (1G)
.quad 0
.quad 0
.quad (0x80000 << 10) | 0xcf # VRWXAD
.zero 8 * 508
.quad (0x80000 << 10) | 0xcf # VRWXAD

@ -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:

@ -6,7 +6,7 @@
OUTPUT_ARCH(riscv)
ENTRY(_start)
BASE_ADDRESS = 0xC0020000;
BASE_ADDRESS = 0xC0400000;
SECTIONS
{

@ -6,7 +6,7 @@
OUTPUT_ARCH(riscv)
ENTRY(_start)
BASE_ADDRESS = 0xffffffffc0020000;
BASE_ADDRESS = 0xffffffffc0200000;
SECTIONS
{

@ -22,17 +22,17 @@ 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;
pub const KERNEL_HEAP_SIZE: usize = 0x00a0_0000;
#[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;
#[cfg(target_arch = "riscv32")]
pub const MEMORY_OFFSET: usize = 0x8000_0000;
#[cfg(target_arch = "riscv64")]
pub const MEMORY_OFFSET: usize = 0x8000_0000;
#[cfg(target_arch = "riscv32")]
pub const MEMORY_END: usize = 0x8100_0000;
#[cfg(target_arch = "riscv64")]
pub const MEMORY_END: usize = 0x8100_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 ???
pub const USER_STACK_OFFSET: usize = 0x80000000 - USER_STACK_SIZE;

@ -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()
}
}

@ -1,8 +1,3 @@
use crate::consts::MAX_CPU_NUM;
use core::ptr::{read_volatile, write_volatile};
static mut STARTED: [bool; MAX_CPU_NUM] = [false; MAX_CPU_NUM];
pub unsafe fn set_cpu_id(cpu_id: usize) {
asm!("mv gp, $0" : : "r"(cpu_id));
}
@ -19,18 +14,6 @@ pub fn send_ipi(cpu_id: usize) {
super::sbi::send_ipi(1 << cpu_id);
}
pub unsafe fn has_started(cpu_id: usize) -> bool {
read_volatile(&STARTED[cpu_id])
}
pub unsafe fn start_others(hart_mask: usize) {
for cpu_id in 0..32 {
if (hart_mask >> cpu_id) & 1 != 0 {
write_volatile(&mut STARTED[cpu_id], true);
}
}
}
pub fn halt() {
unsafe { riscv::asm::wfi() }
}

@ -47,6 +47,3 @@ pub fn getchar_option() -> Option<char> {
pub fn putfmt(fmt: Arguments) {
SerialPort.write_fmt(fmt).unwrap();
}
const TXDATA: *mut u32 = 0x38000000 as *mut u32;
const RXDATA: *mut u32 = 0x38000004 as *mut u32;

@ -8,13 +8,19 @@ 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();
} // Allow user memory access
}
// initialize heap and Frame allocator
init_frame_allocator();
init_heap();
// remap the kernel use 4K page
unsafe {
super::paging::setup_recursive_mapping();
}
remap_the_kernel(dtb);
}
@ -86,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,
@ -93,7 +101,7 @@ fn remap_the_kernel(dtb: usize) {
Linear::new(offset),
"dts",
);
// map PLIC for HiFiveU
// map PLIC for HiFiveU & VirtIO
let offset = -(KERNEL_OFFSET as isize);
ms.push(
KERNEL_OFFSET + 0x0C00_2000,
@ -109,6 +117,22 @@ fn remap_the_kernel(dtb: usize) {
Linear::new(offset),
"plic1",
);
// map UART for HiFiveU
ms.push(
KERNEL_OFFSET + 0x10010000,
KERNEL_OFFSET + 0x10010000 + PAGE_SIZE,
MemoryAttr::default(),
Linear::new(offset),
"uart",
);
// map UART for VirtIO
ms.push(
KERNEL_OFFSET + 0x10000000,
KERNEL_OFFSET + 0x10000000 + PAGE_SIZE,
MemoryAttr::default(),
Linear::new(offset),
"uart16550",
);
unsafe {
ms.activate();
}

@ -1,6 +1,10 @@
#[cfg(feature = "board_u540")]
#[path = "board/u540/mod.rs"]
mod board;
#[cfg(not(feature = "board_u540"))]
#[path = "board/virt/mod.rs"]
mod board;
pub mod compiler_rt;
pub mod consts;
pub mod cpu;
@ -13,19 +17,24 @@ mod sbi;
pub mod syscall;
pub mod timer;
use self::consts::{KERNEL_OFFSET, MEMORY_OFFSET};
use core::sync::atomic::{AtomicBool, Ordering};
use log::*;
#[no_mangle]
pub extern "C" fn rust_main(hartid: usize, dtb: usize, hart_mask: usize) -> ! {
// An initial recursive page table has been set by BBL (shared by all cores)
pub extern "C" fn rust_main(hartid: usize, device_tree_paddr: usize) -> ! {
let device_tree_vaddr = device_tree_paddr - MEMORY_OFFSET + KERNEL_OFFSET;
unsafe {
cpu::set_cpu_id(hartid);
}
if hartid != BOOT_HART_ID {
while unsafe { !cpu::has_started(hartid) } {}
println!("Hello RISCV! in hart {}, dtb @ {:#x}", hartid, dtb);
while !AP_CAN_INIT.load(Ordering::Relaxed) {}
println!(
"Hello RISCV! in hart {}, device tree @ {:#x}",
hartid, device_tree_vaddr
);
others_main();
//other_main -> !
}
@ -34,24 +43,27 @@ pub extern "C" fn rust_main(hartid: usize, dtb: usize, hart_mask: usize) -> ! {
memory::clear_bss();
}
println!("Hello RISCV! in hart {}, dtb @ {:#x}", hartid, dtb);
println!(
"Hello RISCV! in hart {}, device tree @ {:#x}",
hartid, device_tree_vaddr
);
crate::logging::init();
interrupt::init();
memory::init(dtb);
memory::init(device_tree_vaddr);
timer::init();
// FIXME: init driver on u540
#[cfg(not(feature = "board_u540"))]
crate::drivers::init(dtb);
#[cfg(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();
}
crate::process::init();
unsafe {
cpu::start_others(hart_mask);
}
AP_CAN_INIT.store(true, Ordering::Relaxed);
crate::kmain();
}
@ -62,6 +74,8 @@ fn others_main() -> ! {
crate::kmain();
}
static AP_CAN_INIT: AtomicBool = AtomicBool::new(false);
#[cfg(not(feature = "board_u540"))]
const BOOT_HART_ID: usize = 0;
#[cfg(feature = "board_u540")]
@ -94,6 +108,10 @@ global_asm!(
.endm
"
);
global_asm!(include_str!("boot/entry.asm"));
#[cfg(target_arch = "riscv32")]
global_asm!(include_str!("boot/entry32.asm"));
#[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"));

@ -198,7 +198,7 @@ impl InactivePageTable for InactivePageTable0 {
fn start();
fn end();
}
let mut entrys: [PageTableEntry; 16] = unsafe { core::mem::uninitialized() };
let mut entrys: [PageTableEntry; 256] = unsafe { core::mem::uninitialized() };
let entry_start = start as usize >> 22;
let entry_end = (end as usize >> 22) + 1;
let entry_count = entry_end - entry_start;
@ -299,3 +299,13 @@ impl FrameDeallocator for FrameAllocatorForRiscv {
dealloc_frame(frame.start_address().as_usize());
}
}
pub unsafe fn setup_recursive_mapping() {
let frame = satp::read().frame();
let root_page_table = unsafe { &mut *(frame.start_address().as_usize() as *mut RvPageTable) };
root_page_table.set_recursive(RECURSIVE_INDEX, frame);
unsafe {
sfence_vma_all();
}
info!("setup recursive mapping end");
}

@ -1,4 +1,5 @@
//! Port from sbi.h
#![allow(dead_code)]
#[inline(always)]
fn sbi_call(which: usize, arg0: usize, arg1: usize, arg2: usize) -> usize {

@ -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_SIZE: usize = 1024 * 1024; // 1 MB
/// 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;
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

@ -17,22 +17,19 @@ pub fn init() {
static mut CPUS: [Option<Cpu>; MAX_CPU_NUM] = [
// TODO: More elegant ?
None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None,
// None, None, None, None, None, None, None, None,
// None, None, None, None, None, None, None, None,
// None, None, None, None, None, None, None, None,
// None, None, None, None, None, None, None, None,
// None, None, None, None, None, None, None, None,
// None, None, None, None, None, None, None, None,
// None, None, None, None, None, None, None, None,
// None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
None,
// None, None, None, None, None, None, None, None,
// None, None, None, None, None, None, None, None,
// None, None, None, None, None, None, None, None,
// None, None, None, None, None, None, None, None,
// None, None, None, None, None, None, None, None,
// None, None, None, None, None, None, None, None,
// None, None, None, None, None, None, None, None,
// None, None, None, None, None, None, None, None,
];
pub struct Cpu {
@ -42,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(),
@ -75,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,9 +2,7 @@ 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::*;
@ -15,7 +13,6 @@ pub fn init(boot_info: &BootInfo) {
init_frame_allocator(boot_info);
init_device_vm_map();
init_heap();
enlarge_heap();
info!("memory: init end");
}
@ -42,30 +39,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
gdt::init();
// 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();
}

@ -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;

File diff suppressed because it is too large Load Diff

@ -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")
}
}

@ -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;

@ -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;

@ -116,4 +116,8 @@ 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()
}
}

@ -10,12 +10,14 @@ pub use self::file::*;
pub use self::file_like::*;
pub use self::pipe::Pipe;
pub use self::stdio::{STDIN, STDOUT};
pub use self::pseudo::*;
mod device;
mod file;
mod file_like;
mod pipe;
mod stdio;
mod pseudo;
/// Hard link user programs
#[cfg(feature = "link_user")]

@ -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!();
}

@ -20,8 +20,15 @@ impl Stdin {
self.pushed.notify_one();
}
pub fn pop(&self) -> char {
// QEMU v3.0 don't support M-mode external interrupt (bug?)
// So we have to use polling.
#[cfg(feature = "board_k210")]
loop {
// polling
let c = crate::arch::io::getchar();
if c != '\0' {
return c;
}
}
#[cfg(not(feature = "board_k210"))]
loop {
let ret = self.buf.lock().pop_front();
match ret {
@ -43,10 +50,31 @@ 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 {

@ -14,13 +14,12 @@ pub fn init() {
static LOGGER: SimpleLogger = SimpleLogger;
log::set_logger(&LOGGER).unwrap();
log::set_max_level(match option_env!("LOG") {
Some("off") => LevelFilter::Off,
Some("error") => LevelFilter::Error,
Some("warn") => LevelFilter::Warn,
Some("info") => LevelFilter::Info,
Some("debug") => LevelFilter::Debug,
Some("trace") => LevelFilter::Trace,
_ => LevelFilter::Warn,
_ => LevelFilter::Off,
});
}

@ -1,3 +1,17 @@
//! 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;
@ -16,14 +30,22 @@ pub type MemorySet = rcore_memory::memory_set::MemorySet<InactivePageTable0>;
#[cfg(target_arch = "x86_64")]
pub type FrameAlloc = bitmap_allocator::BitAlloc16M;
// RISCV has 8M memory
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
pub type FrameAlloc = bitmap_allocator::BitAlloc4K;
// Raspberry Pi 3 has 1G memory
#[cfg(any(target_arch = "aarch64", target_arch = "mips"))]
// 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;
// K210 has 8M memory
#[cfg(feature = "board_k210")]
pub type FrameAlloc = bitmap_allocator::BitAlloc4K;
lazy_static! {
pub static ref FRAME_ALLOCATOR: SpinNoIrqLock<FrameAlloc> =
SpinNoIrqLock::new(FrameAlloc::default());
@ -77,17 +99,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 +119,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(),
);
}
}

@ -55,7 +55,7 @@ pub trait Socket: Send + Sync {
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 +73,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)
}

@ -5,7 +5,7 @@ use core::ptr::null;
pub struct ProcInitInfo {
pub args: Vec<String>,
pub envs: BTreeMap<String, String>,
pub envs: Vec<String>,
pub auxv: BTreeMap<u8, usize>,
}
@ -19,10 +19,8 @@ impl ProcInitInfo {
let envs: Vec<_> = self
.envs
.iter()
.map(|(key, value)| {
writer.push_str(value.as_str());
writer.push_slice(&[b"="]);
writer.push_slice(key.as_bytes());
.map(|arg| {
writer.push_str(arg.as_str());
writer.sp
})
.collect();

@ -20,45 +20,93 @@ pub fn init() {
}
}
crate::shell::run_user_shell();
crate::shell::add_user_shell();
info!("process: init end");
}
static PROCESSORS: [Processor; MAX_CPU_NUM] = [
// TODO: More elegant ?
Processor::new(), Processor::new(), Processor::new(), Processor::new(),
Processor::new(), Processor::new(), Processor::new(), Processor::new(),
Processor::new(), Processor::new(), Processor::new(), Processor::new(),
Processor::new(), Processor::new(), Processor::new(), Processor::new(),
Processor::new(), Processor::new(), Processor::new(), Processor::new(),
Processor::new(), Processor::new(), Processor::new(), Processor::new(),
Processor::new(), Processor::new(), Processor::new(), Processor::new(),
Processor::new(), Processor::new(), Processor::new(), Processor::new(),
Processor::new(), Processor::new(), Processor::new(), Processor::new(),
Processor::new(), Processor::new(), Processor::new(), Processor::new(),
Processor::new(), Processor::new(), Processor::new(), Processor::new(),
Processor::new(), Processor::new(), Processor::new(), Processor::new(),
Processor::new(), Processor::new(), Processor::new(), Processor::new(),
Processor::new(), Processor::new(), Processor::new(), Processor::new(),
Processor::new(), Processor::new(), Processor::new(), Processor::new(),
Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
// Processor::new(), Processor::new(), Processor::new(), Processor::new(),
];
/// Get current process

@ -14,11 +14,14 @@ 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::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 {
@ -32,41 +35,23 @@ pub struct Thread {
/// 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)
}
}
@ -75,6 +60,7 @@ pub struct Process {
pub vm: MemorySet,
pub files: BTreeMap<usize, FileLike>,
pub cwd: String,
pub exec_path: String,
futexes: BTreeMap<usize, Arc<Condvar>>,
// relationship
@ -103,21 +89,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,10 +100,8 @@ 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()
})
}
@ -142,60 +114,77 @@ impl Thread {
kstack,
clear_child_tid: 0,
// 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<'a, Iter>(data: &[u8], exec_path: &str, args: Iter) -> Box<Thread>
where
Iter: Iterator<Item = &'a str>,
{
/// 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>,
) -> 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
match elf.header.pt2.machine().as_machine() {
#[cfg(target_arch = "x86_64")]
header::Machine::X86_64 => {}
#[cfg(target_arch = "aarch64")]
header::Machine::AArch64 => {}
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
header::Machine::Other(243) => {}
#[cfg(target_arch = "mips")]
header::Machine::Mips => {}
machine @ _ => return Err("invalid ELF arch"),
}
// Check interpreter
// 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() {
debug!("using loader {}", &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
let mut new_args: Vec<&str> = args.collect();
new_args.insert(0, loader_path);
new_args.insert(1, exec_path);
new_args.remove(2);
warn!("loader args: {:?}", new_args);
return Thread::new_user(buf.as_slice(), exec_path,new_args.into_iter());
} else {
warn!("loader specified as {} but failed to read", &loader_path);
}
} else {
warn!("loader specified as {} but not found", &loader_path);
}
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};
@ -204,6 +193,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),
@ -214,8 +211,8 @@ impl Thread {
// Make init info
let init_info = ProcInitInfo {
args: args.map(|s| String::from(s)).collect(),
envs: BTreeMap::new(),
args,
envs,
auxv: {
let mut map = BTreeMap::new();
if let Some(phdr_vaddr) = elf.get_phdr_vaddr() {
@ -233,6 +230,19 @@ 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,
mut 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 kstack = KernelStack::new();
let mut files = BTreeMap::new();
@ -270,66 +280,57 @@ impl Thread {
)),
);
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())
},
kstack,
clear_child_tid: 0,
proc: Arc::new(Mutex::new(Process {
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 mut proc = self.proc.lock();
let kstack = KernelStack::new();
Box::new(Thread {
context: unsafe { Context::new_fork(tf, kstack.top(), vm.token()) },
kstack,
clear_child_tid: 0,
proc: Arc::new(Mutex::new(Process {
let vm = proc.vm.clone();
let context = unsafe { Context::new_fork(tf, kstack.top(), vm.token()) };
let new_proc = Process {
vm,
files,
cwd,
files: proc.files.clone(),
cwd: proc.cwd.clone(),
exec_path: proc.exec_path.clone(),
futexes: BTreeMap::default(),
pid: Pid::uninitialized(),
parent,
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,
kstack,
clear_child_tid: 0,
proc: new_proc,
})
}
@ -353,22 +354,40 @@ impl Thread {
}
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 {
@ -378,10 +397,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
}
}
@ -389,7 +410,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>;
@ -399,7 +420,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();
@ -407,33 +428,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.virtual_addr() as usize,
ph.virtual_addr() as usize + ph.mem_size() as usize,
ph.flags().to_attr(),
ByFrame::new(GlobalFrameAlloc),
"",
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",
);
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
}
@ -475,3 +482,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()
}
}

@ -7,25 +7,46 @@ 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("rust/sh") {
let data = inode.read_as_vec().unwrap();
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(data.as_slice(), "rust/sh", "sh".split(' ')));
.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() {
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(), cmdline.split(' ')));
processor().manager().add(Thread::new_user(
&inode,
cmdline.split(' ').map(|s| s.into()).collect(),
Vec::new(),
));
}
pub extern "C" fn shell(_arg: usize) -> ! {
@ -40,13 +61,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(), &cmd, cmd.split(' ')));
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");
}

@ -43,10 +43,8 @@ pub fn sys_map_pci_device(vendor: usize, product: usize) -> SysResult {
/// 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) };
let vaddrs = unsafe { proc.vm.check_read_array(vaddrs, count)? };
let paddrs = unsafe { proc.vm.check_write_array(paddrs, count)? };
for i in 0..count {
let paddr = proc.vm.translate(vaddrs[i] as usize).unwrap_or(0);
paddrs[i] = paddr as u64;

@ -3,6 +3,7 @@
use core::cell::UnsafeCell;
use core::cmp::min;
use core::mem::size_of;
#[cfg(not(target_arch = "mips"))]
use rcore_fs::vfs::Timespec;
use crate::drivers::SOCKET_ACTIVITY;
@ -20,8 +21,7 @@ pub fn sys_read(fd: usize, base: *mut u8, len: usize) -> SysResult {
// we trust pid 0 process
info!("read: fd: {}, base: {:?}, len: {:#x}", fd, base, len);
}
proc.vm.check_write_array(base, len)?;
let slice = unsafe { slice::from_raw_parts_mut(base, len) };
let slice = unsafe { proc.vm.check_write_array(base, len)? };
let file_like = proc.get_file_like(fd)?;
let len = file_like.read(slice)?;
Ok(len)
@ -33,8 +33,7 @@ pub fn sys_write(fd: usize, base: *const u8, len: usize) -> SysResult {
// we trust pid 0 process
info!("write: fd: {}, base: {:?}, len: {:#x}", fd, base, len);
}
proc.vm.check_read_array(base, len)?;
let slice = unsafe { slice::from_raw_parts(base, len) };
let slice = unsafe { proc.vm.check_read_array(base, len)? };
let file_like = proc.get_file_like(fd)?;
let len = file_like.write(slice)?;
Ok(len)
@ -46,9 +45,7 @@ pub fn sys_pread(fd: usize, base: *mut u8, len: usize, offset: usize) -> SysResu
fd, base, len, offset
);
let mut proc = process();
proc.vm.check_write_array(base, len)?;
let slice = unsafe { slice::from_raw_parts_mut(base, len) };
let slice = unsafe { proc.vm.check_write_array(base, len)? };
let len = proc.get_file(fd)?.read_at(offset, slice)?;
Ok(len)
}
@ -59,9 +56,7 @@ pub fn sys_pwrite(fd: usize, base: *const u8, len: usize, offset: usize) -> SysR
fd, base, len, offset
);
let mut proc = process();
proc.vm.check_read_array(base, len)?;
let slice = unsafe { slice::from_raw_parts(base, len) };
let slice = unsafe { proc.vm.check_read_array(base, len)? };
let len = proc.get_file(fd)?.write_at(offset, slice)?;
Ok(len)
}
@ -71,8 +66,8 @@ pub fn sys_ppoll(ufds: *mut PollFd, nfds: usize, timeout: *const TimeSpec) -> Sy
let timeout_msecs = if timeout.is_null() {
1 << 31 // infinity
} else {
proc.vm.check_read_ptr(timeout)?;
unsafe { (*timeout).to_msec() }
let timeout = unsafe { proc.vm.check_read_ptr(timeout)? };
timeout.to_msec()
};
drop(proc);
@ -80,14 +75,16 @@ pub fn sys_ppoll(ufds: *mut PollFd, nfds: usize, timeout: *const TimeSpec) -> Sy
}
pub fn sys_poll(ufds: *mut PollFd, nfds: usize, timeout_msecs: usize) -> SysResult {
let proc = process();
if !proc.pid.is_init() {
// we trust pid 0 process
info!(
"poll: ufds: {:?}, nfds: {}, timeout_msecs: {:#x}",
ufds, nfds, timeout_msecs
);
let proc = process();
proc.vm.check_write_array(ufds, nfds)?;
}
let polls = unsafe { slice::from_raw_parts_mut(ufds, nfds) };
let polls = unsafe { proc.vm.check_write_array(ufds, nfds)? };
for poll in polls.iter() {
if proc.files.get(&(poll.fd as usize)).is_none() {
return Err(SysError::EINVAL);
@ -152,9 +149,9 @@ pub fn sys_select(
let mut read_fds = FdSet::new(&proc.vm, read, nfds)?;
let mut write_fds = FdSet::new(&proc.vm, write, nfds)?;
let mut err_fds = FdSet::new(&proc.vm, err, nfds)?;
let timeout_msecs = if timeout as usize != 0 {
proc.vm.check_read_ptr(timeout)?;
unsafe { *timeout }.to_msec()
let timeout_msecs = if !timeout.is_null() {
let timeout = unsafe { proc.vm.check_read_ptr(timeout)? };
timeout.to_msec()
} else {
// infinity
1 << 31
@ -169,6 +166,9 @@ pub fn sys_select(
if fd >= nfds {
continue;
}
if !err_fds.contains(fd) && !read_fds.contains(fd) && !write_fds.contains(fd) {
continue;
}
let status = file_like.poll()?;
if status.error && err_fds.contains(fd) {
err_fds.set(fd);
@ -210,7 +210,7 @@ pub fn sys_readv(fd: usize, iov_ptr: *const IoVec, iov_count: usize) -> SysResul
fd, iov_ptr, iov_count
);
let mut proc = process();
let mut iovs = IoVecs::check_and_new(iov_ptr, iov_count, &proc.vm, true)?;
let mut iovs = unsafe { IoVecs::check_and_new(iov_ptr, iov_count, &proc.vm, true)? };
// read all data to a buf
let file_like = proc.get_file_like(fd)?;
@ -222,12 +222,15 @@ pub fn sys_readv(fd: usize, iov_ptr: *const IoVec, iov_count: usize) -> SysResul
}
pub fn sys_writev(fd: usize, iov_ptr: *const IoVec, iov_count: usize) -> SysResult {
let mut proc = process();
if !proc.pid.is_init() {
// we trust pid 0 process
info!(
"writev: fd: {}, iov: {:?}, count: {}",
fd, iov_ptr, iov_count
);
let mut proc = process();
let iovs = IoVecs::check_and_new(iov_ptr, iov_count, &proc.vm, false)?;
}
let iovs = unsafe { IoVecs::check_and_new(iov_ptr, iov_count, &proc.vm, false)? };
let buf = iovs.read_all_to_vec();
let len = buf.len();
@ -253,7 +256,7 @@ pub fn sys_openat(dir_fd: usize, path: *const u8, flags: usize, mode: usize) ->
let inode = if flags.contains(OpenFlags::CREATE) {
let (dir_path, file_name) = split_path(&path);
// relative to cwd
let dir_inode = proc.lookup_inode_at(dir_fd, dir_path)?;
let dir_inode = proc.lookup_inode_at(dir_fd, dir_path, true)?;
match dir_inode.find(file_name) {
Ok(file_inode) => {
if flags.contains(OpenFlags::EXCLUSIVE) {
@ -267,13 +270,11 @@ pub fn sys_openat(dir_fd: usize, path: *const u8, flags: usize, mode: usize) ->
Err(e) => return Err(SysError::from(e)),
}
} else {
proc.lookup_inode_at(dir_fd, &path)?
proc.lookup_inode_at(dir_fd, &path, true)?
};
let fd = proc.get_free_fd();
let file = FileHandle::new(inode, flags.to_options());
proc.files.insert(fd, FileLike::File(file));
let fd = proc.add_file(FileLike::File(file));
Ok(fd)
}
@ -297,10 +298,10 @@ pub fn sys_faccessat(dirfd: usize, path: *const u8, mode: usize, flags: usize) -
// we trust pid 0 process
info!(
"faccessat: dirfd: {}, path: {:?}, mode: {:#o}, flags: {:?}",
dirfd, path, mode, flags
dirfd as isize, path, mode, flags
);
}
let inode = proc.lookup_inode_at(dirfd, &path)?;
let inode = proc.lookup_inode_at(dirfd, &path, !flags.contains(AtFlags::SYMLINK_NOFOLLOW))?;
Ok(0)
}
@ -310,46 +311,41 @@ pub fn sys_getcwd(buf: *mut u8, len: usize) -> SysResult {
// we trust pid 0 process
info!("getcwd: buf: {:?}, len: {:#x}", buf, len);
}
proc.vm.check_write_array(buf, len)?;
let buf = unsafe { proc.vm.check_write_array(buf, len)? };
if proc.cwd.len() + 1 > len {
return Err(SysError::ERANGE);
}
unsafe { util::write_cstr(buf, &proc.cwd) }
Ok(buf as usize)
unsafe { util::write_cstr(buf.as_mut_ptr(), &proc.cwd) }
Ok(buf.as_ptr() as usize)
}
pub fn sys_lstat(path: *const u8, stat_ptr: *mut Stat) -> SysResult {
warn!("lstat is partial implemented as stat");
sys_stat(path, stat_ptr)
sys_fstatat(AT_FDCWD, path, stat_ptr, AtFlags::SYMLINK_NOFOLLOW.bits())
}
pub fn sys_fstat(fd: usize, stat_ptr: *mut Stat) -> SysResult {
info!("fstat: fd: {}, stat_ptr: {:?}", fd, stat_ptr);
let mut proc = process();
proc.vm.check_write_ptr(stat_ptr)?;
let stat_ref = unsafe { proc.vm.check_write_ptr(stat_ptr)? };
let file = proc.get_file(fd)?;
let stat = Stat::from(file.metadata()?);
unsafe {
stat_ptr.write(stat);
}
*stat_ref = stat;
Ok(0)
}
pub fn sys_fstatat(dirfd: usize, path: *const u8, stat_ptr: *mut Stat, flags: usize) -> SysResult {
let proc = process();
let path = unsafe { proc.vm.check_and_clone_cstr(path)? };
proc.vm.check_write_ptr(stat_ptr)?;
let stat_ref = unsafe { proc.vm.check_write_ptr(stat_ptr)? };
let flags = AtFlags::from_bits_truncate(flags);
info!(
"fstatat: dirfd: {}, path: {:?}, stat_ptr: {:?}, flags: {:?}",
dirfd, path, stat_ptr, flags
dirfd as isize, path, stat_ptr, flags
);
let inode = proc.lookup_inode_at(dirfd, &path)?;
let inode = proc.lookup_inode_at(dirfd, &path, !flags.contains(AtFlags::SYMLINK_NOFOLLOW))?;
let stat = Stat::from(inode.metadata()?);
unsafe {
stat_ptr.write(stat);
}
*stat_ref = stat;
Ok(0)
}
@ -364,14 +360,16 @@ pub fn sys_readlink(path: *const u8, base: *mut u8, len: usize) -> SysResult {
pub fn sys_readlinkat(dirfd: usize, path: *const u8, base: *mut u8, len: usize) -> SysResult {
let proc = process();
let path = unsafe { proc.vm.check_and_clone_cstr(path)? };
proc.vm.check_write_array(base, len)?;
info!("readlink: path: {:?}, base: {:?}, len: {}", path, base, len);
let slice = unsafe { proc.vm.check_write_array(base, len)? };
info!(
"readlinkat: dirfd: {}, path: {:?}, base: {:?}, len: {}",
dirfd as isize, path, base, len
);
let inode = proc.lookup_inode_at(dirfd, &path)?;
let inode = proc.lookup_inode_at(dirfd, &path, false)?;
if inode.metadata()?.type_ == FileType::SymLink {
// TODO: recursive link resolution and loop detection
let mut slice = unsafe { slice::from_raw_parts_mut(base, len) };
let len = inode.read_at(0, &mut slice)?;
let len = inode.read_at(0, slice)?;
Ok(len)
} else {
Err(SysError::EINVAL)
@ -425,13 +423,13 @@ pub fn sys_getdents64(fd: usize, buf: *mut LinuxDirent64, buf_size: usize) -> Sy
fd, buf, buf_size
);
let mut proc = process();
proc.vm.check_write_array(buf as *mut u8, buf_size)?;
let buf = unsafe { proc.vm.check_write_array(buf as *mut u8, buf_size)? };
let file = proc.get_file(fd)?;
let info = file.metadata()?;
if info.type_ != FileType::Dir {
return Err(SysError::ENOTDIR);
}
let mut writer = unsafe { DirentBufWriter::new(buf, buf_size) };
let mut writer = DirentBufWriter::new(buf);
loop {
let name = match file.read_entry() {
Err(FsError::EntryNotFound) => break,
@ -459,7 +457,7 @@ pub fn sys_dup2(fd1: usize, fd2: usize) -> SysResult {
pub fn sys_ioctl(fd: usize, request: usize, arg1: usize, arg2: usize, arg3: usize) -> SysResult {
info!(
"ioctl: fd: {}, request: {}, args: {} {} {}",
"ioctl: fd: {}, request: {:x}, args: {} {} {}",
fd, request, arg1, arg2, arg3
);
let mut proc = process();
@ -525,13 +523,13 @@ pub fn sys_renameat(
let newpath = unsafe { proc.vm.check_and_clone_cstr(newpath)? };
info!(
"renameat: olddirfd: {}, oldpath: {:?}, newdirfd: {}, newpath: {:?}",
olddirfd, oldpath, newdirfd, newpath
olddirfd as isize, oldpath, newdirfd as isize, newpath
);
let (old_dir_path, old_file_name) = split_path(&oldpath);
let (new_dir_path, new_file_name) = split_path(&newpath);
let old_dir_inode = proc.lookup_inode_at(olddirfd, old_dir_path)?;
let new_dir_inode = proc.lookup_inode_at(newdirfd, new_dir_path)?;
let old_dir_inode = proc.lookup_inode_at(olddirfd, old_dir_path, false)?;
let new_dir_inode = proc.lookup_inode_at(newdirfd, new_dir_path, false)?;
old_dir_inode.move_(old_file_name, &new_dir_inode, new_file_name)?;
Ok(0)
}
@ -546,11 +544,11 @@ pub fn sys_mkdirat(dirfd: usize, path: *const u8, mode: usize) -> SysResult {
// TODO: check pathname
info!(
"mkdirat: dirfd: {}, path: {:?}, mode: {:#o}",
dirfd, path, mode
dirfd as isize, path, mode
);
let (dir_path, file_name) = split_path(&path);
let inode = proc.lookup_inode_at(dirfd, dir_path)?;
let inode = proc.lookup_inode_at(dirfd, dir_path, true)?;
if inode.find(file_name).is_ok() {
return Err(SysError::EEXIST);
}
@ -590,12 +588,12 @@ pub fn sys_linkat(
let flags = AtFlags::from_bits_truncate(flags);
info!(
"linkat: olddirfd: {}, oldpath: {:?}, newdirfd: {}, newpath: {:?}, flags: {:?}",
olddirfd, oldpath, newdirfd, newpath, flags
olddirfd as isize, oldpath, newdirfd as isize, newpath, flags
);
let (new_dir_path, new_file_name) = split_path(&newpath);
let inode = proc.lookup_inode_at(olddirfd, &oldpath)?;
let new_dir_inode = proc.lookup_inode_at(newdirfd, new_dir_path)?;
let inode = proc.lookup_inode_at(olddirfd, &oldpath, true)?;
let new_dir_inode = proc.lookup_inode_at(newdirfd, new_dir_path, true)?;
new_dir_inode.link(new_file_name, &inode)?;
Ok(0)
}
@ -610,11 +608,11 @@ pub fn sys_unlinkat(dirfd: usize, path: *const u8, flags: usize) -> SysResult {
let flags = AtFlags::from_bits_truncate(flags);
info!(
"unlinkat: dirfd: {}, path: {:?}, flags: {:?}",
dirfd, path, flags
dirfd as isize, path, flags
);
let (dir_path, file_name) = split_path(&path);
let dir_inode = proc.lookup_inode_at(dirfd, dir_path)?;
let dir_inode = proc.lookup_inode_at(dirfd, dir_path, true)?;
let file_inode = dir_inode.find(file_name)?;
if file_inode.metadata()?.type_ == FileType::Dir {
return Err(SysError::EISDIR);
@ -627,39 +625,29 @@ pub fn sys_pipe(fds: *mut u32) -> SysResult {
info!("pipe: fds: {:?}", fds);
let mut proc = process();
proc.vm.check_write_array(fds, 2)?;
let fds = unsafe { proc.vm.check_write_array(fds, 2)? };
let (read, write) = Pipe::create_pair();
let read_fd = proc.get_free_fd();
proc.files.insert(
read_fd,
FileLike::File(FileHandle::new(
let read_fd = proc.add_file(FileLike::File(FileHandle::new(
Arc::new(read),
OpenOptions {
read: true,
write: false,
append: false,
},
)),
);
)));
let write_fd = proc.get_free_fd();
proc.files.insert(
write_fd,
FileLike::File(FileHandle::new(
let write_fd = proc.add_file(FileLike::File(FileHandle::new(
Arc::new(write),
OpenOptions {
read: false,
write: true,
append: false,
},
)),
);
)));
unsafe {
*fds = read_fd as u32;
*(fds.add(1)) = write_fd as u32;
}
fds[0] = read_fd as u32;
fds[1] = write_fd as u32;
info!("pipe: created rfd: {} wfd: {}", read_fd, write_fd);
@ -671,47 +659,32 @@ pub fn sys_sync() -> SysResult {
Ok(0)
}
pub fn sys_sendfile(out_fd: usize, in_fd: usize, offset: *mut usize, count: usize) -> SysResult {
pub fn sys_sendfile(
out_fd: usize,
in_fd: usize,
offset_ptr: *mut usize,
count: usize,
) -> SysResult {
info!(
"sendfile: out: {}, in: {}, offset: {:?}, count: {}",
out_fd, in_fd, offset, count
"sendfile:BEG out: {}, in: {}, offset_ptr: {:?}, count: {}",
out_fd, in_fd, offset_ptr, count
);
let proc = process();
// We know it's save, pacify the borrow checker
let proc_cell = UnsafeCell::new(proc);
let proc_in = unsafe { &mut *proc_cell.get() };
let proc_out = unsafe { &mut *proc_cell.get() };
//let in_file: &mut FileHandle = unsafe { &mut *UnsafeCell::new(proc.get_file(in_fd)?).get() };
//let out_file: &mut FileHandle = unsafe { &mut *UnsafeCell::new(proc.get_file(out_fd)?).get() };
let in_file = proc_in.get_file(in_fd)?;
let out_file = proc_out.get_file(out_fd)?;
let in_file = unsafe { (*proc_cell.get()).get_file(in_fd)? };
let out_file = unsafe { (*proc_cell.get()).get_file(out_fd)? };
let mut buffer = [0u8; 1024];
if offset.is_null() {
// read from current file offset
let mut bytes_read = 0;
while bytes_read < count {
let len = min(buffer.len(), count - bytes_read);
let read_len = in_file.read(&mut buffer[..len])?;
if read_len == 0 {
break;
}
bytes_read += read_len;
let mut bytes_written = 0;
while bytes_written < read_len {
let write_len = out_file.write(&buffer[bytes_written..])?;
if write_len == 0 {
return Err(SysError::EBADF);
}
bytes_written += write_len;
}
}
return Ok(bytes_read);
let mut read_offset = if !offset_ptr.is_null() {
unsafe { *(*proc_cell.get()).vm.check_read_ptr(offset_ptr)? }
} else {
let proc_mem = unsafe { &mut *proc_cell.get() };
proc_mem.vm.check_read_ptr(offset)?;
let mut read_offset = unsafe { *offset };
in_file.seek(SeekFrom::Current(0))? as usize
};
// read from specified offset and write new offset back
let mut bytes_read = 0;
let mut total_written = 0;
while bytes_read < count {
let len = min(buffer.len(), count - bytes_read);
let read_len = in_file.read_at(read_offset, &mut buffer[..len])?;
@ -720,20 +693,36 @@ pub fn sys_sendfile(out_fd: usize, in_fd: usize, offset: *mut usize, count: usiz
}
bytes_read += read_len;
read_offset += read_len;
let mut bytes_written = 0;
let mut rlen = read_len;
while bytes_written < read_len {
let write_len = out_file.write(&buffer[bytes_written..])?;
let write_len = out_file.write(&buffer[bytes_written..(bytes_written + rlen)])?;
if write_len == 0 {
info!(
"sendfile:END_ERR out: {}, in: {}, offset_ptr: {:?}, count: {} = bytes_read {}, bytes_written {}, write_len {}",
out_fd, in_fd, offset_ptr, count, bytes_read, bytes_written, write_len
);
return Err(SysError::EBADF);
}
bytes_written += write_len;
rlen -= write_len;
}
total_written += bytes_written;
}
if !offset_ptr.is_null() {
unsafe {
*offset = read_offset;
offset_ptr.write(read_offset);
}
return Ok(bytes_read);
} else {
in_file.seek(SeekFrom::Current(bytes_read as i64))?;
}
info!(
"sendfile:END out: {}, in: {}, offset_ptr: {:?}, count: {} = bytes_read {}, total_written {}",
out_fd, in_fd, offset_ptr, count, bytes_read, total_written
);
return Ok(total_written);
}
impl Process {
@ -761,13 +750,20 @@ impl Process {
&self,
dirfd: usize,
path: &str,
// follow: bool,
follow: bool,
) -> Result<Arc<INode>, SysError> {
let follow = true;
debug!(
"lookup_inode_at: fd: {:?}, cwd: {:?}, path: {:?}, follow: {:?}",
dirfd, self.cwd, path, follow
"lookup_inode_at: dirfd: {:?}, cwd: {:?}, path: {:?}, follow: {:?}",
dirfd as isize, self.cwd, path, follow
);
// hard code special path
match path {
"/proc/self/exe" => {
return Ok(Arc::new(Pseudo::new(&self.exec_path, FileType::SymLink)));
}
_ => {}
}
let follow_max_depth = if follow { FOLLOW_MAX_DEPTH } else { 0 };
if dirfd == AT_FDCWD {
Ok(ROOT_INODE
@ -783,7 +779,7 @@ impl Process {
}
pub fn lookup_inode(&self, path: &str) -> Result<Arc<INode>, SysError> {
self.lookup_inode_at(AT_FDCWD, path)
self.lookup_inode_at(AT_FDCWD, path, true)
}
}
@ -877,18 +873,20 @@ pub struct LinuxDirent64 {
name: [u8; 0],
}
struct DirentBufWriter {
struct DirentBufWriter<'a> {
buf: &'a mut [u8],
ptr: *mut LinuxDirent64,
rest_size: usize,
written_size: usize,
}
impl DirentBufWriter {
unsafe fn new(buf: *mut LinuxDirent64, size: usize) -> Self {
impl<'a> DirentBufWriter<'a> {
fn new(buf: &'a mut [u8]) -> Self {
DirentBufWriter {
ptr: buf,
rest_size: size,
ptr: buf.as_mut_ptr() as *mut LinuxDirent64,
rest_size: buf.len(),
written_size: 0,
buf,
}
}
fn try_write(&mut self, inode: u64, type_: u8, name: &str) -> bool {
@ -988,7 +986,55 @@ pub struct Stat {
ctime: Timespec,
}
#[cfg(not(target_arch = "x86_64"))]
#[cfg(target_arch = "mips")]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Timespec {
pub sec: i32,
pub nsec: i32,
}
#[cfg(target_arch = "mips")]
#[repr(C)]
#[derive(Debug)]
pub struct Stat {
/// ID of device containing file
dev: u64,
/// padding
__pad1: u64,
/// inode number
ino: u64,
/// file type and mode
mode: StatMode,
/// number of hard links
nlink: u32,
/// user ID of owner
uid: u32,
/// group ID of owner
gid: u32,
/// device ID (if special file)
rdev: u64,
/// padding
__pad2: u64,
/// total size, in bytes
size: u64,
/// last access time
atime: Timespec,
/// last modification time
mtime: Timespec,
/// last status change time
ctime: Timespec,
/// blocksize for filesystem I/O
blksize: u32,
/// padding
__pad3: u32,
/// number of 512B blocks allocated
blocks: u64,
}
#[cfg(not(any(target_arch = "x86_64", target_arch = "mips")))]
#[repr(C)]
#[derive(Debug)]
pub struct Stat {
@ -1117,7 +1163,38 @@ impl From<Metadata> for Stat {
}
}
#[cfg(not(target_arch = "x86_64"))]
#[cfg(target_arch = "mips")]
fn from(info: Metadata) -> Self {
Stat {
dev: info.dev as u64,
ino: info.inode as u64,
mode: StatMode::from_type_mode(info.type_, info.mode as u16),
nlink: info.nlinks as u32,
uid: info.uid as u32,
gid: info.gid as u32,
rdev: 0,
size: info.size as u64,
blksize: info.blk_size as u32,
blocks: info.blocks as u64,
atime: Timespec {
sec: info.atime.sec as i32,
nsec: info.atime.nsec,
},
mtime: Timespec {
sec: info.mtime.sec as i32,
nsec: info.mtime.nsec,
},
ctime: Timespec {
sec: info.ctime.sec as i32,
nsec: info.ctime.nsec,
},
__pad1: 0,
__pad2: 0,
__pad3: 0,
}
}
#[cfg(not(any(target_arch = "x86_64", target_arch = "mips")))]
fn from(info: Metadata) -> Self {
Stat {
dev: info.dev as u64,
@ -1149,7 +1226,7 @@ pub struct IoVec {
/// Starting address
base: *mut u8,
/// Number of bytes to transfer
len: u64,
len: usize,
}
/// A valid IoVecs request from user
@ -1157,28 +1234,28 @@ pub struct IoVec {
pub struct IoVecs(Vec<&'static mut [u8]>);
impl IoVecs {
pub fn check_and_new(
pub unsafe fn check_and_new(
iov_ptr: *const IoVec,
iov_count: usize,
vm: &MemorySet,
readv: bool,
) -> Result<Self, SysError> {
vm.check_read_array(iov_ptr, iov_count)?;
let iovs = unsafe { slice::from_raw_parts(iov_ptr, iov_count) }.to_vec();
let iovs = vm.check_read_array(iov_ptr, iov_count)?.to_vec();
// check all bufs in iov
for iov in iovs.iter() {
if iov.len > 0 {
// skip empty iov
if iov.len == 0 {
continue;
}
if readv {
vm.check_write_array(iov.base, iov.len as usize)?;
vm.check_write_array(iov.base, iov.len)?;
} else {
vm.check_read_array(iov.base, iov.len as usize)?;
}
vm.check_read_array(iov.base, iov.len)?;
}
}
let slices = iovs
.iter()
.map(|iov| unsafe { slice::from_raw_parts_mut(iov.base, iov.len as usize) })
.map(|iov| slice::from_raw_parts_mut(iov.base, iov.len))
.collect();
Ok(IoVecs(slices))
}
@ -1260,12 +1337,12 @@ impl FdSet {
})
} else {
let len = (nfds + FD_PER_ITEM - 1) / FD_PER_ITEM;
vm.check_write_array(addr, len)?;
if len > MAX_FDSET_SIZE {
return Err(SysError::EINVAL);
}
let slice = unsafe { slice::from_raw_parts_mut(addr, len) };
let slice = unsafe { vm.check_write_array(addr, len)? };
let bitset: &'static mut BitSlice<LittleEndian, u32> = slice.into();
debug!("bitset {:?}", bitset);
// save the fdset, and clear it
use alloc::prelude::ToOwned;
@ -1289,7 +1366,11 @@ impl FdSet {
/// Check to see whether `fd` is in original `FdSet`
/// Fd should be less than nfds
fn contains(&self, fd: usize) -> bool {
if fd < self.bitset.len() {
self.origin[fd]
} else {
false
}
}
}

@ -1,4 +1,4 @@
use rcore_memory::memory_set::handler::{ByFrame, Delay};
use rcore_memory::memory_set::handler::{ByFrame, Delay, File};
use rcore_memory::memory_set::MemoryAttr;
use rcore_memory::paging::PageTable;
use rcore_memory::Page;
@ -51,24 +51,20 @@ pub fn sys_mmap(
);
return Ok(addr);
} else {
// only check
let _ = proc.get_file(fd)?;
// TODO: delay mmap file
let inode = proc.get_file(fd)?.inode();
proc.vm.push(
addr,
addr + len,
prot.to_attr(),
ByFrame::new(GlobalFrameAlloc),
File {
file: INodeForMap(inode),
mem_start: addr,
file_start: offset,
file_end: offset + len,
allocator: GlobalFrameAlloc,
},
"mmap_file",
);
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();
}
return Ok(addr);
}
}
@ -123,6 +119,21 @@ bitflags! {
}
}
#[cfg(target_arch = "mips")]
bitflags! {
pub struct MmapFlags: usize {
/// Changes are shared.
const SHARED = 1 << 0;
/// Changes are private.
const PRIVATE = 1 << 1;
/// Place the mapping at the exact address
const FIXED = 1 << 4;
/// The mapping is not backed by any file. (non-POSIX)
const ANONYMOUS = 0x800;
}
}
#[cfg(not(target_arch = "mips"))]
bitflags! {
pub struct MmapFlags: usize {
/// Changes are shared.

@ -18,16 +18,16 @@ pub fn sys_arch_prctl(code: i32, addr: usize, tf: &mut TrapFrame) -> SysResult {
}
pub fn sys_uname(buf: *mut u8) -> SysResult {
info!("sched_uname: buf: {:?}", buf);
info!("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)?;
let buf = unsafe { 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]);
util::write_cstr(&mut buf[i * offset], &strings[i]);
}
}
Ok(0)
@ -39,22 +39,20 @@ pub fn sys_sched_getaffinity(pid: usize, size: usize, mask: *mut u32) -> SysResu
pid, size, mask
);
let proc = process();
proc.vm.check_write_array(mask, size / size_of::<u32>())?;
let mask = unsafe { proc.vm.check_write_array(mask, size / size_of::<u32>())? };
// we only have 4 cpu at most.
// so just set it.
unsafe {
*mask = 0b1111;
}
mask[0] = 0b1111;
Ok(0)
}
pub fn sys_sysinfo(sys_info: *mut SysInfo) -> SysResult {
let proc = process();
proc.vm.check_write_ptr(sys_info)?;
let sys_info = unsafe { proc.vm.check_write_ptr(sys_info)? };
let sysinfo = SysInfo::default();
unsafe { *sys_info = sysinfo };
*sys_info = sysinfo;
Ok(0)
}
@ -74,13 +72,11 @@ pub fn sys_futex(uaddr: usize, op: u32, val: i32, timeout: *const TimeSpec) -> S
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 atomic = unsafe { process().vm.check_write_ptr(uaddr as *mut AtomicI32)? };
let _timeout = if timeout.is_null() {
None
} else {
process().vm.check_read_ptr(timeout)?;
Some(unsafe { *timeout })
Some(unsafe { *process().vm.check_read_ptr(timeout)? })
};
const OP_WAIT: u32 = 0;
@ -156,39 +152,33 @@ pub fn sys_prlimit64(
match resource {
RLIMIT_STACK => {
if !old_limit.is_null() {
proc.vm.check_write_ptr(old_limit)?;
unsafe {
let old_limit = unsafe { proc.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() {
proc.vm.check_write_ptr(old_limit)?;
unsafe {
let old_limit = unsafe { proc.vm.check_write_ptr(old_limit)? };
*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 {
let old_limit = unsafe { proc.vm.check_write_ptr(old_limit)? };
// 1GB
*old_limit = RLimit {
cur: 1024 * 1024 * 1024,
max: 1024 * 1024 * 1024,
};
}
}
Ok(0)
}
_ => Err(SysError::ENOSYS),
@ -201,3 +191,18 @@ pub struct RLimit {
cur: u64, // soft limit
max: u64, // hard limit
}
pub fn sys_getrandom(buf: *mut u8, len: usize, flag: u32) -> SysResult {
//info!("getrandom: buf: {:?}, len: {:?}, falg {:?}", buf, len,flag);
let mut proc = process();
let slice = unsafe { proc.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)
}

@ -31,13 +31,25 @@ mod net;
mod proc;
mod time;
use spin::Mutex;
use alloc::collections::BTreeMap;
#[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 {
#[cfg(feature = "profile")]
let begin_time = unsafe {
core::arch::x86_64::_rdtsc()
};
let cid = cpu::id();
let pid = { process().pid.clone() };
let pid = process().pid.clone();
let tid = processor().tid();
if !pid.is_init() {
// we trust pid 0 process
@ -48,50 +60,85 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
// See https://filippo.io/linux-syscall-table/
// And https://fedora.juszkiewicz.com.pl/syscalls.html.
let ret = match id {
// 0
// file
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_OPENAT => sys_openat(args[0], args[1] as *const u8, args[2], args[3]),
SYS_CLOSE => sys_close(args[0]),
SYS_FSTAT => sys_fstat(args[0], args[1] as *mut Stat),
SYS_NEWFSTATAT => sys_fstatat(args[0], args[1] as *const u8, args[2] as *mut Stat, args[3]),
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");
Ok(0)
}
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_SENDFILE => sys_sendfile(args[0], args[1], args[2] as *mut usize, args[3]),
SYS_FCNTL => unimplemented("fcntl", Ok(0)),
SYS_FLOCK => unimplemented("flock", 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_GETDENTS64 => sys_getdents64(args[0], args[1] as *mut LinuxDirent64, args[2]),
SYS_GETCWD => sys_getcwd(args[0] as *mut u8, args[1]),
SYS_CHDIR => sys_chdir(args[0] as *const u8),
SYS_RENAMEAT => sys_renameat(args[0], args[1] as *const u8, args[2], args[3] as *const u8),
SYS_MKDIRAT => sys_mkdirat(args[0], args[1] as *const u8, args[2]),
SYS_LINKAT => sys_linkat(
args[0],
args[1] as *const u8,
args[2],
args[3] as *const u8,
args[4],
),
SYS_UNLINKAT => sys_unlinkat(args[0], args[1] as *const u8, args[2]),
SYS_SYMLINKAT => unimplemented("symlinkat", Err(SysError::EACCES)),
SYS_READLINKAT => {
sys_readlinkat(args[0], args[1] as *const u8, args[2] as *mut u8, args[3])
}
SYS_GETPID => sys_getpid(),
// 40
SYS_SENDFILE => sys_sendfile(args[0], args[1], args[3] as *mut usize, args[4]),
SYS_FCHMOD => unimplemented("fchmod", Ok(0)),
SYS_FCHMODAT => unimplemented("fchmodat", Ok(0)),
SYS_FCHOWN => unimplemented("fchown", Ok(0)),
SYS_FCHOWNAT => unimplemented("fchownat", Ok(0)),
SYS_FACCESSAT => sys_faccessat(args[0], args[1] as *const u8, args[2], args[3]),
SYS_DUP3 => sys_dup2(args[0], args[1]), // TODO: handle `flags`
SYS_PIPE2 => sys_pipe(args[0] as *mut u32), // TODO: handle `flags`
SYS_UTIMENSAT => unimplemented("utimensat", Ok(0)),
// io multiplexing
SYS_PPOLL => sys_ppoll(args[0] as *mut PollFd, args[1], args[2] as *const TimeSpec), // ignore sigmask
SYS_EPOLL_CREATE1 => unimplemented("epoll_create1", Err(SysError::ENOSYS)),
// file system
SYS_STATFS => unimplemented("statfs", Err(SysError::EACCES)),
SYS_FSTATFS => unimplemented("fstatfs", Err(SysError::EACCES)),
SYS_SYNC => sys_sync(),
SYS_MOUNT => unimplemented("mount", Err(SysError::EACCES)),
SYS_UMOUNT2 => unimplemented("umount2", Err(SysError::EACCES)),
// memory
SYS_BRK => unimplemented("brk", Err(SysError::ENOMEM)),
SYS_MMAP => sys_mmap(args[0], args[1], args[2], args[3], args[4], args[5]),
SYS_MPROTECT => sys_mprotect(args[0], args[1], args[2]),
SYS_MUNMAP => sys_munmap(args[0], args[1]),
SYS_MADVISE => unimplemented("madvise", Ok(0)),
// signal
SYS_RT_SIGACTION => unimplemented("sigaction", Ok(0)),
SYS_RT_SIGPROCMASK => unimplemented("sigprocmask", Ok(0)),
SYS_SIGALTSTACK => unimplemented("sigaltstack", Ok(0)),
SYS_KILL => sys_kill(args[0], args[1]),
// schedule
SYS_SCHED_YIELD => sys_yield(),
SYS_SCHED_GETAFFINITY => sys_sched_getaffinity(args[0], args[1], args[2] as *mut u32),
// socket
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_ACCEPT4 => sys_accept(args[0], args[1] as *mut SockAddr, args[2] as *mut u32), // use accept for accept4
SYS_SENDTO => sys_sendto(
args[0],
args[1] as *const u8,
@ -112,7 +159,6 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
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),
@ -124,6 +170,8 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
args[3] as *mut u8,
args[4] as *mut u32,
),
// process
SYS_CLONE => sys_clone(
args[0],
args[1],
@ -138,180 +186,75 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
args[2] as *const *const u8,
tf,
),
// 60
SYS_EXIT => sys_exit(args[0] as usize),
SYS_EXIT_GROUP => sys_exit_group(args[0]),
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_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_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_SET_TID_ADDRESS => unimplemented("set_tid_address", Ok(thread::current().id())),
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())
}
// time
SYS_NANOSLEEP => sys_nanosleep(args[0] as *const TimeSpec),
SYS_SETITIMER => unimplemented("setitimer", Ok(0)),
SYS_GETTIMEOFDAY => sys_gettimeofday(args[0] as *mut TimeVal, args[1] as *const u8),
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_READLINKAT => {
sys_readlinkat(args[0], args[1] as *const u8, args[2] as *mut u8, args[3])
}
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_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`
// system
SYS_GETPID => sys_getpid(),
SYS_GETTID => sys_gettid(),
SYS_UNAME => sys_uname(args[0] as *mut u8),
SYS_UMASK => unimplemented("umask", Ok(0o777)),
// SYS_GETRLIMIT => sys_getrlimit(),
// SYS_SETRLIMIT => sys_setrlimit(),
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 => unimplemented("getuid", Ok(0)),
SYS_GETGID => unimplemented("getgid", Ok(0)),
SYS_SETUID => unimplemented("setuid", Ok(0)),
SYS_GETEUID => unimplemented("geteuid", Ok(0)),
SYS_GETEGID => unimplemented("getegid", Ok(0)),
SYS_SETPGID => unimplemented("setpgid", Ok(0)),
SYS_GETPPID => sys_getppid(),
SYS_SETSID => unimplemented("setsid", Ok(0)),
SYS_GETPGID => unimplemented("getpgid", Ok(0)),
SYS_GETGROUPS => unimplemented("getgroups", Ok(0)),
SYS_SETGROUPS => unimplemented("setgroups", Ok(0)),
SYS_SETPRIORITY => sys_set_priority(args[0]),
SYS_PRCTL => unimplemented("prctl", Ok(0)),
SYS_PRLIMIT64 => sys_prlimit64(
args[0],
args[1],
args[2] as *const RLimit,
args[3] as *mut RLimit,
),
// custom temporary syscall
SYS_REBOOT => sys_reboot(
args[0] as u32,
args[1] as u32,
args[2] as u32,
args[3] as *const u8,
),
// custom
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]),
//SYS_GETRANDOM => unimplemented("getrandom", Err(SysError::EINVAL)),
SYS_GETRANDOM => sys_getrandom(args[0] as *mut u8, args[1] as usize, args[2] as u32),
SYS_TKILL => unimplemented("tkill", Ok(0)),
_ => {
let ret = match () {
#[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;
if let Some(ret) = x86_64_ret {
() => x86_64_syscall(id, args, tf),
#[cfg(target_arch = "mips")]
() => mips_syscall(id, args, tf),
#[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);
@ -321,10 +264,22 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
};
if !pid.is_init() {
// we trust pid 0 process
debug!(
"{}:{}:{} syscall id {} ret with {:x?}",
cid, pid, tid, id, ret
);
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);
}
}
}
match ret {
Ok(code) => code as isize,
@ -332,6 +287,53 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
}
}
fn unimplemented(name: &str, ret: SysResult) -> SysResult {
warn!("{} is unimplemented", name);
ret
}
#[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)
}
Err(err) => Err(err),
}
}
SYS_FCNTL64 => 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(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option<SysResult> {
let ret = match id {
@ -349,37 +351,21 @@ fn x86_64_syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> Option<Sys
args[4] as *const TimeVal,
),
SYS_DUP2 => sys_dup2(args[0], args[1]),
SYS_ALARM => {
warn!("sys_alarm is unimplemented");
Ok(0)
}
SYS_ALARM => unimplemented("alarm", Ok(0)),
SYS_FORK => sys_fork(tf),
// use fork for vfork
SYS_VFORK => sys_fork(tf),
SYS_VFORK => sys_vfork(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_CHMOD => unimplemented("chmod", Ok(0)),
SYS_CHOWN => unimplemented("chown", 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;
}
SYS_EPOLL_CREATE => unimplemented("epoll_create", Err(SysError::ENOSYS)),
_ => return None,
};
Some(ret)
}

@ -39,8 +39,7 @@ pub fn sys_socket(domain: usize, socket_type: usize, protocol: usize) -> SysResu
},
_ => return Err(SysError::EAFNOSUPPORT),
};
let fd = proc.get_free_fd();
proc.files.insert(fd, FileLike::Socket(socket));
let fd = proc.add_file(FileLike::Socket(socket));
Ok(fd)
}
@ -56,8 +55,7 @@ pub fn sys_setsockopt(
fd, level, optname
);
let mut proc = process();
proc.vm.check_read_array(optval, optlen)?;
let data = unsafe { slice::from_raw_parts(optval, optlen) };
let data = unsafe { proc.vm.check_read_array(optval, optlen)? };
let socket = proc.get_socket(fd)?;
socket.setsockopt(level, optname, data)
}
@ -74,23 +72,19 @@ pub fn sys_getsockopt(
fd, level, optname, optval, optlen
);
let proc = process();
proc.vm.check_write_ptr(optlen)?;
let optlen = unsafe { 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;
let optval = unsafe { proc.vm.check_write_ptr(optval as *mut u32)? };
*optval = 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;
let optval = unsafe { proc.vm.check_write_ptr(optval as *mut u32)? };
*optval = crate::net::TCP_RECVBUF as u32;
*optlen = 4;
}
Ok(0)
}
_ => Err(SysError::ENOPROTOOPT),
@ -130,9 +124,8 @@ pub fn sys_sendto(
);
let mut proc = process();
proc.vm.check_read_array(base, len)?;
let slice = unsafe { slice::from_raw_parts(base, len) };
let slice = unsafe { proc.vm.check_read_array(base, len)? };
let endpoint = if addr.is_null() {
None
} else {
@ -158,10 +151,9 @@ pub fn sys_recvfrom(
);
let mut proc = process();
proc.vm.check_write_array(base, len)?;
let mut slice = unsafe { 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() {
@ -177,9 +169,8 @@ pub fn sys_recvfrom(
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 hdr = unsafe { proc.vm.check_write_ptr(msg)? };
let mut iovs = unsafe { IoVecs::check_and_new(hdr.msg_iov, hdr.msg_iovlen, &proc.vm, true)? };
let mut buf = iovs.new_buf(true);
let socket = proc.get_socket(fd)?;
@ -237,8 +228,7 @@ pub fn sys_accept(fd: usize, addr: *mut SockAddr, addr_len: *mut u32) -> SysResu
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));
let new_fd = proc.add_file(FileLike::Socket(new_socket));
if !addr.is_null() {
let sockaddr_in = SockAddr::from(remote_endpoint);
@ -408,16 +398,16 @@ fn sockaddr_to_endpoint(
if len < size_of::<u16>() {
return Err(SysError::EINVAL);
}
proc.vm.check_read_array(addr as *const u8, len)?;
let addr = unsafe { proc.vm.check_read_ptr(addr)? };
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()))
}
@ -427,7 +417,7 @@ fn sockaddr_to_endpoint(
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 => {
@ -435,8 +425,8 @@ fn sockaddr_to_endpoint(
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),
@ -458,7 +448,7 @@ impl SockAddr {
return Ok(0);
}
proc.vm.check_write_ptr(addr_len)?;
let addr_len = unsafe { proc.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>(),
@ -470,12 +460,11 @@ impl SockAddr {
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 { proc.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);
}
}

@ -6,11 +6,17 @@ 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);
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)
}
pub fn sys_vfork(tf: &TrapFrame) -> SysResult {
sys_fork(tf)
}
/// 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`.
@ -26,40 +32,43 @@ pub fn sys_clone(
) -> SysResult {
let clone_flags = CloneFlags::from_bits_truncate(flags);
info!(
"clone: flags: {:?}, newsp: {:#x}, parent_tid: {:?}, child_tid: {:?}, newtls: {:#x}",
clone_flags, newsp, parent_tid, child_tid, newtls
"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);
}
if flags != 0x7d0f00 {
warn!("sys_clone only support musl pthread_create");
return Err(SysError::ENOSYS);
}
{
let proc = process();
proc.vm.check_write_ptr(parent_tid)?;
proc.vm.check_write_ptr(child_tid)?;
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 { process().vm.check_write_ptr(parent_tid)? };
let child_tid_ref = unsafe { process().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);
processor().manager().detach(tid);
info!("clone: {} -> {}", thread::current().id(), tid);
unsafe {
parent_tid.write(tid as u32);
child_tid.write(tid as u32);
}
*parent_tid_ref = tid as u32;
*child_tid_ref = 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)?;
}
//info!("wait4: pid: {}, code: {:?}", pid, wstatus);
let wstatus = if !wstatus.is_null() {
Some(unsafe { process().vm.check_write_ptr(wstatus)? })
} else {
None
};
#[derive(Debug)]
enum WaitFor {
AnyChild,
@ -84,10 +93,8 @@ pub fn sys_wait4(pid: isize, wstatus: *mut i32) -> SysResult {
// 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);
}
if let Some(wstatus) = wstatus {
*wstatus = exit_code as i32;
}
return Ok(pid);
}
@ -118,75 +125,71 @@ pub fn sys_wait4(pid: isize, wstatus: *mut i32) -> SysResult {
}
}
/// 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(
name: *const u8,
path: *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)? }
};
info!(
"exec:BEG: path: {:?}, argv: {:?}, envp: {:?}",
path, argv, envp
);
let mut proc = process();
let path = unsafe { proc.vm.check_and_clone_cstr(path)? };
let args = unsafe { proc.vm.check_and_clone_cstr_array(argv)? };
let envs = unsafe { proc.vm.check_and_clone_cstr_array(envp)? };
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);
}
}
// // Check and copy envs to kernel
// let mut envs = Vec::new();
// unsafe {
// let mut current_env = envp as *const *const u8;
// 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 args.is_empty() {
error!("exec: args is null");
return Err(SysError::EINVAL);
}
info!("EXEC: name:{:?} , args {:?}", exec_name, args);
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 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()?;
let inode = proc.lookup_inode(&path)?;
// Make new Thread
let iter = args.iter().map(|s| s.as_str());
let mut thread = Thread::new_user(buf.as_slice(), exec_path, iter);
thread.proc.lock().clone_for_exec(&proc);
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 proc.vm, &mut vm);
unsafe {
thread.proc.lock().vm.activate();
proc.vm.activate();
}
// Modify the TrapFrame
*tf = unsafe { thread.context.get_init_tf() };
// Modify exec path
proc.exec_path = path.clone();
// Swap Context but keep KStack
::core::mem::swap(&mut current_thread().kstack, &mut thread.kstack);
::core::mem::swap(current_thread(), &mut *thread);
// Modify the TrapFrame
*tf = TrapFrame::new_user_thread(entry_addr, ustack_top);
info!("exec:END: path: {:?}", path);
Ok(0)
}
@ -319,8 +322,7 @@ pub fn sys_exit_group(exit_code: usize) -> ! {
}
pub fn sys_nanosleep(req: *const TimeSpec) -> SysResult {
process().vm.check_read_ptr(req)?;
let time = unsafe { req.read() };
let time = unsafe { *process().vm.check_read_ptr(req)? };
info!("nanosleep: time: {:#?}", time);
// TODO: handle spurious wakeup
thread::sleep(time.to_duration());

@ -33,20 +33,20 @@ fn get_epoch_usec() -> u64 {
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct TimeVal {
sec: u64,
usec: u64,
sec: usize,
usec: usize,
}
impl TimeVal {
pub fn to_msec(&self) -> u64 {
self.sec * MSEC_PER_SEC + self.usec / USEC_PER_MSEC
(self.sec as u64) * MSEC_PER_SEC + (self.usec as u64) / USEC_PER_MSEC
}
pub fn get_epoch() -> Self {
let usec = get_epoch_usec();
TimeVal {
sec: usec / USEC_PER_SEC,
usec: usec % USEC_PER_SEC,
sec: (usec / USEC_PER_SEC) as usize,
usec: (usec % USEC_PER_SEC) as usize,
}
}
}
@ -54,24 +54,24 @@ impl TimeVal {
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct TimeSpec {
sec: u64,
nsec: u64,
sec: usize,
nsec: usize,
}
impl TimeSpec {
pub fn to_msec(&self) -> u64 {
self.sec * MSEC_PER_SEC + self.nsec / NSEC_PER_MSEC
(self.sec as u64) * MSEC_PER_SEC + (self.nsec as u64) / NSEC_PER_MSEC
}
pub fn to_duration(&self) -> Duration {
Duration::new(self.sec, self.nsec as u32)
Duration::new(self.sec as u64, self.nsec as u32)
}
pub fn get_epoch() -> Self {
let usec = get_epoch_usec();
TimeSpec {
sec: usec / USEC_PER_SEC,
nsec: usec % USEC_PER_SEC * NSEC_PER_USEC,
sec: (usec / USEC_PER_SEC) as usize,
nsec: (usec % USEC_PER_SEC * NSEC_PER_USEC) as usize,
}
}
}
@ -83,12 +83,10 @@ pub fn sys_gettimeofday(tv: *mut TimeVal, tz: *const u8) -> SysResult {
}
let proc = process();
proc.vm.check_write_ptr(tv)?;
let tv = unsafe { proc.vm.check_write_ptr(tv)? };
let timeval = TimeVal::get_epoch();
unsafe {
*tv = timeval;
}
Ok(0)
}
@ -96,12 +94,10 @@ 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 ts = unsafe { proc.vm.check_write_ptr(ts)? };
let timespec = TimeSpec::get_epoch();
unsafe {
*ts = timespec;
}
Ok(0)
}
@ -109,10 +105,8 @@ 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);
}
let time = unsafe { proc.vm.check_write_ptr(time)? };
*time = sec as u64;
}
Ok(sec as usize)
}
@ -127,7 +121,7 @@ pub struct RUsage {
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 rusage = unsafe { proc.vm.check_write_ptr(rusage)? };
let tick_base = *TICK_BASE;
let tick = unsafe { crate::trap::TICK as u64 };
@ -135,14 +129,42 @@ pub fn sys_getrusage(who: usize, rusage: *mut RUsage) -> SysResult {
let usec = (tick - tick_base) * USEC_PER_TICK as u64;
let new_rusage = RUsage {
utime: TimeVal {
sec: usec / USEC_PER_SEC,
usec: usec % USEC_PER_SEC,
sec: (usec / USEC_PER_SEC) as usize,
usec: (usec % USEC_PER_SEC) as usize,
},
stime: TimeVal {
sec: usec / USEC_PER_SEC,
usec: usec % USEC_PER_SEC,
sec: (usec / USEC_PER_SEC) as usize,
usec: (usec % USEC_PER_SEC) as usize,
},
};
unsafe { *rusage = new_rusage };
*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 */
}
pub fn sys_times(buf: *mut Tms) -> SysResult {
info!("times: buf: {:?}", buf);
let proc = process();
let buf = unsafe { proc.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)
}

@ -1 +0,0 @@
Subproject commit 405ea59dd7dd2762c5883822f21d9995bea32b0c

File diff suppressed because one or more lines are too long

@ -0,0 +1,13 @@
# OpenSBI
These are binary release of OpenSBI on this [commit](https://github.com/riscv/opensbi/tree/194dbbe5a13dff2255411c26d249f3ad4ef42c0b) at 2019.04.15.
- 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. 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.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -1 +1 @@
Subproject commit 8dbc0edb935a62d748aaac39258d4a985de0ae17
Subproject commit 05f0efd3fda084109e4b6da8ff30ecb1557a267f
Loading…
Cancel
Save