자!! 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 |