mirror of
https://github.com/rcore-os/rCore.git
synced 2025-01-18 17:07:04 +04:00
Move raspi drivers out of arch, fix aarch64 trap handling and add spec.md
This commit is contained in:
parent
a56e2b54e0
commit
55de8e6dcf
51
kernel/spec.md
Normal file
51
kernel/spec.md
Normal file
@ -0,0 +1,51 @@
|
||||
# 代码结构
|
||||
|
||||
## 驱动
|
||||
|
||||
按照分类放到 `src/drivers` 目录下。
|
||||
|
||||
如果是有 device tree 或者 pci 的平台,应当从对应的 bus 中初始化并传递参数。
|
||||
|
||||
如果是全局唯一并且代码不会复用的情况,可以写成 singleton。
|
||||
|
||||
## ISA 相关代码结构
|
||||
|
||||
路径:`src/arch/ISA`。其余的代码尽量不要出现平台相关的代码。
|
||||
|
||||
### consts.rs
|
||||
|
||||
- KERNEL_OFFSET: 线性映射的偏移
|
||||
- ARCH:ISA 的名称
|
||||
|
||||
### cpu
|
||||
|
||||
- fn id():当前正在运行的 CPU 的 ID
|
||||
|
||||
### timer
|
||||
|
||||
- fn timer_now():当前的时间
|
||||
|
||||
### interrupt
|
||||
|
||||
- fn ack(trap: usize):确认中断处理
|
||||
- fn timer():处理时钟中断
|
||||
|
||||
### interrupt/consts
|
||||
|
||||
- fn is_page_fault(trap: usize):是否缺页
|
||||
- IrqMin:中断的最小 trap
|
||||
- IrqMax:中断的最大 trap
|
||||
- Syscall:系统调用的 trap
|
||||
- Timer:时钟中断的 trap
|
||||
|
||||
### syscall
|
||||
|
||||
含有所有 syscall 的编号的定义
|
||||
|
||||
### board/xxx
|
||||
|
||||
针对该架构下某个平台的相关代码
|
||||
|
||||
- fn early_init():早期初始化串口等
|
||||
- fn early_final():结束早期初始化串口
|
||||
- fn init():初始化
|
@ -1,26 +0,0 @@
|
||||
use bcm2837::interrupt::Controller;
|
||||
use spin::RwLock;
|
||||
use trapframe::TrapFrame;
|
||||
|
||||
pub use bcm2837::interrupt::Interrupt;
|
||||
|
||||
lazy_static! {
|
||||
static ref IRQ_HANDLERS: RwLock<[Option<fn()>; 64]> = RwLock::new([None; 64]);
|
||||
}
|
||||
|
||||
pub fn is_timer_irq() -> bool {
|
||||
super::timer::is_pending()
|
||||
}
|
||||
|
||||
pub fn handle_irq(_tf: &mut TrapFrame) {
|
||||
for int in Controller::new().pending_interrupts() {
|
||||
if let Some(handler) = IRQ_HANDLERS.read()[int] {
|
||||
handler();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_irq(int: Interrupt, handler: fn()) {
|
||||
IRQ_HANDLERS.write()[int as usize] = Some(handler);
|
||||
Controller::new().enable(int);
|
||||
}
|
@ -2,9 +2,7 @@
|
||||
|
||||
use bcm2837::{addr::bus_to_phys, atags::Atags};
|
||||
|
||||
pub mod irq;
|
||||
pub mod mailbox;
|
||||
pub mod serial;
|
||||
pub mod timer;
|
||||
|
||||
use crate::drivers::gpu::fb::{self, ColorDepth, ColorFormat, FramebufferInfo, FramebufferResult};
|
||||
@ -21,7 +19,7 @@ pub static CPU_SPIN_TABLE: [usize; CPU_NUM] = [0xd8, 0xe0, 0xe8, 0xf0];
|
||||
|
||||
/// Initialize serial port before other initializations.
|
||||
pub fn init_serial_early() {
|
||||
serial::init();
|
||||
crate::drivers::serial::bcm2837::driver_init();
|
||||
}
|
||||
|
||||
/// Initialize raspi3 drivers
|
||||
|
@ -1,87 +0,0 @@
|
||||
use crate::sync::SpinNoIrqLock as Mutex;
|
||||
use bcm2837::mini_uart::{MiniUart, MiniUartInterruptId};
|
||||
use core::fmt;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
/// Struct to get a global SerialPort interface
|
||||
pub struct SerialPort {
|
||||
mu: MiniUart,
|
||||
}
|
||||
|
||||
pub trait SerialRead {
|
||||
fn receive(&mut self) -> u8;
|
||||
}
|
||||
|
||||
impl SerialPort {
|
||||
/// Creates a new instance of `SerialPort`.
|
||||
fn new() -> SerialPort {
|
||||
SerialPort {
|
||||
mu: MiniUart::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Init a newly created SerialPort, can only be called once.
|
||||
fn init(&mut self) {
|
||||
self.mu.init();
|
||||
super::irq::register_irq(super::irq::Interrupt::Aux, handle_serial_irq);
|
||||
}
|
||||
|
||||
/// Writes the byte `byte` to the UART device.
|
||||
fn write_byte(&mut self, byte: u8) {
|
||||
self.mu.write_byte(byte)
|
||||
}
|
||||
|
||||
/// Reads a byte from the UART device, blocking until a byte is available.
|
||||
fn read_byte(&self) -> u8 {
|
||||
self.mu.read_byte()
|
||||
}
|
||||
|
||||
// Whether the interrupt `id` is pending.
|
||||
fn interrupt_is_pending(&self, id: MiniUartInterruptId) -> bool {
|
||||
self.mu.interrupt_is_pending(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl SerialRead for SerialPort {
|
||||
fn receive(&mut self) -> u8 {
|
||||
self.read_byte()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Write for SerialPort {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
for byte in s.bytes() {
|
||||
match byte {
|
||||
// Backspace
|
||||
b'\x7f' => {
|
||||
self.write_byte(b'\x08');
|
||||
self.write_byte(b' ');
|
||||
self.write_byte(b'\x08');
|
||||
}
|
||||
// Return
|
||||
b'\n' => {
|
||||
self.write_byte(b'\r');
|
||||
self.write_byte(b'\n');
|
||||
}
|
||||
// Others
|
||||
_ => self.write_byte(byte),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_serial_irq() {
|
||||
let serial = SERIAL_PORT.lock();
|
||||
if serial.interrupt_is_pending(MiniUartInterruptId::Recive) {
|
||||
crate::trap::serial(serial.read_byte() as u8)
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref SERIAL_PORT: Mutex<SerialPort> = Mutex::new(SerialPort::new());
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
SERIAL_PORT.lock().init();
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
//! ARM64 drivers
|
||||
|
||||
pub use self::board::serial;
|
||||
use super::board;
|
||||
|
||||
/// Initialize ARM64 common drivers
|
||||
|
@ -1,11 +1,13 @@
|
||||
use super::syndrome::{Fault, Syndrome};
|
||||
use aarch64::regs::*;
|
||||
|
||||
pub fn is_page_fault(trap: usize) -> bool {
|
||||
// 2: from lower el, sync error
|
||||
if (trap >> 32) != 0x2 {
|
||||
if trap != 0x2 {
|
||||
return false;
|
||||
}
|
||||
let syndrome = Syndrome::from(trap as u32);
|
||||
let esr = ESR_EL1.get() as u32;
|
||||
let syndrome = Syndrome::from(esr);
|
||||
match syndrome {
|
||||
Syndrome::DataAbort { kind, level: _ } | Syndrome::InstructionAbort { kind, level: _ } => {
|
||||
match kind {
|
||||
@ -18,8 +20,9 @@ pub fn is_page_fault(trap: usize) -> bool {
|
||||
}
|
||||
|
||||
// from el0, irq
|
||||
pub const IrqMax: usize = 0x10002_00000000;
|
||||
pub const IrqMin: usize = 0x10002_00000000;
|
||||
pub const Timer: usize = 0x10002_00000000;
|
||||
pub const IrqMax: usize = 0x10002;
|
||||
pub const IrqMin: usize = 0x10002;
|
||||
pub const Timer: usize = 0x10002;
|
||||
|
||||
pub const Syscall: usize = 0b010001_000000;
|
||||
// from el0, sync
|
||||
pub const Syscall: usize = 0x00002;
|
||||
|
@ -1,11 +1,11 @@
|
||||
//! Trap handler
|
||||
|
||||
use super::syndrome::{Fault, Syndrome};
|
||||
use crate::arch::board::irq::{handle_irq, is_timer_irq};
|
||||
use trapframe::TrapFrame;
|
||||
|
||||
use crate::arch::board::timer;
|
||||
use crate::drivers::IRQ_MANAGER;
|
||||
use aarch64::regs::*;
|
||||
use log::*;
|
||||
use trapframe::TrapFrame;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
pub enum Kind {
|
||||
@ -90,10 +90,10 @@ pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
|
||||
}
|
||||
}
|
||||
Kind::Irq => {
|
||||
if is_timer_irq() {
|
||||
if timer::is_pending() {
|
||||
handle_timer()
|
||||
} else {
|
||||
handle_irq(tf)
|
||||
IRQ_MANAGER.read().try_handle_interrupt(Some(tf.trap_num));
|
||||
}
|
||||
}
|
||||
_ => panic!(),
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Interrupt and exception for aarch64.
|
||||
|
||||
pub use self::handler::*;
|
||||
use crate::arch::board::irq::is_timer_irq;
|
||||
use crate::arch::board::timer::is_pending;
|
||||
use aarch64::regs::*;
|
||||
use trapframe::UserContext;
|
||||
|
||||
@ -41,7 +41,7 @@ pub unsafe fn restore(flags: usize) {
|
||||
}
|
||||
|
||||
pub fn timer() {
|
||||
if is_timer_irq() {
|
||||
if is_pending() {
|
||||
crate::arch::board::timer::set_next();
|
||||
crate::trap::timer();
|
||||
}
|
||||
@ -52,9 +52,7 @@ pub fn ack(_irq: usize) {
|
||||
}
|
||||
|
||||
pub fn get_trap_num(cx: &UserContext) -> usize {
|
||||
// low 32bits: esr
|
||||
// high 32bits: trap_num
|
||||
(cx.trap_num << 32) | ESR_EL1.get() as usize
|
||||
cx.trap_num
|
||||
}
|
||||
|
||||
pub fn enable_irq(irq: usize) {
|
||||
|
@ -1,16 +1,15 @@
|
||||
//! Input/output for aarch64.
|
||||
|
||||
use super::driver::serial::*;
|
||||
use crate::drivers::SERIAL_DRIVERS;
|
||||
use core::fmt::{Arguments, Write};
|
||||
|
||||
pub fn getchar() -> char {
|
||||
unsafe { SERIAL_PORT.force_unlock() }
|
||||
SERIAL_PORT.lock().receive() as char
|
||||
}
|
||||
|
||||
pub fn putfmt(fmt: Arguments) {
|
||||
unsafe { SERIAL_PORT.force_unlock() }
|
||||
SERIAL_PORT.lock().write_fmt(fmt).unwrap();
|
||||
{
|
||||
let mut drivers = SERIAL_DRIVERS.write();
|
||||
if let Some(serial) = drivers.first_mut() {
|
||||
serial.write(format!("{}", fmt).as_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
// print to graphic
|
||||
#[cfg(feature = "consolegraphic")]
|
||||
|
@ -24,9 +24,6 @@ static AP_CAN_INIT: AtomicBool = AtomicBool::new(false);
|
||||
/// The entry point of kernel
|
||||
#[no_mangle] // don't mangle the name of this function
|
||||
pub extern "C" fn master_main() -> ! {
|
||||
board::init_serial_early();
|
||||
println!("Hello {}! from CPU {}", board::BOARD_NAME, cpu::id());
|
||||
|
||||
// start up other CPUs
|
||||
unsafe { cpu::start_others() };
|
||||
|
||||
@ -35,6 +32,10 @@ pub extern "C" fn master_main() -> ! {
|
||||
trapframe::init();
|
||||
}
|
||||
memory::init();
|
||||
|
||||
board::init_serial_early();
|
||||
println!("Hello {}! from CPU {}", board::BOARD_NAME, cpu::id());
|
||||
|
||||
crate::lkm::manager::ModuleManager::init();
|
||||
driver::init();
|
||||
println!("{}", LOGO);
|
||||
|
73
kernel/src/drivers/irq/bcm2837.rs
Normal file
73
kernel/src/drivers/irq/bcm2837.rs
Normal file
@ -0,0 +1,73 @@
|
||||
//! BCM2836 interrupt
|
||||
|
||||
use super::super::DRIVERS;
|
||||
use super::{super::IRQ_MANAGER, IntcDriver, IrqManager};
|
||||
use crate::drivers::{
|
||||
device_tree::DEVICE_TREE_INTC, device_tree::DEVICE_TREE_REGISTRY, DeviceType, Driver,
|
||||
};
|
||||
use crate::memory::phys_to_virt;
|
||||
use crate::{sync::SpinNoIrqLock as Mutex, util::read, util::write};
|
||||
use alloc::string::String;
|
||||
use alloc::sync::Arc;
|
||||
use bcm2837::interrupt::Controller;
|
||||
use bcm2837::interrupt::Interrupt;
|
||||
|
||||
pub struct Bcm2837Intc {
|
||||
manager: Mutex<IrqManager>,
|
||||
}
|
||||
|
||||
impl Driver for Bcm2837Intc {
|
||||
fn try_handle_interrupt(&self, irq: Option<usize>) -> bool {
|
||||
let mut res = false;
|
||||
let manager = self.manager.lock();
|
||||
for intr in Controller::new().pending_interrupts() {
|
||||
res |= manager.try_handle_interrupt(Some(intr as usize));
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn device_type(&self) -> DeviceType {
|
||||
DeviceType::Intc
|
||||
}
|
||||
|
||||
fn get_id(&self) -> String {
|
||||
format!("bcm2837_intc")
|
||||
}
|
||||
}
|
||||
|
||||
impl IntcDriver for Bcm2837Intc {
|
||||
/// Register interrupt controller local irq
|
||||
fn register_local_irq(&self, irq: usize, driver: Arc<dyn Driver>) {
|
||||
// enable irq
|
||||
use bcm2837::interrupt::Interrupt::*;
|
||||
let intr = match irq {
|
||||
_ if irq == Timer1 as usize => Timer1,
|
||||
_ if irq == Aux as usize => Aux,
|
||||
_ => todo!(),
|
||||
};
|
||||
Controller::new().enable(intr);
|
||||
let mut manager = self.manager.lock();
|
||||
manager.register_irq(irq, driver);
|
||||
}
|
||||
}
|
||||
|
||||
// singleton
|
||||
lazy_static! {
|
||||
pub static ref BCM2837_INTC: Arc<Bcm2837Intc> = init();
|
||||
}
|
||||
|
||||
fn init() -> Arc<Bcm2837Intc> {
|
||||
info!("Init bcm2837 interrupt controller");
|
||||
let intc = Arc::new(Bcm2837Intc {
|
||||
manager: Mutex::new(IrqManager::new(false)),
|
||||
});
|
||||
DRIVERS.write().push(intc.clone());
|
||||
// register under root irq manager
|
||||
// 0x10002: from lower el, irq
|
||||
IRQ_MANAGER.write().register_irq(0x10002, intc.clone());
|
||||
intc
|
||||
}
|
||||
|
||||
pub fn driver_init() {
|
||||
lazy_static::initialize(&BCM2837_INTC);
|
||||
}
|
@ -5,6 +5,8 @@ use alloc::collections::BTreeMap;
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
#[cfg(feature = "board_raspi3")]
|
||||
pub mod bcm2837;
|
||||
pub mod plic;
|
||||
|
||||
// Irq manager
|
||||
|
59
kernel/src/drivers/serial/bcm2837.rs
Normal file
59
kernel/src/drivers/serial/bcm2837.rs
Normal file
@ -0,0 +1,59 @@
|
||||
//! uart in bcm2837
|
||||
use super::super::irq::IntcDriver;
|
||||
use super::super::DRIVERS;
|
||||
use super::super::IRQ_MANAGER;
|
||||
use super::{super::SERIAL_DRIVERS, SerialDriver};
|
||||
use crate::drivers::irq::bcm2837::BCM2837_INTC;
|
||||
use crate::drivers::{DeviceType, Driver};
|
||||
use crate::sync::SpinNoIrqLock as Mutex;
|
||||
use alloc::string::String;
|
||||
use alloc::sync::Arc;
|
||||
use bcm2837::interrupt::Interrupt;
|
||||
use bcm2837::mini_uart::{MiniUart, MiniUartInterruptId};
|
||||
|
||||
struct Bcm2837Serial {
|
||||
mu: Mutex<MiniUart>,
|
||||
}
|
||||
|
||||
impl Driver for Bcm2837Serial {
|
||||
fn try_handle_interrupt(&self, irq: Option<usize>) -> bool {
|
||||
let mu = self.mu.lock();
|
||||
if mu.interrupt_is_pending(MiniUartInterruptId::Recive) {
|
||||
let c = self.read();
|
||||
crate::trap::serial(c);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn device_type(&self) -> DeviceType {
|
||||
DeviceType::Serial
|
||||
}
|
||||
|
||||
fn get_id(&self) -> String {
|
||||
format!("bcm2837_serial")
|
||||
}
|
||||
}
|
||||
|
||||
impl SerialDriver for Bcm2837Serial {
|
||||
fn read(&self) -> u8 {
|
||||
self.mu.lock().read_byte()
|
||||
}
|
||||
|
||||
fn write(&self, data: &[u8]) {
|
||||
let mut mu = self.mu.lock();
|
||||
for byte in data {
|
||||
mu.write_byte(*byte);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn driver_init() {
|
||||
let serial = Arc::new(Bcm2837Serial {
|
||||
mu: Mutex::new(MiniUart::new()),
|
||||
});
|
||||
DRIVERS.write().push(serial.clone());
|
||||
SERIAL_DRIVERS.write().push(serial.clone());
|
||||
BCM2837_INTC.register_local_irq(Interrupt::Aux as u8 as usize, serial);
|
||||
}
|
@ -3,6 +3,8 @@ use super::SERIAL_DRIVERS;
|
||||
use alloc::sync::Arc;
|
||||
use core::fmt::{Result, Write};
|
||||
|
||||
#[cfg(feature = "board_raspi3")]
|
||||
pub mod bcm2837;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub mod com;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
|
@ -451,15 +451,7 @@ pub fn spawn(thread: Arc<Thread>) {
|
||||
|
||||
let mut exit = false;
|
||||
match trap_num {
|
||||
Syscall => exit = handle_syscall(&thread, &mut cx).await,
|
||||
IrqMin..=IrqMax => {
|
||||
crate::arch::interrupt::ack(trap_num);
|
||||
trace!("handle irq {:#x}", trap_num);
|
||||
if trap_num == Timer {
|
||||
crate::arch::interrupt::timer();
|
||||
}
|
||||
IRQ_MANAGER.read().try_handle_interrupt(Some(trap_num));
|
||||
}
|
||||
// must be first
|
||||
_ if is_page_fault(trap_num) => {
|
||||
// page fault
|
||||
let addr = get_page_fault_addr();
|
||||
@ -470,9 +462,18 @@ pub fn spawn(thread: Arc<Thread>) {
|
||||
panic!("page fault handle failed");
|
||||
}
|
||||
}
|
||||
Syscall => exit = handle_syscall(&thread, &mut cx).await,
|
||||
IrqMin..=IrqMax => {
|
||||
crate::arch::interrupt::ack(trap_num);
|
||||
trace!("handle irq {:#x}", trap_num);
|
||||
if trap_num == Timer {
|
||||
crate::arch::interrupt::timer();
|
||||
}
|
||||
IRQ_MANAGER.read().try_handle_interrupt(Some(trap_num));
|
||||
}
|
||||
_ => {
|
||||
panic!(
|
||||
"unhandled trap in thread {} {} {:x?}",
|
||||
"unhandled trap in thread {} trap {:#x} {:x?}",
|
||||
thread.tid, trap_num, cx
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user