Linux kernel mm 异常处理 on arm

linux中的虚拟地址需要通过MMU映射到物理地址。但当这个映射过程无法正常映射时候,就会报错。那么什么时候会无法正常呢?

  • 编程错误。程序使用了不存在的地址
  • 不是编程错误,linux的请求调页机制。即:当进程运行时,linux并不将全部的资源分配给进程,而是仅分配当前需要的这一部分,当进程需要另外的资源的时候(这时候就会产生缺页异常),linux再分配这部分。

 编程错误linux肯定不会手软的,直接弄死进程。请求调页机制,linux会申请页的。

错误处理结构定义:

struct fsr_info {
 int (*fn)(unsigned long addr, unsigned int fsr, struct pt_regs *regs);
 int sig;
 int code;
 const char *name;
};

具体实现:

/* FSR definition */
#ifdef CONFIG_ARM_LPAE
#include "fsr-3level.c"
#else
#include "fsr-2level.c"
#endif
上面数组形式是静态定义的,内核也支持动态定义hook,函数hook_fault_code支持动态设置,如下:

void __init
hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *),
  int sig, int code, const char *name)
{
 if (nr < 0 || nr >= ARRAY_SIZE(fsr_info))
  BUG();

 fsr_info[nr].fn   = fn;
 fsr_info[nr].sig  = sig;
 fsr_info[nr].code = code;
 fsr_info[nr].name = name;
}

void __init
hook_ifault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *),
   int sig, int code, const char *name)
{
 if (nr < 0 || nr >= ARRAY_SIZE(ifsr_info))
  BUG();

 ifsr_info[nr].fn   = fn;
 ifsr_info[nr].sig  = sig;
 ifsr_info[nr].code = code;
 ifsr_info[nr].name = name;
}

 

 

数据异常调用:

asmlinkage void __exception
do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
 const struct fsr_info *inf = fsr_info + fsr_fs(fsr);
 struct siginfo info;

 if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs))
  return;

 printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n",
  inf->name, fsr, addr);

 info.si_signo = inf->sig;
 info.si_errno = 0;
 info.si_code  = inf->code;
 info.si_addr  = (void __user *)addr;
 arm_notify_die("", regs, &info, fsr, 0);
}

 

 

预取异常:

asmlinkage void __exception
do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs)
{
 const struct fsr_info *inf = ifsr_info + fsr_fs(ifsr);
 struct siginfo info;

 if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs))
  return;

 printk(KERN_ALERT "Unhandled prefetch abort: %s (0x%03x) at 0x%08lx\n",
  inf->name, ifsr, addr);

 info.si_signo = inf->sig;
 info.si_errno = 0;
 info.si_code  = inf->code;
 info.si_addr  = (void __user *)addr;
 arm_notify_die("", regs, &info, ifsr, 0);
}

 

fsr-3level.c

