GDT临时分段

本文深入探讨了从实模式切换至保护模式的过程,重点介绍了GDT(全局描述符表)的作用及其构建方法。文章详细解释了如何通过设置GDT描述符,包括代码段、数据段和VGA内存数据段,来实现对内存的高效访问。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

GDT临时分段

GDT临时段说明

现在已经进入了保护模式, 目前的改变

  • 可以访问1M以上的内存了
  • 可以使用32位的指令操作

问题:

由于以前的是实式下段寄存器寻址方式无法使用了,我们必须切换到使用GDT段方式来寻址

首要的任务就是先建立一个临时的GDT段,以便我们接下来的指令操作

目前准备建立3个段,如下:

Base, Limit, Attr

代码段:0x00000000, 0xfffff, 1100_1001_1010B = db 0x0000ffff, 0x00cf9a00

数据段:0x00000000, 0xfffff, 1100_1001_0010B = db 0x0000ffff, 0x00cf9200

vga显卡内存数据段:x000b8000, 0x07fff, 1100_1001_0010B

GDT解析宏

首先创建一个nasm宏,可以进行GDT解析

参数为GDT的Base, Limit, Attr,也就是段基址(32位),段界限(20位),段描述符(12位),然后生成GDT在内存中的数据

;---------------------------------------------------------
; 描述符
; usage: Gdt_Descriptor Base, Limit, Attr :  段基址(32位),段界限(20位),段描述符(12位)
;        Base:  dd
;        Limit: dd (low 20 bits available)
;        Attr:  dw (lower 4 bits of higher byte are always 0)
;---------------------------------------------------------
%macro Gdt_Descriptor  3
dw %2 & 0xFFFF
dw %1 & 0xFFFF
db (%1 >> 16) & 0xFF
db %3 & 0xFF
db ((%3 >> 4 ) & 0xF0 ) | ((%2 >> 16) & 0x0F )
db (%1 >> 24) & 0xFF
%endmacro

GDT 描述符属性定义

;--------------   gdt描述符属性  -------------
DESC_G_4K   equ   1000_0000_0000b   
DESC_D_32   equ   0100_0000_0000b
DESC_L      equ   0000_0000_0000b   ;  64位代码标记,此处标记为0便可。
DESC_AVL    equ   0000_0000_0000b   ;  cpu不用此位,暂置为0  
DESC_P      equ   0000_1000_0000b
DESC_DPL_0  equ         000_0000b
DESC_DPL_1  equ         010_0000b
DESC_DPL_2  equ         100_0000b
DESC_DPL_3  equ         110_0000b
DESC_S_CODE equ           1_0000b
DESC_S_DATA equ           1_0000b
DESC_S_SYS  equ           0_0000b
DESC_TYPE_CODE  equ         1010b   ;x=1可执行代码段,c=0普通,r=1可读,a=0已访问位a清0  
DESC_TYPE_DATA  equ         0010b   ;x=0数据段,e=0向高位扩展,w=1可写,a=0已访问位a清0.

;--------------   选择子属性  ---------------
RPL0    equ   00b
RPL1    equ   01b
RPL2    equ   10b
RPL3    equ   11b
TI_GDT  equ   000b
TI_LDT  equ   100b

    
DESC_CODE equ  DESC_G_4K + DESC_D_32 + DESC_L + DESC_AVL + DESC_P + DESC_DPL0 + DESC_S_CODE + DESC_TYPE_CODE 
DESC_DATA equ  DESC_G_4K + DESC_D_32 + DESC_L + DESC_AVL + DESC_P + DESC_DPL0 + DESC_S_DATA + DESC_TYPE_DATA 

定义GDT全局描述符表

;---------------------------------
;定义GDT全局描述符表
;code: 0x0000ffff, 0x00cf9a00   
;data: 0x0000ffff, 0x00cf9200
;vga:
Gdt_Addr:
    dw      8*4-1                       ;指定段上限为4(GDT全局描述符表的大小)
    dd      gdt_table_addr              ;GDT全局描述符表的地址
Gdt_Table_Addr:
                Gdt_Descriptor 0,0,0
