지난 포스트에 올린 부트로더가 동작을 안 한다. 왜 안되는지 모르겠다. 디버깅을 해봐도 뜻대로 동작하지 않았다. 어셈블리어 생각대로 코딩이 안 된다. 이쯤되면 하기 싫어진다…흐……….

여튼 시작은 했으니, 부트로더 만이라도 빨리 끝내야 겠다는 성급함이 기초 공부를 게을리 하게 된것 같다. 원인이 무엇인가 부터 찾아 봤다.

우선, 의심가는 부분이 헤드,트랙 계산 부분이다.


	; 헤드, 트랙, 섹터로 재 계산해서 저장하자.
	; 트랙 = 총섹터 / (헤드 갯수 * 트랙당 섹터수)
	; 헤드 = (총섹터/트랙 당 섹터수) % 헤드 갯수
	; 섹터 = (총섹터 % 트랙 당 섹터) + 1
	; EAX 는 총섹터 값이 있다.
CONVERT_CHS:
	xor dx, dx	; dx를 0으로 초기화 하자.
	mov cx, [BPB_SECTOR_PER_TRACK]
	div cx	; AX / CX = AX , AX % CX = DX

	inc dl	; 나머지 + 1 = 섹터다.
	mov [SECTOR], dl

	xor dx, dx	; dx를 0으로 초기화 하자. ax는 총섹터/트랙 당 섹터수 값이 있다.
	mov cx, [BPB_HEADS]
	div cx	; (총섹터/트랙 당 섹터수) / 헤드수 = 트랙, (총섹터/트랙 당 섹터수) % 헤드수 = 헤드

	mov [HEAD], dl
	mov [TRACK], al
	ret


여기저기 찾아봐도 계산에는 문제가 없다….


BPB_SECTOR_PER_TRACK이 잘못된 것일까? BPB_HEADS가 잘못된 것일까?? 아…..어려움과 디버깅을 할 수 없다는 답답함이 밀려온다…

여기 저기 검색해 본다..LBA 모드???? 기존 Cylinder, Head, Sector 파일 접근 방식을 그냥 섹터 번호로만 접근해서 읽을 수 있는 방식이란다. 오!!!!! 이제까지 CHS 모드로 접근 하다 보니 CONVERT_CHS함수 까지 만들어서 변환 작업을 했었는데 이 부분이 필요 없게 된다. 코드 량도 확실히 줄어 들것 같다. 한번 파일 접근을 CHS 모드에서 LBA 모드로 변경해 봐야 겠다.




CHS 모드 LBA 모드


CHS 모드는 Cylinder, Head, Sector를 직접 명기해서 디스크 섹터 위치를 접근 하는 방식이란다. 초기에는 이 방식으로 접근 했었는데 점점 디스크 용량이 증가함에 따라 표현 할 수 있는 용량이 한계에 다다르게 되었단다. (컴퓨터 하드웨어 시장이 용량, 속도 부분에서 초기 설계치 보다 급속도로 늘어나는거지.. 자고 일어나면 달라지는 세상이니… 테라바이트가 예전에는 꿈의 용량이었는데 이젠 현실이고.. 페타바이트도 뭐 꿈의 용량이 아니지..근데 존재하나?) 여튼 꼼수(ECHS : Extended CHS)로 버티다. GG 치고… LBA 모드가 나오게 되었단다.  LBA모드는 디스크를 0섹터부터 끝까지 일련된 숫자를 부여해서 접근하면 된다고 한다.  근데 CHS 모드가 나온뒤에 LBA가 나온게 아니고 CHS 모드와 LBA 모드는 초기 표준에 설계되어 있다가 CHS가 용량 한계에 부딪치자 LBA로 선회 했다고 한다. 또한 LBA도 28비트로 사용되었는데 128G 밖에 표현 못한다. 또 용량의 한계가 생겼고 28비트를 48비트로 확장 시켜서 이젠 144PB 까지 가능하다고 한다.


즉,  직관적인 LBA가 편하다는 거네… LBA 모드로 변경해야 겠다. 소스 코드도 줄고.. 그럼 어떻게 사용해야 하나??


LBA 모드로 데이터를 읽으려면 CHS 와 마찬가지로 int 13 인터럽트를 이용하면 된다고 한다. DAP(Disk Access Packet)이라는 16바이트의 구조체에 읽을 위치, 읽어서 저장할 메모리 위치, 읽을 섹터 수 를 설정해 주면 읽는단다.


종류

크기

설명

DAP 크기 1 Byte 구조체 크기 총 16 (0x10) 으로 설정
예약 1 Byte 사용 안한다고 한다. 그냥 0
읽을 섹터 수 2 Byte 읽어야 할 섹터 수
저장할 메모리 4 Byte 세그먼트:오프셋 으로 읽은 데이터를 저장 할 메모리 위치
읽을 위치 8 Byte 읽을 시작 섹터 번호(0 base index)


기존 CONVERT_CHS함수가 필요 없어져서 512바이트 제한에서 조금 해방되나 싶었는데 위 16바이트 구조체 변수 때문에 그닥 해방되지 않는다. 그래서 검색 좀 해봤더니 호~~ 그냥 임의의 사용하지 않는 메모리에다가 값을 설정하고 사용해 버리네..


READ_DISK:
	pusha				; 모든 레지스터를 스택에 넣는다.
