ICZelion vxd CNTUT9

zhaozj2021-02-11  219

Memory management of virtual 8086 mode

The V86 we used below refers to the virtual 8086 mode. In the previous tutorial, you learned how to simulate V86 interrupts, but there is still a problem: exchange data between VXD and V86 code. We will learn how to use the V86 Memory Manager to implement this feature. Download example programs here

theory

If your VXD is running with some V86 programs, how to transfer a large amount of data into the V86 program or transfer a lot of data from the V86 program sooner or later. Transferring a large amount of data through the register is unrealistic. Maybe your next idea is to allocate a large number of memory in RING0, and transfer its pointer to the V86 program by some registers to access these data. If you do this, you may destroy your system because the address location of V86 requires segment: offset pair, not linear positioning. There are many solutions to this problem. However, I chose a simple way to provide by the V86 memory manager.

If you can find an idle memory block as a communication buffer in the V86 memory you can use, this will solve one of the problems. However, the problem of pointer transmission still exists. You can solve these two problems through the V86 Memory Manager service. The V86 memory manager is a static VXD for the V86 application management memory. It also provides EMS and XMS services for V86 applications and provides API delivery services for other VXDs. The API transmission is a process of buffer from Ring0 copy data to the V86 range and transmits the V86 buffer address to the V86 code. The V86 Memory Manager has a transfer buffer within the V86 memory, which contains data from VXD to V86 memory, and vice versa. The initial buffer is 4K. You use the V86MMGR_SET_MAPPING_INFO to add its size.

Now you know the transfer buffer, how do we copy or copy out data? This problem resolves two services: V86mmgr_allocate_buffer and v86mmgr_free_buffer.

V86mmgr_allocate_buffer assigns a memory from the transfer buffer and copies some data from Ring0 to allocated V86 buffers. V86MMGR_FREE_BUFFER is exactly the opposite: it copies some data to the Ring0 buffer from allocated V86 memory blocks and releases the memory block allocated by V86MMGR_allocate_buffer.

Remember, V86 manages the assigned buffer like the memory manager icon stack. This means that allocation / release must be based on the rules of advanced. So if you call two V86MMGR_allocate_buffers, the first V86MMGR_Free_buffer will release buffers allocated by the second V86MMGR_Allocate_buffer call.

Let's take a look at the definition of v86mmgr_allocate_buffer, which is a service of a basic register transmitting parameters.

EBX Current VM's handle EBP points to the pointer of the current VM's client register structure ECX that assigns the number of bytes assigned from the transfer buffer, if you don't want to copy data from the RING0 buffer to the allocated memory block, such as You want to copy data from the Ring0 buffer to the allocated memory block 1 fs: ESI points to the Selector: OFFSET pointer to the Ring0 buffer, there is data to be copied to the assigned buffer if the carry flag is Obtain it clearly.

If the call is successful, the carrier bits are cleared and the ECX is included in the number of bytes in the transfer buffer. This value should be less than your requirements, so you should keep this value, V86MMGR_Free_buffer will use it. The high character of the EDI contains the V86 segment address of the assigned memory block, and the offset address is in the low word. The carry flag is set when the error occurs.

V86mmgr_free_buffer and v86mmgr_allocate_buffer accept the same parameters.

When you call V86MMGR_Allocate_buffer, you assign a memory within the current VM V86 memory and put its address in the EDI. You can use these service to transfer data to the V86 interrupt or acquire data from the V86 interrupt. In additional API transmission, the V86 memory manager also provides an API mapping service to other VXDs. The API mapping service is a V86 memory range that maps some pages in the extended memory to each VM. You can perform API mappings using V86MMGR_MAP_PAGES. With this service, the page is mapped to the same linear address space of each VM. If you just work on a VM, this will waste address space. Because the API mapping is slower than the API transmission, you use the API transmission method as much as possible. The API mapping is only used in some V86 operations to access the same linear address space and act to all VMs.

example:

This example demonstrates the API transmission mode using the 440DH function of INT 21H (from code 66h). This interrupt is called to get the media ID, your first fixed disk of the volume mark.

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

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_bufferpop 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 loading.

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

.386

.Model flat, stdcall

Option CaseMAP: NONE

INCLUDE /MASM32/INCLUDE/Windows.inc

INCLUDE /MASM32/INCLUDE/USER32.INC

INCLUDE /MASM32/INCLUDE / WANEL32.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" 0OUTPUTTEMPLATE 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

.lse

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_ICONITIONMATION

.endif

.endif

.Lse

Mov Eax, False

RET

.Endif

Mov Eax, True

RET

DLGPROC ENDP

End Start

explain

We first analyze Lable.asm, which is a Win32 application loaded with VXD.

Invoke DeviceioControl, HVXD, 1, NULL, 0, AddR Disklabel, 12, Addr Bytesreturned, Null

It calls Deviceiocontrol, the device code is 1, no input buffer, a pointer to the output buffer and its size. Disklable is a buffer that receives a volume marking number returned by VXD. The BYTESRETURNED variable has the number of bytes returned. This example illustrates how to transmit data and receive data from VXD: You transmit the input / output buffer to VXD and VXD read / write data to the specified buffer.

Let's take a look at the VXD code.

VMMCALL GET_SYS_VM_HANDLE

Mov Handle, EBX

Assume EBX: PTR CB_S

MOV EBP, [EBX CB_CLIENT_POINTER]

When a VXD receives the W32_Deviceiocontrol message, it calls get_sys_vm_handle to get the handle of the system VM and exist it in a variable called Handle. The pointer to the EBP pointing to the client register structure is extracted from the VM control block. 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

Next, you are ready to transmit to the parameter of V86MMGR_Allocate_buffer. We must initialize the assigned buffer. We sent the offset of MediaI to ESI and put the selection in the FS and then call V86MMGR_allocate_buffer. You will want to resume the pointer to Diocparams, so we must protect it through the PUSH ESI and 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

We prepare a parameter value in the client register structure to perform the 440DH function of INT 21h (from code 66h) to obtain the media ID of the disk C. We copy the value of EDI to EDX (EDI has a V86 address of the memory block allocated by V86MMGR_Allocate_buffer).

MOV [EBP] .client_dx, dx

SHR EDX, 16

MOV [EBP] .client_ds, dx

After calling the 440DH function of INT 21H (from code 66h), get a pointer to a MID structure in DS: DX, we must convert the segment: offset in EDX into two parts and put them in the right The register image is in the mapping.

MOV EAX, 21h

VMMCALL EXEC_INT

VMMCALL END_NEST_EXEC

POP_CLIENT_STATE

When everything is ready, we will run the exec_int to simulate an interrupt.

MOV ECX, Allocsize

STC

Mov EBX, HANDLE

PUSH ESI

Mov ESI, Offset32 Mediaid

Push DS

POP FS

Vxdcall v86mmgr_free_buffer

POP ESI

When EXEC_INT returns, the assigned buffer has filled with the information we want. The next step is to retrieve information. We use v86mmgr_free_buffer to complete this goal. This service releases the memory block allocated by V86MMGR_allocate_memory, and copy data into the memory block in RING0 from the assigned memory block. Like V86mmgr_allocate_memory, if you want to make a copy, you must first put the carry mark position 1, call the service.

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

After getting this information in RING0, we copy this volume value to the buffer provided by the Win32 application. We can use DiocParams' member LPVOTBuffer to access it.