ANDROID: KVM: arm64: trace_hyp_printk()
Simple trace_printk() equivalent for the pKVM hypervisor. This only
supports up to 4 arguments and can't print '%p' or '%s' formats.
Bug: 357781595
Change-Id: Ief8355accfbcb630d7df36c93498d62d50f63d0c
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
diff --git a/arch/arm64/include/asm/kvm_define_hypevents.h b/arch/arm64/include/asm/kvm_define_hypevents.h
index efa2c2c..39e5963 100644
--- a/arch/arm64/include/asm/kvm_define_hypevents.h
+++ b/arch/arm64/include/asm/kvm_define_hypevents.h
@@ -43,8 +43,10 @@
#undef HYP_EVENT
#undef HE_PRINTK
+#undef HE_PRINTK_UNKNOWN_FMT
#define __entry REC
#define HE_PRINTK(fmt, args...) "\"" fmt "\", " __stringify(args)
+#define HE_PRINTK_UNKNOWN_FMT(fmt, args...) "Unknown"
#define HYP_EVENT(__name, __proto, __struct, __assign, __printk) \
static char hyp_event_print_fmt_##__name[] = __printk; \
static bool hyp_event_enabled_##__name; \
diff --git a/arch/arm64/include/asm/kvm_hypevents.h b/arch/arm64/include/asm/kvm_hypevents.h
index bae2f92..f7a326b 100644
--- a/arch/arm64/include/asm/kvm_hypevents.h
+++ b/arch/arm64/include/asm/kvm_hypevents.h
@@ -72,6 +72,26 @@ HYP_EVENT(host_mem_abort,
__entry->esr, __entry->addr)
);
+HYP_EVENT(__hyp_printk,
+ HE_PROTO(const char *fmt, u64 a, u64 b, u64 c, u64 d),
+ HE_STRUCT(
+ he_field(u8, fmt_id)
+ he_field(u64, a)
+ he_field(u64, b)
+ he_field(u64, c)
+ he_field(u64, d)
+ ),
+ HE_ASSIGN(
+ __entry->fmt_id = hyp_printk_fmt_to_id(fmt);
+ __entry->a = a;
+ __entry->b = b;
+ __entry->c = c;
+ __entry->d = d;
+ ),
+ HE_PRINTK_UNKNOWN_FMT(hyp_printk_fmt_from_id(__entry->fmt_id),
+ __entry->a, __entry->b, __entry->c, __entry->d)
+);
+
#ifdef CONFIG_PROTECTED_NVHE_TESTING
HYP_EVENT(selftest,
HE_PROTO(void),
diff --git a/arch/arm64/include/asm/kvm_hypevents_defs.h b/arch/arm64/include/asm/kvm_hypevents_defs.h
index 473bf43..b961410f 100644
--- a/arch/arm64/include/asm/kvm_hypevents_defs.h
+++ b/arch/arm64/include/asm/kvm_hypevents_defs.h
@@ -23,6 +23,12 @@ struct hyp_entry_hdr {
unsigned short id;
};
+struct hyp_printk_fmt {
+ /* __MUST__ be the first element */
+ const char fmt[127];
+ const char null;
+};
+
/*
* Hyp events definitions common to the hyp and the host
*/
@@ -32,10 +38,11 @@ struct hyp_entry_hdr {
__struct \
}
-#define HE_PROTO(args...) args
-#define HE_STRUCT(args...) args
-#define HE_ASSIGN(args...) args
-#define HE_PRINTK(args...) args
+#define HE_PROTO(args...) args
+#define HE_STRUCT(args...) args
+#define HE_ASSIGN(args...) args
+#define HE_PRINTK(args...) args
+#define HE_PRINTK_UNKNOWN_FMT(args...) args
#define he_field(type, item) type item;
#endif
diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h
index e60754c..6084332c 100644
--- a/arch/arm64/kernel/image-vars.h
+++ b/arch/arm64/kernel/image-vars.h
@@ -137,6 +137,7 @@ KVM_NVHE_ALIAS(__hyp_rodata_end);
#ifdef CONFIG_TRACING
KVM_NVHE_ALIAS(__hyp_event_ids_start);
KVM_NVHE_ALIAS(__hyp_event_ids_end);
+KVM_NVHE_ALIAS(__hyp_printk_fmts_start);
#endif
/* pKVM static key */
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index 8e578dc..04c6dc8 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -217,6 +217,11 @@
*(_hyp_events)
__hyp_events_end = .;
}
+ .rodata.hyp_printk_fmts : {
+ __hyp_printk_fmts_start = .;
+ *(HYP_SECTION_NAME(.printk_fmts))
+ __hyp_printk_fmts_end = .;
+ }
#endif
/* code sections that are never executed via the kernel mapping */
.rodata.text : {
diff --git a/arch/arm64/kvm/hyp/include/nvhe/trace.h b/arch/arm64/kvm/hyp/include/nvhe/trace.h
index 8384801..abc0ee5 100644
--- a/arch/arm64/kvm/hyp/include/nvhe/trace.h
+++ b/arch/arm64/kvm/hyp/include/nvhe/trace.h
@@ -42,6 +42,40 @@ int __pkvm_enable_tracing(bool enable);
int __pkvm_reset_tracing(unsigned int cpu);
int __pkvm_swap_reader_tracing(unsigned int cpu);
int __pkvm_enable_event(unsigned short id, bool enable);
+
+extern char __hyp_printk_fmts_start[];
+
+static inline u8 hyp_printk_fmt_to_id(const char *fmt)
+{
+ return (fmt - __hyp_printk_fmts_start) / sizeof(struct hyp_printk_fmt);
+}
+
+#define __trace_hyp_printk(__fmt, a, b, c, d) \
+do { \
+ static struct hyp_printk_fmt __used \
+ __section(".hyp.printk_fmts") \
+ ht_fmt = { \
+ .fmt = __fmt \
+ }; \
+ trace___hyp_printk(ht_fmt.fmt, a, b, c, d); \
+} while (0)
+
+#define __trace_hyp_printk_0(fmt, arg) \
+ __trace_hyp_printk(fmt, 0, 0, 0, 0)
+#define __trace_hyp_printk_1(fmt, a) \
+ __trace_hyp_printk(fmt, a, 0, 0, 0)
+#define __trace_hyp_printk_2(fmt, a, b) \
+ __trace_hyp_printk(fmt, a, b, 0, 0)
+#define __trace_hyp_printk_3(fmt, a, b, c) \
+ __trace_hyp_printk(fmt, a, b, c, 0)
+#define __trace_hyp_printk_4(fmt, a, b, c, d) \
+ __trace_hyp_printk(fmt, a, b, c, d)
+
+#define __trace_hyp_printk_N(fmt, ...) \
+ CONCATENATE(__trace_hyp_printk_, COUNT_ARGS(__VA_ARGS__))(fmt, ##__VA_ARGS__)
+
+#define trace_hyp_printk(fmt, ...) \
+ __trace_hyp_printk_N(fmt, __VA_ARGS__)
#else
static inline void *tracing_reserve_entry(unsigned long length) { return NULL; }
static inline void tracing_commit_entry(void) { }
@@ -56,5 +90,6 @@ static inline int __pkvm_enable_tracing(bool enable) { return -ENODEV; }
static inline int __pkvm_reset_tracing(unsigned int cpu) { return -ENODEV; }
static inline int __pkvm_swap_reader_tracing(unsigned int cpu) { return -ENODEV; }
static inline int __pkvm_enable_event(unsigned short id, bool enable) { return -ENODEV; }
+#define trace_hyp_printk(fmt, ...)
#endif
#endif
diff --git a/arch/arm64/kvm/hyp_events.c b/arch/arm64/kvm/hyp_events.c
index de5cc7e..2fe7726 100644
--- a/arch/arm64/kvm/hyp_events.c
+++ b/arch/arm64/kvm/hyp_events.c
@@ -6,11 +6,29 @@
#include <linux/tracefs.h>
#include <asm/kvm_host.h>
-#include <asm/kvm_define_hypevents.h>
#include <asm/setup.h>
#include "hyp_trace.h"
+static const char *hyp_printk_fmt_from_id(u8 fmt_id);
+
+#include <asm/kvm_define_hypevents.h>
+
+extern char __hyp_printk_fmts_start[];
+extern char __hyp_printk_fmts_end[];
+
+static const char *hyp_printk_fmt_from_id(u8 fmt_id)
+{
+ u8 max_ids = (__hyp_printk_fmts_end -
+ __hyp_printk_fmts_start) / sizeof(struct hyp_printk_fmt);
+
+ if (fmt_id >= max_ids)
+ return "Unknown Format";
+
+ return (const char *)(__hyp_printk_fmts_start +
+ (fmt_id * sizeof(struct hyp_printk_fmt)));
+}
+
extern struct hyp_event __hyp_events_start[];
extern struct hyp_event __hyp_events_end[];
@@ -311,6 +329,9 @@ int hyp_trace_init_events(void)
struct hyp_event *event = __hyp_events_start;
int id = 0;
+ /* __hyp_printk event only supports U8_MAX different formats */
+ WARN_ON((__hyp_printk_fmts_end - __hyp_printk_fmts_start) > U8_MAX);
+
for (; (unsigned long)event < (unsigned long)__hyp_events_end;
event++, hyp_event_id++, id++) {