Test UART echo
This commit is contained in:
parent
98bf52ad06
commit
2b5aa03505
3
Cargo.lock
generated
3
Cargo.lock
generated
@ -32,8 +32,11 @@ version = "0.1.0"
|
||||
name = "kernel"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"address",
|
||||
"cfg-if",
|
||||
"cortex-a",
|
||||
"error",
|
||||
"tock-registers",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -6,4 +6,5 @@ pub enum Errno {
|
||||
DoesNotExist,
|
||||
NotADirectory,
|
||||
OutOfMemory,
|
||||
WouldBlock,
|
||||
}
|
||||
|
@ -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" }
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
11
kernel/src/arch/aarch64/mach_qemu/mod.rs
Normal file
11
kernel/src/arch/aarch64/mach_qemu/mod.rs
Normal 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) });
|
@ -1 +1,9 @@
|
||||
pub mod boot;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "mach_qemu")] {
|
||||
pub mod mach_qemu;
|
||||
|
||||
pub use mach_qemu as machine;
|
||||
}
|
||||
}
|
||||
|
@ -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 _) }
|
||||
}
|
||||
}
|
||||
|
@ -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
9
kernel/src/dev/mod.rs
Normal 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>;
|
||||
}
|
9
kernel/src/dev/serial/mod.rs
Normal file
9
kernel/src/dev/serial/mod.rs
Normal 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>;
|
||||
}
|
90
kernel/src/dev/serial/pl011.rs
Normal file
90
kernel/src/dev/serial/pl011.rs
Normal 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),
|
||||
}
|
||||
}
|
||||
}
|
@ -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
42
kernel/src/sync.rs
Normal 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;
|
Loading…
x
Reference in New Issue
Block a user