Reputation: 21
I've been coding a small OS for a while and I've always tested it using VMs, specifically it works on QEMU, VMWare, and VirtualBox. The kernel expects to be booted from an HDD so to test it on real hardware I burned it to a real HDD and connected it to a real pc. From there it was a disaster! Anything was working. I've partially fixed all the errors that I could find but I really don't know what causes this: the VBR, after being loaded by the MBR, achieve to load only a part of the second stage bootloader; In BOCHS it loads only the first cluster but in the real pc even less code is loaded in memory. All the code that handles FAT16 is in a single file but it still too large to be posted here so I'll provide its link on GitHub. This file (/boot/include/fat16.inc) is included by the main VBR file (/boot/src/vbr.asm). Some initialization may miss in vbr.asm but they are treated in the MBR file (/boot/src/mbr.asm)'cause of space limitation.
EDIT:
If for some reasons the GitHub repo gets lost I'm posting the code of fat16.inc for future readers:
%ifndef __FAT12_INC__
%define __FAT12_INC__
; this file relies on a word variable called partition_offset
; partition_offset should contain the address in memory of
; the current partition entry in the table
bits 16
%define ROOT_OFFSET Mem.Loader.FAT16.Data
%define ROOT_SEG LIN_TO_FAR_ADDR(ROOT_OFFSET)
%define FAT_OFFSET Mem.Loader.FAT16.Data
%define FAT_SEG LIN_TO_FAR_ADDR(FAT_OFFSET)
%include "include/disk.inc"
;*********************************;
; Sets Rot Directory informations ;
; Returns: ;
; ecx => location in sectors. ;
; eax => size in sectors ;
;*********************************;
GetRootInfo:
; clear registers
xor eax, eax
xor ecx, ecx
; compute location of root directory in sectors and store in "ecx"
mov al, byte [bpb_NumberOfFATs] ; number of FATs
mul word [bpb_SectorsPerFAT] ; sectors used by FATs
add ax, word [bpb_ReservedSectors] ; reserved sectors
mov cx, ax ; move into cx
mov ax, word [partition_offset]
add cx, word [eax + 8] ; offset from partition information
; compute size of root directory in sectors and store in "ax"
mov ax, 32 ; 32 byte directory entry
mul word [bpb_RootEntries] ; total size of directory
div word [bpb_BytesPerSector] ; sectors used by directory
ret
;***************************************;
; Load Root Directory Table to ROOT_SEG ;
;***************************************;
LoadRoot:
call GetRootInfo
; read Root into memory at ROOT_SEG
mov dl, byte [bpb_DriveNumber]
mov ebx, dword ROOT_SEG
call ReadSectorsLBA
ret
;****************************;
; Loads FAT table to FAT_SEG ;
;****************************;
LoadFAT:
pushad
; clear registers
xor ax, ax
xor cx, cx
; compute size of FAT and store in "ax"
mov ax, word [bpb_SectorsPerFAT] ; number of FATs
; compute location of FAT and store in "ecx"
mov cx, word [partition_offset]
mov cx, word [ecx + 8] ; offset from partition information
add cx, word [bpb_ReservedSectors]
; read FAT into memory at FAT_SEG
mov dl, byte [bpb_DriveNumber]
mov ebx, dword FAT_SEG
call ReadSectorsLBA
popad
ret
;***********************************************;
; Search for filename in root table ;
; Parameters: ;
; si => File name ;
; Returns: ;
; ax => File index number in directory table. ;
; di => Location of the file root entry ;
;***********************************************;
FindFile:
; store registers
push cx
push bx
push es
mov bx, si ; save filename for later
push ROOT_SEG >> 16 ; locate first root entry
pop es
mov di, ROOT_SEG ; ES:DI is memory location of root dir
mov cx, word [bpb_RootEntries] ; load loop counter
; browse root directory for binary image
cld ; clear direction flag
.loop:
push cx
mov cx, 11 ; eleven character name. Image name is in SI
mov si, bx ; image name is in BX
push di
rep cmpsb ; test for entry match [ DS:SI - ES:DI ]
pop di
je .Found
pop cx
add di, 32 ; queue next directory entry
loop .loop
.NotFound:
; set error code
mov ax, -1
; restore registers and return
pop es
pop bx
pop cx
ret
.Found:
; return value into AX contains entry of file
pop ax
; restore registers and return
pop es
pop bx
pop cx
ret
;**********************************************;
; Gain information about the file to be loaded ;
; Parameters: ;
; edi => Location of the file root entry ;
;**********************************************;
PrepareFile:
; get starting cluster
push word ROOT_SEG >> 16
pop es
mov ax, word [es:edi + 0x1A] ; retrive cluster from root entry
mov word [cluster], ax
; get 0th cluster address
call GetRootInfo
add eax, ecx
mov dword [first_cluster_sector], eax
call LoadFAT
ret
;*********************************************;
; Read the current selected cluster in memory ;
; Parameters: ;
; ebx => Buffer to load file to ;
;*********************************************;
LoadNextCluster:
; zero out registers for calculations
xor cx, cx
xor dx, dx
; convert the cluster in lba
mov ax, word [cluster]
sub ax, 2
mov dl, byte [bpb_SectorsPerCluster]
mul dx
xchg cx, ax
add ecx, dword [first_cluster_sector]
; sets the others parameters and read the disk
mov dl, byte [bpb_DriveNumber]
mov al, byte [bpb_SectorsPerCluster]
call ReadSectorsLBA
; get next cluster from fat table
xor eax, eax
mov ax, word [cluster]
mov dx, 2
mul dx ; since fat table is an array of words (2 byte)
push word FAT_SEG >> 16
pop es
mov dx, word [dword es:eax]
mov word [cluster], dx
ret
;*******************************************************;
; Check if the current reading file has been compleated ;
; Returns: ;
; cf => set on compleated ;
;*******************************************************;
FileReadCompleated:
; test if it was the last cluster
cmp word [cluster], 0xFFFF
je .complete
cmp word [cluster], 0xFFF8
je .complete
.incomplete:
clc ; clear carry flag
ret
.complete:
stc ; set carry flag
ret
;************************************;
; Load file ;
; Parameters: ;
; es:si => File name ;
; ebx => Buffer to load file to ;
; Returns: ;
; ax => -1 on error, 0 on success ;
;************************************;
LoadFile:
.findFile:
; find file using name in es:si
call FindFile
cmp ax, -1
je .done ; file not found
.loadFilePre:
call PrepareFile
.nextCluster:
call LoadNextCluster
call FileReadCompleated
jc .success
; increase address
xor eax, eax
mov ax, word [bpb_SectorsPerCluster]
mul word [bpb_BytesPerSector]
mov ecx, eax
shr eax, 4
shl eax, 16
and ecx, 0xF
or eax, ecx
add ebx, eax
; check if riporto
mov eax, ebx
and eax, (1 << 4)
cmp eax, 0
je .nextCluster
; fix riporto
xor ebx, 1 << 4
add ebx, 1 << 16
jmp .nextCluster
.success:
xor ax, ax
.done
ret
cluster dw 0x0000
first_cluster_sector dd 0x00000000
%endif ; __FAT12_INC__
Upvotes: 1
Views: 340
Reputation: 21
This is not a full solution to the problem I have but still, I want to post this as an answer 'cause it can be useful for future readers.
Turns out that is not sure that bios functions will leave register as they are, in fact in my case int 13.42
was destroying the content of ebx
.
Now I can boot my image in both BOCHS and Microsoft Hyper-V, It still does not boot on real hardware but surely this is an important thing.
Upvotes: 1