본문 바로가기

Computer Engineering/Operating System

[OS 만들기] #01

Restart

From Evernote:

[Restart_OS#1] 0319

Clipped from: http://happydal.blogspot.com/2010/07/%EB%A0%88%EC%A7%80%EC%8A%A4%ED%84%B0.html
처음해야 할 일

컴퓨터에 전원이 들어온 후 무슨일을 해야하는가를 알려주는 것 => Bootstrap

컴퓨터에 전원 -> CPU는 BIOS 롬에 새겨진 프로그램을 실행 -> 현재 사용하는 마더보드의 상태를 체크하고 어떤 주변 장치가 접속되어있는지 등등을 체크 -> 현재 유저가 부팅에 사용할 것이라고 정해놓은 디스크의 첫 512바이트(MBR)에 있는 프로그램을 램으로 읽어들여 실행 (BIOS의 프로그램이 마지막으로 하는 일 )

512바이트에 있는 프로그램 = 작성할 프로그램

= 모르는 용어 확인 =

* CS (Code Segment)

; 함수나 제어문 같은 명령어들이 저장되는 코드 세그먼트의 세그먼트 셀렉터를 포함하고 있으며 이를 참조하여 EIP를 이용해 명령어의 주소를 계산한다.

 

 ex> CS가 0x1b일 경우 2진값은 0b0000 0000 0001 1011 이 된다. (위 그림 참조) TI는 0이므로 Global 디스크립터, RPL은 3(11)이므로 유저모드, 인덱스 00...011이므로 3번째 인덱스임을 알수 있다. 디스크립터 테이블의 3번째 인덱스를 살펴보면 해당 세그먼트의 자세한 정보를 알 수 있는데 이 정보는 WinDBG와 같은 커널 디버거 프로그램을 이용하면 된다. 

 

* DS (Data Segment)

 ; 주로 전역, 정적 변수 데이터가 들어있는 데이터 세그먼트의 데이터 위치를 가르키는 레지스터로 CS레지스터와 같은 방법으로 정보를 얻을 수 있다. 이 정보를 통해 얻을 수 있는 주소 범위 내에서 명령어 내부의 오프셋을 더해 찾고자하는 데이터의 위치를 구할 수 있다.

 

* SS (Stack Segment)

 ; 주소와  데이터를 일시적으로 저장할 목적으로 쓰이는 스택의 주소를 지정하는데 쓰인다.

 

* ES (Extra Segment)

 ; 추가 레지스터로 주로 문자 데이터의 주소를 지정하는데 사용된다.

* DI (Destination Index, 쓰기 인덱스)
* EDI(Extended Destination Index)
; 복사 작업시 Destination의 주소가 저장된다. 주로 ESI 레지스터가 가리키는 주소의 데이터가 복사된다.

boot.txt
[org 0]                             ;메모리의 몇 번지에서 실행해야 하는지 컴파일러에게 알려주는 선언문
[bits 16]
    jmp 0x07C0:start                ;far jmp를 한다.
   
start:
    mov ax,cs                       ;cs에는 0x07c0이 들어있다.
    mov ds,ax                       ;ds를 cs와 같게 해준다.

    mov ax,0xB800                   ;비디오 메모리의 세그먼트를
    mov es,ax                       ;es 레지스터에 넣는다.
    mov di, 0                       ;제일 윗줄의 처음에 쓸것이다.
    mov ax,word[msgBack]            ;써야 할 데이터의 주소 값을 지정한다.
    mov cx,0x7FF                    ;화면 전체에 쓰기 위해서는
                                    ;0x7FF(2047)개의 WORD가 필요하다.
                                   
paint:
    mov word[es:di],ax              ;비디오 메모리에 쓴다.
    add di,2                        ;한 WORD를 썼으므로 2를 더한다.
    dec cx                          ;한 WORD를 썼으므로 CX의 값을 하나 줄인다.
    jnz paint                       ;CX가 0이 아니면 paint로 점프하여 나머지를 더 쓴다.
   
    mov edi,0                       ;제일 윗줄의 처음에 쓸것이다.
    mov byte [es:edi], 'J'          ;비디오 메모리에 쓴다.
    inc edi                         ;한 개의 BYTE를 썼으므로 1을 더한다.
    mov byte [es:edi],0x06          ;배경색을 쓴다.
    inc edi                         ;한 개의 BYTE를 썼으므로 1을 더한다.
    mov byte [es:edi], 'A'
    inc edi
    mov byte [es:edi],0x06
    inc edi
    mov byte [es:edi], 'C'
    inc edi
    mov byte [es:edi],0x06
    inc edi
    mov byte [es:edi], 'K'
    inc edi
    mov byte [es:edi],0x06
    inc edi
    mov byte [es:edi], '2'
    inc edi
    mov byte [es:edi],0x06
    inc edi
    mov byte [es:edi], '_'
    inc edi
    mov byte [es:edi],0x06
    inc edi
    mov byte [es:edi], 'S'
    inc edi
    mov byte [es:edi],0x06
    inc edi
    mov byte [es:edi], 'O'
    inc edi
    mov byte [es:edi],0x06
    inc edi
    mov byte [es:edi], 'S'
    inc edi
    mov byte [es:edi],0x06
    inc edi
    jmp $                           ;이 번지에서 무한루프를 돈다.

msgBack db '*',0xE7                 ;배경색으로 사용할 데이터

times 510-($-$$) db 0               ;여기서부터 509번지까지 0으로 채운다.
dw 0xAA55                           ;510번지에 0xAA, 511번지에 0x55를 넣어둔다.

=>nasm -f bin -o boot.bin boot.txt

qemu.exe -L . -m 32 -localtime -std-vga -fda boot.bin
=> 카와이꺼에 있는 qemu 배치파일 수정

어떤 블로그에서
qemu.exe -L . -boot c -m 256 -hda "boot.bin경로"  -soundhw all -localtime -M pc

중요한 명령인자만 살펴보자면

-L . 은 바이오스파일을 불러오는 명령어입니다. 뒤에 .(점)은 경로입니다.

-boot c는 부팅을 하드디스크로 하겠다는 의미입니다. A는 플로피, D는 시디롬이 됩니다.

-m 256은 메모리를 256메가로 잡아주겠다는 의미입니다.

-hda "경로"는 "경로"를 0번 하드디스크로 사용하겠다는 의미입니다.


* Real Mode
컴퓨터에 전원이 들어온 후 CPU가 처음 움직이기 시작하면서 활동하는 모드.
ex) MS-DOS 전원 켜진 후부터 꺼질 때까지 리얼모드로 작동

