读取磁盘:LBA方式 以及 CHS方式

https://www.cnblogs.com/mlzrq/p/10223060.html

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寄存器0x1F3lba地址的低8位
LBA mid寄存器0x1F4lba地址的中8位
LBA high寄存器0x1F5lba地址的高8位
device寄存器0x1F6lba地址的前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: 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)

运行结果

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值