[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Minios-devel] [UNIKRAFT PATCHv6 06/37] plat/common: Add early debug console library for Arm64
Reviewed-by: Simon Kuenzer <simon.kuenzer@xxxxxxxxx>
On 14.09.2018 09:56, Wei Chen wrote:
From: Wei Chen <Wei.Chen@xxxxxxx>
PL011 UART is used frequently for virtual machine or bare metal,
so we implement a simple PL011 device driver library for early
debug console. Unikraft Kconfig provides a KVM_EARLY_DEBUG_PL011_UART
for early debug console UART address. If users want to enable PL011
for early debug, they can configure the base address in this variable.
Signed-off-by: Wei Chen <Wei.Chen@xxxxxxx>
---
plat/common/arm/pl011.c | 148 ++++++++++++++++++++++++++++++++++++++++
plat/kvm/Makefile.uk | 3 +
2 files changed, 151 insertions(+)
create mode 100644 plat/common/arm/pl011.c
diff --git a/plat/common/arm/pl011.c b/plat/common/arm/pl011.c
new file mode 100644
index 0000000..2a2311f
--- /dev/null
+++ b/plat/common/arm/pl011.c
@@ -0,0 +1,148 @@
+/* SPDX-License-Identifier: ISC */
+/*
+ * Authors: Wei Chen <Wei.Chen@xxxxxxx>
+ *
+ * Copyright (c) 2018 Arm Ltd.
+ *
+ * Permission to use, copy, modify, and/or distribute this software
+ * for any purpose with or without fee is hereby granted, provided
+ * that the above copyright notice and this permission notice appear
+ * in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <uk/plat/console.h>
+#include <uk/assert.h>
+#include <arm/cpu.h>
+
+/* PL011 UART registers and masks*/
+/* Data register */
+#define REG_UARTDR_OFFSET 0x00
+
+/* Receive status register/error clear register */
+#define REG_UARTRSR_OFFSET 0x04
+#define REG_UARTECR_OFFSET 0x04
+
+/* Flag register */
+#define REG_UARTFR_OFFSET 0x18
+#define FR_TXFF (1 << 5) /* Transmit FIFO/reg full */
+#define FR_RXFE (1 << 4) /* Receive FIFO/reg empty */
+
+/* Integer baud rate register */
+#define REG_UARTIBRD_OFFSET 0x24
+/* Fractional baud rate register */
+#define REG_UARTFBRD_OFFSET 0x28
+
+/* Line control register */
+#define REG_UARTLCR_H_OFFSET 0x2C
+#define LCR_H_WLEN8 (0x3 << 5) /* Data width is 8-bits */
+
+/* Control register */
+#define REG_UARTCR_OFFSET 0x30
+#define CR_RXE (1 << 9) /* Receive enable */
+#define CR_TXE (1 << 8) /* Transmit enable */
+#define CR_UARTEN (1 << 0) /* UART enable */
+
+/* Interrupt FIFO level select register */
+#define REG_UARTIFLS_OFFSET 0x34
+/* Interrupt mask set/clear register */
+#define REG_UARTIMSC_OFFSET 0x38
+/* Raw interrupt status register */
+#define REG_UARTRIS_OFFSET 0x3C
+/* Masked interrupt status register */
+#define REG_UARTMIS_OFFSET 0x40
+/* Interrupt clear register */
+#define REG_UARTICR_OFFSET 0x44
+
+/*
+ * PL011 UART base address
+ * As we are using the PA = VA mapping, some SoC would set PA 0
+ * as a valid address, so we can't use pl011_uart_bas == 0 to
+ * indicate PL011 hasn't been initialized. In this case, we
+ * use pl011_uart_initialized as an extra variable to check
+ * whether the UART has been initialized.
+ */
+#if defined(CONFIG_EARLY_PRINT_PL011_UART_ADDR)
+static uint8_t pl011_uart_initialized = 1;
+static uint64_t pl011_uart_bas = CONFIG_EARLY_PRINT_PL011_UART_ADDR;
+#else
+static uint8_t pl011_uart_initialized = 0;
+static uint64_t pl011_uart_bas = 0;
+#endif
+
+/* Macros to access PL011 Registers with base address */
+#define PL011_REG(r) ((uint16_t *)(pl011_uart_bas + (r)))
+#define PL011_REG_READ(r) ioreg_read16(PL011_REG(r))
+#define PL011_REG_WRITE(r, v) ioreg_write16(PL011_REG(r), v)
+
+int ukplat_coutd(const char *str, uint32_t len)
+{
+ return ukplat_coutk(str, len);
+}
+
+static void pl011_write(char a)
+{
+ /*
+ * Avoid using the UART before base address initialized,
+ * or CONFIG_KVM_EARLY_DEBUG_PL011_UART doesn't be enabled.
+ */
+ if (!pl011_uart_initialized)
+ return;
+
+ /* Wait until TX FIFO becomes empty */
+ while (PL011_REG_READ(REG_UARTFR_OFFSET) & FR_TXFF)
+ ;
+
+ PL011_REG_WRITE(REG_UARTDR_OFFSET, a & 0xff);
+}
+
+static void pl011_putc(char a)
+{
+ if (a == '\n')
+ pl011_write('\r');
+ pl011_write(a);
+}
+
+/* Try to get data from pl011 UART without blocking */
+static int pl011_getc(void)
+{
+ /*
+ * Avoid using the UART before base address initialized,
+ * or CONFIG_KVM_EARLY_DEBUG_PL011_UART doesn't be enabled.
+ */
+ if (!pl011_uart_initialized)
+ return -1;
+
+ /* If RX FIFO is empty, return -1 immediately */
+ if (PL011_REG_READ(REG_UARTFR_OFFSET) & FR_RXFE)
+ return -1;
+
+ return (int) (PL011_REG_READ(REG_UARTDR_OFFSET) & 0xff);
+}
+
+int ukplat_coutk(const char *buf, unsigned int len)
+{
+ for (unsigned int i = 0; i < len; i++)
+ pl011_putc(buf[i]);
+ return len;
+}
+
+int ukplat_cink(char *buf, unsigned int maxlen)
+{
+ int ret;
+ unsigned int num = 0;
+
+ while (num < maxlen && (ret = pl011_getc()) >= 0) {
+ *(buf++) = (char) ret;
+ num++;
+ }
+
+ return (int) num;
+}
diff --git a/plat/kvm/Makefile.uk b/plat/kvm/Makefile.uk
index 9f2a01f..0bae258 100644
--- a/plat/kvm/Makefile.uk
+++ b/plat/kvm/Makefile.uk
@@ -49,6 +49,9 @@ endif
## Architecture library definitions for arm64
##
ifeq ($(CONFIG_ARCH_ARM_64),y)
+ifeq ($(findstring y,$(CONFIG_KVM_KERNEL_SERIAL_CONSOLE)
$(CONFIG_KVM_DEBUG_SERIAL_CONSOLE)),y)
+LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) +=
$(UK_PLAT_COMMON_BASE)/arm/pl011.c|common
+endif
LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(LIBKVMPLAT_BASE)/arm/entry64.S
LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(LIBKVMPLAT_BASE)/arm/setup.c
endif
_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel
|