mirror of
https://github.com/rcore-os/rCore.git
synced 2024-11-25 01:16:18 +04:00
Merge remote-tracking branch 'equation314/arch-aarch64' into dev
# Conflicts: # .gitignore # kernel/Cargo.lock # kernel/Cargo.toml # kernel/Makefile # kernel/riscv32-blog_os.json # kernel/src/consts.rs # kernel/src/fs.rs # kernel/src/lib.rs # kernel/src/process/context.rs # kernel/src/process/mod.rs
This commit is contained in:
commit
2daf8c188d
5
.gitignore
vendored
5
.gitignore
vendored
@ -6,3 +6,8 @@ target
|
|||||||
/crate/bbl/Cargo.lock
|
/crate/bbl/Cargo.lock
|
||||||
/crate/sync/Cargo.lock
|
/crate/sync/Cargo.lock
|
||||||
/crate/process/Cargo.lock
|
/crate/process/Cargo.lock
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# for eclipse
|
||||||
|
.project
|
||||||
|
14
crate/atags/Cargo.lock
generated
Normal file
14
crate/atags/Cargo.lock
generated
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[[package]]
|
||||||
|
name = "atags"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"volatile 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "volatile"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
"checksum volatile 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d9ca391c55768e479d5c2f8beb40c136df09257292a809ea514e82cfdfc15d00"
|
6
crate/atags/Cargo.toml
Normal file
6
crate/atags/Cargo.toml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "atags"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["koumingyang <1761674434@qq.com>"]
|
||||||
|
|
||||||
|
[dependencies]
|
67
crate/atags/src/atag.rs
Normal file
67
crate/atags/src/atag.rs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
use raw;
|
||||||
|
use core::slice;
|
||||||
|
use core::str;
|
||||||
|
|
||||||
|
pub use raw::{Core, Mem};
|
||||||
|
|
||||||
|
/// An ATAG.
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub enum Atag {
|
||||||
|
Core(raw::Core),
|
||||||
|
Mem(raw::Mem),
|
||||||
|
Cmd(&'static str),
|
||||||
|
Unknown(u32),
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Atag {
|
||||||
|
/// Returns `Some` if this is a `Core` ATAG. Otherwise returns `None`.
|
||||||
|
pub fn core(self) -> Option<Core> {
|
||||||
|
match self {
|
||||||
|
Atag::Core(x) => Some(x),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `Some` if this is a `Mem` ATAG. Otherwise returns `None`.
|
||||||
|
pub fn mem(self) -> Option<Mem> {
|
||||||
|
match self {
|
||||||
|
Atag::Mem(x) => Some(x),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `Some` with the command line string if this is a `Cmd` ATAG.
|
||||||
|
/// Otherwise returns `None`.
|
||||||
|
pub fn cmd(self) -> Option<&'static str> {
|
||||||
|
match self {
|
||||||
|
Atag::Cmd(x) => Some(x),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert between raw::* types and Atag wrapper.
|
||||||
|
impl<'a> From<&'a raw::Atag> for Atag {
|
||||||
|
fn from(atag: &raw::Atag) -> Atag {
|
||||||
|
unsafe {
|
||||||
|
match (atag.tag, &atag.kind) {
|
||||||
|
(raw::Atag::CORE, &raw::Kind { core }) => Atag::Core(core),
|
||||||
|
(raw::Atag::MEM, &raw::Kind { mem }) => Atag::Mem(mem),
|
||||||
|
(raw::Atag::CMDLINE, &raw::Kind { ref cmd }) => {
|
||||||
|
let mut cmd_ptr: *const u8 = &cmd.cmd as *const u8;
|
||||||
|
let mut len: usize = 0;
|
||||||
|
|
||||||
|
while *cmd_ptr.add(len) != 0 {
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cmd_slice = slice::from_raw_parts(cmd_ptr, len);
|
||||||
|
Atag::Cmd(str::from_utf8_unchecked(cmd_slice))
|
||||||
|
},
|
||||||
|
(raw::Atag::NONE, _) => Atag::None,
|
||||||
|
(id, _) => Atag::Unknown(id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
crate/atags/src/atags.rs
Normal file
37
crate/atags/src/atags.rs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
pub use atag::*;
|
||||||
|
use raw;
|
||||||
|
|
||||||
|
/// The address at which the firmware loads the ATAGS.
|
||||||
|
const ATAG_BASE: usize = 0x100;
|
||||||
|
|
||||||
|
/// An iterator over the ATAGS on this system.
|
||||||
|
pub struct Atags {
|
||||||
|
ptr: &'static raw::Atag,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Atags {
|
||||||
|
/// Returns an instance of `Atags`, an iterator over ATAGS on this system.
|
||||||
|
pub fn get() -> Atags {
|
||||||
|
Atags {
|
||||||
|
ptr: unsafe { &*(ATAG_BASE as *const raw::Atag) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for Atags {
|
||||||
|
type Item = Atag;
|
||||||
|
|
||||||
|
/// Iterate over Atags. Returns a valid Atag until the iterator hits the
|
||||||
|
/// Atag::None.
|
||||||
|
fn next(&mut self) -> Option<Atag> {
|
||||||
|
let cur = self.ptr;
|
||||||
|
match cur.next() {
|
||||||
|
Some(next) => {
|
||||||
|
let result = Some(Atag::from(cur));
|
||||||
|
self.ptr = next;
|
||||||
|
result
|
||||||
|
},
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
crate/atags/src/lib.rs
Normal file
6
crate/atags/src/lib.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#![no_std]
|
||||||
|
|
||||||
|
mod raw;
|
||||||
|
mod atag;
|
||||||
|
|
||||||
|
pub mod atags;
|
67
crate/atags/src/raw.rs
Normal file
67
crate/atags/src/raw.rs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/// A raw `ATAG` as laid out in memory.
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Atag {
|
||||||
|
pub dwords: u32,
|
||||||
|
pub tag: u32,
|
||||||
|
pub kind: Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Atag {
|
||||||
|
pub const NONE: u32 = 0x00000000;
|
||||||
|
pub const CORE: u32 = 0x54410001;
|
||||||
|
pub const MEM: u32 = 0x54410002;
|
||||||
|
pub const VIDEOTEXT: u32 = 0x54410003;
|
||||||
|
pub const RAMDISK: u32 = 0x54410004;
|
||||||
|
pub const INITRD2: u32 = 0x54420005;
|
||||||
|
pub const SERIAL: u32 = 0x54410006;
|
||||||
|
pub const REVISION: u32 = 0x54410007;
|
||||||
|
pub const VIDEOLFB: u32 = 0x54410008;
|
||||||
|
pub const CMDLINE: u32 = 0x54410009;
|
||||||
|
|
||||||
|
/// Returns the ATAG following `self`, if there is one.
|
||||||
|
pub fn next(&self) -> Option<&Atag> {
|
||||||
|
if self.tag == Atag::NONE {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let current = self as *const Atag as *const u32;
|
||||||
|
let next: &Atag = unsafe {
|
||||||
|
&*(current.add(self.dwords as usize) as *const Atag)
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(next)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The possible variant of an ATAG.
|
||||||
|
#[repr(C)]
|
||||||
|
pub union Kind {
|
||||||
|
pub core: Core,
|
||||||
|
pub mem: Mem,
|
||||||
|
pub cmd: Cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A `CORE` ATAG.
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct Core {
|
||||||
|
pub flags: u32,
|
||||||
|
pub page_size: u32,
|
||||||
|
pub root_dev: u32
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A `MEM` ATAG.
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct Mem {
|
||||||
|
pub size: u32,
|
||||||
|
pub start: u32
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A `CMDLINE` ATAG.
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct Cmd {
|
||||||
|
/// The first byte of the command line string.
|
||||||
|
pub cmd: u8
|
||||||
|
}
|
11
crate/bcm2837/Cargo.toml
Normal file
11
crate/bcm2837/Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "bcm2837"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["equation314 <equation618@gmail.com>"]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
use_generic_timer = []
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
volatile = "0.2.4"
|
||||||
|
cortex-a = "2.2.2"
|
163
crate/bcm2837/src/gpio.rs
Normal file
163
crate/bcm2837/src/gpio.rs
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
use IO_BASE;
|
||||||
|
use timer::delay;
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
use volatile::{ReadOnly, Volatile, WriteOnly};
|
||||||
|
|
||||||
|
/// The base address of the `GPIO` registers.
|
||||||
|
const GPIO_BASE: usize = IO_BASE + 0x200000;
|
||||||
|
|
||||||
|
/// An alternative GPIO function. (ref: peripherals 6.1, page 92)
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum Function {
|
||||||
|
Input = 0b000,
|
||||||
|
Output = 0b001,
|
||||||
|
Alt0 = 0b100,
|
||||||
|
Alt1 = 0b101,
|
||||||
|
Alt2 = 0b110,
|
||||||
|
Alt3 = 0b111,
|
||||||
|
Alt4 = 0b011,
|
||||||
|
Alt5 = 0b010,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// GPIO registers starting from `GPIO_BASE` (ref: peripherals 6.1, page 90)
|
||||||
|
#[repr(C)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
struct Registers {
|
||||||
|
FSEL: [Volatile<u32>; 6],
|
||||||
|
__reserved0: u32,
|
||||||
|
SET: [WriteOnly<u32>; 2],
|
||||||
|
__reserved1: u32,
|
||||||
|
CLR: [WriteOnly<u32>; 2],
|
||||||
|
__reserved2: u32,
|
||||||
|
LEV: [ReadOnly<u32>; 2],
|
||||||
|
__reserved3: u32,
|
||||||
|
EDS: [Volatile<u32>; 2],
|
||||||
|
__reserved4: u32,
|
||||||
|
REN: [Volatile<u32>; 2],
|
||||||
|
__reserved5: u32,
|
||||||
|
FEN: [Volatile<u32>; 2],
|
||||||
|
__reserved6: u32,
|
||||||
|
HEN: [Volatile<u32>; 2],
|
||||||
|
__reserved7: u32,
|
||||||
|
LEN: [Volatile<u32>; 2],
|
||||||
|
__reserved8: u32,
|
||||||
|
AREN: [Volatile<u32>; 2],
|
||||||
|
__reserved9: u32,
|
||||||
|
AFEN: [Volatile<u32>; 2],
|
||||||
|
__reserved10: u32,
|
||||||
|
PUD: Volatile<u32>,
|
||||||
|
PUDCLK: [Volatile<u32>; 2],
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Possible states for a GPIO pin.
|
||||||
|
pub enum Uninitialized {}
|
||||||
|
pub enum Input {}
|
||||||
|
pub enum Output {}
|
||||||
|
pub enum Alt {}
|
||||||
|
|
||||||
|
/// A GPIO pin in state `State`.
|
||||||
|
///
|
||||||
|
/// The `State` generic always corresponds to an uninstantiatable type that is
|
||||||
|
/// use solely to mark and track the state of a given GPIO pin. A `Gpio`
|
||||||
|
/// structure starts in the `Uninitialized` state and must be transitions into
|
||||||
|
/// one of `Input`, `Output`, or `Alt` via the `into_input`, `into_output`, and
|
||||||
|
/// `into_alt` methods before it can be used.
|
||||||
|
pub struct Gpio<State> {
|
||||||
|
pin: u8,
|
||||||
|
registers: &'static mut Registers,
|
||||||
|
_state: PhantomData<State>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Gpio<T> {
|
||||||
|
/// Transitions `self` to state `S`, consuming `self` and returning a new
|
||||||
|
/// `Gpio` instance in state `S`. This method should _never_ be exposed to
|
||||||
|
/// the public!
|
||||||
|
#[inline(always)]
|
||||||
|
fn transition<S>(self) -> Gpio<S> {
|
||||||
|
Gpio {
|
||||||
|
pin: self.pin,
|
||||||
|
registers: self.registers,
|
||||||
|
_state: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the Gpio pull-up/pull-down state for values in `pin_value`
|
||||||
|
/// (ref: peripherals 6.1, page 101)
|
||||||
|
pub fn set_gpio_pd(&mut self, pud_value: u8) {
|
||||||
|
let index = if self.pin >= 32 { 1 } else { 0 };
|
||||||
|
|
||||||
|
self.registers.PUD.write(pud_value as u32);
|
||||||
|
delay(150);
|
||||||
|
self.registers.PUDCLK[index as usize].write((1 << self.pin) as u32);
|
||||||
|
delay(150);
|
||||||
|
self.registers.PUD.write(0);
|
||||||
|
self.registers.PUDCLK[index as usize].write(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Gpio<Uninitialized> {
|
||||||
|
/// Returns a new `GPIO` structure for pin number `pin`.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if `pin` > `53`.
|
||||||
|
pub fn new(pin: u8) -> Gpio<Uninitialized> {
|
||||||
|
if pin > 53 {
|
||||||
|
panic!("Gpio::new(): pin {} exceeds maximum of 53", pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
Gpio {
|
||||||
|
registers: unsafe { &mut *(GPIO_BASE as *mut Registers) },
|
||||||
|
pin: pin,
|
||||||
|
_state: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enables the alternative function `function` for `self`. Consumes self
|
||||||
|
/// and returns a `Gpio` structure in the `Alt` state.
|
||||||
|
pub fn into_alt(self, function: Function) -> Gpio<Alt> {
|
||||||
|
let select = (self.pin / 10) as usize;
|
||||||
|
let offset = 3 * (self.pin % 10) as usize;
|
||||||
|
self.registers.FSEL[select].update(|value| {
|
||||||
|
*value &= !(0b111 << offset);
|
||||||
|
*value |= (function as u32) << offset;
|
||||||
|
});
|
||||||
|
self.transition()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets this pin to be an _output_ pin. Consumes self and returns a `Gpio`
|
||||||
|
/// structure in the `Output` state.
|
||||||
|
pub fn into_output(self) -> Gpio<Output> {
|
||||||
|
self.into_alt(Function::Output).transition()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets this pin to be an _input_ pin. Consumes self and returns a `Gpio`
|
||||||
|
/// structure in the `Input` state.
|
||||||
|
pub fn into_input(self) -> Gpio<Input> {
|
||||||
|
self.into_alt(Function::Input).transition()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Gpio<Output> {
|
||||||
|
/// Sets (turns on) the pin.
|
||||||
|
pub fn set(&mut self) {
|
||||||
|
let index = if self.pin >= 32 { 1 } else { 0 };
|
||||||
|
self.registers.SET[index as usize].write(1 << (self.pin - index * 32));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clears (turns off) the pin.
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
let index = if self.pin >= 32 { 1 } else { 0 };
|
||||||
|
self.registers.CLR[index as usize].write(1 << (self.pin - index * 32));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Gpio<Input> {
|
||||||
|
/// Reads the pin's value. Returns `true` if the level is high and `false`
|
||||||
|
/// if the level is low.
|
||||||
|
pub fn level(&mut self) -> bool {
|
||||||
|
let index = if self.pin >= 32 { 1 } else { 0 };
|
||||||
|
let high = 1 << (self.pin - index * 32);
|
||||||
|
(self.registers.LEV[index as usize].read() & high) == high
|
||||||
|
}
|
||||||
|
}
|
61
crate/bcm2837/src/interrupt.rs
Normal file
61
crate/bcm2837/src/interrupt.rs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
use IO_BASE;
|
||||||
|
use volatile::{ReadOnly, Volatile};
|
||||||
|
|
||||||
|
const INT_BASE: usize = IO_BASE + 0xB000 + 0x200;
|
||||||
|
|
||||||
|
/// Allowed interrupts (ref: peripherals 7.5, page 113)
|
||||||
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||||
|
pub enum Interrupt {
|
||||||
|
Timer1 = 1,
|
||||||
|
Timer3 = 3,
|
||||||
|
Usb = 9,
|
||||||
|
Aux = 29,
|
||||||
|
Gpio0 = 49,
|
||||||
|
Gpio1 = 50,
|
||||||
|
Gpio2 = 51,
|
||||||
|
Gpio3 = 52,
|
||||||
|
Uart = 57,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Interrupts registers starting from `INT_BASE` (ref: peripherals 7.5, page 112)
|
||||||
|
#[repr(C)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
struct Registers {
|
||||||
|
IRQBasicPending: ReadOnly<u32>,
|
||||||
|
IRQPending: [ReadOnly<u32>; 2],
|
||||||
|
FIQControl: Volatile<u32>,
|
||||||
|
EnableIRQ: [Volatile<u32>; 2],
|
||||||
|
EnableBasicIRQ: Volatile<u32>,
|
||||||
|
DisableIRQ: [Volatile<u32>; 2],
|
||||||
|
DisableBasicIRQ: Volatile<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An interrupt controller. Used to enable and disable interrupts as well as to
|
||||||
|
/// check if an interrupt is pending.
|
||||||
|
pub struct Controller {
|
||||||
|
registers: &'static mut Registers,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Controller {
|
||||||
|
/// Returns a new handle to the interrupt controller.
|
||||||
|
pub fn new() -> Controller {
|
||||||
|
Controller {
|
||||||
|
registers: unsafe { &mut *(INT_BASE as *mut Registers) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enables the interrupt `int`.
|
||||||
|
pub fn enable(&mut self, int: Interrupt) {
|
||||||
|
self.registers.EnableIRQ[int as usize / 32].write(1 << (int as usize) % 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Disables the interrupt `int`.
|
||||||
|
pub fn disable(&mut self, int: Interrupt) {
|
||||||
|
self.registers.DisableIRQ[int as usize / 32].write(1 << (int as usize) % 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if `int` is pending. Otherwise, returns `false`.
|
||||||
|
pub fn is_pending(&self, int: Interrupt) -> bool {
|
||||||
|
self.registers.IRQPending[int as usize / 32].read() & (1 << (int as usize) % 32) != 0
|
||||||
|
}
|
||||||
|
}
|
11
crate/bcm2837/src/lib.rs
Normal file
11
crate/bcm2837/src/lib.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![feature(asm)]
|
||||||
|
|
||||||
|
extern crate volatile;
|
||||||
|
|
||||||
|
pub mod gpio;
|
||||||
|
pub mod timer;
|
||||||
|
pub mod mini_uart;
|
||||||
|
pub mod interrupt;
|
||||||
|
|
||||||
|
pub const IO_BASE: usize = 0x3F000000;
|
118
crate/bcm2837/src/mini_uart.rs
Normal file
118
crate/bcm2837/src/mini_uart.rs
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
use IO_BASE;
|
||||||
|
use gpio::{Function, Gpio};
|
||||||
|
use volatile::{ReadOnly, Volatile};
|
||||||
|
|
||||||
|
/// The base address for the `MU` registers.
|
||||||
|
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_LSR_REG` register.
|
||||||
|
#[repr(u8)]
|
||||||
|
enum LsrStatus {
|
||||||
|
DataReady = 1,
|
||||||
|
TxAvailable = 1 << 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// MU registers starting from `AUX_ENABLES` (ref: peripherals 2.1, page 8)
|
||||||
|
#[repr(C)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
struct Registers {
|
||||||
|
AUX_MU_IO_REG: Volatile<u8>,
|
||||||
|
__r0: [u8; 3],
|
||||||
|
AUX_MU_IER_REG: Volatile<u8>,
|
||||||
|
__r1: [u8; 3],
|
||||||
|
AUX_MU_IIR_REG: Volatile<u8>,
|
||||||
|
__r2: [u8; 3],
|
||||||
|
AUX_MU_LCR_REG: Volatile<u8>,
|
||||||
|
__r3: [u8; 3],
|
||||||
|
AUX_MU_MCR_REG: Volatile<u8>,
|
||||||
|
__r4: [u8; 3],
|
||||||
|
AUX_MU_LSR_REG: ReadOnly<u8>,
|
||||||
|
__r5: [u8; 3],
|
||||||
|
AUX_MU_MSR_REG: ReadOnly<u8>,
|
||||||
|
__r6: [u8; 3],
|
||||||
|
AUX_MU_SCRATCH: Volatile<u8>,
|
||||||
|
__r7: [u8; 3],
|
||||||
|
AUX_MU_CNTL_REG: Volatile<u8>,
|
||||||
|
__r8: [u8; 3],
|
||||||
|
AUX_MU_STAT_REG: ReadOnly<u32>,
|
||||||
|
AUX_MU_BAUD_REG: Volatile<u16>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The Raspberry Pi's "mini UART".
|
||||||
|
pub struct MiniUart {
|
||||||
|
registers: &'static mut Registers,
|
||||||
|
timeout: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MiniUart {
|
||||||
|
/// Initializes the mini UART by enabling it as an auxiliary peripheral,
|
||||||
|
/// setting the data size to 8 bits, setting the BAUD rate to ~115200 (baud
|
||||||
|
/// divider of 270), setting GPIO pins 14 and 15 to alternative function 5
|
||||||
|
/// (TXD1/RDXD1), and finally enabling the UART transmitter and receiver.
|
||||||
|
///
|
||||||
|
/// By default, reads will never time out. To set a read timeout, use
|
||||||
|
/// `set_read_timeout()`.
|
||||||
|
pub fn new() -> MiniUart {
|
||||||
|
let registers = unsafe {
|
||||||
|
// Enable the mini UART as an auxiliary device.
|
||||||
|
(*AUX_ENABLES).write(1);
|
||||||
|
&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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the read timeout to `milliseconds` milliseconds.
|
||||||
|
pub fn set_read_timeout(&mut self, milliseconds: u32) {
|
||||||
|
self.timeout = Some(milliseconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write the byte `byte`. This method blocks until there is space available
|
||||||
|
/// in the output FIFO.
|
||||||
|
pub fn write_byte(&mut self, byte: u8) {
|
||||||
|
while self.registers.AUX_MU_LSR_REG.read() & (LsrStatus::TxAvailable as u8) == 0 {}
|
||||||
|
self.registers.AUX_MU_IO_REG.write(byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if there is at least one byte ready to be read. If this
|
||||||
|
/// method returns `true`, a subsequent call to `read_byte` is guaranteed to
|
||||||
|
/// return immediately. This method does not block.
|
||||||
|
pub fn has_byte(&self) -> bool {
|
||||||
|
self.registers.AUX_MU_LSR_REG.read() & (LsrStatus::DataReady as u8) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Blocks until there is a byte ready to read. If a read timeout is set,
|
||||||
|
/// this method blocks for at most that amount of time. Otherwise, this
|
||||||
|
/// method blocks indefinitely until there is a byte to read.
|
||||||
|
///
|
||||||
|
/// Returns `Ok(())` if a byte is ready to read. Returns `Err(())` if the
|
||||||
|
/// timeout expired while waiting for a byte to be ready. If this method
|
||||||
|
/// returns `Ok(())`, a subsequent call to `read_byte` is guaranteed to
|
||||||
|
/// return immediately.
|
||||||
|
pub fn wait_for_byte(&self) -> Result<(), ()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads a byte. Blocks indefinitely until a byte is ready to be read.
|
||||||
|
pub fn read_byte(&mut self) -> u8 {
|
||||||
|
while !self.has_byte() {}
|
||||||
|
self.registers.AUX_MU_IO_REG.read()
|
||||||
|
}
|
||||||
|
}
|
83
crate/bcm2837/src/timer/generic_timer.rs
Normal file
83
crate/bcm2837/src/timer/generic_timer.rs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
extern crate cortex_a;
|
||||||
|
|
||||||
|
use self::cortex_a::regs::*;
|
||||||
|
use volatile::*;
|
||||||
|
|
||||||
|
/// The base address for the ARM generic timer, IRQs, mailboxes
|
||||||
|
const GEN_TIMER_REG_BASE: usize = 0x40000000;
|
||||||
|
|
||||||
|
/// Core interrupt sources (ref: QA7 4.10, page 16)
|
||||||
|
#[repr(u8)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||||
|
enum CoreInterrupt {
|
||||||
|
CNTPSIRQ = 0,
|
||||||
|
CNTPNSIRQ = 1,
|
||||||
|
CNTHPIRQ = 2,
|
||||||
|
CNTVIRQ = 3,
|
||||||
|
Mailbox0 = 4,
|
||||||
|
Mailbox1 = 5,
|
||||||
|
Mailbox2 = 6,
|
||||||
|
Mailbox3 = 7,
|
||||||
|
Gpu = 8,
|
||||||
|
Pmu = 9,
|
||||||
|
AxiOutstanding = 10,
|
||||||
|
LocalTimer = 11,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Timer, IRQs, mailboxes registers (ref: QA7 chapter 4, page 7)
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct Registers {
|
||||||
|
CONTROL: Volatile<u32>,
|
||||||
|
_unused1: [Volatile<u32>; 8],
|
||||||
|
LOCAL_IRQ: Volatile<u32>,
|
||||||
|
_unused2: [Volatile<u32>; 3],
|
||||||
|
LOCAL_TIMER_CTL: Volatile<u32>,
|
||||||
|
LOCAL_TIMER_FLAGS: Volatile<u32>,
|
||||||
|
_unused3: Volatile<u32>,
|
||||||
|
CORE_TIMER_IRQCNTL: [Volatile<u32>; 4],
|
||||||
|
CORE_MAILBOX_IRQCNTL: [Volatile<u32>; 4],
|
||||||
|
CORE_IRQ_SRC: [Volatile<u32>; 4],
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The ARM generic timer.
|
||||||
|
pub struct Timer {
|
||||||
|
registers: &'static mut Registers,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Timer {
|
||||||
|
/// Returns a new instance of `Timer`.
|
||||||
|
pub fn new() -> Timer {
|
||||||
|
Timer {
|
||||||
|
registers: unsafe { &mut *(GEN_TIMER_REG_BASE as *mut Registers) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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();
|
||||||
|
(CNTPCT_EL0.get() * 1000000 / (cntfrq as u64)) as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets up a match in timer 1 to occur `us` microseconds from now. If
|
||||||
|
/// 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();
|
||||||
|
CNTP_TVAL_EL0.set(((cntfrq as f64) * (us as f64) / 1000000.0) as u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialization timer
|
||||||
|
pub fn init(&mut self) {
|
||||||
|
self.registers.CORE_TIMER_IRQCNTL[0].write(1 << (CoreInterrupt::CNTPNSIRQ as u8));
|
||||||
|
CNTP_CTL_EL0.write(CNTP_CTL_EL0::ENABLE::SET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if timer interruption is pending. Otherwise, returns `false`.
|
||||||
|
pub fn is_pending(&self) -> bool {
|
||||||
|
self.registers.CORE_IRQ_SRC[0].read() & (1 << (CoreInterrupt::CNTPNSIRQ as u8)) != 0
|
||||||
|
}
|
||||||
|
}
|
34
crate/bcm2837/src/timer/mod.rs
Normal file
34
crate/bcm2837/src/timer/mod.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#[cfg(feature = "use_generic_timer")]
|
||||||
|
mod generic_timer;
|
||||||
|
#[cfg(feature = "use_generic_timer")]
|
||||||
|
pub use self::generic_timer::Timer;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "use_generic_timer"))]
|
||||||
|
mod system_timer;
|
||||||
|
#[cfg(not(feature = "use_generic_timer"))]
|
||||||
|
pub use self::system_timer::Timer;
|
||||||
|
|
||||||
|
/// Initialization timer
|
||||||
|
pub fn init() {
|
||||||
|
Timer::new().init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the current time in microseconds.
|
||||||
|
pub fn current_time() -> u64 {
|
||||||
|
Timer::new().read()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets up a match in timer 1 to occur `us` microseconds from now. If
|
||||||
|
/// interrupts for timer 1 are enabled and IRQs are unmasked, then a timer
|
||||||
|
/// interrupt will be issued in `us` microseconds.
|
||||||
|
pub fn tick_in(us: u32) {
|
||||||
|
Timer::new().tick_in(us);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// wait for `cycle` CPU cycles
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn delay(cycle: u32) {
|
||||||
|
for _ in 0..cycle {
|
||||||
|
unsafe { asm!("nop") }
|
||||||
|
}
|
||||||
|
}
|
69
crate/bcm2837/src/timer/system_timer.rs
Normal file
69
crate/bcm2837/src/timer/system_timer.rs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
use ::IO_BASE;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/// System timer registers (ref: peripherals 12.1, page 172)
|
||||||
|
#[repr(C)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
struct Registers {
|
||||||
|
CS: Volatile<u32>,
|
||||||
|
CLO: ReadOnly<u32>,
|
||||||
|
CHI: ReadOnly<u32>,
|
||||||
|
COMPARE: [Volatile<u32>; 4],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||||
|
enum SystemTimer {
|
||||||
|
Timer0 = 0,
|
||||||
|
Timer1 = 1,
|
||||||
|
Timer2 = 2,
|
||||||
|
Timer3 = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The Raspberry Pi ARM system timer.
|
||||||
|
pub struct Timer {
|
||||||
|
registers: &'static mut Registers,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Timer {
|
||||||
|
/// Returns a new instance of `Timer`.
|
||||||
|
pub fn new() -> Timer {
|
||||||
|
Timer {
|
||||||
|
registers: unsafe { &mut *(TIMER_REG_BASE as *mut Registers) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads the system 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 low = self.registers.CLO.read();
|
||||||
|
let high = self.registers.CHI.read();
|
||||||
|
((high as u64) << 32) | (low as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets up a match in timer 1 to occur `us` microseconds from now. If
|
||||||
|
/// 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 current_low = self.registers.CLO.read();
|
||||||
|
let compare = current_low.wrapping_add(us);
|
||||||
|
self.registers.COMPARE[SystemTimer::Timer1 as usize].write(compare);
|
||||||
|
self.registers.CS.write(1 << (SystemTimer::Timer1 as usize)); // unmask
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialization timer
|
||||||
|
pub fn init(&mut self) {
|
||||||
|
Controller::new().enable(Interrupt::Timer1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if timer interruption is pending. Otherwise, returns `false`.
|
||||||
|
pub fn is_pending(&self) -> bool {
|
||||||
|
let controller = Controller::new();
|
||||||
|
controller.is_pending(Interrupt::Timer1)
|
||||||
|
}
|
||||||
|
}
|
45
kernel/Cargo.lock
generated
45
kernel/Cargo.lock
generated
@ -16,6 +16,10 @@ dependencies = [
|
|||||||
"nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
"nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atags"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bare-metal"
|
name = "bare-metal"
|
||||||
version = "0.2.4"
|
version = "0.2.4"
|
||||||
@ -28,6 +32,14 @@ dependencies = [
|
|||||||
name = "bbl"
|
name = "bbl"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bcm2837"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"cortex-a 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"volatile 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit-allocator"
|
name = "bit-allocator"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -72,6 +84,14 @@ 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"
|
||||||
@ -179,6 +199,14 @@ dependencies = [
|
|||||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "register"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"tock-registers 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "remove_dir_all"
|
name = "remove_dir_all"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
@ -256,6 +284,11 @@ dependencies = [
|
|||||||
"remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tock-registers"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uart_16550"
|
name = "uart_16550"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -270,12 +303,15 @@ name = "ucore"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"apic 0.1.0 (git+https://github.com/wangrunji0408/APIC-Rust)",
|
"apic 0.1.0 (git+https://github.com/wangrunji0408/APIC-Rust)",
|
||||||
|
"atags 0.1.0",
|
||||||
"bbl 0.1.0",
|
"bbl 0.1.0",
|
||||||
|
"bcm2837 0.1.0",
|
||||||
"bit-allocator 0.1.0",
|
"bit-allocator 0.1.0",
|
||||||
"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)",
|
||||||
"bootloader 0.3.4 (git+https://github.com/wangrunji0408/bootloader)",
|
"bootloader 0.3.4 (git+https://github.com/wangrunji0408/bootloader)",
|
||||||
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"cortex-a 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"linked_list_allocator 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"linked_list_allocator 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -288,7 +324,7 @@ dependencies = [
|
|||||||
"uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ucore-memory 0.1.0",
|
"ucore-memory 0.1.0",
|
||||||
"ucore-process 0.1.0",
|
"ucore-process 0.1.0",
|
||||||
"volatile 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"volatile 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"x86_64 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"x86_64 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@ -325,7 +361,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "volatile"
|
name = "volatile"
|
||||||
version = "0.1.0"
|
version = "0.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -404,6 +440,7 @@ 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"
|
||||||
@ -419,6 +456,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07"
|
"checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07"
|
||||||
"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
|
"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
|
||||||
"checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d"
|
"checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d"
|
||||||
|
"checksum register 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e10f31b6d2299e5620986ad9fcdd66463e125ad72af4f403f9aedf7592d5ccdb"
|
||||||
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
|
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
|
||||||
"checksum riscv 0.3.0 (git+https://github.com/riscv-and-rust-and-decaf/riscv)" = "<none>"
|
"checksum riscv 0.3.0 (git+https://github.com/riscv-and-rust-and-decaf/riscv)" = "<none>"
|
||||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||||
@ -429,11 +467,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f"
|
"checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f"
|
||||||
"checksum static_assertions 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "389ce475f424f267dbed6479cbd8f126c5e1afb053b0acdaa019c74305fc65d1"
|
"checksum static_assertions 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "389ce475f424f267dbed6479cbd8f126c5e1afb053b0acdaa019c74305fc65d1"
|
||||||
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
|
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
|
||||||
|
"checksum tock-registers 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3a385d94f3f62e60445a0adb9ff8d9621faa272234530d4c0f848ec98f88e316"
|
||||||
"checksum uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "269f953d8de3226f7c065c589c7b4a3e83d10a419c7c3b5e2e0f197e6acc966e"
|
"checksum uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "269f953d8de3226f7c065c589c7b4a3e83d10a419c7c3b5e2e0f197e6acc966e"
|
||||||
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
||||||
"checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5"
|
"checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5"
|
||||||
"checksum ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53d8df5dd8d07fedccd202de1887d94481fadaea3db70479f459e8163a1fab41"
|
"checksum ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53d8df5dd8d07fedccd202de1887d94481fadaea3db70479f459e8163a1fab41"
|
||||||
"checksum volatile 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37c5d76c0f40ba4f8ac10ec4717d4e98ce3e58c5607eea36e9464226fc5e0a95"
|
"checksum volatile 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "54d4343a2df2d65144a874f95950754ee7b7e8594f6027aae8c7d0f4858a3fe8"
|
||||||
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
||||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
@ -7,6 +7,7 @@ edition = "2018"
|
|||||||
[features]
|
[features]
|
||||||
link_user_program = []
|
link_user_program = []
|
||||||
no_bbl = []
|
no_bbl = []
|
||||||
|
board_raspi3 = []
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
# MUST >= 1 : Enable RVO to avoid stack overflow
|
# MUST >= 1 : Enable RVO to avoid stack overflow
|
||||||
@ -22,7 +23,7 @@ once = "0.3"
|
|||||||
xmas-elf = "0.6"
|
xmas-elf = "0.6"
|
||||||
bitflags = "1.0"
|
bitflags = "1.0"
|
||||||
bit_field = "0.9"
|
bit_field = "0.9"
|
||||||
volatile = "0.1"
|
volatile = "0.2"
|
||||||
linked_list_allocator = "0.6"
|
linked_list_allocator = "0.6"
|
||||||
lazy_static = { version = "1.2", features = ["spin_no_std"] }
|
lazy_static = { version = "1.2", features = ["spin_no_std"] }
|
||||||
bit-allocator = { path = "../crate/bit-allocator" }
|
bit-allocator = { path = "../crate/bit-allocator" }
|
||||||
@ -44,6 +45,11 @@ pc-keyboard = "0.3"
|
|||||||
riscv = { git = "https://github.com/riscv-and-rust-and-decaf/riscv" }
|
riscv = { git = "https://github.com/riscv-and-rust-and-decaf/riscv" }
|
||||||
bbl = { path = "../crate/bbl" }
|
bbl = { path = "../crate/bbl" }
|
||||||
|
|
||||||
|
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
||||||
|
cortex-a = "2.2.1"
|
||||||
|
atags = { path = "../crate/atags" }
|
||||||
|
bcm2837 = { path = "../crate/bcm2837", features = ["use_generic_timer"] }
|
||||||
|
|
||||||
[package.metadata.bootimage]
|
[package.metadata.bootimage]
|
||||||
default-target = "x86_64-blog_os.json"
|
default-target = "x86_64-blog_os.json"
|
||||||
output = "target/x86_64-blog_os/bootimage.bin"
|
output = "target/x86_64-blog_os/bootimage.bin"
|
||||||
|
110
kernel/Makefile
110
kernel/Makefile
@ -8,14 +8,17 @@
|
|||||||
# make clean Clean
|
# make clean Clean
|
||||||
#
|
#
|
||||||
# Options:
|
# Options:
|
||||||
# arch = x86_64 | riscv32
|
# arch = x86_64 | riscv32 | aarch64
|
||||||
# d = int | in_asm | ... QEMU debug info
|
# d = int | in_asm | ... QEMU debug info
|
||||||
# mode = debug | release
|
# mode = debug | release
|
||||||
# LOG = off | error | warn | info | debug | trace
|
# LOG = off | error | warn | info | debug | trace
|
||||||
# smp SMP core number
|
# smp SMP core number
|
||||||
# board Only available on riscv32, build without bbl, run on board
|
# board = fpga Only available on riscv32, build without bbl, run on board
|
||||||
|
# | raspi3 Only available on aarch64, run on Raspberry Pi 3 Model B/B+
|
||||||
|
|
||||||
arch ?= riscv32
|
arch ?= riscv32
|
||||||
|
board ?= raspi3
|
||||||
|
prefix ?= $(arch)-none-elf
|
||||||
mode ?= debug
|
mode ?= debug
|
||||||
LOG ?= debug
|
LOG ?= debug
|
||||||
smp ?= 4
|
smp ?= 4
|
||||||
@ -29,25 +32,40 @@ user_bin_path := ../user/target/$(arch)-ucore/debug
|
|||||||
user_bins := $(patsubst $(user_bin_path)/%.d, $(user_bin_path)/%, $(wildcard $(user_bin_path)/*.d))
|
user_bins := $(patsubst $(user_bin_path)/%.d, $(user_bin_path)/%, $(wildcard $(user_bin_path)/*.d))
|
||||||
user_obj := build/$(arch)/user.o
|
user_obj := build/$(arch)/user.o
|
||||||
SFSIMG := ../user/ucore32.img
|
SFSIMG := ../user/ucore32.img
|
||||||
|
|
||||||
|
### qemu options ###
|
||||||
ifeq ($(arch), x86_64)
|
ifeq ($(arch), x86_64)
|
||||||
qemu_opts := \
|
qemu_opts := \
|
||||||
-drive format=raw,file=$(bootimage) \
|
-drive format=raw,file=$(bootimage) \
|
||||||
-drive format=raw,file=$(SFSIMG),media=disk,cache=writeback \
|
-drive format=raw,file=$(SFSIMG),media=disk,cache=writeback \
|
||||||
-smp cores=$(smp) \
|
-smp cores=$(smp) \
|
||||||
-serial mon:stdio \
|
-serial mon:stdio \
|
||||||
-device isa-debug-exit
|
-device isa-debug-exit \
|
||||||
endif
|
-nographic
|
||||||
ifeq ($(arch), riscv32)
|
else ifeq ($(arch), riscv32)
|
||||||
qemu_opts := \
|
qemu_opts := \
|
||||||
-machine virt \
|
-machine virt \
|
||||||
-kernel $(bin) \
|
-kernel $(bin) \
|
||||||
-nographic \
|
-nographic \
|
||||||
-smp cores=$(smp)
|
-smp cores=$(smp)
|
||||||
|
else ifeq ($(arch), aarch64)
|
||||||
|
qemu_opts := \
|
||||||
|
-machine $(board) \
|
||||||
|
-serial null -serial mon:stdio \
|
||||||
|
-nographic \
|
||||||
|
-kernel $(bin)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifdef board
|
ifdef d
|
||||||
|
qemu_opts := $(qemu_opts) -d $(d)
|
||||||
|
endif
|
||||||
|
|
||||||
|
### build args ###
|
||||||
|
ifeq ($(arch), riscv32)
|
||||||
|
ifeq ($(board), fpga)
|
||||||
features := $(features) no_bbl
|
features := $(features) no_bbl
|
||||||
endif
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
# Link user binaries at ../user
|
# Link user binaries at ../user
|
||||||
ifdef link_user
|
ifdef link_user
|
||||||
@ -55,37 +73,26 @@ features := $(features) link_user_program
|
|||||||
assembly_object_files := $(assembly_object_files) $(user_obj)
|
assembly_object_files := $(assembly_object_files) $(user_obj)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifdef d
|
features := $(features) board_$(board)
|
||||||
qemu_opts := $(qemu_opts) -d $(d)
|
|
||||||
endif
|
|
||||||
|
|
||||||
build_args := --target $(target).json --features "$(features)"
|
build_args := --target $(target).json --features "$(features)"
|
||||||
|
|
||||||
ifeq ($(mode), release)
|
ifeq ($(mode), release)
|
||||||
build_args := $(build_args) --release
|
build_args := $(build_args) --release
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(OS),Windows_NT)
|
|
||||||
uname := Win32
|
|
||||||
else
|
|
||||||
uname := $(shell uname)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(uname), Darwin)
|
|
||||||
prefix := x86_64-elf-
|
|
||||||
endif
|
|
||||||
ifeq ($(arch), riscv32)
|
|
||||||
prefix := riscv64-unknown-elf-
|
|
||||||
endif
|
|
||||||
|
|
||||||
ld := $(prefix)ld
|
### prefix ###
|
||||||
objdump := $(prefix)objdump
|
ld := $(prefix)-ld
|
||||||
cc := $(prefix)gcc
|
objdump := $(prefix)-objdump
|
||||||
as := $(prefix)as
|
objcopy := $(prefix)-objcopy
|
||||||
|
cc := $(prefix)-gcc
|
||||||
|
as := $(prefix)-as
|
||||||
|
gdb := $(prefix)-gdb
|
||||||
|
|
||||||
.PHONY: all clean run build asm doc justrun kernel
|
.PHONY: all clean run build asm doc justrun kernel
|
||||||
|
|
||||||
all: $(kernel)
|
all: kernel
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@cargo clean
|
@cargo clean
|
||||||
@ -99,8 +106,10 @@ run: build justrun
|
|||||||
justrun:
|
justrun:
|
||||||
@qemu-system-$(arch) $(qemu_opts) || [ $$? -eq 11 ] # run qemu and assert it exit 11
|
@qemu-system-$(arch) $(qemu_opts) || [ $$? -eq 11 ] # run qemu and assert it exit 11
|
||||||
|
|
||||||
debug: $(bin)
|
debug: $(kernel) $(bin)
|
||||||
@qemu-system-$(arch) $(qemu_opts) -s -S &
|
@qemu-system-$(arch) $(qemu_opts) -s -S &
|
||||||
|
@sleep 1
|
||||||
|
@$(gdb) $(kernel) -x ../tools/gdbinit
|
||||||
|
|
||||||
ifeq ($(arch), x86_64)
|
ifeq ($(arch), x86_64)
|
||||||
build: kernel
|
build: kernel
|
||||||
@ -118,20 +127,24 @@ sym:
|
|||||||
@$(objdump) -t $(kernel) | less
|
@$(objdump) -t $(kernel) | less
|
||||||
|
|
||||||
$(bin): kernel
|
$(bin): kernel
|
||||||
ifdef board
|
ifeq ($(arch), riscv32)
|
||||||
|
ifeq ($(board), fpga)
|
||||||
@cp $(kernel) $@
|
@cp $(kernel) $@
|
||||||
else
|
else
|
||||||
@cd ../riscv-pk && \
|
@cd ../riscv-pk && \
|
||||||
mkdir -p build && \
|
mkdir -p build && \
|
||||||
cd build && \
|
cd build && \
|
||||||
../configure \
|
../configure \
|
||||||
--enable-32bit \
|
--enable-32bit \
|
||||||
--enable-logo \
|
--enable-logo \
|
||||||
--disable-fp-emulation \
|
--disable-fp-emulation \
|
||||||
--host=riscv64-unknown-elf \
|
--host=riscv64-unknown-elf \
|
||||||
--with-payload=$(abspath $(kernel)) && \
|
--with-payload=$(abspath $(kernel)) && \
|
||||||
make && \
|
make && \
|
||||||
cp bbl ../../kernel/$@
|
cp bbl ../../kernel/$@
|
||||||
|
endif
|
||||||
|
else ifeq ($(arch), aarch64)
|
||||||
|
$(objcopy) $(kernel) --strip-all -O binary $@
|
||||||
endif
|
endif
|
||||||
|
|
||||||
kernel:
|
kernel:
|
||||||
@ -148,3 +161,24 @@ endif
|
|||||||
$(user_obj): $(user_bins)
|
$(user_obj): $(user_bins)
|
||||||
@cd $(user_bin_path) && \
|
@cd $(user_bin_path) && \
|
||||||
$(ld) -o $(abspath $@) $(patsubst %, -b binary %, $(notdir $(user_bins)))
|
$(ld) -o $(abspath $@) $(patsubst %, -b binary %, $(notdir $(user_bins)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### install ###
|
||||||
|
ifeq ($(board), raspi3)
|
||||||
|
sd_card ?=
|
||||||
|
|
||||||
|
ifeq ($(shell uname), Darwin)
|
||||||
|
sd_card := /Volumes/boot
|
||||||
|
else ifeq ($(shell uname), Linux)
|
||||||
|
sd_card := /media/$(shell whoami)/boot
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef sd_card
|
||||||
|
.PHONY:
|
||||||
|
install: $(bin)
|
||||||
|
cp $(bin) $(sd_card)/kernel8.img
|
||||||
|
sudo umount $(sd_card)
|
||||||
|
endif
|
||||||
|
|
||||||
|
endif
|
||||||
|
35
kernel/aarch64-blog_os.json
Normal file
35
kernel/aarch64-blog_os.json
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"abi-blacklist": [
|
||||||
|
"stdcall",
|
||||||
|
"fastcall",
|
||||||
|
"vectorcall",
|
||||||
|
"thiscall",
|
||||||
|
"win64",
|
||||||
|
"sysv64"
|
||||||
|
],
|
||||||
|
"arch": "aarch64",
|
||||||
|
"data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
|
||||||
|
"executables": true,
|
||||||
|
"linker": "rust-lld",
|
||||||
|
"linker-flavor": "ld.lld",
|
||||||
|
"linker-is-gnu": true,
|
||||||
|
"pre-link-args": {
|
||||||
|
"ld.lld": [
|
||||||
|
"-Tsrc/arch/aarch64/boot/linker.ld"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"llvm-target": "aarch64-unknown-none",
|
||||||
|
"no-compiler-rt": true,
|
||||||
|
"features": "+a53,+strict-align,-neon",
|
||||||
|
"max-atomic-width": 128,
|
||||||
|
"os": "none",
|
||||||
|
"panic": "abort",
|
||||||
|
"panic-strategy": "abort",
|
||||||
|
"relocation-model": "static",
|
||||||
|
"position-independent-executables": true,
|
||||||
|
"target-c-int-width": "32",
|
||||||
|
"target-endian": "little",
|
||||||
|
"target-pointer-width": "64",
|
||||||
|
"target-family": "unix",
|
||||||
|
"disable-redzone": true
|
||||||
|
}
|
11
kernel/src/arch/aarch64/board/raspi3/irq.rs
Normal file
11
kernel/src/arch/aarch64/board/raspi3/irq.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
use arch::interrupt::TrapFrame;
|
||||||
|
use super::bcm2837::timer::Timer;
|
||||||
|
use super::bcm2837::interrupt::{Controller, Interrupt};
|
||||||
|
|
||||||
|
pub fn handle_irq(tf: &mut TrapFrame) {
|
||||||
|
let controller = Timer::new();
|
||||||
|
if controller.is_pending() {
|
||||||
|
super::timer::set_next();
|
||||||
|
::trap::timer();
|
||||||
|
}
|
||||||
|
}
|
18
kernel/src/arch/aarch64/board/raspi3/mod.rs
Normal file
18
kernel/src/arch/aarch64/board/raspi3/mod.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
//! Raspberry PI 3 Model B/B+
|
||||||
|
|
||||||
|
extern crate bcm2837;
|
||||||
|
|
||||||
|
pub mod irq;
|
||||||
|
pub mod timer;
|
||||||
|
pub mod serial;
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
// FIXME
|
||||||
|
// assert_has_not_been_called!("board::init must be called only once");
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
serial::SERIAL_PORT.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Hello Raspberry Pi!");
|
||||||
|
}
|
77
kernel/src/arch/aarch64/board/raspi3/serial.rs
Normal file
77
kernel/src/arch/aarch64/board/raspi3/serial.rs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
use super::bcm2837::mini_uart::MiniUart;
|
||||||
|
|
||||||
|
use core::fmt;
|
||||||
|
use spin::Mutex;
|
||||||
|
|
||||||
|
/// Struct to get a global SerialPort interface
|
||||||
|
pub struct SerialPort {
|
||||||
|
mu: Option<MiniUart>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait SerialRead {
|
||||||
|
fn receive(&mut self) -> u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SerialPort {
|
||||||
|
/// Creates a new instance of `SerialPort`.
|
||||||
|
const fn new() -> SerialPort {
|
||||||
|
SerialPort { mu: None }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Init a newly created SerialPort, can only be called once.
|
||||||
|
pub fn init(&mut self) {
|
||||||
|
// FIXME
|
||||||
|
// assert_has_not_been_called!("SerialPort::init must be called only once");
|
||||||
|
self.mu = Some(MiniUart::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME
|
||||||
|
// pub static SERIAL_PORT: Mutex<SerialPort> = Mutex::new(SerialPort::new());
|
||||||
|
pub static mut SERIAL_PORT: SerialPort = SerialPort::new();
|
||||||
|
|
17
kernel/src/arch/aarch64/board/raspi3/timer.rs
Normal file
17
kernel/src/arch/aarch64/board/raspi3/timer.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
use super::bcm2837::timer;
|
||||||
|
use super::bcm2837::interrupt::{Controller, Interrupt};
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
timer::init();
|
||||||
|
set_next();
|
||||||
|
info!("timer: init end");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_cycle() -> u64 {
|
||||||
|
timer::current_time()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_next() {
|
||||||
|
// 10 ms
|
||||||
|
timer::tick_in(10 * 1000);
|
||||||
|
}
|
110
kernel/src/arch/aarch64/boot/boot.S
Normal file
110
kernel/src/arch/aarch64/boot/boot.S
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
# TODO rewrite in Rust, use crate cortex-a
|
||||||
|
|
||||||
|
.section .text.boot
|
||||||
|
|
||||||
|
.global _start
|
||||||
|
_start:
|
||||||
|
# read cpu affinity, start core 0, halt rest
|
||||||
|
mrs x1, mpidr_el1
|
||||||
|
and x1, x1, #3
|
||||||
|
cbz x1, setup
|
||||||
|
|
||||||
|
halt:
|
||||||
|
# core affinity != 0, halt it
|
||||||
|
wfe
|
||||||
|
b halt
|
||||||
|
|
||||||
|
setup:
|
||||||
|
# store the desired EL1 stack pointer in x1
|
||||||
|
adr x1, _start
|
||||||
|
|
||||||
|
# use SP_ELx for Exception level ELx
|
||||||
|
msr SPsel, #1
|
||||||
|
|
||||||
|
# read the current exception level into x0 (ref: C5.2.1)
|
||||||
|
mrs x0, CurrentEL
|
||||||
|
and x0, x0, #0b1100
|
||||||
|
lsr x0, x0, #2
|
||||||
|
|
||||||
|
switch_to_el2:
|
||||||
|
# switch to EL2 if we're in EL3. otherwise switch to EL1
|
||||||
|
cmp x0, #2
|
||||||
|
beq switch_to_el1
|
||||||
|
|
||||||
|
# set-up SCR_EL3 (bits 0, 4, 5, 7, 8, 10) (A53: 4.3.42)
|
||||||
|
mov x0, #0x5b1
|
||||||
|
msr scr_el3, x0
|
||||||
|
|
||||||
|
# set-up SPSR_EL3 (bits 0, 3, 6, 7, 8, 9) (ref: C5.2.20)
|
||||||
|
mov x0, #0x3c9
|
||||||
|
msr spsr_el3, x0
|
||||||
|
|
||||||
|
# switch
|
||||||
|
adr x0, switch_to_el1
|
||||||
|
msr elr_el3, x0
|
||||||
|
|
||||||
|
eret
|
||||||
|
|
||||||
|
switch_to_el1:
|
||||||
|
# switch to EL1 if we're not already in EL1. otherwise continue with start
|
||||||
|
cmp x0, #1
|
||||||
|
beq set_stack
|
||||||
|
|
||||||
|
# set the stack-pointer for EL1
|
||||||
|
msr sp_el1, x1
|
||||||
|
|
||||||
|
# set-up HCR_EL2, enable AArch64 in EL1 (bits 1, 31) (ref: D10.2.45)
|
||||||
|
mov x0, #0x0002
|
||||||
|
movk x0, #0x8000, lsl #16
|
||||||
|
msr hcr_el2, x0
|
||||||
|
|
||||||
|
# don't trap accessing SVE registers (ref: D10.2.30)
|
||||||
|
msr cptr_el2, xzr
|
||||||
|
|
||||||
|
# enable floating point and SVE (SIMD) (bits 20, 21) (ref: D10.2.29)
|
||||||
|
mrs x0, cpacr_el1
|
||||||
|
orr x0, x0, #(0x3 << 20)
|
||||||
|
msr cpacr_el1, x0
|
||||||
|
|
||||||
|
# Set SCTLR to known state (RES1: 11, 20, 22, 23, 28, 29) (ref: D10.2.100)
|
||||||
|
mov x0, #0x0800
|
||||||
|
movk x0, #0x30d0, lsl #16
|
||||||
|
msr sctlr_el1, x0
|
||||||
|
|
||||||
|
# set-up SPSR_EL2 (bits 0, 2, 6, 7, 8, 9) (ref: C5.2.19)
|
||||||
|
mov x0, #0x3c5
|
||||||
|
msr spsr_el2, x0
|
||||||
|
|
||||||
|
# enable CNTP for EL1/EL0 (ref: D7.5.2, D7.5.13)
|
||||||
|
# NOTE: This doesn't actually enable the counter stream.
|
||||||
|
mrs x0, cnthctl_el2
|
||||||
|
orr x0, x0, #3
|
||||||
|
msr cnthctl_el2, x0
|
||||||
|
msr cntvoff_el2, xzr
|
||||||
|
|
||||||
|
# switch
|
||||||
|
adr x0, set_stack
|
||||||
|
msr elr_el2, x0
|
||||||
|
|
||||||
|
eret
|
||||||
|
|
||||||
|
set_stack:
|
||||||
|
# set the current stack pointer
|
||||||
|
mov sp, x1
|
||||||
|
|
||||||
|
zero_bss:
|
||||||
|
# load the start address and number of bytes in BSS section
|
||||||
|
ldr x1, =__bss_start
|
||||||
|
ldr x2, =__bss_length
|
||||||
|
|
||||||
|
zero_bss_loop:
|
||||||
|
# zero out the BSS section, 64-bits at a time
|
||||||
|
cbz x2, go_kmain
|
||||||
|
str xzr, [x1], #8
|
||||||
|
sub x2, x2, #8
|
||||||
|
cbnz x2, zero_bss_loop
|
||||||
|
|
||||||
|
go_kmain:
|
||||||
|
# jump to rust_main, which shouldn't return. halt if it does
|
||||||
|
bl rust_main
|
||||||
|
b halt
|
39
kernel/src/arch/aarch64/boot/linker.ld
Normal file
39
kernel/src/arch/aarch64/boot/linker.ld
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
. = 0x80000; /* Raspbery Pi 3 Aarch64 (kernel8.img) load address */
|
||||||
|
|
||||||
|
/* start of the binary */
|
||||||
|
_start = .;
|
||||||
|
|
||||||
|
.text : {
|
||||||
|
KEEP(*(.text.boot)) /* from boot.S */
|
||||||
|
*(.text .text.* .gnu.linkonce.t*)
|
||||||
|
}
|
||||||
|
|
||||||
|
.rodata : {
|
||||||
|
*(.rodata .rodata.* .gnu.linkonce.r*)
|
||||||
|
}
|
||||||
|
|
||||||
|
.data : {
|
||||||
|
*(.data .data.* .gnu.linkonce.d*)
|
||||||
|
}
|
||||||
|
|
||||||
|
.bss (NOLOAD) : {
|
||||||
|
. = ALIGN(32);
|
||||||
|
__bss_start = .;
|
||||||
|
*(.bss .bss.*)
|
||||||
|
*(COMMON)
|
||||||
|
. = ALIGN(8);
|
||||||
|
__bss_end = .;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end of the binary */
|
||||||
|
_end = ALIGN(8);
|
||||||
|
|
||||||
|
/* number of bytes in BSS section and complete binary */
|
||||||
|
__bss_length = (__bss_end - __bss_start);
|
||||||
|
__binary_length = (_end - _start);
|
||||||
|
|
||||||
|
/DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) }
|
||||||
|
}
|
11
kernel/src/arch/aarch64/consts.rs
Normal file
11
kernel/src/arch/aarch64/consts.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
//! TODO: replace unmiplemented consts with real value
|
||||||
|
const UNIMPLEMENTED: usize = 0;
|
||||||
|
pub const KERNEL_OFFSET: usize = UNIMPLEMENTED;
|
||||||
|
pub const KERNEL_PML4: usize = UNIMPLEMENTED;
|
||||||
|
pub const KERNEL_HEAP_OFFSET: usize = UNIMPLEMENTED;
|
||||||
|
pub const KERNEL_HEAP_SIZE: usize = 8 * 1024 * 1024;
|
||||||
|
pub const MEMORY_OFFSET: usize = UNIMPLEMENTED;
|
||||||
|
pub const MEMORY_END: usize = UNIMPLEMENTED;
|
||||||
|
pub const USER_STACK_OFFSET: usize = UNIMPLEMENTED;
|
||||||
|
pub const USER_STACK_SIZE: usize = UNIMPLEMENTED;
|
||||||
|
pub const USER32_STACK_OFFSET: usize = UNIMPLEMENTED;
|
151
kernel/src/arch/aarch64/interrupt/context.rs
Normal file
151
kernel/src/arch/aarch64/interrupt/context.rs
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
//! TrapFrame and context definitions for aarch64.
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Default, Debug, Copy, Clone)]
|
||||||
|
pub struct TrapFrame {
|
||||||
|
pub elr: usize,
|
||||||
|
pub spsr: usize,
|
||||||
|
pub sp: usize,
|
||||||
|
pub tpidr: usize,
|
||||||
|
// pub q0to31: [u128; 32], // disable SIMD/FP registers
|
||||||
|
pub x1to29: [usize; 29],
|
||||||
|
pub __reserved: usize,
|
||||||
|
pub x30: usize, // lr
|
||||||
|
pub x0: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 用于在内核栈中构造新线程的中断帧
|
||||||
|
impl TrapFrame {
|
||||||
|
fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, sp: usize) -> Self {
|
||||||
|
use core::mem::zeroed;
|
||||||
|
let mut tf: Self = unsafe { zeroed() };
|
||||||
|
tf.x0 = arg;
|
||||||
|
tf.sp = sp;
|
||||||
|
tf.elr = entry as usize;
|
||||||
|
tf.spsr = 0b1101_00_0101; // To EL 1, enable IRQ
|
||||||
|
tf
|
||||||
|
}
|
||||||
|
fn new_user_thread(entry_addr: usize, sp: usize) -> Self {
|
||||||
|
use core::mem::zeroed;
|
||||||
|
let mut tf: Self = unsafe { zeroed() };
|
||||||
|
tf.sp = sp;
|
||||||
|
tf.elr = entry_addr;
|
||||||
|
tf.spsr = 0b1101_00_0000; // To EL 0, enable IRQ
|
||||||
|
tf
|
||||||
|
}
|
||||||
|
pub fn is_user(&self) -> bool {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 新线程的内核栈初始内容
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct InitStack {
|
||||||
|
context: ContextData,
|
||||||
|
tf: TrapFrame,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InitStack {
|
||||||
|
unsafe fn push_at(self, stack_top: usize) -> Context {
|
||||||
|
let ptr = (stack_top as *mut Self).offset(-1);
|
||||||
|
*ptr = self;
|
||||||
|
Context(ptr as usize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern {
|
||||||
|
fn __trapret();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct ContextData {
|
||||||
|
x19to29: [usize; 11],
|
||||||
|
lr: usize,
|
||||||
|
ttbr0: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ContextData {
|
||||||
|
fn new(ttbr0: usize) -> Self {
|
||||||
|
ContextData { lr: __trapret as usize, ttbr0, ..ContextData::default() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Context(usize);
|
||||||
|
|
||||||
|
impl Context {
|
||||||
|
/// Switch to another kernel thread.
|
||||||
|
///
|
||||||
|
/// Defined in `trap.S`.
|
||||||
|
///
|
||||||
|
/// Push all callee-saved registers at the current kernel stack.
|
||||||
|
/// Store current sp, switch to target.
|
||||||
|
/// Pop all callee-saved registers, then return to the target.
|
||||||
|
#[naked]
|
||||||
|
#[inline(never)]
|
||||||
|
pub unsafe extern fn switch(&mut self, target: &mut Self) {
|
||||||
|
asm!(
|
||||||
|
"
|
||||||
|
mov x10, #-(13 * 8)
|
||||||
|
add x8, sp, x10
|
||||||
|
str x8, [x0]
|
||||||
|
stp x19, x20, [x8], #16 // store callee-saved registers
|
||||||
|
stp x21, x22, [x8], #16
|
||||||
|
stp x23, x24, [x8], #16
|
||||||
|
stp x25, x26, [x8], #16
|
||||||
|
stp x27, x28, [x8], #16
|
||||||
|
stp x29, lr, [x8], #16
|
||||||
|
mrs x9, ttbr0_el1
|
||||||
|
str x9, [x8], #8
|
||||||
|
|
||||||
|
ldr x8, [x1]
|
||||||
|
ldp x19, x20, [x8], #16 // restore callee-saved registers
|
||||||
|
ldp x21, x22, [x8], #16
|
||||||
|
ldp x23, x24, [x8], #16
|
||||||
|
ldp x25, x26, [x8], #16
|
||||||
|
ldp x27, x28, [x8], #16
|
||||||
|
ldp x29, lr, [x8], #16
|
||||||
|
ldr x9, [x8], #8
|
||||||
|
mov sp, x8
|
||||||
|
|
||||||
|
msr ttbr0_el1, x9 // set new page directory
|
||||||
|
dsb ishst // ensure write has completed
|
||||||
|
tlbi vmalle1is // invalidate the TLB entry for the entry that changes
|
||||||
|
dsb ish // ensure TLB invalidation is complete
|
||||||
|
isb // synchronize context on this processor
|
||||||
|
|
||||||
|
str xzr, [x1]
|
||||||
|
ret"
|
||||||
|
: : : : "volatile" );
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn null() -> Self {
|
||||||
|
Context(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, kstack_top: usize, ttbr0: usize) -> Self {
|
||||||
|
InitStack {
|
||||||
|
context: ContextData::new(ttbr0),
|
||||||
|
tf: TrapFrame::new_kernel_thread(entry, arg, kstack_top),
|
||||||
|
}.push_at(kstack_top)
|
||||||
|
}
|
||||||
|
pub unsafe fn new_user_thread(entry_addr: usize, ustack_top: usize, kstack_top: usize, is32: bool, ttbr0: usize) -> Self {
|
||||||
|
InitStack {
|
||||||
|
context: ContextData::new(ttbr0),
|
||||||
|
tf: TrapFrame::new_user_thread(entry_addr, ustack_top),
|
||||||
|
}.push_at(kstack_top)
|
||||||
|
}
|
||||||
|
pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, ttbr0: usize) -> Self {
|
||||||
|
InitStack {
|
||||||
|
context: ContextData::new(ttbr0),
|
||||||
|
tf: {
|
||||||
|
let mut tf = tf.clone();
|
||||||
|
tf.x0 = 0;
|
||||||
|
tf
|
||||||
|
},
|
||||||
|
}.push_at(kstack_top)
|
||||||
|
}
|
||||||
|
}
|
79
kernel/src/arch/aarch64/interrupt/handler.rs
Normal file
79
kernel/src/arch/aarch64/interrupt/handler.rs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
//! Trap handler
|
||||||
|
|
||||||
|
use arch::board::irq::handle_irq;
|
||||||
|
use super::context::TrapFrame;
|
||||||
|
use super::syndrome::Syndrome;
|
||||||
|
|
||||||
|
global_asm!(include_str!("trap.S"));
|
||||||
|
global_asm!(include_str!("vector.S"));
|
||||||
|
|
||||||
|
#[repr(u16)]
|
||||||
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
|
pub enum Kind {
|
||||||
|
Synchronous = 0,
|
||||||
|
Irq = 1,
|
||||||
|
Fiq = 2,
|
||||||
|
SError = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u16)]
|
||||||
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
|
pub enum Source {
|
||||||
|
CurrentSpEl0 = 0,
|
||||||
|
CurrentSpElx = 1,
|
||||||
|
LowerAArch64 = 2,
|
||||||
|
LowerAArch32 = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
|
pub struct Info {
|
||||||
|
source: Source,
|
||||||
|
kind: Kind,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This function is called when an exception occurs. The `info` parameter
|
||||||
|
/// specifies the source and kind of exception that has occurred. The `esr` is
|
||||||
|
/// the value of the exception syndrome register. Finally, `tf` is a pointer to
|
||||||
|
/// the trap frame for the exception.
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn rust_trap(info: Info, esr: u32, tf: &mut TrapFrame) {
|
||||||
|
let syndrome = Syndrome::from(esr);
|
||||||
|
trace!("Interrupt: {:?} from: {:?}", syndrome, info);
|
||||||
|
match info.kind {
|
||||||
|
Kind::Synchronous => {
|
||||||
|
// syndrome is only valid with sync
|
||||||
|
match syndrome {
|
||||||
|
Syndrome::Brk(brk) => handle_break(brk, tf),
|
||||||
|
Syndrome::Svc(_) => handle_syscall(tf),
|
||||||
|
_ => ::trap::error(tf),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Kind::Irq => handle_irq(tf),
|
||||||
|
_ => ::trap::error(tf),
|
||||||
|
}
|
||||||
|
::trap::before_return();
|
||||||
|
trace!("Interrupt end");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_break(num: u16, tf: &mut TrapFrame) {
|
||||||
|
// Skip the current brk instruction (ref: J1.1.2, page 6147)
|
||||||
|
tf.elr += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_syscall(tf: &mut TrapFrame) {
|
||||||
|
// svc instruction has been skipped in syscall (ref: J1.1.2, page 6152)
|
||||||
|
let ret = ::syscall::syscall(
|
||||||
|
tf.x1to29[7] as usize,
|
||||||
|
[
|
||||||
|
tf.x0,
|
||||||
|
tf.x1to29[0],
|
||||||
|
tf.x1to29[1],
|
||||||
|
tf.x1to29[2],
|
||||||
|
tf.x1to29[3],
|
||||||
|
tf.x1to29[4],
|
||||||
|
],
|
||||||
|
tf,
|
||||||
|
);
|
||||||
|
tf.x0 = ret as usize;
|
||||||
|
}
|
50
kernel/src/arch/aarch64/interrupt/mod.rs
Normal file
50
kernel/src/arch/aarch64/interrupt/mod.rs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
//! Interrupt and exception for aarch64.
|
||||||
|
|
||||||
|
mod handler;
|
||||||
|
mod context;
|
||||||
|
mod syndrome;
|
||||||
|
|
||||||
|
use super::cortex_a::regs::*;
|
||||||
|
pub use self::context::*;
|
||||||
|
pub use self::handler::*;
|
||||||
|
|
||||||
|
/// Set the exception vector address
|
||||||
|
pub fn init() {
|
||||||
|
unsafe {
|
||||||
|
asm!(
|
||||||
|
"adr x0, __vectors;
|
||||||
|
msr vbar_el1, x0"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enable the interrupt (only IRQ).
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn enable() {
|
||||||
|
asm!("msr daifclr, #2");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Disable the interrupt (only IRQ).
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn disable() {
|
||||||
|
asm!("msr daifset, #2");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Disable the interrupt and store the status.
|
||||||
|
///
|
||||||
|
/// return: status(usize)
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn disable_and_store() -> usize {
|
||||||
|
let daif = DAIF.get() as usize;
|
||||||
|
disable();
|
||||||
|
daif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Use the original status to restore the process
|
||||||
|
///
|
||||||
|
/// Arguments:
|
||||||
|
/// * flags: original status(usize)
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn restore(flags: usize) {
|
||||||
|
DAIF.set(flags as u32);
|
||||||
|
}
|
108
kernel/src/arch/aarch64/interrupt/syndrome.rs
Normal file
108
kernel/src/arch/aarch64/interrupt/syndrome.rs
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
//! Exception syndrome from ESR
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||||
|
pub enum Fault {
|
||||||
|
AddressSize,
|
||||||
|
Translation,
|
||||||
|
AccessFlag,
|
||||||
|
Permission,
|
||||||
|
Alignment,
|
||||||
|
TlbConflict,
|
||||||
|
Other(u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u32> for Fault {
|
||||||
|
fn from(val: u32) -> Fault {
|
||||||
|
use self::Fault::*;
|
||||||
|
|
||||||
|
// IFSC or DFSC bits (ref: D10.2.39, Page 2457~2464).
|
||||||
|
match val & 0b111100 {
|
||||||
|
0b000000 => AddressSize,
|
||||||
|
0b000100 => Translation,
|
||||||
|
0b001000 => AccessFlag,
|
||||||
|
0b001100 => Permission,
|
||||||
|
0b100000 => Alignment,
|
||||||
|
0b110000 => TlbConflict,
|
||||||
|
_ => Other((val & 0b111111) as u8),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||||
|
pub enum Syndrome {
|
||||||
|
Unknown,
|
||||||
|
WfiWfe,
|
||||||
|
McrMrc,
|
||||||
|
McrrMrrc,
|
||||||
|
LdcStc,
|
||||||
|
SimdFp,
|
||||||
|
Vmrs,
|
||||||
|
Mrrc,
|
||||||
|
IllegalExecutionState,
|
||||||
|
Svc(u16),
|
||||||
|
Hvc(u16),
|
||||||
|
Smc(u16),
|
||||||
|
MsrMrsSystem,
|
||||||
|
InstructionAbort { kind: Fault, level: u8 },
|
||||||
|
PCAlignmentFault,
|
||||||
|
DataAbort { kind: Fault, level: u8 },
|
||||||
|
SpAlignmentFault,
|
||||||
|
TrappedFpu,
|
||||||
|
SError,
|
||||||
|
Breakpoint,
|
||||||
|
Step,
|
||||||
|
Watchpoint,
|
||||||
|
Brk(u16),
|
||||||
|
Other(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts a raw syndrome value (ESR) into a `Syndrome` (ref: D1.10.4, D10.2.39).
|
||||||
|
impl From<u32> for Syndrome {
|
||||||
|
fn from(esr: u32) -> Syndrome {
|
||||||
|
use self::Syndrome::*;
|
||||||
|
|
||||||
|
let ec = esr >> 26;
|
||||||
|
let iss = esr & 0xFFFFFF;
|
||||||
|
|
||||||
|
match ec {
|
||||||
|
0b000000 => Unknown,
|
||||||
|
0b000001 => WfiWfe,
|
||||||
|
0b000011 => McrMrc,
|
||||||
|
0b000100 => McrrMrrc,
|
||||||
|
0b000101 => McrMrc,
|
||||||
|
0b000110 => LdcStc,
|
||||||
|
0b000111 => SimdFp,
|
||||||
|
0b001000 => Vmrs,
|
||||||
|
0b001100 => Mrrc,
|
||||||
|
0b001110 => IllegalExecutionState,
|
||||||
|
0b010001 => Svc((iss & 0xFFFF) as u16),
|
||||||
|
0b010010 => Hvc((iss & 0xFFFF) as u16),
|
||||||
|
0b010011 => Smc((iss & 0xFFFF) as u16),
|
||||||
|
0b010101 => Svc((iss & 0xFFFF) as u16),
|
||||||
|
0b010110 => Hvc((iss & 0xFFFF) as u16),
|
||||||
|
0b010111 => Smc((iss & 0xFFFF) as u16),
|
||||||
|
0b011000 => MsrMrsSystem,
|
||||||
|
0b100000 | 0b100001 => InstructionAbort {
|
||||||
|
kind: Fault::from(iss),
|
||||||
|
level: (iss & 0b11) as u8,
|
||||||
|
},
|
||||||
|
0b100010 => PCAlignmentFault,
|
||||||
|
0b100100 | 0b100101 => DataAbort {
|
||||||
|
kind: Fault::from(iss),
|
||||||
|
level: (iss & 0b11) as u8,
|
||||||
|
},
|
||||||
|
0b100110 => SpAlignmentFault,
|
||||||
|
0b101000 => TrappedFpu,
|
||||||
|
0b101100 => TrappedFpu,
|
||||||
|
0b101111 => SError,
|
||||||
|
0b110000 => Breakpoint,
|
||||||
|
0b110001 => Breakpoint,
|
||||||
|
0b110010 => Step,
|
||||||
|
0b110011 => Step,
|
||||||
|
0b110100 => Watchpoint,
|
||||||
|
0b110101 => Watchpoint,
|
||||||
|
0b111100 => Brk((iss & 0xFFFF) as u16),
|
||||||
|
other => Other(other),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
103
kernel/src/arch/aarch64/interrupt/trap.S
Normal file
103
kernel/src/arch/aarch64/interrupt/trap.S
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
.section .text
|
||||||
|
|
||||||
|
.macro SAVE_ALL
|
||||||
|
# lr, x0 is saved in HANDLER
|
||||||
|
str x29, [sp, #-16]!
|
||||||
|
stp x27, x28, [sp, #-16]!
|
||||||
|
stp x25, x26, [sp, #-16]!
|
||||||
|
stp x23, x24, [sp, #-16]!
|
||||||
|
stp x21, x22, [sp, #-16]!
|
||||||
|
stp x19, x20, [sp, #-16]!
|
||||||
|
stp x17, x18, [sp, #-16]!
|
||||||
|
stp x15, x16, [sp, #-16]!
|
||||||
|
stp x13, x14, [sp, #-16]!
|
||||||
|
stp x11, x12, [sp, #-16]!
|
||||||
|
stp x9, x10, [sp, #-16]!
|
||||||
|
stp x7, x8, [sp, #-16]!
|
||||||
|
stp x5, x6, [sp, #-16]!
|
||||||
|
stp x3, x4, [sp, #-16]!
|
||||||
|
stp x1, x2, [sp, #-16]!
|
||||||
|
|
||||||
|
# stp q30, q31, [sp, #-32]!
|
||||||
|
# stp q28, q29, [sp, #-32]!
|
||||||
|
# stp q26, q27, [sp, #-32]!
|
||||||
|
# stp q24, q25, [sp, #-32]!
|
||||||
|
# stp q22, q23, [sp, #-32]!
|
||||||
|
# stp q20, q21, [sp, #-32]!
|
||||||
|
# stp q18, q19, [sp, #-32]!
|
||||||
|
# stp q16, q17, [sp, #-32]!
|
||||||
|
# stp q14, q15, [sp, #-32]!
|
||||||
|
# stp q12, q13, [sp, #-32]!
|
||||||
|
# stp q10, q11, [sp, #-32]!
|
||||||
|
# stp q8, q9, [sp, #-32]!
|
||||||
|
# stp q6, q7, [sp, #-32]!
|
||||||
|
# stp q4, q5, [sp, #-32]!
|
||||||
|
# stp q2, q3, [sp, #-32]!
|
||||||
|
# stp q0, q1, [sp, #-32]!
|
||||||
|
|
||||||
|
mrs x2, tpidr_el0
|
||||||
|
mrs x1, sp_el0
|
||||||
|
stp x1, x2, [sp, #-16]!
|
||||||
|
|
||||||
|
mrs x2, spsr_el1
|
||||||
|
mrs x1, elr_el1
|
||||||
|
stp x1, x2, [sp, #-16]!
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro RESTORE_ALL
|
||||||
|
ldp x1, x2, [sp], #16
|
||||||
|
msr elr_el1, x1
|
||||||
|
msr spsr_el1, x2
|
||||||
|
|
||||||
|
ldp x1, x2, [sp], #16
|
||||||
|
msr sp_el0, x1
|
||||||
|
msr tpidr_el0, x2
|
||||||
|
|
||||||
|
# ldp q0, q1, [sp], #32
|
||||||
|
# ldp q2, q3, [sp], #32
|
||||||
|
# ldp q4, q5, [sp], #32
|
||||||
|
# ldp q6, q7, [sp], #32
|
||||||
|
# ldp q8, q9, [sp], #32
|
||||||
|
# ldp q10, q11, [sp], #32
|
||||||
|
# ldp q12, q13, [sp], #32
|
||||||
|
# ldp q14, q15, [sp], #32
|
||||||
|
# ldp q16, q17, [sp], #32
|
||||||
|
# ldp q18, q19, [sp], #32
|
||||||
|
# ldp q20, q21, [sp], #32
|
||||||
|
# ldp q22, q23, [sp], #32
|
||||||
|
# ldp q24, q25, [sp], #32
|
||||||
|
# ldp q26, q27, [sp], #32
|
||||||
|
# ldp q28, q29, [sp], #32
|
||||||
|
# ldp q30, q31, [sp], #32
|
||||||
|
|
||||||
|
ldp x1, x2, [sp], #16
|
||||||
|
ldp x3, x4, [sp], #16
|
||||||
|
ldp x5, x6, [sp], #16
|
||||||
|
ldp x7, x8, [sp], #16
|
||||||
|
ldp x9, x10, [sp], #16
|
||||||
|
ldp x11, x12, [sp], #16
|
||||||
|
ldp x13, x14, [sp], #16
|
||||||
|
ldp x15, x16, [sp], #16
|
||||||
|
ldp x17, x18, [sp], #16
|
||||||
|
ldp x19, x20, [sp], #16
|
||||||
|
ldp x21, x22, [sp], #16
|
||||||
|
ldp x23, x24, [sp], #16
|
||||||
|
ldp x25, x26, [sp], #16
|
||||||
|
ldp x27, x28, [sp], #16
|
||||||
|
ldr x29, [sp], #16
|
||||||
|
ldp lr, x0, [sp], #16
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.global __alltraps
|
||||||
|
__alltraps:
|
||||||
|
SAVE_ALL
|
||||||
|
|
||||||
|
# x0 is set in HANDLER
|
||||||
|
mrs x1, esr_el1
|
||||||
|
mov x2, sp
|
||||||
|
bl rust_trap
|
||||||
|
|
||||||
|
.global __trapret
|
||||||
|
__trapret:
|
||||||
|
RESTORE_ALL
|
||||||
|
eret
|
29
kernel/src/arch/aarch64/interrupt/vector.S
Normal file
29
kernel/src/arch/aarch64/interrupt/vector.S
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
.section .text
|
||||||
|
|
||||||
|
.macro HANDLER source kind
|
||||||
|
.align 7
|
||||||
|
stp lr, x0, [sp, #-16]!
|
||||||
|
mov x0, #\source
|
||||||
|
movk x0, #\kind, lsl #16
|
||||||
|
b __alltraps
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.global __vectors
|
||||||
|
.align 11
|
||||||
|
__vectors:
|
||||||
|
HANDLER 0 0
|
||||||
|
HANDLER 0 1
|
||||||
|
HANDLER 0 2
|
||||||
|
HANDLER 0 3
|
||||||
|
HANDLER 1 0
|
||||||
|
HANDLER 1 1
|
||||||
|
HANDLER 1 2
|
||||||
|
HANDLER 1 3
|
||||||
|
HANDLER 2 0
|
||||||
|
HANDLER 2 1
|
||||||
|
HANDLER 2 2
|
||||||
|
HANDLER 2 3
|
||||||
|
HANDLER 3 0
|
||||||
|
HANDLER 3 1
|
||||||
|
HANDLER 3 2
|
||||||
|
HANDLER 3 3
|
18
kernel/src/arch/aarch64/io.rs
Normal file
18
kernel/src/arch/aarch64/io.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
//! Serial driver for aarch64.
|
||||||
|
|
||||||
|
use core::fmt::{Arguments, Write};
|
||||||
|
use super::board::serial::{SerialRead, SERIAL_PORT};
|
||||||
|
|
||||||
|
pub fn getchar() -> char {
|
||||||
|
// FIXME
|
||||||
|
unsafe {
|
||||||
|
SERIAL_PORT.receive() as char
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn putfmt(fmt: Arguments) {
|
||||||
|
// FIXME
|
||||||
|
unsafe {
|
||||||
|
SERIAL_PORT.write_fmt(fmt).unwrap()
|
||||||
|
}
|
||||||
|
}
|
35
kernel/src/arch/aarch64/memory.rs
Normal file
35
kernel/src/arch/aarch64/memory.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
//! Memory initialization for aarch64.
|
||||||
|
|
||||||
|
use ucore_memory::PAGE_SIZE;
|
||||||
|
use super::atags::atags::Atags;
|
||||||
|
use super::super::HEAP_ALLOCATOR;
|
||||||
|
|
||||||
|
/// Memory initialization.
|
||||||
|
pub fn init() {
|
||||||
|
let (start, end) = memory_map().expect("failed to find memory map");
|
||||||
|
unsafe {
|
||||||
|
HEAP_ALLOCATOR.lock().init(start, end - start);
|
||||||
|
}
|
||||||
|
info!("memory: init end");
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
static _end: u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the (start address, end address) of the available memory on this
|
||||||
|
/// system if it can be determined. If it cannot, `None` is returned.
|
||||||
|
///
|
||||||
|
/// This function is expected to return `Some` under all normal cirumstances.
|
||||||
|
pub fn memory_map() -> Option<(usize, usize)> {
|
||||||
|
let binary_end = unsafe { (&_end as *const u8) as u32 };
|
||||||
|
|
||||||
|
let mut atags: Atags = Atags::get();
|
||||||
|
while let Some(atag) = atags.next() {
|
||||||
|
if let Some(mem) = atag.mem() {
|
||||||
|
return Some((binary_end as usize, (mem.start + mem.size) as usize));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
30
kernel/src/arch/aarch64/mod.rs
Normal file
30
kernel/src/arch/aarch64/mod.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
//! Entrance and initialization for aarch64.
|
||||||
|
|
||||||
|
extern crate atags;
|
||||||
|
extern crate cortex_a;
|
||||||
|
|
||||||
|
pub mod io;
|
||||||
|
pub mod paging;
|
||||||
|
pub mod memory;
|
||||||
|
pub mod interrupt;
|
||||||
|
pub mod consts;
|
||||||
|
|
||||||
|
#[cfg(feature = "board_raspi3")]
|
||||||
|
#[path = "board/raspi3/mod.rs"]
|
||||||
|
pub mod board;
|
||||||
|
|
||||||
|
pub use self::board::timer;
|
||||||
|
|
||||||
|
/// The entry point of kernel
|
||||||
|
#[no_mangle] // don't mangle the name of this function
|
||||||
|
pub extern "C" fn rust_main() -> ! {
|
||||||
|
// Init board to enable serial port.
|
||||||
|
board::init();
|
||||||
|
::logging::init(); // FIXME
|
||||||
|
interrupt::init();
|
||||||
|
memory::init();
|
||||||
|
timer::init();
|
||||||
|
::kmain();
|
||||||
|
}
|
||||||
|
|
||||||
|
global_asm!(include_str!("boot/boot.S"));
|
222
kernel/src/arch/aarch64/paging.rs
Normal file
222
kernel/src/arch/aarch64/paging.rs
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
//! Page table implementations for aarch64.
|
||||||
|
|
||||||
|
use ucore_memory::memory_set::*;
|
||||||
|
use ucore_memory::paging::*;
|
||||||
|
|
||||||
|
type VirtAddr = usize;
|
||||||
|
type PhysAddr = usize;
|
||||||
|
|
||||||
|
use alloc::alloc::{alloc, Layout};
|
||||||
|
use memory::{active_table, alloc_frame, alloc_stack, dealloc_frame};
|
||||||
|
|
||||||
|
/// TODO
|
||||||
|
pub struct ActivePageTable {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActivePageTable {
|
||||||
|
/// TODO
|
||||||
|
pub unsafe fn new() -> Self {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PageTable for ActivePageTable {
|
||||||
|
type Entry = PageEntry;
|
||||||
|
|
||||||
|
fn map(&mut self, addr: VirtAddr, target: PhysAddr) -> &mut Self::Entry {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
fn unmap(&mut self, addr: VirtAddr) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_entry(&mut self, addr: VirtAddr) -> &mut Self::Entry {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
// For testing with mock
|
||||||
|
fn get_page_slice_mut<'a, 'b>(&'a mut self, addr: VirtAddr) -> &'b mut [u8] {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read(&mut self, addr: VirtAddr) -> u8 {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, addr: VirtAddr, data: u8) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TODO
|
||||||
|
pub struct PageEntry {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Entry for PageEntry {
|
||||||
|
/// IMPORTANT!
|
||||||
|
/// This must be called after any change to ensure it become effective.
|
||||||
|
/// Usually this will make a flush to TLB/MMU.
|
||||||
|
fn update(&mut self) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Will be set when accessed
|
||||||
|
fn accessed(&self) -> bool {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Will be set when written
|
||||||
|
fn dirty(&self) -> bool {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Will PageFault when try to write page where writable=0
|
||||||
|
fn writable(&self) -> bool {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Will PageFault when try to access page where present=0
|
||||||
|
fn present(&self) -> bool {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_accessed(&mut self) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_dirty(&mut self) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_writable(&mut self, value: bool) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_present(&mut self, value: bool) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn target(&self) -> PhysAddr {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_target(&mut self, target: PhysAddr) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
// For Copy-on-write extension
|
||||||
|
fn writable_shared(&self) -> bool {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readonly_shared(&self) -> bool {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_shared(&mut self, writable: bool) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_shared(&mut self) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
// For Swap extension
|
||||||
|
fn swapped(&self) -> bool {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_swapped(&mut self, value: bool) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn user(&self) -> bool {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_user(&mut self, value: bool) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute(&self) -> bool {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_execute(&mut self, value: bool) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct MockFrame(PhysAddr);
|
||||||
|
|
||||||
|
impl MockFrame {
|
||||||
|
pub fn of_addr(addr: PhysAddr) -> Self {
|
||||||
|
MockFrame(addr)
|
||||||
|
}
|
||||||
|
pub fn start_address(&self) -> PhysAddr {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
pub fn p2_index(&self) -> usize {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
pub fn p1_index(&self) -> usize {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
pub fn number(&self) -> usize {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TODO
|
||||||
|
pub struct InactivePageTable0 {
|
||||||
|
p4_frame: MockFrame,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TODO
|
||||||
|
impl InactivePageTable for InactivePageTable0 {
|
||||||
|
type Active = ActivePageTable;
|
||||||
|
|
||||||
|
fn new() -> Self {
|
||||||
|
unsafe {
|
||||||
|
let layout = Layout::new::<u64>();
|
||||||
|
let ptr = alloc(layout);
|
||||||
|
let frame = MockFrame::of_addr(*ptr as usize);
|
||||||
|
InactivePageTable0 { p4_frame: frame }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_bare() -> Self {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn edit(&mut self, f: impl FnOnce(&mut Self::Active)) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn activate(&self) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn with(&self, f: impl FnOnce()) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn token(&self) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alloc_frame() -> Option<PhysAddr> {
|
||||||
|
alloc_frame()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dealloc_frame(target: PhysAddr) {
|
||||||
|
dealloc_frame(target)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alloc_stack() -> Stack {
|
||||||
|
alloc_stack()
|
||||||
|
}
|
||||||
|
}
|
@ -42,6 +42,10 @@ pub mod arch;
|
|||||||
#[path = "arch/riscv32/mod.rs"]
|
#[path = "arch/riscv32/mod.rs"]
|
||||||
pub mod arch;
|
pub mod arch;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
#[path = "arch/aarch64/mod.rs"]
|
||||||
|
pub mod arch;
|
||||||
|
|
||||||
pub fn kmain() -> ! {
|
pub fn kmain() -> ! {
|
||||||
processor().run();
|
processor().run();
|
||||||
|
|
||||||
|
@ -23,6 +23,10 @@ pub type FrameAlloc = BitAlloc64K;
|
|||||||
#[cfg(target_arch = "riscv32")]
|
#[cfg(target_arch = "riscv32")]
|
||||||
pub type FrameAlloc = BitAlloc4K;
|
pub type FrameAlloc = BitAlloc4K;
|
||||||
|
|
||||||
|
// Raspberry Pi 3 has 1G memory
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
pub type FrameAlloc = BitAlloc64K;
|
||||||
|
|
||||||
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());
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,15 @@ impl ContextImpl {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_user_test(entry: extern fn(usize) -> !) -> Self {
|
||||||
|
let ms = MemorySet::new();
|
||||||
|
let user_stack = ::memory::alloc_stack();
|
||||||
|
Context {
|
||||||
|
arch: unsafe { ArchContext::new_user_thread(entry as usize, user_stack.top - 8, ms.kstack_top(), false, ms.token()) },
|
||||||
|
memory_set: ms,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Make a new user thread from ELF data
|
/// Make a new user thread from ELF data
|
||||||
/*
|
/*
|
||||||
* @param:
|
* @param:
|
||||||
|
@ -217,6 +217,8 @@ impl MutexSupport for Spin {
|
|||||||
asm!("pause" :::: "volatile");
|
asm!("pause" :::: "volatile");
|
||||||
#[cfg(target_arch = "riscv32")]
|
#[cfg(target_arch = "riscv32")]
|
||||||
asm!("nop" :::: "volatile");
|
asm!("nop" :::: "volatile");
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
asm!("yield" :::: "volatile");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn before_lock() -> Self::GuardData {}
|
fn before_lock() -> Self::GuardData {}
|
||||||
@ -247,6 +249,8 @@ impl MutexSupport for SpinNoIrq {
|
|||||||
asm!("pause" :::: "volatile");
|
asm!("pause" :::: "volatile");
|
||||||
#[cfg(target_arch = "riscv32")]
|
#[cfg(target_arch = "riscv32")]
|
||||||
asm!("nop" :::: "volatile");
|
asm!("nop" :::: "volatile");
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
asm!("yield" :::: "volatile");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn before_lock() -> Self::GuardData {
|
fn before_lock() -> Self::GuardData {
|
||||||
|
3
tools/gdbinit
Normal file
3
tools/gdbinit
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
target remote :1234
|
||||||
|
break rust_main
|
||||||
|
continue
|
30
user/aarch64-ucore.json
Normal file
30
user/aarch64-ucore.json
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"abi-blacklist": [
|
||||||
|
"stdcall",
|
||||||
|
"fastcall",
|
||||||
|
"vectorcall",
|
||||||
|
"thiscall",
|
||||||
|
"win64",
|
||||||
|
"sysv64"
|
||||||
|
],
|
||||||
|
"arch": "aarch64",
|
||||||
|
"data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
|
||||||
|
"executables": true,
|
||||||
|
"linker": "rust-lld",
|
||||||
|
"linker-flavor": "ld.lld",
|
||||||
|
"linker-is-gnu": true,
|
||||||
|
"llvm-target": "aarch64-unknown-none",
|
||||||
|
"no-compiler-rt": true,
|
||||||
|
"features": "+a53,+strict-align,-neon",
|
||||||
|
"max-atomic-width": 128,
|
||||||
|
"os": "none",
|
||||||
|
"panic": "abort",
|
||||||
|
"panic-strategy": "abort",
|
||||||
|
"relocation-model": "static",
|
||||||
|
"position-independent-executables": true,
|
||||||
|
"target-c-int-width": "32",
|
||||||
|
"target-endian": "little",
|
||||||
|
"target-pointer-width": "64",
|
||||||
|
"target-family": "unix",
|
||||||
|
"disable-redzone": true
|
||||||
|
}
|
@ -44,6 +44,12 @@ fn sys_call(id: usize, arg0: usize, arg1: usize, arg2: usize, arg3: usize, arg4:
|
|||||||
: "{rax}" (id), "{rdi}" (arg0), "{rsi}" (arg1), "{rdx}" (arg2), "{rcx}" (arg3), "{r8}" (arg4), "{r9}" (arg5)
|
: "{rax}" (id), "{rdi}" (arg0), "{rsi}" (arg1), "{rdx}" (arg2), "{rcx}" (arg3), "{r8}" (arg4), "{r9}" (arg5)
|
||||||
: "memory"
|
: "memory"
|
||||||
: "intel" "volatile");
|
: "intel" "volatile");
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
asm!("svc 0"
|
||||||
|
: "={x0}" (ret)
|
||||||
|
: "{x8}" (id), "{x0}" (arg0), "{x1}" (arg1), "{x2}" (arg2), "{x3}" (arg3), "{x4}" (arg4), "{x5}" (arg5)
|
||||||
|
: "memory"
|
||||||
|
: "volatile");
|
||||||
}
|
}
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
@ -68,7 +74,7 @@ pub fn sys_open(path: &str, flags: usize) -> i32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn sys_close(fd: usize) -> i32 {
|
pub fn sys_close(fd: usize) -> i32 {
|
||||||
sys_call(SYS_CLOSE, fd, 0 , 0, 0, 0, 0)
|
sys_call(SYS_CLOSE, fd, 0, 0, 0, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fork the current process. Return the child's PID.
|
/// Fork the current process. Return the child's PID.
|
||||||
|
Loading…
Reference in New Issue
Block a user