This commit is contained in:
2021-09-03 15:48:32 +03:00
parent 06f5aabdb0
commit 74eedfe540
15 changed files with 485 additions and 71 deletions
+70
View File
@@ -0,0 +1,70 @@
use crate::{
arch::{mmio_read, mmio_write},
dev::{irq::InterruptHandler, serial::SerialDevice, Device},
};
use address::PhysicalAddress;
pub struct AuxUart;
pub struct Aux;
impl Aux {
const REG_AUX_ENABLES: PhysicalAddress = PhysicalAddress::new(0x3F215004);
const AUX_ENABLES_MUART: u32 = 1 << 0;
pub unsafe fn enable_uart(&self) {
let tmp = mmio_read(Self::REG_AUX_ENABLES);
mmio_write(Self::REG_AUX_ENABLES, tmp | Self::AUX_ENABLES_MUART);
}
}
impl AuxUart {
const AUX_MU_BASE: PhysicalAddress = PhysicalAddress::new(0x3F215000);
const REG_AUX_MU_IO: PhysicalAddress = Self::AUX_MU_BASE.add(0x40);
const REG_AUX_MU_IER: PhysicalAddress = Self::AUX_MU_BASE.add(0x44);
const REG_AUX_MU_CNTL: PhysicalAddress = Self::AUX_MU_BASE.add(0x60);
const AUX_MU_CNTL_TE: u32 = 1 << 1;
const AUX_MU_CNTL_RE: u32 = 1 << 0;
const AUX_MU_IER_RIE: u32 = 1 << 0;
}
impl InterruptHandler for Aux {
fn do_irq(&self, _irq: u32) {}
}
impl Device for AuxUart {
fn name(&self) -> &'static str {
"BCM283x Mini-UART"
}
unsafe fn enable(&self) {
AUX.enable_uart();
mmio_write(Self::REG_AUX_MU_IER, Self::AUX_MU_IER_RIE);
mmio_write(
Self::REG_AUX_MU_CNTL,
Self::AUX_MU_CNTL_TE | Self::AUX_MU_CNTL_RE,
);
}
unsafe fn disable(&self) {}
}
impl SerialDevice for AuxUart {
fn send(&self, ch: u8) {
unsafe {
mmio_write(Self::REG_AUX_MU_IO, ch as u32);
}
}
}
impl InterruptHandler for AuxUart {
fn do_irq(&self, _irq: u32) {
let byte = unsafe { mmio_read(Self::REG_AUX_MU_IO) } as u8;
debugln!("{}", byte as char);
}
}
pub static AUX: Aux = Aux;
pub static UART: AuxUart = AuxUart;
+138
View File
@@ -0,0 +1,138 @@
use crate::{
arch::{cpu, mmio_read, mmio_write},
dev::{irq::InterruptController, Device},
};
use address::PhysicalAddress;
pub struct Qa7Intc;
pub struct Bcm2837Intc;
pub struct Intc {
qa7_intc: Qa7Intc,
bcm2837_intc: Bcm2837Intc,
}
impl Bcm2837Intc {
const REG_PENDING_IRQ1: PhysicalAddress = PhysicalAddress::new(0x3F00B204);
const REG_PENDING_IRQ2: PhysicalAddress = PhysicalAddress::new(0x3F00B208);
const REG_ENABLE_IRQ1: PhysicalAddress = PhysicalAddress::new(0x3F00B210);
const REG_ENABLE_IRQ2: PhysicalAddress = PhysicalAddress::new(0x3F00B214);
}
impl Qa7Intc {
const REG_TIMER_INTC: PhysicalAddress = PhysicalAddress::new(0x40000040);
const REG_INT_SRC: PhysicalAddress = PhysicalAddress::new(0x40000060);
const INTC_CNTPNSIRQ_IRQ: u32 = 1 << 1;
}
impl Device for Intc {
fn name(&self) -> &'static str {
"BCM283x Interrupt Controller"
}
unsafe fn enable(&self) {}
unsafe fn disable(&self) {}
}
impl Device for Qa7Intc {
fn name(&self) -> &'static str {
"Broadcom QA7 Interrupt Controller"
}
unsafe fn enable(&self) {}
unsafe fn disable(&self) {}
}
impl Device for Bcm2837Intc {
fn name(&self) -> &'static str {
"BCM2837 Interrupt Controller"
}
unsafe fn enable(&self) {}
unsafe fn disable(&self) {}
}
impl InterruptController for Qa7Intc {
unsafe fn enable_irq(&self, irq: u32) {
match irq {
super::IRQ_LOCAL_TIMER => {
let phys_core_id = cpu::get_phys_id();
let tmp = mmio_read(Self::REG_TIMER_INTC + 4 * phys_core_id);
mmio_write(
Self::REG_TIMER_INTC + 4 * phys_core_id,
tmp | Self::INTC_CNTPNSIRQ_IRQ,
);
}
_ => panic!("Unhandled IRQ number: {}", irq),
}
}
unsafe fn disable_irq(&self, _irq: u32) {
todo!();
}
fn is_irq_pending(&self, irq: u32) -> bool {
unsafe { mmio_read(Self::REG_INT_SRC) & (1 << irq) != 0 }
}
unsafe fn clear_irq(&self, _irq: u32) {}
}
impl InterruptController for Bcm2837Intc {
unsafe fn enable_irq(&self, irq: u32) {
if irq < 32 {
mmio_write(Self::REG_ENABLE_IRQ1, 1 << irq);
} else if irq < 64 {
mmio_write(Self::REG_ENABLE_IRQ2, 1 << (irq - 32));
}
}
unsafe fn disable_irq(&self, _irq: u32) {
todo!();
}
fn is_irq_pending(&self, irq: u32) -> bool {
if irq < 32 {
unsafe { mmio_read(Self::REG_PENDING_IRQ1) & (1 << irq) != 0 }
} else if irq < 64 {
unsafe { mmio_read(Self::REG_PENDING_IRQ2) & (1 << (irq - 32)) != 0 }
} else {
false
}
}
unsafe fn clear_irq(&self, _irq: u32) {
todo!();
}
}
impl InterruptController for Intc {
unsafe fn enable_irq(&self, irq: u32) {
if irq < 16 {
self.qa7_intc.enable_irq(irq);
} else {
self.bcm2837_intc.enable_irq(irq - 16);
}
}
unsafe fn disable_irq(&self, _irq: u32) {
todo!();
}
fn is_irq_pending(&self, irq: u32) -> bool {
if irq < 16 {
self.qa7_intc.is_irq_pending(irq)
} else {
self.bcm2837_intc.is_irq_pending(irq - 16)
}
}
unsafe fn clear_irq(&self, _irq: u32) {}
}
pub static INTC: Intc = Intc {
qa7_intc: Qa7Intc,
bcm2837_intc: Bcm2837Intc,
};
+17 -44
View File
@@ -1,52 +1,23 @@
use crate::mem::phys::{init_from_iter, SimpleMemoryIterator, UsableMemory};
use address::PhysicalAddress;
pub mod aux;
pub mod intc;
pub mod mbox;
pub mod smp;
pub mod timer;
use crate::{
arch::{cpu, mmio_read, mmio_write},
dev::irq::InterruptController,
mem::phys::{init_from_iter, SimpleMemoryIterator, UsableMemory},
};
use address::PhysicalAddress;
pub struct Intc;
impl Intc {
const REG_TIMER_INTC: PhysicalAddress = PhysicalAddress::new(0x40000040);
const REG_INT_SRC: PhysicalAddress = PhysicalAddress::new(0x40000060);
const INTC_CNTPNSIRQ_IRQ: u32 = 1 << 1;
}
impl InterruptController for Intc {
unsafe fn init(&self) {}
unsafe fn enable_irq(&self, irq: u32) {
match irq {
IRQ_LOCAL_TIMER => {
let phys_core_id = cpu::get_phys_id();
let tmp = mmio_read(Self::REG_TIMER_INTC + 4 * phys_core_id);
mmio_write(Self::REG_TIMER_INTC + 4 * phys_core_id, tmp | Self::INTC_CNTPNSIRQ_IRQ);
}
_ => panic!("Unhandled IRQ number: {}", irq),
}
}
unsafe fn disable_irq(&self, _irq: u32) {
todo!();
}
fn is_irq_pending(&self, irq: u32) -> bool {
unsafe { mmio_read(Self::REG_INT_SRC) & (1 << irq) != 0 }
}
unsafe fn clear_irq(&self, _irq: u32) {
}
}
pub static INTC: Intc = Intc;
pub const IRQ_LOCAL_TIMER: u32 = 1;
pub const IRQ_AUX: u32 = 16 + 29;
// TODO as long as AUX is not used for anything else?
pub const IRQ_UART: u32 = IRQ_AUX;
pub use aux::UART as AUX_UART;
pub use intc::INTC;
// Configured as primary UART
pub use AUX_UART as UART;
// pub const INT_SRC_TIMER: u32 = 1 << 11;
// pub const INT_SRC_MBOX0: u32 = 1 << 4;
@@ -61,3 +32,5 @@ pub fn init_phys_memory() {
init_from_iter(iter);
}
}
pub fn init() {}
+13
View File
@@ -1,8 +1,21 @@
use crate::arch;
pub mod timer;
use address::PhysicalAddress;
pub const IRQ_LOCAL_TIMER: u32 = 30;
pub const IRQ_UART: u32 = 32 + 1;
pub const IRQ_RTC: u32 = 32 + 2;
pub const GICD_BASE: PhysicalAddress = PhysicalAddress::new(0x08000000usize);
pub const GICC_BASE: PhysicalAddress = PhysicalAddress::new(0x08010000usize);
pub const PL031_BASE: PhysicalAddress = PhysicalAddress::new(0x09010000usize);
pub const PL011_BASE: PhysicalAddress = PhysicalAddress::new(0x09000000usize);
pub fn init() {
unsafe {
arch::timer::enable_rtc();
}
}
+40 -3
View File
@@ -1,24 +1,61 @@
use crate::{
arch::{intrin, machine},
dev::irq::{self, InterruptController, InterruptHandler},
dev::{
irq::{self, InterruptController, InterruptHandler},
Device,
},
};
struct ArmTimer;
impl Device for ArmTimer {
fn name(&self) -> &'static str {
"ARM Generic Timer"
}
unsafe fn enable(&self) {
intrin::write_cntp_ctl_el0(1);
}
unsafe fn disable(&self) {
intrin::write_cntp_ctl_el0(0);
}
}
impl InterruptHandler for ArmTimer {
fn do_irq(&self, _irq: u32) {
debugln!("T");
unsafe {
intrin::write_cntp_tval_el0(100000);
intrin::write_cntp_tval_el0(10000000);
}
}
}
pub unsafe fn enable_local_timer() {
LOCAL_TIMER.enable();
let intc = irq::get_intc();
irq::set_irq_handler(machine::IRQ_LOCAL_TIMER, &LOCAL_TIMER);
intc.enable_irq(machine::IRQ_LOCAL_TIMER);
}
intrin::write_cntp_ctl_el0(1);
// TODO bcm283x RTC?
cfg_if! {
if #[cfg(feature = "mach_virt")] {
use crate::dev::pl031::Pl031;
static PL031: Pl031 = Pl031::new(machine::PL031_BASE);
use PL031 as RTC;
pub unsafe fn enable_rtc() {
RTC.enable();
let intc = irq::get_intc();
irq::set_irq_handler(machine::IRQ_RTC, &RTC);
intc.enable_irq(machine::IRQ_RTC);
}
}
}
static LOCAL_TIMER: ArmTimer = ArmTimer;
+2 -11
View File
@@ -1,5 +1,4 @@
use crate::arch::mmio_write;
use address::PhysicalAddress;
use crate::dev::serial::{SerialDevice, SERIAL0};
use core::fmt;
use spin::Mutex;
@@ -7,15 +6,7 @@ struct Debug;
impl Debug {
fn putc(&mut self, ch: u8) {
unsafe {
cfg_if! {
if #[cfg(feature = "mach_rpi3b")] {
mmio_write(PhysicalAddress::new(0x3F215040), ch as u32);
} else if #[cfg(feature = "mach_virt")] {
mmio_write(PhysicalAddress::new(0x09000000), ch as u32);
}
}
}
SERIAL0.send(ch);
}
}
+3 -4
View File
@@ -1,3 +1,4 @@
use crate::dev::Device;
use alloc::collections::LinkedList;
#[repr(C)]
@@ -28,9 +29,7 @@ pub struct IrqRegisters {
far: usize,
}
pub trait InterruptController {
unsafe fn init(&self);
pub trait InterruptController: Device {
unsafe fn enable_irq(&self, irq: u32);
unsafe fn disable_irq(&self, irq: u32);
@@ -91,5 +90,5 @@ cfg_if! {
}
pub unsafe fn init() {
get_intc().init();
get_intc().enable();
}
+13 -3
View File
@@ -1,6 +1,6 @@
use crate::{
arch::{mmio_read, mmio_write},
dev::irq::InterruptController,
dev::{irq::InterruptController, Device},
};
use address::PhysicalAddress;
@@ -9,13 +9,23 @@ pub struct Gic {
gicc_base: PhysicalAddress,
}
impl InterruptController for Gic {
unsafe fn init(&self) {
impl Device for Gic {
fn name(&self) -> &'static str {
"ARM Generic Interrupt Controller"
}
unsafe fn enable(&self) {
mmio_write(self.gicd_base + Self::GICD_CTLR, Self::GICD_CTLR_ENABLE);
mmio_write(self.gicc_base + Self::GICC_CTLR, Self::GICC_CTLR_ENABLE);
mmio_write(self.gicc_base + Self::GICC_PMR, 0xFF);
}
unsafe fn disable(&self) {
todo!()
}
}
impl InterruptController for Gic {
unsafe fn enable_irq(&self, irq: u32) {
self.set_irq_config(irq, 1);
self.unmask_irq(irq);
+10
View File
@@ -1 +1,11 @@
pub mod irq;
pub mod serial;
pub mod pl011;
pub mod pl031;
pub trait Device {
fn name(&self) -> &'static str;
unsafe fn enable(&self);
unsafe fn disable(&self);
}
+78
View File
@@ -0,0 +1,78 @@
use crate::{
arch::{mmio_read, mmio_write},
dev::{irq::InterruptHandler, serial::SerialDevice, Device},
};
use address::PhysicalAddress;
pub struct Pl011 {
base: PhysicalAddress,
}
impl InterruptHandler for Pl011 {
fn do_irq(&self, _irq: u32) {
let tmp = unsafe { mmio_read(self.base + Self::UARTRIS) };
if tmp & Self::UARTRIS_RXRIS != 0 {
let ch = unsafe { mmio_read(self.base + Self::UARTDR) } as u8;
debugln!("{}", ch as char);
unsafe {
mmio_write(self.base + Self::UARTICR, Self::UARTICR_RXIC);
}
}
}
}
impl Device for Pl011 {
fn name(&self) -> &'static str {
"PL011 UART"
}
unsafe fn enable(&self) {
mmio_write(self.base + Self::UARTCR, 0);
mmio_write(self.base + Self::UARTCLR_H, 3 << 5);
mmio_write(
self.base + Self::UARTIMSC,
Self::UARTIMSC_RXIM,
);
mmio_write(
self.base + Self::UARTCR,
Self::UARTCR_TXE | Self::UARTCR_RXE | Self::UARTCR_UARTEN,
);
}
unsafe fn disable(&self) {}
}
impl SerialDevice for Pl011 {
fn send(&self, ch: u8) {
unsafe {
while mmio_read(self.base + Self::UARTFR) & Self::UARTFR_BUSY != 0 {}
mmio_write(self.base + Self::UARTDR, ch as u32);
}
}
}
impl Pl011 {
const UARTDR: usize = 0x00;
const UARTFR: usize = 0x18;
const UARTCLR_H: usize = 0x2C;
const UARTCR: usize = 0x30;
const UARTIMSC: usize = 0x38;
const UARTRIS: usize = 0x3C;
const UARTICR: usize = 0x44;
const UARTCR_UARTEN: u32 = 1 << 0;
const UARTCR_TXE: u32 = 1 << 8;
const UARTCR_RXE: u32 = 1 << 9;
const UARTFR_BUSY: u32 = 1 << 3;
const UARTIMSC_RXIM: u32 = 1 << 4;
const UARTRIS_RXRIS: u32 = 1 << 4;
const UARTICR_RXIC: u32 = 1 << 4;
pub const fn new(base: PhysicalAddress) -> Self {
Self { base }
}
}
+47
View File
@@ -0,0 +1,47 @@
use crate::{
arch::{mmio_read, mmio_write},
dev::{irq::InterruptHandler, Device},
};
use address::PhysicalAddress;
pub struct Pl031 {
base: PhysicalAddress,
}
impl Pl031 {
const RTCDR: usize = 0x00;
const RTCMR: usize = 0x04;
const RTCCR: usize = 0x0C;
const RTCIMSC: usize = 0x10;
const RTCICR: usize = 0x1C;
pub const fn new(base: PhysicalAddress) -> Self {
Self { base }
}
}
impl Device for Pl031 {
fn name(&self) -> &'static str {
"ARM PL031 RTC"
}
unsafe fn enable(&self) {
let tmp = mmio_read(self.base + Self::RTCDR);
mmio_write(self.base + Self::RTCMR, tmp + 1);
mmio_write(self.base + Self::RTCIMSC, 1);
mmio_write(self.base + Self::RTCCR, 1);
}
unsafe fn disable(&self) {}
}
impl InterruptHandler for Pl031 {
fn do_irq(&self, _irq: u32) {
let time_int = unsafe { mmio_read(self.base + Self::RTCDR) };
unsafe {
mmio_write(self.base + Self::RTCICR, 1);
mmio_write(self.base + Self::RTCMR, time_int + 1);
}
}
}
+23
View File
@@ -0,0 +1,23 @@
use crate::dev::Device;
pub trait SerialDevice: Device {
fn send(&self, ch: u8);
}
cfg_if! {
if #[cfg(feature = "mach_rpi3b")] {
use crate::arch::mach_bcm283x;
pub use mach_bcm283x::UART as SERIAL0;
} else {
use crate::{dev::pl011::Pl011, arch::machine};
pub static SERIAL0: Pl011 = Pl011::new(machine::PL011_BASE);
}
}
pub fn init() {
unsafe {
SERIAL0.enable();
}
}
+12 -2
View File
@@ -21,12 +21,13 @@ pub mod dev;
#[cfg(feature = "fdt-rs")]
pub mod fdt;
pub mod mem;
pub mod time;
pub use mem::KernelSpace;
use address::PhysicalAddress;
use arch::{cpu, intrin, smp, timer};
use dev::irq;
use arch::{timer, cpu, intrin, smp};
use dev::irq::{self, InterruptController};
pub fn entry_common() -> ! {
smp::init_ipi_delivery();
@@ -43,6 +44,7 @@ pub fn entry_common() -> ! {
#[no_mangle]
extern "C" fn kernel_bsp_main(fdt_base: PhysicalAddress) -> ! {
cpu::init(0);
dev::serial::init();
cfg_if! {
if #[cfg(feature = "fdt-rs")] {
@@ -55,6 +57,14 @@ extern "C" fn kernel_bsp_main(fdt_base: PhysicalAddress) -> ! {
}
}
mem::heap::init();
arch::machine::init();
// Enable IRQs for SERIAL0
let intc = irq::get_intc();
irq::set_irq_handler(arch::machine::IRQ_UART, &dev::serial::SERIAL0);
unsafe {
intc.enable_irq(arch::machine::IRQ_UART);
}
debug!("BSP init finished\n");
//smp::wakeup_ap_cpus();
+9
View File
@@ -0,0 +1,9 @@
#[derive(Debug)]
pub struct Time {
pub year: u32,
pub mday: u8,
pub mon: u8,
pub hour: u8,
pub min: u8,
pub sec: u8
}
+10 -4
View File
@@ -6,10 +6,15 @@ if [ -z "${MACH}" ]; then
MACH=rpi3b
fi
if [ -z "$QEMU_BIN" ]; then
QEMU_BIN=qemu-system-aarch64
fi
ARCH=aarch64-unknown-none-${MACH}
KERNEL=target/${ARCH}/debug/kernel
QEMU_OPTS=""
QEMU_OPTS="-chardev stdio,nowait,id=char0,mux=on \
-mon chardev=char0"
if [ "$QEMU_DINT" = 1 ]; then
QEMU_OPTS="$QEMU_OPTS -d int"
@@ -19,22 +24,23 @@ case ${MACH} in
rpi3b)
QEMU_OPTS="$QEMU_OPTS \
-serial null \
-serial stdio \
-serial chardev:char0 \
-dtb bcm2837-rpi-3-b.dtb \
-M raspi3b"
;;
virt)
KERNEL=target/${ARCH}/debug/kernel.bin
QEMU_OPTS="$QEMU_OPTS \
-serial stdio \
-serial chardev:char0 \
-M virt,virtualization=on \
-cpu cortex-a57 \
-m 256"
esac
QEMU_OPTS="$QEMU_OPTS \
-kernel ${KERNEL} \
-display none \
-s"
./build.sh
qemu-system-aarch64 ${QEMU_OPTS}
${QEMU_BIN} ${QEMU_OPTS}