Skip to content

Commit 32314d9

Browse files
author
Marc Zyngier
committed
Merge branch kvm-arm64/dump-instr into kvmarm-master/next
* kvm-arm64/dump-instr: : . : Dump the isntruction stream on panic, just like the rest of the kernel : already does. : : Patches courtesy of Mostafa Saleh (20250909133631.3844423-1-smostafa@google.com) : . KVM: arm64: Map hyp text as RO and dump instr on panic KVM: arm64: Dump instruction on hyp panic Signed-off-by: Marc Zyngier <maz@kernel.org>
2 parents 295593a + 6f1ece1 commit 32314d9

4 files changed

Lines changed: 23 additions & 8 deletions

File tree

arch/arm64/include/asm/traps.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ int kasan_brk_handler(struct pt_regs *regs, unsigned long esr);
3636
int ubsan_brk_handler(struct pt_regs *regs, unsigned long esr);
3737

3838
int early_brk64(unsigned long addr, unsigned long esr, struct pt_regs *regs);
39+
void dump_kernel_instr(unsigned long kaddr);
3940

4041
/*
4142
* Move regs->pc to next instruction and do necessary setup before it

arch/arm64/kernel/traps.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -149,27 +149,26 @@ pstate_check_t * const aarch32_opcode_cond_checks[16] = {
149149

150150
int show_unhandled_signals = 0;
151151

152-
static void dump_kernel_instr(const char *lvl, struct pt_regs *regs)
152+
void dump_kernel_instr(unsigned long kaddr)
153153
{
154-
unsigned long addr = instruction_pointer(regs);
155154
char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str;
156155
int i;
157156

158-
if (user_mode(regs))
157+
if (!is_ttbr1_addr(kaddr))
159158
return;
160159

161160
for (i = -4; i < 1; i++) {
162161
unsigned int val, bad;
163162

164-
bad = aarch64_insn_read(&((u32 *)addr)[i], &val);
163+
bad = aarch64_insn_read(&((u32 *)kaddr)[i], &val);
165164

166165
if (!bad)
167166
p += sprintf(p, i == 0 ? "(%08x) " : "%08x ", val);
168167
else
169168
p += sprintf(p, i == 0 ? "(????????) " : "???????? ");
170169
}
171170

172-
printk("%sCode: %s\n", lvl, str);
171+
printk(KERN_EMERG "Code: %s\n", str);
173172
}
174173

175174
#define S_SMP " SMP"
@@ -178,6 +177,7 @@ static int __die(const char *str, long err, struct pt_regs *regs)
178177
{
179178
static int die_counter;
180179
int ret;
180+
unsigned long addr = instruction_pointer(regs);
181181

182182
pr_emerg("Internal error: %s: %016lx [#%d] " S_SMP "\n",
183183
str, err, ++die_counter);
@@ -190,7 +190,10 @@ static int __die(const char *str, long err, struct pt_regs *regs)
190190
print_modules();
191191
show_regs(regs);
192192

193-
dump_kernel_instr(KERN_EMERG, regs);
193+
if (user_mode(regs))
194+
return ret;
195+
196+
dump_kernel_instr(addr);
194197

195198
return ret;
196199
}

arch/arm64/kvm/handle_exit.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,9 @@ void __noreturn __cold nvhe_hyp_panic_handler(u64 esr, u64 spsr,
559559
/* Dump the nVHE hypervisor backtrace */
560560
kvm_nvhe_dump_backtrace(hyp_offset);
561561

562+
/* Dump the faulting instruction */
563+
dump_kernel_instr(panic_addr + kaslr_offset());
564+
562565
/*
563566
* Hyp has panicked and we're going to handle that by panicking the
564567
* kernel. The kernel offset will be revealed in the panic so we're

arch/arm64/kvm/hyp/nvhe/setup.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ static int fix_host_ownership_walker(const struct kvm_pgtable_visit_ctx *ctx,
192192
enum pkvm_page_state state;
193193
struct hyp_page *page;
194194
phys_addr_t phys;
195+
enum kvm_pgtable_prot prot;
195196

196197
if (!kvm_pte_valid(ctx->old))
197198
return 0;
@@ -210,11 +211,18 @@ static int fix_host_ownership_walker(const struct kvm_pgtable_visit_ctx *ctx,
210211
* configured in the hypervisor stage-1, and make sure to propagate them
211212
* to the hyp_vmemmap state.
212213
*/
213-
state = pkvm_getstate(kvm_pgtable_hyp_pte_prot(ctx->old));
214+
prot = kvm_pgtable_hyp_pte_prot(ctx->old);
215+
state = pkvm_getstate(prot);
214216
switch (state) {
215217
case PKVM_PAGE_OWNED:
216218
set_hyp_state(page, PKVM_PAGE_OWNED);
217-
return host_stage2_set_owner_locked(phys, PAGE_SIZE, PKVM_ID_HYP);
219+
/* hyp text is RO in the host stage-2 to be inspected on panic. */
220+
if (prot == PAGE_HYP_EXEC) {
221+
set_host_state(page, PKVM_NOPAGE);
222+
return host_stage2_idmap_locked(phys, PAGE_SIZE, KVM_PGTABLE_PROT_R);
223+
} else {
224+
return host_stage2_set_owner_locked(phys, PAGE_SIZE, PKVM_ID_HYP);
225+
}
218226
case PKVM_PAGE_SHARED_OWNED:
219227
set_hyp_state(page, PKVM_PAGE_SHARED_OWNED);
220228
set_host_state(page, PKVM_PAGE_SHARED_BORROWED);

0 commit comments

Comments
 (0)