Skip to content

Commit 2e72a84

Browse files
committed
Rework driver subsystem
This update significantly decouples the generic kernel code from the BSP code. Prior to this patch, the BSP had way too much business logic that should have always been the generic kernel's concern.
1 parent 7014c0c commit 2e72a84

File tree

236 files changed

+7448
-4235
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

236 files changed

+7448
-4235
lines changed

05_drivers_gpio_uart/README.md

+351-91
Large diffs are not rendered by default.

05_drivers_gpio_uart/src/bsp/raspberrypi.rs

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
//! Top-level BSP file for the Raspberry Pi 3 and 4.
66
7-
pub mod console;
87
pub mod cpu;
98
pub mod driver;
109
pub mod memory;

05_drivers_gpio_uart/src/bsp/raspberrypi/driver.rs

+46-30
Original file line numberDiff line numberDiff line change
@@ -5,51 +5,67 @@
55
//! BSP driver support.
66
77
use super::memory::map::mmio;
8-
use crate::{bsp::device_driver, driver};
8+
use crate::{bsp::device_driver, console, driver as generic_driver};
9+
use core::sync::atomic::{AtomicBool, Ordering};
910

1011
//--------------------------------------------------------------------------------------------------
11-
// Private Definitions
12+
// Global instances
1213
//--------------------------------------------------------------------------------------------------
1314

14-
/// Device Driver Manager type.
15-
struct BSPDriverManager {
16-
device_drivers: [&'static (dyn DeviceDriver + Sync); 2],
17-
}
15+
static PL011_UART: device_driver::PL011Uart =
16+
unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) };
17+
static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) };
1818

1919
//--------------------------------------------------------------------------------------------------
20-
// Global instances
20+
// Private Code
2121
//--------------------------------------------------------------------------------------------------
2222

23-
pub(super) static PL011_UART: device_driver::PL011Uart =
24-
unsafe { device_driver::PL011Uart::new(mmio::PL011_UART_START) };
23+
/// This must be called only after successful init of the UART driver.
24+
fn post_init_uart() -> Result<(), &'static str> {
25+
console::register_console(&PL011_UART);
2526

26-
static GPIO: device_driver::GPIO = unsafe { device_driver::GPIO::new(mmio::GPIO_START) };
27+
Ok(())
28+
}
2729

28-
static BSP_DRIVER_MANAGER: BSPDriverManager = BSPDriverManager {
29-
device_drivers: [&PL011_UART, &GPIO],
30-
};
30+
/// This must be called only after successful init of the GPIO driver.
31+
fn post_init_gpio() -> Result<(), &'static str> {
32+
GPIO.map_pl011_uart();
33+
Ok(())
34+
}
3135

32-
//--------------------------------------------------------------------------------------------------
33-
// Public Code
34-
//--------------------------------------------------------------------------------------------------
36+
fn driver_uart() -> Result<(), &'static str> {
37+
let uart_descriptor =
38+
generic_driver::DeviceDriverDescriptor::new(&PL011_UART, Some(post_init_uart));
39+
generic_driver::driver_manager().register_driver(uart_descriptor);
3540

36-
/// Return a reference to the driver manager.
37-
pub fn driver_manager() -> &'static impl driver::interface::DriverManager {
38-
&BSP_DRIVER_MANAGER
41+
Ok(())
3942
}
4043

41-
//------------------------------------------------------------------------------
42-
// OS Interface Code
43-
//------------------------------------------------------------------------------
44-
use driver::interface::DeviceDriver;
44+
fn driver_gpio() -> Result<(), &'static str> {
45+
let gpio_descriptor = generic_driver::DeviceDriverDescriptor::new(&GPIO, Some(post_init_gpio));
46+
generic_driver::driver_manager().register_driver(gpio_descriptor);
4547

46-
impl driver::interface::DriverManager for BSPDriverManager {
47-
fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)] {
48-
&self.device_drivers[..]
49-
}
48+
Ok(())
49+
}
50+
51+
//--------------------------------------------------------------------------------------------------
52+
// Public Code
53+
//--------------------------------------------------------------------------------------------------
5054

51-
fn post_device_driver_init(&self) {
52-
// Configure PL011Uart's output pins.
53-
GPIO.map_pl011_uart();
55+
/// Initialize the driver subsystem.
56+
///
57+
/// # Safety
58+
///
59+
/// See child function calls.
60+
pub unsafe fn init() -> Result<(), &'static str> {
61+
static INIT_DONE: AtomicBool = AtomicBool::new(false);
62+
if INIT_DONE.load(Ordering::Relaxed) {
63+
return Err("Init already done");
5464
}
65+
66+
driver_uart()?;
67+
driver_gpio()?;
68+
69+
INIT_DONE.store(true, Ordering::Relaxed);
70+
Ok(())
5571
}

05_drivers_gpio_uart/src/console.rs

+18-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
//! System console.
66
7-
use crate::bsp;
7+
mod null_console;
8+
9+
use crate::synchronization::{self, NullLock};
810

