读取磁盘:LBA方式

LBA简介

磁盘读取发展

IO操作读取硬盘的三种方式:

  • chs方式 :小于8G (8064MB)
  • LBA28方式:小于137GB
  • LBA48方式:小于144,000,000 GB

LBA方式访问使用了data寄存器,LBA寄存器(总共3个),device寄存器,command寄存器来完成的。

LBA28和LBA48方式:

LBA28方式使用28位来描述一个扇区地址,最大支持128GB的硬磁盘容量。

LBA28的寄存器

寄存器 端口 作用
data寄存器 0x1F0 已经读取或写入的数据,大小为两个字节(16位数据)
每次读取1个word,反复循环,直到读完所有数据
features寄存器 0x1F1 读取时的错误信息
写入时的额外参数
sector count寄存器 0x1F2 指定读取或写入的扇区数
LBA low寄存器 0x1F3 lba地址的低8位
LBA mid寄存器 0x1F4 lba地址的中8位
LBA high寄存器 0x1F5 lba地址的高8位
device寄存器 0x1F6 lba地址的前4位(占用device寄存器的低4位)
主盘值为0(占用device寄存器的第5位)
第6位值为1
LBA模式为1,CHS模式为0(占用device寄存器的第7位)
第8位值为1
command寄存器 0x1F7 读取,写入的命令,返回磁盘状态
1 读取扇区:0x20

IDE通道1,读写0x1f0-0x1f7号端口

IDE通道2,读写0x170-0x17f号端口

CHS方式:

写0x1f1: 0

写0x1f2: 要读的扇区数

写0x1f3: 扇区号W

写0x1f4: 柱面的低8位

写0x1f5: 柱面的高8位

写0x1f6: 7~5位,101,第4位0表示主盘,1表示从盘,3~0位,磁头号

写0x1f7: 0x20为读, 0x30为写

读0x1f7: 第4位为0表示读写完成,否则要一直循环等待

读0x1f0: 每次读取1个word,反复循环,直到读完所有数据

24-bit LBA方式:

写0x1f1: 0

写0x1f2: 要读的扇区数

写0x1f3: LBA参数的0~7位

写0x1f4: LBA参数的8~15位

写0x1f5: LBA参数的16~23位

写0x1f6: 7~5位,111,第4位0表示主盘,1表示从盘,3~0位,LBA参数的24~27位

写0x1f7: 0x20为读, 0x30为写

读0x1f7: 第4位为0表示读写完成,否则要一直循环等待

读0x1f0: 每次读取1个word,反复循环,直到读完所有数据

48-bit LBA方式:

写两次0x1f1端口: 0

写两次0x1f2端口: 第一次要读的扇区数的高8位,第二次低8位

写0x1f3: LBA参数的24~31位

写0x1f3: LBA参数的0~7位

写0x1f4: LBA参数的32~39位

写0x1f4: LBA参数的8~15位

写0x1f5: LBA参数的40~47位

写0x1f5: LBA参数的16~23位

写0x1f6: 7~5位,010,第4位0表示主盘,1表示从盘,3~0位,0

写0x1f7: 0x24为读, 0x34为写

LBA和CHS的的对应关系

虽然LBA和CHS的两种定位方式不同,但其实两者间还是有一个转换关系的。

读取硬盘

1)sector count寄存器寄存器写入读取的扇区数

2)LBA low寄存器,LBA mid寄存器,LBA high寄存器写入lba地址

3)device寄存器写入lba地址和读取模式

4)command寄存器写入写入命令

5)读取两个字节数据,多次循环直到读取完扇区数据。

代码

boot.asm

引导文件,初始化屏幕后,读取硬盘并加载4个扇区到内存位置[0x90000]处。然后跳转到0x90000处执行指令。

;Rats OS
;Tab=4
[bits 16]

    org     0x7c00              ;指明程序的偏移的基地址

;----------- loader const ------------------
LOADER_SECTOR_LBA       equ 0x1     ;第2个逻辑扇区开始
LOADER_SECTOR_COUNT     equ 9       ;读取9个扇区
LOADER_BASE_ADDR        equ 0x9000  ;内存地址0x9000
;-------------------------------------------

;引导扇区代码
    jmp     Entry
    db      0x90
    db      "RATSBOOT"          ;启动区的名称可以是任意的字符串(8字节)    

;程序核心内容
Entry:

    ;------------------
    ;初始化寄存器
    mov ax,0
    mov ss,ax
    mov ds,ax
    mov es,ax
    mov ss,ax
    mov fs,ax
    mov gs,ax
    mov sp,0x7c00

    ;------------------
    ;清屏
    mov ah,0x06             ;清除屏幕
    mov al,0
    mov cx,0
    mov dx,0xffff
    mov bh,0x17             ;属性为蓝底白字
    int 0x10

    mov ah,0x02             ;光标位置初始化
    mov dx,0
    mov bh,0
    mov dh,0x0
    mov dl,0x0
    int 0x10

    ;------------------
    ;读取硬盘1-10扇区
    mov ebx,LOADER_SECTOR_LBA       ;LBA扇区号
    mov cx,LOADER_SECTOR_COUNT      ;读取扇区数
    mov di,LOADER_BASE_ADDR         ;写入内存地址
    call Func_ReadLBA16

    jmp LOADER_BASE_ADDR

