【问题标题】:BIOS Read SectorsBIOS 读取扇区
【发布时间】:2015-09-29 10:20:11
【问题描述】:

为了学习,我已经研究过制作一个小型操作系统,现在正在使用引导加载程序。我希望能够使用int 0x13 从软盘驱动器读取扇区,将它们放入内存,然后跳转到该代码。这是我目前所拥有的:

org 0x7c00
bits 16

main:
    call setup_segments

    mov ah, 2      ; function
    mov al, 1      ; num of sectors
    mov ch, 1      ; cylinder
    mov cl, 2      ; sector
    mov dh, 0      ; head
    mov dl, 0      ; drive
    mov bx, 0x1000 ;
    mov es, bx     ; dest (segment)
    mov bx, 0      ; dest (offset)
    int 0x13       ; BIOS Drive Interrupt

    jmp 0x1000:0   ; jump to loaded code

times 510 - ($-$$) db 0 ; fluff up program to 510 B
dw 0xAA55               ; boot loader signature




LoadTarget: ; Print Message, Get Key Press, Reboot

jmp new_main

Greeting: db "Hello, welcome to the bestest bootloader there ever was!", 0
Prompt:   db "Press any key to reboot...", 0

Println:
    lodsb ; al <-- [ds:si], si++

    or al, al    ; needed for jump ?
    jz PrintNwl  ; if null is found print '\r\n'
    mov ah, 0x0e ; function
    mov bh, 0    ; page number ?
    mov bl, 7    ; text attribute ?
    int 0x10     ; BIOS Interrupt
    jmp Println

PrintNwl: ; print \r\n
    ; print \r
    mov ah, 0x0e ; function
    mov al, 13   ; char (carriage return)
    mov bh, 0    ; page number ?
    mov bl, 7    ; text attribute ?
    int 0x10

    ; print \n
    mov ah, 0x0e ; function
    mov al, 20   ; char (line feed)
    mov bh, 0    ; page number ?
    mov bl, 7    ; text attribute ?
    int 0x10

    ret          ; return

GetKeyPress:
    mov si, Prompt ; load prompt
    call Println   ; print prompt

    xor ah, ah     ; clear ah
    int 0x16       ; BIOS Keyboard Service

    ret            ; return

setup_segments:
    cli ;Clear interrupts
    ;Setup stack segments
    mov ax,cs
    mov ds,ax
    mov es,ax
    mov ss,ax
    sti ;Enable interrupts

    ret

new_main:
    call setup_segments

    mov si, Greeting ; load greeting
    call Println     ; print greeting

    call GetKeyPress ; wait for key press

    jmp 0xffff:0     ; jump to reboot address

times 1024 - ($-$$) db 0 ; fluff up sector

我想将LoadTarget之后的扇区加载到地址0x1000:0中,然后跳转到它。到目前为止,我只是得到一个空白屏幕。我觉得这个错误介于maintimes 510 - ($-$$) db 0 之间。也许我只是没有得到寄存器的值吗?请帮忙!谢谢

【问题讨论】:

标签: assembly x86 nasm boot bios


【解决方案1】:

您应该将第一个 call setup_segments 替换为执行该工作的实际指令。同样正如 Jester 指出的那样,在更改 SS 寄存器时始终更新 SP 寄存器。

目前您正在从气缸 1 读取。它应该是气缸 0。

换行的代码是 10(不是你写的 20)。

PrintNwl 中的两个 BIOS 调用都不需要 BL 寄存器,因为 CR 和 LF 都是不可显示的 ascii。

【讨论】:

  • 哇,我简直不敢相信我搞砸了 '\n' 字符!我知道是 10,我不知道为什么我放了 20。我也会修复其他错误,谢谢!
  • 感谢您的帮助,但它仍然显示空白屏幕。我在 Virtualbox 上使用软盘。这和真正的软盘有什么不同吗?
  • 对不起,从来没有享受过使用 Virtualbox 的乐趣。
  • 没关系,我的程序现在可以工作了,它重新启动,但不显示任何内容。我认为这可能与sp 有关。我不知道我应该把它设置成什么。我应该将ss 复制到sp 吗?
  • @TheTromboneWilly 你用ORG 正确设置了原点吗?第二阶段不应该是0吗?
【解决方案2】:

您使用ORG 0x7C00 的事实意味着您希望 CS:IP 对或寄存器保存 0000h:7C00h。请记住,BIOS 已经将 1024 字节长程序的前 512 字节放在线性地址 00007C00h 处。

设置其他段寄存器只需将 CS 复制到 DS、ES 和 SS 即可。但非常重要的是,每次更改 SS 时,您还必须更改 SP 以保持一致的 SS:SP 寄存器对。在您的程序中,堆栈的方便位置将位于程序下方,因此我使用 7C00h 设置了 SP 寄存器。您不能在子例程中摆弄 SS:SP(就像您所做的那样),因为最后的 RET 不知道返回到哪里!

当您从软盘加载第二个扇区时,它必须来自柱面 0。在 CHS 表示中,柱面和磁头从 0 开始,扇区从 1 开始。
如果您检查 CF 是否成功操作,那就太好了。

无法通过jmp 0x1000:0 跳转到加载的代码,因为现在位于那里的代码是使用ORG 0x7C00 指令编译的程序的一部分。你需要弥补这一点!

  1. 补偿ORG 0x7C00 指令。段部分减去 07C0h,偏移部分加上 7C00h。 => jmp 0840h:7C00h
  2. 补偿您的 LoadTarget 标签位于程序中 偏移量 512 的事实。段部分减去 0020h,偏移部分加 0200h。 => jmp 0820h:7E00h

这是初始代码的样子

 org 7C00h
 bits 16
main:
 mov ax,cs
 mov ds,ax  <-- Not necessary at this stage in this program
 mov es,ax  <-- (keep them should you display a message on error)
 cli
 mov ss,ax
 mov sp,7C00h
 sti
 mov ax,0201h
 mov cx,0002h
 mov dx,0000h
 mov bx,1000h
 mov es,bx
 mov bx,0000h
 int 13h
 jc  Error
 jmp 0820h:7E00h
Error:
 hlt

第二阶段运行后,您只需设置 DS 和 ES 寄存器。 CS:IP 是通过JMP 设置的,SS:SP 继续。

 ...
new_main:
 push cs
 pop  ds
 push cs
 pop  es
 mov  si,Greeting
 call Println
 ...

【讨论】:

    猜你喜欢
    • 2019-04-25
    • 2020-02-22
    • 2011-04-08
    • 1970-01-01
    • 2013-07-16
    • 1970-01-01
    • 2013-07-15
    • 2010-12-17
    相关资源
    最近更新 更多