BIOS阅读部门

时间:2015-07-10 15:27:21

标签: assembly x86 nasm boot bios

我已经考虑过为了学习而制作一个小操作系统,而且我现在正在启动加载器。我希望能够使用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中,然后跳转到它。到目前为止,我只是得到一个空白屏幕。我觉得这个错误介于main和行times 510 - ($-$$) db 0之间。也许我只是没有得到正确的寄存器值?请帮忙!感谢

2 个答案:

答案 0 :(得分:5)

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

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

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

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

答案 1 :(得分:3)

您使用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表示中,Cylinder和Head从0开始,扇区从1开始。 如果你检查了CF的成功操作,那就太好了。

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

  1. 补偿ORG 0x7C00指令。从段部分减去07C0h,将7C00h添加到偏移部分。 =&GT; jmp 0840h:7C00h
  2. 补偿您的 LoadTarget 标签在程序中偏移512 的事实。从段部分减去0020h,将0200h添加到偏移部分。 =&GT; jmp 0820h:7E00h
  3. 这里是初始代码的样子

     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
     ...