메모리 주소 종류
80x86 프로세서에서는 세 종류의 메모리 주소가 있습니다.

논리 주소
세그먼트 구조에서 Segment Selectro + 오프셋 형식으로 나타냅니다.
기계어 명령어에서 피연산자나 명령어 주소를 지정할 때 사용되는 주소로 디버깅할때나 어셈블리에서 사용되는 주소가 이 주소입니다.
[논리 주소 예]
사용자 삽입 이미지











선형주소
보통 16진수로 표기하며 0x00000000 ~ 0xffffffff 까지 지정할 수 있습니다.

[선형주소 예]
사용자 삽입 이미지








물리주소
메모리의 실제주소입니다.

메모리 모델에 대해서 좀 더 자세한 설명
http://www.hanb.co.kr/network/view.html?bi_id=1321

[리눅스에서 메모리 주소 변환 과정]
사용자 삽입 이미지





















위에 그림을 보시면 먼저 세그먼트로 나누어져 있는 메모리에 세그먼트 식별자와 오프셋값을 이용하여 찾아가면 해당
데이터의 선형 주소가 있고 그 선형 주소를 이용하여 페이징 되어 있는 메모리를 찾아가면 물리 주소가 있습니다.




리눅스에서의 세그먼테이션
세그먼테이션은 각 프로세스에 다른 선형 주소 공간을 할당하는 메모리 관리 기법입니다.
리눅스에서는 메모리 관리를 좀 더 간단하고 다른 대중적인 아키텍처와 호환하기 위해서 세그먼테이션을 매우 제한적으로 지원합니다.

세그먼트 디스크립터는 세그먼트 특징을 기술하는 8바이트 크기의 데이터입니다.
세그먼트 디스크립터는 GDT(Global Descriptor Table)이나 LDT(Local Descriptor Talbe)에 저장 되는데, GDT는 보통 하나만 정의하지만 LDT는 필요한 만큼 정의해서 사용할수 있습니다. GDT가 위치한 주소는 gdtr 프로세서 레지스터에, LDT는 lgtr 프로세서 레지스터에 들어가 있습니다.

[세그먼트 디스크립터 필드들]
사용자 삽입 이미지




























이러한 세그먼테이션 디스크립터를 이용하여 세그먼테이션 유닛이 논리 주소를 선형 주소로 변환합니다.
세그먼테이션 유닛은 세그먼테이션를 처리하기 위한 하드웨어 적인 회로로써 다음과 같은 작업을 수행합니다.

    1. 세그먼트 셀렉터의 TI 필드를 검사해서 세그먼트 디스크립터가 어떤 디스크립터 테이블에 들어 있는지 확인합니다. TI 필드는 디스크립터가 있는 위치를 나타내는 필드입니다.
    2. 세그먼트 셀렉터의 index 필드로 세그먼트 디스크립터의 주소를 계산합니다. 즉 index 필드에 세그먼트 디스크립터의 크기를 곱한 값을 gdtr이나 ldtr의 레지스터 내용에 더합니다.
    3. 세그먼트 디스크립터의 Base 필드에 논리 주소의 오프셋을 더하여 선형 주소를 얻게 됩니다.

[세그먼트 논리 주소 변환 과정]
사용자 삽입 이미지


















또한 세그먼트 디스크립터로의 빠른 접근하기 위해서 80x86프로세서는 논리 주소를 선형 주소로 빠르게 변형하기 위하여 프로그래밍이 가능한 여섯개의 세그먼테이션 레지스터에 각각 프로그램이 불가능한 레지스터를 추가로 제공합니다.
세그먼트 셀렉터를 세그먼테이션 레지스터로 로딩할때마다 이 프로그래밍이 불가능한 레지스터에 세그먼트 디스크립터를 저장하여 프로세서가 GDT나 LDT에 접근하지 않고 바로 세그먼트에 접근 할 수 있도록 해줍니다.




리눅스에서의 페이징
페이징은 선형주소를 '페이지'라는 고정된 크기로 나누는 메모리 관리 기법입니다.
한 페이지에 있는 연속된 선형 주소는 연속된 물리 주소로 매핑되어 커널은 모든 선형 주소마다 물리 주소와 접근 권한을 지정하는 것이 아니라 페이지 단위로 지정합니다.
페이징 유닛은 램의 모든 영역이 '페이지 프레임'이라는 고정된 길이로 나뉘어져 있다고 생각하며, 각 페이지 프레임마다 페이지가 하나씩 들어가는 식으로 메모리를 관리합니다.

일반적으로 80x86에서는 4KB 크기의 페이지를 사용합니다.
선형 주소 변환은 '페이지 디렉토리'라고 하는 변환 테이블을 사용하는 단계와 '페이지 테이블'을 사용하는 단계로 이루어집니다. 이렇게 두 단계로 나누어 변환하는 이유는 프로세스마다 필요한 페이지 테이블이 램에서 차지하는 크기를 줄이기 때문입니다.

[일반적인 80x86 프로세서의 페이징]
사용자 삽입 이미지













제어 레지스터 cr3에는 현재 사용 중인 페이지 디렉토리의 물리 주소가 들어 있습니다. 이를 좀 더 자세히 살펴 보겠습니다.

커널이 어떤 프로세스에 0x20000000에서 0x2003ffff까지 선형 주소를 할당하였고 0x20021406에 있는 값을 가져오려고 하겠습니다.

1. 먼저 페이징 유닛은 선형주소의 상위 10비트를 페이지 디렉토리에서 페이지 테이블을 가리키는 주소로 해석합니다.
즉, 0001 0000  0000 0000 0000 0000 0000 0000에서 상위 비트 10비트는 0001 0000 00인데 이 값은 00 1000 0000 으로 0x80입니다.
2. 테이블 디렉토리의 0x80번째 엔트리가 가리키는 페이지 테이블에서 선형주소의 상위10비트 다음의 10비트 값을 해석합니다. 즉 중간 비트 10비트인 0x0에서 0x3f까지가 할당된 페이지입니다.
3. 마지막으로 0x406값은 오프셋 필드 값으로 할당된 페이지에서 0x406 오프셋에 있는 값을 가져오게 됩니다.


리눅스에서는 32비트와 64비트 아키텍처 양쪽 모두에 적합하도록 페이징을 3단계 걸쳐서 수행합니다.
(커널 2.6.11부터는 네 단계의 페이징 모델이 채택되었습니다)
[리눅스에서의 페이징]
사용자 삽입 이미지













일반적인 32비트 아키텍처에서는 페이지 중간 디렉토리 필드의 길이가 0비트라고 표시하고 페이지 상위 디렉토리 및 페이지 중간 디렉토리를 기본적으로 제거합니다. 하지만 포인터 연결 과정에서 페이지 상위 디렉토리와 페이지 중간 디렉토리의 위치는 그대로 남겨놓아서 동일한 코드로 32비트와 64비트 아키텍처 모두 정상적으로 동작하게 됩니다.
물리 주소 확장 기능이 활성된 32비트 아키텍처에서는 페이지 전역 디렉토리가 80x86의 페이지 디렉토리 포인터 테이블에 해당되며, 페이지 상위 디렉토리는 제거되고 리눅스의 중간 디렉토리는 80x86의 페이지 디렉토리에, 리눅스의 페이지 테이블은 80x86의 페이지 테이블에 해당하게됩니다.
64비트 아키텍처에서는 3 또는 4 단계의 페이징이 사용됩니다.


출처 : http://guimong.tistory.com/category/Linux%20Kernel

WRITTEN BY
RootFriend
개인적으로... 나쁜 기억력에 도움되라고 만들게되었습니다.

,