千家信息网

操作系统--局部段描述符表的使用

发表于:2024-10-19 作者:千家信息网编辑
千家信息网最后更新 2024年10月19日,Q:什么是LDTA.局部段描述符表1.本质是一个段描述符表,用于定义段描述符2.与GDT类似,可以看作"段描述符的数组"3.通过定义选择子访问局部描述符表中的元素局部段描述符选择子局部段描述符表需要注
千家信息网最后更新 2024年10月19日操作系统--局部段描述符表的使用

Q:什么是LDT
A.局部段描述符表

1.本质是一个段描述符表,用于定义段描述符
2.与GDT类似,可以看作"段描述符的数组"
3.通过定义选择子访问局部描述符表中的元素
局部段描述符选择子

局部段描述符表

需要注意的是
1.局部段描述符表需要在全局段描述符表中注册(增加描述符)
2.通过对应的选择子加载局部段描述符(lldt)
3.局部段描述符从第0项开始使用
在这里会出现一个问题-LDT具体用来干什么?同时为什么还需要一个"额外的"段描述符?
LDT的意义主要体现在两个方面:代码层次的意义-分级管理功能相同意义不同的段(多个代码段);系统层次的意义-实现多任务的基础要素(每个任务对应一系列不同的段)
B.LDT的定义与使用
1.定义独立功能相关的段(代码段,数据段,栈段)
2.将目标段描述符组成局部段描述表(LDT)
3.为各个段描述符定义选择子(SA_TIL)
4.在GDT中定义LDT的段描述符,并定义选择子
C.LDT的定义与使用

代码实现-要在inc.asm中对DA_LDT equ 0x82进行定义要不然会在运行时出现错误