; ------------------------------------------------------------------------
; 读取磁盘:Func_ReadLBA16
; 参数:
; ebx 扇区逻辑号
; cx 读入的扇区数,8位
; di 读取后的写入内存地址
; ------------------------------------------------------------------------
Func_ReadLBA16:
    ;设置读取的扇区数
    mov al,cl
    mov dx,0x1F2
    out dx,al

    ;设置lba地址
    ;设置低8位
    mov al,bl
    mov dx,0x1F3
    out dx,al

    ;设置中8位
    shr ebx,8
    mov al,bl
    mov dx,0x1F4
    out dx,al

    ;设置高8位
    shr ebx,8
    mov al,bl
    mov dx,0x1F5
    out dx,al

    ;设置高4位和device
    shr ebx,8
    and bl,0x0F
    or bl,0xE0
    mov al,bl
    mov dx,0x1F6
    out dx,al

    ;设置commond
    mov al,0x20
    mov dx,0x1F7
    out dx,al

.check_status:;检查磁盘状态
    nop
    in al,dx
    and al,0x88         ;第4位为1表示硬盘准备好数据传输,第7位为1表示硬盘忙
    cmp al,0x08
    jnz .check_status   ;磁盘数据没准备好,继续循环检查

    ;设置循环次数到cx
    mov ax,cx           ;乘法ax存放目标操作数
    mov dx,256
    mul dx
    mov cx,ax           ;循环次数 = 扇区数 x 512 / 2
    mov bx,di
    mov dx,0x1F0

.read_data:
    in ax,dx            ;读取数据
    mov [bx],ax         ;复制数据到内存
    add bx,2            ;读取完成,内存地址后移2个字节

    loop .read_data
    ret

FillSector:
    resb    510-($-$$)          ;处理当前行$至结束(1FE)的填充
    db      0x55, 0xaa

loader.asm

被引导扇区加载到0x90000位置,执行输出hello in loader文字

;Rats OS
;Tab=4
[bits 16]

section loader vstart=LOADER_BASE_ADDR ;指明程序的偏移的基地址

;----------- loader const ------------------
LOADER_BASE_ADDR        equ 0x9000  ;内存地址0x9000
;---------------------------------------
    jmp Entry

;程序核心内容
Entry:

    ;---------------------------
    ;输出字符串
    mov si,HelloMsg         ;将HelloMsg的地址放入si
    mov dh,0                ;设置显示行
    mov dl,0                ;设置显示列
    call Func_Sprint            ;调用函数

    jmp $           ;让CPU挂起,等待指令

; ------------------------------------------------------------------------
; 显示字符串函数:Func_Sprint
; 参数:
; si = 字符串开始地址,
; dh = 第N行,0开始
; dl = 第N列,0开始
; ------------------------------------------------------------------------
Func_Sprint:
            mov cx,0            ;BIOS中断参数:显示字符串长度
            mov bx,si
    .len:;获取字符串长度
            mov al,[bx]         ;读取1个字节到al
            inc bx              ;读取下个字节
            cmp al,0            ;是否以0结束
            je .sprint
            inc cx              ;计数器
            jmp .len
    .sprint:;显示字符串
            mov bx,si
            mov bp,bx
            mov bx,ds
            mov es,bx           ;BIOS中断参数:计算[ES:BP]为显示字符串开始地址

            mov ah,0x13         ;BIOS中断参数:中断模式
            mov al,0x01         ;BIOS中断参数:输出方式
            mov bh,0x0          ;BIOS中断参数:指定分页为0
            mov bl,0x1F         ;BIOS中断参数:显示属性,指定白色文字
            int 0x10            ;调用BIOS中断操作显卡。输出字符串
            ret
; ------------------------------------------------------------------------
;准备显示字符串
HelloMsg: db "hello in loader!",0
    times   512-($-$$) db  0 ; 处理当前行$至结束(1FE)的填充    

运行

创建Makefile文件,并执行make命令

# tools
PLATFORM=Linux
NASM=nasm
QEMU=qemu-system-x86_64
QEMU-IMG=qemu-img
BOCHS=bochs
BX-IMG=bximage

# args
boot=boot
build=build

target: prepare img
    $(BOCHS) -f bochsrc.me

img: $(build)/ratsos.img
    @echo "build img completed"

$(build)/ratsos.img:$(build)/boot.bin $(build)/loader.bin
    $(BX-IMG) -hd -mode=flat -size=32 -q $(build)/ratsos.img
    sleep 1
    dd if=$(build)/boot.bin of=$(build)/ratsos.img bs=512 count=1  conv=notrunc
    dd if=$(build)/loader.bin of=$(build)/ratsos.img bs=512 count=1 seek=1 conv=notrunc

$(build)/%.bin: $(boot)/%.asm
    $(NASM) -f bin -o $(build)/$*.bin $(boot)/$*.asm    

