일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- libtins
- #IntelManual #segment Descriptor #세그먼트 디스크립터 #MINT64 #Sqix
- #Qt Creator
- ftz
- Network
- linux
- vi 외부 명령어
- Sqix
- vim
- KASAN
- 오버워치
- Find
- #IntelManual
- FTZ 레벨2
- vi
- #MINT64 #Sqix
- libpcap
- #
- C++11
- 인터럽트
- 오버워치 세이버메트릭스
- Overwatch League SaberMetrics
- #Best of the Best #OS #MINT64 #Sqix
- command
- >
- BEST of the BEST
- Today
- Total
Sqix
64bit 멀티코어 OS 제작하기 [3] - 3 : 부트로더 화면 제어 본문
이번 글은 부트로더 제작에 대해 다룹니다.
기존에 제작한 부트로더는 QEMU 기본 출력만 나와 있었습니다. 이제 보다 그럴듯하게 부트로더를 만들어 보도록 합시다.
(출처 : http://byuljong.tistory.com/88)
화면에 글자를 출력하기 위해서는 Video Memory의 주소를 알아야 합니다. 메모리에 형식에 맞춰 데이터를 넣는다면 원하는 것을 출력할 수 있습니다. Default 화면 설정은 80*20의 크기를 가지며, 시작 Address는 0xB8000입니다. 한 문자당 1byte씩의 문자, 속성값을 가지고, 따라서 메모리 크기는 80*25*2 == 4000 byte입니다. 위 그림에서 보이다시피, 속성값은 0~3비트의 전경, 4~7비트의 배경색으로 나뉩니다. 이는 다시 Attribute field(최상위)와 전경, 배경색으로 나뉩니다.
텍스트 모드의 속성값 구성은 다음과 같습니다.
BIT 00 ~ 02
- 0x00 : Black
- 0x01 : Blue
- 0x02 : Green
- 0x03 : Cyan(청색)
- 0x04 : Red
- 0x05 : Magneta(자홍색)
- 0x06 : Yellow
- 0x07 : White
BIT 03
- 0x00 : No Effect
- 0x01 : 배경색 -> Blink or Highlight on 00~02 bit / 전경색 -> Highlight on 00~02 bit
비디오 메모리의 시작 주소에 접근하려면 세그먼트 레지스터에 정의된 기준 주소에 값을 더해서 계산해야 하므로, 우선 기준 주소부터 설정해 주어야 합니다. 범용 레지스터들과 세그먼트 레지스터를 조합해서 0xB800을 만들어도 좋지만, 편리하게 세그먼트 레지스터에 0xB800을 넣어서 간단하게 쓸 수도 있습니다.
mov ax, 0xB800
mov ds, ax
이렇게 범용 레지스터에 0xB800을 넣고, 이를 다시 세그먼트 레지스터에 넣어서 설정해 주면 됩니다. 이렇게 하면 데이터에 접근하는 명령어는 기준 주소 0xB8000이 기준 주소로 사용됩니다. 이제 이 다음에 글자를 넣어야 하는데, 이 작업을 수행하려면 메모리 참조를 통해 해당 메모리에 값을 복사해 주어야 합니다. 보통 lea, mov 명령어를 이용하고, [ ] 를 통해서 메모리 참조를 하겠다고 알리며, 이 앞에는 자료형(dword, qword, byte, word)이 표기됩니다.
mov byte [ 0x00 ], 'M'
mov byte [ 0x01 ], 0x4A
이는 위의 세그먼트 레지스터 초기화 명령어와 이어집니다. 가장 최근에 이용한 레지스터인 ds가 기준이 되며, 해당 레지스터를 참조하여 가져온 값인 0xB8000에 byte [0x00]의 오프셋을 더하여 그 위치에 'M'을 넣고, 그 뒤에는 0x01 + 0xB8000의 위치에 0x4A의 값을 넣어 4 = 빨간색 배경, A = 녹색 효과를 주겠다는 의미입니다. 이제 해당 내용을 기반으로 부트로더의 로딩 화면에 메시지를 띄워 보도록 합시다.
여러 문자를 출력하기 전에, 세그먼트 레지스터에 있는 값을 초기화하는 것이 좋습니다. 이전에 BIOS에서 진행한 작업의 결과값이 들어가 있어 꼬일 수 있기 때문입니다. 여기서는 BIOS가 부트 로더를 읽어서 메모리에 복사하는 위치인 0x07C0으로 초기화를 했습니다. 우리는 ds, cs를 해당 값으로 바꾸어야 하는데, 여기서 ds는 기존의 mov 명령어를 이용해서 초기화를 하면 되지만, cs는 코드 세그먼트이기 때문에 instruction pointer(IP)와 연관이 있어 mov만으로 바뀐다면 코드가 취약해질 수 있다는 이유로 일반적인 복사 명령어로는 바꿀 수 없습니다(자세한 내용은 https://goo.gl/o84GHJ에서 확인해 보시기 바랍니다). 따라서 우리는 jmp 명령어를 이용해 이를 바꾸도록 하겠습니다.
또한, ES 세그먼트는 화면 출력에 이용할 것이기 때문에 0xB800으로 초기화를 하였습니다. 따라서 es를 기준 주소로 잡고 offset을 더해서 화면 출력을 할 것이기 때문에 어셈블리 코드도 mov byte [es : 0x00], 'M' <- 과 같은 식으로 es에서 특정 오프셋만큼 더해서 그 곳에 값을 복사한다! 와 같이 작성해 주어야 할 것입니다. 결과는 아래와 같습니다.
SECTION .text
jmp 0x07C0 : START
START :
mov ax, 0x07C0
mov ds, ax
mov ax, 0xB800
mov es, ax
mov byte [ es: 0x00 ], 'M'
mov byte [ es: 0x01 ], 0x4A
이제 출력을 하는 방법을 알았으니, 기존에 화면에 나와 있던 문자열들을 깔끔하게 정리해 보도록 하겠습니다. 화면 전체에 출력된 값을 전부 없앨 것이기 때문에 루프를 활용합니다. 먼저 si 레지스터에 있는 문자열 인덱스 레지스터를 0으로 초기화해 줍니다. 그 후, 바탕색을 담은 문자(0x0A)를 si(문자열 인덱스)의 위치에 넣어 주고 si를 1씩 증가시켜 si가 총 화면 크기와 같아질 때 까지 출력해 주면 깔끔하게 지울 수 있습니다.
또한, 그 후 우리가 원하는 메세지를 출력해 줄 것입니다. 마찬가지로 si, di(문자열대상 레지스터)를 0으로 초기화해 주고, 원하는 문자열을 하나씩 출력해 줍니다. 원하는 문자열이 종료되는 동시에 루프는 종료가 될 것입니다.
이를 통해 만든 소스 코드는 다음과 같습니다.
그리고 실행을 해서 작동을 확인합니다. 명령어는 이전과 동일합니다.
# qemu-system-x86_64 -m 64 -fda ./Disk.img -localtime -M pc
이제 부트로더가 완성되었습니다. 다음 글에서는 OS 이미지를 로딩하는 기능을 추가하고, 테스트용 OS 이미지를 이용해 부트로더의 성능 테스트를 해 보도록 하겠습니다.
감사합니다.
'MINT64 OS ' 카테고리의 다른 글
64bit 멀티코어 OS 제작하기 [4] - 2 : OS 이미지 로딩을 위한 부트로더 기능 추가 (2) (0) | 2018.05.28 |
---|---|
64bit 멀티코어 OS 제작하기 [4] - 1 : OS 이미지 로딩을 위한 부트로더 기능 추가 (1) (0) | 2018.05.16 |
64bit 멀티코어 OS 제작하기 [3] - 2 : 가장 기초적인 부트 로더 제작 (0) | 2018.05.14 |
64bit 멀티코어 OS 제작하기 [3] - 1 : 부트로더와 makefile (0) | 2018.05.14 |
64bit 멀티코어 OS 제작하기 [2] - 2 : 메모리 관리 기법 (0) | 2018.05.10 |