iczelion Vxd cntut9

限时加码!20+主流AI编程工具免费用 购周边加赠Coding Plan Lite,Claude Code、Cursor等即刻畅享,学习进阶更高效! 阅读详情

 

虚拟8086模式的内存管理


下边我们用到的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 /masm/include/vmm.inc 
include /masm/include/vwin32.inc 
include /masm/include/v86mmgr.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_INIT_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 /masm32/include/windows.inc 
include /masm32/include/user32.inc 
include /masm32/include/kernel32.inc 
includelib /masm32/lib/user32.lib 
includelib /masm32/lib/kernel32.lib 

DlgProc PROTO :DWORD,:DWORD,:DWORD,:DWORD 
.data 
Failure db "Cannot load VxDLabel.VXD",0 
AppName db "Get Disk Label",0 
VxDName db "//./vxdLabel.vxd",0 
OutputTemplate db "Volume Label of Drive C",0 

.data? 
hInstance HINSTANCE ? 
hVxD dd ? 
DiskLabel db 12 dup(?) 
BytesReturned dd ? 

.const 
IDD_VXDRUN    equ 101 
IDC_LOAD      equ 1000 

.code 
start: 
 invoke GetModuleHandle, NULL 
 mov    hInstance,eax 
 invoke DialogBoxParam, hInstance, IDD_VXDRUN ,NULL,addr DlgProc,NULL 
 invoke ExitProcess,eax 

DlgProc proc hDlg:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM 
 .IF uMsg==WM_INITDIALOG 
  invoke CreateFile,addr VxDName,0,0,0,0,FILE_FLAG_DELETE_ON_CLOSE,0 
  .if eax==INVALID_HANDLE_VALUE 
   invoke MessageBox,hDlg,addr Failure,addr AppName,MB_OK+MB_ICONERROR 
   mov hVxD,0 
   invoke EndDialog,hDlg,NULL 
  .else 
   mov hVxD,eax 
  .endif 
 .elseif uMsg==WM_CLOSE 
  .if hVxD!=0 
   invoke CloseHandle,hVxD 
  .endif 
  invoke EndDialog,hDlg,0 
 .ELSEIF uMsg==WM_COMMAND 
  mov eax,wParam 
  mov edx,wParam 
  shr edx,16 
  .if dx==BN_CLICKED 
   .IF ax==IDC_LOAD 
     invoke DeviceIoControl,hVxD,1,NULL,0,addr DiskLabel,12,addr BytesReturned,NULL 
     invoke MessageBox,hDlg,addr DiskLabel,addr OutputTemplate,MB_OK+MB_ICONINFORMATION 
   .endif 
  .endif 
 .ELSE 
  mov eax,FALSE 
  ret 
 .ENDIF 
 mov eax,TRUE 
 ret 
DlgProc endp 
end start
   
  

讲解

我们首先分析lable.asm,它是一个加载了VxD的WIN32应用程序。

invoke DeviceIoControl,hVxD,1,NULL,0,addr DiskLabel,12,addr BytesReturned,NULL

它调用DeviceIoControl,设备代码是1,没有输入缓冲区,一个指向输出缓冲区的指针及其大小。DiskLable是一个接收由VxD返回的卷标号的缓冲区。BytesReturned变量存有返回的字节数。这个例子说明了怎样传送数据和从VxD接收数据:你传送输入/输出缓冲区给VxD并且VxD读取/写入数据到指定的缓冲区。

我们下面看看VxD代码。

    VMMCall Get_Sys_VM_Handle 
    mov Handle,ebx 
    assume ebx:ptr cb_s 
    mov ebp,[ebx+CB_Client_Pointer]

当一个VxD接收W32_DeviceIoControl消息,它调用Get_Sys_VM_Handle得到系统VM的句柄并把它存在一个叫Handle的变量中。下面将从VM控制块中提取指向客户寄存器结构的指针到EBP。

    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

下面,准备传送到V86MMGR_Allocate_Buffer的参数。我们必须初始化被分配的缓冲区。我们把MediaID的偏移量送到ESI中,并且把选择子放在FS中,然后调用V86MMGR_Allocate_Buffer。你等会要恢复指向DIOCParams的指针,所以我们必须通过push esi 和pop esi来保护它。

    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 C 
    mov [ebp].Client_ax,440dh

我们在客户寄存器结构中准备参数值来执行int 21h的440Dh功能(从代码66h),得到盘C的媒体ID。我们拷贝edi的值到edx中(edi中有由V86MMGR_Allocate_Buffer分配的内存块的V86地址)。

    mov [ebp].Client_dx,dx 
    shr edx,16 
    mov [ebp].Client_ds,dx

调用了int 21h的440Dh功能(从代码66h)后,在ds:dx中得到一指向一个MID结构的指针,我们必须把在edx中的segment:offset对转换成两个部分并把它们放到合适的寄存器映象中。

    mov eax,21h 
    VMMCall Exec_Int 
    VMMCall End_Nest_Exec 
    Pop_Client_State

