xref: /kvm-unit-tests/lib/arm/io.c (revision 8c065edf33c01d4919d22332607353650b9a2890)
1 /*
2  * Each architecture must implement puts() and exit() with the I/O
3  * devices exposed from QEMU, e.g. pl011 and chr-testdev. That's
4  * what's done here, along with initialization functions for those
5  * devices.
6  *
7  * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com>
8  *
9  * This work is licensed under the terms of the GNU LGPL, version 2.
10  */
11 #include <libcflat.h>
12 #include <devicetree.h>
13 #include <chr-testdev.h>
14 #include <config.h>
15 #include <asm/psci.h>
16 #include <asm/spinlock.h>
17 #include <asm/io.h>
18 
19 #include "io.h"
20 
21 static struct spinlock uart_lock;
22 /*
23  * Use this guess for the uart base in order to make an attempt at
24  * having earlier printf support. We'll overwrite it with the real
25  * base address that we read from the device tree later. This is
26  * the address we expect the virtual machine manager to put in
27  * its generated device tree.
28  */
29 #define UART_EARLY_BASE (u8 *)(unsigned long)CONFIG_UART_EARLY_BASE
30 static volatile u8 *uart0_base = UART_EARLY_BASE;
31 bool is_pl011_uart;
32 
uart0_init_fdt(void)33 static void uart0_init_fdt(void)
34 {
35 	/*
36 	 * kvm-unit-tests uses the uart only for output. Both uart models have
37 	 * the TX register at offset 0 from the base address, so there is no
38 	 * need to treat them separately.
39 	 */
40 	const char *compatible[] = {"arm,pl011", "ns16550a"};
41 	struct dt_pbus_reg base;
42 	int i, ret;
43 
44 	ret = dt_get_default_console_node();
45 	assert(ret >= 0 || ret == -FDT_ERR_NOTFOUND);
46 
47 	if (ret == -FDT_ERR_NOTFOUND) {
48 
49 		for (i = 0; i < ARRAY_SIZE(compatible); i++) {
50 			ret = dt_pbus_get_base_compatible(compatible[i], &base);
51 			assert(ret == 0 || ret == -FDT_ERR_NOTFOUND);
52 
53 			if (ret == 0)
54 				break;
55 		}
56 
57 		if (ret) {
58 			printf("%s: Compatible uart not found in the device tree, "
59 				"aborting...\n", __func__);
60 			abort();
61 		}
62 
63 		is_pl011_uart = (i == 0);
64 	} else {
65 		is_pl011_uart = !fdt_node_check_compatible(dt_fdt(), ret,
66 		                                           "arm,pl011");
67 		ret = dt_pbus_translate_node(ret, 0, &base);
68 		assert(ret == 0);
69 	}
70 
71 	uart0_base = ioremap(base.addr, base.size);
72 }
73 
74 #ifdef CONFIG_EFI
75 
76 #include <acpi.h>
77 
uart0_init_acpi(void)78 static void uart0_init_acpi(void)
79 {
80 	struct spcr_descriptor *spcr = find_acpi_table_addr(SPCR_SIGNATURE);
81 
82 	assert_msg(spcr, "Unable to find ACPI SPCR");
83 	uart0_base = ioremap(spcr->serial_port.address, spcr->serial_port.bit_width);
84 }
85 #else
86 
uart0_init_acpi(void)87 static void uart0_init_acpi(void)
88 {
89 	assert_msg(false, "ACPI not available");
90 }
91 
92 #endif
93 
io_init(void)94 void io_init(void)
95 {
96 	if (dt_available())
97 		uart0_init_fdt();
98 	else
99 		uart0_init_acpi();
100 
101 	if (uart0_base != UART_EARLY_BASE) {
102 		printf("WARNING: early print support may not work. "
103 		       "Found uart at %p, but early base is %p.\n",
104 			uart0_base, UART_EARLY_BASE);
105 	}
106 
107 	chr_testdev_init();
108 }
109 
puts(const char * s)110 void puts(const char *s)
111 {
112 	spin_lock(&uart_lock);
113 	while (*s)
114 		writeb(*s++, uart0_base);
115 	spin_unlock(&uart_lock);
116 }
117 
__getchar(void)118 int __getchar(void)
119 {
120 	int c = -1;
121 
122 	spin_lock(&uart_lock);
123 
124 	if (is_pl011_uart) {
125 		if (!(readb(uart0_base + 6 * 4) & 0x10))  /* RX not empty? */
126 			c = readb(uart0_base);
127 	} else {
128 		if (readb(uart0_base + 5) & 0x01)         /* RX data ready? */
129 			c = readb(uart0_base);
130 	}
131 
132 	spin_unlock(&uart_lock);
133 
134 	return c;
135 }
136 
137 /*
138  * Defining halt to take 'code' as an argument guarantees that it will
139  * be in x0/r0 when we halt. That gives us a final chance to see the exit
140  * status while inspecting the halted unit test state.
141  */
142 extern void halt(int code);
143 
exit(int code)144 void exit(int code)
145 {
146 	/*
147 	 * Print the test return code in the following format which is
148 	 * consistent with powerpc and s390x. The runner can pick it
149 	 * up when chr-testdev is not present.
150 	 */
151 	printf("\nEXIT: STATUS=%d\n", ((code) << 1) | 1);
152 
153 	chr_testdev_exit(code);
154 	psci_system_off();
155 	halt(code);
156 	__builtin_unreachable();
157 }
158