diff --git a/03_uart1/kernel8.img b/03_uart1/kernel8.img index e5229c8e..47f2b494 100755 Binary files a/03_uart1/kernel8.img and b/03_uart1/kernel8.img differ diff --git a/03_uart1/src/uart.rs b/03_uart1/src/uart.rs index 21555567..e9edb264 100644 --- a/03_uart1/src/uart.rs +++ b/03_uart1/src/uart.rs @@ -23,6 +23,7 @@ */ use super::MMIO_BASE; +use core::ops; use gpio; use volatile_register::*; @@ -31,7 +32,7 @@ const MINI_UART_BASE: u32 = MMIO_BASE + 0x21_5000; /// Auxilary mini UART registers #[allow(non_snake_case)] #[repr(C)] -struct Registers { +pub struct RegisterBlock { __reserved_0: u32, // 0x00 ENABLES: RW, // 0x04 __reserved_1: [u32; 14], // 0x08 @@ -48,29 +49,38 @@ struct Registers { MU_BAUD: RW, // 0x68 } -pub struct MiniUart { - registers: *const Registers, +pub struct MiniUart; + +impl ops::Deref for MiniUart { + type Target = RegisterBlock; + + fn deref(&self) -> &Self::Target { + unsafe { &*Self::ptr() } + } } impl MiniUart { pub fn new() -> MiniUart { - MiniUart { - registers: MINI_UART_BASE as *const Registers, - } + MiniUart + } + + /// Returns a pointer to the register block + fn ptr() -> *const RegisterBlock { + MINI_UART_BASE as *const _ } ///Set baud rate and characteristics (115200 8N1) and map to GPIO pub fn init(&self) { // initialize UART unsafe { - (*self.registers).ENABLES.modify(|x| x | 1); // enable UART1, AUX mini uart - (*self.registers).MU_IER.write(0); - (*self.registers).MU_CNTL.write(0); - (*self.registers).MU_LCR.write(3); // 8 bits - (*self.registers).MU_MCR.write(0); - (*self.registers).MU_IER.write(0); - (*self.registers).MU_IIR.write(0xC6); // disable interrupts - (*self.registers).MU_BAUD.write(270); // 115200 baud + self.ENABLES.modify(|x| x | 1); // enable UART1, AUX mini uart + self.MU_IER.write(0); + self.MU_CNTL.write(0); + self.MU_LCR.write(3); // 8 bits + self.MU_MCR.write(0); + self.MU_IER.write(0); + self.MU_IIR.write(0xC6); // disable interrupts + self.MU_BAUD.write(270); // 115200 baud // map UART1 to GPIO pins (*gpio::GPFSEL1).modify(|x| { @@ -92,40 +102,38 @@ impl MiniUart { asm!("nop" :::: "volatile"); } (*gpio::GPPUDCLK0).write(0); // flush GPIO setup - (*self.registers).MU_CNTL.write(3); // enable Tx, Rx + self.MU_CNTL.write(3); // enable Tx, Rx } } /// Send a character pub fn send(&self, c: char) { - unsafe { - // wait until we can send - loop { - if ((*self.registers).MU_LSR.read() & 0x20) == 0x20 { - break; - } - asm!("nop" :::: "volatile"); + // wait until we can send + loop { + if (self.MU_LSR.read() & 0x20) == 0x20 { + break; } - // write the character to the buffer - (*self.registers).MU_IO.write(c as u32); + unsafe { asm!("nop" :::: "volatile") }; } + + // write the character to the buffer + unsafe { self.MU_IO.write(c as u32) }; } /// Receive a character pub fn getc(&self) -> char { - unsafe { - // wait until something is in the buffer - loop { - if ((*self.registers).MU_LSR.read() & 0x01) == 0x01 { - break; - } - asm!("nop" :::: "volatile"); + // wait until something is in the buffer + loop { + if (self.MU_LSR.read() & 0x01) == 0x01 { + break; } + + unsafe { asm!("nop" :::: "volatile") }; } // read it and return - let mut ret = unsafe { (*self.registers).MU_IO.read() as u8 as char }; + let mut ret = self.MU_IO.read() as u8 as char; // convert carrige return to newline if ret == '\r' { diff --git a/04_mailboxes/kernel8.img b/04_mailboxes/kernel8.img index f36cf015..91ac37ea 100755 Binary files a/04_mailboxes/kernel8.img and b/04_mailboxes/kernel8.img differ diff --git a/04_mailboxes/src/mbox.rs b/04_mailboxes/src/mbox.rs index 3617f964..78f43c06 100644 --- a/04_mailboxes/src/mbox.rs +++ b/04_mailboxes/src/mbox.rs @@ -23,13 +23,14 @@ */ use super::MMIO_BASE; +use core::ops; use volatile_register::{RO, WO}; const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880; #[allow(non_snake_case)] #[repr(C)] -struct Registers { +pub struct RegisterBlock { READ: RO, // 0x00 __reserved_0: [u32; 3], // 0x04 POLL: RO, // 0x10 @@ -76,33 +77,52 @@ pub struct Mbox { // data structures in Rust is a bit of a hassle right now, we just // close our eyes and roll with it. pub buffer: [u32; 36], - registers: *const Registers, +} + +/// Deref to RegisterBlock +/// +/// Allows writing +/// ``` +/// self.STATUS.read() +/// ``` +/// instead of something along the lines of +/// ``` +/// unsafe { (*Mbox::ptr()).STATUS.read() } +/// ``` +impl ops::Deref for Mbox { + type Target = RegisterBlock; + + fn deref(&self) -> &Self::Target { + unsafe { &*Self::ptr() } + } } impl Mbox { pub fn new() -> Mbox { - Mbox { - buffer: [0; 36], - registers: VIDEOCORE_MBOX as *const Registers, - } + Mbox { buffer: [0; 36] } + } + + /// Returns a pointer to the register block + fn ptr() -> *const RegisterBlock { + VIDEOCORE_MBOX as *const _ } /// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success pub fn call(&self, channel: u32) -> Result<()> { // wait until we can write to the mailbox loop { + if (self.STATUS.read() & FULL) != FULL { + break; + } + unsafe { - if ((*self.registers).STATUS.read() & FULL) != FULL { - break; - } asm!("nop" :::: "volatile"); } } // write the address of our message to the mailbox with channel identifier unsafe { - (*self.registers) - .WRITE + self.WRITE .write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF)); } @@ -110,15 +130,16 @@ impl Mbox { loop { // is there a response? loop { + if (self.STATUS.read() & EMPTY) != EMPTY { + break; + } + unsafe { - if ((*self.registers).STATUS.read() & EMPTY) != EMPTY { - break; - } asm!("nop" :::: "volatile"); } } - let resp: u32 = unsafe { (*self.registers).READ.read() }; + let resp: u32 = self.READ.read(); // is it a response to our message? if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) { diff --git a/04_mailboxes/src/uart.rs b/04_mailboxes/src/uart.rs index 77a12ff1..db12f800 100644 --- a/04_mailboxes/src/uart.rs +++ b/04_mailboxes/src/uart.rs @@ -23,6 +23,7 @@ */ use super::MMIO_BASE; +use core::ops; use gpio; use volatile_register::*; @@ -31,7 +32,7 @@ const MINI_UART_BASE: u32 = MMIO_BASE + 0x21_5000; /// Auxilary mini UART registers #[allow(non_snake_case)] #[repr(C)] -struct Registers { +pub struct RegisterBlock { __reserved_0: u32, // 0x00 ENABLES: RW, // 0x04 __reserved_1: [u32; 14], // 0x08 @@ -48,29 +49,38 @@ struct Registers { MU_BAUD: RW, // 0x68 } -pub struct MiniUart { - registers: *const Registers, +pub struct MiniUart; + +impl ops::Deref for MiniUart { + type Target = RegisterBlock; + + fn deref(&self) -> &Self::Target { + unsafe { &*Self::ptr() } + } } impl MiniUart { pub fn new() -> MiniUart { - MiniUart { - registers: MINI_UART_BASE as *const Registers, - } + MiniUart + } + + /// Returns a pointer to the register block + fn ptr() -> *const RegisterBlock { + MINI_UART_BASE as *const _ } ///Set baud rate and characteristics (115200 8N1) and map to GPIO pub fn init(&self) { // initialize UART unsafe { - (*self.registers).ENABLES.modify(|x| x | 1); // enable UART1, AUX mini uart - (*self.registers).MU_IER.write(0); - (*self.registers).MU_CNTL.write(0); - (*self.registers).MU_LCR.write(3); // 8 bits - (*self.registers).MU_MCR.write(0); - (*self.registers).MU_IER.write(0); - (*self.registers).MU_IIR.write(0xC6); // disable interrupts - (*self.registers).MU_BAUD.write(270); // 115200 baud + self.ENABLES.modify(|x| x | 1); // enable UART1, AUX mini uart + self.MU_IER.write(0); + self.MU_CNTL.write(0); + self.MU_LCR.write(3); // 8 bits + self.MU_MCR.write(0); + self.MU_IER.write(0); + self.MU_IIR.write(0xC6); // disable interrupts + self.MU_BAUD.write(270); // 115200 baud // map UART1 to GPIO pins (*gpio::GPFSEL1).modify(|x| { @@ -92,40 +102,38 @@ impl MiniUart { asm!("nop" :::: "volatile"); } (*gpio::GPPUDCLK0).write(0); // flush GPIO setup - (*self.registers).MU_CNTL.write(3); // enable Tx, Rx + self.MU_CNTL.write(3); // enable Tx, Rx } } /// Send a character pub fn send(&self, c: char) { - unsafe { - // wait until we can send - loop { - if ((*self.registers).MU_LSR.read() & 0x20) == 0x20 { - break; - } - asm!("nop" :::: "volatile"); + // wait until we can send + loop { + if (self.MU_LSR.read() & 0x20) == 0x20 { + break; } - // write the character to the buffer - (*self.registers).MU_IO.write(c as u32); + unsafe { asm!("nop" :::: "volatile") }; } + + // write the character to the buffer + unsafe { self.MU_IO.write(c as u32) }; } /// Receive a character pub fn getc(&self) -> char { - unsafe { - // wait until something is in the buffer - loop { - if ((*self.registers).MU_LSR.read() & 0x01) == 0x01 { - break; - } - asm!("nop" :::: "volatile"); + // wait until something is in the buffer + loop { + if (self.MU_LSR.read() & 0x01) == 0x01 { + break; } + + unsafe { asm!("nop" :::: "volatile") }; } // read it and return - let mut ret = unsafe { (*self.registers).MU_IO.read() as u8 as char }; + let mut ret = self.MU_IO.read() as u8 as char; // convert carrige return to newline if ret == '\r' { diff --git a/05_uart0/kernel8.img b/05_uart0/kernel8.img index f2cc1a91..b56a2d52 100755 Binary files a/05_uart0/kernel8.img and b/05_uart0/kernel8.img differ diff --git a/05_uart0/src/mbox.rs b/05_uart0/src/mbox.rs index d41fa421..de2144f6 100644 --- a/05_uart0/src/mbox.rs +++ b/05_uart0/src/mbox.rs @@ -23,13 +23,14 @@ */ use super::MMIO_BASE; +use core::ops; use volatile_register::{RO, WO}; const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880; #[allow(non_snake_case)] #[repr(C)] -struct Registers { +pub struct RegisterBlock { READ: RO, // 0x00 __reserved_0: [u32; 3], // 0x04 POLL: RO, // 0x10 @@ -82,49 +83,65 @@ pub struct Mbox { // data structures in Rust is a bit of a hassle right now, we just // close our eyes and roll with it. pub buffer: [u32; 36], - registers: *const Registers, +} + +/// Deref to RegisterBlock +/// +/// Allows writing +/// ``` +/// self.STATUS.read() +/// ``` +/// instead of something along the lines of +/// ``` +/// unsafe { (*Mbox::ptr()).STATUS.read() } +/// ``` +impl ops::Deref for Mbox { + type Target = RegisterBlock; + + fn deref(&self) -> &Self::Target { + unsafe { &*Self::ptr() } + } } impl Mbox { pub fn new() -> Mbox { - Mbox { - buffer: [0; 36], - registers: VIDEOCORE_MBOX as *const Registers, - } + Mbox { buffer: [0; 36] } + } + + /// Returns a pointer to the register block + fn ptr() -> *const RegisterBlock { + VIDEOCORE_MBOX as *const _ } /// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success pub fn call(&self, channel: u32) -> Result<()> { // wait until we can write to the mailbox loop { - unsafe { - if ((*self.registers).STATUS.read() & FULL) != FULL { - break; - } - asm!("nop" :::: "volatile"); + if (self.STATUS.read() & FULL) != FULL { + break; } + + unsafe { asm!("nop" :::: "volatile") }; } // write the address of our message to the mailbox with channel identifier unsafe { - (*self.registers) - .WRITE - .write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF)); - } + self.WRITE + .write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF)) + }; // now wait for the response loop { // is there a response? loop { - unsafe { - if ((*self.registers).STATUS.read() & EMPTY) != EMPTY { - break; - } - asm!("nop" :::: "volatile"); + if (self.STATUS.read() & EMPTY) != EMPTY { + break; } + + unsafe { asm!("nop" :::: "volatile") }; } - let resp: u32 = unsafe { (*self.registers).READ.read() }; + let resp: u32 = self.READ.read(); // is it a response to our message? if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) { diff --git a/05_uart0/src/uart.rs b/05_uart0/src/uart.rs index 522bb2dc..b79aa2b0 100644 --- a/05_uart0/src/uart.rs +++ b/05_uart0/src/uart.rs @@ -23,6 +23,7 @@ */ use super::MMIO_BASE; +use core::ops; use core::sync::atomic::{compiler_fence, Ordering}; use gpio; use mbox; @@ -33,7 +34,7 @@ const UART_BASE: u32 = MMIO_BASE + 0x20_1000; // PL011 UART registers #[allow(non_snake_case)] #[repr(C)] -struct Registers { +pub struct RegisterBlock { DR: RW, // 0x00 __reserved_0: [u32; 5], // 0x04 FR: RO, // 0x18 @@ -51,21 +52,30 @@ pub enum UartError { } pub type Result = ::core::result::Result; -pub struct Uart { - registers: *const Registers, +pub struct Uart; + +impl ops::Deref for Uart { + type Target = RegisterBlock; + + fn deref(&self) -> &Self::Target { + unsafe { &*Self::ptr() } + } } impl Uart { pub fn new() -> Uart { - Uart { - registers: UART_BASE as *const Registers, - } + Uart + } + + /// Returns a pointer to the register block + fn ptr() -> *const RegisterBlock { + UART_BASE as *const _ } ///Set baud rate and characteristics (115200 8N1) and map to GPIO pub fn init(&self, mbox: &mut mbox::Mbox) -> Result<()> { // turn off UART0 - unsafe { (*self.registers).CR.write(0) }; + unsafe { self.CR.write(0) }; // set up clock for consistent divisor values mbox.buffer[0] = 9 * 4; @@ -109,11 +119,11 @@ impl Uart { } (*gpio::GPPUDCLK0).write(0); - (*self.registers).ICR.write(0x7FF); // clear interrupts - (*self.registers).IBRD.write(2); // 115200 baud - (*self.registers).FBRD.write(0xB); - (*self.registers).LCRH.write(0b11 << 5); // 8n1 - (*self.registers).CR.write(0x301); // enable Tx, Rx, FIFO + self.ICR.write(0x7FF); // clear interrupts + self.IBRD.write(2); // 115200 baud + self.FBRD.write(0xB); + self.LCRH.write(0b11 << 5); // 8n1 + self.CR.write(0x301); // enable Tx, Rx, FIFO } Ok(()) @@ -121,34 +131,32 @@ impl Uart { /// Send a character pub fn send(&self, c: char) { - unsafe { - // wait until we can send - loop { - if ((*self.registers).FR.read() & 0x20) != 0x20 { - break; - } - asm!("nop" :::: "volatile"); + // wait until we can send + loop { + if (self.FR.read() & 0x20) != 0x20 { + break; } - // write the character to the buffer - (*self.registers).DR.write(c as u32); + unsafe { asm!("nop" :::: "volatile") }; } + + // write the character to the buffer + unsafe { self.DR.write(c as u32) }; } /// Receive a character pub fn getc(&self) -> char { - unsafe { - // wait until something is in the buffer - loop { - if ((*self.registers).FR.read() & 0x10) != 0x10 { - break; - } - asm!("nop" :::: "volatile"); + // wait until something is in the buffer + loop { + if (self.FR.read() & 0x10) != 0x10 { + break; } + + unsafe { asm!("nop" :::: "volatile") }; } // read it and return - let mut ret = unsafe { (*self.registers).DR.read() as u8 as char }; + let mut ret = self.DR.read() as u8 as char; // convert carrige return to newline if ret == '\r' { diff --git a/06_raspbootin64/kernel8.img b/06_raspbootin64/kernel8.img index a4119184..0b595b56 100755 Binary files a/06_raspbootin64/kernel8.img and b/06_raspbootin64/kernel8.img differ diff --git a/06_raspbootin64/src/mbox.rs b/06_raspbootin64/src/mbox.rs index a417ff9f..698daf93 100644 --- a/06_raspbootin64/src/mbox.rs +++ b/06_raspbootin64/src/mbox.rs @@ -23,13 +23,14 @@ */ use super::MMIO_BASE; +use core::ops; use volatile_register::{RO, WO}; const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880; #[allow(non_snake_case)] #[repr(C)] -struct Registers { +pub struct RegisterBlock { READ: RO, // 0x00 __reserved_0: [u32; 3], // 0x04 POLL: RO, // 0x10 @@ -80,50 +81,66 @@ pub struct Mbox { // to achieve that, but for now it just works. Since alignment of // data structures in Rust is a bit of a hassle right now, we just // close our eyes and roll with it. - pub buffer: [u32; 10], - registers: *const Registers, + pub buffer: [u32; 36], +} + +/// Deref to RegisterBlock +/// +/// Allows writing +/// ``` +/// self.STATUS.read() +/// ``` +/// instead of something along the lines of +/// ``` +/// unsafe { (*Mbox::ptr()).STATUS.read() } +/// ``` +impl ops::Deref for Mbox { + type Target = RegisterBlock; + + fn deref(&self) -> &Self::Target { + unsafe { &*Self::ptr() } + } } impl Mbox { pub fn new() -> Mbox { - Mbox { - buffer: [0; 10], - registers: VIDEOCORE_MBOX as *const Registers, - } + Mbox { buffer: [0; 36] } + } + + /// Returns a pointer to the register block + fn ptr() -> *const RegisterBlock { + VIDEOCORE_MBOX as *const _ } /// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success pub fn call(&self, channel: u32) -> Result<()> { // wait until we can write to the mailbox loop { - unsafe { - if ((*self.registers).STATUS.read() & FULL) != FULL { - break; - } - asm!("nop" :::: "volatile"); + if (self.STATUS.read() & FULL) != FULL { + break; } + + unsafe { asm!("nop" :::: "volatile") }; } // write the address of our message to the mailbox with channel identifier unsafe { - (*self.registers) - .WRITE - .write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF)); - } + self.WRITE + .write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF)) + }; // now wait for the response loop { // is there a response? loop { - unsafe { - if ((*self.registers).STATUS.read() & EMPTY) != EMPTY { - break; - } - asm!("nop" :::: "volatile"); + if (self.STATUS.read() & EMPTY) != EMPTY { + break; } + + unsafe { asm!("nop" :::: "volatile") }; } - let resp: u32 = unsafe { (*self.registers).READ.read() }; + let resp: u32 = self.READ.read(); // is it a response to our message? if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) { diff --git a/06_raspbootin64/src/uart.rs b/06_raspbootin64/src/uart.rs index 25b7872f..6044e590 100644 --- a/06_raspbootin64/src/uart.rs +++ b/06_raspbootin64/src/uart.rs @@ -23,6 +23,7 @@ */ use super::MMIO_BASE; +use core::ops; use core::sync::atomic::{compiler_fence, Ordering}; use gpio; use mbox; @@ -33,7 +34,7 @@ const UART_BASE: u32 = MMIO_BASE + 0x20_1000; // PL011 UART registers #[allow(non_snake_case)] #[repr(C)] -struct Registers { +pub struct RegisterBlock { DR: RW, // 0x00 __reserved_0: [u32; 5], // 0x04 FR: RO, // 0x18 @@ -51,21 +52,30 @@ pub enum UartError { } pub type Result = ::core::result::Result; -pub struct Uart { - registers: *const Registers, +pub struct Uart; + +impl ops::Deref for Uart { + type Target = RegisterBlock; + + fn deref(&self) -> &Self::Target { + unsafe { &*Self::ptr() } + } } impl Uart { pub fn new() -> Uart { - Uart { - registers: UART_BASE as *const Registers, - } + Uart + } + + /// Returns a pointer to the register block + fn ptr() -> *const RegisterBlock { + UART_BASE as *const _ } ///Set baud rate and characteristics (115200 8N1) and map to GPIO pub fn init(&self, mbox: &mut mbox::Mbox) -> Result<()> { // turn off UART0 - unsafe { (*self.registers).CR.write(0) }; + unsafe { self.CR.write(0) }; // set up clock for consistent divisor values mbox.buffer[0] = 9 * 4; @@ -109,11 +119,11 @@ impl Uart { } (*gpio::GPPUDCLK0).write(0); - (*self.registers).ICR.write(0x7FF); // clear interrupts - (*self.registers).IBRD.write(2); // 115200 baud - (*self.registers).FBRD.write(0xB); - (*self.registers).LCRH.write(0b11 << 5); // 8n1 - (*self.registers).CR.write(0x301); // enable Tx, Rx, FIFO + self.ICR.write(0x7FF); // clear interrupts + self.IBRD.write(2); // 115200 baud + self.FBRD.write(0xB); + self.LCRH.write(0b11 << 5); // 8n1 + self.CR.write(0x301); // enable Tx, Rx, FIFO } Ok(()) @@ -121,33 +131,31 @@ impl Uart { /// Send a character pub fn send(&self, c: char) { - unsafe { - // wait until we can send - loop { - if ((*self.registers).FR.read() & 0x20) != 0x20 { - break; - } - asm!("nop" :::: "volatile"); + // wait until we can send + loop { + if (self.FR.read() & 0x20) != 0x20 { + break; } - // write the character to the buffer - (*self.registers).DR.write(c as u32); + unsafe { asm!("nop" :::: "volatile") }; } + + // write the character to the buffer + unsafe { self.DR.write(c as u32) }; } /// Receive a character pub fn getc(&self) -> u8 { - unsafe { - // wait until something is in the buffer - loop { - if ((*self.registers).FR.read() & 0x10) != 0x10 { - break; - } - asm!("nop" :::: "volatile"); + // wait until something is in the buffer + loop { + if (self.FR.read() & 0x10) != 0x10 { + break; } - // read it and return - (*self.registers).DR.read() as u8 + unsafe { asm!("nop" :::: "volatile") }; } + + // read it and return + self.DR.read() as u8 } } diff --git a/07_abstraction/kernel8.img b/07_abstraction/kernel8.img index cba06573..6ede73af 100755 Binary files a/07_abstraction/kernel8.img and b/07_abstraction/kernel8.img differ diff --git a/07_abstraction/src/mbox.rs b/07_abstraction/src/mbox.rs index 96934dec..405d6056 100644 --- a/07_abstraction/src/mbox.rs +++ b/07_abstraction/src/mbox.rs @@ -23,6 +23,7 @@ */ use super::MMIO_BASE; +use core::ops; use cortex_a::asm; use volatile_register::{RO, WO}; @@ -30,7 +31,7 @@ const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880; #[allow(non_snake_case)] #[repr(C)] -struct Registers { +pub struct RegisterBlock { READ: RO, // 0x00 __reserved_0: [u32; 3], // 0x04 POLL: RO, // 0x10 @@ -83,22 +84,41 @@ pub struct Mbox { // data structures in Rust is a bit of a hassle right now, we just // close our eyes and roll with it. pub buffer: [u32; 36], - registers: *const Registers, +} + +/// Deref to RegisterBlock +/// +/// Allows writing +/// ``` +/// self.STATUS.read() +/// ``` +/// instead of something along the lines of +/// ``` +/// unsafe { (*Mbox::ptr()).STATUS.read() } +/// ``` +impl ops::Deref for Mbox { + type Target = RegisterBlock; + + fn deref(&self) -> &Self::Target { + unsafe { &*Self::ptr() } + } } impl Mbox { pub fn new() -> Mbox { - Mbox { - buffer: [0; 36], - registers: VIDEOCORE_MBOX as *const Registers, - } + Mbox { buffer: [0; 36] } + } + + /// Returns a pointer to the register block + fn ptr() -> *const RegisterBlock { + VIDEOCORE_MBOX as *const _ } /// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success pub fn call(&self, channel: u32) -> Result<()> { // wait until we can write to the mailbox loop { - if (unsafe { (*self.registers).STATUS.read() } & FULL) != FULL { + if (self.STATUS.read() & FULL) != FULL { break; } @@ -107,23 +127,22 @@ impl Mbox { // write the address of our message to the mailbox with channel identifier unsafe { - (*self.registers) - .WRITE - .write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF)); - } + self.WRITE + .write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF)) + }; // now wait for the response loop { // is there a response? loop { - if (unsafe { (*self.registers).STATUS.read() } & EMPTY) != EMPTY { + if (self.STATUS.read() & EMPTY) != EMPTY { break; } asm::nop(); } - let resp: u32 = unsafe { (*self.registers).READ.read() }; + let resp: u32 = self.READ.read(); // is it a response to our message? if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) { diff --git a/07_abstraction/src/uart.rs b/07_abstraction/src/uart.rs index 7d9cac0f..c8fd4fb5 100644 --- a/07_abstraction/src/uart.rs +++ b/07_abstraction/src/uart.rs @@ -23,6 +23,7 @@ */ use super::MMIO_BASE; +use core::ops; use core::sync::atomic::{compiler_fence, Ordering}; use cortex_a::asm; use gpio; @@ -34,7 +35,7 @@ const UART_BASE: u32 = MMIO_BASE + 0x20_1000; // PL011 UART registers #[allow(non_snake_case)] #[repr(C)] -struct Registers { +pub struct RegisterBlock { DR: RW, // 0x00 __reserved_0: [u32; 5], // 0x04 FR: RO, // 0x18 @@ -52,21 +53,30 @@ pub enum UartError { } pub type Result = ::core::result::Result; -pub struct Uart { - registers: *const Registers, +pub struct Uart; + +impl ops::Deref for Uart { + type Target = RegisterBlock; + + fn deref(&self) -> &Self::Target { + unsafe { &*Self::ptr() } + } } impl Uart { pub fn new() -> Uart { - Uart { - registers: UART_BASE as *const Registers, - } + Uart + } + + /// Returns a pointer to the register block + fn ptr() -> *const RegisterBlock { + UART_BASE as *const _ } ///Set baud rate and characteristics (115200 8N1) and map to GPIO pub fn init(&self, mbox: &mut mbox::Mbox) -> Result<()> { // turn off UART0 - unsafe { (*self.registers).CR.write(0) }; + unsafe { self.CR.write(0) }; // set up clock for consistent divisor values mbox.buffer[0] = 9 * 4; @@ -110,11 +120,11 @@ impl Uart { } (*gpio::GPPUDCLK0).write(0); - (*self.registers).ICR.write(0x7FF); // clear interrupts - (*self.registers).IBRD.write(2); // 115200 baud - (*self.registers).FBRD.write(0xB); - (*self.registers).LCRH.write(0b11 << 5); // 8n1 - (*self.registers).CR.write(0x301); // enable Tx, Rx, FIFO + self.ICR.write(0x7FF); // clear interrupts + self.IBRD.write(2); // 115200 baud + self.FBRD.write(0xB); + self.LCRH.write(0b11 << 5); // 8n1 + self.CR.write(0x301); // enable Tx, Rx, FIFO } Ok(()) @@ -124,7 +134,7 @@ impl Uart { pub fn send(&self, c: char) { // wait until we can send loop { - if (unsafe { (*self.registers).FR.read() } & 0x20) != 0x20 { + if (self.FR.read() & 0x20) != 0x20 { break; } @@ -132,14 +142,14 @@ impl Uart { } // write the character to the buffer - unsafe { (*self.registers).DR.write(c as u32) }; + unsafe { self.DR.write(c as u32) }; } /// Receive a character pub fn getc(&self) -> char { // wait until something is in the buffer loop { - if (unsafe { (*self.registers).FR.read() } & 0x10) != 0x10 { + if (self.FR.read() & 0x10) != 0x10 { break; } @@ -147,7 +157,7 @@ impl Uart { } // read it and return - let mut ret = unsafe { (*self.registers).DR.read() as u8 as char }; + let mut ret = self.DR.read() as u8 as char; // convert carrige return to newline if ret == '\r' { diff --git a/08_random/kernel8.img b/08_random/kernel8.img index 4fde6cb1..28ad5ba9 100755 Binary files a/08_random/kernel8.img and b/08_random/kernel8.img differ diff --git a/08_random/src/mbox.rs b/08_random/src/mbox.rs index 369209fb..6c6b9710 100644 --- a/08_random/src/mbox.rs +++ b/08_random/src/mbox.rs @@ -23,6 +23,7 @@ */ use super::MMIO_BASE; +use core::ops; use cortex_a::asm; use volatile_register::{RO, WO}; @@ -30,7 +31,7 @@ const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880; #[allow(non_snake_case)] #[repr(C)] -struct Registers { +pub struct RegisterBlock { READ: RO, // 0x00 __reserved_0: [u32; 3], // 0x04 POLL: RO, // 0x10 @@ -82,22 +83,41 @@ pub struct Mbox { // data structures in Rust is a bit of a hassle right now, we just // close our eyes and roll with it. pub buffer: [u32; 36], - registers: *const Registers, +} + +/// Deref to RegisterBlock +/// +/// Allows writing +/// ``` +/// self.STATUS.read() +/// ``` +/// instead of something along the lines of +/// ``` +/// unsafe { (*Mbox::ptr()).STATUS.read() } +/// ``` +impl ops::Deref for Mbox { + type Target = RegisterBlock; + + fn deref(&self) -> &Self::Target { + unsafe { &*Self::ptr() } + } } impl Mbox { pub fn new() -> Mbox { - Mbox { - buffer: [0; 36], - registers: VIDEOCORE_MBOX as *const Registers, - } + Mbox { buffer: [0; 36] } + } + + /// Returns a pointer to the register block + fn ptr() -> *const RegisterBlock { + VIDEOCORE_MBOX as *const _ } /// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success pub fn call(&self, channel: u32) -> Result<()> { // wait until we can write to the mailbox loop { - if (unsafe { (*self.registers).STATUS.read() } & FULL) != FULL { + if (self.STATUS.read() & FULL) != FULL { break; } @@ -106,23 +126,22 @@ impl Mbox { // write the address of our message to the mailbox with channel identifier unsafe { - (*self.registers) - .WRITE - .write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF)); - } + self.WRITE + .write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF)) + }; // now wait for the response loop { // is there a response? loop { - if (unsafe { (*self.registers).STATUS.read() } & EMPTY) != EMPTY { + if (self.STATUS.read() & EMPTY) != EMPTY { break; } asm::nop(); } - let resp: u32 = unsafe { (*self.registers).READ.read() }; + let resp: u32 = self.READ.read(); // is it a response to our message? if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) { diff --git a/08_random/src/rand.rs b/08_random/src/rand.rs index 892d9e23..de4d973d 100644 --- a/08_random/src/rand.rs +++ b/08_random/src/rand.rs @@ -23,6 +23,7 @@ */ use super::MMIO_BASE; +use core::ops; use cortex_a::asm; use volatile_register::*; @@ -30,7 +31,7 @@ const RNG_BASE: u32 = MMIO_BASE + 0x104_000; #[allow(non_snake_case)] #[repr(C)] -struct Registers { +pub struct RegisterBlock { CTRL: RW, // 0x00 STATUS: RW, // 0x04 DATA: RO, // 0x08 @@ -39,42 +40,51 @@ struct Registers { } /// Public interface to the RNG -pub struct Rng { - registers: *const Registers, +pub struct Rng; + +impl ops::Deref for Rng { + type Target = RegisterBlock; + + fn deref(&self) -> &Self::Target { + unsafe { &*Self::ptr() } + } } impl Rng { pub fn new() -> Rng { - Rng { - registers: RNG_BASE as *const Registers, - } + Rng + } + + /// Returns a pointer to the register block + fn ptr() -> *const RegisterBlock { + RNG_BASE as *const _ } /// Initialize the RNG pub fn init(&self) { unsafe { - (*self.registers).STATUS.write(0x40_000); + self.STATUS.write(0x40_000); // mask interrupt - (*self.registers).INT_MASK.modify(|x| x | 1); + self.INT_MASK.modify(|x| x | 1); // enable - (*self.registers).CTRL.modify(|x| x | 1); + self.CTRL.modify(|x| x | 1); + } - // wait for gaining some entropy - loop { - if ((*self.registers).STATUS.read() >> 24) != 0 { - break; - } - - asm::nop(); + // wait for gaining some entropy + loop { + if (self.STATUS.read() >> 24) != 0 { + break; } + + asm::nop(); } } /// Return a random number between [min..max] pub fn rand(&self, min: u32, max: u32) -> u32 { - let r = unsafe { (*self.registers).DATA.read() }; + let r = self.DATA.read(); r % (max - min) + min } diff --git a/08_random/src/uart.rs b/08_random/src/uart.rs index 7d9cac0f..c8fd4fb5 100644 --- a/08_random/src/uart.rs +++ b/08_random/src/uart.rs @@ -23,6 +23,7 @@ */ use super::MMIO_BASE; +use core::ops; use core::sync::atomic::{compiler_fence, Ordering}; use cortex_a::asm; use gpio; @@ -34,7 +35,7 @@ const UART_BASE: u32 = MMIO_BASE + 0x20_1000; // PL011 UART registers #[allow(non_snake_case)] #[repr(C)] -struct Registers { +pub struct RegisterBlock { DR: RW, // 0x00 __reserved_0: [u32; 5], // 0x04 FR: RO, // 0x18 @@ -52,21 +53,30 @@ pub enum UartError { } pub type Result = ::core::result::Result; -pub struct Uart { - registers: *const Registers, +pub struct Uart; + +impl ops::Deref for Uart { + type Target = RegisterBlock; + + fn deref(&self) -> &Self::Target { + unsafe { &*Self::ptr() } + } } impl Uart { pub fn new() -> Uart { - Uart { - registers: UART_BASE as *const Registers, - } + Uart + } + + /// Returns a pointer to the register block + fn ptr() -> *const RegisterBlock { + UART_BASE as *const _ } ///Set baud rate and characteristics (115200 8N1) and map to GPIO pub fn init(&self, mbox: &mut mbox::Mbox) -> Result<()> { // turn off UART0 - unsafe { (*self.registers).CR.write(0) }; + unsafe { self.CR.write(0) }; // set up clock for consistent divisor values mbox.buffer[0] = 9 * 4; @@ -110,11 +120,11 @@ impl Uart { } (*gpio::GPPUDCLK0).write(0); - (*self.registers).ICR.write(0x7FF); // clear interrupts - (*self.registers).IBRD.write(2); // 115200 baud - (*self.registers).FBRD.write(0xB); - (*self.registers).LCRH.write(0b11 << 5); // 8n1 - (*self.registers).CR.write(0x301); // enable Tx, Rx, FIFO + self.ICR.write(0x7FF); // clear interrupts + self.IBRD.write(2); // 115200 baud + self.FBRD.write(0xB); + self.LCRH.write(0b11 << 5); // 8n1 + self.CR.write(0x301); // enable Tx, Rx, FIFO } Ok(()) @@ -124,7 +134,7 @@ impl Uart { pub fn send(&self, c: char) { // wait until we can send loop { - if (unsafe { (*self.registers).FR.read() } & 0x20) != 0x20 { + if (self.FR.read() & 0x20) != 0x20 { break; } @@ -132,14 +142,14 @@ impl Uart { } // write the character to the buffer - unsafe { (*self.registers).DR.write(c as u32) }; + unsafe { self.DR.write(c as u32) }; } /// Receive a character pub fn getc(&self) -> char { // wait until something is in the buffer loop { - if (unsafe { (*self.registers).FR.read() } & 0x10) != 0x10 { + if (self.FR.read() & 0x10) != 0x10 { break; } @@ -147,7 +157,7 @@ impl Uart { } // read it and return - let mut ret = unsafe { (*self.registers).DR.read() as u8 as char }; + let mut ret = self.DR.read() as u8 as char; // convert carrige return to newline if ret == '\r' {