|
ncloader
0.1
|
Memory에 대한 협력 다이어그램:이 장에서는 Real Mode 상태에서의 Memory Map 과 메모리 접근 방법, A20 Enable 방법에 대해 알아본다. 처음 IBM PC 가 등장했을 때, 16 bits 컴퓨터로 접근할 수 있는 최대 메모리 주소는 1 MB 였다. 그 중 640 KB(0 – 0x9ffff) 만을 프로그램에게 할당하고, 나머지 384 KB (0xa0000 – 0xffff) 는 BIOS 와 ISA 장치용으로 할당하였다.
다음은 메모리 구성 내용이다.
| 시작 주소 | 마지막 주소 | 영역 |
|---|---|---|
| 0x0000:0x0000 | 0x0000:0x03FF | IVT (Interrupt Vector Table) |
| 0x0000:0x0400 | 0x0000:0x04FF | BDA (BIOS Data Area) |
| 0x0000:0x0500 | 0x0000:0x7BFF | Free Usable Memory |
| 0x0000:0x7c00 | 0x0000:0x7DFF | Boot program |
| 0x0000:0x7E00 | 0x9000:0xFFFF | Free usable memory |
| 0xA000:0x0000 | 0xB000:0xFFFF | VGA Video RAM |
| 0xC000:0x0000 | 0xF000:0xFFFF | BIOS ROM Memory Area |
| 0xFFFF:0x0010 | 0xFFFF:0xFFFF | Free usable memory(A20) |
<표 1> Real mode 에서의 메모리 구성
IVT 는 Interrupt Vector Table 이 기록된 위치로, 인터럽트를 처리하는 핸들러들이 구현되어 있는 곳이다. (* ARM 계열 CPU 도 0번지부터 IVT 가 시작된다.) 이 IVT 에는 0으로 나누는 경우를 위한 Divide Error Handler 를 비롯하여, 시스템 타이머에 의해 CPU 에 걸린 인터럽트를 처리하는 System timer interrupt handler 등 S/W Interrupt(Trap) 부터 H/W Interrupt(Interrupt) 까지 각각에 대한 Handler Address 들이 저장된다.
Real mode 에서 정의된 Interrupt Vector Table 은 보호모드로 진입하게 되면 새로 정의한다.
Free usable memory 는 말 그대로 사용 가능한 메모리 영역으로, 우리가 만들 운영체제 코드, 부트로더등이 적재될 메로리 공간이다. CPU 는 디스크에 있는 코드를 메모리에 적재한 후 실행하는 것이 일반적이다.
Boot Sector 는 응용 프로그램이 사용 가능한 메모리 공간 중에, 디스크의 부트 섹터가 적재되는 영역으로 앞에서 누차 말했던 0x07c00 부분이다.
VGA Video ram 영역은 디스플레이 장치와 직접 연관된 부분으로 Device mapped memory area 라고도 볼 수 있다. 해당 영역에 값을 쓰게 되면, 관련된 CRT 장치로 글자가 출력되어 사용자가 볼 수 있게 된다. 예를 들어 0xb8000(0xb800:0000) 은 80x25 color mode 비디오 공간으로 값을 쓰게 되면 화면에 글자가 찍히는 것을 확인할 수 있다. 이 후 printf 함수를 비록하여 기본적인 I/O 함수 구현에서 사용된다.
BIOS ROM 영역은 BIOS 에서 사용하는 읽기 전용 데이터들이 기록된 곳으로, 우리가 사용할 수 있는 공간은 아니다.
지금까지 설명한 메모리 공간은 Real mode 상의 공간이다. x86 CPU 는 Real mode 와 Protoected mode 를 지원하는데, Real mode 는 옛날 시스템과의 호환을 위해 남아 있는 모드이다. (64 Bits 에서는 Long mode 가 있다.)
Real mode 에서 주소 표기 방식은 Segmentation 을 사용하고 있으며, Segment 를 4 bits shift 한 후 Offset 과 더해서 Linear address 를 얻게 된다.
| Linear Address = Segment << 4 + Offset |
테이블의 마지막에 있는 활용 가능 메모리에 A20 이라고 표시된 부분이 있다. PC는 0xFFFF:0x0010 ~ 0xFFFF:0xFFFF 영역을 Wrap-around 영역이라고 해서 남겨 두었다. (0x100000 ~ 0x10FFEF) (물론 남겨두고 싶어서 남겨 둔 건 아니고, 그 당시 접근 가능한 메모리 주소가 20 Bits 밖에 되지 않았으므로..)
실제로 이 영역을 접근하려고 하면, 0x0000:0x0000 영역 이후를 접근 하도록 한 것이다. 하지만 향 후 컴퓨터가 발전하면서 상위 메모리를 수용할 수 있는 램이 등장하였고, 이 영역을 사용할 수 있게 되었다. 하지만, 예전의 컴퓨터를 위해 개발된 응용프로그램 들은 새로운 영역에 대해 잘못된 계산을 할 수 있었고, 이를 방지하기 위해 A20 Gate 을 설치했다.
하위 호환성을 유지하면서, 표현 가능한 전체 주소 영역을 모두 쓰기 위해서, A20 Line 이 소개 된 것이다.
A20 Line 을 Enable 시키는 방법은 여러가지가 있지만 주로 다음과 같은 두가지 방식을 사용한다.
Port 0x92 를 이용한 A20 Gate 활성화
위에서 설명한 코드를 이용하면 A20 Gate 를 Enable 시킬 수 있다. 활성화가 제대로 되었는지를 확인하기 위한 코드는 아래와 같다.
FS 세그먼트를 초기화 시키기 위해 AX 를 0 으로 만든 후, AX 레지스터 값을 FS 세그먼트에 대입했고, BX 에 0xFFFF 값을 대입한 후, GS 세그먼트에 그 값을 저장하였다.
Wrap around 영역에 값을 넣고, 0:0 영역의 값을 비교하는 것으로, A20 Gate 활성화 상태를 확인했다.
Reference site : http://www.osdever.net/tutorials/rm_addressing.php?the_id=50
이제 우리는 1 MB 영역을 넘어서는 곳도 접근할 수 있게 되었다.
프로그램이 동작하기 위해서는 데이터 영역과 스택 영역이 필요하다. SS, SP, BP 와 DS 를 초기화 해주는 것으로 시작된다. SS 는 Stack segment, SP는 Stack pointer, BP 는 Base pointer, DS 는 Data segment 를 의미한다. 세그먼트의 경우 즉치 값을 바로 설정할 수 없기 때문에 반드시 레지스터를 한 번 거쳐서 사용하거나 메모리에 기록된 값을 전달해 주는 방식으로 해야 한다. 메모리 맵은 위에서 설명한 공간 중 사용 가능 공간을 임의의 방식대로 적절히 나누어서 사용하면 된다. 다만 스택과 DS 를 초기화 할 때에는 인터럽트가 발생하지 못하게 설정해 두어야 한다. 스택을 변경하는 도중에 인터럽트가 발생하면 스택이 꼬일 수 있기 때문이다. 아래는 초기화와 관련된 코드이다.
Stage 1 에서는 이정도로 Memory 를 초기화 하고, Stage 2 에서 좀 더 많은 정보를 다루기로 한다.