linux 0.11时钟初始化,linux 0.11内核初始化篇

从head.s到main()函数。原来对于内核来说,在执行了初始化之后,内核执行权切换到了用户模式(0),cpu从0特权级切换到了3特权级。这是和原来想的不同。

言归正传,在boot/目录中有bootsect.s、setup.s、head.s按照执行顺序来的。

总体功能:Pc开机,80x86进入实模式,并从地址0xffff0(此处是rom-bios中的地址)。Pc的bios将指向系统检测,从物理地址0初始化中断响亮。然后启动设备的第一扇区磁盘引导区(此就是在文件系统中描述的那个bootblock块)读入内存绝对地址0x7c00处(此时为实模式,汇编语言可以访问直接地址)。然后跳转至此。启动设备。

bootsect.s由bios读入内存,然后自己将自己移动到0x90000处,启动设备后2kb代码读到0x90200处,

内核其他模块被读到0x10000开始处。

在系统显示loading....时,控制权将给boot/setup.s。启动部分识别主机及vga卡类型,然后将系统地址从0x10000移动到0x0000处,进入保护模式。

此时idt 、gdt、ldt被加载,分页工作也设置好了(从这里可以看出分页工作是head.s在中完成的,具体的内存分配则是完成从虚拟地址到物理地址映射的一个过程。),处理器和协处理器最终调用init/main.c的程序。

不直接移动到0x0000开始处呢?因为在setup程序开始处还需要利用ROM-BIOS的中断调用来获取机器的参数。BIOS在初始化时会在物理内存开始处放置0x400的向量表,使用完后才可以覆盖。

/linux/boot/bootsect.s中的重要代码

其中都是一些BIOS中断用汇编语言编写,可见汇编的不可取代的位置。

jmpi go,INITSEG /*这条指令后段地址cs是0x9000。

seg cs

mov  sectors , cx/*将cx寄存器的值送入cs:sectors;cs是0x9000。*/

......

seg cs

mov bx,sectors /*cs : sectors的值送入bx寄存器。*/

root_defined:

seg cs

mov  root_dev,ax /*保存,后面有.org 508(0x1fc开始)。:.word ROOT_DEV存放根文件系统的设备号(其在启动扇区的508开始的第二个字节*/

boot_flags:

.word 0x55aa   /*硬盘有效标识符*/

setup.s

也是利用rom bios读取机器系统数据。并保存在0x90000开始的位置,覆盖了bootsect程序的地方。比较重要的有0x90080第一个硬盘参数表(长度16个字节),0x90090第二个硬盘参数表,0x901fc是根设备号2个字节。

setup程序重要代码。

mov ah,#0x88

int 0x15

mov [2],ax 将扩展内存数值放在0x90002处。(一个字)

在取硬盘信息时

mov ax ,#0x000

mov ds, ax

lds  si,[4*0x41]取向量中断0x41的值,也即hd0的参数表地址->ds:si

mov ax,#INITSEG       // (0x9000)

mov es, ax

mov di,#0x0080 /*传输目的地址:0x9000:0x0080 es:di

mov cx,#0x10 //传输0x10字节*/

rep

movsb

.....

这里有

end_move:

mov ax, #SETUPSEG/*#define SETUPSEG 0x9020*/

mov  ds,ax

lidt  idt_48/*加载中断描述符(idt)寄存器idt_48是6字节操作数,钱粮字节是限长,后字节是idt表长*/

lgdt dgt_48 /* 加载全局描述符寄存器*/

.word 0x00eb,0x00eb /*jmp $ + 2, jmp $ + 2,跳转值是0,还是直接执行。*/

设置进入32保护模式运行:

mov ax,#0x0001  /*CR0寄存器比特位是0,导致cpu工作在保护模式.*/

lmsw   ax  /*加载机器状态字*/

jmpi   0, 8 /*跳转到cs段8,偏移值为0的地方,此时段8已经是保护模式下的段选择符了,段选择符为2字节。0x0000 0000, 0000 , 1000表示请求特权级0,使用全局描述符表的第一项,基地址是0*/

gdt:          /*此处是全局描述符表的开始,由多个8字节常的描述符项组成*/

.word 0, 0, 0, 0

/*用的是它,当加载代码段寄存器时,使用的是这个偏移值*/

.word 0x07ff /*8M Limit*/

.word 0x0000 /*基址是0*/

.word 0x9a00

.word 0x00c0

/*gdt表中偏移量是0x10,加载数据段寄存器(ds)时,使用的是这个偏移值*/

.word  0x7fff

