이 질문은 주제에 대한 좋은 무료 정보의 공백을 채우기위한 것입니다.
나는 좋은 대답이 하나의 큰 SO 대답 또는 적어도 몇 가지 대답에 맞을 것이라고 믿습니다.
주된 목표는 완전한 초보자가 스스로 매뉴얼을 읽고 페이징과 관련된 기본 OS 개념을 이해할 수 있도록 충분한 정보를 제공하는 것입니다.
권장 지침 :
- 답변은 초보자에게 친숙해야합니다.
- 구체적이지만 단순화 된 예는 매우 중요합니다.
- 표시된 개념의 응용 프로그램을 환영합니다.
- 유용한 자료를 인용하는 것이 좋습니다.
- OS에서 페이징 기능을 사용하는 방법에 대한 작은 설명도 환영합니다.
- PAE 및 PSE 설명을 환영합니다.
- x86_64 로의 작은 차이는 환영합니다
관련 질문과 내가 속이지 않는 이유 :
-
x86 페이지 테이블은 어떻게 작동합니까? : 제목은이 질문과 거의 동일하지만 본문은 cr3 및 TLB와 관련된 구체적인 질문을합니다. 이 질문은이 질문의 일부입니다.
-
x86 가상화는 어떻게 작동합니까? 본문은 소스 만 요청합니다.
답변
좋은 TOC 및 더 많은 내용이있는이 답변의 버전입니다 .
보고 된 오류를 수정하겠습니다. 큰 수정을가하거나 누락 된 측면을 추가하려면 자신의 답변을 작성하여 적절한 담당자를 확보하십시오. 사소한 편집 내용을 직접 병합 할 수 있습니다.
샘플 코드
프로그래밍의 다른 모든 것과 마찬가지로 이것을 실제로 이해하는 유일한 방법은 최소한의 예제로 플레이하는 것입니다.
이것을 “어려운”주제로 만드는 것은 자신의 작은 OS를 만들어야하기 때문에 최소한의 예제가 크다는 것입니다.
인텔 매뉴얼
예제를 염두에 두지 않으면 이해할 수 없지만 가능한 한 빨리 매뉴얼에 익숙해 지도록 노력하십시오.
인텔은 인텔 매뉴얼 볼륨 3 시스템 프로그래밍 가이드-325384-056US 2015 년 9 월 4 장 “페이징”에서 페이징을 설명합니다.
특히 흥미로운 것은 그림 4-4 “32 비트 페이징을 사용하는 CR3 및 페이징 구조 항목의 형식”으로, 주요 데이터 구조를 제공합니다.
MMU
페이징은 CPU의 MMU ( Memory Management Unit ) 부분에서 수행됩니다 . 다른 많은 것 (예 : x87 co-processor , APIC ) 과 마찬가지로 , 초기에는 별도의 칩으로 사용되었으며 나중에 CPU에 통합되었습니다. 그러나이 용어는 여전히 사용됩니다.
일반적인 사실들
논리 주소는 “일반”사용자 영역 코드에 사용되는 메모리 주소 (예 : 내용이다 rsi
에서 mov eax, [rsi]
).
첫 번째 세분화는이를 선형 주소로 변환 한 다음 페이징을 통해 선형 주소를 물리적 주소로 변환합니다.
(logical) ------------------> (linear) ------------> (physical)
segmentation paging
대부분의 경우 실제 주소는 실제 RAM 하드웨어 메모리 셀을 인덱싱하는 것으로 생각할 수 있지만 다음과 같은 이유로 100 % 사실이 아닙니다.
페이징은 보호 모드에서만 사용할 수 있습니다. 보호 모드에서 페이징을 사용하는 것은 선택 사항입니다. 레지스터 의 PG
비트 cr0
가 설정 되면 페이징이 켜집니다 .
페이징 대 세분화
페이징과 세분화의 주요 차이점은 다음과 같습니다.
- 페이징은 RAM을 페이지라고하는 동일한 크기의 청크로 분할합니다.
- 세분화는 메모리를 임의 크기의 청크로 분할합니다.
이것은 동일한 크기의 청크가 일을 더 쉽게 관리 할 수 있도록하기 때문에 페이징의 주요 이점입니다.
페이징은 훨씬 더 대중적이되어 새로운 소프트웨어의 기본 작동 모드 인 64 비트 모드의 x86-64에서 분할 지원이 중단되었습니다. 여기서 IA32를 에뮬레이트하는 호환성 모드에서만 존재합니다.
신청
페이징은 최신 OS에서 프로세스 가상 주소 공간을 구현하는 데 사용됩니다. 가상 주소를 사용하면 OS는 다음과 같은 방식으로 단일 RAM에 둘 이상의 동시 프로세스를 맞출 수 있습니다.
- 두 프로그램 모두 다른 프로그램에 대해 알 필요가 없습니다.
- 두 프로그램의 메모리는 필요에 따라 늘어나거나 줄어들 수 있습니다.
- 프로그램 간 전환이 매우 빠릅니다.
- 한 프로그램은 다른 프로세스의 메모리에 액세스 할 수 없습니다.
페이징은 역사적으로 세그먼트 화 이후에 왔으며 가변 길이 세그먼트 대신 페이지의 고정 된 크기의 메모리 청크를 관리하는 것이 더 쉽기 때문에 Linux와 같은 최신 OS에서 가상 메모리 구현을 위해 대체로 대체되었습니다.
하드웨어 구현
보호 모드의 세분화 (세그먼트 레지스터를 수정하면 GDT 또는 LDT에서로드가 트리거 됨)와 마찬가지로 페이징 하드웨어는 메모리의 데이터 구조를 사용하여 작업 (페이지 테이블, 페이지 디렉토리 등)을 수행합니다.
이러한 데이터 구조의 형식은 하드웨어에 의해 고정 되지만 RAM에서 해당 데이터 구조를 올바르게 설정 및 관리하고이를 찾을 위치를 하드웨어에 알리는 것은 OS에 달려 cr3
있습니다.
일부 다른 아키텍처는 페이징을 거의 완전히 소프트웨어의 손에 맡기므로 TLB 미스는 OS 제공 기능을 실행하여 페이지 테이블을 살펴보고 새 매핑을 TLB에 삽입합니다. 이로 인해 OS에서 페이지 테이블 형식을 선택할 수 있지만 x86과 같이 하드웨어가 다른 명령의 비 순차적 실행과 페이지 이동을 겹칠 가능성은 거의 없습니다 .
예 : 단순화 된 단일 레벨 페이징 체계
이것은 가상 메모리 공간을 구현하기 위해 x86 아키텍처 의 단순화 된 버전 에서 페이징이 작동하는 방법의 예입니다 .
페이지 테이블
OS는 다음 페이지 테이블을 제공 할 수 있습니다.
OS가 프로세스 1에 제공 한 페이지 테이블 :
RAM location physical address present
----------------- ----------------- --------
PT1 + 0 * L 0x00001 1
PT1 + 1 * L 0x00000 1
PT1 + 2 * L 0x00003 1
PT1 + 3 * L 0
... ...
PT1 + 0xFFFFF * L 0x00005 1
OS가 프로세스 2에 제공 한 페이지 테이블 :
RAM location physical address present
----------------- ----------------- --------
PT2 + 0 * L 0x0000A 1
PT2 + 1 * L 0x0000B 1
PT2 + 2 * L 0
PT2 + 3 * L 0x00003 1
... ... ...
PT2 + 0xFFFFF * L 0x00004 1
어디:
-
PT1
및PT2
: RAM에서 표 1 및 2의 초기 위치.샘플 값 :
0x00000000
,0x12345678
, 등그 값을 결정하는 것은 OS입니다.
-
L
: 페이지 테이블 항목의 길이. -
present
: 페이지가 메모리에 있음을 나타냅니다.
페이지 테이블은 RAM에 있습니다. 예를 들어 다음과 같이 위치 할 수 있습니다.
--------------> 0xFFFFFFFF
--------------> PT1 + 0xFFFFF * L
Page Table 1
--------------> PT1
--------------> PT2 + 0xFFFFF * L
Page Table 2
--------------> PT2
--------------> 0x0
두 페이지 테이블 모두 RAM의 초기 위치는 임의적이며 OS에 의해 제어됩니다. 중복되지 않도록하는 것은 OS에 달려 있습니다!
각 프로세스는 페이지 테이블을 직접 건드릴 수 없지만 OS에 요청하여 페이지 테이블을 수정하도록 할 수 있습니다 (예 : 더 큰 스택 또는 힙 세그먼트 요청).
페이지는 4KB (12 비트)의 청크이며 주소가 32 비트이므로 각 페이지를 식별하는 데 20 비트 (20 + 12 = 32, 따라서 16 진수 표기법의 5 개 문자) 만 필요합니다. 이 값은 하드웨어에 의해 고정됩니다.
페이지 테이블 항목
페이지 테이블은 … 페이지 테이블 항목의 테이블입니다!
테이블 항목의 정확한 형식은 하드웨어에 의해 고정 됩니다 .
이 단순화 된 예에서 페이지 테이블 항목에는 두 개의 필드 만 포함됩니다.
bits function
----- -----------------------------------------
20 physical address of the start of the page
1 present flag
따라서이 예에서 하드웨어 설계자는 L = 21
.
대부분의 실제 페이지 테이블 항목에는 다른 필드가 있습니다.
메모리는 비트가 아닌 바이트로 주소 지정이 가능하므로 21 비트로 정렬하는 것은 비현실적입니다. 따라서이 경우에는 21 비트 만 필요하더라도 하드웨어 설계자는 L = 32
액세스 속도를 높이고 나중에 사용할 수 있도록 나머지 비트 만 남겨 두도록 선택할 수 있습니다. L
x86 의 실제 값 은 32 비트입니다.
단일 수준 체계의 주소 변환
OS에서 페이지 테이블을 설정 하면 하드웨어 가 선형 주소와 물리적 주소 간의 주소 변환을 수행 합니다 .
OS가 프로세스 1을 활성화하려고 할 때 프로세스 1 에 대한 테이블의 시작 인 cr3
을로 설정합니다 PT1
.
프로세스 1이 선형 주소에 액세스하려는 경우 0x00000001
페이징 하드웨어 회로는 OS에 대해 자동으로 다음을 수행합니다.
-
선형 주소를 두 부분으로 나눕니다.
| page (20 bits) | offset (12 bits) |
따라서이 경우 우리는
- 페이지 = 0x00000
- 오프셋 = 0x001
-
cr3
그것을 가리 키기 때문에 페이지 표 1 을보십시오. -
0x00000
페이지 부분이기 때문에 항목을보십시오 .하드웨어는이 항목이 RAM 주소에 있음을 알고 있습니다
PT1 + 0 * L = PT1
. -
존재하기 때문에 액세스가 유효합니다.
-
페이지 테이블에 의해, 페이지 번호의 위치
0x00000
에 있습니다0x00001 * 4K = 0x00001000
. -
최종 물리적 주소를 찾으려면 오프셋을 추가하면됩니다.
00001 000 + 00000 001 ----------- 00001 001
00001
페이지의 실제 주소가 테이블에서 조회되고001
오프셋 이기 때문 입니다 .이름에서 알 수 있듯이 오프셋은 항상 페이지의 실제 주소에 추가됩니다.
-
그런 다음 하드웨어는 해당 물리적 위치에서 메모리를 가져옵니다.
같은 방식으로 프로세스 1에 대해 다음 번역이 발생합니다.
linear physical
--------- ---------
00000 002 00001 002
00000 003 00001 003
00000 FFF 00001 FFF
00001 000 00000 000
00001 001 00000 001
00001 FFF 00000 FFF
00002 000 00002 000
FFFFF 000 00005 000
예를 들어 주소 00001000
에 액세스 할 때 페이지 부분은 00001
하드웨어가 페이지 테이블 항목이 RAM 주소 PT1 + 1 * L
( 1
페이지 부분 때문에)에 있음을 알고 있으며 여기서 찾을 위치입니다.
OS가 프로세스 2로 전환하기를 원하면 2 cr3
페이지를 가리 키기 만하면됩니다. 간단합니다!
이제 프로세스 2에 대해 다음 번역이 발생합니다.
linear physical
--------- ---------
00000 002 00001 002
00000 003 00001 003
00000 FFF 00001 FFF
00001 000 00000 000
00001 001 00000 001
00001 FFF 00000 FFF
00003 000 00003 000
FFFFF 000 00004 000
동일한 선형 주소 는 내부 값에 따라서 만 다른 프로세스에 대해 다른 물리적 주소로 변환됩니다cr3
.
이러한 방식으로 모든 프로그램 은 정확한 물리적 주소에 대해 걱정하지 않고 데이터가에서 시작 0
하고 끝날 것으로 예상 할 수 있습니다 FFFFFFFF
.
페이지 폴트
프로세스 1이 존재하지 않는 페이지 내의 주소에 액세스하려고하면 어떻게됩니까?
하드웨어는 Page Fault Exception을 통해 소프트웨어에 알립니다.
그런 다음 수행해야 할 작업을 결정하기 위해 예외 처리기를 등록하는 것은 일반적으로 OS에 달려 있습니다.
테이블에없는 페이지에 액세스하는 것이 프로그래밍 오류 일 수 있습니다.
int is[1];
is[2] = 1;
그러나 다음과 같은 경우 Linux에서 허용되는 경우가있을 수 있습니다.
-
프로그램이 스택을 늘리려 고합니다.
주어진 가능한 범위에서 특정 바이트에 액세스하려고 시도하고 OS가 만족하면 해당 페이지를 프로세스 주소 공간에 추가합니다.
-
페이지가 디스크로 스왑되었습니다.
OS는 페이지를 RAM으로 되돌리려면 프로세스 뒤에서 몇 가지 작업을 수행해야합니다.
OS는 이것이 나머지 페이지 테이블 항목의 내용을 기반으로 한 경우임을 발견 할 수 있습니다. 현재 플래그가 지워지면 페이지 테이블 항목의 다른 항목이 OS가 원하는대로 완전히 남아 있기 때문입니다.
예를 들어 Linux에서 존재하는 경우 = 0 :
-
페이지 테이블 항목의 모든 필드가 0이면 잘못된 주소입니다.
-
그렇지 않으면 페이지가 디스크로 스왑되었으며 해당 필드의 실제 값이 디스크에서 페이지의 위치를 인코딩합니다.
-
어쨌든 OS는 문제를 처리 할 수 있도록 페이지 폴트를 생성 한 주소를 알아야합니다. 이것이 좋은 IA32 개발자 cr2
가 페이지 오류가 발생할 때마다 해당 주소 의 값을 설정하는 이유 입니다. 그런 다음 예외 처리기는 cr2
주소를 얻기 위해 조사 할 수 있습니다 .
단순화
이 예제를 이해하기 쉽게 만드는 현실 단순화 :
-
모든 실제 페이징 회로는 공간을 절약하기 위해 다중 레벨 페이징을 사용하지만 이것은 단순한 단일 레벨 체계를 보여줍니다.
-
페이지 테이블에는 20 비트 주소와 1 비트 존재 플래그라는 두 개의 필드 만 포함되었습니다.
실제 페이지 테이블에는 총 12 개의 필드가 포함되어 있으므로 생략 된 기타 기능이 있습니다.
예 : 다단계 페이징 체계
단일 레벨 페이징 체계의 문제점은 너무 많은 RAM을 차지한다는 것입니다 : 4G / 4K = 프로세스 당 1M 항목 . 각 항목의 길이가 4 바이트 인 경우 프로세스 당 4M 이됩니다 . 이는 데스크톱 컴퓨터에서도 너무 많은 양입니다. ps -A | wc -l
현재 244 개의 프로세스를 실행 중이므로 약 1GB의 RAM이 필요합니다!
이러한 이유로 x86 개발자는 RAM 사용량을 줄이는 다단계 체계를 사용하기로 결정했습니다.
이 시스템의 단점은 액세스 시간이 약간 더 높다는 것입니다.
PAE가없는 32 비트 프로세서에 사용되는 간단한 3 레벨 페이징 체계에서 32 주소 비트는 다음과 같이 나뉩니다.
| directory (10 bits) | table (10 bits) | offset (12 bits) |
각 프로세스에는 하나의 페이지 디렉토리 만 연결되어 있어야하므로 2^10 = 1K
단일 레벨 체계에 필요한 최소 1M보다 훨씬 더 나은 페이지 디렉토리 항목이 최소한 포함됩니다 .
페이지 테이블은 OS에서 필요한 경우에만 할당됩니다. 각 페이지 테이블에는 2^10 = 1K
페이지 디렉토리 항목이 있습니다.
페이지 디렉토리는 … 페이지 디렉토리 항목을 포함합니다! 페이지 디렉토리 항목은 테이블의 물리적 주소 대신 페이지 테이블의 RAM 주소를 가리키는 점을 제외하면 페이지 테이블 항목과 동일합니다 . 이러한 주소는 폭이 20 비트에 불과하므로 페이지 테이블은 4KB 페이지의 시작 부분에 있어야합니다.
cr3
이제 페이지 테이블 대신 현재 프로세스의 페이지 디렉토리에서 RAM 위치를 가리 킵니다.
페이지 표 항목은 단일 수준 체계에서 전혀 변경되지 않습니다.
페이지 테이블은 다음과 같은 이유로 단일 수준 체계에서 변경됩니다.
- 각 프로세스에는 페이지 디렉토리 항목 당 하나씩 최대 1K 페이지 테이블이있을 수 있습니다.
- 각 페이지 테이블은 1M 항목 대신 정확히 1K 항목을 포함합니다.
처음 두 레벨에서 10 비트를 사용하는 이유 12 | 8 | 12
는 각 페이지 테이블 항목의 길이가 4 바이트이기 때문입니다. 그러면 페이지 디렉토리와 페이지 테이블의 2 ^ 10 항목이 4Kb 페이지에 잘 맞습니다. 이는 해당 목적을 위해 페이지를 할당하고 할당 해제하는 것이 더 빠르고 간단하다는 것을 의미합니다.
다단계 체계의 주소 변환
OS가 프로세스 1에 제공 한 페이지 디렉토리 :
RAM location physical address present
--------------- ----------------- --------
PD1 + 0 * L 0x10000 1
PD1 + 1 * L 0
PD1 + 2 * L 0x80000 1
PD1 + 3 * L 0
... ...
PD1 + 0x3FF * L 0
PT1 = 0x10000000
( 0x10000
* 4K) 에서 OS가 프로세스 1에 제공 한 페이지 테이블 :
RAM location physical address present
--------------- ----------------- --------
PT1 + 0 * L 0x00001 1
PT1 + 1 * L 0
PT1 + 2 * L 0x0000D 1
... ...
PT1 + 0x3FF * L 0x00005 1
PT2 = 0x80000000
( 0x80000
* 4K) 에서 OS가 프로세스 1에 제공 한 페이지 테이블 :
RAM location physical address present
--------------- ----------------- --------
PT2 + 0 * L 0x0000A 1
PT2 + 1 * L 0x0000C 1
PT2 + 2 * L 0
... ...
PT2 + 0x3FF * L 0x00003 1
어디:
PD1
: RAM에서 프로세스 1의 페이지 디렉토리 초기 위치.PT1
및PT2
: RAM상의 프로세스 1에 대한 페이지 테이블 1 및 페이지 테이블 2의 초기 위치.
따라서이 예제에서 페이지 디렉토리와 페이지 테이블은 다음과 같이 RAM에 저장 될 수 있습니다.
----------------> 0xFFFFFFFF
----------------> PT2 + 0x3FF * L
Page Table 1
----------------> PT2
----------------> PD1 + 0x3FF * L
Page Directory 1
----------------> PD1
----------------> PT1 + 0x3FF * L
Page Table 2
----------------> PT1
----------------> 0x0
선형 주소를 0x00801004
단계별로 번역 해 봅시다 .
즉 cr3 = PD1
, 방금 설명한 페이지 디렉토리를 가리키는 것으로 가정합니다 .
바이너리에서 선형 주소는 다음과 같습니다.
0 0 8 0 1 0 0 4
0000 0000 1000 0000 0001 0000 0000 0100
다음과 같이 그룹화 10 | 10 | 12
:
0000000010 0000000001 000000000100
0x2 0x1 0x4
다음을 제공합니다.
- 페이지 디렉토리 항목 = 0x2
- 페이지 테이블 항목 = 0x1
- 오프셋 = 0x4
따라서 하드웨어는 페이지 디렉토리의 항목 2를 찾습니다.
페이지 디렉토리 테이블은 페이지 테이블이에 있습니다 0x80000 * 4K = 0x80000000
. 이것은 프로세스의 첫 번째 RAM 액세스입니다.
페이지 테이블 항목이 0x1
이므로 하드웨어는 페이지 테이블의 항목 1 0x80000000
을보고 물리적 페이지가 주소에 있음을 알려줍니다 0x0000C * 4K = 0x0000C000
. 이것은 프로세스의 두 번째 RAM 액세스입니다.
마지막으로 페이징 하드웨어가 오프셋을 추가하고 최종 주소는 0x0000C004
입니다.
번역 된 주소의 다른 예는 다음과 같습니다.
linear 10 10 12 split physical
-------- --------------- ----------
00000001 000 000 001 00001001
00001001 000 001 001 page fault
003FF001 000 3FF 001 00005001
00400000 001 000 000 page fault
00800001 002 000 001 0000A001
00801008 002 001 008 0000C008
00802008 002 002 008 page fault
00B00001 003 000 000 page fault
페이지 디렉토리 항목 또는 페이지 테이블 항목이없는 경우 페이지 폴트가 발생합니다.
OS가 다른 프로세스를 동시에 실행하려는 경우 두 번째 프로세스에 별도의 페이지 디렉터리를 제공하고 해당 디렉터리를 별도의 페이지 테이블에 연결합니다.
64 비트 아키텍처
64 비트는 여전히 현재 RAM 크기에 비해 너무 많은 주소이므로 대부분의 아키텍처는 더 적은 비트를 사용합니다.
x86_64는 48 비트 (256TiB)를 사용하며 레거시 모드의 PAE는 이미 52 비트 주소 (4PiB)를 허용합니다.
48 비트 중 12 개는 이미 오프셋을 위해 예약되어 있으며 36 비트를 남깁니다.
2 단계 접근 방식을 사용하는 경우 최상의 분할은 두 개의 18 비트 수준입니다.
그러나 이는 페이지 디렉토리에 2^18 = 256K
항목이있어서 너무 많은 RAM을 차지 한다는 것을 의미합니다. 32 비트 아키텍처의 경우 단일 레벨 페이징에 가깝습니다!
따라서 64 비트 아키텍처는 더 많은 페이지 수준 (일반적으로 3 또는 4)을 생성합니다.
x86_64는 9 | 9 | 9 | 12
체계 에서 4 개의 레벨을 사용 하므로 상위 레벨은 2^9
상위 레벨 항목 만 차지 합니다.
PAE
물리적 주소 확장.
32 비트에서는 4GB RAM 만 지정할 수 있습니다.
이것은 대형 서버에 대한 제한 사항이되기 시작하여 Intel은 Pentium Pro에 PAE 메커니즘을 도입했습니다.
이 문제를 해결하기 위해 인텔은 64GB를 처리 할 수 있도록 4 개의 새로운 주소 라인을 추가했습니다.
PAE가 켜져 있으면 페이지 테이블 구조도 변경됩니다. 변경되는 정확한 방법은 PSE가 켜져 있는지 꺼져 있는지에 따라 다릅니다.
PAE는 PAE
비트를 통해 켜고 끕니다 cr4
.
총 주소 지정 가능 메모리가 64GB이더라도 개별 프로세스는 최대 4GB까지만 사용할 수 있습니다. 그러나 OS는 다른 4GB 청크에 다른 프로세스를 배치 할 수 있습니다.
PSE
페이지 크기 확장.
페이지 길이는 4K 대신 4M (또는 PAE가 켜져있는 경우 2M)이 될 수 있습니다.
PSE는 PAE
비트를 통해 켜고 끕니다 cr4
.
PAE 및 PSE 페이지 테이블 체계
PAE와 PSE가 활성 상태이면 다른 페이징 수준 체계가 사용됩니다.
-
PAE 및 PSE 없음 :
10 | 10 | 12
-
PAE 및 PSE 없음 :
10 | 22
.22 비트 주소 4Mb이므로 22는 4Mb 페이지 내의 오프셋입니다.
-
PAE 및 PSE 없음 :
2 | 9 | 9 | 12
9가 10 대신 두 번 사용되는 설계 이유는 이제 항목이 더 이상 32 비트에 맞지 않는데, 이는 모두 20 개의 주소 비트와 12 개의 의미있는 또는 예약 된 플래그 비트로 채워졌습니다.
그 이유는 20 비트가 더 이상 페이지 테이블의 주소를 나타내는 데 충분하지 않기 때문입니다. 프로세서에 4 개의 추가 와이어가 추가 되었기 때문에 이제 24 비트가 필요합니다.
따라서 디자이너는 항목 크기를 64 비트로 늘리기로 결정했으며 단일 페이지 테이블에 맞추려면 항목 수를 2 ^ 10 대신 2 ^ 9로 줄여야합니다.
시작 2는 페이지 디렉토리를 가리키고 32 비트 선형 주소를 채우 므로 PDPT (Page Directory Pointer Table)라고하는 새로운 페이지 레벨 입니다. PDPT는 폭이 64 비트입니다.
cr3
이제 4 개의 4GB 메모리에 있어야하고 효율성을 처리하기 위해 32 비트 배수로 정렬되어야하는 PDPT를 가리 킵니다. 이것은 이제cr3
20이 아닌 27 개의 유효 비트가 있음을 의미합니다 . 32 배수의 경우 2 ^ 5 * 2 ^ 27은 처음 4GB의 2 ^ 32를 완료합니다. -
PAE 및 PSE :
2 | 9 | 21
디자이너는 한 페이지에 맞추기 위해 9 비트 너비의 필드를 유지하기로 결정했습니다.
이것은 23 비트를 남깁니다. PDPT가 PSE없이 PAE 케이스로 일관되게 유지하기 위해 2를 남겨두면 오프셋을 위해 21이 남습니다. 이는 페이지 너비가 4M 대신 2M임을 의미합니다.
TLB
TLB (Translation Lookahead Buffer)는 페이징 주소를위한 캐시입니다.
캐시이기 때문에 연관성 수준과 같은 CPU 캐시의 많은 설계 문제를 공유합니다.
이 섹션은 4 개의 단일 주소 항목이있는 단순화 된 완전 연관 TLB를 설명합니다. 다른 캐시와 마찬가지로 실제 TLB는 일반적으로 완전히 연관되지 않습니다.
기본 동작
선형 주소와 물리적 주소 간의 변환이 발생하면 TLB에 저장됩니다. 예를 들어, 4 개 항목 TLB는 다음 상태에서 시작됩니다.
valid linear physical
------ ------- ---------
> 0 00000 00000
0 00000 00000
0 00000 00000
0 00000 00000
은 >
대체 할 현재 항목을 나타냅니다.
페이지 선형 주소 00003
가 실제 주소로 변환 된 00005
후 TLB는 다음과 같습니다.
valid linear physical
------ ------- ---------
1 00003 00005
> 0 00000 00000
0 00000 00000
0 00000 00000
과의 두 번째 변환 이후 00007
에 00009
이된다 :
valid linear physical
------ ------- ---------
1 00003 00005
1 00007 00009
> 0 00000 00000
0 00000 00000
이제 00003
다시 번역해야하는 경우 하드웨어는 먼저 TLB를 찾고 단일 RAM 액세스로 해당 주소를 찾습니다 00003 --> 00005
.
물론 00000
유효한 항목이 00000
키로 포함되어 있지 않기 때문에 TLB에 없습니다 .
교체 정책
TLB가 채워지면 이전 주소를 덮어 씁니다. CPU 캐시와 마찬가지로 교체 정책은 잠재적으로 복잡한 작업이지만 간단하고 합리적인 휴리스틱은 최근에 가장 적게 사용 된 항목 (LRU)을 제거하는 것입니다.
LRU를 사용하면 상태에서 시작합니다.
valid linear physical
------ ------- ---------
> 1 00003 00005
1 00007 00009
1 00009 00001
1 0000B 00003
추가하면 다음 0000D -> 0000A
이 제공됩니다.
valid linear physical
------ ------- ---------
1 0000D 0000A
> 1 00007 00009
1 00009 00001
1 0000B 00003
캠
TLB를 사용하면 TLB 수준 당 하나의 액세스가 필요하므로 TLB를 사용하면 번역 속도가 빨라 집니다. 즉, 간단한 32 비트 체계에서는 2 개, 64 비트 아키텍처에서는 3 개 또는 4 개입니다.
TLB는 일반적으로 CAM (content-addressable memory)이라고하는 고가의 RAM 유형으로 구현됩니다. CAM은 하드웨어에 연관 맵을 구현합니다. 즉, 키 (선형 주소)가 주어진 구조가 값을 검색합니다.
매핑은 RAM 주소에서도 구현할 수 있지만 CAM 매핑에는 RAM 매핑보다 훨씬 적은 항목이 필요할 수 있습니다.
예를 들어 다음과 같은지도가 있습니다.
- 키와 값 모두 20 비트 (간단한 페이징 체계의 경우)
- 한 번에 최대 4 개의 값을 저장해야합니다.
4 개의 항목이있는 TLB에 저장할 수 있습니다.
linear physical
------- ---------
00000 00001
00001 00010
00010 00011
FFFFF 00000
그러나 이를 RAM으로 구현 하려면 2 ^ 20 개의 주소가 필요합니다 .
linear physical
------- ---------
00000 00001
00001 00010
00010 00011
... (from 00011 to FFFFE)
FFFFF 00000
TLB를 사용하는 것보다 훨씬 비쌉니다.
항목 무효화
때 cr3
변경 사항이 모든 TLB 엔트리를 무효화하는 새로운 프로세스에 대한 새로운 페이지 테이블을 사용하는 것입니다 때문에, 그래서 기존 항목 중 하나가 어떤 의미를 가질 것 같지는 않다.
x86은 invlpg
단일 TLB 항목을 명시 적으로 무효화하는 명령 도 제공합니다 . 다른 아키텍처는 지정된 범위의 모든 항목을 무효화하는 것과 같이 무효화 된 TLB 항목에 더 많은 지침을 제공합니다.
일부 x86 CPU는 x86 사양의 요구 사항을 넘어서 페이지 테이블 항목을 수정하고 TLB에 아직 캐시되지 않은 경우 사용하는 사이에 보장하는 것보다 더 많은 일관성을 제공 합니다 . 분명히 Windows 9x는 정확성을 위해 그것에 의존했지만 최신 AMD CPU는 일관된 페이지 워크를 제공하지 않습니다. 인텔 CPU는 그렇게하기 위해 오해를 감지해야하지만 그렇습니다. 이를 활용하는 것은 아마도 얻을 것이 많지 않을 것이며 디버깅하기 어려운 미묘한 타이밍에 민감한 문제를 일으킬 위험이 크기 때문에 아마도 나쁜 생각 일 것입니다.
Linux 커널 사용
Linux 커널은 x86의 페이징 기능을 광범위하게 사용하여 작은 데이터 조각화로 빠른 프로세스 전환을 허용합니다.
에서 v4.2
아래를보십시오 arch/x86/
.
include/asm/pgtable*
include/asm/page*
mm/pgtable*
mm/page*
페이지를 나타 내기 위해 정의 된 구조체는없고 매크로 만있는 것 같습니다 include/asm/page_types.h
. 특히 흥미 롭습니다. 발췌 :
#define _PAGE_BIT_PRESENT 0 /* is present */
#define _PAGE_BIT_RW 1 /* writeable */
#define _PAGE_BIT_USER 2 /* userspace addressable */
#define _PAGE_BIT_PWT 3 /* page write through */
arch/x86/include/uapi/asm/processor-flags.h
CR0
, 특히 PG
비트 위치를 정의합니다 .
#define X86_CR0_PG_BIT 31 /* Paging */
서지
비어 있는:
-
rutgers-pxk-416 “메모리 관리 : 강의 노트”장
이전 OS에서 사용하는 메모리 구성 기술에 대한 좋은 역사적 검토.
비 무료 :
-
bovet05 장 “메모리 주소 지정”
x86 메모리 주소 지정에 대한 합리적인 소개. 좋고 간단한 예가 누락되었습니다.
답변
다음은 매우 짧고 높은 수준의 답변입니다.
x86 프로세서는 여러 가능한 모드 (대략 : 실제, 보호, 64 비트) 중 하나로 작동합니다. 각 모드는 여러 가능한 메모리 주소 지정 모델 중 하나를 사용할 수 있습니다 (모든 모드가 모든 모델을 사용할 수있는 것은 아님). 즉, 리얼 모드 주소 지정, 세그먼트 화 된 주소 지정 및 평면 선형 주소 지정.
현대 세계에서는 보호 모드 또는 64 비트 모드의 평면 선형 주소 지정 만 관련되며 두 모드는 본질적으로 동일하며 주요 차이점은 기계어의 크기와 따라서 주소 지정 가능한 메모리 양입니다.
이제 메모리 주소 지정 모드는 기계 명령어의 메모리 피연산자 (예 : mov DWORD PTR [eax], 25
32 비트 (일명 dword
) 정수 값 25를 주소가 eax
32 비트 레지스터에 저장된 메모리에 저장 )에 의미를 부여합니다. 플랫 선형 어드레싱이 번호 eax
최대 값으로부터 제로까지, 하나의 연속 영역을 통해 실행할 수있다 (우리의 경우 2 있다고 32 – 1)의.
그러나 플랫 선형 주소 지정은 페이징 되거나 페이징되지 않을 수 있습니다 . 페이징이 없으면 주소는 물리적 메모리를 직접 참조합니다. 로 페이징, 프로세서의 메모리 관리 유닛 (또는 MMU)를 투명하게 (현재 착신 원하는 주소 피드 가상 어드레스 룩업 메커니즘 소위으로) 페이지 테이블 및 물리 어드레스로 해석되는 새로운 값을 구한다. 이제 원래 작업은 사용자가 가상 주소 만 볼 수있는 경우에도 물리적 메모리의이 새로운 변환 된 주소에서 작동합니다.
페이징의 주요 이점은 페이지 테이블이 운영 체제에서 관리된다는 것입니다. 따라서 운영 체제는 “작업 전환”과 같이 페이지 테이블을 임의로 수정하고 교체 할 수 있습니다. 각 “프로세스”에 대해 하나씩 전체 페이지 테이블 모음을 유지할 수 있으며 특정 프로세스가 주어진 CPU에서 실행될 것이라고 결정할 때마다 프로세스의 페이지 테이블을 해당 CPU의 MMU로로드합니다 (각 CPU에는 자체 페이지 테이블 세트). 결과적으로 각 프로세스는 OS가 메모리를 할당해야 할 때 사용 가능한 물리적 페이지에 관계없이 동일하게 보이는 자체 가상 주소 공간을 보게 됩니다. 실제 메모리에 직접 액세스 할 수 없기 때문에 다른 프로세스의 메모리에 대해 알지 못합니다.
페이지 테이블은 일반 메모리에 저장되는 중첩 된 트리 형태의 데이터 구조로 OS에서 작성되지만 하드웨어에서 직접 읽으므로 형식이 고정됩니다. 최상위 테이블을 가리 키도록 특수 CPU 제어 레지스터를 설정하여 MMU에 “로드”됩니다. CPU는 TLB라고하는 캐시를 사용하여 조회를 기억하므로 TLB 누락 및 일반적인 데이터 캐시 이유 때문에 동일한 몇 페이지에 대한 반복 액세스가 분산 액세스보다 훨씬 빠릅니다. TLB에 캐시되지 않은 경우에도 페이지 테이블 항목을 참조하는 데 사용되는 “TLB 항목”이라는 용어를 보는 것이 일반적입니다.
그리고 프로세스가 페이징을 비활성화하거나 페이지 테이블을 수정하려고 시도 할 수 있다고 걱정하는 경우 : x86이 권한 수준 ( “링”이라고 함)을 구현 하고 사용자 코드가 허용하기에 너무 낮은 권한 수준에서 실행 되므로 이는 허용되지 않습니다. CPU의 페이지 테이블을 수정합니다.