• Paran Lee

[Practice] 64비트 RISC-V 아키텍쳐 부트 업 첫걸음 (작성중)

최종 수정일: 2021년 5월 29일



분석 과정에서 사용하는 환경이 일반적으로 우리가 사용하는 데스크톱 환경과는 다르니까,

이를 가능하도록 크로스 플랫폼 환경이 가능하게 Cross Compile, QEMU 가상화, Cross debugging 의 도움을 받으면서 진행보려고 해요.


우선 필요한 패키지를 설치해 보아요.

저는 데스크톱 리눅스 개발환경은 우분투를 주로 사용해요.

우선 간단하게 부팅가능한 정말 자그만한 OS Kernel 을 만들어볼께요.

만들기 위해서 찬찬히 RV64I ISA 기준으로 사용할 때 필요한 어셈블리 명령어들만 우선 보도록 할께요.


TODO: 부팅 가능한 간단한 소스코드


TODO: 페이징 관련한 내용을 어떻게 여기에 넣을까?! 페이지 테이블을 만들다 말아볼까?


아래 그림은 64비트 RISC-V 아키텍쳐, 4K 페이지 기준 1단계 정규 페이징을 하는 예시에요. ( PTE 한 단계만 존재함 )


"페이징?! 1단계를 한다고? 무슨 말이야."

"아 중간에 하나 있네, 1단계고, 음 가상주소가 물리주소로 바뀌네? 이게 페이징이구나."


라고 몇 년 전의 OS Kernel 공부 하기 전에 저라면 그랬을 것 같아요. (단순 : )

Figure : RISC-V virtual and physical addresses, with a simplified logical page table.


바로 본론으로 들어가면 너무 머리 속이 너무 복잡해지니까, 페이징이라는 단어의 이미지를 잡고 가볼까요?


보통 우리가 책을 보게 되면 펼친 양쪽을 보게 되요. 어려운 책을 정독하고 있으면, 두 쪽을 보고 이해하는데도 시간이 꽤나 걸리겠죠? 예를 들어, 응용 프로그램에서도 게시판에 한 페이지당 50개 단위로 게시글을 보여주고 그 다음으로 넘어가는 구현을 페이징이라고 하죠.


우리는 종이책을 한장 한장을 바닥에 전부 깔아서 보고 있을 필요는 없어요. 사람의 눈은 기껏 해봐야 한번에 한 문장 정도 밖에 보지 못하니까요. 그리고 공간을 너무 차지해서, 주위에 다른 사람이 지나다닐 수 없을 거에요.


자 이제 다시 돌아와서 본론으로 들어가볼까요? 한 페이지에 있는 연속된 가상 주소는 연속된 물리 주소로 매핑해야 해요.

이런 식으로 커널은 모든 선형 주소 바이트 마다 잘게 잘게 물리 주소와 접근 권한을 지정하는 것이 아니라,

하나의 페이지가 단위가 되고, 이를 DRAM에 대응하는 위치인 페이지 프레임에 지정해요.


각각 Key -> Value 에 대응하는 한다고 보면 되고, 대응해줄 때는 규칙이 있어야 하겠죠?

HW 페이징 유닛이 Map 을 통해서 값을 가져오는데요. 페이징 유닛은 Key 인 가상주소를 가지고, 보고있는 목록 리스트인 TLB(Translation Look-aside Buffer) 를 살펴봅니다. 없으면 가상주소에 해당하는 페이지 테이블을 DRAM 으로부터 불러오구요. TLB 목록의 값을 참고하여, 페이징 유닛은 자기에게 주어진 규칙에 따라서 결국 Value 인 물리 메모리의 페이지 프레임을 가져오게 되요. 페이징 유닛에게 주어진 이 규칙에 따라 페이지 테이블을 만들어주는 작업이 바로 조금 이따가 살펴볼 N 레벨 정규 페이징이에요.


RISC-V 코어의 페이징 하드웨어는 TLB에 가상주소와 DRAM에 존재하는 페이지 프레임을 짝을 지어 캐쉬합니다.


커널 코드에서 커널을 컴파일 했을 때의 가상 주소, 즉 프로세서 CPU 코어 안에 들어있는 페이징 유닛을 사용하여 물리 메모리를 사용하고 싶다면, 사용하기 이전에 반드시 페이지 테이블을 올바로 초기화 해야해요! 이꼬르(=) 가상 주소에 대응할 물리 메모리의 짝꿍을 만드는 거죠! 가상 주소를 사용하지 않으면, 기준 주소 값을 두고 상대적으로 동작하는 어셈블리, C 프로그래밍을 해야하거든요.