.word  0x0000

.word  0x9200

.wrod  0x00c0

idt_48:

.word 0

.word 0 , 0 /*idt_base = 0L

gdt_48:

.word 0x800  /*gdt limit = 2048,256 项*/

.word 512 + gdt, 0x9 /*gdt_base = 0x9xxxx,用来表示此描述符所在内存的地址*/

因为代码段描述符和数据段描述符都指向系统模块的开始处,是物理地址0x0000,执行jmpi 0, 8(就会跳到基地址为0,偏移地址为0的地方执行,在段描述符项中段限制是检测用的看是否访问越位。)*/head.s程序开始执行。

head.s汇编和前面的语法不同,采用了AT&T汇编语言格式,使用GNU的gas和gld2进行汇编连接。

此程序在内存绝对地址为0的地方。功能加载数据段寄存器,重新设置终端描述符idt,共有256项。然后重新设置全局描述符表gdt.检测A20线是否开启。分页处理机制,将页面目录表放在绝对地址0开始处,此被覆盖,后放置可以寻址16M的4个也表,分别设置表项。利用返回指令将预先放置在堆栈的init/main.c程序入口弹出,运行main()程序。

重要代码:

movl $0x10, %eax 表示段选择符请求的是数据段描述符。

......

lss _stack_start, %esp /*_stack_start -> ss: esp*/

call setup_idt  /*调用设置中断描述符表子程序*/

call setup_gdt  /*调用设置全局描述符表子程序*/

setup _idt :

lea  ignore_int, %edx  /*将ignore_int的有效地址值->edx寄存器 ignore_int 是中断门*/

movl  $0x00080000, %eax /*将选择符0x0008置入%eax的高16位中。*/

movw  %dx, %ax  /*偏移值的低16位置入eax的低十六位中。此时eax含有门描述符低4字节的值*/

movw $0x8e00, %dx /*吃食edx含有门描述符高4字节的值*.

lea  _idt, %edi/*中断描述符的地址*/

mov  $256 %ecx;

rp_sidt:

movl  %eax,(%edi) /*将哑中断描述符存入表中(%edi)为描述符的地址*/

movl %edx, 4(%edi)/*

add $8,%edi /*edi指向下一项*/

dec %ecx  /*运行256次的意义是啥,因为是哑的*/

jne rp_sidt

lidt ldt_descr /*加载终端描述符寄存器值*/

ret;

setup_gdt:

lgdt  gdt_descr  /*加载全局描述符寄存器*/

ret

.org 0x1000  /*从偏移0x1000开始的是第一个页表*/

pg0:

.org 0x2000

pg1:

.org 0x3000

pg2:

.org 0x4000

pg3:

org 0x5000/*内存数据块从偏移0x5000开始*/

_tmp_flopy_area:

.fill 1024 , 1, 0 /*共保留1024项,每项1字节,填充0*/

.......

setup_paging:

movl $1024 * 5 ,%ecx/*首先对1页目录4页也表)清零*/

xorl  %eax, %eax

xorl  %edi, %edi             /*页目录从0x000地址开始*/

cld  ; rep; stosl

movl $pg0+7, _pg_dir /*$pg0 + 7表示0x00001007是页目录的第一项*/

movl $pg1+7,_pg_dir + 4

movl  $pg2+7,_pg_dir+ 8

movl $pg3+7, pg_dir +12

movl $pg3+4092, %edi

movl  $0xfff007, %eax /*最后一项对应物理内存页面的地址是0xfff000,加上属性是0xfff007。

std /*edi 值递减(4字节)

stosl

subl %0x1000, %eax  /*每添好一项物理值减0x1000。

jge 1b  /*如果小于0,那么己说明全填好了*/

xorl %eax,%eax

movl %eax,%cr4

/*设置页目录基地址寄存器cr3的值*/

movl %cr0, %eax

orl $0x80000000, %eax/*添加pg标志位*/

movl %eax,%cr0

ret

.....

.align 2

.word 0

gdt_descr:

.word 256 * 8 -1

.long _gdt

.align 3

_idt: .fill 256, 8, 0    /*256项每项8字节,都是0*/

_gdt: .quad  0x0000000000000000

.quad  0x00c09a0000000fff /*0x08,内核代码段最大长度是16M*/

.quad  0x00c0920000000fff/*0x10,内核数据段最大长度是16M*/

.quad  0x0000000000000000

fill 252 , 8, 0 /*其他的为TSS段和LDT段*/

阅读(1187) | 评论(0) | 转发(0) |

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值