标签:
一, 执行BIOS程序
x86 PC刚开机的时候, CPU处于实模式, 实模式和保护模式相对应, 实模式的寻址是cs:ip (CS左移4位+ip). 开机时, cs=0xFFFF, ip=0x0000, 也就是说cpu从0xFFFF0地址处开始执行, 但是我们发现0xFFFF0这个地址距离0xFFFFF只有16个字节, 这16个字节并不能做什么事情, 所以在0xFFFF0处的指令是一个跳转指令 jmp far f000:e05b 跳转到对应的地址处执行. 这里的代码具体的任务是检查硬件, 如RAM, 键盘, 显示器, 软盘, 硬盘等. 如果电脑的这些硬件没有什么问题, 就将启动设备(可以是磁盘, 软盘, U盘等, 这可以在BIOS菜单中设置)的0磁道0扇区的512个字节的代码读入到0x7c00处, 然后设置cs=0x7c0, ip=0x0000, CPU就从0x7c00处开始执行了
二, 操作系统的引导(1)
在磁盘的0磁道1扇区中处的程序对应的源代码是bootsect.s 下面是对这个程序代码的简要分析:
...... _start: ! bootsect模块是在内存中的0x7c00处 ! 先把bootsect模块自身拷贝到内存中的0x90000处 ! 然后在0x9000段里继续向下执行 mov ax,#BOOTSEG ! BOOTSEG = 0x07c0 mov ds,ax mov ax,#INITSEG ! INITSEG = 0x9000 mov es,ax mov cx,#256 sub si,si sub di,di rep movw jmpi go,INITSEG go: mov ax,cs mov ds,ax mov es,ax ! 把0磁道2扇区开始的4个扇区的程序读入到0x90200处, 这个模块的名字叫做setup load_setup: mov dx,#0x0000 mov cx,#0x0002 mov bx,#0x0200 mov ax,#0x0200+SETUPLEN ! SETUPLEN = 4 int 0x13 jnc ok_load_setup mov dx,#0x0000 mov ax,#0x0000 int 0x13 j load_setup ok_load_setup: ...... ! 获取光标位置 mov ah,#0x03 xor bh,bh int 0x10 ! 打印启动信息到屏幕上 mov cx,#24 mov bx,#0x0007 mov bp,#msg1 mov ax,#0x1301 int 0x10 mov ax,#SYSSEG mov es,ax call read_it ......
! 读入system模块到0x10000处, 此处代码比较复杂, 省略了
read_it: ...... msg1: .byte 13,10 .ascii "Loading system ..." .byte 13,10,13,10 ......
总结一下bootsect模块的主要任务:
1, bootsect模块本身是在内存的0x7c00处
2, 首先将bootsect模块自身复制到0x90000处
3, 将setup模块复制到0x90200处
4, 显示一些欢迎进入系统的信息
5, 将system模块复制到0x10000处
此时, 内存中的情况如下:
三, 操作系统的引导(2)
在磁盘的0磁道2扇区到5扇区中处的程序对应的源代码是setup.s. 下面是对这个程序代码的简要分析:
...... start: ! 取出光标位置的信息, 存放到地址0x90000处 mov ax,#INITSEG ! INITSEG = 0x9000 mov ds,ax mov ah,#0x03 xor bh,bh int 0x10 mov [0],dx ! 取出内存大小的信息, 存放到地址0x90002处 mov ah,#0x88 int 0x15 mov [2],ax ...... ! 将system模块移动到地址0x0处 do_move: mov es,ax ! destination segment add ax,#0x1000 cmp ax,#0x9000 jz end_move mov ds,ax ! source segment sub di,di sub si,si mov cx,#0x8000 rep movsw jmp do_move end_move: mov ax,#SETUPSEG mov ds,ax lidt idt_48 ! 将IDT表的地址存放到LDTR寄存器中 lgdt gdt_48 ! 将GDT表的地址存放到GDTR寄存器中 ! 切换到保护模式 mov ax,#0x0001 ! CR0寄存器的第0位如果为0表示启动实模式, 为1表示启动保护模式, lmsw ax ! 启用保护模式. 这个可以替换为mov cr0,ax 用lmsw是为了兼容以前的CPU ! ip的值为0, cs的值为8(0b0000,0000,0000,10000) ! 在保护模式下, cs表示选择子, 即GDT表的索引 ! 通过查GTD表可以知道基址为0, 即跳转到0x0地址处开始执行 jmpi 0,8 ! 初始化GDT表 gdt: .word 0,0,0,0 .word 0x07FF, 0x0000, 0x9A00, 0x00C0 .word 0x07FF, 0x0000, 0x9200, 0x00C0 ! idt是保护模式下的中断函数表 idt_48: .word 0 ! idt limit=0 .word 0,0 ! idt base=0L ! gdt是全局描述符表 gdt_48: .word 0x800 ! gdt limit=2048, 256 GDT entries .word 512+gdt,0x9 ! gdt base = 0X9xxxx ......
总结一下setup模块的主要任务:
1, 读取硬件相关的信息, 并将这些信息存储到0x9000处
2, 将system模块复制到0x0000处
3, 从实模式切换到保护模式
4, 跳转到0x0000处开始执行system模块
至此, 操作系统的引导就完成了
标签:
原文地址:http://www.cnblogs.com/XiangfeiAi/p/4736264.html