911
//--------------------------------------------------------------------------------------------------
1012
// Public Definitions
@@ -54,13 +56,26 @@ pub mod interface {
5456
pub trait All: Write + Read + Statistics {}
5557
}
5658

59+
//--------------------------------------------------------------------------------------------------
60+
// Global instances
61+
//--------------------------------------------------------------------------------------------------
62+
63+
static CUR_CONSOLE: NullLock<&'static (dyn interface::All + Sync)> =
64+
NullLock::new(&null_console::NULL_CONSOLE);
65+
5766
//--------------------------------------------------------------------------------------------------
5867
// Public Code
5968
//--------------------------------------------------------------------------------------------------
69+
use synchronization::interface::Mutex;
70+
71+
/// Register a new console.
72+
pub fn register_console(new_console: &'static (dyn interface::All + Sync)) {
73+
CUR_CONSOLE.lock(|con| *con = new_console);
74+
}
6075

61-
/// Return a reference to the console.
76+
/// Return a reference to the currently registered console.
6277
///
6378
/// This is the global console used by all printing macros.
6479
pub fn console() -> &'static dyn interface::All {
65-
bsp::console::console()
80+
CUR_CONSOLE.lock(|con| *con)
6681
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
//
3+
// Copyright (c) 2022 Andre Richter <[email protected]>
4+
5+
//! Null console.
6+
7+
use super::interface;
8+
use core::fmt;
9+
10+
//--------------------------------------------------------------------------------------------------
11+
// Public Definitions
12+
//--------------------------------------------------------------------------------------------------
13+
14+
pub struct NullConsole;
15+
16+
//--------------------------------------------------------------------------------------------------
17+
// Global instances
18+
//--------------------------------------------------------------------------------------------------
19+
20+
pub static NULL_CONSOLE: NullConsole = NullConsole {};
21+
22+
//--------------------------------------------------------------------------------------------------
23+
// Public Code
24+
//--------------------------------------------------------------------------------------------------
25+
26+
impl interface::Write for NullConsole {
27+
fn write_char(&self, _c: char) {}
28+
29+
fn write_fmt(&self, _args: fmt::Arguments) -> fmt::Result {
30+
fmt::Result::Ok(())
31+
}
32+
33+
fn flush(&self) {}
34+
}
35+
36+
impl interface::Read for NullConsole {
37+
fn clear_rx(&self) {}
38+
}
39+
40+
impl interface::Statistics for NullConsole {}
41+
impl interface::All for NullConsole {}

05_drivers_gpio_uart/src/driver.rs

+136-13
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,22 @@
44

