Compare commits

...

14 Commits

Author SHA1 Message Date
刘丰源 6e3444acb9 try handle tlb miss, but fail 2020-08-02 00:42:35 +08:00
刘丰源 f902d6bfe7 impl timer 2020-07-31 12:28:07 +08:00
刘丰源 1c8d17fb1b fix mips commit page error 2020-07-30 22:47:08 +08:00
刘丰源 73f447077c init other 2020-07-30 15:20:43 +08:00
刘丰源 26704a253e fix merge error 2020-07-29 23:49:29 +08:00
刘丰源 fc034c534a merge master 2020-07-29 23:35:53 +08:00
刘丰源 8833f8c1ca reimpl RegExt to CtxExt, fix compile error 2020-07-29 23:19:54 +08:00
刘丰源 be7b2d5b28 fix mipsel, now can print... 2020-07-29 21:50:51 +08:00
刘丰源 b32e2527c7 impl mips putfmt(serial still can not work...) 2020-07-26 12:36:55 +08:00
刘丰源 690694a17e handle mips page fault 2020-07-25 17:58:33 +08:00
刘丰源 9e63d2810d mips mem init 2020-07-24 22:00:46 +08:00
刘丰源 e2926e144e try mipsel serial, but fail... qaq 2020-07-24 16:20:33 +08:00
刘丰源 9ae7dce43e init mipsel dtb 2020-07-24 11:15:29 +08:00
刘丰源 ea1aa37bc6 fix compile error 2020-07-22 21:45:53 +08:00
45 changed files with 1463 additions and 77 deletions

5
.gitignore vendored
View File

@ -5,3 +5,8 @@ Cargo.lock
/rootfs
/prebuilt/linux/alpine*
.idea
.DS_Store
/zCore/src/arch/mipsel/boot/linker.ld
*.gen.s
*.dtb

View File

@ -12,7 +12,9 @@ log = "0.4"
spin = "0.5"
git-version = "0.3"
executor = { git = "https://github.com/rcore-os/executor.git", rev = "a2d02ee9" }
trapframe = "0.4.1"
# trapframe = "0.4.1"
trapframe = { git = "https://github.com/rcore-os/trapframe-rs", rev = "fed9668" }
device_tree = { git = "https://github.com/rcore-os/device_tree-rs", rev = "eee2c23" }
kernel-hal = { path = "../kernel-hal" }
naive-timer = "0.1.0"
lazy_static = { version = "1.4", features = ["spin_no_std" ] }
@ -29,3 +31,6 @@ acpi = "1.0.0"
[target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies]
riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"], rev = "c62af46" }
[target.'cfg(target_arch = "mips")'.dependencies]
mips = { git = "https://github.com/Harry-Chen/rust-mips", rev = "3b828a2" }

View File

@ -0,0 +1,192 @@
use crate::drivers::IRQ_MANAGER;
use mips::addr::*;
use mips::paging::PageTable as MIPSPageTable;
use mips::registers::cp0;
use trapframe::TrapFrame;
/// Initialize interrupt
pub fn intr_init() {
unsafe {
trapframe::init();
}
let mut status = cp0::status::read();
// Enable IPI
// status.enable_soft_int0();
// status.enable_soft_int1();
// Enable serial interrupt
status.enable_hard_int2();
// Enable clock interrupt in timer::init
// status.enable_hard_int5();
cp0::status::write(status);
info!("interrupt: init end");
}
#[export_name = "hal_page_fault"]
pub fn is_page_fault(trap: usize) -> bool {
use cp0::cause::Exception as E;
let cause = cp0::cause::Cause { bits: trap as u32 };
match cause.cause() {
E::TLBModification | E::TLBLoadMiss | E::TLBStoreMiss => true,
_ => false,
}
}
#[export_name = "hal_is_syscall"]
pub fn is_syscall(trap: usize) -> bool {
use cp0::cause::Exception as E;
let cause = cp0::cause::Cause { bits: trap as u32 };
match cause.cause() {
E::Syscall => true,
_ => false,
}
}
#[export_name = "hal_is_intr"]
pub fn is_intr(trap: usize) -> bool {
use cp0::cause::Exception as E;
let cause = cp0::cause::Cause { bits: trap as u32 };
match cause.cause() {
E::Interrupt => true,
_ => false,
}
}
#[export_name = "hal_is_timer_intr"]
pub fn is_timer_intr(trap: usize) -> bool {
use cp0::cause::Exception as E;
let cause = cp0::cause::Cause { bits: trap as u32 };
match cause.cause() {
E::Interrupt => trap & (1 << 30) != 0,
_ => false,
}
}
#[export_name = "hal_is_reserved_inst"]
pub fn is_reserved_inst(trap: usize) -> bool {
use cp0::cause::Exception as E;
let cause = cp0::cause::Cause { bits: trap as u32 };
match cause.cause() {
E::ReservedInstruction => true,
_ => false,
}
}
#[export_name = "hal_wait_for_interrupt"]
pub fn wait_for_interrupt() {
cp0::status::enable_interrupt();
cp0::status::disable_interrupt();
}
#[export_name = "hal_irq_enable"]
pub fn irq_enable(_irq: u32) {
// unimplemented!()
warn!("unimplemented irq_enable");
}
#[no_mangle]
pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
use cp0::cause::Exception as E;
let cause = cp0::cause::Cause {
bits: tf.cause as u32,
};
info!("Exception @ CPU{}: {:?} ", 0, cause.cause());
match cause.cause() {
E::Interrupt => interrupt_dispatcher(tf),
// E::Syscall => syscall(tf),
E::TLBModification => page_fault(tf),
E::TLBLoadMiss => page_fault(tf),
E::TLBStoreMiss => page_fault(tf),
UNKNOWN => {
error!("Unhandled Exception @ CPU{}: {:?} ", 0, UNKNOWN);
}
}
trace!("Interrupt end");
}
fn interrupt_dispatcher(tf: &mut TrapFrame) {
let cause = cp0::cause::Cause {
bits: tf.cause as u32,
};
let pint = cause.pending_interrupt();
trace!(" Interrupt {:08b} ", pint);
if (pint & 0b100_000_00) != 0 {
timer();
} else if (pint & 0b011_111_00) != 0 {
for i in 0..6 {
if (pint & (1 << i)) != 0 {
IRQ_MANAGER.read().try_handle_interrupt(Some(i));
}
}
} else {
ipi();
}
}
fn ipi() {
debug!("IPI");
cp0::cause::reset_soft_int0();
cp0::cause::reset_soft_int1();
}
pub fn timer() {
super::timer::set_next();
crate::timer_tick();
}
fn page_fault(tf: &mut TrapFrame) {
// TODO: set access/dirty bit
let addr = tf.vaddr;
// info!("\nEXCEPTION: Page Fault @ {:#x}", addr);
let virt_addr = VirtAddr::new(addr);
error!("{:x}", super::memory::get_page_table());
let root_table = unsafe { &mut *(super::memory::get_page_table() as *mut MIPSPageTable) };
let tlb_result = root_table.lookup(addr);
match tlb_result {
Ok(tlb_entry) => {
trace!(
"PhysAddr = {:x}/{:x}",
tlb_entry.entry_lo0.get_pfn() << 12,
tlb_entry.entry_lo1.get_pfn() << 12
);
let tlb_valid = if virt_addr.page_number() & 1 == 0 {
tlb_entry.entry_lo0.valid()
} else {
tlb_entry.entry_lo1.valid()
};
if !tlb_valid {
panic!("hhh");
// 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::read_user_fixup as usize;
// return;
// }
// }
}
tlb_entry.write_random()
}
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::read_user_fixup as usize;
// return;
// }
// }
panic!("...");
}
}
}

View File

@ -0,0 +1,10 @@
//! Input/output for mipsel.
use crate::drivers::SERIAL_DRIVERS;
use core::fmt::Arguments;
pub fn putfmt(fmt: Arguments) {
let mut drivers = SERIAL_DRIVERS.write();
if let Some(serial) = drivers.first_mut() {
serial.write(format!("{}", fmt).as_bytes());
}
}

View File

@ -0,0 +1,15 @@
#[allow(dead_code)]
extern "C" {
fn _root_page_table_buffer();
fn _root_page_table_ptr();
}
pub unsafe fn set_page_table(vmtoken: usize) {
use mips::tlb::TLBEntry;
TLBEntry::clear_all();
*(_root_page_table_ptr as *mut usize) = vmtoken;
}
pub fn get_page_table() -> usize {
unsafe { *(_root_page_table_ptr as *mut usize) }
}

View File

