From 8f1f4a1b65a4aa9b4ab2c37052d08d59404a06db Mon Sep 17 00:00:00 2001 From: Vincent Donnefort Date: Tue, 18 Oct 2022 15:44:27 +0100 Subject: [PATCH] ANDROID: KVM: arm64: add support for early enablement nVHE hyp events Set hyp_event="event1,event2" in the commandline to start tracing as soon as possible the nVHE hypervisor. Bug: 229972309 Change-Id: I878e342a8758a78a01d6ddf26355020945b2df33 Signed-off-by: Vincent Donnefort --- arch/arm64/kvm/hyp_events.c | 91 +++++++++++++++++++++++++++++++++---- arch/arm64/kvm/hyp_trace.c | 7 +++ 2 files changed, 89 insertions(+), 9 deletions(-) diff --git a/arch/arm64/kvm/hyp_events.c b/arch/arm64/kvm/hyp_events.c index 4bc5c5dee12d..6b05da594062 100644 --- a/arch/arm64/kvm/hyp_events.c +++ b/arch/arm64/kvm/hyp_events.c @@ -8,12 +8,15 @@ #include #include +#include #include "hyp_trace.h" +#define HYP_EVENT_NAME_MAX 32 + struct hyp_event { struct trace_event_call *call; - char name[32]; + char name[HYP_EVENT_NAME_MAX]; bool *enabled; }; @@ -81,12 +84,41 @@ extern struct hyp_event __stop_hyp_events[]; extern struct hyp_event_id __hyp_event_ids_start[]; extern struct hyp_event_id __hyp_event_ids_end[]; +static struct hyp_event *find_hyp_event(const char *name) +{ + struct hyp_event *event = __start_hyp_events; + + for (; (unsigned long)event < (unsigned long)__stop_hyp_events; + event++) { + if (!strncmp(name, event->name, HYP_EVENT_NAME_MAX)) + return event; + } + + return NULL; +} + +static int enable_hyp_event(struct hyp_event *event, bool enable) +{ + unsigned short id = event->call->event.type; + int ret; + + if (enable == *event->enabled) + return 0; + + ret = kvm_call_hyp_nvhe(__pkvm_enable_event, id, enable); + if (ret) + return ret; + + *event->enabled = enable; + + return 0; +} + static ssize_t hyp_event_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { struct seq_file *seq_file = (struct seq_file *)filp->private_data; struct hyp_event *evt = (struct hyp_event *)seq_file->private; - unsigned short id = evt->call->event.type; bool enabling; int ret; char c; @@ -108,13 +140,9 @@ hyp_event_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t * return -EINVAL; } - if (enabling != *evt->enabled) { - ret = kvm_call_hyp_nvhe(__pkvm_enable_event, id, enabling); - if (ret) - return ret; - } - - *evt->enabled = enabling; + ret = enable_hyp_event(evt, enabling); + if (ret) + return ret; return cnt; } @@ -163,6 +191,51 @@ static const struct file_operations hyp_event_id_fops = { .release = single_release, }; +static char early_events[COMMAND_LINE_SIZE]; + +static __init int setup_hyp_event_early(char *str) +{ + strscpy(early_events, str, COMMAND_LINE_SIZE); + + return 1; +} +__setup("hyp_event=", setup_hyp_event_early); + +bool kvm_hyp_events_enable_early(void) +{ + char *token, *buf = early_events; + bool enabled = false; + + while (true) { + token = strsep(&buf, ","); + + if (!token) + break; + + if (*token) { + struct hyp_event *event; + int ret; + + event = find_hyp_event(token); + if (event) { + ret = enable_hyp_event(event, true); + if (ret) + pr_warn("Couldn't enable hyp event %s:%d\n", + token, ret); + else + enabled = true; + } else { + pr_warn("Couldn't find hyp event %s\n", token); + } + } + + if (buf) + *(buf - 1) = ','; + } + + return enabled; +} + void kvm_hyp_init_events_tracefs(struct dentry *parent) { struct hyp_event *event = __start_hyp_events; diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c index 0ea14666e970..cabf73099570 100644 --- a/arch/arm64/kvm/hyp_trace.c +++ b/arch/arm64/kvm/hyp_trace.c @@ -730,12 +730,14 @@ static void hyp_tracefs_create_cpu_file(const char *file_name, } void kvm_hyp_init_events_tracefs(struct dentry *parent); +bool kvm_hyp_events_enable_early(void); int init_hyp_tracefs(void) { struct dentry *d, *root_dir, *per_cpu_root_dir; char per_cpu_name[16]; unsigned long cpu; + int err; if (!is_protected_kvm_enabled()) return 0; @@ -784,6 +786,11 @@ int init_hyp_tracefs(void) } kvm_hyp_init_events_tracefs(root_dir); + if (kvm_hyp_events_enable_early()) { + err = hyp_start_tracing(); + if (err) + pr_warn("Failed to start early events tracing: %d\n", err); + } return 0; }