From 747e902761ba54583c1304836109835e5dbfd641 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 16 Jul 2018 21:24:33 +0200 Subject: [PATCH] Rewrite for register-rs. We now have the same API for MMIO and CPU registers. Makes the code more concise, inntuitive, and improves readability. https://crates.io/crates/register --- 02_multicore_rust/raspi3_glue/src/lib.rs | 4 +- 03_uart1/Cargo.lock | 20 +-- 03_uart1/Cargo.toml | 2 +- 03_uart1/README.md | 9 +- 03_uart1/kernel8.img | Bin 768 -> 952 bytes 03_uart1/raspi3_glue/src/lib.rs | 4 +- 03_uart1/src/gpio.rs | 52 ++++++- 03_uart1/src/main.rs | 4 +- 03_uart1/src/uart.rs | 154 +++++++++++++++------ 04_mailboxes/Cargo.lock | 20 +-- 04_mailboxes/Cargo.toml | 2 +- 04_mailboxes/kernel8.img | Bin 1856 -> 2272 bytes 04_mailboxes/raspi3_glue/src/lib.rs | 4 +- 04_mailboxes/src/gpio.rs | 52 ++++++- 04_mailboxes/src/main.rs | 4 +- 04_mailboxes/src/mbox.rs | 54 ++++---- 04_mailboxes/src/uart.rs | 164 +++++++++++++++++------ 05_uart0/Cargo.lock | 20 +-- 05_uart0/Cargo.toml | 2 +- 05_uart0/kernel8.img | Bin 2016 -> 2544 bytes 05_uart0/raspi3_glue/src/lib.rs | 4 +- 05_uart0/src/gpio.rs | 54 +++++++- 05_uart0/src/main.rs | 4 +- 05_uart0/src/mbox.rs | 46 ++++--- 05_uart0/src/uart.rs | 155 ++++++++++++++++----- 06_raspbootin64/Cargo.lock | 20 +-- 06_raspbootin64/Cargo.toml | 2 +- 06_raspbootin64/kernel8.img | Bin 1464 -> 1768 bytes 06_raspbootin64/raspi3_glue/src/lib.rs | 4 +- 06_raspbootin64/src/gpio.rs | 54 +++++++- 06_raspbootin64/src/main.rs | 4 +- 06_raspbootin64/src/mbox.rs | 46 ++++--- 06_raspbootin64/src/uart.rs | 155 ++++++++++++++++----- 07_abstraction/Cargo.lock | 36 +++-- 07_abstraction/Cargo.toml | 4 +- 07_abstraction/README.md | 46 ++++--- 07_abstraction/kernel8.img | Bin 2016 -> 2544 bytes 07_abstraction/raspi3_glue/Cargo.toml | 2 +- 07_abstraction/raspi3_glue/src/lib.rs | 17 +-- 07_abstraction/src/gpio.rs | 54 +++++++- 07_abstraction/src/main.rs | 4 +- 07_abstraction/src/mbox.rs | 46 ++++--- 07_abstraction/src/uart.rs | 155 ++++++++++++++++----- 08_random/Cargo.lock | 36 +++-- 08_random/Cargo.toml | 4 +- 08_random/README.md | 7 +- 08_random/kernel8.img | Bin 1888 -> 2384 bytes 08_random/raspi3_glue/Cargo.toml | 2 +- 08_random/raspi3_glue/src/lib.rs | 17 +-- 08_random/src/gpio.rs | 54 +++++++- 08_random/src/main.rs | 4 +- 08_random/src/mbox.rs | 46 ++++--- 08_random/src/rand.rs | 54 +++++--- 08_random/src/uart.rs | 155 ++++++++++++++++----- 09_delays/Cargo.lock | 36 +++-- 09_delays/Cargo.toml | 4 +- 09_delays/kernel8.img | Bin 1848 -> 2104 bytes 09_delays/raspi3_glue/Cargo.toml | 2 +- 09_delays/raspi3_glue/src/lib.rs | 17 +-- 09_delays/src/delays.rs | 45 +++---- 09_delays/src/gpio.rs | 54 +++++++- 09_delays/src/main.rs | 4 +- 09_delays/src/mbox.rs | 46 ++++--- 09_delays/src/uart.rs | 156 ++++++++++++++++----- 0A_power/Cargo.lock | 48 ++++--- 0A_power/Cargo.toml | 4 +- 0A_power/README.md | 8 +- 0A_power/kernel8.img | Bin 1808 -> 2296 bytes 0A_power/raspi3_glue/Cargo.toml | 2 +- 0A_power/raspi3_glue/src/lib.rs | 17 +-- 0A_power/src/delays.rs | 45 +++---- 0A_power/src/gpio.rs | 91 +++++++++---- 0A_power/src/main.rs | 6 +- 0A_power/src/mbox.rs | 46 ++++--- 0A_power/src/power.rs | 99 +++++++------- 0A_power/src/uart.rs | 160 ++++++++++++++++------ 76 files changed, 1904 insertions(+), 848 deletions(-) diff --git a/02_multicore_rust/raspi3_glue/src/lib.rs b/02_multicore_rust/raspi3_glue/src/lib.rs index 57eff37e..8e064b55 100644 --- a/02_multicore_rust/raspi3_glue/src/lib.rs +++ b/02_multicore_rust/raspi3_glue/src/lib.rs @@ -30,8 +30,6 @@ extern crate panic_abort; extern crate r0; -use core::ptr; - #[lang = "start"] extern "C" fn start(user_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize where @@ -53,6 +51,8 @@ impl Termination for () { #[no_mangle] pub unsafe extern "C" fn reset() -> ! { + use core::ptr; + extern "C" { fn main(argc: isize, argv: *const *const u8) -> isize; diff --git a/03_uart1/Cargo.lock b/03_uart1/Cargo.lock index e3eb9afc..7fb179fb 100644 --- a/03_uart1/Cargo.lock +++ b/03_uart1/Cargo.lock @@ -3,7 +3,7 @@ name = "kernel8" version = "0.1.0" dependencies = [ "raspi3_glue 0.1.0", - "volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "register 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -25,20 +25,20 @@ dependencies = [ ] [[package]] -name = "vcell" -version = "0.1.0" +name = "register" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "tock-registers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "volatile-register" -version = "0.2.0" +name = "tock-registers" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] [metadata] "checksum panic-abort 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6bc796c620f27056d4ffe7c558533fd67ae5af0fd8e919fbe38de803368af73e" "checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -"checksum vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45c297f0afb6928cd08ab1ff9d95e99392595ea25ae1b5ecf822ff8764e57a0d" -"checksum volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286" +"checksum register 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e985243ba7e1c336b62444ef2a10d7bd87cf41a222285ae3de605c859006479" +"checksum tock-registers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2acc33f980e23cee18d234a32d0637fbc1ea55e13ab04012fa857b899fa1b7a9" diff --git a/03_uart1/Cargo.toml b/03_uart1/Cargo.toml index df9e43a9..c3a97d79 100644 --- a/03_uart1/Cargo.toml +++ b/03_uart1/Cargo.toml @@ -5,4 +5,4 @@ authors = ["Andre Richter "] [dependencies] raspi3_glue = { path = "raspi3_glue" } -volatile-register = "0.2.0" +register = "0.1.1" diff --git a/03_uart1/README.md b/03_uart1/README.md index 4acb10f2..7b8400fb 100644 --- a/03_uart1/README.md +++ b/03_uart1/README.md @@ -7,15 +7,14 @@ NOTE: qemu does not redirect UART1 to terminal by default, only UART0! ## gpio.rs -We have a new header file. This defines the base MMIO address, and the GPIO -controller's addresses. This file going to be very popular, as many device needs -it. +We have a new file that defines the GPIO controller addresses. It is going to be +very popular, as many device will need it in the future. -We are using the [volatile_register] crate to modify MMIO addresses, because it +We are using the [register][register] crate to modify MMIO addresses, because it allows easy wrapping of addresses to volatile types. It will also be used for UART registers. -[volatile_register]: https://docs.rs/volatile-register/0.2.0/volatile_register/ +[register]: https://crates.io/crates/register ## uart.rs diff --git a/03_uart1/kernel8.img b/03_uart1/kernel8.img index 47f2b4943b58df798950823e79f1522f902fc66c..b63bc839515614fdcd2d76ce9b950e8017593f5d 100755 GIT binary patch literal 952 zcmY*YO-vI(6n?WSbhnxk*KPSpa4DWzPnMwd#1=G4kJ~jGNkk+hEf7f+P8{06h2X^% zh>0;#PEyWk)q9t=@4{hVao_=sep4dphx5Ii38U*#dLqG z9Nu*8B%av=(A^WYa9LFU(<=UT%xJ3==5J(2j;X?L-}S54oZ)`gYJMA4$Mm{>lI%-x zKM8SLnD<0yqvDtX&%@2J1vyS2N6pP~y?8m#bLV)<#VcZSm@(9-j`O6B!|gohWaGk{ zJovl69kV>$hhFsN4hLen>hR~4f;jk%_v=qndu5KYhJ?NxBp7-phy|1EqOB8|dqvM~TQwHCsKd0sDnGNob$eEQ#8v zjFe8~|4yjQMW*;D&+zu3?z1`(Yv&4C4;|;ViFvE%`N2aE7eBeYBzP(4Nqj!KDZM1j zwOvQuQHRAJ@Y%&Y@;CCB0pJZT&S!B7buQsw*ugyT+DeEoV@unyYUq2c+QXz$5qyrF z+;3B!W1HX}H)$2{R(G-A;+@BySOu-Y)6SOT)V}YIjE_%r7*o$DhlWRno(3^nC#xVL IBG&2o4;@A(p8x;= literal 768 zcmY*XOH30{6ur}_=}eItn-;B!4Al*tP>3a#y0KHE25>iyi7T-&B$N=eeimv>3v4K2 zLjACeZ)2l<+o zR-y3%z3vA#EKoodD7Ryyz}oSop0Frp!a=#%v|^ULh>M7UjbBjASO?`~+#R+g^&z*b zU&g(XGpQ?S%J~jaoYzxe%-FFx1M;hbTq~{s`;K?Upg(5Oa(user_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize where @@ -53,6 +51,8 @@ impl Termination for () { #[no_mangle] pub unsafe extern "C" fn reset() -> ! { + use core::ptr; + extern "C" { fn main(argc: isize, argv: *const *const u8) -> isize; diff --git a/03_uart1/src/gpio.rs b/03_uart1/src/gpio.rs index 65bf7f0a..4bd5afe8 100644 --- a/03_uart1/src/gpio.rs +++ b/03_uart1/src/gpio.rs @@ -23,8 +23,52 @@ */ use super::MMIO_BASE; -use volatile_register::RW; +use register::mmio::ReadWrite; -pub const GPFSEL1: *const RW = (MMIO_BASE + 0x0020_0004) as *const RW; -pub const GPPUD: *const RW = (MMIO_BASE + 0x0020_0094) as *const RW; -pub const GPPUDCLK0: *const RW = (MMIO_BASE + 0x0020_0098) as *const RW; +// Descriptions taken from +// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf +register_bitfields! { + u32, + + /// GPIO Function Select 1 + GPFSEL1 [ + /// Pin 15 + FSEL15 OFFSET(15) NUMBITS(3) [ + Input = 0b000, + Output = 0b001, + RXD1 = 0b010 // Mini UART - Alternate function 5 + + ], + + /// Pin 14 + FSEL14 OFFSET(12) NUMBITS(3) [ + Input = 0b000, + Output = 0b001, + TXD1 = 0b010 // Mini UART - Alternate function 5 + ] + ], + + /// GPIO Pull-up/down Clock Register 0 + GPPUDCLK0 [ + /// Pin 15 + PUDCLK15 OFFSET(15) NUMBITS(1) [ + NoEffect = 0, + AssertClock = 1 + ], + + /// Pin 14 + PUDCLK14 OFFSET(14) NUMBITS(1) [ + NoEffect = 0, + AssertClock = 1 + ] + ] +} + + +pub const GPFSEL1: *const ReadWrite = + (MMIO_BASE + 0x0020_0004) as *const ReadWrite; + +pub const GPPUD: *const ReadWrite = (MMIO_BASE + 0x0020_0094) as *const ReadWrite; + +pub const GPPUDCLK0: *const ReadWrite = + (MMIO_BASE + 0x0020_0098) as *const ReadWrite; diff --git a/03_uart1/src/main.rs b/03_uart1/src/main.rs index 018590d6..8cc527df 100644 --- a/03_uart1/src/main.rs +++ b/03_uart1/src/main.rs @@ -26,7 +26,9 @@ #![feature(asm)] extern crate raspi3_glue; -extern crate volatile_register; + +#[macro_use] +extern crate register; const MMIO_BASE: u32 = 0x3F00_0000; diff --git a/03_uart1/src/uart.rs b/03_uart1/src/uart.rs index 4da2c03f..894eca33 100644 --- a/03_uart1/src/uart.rs +++ b/03_uart1/src/uart.rs @@ -25,28 +25,98 @@ use super::MMIO_BASE; use core::ops; use gpio; -use volatile_register::*; +use register::mmio::*; + +/// Auxilary mini UART registers +// +// Descriptions taken from +// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf +register_bitfields! { + u32, + + /// Auxiliary enables + AUX_ENABLES [ + /// If set the mini UART is enabled. The UART will immediately + /// start receiving data, especially if the UART1_RX line is + /// low. + /// If clear the mini UART is disabled. That also disables any + /// mini UART register access + MINI_UART_ENABLE OFFSET(0) NUMBITS(1) [] + ], + + /// Mini Uart Interrupt Identify + AUX_MU_IIR [ + /// Writing with bit 1 set will clear the receive FIFO + /// Writing with bit 2 set will clear the transmit FIFO + FIFO_CLEAR OFFSET(1) NUMBITS(2) [ + Rx = 0b01, + Tx = 0b10, + All = 0b11 + ] + ], + + /// Mini Uart Line Control + AUX_MU_LCR [ + /// Mode the UART works in + DATA_SIZE OFFSET(0) NUMBITS(2) [ + SevenBit = 0b00, + EightBit = 0b11 + ] + ], + + /// Mini Uart Line Status + AUX_MU_LSR [ + /// This bit is set if the transmit FIFO can accept at least + /// one byte. + TX_EMPTY OFFSET(5) NUMBITS(1) [], + + /// This bit is set if the receive FIFO holds at least 1 + /// symbol. + DATA_READY OFFSET(0) NUMBITS(1) [] + ], + + /// Mini Uart Extra Control + AUX_MU_CNTL [ + /// If this bit is set the mini UART transmitter is enabled. + /// If this bit is clear the mini UART transmitter is disabled. + TX_EN OFFSET(1) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// If this bit is set the mini UART receiver is enabled. + /// If this bit is clear the mini UART receiver is disabled. + RX_EN OFFSET(0) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ] + ], + + /// Mini Uart Baudrate + AUX_MU_BAUD [ + /// Mini UART baudrate counter + RATE OFFSET(0) NUMBITS(16) [] + ] +} const MINI_UART_BASE: u32 = MMIO_BASE + 0x21_5000; -/// Auxilary mini UART registers #[allow(non_snake_case)] #[repr(C)] pub struct RegisterBlock { - __reserved_0: u32, // 0x00 - ENABLES: RW, // 0x04 - __reserved_1: [u32; 14], // 0x08 - MU_IO: RW, // 0x40 - MU_IER: RW, // 0x44 - MU_IIR: RW, // 0x48 - MU_LCR: RW, // 0x4C - MU_MCR: RW, // 0x50 - MU_LSR: RW, // 0x54 - MU_MSR: RW, // 0x58 - MU_SCRATCH: RW, // 0x5C - MU_CNTL: RW, // 0x60 - MU_STAT: RW, // 0x64 - MU_BAUD: RW, // 0x68 + __reserved_0: u32, // 0x00 + AUX_ENABLES: ReadWrite, // 0x04 + __reserved_1: [u32; 14], // 0x08 + AUX_MU_IO: ReadWrite, // 0x40 - Mini Uart I/O Data + AUX_MU_IER: WriteOnly, // 0x44 - Mini Uart Interrupt Enable + AUX_MU_IIR: WriteOnly, // 0x48 + AUX_MU_LCR: WriteOnly, // 0x4C + AUX_MU_MCR: WriteOnly, // 0x50 + AUX_MU_LSR: ReadOnly, // 0x54 + __reserved_2: [u32; 2], // 0x58 + AUX_MU_CNTL: WriteOnly, // 0x60 + __reserved_3: u32, // 0x64 + AUX_MU_BAUD: WriteOnly, // 0x68 } pub struct MiniUart; @@ -82,45 +152,43 @@ impl MiniUart { ///Set baud rate and characteristics (115200 8N1) and map to GPIO pub fn init(&self) { // initialize UART + self.AUX_ENABLES.modify(AUX_ENABLES::MINI_UART_ENABLE::SET); + self.AUX_MU_IER.set(0); + self.AUX_MU_CNTL.set(0); + self.AUX_MU_LCR.write(AUX_MU_LCR::DATA_SIZE::EightBit); + self.AUX_MU_MCR.set(0); + self.AUX_MU_IER.set(0); + self.AUX_MU_IIR.write(AUX_MU_IIR::FIFO_CLEAR::All); + self.AUX_MU_BAUD.write(AUX_MU_BAUD::RATE.val(270)); // 115200 baud + + // map UART1 to GPIO pins unsafe { - 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| { - // Modify with a closure - let mut ret = x; - ret &= !((7 << 12) | (7 << 15)); // gpio14, gpio15 - ret |= (2 << 12) | (2 << 15); // alt5 - - ret - }); - - (*gpio::GPPUD).write(0); // enable pins 14 and 15 + (*gpio::GPFSEL1).modify(gpio::GPFSEL1::FSEL14::TXD1 + gpio::GPFSEL1::FSEL15::RXD1); + + (*gpio::GPPUD).set(0); // enable pins 14 and 15 for _ in 0..150 { asm!("nop" :::: "volatile"); } - (*gpio::GPPUDCLK0).write((1 << 14) | (1 << 15)); + (*gpio::GPPUDCLK0).write( + gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, + ); for _ in 0..150 { asm!("nop" :::: "volatile"); } - (*gpio::GPPUDCLK0).write(0); // flush GPIO setup - self.MU_CNTL.write(3); // enable Tx, Rx + + (*gpio::GPPUDCLK0).set(0); } + + self.AUX_MU_CNTL + .write(AUX_MU_CNTL::RX_EN::Enabled + AUX_MU_CNTL::TX_EN::Enabled); } /// Send a character pub fn send(&self, c: char) { // wait until we can send loop { - if (self.MU_LSR.read() & 0x20) == 0x20 { + if self.AUX_MU_LSR.is_set(AUX_MU_LSR::TX_EMPTY) { break; } @@ -128,14 +196,14 @@ impl MiniUart { } // write the character to the buffer - unsafe { self.MU_IO.write(c as u32) }; + self.AUX_MU_IO.set(c as u32); } /// Receive a character pub fn getc(&self) -> char { // wait until something is in the buffer loop { - if (self.MU_LSR.read() & 0x01) == 0x01 { + if self.AUX_MU_LSR.is_set(AUX_MU_LSR::DATA_READY) { break; } @@ -143,7 +211,7 @@ impl MiniUart { } // read it and return - let mut ret = self.MU_IO.read() as u8 as char; + let mut ret = self.AUX_MU_IO.get() as u8 as char; // convert carrige return to newline if ret == '\r' { diff --git a/04_mailboxes/Cargo.lock b/04_mailboxes/Cargo.lock index e3eb9afc..7fb179fb 100644 --- a/04_mailboxes/Cargo.lock +++ b/04_mailboxes/Cargo.lock @@ -3,7 +3,7 @@ name = "kernel8" version = "0.1.0" dependencies = [ "raspi3_glue 0.1.0", - "volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "register 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -25,20 +25,20 @@ dependencies = [ ] [[package]] -name = "vcell" -version = "0.1.0" +name = "register" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "tock-registers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "volatile-register" -version = "0.2.0" +name = "tock-registers" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] [metadata] "checksum panic-abort 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6bc796c620f27056d4ffe7c558533fd67ae5af0fd8e919fbe38de803368af73e" "checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -"checksum vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45c297f0afb6928cd08ab1ff9d95e99392595ea25ae1b5ecf822ff8764e57a0d" -"checksum volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286" +"checksum register 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e985243ba7e1c336b62444ef2a10d7bd87cf41a222285ae3de605c859006479" +"checksum tock-registers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2acc33f980e23cee18d234a32d0637fbc1ea55e13ab04012fa857b899fa1b7a9" diff --git a/04_mailboxes/Cargo.toml b/04_mailboxes/Cargo.toml index df9e43a9..c3a97d79 100644 --- a/04_mailboxes/Cargo.toml +++ b/04_mailboxes/Cargo.toml @@ -5,4 +5,4 @@ authors = ["Andre Richter "] [dependencies] raspi3_glue = { path = "raspi3_glue" } -volatile-register = "0.2.0" +register = "0.1.1" diff --git a/04_mailboxes/kernel8.img b/04_mailboxes/kernel8.img index 91ac37ea057fd4a0baf68335ca08da0bf2818115..6d1d0050f73eae7eee58222e14361e1ea886e16b 100755 GIT binary patch literal 2272 zcmZ`)ZA?>V6h8M}u(uUZYRlJv+me_Jj7?U?R<Oq*;G%9gn8&rIX8A6r(o{Q%i81{_pV?wB)WdYB;1i@Ie(O>zJ@3;%F*B>{Fi_eiNt=1rf-7tokDP4 z;6jUsx!?mAA1uqF>qEM8&XYXfU-kEucF#Hr+~B&Mhwym$@oHNM>3`ssUY!@jkhF#T z;~H{HyLS6=rrSwmVEkjeJyK}QboJuQ8i87l%Ch?{X5$RApY!C_8tt}nBk383xQX=A zS;1cp-m|cE@rK!PtncL6Z4UT2fJ>8tzphYQF{#=~cw)~3?~EW-%nOE9T+yWLwiSvM zOe6P5b{pV#SM^Kh>}7s0rTiumvRkM6iP{_&^AmAy0jE=VCYEG3&+<@nEI^KR$Wc;r zyb&!8v)mcJOU0Lj{0ff49i_#*kru=3EN9QUOP_`jKeZsc=R0?y7CVEBhj#=MP2Y`; z3rBuo^;$gqEpRS4i2BTT^1+u;pK~}5^{eolDR#|himfeYN?hXalqDjZ}G#C^frsp8^yoZ>Fw6>lF6lr<`#Jfr99=ji!z zEj>A;SL&5R3Qr~KbpUsa_kZx_Q}r?e|4hZ%{aix5<~w(yw|1cCCLi~kEC{zBxOA8i z>w}ljbA#0Fp+qHm(13^W^&PYaw46PHcj#lsggLNBYmbz3WYuyM zaR9$%?sj@OQ8%L@t0R~6UAz?T%Att2R|?N)B&%rtv8XEw47hiv6!zp%g!O10-|c+S zXsGPtDRK+vk6fgPm`Q%t!xPXytQ+w z{vMni*U(q#@3i3q$>l~aBe=6ha4#U&KEA{{rlUx@U*73bmjiyR_n6;UZ$ns{P5K%$ z`Ng(k{nWDT#=L78#k!!eKaTYvA0tQl*VFF5E7}m|pwnzG3zQ+(coQG^WLX}b7C7q& zFSeL5_Z0hwWq~hLdjR&S7wi${`;hJPQ~O2i72jXW0?hWOK-NsmECu^b#WW?>9{9O2 z(^qm@(Pd22<$*3Q^onc-SCM~+?<;x*y_2QpJ*CbO7RzS9Iu&O<)q$Rx#rKBItvGsx z&9Ievh~C|a^0wWH8cv*zf`ipa`Tr(`88(Udh+=&b~YHS-M?2-FeZJ#qHDDDR39xmbj*S+w6LK;vYd9a`e#s{%py1Z-YJI zOV-EQlAhQ=HdXtQwXv;lOSZP;{+K0KvdsZMuchjLg{;s(6;;o{e(gNj1~#*Oee5b? z=HPo3KECA9*uY*w%+c6YtiI%_SWEIEv;f SzoWT*#l@_nxR^R|W&I!bq4_)j literal 1856 zcma)7UrbY182@f>&AlxJr7Qj|wq0UE3$0m+P!^TT+!h2~Tch_Dru)kr$D}B(}xl8`#vTzF)k-3Wqww6 z*X_sr9w#o|(2#GeLh?MQAR}8hTu#Phl#e_B*9F8HNn9MqxZ5OomVsG@KRLli9&ami zOcmqAlh1`XowBs{>Zuqutc@1bnT)JKIevp79@#4*xg* zp-lz;Lz~{rzt`}Jf3M-~_-n)he~tKNezW!!zghcs{01_r^)b-@^0V)uOlclIZKd4b z=k(uyg>Q3>2E7{Npf}4?Vh(4f7T?N*H%4?V_PLbMp}uyG+&Ydj^8&eNwhnp+G?w&0 z8D)a!E$L|+=98Gi7y7`G4sNDQOe19uY6iVk6{gylhBDLOPhO>rxPc<<%uFbXZ(cCE zV_z3y>-{>SD>#=|teJ^@O+QZT6W_V+6|=Yc7O-~`_z?EZ3Ur(4iqmQx<74)WqSP-S z2M1T_*6S$q^6VDQ$Mbr9^k}-Zl#By5inR2ajZM(d!RbzL7@rDKCJ4>QSv}Lto>qjq zfytw34q9yEI}-0ApX@PB;@O&VeV*ssNsV}76n9jOYt4z9#rP89b33FA!(xx?b6X1b ze%LD3Z%(k-?>xEx0Ja(ZCB*8*QJn$zO~teqF+!#L*L9e9Q6Iz4Kwk*@j>ER&?l$hB zh>nYIzgWB%%+KycXmV#-eBaza})TqE({35OtNHulCbQ5NqcV_rkASpoh)#=dM}}+$TDT5`Upj zWre|gizQO-F|SLtL}_KH)Z$s*DCNR=zucP-$|I%J5Y9Kt&QC3#-uw~SRc`St!9T2{ zh9|rsHL`~qmJq))OrDWl%=XJ;ShED|7%<^{r#y0)u%=TU!x+w=l~3fqPQlgq;96@$)##KTgAyRC#{h)-F+`1Ha$r~VTYIFzl(!@_5c6? diff --git a/04_mailboxes/raspi3_glue/src/lib.rs b/04_mailboxes/raspi3_glue/src/lib.rs index 57eff37e..8e064b55 100644 --- a/04_mailboxes/raspi3_glue/src/lib.rs +++ b/04_mailboxes/raspi3_glue/src/lib.rs @@ -30,8 +30,6 @@ extern crate panic_abort; extern crate r0; -use core::ptr; - #[lang = "start"] extern "C" fn start(user_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize where @@ -53,6 +51,8 @@ impl Termination for () { #[no_mangle] pub unsafe extern "C" fn reset() -> ! { + use core::ptr; + extern "C" { fn main(argc: isize, argv: *const *const u8) -> isize; diff --git a/04_mailboxes/src/gpio.rs b/04_mailboxes/src/gpio.rs index 65bf7f0a..4bd5afe8 100644 --- a/04_mailboxes/src/gpio.rs +++ b/04_mailboxes/src/gpio.rs @@ -23,8 +23,52 @@ */ use super::MMIO_BASE; -use volatile_register::RW; +use register::mmio::ReadWrite; -pub const GPFSEL1: *const RW = (MMIO_BASE + 0x0020_0004) as *const RW; -pub const GPPUD: *const RW = (MMIO_BASE + 0x0020_0094) as *const RW; -pub const GPPUDCLK0: *const RW = (MMIO_BASE + 0x0020_0098) as *const RW; +// Descriptions taken from +// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf +register_bitfields! { + u32, + + /// GPIO Function Select 1 + GPFSEL1 [ + /// Pin 15 + FSEL15 OFFSET(15) NUMBITS(3) [ + Input = 0b000, + Output = 0b001, + RXD1 = 0b010 // Mini UART - Alternate function 5 + + ], + + /// Pin 14 + FSEL14 OFFSET(12) NUMBITS(3) [ + Input = 0b000, + Output = 0b001, + TXD1 = 0b010 // Mini UART - Alternate function 5 + ] + ], + + /// GPIO Pull-up/down Clock Register 0 + GPPUDCLK0 [ + /// Pin 15 + PUDCLK15 OFFSET(15) NUMBITS(1) [ + NoEffect = 0, + AssertClock = 1 + ], + + /// Pin 14 + PUDCLK14 OFFSET(14) NUMBITS(1) [ + NoEffect = 0, + AssertClock = 1 + ] + ] +} + + +pub const GPFSEL1: *const ReadWrite = + (MMIO_BASE + 0x0020_0004) as *const ReadWrite; + +pub const GPPUD: *const ReadWrite = (MMIO_BASE + 0x0020_0094) as *const ReadWrite; + +pub const GPPUDCLK0: *const ReadWrite = + (MMIO_BASE + 0x0020_0098) as *const ReadWrite; diff --git a/04_mailboxes/src/main.rs b/04_mailboxes/src/main.rs index 9a4a942f..2fb3ba69 100644 --- a/04_mailboxes/src/main.rs +++ b/04_mailboxes/src/main.rs @@ -26,7 +26,9 @@ #![feature(asm)] extern crate raspi3_glue; -extern crate volatile_register; + +#[macro_use] +extern crate register; const MMIO_BASE: u32 = 0x3F00_0000; diff --git a/04_mailboxes/src/mbox.rs b/04_mailboxes/src/mbox.rs index 78f43c06..2c0ceab9 100644 --- a/04_mailboxes/src/mbox.rs +++ b/04_mailboxes/src/mbox.rs @@ -24,20 +24,27 @@ use super::MMIO_BASE; use core::ops; -use volatile_register::{RO, WO}; +use register::mmio::{ReadOnly, WriteOnly}; + +register_bitfields! { + u32, + + STATUS [ + FULL OFFSET(31) NUMBITS(1) [], + EMPTY OFFSET(30) NUMBITS(1) [] + ] +} const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880; #[allow(non_snake_case)] #[repr(C)] pub struct RegisterBlock { - READ: RO, // 0x00 - __reserved_0: [u32; 3], // 0x04 - POLL: RO, // 0x10 - SENDER: RO, // 0x14 - STATUS: RO, // 0x18 - CONFIG: RO, // 0x1C - WRITE: WO, // 0x20 + READ: ReadOnly, // 0x00 + __reserved_0: [u32; 5], // 0x04 + STATUS: ReadOnly, // 0x18 + __reserved_1: u32, // 0x1C + WRITE: WriteOnly, // 0x20 } // Custom errors @@ -65,17 +72,13 @@ mod response { } pub const REQUEST: u32 = 0; -const FULL: u32 = 0x8000_0000; -const EMPTY: u32 = 0x4000_0000; // Public interface to the mailbox #[repr(C)] +#[repr(align(16))] pub struct Mbox { // The address for buffer needs to be 16-byte aligned so that the - // Videcore can handle it properly. We don't take precautions here - // 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. + // Videcore can handle it properly. pub buffer: [u32; 36], } @@ -111,38 +114,33 @@ impl Mbox { pub fn call(&self, channel: u32) -> Result<()> { // wait until we can write to the mailbox loop { - if (self.STATUS.read() & FULL) != FULL { + if !self.STATUS.is_set(STATUS::FULL) { break; } - unsafe { - asm!("nop" :::: "volatile"); - } + unsafe { asm!("nop" :::: "volatile") }; } + let buf_ptr = self.buffer.as_ptr() as u32; + // write the address of our message to the mailbox with channel identifier - unsafe { - self.WRITE - .write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF)); - } + self.WRITE.set((buf_ptr & !0xF) | (channel & 0xF)); // now wait for the response loop { // is there a response? loop { - if (self.STATUS.read() & EMPTY) != EMPTY { + if !self.STATUS.is_set(STATUS::EMPTY) { break; } - unsafe { - asm!("nop" :::: "volatile"); - } + unsafe { asm!("nop" :::: "volatile") }; } - let resp: u32 = self.READ.read(); + let resp: u32 = self.READ.get(); // is it a response to our message? - if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) { + if ((resp & 0xF) == channel) && ((resp & !0xF) == buf_ptr) { // is it a valid successful response? return match self.buffer[1] { response::SUCCESS => Ok(()), diff --git a/04_mailboxes/src/uart.rs b/04_mailboxes/src/uart.rs index db12f800..95d7f740 100644 --- a/04_mailboxes/src/uart.rs +++ b/04_mailboxes/src/uart.rs @@ -25,32 +25,112 @@ use super::MMIO_BASE; use core::ops; use gpio; -use volatile_register::*; +use register::mmio::*; + +/// Auxilary mini UART registers +// +// Descriptions taken from +// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf +register_bitfields! { + u32, + + /// Auxiliary enables + AUX_ENABLES [ + /// If set the mini UART is enabled. The UART will immediately + /// start receiving data, especially if the UART1_RX line is + /// low. + /// If clear the mini UART is disabled. That also disables any + /// mini UART register access + MINI_UART_ENABLE OFFSET(0) NUMBITS(1) [] + ], + + /// Mini Uart Interrupt Identify + AUX_MU_IIR [ + /// Writing with bit 1 set will clear the receive FIFO + /// Writing with bit 2 set will clear the transmit FIFO + FIFO_CLEAR OFFSET(1) NUMBITS(2) [ + Rx = 0b01, + Tx = 0b10, + All = 0b11 + ] + ], + + /// Mini Uart Line Control + AUX_MU_LCR [ + /// Mode the UART works in + DATA_SIZE OFFSET(0) NUMBITS(2) [ + SevenBit = 0b00, + EightBit = 0b11 + ] + ], + + /// Mini Uart Line Status + AUX_MU_LSR [ + /// This bit is set if the transmit FIFO can accept at least + /// one byte. + TX_EMPTY OFFSET(5) NUMBITS(1) [], + + /// This bit is set if the receive FIFO holds at least 1 + /// symbol. + DATA_READY OFFSET(0) NUMBITS(1) [] + ], + + /// Mini Uart Extra Control + AUX_MU_CNTL [ + /// If this bit is set the mini UART transmitter is enabled. + /// If this bit is clear the mini UART transmitter is disabled. + TX_EN OFFSET(1) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// If this bit is set the mini UART receiver is enabled. + /// If this bit is clear the mini UART receiver is disabled. + RX_EN OFFSET(0) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ] + ], + + /// Mini Uart Baudrate + AUX_MU_BAUD [ + /// Mini UART baudrate counter + RATE OFFSET(0) NUMBITS(16) [] + ] +} const MINI_UART_BASE: u32 = MMIO_BASE + 0x21_5000; -/// Auxilary mini UART registers #[allow(non_snake_case)] #[repr(C)] pub struct RegisterBlock { - __reserved_0: u32, // 0x00 - ENABLES: RW, // 0x04 - __reserved_1: [u32; 14], // 0x08 - MU_IO: RW, // 0x40 - MU_IER: RW, // 0x44 - MU_IIR: RW, // 0x48 - MU_LCR: RW, // 0x4C - MU_MCR: RW, // 0x50 - MU_LSR: RW, // 0x54 - MU_MSR: RW, // 0x58 - MU_SCRATCH: RW, // 0x5C - MU_CNTL: RW, // 0x60 - MU_STAT: RW, // 0x64 - MU_BAUD: RW, // 0x68 + __reserved_0: u32, // 0x00 + AUX_ENABLES: ReadWrite, // 0x04 + __reserved_1: [u32; 14], // 0x08 + AUX_MU_IO: ReadWrite, // 0x40 - Mini Uart I/O Data + AUX_MU_IER: WriteOnly, // 0x44 - Mini Uart Interrupt Enable + AUX_MU_IIR: WriteOnly, // 0x48 + AUX_MU_LCR: WriteOnly, // 0x4C + AUX_MU_MCR: WriteOnly, // 0x50 + AUX_MU_LSR: ReadOnly, // 0x54 + __reserved_2: [u32; 2], // 0x58 + AUX_MU_CNTL: WriteOnly, // 0x60 + __reserved_3: u32, // 0x64 + AUX_MU_BAUD: WriteOnly, // 0x68 } pub struct MiniUart; +/// Deref to RegisterBlock +/// +/// Allows writing +/// ``` +/// self.MU_IER.read() +/// ``` +/// instead of something along the lines of +/// ``` +/// unsafe { (*MiniUart::ptr()).MU_IER.read() } +/// ``` impl ops::Deref for MiniUart { type Target = RegisterBlock; @@ -72,45 +152,43 @@ impl MiniUart { ///Set baud rate and characteristics (115200 8N1) and map to GPIO pub fn init(&self) { // initialize UART + self.AUX_ENABLES.modify(AUX_ENABLES::MINI_UART_ENABLE::SET); + self.AUX_MU_IER.set(0); + self.AUX_MU_CNTL.set(0); + self.AUX_MU_LCR.write(AUX_MU_LCR::DATA_SIZE::EightBit); + self.AUX_MU_MCR.set(0); + self.AUX_MU_IER.set(0); + self.AUX_MU_IIR.write(AUX_MU_IIR::FIFO_CLEAR::All); + self.AUX_MU_BAUD.write(AUX_MU_BAUD::RATE.val(270)); // 115200 baud + + // map UART1 to GPIO pins unsafe { - 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| { - // Modify with a closure - let mut ret = x; - ret &= !((7 << 12) | (7 << 15)); // gpio14, gpio15 - ret |= (2 << 12) | (2 << 15); // alt5 - - ret - }); - - (*gpio::GPPUD).write(0); // enable pins 14 and 15 + (*gpio::GPFSEL1).modify(gpio::GPFSEL1::FSEL14::TXD1 + gpio::GPFSEL1::FSEL15::RXD1); + + (*gpio::GPPUD).set(0); // enable pins 14 and 15 for _ in 0..150 { asm!("nop" :::: "volatile"); } - (*gpio::GPPUDCLK0).write((1 << 14) | (1 << 15)); + (*gpio::GPPUDCLK0).write( + gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, + ); for _ in 0..150 { asm!("nop" :::: "volatile"); } - (*gpio::GPPUDCLK0).write(0); // flush GPIO setup - self.MU_CNTL.write(3); // enable Tx, Rx + + (*gpio::GPPUDCLK0).set(0); } + + self.AUX_MU_CNTL + .write(AUX_MU_CNTL::RX_EN::Enabled + AUX_MU_CNTL::TX_EN::Enabled); } /// Send a character pub fn send(&self, c: char) { // wait until we can send loop { - if (self.MU_LSR.read() & 0x20) == 0x20 { + if self.AUX_MU_LSR.is_set(AUX_MU_LSR::TX_EMPTY) { break; } @@ -118,14 +196,14 @@ impl MiniUart { } // write the character to the buffer - unsafe { self.MU_IO.write(c as u32) }; + self.AUX_MU_IO.set(c as u32); } /// Receive a character pub fn getc(&self) -> char { // wait until something is in the buffer loop { - if (self.MU_LSR.read() & 0x01) == 0x01 { + if self.AUX_MU_LSR.is_set(AUX_MU_LSR::DATA_READY) { break; } @@ -133,7 +211,7 @@ impl MiniUart { } // read it and return - let mut ret = self.MU_IO.read() as u8 as char; + let mut ret = self.AUX_MU_IO.get() as u8 as char; // convert carrige return to newline if ret == '\r' { diff --git a/05_uart0/Cargo.lock b/05_uart0/Cargo.lock index e3eb9afc..7fb179fb 100644 --- a/05_uart0/Cargo.lock +++ b/05_uart0/Cargo.lock @@ -3,7 +3,7 @@ name = "kernel8" version = "0.1.0" dependencies = [ "raspi3_glue 0.1.0", - "volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "register 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -25,20 +25,20 @@ dependencies = [ ] [[package]] -name = "vcell" -version = "0.1.0" +name = "register" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "tock-registers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "volatile-register" -version = "0.2.0" +name = "tock-registers" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] [metadata] "checksum panic-abort 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6bc796c620f27056d4ffe7c558533fd67ae5af0fd8e919fbe38de803368af73e" "checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -"checksum vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45c297f0afb6928cd08ab1ff9d95e99392595ea25ae1b5ecf822ff8764e57a0d" -"checksum volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286" +"checksum register 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e985243ba7e1c336b62444ef2a10d7bd87cf41a222285ae3de605c859006479" +"checksum tock-registers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2acc33f980e23cee18d234a32d0637fbc1ea55e13ab04012fa857b899fa1b7a9" diff --git a/05_uart0/Cargo.toml b/05_uart0/Cargo.toml index df9e43a9..c3a97d79 100644 --- a/05_uart0/Cargo.toml +++ b/05_uart0/Cargo.toml @@ -5,4 +5,4 @@ authors = ["Andre Richter "] [dependencies] raspi3_glue = { path = "raspi3_glue" } -volatile-register = "0.2.0" +register = "0.1.1" diff --git a/05_uart0/kernel8.img b/05_uart0/kernel8.img index 6bb98be8f1d370c59ad5f02be5cf8d396ada1da6..547fdf2eab393547ca90cb19aa8668dc552c3192 100755 GIT binary patch literal 2544 zcmZ`*ZA?>F7=G`)KyMLL`T>Z*Eo{00vB^qwWeZY;Wr)+bwknI63XG%()Da&8U|TXiCXQ4-8UuIFxxLJy&;-u8@B5tR zKJWXU^PYQ?tPk@NY*%ZD?jAD<4`o@-xJgu9M&$pKqw7!cEWu7B68p*J+yl%$rT2$R zXB|Sokknx}{B^5kPEXN@HzCl=Q)pE1m5ys{(TKnWwZNKchD%+^6q*!lQE~Bj*tMQQ z6M{ZiiTR0qDj3xOzs?pl>TlSMqqkaKP2~nAH>lWj3bo}^h+zx!xB{NY!1VO-wov-V zlA|9Qf9I*OMwXo}ceYOCax8s#*9zR(T*udOxW0~~1KL#5mF1B~Y|hq=Ey+%a(>LD4 z=t{Cd8)uO?ZR3zY&Q9{#MZ~A&Y@tgDKKmY{p;*gN=)TTpm;4keNF)!_Glcg~Xml2B zPs|r@mtY$gBufM5vrlR^TZ)eR?4yEI*o)XYcS{2oJEVb2!_q((a>sO!3S^0RD+05Q z^1z(l7DdkegTk?2SpK7R-v=UIA;5Awe}n^u59FuNU8B%pKh5)9Mrd^4M-X0Ph9(+IYj%AjT8vHft3yRj^AVf@jYrZQ+ROC**S3pAOy$#2*n1 zE4YRiWv6wMSjaSTPi3b8xJeZk&)LCnuf=dfQQ4WS;zaFw2g8YYZzh+l@C+@;&iK8M zi5LqIqol^z-;q1O_7bzdq}msRj6&j&BXyrKUv}IY=4UaxlCFI|fc0ZfWM{-%j#}&v z%pchmh}PZfTdvpqksn~^0tVD4;^hPEtX#tTP`^Ug`E198Cfm|@KF1;cMrjS_vy0o( z$TJIDdi%w!!+7r!(RCU7dla=|dOEQ-1NH^g&i4Ih(7-rd?o5XkJgx4`VrdI`wzv0W z9Rl_duckK97hd`revn)s6pXjdJaL)M_BXg8hUDig`OwZ1g7xeV6q37Gx^q9q%9<#VY&sS^c>0M1vZo)G?xd|`mxw?j) zPgc{jo^(pR)|0|hjCvhJj@yC#@ws{#VfU(bRdi3Q{4SlnGmR#5?2K3)U;OtfV?-THL@;MgP>*H}o^xt>lw7XXAzXqlM zKGE1hdYlzK&dCanv;@bSaU5;n;Gi+jx7DA|BVNQ6LQLc6-Mzfnn1{Zj`0s7?f2sPv zgMVzZEyS={GUgevc?RYRHuDuf^ZkMTn}|Fpwrtg=$+6&mxZy-keO{L_P8W-<0l5)b z58O_k9=iQwq0VYa{<8dOW+6r*J3#BWQzF?KIPsDp?=nPIfO=hnp8&;qFu_aW7Vex4kP_ zn->p+&1sT#8urUtDtRQN1iQCW$u#_TE|ax;3!7JmZ)43gu(yG6<38`+M_6+_d>f;C z@l3dJ@k51o8uQ1PcLB%N+`-7cDW>rK!1QcuCw~#gI9%b!_|7mJ*}OVzRy0A2!e1FS zC$jgs!dIZdtmvs$`45D*rpc^mI-|xH)5Nqe?jo$25K@CzFmm(kn}MG~ z?)-zucw%8>Zxg?wZ=BdeiBXCQoa9 Q%Q7S{nf}$r6fBSb0nR8}$^ZZW literal 2016 zcma)7T})GF7=BMrO;3M7sjUhEZ8wclXw7O|%VI}~b3xF>wOzu6S*eBu3)B@gagoFp zcOewe8WWS`LH zYJb1f<4{v7!^QnAXigfhzgpI}V ze@Ve{KJ>GIH5IU)2ISd$D+75=rOVM<6==RsWwpJPTgS>M_5fqeiDbo~!l?iIi} z!+d+!y1;JWYr58L4Q-@Yf1y3n_Cwvm*X&q%>o}Ub2lhSi{rtkA>EhS_;VWU`cccrmWl7b;l z=;UA@YJAx|&$&XJzSE{BoZ&vd33Uwo(JZ?{r>cbg}pp;+@N4xbxYEwd9I8VR?%yQcBqf?smk8zGl5EvWBv_4`+Nc z6JBN;?@oB_ZHPlJ)5TSX~b_qV;UOm&=`Wo8bxD+qVX9tb^v#Ztn!*M z|E9FbJp#*NPMfbf^^Pj;&mB;u?k!2@XR#h*DxuScH$aYmRh_!1#D7A3X1y=Vu$v_K zYm5E{_%imF>J*Fp#*^z7uuafxX4I z{Yt%ZKI-iUPXw(7Z$`s5ifOt2iUH+5vT=4F`&E=>_+3kz+<)S&&EZ_h?*Vjb(S!#( z7Hb~wSj5`ouj376V{(5dU1MW6u%AmSEepuY;7n%x(6yv#T)zp+g)l zq55c{NpyT_@pKpViq0~NXAa{-TB?7{8#2S&sD2LdD?{WN-pKq`aTGaoz>WeFEwqWl zdk8sg;wWsia7^qhd?EAB!Jmhp1diogfz9!#hcDLSNKmSlV;mjgyvDcaG&8?dbjmfM z7MZ_Ebgp3Yb%>`?gHx`jRpH+&4gGphSJ>1@NFx+L09_`-W-eWy@_yeo%vuJpKSG)Dd VA#3btd(TUVO-DHmn}J^0e*kOiuXO+b diff --git a/05_uart0/raspi3_glue/src/lib.rs b/05_uart0/raspi3_glue/src/lib.rs index 57eff37e..8e064b55 100644 --- a/05_uart0/raspi3_glue/src/lib.rs +++ b/05_uart0/raspi3_glue/src/lib.rs @@ -30,8 +30,6 @@ extern crate panic_abort; extern crate r0; -use core::ptr; - #[lang = "start"] extern "C" fn start(user_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize where @@ -53,6 +51,8 @@ impl Termination for () { #[no_mangle] pub unsafe extern "C" fn reset() -> ! { + use core::ptr; + extern "C" { fn main(argc: isize, argv: *const *const u8) -> isize; diff --git a/05_uart0/src/gpio.rs b/05_uart0/src/gpio.rs index 65bf7f0a..6ec8b4c6 100644 --- a/05_uart0/src/gpio.rs +++ b/05_uart0/src/gpio.rs @@ -23,8 +23,54 @@ */ use super::MMIO_BASE; -use volatile_register::RW; +use register::mmio::ReadWrite; -pub const GPFSEL1: *const RW = (MMIO_BASE + 0x0020_0004) as *const RW; -pub const GPPUD: *const RW = (MMIO_BASE + 0x0020_0094) as *const RW; -pub const GPPUDCLK0: *const RW = (MMIO_BASE + 0x0020_0098) as *const RW; +// Descriptions taken from +// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf +register_bitfields! { + u32, + + /// GPIO Function Select 1 + GPFSEL1 [ + /// Pin 15 + FSEL15 OFFSET(15) NUMBITS(3) [ + Input = 0b000, + Output = 0b001, + RXD0 = 0b100, // UART0 - Alternate function 0 + RXD1 = 0b010 // Mini UART - Alternate function 5 + + ], + + /// Pin 14 + FSEL14 OFFSET(12) NUMBITS(3) [ + Input = 0b000, + Output = 0b001, + TXD0 = 0b100, // UART0 - Alternate function 0 + TXD1 = 0b010 // Mini UART - Alternate function 5 + ] + ], + + /// GPIO Pull-up/down Clock Register 0 + GPPUDCLK0 [ + /// Pin 15 + PUDCLK15 OFFSET(15) NUMBITS(1) [ + NoEffect = 0, + AssertClock = 1 + ], + + /// Pin 14 + PUDCLK14 OFFSET(14) NUMBITS(1) [ + NoEffect = 0, + AssertClock = 1 + ] + ] +} + + +pub const GPFSEL1: *const ReadWrite = + (MMIO_BASE + 0x0020_0004) as *const ReadWrite; + +pub const GPPUD: *const ReadWrite = (MMIO_BASE + 0x0020_0094) as *const ReadWrite; + +pub const GPPUDCLK0: *const ReadWrite = + (MMIO_BASE + 0x0020_0098) as *const ReadWrite; diff --git a/05_uart0/src/main.rs b/05_uart0/src/main.rs index 37b4c263..86e4635f 100644 --- a/05_uart0/src/main.rs +++ b/05_uart0/src/main.rs @@ -26,7 +26,9 @@ #![feature(asm)] extern crate raspi3_glue; -extern crate volatile_register; + +#[macro_use] +extern crate register; const MMIO_BASE: u32 = 0x3F00_0000; diff --git a/05_uart0/src/mbox.rs b/05_uart0/src/mbox.rs index de2144f6..279b3129 100644 --- a/05_uart0/src/mbox.rs +++ b/05_uart0/src/mbox.rs @@ -24,20 +24,27 @@ use super::MMIO_BASE; use core::ops; -use volatile_register::{RO, WO}; +use register::mmio::{ReadOnly, WriteOnly}; + +register_bitfields! { + u32, + + STATUS [ + FULL OFFSET(31) NUMBITS(1) [], + EMPTY OFFSET(30) NUMBITS(1) [] + ] +} const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880; #[allow(non_snake_case)] #[repr(C)] pub struct RegisterBlock { - READ: RO, // 0x00 - __reserved_0: [u32; 3], // 0x04 - POLL: RO, // 0x10 - SENDER: RO, // 0x14 - STATUS: RO, // 0x18 - CONFIG: RO, // 0x1C - WRITE: WO, // 0x20 + READ: ReadOnly, // 0x00 + __reserved_0: [u32; 5], // 0x04 + STATUS: ReadOnly, // 0x18 + __reserved_1: u32, // 0x1C + WRITE: WriteOnly, // 0x20 } // Custom errors @@ -71,17 +78,13 @@ mod response { } pub const REQUEST: u32 = 0; -const FULL: u32 = 0x8000_0000; -const EMPTY: u32 = 0x4000_0000; // Public interface to the mailbox #[repr(C)] +#[repr(align(16))] pub struct Mbox { // The address for buffer needs to be 16-byte aligned so that the - // Videcore can handle it properly. We don't take precautions here - // 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. + // Videcore can handle it properly. pub buffer: [u32; 36], } @@ -117,34 +120,33 @@ impl Mbox { pub fn call(&self, channel: u32) -> Result<()> { // wait until we can write to the mailbox loop { - if (self.STATUS.read() & FULL) != FULL { + if !self.STATUS.is_set(STATUS::FULL) { break; } unsafe { asm!("nop" :::: "volatile") }; } + let buf_ptr = self.buffer.as_ptr() as u32; + // write the address of our message to the mailbox with channel identifier - unsafe { - self.WRITE - .write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF)) - }; + self.WRITE.set((buf_ptr & !0xF) | (channel & 0xF)); // now wait for the response loop { // is there a response? loop { - if (self.STATUS.read() & EMPTY) != EMPTY { + if !self.STATUS.is_set(STATUS::EMPTY) { break; } unsafe { asm!("nop" :::: "volatile") }; } - let resp: u32 = self.READ.read(); + let resp: u32 = self.READ.get(); // is it a response to our message? - if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) { + if ((resp & 0xF) == channel) && ((resp & !0xF) == buf_ptr) { // is it a valid successful response? return match self.buffer[1] { response::SUCCESS => Ok(()), diff --git a/05_uart0/src/uart.rs b/05_uart0/src/uart.rs index b79aa2b0..a2afdfec 100644 --- a/05_uart0/src/uart.rs +++ b/05_uart0/src/uart.rs @@ -23,28 +23,116 @@ */ use super::MMIO_BASE; -use core::ops; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::{ + ops, + sync::atomic::{compiler_fence, Ordering}, +}; use gpio; use mbox; -use volatile_register::*; +use register::mmio::*; + +// PL011 UART registers. +// +// Descriptions taken from +// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf +register_bitfields! { + u32, + + /// Flag Register + FR [ + /// Transmit FIFO full. The meaning of this bit depends on the + /// state of the FEN bit in the UARTLCR_ LCRH Register. If the + /// FIFO is disabled, this bit is set when the transmit + /// holding register is full. If the FIFO is enabled, the TXFF + /// bit is set when the transmit FIFO is full. + TXFF OFFSET(5) NUMBITS(1) [], + + /// Receive FIFO empty. The meaning of this bit depends on the + /// state of the FEN bit in the UARTLCR_H Register. If the + /// FIFO is disabled, this bit is set when the receive holding + /// register is empty. If the FIFO is enabled, the RXFE bit is + /// set when the receive FIFO is empty. + RXFE OFFSET(4) NUMBITS(1) [] + ], + + /// Integer Baud rate divisor + IBRD [ + /// Integer Baud rate divisor + IBRD OFFSET(0) NUMBITS(16) [] + ], + + /// Fractional Baud rate divisor + FBRD [ + /// Fractional Baud rate divisor + FBRD OFFSET(0) NUMBITS(6) [] + ], + + /// Line Control register + LCRH [ + /// Word length. These bits indicate the number of data bits + /// transmitted or received in a frame. + WLEN OFFSET(5) NUMBITS(2) [ + FiveBit = 0b00, + SixBit = 0b01, + SevenBit = 0b10, + EightBit = 0b11 + ] + ], + + /// Control Register + CR [ + /// Receive enable. If this bit is set to 1, the receive + /// section of the UART is enabled. Data reception occurs for + /// UART signals. When the UART is disabled in the middle of + /// reception, it completes the current character before + /// stopping. + RXE OFFSET(9) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// Transmit enable. If this bit is set to 1, the transmit + /// section of the UART is enabled. Data transmission occurs + /// for UART signals. When the UART is disabled in the middle + /// of transmission, it completes the current character before + /// stopping. + TXE OFFSET(8) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// UART enable + UARTEN OFFSET(0) NUMBITS(1) [ + /// If the UART is disabled in the middle of transmission + /// or reception, it completes the current character + /// before stopping. + Disabled = 0, + Enabled = 1 + ] + ], + + /// Interupt Clear Register + ICR [ + /// Meta field for all pending interrupts + ALL OFFSET(0) NUMBITS(11) [] + ] +} const UART_BASE: u32 = MMIO_BASE + 0x20_1000; -// PL011 UART registers #[allow(non_snake_case)] #[repr(C)] pub struct RegisterBlock { - DR: RW, // 0x00 - __reserved_0: [u32; 5], // 0x04 - FR: RO, // 0x18 - __reserved_1: [u32; 2], // 0x1c - IBRD: WO, // 0x24 - FBRD: WO, // 0x28 - LCRH: WO, // 0x2C - CR: WO, // 0x30 - __reserved_2: [u32; 4], // 0x34 - ICR: WO, // 0x44 + DR: ReadWrite, // 0x00 + __reserved_0: [u32; 5], // 0x04 + FR: ReadOnly, // 0x18 + __reserved_1: [u32; 2], // 0x1c + IBRD: WriteOnly, // 0x24 + FBRD: WriteOnly, // 0x28 + LCRH: WriteOnly, // 0x2C + CR: WriteOnly, // 0x30 + __reserved_2: [u32; 4], // 0x34 + ICR: WriteOnly, // 0x44 } pub enum UartError { @@ -75,7 +163,7 @@ impl Uart { ///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.CR.write(0) }; + self.CR.set(0); // set up clock for consistent divisor values mbox.buffer[0] = 9 * 4; @@ -99,33 +187,30 @@ impl Uart { // map UART0 to GPIO pins unsafe { - (*gpio::GPFSEL1).modify(|x| { - // Modify with a closure - let mut ret = x; - ret &= !((7 << 12) | (7 << 15)); // gpio14, gpio15 - ret |= (4 << 12) | (4 << 15); // alt0 - - ret - }); + (*gpio::GPFSEL1).modify(gpio::GPFSEL1::FSEL14::TXD0 + gpio::GPFSEL1::FSEL15::RXD0); - (*gpio::GPPUD).write(0); // enable pins 14 and 15 + (*gpio::GPPUD).set(0); // enable pins 14 and 15 for _ in 0..150 { asm!("nop" :::: "volatile"); } - (*gpio::GPPUDCLK0).write((1 << 14) | (1 << 15)); + (*gpio::GPPUDCLK0).write( + gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, + ); for _ in 0..150 { asm!("nop" :::: "volatile"); } - (*gpio::GPPUDCLK0).write(0); - 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 + (*gpio::GPPUDCLK0).set(0); } + self.ICR.write(ICR::ALL::CLEAR); + self.IBRD.write(IBRD::IBRD.val(2)); // Results in 115200 baud + self.FBRD.write(FBRD::FBRD.val(0xB)); + self.LCRH.write(LCRH::WLEN::EightBit); // 8N1 + self.CR + .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); + Ok(()) } @@ -133,7 +218,7 @@ impl Uart { pub fn send(&self, c: char) { // wait until we can send loop { - if (self.FR.read() & 0x20) != 0x20 { + if !self.FR.is_set(FR::TXFF) { break; } @@ -141,14 +226,14 @@ impl Uart { } // write the character to the buffer - unsafe { self.DR.write(c as u32) }; + self.DR.set(c as u32); } /// Receive a character pub fn getc(&self) -> char { // wait until something is in the buffer loop { - if (self.FR.read() & 0x10) != 0x10 { + if !self.FR.is_set(FR::RXFE) { break; } @@ -156,7 +241,7 @@ impl Uart { } // read it and return - let mut ret = self.DR.read() as u8 as char; + let mut ret = self.DR.get() as u8 as char; // convert carrige return to newline if ret == '\r' { diff --git a/06_raspbootin64/Cargo.lock b/06_raspbootin64/Cargo.lock index c7511762..fa5cb7b9 100644 --- a/06_raspbootin64/Cargo.lock +++ b/06_raspbootin64/Cargo.lock @@ -3,7 +3,7 @@ name = "kernel8" version = "0.1.0" dependencies = [ "raspi3_glue 0.1.0", - "volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "register 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -19,19 +19,19 @@ dependencies = [ ] [[package]] -name = "vcell" -version = "0.1.0" +name = "register" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "tock-registers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "volatile-register" -version = "0.2.0" +name = "tock-registers" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] [metadata] "checksum panic-abort 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6bc796c620f27056d4ffe7c558533fd67ae5af0fd8e919fbe38de803368af73e" -"checksum vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45c297f0afb6928cd08ab1ff9d95e99392595ea25ae1b5ecf822ff8764e57a0d" -"checksum volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286" +"checksum register 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e985243ba7e1c336b62444ef2a10d7bd87cf41a222285ae3de605c859006479" +"checksum tock-registers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2acc33f980e23cee18d234a32d0637fbc1ea55e13ab04012fa857b899fa1b7a9" diff --git a/06_raspbootin64/Cargo.toml b/06_raspbootin64/Cargo.toml index df9e43a9..c3a97d79 100644 --- a/06_raspbootin64/Cargo.toml +++ b/06_raspbootin64/Cargo.toml @@ -5,4 +5,4 @@ authors = ["Andre Richter "] [dependencies] raspi3_glue = { path = "raspi3_glue" } -volatile-register = "0.2.0" +register = "0.1.1" diff --git a/06_raspbootin64/kernel8.img b/06_raspbootin64/kernel8.img index 45923d37dd3efa4e104ffb7647e00e611d85690f..7d5606149de189bbafd10f4a9ea663e683f749ae 100755 GIT binary patch literal 1768 zcmZ`(T})GF7=FL=@pBGP)cycw>H*@iQDPH|NXddU;1Yf|qiwS^F&QW~MFJ7CWE!@t zR+lh|xEeMu)p;R37Z?+lwO0eYncEdR)4Roz?4r;OLij5e_3Zgd$<7EiIeahQ`@HY> zyuT00^RlMEd-np-vz}`H(lCrl#vc6M#wggwsOsoVZ|3w(%Jdb`xkrZ4$Z+3E6g_1a z_tt==OfiYypZHYR@BDAHvpJdQTYCDuW!=wX_M(W-{@3Fx8#dZn9Vv+2mnf0s;g(df zcWae1O#!z0$LB4f5=ty`@0OhH)kEc!Sl~9T1M;O>s!J9FU+Ud**zWlp$;VgTx3Ku) zzC5;q5?|F)LSUUWtWF}b3qF&QH&OAW>Mv(B@mivR3x*L04IQ$|?67+hZ~YH{DmdcwHe43qCV=Ut!)vU7^*jFiHr$S*PMI#Z`Ad3;Py}-*MOXhJ8t{ zI`1RC(Ka>yO+<~~npNXt$e-Yzt0QHxKZquheG+sO{SLLHDr&N$1~wk?O+-G3+7QcV5k(uN2fht%*Ir1| z%}s~N+E1CL4K8a9c>DWWimI$4os=k`IJ}-Z2U&$KWhJW-;lp*nKZ0%yxYtr?It=;O z3a_UNxGw07Sw7r(P;uTcVR}s%E8bWDceB4AvPPikpzO3kw+P(^FV)PxW`+K^>?}3u zWu@FNFf!h%WF<~Ratxr~1LeSonuO3JRgOac*T{*=w|itX$5~GQf*gDvITB|XBe2se z0&fTY8t~}jTu-ePllwE^%oqnSmx1{?kJ+skK0+oRDfkHO@?k$v;O{YELg>kU@jl{d zgf5u(pF})6u{dz=GrjwtO;v-i>3)mNhkM%W&)J-Mi;ZUwn~96Evk|c!-^&K~^(LE? z687zmS>&zOgbC#_&m=mr&Q)!V+fjFmTh!qv)TatDRRAw)XU>DT-=DwF%{_8wNcQyP zrIVg@Ua2w6aSDEjwZ2*%`3SSo9oszL70YysIpR@{{t&Y#=4t1Avro-H)-Y4rdtz>Y z!ABQMu|L0{71R?xRSo&K8#idKBQ|{<{*#QpQ0Wj=i+yC`yeUIsSL7=4>L%l Qw1~gtYwJ97@`R=2UrcRSl>h($ delta 1000 zcmZ`&O-LI-6n>LIlC0UN8-Hrs5JL}|wXJkpTzd#c=%q$!+2&YkJ$TRHGhtfmclZISc+X^1^oI-`f6{S_E9-8f&O#~5K81~J4-+b@A?=b~_t$Myo z{Zq0QPAsblPMyHM&$t3Dbmx3;ik&WKT@L<$ghyr&6bE=VgbEQI^r zy&WYH!vj;w?b7*_>fnK6OR~jyixd%VZ_1M6jI7MQNie~f+S0tMN#f;c-wRe z5+i&=Li_?YfM*E;(I9B+q}t3oAhyyF=^ASQ!Bi=)&((pj_=+aC{2;tX@F@~iQfqEtJdVU8BpxBQ zn5D^sX0MpT^Cvc^#ughx&K7bSG07p0{>_1gWJE5X_;vCtqV&Ri;T-f4IGCpL+BxT2{adK)QF2CwrGq jqLDLvni{i_J=;9abb}7;mTCg080+{fb>F9O)e89!c56sY diff --git a/06_raspbootin64/raspi3_glue/src/lib.rs b/06_raspbootin64/raspi3_glue/src/lib.rs index aef1a672..d01c7a73 100644 --- a/06_raspbootin64/raspi3_glue/src/lib.rs +++ b/06_raspbootin64/raspi3_glue/src/lib.rs @@ -29,8 +29,6 @@ extern crate panic_abort; -use core::ptr; - #[lang = "start"] extern "C" fn start(user_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize where @@ -52,6 +50,8 @@ impl Termination for () { #[no_mangle] pub unsafe extern "C" fn reset() -> ! { + use core::ptr; + extern "C" { fn main(argc: isize, argv: *const *const u8) -> isize; } diff --git a/06_raspbootin64/src/gpio.rs b/06_raspbootin64/src/gpio.rs index 65bf7f0a..6ec8b4c6 100644 --- a/06_raspbootin64/src/gpio.rs +++ b/06_raspbootin64/src/gpio.rs @@ -23,8 +23,54 @@ */ use super::MMIO_BASE; -use volatile_register::RW; +use register::mmio::ReadWrite; -pub const GPFSEL1: *const RW = (MMIO_BASE + 0x0020_0004) as *const RW; -pub const GPPUD: *const RW = (MMIO_BASE + 0x0020_0094) as *const RW; -pub const GPPUDCLK0: *const RW = (MMIO_BASE + 0x0020_0098) as *const RW; +// Descriptions taken from +// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf +register_bitfields! { + u32, + + /// GPIO Function Select 1 + GPFSEL1 [ + /// Pin 15 + FSEL15 OFFSET(15) NUMBITS(3) [ + Input = 0b000, + Output = 0b001, + RXD0 = 0b100, // UART0 - Alternate function 0 + RXD1 = 0b010 // Mini UART - Alternate function 5 + + ], + + /// Pin 14 + FSEL14 OFFSET(12) NUMBITS(3) [ + Input = 0b000, + Output = 0b001, + TXD0 = 0b100, // UART0 - Alternate function 0 + TXD1 = 0b010 // Mini UART - Alternate function 5 + ] + ], + + /// GPIO Pull-up/down Clock Register 0 + GPPUDCLK0 [ + /// Pin 15 + PUDCLK15 OFFSET(15) NUMBITS(1) [ + NoEffect = 0, + AssertClock = 1 + ], + + /// Pin 14 + PUDCLK14 OFFSET(14) NUMBITS(1) [ + NoEffect = 0, + AssertClock = 1 + ] + ] +} + + +pub const GPFSEL1: *const ReadWrite = + (MMIO_BASE + 0x0020_0004) as *const ReadWrite; + +pub const GPPUD: *const ReadWrite = (MMIO_BASE + 0x0020_0094) as *const ReadWrite; + +pub const GPPUDCLK0: *const ReadWrite = + (MMIO_BASE + 0x0020_0098) as *const ReadWrite; diff --git a/06_raspbootin64/src/main.rs b/06_raspbootin64/src/main.rs index e5009318..5a4c18f0 100644 --- a/06_raspbootin64/src/main.rs +++ b/06_raspbootin64/src/main.rs @@ -26,7 +26,9 @@ #![feature(asm)] extern crate raspi3_glue; -extern crate volatile_register; + +#[macro_use] +extern crate register; const MMIO_BASE: u32 = 0x3F00_0000; diff --git a/06_raspbootin64/src/mbox.rs b/06_raspbootin64/src/mbox.rs index 698daf93..b33d2dab 100644 --- a/06_raspbootin64/src/mbox.rs +++ b/06_raspbootin64/src/mbox.rs @@ -24,20 +24,27 @@ use super::MMIO_BASE; use core::ops; -use volatile_register::{RO, WO}; +use register::mmio::{ReadOnly, WriteOnly}; + +register_bitfields! { + u32, + + STATUS [ + FULL OFFSET(31) NUMBITS(1) [], + EMPTY OFFSET(30) NUMBITS(1) [] + ] +} const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880; #[allow(non_snake_case)] #[repr(C)] pub struct RegisterBlock { - READ: RO, // 0x00 - __reserved_0: [u32; 3], // 0x04 - POLL: RO, // 0x10 - SENDER: RO, // 0x14 - STATUS: RO, // 0x18 - CONFIG: RO, // 0x1C - WRITE: WO, // 0x20 + READ: ReadOnly, // 0x00 + __reserved_0: [u32; 5], // 0x04 + STATUS: ReadOnly, // 0x18 + __reserved_1: u32, // 0x1C + WRITE: WriteOnly, // 0x20 } // Custom errors @@ -70,17 +77,13 @@ mod response { } pub const REQUEST: u32 = 0; -const FULL: u32 = 0x8000_0000; -const EMPTY: u32 = 0x4000_0000; // Public interface to the mailbox #[repr(C)] +#[repr(align(16))] pub struct Mbox { // The address for buffer needs to be 16-byte aligned so that the - // Videcore can handle it properly. We don't take precautions here - // 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. + // Videcore can handle it properly. pub buffer: [u32; 36], } @@ -116,34 +119,33 @@ impl Mbox { pub fn call(&self, channel: u32) -> Result<()> { // wait until we can write to the mailbox loop { - if (self.STATUS.read() & FULL) != FULL { + if !self.STATUS.is_set(STATUS::FULL) { break; } unsafe { asm!("nop" :::: "volatile") }; } + let buf_ptr = self.buffer.as_ptr() as u32; + // write the address of our message to the mailbox with channel identifier - unsafe { - self.WRITE - .write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF)) - }; + self.WRITE.set((buf_ptr & !0xF) | (channel & 0xF)); // now wait for the response loop { // is there a response? loop { - if (self.STATUS.read() & EMPTY) != EMPTY { + if !self.STATUS.is_set(STATUS::EMPTY) { break; } unsafe { asm!("nop" :::: "volatile") }; } - let resp: u32 = self.READ.read(); + let resp: u32 = self.READ.get(); // is it a response to our message? - if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) { + if ((resp & 0xF) == channel) && ((resp & !0xF) == buf_ptr) { // is it a valid successful response? return match self.buffer[1] { response::SUCCESS => Ok(()), diff --git a/06_raspbootin64/src/uart.rs b/06_raspbootin64/src/uart.rs index 6044e590..e148331b 100644 --- a/06_raspbootin64/src/uart.rs +++ b/06_raspbootin64/src/uart.rs @@ -23,28 +23,116 @@ */ use super::MMIO_BASE; -use core::ops; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::{ + ops, + sync::atomic::{compiler_fence, Ordering}, +}; use gpio; use mbox; -use volatile_register::*; +use register::mmio::*; + +// PL011 UART registers. +// +// Descriptions taken from +// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf +register_bitfields! { + u32, + + /// Flag Register + FR [ + /// Transmit FIFO full. The meaning of this bit depends on the + /// state of the FEN bit in the UARTLCR_ LCRH Register. If the + /// FIFO is disabled, this bit is set when the transmit + /// holding register is full. If the FIFO is enabled, the TXFF + /// bit is set when the transmit FIFO is full. + TXFF OFFSET(5) NUMBITS(1) [], + + /// Receive FIFO empty. The meaning of this bit depends on the + /// state of the FEN bit in the UARTLCR_H Register. If the + /// FIFO is disabled, this bit is set when the receive holding + /// register is empty. If the FIFO is enabled, the RXFE bit is + /// set when the receive FIFO is empty. + RXFE OFFSET(4) NUMBITS(1) [] + ], + + /// Integer Baud rate divisor + IBRD [ + /// Integer Baud rate divisor + IBRD OFFSET(0) NUMBITS(16) [] + ], + + /// Fractional Baud rate divisor + FBRD [ + /// Fractional Baud rate divisor + FBRD OFFSET(0) NUMBITS(6) [] + ], + + /// Line Control register + LCRH [ + /// Word length. These bits indicate the number of data bits + /// transmitted or received in a frame. + WLEN OFFSET(5) NUMBITS(2) [ + FiveBit = 0b00, + SixBit = 0b01, + SevenBit = 0b10, + EightBit = 0b11 + ] + ], + + /// Control Register + CR [ + /// Receive enable. If this bit is set to 1, the receive + /// section of the UART is enabled. Data reception occurs for + /// UART signals. When the UART is disabled in the middle of + /// reception, it completes the current character before + /// stopping. + RXE OFFSET(9) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// Transmit enable. If this bit is set to 1, the transmit + /// section of the UART is enabled. Data transmission occurs + /// for UART signals. When the UART is disabled in the middle + /// of transmission, it completes the current character before + /// stopping. + TXE OFFSET(8) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// UART enable + UARTEN OFFSET(0) NUMBITS(1) [ + /// If the UART is disabled in the middle of transmission + /// or reception, it completes the current character + /// before stopping. + Disabled = 0, + Enabled = 1 + ] + ], + + /// Interupt Clear Register + ICR [ + /// Meta field for all pending interrupts + ALL OFFSET(0) NUMBITS(11) [] + ] +} const UART_BASE: u32 = MMIO_BASE + 0x20_1000; -// PL011 UART registers #[allow(non_snake_case)] #[repr(C)] pub struct RegisterBlock { - DR: RW, // 0x00 - __reserved_0: [u32; 5], // 0x04 - FR: RO, // 0x18 - __reserved_1: [u32; 2], // 0x1c - IBRD: WO, // 0x24 - FBRD: WO, // 0x28 - LCRH: WO, // 0x2C - CR: WO, // 0x30 - __reserved_2: [u32; 4], // 0x34 - ICR: WO, // 0x44 + DR: ReadWrite, // 0x00 + __reserved_0: [u32; 5], // 0x04 + FR: ReadOnly, // 0x18 + __reserved_1: [u32; 2], // 0x1c + IBRD: WriteOnly, // 0x24 + FBRD: WriteOnly, // 0x28 + LCRH: WriteOnly, // 0x2C + CR: WriteOnly, // 0x30 + __reserved_2: [u32; 4], // 0x34 + ICR: WriteOnly, // 0x44 } pub enum UartError { @@ -75,7 +163,7 @@ impl Uart { ///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.CR.write(0) }; + self.CR.set(0); // set up clock for consistent divisor values mbox.buffer[0] = 9 * 4; @@ -99,33 +187,30 @@ impl Uart { // map UART0 to GPIO pins unsafe { - (*gpio::GPFSEL1).modify(|x| { - // Modify with a closure - let mut ret = x; - ret &= !((7 << 12) | (7 << 15)); // gpio14, gpio15 - ret |= (4 << 12) | (4 << 15); // alt0 - - ret - }); + (*gpio::GPFSEL1).modify(gpio::GPFSEL1::FSEL14::TXD0 + gpio::GPFSEL1::FSEL15::RXD0); - (*gpio::GPPUD).write(0); // enable pins 14 and 15 + (*gpio::GPPUD).set(0); // enable pins 14 and 15 for _ in 0..150 { asm!("nop" :::: "volatile"); } - (*gpio::GPPUDCLK0).write((1 << 14) | (1 << 15)); + (*gpio::GPPUDCLK0).modify( + gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, + ); for _ in 0..150 { asm!("nop" :::: "volatile"); } - (*gpio::GPPUDCLK0).write(0); - 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 + (*gpio::GPPUDCLK0).set(0); } + self.ICR.write(ICR::ALL::CLEAR); + self.IBRD.write(IBRD::IBRD.val(2)); // Results in 115200 baud + self.FBRD.write(FBRD::FBRD.val(0xB)); + self.LCRH.write(LCRH::WLEN::EightBit); // 8N1 + self.CR + .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); + Ok(()) } @@ -133,7 +218,7 @@ impl Uart { pub fn send(&self, c: char) { // wait until we can send loop { - if (self.FR.read() & 0x20) != 0x20 { + if !self.FR.is_set(FR::TXFF) { break; } @@ -141,14 +226,14 @@ impl Uart { } // write the character to the buffer - unsafe { self.DR.write(c as u32) }; + self.DR.set(c as u32); } /// Receive a character pub fn getc(&self) -> u8 { // wait until something is in the buffer loop { - if (self.FR.read() & 0x10) != 0x10 { + if !self.FR.is_set(FR::RXFE) { break; } @@ -156,6 +241,6 @@ impl Uart { } // read it and return - self.DR.read() as u8 + self.DR.get() as u8 } } diff --git a/07_abstraction/Cargo.lock b/07_abstraction/Cargo.lock index 595dbca6..b1d7d368 100644 --- a/07_abstraction/Cargo.lock +++ b/07_abstraction/Cargo.lock @@ -1,23 +1,18 @@ -[[package]] -name = "bitflags" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "cortex-a" -version = "0.1.3" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "register 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "kernel8" version = "0.1.0" dependencies = [ - "cortex-a 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cortex-a 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "raspi3_glue 0.1.0", - "volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "register 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -34,28 +29,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "raspi3_glue" version = "0.1.0" dependencies = [ - "cortex-a 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cortex-a 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "panic-abort 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "vcell" -version = "0.1.0" +name = "register" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "tock-registers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "volatile-register" -version = "0.2.0" +name = "tock-registers" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] [metadata] -"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" -"checksum cortex-a 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a123fa5a346531ed0fc9fcb8f69ca34d9b8c55b15162731945d14c4d461c5bfe" +"checksum cortex-a 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24174fbfe16d46844856c0f5e16ee15f7adbacfd87cb0148d34463dd34b54eeb" "checksum panic-abort 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6bc796c620f27056d4ffe7c558533fd67ae5af0fd8e919fbe38de803368af73e" "checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -"checksum vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45c297f0afb6928cd08ab1ff9d95e99392595ea25ae1b5ecf822ff8764e57a0d" -"checksum volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286" +"checksum register 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e985243ba7e1c336b62444ef2a10d7bd87cf41a222285ae3de605c859006479" +"checksum tock-registers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2acc33f980e23cee18d234a32d0637fbc1ea55e13ab04012fa857b899fa1b7a9" diff --git a/07_abstraction/Cargo.toml b/07_abstraction/Cargo.toml index 27e97224..a9dc0498 100644 --- a/07_abstraction/Cargo.toml +++ b/07_abstraction/Cargo.toml @@ -5,5 +5,5 @@ authors = ["Andre Richter "] [dependencies] raspi3_glue = { path = "raspi3_glue" } -cortex-a = "0.1.3" -volatile-register = "0.2.0" +cortex-a = "1.0.0" +register = "0.1.1" diff --git a/07_abstraction/README.md b/07_abstraction/README.md index 7b5a064e..f5d646b3 100644 --- a/07_abstraction/README.md +++ b/07_abstraction/README.md @@ -15,20 +15,30 @@ wrappers around assembly instructions. For single assembler instructions, we now have the `cortex-a::asm` namespace, e.g. providing `asm::nop()`. -For registers, there is `cortex-a::register`. For registers like the stack -pointer, which are generally read and written as a whole, there's simple -[read()][sp_read] and [write()][sp_write] functions which take and return -primitive integer types. +For registers, there is `cortex-a::regs`. The interface is the same as we have +it for MMIO accesses, aka provided by [register-rs][register-rs] and therefore +based on [tock-regs][tock-regs]. For registers like the stack pointer, which are +generally read and written as a whole, there's the common [get()][get] and +[set()][set] functions which take and return primitive integer types. + +[register-rs]: https://github.com/rust-osdev/register-rs +[tock-regs]: https://github.com/tock/tock/tree/master/libraries/tock-register-interface +[get]: https://docs.rs/cortex-a/1.0.0/cortex_a/regs/sp/trait.RegisterReadWrite.html#tymethod.get +[set]: https://docs.rs/cortex-a/1.0.0/cortex_a/regs/sp/trait.RegisterReadWrite.html#tymethod.set + +Registers that are divided into multiple fields, like `MPIDR_EL1` ([see the ARM +Reference Manual][el1]), on the other hand, are backed by a respective +[type][cntp_type] definition that allow for fine-grained reading and +modifications. -[sp_read]: https://docs.rs/cortex-a/0.1.2/cortex_a/register/sp/fn.read.html -[sp_write]: https://docs.rs/cortex-a/0.1.2/cortex_a/register/sp/fn.write.html +[el1]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0500g/BABHBJCI.html +[cntp_bitfields]: https://docs.rs/cortex-a/1.0.0/cortex_a/regs/cntp_ctl_el0/CNTP_CTL_EL0/index.html -Registers that are divided into multiple fields, e.g. `MPIDR_EL1` ([see the ARM -Reference Manual][el1]), on the other hand, are abstracted into their [own -types][mpidr_type] and offer getter and/or setter methods, respectively. +The register API is based on the [tock project's][tock] register +interface. Please see [their homepage][tock_registers] for all the details. -[el1]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0500g/BABHBJCI.html -[mpidr_type]:https://docs.rs/cortex-a/0.1.2/cortex_a/register/mpidr_el1/struct.MPIDR_EL1.html +[tock]: https://github.com/tock/tock +[tock_register]: https://github.com/tock/tock/tree/master/libraries/tock-register-interface To some extent, this namespacing also makes our code more portable. For example, if we want to reuse parts of it on another processor architecture, we could pull @@ -56,11 +66,13 @@ replaced it with a Rust function. Why? Because we can, for the fun of it. #[link_section = ".text.boot"] #[no_mangle] pub extern "C" fn _boot_cores() -> ! { - match register::MPIDR_EL1::read_raw() & 0x3 { - 0 => unsafe { - register::sp::write(0x80_000); - reset() - }, + use cortex_a::{asm, regs::mpidr_el1::*, regs::sp::*}; + + match MPIDR_EL1.get() & 0x3 { + 0 => { + SP.set(0x80_000); + unsafe { reset() } + } _ => loop { // if not core0, infinitely wait for events asm::wfe(); @@ -74,7 +86,7 @@ set up yet. Actually it is this function that will do it for the first time. Therefore, it is important to check that code generated from this function does not call any subroutines that need a working stack themselves. -The `read_raw()` and `asm` wrappers that we use from the `cortex-a` crate are all +The `get()` and `asm` wrappers that we use from the `cortex-a` crate are all inlined, so we fulfill this requirement. The compilation result of this function should yield something like the following, where you can see that the stack pointer is not used apart from ourselves setting it. diff --git a/07_abstraction/kernel8.img b/07_abstraction/kernel8.img index 35c2f5367ba745f082306d11fe5b362665d77c97..b71974406ff72ae2826ad603a7612428a79c8d50 100755 GIT binary patch literal 2544 zcmZ`*ZA?>F7=G`)KyMLH`T>Z*Eo8a@vDr%0vIMQdGQ{XyTb0F3`3Ol7s4L2*>Bg6T zP%>QSn92U&_G8i}(=0QlO}2~=|LA_1&h3}6Ec?O7hGP|>F>v>s+si15P1<|$XdyQm{CgJWS6h*4J{jP;s)( zqU9*W{E0r~F*GSimS(QoKCRheDXr_aM+B*42=VpplY$p}rQoG8DcFzvG3^n7EKzTj zf8J5)f2y~|kaypRaPqfUrOGN#J!)-F$meEbvg1SKX^#-k=iAK38D_5W+7>B4QopeF)6odByd|kX@W(3buSvG48Fg37CL=uK#h(S+K$ zx-!W#4_j8x#oS|9SBG_F?C%I_#q{)HZZ_;`s-5loFQI{Py4*PqEqFTIIc3sT^6cmt z%smP$2P``yi5yw5Kcm&NGYF1;#&N=+Xi8;zP8bv(rspX1e1ti(n6sXqN!7ka&!J6m zJ%=`}(eqGU_jx_Pucv2s+Nz%2X)oxx_YysK*3)Aa<9f{E8a<(x==otiJq1atdJ2+W z(DUs}^jup{PX_6fdS#HpQ-*pSL5>H3{rS0i8DYPy+F6dTpk7h$KJ2Z%*mL9m?>AWx z?(^t9=pViboSml!C^qj%MbFsa@4@^?BM&?I2A1WkBSbr+-UHyM@jpF)9wP|82Am}k zJ)8AyY8tC3d~d8mkG`x&Uyf+#yOp!#!d@|;|DFQpklKHrfVYp&x3FHHh%=)9)+K0n zt=oSMO8CfV`29;UlEUZ5myK?O`>-X@nTCM`i|ni zv(5L7>i-`8i7mDe!{*8uXUE6c7%SMESAER)2YPQZ@}SuARGTK>g8SjB6Fv2LUBwBy zSZvM6jmUc74)P50eYrbPI}`Y8Y3q9C)4WB&3+X%X`RsC%FjF)eHME`kbebd|4R1Km3LG0nNaf%_=H z`oDaE?pIHGKR2auhqN~GO{2%NJ9!3o@?U~BP}4(m{pphRG45pdQf;_x$rT<*r*ijF zb$I)`lC^E=aM+wFS!ZGYR7>T53u%FY9aKIG|IJUyIle8NoZn4Bj7@p6xy4E9Dr6EBqMm8D=9J*M`lC zCTLOktHb7Gww^0|85+!ro?4avaCiV1rq8Tsi)&$;%!;OSYJ71`Obg>K#hfW2J#ZOM zZh^fs@H5DrZv?sAPvS2kiT$|q=Qtx-M^TTJJAmaMbzJj#Mg7Nj3zUX2^J8BTX)D+- znUr6mBwR$ySKZXwdfH^~ICHkXv8mo&n0oNM=}c35bA7AH-O<+2)NX1%^QI~Fh`YX_ ZwaIk$w8_)a)V=~KOr?LcaRn>S{{S5USh)ZI literal 2016 zcma)7T})GF7=BL=q^Ex_yWQkGqyRfsw#Y$<2YcY2)cV$&vv_dVbH zyw7=_?~jY*zH2G57K$_iZ6nLi5{& zUV8~8(_GBgipN0{4Y#Vv7~vLOv%DcaT1(M(H3deSK8S|E`w@}J0&Y9!&HN~Bb-j=G zaZbp8tD?Y|+3UV-CL`+`E+^w?oR8iH*GbeGNytwiZZ&z`3&1R3d~}kJKB_3QU03SF zQ^0{b<5&ycdER21<%NH7T`Nd|TNMTy(-rzl3YdUfP;e_b`+*yJr--xuDFw6&-z80% zpK1E8LT?-5%48nvk`z#(&V1Fw*Dd(6#cQrIkB@kr?GkNycV&%@F+cW__&4>yh5nEN z6MXO|0dp!~KK1Cc^;P-v>MEzbuiD>opUUg{s@>co1rN(@ z-Ru3kfv@dezb&|lq66`P%7lW|qCN$z23YwU`%M1F;A;imzRx7%8GkrF{NMb$R~Pwr zuYNuM4*e_s9r`!puNR8^^}_4HwZyd3ul%i}O zPJ(0byk{n_Hab~-8uhLfwIIeG){!&pK;$jXa2aL7INM<(-qjnN;kA^(c{t;po%FES zba&EYYeyY^nOEjvQ1M#yBe_<3Ord@g9#imWgU28|)+!zw6_3y1u@kscB+7Hf@*C1- z*C--~Z(6-I$+uK7U+#b^d2d-dH;4HcR|#EK+yQd^tD59_rG5wX*$v(d!)}(4uPf#o zk;~YhYm%(?D^Jdwz&69{L8g%tU8`}fpB-;aJ@>byupg2Yc$a(bDLv|H=MO7-1{A$= zKlBcOCyb{ScShrOifXul%0cBkvT=4E2UL_{_+87JUBBbb&0$~3_W^ur@CXlfF4aEX zxrDjNU&9^B#^m=8=_(t$j`dt#Wm!aD8hbMBgRfTMLqYi#!JbExF>V!m?y9EE6SP>Nf<2dg;n0ANTDs;Q|Qc&7^opq zXwKR{vABB*d$W#mi+dj9!y0OM%zDaJriF3Wq2~eqADu?zUPu88 zr^;jQk`tKAT_j8kBqVA}=?P~hH#=8s-PoM7pHK|{{N1Qzsu)jtrH*q?r18iVQT|I* zLY&;&+|k{ANc0^&d?a+BBNVY}_k1ZH?&v)j>J}qMd-iwqiU$wBCu%>9g!XrLh(`{I S(W4!`FCkVf<"] [dependencies] -cortex-a = "0.1.3" +cortex-a = "1.0.0" panic-abort = "0.2.0" r0 = "0.2.2" diff --git a/07_abstraction/raspi3_glue/src/lib.rs b/07_abstraction/raspi3_glue/src/lib.rs index a84d91f2..97ff3f7c 100644 --- a/07_abstraction/raspi3_glue/src/lib.rs +++ b/07_abstraction/raspi3_glue/src/lib.rs @@ -30,9 +30,6 @@ extern crate cortex_a; extern crate panic_abort; extern crate r0; -use core::ptr; -use cortex_a::{asm, register}; - #[lang = "start"] extern "C" fn start(user_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize where @@ -53,6 +50,8 @@ impl Termination for () { } unsafe fn reset() -> ! { + use core::ptr; + extern "C" { fn main(argc: isize, argv: *const *const u8) -> isize; @@ -77,11 +76,13 @@ unsafe fn reset() -> ! { #[link_section = ".text.boot"] #[no_mangle] pub extern "C" fn _boot_cores() -> ! { - match register::MPIDR_EL1::read_raw() & 0x3 { - 0 => unsafe { - register::SP::write_raw(0x80_000); - reset() - }, + use cortex_a::{asm, regs::mpidr_el1::*, regs::sp::*}; + + match MPIDR_EL1.get() & 0x3 { + 0 => { + SP.set(0x80_000); + unsafe { reset() } + } _ => loop { // if not core0, infinitely wait for events asm::wfe(); diff --git a/07_abstraction/src/gpio.rs b/07_abstraction/src/gpio.rs index 65bf7f0a..6ec8b4c6 100644 --- a/07_abstraction/src/gpio.rs +++ b/07_abstraction/src/gpio.rs @@ -23,8 +23,54 @@ */ use super::MMIO_BASE; -use volatile_register::RW; +use register::mmio::ReadWrite; -pub const GPFSEL1: *const RW = (MMIO_BASE + 0x0020_0004) as *const RW; -pub const GPPUD: *const RW = (MMIO_BASE + 0x0020_0094) as *const RW; -pub const GPPUDCLK0: *const RW = (MMIO_BASE + 0x0020_0098) as *const RW; +// Descriptions taken from +// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf +register_bitfields! { + u32, + + /// GPIO Function Select 1 + GPFSEL1 [ + /// Pin 15 + FSEL15 OFFSET(15) NUMBITS(3) [ + Input = 0b000, + Output = 0b001, + RXD0 = 0b100, // UART0 - Alternate function 0 + RXD1 = 0b010 // Mini UART - Alternate function 5 + + ], + + /// Pin 14 + FSEL14 OFFSET(12) NUMBITS(3) [ + Input = 0b000, + Output = 0b001, + TXD0 = 0b100, // UART0 - Alternate function 0 + TXD1 = 0b010 // Mini UART - Alternate function 5 + ] + ], + + /// GPIO Pull-up/down Clock Register 0 + GPPUDCLK0 [ + /// Pin 15 + PUDCLK15 OFFSET(15) NUMBITS(1) [ + NoEffect = 0, + AssertClock = 1 + ], + + /// Pin 14 + PUDCLK14 OFFSET(14) NUMBITS(1) [ + NoEffect = 0, + AssertClock = 1 + ] + ] +} + + +pub const GPFSEL1: *const ReadWrite = + (MMIO_BASE + 0x0020_0004) as *const ReadWrite; + +pub const GPPUD: *const ReadWrite = (MMIO_BASE + 0x0020_0094) as *const ReadWrite; + +pub const GPPUDCLK0: *const ReadWrite = + (MMIO_BASE + 0x0020_0098) as *const ReadWrite; diff --git a/07_abstraction/src/main.rs b/07_abstraction/src/main.rs index 1711690d..1c9a3aa9 100644 --- a/07_abstraction/src/main.rs +++ b/07_abstraction/src/main.rs @@ -26,7 +26,9 @@ extern crate cortex_a; extern crate raspi3_glue; -extern crate volatile_register; + +#[macro_use] +extern crate register; const MMIO_BASE: u32 = 0x3F00_0000; diff --git a/07_abstraction/src/mbox.rs b/07_abstraction/src/mbox.rs index 405d6056..3a2bc67f 100644 --- a/07_abstraction/src/mbox.rs +++ b/07_abstraction/src/mbox.rs @@ -25,20 +25,27 @@ use super::MMIO_BASE; use core::ops; use cortex_a::asm; -use volatile_register::{RO, WO}; +use register::mmio::{ReadOnly, WriteOnly}; + +register_bitfields! { + u32, + + STATUS [ + FULL OFFSET(31) NUMBITS(1) [], + EMPTY OFFSET(30) NUMBITS(1) [] + ] +} const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880; #[allow(non_snake_case)] #[repr(C)] pub struct RegisterBlock { - READ: RO, // 0x00 - __reserved_0: [u32; 3], // 0x04 - POLL: RO, // 0x10 - SENDER: RO, // 0x14 - STATUS: RO, // 0x18 - CONFIG: RO, // 0x1C - WRITE: WO, // 0x20 + READ: ReadOnly, // 0x00 + __reserved_0: [u32; 5], // 0x04 + STATUS: ReadOnly, // 0x18 + __reserved_1: u32, // 0x1C + WRITE: WriteOnly, // 0x20 } // Custom errors @@ -72,17 +79,13 @@ mod response { } pub const REQUEST: u32 = 0; -const FULL: u32 = 0x8000_0000; -const EMPTY: u32 = 0x4000_0000; // Public interface to the mailbox #[repr(C)] +#[repr(align(16))] pub struct Mbox { // The address for buffer needs to be 16-byte aligned so that the - // Videcore can handle it properly. We don't take precautions here - // 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. + // Videcore can handle it properly. pub buffer: [u32; 36], } @@ -118,34 +121,33 @@ impl Mbox { pub fn call(&self, channel: u32) -> Result<()> { // wait until we can write to the mailbox loop { - if (self.STATUS.read() & FULL) != FULL { + if !self.STATUS.is_set(STATUS::FULL) { break; } asm::nop(); } + let buf_ptr = self.buffer.as_ptr() as u32; + // write the address of our message to the mailbox with channel identifier - unsafe { - self.WRITE - .write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF)) - }; + self.WRITE.set((buf_ptr & !0xF) | (channel & 0xF)); // now wait for the response loop { // is there a response? loop { - if (self.STATUS.read() & EMPTY) != EMPTY { + if !self.STATUS.is_set(STATUS::EMPTY) { break; } asm::nop(); } - let resp: u32 = self.READ.read(); + let resp: u32 = self.READ.get(); // is it a response to our message? - if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) { + if ((resp & 0xF) == channel) && ((resp & !0xF) == buf_ptr) { // is it a valid successful response? return match self.buffer[1] { response::SUCCESS => Ok(()), diff --git a/07_abstraction/src/uart.rs b/07_abstraction/src/uart.rs index c8fd4fb5..a25f0d13 100644 --- a/07_abstraction/src/uart.rs +++ b/07_abstraction/src/uart.rs @@ -23,29 +23,117 @@ */ use super::MMIO_BASE; -use core::ops; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::{ + ops, + sync::atomic::{compiler_fence, Ordering}, +}; use cortex_a::asm; use gpio; use mbox; -use volatile_register::*; +use register::mmio::*; + +// PL011 UART registers. +// +// Descriptions taken from +// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf +register_bitfields! { + u32, + + /// Flag Register + FR [ + /// Transmit FIFO full. The meaning of this bit depends on the + /// state of the FEN bit in the UARTLCR_ LCRH Register. If the + /// FIFO is disabled, this bit is set when the transmit + /// holding register is full. If the FIFO is enabled, the TXFF + /// bit is set when the transmit FIFO is full. + TXFF OFFSET(5) NUMBITS(1) [], + + /// Receive FIFO empty. The meaning of this bit depends on the + /// state of the FEN bit in the UARTLCR_H Register. If the + /// FIFO is disabled, this bit is set when the receive holding + /// register is empty. If the FIFO is enabled, the RXFE bit is + /// set when the receive FIFO is empty. + RXFE OFFSET(4) NUMBITS(1) [] + ], + + /// Integer Baud rate divisor + IBRD [ + /// Integer Baud rate divisor + IBRD OFFSET(0) NUMBITS(16) [] + ], + + /// Fractional Baud rate divisor + FBRD [ + /// Fractional Baud rate divisor + FBRD OFFSET(0) NUMBITS(6) [] + ], + + /// Line Control register + LCRH [ + /// Word length. These bits indicate the number of data bits + /// transmitted or received in a frame. + WLEN OFFSET(5) NUMBITS(2) [ + FiveBit = 0b00, + SixBit = 0b01, + SevenBit = 0b10, + EightBit = 0b11 + ] + ], + + /// Control Register + CR [ + /// Receive enable. If this bit is set to 1, the receive + /// section of the UART is enabled. Data reception occurs for + /// UART signals. When the UART is disabled in the middle of + /// reception, it completes the current character before + /// stopping. + RXE OFFSET(9) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// Transmit enable. If this bit is set to 1, the transmit + /// section of the UART is enabled. Data transmission occurs + /// for UART signals. When the UART is disabled in the middle + /// of transmission, it completes the current character before + /// stopping. + TXE OFFSET(8) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// UART enable + UARTEN OFFSET(0) NUMBITS(1) [ + /// If the UART is disabled in the middle of transmission + /// or reception, it completes the current character + /// before stopping. + Disabled = 0, + Enabled = 1 + ] + ], + + /// Interupt Clear Register + ICR [ + /// Meta field for all pending interrupts + ALL OFFSET(0) NUMBITS(11) [] + ] +} const UART_BASE: u32 = MMIO_BASE + 0x20_1000; -// PL011 UART registers #[allow(non_snake_case)] #[repr(C)] pub struct RegisterBlock { - DR: RW, // 0x00 - __reserved_0: [u32; 5], // 0x04 - FR: RO, // 0x18 - __reserved_1: [u32; 2], // 0x1c - IBRD: WO, // 0x24 - FBRD: WO, // 0x28 - LCRH: WO, // 0x2C - CR: WO, // 0x30 - __reserved_2: [u32; 4], // 0x34 - ICR: WO, // 0x44 + DR: ReadWrite, // 0x00 + __reserved_0: [u32; 5], // 0x04 + FR: ReadOnly, // 0x18 + __reserved_1: [u32; 2], // 0x1c + IBRD: WriteOnly, // 0x24 + FBRD: WriteOnly, // 0x28 + LCRH: WriteOnly, // 0x2C + CR: WriteOnly, // 0x30 + __reserved_2: [u32; 4], // 0x34 + ICR: WriteOnly, // 0x44 } pub enum UartError { @@ -76,7 +164,7 @@ impl Uart { ///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.CR.write(0) }; + self.CR.set(0); // set up clock for consistent divisor values mbox.buffer[0] = 9 * 4; @@ -100,33 +188,30 @@ impl Uart { // map UART0 to GPIO pins unsafe { - (*gpio::GPFSEL1).modify(|x| { - // Modify with a closure - let mut ret = x; - ret &= !((7 << 12) | (7 << 15)); // gpio14, gpio15 - ret |= (4 << 12) | (4 << 15); // alt0 - - ret - }); + (*gpio::GPFSEL1).modify(gpio::GPFSEL1::FSEL14::TXD0 + gpio::GPFSEL1::FSEL15::RXD0); - (*gpio::GPPUD).write(0); // enable pins 14 and 15 + (*gpio::GPPUD).set(0); // enable pins 14 and 15 for _ in 0..150 { asm::nop(); } - (*gpio::GPPUDCLK0).write((1 << 14) | (1 << 15)); + (*gpio::GPPUDCLK0).modify( + gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, + ); for _ in 0..150 { asm::nop(); } - (*gpio::GPPUDCLK0).write(0); - 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 + (*gpio::GPPUDCLK0).set(0); } + self.ICR.write(ICR::ALL::CLEAR); + self.IBRD.write(IBRD::IBRD.val(2)); // Results in 115200 baud + self.FBRD.write(FBRD::FBRD.val(0xB)); + self.LCRH.write(LCRH::WLEN::EightBit); // 8N1 + self.CR + .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); + Ok(()) } @@ -134,7 +219,7 @@ impl Uart { pub fn send(&self, c: char) { // wait until we can send loop { - if (self.FR.read() & 0x20) != 0x20 { + if !self.FR.is_set(FR::TXFF) { break; } @@ -142,14 +227,14 @@ impl Uart { } // write the character to the buffer - unsafe { self.DR.write(c as u32) }; + self.DR.set(c as u32); } /// Receive a character pub fn getc(&self) -> char { // wait until something is in the buffer loop { - if (self.FR.read() & 0x10) != 0x10 { + if !self.FR.is_set(FR::RXFE) { break; } @@ -157,7 +242,7 @@ impl Uart { } // read it and return - let mut ret = self.DR.read() as u8 as char; + let mut ret = self.DR.get() as u8 as char; // convert carrige return to newline if ret == '\r' { diff --git a/08_random/Cargo.lock b/08_random/Cargo.lock index 595dbca6..b1d7d368 100644 --- a/08_random/Cargo.lock +++ b/08_random/Cargo.lock @@ -1,23 +1,18 @@ -[[package]] -name = "bitflags" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "cortex-a" -version = "0.1.3" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "register 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "kernel8" version = "0.1.0" dependencies = [ - "cortex-a 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cortex-a 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "raspi3_glue 0.1.0", - "volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "register 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -34,28 +29,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "raspi3_glue" version = "0.1.0" dependencies = [ - "cortex-a 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cortex-a 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "panic-abort 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "vcell" -version = "0.1.0" +name = "register" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "tock-registers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "volatile-register" -version = "0.2.0" +name = "tock-registers" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] [metadata] -"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" -"checksum cortex-a 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a123fa5a346531ed0fc9fcb8f69ca34d9b8c55b15162731945d14c4d461c5bfe" +"checksum cortex-a 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24174fbfe16d46844856c0f5e16ee15f7adbacfd87cb0148d34463dd34b54eeb" "checksum panic-abort 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6bc796c620f27056d4ffe7c558533fd67ae5af0fd8e919fbe38de803368af73e" "checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -"checksum vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45c297f0afb6928cd08ab1ff9d95e99392595ea25ae1b5ecf822ff8764e57a0d" -"checksum volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286" +"checksum register 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e985243ba7e1c336b62444ef2a10d7bd87cf41a222285ae3de605c859006479" +"checksum tock-registers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2acc33f980e23cee18d234a32d0637fbc1ea55e13ab04012fa857b899fa1b7a9" diff --git a/08_random/Cargo.toml b/08_random/Cargo.toml index 27e97224..a9dc0498 100644 --- a/08_random/Cargo.toml +++ b/08_random/Cargo.toml @@ -5,5 +5,5 @@ authors = ["Andre Richter "] [dependencies] raspi3_glue = { path = "raspi3_glue" } -cortex-a = "0.1.3" -volatile-register = "0.2.0" +cortex-a = "1.0.0" +register = "0.1.1" diff --git a/08_random/README.md b/08_random/README.md index 8ef25b0e..a26475ca 100644 --- a/08_random/README.md +++ b/08_random/README.md @@ -2,11 +2,14 @@ This going to be an easy tutorial. We query a number from the (undocumented) hardware random number generator. You can use this to implement a simple, but -accurate dice throw in any game. It is important as without hardware support -you can only generate pseudo-random numbers. +accurate dice throw in any game. It is important as without hardware support you +can only generate pseudo-random numbers. ## rand.s +Due to lack of documentation, we [mimic the respective Linux driver] +(https://github.com/torvalds/linux/blob/master/drivers/char/hw_random/bcm2835-rng.c). + `Rng::init(&self)` initializes the hardware. `Rng::rand(&self, min: u32, max: u32)` returns a random number between min and diff --git a/08_random/kernel8.img b/08_random/kernel8.img index f49f64d8c8cfb48b56401f085abf9107d1326f23..e139574285225a81236c739b0adee37cf69fd2b4 100755 GIT binary patch literal 2384 zcmZ`)YfMvT7=F(=T+Ts2=}mCRDFl-Nv6*FV{rc*Bd zL5XN5Xm&}|B~#iM{bNj~^d;Pz*xbN`IsmW9iPaaEyN%GvXks%1ix_WSx?p7;6Q z_xs*=kWBaFWb;3bM79RKa8FT`wUa`IQRc`y%u&Cd^uH25N+ow!BsxoFBjr!6f=`pu zZPEO3)%{FOk+3Jpcaf*yxX@WXnQD%N1TGuYubG zo?4m|#pZD4szh$RaS*YV*d5KYev@D~*u5tpWsquXKDor!T-C&aVv{*_%Vn&N6f?MS zIJeX?A&^Z}cUnZ8Pa578IF;0C*{;=;O2fLq9aX1A9+m?|$>d^uh7n)l%)z2$l~Lj- z$n=RiFkb&-ZG<)saHpTZpq8-+la0 znQ1+#?r`&OhXv6umyl~Hm27flm8%K0wj|^;N1JS|L!Pz@i}`$)={U{IC7x`O)@&-$ zl8Rx7YEsE31XmGoPe9kfYi5S9?$?=3HL$6HTpkr%+jFGi(YT(F%jbF>aHnwgu%KCj zH4;^9rW~=DapeA0Y#P{2$L$g^yP4glMZ4jMVoQtLiBhJO*@=jo&85X~hUXPq;$6tb z8BvRVIex}l-FX3amzX>!E}s|H788dY#qSx@sSuXwW#pT z)o=4fntvE%wPNpOuKs(-IiCjg343@Sdn>095A`c{9M82*rREx2j<2_h_bF@N@!Zmm zEOI@COxJaC-EPEvLe#I|evhM8j86}I*FruUm$Q3+9vm2^!8c97B1gtC%z-=TcVimbo)_I6(USClu$(C3-GoJ^ZIZO=NLf?UM>3H}=Y z75M*&8OVAxd&?qtuvsQvu8I_WTNT;Li8CX3lS~%-{|*J1Y!tOwSS`=P&yW23zXt9? z>b7~b0vv_tIo{q?bhF_zdh7rO=7OK~VdVtft)BFJu21K7N@ns-qt~+8ID^^vmmv9T zy6AClhHQF-+31Ycg<7MIP+ta>IiuB~jUURU)@W_WkR_XDAwMlq+22CCzi%^@%|d_U zG@1G~uzg+VI(%kfdmT1T%+sX!9BcYb)r!m}F>>pv@3p?g>11p>DGnnIy z&&DqDmT(Ni5qgAqZ_u)RUC0pQ1THcB>X0Fs#dCztfP*2%r!J0P8|s4%<7bF*Tjatx z8DgA{#Lu_LiE&}rCGeRNGW=(-a&v5U^E1eucL=%MPU6oZiM^P;k2x)w*j#4yD`d&X zhwl_99V_ZdxKBh>e~!T1B<=PM=LQP6$PVvvOu zKTiZK8NfxUptBagR+y_;ECP*>+O@CJ>gae0_?zV59zXY{--Fz@0kj5WTPT+QUOZuc z9j|98Ch?^V+|xSNabE`-Qa6+Xn(+|rzmKeIm^%whVh+a>TGp|NnoW$4&(r?(f^75M zbRKAMTQN@#+D#N}Ou`hGzr5V!WI-O;ng5uLp=17e6W6218QHDCt z@1lE-Zv2tKHDz!;Raj^4)w>dMz0J~Fma%+4>`G^W%wwWxCwv7}WNT3Z|MwYc!Q8jvj=iPtqZzXrG>s!FCy+OX%w^=|Vho?(kxpw7H+s5=BR=}!-=2tvhuGID zof};uK3-sX5;J7NNlMpWcvKX}QW`*wHX1_>Va1Zi?Z4tXaJ#22^4L`y**RYm!85^; zeIoC{72JR6xkV3T&zVToUddF|9_~?M0pE2bCSAV;GbDBw*M9$yVHfM7cy^-Ac;9{b zxm`p_yo*_Ir?D5dnz1&Hc_+rjYp_%u@3~=AQSU2Q;C{jP*@`?^naE=I)@enwCInky zwZXA@h~4ug8-(^`voNfN3SY8XuzYB6v?uEYYmULOf$<>)R6L?p(cx22v4Q#9L*N)b zM&=E|G}dgOb{aLlWRo!b9$-zAFpZ-x*)6mtKb5!}IN!v17rW_UL=0CV9g}=YZk7f2dm_#Ao`(7qT4{p61aBU9IoZNz}#bi372HT7Nr9Rc?QV7y+Sq-Ke8YV zDjXRyCjmtz`Gsn4TU&?Gd8M<$G5`Po diff --git a/08_random/raspi3_glue/Cargo.toml b/08_random/raspi3_glue/Cargo.toml index ba763bab..411b7763 100644 --- a/08_random/raspi3_glue/Cargo.toml +++ b/08_random/raspi3_glue/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" authors = ["Andre Richter "] [dependencies] -cortex-a = "0.1.3" +cortex-a = "1.0.0" panic-abort = "0.2.0" r0 = "0.2.2" diff --git a/08_random/raspi3_glue/src/lib.rs b/08_random/raspi3_glue/src/lib.rs index a84d91f2..97ff3f7c 100644 --- a/08_random/raspi3_glue/src/lib.rs +++ b/08_random/raspi3_glue/src/lib.rs @@ -30,9 +30,6 @@ extern crate cortex_a; extern crate panic_abort; extern crate r0; -use core::ptr; -use cortex_a::{asm, register}; - #[lang = "start"] extern "C" fn start(user_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize where @@ -53,6 +50,8 @@ impl Termination for () { } unsafe fn reset() -> ! { + use core::ptr; + extern "C" { fn main(argc: isize, argv: *const *const u8) -> isize; @@ -77,11 +76,13 @@ unsafe fn reset() -> ! { #[link_section = ".text.boot"] #[no_mangle] pub extern "C" fn _boot_cores() -> ! { - match register::MPIDR_EL1::read_raw() & 0x3 { - 0 => unsafe { - register::SP::write_raw(0x80_000); - reset() - }, + use cortex_a::{asm, regs::mpidr_el1::*, regs::sp::*}; + + match MPIDR_EL1.get() & 0x3 { + 0 => { + SP.set(0x80_000); + unsafe { reset() } + } _ => loop { // if not core0, infinitely wait for events asm::wfe(); diff --git a/08_random/src/gpio.rs b/08_random/src/gpio.rs index 65bf7f0a..6ec8b4c6 100644 --- a/08_random/src/gpio.rs +++ b/08_random/src/gpio.rs @@ -23,8 +23,54 @@ */ use super::MMIO_BASE; -use volatile_register::RW; +use register::mmio::ReadWrite; -pub const GPFSEL1: *const RW = (MMIO_BASE + 0x0020_0004) as *const RW; -pub const GPPUD: *const RW = (MMIO_BASE + 0x0020_0094) as *const RW; -pub const GPPUDCLK0: *const RW = (MMIO_BASE + 0x0020_0098) as *const RW; +// Descriptions taken from +// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf +register_bitfields! { + u32, + + /// GPIO Function Select 1 + GPFSEL1 [ + /// Pin 15 + FSEL15 OFFSET(15) NUMBITS(3) [ + Input = 0b000, + Output = 0b001, + RXD0 = 0b100, // UART0 - Alternate function 0 + RXD1 = 0b010 // Mini UART - Alternate function 5 + + ], + + /// Pin 14 + FSEL14 OFFSET(12) NUMBITS(3) [ + Input = 0b000, + Output = 0b001, + TXD0 = 0b100, // UART0 - Alternate function 0 + TXD1 = 0b010 // Mini UART - Alternate function 5 + ] + ], + + /// GPIO Pull-up/down Clock Register 0 + GPPUDCLK0 [ + /// Pin 15 + PUDCLK15 OFFSET(15) NUMBITS(1) [ + NoEffect = 0, + AssertClock = 1 + ], + + /// Pin 14 + PUDCLK14 OFFSET(14) NUMBITS(1) [ + NoEffect = 0, + AssertClock = 1 + ] + ] +} + + +pub const GPFSEL1: *const ReadWrite = + (MMIO_BASE + 0x0020_0004) as *const ReadWrite; + +pub const GPPUD: *const ReadWrite = (MMIO_BASE + 0x0020_0094) as *const ReadWrite; + +pub const GPPUDCLK0: *const ReadWrite = + (MMIO_BASE + 0x0020_0098) as *const ReadWrite; diff --git a/08_random/src/main.rs b/08_random/src/main.rs index acb1666c..9a328772 100644 --- a/08_random/src/main.rs +++ b/08_random/src/main.rs @@ -26,7 +26,9 @@ extern crate cortex_a; extern crate raspi3_glue; -extern crate volatile_register; + +#[macro_use] +extern crate register; const MMIO_BASE: u32 = 0x3F00_0000; diff --git a/08_random/src/mbox.rs b/08_random/src/mbox.rs index 6c6b9710..18fe5787 100644 --- a/08_random/src/mbox.rs +++ b/08_random/src/mbox.rs @@ -25,20 +25,27 @@ use super::MMIO_BASE; use core::ops; use cortex_a::asm; -use volatile_register::{RO, WO}; +use register::mmio::{ReadOnly, WriteOnly}; + +register_bitfields! { + u32, + + STATUS [ + FULL OFFSET(31) NUMBITS(1) [], + EMPTY OFFSET(30) NUMBITS(1) [] + ] +} const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880; #[allow(non_snake_case)] #[repr(C)] pub struct RegisterBlock { - READ: RO, // 0x00 - __reserved_0: [u32; 3], // 0x04 - POLL: RO, // 0x10 - SENDER: RO, // 0x14 - STATUS: RO, // 0x18 - CONFIG: RO, // 0x1C - WRITE: WO, // 0x20 + READ: ReadOnly, // 0x00 + __reserved_0: [u32; 5], // 0x04 + STATUS: ReadOnly, // 0x18 + __reserved_1: u32, // 0x1C + WRITE: WriteOnly, // 0x20 } // Custom errors @@ -71,17 +78,13 @@ mod response { } pub const REQUEST: u32 = 0; -const FULL: u32 = 0x8000_0000; -const EMPTY: u32 = 0x4000_0000; // Public interface to the mailbox #[repr(C)] +#[repr(align(16))] pub struct Mbox { // The address for buffer needs to be 16-byte aligned so that the - // Videcore can handle it properly. We don't take precautions here - // 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. + // Videcore can handle it properly. pub buffer: [u32; 36], } @@ -117,34 +120,33 @@ impl Mbox { pub fn call(&self, channel: u32) -> Result<()> { // wait until we can write to the mailbox loop { - if (self.STATUS.read() & FULL) != FULL { + if !self.STATUS.is_set(STATUS::FULL) { break; } asm::nop(); } + let buf_ptr = self.buffer.as_ptr() as u32; + // write the address of our message to the mailbox with channel identifier - unsafe { - self.WRITE - .write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF)) - }; + self.WRITE.set((buf_ptr & !0xF) | (channel & 0xF)); // now wait for the response loop { // is there a response? loop { - if (self.STATUS.read() & EMPTY) != EMPTY { + if !self.STATUS.is_set(STATUS::EMPTY) { break; } asm::nop(); } - let resp: u32 = self.READ.read(); + let resp: u32 = self.READ.get(); // is it a response to our message? - if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) { + if ((resp & 0xF) == channel) && ((resp & !0xF) == buf_ptr) { // is it a valid successful response? return match self.buffer[1] { response::SUCCESS => Ok(()), diff --git a/08_random/src/rand.rs b/08_random/src/rand.rs index de4d973d..866fce83 100644 --- a/08_random/src/rand.rs +++ b/08_random/src/rand.rs @@ -25,18 +25,37 @@ use super::MMIO_BASE; use core::ops; use cortex_a::asm; -use volatile_register::*; +use register::mmio::*; + +register_bitfields! { + u32, + + CTRL [ + ENABLE OFFSET(0) NUMBITS(1) [ + True = 1, + False = 0 + ] + ], + + INT_MASK [ + INT_OFF OFFSET(0) NUMBITS(1) [ + True = 1, + False = 0 + ] + ] +} const RNG_BASE: u32 = MMIO_BASE + 0x104_000; +const RNG_WARMUP_COUNT: u32 = 0x40_000; #[allow(non_snake_case)] #[repr(C)] pub struct RegisterBlock { - CTRL: RW, // 0x00 - STATUS: RW, // 0x04 - DATA: RO, // 0x08 - __reserved_0: u32, // 0x0c - INT_MASK: RW, // 0x10 + CTRL: ReadWrite, // 0x00 + STATUS: ReadWrite, // 0x04 + DATA: ReadOnly, // 0x08 + __reserved_0: u32, // 0x0c + INT_MASK: ReadWrite, // 0x10 } /// Public interface to the RNG @@ -62,29 +81,26 @@ impl Rng { /// Initialize the RNG pub fn init(&self) { - unsafe { - self.STATUS.write(0x40_000); - - // mask interrupt - self.INT_MASK.modify(|x| x | 1); + // Disable interrupts + self.INT_MASK.modify(INT_MASK::INT_OFF::True); - // enable - self.CTRL.modify(|x| x | 1); - } + // Set warm-up count and enable + self.STATUS.set(RNG_WARMUP_COUNT); + self.CTRL.modify(CTRL::ENABLE::True); + } + /// Return a random number between [min..max] + pub fn rand(&self, min: u32, max: u32) -> u32 { // wait for gaining some entropy loop { - if (self.STATUS.read() >> 24) != 0 { + if (self.STATUS.get() >> 24) != 0 { break; } asm::nop(); } - } - /// Return a random number between [min..max] - pub fn rand(&self, min: u32, max: u32) -> u32 { - let r = self.DATA.read(); + let r = self.DATA.get(); r % (max - min) + min } diff --git a/08_random/src/uart.rs b/08_random/src/uart.rs index c8fd4fb5..a25f0d13 100644 --- a/08_random/src/uart.rs +++ b/08_random/src/uart.rs @@ -23,29 +23,117 @@ */ use super::MMIO_BASE; -use core::ops; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::{ + ops, + sync::atomic::{compiler_fence, Ordering}, +}; use cortex_a::asm; use gpio; use mbox; -use volatile_register::*; +use register::mmio::*; + +// PL011 UART registers. +// +// Descriptions taken from +// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf +register_bitfields! { + u32, + + /// Flag Register + FR [ + /// Transmit FIFO full. The meaning of this bit depends on the + /// state of the FEN bit in the UARTLCR_ LCRH Register. If the + /// FIFO is disabled, this bit is set when the transmit + /// holding register is full. If the FIFO is enabled, the TXFF + /// bit is set when the transmit FIFO is full. + TXFF OFFSET(5) NUMBITS(1) [], + + /// Receive FIFO empty. The meaning of this bit depends on the + /// state of the FEN bit in the UARTLCR_H Register. If the + /// FIFO is disabled, this bit is set when the receive holding + /// register is empty. If the FIFO is enabled, the RXFE bit is + /// set when the receive FIFO is empty. + RXFE OFFSET(4) NUMBITS(1) [] + ], + + /// Integer Baud rate divisor + IBRD [ + /// Integer Baud rate divisor + IBRD OFFSET(0) NUMBITS(16) [] + ], + + /// Fractional Baud rate divisor + FBRD [ + /// Fractional Baud rate divisor + FBRD OFFSET(0) NUMBITS(6) [] + ], + + /// Line Control register + LCRH [ + /// Word length. These bits indicate the number of data bits + /// transmitted or received in a frame. + WLEN OFFSET(5) NUMBITS(2) [ + FiveBit = 0b00, + SixBit = 0b01, + SevenBit = 0b10, + EightBit = 0b11 + ] + ], + + /// Control Register + CR [ + /// Receive enable. If this bit is set to 1, the receive + /// section of the UART is enabled. Data reception occurs for + /// UART signals. When the UART is disabled in the middle of + /// reception, it completes the current character before + /// stopping. + RXE OFFSET(9) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// Transmit enable. If this bit is set to 1, the transmit + /// section of the UART is enabled. Data transmission occurs + /// for UART signals. When the UART is disabled in the middle + /// of transmission, it completes the current character before + /// stopping. + TXE OFFSET(8) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// UART enable + UARTEN OFFSET(0) NUMBITS(1) [ + /// If the UART is disabled in the middle of transmission + /// or reception, it completes the current character + /// before stopping. + Disabled = 0, + Enabled = 1 + ] + ], + + /// Interupt Clear Register + ICR [ + /// Meta field for all pending interrupts + ALL OFFSET(0) NUMBITS(11) [] + ] +} const UART_BASE: u32 = MMIO_BASE + 0x20_1000; -// PL011 UART registers #[allow(non_snake_case)] #[repr(C)] pub struct RegisterBlock { - DR: RW, // 0x00 - __reserved_0: [u32; 5], // 0x04 - FR: RO, // 0x18 - __reserved_1: [u32; 2], // 0x1c - IBRD: WO, // 0x24 - FBRD: WO, // 0x28 - LCRH: WO, // 0x2C - CR: WO, // 0x30 - __reserved_2: [u32; 4], // 0x34 - ICR: WO, // 0x44 + DR: ReadWrite, // 0x00 + __reserved_0: [u32; 5], // 0x04 + FR: ReadOnly, // 0x18 + __reserved_1: [u32; 2], // 0x1c + IBRD: WriteOnly, // 0x24 + FBRD: WriteOnly, // 0x28 + LCRH: WriteOnly, // 0x2C + CR: WriteOnly, // 0x30 + __reserved_2: [u32; 4], // 0x34 + ICR: WriteOnly, // 0x44 } pub enum UartError { @@ -76,7 +164,7 @@ impl Uart { ///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.CR.write(0) }; + self.CR.set(0); // set up clock for consistent divisor values mbox.buffer[0] = 9 * 4; @@ -100,33 +188,30 @@ impl Uart { // map UART0 to GPIO pins unsafe { - (*gpio::GPFSEL1).modify(|x| { - // Modify with a closure - let mut ret = x; - ret &= !((7 << 12) | (7 << 15)); // gpio14, gpio15 - ret |= (4 << 12) | (4 << 15); // alt0 - - ret - }); + (*gpio::GPFSEL1).modify(gpio::GPFSEL1::FSEL14::TXD0 + gpio::GPFSEL1::FSEL15::RXD0); - (*gpio::GPPUD).write(0); // enable pins 14 and 15 + (*gpio::GPPUD).set(0); // enable pins 14 and 15 for _ in 0..150 { asm::nop(); } - (*gpio::GPPUDCLK0).write((1 << 14) | (1 << 15)); + (*gpio::GPPUDCLK0).modify( + gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, + ); for _ in 0..150 { asm::nop(); } - (*gpio::GPPUDCLK0).write(0); - 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 + (*gpio::GPPUDCLK0).set(0); } + self.ICR.write(ICR::ALL::CLEAR); + self.IBRD.write(IBRD::IBRD.val(2)); // Results in 115200 baud + self.FBRD.write(FBRD::FBRD.val(0xB)); + self.LCRH.write(LCRH::WLEN::EightBit); // 8N1 + self.CR + .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); + Ok(()) } @@ -134,7 +219,7 @@ impl Uart { pub fn send(&self, c: char) { // wait until we can send loop { - if (self.FR.read() & 0x20) != 0x20 { + if !self.FR.is_set(FR::TXFF) { break; } @@ -142,14 +227,14 @@ impl Uart { } // write the character to the buffer - unsafe { self.DR.write(c as u32) }; + self.DR.set(c as u32); } /// Receive a character pub fn getc(&self) -> char { // wait until something is in the buffer loop { - if (self.FR.read() & 0x10) != 0x10 { + if !self.FR.is_set(FR::RXFE) { break; } @@ -157,7 +242,7 @@ impl Uart { } // read it and return - let mut ret = self.DR.read() as u8 as char; + let mut ret = self.DR.get() as u8 as char; // convert carrige return to newline if ret == '\r' { diff --git a/09_delays/Cargo.lock b/09_delays/Cargo.lock index 595dbca6..b1d7d368 100644 --- a/09_delays/Cargo.lock +++ b/09_delays/Cargo.lock @@ -1,23 +1,18 @@ -[[package]] -name = "bitflags" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "cortex-a" -version = "0.1.3" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "register 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "kernel8" version = "0.1.0" dependencies = [ - "cortex-a 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cortex-a 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "raspi3_glue 0.1.0", - "volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "register 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -34,28 +29,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "raspi3_glue" version = "0.1.0" dependencies = [ - "cortex-a 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cortex-a 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "panic-abort 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "vcell" -version = "0.1.0" +name = "register" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "tock-registers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "volatile-register" -version = "0.2.0" +name = "tock-registers" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] [metadata] -"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" -"checksum cortex-a 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a123fa5a346531ed0fc9fcb8f69ca34d9b8c55b15162731945d14c4d461c5bfe" +"checksum cortex-a 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24174fbfe16d46844856c0f5e16ee15f7adbacfd87cb0148d34463dd34b54eeb" "checksum panic-abort 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6bc796c620f27056d4ffe7c558533fd67ae5af0fd8e919fbe38de803368af73e" "checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -"checksum vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45c297f0afb6928cd08ab1ff9d95e99392595ea25ae1b5ecf822ff8764e57a0d" -"checksum volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286" +"checksum register 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e985243ba7e1c336b62444ef2a10d7bd87cf41a222285ae3de605c859006479" +"checksum tock-registers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2acc33f980e23cee18d234a32d0637fbc1ea55e13ab04012fa857b899fa1b7a9" diff --git a/09_delays/Cargo.toml b/09_delays/Cargo.toml index 27e97224..a9dc0498 100644 --- a/09_delays/Cargo.toml +++ b/09_delays/Cargo.toml @@ -5,5 +5,5 @@ authors = ["Andre Richter "] [dependencies] raspi3_glue = { path = "raspi3_glue" } -cortex-a = "0.1.3" -volatile-register = "0.2.0" +cortex-a = "1.0.0" +register = "0.1.1" diff --git a/09_delays/kernel8.img b/09_delays/kernel8.img index ce8336918440d264825c6c0735b2677333507d93..0a6c813ebff842a8981c48152857ee1622f3f2f8 100755 GIT binary patch delta 1403 zcmaJ>O=ufO6n?W~S+kB~x7w9#V_PG;7fU%+Ev?gFtXL{(++4cawg*FFV+cx2OXVhq zAj}E{N|R9V;((z&xXmSAK`(6@c1xj>-Aj%kbs>jR+2oMeJp@$8T8h1WqaUhVx*%rt z-Z$U--rw3i_Djn{#vFlL5s3T-_;^Y3fB`JSqw>Ulnp$dSK~o>!S$wX5Tg`P?YZ5pW znxA;$Pq+o8tsO=L0Zr*OVZ6Cip_L_c@Kkph`)E!q@1n!gCn^nq+`~+l6e$aU`m7N37 zwYG{51byimz^zHzsOTB=8Jwtl-$BhFRRBZXZ35d#3j+9R z16X!Fy$cBij>$b~fnylBpLErU$~8}KpND?T@)yjKH?zD~2-{+wgxzV{YqT#01gjJ= z8p9@>-?v>70Fia3bLA@=3AX?C^lC1N?U=F-W=>n~{IBbxU5%}w4+QO%u0|GUUDZFzcseztF-w!+SX7!j2oY zdgZ6<8mpYzdcXVjB3t_L>(CM|!{LR8Y$-Izb_Tb`c1~?EAH>I+?}{v?=TVP=dh)ms z!Y^Vg1_>uoKt{31`1GM;l Qc-C=J>SaiaPojDL3pOX?z5oCK delta 1119 zcmaJ=T}TvB6h1R|mz`O4v;9%jwRQ8Mb@PX|a1}AfpMvxu8i$~lRD!_FU=4Z^+tnc4 zGI0DsOv3O*6z!pUaC*_Tmjsid?0FR*G%W?u+(K{X?yjUS4GeSdcfNDZ_uV;nDtXG( zZTDw$(3b^SUjd&HBfJ$!hwK9Wskk!QlBWZ8oD0Y`_~ye*@q8wj?{RzHC6Y8goCCgk z11Q7gRlWuQ^@cI(~{gw zSi>KxSdq6G=N+xtfxNDBF`o0cpDM<9!Aa3n%T!IICAzyfQ?!sXLKPn4%vmlvn@4Bv z_ES^Lb_AzKCco`cWRAe+pP&>7CdFEWk3eM z3Tj7EKwd(nyEPE8;IUi7qb;8R`UHS(5nmV#l{#O9O8x1e(QMGd2AJ&RC9MG{+*sSM84zxLQKz690<> zXJ^BZ;mNDVT;w(8gLcORT9X;HyD3niHKVIWR2hV?wydXp5_B` z_!h6;pmZRLRi&%EK87j1Yb4X3uCn;D0X)@*oGr{l@eIF&m=G>mYtxce=3^#Yz6{(fsz z5H@5cmWXA1nOMh}u-${0p_q}Bq5qnwM)l0a4@y(FTWiL4YOBX~YorJcrOM`nUHvf5 z9~;!enG^aeBRPYW5uB0rS-jqC4sqW*txrpKq2L2U`5vZ4bKh*~i}@1"] [dependencies] -cortex-a = "0.1.3" +cortex-a = "1.0.0" panic-abort = "0.2.0" r0 = "0.2.2" diff --git a/09_delays/raspi3_glue/src/lib.rs b/09_delays/raspi3_glue/src/lib.rs index a84d91f2..97ff3f7c 100644 --- a/09_delays/raspi3_glue/src/lib.rs +++ b/09_delays/raspi3_glue/src/lib.rs @@ -30,9 +30,6 @@ extern crate cortex_a; extern crate panic_abort; extern crate r0; -use core::ptr; -use cortex_a::{asm, register}; - #[lang = "start"] extern "C" fn start(user_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize where @@ -53,6 +50,8 @@ impl Termination for () { } unsafe fn reset() -> ! { + use core::ptr; + extern "C" { fn main(argc: isize, argv: *const *const u8) -> isize; @@ -77,11 +76,13 @@ unsafe fn reset() -> ! { #[link_section = ".text.boot"] #[no_mangle] pub extern "C" fn _boot_cores() -> ! { - match register::MPIDR_EL1::read_raw() & 0x3 { - 0 => unsafe { - register::SP::write_raw(0x80_000); - reset() - }, + use cortex_a::{asm, regs::mpidr_el1::*, regs::sp::*}; + + match MPIDR_EL1.get() & 0x3 { + 0 => { + SP.set(0x80_000); + unsafe { reset() } + } _ => loop { // if not core0, infinitely wait for events asm::wfe(); diff --git a/09_delays/src/delays.rs b/09_delays/src/delays.rs index c4fbc769..d9a6cbc1 100644 --- a/09_delays/src/delays.rs +++ b/09_delays/src/delays.rs @@ -24,9 +24,11 @@ use super::MMIO_BASE; use core::ops; -use cortex_a::{asm, - register::{CNTFRQ_EL0, CNTP_CTL_EL0, CNTP_TVAL_EL0}}; -use volatile_register::*; +use cortex_a::{ + asm, + regs::{cntfrq_el0::*, cntp_ctl_el0::*, cntp_tval_el0::*}, +}; +use register::mmio::*; const DELAY_BASE: u32 = MMIO_BASE + 0x3004; @@ -38,8 +40,8 @@ const DELAY_BASE: u32 = MMIO_BASE + 0x3004; #[allow(non_snake_case)] #[repr(C)] pub struct RegisterBlock { - SYSTMR_LO: RO, // 0x00 - SYSTMR_HI: RO, // 0x04 + SYSTMR_LO: ReadOnly, // 0x00 + SYSTMR_HI: ReadOnly, // 0x04 } /// Public interface to the BCM System Timer @@ -66,16 +68,16 @@ impl SysTmr { /// Get System Timer's counter pub fn get_system_timer(&self) -> u64 { // Since it is MMIO, we must emit two separate 32 bit reads - let mut hi = self.SYSTMR_HI.read(); + let mut hi = self.SYSTMR_HI.get(); // We have to repeat if high word changed during read. It // looks a bit odd, but clippy insists that this is idiomatic // Rust! - let lo = if hi != self.SYSTMR_HI.read() { - hi = self.SYSTMR_HI.read(); - self.SYSTMR_LO.read() + let lo = if hi != self.SYSTMR_HI.get() { + hi = self.SYSTMR_HI.get(); + self.SYSTMR_LO.get() } else { - self.SYSTMR_LO.read() + self.SYSTMR_LO.get() }; // Compose long int value @@ -107,35 +109,26 @@ impl SysTmr { /// Wait N microsec (ARM CPU only) pub fn wait_msec(n: u32) { // Get the counter frequency - let frq = CNTFRQ_EL0::read_raw(); + let frq = CNTFRQ_EL0.get(); // Calculate number of ticks let tval = (frq as u32 / 1000) * n; - unsafe { - // Set the compare value register - CNTP_TVAL_EL0::write_raw(tval); + // Set the compare value register + CNTP_TVAL_EL0.set(tval); - // Kick off the counting - CNTP_CTL_EL0::modify_flags(|r| { - r.set(CNTP_CTL_EL0::ENABLE, true); - r.set(CNTP_CTL_EL0::IMASK, true); // Disable timer interrupt - }); - } + // Kick off the counting // Disable timer interrupt + CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::SET); loop { // ISTATUS will be one when cval ticks have passed. Continuously check it. - if CNTP_CTL_EL0::read_flags().contains(CNTP_CTL_EL0::ISTATUS) { + if CNTP_CTL_EL0.is_set(CNTP_CTL_EL0::ISTATUS) { break; } } // Disable counting again - unsafe { - CNTP_CTL_EL0::modify_flags(|r| { - r.set(CNTP_CTL_EL0::ENABLE, false); - }); - } + CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR); } /* diff --git a/09_delays/src/gpio.rs b/09_delays/src/gpio.rs index 65bf7f0a..6ec8b4c6 100644 --- a/09_delays/src/gpio.rs +++ b/09_delays/src/gpio.rs @@ -23,8 +23,54 @@ */ use super::MMIO_BASE; -use volatile_register::RW; +use register::mmio::ReadWrite; -pub const GPFSEL1: *const RW = (MMIO_BASE + 0x0020_0004) as *const RW; -pub const GPPUD: *const RW = (MMIO_BASE + 0x0020_0094) as *const RW; -pub const GPPUDCLK0: *const RW = (MMIO_BASE + 0x0020_0098) as *const RW; +// Descriptions taken from +// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf +register_bitfields! { + u32, + + /// GPIO Function Select 1 + GPFSEL1 [ + /// Pin 15 + FSEL15 OFFSET(15) NUMBITS(3) [ + Input = 0b000, + Output = 0b001, + RXD0 = 0b100, // UART0 - Alternate function 0 + RXD1 = 0b010 // Mini UART - Alternate function 5 + + ], + + /// Pin 14 + FSEL14 OFFSET(12) NUMBITS(3) [ + Input = 0b000, + Output = 0b001, + TXD0 = 0b100, // UART0 - Alternate function 0 + TXD1 = 0b010 // Mini UART - Alternate function 5 + ] + ], + + /// GPIO Pull-up/down Clock Register 0 + GPPUDCLK0 [ + /// Pin 15 + PUDCLK15 OFFSET(15) NUMBITS(1) [ + NoEffect = 0, + AssertClock = 1 + ], + + /// Pin 14 + PUDCLK14 OFFSET(14) NUMBITS(1) [ + NoEffect = 0, + AssertClock = 1 + ] + ] +} + + +pub const GPFSEL1: *const ReadWrite = + (MMIO_BASE + 0x0020_0004) as *const ReadWrite; + +pub const GPPUD: *const ReadWrite = (MMIO_BASE + 0x0020_0094) as *const ReadWrite; + +pub const GPPUDCLK0: *const ReadWrite = + (MMIO_BASE + 0x0020_0098) as *const ReadWrite; diff --git a/09_delays/src/main.rs b/09_delays/src/main.rs index 0d61ef46..b1f22ce6 100644 --- a/09_delays/src/main.rs +++ b/09_delays/src/main.rs @@ -26,7 +26,9 @@ extern crate cortex_a; extern crate raspi3_glue; -extern crate volatile_register; + +#[macro_use] +extern crate register; const MMIO_BASE: u32 = 0x3F00_0000; diff --git a/09_delays/src/mbox.rs b/09_delays/src/mbox.rs index 6c6b9710..18fe5787 100644 --- a/09_delays/src/mbox.rs +++ b/09_delays/src/mbox.rs @@ -25,20 +25,27 @@ use super::MMIO_BASE; use core::ops; use cortex_a::asm; -use volatile_register::{RO, WO}; +use register::mmio::{ReadOnly, WriteOnly}; + +register_bitfields! { + u32, + + STATUS [ + FULL OFFSET(31) NUMBITS(1) [], + EMPTY OFFSET(30) NUMBITS(1) [] + ] +} const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880; #[allow(non_snake_case)] #[repr(C)] pub struct RegisterBlock { - READ: RO, // 0x00 - __reserved_0: [u32; 3], // 0x04 - POLL: RO, // 0x10 - SENDER: RO, // 0x14 - STATUS: RO, // 0x18 - CONFIG: RO, // 0x1C - WRITE: WO, // 0x20 + READ: ReadOnly, // 0x00 + __reserved_0: [u32; 5], // 0x04 + STATUS: ReadOnly, // 0x18 + __reserved_1: u32, // 0x1C + WRITE: WriteOnly, // 0x20 } // Custom errors @@ -71,17 +78,13 @@ mod response { } pub const REQUEST: u32 = 0; -const FULL: u32 = 0x8000_0000; -const EMPTY: u32 = 0x4000_0000; // Public interface to the mailbox #[repr(C)] +#[repr(align(16))] pub struct Mbox { // The address for buffer needs to be 16-byte aligned so that the - // Videcore can handle it properly. We don't take precautions here - // 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. + // Videcore can handle it properly. pub buffer: [u32; 36], } @@ -117,34 +120,33 @@ impl Mbox { pub fn call(&self, channel: u32) -> Result<()> { // wait until we can write to the mailbox loop { - if (self.STATUS.read() & FULL) != FULL { + if !self.STATUS.is_set(STATUS::FULL) { break; } asm::nop(); } + let buf_ptr = self.buffer.as_ptr() as u32; + // write the address of our message to the mailbox with channel identifier - unsafe { - self.WRITE - .write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF)) - }; + self.WRITE.set((buf_ptr & !0xF) | (channel & 0xF)); // now wait for the response loop { // is there a response? loop { - if (self.STATUS.read() & EMPTY) != EMPTY { + if !self.STATUS.is_set(STATUS::EMPTY) { break; } asm::nop(); } - let resp: u32 = self.READ.read(); + let resp: u32 = self.READ.get(); // is it a response to our message? - if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) { + if ((resp & 0xF) == channel) && ((resp & !0xF) == buf_ptr) { // is it a valid successful response? return match self.buffer[1] { response::SUCCESS => Ok(()), diff --git a/09_delays/src/uart.rs b/09_delays/src/uart.rs index 7382eab9..4748bb56 100644 --- a/09_delays/src/uart.rs +++ b/09_delays/src/uart.rs @@ -23,30 +23,118 @@ */ use super::MMIO_BASE; -use core::ops; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::{ + ops, + sync::atomic::{compiler_fence, Ordering}, +}; use cortex_a::asm; use delays; use gpio; use mbox; -use volatile_register::*; +use register::mmio::*; + +// PL011 UART registers. +// +// Descriptions taken from +// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf +register_bitfields! { + u32, + + /// Flag Register + FR [ + /// Transmit FIFO full. The meaning of this bit depends on the + /// state of the FEN bit in the UARTLCR_ LCRH Register. If the + /// FIFO is disabled, this bit is set when the transmit + /// holding register is full. If the FIFO is enabled, the TXFF + /// bit is set when the transmit FIFO is full. + TXFF OFFSET(5) NUMBITS(1) [], + + /// Receive FIFO empty. The meaning of this bit depends on the + /// state of the FEN bit in the UARTLCR_H Register. If the + /// FIFO is disabled, this bit is set when the receive holding + /// register is empty. If the FIFO is enabled, the RXFE bit is + /// set when the receive FIFO is empty. + RXFE OFFSET(4) NUMBITS(1) [] + ], + + /// Integer Baud rate divisor + IBRD [ + /// Integer Baud rate divisor + IBRD OFFSET(0) NUMBITS(16) [] + ], + + /// Fractional Baud rate divisor + FBRD [ + /// Fractional Baud rate divisor + FBRD OFFSET(0) NUMBITS(6) [] + ], + + /// Line Control register + LCRH [ + /// Word length. These bits indicate the number of data bits + /// transmitted or received in a frame. + WLEN OFFSET(5) NUMBITS(2) [ + FiveBit = 0b00, + SixBit = 0b01, + SevenBit = 0b10, + EightBit = 0b11 + ] + ], + + /// Control Register + CR [ + /// Receive enable. If this bit is set to 1, the receive + /// section of the UART is enabled. Data reception occurs for + /// UART signals. When the UART is disabled in the middle of + /// reception, it completes the current character before + /// stopping. + RXE OFFSET(9) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// Transmit enable. If this bit is set to 1, the transmit + /// section of the UART is enabled. Data transmission occurs + /// for UART signals. When the UART is disabled in the middle + /// of transmission, it completes the current character before + /// stopping. + TXE OFFSET(8) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// UART enable + UARTEN OFFSET(0) NUMBITS(1) [ + /// If the UART is disabled in the middle of transmission + /// or reception, it completes the current character + /// before stopping. + Disabled = 0, + Enabled = 1 + ] + ], + + /// Interupt Clear Register + ICR [ + /// Meta field for all pending interrupts + ALL OFFSET(0) NUMBITS(11) [] + ] +} const UART_BASE: u32 = MMIO_BASE + 0x20_1000; -// PL011 UART registers #[allow(non_snake_case)] #[repr(C)] pub struct RegisterBlock { - DR: RW, // 0x00 - __reserved_0: [u32; 5], // 0x04 - FR: RO, // 0x18 - __reserved_1: [u32; 2], // 0x1c - IBRD: WO, // 0x24 - FBRD: WO, // 0x28 - LCRH: WO, // 0x2C - CR: WO, // 0x30 - __reserved_2: [u32; 4], // 0x34 - ICR: WO, // 0x44 + DR: ReadWrite, // 0x00 + __reserved_0: [u32; 5], // 0x04 + FR: ReadOnly, // 0x18 + __reserved_1: [u32; 2], // 0x1c + IBRD: WriteOnly, // 0x24 + FBRD: WriteOnly, // 0x28 + LCRH: WriteOnly, // 0x2C + CR: WriteOnly, // 0x30 + __reserved_2: [u32; 4], // 0x34 + ICR: WriteOnly, // 0x44 } pub enum UartError { @@ -77,7 +165,7 @@ impl Uart { ///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.CR.write(0) }; + self.CR.set(0); // set up clock for consistent divisor values mbox.buffer[0] = 9 * 4; @@ -101,30 +189,26 @@ impl Uart { // map UART0 to GPIO pins unsafe { - (*gpio::GPFSEL1).modify(|x| { - // Modify with a closure - let mut ret = x; - ret &= !((7 << 12) | (7 << 15)); // gpio14, gpio15 - ret |= (4 << 12) | (4 << 15); // alt0 + (*gpio::GPFSEL1).modify(gpio::GPFSEL1::FSEL14::TXD0 + gpio::GPFSEL1::FSEL15::RXD0); - ret - }); - - (*gpio::GPPUD).write(0); // enable pins 14 and 15 + (*gpio::GPPUD).set(0); // enable pins 14 and 15 delays::wait_cycles(150); - (*gpio::GPPUDCLK0).write((1 << 14) | (1 << 15)); + (*gpio::GPPUDCLK0).modify( + gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, + ); delays::wait_cycles(150); - (*gpio::GPPUDCLK0).write(0); - - 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 + (*gpio::GPPUDCLK0).set(0); } + self.ICR.write(ICR::ALL::CLEAR); + self.IBRD.write(IBRD::IBRD.val(2)); // Results in 115200 baud + self.FBRD.write(FBRD::FBRD.val(0xB)); + self.LCRH.write(LCRH::WLEN::EightBit); // 8N1 + self.CR + .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); + Ok(()) } @@ -132,7 +216,7 @@ impl Uart { pub fn send(&self, c: char) { // wait until we can send loop { - if (self.FR.read() & 0x20) != 0x20 { + if !self.FR.is_set(FR::TXFF) { break; } @@ -140,14 +224,14 @@ impl Uart { } // write the character to the buffer - unsafe { self.DR.write(c as u32) }; + self.DR.set(c as u32); } /// Receive a character pub fn getc(&self) -> char { // wait until something is in the buffer loop { - if (self.FR.read() & 0x10) != 0x10 { + if !self.FR.is_set(FR::RXFE) { break; } @@ -155,7 +239,7 @@ impl Uart { } // read it and return - let mut ret = self.DR.read() as u8 as char; + let mut ret = self.DR.get() as u8 as char; // convert carrige return to newline if ret == '\r' { diff --git a/0A_power/Cargo.lock b/0A_power/Cargo.lock index 595dbca6..efd63522 100644 --- a/0A_power/Cargo.lock +++ b/0A_power/Cargo.lock @@ -1,23 +1,26 @@ [[package]] -name = "bitflags" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "cortex-a" +version = "1.0.0" +source = "git+https://github.com/andre-richter/cortex-a.git?branch=registers#aae179e34af014725706bb1821e9e285674db97b" +dependencies = [ + "register 0.1.1 (git+https://github.com/andre-richter/register-rs.git)", +] [[package]] name = "cortex-a" -version = "0.1.3" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "register 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "kernel8" version = "0.1.0" dependencies = [ - "cortex-a 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cortex-a 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "raspi3_glue 0.1.0", - "volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "register 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -34,28 +37,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "raspi3_glue" version = "0.1.0" dependencies = [ - "cortex-a 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cortex-a 1.0.0 (git+https://github.com/andre-richter/cortex-a.git?branch=registers)", "panic-abort 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "vcell" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "register" +version = "0.1.1" +source = "git+https://github.com/andre-richter/register-rs.git#e0fdae3f2dc1e9691bbe4d57519e746f0d9aada0" +dependencies = [ + "tock-registers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "volatile-register" -version = "0.2.0" +name = "register" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tock-registers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tock-registers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [metadata] -"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" -"checksum cortex-a 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a123fa5a346531ed0fc9fcb8f69ca34d9b8c55b15162731945d14c4d461c5bfe" +"checksum cortex-a 1.0.0 (git+https://github.com/andre-richter/cortex-a.git?branch=registers)" = "" +"checksum cortex-a 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24174fbfe16d46844856c0f5e16ee15f7adbacfd87cb0148d34463dd34b54eeb" "checksum panic-abort 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6bc796c620f27056d4ffe7c558533fd67ae5af0fd8e919fbe38de803368af73e" "checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -"checksum vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45c297f0afb6928cd08ab1ff9d95e99392595ea25ae1b5ecf822ff8764e57a0d" -"checksum volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286" +"checksum register 0.1.1 (git+https://github.com/andre-richter/register-rs.git)" = "" +"checksum register 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e985243ba7e1c336b62444ef2a10d7bd87cf41a222285ae3de605c859006479" +"checksum tock-registers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2acc33f980e23cee18d234a32d0637fbc1ea55e13ab04012fa857b899fa1b7a9" diff --git a/0A_power/Cargo.toml b/0A_power/Cargo.toml index 27e97224..a9dc0498 100644 --- a/0A_power/Cargo.toml +++ b/0A_power/Cargo.toml @@ -5,5 +5,5 @@ authors = ["Andre Richter "] [dependencies] raspi3_glue = { path = "raspi3_glue" } -cortex-a = "0.1.3" -volatile-register = "0.2.0" +cortex-a = "1.0.0" +register = "0.1.1" diff --git a/0A_power/README.md b/0A_power/README.md index 85bcc3ca..fcf4f2f9 100644 --- a/0A_power/README.md +++ b/0A_power/README.md @@ -9,8 +9,14 @@ transistor connected to a data GPIO pin for example). ## power.rs +Unfortunately, the documentation about the PM interface is very very rare. We +will therefore more or less implement a carbon copy of respective functions of +Linux' +[bcm2835_wdt.c](https://github.com/torvalds/linux/blob/master/drivers/watchdog/bcm2835_wdt.c) +driver. + The power management controller is one of the peripherals that are not emulated -properly by QEMU. Our implementation works on real hardware though. +properly by QEMU. Our implementation therefore works on real hardware only. `Power::off(&self, mbox: &mut mbox::Mbox, gpio: &gpio::GPIO)` shuts down the board to an almost zero power consumption state. diff --git a/0A_power/kernel8.img b/0A_power/kernel8.img index 1aed8a7e3198c67aeed54cefea789c8da7d911ac..830c2e6c0fd02dda104d9b9b3a60bae0c4418d5b 100755 GIT binary patch literal 2296 zcmah~TTEMJ9RHtlC_SgZ7J7j($IbySSs@UI*(@Z4a#`f!be2XjGXf)B%Gh8nTVz2) zffoeFtj;X)1$`Q=$@YRvo6HEz#4LLvb(;8MS$yE4%-IbnvmAflX_=iqc#?CzbN;vQ z_rLtUGflR;vd;cz2a&T~5$>w0n!hCERLC6pr#QN-kn#iJQtP<|k?3P8n6G}+Dg?}# zBM$SgSH0^dipK^s0#iJNqk^w`NpFwG1THASRw3JNfBq|iOe$aP4o6}-Uo8)II#V~ zQ%|R=I^Dhdj3QT9F^#>Rvb(Uq)t6>BJ@Rfy${}M-5qZQj`;3d*s#E4nJzrvVXWD^{ zL*7!)qCig3g3ReBXVebUJgy5ehhn5po-XFL*P+s zePG>WkE8DXS)u*Mc-PH9Y)}ZW+HM@@pyva{*)(GjMjYpOe!>E*?o9IEz#ebm?&fDJ zZG~jK&27FM6U3lgN}gFgIpz8WPbYfqNULXoMb~;5b*d4P^?ZftIP>ZkJUJzc-Db6r zk;M>AWRyn*j}>u8p&R1OtFu^7<=Jh`uxW-|z9o2?3Z#--DLtWLuP*|~n z8Du&a7`NzSM+TdnZ~ykJ~f246HT{mfYhwt4FT@MCB{g}cG0F_w>>atpwZdEjRK zjH1^pAEsmSn<+Wt&1Y$R(e&WUOqzb|fA}JE`8~5+tOiF=g9hYNj~dhk*bJ+q$+_L( zk;a?hypRkI!7n7&;vU95$L@deiF`)JB}w;RJ~1xIkdF!A=RNRKXAd`H-VOGzye(yx zTq~DV!u$*p{K3oB_>^Py+Zk{3+r)GRE9Qg6MvpLNIM+sn1sY+i+J3-WFbY_))|qk{i+#LfpV^TElT z8C*jBO}QDZ?;zGt>fBOMUk>MFk-gYo#{&amXR7KI6J!?L{o}>{hd6uMkl)uYJnO%K zoOOtu#9|5F6Y_#vz>@qn;oBTs$9MXk1=zDDt*1-aa~W7f#??dQDGMJBhdi}^sZRY9JjvSB0l)9D{_s!ukFXv!0lU^G^hZKZ z3~4>Fq9@JhNfReM=?Ob88HYsV&-f#rZ-`qjG{kE-aTPP|WHRmh2!)vJ7I1CvmN(%S zME`;xVgGG??dDE@cjBGMqM7#h>46(Da25yI`KON3LgUilCrUQ=nq(*c3eGsjwN-HJ zH$e(E57UE*9NBgs-0MxWMb0GLk;xpY>`gRA%HEJ|XA;LE<+-wL4f2Z;RsJqy2PY3v z)3wo$R%JX*YLEZ;vb7l!iM21 z*RUnAFihndrh!y`NlXk2i(LwzWg#bc2`jh3{+awLYUiItEt^QZBa%2_)zJgaLN@k4 z+&Kf$1A2}cum*nI(@oNah&fz*V*Oj>@6}F49Y>J zOgY>4p3AHBojhq!D)8xb^}Eg)>fL>P{Vt`i*Hxt)?d(2%qHjQPdA)sJrMp)-#yqO3 O;Bvr=S&d*k$#=e=_vd@w z_j$kfBDrqM<(@wWiF^YJyRB(jW0sknvOw{z0-aSz`GxSEH_=szo%FVnVN&}2Ld0H1 z@uU#-zK-Fb*^V2V$r2RS+83EQIo(F#K_mI5yI%dS;6`A91AZsRoUiCa$@9j zK+b(M!0$4XZHr8N%Gb4`=DX2kwsBlTe`&rt=&h9Wp7ePVdZ%`*>scRaK2yoxWvS{- zj_LcRO4})+O7~+eXg&kvJg#ks>jvVojXj&VRT?EEQp~}R=56p?xx2qHP_isoPPt+tD zk^haE3z6GIXGNkfBnOvYGswH1bZPeQW9D(_R zsfn_vx3#|R#lU<+YQYlqj?T*|v7Ev@{yA=Iv^WEdR4#k!d@DI~Om=>R8p<16oZALr z3%#s^)La#*cP*sm8%SM3Oj!euMbTs7>jiB~`{?j~RY2^UaQ{L0u+BEeUp7R&ncocY zO?NIt8a$UGUQIiLIF z7l1ADp7i2ei_xv#?1?XxN@1Vmq4-_&7hWs*3Qu8)Ny*p7=-#ARcCA!<3c+H3`baU5 zo-$KMu-KcnACO%~ihXHEjqF;+`Duwd{$Q2Ksh!lZ4EdGQzFte?t3e2a_Hk{ zFbfZO?=a+%yZ9_}xrfA`L=q?4%ITg^PcGgUIB(DMq~kM08C7BikA%KNB)R#Y6#Y*m zL=C#E*MInMNb!C=a%|{*|4`6sGMSVeid{Jx`otemLWd5S6eqS3|A_yXsV5K$jrf&N f(BG--jzmHc<-?%T$2B`Uq1xI;w86-4{CEBv=fr~v diff --git a/0A_power/raspi3_glue/Cargo.toml b/0A_power/raspi3_glue/Cargo.toml index ba763bab..768f1158 100644 --- a/0A_power/raspi3_glue/Cargo.toml +++ b/0A_power/raspi3_glue/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" authors = ["Andre Richter "] [dependencies] -cortex-a = "0.1.3" +cortex-a = { git = "https://github.com/andre-richter/cortex-a.git", branch = "registers" } panic-abort = "0.2.0" r0 = "0.2.2" diff --git a/0A_power/raspi3_glue/src/lib.rs b/0A_power/raspi3_glue/src/lib.rs index a84d91f2..97ff3f7c 100644 --- a/0A_power/raspi3_glue/src/lib.rs +++ b/0A_power/raspi3_glue/src/lib.rs @@ -30,9 +30,6 @@ extern crate cortex_a; extern crate panic_abort; extern crate r0; -use core::ptr; -use cortex_a::{asm, register}; - #[lang = "start"] extern "C" fn start(user_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize where @@ -53,6 +50,8 @@ impl Termination for () { } unsafe fn reset() -> ! { + use core::ptr; + extern "C" { fn main(argc: isize, argv: *const *const u8) -> isize; @@ -77,11 +76,13 @@ unsafe fn reset() -> ! { #[link_section = ".text.boot"] #[no_mangle] pub extern "C" fn _boot_cores() -> ! { - match register::MPIDR_EL1::read_raw() & 0x3 { - 0 => unsafe { - register::SP::write_raw(0x80_000); - reset() - }, + use cortex_a::{asm, regs::mpidr_el1::*, regs::sp::*}; + + match MPIDR_EL1.get() & 0x3 { + 0 => { + SP.set(0x80_000); + unsafe { reset() } + } _ => loop { // if not core0, infinitely wait for events asm::wfe(); diff --git a/0A_power/src/delays.rs b/0A_power/src/delays.rs index c4fbc769..d9a6cbc1 100644 --- a/0A_power/src/delays.rs +++ b/0A_power/src/delays.rs @@ -24,9 +24,11 @@ use super::MMIO_BASE; use core::ops; -use cortex_a::{asm, - register::{CNTFRQ_EL0, CNTP_CTL_EL0, CNTP_TVAL_EL0}}; -use volatile_register::*; +use cortex_a::{ + asm, + regs::{cntfrq_el0::*, cntp_ctl_el0::*, cntp_tval_el0::*}, +}; +use register::mmio::*; const DELAY_BASE: u32 = MMIO_BASE + 0x3004; @@ -38,8 +40,8 @@ const DELAY_BASE: u32 = MMIO_BASE + 0x3004; #[allow(non_snake_case)] #[repr(C)] pub struct RegisterBlock { - SYSTMR_LO: RO, // 0x00 - SYSTMR_HI: RO, // 0x04 + SYSTMR_LO: ReadOnly, // 0x00 + SYSTMR_HI: ReadOnly, // 0x04 } /// Public interface to the BCM System Timer @@ -66,16 +68,16 @@ impl SysTmr { /// Get System Timer's counter pub fn get_system_timer(&self) -> u64 { // Since it is MMIO, we must emit two separate 32 bit reads - let mut hi = self.SYSTMR_HI.read(); + let mut hi = self.SYSTMR_HI.get(); // We have to repeat if high word changed during read. It // looks a bit odd, but clippy insists that this is idiomatic // Rust! - let lo = if hi != self.SYSTMR_HI.read() { - hi = self.SYSTMR_HI.read(); - self.SYSTMR_LO.read() + let lo = if hi != self.SYSTMR_HI.get() { + hi = self.SYSTMR_HI.get(); + self.SYSTMR_LO.get() } else { - self.SYSTMR_LO.read() + self.SYSTMR_LO.get() }; // Compose long int value @@ -107,35 +109,26 @@ impl SysTmr { /// Wait N microsec (ARM CPU only) pub fn wait_msec(n: u32) { // Get the counter frequency - let frq = CNTFRQ_EL0::read_raw(); + let frq = CNTFRQ_EL0.get(); // Calculate number of ticks let tval = (frq as u32 / 1000) * n; - unsafe { - // Set the compare value register - CNTP_TVAL_EL0::write_raw(tval); + // Set the compare value register + CNTP_TVAL_EL0.set(tval); - // Kick off the counting - CNTP_CTL_EL0::modify_flags(|r| { - r.set(CNTP_CTL_EL0::ENABLE, true); - r.set(CNTP_CTL_EL0::IMASK, true); // Disable timer interrupt - }); - } + // Kick off the counting // Disable timer interrupt + CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::SET); loop { // ISTATUS will be one when cval ticks have passed. Continuously check it. - if CNTP_CTL_EL0::read_flags().contains(CNTP_CTL_EL0::ISTATUS) { + if CNTP_CTL_EL0.is_set(CNTP_CTL_EL0::ISTATUS) { break; } } // Disable counting again - unsafe { - CNTP_CTL_EL0::modify_flags(|r| { - r.set(CNTP_CTL_EL0::ENABLE, false); - }); - } + CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR); } /* diff --git a/0A_power/src/gpio.rs b/0A_power/src/gpio.rs index 9550cf00..2175cc3a 100644 --- a/0A_power/src/gpio.rs +++ b/0A_power/src/gpio.rs @@ -24,37 +24,78 @@ use super::MMIO_BASE; use core::ops; -use volatile_register::RW; +use register::mmio::ReadWrite; + +// Descriptions taken from +// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf +register_bitfields! { + u32, + + /// GPIO Function Select 1 + GPFSEL1 [ + /// Pin 15 + FSEL15 OFFSET(15) NUMBITS(3) [ + Input = 0b000, + Output = 0b001, + RXD0 = 0b100, // UART0 - Alternate function 0 + RXD1 = 0b010 // Mini UART - Alternate function 5 + + ], + + /// Pin 14 + FSEL14 OFFSET(12) NUMBITS(3) [ + Input = 0b000, + Output = 0b001, + TXD0 = 0b100, // UART0 - Alternate function 0 + TXD1 = 0b010 // Mini UART - Alternate function 5 + ] + ], + + /// GPIO Pull-up/down Clock Register 0 + GPPUDCLK0 [ + /// Pin 15 + PUDCLK15 OFFSET(15) NUMBITS(1) [ + NoEffect = 0, + AssertClock = 1 + ], + + /// Pin 14 + PUDCLK14 OFFSET(14) NUMBITS(1) [ + NoEffect = 0, + AssertClock = 1 + ] + ] +} const GPIO_BASE: u32 = MMIO_BASE + 0x200_000; #[allow(non_snake_case)] #[repr(C)] pub struct RegisterBlock { - pub GPFSEL0: RW, // 0x00 - pub GPFSEL1: RW, // 0x04 - pub GPFSEL2: RW, // 0x08 - pub GPFSEL3: RW, // 0x0C - pub GPFSEL4: RW, // 0x10 - pub GPFSEL5: RW, // 0x14 - __reserved_0: u32, // 0x18 - GPSET0: RW, // 0x1C - GPSET1: RW, // 0x20 - __reserved_1: u32, // - GPCLR0: RW, // 0x28 - __reserved_2: [u32; 2], // - GPLEV0: RW, // 0x34 - GPLEV1: RW, // 0x38 - __reserved_3: u32, // - GPEDS0: RW, // 0x40 - GPEDS1: RW, // 0x44 - __reserved_4: [u32; 7], // - GPHEN0: RW, // 0x64 - GPHEN1: RW, // 0x68 - __reserved_5: [u32; 10], // - pub GPPUD: RW, // 0x94 - pub GPPUDCLK0: RW, // 0x98 - pub GPPUDCLK1: RW, // 0x9C + pub GPFSEL0: ReadWrite, // 0x00 + pub GPFSEL1: ReadWrite, // 0x04 + pub GPFSEL2: ReadWrite, // 0x08 + pub GPFSEL3: ReadWrite, // 0x0C + pub GPFSEL4: ReadWrite, // 0x10 + pub GPFSEL5: ReadWrite, // 0x14 + __reserved_0: u32, // 0x18 + GPSET0: ReadWrite, // 0x1C + GPSET1: ReadWrite, // 0x20 + __reserved_1: u32, // + GPCLR0: ReadWrite, // 0x28 + __reserved_2: [u32; 2], // + GPLEV0: ReadWrite, // 0x34 + GPLEV1: ReadWrite, // 0x38 + __reserved_3: u32, // + GPEDS0: ReadWrite, // 0x40 + GPEDS1: ReadWrite, // 0x44 + __reserved_4: [u32; 7], // + GPHEN0: ReadWrite, // 0x64 + GPHEN1: ReadWrite, // 0x68 + __reserved_5: [u32; 10], // + pub GPPUD: ReadWrite, // 0x94 + pub GPPUDCLK0: ReadWrite, // 0x98 + pub GPPUDCLK1: ReadWrite, // 0x9C } /// Public interface to the GPIO MMIO area diff --git a/0A_power/src/main.rs b/0A_power/src/main.rs index 36136a23..123af615 100644 --- a/0A_power/src/main.rs +++ b/0A_power/src/main.rs @@ -26,7 +26,9 @@ extern crate cortex_a; extern crate raspi3_glue; -extern crate volatile_register; + +#[macro_use] +extern crate register; const MMIO_BASE: u32 = 0x3F00_0000; @@ -58,7 +60,7 @@ fn main() { match c { '1' => { if power.off(&mut mbox, &gpio).is_err() { - uart.puts("Error in Power::off()"); + uart.puts("Mailbox error in Power::off()"); } } '2' => power.reset(), diff --git a/0A_power/src/mbox.rs b/0A_power/src/mbox.rs index 1ad1a981..00abf8fc 100644 --- a/0A_power/src/mbox.rs +++ b/0A_power/src/mbox.rs @@ -25,20 +25,27 @@ use super::MMIO_BASE; use core::ops; use cortex_a::asm; -use volatile_register::{RO, WO}; +use register::mmio::{ReadOnly, WriteOnly}; + +register_bitfields! { + u32, + + STATUS [ + FULL OFFSET(31) NUMBITS(1) [], + EMPTY OFFSET(30) NUMBITS(1) [] + ] +} const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880; #[allow(non_snake_case)] #[repr(C)] pub struct RegisterBlock { - READ: RO, // 0x00 - __reserved_0: [u32; 3], // 0x04 - POLL: RO, // 0x10 - SENDER: RO, // 0x14 - STATUS: RO, // 0x18 - CONFIG: RO, // 0x1C - WRITE: WO, // 0x20 + READ: ReadOnly, // 0x00 + __reserved_0: [u32; 5], // 0x04 + STATUS: ReadOnly, // 0x18 + __reserved_1: u32, // 0x1C + WRITE: WriteOnly, // 0x20 } // Custom errors @@ -72,17 +79,13 @@ mod response { } pub const REQUEST: u32 = 0; -const FULL: u32 = 0x8000_0000; -const EMPTY: u32 = 0x4000_0000; // Public interface to the mailbox #[repr(C)] +#[repr(align(16))] pub struct Mbox { // The address for buffer needs to be 16-byte aligned so that the - // Videcore can handle it properly. We don't take precautions here - // 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. + // Videcore can handle it properly. pub buffer: [u32; 36], } @@ -118,34 +121,33 @@ impl Mbox { pub fn call(&self, channel: u32) -> Result<()> { // wait until we can write to the mailbox loop { - if (self.STATUS.read() & FULL) != FULL { + if !self.STATUS.is_set(STATUS::FULL) { break; } asm::nop(); } + let buf_ptr = self.buffer.as_ptr() as u32; + // write the address of our message to the mailbox with channel identifier - unsafe { - self.WRITE - .write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF)) - }; + self.WRITE.set((buf_ptr & !0xF) | (channel & 0xF)); // now wait for the response loop { // is there a response? loop { - if (self.STATUS.read() & EMPTY) != EMPTY { + if !self.STATUS.is_set(STATUS::EMPTY) { break; } asm::nop(); } - let resp: u32 = self.READ.read(); + let resp: u32 = self.READ.get(); // is it a response to our message? - if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) { + if ((resp & 0xF) == channel) && ((resp & !0xF) == buf_ptr) { // is it a valid successful response? return match self.buffer[1] { response::SUCCESS => Ok(()), diff --git a/0A_power/src/power.rs b/0A_power/src/power.rs index 5073dc23..68f0bb97 100644 --- a/0A_power/src/power.rs +++ b/0A_power/src/power.rs @@ -28,20 +28,27 @@ use core::sync::atomic::{compiler_fence, Ordering}; use delays; use gpio; use mbox; -use volatile_register::*; +use register::mmio::*; const POWER_BASE: u32 = MMIO_BASE + 0x100_01C; #[allow(non_snake_case)] #[repr(C)] pub struct RegisterBlock { - PM_RSTC: RW, // 0x1C - PM_RSTS: RW, // 0x20 - PM_WDOG: RW, // 0x24 + PM_RSTC: ReadWrite, // 0x1C + PM_RSTS: ReadWrite, // 0x20 + PM_WDOG: ReadWrite, // 0x24 } -const PM_WDOG_MAGIC: u32 = 0x5a_000_000; -const PM_RSTC_FULLRST: u32 = 0x20; +const PM_PASSWORD: u32 = 0x5a_000_000; +const PM_RSTC_WRCFG_CLR: u32 = 0xffff_ffcf; +const PM_RSTC_WRCFG_FULL_RESET: u32 = 0x0000_0020; + +// The Raspberry Pi firmware uses the RSTS register to know which +// partiton to boot from. The partiton value is spread into bits 0, 2, +// 4, 6, 8, 10. Partiton 63 is a special partition used by the +// firmware to indicate halt. +const PM_RSTS_RASPBERRYPI_HALT: u32 = 0x555; pub enum PowerError { MailboxError, @@ -93,52 +100,44 @@ impl Power { } // power off gpio pins (but not VCC pins) - unsafe { - gpio.GPFSEL0.write(0); - gpio.GPFSEL1.write(0); - gpio.GPFSEL2.write(0); - gpio.GPFSEL3.write(0); - gpio.GPFSEL4.write(0); - gpio.GPFSEL5.write(0); - - gpio.GPPUD.write(0); - delays::wait_cycles(150); - - gpio.GPPUDCLK0.write(0xffff_ffff); - gpio.GPPUDCLK1.write(0xffff_ffff); - delays::wait_cycles(150); - - // flush GPIO setup - gpio.GPPUDCLK0.write(0); - gpio.GPPUDCLK1.write(0); - - // power off the SoC (GPU + CPU) - self.PM_RSTS.modify(|reg| { - let mut r = reg; - - r &= !0xffff_faaa; - r |= 0x555; // partition 63 used to indicate halt - PM_WDOG_MAGIC | r - }); - self.PM_WDOG.write(PM_WDOG_MAGIC | 10); - self.PM_RSTC.write(PM_WDOG_MAGIC | PM_RSTC_FULLRST); - } - - Ok(()) + gpio.GPFSEL0.set(0); + gpio.GPFSEL1.set(0); + gpio.GPFSEL2.set(0); + gpio.GPFSEL3.set(0); + gpio.GPFSEL4.set(0); + gpio.GPFSEL5.set(0); + + gpio.GPPUD.set(0); + delays::wait_cycles(150); + + gpio.GPPUDCLK0.set(0xffff_ffff); + gpio.GPPUDCLK1.set(0xffff_ffff); + delays::wait_cycles(150); + + // flush GPIO setup + gpio.GPPUDCLK0.set(0); + gpio.GPPUDCLK1.set(0); + + // We set the watchdog hard reset bit here to distinguish this + // reset from the normal (full) reset. bootcode.bin will not + // reboot after a hard reset. + let mut val = self.PM_RSTS.get(); + val |= PM_PASSWORD | PM_RSTS_RASPBERRYPI_HALT; + self.PM_RSTS.set(val); + + // Continue with normal reset mechanism + self.reset(); } /// Reboot - pub fn reset(&self) { - // trigger a restart by instructing the GPU to boot from partition 0 - unsafe { - self.PM_RSTS.modify(|reg| { - let mut r = reg; - - r &= !0xffff_faaa; - PM_WDOG_MAGIC | r - }); - self.PM_WDOG.write(PM_WDOG_MAGIC | 10); - self.PM_RSTC.write(PM_WDOG_MAGIC | PM_RSTC_FULLRST); - } + pub fn reset(&self) -> ! { + // use a timeout of 10 ticks (~150us) + self.PM_WDOG.set(PM_PASSWORD | 10); + let mut val = self.PM_RSTC.get(); + val &= PM_RSTC_WRCFG_CLR; + val |= PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET; + self.PM_RSTC.set(val); + + loop {} } } diff --git a/0A_power/src/uart.rs b/0A_power/src/uart.rs index 0b72dcbc..b8116b90 100644 --- a/0A_power/src/uart.rs +++ b/0A_power/src/uart.rs @@ -23,30 +23,118 @@ */ use super::MMIO_BASE; -use core::ops; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::{ + ops, + sync::atomic::{compiler_fence, Ordering}, +}; use cortex_a::asm; use delays; use gpio; use mbox; -use volatile_register::*; +use register::mmio::*; + +// PL011 UART registers. +// +// Descriptions taken from +// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf +register_bitfields! { + u32, + + /// Flag Register + FR [ + /// Transmit FIFO full. The meaning of this bit depends on the + /// state of the FEN bit in the UARTLCR_ LCRH Register. If the + /// FIFO is disabled, this bit is set when the transmit + /// holding register is full. If the FIFO is enabled, the TXFF + /// bit is set when the transmit FIFO is full. + TXFF OFFSET(5) NUMBITS(1) [], + + /// Receive FIFO empty. The meaning of this bit depends on the + /// state of the FEN bit in the UARTLCR_H Register. If the + /// FIFO is disabled, this bit is set when the receive holding + /// register is empty. If the FIFO is enabled, the RXFE bit is + /// set when the receive FIFO is empty. + RXFE OFFSET(4) NUMBITS(1) [] + ], + + /// Integer Baud rate divisor + IBRD [ + /// Integer Baud rate divisor + IBRD OFFSET(0) NUMBITS(16) [] + ], + + /// Fractional Baud rate divisor + FBRD [ + /// Fractional Baud rate divisor + FBRD OFFSET(0) NUMBITS(6) [] + ], + + /// Line Control register + LCRH [ + /// Word length. These bits indicate the number of data bits + /// transmitted or received in a frame. + WLEN OFFSET(5) NUMBITS(2) [ + FiveBit = 0b00, + SixBit = 0b01, + SevenBit = 0b10, + EightBit = 0b11 + ] + ], + + /// Control Register + CR [ + /// Receive enable. If this bit is set to 1, the receive + /// section of the UART is enabled. Data reception occurs for + /// UART signals. When the UART is disabled in the middle of + /// reception, it completes the current character before + /// stopping. + RXE OFFSET(9) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// Transmit enable. If this bit is set to 1, the transmit + /// section of the UART is enabled. Data transmission occurs + /// for UART signals. When the UART is disabled in the middle + /// of transmission, it completes the current character before + /// stopping. + TXE OFFSET(8) NUMBITS(1) [ + Disabled = 0, + Enabled = 1 + ], + + /// UART enable + UARTEN OFFSET(0) NUMBITS(1) [ + /// If the UART is disabled in the middle of transmission + /// or reception, it completes the current character + /// before stopping. + Disabled = 0, + Enabled = 1 + ] + ], + + /// Interupt Clear Register + ICR [ + /// Meta field for all pending interrupts + ALL OFFSET(0) NUMBITS(11) [] + ] +} const UART_BASE: u32 = MMIO_BASE + 0x20_1000; -// PL011 UART registers #[allow(non_snake_case)] #[repr(C)] pub struct RegisterBlock { - DR: RW, // 0x00 - __reserved_0: [u32; 5], // 0x04 - FR: RO, // 0x18 - __reserved_1: [u32; 2], // 0x1c - IBRD: WO, // 0x24 - FBRD: WO, // 0x28 - LCRH: WO, // 0x2C - CR: WO, // 0x30 - __reserved_2: [u32; 4], // 0x34 - ICR: WO, // 0x44 + DR: ReadWrite, // 0x00 + __reserved_0: [u32; 5], // 0x04 + FR: ReadOnly, // 0x18 + __reserved_1: [u32; 2], // 0x1c + IBRD: WriteOnly, // 0x24 + FBRD: WriteOnly, // 0x28 + LCRH: WriteOnly, // 0x2C + CR: WriteOnly, // 0x30 + __reserved_2: [u32; 4], // 0x34 + ICR: WriteOnly, // 0x44 } pub enum UartError { @@ -77,7 +165,7 @@ impl Uart { ///Set baud rate and characteristics (115200 8N1) and map to GPIO pub fn init(&self, mbox: &mut mbox::Mbox, gpio: &gpio::GPIO) -> Result<()> { // turn off UART0 - unsafe { self.CR.write(0) }; + self.CR.set(0); // set up clock for consistent divisor values mbox.buffer[0] = 9 * 4; @@ -100,30 +188,24 @@ impl Uart { }; // map UART0 to GPIO pins - unsafe { - gpio.GPFSEL1.modify(|x| { - // Modify with a closure - let mut ret = x; - ret &= !((7 << 12) | (7 << 15)); // gpio14, gpio15 - ret |= (4 << 12) | (4 << 15); // alt0 - - ret - }); + gpio.GPFSEL1.modify(gpio::GPFSEL1::FSEL14::TXD0 + gpio::GPFSEL1::FSEL15::RXD0); - gpio.GPPUD.write(0); // enable pins 14 and 15 - delays::wait_cycles(150); + gpio.GPPUD.set(0); // enable pins 14 and 15 + delays::wait_cycles(150); - gpio.GPPUDCLK0.write((1 << 14) | (1 << 15)); - delays::wait_cycles(150); + gpio.GPPUDCLK0.modify( + gpio::GPPUDCLK0::PUDCLK14::AssertClock + gpio::GPPUDCLK0::PUDCLK15::AssertClock, + ); + delays::wait_cycles(150); - gpio.GPPUDCLK0.write(0); + gpio.GPPUDCLK0.set(0); - 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 - } + self.ICR.write(ICR::ALL::CLEAR); + self.IBRD.write(IBRD::IBRD.val(2)); // Results in 115200 baud + self.FBRD.write(FBRD::FBRD.val(0xB)); + self.LCRH.write(LCRH::WLEN::EightBit); // 8N1 + self.CR + .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled); Ok(()) } @@ -132,7 +214,7 @@ impl Uart { pub fn send(&self, c: char) { // wait until we can send loop { - if (self.FR.read() & 0x20) != 0x20 { + if !self.FR.is_set(FR::TXFF) { break; } @@ -140,14 +222,14 @@ impl Uart { } // write the character to the buffer - unsafe { self.DR.write(c as u32) }; + self.DR.set(c as u32); } /// Receive a character pub fn getc(&self) -> char { // wait until something is in the buffer loop { - if (self.FR.read() & 0x10) != 0x10 { + if !self.FR.is_set(FR::RXFE) { break; } @@ -155,7 +237,7 @@ impl Uart { } // read it and return - let mut ret = self.DR.read() as u8 as char; + let mut ret = self.DR.get() as u8 as char; // convert carrige return to newline if ret == '\r' {