BLOG main image
LoofBackER's Blog
Jun - Sik , Yang Blog


뭐?  
어렵게만 여겨지던 운영체제의 베일이 벗겨지고 있습니다. 이것도 유행일까요?
소프트웨어 개발자라면 알고 싶어지고, 구현해 보고픈 운영체제. 그속을 들여다보고
연구하며 스스로 제작해 보는 사이트들이 계속 늘고 있습니다. 저역시 그 만들기의
시작을 조심스럽게 열어 보려 합니다. 여기-저기, 이곳-저곳, 앞-뒤-옆집에서 짬짬히
얻은 정보들을 토대로(어쩌면 짜집기(^^)로 보일 수도 있지만) 한몫 해보고픈 마음에 글을 써 봅니다.

아래의 내용들은 제가 직접 작성한 부트섹터 코드의 간단한 설명과 컴파일 방법
그리고 x86 Protected Mode로 포팅된 μC/OS-II소스를 가지고 빌드하는 설명을 가지고 있습니다.

이 강좌는 절대로 기술적인 내용이 없습니다. 어셈코드의 지식과 부트섹터, 커널에
관한 어느정도의 지식을 갖추었다는 가정하에 내용을 진행하게 됩니다.
단지 예제로 제시한 코드를 컴파일 하고, 실제 운영체제처럼 동작하는 모습을 보여줌 으로써
Visual C++환경하에서도 운영체제 개발 작업을 할 수 있다는 것을 보이기 위함입니다.
만약, 그러한 것들의 개념이 필요하다면 먼저 위의 메뉴에서 PROJECT -> OS PAGE에 링크된
여러 자료를 참고 하시기 바랍니다. 물론 예전에 Bellona라는 운영체제를 만드신
 오재준님의 강좌와 서적이 이와 유사합니다만, 그 내용에는 VC 5.0의 환경과 조금은
복잡한 부트섹터에 의해 커널이 로드됩니다. 나름대로의 이유가 있겠습니다만, 그와는 상관없이
이 강좌는 순수하게 VC 6.0의 환경에서 커널제작이 가능함을 보이기 위한 내용임을 다시 한번 주지시켜 드립니다.
 


준비물  
 


 - 환경
	Microsoft Windows® 98, 2000, XP에서 테스트 되었습니다. 

 - Tool
	Borland-C++® 3.0(2.0도 됩니다^^) [Turbo-C® 2.0 download]
	Microsoft Visual C++® 6.0
	Microsoft Macro Assembler® 6.11 (다른 버전은 안됩니다.)
	NASM 0.98.36 (다른버전도 괜찮을지(?) 모릅니다.^^) [NASM site link]

 - Source
μC/OS-II(Port : x86 Protected Mode) [UCOS-ii(intel port) Site link]
LestatOS(TM) Boot Sector [bootsect.asm download]
: 장진호(devilnis@nownuri.net)님께서 고맙게도 버그를 하나 지적해 주셨습니다. 
Boot Sector를 디스켙의 젤 첫섹터에 옮겨주는 C 소스 [scopy.c download] 윈도우 환경에서 부트 섹터 정보를 읽고 써주는 유틸리티 [GSector.exe download]


구성  

우리가 빌드해볼 전체 목록 구성은 대충 이렇습니다.

- μC/OS-II 커널 이미지
- 커널 이미지를 로드할 부트섹터

위의 준비물들은 모두 예제로 다뤄볼 위에서 나열한 운영체제와 부트섹터를 빌드하기
위함입니다.
μC/OS-II 커널 이미지를 빌드하는 방법은 UCOS-II 웹 사이트의
http://www.ucos-ii.com/intel/index.html 페이지를 참고하시면 됩니다. 거기엔
Jean Louis Gareau가 제작한 부트섹터와 커널이미지 그리고 커널이미지 로더 소스와
태스크 소스가 있습니다. 이를 참고로 하는 이유는 장점이 커널제작 작업을 Visual C환경에서 할 수 있다는 것입니다.
	

μC/OS-II
에 관해 좀 더 알고 싶으시다면, http://www.ucos-ii.com사이트를 참조하시기
바랍니다. 아주 소형인 리얼타임 커널이면서도 탁원한 스케쥴링 알고리즘과 여러 시스템에
 유연하게 포팅된 운영체제입니다.


 ::TOP


