Initial documentation

This commit is contained in:
2021-09-24 13:01:58 +03:00
parent 2b5aa03505
commit e85116c5aa
14 changed files with 160 additions and 42 deletions
+2 -2
View File
@@ -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);
}
}
+4 -1
View File
@@ -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
+2
View File
@@ -1,3 +1,5 @@
//! aarch64 architecture implementation
pub mod boot;
cfg_if! {
+17
View File
@@ -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
View File
@@ -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();
}
+10
View File
@@ -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>;
}
+10 -2
View File
@@ -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>;
}
+26 -2
View File
@@ -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),
+2
View File
@@ -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]
+8
View File
@@ -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 {
+9
View File
@@ -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() } }