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 写入扇区:0x30
磁盘识别:0xEC

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

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

CHS方式:

写0x1f1: 0

写0x1f2: 要读的扇区数

写0x1f3: 扇区号W

写0x1f4: 柱面的低8位

写0x1f5: 柱面的高8位

写0x1f6: 75位,101,第4位0表示主盘,1表示从盘,30位,磁头号

写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: 75位,111,第4位0表示主盘,1表示从盘,30位,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: 75位,010,第4位0表示主盘,1表示从盘,30位,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)

运行结果

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

  1. 读取磁盘:CHS方式

    读取磁盘:CHS方式 BIOS读取磁盘 读取磁盘也是调用BIOS: 中断命令: INT 13H 读取扇区的入口参数为 AH = 02H 功能参数,读取扇区 AL = 扇区数 CH = 柱面 CL = ...

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

    前言 windows操作系统中常见的一个文件存储系统是NTFS.在这个文件系统中MFT是它的核心.             图一 MFT是一个数据结构,上图是它的结构,它主要用来存放每个文件和目录在磁 ...

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

    Android 4.4前后版本读取图库图片方式的变化   本文讲述Android 4.4(KitKat)前后访问图库以及访问后通过图片路径读取图片的变化   Android 4.4(KitKat)以前 ...

  4. python读取配置文件的方式

    python读取配置文件的方式 1.从config.ini中读取,后缀无所谓,文件名字也无所谓,不过config.ini是常用写法,所谓见名知意 config.ini内容: [global] ip = ...

  5. JavaWeb中servlet读取配置文件的方式

    我们在JavaWeb中常常要涉及到一些文件的操作,比如读取配置文件,下载图片等等操作.那我们能不能采用我们以前在Java工程中读取文件的方式呢?废话不多说我们来看看下我们以前在Java工程中读取文件是 ...

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

    Windows Server 2003中报PerfDisk “无法从系统读取磁盘性能信息.”的问题解决 2015-01-22 09:49:02 标签:Windows Server2003 PerfDi ...

  7. Java读取配置文件的方式

    Java读取配置文件的方式-笔记 1       取当前启动文件夹下的配置文件   一般来讲启动java程序的时候.在启动的文件夹下会有配置文件 classLoader.getResource(&qu ...

  8. linux初学者-磁盘分区方式篇

    linux初学者-磁盘分区方式篇 一般的计算机都会采用mbr分区方式,这种分区方式只能够建立四个主分区,如果还需要或更多的分区,就需要将其中一个主分区建立成一个扩展分区,在里面建立逻辑分区,这些分区信 ...

  9. Java 将数据写入磁盘并读取磁盘上的文件

    package test; import java.io.BufferedReader;import java.io.FileReader;import java.io.FileWriter;impo ...

随机推荐

  1. 133. Clone Graph(图的复制)

    Given the head of a graph, return a deep copy (clone) of the graph. Each node in the graph contains ...

  2. PM九步法

    本文转载自网络. 多年以后,当我面对那些年青的产品经理,我会想起自己当年从事的是一份高薪的工作.那是2000年,我大学毕业后在北京一家IT网站做搜索引擎PM,当时我一个月的薪水能在亚运村买一平方米房子 ...

  3. Vue单元测试Karma+Mocha

    Vue单元测试Karma+Mocha Karma是一个基于Node.js的JavaScript测试执行过程管理工具(Test Runner).该工具在Vue中的主要作用是将项目运行在各种主流Web浏览 ...

  4. Redis学习-hash数据类型

    hash 类型是string类型的field和value的映射表,或者说是一个string集合,适合存储对象,相比较而言,将一个对象类型存储在hash类型里要比存储在string类型里占用更少的内存空 ...

  5. 使用现有的appid和appsecret无法打开二维码

    在微信公众平台申请的现有的appid和appsecret无法打开二维码 因为已有的appid和appsecret是微信公众平台认证的,没有在开放平台认证,所以会显示 "Scope参数错误或者 ...

  6. [C++ Primer Plus] 第3章、处理数据(二)课后习题

    1 . 编写一个小程序,要求用户使用一个整数输出自己的身高(单位为厘米),然后将身高转换为米和厘米.该程序使用下划线字符来指示输入位置.另外,使用一个 const 符号常量来表示转换因子. #incl ...

  7. yaf

    一.yaf使用自定义的类 Yaf的library和model的文件命名规则和调用:https://www.cnblogs.com/leedom/p/9396138.html 安装参考: https:/ ...

  8. Python新手入门英文词汇笔记(1-2)

    英文词汇总结一.循环1.for…in…循环的使用2.while…循环的使用本节英文单词与中文释义:1.for:因为2.while:当…时…3.range:范围4.sep(separate):分隔5.f ...

  9. 尚硅谷面试第一季-17Redis 在项目中的使用场景

    数据类型 使用场景 String 比如说 ,我想知道什么时候封锁一个IP地址.Incrby命令 Hash 存储用户信息[id,name,age] Hset(key,field,value) Hset( ...

  10. flask --- 01 .初始

    一. 四种web框架比较 Django : 优点 - 大而全所有组件都是有组织内部开发高度定制化 教科书级别的框架 缺点 - 大到浪费资源,请求的时候需要的资源较高 Flask : 优势 - 小而精, ...