Gunyah is a Type-1 hypervisor independent of any high-level OS kernel,
and runs in a higher CPU privilege level. It does not depend on any
lower-privileged OS kernel/code for its core functionality. This
increases its security and can support a much smaller trusted computing
base than a Type-2 hypervisor. Gunyah is designed for isolated virtual
machine use cases and to support launching trusted+isolated virtual
machines from a relatively less trusted host virtual machine.
Gunyah is an open source hypervisor. The source repo is available at
https://github.com/quic/gunyah-hypervisor.
The diagram below shows the architecture for AArch64.
::
VM A VM B
+-----+ +-----+ | +-----+ +-----+ +-----+
| | | | | | | | | | |
EL0 | APP | | APP | | | APP | | APP | | APP |
| | | | | | | | | | |
+-----+ +-----+ | +-----+ +-----+ +-----+
---------------------|-------------------------
+--------------+ | +----------------------+
| | | | |
EL1 | Linux Kernel | | |Linux kernel/Other OS | ...
| | | | |
+--------------+ | +----------------------+
--------hvc/smc------|------hvc/smc------------
+----------------------------------------+
| |
EL2 | Gunyah Hypervisor |
| |
+----------------------------------------+
Gunyah provides these following features.
- Threads and Scheduling: The scheduler schedules virtual CPUs (VCPUs)
on physical CPUs and enables time-sharing of the CPUs.
- Memory Management: Gunyah tracks memory ownership and use of all
memory under its control. It provides low level dynamic memory
management APIs on top of which higher level donation, lending and sharing
is built. Gunyah provides strong VM memory isolation for trusted VMs.
- Interrupt Virtualization: Interrupts are managed by the hypervisor
and are routed directly to the assigned VM.
- Inter-VM Communication: There are several different mechanisms
provided for communicating between VMs.
- Device Virtualization: Para-virtualization of devices is supported
using inter-VM communication and virtio primitives. Low level architecture
features and devices such as cpu timers, interrupt controllers are supported
with hardware virtualization and emulation where required.
- Resource Manager: Gunyah supports a "root" VM that initially owns all
VM memory and IO resources. The Gunyah Resource Manager is the default
bundled root VM and provides high-level services including dynamic VM
management and secure memory donation, lending and sharing.
This series adds the basic framework for detecting that Linux is running
under Gunyah as a virtual machine, communication with the Gunyah
Resource Manager, and a sample virtual machine manager capable of
launching virtual machines.
Changes in v17:
- Replace RM's irq_chip with irq_create_fwspec_mapping
- Unmap lent memory from kernel logical map
- Small optimization to unlock folio earlier to allow vCPUs racing for
the same folio to run sooner
- Add missed "safe to lend" checks for a folio when constructing mem
parcel
Changes in v16:
https://lore.kernel.org/r/[email protected]
- Fleshed out memory reclaim while VM is running
- Documentation and comments
Changes in v15:
https://lore.kernel.org/r/[email protected]
- First implementation of virtual machines backed by guestmemfd and
using demand paging to provide memory instead of all up front.
- Use message queue hypercalls directly instead of traversing through
mailbox framework.
Changes in v14: https://lore.kernel.org/all/[email protected]/
- Coding/cosmetic tweaks suggested by Alex
- Mark IRQs as wake-up capable
Changes in v13:
https://lore.kernel.org/all/[email protected]/
- Tweaks to message queue driver to address race condition between IRQ
and mailbox registration
- Allow removal of VM functions by function-specific comparison --
specifically to allow
removing irqfd by label only and not requiring original FD to be
provided.
Changes in v12:
https://lore.kernel.org/all/[email protected]/
- Stylistic/cosmetic tweaks suggested by Alex
- Remove patch "virt: gunyah: Identify hypervisor version" and squash
the
check that we're running under a reasonable Gunyah hypervisor into RM
driver
- Refactor platform hooks into a separate module per suggestion from
Srini
- GFP_KERNEL_ACCOUNT and account_locked_vm() for page pinning
- enum-ify related constants
Changes in v11:
https://lore.kernel.org/all/[email protected]/
- Rename struct gh_vm_dtb_config:gpa -> guest_phys_addr & overflow
checks for this
- More docstrings throughout
- Make resp_buf and resp_buf_size optional
- Replace deprecated idr with xarray
- Refconting on misc device instead of RM's platform device
- Renaming variables, structs, etc. from gunyah_ -> gh_
- Drop removal of user mem regions
- Drop mem_lend functionality; to converge with restricted_memfd later
Changes in v10:
https://lore.kernel.org/all/[email protected]/
- Fix bisectability (end result of series is same, --fixups applied to
wrong commits)
- Convert GH_ERROR_* and GH_RM_ERROR_* to enums
- Correct race condition between allocating/freeing user memory
- Replace offsetof with struct_size
- Series-wide renaming of functions to be more consistent
- VM shutdown & restart support added in vCPU and VM Manager patches
- Convert VM function name (string) to type (number)
- Convert VM function argument to value (which could be a pointer) to
remove memory wastage for arguments
- Remove defensive checks of hypervisor correctness
- Clean ups to ioeventfd as suggested by Srivatsa
Changes in v9:
https://lore.kernel.org/all/[email protected]/
- Refactor Gunyah API flags to be exposed as feature flags at kernel
level
- Move mbox client cleanup into gunyah_msgq_remove()
- Simplify gh_rm_call return value and response payload
- Missing clean-up/error handling/little endian fixes as suggested by
Srivatsa and Alex in v8 series
Changes in v8:
https://lore.kernel.org/all/[email protected]/
- Treat VM manager as a library of RM
- Add patches 21-28 as RFC to support proxy-scheduled vCPUs and
necessary bits to support virtio
from Gunyah userspace
Changes in v7:
https://lore.kernel.org/all/[email protected]/
- Refactor to remove gunyah RM bus
- Refactor allow multiple RM device instances
- Bump UAPI to start at 0x0
- Refactor QCOM SCM's platform hooks to allow
CONFIG_QCOM_SCM=Y/CONFIG_GUNYAH=M combinations
Changes in v6:
https://lore.kernel.org/all/[email protected]/
- *Replace gunyah-console with gunyah VM Manager*
- Move include/asm-generic/gunyah.h into include/linux/gunyah.h
- s/gunyah_msgq/gh_msgq/
- Minor tweaks and documentation tidying based on comments from Jiri,
Greg, Arnd, Dmitry, and Bagas.
Changes in v5
https://lore.kernel.org/all/[email protected]/
- Dropped sysfs nodes
- Switch from aux bus to Gunyah RM bus for the subdevices
- Cleaning up RM console
Changes in v4:
https://lore.kernel.org/all/[email protected]/
- Tidied up documentation throughout based on questions/feedback received
- Switched message queue implementation to use mailboxes
- Renamed "gunyah_device" as "gunyah_resource"
Changes in v3:
https://lore.kernel.org/all/[email protected]/
- /Maintained/Supported/ in MAINTAINERS
- Tidied up documentation throughout based on questions/feedback received
- Moved hypercalls into arch/arm64/gunyah/; following hyper-v's implementation
- Drop opaque typedefs
- Move sysfs nodes under /sys/hypervisor/gunyah/
- Moved Gunyah console driver to drivers/tty/
- Reworked gh_device design to drop the Gunyah bus.
Changes in v2: https://lore.kernel.org/all/[email protected]/
- DT bindings clean up
- Switch hypercalls to follow SMCCC
v1: https://lore.kernel.org/all/[email protected]/
Signed-off-by: Elliot Berman <[email protected]>
---
Elliot Berman (35):
docs: gunyah: Introduce Gunyah Hypervisor
dt-bindings: Add binding for gunyah hypervisor
gunyah: Common types and error codes for Gunyah hypercalls
virt: gunyah: Add hypercalls to identify Gunyah
virt: gunyah: Add hypervisor driver
virt: gunyah: msgq: Add hypercalls to send and receive messages
gunyah: rsc_mgr: Add resource manager RPC core
gunyah: vm_mgr: Introduce basic VM Manager
gunyah: rsc_mgr: Add VM lifecycle RPC
gunyah: vm_mgr: Add VM start/stop
virt: gunyah: Translate gh_rm_hyp_resource into gunyah_resource
virt: gunyah: Add resource tickets
gunyah: vm_mgr: Add framework for VM Functions
virt: gunyah: Add hypercalls for running a vCPU
virt: gunyah: Add proxy-scheduled vCPUs
gunyah: Add hypercalls for demand paging
gunyah: rsc_mgr: Add memory parcel RPC
mm/interval_tree: Export iter_first/iter_next
arch/mm: Export direct {un,}map functions
virt: gunyah: Add interfaces to map memory into guest address space
gunyah: rsc_mgr: Add platform ops on mem_lend/mem_reclaim
virt: gunyah: Add Qualcomm Gunyah platform ops
virt: gunyah: Implement guestmemfd
virt: gunyah: Add ioctl to bind guestmem to VMs
virt: gunyah: guestmem: Initialize RM mem parcels from guestmem
virt: gunyah: Share guest VM dtb configuration to Gunyah
gunyah: rsc_mgr: Add RPC to enable demand paging
virt: gunyah: Enable demand paging
gunyah: rsc_mgr: Add RPC to set VM boot context
virt: gunyah: Allow userspace to initialize context of primary vCPU
virt: gunyah: Add hypercalls for sending doorbell
virt: gunyah: Add irqfd interface
virt: gunyah: Add IO handlers
virt: gunyah: Add ioeventfd
MAINTAINERS: Add Gunyah hypervisor drivers section
.../bindings/firmware/gunyah-hypervisor.yaml | 82 ++
Documentation/userspace-api/ioctl/ioctl-number.rst | 1 +
Documentation/virt/gunyah/index.rst | 135 +++
Documentation/virt/gunyah/message-queue.rst | 68 ++
Documentation/virt/index.rst | 1 +
MAINTAINERS | 12 +
arch/arm64/Kbuild | 1 +
arch/arm64/gunyah/Makefile | 3 +
arch/arm64/gunyah/gunyah_hypercall.c | 279 ++++++
arch/arm64/include/asm/gunyah.h | 57 ++
arch/arm64/mm/pageattr.c | 3 +
drivers/virt/Kconfig | 2 +
drivers/virt/Makefile | 1 +
drivers/virt/gunyah/Kconfig | 47 +
drivers/virt/gunyah/Makefile | 9 +
drivers/virt/gunyah/guest_memfd.c | 987 ++++++++++++++++++++
drivers/virt/gunyah/gunyah.c | 52 ++
drivers/virt/gunyah/gunyah_ioeventfd.c | 139 +++
drivers/virt/gunyah/gunyah_irqfd.c | 187 ++++
drivers/virt/gunyah/gunyah_platform_hooks.c | 117 +++
drivers/virt/gunyah/gunyah_qcom.c | 220 +++++
drivers/virt/gunyah/gunyah_vcpu.c | 590 ++++++++++++
drivers/virt/gunyah/rsc_mgr.c | 836 +++++++++++++++++
drivers/virt/gunyah/rsc_mgr.h | 144 +++
drivers/virt/gunyah/rsc_mgr_rpc.c | 602 +++++++++++++
drivers/virt/gunyah/vm_mgr.c | 993 +++++++++++++++++++++
drivers/virt/gunyah/vm_mgr.h | 215 +++++
drivers/virt/gunyah/vm_mgr_mem.c | 356 ++++++++
include/linux/gunyah.h | 483 ++++++++++
include/uapi/linux/gunyah.h | 378 ++++++++
mm/interval_tree.c | 3 +
31 files changed, 7003 insertions(+)
---
base-commit: ffd2cb6b718e189e7e2d5d0c19c25611f92e061a
change-id: 20231208-gunyah-952aca7668e0
Best regards,
--
Elliot Berman <[email protected]>
Add architecture-independent standard error codes, types, and macros for
Gunyah hypercalls.
Reviewed-by: Dmitry Baryshkov <[email protected]>
Reviewed-by: Srinivas Kandagatla <[email protected]>
Reviewed-by: Alex Elder <[email protected]>
Signed-off-by: Elliot Berman <[email protected]>
---
include/linux/gunyah.h | 106 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 106 insertions(+)
diff --git a/include/linux/gunyah.h b/include/linux/gunyah.h
new file mode 100644
index 0000000000000..1eab631a49b6d
--- /dev/null
+++ b/include/linux/gunyah.h
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _LINUX_GUNYAH_H
+#define _LINUX_GUNYAH_H
+
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/limits.h>
+
+/* Matches resource manager's resource types for VM_GET_HYP_RESOURCES RPC */
+enum gunyah_resource_type {
+ /* clang-format off */
+ GUNYAH_RESOURCE_TYPE_BELL_TX = 0,
+ GUNYAH_RESOURCE_TYPE_BELL_RX = 1,
+ GUNYAH_RESOURCE_TYPE_MSGQ_TX = 2,
+ GUNYAH_RESOURCE_TYPE_MSGQ_RX = 3,
+ GUNYAH_RESOURCE_TYPE_VCPU = 4,
+ GUNYAH_RESOURCE_TYPE_MEM_EXTENT = 9,
+ GUNYAH_RESOURCE_TYPE_ADDR_SPACE = 10,
+ /* clang-format on */
+};
+
+struct gunyah_resource {
+ enum gunyah_resource_type type;
+ u64 capid;
+ unsigned int irq;
+};
+
+/******************************************************************************/
+/* Common arch-independent definitions for Gunyah hypercalls */
+#define GUNYAH_CAPID_INVAL U64_MAX
+#define GUNYAH_VMID_ROOT_VM 0xff
+
+enum gunyah_error {
+ /* clang-format off */
+ GUNYAH_ERROR_OK = 0,
+ GUNYAH_ERROR_UNIMPLEMENTED = -1,
+ GUNYAH_ERROR_RETRY = -2,
+
+ GUNYAH_ERROR_ARG_INVAL = 1,
+ GUNYAH_ERROR_ARG_SIZE = 2,
+ GUNYAH_ERROR_ARG_ALIGN = 3,
+
+ GUNYAH_ERROR_NOMEM = 10,
+
+ GUNYAH_ERROR_ADDR_OVFL = 20,
+ GUNYAH_ERROR_ADDR_UNFL = 21,
+ GUNYAH_ERROR_ADDR_INVAL = 22,
+
+ GUNYAH_ERROR_DENIED = 30,
+ GUNYAH_ERROR_BUSY = 31,
+ GUNYAH_ERROR_IDLE = 32,
+
+ GUNYAH_ERROR_IRQ_BOUND = 40,
+ GUNYAH_ERROR_IRQ_UNBOUND = 41,
+
+ GUNYAH_ERROR_CSPACE_CAP_NULL = 50,
+ GUNYAH_ERROR_CSPACE_CAP_REVOKED = 51,
+ GUNYAH_ERROR_CSPACE_WRONG_OBJ_TYPE = 52,
+ GUNYAH_ERROR_CSPACE_INSUF_RIGHTS = 53,
+ GUNYAH_ERROR_CSPACE_FULL = 54,
+
+ GUNYAH_ERROR_MSGQUEUE_EMPTY = 60,
+ GUNYAH_ERROR_MSGQUEUE_FULL = 61,
+ /* clang-format on */
+};
+
+/**
+ * gunyah_error_remap() - Remap Gunyah hypervisor errors into a Linux error code
+ * @gunyah_error: Gunyah hypercall return value
+ */
+static inline int gunyah_error_remap(enum gunyah_error gunyah_error)
+{
+ switch (gunyah_error) {
+ case GUNYAH_ERROR_OK:
+ return 0;
+ case GUNYAH_ERROR_NOMEM:
+ return -ENOMEM;
+ case GUNYAH_ERROR_DENIED:
+ case GUNYAH_ERROR_CSPACE_CAP_NULL:
+ case GUNYAH_ERROR_CSPACE_CAP_REVOKED:
+ case GUNYAH_ERROR_CSPACE_WRONG_OBJ_TYPE:
+ case GUNYAH_ERROR_CSPACE_INSUF_RIGHTS:
+ return -EACCES;
+ case GUNYAH_ERROR_CSPACE_FULL:
+ case GUNYAH_ERROR_BUSY:
+ case GUNYAH_ERROR_IDLE:
+ return -EBUSY;
+ case GUNYAH_ERROR_IRQ_BOUND:
+ case GUNYAH_ERROR_IRQ_UNBOUND:
+ case GUNYAH_ERROR_MSGQUEUE_FULL:
+ case GUNYAH_ERROR_MSGQUEUE_EMPTY:
+ return -EIO;
+ case GUNYAH_ERROR_UNIMPLEMENTED:
+ return -EOPNOTSUPP;
+ case GUNYAH_ERROR_RETRY:
+ return -EAGAIN;
+ default:
+ return -EINVAL;
+ }
+}
+
+#endif
--
2.34.1
Add hypercalls to send and receive messages on a Gunyah message queue.
Reviewed-by: Alex Elder <[email protected]>
Reviewed-by: Srinivas Kandagatla <[email protected]>
Signed-off-by: Elliot Berman <[email protected]>
---
arch/arm64/gunyah/gunyah_hypercall.c | 55 ++++++++++++++++++++++++++++++++++++
include/linux/gunyah.h | 8 ++++++
2 files changed, 63 insertions(+)
diff --git a/arch/arm64/gunyah/gunyah_hypercall.c b/arch/arm64/gunyah/gunyah_hypercall.c
index d44663334f381..1302e128be6e9 100644
--- a/arch/arm64/gunyah/gunyah_hypercall.c
+++ b/arch/arm64/gunyah/gunyah_hypercall.c
@@ -37,6 +37,8 @@ EXPORT_SYMBOL_GPL(arch_is_gunyah_guest);
/* clang-format off */
#define GUNYAH_HYPERCALL_HYP_IDENTIFY GUNYAH_HYPERCALL(0x8000)
+#define GUNYAH_HYPERCALL_MSGQ_SEND GUNYAH_HYPERCALL(0x801B)
+#define GUNYAH_HYPERCALL_MSGQ_RECV GUNYAH_HYPERCALL(0x801C)
/* clang-format on */
/**
@@ -58,5 +60,58 @@ void gunyah_hypercall_hyp_identify(
}
EXPORT_SYMBOL_GPL(gunyah_hypercall_hyp_identify);
+/**
+ * gunyah_hypercall_msgq_send() - Send a buffer on a message queue
+ * @capid: capability ID of the message queue to add message
+ * @size: Size of @buff
+ * @buff: Address of buffer to send
+ * @tx_flags: See GUNYAH_HYPERCALL_MSGQ_TX_FLAGS_*
+ * @ready: If the send was successful, ready is filled with true if more
+ * messages can be sent on the queue. If false, then the tx IRQ will
+ * be raised in future when send can succeed.
+ */
+enum gunyah_error gunyah_hypercall_msgq_send(u64 capid, size_t size, void *buff,
+ u64 tx_flags, bool *ready)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_1_1_hvc(GUNYAH_HYPERCALL_MSGQ_SEND, capid, size,
+ (uintptr_t)buff, tx_flags, 0, &res);
+
+ if (res.a0 == GUNYAH_ERROR_OK)
+ *ready = !!res.a1;
+
+ return res.a0;
+}
+EXPORT_SYMBOL_GPL(gunyah_hypercall_msgq_send);
+
+/**
+ * gunyah_hypercall_msgq_recv() - Send a buffer on a message queue
+ * @capid: capability ID of the message queue to add message
+ * @buff: Address of buffer to copy received data into
+ * @size: Size of @buff
+ * @recv_size: If the receive was successful, recv_size is filled with the
+ * size of data received. Will be <= size.
+ * @ready: If the receive was successful, ready is filled with true if more
+ * messages are ready to be received on the queue. If false, then the
+ * rx IRQ will be raised in future when recv can succeed.
+ */
+enum gunyah_error gunyah_hypercall_msgq_recv(u64 capid, void *buff, size_t size,
+ size_t *recv_size, bool *ready)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_1_1_hvc(GUNYAH_HYPERCALL_MSGQ_RECV, capid, (uintptr_t)buff,
+ size, 0, &res);
+
+ if (res.a0 == GUNYAH_ERROR_OK) {
+ *recv_size = res.a1;
+ *ready = !!res.a2;
+ }
+
+ return res.a0;
+}
+EXPORT_SYMBOL_GPL(gunyah_hypercall_msgq_recv);
+
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Gunyah Hypervisor Hypercalls");
diff --git a/include/linux/gunyah.h b/include/linux/gunyah.h
index 33bcbd22d39f7..acd70f9824253 100644
--- a/include/linux/gunyah.h
+++ b/include/linux/gunyah.h
@@ -141,4 +141,12 @@ gunyah_api_version(const struct gunyah_hypercall_hyp_identify_resp *gunyah_api)
void gunyah_hypercall_hyp_identify(
struct gunyah_hypercall_hyp_identify_resp *hyp_identity);
+/* Immediately raise RX vIRQ on receiver VM */
+#define GUNYAH_HYPERCALL_MSGQ_TX_FLAGS_PUSH BIT(0)
+
+enum gunyah_error gunyah_hypercall_msgq_send(u64 capid, size_t size, void *buff,
+ u64 tx_flags, bool *ready);
+enum gunyah_error gunyah_hypercall_msgq_recv(u64 capid, void *buff, size_t size,
+ size_t *recv_size, bool *ready);
+
#endif
--
2.34.1
Add hypercalls to identify when Linux is running in a virtual machine
under Gunyah.
There are two calls to help identify Gunyah:
1. gh_hypercall_get_uid() returns a UID when running under a Gunyah
hypervisor.
2. gh_hypercall_hyp_identify() returns build information and a set of
feature flags that are supported by Gunyah.
Reviewed-by: Srinivas Kandagatla <[email protected]>
Reviewed-by: Alex Elder <[email protected]>
Signed-off-by: Elliot Berman <[email protected]>
---
arch/arm64/Kbuild | 1 +
arch/arm64/gunyah/Makefile | 3 ++
arch/arm64/gunyah/gunyah_hypercall.c | 62 ++++++++++++++++++++++++++++++++++++
drivers/virt/Kconfig | 2 ++
drivers/virt/gunyah/Kconfig | 12 +++++++
include/linux/gunyah.h | 38 ++++++++++++++++++++++
6 files changed, 118 insertions(+)
diff --git a/arch/arm64/Kbuild b/arch/arm64/Kbuild
index 5bfbf7d79c99b..e4847ba0e3c95 100644
--- a/arch/arm64/Kbuild
+++ b/arch/arm64/Kbuild
@@ -3,6 +3,7 @@ obj-y += kernel/ mm/ net/
obj-$(CONFIG_KVM) += kvm/
obj-$(CONFIG_XEN) += xen/
obj-$(subst m,y,$(CONFIG_HYPERV)) += hyperv/
+obj-$(CONFIG_GUNYAH) += gunyah/
obj-$(CONFIG_CRYPTO) += crypto/
# for cleaning
diff --git a/arch/arm64/gunyah/Makefile b/arch/arm64/gunyah/Makefile
new file mode 100644
index 0000000000000..84f1e38cafb1e
--- /dev/null
+++ b/arch/arm64/gunyah/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_GUNYAH) += gunyah_hypercall.o
diff --git a/arch/arm64/gunyah/gunyah_hypercall.c b/arch/arm64/gunyah/gunyah_hypercall.c
new file mode 100644
index 0000000000000..d44663334f381
--- /dev/null
+++ b/arch/arm64/gunyah/gunyah_hypercall.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/module.h>
+#include <linux/gunyah.h>
+#include <linux/uuid.h>
+
+/* {c1d58fcd-a453-5fdb-9265-ce36673d5f14} */
+static const uuid_t GUNYAH_UUID = UUID_INIT(0xc1d58fcd, 0xa453, 0x5fdb, 0x92,
+ 0x65, 0xce, 0x36, 0x67, 0x3d, 0x5f,
+ 0x14);
+
+bool arch_is_gunyah_guest(void)
+{
+ struct arm_smccc_res res;
+ uuid_t uuid;
+ u32 *up;
+
+ arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, &res);
+
+ up = (u32 *)&uuid.b[0];
+ up[0] = lower_32_bits(res.a0);
+ up[1] = lower_32_bits(res.a1);
+ up[2] = lower_32_bits(res.a2);
+ up[3] = lower_32_bits(res.a3);
+
+ return uuid_equal(&uuid, &GUNYAH_UUID);
+}
+EXPORT_SYMBOL_GPL(arch_is_gunyah_guest);
+
+#define GUNYAH_HYPERCALL(fn) \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64, \
+ ARM_SMCCC_OWNER_VENDOR_HYP, fn)
+
+/* clang-format off */
+#define GUNYAH_HYPERCALL_HYP_IDENTIFY GUNYAH_HYPERCALL(0x8000)
+/* clang-format on */
+
+/**
+ * gunyah_hypercall_hyp_identify() - Returns build information and feature flags
+ * supported by Gunyah.
+ * @hyp_identity: filled by the hypercall with the API info and feature flags.
+ */
+void gunyah_hypercall_hyp_identify(
+ struct gunyah_hypercall_hyp_identify_resp *hyp_identity)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_1_1_hvc(GUNYAH_HYPERCALL_HYP_IDENTIFY, &res);
+
+ hyp_identity->api_info = res.a0;
+ hyp_identity->flags[0] = res.a1;
+ hyp_identity->flags[1] = res.a2;
+ hyp_identity->flags[2] = res.a3;
+}
+EXPORT_SYMBOL_GPL(gunyah_hypercall_hyp_identify);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Gunyah Hypervisor Hypercalls");
diff --git a/drivers/virt/Kconfig b/drivers/virt/Kconfig
index 40129b6f0eca4..172a6a12073c3 100644
--- a/drivers/virt/Kconfig
+++ b/drivers/virt/Kconfig
@@ -50,4 +50,6 @@ source "drivers/virt/acrn/Kconfig"
source "drivers/virt/coco/Kconfig"
+source "drivers/virt/gunyah/Kconfig"
+
endif
diff --git a/drivers/virt/gunyah/Kconfig b/drivers/virt/gunyah/Kconfig
new file mode 100644
index 0000000000000..6f4c85db80b52
--- /dev/null
+++ b/drivers/virt/gunyah/Kconfig
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config GUNYAH
+ tristate "Gunyah Virtualization drivers"
+ depends on ARM64
+ help
+ The Gunyah drivers are the helper interfaces that run in a guest VM
+ such as basic inter-VM IPC and signaling mechanisms, and higher level
+ services such as memory/device sharing, IRQ sharing, and so on.
+
+ Say Y/M here to enable the drivers needed to interact in a Gunyah
+ virtual environment.
diff --git a/include/linux/gunyah.h b/include/linux/gunyah.h
index 1eab631a49b6d..33bcbd22d39f7 100644
--- a/include/linux/gunyah.h
+++ b/include/linux/gunyah.h
@@ -6,9 +6,11 @@
#ifndef _LINUX_GUNYAH_H
#define _LINUX_GUNYAH_H
+#include <linux/bitfield.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/limits.h>
+#include <linux/types.h>
/* Matches resource manager's resource types for VM_GET_HYP_RESOURCES RPC */
enum gunyah_resource_type {
@@ -103,4 +105,40 @@ static inline int gunyah_error_remap(enum gunyah_error gunyah_error)
}
}
+enum gunyah_api_feature {
+ /* clang-format off */
+ GUNYAH_FEATURE_DOORBELL = 1,
+ GUNYAH_FEATURE_MSGQUEUE = 2,
+ GUNYAH_FEATURE_VCPU = 5,
+ GUNYAH_FEATURE_MEMEXTENT = 6,
+ /* clang-format on */
+};
+
+bool arch_is_gunyah_guest(void);
+
+#define GUNYAH_API_V1 1
+
+/* Other bits reserved for future use and will be zero */
+/* clang-format off */
+#define GUNYAH_API_INFO_API_VERSION_MASK GENMASK_ULL(13, 0)
+#define GUNYAH_API_INFO_BIG_ENDIAN BIT_ULL(14)
+#define GUNYAH_API_INFO_IS_64BIT BIT_ULL(15)
+#define GUNYAH_API_INFO_VARIANT_MASK GENMASK_ULL(63, 56)
+/* clang-format on */
+
+struct gunyah_hypercall_hyp_identify_resp {
+ u64 api_info;
+ u64 flags[3];
+};
+
+static inline u16
+gunyah_api_version(const struct gunyah_hypercall_hyp_identify_resp *gunyah_api)
+{
+ return FIELD_GET(GUNYAH_API_INFO_API_VERSION_MASK,
+ gunyah_api->api_info);
+}
+
+void gunyah_hypercall_hyp_identify(
+ struct gunyah_hypercall_hyp_identify_resp *hyp_identity);
+
#endif
--
2.34.1
When booting a Gunyah virtual machine, the host VM may gain capabilities
to interact with resources for the guest virtual machine. Examples of
such resources are vCPUs or message queues. To use those resources, we
need to translate the RM response into a gunyah_resource structure which
are useful to Linux drivers. Presently, Linux drivers need only to know
the type of resource, the capability ID, and an interrupt.
On ARM64 systems, the interrupt reported by Gunyah is the GIC interrupt
ID number and always a SPI or extended SPI.
Signed-off-by: Elliot Berman <[email protected]>
---
arch/arm64/include/asm/gunyah.h | 36 ++++++++++++++++++++++
drivers/virt/gunyah/rsc_mgr.c | 67 +++++++++++++++++++++++++++++++++++++++++
drivers/virt/gunyah/rsc_mgr.h | 5 +++
include/linux/gunyah.h | 2 ++
4 files changed, 110 insertions(+)
diff --git a/arch/arm64/include/asm/gunyah.h b/arch/arm64/include/asm/gunyah.h
new file mode 100644
index 0000000000000..0cd3debe22b64
--- /dev/null
+++ b/arch/arm64/include/asm/gunyah.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+#ifndef _ASM_GUNYAH_H
+#define _ASM_GUNYAH_H
+
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+
+static inline int arch_gunyah_fill_irq_fwspec_params(u32 virq,
+ struct irq_fwspec *fwspec)
+{
+ /* Assume that Gunyah gave us an SPI or ESPI; defensively check it */
+ if (WARN(virq < 32, "Unexpected virq: %d\n", virq)) {
+ return -EINVAL;
+ } else if (virq <= 1019) {
+ fwspec->param_count = 3;
+ fwspec->param[0] = 0; /* GIC_SPI */
+ fwspec->param[1] = virq - 32; /* virq 32 -> SPI 0 */
+ fwspec->param[2] = IRQ_TYPE_EDGE_RISING;
+ } else if (WARN(virq < 4096, "Unexpected virq: %d\n", virq)) {
+ return -EINVAL;
+ } else if (virq < 5120) {
+ fwspec->param_count = 3;
+ fwspec->param[0] = 2; /* GIC_ESPI */
+ fwspec->param[1] = virq - 4096; /* virq 4096 -> ESPI 0 */
+ fwspec->param[2] = IRQ_TYPE_EDGE_RISING;
+ } else {
+ WARN(1, "Unexpected virq: %d\n", virq);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+#endif
diff --git a/drivers/virt/gunyah/rsc_mgr.c b/drivers/virt/gunyah/rsc_mgr.c
index fb0efe68f0e22..c320c9ceaf8ac 100644
--- a/drivers/virt/gunyah/rsc_mgr.c
+++ b/drivers/virt/gunyah/rsc_mgr.c
@@ -9,9 +9,12 @@
#include <linux/mutex.h>
#include <linux/notifier.h>
#include <linux/of.h>
+#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
+#include <asm/gunyah.h>
+
#include "rsc_mgr.h"
#include "vm_mgr.h"
@@ -121,6 +124,7 @@ struct gunyah_rm_message {
* @send_ready: completed when we know Tx message queue can take more messages
* @nh: notifier chain for clients interested in RM notification messages
* @miscdev: /dev/gunyah
+ * @parent_fwnode: Parent IRQ fwnode to translate Gunyah hwirqs to Linux irqs
*/
struct gunyah_rm {
struct device *dev;
@@ -138,6 +142,7 @@ struct gunyah_rm {
struct blocking_notifier_head nh;
struct miscdevice miscdev;
+ struct fwnode_handle *parent_fwnode;
};
/**
@@ -178,6 +183,53 @@ static inline int gunyah_rm_error_remap(enum gunyah_rm_error rm_error)
}
}
+struct gunyah_resource *
+gunyah_rm_alloc_resource(struct gunyah_rm *rm,
+ struct gunyah_rm_hyp_resource *hyp_resource)
+{
+ struct gunyah_resource *ghrsc;
+ int ret;
+
+ ghrsc = kzalloc(sizeof(*ghrsc), GFP_KERNEL);
+ if (!ghrsc)
+ return NULL;
+
+ ghrsc->type = hyp_resource->type;
+ ghrsc->capid = le64_to_cpu(hyp_resource->cap_id);
+ ghrsc->irq = IRQ_NOTCONNECTED;
+ ghrsc->rm_label = le32_to_cpu(hyp_resource->resource_label);
+ if (hyp_resource->virq) {
+ struct irq_fwspec fwspec;
+
+
+ fwspec.fwnode = rm->parent_fwnode;
+ ret = arch_gunyah_fill_irq_fwspec_params(le32_to_cpu(hyp_resource->virq), &fwspec);
+ if (ret) {
+ dev_err(rm->dev,
+ "Failed to translate interrupt for resource %d label: %d: %d\n",
+ ghrsc->type, ghrsc->rm_label, ret);
+ }
+
+ ret = irq_create_fwspec_mapping(&fwspec);
+ if (ret < 0) {
+ dev_err(rm->dev,
+ "Failed to allocate interrupt for resource %d label: %d: %d\n",
+ ghrsc->type, ghrsc->rm_label, ret);
+ kfree(ghrsc);
+ return NULL;
+ }
+ ghrsc->irq = ret;
+ }
+
+ return ghrsc;
+}
+
+void gunyah_rm_free_resource(struct gunyah_resource *ghrsc)
+{
+ irq_dispose_mapping(ghrsc->irq);
+ kfree(ghrsc);
+}
+
static int gunyah_rm_init_message_payload(struct gunyah_rm_message *message,
const void *msg, size_t hdr_size,
size_t msg_size)
@@ -707,6 +759,7 @@ static int gunyah_rm_probe_rx_msgq(struct gunyah_rm *rm,
static int gunyah_rm_probe(struct platform_device *pdev)
{
+ struct device_node *parent_irq_node;
struct gunyah_rm *rm;
int ret;
@@ -734,6 +787,20 @@ static int gunyah_rm_probe(struct platform_device *pdev)
if (ret)
return ret;
+ parent_irq_node = of_irq_find_parent(pdev->dev.of_node);
+ if (!parent_irq_node) {
+ dev_err(&pdev->dev,
+ "Failed to find interrupt parent of resource manager\n");
+ return -ENODEV;
+ }
+
+ rm->parent_fwnode = of_node_to_fwnode(parent_irq_node);
+ if (!rm->parent_fwnode) {
+ dev_err(&pdev->dev,
+ "Failed to find interrupt parent domain of resource manager\n");
+ return -ENODEV;
+ }
+
rm->miscdev.parent = &pdev->dev;
rm->miscdev.name = "gunyah";
rm->miscdev.minor = MISC_DYNAMIC_MINOR;
diff --git a/drivers/virt/gunyah/rsc_mgr.h b/drivers/virt/gunyah/rsc_mgr.h
index 205b9ea735e53..52711de77bb79 100644
--- a/drivers/virt/gunyah/rsc_mgr.h
+++ b/drivers/virt/gunyah/rsc_mgr.h
@@ -99,6 +99,11 @@ struct gunyah_rm_hyp_resources {
int gunyah_rm_get_hyp_resources(struct gunyah_rm *rm, u16 vmid,
struct gunyah_rm_hyp_resources **resources);
+struct gunyah_resource *
+gunyah_rm_alloc_resource(struct gunyah_rm *rm,
+ struct gunyah_rm_hyp_resource *hyp_resource);
+void gunyah_rm_free_resource(struct gunyah_resource *ghrsc);
+
int gunyah_rm_call(struct gunyah_rm *rsc_mgr, u32 message_id,
const void *req_buf, size_t req_buf_size, void **resp_buf,
size_t *resp_buf_size);
diff --git a/include/linux/gunyah.h b/include/linux/gunyah.h
index acd70f9824253..45033bdb5e151 100644
--- a/include/linux/gunyah.h
+++ b/include/linux/gunyah.h
@@ -29,6 +29,8 @@ struct gunyah_resource {
enum gunyah_resource_type type;
u64 capid;
unsigned int irq;
+
+ u32 rm_label;
};
/******************************************************************************/
--
2.34.1
The Gunyah Resource Manager applies a devicetree overlay describing the
virtual platform configuration of the guest VM, such as the message
queue capability IDs for communicating with the Resource Manager. This
information is not otherwise discoverable by a VM: the Gunyah hypervisor
core does not provide a direct interface to discover capability IDs nor
a way to communicate with RM without having already known the
corresponding message queue capability ID. Add the DT bindings that
Gunyah adheres for the hypervisor node and message queues.
Reviewed-by: Rob Herring <[email protected]>
Signed-off-by: Elliot Berman <[email protected]>
---
.../bindings/firmware/gunyah-hypervisor.yaml | 82 ++++++++++++++++++++++
1 file changed, 82 insertions(+)
diff --git a/Documentation/devicetree/bindings/firmware/gunyah-hypervisor.yaml b/Documentation/devicetree/bindings/firmware/gunyah-hypervisor.yaml
new file mode 100644
index 0000000000000..cdeb4885a8072
--- /dev/null
+++ b/Documentation/devicetree/bindings/firmware/gunyah-hypervisor.yaml
@@ -0,0 +1,82 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/firmware/gunyah-hypervisor.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Gunyah Hypervisor
+
+maintainers:
+ - Prakruthi Deepak Heragu <[email protected]>
+ - Elliot Berman <[email protected]>
+
+description: |+
+ Gunyah virtual machines use this information to determine the capability IDs
+ of the message queues used to communicate with the Gunyah Resource Manager.
+ See also: https://github.com/quic/gunyah-resource-manager/blob/develop/src/vm_creation/dto_construct.c
+
+properties:
+ compatible:
+ const: gunyah-hypervisor
+
+ "#address-cells":
+ description: Number of cells needed to represent 64-bit capability IDs.
+ const: 2
+
+ "#size-cells":
+ description: must be 0, because capability IDs are not memory address
+ ranges and do not have a size.
+ const: 0
+
+patternProperties:
+ "^gunyah-resource-mgr(@.*)?":
+ type: object
+ description:
+ Resource Manager node which is required to communicate to Resource
+ Manager VM using Gunyah Message Queues.
+
+ properties:
+ compatible:
+ const: gunyah-resource-manager
+
+ reg:
+ items:
+ - description: Gunyah capability ID of the TX message queue
+ - description: Gunyah capability ID of the RX message queue
+
+ interrupts:
+ items:
+ - description: Interrupt for the TX message queue
+ - description: Interrupt for the RX message queue
+
+ additionalProperties: false
+
+ required:
+ - compatible
+ - reg
+ - interrupts
+
+additionalProperties: false
+
+required:
+ - compatible
+ - "#address-cells"
+ - "#size-cells"
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ hypervisor {
+ #address-cells = <2>;
+ #size-cells = <0>;
+ compatible = "gunyah-hypervisor";
+
+ gunyah-resource-mgr@0 {
+ compatible = "gunyah-resource-manager";
+ interrupts = <GIC_SPI 3 IRQ_TYPE_EDGE_RISING>, /* TX allowed IRQ */
+ <GIC_SPI 4 IRQ_TYPE_EDGE_RISING>; /* RX requested IRQ */
+ reg = <0x00000000 0x00000000>, /* TX capability ID */
+ <0x00000000 0x00000001>; /* RX capability ID */
+ };
+ };
--
2.34.1
* Elliot Berman <[email protected]> [2024-02-22 15:16:34]:
> When booting a Gunyah virtual machine, the host VM may gain capabilities
> to interact with resources for the guest virtual machine. Examples of
> such resources are vCPUs or message queues. To use those resources, we
> need to translate the RM response into a gunyah_resource structure which
> are useful to Linux drivers. Presently, Linux drivers need only to know
> the type of resource, the capability ID, and an interrupt.
>
> On ARM64 systems, the interrupt reported by Gunyah is the GIC interrupt
> ID number and always a SPI or extended SPI.
>
> Signed-off-by: Elliot Berman <[email protected]>
Minor nit below. LGTM otherwise
Reviewed-by: Srivatsa Vaddagiri <[email protected]>
> +struct gunyah_resource *
> +gunyah_rm_alloc_resource(struct gunyah_rm *rm,
> + struct gunyah_rm_hyp_resource *hyp_resource)
> +{
> + struct gunyah_resource *ghrsc;
> + int ret;
> +
> + ghrsc = kzalloc(sizeof(*ghrsc), GFP_KERNEL);
> + if (!ghrsc)
> + return NULL;
> +
> + ghrsc->type = hyp_resource->type;
> + ghrsc->capid = le64_to_cpu(hyp_resource->cap_id);
> + ghrsc->irq = IRQ_NOTCONNECTED;
> + ghrsc->rm_label = le32_to_cpu(hyp_resource->resource_label);
> + if (hyp_resource->virq) {
> + struct irq_fwspec fwspec;
> +
> +
> + fwspec.fwnode = rm->parent_fwnode;
> + ret = arch_gunyah_fill_irq_fwspec_params(le32_to_cpu(hyp_resource->virq), &fwspec);
> + if (ret) {
> + dev_err(rm->dev,
> + "Failed to translate interrupt for resource %d label: %d: %d\n",
> + ghrsc->type, ghrsc->rm_label, ret);
Not bailing on error here appears wrong. Can you check?
> + }
> +
> + ret = irq_create_fwspec_mapping(&fwspec);
> + if (ret < 0) {
> + dev_err(rm->dev,
> + "Failed to allocate interrupt for resource %d label: %d: %d\n",
> + ghrsc->type, ghrsc->rm_label, ret);
> + kfree(ghrsc);
> + return NULL;
> + }
> + ghrsc->irq = ret;
> + }
> +
> + return ghrsc;
> +}
On Mon, Mar 11, 2024 at 11:09:05AM +0530, Srivatsa Vaddagiri wrote:
> * Elliot Berman <[email protected]> [2024-02-22 15:16:34]:
>
> > When booting a Gunyah virtual machine, the host VM may gain capabilities
> > to interact with resources for the guest virtual machine. Examples of
> > such resources are vCPUs or message queues. To use those resources, we
> > need to translate the RM response into a gunyah_resource structure which
> > are useful to Linux drivers. Presently, Linux drivers need only to know
> > the type of resource, the capability ID, and an interrupt.
> >
> > On ARM64 systems, the interrupt reported by Gunyah is the GIC interrupt
> > ID number and always a SPI or extended SPI.
> >
> > Signed-off-by: Elliot Berman <[email protected]>
>
> Minor nit below. LGTM otherwise
>
> Reviewed-by: Srivatsa Vaddagiri <[email protected]>
>
> > +struct gunyah_resource *
> > +gunyah_rm_alloc_resource(struct gunyah_rm *rm,
> > + struct gunyah_rm_hyp_resource *hyp_resource)
> > +{
> > + struct gunyah_resource *ghrsc;
> > + int ret;
> > +
> > + ghrsc = kzalloc(sizeof(*ghrsc), GFP_KERNEL);
> > + if (!ghrsc)
> > + return NULL;
> > +
> > + ghrsc->type = hyp_resource->type;
> > + ghrsc->capid = le64_to_cpu(hyp_resource->cap_id);
> > + ghrsc->irq = IRQ_NOTCONNECTED;
> > + ghrsc->rm_label = le32_to_cpu(hyp_resource->resource_label);
> > + if (hyp_resource->virq) {
> > + struct irq_fwspec fwspec;
> > +
> > +
> > + fwspec.fwnode = rm->parent_fwnode;
> > + ret = arch_gunyah_fill_irq_fwspec_params(le32_to_cpu(hyp_resource->virq), &fwspec);
> > + if (ret) {
> > + dev_err(rm->dev,
> > + "Failed to translate interrupt for resource %d label: %d: %d\n",
> > + ghrsc->type, ghrsc->rm_label, ret);
>
> Not bailing on error here appears wrong. Can you check?
>
Ah, yes. I'll return ghrsc here. I think it's better than returning
NULL because user of resource might be able to cope without the
interrupt and can let us get a more helpful kernel log messages because
the higher level VM function will complain.
> > + }
> > +
> > + ret = irq_create_fwspec_mapping(&fwspec);
> > + if (ret < 0) {
> > + dev_err(rm->dev,
> > + "Failed to allocate interrupt for resource %d label: %d: %d\n",
> > + ghrsc->type, ghrsc->rm_label, ret);
> > + kfree(ghrsc);
> > + return NULL;
> > + }
> > + ghrsc->irq = ret;
> > + }
> > +
> > + return ghrsc;
> > +}
On Thu, Feb 22, 2024 at 03:16:34PM -0800, Elliot Berman wrote:
> When booting a Gunyah virtual machine, the host VM may gain capabilities
> to interact with resources for the guest virtual machine. Examples of
> such resources are vCPUs or message queues. To use those resources, we
> need to translate the RM response into a gunyah_resource structure which
> are useful to Linux drivers. Presently, Linux drivers need only to know
> the type of resource, the capability ID, and an interrupt.
>
> On ARM64 systems, the interrupt reported by Gunyah is the GIC interrupt
> ID number and always a SPI or extended SPI.
>
> Signed-off-by: Elliot Berman <[email protected]>
> ---
> arch/arm64/include/asm/gunyah.h | 36 ++++++++++++++++++++++
> drivers/virt/gunyah/rsc_mgr.c | 67 +++++++++++++++++++++++++++++++++++++++++
> drivers/virt/gunyah/rsc_mgr.h | 5 +++
> include/linux/gunyah.h | 2 ++
> 4 files changed, 110 insertions(+)
>
> diff --git a/arch/arm64/include/asm/gunyah.h b/arch/arm64/include/asm/gunyah.h
> new file mode 100644
> index 0000000000000..0cd3debe22b64
> --- /dev/null
> +++ b/arch/arm64/include/asm/gunyah.h
> @@ -0,0 +1,36 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +#ifndef _ASM_GUNYAH_H
> +#define _ASM_GUNYAH_H
> +
> +#include <linux/irq.h>
> +#include <linux/irqdomain.h>
> +
> +static inline int arch_gunyah_fill_irq_fwspec_params(u32 virq,
> + struct irq_fwspec *fwspec)
> +{
> + /* Assume that Gunyah gave us an SPI or ESPI; defensively check it */
> + if (WARN(virq < 32, "Unexpected virq: %d\n", virq)) {
> + return -EINVAL;
> + } else if (virq <= 1019) {
> + fwspec->param_count = 3;
> + fwspec->param[0] = 0; /* GIC_SPI */
> + fwspec->param[1] = virq - 32; /* virq 32 -> SPI 0 */
> + fwspec->param[2] = IRQ_TYPE_EDGE_RISING;
> + } else if (WARN(virq < 4096, "Unexpected virq: %d\n", virq)) {
> + return -EINVAL;
> + } else if (virq < 5120) {
> + fwspec->param_count = 3;
> + fwspec->param[0] = 2; /* GIC_ESPI */
> + fwspec->param[1] = virq - 4096; /* virq 4096 -> ESPI 0 */
> + fwspec->param[2] = IRQ_TYPE_EDGE_RISING;
> + } else {
> + WARN(1, "Unexpected virq: %d\n", virq);
> + return -EINVAL;
> + }
> + return 0;
> +}
> +
__get_intid_range() in gic-v3 driver looks more pleasing. Other than
that the logic for the translation looks good to me.
Thanks,
Pavan
On Fri, Apr 05, 2024 at 08:40:40AM +0530, Pavan Kondeti wrote:
> On Thu, Feb 22, 2024 at 03:16:34PM -0800, Elliot Berman wrote:
> > When booting a Gunyah virtual machine, the host VM may gain capabilities
> > to interact with resources for the guest virtual machine. Examples of
> > such resources are vCPUs or message queues. To use those resources, we
> > need to translate the RM response into a gunyah_resource structure which
> > are useful to Linux drivers. Presently, Linux drivers need only to know
> > the type of resource, the capability ID, and an interrupt.
> >
> > On ARM64 systems, the interrupt reported by Gunyah is the GIC interrupt
> > ID number and always a SPI or extended SPI.
> >
> > Signed-off-by: Elliot Berman <[email protected]>
> > ---
> > arch/arm64/include/asm/gunyah.h | 36 ++++++++++++++++++++++
> > drivers/virt/gunyah/rsc_mgr.c | 67 +++++++++++++++++++++++++++++++++++++++++
> > drivers/virt/gunyah/rsc_mgr.h | 5 +++
> > include/linux/gunyah.h | 2 ++
> > 4 files changed, 110 insertions(+)
> >
> > diff --git a/arch/arm64/include/asm/gunyah.h b/arch/arm64/include/asm/gunyah.h
> > new file mode 100644
> > index 0000000000000..0cd3debe22b64
> > --- /dev/null
> > +++ b/arch/arm64/include/asm/gunyah.h
> > @@ -0,0 +1,36 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +/*
> > + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
> > + */
> > +#ifndef _ASM_GUNYAH_H
> > +#define _ASM_GUNYAH_H
> > +
> > +#include <linux/irq.h>
> > +#include <linux/irqdomain.h>
> > +
> > +static inline int arch_gunyah_fill_irq_fwspec_params(u32 virq,
> > + struct irq_fwspec *fwspec)
> > +{
> > + /* Assume that Gunyah gave us an SPI or ESPI; defensively check it */
> > + if (WARN(virq < 32, "Unexpected virq: %d\n", virq)) {
> > + return -EINVAL;
> > + } else if (virq <= 1019) {
> > + fwspec->param_count = 3;
> > + fwspec->param[0] = 0; /* GIC_SPI */
> > + fwspec->param[1] = virq - 32; /* virq 32 -> SPI 0 */
> > + fwspec->param[2] = IRQ_TYPE_EDGE_RISING;
> > + } else if (WARN(virq < 4096, "Unexpected virq: %d\n", virq)) {
> > + return -EINVAL;
> > + } else if (virq < 5120) {
> > + fwspec->param_count = 3;
> > + fwspec->param[0] = 2; /* GIC_ESPI */
> > + fwspec->param[1] = virq - 4096; /* virq 4096 -> ESPI 0 */
> > + fwspec->param[2] = IRQ_TYPE_EDGE_RISING;
> > + } else {
> > + WARN(1, "Unexpected virq: %d\n", virq);
> > + return -EINVAL;
> > + }
> > + return 0;
> > +}
> > +
>
> __get_intid_range() in gic-v3 driver looks more pleasing. Other than
> that the logic for the translation looks good to me.
Agreed, updated for v18.
static inline int arch_gunyah_fill_irq_fwspec_params(u32 virq,
struct irq_fwspec *fwspec)
{
/* Assume that Gunyah gave us an SPI or ESPI; defensively check it */
switch (virq) {
case 32 ... 1019:
fwspec->param_count = 3;
fwspec->param[0] = 0; /* GIC_SPI */
fwspec->param[1] = virq - 32; /* virq 32 -> SPI 0 */
fwspec->param[2] = IRQ_TYPE_EDGE_RISING;
break;
case 4096 ... 5119:
fwspec->param_count = 3;
fwspec->param[0] = 2; /* GIC_ESPI */
fwspec->param[1] = virq - 4096; /* virq 4096 -> ESPI 0 */
fwspec->param[2] = IRQ_TYPE_EDGE_RISING;
break;
default:
WARN(1, "Unexpected virq: %d\n", virq)
return -EINVAL;
}
return 0;
}