/* * Each architecture must implement puts() and exit() with the I/O * devices exposed from QEMU, e.g. pl011 and chr-testdev. That's * what's done here, along with initialization functions for those * devices. * * Copyright (C) 2014, Red Hat Inc, Andrew Jones * * This work is licensed under the terms of the GNU LGPL, version 2. */ #include #include #include #include #include #include #include #include "io.h" static struct spinlock uart_lock; /* * Use this guess for the uart base in order to make an attempt at * having earlier printf support. We'll overwrite it with the real * base address that we read from the device tree later. This is * the address we expect the virtual machine manager to put in * its generated device tree. */ #define UART_EARLY_BASE (u8 *)(unsigned long)CONFIG_UART_EARLY_BASE static volatile u8 *uart0_base = UART_EARLY_BASE; bool is_pl011_uart; static void uart0_init_fdt(void) { /* * kvm-unit-tests uses the uart only for output. Both uart models have * the TX register at offset 0 from the base address, so there is no * need to treat them separately. */ const char *compatible[] = {"arm,pl011", "ns16550a"}; struct dt_pbus_reg base; int i, ret; ret = dt_get_default_console_node(); assert(ret >= 0 || ret == -FDT_ERR_NOTFOUND); if (ret == -FDT_ERR_NOTFOUND) { for (i = 0; i < ARRAY_SIZE(compatible); i++) { ret = dt_pbus_get_base_compatible(compatible[i], &base); assert(ret == 0 || ret == -FDT_ERR_NOTFOUND); if (ret == 0) break; } if (ret) { printf("%s: Compatible uart not found in the device tree, " "aborting...\n", __func__); abort(); } is_pl011_uart = (i == 0); } else { is_pl011_uart = !fdt_node_check_compatible(dt_fdt(), ret, "arm,pl011"); ret = dt_pbus_translate_node(ret, 0, &base); assert(ret == 0); } uart0_base = ioremap(base.addr, base.size); } #ifdef CONFIG_EFI #include static void uart0_init_acpi(void) { struct spcr_descriptor *spcr = find_acpi_table_addr(SPCR_SIGNATURE); assert_msg(spcr, "Unable to find ACPI SPCR"); uart0_base = ioremap(spcr->serial_port.address, spcr->serial_port.bit_width); } #else static void uart0_init_acpi(void) { assert_msg(false, "ACPI not available"); } #endif void io_init(void) { if (dt_available()) uart0_init_fdt(); else uart0_init_acpi(); if (uart0_base != UART_EARLY_BASE) { printf("WARNING: early print support may not work. " "Found uart at %p, but early base is %p.\n", uart0_base, UART_EARLY_BASE); } chr_testdev_init(); } void puts(const char *s) { spin_lock(&uart_lock); while (*s) writeb(*s++, uart0_base); spin_unlock(&uart_lock); } int __getchar(void) { int c = -1; spin_lock(&uart_lock); if (is_pl011_uart) { if (!(readb(uart0_base + 6 * 4) & 0x10)) /* RX not empty? */ c = readb(uart0_base); } else { if (readb(uart0_base + 5) & 0x01) /* RX data ready? */ c = readb(uart0_base); } spin_unlock(&uart_lock); return c; } /* * Defining halt to take 'code' as an argument guarantees that it will * be in x0/r0 when we halt. That gives us a final chance to see the exit * status while inspecting the halted unit test state. */ extern void halt(int code); void exit(int code) { /* * Print the test return code in the following format which is * consistent with powerpc and s390x. The runner can pick it * up when chr-testdev is not present. */ printf("\nEXIT: STATUS=%d\n", ((code) << 1) | 1); chr_testdev_exit(code); psci_system_off(); halt(code); __builtin_unreachable(); }