babyos (三)——利用BIOS INT 0x13读取软盘
注:以下程序为原创,若发现任何BUG,欢迎指正;若有问题,欢迎交流;权利归原作者所有,若转载,请注明出处;若能有益于一二访客,幸甚。
昨天学习了VGA显示的一些东西,今天准备学习一下读取软盘的知识。
1.babyos将使用的引导过程
1)系统上电或reset时,处理器执行一些初始化,CPU处于实模式
2)处理器会执行一个位于已知位置处的代码,PC中这个位置位于BIOS,它保存在主板上的闪存中
3)控制权交给BIOS后,它寻找一个可引导的设备(软盘、硬盘等),BIOS读取引导扇区(512字节)到内存0x7c00处,并跳转到该地址执行
4)引导扇区中存放的指令可以使用BIOS中断,它将会读取软盘中内核部分到一个临时地址(如0x10000,不覆盖0x7c00处的boot代码即可)
5)将内核前512字节(load.s, 它主要负责将内核剩余部分拷贝到load.s后面)移动到0x0处,将GDT拷贝到0x80000处。为什么不一次全部将内核放到0x0处呢?因为内核可能较大,会覆盖掉0x7c00处的代码。
6)开启A20总线,置位CR0的bit 0,开启保护模式,加载GDT到GDTR,跳转到GDT第二项(第一项为空GDT),即load.s处执行
7)load.s将内核剩余部分移动到load.s后面,即0x200开始的地址处。然后执行初始化代码。
8)初始化代码,至此系统启动成功。
所以首当其冲的问题就是如何读软盘。
2.软盘的结构
3.5寸1.44M 软盘,如图floppy_struct.png 所示,有两个磁头,正反两面各一个;80个磁道(即80个圆圈);每个磁道有18个扇区;每个扇区为512字节。
容量 = 512字节/扇区 * 2面 * 80磁道(柱面)/面 * 18扇区/磁道 = 1440 KB
磁头,即面:编号[0, 1]
80个磁道,即柱面(圆圈):编号[0, 79]
18个扇区:编号[1, 18]
相对扇区号[0, 2879]:
相对扇区号按照柱面排序,即从最外头的圆圈到最里头的圆圈。
0柱面正面(即磁头号为0)的1-18扇区为0-17号相对扇区,0柱面反面(即磁头号为2)的1-18扇区为18-35号相对扇区,然后是1柱面,2柱面,直到79柱面。如下:
- 0柱面,0磁头,1扇区 0
- 0柱面,0磁头,2扇区 1
- ……
- 0柱面,0磁头,18扇区 17
- 0柱面,1磁头,1扇区 18
- ……
- 0柱面,1磁头,18扇区 35
- 1柱面,0磁头,1扇区 36
- ……
- 1柱面,0磁头,18扇区 53
- 1柱面,1磁头,1扇区 54
- ……
- 1柱面,1磁头,18扇区 71
- 2柱面,0磁头,1扇区 72
- ……
3.利用BIOS 中断读取软盘
- -------------------------------------------------------------------
- INT 0x13,功能02
- -----------------------------------------------------------
- 参数:
- AH 02
- AL 读取扇区数
- CH 柱面[0, 79]
- CL 扇区[1, 18]
- DH 磁头[0, 1]
- DL 驱动器(0x0 ~ 0x7f表示软盘,0x80 ~ 0xff表示硬盘)
- ES:BX 缓冲区地址,即数据读到这里
- 返回值:
- CF = 0表示操作成功,此时AH=0,AL=传输的扇区数
- CF = 1即carry位置位(可用JC表示跳转)表示操作失败,AH=状态代码
- --------------------------------------------------------------------
4.相对扇区号的计算
1)知道柱面号,磁头号,扇区号计算相对扇区号
由上面可知0号柱面包含了相对扇区号[0,35],1号柱面包含相对扇区号[36,71],依次类推。
设相对扇区号为N,则
柱面号CH = N / 36;
令x = N % 36;
则x范围为[0,35],其中[0,17] 为磁头号0, [18,35]为磁头号1.
则磁头号DH = x / 18;
零y = x % 18; y范围[0, 17]
则扇区号CL = y + 1。
2)知道相对扇区号,计算柱面号、磁头号、扇区号
N = 36*CH + 18*DH + CL;
由此式子,也可计算:
CH = N / 36
DH = (N % 36) / 18
CL = (N % 36) % 18 + 1
5.读取一个扇区
实验:将一些数据写入软盘的第二个扇区(第一个扇区是引导扇区),然后用BIOS 中断读取该扇区的数据,并显示在屏幕上。然后看读取的数据是否与写入的数据相同。注:第二个扇区相对扇区号为1.
- 写数据的C代码:
- /*************************************************************************
- > File: write_data.c
- > Author: 孤舟钓客
- > Mail: guzhoudiaoke@126.com
- > Time: 2012年12月26日 星期三 01时20分26秒
- ************************************************************************/
- #include <stdio.h>
- #include <string.h>
- int main()
- {
- FILE *fp;
- fp = fopen("./data", "wb");
- int i;
- char *str = "baby os, guzhoudiaoke@126.com ";
- int len = strlen(str);
- for (i = 0; i < len; i++)
- fprintf(fp, "%c", str[i]);
- for (i = 512-len; i > 0; i--)
- fprintf(fp, "%c", i % 26 + 'A');
- return 0;
- }
- 汇编代码:
- # This program draws color pixels at mode 0x13
- # 2012-12-26 01:31
- # guzhoudiaoke@126.com
- .include "boot.inc"
- .section .text
- .global _start
- .code16
- _start:
- jmp main
- #--------------------------------------------------------------
- # 清屏函数:
- # 设置屏幕背景色,调色板的索引0指代的颜色为背景色
- clear_screen: # 清屏函数
- movb $0x06, %ah # 功能号0x06
- movb $0, %al # 上卷全部行,即清屏
- movb $0, %ch # 左上角行
- movb $0, %ch # 左上角列
- movb $24, %dh # 右下角行
- movb $79, %dl # 右下角列
- movb $0x07, %bh # 空白区域属性
- int $0x10
- ret
- #---------------------------------------------------------------
- # 直接写显存显示一些文字函数:
- # 调用前需要设置DS:SI为源地址,DI为显示位置,
- # CX 为显示的字符个数, AL为颜色属性
- draw_some_text:
- # ES:DI is the dst address, DS:SI is the src address
- movw $VIDEO_SEG_TEXT, %bx
- movw %bx, %es
- copy_a_char:
- movsb
- stosb
- loop copy_a_char
- ret
- #----------------------------------------------------------------
- # 读取软盘第二个扇区:
- # 使用BIOS INT 0x13中断,使用前需要设置ES:BX作为缓冲区
- read_one_sect:
- movb $0x02, %ah # 功能号
- movb $0x01, %al # 读取扇区数
- movb $0x00, %ch # 柱面号
- movb $0x02, %cl # 扇区号
- movb $0x00, %dh # 磁头号
- movb $0x00, %dl # 驱动器号
- re_read: # 若调用失败则重新调用
- int $0x13
- jc re_read # 若进位位(CF)被置位,表示调用失败
- ret
- main:
- movw %cx, %ax
- movw %ax, %ds
- movw %ax, %es
- call clear_screen # 清屏
- movw $0, %ax
- movw %ax, %ds
- leaw msg_str, %si
- xorw %di, %di
- movw msg_len, %cx
- movb $TEXT_COLOR,%al
- call draw_some_text # 绘制字符串
- movw $BUFFER_SEG,%ax
- movw %ax, %es # ES:BX 为缓冲区地址
- xorw %bx, %bx
- call read_one_sect
- # 下面调用绘制函数,在屏幕上显示读取的信息
- movw $BUFFER_SEG,%ax
- movw %ax, %ds # ds:si 为源地址
- xorw %si, %si
- movw $160, %di # 第一行已经打印了msg_str,从第二行开始显示
- movw $512, %cx # 显示512个字符
- movb $0x01, %al
- call draw_some_text
- 1:
- jmp 1b
- msg_str:
- .asciz "The data of the second sect of the floppy (sect 1):"
- msg_len:
- .int . - msg_str - 1
- .org 0x1fe, 0x90
- .word 0xaa55
实验结果:
6.读取任意扇区(给定相对扇区号)
实验,写用C语言写入文件,该文件包含512个‘a’,512个1……512个‘z’, 循环50次,将该文件写入软盘(相对扇区号1~50*26),然后读取给定的相对扇区号的扇区,将读取的内容打印到屏幕上。并与写入的数据比较,验证读取的正确性。
- C代码用于写文件:
- /*************************************************************************
- > File: write_data.c
- > Author: 孤舟钓客
- > Mail: guzhoudiaoke@126.com
- > Time: 2012年12月26日 星期三 20时16分45秒
- ************************************************************************/
- #include <stdio.h>
- #include <string.h>
- int main(int argc, char *argv[])
- {
- if (argc != 2)
- {
- printf("usage: ./write_data file_name");
- exit(0);
- }
- FILE *fp;
- fp = fopen(argv[1], "wb");
- int i, j, k;
- for (i = 0; i < 50; i++)
- {
- for (j = 'a'; j <= 'z'; j++)
- {
- for (k = 0; k < 512; k++)
- {
- fprintf(fp, "%c", (char)j);
- }
- }
- }
- return 0;
- }
- 汇编代码:
- # This program draws color pixels at mode 0x13
- # 2012-12-26 20:23:42
- # guzhoudiaoke@126.com
- .include "boot.inc"
- .section .text
- .global _start
- .code16
- _start:
- jmp main
- #--------------------------------------------------------------
- # 清屏函数:
- # 设置屏幕背景色,调色板的索引0指代的颜色为背景色
- clear_screen: # 清屏函数
- movb $0x06, %ah # 功能号0x06
- movb $0, %al # 上卷全部行,即清屏
- movb $0, %ch # 左上角行
- movb $0, %ch # 左上角列
- movb $24, %dh # 右下角行
- movb $79, %dl # 右下角列
- movb $0x07, %bh # 空白区域属性
- int $0x10
- ret
- #---------------------------------------------------------------
- # 直接写显存显示一些文字函数:
- # 调用前需要设置DS:SI为源地址,DI为在屏幕上的显示位置,
- # CX 为显示的字符个数, AL为颜色属性
- draw_some_text:
- # ES:DI is the dst address, DS:SI is the src address
- movw $VIDEO_SEG_TEXT, %bx
- movw %bx, %es
- copy_a_char:
- movsb
- stosb
- loop copy_a_char
- ret
- #----------------------------------------------------------------
- # 读取软盘一个扇区:
- # 使用BIOS INT 0x13中断,使用前需要设置ES:BX作为缓冲区
- # AX为相对扇区号
- read_one_sect:
- movb $36, %dl
- divb %dl
- movb %al, %ch # 柱面号=N / 36, 假设x = N % 36
- movb %ah, %al # AL = N % 36
- movb $0, %ah # AX = N % 36
- movb $18, %dl
- divb %dl
- movb %al, %dh # 磁头号DH = x / 18
- movb %ah, %cl
- incb %cl # 扇区号CL = x % 18 + 1
- movb $0x00, %dl # 驱动器号DL
- movb $0x02, %ah # 功能号
- movb $0x01, %al # 读取扇区数
- re_read: # 若调用失败则重新调用
- int $0x13
- jc re_read # 若进位位(CF)被置位,表示调用失败
- ret
- #-------------------------------------------------------------------
- # 该函数读取指定的若干扇区号
- # 需要指定ES:BX作为缓冲区
- read_sects:
- movw $0x00, %si # 已经读取的扇区数
- leaw sect_no, %di
- 1:
- movw (%di), %ax # 获取相对扇区号
- addw $2, %di
- call read_one_sect
- incw %si
- incw %bx
- cmpw num_to_read, %si
- jne 1b
- ret
- main:
- movw %cx, %ax
- movw %ax, %ds
- movw %ax, %es
- call clear_screen # 清屏
- # 显示提示信息
- movw $0, %ax
- movw %ax, %ds
- leaw msg_str, %si
- xorw %di, %di
- movw msg_len, %cx
- movb $TEXT_COLOR,%al
- call draw_some_text # 绘制字符串
- # 读取软盘
- movw $BUFFER_SEG, %ax
- movw %ax, %es # ES:BX 为缓冲区地址
- xorw %bx, %bx
- call read_sects
- # 在屏幕上显示读取的信息
- # movw $BUFFER_SEG,%ax
- # movw %ax, %ds # ds:si 为源地址
- # movw $0, %si
- # movw $320, %di # 第一行已经打印了msg_str,从第二行开始显示
- # movw $512, %cx # 显示字符数
- # movb $0x01, %al
- # call draw_some_text
- # 将缓冲区中前data_len个字节拷贝到data_save
- xorw %ax, %ax
- movw %ax, %ds
- movw num_to_read,%cx
- movw $BUFFER_SEG,%ax
- movw %ax, %ds
- xorw %ax, %ax
- movw %ax, %es
- movw $0, %si
- movw $data_save, %di
- cld
- rep movsb
- # 下面调用绘制函数,在屏幕上显示读取的信息
- xorw %ax, %ax
- movw %ax, %ds # ds:si 为源地址
- leaw data_save, %si
- movw $160, %di # 第一行已经打印了msg_str,从第二行开始显示
- movw num_to_read,%cx # 显示字符数
- movb $0x01, %al
- call draw_some_text
- 1:
- jmp 1b
- msg_str:
- .asciz "The data read from floppy:"
- msg_len:
- .short . - msg_str - 1
- sect_no:
- # 下面的扇区数据为:"babyosguzhoudiaoke"
- # sect: 2+26*1, 1+26*2, 2+26*3, 25+26*4, 15+26*5, 19+26*6,
- # 7+26*11, 21+26*12, 26+26*13, 8+26*14, 15+26*15, 21+26*16,
- # 4+26*31, 9+26*32, 1+26*33, 15+26*34, 11+26*35, 5+26*36
- .short 28, 53, 80, 129, 145, 175
- .short 293, 333, 364, 372, 379, 411
- .short 810, 841, 859, 899, 921, 941
- num_to_read:
- .short 18
- data_save:
- .asciz "XXXXXXXXXXXXXXXXXX"
- .org 0x1fe, 0x90
- .word 0xaa55
- <pre></pre>
- <pre></pre>
babyos (三)——利用BIOS INT 0x13读取软盘相关推荐
- 突破BIOS无法连续读取软盘72扇区的限制
具体代码调试和讲解请参看视频: Linux kernel Hacker, 从零构建自己的内核 一直以来,我们的操作系统加载器,秉承简单够用的原则,只要能把编译好的二进制内核送进内存就可以了,所以加载器 ...
- 利用BIOS 中断INT 0x10显示字符和字符串
注:以下程序系原创,使用AT&T格式汇编来调用BIOS 0x10中断,如有错误,欢迎指正.表达能力较差,写的不好,但若能帮助一二访客,幸甚. 使用BIOS 显示服务(Video Service ...
- linux 汇编 读取软盘,读取软盘逻辑扇区的汇编实现代码
该过程以int 13H 02H子功能为基础,与int 13H采用相同的基于1的扇区地址,完成读取若干逻辑扇区的功能.过程没有对输入参数做任何检测,请读者自行保证输入参数的正确性.参数的合法范围:AX& ...
- linux 汇编 读取软盘,学习x86汇编语言7 使用INT13读取软盘数据
学习x86汇编语言7 使用INT13读取软盘数据 一.本章使用工具 二.软盘存储介绍 三.BIOS int13功能 四.引导程序源代码 一.本章使用工具 nasm FloppyWriter bochs ...
- 30天自制操作系统 - 用INT 0x13/AH=0x42h读磁盘
背景 基本上,每个硬盘除了每扇(Sector)大小依旧是512字节外,柱面(Cylinder)数.磁头(Header)数都不一致. 用磁盘来取代原作者的软盘后,沿用原来的INT 0x13/AH=2h读 ...
- xml 和android脚本之家,Android利用Document实现xml读取和写入操作
本文实例为大家分享了利用Document实现xml读取和写入操作,供大家参考,具体内容如下 首先先来介绍一下什么xml?xml是可扩展标记语言,他可以用来标记数据,定义数据类型.是一种允许用户对自己标 ...
- BIOS INT中断整理
BIOS 中断 1. 显示服务(Video Service--INT 10H) 2. 直接磁盘服务(Direct Disk Service--INT 13H) 3.串行口服务(Serial Port ...
- CUDA实例系列三:利用GPU优化向量规约问题
CUDA实例系列三:利用GPU优化向量规约问题 先简单的描述一下题目中说的向量规约问题. 这里举个例子, 比如: 我要求出1+2+3-+100的和 我要求出123-*100的积 我要找到a[100]中 ...
- BIOS int 13H中断介绍
BIOS int 13H中断也叫直接磁盘服务(Direct Disk Service),该中断的各个功能号及对应的功能描述如下: 1.功能 00H 功能描述:磁盘系统复位 入口参数:AH=00H DL ...
最新文章
- c++ make_pairpair
- UiBot带你两分钟看懂RPA是什么
- viewflipper动画切换屏幕
- IE6与其他浏览器的区别
- 常用数据绑定控件详解
- SAP 电商云 Spartacus UI set delivery mode HTTP put 请求的触发时机
- 关于 hibernate 官网的例子 出现的问题
- 给谷歌浏览器安装vue调试工具:vue-devtools
- pg10 10.3 1 linux64,Install Postgresql 10 In Ubutnu 16.04 LTS
- 理解PHP5中static和const关键字
- 使用Windows版Redis
- 使用OGR2OGR将S57数据转为shp格式
- C/C++编程语言中指针(pointer)介绍
- win10电脑显示无法自动修复此计算机,win10系统无法自动修复此计算机的操作步骤...
- ACL2021 | 对比学习8篇论文一句话总结
- 计算机专业毕业论文选题方向,计算机毕业方向论文选题 计算机毕业论文题目选什么比较好...
- cppc文件无法正常输出汉字,将文件修改为UTF-8格式
- 企业cc邮箱发件服务器设置,C#发送邮件(阿里企业邮箱示例 包括各个类型的服务器及端口配置)...
- 2019年Q4三星和华为都败了,谁也想不到第一名是它
- 近10年的网盘发展史(那些年你的网盘存了多少资料)
热门文章
- 【Java 并发编程】线程池机制 ( 线程池状态分析 | 线程池状态转换 | RUNNING | SHUTDOWN | STOP | TIDYING | TERMINATED )
- 【错误记录】Android Studio 编译报错 ( SDK location not found )
- 【Android 插件化】Hook 插件化框架 ( 合并 “插件包“ 与 “宿主“ 中的 Element[] dexElements | 设置合并后的 Element[] 数组 )
- 【错误记录】Android Studio 导入外部 so 动态库报错 ( java.lang.UnsatisfiedLinkError | 指定 APK 打包动态库的 CPU 架构 )
- 【Android 安全】DEX 加密 ( 代理 Application 开发 | 交叉编译 OpenSSL 开源库 )
- Nginx初学第一步
- cs224n第一讲深度自然语言处理
- js实现旋转木马轮播图
- VMware虚拟机 CentOS 6.5系统安装配置详细图文教程 --技术支持TPshop商城
- 119. Pascal's Triangle II (Graph; WFS)