阅读写从INT 13H硬盘的扇区 [英] Read a write a sector from hard drive with int 13h

查看:309
本文介绍了阅读写从INT 13H硬盘的扇区的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的程序。它必须读取的硬盘驱动器(未MBR)第一扇区,并将其写入0扇区(MBR)。但它不工作。我认为它是与错误的DAP连接。谢谢你。

I have a simple program. It must read first sector from hard drive (not mbr), and write it to the 0 sector (mbr). But it doesnt work. I think it is connected with wrong DAP. Thanks.

    [bits   16]
    [org    0x7c00]

;clear screen
start:
    mov     ax, 0x3
    int     0x10

;reset the hard drive
    xor     ah, ah
    mov     dl, 0x80
    int     0x13
    jnz     error

;read the second sector
    mov     si, DAP
    mov     ah, 0x42
    int     0x13

    mov     si, data
    call    print_string
    jmp     $

DAP:
    db      0x10    ;size of DAP
    db      0x0     ;zero
    db      0x1     ;number of sectors to read
    db      0x0     ;zero
;point to memory
    dw      0x0     ;offset
    dw      0x0     ;segment
    dq      0x1     ;disk address

DAP2:
    db      0x10
    db      0x0
    db      0x1
    db      0x0
    dw      0x0
    dw      0x0
    dd      0x0
    dd      0x0            

print_string:
    mov     ax, 0xb800
    mov     es, ax
    xor     di, di
    mov     cx, 8
    rep     movsw
    ret
data: db 'H',2,'e',2,'l',2,'l',2
error:db 'E',2,'r',2,'r',2
    times   510 - ($ - $$) db 0
    dw      0xaa55   

UPD:新的code

UPD: new code

    [bits   16]
    [org    0x7c00]

;clear screen
start:
;    mov     ah, 0
;    push    ax
;    pop     ds
    mov     ax, 0x3
    int     0x10

;reset the hard drive
    xor     ah, ah
    mov     dl, 0x80
    int     0x13
    jc      error

;read the second sector
    mov     si, DAP
    mov     ah, 0x42
    int     0x13

    mov     si, data
    call    print_string
    jmp     $

DAP:
    db      0x10    ;size of DAP
    db      0x0     ;zero
    db      0x1     ;number of sectors to read
    db      0x0     ;zero
;point to memory
    dw      0x0     ;offset
    dw      0x8c00  ;segment
    dq      0x1     ;disk address

DAP2:
    db      0x10
    db      0x0
    db      0x1
    db      0x0
    dw      0x0
    dw      0x8c00
    dq      0x2            

print_string:
    mov     ax, 0xb800
    mov     es, ax
    xor     di, di
    mov     si, 0x8c00
    mov     cx, 8
    rep     movsw
    ret

data: db 'H',2,'e',2,'l',2,'l',2
error:db 'E',2,'r',2,'r',2
endp:
    times   510 - ($ - $$) db 0
    dw      0xaa55 

P.S。我使用Bochs的。

P.S. I'm using Bochs.

推荐答案

奸尸的位;希望您的装配技能,在​​此期间有所改善。但是为了以防万一......

A bit of necrophilia; hopefully your assembly skills have improved in the meantime. But just in case...

要引用@Alexey伏龙芝,你需要注意你在做什么。除了其他答案详细的错误,这里是我的一些意见:

To quote @Alexey Frunze, "You need to pay attention to what you're doing". In addition to the mistakes detailed in the other answers, here are some of my observations:

结果


  • 您code似乎是一个引导程序。您将承担BIOS会在 0×0000加载code:0x7C00 ,但你不能确定它其实并没有加载在 0x07C0 :0000 ,或者任何其他等效地址。阅读上分割

  • Your code appears to be a bootloader. You assume the BIOS will load your code at 0x0000:0x7C00, but you cannot be sure it doesn't in fact load it at 0x07C0:0000, or any other equivalent address. Read up on segmentation.

您无法初始化任何段寄存器。你可能逃脱它,因为你的模拟器是善良,正确初始化 CS DS ES 0×0000

You fail to initialise any segment registers. You probably get away with it because your emulator is kind, and correctly initialises cs, ds, and es to 0x0000.

您可以解决这两个问题是这样的:

You can solve both of these problems like this:

[bits 16]
[org 0x7C00]

    jmp 0x0000:start_16 ; ensure cs == 0x0000

start_16:
    ; initialise essential segment registers
    xor ax, ax
    mov ds, ax
    mov es, ax

结果


  • 在一个错误的情况下,您可以直接跳转到一个字符串,而不是可执行code。上帝只知道如果出现这种情况,电脑会做什么。

  • In the event of an error, you jump directly to a string, rather than executable code. Lord only knows what the computer will do if that happens.

您检查驱动器复位的返回值(CF),而不是阅读本身。在读的情况下失败,您应该重置驱动器并再次尝试读取。在几次尝试(例如,3)的情况下,驱动器打嗝一个循环做到这一点。如果驱动器复位失败,很可能更严重是不对的,你应该保释。

You check the return value (CF) of the drive reset, but not the read itself. In the event of a read fail, you should reset the drive and attempt the read again. Do this in a loop for a few attempts (say, 3) in case the drive is hiccuping. If the drive reset fails, it's likely something more serious is wrong, and you should bail.

结果

INT 0x13啊= 0×02 建议使用。您正在使用可能不会在所有系统上支持扩展BIOS功能(支持模拟器可能是古怪,更不用提一些现代硬件发现懒惰BIOS实现)。你在实模式 - 你不需要做任何幻想。这将是最好的进入写一个PM驱动程序来处理磁盘I / O的长远目标的保护模式。

