2013년 6월 2일 일요일

ARM Cortex-A 페이징 (2)

ARM Cortex 페이징 (1)에서 이어지는 내용입니다.

2단계 페이징


작은 크기 페이지들인 Large Page(64KB)와 Small Page(4KB)를 사용하고자 할 때는 2단계 페이징을 합니다. 물론 크기가 작은 페이지도 하나의 페이지 테이블을 활용하는 1단계 페이징으로 할 수 있습니다만, 이것은 매우 비효율적입니다. 예를 들어, 4KB 페이지를 하나의 페이지 테이블로 페이징한다고 가정해 봅시다. 32비트 머신에서 가장 주소 공간은 4GB이므로, 총 1048576개의 엔트리가 필요합니다. 하나의 엔트리 크기는 4B이므로, 페이지 테이블의 크기는 총 4MB가 됩니다. 페이지 테이블은 프로세스마다 존재하므로 프로세스를 생성할때마다 페이지 테이블 용도로 4MB 메모리 공간을 할당하는 것은 낭비가 너무 심합니다. 이것을 2단계 페이징으로 변경하면, 16KB 크기의 1단계 페이지 테이블을 할당하고, 2단계 페이지 테이블은 가상 주소 영역에서 필요한 공간만 할당해서 사용할 수 있습니다. 이것이 다단계 페이징을 하는 이유입니다. 앞으로 2단계 페이지 테이블도 L1 페이지 테이블과 마찬가지로 L2 페이지 테이블(Level 2 Page Table)이라고 하겠습니다.


<그림 4. 2단계 페이징>

<그림 4>는 2단계 페이징 과정을 보여줍니다. MMU는 우선 TTBA(Translation Table Base Address)에서 L1 페이지 테이블의 시작 주소를 얻어옵니다. L1 페이지 테이블의 시작 주소에서 가상 주소 [31..20] 비트를 오프셋으로 사용하여 접근하려는 L1 페이지 테이블 엔트리의 주소를 구합니다(Level 1 Descriptor Address). L1 페이지 테이블 엔트리에서는 2단계 페이지 테이블 시작 주소가 저장되어 있습니다. L2 페이지 테이블 시작 주소(Level 2 Table Base Address)에서 가상 주소 [19..12] 비트를 오프셋으로 사용하여 L2 페이지 테이블 엔트리(L2 Page Table Entry)의 주소를 구합니다(Level 2 Descriptor Address). 메모리에서 L2 페이지 테이블 엔트리를 읽어오면, L2 페이지 테이블 엔트리에 저장된 가상 주소에 해당하는 페이지 프레임의 시작 주소(Small Page Base Address)를 알 수 있습니다. 마지막으로 페이지 프레임의 시작 주소에서 가상 주소 [11..0] 비트를 오프셋으로 사용하여 최종 접근하는 물리 주소(Physical Address)를 구하게 됩니다.

사실 2단계 페이징은 단계만 하나 늘었다뿐이지 1단계 페이징과 별반 다른점이 없습니다. <L1 페이지 테이블 시작 주소>, <L2 페이지 테이블 시작 주소>, <페이지 프레임 시작 주소>는 각각 <TTBA>, <L1 페이지 테이블 엔트리>, <L2 페이지 테이블 엔트리>에 저장되어 있고, 가상 주소를 나눠서 오프셋(인덱스)으로 사용한다는 점만 유념합시다.

2단계 페이징 과정도 좀 더 명확하게 이해하기 위해 예를 들어 볼까요? 아래와 같이 가정하고 2단계 페이징이 어떻게 되는지 보겠습니다.

  • 가상 주소 = 0xC0010010
  • 물리 주소 = 0x00010010
  • L1 페이지 테이블 시작 주소 = 0x4000
  • L2 페이지 테이블 시작 주소 = 0x9000

먼저 TTBA에 저장된 L1 페이지 테이블 시작 주소에서 L1 페이지 테이블 시작 주소를 얻어옵니다. L1 페이지 테이블 시작 주소에서 가상 주소의 [31..20] 비트를 오프셋으로 사용하여 L1 페이지 테이블 엔트리를 구합니다.

  • 0x4000(TTBA) + 0xC00(L1 PT Index) = 0x4C00(L1 Page Table Entry)

L1 페이지 테이블 엔트리에는 L2 페이지 테이블의 시작 주소가 저장되어 있습니다. L2 페이지 테이블 시작 주소에서 가상 주소 [19..12] 비트를 오프셋으로 사용하여 L2 페이지 테이블 엔트리를 구합니다.

  • 0x9000(L2 Page Table Base) + 0x10(L2 PT Index) = 0x9010(L2 Page Table Entry)

