Initial documentation
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
use cortex_a::asm;
|
||||
//! aarch64 common boot logic
|
||||
|
||||
#[no_mangle]
|
||||
fn __aa64_bsp_main() {
|
||||
@@ -11,7 +11,7 @@ fn __aa64_bsp_main() {
|
||||
}
|
||||
|
||||
loop {
|
||||
let ch = unsafe { machine::console().lock().recv(true).unwrap() };
|
||||
let ch = machine::console().lock().recv(true).unwrap();
|
||||
debugln!("{:#04x} = '{}'!", ch, ch as char);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
//! QEMU virt machine
|
||||
|
||||
use crate::dev::serial::{pl011::Pl011, SerialDevice};
|
||||
use crate::sync::Spin;
|
||||
|
||||
pub const UART0_BASE: usize = 0x09000000;
|
||||
const UART0_BASE: usize = 0x09000000;
|
||||
|
||||
/// Returns primary console for this machine
|
||||
#[inline]
|
||||
pub fn console() -> &'static Spin<impl SerialDevice> {
|
||||
&UART0
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//! aarch64 architecture implementation
|
||||
|
||||
pub mod boot;
|
||||
|
||||
cfg_if! {
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
//! Architecture-specific detail module
|
||||
//!
|
||||
//! Contains two module aliases, which may or may not point
|
||||
//! the same architecture module:
|
||||
//!
|
||||
//! * [platform] - architecture details (e.g. aarch64)
|
||||
//! * [machine] - particular machine implementation (e.g. bcm2837)
|
||||
//!
|
||||
//! Modules visible in the documentation will depend on
|
||||
//! build target platform.
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(target_arch = "aarch64")] {
|
||||
pub mod aarch64;
|
||||
@@ -11,12 +22,18 @@ cfg_if! {
|
||||
use core::ops::Deref;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
/// Wrapper for setting up memory-mapped registers and IO
|
||||
pub struct MemoryIo<T> {
|
||||
base: usize,
|
||||
_pd: PhantomData<fn() -> T>,
|
||||
}
|
||||
|
||||
impl<T> MemoryIo<T> {
|
||||
/// Constructs a new instance of MMIO region.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Does not perform `base` validation.
|
||||
pub const unsafe fn new(base: usize) -> Self {
|
||||
Self {
|
||||
base,
|
||||
|
||||
+13
-5
@@ -1,3 +1,8 @@
|
||||
//! Debug output module.
|
||||
//!
|
||||
//! The module provides [debug!] and [debugln!] macros
|
||||
//! which can be used in similar way to print! and
|
||||
//! println! from std.
|
||||
use crate::dev::serial::SerialDevice;
|
||||
use crate::sync::Spin;
|
||||
use core::fmt;
|
||||
@@ -10,28 +15,31 @@ impl<T: SerialDevice> fmt::Write for SerialOutput<T> {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
let mut lock = self.inner.lock();
|
||||
for &byte in s.as_bytes() {
|
||||
unsafe {
|
||||
// TODO check for errors
|
||||
drop(lock.send(byte));
|
||||
}
|
||||
// TODO check for errors
|
||||
lock.send(byte).ok();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a debug message to debug output
|
||||
#[macro_export]
|
||||
macro_rules! debug {
|
||||
($($it:tt)+) => ($crate::debug::_debug(format_args!($($it)+)))
|
||||
}
|
||||
|
||||
/// Writes a debug message, followed by a newline, to debug output
|
||||
///
|
||||
/// See [debug!]
|
||||
#[macro_export]
|
||||
macro_rules! debugln {
|
||||
($($it:tt)+) => (debug!("{}\n", format_args!($($it)+)))
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn _debug(args: fmt::Arguments) {
|
||||
use crate::arch::machine;
|
||||
use fmt::Write;
|
||||
|
||||
drop(SerialOutput { inner: machine::console() }.write_fmt(args));
|
||||
SerialOutput { inner: machine::console() }.write_fmt(args).ok();
|
||||
}
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
//! Module for device interfaces and drivers
|
||||
|
||||
use error::Errno;
|
||||
|
||||
pub mod serial;
|
||||
|
||||
/// Generic device trait
|
||||
pub trait Device {
|
||||
/// Returns device type/driver name
|
||||
fn name() -> &'static str;
|
||||
|
||||
/// Performs device initialization logic.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Marked unsafe as it may cause direct hardware-specific side-effects.
|
||||
/// Additionally, may be called twice with undefined results.
|
||||
unsafe fn enable(&mut self) -> Result<(), Errno>;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
//! Module for serial device drivers
|
||||
|
||||
use crate::dev::Device;
|
||||
use error::Errno;
|
||||
|
||||
pub mod pl011;
|
||||
|
||||
/// Generic interface for serial devices
|
||||
pub trait SerialDevice: Device {
|
||||
unsafe fn send(&mut self, byte: u8) -> Result<(), Errno>;
|
||||
unsafe fn recv(&mut self, blocking: bool) -> Result<u8, Errno>;
|
||||
/// Transmits (blocking) a byte through the serial device
|
||||
fn send(&mut self, byte: u8) -> Result<(), Errno>;
|
||||
/// Receives a byte through the serial interface.
|
||||
///
|
||||
/// If `blocking` is `false` and there's no data in device's queue,
|
||||
/// will return [Errno::WouldBlock].
|
||||
fn recv(&mut self, blocking: bool) -> Result<u8, Errno>;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//! PL011 - ARM PrimeCell UART implementation
|
||||
|
||||
use crate::arch::MemoryIo;
|
||||
use crate::dev::{serial::SerialDevice, Device};
|
||||
use error::Errno;
|
||||
@@ -7,6 +9,7 @@ use tock_registers::{
|
||||
registers::{ReadOnly, ReadWrite, WriteOnly},
|
||||
};
|
||||
|
||||
/// Device struct for PL011
|
||||
#[repr(transparent)]
|
||||
pub struct Pl011 {
|
||||
regs: MemoryIo<Regs>,
|
||||
@@ -14,36 +17,52 @@ pub struct Pl011 {
|
||||
|
||||
register_bitfields! {
|
||||
u32,
|
||||
/// Flag register
|
||||
FR [
|
||||
/// Transmit FIFO full
|
||||
TXFF OFFSET(5) NUMBITS(1) [],
|
||||
/// Receive FIFO empty
|
||||
RXFE OFFSET(4) NUMBITS(1) [],
|
||||
/// UART busy
|
||||
BUSY OFFSET(3) NUMBITS(1) [],
|
||||
],
|
||||
/// Control register
|
||||
CR [
|
||||
/// Enable UART receiver
|
||||
RXE OFFSET(9) NUMBITS(1) [],
|
||||
/// Enable UART transmitter
|
||||
TXE OFFSET(8) NUMBITS(1) [],
|
||||
/// Enable UART
|
||||
UARTEN OFFSET(0) NUMBITS(1) [],
|
||||
],
|
||||
/// Interrupt clear register
|
||||
ICR [
|
||||
/// Writing this to ICR clears all IRQs
|
||||
ALL OFFSET(0) NUMBITS(11) []
|
||||
]
|
||||
}
|
||||
|
||||
register_structs! {
|
||||
/// PL011 registers
|
||||
#[allow(non_snake_case)]
|
||||
Regs {
|
||||
/// Data register
|
||||
(0x00 => DR: ReadWrite<u32>),
|
||||
(0x04 => _res1),
|
||||
/// Flag register
|
||||
(0x18 => FR: ReadOnly<u32, FR::Register>),
|
||||
/// Line control register
|
||||
(0x2C => LCR_H: ReadWrite<u32>),
|
||||
/// Control register
|
||||
(0x30 => CR: ReadWrite<u32, CR::Register>),
|
||||
/// Interrupt clear register
|
||||
(0x44 => ICR: WriteOnly<u32, ICR::Register>),
|
||||
(0x04 => @END),
|
||||
}
|
||||
}
|
||||
|
||||
impl SerialDevice for Pl011 {
|
||||
unsafe fn send(&mut self, byte: u8) -> Result<(), Errno> {
|
||||
fn send(&mut self, byte: u8) -> Result<(), Errno> {
|
||||
while self.regs.FR.matches_all(FR::TXFF::SET) {
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
@@ -51,7 +70,7 @@ impl SerialDevice for Pl011 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn recv(&mut self, blocking: bool) -> Result<u8, Errno> {
|
||||
fn recv(&mut self, blocking: bool) -> Result<u8, Errno> {
|
||||
if self.regs.FR.matches_all(FR::RXFE::SET) {
|
||||
if !blocking {
|
||||
return Err(Errno::WouldBlock);
|
||||
@@ -82,6 +101,11 @@ impl Device for Pl011 {
|
||||
}
|
||||
|
||||
impl Pl011 {
|
||||
/// Constructs an instance of PL011 device.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Does not perform `base` validation.
|
||||
pub const unsafe fn new(base: usize) -> Self {
|
||||
Self {
|
||||
regs: MemoryIo::new(base),
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
|
||||
#[macro_use]
|
||||
extern crate cfg_if;
|
||||
|
||||
@@ -16,6 +17,7 @@ pub mod debug;
|
||||
pub mod arch;
|
||||
pub mod dev;
|
||||
pub mod mem;
|
||||
#[deny(missing_docs)]
|
||||
pub mod sync;
|
||||
|
||||
#[panic_handler]
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
//! Memory management and functions module
|
||||
|
||||
/// Implements the rust language dependency for memcpy(3p) function.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe: writes to arbitrary memory locations, performs no pointer
|
||||
/// validation.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn memcpy(dst: *mut u8, src: *mut u8, mut len: usize) -> *mut u8 {
|
||||
while len != 0 {
|
||||
|
||||
@@ -1,22 +1,31 @@
|
||||
//! Synchronization facilities module
|
||||
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use core::cell::UnsafeCell;
|
||||
|
||||
/// Dummy lock implementation, does not do any locking.
|
||||
///
|
||||
/// Only safe to use before I implement context switching or
|
||||
/// interrupts are enabled.
|
||||
#[repr(transparent)]
|
||||
pub struct NullLock<T: ?Sized> {
|
||||
value: UnsafeCell<T>
|
||||
}
|
||||
|
||||
/// Dummy lock guard for [NullLock].
|
||||
#[repr(transparent)]
|
||||
pub struct NullLockGuard<'a, T: ?Sized> {
|
||||
value: &'a mut T
|
||||
}
|
||||
|
||||
impl<T> NullLock<T> {
|
||||
/// Constructs a new instance of the lock, wrapping `value`
|
||||
#[inline(always)]
|
||||
pub const fn new(value: T) -> Self {
|
||||
Self { value: UnsafeCell::new(value) }
|
||||
}
|
||||
|
||||
/// Returns [NullLockGuard] for this lock
|
||||
#[inline(always)]
|
||||
pub fn lock(&self) -> NullLockGuard<T> {
|
||||
NullLockGuard { value: unsafe { &mut *self.value.get() } }
|
||||
|
||||
Reference in New Issue
Block a user