龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 软件开发 > C/C++开发 >

罗云彬VxD教程--虚拟8086模式的内存管理

时间:2009-12-22 15:42来源:未知 作者:admin 点击:
分享到:
下边我们用到的V86即指虚拟8086模式。 在以前的教程中,你学习了怎样模拟V86中断,但还有一个问题没有解决:在VxD和V86代码之间交换数据。我们将在此学习如何使用V86内存治理器来实

  下边我们用到的V86即指虚拟8086模式。 在以前的教程中,你学习了怎样模拟V86中断,但还有一个问题没有解决:在VxD和V86代码之间交换数据。我们将在此学习如何使用V86内存治理器来实现这个功能。在这里下载例子程序

  

  

理论

  

  

假如你的VxD和一些V86程序一起运行,如何传送大量数据到V86程序中或从V86程序中传送大量数据迟早是一个大问题。通过寄存器传送大量数据是不现实的。可能你的下一个想法是在ring0中分配一大块内存,并且通过一些寄存器传送其指针到V86程序,使其能访问这些数据。假如你这样做,可能会破坏你的系统,因为V86的地址定位方式需要segment:offset对,而不是线性定位方式。对这个问题,有很多解决的方法。然而,我选择了一个由V86内存治理器提供的一种简便的方法。

  

  

如你能在你可使用的V86内存范围内找到一个空闲的内存块作为通讯缓冲区,这将解决其中的一个问题。然而,指针传送的问题依然存在。你可以通过V86内存治理器的服务来解决这两个问题。V86内存治理器是为V86应用治理内存的静态VxD。它还为V86应用提供EMS和XMS服务和为其他VxD提供API传送服务。API传送是一个从ring0拷贝数据到V86范围内的缓冲区并且传送V86缓冲区地址到V86代码的过程。V86内存治理器有一个在V86内存范围内的传送缓冲区,其含有VxD拷贝到V86内存范围内的数据,反之亦然。初始的缓冲区是4K。你以调用V86MMGR_Set_Mapping_Info来增加它的大小。

  

  

现在你知道了传送缓冲区,我们如何拷入或拷出数据呢?这个问题通过调用两个服务来解决:V86MMGR_Allocate_Buffer和V86MMGR_Free_Buffer。

  

  

V86MMGR_Allocate_Buffer从传送缓冲区分配一块内存并且从ring0拷贝一些数据到分配的V86缓冲区。V86MMGR_Free_Buffer正好相反:它从分配的V86内存块拷贝一些数据到ring0缓冲区并且释放由V86MMGR_Allocate_Buffer分配的内存块。

  

  

记住,V86在内存治理器象堆栈一样治理被分配的缓冲区。这意味着分配/释放必须按先进后出的规则。所以如你调用了两次V86MMGR_Allocate_Buffer,第一个V86MMGR_Free_Buffer将释放由第二个V86MMGR_Allocate_Buffer调用而分配的缓冲区。

  

  

我们来看一下V86MMGR_Allocate_Buffer的定义,它是一个基本寄存器传送参数的服务。

  

  

EBX 当前VM的句柄

  

EBP 指向当前VM的客户寄存器结构的指针

  

ECX 从传送缓冲区分配的字节数 CARRY FLAG 进位标志位,如你不想从ring0缓冲区拷贝数据到分配的内存块就清零, 如你想从ring0缓冲区拷贝数据到分配的内存块就置1

  

FS:ESI 指向ring0缓冲区的selector:offset指针,缓冲区中有要被拷贝到被分配的 缓冲区中的数据假如进位标志位被清零,则忽略它。

  

假如调用成功,进位标志位被清零并且ECX包含在传送缓冲区中的字节数。这个数值应小于你要求的数值,所以你应保持这个数值,V86MMGR_Free_Buffer待会要用到它。EDI的高字包含被分配的内存块的V86段地址,偏移地址在在低字中。进位标志位当错误发生时被置位。

  

  

V86MMGR_Free_Buffer和V86MMGR_Allocate_Buffer接受同样的参数。

  

  

当你调用V86MMGR_Allocate_Buffer时,你在当前VM的V86内存范围内分配了一块内存,并且把其地址放到了EDI中。你可以使用这些服务传送数据到V86中断中或从V86中断中取得数据。

  

  

在附加的API传送中,V86内存治理器也给其他VxDs提供了API映射服务。API映射服务是映射一些在扩展内存中的页到每个VM的V86内存范围。你可以使用V86MMGR_Map_Pages执行API映射。使用这个服务,页被映射到每个VM的同一线性地址空间上。如你仅仅工作在一个VM上,这将浪费地址空间。因为API映射比API传送要慢,所以你尽可能使用API传送方式。API映射仅仅使用在一些要访问同一线性地址空间并作用到所有VM的V86操作上。

  

  

