sonumb

How to Compile your own OS Kernel in the Visual Studio 2005 Environment 본문

개발자 이야기/OS_Development

How to Compile your own OS Kernel in the Visual Studio 2005 Environment

sonumb 2008. 2. 18. 18:05

작성자 : sonumb http://sonumb.tistory.com

E-mail:

작성일 : 2008년 2월 17일

Licence :
Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.

Contents

0.서론
1. OS kernel – TOS(tesTOS)
2. 준비사항
    2.1 컴파일러 환경
    2.2 커널실행 환경
3. 소스파일
4. 빌드
    4.1 빌드 전 세팅
5. 테스트
6. 결론
7. 관련 링크 & 참고

0. 서론

이글의 목적은 OS개발이 아니라, OS 개발을 위한 환경을 Visaul Studio 2005 (이하 VS2005 )으로 정했을 때 IDE 설정을 어떻게 해야하는 가입니다. 설정 항목에 대한 각각의 의미는 설명 드리지 않겠습니다. 각자 컴파일러를 자체를 공부해보세요.

유의점 1. VS2005를 OS개발 툴로 정할 시 몇가지 유의점이 있는데 그 중 하나가 바로 PE헤더 정보입니다. 그외에는 아직 발견하지 못했네요. ( 작성일 기준 )
유의점 2. 아래 내용중에 보시면 경로와 프로젝트 이름에 따른 의존적인 부분들이 있습니다. 그래서 컴파일시 에러 없는 완벽한 빌드를 원할 시 프로젝트명과 경로를 준수해주길 바랍니다.
 

1. OS kernel – TestOS

OS 설명 : MBR과 로드 될 커널 프로그램의 집합입니다..

아키텍쳐 : MBR은 플로피에서 하나의 섹터(512Bytes)가 자동으로 읽혀서 물리 메모리 0x7C00으로 올라갑니다. 0x10000번지에 우리가 C코드로 작성한 프로그램이 올라갈 겁니다. 물론 MBR내의 프로그램 즉, 부트로더가 올려야겠지요.

우리가 작성한 C로 작성한 프로그램은 컴파일 및 링크 과정을 거칠 때, PE헤더정보가 0x200바이트 정도 붙여집니다. 따라서 실질 적인 엔트리 포인트는 0x10200이 되겠군요. 그러면 부트로더가 자기 일을 끝마치면 0x10000으로 점프를 해야 하는 것이 아니라 0x10200으로 점프를 해야 됩니다.

2. 준비 사항.

2.1 VS 2005 컴파일러 환경 설정.

  1. 일단 프로젝트를 생성합니다.
    ctrl+shift+N 을 누릅니다. Visual C++ -> Win32 Console 선택, 프로젝트명은 "test_os" 합니다.
    [각주:1]그리고 Win32 Application Wizard 다이얼로그창이 뜨면 Applicaion Settings에서
    1. Application Types: Console application
    2. Additional Option : Empty project

      를 선택합니다.
  2. 프로젝트 설정(메뉴 Project -> (Project명) properties..) 에 관한 부분을 나열해 놓겠습니다. 빌드는 항상 Release 모드로 합니다. 그래서 Release 모드의 설정을 세팅 합니다.

- General


- Compiler
0123456789


- Linker

012345678

2.2 커널실행 환경

여러 가지 환경이 있습니다만 두 가지 환경을 쓰는 게 좋을 듯합니다.

1) Microsoft Virtual PC 2007
2) VMware Player

둘 다 장단점이 있습니다. 1)인 경우 MS제품이라 그런지 최적화가 되어 있어 실행속도가 빠릅니다. 하지만 보통 kernel을 만들 때 확장자가 img인 파일로 만들어서 부팅을 해야 하는데 이 파일의 크기를 체크를 합니다. 즉, img 파일이 1.44MB가 아닌 경우 에러가 납니다. 2)인 경우에는 느리지만 img파일의 크기에 상관없이 인식을 하네요. 자세한 것은 `5. 실행`에서 설명 드리겠습니다.

3. 소스파일

최소한의 커널을 지향해서 일단은 2개의 파일이 필요합니다.하나는 부팅 및 커널 로더의 기능을 하는 프로그램, 다른 하나는 커널 자체입니다.