구현  
 

자, 그럼 시작합니다!
제가 제작한 부트섹터는 NYAOS부트섹터를 참고했습니다.
부트섹터 설명 : bootsect.asm

부트 섹터는 BIOS에 의해 (물리주소)0x7C00번지에 로드 됩니다. 512 BYTE의 크기를
가져야 하며, 파일의 끝은 0x55,0xaa캐릭터가 포함됩니다. 그리고 디스크의 젤 첫번째
섹터에 위치시키면 되는데요, 이왕이면 파일시스템정보를 포함함으로써 윈도우/리눅스나
도스등에서 접근할 수 있는 편리함을 이용해도 되겠죠. 무슨 말이냐 하면, 커널 이미지를
나중에 완성해 보시면 아시겠지만, 이미지를 특정 섹터에 위치 시켜 두고 부트로더가
로드하는 방식은 소스가 간단할 수도 있지만, 업데이트 된 커널을 매번 그렇게 위치시키느니
차라리 적당한 파일이름으로 복사만 시켜 주더라도 부트섹터가 알아서 커널을 로드한다면
많이 편하다는 것을 느끼실 겁니다. 그렇기에 부트섹터의 소스 첫부분은 파일시스템 정보를
채웁니다.
1 fatOEM       db "LestatOS"               ; OEM  
2 fatSectSize  dw 0x200                    ; Bytes per sector = 512  
3 fatClustSize db 1                        ; Sectors per cluster  
4 fatRessect   dw 1                        ; # of reserved sectors  
5 fatFatCnt    db 2                        ; # of fat copies  
6 fatRootSize  dw 224                      ; size of root directory  
7 fatTotalSect dw 2880                     ; total # of sectors if < 32 meg  
8 fatMedia     db 0xF0                     ; Media Descriptor  
9 fatFatSize   dw 9                        ; Size of each FAT  
10 fatTrackSect dw 18                       ; Sectors per track  
11 fatHeadCnt   dw 2                        ; number of read-write heads  
12 fatHidenSect dd 0                        ; number of hidden sectors  
13 fatHugeSect  dd 0                        ; if fatTotalSect is 0 this value is  
14                                         ; the number of sectors  
15 fatBootDrv   db 0                        ; holds drive that the fat came from  
16 fatReserv    db 0                        ; not used for anything  
17 fatBootSign  db 29h                      ; boot signature 29h  
18 fatVolID     dd 0                ; Disk volume ID also used for temp  
19                                         ; sector # / # sectors to load  
20 fatVoLabel   db "LestatOS",13,10,0       ; Volume Label  
21 fatFSType    db "FAT12   "               ; File System type  
view plain | print | copy to clipboard | ?

 물론 부트섹터가 하는 젤처음 동작은 점프입니다. 확장자가 COM인 파일의 포멧과 비슷합니다. 점프를 끝내고 인터럽트를 디스에이블 시킨 후 현재 부트된 드라이브의 정보를 얻어 옵니다. 즉, 바이오스는 DL레지스터에 현재 부트된 드라이브의 정보를 담아 둡니다. dl0x00이 들어있으면 A드라이브, 0x80이면 C드라이브 입니다.
1 mov ax,0x9000                ; put stack at 0x91000  
2 mov ss,ax  
3 mov sp,0x1000  
view plain | print | copy to clipboard | ?

 그런다음 위처럼 스텍공간을 잡아 줍니다. 넉넉히 메모리의 저 위쪽으로 말이죠^^
이후, 플로피 컨트롤러를 초기화 하고, 에러면 에러 메세지를 출력하면서 리붓을
한다거나 하는 루틴은 먼저 말씀드린 NYAOS의 부트섹터 소스 설명을 참고 하시구요(^^).
본인이 수정/삽입한 중요 부분들의 설명을 이어 나가겠습니다.^^
1 MOV AX,0x8000           ;80000번지로 이동...  
2 MOV ES,AX                                
3 XOR DI,DI                                
4 MOV AX,0x07C0                              
5 MOV DS,AX                                
6 XOR SI,SI                                
7 MOV CX,0x0100                              
8 REPZ                                         
9 MOVSW                
10              
11 JMP 0x8000:go       ;0x8000:go 의 위치로 점프              
12              
13   go:   mov ax,0x8000  
14 mov ds,ax    
view plain | print | copy to clipboard | ?

 위의 코드는 현재 메모리의 0x07c0:0x0000의 위치에 있는 부트섹터 코드를 물리주소0x80000번지로 이동시킵니다. 이동이 끝난후 당연히 수행된 코드의 다음으로 점프를 해야겠죠? 그렇기에 JMP 0x8000:go 명령을 내립니다. 그리고 DS레지스터를 이동된 세그먼트 위치 0x8000으로 세트 합니다.
	
