如何使用x86汇编对硬盘进行读写

     硬盘读写的基本单位是扇区。就是说,要读就至少读一个扇区,要写就至少写一个扇区,不可能仅读写一个扇区中的几个字节。这样一来,就使得主机和硬盘之间的数据交换是成块的,所以硬盘是典型的块设备。

     从硬盘读写数据,最经典的方式是向硬盘控制器分别发送磁头号、柱面号和扇区号(扇区在某个柱面上的编号),这称为 CHS 模式。这种方法最原始,最自然,也最容易理解。

    最早的逻辑扇区编址方法是LBA28,使用 28 个比特来表示逻辑扇区号,从逻辑扇区 0x0000000 到 0xFFFFFFF,共可以表示 2 ^28=268435456个扇区。每个扇区有512 字节,所以 LBA28 可以管理 128 GB 的硬盘。

   但是硬盘技术发展得非常快,最新的硬盘已经达到几百个吉字节的容量,LBA28 已经落后了。在这种情况下,业界又共同推出了 LBA48,采用 48 个比特来表示逻辑扇区号。如此一来,就可以管理131072 TB 的硬盘容量了。在这里我们采用将采用 LBA28 来访问硬盘。

  第 1 步:

       设置要读取的扇区数量。这个数值要写入 0x1f2 端口。这是个 8 位端口,因此每次只能读写 255 个扇区:

            mov dx,0x1f2

    mov al,0x01    ;1 个扇区

            out dx,al

       注意:如果写入的值为 0,则表示要读取 256 个扇区。每读一个扇区,这个数值就减一。因此,如果在读写过程中发生错误,该端口包含着尚未读取的扇区数。

   第 2 步:

     设置起始 LBA 扇区号。扇区的读写是连续的,因此只需要给出第一个扇区的编号就可以了。28 位的扇区号太长,需要将其分成 4 段,分别写入端口 0x1f3、0x1f4、0x1f5 和 0x1f6 号端口。其中,0x1f3 号端口存放的是 0~7 位;0x1f4 号端口存放的是 8~15 位;0x1f5 号端口存放的是 16~23 位,最后 4 位在 0x1f6 号端口。假定我们要读写的起始逻辑扇区号为 0x02,可编写代码

  如下:

      mov dx,0x1f3

      mov al,0x02

      out dx,al ;LBA 地址 7~0

      inc dx ;0x1f4

      mov al,0x00

      out dx,al ;LBA 地址 15~8

      inc dx ;0x1f5

      out dx,al ;LBA 地址 23~16

      inc dx ;0x1f6

      mov al,0xe0 ;LBA模式,主硬盘,以及 LBA 地址 27~24

      out dx,al

   第 3 步:

      向端口 0x1f7 写入 0x20,请求硬盘读。这也是一个8 位端口:

       mov dx,0x1f7

       mov al,0x20   ;读命令

       out dx,al

   第 4 步:

      等待读写操作完成。端口0x1f7 既是命令端口,又是状态端口。在通过这个端口发送读写命令之后,硬盘就忙乎开了。如图 8-12 所示,在它内部操作期间,它将 0x1f7 端口的第 7 位置“1”,表明自己很忙。一旦硬盘系统准备就绪,它再将此位清零,说明自己已经忙完了,同时将第 3位置“1”,意思是准备好了,请求主机发送或者接收数据(图 8-12)。完成这一步的典型代码如下:

      mov dx,0x1f7

     .waits:

         in al,dx

         and al,0x88

         cmp al,0x08

         jnz .waits

  第 5 步:

    连续取出数据。0x1f0 是硬盘接口的数据端口,而且还是一个 16 位端口。一旦硬盘控制器空闲,且准备就绪,就可以连续从这个端口写入或者读取数据。下面的代码假定是从硬盘读一个扇区(512 字节,或者 256 字节),读取的数据存放到由段寄存器 DS 指定的数据段,偏移地址由寄存器 BX 指定:

     mov cx,256   ;总共要读取的字数

     mov dx,0x1f0

    .readw:

        in ax,dx

        mov  [bx],ax

        add bx,2

        loop .readw

  • 12
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
好的,以下是x86汇编代码: ``` section .data msg db 'Enter an integer between 0 and 20: $' summsg db 'The sum of cubes from 0 to %d is %d$' nl db 0dh, 0ah, '$' x db ? sum dw 0 section .text global _start _start: ; print message and read input mov eax, 4 ; system call for write mov ebx, 1 ; file descriptor for stdout mov ecx, msg mov edx, 31 ; message length int 0x80 mov eax, 3 ; system call for read mov ebx, 0 ; file descriptor for stdin mov ecx, x mov edx, 1 ; number of bytes to read int 0x80 sub byte [x], '0' ; convert character to number ; calculate sum of cubes xor ecx, ecx ; clear ecx mov ax, 0 ; clear ax loop1: cmp cl, [x] jg done push ecx ; save ecx on stack mov ebx, ecx mov ax, cx ; calculate cube of cx mul cx mul bx add [sum], ax ; add cube to sum pop ecx ; restore ecx inc cl ; increment ecx jmp loop1 done: ; print sum of cubes mov eax, 4 ; system call for write mov ebx, 1 ; file descriptor for stdout mov ecx, nl mov edx, 2 ; message length int 0x80 mov eax, 4 ; system call for write mov ebx, 1 ; file descriptor for stdout mov ecx, summsg mov edx, 31 ; message length int 0x80 mov eax, [sum] ; move sum to eax mov ebx, 10 ; set ebx to 10 xor ecx, ecx ; clear ecx xor edx, edx ; clear edx loop2: div ebx ; divide eax by 10 add edx, '0' ; convert remainder to character push edx ; push remainder onto stack inc cl ; increment ecx cmp eax, 0 ; check if quotient is zero jne loop2 print: pop edx ; pop remainder from stack mov eax, 4 ; system call for write mov ebx, 1 ; file descriptor for stdout mov ecx, edx mov edx, 1 ; message length int 0x80 loop print ; loop until stack is empty mov eax, 1 ; system call for exit xor ebx, ebx ; exit status int 0x80 ``` 这个程序与之前的程序非常相似,只不过使用x86汇编语言,并使用了Linux系统调用来进行输入和输出。请注意,Linux系统调用使用`int 0x80`指令来触发,而不是`int 21h`。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值