当一切都准备好了,我们将运行Exec_Int去模拟一个中断。

    mov ecx,AllocSize 
    stc 
    mov ebx,Handle 
    push esi 
    mov esi,OFFSET32 MediaID 
    push ds 
    pop fs 
    VxDCall V86MMGR_Free_Buffer 
    pop esi

当Exec_Int返回时,分配的缓冲已经由我们想要的信息填满了。下一步是检索信息。我们使用 V86MMGR_Free_Buffer来完成这个目标。这个服务释放由V86MMGR_Allocate_Memory分配的内存块,并且从分配的内存块中拷贝数据到ring0中的内存块。象V86MMGR_Allocate_Memory,如果你想要进行拷贝操作,你必须先把进位标志位置1,再调用服务。


    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

我们在ring0中得到这个信息后,拷贝这个卷标值到Win32应用程序提供的缓冲区中。我们可以用DIOCParams的成员lpvOutBuffer来访问它。




翻译:吕骏,整理:LuoYunBin's Win32 ASM Page, http://asm.yeah.net
汇编语言(1)——寄存器 右边将该段分为更小的两端,大小都为80。段地址一定是16的倍数,这是因为物理地址是由段地址*16+偏移地址得到的,而偏移地址是16位的,因此一个段的最大长度为16KB。在CPU中,程序员能够用指令读写的部件只有寄存器,通过改变寄存器中的内容来控制CPU,CPU执行的指令位置是由CS、IP寄存器中的内容决定的,通过改变这两个寄存器的内容就可以控制CPU执行目标指令。如下图所示,cpu将内存进行段的划分,即将若干地址连续的内存单元看作一个段,将段地址左移4位就是定位段的起始地址,用偏移地址确定具体的内存单元。 阅读详情

相关推荐

Iczelion的Win32汇编教程

Iczelion的Win32汇编教程,传说中的经典win32汇编教程

虚拟8086模式

十一.虚拟8086模式 继推出80386之后,Intel又推出了80386、Pentium和Pentium PRO。这些处理器都具有 实模式和保护模式两种工作方式。前面已介绍过,实模式与8086兼容,可以运行DOS及 以其为平台的几乎所有软件;但在实模式下,处理器不能发挥自身的优越性能,不能支 持多用户、多任务操作系统的运行。为了充分发挥处理器的功能,同时使DOS及以其为 平台的软件继续有效

SpadgerZ的博客 6119

Iczelion&#39;s Win32 Assembly English(Iczelion的汇编教程英文版)

Iczelion&#39;s Win32 Assembly English(Iczelion的汇编教程英文版) 从Iczelion的官网(http://win32assembly.online.fr)下载的zip,为方便收藏打包成chm。

汇编:8086的内存管理方式及数据寻址方式

8086的内存管理及数据寻址方式 立即数寻址、直接寻址、寄存器寻址、寄存器间接寻址、寄存器相对寻址、基址变址寻址、相对基址变址寻址

Tao_Shimmer的博客 3766

第二章:16位 Intel 8086 微处理器

8086微处理器

m0_63997099的博客 3828

80x86保护模式之DOS与虚拟8086模式

虚拟8086模式 ....继推出80386之后,Intel又推出了80386、Pentium和Pentium PRO。这些处理器都具有实模式和保护模式 两种工作方式。前面已介绍过,实模式与8086兼容,可以运行DOS及以其为平台的几乎所有软件;但在实模 式下,处理器不能发挥自身的优越性能,不能支持多用户、多任务操作系统的运行。为了充分发挥处理器的 功能,同时使DOS及以其为平台的软件继

imgodor的专栏 1740

iczelion Vxd cntut3

 虚拟设备驱动程序结构现在大家对vmm和vxd有了一定的了解,接下来我们来看一看如何编写vxd代码。首先,你必须具备Windows 95/98 Device Driver Development Kit。Window95 ddk只有MSDN 订户才能拿到,但Windows98 ddk却可以免费从Microsoft公司取得。尽管Windows 98 ddk是面向WDM的,但你还是

jimgreen的专栏 1006

iczelion Vxd cntut8

 客户寄存器结构我们将学习本教程中另外一个重要的结构,叫客户寄存器结构。在本文中,V86指虚拟8086模式。在这里下载例子程序理论VxDs与正常的win32/win16/DOS应用程序有很大不同。大多数情况下,当其他应用程序正常工作时,它们是休眠的。它们象一个监管者一样工作,其作用是监视ring-3应用程序并在其出错时改正它们。下面是其工作时的典型的情况:1、中断发生时

jimgreen的专栏 1055

iczelion Vxd cntut1

虚拟设备驱动程序初步在本教程里,我假定读者对诸如虚8086模式,调页,GDT,LDT,IDT之类的INTEL 80x86保护模式的操作比较熟悉。如果你不了解这些,那你要先在 http://developer.intel.com/design/pentium/manuals/阅读INTEL的文档。 内容:Windows95是一个运行在最高级特权,第0层级别的多线程操作系统。所有的应用程序都运

jimgreen的专栏 1054

iczelion Vxd cntut8 (转)

