张国祥 发表于 2013-1-7 21:05:42

保护模式问题(LDT和自定义段基址的段的冲突问题)

本帖最后由 张国祥 于 2013-1-7 21:13 编辑

%include "pm.inc"
org 0100h
jmp start


GDT_DESC:                Descriptor      0,0,0
NORMAL_DESC:      Descriptor      0,0ffffh,DA_DRW
RETURN_16_DESC:      Descriptor      0,0ffffh,DA_C
MAIN_DESC:                Descriptor      0,mainlen-1,DA_C+DA_32
DISP_DESC:                Descriptor      0b8000h,0ffffh,DA_DRW
STK_DESC:                Descriptor      0,TopOfStk+1,DA_DRW+DA_32
DATA_DESC:                Descriptor      0,datalen-1,DA_DRW
LDT_DESC:                Descriptor      0,ldtlen-1,DA_LDT
TEST_DESC:                Descriptor      500000h,0ffffh,DA_DRW
;test和ldt两个描述符是不是不能共存

gdtlim                equ      $-$-1
;注意长度和界限的区别
dd 0

SEL_NORMAL                EQU                NORMAL_DESC-GDT_DESC
SEL_RETURN_16      EQU                RETURN_16_DESC-GDT_DESC
SEL_MAIN                EQU                MAIN_DESC-GDT_DESC
SEL_DISP                EQU                DISP_DESC-GDT_DESC
SEL_STK                        EQU                STK_DESC-GDT_DESC
SEL_DATA                EQU                DATA_DESC-GDT_DESC
SEL_LDT                        EQU                LDT_DESC-GDT_DESC

SEL_TEST                EQU                TEST_DESC-GDT_DESC



ldt:
L_CODE_DESC:      Descriptor      0,lcodelen-1,DA_C+DA_32
ldtlen                equ      $-$

SEL_L_CODE                EQU                L_CODE_DESC-ldt+SA_TIL



lcode:
      mov edi,160*0+2*40
      mov ah,0ah
      mov al,'L'
      mov ,ax
      jmp SEL_RETURN_16:0
      
lcodelen                equ      $-$


data:
      RMSPValue      dw 0
      pmmsg:                db 'Protect Mode!',0
      pmmsgost      equ      pmmsg-$
datalen                        equ      $-$


stk:
      times 512 db 0
TopOfStk                equ      $-$-2



start:
      mov ax,cs
      mov ds,ax
      mov es,ax
      mov ss,ax
      mov sp,0100h
      
      mov ,ax
      mov ,sp
      
      ;初始化
      movzx eax,ax
      shl eax,4
      add eax,main
      mov word ,ax
      shr eax,16
      mov byte ,al
      mov byte ,ah
      
      mov ax,ds
      movzx eax,ax
      shl eax,4
      add eax,data
      mov word ,ax
      shr eax,16
      mov byte ,al
      mov byte ,ah
      
      mov ax,ds
      movzx eax,ax
      shl eax,4
      add eax,return16
      mov word ,ax
      shr eax,16
      mov byte ,al
      mov byte ,ah
      
      mov ax,ds
      movzx eax,ax
      shl eax,4
      add eax,ldt
      mov word ,ax
      shr eax,16
      mov byte ,al
      mov byte ,ah
      
      mov ax,cs
      movzx eax,ax
      shl eax,4
      add eax,lcode
      mov word ,ax
      shr eax,16
      mov byte ,al
      mov byte ,ah
      
      mov ax,ss
      movzx eax,ax
      shl eax,4
      add eax,stk
      mov word ,ax
      shr eax,16
      mov byte ,al
      mov byte ,ah
      
      mov ax,ds
      movzx eax,ax
      shl eax,4
      add eax,GDT_DESC
      mov dword ,eax
      lgdt
      
      cli
      
      in al,92h
      or al,00000010b
      out 92h,al
      
      mov eax,cr0
      or al,1
      mov cr0,eax
      
      jmp dword SEL_MAIN:0
      
real:
      mov ax,cs
      mov ds,ax
      mov es,ax
      mov ss,ax
      mov sp,
      
      in      al, 92h
      and      al, 11111101b
      out      92h, al

      sti

      mov      ax, 4c00h
      int      21h
      


return16:
      mov ax,SEL_NORMAL
      mov ds,ax
      mov es,ax
      mov ss,ax
      mov fs,ax
      mov gs,ax
      
      mov      eax, cr0
      and      al, 11111110b
      mov      cr0, eax
      
GoToReal:
      jmp 0:real
      


main:
      mov ax,SEL_DISP
      mov gs,ax
      mov ax,SEL_DATA
      mov ds,ax
      
      mov ax,SEL_TEST
      mov es,ax
      
      mov ax,SEL_STK
      mov ss,ax
      mov sp,TopOfStk

      mov ah,0ah
      mov esi,pmmsgost
      mov edi,0
      cld

.1:
      lodsb
      cmp al,0
      je .2
      mov ,ax
      add edi,2
      jmp .1
      
.2:
      jmp SEL_RETURN_16:0
      mov ax,SEL_LDT
      lldt ax
      call SEL_L_CODE:0
mainlen                equ      $-$
很诡异,是不是LDT描述符和TEST描述符不能共存,一运行就崩溃

李忠 发表于 2013-1-7 21:05:43

问题的根本原因是这一句:
gdtlimequ $-$-1把这里的“equ”改成“dw”就Okay了。

下面来具体分析一下,特别是奇偶描述符个数导致有时成功/失败的原因。

首先,lgdt指令的操作数需要一个指向6字节内存区域的指针。在你的程序中,是这样做的:

