summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm64/include/asm/stacktrace/common.h6
-rw-r--r--arch/arm64/kvm/stacktrace.c82
2 files changed, 49 insertions, 39 deletions
diff --git a/arch/arm64/include/asm/stacktrace/common.h b/arch/arm64/include/asm/stacktrace/common.h
index 3c3bda34bb87..2f972441f572 100644
--- a/arch/arm64/include/asm/stacktrace/common.h
+++ b/arch/arm64/include/asm/stacktrace/common.h
@@ -113,14 +113,12 @@ static inline void unwind_init_common(struct unwind_state *state,
* pointer to a kernel address.
*
* @fp: the frame pointer to be updated to its kernel address.
- * @type: the stack type associated with frame pointer @fp
*
* Return: true if the VA can be translated, false otherwise.
*
* Upon success @fp is updated to the corresponding kernel virtual address.
*/
-typedef bool (*stack_trace_translate_fp_fn)(unsigned long *fp,
- enum stack_type type);
+typedef bool (*stack_trace_translate_fp_fn)(unsigned long *fp);
/**
* typedef on_accessible_stack_fn() - Check whether a stack range is on any of
@@ -172,7 +170,7 @@ unwind_next_frame_record(struct unwind_state *state,
* If fp is not from the current address space perform the necessary
* translation before dereferencing it to get the next fp.
*/
- if (translate_fp && !translate_fp(&kern_fp, info.type))
+ if (translate_fp && !translate_fp(&kern_fp))
return -EINVAL;
/*
diff --git a/arch/arm64/kvm/stacktrace.c b/arch/arm64/kvm/stacktrace.c
index 26927344a263..7658c5db47c1 100644
--- a/arch/arm64/kvm/stacktrace.c
+++ b/arch/arm64/kvm/stacktrace.c
@@ -21,6 +21,34 @@
#include <asm/stacktrace/nvhe.h>
+static struct stack_info stackinfo_get_overflow(void)
+{
+ struct kvm_nvhe_stacktrace_info *stacktrace_info
+ = this_cpu_ptr_nvhe_sym(kvm_stacktrace_info);
+ unsigned long low = (unsigned long)stacktrace_info->overflow_stack_base;
+ unsigned long high = low + OVERFLOW_STACK_SIZE;
+
+ return (struct stack_info) {
+ .low = low,
+ .high = high,
+ .type = STACK_TYPE_OVERFLOW,
+ };
+}
+
+static struct stack_info stackinfo_get_hyp(void)
+{
+ struct kvm_nvhe_stacktrace_info *stacktrace_info
+ = this_cpu_ptr_nvhe_sym(kvm_stacktrace_info);
+ unsigned long low = (unsigned long)stacktrace_info->stack_base;
+ unsigned long high = low + PAGE_SIZE;
+
+ return (struct stack_info) {
+ .low = low,
+ .high = high,
+ .type = STACK_TYPE_HYP,
+ };
+}
+
/*
* kvm_nvhe_stack_kern_va - Convert KVM nVHE HYP stack addresses to a kernel VAs
*
@@ -34,27 +62,31 @@
* Returns true on success and updates @addr to its corresponding kernel VA;
* otherwise returns false.
*/
-static bool kvm_nvhe_stack_kern_va(unsigned long *addr,
- enum stack_type type)
+static bool kvm_nvhe_stack_kern_va(unsigned long *addr, unsigned long size)
{
struct kvm_nvhe_stacktrace_info *stacktrace_info;
unsigned long hyp_base, kern_base, hyp_offset;
+ struct stack_info stack;
stacktrace_info = this_cpu_ptr_nvhe_sym(kvm_stacktrace_info);
- switch (type) {
- case STACK_TYPE_HYP:
+ stack = stackinfo_get_hyp();
+ if (stackinfo_on_stack(&stack, *addr, size)) {
kern_base = (unsigned long)*this_cpu_ptr(&kvm_arm_hyp_stack_page);
hyp_base = (unsigned long)stacktrace_info->stack_base;
- break;
- case STACK_TYPE_OVERFLOW:
+ goto found;
+ }
+
+ stack = stackinfo_get_overflow();
+ if (stackinfo_on_stack(&stack, *addr, size)) {
kern_base = (unsigned long)this_cpu_ptr_nvhe_sym(overflow_stack);
hyp_base = (unsigned long)stacktrace_info->overflow_stack_base;
- break;
- default:
- return false;
+ goto found;
}
+ return false;
+
+found:
hyp_offset = *addr - hyp_base;
*addr = kern_base + hyp_offset;
@@ -62,32 +94,12 @@ static bool kvm_nvhe_stack_kern_va(unsigned long *addr,
return true;
}
-static struct stack_info stackinfo_get_overflow(void)
-{
- struct kvm_nvhe_stacktrace_info *stacktrace_info
- = this_cpu_ptr_nvhe_sym(kvm_stacktrace_info);
- unsigned long low = (unsigned long)stacktrace_info->overflow_stack_base;
- unsigned long high = low + OVERFLOW_STACK_SIZE;
-
- return (struct stack_info) {
- .low = low,
- .high = high,
- .type = STACK_TYPE_OVERFLOW,
- };
-}
-
-static struct stack_info stackinfo_get_hyp(void)
+/*
+ * Convert a KVN nVHE HYP frame record address to a kernel VA
+ */
+static bool kvm_nvhe_stack_kern_record_va(unsigned long *addr)
{
- struct kvm_nvhe_stacktrace_info *stacktrace_info
- = this_cpu_ptr_nvhe_sym(kvm_stacktrace_info);
- unsigned long low = (unsigned long)stacktrace_info->stack_base;
- unsigned long high = low + PAGE_SIZE;
-
- return (struct stack_info) {
- .low = low,
- .high = high,
- .type = STACK_TYPE_HYP,
- };
+ return kvm_nvhe_stack_kern_va(addr, 16);
}
static bool on_accessible_stack(const struct task_struct *tsk,
@@ -115,7 +127,7 @@ found:
static int unwind_next(struct unwind_state *state)
{
return unwind_next_frame_record(state, on_accessible_stack,
- kvm_nvhe_stack_kern_va);
+ kvm_nvhe_stack_kern_record_va);
}
static void unwind(struct unwind_state *state,