启动引导代码分析setup.s

setup的整体作用:

首先利用BIOS中断读取机器的数据,将其保存在地址0x9000:0x0000处,覆盖了原来bootsect.s代码所在的位置,由于bootsetc模块的代

码运行完毕,已经没有其他的用处了,所以可以将其覆盖掉。

启动引导代码分析setup.s

然后关闭中断,setup将system模块整体移动至内存起始处,原来位于0x1000:0x0000,由于movsb和movsw指令的功能是移动一个字节或

者一个字,源地址由寄存器ds:si指定,目的地址由es:di指定。

指令cld指明di和si的方向是递增,而std是递减。

由于system模块大小超过64K(实模式一个段的最大偏移),而移动指令需要指明段寄存器,所以需要分段移动,下面是移动代码,代码语法是

AT&T改写的

# first we move the system to it's rightful place        mov $0x0000, %ax       cld         # 'direction'=0, movs moves forward   do_move:       mov %ax, %es    # destination segment       add $0x1000, %ax       cmp $0x9000, %ax       jz  end_move       mov %ax, %ds    # source segment       sub %di, %di       sub %si, %si       mov     $0x8000, %cx       rep       movsw       jmp do_move   # then we load the segment descriptors    end_move:  

然后设置数据段寄存器ds并加载中断描述符和全局描述符

end_move:       mov $SETUPSEG, %ax  # right, forgot this at first. didn't work :-)       mov %ax, %ds       lidt    idt_48      # load idt with 0,0       lgdt    gdt_48      # load gdt with whatever appropriate  

lidt和lgdt的操作数是6个字节

第一第二字节表示描述符表的长度值,第三到第六字节表示的是32位的线性基地址(描述符在内存的中的位置)

GDT格式的详情请见 

Linux0.11内核--32位保护模式GDT(全局描述符表)

idt_48和gdt_48的内容如下:

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,        # 512+gdt is the real gdt after setup is moved to 0x9020 * 0x10  

其中gdt_48中第一个字节表示描述符表中的描述符的个数,由于GDT表在内存中占用2KB的内存空间,一个GDT有64位(8个字节),故有256项,后面四个字节表示一个32位的线性地址0x0009<<16+0x0200+gdt

实际就是本程序中的gdt的地址。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://127.0.0.1/wyydpy.html