linux内核设计的艺术--从16位转向32位

上一篇讲到了将kernel模块加载到了内存的0x10000-0x10000+120KB处,接下来,将会执行setup.s中的代码了。


首先,setup要获取一系列系统硬件信息

mov	ax,#INITSEG	
mov	ds,ax           //设置段地址
mov	ah,#0x03	
xor	bh,bh
int	0x10		//调用0x10中断获取屏幕光标位置
mov	[0],dx		//将屏幕光标保存至0x90000处
//调用0x15中断,获取内存信息保存至0x90002
mov ah,#0x88 
int 0x15mov [2],ax
//调用0x10中断,获取显卡信息保存至0x90004 - 0x90006
mov ah,#0x0f
int 0x10
mov [4],bx 
mov [6],ax
//调用0x10中断,获取VGA/EGA配置保存至0x90008 - 0x900012
mov ah,#0x12
mov bl,#0x10
int 0x10
mov [8],ax
mov [10],bx
mov [12],cx
//获取hd0信息
mov ax,#0x0000
mov ds,ax
lds si,[4*0x41]
mov ax,#INITSEG
mov es,ax
mov di,#0x0080
mov cx,#0x10
rep
movsb
//获取hd1信息
mov ax,#0x0000
mov ds,ax
lds si,[4*0x46]
mov ax,#INITSEG
mov es,ax
mov di,#0x0090
mov cx,#0x10
rep
movsb
//检查是否存在hd1
mov ax,#0x01500
mov dl,#0x81
int 0x13
jc no_disk1
cmp ah,#3
je is_disk1
no_disk1:mov ax,#INITSEG
mov es,ax
mov di,#0x0090
mov cx,#0x10
mov ax,#0x00
rep
stosb
is_disk1:



接下来为了方便进行内核的地址映射,将system模块从0x10000处移动至0x00000处

do_move:
	mov	es,ax		//指定目标段基址
	add	ax,#0x1000
	cmp	ax,#0x9000
	jz	end_move
	mov	ds,ax		//指定源段基址
	sub	di,di
	sub	si,si
	mov 	cx,#0x8000
	rep
	movsw
	jmp	do_move

在移动完成之后,我们需要为32位地址重新建立寻址方式,32位寻址采用段描述符的方式,所以要新建一个GDT(全局描述表),以及GDTR(GDT基地址寄存器),IDT(中断描述表),IDTR(IDT基地址寄存器)

end_move:
	mov	ax,#SETUPSEG	
	mov	ds,ax
	lidt	idt_48		
	lgdt	gdt_48		


然后就是打开A20寄存器,就可以实现32位寻址


	call	empty_8042
	mov	al,#0xD1		
	out	#0x64,al
	call	empty_8042
	mov	al,#0xDF		
	out	#0x60,al
	call	empty_8042



郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。