# 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.rstoolchain_update
commit
2daf8c188d
@ -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"
|
@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "atags"
|
||||
version = "0.1.0"
|
||||
authors = ["koumingyang <1761674434@qq.com>"]
|
||||
|
||||
[dependencies]
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
#![no_std]
|
||||
|
||||
mod raw;
|
||||
mod atag;
|
||||
|
||||
pub mod atags;
|
@ -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
|
||||
}
|
@ -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"
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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;
|
@ -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()
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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") }
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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!");
|
||||
}
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
@ -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*) }
|
||||
}
|
@ -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;
|
@ -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)
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
@ -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
|
@ -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()
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
@ -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"));
|
@ -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()
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
target remote :1234
|
||||
break rust_main
|
||||
continue
|
@ -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
|
||||
}
|
Loading…
Reference in new issue