하!~~~ 전 포스트에서 어찌어찌 해서 보호모드 까지 진입 했다. 이제 바람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 로 변경!!!

자 테스트 해보잣!!!

 

os14-1

흐흐흐흐 잘된다…

자~~~~~ 이제 읽은 이미지 데이터를 이제 메모리에 재배치 하잣!!!!

메모리 0x10000위치에 커널 이미지(BARAMOS.SYS) 데이터를 섹션별로 재배치~~~

..

……

…………..

PE포맷은 ImageBase + AddressOfEntryPoint 가 실제 주소란다.. 그렇겠지..ImageBase는 기본 메모리 시작점이라고 했고, AddressOfEntryPoint가 RVA 가상 위치 오프셋 이라고 하니..

근데 … 진짜 근데…보통 실행파일은 0x400000라는데….(?)

그래서 PCVIEW 프로그램으로 내가 예제로 만든 프로그램을 분석해 봤다.

os14-2

역쉬 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 입력하고 컴파일…

아직까진 간단한 코드니 에러 없이 컴파일 잘 된다!!

자 이제!! 테스트

os14-3

ㅠㅠ

된다… 와 ! 된다 ㅠㅠ

부트로더, 커널로더 까지 많은 시행 착오 및 병행 학습을 많이 했는데 막상 이렇게 기능상 구현이 된 모습을 보니 간단하다… 누가 이걸 보고 많은 지식이 포함되어 있다는걸 알겠누.. 흠..

이제 어려운 과정(?)은 다 끝난것 같다. 물론 남은 일이 더 남아 있지만, 어셈블리어 메뉴얼 뒤져 보면서 한자 한자 출력 해보면서 테스트 하는 작업은 끝난 듯….

OS의 핵심인 커널은 이것보다 험난 할 듯 보이지만.. 적어도 문법적으로 검증해야 하는 난관이 없다는데 행복함을 느낀다.

커널은 부트로더, 커널 로더 처럼 단일 기능이 아니고 필요할 때마다 학습해서 될 문제는 아닌듯 해서 커널 까지는 다시 학습이 필요 할 것 같다…

학 ………………..습.

 

+ Recent posts