DISK_RESET:
	; Disk Address Packet (DAP)
	xor ax,ax			;INT 13h AH=00h: Reset Disk Drive
	mov dl,BYTE 0x80		;DL = Drive Number
	int 0x13
	jc DISK_RESET
	mov	al, 0x10 ; 크기
	mov	[0x500], al

	mov al, [READ_SIZE]	; 읽을 섹터 수
	mov	[0x502], ax
	mov ax, [READ_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, [DRIVE]

	int 0x13

         popa
	ret


0x500 위치에 DAP를 구성해서 읽게 했다.

그러면 총 소스 코드는


org 0x7C00
bits 16

BOOTLOADER_ENTRY:
	;; start로 이동한다. (BPB의 영역의 3바이트는 점프 명령 코드로 이용한다. )
	jmp BOOTLOADER_MAIN
	nop ; 코드에서 2바이트 밖에 안되서 nop 1바이트 추가.

;; FAT32 파일시스템 구조
BPB_OEM: db "EOS Boot"				; 8 바이트 OEM 이름..
BPB_BYTE_PER_SECTOR:	dw 512		; 섹터당 바이트 크기.
BPB_SECTOR_PER_CLUSTER: db 0x02		; 클러스터당 섹터 갯수
BPB_RESERVED_SECTOR:	dw 0x186E   ;  예약 섹터 갯수
BPB_FAT_NUM:			db 0x02		; FAT 갯수 (FAT1, FAT2 의 카피본을 두므로 보통 2개)
BPB_ROOT_ENTRY_NUMBER:	dw 0x0000	; 루트 디렉토리에 최대 디렉토리 포함할 수 있는 갯수
BPB_FAT16_SECTORS:		dw 0x0000	; FAT16일 때 총 섹터 갯수
BPB_MEDIA_TYPE:			db 0xF8		; 장치 타입 (0xF8 는 하드디스크)
BPB_FAT16_SIZE:			dw 0x0000	; FAT16일때 FAT테이블 크기
BPB_SECTOR_PER_TRACK:	dw 0x003F	; 트랙당 섹터 갯수
BPB_HEADS:				dw 0x00FF 	; 헤드 갯수
BPB_HIDDEN_SECTOR:		dd 0x00000080	; 숨겨진 섹터 갯수
BPB_FAT32_SECTORS:		dd 0x0003E800	; FAT32 파일시스템일 때 총 섹터 갯수
BPB_FAT32_SIZE:			dd 0x000003C9	; FAT32일때 FAT테이블 크기
BPB_EXTENSION_FLAGS:	dw 0x0000		; 확장 플래그 ( 0-3 : 활성화 FAT )
BPB_FILESYSTEM_VER:		dw 0x0000		; FAT32의 버젼
BPB_ROOT_ENTRY_CLUSTER: dd 0x00000002	; 데이터 시작 클러스터 위치
BPB_FILESYSTEM_INFO:	dw 0x0001		; 파일시스템 정보 위치
BPB_BACKUP_BOOT_SECTOR: dw 0x0006		; 백업 부트 섹터 위치
BPB_RESERVED:							; 예약된 정보 
						dd 0x00
						dd 0x00
						dd 0x00
BS_DRIVE:							; 바이오스콜(0x13) 드라이브 정보
						db 0x80
BS_RESERVED1:						; 예약
						db 0x00
BS_BOOT_SIGNATURE:					; 부트 서명 (0x29)
						db 0x29		;
BS_VOLUME_ID:						; 볼륨 시리얼 번호
						dd 0xC1C286C
BS_VOLUME_LABEL:					; 볼륨 레이블명
						dd 0x4E4F204E
						dd 0x414D4520
						dw 0x2020
						db 0x20
BS_FILESYSTEM_TYPE:					; 파일 시스템 이름
						dd 0x46415433
						dd 0x32202020

BOOTLOADER_MAIN:
	cli
	;; CS, DS, ES, & SS을 초기화 하자.
	xor eax, eax
	mov ds, ax
	mov ss, ax
	mov es, ax

	mov sp, 0x8000  ; 스택포인터를 잡자.
	mov bp, sp		; bp도 0x8000으로 잡자.
	sti

	;mov [DRIVE], dl	; 현재 드라이브를 저장하자.

	; 루트 디렉토리 엔트리 위치를 구하자.
	; 루트 디렉토리 엔트리 = (FAT 갯수 * FAT 테이블크기) + 예약 섹터 + 히든 섹터
	mov al, [BPB_FAT_NUM]	
	mov ebx, [BPB_FAT32_SIZE]
	mul ebx		; AL * EBX = EAX
	xor ebx, ebx ; EBX를 0으로 초기화 하자.
	mov bx, [BPB_RESERVED_SECTOR] ; 예약 섹터를 bx 저장.
	add eax, ebx	; EAX = EAX + EBX
	mov ebx, [BPB_HIDDEN_SECTOR] ; 히든 섹터를 ebx로 저장.
	add eax, ebx	; EAX = EAX + EBX
	mov [ROOT_ENTRY], eax

	; FAT1 위치를 찾자.
	; FAT1 = 예약 섹터 + 히든 섹터
	xor eax, eax	; eax는 0으로 초기화 한다.
	mov ax, [BPB_RESERVED_SECTOR] ; 예약 섹터를 ax 저장.
	add eax, ebx	; ebx 는 이미 히든 섹터가 저장되어 있다.
	mov [FAT1], eax

	; 클러스터를 바이트로 변환하자.
	; 클러스터 총 바이트 = (섹터당 바이트 * 클러스터당 섹터 갯수)
	xor ebx, ebx
	mov ax, [BPB_BYTE_PER_SECTOR]
	mov bl, [BPB_SECTOR_PER_CLUSTER]
	mul bx	; EAX = AX * BX  총 바이트를 구했다.
	mov [CLUSTER_BYTES], eax

	mov ax, 0x8000	; OS_LDR 저장될 위치
	mov [LDR_MEMORY], ax
		
	; 현재 위치 클러스터를 저장하자.
	mov eax, [BPB_ROOT_ENTRY_CLUSTER]
	mov [CURRENT_CLUSTER], eax

	; 0x9000 에 임시로 루트 디렉토리 엔트리를 읽어서 저장해 놓자.
	mov ax, 0x9000	; 임시
	mov [READ_MEMORY], ax

	mov al, [BPB_SECTOR_PER_CLUSTER]
	mov [READ_SIZE], al

FILE_LIST:
	mov ebx, [ROOT_ENTRY]	; 루트 디렉토리 섹터 위치.
	mov eax, [CURRENT_CLUSTER]
	sub eax, 2
	add eax, ebx

	mov [READ_SECTOR], eax
	call READ_DISK	; 데이터를 읽는다.

FILE_FIND:
	; 파일이름을 찾자. 
	mov ax, 0x9000	; 0x9000에 루트 디렉토리 엔트리 데이터 존재.

FIND_LOOP:
	add ax, 0x20		; 첫 데이터는 C:\ 데이터므로 넘어간다.

	mov ebx, [CLUSTER_BYTES]
	add ebx, 0x9000
	cmp ax, bx
	je NO_FIND

	; 파일 이름을 비교한다.
	mov si, ax
	mov di, OS_LDR_FILENAME
	mov cx, 11
	repe cmpsb

	jnz FIND_LOOP


	; 파일을 찾았다.!!! ^^

	; 데이터 클러스터 위치를 구하자.
	mov ax, [si+9]	; 클러스터 상위 2바이트
	push ax
	mov ax, [si+15]	; 클러스터 하위 2바이트
	push ax
	pop eax
	mov [CURRENT_CLUSTER], eax

LOOP_DATA_READ:

	call DATA_READ	; 데이터 클러스터에서 데이터 읽기
	call FAT_SEARCH	; FAT 테이블에서 다음 클러스터를 찾는다.
	cmp al, 0x01	; al에 다음 클러스터가 있으면 0x00, 없으면 0x01 
	je RUN_LDR		; 다음 클러스터가 없으면 OS_LDR 실행하러 가자.
	jmp LOOP_DATA_READ	; 다음 데이터 클러스터 읽으로 가자.

RUN_LDR:
	jmp 0x8000		; 0x8000(OS_LDR.SYS) 실행하자.

	; 루트 디렉토리 엔트리에서 OS_LDR.SYS를 못 찾으면
	; 루트 디렉토리 엔트리의 다음 클러스터를 찾아서
	; 파일 목록을 비교 하러간다.
NO_FIND:
	call FAT_SEARCH	; FAT 테이블에서 다음 클러스터를 찾자.
	cmp al, 0x00	; 다음 클러스터를 찾으면 0x00 
	je FILE_FIND	; 다시 파일이름 찾으로 가자.

	jmp $			; 다음 클러스터가 없으면 무한루프.

	; 데이터 클러스터에서 데이터를 읽어서
	; LDR_MEMORY에 로딩하자.
DATA_READ:
	mov ax, [LDR_MEMORY]	
	mov [READ_MEMORY], ax	; READ_MEMORY에 LDR_MEMORY 복사하자. (세그먼트임을 기억하자)
	mov al, [BPB_SECTOR_PER_CLUSTER]
	mov [READ_SIZE], al	; 클러스터(섹터 2) 만큼 읽자.
	mov ebx, [ROOT_ENTRY]	; 루트 디렉토리 섹터 위치.
	mov eax, [CURRENT_CLUSTER] ; 현재 클러스터.
	sub eax, 2		; 클러스터가 2부터 시작한다고 하니 2를 뺀다.
	mov cl, [BPB_SECTOR_PER_CLUSTER]
	mul cl
	add eax, ebx	; EAX = EAX+EBX. EAX는 루트디렉토리부터 현재 클러스터(-2) 더한값.
	mov [READ_SECTOR], eax

	call READ_DISK	; 데이터를 읽는다.

	mov ax, [LDR_MEMORY]	; 데이터를 읽었으니까 데이터 주소를
	mov ebx, [CLUSTER_BYTES]	; 읽은 만큼 증가시켜준다.(클러스터의 바이트수)
	add ax, bx	
	mov [LDR_MEMORY], ax	; 데이터 읽을만큼 LDR_MEMORY를 증가.

	ret

	; FAT 테이블에서 다음 클러스터를 찾자.
FAT_SEARCH:
	; FAT 리스트
	; 0x9000 에 임시로 FAT테이블을 읽어서 저장해 놓자.
	mov ax, 0x9000	; ES 세그먼트
	mov [READ_MEMORY], ax

	; FAT 테이블의 클러스터는 4바이트 이루어져 있으므로
	; 512 / 4 = 128 . 한 섹터당 128개의 클러스터로 이루어져 있다.
	; 현재 클러스터의 FAT 테이블에서 위치를 찾아보자.
	; 현재클러스터 / 128 은 FAT에서 클러스터 위치.
	mov al, 1
	mov [READ_SIZE], al	; FAT 테이블은 섹터 하나만 읽자.
	mov eax, [CURRENT_CLUSTER]
	mov bx, [BPB_BYTE_PER_SECTOR]
	shr bx, 2	; 4로 나누자.
	xor edx, edx
	div ebx	; 128로 AX를 나누자.
	push edx	; AX를 128로 나눈 나머지는 DX로.
	add eax, [FAT1] ; 나눈 몫에 FAT테이블 위치를 더한다.
	mov [READ_SECTOR], eax

	; FAT 테이블을 읽자.
	call READ_DISK	; 데이터를 읽는다.

	pop edx	; 나눠서 나머지 스택에서 빼내고.
	mov esi, 0x9000	;
	sal edx, 2	; 클러스터 X 4 = 클러스터 메모리 위치.
	add esi, edx	; 0x9000 + 클러스터 메모리 위치.
	mov eax, [esi]	; eax에 현재 클러스터의 다음 클러스터값을 읽자.

	cmp eax, 0x0FFFFFFF	; 끝이라면
	je FAT_END			; al에 0x01 실패!
	
	mov [CURRENT_CLUSTER], eax	; 다음 클러스터를 저장.
	mov al, 0			; al에 0x00 성공!
	ret

FAT_END:
	mov al, 1
	ret

READ_DISK:
	;pusha				; 모든 레지스터를 스택에 넣는다.
DISK_RESET:
	; Disk Address Packet (DAP)
	xor ax,ax								;INT 13h AH=00h: Reset Disk Drive
	mov dl,BYTE 0x80				;DL = Drive Number
	int 0x13
	jc DISK_RESET
	mov	al, 0x10 ; 크기
	mov	[0x500], al

	mov al, [READ_SIZE]	; 읽을 섹터 수
	mov	[0x502], ax
	mov ax, [READ_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, 0x80

	int 0x13
	;popa
	ret

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					;호출 한곳으로 리턴.

; 변수를 선언하자.
DRIVE		equ 0x0550
ROOT_ENTRY	equ 0x0551
FAT1		equ 0x0555
CLUSTER_BYTES	equ 0x0559
CURRENT_CLUSTER	equ 0x055D
READ_MEMORY		equ 0x0561
READ_SIZE		equ 0x0563
LDR_MEMORY		equ 0x0564
READ_SECTOR		equ 0x0566

OS_LDR_FILENAME db "OS_LDR  SYS",0

	times 510-($-$$) db 0x00
	dw	0xAA55


휴~ 512 바이트에 맞추려고 아주 삽질좀 했다. 동작???

동작도 잘된다!!!


LOAD MY KERNEL


스트레스 만땅 받았는데 동작 되니 후련하다. CHS 모드에서 왜 동작 안되었는지는 모르겠다.

BPB의 트랙, 헤드 정보가 잘못 된 건지… 여튼 원인은 밝혀 내지 못하고 LBA로 처리해서 되긴하지만 좀 뒤 안 닦은듯한 느낌이다.

성공은 했으나, 기쁘지 않는 기분….



이제 보호모드? 로 진입하고 실 커널 호출 하는 부분을 진행해야 한다.. 막막하다…

 

'프로그래밍 > OS 만들기' 카테고리의 다른 글

OS 만들기 #11 - 리얼모드 & 보호모드  (0) 2013.08.14
OS 만들기 #10  (0) 2013.08.14
OS 만들기 #8 - 부트로더  (0) 2013.08.14
OS 만들기 #7 - FAT32  (1) 2013.08.14
OS 만들기 #6 - MBR  (0) 2013.08.14

자!! FAT32 파일 시스템 분석해서 파일 찾아서 읽어 오는 것까지 다 했다.!! 이제 부트로더에서 파일 찾아서 메모리에 로딩 시키는 일만 남았다. 참 험난한 길이었다. 블로그에 글로 적는 것도 험난했고, 공부하는 것도 험난했다. 뭐 이제 코딩만 남았으니~~

부트로더는 또 어떻게 만드냐!~~~ 아~ 험난하다!!

흠… OS 하나 만들기 정말 힘들다.

우선, 부트로더는 NASM 으로 컴파일 하고 나머지 커널은 Visual Studio C++ 2010에서 컴파일 할 생각이다. 부트로더에서 바로 KERNEL.SYS 파일을 읽어 0x10000에 로딩하고 실행시킬 생각이다.

하지만, 안 된단다.. Visual studio 2010에서 커널 작성 컴파일 방법을 검색 하던 중 부트로더 => KERNEL.SYS (Visual Studio C++)로 실행 시킬 수 없다고 한다!!!!!!!!!


왜!!!!!!!!!! 왜 왜! ??? 왜 안되냐고!~~~~~~~~~~~~~~~~~~


OS 개발 안 해!!!!

ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ

에고고고고..


실은 부트로더 에서 KERNEL.SYS를 호출 해서 실행 시킬 수는 있단다. 다만 리얼 모드 에서 보호 모드로 전환 하고 실행 해야 한단다. 리얼 모드는 뭐고 보호 모드가 뭐길래? 안 된다는 것이냐??? 뭐 쏼라 쏼라 영어를 보니 16bit , 32bit가 언급된다. 아마 리얼 모드는 16비트이고 보호 모드는 32비트 인 모양이다. Visual Studio C++ 은 컴파일러가 32비트만 컴파일 된다고 한다. 16비트 컴파일 하려면 아~~~주 낮은 고대 유물과 비슷한 버전의 Visual Studio C++를 사용 하라고 한다.

아놔!~~~

OS만들려다 사람 잡겄다!!!

에고.. 보호모드 로 전환하고 KERNEL.SYS 호출하지 모… 근데 보호모드 예제 코드들을 보니..라인수가 장난이 아니다. 부트로더 512byte로는 어림도 없겠다. 아~~~~~ 미치겠다. VC++에서 인라인 어셈으로 처리해서 KERNEL.SYS 엔트리 포인터 위치에 보호모드 코드 작성 후 실제 커널 코드로 들어가는 부분 방법으로 작성해야 겠다.

아~~ 이 방법도 쉽지 않다. 쉽지 않아. 어렵다!!! 어렵다!!! 모르고 시작 할땐 의욕이 넘쳤는데 이젠 점점 하기가 싫어진다.

그냥 세 분류로 작성 하련다… 생각대로 하기에는 지친다..어렵고..

..

부트로더, 커널로더, 커널  이렇게 세 분류로 계획했다.


메모리 영역

구분

파일

역활

0x7C00

부트로더

BOOTLOADER

- 커널로더를 로드 하고 실행한다.

0x8000

커널로더

OS_LDR.SYS

- 커널 로드한다.
- 보호모드로 전환한다.
- 커널을 실행한다.

0x10000

커널

BARAM.SYS - 커널 실제 동작


꺼림직한 구조지만, 그냥 이렇게 타협?을 봤다. 커널로더에서 공부 할게 많지만 우선은 부트로더가 제일 문제다. ㅠㅠ 아직까지 부트로더에서 헤매고 있다니 ㅠㅠ




- FAT32 부트로더


음…기존 코드에서 BPB 영역(FAT32 정보) 부분만 더 붙여 주고 OS_LDR.SYS 파일 찾아서 로드하고 실행 하는 코드를 만들어야 한다. Baram 이미지 파일내의 0x10000 에서 각 값을 구해서 직접 입력했다.


org 0x7C00
bits 16

BOOTLOADER_ENTRY:
	;; start로 이동한다. (BPB의 영역의 3바이트는 점프 명령 코드로 이용한다. )
	jmp BOOTLOADER_MAIN
	nop ; 코드에서 2바이트 밖에 안되서 nop 1바이트 추가.

;; FAT32 파일시스템 구조
BPB_OEM: db "EOS Boot"				; 8 바이트 OEM 이름..
BPB_BYTE_PER_SECTOR:	dw 512		; 2바이트 섹터당 바이트 크기.
BPB_SECTOR_PER_CLUSTER: db 0x02		; 클러스터당 섹터 갯수
BPB_RESERVED_SECTOR:	dw 0x186E   ;  예약 섹터 갯수
BPB_FAT_NUM:			db 0x02		; FAT 갯수 (FAT1, FAT2 의 카피본을 두므로 보통 2개)
BPB_ROOT_ENTRY_NUMBER:	dw 0x0000	; 루트 디렉토리에 최대 디렉토리 포함할 수 있는 갯수
BPB_FAT16_SECTORS:		dw 0x0000	; FAT16일 때 총 섹터 갯수
BPB_MEDIA_TYPE:			db 0xF8		; 장치 타입 (0xF8 는 하드디스크)
BPB_FAT16_SIZE:			dw 0x0000	; FAT16일때 FAT테이블 크기
BPB_SECTOR_PER_TRACK:	dw 0x003F	; 트랙당 섹터 갯수
BPB_HEADS:				dw 0x00FF 	; 헤드 갯수
BPB_HIDDEN_SECTOR:		dd 0x00000080	; 숨겨진 섹터 갯수
BPB_FAT32_SECTORS:		dd 0x0003E800	; FAT32 파일시스템일 때 총 섹터 갯수
BPB_FAT16_SIZE:			dd 0x000003C9	; FAT32일때 FAT테이블 크기
BPB_EXTENSION_FLAGS:	dw 0x0000		; 확장 플래그 ( 0-3 : 활성화 FAT )
BPB_FILESYSTEM_VER:		dw 0x0000		; FAT32의 버젼
BPB_ROOT_ENTRY_CLUSTER: dd 0x00000002	; 데이터 시작 클러스터 위치
BPB_FILESYSTEM_INFO:	dw 0x0001		; 파일시스템 정보 위치
BPB_BACKUP_BOOT_SECTOR: dw 0x0006		; 백업 부트 섹터 위치
BPB_RESERVED:							; 예약된 정보 
						dd 0x00
						dd 0x00
						dd 0x00
BS_DRIVE:							; 바이오스콜(0x13) 드라이브 정보
						db 0x80
BS_RESERVED1:						; 예약
						db 0x00
BS_BOOT_SIGNATURE:					; 부트 서명 (0x29)
						db 0x29		;
BS_VOLUME_ID:						; 볼륨 시리얼 번호
						dd 0xC1C286C
BS_VOLUME_LABEL:					; 볼륨 레이블명
						dd 0x4E4F204E
						dd 0x414D4520
						dw 0x2020
						db 0x20
BS_FILESYSTEM_TYPE:					; 파일 시스템 이름
						dd 0x46415433
						dd 0x32202020

BOOTLOADER_MAIN:
	cli
	;; CS, DS, ES, & SS을 초기화 하자.
	xor eax, eax
	mov ds, ax
	mov ss, ax
	mov es, ax


제길… 탭을 넣어서 보기 좋게 정리 했더니 여기에 붙여 넣기 하니 저리 되네.. 아 모르겠다.. 그냥 넘어가자.

스택 위치를 잡아야 하는데 0x8000에 커널 로더 OS_LDR.SYS를 로딩한다. 그러니까 0x8000으로 스택 주소를 잡는다. 뭐 스택은 아래로 감소하면서 포인터가 위치하니까 문제는 없을 것 같다. 그리고 부트로드 드라이버도 변수 하나 생성해서 저장해 주자!!


mov sp, 0x8000     ; 스택을 잡자
mov bp, sp           ; bp 도 0x8000으로 잡자.
mov [DRIVE], dl    ; 현재 드라이브 저장하자.


음…이제 FAT32 접근해야 하는데…..


1. 루트 디렉토리 엔트리 위치를 구하자.
2. FAT 테이블 위치를 구하자.
3. 클러스터당 몇 바이트 인지 구하자.
4. 현재 클러스터 위치를 저장하자.
5. 루트 디렉토리 엔트리 가서 파일명을 읽어서 OS_LDR.SYS를 찾는다.
6. OS_LDR.SYS의 데이터 클러스터로 이동해서 읽는다.
7. FAT 테이블 위치로 가서 OS_LDR.SYS 데이터가 더 있는지 확인한다.
8. 6,7번을 반복한다.
9. OS_LDR.SYS를 실행한다. (이동)


위와 같이 한번 설계해 봤다. 이 구조로 한번 코딩 해 봐야지~


	; 루트 디렉토리 엔트리 위치를 구하자.
	; 루트 디렉토리 엔트리 = (FAT 갯수 * FAT 테이블크기) + 예약 섹터 + 히든 섹터
	mov al, [BPB_FAT_NUM]	
	mov ebx, [BPB_FAT32_SIZE]
	mul ebx		; AL * EBX = EAX
	xor ebx, ebx ; EBX를 0으로 초기화 하자.
	mov bx, [BPB_RESERVED_SECTOR] ; 예약 섹터를 bx 저장.
	add eax, ebx	; EAX = EAX + EBX
	mov ebx, [BPB_HIDDEN_SECTOR] ; 히든 섹터를 ebx로 저장.
	add eax, ebx	; EAX = EAX + EBX
	mov [ROOT_ENTRY], eax

	; FAT1 위치를 찾자.
	; FAT1 = 예약 섹터 + 히든 섹터
	xor eax, eax	; eax는 0으로 초기화 한다.
	mov ax, [BPB_RESERVED_SECTOR] ; 예약 섹터를 ax 저장.
	add eax, ebx	; ebx 는 이미 히든 섹터가 저장되어 있다.
	mov [FAT1], eax

	; 클러스터를 바이트로 변환하자.
	; 클러스터 총 바이트 = (섹터당 바이트 * 클러스터당 섹터 갯수)
	xor ebx, ebx
	mov ax, [BPB_BYTE_PER_SECTOR]
	mov bl, [BPB_SECTOR_PER_CLUSTER]
	mul bx	; EAX = AX * BX  총 바이트를 구했다.
	mov [CLUSTER_BYTES], eax
	
	; 현재 위치 클러스터를 저장하자.
	mov eax, [BPB_ROOT_ENTRY_CLUSTER]
	mov [CURRENT_CLUSTER], eax

; 변수를 선언하자.
DRIVE		db 0x00
ROOT_ENTRY	dd 0x00
FAT1		dd 0x00
CLUSTER_BYTES	dd 0x00
CURRENT_CLUSTER dd 0x00


1,2,3,4번을 구현했다. 여기까지는 순조롭다.

이제 루트 디렉토리 엔트리 위치를 로딩해서 OS_LDR.SYS를 찾아야 한다. 파일 로딩하는 함수를 만들어야 하는데~~


READ_SECTOR:
	pusha				; 모든 레지스터를 스택에 넣는다.
	mov ah, 0x02		; 디스크 읽기 모드
	mov al, 5			; 1 섹터만 읽는다.
	mov ch, 0			; 트랙은 0번 트랙
	mov cl, 2			; 읽을 섹터는 2번째 섹터
	mov dh, 0			; 헤드는 0번 헤드
	mov dl, [DRIVE_NUM] ; 읽을 드라이브 번호
	mov bx, 0x1000		; 0x9000 메모리에 커널 이미지 올린다.
	mov es, bx
	mov bx, 0x0000
	int 0x13			; 읽어라!

	popa
	ret	


루트 디렉토리 엔트리 위치는 섹터 번호로 기록되어 있다. 이걸 트랙 하고 헤드,섹터 이렇게 다시 재 계산 해야 한다.

트랙, 헤드를 구하는 식은 검색해 보니 이렇게 한다고 한다.


트랙 = 총섹터 / (헤드 갯수 * 트랙당 섹터수)
헤드 = (총섹터/트랙 당 섹터수) % 헤드 갯수
섹터 = (총섹터 % 트랙 당 섹터) + 1


식을 보면서 생각해 보니 대충 그림이 그려진다. 그렇다고 이걸 어셈으로 바꾸긴 힘들었다. 이해와 구현의 괴리감…인터넷에 있는 걸로 만들었다.^^


	; 헤드, 트랙, 섹터로 재 계산해서 저장하자.
	; 트랙 = 총섹터 / (헤드 갯수 * 트랙당 섹터수)
	; 헤드 = (총섹터/트랙 당 섹터수) % 헤드 갯수
	; 섹터 = (총섹터 % 트랙 당 섹터) + 1
	; EAX 는 총섹터 값이 있다.
CONVERT_CHS:
	xor dx, dx	; dx를 0으로 초기화 하자.
	mov cx, [BPB_SECTOR_PER_TRACK]
	div cx	; AX / CX = AX , AX % CX = DX

	inc dl	; 나머지 + 1 = 섹터다.
	mov [SECTOR], dl

	xor dx, dx	; dx를 0으로 초기화 하자. ax는 총섹터/트랙 당 섹터수 값이 있다.
	mov cx, [BPB_HEADS]
	div cx	; (총섹터/트랙 당 섹터수) / 헤드수 = 트랙, (총섹터/트랙 당 섹터수) % 헤드수 = 헤드

	mov [HEAD], dl
	mov [TRACK], al
	ret


위와 같이 만들었다. 이제 섹터 읽는 부분을 구현해야 겠다~


READ_SECTOR:
	pusha				; 모든 레지스터를 스택에 넣는다.
	mov ah, 0x02		; 디스크 읽기 모드
	mov al, [READ_SIZE]	; 읽을 섹터
	mov ch, [TRACK]		; 트랙
	mov cl, [SECTOR]	; 섹터
	mov dh, [HEAD]		; 헤드
	mov dl, [DRIVE_NUM] ; 읽을 드라이브 번호
	mov bx, [READ_MEMORY]	; 읽는 데이터 저장될 메모리
	mov es, bx
	mov bx, 0x0000
	int 0x13			; 읽어라!

	popa
	ret	


아주 쉽게 구현되었다. ㅎㅎ

이제 5번을 구현해 봐야지!~


FILE_FIND:
	; 파일이름을 찾자. 
	mov ax, [0x9000]	; 0x9000에 루트 디렉토리 엔트리 데이터 존재.

FIND_LOOP:
	add ax, 0x20		; 첫 데이터는 C:\ 데이터므로 넘어간다.

	// 파일 이름을 비교한다.
	mov si, ax	
	mov di, OS_LDR_FILENAME
	mov cx, 11
	repe cmpsb

	jnz FIND_LOOP

	; 파일을 찾았다.!!! ^^

	; 데이터 클러스터 위치를 구하자.
	mov ax, [si+9]	; 클러스터 상위 2바이트
	push ax
	mov ax, [si+15]	; 클러스터 하위 2바이트
	push ax
	pop eax
	mov [CURRENT_CLUSTER], eax


어셈 문법 찾아보면서 하려니 너무 진도가 더디다. 좀 쉬어야 겠다… 머리 쥐나겠다.

….

;; creator : cyj (mangg@manggong.org)
;; date : 2012. 4. 17
;; desc : BPB bootloader on FAT32
;;        1. FAT32를 분석한다.
;;        2. OS_LDR.sys파일을 FAT32 파일 시스템에서 찾아서 0x8000 번지로 로드한다.
;;        3. OS_LDR.sys데이터가 있는 0x8000으로 이동한다.

org 0x7C00
bits 16

BOOTLOADER_ENTRY:
	;; start로 이동한다. (BPB의 영역의 3바이트는 점프 명령 코드로 이용한다. )
	jmp BOOTLOADER_MAIN
	nop ; 코드에서 2바이트 밖에 안되서 nop 1바이트 추가.

;; FAT32 파일시스템 구조
BPB_OEM: db "EOS Boot"				; 8 바이트 OEM 이름..
BPB_BYTE_PER_SECTOR:	dw 512		; 섹터당 바이트 크기.
BPB_SECTOR_PER_CLUSTER: db 0x02		; 클러스터당 섹터 갯수
BPB_RESERVED_SECTOR:	dw 0x186E   ;  예약 섹터 갯수
BPB_FAT_NUM:			db 0x02		; FAT 갯수 (FAT1, FAT2 의 카피본을 두므로 보통 2개)
BPB_ROOT_ENTRY_NUMBER:	dw 0x0000	; 루트 디렉토리에 최대 디렉토리 포함할 수 있는 갯수
BPB_FAT16_SECTORS:		dw 0x0000	; FAT16일 때 총 섹터 갯수
BPB_MEDIA_TYPE:			db 0xF8		; 장치 타입 (0xF8 는 하드디스크)
BPB_FAT16_SIZE:			dw 0x0000	; FAT16일때 FAT테이블 크기
BPB_SECTOR_PER_TRACK:	dw 0x003F	; 트랙당 섹터 갯수
BPB_HEADS:				dw 0x00FF 	; 헤드 갯수
BPB_HIDDEN_SECTOR:		dd 0x00000080	; 숨겨진 섹터 갯수
BPB_FAT32_SECTORS:		dd 0x0003E800	; FAT32 파일시스템일 때 총 섹터 갯수
BPB_FAT32_SIZE:			dd 0x000003C9	; FAT32일때 FAT테이블 크기
BPB_EXTENSION_FLAGS:	dw 0x0000		; 확장 플래그 ( 0-3 : 활성화 FAT )
BPB_FILESYSTEM_VER:		dw 0x0000		; FAT32의 버젼
BPB_ROOT_ENTRY_CLUSTER: dd 0x00000002	; 데이터 시작 클러스터 위치
BPB_FILESYSTEM_INFO:	dw 0x0001		; 파일시스템 정보 위치
BPB_BACKUP_BOOT_SECTOR: dw 0x0006		; 백업 부트 섹터 위치
BPB_RESERVED:							; 예약된 정보 
						dd 0x00
						dd 0x00
						dd 0x00
BS_DRIVE:							; 바이오스콜(0x13) 드라이브 정보
						db 0x80
BS_RESERVED1:						; 예약
						db 0x00
BS_BOOT_SIGNATURE:					; 부트 서명 (0x29)
						db 0x29		;
BS_VOLUME_ID:						; 볼륨 시리얼 번호
						dd 0xC1C286C
BS_VOLUME_LABEL:					; 볼륨 레이블명
						dd 0x4E4F204E
						dd 0x414D4520
						dw 0x2020
						db 0x20
BS_FILESYSTEM_TYPE:					; 파일 시스템 이름
						dd 0x46415433
						dd 0x32202020

BOOTLOADER_MAIN:
	cli
	;; CS, DS, ES, & SS을 초기화 하자.
	xor eax, eax
	mov ds, ax
	mov ss, ax
	mov es, ax

	mov sp, 0x8000  ; 스택포인터를 잡자.
	mov bp, sp		; bp도 0x8000으로 잡자.
	sti

	mov [DRIVE], dl	; 현재 드라이브를 저장하자.

	; 루트 디렉토리 엔트리 위치를 구하자.
	; 루트 디렉토리 엔트리 = (FAT 갯수 * FAT 테이블크기) + 예약 섹터 + 히든 섹터
	mov al, [BPB_FAT_NUM]	
	mov ebx, [BPB_FAT32_SIZE]
	mul ebx		; AL * EBX = EAX
	xor ebx, ebx ; EBX를 0으로 초기화 하자.
	mov bx, [BPB_RESERVED_SECTOR] ; 예약 섹터를 bx 저장.
	add eax, ebx	; EAX = EAX + EBX
	mov ebx, [BPB_HIDDEN_SECTOR] ; 히든 섹터를 ebx로 저장.
	add eax, ebx	; EAX = EAX + EBX
	mov [ROOT_ENTRY], eax

	; FAT1 위치를 찾자.
	; FAT1 = 예약 섹터 + 히든 섹터
	xor eax, eax	; eax는 0으로 초기화 한다.
	mov ax, [BPB_RESERVED_SECTOR] ; 예약 섹터를 ax 저장.
	add eax, ebx	; ebx 는 이미 히든 섹터가 저장되어 있다.
	mov [FAT1], eax

	; 클러스터를 바이트로 변환하자.
	; 클러스터 총 바이트 = (섹터당 바이트 * 클러스터당 섹터 갯수)
	xor ebx, ebx
	mov ax, [BPB_BYTE_PER_SECTOR]
	mov bl, [BPB_SECTOR_PER_CLUSTER]
	mul bx	; EAX = AX * BX  총 바이트를 구했다.
	mov [CLUSTER_BYTES], eax

	mov eax, 0x0800
	mov [LDR_MEMORY], eax
		
	; 현재 위치 클러스터를 저장하자.
	mov eax, [BPB_ROOT_ENTRY_CLUSTER]
	mov [CURRENT_CLUSTER], eax

	; 0x9000 에 임시로 루트 디렉토리 엔트리를 읽어서 저장해 놓자.
	mov ax, 0x0900	; ES 세그먼트
	mov [READ_MEMORY], ax

FILE_LIST:
	mov ebx, [ROOT_ENTRY]	; 루트 디렉토리 섹터 위치.
	mov eax, [CURRENT_CLUSTER]
	sub eax, 2
	add eax, ebx

	call CONVERT_CHS	; 헤드, 트랙, 섹터로 변환한다.
	call READ_SECTOR	; 데이터를 읽는다.

FILE_FIND:
	; 파일이름을 찾자. 
	mov ax, [0x9000]	; 0x9000에 루트 디렉토리 엔트리 데이터 존재.

FIND_LOOP:
	add ax, 0x20		; 첫 데이터는 C:\ 데이터므로 넘어간다.

	; 파일 이름을 비교한다.
	mov si, ax	
	mov di, OS_LDR_FILENAME
	mov cx, 11
	repe cmpsb

	mov ebx, [CLUSTER_BYTES]
	add ebx, 0x9000
	cmp eax, ebx
	je NO_FIND

	jnz FIND_LOOP

	; 파일을 찾았다.!!! ^^

	; 데이터 클러스터 위치를 구하자.
	mov ax, [si+9]	; 클러스터 상위 2바이트
	push ax
	mov ax, [si+15]	; 클러스터 하위 2바이트
	push ax
	pop eax
	mov [CURRENT_CLUSTER], eax

LOOP_DATA_READ:
	call DATA_READ	; 데이터 클러스터에서 데이터 읽기
	call FAT_SEARCH	; FAT 테이블에서 다음 클러스터를 찾는다.
	cmp al, 0x01	; al에 다음 클러스터가 있으면 0x00, 없으면 0x01 
	je RUN_LDR		; 다음 클러스터가 없으면 OS_LDR 실행하러 가자.
	jmp LOOP_DATA_READ	; 다음 데이터 클러스터 읽으로 가자.

RUN_LDR:
	jmp 0x8000		; 0x8000(OS_LDR.SYS) 실행하자.

	; 루트 디렉토리 엔트리에서 OS_LDR.SYS를 못 찾으면
	; 루트 디렉토리 엔트리의 다음 클러스터를 찾아서
	; 파일 목록을 비교 하러간다.
NO_FIND:
	call FAT_SEARCH	; FAT 테이블에서 다음 클러스터를 찾자.
	cmp al, 0x00	; 다음 클러스터를 찾으면 0x00 
	je FILE_FIND	; 다시 파일이름 찾으로 가자.
	jmp $			; 다음 클러스터가 없으면 무한루프.

	; 데이터 클러스터에서 데이터를 읽어서
	; LDR_MEMORY에 로딩하자.
DATA_READ:
	mov ax, [LDR_MEMORY]	
	mov [READ_MEMORY], ax	; READ_MEMORY에 LDR_MEMORY 복사하자. (세그먼트임을 기억하자)
	mov al, [BPB_SECTOR_PER_CLUSTER]
	mov [READ_SIZE], al	; 클러스터(섹터 2) 만큼 읽자.
	mov ebx, [ROOT_ENTRY]	; 루트 디렉토리 섹터 위치.
	mov eax, [CURRENT_CLUSTER] ; 현재 클러스터.
	sub eax, 2		; 클러스터가 2부터 시작한다고 하니 2를 뺀다.
	add eax, ebx	; EAX = EAX-EBX. EAX는 루트디렉토리부터 현재 클러스터(-2) 더한값.

	call CONVERT_CHS	; 헤드, 트랙, 섹터로 변환한다.
	call READ_SECTOR	; 데이터를 읽는다.

	mov ax, [LDR_MEMORY]	; 데이터를 읽었으니까 데이터 주소를
	mov ebx, [CLUSTER_BYTES]	; 읽은 만큼 증가시켜준다.(클러스터의 바이트수)
	shr ebx, 4	; 세그먼트 계산법에 의해 4바이트 빼 버린다.
	add ax, bx	
	mov [LDR_MEMORY], ax	; 데이터 읽을만큼 LDR_MEMORY를 증가.

	ret

	; FAT 테이블에서 다음 클러스터를 찾자.
FAT_SEARCH:
	; FAT 리스트
	; 0x9000 에 임시로 FAT테이블을 읽어서 저장해 놓자.
	mov ax, 0x0900	; ES 세그먼트
	mov [READ_MEMORY], ax

	; FAT 테이블의 클러스터는 4바이트 이루어져 있으므로
	; 512 / 4 = 128 . 한 섹터당 128개의 클러스터로 이루어져 있다.
	; 현재 클러스터의 FAT 테이블에서 위치를 찾아보자.
	; 현재클러스터 / 128 은 FAT에서 클러스터 위치.
	mov al, 1
	mov [READ_SIZE], al	; FAT 테이블은 섹터 하나만 읽자.
	mov eax, [CURRENT_CLUSTER]
	mov bx, [BPB_BYTE_PER_SECTOR]
	shr bx, 2	; 4로 나누자.
	xor edx, edx
	div ebx	; 128로 AX를 나누자.
	push edx	; AX를 128로 나눈 나머지는 DX로.
	add eax, [FAT1] ; 나눈 몫에 FAT테이블 위치를 더한다.

	; FAT 테이블을 읽자.
	call CONVERT_CHS	; 헤드, 트랙, 섹터로 변환한다.
	call READ_SECTOR	; 데이터를 읽는다.

	pop edx	; 나눠서 나머지 스택에서 빼내고.
	mov esi, 0x9000	;
	sal edx, 2	; 클러스터 X 4 = 클러스터 메모리 위치.
	add esi, edx	; 0x9000 + 클러스터 메모리 위치.
	mov eax, [esi]	; eax에 현재 클러스터의 다음 클러스터값을 읽자.

	cmp eax, 0x0FFFFFFF	; 끝이라면
	jz FAT_END			; al에 0x01 실패!
	
	mov [CURRENT_CLUSTER], eax	; 다음 클러스터를 저장.
	mov al, 0			; al에 0x00 성공!
	ret

FAT_END:
	mov al, 1
	ret

	; 헤드, 트랙, 섹터로 재 계산해서 저장하자.
	; 트랙 = 총섹터 / (헤드 갯수 * 트랙당 섹터수)
	; 헤드 = (총섹터/트랙 당 섹터수) % 헤드 갯수
	; 섹터 = (총섹터 % 트랙 당 섹터) + 1
	; EAX 는 총섹터 값이 있다.
CONVERT_CHS:
	xor dx, dx	; dx를 0으로 초기화 하자.
	mov cx, [BPB_SECTOR_PER_TRACK]
	div cx	; AX / CX = AX , AX % CX = DX

	inc dl	; 나머지 + 1 = 섹터다.
	mov [SECTOR], dl

	xor dx, dx	; dx를 0으로 초기화 하자. ax는 총섹터/트랙 당 섹터수 값이 있다.
	mov cx, [BPB_HEADS]
	div cx	; (총섹터/트랙 당 섹터수) / 헤드수 = 트랙, (총섹터/트랙 당 섹터수) % 헤드수 = 헤드

	mov [HEAD], dl
	mov [TRACK], al
	ret
	
READ_SECTOR:
	pusha				; 모든 레지스터를 스택에 넣는다.
	mov ah, 0x02		; 디스크 읽기 모드
	mov al, [READ_SIZE]	; 읽을 섹터 수
	mov ch, [TRACK]		; 트랙
	mov cl, [SECTOR]	; 섹터
	mov dh, [HEAD]		; 헤드
	mov dl, [DRIVE] ; 읽을 드라이브 번호
	mov bx, [READ_MEMORY]	; 읽는 데이터 저장될 메모리
	mov es, bx
	mov bx, 0x0000
	int 0x13			; 읽어라!

	popa
	ret	

; 변수를 선언하자.
DRIVE		db 0x00
ROOT_ENTRY	dd 0x00
FAT1		dd 0x00
CLUSTER_BYTES	dd 0x00
CURRENT_CLUSTER dd 0x00
READ_MEMORY		dw 0x00
READ_SIZE		db 0x00
SECTOR			db 0x00
TRACK			db 0x00
HEAD			db 0x00
LDR_MEMORY		dw 0x00

OS_LDR_FILENAME db "OS_LDR  SYS",0

	times 510-($-$$) db 0x00
	dw	0xAA55


쉬는 동안 6,7,8,9 구현해 봤다. 하고 보니 완전 길다~  컴파일 될지도 모르겠고 동작 되는지도 모르겠다. 그냥 말 그대로 그냥 구현했다.

error : TIMES value –13 is negative


제길 … 컴파일 안 된다. 요건 왜 이러냐..


510-($-$$) 요거 때문에 생기는 에러란다. (현재위치 – 첫 위치) 가 510 바이트를 넘는다는 거지~~ 512… 아니…이것보다는 적은 공간에 작성하려니 너무 적다. 아 … 어떻게 해야 하나…


변수를 저렇게 잡지 않고 메모리 영역 하나 잡아서 선언하는 방법을 인터넷에서 검색하다가 찾았다.


DRIVE		equ 0x500
ROOT_ENTRY	equ 0x501
FAT1		equ 0x505
CLUSTER_BYTES	equ 0x509
CURRENT_CLUSTER	equ 0x50D
READ_MEMORY		equ 0x511
READ_SIZE		equ 0x513
SECTOR			equ 0x514
TRACK			equ 0x515
HEAD			equ 0x516
LDR_MEMORY		equ 0x517


요렇게 하고 컴파일 해보니 호~~~ 된다. 동작은 될련지는 미지수다…내가 만든 코드지만 솔직히 못 믿겠다. 문법도 맞는지도….그냥 막코딩!!!!

검증을 하기 위해서 전번에 만들어 두었던 코드로 테스트 해봐야 겠다.


ORG 0x8000			; 0x8000 메모리에서 실행되므로 0x8000 으로 주소정렬
BITS 16

	cli				; 인터럽트 발생안되게 설정
	xor ax,ax		; ax 0으로 초기화 한다. ax xor ax 어차피 0이다.
	mov ds, ax		; ds 세그먼트 레지스터를 0 으로 초기화 한다.
	mov es, ax		; es 세그먼트 레지스터를 0 으로 초기화 한다.
	mov ss,ax
	mov sp,0xffff
	sti				; 인터럽트 발생 설정

	lea si, [LOAD_MSG]	; LOAD_MSG 위치 주소
	call PRINT			; 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					;호출 한곳으로 리턴.

LOAD_MSG:
	db "LOAD MY KERNEL", 0x00

	times 510-($-$$) db 0x00
	dw	0xAA55


요걸 OS_LDR.SYS 이름으로 컴파일 한다.

nasm –fbin –o OS_LDR.SYS OS_LDR.ASM


파티션 부트로더에 컴파일 한 코드 붙여 넣고, 이걸 다시 [제어판][관리 도구][컴퓨터관리] 가서 VHD 연결 해서 드라이브로 연결해서 OS_LDR.SYS를 넣었다. 잘 될까?

 

'프로그래밍 > OS 만들기' 카테고리의 다른 글

OS 만들기 #10  (0) 2013.08.14
OS 만들기 #9 - 부트로더  (0) 2013.08.14
OS 만들기 #7 - FAT32  (1) 2013.08.14
OS 만들기 #6 - MBR  (0) 2013.08.14
OS 만들기 #5 - 부트로더  (0) 2013.08.14

- FAT32

MBR에 기록된 0x10000 위치를 헥사뷰어로 보니 뭔가 Windows 7에서 포맷하면서 써 놨다. 부트레코드 인가 보다. 음. 내가 알 수 없는 부분이라 불안하다. Windows 7 에서 만든 MBR 과 이 코드를 검색해 봐야 겠다. 있을진 모른겠다.


http://thestarman.pcministry.com/asm/mbr/W7MBR.htm

http://thestarman.pcministry.com/asm/mbr/W7VBR.htm


이 사이트에 MBR과 VBR(Volume Boot Record), BPB(Bios Parameter Block) 이라고 하는 0x10000 부트레코드 코드가 다 있다. 오! 역시 인터넷은 정보의 바다다!! 만쉐!!


에고.. 영어라 모르겠다. VBR 같은 경우 NTFS로 쏼라 쏼라 한다. 난 FAT32인데?? 음…이 사이트 기웃 거리다가 FAT32 찾았다!!

http://thestarman.pcministry.com/asm/mbr/ntFAT32BR.htm


내 부트레코드랑 틀리다. 참고만 해야 겠다. 대충 통빡으로 보면 앞 3자리는 jump 코드란다. 그 다음은 BPB 영역(http://thestarman.pcministry.com/asm/mbr/MSWIN41.htm#BPB)이라고 해서 클릭해 보니… 와우 이건 모냐???


FAT32 정보네~~ 아고 FAT32 정보가 어디 있나 했더니 부트로더랑 FAT32 정보가 포함되어 있네? 흠…공부해야겠다.

우선 복습하는 차원에서 MBR의 파티션 정보는 다음과 같다.



저번에 포스팅 했던 내용과 같다. 그리고 FAT32 구조는.



위와 같다. 위 그림에서 Volume ID 이 부분이 0x10000 위치의 부트코드가 있는 위치이고 그 다음이 Reserved Sector, FAT#1, FAT#2, Files & 디렉토리가 일련의 순서대로 구성되어 있다. 부트로더와 FAT#1 사이에는 Reserved Sector가 존재한다. 왜 들어가 있는지 모르겠다. 그리고 FAT#1 과 FAT#2가 있는데 파일이 하드디스크의 어느 부분에 저장되어 있는지 위치를 기록하는 공간(Data영역에서 어느 위치)이다. 두 개나? 있는데 하나는 백업용이란다. FAT#1이 지워졌을 때 복구 하기 위해 있다고 한다.  Data 영역(파일과 디렉토리) 영역에는 파일 목록과 실제 파일 데이터가 기록된다.

파일이 FAT32에서 어떻게 읽고 쓰는지는 요거 BPB 라는 놈 분석해 보고 알아보자. (아 ..하기 싫어..)



잊어 버릴 것 같아서 직접 표로 작성했다.

부트로더 0x03부터 0x59 까지 FAT 정보가 들어갔다. FAT12/16/32가 서로 유사하다고 한다. 뭐 난 FAT32 만 할꺼니 딴 건 신경 안 쓰기로 했다.


모르는 용어가 나온다. 나머지야 다 유추해 볼만 한데 클러스트 라는 용어는 생소한다.


PC의 저장기술 측면에서의 클러스터는 하드디스크 위에 파일을 저장하는 논리적 단위이며, 컴퓨터의 운영체계에 의해 관리된다.
파일이 하드디스크에 저장되면 적어도 하나 이상의 클러스터를 차지하게 되며, 아주 커다란 파일인 경우 여러 개의 클러스터에 걸쳐 저장되는 수도 있다. 그러나, 비록 하나의 파일이 여러 개의 클러스터에 나뉘어 있다고 해도, 이 클러스터들이 항상 연속되어 있어야만 하는 것은 아니며, 하드디스크의 이곳 저곳에 흩어져 있는 것도 가능하다. 이런 경우 하나의 파일에 연관된 여러 개의 클러스터들의 위치는 하드디스크의 파일 배치표(FAT)에 관리되므로, 사용자의 입장에서는 파일이 어떤 클러스터에 저장되어 있는지, 혹은 나뉘어 저장되어 있는지 아닌지 등에 대해 전혀 알 필요가 없으며, 그저 원하는 파일을 읽고자 하면 파일 내용 전체가 읽혀진다.


http://www.terms.co.kr/cluster.htm 에 이렇게 쓰여져 있다. 내용이 어렵고 부족하다. 좀더 검색 질 좀 해야겠다.

음.. 대충 검색해서 이해한 바로는..


파일을 디스크에 쓸 때 클러스터 단위로 파일을 쪼개고, 그걸 클러스터 단위로 저장하나 보다. 각 클러스터는 연속적으로 저장 될 수 있고 여기 저기 흩어질 수 있다고 한다. 클러스터는 섹터들이 모여서 구성된다고 한다. . 그럼 왜 저장 단위를 클러스터 단위로 묶는 것일 까??? 흐… 메모리 생성, 삭제를 생각해 보면 되겠다… 단.편.화! 아니면 용량이 큰 디스크 일 경우 섹터로 할 경우, 4바이트를 벗어날 경우가 있어서 그런가?? 흠. 뭐 다른 이유가 있을 지도 모르겠지만, 아무튼 클러스터가 이런 거란다.

BPB구조를 표로 다시 작성해봤다.


위치

구분

설명

0x00

Jump Boot Code 0x03부터 0x59까지 FAT32 정보가 들어가기 때문에 그 위치를 건너 코드를 호출한다.

0x03

OEM Name OEM Name이라는데 그냥 8바이트 문자열.

0x0B

섹터 당 바이트 1 섹터에 몇 바이트를 저장 하는지에 대한 정보. 보통 512 바이트이지만 뭐 다를 수도 있나 보다.

0x0D

섹터 당 클러스터 클러스터 하나에 섹터 몇 개가 묶이는지에 대한 정보.

0x0E

예약 영역 섹터 파티션 시작 위치부터 FAT#1 까지 위치까지의 섹터 수.

0x10

FAT 수 FAT 테이블 수.

0x11

최대 루트 엔트리 수 루트 엔트리 수. 그냥 0 이란다.

0x13

FAT16 총 섹터 FAT16 파일 시스템 일 경우, FAT16의 총 섹터 수.

0x15

장치 타입 플로피 디스크 인지, 하드디스크인지 정보 기록.
0xF0 : 기본 플로피 디스크
0xF8 : 하드 디스크

0x16

FAT16의 크기 FAT16 파일 시스템일 경우, FAT#1 테이블의 크기

0x18

트랙 당 섹터 수 한 트랙에 존재하는 섹터 총 수.

0x1A

헤드 수 헤드 수

0x1C

숨은 섹터 수 디스크의 0 부터 파티션 시작 위치까지의 섹터 수

0x20

FAT32 총 섹터 FAT32 파일 시스템 일 경우, 총 섹터 수. (총 크기)

0x24

FAT32 크기 FAT32 파일 시스템일 경우, FAT#1 테이블 크기

0x28

확장 FLAGS - 플래그

0x2A

File System Version 파일 시스템 버전

0x2C

루트 디렉토리 클러스터 루트 디렉토리 시작 클러스터 번호

0x30

File System Info -

0x32

백업 부트 섹터 백업 부트 섹터 위치

0x34

예약  

0x40

드라이브 번호 BIOS 콜 (INT 13h)드라이브 정보
0x00 : 플로피 디스크 A
0x01 : 플로피 디스크 B
0x80 : 드라이브 C
0x81 : 드라이브 D

0x41

예약  

0x42

부트 시그널 0x29 시그널

0x43

볼륨 ID 디스크 볼륨 ID

0x47

볼륨 레이블 디스크 볼륨 레이블

0x52

File System Type -


위치 별 각 항목을 적어봤다.

이 구조에 값을 대입해 보면서 파일을 찾고 파일 데이터 읽는 부분을 순차적으로 분석해 봐야 겠다.

우선 파일을 찾기 위해선 파일 목록 정보를 가지고 있는 루트 디렉토리 엔트리로 가야한단다. 무조건 시작은 루트 디렉토리 엔트리 영역에서 파일을 찾든 데이터를 읽든 시작한단다. 파일 목록이 너무 길면, 다음 파일 목록이 어디에 있는지 루트 디렉토리 영역에 기록되어 있단다. 그래?? 한번 찾아가봐야 겠네! 


(ㅋㅋㅋㅋ 실제로는 FAT 테이블에 다음 영역이 기록된다고 한다. ㅋ)

실제 디스크에서 루트 디렉토리는 위치는 위 표에서 나온대로

루트 디렉토리 = 숨은 영역 섹터 + 예약 영역 섹터 + (FAT#1 크기 * FAT 수)


위치에 있다. 이 영역에서 파일을 검색한다. 함 찾아 볼까??

내 BaramOS 이미지 BPB 영역에서 각 항목은



숨은 영역 섹터(0x1C) = 0x00000080
예약 영역 섹터(0x0E) = 0x186E
FAT32 크기(0x24) = 0x000003C9
FAT 수(0x10) = 0x02

루트 디렉토리 = 0x00000080 + 0x186E + (0x000003C9 * 0x02)


0x2080 섹터에 루트 디렉토리가 존재 한다. 그럼 이미지 파일에서 0x2080 섹터 위치를 찾아 볼까나? 아! 섹터 위치다 여기서 섹터당 바이트(0x0B) 위치에 보면 0x200 이므로 0x200을 곱한다. 그럼 0x410000위치에 루트 디렉토리가 존재한다. 가보잣!!



뭔가 적어져 있다. 포맷 하고 아무것도 파일 저장 안 했는데 뭔가 있다. 아! 루트 디렉토리(C:\) 정보란다. 그냥 기본으로 들어간다고 한다. 그래서 파일 하나를 저장해봤다.


오!! 파일이 기록되어 있다. KERNEL.SYS 파일명이 있고 쏼라 쏼라.. KERNEL.SYS 에서 “.” 이 빠진 게 특이하다. 그럼 이 파일목록 구조를 살펴봐야 겠다. (할게 겁나 많네..)


한 파일당 32바이트(0x20) 구성으로 이루어져 있다고 한다. 이미지 파일이 0x410000에서 시작하니 KERNEL.SYS 파일은 0x410020 에서 시작되는 것이다. 위 항목에 실제 이미지 파일 데이터를 대입해 보면


파일이름 : KERNEL
확장자 : SYS
속성 : 0x20 (Archive)

0000 0001 읽기 전용
0000 0010 숨은 파일
0000 0100 시스템 파일
0000 1000 볼륨 레이블
0000 1111 긴 파일
0001 0000 디렉토리
0010 0000 Archive

예약 : 0xAB18
파일 생성시간 : 0x7CA2

11~15비트 시간 0~23
5~10비트 분 0~59
0~4비트 초 0~59
파일 생성날짜 : 0x42EF
9~15비트 년도 (1980 + 비트값)
5~8비트 월(1~12)
0~4비트 일(1~31)
액세스 날짜 : 0x42EF
클러스터 위치: 0x0000 (high)
파일 Write 시간 : 0x0577
파일 Write 날짜 : 0x42EC (
클러스터 위치: 0x0003 (low) (3)
파일크기: 0x0000048F (1167 byte)


KERNEL.SYS 파일은 클러스터 HIGH + LOW 하면 0x00000003 위치에 있다. 그러면 데이터 영역 3번 클러스터 위치로 가보자! 1 클러스터는 2 섹터가 묶여 있다고 하니, 2 * 0x200(512) * 3.

현재 위치 0x410000 + (0x00000003 * 0x200 * 2) = 0x410C00 .. 으로 가보자!!!


없다…아무런 데이터도 없다.. 이게 웬일이냐??

흠…


그러니까 데이터 영역 시작과 현재 내가 보고 있는 루트 디렉토리 영역은 동일한 위치가 아니란다. 뭔말?? 즉, 데이터 영역에서 2 클러스터 이동한 위치가 루트 디렉토리 영역이다. 난, 데이터 영역 시작 위치가 루트 디렉토리 영역인지 알았다. 하지만 그게 아니고 데이터 영역 위치에서 2 클러스터 위치를 이동한 위치가 0x410000인것이다. 이 정보가 어디에 있냐면, BPB 의 루트 디렉토리 클러스터 (0x2C) 위치에 0x2 라고 적어 놨다… 아놔!!!~~~흠


현재 위치가 데이터 영역에서 2클러스터 위치 0x410000 이니까 3 클러스터 위치는 0x410000 영역에서 0x200(512) * 2 = 0x400 를 더한 0x410400 위치에 있다. 함 볼까?



데이터가 있다. 얼마나 있을까? 생각해 보니 1 클러스터 크기 만큼 있을테니 1 클러스터(2섹터)는 1024byte 만큼 있을 것이다. 그렇겠지!~~~? 그러면 내 KERNEL.SYS 파일 크기는 1167 byte 이므로 하나의 클러스터(1024byte)에 다 기록하기에는 힘들다. 그럼 다음 클러스터에 있겠지….라고 생각해서 이동해 봤더니 다음 데이터가 다음 클러스터 위치(0x410800)에 있다. 그런데 검색 질 해보니 이건 방금 포맷하고 파일 저장 한 거라 이렇게 되지만, 파일을 삭제,추가를 반복하게 되면 이렇게 순차적으로 저장되지 않는다고 한다. 어째 다음 데이터가 있길래 잘 풀린다 했다. 검색 내용으로는 파일 데이터가 있는 클러스터를 읽고 난 후 FAT 테이블로 이동해서 다음 데이터가 어디에 있는 지 클러스터 번호를 얻어야 한다고 한다.

그래 FAT 테이블이 어떤지를 또 알아야 된다는 거네!!!! 아놔~FAT 테이블로 이동해 보자.

FAT 테이블 = 숨은 영역 섹터 + 예약 영역 섹터
0x18EE = 0x00000080 + 0x186E
FAT 위치 = 0x18EE * 0x200 (512byte)

0x31DC00 위치에 FAT가 있다. 가보자!!


이상한 FF FF FF 만 있다. 이게 뭔지를 알아야 한다 ㅠㅠ 아이고!!!


FAT는 위 구조와 같이 구성되어 있다고 한다. 각 클러스터는 4바이트로 구성되고 다음 클러스터 위치를 가르킨 다고 한다. 0x0FFFFFFF 일 경우에는 다음 클러스터가 없다는 의미란다.


클러스터 0, 1 위치는 FAT32 에서는 쓰이지 않는다고 하니, 클러스터 2 는 루트 디렉토리 엔트리를 뜻한다. 현재 파일이 하나밖에 없고 디렉토리도 없으니까(클러스터 한 개에 파일 목록을 담을 수 있는 갯수는 32개이다. 왜??? 파일목록 데이터는 32바이트로 구성되고 한 개의 클러스터(1024) / 32 = 32이니까!~~즉 32개의 파일 목록 이상 가지고 있지 않으니 파일 목록 정보를 담은 클러스터는 클래스터2 로 충분하다는 말이다) 클러스터 2는 다음 클러스터를 0x0FFFFFFF 라고 기록되어 있다. 하지만 클러스터 3 은 KERNEL.SYS 데이터를 기록되어 있는 클러스터로 파일 크기가 1167 이니 클러스터 2개가 필요하다. 그래서 클러스터3 위치에 보면 다음 위치 0x00000004 위치를 가르킨다. 그리고 클러스터4 는 다음 클러스터를 0x0FFFFFFF 으로 더 이상 다음 클러스터가 없다고 기록되어 있다. 즉 KERNEL.SYS파일은 클러스터 3번과 4번을 이용해서 파일 데이터를 기록해 놓고 있다.


자 정리해 보면!


1. 루트 디렉토리 엔트리에서 원하는 파일을 찾는다.(KERNEL.SYS)
2. 파일 데이터가 기록되어 있는 클러스터3으로 이동해서 데이터를 읽는다.
3. FAT 테이블로 이동해 클러스터3번의 다음 클러스터가 있는지 체크한다. (클러스터 4가 있다)
4. 데이터 영역에서 다음 클러스터4 위치로 이동해서 데이터를 읽는다.
5. FAT 테이블로 이동해 클러스터4번의 다음 클러스터가 있는지 체크한다. (0x0FFFFFFF 이므로 더 이상 없다.)
6. 종료.


위와 같은 방법이 FAT32 동작 시나리오라 할 수 있겠다. 휴~~ 긴 FAT32 를 공부했다.

검색질을 몇번을 했는지 모른다. 글 쓰고 수정하고 수정하고… 글이 완전 산으로 간다.

'프로그래밍 > OS 만들기' 카테고리의 다른 글

OS 만들기 #9 - 부트로더  (0) 2013.08.14
OS 만들기 #8 - 부트로더  (0) 2013.08.14
OS 만들기 #6 - MBR  (0) 2013.08.14
OS 만들기 #5 - 부트로더  (0) 2013.08.14
OS 만들기 #4 - 부트로더  (0) 2013.08.14

부트로더 #3

파일시스템 전혀 생각 안하고 그냥 되는데로 부트로더만 만들다 보니 이런… 처음부터 다시 해야 한다. 아무래도 기본 구조 및 설계는 해 놓고 시작해 놔야 겠다. 그래! 파일시스템. 파일 시스템을 선정 하려고 여기 저기 검색질 해 봤다. 자체 파일 시스템 쓰는곳도 있고 EXT2 , FAT12/16 도 있다. 윈도우에서 개발하니 FAT 시스템으로 가자!! 흠..

FAT 파일 시스템으로 결정하고, 이젠 뭘 해야 하나??

검색질 하니 FAT16 부트로더가 있다. 좋아~ 이걸 참조해서 만들어 보자!! 음.. 이것 역시 플로피 디스크 이미지를 이용한다. 아놔!~ 난 하드디스크 라고!!!!!! ㅠㅠ 참조해서 테스트 하기 어렵겠다..또 검색질 해서 만들어야겠다. 그래 이왕 만드는 김에 FAT16말고 FAT32 파일 시스템으로 가자~~!!! 난 FAT16 같은 오래된 건 싫다고~~~또, 부트로더에 커널 크기 집어 넣는 따위는 하지 말고, 루트 디렉토리에서 파일을 찾아서 로드, 실행 하게끔 깔끔하게 가자~


부트로더 목표


1. FAT32 파일 시스템을 사용한다.
2. 커널은 루트 디렉토리에서 파일 찾아서 로드한다. (C:\OSLDR.SYS)


갑자기 하기 싫어진다…뭘 이제 뭘 어떻게 해야 할지 모르겠다…ㅠㅠ


맹붕!!~~~~~~~~


우선, 기존 이미지 파일은 첫 부트로더 기념으로 그냥 묵혀 둬야 겠다. Virtual PC로 새 장치 추가 해서 다른 이미지 하나를 만들었다. 이번엔 test가 아니고 정식으로 만들 생각이니깐 BaramOS 라고 이름을 지었다. 의미 없다. 그냥 지금 하고 있는 이 삽질이 그냥 부질없다고 생각이 들고 이리저리 흔들리는 것 같아 아무 생각 없이 바람 이라고 지었다. 흠.. 생성한 이 BaramOS 이미지 파일을 FAT32 파일 시스템 이용할 생각이니 포맷이나 해 두자. 음.. 어떻게 포맷하지??? 어떻게 포맷하냐고!~~ 검색..검색..

흘… MS-DOS 플로피 디스크 이미지 파일 하나 구해서 그걸로 부팅하고 하드디스크 포맷하란다!!~ 아놔 고대적 유물 같은 그 이미지를 어떻게 구하냐고!!!! 다시 검색..검색..휴~~ 윈도우즈 7 에 VHD 파일을 가상 드라이브로 연결해 주는 기능이 있다고 한다. 다행이다! 


Virtual PC 로 이미지 만들어서….

제어판 –> 관리도구 –> 컴퓨터 관리


디스크 관리 에서 오른쪽 마우스 클릭 하면 VHD 연결 메뉴가 나온다. 선택.



흠. 디스크에 이미지 파일이 들어갔다. 디스크 1 에 파일이 들어간 그림이다.



초기화 안됨 이라고 나오네..이건 모냐.. 흠. 디스크 1에 마우스 올리고 오른쪽 마우스를 클릭해 봤다. 디스크 초기화 라는 메뉴가 있다. 선택해 봤다.



MBR(마스터 부트 레코드) ? 우선 이건 모르겠다. 그냥 확인 눌러 버렸다. 초기화 안됨이 온라인 으로 바뀌었네..흠


또 디스크 포맷 해야 하니 오른쪽 마우스 클릭해본다. 음. 근데 새 단순 볼륨 ???이건 모냐!! 선택해 본다. 아 파티션 잡는 거구나.. 아~ 플로피 디스크에서는 없는 파티션이다… ㅠㅠ 하드 디스크 이미지 이기 때문에 파티션을 잡아줘야 하나 보다. 아 귀찮다..새 단순 볼륨 생성 다음 다음 누르다 보니 파티션 포맷이 나온다.



FAT32 로 포맷 해야 하니, 선택하고 할당 단위?? 그냥 기본값으로 볼륨 레이블은 모르겠다. 그냥 다음.



파티션 생성 되었고 포맷도 다 되었다. 다시 마우스 오른쪽 클릭을 해보니 [파티션을 활성 파티션으로 표시] 메뉴가 있다. 아! 파티션 생성했으니, 활성 파티션으로 만드는 거구나.. 선택했다.


디스크1 에서 오른쪽 클릭 하면 VHD 분리가 있다. 분리시켰다.


뭔일이 생겼나~~ 한번 헥사 뷰어로 볼까??.



음.. 첫번째 섹터에 이상한 데이터가 들어 있다. 문자열들을 보면 파티션 이라는 단어가 보이네?? 이건 모지??? 조금전 생성했던 파티션에 대한 정보인가?? 왜 이게 여기 있지?? 아놔 이거 관련해서 공부좀 해놔야 겠다



'프로그래밍 > OS 만들기' 카테고리의 다른 글

OS 만들기 #7 - FAT32  (1) 2013.08.14
OS 만들기 #6 - MBR  (0) 2013.08.14
OS 만들기 #4 - 부트로더  (0) 2013.08.14
OS 만들기 #3 - 부트로더  (1) 2013.08.14
OS 만들기 #2  (0) 2013.08.14

+ Recent posts