본문 바로가기

RISC-V/레지스터

[Linux Kernel] RISC-V: swapper_pg_dir 변수를 이용한 satp 주소 찾기

배경

RISC-V 아키텍처에는 여러 가지 CSR(Control and Status Register) 레지스터가 있습니다.
그중 하나가 satp 레지스터입니다.

satp 레지스터의 역할은 무엇일까요? 첫 번째(1st) 페이지 테이블 엔트리의 주소를 저장하는 역할을 합니다.
만약 TRACE32 같은 디버깅 장비를 사용하면 satp 레지스터 값을 직접 확인할 수 있습니다. 하지만 TRACE32 없이 리눅스 커널 내부에서 satp 값을 확인하는 방법은 무엇일까요? 이 글에서는 그 방법에 대해서 상세히 다룹니다. 

리눅스 커널: swapper_pg_dir

satp 값(첫 번째 페이지 테이블의 엔트리 주소)을 확인하려면 swapper_pg_dir 전역 변수의 가상 주소를 먼저 알아야 합니다.
왜 swapper_pg_dir이 중요할까요? 
리눅스 커널이 부팅할 때, satp 레지스터의 값을 swapper_pg_dir에 저장하기 때문입니다.

 

Crash 유틸리티를 사용하여 swapper_pg_dir 주소 확인

 

 

Crash 유틸리티를 사용하면 swapper_pg_dir의 가상 주소와 물리 주소를 확인할 수 있습니다.

출력 결과:

- swapper_pg_dir 가상 주소: 0xffffffff81c4f000
- swapper_pg_dir 물리 주소: 0x41e4f000


satp 값 계산하기


swapper_pg_dir의 물리 주소를 이용해 satp 값을 계산할 수 있습니다.

0x41e4f000 >> 12 = 0x41e4f


왜 12비트를 오른쪽으로 이동할까요? 기본 페이지 크기(default page size)는 0x1000 (4KB)입니다. 물리 주소를 12비트(0x1000) 만큼 오른쪽으로 시프트하면 페이지 프레임 번호(PFN) 를 얻을 수 있습니다.

 

satp 레지스터 분석


더 정확한 정보를 확인하기 위해, RISC-V 명령어 매뉴얼(RISC-V Instruction Set Manual)의 satp 레지스터 비트 구조를 살펴보겠습니다.


satp 레지스터 비트 구조
-[43:0] 비트 → 페이지 프레임 번호(PFN) 저장 이 값이 root page table의 물리 주소입니다.
-[63:60] 비트 → 멀티 레벨 페이지 변환 단계 정보 저장
즉, satp 레지스터는 1st lookup page table의 베이스 주소를 저장합니다.

리눅스 커널 코드 분석


satp 값은 리눅스 커널에서 어떻게 설정될까요? 커널 부팅 시 실행되는 setup_vm_final() 함수에서 설정됩니다.

riscv/mm/init.c
static void __init setup_vm_final(void)
{
    ...
    csr_write(CSR_SATP, PFN_DOWN(__pa_symbol(swapper_pg_dir)) | satp_mode);

 


이 한 줄의 코드에는 중요한 정보가 포함되어 있습니다.

-__pa_symbol(swapper_pg_dir): swapper_pg_dir의 가상 주소를 물리 주소로 변환하는 매크로
-PFN_DOWN(): 물리 주소를 페이지 프레임 번호(PFN)로 변환하는 매크로
-satp_mode: 페이지 변환 레벨을 지정하는 값


satp_mode 값

 

satp_mode 값은 satp 레지스터의 [63:60] 비트에 저장됩니다.
RISC-V 문서와 리눅스 커널 코드에서 확인할 수 있습니다.

#define SATP_MODE_39 _AC(0x8000000000000000, UL)
#define SATP_MODE_48 _AC(0x9000000000000000, UL)
#define SATP_MODE_57 _AC(0xa000000000000000, UL)

 

요약

1. satp 레지스터는 첫 번째 페이지 테이블 엔트리 주소를 저장합니다.
리눅스 커널이 부팅될 때, satp 값이 swapper_pg_dir에 저장됩니다.

 

2. satp 값을 찾으려면:
swapper_pg_dir의 물리 주소를 확인합니다.
12비트 오른쪽 시프트(>> 12) 하여 페이지 프레임 번호(PFN)를 얻습니다.

 

3. setup_vm_final() 함수에서 satp 값이 설정됩니다.
satp_mode는 페이지 변환 레벨을 결정합니다.

 

이 과정을 이해하면, TRACE32 같은 외부 디버깅 장비 없이 리눅스 커널 내부에서 satp 값을 확인할 수 있습니다. 🚀