1
0
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:
Jiajie Chen 2020-06-22 22:51:32 +08:00
parent a56e2b54e0
commit 55de8e6dcf
15 changed files with 227 additions and 154 deletions

51
kernel/spec.md Normal file
View File

@ -0,0 +1,51 @@
# 代码结构
## 驱动
按照分类放到 `src/drivers` 目录下。
如果是有 device tree 或者 pci 的平台,应当从对应的 bus 中初始化并传递参数。
如果是全局唯一并且代码不会复用的情况,可以写成 singleton。
## ISA 相关代码结构
路径:`src/arch/ISA`。其余的代码尽量不要出现平台相关的代码。
### consts.rs
- KERNEL_OFFSET 线性映射的偏移
- ARCHISA 的名称
### 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():初始化

View File

@ -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);
}

View File

@ -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

View File

@ -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();
}

View File

@ -1,6 +1,5 @@
//! ARM64 drivers
pub use self::board::serial;
use super::board;
/// Initialize ARM64 common drivers

View File

@ -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;

View File

@ -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!(),

View File

@ -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) {

View File

@ -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")]

View File

@ -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);

View 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);
}

View File

@ -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

View 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);
}

View File

@ -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")]

View File

@ -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
);
}