Merge remote-tracking branch 'origin/dev'

master
Yuhao Zhou 6 years ago
commit 65b121e55e

1
.gitignore vendored

@ -1,6 +1,7 @@
build
target
/kernel/src/arch/x86_64/interrupt/vector.asm
/kernel/src/arch/mipsel/boot/linker.ld
*.gen.s
*.dtb

@ -2,11 +2,12 @@
# It is not intended for manual editing.
[[package]]
name = "aarch64"
version = "2.5.0"
source = "git+https://github.com/rcore-os/aarch64#797c24f07f9d90542eb094530b6f63fe3ea7dded"
version = "2.6.1"
source = "git+https://github.com/rcore-os/aarch64#65d1453f11f3cc113247352dffa02d8dcdd34769"
dependencies = [
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"register 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
@ -30,6 +31,11 @@ name = "bitflags"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cast"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cc"
version = "1.0.31"
@ -98,7 +104,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
name = "rcore-bootloader"
version = "0.1.0"
dependencies = [
"aarch64 2.5.0 (git+https://github.com/rcore-os/aarch64)",
"aarch64 2.6.1 (git+https://github.com/rcore-os/aarch64)",
"bcm2837 1.0.0 (git+https://github.com/rcore-os/bcm2837)",
"cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)",
"fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
@ -205,10 +211,11 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum aarch64 2.5.0 (git+https://github.com/rcore-os/aarch64)" = "<none>"
"checksum aarch64 2.6.1 (git+https://github.com/rcore-os/aarch64)" = "<none>"
"checksum bcm2837 1.0.0 (git+https://github.com/rcore-os/bcm2837)" = "<none>"
"checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427"
"checksum cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "c9ce8bb087aacff865633f0bd5aeaed910fe2fe55b55f4739527f2e023a2e53d"
"checksum fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6c16d316ccdac21a4dd648e314e76facbbaf316e83ca137d0857a9c07419d0"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"

@ -9,7 +9,7 @@ xmas-elf = "0.6.2"
fixedvec = "0.2.3"
[target.'cfg(target_arch = "aarch64")'.dependencies]
aarch64 = { git = "https://github.com/rcore-os/aarch64", version = "2.5.0" }
aarch64 = { git = "https://github.com/rcore-os/aarch64", version = "2.6.1" }
bcm2837 = { git = "https://github.com/rcore-os/bcm2837", version = "1.0.0" }
[build-dependencies]

@ -1,6 +1,6 @@
use aarch64::addr::{VirtAddr, PhysAddr};
use aarch64::addr::{PhysAddr, VirtAddr};
use aarch64::paging::{memory_attribute::*, Page, PageTable, PageTableFlags as EF, PhysFrame};
use aarch64::paging::{Size4KiB, Size2MiB, Size1GiB};
use aarch64::paging::{Size1GiB, Size2MiB, Size4KiB};
use aarch64::{asm::*, barrier, regs::*};
use bcm2837::consts::RAW_IO_BASE;
use core::ptr;
@ -10,12 +10,22 @@ use xmas_elf::program::{ProgramHeader64, Type};
const PAGE_SIZE: usize = 4096;
const ALIGN_2MB: u64 = 0x200000;
const RECURSIVE_INDEX: usize = 0o777;
const KERNEL_OFFSET: u64 = 0xFFFF_0000_0000_0000;
const PHYSICAL_MEMORY_OFFSET: u64 = 0xFFFF_0000_0000_0000;
global_asm!(include_str!("boot.S"));
fn setup_temp_page_table(start_vaddr: VirtAddr, end_vaddr: VirtAddr, offset: u64) {
/// Convert physical address to virtual address
const fn phys_to_virt(paddr: u64) -> u64 {
PHYSICAL_MEMORY_OFFSET + paddr
}
/// Convert virtual address to physical address
const fn virt_to_phys(vaddr: u64) -> u64 {
vaddr - PHYSICAL_MEMORY_OFFSET
}
// TODO: set segments permission
fn create_page_table(start_paddr: usize, end_paddr: usize) {
#[repr(align(4096))]
struct PageData([u8; PAGE_SIZE]);
static mut PAGE_TABLE_LVL4: PageData = PageData([0; PAGE_SIZE]);
@ -34,13 +44,17 @@ fn setup_temp_page_table(start_vaddr: VirtAddr, end_vaddr: VirtAddr, offset: u64
let block_flags = EF::VALID | EF::AF | EF::WRITE | EF::UXN;
// normal memory
for page in Page::<Size2MiB>::range_of(start_vaddr.as_u64(), end_vaddr.as_u64()) {
let paddr = PhysAddr::new(page.start_address().as_u64().wrapping_add(offset));
for frame in PhysFrame::<Size2MiB>::range_of(start_paddr as u64, end_paddr as u64) {
let paddr = frame.start_address();
let vaddr = VirtAddr::new(phys_to_virt(paddr.as_u64()));
let page = Page::<Size2MiB>::containing_address(vaddr);
p2[page.p2_index()].set_block::<Size2MiB>(paddr, block_flags, MairNormal::attr_value());
}
// device memory
for page in Page::<Size2MiB>::range_of(RAW_IO_BASE as u64, 0x4000_0000) {
let paddr = PhysAddr::new(page.start_address().as_u64());
for frame in PhysFrame::<Size2MiB>::range_of(RAW_IO_BASE as u64, 0x4000_0000) {
let paddr = frame.start_address();
let vaddr = VirtAddr::new(phys_to_virt(paddr.as_u64()));
let page = Page::<Size2MiB>::containing_address(vaddr);
p2[page.p2_index()].set_block::<Size2MiB>(paddr, block_flags | EF::PXN, MairDevice::attr_value());
}
@ -48,8 +62,9 @@ fn setup_temp_page_table(start_vaddr: VirtAddr, end_vaddr: VirtAddr, offset: u64
p3[1].set_block::<Size1GiB>(PhysAddr::new(0x4000_0000), block_flags | EF::PXN, MairDevice::attr_value());
p4[0].set_frame(frame_lvl3, EF::default(), MairNormal::attr_value());
p4[RECURSIVE_INDEX].set_frame(frame_lvl4, EF::default(), MairNormal::attr_value());
// the bootloader is still running at the lower virtual address range,
// so the TTBR0_EL1 also needs to be set.
ttbr_el1_write(0, frame_lvl4);
ttbr_el1_write(1, frame_lvl4);
tlb_invalidate_all();
@ -118,7 +133,7 @@ pub fn map_kernel(kernel_start: usize, segments: &FixedVec<ProgramHeader64>) {
unsafe {
let src = (kernel_start as u64 + offset) as *const u8;
let dst = virt_addr.wrapping_sub(KERNEL_OFFSET) as *mut u8;
let dst = virt_to_phys(virt_addr) as *mut u8;
ptr::copy(src, dst, file_size as usize);
ptr::write_bytes(dst.offset(file_size as isize), 0, (mem_size - file_size) as usize);
}
@ -131,6 +146,6 @@ pub fn map_kernel(kernel_start: usize, segments: &FixedVec<ProgramHeader64>) {
}
}
setup_temp_page_table(start_vaddr, end_vaddr, KERNEL_OFFSET.wrapping_neg());
create_page_table(0, RAW_IO_BASE);
enable_mmu();
}

@ -11,30 +11,19 @@ pub struct Page {
}
impl Page {
/*
** @brief get the virtual address of beginning of the page
** @retval VirtAddr the virtual address of beginning of the page
*/
/// Returns the start address of the page.
pub fn start_address(&self) -> VirtAddr {
self.number * PAGE_SIZE
}
/*
** @brief get the page of a given virtual address
** @param addr: VirtAddr the given virtual address
** @retval Page the page of the given virtual address
*/
/// Returns the page that contains the given virtual address.
pub fn of_addr(addr: VirtAddr) -> Self {
Page {
number: addr / PAGE_SIZE,
}
}
/*
** @brief get a pageRange between two virtual address
** @param begin: VirtAddr the virtual address of the beginning
** @param end: VirtAddr the virtual address of the end
** @retval PageRange the page of the given virtual address
*/
/// Returns a range of pages between address `begin` and `end`
pub fn range_of(begin: VirtAddr, end: VirtAddr) -> PageRange {
PageRange {
start: Page::of_addr(begin),
@ -79,45 +68,3 @@ impl Iterator for PageRange {
}
}
}
/// frame for the swapmanager
#[derive(Debug, Copy, Clone, PartialOrd, Ord)]
#[repr(C)]
pub struct Frame {
/// the raw pointer for the frame's memory set's inactive page table
page_table: usize,
/// the virtual addr for the frame
virtaddr: VirtAddr,
/// the token for frame
token: usize,
}
impl Frame {
pub fn get_page_table(&self) -> usize {
self.page_table
}
pub fn get_virtaddr(&self) -> VirtAddr {
self.virtaddr
}
pub fn get_token(&self) -> usize {
self.token
}
pub fn new(pt: usize, addr: VirtAddr, pttoken: usize) -> Self {
Frame {
page_table: pt,
virtaddr: addr,
token: pttoken,
}
}
}
impl PartialEq for Frame {
fn eq(&self, other: &Frame) -> bool {
self.token == other.token && self.virtaddr == other.virtaddr
}
}
impl Eq for Frame {}

@ -109,8 +109,8 @@ impl<T: PageTable> CowExt<T> {
self.rc_map.write_decrease(&frame);
return true;
}
use core::mem::uninitialized;
let mut temp_data: [u8; PAGE_SIZE] = unsafe { uninitialized() };
use core::mem::MaybeUninit;
let mut temp_data: [u8; PAGE_SIZE] = unsafe { MaybeUninit::uninitialized().into_initialized() };
temp_data[..].copy_from_slice(self.get_page_slice_mut(addr));
self.unmap_shared(addr);

@ -1,6 +1,7 @@
#![cfg_attr(not(test), no_std)]
#![feature(alloc)]
#![feature(nll)]
#![feature(maybe_uninit)]
// import macros from log
use log::*;
@ -11,7 +12,7 @@ pub mod cow;
pub mod memory_set;
pub mod no_mmu;
pub mod paging;
pub mod swap;
//pub mod swap;
pub use crate::addr::*;

@ -25,15 +25,13 @@ impl<T: FrameAllocator> MemoryHandler for ByFrame<T> {
fn clone_map(
&self,
pt: &mut PageTable,
with: &Fn(&mut FnMut()),
src_pt: &mut PageTable,
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);
});
let data = src_pt.get_page_slice_mut(addr);
pt.get_page_slice_mut(addr).copy_from_slice(data);
}
fn handle_page_fault(&self, _pt: &mut PageTable, _addr: VirtAddr) -> bool {

@ -30,24 +30,21 @@ impl<T: FrameAllocator> MemoryHandler for Delay<T> {
fn clone_map(
&self,
pt: &mut PageTable,
with: &Fn(&mut FnMut()),
src_pt: &mut PageTable,
addr: VirtAddr,
attr: &MemoryAttr,
) {
let entry = pt.get_entry(addr).expect("failed to get entry");
let entry = src_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 data = src_pt.get_page_slice_mut(addr);
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);
});
pt.get_page_slice_mut(addr).copy_from_slice(data);
} else {
// delay map
with(&mut || self.map(pt, addr, attr));
self.map(pt, addr, attr);
}
}

@ -39,24 +39,21 @@ impl<F: Read, T: FrameAllocator> MemoryHandler for File<F, T> {
fn clone_map(
&self,
pt: &mut PageTable,
with: &Fn(&mut FnMut()),
src_pt: &mut PageTable,
addr: usize,
attr: &MemoryAttr,
) {
let entry = pt.get_entry(addr).expect("failed to get entry");
let entry = src_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 data = src_pt.get_page_slice_mut(addr);
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);
});
pt.get_page_slice_mut(addr).copy_from_slice(data);
} else {
// delay map
with(&mut || self.map(pt, addr, attr));
self.map(pt, addr, attr);
}
}
@ -69,16 +66,9 @@ impl<F: Read, T: FrameAllocator> MemoryHandler for File<F, T> {
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
}
}

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

@ -5,20 +5,17 @@ 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
/// Should set page flags here instead of in `page_fault_handler`
fn map(&self, pt: &mut PageTable, addr: VirtAddr, attr: &MemoryAttr);
/// 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.
/// Clone map `addr` from page table `src_pt` to `pt`.
fn clone_map(
&self,
pt: &mut PageTable,
with: &Fn(&mut FnMut()),
src_pt: &mut PageTable,
addr: VirtAddr,
attr: &MemoryAttr,
);

@ -1,5 +1,4 @@
//! memory set, area
//! and the inactive page table
//! Memory management structures
use alloc::{boxed::Box, string::String, vec::Vec};
use core::fmt::{Debug, Error, Formatter};
@ -13,8 +12,7 @@ use self::handler::MemoryHandler;
pub mod handler;
/// a continuous memory space when the same attribute
/// like `vma_struct` in ucore
/// A continuous memory space when the same attribute
#[derive(Debug, Clone)]
pub struct MemoryArea {
start_addr: VirtAddr,
@ -25,31 +23,7 @@ pub struct MemoryArea {
}
impl MemoryArea {
/*
** @brief get slice of the content in the memory area
** @retval &[u8] the slice of the content in the memory area
*/
pub unsafe fn as_slice(&self) -> &[u8] {
::core::slice::from_raw_parts(
self.start_addr as *const u8,
self.end_addr - self.start_addr,
)
}
/*
** @brief get mutable slice of the content in the memory area
** @retval &mut[u8] the mutable slice of the content in the memory area
*/
pub unsafe fn as_slice_mut(&self) -> &mut [u8] {
::core::slice::from_raw_parts_mut(
self.start_addr as *mut u8,
self.end_addr - self.start_addr,
)
}
/*
** @brief test whether a virtual address is in the memory area
** @param addr: VirtAddr the virtual address to test
** @retval bool whether the virtual address is in the memory area
*/
/// Test whether a virtual address is in the memory area
pub fn contains(&self, addr: VirtAddr) -> bool {
addr >= self.start_addr && addr < self.end_addr
}
@ -75,20 +49,6 @@ impl MemoryArea {
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.
///
/// Unsafe: the page table must be active.
pub unsafe fn check_and_clone_cstr(&self, ptr: *const u8) -> Option<String> {
if ptr as usize >= self.end_addr {
return None;
}
let max_len = self.end_addr - ptr as usize;
(0..max_len)
.find(|&i| ptr.offset(i as isize).read() == 0)
.and_then(|len| core::str::from_utf8(core::slice::from_raw_parts(ptr, len)).ok())
.map(|s| String::from(s))
}
/// Test whether this area is (page) overlap with area [`start_addr`, `end_addr`]
pub fn is_overlap_with(&self, start_addr: VirtAddr, end_addr: VirtAddr) -> bool {
let p0 = Page::of_addr(self.start_addr);
@ -121,42 +81,22 @@ pub struct MemoryAttr {
}
impl MemoryAttr {
/*
** @brief set the memory attribute's user bit
** @retval MemoryAttr the memory attribute itself
*/
pub fn user(mut self) -> Self {
self.user = true;
self
}
/*
** @brief set the memory attribute's readonly bit
** @retval MemoryAttr the memory attribute itself
*/
pub fn readonly(mut self) -> Self {
self.readonly = true;
self
}
/*
** @brief unset the memory attribute's readonly bit
** @retval MemoryAttr the memory attribute itself
*/
pub fn writable(mut self) -> Self {
self.readonly = false;
self
}
/*
** @brief set the memory attribute's execute bit
** @retval MemoryAttr the memory attribute itself
*/
pub fn execute(mut self) -> Self {
self.execute = true;
self
}
/*
** @brief set the MMIO type
** @retval MemoryAttr the memory attribute itself
*/
pub fn mmio(mut self, value: u8) -> Self {
self.mmio = value;
self
@ -172,26 +112,24 @@ impl MemoryAttr {
}
}
/// set of memory space with multiple memory area with associated page table and stack space
/// like `mm_struct` in ucore
/// A set of memory space with multiple memory areas with associated page table
/// NOTE: Don't remove align(64), or you will fail to run MIPS.
#[repr(align(64))]
pub struct MemorySet<T: InactivePageTable> {
/// Temporary solution for rv64
#[cfg_attr(not(target_arch = "riscv64"), repr(align(64)))]
pub struct MemorySet<T: PageTableExt> {
areas: Vec<MemoryArea>,
page_table: T,
}
impl<T: InactivePageTable> MemorySet<T> {
/*
** @brief create a memory set
** @retval MemorySet<T> the memory set created
*/
impl<T: PageTableExt> MemorySet<T> {
/// Create a new `MemorySet`
pub fn new() -> Self {
MemorySet {
areas: Vec::new(),
page_table: T::new(),
}
}
/// Create a new `MemorySet` for kernel remap
pub fn new_bare() -> Self {
MemorySet {
areas: Vec::new(),
@ -236,35 +174,6 @@ impl<T: InactivePageTable> MemorySet<T> {
}
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.
///
/// Unsafe: the page table must be active.
pub unsafe fn check_and_clone_cstr(&self, ptr: *const u8) -> VMResult<String> {
self.areas
.iter()
.filter_map(|area| area.check_and_clone_cstr(ptr))
.next()
.ok_or(VMError::InvalidPtr)
}
/// Find a free area with hint address `addr_hint` and length `len`.
/// Return the start address of found free area.
/// Used for mmap.
@ -284,11 +193,7 @@ impl<T: InactivePageTable> MemorySet<T> {
.find(|area| area.is_overlap_with(start_addr, end_addr))
.is_none()
}
/*
** @brief add the memory area to the memory set
** @param area: MemoryArea the memory area to add
** @retval none
*/
/// Add an area to this set
pub fn push(
&mut self,
start_addr: VirtAddr,
@ -309,7 +214,7 @@ impl<T: InactivePageTable> MemorySet<T> {
handler: Box::new(handler),
name,
};
self.page_table.edit(|pt| area.map(pt));
area.map(&mut self.page_table);
// keep order by start address
let idx = self
.areas
@ -321,28 +226,21 @@ impl<T: InactivePageTable> MemorySet<T> {
self.areas.insert(idx, area);
}
/*
** @brief remove the memory area from the memory set
** @param area: MemoryArea the memory area to remove
** @retval none
*/
/// Remove the area `[start_addr, end_addr)` from `MemorySet`
pub fn pop(&mut self, start_addr: VirtAddr, end_addr: VirtAddr) {
assert!(start_addr <= end_addr, "invalid memory area");
for i in 0..self.areas.len() {
if self.areas[i].start_addr == start_addr && self.areas[i].end_addr == end_addr {
let area = self.areas.remove(i);
self.page_table.edit(|pt| area.unmap(pt));
area.unmap(&mut self.page_table);
return;
}
}
panic!("no memory area found");
}
/*
** @brief remove the memory area from the memory set and split existed ones when necessary
** @param area: MemoryArea the memory area to remove
** @retval none
*/
/// Remove the area `[start_addr, end_addr)` from `MemorySet`
/// and split existed ones when necessary.
pub fn pop_with_split(&mut self, start_addr: VirtAddr, end_addr: VirtAddr) {
assert!(start_addr <= end_addr, "invalid memory area");
let mut i = 0;
@ -351,7 +249,7 @@ impl<T: InactivePageTable> MemorySet<T> {
if self.areas[i].start_addr >= start_addr && self.areas[i].end_addr <= end_addr {
// subset
let area = self.areas.remove(i);
self.page_table.edit(|pt| area.unmap(pt));
area.unmap(&mut self.page_table);
i -= 1;
} else if self.areas[i].start_addr >= start_addr
&& self.areas[i].start_addr < end_addr
@ -365,7 +263,7 @@ impl<T: InactivePageTable> MemorySet<T> {
handler: area.handler.box_clone(),
name: area.name,
};
self.page_table.edit(|pt| dead_area.unmap(pt));
dead_area.unmap(&mut self.page_table);
let new_area = MemoryArea {
start_addr: end_addr,
end_addr: area.end_addr,
@ -379,13 +277,13 @@ impl<T: InactivePageTable> MemorySet<T> {
// postfix
let area = self.areas.remove(i);
let dead_area = MemoryArea {
start_addr: start_addr,
start_addr,
end_addr: area.end_addr,
attr: area.attr,
handler: area.handler.box_clone(),
name: area.name,
};
self.page_table.edit(|pt| dead_area.unmap(pt));
dead_area.unmap(&mut self.page_table);
let new_area = MemoryArea {
start_addr: area.start_addr,
end_addr: start_addr,
@ -398,13 +296,13 @@ impl<T: InactivePageTable> MemorySet<T> {
// superset
let area = self.areas.remove(i);
let dead_area = MemoryArea {
start_addr: start_addr,
end_addr: end_addr,
start_addr,
end_addr,
attr: area.attr,
handler: area.handler.box_clone(),
name: area.name,
};
self.page_table.edit(|pt| dead_area.unmap(pt));
dead_area.unmap(&mut self.page_table);
let new_area_left = MemoryArea {
start_addr: area.start_addr,
end_addr: start_addr,
@ -428,74 +326,50 @@ impl<T: InactivePageTable> MemorySet<T> {
}
}
/*
** @brief get iterator of the memory area
** @retval impl Iterator<Item=&MemoryArea>
** the memory area iterator
*/
/// Get iterator of areas
pub fn iter(&self) -> impl Iterator<Item = &MemoryArea> {
self.areas.iter()
}
pub fn edit(&mut self, f: impl FnOnce(&mut T::Active)) {
self.page_table.edit(f);
}
/*
** @brief execute function with the associated page table
** @param f: impl FnOnce() the function to be executed
** @retval none
*/
/// Execute function `f` with the associated page table
pub unsafe fn with(&self, f: impl FnOnce()) {
self.page_table.with(f);
}
/*
** @brief activate the associated page table
** @retval none
*/
/// Activate the associated page table
pub unsafe fn activate(&self) {
self.page_table.activate();
}
/*
** @brief get the token of the associated page table
** @retval usize the token of the inactive page table
*/
/// Get the token of the associated page table
pub fn token(&self) -> usize {
self.page_table.token()
}
/*
** @brief clear the memory set
** @retval none
*/
/// Clear and unmap all areas
pub fn clear(&mut self) {
let Self {
ref mut page_table,
ref mut areas,
..
} = self;
page_table.edit(|pt| {
for area in areas.iter() {
area.unmap(pt);
area.unmap(page_table);
}
});
areas.clear();
}
/// Get physical address of the page of given virtual `addr`
pub fn translate(&mut self, addr: VirtAddr) -> Option<PhysAddr> {
self.page_table.edit(|pt| {
pt.get_entry(addr).and_then(|entry| {
self.page_table.get_entry(addr).and_then(|entry| {
if entry.user() {
Some(entry.target())
} else {
None
}
})
})
}
/*
** @brief get the mutable reference for the inactive page table
** @retval: &mut T the mutable reference of the inactive page table
*/
/// Get the reference of inner page table
pub fn get_page_table_mut(&mut self) -> &mut T {
&mut self.page_table
}
@ -503,32 +377,28 @@ impl<T: InactivePageTable> MemorySet<T> {
pub fn handle_page_fault(&mut self, addr: VirtAddr) -> bool {
let area = self.areas.iter().find(|area| area.contains(addr));
match area {
Some(area) => self
.page_table
.edit(|pt| area.handler.handle_page_fault(pt, addr)),
Some(area) => area.handler.handle_page_fault(&mut self.page_table, addr),
None => false,
}
}
pub fn clone(&mut self) -> Self {
let new_page_table = T::new();
let mut new_page_table = T::new();
let Self {
ref mut page_table,
ref areas,
..
} = self;
page_table.edit(|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) },
&mut new_page_table,
page_table,
page.start_address(),
&area.attr,
);
}
}
});
MemorySet {
areas: areas.clone(),
page_table: new_page_table,
@ -536,13 +406,13 @@ impl<T: InactivePageTable> MemorySet<T> {
}
}
impl<T: InactivePageTable> Drop for MemorySet<T> {
impl<T: PageTableExt> Drop for MemorySet<T> {
fn drop(&mut self) {
self.clear();
}
}
impl<T: InactivePageTable> Debug for MemorySet<T> {
impl<T: PageTableExt> Debug for MemorySet<T> {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
f.debug_list().entries(self.areas.iter()).finish()
}

@ -1,23 +0,0 @@
//! Helper functions
use super::*;
pub trait PageTableExt: PageTable {
// Take some special care here.
// TEMP_PAGE_ADDR mapping might be overwritten in the `f` below.
// So this should be really high in kernel space when necessary.
const TEMP_PAGE_ADDR: VirtAddr = 0xcafeb000;
fn with_temporary_map<T, D>(
&mut self,
target: PhysAddr,
f: impl FnOnce(&mut Self, &mut D) -> T,
) -> T {
self.map(Self::TEMP_PAGE_ADDR, target);
let data =
unsafe { &mut *(self.get_page_slice_mut(Self::TEMP_PAGE_ADDR).as_ptr() as *mut D) };
let ret = f(self, data);
self.unmap(Self::TEMP_PAGE_ADDR);
ret
}
}

@ -144,10 +144,10 @@ impl MockPageTable {
** @retval MockPageTable the mock page table created
*/
pub fn new() -> Self {
use core::mem::uninitialized;
use core::mem::MaybeUninit;
MockPageTable {
entries: [MockEntry::default(); PAGE_COUNT],
data: unsafe { uninitialized() },
data: unsafe { MaybeUninit::uninitialized().into_initialized() },
page_fault_handler: None,
}
}

@ -2,12 +2,10 @@
//!
//! Implemented for every architecture, used by OS.
pub use self::ext::*;
#[cfg(test)]
pub use self::mock_page_table::MockPageTable;
use super::*;
mod ext;
#[cfg(test)]
mod mock_page_table;
@ -26,31 +24,18 @@ pub trait PageTable {
fn get_entry(&mut self, addr: VirtAddr) -> Option<&mut Entry>;
/// Get a mutable reference of the content of a page of virtual address `addr`
/// Used for testing with mock
fn get_page_slice_mut<'a>(&mut self, addr: VirtAddr) -> &'a mut [u8] {
unsafe { core::slice::from_raw_parts_mut((addr & !(PAGE_SIZE - 1)) as *mut u8, PAGE_SIZE) }
}
fn get_page_slice_mut<'a>(&mut self, addr: VirtAddr) -> &'a mut [u8];
/// Read data from virtual address `addr`
/// Used for testing with mock
fn read(&mut self, addr: VirtAddr) -> u8 {
unsafe { (addr as *const u8).read() }
fn read(&mut self, _addr: VirtAddr) -> u8 {
unimplemented!()
}
/// Write data to virtual address `addr`
/// Used for testing with mock
fn write(&mut self, addr: VirtAddr, data: u8) {
unsafe { (addr as *mut u8).write(data) }
}
/// When `vaddr` is not mapped, map it to `paddr`.
fn map_if_not_exists(&mut self, vaddr: VirtAddr, paddr: usize) -> bool {
if let Some(entry) = self.get_entry(vaddr) {
if entry.present() {
return false;
}
}
self.map(vaddr, paddr);
true
fn write(&mut self, _addr: VirtAddr, _data: u8) {
unimplemented!()
}
}
@ -99,13 +84,8 @@ pub trait Entry {
fn set_mmio(&mut self, value: u8);
}
/// An inactive page table
/// Note: InactivePageTable is not a PageTable
/// but it can be activated and "become" a PageTable
pub trait InactivePageTable: Sized {
/// the active version of page table
type Active: PageTable;
/// Extra methods of `PageTable` for non-trait-object usage
pub trait PageTableExt: PageTable + Sized {
/// Create a new page table with kernel memory mapped
fn new() -> Self {
let mut pt = Self::new_bare();
@ -125,10 +105,6 @@ pub trait InactivePageTable: Sized {
fn active_token() -> usize;
fn flush_tlb();
/// Make this page table editable
/// Set the recursive entry of current active page table to this
fn edit<T>(&mut self, f: impl FnOnce(&mut Self::Active) -> T) -> T;
/// Activate this page table
unsafe fn activate(&self) {
let old_token = Self::active_token();

@ -5,7 +5,7 @@
use super::Swapper;
use alloc::collections::BTreeMap;
use core::mem::uninitialized;
use core::mem::MaybeUninit;
const PAGE_SIZE: usize = 4096;
@ -17,7 +17,7 @@ pub struct MockSwapper {
impl Swapper for MockSwapper {
fn swap_out(&mut self, data: &[u8]) -> Result<usize, ()> {
let id = self.alloc_id();
let mut slice: [u8; PAGE_SIZE] = unsafe { uninitialized() };
let mut slice: [u8; PAGE_SIZE] = unsafe { MaybeUninit::uninitialized().into_initialized() };
slice.copy_from_slice(data);
self.map.insert(id, slice);
Ok(id)
@ -27,7 +27,7 @@ impl Swapper for MockSwapper {
if !self.map.contains_key(&token) {
return Err(());
}
let mut slice: [u8; PAGE_SIZE] = unsafe { uninitialized() };
let mut slice: [u8; PAGE_SIZE] = unsafe { MaybeUninit::uninitialized().into_initialized() };
slice.copy_from_slice(data);
self.map.insert(token, slice);
Ok(())
@ -64,8 +64,8 @@ mod test {
#[test]
fn swap_out_in() {
let mut swapper = MockSwapper::default();
let mut data: [u8; 4096] = unsafe { uninitialized() };
let data1: [u8; 4096] = unsafe { uninitialized() };
let mut data: [u8; 4096] = unsafe { MaybeUninit::uninitialized().into_initialized() };
let data1: [u8; 4096] = unsafe { MaybeUninit::uninitialized().into_initialized() };
let token = swapper.swap_out(&data1).unwrap();
swapper.swap_in(token, &mut data).unwrap();
assert_data_eq(&data, &data1);
@ -74,9 +74,9 @@ mod test {
#[test]
fn swap_update() {
let mut swapper = MockSwapper::default();
let mut data: [u8; 4096] = unsafe { uninitialized() };
let data1: [u8; 4096] = unsafe { uninitialized() };
let data2: [u8; 4096] = unsafe { uninitialized() };
let mut data: [u8; 4096] = unsafe { MaybeUninit::uninitialized().into_initialized() };
let data1: [u8; 4096] = unsafe { MaybeUninit::uninitialized().into_initialized() };
let data2: [u8; 4096] = unsafe { MaybeUninit::uninitialized().into_initialized() };
let token = swapper.swap_out(&data1).unwrap();
swapper.swap_update(token, &data2).unwrap();
swapper.swap_in(token, &mut data).unwrap();
@ -86,7 +86,7 @@ mod test {
#[test]
fn invalid_token() {
let mut swapper = MockSwapper::default();
let mut data: [u8; 4096] = unsafe { uninitialized() };
let mut data: [u8; 4096] = unsafe { MaybeUninit::uninitialized().into_initialized() };
assert_eq!(swapper.swap_in(0, &mut data), Err(()));
}
}

178
kernel/Cargo.lock generated

@ -2,11 +2,12 @@
# It is not intended for manual editing.
[[package]]
name = "aarch64"
version = "2.5.0"
source = "git+https://github.com/rcore-os/aarch64#797c24f07f9d90542eb094530b6f63fe3ea7dded"
version = "2.6.1"
source = "git+https://github.com/rcore-os/aarch64#65d1453f11f3cc113247352dffa02d8dcdd34769"
dependencies = [
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"register 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
@ -15,11 +16,11 @@ dependencies = [
[[package]]
name = "apic"
version = "0.1.0"
source = "git+https://github.com/rcore-os/apic-rs#5ddc5fba952ae7420bcf3b7af3d79004e2b8c12f"
source = "git+https://github.com/rcore-os/apic-rs#3bc93873eaa4d21f09fc4134853d0a1ff917951b"
dependencies = [
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"x86 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"x86 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -30,6 +31,15 @@ dependencies = [
"nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "as-slice"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bare-metal"
version = "0.2.4"
@ -43,7 +53,7 @@ name = "bcm2837"
version = "1.0.0"
source = "git+https://github.com/rcore-os/bcm2837#b29a8db5504b7eaa6f8adf2c3ff916d1ffd15194"
dependencies = [
"aarch64 2.5.0 (git+https://github.com/rcore-os/aarch64)",
"aarch64 2.6.1 (git+https://github.com/rcore-os/aarch64)",
"volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -60,7 +70,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitmap-allocator"
version = "0.1.0"
source = "git+https://github.com/rcore-os/bitmap-allocator#891867c95bc81f2376ec6eca9e349c42dc26c7fb"
source = "git+https://github.com/rcore-os/bitmap-allocator#5077c47649c1bfe12606ab222e79c70b54940906"
dependencies = [
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -72,13 +82,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitvec"
version = "0.11.0"
source = "git+https://github.com/myrrlyn/bitvec.git#8ab20a3e33fe068fc3a4a05eda1211d5fcc1237b"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bootloader"
version = "0.4.0"
source = "git+https://github.com/rcore-os/bootloader#18e4fec0d82e8a5571abceb69d1d11fc0edccba1"
source = "git+https://github.com/rcore-os/bootloader?branch=vga#861e0448eba3085d9af6b5b3c9454d5c8d59f82e"
dependencies = [
"apic 0.1.0 (git+https://github.com/rcore-os/apic-rs)",
"fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
@ -101,9 +111,14 @@ name = "byteorder"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cast"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cc"
version = "1.0.31"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -124,7 +139,7 @@ source = "git+https://github.com/rcore-os/deque.git?branch=no_std#b13a836dd69ae8
[[package]]
name = "device_tree"
version = "1.0.3"
source = "git+https://github.com/rcore-os/device_tree-rs#7945459093f49a39996291283b8894753c8a638d"
source = "git+https://github.com/rcore-os/device_tree-rs#2fa8411c421c6b4761992fd3d1a9b2427bf0cfc4"
[[package]]
name = "fixedvec"
@ -152,9 +167,17 @@ dependencies = [
"typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "generic-array"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "getopts"
version = "0.2.18"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -170,9 +193,10 @@ dependencies = [
[[package]]
name = "heapless"
version = "0.4.2"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"as-slice 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"generic-array 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
"hash32 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -180,10 +204,11 @@ dependencies = [
[[package]]
name = "isomorphic_drivers"
version = "0.1.0"
source = "git+https://github.com/rcore-os/isomorphic_drivers#fe4af36d5f7bf3ac32be77597ccc61fc8cf8bd98"
source = "git+https://github.com/rcore-os/isomorphic_drivers#b6492b0759e4d6819f6591c3d29ef5ed83138531"
dependencies = [
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -198,7 +223,7 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.50"
version = "0.2.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -247,7 +272,7 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"paste-impl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro-hack 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro-hack 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -255,10 +280,10 @@ name = "paste-impl"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro-hack 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro-hack 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -269,24 +294,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "pci"
version = "0.0.1"
source = "git+https://github.com/rcore-os/pci-rs#30f2e83aa51dd313957f3fd6c3b233d3c905a4d0"
source = "git+https://github.com/rcore-os/pci-rs#3f5ca7b27f8d365f1a9b5e45d249e78bff944927"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "proc-macro-hack"
version = "0.5.4"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "proc-macro2"
version = "0.4.27"
version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -297,15 +322,15 @@ name = "pulldown-cmark"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quote"
version = "0.6.11"
version = "0.6.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -314,10 +339,10 @@ version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -339,7 +364,7 @@ version = "6.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -347,19 +372,19 @@ dependencies = [
name = "rcore"
version = "0.2.0"
dependencies = [
"aarch64 2.5.0 (git+https://github.com/rcore-os/aarch64)",
"aarch64 2.6.1 (git+https://github.com/rcore-os/aarch64)",
"apic 0.1.0 (git+https://github.com/rcore-os/apic-rs)",
"bcm2837 1.0.0 (git+https://github.com/rcore-os/bcm2837)",
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitmap-allocator 0.1.0 (git+https://github.com/rcore-os/bitmap-allocator)",
"bitvec 0.11.0 (git+https://github.com/myrrlyn/bitvec.git)",
"bootloader 0.4.0 (git+https://github.com/rcore-os/bootloader)",
"bitvec 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bootloader 0.4.0 (git+https://github.com/rcore-os/bootloader?branch=vga)",
"buddy_system_allocator 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)",
"console-traits 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"device_tree 1.0.3 (git+https://github.com/rcore-os/device_tree-rs)",
"heapless 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"heapless 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"isomorphic_drivers 0.1.0 (git+https://github.com/rcore-os/isomorphic_drivers)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -377,14 +402,14 @@ dependencies = [
"spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"uart_16550 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"x86_64 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"x86_64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rcore-fs"
version = "0.1.0"
source = "git+https://github.com/rcore-os/rcore-fs#41ccb1675cbea1df079f39fdc1bcd50c609df707"
source = "git+https://github.com/rcore-os/rcore-fs#ee0d0b31a1cea4c905100cef501a3bc522ded00d"
dependencies = [
"spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -392,7 +417,7 @@ dependencies = [
[[package]]
name = "rcore-fs-sfs"
version = "0.1.0"
source = "git+https://github.com/rcore-os/rcore-fs#41ccb1675cbea1df079f39fdc1bcd50c609df707"
source = "git+https://github.com/rcore-os/rcore-fs#ee0d0b31a1cea4c905100cef501a3bc522ded00d"
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)",
@ -411,7 +436,7 @@ dependencies = [
[[package]]
name = "rcore-thread"
version = "0.1.0"
source = "git+https://github.com/rcore-os/rcore-thread#fd972c7e3aa2b7618f625f143655c16adfd2ca78"
source = "git+https://github.com/rcore-os/rcore-thread#56021ab440fab8c7b819fed6a42649fb8bbaec07"
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)",
@ -439,13 +464,13 @@ name = "remove_dir_all"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "riscv"
version = "0.5.0"
source = "git+https://github.com/rcore-os/riscv#e8be9f93513225596709a2dccd9064324591fc3c"
source = "git+https://github.com/rcore-os/riscv#8e25d63d123773145911f4a1f718fc1bc73d80c6"
dependencies = [
"bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -504,6 +529,11 @@ name = "spin"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "stable_deref_trait"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "static_assertions"
version = "0.3.1"
@ -511,11 +541,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "syn"
version = "0.15.30"
version = "0.15.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -544,7 +574,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"x86_64 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"x86_64 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -574,7 +604,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.3.6"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -593,7 +623,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "x86"
version = "0.12.0"
version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -615,14 +645,27 @@ dependencies = [
[[package]]
name = "x86_64"
version = "0.5.4"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "x86_64"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -640,20 +683,22 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum aarch64 2.5.0 (git+https://github.com/rcore-os/aarch64)" = "<none>"
"checksum aarch64 2.6.1 (git+https://github.com/rcore-os/aarch64)" = "<none>"
"checksum apic 0.1.0 (git+https://github.com/rcore-os/apic-rs)" = "<none>"
"checksum array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "23589ecb866b460d3a0f1278834750268c607e8e28a1b982c907219f3178cd72"
"checksum as-slice 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "293dac66b274fab06f95e7efb05ec439a6b70136081ea522d270bc351ae5bb27"
"checksum bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a3caf393d93b2d453e80638d0674597020cef3382ada454faacd43d1a55a735a"
"checksum bcm2837 1.0.0 (git+https://github.com/rcore-os/bcm2837)" = "<none>"
"checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum bitmap-allocator 0.1.0 (git+https://github.com/rcore-os/bitmap-allocator)" = "<none>"
"checksum bitvec 0.11.0 (git+https://github.com/myrrlyn/bitvec.git)" = "<none>"
"checksum bitvec 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c28d4291b516ccfbb897d45de3c468c135e6af7c4f1f1aacfaae0a5bc2e6ea2c"
"checksum bitvec 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cfadef5c4e2c2e64067b9ecc061179f12ac7ec65ba613b1f60f3972bbada1f5b"
"checksum bootloader 0.4.0 (git+https://github.com/rcore-os/bootloader)" = "<none>"
"checksum bootloader 0.4.0 (git+https://github.com/rcore-os/bootloader?branch=vga)" = "<none>"
"checksum buddy_system_allocator 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "59da15ef556589ee78370281d75b67f2d69ed26465ec0e0f3961e2021502426f"
"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
"checksum cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "c9ce8bb087aacff865633f0bd5aeaed910fe2fe55b55f4739527f2e023a2e53d"
"checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427"
"checksum cc 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a0c56216487bb80eec9c4516337b2588a4f2a2290d72a1416d930e4dcdb0c90d"
"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
"checksum console-traits 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f711b3d1d5c3f7ae7d6428901c0f3e5d5f5c800fcfac86bf0252e96373a2cec6"
"checksum deque 0.3.2 (git+https://github.com/rcore-os/deque.git?branch=no_std)" = "<none>"
@ -662,12 +707,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum font8x8 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b81d84c3c978af7d05d31a2198af4b9ba956d819d15d8f6d58fc150e33f8dc1f"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum generic-array 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8107dafa78c80c848b71b60133954b4a58609a3a1a5f9af037ecc7f67280f369"
"checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797"
"checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592"
"checksum getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "72327b15c228bfe31f1390f93dd5e9279587f0463836393c9df719ce62a3e450"
"checksum hash32 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "12d790435639c06a7b798af9e1e331ae245b7ef915b92f70a39b4cf8c00686af"
"checksum heapless 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "56b960caff1a46f1fb3c1eb05f0575ac21c6248364ebebde11b11116e099881c"
"checksum heapless 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e1ae80bbc62401ae8096976857172507cadbd2200f36670e5144634360a05959"
"checksum isomorphic_drivers 0.1.0 (git+https://github.com/rcore-os/isomorphic_drivers)" = "<none>"
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
"checksum libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "aab692d7759f5cd8c859e169db98ae5b52c924add2af5fbbca11d12fefb567c1"
"checksum libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)" = "c6785aa7dd976f5fbf3b71cfd9cd49d7f783c1ff565a858d71031c6c313aa5c6"
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
"checksum managed 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fdcec5e97041c7f0f1c5b7d93f12e57293c831c646f4cc7a5db59460c7ea8de6"
@ -678,10 +724,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum paste-impl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "26e796e623b8b257215f27e6c80a5478856cae305f5b59810ff9acdaa34570e6"
"checksum pc-keyboard 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c48392db76c4e9a69e0b3be356c5f97ebb7b14413c5e4fd0af4755dbf86e2fce"
"checksum pci 0.0.1 (git+https://github.com/rcore-os/pci-rs)" = "<none>"
"checksum proc-macro-hack 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3e90aa19cd73dedc2d0e1e8407473f073d735fef0ab521438de6da8ee449ab66"
"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
"checksum proc-macro-hack 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0c1dd4172a1e1f96f709341418f49b11ea6c2d95d53dca08c0f74cbd332d9cf3"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07"
"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
@ -700,8 +746,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum smoltcp 0.5.0 (git+https://github.com/rcore-os/smoltcp)" = "<none>"
"checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f"
"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55"
"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
"checksum static_assertions 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "389ce475f424f267dbed6479cbd8f126c5e1afb053b0acdaa019c74305fc65d1"
"checksum syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)" = "66c8865bf5a7cbb662d8b011950060b3c8743dca141b054bf7195b20d314d8e2"
"checksum syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)" = "a1393e4a97a19c01e900df2aec855a29f71cf02c402e2f443b8d2747c25c5dbe"
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
"checksum tock-registers 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3a385d94f3f62e60445a0adb9ff8d9621faa272234530d4c0f848ec98f88e316"
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
@ -711,11 +758,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5"
"checksum ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dfeb711b61ce620c0cb6fd9f8e3e678622f0c971da2a63c4b3e25e88ed012f"
"checksum volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6af0edf5b4faacc31fc51159244d78d65ec580f021afcef7bd53c04aeabc7f29"
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
"checksum x86 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "841e1ca5a87068718a2a26f2473c6f93cf3b8119f9778fa0ae4b39b664d9e66a"
"checksum x86 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f21eecbd666e3a8edbf0b26d36f270f7a613d8986ca0eafb8205e324f7336dab"
"checksum x86_64 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f9258d7e2dd25008d69e8c9e9ee37865887a5e1e3d06a62f1cb3f6c209e6f177"
"checksum x86_64 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1d0a8201f52d2c7b373c7243dcdfb27c0dd5012f221ef6a126f507ee82005204"
"checksum x86_64 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bb8f09c32a991cc758ebcb9b7984f530095d32578a4e7b85db6ee1f0bbe4c9c6"
"checksum x86_64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d69bf2d256c74df90fcc68aaf99862dd205310609e9d56247a5c82ead2f28a93"
"checksum xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22678df5df766e8d1e5d609da69f0c3132d794edf6ab5e75e7abcd2270d4cf58"
"checksum zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5"

@ -19,14 +19,13 @@ 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"]
default = []
board_u540 = ["link_user"]
board_k210 = ["link_user"]
board_rocket_chip = ["link_user"]
# (for aarch64 RaspberryPi3)
nographic = []
consolegraphic = []
board_raspi3 = ["bcm2837", "link_user"]
raspi3_use_generic_timer = ["bcm2837/use_generic_timer"]
# for qemu machine
@ -55,12 +54,12 @@ bitflags = "1.0"
bit_field = "0.9"
volatile = "0.2"
heapless = "0.4"
bitvec = { git = "https://github.com/myrrlyn/bitvec.git", default-features = false, features = ["alloc"] }
bitvec = { version = "0.11", default-features = false, features = ["alloc"] }
console-traits = "0.3"
buddy_system_allocator = "0.3"
pci = { git = "https://github.com/rcore-os/pci-rs" }
device_tree = { git = "https://github.com/rcore-os/device_tree-rs" }
isomorphic_drivers = { git = "https://github.com/rcore-os/isomorphic_drivers" }
isomorphic_drivers = { git = "https://github.com/rcore-os/isomorphic_drivers", features = ["log"] }
lazy_static = { version = "1.3", features = ["spin_no_std"] }
smoltcp = { git = "https://github.com/rcore-os/smoltcp", default-features = false, features = ["alloc", "log", "proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp", "socket-raw"] }
bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator" }
@ -70,9 +69,9 @@ rcore-fs = { git = "https://github.com/rcore-os/rcore-fs" }
rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs" }
[target.'cfg(target_arch = "x86_64")'.dependencies]
bootloader = { git = "https://github.com/rcore-os/bootloader" }
bootloader = { git = "https://github.com/rcore-os/bootloader", branch = "vga" }
apic = { git = "https://github.com/rcore-os/apic-rs" }
x86_64 = "0.5"
x86_64 = "0.6"
raw-cpuid = "6.0"
uart_16550 = "0.2"
pc-keyboard = "0.5"
@ -81,7 +80,7 @@ pc-keyboard = "0.5"
riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] }
[target.'cfg(target_arch = "aarch64")'.dependencies]
aarch64 = { git = "https://github.com/rcore-os/aarch64", version = "2.5.0" }
aarch64 = { git = "https://github.com/rcore-os/aarch64", version = "2.6.1" }
bcm2837 = { git = "https://github.com/rcore-os/bcm2837", version = "1.0.0", optional = true }
[target.'cfg(target_arch = "mips")'.dependencies]

@ -21,7 +21,7 @@
# LOG = off | error | warn | info | debug | trace
# SFSIMG = <sfsimg> SFS image path of user programs
# smp = 1 | 2 | ... SMP core number
# graphic = on | off Enable/disable qemu graphical output
# graphic = on | off | console Enable/disable qemu graphical output, or print console to graphic output
# 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
@ -98,6 +98,7 @@ export DTB = $(dtb)
qemu_opts := \
-smp cores=$(smp)
qemu_net_opts :=
qemu_ui_opts :=
ifeq ($(arch), x86_64)
qemu_opts += \
@ -120,6 +121,8 @@ qemu_opts += \
-machine accel=kvm
qemu_net_opts += \
-device vfio-pci,host=$(pci_passthru)
qemu_ui_opts += \
-vga std
endif
ifeq ($(extra_nic), on)
qemu_net_opts += \
@ -138,6 +141,9 @@ qemu_opts += \
qemu_net_opts += \
-netdev type=tap,id=net0,script=no,downscript=no \
-device virtio-net-device,netdev=net0
qemu_ui_opts += \
-device virtio-gpu-device \
-device virtio-mouse-device
else ifeq ($(arch), riscv64)
ifeq ($(board), u540)
@ -158,6 +164,9 @@ endif
qemu_net_opts += \
-netdev type=tap,id=net0,script=no,downscript=no \
-device virtio-net-device,netdev=net0
qemu_ui_opts += \
-device virtio-gpu-device \
-device virtio-mouse-device
else ifeq ($(arch), aarch64)
qemu_opts += \
@ -193,10 +202,14 @@ qemu_opts += -nographic
endif
### build args ###
ifneq ($(graphic), on)
ifeq ($(graphic), off)
features += nographic
endif
ifeq ($(graphic), console)
features += consolegraphic
endif
ifneq ($(init), )
features += run_cmdline
endif
@ -271,9 +284,7 @@ justrunnet: build
@sudo qemu-system-$(arch) $(qemu_opts) $(qemu_net_opts)
justrunui: build
@qemu-system-$(arch) $(qemu_opts) \
-device virtio-gpu-device \
-device virtio-mouse-device
@qemu-system-$(arch) $(qemu_opts) $(qemu_ui_opts)
justruntest: build
@qemu-system-$(arch) $(filter-out -serial mon:stdio, $(qemu_opts)) --append $(init) -serial file:../tests/stdout -monitor null
@ -346,8 +357,9 @@ else ifeq ($(arch), aarch64)
@cargo xbuild $(build_args)
else ifeq ($(arch), mipsel)
@for file in context entry trap ; do \
$(hostcc) -E src/arch/$(arch)/boot/$${file}.S -o src/arch/$(arch)/boot/$${file}.gen.s ; \
$(hostcc) -Dboard_$(board) -E src/arch/$(arch)/boot/$${file}.S -o src/arch/$(arch)/boot/$${file}.gen.s ; \
done
$(hostcc) -Dboard_$(board) -E src/arch/$(arch)/boot/linker.ld.S -o src/arch/$(arch)/boot/linker.ld
@cargo xbuild $(build_args)
endif

@ -1,6 +1,5 @@
//! Raspberry PI 3 Model B/B+
use alloc::string::String;
use bcm2837::atags::Atags;
#[path = "../../../../drivers/gpu/fb.rs"]
@ -10,7 +9,7 @@ pub mod mailbox;
pub mod serial;
pub mod timer;
use fb::{ColorConfig, FramebufferInfo, FramebufferResult};
use fb::{ColorConfig, FramebufferResult};
pub const IO_REMAP_BASE: usize = bcm2837::consts::IO_BASE;
pub const IO_REMAP_END: usize = bcm2837::consts::KERNEL_OFFSET + 0x4000_1000;
@ -67,9 +66,8 @@ pub fn probe_fb_info(width: u32, height: u32, depth: u32) -> FramebufferResult {
))?;
}
use crate::arch::memory;
let paddr = info.bus_addr & !0xC0000000;
let vaddr = memory::ioremap(paddr as usize, info.screen_size as usize, "fb");
let vaddr = crate::memory::phys_to_virt(paddr as usize);
if vaddr == 0 {
Err(format!(
"cannot remap memory range [{:#x?}..{:#x?}]",

@ -1,7 +1,7 @@
pub const RECURSIVE_INDEX: usize = 0o777;
pub const MEMORY_OFFSET: usize = 0;
pub const KERNEL_OFFSET: usize = 0xFFFF_0000_0000_0000;
pub const KERNEL_PML4: usize = 0;
pub const PHYSICAL_MEMORY_OFFSET: usize = KERNEL_OFFSET - MEMORY_OFFSET;
pub const KERNEL_HEAP_SIZE: usize = 8 * 1024 * 1024;
pub const MEMORY_OFFSET: usize = 0;
pub const USER_STACK_OFFSET: usize = 0x0000_8000_0000_0000 - USER_STACK_SIZE;
pub const USER_STACK_SIZE: usize = 1 * 1024 * 1024;

@ -1,12 +1,13 @@
use aarch64::{asm, regs::*};
pub fn halt() {
unsafe { asm!("wfi" :::: "volatile") }
asm::wfi();
}
pub fn id() -> usize {
// TODO: cpu id
0
(MPIDR_EL1.get() & 3) as usize
}
pub unsafe fn exit_in_qemu(error_code: u8) -> ! {
pub unsafe fn exit_in_qemu(_error_code: u8) -> ! {
unimplemented!()
}

@ -1,9 +1,7 @@
//! Memory initialization for aarch64.
use super::paging::MMIOType;
use crate::consts::{KERNEL_OFFSET, MEMORY_OFFSET};
use crate::memory::{init_heap, Linear, MemoryAttr, MemorySet, FRAME_ALLOCATOR};
use aarch64::regs::*;
use crate::consts::MEMORY_OFFSET;
use crate::memory::{init_heap, virt_to_phys, FRAME_ALLOCATOR};
use log::*;
use rcore_memory::PAGE_SIZE;
@ -11,7 +9,6 @@ use rcore_memory::PAGE_SIZE;
pub fn init() {
init_frame_allocator();
init_heap();
remap_the_kernel();
info!("memory: init end");
}
@ -22,7 +19,7 @@ fn init_frame_allocator() {
let end = super::board::probe_memory()
.expect("failed to find memory map")
.1;
let start = (_end as u64 + PAGE_SIZE as u64).wrapping_sub(KERNEL_OFFSET as u64) as usize;
let start = virt_to_phys(_end as usize + PAGE_SIZE);
let mut ba = FRAME_ALLOCATOR.lock();
ba.insert(to_range(start, end));
info!("FrameAllocator init end");
@ -35,79 +32,7 @@ fn init_frame_allocator() {
}
}
static mut KERNEL_MEMORY_SET: Option<MemorySet> = None;
/// remap kernel page table after all initialization.
fn remap_the_kernel() {
let offset = -(KERNEL_OFFSET as isize);
let mut ms = MemorySet::new_bare();
ms.push(
stext as usize,
etext as usize,
MemoryAttr::default().execute().readonly(),
Linear::new(offset),
"text",
);
ms.push(
sdata as usize,
edata as usize,
MemoryAttr::default(),
Linear::new(offset),
"data",
);
ms.push(
srodata as usize,
erodata as usize,
MemoryAttr::default().readonly(),
Linear::new(offset),
"rodata",
);
ms.push(
sbss as usize,
ebss as usize,
MemoryAttr::default(),
Linear::new(offset),
"bss",
);
ms.push(
bootstack as usize,
bootstacktop as usize,
MemoryAttr::default(),
Linear::new(offset),
"kstack",
);
use super::board::{IO_REMAP_BASE, IO_REMAP_END};
ms.push(
IO_REMAP_BASE,
IO_REMAP_END,
MemoryAttr::default().mmio(MMIOType::Device as u8),
Linear::new(offset),
"io_remap",
);
info!("{:#x?}", ms);
unsafe { ms.get_page_table_mut().activate_as_kernel() }
unsafe { KERNEL_MEMORY_SET = Some(ms) }
info!("kernel remap end");
}
pub fn ioremap(paddr: usize, len: usize, name: &'static str) -> usize {
let offset = -(KERNEL_OFFSET as isize);
let vaddr = paddr.wrapping_add(KERNEL_OFFSET);
if let Some(ms) = unsafe { KERNEL_MEMORY_SET.as_mut() } {
ms.push(
vaddr,
vaddr + len,
MemoryAttr::default().mmio(MMIOType::NormalNonCacheable as u8),
Linear::new(offset),
name,
);
return vaddr;
}
0
}
#[allow(dead_code)]
extern "C" {
fn stext();
fn etext();

@ -1,26 +1,34 @@
//! Page table implementations for aarch64.
use crate::memory::{alloc_frame, dealloc_frame, phys_to_virt};
use aarch64::asm::{tlb_invalidate, tlb_invalidate_all, ttbr_el1_read, ttbr_el1_write};
use aarch64::paging::memory_attribute::*;
use aarch64::paging::{FrameAllocator, FrameDeallocator, Page, PhysFrame as Frame, Size4KiB};
use aarch64::paging::{
Mapper, PageTable as Aarch64PageTable, PageTableEntry, PageTableFlags as EF, RecursivePageTable,
frame::PhysFrame as Frame,
mapper::{MappedPageTable, Mapper},
memory_attribute::*,
page_table::{PageTable as Aarch64PageTable, PageTableEntry, PageTableFlags as EF},
FrameAllocator, FrameDeallocator, Page as PageAllSizes, Size4KiB,
};
use aarch64::{PhysAddr, VirtAddr};
use log::*;
use rcore_memory::paging::*;
// Depends on kernel
use crate::consts::{KERNEL_OFFSET, KERNEL_PML4, RECURSIVE_INDEX};
use crate::memory::{active_table, alloc_frame, dealloc_frame};
pub struct ActivePageTable(RecursivePageTable);
type Page = PageAllSizes<Size4KiB>;
pub struct PageTableImpl {
page_table: MappedPageTable<'static, fn(Frame) -> *mut Aarch64PageTable>,
root_frame: Frame,
entry: PageEntry,
}
pub struct PageEntry(PageTableEntry);
pub struct PageEntry(&'static mut PageTableEntry, Page);
impl PageTable for ActivePageTable {
impl PageTable for PageTableImpl {
fn map(&mut self, addr: usize, target: usize) -> &mut Entry {
let flags = EF::default();
let attr = MairNormal::attr_value();
self.0
unsafe {
self.page_table
.map_to(
Page::of_addr(addr as u64),
Frame::of_addr(target as u64),
@ -30,29 +38,42 @@ impl PageTable for ActivePageTable {
)
.unwrap()
.flush();
}
self.get_entry(addr).expect("fail to get entry")
}
fn unmap(&mut self, addr: usize) {
self.0.unmap(Page::of_addr(addr as u64)).unwrap().1.flush();
self.page_table
.unmap(Page::of_addr(addr as u64))
.unwrap()
.1
.flush();
}
fn get_entry(&mut self, vaddr: usize) -> Option<&mut Entry> {
// get p1 entry
let entry_addr =
((vaddr >> 9) & 0o777_777_777_7770) | (RECURSIVE_INDEX << 39) | (vaddr & KERNEL_OFFSET);
Some(unsafe { &mut *(entry_addr as *mut PageEntry) })
let page = Page::of_addr(vaddr as u64);
if let Ok(e) = self.page_table.get_entry_mut(page) {
let e = unsafe { &mut *(e as *mut PageTableEntry) };
self.entry = PageEntry(e, page);
Some(&mut self.entry as &mut Entry)
} else {
None
}
}
}
impl PageTableExt for ActivePageTable {
const TEMP_PAGE_ADDR: usize = KERNEL_OFFSET | 0xcafeb000;
fn get_page_slice_mut<'a>(&mut self, addr: usize) -> &'a mut [u8] {
let frame = self
.page_table
.translate_page(Page::of_addr(addr as u64))
.unwrap();
let vaddr = phys_to_virt(frame.start_address().as_u64() as usize);
unsafe { core::slice::from_raw_parts_mut(vaddr as *mut u8, 0x1000) }
}
}
impl ActivePageTable {
pub unsafe fn new() -> Self {
ActivePageTable(RecursivePageTable::new(RECURSIVE_INDEX as u16))
}
fn frame_to_page_table(frame: Frame) -> *mut Aarch64PageTable {
let vaddr = phys_to_virt(frame.start_address().as_u64() as usize);
vaddr as *mut Aarch64PageTable
}
#[repr(u8)]
@ -65,8 +86,7 @@ pub enum MMIOType {
impl Entry for PageEntry {
fn update(&mut self) {
let addr = VirtAddr::new_unchecked((self as *const _ as u64) << 9);
tlb_invalidate(addr);
tlb_invalidate(self.1.start_address());
}
fn present(&self) -> bool {
@ -100,7 +120,8 @@ impl Entry for PageEntry {
self.0.addr().as_u64() as usize
}
fn set_target(&mut self, target: usize) {
self.0.modify_addr(PhysAddr::new(target as u64));
self.0
.set_addr(PhysAddr::new(target as u64), self.0.flags(), self.0.attr());
}
fn writable_shared(&self) -> bool {
self.0.flags().contains(EF::WRITABLE_SHARED)
@ -163,7 +184,7 @@ impl Entry for PageEntry {
2 => MairNormalNonCacheable::attr_value(),
_ => return,
};
self.0.modify_attr(attr);
self.0.set_attr(attr);
}
}
@ -178,40 +199,45 @@ impl PageEntry {
self.0.flags().contains(EF::DIRTY)
}
fn as_flags(&mut self) -> &mut EF {
unsafe { &mut *(self as *mut _ as *mut EF) }
unsafe { &mut *(self.0 as *mut _ as *mut EF) }
}
}
#[derive(Debug)]
pub struct InactivePageTable0 {
p4_frame: Frame,
impl PageTableImpl {
/// Unsafely get the current active page table.
/// WARN: You MUST call `core::mem::forget` for it after use!
pub unsafe fn active() -> Self {
let frame = Frame::of_addr(PageTableImpl::active_token() as u64);
let table = &mut *frame_to_page_table(frame);
PageTableImpl {
page_table: MappedPageTable::new(table, frame_to_page_table),
root_frame: frame,
entry: core::mem::MaybeUninit::uninitialized().into_initialized(),
}
}
}
impl InactivePageTable for InactivePageTable0 {
type Active = ActivePageTable;
impl PageTableExt for PageTableImpl {
fn new_bare() -> Self {
let target = alloc_frame().expect("failed to allocate frame");
let frame = Frame::of_addr(target as u64);
active_table().with_temporary_map(target, |_, table: &mut Aarch64PageTable| {
let table = unsafe { &mut *frame_to_page_table(frame) };
table.zero();
// set up recursive mapping for the table
table[RECURSIVE_INDEX].set_frame(
frame.clone(),
EF::default(),
MairNormal::attr_value(),
);
});
InactivePageTable0 { p4_frame: frame }
unsafe {
PageTableImpl {
page_table: MappedPageTable::new(table, frame_to_page_table),
root_frame: frame,
entry: core::mem::MaybeUninit::uninitialized().into_initialized(),
}
}
}
fn map_kernel(&mut self) {
// When the new InactivePageTable is created for the user MemorySet, it's use ttbr0 as the
// TTBR. And the kernel TTBR ttbr1 will never changed, so we needn't call map_kernel()
// kernel page table is based on TTBR1_EL1 and will nerver change.
}
fn token(&self) -> usize {
self.p4_frame.start_address().as_u64() as usize // as TTBRx_EL1
self.root_frame.start_address().as_u64() as usize // as TTBR0_EL1
}
unsafe fn set_token(token: usize) {
@ -225,73 +251,25 @@ impl InactivePageTable for InactivePageTable0 {
fn flush_tlb() {
tlb_invalidate_all();
}
fn edit<T>(&mut self, f: impl FnOnce(&mut Self::Active) -> T) -> T {
let target = ttbr_el1_read(1);
if self.p4_frame == target {
return f(&mut active_table());
}
let target = target.start_address().as_u64() as usize;
active_table().with_temporary_map(
target,
|active_table, p4_table: &mut Aarch64PageTable| {
let backup = p4_table[RECURSIVE_INDEX].clone();
let old_frame = ttbr_el1_read(0);
// overwrite recursive mapping
p4_table[RECURSIVE_INDEX].set_frame(
self.p4_frame.clone(),
EF::default(),
MairNormal::attr_value(),
);
ttbr_el1_write(0, self.p4_frame.clone());
tlb_invalidate_all();
// execute f in the new context
let ret = f(active_table);
// restore recursive mapping to original p4 table
p4_table[RECURSIVE_INDEX] = backup;
ttbr_el1_write(0, old_frame);
tlb_invalidate_all();
ret
},
)
}
}
impl InactivePageTable0 {
/// Activate as kernel page table (TTBR0).
/// Used in `arch::memory::remap_the_kernel()`.
pub unsafe fn activate_as_kernel(&self) {
let old_frame = ttbr_el1_read(1);
let new_frame = self.p4_frame.clone();
debug!("switch TTBR1 {:?} -> {:?}", old_frame, new_frame);
if old_frame != new_frame {
ttbr_el1_write(0, Frame::of_addr(0));
ttbr_el1_write(1, new_frame);
tlb_invalidate_all();
}
}
}
impl Drop for InactivePageTable0 {
impl Drop for PageTableImpl {
fn drop(&mut self) {
info!("PageTable dropping: {:?}", self);
dealloc_frame(self.p4_frame.start_address().as_u64() as usize);
info!("PageTable dropping: {:?}", self.root_frame);
dealloc_frame(self.root_frame.start_address().as_u64() as usize);
}
}
struct FrameAllocatorForAarch64;
impl FrameAllocator<Size4KiB> for FrameAllocatorForAarch64 {
fn alloc(&mut self) -> Option<Frame> {
unsafe impl FrameAllocator<Size4KiB> for FrameAllocatorForAarch64 {
fn allocate_frame(&mut self) -> Option<Frame> {
alloc_frame().map(|addr| Frame::of_addr(addr as u64))
}
}
impl FrameDeallocator<Size4KiB> for FrameAllocatorForAarch64 {
fn dealloc(&mut self, frame: Frame) {
fn deallocate_frame(&mut self, frame: Frame) {
dealloc_frame(frame.start_address().as_u64() as usize);
}
}

@ -9,7 +9,7 @@
chosen {
stdio = &uart2;
bootargs = "rust/sh";
bootargs = "sh";
};
aliases { };

@ -1,3 +1,3 @@
/// board specific constants
pub const MEMORY_END: usize = 0x8080_0000;
pub const KERNEL_HEAP_SIZE: usize = 0x0044_0000;
pub const KERNEL_HEAP_SIZE: usize = 0x0038_0000;

@ -9,7 +9,7 @@
chosen {
stdio = &uart;
bootargs = "";
bootargs = "sh";
};
aliases { };

@ -4,7 +4,11 @@
OUTPUT_ARCH(riscv)
ENTRY(_start)
#ifdef board_thinpad
BASE_ADDRESS = 0x80000000;
#else
BASE_ADDRESS = 0x80100000;
#endif
SECTIONS
{
@ -17,6 +21,9 @@ SECTIONS
*(.text.entry)
. = ALIGN(4K);
*(.text.ebase)
_copy_user_start = .;
*(.text.copy_user)
_copy_user_end = .;
*(.text .text.*)
. = ALIGN(4K);
etext = .;

@ -32,6 +32,12 @@ trap_from_kernel:
* k1 = old stack pointer
* sp = kernel stack */
#ifdef board_thinpad
#define TRAPFRAME_SIZE 304
#else
#define TRAPFRAME_SIZE 176
#endif
# align stack pointer
andi k0, sp, 0xf
beqz k0, sp_aligned
@ -39,12 +45,13 @@ trap_from_kernel:
la k0, 0xfffffff0
and k0, sp, k0
sw sp, -176(k0)
sw sp, -TRAPFRAME_SIZE(k0)
move sp, k0
sp_aligned:
# allocate 38 words for trapframe + 6 extra words
addiu sp, sp, -176
# allocate 38 / 70 words for trapframe + 6 extra words
addiu sp, sp, -TRAPFRAME_SIZE
# save general registers
sw ra, 160(sp)
@ -80,6 +87,42 @@ sp_aligned:
sw AT, 40(sp)
nop
#ifdef board_thinpad
# save floating point registers
swc1 $f0, 164(sp)
swc1 $f1, 168(sp)
swc1 $f2, 172(sp)
swc1 $f3, 176(sp)
swc1 $f4, 180(sp)
swc1 $f5, 184(sp)
swc1 $f6, 188(sp)
swc1 $f7, 192(sp)
swc1 $f8, 196(sp)
swc1 $f9, 200(sp)
swc1 $f10, 204(sp)
swc1 $f11, 208(sp)
swc1 $f12, 212(sp)
swc1 $f13, 216(sp)
swc1 $f14, 220(sp)
swc1 $f15, 224(sp)
swc1 $f16, 228(sp)
swc1 $f17, 232(sp)
swc1 $f18, 236(sp)
swc1 $f19, 240(sp)
swc1 $f20, 244(sp)
swc1 $f21, 248(sp)
swc1 $f22, 252(sp)
swc1 $f23, 256(sp)
swc1 $f24, 260(sp)
swc1 $f25, 264(sp)
swc1 $f26, 268(sp)
swc1 $f27, 272(sp)
swc1 $f28, 276(sp)
swc1 $f29, 280(sp)
swc1 $f30, 284(sp)
swc1 $f31, 288(sp)
#endif
# save hi/lo
mflo t1
sw t1, 36(sp)
@ -158,9 +201,45 @@ trap_return:
lw fp, 156(sp)
lw ra, 160(sp)
#ifdef board_thinpad
# restore floating point registers
lwc1 $f0, 164(sp)
lwc1 $f1, 168(sp)
lwc1 $f2, 172(sp)
lwc1 $f3, 176(sp)
lwc1 $f4, 180(sp)
lwc1 $f5, 184(sp)
lwc1 $f6, 188(sp)
lwc1 $f7, 192(sp)
lwc1 $f8, 196(sp)
lwc1 $f9, 200(sp)
lwc1 $f10, 204(sp)
lwc1 $f11, 208(sp)
lwc1 $f12, 212(sp)
lwc1 $f13, 216(sp)
lwc1 $f14, 220(sp)
lwc1 $f15, 224(sp)
lwc1 $f16, 228(sp)
lwc1 $f17, 232(sp)
lwc1 $f18, 236(sp)
lwc1 $f19, 240(sp)
lwc1 $f20, 244(sp)
lwc1 $f21, 248(sp)
lwc1 $f22, 252(sp)
lwc1 $f23, 256(sp)
lwc1 $f24, 260(sp)
lwc1 $f25, 264(sp)
lwc1 $f26, 268(sp)
lwc1 $f27, 272(sp)
lwc1 $f28, 276(sp)
lwc1 $f29, 280(sp)
lwc1 $f30, 284(sp)
lwc1 $f31, 288(sp)
#endif
# save kernel stack
lw k0, 0(sp)
addiu k1, sp, 176
addiu k1, sp, TRAPFRAME_SIZE
movn k1, k0, k0
la k0, _cur_kstack_ptr

@ -2,12 +2,16 @@
///
pub use super::board::consts::*;
pub const KERNEL_OFFSET: usize = 0x80100000;
pub const MEMORY_OFFSET: usize = 0x8000_0000;
pub const USER_STACK_OFFSET: usize = 0x70000000 - USER_STACK_SIZE;
#[cfg(feature = "board_thinpad")]
pub const KERNEL_OFFSET: usize = 0x8000_0000;
#[cfg(feature = "board_malta")]
pub const KERNEL_OFFSET: usize = 0x8010_0000;
pub const PHYSICAL_MEMORY_OFFSET: usize = 0x8000_0000;
pub const USER_STACK_OFFSET: usize = 0x7000_0000 - 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;

@ -52,6 +52,39 @@ pub struct TrapFrame {
pub sp: usize,
pub fp: usize,
pub ra: usize,
/// Floating-point registers (contains garbage if no FP support present)
pub f0: usize,
pub f1: usize,
pub f2: usize,
pub f3: usize,
pub f4: usize,
pub f5: usize,
pub f6: usize,
pub f7: usize,
pub f8: usize,
pub f9: usize,
pub f10: usize,
pub f11: usize,
pub f12: usize,
pub f13: usize,
pub f14: usize,
pub f15: usize,
pub f16: usize,
pub f17: usize,
pub f18: usize,
pub f19: usize,
pub f20: usize,
pub f21: usize,
pub f22: usize,
pub f23: usize,
pub f24: usize,
pub f25: usize,
pub f26: usize,
pub f27: usize,
pub f28: usize,
pub f29: usize,
pub f30: usize,
pub f31: usize,
/// Reserved
pub reserved: usize,
pub __padding: [usize; 2],

@ -232,7 +232,7 @@ fn reserved_inst(tf: &mut TrapFrame) -> bool {
let tls = unsafe { *(_cur_tls as *const usize) };
set_trapframe_register(rt, tls, tf);
info!("Read TLS by rdhdr {:x} to register {:?}", tls, rt);
debug!("Read TLS by rdhdr {:x} to register {:?}", tls, rt);
return true;
} else {
return false;
@ -266,6 +266,15 @@ fn page_fault(tf: &mut TrapFrame) {
if !tlb_valid {
if !crate::memory::handle_page_fault(addr) {
extern "C" {
fn _copy_user_start();
fn _copy_user_end();
}
if tf.epc >= _copy_user_start as usize && tf.epc < _copy_user_end as usize {
debug!("fixup for addr {:x?}", addr);
tf.epc = crate::memory::read_user_fixup as usize;
return;
}
crate::trap::error(tf);
}
}
@ -274,6 +283,15 @@ fn page_fault(tf: &mut TrapFrame) {
}
Err(()) => {
if !crate::memory::handle_page_fault(addr) {
extern "C" {
fn _copy_user_start();
fn _copy_user_end();
}
if tf.epc >= _copy_user_start as usize && tf.epc < _copy_user_end as usize {
debug!("fixup for addr {:x?}", addr);
tf.epc = crate::memory::read_user_fixup as usize;
return;
}
crate::trap::error(tf);
}
}

@ -1,29 +1,32 @@
// Depends on kernel
use crate::memory::{active_table, alloc_frame, dealloc_frame};
use log::*;
use crate::memory::{alloc_frame, dealloc_frame};
use mips::addr::*;
use mips::paging::{FrameAllocator, FrameDeallocator};
use mips::paging::{
Mapper, PageTable as MIPSPageTable, PageTableEntry, PageTableFlags as EF, TwoLevelPageTable,
FrameAllocator, FrameDeallocator, Mapper, PageTable as MIPSPageTable, PageTableEntry,
PageTableFlags as EF, TwoLevelPageTable,
};
use mips::tlb::*;
use mips::tlb::TLBEntry;
use rcore_memory::paging::*;
pub struct ActivePageTable(usize, PageEntry);
pub struct PageTableImpl {
page_table: TwoLevelPageTable<'static>,
root_frame: Frame,
entry: PageEntry,
}
/// PageTableEntry: the contents of this entry.
/// Page: this entry is the pte of page `Page`.
pub struct PageEntry(&'static mut PageTableEntry, Page);
impl PageTable for ActivePageTable {
impl PageTable for PageTableImpl {
fn map(&mut self, addr: usize, target: usize) -> &mut Entry {
// map the 4K `page` to the 4K `frame` with `flags`
let flags = EF::VALID | EF::WRITABLE | EF::CACHEABLE;
let page = Page::of_addr(VirtAddr::new(addr));
let frame = Frame::of_addr(PhysAddr::new(target));
// we may need frame allocator to alloc frame for new page table(first/second)
self.get_table()
.map_to(page, frame, flags, &mut FrameAllocatorForRiscv)
self.page_table
.map_to(page, frame, flags, &mut FrameAllocatorForMips)
.unwrap()
.flush();
self.get_entry(addr).expect("fail to get entry")
@ -31,20 +34,29 @@ impl PageTable for ActivePageTable {
fn unmap(&mut self, addr: usize) {
let page = Page::of_addr(VirtAddr::new(addr));
let (_, flush) = self.get_table().unmap(page).unwrap();
let (_, flush) = self.page_table.unmap(page).unwrap();
flush.flush();
}
fn get_entry(&mut self, vaddr: usize) -> Option<&mut Entry> {
let page = Page::of_addr(VirtAddr::new(vaddr));
if let Ok(e) = self.get_table().ref_entry(page.clone()) {
if let Ok(e) = self.page_table.ref_entry(page.clone()) {
let e = unsafe { &mut *(e as *mut PageTableEntry) };
self.1 = PageEntry(e, page);
Some(&mut self.1 as &mut Entry)
self.entry = PageEntry(e, page);
Some(&mut self.entry as &mut Entry)
} else {
None
}
}
fn get_page_slice_mut<'a>(&mut self, addr: usize) -> &'a mut [u8] {
let frame = self
.page_table
.translate_page(Page::of_addr(VirtAddr::new(addr)))
.unwrap();
let vaddr = frame.to_kernel_unmapped().as_usize();
unsafe { core::slice::from_raw_parts_mut(vaddr as *mut u8, 0x1000) }
}
}
extern "C" {
@ -54,7 +66,7 @@ extern "C" {
pub fn set_root_page_table_ptr(ptr: usize) {
unsafe {
clear_all_tlb();
TLBEntry::clear_all();
*(_root_page_table_ptr as *mut usize) = ptr;
}
}
@ -67,35 +79,11 @@ pub fn root_page_table_buffer() -> &'static mut MIPSPageTable {
unsafe { &mut *(_root_page_table_ptr as *mut MIPSPageTable) }
}
impl PageTableExt for ActivePageTable {}
static mut __page_table_with_mode: bool = false;
/// The virtual address of root page table
impl ActivePageTable {
pub unsafe fn new() -> Self {
ActivePageTable(get_root_page_table_ptr(), ::core::mem::uninitialized())
}
unsafe fn get_raw_table(&mut self) -> *mut MIPSPageTable {
if __page_table_with_mode {
get_root_page_table_ptr() as *mut MIPSPageTable
} else {
self.0 as *mut MIPSPageTable
}
}
fn get_table(&mut self) -> TwoLevelPageTable<'static> {
unsafe { TwoLevelPageTable::new(&mut *self.get_raw_table()) }
}
}
/// implementation for the Entry trait in /crate/memory/src/paging/mod.rs
impl Entry for PageEntry {
fn update(&mut self) {
unsafe {
clear_all_tlb();
TLBEntry::clear_all();
}
}
fn accessed(&self) -> bool {
@ -158,22 +146,33 @@ impl Entry for PageEntry {
fn set_mmio(&mut self, _value: u8) {}
}
#[derive(Debug)]
pub struct InactivePageTable0 {
root_frame: Frame,
impl PageTableImpl {
/// Unsafely get the current active page table.
/// WARN: You MUST call `core::mem::forget` for it after use!
pub unsafe fn active() -> Self {
let frame = Frame::of_addr(PhysAddr::new(get_root_page_table_ptr() & 0x7fffffff));
let table = root_page_table_buffer();
PageTableImpl {
page_table: TwoLevelPageTable::new(table),
root_frame: frame,
entry: unsafe { core::mem::MaybeUninit::uninitialized().into_initialized() },
}
}
}
impl InactivePageTable for InactivePageTable0 {
type Active = ActivePageTable;
impl PageTableExt for PageTableImpl {
fn new_bare() -> Self {
let target = alloc_frame().expect("failed to allocate frame");
let frame = Frame::of_addr(PhysAddr::new(target));
let table = unsafe { &mut *(target as *mut MIPSPageTable) };
table.zero();
InactivePageTable0 { root_frame: frame }
PageTableImpl {
page_table: TwoLevelPageTable::new(table),
root_frame: frame,
entry: unsafe { core::mem::MaybeUninit::uninitialized().into_initialized() },
}
}
fn map_kernel(&mut self) {
@ -194,75 +193,26 @@ impl InactivePageTable for InactivePageTable0 {
fn flush_tlb() {
unsafe {
clear_all_tlb();
}
}
fn edit<T>(&mut self, f: impl FnOnce(&mut Self::Active) -> T) -> T {
unsafe {
clear_all_tlb();
}
debug!(
"edit table {:x?} -> {:x?}",
Self::active_token(),
self.token()
);
let mut active = unsafe { ActivePageTable(self.token(), ::core::mem::uninitialized()) };
let ret = f(&mut active);
debug!("finish table");
unsafe {
clear_all_tlb();
}
ret
}
unsafe fn with<T>(&self, f: impl FnOnce() -> T) -> T {
let old_token = Self::active_token();
let new_token = self.token();
let old_mode = unsafe { __page_table_with_mode };
unsafe {
__page_table_with_mode = true;
}
debug!("switch table {:x?} -> {:x?}", old_token, new_token);
if old_token != new_token {
Self::set_token(new_token);
Self::flush_tlb();
TLBEntry::clear_all();
}
let ret = f();
debug!("switch table {:x?} -> {:x?}", new_token, old_token);
if old_token != new_token {
Self::set_token(old_token);
Self::flush_tlb();
}
unsafe {
__page_table_with_mode = old_mode;
}
ret
}
}
impl Drop for InactivePageTable0 {
impl Drop for PageTableImpl {
fn drop(&mut self) {
dealloc_frame(self.root_frame.start_address().as_usize());
}
}
struct FrameAllocatorForRiscv;
struct FrameAllocatorForMips;
impl FrameAllocator for FrameAllocatorForRiscv {
impl FrameAllocator for FrameAllocatorForMips {
fn alloc(&mut self) -> Option<Frame> {
alloc_frame().map(|addr| Frame::of_addr(PhysAddr::new(addr)))
}
}
impl FrameDeallocator for FrameAllocatorForRiscv {
impl FrameDeallocator for FrameAllocatorForMips {
fn dealloc(&mut self, frame: Frame) {
dealloc_frame(frame.start_address().as_usize());
}

@ -17,6 +17,9 @@ SECTIONS
.text : {
stext = .;
*(.text.entry)
_copy_user_start = .;
*(.text.copy_user)
_copy_user_end = .;
*(.text .text.*)
. = ALIGN(4K);
etext = .;

@ -100,6 +100,13 @@
compatible = "xlnx,xps-intc-1.00.a";
reg = <0x61200000 0x1000>;
interrupt-parent = <&L10>;
interrupts = <0>;
};
router: router@64A00000 {
compatible = "rcore,router";
reg = <0x64A00000 0x1000>;
interrupt-parent = <&L10>;
interrupts = <1>;
};
};

@ -17,6 +17,9 @@ SECTIONS
.text : {
stext = .;
*(.text.entry)
_copy_user_start = .;
*(.text.copy_user)
_copy_user_end = .;
*(.text .text.*)
. = ALIGN(4K);
etext = .;

@ -1,19 +1,20 @@
use super::consts::KERNEL_OFFSET;
use crate::memory::phys_to_virt;
/// Mask all external interrupt except serial.
pub unsafe fn init_external_interrupt() {
const HART0_S_MODE_INTERRUPT_ENABLES: *mut u64 = (KERNEL_OFFSET + 0x0C00_2080) as *mut u64;
const HART0_S_MODE_INTERRUPT_ENABLES: *mut u64 = phys_to_virt(0x0C00_2080) as *mut u64;
// enable all external interrupts
HART0_S_MODE_INTERRUPT_ENABLES.write_volatile(0xf);
// mask interrupts first
const AXI_INTC_IER: *mut u32 = (KERNEL_OFFSET + 0x1900_0008) as *mut u32;
const AXI_INTC_IER: *mut u32 = phys_to_virt(0x6120_0008) as *mut u32;
AXI_INTC_IER.write_volatile(0x0);
// acknowledge all interrupts
const AXI_INTC_IAR: *mut u32 = (KERNEL_OFFSET + 0x1900_000C) as *mut u32;
const AXI_INTC_IAR: *mut u32 = phys_to_virt(0x6120_000C) as *mut u32;
AXI_INTC_IAR.write_volatile(0xffffffff);
const AXI_INTC_MER: *mut u32 = (KERNEL_OFFSET + 0x1900_001C) as *mut u32;
const AXI_INTC_MER: *mut u32 = phys_to_virt(0x6120_001C) as *mut u32;
// Hardware Interrupt enable | Enable irq output
AXI_INTC_MER.write_volatile(0b11);
@ -24,20 +25,19 @@ pub unsafe fn init_external_interrupt() {
/// Claim and complete external interrupt by reading and writing to
/// PLIC Interrupt Claim/Complete Register.
pub unsafe fn handle_external_interrupt() {
const HART0_S_MODE_INTERRUPT_CLAIM_COMPLETE: *mut u32 =
(KERNEL_OFFSET + 0x0C20_1004) as *mut u32;
const HART0_S_MODE_INTERRUPT_CLAIM_COMPLETE: *mut u32 = phys_to_virt(0x0C20_1004) as *mut u32;
// claim
let source = HART0_S_MODE_INTERRUPT_CLAIM_COMPLETE.read_volatile();
// complete
HART0_S_MODE_INTERRUPT_CLAIM_COMPLETE.write_volatile(source);
// acknowledge all interrupts
const AXI_INTC_IAR: *mut u32 = (KERNEL_OFFSET + 0x1900_000C) as *mut u32;
const AXI_INTC_IAR: *mut u32 = phys_to_virt(0x6120_000C) as *mut u32;
AXI_INTC_IAR.write_volatile(0xffffffff);
}
pub unsafe fn enable_serial_interrupt() {
const SERIAL_BASE: *mut u32 = (KERNEL_OFFSET + 0x18000000) as *mut u32;
const SERIAL_BASE: *mut u32 = phys_to_virt(0x60000000) as *mut u32;
const UART_CTRL_REG: usize = 3;
// Intr enable | rx reset | tx reset
const UART_IE: u32 = 0x13;

@ -17,6 +17,9 @@ SECTIONS
.text : {
stext = .;
*(.text.entry)
_copy_user_start = .;
*(.text.copy_user)
_copy_user_end = .;
*(.text .text.*)
. = ALIGN(4K);
etext = .;

@ -1,8 +1,12 @@
#[path = "../../../../drivers/gpu/fb.rs"]
pub mod fb;
use super::consts::KERNEL_OFFSET;
use crate::memory::phys_to_virt;
/// Mask all external interrupt except serial.
pub unsafe fn init_external_interrupt() {
const HART1_S_MODE_INTERRUPT_ENABLES: *mut u64 = (KERNEL_OFFSET + 0x0C00_2100) as *mut u64;
const HART1_S_MODE_INTERRUPT_ENABLES: *mut u64 = phys_to_virt(0x0C00_2100) as *mut u64;
const SERIAL: u64 = 4;
HART1_S_MODE_INTERRUPT_ENABLES.write_volatile(1 << SERIAL);
}
@ -10,8 +14,7 @@ pub unsafe fn init_external_interrupt() {
/// Claim and complete external interrupt by reading and writing to
/// PLIC Interrupt Claim/Complete Register.
pub unsafe fn handle_external_interrupt() {
const HART1_S_MODE_INTERRUPT_CLAIM_COMPLETE: *mut u32 =
(KERNEL_OFFSET + 0x0C20_2004) as *mut u32;
const HART1_S_MODE_INTERRUPT_CLAIM_COMPLETE: *mut u32 = phys_to_virt(0x0C20_2004) as *mut u32;
// claim
let source = HART1_S_MODE_INTERRUPT_CLAIM_COMPLETE.read_volatile();
// complete
@ -19,8 +22,12 @@ pub unsafe fn handle_external_interrupt() {
}
pub unsafe fn enable_serial_interrupt() {
const SERIAL_BASE: *mut u8 = (KERNEL_OFFSET + 0x10010000) as *mut u8;
const SERIAL_BASE: *mut u8 = phys_to_virt(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);
}
pub fn probe_fb_info(_width: u32, _height: u32, _depth: u32) -> fb::FramebufferResult {
unimplemented!()
}

@ -1,4 +1,7 @@
use super::consts::KERNEL_OFFSET;
#[path = "../../../../drivers/gpu/fb.rs"]
pub mod fb;
use crate::memory::phys_to_virt;
/// Mask all external interrupt except serial.
pub unsafe fn init_external_interrupt() {
@ -6,13 +9,17 @@ pub unsafe fn init_external_interrupt() {
// 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 HART0_S_MODE_INTERRUPT_ENABLES: *mut u32 = phys_to_virt(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;
const UART16550: *mut u8 = phys_to_virt(0x10000000) as *mut u8;
UART16550.add(4).write_volatile(0x0B);
UART16550.add(1).write_volatile(0x01);
}
pub fn probe_fb_info(_width: u32, _height: u32, _depth: u32) -> fb::FramebufferResult {
unimplemented!()
}

@ -12,11 +12,27 @@ _start:
lui sp, %hi(bootstack)
add sp, sp, t0
# 2. enable paging
# 2. paging
# satp = (1 << 31) | PPN(boot_page_table_sv32)
lui t0, %hi(boot_page_table_sv32)
li t1, 0xc0000000 - 0x80000000
sub t0, t0, t1
# 2.1 linear mapping (0xc0000000 -> 0x80000000)
li t2, 768*4
li t4, 0x400 << 10
li t5, 4
add t1, t0, t2
li t6, 1024*4
add t6, t0, t6
li t3, (0x80000 << 10) | 0xcf # VRWXAD
loop:
sw t3, 0(t1)
add t3, t3, t4
add t1, t1, t5
bne t1, t6, loop
# 2.2 enable paging
srli t0, t0, 12
li t1, 1 << 31
or t0, t0, t1
@ -41,15 +57,11 @@ bootstacktop:
boot_page_table_sv32:
# NOTE: assume kernel image < 16M
# 0x80000000 -> 0x80000000 (4M * 4)
# 0xc0000000 -> 0x80000000 (4M * 4)
# 0xc0000000 -> 0x80000000 (mapped in code above)
.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
.zero 4 * 256

@ -22,6 +22,9 @@ SECTIONS
.text : {
stext = .;
*(.text.entry)
_copy_user_start = .;
*(.text.copy_user)
_copy_user_end = .;
*(.text .text.*)
. = ALIGN(4K);
etext = .;

@ -17,6 +17,9 @@ SECTIONS
.text : {
stext = .;
*(.text.entry)
_copy_user_start = .;
*(.text.copy_user)
_copy_user_end = .;
*(.text .text.*)
. = ALIGN(4K);
etext = .;

@ -1,27 +1,14 @@
// Physical address available on THINPAD:
// [0x80000000, 0x80800000]
// Linear mapping
#[cfg(target_arch = "riscv32")]
pub const RECURSIVE_INDEX: usize = 0x3fd;
pub const PHYSICAL_MEMORY_OFFSET: usize = 0x4000_0000;
#[cfg(target_arch = "riscv64")]
pub const RECURSIVE_INDEX: usize = 0o774;
// Under riscv64, upon booting, paging is enabled by bbl and
// root_table[0777] maps to p3_table,
// and p3_table[0777] maps to gigapage 8000_0000H,
// so 0xFFFF_FFFF_8000_0000 maps to 0x8000_0000
// root_table[0774] points to root_table itself as page table
// root_table[0775] points to root_table itself as leaf page
// root_table[0776] points to a temp page table as leaf page
pub const PHYSICAL_MEMORY_OFFSET: usize = 0xFFFF_FFFF_4000_0000;
#[cfg(target_arch = "riscv32")]
pub const KERNEL_OFFSET: usize = 0xC000_0000;
#[cfg(target_arch = "riscv64")]
pub const KERNEL_OFFSET: usize = 0xFFFF_FFFF_C000_0000;
#[cfg(target_arch = "riscv32")]
pub const KERNEL_P2_INDEX: usize = (KERNEL_OFFSET >> 12 >> 10) & 0x3ff;
#[cfg(target_arch = "riscv64")]
pub const KERNEL_P4_INDEX: usize = (KERNEL_OFFSET >> 12 >> 9 >> 9 >> 9) & 0o777;
#[cfg(feature = "board_k210")]
pub const KERNEL_HEAP_SIZE: usize = 0x0020_0000;
#[cfg(not(feature = "board_k210"))]
@ -35,7 +22,7 @@ pub const MEMORY_END: usize = 0x8060_0000;
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;
pub const USER_STACK_OFFSET: usize = 0x40000000 - USER_STACK_SIZE;
pub const USER_STACK_SIZE: usize = 0x10000;
pub const MAX_DTB_SIZE: usize = 0x2000;

@ -132,6 +132,15 @@ fn page_fault(tf: &mut TrapFrame) {
trace!("\nEXCEPTION: Page Fault @ {:#x}", addr);
if !crate::memory::handle_page_fault(addr) {
extern "C" {
fn _copy_user_start();
fn _copy_user_end();
}
if tf.sepc >= _copy_user_start as usize && tf.sepc < _copy_user_end as usize {
debug!("fixup for addr {:x?}", addr);
tf.sepc = crate::memory::read_user_fixup as usize;
return;
}
crate::trap::error(tf);
}
}

@ -1,4 +1,4 @@
use crate::consts::{KERNEL_OFFSET, MEMORY_END, MEMORY_OFFSET};
use crate::consts::{KERNEL_OFFSET, MEMORY_END, MEMORY_OFFSET, PHYSICAL_MEMORY_OFFSET};
use crate::memory::{init_heap, Linear, MemoryAttr, MemorySet, FRAME_ALLOCATOR};
use core::mem;
use log::*;
@ -17,10 +17,6 @@ pub fn init(dtb: usize) {
// 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);
}
@ -54,112 +50,8 @@ fn init_frame_allocator() {
}
/// Remap the kernel memory address with 4K page recorded in p1 page table
fn remap_the_kernel(dtb: usize) {
let offset = -(KERNEL_OFFSET as isize - MEMORY_OFFSET as isize);
let mut ms = MemorySet::new_bare();
ms.push(
stext as usize,
etext as usize,
MemoryAttr::default().execute().readonly(),
Linear::new(offset),
"text",
);
ms.push(
sdata as usize,
edata as usize,
MemoryAttr::default(),
Linear::new(offset),
"data",
);
ms.push(
srodata as usize,
erodata as usize,
MemoryAttr::default().readonly(),
Linear::new(offset),
"rodata",
);
ms.push(
bootstack as usize,
bootstacktop as usize,
MemoryAttr::default(),
Linear::new(offset),
"stack",
);
ms.push(
sbss as usize,
ebss as usize,
MemoryAttr::default(),
Linear::new(offset),
"bss",
);
// dtb on rocket chip is embedded into kernel
#[cfg(not(feature = "board_rocket_chip"))]
ms.push(
dtb,
dtb + super::consts::MAX_DTB_SIZE,
MemoryAttr::default().readonly(),
Linear::new(offset),
"dts",
);
// map PLIC for HiFiveU & VirtIO
let offset = -(KERNEL_OFFSET as isize);
ms.push(
KERNEL_OFFSET + 0x0C00_2000,
KERNEL_OFFSET + 0x0C00_2000 + PAGE_SIZE,
MemoryAttr::default(),
Linear::new(offset),
"plic0",
);
ms.push(
KERNEL_OFFSET + 0x0C20_2000,
KERNEL_OFFSET + 0x0C20_2000 + PAGE_SIZE,
MemoryAttr::default(),
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",
);
// map PLIC for Rocket Chip
#[cfg(feature = "board_rocket_chip")]
ms.push(
KERNEL_OFFSET + 0x0C20_1000,
KERNEL_OFFSET + 0x0C20_1000 + PAGE_SIZE,
MemoryAttr::default(),
Linear::new(offset),
"plic2",
);
// map UART for Rocket Chip
#[cfg(feature = "board_rocket_chip")]
ms.push(
KERNEL_OFFSET + 0x18000000,
KERNEL_OFFSET + 0x18000000 + PAGE_SIZE,
MemoryAttr::default(),
Linear::new(-(KERNEL_OFFSET as isize + 0x18000000 - 0x60000000)),
"uartlite",
);
// map AXI INTC for Rocket Chip
#[cfg(feature = "board_rocket_chip")]
ms.push(
KERNEL_OFFSET + 0x19000000,
KERNEL_OFFSET + 0x19000000 + PAGE_SIZE,
MemoryAttr::default(),
Linear::new(-(KERNEL_OFFSET as isize + 0x19000000 - 0x61200000)),
"axi_intc",
);
fn remap_the_kernel(_dtb: usize) {
let mut ms = MemorySet::new();
unsafe {
ms.activate();
}

@ -1,12 +1,12 @@
#[cfg(feature = "board_u540")]
#[path = "board/u540/mod.rs"]
mod board;
pub mod board;
#[cfg(feature = "board_rocket_chip")]
#[path = "board/rocket_chip/mod.rs"]
mod board;
pub mod board;
#[cfg(not(any(feature = "board_u540", feature = "board_rocket_chip")))]
#[path = "board/virt/mod.rs"]
mod board;
pub mod board;
pub mod compiler_rt;
pub mod consts;
@ -20,13 +20,13 @@ mod sbi;
pub mod syscall;
pub mod timer;
use self::consts::{KERNEL_OFFSET, MEMORY_OFFSET};
use crate::memory::phys_to_virt;
use core::sync::atomic::{AtomicBool, Ordering};
use log::*;
#[no_mangle]
pub extern "C" fn rust_main(hartid: usize, device_tree_paddr: usize) -> ! {
let mut device_tree_vaddr = device_tree_paddr - MEMORY_OFFSET + KERNEL_OFFSET;
let mut device_tree_vaddr = phys_to_virt(device_tree_paddr);
unsafe {
cpu::set_cpu_id(hartid);

@ -1,10 +1,5 @@
use crate::consts::RECURSIVE_INDEX;
// Depends on kernel
#[cfg(target_arch = "riscv32")]
use crate::consts::KERNEL_P2_INDEX;
#[cfg(target_arch = "riscv64")]
use crate::consts::KERNEL_P4_INDEX;
use crate::memory::{active_table, alloc_frame, dealloc_frame};
use crate::consts::PHYSICAL_MEMORY_OFFSET;
use crate::memory::{alloc_frame, dealloc_frame, phys_to_virt};
use log::*;
use rcore_memory::paging::*;
use riscv::addr::*;
@ -16,22 +11,29 @@ use riscv::paging::{
};
use riscv::register::satp;
pub struct ActivePageTable(RecursivePageTable<'static>, PageEntry);
#[cfg(target_arch = "riscv32")]
type TopLevelPageTable<'a> = riscv::paging::Rv32PageTable<'a>;
#[cfg(target_arch = "riscv64")]
type TopLevelPageTable<'a> = riscv::paging::Rv39PageTable<'a>;
pub struct PageTableImpl {
page_table: TopLevelPageTable<'static>,
root_frame: Frame,
entry: PageEntry,
}
/// PageTableEntry: the contents of this entry.
/// Page: this entry is the pte of page `Page`.
pub struct PageEntry(&'static mut PageTableEntry, Page);
impl PageTable for ActivePageTable {
impl PageTable for PageTableImpl {
fn map(&mut self, addr: usize, target: usize) -> &mut Entry {
// use riscv::paging:Mapper::map_to,
// map the 4K `page` to the 4K `frame` with `flags`
let flags = EF::VALID | EF::READABLE | EF::WRITABLE;
let page = Page::of_addr(VirtAddr::new(addr));
let frame = Frame::of_addr(PhysAddr::new(target));
// map the page to the frame using FrameAllocatorForRiscv
// we may need frame allocator to alloc frame for new page table(first/second)
self.0
self.page_table
.map_to(page, frame, flags, &mut FrameAllocatorForRiscv)
.unwrap()
.flush();
@ -40,59 +42,28 @@ impl PageTable for ActivePageTable {
fn unmap(&mut self, addr: usize) {
let page = Page::of_addr(VirtAddr::new(addr));
let (_, flush) = self.0.unmap(page).unwrap();
let (_, flush) = self.page_table.unmap(page).unwrap();
flush.flush();
}
fn get_entry(&mut self, vaddr: usize) -> Option<&mut Entry> {
let page = Page::of_addr(VirtAddr::new(vaddr));
if let Ok(e) = self.0.ref_entry(page.clone()) {
if let Ok(e) = self.page_table.ref_entry(page.clone()) {
let e = unsafe { &mut *(e as *mut PageTableEntry) };
self.1 = PageEntry(e, page);
Some(&mut self.1 as &mut Entry)
self.entry = PageEntry(e, page);
Some(&mut self.entry as &mut Entry)
} else {
None
}
}
}
impl PageTableExt for ActivePageTable {}
/// The virtual address of root page table
#[cfg(target_arch = "riscv32")]
const ROOT_PAGE_TABLE: *mut RvPageTable =
((RECURSIVE_INDEX << 12 << 10) | ((RECURSIVE_INDEX + 1) << 12)) as *mut RvPageTable;
#[cfg(all(target_arch = "riscv64", feature = "sv39"))]
const ROOT_PAGE_TABLE: *mut RvPageTable = ((0xFFFF_0000_0000_0000)
| (0o777 << 12 << 9 << 9 << 9)
| (RECURSIVE_INDEX << 12 << 9 << 9)
| (RECURSIVE_INDEX << 12 << 9)
| ((RECURSIVE_INDEX + 1) << 12)) as *mut RvPageTable;
#[cfg(all(target_arch = "riscv64", not(feature = "sv39")))]
const ROOT_PAGE_TABLE: *mut RvPageTable = ((0xFFFF_0000_0000_0000)
| (RECURSIVE_INDEX << 12 << 9 << 9 << 9)
| (RECURSIVE_INDEX << 12 << 9 << 9)
| (RECURSIVE_INDEX << 12 << 9)
| ((RECURSIVE_INDEX + 1) << 12)) as *mut RvPageTable;
impl ActivePageTable {
#[cfg(target_arch = "riscv32")]
pub unsafe fn new() -> Self {
ActivePageTable(
RecursivePageTable::new(&mut *ROOT_PAGE_TABLE).unwrap(),
::core::mem::uninitialized(),
)
}
#[cfg(target_arch = "riscv64")]
pub unsafe fn new() -> Self {
#[cfg(feature = "sv39")]
let type_ = PageTableType::Sv39;
#[cfg(not(feature = "sv39"))]
let type_ = PageTableType::Sv48;
ActivePageTable(
RecursivePageTable::new(&mut *ROOT_PAGE_TABLE, type_).unwrap(),
::core::mem::uninitialized(),
)
fn get_page_slice_mut<'a>(&mut self, addr: usize) -> &'a mut [u8] {
let frame = self
.page_table
.translate_page(Page::of_addr(VirtAddr::new(addr)))
.unwrap();
let vaddr = frame.start_address().as_usize() + PHYSICAL_MEMORY_OFFSET;
unsafe { core::slice::from_raw_parts_mut(vaddr as *mut u8, 0x1000) }
}
}
@ -173,72 +144,107 @@ impl Entry for PageEntry {
fn set_mmio(&mut self, _value: u8) {}
}
#[derive(Debug)]
pub struct InactivePageTable0 {
root_frame: Frame,
impl PageTableImpl {
/// Unsafely get the current active page table.
/// WARN: You MUST call `core::mem::forget` for it after use!
pub unsafe fn active() -> Self {
#[cfg(target_arch = "riscv32")]
let mask = 0x7fffffff;
#[cfg(target_arch = "riscv64")]
let mask = 0x0fffffff_ffffffff;
let frame = Frame::of_ppn(PageTableImpl::active_token() & mask);
let table = frame.as_kernel_mut(PHYSICAL_MEMORY_OFFSET);
PageTableImpl {
page_table: TopLevelPageTable::new(table, PHYSICAL_MEMORY_OFFSET),
root_frame: frame,
entry: unsafe { core::mem::MaybeUninit::uninitialized().into_initialized() },
}
}
}
impl InactivePageTable for InactivePageTable0 {
type Active = ActivePageTable;
impl PageTableExt for PageTableImpl {
fn new_bare() -> Self {
let target = alloc_frame().expect("failed to allocate frame");
let frame = Frame::of_addr(PhysAddr::new(target));
active_table().with_temporary_map(target, |_, table: &mut RvPageTable| {
table.zero();
table.set_recursive(RECURSIVE_INDEX, frame.clone());
});
InactivePageTable0 { root_frame: frame }
}
#[cfg(target_arch = "riscv32")]
fn map_kernel(&mut self) {
let table = unsafe { &mut *ROOT_PAGE_TABLE };
extern "C" {
fn start();
fn end();
}
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;
for i in 0..entry_count {
entrys[i] = table[entry_start + i];
}
let table = unsafe { &mut *(phys_to_virt(target) as *mut RvPageTable) };
table.zero();
self.edit(|_| {
// NOTE: 'table' now refers to new page table
for i in 0..entry_count {
table[entry_start + i] = entrys[i];
PageTableImpl {
page_table: TopLevelPageTable::new(table, PHYSICAL_MEMORY_OFFSET),
root_frame: frame,
entry: unsafe { core::mem::MaybeUninit::uninitialized().into_initialized() },
}
});
}
#[cfg(target_arch = "riscv64")]
fn map_kernel(&mut self) {
let table = unsafe { &mut *ROOT_PAGE_TABLE };
let e1 = table[KERNEL_P4_INDEX];
assert!(!e1.is_unused());
info!("mapping kernel linear mapping");
let table = unsafe {
&mut *(phys_to_virt(self.root_frame.start_address().as_usize()) as *mut RvPageTable)
};
#[cfg(target_arch = "riscv32")]
for i in 256..1024 {
let flags =
EF::VALID | EF::READABLE | EF::WRITABLE | EF::EXECUTABLE | EF::ACCESSED | EF::DIRTY;
let frame = Frame::of_addr(PhysAddr::new((i << 22) - PHYSICAL_MEMORY_OFFSET));
table[i].set(frame, flags);
}
#[cfg(target_arch = "riscv64")]
for i in 509..512 {
if (i == 510) {
// MMIO range 0x60000000 - 0x7FFFFFFF does not work as a large page, dunno why
continue;
}
let flags =
EF::VALID | EF::READABLE | EF::WRITABLE | EF::EXECUTABLE | EF::ACCESSED | EF::DIRTY;
let frame = Frame::of_addr(PhysAddr::new(
(0xFFFFFF80_00000000 + (i << 30)) - PHYSICAL_MEMORY_OFFSET,
));
table[i].set(frame, flags);
}
self.edit(|_| {
table[KERNEL_P4_INDEX] = e1;
});
// MMIO range 0x60000000 - 0x7FFFFFFF does not work as a large page, dunno why
let flags = EF::VALID | EF::READABLE | EF::WRITABLE;
// map Uartlite for Rocket Chip
#[cfg(feature = "board_rocket_chip")]
self.page_table
.map_to(
Page::of_addr(VirtAddr::new(PHYSICAL_MEMORY_OFFSET + 0x6000_0000)),
Frame::of_addr(PhysAddr::new(0x6000_0000)),
flags,
&mut FrameAllocatorForRiscv,
)
.unwrap()
.flush();
// map AXI INTC for Rocket Chip
#[cfg(feature = "board_rocket_chip")]
self.page_table
.map_to(
Page::of_addr(VirtAddr::new(PHYSICAL_MEMORY_OFFSET + 0x6120_0000)),
Frame::of_addr(PhysAddr::new(0x6120_0000)),
flags,
&mut FrameAllocatorForRiscv,
)
.unwrap()
.flush();
// map AXI4-Stream Data FIFO for Rocket Chip
#[cfg(feature = "board_rocket_chip")]
self.page_table
.map_to(
Page::of_addr(VirtAddr::new(PHYSICAL_MEMORY_OFFSET + 0x64A0_0000)),
Frame::of_addr(PhysAddr::new(0x64A0_0000)),
flags,
&mut FrameAllocatorForRiscv,
)
.unwrap()
.flush();
}
#[cfg(target_arch = "riscv32")]
fn token(&self) -> usize {
self.root_frame.number() | (1 << 31) // as satp
}
#[cfg(target_arch = "riscv32")]
return self.root_frame.number() | (1 << 31);
#[cfg(target_arch = "riscv64")]
fn token(&self) -> usize {
use bit_field::BitField;
let mut satp = self.root_frame.number();
satp.set_bits(44..60, 0); // AS is 0
#[cfg(feature = "sv39")]
satp.set_bits(60..64, satp::Mode::Sv39 as usize);
#[cfg(not(feature = "sv39"))]
satp.set_bits(60..64, satp::Mode::Sv48 as usize);
satp
return self.root_frame.number() | (8 << 60);
}
unsafe fn set_token(token: usize) {
@ -246,41 +252,21 @@ impl InactivePageTable for InactivePageTable0 {
}
fn active_token() -> usize {
satp::read().bits()
}
fn flush_tlb() {
let mut token: usize = 0;
unsafe {
sfence_vma_all();
}
asm!("csrr $0, satp" : "=r"(token) ::: "volatile");
}
fn edit<T>(&mut self, f: impl FnOnce(&mut Self::Active) -> T) -> T {
let target = satp::read().frame().start_address().as_usize();
active_table().with_temporary_map(target, |active_table, root_table: &mut RvPageTable| {
let backup = root_table[RECURSIVE_INDEX].clone();
// overwrite recursive mapping
root_table[RECURSIVE_INDEX].set(self.root_frame.clone(), EF::VALID);
unsafe {
sfence_vma_all();
token
}
// execute f in the new context
let ret = f(active_table);
// restore recursive mapping to original p2 table
root_table[RECURSIVE_INDEX] = backup;
fn flush_tlb() {
unsafe {
sfence_vma_all();
}
ret
})
}
}
impl Drop for InactivePageTable0 {
impl Drop for PageTableImpl {
fn drop(&mut self) {
dealloc_frame(self.root_frame.start_address().as_usize());
}
@ -299,13 +285,3 @@ 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");
}

@ -0,0 +1,57 @@
#[path = "../../../drivers/gpu/fb.rs"]
pub mod fb;
use crate::consts::KERNEL_OFFSET;
use crate::memory::phys_to_virt;
use bootloader::bootinfo::{BootInfo, VbeModeInfo};
use core::mem::zeroed;
use fb::{ColorConfig, FramebufferInfo, FramebufferResult, FRAME_BUFFER};
static mut VBE_MODE: VbeModeInfo = VbeModeInfo {
_1: [0; 6],
window_size: 0,
segment_a: 0,
segment_b: 0,
_2: 0,
pitch: 0,
width: 0,
height: 0,
_3: [0; 3],
bpp: 0,
_4: [0; 14],
framebuffer: 0,
};
pub fn init_driver(boot_info: &BootInfo) {
unsafe {
VBE_MODE = boot_info.vbe_info;
}
#[cfg(not(feature = "nographic"))]
fb::init();
}
pub fn probe_fb_info(_width: u32, _height: u32, _depth: u32) -> FramebufferResult {
let width = unsafe { VBE_MODE.width as u32 };
let height = unsafe { VBE_MODE.height as u32 };
let pitch = unsafe { VBE_MODE.pitch as u32 };
let framebuffer = unsafe { VBE_MODE.framebuffer as usize };
let depth = unsafe { VBE_MODE.bpp as u32 };
let fb_info = FramebufferInfo {
xres: width,
yres: height,
xres_virtual: width,
yres_virtual: height,
xoffset: 0,
yoffset: 0,
depth: depth,
pitch: pitch, // TOKNOW
bus_addr: framebuffer as u32,
screen_size: width * height * (depth / 8),
};
// assume BGRA8888 for now
Ok((
fb_info,
fb::ColorConfig::BGRA8888,
phys_to_virt(framebuffer),
))
}

@ -1,6 +1,7 @@
pub const MEMORY_OFFSET: usize = 0;
pub const KERNEL_OFFSET: usize = 0xffffff00_00000000;
pub const KERNEL_HEAP_SIZE: usize = 8 * 1024 * 1024; // 8 MB
pub const PHYSICAL_MEMORY_OFFSET: usize = 0xfffffc00_00000000;
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

@ -1,3 +1,4 @@
use crate::memory::phys_to_virt;
use apic::{LocalApic, XApic};
use raw_cpuid::CpuId;
use x86_64::registers::control::{Cr0, Cr0Flags};
@ -21,12 +22,12 @@ pub fn id() -> usize {
}
pub fn send_ipi(cpu_id: usize) {
let mut lapic = unsafe { XApic::new(0xffffff00_fee00000) };
let mut lapic = unsafe { XApic::new(phys_to_virt(0xfee00000)) };
lapic.send_ipi(cpu_id as u8, 0x30); // TODO: Find a IPI trap num
}
pub fn init() {
let mut lapic = unsafe { XApic::new(0xffffff00_fee00000) };
let mut lapic = unsafe { XApic::new(phys_to_virt(0xfee00000)) };
lapic.cpu_init();
// enable FPU, the manual Volume 3 Chapter 13

@ -7,6 +7,7 @@ pub fn init() {
use crate::arch::interrupt::consts;
use crate::arch::interrupt::enable_irq;
enable_irq(consts::Keyboard);
info!("keyboard: init end");
}
/// Receive character from keyboard

@ -6,7 +6,13 @@ pub mod rtc_cmos;
pub mod serial;
pub mod vga;
pub fn init() {
use super::{board, BootInfo};
pub use self::board::fb;
#[path = "../../../drivers/console/mod.rs"]
pub mod console;
pub fn init(boot_info: &BootInfo) {
// Use IOAPIC instead of PIC
pic::disable();
@ -29,4 +35,9 @@ pub fn init() {
enable_irq(consts::PIRQG);
enable_irq(consts::PIRQH);
*/
board::init_driver(boot_info);
console::init();
//if let Some(con) = console::CONSOLE.lock().as_mut() {
//con.clear();
//}
}

@ -12,6 +12,7 @@ pub fn init() {
COM2.lock().init();
enable_irq(consts::COM1);
enable_irq(consts::COM2);
info!("serial: init end");
}
pub trait SerialRead {

@ -6,7 +6,7 @@ use spin::Mutex;
use volatile::Volatile;
use x86_64::instructions::port::Port;
use crate::consts::KERNEL_OFFSET;
use crate::memory::phys_to_virt;
use crate::util::color::ConsoleColor;
use crate::util::escape_parser::{EscapeParser, CSI};
@ -99,10 +99,9 @@ impl VgaBuffer {
}
lazy_static! {
pub static ref VGA_WRITER: Mutex<VgaWriter> = Mutex::new(
// VGA virtual address is specified at bootloader
VgaWriter::new(unsafe{ &mut *((KERNEL_OFFSET + 0xf0000000) as *mut VgaBuffer) })
);
pub static ref VGA_WRITER: Mutex<VgaWriter> = Mutex::new(VgaWriter::new(unsafe {
&mut *((phys_to_virt(0xb8000)) as *mut VgaBuffer)
}));
}
pub struct VgaWriter {

@ -1,5 +1,4 @@
use super::ipi::IPIEventItem;
use alloc::boxed::Box;
use alloc::vec::*;
use core::sync::atomic::{AtomicBool, Ordering};
use x86_64::registers::model_specific::Msr;
@ -8,7 +7,7 @@ use x86_64::structures::tss::TaskStateSegment;
use x86_64::{PrivilegeLevel, VirtAddr};
use crate::consts::MAX_CPU_NUM;
use crate::sync::{Semaphore, SpinLock as Mutex};
use crate::sync::SpinLock as Mutex;
/// Init TSS & GDT.
pub fn init() {
@ -36,6 +35,10 @@ 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(),
@ -48,10 +51,7 @@ impl Cpu {
}
pub fn iter() -> impl Iterator<Item = &'static Self> {
unsafe {
CPUS.iter()
.filter_map(|x| x.as_ref())
}
unsafe { CPUS.iter().filter_map(|x| x.as_ref()) }
}
pub fn id(&self) -> usize {
self.id
@ -60,9 +60,6 @@ impl Cpu {
let mut queue = self.ipi_handler_queue.lock();
queue.push(item);
}
pub fn current() -> &'static mut Cpu {
unsafe { CPUS[super::cpu::id()].as_mut().unwrap() }
}
pub fn handle_ipi(&self) {
let mut queue = self.ipi_handler_queue.lock();
let handlers = core::mem::replace(queue.as_mut(), vec![]);
@ -81,7 +78,7 @@ impl Cpu {
self.preemption_disabled.load(Ordering::Relaxed)
}
unsafe fn init(&'static mut self) {
use x86_64::instructions::segmentation::{load_fs, set_cs};
use x86_64::instructions::segmentation::set_cs;
use x86_64::instructions::tables::load_tss;
// Set the stack when DoubleFault occurs
@ -101,9 +98,18 @@ impl Cpu {
set_cs(KCODE_SELECTOR);
// load TSS
load_tss(TSS_SELECTOR);
// store address of TSS to GSBase
let mut gsbase = Msr::new(0xC0000101);
gsbase.write(&self.tss as *const _ as u64);
// 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);
}
}
@ -114,7 +120,7 @@ const KCODE: Descriptor = Descriptor::UserSegment(0x0020980000000000); // EXECUT
const UCODE: Descriptor = Descriptor::UserSegment(0x0020F80000000000); // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT | LONG_MODE
const KDATA: Descriptor = Descriptor::UserSegment(0x0000920000000000); // DATA_WRITABLE | USER_SEGMENT | PRESENT
const UDATA: Descriptor = Descriptor::UserSegment(0x0000F20000000000); // DATA_WRITABLE | USER_SEGMENT | USER_MODE | PRESENT
// Copied from xv6
// Copied from xv6
const UCODE32: Descriptor = Descriptor::UserSegment(0x00cffa00_0000ffff); // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT
const UDATA32: Descriptor = Descriptor::UserSegment(0x00cff200_0000ffff); // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT

@ -1,5 +1,4 @@
use super::super::gdt;
use super::TrapFrame;
use core::mem::transmute;
/// `syscall` instruction
use x86_64::registers::model_specific::*;

@ -147,6 +147,17 @@ fn page_fault(tf: &mut TrapFrame) {
if crate::memory::handle_page_fault(addr) {
return;
}
extern "C" {
fn _copy_user_start();
fn _copy_user_end();
}
if tf.rip >= _copy_user_start as usize && tf.rip < _copy_user_end as usize {
debug!("fixup for addr {:x?}", addr);
tf.rip = crate::memory::read_user_fixup as usize;
return;
}
error!("\nEXCEPTION: Page Fault @ {:#x}, code: {:?}", addr, code);
error(tf);
}
@ -218,3 +229,9 @@ 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);
}

@ -5,7 +5,7 @@ mod trapframe;
pub use self::handler::*;
pub use self::trapframe::*;
use crate::consts::KERNEL_OFFSET;
use crate::memory::phys_to_virt;
use apic::*;
#[inline(always)]
@ -39,12 +39,12 @@ pub fn no_interrupt(f: impl FnOnce()) {
#[inline(always)]
pub fn enable_irq(irq: u8) {
let mut ioapic = unsafe { IoApic::new(KERNEL_OFFSET + IOAPIC_ADDR as usize) };
let mut ioapic = unsafe { IoApic::new(phys_to_virt(IOAPIC_ADDR as usize)) };
ioapic.enable(irq, 0);
}
#[inline(always)]
pub fn ack(_irq: u8) {
let mut lapic = unsafe { XApic::new(KERNEL_OFFSET + LAPIC_ADDR) };
let mut lapic = unsafe { XApic::new(phys_to_virt(LAPIC_ADDR)) };
lapic.eoi();
}

@ -49,10 +49,8 @@ __alltraps:
.global trap_ret
trap_ret:
# store kernel rsp -> TSS.sp0
mov rdi, rsp
add rdi, 720
mov gs:[4], rdi
call set_return_rsp
# pop fp state offset
pop rcx
@ -106,6 +104,8 @@ 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,8 +119,11 @@ 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
@ -170,10 +173,8 @@ syscall_return:
# disable interrupt
cli
# store kernel rsp -> TSS.sp0
mov rdi, rsp
add rdi, 720
mov gs:[4], rdi
call set_return_rsp
# pop fp state offset
pop rcx

@ -1,5 +1,5 @@
use super::driver::console::CONSOLE;
use super::driver::serial::*;
use super::driver::vga::VGA_WRITER;
use core::fmt::{Arguments, Write};
pub fn getchar() -> char {
@ -10,18 +10,19 @@ pub fn getchar() -> char {
}
pub fn putfmt(fmt: Arguments) {
#[cfg(feature = "nographic")]
{
// print to console
unsafe {
COM1.force_unlock();
}
COM1.lock().write_fmt(fmt).unwrap();
}
#[cfg(not(feature = "nographic"))]
// print to graphic
#[cfg(feature = "consolegraphic")]
{
unsafe {
VGA_WRITER.force_unlock();
use super::driver::vga::VGA_WRITER;
unsafe { CONSOLE.force_unlock() }
if let Some(console) = CONSOLE.lock().as_mut() {
console.write_fmt(fmt).unwrap();
}
VGA_WRITER.lock().write_fmt(fmt).unwrap();
}
}

@ -1,7 +1,6 @@
use crate::memory::phys_to_virt;
/// Interface for inter-processor interrupt.
/// This module wraps inter-processor interrupt into a broadcast-calling style.
use crate::consts::KERNEL_OFFSET;
use alloc::boxed::{Box, FnBox};
use alloc::sync::Arc;
use apic::{LocalApic, XApic, LAPIC_ADDR};
@ -10,7 +9,7 @@ use core::sync::atomic::{spin_loop_hint, AtomicU8, Ordering};
pub type IPIEventItem = Box<FnBox()>;
unsafe fn get_apic() -> XApic {
let mut lapic = unsafe { XApic::new(KERNEL_OFFSET + LAPIC_ADDR) };
let mut lapic = XApic::new(phys_to_virt(LAPIC_ADDR));
lapic
}

@ -14,6 +14,9 @@ SECTIONS {
.text ALIGN(4K):
{
stext = .;
_copy_user_start = .;
*(.text.copy_user)
_copy_user_end = .;
*(.text .text.*)
etext = .;
}

@ -1,15 +1,10 @@
use crate::consts::KERNEL_OFFSET;
use bitmap_allocator::BitAlloc;
// Depends on kernel
use super::{BootInfo, MemoryRegionType};
use crate::memory::{active_table, init_heap, FRAME_ALLOCATOR};
use log::*;
use crate::memory::{init_heap, FRAME_ALLOCATOR};
use bitmap_allocator::BitAlloc;
use rcore_memory::paging::*;
use rcore_memory::PAGE_SIZE;
pub fn init(boot_info: &BootInfo) {
init_frame_allocator(boot_info);
init_device_vm_map();
init_heap();
info!("memory: init end");
}
@ -25,15 +20,3 @@ fn init_frame_allocator(boot_info: &BootInfo) {
}
}
}
fn init_device_vm_map() {
let mut page_table = active_table();
// IOAPIC
page_table
.map(KERNEL_OFFSET + 0xfec00000, 0xfec00000)
.update();
// LocalAPIC
page_table
.map(KERNEL_OFFSET + 0xfee00000, 0xfee00000)
.update();
}

@ -2,6 +2,7 @@ use bootloader::bootinfo::{BootInfo, MemoryRegionType};
use core::sync::atomic::*;
use log::*;
pub mod board;
pub mod consts;
pub mod cpu;
pub mod driver;
@ -9,12 +10,12 @@ pub mod gdt;
pub mod idt;
pub mod interrupt;
pub mod io;
pub mod ipi;
pub mod memory;
pub mod paging;
pub mod rand;
pub mod syscall;
pub mod timer;
pub mod ipi;
static AP_CAN_INIT: AtomicBool = AtomicBool::new(false);
@ -25,16 +26,23 @@ pub extern "C" fn _start(boot_info: &'static BootInfo) -> ! {
println!("Hello world! from CPU {}!", cpu_id);
if cpu_id != 0 {
while !AP_CAN_INIT.load(Ordering::Relaxed) {}
while !AP_CAN_INIT.load(Ordering::Relaxed) {
spin_loop_hint();
}
other_start();
}
// First init log mod, so that we can print log info.
crate::logging::init();
info!("{:#?}", boot_info);
info!("{:#x?}", boot_info);
assert_eq!(
boot_info.physical_memory_offset as usize,
consts::PHYSICAL_MEMORY_OFFSET
);
// Init trap handling.
idt::init();
// setup fast syscall in x86_64
interrupt::fast_syscall::init();
// Init physical memory management and heap.
@ -47,27 +55,29 @@ pub extern "C" fn _start(boot_info: &'static BootInfo) -> ! {
//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();
driver::init(boot_info);
// 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.
// init trap handling.
idt::init();
// init gdt
gdt::init();
// init local apic
cpu::init();
// setup fast syscall in xv6-64
// setup fast syscall in x86_64
interrupt::fast_syscall::init();
//call the first main function in kernel.
// call the first main function in kernel.
crate::kmain();
}

@ -1,6 +1,4 @@
// Depends on kernel
use crate::consts::KERNEL_OFFSET;
use crate::memory::{active_table, alloc_frame, dealloc_frame};
use crate::memory::{alloc_frame, dealloc_frame, phys_to_virt};
use core::sync::atomic::Ordering;
use log::*;
use rcore_memory::paging::*;
@ -8,12 +6,12 @@ use x86_64::instructions::tlb;
use x86_64::registers::control::{Cr3, Cr3Flags};
use x86_64::structures::paging::{
frame::PhysFrame as Frame,
mapper::{Mapper, RecursivePageTable},
mapper::{MappedPageTable, Mapper},
page::{Page, PageRange, Size4KiB},
page_table::{PageTable as x86PageTable, PageTableEntry, PageTableFlags as EF},
FrameAllocator, FrameDeallocator,
};
use x86_64::{VirtAddr, PhysAddr};
use x86_64::{PhysAddr, VirtAddr};
pub trait PageExt {
fn of_addr(address: usize) -> Self;
@ -23,7 +21,7 @@ pub trait PageExt {
impl PageExt for Page {
fn of_addr(address: usize) -> Self {
use x86_64;
Page::containing_address(x86_64::VirtAddr::new(address as u64))
Page::containing_address(VirtAddr::new(address as u64))
}
fn range_of(begin: usize, end: usize) -> PageRange {
Page::range(Page::of_addr(begin), Page::of_addr(end - 1) + 1)
@ -40,11 +38,15 @@ impl FrameExt for Frame {
}
}
pub struct ActivePageTable(RecursivePageTable<'static>);
pub struct PageTableImpl(
MappedPageTable<'static, fn(Frame) -> *mut x86PageTable>,
PageEntry,
Frame,
);
pub struct PageEntry(PageTableEntry);
pub struct PageEntry(&'static mut PageTableEntry, Page, Frame);
impl PageTable for ActivePageTable {
impl PageTable for PageTableImpl {
fn map(&mut self, addr: usize, target: usize) -> &mut Entry {
let flags = EF::PRESENT | EF::WRITABLE | EF::NO_EXECUTE;
unsafe {
@ -59,7 +61,7 @@ impl PageTable for ActivePageTable {
.flush();
}
flush_tlb_all(addr);
unsafe { &mut *(get_entry_ptr(addr, 1)) }
self.get_entry(addr).unwrap()
}
fn unmap(&mut self, addr: usize) {
@ -68,33 +70,39 @@ impl PageTable for ActivePageTable {
}
fn get_entry(&mut self, addr: usize) -> Option<&mut Entry> {
for level in 0..3 {
let entry = get_entry_ptr(addr, 4 - level);
if unsafe { !(*entry).present() } {
let mut page_table = frame_to_page_table(self.2);
for level in 0..4 {
let index = (addr >> (12 + (3 - level) * 9)) & 0o777;
let entry = unsafe { &mut (&mut *page_table)[index] };
if level == 3 {
let page = Page::of_addr(addr);
self.1 = PageEntry(entry, page, self.2);
return Some(&mut self.1 as &mut Entry);
}
if !entry.flags().contains(EF::PRESENT) {
return None;
}
page_table = frame_to_page_table(entry.frame().unwrap());
}
unsafe { Some(&mut *(get_entry_ptr(addr, 1))) }
unreachable!();
}
}
impl PageTableExt for ActivePageTable {
// FIXME: the default value 0xcafebe000 is so low that allocation might overwrite it sometimes.
// However, putting it to KERNEL_OFFSET | 0xcafeb000 has unintended effects.
// Someone needs to reconsider this and use an ultimate solution.
// const TEMP_PAGE_ADDR: usize = KERNEL_OFFSET | 0xcafeb000;
fn get_page_slice_mut<'a>(&mut self, addr: usize) -> &'a mut [u8] {
let frame = self.0.translate_page(Page::of_addr(addr)).unwrap();
let vaddr = phys_to_virt(frame.start_address().as_u64() as usize);
unsafe { core::slice::from_raw_parts_mut(vaddr as *mut u8, 0x1000) }
}
}
impl ActivePageTable {
pub unsafe fn new() -> Self {
ActivePageTable(RecursivePageTable::new(&mut *(0xffffffff_fffff000 as *mut _)).unwrap())
}
fn frame_to_page_table(frame: Frame) -> *mut x86PageTable {
let vaddr = phys_to_virt(frame.start_address().as_u64() as usize);
vaddr as *mut x86PageTable
}
impl Entry for PageEntry {
fn update(&mut self) {
use x86_64::{instructions::tlb::flush, VirtAddr};
let addr = VirtAddr::new_unchecked((self as *const _ as u64) << 9);
use x86_64::instructions::tlb::flush;
let addr = self.1.start_address();
flush(addr);
flush_tlb_all(addr.as_u64() as usize);
}
@ -153,14 +161,18 @@ impl Entry for PageEntry {
self.0.flags().contains(EF::USER_ACCESSIBLE)
}
fn set_user(&mut self, value: bool) {
self.as_flags().set(EF::USER_ACCESSIBLE, value);
// x86_64 page table struct do not implement setting USER bit
if value {
let mut addr = self as *const _ as usize;
for _ in 0..3 {
// Upper level entry
addr = ((addr >> 9) & 0o777_777_777_7770) | 0xffffff80_00000000;
// set USER_ACCESSIBLE
unsafe { (*(addr as *mut EF)).insert(EF::USER_ACCESSIBLE) };
let mut page_table = frame_to_page_table(self.2);
for level in 0..4 {
let index =
(self.1.start_address().as_u64() as usize >> (12 + (3 - level) * 9)) & 0o777;
let entry = unsafe { &mut (&mut *page_table)[index] };
entry.set_flags(entry.flags() | EF::USER_ACCESSIBLE);
if level == 3 {
return;
}
page_table = frame_to_page_table(entry.frame().unwrap());
}
}
}
@ -176,51 +188,57 @@ impl Entry for PageEntry {
fn set_mmio(&mut self, _value: u8) {}
}
fn get_entry_ptr(addr: usize, level: u8) -> *mut PageEntry {
debug_assert!(level <= 4);
let entry_addr = ((addr >> (level * 9)) & !0x7) | !((1 << (48 - level * 9)) - 1);
entry_addr as *mut PageEntry
}
impl PageEntry {
fn as_flags(&mut self) -> &mut EF {
unsafe { &mut *(self as *mut _ as *mut EF) }
unsafe { &mut *(self.0 as *mut _ as *mut EF) }
}
}
#[derive(Debug)]
pub struct InactivePageTable0 {
p4_frame: Frame,
impl PageTableImpl {
/// Unsafely get the current active page table.
/// WARN: You MUST call `core::mem::forget` for it after use!
pub unsafe fn active() -> Self {
let frame = Cr3::read().0;
let table = &mut *frame_to_page_table(frame);
PageTableImpl(
MappedPageTable::new(table, frame_to_page_table),
core::mem::MaybeUninit::uninitialized().into_initialized(),
frame,
)
}
}
impl InactivePageTable for InactivePageTable0 {
type Active = ActivePageTable;
impl PageTableExt for PageTableImpl {
fn new_bare() -> Self {
let target = alloc_frame().expect("failed to allocate frame");
let frame = Frame::of_addr(target);
active_table().with_temporary_map(target, |_, table: &mut x86PageTable| {
let table = unsafe { &mut *frame_to_page_table(frame) };
table.zero();
// set up recursive mapping for the table
table[511].set_frame(frame.clone(), EF::PRESENT | EF::WRITABLE);
});
InactivePageTable0 { p4_frame: frame }
unsafe {
PageTableImpl(
MappedPageTable::new(table, frame_to_page_table),
core::mem::MaybeUninit::uninitialized().into_initialized(),
frame,
)
}
}
fn map_kernel(&mut self) {
let table = unsafe { &mut *(0xffffffff_fffff000 as *mut x86PageTable) };
let table = unsafe { &mut *frame_to_page_table(Cr3::read().0) };
// Kernel at 0xffff_ff00_0000_0000
// Kernel stack at 0x0000_57ac_0000_0000 (defined in bootloader crate)
let e510 = table[510].clone();
let ekernel = table[510].clone();
let ephysical = table[0x1f8].clone();
let estack = table[175].clone();
self.edit(|_| {
table[510].set_addr(e510.addr(), e510.flags() | EF::GLOBAL);
let table = unsafe { &mut *frame_to_page_table(self.2) };
table[510].set_addr(ekernel.addr(), ekernel.flags() | EF::GLOBAL);
table[0x1f8].set_addr(ephysical.addr(), ephysical.flags() | EF::GLOBAL);
table[175].set_addr(estack.addr(), estack.flags() | EF::GLOBAL);
});
}
fn token(&self) -> usize {
self.p4_frame.start_address().as_u64() as usize // as CR3
self.2.start_address().as_u64() as usize // as CR3
}
unsafe fn set_token(token: usize) {
@ -237,40 +255,18 @@ impl InactivePageTable for InactivePageTable0 {
fn flush_tlb() {
tlb::flush_all();
}
fn edit<T>(&mut self, f: impl FnOnce(&mut Self::Active) -> T) -> T {
let target = Cr3::read().0.start_address().as_u64() as usize;
if self.p4_frame == Cr3::read().0 {
return f(&mut active_table());
}
active_table().with_temporary_map(target, |active_table, p4_table: &mut x86PageTable| {
let backup = p4_table[0o777].clone();
// overwrite recursive mapping
p4_table[0o777].set_frame(self.p4_frame.clone(), EF::PRESENT | EF::WRITABLE);
tlb::flush_all();
// execute f in the new context
let ret = f(active_table);
// restore recursive mapping to original p4 table
p4_table[0o777] = backup;
tlb::flush_all();
ret
})
}
}
impl Drop for InactivePageTable0 {
impl Drop for PageTableImpl {
fn drop(&mut self) {
info!("PageTable dropping: {:?}", self);
dealloc_frame(self.p4_frame.start_address().as_u64() as usize);
info!("PageTable dropping: {:?}", self.2);
dealloc_frame(self.2.start_address().as_u64() as usize);
}
}
struct FrameAllocatorForX86;
impl FrameAllocator<Size4KiB> for FrameAllocatorForX86 {
unsafe impl FrameAllocator<Size4KiB> for FrameAllocatorForX86 {
fn allocate_frame(&mut self) -> Option<Frame> {
alloc_frame().map(|addr| Frame::of_addr(addr))
}
@ -284,11 +280,10 @@ impl FrameDeallocator<Size4KiB> for FrameAllocatorForX86 {
/// Flush TLB for `vaddr` on all CPU
fn flush_tlb_all(vaddr: usize) {
// FIXME: too slow, disable now.
return;
if !super::AP_CAN_INIT.load(Ordering::Relaxed) {
return;
}
super::ipi::invoke_on_allcpu(
move || tlb::flush(VirtAddr::new(vaddr as u64)),
false,
);
super::ipi::invoke_on_allcpu(move || tlb::flush(VirtAddr::new(vaddr as u64)), false);
}

@ -8,7 +8,6 @@ use alloc::sync::Arc;
use isomorphic_drivers::block::ahci::{AHCI, BLOCK_SIZE};
use crate::drivers::provider::Provider;
use crate::drivers::BlockDriver;
use crate::sync::SpinNoIrqLock as Mutex;
use super::super::{DeviceType, Driver, BLK_DRIVERS, DRIVERS};
@ -44,10 +43,13 @@ impl Driver for AHCIDriver {
}
}
pub fn init(_irq: Option<u32>, header: usize, size: usize) -> Arc<AHCIDriver> {
let ahci = AHCI::new(header, size);
pub fn init(_irq: Option<u32>, header: usize, size: usize) -> Option<Arc<AHCIDriver>> {
if let Some(ahci) = AHCI::new(header, size) {
let driver = Arc::new(AHCIDriver(Mutex::new(ahci)));
DRIVERS.write().push(driver.clone());
BLK_DRIVERS.write().push(driver.clone());
driver
Some(driver)
} else {
None
}
}

@ -8,16 +8,14 @@ use bitflags::*;
use device_tree::util::SliceRead;
use device_tree::Node;
use log::*;
use rcore_memory::paging::PageTable;
use rcore_memory::PAGE_SIZE;
use volatile::Volatile;
use crate::drivers::BlockDriver;
use crate::memory::active_table;
use crate::sync::SpinNoIrqLock as Mutex;
use super::super::bus::virtio_mmio::*;
use super::super::{DeviceType, Driver, BLK_DRIVERS, DRIVERS};
use crate::memory::phys_to_virt;
pub struct VirtIOBlk {
interrupt_parent: u32,
@ -106,8 +104,6 @@ impl Driver for VirtIOBlkDriver {
fn try_handle_interrupt(&self, _irq: Option<u32>) -> bool {
let driver = self.0.lock();
// ensure header page is mapped
active_table().map_if_not_exists(driver.header as usize, driver.header as usize);
let header = unsafe { &mut *(driver.header as *mut VirtIOHeader) };
let interrupt = header.interrupt_status.read();
if interrupt != 0 {
@ -127,9 +123,6 @@ impl Driver for VirtIOBlkDriver {
fn read_block(&self, block_id: usize, buf: &mut [u8]) -> bool {
let mut driver = self.0.lock();
// ensure header page is mapped
active_table().map_if_not_exists(driver.header as usize, driver.header as usize);
let mut req = VirtIOBlkReadReq::default();
req.req_type = VIRTIO_BLK_T_IN;
req.reserved = 0;
@ -155,9 +148,6 @@ impl Driver for VirtIOBlkDriver {
fn write_block(&self, block_id: usize, buf: &[u8]) -> bool {
let mut driver = self.0.lock();
// ensure header page is mapped
active_table().map_if_not_exists(driver.header as usize, driver.header as usize);
let mut req: VirtIOBlkWriteReq = unsafe { zeroed() };
req.req_type = VIRTIO_BLK_T_OUT;
req.reserved = 0;
@ -184,8 +174,9 @@ impl Driver for VirtIOBlkDriver {
pub fn virtio_blk_init(node: &Node) {
let reg = node.prop_raw("reg").unwrap();
let from = reg.as_slice().read_be_u64(0).unwrap();
let header = unsafe { &mut *(from as *mut VirtIOHeader) };
let paddr = reg.as_slice().read_be_u64(0).unwrap();
let vaddr = phys_to_virt(paddr as usize);
let header = unsafe { &mut *(vaddr as *mut VirtIOHeader) };
header.status.write(VirtIODeviceStatus::DRIVER.bits());
@ -199,7 +190,7 @@ pub fn virtio_blk_init(node: &Node) {
header.write_driver_features(driver_features);
// read configuration space
let config = unsafe { &mut *((from + VIRTIO_CONFIG_SPACE_OFFSET) as *mut VirtIOBlkConfig) };
let config = unsafe { &mut *((vaddr + VIRTIO_CONFIG_SPACE_OFFSET) as *mut VirtIOBlkConfig) };
info!("Config: {:?}", config);
info!(
"Found a block device of size {}KB",
@ -213,7 +204,7 @@ pub fn virtio_blk_init(node: &Node) {
let driver = VirtIOBlkDriver(Mutex::new(VirtIOBlk {
interrupt: node.prop_u32("interrupts").unwrap(),
interrupt_parent: node.prop_u32("interrupt-parent").unwrap(),
header: from as usize,
header: vaddr as usize,
queue: VirtIOVirtqueue::new(header, 0, 16),
capacity: config.capacity.read() as usize,
}));

@ -1,12 +1,11 @@
use crate::consts::KERNEL_OFFSET;
use crate::drivers::block::*;
use crate::drivers::net::*;
use crate::drivers::{Driver, DRIVERS, NET_DRIVERS};
use crate::memory::active_table;
use crate::memory::phys_to_virt;
use alloc::collections::BTreeMap;
use alloc::sync::Arc;
use pci::*;
use rcore_memory::{paging::PageTable, PAGE_SIZE};
use rcore_memory::PAGE_SIZE;
use spin::Mutex;
const PCI_COMMAND: u16 = 0x04;
@ -17,7 +16,8 @@ const PCI_INTERRUPT_PIN: u16 = 0x3d;
const PCI_MSI_CTRL_CAP: u16 = 0x00;
const PCI_MSI_ADDR: u16 = 0x04;
const PCI_MSI_UPPER_ADDR: u16 = 0x08;
const PCI_MSI_DATA: u16 = 0x0C;
const PCI_MSI_DATA_32: u16 = 0x08;
const PCI_MSI_DATA_64: u16 = 0x0C;
const PCI_CAP_ID_MSI: u8 = 0x05;
@ -95,6 +95,7 @@ unsafe fn enable(loc: Location) -> Option<u32> {
while cap_ptr > 0 {
let cap_id = am.read8(ops, loc, cap_ptr);
if cap_id == PCI_CAP_ID_MSI {
let orig_ctrl = am.read32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP);
// The manual Volume 3 Chapter 10.11 Message Signalled Interrupts
// 0 is (usually) the apic id of the bsp.
am.write32(ops, loc, cap_ptr + PCI_MSI_ADDR, 0xfee00000 | (0 << 12));
@ -102,10 +103,15 @@ unsafe fn enable(loc: Location) -> Option<u32> {
let irq = MSI_IRQ;
assigned_irq = Some(irq);
// we offset all our irq numbers by 32
am.write32(ops, loc, cap_ptr + PCI_MSI_DATA, irq + 32);
if (orig_ctrl >> 16) & (1 << 7) != 0 {
// 64bit
am.write32(ops, loc, cap_ptr + PCI_MSI_DATA_64, irq + 32);
} else {
// 32bit
am.write32(ops, loc, cap_ptr + PCI_MSI_DATA_32, irq + 32);
}
// enable MSI interrupt, assuming 64bit for now
let orig_ctrl = am.read32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP);
am.write32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP, orig_ctrl | 0x10000);
debug!(
"MSI control {:#b}, enabling MSI interrupt {}",
@ -113,7 +119,6 @@ unsafe fn enable(loc: Location) -> Option<u32> {
irq
);
msi_found = true;
break;
}
debug!("PCI device has cap id {} at {:#X}", cap_id, cap_ptr);
cap_ptr = am.read8(ops, loc, cap_ptr + 1) as u16;
@ -126,6 +131,8 @@ unsafe fn enable(loc: Location) -> Option<u32> {
debug!("MSI not found, using PCI interrupt");
}
info!("pci device enable done");
assigned_irq
}
@ -141,12 +148,7 @@ pub fn init_driver(dev: &PCIDevice) {
// 82574L Gigabit Network Connection
if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] {
let irq = unsafe { enable(dev.loc) };
let vaddr = KERNEL_OFFSET + addr as usize;
let mut current_addr = addr as usize;
while current_addr < addr as usize + len as usize {
active_table().map_if_not_exists(KERNEL_OFFSET + current_addr, current_addr);
current_addr = current_addr + PAGE_SIZE;
}
let vaddr = phys_to_virt(addr as usize);
let index = NET_DRIVERS.read().len();
e1000::init(name, irq, vaddr, len as usize, index);
}
@ -155,12 +157,7 @@ pub fn init_driver(dev: &PCIDevice) {
// 82599ES 10-Gigabit SFI/SFP+ Network Connection
if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[0] {
let irq = unsafe { enable(dev.loc) };
let vaddr = KERNEL_OFFSET + addr as usize;
let mut current_addr = addr as usize;
while current_addr < addr as usize + len as usize {
active_table().map_if_not_exists(KERNEL_OFFSET + current_addr, current_addr);
current_addr = current_addr + PAGE_SIZE;
}
let vaddr = phys_to_virt(addr as usize);
let index = NET_DRIVERS.read().len();
PCI_DRIVERS.lock().insert(
dev.loc,
@ -168,16 +165,18 @@ pub fn init_driver(dev: &PCIDevice) {
);
}
}
(0x8086, 0x2922) => {
(0x8086, 0x2922) | (0x8086, 0xa282) | (0x8086, 0x8d02) => {
// 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA Controller [AHCI mode]
// 200 Series PCH SATA controller [AHCI mode]
// C610/X99 series chipset 6-Port SATA Controller [AHCI mode]
if let Some(BAR::Memory(addr, len, _, _)) = dev.bars[5] {
info!("Found AHCI dev {:?} BAR5 {:x?}", dev, addr);
let irq = unsafe { enable(dev.loc) };
assert!(len as usize <= PAGE_SIZE);
let vaddr = KERNEL_OFFSET + addr as usize;
active_table().map(vaddr, addr as usize);
PCI_DRIVERS
.lock()
.insert(dev.loc, ahci::init(irq, vaddr, len as usize));
let vaddr = phys_to_virt(addr as usize);
if let Some(driver) = ahci::init(irq, vaddr, len as usize) {
PCI_DRIVERS.lock().insert(dev.loc, driver);
}
}
}
_ => {}

@ -8,18 +8,16 @@ use bitflags::*;
use device_tree::util::SliceRead;
use device_tree::Node;
use log::*;
use rcore_memory::paging::PageTable;
use rcore_memory::PAGE_SIZE;
use volatile::{ReadOnly, Volatile, WriteOnly};
use crate::arch::consts::{KERNEL_OFFSET, MEMORY_OFFSET};
use crate::memory::active_table;
use crate::HEAP_ALLOCATOR;
use super::super::block::virtio_blk;
use super::super::gpu::virtio_gpu;
use super::super::input::virtio_input;
use super::super::net::virtio_net;
use crate::memory::{phys_to_virt, virt_to_phys};
// virtio 4.2.4 Legacy interface
#[repr(C)]
@ -85,10 +83,10 @@ impl VirtIOVirtqueue {
assert_eq!(header.queue_pfn.read(), 0); // not in use
let queue_num_max = header.queue_num_max.read();
assert!(queue_num_max >= queue_num as u32); // queue available
assert!(queue_num & (queue_num - 1) == 0); // power of two
assert_eq!(queue_num & (queue_num - 1), 0); // power of two
let align = PAGE_SIZE;
let size = virtqueue_size(queue_num, align);
assert!(size % align == 0);
assert_eq!(size % align, 0);
// alloc continuous pages
let address =
unsafe { HEAP_ALLOCATOR.alloc_zeroed(Layout::from_size_align(size, align).unwrap()) }
@ -96,9 +94,7 @@ impl VirtIOVirtqueue {
header.queue_num.write(queue_num as u32);
header.queue_align.write(align as u32);
header
.queue_pfn
.write(((address - KERNEL_OFFSET + MEMORY_OFFSET) as u32) >> 12);
header.queue_pfn.write((virt_to_phys(address) as u32) >> 12);
// link desc together
let desc =
@ -146,7 +142,7 @@ impl VirtIOVirtqueue {
desc[cur].flags.write(VirtIOVirtqueueFlag::NEXT.bits());
desc[cur]
.addr
.write(output[i].as_ptr() as u64 - KERNEL_OFFSET as u64 + MEMORY_OFFSET as u64);
.write(virt_to_phys(output[i].as_ptr() as usize) as u64);
desc[cur].len.write(output[i].len() as u32);
prev = cur;
cur = desc[cur].next.read() as usize;
@ -157,7 +153,7 @@ impl VirtIOVirtqueue {
.write((VirtIOVirtqueueFlag::NEXT | VirtIOVirtqueueFlag::WRITE).bits());
desc[cur]
.addr
.write(input[i].as_ptr() as u64 - KERNEL_OFFSET as u64 + MEMORY_OFFSET as u64);
.write(virt_to_phys(input[i].as_ptr() as usize) as u64);
desc[cur].len.write(input[i].len() as u32);
prev = cur;
cur = desc[cur].next.read() as usize;
@ -222,7 +218,7 @@ impl VirtIOVirtqueue {
let mut output = Vec::new();
loop {
let flags = VirtIOVirtqueueFlag::from_bits_truncate(desc[cur].flags.read());
let addr = desc[cur].addr.read() as u64 - MEMORY_OFFSET as u64 + KERNEL_OFFSET as u64;
let addr = phys_to_virt(desc[cur].addr.read() as usize);
let buffer =
unsafe { slice::from_raw_parts(addr as *const u8, desc[cur].len.read() as usize) };
if flags.contains(VirtIOVirtqueueFlag::WRITE) {
@ -265,7 +261,7 @@ impl VirtIOVirtqueue {
}
}
pub const VIRTIO_CONFIG_SPACE_OFFSET: u64 = 0x100;
pub const VIRTIO_CONFIG_SPACE_OFFSET: usize = 0x100;
impl VirtIOHeader {
pub fn read_device_features(&mut self) -> u64 {
@ -354,12 +350,13 @@ pub fn virtqueue_used_elem_offset(num: usize, align: usize) -> usize {
pub fn virtio_probe(node: &Node) {
if let Some(reg) = node.prop_raw("reg") {
let from = reg.as_slice().read_be_u64(0).unwrap();
let paddr = reg.as_slice().read_be_u64(0).unwrap();
let vaddr = phys_to_virt(paddr as usize);
debug!("walk dt {:x} {:x}", paddr, vaddr);
let size = reg.as_slice().read_be_u64(8).unwrap();
// assuming one page
assert_eq!(size as usize, PAGE_SIZE);
active_table().map(from as usize, from as usize);
let header = unsafe { &mut *(from as *mut VirtIOHeader) };
let header = unsafe { &mut *(vaddr as *mut VirtIOHeader) };
let magic = header.magic.read();
let version = header.version.read();
let device_id = header.device_id.read();
@ -374,23 +371,13 @@ pub fn virtio_probe(node: &Node) {
// virtio 3.1.1 Device Initialization
header.status.write(0);
header.status.write(VirtIODeviceStatus::ACKNOWLEDGE.bits());
if device_id == 1 {
// net device
virtio_net::virtio_net_init(node);
} else if device_id == 2 {
// blk device
virtio_blk::virtio_blk_init(node);
} else if device_id == 16 {
// gpu device
virtio_gpu::virtio_gpu_init(node);
} else if device_id == 18 {
// input device
virtio_input::virtio_input_init(node);
} else {
println!("Unrecognized virtio device {}", device_id);
match device_id {
1 => virtio_net::virtio_net_init(node),
2 => virtio_blk::virtio_blk_init(node),
16 => virtio_gpu::virtio_gpu_init(node),
18 => virtio_input::virtio_input_init(node),
_ => warn!("Unrecognized virtio device {}", device_id),
}
} else {
active_table().unmap(from as usize);
}
}
}

@ -184,6 +184,12 @@ impl<F: Font> Console<F> {
self.buf.delete(self.row, self.col);
}
}
b'\t' => {
self.write_byte(b' ');
while self.col % 8 != 0 {
self.write_byte(b' ');
}
}
b'\n' => self.new_line(),
b'\r' => self.col = 0,
b'\x1b' => self.parser.start_parse(),

@ -4,6 +4,7 @@ use core::slice;
use device_tree::{DeviceTree, Node};
use super::bus::virtio_mmio::virtio_probe;
use super::net::router::router_init;
use super::CMDLINE;
const DEVICE_TREE_MAGIC: u32 = 0xd00dfeed;
@ -14,6 +15,9 @@ fn walk_dt_node(dt: &Node) {
if compatible == "virtio,mmio" {
virtio_probe(dt);
}
if compatible == "rcore,router" {
router_init();
}
// TODO: initial other devices (16650, etc.)
}
if let Ok(bootargs) = dt.prop_str("bootargs") {

@ -1,5 +1,6 @@
//! Framebuffer
use crate::fs::vga::{fb_bitfield, fb_var_screeninfo};
use alloc::string::String;
use core::fmt;
use lazy_static::lazy_static;
@ -40,6 +41,7 @@ pub struct FramebufferInfo {
pub enum ColorDepth {
ColorDepth8 = 8,
ColorDepth16 = 16,
ColorDepth24 = 24,
ColorDepth32 = 32,
}
use self::ColorDepth::*;
@ -74,6 +76,9 @@ impl ColorBuffer {
ColorDepth16 => ColorBuffer {
buf16: core::slice::from_raw_parts_mut(base_addr as *mut u16, size / 2),
},
ColorDepth24 => ColorBuffer {
buf8: core::slice::from_raw_parts_mut(base_addr as *mut u8, size),
},
ColorDepth32 => ColorBuffer {
buf32: core::slice::from_raw_parts_mut(base_addr as *mut u32, size / 4),
},
@ -106,6 +111,14 @@ impl ColorBuffer {
unsafe { self.buf16[index as usize] = pixel }
}
#[inline]
fn write24(&mut self, index: u32, pixel: u32) {
let index = index * 3;
unsafe { self.buf8[2 + index as usize] = (pixel >> 16) as u8 }
unsafe { self.buf8[1 + index as usize] = (pixel >> 8) as u8 }
unsafe { self.buf8[index as usize] = pixel as u8 }
}
#[inline]
fn write32(&mut self, index: u32, pixel: u32) {
unsafe { self.buf32[index as usize] = pixel }
@ -141,6 +154,7 @@ impl Framebuffer {
8 => ColorDepth8,
16 => ColorDepth16,
32 => ColorDepth32,
24 => ColorDepth24,
_ => Err(format!("unsupported color depth {}", info.depth))?,
};
Ok(Framebuffer {
@ -159,12 +173,23 @@ impl Framebuffer {
unsafe { self.buf.base_addr }
}
#[inline]
pub fn framebuffer_size(&self) -> usize {
self.fb_info.screen_size as usize
}
#[inline]
pub fn bus_addr(&self) -> usize {
self.fb_info.bus_addr as usize
}
/// Read pixel at `(x, y)`.
#[inline]
pub fn read(&self, x: u32, y: u32) -> u32 {
match self.color_depth {
ColorDepth8 => self.buf.read8(y * self.fb_info.xres + x) as u32,
ColorDepth16 => self.buf.read16(y * self.fb_info.xres + x) as u32,
ColorDepth24 => self.buf.read16(y * self.fb_info.xres + x) as u32, // TODO
ColorDepth32 => self.buf.read32(y * self.fb_info.xres + x),
}
}
@ -175,6 +200,7 @@ impl Framebuffer {
match self.color_depth {
ColorDepth8 => self.buf.write8(y * self.fb_info.xres + x, pixel as u8),
ColorDepth16 => self.buf.write16(y * self.fb_info.xres + x, pixel as u16),
ColorDepth24 => self.buf.write24(y * self.fb_info.xres + x, pixel),
ColorDepth32 => self.buf.write32(y * self.fb_info.xres + x, pixel),
}
}
@ -217,6 +243,16 @@ impl Framebuffer {
pub fn clear(&mut self) {
self.fill(0, self.fb_info.screen_size as usize, 0);
}
pub fn fill_var_screeninfo(&self, var_info: &mut fb_var_screeninfo) {
var_info.xres = self.fb_info.xres;
var_info.yres = self.fb_info.yres;
var_info.xres_virtual = self.fb_info.xres_virtual;
var_info.yres_virtual = self.fb_info.yres_virtual;
var_info.xoffset = self.fb_info.xoffset;
var_info.yoffset = self.fb_info.yoffset;
var_info.bits_per_pixel = self.fb_info.depth;
}
}
lazy_static! {

@ -7,19 +7,18 @@ use bitflags::*;
use device_tree::util::SliceRead;
use device_tree::Node;
use log::*;
use rcore_memory::paging::PageTable;
use rcore_memory::PAGE_SIZE;
use volatile::{ReadOnly, Volatile, WriteOnly};
use crate::arch::consts::{KERNEL_OFFSET, MEMORY_OFFSET};
use crate::arch::cpu;
use crate::memory::active_table;
use crate::memory::virt_to_phys;
use crate::sync::SpinNoIrqLock as Mutex;
use crate::HEAP_ALLOCATOR;
use super::super::bus::virtio_mmio::*;
use super::super::{DeviceType, Driver, DRIVERS};
use super::test::mandelbrot;
use crate::memory::phys_to_virt;
const VIRTIO_GPU_EVENT_DISPLAY: u32 = 1 << 0;
@ -198,11 +197,6 @@ impl Driver for VirtIOGpuDriver {
let mut driver = self.0.lock();
// ensure header page is mapped
// TODO: this should be mapped in all page table by default
let header_addr = &mut driver.header as *mut _ as usize;
active_table().map_if_not_exists(header_addr, header_addr);
let interrupt = driver.header.interrupt_status.read();
if interrupt != 0 {
driver.header.interrupt_ack.write(interrupt);
@ -285,7 +279,7 @@ fn setup_framebuffer(driver: &mut VirtIOGpu) {
header: VirtIOGpuCtrlHdr::with_type(VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING),
resource_id: VIRTIO_GPU_RESOURCE_ID,
nr_entries: 1,
addr: (frame_buffer - KERNEL_OFFSET + MEMORY_OFFSET) as u64,
addr: virt_to_phys(frame_buffer) as u64,
length: size,
padding: 0,
};
@ -350,8 +344,9 @@ fn flush_frame_buffer_to_screen(driver: &mut VirtIOGpu) {
pub fn virtio_gpu_init(node: &Node) {
let reg = node.prop_raw("reg").unwrap();
let from = reg.as_slice().read_be_u64(0).unwrap();
let header = unsafe { &mut *(from as *mut VirtIOHeader) };
let paddr = reg.as_slice().read_be_u64(0).unwrap();
let vaddr = phys_to_virt(paddr as usize);
let header = unsafe { &mut *(vaddr as *mut VirtIOHeader) };
header.status.write(VirtIODeviceStatus::DRIVER.bits());
@ -365,7 +360,7 @@ pub fn virtio_gpu_init(node: &Node) {
header.write_driver_features(driver_features);
// read configuration space
let config = unsafe { &mut *((from + VIRTIO_CONFIG_SPACE_OFFSET) as *mut VirtIOGpuConfig) };
let config = unsafe { &mut *((vaddr + VIRTIO_CONFIG_SPACE_OFFSET) as *mut VirtIOGpuConfig) };
info!("Config: {:?}", config);
// virtio 4.2.4 Legacy interface

@ -11,16 +11,15 @@ use bitflags::*;
use device_tree::util::SliceRead;
use device_tree::Node;
use log::*;
use rcore_memory::paging::PageTable;
use rcore_memory::PAGE_SIZE;
use volatile::Volatile;
use crate::arch::cpu;
use crate::memory::active_table;
use crate::sync::SpinNoIrqLock as Mutex;
use super::super::bus::virtio_mmio::*;
use super::super::{DeviceType, Driver, DRIVERS};
use crate::memory::phys_to_virt;
struct VirtIOInput {
interrupt_parent: u32,
@ -125,11 +124,6 @@ impl VirtIOInput {
return false;
}
// ensure header page is mapped
// TODO: this should be mapped in all page table by default
let header_addr = self.header as *mut _ as usize;
active_table().map_if_not_exists(header_addr, header_addr);
let interrupt = self.header.interrupt_status.read();
if interrupt != 0 {
self.header.interrupt_ack.write(interrupt);
@ -173,8 +167,9 @@ impl Driver for VirtIOInputDriver {
pub fn virtio_input_init(node: &Node) {
let reg = node.prop_raw("reg").unwrap();
let from = reg.as_slice().read_be_u64(0).unwrap();
let header = unsafe { &mut *(from as *mut VirtIOHeader) };
let paddr = reg.as_slice().read_be_u64(0).unwrap();
let vaddr = phys_to_virt(paddr as usize);
let header = unsafe { &mut *(vaddr as *mut VirtIOHeader) };
header.status.write(VirtIODeviceStatus::DRIVER.bits());
@ -188,7 +183,7 @@ pub fn virtio_input_init(node: &Node) {
header.write_driver_features(driver_features);
// read configuration space
let config = unsafe { &mut *((from + VIRTIO_CONFIG_SPACE_OFFSET) as *mut VirtIOInputConfig) };
let config = unsafe { &mut *((vaddr + VIRTIO_CONFIG_SPACE_OFFSET) as *mut VirtIOInputConfig) };
info!("Config: {:?}", config);
// virtio 4.2.4 Legacy interface

@ -1,3 +1,4 @@
pub mod e1000;
pub mod ixgbe;
pub mod router;
pub mod virtio_net;

@ -0,0 +1,263 @@
//! rCore Router Driver
use alloc::collections::BTreeMap;
use alloc::string::String;
use alloc::sync::Arc;
use alloc::vec::Vec;
use bitflags::*;
use smoltcp::iface::*;
use smoltcp::phy::{self, DeviceCapabilities};
use smoltcp::time::Instant;
use smoltcp::wire::*;
use smoltcp::Result;
use crate::net::SOCKETS;
use crate::sync::SpinNoIrqLock as Mutex;
use super::super::{DeviceType, Driver, DRIVERS, NET_DRIVERS, SOCKET_ACTIVITY};
use crate::memory::phys_to_virt;
const AXI_STREAM_FIFO_ISR: *mut u32 = phys_to_virt(0x64A0_0000) as *mut u32;
const AXI_STREAM_FIFO_IER: *mut u32 = phys_to_virt(0x64A0_0004) as *mut u32;
const AXI_STREAM_FIFO_TDFR: *mut u32 = phys_to_virt(0x64A0_0008) as *mut u32;
const AXI_STREAM_FIFO_TDFD: *mut u32 = phys_to_virt(0x64A0_0010) as *mut u32;
const AXI_STREAM_FIFO_TLR: *mut u32 = phys_to_virt(0x64A0_0014) as *mut u32;
const AXI_STREAM_FIFO_RDFR: *mut u32 = phys_to_virt(0x64A0_0018) as *mut u32;
const AXI_STREAM_FIFO_RDFO: *mut u32 = phys_to_virt(0x64A0_001C) as *mut u32;
const AXI_STREAM_FIFO_RDFD: *mut u32 = phys_to_virt(0x64A0_0020) as *mut u32;
const AXI_STREAM_FIFO_RLR: *mut u32 = phys_to_virt(0x64A0_0024) as *mut u32;
const AXI_STREAM_FIFO_TDR: *mut u32 = phys_to_virt(0x64A0_002C) as *mut u32;
const AXI_STREAM_FIFO_RDR: *mut u32 = phys_to_virt(0x64A0_0030) as *mut u32;
const ENABLED_PORTS: u8 = 2;
bitflags! {
struct AXIStreamFifoInterrupt : u32 {
const RECV_EMPTY = 1 << 19;
const RECV_FULL = 1 << 20;
const TRAN_EMPTY = 1 << 21;
const TRAN_FULL = 1 << 22;
const RECV_RESET = 1 << 23;
const TRAN_RESET = 1 << 24;
const TRAN_SIZE_ERR = 1 << 25;
const RECV_COMPLETE = 1 << 26;
const TRAN_COMPLETE = 1 << 27;
const TRAN_PACKET_OVERRUN_ERR = 1 << 28;
const RECV_PACKET_UNDERRUN_ERR = 1 << 29;
const RECV_PACKET_OVERRUN_READ_ERR = 1 << 30;
const RECV_PACKET_UNDERRUN_READ_ERR = 1 << 31;
}
}
pub struct Router {
buffer: [Vec<Vec<u8>>; ENABLED_PORTS as usize],
}
impl Router {
fn transmit_available(&self) -> bool {
true
}
fn receive_available(&self, port: u8) -> bool {
self.buffer[port as usize].len() > 0
}
}
#[derive(Clone)]
pub struct RouterDriver(Arc<Mutex<Router>>, u8);
pub struct RouterRxToken(RouterDriver);
pub struct RouterTxToken(RouterDriver);
impl<'a> phy::Device<'a> for RouterDriver {
type RxToken = RouterRxToken;
type TxToken = RouterTxToken;
fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
let driver = self.0.lock();
if driver.transmit_available() && driver.receive_available(self.1) {
// potential racing
Some((RouterRxToken(self.clone()), RouterTxToken(self.clone())))
} else {
None
}
}
fn transmit(&'a mut self) -> Option<Self::TxToken> {
let driver = self.0.lock();
if driver.transmit_available() {
Some(RouterTxToken(self.clone()))
} else {
None
}
}
fn capabilities(&self) -> DeviceCapabilities {
let mut caps = DeviceCapabilities::default();
caps.max_transmission_unit = 1536;
caps.max_burst_size = Some(1);
caps
}
}
impl phy::RxToken for RouterRxToken {
fn consume<R, F>(self, _timestamp: Instant, f: F) -> Result<R>
where
F: FnOnce(&[u8]) -> Result<R>,
{
let mut router = (self.0).0.lock();
let buffer = router.buffer[(self.0).1 as usize].pop().unwrap();
f(&buffer)
}
}
impl phy::TxToken for RouterTxToken {
fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> Result<R>
where
F: FnOnce(&mut [u8]) -> Result<R>,
{
let mut buffer = vec![0; len];
let res = f(&mut buffer);
debug!(
"out buf {} data {:x?} port {}",
len,
&buffer[..20],
(self.0).1
);
unsafe {
AXI_STREAM_FIFO_TDR.write_volatile(2);
AXI_STREAM_FIFO_TDFD.write_volatile((self.0).1 as u32);
for byte in buffer {
AXI_STREAM_FIFO_TDFD.write_volatile(byte as u32);
}
AXI_STREAM_FIFO_TLR.write(((len + 1) * 4) as u32);
}
res
}
}
pub struct RouterInterface {
iface: Mutex<EthernetInterface<'static, 'static, 'static, RouterDriver>>,
driver: RouterDriver,
}
impl Driver for RouterInterface {
fn try_handle_interrupt(&self, _irq: Option<u32>) -> bool {
let mut driver = self.driver.0.lock();
let isr = unsafe { AXI_STREAM_FIFO_ISR.read_volatile() };
if isr > 0 {
debug!(
"handle router interrupt {:?}",
AXIStreamFifoInterrupt::from_bits_truncate(isr)
);
unsafe {
AXI_STREAM_FIFO_ISR.write(isr);
let rdfo = AXI_STREAM_FIFO_RDFO.read_volatile();
if rdfo > 0 {
let mut buffer = Vec::new();
let rlr = AXI_STREAM_FIFO_RLR.read_volatile();
let rdr = AXI_STREAM_FIFO_RDR.read_volatile();
let port = AXI_STREAM_FIFO_RDFD.read_volatile();
for i in 1..rdfo {
buffer.push(AXI_STREAM_FIFO_RDFD.read_volatile() as u8);
}
debug!(
"got packet of length {} port {} data {:x?}",
rdfo,
port,
&buffer[..20]
);
driver.buffer[port as usize].push(buffer);
}
drop(driver);
let timestamp = Instant::from_millis(crate::trap::uptime_msec() as i64);
let mut sockets = SOCKETS.lock();
match self.iface.lock().poll(&mut sockets, timestamp) {
Ok(_) => {
SOCKET_ACTIVITY.notify_all();
}
Err(err) => {
debug!("poll got err {}", err);
}
}
}
return true;
}
return false;
}
fn device_type(&self) -> DeviceType {
DeviceType::Net
}
fn get_id(&self) -> String {
format!("router")
}
fn get_mac(&self) -> EthernetAddress {
unimplemented!()
}
fn get_ifname(&self) -> String {
format!("router")
}
fn ipv4_address(&self) -> Option<Ipv4Address> {
unimplemented!()
}
fn poll(&self) {
unimplemented!()
}
}
pub fn router_init() {
unsafe {
// reset tx fifo
AXI_STREAM_FIFO_TDFR.write_volatile(0xA5);
// reset rx fifo
AXI_STREAM_FIFO_RDFR.write_volatile(0xA5);
}
for i in 0..ENABLED_PORTS {
let ethernet_addr = EthernetAddress::from_bytes(&[2, 2, 3, 3, 0, i]);
let net_driver = RouterDriver(
Arc::new(Mutex::new(Router {
buffer: [Vec::new(), Vec::new()],
})),
i,
);
let ip_addrs = [IpCidr::new(IpAddress::v4(10, 0, i, 1), 24)];
let neighbor_cache = NeighborCache::new(BTreeMap::new());
let routes = Routes::new(BTreeMap::new());
let iface = EthernetInterfaceBuilder::new(net_driver.clone())
.ethernet_addr(ethernet_addr)
.ip_addrs(ip_addrs)
.neighbor_cache(neighbor_cache)
.routes(routes)
.finalize();
info!("router interface up #{}", i);
let router_iface = RouterInterface {
iface: Mutex::new(iface),
driver: net_driver,
};
let driver = Arc::new(router_iface);
DRIVERS.write().push(driver.clone());
NET_DRIVERS.write().push(driver.clone());
}
// Enable Receive Complete Interrupt
unsafe {
AXI_STREAM_FIFO_IER.write_volatile(1 << 26);
}
}

@ -9,7 +9,6 @@ use bitflags::*;
use device_tree::util::SliceRead;
use device_tree::Node;
use log::*;
use rcore_memory::paging::PageTable;
use rcore_memory::PAGE_SIZE;
use smoltcp::phy::{self, DeviceCapabilities};
use smoltcp::time::Instant;
@ -17,12 +16,12 @@ use smoltcp::wire::{EthernetAddress, Ipv4Address};
use smoltcp::Result;
use volatile::{ReadOnly, Volatile};
use crate::memory::active_table;
use crate::sync::SpinNoIrqLock as Mutex;
use crate::HEAP_ALLOCATOR;
use super::super::bus::virtio_mmio::*;
use super::super::{DeviceType, Driver, DRIVERS, NET_DRIVERS};
use crate::memory::phys_to_virt;
pub struct VirtIONet {
interrupt_parent: u32,
@ -43,9 +42,6 @@ impl Driver for VirtIONetDriver {
fn try_handle_interrupt(&self, _irq: Option<u32>) -> bool {
let driver = self.0.lock();
// ensure header page is mapped
active_table().map_if_not_exists(driver.header as usize, driver.header as usize);
let header = unsafe { &mut *(driver.header as *mut VirtIOHeader) };
let interrupt = header.interrupt_status.read();
if interrupt != 0 {
@ -138,10 +134,6 @@ impl phy::RxToken for VirtIONetRxToken {
{
let (input, output, _, user_data) = {
let mut driver = (self.0).0.lock();
// ensure header page is mapped
active_table().map_if_not_exists(driver.header as usize, driver.header as usize);
driver.queues[VIRTIO_QUEUE_RECEIVE].get().unwrap()
};
let result = f(&input[0][size_of::<VirtIONetHeader>()..]);
@ -159,10 +151,6 @@ impl phy::TxToken for VirtIONetTxToken {
{
let output = {
let mut driver = (self.0).0.lock();
// ensure header page is mapped
active_table().map_if_not_exists(driver.header as usize, driver.header as usize);
if let Some((_, output, _, _)) = driver.queues[VIRTIO_QUEUE_TRANSMIT].get() {
unsafe { slice::from_raw_parts_mut(output[0].as_ptr() as *mut u8, output[0].len()) }
} else {
@ -252,8 +240,9 @@ struct VirtIONetHeader {
pub fn virtio_net_init(node: &Node) {
let reg = node.prop_raw("reg").unwrap();
let from = reg.as_slice().read_be_u64(0).unwrap();
let header = unsafe { &mut *(from as *mut VirtIOHeader) };
let paddr = reg.as_slice().read_be_u64(0).unwrap();
let vaddr = phys_to_virt(paddr as usize);
let header = unsafe { &mut *(vaddr as *mut VirtIOHeader) };
header.status.write(VirtIODeviceStatus::DRIVER.bits());
@ -267,7 +256,8 @@ pub fn virtio_net_init(node: &Node) {
header.write_driver_features(driver_features);
// read configuration space
let config = unsafe { &mut *((from + VIRTIO_CONFIG_SPACE_OFFSET) as *mut VirtIONetworkConfig) };
let config =
unsafe { &mut *((vaddr + VIRTIO_CONFIG_SPACE_OFFSET) as *mut VirtIONetworkConfig) };
let mac = config.mac;
let status = VirtIONetworkStatus::from_bits_truncate(config.status.read());
debug!("Got MAC address {:?} and status {:?}", mac, status);
@ -280,7 +270,7 @@ pub fn virtio_net_init(node: &Node) {
let mut driver = VirtIONet {
interrupt: node.prop_u32("interrupts").unwrap(),
interrupt_parent: node.prop_u32("interrupt-parent").unwrap(),
header: from as usize,
header: vaddr as usize,
mac: EthernetAddress(mac),
queues: [
VirtIOVirtqueue::new(header, VIRTIO_QUEUE_RECEIVE, queue_num),

@ -1,25 +1,27 @@
use alloc::alloc::{alloc_zeroed, dealloc, Layout};
pub use crate::arch::paging::PageTableImpl;
use crate::memory::{alloc_frame, dealloc_frame, phys_to_virt, virt_to_phys};
use isomorphic_drivers::provider;
use rcore_memory::paging::PageTable;
use rcore_memory::PAGE_SIZE;
use crate::memory::active_table;
pub struct Provider;
impl provider::Provider for Provider {
const PAGE_SIZE: usize = PAGE_SIZE;
fn alloc_dma(size: usize) -> (usize, usize) {
let layout = Layout::from_size_align(size, PAGE_SIZE).unwrap();
let vaddr = unsafe { alloc_zeroed(layout) } as usize;
let paddr = active_table().get_entry(vaddr).unwrap().target();
// TODO: allocate continuous pages
let mut paddr = alloc_frame().unwrap();
for i in 1..(size / PAGE_SIZE) {
let paddr_new = alloc_frame().unwrap();
assert_eq!(paddr - PAGE_SIZE, paddr_new);
paddr = paddr_new;
}
let vaddr = phys_to_virt(paddr);
(vaddr, paddr)
}
fn dealloc_dma(vaddr: usize, size: usize) {
let layout = Layout::from_size_align(size, PAGE_SIZE).unwrap();
unsafe { dealloc(vaddr as *mut u8, layout) }
let paddr = virt_to_phys(vaddr);
dealloc_frame(paddr);
}
}

@ -68,14 +68,21 @@ impl SerialPort {
impl Write for SerialPort {
fn write_str(&mut self, s: &str) -> Result {
for c in s.bytes() {
if c == 127 {
match c {
127 => {
self.putchar(8);
self.putchar(b' ');
self.putchar(8);
} else {
}
b'\n' => {
self.putchar(b'\r');
self.putchar(b'\n');
}
c => {
self.putchar(c);
}
}
}
Ok(())
}
}

@ -59,14 +59,21 @@ impl SerialPort {
impl Write for SerialPort {
fn write_str(&mut self, s: &str) -> Result {
for c in s.bytes() {
if c == 127 {
match c {
127 => {
self.putchar(8);
self.putchar(b' ');
self.putchar(8);
} else {
}
b'\n' => {
self.putchar(b'\r');
self.putchar(b'\n');
}
c => {
self.putchar(c);
}
}
}
Ok(())
}
}

@ -68,14 +68,21 @@ impl SerialPort {
impl Write for SerialPort {
fn write_str(&mut self, s: &str) -> Result {
for c in s.bytes() {
if c == 127 {
match c {
127 => {
self.putchar(8);
self.putchar(b' ');
self.putchar(8);
} else {
}
b'\n' => {
self.putchar(b'\r');
self.putchar(b'\n');
}
c => {
self.putchar(c);
}
}
}
Ok(())
}
}

@ -1,5 +1,6 @@
//! File handle for process
use crate::thread;
use alloc::{string::String, sync::Arc};
use core::fmt;
@ -19,6 +20,7 @@ pub struct OpenOptions {
pub write: bool,
/// Before each write, the file offset is positioned at the end of the file.
pub append: bool,
pub nonblock: bool,
}
#[derive(Debug)]
@ -48,7 +50,26 @@ impl FileHandle {
if !self.options.read {
return Err(FsError::InvalidParam); // FIXME: => EBADF
}
let len = self.inode.read_at(offset, buf)?;
let mut len: usize = 0;
if !self.options.nonblock {
// block
loop {
match self.inode.read_at(offset, buf) {
Ok(read_len) => {
len = read_len;
break;
}
Err(FsError::Again) => {
thread::yield_now();
}
Err(err) => {
return Err(err);
}
}
}
} else {
len = self.inode.read_at(offset, buf)?;
}
Ok(len)
}
@ -123,6 +144,13 @@ impl FileHandle {
pub fn inode(&self) -> Arc<INode> {
self.inode.clone()
}
pub fn fcntl(&mut self, cmd: usize, arg: usize) -> Result<()> {
if arg == 2048 && cmd == 4 {
self.options.nonblock = true;
}
Ok(())
}
}
impl fmt::Debug for FileHandle {

@ -32,7 +32,7 @@ impl FileLike {
}
pub fn ioctl(&mut self, request: usize, arg1: usize, arg2: usize, arg3: usize) -> SysResult {
match request {
// TODO: place flags & path in FileLike in stead of FileHandle/Socket
// TODO: place flags & path in FileLike instead of FileHandle/Socket
FIOCLEX => Ok(0),
FIONBIO => Ok(0),
_ => {
@ -56,6 +56,16 @@ impl FileLike {
};
Ok(status)
}
pub fn fcntl(&mut self, cmd: usize, arg: usize) -> SysResult {
match self {
FileLike::File(file) => file.fcntl(cmd, arg)?,
FileLike::Socket(socket) => {
//TODO
}
}
Ok(0)
}
}
impl fmt::Debug for FileLike {

@ -11,6 +11,7 @@ pub use self::file_like::*;
pub use self::pipe::Pipe;
pub use self::pseudo::*;
pub use self::stdio::{STDIN, STDOUT};
pub use self::vga::*;
mod device;
mod file;
@ -19,8 +20,9 @@ mod ioctl;
mod pipe;
mod pseudo;
mod stdio;
pub mod vga;
/// Hard link user programs
// Hard link user programs
#[cfg(feature = "link_user")]
global_asm!(concat!(
r#"

@ -45,13 +45,25 @@ impl Pipe {
)
}
pub fn can_read(&self) -> bool {
fn can_read(&self) -> bool {
if let PipeEnd::Read = self.direction {
self.data.lock().buf.len() > 0
self.data.lock().buf.len() > 0 || self.is_broken()
} else {
false
}
}
fn can_write(&self) -> bool {
if let PipeEnd::Write = self.direction {
!self.is_broken()
} else {
false
}
}
fn is_broken(&self) -> bool {
Arc::strong_count(&self.data) < 2
}
}
// TODO: better way to provide default impl?
@ -105,39 +117,11 @@ impl INode for Pipe {
}
fn poll(&self) -> Result<PollStatus> {
let data = self.data.lock();
match self.direction {
PipeEnd::Read => {
if data.buf.len() > 0 {
Ok(PollStatus {
read: true,
write: false,
error: false,
})
} else {
Ok(PollStatus {
read: false,
write: false,
read: self.can_read(),
write: self.can_write(),
error: false,
})
}
}
PipeEnd::Write => {
if data.buf.len() > 0 {
Ok(PollStatus {
read: false,
write: true,
error: false,
})
} else {
Ok(PollStatus {
read: false,
write: false,
error: false,
})
}
}
}
}
impl_inode!();
}

@ -72,6 +72,7 @@ impl INode for Pseudo {
nlinks: 0,
uid: 0,
gid: 0,
rdev: 0,
})
}
impl_inode!();

@ -91,8 +91,12 @@ macro_rules! impl_inode {
impl INode for Stdin {
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
if self.can_read() {
buf[0] = self.pop() as u8;
Ok(1)
} else {
Err(FsError::Again)
}
}
fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize> {
unimplemented!()

@ -0,0 +1,173 @@
use rcore_fs::vfs::*;
use crate::arch::board::fb::FRAME_BUFFER;
use crate::memory::phys_to_virt;
use alloc::{string::String, sync::Arc, vec::Vec};
use core::any::Any;
#[derive(Default)]
pub struct Vga;
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 fs(&self) -> Arc<FileSystem> { unimplemented!() }
fn as_any_ref(&self) -> &Any { self }
};
}
impl INode for Vga {
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
Err(FsError::NotSupported)
}
fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize> {
info!("the _offset is {} {}", _offset, _buf[0]);
let lock = FRAME_BUFFER.lock();
if let Some(ref frame_buffer) = *lock {
use core::slice;
let frame_buffer_data = unsafe {
slice::from_raw_parts_mut(
frame_buffer.base_addr() as *mut u8,
frame_buffer.framebuffer_size(),
)
};
frame_buffer_data.copy_from_slice(&_buf);
Ok(frame_buffer.framebuffer_size())
} else {
Err(FsError::EntryNotFound)
}
}
fn poll(&self) -> Result<PollStatus> {
Ok(PollStatus {
// TOKNOW and TODO
read: true,
write: false,
error: false,
})
}
fn metadata(&self) -> Result<Metadata> {
Ok(Metadata {
dev: 0,
inode: 0,
size: 0x24000,
blk_size: 0,
blocks: 0,
atime: Timespec { sec: 0, nsec: 0 },
mtime: Timespec { sec: 0, nsec: 0 },
ctime: Timespec { sec: 0, nsec: 0 },
type_: FileType::SymLink,
mode: 0,
nlinks: 0,
uid: 0,
gid: 0,
rdev: 0,
})
}
fn io_control(&self, cmd: u32, data: usize) -> Result<()> {
info!("cmd {:#x} , data {:#x} vga not support ioctl !", cmd, data);
match cmd {
FBIOGET_FSCREENINFO => {
let fb_fix_info = unsafe { &mut *(data as *mut fb_fix_screeninfo) };
fb_fix_info.line_length = 100;
Ok(())
}
FBIOGET_VSCREENINFO => {
let fb_var_info = unsafe { &mut *(data as *mut fb_var_screeninfo) };
if let Some(fb) = FRAME_BUFFER.lock().as_ref() {
fb.fill_var_screeninfo(fb_var_info);
}
Ok(())
}
_ => {
warn!("use never support ioctl !");
Err(FsError::NotSupported)
}
}
//let fb_fix_info = unsafe{ &mut *(data as *mut fb_fix_screeninfo) };
//Ok(())
}
impl_inode!();
}
const FBIOGET_FSCREENINFO: u32 = 0x4602;
const FBIOGET_VSCREENINFO: u32 = 0x4600;
#[repr(C)]
struct fb_fix_screeninfo {
pub id: [u8; 16], /* identification string eg "TT Builtin" */
pub smem_start: u64, /* Start of frame buffer mem */
/* (physical address) */
pub smem_len: u32, /* Length of frame buffer mem */
pub _type: u32, /* see FB_TYPE_* */
pub type_aux: u32, /* Interleave for interleaved Planes */
pub visual: u32, /* see FB_VISUAL_* */
pub xpanstep: u16, /* zero if no hardware panning */
pub ypanstep: u16, /* zero if no hardware panning */
pub ywrapstep: u16, /* zero if no hardware ywrap */
pub line_length: u32, /* length of a line in bytes */
pub mmio_start: u64, /* Start of Memory Mapped I/O */
/* (physical address) */
pub mmio_len: u32, /* Length of Memory Mapped I/O */
pub accel: u32, /* Indicate to driver which */
/* specific chip/card we have */
pub capabilities: u16, /* see FB_CAP_* */
pub reserved: [u16; 2], /* Reserved for future compatibility */
}
#[repr(C)]
pub struct fb_var_screeninfo {
pub xres: u32, /* visible resolution */
pub yres: u32,
pub xres_virtual: u32, /* virtual resolution */
pub yres_virtual: u32,
pub xoffset: u32, /* offset from virtual to visible */
pub yoffset: u32, /* resolution */
pub bits_per_pixel: u32, /* guess what */
pub grayscale: u32, /* 0 = color, 1 = grayscale, */
/* >1 = FOURCC */
pub red: fb_bitfield, /* bitfield in fb mem if true color, */
pub green: fb_bitfield, /* else only length is significant */
pub blue: fb_bitfield,
pub transp: fb_bitfield, /* transparency */
pub nonstd: u32, /* != 0 Non standard pixel format */
pub activate: u32, /* see FB_ACTIVATE_* */
pub height: u32, /* height of picture in mm */
pub width: u32, /* width of picture in mm */
pub accel_flags: u32, /* (OBSOLETE) see fb_info.flags */
/* Timing: All values in pixclocks, except pixclock (of course) */
pub pixclock: u32, /* pixel clock in ps (pico seconds) */
pub left_margin: u32, /* time from sync to picture */
pub right_margin: u32, /* time from picture to sync */
pub upper_margin: u32, /* time from sync to picture */
pub lower_margin: u32,
pub hsync_len: u32, /* length of horizontal sync */
pub vsync_len: u32, /* length of vertical sync */
pub sync: u32, /* see FB_SYNC_* */
pub vmode: u32, /* see FB_VMODE_* */
pub rotate: u32, /* angle we rotate counter clockwise */
pub colorspace: u32, /* colorspace for FOURCC-based modes */
pub reserved: [u32; 4], /* Reserved for future compatibility */
}
#[repr(C)]
pub struct fb_bitfield {
pub offset: u32, /* beginning of bitfield */
pub length: u32, /* length of bitfield */
pub msb_right: u32, /* != 0 : Most significant bit is */
/* right */
}

@ -7,6 +7,7 @@
#![feature(panic_info_message)]
#![feature(global_asm)]
#![feature(fnbox)]
#![feature(maybe_uninit)]
#![deny(unused_must_use)]
#![no_std]

@ -3,6 +3,7 @@ use core::fmt;
use lazy_static::lazy_static;
use log::{self, Level, LevelFilter, Log, Metadata, Record};
use crate::processor;
use crate::sync::SpinNoIrqLock as Mutex;
use crate::util::color::ConsoleColor;
@ -63,12 +64,17 @@ impl Log for SimpleLogger {
true
}
fn log(&self, record: &Record) {
static DISABLED_TARGET: &[&str] = &[];
if self.enabled(record.metadata()) && !DISABLED_TARGET.contains(&record.target()) {
// let target = record.target();
// let begin = target.as_bytes().iter().rposition(|&c| c == b':').map(|i| i + 1).unwrap_or(0);
if !self.enabled(record.metadata()) {
return;
}
if let Some(tid) = processor().tid_option() {
print_in_color(
format_args!("[{:>5}][{}] {}\n", record.level(), tid, record.args()),
ConsoleColor::from(record.level()),
);
} else {
print_in_color(
format_args!("[{:>5}] {}\n", record.level(), record.args()),
format_args!("[{:>5}][-] {}\n", record.level(), record.args()),
ConsoleColor::from(record.level()),
);
}

@ -14,24 +14,24 @@
use super::HEAP_ALLOCATOR;
pub use crate::arch::paging::*;
use crate::consts::{KERNEL_OFFSET, MEMORY_OFFSET};
use crate::consts::{MEMORY_OFFSET, PHYSICAL_MEMORY_OFFSET};
use crate::process::current_thread;
use crate::sync::SpinNoIrqLock;
use alloc::boxed::Box;
use bitmap_allocator::BitAlloc;
use buddy_system_allocator::Heap;
use core::mem;
use core::mem::size_of;
use lazy_static::*;
use log::*;
pub use rcore_memory::memory_set::{handler::*, MemoryArea, MemoryAttr};
use rcore_memory::paging::PageTable;
use rcore_memory::*;
pub type MemorySet = rcore_memory::memory_set::MemorySet<InactivePageTable0>;
pub type MemorySet = rcore_memory::memory_set::MemorySet<PageTableImpl>;
// x86_64 support up to 64G memory
// x86_64 support up to 1T memory
#[cfg(target_arch = "x86_64")]
pub type FrameAlloc = bitmap_allocator::BitAlloc16M;
pub type FrameAlloc = bitmap_allocator::BitAlloc256M;
// RISCV, ARM, MIPS has 1G memory
#[cfg(all(
@ -54,22 +54,14 @@ lazy_static! {
SpinNoIrqLock::new(FrameAlloc::default());
}
/// The only way to get active page table
///
/// ## CHANGE LOG
///
/// In the past, this function returns a `MutexGuard` of a global
/// `Mutex<ActiveTable>` object, which means only one CPU core
/// can access its active table at a time.
///
/// But given that a page table is ** process local **, and being active
/// when and only when a thread of the process is running.
/// The ownership of this page table is in the `MemorySet` object.
/// So it's safe to access the active table inside `MemorySet`.
/// But the shared parts is readonly, e.g. all pages mapped in
/// `InactivePageTable::map_kernel()`.
pub fn active_table() -> ActivePageTable {
unsafe { ActivePageTable::new() }
/// Convert physical address to virtual address
pub const fn phys_to_virt(paddr: usize) -> usize {
PHYSICAL_MEMORY_OFFSET + paddr
}
/// Convert virtual address to physical address
pub const fn virt_to_phys(vaddr: usize) -> usize {
vaddr - PHYSICAL_MEMORY_OFFSET
}
#[derive(Debug, Clone, Copy)]
@ -139,13 +131,13 @@ pub fn handle_page_fault(addr: usize) -> bool {
pub fn init_heap() {
use crate::consts::KERNEL_HEAP_SIZE;
const machine_align: usize = mem::size_of::<usize>();
const heap_block: usize = KERNEL_HEAP_SIZE / machine_align;
static mut HEAP: [usize; heap_block] = [0; heap_block];
const MACHINE_ALIGN: usize = mem::size_of::<usize>();
const HEAP_BLOCK: usize = KERNEL_HEAP_SIZE / MACHINE_ALIGN;
static mut HEAP: [usize; HEAP_BLOCK] = [0; HEAP_BLOCK];
unsafe {
HEAP_ALLOCATOR
.lock()
.init(HEAP.as_ptr() as usize, heap_block * machine_align);
.init(HEAP.as_ptr() as usize, HEAP_BLOCK * MACHINE_ALIGN);
}
info!("heap init end");
}
@ -153,13 +145,9 @@ pub fn init_heap() {
pub fn enlarge_heap(heap: &mut Heap) {
info!("Enlarging heap to avoid oom");
let mut page_table = active_table();
let mut addrs = [(0, 0); 32];
let mut addr_len = 0;
#[cfg(target_arch = "x86_64")]
let va_offset = KERNEL_OFFSET + 0xe0000000;
#[cfg(not(target_arch = "x86_64"))]
let va_offset = KERNEL_OFFSET + 0x00e00000;
let va_offset = PHYSICAL_MEMORY_OFFSET;
for i in 0..16384 {
let page = alloc_frame().unwrap();
let va = va_offset + page;
@ -175,12 +163,37 @@ pub fn enlarge_heap(heap: &mut Heap) {
addr_len += 1;
}
for (addr, len) in addrs[..addr_len].into_iter() {
for va in (*addr..(*addr + *len)).step_by(PAGE_SIZE) {
page_table.map(va, va - va_offset).update();
}
info!("Adding {:#X} {:#X} to heap", addr, len);
unsafe {
heap.init(*addr, *len);
}
}
}
/// Check whether the address range [addr, addr + len) is not in kernel space
pub fn access_ok(addr: usize, len: usize) -> bool {
addr < PHYSICAL_MEMORY_OFFSET && (addr + len) < PHYSICAL_MEMORY_OFFSET
}
#[naked]
pub unsafe extern "C" fn read_user_fixup() -> usize {
return 1;
}
pub fn copy_from_user<T>(addr: *const T) -> Option<T> {
#[naked]
#[inline(never)]
#[link_section = ".text.copy_user"]
unsafe extern "C" fn read_user<T>(dst: *mut T, src: *const T) -> usize {
dst.copy_from_nonoverlapping(src, 1);
0
}
if !access_ok(addr as usize, size_of::<T>()) {
return None;
}
let mut dst: T = unsafe { core::mem::uninitialized() };
match unsafe { read_user(&mut dst, addr) } {
0 => Some(dst),
_ => None,
}
}

@ -1,7 +1,6 @@
pub use self::structs::*;
use crate::arch::cpu;
use crate::consts::{MAX_CPU_NUM, MAX_PROCESS_NUM};
use crate::sync::{MutexGuard, SpinNoIrq};
use alloc::{boxed::Box, sync::Arc};
use log::*;
pub use rcore_thread::*;

@ -20,7 +20,8 @@ use crate::memory::{
use crate::sync::{Condvar, SpinNoIrqLock as Mutex};
use super::abi::{self, ProcInitInfo};
use core::mem::uninitialized;
use crate::processor;
use core::mem::MaybeUninit;
use rcore_fs::vfs::INode;
pub struct Thread {
@ -66,7 +67,7 @@ pub struct Process {
// relationship
pub pid: Pid, // i.e. tgid, usually the tid of first thread
pub parent: Option<Arc<Mutex<Process>>>,
pub parent: Weak<Mutex<Process>>,
pub children: Vec<Weak<Mutex<Process>>>,
pub threads: Vec<Tid>, // threads in the same process
@ -75,8 +76,8 @@ pub struct Process {
pub child_exit_code: BTreeMap<usize, usize>, // child process store its exit code here
}
/// Records the mapping between pid and Process struct.
lazy_static! {
/// Records the mapping between pid and Process struct.
pub static ref PROCESSES: RwLock<BTreeMap<usize, Weak<Mutex<Process>>>> =
RwLock::new(BTreeMap::new());
}
@ -102,7 +103,7 @@ impl Thread {
Box::new(Thread {
context: Context::null(),
// safety: other fields will never be used
..core::mem::uninitialized()
..core::mem::MaybeUninit::uninitialized().into_initialized()
})
}
@ -125,7 +126,7 @@ impl Thread {
exec_path: String::new(),
futexes: BTreeMap::default(),
pid: Pid(0),
parent: None,
parent: Weak::new(),
children: Vec::new(),
threads: Vec::new(),
child_exit: Arc::new(Condvar::new()),
@ -145,7 +146,7 @@ impl Thread {
) -> Result<(MemorySet, usize, usize), &'static str> {
// Read ELF header
// 0x3c0: magic number from ld-musl.so
let mut data: [u8; 0x3c0] = unsafe { uninitialized() };
let mut data: [u8; 0x3c0] = unsafe { MaybeUninit::uninitialized().into_initialized() };
inode
.read_at(0, &mut data)
.map_err(|_| "failed to read from INode")?;
@ -260,6 +261,7 @@ impl Thread {
read: true,
write: false,
append: false,
nonblock: false,
},
String::from("stdin"),
)),
@ -272,6 +274,7 @@ impl Thread {
read: false,
write: true,
append: false,
nonblock: false,
},
String::from("stdout"),
)),
@ -284,6 +287,7 @@ impl Thread {
read: false,
write: true,
append: false,
nonblock: false,
},
String::from("stderr"),
)),
@ -303,7 +307,7 @@ impl Thread {
exec_path: String::from(exec_path),
futexes: BTreeMap::default(),
pid: Pid(0),
parent: None,
parent: Weak::new(),
children: Vec::new(),
threads: Vec::new(),
child_exit: Arc::new(Condvar::new()),
@ -329,7 +333,7 @@ impl Thread {
exec_path: proc.exec_path.clone(),
futexes: BTreeMap::default(),
pid: Pid(0),
parent: Some(self.proc.clone()),
parent: Arc::downgrade(&self.proc),
children: Vec::new(),
threads: Vec::new(),
child_exit: Arc::new(Condvar::new()),
@ -403,6 +407,20 @@ impl Process {
}
self.futexes.get(&uaddr).unwrap().clone()
}
/// Exit the process.
/// Kill all threads and notify parent with the exit code.
pub fn exit(&mut self, exit_code: usize) {
// quit all threads
for tid in self.threads.iter() {
processor().manager().exit(*tid, 1);
}
// notify parent and fill exit code
if let Some(parent) = self.parent.upgrade() {
let mut parent = parent.lock();
parent.child_exit_code.insert(self.pid.get(), exit_code);
parent.child_exit.notify_one();
}
}
}
trait ToMemoryAttr {

@ -1,6 +1,5 @@
//! Kernel shell
use crate::arch::io;
use crate::fs::ROOT_INODE;
use crate::process::*;
use alloc::string::String;

@ -1,4 +1,5 @@
use super::*;
use crate::process::processor;
use crate::thread;
use alloc::collections::VecDeque;
use alloc::sync::Arc;
@ -26,26 +27,46 @@ impl Condvar {
});
}
#[deprecated(note = "this may leads to lost wakeup problem. please use `wait` instead.")]
pub fn wait_any(condvars: &[&Condvar]) {
let token = Arc::new(thread::current());
// Avoid racing in the same way as the function above
let mut locks = Vec::new();
locks.reserve(condvars.len());
fn add_to_wait_queue(&self) -> MutexGuard<VecDeque<Arc<thread::Thread>>, SpinNoIrq> {
let mut lock = self.wait_queue.lock();
lock.push_back(Arc::new(thread::current()));
return lock;
}
/// Wait for condvar until condition() returns Some
pub fn wait_event<T>(condvar: &Condvar, mut condition: impl FnMut() -> Option<T>) -> T {
Self::wait_events(&[condvar], condition)
}
/// Wait for condvars until condition() returns Some
pub fn wait_events<T>(condvars: &[&Condvar], mut condition: impl FnMut() -> Option<T>) -> T {
let thread = thread::current();
let tid = thread.id();
let token = Arc::new(thread);
for condvar in condvars {
let mut lock = condvar.wait_queue.lock();
lock.push_back(token.clone());
locks.push(lock);
}
thread::park_action(move || {
drop(locks);
});
let mut locks = Vec::with_capacity(condvars.len());
loop {
for condvar in condvars {
let mut lock = condvar.wait_queue.lock();
locks.push(lock);
}
processor().manager().sleep(tid, 0);
locks.clear();
fn add_to_wait_queue(&self) -> MutexGuard<VecDeque<Arc<thread::Thread>>, SpinNoIrq> {
let mut lock = self.wait_queue.lock();
lock.push_back(Arc::new(thread::current()));
return lock;
if let Some(res) = condition() {
let _ = FlagsGuard::no_irq_region();
processor().manager().cancel_sleeping(tid);
for condvar in condvars {
let mut lock = condvar.wait_queue.lock();
lock.retain(|t| !Arc::ptr_eq(t, &token));
}
return res;
}
processor().yield_now();
}
}
/// Park current thread and wait for this condvar to be notified.
@ -54,21 +75,28 @@ impl Condvar {
S: MutexSupport,
{
let mutex = guard.mutex;
let lock = self.add_to_wait_queue();
let token = Arc::new(thread::current());
let mut lock = self.wait_queue.lock();
lock.push_back(token.clone());
thread::park_action(move || {
drop(lock);
drop(guard);
});
mutex.lock()
let ret = mutex.lock();
let mut lock = self.wait_queue.lock();
lock.retain(|t| !Arc::ptr_eq(&t, &token));
ret
}
pub fn notify_one(&self) {
if let Some(t) = self.wait_queue.lock().pop_front() {
if let Some(t) = self.wait_queue.lock().front() {
t.unpark();
}
}
pub fn notify_all(&self) {
while let Some(t) = self.wait_queue.lock().pop_front() {
let queue = self.wait_queue.lock();
for t in queue.iter() {
t.unpark();
}
}
@ -76,14 +104,15 @@ impl Condvar {
/// Return the number of waiters that were woken up.
pub fn notify_n(&self, n: usize) -> usize {
let mut count = 0;
while count < n {
if let Some(t) = self.wait_queue.lock().pop_front() {
t.unpark();
count += 1;
} else {
let queue = self.wait_queue.lock();
for t in queue.iter() {
if count >= n {
break;
}
t.unpark();
count += 1;
}
count
}
}

@ -28,6 +28,7 @@
use super::Condvar;
use crate::arch::interrupt;
use crate::processor;
use core::cell::UnsafeCell;
use core::fmt;
use core::ops::{Deref, DerefMut};
@ -35,11 +36,12 @@ use core::sync::atomic::{AtomicBool, Ordering};
pub type SpinLock<T> = Mutex<T, Spin>;
pub type SpinNoIrqLock<T> = Mutex<T, SpinNoIrq>;
pub type ThreadLock<T> = Mutex<T, Condvar>;
pub type SleepLock<T> = Mutex<T, Condvar>;
pub struct Mutex<T: ?Sized, S: MutexSupport> {
lock: AtomicBool,
support: S,
user: UnsafeCell<(usize, usize)>, // (cid, tid)
data: UnsafeCell<T>,
}
@ -78,6 +80,7 @@ impl<T, S: MutexSupport> Mutex<T, S> {
lock: AtomicBool::new(false),
data: UnsafeCell::new(user_data),
support: S::new(),
user: UnsafeCell::new((0, 0)),
}
}
@ -93,12 +96,24 @@ impl<T, S: MutexSupport> Mutex<T, S> {
impl<T: ?Sized, S: MutexSupport> Mutex<T, S> {
fn obtain_lock(&self) {
while self.lock.compare_and_swap(false, true, Ordering::Acquire) != false {
let mut try_count = 0;
// Wait until the lock looks unlocked before retrying
while self.lock.load(Ordering::Relaxed) {
self.support.cpu_relax();
try_count += 1;
if try_count == 0x100000 {
let (cid, tid) = unsafe { *self.user.get() };
error!(
"Mutex: deadlock detected! locked by cpu {} thread {} @ {:?}",
cid, tid, self as *const Self
);
}
}
}
let cid = crate::arch::cpu::id();
let tid = processor().tid_option().unwrap_or(0);
unsafe { self.user.get().write((cid, tid)) };
}
/// Locks the spinlock and returns a guard.
///

@ -3,7 +3,7 @@
//! The code is borrowed from [RustDoc - Dining Philosophers](https://doc.rust-lang.org/1.6.0/book/dining-philosophers.html)
use crate::sync::Condvar;
use crate::sync::ThreadLock as Mutex;
use crate::sync::SleepLock as Mutex;
use crate::thread;
use alloc::vec;
use alloc::{sync::Arc, vec::Vec};

@ -105,14 +105,17 @@ impl Syscall<'_> {
drop(proc);
let begin_time_ms = crate::trap::uptime_msec();
loop {
Condvar::wait_events(&[&STDIN.pushed, &(*SOCKET_ACTIVITY)], move || {
use PollEvents as PE;
let proc = self.process();
let mut events = 0;
for poll in polls.iter_mut() {
poll.revents = PE::empty();
if let Some(file_like) = proc.files.get(&(poll.fd as usize)) {
let status = file_like.poll()?;
let status = match file_like.poll() {
Ok(ret) => ret,
Err(err) => return Some(Err(err)),
};
if status.error {
poll.revents |= PE::HUP;
events += 1;
@ -133,16 +136,15 @@ impl Syscall<'_> {
drop(proc);
if events > 0 {
return Ok(events);
return Some(Ok(events));
}
let current_time_ms = crate::trap::uptime_msec();
if timeout_msecs < (1 << 31) && current_time_ms - begin_time_ms > timeout_msecs {
return Ok(0);
}
Condvar::wait_any(&[&STDIN.pushed, &(*SOCKET_ACTIVITY)]);
return Some(Ok(0));
}
return None;
})
}
pub fn sys_select(
@ -177,7 +179,7 @@ impl Syscall<'_> {
drop(proc);
let begin_time_ms = crate::trap::uptime_msec();
loop {
Condvar::wait_events(&[&STDIN.pushed, &(*SOCKET_ACTIVITY)], move || {
let proc = self.process();
let mut events = 0;
for (&fd, file_like) in proc.files.iter() {
@ -187,7 +189,10 @@ impl Syscall<'_> {
if !err_fds.contains(fd) && !read_fds.contains(fd) && !write_fds.contains(fd) {
continue;
}
let status = file_like.poll()?;
let status = match file_like.poll() {
Ok(ret) => ret,
Err(err) => return Some(Err(err)),
};
if status.error && err_fds.contains(fd) {
err_fds.set(fd);
events += 1;
@ -204,23 +209,23 @@ impl Syscall<'_> {
drop(proc);
if events > 0 {
return Ok(events);
return Some(Ok(events));
}
if timeout_msecs == 0 {
// no timeout, return now;
return Ok(0);
return Some(Ok(0));
}
let current_time_ms = crate::trap::uptime_msec();
// infinity check
if timeout_msecs < (1 << 31) && current_time_ms - begin_time_ms > timeout_msecs as usize
{
return Ok(0);
return Some(Ok(0));
}
Condvar::wait_any(&[&STDIN.pushed, &(*SOCKET_ACTIVITY)]);
}
return None;
})
}
pub fn sys_readv(&mut self, fd: usize, iov_ptr: *const IoVec, iov_count: usize) -> SysResult {
@ -269,7 +274,7 @@ impl Syscall<'_> {
mode: usize,
) -> SysResult {
let mut proc = self.process();
let path = unsafe { self.vm().check_and_clone_cstr(path)? };
let path = unsafe { check_and_clone_cstr(path)? };
let flags = OpenFlags::from_bits_truncate(flags);
info!(
"openat: dir_fd: {}, path: {:?}, flags: {:?}, mode: {:#o}",
@ -333,7 +338,7 @@ impl Syscall<'_> {
) -> SysResult {
// TODO: check permissions based on uid/gid
let proc = self.process();
let path = unsafe { self.vm().check_and_clone_cstr(path)? };
let path = unsafe { check_and_clone_cstr(path)? };
let flags = AtFlags::from_bits_truncate(flags);
if !proc.pid.is_init() {
// we trust pid 0 process
@ -383,7 +388,7 @@ impl Syscall<'_> {
flags: usize,
) -> SysResult {
let proc = self.process();
let path = unsafe { self.vm().check_and_clone_cstr(path)? };
let path = check_and_clone_cstr(path)?;
let stat_ref = unsafe { self.vm().check_write_ptr(stat_ptr)? };
let flags = AtFlags::from_bits_truncate(flags);
info!(
@ -414,7 +419,7 @@ impl Syscall<'_> {
len: usize,
) -> SysResult {
let proc = self.process();
let path = unsafe { self.vm().check_and_clone_cstr(path)? };
let path = unsafe { check_and_clone_cstr(path)? };
let slice = unsafe { self.vm().check_write_array(base, len)? };
info!(
"readlinkat: dirfd: {}, path: {:?}, base: {:?}, len: {}",
@ -460,7 +465,7 @@ impl Syscall<'_> {
pub fn sys_truncate(&mut self, path: *const u8, len: usize) -> SysResult {
let proc = self.process();
let path = unsafe { self.vm().check_and_clone_cstr(path)? };
let path = unsafe { check_and_clone_cstr(path)? };
info!("truncate: path: {:?}, len: {}", path, len);
proc.lookup_inode(&path)?.resize(len)?;
Ok(0)
@ -524,7 +529,7 @@ impl Syscall<'_> {
arg3: usize,
) -> SysResult {
info!(
"ioctl: fd: {}, request: {:x}, args: {} {} {}",
"ioctl: fd: {}, request: {:#x}, args: {:#x} {:#x} {:#x}",
fd, request, arg1, arg2, arg3
);
let mut proc = self.process();
@ -534,7 +539,7 @@ impl Syscall<'_> {
pub fn sys_chdir(&mut self, path: *const u8) -> SysResult {
let mut proc = self.process();
let path = unsafe { self.vm().check_and_clone_cstr(path)? };
let path = check_and_clone_cstr(path)?;
if !proc.pid.is_init() {
// we trust pid 0 process
info!("chdir: path: {:?}", path);
@ -587,8 +592,8 @@ impl Syscall<'_> {
newpath: *const u8,
) -> SysResult {
let proc = self.process();
let oldpath = unsafe { self.vm().check_and_clone_cstr(oldpath)? };
let newpath = unsafe { self.vm().check_and_clone_cstr(newpath)? };
let oldpath = check_and_clone_cstr(oldpath)?;
let newpath = check_and_clone_cstr(newpath)?;
info!(
"renameat: olddirfd: {}, oldpath: {:?}, newdirfd: {}, newpath: {:?}",
olddirfd as isize, oldpath, newdirfd as isize, newpath
@ -608,7 +613,7 @@ impl Syscall<'_> {
pub fn sys_mkdirat(&mut self, dirfd: usize, path: *const u8, mode: usize) -> SysResult {
let proc = self.process();
let path = unsafe { self.vm().check_and_clone_cstr(path)? };
let path = check_and_clone_cstr(path)?;
// TODO: check pathname
info!(
"mkdirat: dirfd: {}, path: {:?}, mode: {:#o}",
@ -626,7 +631,7 @@ impl Syscall<'_> {
pub fn sys_rmdir(&mut self, path: *const u8) -> SysResult {
let proc = self.process();
let path = unsafe { self.vm().check_and_clone_cstr(path)? };
let path = check_and_clone_cstr(path)?;
info!("rmdir: path: {:?}", path);
let (dir_path, file_name) = split_path(&path);
@ -652,8 +657,8 @@ impl Syscall<'_> {
flags: usize,
) -> SysResult {
let proc = self.process();
let oldpath = unsafe { self.vm().check_and_clone_cstr(oldpath)? };
let newpath = unsafe { self.vm().check_and_clone_cstr(newpath)? };
let oldpath = check_and_clone_cstr(oldpath)?;
let newpath = check_and_clone_cstr(newpath)?;
let flags = AtFlags::from_bits_truncate(flags);
info!(
"linkat: olddirfd: {}, oldpath: {:?}, newdirfd: {}, newpath: {:?}, flags: {:?}",
@ -673,7 +678,7 @@ impl Syscall<'_> {
pub fn sys_unlinkat(&mut self, dirfd: usize, path: *const u8, flags: usize) -> SysResult {
let proc = self.process();
let path = unsafe { self.vm().check_and_clone_cstr(path)? };
let path = unsafe { check_and_clone_cstr(path)? };
let flags = AtFlags::from_bits_truncate(flags);
info!(
"unlinkat: dirfd: {}, path: {:?}, flags: {:?}",
@ -703,6 +708,7 @@ impl Syscall<'_> {
read: true,
write: false,
append: false,
nonblock: false,
},
String::from("pipe_r:[]"),
)));
@ -713,6 +719,7 @@ impl Syscall<'_> {
read: false,
write: true,
append: false,
nonblock: false,
},
String::from("pipe_w:[]"),
)));
@ -828,6 +835,13 @@ impl Syscall<'_> {
);
return Ok(total_written);
}
pub fn sys_fcntl(&mut self, fd: usize, cmd: usize, arg: usize) -> SysResult {
info!("fcntl: fd: {}, cmd: {:x}, arg: {}", fd, cmd, arg);
let mut proc = self.process();
let file_like = proc.get_file_like(fd)?;
file_like.fcntl(cmd, arg)
}
}
impl Process {
@ -872,6 +886,10 @@ impl Process {
"/proc/self/exe" => {
return Ok(Arc::new(Pseudo::new(&self.exec_path, FileType::SymLink)));
}
"/dev/fb0" => {
info!("/dev/fb0 will be opened");
return Ok(Arc::new(Vga::default()));
}
_ => {}
}
let (fd_dir_path, fd_name) = split_path(&path);
@ -930,6 +948,9 @@ impl From<FsError> for SysError {
FsError::DirNotEmpty => SysError::ENOTEMPTY,
FsError::WrongFs => SysError::EINVAL,
FsError::DeviceError => SysError::EIO,
FsError::IOCTLError => SysError::EINVAL,
FsError::NoDevice => SysError::EINVAL,
FsError::Again => SysError::EAGAIN,
}
}
}
@ -974,6 +995,7 @@ impl OpenFlags {
read: self.readable(),
write: self.writable(),
append: self.contains(OpenFlags::APPEND),
nonblock: false,
}
}
}
@ -1416,6 +1438,7 @@ impl IoVecs {
}
#[repr(C)]
#[derive(Debug)]
pub struct PollFd {
fd: u32,
events: PollEvents,

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save