Andrew Walbran | f259488 | 2022-03-15 17:32:53 +0000 | [diff] [blame] | 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; |
Andrew Walbran | f86d4b0 | 2024-07-19 17:23:18 +0100 | [diff] [blame] | 18 | use core::fmt::{write, Arguments, Write}; |
| 19 | use spin::{mutex::SpinMutex, Once}; |
Andrew Walbran | f259488 | 2022-03-15 17:32:53 +0000 | [diff] [blame] | 20 | |
Pierre-Clément Tosi | 075aade | 2024-06-18 20:08:13 +0100 | [diff] [blame] | 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; |
Andrew Walbran | f259488 | 2022-03-15 17:32:53 +0000 | [diff] [blame] | 25 | |
Andrew Walbran | f615d73 | 2024-07-22 14:41:09 +0100 | [diff] [blame^] | 26 | static CONSOLES: [Once<SpinMutex<Uart>>; MAX_CONSOLES] = |
| 27 | [Once::new(), Once::new(), Once::new(), Once::new()]; |
Andrew Walbran | f86d4b0 | 2024-07-19 17:23:18 +0100 | [diff] [blame] | 28 | static ADDRESSES: [Once<usize>; MAX_CONSOLES] = |
| 29 | [Once::new(), Once::new(), Once::new(), Once::new()]; |
Pierre-Clément Tosi | 075aade | 2024-06-18 20:08:13 +0100 | [diff] [blame] | 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. |
Pierre-Clément Tosi | 8e92d1a | 2024-06-18 16:15:14 +0100 | [diff] [blame] | 38 | /// |
| 39 | /// This must be called before using the `print!` and `println!` macros. |
| 40 | /// |
| 41 | /// # Safety |
| 42 | /// |
Pierre-Clément Tosi | 075aade | 2024-06-18 20:08:13 +0100 | [diff] [blame] | 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. |
| 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. |
Andrew Walbran | f86d4b0 | 2024-07-19 17:23:18 +0100 | [diff] [blame] | 48 | ADDRESSES[i].call_once(|| base_address); |
Andrew Walbran | f259488 | 2022-03-15 17:32:53 +0000 | [diff] [blame] | 49 | |
Pierre-Clément Tosi | 075aade | 2024-06-18 20:08:13 +0100 | [diff] [blame] | 50 | // Initialize the console driver, for normal console accesses. |
Andrew Walbran | f615d73 | 2024-07-22 14:41:09 +0100 | [diff] [blame^] | 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) })); |
Pierre-Clément Tosi | 075aade | 2024-06-18 20:08:13 +0100 | [diff] [blame] | 55 | } |
Andrew Walbran | f259488 | 2022-03-15 17:32:53 +0000 | [diff] [blame] | 56 | } |
| 57 | |
Pierre-Clément Tosi | 075aade | 2024-06-18 20:08:13 +0100 | [diff] [blame] | 58 | /// Writes a formatted string followed by a newline to the n-th console. |
Andrew Walbran | f259488 | 2022-03-15 17:32:53 +0000 | [diff] [blame] | 59 | /// |
Pierre-Clément Tosi | 075aade | 2024-06-18 20:08:13 +0100 | [diff] [blame] | 60 | /// Panics if the n-th console was not initialized by calling [`init`] first. |
Pierre-Clément Tosi | b5a3ab1 | 2023-09-15 11:18:38 +0100 | [diff] [blame] | 61 | pub fn writeln(n: usize, format_args: Arguments) { |
Andrew Walbran | f615d73 | 2024-07-22 14:41:09 +0100 | [diff] [blame^] | 62 | let uart = &mut *CONSOLES[n].get().unwrap().lock(); |
Pierre-Clément Tosi | bc9fb7e | 2024-06-19 17:28:47 +0100 | [diff] [blame] | 63 | |
| 64 | write(uart, format_args).unwrap(); |
| 65 | let _ = uart.write_str("\n"); |
Andrew Walbran | f259488 | 2022-03-15 17:32:53 +0000 | [diff] [blame] | 66 | } |
| 67 | |
Pierre-Clément Tosi | 075aade | 2024-06-18 20:08:13 +0100 | [diff] [blame] | 68 | /// Reinitializes the n-th UART driver and writes a formatted string followed by a newline to it. |
Andrew Walbran | f259488 | 2022-03-15 17:32:53 +0000 | [diff] [blame] | 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. |
Pierre-Clément Tosi | 075aade | 2024-06-18 20:08:13 +0100 | [diff] [blame] | 72 | pub fn ewriteln(n: usize, format_args: Arguments) { |
Andrew Walbran | f86d4b0 | 2024-07-19 17:23:18 +0100 | [diff] [blame] | 73 | let Some(addr) = ADDRESSES[n].get() else { return }; |
Pierre-Clément Tosi | 8e92d1a | 2024-06-18 16:15:14 +0100 | [diff] [blame] | 74 | |
| 75 | // SAFETY: addr contains the base of a mapped UART, passed in init(). |
| 76 | let mut uart = unsafe { Uart::new(*addr) }; |
| 77 | |
Andrew Walbran | c1bcb3c | 2022-03-31 13:13:57 +0000 | [diff] [blame] | 78 | let _ = write(&mut uart, format_args); |
Pierre-Clément Tosi | bc9fb7e | 2024-06-19 17:28:47 +0100 | [diff] [blame] | 79 | let _ = uart.write_str("\n"); |
Andrew Walbran | c1bcb3c | 2022-03-31 13:13:57 +0000 | [diff] [blame] | 80 | } |
| 81 | |
Pierre-Clément Tosi | b5a3ab1 | 2023-09-15 11:18:38 +0100 | [diff] [blame] | 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 | |
Andrew Walbran | c1bcb3c | 2022-03-31 13:13:57 +0000 | [diff] [blame] | 95 | /// Prints the given formatted string to the console, followed by a newline. |
| 96 | /// |
Alice Wang | eff5839 | 2023-07-04 13:32:09 +0000 | [diff] [blame] | 97 | /// Panics if the console has not yet been initialized. May hang if used in an exception context; |
Andrew Walbran | c1bcb3c | 2022-03-31 13:13:57 +0000 | [diff] [blame] | 98 | /// use `eprintln!` instead. |
Andrew Walbran | c1bcb3c | 2022-03-31 13:13:57 +0000 | [diff] [blame] | 99 | macro_rules! println { |
Pierre-Clément Tosi | 075aade | 2024-06-18 20:08:13 +0100 | [diff] [blame] | 100 | ($($arg:tt)*) => ({ |
Pierre-Clément Tosi | b5a3ab1 | 2023-09-15 11:18:38 +0100 | [diff] [blame] | 101 | $crate::console::console_writeln!($crate::console::DEFAULT_CONSOLE_INDEX, $($arg)*) |
Pierre-Clément Tosi | 075aade | 2024-06-18 20:08:13 +0100 | [diff] [blame] | 102 | }) |
Andrew Walbran | c1bcb3c | 2022-03-31 13:13:57 +0000 | [diff] [blame] | 103 | } |
| 104 | |
Jakob Vukalovic | ef99629 | 2023-04-13 14:28:34 +0000 | [diff] [blame] | 105 | pub(crate) use println; // Make it available in this crate. |
| 106 | |
Andrew Walbran | c1bcb3c | 2022-03-31 13:13:57 +0000 | [diff] [blame] | 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 { |
Pierre-Clément Tosi | 075aade | 2024-06-18 20:08:13 +0100 | [diff] [blame] | 113 | ($($arg:tt)*) => ({ |
| 114 | $crate::console::ewriteln($crate::console::DEFAULT_EMERGENCY_CONSOLE_INDEX, format_args!($($arg)*)) |
| 115 | }) |
Andrew Walbran | c1bcb3c | 2022-03-31 13:13:57 +0000 | [diff] [blame] | 116 | } |