十堰市湖北汽车工业学院电气工程系(442002)  陈家祺
摘 要: 分析了80486CPU 的寻址机制, 提出了在实方式下直接访问4GB 内存的策略和C 程序设计方法。

关键词: DO S 程序 扩展内存 程序设计

在高档PC 微机系统中, 如80486CPU 微机系统,应用软件的开发可以基于DO S 系统的实方式, 也可以基于W indow s和O Sö2 系统的保护方式。如何在DO S系统的实方式下开发具有访问扩展内存的应用程序,这是广大软件开发者关心的问题。因为DO S 系统是在PC 机中应用最广泛的操作系统, 经过广大用户长年的应用和面向实际的软件开发, 其接口特性和编程方法被广大软件开发者所熟悉和掌握。然而, 开发基于DO S 系统的实方式应用程序存在一定的局限性, 主要是不能有效地利用高档微机的内存资源, 如扩展内存的访问。尤其在开发实时性很强的大数据量的应用程序中, 高效使用扩展内存是极为重要的。
目前常用的访问扩展内存方法有: (1) 采用“IN T15H”或HTM EM 1SYS 的功能调用; (2) 采用虚拟磁盘。前者只能实现数据块在常规内存与扩展内存之间移动, 这样, 不但还要占用一定的常规内存空间, 而且数据块的移动还需占用程序运行时间, 使程序的运行效率降低。后者可以以文件的形式将数据存储在扩展内存中, 采用文件的访问方式进行数据操作。显然, 这2 种方法只能间接访问扩展内存, 不能直接访问扩展内存, 而且数据的操作效率低, 难以满足实时性要求。

本文将从80486CPU (以下简称CPU ) 的寻址机制研究入手, 讨论在实方式下直接访问4GB 内存的方法和C 程序设计方法。

1 基本原理
1.1 物理地址形成的统一性
无论CPU 在实方式下或保护方式下, 其物理地址的形成都将使用段描述符高速缓冲寄存器。其差别是:在实方式下, 每当向段寄存器赋予新的内容(段地址) 时, 段描述符高速缓冲寄存器的基地址值相应发生改变, 其值为16×SEG, 这是线性基地址; CPU 最终形成的物理地址为某地址值加偏移量。段描述符高速缓冲寄存器的界限值和属性值始终不变。当CPU 复位后, CPU 的工作模式为实方式, 段描述符高速缓冲寄存器的界限值自动设置为FFFFH。因此, CPU 能够访问内存的空间为0~ 10FFEFH ( FFFFH × 16 +FFFFH =1114095) , 每个段的大小为64KB。在保护方式下, 每当向段寄存器赋予新的内容SEL (选择字) 时, 段描述符高速缓冲寄存器的内容将由SEL 对应的段描述符更新; 段描述符高速缓冲寄存器的基地址值、界限值和属性值依据段描述符的设置而发生改变。段的基地址可设置在4GB 内存的任意地址处, 段的最大界限值可达FFFFFFFFH (4GB - 1)。
在不分页的情况下, CPU 最终形成的物理地址同样是基地址值加偏移量。所以, CPU 能够整个访问4GB 内存。

显然, 对于CPU 在形成物理地址时, 在实方式下与在0 特权级不分页的保护方式下是相同的。只是段的基地址和段的大小设置范围不同。工作方式确定是由控制寄存器CR0 的最低位PE 位决定的, 若PE 为0, 则工作在实方式; 若PE 为1, 则工作在保护方式。在通过PE 位的改变时, 就进行了工作方式切换。这种切换只影响段描述符高速缓冲寄存器的基地址值运算方式, 不影响段描述符高速缓冲寄存器的段界限值。

