linux引导程序对比,linux引导程序剖析(三)

该部分程序是在内核代码的开头部分,用来

做一些初始化的操作,比如重新设置idt,gdt,

设置页表等,最后将控制转移到内核的main函数。

.text

.globl _idt,_gdt,_pg_dir,_tmp_floppy_area

这个标志是站位的,之后该程序会将页目录表存放在该处

将head.s的开头部分覆盖。也就是说把页目录表放在内存

最开始处。

_pg_dir:

程序开始

startup_32:

段选择符0x10表示,RPL为0,在全局描述符表

中,索引值为2,

movl $0x10,%eax

用段选择符加载各个段寄存器

在setup.s程序中,设置了GDT表,0x10表示

内核数据段,内存基地址为0

mov %ax,%ds

mov %ax,%es

mov %ax,%fs

mov %ax,%gs

设置系统堆栈,_stack_start定义在kernel/sched.c中

/*

long user_stack [ PAGE_SIZE>>2 ] ;

struct {

long * a;

short b;

} stack_start = { & user_stack [PAGE_SIZE>>2] , 0x10 };

*/

表示系统堆栈空间可以达到4 * 1024 byte.即4k,一个页面

lss _stack_start,%esp

重新设置中断描述符表

call setup_idt

重新设置全局描述符表

call setup_gdt

重新用0x10选择符加载段寄存器

movl $0x10,%eax

mov %ax,%ds

mov %ax,%es

mov %ax,%fs

mov %ax,%gs

重新加载堆栈段

lss _stack_start,%esp

eax寄存器清0

xorl %eax,%eax

检查A20地址线是否开启,如果没开启,

最高20位地址 + 1必将回环

1: incl %eax

movl %eax,0x000000

cmpl %eax,0x100000

je 1b

检查协处理器是否存在

movl %cr0,%eax

andl $0x80000011,%eax

设置协处理器存在标志位

orl $2,%eax

movl %eax,%cr0

调用协处理器检查子过程

call check_x87

安装页表

jmp after_page_tables

check_x87:

向协处理器发送初始化命令

fninit

取状态值

fstsw %ax

如果为0表示协处理器不存在

cmpb $0,%al

je 1f

取CR0寄存器进行重置协处理器标志位mp,em

movl %cr0,%eax

xorl $6,%eax

movl %eax,%cr0

ret

.align 2

fsetpm的机器码,看作空操作即可。

1: .byte 0xDB,0xE4

ret

安装中断描述符表

setup_idt:

将所有中断描述符项对应的中断处理子程序设置成

亚中断处理子程序的函数地址

lea ignore_int,%edx

0x00080000对应idt表描述符

0x0008表示指向内核代码段的选择符,

movl $0x00080000,%eax

将idt描述符的开始2个字节付值为哑中断处理子程序

的偏移地址

movw %dx,%ax

0x8E00表示中断描述符的高4个字节的

值。存在位置位,DPL位0级。

movw $0x8E00,%dx

设置256项中断描述符表

lea _idt,%edi

mov $256,%ecx

rp_sidt:

movl %eax,(%edi)

movl %edx,4(%edi)

addl $8,%edi

dec %ecx

jne rp_sidt

加载中断描述符表寄存器

lidt idt_descr

ret

setup_gdt:

加载全局描述附表寄存器

lgdt gdt_descr

ret

第一个也表的位置0x1000

.org 0x1000

pg0:

第二个也表的位置0x2000

.org 0x2000

pg1:

第三个页表的位置0x3000

.org 0x3000

pg2:

第四个页表的位置0x4000

.org 0x4000

pg3:

为软盘驱动预留缓冲,大小为1024byte.

.org 0x5000

_tmp_floppy_area:

.fill 1024,1,0

after_page_tables:

为init/main.c压入输入参数

参数char * enivorn

pushl $0

参数char ** argc

pushl $0

参数int argv

pushl $0

main函数返回地址

pushl $L6

压入函数地址

pushl $_main

安装页表

jmp setup_paging

main函数不会返回,否则死机

L6:

jmp L6

哑中断处理子程序打印的信息

int_msg:

.asciz "Unknown interrupt/n/r"

.align 2

哑中断处理子程序

ignore_int:

pushl %eax

pushl %ecx

pushl %edx

push %ds

push %es

push %fs

仅仅重新用内核数据段描述符加载各个段寄存器

在屏幕上打印"Unknown interrupt"

movl $0x10,%eax

mov %ax,%ds

mov %ax,%es

mov %ax,%fs

pushl $int_msg

call _printk

popl %eax

pop %fs

pop %es

pop %ds

popl %edx

popl %ecx

popl %eax

iret

.align 2

安装页表

setup_paging:

一共5个页表,每个页表1024个表项

movl $1024*5,%ecx

初始化eax寄存器为0

edi寄存器为0

xorl %eax,%eax

xorl %edi,%edi

开始加载页目录表和页表

cld;rep;stosl

设置页目录表项

7表示页目录表项对应的页表具有读写权限,以及该页在内存中

movl $pg0+7,_pg_dir

movl $pg1+7,_pg_dir+4

movl $pg2+7,_pg_dir+8

movl $pg3+7,_pg_dir+12

在第四个页表的最后一个页表项开始初始化页表

movl $pg3+4092,%edi

初始化页表所用的值:0xfff007,物理页地址为:0xfff000,该页可读写、存在内存中

movl $0xfff007,%eax

std

循环初始化

1: stosl

subl $0x1000,%eax

jge 1b

页目录表的地址在内存中0x00000000

设置页目录表寄存器

xorl %eax,%eax

movl %eax,%cr3

movl %cr0,%eax

打开CR0控制寄存器的PG位,启用分页机制

orl $0x80000000,%eax

movl %eax,%cr0

ret

定义中断描述符表地址空间

.align 2

.word 0

idt_descr:

.word 256*8-1

.long _idt

定义全局描述符表地址空间

.align 2

.word 0

gdt_descr:

.word 256*8-1

.long _gdt

.align 3

_idt: .fill 256,8,0

定义全局描述符表_gdt: .quad 0x0000000000000000  .quad 0x00c09a0000000fff  .quad 0x00c0920000000fff  .quad 0x0000000000000000  .fill 252,8,0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值