Compare commits

...

3 Commits

Author SHA1 Message Date
Runji Wang ffbdd8e8cb recover workspace toml 2021-08-14 19:20:27 +08:00
Runji Wang b6d6e61a15 riscv code cleanup: use uart_16550 2021-08-14 19:20:27 +08:00
Runji Wang e2bed6a086 riscv code cleanup 2021-08-14 19:20:24 +08:00
23 changed files with 143 additions and 920 deletions

View File

@ -1,9 +1,10 @@
[workspace]
members = [
"zircon-object",
"zircon-syscall",
"zircon-loader",
"linux-object",
"zircon-syscall",
"linux-syscall",
"linux-loader",
"kernel-hal-unix",
"kernel-hal",
@ -13,6 +14,5 @@ exclude = [
"zircon-user",
"zCore",
"rboot",
"linux-syscall",
"kernel-hal-bare",
]

View File

@ -14,12 +14,12 @@ git-version = "0.3"
executor = { git = "https://github.com/rcore-os/executor.git", rev = "a2d02ee9" }
trapframe = "0.8.0"
kernel-hal = { path = "../kernel-hal" }
naive-timer = "0.1.0"
naive-timer = "0.2.0"
lazy_static = { version = "1.4", features = ["spin_no_std" ] }
uart_16550 = { version = "=0.2.15", default-features = false, features = ["stable"] }
[target.'cfg(target_arch = "x86_64")'.dependencies]
x86_64 = "0.14"
uart_16550 = "=0.2.15"
raw-cpuid = "9.0"
pc-keyboard = "0.5"
apic = { git = "https://github.com/rcore-os/apic-rs", rev = "fb86bd7" }
@ -29,7 +29,6 @@ acpi = "1.1"
[target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies]
riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"], rev = "0074cbc" }
# 注意rev版本号必须与其他组件的完全一致不可多字符
rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "6df6cd2" }
device_tree = { git = "https://github.com/rcore-os/device_tree-rs" }
virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "568276" }

View File

@ -18,14 +18,4 @@ pub const MEMORY_END: usize = 0x8800_0000;
pub const USER_STACK_OFFSET: usize = 0x40000000 - USER_STACK_SIZE;
pub const USER_STACK_SIZE: usize = 0x10000;
#[cfg(target_arch = "riscv32")]
pub const KSEG2_START: usize = 0xfe80_0000;
#[cfg(target_arch = "riscv64")]
pub const KSEG2_START: usize = 0xffff_fe80_0000_0000;
pub const MAX_DTB_SIZE: usize = 0x2000;
#[cfg(target_arch = "riscv64")]
pub const ARCH: &'static str = "riscv64";
#[cfg(target_arch = "riscv32")]
pub const ARCH: &'static str = "riscv32";

View File