1.2 直接访问4GB 内存
当CPU 复位后, CPU 处于实方式下, 尽管在实方式下可执行诸如“MOV AX,〔ES I〕”指令的32 位寄存器间接寻址操作, 但是ES I 的内容必须在0~ FFFFH范围内, 否则, 将引起13 号异常中断。基于CPU 物理地址形成的统一性, 在实方式下直接访问4GB 内存的关键是扩大段描述符高速缓冲寄存器的界限值。使诸如“MOV AX,〔ES I〕”指令的32位寄存器间接寻址操作实现4GB 内存的访问。然而,CPU 在实方式下并没有提供改变段描述符高速缓冲寄存器的界限值的操作指令。改变段描述符高速缓冲寄存器的内容只能在保护方式下进行, 即向段寄存器赋予段的选择字SEL , 段描述符高速缓冲寄存器的内容将由SEL 对应的段描述符更新。当CPU 从保护方式切换到实方式时, 段描述符高速缓冲寄存器的内容不发生变化。
因此, 在DO S 实方式下直接访问4GB 内存之前,让CPU 进入保护方式下, 通过装载具有4GB 界限的段描述符到段描述符高速缓冲寄存器中去, 然后返回到实方式下, CPU 就可以通过32 位寄存器间接寻址 操作实现4GB 内存的访问。
2 C 程序设计
2.1 编程环境
本文采用Bo rland C+ + 3. 1 程序设计环境, 在程序中使用内嵌汇编方法实现特定的操作, 在O P t ions的“Comp ile”- “A dvanced Code generat ion”中选择386 指令集。由于集成开发环境下的内部编译器不能识别内嵌的386 汇编指令, 对于32 位寄存器和32 位地址操作汇编指令, 可以采用直接在代码前加入操作数前缀0x66 或地址前缀0x67, 以便实现32 位寄存器地址的操作。最好的方法是让集成开发环境调用TA SM 1EXE 进行编译, 即设置O P t ions 中的“Comp ile”- “Code generat ion ”- “ Comp ile via as2sem ler”为ON。这样便可完整地运用386 汇编指令。在以下编程示例中采用了这种编译方法。

本程序是采用基于实方式下的编程方法。它不能在保护方式下和虚拟8086 方式下运行, 不能装载扩充内存EM S 驱动程序(如EMM 3861EXE) , 因为, 它使DO S 系统处于虚拟8086 方式下。

2.2 打开A 20 地址线
CPU 的A 20 地址线受到键盘接口处理器8042 的输出口P21 控制, 如果DO S 系统启动后, 没有装载XM S 驱动程序(如h imem. sys) , 此时A 20 被关闭, 要访问4GB 内存, 必须打开A 20, 是A 20 受到CPU 的控制。
vo id openA 20 ()
{  wh ile ( inp (0x64) & 2) ;   outp (0x64, 0xd1) ;
wh ile ( inp (0x64) & 2) ;   outp (0x60, 0xdf) ;
wh ile ( inp (0x64) & 2) ;   outp (0x64, 0xff) ;

}

2.3 设置数据段的4GB 界限函数
首先, 建立1 个全局描述符表GDT, 即GDT- def,它含有2 个描述符, 第1 个为空描述符(保护方式下系统要求的) , 第2 个是具有4GB 段界限的数据段描述符, 它的选择字为8。再计算出GDT 的基地址和长度存入GDT- A ddr 中。然后, 装载GDT, 进入保护方式,把选择字8 赋给DS 和ES, 此时第2 个是具有4GB 段界限的数据段描述符被装载到DS 和ES 的描述符高速缓冲寄存器中, 最后返回实方式。同理, 也可设置FS和GS 的4GB 界限。
unsigned long GDT2def [ ]= {0, 0, 0x0000FFFF, 0x008F9200};  //全局描述符表GDT
unsigned char GDT- A ddr[ 6 ]= {0};  //存放GDT 的基地址和长度
vo id set4gb ()
{ asm{
 cli
 push ds ;  push es
 mov wo rd p tr GDT- A ddr[ 0 ], (23 8- 1)  //GDT 的长度存入GDT- A ddr 中
 mov eax, ds //计算GDT 描述符表的线性基地址31~ 0
 sh l eax, 4 //段地址eax= ds x 16
 xo r ebx, ebx //ebx 清零
 mov bx, offset GDT- def //b x= GDT 的偏移地址
 add eax, ebx //GDT 的线性基地址= eax+ ebx
 mov dwo rd p tr GDT- A ddr [ 2 ]eax //GDT 的线性基地址存入GDT- A ddr 中
 lgdt fwo rd p tr GDT- A ddr
 mov bx, 8 /设置数据段描述的选择字
 mov eax, cr0
 o r al, 1
 mov cr0, eax
 jmp flush l
 }      //进入保护方式
flush l: asm{
 mov ds, bx //D S 装载具有4GB 界限的数据段描述符
 mov es, bx //ES 装载具有4GB 界限的数据段描述符
 and al, 0feh
 mov cr0, eax
 jmp flush2
 }      //返回实方式
flush2:  asm{
 pop es ; pop ds
 sti
 }

}

