blob: 7356d7f1b7cdbde38ac46f2a1d99a1330152c8ba [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 Tosi8e92d1a2024-06-18 16:15:14 +010024// ADDRESS is the base of the MMIO region for a UART and must be mapped as device memory.
25static ADDRESS: SpinMutex<OnceCell<usize>> = SpinMutex::new(OnceCell::new());
Andrew Walbranf2594882022-03-15 17:32:53 +000026static CONSOLE: SpinMutex<Option<Uart>> = SpinMutex::new(None);
27
Pierre-Clément Tosi8e92d1a2024-06-18 16:15:14 +010028/// Initialises the global instance of the UART driver.
29///
30/// This must be called before using the `print!` and `println!` macros.
31///
32/// # Safety
33///
34/// This must be called with the base of a UART, mapped as device memory and (if necessary) shared
35/// with the host as MMIO.
36pub unsafe fn init(base_address: usize) {
37 // Remember the valid address, for emergency console accesses.
38 ADDRESS.lock().set(base_address).expect("console::init() called more than once");
Andrew Walbranf2594882022-03-15 17:32:53 +000039
Pierre-Clément Tosi8e92d1a2024-06-18 16:15:14 +010040 // Initialize the console driver, for normal console accesses.
41 let mut console = CONSOLE.lock();
42 assert!(console.is_none(), "console::init() called more than once");
43 // SAFETY: base_address must be the base of a mapped UART.
44 console.replace(unsafe { Uart::new(base_address) });
Andrew Walbranf2594882022-03-15 17:32:53 +000045}
46
Pierre-Clément Tosibc9fb7e2024-06-19 17:28:47 +010047/// Writes a formatted string followed by a newline to the console.
Andrew Walbranf2594882022-03-15 17:32:53 +000048///
49/// Panics if [`init`] was not called first.
Pierre-Clément Tosibc9fb7e2024-06-19 17:28:47 +010050pub(crate) fn writeln(format_args: Arguments) {
51 let mut guard = CONSOLE.lock();
52 let uart = guard.as_mut().unwrap();
53
54 write(uart, format_args).unwrap();
55 let _ = uart.write_str("\n");
Andrew Walbranf2594882022-03-15 17:32:53 +000056}
57
Pierre-Clément Tosibc9fb7e2024-06-19 17:28:47 +010058/// Reinitializes the UART driver and writes a formatted string followed by a newline to it.
Andrew Walbranf2594882022-03-15 17:32:53 +000059///
60/// This is intended for use in situations where the UART may be in an unknown state or the global
61/// instance may be locked, such as in an exception handler or panic handler.
Pierre-Clément Tosibc9fb7e2024-06-19 17:28:47 +010062pub fn ewriteln(format_args: Arguments) {
Pierre-Clément Tosi8e92d1a2024-06-18 16:15:14 +010063 let Some(cell) = ADDRESS.try_lock() else { return };
64 let Some(addr) = cell.get() else { return };
65
66 // SAFETY: addr contains the base of a mapped UART, passed in init().
67 let mut uart = unsafe { Uart::new(*addr) };
68
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +000069 let _ = write(&mut uart, format_args);
Pierre-Clément Tosibc9fb7e2024-06-19 17:28:47 +010070 let _ = uart.write_str("\n");
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +000071}
72
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +000073/// Prints the given formatted string to the console, followed by a newline.
74///
Alice Wangeff58392023-07-04 13:32:09 +000075/// Panics if the console has not yet been initialized. May hang if used in an exception context;
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +000076/// use `eprintln!` instead.
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +000077macro_rules! println {
Pierre-Clément Tosibc9fb7e2024-06-19 17:28:47 +010078 ($($arg:tt)*) => ($crate::console::writeln(format_args!($($arg)*)));
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +000079}
80
Jakob Vukalovicef996292023-04-13 14:28:34 +000081pub(crate) use println; // Make it available in this crate.
82
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +000083/// Prints the given string followed by a newline to the console in an emergency, such as an
84/// exception handler.
85///
86/// Never panics.
87#[macro_export]
88macro_rules! eprintln {
Pierre-Clément Tosibc9fb7e2024-06-19 17:28:47 +010089 ($($arg:tt)*) => ($crate::console::ewriteln(format_args!($($arg)*)));
Andrew Walbranc1bcb3c2022-03-31 13:13:57 +000090}