例子:

  

  

这个例子演示了API传送方式,使用了int 21h的440Dh功能(从代码66h)。这个中断调用得到媒体ID,你的第一个固定磁盘的卷标号。

  

  

;---------------------------------------------------------------

  

; VxDLabel.asm

  

;---------------------------------------------------------------

  

.386p

  

include masmincludevmm.inc

  

include masmincludevwin32.inc

  

include masmincludev86mmgr.inc

  

VxDName TEXTEQU

  

ControlName TEXTEQU

  

VxDMajorVersion TEXTEQU <1>

  

VxDMinorVersion TEXTEQU <0>

  

  

VxD_STATIC_DATA_SEG

  

VxD_STATIC_DATA_ENDS

  

  

VXD_LOCKED_CODE_SEG

  

  

;----------------------------------------------------------------------------

  

; Remember: The name of the vxd MUST be uppercase else it won't work/unload

  

;----------------------------------------------------------------------------

  

DECLARE_VIRTUAL_DEVICE %VxDName,%VxDMajorVersion,%VxDMinorVersion, %ControlName,UNDEFINED_DEVICE_ID,UNDEFINED_IN99v_ORDER

  

  

Begin_control_dispatch %VxDName

  

Control_Dispatch W32_DEVICEIOCONTROL, OnDeviceIoControl

  

End_control_dispatch %VxDName

  

  

VXD_LOCKED_CODE_ENDS

  

  

VXD_PAGEABLE_CODE_SEG

  

BeginProc OnDeviceIoControl

  

assume esi:ptr DIOCParams

  

.if [esi].dwIoControlCode==1

  

VMMCall Get_Sys_VM_Handle

  

mov Handle,ebx

  

assume ebx:ptr cb_s

  

mov ebp,[ebx+CB_Client_Pointer]

  

mov ecx,sizeof MID

  

stc

  

push esi

  

mov esi,OFFSET32 MediaID

  

push ds

  

pop fs

  

VxDCall V86MMGR_Allocate_Buffer

  

pop esi

  

jc EndI

  

mov AllocSize,ecx

  

Push_Client_State

  

VMMCall Begin_Nest_V86_Exec

  

assume ebp:ptr Client_Byte_Reg_StrUC

  

mov [ebp].Client_ch,8

  

mov [ebp].Client_cl,66h

  

assume ebp:ptr Client_Word_reg_struc

  

mov edx,edi

  

mov [ebp].Client_bx,3 ; drive A

  

mov [ebp].Client_ax,440dh

  

mov [ebp].Client_dx,dx

  

shr edx,16

  

mov [ebp].Client_ds,dx

  

mov eax,21h

  

VMMCall Exec_Int

  

VMMCall End_Nest_Exec

  

Pop_Client_State

  

;-------------------------------

  

; retrieve the data

  

;-------------------------------

  

mov ecx,AllocSize

  

stc

  

mov ebx,Handle

  

push esi

  

mov esi,OFFSET32 MediaID

  

push ds

  

pop fs

  

VxDCall V86MMGR_Free_Buffer

  

pop esi

  

mov edx,esi

  

assume edx:ptr DIOCParams

  

mov edi,[edx].lpvOutBuffer

  

mov esi,OFFSET32 MediaID.midVolLabel

  

mov ecx,11

  

rep movsb

  

mov byte ptr [edi],0

  

  

mov ecx,[edx].lpcbBytesReturned

  

mov dword ptr [edx],11

  

EndI:

  

.endif

  

xor eax,eax

  

ret

  

EndProc OnDeviceIoControl

  

VXD_PAGEABLE_CODE_ENDS

  

  

VXD_PAGEABLE_DATA_SEG

  

MID struct

  

midInfoLevel dw 0

  

midSerialNum dd ?

  

midVolLabel db 11 dup(?)

  

midFileSysType db 8 dup(?)

  

MID ends

  

MediaID MID <>

  

Handle dd ?

  

AllocSize dd ?

  

VXD_PAGEABLE_DATA_ENDS

  

  

end

  

  

;------------------------------------------------------------

  

; Label.asm

  

; The win32 VxD loader.

  

;------------------------------------------------------------

  

.386

  

.model flat,stdcall

  

option casemap:none

  

  

include masm32includewindows.inc

  

include masm32includeuser32.inc

  

include masm32includekernel32.inc

  

includelib masm32libuser32.lib

  

includelib masm32libkernel32.lib

  

精彩图集

赞助商链接