《Linux内核设计的艺术》学习笔记(六)执行setup.s

  参考资料

  1. 8259A可编程中断控制器

jmpi , SETUPSEG // 0x90200

  到这里,bootsect.s的执行就算结束了。控制权转移到了setup.s文件的手中。

  setup程序的主要作用是利用ROM BIOS中断读取机器系统数据,并将这些数据保存到0x90000开始的位置。下表基本归纳了Line 109之前的所有代码逻辑。

  表1 setup.s前半段代码的作用

内存地址 长度(字节) 名称 描述
0x90000 2 光标位置 行列都是从0开始,各占一个字节。由int 0x10中断(入口参数为AH=0x03)取得到DX中,并保存到内存。
0x90002 2 扩展内存数 系统从1MB开始的扩展内存数值(KB)。由0x15中断(入口参数为AH=0x88)取得到AX中,并保存到内存。
0x90004 2 当前活动页 当前显示的页面。由int 0x10中断(入口参数为AH=0x0F)取得到BH中,并保存到内存。
0x90006 1 显示模式 同上,由int 0x10中断(入口参数为AH=0x0F)取得到AL中,并保存到内存。
0x90007 1 字符的列数 同上,int 0x10中断(入口参数为AH=0x0F)取得到AH中,并保存到内存。
0x90008 2 未知 被破坏了。int 0x10中断(入口参数为AH=0x0F,BL=0x10)。
0x9000A 1 内存大小标识 同上,int 0x10中断(入口参数AH=0x0F,BL=0x10)取得到BL中,并保存到内存(0x00=64K,0x01=128K,0x02=192K,0x03=256K)。
0x9000B 1 视频状态 同上,int 0x10中断(入口参数AH=0x0F,BL=0x10)取得到BL中,并保存到内存(0x00为彩色模式,I/O端口为0x3DX;0x01为单色,I/O端口为0x3BX)。
0x9000C 2 显卡特性参数 同上,int 0x10中断(入口参数AH=0x0F,BL=0x10)取得到CX中,并保存到内存。CH和CL各有含义。
0x90080 16 硬盘hd0参数表 取中断向量0x41所指的内存值,放于0x9000:0x0080处。由movsb命令实现。
0x90090 16 硬盘hd1参数表 取中断向量0x46所指的内存值,放于0x9000:0x0090处。由movsb命令实现。
0x901FC 2 根设备号 根文件系统所在的设备号在bootsect.s中设置,这里没有代码参与。 见bootsect.s中第251行。

接下来使用cli命令屏蔽中断。

cld命令将DF设置为0,增址方向。std与之相反。

通过movsw命令,将system模块从0x10000到0x8FFFF的内存数据块(512KB)移动到0x00000开始的位置。每次移动64KB,共移动8次。

初始化IDT寄存器和GDT寄存器。

选通A20地址线。

重新对8259A中断控制器编程。

通过lmsw命令将0x0001写入到控制寄存器CR0中,打开保护模式。

最后,通过jmpi 0, 8命令跳转至CS段8,偏移地址为0处。即,0x00000处。

《Linux内核设计的艺术》学习笔记(六)执行setup.s

图1 setup.s程序结束后内存中程序示意图

setup.s代码如下:

 !
