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(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 if (uart0_base != UART_EARLY_BASE) { 70 printf("WARNING: early print support may not work. " 71 "Found uart at %p, but early base is %p.\n", 72 uart0_base, UART_EARLY_BASE); 73 } 74 } 75 76 void io_init(void) 77 { 78 uart0_init(); 79 chr_testdev_init(); 80 } 81 82 void puts(const char *s) 83 { 84 spin_lock(&uart_lock); 85 while (*s) 86 writeb(*s++, uart0_base); 87 spin_unlock(&uart_lock); 88 } 89 90 static int do_getchar(void) 91 { 92 int c; 93 94 spin_lock(&uart_lock); 95 c = readb(uart0_base); 96 spin_unlock(&uart_lock); 97 98 return c ?: -1; 99 } 100 101 /* 102 * Minimalist implementation for migration completion detection. 103 * Without FIFOs enabled on the QEMU UART device we just read 104 * the data register: we cannot read more than 16 characters. 105 */ 106 int __getchar(void) 107 { 108 int c = do_getchar(); 109 static int count; 110 111 if (c != -1) 112 ++count; 113 114 assert(count < 16); 115 116 return c; 117 } 118 119 /* 120 * Defining halt to take 'code' as an argument guarantees that it will 121 * be in x0/r0 when we halt. That gives us a final chance to see the exit 122 * status while inspecting the halted unit test state. 123 */ 124 extern void halt(int code); 125 126 void exit(int code) 127 { 128 chr_testdev_exit(code); 129 psci_system_off(); 130 halt(code); 131 __builtin_unreachable(); 132 } 133