리얼모드에서는 프로그램이 한 번에 한 개씩 밖에 동작하지 못한다. 하나의 프로그램이 동작을 마친 후 다른 프로그램을 실행할 수 있다. 그리고 한 프로그램은 현재 컴퓨터가 가지고 있는 램의 모든 영역을 자기 마음대로 사용할 수 있다.

현재까지 리얼모드를 사용하고 있는 이유는 호환성 문제 때문이다. 386이든 펜티엄이든 리얼 모드가 동작하고 있을 때에는 CPU가 모두 하드웨어적으로 8086이 되어 있다고 생각하고 프로그램을 작성해야 한다. 그래서 모든 커널은 컴퓨터에 전원이 들어온 후 리얼 모드에서 여러가지 하드웨어적인 세팅을 마친 후 프로텍티드 모드로 CPU를 전환하는 것이다.

*Protected Mode
현재 사용하고 있는 windows나 Linux가 CPU에서 동작되고 있는 Mode.

이 모드에서는 모든 프로그램이 한꺼번에 동작한다. 정확히 말하면 프로텍티드 모드에서는 유저모드 + 커널 모드, 이렇게 두 가지 모드로 나뉘어진다. 프로그램들은 실행하는 도중 아직 끝나지 않은 상태에서 CPU가 갑자기 커널 모드로 들어가면서 커널의 루틴에 의해 멈추어지게 되고, 다른 프로그램이 이 커널의 루틴에 의해 실행되는 식으로 순서대로 조금씩 조금씩 실행된다. 

프로그램1 실행-> 아직 안 끝남-> CPU-> 커널 모드 진입-> 프로그램1 멈춤-> 프로그램2 실행

이 동작은 엄청나게 빠르게 진행되기 때문에 사람에게는 프로그램들이 한꺼번에 동시에 실행되고 있는 것처럼 보이게 되는 것이다. 

프로그램이 사용할 수 있는 램의 영역커널의 루틴에 의해 정해지게 되고 더 필요하면 커널 모드로 들어가서 요청하여 허락을 받고 얻어오는 방식을 취한다. 

커널 모드의 영역은 유저 모드 프로그램에서는 정해진 루트 외에는 접근을 할 수 없다. 모든 프로그램이 CPU를 공평하게 사용하여 CPU시간이라는 소중한 자원의 낭비를 없애고 메모리를 아무렇게나 사용하지 않도록 해서 메모리 낭비를 없애는 관리를 커널 루틴이 효율적으로 해주는 것이다.

*세그먼트와 오프셋(Segment & Offset)

컴퓨터 Power ON ->BIOS에 새겨진 프로그램 실행-> 여러가지 일 수행 -> 디스크의 첫 512바이트를 램으로 읽어들인다. 이 과정에서 BIOS 프로그램은 디스크에 있는 프로그램을 램의 0x7C00번지에 복사한다.

일반적으로 0x07C00번지 = 0x07C0:0000 = 0x0000:7C00 = 0x0700:0C00
                   물리주소               논리주소                논리주소               논리주소

논리주소 : 프로그래머가 소스를 작성할 때와 컴파일러가 이 소스를 기계어로 컴파일했을 때의 결과물인 기계어에서 사용된다. 이 기계어가 CPU에서 실행될 때 CPU의 하드웨어적인 펌웨어가 논리 주소를 물리 주소로 변환시켜서 사용한다.

변환시킬 때에는 세그먼트에 있는 값에 16을 곱한뒤(16 = 2^4 = << 4 , 16진수에서 0 하나를 더 추가) 거기에 오프셋을 더하는 것이다.

ex) 0x07C0:0000
          /               |
     0x7C00 + 0x0000 = 0x7C00 = 0x07C00
                                                                    |
                                                             앞에 0이 붙은 것은 의미는 없고 단지 설명을 위해 자릿수를 맞춘것이다. 0x 라는 것은 16진수라는 표시

0x0700:0C00
     |               |
0x07000 + 0x0C00 = 0x07C00

0x2004:0101
     |               |
0x20040 + 0x0101 = 0x20141

지금 설명한 것은 Real Mode에서의 주소 지정 방식이다.

Posted via email from zzackzack2's Space