prepare: $(build)
    @echo "prepare dir $(build)"
    ifeq ($(build), $(wildcard $(build)))
        @echo "build directory exist..."
    else
        mkdir -p $(build)
    endif

clean:
    @echo "clean dir $(build)"
    rm -rf $(build)/*

platform:
    @echo $(PLATFORM)

运行结果

原文地址:https://www.cnblogs.com/mlzrq/p/10223060.html

时间: 2024-10-15 12:25:34

读取磁盘:LBA方式的相关文章

读取磁盘:CHS方式

读取磁盘:CHS方式 BIOS读取磁盘 读取磁盘也是调用BIOS: 中断命令: INT 13H 读取扇区的入口参数为 AH = 02H 功能参数,读取扇区 AL = 扇区数 CH = 柱面 CL = 扇区 DH = 磁头 DL = 驱动器号,00H~7FH:软盘驱动器号:80H~0FFH:硬盘驱动器号 ES:BX = 缓冲区的地址 出口参数 CF = 0: 操作成功,AH = 00H,AL = 传输的扇区数 否则,AH = 状态代码 定义磁盘读取函数 1. 读取一个扇区 ; ----------

通过DeviceIoControl读磁盘的方式读取独占文件内容

前言 windows操作系统中常见的一个文件存储系统是NTFS.在这个文件系统中MFT是它的核心.             图一 MFT是一个数据结构,上图是它的结构,它主要用来存放每个文件和目录在磁盘中的索引.MFT由一个个MFT项构成.每个MFT项的大小是1024Bytes.每个MFT项由固定头结构和多个属性构成.属性用来记录与文件相关的信息.每个属性又由属性头和属性体构成.属性头包含了一些该属性的重要信息,如属性类型.属性大小.是否为常驻属性等等.[1]文件内容也被NTFS看作属性.  其

【原创】Android 4.4前后版本读取图库图片方式的变化

Android 4.4前后版本读取图库图片方式的变化 本文讲述Android 4.4(KitKat)前后访问图库以及访问后通过图片路径读取图片的变化 Android 4.4(KitKat)以前: 访问图库(方法一): 1 /** 2 * Access the gallery to pick up an image. 3 */ 4 private void startPickPhotoActivity() { 5 Intent intent = new Intent(Intent. ACTION_

C3P0数据库连接池-方式2读取配置文件的方式

package com.itheima.c_c3p0; import java.sql.Connection; import java.sql.SQLException; import javax.sql.DataSource; import com.mchange.v2.c3p0.ComboPooledDataSource; public class C3P0Utils { //提供连接池 private static DataSource dataSource = new ComboPool

Java读取配置文件的方式

Java读取配置文件的方式-笔记 1       取当前启动目录下的配置文件 一般来讲启动java程序的时候,在启动的目录下会有配置文件 classLoader.getResource("").getFile()  会取到java当前启动项目的目录,然后指定对应的配置文件路径即可比如conf/conf.properties //取当前启动目录的配置文件 String filePath =classLoader.getResource("").getFile()+&q

Windows Server 2003中报PerfDisk “无法从系统读取磁盘性能信息。”的问题解决

现象描述: 服务器经常在午夜,自动死机,无法连接外网,查询日志报如下错误: " 无法从系统读取磁盘性能信息. 必须至少有一个物理磁盘或逻辑磁盘卷启用了 "磁盘性能计数器",这些计数器才会出现. 可以使用"硬件设备管理器"属性页来启用磁盘性能计数器. 返回的状态码是数据 DWORD 0. " 解决办法: 这是没有启用"磁盘性能计数器",可以在命令行下执行:diskperf -y 来启用! 更详细的可以执行diskperf /?

无法从系统读取磁盘性能信息

    有时候系统日志会不断出现:"无法从系统读取磁盘性能信息. 必须至少有一个物理磁盘或逻辑磁盘卷启用了 "磁盘性能计数器",这些计数器才会出现. 可以使用"硬件设备管理器"属性页来启用磁盘性能计数器. 返回的状态码是数据 DWORD 0. "而且频繁出现,一会你的日志就满了,一般都是有多块硬盘等原因引起的,解决办法可以参考以下参数: Diskperf(控制计数器的类型,这些计数器可以用系统监视器查看.) 命令参数: diskperf [-y[

Windows Server 2003中报PerfDisk “无法从系统读取磁盘性能信息。

Windows Server 2003中报PerfDisk "无法从系统读取磁盘性能信息."的问题解决 2015-01-22 09:49:02 标签:Windows Server2003 PerfDisk 磁盘性能计数器 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://huangfuff.blog.51cto.com/2632203/1606861 现象描述: 服务器经常在午夜,自动死机,无法连接外网,查询日志报如下

面试题目java读取文本内容方式

面试题目java读取文本内容方式二种方式 第一种通过FileInputStream()方式读取 FileInputStream fis = new FileInputStream("a.txt"); //创建流对象 byte[] arr = new byte[4]; int len; while((len = fis.read(arr)) != -1) { System.out.print(new String(arr,0,len)); } fis.close(); 第二种通过:Fil