From 899fb1af16c201a1e25f008125b4578fa4d91fb4 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Mon, 30 Nov 2020 12:46:57 +0100 Subject: [PATCH] drivers/virtualization: Add a shell module for the ivshmem driver This easily permits to test ivshmem and basic functionality of a custom protocol passing through. Signed-off-by: Tomasz Bursztyka --- drivers/virtualization/CMakeLists.txt | 1 + drivers/virtualization/Kconfig | 7 + drivers/virtualization/virt_ivshmem_shell.c | 228 ++++++++++++++++++++ 3 files changed, 236 insertions(+) create mode 100644 drivers/virtualization/virt_ivshmem_shell.c diff --git a/drivers/virtualization/CMakeLists.txt b/drivers/virtualization/CMakeLists.txt index 78bfc3d3948..9d2ed4e82c2 100644 --- a/drivers/virtualization/CMakeLists.txt +++ b/drivers/virtualization/CMakeLists.txt @@ -3,3 +3,4 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_IVSHMEM virt_ivshmem.c) +zephyr_library_sources_ifdef(CONFIG_IVSHMEM_SHELL virt_ivshmem_shell.c) diff --git a/drivers/virtualization/Kconfig b/drivers/virtualization/Kconfig index 4783d8d3c50..8b4ceb8ff0e 100644 --- a/drivers/virtualization/Kconfig +++ b/drivers/virtualization/Kconfig @@ -54,6 +54,13 @@ config IVSHMEM_INT_PRIORITY help Interrupt priority used for the MSI-X generated interrupts. +config IVSHMEM_SHELL + bool "Enable IVshmem shell module" + depends on SHELL + help + This is mostly a module to help getting info the ivshmem and/or + quickly testing your ivshmem client application (from another VM). + endif # IVSHMEM endif # VIRTUALIZATION diff --git a/drivers/virtualization/virt_ivshmem_shell.c b/drivers/virtualization/virt_ivshmem_shell.c new file mode 100644 index 00000000000..c5f5d219f97 --- /dev/null +++ b/drivers/virtualization/virt_ivshmem_shell.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +static const struct device *ivshmem; + +#ifdef CONFIG_IVSHMEM_DOORBELL + +#define STACK_SIZE 512 +static struct k_poll_signal doorbell_sig = + K_POLL_SIGNAL_INITIALIZER(doorbell_sig); +static struct k_poll_event doorbell_evt = + K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL, + K_POLL_MODE_NOTIFY_ONLY, + &doorbell_sig); +K_THREAD_STACK_DEFINE(doorbell_stack, STACK_SIZE); +static bool doorbell_started; +static struct k_thread doorbell_thread; + +static void doorbell_notification_thread(const struct shell *shell) +{ + while (1) { + unsigned int signaled; + int vector; + + k_poll(&doorbell_evt, 1, K_FOREVER); + + k_poll_signal_check(&doorbell_sig, &signaled, &vector); + if (signaled == 0) { + continue; + } + + shell_fprintf(shell, SHELL_NORMAL, + "Received a notification on vector %u\n", + (unsigned int)vector); + + k_poll_signal_init(&doorbell_sig); + } +} + +#endif /* CONFIG_IVSHMEM_DOORBELL */ + +static bool get_ivshmem(const struct shell *shell) +{ + if (ivshmem == NULL) { + ivshmem = device_get_binding(CONFIG_IVSHMEM_DEV_NAME); + if (!ivshmem) { + shell_error(shell, "IVshmem device cannot be found"); + } + } + + return ivshmem != NULL ? true : false; +} + +static int cmd_ivshmem_shmem(const struct shell *shell, + size_t argc, char **argv) +{ + uintptr_t mem; + size_t size; + uint32_t id; + uint16_t vectors; + + if (!get_ivshmem(shell)) { + return 0; + } + + size = ivshmem_get_mem(ivshmem, &mem); + id = ivshmem_get_id(ivshmem); + vectors = ivshmem_get_vectors(ivshmem); + + shell_fprintf(shell, SHELL_NORMAL, + "IVshmem up and running: \n" + "\tShared memory: 0x%x of size %u bytes\n" + "\tPeer id: %u\n" + "\tNotification vectors: %u\n", + mem, size, id, vectors); + + return 0; +} + +static int cmd_ivshmem_dump(const struct shell *shell, + size_t argc, char **argv) +{ + uintptr_t dump_pos; + size_t dump_size; + uintptr_t mem; + size_t size; + + if (!get_ivshmem(shell)) { + return 0; + } + + dump_pos = strtol(argv[1], NULL, 10); + dump_size = strtol(argv[2], NULL, 10); + + size = ivshmem_get_mem(ivshmem, &mem); + + if (dump_size > size) { + shell_error(shell, "Size is too big"); + } else if (dump_pos > size) { + shell_error(shell, "Position is out of the shared memory"); + } else if ((mem + dump_pos + dump_size) > (mem + size)) { + shell_error(shell, "Position and size overflow"); + } else { + shell_hexdump(shell, (const uint8_t *)mem+dump_pos, dump_size); + } + + return 0; +} + +static int cmd_ivshmem_int(const struct shell *shell, + size_t argc, char **argv) +{ + int peer_id; + int vector; + int ret; + + if (!IS_ENABLED(CONFIG_IVSHMEM_DOORBELL)) { + shell_error(shell, "CONFIG_IVSHMEM_DOORBELL is not enabled"); + return 0; + } + + if (!get_ivshmem(shell)) { + return 0; + } + + peer_id = strtol(argv[1], NULL, 10); + vector = strtol(argv[2], NULL, 10); + + ret = ivshmem_int_peer(ivshmem, (uint16_t)peer_id, (uint16_t)vector); + if (ret != 0) { + shell_error(shell, + "Could not notify peer %u on %u. status %d", + peer_id, vector, ret); + return -EIO; + } + + shell_fprintf(shell, SHELL_NORMAL, + "Notification sent to peer %u on vector %u\n", + peer_id, vector); + + return 0; +} + +static int cmd_ivshmem_get_notified(const struct shell *shell, + size_t argc, char **argv) +{ +#ifdef CONFIG_IVSHMEM_DOORBELL + int vector; + + if (!get_ivshmem(shell)) { + return 0; + } + + vector = strtol(argv[1], NULL, 10); + + if (ivshmem_register_handler(ivshmem, &doorbell_sig, + (uint16_t)vector)) { + shell_error(shell, "Could not get notifications on vector %u", + vector); + return -EIO; + } + + shell_fprintf(shell, SHELL_NORMAL, + "Notifications enabled for vector %u\n", vector); + + if (!doorbell_started) { + k_tid_t tid; + + tid = k_thread_create( + &doorbell_thread, + doorbell_stack, STACK_SIZE, + (k_thread_entry_t)doorbell_notification_thread, + (void *)shell, NULL, NULL, + K_PRIO_COOP(2), 0, K_NO_WAIT); + if (!tid) { + shell_error(shell, "Cannot start notification thread"); + return -ENOEXEC; + } + + k_thread_name_set(tid, "notification_thread"); + + k_thread_start(tid); + + doorbell_started = true; + } +#else + shell_error(shell, "CONFIG_IVSHMEM_DOORBELL is not enabled"); +#endif + return 0; +} + +SHELL_STATIC_SUBCMD_SET_CREATE(sub_ivshmem_cmds, + SHELL_CMD(shmem, NULL, + "Show shared memory info", + cmd_ivshmem_shmem), + SHELL_CMD_ARG(dump, NULL, + "Dump shared memory content", + cmd_ivshmem_dump, 3, 0), + SHELL_CMD_ARG(int_peer, NULL, + "Notify a vector on a peer", + cmd_ivshmem_int, 3, 0), + SHELL_CMD_ARG(get_notified, NULL, + "Get notification on vector", + cmd_ivshmem_get_notified, 2, 0), + SHELL_SUBCMD_SET_END + ); + +SHELL_CMD_REGISTER(ivshmem, &sub_ivshmem_cmds, + "IVshmem information", cmd_ivshmem_shmem); + +SHELL_CMD_ARG_REGISTER(ivshmem_dump, &sub_ivshmem_cmds, + "Dump shared memory content", + cmd_ivshmem_dump, 3, 0); + +SHELL_CMD_ARG_REGISTER(ivshmem_int, &sub_ivshmem_cmds, + "Notify a vector on an ivshmem peer", + cmd_ivshmem_int, 3, 0); + +SHELL_CMD_ARG_REGISTER(ivshmem_get_notified, &sub_ivshmem_cmds, + "Get notification on vector", + cmd_ivshmem_get_notified, 2, 0);