// XK> Origin
Go deep into Linux kernel architecture P144. Read questions and try again.
// XK> foreshadowing
Generally, the virtual address space is divided into process address space and kernel address space by. The virtual address space of 32-bit machines with 4 GB memory is divided into kernel address space.
(1) The first 896m of the kernel address space is the physical page frame mapped directly, that is, the 896m on the physical memory can be directly mapped (through linear offset 0xc000000) to this area of the kernel address space.
(2) A short memory gap is used for Kernel Fault reporting.
(3) The vmalloc area is used for dynamic allocation. The kernel itself tries its best to avoid non-consecutive physical addresses. This memory area is mainly used for dynamic module loading.
(4) There is a protective interval of two pages of memory.
(5) next is the persistent ing area, which is used to map non-persistent pages in highmemory to the kernel. (In doubt, I am not seeking further explanation)
(6) The last is the fixed ing area until the virtual address is 4 GB. For the direct ing area described above, virtual address translation _ page_offset (0xc000000 on the IA-32) gets the physical address, and the fixed ing is different, virtual addresses in this area point to random physical addresses. The associations between virtual addresses and physical addresses can be freely defined, but cannot be changed after definition. The advantage of fixed ing is: 1. The processing of such addresses is similar to a constant during compilation. When the kernel is started, it is assigned a physical address. 2. Anti-reference of such addresses is faster than normal pointers. 3. the kernel ensures that the page table items corresponding to the fixed ing are not flushed from TLB during context switching. when accessing the fixed ing memory, the corresponding physical address is always obtained through the TLB cache.
// XK> body
A constant is created for each fixed ing address and added to the fixed_addresses enumerated Value List. __end_of_fixed_addresses is the last enumeration member and defines the maximum number of possible values. Linux_kernel_2.6.27.62/include/asm-x86/fixmap_32.h: fix_to_virt () function is used to calculate the virtual address based on the fixed_addresses constant of the fixed ing
static __always_inline unsigned long fix_to_virt(const unsigned int idx){ if(idx >= __end_of_fixed_addresses) __this_fixmap_does_not_exist(); return __fix_to_virt(idx);}
If idx is larger than the maximum possible value, an error occurs. The kernel accesses an Invalid Address and calls the _ this_fixmap_does_not_exist () function. Note: This function is not defined! An error is reported during kernel connection: the image file cannot be generated because of undefined symbols. The advantage of doing so is to advance the runtime errors to the link period. Such kernel faults can be detected during the compilation link, rather than during the runtime.
The problem arises. What if there is no kernel error? The linker does not know the execution process of if judgment. How does it know that the definition of _ this_fixmap_does_not_exist () is not linked? It is subtle in the compiler optimization mechanism, because fix_to_virt () is an inline function, and its parameter idx is an enumerated value constant, this can be calculated during the compilation period (this is why the entire fixed_addresses enumeration table is used instead of the fixed ing zone virtual address ). In the compiler optimization stage, the IF statement will be eliminated. If the idx value is out of bounds, the calls of __this_fixmap_does_not_exist () will remain in the code, causing a link error. If the idx value is valid, __this_fixmap_does_not_exist () is optimized and the kernel compilation link passes.
OK, GCC optimization is still not very thorough, and the relevant knowledge is estimated to be a large part. However, the next time you encounter this kind of skill, you will not get confused when using undefined pseudo functions to advance the runtime errors to the link.