Merge branch 'kvm-arm64/nvhe-panic-info' into kvmarm-master/next
Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
Коммит
5c92a7643b
|
@ -102,7 +102,6 @@ u64 __guest_enter(struct kvm_vcpu *vcpu);
|
|||
|
||||
bool kvm_host_psci_handler(struct kvm_cpu_context *host_ctxt);
|
||||
|
||||
void __noreturn hyp_panic(void);
|
||||
#ifdef __KVM_NVHE_HYPERVISOR__
|
||||
void __noreturn __hyp_do_panic(struct kvm_cpu_context *host_ctxt, u64 spsr,
|
||||
u64 elr, u64 par);
|
||||
|
|
|
@ -121,6 +121,8 @@ void kvm_update_va_mask(struct alt_instr *alt,
|
|||
void kvm_compute_layout(void);
|
||||
void kvm_apply_hyp_relocations(void);
|
||||
|
||||
#define __hyp_pa(x) (((phys_addr_t)(x)) + hyp_physvirt_offset)
|
||||
|
||||
static __always_inline unsigned long __kern_hyp_va(unsigned long v)
|
||||
{
|
||||
asm volatile(ALTERNATIVE_CB("and %0, %0, #1\n"
|
||||
|
|
|
@ -71,8 +71,7 @@ KVM_NVHE_ALIAS(kvm_compute_final_ctr_el0);
|
|||
KVM_NVHE_ALIAS(kvm_vgic_global_state);
|
||||
|
||||
/* Kernel symbols used to call panic() from nVHE hyp code (via ERET). */
|
||||
KVM_NVHE_ALIAS(__hyp_panic_string);
|
||||
KVM_NVHE_ALIAS(panic);
|
||||
KVM_NVHE_ALIAS(nvhe_hyp_panic_handler);
|
||||
|
||||
/* Vectors installed by hyp-init on reset HVC. */
|
||||
KVM_NVHE_ALIAS(__hyp_stub_vectors);
|
||||
|
|
|
@ -291,3 +291,48 @@ void handle_exit_early(struct kvm_vcpu *vcpu, int exception_index)
|
|||
if (exception_index == ARM_EXCEPTION_EL1_SERROR)
|
||||
kvm_handle_guest_serror(vcpu, kvm_vcpu_get_esr(vcpu));
|
||||
}
|
||||
|
||||
void __noreturn __cold nvhe_hyp_panic_handler(u64 esr, u64 spsr, u64 elr,
|
||||
u64 par, uintptr_t vcpu,
|
||||
u64 far, u64 hpfar) {
|
||||
u64 elr_in_kimg = __phys_to_kimg(__hyp_pa(elr));
|
||||
u64 hyp_offset = elr_in_kimg - kaslr_offset() - elr;
|
||||
u64 mode = spsr & PSR_MODE_MASK;
|
||||
|
||||
/*
|
||||
* The nVHE hyp symbols are not included by kallsyms to avoid issues
|
||||
* with aliasing. That means that the symbols cannot be printed with the
|
||||
* "%pS" format specifier, so fall back to the vmlinux address if
|
||||
* there's no better option.
|
||||
*/
|
||||
if (mode != PSR_MODE_EL2t && mode != PSR_MODE_EL2h) {
|
||||
kvm_err("Invalid host exception to nVHE hyp!\n");
|
||||
} else if (ESR_ELx_EC(esr) == ESR_ELx_EC_BRK64 &&
|
||||
(esr & ESR_ELx_BRK64_ISS_COMMENT_MASK) == BUG_BRK_IMM) {
|
||||
struct bug_entry *bug = find_bug(elr_in_kimg);
|
||||
const char *file = NULL;
|
||||
unsigned int line = 0;
|
||||
|
||||
/* All hyp bugs, including warnings, are treated as fatal. */
|
||||
if (bug)
|
||||
bug_get_file_line(bug, &file, &line);
|
||||
|
||||
if (file)
|
||||
kvm_err("nVHE hyp BUG at: %s:%u!\n", file, line);
|
||||
else
|
||||
kvm_err("nVHE hyp BUG at: %016llx!\n", elr + hyp_offset);
|
||||
} else {
|
||||
kvm_err("nVHE hyp panic at: %016llx!\n", elr + hyp_offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* Hyp has panicked and we're going to handle that by panicking the
|
||||
* kernel. The kernel offset will be revealed in the panic so we're
|
||||
* also safe to reveal the hyp offset as a debugging aid for translating
|
||||
* hyp VAs to vmlinux addresses.
|
||||
*/
|
||||
kvm_err("Hyp Offset: 0x%llx\n", hyp_offset);
|
||||
|
||||
panic("HYP panic:\nPS:%08llx PC:%016llx ESR:%08llx\nFAR:%016llx HPFAR:%016llx PAR:%016llx\nVCPU:%016lx\n",
|
||||
spsr, elr, esr, far, hpfar, par, vcpu);
|
||||
}
|
||||
|
|
|
@ -30,8 +30,6 @@
|
|||
#include <asm/processor.h>
|
||||
#include <asm/thread_info.h>
|
||||
|
||||
extern const char __hyp_panic_string[];
|
||||
|
||||
extern struct exception_table_entry __start___kvm_ex_table;
|
||||
extern struct exception_table_entry __stop___kvm_ex_table;
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ static inline void hyp_set_page_refcounted(struct hyp_page *p)
|
|||
hyp_spin_lock(&pool->lock);
|
||||
if (p->refcount) {
|
||||
hyp_spin_unlock(&pool->lock);
|
||||
hyp_panic();
|
||||
BUG();
|
||||
}
|
||||
p->refcount = 1;
|
||||
hyp_spin_unlock(&pool->lock);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#ifndef __KVM_HYP_MEMORY_H
|
||||
#define __KVM_HYP_MEMORY_H
|
||||
|
||||
#include <asm/kvm_mmu.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
|
@ -14,11 +15,9 @@ struct hyp_page {
|
|||
struct list_head node;
|
||||
};
|
||||
|
||||
extern s64 hyp_physvirt_offset;
|
||||
extern u64 __hyp_vmemmap;
|
||||
#define hyp_vmemmap ((struct hyp_page *)__hyp_vmemmap)
|
||||
|
||||
#define __hyp_pa(virt) ((phys_addr_t)(virt) + hyp_physvirt_offset)
|
||||
#define __hyp_va(phys) ((void *)((phys_addr_t)(phys) - hyp_physvirt_offset))
|
||||
|
||||
static inline void *hyp_phys_to_virt(phys_addr_t phys)
|
||||
|
|
|
@ -79,22 +79,18 @@ SYM_FUNC_START(__hyp_do_panic)
|
|||
mov lr, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
|
||||
PSR_MODE_EL1h)
|
||||
msr spsr_el2, lr
|
||||
ldr lr, =panic
|
||||
ldr lr, =nvhe_hyp_panic_handler
|
||||
hyp_kimg_va lr, x6
|
||||
msr elr_el2, lr
|
||||
|
||||
mov x29, x0
|
||||
|
||||
/* Load the format string into x0 and arguments into x1-7 */
|
||||
ldr x0, =__hyp_panic_string
|
||||
hyp_kimg_va x0, x6
|
||||
|
||||
/* Load the format arguments into x1-7. */
|
||||
mov x6, x3
|
||||
get_vcpu_ptr x7, x3
|
||||
mrs x3, esr_el2
|
||||
mrs x4, far_el2
|
||||
mrs x5, hpfar_el2
|
||||
/* Load the panic arguments into x0-7 */
|
||||
mrs x0, esr_el2
|
||||
get_vcpu_ptr x4, x5
|
||||
mrs x5, far_el2
|
||||
mrs x6, hpfar_el2
|
||||
mov x7, xzr // Unused argument
|
||||
|
||||
/* Enter the host, conditionally restoring the host context. */
|
||||
cbz x29, __host_enter_without_restoring
|
||||
|
|
|
@ -251,6 +251,6 @@ void handle_trap(struct kvm_cpu_context *host_ctxt)
|
|||
handle_host_mem_abort(host_ctxt);
|
||||
break;
|
||||
default:
|
||||
hyp_panic();
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@ u64 __ro_after_init hyp_cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = INVALID
|
|||
|
||||
u64 cpu_logical_map(unsigned int cpu)
|
||||
{
|
||||
if (cpu >= ARRAY_SIZE(hyp_cpu_logical_map))
|
||||
hyp_panic();
|
||||
BUG_ON(cpu >= ARRAY_SIZE(hyp_cpu_logical_map));
|
||||
|
||||
return hyp_cpu_logical_map[cpu];
|
||||
}
|
||||
|
@ -30,8 +29,7 @@ unsigned long __hyp_per_cpu_offset(unsigned int cpu)
|
|||
unsigned long this_cpu_base;
|
||||
unsigned long elf_base;
|
||||
|
||||
if (cpu >= ARRAY_SIZE(kvm_arm_hyp_percpu_base))
|
||||
hyp_panic();
|
||||
BUG_ON(cpu >= ARRAY_SIZE(kvm_arm_hyp_percpu_base));
|
||||
|
||||
cpu_base_array = (unsigned long *)&kvm_arm_hyp_percpu_base;
|
||||
this_cpu_base = kern_hyp_va(cpu_base_array[cpu]);
|
||||
|
|
|
@ -271,11 +271,9 @@ void handle_host_mem_abort(struct kvm_cpu_context *host_ctxt)
|
|||
int ret = 0;
|
||||
|
||||
esr = read_sysreg_el2(SYS_ESR);
|
||||
if (!__get_fault_info(esr, &fault))
|
||||
hyp_panic();
|
||||
BUG_ON(!__get_fault_info(esr, &fault));
|
||||
|
||||
addr = (fault.hpfar_el2 & HPFAR_MASK) << 8;
|
||||
ret = host_stage2_idmap(addr);
|
||||
if (ret && ret != -EAGAIN)
|
||||
hyp_panic();
|
||||
BUG_ON(ret && ret != -EAGAIN);
|
||||
}
|
||||
|
|
|
@ -27,8 +27,6 @@
|
|||
#include <asm/processor.h>
|
||||
#include <asm/thread_info.h>
|
||||
|
||||
const char __hyp_panic_string[] = "HYP panic:\nPS:%08llx PC:%016llx ESR:%08llx\nFAR:%016llx HPFAR:%016llx PAR:%016llx\nVCPU:%p\n";
|
||||
|
||||
/* VHE specific context */
|
||||
DEFINE_PER_CPU(struct kvm_host_data, kvm_host_data);
|
||||
DEFINE_PER_CPU(struct kvm_cpu_context, kvm_hyp_ctxt);
|
||||
|
@ -207,7 +205,7 @@ static void __hyp_call_panic(u64 spsr, u64 elr, u64 par)
|
|||
__deactivate_traps(vcpu);
|
||||
sysreg_restore_host_state_vhe(host_ctxt);
|
||||
|
||||
panic(__hyp_panic_string,
|
||||
panic("HYP panic:\nPS:%08llx PC:%016llx ESR:%08llx\nFAR:%016llx HPFAR:%016llx PAR:%016llx\nVCPU:%p\n",
|
||||
spsr, elr,
|
||||
read_sysreg_el2(SYS_ESR), read_sysreg_el2(SYS_FAR),
|
||||
read_sysreg(hpfar_el2), par, vcpu);
|
||||
|
|
|
@ -36,6 +36,9 @@ static inline int is_warning_bug(const struct bug_entry *bug)
|
|||
return bug->flags & BUGFLAG_WARNING;
|
||||
}
|
||||
|
||||
void bug_get_file_line(struct bug_entry *bug, const char **file,
|
||||
unsigned int *line);
|
||||
|
||||
struct bug_entry *find_bug(unsigned long bugaddr);
|
||||
|
||||
enum bug_trap_type report_bug(unsigned long bug_addr, struct pt_regs *regs);
|
||||
|
|
50
lib/bug.c
50
lib/bug.c
|
@ -127,6 +127,22 @@ static inline struct bug_entry *module_find_bug(unsigned long bugaddr)
|
|||
}
|
||||
#endif
|
||||
|
||||
void bug_get_file_line(struct bug_entry *bug, const char **file,
|
||||
unsigned int *line)
|
||||
{
|
||||
#ifdef CONFIG_DEBUG_BUGVERBOSE
|
||||
#ifndef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
|
||||
*file = bug->file;
|
||||
#else
|
||||
*file = (const char *)bug + bug->file_disp;
|
||||
#endif
|
||||
*line = bug->line;
|
||||
#else
|
||||
*file = NULL;
|
||||
*line = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
struct bug_entry *find_bug(unsigned long bugaddr)
|
||||
{
|
||||
struct bug_entry *bug;
|
||||
|
@ -153,32 +169,20 @@ enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs)
|
|||
|
||||
disable_trace_on_warning();
|
||||
|
||||
file = NULL;
|
||||
line = 0;
|
||||
warning = 0;
|
||||
bug_get_file_line(bug, &file, &line);
|
||||
|
||||
if (bug) {
|
||||
#ifdef CONFIG_DEBUG_BUGVERBOSE
|
||||
#ifndef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
|
||||
file = bug->file;
|
||||
#else
|
||||
file = (const char *)bug + bug->file_disp;
|
||||
#endif
|
||||
line = bug->line;
|
||||
#endif
|
||||
warning = (bug->flags & BUGFLAG_WARNING) != 0;
|
||||
once = (bug->flags & BUGFLAG_ONCE) != 0;
|
||||
done = (bug->flags & BUGFLAG_DONE) != 0;
|
||||
warning = (bug->flags & BUGFLAG_WARNING) != 0;
|
||||
once = (bug->flags & BUGFLAG_ONCE) != 0;
|
||||
done = (bug->flags & BUGFLAG_DONE) != 0;
|
||||
|
||||
if (warning && once) {
|
||||
if (done)
|
||||
return BUG_TRAP_TYPE_WARN;
|
||||
if (warning && once) {
|
||||
if (done)
|
||||
return BUG_TRAP_TYPE_WARN;
|
||||
|
||||
/*
|
||||
* Since this is the only store, concurrency is not an issue.
|
||||
*/
|
||||
bug->flags |= BUGFLAG_DONE;
|
||||
}
|
||||
/*
|
||||
* Since this is the only store, concurrency is not an issue.
|
||||
*/
|
||||
bug->flags |= BUGFLAG_DONE;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Загрузка…
Ссылка в новой задаче