L2 페이지 테이블 엔트리에는 페이지 프레임의 주소가 저장되어 있습니다. 페이지 프레임의 주소에서 가상 주소 [11..0] 비트를 오프셋으로 사용하여 최종 물리 주소를 구할 수 있습니다.

  • 0x10000(Page Frame Base) + 0x10(Page Frame Index) = 0x10010(Physical Address)

페이지 크기가 작아질수록, 가상 주소 공간이 늘어 날수록 페이징 단계가 늘어나게 됩니다. ARM Cortex-A를 포함하여 전통적인 ARM 아키텍처는 32비트 가상 주소 공간을 제공합니다. 페이지 크기가 16MB, 1MB일때는 1단계 페이징, 페이지 크기가 64KB, 4KB일때는 2단계 페이징을 하였습니다. 반면에 우리가 PC로 많이 사용하고 있는 x86-64 아키텍처와 ARMv8의 aarch64 아키텍처는 64비트 가상 주소를 사용하는 64비트 아키텍처입니다. 64비트 아키텍처는 늘어난 가상 주소 공간을 지원하기 위해 주로 4단계 페이징을 합니다.(물론, 64비트 아키텍처도 페이지 크기에 따라 페이징 단계가 다릅니다.) 어쨋든, 페이징 단계가 늘어나더라도 각 단계별 페이지 테이블과 페이지 프레임의 오프셋으로 가상 주소를 분할하여 사용하는 것은 모두 동일합니다.

자 그럼, L2 페이지 테이블 엔트리들이 어떻게 생겼는지 한번 살펴 보겠습니다.

<그림 5. L2 페이지 테이블 엔트리의 종류>

L2 페이지 테이블 엔트리도 L1 페이지 테이블 엔트리와 마찬가지로 하위 2비트로 페이지 테이블 엔트리의 종류를 판별합니다. Lage page는 64KB 페이지를 사용하는 페이지 테이블 엔트리이고, Small page는 4KB 페이지를 사용하는 페이지 테이블 엔트리입니다. L2 페이지 테이블 엔트리는 페이지 프레임의 시작 주소를 저장하는 필드와 메모리 속성과 접근 권한을 설정하는 필드가 있습니다. 각 필드의 의미는 L1 페이지 테이블 엔트리의 것과 동일합니다. (참고> ARM Cortex 페이징 (1)) 2단계 페이징에 사용되는 L1 페이지 테이블 엔트리(Page table)에는 SectionSupersection에 있던 메모리 속성과 접근 권한을 설정하는 필드가 없고, L2 페이지 테이블 엔트리에 존재하는 것 입니다. 

메모리 속성


페이지 테이블 엔트리의 TEX, C, B등의 필드로 메모리 속성을 설정한다고 했는데, 메모리 속성을 도대체 어떻게 설정하는지 한번 알아보겠습니다. 우선, TEX, B, C 필드 값에 따라서 다음과 같이 메모리 속성이 설정 됩니다.

< 테이블 1. 페이지 테이블 엔트리 값에 따른 메모리 타입과 캐시 속성 설정 >
<테이블 1>의 메모리 타입은 메모리 오더링을 어떻게 하는지에 따라 달라집니다. ARM Cortex-A는 세가지 메모리 오더링 모델이 존재합니다.

  • Strongly-ordered: CPU로 부터 순차적으로 메모리 접근을 보장합니다. 캐싱(C)과 버퍼링(B)를 하지 않습니다.
  • Device: ARM은 MMIO을 사용하므로 해당 메모리 주소 영역이 디바이스 I/O 주소를 의미합니다.
  • Normal: 데이터를 저장하는 일반적인 메모리를 의미합니다. 

메모리 타입이 Normal의 Description를 보시면 Outer, Inner라는 것이 있는데, 이것은 캐시를 의미합니다. 만약, 시스템의 메모리 계층이 CORE <-> L1 명렁어/데이터 캐쉬 <-> L2 캐쉬 <-> 메모리  이렇게 가장 기본적인 형태로 되어 있다고 하면 일반적으로 L1 캐시를 Inner로 설정하고, L2 캐시를 Outer로 설정해서 사용합니다. 캐시는 시스템에 따라 많은 계층을 가질 수 있고, 시스템 프로그래머가 시스템 특성에 맞게 캐시를 Inner와 Outer로 설정할 수 있습니다. Inner와 Outer 별로 캐쉬 정책을 설정 할 수 있다는 것만 알아두도록 합시다.

write-throughwrite-back는 캐쉬 정책을 의미합니다. write-through는 쓰기 연산시 데이터를 캐쉬와 메모리에 동시에 반영하는 것이고, write-back은 캐시에만 반영하고 메모리에는 추후에 캐시에 저장된 데이터를 한번에 반영하는 것입니다. write-back 방식은 메모리 접근 횟수가 적으므로 성능상의 이점이 있지만 메모리에 쓰기 연산을 한 데이터가 적용되어 있지 않으므로 데이터 무결성 문제가 발생 할 수 있습니다.