%include "inc.asm"org 0x9000jmp ENTRY_SEGMENT[section .gdt]; GDT definition;                                 段基址,       段界限,       段属性GDT_ENTRY       :     Descriptor    0,            0,           0CODE32_DESC     :     Descriptor    0,    Code32SegLen - 1,    DA_C + DA_32VIDEO_DESC      :     Descriptor 0xB8000,     0x07FFF,         DA_DRWA + DA_32DATA32_DESC     :     Descriptor    0,    Data32SegLen - 1,    DA_DR + DA_32STACK32_DESC    :     Descriptor    0,     TopOfStack32,       DA_DRW + DA_32CODE16_DESC     :     Descriptor    0,        0xFFFF,          DA_C UPDATE_DESC     :     Descriptor    0,        0xFFFF,          DA_DRWTASK_A_LDT_DESC :     Descriptor    0,     TaskALdtLen - 1,    DA_LDT; GDT endGdtLen    equ   $ - GDT_ENTRYGdtPtr:          dw   GdtLen - 1          dd   0; GDT SelectorCode32Selector    equ (0x0001 << 3) + SA_TIG + SA_RPL0VideoSelector     equ (0x0002 << 3) + SA_TIG + SA_RPL0Data32Selector    equ (0x0003 << 3) + SA_TIG + SA_RPL0Stack32Selector   equ (0x0004 << 3) + SA_TIG + SA_RPL0Code16Selector    equ (0x0005 << 3) + SA_TIG + SA_RPL0UpdateSelector    equ (0x0006 << 3) + SA_TIG + SA_RPL0TaskALdtSelector  equ (0x0007 << 3) + SA_TIG + SA_RPL0; end of [section .gdt]TopOfStack16    equ 0x7c00[section .dat][bits 32]DATA32_SEGMENT:    DTOS               db  "D.T.OS!", 0    DTOS_OFFSET        equ DTOS - $$    HELLO_WORLD        db  "Hello World!", 0    HELLO_WORLD_OFFSET equ HELLO_WORLD - $$Data32SegLen equ $ - DATA32_SEGMENT[section .s16][bits 16]ENTRY_SEGMENT:    mov ax, cs    mov ds, ax    mov es, ax    mov ss, ax    mov sp, TopOfStack16    mov [BACK_TO_REAL_MODE + 3], ax    ; initialize GDT for 32 bits code segment    mov esi, CODE32_SEGMENT    mov edi, CODE32_DESC    call InitDescItem    mov esi, DATA32_SEGMENT    mov edi, DATA32_DESC    call InitDescItem    mov esi, STACK32_SEGMENT    mov edi, STACK32_DESC    call InitDescItem    mov esi, CODE16_SEGMENT    mov edi, CODE16_DESC    call InitDescItem    mov esi, TASK_A_LDT_ENTRY    mov edi, TASK_A_LDT_DESC    call InitDescItem    mov esi, TASK_A_CODE32_SEGMENT    mov edi, TASK_A_CODE32_DESC    call InitDescItem    mov esi, TASK_A_DATA32_SEGMENT    mov edi, TASK_A_DATA32_DESC    call InitDescItem    mov esi, TASK_A_STACK32_SEGMENT    mov edi, TASK_A_STACK32_DESC    call InitDescItem    ; initialize GDT pointer struct    mov eax, 0    mov ax, ds    shl eax, 4    add eax, GDT_ENTRY    mov dword [GdtPtr + 2], eax    ; 1. load GDT    lgdt [GdtPtr]    ; 2. close interrupt    cli     ; 3. open A20    in al, 0x92    or al, 00000010b    out 0x92, al    ; 4. enter protect mode    mov eax, cr0    or eax, 0x01    mov cr0, eax    ; 5. jump to 32 bits code    jmp dword Code32Selector : 0BACK_ENTRY_SEGMENT:    mov ax, cs    mov ds, ax    mov es, ax    mov ss, ax    mov sp, TopOfStack16    in al, 0x92    and al, 11111101b    out 0x92, al    sti    mov bp, HELLO_WORLD    mov cx, 12    mov dx, 0    mov ax, 0x1301    mov bx, 0x0007    int 0x10    jmp $; esi    --> code segment label; edi    --> descriptor labelInitDescItem:    push eax    mov eax, 0    mov ax, cs    shl eax, 4    add eax, esi    mov word [edi + 2], ax    shr eax, 16    mov byte [edi + 4], al    mov byte [edi + 7], ah    pop eax    ret[section .s16][bits 16]CODE16_SEGMENT:    mov ax, UpdateSelector    mov ds, ax    mov es, ax    mov fs, ax    mov gs, ax    mov ss, ax    mov eax, cr0    and al, 11111110b    mov cr0, eaxBACK_TO_REAL_MODE:        jmp 0 : BACK_ENTRY_SEGMENTCode16SegLen    equ    $ - CODE16_SEGMENT[section .s32][bits 32]CODE32_SEGMENT:    mov ax, VideoSelector    mov gs, ax    mov ax, Stack32Selector    mov ss, ax    mov eax, TopOfStack32    mov esp, eax    mov ax, Data32Selector    mov ds, ax    mov ebp, DTOS_OFFSET    mov bx, 0x0C    mov dh, 12    mov dl, 33    call PrintString    mov ebp, HELLO_WORLD_OFFSET    mov bx, 0x0C    mov dh, 13    mov dl, 31    call PrintString    mov ax, TaskALdtSelector    lldt ax    jmp TaskACode32Selector : 0    ; jmp Code16Selector : 0; ds:ebp    --> string address; bx        --> attribute; dx        --> dh : row, dl : colPrintString:    push ebp    push eax    push edi    push cx    push dxprint:    mov cl, [ds:ebp]    cmp cl, 0    je end    mov eax, 80    mul dh    add al, dl    shl eax, 1    mov edi, eax    mov ah, bl    mov al, cl    mov [gs:edi], ax    inc ebp    inc dl    jmp printend:    pop dx    pop cx    pop edi    pop eax    pop ebp    retCode32SegLen    equ    $ - CODE32_SEGMENT[section .gs][bits 32]STACK32_SEGMENT:    times 1024 * 4 db 0Stack32SegLen equ $ - STACK32_SEGMENTTopOfStack32  equ Stack32SegLen - 1; ==========================================;;            Task A Code Segment ;; ==========================================[section .task-a-ldt]; Task A LDT definition;                                             段基址,                段界限,                段属性TASK_A_LDT_ENTRY:TASK_A_CODE32_DESC    :    Descriptor          0,           TaskACode32SegLen - 1,        DA_C + DA_32TASK_A_DATA32_DESC    :    Descriptor          0,           TaskAData32SegLen - 1,        DA_DR + DA_32TASK_A_STACK32_DESC   :    Descriptor          0,           TaskAStack32SegLen - 1,       DA_DRW + DA_32TaskALdtLen  equ   $ - TASK_A_LDT_ENTRY; Task A LDT SelectorTaskACode32Selector  equ   (0x0000 << 3) + SA_TIL + SA_RPL0TaskAData32Selector  equ   (0x0001 << 3) + SA_TIL + SA_RPL0TaskAStack32Selector equ   (0x0002 << 3) + SA_TIL + SA_RPL0[section .task-a-dat][bits 32]TASK_A_DATA32_SEGMENT:    TASK_A_STRING        db   "This is Task A!", 0    TASK_A_STRING_OFFSET equ  TASK_A_STRING - $$TaskAData32SegLen  equ  $ - TASK_A_DATA32_SEGMENT[section .task-a-gs][bits 32]TASK_A_STACK32_SEGMENT:    times 1024 db 0TaskAStack32SegLen  equ  $ - TASK_A_STACK32_SEGMENTTaskATopOfStack32   equ  TaskAStack32SegLen - 1[section .task-a-s32][bits 32]TASK_A_CODE32_SEGMENT:    mov ax, VideoSelector    mov gs, ax    mov ax, TaskAStack32Selector    mov ss, ax    mov eax, TaskATopOfStack32    mov esp, eax    mov ax, TaskAData32Selector    mov ds, ax    mov ebp, TASK_A_STRING_OFFSET    mov bx, 0x0C    mov dh, 14    mov dl, 29    call PrintString    jmp $; ds:ebp    --> string address; bx        --> attribute; dx        --> dh : row, dl : colTaskACode32SegLen   equ  $ - TASK_A_CODE32_SEGMENT

运行结果
该处的运行结果

从运行结果可以得知并没有打印出自定义的字符串,还是打印之前的结果,同时发现还存在一个错误,就是CPU进行了重置,但是取消掉call PrintString 这个操作,会发现存在的错误消失了,这个函数是保护模式下的函数在这里调用出现错误的原因是属于其它段的,不属于现在的段,代码段发生了跳转,选择子不一样了。可以进行改进的是将之前的打印函数复制粘贴一份到现在的段中,需要注意的是要将名字进行修改,不然会出现错误
改正后的代码,注意jmp Code16Selector : 0命令会返回实模式打印Hello World及打印结果



D.多任务程序设计的实现思路

从这张图可以联想出-在保护模式下的不同段之间如何进行代码复用?
小结
1.局部段描述符表用于组织功能相关的段
2.局部段描述符表需要加载后才能正常使用
3.局部段描述符表必须在全局段描述符表中注册
4.通过局部段描述符表的选择子对其进行访问
5.局部段描述符表是实现多任务的基础

0