! setup.s (C) Linus Torvalds
!
! setup.s is responsible for getting the system data from the BIOS,
! and putting them into the appropriate places in system memory.
! both setup.s and system has been loaded by the bootblock.
!
! This code asks the bios for memory/disk/other parameters, and
! puts them in a "safe" place: 0x90000-0x901FF, ie where the
! boot-block used to be. It is then up to the protected mode
! system to read them from there before the area is overwritten
! for buffer-blocks.
! ! NOTE! These had better be the same as in bootsect.s! INITSEG = 0x9000 ! we move boot here - out of the way
SYSSEG = 0x1000 ! system loaded at 0x10000 ().
SETUPSEG = 0x9020 ! this is the current segment .globl begtext, begdata, begbss, endtext, enddata, endbss
.text
begtext:
.data
begdata:
.bss
begbss:
.text entry start
start: ! 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 [],dx ! it from 0x90000. ! Get memory size (extended mem, kB) mov ah,#0x88
int 0x15
mov [],ax ! Get video-card data: mov ah,#0x0f
int 0x10
mov [],bx ! bh = display page
mov [],ax ! al = video mode, ah = window width ! check for EGA/VGA and some config parameters mov ah,#0x12
mov bl,#0x10
int 0x10
mov [],ax
mov [],bx
mov [],cx ! Get hd0 data mov ax,#0x0000
mov ds,ax
lds si,[*0x41]
mov ax,#INITSEG
mov es,ax
mov di,#0x0080
mov cx,#0x10
rep
movsb ! Get hd1 data mov ax,#0x0000
mov ds,ax
lds si,[*0x46]
mov ax,#INITSEG
mov es,ax
mov di,#0x0090
mov cx,#0x10
rep
movsb ! Check that there IS a hd1 :-) mov ax,#0x01500
mov dl,#0x81
int 0x13
jc no_disk1
cmp ah,#
je is_disk1
no_disk1:
mov ax,#INITSEG
mov es,ax
mov di,#0x0090
mov cx,#0x10
mov ax,#0x00
rep
stosb
is_disk1: ! now we want to move to protected mode ... cli ! no interrupts allowed ! ! first we move the system to it's rightful place mov ax,#0x0000
cld ! 'direction'=0, movs moves forward
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 ! then we load the segment descriptors end_move:
mov ax,#SETUPSEG ! right, forgot this at first. didn't work :-)
mov ds,ax
lidt idt_48 ! load idt with ,
lgdt gdt_48 ! load gdt with whatever appropriate ! that was painless, now we enable A20 call empty_8042
mov al,#0xD1 ! command write
out #0x64,al
call empty_8042
mov al,#0xDF ! A20 on
out #0x60,al
call empty_8042 ! well, that went ok, I hope. Now we have to reprogram the interrupts :-(
! we put them right after the intel-reserved hardware interrupts, at
! int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
! messed this up with the original PC, and they haven't been able to
! rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
! which is used for the internal hardware interrupts as well. We just
! have to reprogram the 's, and it isn't fun. mov al,#0x11 ! initialization sequence
out #0x20,al ! send it to 8259A-
.word 0x00eb,0x00eb ! jmp $+, jmp $+
out #0xA0,al ! and to 8259A-
.word 0x00eb,0x00eb
mov al,#0x20 ! start of hardware int's (0x20)
out #0x21,al
.word 0x00eb,0x00eb
mov al,#0x28 ! start of hardware int's (0x28)
out #0xA1,al
.word 0x00eb,0x00eb
mov al,#0x04 ! - is master
out #0x21,al
.word 0x00eb,0x00eb
mov al,#0x02 ! - is slave
out #0xA1,al
.word 0x00eb,0x00eb
mov al,#0x01 ! mode for both
out #0x21,al
.word 0x00eb,0x00eb
out #0xA1,al
.word 0x00eb,0x00eb
mov al,#0xFF ! mask off all interrupts for now
out #0x21,al
.word 0x00eb,0x00eb
out #0xA1,al ! well, that certainly wasn't fun :-(. Hopefully it works, and we don't
! need no steenking BIOS anyway (except for the initial loading :-).
! The BIOS-routine wants lots of unnecessary data, and it's less
! "interesting" anyway. This is how REAL programmers do it.
!
! Well, now's the time to actually move into protected mode. To make
! things as simple as possible, we do no register set-up or anything,
! we let the gnu-compiled -bit programs do that. We just jump to
! absolute address 0x00000, in -bit protected mode. mov ax,#0x0001 ! protected mode (PE) bit
lmsw ax ! This is it!
jmpi , ! jmp offset of segment (cs) ! This routine checks that the keyboard command queue is empty
! No timeout is used - if this hangs there is something wrong with
! the machine, and we probably couldn't proceed anyway.
empty_8042:
.word 0x00eb,0x00eb
in al,#0x64 ! 8042 status port
test al,#2 ! is input buffer full?
jnz empty_8042 ! yes - loop
ret 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 idt_48:
.word 0 ! idt limit=0
.word 0,0 ! idt base=0L gdt_48:
.word 0x800 ! gdt limit=2048, 256 GDT entries
.word 512+gdt,0x9 ! gdt base = 0X9xxxx .text
endtext:
.data
enddata:
.bss
endbss:
上一篇:C++之vector中元素删除


下一篇:Android使用OKHttp3实现下载(断点续传、显示运行进度)