Windows 95/98下直接访问物理内存

原创 2001年09月09日 23:16:00
Windows 95/98下直接访问物理内存   在很多情况下,我们都有直接访问物理内存的要求,如在实时高速数据采集系统中, 对I/O板上配置的存储器的访问。但是,为了保证系统的安全性和稳定性,操作系统 并不提倡应用程序直接访问硬件资源, 因此,随着操作系统的进步,导致了目前存在 的这样一个不幸的事实: 以前在DOS下很容易实现的特定物理内存的读写操作,在Windows 下却变得相当困难。 本文主要讨论如何在Windows 95/98下实现物理内存的直接读写操作。为了论述清 楚这个问题,有必要叙述保护模式的寻址方式以及W indows 95/98的内存管理方式。 Windows 95/98内存管理方式 Windows 95/98工作在32位保护模式下,保护模式与实模式的根本区别在于CPU寻址方 式上的不同:尽管两者对应的内存地址均为"段地址:偏移量"形式,但在保护模式下, "段地址"代表的值已不再是实模式中段的起始基准地址了;对于CS、DS、ES、SS寄存 器,在实模式下,这些寄存器的值左移4位,再加上偏移量,即得到物理地址,而在保护 模式下,这些寄存器的值为"段选择符",它实际上是一个查全局描述符表(G DT)或局 部描述符表(LDT)的索引,据此在GDT或LDT找到对应的段描述符,从而获得段的基址及 类型等信息,再根据偏移量,才能得到线性地址。如果操作系统没有采用分页机制, 那么得到的线性地址即为物理地址,否则,线性地址需要进一步经过分页机制才能得 到物理地址。这就是保护模式下的"段页式寻址机制"。 Windows 95/98使用4GB的虚拟内存地址空间,应用程序访问内存使用虚拟地址,从虚 拟地址到物理地址的转换过程如图1所示: 图1 虚拟地址到物理地址的转化过程 对于图1中的分页机制,Windows 95/98采用两级页表结构,如图2 所示。图2 采用的 分页机制的两级页表结构 从图2可知,线性地址被分割成页目录条目(PDE)、页表条目(PTE) 、页偏移地址(Off set) 三个部分。当建立一个新的WIN 32进程时,Wi ndows 95/98会为它分配一块内存,并 建立它自己的页目录、页表,页目录的地址也同时放入进程的现场信息中。当计算一 个地址时,系统首先从控制寄存器CR3中读出页目录所在的地址(该地址为物理地址, 并且是页对齐的),然后根据PDE得到页表所在的地址,再根据PTE得到包含了实际Code 或Data的页帧, 最后根据Offset访问页帧中的特定单元。 常用内存段的段选择符 从上述所介绍的Windows 95/98采用的分段、分页机制可看出,要想在Windows 95/98 下直接访问物理内存,关键是得到欲访问物理内存所在的内存区域对应的段选择符。 一般说来,要求直接访问的物理内存都与实模式下能够寻址的内存有关(即DOS能直 接访问的1M物理内存)。在Windows 3.X中,Microso ft给出了DOS常用段的段选择符, 如_000 0H(未公开),_B800H,_F000H( 已公开),等等,均可以在KERNEL中找到,应用 程序可以直接使用这些段选择符,实现物理内存的直接访问。而在Windows 95/98中, Microsoft 却不在任何文档中提供这些段的预定义,在KERNEL中也不提供相应的段选 择符。但是,Windows 95 /98确实给DOS下的这些常用内存段定义了相应的段描述符。 通过SoftIce 3.02 for Win dows 95/98,我们得到了关于LDT的如下信息: ...... :ldt LDTbase=80003000 Limit=3FFF …… 1007 Data16 00000C90 0000FFFF 3 P RW 100F Data16 00000000 0000FFFF 3 P RW 1017 Data16 00000400 0000FFFF 3 P RW 101F Data16 000F0000 0000FFFF 3 P RW 1027 Data16 000A0000 0000FFFF 3 P RW 102F Data16 000B0000 0000FFFF 3 P RW 1037 Data16 000B8000 0000FFFF 3 P RW 103F Data16 000C0000 0000FFFF 3 P RW 1047 Data16 000D0000 0000FFFF 3 P RW 104F Data16 000E0000 0000FFFF 3 P RW …… 其中,每一行对应一个段描述符,第一栏为其段选择符,第二栏为段描述符的类型, 第三栏为段的基地址(线性地址),第四栏为段的限长 ,第五栏为段描述符的特权级, 第六栏标志对应段是否存在于内存中, 第七栏表示段的访问权限。 可以看出,这些段的基地址与DOS下的常用内存段完全吻合,并且均为16位的数据段, 限长为64K(0XFFFF),供应用程序访问,都存在于内存中,可读写。实践证明,这些段 就是D OS的常用内存段,也就是说, 这里的线性地址即为物理地址。因此,可以用这 些段选择符对相应的物理内存进行访问。 从程序运行的健壮性考虑,不应该直接应用上述段选择符,而应该用GetThreadSelec torEntry()函数得到欲访问物理内存对应的段选择符,该API函数的原型定义为 BOOL GetThreadSelectorEntry ( HANDLE hThread, // handle of thread that contains selector DWORD dwSelector, // number of selector value to look up LPLDT_ENTRY lpSelectorEntry // address of selector entry structure ); 其中,LDT_ENTRY的结构定义如下 typedef struct _LDT_ENTRY { // ldte WORD LimitLow; WORD BaseLow; union { struct { BYTE BaseMid; BYTE Flags1; BYTE Flags2; BYTE BaseHi; } Bytes; struct { DWORD BaseMid : 8; DWORD Type : 5; DWORD Dpl : 2; DWORD Pres : 1; DWORD LimitHi : 4; DWORD Sys : 1; DWORD Reserved_0 : 1; DWORD Default_Big : 1; DWORD Granularity : 1; DWORD BaseHi : 8; } Bits; } HighWord; } LDT_ENTRY, *PLDT_ENTRY; 用下面的代码可以得到基地址为BASE_DESIRED,限长为0XFFFF的 内存段对应的段选择符: ...... extern CLDTApp theApp; WORD wSelector; // 内存段对应的段选择符 LDT_ENTRY ldtEntry; DWORD base, baseMid, baseHigh; DWORD limit, limitHigh; for ( WORD sel = 7; sel <= 0xffff; sel +=8 ) { if (::GetThreadSelectorEntry ( theApp.m_hThread, DWORD ( sel ), &ldtEntry ) ) { baseMid = ldtEntry . HighWord . Bytes . BaseMid; baseMid <<= 16; baseHigh = ldtEntry . HighWord . Bytes . BaseHi; baseHigh <<= 24; base = ldtEntry . BaseLow + baseMid + baseHigh; limitHigh = m_ldtEntry . HighWord . Bits . LimitHi; limitHigh <<= 24; limit = limitHigh + m_ldtEntry . LimitLow; if ( 0xFFFF == limit ) if ( BASE_DESIRED == base ) { // BASE_DESIRED为内存段对应的基地址 wSelector = sel; break; }}} 直接访问物理内存的实现 得到了段选择符之后,即可把该段选择符置于相应的段寄存器中( 不能用CS,DS), 用该寄存器进行数据访问。需注意的是,任何非法段选择符写入段寄存器将会导 致通用保护错误(General Protection Faul t)。 下面的代码实现物理内存的读/写操作(段选择符用上述方法得到): void WriteMemory(WORD sel, DWORD dwOffset, const char * str, UINT length) { char cWrite; for ( UINT i = 0; i < length; i ++ ) { cWrite = str [i]; _asm {     push es     mov ax, sel     mov es, ax     mov ebx, dwOffset     mov al, cWrite     mov byte ptr es:[ebx], al     inc dwOffset     pop es } } } void ReadMemory ( WORD sel, DWORD dwOffset,char * str, UINT length ) { char cRead; for ( UINT i = 0; i < length; i ++ ) { _asm {     push es     mov ax, sel     mov es, ax     mov ebx, dwOffset     mov al, byte ptres:[ebx]     mov cRead, al     inc dwOffset     pop es }   str [i] = cRead; } } 本文所用操作系统为中文Windows 95 OSR 2.0以及中文Windows 98,编程环境为Vis ual C++ 5.0。

[Windows驱动开发](四)内存管理

一、内存管理概念 1. 物理内存概念(Physical Memory Address)     PC上有三条总线,分别是数据总线、地址总线和控制总线。32位CPU的寻址能力为4GB(2的32次方)...
  • baggiowangyu
  • baggiowangyu
  • 2012年09月03日 09:48
  • 11631

windows 物理内存获取

由于我一般使用的虚拟内存, 有时我们需要获取到物理内存中的数据(也就是内存条中的真实数据), 按理说是很简单,打开物理内存,读取就可以了.但似乎没这么简单: #include "window...
  • wangxvfeng101
  • wangxvfeng101
  • 2012年03月26日 13:31
  • 6485

Windows 95/98下直接访问物理内存

Windows 95/98下直接访问物理内存  在很多情况下,我们都有直接访问物理内存的要求,如在实时高速数据采集系统中,对I/O板上配置的存储器的访问。但是,为了保证系统的安全性和稳定性,操作系统并...
  • firetoucher
  • firetoucher
  • 2001年09月09日 23:16
  • 1460

Windows内核编程基础之内存的分配与释放

内存泄漏是C语言中一个臭名昭著的问题。但是作为内核开发者,读者将有必要自己来面对它。在传统的C语言中,分配内存常常使用的函数是:malloc,这个函数的使用非常简单,传入长度参数就得到内存空间。在驱动...
  • HK_5788
  • HK_5788
  • 2015年08月26日 15:05
  • 1083

Wince直接访问物理内存

嵌入式设备与桌面PC的一个显著不同是它的应用程序中通常需要直接访问某一段物理内存,这在驱动程序中对物理内存的访问尤为重要,尤其是像ARM体系结构下,I/O端口也被映射成某一个物理内存地址。因此,与桌面...
  • yeguanping11
  • yeguanping11
  • 2013年02月28日 11:49
  • 378

Windows 核心编程研究系列之二:读取指定物理内存地址中的内容

[原创/讨论] Windows 核心编程研究系列之二: 读取指定物理内存地址中的内容 关键字:windows内核,物理内存   大家知道在windows NT中,如果已...
  • mydo
  • mydo
  • 2006年12月19日 21:45
  • 6493

在NT中直接访问物理内存

原文地址:http://blog.csdn.net/bhw98/archive/2004/04/28/19683.aspx   我们知道,在NT/2K/XP中,操作系统利用虚拟内存管理技术来维...
  • VHeroin
  • VHeroin
  • 2017年06月17日 10:25
  • 269

一种User Mode下访问物理内存及Kernel Space的简单实现

一.背景       WinCE发展到6.0之后,内存结构和管理方法进行了完善。对应用程序影响比较大的有Virtual Memory Layout的变化,如每个进程的虚拟内存空间扩展为2GB。对驱动程...
  • alien75
  • alien75
  • 2010年01月18日 11:13
  • 1687

Linux读写物理内存的实践环节

一、基础知识 1.打开设备文件: mem是一个字符设备文件,是计算机主存的一个映像。通常只有root用户对其有读写权限。因此只有root用户能进行这些操作。 如果要打开设备文件/de...
  • liuer2004_82
  • liuer2004_82
  • 2016年02月19日 08:59
  • 1115

常用的连续物理内存的获取方法(一)

获得连续物理内存的方法有很多,在很多地方搜了但是自己拿过来用就是用不了,这里展示几个亲测能用的。包括dma_alloc_coherent和kmalloc等。 代码: #include #incl...
  • u014792216
  • u014792216
  • 2018年01月12日 16:05
  • 43
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Windows 95/98下直接访问物理内存
举报原因:
原因补充:

(最多只允许输入30个字)