1 // Copyright 2022, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 //! Console driver for 8250 UART.
16
17 use crate::uart::Uart;
18 use core::fmt::{write, Arguments, Write};
19 use spin::{mutex::SpinMutex, Once};
20
21 // Arbitrary limit on the number of consoles that can be registered.
22 //
23 // Matches the UART count in crosvm.
24 const MAX_CONSOLES: usize = 4;
25
26 static CONSOLES: [Once<SpinMutex<Uart>>; MAX_CONSOLES] =
27 [Once::new(), Once::new(), Once::new(), Once::new()];
28 static ADDRESSES: [Once<usize>; MAX_CONSOLES] =
29 [Once::new(), Once::new(), Once::new(), Once::new()];
30
31 /// Index of the console used by default for logging.
32 pub const DEFAULT_CONSOLE_INDEX: usize = 0;
33
34 /// Index of the console used by default for emergency logging.
35 pub const DEFAULT_EMERGENCY_CONSOLE_INDEX: usize = DEFAULT_CONSOLE_INDEX;
36
37 /// Initialises the global instance(s) of the UART driver.
38 ///
39 /// This must be called before using the `print!` and `println!` macros.
40 ///
41 /// # Safety
42 ///
43 /// This must be called once with the bases of UARTs, mapped as device memory and (if necessary)
44 /// shared with the host as MMIO, to which no other references must be held.
init(base_addresses: &[usize])45 pub unsafe fn init(base_addresses: &[usize]) {
46 for (i, &base_address) in base_addresses.iter().enumerate() {
47 // Remember the valid address, for emergency console accesses.
48 ADDRESSES[i].call_once(|| base_address);
49
50 // Initialize the console driver, for normal console accesses.
51 assert!(!CONSOLES[i].is_completed(), "console::init() called more than once");
52 // SAFETY: The caller promised that base_address is the base of a mapped UART with no
53 // aliases.
54 CONSOLES[i].call_once(|| SpinMutex::new(unsafe { Uart::new(base_address) }));
55 }
56 }
57
58 /// Writes a formatted string followed by a newline to the n-th console.
59 ///
60 /// Panics if the n-th console was not initialized by calling [`init`] first.
writeln(n: usize, format_args: Arguments)61 pub fn writeln(n: usize, format_args: Arguments) {
62 let uart = &mut *CONSOLES[n].get().unwrap().lock();
63
64 write(uart, format_args).unwrap();
65 let _ = uart.write_str("\n");
66 }
67
68 /// Reinitializes the n-th UART driver and writes a formatted string followed by a newline to it.
69 ///
70 /// This is intended for use in situations where the UART may be in an unknown state or the global
71 /// instance may be locked, such as in an exception handler or panic handler.
ewriteln(n: usize, format_args: Arguments)72 pub fn ewriteln(n: usize, format_args: Arguments) {
73 let Some(addr) = ADDRESSES[n].get() else { return };
74
75 // SAFETY: addr contains the base of a mapped UART, passed in init().
76 let mut uart = unsafe { Uart::new(*addr) };
77
78 let _ = write(&mut uart, format_args);
79 let _ = uart.write_str("\n");
80 }
81
82 /// Prints the given formatted string to the n-th console, followed by a newline.
83 ///
84 /// Panics if the console has not yet been initialized. May hang if used in an exception context;
85 /// use `eprintln!` instead.
86 #[macro_export]
87 macro_rules! console_writeln {
88 ($n:expr, $($arg:tt)*) => ({
89 $crate::console::writeln($n, format_args!($($arg)*))
90 })
91 }
92
93 pub(crate) use console_writeln;
94
95 /// Prints the given formatted string to the console, followed by a newline.
96 ///
97 /// Panics if the console has not yet been initialized. May hang if used in an exception context;
98 /// use `eprintln!` instead.
99 macro_rules! println {
100 ($($arg:tt)*) => ({
101 $crate::console::console_writeln!($crate::console::DEFAULT_CONSOLE_INDEX, $($arg)*)
102 })
103 }
104
105 pub(crate) use println; // Make it available in this crate.
106
107 /// Prints the given string followed by a newline to the console in an emergency, such as an
108 /// exception handler.
109 ///
110 /// Never panics.
111 #[macro_export]
112 macro_rules! eprintln {
113 ($($arg:tt)*) => ({
114 $crate::console::ewriteln($crate::console::DEFAULT_EMERGENCY_CONSOLE_INDEX, format_args!($($arg)*))
115 })
116 }
117