하!~~~ 전 포스트에서 어찌어찌 해서 보호모드 까지 진입 했다. 이제 바람OS 커널을 읽어서 커널로 이동하면 되는데 Visual Studio 툴로 컴파일 하다 보니 PE 포맷이다. ㅠㅠ 아~~~메모리에 커널이미지를 재배치라는 걸 해줘야 커널로 이동 할 수 있다. 젠장 할일 정말 많네…
여튼, 보호모드 까지.. 진입 했으니 커널 이미지를 읽는 작업부터 해야 겠다.
그런데 보호모드에서는 BIOS 인터럽트를 이용 할 수 없으니 , 보호모드에서 파일 읽는 방법을 찾아야 한다.
어디 보자~~~~~~~
음… http://wiki.osdev.org/ATA_read/write_sectors#Read_in_LBA_mode 이 사이트에서 방법을 찾았다. 다만 기존의 만들어 놓은 걸 다시 고쳐서 만들어야 하니.. 그냥… 보호모드 들어가기 전에 커널 이미지를 읽자 ㅡㅡ;;;; 너~~~~~~~~~~~~~~~~~무 귀찮고… 힘들다 ….
그러면.. 기존의 부트로더에서 OS_LDR.SYS 읽는 방법을 그대로 사용…….
;; creator : cyj (mangg@manggong.org)
;; date : 2014. 3. 27
;; desc : 커널 로더.
;; 1. BARAMOS.SYS 파일을 찾아서 읽자.
;; 1. 보호모드로 진입한다.
;; 2. OK 문자 화면에 출력
[bits 16]
org 0x8000
OS_LDR_ENTRY:
;; CS, DS, ES, & SS을 초기화 하자.
cli
xor eax, eax
mov ds, ax
mov ss, ax
mov es, ax
mov sp, 0xFFFF
mov bp, sp
sti
mov dl,[0x0550] ; 부트 드라이브
mov [BootDrive], dl
lea si, [LOADING_MSG]
call PRINT
call FAT_INFO
; RootDirectoryEntry 읽어 첫번째 파일을 읽자.
mov eax, 0x9000
mov [TEMP_MEMORY], eax
mov eax, [RootDirectoryEntry]
mov [READ_SECTOR], eax
mov eax, 0x10000000 ; 0x10000 위치
mov ebx, eax
mov [FILE_MEMORY], eax
call READ
mov ebx, [TEMP_MEMORY]
add ebx, 0x200
; find file name
mov ax, [TEMP_MEMORY]
FIND_LOOP:
cmp eax, ebx
je NOTFOUND
add ax, 0x20
mov si, ax
mov di, KERNEL_NAME
mov cx, 11
repe cmpsb
jnz FIND_LOOP
mov ax, [si+9]
push ax
mov ax, [si+15]
push ax
pop eax
mov [CurrentCluster], eax
DATA_READ:
lea si,[DOT]
call PRINT
sub eax, 2
xor ebx, ebx
mov bl, [BPB_SecPerClus]
mul ebx
mov ebx, [RootDirectoryEntry]
add eax, ebx
mov [READ_SECTOR], eax
mov eax, [FILE_MEMORY]
mov [TEMP_MEMORY], eax
call READ
mov eax, [BytsPerCluster]
mov ebx, [FILE_MEMORY]
add eax, ebx
mov [FILE_MEMORY], eax
xor ebx, ebx
; FAT 리스트
mov eax, 0x9000
mov [TEMP_MEMORY], eax
mov eax, [CurrentCluster]
;xor ebx, ebx
mov bx, [BPB_BytsPerSec]
shr bx, 2
xor edx, edx
div ebx
push edx
add eax, [FATsector]
mov [READ_SECTOR], eax
call READ
pop edx
mov esi, 0x9000
sal edx, 2
add esi, edx
mov eax, [esi]
mov [CurrentCluster], eax
cmp eax, [FATEoFMask]
jz END
jmp DATA_READ
END:
lea si, [KERNEL_LOADING]
call PRINT
; GDT 등록
xor eax, eax
lgdt [GDT_INFO]
cli
mov eax, cr0
or eax, 1
mov cr0, eax
jmp $+2
nop
nop
jmp 0x08:Entry32
NOTFOUND:
lea si,[FAIL_MSG]
call PRINT
jmp $
; 하드디스크 읽기
READ:
; Disk Address Packet (DAP)
xor ax,ax ;INT 13h AH=00h: Reset Disk Drive
mov dl,BYTE [BootDrive] ;DL = Drive Number
int 0x13
jc READ
mov al, 0x10 ; 크기
mov [0x500], al
mov al, [BPB_SecPerClus] ; 읽을 섹터 수
mov [0x502], ax
mov eax, [TEMP_MEMORY] ; 데이터가 들어갈 주소
mov [0x504], eax ; Segment:offset
mov eax, [READ_SECTOR] ; 접근 할 LBA 번호
mov [0x508], eax
mov ax, 0x500 ; DAP의 Segment:offset
mov si, ax
mov ax, 0
mov ds, ax
mov ah, 0x42 ; LBA 읽기 명령
mov dl, [BootDrive] ; 장치
int 0x13
jc READ_ERROR
ret
READ_ERROR:
lea si,[READ_ERR]
call PRINT
jmp $
PRINT:
pusha ; 모든 레지스터를 스택에 넣는다.
PRINT_LOOP:
mov al, [si] ; al에 글자 하나 저장한다.
inc si ; si 주소를 증가한다.
or al, al ; or 연산.
jz PRINT_END ; 문자열 끝이 or 연산이 0 이라면. 종료
mov ah,0x0E ; ah = 0xE
int 0x10 ; 인터럽트 0x10h
jmp PRINT_LOOP ; 다음 문자 출력 루프
PRINT_END:
popa ;모든 레지스터 스택에서 뺀다.
ret ;호출 한곳으로 리턴.
FAT_INFO:
pusha
xor ebx, ebx
mov eax, 0x9000
mov [TEMP_MEMORY], eax
xor eax, eax
mov eax, 0
mov [READ_SECTOR], eax
call READ
xor ebx, ebx
mov si, [TEMP_MEMORY]
mov bl, [si+454]
mov bl, 0x80
mov eax, 0x9000
mov [TEMP_MEMORY], eax
mov eax, ebx
mov [READ_SECTOR], eax
call READ
mov si, [TEMP_MEMORY]
mov bx, [si]
mov bx, [si + 11] ; BytePerSec
mov [BPB_BytsPerSec], bx
xor ebx, ebx
mov bl, [si + 13] ; SecPerCluster
mov [BPB_SecPerClus], bl
xor ecx, ecx
xor ebx, ebx
xor eax, eax
mov cl, [si + 16] ; FAT NUM
mov ebx, [si + 28] ; Hidden Sector
mov eax, [si + 36] ; FAT 32
mul ecx
mov cx, [si + 14] ; Reserved Sector
add eax, ecx
add eax, ebx
mov [RootDirectoryEntry], eax
xor eax, eax
mov eax, ebx
add eax, ecx
mov [FATsector], eax
xor eax, eax
xor ebx, ebx
mov bx, [si + 11]
mov al, [si + 13]
mul ebx
mov [BytsPerCluster], eax
lea si,[FAT32_OK]
call PRINT
popa
ret
DOT:
db ".", 0x0D, 0x0A,0
FAT32_OK:
db "Loading FAT's Info...", 0x0D, 0x0A, 0
KERNEL_LOADING:
db "Loading BARAMOS.SYS...", 0x0D, 0x0A, 0
READ_ERR:
db "Can't Read Disk..", 0x0D, 0x0A, 0
KERNEL_NAME:
db "BARAMOS SYS",0
LOADING_MSG db 0x0D, 0x0A, "Searching for BARAMOS.SYS...", 0x0D, 0x0A, 0x00
FAIL_MSG db 0x0D, 0x0A, "ERROR.... ", 0x0D, 0x0A, 0x0A, 0x00
BPB_BytsPerSec dw 0
BPB_SecPerClus db 1
BootDrive db 0x00
RootDirectoryEntry dd 0
FATsector dd 0
BytsPerCluster dd 0
FATClusterMask dd 0
FATEoFMask dd 0x0FFFFFFF
CurrentCluster dd 2
TEMP_MEMORY dd 0x9000
READ_SECTOR dd 0
FILE_MEMORY dd 0x10000
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 보호모드 GDT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
GDT_INFO:
dw GDT_TABLE_END - GDT_TABLE - 1
dd GDT_TABLE
GDT_TABLE:
dw 0x0000 ; null
dw 0x0000
db 0x00
db 0x00
db 0x00
db 0x00
dw 0xFFFF ; Code
dw 0x0000
db 0x00
db 0x9A
db 0xCF
db 0x00
dw 0xFFFF ; Data
dw 0x0000
db 0x00
db 0x92
db 0xCF
db 0x00
GDT_TABLE_END:
[bits 32]
Entry32:
xor eax, eax
mov ax, 0x10
mov ds, ax
mov es, ax
mov ss, ax
xor esp, esp
mov esp, 0xFFFF
mov BYTE [0xB8000], 'O'
mov BYTE [0xB8002], 'K'
hang:
jmp hang
위와 같이 작성..
이제 BARAMOS.SYS 파일을 만들어야 하는데~~~
음..
동작 까진 필요 없는 테스트이니깐....
Visual Studio 에서 콘솔에 프로그램 임의로 하나 작성..
// testKernel.cpp : 콘솔 응용 프로그램에 대한 진입점을 정의합니다.
//
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
return 0;
}
Visual Studio 에서 기본 으로 생성해주는 파일 그대로 컴파일 해서 BARAMOS.SYS 로 변경!!!
자 테스트 해보잣!!!
흐흐흐흐 잘된다…
자~~~~~ 이제 읽은 이미지 데이터를 이제 메모리에 재배치 하잣!!!!
메모리 0x10000위치에 커널 이미지(BARAMOS.SYS) 데이터를 섹션별로 재배치~~~
..
……
…………..
PE포맷은 ImageBase + AddressOfEntryPoint 가 실제 주소란다.. 그렇겠지..ImageBase는 기본 메모리 시작점이라고 했고, AddressOfEntryPoint가 RVA 가상 위치 오프셋 이라고 하니..
근데 … 진짜 근데…보통 실행파일은 0x400000라는데….(?)
그래서 PCVIEW 프로그램으로 내가 예제로 만든 프로그램을 분석해 봤다.
역쉬 4M 위치다. 리얼모드 모드에서는 1M 이상은 접근 안된다고 했는데????
아~~~~ 맞다… ㅡㅡ;;; 보호 모드로 넘어가서 재배치 해야 하는거군 … 에휴!!
음. 근데 초기 메모리 레이아웃에는 0x10000 위치에 커널 이미지 올린다고 했는데 … 0x400000으로 바꿔야 하나??? 흠…
구분
|
위치
|
부트로더 |
0x7C00 |
커널 로더 |
0x8000 |
커널 임시 |
0x10000 |
커널 재배치 |
0x400000 |
자… 이제 커널 재배치를 해보잣!!!!
0x10000 커널 데이터에서 ImageBase를 우선 구해야 하니, 요넘은 IMAGE_NT_HEADER 구조체 IMAGE_OPTIONAL_HEADER32 구조체 안에 있으니… 우선 IMAGE_OPTIONAL_HEADER32 구조체 위치를 찾아야겠다.
IMAGE_DOS_HEADER의 e_lfanew 에 IMAGE_NT_HEADER위치가 기록 되어 있고, IMAGE_OPTIONAL_HEADER32 위치는 e_lfanew + 0x18 에 있네.. 여기서 다시 ImageBase 위치는 아~~~ 그냥 e_lfanew + 0x34 구만..
ImageBase = e_lfanew(IMAGE_DOS_HEADER) + 0x34
PCVIEW 프로그램으로 찾아보니 쉽네 ㅋㅋㅋㅋ
ImageBase를 찾았으니, 섹션만 ImageBase 위치에 순차적으로 복사하면 되겠군..
섹션 첫 위치는 IMAGE_OPTIONAL_HEADER32 구조체의 SizeOfHeaders에 기록되니까 ImageBase 찾는거랑 마찬가지로…
Section = e_lfanew + 0x54
아.. 그런데 섹션위치는 알았는데 얼마만큼 복사하는지 섹션 크기가 알아야 하네… 그리고 섹션이 하나가 아니고 여러개 존재 하니깐…. Section 첫번째 위치는 별 의미가 없다… 흠… 그러면 섹션들 헤더를 열고.. 섹션 크기, 섹션 실제 위치, ImageBase + 섹션 RVA를 구한후 복사해줘야 할듯… 그러자면 섹션이 몇개 있는지에 대한 정보도 필요하다..섹션갯수는 elfanew 에서 …
SectionCount = e_lfanew + 0x06
그리고 각 섹션헤더 위치는 IMAGE_OPTION_HEADER 다음 위치에 있으니깐 IMAGE_FILE_HEADER구조체 SizeOfOptionalHeader가 IMAGE_OPTION_HEADER 크기니깐 ㅡㅡ;;;
SizeOfOptionHeader = e_lfanew + 0x14 구하고,
SectionHeader = e_lfanew + SizeOfOptionHeader + IMAGE_FILE_HEADER크기
IMAGE_FILE_HEADER크기는 0x14 크기니깐..
SectionHeader = e_lfanew + SizeOfOptionHeader + 0x14
에다가 다시 Signature 4바이트 더하면…
SectionHeader = e_lfanew + SizeOfOptionHeader + 0x14 + 0x04
만큼 있다.
아고 힘들어…
이제 섹션 갯수 만큼루프 돌면서 섹션 헤더를 보고 섹션의 실제 저장된 데이터를 ImageBase + 섹션 RVA만큼 위치에다가 복사해주면 된다!!!!
그럼 코딩해 보잣!!!!
;; creator : cyj (mangg@manggong.org)
;; date : 2014. 3. 27
;; desc : 커널 로더.
;; 1. BARAMOS.SYS 파일을 찾아서 읽자.
;; 1. 보호모드로 진입한다.
;; 2. OK 문자 화면에 출력
[bits 16]
org 0x8000
OS_LDR_ENTRY:
;; CS, DS, ES, & SS을 초기화 하자.
cli
xor eax, eax
mov ds, ax
mov ss, ax
mov es, ax
mov sp, 0xFFFF
mov bp, sp
sti
mov dl,[0x0550] ; 부트 드라이브
mov [BootDrive], dl
lea si, [LOADING_MSG]
call PRINT
call FAT_INFO
; RootDirectoryEntry 읽어 첫번째 파일을 읽자.
mov eax, 0x9000
mov [TEMP_MEMORY], eax
mov eax, [RootDirectoryEntry]
mov [READ_SECTOR], eax
mov eax, 0x10000000
mov ebx, eax
mov [FILE_MEMORY], eax
call READ
mov ebx, [TEMP_MEMORY]
add ebx, 0x200
; find file name
mov ax, [TEMP_MEMORY]
FIND_LOOP:
cmp eax, ebx
je NOTFOUND
add ax, 0x20
mov si, ax
mov di, KERNEL_NAME
mov cx, 11
repe cmpsb
jnz FIND_LOOP
mov ax, [si+9]
push ax
mov ax, [si+15]
push ax
pop eax
mov [CurrentCluster], eax
DATA_READ:
lea si,[DOT]
call PRINT
sub eax, 2
xor ebx, ebx
mov bl, [BPB_SecPerClus]
mul ebx
mov ebx, [RootDirectoryEntry]
add eax, ebx
mov [READ_SECTOR], eax
mov eax, [FILE_MEMORY]
mov [TEMP_MEMORY], eax
call READ
mov eax, [BytsPerCluster]
mov ebx, [FILE_MEMORY]
add eax, ebx
mov [FILE_MEMORY], eax
xor ebx, ebx
; FAT 리스트
mov eax, 0x9000
mov [TEMP_MEMORY], eax
mov eax, [CurrentCluster]
;xor ebx, ebx
mov bx, [BPB_BytsPerSec]
shr bx, 2
xor edx, edx
div ebx
push edx
add eax, [FATsector]
mov [READ_SECTOR], eax
call READ
pop edx
mov esi, 0x9000
sal edx, 2
add esi, edx
mov eax, [esi]
mov [CurrentCluster], eax
cmp eax, [FATEoFMask]
jz END
jmp DATA_READ
END:
lea si, [KERNEL_LOADING]
call PRINT
; GDT 등록
xor eax, eax
lgdt [GDT_INFO]
cli
mov eax, cr0
or eax, 1
mov cr0, eax
jmp $+2
nop
nop
jmp 0x08:Entry32
NOTFOUND:
lea si,[FAIL_MSG]
call PRINT
jmp $
; 하드디스크 읽기
READ:
; Disk Address Packet (DAP)
xor ax,ax ;INT 13h AH=00h: Reset Disk Drive
mov dl,BYTE [BootDrive] ;DL = Drive Number
int 0x13
jc READ
mov al, 0x10 ; 크기
mov [0x500], al
mov al, [BPB_SecPerClus] ; 읽을 섹터 수
mov [0x502], ax
mov eax, [TEMP_MEMORY] ; 데이터가 들어갈 주소
mov [0x504], eax ; Segment:offset
mov eax, [READ_SECTOR] ; 접근 할 LBA 번호
mov [0x508], eax
mov ax, 0x500 ; DAP의 Segment:offset
mov si, ax
mov ax, 0
mov ds, ax
mov ah, 0x42 ; LBA 읽기 명령
mov dl, [BootDrive] ; 장치
int 0x13
jc READ_ERROR
ret
READ_ERROR:
lea si,[READ_ERR]
call PRINT
jmp $
PRINT:
pusha ; 모든 레지스터를 스택에 넣는다.
PRINT_LOOP:
mov al, [si] ; al에 글자 하나 저장한다.
inc si ; si 주소를 증가한다.
or al, al ; or 연산.
jz PRINT_END ; 문자열 끝이 or 연산이 0 이라면. 종료
mov ah,0x0E ; ah = 0xE
int 0x10 ; 인터럽트 0x10h
jmp PRINT_LOOP ; 다음 문자 출력 루프
PRINT_END:
popa ;모든 레지스터 스택에서 뺀다.
ret ;호출 한곳으로 리턴.
FAT_INFO:
pusha
xor ebx, ebx
mov eax, 0x9000
mov [TEMP_MEMORY], eax
xor eax, eax
mov eax, 0
mov [READ_SECTOR], eax
call READ
xor ebx, ebx
mov si, [TEMP_MEMORY]
mov bl, [si+454]
mov bl, 0x80
mov eax, 0x9000
mov [TEMP_MEMORY], eax
mov eax, ebx
mov [READ_SECTOR], eax
call READ
mov si, [TEMP_MEMORY]
mov bx, [si]
mov bx, [si + 11] ; BytePerSec
mov [BPB_BytsPerSec], bx
xor ebx, ebx
mov bl, [si + 13] ; SecPerCluster
mov [BPB_SecPerClus], bl
xor ecx, ecx
xor ebx, ebx
xor eax, eax
mov cl, [si + 16] ; FAT NUM
mov ebx, [si + 28] ; Hidden Sector
mov eax, [si + 36] ; FAT 32
mul ecx
mov cx, [si + 14] ; Reserved Sector
add eax, ecx
add eax, ebx
mov [RootDirectoryEntry], eax
xor eax, eax
mov eax, ebx
add eax, ecx
mov [FATsector], eax
xor eax, eax
xor ebx, ebx
mov bx, [si + 11]
mov al, [si + 13]
mul ebx
mov [BytsPerCluster], eax
lea si,[FAT32_OK]
call PRINT
popa
ret
DOT:
db ".", 0x0D, 0x0A,0
FAT32_OK:
db "Loading FAT's Info...", 0x0D, 0x0A, 0
KERNEL_LOADING:
db "Loading BARAMOS.SYS...", 0x0D, 0x0A, 0
READ_ERR:
db "Can't Read Disk..", 0x0D, 0x0A, 0
KERNEL_NAME:
db "BARAMOS SYS",0
LOADING_MSG db 0x0D, 0x0A, "Searching for BARAMOS.SYS...", 0x0D, 0x0A, 0x00
FAIL_MSG db 0x0D, 0x0A, "ERROR.... ", 0x0D, 0x0A, 0x0A, 0x00
BPB_BytsPerSec dw 0
BPB_SecPerClus db 1
BootDrive db 0x00
RootDirectoryEntry dd 0
FATsector dd 0
BytsPerCluster dd 0
FATClusterMask dd 0
FATEoFMask dd 0x0FFFFFFF
CurrentCluster dd 2
TEMP_MEMORY dd 0x9000
READ_SECTOR dd 0
FILE_MEMORY dd 0x10000
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 보호모드 GDT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
GDT_INFO:
dw GDT_TABLE_END - GDT_TABLE - 1
dd GDT_TABLE
GDT_TABLE:
dw 0x0000 ; null
dw 0x0000
db 0x00
db 0x00
db 0x00
db 0x00
dw 0xFFFF ; Code
dw 0x0000
db 0x00
db 0x9A
db 0xCF
db 0x00
dw 0xFFFF ; Data
dw 0x0000
db 0x00
db 0x92
db 0xCF
db 0x00
GDT_TABLE_END:
[bits 32]
Entry32:
xor eax, eax
mov ax, 0x10
mov ds, ax
mov es, ax
mov ss, ax
xor esp, esp
mov esp, 0xFFFF
; 메모리 재배치 해보자
mov esi, 0x10000 ; 커널 이미지 저장된곳
xor edx, edx
xor eax, eax
add edx, 0x3C
mov eax, [esi+edx]
mov [NT_POINTER], eax ; e_lfanew 위치 구하기(IMAGE_NT_HEADER위치)
mov ebx, eax
mov edx, 0x34
add edx, ebx
mov eax, [esi+edx]
mov [IMAGE_BASE], eax ; IMAGE_BASE 위치 구하기
mov edx, 0x28
add edx, ebx
mov eax, [esi+edx]
mov [ENTRY_POINT], eax ; ENTRY_POINT 위치 구하기
mov edx, 0x06
add edx, ebx
mov ax, WORD [esi+edx]
mov [SECTION_COUNT], ax ; 섹션 갯수 구하기
mov edx, 0x14
add edx, ebx
mov ax, WORD [esi+edx]
mov [OPTIONHEADER_SIZE], ax ;IMAGE_OPTION_HEADER크기 구하기
mov edx, 0x18
add dx, WORD[OPTIONHEADER_SIZE]
add edx, ebx
mov eax, edx
mov [SECTION_HEADER], eax ;섹션 헤더 위치 구하기
xor ecx, ecx
mov cx, [SECTION_COUNT] ; 섹션 갯수 만큼 반복
SECTION_LOOP:
mov esi, 0x10000
mov ebx, [SECTION_HEADER] ; 섹션 헤더 위치
mov edx, 0x0C ; 섹션 RVA = 섹션 헤더 위치 + 0x0C
add edx, ebx
mov eax, [esi+edx]
mov [SECTION_RVA], eax
mov edx, 0x10 ; 섹션 크기 = 섹션 헤더 위치 + 0x10
add edx, ebx
mov eax, [esi+edx]
mov [SECTION_SIZE], eax
mov edx, 0x14 ; 섹션 데이터 위치 = 섹션 헤더 위치 + 14
add edx, ebx
mov eax, [esi+edx]
mov [SECTION_POINTER], eax
; 복사할 원본 위치
add esi, [SECTION_POINTER] ; 섹션 데이터가 있는 위치 .
mov edi, [IMAGE_BASE] ; 복사될 메모리 위치
add edi, [SECTION_RVA] ; IMAGE_BASE 에서 섹션 RVA 만큼 위치
push ecx
cld
mov ecx, [SECTION_SIZE] ; 섹션 사이즈 만큼
repz movsb ; 복사
pop ecx
mov eax, [SECTION_HEADER] ; 섹션 헤더 위치를 다음 섹션 헤더 위치로 변경
add eax, 40
mov [SECTION_HEADER], eax
loop SECTION_LOOP
mov BYTE [0xB8000], 'O'
mov BYTE [0xB8002], 'K'
mov eax, [IMAGE_BASE]
add eax, [ENTRY_POINT]
call eax
hang:
jmp hang
IMAGE_BASE dd 0
ENTRY_POINT dd 0
NT_POINTER dd 0
OPTIONHEADER_SIZE dw 0
SECTION_COUNT dw 0
SECTION_HEADER dd 0
SECTION_RVA dd 0
SECTION_SIZE dd 0
SECTION_POINTER dd 0
PE 메모리 재배치 하는 코드 찾다가 http://1228.tistory.com/entry/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0-%EC%96%B4%EC%85%88%EB%B8%94%EB%A6%AC%EC%BD%94%EB%93%9C%EC%97%90%EC%84%9C-C%EC%BD%94%EB%93%9C%EB%A1%9C-%EC%A0%90%ED%94%84%ED%95%98%EA%B8%B0-%EB%A1%9C%EB%8D%94-%EC%9E%91%EC%84%B1 블로그 꼬꼬넷님 코드를 훔쳤다(?) … 정말 감사드린다……똭!!!
이제 테스트…!!!
헐… 또 재부팅이다… 음…
코드를 몇번을 확인해도 문제는 없어 보인다.
커널이 메모리상에 재배치 되는건 문제가 없어 보인다. 그래서 Visual Studio에서 컴파일 할때 옵션이 잘못된듯 해 보여 또 부랴부랴 검색질.
http://wiki.osdev.org/Visual_Studio
요기 이 사이트에서 하라는대로 컴파일 옵션을 수정했다.
그리고 커널 코드도 바꿨다…
int StartKernel(int argc, char* argv[])
{
char* hello = "Hello OS!";
unsigned char* vidmem = (unsigned char*)0xB8000;
while( *hello != '\0' )
{
*vidmem++ = *hello++;
*vidmem++ = 7; // 문자 기본 속성
}
return 0;
}
그리고 컴파일 옵션->고급 에서 진입점을 StartKernel 입력하고 컴파일…
아직까진 간단한 코드니 에러 없이 컴파일 잘 된다!!
자 이제!! 테스트
ㅠㅠ
된다… 와 ! 된다 ㅠㅠ
부트로더, 커널로더 까지 많은 시행 착오 및 병행 학습을 많이 했는데 막상 이렇게 기능상 구현이 된 모습을 보니 간단하다… 누가 이걸 보고 많은 지식이 포함되어 있다는걸 알겠누.. 흠..
이제 어려운 과정(?)은 다 끝난것 같다. 물론 남은 일이 더 남아 있지만, 어셈블리어 메뉴얼 뒤져 보면서 한자 한자 출력 해보면서 테스트 하는 작업은 끝난 듯….
OS의 핵심인 커널은 이것보다 험난 할 듯 보이지만.. 적어도 문법적으로 검증해야 하는 난관이 없다는데 행복함을 느낀다.
커널은 부트로더, 커널 로더 처럼 단일 기능이 아니고 필요할 때마다 학습해서 될 문제는 아닌듯 해서 커널 까지는 다시 학습이 필요 할 것 같다…
학 ………………..습.