iczelion Vxd cntut8 (转)[@more@] 客户寄存器结构 我们将学习本教程中另外一个重要的结构,叫客户寄存器结构。在本文中,V86指虚拟8086模式。在这里下载DOWNLOAD/new/asm...

csd3176的博客 95

win32汇编语言教程

本帮助文件包括:Iczelion的Win32汇编教程、Iczelion 的 ODBC 教程、IczelionVxD 教程共三部分

win32汇编教程(比较全)

mht格式的win32汇编,比较全!想学汇编的朋友可以下载来看看。

实模式、保护模式和虚拟8086方式(详细)

实模式、保护模式和虚拟8086方式(详细) 热度 12已有 323 次阅读2011-3-12 16:41 |个人分类:技术 1:实模式:寻址采用和8086相同的16位段和偏移量,最大寻址空间1MB,最大分段64KB。可以使用32位指令。32位的x86 CPU用做高速的8086。 2:保护模式:寻址采用32位段和偏移量,最大寻址空间4GB,最大分段4GB (Pentium Pre及以后

飞叶如刀 1687

汇编语言 引脚功能和工作模式 | 实模式 保护模式 虚拟模式

由于8088只有一个8位的数据总线,它需要两个时钟周期来传输一个16位的字,而8086只需一个。然而,8088的8位数据总线使得它可以更容易地与现有的8位系统组件兼容,从而降低了系统升级的成本。在最大模式下,CPU的某些功能由外部的总线控制器(如系统控制芯片)来处理,以协调多个处理器之间的活动和资源共享。简而言之,最小模式是为单处理器系统设计的,而最大模式则支持多处理器系统,提供更复杂的控制和协调机制。CPU的最大和最小工作模式是指微处理器操作的两种不同配置方式,主要用于适应不同类型的系统设计。

专注于人工智能的算法与应用 1271

8086/8088计算机内存分配详解

8086/8088微处理器的内存分配机制在当时是一个创新,它采用分段内存管理方式,允许访问高达1MB的内存空间。通过合理的内存分配策略和系统调用,可以有效管理内存资源,提高程序运行效率。8086/8088处理器采用了20位地址总线,最多可以寻址1MB的内存空间。它们使用了分段内存管理机制,将内存划分为多个段,每个段最大为64KB。在MS-DOS环境中,8086/8088程序可以通过DOS系统调用进行内存分配和释放。内存分段是一种将内存分为多个固定大小段的技术,每个段由一个段寄存器指定其基址。

TheJustice_的博客 1926

VM8086模式在LINUX中的代码实现

最近看X11 server的代码,其中有关于显卡由字符模式转为图形模式的过程,查阅网上的资料只说到用到了X86 cpu的VM8086模式(虚拟8086模式),没有具体讲解代码执行过程,通过分析对X86的VM86模式有个一个大致的了解。X86的实模式与保持模式讲的比较多,VM86模式是用于在保护模式下执行X86的16位指令,比较少用,在X11中主要用于显卡由字符模式转为图形模式过程中执行显卡的VBIOS。执行的代码为显卡中的VBIOS的代码,16位地址段地址为0XC0000。主要执行vm86_rep。

weixin_32768871的博客 934

汇编_基础概念

文章目录前言位运算通用寄存器内存与内存地址 前言 这篇文章可以对汇编语言有一个基础的认识 汇编语言入门教程 位运算 位运算汇编指令 汇编指令 C语言 释义 and & 与 两个位都为1时,结果才为1 or | 或 两个位都为0时,结果才为0 xor ^ 异或 两个位相同为0,相异为1 not ~ 取反 0变11变0 shl << 左移 各二进位全部左移若干位,高位丢弃,低位补0 shr/sar >> 右移 各二进位全部右移若干位,对无符

qq_44657899的博客 864

王爽《汇编语言》(第二版) 学习笔记 ( 第三章 寄存器(内存访问))

<br />第三章    寄存器(内存访问)<br />一、             内存中字的存储<br />1.         8086CPU中,用16位寄存器来存储一个字。高8位存放高位字节,低8位存放低位字节。<br />2.         在内存中存储时,由于内存单元是字节单元(一个单元存放一个字节),则一个字要用两个地址连续的内存单元来存放,这个字的低位字节存放在低地址单元中,高位字节存放在高地址单元中。<br />3.         字单元:存放一个字型数据(16位)的内存单元,由两个地

lr2131的专栏 1705

iczelion Vxd cntut4

VxD 程序设计入门We 我们在上一节学会了如何编写一个什么事也不做的VxD程序。在这一节里,我们要给它增加处理控制消息的功能。 VxD的初始化和结束VxD程序分为两种:静态的和动态的。每种的加载方法都不同,接受到的初始化和结束的控制消息也不同。 静态VxD:下列情况下,VMM加载一个静态VxD: 一个实模式常驻程序通过调用中断2FH,1605H,来调用此VxD

jimgreen的专栏 947
上一篇: iczelion Vxd cntut8
下一篇: BadBoy I 源程序!
jimgreen
博客等级 码龄26年 1粉丝 74原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值