blob: bbbcb0749aa469c247b5df1b8efe1391baba2218 [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;
Pierre-Clément Tosi8e92d1a2024-06-18 16:15:14 +010018use core::{
19 cell::OnceCell,
20 fmt::{write, Arguments, Write},
21};
Andrew Walbranf2594882022-03-15 17:32:53 +000022use spin::mutex::SpinMutex;
23
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +010024// Arbitrary limit on the number of consoles that can be registered.
25//
26// Matches the UART count in crosvm.
27const MAX_CONSOLES: usize = 4;
Andrew Walbranf2594882022-03-15 17:32:53 +000028
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +010029static CONSOLES: [SpinMutex<Option<Uart>>; MAX_CONSOLES] =
30 [SpinMutex::new(None), SpinMutex::new(None), SpinMutex::new(None), SpinMutex::new(None)];
31static ADDRESSES: [SpinMutex<OnceCell<usize>>; MAX_CONSOLES] = [
32 SpinMutex::new(OnceCell::new()),
33 SpinMutex::new(OnceCell::new()),
34 SpinMutex::new(OnceCell::new()),
35 SpinMutex::new(OnceCell::new()),
36];
37
38/// Index of the console used by default for logging.
39pub const DEFAULT_CONSOLE_INDEX: usize = 0;
40
41/// Index of the console used by default for emergency logging.
42pub const DEFAULT_EMERGENCY_CONSOLE_INDEX: usize = DEFAULT_CONSOLE_INDEX;
43
44/// Initialises the global instance(s) of the UART driver.
Pierre-Clément Tosi8e92d1a2024-06-18 16:15:14 +010045///
46/// This must be called before using the `print!` and `println!` macros.
47///
48/// # Safety
49///
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +010050/// This must be called once with the bases of UARTs, mapped as device memory and (if necessary)
51/// shared with the host as MMIO, to which no other references must be held.
52pub unsafe fn init(base_addresses: &[usize]) {
53 for (i, &base_address) in base_addresses.iter().enumerate() {
54 // Remember the valid address, for emergency console accesses.
55 ADDRESSES[i].lock().set(base_address).expect("console::init() called more than once");
Andrew Walbranf2594882022-03-15 17:32:53 +000056
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +010057 // Initialize the console driver, for normal console accesses.
58 let mut console = CONSOLES[i].lock();
59 assert!(console.is_none(), "console::init() called more than once");
60 // SAFETY: base_address must be the base of a mapped UART.
61 console.replace(unsafe { Uart::new(base_address) });
62 }
Andrew Walbranf2594882022-03-15 17:32:53 +000063}
64
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +010065/// Writes a formatted string followed by a newline to the n-th console.
Andrew Walbranf2594882022-03-15 17:32:53 +000066///
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +010067/// Panics if the n-th console was not initialized by calling [`init`] first.
Pierre-Clément Tosib5a3ab12023-09-15 11:18:38 +010068pub fn writeln(n: usize, format_args: Arguments) {
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +010069 let mut guard = CONSOLES[n].lock();
Pierre-Clément Tosibc9fb7e2024-06-19 17:28:47 +010070 let uart = guard.as_mut().unwrap();
71
72 write(uart, format_args).unwrap();
73 let _ = uart.write_str("\n");
Andrew Walbranf2594882022-03-15 17:32:53 +000074}
75
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +010076/// Reinitializes the n-th UART driver and writes a formatted string followed by a newline to it.
Andrew Walbranf2594882022-03-15 17:32:53 +000077///
78/// This is intended for use in situations where the UART may be in an unknown state or the global
79/// instance may be locked, such as in an exception handler or panic handler.
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +010080pub fn ewriteln(n: usize, format_args: Arguments) {
81 let Some(cell) = ADDRESSES[n].try_lock() else { return };
Pierre-Clément Tosi8e92d1a2024-06-18 16:15:14 +010082 let Some(addr) = cell.get() else { return };
83
84 // SAFETY: addr contains the base of a mapped UART, passed in init().
85 let mut uart = unsafe { Uart::new(*addr) };
86
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +000087 let _ = write(&mut uart, format_args);
Pierre-Clément Tosibc9fb7e2024-06-19 17:28:47 +010088 let _ = uart.write_str("\n");
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +000089}
90
Pierre-Clément Tosib5a3ab12023-09-15 11:18:38 +010091/// Prints the given formatted string to the n-th console, followed by a newline.
92///
93/// Panics if the console has not yet been initialized. May hang if used in an exception context;
94/// use `eprintln!` instead.
95#[macro_export]
96macro_rules! console_writeln {
97 ($n:expr, $($arg:tt)*) => ({
98 $crate::console::writeln($n, format_args!($($arg)*))
99 })
100}
101
102pub(crate) use console_writeln;
103
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +0000104/// Prints the given formatted string to the console, followed by a newline.
105///
Alice Wangeff58392023-07-04 13:32:09 +0000106/// Panics if the console has not yet been initialized. May hang if used in an exception context;
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +0000107/// use `eprintln!` instead.
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +0000108macro_rules! println {
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +0100109 ($($arg:tt)*) => ({
Pierre-Clément Tosib5a3ab12023-09-15 11:18:38 +0100110 $crate::console::console_writeln!($crate::console::DEFAULT_CONSOLE_INDEX, $($arg)*)
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +0100111 })
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +0000112}
113
Jakob Vukalovicef996292023-04-13 14:28:34 +0000114pub(crate) use println; // Make it available in this crate.
115
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +0000116/// Prints the given string followed by a newline to the console in an emergency, such as an
117/// exception handler.
118///
119/// Never panics.
120#[macro_export]
121macro_rules! eprintln {
Pierre-Clément Tosi075aade2024-06-18 20:08:13 +0100122 ($($arg:tt)*) => ({
123 $crate::console::ewriteln($crate::console::DEFAULT_EMERGENCY_CONSOLE_INDEX, format_args!($($arg)*))
124 })
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +0000125}