blob: cd05250be5f3bff175909092fb6d5043884c9f36 [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
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +010026static CONSOLES: [SpinMutex<Option<Uart>>; MAX_CONSOLES] =
27 [SpinMutex::new(None), SpinMutex::new(None), SpinMutex::new(None), SpinMutex::new(None)];
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.
51 let mut console = CONSOLES[i].lock();
52 assert!(console.is_none(), "console::init() called more than once");
53 // SAFETY: base_address must be the base of a mapped UART.
54 console.replace(unsafe { Uart::new(base_address) });
55 }
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) {
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +010062 let mut guard = CONSOLES[n].lock();
Pierre-Clément Tosibc9fb7e2024-06-19 17:28:47 +010063 let uart = guard.as_mut().unwrap();
64
65 write(uart, format_args).unwrap();
66 let _ = uart.write_str("\n");
Andrew Walbranf2594882022-03-15 17:32:53 +000067}
68
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +010069/// Reinitializes the n-th UART driver and writes a formatted string followed by a newline to it.
Andrew Walbranf2594882022-03-15 17:32:53 +000070///
71/// This is intended for use in situations where the UART may be in an unknown state or the global
72/// instance may be locked, such as in an exception handler or panic handler.
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +010073pub fn ewriteln(n: usize, format_args: Arguments) {
Andrew Walbranf86d4b02024-07-19 17:23:18 +010074 let Some(addr) = ADDRESSES[n].get() else { return };
Pierre-Clément Tosi8e92d1a2024-06-18 16:15:14 +010075
76 // SAFETY: addr contains the base of a mapped UART, passed in init().
77 let mut uart = unsafe { Uart::new(*addr) };
78
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +000079 let _ = write(&mut uart, format_args);
Pierre-Clément Tosibc9fb7e2024-06-19 17:28:47 +010080 let _ = uart.write_str("\n");
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +000081}
82
Pierre-Clément Tosib5a3ab12023-09-15 11:18:38 +010083/// Prints the given formatted string to the n-th console, followed by a newline.
84///
85/// Panics if the console has not yet been initialized. May hang if used in an exception context;
86/// use `eprintln!` instead.
87#[macro_export]
88macro_rules! console_writeln {
89 ($n:expr, $($arg:tt)*) => ({
90 $crate::console::writeln($n, format_args!($($arg)*))
91 })
92}
93
94pub(crate) use console_writeln;
95
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +000096/// Prints the given formatted string to the console, followed by a newline.
97///
Alice Wangeff58392023-07-04 13:32:09 +000098/// Panics if the console has not yet been initialized. May hang if used in an exception context;
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +000099/// use `eprintln!` instead.
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +0000100macro_rules! println {
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +0100101 ($($arg:tt)*) => ({
Pierre-Clément Tosib5a3ab12023-09-15 11:18:38 +0100102 $crate::console::console_writeln!($crate::console::DEFAULT_CONSOLE_INDEX, $($arg)*)
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +0100103 })
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +0000104}
105
Jakob Vukalovicef996292023-04-13 14:28:34 +0000106pub(crate) use println; // Make it available in this crate.
107
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +0000108/// Prints the given string followed by a newline to the console in an emergency, such as an
109/// exception handler.
110///
111/// Never panics.
112#[macro_export]
113macro_rules! eprintln {
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +0100114 ($($arg:tt)*) => ({
115 $crate::console::ewriteln($crate::console::DEFAULT_EMERGENCY_CONSOLE_INDEX, format_args!($($arg)*))
116 })
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +0000117}