MS-DOS가 도는 옛 PC의 메모리는 1메가바이트짜리 건물 한 채다. 맨 아래층에는 “무슨 일이 생기면 어디로 가라”는 안내판이 있고, 그 위로 운영체제, 내 프로그램, 화면에 쓸 자리, 맨 꼭대기에 지울 수 없는 기본 프로그램이 층층이 놓인다. 층마다 주소가 정해져 있어서 어느 프로그램이든 화면이나 키보드 상태를 주소만으로 바로 건드릴 수 있다. 그만큼 위험해서, 층 사이에 문이 없다 보니 프로그램 하나가 실수하면 운영체제의 자리까지 망가뜨린다.
예시로 보기
요즘 운영체제에서는 프로그램이 화면이나 키보드를 직접 건드릴 수 없다. 운영체제에 부탁해야 한다. 실주소 모드의 MS-DOS는 반대다. 한 번에 프로그램 하나만 돌고, 메모리 경계를 지키는 장치가 없다. 프로그램은 1MB 안의 어느 주소든 읽고 쓸 수 있다.
1MB는 \(2^{20}\)바이트이고, 주소로는 00000h부터 FFFFFh까지다. 이 안이 다음처럼 나뉜다.
주소
FFFFFh +------------------------------------+
| ROM BIOS | 64K
F0000h +------------------------------------+
| 예약 (장치 제어기용) | 192K
C0000h +------------------------------------+ -+
| 비디오: 글자와 그래픽 | |
B8000h +------------------------------------+ | VRAM (화면 메모리) 128K
| 비디오: 그래픽 | |
A0000h +------------------------------------+ -+
| (잠깐 올라오는 명령 처리기) | |
| 응용 프로그램이 쓰는 자리 | |
| Transient Program Area | |
+------------------------------------+ |
| 늘 올라와 있는 명령 처리기 | | 640K RAM
+------------------------------------+ |
| DOS 커널, 장치 드라이버 | |
+------------------------------------+ |
| 소프트웨어 BIOS | |
+------------------------------------+ |
| BIOS·DOS 데이터 | |
00400h +------------------------------------+ |
| 인터럽트 벡터 표 | |
00000h +------------------------------------+ -+
아래쪽 640K(00000h~9FFFFh)가 보통의 RAM이다. 그 위 128K는 화면에 보일 내용을 담는 메모리(VRAM)이고, 맨 위 64K에는 전원을 꺼도 남아 있는 BIOS 프로그램이 있다. 크기를 더하면 640 + 128 + 192 + 64 = 1,024K로 딱 1MB다1.
구역별 내용
| 구역 | 들어 있는 것 |
|---|---|
| 인터럽트 벡터 표 (00000h~003FFh) | 인터럽트 번호마다 처리 코드의 주소 4바이트. 칸이 256개라 1,024바이트다: INT 명령과 인터럽트 벡터 표 |
| BIOS·DOS 데이터 (00400h~) | 장치 상태를 적어 두는 자리. 아래 표 참고 |
| 소프트웨어 BIOS, DOS 커널 | 장치를 다루는 코드와 MS-DOS 본체 |
| 명령 처리기 | 사용자가 친 명령을 읽어 실행하는 프로그램. 늘 올라와 있는 부분과, 자리가 모자라면 응용 프로그램에 덮여도 되는 부분으로 나뉜다2 |
| 응용 프로그램 자리 | 내가 만든 프로그램이 올라오는 곳 |
| 비디오 메모리 (A0000h~BFFFFh) | 화면에 보이는 글자와 점: BIOS 비디오 INT 10h와 속성 바이트 |
| ROM BIOS (F0000h~FFFFFh) | 지워지지 않는 기본 입출력 코드 |
낮은 주소부터 차례로 적으면 인터럽트 벡터 표, BIOS·DOS 데이터, 소프트웨어 BIOS, MS-DOS 커널, 상주 명령 처리기, 잠깐 올라오는 프로그램, 비디오, 예약, ROM BIOS 순서다.
BIOS 데이터 영역
주소 00400h부터는 BIOS와 MS-DOS가 장치의 상태를 적어 두는 자리다. 위치가 고정이라 어느 프로그램이든 같은 주소에서 같은 정보를 읽는다. 세그먼트 0040h로 잡으면 오프셋이 표의 값 그대로다.
| 오프셋(16진) | 내용 |
|---|---|
| 0000~0007 | 직렬 포트 COM1~COM4의 주소 |
| 0008~000F | 병렬 포트 LPT1~LPT4의 주소 |
| 0010~0011 | 달려 있는 하드웨어 목록 |
| 0013~0014 | 메모리 크기(킬로바이트) |
| 0017~0018 | 키보드 상태 플래그 |
| 001A~001B, 001C~001D | 키보드 버퍼의 머리 포인터와 꼬리 포인터 |
| 001E~003D | 미리 입력한 키를 쌓아 두는 버퍼 |
| 0049 | 지금 비디오 모드 |
| 004A~004B | 화면의 칸 수 |
| 0050~005F | 비디오 페이지 1~8의 커서 위치 |
| 0062 | 지금 보이는 비디오 페이지 번호 |
| 006C~0070 | 타이머 자료 |
예: 키보드 상태 플래그는 0040:0017에 있다. 세그먼트에 16을 곱해 오프셋을 더하면 \(0040\text{h} \times 16 + 0017\text{h} = 00417\text{h}\)다: 실주소 모드의 세그먼트 주소.
이 영역은 Windows 98과 Windows Me에서는 읽을 수 있지만 Windows NT, 2000, XP에서는 읽을 수 없다.
활용
- INT 21h, INT 16h, INT 10h, 인터럽트 처리기 바꾸기는 모두 이 배치를 전제로 한다. 16비트 실주소 모드에서만 돈다.
- 흔한 실수: 640K를 “메모리 전체”로 읽는 것. 주소 공간은 1MB이고, 640K는 그 가운데 프로그램과 운영체제가 쓰는 RAM이다.
연결
- 주소를 세그먼트와 오프셋으로 쓰는 법: 실주소 모드의 세그먼트 주소
- 실주소 모드와 보호 모드의 차이: x86 동작 모드
- 프로그램이 운영체제 자리를 못 건드리게 막는 장치: 사용자 모드와 커널 모드
확인 문제
C1 MS-DOS 메모리 맵에서 00000h, 00400h, A0000h, F0000h에서 시작하는 구역은 각각 무엇인가?
답: 00000h 인터럽트 벡터 표, 00400h BIOS·DOS 데이터, A0000h 비디오 메모리(VRAM), F0000h ROM BIOS.
C2 키보드 버퍼는 0040:001E에서 시작한다. 선형 주소는? 글자 화면 메모리의 B800:00A0은?
답: 0041Eh, B80A0h.
이유: 세그먼트 뒤에 16진수 0을 하나 붙이고(× 16) 오프셋을 더한다. 00400h + 001Eh = 0041Eh, B8000h + 00A0h = B80A0h.
C3 실주소 모드의 프로그램은 왜 BIOS 데이터 영역을 주소만으로 바로 읽을 수 있는가? Windows NT 이후에는 왜 안 되는가?
답: 실주소 모드에는 메모리 경계를 지키는 장치가 없어서 프로그램이 1MB 안의 어느 주소든 읽고 쓴다. 그리고 그 영역의 위치가 00400h로 고정이다. Windows NT 이후의 운영체제는 응용 프로그램이 이 영역에 직접 가는 것을 막는다.
이유: 직접 갈 수 있다는 것은 실수로 망가뜨릴 수도 있다는 뜻이다. 보호 장치가 생기면서 길이 닫혔다.