user & kernel address deep analyze
이 글에서 좀더 심도 있게 다루는 분석글이다.
========================================================================================================================
Start addr | Offset | End addr | Size | VM area description
========================================================================================================================
| | | |
0000000000000000 | 0 | 00007fffffffffff | 128 TB | user-space virtual memory, different per mm
__________________|____________|__________________|_________|___________________________________________________________
|
| Kernel-space virtual memory, shared between all processes:
____________________________________________________________|___________________________________________________________
| | | |
ffff888000000000 | -119.5 TB | ffffc87fffffffff | 64 TB | direct mapping of all physical memory (page_offset_base)
ffffc90000000000 | -55 TB | ffffe8ffffffffff | 32 TB | vmalloc/ioremap space (vmalloc_base)
__________________|____________|__________________|_________|____________________________________________________________
|
| Identical layout to the 56-bit one from here on:
____________________________________________________________|____________________________________________________________
ffffffff80000000 | -2 GB | ffffffff9fffffff | 512 MB | kernel text mapping, mapped to physical address 0
ffffffffa0000000 |-1536 MB | fffffffffeffffff | 1520 MB | module mapping space
__________________|____________|__________________|_________|___________________________________________________________앞에서 다뤘듯 , 유저 영역의 메모리 구조는 각 프로세스마다 독립적임 그렇기에 다른 프로세스가 같은 가상 주소에 접근하더라도 서로 다른 독립적인 데이터를 읽어오게 된다. 그러나 커널 영역의 메모리 구조는 유저 영역과 달리 모든 프로세스가 공유하기 때문에, 서로 다른 프로세스가 같은 커널 영역의 주소에 접근하게 되면 모두 같은 커널 영역 메모리에 접근하게 된다.
x86-64 아키텍쳐의 4-level 페이지 테이블(Page Tables) 기준 으로 커널의 주요 메모리 구조를 정리하면 다음과 같다.
0x0000000000000000 ~ 0x00007fffffffffff: 유저 영역이 위치한 가상 주소입니다. 코드 세그먼트, 스택 세그먼트 등이 이 영역에 위치하며 각 프로세스는 독립적인 영역을 보유합니다.0xffff888000000000 ~ 0xffffc87fffffffff: 물리적인 RAM을 나타내는 물리 메모리 영역입니다.0xffffc90000000000 ~ 0xffffe8ffffffffff: vmalloc 영역입니다. 커널 개발자가vmalloc()을 호출해 할당받은 주소가 해당 영역에 위치합니다.0xffffffff80000000 ~ 0xffffffff9fffffff: 커널 코드가 위치한 .text 영역입니다. 이어서 rodata , data , bss 영역이 존재함, 즉 , 우리가 빌드한 커널 이미지가 해당 영역에 위치합니다.0xffffffffa0000000 ~ 0xfffffffffeffffff: 커널 모듈이 위치한 영역입니다. 커널을 부팅한 후, 디바이스 드라이버 등의 모듈을 로드하면 해당 위치에 매핑됩니다.
커널의 CONFIG_X86_5LEVEL 옵션 여부에 따라 5단계 페이징 테이블을 사용할 수 있다.
추가적인 설명
0xffff888000000000 ~ 0xffffc87fffffffff: 물리적인 RAM을 나타내는 물리 메모리 영역입니다. ( direct map , linear map 이라고 불림 )→ 이부분이 헷갈릴 수 있는데, 일단 메인메모리의 전체를 va에 올리는 건 맞음
근데 당연하겠지만, 매핑이 어디에 되어 있는지 모르기 때문에 mmu를 통한 페이징 방식으로 접근을 해야 하는 건 맞으며, 이 영역이 있는 이유는 커널이 phys↔virt 변환을 단순화/가속하려고 사용한다 → 좀더 자세히 설명을 하자면, what is direct map
0xffffc90000000000 ~ 0xffffe8ffffffffff: vmalloc 영역입니다. 커널 개발자가 vmalloc()을 호출해 할당받은 주소가 해당 영역에 위치합니다.
→ kmalloc이 있는데 이 영역은 왜 존재 하나요?
0xffffffff80000000 ~ 0xffffffff9fffffff: 커널 코드가 위치한 .text 영역입니다. 이어서 rodata , data , bss 영역이 존재함, 즉 , 우리가 빌드한 커널 이미지가 해당 영역에 위치합니다.
0xffffffffa0000000 ~ 0xfffffffffeffffff: 커널 모듈이 위치한 영역입니다. 커널을 부팅한 후, 디바이스 드라이버 등의 모듈을 로드하면 해당 위치에 매핑됩니다.
→ 이런 식으로 되어 있는데 그럼 모듈의 data 영역은 어디에 들어감?
0xffffffff80000000 ~ 0xffffffff9fffffff: 커널 코드가 위치한 .text 영역입니다. 이어서 rodata , data , bss 영역이 존재함, 즉 , 우리가 빌드한 커널 이미지가 해당 영역에 위치합니다.
→ 그럼 이건 kaslr이 꺼져 있는 기준임? → 맞음, 켜져있으면 역시 base가 바뀌면서 정확한 주소를 알 수 없게 됨 0xffffffff80000000 이 영역 뿐만 아니라 directmap, vmalloc 영역도 CONFIG_RANDOMIZE_MEMORY 설정에 따라 랜덤 오프셋으로 밀릴 수 있음
가상 주소는 메모리 관리 장치(Memory Management Unit, MMU)에 의해 물리 주소로 변환된다.
좀더 자세한 표
========================================================================================================================
Start addr | Offset | End addr | Size | VM area description
========================================================================================================================
| | | |
0000000000000000 | 0 | 00007fffffffffff | 128 TB | user-space virtual memory, different per mm
__________________|____________|__________________|_________|___________________________________________________________
| | | |
0000800000000000 | +128 TB | ffff7fffffffffff | ~16M TB | ... huge, almost 64 bits wide hole of non-canonical
| | | | virtual memory addresses up to the -128 TB
| | | | starting offset of kernel mappings.
__________________|____________|__________________|_________|___________________________________________________________
|
| Kernel-space virtual memory, shared between all processes:
____________________________________________________________|___________________________________________________________
| | | |
ffff800000000000 | -128 TB | ffff87ffffffffff | 8 TB | ... guard hole, also reserved for hypervisor
ffff880000000000 | -120 TB | ffff887fffffffff | 0.5 TB | LDT remap for PTI
ffff888000000000 | -119.5 TB | ffffc87fffffffff | 64 TB | direct mapping of all physical memory (page_offset_base)
ffffc88000000000 | -55.5 TB | ffffc8ffffffffff | 0.5 TB | ... unused hole
ffffc90000000000 | -55 TB | ffffe8ffffffffff | 32 TB | vmalloc/ioremap space (vmalloc_base)
ffffe90000000000 | -23 TB | ffffe9ffffffffff | 1 TB | ... unused hole
ffffea0000000000 | -22 TB | ffffeaffffffffff | 1 TB | virtual memory map (vmemmap_base)
ffffeb0000000000 | -21 TB | ffffebffffffffff | 1 TB | ... unused hole
ffffec0000000000 | -20 TB | fffffbffffffffff | 16 TB | KASAN shadow memory
__________________|____________|__________________|_________|____________________________________________________________
|
| Identical layout to the 56-bit one from here on:
____________________________________________________________|____________________________________________________________
| | | |
fffffc0000000000 | -4 TB | fffffdffffffffff | 2 TB | ... unused hole
| | | | vaddr_end for KASLR
fffffe0000000000 | -2 TB | fffffe7fffffffff | 0.5 TB | cpu_entry_area mapping
fffffe8000000000 | -1.5 TB | fffffeffffffffff | 0.5 TB | ... unused hole
ffffff0000000000 | -1 TB | ffffff7fffffffff | 0.5 TB | %esp fixup stacks
ffffff8000000000 | -512 GB | ffffffeeffffffff | 444 GB | ... unused hole
ffffffef00000000 | -68 GB | fffffffeffffffff | 64 GB | EFI region mapping space
ffffffff00000000 | -4 GB | ffffffff7fffffff | 2 GB | ... unused hole
ffffffff80000000 | -2 GB | ffffffff9fffffff | 512 MB | kernel text mapping, mapped to physical address 0
ffffffff80000000 |-2048 MB | | |
ffffffffa0000000 |-1536 MB | fffffffffeffffff | 1520 MB | module mapping space
ffffffffff000000 | -16 MB | | |
FIXADDR_START | ~-11 MB | ffffffffff5fffff | ~0.5 MB | kernel-internal fixmap range, variable size and offset
ffffffffff600000 | -10 MB | ffffffffff600fff | 4 kB | legacy vsyscall ABI
ffffffffffe00000 | -2 MB | ffffffffffffffff | 2 MB | ... unused hole
__________________|____________|__________________|_________|___________________________________________________________