一些内核的ARM代码

我正在阅读一些ARM内核源码,直到我偶然发现了以下function:

314 #define __get_user_asm_byte(x, addr, err) \ 315 __asm__ __volatile__( \ 316 "1: " TUSER(ldrb) " %1,[%2],#0\n" \ 317 "2:\n" \ 318 " .pushsection .fixup,\"ax\"\n" \ 319 " .align 2\n" \ 320 "3: mov %0, %3\n" \ 321 " mov %1, #0\n" \ 322 " b 2b\n" \ 323 " .popsection\n" \ 324 " .pushsection __ex_table,\"a\"\n" \ 325 " .align 3\n" \ 326 " .long 1b, 3b\n" \ 327 " .popsection" \ 328 : "+r" (err), "=&r" (x) \ 329 : "r" (addr), "i" (-EFAULT) \ 330 : "cc") 

调用上下文似乎如下:

 299 #define __get_user_err(x, ptr, err) \ 300 do { \ 301 unsigned long __gu_addr = (unsigned long)(ptr); \ 302 unsigned long __gu_val; \ 303 __chk_user_ptr(ptr); \ 304 might_fault(); \ 305 switch (sizeof(*(ptr))) { \ 306 case 1: __get_user_asm_byte(__gu_val, __gu_addr, err); break; \ 

现在我想清楚一下上面的ARM组件。

  1. __get_user_asm_byte在做什么function? 我可以看到r3被复制到r0中,并且值0被移动到r1中。 之后,它分支到偏移量0x2b?
  2. 试图做什么function? 328行以后的"+r" (err), "=&r" (x)是什么意思?
  3. 什么是.pushsection和.popsection?
  4. 为什么针对内核编写的ARM程序集在语法上如此不同(汇编程序使用了什么?为什么有%<regno>而不是r<regno> ?)

首先,正如注释已经注意到的那样,语法是标准的gcc内联汇编语法( +r=&r%<arg>部分)。

其余的内核就是用来处理页面错误的。 get_user_asm_byte的要点是从用户空间拉出一个字节。 但是,在从用户空间提取数据时,需要适应两种特殊情况:

  1. 一个完全合法的用户空间地址,目前根本不存在(即通常是因为它已被换出)
  2. 非法的用户空间地址。

要么可能会导致页面错误。 对于(1),期望的行为是恢复用户页面(从交换空间或其他任何地方读取它),然后重新执行加载指令,最终成功; 对于(2),期望的行为是在不重试的情况下使操作失败,并将EFAULT错误返回给调用者。

如果没有特殊处理,内核模式下页面错误的正常行为是“Oops”。 特殊部分与页面错误处理代码一起协调,并能够正确恢复。 如果你想了解这个工作的细节,在内核源代码中搜索__ex_table

另外,签出内核文档在: Documentation / x86 / exception-tables.txt

唯一的ARM特定项目是使用ldrt或MMU域; 这是在domain.h中的条件。 现代ARM CPU支持域。 已翻译的加载/存储变体为较旧的CPU应用用户模式访问。