mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-05-18 00:22:40 +02:00
Extend bare metal afternoon exercise (#561)
* Add methods to set match register and check whether it matches. * Add first extension to RTC exercise, using match register. * No need for constants to be public.
This commit is contained in:
parent
5b316b8b5b
commit
d8e442b9cb
@ -25,7 +25,7 @@ use log::error;
|
|||||||
use psci::system_off;
|
use psci::system_off;
|
||||||
|
|
||||||
/// Base address of the primary PL011 UART.
|
/// Base address of the primary PL011 UART.
|
||||||
pub const PL011_BASE_ADDRESS: *mut u32 = 0x900_0000 as _;
|
const PL011_BASE_ADDRESS: *mut u32 = 0x900_0000 as _;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
|
extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
|
||||||
|
@ -26,7 +26,7 @@ use log::{error, info, LevelFilter};
|
|||||||
use psci::system_off;
|
use psci::system_off;
|
||||||
|
|
||||||
/// Base address of the primary PL011 UART.
|
/// Base address of the primary PL011 UART.
|
||||||
pub const PL011_BASE_ADDRESS: *mut u32 = 0x900_0000 as _;
|
const PL011_BASE_ADDRESS: *mut u32 = 0x900_0000 as _;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
|
extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
|
||||||
|
@ -25,7 +25,7 @@ use log::error;
|
|||||||
use psci::system_off;
|
use psci::system_off;
|
||||||
|
|
||||||
/// Base address of the primary PL011 UART.
|
/// Base address of the primary PL011 UART.
|
||||||
pub const PL011_BASE_ADDRESS: *mut u8 = 0x900_0000 as _;
|
const PL011_BASE_ADDRESS: *mut u8 = 0x900_0000 as _;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
|
extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
# RTC driver
|
# RTC driver
|
||||||
|
|
||||||
The QEMU aarch64 virt machine has a [PL031][1] real-time clock at 0x9010000. For this exercise, you
|
The QEMU aarch64 virt machine has a [PL031][1] real-time clock at 0x9010000. For this exercise, you
|
||||||
should write a driver for it and use it to print the current time to the serial console. You can use
|
should write a driver for it.
|
||||||
the [`chrono`][2] crate for date/time formatting.
|
|
||||||
|
1. Use it to print the current time to the serial console. You can use the [`chrono`][2] crate for
|
||||||
|
date/time formatting.
|
||||||
|
2. Use the match register and raw interrupt status to busy-wait until a given time, e.g. 3 seconds
|
||||||
|
in the future. (Call [`core::hint::spin_loop`][3] inside the loop.)
|
||||||
|
|
||||||
Download the [exercise template](../../comprehensive-rust-exercises.zip) and look in the `rtc`
|
Download the [exercise template](../../comprehensive-rust-exercises.zip) and look in the `rtc`
|
||||||
directory for the following files.
|
directory for the following files.
|
||||||
@ -20,6 +24,8 @@ directory for the following files.
|
|||||||
|
|
||||||
// TODO: Initialise RTC and print value.
|
// TODO: Initialise RTC and print value.
|
||||||
|
|
||||||
|
// TODO: Wait for 3 seconds.
|
||||||
|
|
||||||
{{#include rtc/src/main.rs:main_end}}
|
{{#include rtc/src/main.rs:main_end}}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -115,3 +121,4 @@ Run the code in QEMU with `make qemu`.
|
|||||||
|
|
||||||
[1]: https://developer.arm.com/documentation/ddi0224/c
|
[1]: https://developer.arm.com/documentation/ddi0224/c
|
||||||
[2]: https://crates.io/crates/chrono
|
[2]: https://crates.io/crates/chrono
|
||||||
|
[3]: https://doc.rust-lang.org/core/hint/fn.spin_loop.html
|
||||||
|
@ -24,6 +24,7 @@ mod pl031;
|
|||||||
|
|
||||||
use crate::pl031::Rtc;
|
use crate::pl031::Rtc;
|
||||||
use chrono::{TimeZone, Utc};
|
use chrono::{TimeZone, Utc};
|
||||||
|
use core::hint::spin_loop;
|
||||||
// ANCHOR: imports
|
// ANCHOR: imports
|
||||||
use crate::pl011::Uart;
|
use crate::pl011::Uart;
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
@ -31,11 +32,11 @@ use log::{error, info, LevelFilter};
|
|||||||
use psci::system_off;
|
use psci::system_off;
|
||||||
|
|
||||||
/// Base address of the primary PL011 UART.
|
/// Base address of the primary PL011 UART.
|
||||||
pub const PL011_BASE_ADDRESS: *mut u32 = 0x900_0000 as _;
|
const PL011_BASE_ADDRESS: *mut u32 = 0x900_0000 as _;
|
||||||
// ANCHOR_END: imports
|
// ANCHOR_END: imports
|
||||||
|
|
||||||
/// Base address of the PL031 RTC.
|
/// Base address of the PL031 RTC.
|
||||||
pub const PL031_BASE_ADDRESS: *mut u32 = 0x901_0000 as _;
|
const PL031_BASE_ADDRESS: *mut u32 = 0x901_0000 as _;
|
||||||
|
|
||||||
// ANCHOR: main
|
// ANCHOR: main
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -50,10 +51,23 @@ extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
|
|||||||
|
|
||||||
// Safe because `PL031_BASE_ADDRESS` is the base address of a PL031 device,
|
// Safe because `PL031_BASE_ADDRESS` is the base address of a PL031 device,
|
||||||
// and nothing else accesses that address range.
|
// and nothing else accesses that address range.
|
||||||
let rtc = unsafe { Rtc::new(PL031_BASE_ADDRESS) };
|
let mut rtc = unsafe { Rtc::new(PL031_BASE_ADDRESS) };
|
||||||
let time = Utc.timestamp_opt(rtc.read().into(), 0).unwrap();
|
let timestamp = rtc.read();
|
||||||
|
let time = Utc.timestamp_opt(timestamp.into(), 0).unwrap();
|
||||||
info!("RTC: {time}");
|
info!("RTC: {time}");
|
||||||
|
|
||||||
|
// Wait for 3 seconds, without interrupts.
|
||||||
|
let target = timestamp + 3;
|
||||||
|
rtc.set_match(target);
|
||||||
|
info!(
|
||||||
|
"Waiting for {}",
|
||||||
|
Utc.timestamp_opt(target.into(), 0).unwrap()
|
||||||
|
);
|
||||||
|
while !rtc.matched() {
|
||||||
|
spin_loop();
|
||||||
|
}
|
||||||
|
info!("Finished waiting");
|
||||||
|
|
||||||
// ANCHOR: main_end
|
// ANCHOR: main_end
|
||||||
system_off().unwrap();
|
system_off().unwrap();
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use core::ptr::addr_of;
|
use core::ptr::{addr_of, addr_of_mut};
|
||||||
|
|
||||||
#[repr(C, align(4))]
|
#[repr(C, align(4))]
|
||||||
struct Registers {
|
struct Registers {
|
||||||
@ -39,6 +39,7 @@ struct Registers {
|
|||||||
_reserved4: [u8; 3],
|
_reserved4: [u8; 3],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Driver for a PL031 real-time clock.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Rtc {
|
pub struct Rtc {
|
||||||
registers: *mut Registers,
|
registers: *mut Registers,
|
||||||
@ -61,8 +62,27 @@ impl Rtc {
|
|||||||
|
|
||||||
/// Reads the current RTC value.
|
/// Reads the current RTC value.
|
||||||
pub fn read(&self) -> u32 {
|
pub fn read(&self) -> u32 {
|
||||||
|
// Safe because we know that self.registers points to the control
|
||||||
|
// registers of a PL031 device which is appropriately mapped.
|
||||||
unsafe { addr_of!((*self.registers).dr).read_volatile() }
|
unsafe { addr_of!((*self.registers).dr).read_volatile() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Writes a match value. When the RTC value matches this then an interrupt
|
||||||
|
/// will be generated (if it is enabled).
|
||||||
|
pub fn set_match(&mut self, value: u32) {
|
||||||
|
// Safe because we know that self.registers points to the control
|
||||||
|
// registers of a PL031 device which is appropriately mapped.
|
||||||
|
unsafe { addr_of_mut!((*self.registers).mr).write_volatile(value) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether the match register matches the RTC value, whether or not
|
||||||
|
/// the interrupt is enabled.
|
||||||
|
pub fn matched(&self) -> bool {
|
||||||
|
// Safe because we know that self.registers points to the control
|
||||||
|
// registers of a PL031 device which is appropriately mapped.
|
||||||
|
let ris = unsafe { addr_of!((*self.registers).ris).read_volatile() };
|
||||||
|
(ris & 0x01) != 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safe because it just contains a pointer to device memory, which can be
|
// Safe because it just contains a pointer to device memory, which can be
|
||||||
|
Loading…
x
Reference in New Issue
Block a user