55
//! Driver support.
66
7+
use crate::{
8+
println,
9+
synchronization::{interface::Mutex, NullLock},
10+
};
11+
12+
//--------------------------------------------------------------------------------------------------
13+
// Private Definitions
14+
//--------------------------------------------------------------------------------------------------
15+
16+
const NUM_DRIVERS: usize = 5;
17+
18+
struct DriverManagerInner {
19+
next_index: usize,
20+
descriptors: [Option<DeviceDriverDescriptor>; NUM_DRIVERS],
21+
}
22+
723
//--------------------------------------------------------------------------------------------------
824
// Public Definitions
925
//--------------------------------------------------------------------------------------------------
@@ -24,21 +40,128 @@ pub mod interface {
2440
Ok(())
2541
}
2642
}
43+
}
44+
45+
/// Tpye to be used as an optional callback after a driver's init() has run.
46+
pub type DeviceDriverPostInitCallback = unsafe fn() -> Result<(), &'static str>;
47+
48+
/// A descriptor for device drivers.
49+
#[derive(Copy, Clone)]
50+
pub struct DeviceDriverDescriptor {
51+
device_driver: &'static (dyn interface::DeviceDriver + Sync),
52+
post_init_callback: Option<DeviceDriverPostInitCallback>,
53+
}
54+
55+
/// Provides device driver management functions.
56+
pub struct DriverManager {
57+
inner: NullLock<DriverManagerInner>,
58+
}
59+
60+
//--------------------------------------------------------------------------------------------------
61+
// Global instances
62+
//--------------------------------------------------------------------------------------------------
63+
64+
static DRIVER_MANAGER: DriverManager = DriverManager::new();
65+
66+
//--------------------------------------------------------------------------------------------------
67+
// Private Code
68+
//--------------------------------------------------------------------------------------------------
69+
70+
impl DriverManagerInner {
71+
/// Create an instance.
72+
pub const fn new() -> Self {
73+
Self {
74+
next_index: 0,
75+
descriptors: [None; NUM_DRIVERS],
76+
}
77+
}
78+
}
79+
80+
//--------------------------------------------------------------------------------------------------
81+
// Public Code
82+
//--------------------------------------------------------------------------------------------------
83+
84+
impl DeviceDriverDescriptor {
85+
/// Create an instance.
86+
pub fn new(
87+
device_driver: &'static (dyn interface::DeviceDriver + Sync),
88+
post_init_callback: Option<DeviceDriverPostInitCallback>,
89+
) -> Self {
90+
Self {
91+
device_driver,
92+
post_init_callback,
93+
}
94+
}
95+
}
96+
97+
/// Return a reference to the global DriverManager.
98+
pub fn driver_manager() -> &'static DriverManager {
99+
&DRIVER_MANAGER
100+
}
101+
102+
impl DriverManager {
103+
/// Create an instance.
104+
pub const fn new() -> Self {
105+
Self {
106+
inner: NullLock::new(DriverManagerInner::new()),
107+
}
108+
}
27109

28-
/// Device driver management functions.
110+
/// Register a device driver with the kernel.
111+
pub fn register_driver(&self, descriptor: DeviceDriverDescriptor) {
112+
self.inner.lock(|inner| {
113+
inner.descriptors[inner.next_index] = Some(descriptor);
114+
inner.next_index += 1;
115+
})
116+
}
117+
118+
/// Helper for iterating over registered drivers.
119+
fn for_each_descriptor<'a>(&'a self, f: impl FnMut(&'a DeviceDriverDescriptor)) {
120+
self.inner.lock(|inner| {
121+
inner
122+
.descriptors
123+
.iter()
124+
.filter_map(|x| x.as_ref())
125+
.for_each(f)
126+
})
127+
}
128+
129+
/// Fully initialize all drivers.
29130
///
30-
/// The `BSP` is supposed to supply one global instance.
31-
pub trait DriverManager {
32-
/// Return a slice of references to all `BSP`-instantiated drivers.
33-
///
34-
/// # Safety
35-
///
36-
/// - The order of devices is the order in which `DeviceDriver::init()` is called.
37-
fn all_device_drivers(&self) -> &[&'static (dyn DeviceDriver + Sync)];
131+
/// # Safety
132+
///
133+
/// - During init, drivers might do stuff with system-wide impact.
134+
pub unsafe fn init_drivers(&self) {
135+
self.for_each_descriptor(|descriptor| {
136+
// 1. Initialize driver.
137+
if let Err(x) = descriptor.device_driver.init() {
138+
panic!(
139+
"Error initializing driver: {}: {}",
140+
descriptor.device_driver.compatible(),
141+
x
142+
);
143+
}
38144

39-
/// Initialization code that runs after driver init.
40-
///
41-
/// For example, device driver code that depends on other drivers already being online.
42-
fn post_device_driver_init(&self);
145+
// 2. Call corresponding post init callback.
146+
if let Some(callback) = &descriptor.post_init_callback {
147+
if let Err(x) = callback() {
148+
panic!(
149+
"Error during driver post-init callback: {}: {}",
150+
descriptor.device_driver.compatible(),
151+
x
152+
);
153+
}
154+
}
155+
});
156+
}
157+
158+
/// Enumerate all registered device drivers.
159+
pub fn enumerate(&self) {
160+
let mut i: usize = 1;
161+
self.for_each_descriptor(|descriptor| {
162+
println!(" {}. {}", i, descriptor.device_driver.compatible());
163+
164+
i += 1;
165+
});
43166
}
44167
}

05_drivers_gpio_uart/src/main.rs

+7-15
Original file line numberDiff line numberDiff line change
@@ -129,14 +129,13 @@ mod synchronization;
129129
/// - Only a single core must be active and running this function.
130130
/// - The init calls in this function must appear in the correct order.
131131
unsafe fn kernel_init() -> ! {
132-
use driver::interface::DriverManager;
133-
134-
for i in bsp::driver::driver_manager().all_device_drivers().iter() {
135-
if let Err(x) = i.init() {
136-
panic!("Error loading driver: {}: {}", i.compatible(), x);
137-
}
132+
// Initialize the BSP driver subsystem.
133+
if let Err(x) = bsp::driver::init() {
134+
panic!("Error initializing BSP driver subsystem: {}", x);
138135
}
139-
bsp::driver::driver_manager().post_device_driver_init();
136+
137+
// Initialize all device drivers.
138+
driver::driver_manager().init_drivers();
140139
// println! is usable from here on.
141140

142141
// Transition from unsafe to safe.
@@ -146,7 +145,6 @@ unsafe fn kernel_init() -> ! {
146145
/// The main function running after the early init.
147146
fn kernel_main() -> ! {
148147
use console::console;
149-
use driver::interface::DriverManager;
150148

151149
println!(
152150
"[0] {} version {}",
@@ -156,13 +154,7 @@ fn kernel_main() -> ! {
156154
println!("[1] Booting on: {}", bsp::board_name());
157155

158156
println!("[2] Drivers loaded:");
159-
for (i, driver) in bsp::driver::driver_manager()
160-
.all_device_drivers()
161-
.iter()
162-
.enumerate()
163-
{
164-
println!(" {}. {}", i + 1, driver.compatible());
165-
}
157+
driver::driver_manager().enumerate();
166158

167159
println!("[3] Chars written: {}", console().chars_written());
168160
println!("[4] Echoing input now");

0 commit comments

Comments
 (0)