Open GoogleCodeExporter opened 9 years ago
/* chapter3/2/loader.S #include "pm.h" .code16 .text jmp LABEL_BEGIN /* jump over the .data section. */ /* Global Descriptor Table */ LABEL_GDT: Descriptor 0, 0, 0 LABEL_DESC_CODE32: Descriptor 0, (SegCode32Len - 1), (DA_C + DA_32) LABEL_DESC_DATA: Descriptor 0, (DataLen - 1), DA_DRW LABEL_DESC_STACK: Descriptor 0, TopOfStack, (DA_DRWA + DA_32) LABEL_DESC_VIDEO: Descriptor 0xB8000, 0xffff, DA_DRW LABEL_DESC_LDT: Descriptor 0, (LDTLen - 1), DA_LDT ============================================================================== 理解1: LABEL_GDT 为GDT描述符表,主要用于存放GDT的段首地址。 LABEL_DESC_CODE32 为GDT描述符表中的一个描述符。 LABEL_DESC_DATA 为数据段描述符,主要用于存放数据段的段首地址 LABEL_DESC_STACK 为堆栈段描述符,主要用于存放堆栈段的段首地址,在本例�� �只作 扩展保留用。 LABEL_DESC_VIDEO 为显示字符串而设的段描述,主要用于存放该段的首地址 LABEL_DESC_LDT 为LDT描述符,主要用于存放LDT的段首地址 以上6个段描述符都是GDT表里面的段描述符。 ============================================================================== .set GdtLen, (. - LABEL_GDT) /* GDT Length */ GdtPtr: .2byte (GdtLen - 1) /* GDT Limit */ .4byte 0 /* GDT Base */ /* GDT Selector(TI flag clear) */ .set SelectorCode32, (LABEL_DESC_CODE32 - LABEL_GDT) .set SelectorData, (LABEL_DESC_DATA - LABEL_GDT) .set SelectorStack, (LABEL_DESC_STACK - LABEL_GDT) .set SelectorVideo, (LABEL_DESC_VIDEO - LABEL_GDT) .set SelectorLDT, (LABEL_DESC_LDT - LABEL_GDT) ============================================================================== 理解2: 在选择子头3位都假定为0的情况下, SelectorCode32 的值为LABEL_DESC_CODE32描述符与GDT段描述符之间的偏移量。 SelectorData 的值为LABEL_DESC_DATA描述符与GDT段描述符之间的偏移量。 SelectorStack 的值为LABEL_DESC_STACK描述符与GDT段描述符之间的偏移量。 SelectorVideo 的值为LABEL_DESC_VIDEO描述符与GDT段描述符之间的偏移量。 SelectorLDT 的值为LABEL_DESC_LDT描述符与GDT段描述符之间的偏移量。 ============================================================================== /* LDT segment */ LABEL_LDT: LABEL_LDT_DESC_CODEA: Descriptor 0, (CodeALen - 1), (DA_C + DA_32) .set LDTLen, (. - LABEL_LDT) /* LDT Length */ /* LDT Selector (TI flag set)*/ .set SelectorLDTCodeA, (LABEL_LDT_DESC_CODEA - LABEL_LDT + SA_TIL) ============================================================================== 理解3: 段描述符LABEL_LDT_DESC_CODEA是LDT段描述符表里面的一个段描述符 ============================================================================== /* 32-bit global data segment. */ LABEL_DATA: PMMessage: .ascii "Welcome to protect mode! ^-^\0" LDTMessage: .ascii "Aha, you jumped into a LDT segment.\0" .set OffsetPMMessage, (PMMessage - LABEL_DATA) .set OffsetLDTMessage, (LDTMessage - LABEL_DATA) .set DataLen, (. - LABEL_DATA) ============================================================================== 理解4: 在数据段LABEL_DATA中: 定义了2个字符串,PMMessage,LDTMessage,并且设定了他们俩的长 度。 同时,也设定了数据段的长度DataLen,其值为整个数据段的长� �� ============================================================================== /* 32-bit global stack segment. */ LABEL_STACK: .space 512, 0 .set TopOfStack, (. - LABEL_STACK - 1) /* Program starts here. */ LABEL_BEGIN: mov %cs, %ax /* Move code segment address(CS) to data segment */ mov %ax, %ds /* register(DS), ES and SS. Because we have */ mov %ax, %es /* embedded .data section into .code section in */ mov %ax, %ss /* the start(metioned in the NOTE above). */ mov $0x100, %sp /* Initialize 32-bits code segment descriptor. */ InitDesc LABEL_SEG_CODE32, LABEL_DESC_CODE32 /* Initialize data segment descriptor. */ InitDesc LABEL_DATA, LABEL_DESC_DATA /* Initialize stack segment descriptor. */ InitDesc LABEL_STACK, LABEL_DESC_STACK /* Initialize LDT descriptor in GDT. */ InitDesc LABEL_LDT, LABEL_DESC_LDT /* Initialize code A descriptor in LDT. */ InitDesc LABEL_CODEA, LABEL_LDT_DESC_CODEA ============================================================================== 理解5: 1、初始化段描述符LABEL_DESC_CODE32,即将代码段中标号LABEL_SEG_C ODE32的地址 (包括 代码段首地址和它在代码段中的段内偏移)作为段描述符LABEL _DESC_CODE32的段地址存于 段描述符LABEL_DESC_CODE32。 2、同理于 LABEL_DESC_DATA,LABEL_DESC_STACK,LABEL_DESC_LDT,LABEL_LDT_DESC_CODEA ============================================================================== /* Prepared for loading GDTR */ xor %eax, %eax mov %ds, %ax shl $4, %eax add $(LABEL_GDT), %eax /* eax <- gdt base*/ movl %eax, (GdtPtr + 2) /* Load GDTR(Global Descriptor Table Register) */ lgdtw GdtPtr ============================================================================== 理解6: 将数据段寄存器中存有数据段地址作为段描述符表LABEL_GDT 的首地址并载入。 ============================================================================== /* Clear Interrupt Flags */ cli /* Open A20 line. */ inb $0x92, %al orb $0b00000010, %al outb %al, $0x92 /* Enable protect mode, PE bit of CR0. */ movl %cr0, %eax orl $1, %eax movl %eax, %cr0 /* Mixed-Size Jump. */ ljmpl $SelectorCode32, $0 /* Thanks to earthengine@gmail, I got */ /* this mixed-size jump insn of gas. */ ============================================================================== 理解7: 由于选择子$SelectorCode32存放的是LABEL_DESC_CODE32描述符与GDT段描 述符之间的 偏移量, 而GDT段描述符表也已载入(即GDT的首地址CPU已知道),因此�� �合跳转指令直接就跳转至 段描述符LABEL_DESC_CODE32的首地址。 另外,在前面提到的: InitDesc LABEL_SEG_CODE32, LABEL_DESC_CODE32 如果改成如下: InitDesc LABEL_GDT, LABEL_DESC_CODE32 那混合跳转指令是不是就也得改成如下? ljmpl $SelectorGDT, $0 (注:文中并没有$SelectorGDT,这是我杜撰上去的,可以假定如� ��: .set SelectorGDT, (LABEL_GDT - LABEL_GDT) ) ============================================================================== /* 32-bit code segment for LDT */ LABEL_CODEA: .code32 mov $(SelectorVideo), %ax mov %ax, %gs movb $0xC, %ah /* 0000: Black Back 1100: Red Front */ xor %esi, %esi xor %edi, %edi movl $(OffsetLDTMessage), %esi movl $((80 * 12 + 0) * 2), %edi cld /* Clear DF flag. */ ============================================================================== 理解8: mov $(SelectorVideo), %ax mov %ax, %gs 将选择子的地址给寄存器%gs并作为字符串的显示用。由于选�� �子SelectorVideo存放的是 LABEL_DESC_VIDEO描述符与GDT段描述符之间的偏移量,而GDT段描述� ��表也已载入(即GDT 的首地址CPU已知道),因此显示字符串时用到的内存段便是�� �段描述符LABEL_DESC_VIDEO 首地址开始的一段内存。这跟0B800H作为ES的起始地址用于显示 字符串的情况一样, 只是这 次的首地址不是0B800H,而是段描述符LABEL_DESC_VIDEO首地址。 ============================================================================== /* Display a string from %esi(string offset) to %edi(video segment). */ CODEA_1: lodsb /* Load a byte from source */ test %al, %al jz CODEA_2 mov %ax, %gs:(%edi) add $2, %edi jmp CODEA_1 CODEA_2: /* Stop here, infinate loop. */ jmp . .set CodeALen, (. - LABEL_CODEA) /* 32-bit code segment for GDT */ LABEL_SEG_CODE32: mov $(SelectorData), %ax mov %ax, %ds /* Data segment selector */ mov $(SelectorStack), %ax mov %ax, %ss /* Stack segment selector */ mov $(SelectorVideo), %ax mov %ax, %gs /* Video segment selector(dest) */ mov $(TopOfStack), %esp ============================================================================== 理解9: 同理,通过对%ds,%ss,%gs,%esp的初始化,CPU获知了各个段的首地� ��。 ============================================================================== movb $0xC, %ah /* 0000: Black Back 1100: Red Front */ xor %esi, %esi xor %edi, %edi movl $(OffsetPMMessage), %esi movl $((80 * 10 + 0) * 2), %edi cld /* Clear DF flag. */ /* Display a string from %esi(string offset) to %edi(video segment). */ CODE32_1: lodsb /* Load a byte from source */ test %al, %al jz CODE32_2 mov %ax, %gs:(%edi) add $2, %edi jmp CODE32_1 CODE32_2: mov $(SelectorLDT), %ax lldt %ax ljmp $(SelectorLDTCodeA), $0 ============================================================================== 理解10: 如果LABEL_LDT_DESC_CODEA是LDT表中的一个段描述符,那根据: InitDesc LABEL_CODEA, LABEL_LDT_DESC_CODEA 得知,该段描述符中所存的段地址是标号LABEL_CODEA的地址。语 句: ljmp $(SelectorLDTCodeA), $0 是在加载LDT表后“混合跳转”(是混合跳转吗?但已经在.code 32里面了....)至标号 LABEL_CODEA, 从而实现字符串的显示。另外,程序段: LABEL_CODEA: .code32 mov $(SelectorVideo), %ax mov %ax, %gs movb $0xC, %ah /* 0000: Black Back 1100: Red Front */ xor %esi, %esi xor %edi, %edi movl $(OffsetLDTMessage), %esi movl $((80 * 12 + 0) * 2), %edi cld /* Clear DF flag. */ /* Display a string from %esi(string offset) to %edi(video segment). */ CODEA_1: lodsb /* Load a byte from source */ test %al, %al jz CODEA_2 mov %ax, %gs:(%edi) add $2, %edi jmp CODEA_1 CODEA_2: /* Stop here, infinate loop. */ jmp . .set CodeALen, (. - LABEL_CODEA) 是用于显示“Aha, you jumped into a LDT segment.”,而标号CODEA_2里面的程序段 是用于结束程序用的,是吗?(也就是语句: “jmp .” ) ============================================================================== /* Get the length of 32-bit segment code. */ .set SegCode32Len, . - LABEL_SEG_CODE32 以上的各个理解不知道对不对,有误的请指出,谢谢。
Original issue reported on code.google.com by linux...@gmail.com on 26 Sep 2008 at 7:17
linux...@gmail.com
希望与作者共同讨论,只为加深对书中例子的理解。另,对�� �操作系统的编写,本人是一初学 者,期望通过本书的学习能得到提高,因此非常期待与作者�� �广大读者一起讨论,一起提高。学 习之初,有些问题可能会提得比较“幼稚”,希望作者不要�� �弃才好,呵呵。
Original comment by linux...@gmail.com on 27 Sep 2008 at 6:16
Original issue reported on code.google.com by
linux...@gmail.com
on 26 Sep 2008 at 7:17