blob: 7b01bb637785b49f17bb95a231ad451c1907cbf8 [file] [log] [blame]
Andrew Walbranf2594882022-03-15 17:32:53 +00001// 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
17use crate::uart::Uart;
Andrew Walbranf86d4b02024-07-19 17:23:18 +010018use core::fmt::{write, Arguments, Write};
19use spin::{mutex::SpinMutex, Once};
Andrew Walbranf2594882022-03-15 17:32:53 +000020
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +010021// Arbitrary limit on the number of consoles that can be registered.
22//
23// Matches the UART count in crosvm.
24const MAX_CONSOLES: usize = 4;
Andrew Walbranf2594882022-03-15 17:32:53 +000025
Andrew Walbranf615d732024-07-22 14:41:09 +010026static CONSOLES: [Once<SpinMutex<Uart>>; MAX_CONSOLES] =
27 [Once::new(), Once::new(), Once::new(), Once::new()];
Andrew Walbranf86d4b02024-07-19 17:23:18 +010028static ADDRESSES: [Once<usize>; MAX_CONSOLES] =
29 [Once::new(), Once::new(), Once::new(), Once::new()];
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +010030
31/// Index of the console used by default for logging.
32pub const DEFAULT_CONSOLE_INDEX: usize = 0;
33
34/// Index of the console used by default for emergency logging.
35pub const DEFAULT_EMERGENCY_CONSOLE_INDEX: usize = DEFAULT_CONSOLE_INDEX;
36
37/// Initialises the global instance(s) of the UART driver.
Pierre-Clément Tosi8e92d1a2024-06-18 16:15:14 +010038///
39/// This must be called before using the `print!` and `println!` macros.
40///
41/// # Safety
42///
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +010043/// 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.
45pub 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 Walbranf86d4b02024-07-19 17:23:18 +010048 ADDRESSES[i].call_once(|| base_address);
Andrew Walbranf2594882022-03-15 17:32:53 +000049
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +010050 // Initialize the console driver, for normal console accesses.
Andrew Walbranf615d732024-07-22 14:41:09 +010051 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 Tosi075aade2024-06-18 20:08:13 +010055 }
Andrew Walbranf2594882022-03-15 17:32:53 +000056}
57
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +010058/// Writes a formatted string followed by a newline to the n-th console.
Andrew Walbranf2594882022-03-15 17:32:53 +000059///
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +010060/// Panics if the n-th console was not initialized by calling [`init`] first.
Pierre-Clément Tosib5a3ab12023-09-15 11:18:38 +010061pub fn writeln(n: usize, format_args: Arguments) {
Andrew Walbranf615d732024-07-22 14:41:09 +010062 let uart = &mut *CONSOLES[n].get().unwrap().lock();
Pierre-Clément Tosibc9fb7e2024-06-19 17:28:47 +010063
64 write(uart, format_args).unwrap();
65 let _ = uart.write_str("\n");
Andrew Walbranf2594882022-03-15 17:32:53 +000066}
67
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +010068/// Reinitializes the n-th UART driver and writes a formatted string followed by a newline to it.
Andrew Walbranf2594882022-03-15 17:32:53 +000069///
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 Tosi075aade2024-06-18 20:08:13 +010072pub fn ewriteln(n: usize, format_args: Arguments) {
Andrew Walbranf86d4b02024-07-19 17:23:18 +010073 let Some(addr) = ADDRESSES[n].get() else { return };
Pierre-Clément Tosi8e92d1a2024-06-18 16:15:14 +010074
75 // SAFETY: addr contains the base of a mapped UART, passed in init().
76 let mut uart = unsafe { Uart::new(*addr) };
77
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +000078 let _ = write(&mut uart, format_args);
Pierre-Clément Tosibc9fb7e2024-06-19 17:28:47 +010079 let _ = uart.write_str("\n");
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +000080}
81
Pierre-Clément Tosib5a3ab12023-09-15 11:18:38 +010082/// 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]
87macro_rules! console_writeln {
88 ($n:expr, $($arg:tt)*) => ({
89 $crate::console::writeln($n, format_args!($($arg)*))
90 })
91}
92
93pub(crate) use console_writeln;
94
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +000095/// Prints the given formatted string to the console, followed by a newline.
96///
Alice Wangeff58392023-07-04 13:32:09 +000097/// Panics if the console has not yet been initialized. May hang if used in an exception context;
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +000098/// use `eprintln!` instead.
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +000099macro_rules! println {
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +0100100 ($($arg:tt)*) => ({
Pierre-Clément Tosib5a3ab12023-09-15 11:18:38 +0100101 $crate::console::console_writeln!($crate::console::DEFAULT_CONSOLE_INDEX, $($arg)*)
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +0100102 })
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +0000103}
104
Jakob Vukalovicef996292023-04-13 14:28:34 +0000105pub(crate) use println; // Make it available in this crate.
106
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +0000107/// 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]
112macro_rules! eprintln {
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +0100113 ($($arg:tt)*) => ({
114 $crate::console::ewriteln($crate::console::DEFAULT_EMERGENCY_CONSOLE_INDEX, format_args!($($arg)*))
115 })
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +0000116}