linux 0.11 源码学习(四)
setup.s
在setup中最主要的工作是使系统进入保护模式,并转入system模块具体如下:
- 通过BIOS中断读取系统数据,如光标、显卡、硬盘等信息,这些信息存放至内存0x9000至0x901FC处,典型代码如下:
! ok, the read went well so we get current cursor position and save it for ! posterity. mov ax,#INITSEG ! this is done in bootsect already, but... mov ds,ax mov ah,#0x03 ! read cursor pos xor bh,bh int 0x10 ! save it in known place, con_init fetches mov [0],dx ! it from 0x90000.
- 将system模块移到内存0x0000处(这里看代码有点不懂,感觉只移动了64K,而不是完整 system的512K):
mov ax,#0x0000 cld ! 'direction'=0, movs moves forward do_move: mov es,ax ! destination segment //es+di 目的地址 add ax,#0x1000 cmp ax,#0x9000 jz end_move mov ds,ax ! source segment //ds+si:源地址 sub di,di sub si,si mov cx,#0x8000 //movsw循环的次数 rep movsw jmp do_move
- 加载GDT和LDT,选择A20地址线,系统进入保护模式。其中GDT初始设置值(包含三个描述符)如下:
gdt: .word 0,0,0,0 ! dummy .word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb) //代码段 .word 0x0000 ! base address=0 .word 0x9A00 ! code read/exec .word 0x00C0 ! granularity=4096, 386 .word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb) //数据段 .word 0x0000 ! base address=0 .word 0x9200 ! data read/write .word 0x00C0 ! granularity=4096, 386
备注:GDT描述符定义 -》 BYTE0,BYTE1(段界限),BYTE2、BYTE3、BYTE4(段基地址1),BYTE5,BYTE6(属性)、BYTE7(段基地址2)。上述代码中比较困惑的是为什么代码段和地址段的基地址都是0x0000。
- 操作8259中断控制器,应该是初始化芯片,未细看;
- 跳转至gdt的第二个描述符,即地址0x0000处,为sysyem模块的head.s,参看链接过程中生成的system.map,该地址重定向到的函数是head.s的startup。这里比较困惑的是为什么0x0000处会是head.s,代码段在链接的时候,多个目标文件不是会重新组合吗?难道是老的连接器采用不整合,简单拼接的方法??
mov ax,#0x0001 ! protected mode (PE) bit lmsw ax ! This is it! jmpi 0,8 ! jmp offset 0 of segment 8 (cs) //一定要注意此时已经是保护模式,跳转的是GDT的偏移:)