1
0
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:
WangRunji 2018-11-19 20:31:33 +08:00
commit 2daf8c188d
46 changed files with 2083 additions and 49 deletions

5
.gitignore vendored
View File

@ -6,3 +6,8 @@ target
/crate/bbl/Cargo.lock
/crate/sync/Cargo.lock
/crate/process/Cargo.lock
.DS_Store
# for eclipse
.project

14
crate/atags/Cargo.lock generated Normal file
View 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
View 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
View 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
View 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
View File

@ -0,0 +1,6 @@
#![no_std]
mod raw;
mod atag;
pub mod atags;

67
crate/atags/src/raw.rs Normal file
View 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
View 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
View 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
}
}

View 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
View 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;

View 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()
}
}

View 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
}
}

View 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") }
}
}

View 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
View File

@ -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"

View File

@ -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"

View File

@ -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

View 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
}

View 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();
}
}

View 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!");
}

View 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();

View 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);
}

View 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

View 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*) }
}

View 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;

View 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)
}
}

View 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;
}

View 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);
}

View 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),
}
}
}

View 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

View 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

View 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()
}
}

View 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
}

View 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"));

View 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()
}
}

View File

@ -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();

View File

@ -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());
}

View File

@ -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:

View File

@ -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 {

3
tools/gdbinit Normal file
View File

@ -0,0 +1,3 @@
target remote :1234
break rust_main
continue

30
user/aarch64-ucore.json Normal file
View 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
}

View File

@ -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.