xref: /kvm-unit-tests/lib/riscv/io.c (revision dfc1fec2fbde04ad607e1aed560cf7059350c70f)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Each architecture must implement puts() and exit() with the I/O
4  * devices exposed from QEMU, e.g. ns16550a.
5  *
6  * Copyright (C) 2023, Ventana Micro Systems Inc., Andrew Jones <ajones@ventanamicro.com>
7  */
8 #include <libcflat.h>
9 #include <config.h>
10 #include <asm/io.h>
11 #include <asm/spinlock.h>
12 
13 /*
14  * Use this guess for the uart base in order to make an attempt at
15  * having earlier printf support. We'll overwrite it with the real
16  * base address that we read from the device tree later. This is
17  * the address we expect the virtual machine manager to put in
18  * its generated device tree.
19  */
20 #define UART_EARLY_BASE ((u8 *)(unsigned long)CONFIG_UART_EARLY_BASE)
21 static volatile u8 *uart0_base = UART_EARLY_BASE;
22 static struct spinlock uart_lock;
23 
24 void puts(const char *s)
25 {
26 	spin_lock(&uart_lock);
27 	while (*s)
28 		writeb(*s++, uart0_base);
29 	spin_unlock(&uart_lock);
30 }
31 
32 /*
33  * Defining halt to take 'code' as an argument guarantees that it will
34  * be in a0 when we halt. That gives us a final chance to see the exit
35  * status while inspecting the halted unit test state.
36  */
37 void halt(int code);
38 
39 void exit(int code)
40 {
41 	printf("\nEXIT: STATUS=%d\n", ((code) << 1) | 1);
42 	halt(code);
43 	__builtin_unreachable();
44 }
45