mirror of
https://github.com/rcore-os/rCore.git
synced 2024-11-22 08:06:17 +04:00
Merge remote-tracking branch 'equation314/arch-aarch64' into dev
# Conflicts: # kernel/src/arch/aarch64/memory.rs # kernel/src/arch/aarch64/paging.rs # kernel/src/process/context.rs
This commit is contained in:
commit
9b0b0064d0
@ -2,10 +2,11 @@
|
|||||||
name = "bcm2837"
|
name = "bcm2837"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["equation314 <equation618@gmail.com>"]
|
authors = ["equation314 <equation618@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
use_generic_timer = []
|
use_generic_timer = ["aarch64"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
volatile = "0.2.4"
|
volatile = "0.2.4"
|
||||||
cortex-a = "2.2.2"
|
aarch64= { git = "https://github.com/equation314/aarch64", optional = true }
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use IO_BASE;
|
use crate::IO_BASE;
|
||||||
use timer::delay;
|
use crate::timer::delay;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use volatile::{ReadOnly, Volatile, WriteOnly};
|
use volatile::{ReadOnly, Volatile, WriteOnly};
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
use IO_BASE;
|
use crate::IO_BASE;
|
||||||
use volatile::{ReadOnly, Volatile};
|
use volatile::{ReadOnly, Volatile};
|
||||||
|
|
||||||
const INT_BASE: usize = IO_BASE + 0xB000 + 0x200;
|
const INT_BASE: usize = IO_BASE + 0xB000 + 0x200;
|
||||||
|
|
||||||
/// Allowed interrupts (ref: peripherals 7.5, page 113)
|
/// Allowed interrupts (ref: peripherals 7.5, page 113)
|
||||||
|
#[repr(u8)]
|
||||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||||
pub enum Interrupt {
|
pub enum Interrupt {
|
||||||
Timer1 = 1,
|
Timer1 = 1,
|
||||||
@ -30,6 +31,24 @@ struct Registers {
|
|||||||
DisableBasicIRQ: Volatile<u32>,
|
DisableBasicIRQ: Volatile<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pending interrupts
|
||||||
|
pub struct PendingInterrupts(u64);
|
||||||
|
|
||||||
|
impl Iterator for PendingInterrupts {
|
||||||
|
type Item = usize;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let int = self.0.trailing_zeros();
|
||||||
|
if int < 64 {
|
||||||
|
self.0 &= !(1 << int);
|
||||||
|
Some(int as usize)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An interrupt controller. Used to enable and disable interrupts as well as to
|
/// An interrupt controller. Used to enable and disable interrupts as well as to
|
||||||
/// check if an interrupt is pending.
|
/// check if an interrupt is pending.
|
||||||
pub struct Controller {
|
pub struct Controller {
|
||||||
@ -38,6 +57,7 @@ pub struct Controller {
|
|||||||
|
|
||||||
impl Controller {
|
impl Controller {
|
||||||
/// Returns a new handle to the interrupt controller.
|
/// Returns a new handle to the interrupt controller.
|
||||||
|
#[inline]
|
||||||
pub fn new() -> Controller {
|
pub fn new() -> Controller {
|
||||||
Controller {
|
Controller {
|
||||||
registers: unsafe { &mut *(INT_BASE as *mut Registers) },
|
registers: unsafe { &mut *(INT_BASE as *mut Registers) },
|
||||||
@ -58,4 +78,11 @@ impl Controller {
|
|||||||
pub fn is_pending(&self, int: Interrupt) -> bool {
|
pub fn is_pending(&self, int: Interrupt) -> bool {
|
||||||
self.registers.IRQPending[int as usize / 32].read() & (1 << (int as usize) % 32) != 0
|
self.registers.IRQPending[int as usize / 32].read() & (1 << (int as usize) % 32) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return all pending interrupts.
|
||||||
|
pub fn pending_interrupts(&self) -> PendingInterrupts {
|
||||||
|
let irq1 = self.registers.IRQPending[0].read() as u64;
|
||||||
|
let irq2 = self.registers.IRQPending[1].read() as u64;
|
||||||
|
PendingInterrupts((irq2 << 32) | irq1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use IO_BASE;
|
use crate::IO_BASE;
|
||||||
use gpio::{Function, Gpio};
|
use crate::gpio::{Function, Gpio};
|
||||||
use volatile::{ReadOnly, Volatile};
|
use volatile::{ReadOnly, Volatile};
|
||||||
|
|
||||||
/// The base address for the `MU` registers.
|
/// The base address for the `MU` registers.
|
||||||
@ -8,6 +8,13 @@ const MU_REG_BASE: usize = IO_BASE + 0x215040;
|
|||||||
/// The `AUXENB` register from page 9 of the BCM2837 documentation.
|
/// The `AUXENB` register from page 9 of the BCM2837 documentation.
|
||||||
const AUX_ENABLES: *mut Volatile<u8> = (IO_BASE + 0x215004) as *mut Volatile<u8>;
|
const AUX_ENABLES: *mut Volatile<u8> = (IO_BASE + 0x215004) as *mut Volatile<u8>;
|
||||||
|
|
||||||
|
/// Enum representing bit fields of the `AUX_MU_IIR_REG` register.
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum MiniUartInterruptId {
|
||||||
|
Transmit = 0b010,
|
||||||
|
Recive = 0b100,
|
||||||
|
}
|
||||||
|
|
||||||
/// Enum representing bit fields of the `AUX_MU_LSR_REG` register.
|
/// Enum representing bit fields of the `AUX_MU_LSR_REG` register.
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
enum LsrStatus {
|
enum LsrStatus {
|
||||||
@ -15,7 +22,7 @@ enum LsrStatus {
|
|||||||
TxAvailable = 1 << 5,
|
TxAvailable = 1 << 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// MU registers starting from `AUX_ENABLES` (ref: peripherals 2.1, page 8)
|
/// MU registers starting from `MU_REG_BASE` (ref: peripherals 2.1, page 8)
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
struct Registers {
|
struct Registers {
|
||||||
@ -62,23 +69,25 @@ impl MiniUart {
|
|||||||
&mut *(MU_REG_BASE as *mut Registers)
|
&mut *(MU_REG_BASE as *mut Registers)
|
||||||
};
|
};
|
||||||
|
|
||||||
Gpio::new(14).into_alt(Function::Alt5).set_gpio_pd(0);
|
|
||||||
Gpio::new(15).into_alt(Function::Alt5).set_gpio_pd(0);
|
|
||||||
|
|
||||||
registers.AUX_MU_CNTL_REG.write(0); // Disable auto flow control and disable receiver and transmitter (for now)
|
|
||||||
registers.AUX_MU_IER_REG.write(0); // Disable receive and transmit interrupts
|
|
||||||
registers.AUX_MU_LCR_REG.write(3); // Enable 8 bit mode
|
|
||||||
registers.AUX_MU_MCR_REG.write(0); // Set RTS line to be always high
|
|
||||||
registers.AUX_MU_BAUD_REG.write(270); // Set baud rate to 115200
|
|
||||||
|
|
||||||
registers.AUX_MU_CNTL_REG.write(3); // Finally, enable transmitter and receiver
|
|
||||||
|
|
||||||
MiniUart {
|
MiniUart {
|
||||||
registers: registers,
|
registers: registers,
|
||||||
timeout: None,
|
timeout: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn init(&mut self) {
|
||||||
|
Gpio::new(14).into_alt(Function::Alt5).set_gpio_pd(0);
|
||||||
|
Gpio::new(15).into_alt(Function::Alt5).set_gpio_pd(0);
|
||||||
|
|
||||||
|
self.registers.AUX_MU_CNTL_REG.write(0); // Disable auto flow control and disable receiver and transmitter (for now)
|
||||||
|
self.registers.AUX_MU_IER_REG.write(1); // Enable receive interrupts and disable transmit interrupts
|
||||||
|
self.registers.AUX_MU_LCR_REG.write(3); // Enable 8 bit mode
|
||||||
|
self.registers.AUX_MU_MCR_REG.write(0); // Set RTS line to be always high
|
||||||
|
self.registers.AUX_MU_BAUD_REG.write(270); // Set baud rate to 115200
|
||||||
|
|
||||||
|
self.registers.AUX_MU_CNTL_REG.write(3); // Finally, enable transmitter and receiver
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the read timeout to `milliseconds` milliseconds.
|
/// Set the read timeout to `milliseconds` milliseconds.
|
||||||
pub fn set_read_timeout(&mut self, milliseconds: u32) {
|
pub fn set_read_timeout(&mut self, milliseconds: u32) {
|
||||||
self.timeout = Some(milliseconds)
|
self.timeout = Some(milliseconds)
|
||||||
@ -111,8 +120,13 @@ impl MiniUart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Reads a byte. Blocks indefinitely until a byte is ready to be read.
|
/// Reads a byte. Blocks indefinitely until a byte is ready to be read.
|
||||||
pub fn read_byte(&mut self) -> u8 {
|
pub fn read_byte(&self) -> u8 {
|
||||||
while !self.has_byte() {}
|
while !self.has_byte() {}
|
||||||
self.registers.AUX_MU_IO_REG.read()
|
self.registers.AUX_MU_IO_REG.read()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read `AUX_MU_IIR_REG` and determine if the interrupt `id` is pending.
|
||||||
|
pub fn interrupt_is_pending(&self, id: MiniUartInterruptId) -> bool {
|
||||||
|
self.registers.AUX_MU_IIR_REG.read() & 0b110 == id as u8
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
extern crate cortex_a;
|
extern crate aarch64;
|
||||||
|
|
||||||
use self::cortex_a::regs::*;
|
use aarch64::regs::*;
|
||||||
use volatile::*;
|
use volatile::*;
|
||||||
|
|
||||||
/// The base address for the ARM generic timer, IRQs, mailboxes
|
/// The base address for the ARM generic timer, IRQs, mailboxes
|
||||||
@ -58,7 +58,7 @@ impl Timer {
|
|||||||
/// Reads the generic timer's counter and returns the 64-bit counter value.
|
/// Reads the generic timer's counter and returns the 64-bit counter value.
|
||||||
/// The returned value is the number of elapsed microseconds.
|
/// The returned value is the number of elapsed microseconds.
|
||||||
pub fn read(&self) -> u64 {
|
pub fn read(&self) -> u64 {
|
||||||
let cntfrq = CNTFRQ_EL0.get();
|
let cntfrq = CNTFRQ_EL0.get(); // 62500000
|
||||||
(CNTPCT_EL0.get() * 1000000 / (cntfrq as u64)) as u64
|
(CNTPCT_EL0.get() * 1000000 / (cntfrq as u64)) as u64
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ impl Timer {
|
|||||||
/// interrupts for timer 1 are enabled and IRQs are unmasked, then a timer
|
/// interrupts for timer 1 are enabled and IRQs are unmasked, then a timer
|
||||||
/// interrupt will be issued in `us` microseconds.
|
/// interrupt will be issued in `us` microseconds.
|
||||||
pub fn tick_in(&mut self, us: u32) {
|
pub fn tick_in(&mut self, us: u32) {
|
||||||
let cntfrq = CNTFRQ_EL0.get();
|
let cntfrq = CNTFRQ_EL0.get(); // 62500000
|
||||||
CNTP_TVAL_EL0.set(((cntfrq as f64) * (us as f64) / 1000000.0) as u32);
|
CNTP_TVAL_EL0.set(((cntfrq as f64) * (us as f64) / 1000000.0) as u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use ::IO_BASE;
|
use crate::IO_BASE;
|
||||||
|
use crate::interrupt::{Controller, Interrupt};
|
||||||
use volatile::{ReadOnly, Volatile};
|
use volatile::{ReadOnly, Volatile};
|
||||||
use interrupt::{Controller, Interrupt};
|
|
||||||
|
|
||||||
/// The base address for the ARM system timer registers.
|
/// The base address for the ARM system timer registers.
|
||||||
const TIMER_REG_BASE: usize = IO_BASE + 0x3000;
|
const TIMER_REG_BASE: usize = IO_BASE + 0x3000;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#![cfg_attr(not(test), no_std)]
|
#![cfg_attr(not(test), no_std)]
|
||||||
#![feature(alloc)]
|
#![feature(alloc)]
|
||||||
#![feature(nll)]
|
#![feature(nll)]
|
||||||
#![feature(extern_crate_item_prelude)]
|
|
||||||
|
|
||||||
// import macros from log
|
// import macros from log
|
||||||
use log::*;
|
use log::*;
|
||||||
@ -14,4 +13,4 @@ pub mod memory_set;
|
|||||||
mod addr;
|
mod addr;
|
||||||
pub mod no_mmu;
|
pub mod no_mmu;
|
||||||
|
|
||||||
pub use crate::addr::*;
|
pub use crate::addr::*;
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
#![feature(vec_resize_default)]
|
#![feature(vec_resize_default)]
|
||||||
#![feature(asm)]
|
#![feature(asm)]
|
||||||
#![feature(exact_size_is_empty)]
|
#![feature(exact_size_is_empty)]
|
||||||
#![feature(extern_crate_item_prelude)]
|
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
|
15
kernel/Cargo.lock
generated
15
kernel/Cargo.lock
generated
@ -1,12 +1,10 @@
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "aarch64"
|
name = "aarch64"
|
||||||
version = "2.2.2"
|
version = "2.2.2"
|
||||||
source = "git+https://github.com/equation314/aarch64#47bf5439f5a1379f0fef6272853cf684207a4e45"
|
source = "git+https://github.com/equation314/aarch64#e3b60adb233ad34d05443e0b5ec34cac29253296"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"register 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"register 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -50,7 +48,7 @@ version = "0.1.0"
|
|||||||
name = "bcm2837"
|
name = "bcm2837"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cortex-a 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"aarch64 2.2.2 (git+https://github.com/equation314/aarch64)",
|
||||||
"volatile 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"volatile 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -98,14 +96,6 @@ name = "cfg-if"
|
|||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cortex-a"
|
|
||||||
version = "2.2.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"register 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fixedvec"
|
name = "fixedvec"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
@ -455,7 +445,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum bootloader 0.3.4 (git+https://github.com/wangrunji0408/bootloader)" = "<none>"
|
"checksum bootloader 0.3.4 (git+https://github.com/wangrunji0408/bootloader)" = "<none>"
|
||||||
"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
|
"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
|
||||||
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
|
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
|
||||||
"checksum cortex-a 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2b187d0d728b4a99ba1d79f9671b976bcdd71a8a2c719585218fd2dc14a4d08c"
|
|
||||||
"checksum fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6c16d316ccdac21a4dd648e314e76facbbaf316e83ca137d0857a9c07419d0"
|
"checksum fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6c16d316ccdac21a4dd648e314e76facbbaf316e83ca137d0857a9c07419d0"
|
||||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||||
|
@ -12,7 +12,8 @@ no_mmu = []
|
|||||||
# Kernel in M-mode (for riscv32)
|
# Kernel in M-mode (for riscv32)
|
||||||
m_mode = ["no_mmu"]
|
m_mode = ["no_mmu"]
|
||||||
# (for aarch64 RaspberryPi3)
|
# (for aarch64 RaspberryPi3)
|
||||||
board_raspi3 = []
|
board_raspi3 = ["bcm2837"]
|
||||||
|
raspi3_use_generic_timer = ["bcm2837/use_generic_timer"]
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
# MUST >= 1 : Enable RVO to avoid stack overflow
|
# MUST >= 1 : Enable RVO to avoid stack overflow
|
||||||
@ -53,7 +54,7 @@ bbl = { path = "../crate/bbl" }
|
|||||||
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
||||||
aarch64 = { git = "https://github.com/equation314/aarch64" }
|
aarch64 = { git = "https://github.com/equation314/aarch64" }
|
||||||
atags = { path = "../crate/atags" }
|
atags = { path = "../crate/atags" }
|
||||||
bcm2837 = { path = "../crate/bcm2837", features = ["use_generic_timer"] }
|
bcm2837 = { path = "../crate/bcm2837", optional = true }
|
||||||
|
|
||||||
[package.metadata.bootimage]
|
[package.metadata.bootimage]
|
||||||
default-target = "x86_64-blog_os.json"
|
default-target = "x86_64-blog_os.json"
|
||||||
|
@ -80,6 +80,15 @@ features += no_bbl
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(board), raspi3)
|
||||||
|
# qemu only has generic timer
|
||||||
|
# TODO: configure system/generic timer automatically
|
||||||
|
raspi3_timer ?= generic
|
||||||
|
ifeq ($(raspi3_timer), generic)
|
||||||
|
features += raspi3_use_generic_timer
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
ifdef m_mode
|
ifdef m_mode
|
||||||
features += no_mmu m_mode
|
features += no_mmu m_mode
|
||||||
bbl_m_mode := --enable-boot-machine
|
bbl_m_mode := --enable-boot-machine
|
||||||
|
@ -1,11 +1,28 @@
|
|||||||
use crate::arch::interrupt::TrapFrame;
|
use crate::arch::interrupt::TrapFrame;
|
||||||
use bcm2837::timer::Timer;
|
use bcm2837::interrupt::Controller;
|
||||||
use bcm2837::interrupt::{Controller, Interrupt};
|
use log::*;
|
||||||
|
|
||||||
pub fn handle_irq(tf: &mut TrapFrame) {
|
pub use bcm2837::interrupt::Interrupt;
|
||||||
let controller = Timer::new();
|
|
||||||
|
static IRQ_HANDLERS: &'static [Option<fn()>; 64] = &[None; 64];
|
||||||
|
|
||||||
|
pub fn handle_irq(_tf: &mut TrapFrame) {
|
||||||
|
let controller = bcm2837::timer::Timer::new();
|
||||||
if controller.is_pending() {
|
if controller.is_pending() {
|
||||||
super::timer::set_next();
|
super::timer::set_next();
|
||||||
crate::trap::timer();
|
crate::trap::timer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for int in Controller::new().pending_interrupts() {
|
||||||
|
if let Some(handler) = IRQ_HANDLERS[int] {
|
||||||
|
handler();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register_irq(int: Interrupt, handler: fn()) {
|
||||||
|
unsafe {
|
||||||
|
*(&IRQ_HANDLERS[int as usize] as *const _ as *mut Option<fn()>) = Some(handler);
|
||||||
|
}
|
||||||
|
Controller::new().enable(int);
|
||||||
}
|
}
|
||||||
|
@ -9,10 +9,16 @@ pub mod serial;
|
|||||||
pub const IO_REMAP_BASE: usize = bcm2837::IO_BASE;
|
pub const IO_REMAP_BASE: usize = bcm2837::IO_BASE;
|
||||||
pub const IO_REMAP_END: usize = 0x40001000;
|
pub const IO_REMAP_END: usize = 0x40001000;
|
||||||
|
|
||||||
pub fn init() {
|
/// Some initializations must be done before other initializations.
|
||||||
|
pub fn init_early() {
|
||||||
assert_has_not_been_called!("board::init must be called only once");
|
assert_has_not_been_called!("board::init must be called only once");
|
||||||
|
|
||||||
serial::SERIAL_PORT.lock().init();
|
serial::SERIAL_PORT.lock().init();
|
||||||
|
|
||||||
println!("Hello Raspberry Pi!");
|
println!("Hello Raspberry Pi!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Initialize raspi3 drivers
|
||||||
|
pub fn init_driver() {
|
||||||
|
timer::init();
|
||||||
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
use bcm2837::mini_uart::MiniUart;
|
use bcm2837::mini_uart::{MiniUart, MiniUartInterruptId};
|
||||||
|
use lazy_static::lazy_static;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
use once::*;
|
|
||||||
|
|
||||||
/// Struct to get a global SerialPort interface
|
/// Struct to get a global SerialPort interface
|
||||||
pub struct SerialPort {
|
pub struct SerialPort {
|
||||||
mu: Option<MiniUart>,
|
mu: MiniUart,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait SerialRead {
|
pub trait SerialRead {
|
||||||
@ -14,30 +14,31 @@ pub trait SerialRead {
|
|||||||
|
|
||||||
impl SerialPort {
|
impl SerialPort {
|
||||||
/// Creates a new instance of `SerialPort`.
|
/// Creates a new instance of `SerialPort`.
|
||||||
const fn new() -> SerialPort {
|
fn new() -> SerialPort {
|
||||||
SerialPort { mu: None }
|
SerialPort {
|
||||||
|
mu: MiniUart::new(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Init a newly created SerialPort, can only be called once.
|
/// Init a newly created SerialPort, can only be called once.
|
||||||
pub fn init(&mut self) {
|
pub fn init(&mut self) {
|
||||||
assert_has_not_been_called!("SerialPort::init must be called only once");
|
self.mu.init();
|
||||||
self.mu = Some(MiniUart::new());
|
super::irq::register_irq(super::irq::Interrupt::Aux, handle_serial_irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes the byte `byte` to the UART device.
|
/// Writes the byte `byte` to the UART device.
|
||||||
pub fn write_byte(&mut self, byte: u8) {
|
fn write_byte(&mut self, byte: u8) {
|
||||||
match &mut self.mu {
|
self.mu.write_byte(byte)
|
||||||
Some(mu) => mu.write_byte(byte),
|
|
||||||
None => panic!("SerialPort is not initialized"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads a byte from the UART device, blocking until a byte is available.
|
/// Reads a byte from the UART device, blocking until a byte is available.
|
||||||
pub fn read_byte(&mut self) -> u8 {
|
fn read_byte(&self) -> u8 {
|
||||||
match &mut self.mu {
|
self.mu.read_byte()
|
||||||
Some(mu) => return mu.read_byte(),
|
}
|
||||||
None => panic!("SerialPort is not initialized"),
|
|
||||||
}
|
// Whether the interrupt `id` is pending.
|
||||||
|
fn interrupt_is_pending(&self, id: MiniUartInterruptId) -> bool {
|
||||||
|
self.mu.interrupt_is_pending(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,4 +71,13 @@ impl fmt::Write for SerialPort {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static SERIAL_PORT: Mutex<SerialPort> = Mutex::new(SerialPort::new());
|
fn handle_serial_irq() {
|
||||||
|
let serial = SERIAL_PORT.lock();
|
||||||
|
if serial.interrupt_is_pending(MiniUartInterruptId::Recive) {
|
||||||
|
crate::trap::serial(serial.read_byte() as char)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static!{
|
||||||
|
pub static ref SERIAL_PORT: Mutex<SerialPort> = Mutex::new(SerialPort::new());
|
||||||
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use bcm2837::timer;
|
use bcm2837::timer;
|
||||||
use bcm2837::interrupt::{Controller, Interrupt};
|
|
||||||
use log::*;
|
use log::*;
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
|
12
kernel/src/arch/aarch64/driver/mod.rs
Normal file
12
kernel/src/arch/aarch64/driver/mod.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
/// ARM64 drivers
|
||||||
|
|
||||||
|
use once::*;
|
||||||
|
|
||||||
|
use super::board;
|
||||||
|
|
||||||
|
/// Initialize ARM64 common drivers
|
||||||
|
pub fn init() {
|
||||||
|
assert_has_not_been_called!();
|
||||||
|
|
||||||
|
board::init_driver();
|
||||||
|
}
|
@ -99,7 +99,7 @@ impl Context {
|
|||||||
/// Pop all callee-saved registers, then return to the target.
|
/// Pop all callee-saved registers, then return to the target.
|
||||||
#[naked]
|
#[naked]
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
unsafe extern fn __switch(self_stack: &mut usize, target_stack: &mut usize) {
|
unsafe extern fn __switch(_self_stack: &mut usize, _target_stack: &mut usize) {
|
||||||
asm!(
|
asm!(
|
||||||
"
|
"
|
||||||
mov x10, #-(12 * 8)
|
mov x10, #-(12 * 8)
|
||||||
@ -149,7 +149,7 @@ impl Context {
|
|||||||
tf: TrapFrame::new_kernel_thread(entry, arg, kstack_top),
|
tf: TrapFrame::new_kernel_thread(entry, arg, kstack_top),
|
||||||
}.push_at(kstack_top, ttbr)
|
}.push_at(kstack_top, ttbr)
|
||||||
}
|
}
|
||||||
pub unsafe fn new_user_thread(entry_addr: usize, ustack_top: usize, kstack_top: usize, is32: bool, ttbr: usize) -> Self {
|
pub unsafe fn new_user_thread(entry_addr: usize, ustack_top: usize, kstack_top: usize, _is32: bool, ttbr: usize) -> Self {
|
||||||
InitStack {
|
InitStack {
|
||||||
context: ContextData::new(),
|
context: ContextData::new(),
|
||||||
tf: TrapFrame::new_user_thread(entry_addr, ustack_top),
|
tf: TrapFrame::new_user_thread(entry_addr, ustack_top),
|
||||||
|
@ -93,8 +93,9 @@ fn handle_syscall(num: u16, tf: &mut TrapFrame) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_page_fault(tf: &mut TrapFrame) {
|
fn handle_page_fault(tf: &mut TrapFrame) {
|
||||||
let addr = FAR_EL1.get();
|
let addr = FAR_EL1.get() as usize;
|
||||||
error!("\nEXCEPTION: Page Fault @ {:#x}", addr);
|
if !crate::memory::page_fault_handler(addr) {
|
||||||
|
error!("\nEXCEPTION: Page Fault @ {:#x}", addr);
|
||||||
crate::trap::error(tf);
|
crate::trap::error(tf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! Serial driver for aarch64.
|
//! Serial driver for aarch64.
|
||||||
|
|
||||||
use core::fmt::{Arguments, Write};
|
use core::fmt::{Arguments, Write};
|
||||||
use super::board::serial::{SerialRead, SERIAL_PORT};
|
use super::board::serial::*;
|
||||||
|
|
||||||
pub fn getchar() -> char {
|
pub fn getchar() -> char {
|
||||||
unsafe { SERIAL_PORT.force_unlock(); }
|
unsafe { SERIAL_PORT.force_unlock(); }
|
||||||
|
@ -99,7 +99,7 @@ fn init_frame_allocator() {
|
|||||||
|
|
||||||
/// remap kernel page table after all initialization.
|
/// remap kernel page table after all initialization.
|
||||||
fn remap_the_kernel() {
|
fn remap_the_kernel() {
|
||||||
let mut ms = unsafe { MemorySet::new_bare() };
|
let mut ms = MemorySet::new_bare();
|
||||||
ms.push(0, bootstacktop as usize, Linear::new(0, MemoryAttr::default()), "kstack");
|
ms.push(0, bootstacktop as usize, Linear::new(0, MemoryAttr::default()), "kstack");
|
||||||
ms.push(stext as usize, etext as usize, Linear::new(0, MemoryAttr::default().execute().readonly()), "text");
|
ms.push(stext as usize, etext as usize, Linear::new(0, MemoryAttr::default().execute().readonly()), "text");
|
||||||
ms.push(sdata as usize, edata as usize, Linear::new(0, MemoryAttr::default()), "data");
|
ms.push(sdata as usize, edata as usize, Linear::new(0, MemoryAttr::default()), "data");
|
||||||
|
@ -6,29 +6,25 @@ pub mod memory;
|
|||||||
pub mod interrupt;
|
pub mod interrupt;
|
||||||
pub mod consts;
|
pub mod consts;
|
||||||
pub mod cpu;
|
pub mod cpu;
|
||||||
|
pub mod driver;
|
||||||
|
|
||||||
#[cfg(feature = "board_raspi3")]
|
#[cfg(feature = "board_raspi3")]
|
||||||
#[path = "board/raspi3/mod.rs"]
|
#[path = "board/raspi3/mod.rs"]
|
||||||
pub mod board;
|
pub mod board;
|
||||||
|
|
||||||
pub use self::board::timer;
|
|
||||||
|
|
||||||
global_asm!(include_str!("boot/boot.S"));
|
global_asm!(include_str!("boot/boot.S"));
|
||||||
|
|
||||||
/// The entry point of kernel
|
/// The entry point of kernel
|
||||||
#[no_mangle] // don't mangle the name of this function
|
#[no_mangle] // don't mangle the name of this function
|
||||||
pub extern "C" fn rust_main() -> ! {
|
pub extern "C" fn rust_main() -> ! {
|
||||||
// Enable mmu and paging
|
memory::init_mmu_early(); // Enable mmu and paging
|
||||||
memory::init_mmu_early();
|
board::init_early();
|
||||||
|
|
||||||
// Init board to enable serial port.
|
|
||||||
board::init();
|
|
||||||
println!("{}", LOGO);
|
println!("{}", LOGO);
|
||||||
|
|
||||||
crate::logging::init();
|
crate::logging::init();
|
||||||
interrupt::init();
|
interrupt::init();
|
||||||
memory::init();
|
memory::init();
|
||||||
timer::init();
|
driver::init();
|
||||||
|
|
||||||
crate::process::init();
|
crate::process::init();
|
||||||
|
|
||||||
|
@ -58,12 +58,14 @@ impl PageTable for ActivePageTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn unmap(&mut self, addr: usize) {
|
fn unmap(&mut self, addr: usize) {
|
||||||
let (frame, flush) = self.0.unmap(Page::of_addr(addr)).unwrap();
|
let (_frame, flush) = self.0.unmap(Page::of_addr(addr)).unwrap();
|
||||||
flush.flush();
|
flush.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_entry(&mut self, addr: usize) -> Option<&mut Entry> {
|
fn get_entry(&mut self, vaddr: usize) -> Option<&mut Entry> {
|
||||||
let entry_addr = ((addr >> 9) & 0o777_777_777_7770) | (RECURSIVE_INDEX << 39);
|
// get p1 entry
|
||||||
|
let entry_addr = ((vaddr >> 9) & 0o777_777_777_7770) | (RECURSIVE_INDEX << 39)
|
||||||
|
| (vaddr & 0xffff_0000_0000_0000);
|
||||||
Some(unsafe { &mut *(entry_addr as *mut PageEntry) })
|
Some(unsafe { &mut *(entry_addr as *mut PageEntry) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -211,9 +213,11 @@ impl InactivePageTable for InactivePageTable0 {
|
|||||||
let target = ttbr_el1_read(0).start_address().as_u64() as usize;
|
let target = ttbr_el1_read(0).start_address().as_u64() as usize;
|
||||||
active_table().with_temporary_map(target, |active_table, p4_table: &mut Aarch64PageTable| {
|
active_table().with_temporary_map(target, |active_table, p4_table: &mut Aarch64PageTable| {
|
||||||
let backup = p4_table[RECURSIVE_INDEX].clone();
|
let backup = p4_table[RECURSIVE_INDEX].clone();
|
||||||
|
let old_frame = ttbr_el1_read(1);
|
||||||
|
|
||||||
// overwrite recursive mapping
|
// overwrite recursive mapping
|
||||||
p4_table[RECURSIVE_INDEX].set_frame(self.p4_frame.clone(), EF::default(), MairNormal::attr_value());
|
p4_table[RECURSIVE_INDEX].set_frame(self.p4_frame.clone(), EF::default(), MairNormal::attr_value());
|
||||||
|
ttbr_el1_write(1, self.p4_frame.clone());
|
||||||
tlb_invalidate_all();
|
tlb_invalidate_all();
|
||||||
|
|
||||||
// execute f in the new context
|
// execute f in the new context
|
||||||
@ -221,6 +225,7 @@ impl InactivePageTable for InactivePageTable0 {
|
|||||||
|
|
||||||
// restore recursive mapping to original p4 table
|
// restore recursive mapping to original p4 table
|
||||||
p4_table[RECURSIVE_INDEX] = backup;
|
p4_table[RECURSIVE_INDEX] = backup;
|
||||||
|
ttbr_el1_write(1, old_frame);
|
||||||
tlb_invalidate_all();
|
tlb_invalidate_all();
|
||||||
ret
|
ret
|
||||||
})
|
})
|
||||||
|
@ -77,13 +77,12 @@ impl Stdin {
|
|||||||
pub fn pop(&self) -> char {
|
pub fn pop(&self) -> char {
|
||||||
// QEMU v3.0 don't support M-mode external interrupt (bug?)
|
// QEMU v3.0 don't support M-mode external interrupt (bug?)
|
||||||
// So we have to use polling.
|
// So we have to use polling.
|
||||||
// TODO: serial interrupt on aarch64
|
#[cfg(feature = "m_mode")]
|
||||||
#[cfg(any(feature = "m_mode", target_arch = "aarch64"))]
|
|
||||||
loop {
|
loop {
|
||||||
let c = crate::arch::io::getchar();
|
let c = crate::arch::io::getchar();
|
||||||
if c != '\0' { return c; }
|
if c != '\0' { return c; }
|
||||||
}
|
}
|
||||||
#[cfg(not(any(feature = "m_mode", target_arch = "aarch64")))]
|
#[cfg(not(feature = "m_mode"))]
|
||||||
loop {
|
loop {
|
||||||
let ret = self.buf.lock().pop_front();
|
let ret = self.buf.lock().pop_front();
|
||||||
match ret {
|
match ret {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
pub use crate::arch::paging::*;
|
pub use crate::arch::paging::*;
|
||||||
use bit_allocator::{BitAlloc, BitAlloc4K, BitAlloc64K, BitAlloc1M};
|
use bit_allocator::BitAlloc;
|
||||||
use crate::consts::MEMORY_OFFSET;
|
use crate::consts::MEMORY_OFFSET;
|
||||||
use super::HEAP_ALLOCATOR;
|
use super::HEAP_ALLOCATOR;
|
||||||
use ucore_memory::{*, paging::PageTable};
|
use ucore_memory::{*, paging::PageTable};
|
||||||
@ -21,15 +21,15 @@ pub type MemorySet = ucore_memory::no_mmu::MemorySet<NoMMUSupportImpl>;
|
|||||||
|
|
||||||
// x86_64 support up to 256M memory
|
// x86_64 support up to 256M memory
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub type FrameAlloc = BitAlloc64K;
|
pub type FrameAlloc = bit_allocator::BitAlloc64K;
|
||||||
|
|
||||||
// RISCV only have 8M memory
|
// RISCV only have 8M memory
|
||||||
#[cfg(target_arch = "riscv32")]
|
#[cfg(target_arch = "riscv32")]
|
||||||
pub type FrameAlloc = BitAlloc4K;
|
pub type FrameAlloc = bit_allocator::BitAlloc4K;
|
||||||
|
|
||||||
// Raspberry Pi 3 has 1G memory
|
// Raspberry Pi 3 has 1G memory
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
pub type FrameAlloc = BitAlloc1M;
|
pub type FrameAlloc = bit_allocator::BitAlloc1M;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref FRAME_ALLOCATOR: SpinNoIrqLock<FrameAlloc> = SpinNoIrqLock::new(FrameAlloc::default());
|
pub static ref FRAME_ALLOCATOR: SpinNoIrqLock<FrameAlloc> = SpinNoIrqLock::new(FrameAlloc::default());
|
||||||
|
Loading…
Reference in New Issue
Block a user