济宁网站建设公司,佛山网站建设工作,南昌网站设计公司,现在做网站到底需要多少钱这里在实验之前需要下载 Bochs-win32-2.6.11 作者使用的是Linux版本的#xff0c;在Linux写代码不太舒服#xff0c;所以最好在Windows上做实验#xff0c;下载好虚拟机以后还需要下载Nasm汇编器#xff0c;以及GCC编译器#xff0c;为了能够使用DD命令实现磁盘拷贝#…这里在实验之前需要下载 Bochs-win32-2.6.11 作者使用的是Linux版本的在Linux写代码不太舒服所以最好在Windows上做实验下载好虚拟机以后还需要下载Nasm汇编器以及GCC编译器为了能够使用DD命令实现磁盘拷贝这里你可以安装windows 10 下面的子系统Ubuntu需要使用命令时可以直接切换。
**注释**该系列笔记是在学习《操作系统真相还原》时通过阅读后简化并适当描述整理的学习笔记首先致敬作者郑刚博士在读本书时能深刻的感觉到作者写书时一丝不苟的态度书很厚写的讲解细致幽默很能让人愿意继续读下去同时也不得不佩服作者计算机底层功力的深厚转载本文请一并附带郑刚版权信息。
BIOS 软件接力第一棒
BIOS 基本输入输出系统,BIOS代码所做的工作是一成不变的,所以他是被固化到ROM中的一块只读区域中,在开机时此ROM会被映射到低端1MB内存的顶部,原因是系统在开启时默认是实地址模式(该模式最大寻址范围0-fffff),所以其寻址范围也就被限制在了0xF0000-x0xFFFFF区域中,这64KB的内存就是BIOS的执行代码.
在开机的一瞬间,CPU的CS:IP寄存器会被强制初始化为0xF000:0xFFF0,在实地址模式下该地址需要乘以16也就是左移四位加上偏移地址得到,于是0xF000:0xFFF0就等效于0xFFFF0此处的地址距离0xFFFFF只有16个字节的空间,里面存放着一条jmp far f000:e05b fe05b的汇编指令,该指令将跳转到真正的BIOS开始的位置.
接着BIOS将会通过自身的代码对硬件进行自检测,在初始化硬件后,则开始向内存0x000-0x3ff中初始化数据结构以及拷贝中断向量表,紧接着BIOS将会通过调用int 19h中断,此中断用以检测计算机中的硬盘,如果检测到0盘0道1扇区末尾的两个字节是0x55,0xaa则认为此扇区确实存在,于是就会将此区域中的内容,加载到内存7c00的位置,并通过一条jmp far 0:0x7c00h的指令跳转到该位置执行,这样BIOS就将CPU控制权交给了MBR了,而BIOS将会再次睡去.
MBR 收到跳转来源继续执行。
此处的7c000就是MBR代码的开始位置,之所以是7C00是因为,DOS中要求最小内存是32KB,而MBR大小必须是512字节(1KB),所以选择32kB中的最后1KB的位置最为合适,32KB(0x8000)-1KB(0x400)0x7c00,这就是7C00的由来,同时还需要保证第510-511字节必须为0x55,0xaa才可以.
保存以下汇编代码,并使用 nasm -o mbr.bin mbr.asm编译简易版MBR文件.
SECTION MBR vstart0x7c00 ; 告诉编译器加载到7c00内存处mov ax,csmov ds,axmov es,axmov ss,axmov fs,axmov sp,0x7c00mov ax,Messagemov bp,ax ; 保存字符串地址mov cx,15 ; 保存字符串长度mov ax,01301h ; 子功能号13是显示字符及属性mov bx,000ch ; 页号位0,使用黑色为背景色,红色为字体颜色mov dl,0int 10h ; 10h中断,用来显示字符retMessage: db hello lyshark !
times 510-($-$$) db 0 ; 填充510字节为0
db 0x55,0xaa ; mbr的结束标志进入Bochs目录下执行bximage.exe生成一个映像文件,默认是a.img,你可以改名为其他的这里我定义为linux.img 并将编译好的mbr.bin写入到镜像中
dd ifmbr.bin oflinux.img bs512 count1 convnotrunc在Bochs目录下新建并编辑bosh.src保存,然后执行bochs.exe -f bosh.src模拟执行MBR代码.
megs:32
romimage:file$BXSHARE/BIOS-bochs-latest
vgaromimage:file$BXSHARE/VGABIOS-lgpl-latest
floppya:1_44linux.img,statusinserted
boot:floppy
log:bochsout.txt
mouse:enabled0
keyboard: keymap$BXSHARE/keymaps/x11-pc-de.map上方屏幕会比较混乱这里我们先来进行清屏操作清屏中断调用也是int10
SECTION MBR vstart0x7c00 ; 告诉编译器加载到7c00内存处mov ax,csmov ds,axmov es,axmov ss,axmov fs,axmov sp,0x7c00mov ax,0x600 ; 清屏范围,也就是宽度mov bx,0x0mov cx,0x0 ; 清屏 左上角(0,0)mov dx,0x184f ; 清屏 右下角(800x4f,250x18)int 0x10mov ax,Messagemov bp,ax ; 保存字符串地址mov cx,15 ; 保存字符串长度mov ax,01301h ; 子功能号13是显示字符及属性mov bx,000ch ; 页号位0,使用黑色为背景色,红色为字体颜色mov dl,0int 10h ; 调用10h号中断,用来显示字符retMessage: db hello lyshark !
times 510-($-$$) db 0 ; 填充510字节为0
db 0x55,0xaa ; mbr的结束标志执行结果如下但是打印字符串在底部因为光标在底部。 设置光标到顶部这里百度一下光标中断发现了。 接着改进代码
SECTION MBR vstart0x7c00 ; 告诉编译器加载到7c00内存处mov ax,csmov ds,axmov es,axmov ss,axmov fs,axmov sp,0x7c00mov ax,0x600 ; 清屏范围,也就是宽度mov bx,0x0mov cx,0x0 ; 清屏 左上角(0,0)mov dx,0x184f ; 清屏 右下角(800x4f,250x18)int 0x10mov dh,0x0 ; 设置光标列号mov dl,0x0 ; 设置光标行号mov bh,0x0 ; 页码int 0x10mov ax,Messagemov bp,ax ; 保存字符串地址mov cx,15 ; 保存字符串长度mov ax,01301h ; 子功能号13是显示字符及属性mov bx,000ch ; 页号位0,使用黑色为背景色,红色为字体颜色mov dl,0int 10h ; 调用10h号中断,用来显示字符retMessage: db hello lyshark !
times 510-($-$$) db 0 ; 填充剩余的510字节的空间为0
db 0x55,0xaa ; mbr的结束标志完美结果。 mbr.asm
SECTION MBR vstart0x7c00 ; 告诉编译器加载到7c00内存处mov ax,csmov ds,axmov es,axmov ss,axmov fs,axmov sp,0x7c00mov ax,0x600 ; 清屏范围,也就是宽度mov bx,0x0mov cx,0x0 ; 清屏 左上角(0,0)mov dx,0x184f ; 清屏 右下角(800x4f,250x18)int 0x10mov dh,0x0 ; 设置光标列号mov dl,0x0 ; 设置光标行号mov bh,0x0 ; 页码int 0x10mov ax,Messagemov bp,ax ; 保存字符串地址mov cx,15 ; 保存字符串长度mov ax,01301h ; 子功能号13是显示字符及属性mov bx,000ch ; 页号位0,使用黑色为背景色,红色为字体颜色mov dl,0int 10h ; 调用10h号中断,用来显示字符hltretMessage: db hello lyshark !
times 510-($-$$) db 0 ; 填充剩余的510字节的空间为0
db 0x55,0xaa ; mbr的结束标志mbr.src
megs:32
romimage:file./BIOS-bochs-latest
vgaromimage:file./VGABIOS-lgpl-latest
boot:disk
mouse:enabled0
ata0-master: typedisk, pathlinux.img, modeflat, statusinserted
keyboard: keymap./x11-pc-de.map填充数据
dd ifmbr.bin oflinux.img bs512 count1 convnotrunc
dd if/dev/zero oflinux.img seek1 bs512 count2879运行
bochsdbg -q -f mbr.src
vb sp:0x7c00
c让我们对显卡说点什么
上面我们通过调用BIOS提供的int 0x10中断来实现打印字符操作但我们在后期必须要借助显卡来输出图像而显卡是外部设备必须通过总线来操作。
由于CPU使用的信号是TTL电平而外部设备都是机械设备故他们不会使用该电平驱动这就导致CPU与硬件设备没有办法实现沟通硬件工程师们提供的方法是在这两者之间架起一座桥也就是在CPU和外设之间加上一层IO接口该接口的作用就是实现CPU和外设之间相互做协调转换。
其次外部设备的种类也是多种多样的其输出的信号可能是数字信号也可能是模拟信号而我们的CPU只能处理数字信号数字信号需要经过数模转换器D/A成模拟量才能送到外设来驱动硬件工作模拟量也同样需要经过模数转换器A/D转换成数字量才能被CPU直接处理所以接口电路中需要包括A/D转换器和D/A转换器。
转换后的数字信号会经过总线进行传递总线的别名是BUS之所以叫做BUS是因为其是公共线路所有硬件设备都会走此线路但同一时刻CPU只能和一个IO接口(寄存器/端口)通信当有多个IO接口同时想和CPU通信时那么IO仲裁模块会对其进行竞争与选优仲裁模块固化到输入输出控制中心(ICH)也就是南桥芯片上的。
多数情况下南桥和北桥是成对出现的南桥主要负责连接PCI,PCI-Express,AGP等低速设备而北桥则用于链接高速设备如内存等。
IO接口都是串行口其在设计之初就是负责与CPU进行通信的我们想要与CPU通信其实是向这些接口中写入数据同时为了区别CPU中的寄存器所以把IO接口叫做端口某些外设可以通过内存映射来访问即把某些端口映射到指定内存中访问某个内存区域就相当于访问了指定的端口。
SECTION MBR vstart0x7c00 ; 告诉编译器加载到7c00内存处mov ax,csmov sp,0x7c00mov ax,0xb800mov gs,axmov ax,0x600 ; 清屏范围,也就是宽度mov bx,0x0mov cx,0x0 ; 清屏 左上角(0,0)mov dx,0x184f ; 清屏 右下角(800x4f,250x18)int 0x10mov dh,0x0 ; 设置光标列号mov dl,0x0 ; 设置光标行号mov bh,0x0 ; 页码int 0x10mov byte [gs:0x00],Mmov byte [gs:0x01],0xa4 ; 显示A绿色闪烁 4红色mov byte [gs:0x02],Bmov byte [gs:0x03],0xa5mov byte [gs:0x04],Rmov byte [gs:0x05],0xa6rettimes 510-($-$$) db 0 ; 填充剩余的510字节的空间为0
db 0x55,0xaa ; mbr的结束标志Bochs调试命令基础
Bochs调试命令常用的有以下几种.
bochs:1 vbreak 0x0000:0x7c000 7c000设置断点
bochs:1 pb 0x7c000 设置物理断点
bochs:1 vb sp:0x7c00 设置虚拟断点(保护模式)
bochs:1 info break 显示所有断点状态
bochs:1 delete num 删除一个断点bochs:1 c 运行遇到断点停下
bochs:1 n 执行下一指令
bochs:1 r 显示寄存器
bochs:1 u/10 向下反汇编10条
bochs:1 print-stack 打印堆栈x /nuf addr 查看一个线性地址的内存
xp /nuf addr 查看一个物理地址的内存n 显示多少个字节的内存u 单位长度; one o单位fb 字节h 半字(2 字节)w 字 (4 字节)g 双字 (8 字节)F 打印格式x 打印十六进制d 打印十进制u 打印无符号十进制o 打印八进制t 打印二进制SECTION MBR vstart0x7c00 ; 告诉编译器加载到7c00内存处mov ax,csmov sp,0x7c00mov ax,0xb800mov gs,axmov ax,0x600 ; 清屏范围,也就是宽度mov bx,0x0mov cx,0x0 ; 清屏 左上角(0,0)mov dx,0x184f ; 清屏 右下角(800x4f,250x18)int 0x10mov dh,0x0 ; 设置光标列号mov dl,0x0 ; 设置光标行号mov bh,0x0 ; 页码int 0x10mov byte [gs:0x00],Lmov byte [gs:0x01],0xa4 ; 显示A绿色闪烁 4红色mov byte [gs:0x02],ymov byte [gs:0x03],0xa5mov byte [gs:0x04],Smov byte [gs:0x05],0xa6mov byte [gs:0x6],hmov byte [gs:0x7],0xa7mov byte[gs:0x8],amov byte [gs:0x9],0xa6mov byte[gs:0xa],rmov byte [gs:0xb],0xa5mov byte[gs:0xc],kmov byte [gs:0xd],0xa4hltrettimes 510-($-$$) db 0 ; 填充剩余的510字节的空间为0
db 0x55,0xaa ; mbr的结束标志循环显存
_start:; 清屏和设置光标位置mov ax,0x600 ; 清屏范围,也就是宽度mov bx,0x0mov cx,0x0 ; 清屏 左上角(0,0)mov dx,0x184f ; 清屏 右下角(800x4f,250x18)int 0x10mov dh,0x0 ; 设置光标列号mov dl,0x0 ; 设置光标行号mov bh,0x0 ; 页码int 0x10;初始化数据段使其指向段基址0X7C0处即Boot代码被加载的地方mov ax, 0x07c0 ; 设置加载基址mov ds, ax;将文本显示内存段基址 放在ES中供后面显示字符使用mov ax, 0xb800 ; 设置显存地址mov es, axmov cx, msglen ; 获取字符串长度mov si, message ; 设置字符串基址xor di, diloop_str:mov al, [si] ; 每次取出一个字符mov [es:di], al ; 将字符逐一赋值到显存中inc siinc dimov byte [es:di], 0x07 ; 设置字体颜色inc diloop loop_strhlt ; 程序在此处终止message db Loading MBR...msglen db $ - messagetimes 510-($-$$) db 0 ; 填充剩余的510字节的空间为0
db 0x55,0xaa ; mbr的结束标志Bochs 调试命令
CPU加电后会跳转到 0xffff0 处我们可以反汇编这段内存地址向下反汇编10条。 分别显示CPU模式中断call调用源。 设置vb虚拟地址断点pb设置物理地址断点。blist显示所有断点。 bpd禁用断点bpe启用断点。del删除断点。 info idt 显示中断向量表 gdt 全局描述符表ldt 局部描述符表tss 任务状态段ivt 中断向量表
SECTION MBR vstart0x7c00 ; 告诉编译器加载到7c00内存处; 清屏和设置光标位置mov ax,0x600 ; 清屏范围,也就是宽度mov bx,0x0mov cx,0x0 ; 清屏 左上角(0,0)mov dx,0x184f ; 清屏 右下角(800x4f,250x18)int 0x10mov dh,0x0 ; 设置光标列号 左上角(0,0)mov dl,0x0 ; 设置光标行号 右下角(0,0)mov bh,0x0 ; 页码int 0x10; 初始化,使SP寄存器指向段基址0X7C0处,GS指向显存基地址mov ax,csmov sp,0x7c00mov ax,0xb800mov gs,ax ; 设置显存地址; 设置字符串长度与字符串基地址mov cx, msglen ; 获取字符串长度mov si, message ; 设置字符串基址xor di, di ; 每次清空di寄存器loop_str:mov al, [si] ; 每次取出一个字符mov [gs:di], al ; 将字符逐一赋值到显存中inc siinc dimov byte [gs:di], 000ch ; 设置字体颜色inc diloop loop_strhlt ; 程序在此处终止;message db Hello LyShark...,0ah,0dh
message db Hello LyShark...
msglen equ $ - messagetimes 510-($-$$) db 0 ; 填充剩余的510字节的空间为0
db 0x55,0xaa ; mbr的结束标志