Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: arm64: Dump instruction on hyp panic

Similar to the kernel panic, where the instruction code is printed,
we can do the same for hypervisor panics.

This patch does that only in case of “CONFIG_NVHE_EL2_DEBUG” or nvhe.

The next patch adds support for pKVM.

Also, remove the hardcoded argument dump_kernel_instr().

Signed-off-by: Mostafa Saleh <smostafa@google.com>
Tested-by: Kunwu Chan <chentao@kylinos.cn>
Reviewed-by: Kunwu Chan <chentao@kylinos.cn>
Acked-by: Will Deacon <will@kernel.org>
Signed-off-by: Marc Zyngier <maz@kernel.org>

authored by

Mostafa Saleh and committed by
Marc Zyngier
92b7624f 1b237f19

+15 -6
+1
arch/arm64/include/asm/traps.h
··· 36 36 int ubsan_brk_handler(struct pt_regs *regs, unsigned long esr); 37 37 38 38 int early_brk64(unsigned long addr, unsigned long esr, struct pt_regs *regs); 39 + void dump_kernel_instr(unsigned long kaddr); 39 40 40 41 /* 41 42 * Move regs->pc to next instruction and do necessary setup before it
+9 -6
arch/arm64/kernel/traps.c
··· 149 149 150 150 int show_unhandled_signals = 0; 151 151 152 - static void dump_kernel_instr(const char *lvl, struct pt_regs *regs) 152 + void dump_kernel_instr(unsigned long kaddr) 153 153 { 154 - unsigned long addr = instruction_pointer(regs); 155 154 char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str; 156 155 int i; 157 156 158 - if (user_mode(regs)) 157 + if (!is_ttbr1_addr(kaddr)) 159 158 return; 160 159 161 160 for (i = -4; i < 1; i++) { 162 161 unsigned int val, bad; 163 162 164 - bad = aarch64_insn_read(&((u32 *)addr)[i], &val); 163 + bad = aarch64_insn_read(&((u32 *)kaddr)[i], &val); 165 164 166 165 if (!bad) 167 166 p += sprintf(p, i == 0 ? "(%08x) " : "%08x ", val); ··· 168 169 p += sprintf(p, i == 0 ? "(????????) " : "???????? "); 169 170 } 170 171 171 - printk("%sCode: %s\n", lvl, str); 172 + printk(KERN_EMERG "Code: %s\n", str); 172 173 } 173 174 174 175 #define S_SMP " SMP" ··· 177 178 { 178 179 static int die_counter; 179 180 int ret; 181 + unsigned long addr = instruction_pointer(regs); 180 182 181 183 pr_emerg("Internal error: %s: %016lx [#%d] " S_SMP "\n", 182 184 str, err, ++die_counter); ··· 190 190 print_modules(); 191 191 show_regs(regs); 192 192 193 - dump_kernel_instr(KERN_EMERG, regs); 193 + if (user_mode(regs)) 194 + return ret; 195 + 196 + dump_kernel_instr(addr); 194 197 195 198 return ret; 196 199 }
+5
arch/arm64/kvm/handle_exit.c
··· 559 559 /* Dump the nVHE hypervisor backtrace */ 560 560 kvm_nvhe_dump_backtrace(hyp_offset); 561 561 562 + /* Dump the faulting instruction */ 563 + if (!is_protected_kvm_enabled() || 564 + IS_ENABLED(CONFIG_NVHE_EL2_DEBUG)) 565 + dump_kernel_instr(panic_addr + kaslr_offset()); 566 + 562 567 /* 563 568 * Hyp has panicked and we're going to handle that by panicking the 564 569 * kernel. The kernel offset will be revealed in the panic so we're