Label_Sel_Code: Gdt_Descriptor 0x00000000, 0xfffff, DESC_CODE  ;可以执行的段
Label_Sel_Data: Gdt_Descriptor 0x00000000, 0xfffff, DESC_DATA  ;可以读写的段
Label_Sel_VGA:  Gdt_Descriptor 0x000b8000, 0x07fff, DESC_DATA  ;vga段
    dw      0   

;--------------------------------
;选择子
Selector_Code  equ   Label_Sel_Code - Gdt_Table_Addr
Selector_Data  equ   Label_Sel_Data - Gdt_Table_Addr
Selector_VGA  equ    Label_Sel_VGA - Gdt_Table_Addr

加载gdt

;---------------------------
;加载GDT
lgdt [Gdt_Addr]

代码

创建常量头文件

创建 boot.inc文件。用来配置常量

;---------------------------------------------------------
; 描述符
; usage: Gdt_Descriptor Base, Limit, Attr :  段基址(32位),段界限(20位),段描述符(12位)
;        Base:  dd
;        Limit: dd (low 20 bits available)
;        Attr:  dw (lower 4 bits of higher byte are always 0)
;---------------------------------------------------------
%macro Gdt_Descriptor  3
dw %2 & 0xFFFF
dw %1 & 0xFFFF
db (%1 >> 16) & 0xFF
db %3 & 0xFF
db ((%3 >> 4 ) & 0xF0 ) | ((%2 >> 16) & 0x0F )
db (%1 >> 24) & 0xFF
%endmacro



;--------------   gdt描述符属性  -------------
DESC_G_4K   equ   1000_0000_0000b   
DESC_D_32   equ   0100_0000_0000b
DESC_L      equ   0000_0000_0000b   ;  64位代码标记,此处标记为0便可。
DESC_AVL    equ   0000_0000_0000b   ;  cpu不用此位,暂置为0  
DESC_P      equ   0000_1000_0000b
DESC_DPL_0  equ         000_0000b
DESC_DPL_1  equ         010_0000b
DESC_DPL_2  equ         100_0000b
DESC_DPL_3  equ         110_0000b
DESC_S_CODE equ           1_0000b
DESC_S_DATA equ           1_0000b
DESC_S_SYS  equ           0_0000b
DESC_TYPE_CODE  equ         1010b   ;x=1可执行代码段,c=0普通,r=1可读,a=0已访问位a清0  
DESC_TYPE_DATA  equ         0010b   ;x=0数据段,e=0向高位扩展,w=1可写,a=0已访问位a清0.


;--------------   选择子属性  ---------------
RPL0    equ   00b
RPL1    equ   01b
RPL2    equ   10b
RPL3    equ   11b
TI_GDT  equ   000b
TI_LDT  equ   100b

DESC_CODE equ  DESC_G_4K + DESC_D_32 + DESC_L + DESC_AVL + DESC_P + DESC_DPL_0 + DESC_S_CODE + DESC_TYPE_CODE 
DESC_DATA equ  DESC_G_4K + DESC_D_32 + DESC_L + DESC_AVL + DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA 

;----------- loader const ------------------
LOADER_SECTOR_LBA       equ 0x1     ;第2个逻辑扇区开始
LOADER_SECTOR_COUNT     equ 9       ;读取9个扇区
LOADER_BASE_ADDR        equ 0x9000  ;内存地址0x9200
LOADER1_BASE_ADDR       equ 0x9800  ;内存地址0x9200
;-------------------------------------------

loader.asm文件

;ratsos
;TAB=4

%include "boot/boot.inc"
section loader vstart=LOADER_BASE_ADDR ;指明程序的偏移的基地址

[bits 16]

    jmp Entry;

;---------------------------------
;定义GDT全局描述符表
;code: 0x0000ffff, 0x00cf9a00   
;data: 0x0000ffff, 0x00cf9200
;vga:
Gdt_Addr:
    dw      8*4-1                       ;指定段上限为4(GDT全局描述符表的大小)
    dd      gdt_table_addr              ;GDT全局描述符表的地址
Gdt_Table_Addr:
                Gdt_Descriptor 0,0,0
Label_Sel_Code: Gdt_Descriptor 0x00000000, 0xfffff, DESC_CODE  ;可以执行的段
Label_Sel_Data: Gdt_Descriptor 0x00000000, 0xfffff, DESC_DATA  ;可以读写的段
Label_Sel_VGA:  Gdt_Descriptor 0x000b8000, 0x07fff, DESC_DATA  ;vga段
                dw      0   