static struct fsr_info fsr_info[] = {
 { do_bad,  SIGBUS,  0,  "unknown 0"   },
 { do_bad,  SIGBUS,  0,  "unknown 1"   },
 { do_bad,  SIGBUS,  0,  "unknown 2"   },
 { do_bad,  SIGBUS,  0,  "unknown 3"   },
 { do_bad,  SIGBUS,  0,  "reserved translation fault" },
 { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 1 translation fault" },
 { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 2 translation fault" },
 { do_page_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" },
 { do_bad,  SIGBUS,  0,  "reserved access flag fault" },
 { do_bad,  SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" },
 { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" },
 { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 access flag fault" },
 { do_bad,  SIGBUS,  0,  "reserved permission fault" },
 { do_bad,  SIGSEGV, SEGV_ACCERR, "level 1 permission fault" },
 { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" },
 { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 permission fault" },
 { do_bad,  SIGBUS,  0,  "synchronous external abort" },
 { do_bad,  SIGBUS,  0,  "asynchronous external abort" },
 { do_bad,  SIGBUS,  0,  "unknown 18"   },
 { do_bad,  SIGBUS,  0,  "unknown 19"   },
 { do_bad,  SIGBUS,  0,  "synchronous abort (translation table walk)" },
 { do_bad,  SIGBUS,  0,  "synchronous abort (translation table walk)" },
 { do_bad,  SIGBUS,  0,  "synchronous abort (translation table walk)" },
 { do_bad,  SIGBUS,  0,  "synchronous abort (translation table walk)" },
 { do_bad,  SIGBUS,  0,  "synchronous parity error" },
 { do_bad,  SIGBUS,  0,  "asynchronous parity error" },
 { do_bad,  SIGBUS,  0,  "unknown 26"   },
 { do_bad,  SIGBUS,  0,  "unknown 27"   },
 { do_bad,  SIGBUS,  0,  "synchronous parity error (translation table walk" },
 { do_bad,  SIGBUS,  0,  "synchronous parity error (translation table walk" },
 { do_bad,  SIGBUS,  0,  "synchronous parity error (translation table walk" },
 { do_bad,  SIGBUS,  0,  "synchronous parity error (translation table walk" },
 { do_bad,  SIGBUS,  0,  "unknown 32"   },
 { do_bad,  SIGBUS,  BUS_ADRALN, "alignment fault"  },
 { do_bad,  SIGBUS,  0,  "debug event"   },
 { do_bad,  SIGBUS,  0,  "unknown 35"   },
 { do_bad,  SIGBUS,  0,  "unknown 36"   },
 { do_bad,  SIGBUS,  0,  "unknown 37"   },
 { do_bad,  SIGBUS,  0,  "unknown 38"   },
 { do_bad,  SIGBUS,  0,  "unknown 39"   },
 { do_bad,  SIGBUS,  0,  "unknown 40"   },
 { do_bad,  SIGBUS,  0,  "unknown 41"   },
 { do_bad,  SIGBUS,  0,  "unknown 42"   },
 { do_bad,  SIGBUS,  0,  "unknown 43"   },
 { do_bad,  SIGBUS,  0,  "unknown 44"   },
 { do_bad,  SIGBUS,  0,  "unknown 45"   },
 { do_bad,  SIGBUS,  0,  "unknown 46"   },
 { do_bad,  SIGBUS,  0,  "unknown 47"   },
 { do_bad,  SIGBUS,  0,  "unknown 48"   },
 { do_bad,  SIGBUS,  0,  "unknown 49"   },
 { do_bad,  SIGBUS,  0,  "unknown 50"   },
 { do_bad,  SIGBUS,  0,  "unknown 51"   },
 { do_bad,  SIGBUS,  0,  "implementation fault (lockdown abort)" },
 { do_bad,  SIGBUS,  0,  "unknown 53"   },
 { do_bad,  SIGBUS,  0,  "unknown 54"   },
 { do_bad,  SIGBUS,  0,  "unknown 55"   },
 { do_bad,  SIGBUS,  0,  "unknown 56"   },
 { do_bad,  SIGBUS,  0,  "unknown 57"   },
 { do_bad,  SIGBUS,  0,  "implementation fault (coprocessor abort)" },
 { do_bad,  SIGBUS,  0,  "unknown 59"   },
 { do_bad,  SIGBUS,  0,  "unknown 60"   },
 { do_bad,  SIGBUS,  0,  "unknown 61"   },
 { do_bad,  SIGBUS,  0,  "unknown 62"   },
 { do_bad,  SIGBUS,  0,  "unknown 63"   },
};

#define ifsr_info fsr_info

 

 

 

fsr-2level.c

static struct fsr_info fsr_info[] = {
 /*
  * The following are the standard ARMv3 and ARMv4 aborts.  ARMv5
  * defines these to be "precise" aborts.
  */
 { do_bad,  SIGSEGV, 0,  "vector exception"     },
 { do_bad,  SIGBUS,  BUS_ADRALN, "alignment exception"     },
 { do_bad,  SIGKILL, 0,  "terminal exception"     },
 { do_bad,  SIGBUS,  BUS_ADRALN, "alignment exception"     },
 { do_bad,  SIGBUS,  0,  "external abort on linefetch"    },
 { do_translation_fault, SIGSEGV, SEGV_MAPERR, "section translation fault"    },
 { do_bad,  SIGBUS,  0,  "external abort on linefetch"    },
 { do_page_fault, SIGSEGV, SEGV_MAPERR, "page translation fault"    },
 { do_bad,  SIGBUS,  0,  "external abort on non-linefetch"  },
 { do_bad,  SIGSEGV, SEGV_ACCERR, "section domain fault"     },
 { do_bad,  SIGBUS,  0,  "external abort on non-linefetch"  },
 { do_bad,  SIGSEGV, SEGV_ACCERR, "page domain fault"     },
 { do_bad,  SIGBUS,  0,  "external abort on translation"    },
 { do_sect_fault, SIGSEGV, SEGV_ACCERR, "section permission fault"    },
 { do_bad,  SIGBUS,  0,  "external abort on translation"    },
 { do_page_fault, SIGSEGV, SEGV_ACCERR, "page permission fault"     },
 /*
  * The following are "imprecise" aborts, which are signalled by bit
  * 10 of the FSR, and may not be recoverable.  These are only
  * supported if the CPU abort handler supports bit 10.
  */
 { do_bad,  SIGBUS,  0,  "unknown 16"      },
 { do_bad,  SIGBUS,  0,  "unknown 17"      },
 { do_bad,  SIGBUS,  0,  "unknown 18"      },
 { do_bad,  SIGBUS,  0,  "unknown 19"      },
 { do_bad,  SIGBUS,  0,  "lock abort"      }, /* xscale */
 { do_bad,  SIGBUS,  0,  "unknown 21"      },
 { do_bad,  SIGBUS,  BUS_OBJERR, "imprecise external abort"    }, /* xscale */
 { do_bad,  SIGBUS,  0,  "unknown 23"      },
 { do_bad,  SIGBUS,  0,  "dcache parity error"     }, /* xscale */
 { do_bad,  SIGBUS,  0,  "unknown 25"      },
 { do_bad,  SIGBUS,  0,  "unknown 26"      },
 { do_bad,  SIGBUS,  0,  "unknown 27"      },
 { do_bad,  SIGBUS,  0,  "unknown 28"      },
 { do_bad,  SIGBUS,  0,  "unknown 29"      },
 { do_bad,  SIGBUS,  0,  "unknown 30"      },
 { do_bad,  SIGBUS,  0,  "unknown 31"      },
};

static struct fsr_info ifsr_info[] = {
 { do_bad,  SIGBUS,  0,  "unknown 0"      },
 { do_bad,  SIGBUS,  0,  "unknown 1"      },
 { do_bad,  SIGBUS,  0,  "debug event"      },
 { do_bad,  SIGSEGV, SEGV_ACCERR, "section access flag fault"    },
 { do_bad,  SIGBUS,  0,  "unknown 4"      },
 { do_translation_fault, SIGSEGV, SEGV_MAPERR, "section translation fault"    },
 { do_bad,  SIGSEGV, SEGV_ACCERR, "page access flag fault"    },
 { do_page_fault, SIGSEGV, SEGV_MAPERR, "page translation fault"    },
 { do_bad,  SIGBUS,  0,  "external abort on non-linefetch"  },
 { do_bad,  SIGSEGV, SEGV_ACCERR, "section domain fault"     },
 { do_bad,  SIGBUS,  0,  "unknown 10"      },
 { do_bad,  SIGSEGV, SEGV_ACCERR, "page domain fault"     },
 { do_bad,  SIGBUS,  0,  "external abort on translation"    },
 { do_sect_fault, SIGSEGV, SEGV_ACCERR, "section permission fault"    },
 { do_bad,  SIGBUS,  0,  "external abort on translation"    },
 { do_page_fault, SIGSEGV, SEGV_ACCERR, "page permission fault"     },
 { do_bad,  SIGBUS,  0,  "unknown 16"      },
 { do_bad,  SIGBUS,  0,  "unknown 17"      },
 { do_bad,  SIGBUS,  0,  "unknown 18"      },
 { do_bad,  SIGBUS,  0,  "unknown 19"      },
 { do_bad,  SIGBUS,  0,  "unknown 20"      },
 { do_bad,  SIGBUS,  0,  "unknown 21"      },
 { do_bad,  SIGBUS,  0,  "unknown 22"      },
 { do_bad,  SIGBUS,  0,  "unknown 23"      },
 { do_bad,  SIGBUS,  0,  "unknown 24"      },
 { do_bad,  SIGBUS,  0,  "unknown 25"      },
 { do_bad,  SIGBUS,  0,  "unknown 26"      },
 { do_bad,  SIGBUS,  0,  "unknown 27"      },
 { do_bad,  SIGBUS,  0,  "unknown 28"      },
 { do_bad,  SIGBUS,  0,  "unknown 29"      },
 { do_bad,  SIGBUS,  0,  "unknown 30"      },
 { do_bad,  SIGBUS,  0,  "unknown 31"      },
};

 

 

你可能感兴趣的:(ARM,体系架构,Linux,Kernel)