linux-0.11学习笔记(一)——从加电到main执行前

1、关于linux-0.11从加电到main函数前

在加电后,计算机执行过的程序有bios、bootsect.s、setup.s和head.s,下面分析下各段程序都做了什么,到main函数执行前内存中是个什么状况,还需要做些什么,希望能有个总体的分析。


① 首先,开机加电后硬件从0xFFFF0处开始执行,也就是bios程序的入口,在bios 程序中bios在内存最开始的位置(即:0x00000)用1KB的内存空间(0x00000—0x003FF) 构建中断向量表(这是实模式下状态),并在紧挨着它的位置用256字节的内存空间构 建bios数据区(0x00400—0x004FF),在大约56KB后的位置(0x0E2CE)加载8KB左 右与中断向量表相关的中断服务程序(BIOS自身在0xFE000—0xFFFFF)。


② 然后在bios执行到加载系统时,由bios产生0x19中断,中断服务程序将第一扇区 bootsect加载进内存(在0X07C00处),然后bios中断服务程序执行完返回,貌似bootsect 得不到执行,我觉得可以这样设计,就是在中断服务程序执行完时通过跳转直接开始从 0X07C00处开始执行bootsect代码,bootsect将要开始内存规划。


③ bootsect上来先把自己复制到INITSEG(0x90000)起始位置,然后将ds、es、ss 等都设置为0x9000,设置栈指针sp为0xFF00,这样整个的在INITSEG起始的位置构 建了一个属于自己的王国,不过没有响应中断的能力,所以不能奈何bios,然后加载 setup.s和system模块,执行完后跳转到setup.s执行,但是我有个问题就是为什么不把bootsect.s和setup.s一起加载在0x07C00位置处呢,并且两段代码总共才5*512B,末地址在0x08600处,不会覆盖到bios的中断服务程序(0x0E2CE-0xFFFE),然后直接在0x90000处加载机器系统数据,在0x9FF00处建立栈顶,好像有点问题就是setup.s在移动system模块时会被覆盖,所以setup.s还是必须在0x90200处,这样设计才好


④ Setup的重要作用是开启32位保护模式,并建立保护模式下的一些要素,首先,趁 现在中断还是开着的加载机器系统数据到0x90000也就是原来的bootsect位置,一旦中 断关闭了就读不了了,读完之后开闭中断,马上要开启32位模式,开着中断会很麻烦 的,关中断后bios起不到什么作用了(bios所有的工作已经全部做完了),然后就直接 把bios占用的那段内存给覆盖了,然后开启A20地址建立GDT和IDT,总之,setup 主要目的就是建立32位保护模式,让head.s得以执行,因为head.s是32位下的汇编, 并且采用的是AT&T汇编,调用jmpi 0,8进入head.s执行,注意到head.s与前面两段程序不同的是,它采用的是AT&T(他下面有个贝尔实验室,而UNIX正是贝尔实验室搞出来的)汇编,所有我猜测head.s及c语言内嵌的汇编都是采用AT&T汇编格式,正是为了与UNIX兼容,因为linux也是原因minix兼容UNIX,这样做也可以使用UNIX下面的一些软件


⑤ head.s代码量为25KB+184B,head.s上来就把几个段选择子置为0x10,给各段指 定段基址和段限长,并且基地址都在0x00000处,然后开始加载栈

lss _stack_start,%esp //这里stack_start结构体在sched.c中定义包括long *a和short b,分别是&user_stack[PAGE_SIZE>>2](user_stack数据结构的最末位置指针)和0x10,这条指令将指针*a赋给esp(即栈顶指针为&user_stack[PAGE_SIZE>>2]),将b赋值给ss(即段选择子为0x10),栈加载完后开始加载IDT和GDT(这里的GDT和IDT为兼容16M内存特意改了的)

setup_idt:

lea ignore_int,%edx  //将ignore_int (系统中断服务函数,在系统出错的时候调用,里面还调用了个printk函数,看来是要panic的)的有效地址(偏移值0x00005428)写入edx 寄存器

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

movw %dx,%ax /* selector = 0x0008 = cs */

//偏移值的低16 位置入eax 的低16 位中。此时eax 含有

//门描述符低4 字节的值。

movw $0x8E00,%dx  /* interrupt gate - dpl=0, present */

//此时edx 含有门描述符高4 字节的值。

lea _idt,%edi  //将中断描述符表地址传给edi,idt在head.h中定义,

typedef struct desc_struct {//描述符结构体,长度8个字节,

unsigned long a,b;

} desc_table[256];

extern unsigned long pg_dir[1024];

extern desc_table idt,gdt;//256*8B(2KB)大小的描述符表,但是我不知道他是怎么控制idt首地址在0x054b8的,反正在msp430中全局变量的起始地址始终是在0x200处,并且全局变量的先后顺序会因为变量类型不同而不同,同时,全局变量值也会在0x1100处依次存放,即使程序中改变全局变量的值这里的值始终不变(猜测用于全局变量初始化),在编译时编译器会自动增加cstart_init_copy函数将全局变量地址拷贝到寄存器中

mov $256,%ecx

rp_sidt:

movl %eax,(%edi) //循环256次,依次将中断门描述符存入表中。

movl %edx,4(%edi)

addl $8,%edi //edi 指向表中下一项。

dec %ecx

jne rp_sidt

lidt idt_descr  //加载中断描述符表寄存器值。

ret

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值