영구커널매핑(kmap) 관련 질문
안녕하세요.
ARM기반 리눅스의 메모리를 공부하고 있는데요, kmap과 관련한 질문이 있습니다.
부팅 초기단계에서 paging_init함수 내 kmap_init함수에서 kmap초기화가 이루어지는데요,
여기서 하는 작업은 딱 하나입니다.
바로 pkmap_page_table의 주소를 할당해 주는 것이구요, 이 주소는 kmap이 사용하게 될 페이지테이블의 시작 주소를 가리키고, 테이블의 갯수는 512개 입니다.(2MB)
궁금한 점은,
1. kmap 사용 목적과 절차
: zone_higmem의 high memory를 접근하기 위한 매핑공간으로 이해하고 있습니다. 그럼 page를 할당받은 이후 kmap을 하게 되는건가요?
: kmap을 사용하는 목적인 뭔가요? 사례는?
2. pkmap_page_table 사용 절차
: kmap을 위한 공간에 high memory가 매핑되려면 페이지디렉토리의 해당 엔트리와 2차변환에 필요한 페이지테이블의 내용이 수정되야 합니다.
: 그런데 주소 매핑에 필요한 페이지 테이블은 pkmap_page_table로 이해하고 있는데, 이것이 정작 실제 페이지테이블에 적용되는 시점과 그 방법이 궁금합니다.
: 참고로 현재 제가 보고있는 시스템은 CR3 TTB0가 0x80204000입니다.
3. vmalloc과의 차이점
: 1M이하의 메모리를 할당 받는다면, vmalloc을 사용하는것과 kmap을 사용하는것에 차이가 있나요?
감사합니다.
부팅시 출력한 메모리 레이아웃입니다. <5>[
부팅시 출력한 메모리 레이아웃입니다.
<5>[ 0.000000] vector : 0xffff0000 - 0xffff1000 ( 4 kB)
<5>[ 0.000000] fixmap : 0xfff00000 - 0xfffe0000 ( 896 kB)
<5>[ 0.000000] vmalloc : 0xec800000 - 0xff000000 ( 296 MB)
<5>[ 0.000000] lowmem : 0xc0000000 - 0xec400000 ( 708 MB)
<5>[ 0.000000] pkmap : 0xbfe00000 - 0xc0000000 ( 2 MB)
<5>[ 0.000000] modules : 0xbf000000 - 0xbfe00000 ( 14 MB)
<5>[ 0.000000] .text : 0xc0008000 - 0xc0b8000c (11745 kB)
<5>[ 0.000000] .init : 0xc0c00000 - 0xc0d03f40 (1040 kB)
<5>[ 0.000000] .data : 0xc0d04000 - 0xc0e721f0 (1465 kB)
<5>[ 0.000000] .bss : 0xc0e72214 - 0xc113b6b8 (2854 kB)
pkmap주소를 보면 0xBFE00000 ~ 0xC0000000 까지 2MB 잡혀있습니다.
실제 PKMAP_BASE 또한 0xBFE00000입니다.
그런데 의문이 있어요. 영구커널매핑이 high memory를 접근하기 위한 공간이라고 들었는데 해당 주소는 user space영역으로 kernel이 직접매핑할 수 없는 공간 아닌가요?
kernel이 저 공간을 어떻게 매핑 하나요?
답변..
메모리에 대한 이해가 부족한 시점에 제가 올린 질문이었는데, 여태 답변이 하나도 없네요.
시간이 흘러 위 질문에 대한 답을 스스로 찾았기에 자답 해 봅니다.
1. kmap 사용 목적과 절차
질문 당시 vmalloc(3번 질문)과 혼동하였는데.. 이렇게 헷갈렸던 이유가 바로 kmap이 메모리를 할당한다고 착각해왔기 때문입니다.
vmalloc 또한 직접 메모리를 할당하지만 주로 io_reamp 또는 vmap등을 통해 순수 매핑을 위한 목적이라 보면 kmap과 유사할 수도 있지만.. 어쨌든 kmap은 순전히 himem의 페이지프레임을 매핑용도로만 사용한다는데 목적이 있겠네요.
절차로는 pages_alloc등을 통해 페이지프레임을 얻어와서.. KMAP 영역에 매핑하기 위해 vaddr=kmap(page_ptr) 뭐 이런식으로 사용하면 되는거지요.
2. 이 질문은 대체 뭔소린지.. 제가 질문해놓고도 이제와서 보니 모르것네요..ㅎ
하여간 pkmap_page_table은 KMAP_BASE의 주소공간을 나타내는 페이지테이블의 주소를 갖고있는 전역변수입니다.
4K의 페이지단위로 512개가 필요하니 당연히 level-2로 관리되는 페이지테이블일테구요.
3. vmalloc과의 차이점은, 그 목적이 틀린데 있죠..
vmalloc - 연속적이지 않은 물리페이지프레임을 할당한 후 연속적인 형태의 가상주로로 매핑해서 그 주소를 제공, I/O 또는 예약되지 않은 물리메모리 공간에 대한 가상주소 제공(iormap함수), 이미 할당되어 있는 불연속적인 여러 페이지를 연속된 가상주소로 제공(vmap함수)
kmap - zone_high의 high memory 페이지를 kernel이 접근가능하도록(주소표현이 가능하도록) 정해진 공간(KMAP)에 매핑 제공.
4. 별도의 질문이었던.. 메모리레이아웃에서 PKMAP_BASE의 주소가 0xC0000000이하 (user space)에 위치하고 있는 점..
이것은 프로젝트 진행 중 특정 BSP에서 제공된 메모리 레이아웃이었는데요.. 이는 아마도 vmalloc으로 매핑해야할 I/O 또는 별도 예약된 메모리가 많아 다소 큰 vmalloc공간이 필요하게 되었고, 이로인해 Low Memory(ZONE NORMAL)이 자연스럽게 줄어드는 것을 회피하기 위해 page offset이하에 위치시켰지 않나 합니다. 다른 이유는 도무지 떠오르지 않네요.
해당 공간은 레이아웃 상 user space이지만 실제 페이지테이블에 작섣된 메모리 레이아웃 및 매핑 상태를 보면, user에서는 접근 불가로 되어 있고 kernel에서 R/W가능하도록 잡혀져 있네요.
직접 눈으로 확인한 바 kernel에서 접근하는데 문제 없도록 mmu세팅이 되어 있습니다. 아마 BSP의 bring up과정에서 메모리 세팅시 이러한 구조로 설계를 했나봅니다.
많은 걸 공부하셨네요
저도 이 부분 공부 중인데 참고하고 갈게요 ㅎ
지나가다가
안녕하세요,
검색으로 들어왔는데 이미 자답하셨네요, 제가 알고있는 부분도 공유 드립니다
잘못된 부분들 알려주시면 저도 더 공부하도록 하겠습니다~
1. kmap 사용 목적과 절차
====>
kmap(pkmap) : page table을 수정하고 schedule out 가능하므로 영구 커널맵핑으로 명명됨
kmap_atomic(fix kmap) : page table을 수정하고 schedule out 될 수 없으므로 임시 커널맵핑으로 명명됨
kmap,kmap_atomic 사용예 : swap등이 있으며, swap이 하는일이 특정 task에 할당된 data를 emmc, ram(zswap)등에 보내거나 받는 것이므로
highmem에 할당된 특정 task의 data(vm_area_struct)를 접근하기 위해서는 page table 구성이 필요함
2. pkmap_page_table 사용 절차
====>
vmalloc, kmap 등의 highmem 할당 함수들은 공통적으로 init_mm의 page table을 수정
(모든 task의 kernel영역 page table을 수정하는 것은 overhead이므로)
init_mm만 수정한 상태이기 때문에 해당 영역을 사용하려는 task가 있다면 page fault exception이 발생하고
arm 기준으로 do_translation_fault -> copy_pmd 함수를 통해 init_mm 의 page table을 현재 task의 page table에 복사함
3. vmalloc과의 차이점
====>
vmalloc : highmem에서 새로이 page를 할당하고 page table 구성
kmap, kmap_atomic : 이미 할당되어 쓰고 있던 highmem page를 kernel page table에도 mapping
* init_mm : swapper(pid=0)의 mm_struct
* vmalloc함수 자체보다는 vmalloc이 page table구성에 사용하는 vmap함수가 kmap과 비슷한 용도인 것 같습니다
4. 별도의 질문이었던.. 메모리레이아웃에서 PKMAP_BASE의 주소가 0xC0000000이하 (user space)에 위치하고 있는 점..
====>
저도 질문자께서 말씀하신 것처럼 vmalloc을 더 사용하기 위함으로 생각하고 있습니다
그러나 어디까지나 선택의 문제로 보여지는데, 아래처럼 arm과 x86 간에도 PKMAP 시작주소가 다르기 때문입니다
x86 : 0xFE000000
#define PKMAP_BASE ((FIXADDR_START - PAGE_SIZE * (LAST_PKMAP + 1)) & PMD_MASK) (arch/x86/include/asm/pgtable_32_types.h)
-------------------------------------------------------------------------------------------
~~ PAGE_OFFSET | Lowmem | Vmalloc | PKMAP | FIXADDR | etc. |
-------------------------------------------------------------------------------------------
arm : 0xBFE00000
#define PKMAP_BASE (PAGE_OFFSET - PMD_SIZE) (arch/arm/include/asm/highmem.h)
---------------------------------------------------------------------------------------
~~ PKMAP |PAGE_OFFSET | Lowmem | Vmalloc | FIXADDR | etc. |
---------------------------------------------------------------------------------------
* Understanding The Linux Virtual Memory Manager 참고했습니다
(http://ptgmedia.pearsoncmg.com/images/0131453483/downloads/gorman_book.pdf)
오늘도 조금 더 배우는 하루
댓글 달기