페이지들을 상위 범주의 비트 그룹들과 오프셋을 사용할 수 있는데요.

이 가상 주소 Key 에 따라 버킷 값을 찾아서 Value 즉, 물리 페이지를 찾아가는 과정을 정규 페이징이라고 합니다.

그리고 이런 자료구조를 우리는 페이지 테이블이라고 해요.

큰 숲을 보는 느낌으로 설명하면, OS 를 사용할 때 필요한 어떤 데이터나 코드를 가지고 있는 물리 메모리의 페이지 프레임이 있구요. 이것을 찾아 가게 해주는 각 단계의 페이지 테이블들! 크게는 두 형태의 페이지 프레임이 존재하는 거죠!


자 이제 조금 더 들어가서 그림과 함께 예시를 볼까요?


64비트 RISC-V 아키텍쳐에서 4K 페이지 기준, 3단계 정규 페이징이에요, ( PGD->PMD->PTE 3단계가 존재함 )

Figure : RISC-V address translation details.


위의 그림에서 보면 physical page number (대학교 서적 기준으로는 PPN 이라고 많이 쓰는 것 같아요, 리눅스 커널에서는 일반적으로 PFN 이라고 일반적으로 쓰고 있어요.) 가 있고 각 단계의 Page Directory 를 차례로 찾아가서 해당 page table entry 의 페이지 프레임 값을 찾는 과정이 보이네요. 위 그림에서는 하나의 물리 메모리 페이지 프레임을 나타내려고 3개의 페이지 테이블 엔트리를 사용하고 있어요! 그리고 해당 페이지 테이블 엔트리의 상태를 알려주는 10:0 비트까지의 플래그를 보여주고 있어요!


그럼 왜 이렇게 복잡한 정규페이징을 하느냐? 왜 이렇게 복잡한 구조를 가져가느냐? 페이지 테이블을 만들어서사용하면 DRAM 에 추가적인 공간이 필요합니다. 따라서 메모리에 용량을 더 차지하겠죠? 사용함에도 여러번 찾아가서 오버헤드가 있고, 그냥 바로 매핑해서 쓰면 안될까?


네 의심은 당연하고 어디 하나 틀린 건 없습니다.


가장 범용적으로 효율을 따져, 가성비 좋게 만들 때 이렇게 하면 가장 좋더라~ 가장 많이 쓴다. 보편적이다. 이거 아니겠어요?


사실은 장점과 단점은 저도 이 글을 쓰는 시점에도 찾아 보고있고, 다양한 방식으로 고민해보려고 노력하고 있어요. ^^;


이렇게 페이징으로 OS Kernel, VLSI 설계자가 논리적인 기준을 세우고 규칙을 정하면, 컴퓨터가 빠르게 동작해야한다! 호환도 되야하고, 해결해야 할 문제가 많다! 이럴 때에 좀 더 문제가 명확해지겠죠?


우리가 공부하면서 많이 참고할 리눅스 커널에 대한 LWN 의 컬럼입니다. 잠깐 머리 식힐(?) 겸 보는 것도 좋을 것 같아요.


2004 년 10 월 12 일

LWN 4 단계 페이지 테이블

- 조나단 콜뱃


2017 년 3월 15일

LWN 5 단계 페이지 테이블

- 조나단 콜뱃


또 궁금점! 정규 페이징만 사용하는가? 방법은 많을 수 있는게 아닌가? 이런 궁금증이 생기네요. 네 맞아요.


메모리 보호, 디스크 Swapping 을 위한 가상 메모리 방법론에 대해서는 오랜 기간 다양한 방식이 논의되었고, 오늘날에 페이징이 대중화되기 전에는 여러가지 다양한 방법이 많았는데요.

현재는 Core 내부에 들어간 HW 페이징 유닛도 페이징 기법에 맞춰서 오랜 기간 성능 향상되었고, 가상 주소를 지원하는 대부분의 OS kernel 에서도 페이징 방법을 기준으로 사용하고 있어요. 한번 시간 나실 때 찬찬히 관련 논의들을 찾아보면 좋을 것 같아요.

Figure : On the left, xv6’s kernel address space. RWX refer to PTE read, write, and execute permissions.

On the right, the RISC-V physical address space that xv6 expects to see.


위의 메모리 레이아웃은 링커 스크립트를 만들 때 기준이 되요.

위의 레이아웃을 사용하기 위해 헤더 파일을 작성하면 아래와 같아요.

위의 레이아웃은 참고 용이고, 우리는 리눅스 커널의 RISC-V 아키텍쳐 기준의 레이아웃을 기준으로 작성해보려고 해요.



조회수 119회댓글 2개

관련 게시물

전체 보기