Boot.asm : 부팅 및 커널 로더, GDT, A20 설정.

   1: [BITS 16]       ; We need 16-bit intructions for Real mode
   2:  
   3: [ORG 0x7C00]    ; The BIOS loads the boot sector into memory location 0x7C00
   4:  
   5: reset_drive:
   6:     mov ah, 0               ; RESET-command
   7:     int 13h                 ; Call interrupt 13h
   8:     or ah, ah               ; Check for error code
   9:     jnz reset_drive         ; Try again if ah != 0
  10:  
  11:     ;vc에서 /base 10000 로 헀기 때문에 여기서부터 메모리를 로드
  12:     ; 해야 한다. ES:BX 로 1000:0000h 이기 때문에 아래처럼 한다.
  13:     mov ax, 1000h           ; es:bx <-- 1000:0000h 
  14:     mov es, ax
  15:     mov bx, 0h          ; Destination address = 0000:1000
  16:  
  17:     mov ah, 02h             ; READ SECTOR-command
  18:     ; 두번째 섹터부터 3칸섹터가 커널이미지 섹터다.
  19:     mov al, 3h             ; Number of sectors to read = 1
  20:     mov ch, 0               ; Cylinder = 0
  21:     ; 현재 첫번째섹터512 이며 두번째 섹터부터 3개 섹터가 커널이미지다
  22:     mov cl, 02h             ; Sector = 2
  23:     mov dh, 0               ; Head = 0
  24:     int 13h                 ; Call interrupt 13h
  25:     or ah, ah               ; Check for error code
  26:     jnz reset_drive         ; Try again if ah != 0
  27:  
  28: A20Address:
  29:     ; Set A20 Address line here
  30:  
  31:     CLI
  32:     CALL enableA20
  33:     STI
  34:     JMP Continue
  35: enableA20:
  36:     call enableA20o1
  37:     jnz short enableA20done
  38:     mov al,0d1h
  39:     out 64h,al
  40:     call enableA20o1
  41:     jnz short enableA20done
  42:     mov al,0dfh
  43:     out 60h,al
  44:     enableA20o1:
  45:     mov ecx,20000h
  46: enableA20o1l:
  47:     jmp short $+2
  48:     in al,64h
  49:     test al,2
  50:     loopnz enableA20o1l
  51: enableA20done:
  52:     ret
  53:     
  54: Continue:    
  55:     cli                     ; Disable interrupts, we want to be alone
  56:  
  57:     xor ax, ax
  58:     mov ds, ax              ; Set DS-register to 0 - used by lgdt
  59:  
  60:     lgdt [gdt_desc]         ; Load the GDT descriptor
  61:  
  62:     mov eax, cr0            ; Copy the contents of CR0 into EAX
  63:     or eax, 1               ; Set bit 0
  64:     mov cr0, eax            ; Copy the contents of EAX into CR0
  65:  
  66:     jmp 08h:clear_pipe      ; Jump to code segment, offset clear_pipe
  67:  
  68: [BITS 32]                       ; We now need 32-bit instructions
  69:     clear_pipe:
  70:     mov ax, 10h             ; Save data segment identifyer
  71:     mov ds, ax              ; Move a valid data segment into the data segment register
  72:     mov ss, ax              ; Move a valid data segment into the stack segment register
  73:     mov esp, 090000h        ; Move the stack pointer to 090000h
  74:  
  75:     ; 10200h로 점프 200h는 vc로 링킹하면 기본 PE헤더(200h)를 붙여서 더했다.
  76:     ; 10200h 즉 1000:0200h 로 점프
  77:     ;jmp 1000:0200h
  78:     jmp 10200h
  79:  
  80:  
  81: gdt:                    ; Address for the GDT
  82:  
  83: gdt_null:               ; Null Segment
  84:     dd 0
  85:     dd 0
  86:  
  87: gdt_code:               ; Code segment, read/execute, nonconforming
  88:     dw 0FFFFh
  89:     dw 0
  90:     db 0
  91:     db 10011010b
  92:     db 11001111b
  93:     db 0
  94:  
  95: gdt_data:               ; Data segment, read/write, expand down
  96:     dw 0FFFFh
  97:     dw 0
  98:     db 0
  99:     db 10010010b
 100:     db 11001111b
 101:     db 0
 102:  
 103: gdt_end:                ; Used to calculate the size of the GDT
 104:  
 105: gdt_desc:                       ; The GDT descriptor
 106:     dw gdt_end - gdt - 1    ; Limit (size)
 107:     dd gdt                  ; Address of the GDT
 108:  
 109: times 510-($-$$) db 0           ; Fill up the file with zeros
 110:  
 111:     dw 0AA55h                ; Boot sector identifyer

 

A20은 1M바이트 이상의 메모리랑 관련 있고, GDT는 세그멘트 기법과 관련 있습니다. 각자 찾아 보세요.

 

Kernel_main.c : 커널 자체

   1: void kernel_main( void ) 
   2: { 
   3:    char* hello = "Hello OS!"; 
   4:    unsigned char* vidmem = (unsigned char*)0xB8000; 
   5:       // 비디오메모리는 물리메모리 0xB8000에 매핑되어있다.
   6:  
   7:    while( *hello != '\0' )        
   8:    { 
   9:       *vidmem++ = *hello++; 
  10:       *vidmem++ = 7;        // 문자 기본 속성 
  11:    } 
  12:  
  13:     // 커널이 끝나면 안된다. 계속 돌아야한다. 
  14:    for(;;); 
  15: } 
  16:  

4. 빌드

4.1 빌드 전 세팅

1) Nasm 세팅

NASM을 다운 받아서 압축을 푼다.그 다음 , 예를 들어 c:\nasm에 압축을 풀었다면, 윈도우즈 환경설정의 Path에 “c:\nasm;”을 추가해준다.

2) 빌드에 관한 세팅.

일단 어셈블리 파일에 대한 커스텀 빌드를 세팅하자

그리고 Build 후 작업을 통해 부팅프로그램과 컴파일한 커널을 머징해준다.


빌드
Ctrl+Shift+B 키를 누르거나 메뉴 'Build->Build Solution'을 클릭하면, 빌드 후 작업(Post-Build Event)에 설정해준 *.img 파일이 생성됩니다.

5.테스트

"D:\program files\Microsoft Virtual PC\Virtual PC.exe" -pc OS_KERNEL -launch
라고 하면 뜹니다.

6.결론

Update

7.관련링크 & 참고

Update
  1. 프로젝트 명에 따라 설정이 어떻게 바뀌는지 잘 아신다면 다른 걸로 하셔도 무방합니다. [본문으로]
반응형