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
master
WangRunji 6 years ago
commit 9b0b0064d0

@ -2,10 +2,11 @@
name = "bcm2837"
version = "0.1.0"
authors = ["equation314 <equation618@gmail.com>"]
edition = "2018"
[features]
use_generic_timer = []
use_generic_timer = ["aarch64"]
[dependencies]
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 timer::delay;
use crate::IO_BASE;
use crate::timer::delay;
use core::marker::PhantomData;
use volatile::{ReadOnly, Volatile, WriteOnly};

@ -1,9 +1,10 @@
use IO_BASE;
use crate::IO_BASE;
use volatile::{ReadOnly, Volatile};
const INT_BASE: usize = IO_BASE + 0xB000 + 0x200;
/// Allowed interrupts (ref: peripherals 7.5, page 113)
#[repr(u8)]
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Interrupt {
Timer1 = 1,
@ -30,6 +31,24 @@ struct Registers {
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
/// check if an interrupt is pending.
pub struct Controller {
@ -38,6 +57,7 @@ pub struct Controller {
impl Controller {
/// Returns a new handle to the interrupt controller.
#[inline]
pub fn new() -> Controller {
Controller {
registers: unsafe { &mut *(INT_BASE as *mut Registers) },
@ -58,4 +78,11 @@ impl Controller {
pub fn is_pending(&self, int: Interrupt) -> bool {
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 gpio::{Function, Gpio};
use crate::IO_BASE;
use crate::gpio::{Function, Gpio};
use volatile::{ReadOnly, Volatile};
/// 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.
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.
#[repr(u8)]
enum LsrStatus {
@ -15,7 +22,7 @@ enum LsrStatus {
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)]
#[allow(non_snake_case)]
struct Registers {
@ -62,23 +69,25 @@ impl MiniUart {
&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 {
registers: registers,
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.
pub fn set_read_timeout(&mut self, milliseconds: u32) {
self.timeout = Some(milliseconds)
@ -111,8 +120,13 @@ impl MiniUart {
}
/// 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() {}
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::*;
/// 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.
/// The returned value is the number of elapsed microseconds.
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
}
@ -66,7 +66,7 @@ impl Timer {
/// interrupts for timer 1 are enabled and IRQs are unmasked, then a timer
/// interrupt will be issued in `us` microseconds.
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);
}

@ -1,6 +1,6 @@
use ::IO_BASE;
use crate::IO_BASE;
use crate::interrupt::{Controller, Interrupt};
use volatile::{ReadOnly, Volatile};
use interrupt::{Controller, Interrupt};
/// The base address for the ARM system timer registers.
const TIMER_REG_BASE: usize = IO_BASE + 0x3000;

@ -1,7 +1,6 @@
#![cfg_attr(not(test), no_std)]
#![feature(alloc)]
#![feature(nll)]
#![feature(extern_crate_item_prelude)]
// import macros from log
use log::*;
@ -14,4 +13,4 @@ pub mod memory_set;
mod addr;
pub mod no_mmu;
pub use crate::addr::*;
pub use crate::addr::*;

@ -6,7 +6,6 @@
#![feature(vec_resize_default)]
#![feature(asm)]
#![feature(exact_size_is_empty)]
#![feature(extern_crate_item_prelude)]
extern crate alloc;

15
kernel/Cargo.lock generated

@ -1,12 +1,10 @@
[[package]]
name = "aarch64"
version = "2.2.2"
source = "git+https://github.com/equation314/aarch64#47bf5439f5a1379f0fef6272853cf684207a4e45"
source = "git+https://github.com/equation314/aarch64#e3b60adb233ad34d05443e0b5ec34cac29253296"
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)",
"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)",
"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)",
@ -50,7 +48,7 @@ version = "0.1.0"
name = "bcm2837"
version = "0.1.0"
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)",
]
@ -98,14 +96,6 @@ name = "cfg-if"
version = "0.1.6"
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]]
name = "fixedvec"
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 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 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 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"

@ -12,7 +12,8 @@ no_mmu = []
# Kernel in M-mode (for riscv32)
m_mode = ["no_mmu"]
# (for aarch64 RaspberryPi3)
board_raspi3 = []
board_raspi3 = ["bcm2837"]
raspi3_use_generic_timer = ["bcm2837/use_generic_timer"]
[profile.dev]
# MUST >= 1 : Enable RVO to avoid stack overflow
@ -53,7 +54,7 @@ bbl = { path = "../crate/bbl" }
[target.'cfg(target_arch = "aarch64")'.dependencies]
aarch64 = { git = "https://github.com/equation314/aarch64" }
atags = { path = "../crate/atags" }
bcm2837 = { path = "../crate/bcm2837", features = ["use_generic_timer"] }
bcm2837 = { path = "../crate/bcm2837", optional = true }
[package.metadata.bootimage]
default-target = "x86_64-blog_os.json"

@ -80,6 +80,15 @@ features += no_bbl
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
features += no_mmu m_mode
bbl_m_mode := --enable-boot-machine

@ -1,11 +1,28 @@
use crate::arch::interrupt::TrapFrame;
use bcm2837::timer::Timer;
use bcm2837::interrupt::{Controller, Interrupt};
use bcm2837::interrupt::Controller;
use log::*;
pub fn handle_irq(tf: &mut TrapFrame) {
let controller = Timer::new();
pub use bcm2837::interrupt::Interrupt;
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() {
super::timer::set_next();
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_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");
serial::SERIAL_PORT.lock().init();
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 spin::Mutex;
use once::*;
/// Struct to get a global SerialPort interface
pub struct SerialPort {
mu: Option<MiniUart>,
mu: MiniUart,
}
pub trait SerialRead {
@ -14,30 +14,31 @@ pub trait SerialRead {
impl SerialPort {
/// Creates a new instance of `SerialPort`.
const fn new() -> SerialPort {
SerialPort { mu: None }
fn new() -> SerialPort {
SerialPort {
mu: MiniUart::new(),
}
}
/// Init a newly created SerialPort, can only be called once.
pub fn init(&mut self) {
assert_has_not_been_called!("SerialPort::init must be called only once");
self.mu = Some(MiniUart::new());
self.mu.init();
super::irq::register_irq(super::irq::Interrupt::Aux, handle_serial_irq);
}
/// Writes the byte `byte` to the UART device.
pub fn write_byte(&mut self, byte: u8) {
match &mut self.mu {
Some(mu) => mu.write_byte(byte),
None => panic!("SerialPort is not initialized"),
}
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.
pub fn read_byte(&mut self) -> u8 {
match &mut self.mu {
Some(mu) => return mu.read_byte(),
None => panic!("SerialPort is not initialized"),
}
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)
}
}
@ -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::interrupt::{Controller, Interrupt};
use log::*;
pub fn init() {

@ -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.
#[naked]
#[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!(
"
mov x10, #-(12 * 8)
@ -149,7 +149,7 @@ impl Context {
tf: TrapFrame::new_kernel_thread(entry, arg, kstack_top),
}.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 {
context: ContextData::new(),
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) {
let addr = FAR_EL1.get();
error!("\nEXCEPTION: Page Fault @ {:#x}", addr);
crate::trap::error(tf);
let addr = FAR_EL1.get() as usize;
if !crate::memory::page_fault_handler(addr) {
error!("\nEXCEPTION: Page Fault @ {:#x}", addr);
crate::trap::error(tf);
}
}

@ -1,7 +1,7 @@
//! Serial driver for aarch64.
use core::fmt::{Arguments, Write};
use super::board::serial::{SerialRead, SERIAL_PORT};
use super::board::serial::*;
pub fn getchar() -> char {
unsafe { SERIAL_PORT.force_unlock(); }

@ -99,7 +99,7 @@ fn init_frame_allocator() {
/// remap kernel page table after all initialization.
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(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");

@ -6,29 +6,25 @@ pub mod memory;
pub mod interrupt;
pub mod consts;
pub mod cpu;
pub mod driver;
#[cfg(feature = "board_raspi3")]
#[path = "board/raspi3/mod.rs"]
pub mod board;
pub use self::board::timer;
global_asm!(include_str!("boot/boot.S"));
/// The entry point of kernel
#[no_mangle] // don't mangle the name of this function
pub extern "C" fn rust_main() -> ! {
// Enable mmu and paging
memory::init_mmu_early();
// Init board to enable serial port.
board::init();
memory::init_mmu_early(); // Enable mmu and paging
board::init_early();
println!("{}", LOGO);
crate::logging::init();
interrupt::init();
memory::init();
timer::init();
driver::init();
crate::process::init();

@ -58,12 +58,14 @@ impl PageTable for ActivePageTable {
}
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();
}
fn get_entry(&mut self, addr: usize) -> Option<&mut Entry> {
let entry_addr = ((addr >> 9) & 0o777_777_777_7770) | (RECURSIVE_INDEX << 39);
fn get_entry(&mut self, vaddr: usize) -> Option<&mut Entry> {
// 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) })
}
}
@ -211,9 +213,11 @@ impl InactivePageTable for InactivePageTable0 {
let target = ttbr_el1_read(0).start_address().as_u64() as usize;
active_table().with_temporary_map(target, |active_table, p4_table: &mut Aarch64PageTable| {
let backup = p4_table[RECURSIVE_INDEX].clone();
let old_frame = ttbr_el1_read(1);
// overwrite recursive mapping
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();
// execute f in the new context
@ -221,6 +225,7 @@ impl InactivePageTable for InactivePageTable0 {
// restore recursive mapping to original p4 table
p4_table[RECURSIVE_INDEX] = backup;
ttbr_el1_write(1, old_frame);
tlb_invalidate_all();
ret
})

@ -77,13 +77,12 @@ impl Stdin {
pub fn pop(&self) -> char {
// QEMU v3.0 don't support M-mode external interrupt (bug?)
// So we have to use polling.
// TODO: serial interrupt on aarch64
#[cfg(any(feature = "m_mode", target_arch = "aarch64"))]
#[cfg(feature = "m_mode")]
loop {
let c = crate::arch::io::getchar();
if c != '\0' { return c; }
}
#[cfg(not(any(feature = "m_mode", target_arch = "aarch64")))]
#[cfg(not(feature = "m_mode"))]
loop {
let ret = self.buf.lock().pop_front();
match ret {

@ -1,5 +1,5 @@
pub use crate::arch::paging::*;
use bit_allocator::{BitAlloc, BitAlloc4K, BitAlloc64K, BitAlloc1M};
use bit_allocator::BitAlloc;
use crate::consts::MEMORY_OFFSET;
use super::HEAP_ALLOCATOR;
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
#[cfg(target_arch = "x86_64")]
pub type FrameAlloc = BitAlloc64K;
pub type FrameAlloc = bit_allocator::BitAlloc64K;
// RISCV only have 8M memory
#[cfg(target_arch = "riscv32")]
pub type FrameAlloc = BitAlloc4K;
pub type FrameAlloc = bit_allocator::BitAlloc4K;
// Raspberry Pi 3 has 1G memory
#[cfg(target_arch = "aarch64")]
pub type FrameAlloc = BitAlloc1M;
pub type FrameAlloc = bit_allocator::BitAlloc1M;
lazy_static! {
pub static ref FRAME_ALLOCATOR: SpinNoIrqLock<FrameAlloc> = SpinNoIrqLock::new(FrameAlloc::default());

Loading…
Cancel
Save