Test UART echo

This commit is contained in:
Mark Poliakov 2021-09-24 10:31:10 +03:00
parent 98bf52ad06
commit 2b5aa03505
14 changed files with 235 additions and 9 deletions

3
Cargo.lock generated
View File

@ -32,8 +32,11 @@ version = "0.1.0"
name = "kernel"
version = "0.1.0"
dependencies = [
"address",
"cfg-if",
"cortex-a",
"error",
"tock-registers",
]
[[package]]

View File

@ -6,4 +6,5 @@ pub enum Errno {
DoesNotExist,
NotADirectory,
OutOfMemory,
WouldBlock,
}

View File

@ -11,6 +11,9 @@ test = false
[dependencies]
cfg-if = "1.x.x"
error = { path = "../error" }
address = { path = "../address" }
tock-registers = "0.7.x"
[target.'cfg(target_arch = "aarch64")'.dependencies]
cortex-a = { version = "6.x.x" }

View File

@ -3,8 +3,16 @@ use cortex_a::asm;
#[no_mangle]
fn __aa64_bsp_main() {
debugln!("Test");
use crate::arch::machine;
use crate::dev::{Device, serial::SerialDevice};
unsafe {
machine::console().lock().enable().unwrap();
}
loop {
asm::wfe();
let ch = unsafe { machine::console().lock().recv(true).unwrap() };
debugln!("{:#04x} = '{}'!", ch, ch as char);
}
}

View File

@ -0,0 +1,11 @@
use crate::dev::serial::{pl011::Pl011, SerialDevice};
use crate::sync::Spin;
pub const UART0_BASE: usize = 0x09000000;
#[inline]
pub fn console() -> &'static Spin<impl SerialDevice> {
&UART0
}
static UART0: Spin<Pl011> = Spin::new(unsafe { Pl011::new(UART0_BASE) });

View File

@ -1 +1,9 @@
pub mod boot;
cfg_if! {
if #[cfg(feature = "mach_qemu")] {
pub mod mach_qemu;
pub use mach_qemu as machine;
}
}

View File

@ -3,5 +3,33 @@ cfg_if! {
pub mod aarch64;
pub use aarch64 as platform;
pub use aarch64::machine;
}
}
// TODO move to mod io
use core::ops::Deref;
use core::marker::PhantomData;
pub struct MemoryIo<T> {
base: usize,
_pd: PhantomData<fn() -> T>,
}
impl<T> MemoryIo<T> {
pub const unsafe fn new(base: usize) -> Self {
Self {
base,
_pd: PhantomData
}
}
}
impl<T> Deref for MemoryIo<T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
unsafe { &*(self.base as *const _) }
}
}

View File

