Initial documentation
This commit is contained in:
parent
2b5aa03505
commit
e85116c5aa
@ -6,13 +6,13 @@
|
||||
const_trait_impl,
|
||||
const_panic
|
||||
)]
|
||||
// #![warn(missing_docs)]
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
extern crate std;
|
||||
|
||||
pub mod virt;
|
||||
#[deny(missing_docs)]
|
||||
pub mod phys;
|
||||
|
||||
trait Address {}
|
||||
|
@ -1,21 +1,24 @@
|
||||
//! Module for handling physical memory addresses
|
||||
|
||||
use crate::{AddressSpace, TrivialConvert, VirtualAddress};
|
||||
use core::convert::TryFrom;
|
||||
use core::fmt;
|
||||
use core::iter::Step;
|
||||
use core::ops::{Add, AddAssign, Sub, SubAssign};
|
||||
|
||||
/// Wrapper struct for representing a physical address
|
||||
#[repr(transparent)]
|
||||
#[derive(PartialEq, PartialOrd, Copy, Clone)]
|
||||
pub struct PhysicalAddress(usize);
|
||||
|
||||
// Arithmetic
|
||||
impl<A: Into<usize>> Add<A> for PhysicalAddress {
|
||||
impl const Add<usize> for PhysicalAddress {
|
||||
type Output = Self;
|
||||
|
||||
#[inline(always)]
|
||||
fn add(self, rhs: A) -> Self {
|
||||
fn add(self, rhs: usize) -> Self {
|
||||
// Will panic on overflow
|
||||
Self::from(self.0 + rhs.into())
|
||||
Self::from(self.0 + rhs)
|
||||
}
|
||||
}
|
||||
impl<A: Into<usize>> AddAssign<A> for PhysicalAddress {
|
||||
@ -25,7 +28,7 @@ impl<A: Into<usize>> AddAssign<A> for PhysicalAddress {
|
||||
*self = Self::from(self.0 + rhs.into());
|
||||
}
|
||||
}
|
||||
impl Sub<usize> for PhysicalAddress {
|
||||
impl const Sub<usize> for PhysicalAddress {
|
||||
type Output = Self;
|
||||
|
||||
#[inline(always)]
|
||||
@ -41,28 +44,23 @@ impl SubAssign<usize> for PhysicalAddress {
|
||||
}
|
||||
|
||||
// Construction
|
||||
impl From<usize> for PhysicalAddress {
|
||||
impl const From<usize> for PhysicalAddress {
|
||||
fn from(p: usize) -> Self {
|
||||
Self(p)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
impl From<u64> for PhysicalAddress {
|
||||
impl const From<u64> for PhysicalAddress {
|
||||
fn from(p: u64) -> Self {
|
||||
Self(p as usize)
|
||||
}
|
||||
}
|
||||
|
||||
impl PhysicalAddress {
|
||||
pub const fn new(value: usize) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
|
||||
pub const fn add(self, value: usize) -> Self {
|
||||
Self(self.0 + value)
|
||||
}
|
||||
|
||||
/// Computes a signed difference between `start` and `end`
|
||||
/// addresses. Will panic if the result cannot be represented due to
|
||||
/// overflow.
|
||||
#[inline(always)]
|
||||
pub fn diff(start: PhysicalAddress, end: PhysicalAddress) -> isize {
|
||||
if end >= start {
|
||||
@ -72,16 +70,24 @@ impl PhysicalAddress {
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes a signed difference between `start` and `end`, does not check for
|
||||
/// overflow condition.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Does not check for signed integer overflow.
|
||||
#[inline(always)]
|
||||
pub fn diff_unchecked(start: PhysicalAddress, end: PhysicalAddress) -> isize {
|
||||
pub unsafe fn diff_unchecked(start: PhysicalAddress, end: PhysicalAddress) -> isize {
|
||||
end.0 as isize - start.0 as isize
|
||||
}
|
||||
|
||||
/// Returns `true` if the address is page-aligned
|
||||
#[inline(always)]
|
||||
pub const fn is_paligned(self) -> bool {
|
||||
return self.0 & 0xFFF == 0
|
||||
self.0 & 0xFFF == 0
|
||||
}
|
||||
|
||||
/// Returns the index of the 4K page containing the address
|
||||
#[inline(always)]
|
||||
pub const fn page_index(self) -> usize {
|
||||
self.0 >> 12
|
||||
@ -103,7 +109,7 @@ impl const From<PhysicalAddress> for usize {
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
impl From<PhysicalAddress> for u64 {
|
||||
impl const From<PhysicalAddress> for u64 {
|
||||
#[inline(always)]
|
||||
fn from(p: PhysicalAddress) -> Self {
|
||||
p.0 as u64
|
||||
|
45
build.sh
45
build.sh
@ -18,18 +18,39 @@ if [ "$PROFILE" = "release" ]; then
|
||||
CARGO_OPTS="$CARGO_OPTS --release"
|
||||
fi
|
||||
|
||||
cd kernel
|
||||
cargo build ${CARGO_OPTS}
|
||||
cd ..
|
||||
|
||||
case $ARCH in
|
||||
aarch64)
|
||||
${LLVM_BIN}/llvm-objcopy -O binary ${OUT_DIR}/kernel ${OUT_DIR}/kernel.bin
|
||||
case $1 in
|
||||
""|build)
|
||||
CARGO_CMD=build
|
||||
;;
|
||||
x86_64)
|
||||
mkdir -p ${OUT_DIR}/cdrom/boot/grub
|
||||
cp etc/x86_64-none.grub ${OUT_DIR}/cdrom/boot/grub/grub.cfg
|
||||
cp ${OUT_DIR}/kernel ${OUT_DIR}/cdrom/boot/kernel.elf
|
||||
grub-mkrescue -o ${OUT_DIR}/cdrom.iso ${OUT_DIR}/cdrom
|
||||
clean)
|
||||
CARGO_CMD=clean
|
||||
;;
|
||||
clippy)
|
||||
CARGO_CMD=clippy
|
||||
;;
|
||||
doc)
|
||||
shift
|
||||
if [ x$1 = xopen ]; then
|
||||
CARGO_OPTS="$CARGO_OPTS --open"
|
||||
fi
|
||||
CARGO_CMD=doc
|
||||
;;
|
||||
esac
|
||||
|
||||
cd kernel
|
||||
cargo ${CARGO_CMD} ${CARGO_OPTS}
|
||||
cd ..
|
||||
|
||||
if [ ${CARGO_CMD} = "build" ]; then
|
||||
case $ARCH in
|
||||
aarch64)
|
||||
${LLVM_BIN}/llvm-objcopy -O binary ${OUT_DIR}/kernel ${OUT_DIR}/kernel.bin
|
||||
;;
|
||||
x86_64)
|
||||
mkdir -p ${OUT_DIR}/cdrom/boot/grub
|
||||
cp etc/x86_64-none.grub ${OUT_DIR}/cdrom/boot/grub/grub.cfg
|
||||
cp ${OUT_DIR}/kernel ${OUT_DIR}/cdrom/boot/kernel.elf
|
||||
grub-mkrescue -o ${OUT_DIR}/cdrom.iso ${OUT_DIR}/cdrom
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
@ -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,
|
||||
|
@ -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() } }
|
||||
|
Loading…
x
Reference in New Issue
Block a user