;--------------------------------
;选择子
Selector_Code  equ   Label_Sel_Code - Gdt_Table_Addr
Selector_Data  equ   Label_Sel_Data - Gdt_Table_Addr
Selector_VGA  equ    Label_Sel_VGA - Gdt_Table_Addr



;程序核心内容
Entry:
    
    
    ;------------------
    ;禁止CPU级别的中断,进入保护模式时没有建立中断表
    cli 

    ;------------------
    ;打开A20
    in      al,0x92
    or      al,0000_0010B       ;设置第1位为1
    out     0x92,al
    
    ;------------------
    ;加载GDT
    lgdt [Gdt_Addr]

    ;------------------
    ;进入保护模式
    mov     eax,cr0
    or      eax,0x1      ;设置第0位为1
    mov     cr0,eax

    jmp  $

测试

使用bochs执行

打好断点后,执行并查看gtd描述符数据是否正确。

info gdt

1573351-20190104235309313-1807897446.png

转载于:https://www.cnblogs.com/mlzrq/p/10223088.html

资源下载链接为: https://pan.quark.cn/s/1bfadf00ae14 “STC单片机电压测量”是一个以STC系列单片机为基础的电压检测应用案例,它涵盖了硬件电路设计、软件编程以及数据处理等核心知识点。STC单片机凭借其低功耗、高性价比和丰富的I/O接口,在电子工程领域得到了广泛应用。 STC是Specialized Technology Corporation的缩写,该公司的单片机基于8051内核,具备内部振荡器、高速运算能力、ISP(在系统编程)和IAP(在应用编程)功能,非常适合用于各种嵌入式控制系统。 在源代码方面,“浅雪”风格的代码通常简洁易懂,非常适合初学者学习。其中,“main.c”文件是程序的入口,包含了电压测量的核心逻辑;“STARTUP.A51”是启动代码,负责初始化单片机的硬件环境;“电压测量_uvopt.bak”和“电压测量_uvproj.bak”可能是Keil编译器的配置文件备份,用于设置编译选项和项目配置。 对于3S锂电池电压测量,3S锂电池由三节锂离子电池串联而成,标称电压为11.1V。测量时需要考虑电池的串联特性,通过分压电路将高电压转换为单片机可接受的范围,并实时监控,防止过充或过放,以确保电池的安全和寿命。 在电压测量电路设计中,“电压测量.lnp”文件可能包含电路布局信息,而“.hex”文件是编译后的机器码,用于烧录到单片机中。电路中通常会使用ADC(模拟数字转换器)将模拟电压信号转换为数字信号供单片机处理。 在软件编程方面,“StringData.h”文件可能包含程序中使用的字符串常量和数据结构定义。处理电压数据时,可能涉及浮点数运算,需要了解STC单片机对浮点数的支持情况,以及如何高效地存储和显示电压值。 用户界面方面,“电压测量.uvgui.kidd”可能是用户界面的配置文件,用于显示测量结果。在嵌入式系统中,用
资源下载链接为: https://pan.quark.cn/s/abbae039bf2a 在 Android 开发中,Fragment 是界面的一个模块化组件,可用于在 Activity 中灵活地添加、删除或替换。将 ListView 集成到 Fragment 中,能够实现数据的动态加载与列表形式展示,对于构建复杂且交互丰富的界面非常有帮助。本文将详细介绍如何在 Fragment 中使用 ListView。 首先,需要在 Fragment 的布局文件中添加 ListView 的 XML 定义。一个基本的 ListView 元素代码如下: 接着,创建适配器来填充 ListView 的数据。通常会使用 BaseAdapter 的子类,如 ArrayAdapter 或自定义适配器。例如,创建一个简单的 MyListAdapter,继承自 ArrayAdapter,并在构造函数中传入数据集: 在 Fragment 的 onCreateView 或 onActivityCreated 方法中,实例化 ListView 和适配器,并将适配器设置到 ListView 上: 为了提升用户体验,可以为 ListView 设置点击事件监听器: 性能优化也是关键。设置 ListView 的 android:cacheColorHint 属性可提升滚动流畅度。在 getView 方法中复用 convertView,可减少视图创建,提升性能。对于复杂需求,如异步加载数据,可使用 LoaderManager 和 CursorLoader,这能更好地管理数据加载,避免内存泄漏,支持数据变更时自动刷新。 总结来说,Fragment 中的 ListView 使用涉及布局设计、适配器创建与定制、数据绑定及事件监听。掌握这些步骤,可构建功能强大的应用。实际开发中,还需优化 ListView 性能,确保应用流畅运
06-19
<think>我们正在讨论GDT(全局描述符表)在x86架构中的作用和实现。根据引用,GDT是保护模式下的核心数据结构,用于存储描述符。每个描述符8字节,包含的基地址、界限和访问权限等信息。在32位和64位模式下,GDT的作用有所不同。在32位保护模式下,GDT是必须的,因为内存管理通过分段机制实现。每个描述符定义了内存的属性,包括基地址(32位)、界限(20位,通过粒度扩展为4KB或1字节单位)、类型(代码/数据/系统)、特权级等。处理器通过GDTR寄存器(48位,包含基地址和界限)定位GDT选择子(16位)作为索引,从GDT中取出描述符,从而确定内存访问的合法性和物理地址转换。在64位长模式(IA-32e)下,分段机制被弱化。大多数基址被强制为0,界限被忽略,形成平坦内存模型。但GDT仍然存在,主要用于定义关键系统(如内核和用户代码/数据)和TSS(任务状态)。此外,GDTR在64位下扩展为80位(64位基址+16位界限),但GDT的每个描述符仍为8字节(传统模式)或扩展为16字节(系统描述符,如TSS或LDT)。实现步骤:1.定义GDT内容:至少包含空描述符(全0)、内核代码、内核数据、用户代码、用户数据,可能包含TSS。2.加载GDTR:使用LGDT指令,操作数指向一个6字节(32位)或10字节(64位)的内存区域,包含GDT界限(16位)和基地址(32位或64位)。3.进入保护模式/长模式:设置CR0的PE位(保护模式)或CR4的PAE位+EFER的LME位(长模式)。示例(32位汇编):```assembly;定义GDTgdt_start:dd0,0;空描述gdt_code:dw0FFFFh;界限0-15dw0;基地址0-15db0;基地址16-23db10011010b;访问字节:P=1,DPL=00,S=1,TYPE=1010(代码,可读,非依从)db11001111b;标志:G=1(4KB粒度),D/B=1(32位),AVL=0,界限16-19db0;基地址24-31gdt_data:;类似,TYPE=0010(数据,可写)gdt_end:;GDTR结构gdt_descriptor:dwgdt_end-gdt_start-1;界限ddgdt_start;基地址;加载GDTlgdt[gdt_descriptor];进入保护模式moveax,cr0oreax,1movcr0,eaxjmp08h:flush;远跳转更新CS选择子(索引1*8,即08h)flush:```在64位模式下,GDT的结构类似,但通常不需要设置基址(因为强制为0)。系统描述符(如TSS)需要16字节,但基本代码/数据仍为8字节。作用总结:-32位:内存分段,隔离和保护不同特权级的代码和数据。-64位:保留分段机制的必要部分(如特权级切换),但主要依赖分页管理内存。相关问题:1.如何为64位操作系统设置GDT?2.GDT中的TSS描述符有什么作用?3.在保护模式下如何切换任务?</think>### GDT(全局描述符表)在x86架构中的作用与实现 #### **一、GDT核心作用** 1. **内存分段管理** - 在x86保护模式下,GDT是**唯一全局数据结构**(引用[1]),用于定义内存的属性: - 基地址(Base Address):32位物理内存起始地址 - 界限(Limit):20位长度(最大$2^{20} \times 4\text{KB} = 4\text{GB}$) - 访问权限(Access):特权级、可读/写/执行等(引用[2]) - **物理地址计算**:`物理地址 = 基址 + 偏移量` 2. **特权级隔离** - 通过描述符中的**DPL字**(2位)实现0-3级特权隔离: - 0级:内核态 - 3级:用户态 - 防止用户程序直接访问内核内存(引用[5]) 3. **模式切换基础** - 实模式→保护模式:**必须定义GDT**(引用[3]) - 控制寄存器`CR0`的`PE位=1`时激活保护模式(引用[2]) #### **二、GDT数据结构详解** ```c // 描述符结构(8字节) struct SegmentDescriptor { uint16_t limit_low; // 界限0-15位 uint16_t base_low; // 基地址0-15位 uint8_t base_mid; // 基地址16-23位 uint8_t access; // 访问控制字节 uint8_t granularity; // 粒度标志 uint8_t base_high; // 基地址24-31位 }; ``` **关键字说明**(引用[2][4]): | 字 | 位域 | 作用 | |-------------|--------|----------------------------------------------------------------------| | **G** | 位23 | 粒度:0=字节粒度,1=4KB粒度(界限需$\times 4096$) | | **D/B** | 位22 | 默认操作数大小:0=16位,1=32位 | | **L** | 位21 | 64位代码标志(仅64位有效) | | **AVL** | 位20 | 保留给操作系统使用 | | **P** | 位15 | 存在标志(1=有效) | | **DPL** | 位13-14| 特权级(0-3) | | **S** | 位12 | 描述符类型:0=系统,1=代码/数据 | | **TYPE** | 位8-11 | 类型:代码(可执行)、数据(可写)、TSS等 | #### **三、32位 vs 64位实现差异** | 特性 | 32位保护模式 | 64位长模式(IA-32e) | |--------------------|-----------------------------------|--------------------------------------| | **GDT必要性** | 必须存在 | 仍需要但作用弱化 | | **基址处理** | 实际使用基地址 | 强制基地址=0(平坦内存模型) | | **界限** | 严格检查 | 大部分忽略(除FS/GS系统) | | **GDTR寄存器** | 48位(32位基址+16位界限) | 80位(64位基址+16位界限) | | **描述符扩展** | 固定8字节 | 系统描述符(如TSS)可扩展至16字节 | | **主要用途** | 内存隔离/特权保护 | CS/SS切换特权级,FS/GS存储系统数据 | #### **四、GDT操作流程(32位示例)** 1. **定义GDT结构** ```assembly gdt_start: dd 0, 0 ; 空描述符(强制要求) gdt_code: ; 内核代码 dw 0xFFFF ; 界限0-15 dw 0x0000 ; 基地址0-15 db 0x00 ; 基地址16-23 db 0x9A ; P=1, DPL=00, S=1, TYPE=1010(可执行/可读) db 0xCF ; G=1, D/B=1, AVL=0, 界限16-19=0xF db 0x00 ; 基地址24-31 gdt_data: ; 内核数据 dw 0xFFFF dw 0x0000 db 0x00 db 0x92 ; TYPE=0010(可写) db 0xCF db 0x00 gdt_end: ``` 2. **加载GDTR寄存器** ```assembly gdt_descriptor: dw gdt_end - gdt_start - 1 ; 界限(16位) dd gdt_start ; 基地址(32位) lgdt [gdt_descriptor] ; 加载GDTR ``` 3. **激活保护模式** ```assembly mov eax, cr0 or eax, 0x1 ; 设置PE位 mov cr0, eax jmp 0x08:flush ; 远跳转更新CS选择子(索引=1) flush: mov ax, 0x10 ; 加载数据选择子(索引=2) mov ds, ax ``` #### **五、64位模式下的特殊处理** - **寄存器行为**: - `CS`:隐含当前特权级(CPL) - `SS`:必须与`CS`同级 - `FS/GS`:可用于存储**线性地址基址**(如Linux内核用`GS`存储per-CPU数据) - **TSS描述符**: ```assembly tss_descriptor: dw tss_limit & 0xFFFF ; 界限0-15 dw tss_base & 0xFFFF ; 基址0-15 db (tss_base >> 16) & 0xFF ; 基址16-23 db 0x89 ; P=1, DPL=0, Type=1001(64位TSS) db 0x00 ; 标志 db (tss_base >> 24) & 0xFF ; 基址24-31 dd (tss_base >> 32) & 0xFFFFFFFF ; 64位扩展 dd 0x00000000 ; 保留 ``` > **关键点**:GDT是x86保护模式基石,64位下虽弱化分段但仍需维护关键描述符以实现特权级隔离和系统数据结构定位[^1][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值