prepare_page_table()

다음의 영역들을 1차 페이지 테이블에서 초기화 하고 해당 영역에 대한 1차 및 2차 TLB 엔트리를 제거(invalidate)한다.

  • 0x0 ~ MODULES_VADDR 영역
    • 모듈 시작 영역은 커널 시작 가상 주소(PAGE_OFFSET) – 16M이다.
  • MODULES_VADDR ~ PAGE_OFFSET 영역
  • lowmem 남은 공간 부터 VMALLOC_START 영역
    • VMALLOC 영역이 가장 작아졌을 때 VMALLOC_START 값은 0xf000_0000(ef80_0000 + 0x80_0000)이다.
    • arm_lowmem_limit 주소를 가상주소로 변환한 주소가 high_memory이며 VMALLOC_START는 여기에 VMALLOC_OFFSET(8M)를 더한 후 8M round up한 주소이다.

 

prepare_page_table()

prepare_page_table-1a

 

arch/arm/mm/mmu.c

static inline void prepare_page_table(void)
{
        unsigned long addr;
        phys_addr_t end; 

        /*
         * Clear out all the mappings below the kernel image.
         */
        for (addr = 0; addr < MODULES_VADDR; addr += PMD_SIZE)
                pmd_clear(pmd_off_k(addr));

#ifdef CONFIG_XIP_KERNEL
        /* The XIP kernel is mapped in the module area -- skip over it */
        addr = ((unsigned long)_etext + PMD_SIZE - 1) & PMD_MASK;
#endif
        for ( ; addr < PAGE_OFFSET; addr += PMD_SIZE)
                pmd_clear(pmd_off_k(addr));

        /*
         * Find the end of the first block of lowmem.
         */
        end = memblock.memory.regions[0].base + memblock.memory.regions[0].size;
        if (end >= arm_lowmem_limit)
                end = arm_lowmem_limit;

        /*
         * Clear out all the kernel space mappings, except for the first
         * memory bank, up to the vmalloc region.
         */
        for (addr = __phys_to_virt(end);
             addr < VMALLOC_START; addr += PMD_SIZE)
                pmd_clear(pmd_off_k(addr));
}
  • for (addr = 0; addr < MODULES_VADDR; addr += PMD_SIZE)
    • 페이지 테이블의 0x0000_0000 ~ MODULES_VADDR 가상 주소까지에 대응하는 2M 단위의 엔트리를 clear한다.
    • MODULES_VADDR
      • PAGE_OFFSET – 16M
      • rpi2: 0x7f00_0000
  • pmd_clear(pmd_off_k(addr));
    • 가상주소에 해당하는 pmd 엔트리 주소를 알아온 후 그 주소의 pmd 엔트리를 clear 한다.
    • 가상주소에 해당하는 TLB 캐시 엔트리도 clean 한다.
    • 참고: TLB Cache (API) | 문c
  • addr = ((unsigned long)_etext + PMD_SIZE – 1) & PMD_MASK;
    • XIP 커널의 경우 시작 주소에 따라 모듈 영역에 대한 페이지 테이블 초기화는 다음과 같이 처리된다.
      • _etext는 PAGE_OFFSET 하단에 위치 즉, 모듈 영역에 위치하므로 addr 주소를 _etext의 2M round up한 주소로 한다.
  • for ( ; addr < PAGE_OFFSET; addr += PMD_SIZE)
    • XIP 커널이 아닌 경우 모듈 시작 주소부터 PAGE_OFFSET 까지의 가상 주소까지에 대응하는 2M 단위의 엔트리를 clear 한다.
    • 만일 XIP 커널인 경우는 재 산정된 addr 주소 부터 PAGE_OFFSET 까지의 가상 주소까지에 대응하는 2M 단위의 pmd 엔트리를 clear 한다.
  • end = memblock.memory.regions[0].base + memblock.memory.regions[0].size;
    • end = 물리 메모리의 끝 주소
  • if (end >= arm_lowmem_limit) end = arm_lowmem_limit;
    • 물리 메모리가 lowmem 영역 한계치(arm_lowmem_limit)를 초과하는 경우 끝 주소를 lowmem 영역의 한계치로 대입한다.
  • for (addr = __phys_to_virt(end); addr < VMALLOC_START; addr += PMD_SIZE)
    • lowmem 영역 내에서의 끝 주소를 가상주소로 바꾼 주소부터 VMALLOC_START 주소까지 2M 단위로 증가시키며 이에 대응하는 2M 단위의 pmd 엔트리를 clear 한다.

 

참고

댓글 남기기