读取磁盘: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 写入扇区: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方式的更多相关文章
- 读取磁盘:CHS方式
读取磁盘:CHS方式 BIOS读取磁盘 读取磁盘也是调用BIOS: 中断命令: INT 13H 读取扇区的入口参数为 AH = 02H 功能参数,读取扇区 AL = 扇区数 CH = 柱面 CL = ...
- 通过DeviceIoControl读磁盘的方式读取独占文件内容
前言 windows操作系统中常见的一个文件存储系统是NTFS.在这个文件系统中MFT是它的核心. 图一 MFT是一个数据结构,上图是它的结构,它主要用来存放每个文件和目录在磁 ...
- 【原创】Android 4.4前后版本读取图库图片方式的变化
Android 4.4前后版本读取图库图片方式的变化 本文讲述Android 4.4(KitKat)前后访问图库以及访问后通过图片路径读取图片的变化 Android 4.4(KitKat)以前 ...
- python读取配置文件的方式
python读取配置文件的方式 1.从config.ini中读取,后缀无所谓,文件名字也无所谓,不过config.ini是常用写法,所谓见名知意 config.ini内容: [global] ip = ...
- JavaWeb中servlet读取配置文件的方式
我们在JavaWeb中常常要涉及到一些文件的操作,比如读取配置文件,下载图片等等操作.那我们能不能采用我们以前在Java工程中读取文件的方式呢?废话不多说我们来看看下我们以前在Java工程中读取文件是 ...
- Windows Server 2003中报PerfDisk “无法从系统读取磁盘性能信息。
Windows Server 2003中报PerfDisk “无法从系统读取磁盘性能信息.”的问题解决 2015-01-22 09:49:02 标签:Windows Server2003 PerfDi ...
- Java读取配置文件的方式
Java读取配置文件的方式-笔记 1 取当前启动文件夹下的配置文件 一般来讲启动java程序的时候.在启动的文件夹下会有配置文件 classLoader.getResource(&qu ...
- linux初学者-磁盘分区方式篇
linux初学者-磁盘分区方式篇 一般的计算机都会采用mbr分区方式,这种分区方式只能够建立四个主分区,如果还需要或更多的分区,就需要将其中一个主分区建立成一个扩展分区,在里面建立逻辑分区,这些分区信 ...
- Java 将数据写入磁盘并读取磁盘上的文件
package test; import java.io.BufferedReader;import java.io.FileReader;import java.io.FileWriter;impo ...
随机推荐
- 133. Clone Graph(图的复制)
Given the head of a graph, return a deep copy (clone) of the graph. Each node in the graph contains ...
- PM九步法
本文转载自网络. 多年以后,当我面对那些年青的产品经理,我会想起自己当年从事的是一份高薪的工作.那是2000年,我大学毕业后在北京一家IT网站做搜索引擎PM,当时我一个月的薪水能在亚运村买一平方米房子 ...
- Vue单元测试Karma+Mocha
Vue单元测试Karma+Mocha Karma是一个基于Node.js的JavaScript测试执行过程管理工具(Test Runner).该工具在Vue中的主要作用是将项目运行在各种主流Web浏览 ...
- Redis学习-hash数据类型
hash 类型是string类型的field和value的映射表,或者说是一个string集合,适合存储对象,相比较而言,将一个对象类型存储在hash类型里要比存储在string类型里占用更少的内存空 ...
- 使用现有的appid和appsecret无法打开二维码
在微信公众平台申请的现有的appid和appsecret无法打开二维码 因为已有的appid和appsecret是微信公众平台认证的,没有在开放平台认证,所以会显示 "Scope参数错误或者 ...
- [C++ Primer Plus] 第3章、处理数据(二)课后习题
1 . 编写一个小程序,要求用户使用一个整数输出自己的身高(单位为厘米),然后将身高转换为米和厘米.该程序使用下划线字符来指示输入位置.另外,使用一个 const 符号常量来表示转换因子. #incl ...
- yaf
一.yaf使用自定义的类 Yaf的library和model的文件命名规则和调用:https://www.cnblogs.com/leedom/p/9396138.html 安装参考: https:/ ...
- Python新手入门英文词汇笔记(1-2)
英文词汇总结一.循环1.for…in…循环的使用2.while…循环的使用本节英文单词与中文释义:1.for:因为2.while:当…时…3.range:范围4.sep(separate):分隔5.f ...
- 尚硅谷面试第一季-17Redis 在项目中的使用场景
数据类型 使用场景 String 比如说 ,我想知道什么时候封锁一个IP地址.Incrby命令 Hash 存储用户信息[id,name,age] Hset(key,field,value) Hset( ...
- flask --- 01 .初始
一. 四种web框架比较 Django : 优点 - 大而全所有组件都是有组织内部开发高度定制化 教科书级别的框架 缺点 - 大到浪费资源,请求的时候需要的资源较高 Flask : 优势 - 小而精, ...