forked from rcore-os/zCore
Compare commits
14 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
6e3444acb9 | |
|
|
f902d6bfe7 | |
|
|
1c8d17fb1b | |
|
|
73f447077c | |
|
|
26704a253e | |
|
|
fc034c534a | |
|
|
8833f8c1ca | |
|
|
be7b2d5b28 | |
|
|
b32e2527c7 | |
|
|
690694a17e | |
|
|
9e63d2810d | |
|
|
e2926e144e | |
|
|
9ae7dce43e | |
|
|
ea1aa37bc6 |
|
|
@ -5,3 +5,8 @@ Cargo.lock
|
|||
/rootfs
|
||||
/prebuilt/linux/alpine*
|
||||
.idea
|
||||
|
||||
.DS_Store
|
||||
/zCore/src/arch/mipsel/boot/linker.ld
|
||||
*.gen.s
|
||||
*.dtb
|
||||
|
|
@ -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" }
|
||||
|
|
@ -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!("...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
@ -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) }
|
||||
}
|
||||
|
|
@ -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!()
|
||||
// }
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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")]
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>);
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
|
@ -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]);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
}
|
||||
|
|
@ -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" }
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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" }
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/// board specific constants
|
||||
pub const MEMORY_END: usize = 0x8800_0000;
|
||||
pub const KERNEL_HEAP_SIZE: usize = 0x0200_0000;
|
||||
|
|
@ -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
|
||||
|
||||
};
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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 = .);
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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::*;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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!()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
//! Objects for Virtual Memory Management.
|
||||
|
||||
mod consts;
|
||||
mod stream;
|
||||
mod vmar;
|
||||
mod vmo;
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue