들어가기
기본 부트로더에서 OS 이미지를 로딩하는 기능을 추가하고 테스트용 OS 이미지를 로드해보자.
본론
- 부트 로더를 사용해 OS 이미지를 로딩하는 방법으로 BIOS 사용하는 방법과 디스크 컨트롤러를 사용하는 방법 존재.
- 이번 정리에서는 BIOS로 가상 OS 이미지를 로딩.
3.1 BIOS 서비스와 소프트웨어 인터럽트
- BIOS는 PC 주변기기를 제어하는 거의 모든 기능을 제공.
BIOS가 제공하는 디스크 서비스는 0x13 인터럽트를 발생 시켜야 함.
- 소프트웨어 인터럽트는 int 0x13 형태로 사용.
- BIOS도 만능은 아니므로 파라미터와 결과 값을 레지스터를 사용해 전달.
- 기본적으로 범용 레지스터와 ES 세그먼트 레지스터를 사용하지만, BIOS 서비스 마다 사용하는 레지스터의 수와 종류가 다르므로 확인을 해야함.
3.2 OS 이미지 로딩 기능 구현
3.2.1 디스크 읽기 기능 구현
- 이번 프로젝트에서는 0x10000에 OS 이미지를 로딩할 예정.
- 플로피 디스크에 첫 번쨰 섹터는 부트 로더로 BIOS가 메모리에 로딩 시킴.
- 즉, 두번째 섹터부터 OS 이미지 크기만큼 읽음.
– 순서는 섹터 -> 헤드 -> 트랙 순.
– 섹터를 다 읽고, 헤드를 1로 바꾸고 다시 같은 섹터를 읽은 뒤, 트랙을 증가 시킴. - 앞서 구현했던 환영 메시지 출력 코드를 함수 형태로 작성해 원하는 곳에서 호출할 예정.
- 이를 위해 스택이 필요.
3.2.2 스택 초기화와 함수 구현
- x86 프로세서에서 함수를 사용하려면 스택이 꼭 필요.
- x86에서는 함수 호출 후 call 호출로 되돌아갈 주소를 스택에 저장한뒤 ret 호출로 되돌아옴.
스택은 함수의 파라미터를 저장하는 역할도 함 -> 호출하는 쪽과 호출되는 쪽은 정해진 규칙에 따라 파라미터를 스택에 저장.
스택 생성을 위해서는 스택 관련 레지스터가 필요.
– 스택 세그먼트 레지스터(SS), 스택 영역을 사용할 세그먼트의 기준 주소를 지정.
– 스택 포인터 레지스터(SP), 데이터를 삽입하고 제거하는 상위를 지정.
– 베이스 포인터 레지스터(BP), 스택의 기준 주소를 임시로 지정할 때 사용.
1 | mov ax, 0x0000 ; 스택 세그먼트의 시작 어드레스를 레지스터 값으로 변환 |
- OS 이미지가 0x10000에 로딩될 예정으로 그 아래 영역을 사용할 예정.
- 메시지 출력 함수는 이전에 봤던 출력 핵심 코드와 상당히 유사.
- but, 함수에서 사용하는 레지스터를 저장하고, 복구하는 코드와 넘겨받은 파라미터를 스택에서 꺼내는 코드를 추가해야 함.
- 화면에서 원하는 위치에 문자열을 출력하려면 x, y 좌표와 문자열의 주소가 필요.
- 스택에 삽입하는 순서는 파라미터를 받는 쪽과 같은 순서로 삽입하면 순서는 상관없지만 C언어의 호출 규약을 따를 예정.
1 | // C 언어 함수 호출 |
1 | push word [ pcString ] |
- 호출된 PRINTMESSAGE는 데이터를 꺼낼 때 C언어 함수 호출 규약과 동일.
- 함수 호출뒤 add sp, 6을 통해 스택에서 데이터를 제거.
- 호출되는 함수는 파라미터가 순서대로 삽입되어 있다는 사실을 알고 있음.
- 즉, 스택의 특정 위치를 기준으로 오프셋을 이용해 접근하며 파라미터를 찾음.
– but, SP는 push, pop에 따라 계속 변해 불편.
– 따라서 고정된 BP를 기준으로 파라미터에 접근.
1 | push bp |
- 호출되는 함수가 작업을 마치고 원래 주소 코드로 복귀할 때 정상적인 수행을 위해서는 함수 호출 전후의 레지스터 상태가 동일해야 함.
– 따라서 호출되는 함수에서는 자신이 사용하는 레지스터의 값을 미리 스택에 저장, 수행이 끝나면 이를 복원.
보호 모드에서 사용되는 세 가지 함수 호출 규약
- stdcall, 파라미터를 스택에 저장하며 호출된 쪽에서 스택을 정리.
- cdecl, 파라미터를 스택에 저장하며 함수를 호출한 쪽에서 스택을 정리.
- fastcall, 일부 파라미터를 레지스터에 저장하지만 stdcall과 유사.
3.3 테스트를 위한 가상 OS 이미지 생성
- 가상 OS 이미지는 세세한 부분까지 구현하지 않고 OS가 제대로 부트 로더로부터 메모리로 복사되는지 확인할 예정.
3.3.1 OS 이미지 통합과 QEMU 실행
- 1024개의 섹터를 돌며 가상 OS를 출력한 결과.
마치며
포기할 뻔 했다. 역시 어셈블리 많이 어렵다..