1

我一直在编写一个小型操作系统,并且一直使用虚拟机对其进行测试,特别是它可以在 QEMU、VMWare 和 VirtualBox 上运行。内核希望从 HDD 启动,因此为了在真实硬件上对其进行测试,我将其刻录到真实 HDD 并将其连接到真实 PC。从那里开始就是一场灾难!一切正常。我已经部分修复了我能找到的所有错误,但我真的不知道是什么原因造成的:VBR 在被 MBR 加载后,实现只加载第二阶段引导加载程序的一部分;在 BOCHS 中,它仅加载第一个集群,但在真实 pc 中,内存中加载的代码更少。处理 FAT16 的所有代码都在一个文件中,但它仍然太大而无法在此处发布,因此我将在 GitHub 上提供其链接。此文件 ( /boot/include/fat16.inc ) 包含在主 VBR 文件 (/boot/src/vbr.asm)。vbr.asm 中可能会丢失一些初始化,但由于空间限制,它们会在 MBR 文件 ( /boot/src/mbr.asm ) 中处理。

编辑

如果由于某些原因 GitHub 存储库丢失了,我将发布 fat16.inc 的代码以供未来的读者使用:

%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__
4

1 回答 1

1

这不是我遇到的问题的完整解决方案,但我仍然想将其发布为答案,因为它对未来的读者很有用。
事实证明,不确定 bios 函数是否会保持原样,实际上在我的情况下int 13.42是破坏ebx.
现在我可以在 BOCHS 和 Microsoft Hyper-V 中启动我的映像,它仍然不能在真正的硬件上启动,但这肯定是一件重要的事情。

于 2021-04-01T08:06:11.667 回答