TEX의 최상위 비트를 1로 설정하면 Outer, Inner 별로 캐시 정책을 설정 할 수 있습니다. (00: non-bacheable, 10: write-through, 11:write-back)


도메인


도메인은 ARM에서 메모리 영역을 구분하는 매커니즘입니다. 도메인은 L1 페이지 테이블 엔트리에서 총 16개의 도메인 ID로 설정 가능하며, 도메인 별로 접근 권한을 다르게 할 수 있습니다. 도메인 설정은 DACR(Domain Access Control Register)에서 하게 되는데, 2비트로 하나의 도메인을 설정합니다.

<그림 6. DACR>
다음과 같이 DACR의 값을 읽거나 설정 할 수 있습니다.

mrc    p15, 0, <Rt>, c3, c0, 0 ; DACR 값을 Rt에 읽어옵니다.
mcr    p15, 0, <Rt>, c3, c0, 0 ; Rt 값을 DACR에 설정합니다.


DACR의 각 도메인에 설정하는 2비트의 값에 따라 도메인은 다른 속성을 가집니다. DACR에 설정하는 2비트 값의 의미는 다음과 같습니다.

  • 0b00: No access. 해당 도메인에 접근하면 도메인 폴트(Domain Fault)가 발생합니다.
  • 0b01: Client. 페이지 테이블 엔트리의 접근 권한을 체크합니다.
  • 0b10: Resesrved.
  • 0b11: Manager. 페이지 테이블 엔트리의 접근 권한을 체크하지 않습니다.

페이지 테이블 엔트리에는 접근 권한을 설정하는 AP 필드가 있습니다(<그림 3>, <그림 5> 참고). 이 필드가 의미를 가지려면 도메인을 Client로 설정해야 합니다. 도메인을 Manager로 설정해두면 페이지 테이블 엔트리의 AP 필드 값에 따른 접근 권한을 체크하지 않고 해당 도메인은 무조건 접근이 가능합니다. 도메인을 Client로 설정하고, 페이지 테이블 엔트리의 AP 필드를 체크하여 도메인의 접근 권한을 위배하였을 경우에는 퍼미션 폴트(Permission Fault)가 발생합니다. 

ARM은 두단계를 거쳐서 메모리 접근 권한을 체크합니다. 먼저, 페이지 테이블 엔트리의 Domain 필드에서 도메인 ID를 가져와서 해당 도메인이 Manager 또는 Client인지 확인하고, Client이면 페이지 테이블 엔트리의 AP 필드를 확인하여 메모리 접근 권한을 체크합니다.

접근 권한


페이지 테이블 엔트리에 설정된 접근 권한은 해당 메모리가 속한 도메인이 Client일 경우에만 체크합니다. 페이지 테이블 엔트리의 APX, AP 필드 값에 따라 다음과 같이 접근 권한을 설정 할 수 있습니다.

<테이블 2. 페이지 테이블 엔트리 접근 권한 >

위 테이블은 페이지 테이블 엔트리의 APX/AP 필드 값에 따라 Privileged/Unprivileged의 접근 권한에 대해 나타냅니다. ARM은 총 7가지 모드(SVC/USR/SYS/ABT/IRQ/FIQ/UND)을 가지고 있는데, User 모드만 비특권(Unprivileged) 모드에 해당되고, 나머지 6가지 모드는 모두 특권(Privileged) 모드입니다. 커널은 Supervisor(SVC) 모드에서 주로 동작하며, 만약 인터럽트가 발생하면 Interrupt Request(IRQ) 모드로 진입하여 인터럽트 처리를 하고 다시 SVC 모드(혹은 USR 모드)로 되돌아가는 것이 모드 전환의 한가지 예로 들 수 있습니다. 특권 모드간, 특권 모드에서 User 모드로의 모드 전환은 CPSR 상태 레지스터 조작으로 할 수 있습니다.

커널에서 사용하는 데이터 영역은 특권 모드에서 Read/Write 할 수 있도록 설정하고, 유저 모드에서 동작하는 사용자 프로세스가 접근하지 못하도록 설정해야 합니다. 그리고, 프로그램 코드 영역으로 사용하는 메모리 공간은 수정이 되면 안되므로 Read만 가능하도록 설정해서 사용해야 합니다. 보안을 고려한 운영체제라면 사용하는 메모리 공간의 용도에 맞게 적절히 메모리 접근 권한을 설정해야 합니다.


< 참고자료 >
[1] Cortex -A Series Programmer’s Guide
[2] Cortex -A9 Technical Reference Manual
[3] ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition

댓글 없음:

댓글 쓰기