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
7
.gitignore
vendored
7
.gitignore
vendored
@ -5,4 +5,9 @@ target
|
||||
/crate/memory/Cargo.lock
|
||||
/crate/bbl/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)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atags"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "bare-metal"
|
||||
version = "0.2.4"
|
||||
@ -28,6 +32,14 @@ dependencies = [
|
||||
name = "bbl"
|
||||
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]]
|
||||
name = "bit-allocator"
|
||||
version = "0.1.0"
|
||||
@ -72,6 +84,14 @@ name = "cfg-if"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cortex-a"
|
||||
version = "2.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"register 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fixedvec"
|
||||
version = "0.2.3"
|
||||
@ -179,6 +199,14 @@ dependencies = [
|
||||
"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]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.1"
|
||||
@ -256,6 +284,11 @@ dependencies = [
|
||||
"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]]
|
||||
name = "uart_16550"
|
||||
version = "0.1.0"
|
||||
@ -270,12 +303,15 @@ name = "ucore"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"apic 0.1.0 (git+https://github.com/wangrunji0408/APIC-Rust)",
|
||||
"atags 0.1.0",
|
||||
"bbl 0.1.0",
|
||||
"bcm2837 0.1.0",
|
||||
"bit-allocator 0.1.0",
|
||||
"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)",
|
||||
"bootloader 0.3.4 (git+https://github.com/wangrunji0408/bootloader)",
|
||||
"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)",
|
||||
"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)",
|
||||
@ -288,7 +324,7 @@ dependencies = [
|
||||
"uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ucore-memory 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)",
|
||||
"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]]
|
||||
name = "volatile"
|
||||
version = "0.1.0"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[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 cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
|
||||
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
|
||||
"checksum cortex-a 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2b187d0d728b4a99ba1d79f9671b976bcdd71a8a2c719585218fd2dc14a4d08c"
|
||||
"checksum fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6c16d316ccdac21a4dd648e314e76facbbaf316e83ca137d0857a9c07419d0"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
@ -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 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 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 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"
|
||||
@ -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 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 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 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 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-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"
|
||||
|
@ -7,6 +7,7 @@ edition = "2018"
|
||||
[features]
|
||||
link_user_program = []
|
||||
no_bbl = []
|
||||
board_raspi3 = []
|
||||
|
||||
[profile.dev]
|
||||
# MUST >= 1 : Enable RVO to avoid stack overflow
|
||||
@ -22,7 +23,7 @@ once = "0.3"
|
||||
xmas-elf = "0.6"
|
||||
bitflags = "1.0"
|
||||
bit_field = "0.9"
|
||||
volatile = "0.1"
|
||||
volatile = "0.2"
|
||||
linked_list_allocator = "0.6"
|
||||
lazy_static = { version = "1.2", features = ["spin_no_std"] }
|
||||
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" }
|
||||
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]
|
||||
default-target = "x86_64-blog_os.json"
|
||||
output = "target/x86_64-blog_os/bootimage.bin"
|
||||
|
110
kernel/Makefile
110
kernel/Makefile
@ -8,14 +8,17 @@
|
||||
# make clean Clean
|
||||
#
|
||||
# Options:
|
||||
# arch = x86_64 | riscv32
|
||||
# arch = x86_64 | riscv32 | aarch64
|
||||
# d = int | in_asm | ... QEMU debug info
|
||||
# mode = debug | release
|
||||
# LOG = off | error | warn | info | debug | trace
|
||||
# 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
|
||||
board ?= raspi3
|
||||
prefix ?= $(arch)-none-elf
|
||||
mode ?= debug
|
||||
LOG ?= debug
|
||||
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_obj := build/$(arch)/user.o
|
||||
SFSIMG := ../user/ucore32.img
|
||||
|
||||
### qemu options ###
|
||||
ifeq ($(arch), x86_64)
|
||||
qemu_opts := \
|
||||
-drive format=raw,file=$(bootimage) \
|
||||
-drive format=raw,file=$(SFSIMG),media=disk,cache=writeback \
|
||||
-smp cores=$(smp) \
|
||||
-serial mon:stdio \
|
||||
-device isa-debug-exit
|
||||
endif
|
||||
ifeq ($(arch), riscv32)
|
||||
-device isa-debug-exit \
|
||||
-nographic
|
||||
else ifeq ($(arch), riscv32)
|
||||
qemu_opts := \
|
||||
-machine virt \
|
||||
-kernel $(bin) \
|
||||
-nographic \
|
||||
-smp cores=$(smp)
|
||||
else ifeq ($(arch), aarch64)
|
||||
qemu_opts := \
|
||||
-machine $(board) \
|
||||
-serial null -serial mon:stdio \
|
||||
-nographic \
|
||||
-kernel $(bin)
|
||||
endif
|
||||
|
||||
ifdef board
|
||||
ifdef d
|
||||
qemu_opts := $(qemu_opts) -d $(d)
|
||||
endif
|
||||
|
||||
### build args ###
|
||||
ifeq ($(arch), riscv32)
|
||||
ifeq ($(board), fpga)
|
||||
features := $(features) no_bbl
|
||||
endif
|
||||
endif
|
||||
|
||||
# Link user binaries at ../user
|
||||
ifdef link_user
|
||||
@ -55,37 +73,26 @@ features := $(features) link_user_program
|
||||
assembly_object_files := $(assembly_object_files) $(user_obj)
|
||||
endif
|
||||
|
||||
ifdef d
|
||||
qemu_opts := $(qemu_opts) -d $(d)
|
||||
endif
|
||||
|
||||
features := $(features) board_$(board)
|
||||
build_args := --target $(target).json --features "$(features)"
|
||||
|
||||
ifeq ($(mode), release)
|
||||
build_args := $(build_args) --release
|
||||
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
|
||||
objdump := $(prefix)objdump
|
||||
cc := $(prefix)gcc
|
||||
as := $(prefix)as
|
||||
### prefix ###
|
||||
ld := $(prefix)-ld
|
||||
objdump := $(prefix)-objdump
|
||||
objcopy := $(prefix)-objcopy
|
||||
cc := $(prefix)-gcc
|
||||
as := $(prefix)-as
|
||||
gdb := $(prefix)-gdb
|
||||
|
||||
.PHONY: all clean run build asm doc justrun kernel
|
||||
|
||||
all: $(kernel)
|
||||
all: kernel
|
||||
|
||||
clean:
|
||||
@cargo clean
|
||||
@ -99,8 +106,10 @@ run: build justrun
|
||||
justrun:
|
||||
@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 &
|
||||
@sleep 1
|
||||
@$(gdb) $(kernel) -x ../tools/gdbinit
|
||||
|
||||
ifeq ($(arch), x86_64)
|
||||
build: kernel
|
||||
@ -118,20 +127,24 @@ sym:
|
||||
@$(objdump) -t $(kernel) | less
|
||||
|
||||
$(bin): kernel
|
||||
ifdef board
|
||||
ifeq ($(arch), riscv32)
|
||||
ifeq ($(board), fpga)
|
||||
@cp $(kernel) $@
|
||||
else
|
||||
@cd ../riscv-pk && \
|
||||
mkdir -p build && \
|
||||
cd build && \
|
||||
../configure \
|
||||
--enable-32bit \
|
||||
--enable-logo \
|
||||
--disable-fp-emulation \
|
||||
--host=riscv64-unknown-elf \
|
||||
--with-payload=$(abspath $(kernel)) && \
|
||||
make && \
|
||||
cp bbl ../../kernel/$@
|
||||
mkdir -p build && \
|
||||
cd build && \
|
||||
../configure \
|
||||
--enable-32bit \
|
||||
--enable-logo \
|
||||
--disable-fp-emulation \
|
||||
--host=riscv64-unknown-elf \
|
||||
--with-payload=$(abspath $(kernel)) && \
|
||||
make && \
|
||||
cp bbl ../../kernel/$@
|
||||
endif
|
||||
else ifeq ($(arch), aarch64)
|
||||
$(objcopy) $(kernel) --strip-all -O binary $@
|
||||
endif
|
||||
|
||||
kernel:
|
||||
@ -148,3 +161,24 @@ endif
|
||||
$(user_obj): $(user_bins)
|
||||
@cd $(user_bin_path) && \
|
||||
$(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
|
||||
}
|
@ -32,4 +32,4 @@
|
||||
"msp430-interrupt",
|
||||
"x86-interrupt"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
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()
|
||||
}
|
||||
}
|
@ -156,4 +156,4 @@ impl INodeExt for INode {
|
||||
self.read_at(0, buf.as_mut_slice())?;
|
||||
Ok(buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,10 @@ pub mod arch;
|
||||
#[path = "arch/riscv32/mod.rs"]
|
||||
pub mod arch;
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[path = "arch/aarch64/mod.rs"]
|
||||
pub mod arch;
|
||||
|
||||
pub fn kmain() -> ! {
|
||||
processor().run();
|
||||
|
||||
|
@ -23,6 +23,10 @@ pub type FrameAlloc = BitAlloc64K;
|
||||
#[cfg(target_arch = "riscv32")]
|
||||
pub type FrameAlloc = BitAlloc4K;
|
||||
|
||||
// Raspberry Pi 3 has 1G memory
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
pub type FrameAlloc = BitAlloc64K;
|
||||
|
||||
lazy_static! {
|
||||
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
|
||||
/*
|
||||
* @param:
|
||||
|
@ -53,4 +53,4 @@ pub fn processor() -> &'static Processor {
|
||||
#[no_mangle]
|
||||
pub fn new_kernel_context(entry: extern fn(usize) -> !, arg: usize) -> Box<Context> {
|
||||
ContextImpl::new_kernel(entry, arg)
|
||||
}
|
||||
}
|
||||
|
@ -217,6 +217,8 @@ impl MutexSupport for Spin {
|
||||
asm!("pause" :::: "volatile");
|
||||
#[cfg(target_arch = "riscv32")]
|
||||
asm!("nop" :::: "volatile");
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
asm!("yield" :::: "volatile");
|
||||
}
|
||||
}
|
||||
fn before_lock() -> Self::GuardData {}
|
||||
@ -247,6 +249,8 @@ impl MutexSupport for SpinNoIrq {
|
||||
asm!("pause" :::: "volatile");
|
||||
#[cfg(target_arch = "riscv32")]
|
||||
asm!("nop" :::: "volatile");
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
asm!("yield" :::: "volatile");
|
||||
}
|
||||
}
|
||||
fn before_lock() -> Self::GuardData {
|
||||
@ -267,4 +271,4 @@ impl MutexSupport for Condvar {
|
||||
fn after_unlock(&self) {
|
||||
self.notify_one();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
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)
|
||||
: "memory"
|
||||
: "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
|
||||
}
|
||||
@ -68,7 +74,7 @@ pub fn sys_open(path: &str, flags: 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.
|
||||
@ -137,4 +143,4 @@ const SYS_FSYNC: usize = 111;
|
||||
const SYS_GETCWD: usize = 121;
|
||||
const SYS_GETDIRENTRY: usize = 128;
|
||||
const SYS_DUP: usize = 130;
|
||||
const SYS_LAB6_SET_PRIORITY: usize = 255;
|
||||
const SYS_LAB6_SET_PRIORITY: usize = 255;
|
||||
|
Loading…
Reference in New Issue
Block a user