@ -8,62 +8,19 @@ use riscv::register::{
use spin::Mutex;
use trapframe::{TrapFrame, UserContext};
/*
use crate::timer::{
TICKS,
clock_set_next_event,
clock_close,
};
*/
//use crate::context::TrapFrame;
use super::plic;
use super::sbi;
use super::uart;
use super::consts::PHYSICAL_MEMORY_OFFSET;
use super::timer_set_next;
use crate::{map_range, phys_to_virt, putfmt};
//global_asm!(include_str!("trap.asm"));
/*
#[repr(C)]
pub struct TrapFrame{
pub x: [usize; 32], //General registers
pub sstatus: Sstatus,
pub sepc: usize,
pub stval: usize,
pub scause: Scause,
}
*/
const TABLE_SIZE: usize = 256;
pub type InterruptHandle = Box<dyn Fn() + Send + Sync>;
lazy_static! {
static ref IRQ_TABLE: Mutex<Vec<Option<InterruptHandle>>> = Default::default();
}
fn init_irq() {
init_irq_table();
irq_add_handle(Timer, Box::new(super_timer)); //模拟参照了x86_64,把timer处理函数也放进去了
//irq_add_handle(Keyboard, Box::new(keyboard));
irq_add_handle(S_PLIC, Box::new(plic::handle_interrupt));
}
use super::{map_range, phys_to_virt, putfmt};
pub fn init() {
unsafe {
sstatus::set_sie();
init_uart();
sie::set_sext();
init_ext();
}
init_irq();
bare_println!("+++ setup interrupt +++");
info!("+++ setup interrupt +++");
}
#[no_mangle]
@ -90,121 +47,30 @@ pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
Trap::Exception(Exception::InstructionPageFault) => page_fault(stval, tf),
Trap::Interrupt(Interrupt::SupervisorTimer) => super_timer(),
Trap::Interrupt(Interrupt::SupervisorSoft) => super_soft(),
Trap::Interrupt(Interrupt::SupervisorExternal) => plic::handle_interrupt(),
Trap::Interrupt(Interrupt::SupervisorExternal) => {
if let Some(id) = plic::next() {
match id {
1..=8 => {
//virtio::handle_interrupt(interrupt);
info!("plic virtio external interrupt: {}", id);
}
10 => serial(),
_ => info!("Unknown external interrupt: {}", id),
}
plic::complete(id);
}
}
//Trap::Interrupt(Interrupt::SupervisorExternal) => irq_handle(code as u8),
_ => panic!("Undefined Trap: {:#x} {:#x}", is_int, code),
}
}
fn init_irq_table() {
let mut table = IRQ_TABLE.lock();
for _ in 0..TABLE_SIZE {
table.push(None);
}
}
#[export_name = "hal_irq_handle"]
pub fn irq_handle(irq: u8) {
debug!("PLIC handle: {:#x}", irq);
let table = IRQ_TABLE.lock();
match &table[irq as usize] {
Some(f) => f(),
None => panic!("unhandled U-mode external IRQ number: {}", irq),
}
}
/// Add a handle to IRQ table. Return the specified irq or an allocated irq on success
#[export_name = "hal_irq_add_handle"]
pub fn irq_add_handle(irq: u8, handle: InterruptHandle) -> Option<u8> {
info!("IRQ add handle {:#x?}", irq);
let mut table = IRQ_TABLE.lock();
// allocate a valid irq number
// why?
if irq == 0 {
let mut id = 0x20;
while id < table.len() {
if table[id].is_none() {
table[id] = Some(handle);
return Some(id as u8);
}
id += 1;
}
return None;
}
match table[irq as usize] {
Some(_) => None,
None => {
table[irq as usize] = Some(handle);
Some(irq)
}
}
}
#[export_name = "hal_irq_remove_handle"]
pub fn irq_remove_handle(irq: u8) -> bool {
info!("IRQ remove handle {:#x?}", irq);
let irq = irq as usize;
let mut table = IRQ_TABLE.lock();
match table[irq] {
Some(_) => {
table[irq] = None;
false
}
None => true,
}
}
/*
#[export_name = "hal_irq_allocate_block"]
pub fn allocate_block(irq_num: u32) -> Option<(usize, usize)> {
info!("hal_irq_allocate_block: count={:#x?}", irq_num);
let irq_num = u32::next_power_of_two(irq_num) as usize;
let mut irq_start = 0x20;
let mut irq_cur = irq_start;
let mut table = IRQ_TABLE.lock();
while irq_cur < TABLE_SIZE && irq_cur < irq_start + irq_num {
if table[irq_cur].is_none() {
irq_cur += 1;
} else {
irq_start = (irq_cur - irq_cur % irq_num) + irq_num;
irq_cur = irq_start;
}
}
for i in irq_start..irq_start + irq_num {
table[i] = Some(Box::new(|| {}));
}
info!(
"hal_irq_allocate_block: start={:#x?} num={:#x?}",
irq_start, irq_num
);
Some((irq_start, irq_num))
}
#[export_name = "hal_irq_free_block"]
pub fn free_block(irq_start: u32, irq_num: u32) {
let mut table = IRQ_TABLE.lock();
for i in irq_start..irq_start + irq_num {
table[i as usize] = None;
}
}
*/
#[export_name = "hal_irq_overwrite_handler"]
pub fn overwrite_handler(msi_id: u32, handle: Box<dyn Fn() + Send + Sync>) -> bool {
info!("IRQ overwrite handle {:#x?}", msi_id);
let mut table = IRQ_TABLE.lock();
let set = table[msi_id as usize].is_none();
table[msi_id as usize] = Some(handle);
set
}
fn breakpoint(sepc: &mut usize) {
bare_println!("Exception::Breakpoint: A breakpoint set @0x{:x} ", sepc);
info!("Exception::Breakpoint: A breakpoint set @0x{:x} ", sepc);
//sepc为触发中断指令ebreak的地址
//防止无限循环中断让sret返回时跳转到sepc的下一条指令地址
*sepc += 2
*sepc += 2;
}
fn page_fault(stval: usize, tf: &mut TrapFrame) {
@ -217,7 +83,7 @@ fn page_fault(stval: usize, tf: &mut TrapFrame) {
);
let vaddr = stval;
use crate::PageTableImpl;
use super::PageTableImpl;
use kernel_hal::{MMUFlags, PageTableTrait};
use riscv::addr::{Page, PhysAddr, VirtAddr};
use riscv::paging::{PageTableFlags as PTF, Rv39PageTable, *};
@ -273,29 +139,12 @@ fn super_timer() {
timer_set_next();
super::timer_tick();
//bare_print!(".");
//发生外界中断时epc的指令还没有执行故无需修改epc到下一条
}
fn init_uart() {
uart::Uart::new(0x1000_0000 + PHYSICAL_MEMORY_OFFSET).simple_init();
//但当没有SBI_CONSOLE_PUTCHAR时却为什么不行
super::putfmt_uart(format_args!("{}", "Uart output testing\n"));
bare_println!("+++ Setting up UART interrupts +++");
}
//被plic串口中断调用
pub fn try_process_serial() -> bool {
match super::getchar_option() {
Some(ch) => {
super::serial_put(ch);
true
}
None => false,
}
fn serial() {
let c = super::UART.lock().receive();
super::serial_put(c);
}
pub fn init_ext() {
@ -305,19 +154,19 @@ pub fn init_ext() {
plic::set_threshold(0);
plic::enable(10);
bare_println!("+++ Setting up PLIC +++");
info!("+++ Setting up PLIC +++");
}
fn super_soft() {
sbi::clear_ipi();
bare_println!("Interrupt::SupervisorSoft!");
info!("Interrupt::SupervisorSoft!");
}
pub fn init_soft() {
unsafe {
sie::set_ssoft();
}
bare_println!("+++ setup soft int! +++");
info!("+++ setup soft int! +++");
}
#[export_name = "fetch_trap_num"]
@ -340,46 +189,3 @@ pub fn wait_for_interrupt() {
fn timer() {
super::timer_tick();
}
/*
* uart::handle_interrupt()
*
fn com1() {
let c = super::COM1.lock().receive();
super::serial_put(c);
}
*/
/*
fn keyboard() {
use pc_keyboard::{DecodedKey, KeyCode};
if let Some(key) = super::keyboard::receive() {
match key {
DecodedKey::Unicode(c) => super::serial_put(c as u8),
DecodedKey::RawKey(code) => {
let s = match code {
KeyCode::ArrowUp => "\u{1b}[A",
KeyCode::ArrowDown => "\u{1b}[B",
KeyCode::ArrowRight => "\u{1b}[C",
KeyCode::ArrowLeft => "\u{1b}[D",
_ => "",
};
for c in s.bytes() {
super::serial_put(c);
}
}
}
}
}
*/
// IRQ
const Timer: u8 = 5;
const U_PLIC: u8 = 8;
const S_PLIC: u8 = 9;
const M_PLIC: u8 = 11;
//const Keyboard: u8 = 1;
//const COM2: u8 = 3;
const COM1: u8 = 0;
//const IDE: u8 = 14;

View File

@ -5,14 +5,15 @@ use riscv::asm::sfence_vma_all;
use riscv::paging::{PageTableFlags as PTF, *};
use riscv::register::{satp, sie, stval, time};
//use crate::sbi;
use alloc::{collections::VecDeque, vec::Vec};
use alloc::{collections::VecDeque, vec::Vec, string::String};
use core::fmt::{self, Write};
use self::consts::PHYSICAL_MEMORY_OFFSET;
mod sbi;
mod consts;
use consts::PHYSICAL_MEMORY_OFFSET;
pub mod interrupt;
mod plic;
pub mod virtio;
// First core stores its SATP here.
static mut SATP: usize = 0;
@ -321,19 +322,6 @@ impl PageTableTrait for PageTableImpl {
fn table_phys(&self) -> PhysAddr {
self.root_paddr
}
/// Activate this page table
#[export_name = "hal_pt_activate"]
fn activate(&self) {
let now_token = satp::read().bits();
let new_token = self.table_phys();
if now_token != new_token {
debug!("switch table {:x?} -> {:x?}", now_token, new_token);
unsafe {
set_page_table(new_token);
}
}
}
}
pub unsafe fn set_page_table(vmtoken: usize) {
@ -390,43 +378,6 @@ impl FrameDeallocator for FrameAllocatorImpl {
}
}
lazy_static! {
static ref STDIN: Mutex<VecDeque<u8>> = Mutex::new(VecDeque::new());
static ref STDIN_CALLBACK: Mutex<Vec<Box<dyn Fn() -> bool + Send + Sync>>> =
Mutex::new(Vec::new());
}
//调用这里
/// Put a char by serial interrupt handler.
fn serial_put(mut x: u8) {
if x == b'\r' {
x = b'\n';
}
STDIN.lock().push_back(x);
STDIN_CALLBACK.lock().retain(|f| !f());
}
#[export_name = "hal_serial_set_callback"]
pub fn serial_set_callback(callback: Box<dyn Fn() -> bool + Send + Sync>) {
STDIN_CALLBACK.lock().push(callback);
}
#[export_name = "hal_serial_read"]
pub fn serial_read(buf: &mut [u8]) -> usize {
let mut stdin = STDIN.lock();
let len = stdin.len().min(buf.len());
for c in &mut buf[..len] {
*c = stdin.pop_front().unwrap();
}
len
}
#[export_name = "hal_serial_write"]
pub fn serial_write(s: &str) {
//putfmt(format_args!("{}", s));
putfmt_uart(format_args!("{}", s));
}
// Get TSC frequency.
fn tsc_frequency() -> u16 {
const DEFAULT: u16 = 2600;
@ -441,73 +392,26 @@ pub fn apic_local_id() -> u8 {
lapic as u8
}
////////////
pub fn getchar_option() -> Option<u8> {
let c = sbi::console_getchar() as isize;
match c {
-1 => None,
c => Some(c as u8),
}
}
////////////
pub fn putchar(ch: char) {
sbi::console_putchar(ch as u8 as usize);
}
pub fn puts(s: &str) {
for ch in s.chars() {
putchar(ch);
}
lazy_static! {
static ref UART: Mutex<uart_16550::MmioSerialPort>
= Mutex::new(unsafe { uart_16550::MmioSerialPort::new(0x1000_0000 + PHYSICAL_MEMORY_OFFSET) });
}
struct Stdout;
impl fmt::Write for Stdout {
fn write_str(&mut self, s: &str) -> fmt::Result {
puts(s);
for b in s.bytes() {
sbi::console_putchar(b as _);
}
Ok(())
}
}
pub fn putfmt(fmt: fmt::Arguments) {
Stdout.write_fmt(fmt).unwrap();
}
////////////
struct Stdout1;
impl fmt::Write for Stdout1 {
fn write_str(&mut self, s: &str) -> fmt::Result {
//每次都创建一个新的Uart ? 内存位置始终相同
write!(
uart::Uart::new(0x1000_0000 + PHYSICAL_MEMORY_OFFSET),
"{}",
s
)
.unwrap();
Ok(())
}
}
pub fn putfmt_uart(fmt: fmt::Arguments) {
Stdout1.write_fmt(fmt).unwrap();
}
////////////
#[macro_export]
macro_rules! bare_print {
($($arg:tt)*) => ({
putfmt(format_args!($($arg)*));
});
}
#[macro_export]
macro_rules! bare_println {
() => (bare_print!("\n"));
($($arg:tt)*) => (bare_print!("{}\n", format_args!($($arg)*)));
// FIXME: use UART would block
// UART.lock().write_fmt(fmt).unwrap();
}
pub const MMIO_MTIMECMP0: *mut u64 = 0x0200_4000usize as *mut u64;
@ -515,22 +419,15 @@ pub const MMIO_MTIME: *const u64 = 0x0200_BFF8 as *const u64;
fn get_cycle() -> u64 {
time::read() as u64
/*
unsafe {
MMIO_MTIME.read_volatile()
}
*/
}
#[export_name = "hal_timer_now"]
pub fn timer_now() -> Duration {
const FREQUENCY: u64 = 10_000_000; // ???
let time = get_cycle();
//bare_println!("timer_now(): {:?}", time);
Duration::from_nanos(time * 1_000_000_000 / FREQUENCY as u64)
}
#[export_name = "hal_timer_set_next"]
fn timer_set_next() {
//let TIMEBASE: u64 = 100000;
let TIMEBASE: u64 = 10_000_000;
@ -547,24 +444,19 @@ fn timer_init() {
pub fn init(config: Config) {
interrupt::init();
timer_init();
UART.lock().init();
/*
interrupt::init_soft();
sbi::send_ipi(0);
*/
let cmdline = virtio::device_tree::init(config.dtb);
unsafe { CMDLINE = cmdline };
}
unsafe {
llvm_asm!("ebreak"::::"volatile");
}
static mut CMDLINE: String = String::new();
bare_println!("Setup virtio @devicetree {:#x}", config.dtb);
//virtio::init(config.dtb);
virtio::device_tree::init(config.dtb);
pub fn cmdline() -> &'static str {
unsafe { CMDLINE.as_str() }
}
pub struct Config {
pub mconfig: u64,
pub dtb: usize,
}
@ -573,53 +465,6 @@ pub fn fetch_fault_vaddr() -> VirtAddr {
stval::read() as _
}
static mut CONFIG: Config = Config { mconfig: 0, dtb: 0 };
/// This structure represents the information that the bootloader passes to the kernel.
#[repr(C)]
#[derive(Debug)]
pub struct BootInfo {
pub memory_map: Vec<u64>,
//pub memory_map: Vec<&'static MemoryDescriptor>,
/// The offset into the virtual address space where the physical memory is mapped.
pub physical_memory_offset: u64,
/// The graphic output information
pub graphic_info: GraphicInfo,
/// Physical address of ACPI2 RSDP, 启动的系统信息表的入口指针
//pub acpi2_rsdp_addr: u64,
/// Physical address of SMBIOS, 产品管理信息的结构表
//pub smbios_addr: u64,
pub hartid: u64,
pub dtb_addr: u64,
/// The start physical address of initramfs
pub initramfs_addr: u64,
/// The size of initramfs
pub initramfs_size: u64,
/// Kernel command line
pub cmdline: &'static str,
}
/// Graphic output information
#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub struct GraphicInfo {
/// Graphic mode
//pub mode: ModeInfo,
pub mode: u64,
/// Framebuffer base physical address
pub fb_addr: u64,
/// Framebuffer size
pub fb_size: u64,
}
pub mod interrupt;
mod plic;
mod uart;
pub mod virtio;
#[export_name = "hal_current_pgtable"]
pub fn current_page_table() -> usize {
#[cfg(target_arch = "riscv32")]

View File

@ -1,7 +1,4 @@
use super::consts::PHYSICAL_MEMORY_OFFSET;
use super::interrupt;
use super::uart;
use crate::putfmt; //For bare_println
const MMODE: usize = 0;
@ -111,27 +108,3 @@ pub fn set_threshold(tsh: u8) {
tsh_reg.write_volatile(actual_tsh as u32); // 0x0c20_0000 <= 0 = 0 & 7
}
}
pub fn handle_interrupt() {
if let Some(interrupt) = next() {
match interrupt {
1..=8 => {
//virtio::handle_interrupt(interrupt);
bare_println!("plic virtio external interrupt: {}", interrupt);
}
10 => {
//UART中断ID是10
uart::handle_interrupt();
//换用sbi的方式获取字符
//interrupt::try_process_serial();
}
_ => {
bare_println!("Unknown external interrupt: {}", interrupt);
}
}
//这将复位pending的中断允许UART再次中断。
//否则UART将被“卡住”
complete(interrupt);
}
}

View File

@ -9,11 +9,14 @@ pub fn console_getchar() -> usize {
fn sbi_call(which: usize, arg0: usize, arg1: usize, arg2: usize) -> usize {
let ret: usize;
unsafe {
llvm_asm!("ecall"
:"={x10}"(ret)
:"{x10}"(arg0), "{x11}"(arg1), "{x12}"(arg2), "{x17}"(which)
:"memory"
:"volatile");
asm!(
"ecall",
in("a0") arg0,
in("a1") arg1,
in("a2") arg2,
in("a7") which,
lateout("a0") ret,
);
}
ret
}

View File

@ -1,130 +0,0 @@
.equ XLENB, 8
# sp + 8*a2 -> a1
.macro LOAD a1, a2
ld \a1, \a2*XLENB(sp)
.endm
.macro STORE a1, a2
sd \a1, \a2*XLENB(sp)
.endm
# int in U: sscratch = kernel_addr; int in S: sscratch = 0;
.macro SAVE_ALL
csrrw sp, sscratch, sp
bnez sp, trap_from_user
trap_from_kernel:
csrr sp, sscratch
trap_from_user:
addi sp, sp, -36*XLENB
# x0 = 0, x2 = sp
STORE x1, 1
STORE x3, 3
STORE x4, 4
STORE x5, 5
STORE x6, 6
STORE x7, 7
STORE x8, 8
STORE x9, 9
STORE x10, 10
STORE x11, 11
STORE x12, 12
STORE x13, 13
STORE x14, 14
STORE x15, 15
STORE x16, 16
STORE x17, 17
STORE x18, 18
STORE x19, 19
STORE x20, 20
STORE x21, 21
STORE x22, 22
STORE x23, 23
STORE x24, 24
STORE x25, 25
STORE x26, 26
STORE x27, 27
STORE x28, 28
STORE x29, 29
STORE x30, 30
STORE x31, 31
csrrw s0, sscratch, x0
csrr s1, sstatus
csrr s2, sepc
csrr s3, stval
csrr s4, scause
STORE s0, 2
STORE s1, 32
STORE s2, 33
STORE s3, 34
STORE s4, 35
.endm
.macro RESTORE_ALL
# s1 = sstatus, s2 = sepc
LOAD s1, 32
LOAD s2, 33
# int in Kernel, sstatus SPP = 1; int in User, sstatus SPP 0
andi s0, s1, 1 << 8
bnez s0, _to_kernel
_to_user:
addi s0, sp, 36 * XLENB
csrw sscratch, s0
_to_kernel:
csrw sstatus, s1
csrw sepc, s2
LOAD x1, 1
LOAD x3, 3
LOAD x4, 4
LOAD x5, 5
LOAD x6, 6
LOAD x7, 7
LOAD x8, 8
LOAD x9, 9
LOAD x10, 10
LOAD x11, 11
LOAD x12, 12
LOAD x13, 13
LOAD x14, 14
LOAD x15, 15
LOAD x16, 16
LOAD x17, 17
LOAD x18, 18
LOAD x19, 19
LOAD x20, 20
LOAD x21, 21
LOAD x22, 22
LOAD x23, 23
LOAD x24, 24
LOAD x25, 25
LOAD x26, 26
LOAD x27, 27
LOAD x28, 28
LOAD x29, 29
LOAD x30, 30
LOAD x31, 31
# sp
LOAD x2, 2
.endm
.section .text
.globl __alltraps
.align 4
__alltraps:
SAVE_ALL
mv a0, sp
jal rust_trap
.globl __trapret
__trapret:
RESTORE_ALL
sret

View File

@ -1,151 +0,0 @@
use super::consts::PHYSICAL_MEMORY_OFFSET;
use crate::putfmt;
use core::convert::TryInto;
use core::fmt::{Error, Write};
//use crate::console::push_stdin;
pub struct Uart {
base_address: usize,
}
// 结构体Uart的实现块
impl Uart {
pub fn new(base_address: usize) -> Self {
Uart { base_address }
}
/*
uart初始化
8-bits (LCR[1:0])
使FIFOs (FCR[0])
使(IER[0]), 使
*/
pub fn init(&mut self) {
let ptr = self.base_address as *mut u8;
unsafe {
// LCR at base_address + 3
// 置位 bit 0 bit 1
let lcr = (1 << 0) | (1 << 1);
ptr.add(3).write_volatile(lcr);
// FCR at offset 2
ptr.add(2).write_volatile(1 << 0);
//IER at offset 1
ptr.add(1).write_volatile(1 << 0);
// 设置波特率,除子,取整等
// 2.729 MHz (22,729,000 cycles per second) --> 波特率 2400 (BAUD)
// 根据NS16550a规格说明书计算出divisor
// divisor = ceil( (clock_hz) / (baud_sps x 16) )
// divisor = ceil( 22_729_000 / (2400 x 16) ) = ceil( 591.901 ) = 592
// divisor寄存器是16 bits
let divisor: u16 = 592;
//let divisor_least: u8 = divisor & 0xff;
//let divisor_most: u8 = divisor >> 8;
let divisor_least: u8 = (divisor & 0xff).try_into().unwrap();
let divisor_most: u8 = (divisor >> 8).try_into().unwrap();
// DLL和DLM会与其它寄存器共用基地址需要设置DLAB来切换选择寄存器
// LCR base_address + 3, DLAB = 1
ptr.add(3).write_volatile(lcr | 1 << 7);
//写DLL和DLM来设置波特率, 把频率22.729 MHz的时钟划分为每秒2400个信号
ptr.add(0).write_volatile(divisor_least);
ptr.add(1).write_volatile(divisor_most);
// 设置后不需要再动了, 清空DLAB
ptr.add(3).write_volatile(lcr);
}
}
pub fn simple_init(&mut self) {
let ptr = self.base_address as *mut u8;
unsafe {
// Enable FIFO; (base + 2)
ptr.add(2).write_volatile(0xC7);
// MODEM Ctrl; (base + 4)
ptr.add(4).write_volatile(0x0B);
// Enable interrupts; (base + 1)
ptr.add(1).write_volatile(0x01);
}
}
pub fn get(&mut self) -> Option<u8> {
let ptr = self.base_address as *mut u8;
unsafe {
//查看LCR, DR位为1则有数据
if ptr.add(5).read_volatile() & 0b1 == 0 {
None
} else {
Some(ptr.add(0).read_volatile())
}
}
}
pub fn put(&mut self, c: u8) {
let ptr = self.base_address as *mut u8;
unsafe {
//此时transmitter empty
ptr.add(0).write_volatile(c);
}
}
}
// 需要实现的write_str()重要函数
impl Write for Uart {
fn write_str(&mut self, out: &str) -> Result<(), Error> {
for c in out.bytes() {
self.put(c);
}
Ok(())
}
}
/*
fn unsafe mmio_write(address: usize, offset: usize, value: u8) {
//write_volatile() 是 *mut raw 的成员;
//new_pointer = old_pointer + sizeof(pointer_type) * offset
//也可使用reg.offset
let reg = address as *mut u8;
reg.add(offset).write_volatile(value);
}
fn unsafe mmio_read(address: usize, offset: usize, value: u8) -> u8 {
let reg = address as *mut u8;
//读取8 bits
reg.add(offset).read_volatile(value) //无分号可直接返回值
}
*/
pub fn handle_interrupt() {
let mut my_uart = Uart::new(0x1000_0000 + PHYSICAL_MEMORY_OFFSET);
if let Some(c) = my_uart.get() {
//CONSOLE
//push_stdin(c);
super::serial_put(c);
/*
* serial_write()
match c {
0x7f => { //0x8 [backspace] ; 而实际qemu运行[backspace]键输出0x7f, 表示del
bare_print!("{} {}", 8 as char, 8 as char);
},
10 | 13 => { // 新行或回车
bare_println!();
},
_ => {
bare_print!("{}", c as char);
},
}
*/
}
}

View File

@ -5,11 +5,10 @@ use device_tree::{DeviceTree, Node};
//use super::virtio_mmio::virtio_probe;
use super::virtio::virtio_probe;
use super::CMDLINE;
const DEVICE_TREE_MAGIC: u32 = 0xd00dfeed;
fn walk_dt_node(dt: &Node) {
fn walk_dt_node(dt: &Node, cmdline_out: &mut String) {
if let Ok(compatible) = dt.prop_str("compatible") {
// TODO: query this from table
if compatible == "virtio,mmio" {
@ -18,13 +17,12 @@ fn walk_dt_node(dt: &Node) {
// TODO: initial other devices (16650, etc.)
}
if let Ok(bootargs) = dt.prop_str("bootargs") {
if bootargs.len() > 0 {
info!("Kernel cmdline: {}", bootargs);
*CMDLINE.write() = String::from(bootargs);
if !bootargs.is_empty() {
*cmdline_out = String::from(bootargs);
}
}
for child in dt.children.iter() {
walk_dt_node(child);
walk_dt_node(child, cmdline_out);
}
}
@ -33,16 +31,18 @@ struct DtbHeader {
size: u32,
}
pub fn init(dtb: usize) {
/// Return cmdline.
pub fn init(dtb: usize) -> String {
info!("DTB: {:#x}", dtb);
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) {
//trace!("DTB: {:#x?}", dt);
walk_dt_node(&dt.root);
}
assert_eq!(magic, DEVICE_TREE_MAGIC, "invalid device tree magic number");
let size = u32::from_be(header.size);
let dtb_data = unsafe { slice::from_raw_parts(dtb as *const u8, size as usize) };
let mut cmdline = String::new();
if let Ok(dt) = DeviceTree::load(dtb_data) {
//trace!("DTB: {:#x?}", dt);
walk_dt_node(&dt.root, &mut cmdline);
}
cmdline
}

View File

@ -97,8 +97,3 @@ impl BlockDevice for BlockDriverWrapper {
Ok(())
}
}
lazy_static! {
// Write only once at boot
pub static ref CMDLINE: RwLock<String> = RwLock::new(String::new());
}

View File

@ -150,12 +150,6 @@ impl PageTableTrait for PageTableImpl {
fn table_phys(&self) -> PhysAddr {
self.root_paddr
}
// /// Activate this page table
// #[export_name = "hal_pt_activate"]
// fn activate(&self) {
// unimplemented!()
// }
}
/// Set page table.
@ -281,41 +275,6 @@ pub fn putfmt(fmt: Arguments) {
}
}
lazy_static! {
static ref STDIN: Mutex<VecDeque<u8>> = Mutex::new(VecDeque::new());
static ref STDIN_CALLBACK: Mutex<Vec<Box<dyn Fn() -> bool + Send + Sync>>> =
Mutex::new(Vec::new());
}
/// Put a char by serial interrupt handler.
fn serial_put(mut x: u8) {
if x == b'\r' {
x = b'\n';
}
STDIN.lock().push_back(x);
STDIN_CALLBACK.lock().retain(|f| !f());
}
#[export_name = "hal_serial_set_callback"]
pub fn serial_set_callback(callback: Box<dyn Fn() -> bool + Send + Sync>) {
STDIN_CALLBACK.lock().push(callback);
}
#[export_name = "hal_serial_read"]
pub fn serial_read(buf: &mut [u8]) -> usize {
let mut stdin = STDIN.lock();
let len = stdin.len().min(buf.len());
for c in &mut buf[..len] {
*c = stdin.pop_front().unwrap();
}
len
}
#[export_name = "hal_serial_write"]
pub fn serial_write(s: &str) {
putfmt(format_args!("{}", s));
}
/// Get TSC frequency.
///
/// WARN: This will be very slow on virtual machine since it uses CPUID instruction.

View File

@ -15,8 +15,6 @@
#![no_std]
#![feature(asm)]
#![feature(llvm_asm)]
#![feature(global_asm)]
#![feature(linkage)]
//#![deny(warnings)]
@ -41,9 +39,10 @@ use kernel_hal::UserContext;
use naive_timer::Timer;
use spin::Mutex;
pub mod arch;
mod arch;
mod serial;
pub use self::arch::*;
pub use self::{arch::*, serial::*};
#[allow(improper_ctypes)]
extern "C" {
@ -190,16 +189,6 @@ pub fn frame_copy(src: PhysAddr, target: PhysAddr) {
}
}
/// Zero `target` frame.
#[export_name = "hal_frame_zero"]
pub fn frame_zero_in_range(target: PhysAddr, start: usize, end: usize) {
assert!(start < PAGE_SIZE && end <= PAGE_SIZE);
trace!("frame_zero: {:#x?}", target);
unsafe {
core::ptr::write_bytes(phys_to_virt(target + start) as *mut u8, 0, end - start);
}
}
lazy_static! {
pub static ref NAIVE_TIMER: Mutex<Timer> = Mutex::new(Timer::default());
}
@ -209,21 +198,16 @@ pub fn timer_set(deadline: Duration, callback: Box<dyn FnOnce(Duration) + Send +
NAIVE_TIMER.lock().add(deadline, callback);
}
#[export_name = "hal_timer_tick"]
pub fn timer_tick() {
let now = arch::timer_now();
NAIVE_TIMER.lock().expire(now);
}
/// Initialize the HAL.
pub fn init(config: Config) {
pub fn init(config: arch::Config) {
unsafe {
trapframe::init();
}
#[cfg(target_arch = "riscv64")]
trace!("hal dtb: {:#x}", config.dtb);
arch::init(config);
}

View File

@ -0,0 +1,37 @@
use spin::Mutex;
use alloc::{boxed::Box, collections::VecDeque, vec::Vec};
lazy_static! {
static ref STDIN: Mutex<VecDeque<u8>> = Mutex::new(VecDeque::new());
static ref STDIN_CALLBACK: Mutex<Vec<Box<dyn Fn() -> bool + Send + Sync>>> =
Mutex::new(Vec::new());
}
/// Put a char by serial interrupt handler.
pub fn serial_put(mut x: u8) {
if x == b'\r' {
x = b'\n';
}
STDIN.lock().push_back(x);
STDIN_CALLBACK.lock().retain(|f| !f());
}
#[export_name = "hal_serial_set_callback"]
pub fn serial_set_callback(callback: Box<dyn Fn() -> bool + Send + Sync>) {
STDIN_CALLBACK.lock().push(callback);
}
#[export_name = "hal_serial_read"]
pub fn serial_read(buf: &mut [u8]) -> usize {
let mut stdin = STDIN.lock();
let len = stdin.len().min(buf.len());
for c in &mut buf[..len] {
*c = stdin.pop_front().unwrap();
}
len
}
#[export_name = "hal_serial_write"]
pub fn serial_write(s: &str) {
crate::arch::putfmt(format_args!("{}", s));
}

View File

@ -12,6 +12,3 @@ bitflags = "1.2"
trapframe = "0.8.0"
numeric-enum-macro = "0.2"
acpi = "1.1"
#[patch.crates-io]
#trapframe = { path = "/home/xly/rust/arch-lib/trapframe-rs" }

View File

@ -70,10 +70,6 @@ pub trait PageTableTrait: Sync + Send {
/// Get the physical address of root page table.
fn table_phys(&self) -> PhysAddr;
#[cfg(target_arch = "riscv64")]
/// Activate this page table
fn activate(&self);
fn map_many(
&mut self,
mut vaddr: VirtAddr,
@ -165,14 +161,6 @@ impl PageTableTrait for PageTable {
self.table_phys
}
/// Activate this page table
#[cfg(target_arch = "riscv64")]
#[linkage = "weak"]
#[export_name = "hal_pt_activate"]
fn activate(&self) {
unimplemented!()
}
#[linkage = "weak"]
#[export_name = "hal_pt_unmap_cont"]
fn unmap_cont(&mut self, vaddr: VirtAddr, pages: usize) -> Result<()> {
@ -300,19 +288,6 @@ pub fn timer_set(_deadline: Duration, _callback: Box<dyn FnOnce(Duration) + Send
unimplemented!()
}
#[linkage = "weak"]
#[export_name = "hal_timer_set_next"]
pub fn timer_set_next() {
unimplemented!()
}
/// Check timers, call when timer interrupt happened.
#[linkage = "weak"]
#[export_name = "hal_timer_tick"]
pub fn timer_tick() {
unimplemented!()
}
pub struct InterruptManager {}
impl InterruptManager {
/// Handle IRQ.

View File

@ -134,17 +134,8 @@ async fn new_thread(thread: CurrentThread) {
//Timer
if trap_num == 4 || trap_num == 5 {
debug!("Timer interrupt: {}", trap_num);
/*
* irq_handle里加入了timer处理函数
kernel_hal::timer_set_next();
kernel_hal::timer_tick();
*/
kernel_hal::yield_now().await;
}
//kernel_hal::InterruptManager::handle(trap_num as u8);
}
_ => panic!(
"not supported pid: {} interrupt {} from user mode. {:#x?}",

View File

@ -196,9 +196,6 @@ impl Syscall<'_> {
};
let (entry, sp) = loader.load(&vmar, &data, args, envs, path.clone())?;
// Activate page table
// vmar.activate();
// Modify exec path
proc.set_execute_path(&path);

View File

@ -8,6 +8,7 @@ user ?=
hypervisor ?=
smp ?= 1
test_filter ?= *.*
log ?=
build_args := -Z build-std=core,alloc --target $(arch).json
build_path := target/$(arch)/$(mode)
@ -69,7 +70,8 @@ qemu_opts += \
-nographic \
-drive file=$(QEMU_DISK),format=qcow2,id=sfs \
-device virtio-blk-device,drive=sfs \
-kernel $(kernel_bin)
-kernel $(kernel_bin) \
-append LOG=$(log)
endif

View File

@ -5,7 +5,7 @@ use {
pub fn init(level: &str) {
static LOGGER: SimpleLogger = SimpleLogger;
log::set_logger(&LOGGER).unwrap();
let _ = log::set_logger(&LOGGER);
log::set_max_level(match level {
"error" => LevelFilter::Error,
"warn" => LevelFilter::Warn,
@ -37,12 +37,12 @@ macro_rules! with_color {
}
fn print_in_color(args: fmt::Arguments, color_code: u8) {
kernel_hal_bare::arch::putfmt(with_color!(args, color_code));
kernel_hal_bare::putfmt(with_color!(args, color_code));
}
#[allow(dead_code)]
pub fn print(args: fmt::Arguments) {
kernel_hal_bare::arch::putfmt(args);
kernel_hal_bare::putfmt(args);
}
struct SimpleLogger;

View File

@ -1,7 +1,6 @@
#![no_std]
#![no_main]
#![feature(lang_items)]
#![feature(llvm_asm)]
#![feature(panic_info_message)]
#![deny(unused_must_use)]
#![feature(global_asm)]
@ -15,12 +14,9 @@ extern crate log;
#[cfg(target_arch = "riscv64")]
extern crate rlibc;
#[cfg(target_arch = "x86_64")]
extern crate rlibc_opt; //Only for x86_64
extern crate fatfs;
#[macro_use]
mod logging;
mod lang;
@ -33,17 +29,17 @@ use rboot::BootInfo;
use kernel_hal_bare::{
phys_to_virt, remap_the_kernel,
virtio::{BlockDriverWrapper, BLK_DRIVERS},
BootInfo, GraphicInfo,
};
use alloc::vec::Vec;
use alloc::{string::String, vec::Vec};
#[cfg(target_arch = "riscv64")]
global_asm!(include_str!("arch/riscv/boot/entry64.asm"));
#[cfg(target_arch = "x86_64")]
#[no_mangle]
pub extern "C" fn _start(boot_info: &BootInfo) -> ! {
logging::init(get_log_level(boot_info.cmdline));
logging::init(get_value(boot_info.cmdline, "LOG").unwrap_or(""));
memory::init_heap();
memory::init_frame_allocator(boot_info);
@ -83,75 +79,38 @@ fn main(ramfs_data: &[u8], cmdline: &str) -> ! {
#[no_mangle]
pub extern "C" fn rust_main(hartid: usize, device_tree_paddr: usize) -> ! {
let device_tree_vaddr = phys_to_virt(device_tree_paddr);
let boot_info = BootInfo {
memory_map: Vec::new(),
physical_memory_offset: 0,
graphic_info: GraphicInfo {
mode: 0,
fb_addr: 0,
fb_size: 0,
},
hartid: hartid as u64,
dtb_addr: device_tree_paddr as u64,
initramfs_addr: 0,
initramfs_size: 0,
cmdline: "LOG=warn:TERM=xterm-256color:console.shell=true:virtcon.disable=true",
};
unsafe {
memory::clear_bss();
}
logging::init(get_log_level(boot_info.cmdline));
warn!("rust_main(), After logging init\n\n");
logging::init("info");
memory::init_heap();
memory::init_frame_allocator(&boot_info);
memory::init_frame_allocator();
remap_the_kernel(device_tree_vaddr);
#[cfg(feature = "graphic")]
init_framebuffer(boot_info);
info!("{:#x?}", boot_info);
kernel_hal_bare::init(kernel_hal_bare::Config {
mconfig: 0,
dtb: device_tree_vaddr,
});
use alloc::{format, string::ToString};
use kernel_hal_bare::virtio::CMDLINE;
let cmdline_dt = CMDLINE.read();
let mut cmdline = boot_info.cmdline.to_string();
if !cmdline_dt.is_empty() {
cmdline = format!("{}:{}", boot_info.cmdline, cmdline_dt);
};
warn!("cmdline: {:?}", cmdline);
let cmdline = kernel_hal_bare::cmdline();
info!("cmdline: {:?}", cmdline);
logging::init(get_value(cmdline, "LOG").unwrap_or(""));
// 正常由bootloader载入文件系统镜像到内存, 这里不用而使用后面的virtio
main(&mut [], &cmdline);
}
use alloc::string::String;
use alloc::vec;
#[cfg(feature = "linux")]
use alloc::vec;
fn get_rootproc(cmdline: &str) -> Vec<String> {
for opt in cmdline.split(':') {
// parse 'key=value'
let mut iter = opt.trim().splitn(2, '=');
let key = iter.next().expect("failed to parse key");
let value = iter.next().expect("failed to parse value");
info!("value {}", value);
if key == "ROOTPROC" {
let mut iter = value.trim().splitn(2, '?');
let k1 = iter.next().expect("failed to parse k1");
let v1 = iter.next().expect("failed to parse v1");
if v1 == "" {
return vec![k1.into()];
} else {
return vec![k1.into(), v1.into()];
}
if let Some(value) = get_value(cmdline, "ROOTPROC") {
let mut iter = value.trim().splitn(2, '?');
let k1 = iter.next().expect("failed to parse k1");
let v1 = iter.next().expect("failed to parse v1");
if v1 == "" {
return vec![k1.into()];
} else {
return vec![k1.into(), v1.into()];
}
}
vec!["/bin/busybox".into(), "sh".into()]
@ -160,9 +119,7 @@ fn get_rootproc(cmdline: &str) -> Vec<String> {
#[cfg(feature = "linux")]
fn main(ramfs_data: &'static mut [u8], cmdline: &str) -> ! {
use alloc::boxed::Box;
use alloc::string::String;
use alloc::sync::Arc;
use alloc::vec;
#[cfg(target_arch = "x86_64")]
use linux_object::fs::MemBuf;
@ -227,17 +184,20 @@ fn run() -> ! {
}
}
fn get_log_level(cmdline: &str) -> &str {
fn get_value<'a>(cmdline: &'a str, key: &str) -> Option<&'a str> {
for opt in cmdline.split(':') {
if opt.is_empty() {
continue;
}
// parse 'key=value'
let mut iter = opt.trim().splitn(2, '=');
let key = iter.next().expect("failed to parse key");
let key0 = iter.next().expect("failed to parse key");
let value = iter.next().expect("failed to parse value");
if key == "LOG" {
return value;
if key == key0 {
return Some(value);
}
}
""
None
}
#[cfg(feature = "graphic")]

View File

@ -76,10 +76,7 @@ pub fn init_frame_allocator(boot_info: &BootInfo) {
}
#[cfg(target_arch = "riscv64")]
use kernel_hal_bare::BootInfo;
#[cfg(target_arch = "riscv64")]
pub fn init_frame_allocator(boot_info: &BootInfo) {
pub fn init_frame_allocator() {
use core::ops::Range;
let mut ba = FRAME_ALLOCATOR.lock();

View File

@ -496,12 +496,6 @@ impl VmAddressRegion {
self.flags
}
#[cfg(target_arch = "riscv64")]
/// Activate this page table
pub fn activate(&self) {
self.page_table.lock().activate();
}
/// Dump all mappings recursively.
pub fn dump(&self) {
let mut guard = self.inner.lock();