2.4 直接访问4GB 内存的基本函数
在DS 和ES 具有4GB 的访问界限后, 通过32 位寄存器间接寻址的指令就可实现4GB 内存的访问。以下仅给出字节的读写函数, 其中, addr 为RAM 的32位线性地址。
1. 读字节函数, 函数的返回值为读出的字节。
unsigned char read- ram (unsigned long addr)
{  asm push ds
asm mov ax, 0
asm mov ds, ax
asm mov esi, addr
asm mov al, [ esi]
asm pop ds
return- AL;
}
2. 写字节函数, ch r 为要写入的字节。
vo id w rite- ram (unsigned long addr, unsigned char ch r)
{  asm push ds
asm mov ax, 0
asm mov ds, ax
asm mov esi, addr
asm mov al, ch r
asm mov [ esi], al
asm pop ds

}

2.5 程序示例
本示例将使用上面所设计的功能函数, 由内嵌汇编程序完成对主机内存的测试和容量的检测任务。在PC386/33、PC486/100 上通过。
# include < do s. h>
# include < stdio. h>
vo id main ()
 {unsigned long addr;
openA 20 () ;
set4gb () ;
asm push ds
asm mov ax, 0
asm mov ds, ax
asm mov esi, 00100000h  //从1M b 开始测试
 N 1: asm mov eax, [ esi]  //暂存esi 地址指定双字单元的内容
asm mov dwo rd p tr [ esi], 0  //向esi 地址指定双字单元写零
asm mov ebx, [ esi]  //读出由esi 地址指定的双字单元的内容给ebx
asm mov dwo rd p tr [ esi], 0ffffffffh//向esi 地址指定双字单元写全1
asm mov ecx, [esi]  //读出由esi 地址指定的双字单元的内容给ecx
asm mov [ esi], eax  //恢复esi 地址指定双字单元的内容
asm inc ecx  //若ecx 的内容为全1, ecx 增1后, ecx= 0
asm cmp ebx, ecx  //比较2次读出的内容
   asm jne N 2  //不相等, 则退出循环检测
   asm add esi, 4  //e si 地址增4
   asm jmp N 1  //继续循环检测
N 2:  asm mov addr, esi
asm pop ds
p rintf ("RAM = % 1d (M b) " , addr > > 20) ;
}

3 与XM S 驱动程序的兼容方法

3.1 基本原理
如果没有装载XM S 驱动程序H imem. sys, 采用上述方法可无限制地使用整个扩展内存。若系统中的某些系统程序和其它应用程序需要使用H imem. sys,通过它分配和访问扩展内存。这样, 扩展内存的部分空间被占据, 用户应用程序所使用的扩展内存空间将受到限制, 否则, 发生冲突。

因此, 在这种情况下, 用户应用程序可通过H imem. sys 的功能调用, 为其分配未使用的扩展内存存储块EMB, 并通过锁定EMB, 得到EMB 的32位线性基址, 便可采用上述方法对存储块进行直接访问。

3.2 H imem. sys 的接口
1.取得安装状态
只有当H imem. sys 已被加载, 才能调用它的功能。当AX= 4300H 时, 执行“IN T2FH”软中断指令后,若AL = 80H, 则已加载; 若AL = 00H, 则未加载。
2.取得入口地址
H imem. sys 的各项功能调用是通过功能调用的入口地址进行的, 当AX= 4310H 时, 执行“IN T2FH”软中断指令后, ES= 入口的段地址,BX= 入口的偏移地址。
3.功能调用
H imem. sys 为用户提供许多XM S 的内存管理功能, 与本文相关的功能和接口如表1所示。

4 结束语
DO S 实方式下直接访问4GB 内存具有一定的特殊性和重要的实际意义。本文提出的方法在图像实时识别系统中得到了成功的应用。该系统需同时采集4幅图像, 每幅图像为512×512的256色点阵, 4幅图像共需1MB 内存空间, 在对图像进行处理时还需要2幅图像的工作缓冲区。显然, 在常规内存中难以进行存储和处理。若采用虚拟磁盘或XM S 驱动程序H imem. sys, 由于图像的数据量大、运算时间长, 影响了实时性要求。
通过采用本文提出的方法, 运用C 程序的内嵌汇编直接对扩展内存进行图像的存储和处理, 发挥了计算机(下转第28页)

