assembly 引导装载程序在qemu上工作,但在真实的计算机上不工作

bz4sfanl  于 2023-02-16  发布在  其他
关注(0)|答案(1)|浏览(142)

我一直在写一个操作系统的最后几个星期,它进行得很好,我决定尝试它在一个真正的机器上,但它不跳转到内核,我试图使用硬盘驱动器,而不是usb棒,它甚至没有得到引导加载程序,因为它得到了usb棒
我试着在网上搜索并使用其他代码,但它就是不跳转到内核,这里是引导代码

[ORG 0x7c00]

[BITS 16]

CODE_SEG EQU gdt_code - gdt_start
DATA_SEG EQU gdt_data - gdt_start

jmp short biosBlock  
nop

biosBlock:
    jmp 0:start


start:
    ;umas checkagens 
    cli ;clear interrupts
    mov ax, 0x00
    mov ds, ax
    mov es, ax

    mov ss, ax
    mov sp, 0x7c00
    sti ;enables interrupts

.load_protected:
    cli
    lgdt[gdt_descriptor]
    mov eax, cr0
    or eax, 0x1
    mov cr0, eax
    jmp CODE_SEG:load32

;just using gdt so we can use all the memory :D 4GB
gdt_start:
gdt_nul:
    dd 0x0
    dd 0x0

;offset 0x8
gdt_code:  ;cs should point to this
    dw 0xffff
    dw 0
    db 0
    db 0x9a
    db 11001111b
    db 0
;offset 0x10
gdt_data:
    dw 0xffff
    dw 0
    db 0
    db 0x92
    db 11001111b
    db 0

gdt_end:

gdt_descriptor:
    dw gdt_end - gdt_start - 1
    dd gdt_start

[BITS 32]
 load32:
    mov eax, 1
    mov ecx, 100
    mov edi, 0x0100000
    call ata_lba_read
    jmp CODE_SEG:0x0100000

ata_lba_read:
    mov ebx, eax, ; Backup the LBA
    ; Send the highest 8 bits of the lba to hard disk controller
    shr eax, 24
    or eax, 0xE0 ; Select the  master drive
    mov dx, 0x1F6
    out dx, al
    ; Finished sending the highest 8 bits of the lba

    ; Send the total sectors to read
    mov eax, ecx
    mov dx, 0x1F2
    out dx, al
    ; Finished sending the total sectors to read

    ; Send more bits of the LBA
    mov eax, ebx ; Restore the backup LBA
    mov dx, 0x1F3
    out dx, al
    ; Finished sending more bits of the LBA

    ; Send more bits of the LBA
    mov dx, 0x1F4
    mov eax, ebx ; Restore the backup LBA
    shr eax, 8
    out dx, al
    ; Finished sending more bits of the LBA

    ; Send upper 16 bits of the LBA
    mov dx, 0x1F5
    mov eax, ebx ; Restore the backup LBA
    shr eax, 16
    out dx, al
    ; Finished sending upper 16 bits of the LBA

    mov dx, 0x1f7
    mov al, 0x20
    out dx, al 

.next_sector:
    push ecx

.try_again:
    mov dx, 0x1f7
    in al, dx
    test al, 8
    jz .try_again

; We need to read 256 words at a time
    mov ecx, 256
    mov dx, 0x1F0
    rep insw
    pop ecx
    loop .next_sector
    ; End of reading sectors into memory
    ret



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

生成文件代码:

dd if=./bin/boot.bin >> ./bin/os.bin
    dd if=./bin/kernel.bin >> ./bin/os.bin
    dd if=/dev/zero bs=1048576 count=32 >> ./bin/os.bin

即时通讯使用

dd if=os.bin of="the_usb"
txu3uszq

txu3uszq1#

最有可能的问题是(对于真实的的硬件,而不是模拟器)ATA控制器在大约20年前被SATA/AHCI取代(然后在大约10年前被NVMe取代);并且您没有健全性检查来确定您认为正在与之通话的ATA控制器是否存在(或有故障,或插入了硬盘驱动器,或该硬盘驱动器是否有故障,或您发送的命令是否起作用而不仅仅返回“读取错误”),并且没有代码来处理许多可能的问题中的任何一个(甚至没有显示绝对最坏的可能“对不起,出错了”错误消息)。
这就是为什么在早期 Boot 期间使用固件访问设备(例如BIOS“int 0x 13”)是一个好主意,直到操作系统能够检测到存在哪些设备(例如从PCI总线枚举开始)并为检测到的任何设备设置正确的设备驱动程序。
更笼统地说;(对于BIOS和UEFI)最好将“ Boot ”分为4个阶段:
a)早期 Boot 。在此阶段,固件拥有所有硬件,您仅使用固件执行操作。早期引导代码的目的是从固件收集信息(例如,获取稍后需要的内存Map),设置临时内存管理(包括使用相关BIOS功能禁用A20),加载“内核加驱动程序和以后需要的任何其他内容”(可能是内核加“初始RAM磁盘”),设置默认视频模式,这通常涉及在真实的模式(以使用BIOS功能)与保护模式或长模式(以能够访问更多存储器)之间切换;以避免“内核和/或初始RAM磁盘有许多MiB,但真实的模式只能访问约640 KiB的RAM”问题(通过在实模式下加载到临时缓冲区,然后使用保护/长模式将数据移动到您实际想要的位置)。当操作系统象征性地(对于BIOS)或字面上(对于UEFI,通过其“ExitBootServices()”)从固件控制所有硬件时,此阶段结束。
B)内核初始化。这是你设置物理内存管理、虚拟内存管理、调度程序、设备驱动程序接口等的地方。注意,在这个阶段,不需要访问任何设备。此外,还可以做一些工作(例如解压缩内核文件,设置分页并将内核Map到虚拟存储器中的正确位置)之后将控制传递给内核(并非所有的“内核初始化”都是由内核本身完成的)。
c)设置设备(检测哪些设备存在、从“初始RAM盘”加载它们的设备驱动程序、让设备驱动程序测试它们的设备并查看什么连接到它们,等等)注意,这可以是概念上递归的并且可以以“非设备服务”结束。例如PCI总线枚举检测网卡并启动网卡驱动程序,然后网卡驱动程序初始化(并检查故障硬件)并检测网络连接,并启动TCPI/IP栈(如果尚未启动);或者PCI总线枚举检测到USB控制器并启动相应的USB控制器驱动程序,USB控制器驱动程序检测到声音设备并启动相应的USB声音设备驱动程序;USB声音设备驱动程序检测扬声器/麦克风并启动某种声音服务(如果尚未启动)。以相同的方式,硬盘控制器可以(在初始化、检测所连接的磁盘等之后)启动RAID层和/或启动文件系统。
d)将控制权交给用户空间进行更多的初始化,这可能是一个“init脚本”(古老的Unix),也可能是用户用来登录的东西(后面跟着一个GUI);并且可能包括各种其他事情(启动服务/守护进程)。
请注意(尤其是在早期阶段,你不能只说“LOL,如果有什么错误内核或设备驱动程序会处理它”),也许你的代码会有一半用于处理不应该发生的事情。这意味着,即使你不做任何必要的事情(例如获取内存Map),也不可能有可接受的512字节的早期 Boot 代码。

相关问题