I would suggest using int 0x13, ah = 0x02. You are using an extended BIOS function that may not be supported on all systems (emulator support might be flakey, not to mention the lazy BIOS implementations found on some modern-day hardware). You're in real mode - you don't need to do anything fancy. It would be best to get into protected mode with the long-term goal of writing a PM driver to handle disk I/O.

只要你留在实模式,这里是一个独立的函数,将读取使用简单的BIOS功能从磁盘中的一个或多个部门。如果你事先不知道哪个部门(S),你需要,你将不得不增加额外的检查,以照顾的多轨读

As long as you stay in real mode, here is a standalone function that will read one or more sectors from disk using simple BIOS functions. If you don't know in advance which sector(s) you need, you will have to add additional checks to take care of multitrack reads.

; read_sectors_16
;
; Reads sectors from disk into memory using BIOS services
;
; input:    dl      = drive
;           ch      = cylinder[7:0]
;           cl[7:6] = cylinder[9:8]
;           dh      = head
;           cl[5:0] = sector (1-63)
;           es:bx  -> destination
;           al      = number of sectors
;
; output:   cf (0 = success, 1 = failure)

read_sectors_16:
    pusha
    mov si, 0x02    ; maximum attempts - 1
.top:
    mov ah, 0x02    ; read sectors into memory (int 0x13, ah = 0x02)
    int 0x13
    jnc .end        ; exit if read succeeded
    dec si          ; decrement remaining attempts
    jc  .end        ; exit if maximum attempts exceeded
    xor ah, ah      ; reset disk system (int 0x13, ah = 0x00)
    int 0x13
    jnc .top        ; retry if reset succeeded, otherwise exit
.end:
    popa
    retn

结果

您打印功能呈彩色显示器(通过0xB8000写显存)。同样,你在实模式。把事情简单化。使用BIOS服务:

Your print function assumes a colour monitor (by writing to video memory at 0xB8000). Again, you're in real mode. Keep it simple. Use a BIOS service:

; print_string_16
;
; Prints a string using BIOS services
;
; input:    ds:si -> string

print_string_16:
    pusha
    mov  ah, 0x0E    ; teletype output (int 0x10, ah = 0x0E)
    mov  bx, 0x0007  ; bh = page number (0), bl = foreground colour (light grey)
.print_char:
    lodsb            ; al = [ds:si]++
    test al, al
    jz   .end        ; exit if null-terminator found
    int  0x10        ; print character
    jmp  .print_char ; repeat for next character
.end:
    popa
    retn

结果

load_sector_2:
    mov  al, 0x01           ; load 1 sector
    mov  bx, 0x7E00         ; destination (might as well load it right after your bootloader)
    mov  cx, 0x0002         ; cylinder 0, sector 2
    mov  dl, [BootDrv]      ; boot drive
    xor  dh, dh             ; head 0
    call read_sectors_16
    jnc  .success           ; if carry flag is set, either the disk system wouldn't reset, or we exceeded our maximum attempts and the disk is probably shagged
    mov  si, read_failure_str
    call print_string_16
    jmp halt                ; jump to a hang routine to prevent further execution
.success:
    ; do whatever (maybe jmp 0x7E00?)


read_failure_str db 'Boot disk read failure!', 13, 10, 0

halt:
    cli
    hlt
    jmp halt

结果

您的bootloader不建立一个堆栈。我公司提供的code使用堆栈prevent寄存器捣毁。有几乎30KiB bootloader之前使用(小于0x7C00),所以你可以简单地做这个地方的附近开始你的引导:

Your bootloader doesn't set up a stack. The code I provided uses the stack to prevent register trashing. There is almost 30KiB available before the bootloader (< 0x7C00), so you can simply do this somewhere near the start of your bootloader:

xor ax, ax
cli         ; disable interrupts to update ss:sp atomically (AFAICT, only required for <= 286)
mov ss, ax
mov sp, 0x7C00
sti

结果

唷!大量消化。请注意,我试图保持独立的功能灵活,所以在其他16位实模式程序可以重新使用它们。我建议你​​尝试写更多模块化code,并坚持这种做法,直到你更有经验。

Phew! A lot to digest. Notice I've tried to keep the standalone functions flexible, so you can re-use them in other 16-bit real mode programs. I'd suggest you try to write more modular code, and stick to this approach until you're more experienced.

例如,如果你在使用扩展​​读取功能死心塌地,也许你应该写一个接受DAP,或指向之一,堆栈上的功能。当然,你会浪费code空间推数据有摆在首位,但一旦它的存在,你可以简单地调整必要的字段为随后的读取,而不是大量的DAP的占用内存。堆栈空间可以在以后收回。

For example, if you're dead set on using the extended read function, perhaps you should write a function that accepts a DAP, or a pointer to one, on the stack. Sure, you'll waste code space pushing the data there in the first place, but once it's there you can simply adjust the necessary fields for subsequent reads, rather than having lots of DAPs taking up memory. The stack space can be reclaimed later.

不要灰心,装配需要时间,而滔天注重细节......在工作中扑不容易,当这个东西出来,所以有可能是在我的code错误! :)

Don't be disheartened, assembly takes time, and monstrous attention to detail... not easy when bashing this stuff out at work, so there might be errors in my code! :)

这篇关于阅读写从INT 13H硬盘的扇区的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