From b582c8956932d0849177908595a2a1c16605deb2 Mon Sep 17 00:00:00 2001 From: Prakruthi Deepak Heragu Date: Mon, 24 Feb 2025 14:51:00 -0800 Subject: [PATCH] ANDROID: gunyah: qtvm: Add status notifier chain for QTVMs QTVMs' Gunyah resources are handled partially by the VMM. The remaining resources are handled by the kernel clients. By providing this notifier, we allow the client drivers to add their operations for setting up the resources they own. Bug: 399219478 Change-Id: I2a5377358aa669dcebd6307ba5bc78ac117886f0 Signed-off-by: Prakruthi Deepak Heragu --- drivers/virt/gunyah/gunyah_qtvm.c | 57 ++++++++++++++++++++++++++++++- drivers/virt/gunyah/vm_mgr.c | 10 +++++- drivers/virt/gunyah/vm_mgr.h | 15 ++++++++ include/linux/gunyah.h | 5 +++ include/linux/gunyah_qtvm.h | 48 ++++++++++++++++++++++++++ 5 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 include/linux/gunyah_qtvm.h diff --git a/drivers/virt/gunyah/gunyah_qtvm.c b/drivers/virt/gunyah/gunyah_qtvm.c index e8a6aa77107e..5ed23ca12818 100644 --- a/drivers/virt/gunyah/gunyah_qtvm.c +++ b/drivers/virt/gunyah/gunyah_qtvm.c @@ -4,13 +4,14 @@ */ #include +#include #include "vm_mgr.h" #define PAS_VM_METADATA_SZ 8192 static DEFINE_MUTEX(gunyah_qtvm_lock); static LIST_HEAD(gunyah_qtvm_list); -SRCU_NOTIFIER_HEAD_STATIC(gunyah_vm_notifier); +SRCU_NOTIFIER_HEAD_STATIC(gunyah_qtvm_notifier); struct gunyah_qtvm { struct gunyah_vm *ghvm; @@ -22,6 +23,24 @@ struct gunyah_qtvm { u16 vmid; }; +int gunyah_qtvm_register_notifier(struct notifier_block *nb) +{ + return srcu_notifier_chain_register(&gunyah_qtvm_notifier, nb); +} +EXPORT_SYMBOL_GPL(gunyah_qtvm_register_notifier); + +int gunyah_qtvm_unregister_notifier(struct notifier_block *nb) +{ + return srcu_notifier_chain_unregister(&gunyah_qtvm_notifier, nb); +} +EXPORT_SYMBOL_GPL(gunyah_qtvm_unregister_notifier); + +static void gunyah_notify_clients(struct gunyah_qtvm *vm, + enum gunyah_qtvm_state state) +{ + srcu_notifier_call_chain(&gunyah_qtvm_notifier, state, &vm->vmid); +} + static u16 gunyah_qtvm_pre_alloc_vmid(struct gunyah_vm *ghvm) { struct gunyah_qtvm *vm = ghvm->auth_vm_mgr_data; @@ -109,10 +128,45 @@ static int gunyah_qtvm_authenticate(struct gunyah_vm *ghvm) return 0; } +static int gunyah_qtvm_pre_vm_start(struct gunyah_vm *ghvm) +{ + struct gunyah_qtvm *vm = ghvm->auth_vm_mgr_data; + + gunyah_notify_clients(vm, GUNYAH_QTVM_BEFORE_POWERUP); + return 0; +} + +static void gunyah_qtvm_vm_start_fail(struct gunyah_vm *ghvm) +{ + struct gunyah_qtvm *vm = ghvm->auth_vm_mgr_data; + + gunyah_notify_clients(vm, GUNYAH_QTVM_POWERUP_FAIL); +} + +static int gunyah_qtvm_pre_vm_reset(struct gunyah_vm *ghvm) +{ + struct gunyah_qtvm *vm = ghvm->auth_vm_mgr_data; + + gunyah_notify_clients(vm, GUNYAH_QTVM_EXITED); + return 0; +} + +static int gunyah_qtvm_post_vm_reset(struct gunyah_vm *ghvm) +{ + struct gunyah_qtvm *vm = ghvm->auth_vm_mgr_data; + + gunyah_notify_clients(vm, GUNYAH_QTVM_EARLY_POWEROFF); + return 0; +} + static struct gunyah_auth_vm_mgr_ops vm_ops = { .pre_alloc_vmid = gunyah_qtvm_pre_alloc_vmid, .pre_vm_configure = gunyah_qtvm_pre_vm_configure, .vm_authenticate = gunyah_qtvm_authenticate, + .pre_vm_start = gunyah_qtvm_pre_vm_start, + .vm_start_fail = gunyah_qtvm_vm_start_fail, + .pre_vm_reset = gunyah_qtvm_pre_vm_reset, + .post_vm_reset = gunyah_qtvm_post_vm_reset, }; static long gunyah_qtvm_attach(struct gunyah_vm *ghvm, struct gunyah_auth_desc *desc) @@ -161,6 +215,7 @@ static void gunyah_qtvm_detach(struct gunyah_vm *ghvm) struct gunyah_qtvm *vm = ghvm->auth_vm_mgr_data; kfree(vm->parcel_list); + gunyah_notify_clients(vm, GUNYAH_QTVM_POWEROFF); list_del(&vm->list); kfree(vm); ghvm->auth_vm_mgr_ops = NULL; diff --git a/drivers/virt/gunyah/vm_mgr.c b/drivers/virt/gunyah/vm_mgr.c index 40198d74fb9a..c5c2f589a720 100644 --- a/drivers/virt/gunyah/vm_mgr.c +++ b/drivers/virt/gunyah/vm_mgr.c @@ -1127,6 +1127,10 @@ static void _gunyah_vm_put(struct kref *kref) gunyah_vm_remove_resource_ticket(ghvm, &ghvm->guest_private_extent_ticket); /* clang-format on */ + ret = gunyah_vm_pre_vm_reset(ghvm); + if (ret) + dev_err(ghvm->parent, "Failed pre reset the vm: %d\n", ret); + gunyah_vm_clean_resources(ghvm); if (ghvm->vm_status == GUNYAH_RM_VM_STATUS_EXITED || @@ -1138,7 +1142,11 @@ static void _gunyah_vm_put(struct kref *kref) wait_event(ghvm->vm_status_wait, ghvm->vm_status == GUNYAH_RM_VM_STATUS_RESET); else - dev_err(ghvm->parent, "Failed to reset the vm: %d\n",ret); + dev_err(ghvm->parent, "Failed to reset the vm: %d\n", ret); + + ret = gunyah_vm_post_vm_reset(ghvm); + if (ret) + dev_err(ghvm->parent, "Failed post reset the vm: %d\n", ret); /* clang-format on */ } diff --git a/drivers/virt/gunyah/vm_mgr.h b/drivers/virt/gunyah/vm_mgr.h index e360f5bef5cb..6919d36d4682 100644 --- a/drivers/virt/gunyah/vm_mgr.h +++ b/drivers/virt/gunyah/vm_mgr.h @@ -329,4 +329,19 @@ static inline void gunyah_vm_start_fail(struct gunyah_vm *ghvm) return ghvm->auth_vm_mgr_ops->vm_start_fail(ghvm); } +static inline int gunyah_vm_pre_vm_reset(struct gunyah_vm *ghvm) +{ + if (ghvm->auth_vm_mgr_ops->pre_vm_reset) + return ghvm->auth_vm_mgr_ops->pre_vm_reset(ghvm); + + return 0; +} + +static inline int gunyah_vm_post_vm_reset(struct gunyah_vm *ghvm) +{ + if (ghvm->auth_vm_mgr_ops->post_vm_reset) + return ghvm->auth_vm_mgr_ops->post_vm_reset(ghvm); + + return 0; +} #endif diff --git a/include/linux/gunyah.h b/include/linux/gunyah.h index 5717b0710c45..f58ed64b980a 100644 --- a/include/linux/gunyah.h +++ b/include/linux/gunyah.h @@ -37,6 +37,9 @@ void gunyah_vm_put(struct gunyah_vm *ghvm); * choose to setup if you want demand paged VM or not. (Optional) * @pre_vm_start: Callback for any setup before VM start where client * drivers can share/lend memory. (Optional) + * @pre_vm_reset: Callback for any cleanup before VM reset. All resources + * tracked by RM will be cleaned at this stage (Optional) + * @post_vm_reset: Callback for any cleanup after VM reset (Optional) * @start_fail: Needed when roll back is needed before auth_mgr can * clean up at a later stage. **/ @@ -46,6 +49,8 @@ struct gunyah_auth_vm_mgr_ops { int (*vm_authenticate)(struct gunyah_vm *ghvm); int (*pre_vm_init)(struct gunyah_vm *ghvm); int (*pre_vm_start)(struct gunyah_vm *ghvm); + int (*pre_vm_reset)(struct gunyah_vm *ghvm); + int (*post_vm_reset)(struct gunyah_vm *ghvm); void (*vm_start_fail)(struct gunyah_vm *ghvm); }; diff --git a/include/linux/gunyah_qtvm.h b/include/linux/gunyah_qtvm.h new file mode 100644 index 000000000000..3986b207a395 --- /dev/null +++ b/include/linux/gunyah_qtvm.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _LINUX_GUNYAH_QTVM_H +#define _LINUX_GUNYAH_QTVM_H + +#include +#include + +enum gunyah_qtvm_state { + GUNYAH_QTVM_BEFORE_POWERUP = 1, + GUNYAH_QTVM_POWERUP_FAIL = 2, + GUNYAH_QTVM_EARLY_POWEROFF = 3, + GUNYAH_QTVM_POWEROFF = 4, + GUNYAH_QTVM_EXITED = 5, + GUNYAH_QTVM_CRASH = 6, +}; + +#if IS_ENABLED(CONFIG_GUNYAH_QCOM_TRUSTED_VM) +int gunyah_qtvm_register_notifier(struct notifier_block *nb); +int gunyah_qtvm_unregister_notifier(struct notifier_block *nb); +int gunyah_qtvm_register_resource_ticket(struct gunyah_vm_resource_ticket *t, + u16 vmid); +void gunyah_qtvm_unregister_resource_ticket(struct gunyah_vm_resource_ticket *t, + u16 vmid); +#else +static inline int gunyah_qtvm_register_notifier(struct notifier_block *nb) +{ + return 0; +} +static inline int gunyah_qtvm_unregister_notifier(struct notifier_block *nb) +{ + return 0; +} +static inline int gunyah_qtvm_register_resource_ticket( + struct gunyah_vm_resource_ticket *t, u16 vmid) +{ + return 0; +} +static inline void gunyah_qtvm_unregister_resource_ticket( + struct gunyah_vm_resource_ticket *t, u16 vmid) +{ +} +#endif + +#endif