@ -0,0 +1,65 @@
pub mod interrupt;
mod io;
mod memory;
mod timer;
pub use interrupt::*;
pub use io::*;
pub use memory::*;
pub use timer::*;
use super::super::{Frame, PhysAddr};
use mips::paging::PageTable as MIPSPageTable;
pub struct Config {}
pub fn init(_config: Config) {
intr_init();
unsafe {
set_page_table(0xFFFF_FFFF);
}
timer_init();
}
#[export_name = "hal_apic_local_id"]
pub fn apic_local_id() -> u8 {
// unimplemented!()
0
}
/// Page Table
#[repr(C)]
pub struct PageTableImpl {
root_paddr: PhysAddr,
}
impl PageTableImpl {
#[export_name = "hal_pt_current"]
pub fn current() -> Self {
PageTableImpl {
root_paddr: get_page_table() & 0x7fffffff,
}
}
/// Create a new `PageTable`.
#[allow(clippy::new_without_default)]
#[export_name = "hal_pt_new"]
pub fn new() -> Self {
let root_frame = Frame::alloc().expect("failed to alloc frame");
let table = unsafe { &mut *(root_frame.paddr as *mut MIPSPageTable) };
table.zero();
trace!("create page table @ {:#x}", root_frame.paddr);
PageTableImpl {
root_paddr: root_frame.paddr,
}
}
// fn get(&mut self) -> OffsetPageTable<'_> {
// // let root_vaddr = phys_to_virt(self.root_paddr);
// // let root = unsafe { &mut *(root_vaddr as *mut PageTable) };
// // let offset = x86_64::VirtAddr::new(phys_to_virt(0) as u64);
// // unsafe { OffsetPageTable::new(root, offset) }
// unimplemented!()
// }
}

View File

@ -0,0 +1,32 @@
use core::time::Duration;
use log::*;
use mips::registers::cp0;
static mut TICK: u64 = 0;
const TIMEBASE: u32 = 250000;
/// Enable timer interrupt
pub fn timer_init() {
// Enable supervisor timer interrupt
cp0::status::enable_hard_int5(); // IP(7), timer interrupt
cp0::count::write_u32(0);
set_next();
info!("timer: init end");
}
/// Set the next timer interrupt
pub fn set_next() {
// 100Hz @ QEMU
cp0::count::write_u32(0);
cp0::compare::write_u32(TIMEBASE);
unsafe {
TICK += 1;
}
}
#[export_name = "hal_timer_now"]
pub fn timer_now() -> Duration {
let mut curr_time = unsafe { TICK * TIMEBASE as u64 };
curr_time += cp0::count::read_u32() as u64;
Duration::from_nanos(curr_time * 10)
}

View File

@ -1,8 +1,12 @@
#[cfg(target_arch = "mips")]
mod mipsel;
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
mod riscv;
#[cfg(target_arch = "x86_64")]
mod x86_64;
#[cfg(target_arch = "mips")]
pub use self::mipsel::*;
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
pub use self::riscv::*;
#[cfg(target_arch = "x86_64")]

View File

@ -299,6 +299,12 @@ pub fn irq_is_valid(irq: u32) -> bool {
get_ioapic(irq).is_some()
}
#[export_name = "hal_wait_for_interrupt"]
pub fn wait_for_interrupt() {
x86_64::instructions::interrupts::enable_interrupts_and_hlt();
x86_64::instructions::interrupts::disable();
}
fn breakpoint() {
panic!("\nEXCEPTION: Breakpoint");
}

View File

