9. OS를 알고 싶다
• Create가 아니고 Copy and Paste
• 직접 만드는 걸 설명하는 책이 있었다!
• 올해 3월 초 ~ 5월 말까지 진행
• 시간 지나니까 다 까먹음
10. 왜 부팅인가?
• 사실 부팅말고 OS에 대한 전반적인 내용을 발표하려고 했습니다
I. 부팅
II. 인터럽트
III. 프로세스, 스레드, 스케줄링
IV. 동적 메모리 할당
V. 이벤트
VI. 시스템 콜
VII. 로더
11. 왜 부팅인가?
• 근데 부팅만 봤더니 양이…
• 결국 부팅 하나만 하기로 결정
• 절대 귀차니즘 때문이 아닙니다
12. 운영 모드
• 인텔 64비트 호환 프로세서(x86-64 프로세서)에는 크게 5가지 운영모드가 존재
• 여기서는 필수인 3가지만 구현
13. 운영 모드 – 리얼 모드
• 프로세서의 초기 상태로서 16비트 모드로 동작하며 8086 프로세서와 호환되는 모드
• 최대 1MB(220
)의 주소 공간을 지원
• BIOS(Basic Input Output System)의 여러 기능을 사용 가능
14. 운영 모드 – 보호 모드
• 32비트 모드로 동작하며 세그먼트, 페이징, 보호, 멀티태스킹 등의 기능을 제공
• 4GB(232
)의 주소 공간을 지원
• IA-32e 모드로 전환하려면 반드시 거쳐야 함
• 32비트 윈도우나 리눅스가 동작하는 기본 모드
15. 운영 모드 – IA-32e 모드
• 32비트 호환 모드와 64비트 모드의 두 가지 서브 모드로 구성
• 16EB(264
)의 주소 공간을 지원
• 32비트 호환 모드일 때는 보호 모드에 있는 것처럼 동작(32비트 코드를 그대로 실행)
• 64비트 OS에서 32비트 보호 모드 코드를 별다른 처리 없이 그대로 실행할 수 있는 이유
• AMD에서는 Long Mode로 표기
16. 운영 모드 사이의 관계
리얼 모드
(16Bit)
전원
IA-32e 모드
(32 or 64Bit)
보호 모드
(32Bit)
CR0 레지스터의
PE 비트를 1로 설정
CR0 레지스터의
PG 비트를 1로 설정
CR4 레지스터의
PAE 비트를 1로 설정
IA32_EFER MSR 레지스터의
LME 비트를 1로 설정
18. BIOS(Basic Input Output System)
• 메인보드에 포함된 펌웨어의 일종
• 보통 PC 메인보드에 롬(ROM)이나 플래시 메모리로 존재
• 전원이 켜짐과 동시에 프로세서가 가장 먼저 실행하는 코드
• BIOS에서 수행하는 각종 테스트나 초기화를 POST(Power On Self Test)라고 부름
• POST가 완료된 후 앞부분에 부트 로더가 있는지 확인
• 부트 로더가 존재하면 코드를 0x7C00 주소에 복사한 후 프로세서가 0x7C00 주소부터 실행하도록 함
19. BIOS(Basic Input Output System)
• 기능을 특별한 방법으로 외부에 제공
• 함수의 어드레스를 인터럽트 벡터 테이블(Interrupt Vector Table)에 넣어 두고
• 소프트웨어 인터럽트(SWI, Software Interrupt)를 호출하는 방법을 사용
20. 인터럽트 벡터 테이블
• 메모리 어드레스 0에 있는 테이블
• 특정 번호의 인터럽트가 발생했을 때 인터럽트를 처리하는 함수(Interrupt Handler) 검색에 사용
• 테이블의 각 항목은 인덱스에 해당하는 인터럽트가 발생했을 때 처리하는 함수 주소가 저장되어 있음
테이블 인덱스 용도 설명
0x00 CPU Exception Divide by zero
0x01 CPU Exception Single step for debugging
… … …
0x13 BIOS Service Disk I/O service
… … …
21. 플로피 디스크 내부 구조
헤드
• 디스크 표면을 의미
• 플로피 디스크는 디스크가 한 장으로 구성되므로 앞, 뒤로 2개
• 번호는 0 ~ 1
트랙
• 파란색 영역
• 플로피 디스크는 80개
• 번호는 0 ~ 79
섹터
• 빨간색 영역
• 디스크를 구성하는 가장 작은 단위
• 트랙을 다시 여러 조각으로 자른 것
• 한 트랙당 18개
• 하나당 512Bytes로 구성
• 번호는 1 ~ 18
22. 부트 로더
• 부트스트랩(Bootstrap) 코드라고도 불림
• BIOS에서 처음으로 제어를 넘겨받는 부분
• 플로피 디스크나 하드 디스크 등 저장 매체의 가장 앞부분에 존재
• 마지막 2바이트가 0x55, 0xAA로 이루어짐
23. 부트 로더 코드
[ORG 0x00] ; 코드의 시작 어드레스를 0x00으로 설정
[BITS 16] ; 이하의 코드는 16비트 코드로 설정
SECTION .text ; text 섹션(세그먼트)을 정의
jmp 0x07C0:START ; CS 세그먼트 레지스터에 0x07C0을 복사하면서, START 레이블로 이동
0x07C0CS
24. 부트 로더 코드
[ORG 0x00] ; 코드의 시작 어드레스를 0x00으로 설정
[BITS 16] ; 이하의 코드는 16비트 코드로 설정
SECTION .text ; text 섹션(세그먼트)을 정의
jmp 0x07C0:START ; CS 세그먼트 레지스터에 0x07C0을 복사하면서, START 레이블로 이동
START:
mov ax, 0x07C0 0x07C0CS 0x07C0AX
25. 부트 로더 코드
[ORG 0x00] ; 코드의 시작 어드레스를 0x00으로 설정
[BITS 16] ; 이하의 코드는 16비트 코드로 설정
SECTION .text ; text 섹션(세그먼트)을 정의
jmp 0x07C0:START ; CS 세그먼트 레지스터에 0x07C0을 복사하면서, START 레이블로 이동
START:
mov ax, 0x07C0
mov ds, ax
0x07C0CS 0x07C0AX
0x07C0DS
26. 부트 로더 코드
[ORG 0x00] ; 코드의 시작 어드레스를 0x00으로 설정
[BITS 16] ; 이하의 코드는 16비트 코드로 설정
SECTION .text ; text 섹션(세그먼트)을 정의
jmp 0x07C0:START ; CS 세그먼트 레지스터에 0x07C0을 복사하면서, START 레이블로 이동
START:
mov ax, 0x07C0
mov ds, ax
mov ax, 0xB800
0x07C0CS 0xB800AX
0x07C0DS
27. 부트 로더 코드
[ORG 0x00] ; 코드의 시작 어드레스를 0x00으로 설정
[BITS 16] ; 이하의 코드는 16비트 코드로 설정
SECTION .text ; text 섹션(세그먼트)을 정의
jmp 0x07C0:START ; CS 세그먼트 레지스터에 0x07C0을 복사하면서, START 레이블로 이동
START:
mov ax, 0x07C0
mov ds, ax
mov ax, 0xB800
mov es, ax
0x07C0CS 0xB800AX
0x07C0DS
0xB800ES
28. 부트 로더 코드
[ORG 0x00] ; 코드의 시작 어드레스를 0x00으로 설정
[BITS 16] ; 이하의 코드는 16비트 코드로 설정
SECTION .text ; text 섹션(세그먼트)을 정의
jmp 0x07C0:START ; CS 세그먼트 레지스터에 0x07C0을 복사하면서, START 레이블로 이동
START:
mov ax, 0x07C0
mov ds, ax
mov ax, 0xB800
mov es, ax
mov ax, 0x0000
0x07C0CS 0x0000AX
0x07C0DS
0xB800ES
29. 부트 로더 코드
[ORG 0x00] ; 코드의 시작 어드레스를 0x00으로 설정
[BITS 16] ; 이하의 코드는 16비트 코드로 설정
SECTION .text ; text 섹션(세그먼트)을 정의
jmp 0x07C0:START ; CS 세그먼트 레지스터에 0x07C0을 복사하면서, START 레이블로 이동
START:
mov ax, 0x07C0
mov ds, ax
mov ax, 0xB800
mov es, ax
mov ax, 0x0000
mov ss, ax
0x07C0CS 0x0000AX
0x07C0DS
0xB800ES
0x0000SS
30. 부트 로더 코드
[ORG 0x00] ; 코드의 시작 어드레스를 0x00으로 설정
[BITS 16] ; 이하의 코드는 16비트 코드로 설정
SECTION .text ; text 섹션(세그먼트)을 정의
jmp 0x07C0:START ; CS 세그먼트 레지스터에 0x07C0을 복사하면서, START 레이블로 이동
START:
mov ax, 0x07C0
mov ds, ax
mov ax, 0xB800
mov es, ax
mov ax, 0x0000
mov ss, ax
mov sp, 0xFFFE
0x07C0CS 0x0000AX
0x07C0DS
0xB800ES
0x0000SS
0xFFFESP
31. 부트 로더 코드
[ORG 0x00] ; 코드의 시작 어드레스를 0x00으로 설정
[BITS 16] ; 이하의 코드는 16비트 코드로 설정
SECTION .text ; text 섹션(세그먼트)을 정의
jmp 0x07C0:START ; CS 세그먼트 레지스터에 0x07C0을 복사하면서, START 레이블로 이동
START:
mov ax, 0x07C0
mov ds, ax
mov ax, 0xB800
mov es, ax
mov ax, 0x0000
mov ss, ax
mov sp, 0xFFFE
mov bp, 0xFFFE
0x07C0CS 0x0000AX
0x07C0DS
0xB800ES
0x0000SS
0xFFFESP
0xFFFEBP
33. 이후 코드 전개
① 화면을 지움
② 화면 상단에 부트 로더 시작 메시지 출력
③ OS 이미지를 로딩한다는 메시지 출력
④ int 0x13 코드를 이용해 BIOS가 디스크를 읽어서 코드를 메모리 주소 0x10000 부터 올림
⑤ 읽기가 끝나면 완료 메시지 출력
⑥ 0x10000 으로 점프
43. 보호 모드 코드
[ORG 0x00] ; 코드의 시작 어드레스를 0x00으로 설정
[BITS 16] ; 이하의 코드는 16비트 코드로 설정
SECTION .text ; text 섹션(세그먼트)을 정의
START:
mov ax, 0x1000 ; ax 레지스터에 0x1000 저장
mov ds, ax ; DS 세그먼트 레지스터 설정
mov es, ax ; ES 세그먼트 레지스터 설정
cli ; 인터럽트가 발생하지 못하도록 설정
lgdt [ GDTR ] ; GDTR 자료구조를 프로세서에 설정하여 GDT 테이블을 로드
mov eax, 0x4000003B ; PG=0, CD=1, NW=0, AM=0, WP=0, NE=1, ET=1, TS=1, EM=0, MP=1, PE=1
mov cr0, eax ; CR0 컨트롤 레지스터에 위에서 저장한 플래그를 설정하여 보호 모드로 전환
jmp dword 0x08: ( PROTECTEDMODE - $$ + 0x10000 ) ; 코드 세그먼트를 교체하고 EIP의 값을 재설정
PROTECTEDMODE:
…
44. 보호 모드 코드
[ORG 0x00] ; 코드의 시작 어드레스를 0x00으로 설정
[BITS 16] ; 이하의 코드는 16비트 코드로 설정
SECTION .text ; text 섹션(세그먼트)을 정의
START:
mov ax, 0x1000
mov ds, ax
mov es, ax
cli
lgdt [ GDTR ]
mov eax, 0x4000003B
mov cr0, eax
jmp dword 0x08: ( PROTECTEDMODE - $$ + 0x10000 )
PROTECTEDMODE:
…
GDT - $$ + 0x10000GDTR
0x08CS
GDTEND - GDT - 1
Base address Limit
Descriptor Index
0x1000DS
0x1000ES
45. 보호 모드 코드
[BITS 32] ; 이하의 코드는 32비트 코드로 설정
PROTECTEDMODE:
mov ax, 0x10 ; 보호 모드 커널용 데이터 세그먼트 디스크립터를 AX 레지스터에 저장
mov ds, ax ; DS 세그먼트 셀렉터에 설정
mov es, ax ; ES 세그먼트 셀렉터에 설정
mov fs, ax ; FS 세그먼트 셀렉터에 설정
mov gs, ax ; GS 세그먼트 셀렉터에 설정
; 스택을 0x00000000~0x0000FFFF 영역에 64KB 크기로 생성
mov ss, ax ; SS 세그먼트 셀렉터에 설정
mov esp, 0xFFFE ; ESP 레지스터의 어드레스를 0xFFFE로 설정
mov ebp, 0xFFFE ; EBP 레지스터의 어드레스를 0xFFFE로 설정
; 화면에 보호 모드로 전환되었다는 메시지를 찍는다.
jmp dword 0x08: 0x10200 ; C 언어 커널이 존재하는 0x10200 어드레스로 이동하여 C 언어 커널 수행
46. 보호 모드 코드
[BITS 32] ; 이하의 코드는 32비트 코드로 설정
PROTECTEDMODE:
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
; 스택을 0x00000000~0x0000FFFF 영역에 64KB 크기로 생성
mov ss, ax
mov esp, 0xFFFE
mov ebp, 0xFFFE
; 화면에 보호 모드로 전환되었다는 메시지를 찍는다.
jmp dword 0x08: 0x10200
0x10DS
0x10ES
0x10FS
0x10GS
0x10SS
0xFFFEESP
0xFFFEEBP
48. C 언어 코드 생성 조건
• C 라이브러리를 사용하지 않게 빌드해야 함
• 0x10200 위치에서 실행하게끔 빌드해야 함
• 코드나 데이터 외에 기타 정보를 포함하지 않은 순수한 바이너리 파일 형태여야 함
• 위의 3가지 조건은 GCC 옵션과 링커 스크립트, 기타 유틸리티 프로그램으로 해결
• 설명하기 복잡하고 이해도 잘 안돼서 패스
49. 보호모드 커널 C언어 코드
#include "Types.h"
void kPrintString( int iX, int iY, const char* pcString );
void Main( void )
{
kPrintString( 0, 3, "C Language Kernel Started~!!!" );
while( 1 ) ;
}
54. A20 게이트
• XT PC가 주로 사용되던 시절에는 오버플로우를 이용한 프로그램이 있었음
• Ex) 0xFFFF:FFFF -> 0x10FFEF -> 0xFFEF
• 16MB 어드레스까지 접근할 수 있는 AT PC가 탄생하면서 문제가 생김
• 이러한 호환성의 문제를 해결하려고 도입된 것이 A20 게이트
• 비활성화하면 20번째 비트를 항상 0으로 고정
68. PIC(Programmable Interrupt Controller)
• 인터럽트 처리에 관련된 세부 기능을 프로그래밍 할 수 있는 컨트롤러
• PC 디바이스(키보드, 마우스, HDD 등)의 인터럽트를 관리
• 1개당 인터럽트 입력 8개 처리 가능
• 2개를 마스터-슬레이브 방식으로 연결하여 최대 15개 인터럽트 처리