xref: /kvm-unit-tests/lib/arm/io.c (revision 1d0f08f40d53daa39566842ec46a112db5f7e524)
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 
32 static void uart0_init_fdt(void)
33 {
34 	/*
35 	 * kvm-unit-tests uses the uart only for output. Both uart models have
36 	 * the TX register at offset 0 from the base address, so there is no
37 	 * need to treat them separately.
38 	 */
39 	const char *compatible[] = {"arm,pl011", "ns16550a"};
40 	struct dt_pbus_reg base;
41 	int i, ret;
42 
43 	ret = dt_get_default_console_node();
44 	assert(ret >= 0 || ret == -FDT_ERR_NOTFOUND);
45 
46 	if (ret == -FDT_ERR_NOTFOUND) {
47 
48 		for (i = 0; i < ARRAY_SIZE(compatible); i++) {
49 			ret = dt_pbus_get_base_compatible(compatible[i], &base);
50 			assert(ret == 0 || ret == -FDT_ERR_NOTFOUND);
51 
52 			if (ret == 0)
53 				break;
54 		}
55 
56 		if (ret) {
57 			printf("%s: Compatible uart not found in the device tree, "
58 				"aborting...\n", __func__);
59 			abort();
60 		}
61 
62 	} else {
63 		ret = dt_pbus_translate_node(ret, 0, &base);
64 		assert(ret == 0);
65 	}
66 
67 	uart0_base = ioremap(base.addr, base.size);
68 }
69 
70 #ifdef CONFIG_EFI
71 
72 #include <acpi.h>
73 
74 static void uart0_init_acpi(void)
75 {
76 	struct spcr_descriptor *spcr = find_acpi_table_addr(SPCR_SIGNATURE);
77 
78 	assert_msg(spcr, "Unable to find ACPI SPCR");
79 	uart0_base = ioremap(spcr->serial_port.address, spcr->serial_port.bit_width);
80 }
81 #else
82 
83 static void uart0_init_acpi(void)
84 {
85 	assert_msg(false, "ACPI not available");
86 }
87 
88 #endif
89 
90 void io_init(void)
91 {
92 	if (dt_available())
93 		uart0_init_fdt();
94 	else
95 		uart0_init_acpi();
96 
97 	if (uart0_base != UART_EARLY_BASE) {
98 		printf("WARNING: early print support may not work. "
99 		       "Found uart at %p, but early base is %p.\n",
100 			uart0_base, UART_EARLY_BASE);
101 	}
102 
103 	chr_testdev_init();
104 }
105 
106 void puts(const char *s)
107 {
108 	spin_lock(&uart_lock);
109 	while (*s)
110 		writeb(*s++, uart0_base);
111 	spin_unlock(&uart_lock);
112 }
113 
114 static int do_getchar(void)
115 {
116 	int c;
117 
118 	spin_lock(&uart_lock);
119 	c = readb(uart0_base);
120 	spin_unlock(&uart_lock);
121 
122 	return c ?: -1;
123 }
124 
125 /*
126  * Minimalist implementation for migration completion detection.
127  * Without FIFOs enabled on the QEMU UART device we just read
128  * the data register: we cannot read more than 16 characters.
129  */
130 int __getchar(void)
131 {
132 	int c = do_getchar();
133 	static int count;
134 
135 	if (c != -1)
136 		++count;
137 
138 	assert(count < 16);
139 
140 	return c;
141 }
142 
143 /*
144  * Defining halt to take 'code' as an argument guarantees that it will
145  * be in x0/r0 when we halt. That gives us a final chance to see the exit
146  * status while inspecting the halted unit test state.
147  */
148 extern void halt(int code);
149 
150 void exit(int code)
151 {
152 	/*
153 	 * Print the test return code in the following format which is
154 	 * consistent with powerpc and s390x. The runner can pick it
155 	 * up when chr-testdev is not present.
156 	 */
157 	printf("\nEXIT: STATUS=%d\n", ((code) << 1) | 1);
158 
159 	chr_testdev_exit(code);
160 	psci_system_off();
161 	halt(code);
162 	__builtin_unreachable();
163 }
164