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
call empty_8042 mov al,#0xD1 out #0x64,al call empty_8042 mov al,#0xDF out #0x60,al call empty_8042
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。