Skip to content

Commit e249cfa

Browse files
committed
xenvm: drivers: serial: Implement serial interface to Xen PV console
This commit adds minimal support of Xen hypervisor console via UART-like driver. Implementation allows to use poll_in/poll_out char interface for uart_console.c driver directly to HV console instead of using Xen virtual PL011 UART. Future implementation will support interrupt driven interface on Xen event channels, currently it is under development. Also this commit introduces early console_io Xen interface, which allows to receive printk/stdout messages quickly after start, but requires Xen, built with CONFIG_DEBUG option. Signed-off-by: Dmytro Firsov <[email protected]>
1 parent 45c2542 commit e249cfa

File tree

13 files changed

+348
-2
lines changed

13 files changed

+348
-2
lines changed

CODEOWNERS

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
/arch/arm/core/aarch32/cortex_a_r/ @MaureenHelm @galak @ioannisg @bbolen @stephanosio
2525
/arch/arm64/ @carlocaione
2626
/arch/arm64/core/cortex_r/ @povergoing
27+
/arch/arm64/core/xen/ @lorc @firscity
2728
/arch/common/ @ioannisg @andyross
2829
/soc/arc/snps_*/ @abrodkin @ruuddw @evgeniy-paltsev
2930
/soc/nios2/ @nashif
@@ -59,7 +60,7 @@
5960
/soc/arm64/qemu_cortex_a53/ @carlocaione
6061
/soc/arm64/bcm_vk/ @abhishek-brcm
6162
/soc/arm64/nxp_layerscape/ @JiafeiPan
62-
/soc/arm64/xenvm/ @lorc
63+
/soc/arm64/xenvm/ @lorc @firscity
6364
/soc/arm64/arm/ @povergoing
6465
/soc/arm64/arm/fvp_aemv8a/ @carlocaione
6566
/arch/x86/ @jhedberg @nashif @jenmwms @aasthagr
@@ -161,7 +162,7 @@
161162
/boards/arm64/qemu_cortex_a53/ @carlocaione
162163
/boards/arm64/bcm958402m2_a72/ @abhishek-brcm
163164
/boards/arm64/nxp_ls1046ardb/ @JiafeiPan
164-
/boards/arm64/xenvm/ @lorc
165+
/boards/arm64/xenvm/ @lorc @firscity
165166
/boards/arm64/fvp_baser_aemv8r/ @povergoing
166167
/boards/arm64/fvp_base_revc_2xaemv8a/ @carlocaione
167168
# All cmake related files
@@ -330,6 +331,8 @@
330331
/drivers/serial/serial_test.c @str4t0m
331332
/drivers/serial/*esp32c3* @uLipe
332333
/drivers/serial/*esp32s2* @glaubermaroto
334+
/drivers/serial/Kconfig.xen @lorc @firscity
335+
/drivers/serial/uart_hvc_xen.c @lorc @firscity
333336
/drivers/disk/ @jfischer-no
334337
/drivers/disk/sdmmc_sdhc.h @JunYangNXP
335338
/drivers/disk/sdmmc_spi.c @JunYangNXP
@@ -375,6 +378,7 @@
375378
/drivers/wifi/eswifi/ @loicpoulain @nandojve
376379
/drivers/wifi/winc1500/ @kludentwo
377380
/drivers/virtualization/ @tbursztyka
381+
/drivers/xen/ @lorc @firscity
378382
/dts/arc/ @abrodkin @ruuddw @iriszzw @evgeniy-paltsev
379383
/dts/arm/acsip/ @NorthernDean
380384
/dts/arm/atmel/sam4e* @nandojve

drivers/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,4 @@ add_subdirectory_ifdef(CONFIG_CACHE_MANAGEMENT cache)
6161
add_subdirectory_ifdef(CONFIG_SYSCON syscon)
6262
add_subdirectory_ifdef(CONFIG_BBRAM bbram)
6363
add_subdirectory_ifdef(CONFIG_FPGA fpga)
64+
add_subdirectory_ifdef(CONFIG_BOARD_XENVM xen)

drivers/serial/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_APBUART uart_apbuart.c)
4343
zephyr_library_sources_ifdef(CONFIG_USB_CDC_ACM ${ZEPHYR_BASE}/misc/empty_file.c)
4444
zephyr_library_sources_ifdef(CONFIG_UART_RCAR uart_rcar.c)
4545
zephyr_library_sources_ifdef(CONFIG_UART_XEC uart_mchp_xec.c)
46+
zephyr_library_sources_ifdef(CONFIG_UART_XEN_HVC uart_hvc_xen.c)
4647

4748
zephyr_library_sources_ifdef(CONFIG_USERSPACE uart_handlers.c)
4849

drivers/serial/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,4 +161,6 @@ source "drivers/serial/Kconfig.xec"
161161

162162
source "drivers/serial/Kconfig.test"
163163

164+
source "drivers/serial/Kconfig.xen"
165+
164166
endif # SERIAL

drivers/serial/Kconfig.xen

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Xen hypervisor console via UART setup
2+
#
3+
# Copyright (c) 2021 EPAM Systems
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
7+
config UART_XEN_HVC
8+
bool "Xen hypervisor console UART Driver"
9+
select SERIAL_HAS_DRIVER
10+
depends on BOARD_XENVM
11+
default y
12+
help
13+
Enable Xen hypervisor console driver.
14+
15+
config XEN_HVC_INIT_PRIORITY
16+
int "Xen hypervisor console init priority"
17+
depends on UART_XEN_HVC
18+
default 55
19+
help
20+
Set init priority for Xen HVC, should be inited before UART
21+
console driver (HVC gets inited on PRE_KERNEL_1 stage).
22+
23+
config XEN_EARLY_CONSOLEIO
24+
bool "Early printk/stdout through console_io Xen interface"
25+
depends on BOARD_XENVM
26+
default n
27+
help
28+
Enable setting of console_io symbol hook for stdout and printk.
29+
Log output will become available on PRE_KERNEL_1 stage. Requires
30+
Xen, compiled with CONFIG_DEBUG flag.

drivers/serial/uart_hvc_xen.c

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
/*
2+
* Copyright (c) 2021 EPAM Systems
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <arch/arm64/hypercall.h>
8+
#include <xen/console.h>
9+
#include <xen/events.h>
10+
#include <xen/generic.h>
11+
#include <xen/hvm.h>
12+
#include <xen/public/io/console.h>
13+
#include <xen/public/xen.h>
14+
15+
#include <device.h>
16+
#include <init.h>
17+
#include <kernel.h>
18+
#include <logging/log.h>
19+
#include <sys/device_mmio.h>
20+
21+
LOG_MODULE_REGISTER(uart_hvc_xen);
22+
23+
static struct hvc_xen_data hvc_data = {0};
24+
25+
static int read_from_ring(const struct device *dev, char *str, int len)
26+
{
27+
int recv = 0;
28+
struct hvc_xen_data *hvc_data = dev->data;
29+
XENCONS_RING_IDX cons = hvc_data->intf->in_cons;
30+
XENCONS_RING_IDX prod = hvc_data->intf->in_prod;
31+
XENCONS_RING_IDX in_idx = 0;
32+
33+
compiler_barrier();
34+
__ASSERT((prod - cons) <= sizeof(hvc_data->intf->in),
35+
"Invalid input ring buffer");
36+
37+
while (cons != prod && recv < len) {
38+
in_idx = MASK_XENCONS_IDX(cons, hvc_data->intf->in);
39+
str[recv] = hvc_data->intf->in[in_idx];
40+
recv++;
41+
cons++;
42+
}
43+
44+
compiler_barrier();
45+
hvc_data->intf->in_cons = cons;
46+
47+
notify_evtchn(hvc_data->evtchn);
48+
return recv;
49+
}
50+
51+
static int write_to_ring(const struct device *dev, const char *str, int len)
52+
{
53+
int sent = 0;
54+
struct hvc_xen_data *hvc_data = dev->data;
55+
XENCONS_RING_IDX cons = hvc_data->intf->out_cons;
56+
XENCONS_RING_IDX prod = hvc_data->intf->out_prod;
57+
XENCONS_RING_IDX out_idx = 0;
58+
59+
compiler_barrier();
60+
__ASSERT((prod - cons) <= sizeof(hvc_data->intf->out),
61+
"Invalid output ring buffer");
62+
63+
while ((sent < len) && ((prod - cons) < sizeof(hvc_data->intf->out))) {
64+
out_idx = MASK_XENCONS_IDX(prod, hvc_data->intf->out);
65+
hvc_data->intf->out[out_idx] = str[sent];
66+
prod++;
67+
sent++;
68+
}
69+
70+
compiler_barrier();
71+
hvc_data->intf->out_prod = prod;
72+
73+
if (sent) {
74+
notify_evtchn(hvc_data->evtchn);
75+
}
76+
77+
return sent;
78+
}
79+
80+
static int xen_hvc_poll_in(const struct device *dev,
81+
unsigned char *c)
82+
{
83+
int ret = 0;
84+
char temp;
85+
86+
ret = read_from_ring(dev, &temp, sizeof(temp));
87+
if (!ret) {
88+
/* Char was not received */
89+
return -1;
90+
}
91+
92+
*c = temp;
93+
return 0;
94+
}
95+
96+
static void xen_hvc_poll_out(const struct device *dev,
97+
unsigned char c)
98+
{
99+
/* Not a good solution (notifying HV every time), but needed for poll_out */
100+
(void) write_to_ring(dev, &c, sizeof(c));
101+
}
102+
103+
static const struct uart_driver_api xen_hvc_api = {
104+
.poll_in = xen_hvc_poll_in,
105+
.poll_out = xen_hvc_poll_out,
106+
};
107+
108+
int xen_console_init(const struct device *dev)
109+
{
110+
int ret = 0;
111+
uint64_t console_pfn = 0;
112+
uintptr_t console_addr = 0;
113+
struct hvc_xen_data *data = dev->data;
114+
115+
data->dev = dev;
116+
117+
ret = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &data->evtchn);
118+
if (ret) {
119+
LOG_ERR("%s: failed to get Xen console evtchn, ret = %d\n",
120+
__func__, ret);
121+
return ret;
122+
}
123+
124+
ret = hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &console_pfn);
125+
if (ret) {
126+
LOG_ERR("%s: failed to get Xen console PFN, ret = %d\n",
127+
__func__, ret);
128+
return ret;
129+
}
130+
131+
console_addr = (uintptr_t) (console_pfn << XEN_PAGE_SHIFT);
132+
device_map(DEVICE_MMIO_RAM_PTR(dev), console_addr, XEN_PAGE_SIZE,
133+
K_MEM_CACHE_WB);
134+
135+
data->intf = (struct xencons_interface *) DEVICE_MMIO_GET(dev);
136+
137+
LOG_INF("Xen HVC inited successfully\n");
138+
139+
return 0;
140+
}
141+
142+
DEVICE_DT_DEFINE(DT_NODELABEL(xen_hvc), xen_console_init, NULL, &hvc_data,
143+
NULL, PRE_KERNEL_1, CONFIG_XEN_HVC_INIT_PRIORITY,
144+
&xen_hvc_api);
145+
146+
#ifdef CONFIG_XEN_EARLY_CONSOLEIO
147+
extern void __printk_hook_install(int (*fn)(int));
148+
extern void __stdout_hook_install(int (*fn)(int));
149+
150+
int xen_consoleio_putc(int c)
151+
{
152+
char symbol = (char) c;
153+
154+
HYPERVISOR_console_io(CONSOLEIO_write, sizeof(symbol), &symbol);
155+
return c;
156+
}
157+
158+
159+
160+
int consoleio_hooks_set(const struct device *dev)
161+
{
162+
ARG_UNUSED(dev);
163+
164+
/* Will be replaced with poll_in/poll_out by uart_console.c later on boot */
165+
__stdout_hook_install(xen_consoleio_putc);
166+
__printk_hook_install(xen_consoleio_putc);
167+
168+
return 0;
169+
}
170+
171+
SYS_INIT(consoleio_hooks_set, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
172+
#endif /* CONFIG_XEN_EARLY_CONSOLEIO */

drivers/xen/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
# Copyright (c) 2021 EPAM Systems
3+
4+
zephyr_sources(hvm.c)
5+
zephyr_sources(events.c)

drivers/xen/events.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright (c) 2021 EPAM Systems
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <arch/arm64/hypercall.h>
8+
#include <xen/public/xen.h>
9+
#include <xen/public/event_channel.h>
10+
#include <xen/events.h>
11+
12+
void notify_evtchn(evtchn_port_t port)
13+
{
14+
struct evtchn_send send;
15+
16+
if (port >= EVTCHN_2L_NR_CHANNELS) {
17+
printk("%s: trying to send notify for invalid evtchn #%u\n",
18+
__func__, port);
19+
return;
20+
}
21+
22+
send.port = port;
23+
24+
HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
25+
}

drivers/xen/hvm.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright (c) 2021 EPAM Systems
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <arch/arm64/hypercall.h>
8+
#include <xen/hvm.h>
9+
#include <xen/public/hvm/hvm_op.h>
10+
#include <xen/public/hvm/params.h>
11+
12+
#include <kernel.h>
13+
14+
int hvm_set_parameter(int idx, uint64_t value)
15+
{
16+
struct xen_hvm_param xhv;
17+
18+
xhv.domid = DOMID_SELF;
19+
xhv.index = idx;
20+
xhv.value = value;
21+
22+
return HYPERVISOR_hvm_op(HVMOP_set_param, &xhv);
23+
}
24+
25+
int hvm_get_parameter(int idx, uint64_t *value)
26+
{
27+
int ret = 0;
28+
struct xen_hvm_param xhv;
29+
30+
xhv.domid = DOMID_SELF;
31+
xhv.index = idx;
32+
33+
ret = HYPERVISOR_hvm_op(HVMOP_get_param, &xhv);
34+
if (ret < 0)
35+
return ret;
36+
37+
*value = xhv.value;
38+
return ret;
39+
}

include/xen/console.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright (c) 2021 EPAM Systems
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#ifndef __XEN_CONSOLE_H__
7+
#define __XEN_CONSOLE_H__
8+
9+
#include <init.h>
10+
#include <device.h>
11+
#include <drivers/uart.h>
12+
#include <sys/device_mmio.h>
13+
14+
struct hvc_xen_data {
15+
DEVICE_MMIO_RAM; /* should be first */
16+
const struct device *dev;
17+
struct xencons_interface *intf;
18+
uint64_t evtchn;
19+
};
20+
21+
int xen_console_init(const struct device *dev);
22+
23+
#endif /* __XEN_CONSOLE_H__ */

0 commit comments

Comments
 (0)