lgdt 遗憾的是,gdtlim是一个常数 $-$$-1,所以,DS:不会在你指定的位置(GDT表的后面)。

那么,它在哪里呢?
注意,这是一个.COM文件,段寄存器DS指向程序段前缀PSP。因此,gdtlim如果不太大的话,它正好指向PSP内部。在你这个例子中,它正好位于一个非常特殊的位置,即,全零数据和非零数据的交汇处。
在这种情况下,如果描述符
q:    Descriptor 0,0,0 ;一旦注释此行,就会出问题没有注释掉,那么gdtlim的数值会随着GDT表的尺寸增大而变大,而且正好使那6个字节中的前两个字节(GDT尺寸)为非零。所以,程序能正常工作。但是,不要得意,此时的GDT的界限值并不是正确的,而是非常大(我做过实验),只是因为非零,所以没有导致程序出错。
然而,如果注释掉那一行,那么,那么gdtlim的数值会随着GDT表的尺寸减小而变小,这正好导致那6个字节中的前两个字节(GDT尺寸)为零(因为PSP中那个地方原本就是0)。此时,执行lgdt指令后,GDT的界限值为0,进入保护模式时出现异常。

张国祥 发表于 2013-1-8 13:21:42

:dizzy:场外求助啊

o70078 发表于 2013-1-8 21:30:01

是数量问题撒,换下GDT描述符数量即可- -

wybmagic 发表于 2013-1-9 19:19:40

看 于渊的书呢?

张国祥 发表于 2013-1-10 12:23:55

wybmagic 发表于 2013-1-9 19:19 static/image/common/back.gif
看 于渊的书呢?

没错,你会吗?:Q这问题太诡异了

张国祥 发表于 2013-1-11 18:54:41

:dizzy:啊啊,求解答,或是有什么好资料推荐也好啊- -来个人吧

张国祥 发表于 2013-1-11 18:55:34

o70078 发表于 2013-1-8 21:30 static/image/common/back.gif
是数量问题撒,换下GDT描述符数量即可- -

没有任何资料表示描述符数量有限制啊

李忠 发表于 2013-1-11 20:24:39

和描述符的数量与类型没有关系。具体是出现什么问题,描述一下。

张国祥 发表于 2013-1-11 23:32:52

本帖最后由 张国祥 于 2013-1-11 23:37 编辑

李忠 发表于 2013-1-11 20:24 static/image/common/back.gif
和描述符的数量与类型没有关系。具体是出现什么问题,描述一下。
经过我的测试,我手动指定一个固定段基址的描述符(比如5MB处)和LDT描述符同时存在时就会引发错误,但有个神奇的地方就在于如果我再加一个空描述符在GDT内,反而不会出错,
如果再加一条,又会出错,也就是说GDT内的描述符个数为奇数时就会出错(包括首个空描述符)。
我留个源码吧,麻烦帮忙看下,谢谢。,zip包含pm.inc和ldt-5m.asm两个文件

李忠 发表于 2013-1-12 12:39:57

总有个出错位置和出错信息吧,告诉我吧。

李忠 发表于 2013-1-12 12:41:32

全是宏、EQU常量,还是COM,有点晕,你告诉我出错位置我好缩小范围。

张国祥 发表于 2013-1-12 14:27:30

李忠 发表于 2013-1-12 12:41 static/image/common/back.gif
全是宏、EQU常量,还是COM,有点晕,你告诉我出错位置我好缩小范围。

我没找到好的工具调试com,不过真的没有出错信息,不论是用dosbox还是虚拟机下的dos,都是直接卡住

张国祥 发表于 2013-1-12 14:29:09

李忠 发表于 2013-1-12 12:41 static/image/common/back.gif
全是宏、EQU常量,还是COM,有点晕,你告诉我出错位置我好缩小范围。

出错位置就是gdt下的最后一个描述符,注释掉就会出错

李忠 发表于 2013-1-12 17:43:02

问题的原因已经找到了。

李忠 发表于 2013-1-12 17:47:00

等朕整理一下,今晚告诉你哈。

李忠 发表于 2013-1-12 19:38:06

注意上面那幅图,这是在执行jmp dword SEL_MAIN:0指令前,段寄存器(包括GDTR)的内容(未加注释,程序可以正常执行的情况下)。
可以看到,DS=0xc4b0,GDT表的基地址是0xc5b4,GDT界限为0xcd00

李忠 发表于 2013-1-12 21:42:17

这是gdtlim所指向的PSP内存区域映像:

注意,图中,00c5b4是你的程序写入的GDT基地址,cd00是PSP原有的内容,被误用作GDT界限值。

张国祥 发表于 2013-1-12 21:43:43

李忠 发表于 2013-1-12 19:38 static/image/common/back.gif
注意上面那幅图,这是在执行指令前,段寄存器(包括GDTR)的内容(未加注释,程序可以正常执行的情况下)。 ...

{:7_157:}谢谢 李老师,了解dw和equ的区别了,equ仅仅是人方便记忆和计算,,并不占用实际空间,导致lgdt实际取址时的错误。

张国祥 发表于 2013-1-12 21:48:49

李忠 发表于 2013-1-12 21:42 static/image/common/back.gif
这是gdtlim所指向的PSP内存区域映像:

注意,图中,00c5b4是你的程序写入的GDT基地址,cd00是PSP原有的内 ...

OK,了解,Bochs我还没怎么用过,我现在所学看的都是于渊老师那本书的。似乎其它适合基础较低的书很少。
页: [1]
查看完整版本: 保护模式问题(LDT和自定义段基址的段的冲突问题)