이후, 루트 디렉토리부터 파일이름으로 지정된 커널이미지를 검색하고, 찾으면
물리주소0x40000번지에 이미지를 로드 합니다. 커널이미지 까지 로드된 메모리의
모습은 아래와 같습니다.
	
그런 다음 플로피 디스크 드라이브의 모터를 아래의 코드와 같이 끄고,
1 mov al, 0x0c  
2 mov dx, 0x03fe  
3 out dx, al  
view plain | print | copy to clipboard | ?

최총적으로 커널 이미지를 다시 최하위 0x0000:0000번지로 이동 시킨 후, 물리주소
0x01000번지로 점프 합니다. 0x1000번지부터 커널이미지의 실제 코드가 시작되기
때문입니다. (컴파일 된 커널이미지를 덤프해 보시면 압니다.^^)
1 cli  
2              
3 MOV AX,0x0000           ;40000번지에서 0x0000:0000으로 이동...  
4 MOV ES,AX                                
5 XOR DI,DI                                
6 MOV AX,0x4000                              
7 MOV DS,AX                                
8 XOR SI,SI                                
9 MOV CX,0x7000                              
10 REPZ                                         
11 MOVSW                      
12              
13 mov ax,0x0000               ; set segment registers and jump  
14 mov es,ax  
15 mov ds,ax  
16 jmp 0x0000:0x1000  
view plain | print | copy to clipboard | ?

 아래의 그림은 부트섹터와 커널이미지가 로드된 후 전체적인 호출 순서를 보여 줍니다.
제일 먼저 부트섹터는 Entry.asm에 의해 컴파일 된 Entry.obj로 점프하게 되며
Entry.obj는 커널의 main함수를 호출하게 됩니다.
Entry.asm이 하는 일은 CPU를 보호모드로 변환함과 동시에 GDT,IDT를 세팅하는
역할을 합니다. 그작업이 끝나면 곧바로 커널의 main함수를 호출합니다.
	



실전! (Build)

네^^; 이제부터 실제로 부트섹터와 운영체제를 빌드해 봅시다. 먼저, 부트섹터를 컴파일
하는 방법은 아래와 같습니다. nasm이 당연히 설치되어 있어야 겠죠?
: (bootsect.asm 컴파일 방법)
	
부트섹터를 디스켙의 첫번째 섹터에 옮기는 방법은 몇가지가 있습니다. 예를 들면 도스의
디버거에서 아래와 같이 하셔도 상관없습니다.
: (bootsect를 디스켙의 첫번째 섹터에 옮기는 방법)
	
그렇지만, 좀더 멋지게- 우리만의 운영체제 인스톨러를 만들고 싶다면, 부트섹터를 복사
해주는 코드를 가지고 있어도 나쁘진 않겠죠? scopy.c의 코드는 아래와 같이 간단합니다.
1 //***************START************************  
2 #include "bios.h"  
3 #include "stdio.h"  
4  
5 void main()   
6 {   
7           FILE *in;   
8            unsigned char buffer[520]; /* 버퍼를 잡고 */  
9  
10         if((in = fopen("bootsect", "rb"))==NULL) /* bootsect 파일을 바이너리로 연다음 */ 
11         {   
12                 printf("Error loading file\n");   
13                 exit(0);   
14            }   
15  
16         fread(&buffer, 512, 1, in); /* 512바이트를 읽고 */ 
17  
18            while(biosdisk(3, 0, 0, 0, 1, 1, buffer)); /* 디스크의 첫섹터에 씁니다 */ 
19  
20         fclose(in);   
21 }   
22 //***************E N D************************  
view plain | print | copy to clipboard | ?
아래의 방법으로 scopy.c를 컴파일 합니다.
: (scopy.c 컴파일 방법)