@ -20,10 +20,14 @@ use {
},
};
use kernel_hal::vdso::{Features, VdsoConstants};
mod acpi_table;
mod interrupt;
pub mod interrupt;
mod keyboard;
pub use super::super::phys_to_virt;
/// Page Table
#[repr(C)]
pub struct PageTableImpl {

View File

@ -0,0 +1,55 @@
use super::irq::IntcDriver;
use alloc::{collections::BTreeMap, sync::Arc};
use core::slice;
use device_tree::{DeviceTree, Node};
use spin::RwLock;
const DEVICE_TREE_MAGIC: u32 = 0xd00dfeed;
lazy_static! {
/// Compatible lookup
pub static ref DEVICE_TREE_REGISTRY: RwLock<BTreeMap<&'static str, fn(&Node)>> =
RwLock::new(BTreeMap::new());
/// Interrupt controller lookup
pub static ref DEVICE_TREE_INTC: RwLock<BTreeMap<u32, Arc<dyn IntcDriver>>> =
RwLock::new(BTreeMap::new());
}
fn walk_dt_node(dt: &Node, intc_only: bool) {
if let Ok(compatible) = dt.prop_str("compatible") {
if dt.has_prop("interrupt-controller") == intc_only {
let registry = DEVICE_TREE_REGISTRY.read();
if let Some(f) = registry.get(compatible) {
f(dt);
}
}
}
if let Ok(bootargs) = dt.prop_str("bootargs") {
if bootargs.len() > 0 {
info!("Kernel cmdline: {}", bootargs);
// *CMDLINE.write() = String::from(bootargs);
}
}
for child in dt.children.iter() {
walk_dt_node(child, intc_only);
}
}
struct DtbHeader {
magic: u32,
size: u32,
}
pub fn init(dtb: usize) {
let header = unsafe { &*(dtb as *const DtbHeader) };
let magic = u32::from_be(header.magic);
if magic == DEVICE_TREE_MAGIC {
let size = u32::from_be(header.size);
let dtb_data = unsafe { slice::from_raw_parts(dtb as *const u8, size as usize) };
if let Ok(dt) = DeviceTree::load(dtb_data) {
// find interrupt controller first
walk_dt_node(&dt.root, true);
walk_dt_node(&dt.root, false);
}
}
}

View File

@ -0,0 +1,91 @@
use super::Driver;
use crate::arch::interrupt::irq_enable;
use alloc::collections::btree_map::Entry;
use alloc::collections::BTreeMap;
use alloc::sync::Arc;
use alloc::vec::Vec;
// Irq manager
pub struct IrqManager {
// is root manager?
root: bool,
// drivers that only respond to specific irq
mapping: BTreeMap<usize, Vec<Arc<dyn Driver>>>,
// drivers that respond to all irqs
all: Vec<Arc<dyn Driver>>,
}
impl IrqManager {
pub fn new(root: bool) -> IrqManager {
IrqManager {
root,
mapping: BTreeMap::new(),
all: Vec::new(),
}
}
pub fn register_irq(&mut self, irq: usize, driver: Arc<dyn Driver>) {
// for root manager, enable irq in arch
// for other interrupt controllers, enable irq before calling this function
if self.root {
irq_enable(irq as u32);
}
match self.mapping.entry(irq) {
Entry::Occupied(mut e) => {
e.get_mut().push(driver);
}
Entry::Vacant(e) => {
let mut v = Vec::new();
v.push(driver);
e.insert(v);
}
}
}
pub fn register_all(&mut self, driver: Arc<dyn Driver>) {
self.all.push(driver);
}
pub fn register_opt(&mut self, irq_opt: Option<usize>, driver: Arc<dyn Driver>) {
if let Some(irq) = irq_opt {
self.register_irq(irq, driver);
} else {
self.register_all(driver);
}
}
pub fn deregister_irq(&mut self, irq: usize, driver: Arc<dyn Driver>) {
if let Some(e) = self.mapping.get_mut(&irq) {
e.retain(|d| !Arc::ptr_eq(&d, &driver));
}
}
pub fn deregister_all(&mut self, driver: Arc<dyn Driver>) {
self.all.retain(|d| !Arc::ptr_eq(&d, &driver));
}
pub fn try_handle_interrupt(&self, irq_opt: Option<usize>) -> bool {
if let Some(irq) = irq_opt {
if let Some(e) = self.mapping.get(&irq) {
for dri in e.iter() {
if dri.try_handle_interrupt(Some(irq)) {
return true;
}
}
}
}
for dri in self.all.iter() {
if dri.try_handle_interrupt(irq_opt) {
return true;
}
}
false
}
}
// interrupt controller
pub trait IntcDriver: Driver {
/// Register interrupt controller local irq
fn register_local_irq(&self, irq: usize, driver: Arc<dyn Driver>);
}

View File

@ -0,0 +1,59 @@
pub mod device_tree;
pub mod irq;
pub mod serial;
use alloc::string::String;
use alloc::sync::Arc;
use alloc::vec::Vec;
use spin::RwLock;
pub use serial::SerialDriver;
#[derive(Debug, Eq, PartialEq)]
pub enum DeviceType {
Net,
Gpu,
Input,
Block,
Rtc,
Serial,
Intc,
}
pub trait Driver: Send + Sync {
// if interrupt belongs to this driver, handle it and return true
// return false otherwise
// irq number is provided when available
// driver should skip handling when irq number is mismatched
fn try_handle_interrupt(&self, irq: Option<usize>) -> bool;
// return the correspondent device type, see DeviceType
fn device_type(&self) -> DeviceType;
// get unique identifier for this device
// should be different for each instance
fn get_id(&self) -> String;
// trait casting
// fn as_net(&self) -> Option<&dyn NetDriver> {
// None
// }
// fn as_block(&self) -> Option<&dyn BlockDriver> {
// None
// }
// fn as_rtc(&self) -> Option<&dyn RtcDriver> {
// None
// }
}
lazy_static! {
// NOTE: RwLock only write when initializing drivers
pub static ref DRIVERS: RwLock<Vec<Arc<dyn Driver>>> = RwLock::new(Vec::new());
// pub static ref NET_DRIVERS: RwLock<Vec<Arc<dyn NetDriver>>> = RwLock::new(Vec::new());
// pub static ref BLK_DRIVERS: RwLock<Vec<Arc<dyn BlockDriver>>> = RwLock::new(Vec::new());
// pub static ref RTC_DRIVERS: RwLock<Vec<Arc<dyn RtcDriver>>> = RwLock::new(Vec::new());
pub static ref SERIAL_DRIVERS: RwLock<Vec<Arc<dyn SerialDriver>>> = RwLock::new(Vec::new());
pub static ref IRQ_MANAGER: RwLock<irq::IrqManager> = RwLock::new(irq::IrqManager::new(true));
}

View File

@ -0,0 +1,11 @@
use super::Driver;
pub mod uart16550;
pub trait SerialDriver: Driver {
// read one byte from tty
fn read(&self) -> u8;
// write bytes to tty
fn write(&self, data: &[u8]);
}

View File

@ -0,0 +1,166 @@
//! 16550 serial adapter driver for malta board
#![allow(dead_code)]
use super::SerialDriver;
use crate::drivers::device_tree::{DEVICE_TREE_INTC, DEVICE_TREE_REGISTRY};
use crate::drivers::IRQ_MANAGER;
use crate::drivers::SERIAL_DRIVERS;
use crate::drivers::{DeviceType, Driver, DRIVERS};
use crate::{
phys_to_virt,
util::{read, write},
};
use alloc::{string::String, sync::Arc};
// use core::fmt::{Arguments, Result, Write};
use device_tree::Node;
// use spin::Mutex;
pub struct SerialPort {
base: usize,
multiplier: usize,
}
impl Driver for SerialPort {
fn try_handle_interrupt(&self, _irq: Option<usize>) -> bool {
unimplemented!()
// if let Some(c) = self.getchar_option() {
// crate::trap::serial(c);
// true
// } else {
// false
// }
}
fn device_type(&self) -> DeviceType {
DeviceType::Serial
}
fn get_id(&self) -> String {
format!("com_{}", self.base)
}
}
impl SerialPort {
fn new(base: usize, shift: usize) -> SerialPort {
let mut res = SerialPort {
base: 0,
multiplier: 1 << shift,
};
res.init(base);
res
}
pub fn init(&mut self, base: usize) {
self.base = base;
// Turn off the FIFO
write(self.base + COM_FCR * self.multiplier, 0 as u8);
// Set speed; requires DLAB latch
write(self.base + COM_LCR * self.multiplier, COM_LCR_DLAB);
// write(self.base + COM_DLL * self.multiplier, (115200 / 9600) as u8);
// write(self.base + COM_DLM * self.multiplier, 0 as u8);
// 8 data bits, 1 stop bit, parity off; turn off DLAB latch
write(
self.base + COM_LCR * self.multiplier,
COM_LCR_WLEN8 & !COM_LCR_DLAB,
);
// No modem controls
write(self.base + COM_MCR * self.multiplier, 0 as u8);
// Enable rcv interrupts
write(self.base + COM_IER * self.multiplier, COM_IER_RDI);
}
/// non-blocking version of putchar()
pub fn putchar(&self, c: u8) {
for _ in 0..100 {
if (read::<u8>(self.base + COM_LSR * self.multiplier) & COM_LSR_TXRDY) == 0 {
break;
}
}
write(self.base + COM_TX * self.multiplier, c);
}
/// blocking version of getchar()
pub fn getchar(&mut self) -> u8 {
loop {
if (read::<u8>(self.base + COM_LSR * self.multiplier) & COM_LSR_DATA) == 0 {
break;
}
}
let c = read::<u8>(self.base + COM_RX * self.multiplier);
match c {
255 => b'\0', // null
c => c,
}
}
/// non-blocking version of getchar()
pub fn getchar_option(&self) -> Option<u8> {
match read::<u8>(self.base + COM_LSR * self.multiplier) & COM_LSR_DATA {
0 => None,
_ => Some(read::<u8>(self.base + COM_RX * self.multiplier) as u8),
}
}
}
impl SerialDriver for SerialPort {
fn read(&self) -> u8 {
self.getchar_option().unwrap_or(0)
}
fn write(&self, data: &[u8]) {
for byte in data {
self.putchar(*byte);
}
}
}
const COM_RX: usize = 0; // In: Receive buffer (DLAB=0)
const COM_TX: usize = 0; // Out: Transmit buffer (DLAB=0)
const COM_DLL: usize = 0; // Out: Divisor Latch Low (DLAB=1)
const COM_DLM: usize = 1; // Out: Divisor Latch High (DLAB=1)
const COM_IER: usize = 1; // Out: Interrupt Enable Register
const COM_IER_RDI: u8 = 0x01; // Enable receiver data interrupt
const COM_IIR: usize = 2; // In: Interrupt ID Register
const COM_FCR: usize = 2; // Out: FIFO Control Register
const COM_LCR: usize = 3; // Out: Line Control Register
const COM_LCR_DLAB: u8 = 0x80; // Divisor latch access bit
const COM_LCR_WLEN8: u8 = 0x03; // Wordlength: 8 bits
const COM_MCR: usize = 4; // Out: Modem Control Register
const COM_MCR_RTS: u8 = 0x02; // RTS complement
const COM_MCR_DTR: u8 = 0x01; // DTR complement
const COM_MCR_OUT2: u8 = 0x08; // Out2 complement
const COM_LSR: usize = 5; // In: Line Status Register
const COM_LSR_DATA: u8 = 0x01; // Data available
const COM_LSR_TXRDY: u8 = 0x20; // Transmit buffer avail
const COM_LSR_TSRE: u8 = 0x40; // Transmitter off
pub fn init_dt(dt: &Node) {
let addr = dt.prop_usize("reg").unwrap();
let shift = dt.prop_u32("reg-shift").unwrap_or(0) as usize;
let base = phys_to_virt(addr);
info!("Init uart16550 at {:#x}", base);
let com = Arc::new(SerialPort::new(base, shift));
let mut found = false;
let irq_opt = dt.prop_u32("interrupts").ok().map(|irq| irq as usize);
DRIVERS.write().push(com.clone());
SERIAL_DRIVERS.write().push(com.clone());
if let Ok(intc) = dt.prop_u32("interrupt-parent") {
if let Some(irq) = irq_opt {
if let Some(manager) = DEVICE_TREE_INTC.write().get_mut(&intc) {
manager.register_local_irq(irq, com.clone());
info!("registered uart16550 to intc");
found = true;
}
}
}
if !found {
info!("registered uart16550 to root");
IRQ_MANAGER.write().register_opt(irq_opt, com);
}
}
pub fn driver_init() {
DEVICE_TREE_REGISTRY.write().insert("ns16550a", init_dt);
}

View File

@ -16,11 +16,13 @@
#![no_std]
#![feature(asm)]
#![feature(linkage)]
#![feature(naked_functions)]
#![deny(warnings)]
#[macro_use]
extern crate log;
#[macro_use]
extern crate alloc;
#[macro_use]
@ -34,12 +36,14 @@ use core::{
task::{Context, Poll},
};
use kernel_hal::defs::*;
use kernel_hal::vdso::*;
// use kernel_hal::vdso::*;
use kernel_hal::UserContext;
use naive_timer::Timer;
use spin::Mutex;
pub mod arch;
pub mod drivers;
pub mod util;
pub use self::arch::*;
@ -133,10 +137,22 @@ impl Frame {
}
}
fn phys_to_virt(paddr: PhysAddr) -> VirtAddr {
#[cfg(not(target_arch = "mips"))]
pub fn phys_to_virt(paddr: PhysAddr) -> VirtAddr {
unsafe { PMEM_BASE + paddr }
}
/// MIPS is special
#[cfg(target_arch = "mips")]
pub fn phys_to_virt(paddr: usize) -> usize {
const PHYSICAL_MEMORY_OFFSET: usize = 0x8000_0000;
if paddr <= PHYSICAL_MEMORY_OFFSET {
PHYSICAL_MEMORY_OFFSET + paddr
} else {
paddr
}
}
/// Read physical memory from `paddr` to `buf`.
#[export_name = "hal_pmem_read"]
pub fn pmem_read(paddr: PhysAddr, buf: &mut [u8]) {
@ -191,6 +207,11 @@ pub fn timer_tick() {
NAIVE_TIMER.lock().expire(now);
}
#[naked]
pub unsafe extern "C" fn read_user_fixup() -> usize {
return 1;
}
/// Initialize the HAL.
pub fn init(config: Config) {
unsafe {

View File

@ -0,0 +1,15 @@
use core::ptr::{read_volatile, write_volatile};
#[inline(always)]
pub fn write<T>(addr: usize, content: T) {
let cell = (addr) as *mut T;
unsafe {
write_volatile(cell, content);
}
}
#[inline(always)]
pub fn read<T>(addr: usize) -> T {
let cell = (addr) as *const T;
unsafe { read_volatile(cell) }
}

View File

@ -16,4 +16,4 @@ lazy_static = "1.4"
kernel-hal = { path = "../kernel-hal" }
async-std = "1.5"
git-version = "0.3"
trapframe = "0.4.1"
trapframe = { git = "https://github.com/rcore-os/trapframe-rs", rev = "fed9668" }

View File

@ -9,6 +9,6 @@ description = "Kernel HAL interface definations."
[dependencies]
bitflags = "1.2"
trapframe = "0.4.1"
trapframe = { git = "https://github.com/rcore-os/trapframe-rs", rev = "fed9668" }
numeric-enum-macro = "0.2"
acpi = "1.0.0"

View File

@ -371,6 +371,36 @@ impl InterruptManager {
pub fn is_valid(_irq: u32) -> bool {
unimplemented!()
}
#[linkage = "weak"]
#[export_name = "hal_wait_for_interrupt"]
pub fn wait_for_interrupt() {
unimplemented!()
}
#[linkage = "weak"]
#[export_name = "hal_page_fault"]
pub fn is_page_fault(_trap: usize) -> bool {
unimplemented!()
}
#[linkage = "weak"]
#[export_name = "hal_is_syscall"]
pub fn is_syscall(_trap: usize) -> bool {
unimplemented!()
}
#[linkage = "weak"]
#[export_name = "hal_is_intr"]
pub fn is_intr(_trap: usize) -> bool {
unimplemented!()
}
#[linkage = "weak"]
#[export_name = "hal_is_timer_intr"]
pub fn is_timer_intr(_trap: usize) -> bool {
unimplemented!()
}
#[linkage = "weak"]
#[export_name = "hal_is_reserved_inst"]
pub fn is_reserved_inst(_trap: usize) -> bool {
unimplemented!()
}
}
/// Get platform specific information.

View File

@ -19,6 +19,9 @@ env_logger = { version = "0.7", optional = true }
kernel-hal-unix = { path = "../kernel-hal-unix", optional = true }
async-std = { version = "1.5", features = ["attributes"], optional = true }
[target.'cfg(target_arch = "mips")'.dependencies]
mips = { git = "https://github.com/Harry-Chen/rust-mips", rev = "3b828a2" }
[features]
default = ["std"]
std = ["env_logger", "async-std", "kernel-hal-unix", "rcore-fs-hostfs"]

View File

@ -2,6 +2,7 @@
#![feature(asm)]
#![feature(global_asm)]
#![deny(warnings, unused_must_use)]
#![allow(unused_assignments)]
extern crate alloc;
#[macro_use]
@ -9,7 +10,7 @@ extern crate log;
use {
alloc::{boxed::Box, string::String, sync::Arc, vec::Vec},
kernel_hal::{GeneralRegs, MMUFlags},
kernel_hal::{InterruptManager, MMUFlags, UserContext},
linux_object::{
fs::{vfs::FileSystem, INodeExt},
loader::LinuxElfLoader,
@ -35,13 +36,13 @@ pub fn run(args: Vec<String>, envs: Vec<String>, rootfs: Arc<dyn FileSystem>) ->
let inode = rootfs.root_inode().lookup(&args[0]).unwrap();
let data = inode.read_as_vec().unwrap();
let (entry, sp) = loader.load(&proc.vmar(), &data, args, envs).unwrap();
thread
.start(entry, sp, 0, 0, spawn)
.expect("failed to start main thread");
proc
}
#[cfg(target_arch = "x86_64")]
fn spawn(thread: Arc<Thread>) {
let vmtoken = thread.proc().vmar().table_phys();
let future = async move {
@ -52,9 +53,9 @@ fn spawn(thread: Arc<Thread>) {
trace!("back from user: {:#x?}", cx);
let mut exit = false;
match cx.trap_num {
0x100 => exit = handle_syscall(&thread, &mut cx.general).await,
0x100 => exit = handle_syscall(&thread, &mut cx).await,
0x20..=0x3f => {
kernel_hal::InterruptManager::handle(cx.trap_num as u8);
InterruptManager::handle(cx.trap_num as u8);
if cx.trap_num == 0x20 {
kernel_hal::yield_now().await;
}
@ -86,10 +87,51 @@ fn spawn(thread: Arc<Thread>) {
kernel_hal::Thread::spawn(Box::pin(future), vmtoken);
}
async fn handle_syscall(thread: &Arc<Thread>, regs: &mut GeneralRegs) -> bool {
#[cfg(target_arch = "mips")]
fn spawn(thread: Arc<Thread>) {
let vmtoken = thread.proc().vmar().table_phys();
let future = async move {
loop {
let mut cx = thread.wait_for_run().await;
trace!("go to user: {:#x?}", cx);
kernel_hal::context_run(&mut cx);
trace!("back from user: {:#x?}", cx);
let mut exit = false;
let trap_num = cx.cause;
match trap_num {
// _ if InterruptManager::is_page_fault(trap_num) => {
// let addr = cp0::bad_vaddr::read_u32() as usize;
// if !handle_user_page_fault(&thread, addr) {
// // TODO: SIGSEGV
// panic!("page fault handle failed");
// }
// }
// _ if InterruptManager::is_syscall(trap_num) => {
// exit = handle_syscall(&thread, &mut cx).await
// }
_ => panic!("not supported interrupt from user mode. {:#x?}", cx),
}
thread.end_running(cx);
if exit {
break;
}
}
};
kernel_hal::Thread::spawn(Box::pin(future), vmtoken);
}
async fn handle_syscall(thread: &Arc<Thread>, context: &mut UserContext) -> bool {
let regs = &context.general;
trace!("syscall: {:#x?}", regs);
let num = regs.rax as u32;
let args = [regs.rdi, regs.rsi, regs.rdx, regs.r10, regs.r8, regs.r9];
let num = context.get_syscall_num();
let args = context.get_syscall_args();
// add before fork
#[cfg(target_arch = "mips")]
{
context.epc = context.epc + 4;
}
let mut syscall = Syscall {
thread,
#[cfg(feature = "std")]
@ -97,11 +139,12 @@ async fn handle_syscall(thread: &Arc<Thread>, regs: &mut GeneralRegs) -> bool {
#[cfg(not(feature = "std"))]
syscall_entry: 0,
spawn_fn: spawn,
regs,
context,
exit: false,
};
let ret = syscall.syscall(num, args).await;
let ret = syscall.syscall(num as u32, args).await;
let exit = syscall.exit;
regs.rax = ret as usize;
context.set_syscall_ret(ret as usize);
exit
}

View File

@ -65,7 +65,7 @@ pub struct Timespec {
#[cfg(target_arch = "mips")]
impl From<linux_object::fs::vfs::Timespec> for Timespec {
fn from(t: Timespec) -> Self {
fn from(t: linux_object::fs::vfs::Timespec) -> Self {
Timespec {
sec: t.sec as _,
nsec: t.nsec,

View File

@ -14,7 +14,7 @@ use {
self::consts::SyscallType as Sys,
alloc::sync::Arc,
core::convert::TryFrom,
kernel_hal::{user::*, GeneralRegs},
kernel_hal::{user::*, UserContext},
linux_object::{error::*, fs::FileDesc, process::*},
zircon_object::{object::*, task::*, vm::VirtAddr},
};
@ -29,7 +29,7 @@ mod vm;
pub struct Syscall<'a> {
pub thread: &'a Arc<Thread>,
pub syscall_entry: VirtAddr,
pub regs: &'a mut GeneralRegs,
pub context: &'a mut UserContext,
pub spawn_fn: fn(thread: Arc<Thread>),
/// Set `true` to exit current task.
pub exit: bool,
@ -196,6 +196,8 @@ impl Syscall<'_> {
// Sys::DELETE_MODULE => self.sys_delete_module(a0.into(), a1 as u32),
#[cfg(target_arch = "x86_64")]
_ => self.x86_64_syscall(sys_type, args).await,
#[cfg(target_arch = "mips")]
_ => self.mips_syscall(sys_type, args).await,
};
info!("<= {:x?}", ret);
match ret {
@ -204,6 +206,12 @@ impl Syscall<'_> {
}
}
#[cfg(target_arch = "mips")]
async fn mips_syscall(&mut self, _sys_type: Sys, _args: [usize; 6]) -> SysResult {
// self.unknown_syscall(sys_type);
unimplemented!();
}
#[cfg(target_arch = "x86_64")]
async fn x86_64_syscall(&mut self, sys_type: Sys, args: [usize; 6]) -> SysResult {
let [a0, a1, a2, _a3, _a4, _a5] = args;
@ -235,6 +243,7 @@ impl Syscall<'_> {
}
}
#[allow(dead_code)]
fn unknown_syscall(&mut self, sys_type: Sys) -> SysResult {
error!("unknown syscall: {:?}. exit...", sys_type);
let proc = self.zircon_process();

View File

@ -9,7 +9,7 @@ impl Syscall<'_> {
match code {
ARCH_SET_FS => {
info!("sys_arch_prctl: set FSBASE to {:#x}", addr);
self.regs.fsbase = addr;
self.context.general.fsbase = addr;
Ok(0)
}
_ => Err(LxError::EINVAL),

View File

@ -12,7 +12,7 @@ impl Syscall<'_> {
info!("fork:");
let new_proc = Process::fork_from(self.zircon_process(), false)?;
let new_thread = Thread::create_linux(&new_proc)?;
new_thread.start_with_regs(GeneralRegs::new_fork(self.regs), self.spawn_fn)?;
new_thread.start_with_context(UserContext::new_fork(self.context), self.spawn_fn)?;
info!("fork: {} -> {}", self.zircon_process().id(), new_proc.id());
Ok(new_proc.id() as usize)
@ -22,7 +22,7 @@ impl Syscall<'_> {
info!("vfork:");
let new_proc = Process::fork_from(self.zircon_process(), true)?;
let new_thread = Thread::create_linux(&new_proc)?;
new_thread.start_with_regs(GeneralRegs::new_fork(self.regs), self.spawn_fn)?;
new_thread.start_with_context(UserContext::new_fork(self.context), self.spawn_fn)?;
let new_proc: Arc<dyn KernelObject> = new_proc;
info!("vfork: {} -> {}", self.zircon_process().id(), new_proc.id());
@ -60,8 +60,8 @@ impl Syscall<'_> {
panic!("unsupported sys_clone flags: {:#x}", flags);
}
let new_thread = Thread::create_linux(self.zircon_process())?;
let regs = GeneralRegs::new_clone(self.regs, newsp, newtls);
new_thread.start_with_regs(regs, self.spawn_fn)?;
let context = UserContext::new_clone(self.context, newsp, newtls);
new_thread.start_with_context(context, self.spawn_fn)?;
let tid = new_thread.id();
info!("clone: {} -> {}", self.thread.id(), tid);
@ -169,7 +169,7 @@ impl Syscall<'_> {
// TODO: use right signal
self.zircon_process().signal_set(Signal::SIGNALED);
*self.regs = GeneralRegs::new_fn(entry, sp, 0, 0);
*self.context = UserContext::new_fn(entry, sp, 0, 0);
Ok(0)
}
//
@ -292,34 +292,34 @@ bitflags! {
}
}
trait RegExt {
trait CtxExt {
fn new_fn(entry: usize, sp: usize, arg1: usize, arg2: usize) -> Self;
fn new_clone(regs: &Self, newsp: usize, newtls: usize) -> Self;
fn new_fork(regs: &Self) -> Self;
}
#[cfg(target_arch = "x86_64")]
impl RegExt for GeneralRegs {
impl CtxExt for UserContext {
fn new_fn(entry: usize, sp: usize, arg1: usize, arg2: usize) -> Self {
GeneralRegs {
rip: entry,
rsp: sp,
rdi: arg1,
rsi: arg2,
..Default::default()
}
let mut ctx = UserContext::default();
ctx.set_ip(entry);
ctx.set_sp(sp);
ctx.set_syscall_args([arg1, arg2, 0, 0, 0, 0]);
ctx
}
fn new_clone(regs: &Self, newsp: usize, newtls: usize) -> Self {
GeneralRegs {
rax: 0,
rsp: newsp,
fsbase: newtls,
..*regs
}
fn new_clone(origin_ctx: &Self, newsp: usize, newtls: usize) -> Self {
let mut ctx = UserContext::default();
ctx.general = origin_ctx.general;
ctx.set_syscall_ret(0);
ctx.set_sp(newsp);
ctx.set_tls(newtls);
ctx
}
fn new_fork(regs: &Self) -> Self {
GeneralRegs { rax: 0, ..*regs }
fn new_fork(origin_ctx: &Self) -> Self {
let mut ctx = UserContext::default();
ctx.general = origin_ctx.general;
ctx.set_syscall_ret(0);
ctx
}
}

View File

@ -10,6 +10,9 @@ edition = "2018"
graphic = []
zircon = ["zircon-loader"]
linux = ["linux-loader", "linux-object", "rcore-fs-sfs"]
# for qemu machine
board_malta = []
link_user = []
hypervisor = ["rvm", "zircon", "zircon-object/hypervisor", "zircon-syscall/hypervisor"]
[profile.release]
@ -19,20 +22,27 @@ lto = true
log = "0.4"
spin = "0.5"
buddy_system_allocator = "0.4.0"
rlibc-opt = { git = "https://github.com/rcore-os/rlibc-opt.git", rev = "0ab1d1e" }
rlibc = "1.0"
# rlibc-opt = { git = "https://github.com/rcore-os/rlibc-opt.git", rev = "0ab1d1e" }
rboot = { path = "../rboot", default-features = false }
kernel-hal = { path = "../kernel-hal" }
kernel-hal-bare = { path = "../kernel-hal-bare" }
lazy_static = { version = "1.4", features = ["spin_no_std" ] }
bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator", rev = "03bd9909" }
trapframe = "0.4.1"
trapframe = { git = "https://github.com/rcore-os/trapframe-rs", rev = "fed9668" }
executor = { git = "https://github.com/rcore-os/executor.git", rev = "a2d02ee9" }
zircon-object = { path = "../zircon-object" }
zircon-loader = { path = "../zircon-loader", default-features = false, optional = true }
linux-loader = { path = "../linux-loader", default-features = false, optional = true }
linux-object = { path = "../linux-object", default-features = false, optional = true }
zircon-syscall = { path = "../zircon-syscall", optional = true }
rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "517af47" }
rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "e17b27b", optional = true }
device_tree = { git = "https://github.com/rcore-os/device_tree-rs", rev = "eee2c23" }
zircon-syscall = { path = "../zircon-syscall", optional = true }
rvm = { git = "https://github.com/rcore-os/RVM", rev = "4b64355", optional = true }
[target.'cfg(target_arch = "x86_64")'.dependencies]
x86_64 = "0.11"
[target.'cfg(target_arch = "mips")'.dependencies]
mips = { git = "https://github.com/Harry-Chen/rust-mips", rev = "3b828a2" }

View File

@ -9,16 +9,41 @@ hypervisor ?=
smp ?= 1
test_filter ?= *.*
FEATURES += board_$(BOARD)
build_args := -Z build-std=core,alloc --target $(arch).json
ifeq ($(arch), mipsel)
build_args += --features board_malta
build_args += --features link_user
endif
build_path := target/$(arch)/$(mode)
kernel := $(build_path)/zcore
kernel_img := $(build_path)/zcore.img
ESP := $(build_path)/esp
OVMF := ../rboot/OVMF.fd
qemu := qemu-system-x86_64
qemu := qemu-system-$(arch)
OBJDUMP := rust-objdump -print-imm-hex -x86-asm-syntax=intel
VMDISK := $(build_path)/boot.vdi
QEMU_DISK := $(build_path)/disk.qcow2
sysroot := $(shell rustc --print sysroot)
strip := $(shell find $(sysroot) -name llvm-strip)
hostcc := gcc
dtc := dtc
ifeq ($(arch), mipsel)
BOARD ?= malta
else
BOARD ?= qemu
endif
# currently only mipsel architecture need DTB linked to the kernel
ifeq ($(arch), mipsel)
DTB := src/arch/$(arch)/board/$(BOARD)/device.dtb
endif
export USER_IMG = $(arch).img
ifeq ($(mode), release)
build_args += --release
@ -31,7 +56,7 @@ else
endif
qemu_opts := \
-smp $(smp)
-smp cores=$(smp)
ifeq ($(arch), x86_64)
qemu_opts += \
@ -46,6 +71,15 @@ qemu_opts += \
-m 4G \
-nic none \
-device isa-debug-exit,iobase=0xf4,iosize=0x04
else ifeq ($(arch), mipsel)
ifeq ($(BOARD), malta)
qemu_opts += \
-machine $(BOARD) -device VGA \
-hda mipsel.qcow2 \
-serial null -serial null -serial mon:stdio \
-kernel $(kernel_img)
endif
endif
ifeq ($(hypervisor), 1)
@ -88,6 +122,7 @@ build-test: build
build: $(kernel_img)
$(kernel_img): kernel bootloader
ifeq ($(arch), x86_64)
mkdir -p $(ESP)/EFI/zCore $(ESP)/EFI/Boot
cp ../rboot/target/x86_64-unknown-uefi/release/rboot.efi $(ESP)/EFI/Boot/BootX64.efi
cp rboot.conf $(ESP)/EFI/Boot/rboot.conf
@ -100,13 +135,32 @@ else
cp ../prebuilt/zircon/x64/$(zbi_file).zbi $(ESP)/EFI/zCore/fuchsia.zbi
endif
cp $(kernel) $(ESP)/EFI/zCore/zcore.elf
else ifeq ($(arch), mipsel)
# qemu-system-mipsel accepts ELF file only, so objcopy is not needed
@$(strip) $(kernel) -o $@
endif
kernel:
%.dtb: %.dts
ifeq ($(arch), mipsel)
@echo Generating device tree file $@
@$(dtc) -I dts -O dtb -o $@ $<
# @rm -rf src/arch/${arch}/boot/dtb.gen.s
endif
kernel: $(DTB)
ifeq ($(arch), mipsel)
@for file in entry ; do \
$(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
endif
echo Building zCore kenel
cargo build $(build_args)
bootloader:
cd ../rboot && make build
bootloader: $(kernel)
ifeq ($(arch), x86_64)
@cd ../rboot && make build
endif
clean:
cargo clean

34
zCore/mipsel.json Normal file
View File

@ -0,0 +1,34 @@
{
"arch": "mips",
"cpu": "mips32r2",
"llvm-target": "mipsel-unknown-none",
"data-layout": "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64",
"target-endian": "little",
"target-pointer-width": "32",
"target-c-int-width": "32",
"os": "none",
"features": "+mips32r2",
"max-atomic-width": "32",
"linker": "rust-lld",
"linker-flavor": "ld.lld",
"pre-link-args": {
"ld.lld": ["-Tsrc/arch/mipsel/boot/linker.ld"]
},
"executables": true,
"panic-strategy": "abort",
"relocation-model": "static",
"abi-blacklist": [
"cdecl",
"stdcall",
"fastcall",
"vectorcall",
"thiscall",
"aapcs",
"win64",
"sysv64",
"ptx-kernel",
"msp430-interrupt",
"x86-interrupt"
],
"eliminate-frame-pointer": false
}

View File

@ -0,0 +1,3 @@
/// board specific constants
pub const MEMORY_END: usize = 0x8800_0000;
pub const KERNEL_HEAP_SIZE: usize = 0x0200_0000;

View File

@ -0,0 +1,43 @@
/dts-v1/;
/ {
model = "qemu malta";
compatible = "qemu,malta";
#address-cells = <1>;
#size-cells = <1>;
chosen {
stdio = &uart2;
bootargs = "sh";
};
aliases { };
cpu_intc: interrupt-controller {
compatible = "mti,cpu-interrupt-controller";
interrupt-controller;
#interrupt-cells = <1>;
};
main_memory: memory@0 {
device_type = "memory";
reg = <0x00000000 0x10000000>;
};
uart2: serial@bf000900 {
compatible = "ns16550a";
reg = <0xbf000900 0x40>;
reg-shift = <3>;
clock-frequency = <1843200>;
interrupts = <4>;
};
nor0: flash@be000000 {
compatible = "cfi-flash";
reg = <0xbe000000 0x00400000>;
};
// TODO: add graphics and ethernet adapter
};

View File

@ -0,0 +1,9 @@
/// Device tree bytes
pub static DTB: &'static [u8] = include_bytes!("device.dtb");
/// Initialize other board drivers
pub fn init(dtb: usize) {
// TODO: add possibly more drivers
kernel_hal_bare::drivers::serial::uart16550::driver_init();
kernel_hal_bare::drivers::device_tree::init(dtb);
}

View File

@ -0,0 +1,51 @@
#include "regdef.h"
.set noreorder
.section .text.entry
.globl _start
.extern _root_page_table_buffer
.extern _cur_kstack_ptr
_start:
# setup stack and gp
la sp, bootstacktop
la gp, _gp
la t0, _cur_kstack_ptr
la t1, _root_page_table_buffer
sw t1, 0(t0)
# set ebase
la t0, trap_entry
mfc0 t1, $15, 1 # C0_EBASE
or t1, t1, t0
mtc0 t1, $15, 1
# exit bootstrap mode
mfc0 t0, $12 # C0_STATUS
li t1, 0xFFBFFFFF # set BEV (bit 22) to 0
and t0, t0, t1
mtc0 t0, $12
# directly jump to main function
jal rust_main
nop
.section .bss.stack
.align 12 #PGSHIFT
.global bootstack
bootstack:
.space 4096 * 16 * 8
.global bootstacktop
bootstacktop:
.align 12 #PGSHIFT
.global _root_page_table_buffer
_root_page_table_buffer:
.space 1024 * 64 # 64KB
.global _root_page_table_ptr
_root_page_table_ptr:
.space 4 # 4bytes
.global _cur_tls
_cur_tls:
.space 4 # 4bytes

View File

@ -0,0 +1,56 @@
/* Simple linker script for the ucore kernel.
See the GNU ld 'info' manual ("info ld") to learn the syntax. */
OUTPUT_ARCH(riscv)
ENTRY(_start)
BASE_ADDRESS = 0x80100000;
SECTIONS
{
. = BASE_ADDRESS;
start = .;
.text : {
stext = .;
*(.text.entry)
. = ALIGN(4K);
*(.text.ebase)
_copy_user_start = .;
*(.text.copy_user)
_copy_user_end = .;
*(.text .text.*)
. = ALIGN(4K);
etext = .;
}
.rodata : {
srodata = .;
*(.rodata .rodata.*)
*(.dtb)
. = ALIGN(4K);
erodata = .;
}
.data ALIGN(4K): {
sdata = .;
PROVIDE_HIDDEN(kcounter_descriptor_begin = .);
KEEP(*(.kcounter.descriptor))
PROVIDE_HIDDEN(kcounter_descriptor_end = .);
*(.data .data.*)
edata = .;
}
.stack : {
*(.bss.stack)
}
.bss : {
sbss = .;
*(.bss .bss.*)
ebss = .;
}
PROVIDE(end = .);
}

View File

@ -0,0 +1,55 @@
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 1985 MIPS Computer Systems, Inc.
* Copyright (C) 1994, 95, 99, 2003 by Ralf Baechle
* Copyright (C) 1990 - 1992, 1999 Silicon Graphics, Inc.
*/
#ifndef _ASM_REGDEF_H
#define _ASM_REGDEF_H
/*
* Symbolic register names for 32 bit ABI
*/
#define zero $0 /* wired zero */
#define AT $1 /* assembler temp - uppercase because of ".set at" */
#define v0 $2 /* return value */
#define v1 $3
#define a0 $4 /* argument registers */
#define a1 $5
#define a2 $6
#define a3 $7
#define t0 $8 /* caller saved */
#define t1 $9
#define t2 $10
#define t3 $11
#define t4 $12
#define t5 $13
#define t6 $14
#define t7 $15
#define s0 $16 /* callee saved */
#define s1 $17
#define s2 $18
#define s3 $19
#define s4 $20
#define s5 $21
#define s6 $22
#define s7 $23
#define t8 $24 /* caller saved */
#define t9 $25
#define jp $25 /* PIC jump register */
#define k0 $26 /* kernel scratch */
#define k1 $27
#define gp $28 /* global pointer */
#define sp $29 /* stack pointer */
#define fp $30 /* frame pointer */
#define s8 $30 /* same like fp! */
#define ra $31 /* return address */
#endif /* _ASM_REGDEF_H */

View File

@ -3,23 +3,27 @@
#![feature(lang_items)]
#![feature(asm)]
#![feature(panic_info_message)]
#![deny(unused_must_use)]
#![deny(warnings)] // comment this on develop
#![feature(global_asm)]
// #![deny(unused_must_use)]
// #![deny(warnings)] // comment this on develop
extern crate alloc;
#[macro_use]
extern crate log;
extern crate rlibc_opt;
extern crate rlibc;
// extern crate rlibc_opt;
#[macro_use]
mod logging;
mod lang;
mod memory;
#[cfg(target_arch = "x86_64")]
use rboot::BootInfo;
pub use memory::{hal_frame_alloc, hal_frame_dealloc, hal_pt_map_kernel};
#[cfg(target_arch = "x86_64")]
#[no_mangle]
pub extern "C" fn _start(boot_info: &BootInfo) -> ! {
logging::init(get_log_level(boot_info.cmdline));
@ -40,10 +44,84 @@ pub extern "C" fn _start(boot_info: &BootInfo) -> ! {
boot_info.initramfs_size as usize,
)
};
info!(
"SFS linked to kernel, from {:08x} to {:08x}",
boot_info.initramfs_addr as usize + boot_info.physical_memory_offset as usize,
boot_info.initramfs_addr as usize
+ boot_info.physical_memory_offset as usize
+ boot_info.initramfs_size as usize
);
main(ramfs_data, boot_info.cmdline);
unreachable!();
}
#[cfg(target_arch = "mips")]
global_asm!(include_str!("arch/mipsel/boot/entry.gen.s"));
#[cfg(target_arch = "mips")]
use mips::registers::cp0;
#[cfg(target_arch = "mips")]
#[path = "arch/mipsel/board/malta/mod.rs"]
pub mod board;
// Hard link user programs
#[cfg(feature = "link_user")]
global_asm!(concat!(
r#"
.section .data.img
.global _user_img_start
.global _user_img_end
_user_img_start:
.incbin ""#,
env!("USER_IMG"),
r#""
_user_img_end:
"#
));
#[cfg(target_arch = "mips")]
#[no_mangle]
pub extern "C" fn rust_main() -> ! {
let ebase = cp0::ebase::read_u32();
let cpu_id = ebase & 0x3ff;
let dtb_start = board::DTB.as_ptr() as usize;
const BOOT_CPU_ID: u32 = 0;
if cpu_id != BOOT_CPU_ID {
// TODO: run others_main on other CPU
// while unsafe { !cpu::has_started(hartid) } { }
// others_main();
loop {}
}
// unsafe { cpu::set_cpu_id(hartid); }
unsafe {
memory::clear_bss();
}
logging::init("info");
memory::init_heap();
memory::init_frame_allocator();
kernel_hal_bare::init(kernel_hal_bare::Config {});
board::init(dtb_start);
info!("Hello MIPS 32 from CPU {}, dtb @ {:#x}", cpu_id, dtb_start);
extern "C" {
fn _user_img_start();
fn _user_img_end();
}
use core::slice;
let ramfs_data = unsafe {
slice::from_raw_parts_mut(
_user_img_start as *mut u8,
_user_img_end as usize - _user_img_start as usize,
)
};
info!(
"SFS linked to kernel, from {:08x} to {:08x}",
_user_img_start as usize, _user_img_end as usize
);
main(ramfs_data, "");
unreachable!();
}
#[cfg(feature = "zircon")]
fn main(ramfs_data: &[u8], cmdline: &str) {
use zircon_loader::{run_userboot, Images};
@ -62,7 +140,11 @@ fn main(ramfs_data: &'static mut [u8], _cmdline: &str) {
use alloc::vec;
use linux_object::fs::MemBuf;
#[cfg(target_arch = "x86_64")]
let args = vec!["/bin/busybox".into()];
#[cfg(target_arch = "mips")]
let args = vec!["busybox".into()];
let envs = vec!["PATH=/usr/sbin:/usr/bin:/sbin:/bin:/usr/x86_64-alpine-linux-musl/bin".into()];
let device = Arc::new(MemBuf::new(ramfs_data));
@ -74,8 +156,9 @@ fn main(ramfs_data: &'static mut [u8], _cmdline: &str) {
fn run() -> ! {
loop {
executor::run_until_idle();
x86_64::instructions::interrupts::enable_interrupts_and_hlt();
x86_64::instructions::interrupts::disable();
kernel_hal::InterruptManager::wait_for_interrupt();
// x86_64::instructions::interrupts::enable_interrupts_and_hlt();
// x86_64::instructions::interrupts::disable();
}
}

View File

@ -1,26 +1,56 @@
//! Define the FrameAllocator for physical memory
//! x86_64 -- 64GB
use {
bitmap_allocator::BitAlloc,
buddy_system_allocator::LockedHeap,
rboot::{BootInfo, MemoryType},
spin::Mutex,
x86_64::structures::paging::page_table::{PageTable, PageTableFlags as EF},
};
#[cfg(target_arch = "x86_64")]
use x86_64::structures::paging::page_table::{PageTable, PageTableFlags as EF};
#[cfg(target_arch = "mips")]
use mips::paging::PageTable;
// x86_64 -- 64GB
#[cfg(target_arch = "x86_64")]
type FrameAlloc = bitmap_allocator::BitAlloc16M;
// RISCV, ARM, MIPS has 1G memory
#[cfg(any(
target_arch = "riscv32",
target_arch = "riscv64",
target_arch = "aarch64",
target_arch = "mips"
))]
pub type FrameAlloc = bitmap_allocator::BitAlloc1M;
static FRAME_ALLOCATOR: Mutex<FrameAlloc> = Mutex::new(FrameAlloc::DEFAULT);
#[cfg(target_arch = "x86_64")]
const MEMORY_OFFSET: usize = 0;
#[cfg(target_arch = "x86_64")]
const KERNEL_OFFSET: usize = 0xffffff00_00000000;
#[cfg(target_arch = "x86_64")]
const PHYSICAL_MEMORY_OFFSET: usize = 0xffff8000_00000000;
#[cfg(target_arch = "x86_64")]
const KERNEL_PM4: usize = (KERNEL_OFFSET >> 39) & 0o777;
#[cfg(target_arch = "x86_64")]
const PHYSICAL_MEMORY_PM4: usize = (PHYSICAL_MEMORY_OFFSET >> 39) & 0o777;
#[cfg(target_arch = "x86_64")]
const KERNEL_HEAP_SIZE: usize = 16 * 1024 * 1024; // 16 MB
const KERNEL_PM4: usize = (KERNEL_OFFSET >> 39) & 0o777;
const PHYSICAL_MEMORY_PM4: usize = (PHYSICAL_MEMORY_OFFSET >> 39) & 0o777;
#[cfg(target_arch = "mips")]
const MEMORY_OFFSET: usize = 0x8000_0000;
#[cfg(target_arch = "mips")]
const KERNEL_OFFSET: usize = 0x8010_0000;
#[cfg(target_arch = "mips")]
const PHYSICAL_MEMORY_OFFSET: usize = 0x8000_0000;
#[cfg(target_arch = "mips")]
const MEMORY_END: usize = 0x8800_0000;
#[cfg(target_arch = "mips")]
const KERNEL_HEAP_SIZE: usize = 0x0200_0000;
const PAGE_SIZE: usize = 1 << 12;
@ -28,6 +58,7 @@ const PAGE_SIZE: usize = 1 << 12;
#[export_name = "hal_pmem_base"]
static PMEM_BASE: usize = PHYSICAL_MEMORY_OFFSET;
#[cfg(target_arch = "x86_64")]
pub fn init_frame_allocator(boot_info: &BootInfo) {
let mut ba = FRAME_ALLOCATOR.lock();
for region in boot_info.memory_map.clone().iter {
@ -40,6 +71,55 @@ pub fn init_frame_allocator(boot_info: &BootInfo) {
info!("Frame allocator init end");
}
// Symbols provided by linker script
#[cfg(target_arch = "mips")]
#[allow(dead_code)]
extern "C" {
fn stext();
fn etext();
fn sdata();
fn edata();
fn srodata();
fn erodata();
fn sbss();
fn ebss();
fn start();
fn end();
fn bootstack();
fn bootstacktop();
}
#[cfg(target_arch = "mips")]
pub unsafe fn clear_bss() {
let start = sbss as usize;
let end = ebss as usize;
let step = core::mem::size_of::<usize>();
for i in (start..end).step_by(step) {
(i as *mut usize).write(0);
}
}
#[cfg(target_arch = "mips")]
pub fn init_frame_allocator() {
use core::ops::Range;
let mut ba = FRAME_ALLOCATOR.lock();
let range = to_range(
(end as usize) - KERNEL_OFFSET + MEMORY_OFFSET + PAGE_SIZE,
MEMORY_END,
);
ba.insert(range);
/// Transform memory area `[start, end)` to integer range for `FrameAllocator`
fn to_range(start: usize, end: usize) -> Range<usize> {
info!("frame allocator: start {:#x} end {:#x}", start, end);
let page_start = (start - MEMORY_OFFSET) / PAGE_SIZE;
let page_end = (end - MEMORY_OFFSET - 1) / PAGE_SIZE + 1;
assert!(page_start < page_end, "illegal range for frame allocator");
page_start..page_end
}
info!("Frame allocator init end");
}
pub fn init_heap() {
const MACHINE_ALIGN: usize = core::mem::size_of::<usize>();
const HEAP_BLOCK: usize = KERNEL_HEAP_SIZE / MACHINE_ALIGN;
@ -49,7 +129,6 @@ pub fn init_heap() {
.lock()
.init(HEAP.as_ptr() as usize, HEAP_BLOCK * MACHINE_ALIGN);
}
info!("heap init end");
}
#[no_mangle]
@ -85,6 +164,7 @@ pub extern "C" fn hal_frame_dealloc(target: &usize) {
.dealloc((*target - MEMORY_OFFSET) / PAGE_SIZE);
}
#[cfg(target_arch = "x86_64")]
#[no_mangle]
pub extern "C" fn hal_pt_map_kernel(pt: &mut PageTable, current: &PageTable) {
let ekernel = current[KERNEL_PM4].clone();
@ -93,6 +173,12 @@ pub extern "C" fn hal_pt_map_kernel(pt: &mut PageTable, current: &PageTable) {
pt[PHYSICAL_MEMORY_PM4].set_addr(ephysical.addr(), ephysical.flags() | EF::GLOBAL);
}
#[cfg(target_arch = "mips")]
#[no_mangle]
pub extern "C" fn hal_pt_map_kernel(_pt: &mut PageTable, _current: &PageTable) {
// nothing to do
}
#[cfg(feature = "hypervisor")]
mod rvm_extern_fn {
use super::*;

View File

@ -229,8 +229,11 @@ impl KObjectBase {
/// Generate a new KoID.
fn new_koid() -> KoID {
#[cfg(target_arch = "x86_64")]
static KOID: AtomicU64 = AtomicU64::new(1024);
KOID.fetch_add(1, Ordering::SeqCst)
#[cfg(target_arch = "mips")]
static KOID: AtomicU32 = AtomicU32::new(1024);
KOID.fetch_add(1, Ordering::SeqCst) as u64
}
/// Get object's name.

View File

@ -87,6 +87,11 @@ pub struct PacketGuestMem {
pub _reserved: u64,
}
#[cfg(target_arch = "mips")]
#[repr(C)]
#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
pub struct PacketGuestMem {}
#[repr(C)]
#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
pub struct PacketGuestIo {

View File

@ -102,6 +102,14 @@ pub struct ExceptionContext {
pub cr2: u64,
}
#[cfg(target_arch = "mips")]
#[repr(C)]
#[derive(Default, Clone)]
pub struct ExceptionContext {
pub cause: u64,
pub bad_vaddr: u64,
}
#[cfg(target_arch = "aarch64")]
#[repr(C)]
#[derive(Default, Clone)]
@ -121,6 +129,13 @@ impl ExceptionContext {
cr2: kernel_hal::fetch_fault_vaddr() as u64,
}
}
#[cfg(target_arch = "mips")]
fn from_user_context(cx: &UserContext) -> Self {
ExceptionContext {
cause: cx.cause as u64,
bad_vaddr: kernel_hal::fetch_fault_vaddr() as u64,
}
}
#[cfg(target_arch = "aarch64")]
fn from_user_context(_cx: &UserContext) -> Self {
unimplemented!()

View File

@ -13,7 +13,11 @@ use {
time::Duration,
},
futures::{channel::oneshot::*, future::FutureExt, select_biased},
kernel_hal::{sleep_until, GeneralRegs, UserContext},
kernel_hal::{
sleep_until,
// GeneralRegs,
UserContext,
},
spin::Mutex,
};
@ -193,21 +197,24 @@ impl Thread {
{
let mut inner = self.inner.lock();
let context = inner.context.as_mut().ok_or(ZxError::BAD_STATE)?;
context.set_ip(entry);
context.set_sp(stack);
#[cfg(target_arch = "x86_64")]
{
context.general.rip = entry;
context.general.rsp = stack;
context.general.rdi = arg1;
context.general.rsi = arg2;
context.general.rflags |= 0x3202;
}
#[cfg(target_arch = "aarch64")]
{
context.elr = entry;
context.sp = stack;
context.general.x0 = arg1;
context.general.x1 = arg2;
}
#[cfg(target_arch = "mips")]
{
context.general.a0 = arg1;
context.general.a1 = arg2;
}
inner.state = ThreadState::Running;
self.base.signal_set(Signal::THREAD_RUNNING);
}
@ -216,19 +223,24 @@ impl Thread {
}
/// Start execution with given registers.
pub fn start_with_regs(
pub fn start_with_context(
self: &Arc<Self>,
regs: GeneralRegs,
ctx: UserContext,
spawn_fn: fn(thread: Arc<Thread>),
) -> ZxResult {
{
let mut inner = self.inner.lock();
let context = inner.context.as_mut().ok_or(ZxError::BAD_STATE)?;
context.general = regs;
context.general = ctx.general;
#[cfg(target_arch = "x86_64")]
{
context.general.rflags |= 0x3202;
}
#[cfg(target_arch = "mips")]
{
context.epc = ctx.epc;
context.tls = ctx.tls;
}
inner.state = ThreadState::Running;
self.base.signal_set(Signal::THREAD_RUNNING);
}

View File

@ -0,0 +1,17 @@
#[cfg(not(target_arch = "mips"))]
pub const KERNEL_VMAR_BASE: usize = 0xffff_ff02_0000_0000;
#[cfg(not(target_arch = "mips"))]
pub const KERNEL_VMAR_SIZE: usize = 0x8000_00000;
#[cfg(not(target_arch = "mips"))]
pub const ROOT_VMAR_ADDR: usize = 0x2_00000000;
#[cfg(not(target_arch = "mips"))]
pub const ROOT_VMAR_SIZE: usize = 0x100_00000000;
#[cfg(target_arch = "mips")]
pub const KERNEL_VMAR_BASE: usize = 0x80100000;
#[cfg(target_arch = "mips")]
pub const KERNEL_VMAR_SIZE: usize = 0x4_00000;
#[cfg(target_arch = "mips")]
pub const ROOT_VMAR_ADDR: usize = 0x100000;
#[cfg(target_arch = "mips")]
pub const ROOT_VMAR_SIZE: usize = 0x8000000;

View File

@ -1,5 +1,6 @@
//! Objects for Virtual Memory Management.
mod consts;
mod stream;
mod vmar;
mod vmo;

View File

@ -50,13 +50,13 @@ impl VmAddressRegion {
// FIXME: workaround for unix
static VMAR_ID: AtomicUsize = AtomicUsize::new(0);
let i = VMAR_ID.fetch_add(1, Ordering::SeqCst);
let addr: usize = 0x2_00000000 + 0x100_00000000 * i;
let addr: usize = consts::ROOT_VMAR_ADDR + consts::ROOT_VMAR_SIZE * i;
Arc::new(VmAddressRegion {
flags: VmarFlags::ROOT_FLAGS,
base: KObjectBase::new(),
_counter: CountHelper::new(),
addr,
size: 0x100_00000000,
size: consts::ROOT_VMAR_SIZE,
parent: None,
page_table: Arc::new(Mutex::new(kernel_hal::PageTable::new())),
inner: Mutex::new(Some(VmarInner::default())),
@ -65,8 +65,8 @@ impl VmAddressRegion {
/// Create a kernel root VMAR.
pub fn new_kernel() -> Arc<Self> {
let kernel_vmar_base = 0xffff_ff02_0000_0000; // Sorry i hard code because i'm lazy
let kernel_vmar_size = 0x8000_00000;
let kernel_vmar_base = consts::KERNEL_VMAR_BASE; // Sorry i hard code because i'm lazy
let kernel_vmar_size = consts::KERNEL_VMAR_SIZE;
Arc::new(VmAddressRegion {
flags: VmarFlags::ROOT_FLAGS,
base: KObjectBase::new(),

View File

@ -7,11 +7,16 @@ use {
core::cell::{Ref, RefCell, RefMut},
core::ops::Range,
core::sync::atomic::*,
hashbrown::HashMap,
kernel_hal::{frame_flush, PhysFrame, PAGE_SIZE},
spin::{Mutex, MutexGuard},
};
#[cfg(target_arch = "mips")]
use alloc::collections::BTreeMap as HashMap;
#[cfg(not(target_arch = "mips"))]
use hashbrown::HashMap;
enum VMOType {
/// The original node.
Origin,
@ -1042,8 +1047,11 @@ impl Drop for VMObjectPaged {
#[allow(dead_code)]
/// Generate a owner ID.
fn new_owner_id() -> u64 {
#[cfg(target_arch = "x86_64")]
static OWNER_ID: AtomicU64 = AtomicU64::new(1);
OWNER_ID.fetch_add(1, Ordering::SeqCst)
#[cfg(target_arch = "mips")]
static OWNER_ID: AtomicU32 = AtomicU32::new(1);
OWNER_ID.fetch_add(1, Ordering::SeqCst) as u64
}
const VM_PAGE_OBJECT_MAX_PIN_COUNT: u8 = 31;