diff --git a/CODEOWNERS b/CODEOWNERS index d8b28facda9..ca2a6d1c31a 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -24,6 +24,7 @@ /arch/arm/core/aarch32/cortex_a_r/ @MaureenHelm @galak @ioannisg @bbolen @stephanosio /arch/arm64/ @carlocaione /arch/arm64/core/cortex_r/ @povergoing +/arch/arm64/core/xen/ @lorc @firscity /arch/common/ @ioannisg @andyross /soc/arc/snps_*/ @abrodkin @ruuddw @evgeniy-paltsev /soc/nios2/ @nashif @@ -60,7 +61,7 @@ /soc/arm64/qemu_cortex_a53/ @carlocaione /soc/arm64/bcm_vk/ @abhishek-brcm /soc/arm64/nxp_layerscape/ @JiafeiPan -/soc/arm64/xenvm/ @lorc +/soc/arm64/xenvm/ @lorc @firscity /soc/arm64/arm/ @povergoing /soc/arm64/arm/fvp_aemv8a/ @carlocaione /submanifests/* @mbolivar-nordic @@ -166,7 +167,7 @@ /boards/arm64/qemu_cortex_a53/ @carlocaione /boards/arm64/bcm958402m2_a72/ @abhishek-brcm /boards/arm64/nxp_ls1046ardb/ @JiafeiPan -/boards/arm64/xenvm/ @lorc +/boards/arm64/xenvm/ @lorc @firscity /boards/arm64/fvp_baser_aemv8r/ @povergoing /boards/arm64/fvp_base_revc_2xaemv8a/ @carlocaione /boards/arm64/intel_socfpga_agilex_socdk/ @siclim @ngboonkhai @@ -343,6 +344,8 @@ /drivers/serial/serial_test.c @str4t0m /drivers/serial/*esp32c3* @uLipe /drivers/serial/*esp32s2* @glaubermaroto +/drivers/serial/Kconfig.xen @lorc @firscity +/drivers/serial/uart_hvc_xen.c @lorc @firscity /drivers/disk/ @jfischer-no /drivers/disk/sdmmc_sdhc.h @JunYangNXP /drivers/disk/sdmmc_spi.c @JunYangNXP @@ -389,6 +392,7 @@ /drivers/wifi/eswifi/ @loicpoulain @nandojve /drivers/wifi/winc1500/ @kludentwo /drivers/virtualization/ @tbursztyka +/drivers/xen/ @lorc @firscity /dts/arc/ @abrodkin @ruuddw @iriszzw @evgeniy-paltsev /dts/arm/acsip/ @NorthernDean /dts/arm/atmel/sam4e* @nandojve diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 9837eb9f81d..528d45b70c9 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -63,3 +63,4 @@ add_subdirectory_ifdef(CONFIG_BBRAM bbram) add_subdirectory_ifdef(CONFIG_FPGA fpga) add_subdirectory_ifdef(CONFIG_PINCTRL pinctrl) add_subdirectory_ifdef(CONFIG_MBOX mbox) +add_subdirectory_ifdef(CONFIG_BOARD_XENVM xen) diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index 5bfc1bf927a..576492a1e04 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -45,6 +45,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_RCAR uart_rcar.c) zephyr_library_sources_ifdef(CONFIG_UART_XEC uart_mchp_xec.c) zephyr_library_sources_ifdef(CONFIG_UART_NEORV32 uart_neorv32.c) zephyr_library_sources_ifdef(CONFIG_USART_GD32 usart_gd32.c) +zephyr_library_sources_ifdef(CONFIG_UART_XEN_HVC uart_hvc_xen.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE uart_handlers.c) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 475c17f2e88..569b7ed2f25 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -171,4 +171,6 @@ source "drivers/serial/Kconfig.test" source "drivers/serial/Kconfig.neorv32" +source "drivers/serial/Kconfig.xen" + endif # SERIAL diff --git a/drivers/serial/Kconfig.xen b/drivers/serial/Kconfig.xen new file mode 100644 index 00000000000..e95ddb7c458 --- /dev/null +++ b/drivers/serial/Kconfig.xen @@ -0,0 +1,30 @@ +# Xen hypervisor console via UART setup +# +# Copyright (c) 2021 EPAM Systems +# SPDX-License-Identifier: Apache-2.0 +# + +config UART_XEN_HVC + bool "Xen hypervisor console UART Driver" + select SERIAL_HAS_DRIVER + depends on BOARD_XENVM + default y + help + Enable Xen hypervisor console driver. + +config XEN_HVC_INIT_PRIORITY + int "Xen hypervisor console init priority" + depends on UART_XEN_HVC + default 55 + help + Set init priority for Xen HVC, should be inited before UART + console driver (HVC gets inited on PRE_KERNEL_1 stage). + +config XEN_EARLY_CONSOLEIO + bool "Early printk/stdout through console_io Xen interface" + depends on BOARD_XENVM + default n + help + Enable setting of console_io symbol hook for stdout and printk. + Log output will become available on PRE_KERNEL_1 stage. Requires + Xen, compiled with CONFIG_DEBUG flag. diff --git a/drivers/serial/uart_hvc_xen.c b/drivers/serial/uart_hvc_xen.c new file mode 100644 index 00000000000..9b0004bc792 --- /dev/null +++ b/drivers/serial/uart_hvc_xen.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2021 EPAM Systems + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(uart_hvc_xen); + +static struct hvc_xen_data hvc_data = {0}; + +static int read_from_ring(const struct device *dev, char *str, int len) +{ + int recv = 0; + struct hvc_xen_data *hvc_data = dev->data; + XENCONS_RING_IDX cons = hvc_data->intf->in_cons; + XENCONS_RING_IDX prod = hvc_data->intf->in_prod; + XENCONS_RING_IDX in_idx = 0; + + compiler_barrier(); + __ASSERT((prod - cons) <= sizeof(hvc_data->intf->in), + "Invalid input ring buffer"); + + while (cons != prod && recv < len) { + in_idx = MASK_XENCONS_IDX(cons, hvc_data->intf->in); + str[recv] = hvc_data->intf->in[in_idx]; + recv++; + cons++; + } + + compiler_barrier(); + hvc_data->intf->in_cons = cons; + + notify_evtchn(hvc_data->evtchn); + return recv; +} + +static int write_to_ring(const struct device *dev, const char *str, int len) +{ + int sent = 0; + struct hvc_xen_data *hvc_data = dev->data; + XENCONS_RING_IDX cons = hvc_data->intf->out_cons; + XENCONS_RING_IDX prod = hvc_data->intf->out_prod; + XENCONS_RING_IDX out_idx = 0; + + compiler_barrier(); + __ASSERT((prod - cons) <= sizeof(hvc_data->intf->out), + "Invalid output ring buffer"); + + while ((sent < len) && ((prod - cons) < sizeof(hvc_data->intf->out))) { + out_idx = MASK_XENCONS_IDX(prod, hvc_data->intf->out); + hvc_data->intf->out[out_idx] = str[sent]; + prod++; + sent++; + } + + compiler_barrier(); + hvc_data->intf->out_prod = prod; + + if (sent) { + notify_evtchn(hvc_data->evtchn); + } + + return sent; +} + +static int xen_hvc_poll_in(const struct device *dev, + unsigned char *c) +{ + int ret = 0; + char temp; + + ret = read_from_ring(dev, &temp, sizeof(temp)); + if (!ret) { + /* Char was not received */ + return -1; + } + + *c = temp; + return 0; +} + +static void xen_hvc_poll_out(const struct device *dev, + unsigned char c) +{ + /* Not a good solution (notifying HV every time), but needed for poll_out */ + (void) write_to_ring(dev, &c, sizeof(c)); +} + +static const struct uart_driver_api xen_hvc_api = { + .poll_in = xen_hvc_poll_in, + .poll_out = xen_hvc_poll_out, +}; + +int xen_console_init(const struct device *dev) +{ + int ret = 0; + uint64_t console_pfn = 0; + uintptr_t console_addr = 0; + struct hvc_xen_data *data = dev->data; + + data->dev = dev; + + ret = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &data->evtchn); + if (ret) { + LOG_ERR("%s: failed to get Xen console evtchn, ret = %d\n", + __func__, ret); + return ret; + } + + ret = hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &console_pfn); + if (ret) { + LOG_ERR("%s: failed to get Xen console PFN, ret = %d\n", + __func__, ret); + return ret; + } + + console_addr = (uintptr_t) (console_pfn << XEN_PAGE_SHIFT); + device_map(DEVICE_MMIO_RAM_PTR(dev), console_addr, XEN_PAGE_SIZE, + K_MEM_CACHE_WB); + + data->intf = (struct xencons_interface *) DEVICE_MMIO_GET(dev); + + LOG_INF("Xen HVC inited successfully\n"); + + return 0; +} + +DEVICE_DT_DEFINE(DT_NODELABEL(xen_hvc), xen_console_init, NULL, &hvc_data, + NULL, PRE_KERNEL_1, CONFIG_XEN_HVC_INIT_PRIORITY, + &xen_hvc_api); + +#ifdef CONFIG_XEN_EARLY_CONSOLEIO +extern void __printk_hook_install(int (*fn)(int)); +extern void __stdout_hook_install(int (*fn)(int)); + +int xen_consoleio_putc(int c) +{ + char symbol = (char) c; + + HYPERVISOR_console_io(CONSOLEIO_write, sizeof(symbol), &symbol); + return c; +} + + + +int consoleio_hooks_set(const struct device *dev) +{ + ARG_UNUSED(dev); + + /* Will be replaced with poll_in/poll_out by uart_console.c later on boot */ + __stdout_hook_install(xen_consoleio_putc); + __printk_hook_install(xen_consoleio_putc); + + return 0; +} + +SYS_INIT(consoleio_hooks_set, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +#endif /* CONFIG_XEN_EARLY_CONSOLEIO */ diff --git a/drivers/xen/CMakeLists.txt b/drivers/xen/CMakeLists.txt new file mode 100644 index 00000000000..2060ee25e15 --- /dev/null +++ b/drivers/xen/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2021 EPAM Systems + +zephyr_sources(hvm.c) +zephyr_sources(events.c) diff --git a/drivers/xen/events.c b/drivers/xen/events.c new file mode 100644 index 00000000000..897a2b89628 --- /dev/null +++ b/drivers/xen/events.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2021 EPAM Systems + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +void notify_evtchn(evtchn_port_t port) +{ + struct evtchn_send send; + + if (port >= EVTCHN_2L_NR_CHANNELS) { + printk("%s: trying to send notify for invalid evtchn #%u\n", + __func__, port); + return; + } + + send.port = port; + + HYPERVISOR_event_channel_op(EVTCHNOP_send, &send); +} diff --git a/drivers/xen/hvm.c b/drivers/xen/hvm.c new file mode 100644 index 00000000000..80895a84ef9 --- /dev/null +++ b/drivers/xen/hvm.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 EPAM Systems + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include + +int hvm_set_parameter(int idx, uint64_t value) +{ + struct xen_hvm_param xhv; + + xhv.domid = DOMID_SELF; + xhv.index = idx; + xhv.value = value; + + return HYPERVISOR_hvm_op(HVMOP_set_param, &xhv); +} + +int hvm_get_parameter(int idx, uint64_t *value) +{ + int ret = 0; + struct xen_hvm_param xhv; + + xhv.domid = DOMID_SELF; + xhv.index = idx; + + ret = HYPERVISOR_hvm_op(HVMOP_get_param, &xhv); + if (ret < 0) + return ret; + + *value = xhv.value; + return ret; +} diff --git a/include/xen/console.h b/include/xen/console.h new file mode 100644 index 00000000000..2e617b04d1d --- /dev/null +++ b/include/xen/console.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021 EPAM Systems + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef __XEN_CONSOLE_H__ +#define __XEN_CONSOLE_H__ + +#include +#include +#include +#include + +struct hvc_xen_data { + DEVICE_MMIO_RAM; /* should be first */ + const struct device *dev; + struct xencons_interface *intf; + uint64_t evtchn; +}; + +int xen_console_init(const struct device *dev); + +#endif /* __XEN_CONSOLE_H__ */ diff --git a/include/xen/events.h b/include/xen/events.h new file mode 100644 index 00000000000..eee0ff0e8fb --- /dev/null +++ b/include/xen/events.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2021 EPAM Systems + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef __XEN_EVENTS_H__ +#define __XEN_EVENTS_H__ + +#include + +void notify_evtchn(evtchn_port_t port); + +#endif /* __XEN_EVENTS_H__ */ diff --git a/include/xen/generic.h b/include/xen/generic.h new file mode 100644 index 00000000000..c1123a73278 --- /dev/null +++ b/include/xen/generic.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2021 EPAM Systems + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef __XEN_GENERIC_H__ +#define __XEN_GENERIC_H__ + +#include + +#define XEN_PAGE_SIZE 4096 +#define XEN_PAGE_SHIFT 12 + +#endif /* __XEN_GENERIC_H__ */ diff --git a/include/xen/hvm.h b/include/xen/hvm.h new file mode 100644 index 00000000000..1bd770ba1df --- /dev/null +++ b/include/xen/hvm.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2021 EPAM Systems + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef __XEN_HVM_H__ +#define __XEN_HVM_H__ + +#include +#include + +#include + +int hvm_set_parameter(int idx, uint64_t value); +int hvm_get_parameter(int idx, uint64_t *value); + +#endif /* __XEN_HVM_H__ */