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