arm: Dump additional fault registers in abort handlers
Paging code is tricky and figuring out what is wrong with it can be a pain. This patch tries to ease the burden by giving a little more information for prefetch and data aborts, dumping the Instruction Fault Address Register (IFAR), Instruction Fault Status Register (IFSR) and Auxiliary Instruction Fault Status Register (AIFSR) or the respective Data registers. These contain additional information about the cause of the abort (internal/external, write or read, fault subtype, etc.) and the faulting address. BUG=None TEST=I have read through enough imprecise asynchronous external abort reports with this patch that I learned the bit pattern by heart. Change-Id: I56a0557d4257f40b5b30c559c84eaf9b9f729099 Signed-off-by: Julius Werner <jwerner@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/223784 Reviewed-by: Aaron Durbin <adurbin@chromium.org>
This commit is contained in:
parent
7d7aa89238
commit
bf3b492412
4 changed files with 114 additions and 0 deletions
|
|
@ -90,6 +90,18 @@ void exception_dispatch(u32 idx)
|
|||
|
||||
printf("%s Exception\n", names[idx]);
|
||||
print_regs();
|
||||
switch (idx) {
|
||||
case EXC_PABORT:
|
||||
printf("IFAR = %#.8x\n", read_ifar());
|
||||
printf("IFSR = %#.8x\n", read_ifsr());
|
||||
printf("AIFSR = %#.8x\n", read_aifsr());
|
||||
break;
|
||||
case EXC_DABORT:
|
||||
printf("DFAR = %#.8x\n", read_dfar());
|
||||
printf("DFSR = %#.8x\n", read_dfsr());
|
||||
printf("ADFSR = %#.8x\n", read_adfsr());
|
||||
break;
|
||||
};
|
||||
dump_stack(exception_state.regs[13], 512);
|
||||
halt();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -268,6 +268,54 @@ static inline void write_sctlr(uint32_t val)
|
|||
isb();
|
||||
}
|
||||
|
||||
/* read data fault address register (DFAR) */
|
||||
static inline uint32_t read_dfar(void)
|
||||
{
|
||||
uint32_t val;
|
||||
asm volatile ("mrc p15, 0, %0, c6, c0, 0" : "=r" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
/* read data fault status register (DFSR) */
|
||||
static inline uint32_t read_dfsr(void)
|
||||
{
|
||||
uint32_t val;
|
||||
asm volatile ("mrc p15, 0, %0, c5, c0, 0" : "=r" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
/* read instruction fault address register (IFAR) */
|
||||
static inline uint32_t read_ifar(void)
|
||||
{
|
||||
uint32_t val;
|
||||
asm volatile ("mrc p15, 0, %0, c6, c0, 2" : "=r" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
/* read instruction fault status register (IFSR) */
|
||||
static inline uint32_t read_ifsr(void)
|
||||
{
|
||||
uint32_t val;
|
||||
asm volatile ("mrc p15, 0, %0, c5, c0, 1" : "=r" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
/* read auxiliary data fault status register (ADFSR) */
|
||||
static inline uint32_t read_adfsr(void)
|
||||
{
|
||||
uint32_t val;
|
||||
asm volatile ("mrc p15, 0, %0, c5, c1, 0" : "=r" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
/* read auxiliary instruction fault status register (AIFSR) */
|
||||
static inline uint32_t read_aifsr(void)
|
||||
{
|
||||
uint32_t val;
|
||||
asm volatile ("mrc p15, 0, %0, c5, c1, 1" : "=r" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cache maintenance API
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -100,6 +100,9 @@ void exception_prefetch_abort(uint32_t *regs)
|
|||
printk(BIOS_ERR, "exception _prefetch_abort\n");
|
||||
regs[15] -= 4;
|
||||
print_regs(regs);
|
||||
printk(BIOS_ERR, "IFAR = %#.8x\n", read_ifar());
|
||||
printk(BIOS_ERR, "IFSR = %#.8x\n", read_ifsr());
|
||||
printk(BIOS_ERR, "AIFSR = %#.8x\n", read_aifsr());
|
||||
dump_stack(regs[13], 512);
|
||||
die("exception");
|
||||
}
|
||||
|
|
@ -109,6 +112,9 @@ void exception_data_abort(uint32_t *regs)
|
|||
printk(BIOS_ERR, "exception _data_abort\n");
|
||||
regs[15] -= 8;
|
||||
print_regs(regs);
|
||||
printk(BIOS_ERR, "DFAR = %#.8x\n", read_dfar());
|
||||
printk(BIOS_ERR, "DFSR = %#.8x\n", read_dfsr());
|
||||
printk(BIOS_ERR, "ADFSR = %#.8x\n", read_adfsr());
|
||||
dump_stack(regs[13], 512);
|
||||
die("exception");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -296,6 +296,54 @@ static inline void write_sctlr(uint32_t val)
|
|||
isb();
|
||||
}
|
||||
|
||||
/* read data fault address register (DFAR) */
|
||||
static inline uint32_t read_dfar(void)
|
||||
{
|
||||
uint32_t val;
|
||||
asm volatile ("mrc p15, 0, %0, c6, c0, 0" : "=r" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
/* read data fault status register (DFSR) */
|
||||
static inline uint32_t read_dfsr(void)
|
||||
{
|
||||
uint32_t val;
|
||||
asm volatile ("mrc p15, 0, %0, c5, c0, 0" : "=r" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
/* read instruction fault address register (IFAR) */
|
||||
static inline uint32_t read_ifar(void)
|
||||
{
|
||||
uint32_t val;
|
||||
asm volatile ("mrc p15, 0, %0, c6, c0, 2" : "=r" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
/* read instruction fault status register (IFSR) */
|
||||
static inline uint32_t read_ifsr(void)
|
||||
{
|
||||
uint32_t val;
|
||||
asm volatile ("mrc p15, 0, %0, c5, c0, 1" : "=r" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
/* read auxiliary data fault status register (ADFSR) */
|
||||
static inline uint32_t read_adfsr(void)
|
||||
{
|
||||
uint32_t val;
|
||||
asm volatile ("mrc p15, 0, %0, c5, c1, 0" : "=r" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
/* read auxiliary instruction fault status register (AIFSR) */
|
||||
static inline uint32_t read_aifsr(void)
|
||||
{
|
||||
uint32_t val;
|
||||
asm volatile ("mrc p15, 0, %0, c5, c1, 1" : "=r" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cache maintenance API
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue