操作系统的引导
来源:互联网 发布:js 数组包含对象 编辑:程序博客网 时间:2024/05/22 00:19
一、源代码
!bootsect.s !当 PC 的电源打开后,80x86 结构的 CPU 将自动进入实模式,并从地址 0xFFFF0 开始自动执行程序代码,这!个地址通常是 ROM-BIOS 中的地址。PC 机的 BIOS 将执行某些系统的检测,在物理地址 0 处开始初始化中!断向量。此后,它将可启动设备的第一个扇区读入内存地址 0x7C00 处,并跳转到这个地方。此代码即为引导扇!区的代码,它将完成自身的复制迁移,加载setup.s设置程序,最后在终端显示启动字符串,并跳到setup程序执!行。.globl begtext,begdata,begbss,endtext,enddata,endbss.textbegtext:.databegdata:.bssbegbss:.textSETUPLEN=4BOOTSEG=0x07c0INITSEG=0x9000SETUPSEG=0x9020entry startstart:!将自身从内存0x7c00处复制到0x90000处!ds:si=>es:di 执行cx次movw mov ax,#BOOTSEG mov ds,ax mov ax,#INITSEG mov es,ax sub si,si sub di,di mov cx,#256 rep movw jmpi go,INITSEG !段间跳转,设置cs为INITSEGgo: mov ax,cs mov ds,ax!cs=>ds mov es,ax!cs=>es!从磁盘加载setup程序到内存0x90200处!调用0x13号中断!输入:ah为功能号,0x02为从磁盘读到内存,al为读取扇区个数!dh为磁头号,dl为驱动器号,ch为柱面(磁道)号,cl为开始扇区,es:bx指向数据缓冲区!如果出错,CF标志置位,ah返回出错码load_setup: xor dx,dx mov cx,#0x0002 mov ax,#0x0200+SETUPLEN mov bx,#0x0200 int #0x13 jnc ok_load_setup !复位磁盘控制器,重试 !调用0x13号中断 !ah为功能号,0x0为复位,dl为驱动器号 xor dl,dl xor ah,ah int #0x13 j load_setup!显示字符串!调用0x10号中断!输入:ah功能号为0x13表示显示字符串,al为0x01表示光标停在字符串结尾处!es:bp指向显示字符串的起始位置,cx为字符串长度,dh为显示位置行号,dl为列号,bh为显示页号,bl为字符属性ok_load_setup:!读取光标位置!调用0x10号中断!ah功能号为0x03,bh为页号!输出dh为光标位置行号,dl为列号 mov ah,#0x03 xor bh,bh int 0x10 mov cx,#25 mov bx,#0x000A mov bp,#msg1 mov ax,#0x1301 int 0x10 jmpi 0,SETUPSEG!跳转到setup程序段执行msg1: .byte 13,10 .ascii "Funix is booting..." .byte 13,10,13,10!ASCII码:13为回车,10为换行.org 510 !定位当前偏移地址为510 .word 0xAA55!有效引导扇区的标志.textendtext:.dataenddata:.bssendbss:
!setup.s!被bootsect.s加载到内存0x90200处,首先显示一个字符串,然后打印光标位置、内存尺寸以及磁盘参数信息.globl begtext,begdata,begbss,endtext,enddata,endbss.textbegtext:.databegdata:.bssbegbss:.textBOOTSEG=0x07c0INITSEG=0x9000SETUPSEG=0x9020entry startstart: mov ax,cs mov ds,ax mov es,ax mov ah,#0x03 xor bh,bh int 0x10 mov cx,#23 mov bx,#0x0007 mov bp,#msg1 mov ax,#0x1301 int 0x10 mov ax,#INITSEG mov ds,ax!设置硬件信息保存的段地址为INITSEG mov ah,0x03 xor bh,bh int 0x10!读取光标位置 mov [0],dx!保存到ds:0x0处 !取扩展内存的大小值 !调用0x15号中断,ah功能号为0x88取系统所含扩展内存大小 !返回ax=从0x100000(1M)处开始的扩展内存大小(KB),若出错则CF置位,ax=出错码 mov ah,#0x88 int 0x15 mov [2],ax!保存到ds:0x2处 !取第一个硬盘的信息 !第一个硬盘参数表的首地址是中断向量0x41的向量值,第二个硬盘参数表紧接其后,为0x46。 !表长为16个字节 !ds:si=>es:di mov ax,#0x0000 mov ds,ax lds si,[4*0x41]!取中断向量0x41的值,即hd0参数表的地址->ds:si mov ax,#INITSEG mov es,ax mov di,#0x0080 mov cx,#0x10 rep movsb mov ax,#INITSEG mov ds,ax mov ax,#SETUPSEG mov es,ax mov ah,#0x03 xor bh,bh int 0x10 mov cx,#11 mov bx,#0x0007 mov bp,#cur mov ax,#0x1301 int 0x10!打印提示字符串 mov ax,[0x0]!取出光标位置 call print_hex!打印数值 call print_nl!打印回车换行 mov ah,#0x03 xor bh,bh int 0x10 mov cx,#12 mov bx,#0x0007 mov bp,#mem mov ax,#0x1301 int 0x10 mov ax,[0x2] call print_hex!打印内存大小 mov ah,#0x03 xor bh,bh int 0x10 mov cx,#25 mov bx,#0x0007 mov bp,#cyl mov ax,#0x1301 int 0x10 mov ax,[0x80] call print_hex!打印柱面个数 call print_nl mov ah,#0x03 xor bh,bh int 0x10 mov cx,#8 mov bx,#0x0007 mov bp,#head mov ax,#0x1301 int 0x10 mov ax,[0x80+0x02] call print_hex!打印磁头个数 call print_nl mov ah,#0x03 xor bh,bh int 0x10 mov cx,#8 mov bx,#0x0007 mov bp,#sect mov ax,#0x1301 int 0x10 mov ax,[0x80+0x0e] call print_hex!打印每磁道扇区数 call print_nlok: j ok !停止!将ax中16位数字打印成按十六进制显示字符输出print_hex: mov cx,#4!打印4个字符 mov dx,ax!参数ax传递给dxprint_digit: rol dx,#4!循环左移4位,最高位变为最低位 mov ah,#0xe!中断功能号,显示al中的字符 mov al,dl and al,#0xf!高4位置零,设置al为显示数字 add al,#0x30!转换ascii码 cmp al,#0x39 jbe good_digit!不超过9直接中断打印出来 add al,#0x41-0x30-0xa!超过9加上'A'-'0'-10设置为大写字母显示good_digit: int 0x10!调用中断0x10 loop print_digit!循环打印4个字符 ret !中断打印回车换行print_nl: mov ax,#0xe0d int 0x10 mov al,#0xa int 0x10 retmsg1: .ascii "Now we are in SETUP" .byte 13,10,13,10cur: .ascii "Cursor POS:"mem: .ascii "Memory SIZE:"cyl: .ascii "KB" .byte 13,10,13,10 .ascii "HD Info" .byte 13,10 .ascii "Cylinders:"head: .ascii "Headers:"sect: .ascii "Sectors:".textendtext:.dataenddata:.bssendbss:
二、无心插柳
在和室友交流的过程中,发现他setup.s中调用print_hex函数传递参数使用的是栈,下面讨论一下这种情况。
!不管代码是否优雅,纯粹是用栈实现一下!此为调用push axcall print_hexpop ax!函数实现print_hex: push bp!保存bp mov bp,sp!设置bp为此时刻的sp,此时栈中有三个字——ax,ip和bp push ds!保存ds mov cx,ss mov ds,cx!设置ds段地址为栈段地址 mov cx,#4 mov dx,(bp+4)!按照bp向上偏移4字节访问参数axprint_digit: rol dx,#4 mov ah,#0xe mov al,dl and al,#0xf add al,#0x30 cmp al,#0x39 jbe good_digit add al,#0x41-0x30-0xagood_digit: int 0x10 loop print_digit pop ds!恢复ds pop bp!恢复bp ret
对setup.s而言,上面的实现可谓很不优雅,因为print_hex函数传递参数可以用寄存器直接传递(像一部分那样),也可以直接访问0x900xx地址(不具有普遍性,不可取),用栈本身也是用内存,只不过此处使用的是默认的栈分配而非手动指定分配的内存。但是突然对栈有了更明确的理解:之前写汇编函数上来就是push ebp;mov ebp,esp感觉是习惯就没怎么思考,这次才想明白ebp的作用只是保存那一时刻的esp,因为之后再push,pop可能会改变esp的值,但ebp基本不变就能得到恒定的参数表达或者访问形式。注意call本身调用的时候相当于先push eip,然后段内近跳转,所以用ebp访问参数的时候不能忘了还有eip的偏移,同理ret相当于pop eip。
三、运行结果
查看Bochs配置文件bochs/bochsrc.bxrc
megs: 16
mode=flat, cylinders=204, heads=16, spt=38
发现扩展内存大小刚好是15M,加上1M为16M,其他柱面数,磁头数和每磁道扇区数都和结果一致。Bingo!
四、参考资料
- HIT-OSLAB-MANUAL操作系统的引导
- LDS指令
- INT 10中断功能
- INT13中断详解
- INT 15中断功能
0 0
- 操作系统的引导(一)
- 操作系统的引导(二)
- 操作系统的引导(三)
- 操作系统的引导
- 操作系统内核的引导
- 操作系统引导的学习
- 操作系统的引导
- 多硬盘操作系统的引导
- 引导操作系统是个很有意思的
- 操作系统的引导与修复
- 实验2 操作系统的引导
- 哈工大操作系统试验1 操作系统的引导
- 操作系统引导
- 操作系统引导
- 恢复Linux操作系统的GRUB引导程序
- 开发自己的操作系统引导程序
- windows操作系统的DBR引导代码
- 用qemu 引导 最小的操作系统
- iOS开发:过滤下载资源类型
- oc字符串存储位置
- 继承情况下类加载顺序
- mybatis+servlet
- 批处理产生001、002序列数字的文件名
- 操作系统的引导
- guava-retrying重试工具库: AttemptTimeLimiter
- 新建的liferay项目在部署时需要注意的事项
- 如何让 cygwin终端中显示的中文改成英文
- Spring HTTP invoker
- HTML5 & CSS3初学者指南(2) – 样式化第一个网页
- iOS开发:判断UIScrollView是上拉还是下拉
- maya mel里面button 函数传参问题
- 前台Autoform 选择下拉框的值进行判断(js)