컴파일된 scopy.exe와 같은 디렉토리에 컴파일된 bootsect파일이 있으면 단지,
scopy.exe를 실행하는 것만으로 디스켙의 첫번째 섹터에 bootsect가 옮겨집니다.

그리고, Entry.asm을 컴파일 해야겠죠? nmake가 세팅되어 있다면, Entry.asm디렉토리에서 아래그림과 같이 nmake만 실행하면 됩니다.
: (Entry.asm 컴파일 방법)

만약, 그렇지 않다면, 아래 그림처럼 ml.exe 파일을 Entry디렉토리에 복사한 후 옵션과
함께 ml.exe를 실행합니다.
: (Entry.asm 컴파일 방법)

ml.exePath되어 있다면, Visual C에서 MyTask.dsw 프로젝트는 제대로
컴파일이 되어 MyTask.IMG 파일을 생성할 겁니다. 만약 그렇지 않다면, ml.exe
MyTask디렉토리에 복사한 후에 F7키를 눌러 빌드하세요.
(물론! 프로젝트 리소스 탶에서 os_cpu_a.asm를 선택하고 Project -> Setting에서
컴파일러 패스를 수정하셔도 됩니다.)


자, 이제 빌드는 모두 끝났습니다. 부트섹터까지 디스켙에 옮겼다면, MyTask.IMG파일만
디스켙에 복사해 주면 됩니다. 만약, MyTask.Img라는 커널이미지 이름이 마음에
안든다면 bootsect.asm의 소스코드의 젤 아랫줄 근처를 보시면 'MyTask__IMG'라는
데이터가 보일겁니다. 이부분을 12칸에 맞춰서 바꿔 주시면 됩니다. 즉, 커널이미지를
1.IMG라는 파일로 명명하고 싶다면, '1_______IMG'로 바꾸시면 됩니다.
(여기서 '_'는 공백입니다.)
1 FileName    db "MYTASK  IMG" 
view plain | print | copy to clipboard | ?

 이젠, 모든 것이 준비된 디스켙을 가지고 부팅만 하시면 됩니다. 자주 수정하고, 부팅하고 또
에러를 확인한 후 다시 부팅하는 과정이 너무 버겁습니다. 그럴땐 VMware®Bochs등을
사용하시면 편할 겁니다.
(저의 경우엔 Bochs보단 VMware®가 좀더 잘 동작하는 것 같았습니다.)
 

 


이제 몰하나?

^^; 이제 몰 하다니요. 이젠 자신만의 커널 알고리즘을 개발하여 운영체제를 만드셔야죠.
(ㅋ...) 즉, ucos-ii.obj파일을 제거하고 기타 Task관련 소스들을 제거하거나 수정해서
자신만의 운영체제를 만드는 겁니다. 물론, 기존 커널을 그대로 이용하셔도 상관없습니다.
자신만의 UI를 개발하여 포팅하고, 좀 더 나아가서 파일 시스템, 네트웍 그리고
사운드 관련 드라이버도 작성해 보는 등 갈길이 멀답니다.
이글로 인해 그 모든 절차나 길을 조금이라도 보았으면 하는 바람입니다.
건투를 빕니다!

2003.09.02 이건우

 ::TOP



기타 질문&답변 : [ PROJECT -> 질문&답변 게시판 ] 참고 자료 : - 디스크 부팅 이미지 만들기 가이드 - PC 보호모드로 포팅된 uCOS-II 에 인터럽트 추가 예제 참고 사이트 : - 오재준님이 작성하신 Bellona 운영체제 사이트입니다. http://www.bellona2.com/ - 기타 관련사이트는 PROJECT -> OS PAGE에 연결된 링크를 참조하시기 바랍니다.

출처 :
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
TAG
1 ··· 44 45 46 47 48 49 50 51 52 ··· 107 

카테고리

분류 전체보기 (107)
::::::Dairy::::: (5)
:::::what?::::: (1)
:::::Computer::::: (5)
:::::Idea::::: (2)
:::::Want::::: (1)

달력

«   2017/06   »
        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  

티스토리 툴바