@ -1,13 +1,18 @@
use crate::dev::serial::SerialDevice;
use crate::sync::Spin;
use core::fmt;
struct Output;
struct SerialOutput<T: 'static + SerialDevice> {
inner: &'static Spin<T>,
}
impl fmt::Write for Output {
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() {
// XXX
unsafe {
core::ptr::write_volatile(0x09000000 as *mut u32, byte as u32);
// TODO check for errors
drop(lock.send(byte));
}
}
Ok(())
@ -25,6 +30,8 @@ macro_rules! debugln {
}
pub fn _debug(args: fmt::Arguments) {
use crate::arch::machine;
use fmt::Write;
drop(Output {}.write_fmt(args));
drop(SerialOutput { inner: machine::console() }.write_fmt(args));
}

9
kernel/src/dev/mod.rs Normal file
View File

@ -0,0 +1,9 @@
use error::Errno;
pub mod serial;
pub trait Device {
fn name() -> &'static str;
unsafe fn enable(&mut self) -> Result<(), Errno>;
}

View File

@ -0,0 +1,9 @@
use crate::dev::Device;
use error::Errno;
pub mod pl011;
pub trait SerialDevice: Device {
unsafe fn send(&mut self, byte: u8) -> Result<(), Errno>;
unsafe fn recv(&mut self, blocking: bool) -> Result<u8, Errno>;
}

View File

@ -0,0 +1,90 @@
use crate::arch::MemoryIo;
use crate::dev::{serial::SerialDevice, Device};
use error::Errno;
use tock_registers::{
interfaces::{Readable, Writeable},
register_bitfields, register_structs,
registers::{ReadOnly, ReadWrite, WriteOnly},
};
#[repr(transparent)]
pub struct Pl011 {
regs: MemoryIo<Regs>,
}
register_bitfields! {
u32,
FR [
TXFF OFFSET(5) NUMBITS(1) [],
RXFE OFFSET(4) NUMBITS(1) [],
BUSY OFFSET(3) NUMBITS(1) [],
],
CR [
RXE OFFSET(9) NUMBITS(1) [],
TXE OFFSET(8) NUMBITS(1) [],
UARTEN OFFSET(0) NUMBITS(1) [],
],
ICR [
ALL OFFSET(0) NUMBITS(11) []
]
}
register_structs! {
#[allow(non_snake_case)]
Regs {
(0x00 => DR: ReadWrite<u32>),
(0x04 => _res1),
(0x18 => FR: ReadOnly<u32, FR::Register>),
(0x2C => LCR_H: ReadWrite<u32>),
(0x30 => CR: ReadWrite<u32, CR::Register>),
(0x44 => ICR: WriteOnly<u32, ICR::Register>),
(0x04 => @END),
}
}
impl SerialDevice for Pl011 {
unsafe fn send(&mut self, byte: u8) -> Result<(), Errno> {
while self.regs.FR.matches_all(FR::TXFF::SET) {
core::hint::spin_loop();
}
self.regs.DR.set(byte as u32);
Ok(())
}
unsafe fn recv(&mut self, blocking: bool) -> Result<u8, Errno> {
if self.regs.FR.matches_all(FR::RXFE::SET) {
if !blocking {
return Err(Errno::WouldBlock);
}
while self.regs.FR.matches_all(FR::RXFE::SET) {
core::hint::spin_loop();
}
}
Ok(self.regs.DR.get() as u8)
}
}
impl Device for Pl011 {
fn name() -> &'static str {
"PL011 UART"
}
unsafe fn enable(&mut self) -> Result<(), Errno> {
self.regs.CR.set(0);
self.regs.ICR.write(ICR::ALL::CLEAR);
self.regs
.CR
.write(CR::UARTEN::SET + CR::TXE::SET + CR::RXE::SET);
Ok(())
}
}
impl Pl011 {
pub const unsafe fn new(base: usize) -> Self {
Self {
regs: MemoryIo::new(base),
}
}
}

View File

@ -1,5 +1,10 @@
#![feature(global_asm)]
#![feature(
global_asm,
const_for,
const_mut_refs,
const_raw_ptr_deref,
const_fn_fn_ptr_basics
)]
#![no_std]
#![no_main]
@ -9,7 +14,9 @@ extern crate cfg_if;
#[macro_use]
pub mod debug;
pub mod arch;
pub mod dev;
pub mod mem;
pub mod sync;
#[panic_handler]
fn panic_handler(_pi: &core::panic::PanicInfo) -> ! {

42
kernel/src/sync.rs Normal file
View File

@ -0,0 +1,42 @@
use core::ops::{Deref, DerefMut};
use core::cell::UnsafeCell;
#[repr(transparent)]
pub struct NullLock<T: ?Sized> {
value: UnsafeCell<T>
}
#[repr(transparent)]
pub struct NullLockGuard<'a, T: ?Sized> {
value: &'a mut T
}
impl<T> NullLock<T> {
#[inline(always)]
pub const fn new(value: T) -> Self {
Self { value: UnsafeCell::new(value) }
}
#[inline(always)]
pub fn lock(&self) -> NullLockGuard<T> {
NullLockGuard { value: unsafe { &mut *self.value.get() } }
}
}
impl<T: ?Sized> Deref for NullLockGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.value
}
}
impl<T: ?Sized> DerefMut for NullLockGuard<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.value
}
}
unsafe impl<T: ?Sized> Sync for NullLock<T> {}
pub use NullLock as Spin;

View File

@ -33,4 +33,4 @@ case $ARCH in
;;
esac
qemu-system-${ARCH} ${QEMU_OPTS} $@
${QEMU_PREFIX}qemu-system-${ARCH} ${QEMU_OPTS} $@