DOS 实方式下直接访问4GB 内存相关推荐

  1. k8s Nodeport方式下service访问,iptables处理逻辑(转)

    原文 https://www.myf5.net/post/2330.htm k8s Nodeport方式下service访问,iptables处理逻辑 2017年07月11日 0条评论 976次阅读 ...

  2. DOS下如何访问4G内存

    转载 首先解释几个基本概念: 1.保护模式和实模式 自从1969年推出第一个微处理器以来,Intel处理器就在不断地更新换代,从8086.8088.80286,到80386.80486.奔腾.奔腾Ⅱ. ...

  3. DOS下读取4GB内存

    好文章我收集下起来 CPU上电后,从ROM 中的BIOS开始运行. BIOS是处在内存的最顶端64KB(FFFF0000H),还是1MB之下的64KB(F0000H)处呢?事实上,BIOS在这两个地方 ...

  4. DOS下读取4GB内存——梁肇新代码分析

    程序原理: CPU上电后,从ROM 中的BIOS开始运行. BIOS是处在内存的最顶端64KB(FFFF0000H),还是1MB之下的64KB(F0000H)处呢?事实上,BIOS在这两个地方都同时出 ...

  5. DOS环境下支持的最大内存是多少?

    DOS 6.22 can address 640 KB (not MBytes!) of conventional memory and use upto 64 MB of extended memo ...

  6. Linux如何访问mmio空间,一文读懂Linux下如何访问I/O端口和I/O内存

    虽然访问I/O端口非常简单,但是检测哪些I/O端口已经分配给I/O设备可能就不这么简单了,对基于ISA总线的系统来说更是如此.通常,I/O设备驱动程序为了探测硬件设备,需要盲目地向某一I/O端口写入数 ...

  7. Excel在.Net 环境下Web方式下驻留内存问题的解决

    这段时间在VS 2003 的WebForm 方式下对Excel 进行操作,遇到一个最为头疼的问题就是对Excel操作完毕后Excel不能够正常关闭,系统退出后,Excel总是驻留在内存中.但是这段代码 ...

  8. linux中非法内存,Linux下数组非法访问导致内存破坏 —— 引发segmentation fault的原因...

    2012-02-05 wcdj 1, 调试时必需的栈知识 2, 数组非法访问导致内存破坏 调试时必需的栈知识 栈(stack)是程序存放数据的内存区域之一,其特征是LIFO(Last In First ...

  9. EJB3.0学习笔记---Bean实现多个接口的情况下定义,访问方式:

    2.EJB实现类型的定义,用注解的方式,当一个EJBbean,实现了多个接口的时候, 需要用注解的方式指明哪一个接口是用Remote方式访问,哪一个接口使用 local方式访问 3.实现多个接口的情况 ...

最新文章

  1. 想为企业杜绝钓鱼邮件,ValiMail 获1200万美元A轮融资
  2. ID3 Algorithm for Decision Trees
  3. python 基础学习 正则表达式1(规则)
  4. HDU 5459 Jesus Is Here (递推,组合数学)
  5. centos打显卡驱动命令_在Linux系统下安装Nvidia官方显卡驱动的方法
  6. 2015年07月04日
  7. tomcat与apache区别
  8. 高鸿股份与鸿蒙,高鸿股份(000851)个股分析_牛叉诊股_同花顺财经
  9. java 获取当前月份减1_java String 日期 转成 Date, 月份减1
  10. java next_permutation_[LeetCode-JAVA] Next Permutation
  11. java代码审计文件包含_代码审计--一道简单的文件包含题目的多种利用方式
  12. 使用Mybatis实例
  13. Windows 使用 Detours 进行 HOOK
  14. ssm酒店预订系统ssm酒店管理系统民宿预订ssm酒店客房预订系统SSM客房预订系统
  15. MTK OTG 功能总结(UVC)
  16. 黑苹果系统升级OC引导升级简单
  17. 电路基础(3)电阻电路等效变换的经典例题
  18. 基于(springmvc+tomcat+JavaScript)的化妆品商城系统
  19. 图书 SCM供应链管理—策略、技术与实务 目录
  20. linux下c语言按q退出_Linux入门所必备的Linux命令和C语言基础

热门文章

  1. 机器学习中的准确率,精确率,召回率以及F1值
  2. 给自己做个地图故事 —— Trip to Greece
  3. 如何手动导出安卓手机中的微信QQ等应用数据
  4. 虚拟网卡是什么?教教大家添加虚拟网卡的方法
  5. 一文理解Ranking Loss/Contrastive Loss/Margin Loss/Triplet Loss/Hinge Loss
  6. 转:给在读研究生的一封信
  7. Linux基础学习之Day7-6-Mount 挂载详解
  8. [Bzoj1034][ZJOJ2008]泡泡堂BNB(贪心)
  9. gz文件Header 解析
  10. 自学一年Java程序员,能找到月入10K的工作吗?