home *** CD-ROM | disk | FTP | other *** search
Wrap
Text File | 1991-03-01 | 780.2 KB | 19,901 lines
%@1@%%@AB@%Microsoft Windows - Virtual Device Adaptation Guide%@AE@%%@EH@%%@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AB@%Microsoft (R) Windows (tm) - Virtual Device Adaptation Guide%@AE@%%@NL@% %@AB@%development tools for providing Microsoft Windows device support %@AB@%VERSION 3.0%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% for the MS-DOS (R) or PC-DOS Operating System%@NL@% Microsoft Corporation %@NL@% Information in this document is subject to change without notice and does not represent a commitment on the part of Microsoft Corporation. The software described in this document is furnished under a license agreement or nondisclosure agreement. The software may be used or copied only in accordance with the terms of the agreement. It is against the law to copy the software on any medium except as specifically allowed in the license or nondisclosure agreement. No part of this manual may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying and recording, for any purpose without the express written permission of Microsoft. U.S. Government Restricted Rights The SOFTWARE and documentation are provided with RESTRICTED RIGHTS. Use, duplication, or disclosure by the Government is subject to restrictions as set forth in subparagraph (c) (1) (ii) of the Rights in Technical Data and Computer Software clause at DFARS 252.227-7013 or subparagraphs (c) (1) and (2) of the Commercial Computer Software ─ Restricted Rights at 48 CFR 52.227-19, as applicable. Contractor/manufacturer is Microsoft Corporation/One Microsoft Way/Redmond, WA 98052-6399. (C) Copyright Microsoft Corporation, 1990. All rights reserved. Simultaneously published in the U.S. and Canada. Printed and bound in the United States of America.%@NL@% Microsoft, MS, MS-DOS, GW-BASIC, QuickC, CodeView, the Microsoft logo, and XENIX are registered trademarks and Windows, Windows/286, and Windows/386 are trademarks of Microsoft Corporation.%@NL@% Paintbrush is a registered trademark of Zsoft Corporation.%@NL@% IBM, AT, and PS/2 are registered trademarks and PC/XT, 386, and Micro Channel are trademarks of International Business Machines Corporation.%@NL@% Intel is a registered trademark and i486 is a trademark of Intel Corporation.%@NL@% COMPAQ is a registered trademark of Compaq Computer Corporation.%@NL@% Document No. SY0329C-300-R00-1089%@NL@% %@NL@% %@1@%%@AB@%Table of Contents%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AB@%Introduction to Virtual Devices%@AE@%%@BO: 72e9@% What You Should Know Before You Start%@BO: 7584@% Organization of This Document%@BO: 7df3@% Notational Conventions%@BO: 8842@% %@AB@%PART III%@AE@%%@BO: 8fdc@% %@AB@%Writing Virtual Devices%@AE@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AB@%Chapter 16%@AE@%%@BO: 93c3@% %@AB@%Overview of Windows in 386 Enhanced Mode%@AE@% 16.1%@BO: 9bc9@% The Operating Environment 16.2%@BO: a358@% Virtual Machines 16.2.1%@BO: ab0e@% The Privilege Rings of a VM 16.2.2%@BO: b0f0@% VM Handles 16.2.3%@BO: b24c@% The Client Register Structure 16.3%@BO: b408@% The Virtual Machine Manager 16.4%@BO: b7c0@% Virtual Devices 16.4.1%@BO: bb6d@% VxD Components 16.4.2%@BO: be3f@% The Device Control Procedure 16.4.3%@BO: c1ab@% The Device Descriptor Block 16.4.4%@BO: c42d@% VxD IDs 16.4.5%@BO: c72e@% VxD Initialization Order 16.5%@BO: ca4f@% How VxDs Work 16.5.1%@BO: cd21@% Enhanced Windows Execution Scheduling 16.5.2%@BO: e287@% Memory Models 16.5.3%@BO: f27f@% Services 16.5.4%@BO: f914@% Callback Procedures 16.5.5%@BO: fd06@% I/O Port Hooks 16.5.6%@BO: 10002@% Interrupt Hooks 16.5.7%@BO: 10335@% Loading Sequence 16.6%@BO: 10c9e@% VxD Examples %@AB@%Chapter 17%@AE@%%@BO: 10e80@% %@AB@%Virtual Device Programming Topics%@AE@% 17.1%@BO: 1147d@% Writing VxDs 17.1.1%@BO: 1196b@% VxD Memory Model 17.1.2%@BO: 11f78@% VxD Segmentation 17.1.3%@BO: 126f1@% VxD Declaration 17.1.4%@BO: 13db0@% VxD Services 17.1.5%@BO: 158bb@% VxD APIs (Call-Ins) 17.1.6%@BO: 16090@% VxD INT 2F Usage 17.2%@BO: 162a7@% Building a VxD 17.2.1%@BO: 16a37@% MASM5.10B 17.2.2%@BO: 16ed1@% LINK386 17.2.3%@BO: 17b8f@% ADDHDR 17.2.4%@BO: 17d35@% MAPSYM32 17.2.5%@BO: 17edf@% Installing a VxD 17.3%@BO: 1803c@% Initializing a VxD 17.3.1%@BO: 1818e@% Real-Mode Initialization 17.3.2%@BO: 19b91@% Protected-Mode Initialization 17.4%@BO: 1a2ac@% Tracking the VM States 17.4.1%@BO: 1a411@% VM Creation and Initialization 17.4.2%@BO: 1a8c3@% VM State Changes 17.4.3%@BO: 1b649@% VM Termination 17.5%@BO: 1bed8@% Exiting Windows 17.6%@BO: 1c2bd@% Debugging a VxD 17.6.1%@BO: 1c4ca@% Entering WDEB386 17.6.2%@BO: 1c7a5@% Tracing Paths of Execution 17.6.3%@BO: 1cfc1@% Querying the VxD State %@AB@%Chapter 18%@AE@%%@BO: 1d1eb@% %@AB@%The VDD and Grabber DLL%@AE@% 18.1%@BO: 1d4d5@% Introduction to VDDs and the Grabber DLL 18.1.1%@BO: 1d7e5@% VDD Interaction with WINOLDAP 18.1.2%@BO: 1e393@% VDD User Messages 18.1.3%@BO: 1e73f@% VDD I/O Trapping and Hooked Pages 18.1.4%@BO: 1eb13@% Grabber Naming Conventions 18.2%@BO: 1ec5c@% VDD Programming 18.2.1%@BO: 1f1da@% VDD Efficiency 18.2.2%@BO: 1f7f2@% Converting Your 2.x VDD 18.2.3%@BO: 2078a@% Environment State Change Requirements for a VDD 18.2.4%@BO: 21cb7@% Grabber API 18.3%@BO: 222db@% Grabber DLL Interfaces 18.3.1%@BO: 22837@% On-Screen Selection Functions 18.3.2%@BO: 23485@% Selection Functions AdjustInitEndPt%@BO: 23544@% BeginSelection%@BO: 2392d@% ConsSelecRec%@BO: 23b70@% EndSelection%@BO: 23d87@% InvertSelection%@BO: 23f1d@% KeySelection%@BO: 24105@% MakeSelctRect%@BO: 24740@% RenderSelection%@BO: 24c1f@% GetDisplayUpd%@BO: 25029@% CheckGRBVersion%@BO: 25611@% CursorOff%@BO: 25824@% CursorOn%@BO: 259d5@% CursorPosit%@BO: 25b90@% GetFontList%@BO: 25daa@% GrabComplete%@BO: 25f92@% GrabEvent%@BO: 262aa@% GrbUnLockApp%@BO: 265c0@% InitGrabber%@BO: 2676f@% PaintScreen%@BO: 269be@% ScreenFree%@BO: 26d11@% SetPaintFnt%@BO: 26efa@% UpdateScreen%@BO: 2750d@% %@AB@%PART IV%@AE@%%@BO: 277ac@% %@AB@%Virtual Device Services%@AE@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AB@%Chapter 19%@AE@%%@BO: 279b6@% %@AB@%Memory Management Services%@AE@% 19.1%@BO: 288e4@% System Data Object Management Allocate_Device_CB_Area%@BO: 28f06@% Allocate_Global_V86_Data_Area%@BO: 29cec@% Allocate_Temp_V86_Data_Area%@BO: 2bcdc@% Free_Temp_V86_Data_Area%@BO: 2c762@% Device V86 Page Management%@BO: 2cd13@% Assign_Device_V86_Pages Assign_Device_V86_Pages service%@BO: 2dad8@% Deassign_Device_V86_Pages%@BO: 2e2ad@% Get_Device_V86_Pages_Array%@BO: 2e987@% Hook_V86_Page%@BO: 2f2bb@% GDT/LDT Management%@BO: 2fad1@% Allocate_GDT_Selector%@BO: 2fe1e@% Allocate_LDT_Selector%@BO: 3084b@% BuildDescDWORDs%@BO: 31a18@% Free_GDT_Selector%@BO: 3239b@% Free_LDT_Selector%@BO: 32730@% GetDescriptor%@BO: 32afb@% SetDescriptor%@BO: 33094@% System Heap Allocator%@BO: 337a4@% HeapAllocate%@BO: 342d7@% HeapFree%@BO: 349bc@% HeapGetSize%@BO: 34cd3@% HeapReAllocate%@BO: 34ff3@% System Page Allocator%@BO: 35d18@% CopyPageTable%@BO: 36409@% GetDemandPageInfo%@BO: 36ff7@% GetFreePageCount%@BO: 378bd@% GetSetPageOutCount%@BO: 38049@% GetSysPageCount%@BO: 386b2@% GetVMPgCount%@BO: 389aa@% MapIntoV86%@BO: 38ebe@% ModifyPageBits%@BO: 3a7cc@% PageAllocate%@BO: 3b597@% PageFree%@BO: 3d946@% PageGetAllocInfo%@BO: 3df3f@% PageGetSizeAddr%@BO: 3e7c5@% PageLock%@BO: 3eca6@% PageOutDirtyPages%@BO: 3f8aa@% PageReAllocate%@BO: 404a2@% PageUnLock%@BO: 41768@% PhysIntoV86%@BO: 4236e@% TestGlobalV86Mem%@BO: 42f47@% Looking At Physical Device Memory From a VxD%@BO: 439cc@% MapPhysToLinear%@BO: 43f3f@% Data Access Services%@BO: 4470f@% GetFirstV86Page%@BO: 44890@% GetNulPageHandle%@BO: 44aa1@% GetAppFlatDSAlias()%@BO: 44bd9@% Special Services For Protected Mode APIs%@BO: 4549a@% GetV86PageableArray%@BO: 45898@% LinMapIntoV86%@BO: 4601b@% LinPageLock%@BO: 47793@% LinPageUnLock%@BO: 47ee7@% PageCheckLinRange%@BO: 48805@% PageDiscardPages%@BO: 48de9@% SelectorMapFlat%@BO: 496fb@% SetResetV86Pageable%@BO: 49d15@% Instance Data Management%@BO: 4b809@% AddInstanceItem%@BO: 4bf0b@% MMGR_Toggle_HMA%@BO: 4d018@% Looking At V86 Address Space%@BO: 4e0b6@% CB_High_Linear%@BO: 4e253@% %@AB@%Chapter 20%@AE@%%@BO: 4e66d@% %@AB@%I/O Services and Macros%@AE@% 20.1%@BO: 4ec75@% Handling Different I/O Types 20.2%@BO: 4fcff@% I/O Macros 20.3%@BO: 501ec@% I/O Services Enable_Global_Trapping, Disable_Global_Trapping%@BO: 5041d@% Enable_Local_Trapping, Disable_Local_Trapping%@BO: 50747@% Install_IO_Handler (Initialization only)%@BO: 509df@% Install_Mult_IO_Handlers (Initialization only)%@BO: 50f55@% Simulate_IO%@BO: 51469@% %@AB@%Chapter 21%@AE@%%@BO: 52402@% %@AB@%VM Interrupt and Call Services%@AE@% Build_Int_Stack_Frame%@BO: 52921@% Call_When_Idle%@BO: 52e17@% Call_When_VM_Ints_Enabled%@BO: 534ee@% Disable_VM_Ints%@BO: 539e5@% Enable_VM_Ints%@BO: 53c12@% Get_PM_Int_Type%@BO: 53f8b@% Get_V86_Int_Vector, Get_PM_Int_Vector%@BO: 54478@% Hook_V86_Int_Chain (Initialization only)%@BO: 54a5a@% Set_PM_Int_Type%@BO: 557b1@% Set_V86_Int_Vector, Set_PM_Int_Vector%@BO: 55c9f@% Simulate_Far_Call%@BO: 56108@% Simulate_Far_Jmp%@BO: 56541@% Simulate_Far_Ret%@BO: 56800@% Simulate_Far_Ret_N%@BO: 56a8f@% Simulate_Int%@BO: 56d7b@% Simulate_Iret%@BO: 5743c@% %@AB@%Chapter 22%@AE@%%@BO: 5774c@% %@AB@%Nested Execution Services%@AE@% Begin_Nest_Exec%@BO: 57b4b@% Begin_Nest_V86_Exec%@BO: 58713@% Begin_Use_Locked_PM_Stack%@BO: 58b97@% End_Nest_Exec%@BO: 590a6@% End_Use_Locked_PM_Stack%@BO: 5954c@% Exec_Int%@BO: 59882@% Exec_VxD_Int%@BO: 59ccb@% Restore_Client_State%@BO: 5ae31@% Resume_Exec%@BO: 5b3f0@% Save_Client_State%@BO: 5c014@% Set_PM_Exec_Mode%@BO: 5ca27@% Set_V86_Exec_Mode%@BO: 5ce84@% %@AB@%Chapter 23%@AE@%%@BO: 5d2a4@% %@AB@%Break Point and Callback Services%@AE@% Allocate_V86_Call_Back, Allocate_PM_Call_Back%@BO: 5d61c@% Call_When_Idle%@BO: 5dd2e@% Call_When_VM_Returns%@BO: 5e3a0@% Install_V86_Break_Point%@BO: 5ed32@% Remove_V86_Break_Point%@BO: 5fa7b@% %@AB@%Chapter 24%@AE@%%@BO: 5fd77@% %@AB@%Primary Scheduler Services%@AE@% Adjust_Exec_Priority%@BO: 60c1f@% Begin_Critical_Section%@BO: 618bc@% Call_When_Not_Critical%@BO: 624e8@% Call_When_Task_Switched%@BO: 62a5b@% Claim_Critical_Section%@BO: 62fa5@% Create_Semaphore%@BO: 632cc@% Destroy_Semaphore%@BO: 633f1@% End_Crit_And_Suspend%@BO: 63517@% End_Critical_Section%@BO: 63e19@% Get_Crit_Section_Status%@BO: 6414b@% No_Fail_Resume_VM%@BO: 6454f@% Nuke_VM%@BO: 648fd@% Release_Critical_Section%@BO: 64cb5@% Resume_VM%@BO: 64f35@% Signal_Semaphore%@BO: 653d3@% Suspend_VM%@BO: 654e5@% Wait_Semaphore%@BO: 65c53@% %@AB@%Chapter 25%@AE@%%@BO: 65d54@% %@AB@%Time-Slice Scheduler Services%@AE@% Adjust_Execution_Time%@BO: 67376@% Call_When_Idle%@BO: 67a48@% Get_Execution_Focus%@BO: 68125@% Get_Time_Slice_Granularity%@BO: 6837f@% Get_Time_Slice_Info%@BO: 6861e@% Get_Time_Slice_Priority%@BO: 68919@% Release_Time_Slice%@BO: 68dd6@% Set_Execution_Focus%@BO: 69226@% Set_Time_Slice_Granularity%@BO: 6961a@% Set_Time_Slice_Priority%@BO: 69949@% Wake_Up_VM%@BO: 69e64@% %@AB@%Chapter 26%@AE@%%@BO: 6a0b8@% %@AB@%Event Services%@AE@% Call_Global_Event%@BO: 6aa71@% Call_Priority_VM_Event%@BO: 6aebf@% Call_VM_Event%@BO: 6c218@% Cancel_Global_Event%@BO: 6c692@% Cancel_Priority_VM_Event%@BO: 6cc38@% Cancel_VM_Event%@BO: 6d34f@% Hook_NMI_Event%@BO: 6d9b1@% Schedule_Global_Event%@BO: 6dc88@% Schedule_VM_Event%@BO: 6e001@% %@AB@%Chapter 27%@AE@%%@BO: 6e4a6@% %@AB@%Timing Services%@AE@% Cancel_Time_Out%@BO: 6e848@% Get_Last_Updated_System_Time%@BO: 6ed71@% Get_Last_Updated_VM_Exec_Time%@BO: 6ef86@% Get_System_Time%@BO: 6f189@% Get_VM_Exec_Time%@BO: 6f4b2@% Set_Global_Time_Out%@BO: 6f850@% Set_VM_Time_Out%@BO: 6fead@% Update_System_Clock%@BO: 70662@% %@AB@%Chapter 28%@AE@%%@BO: 70a3b@% %@AB@%Processor Fault and Interrupt Services%@AE@% Get_Fault_Hook_Addrs%@BO: 70d9a@% Get_NMI_Handler_Addr%@BO: 71178@% Hook_NMI_Event%@BO: 71ace@% Hook_V86_Fault, Hook_PM_Fault, Hook_VMM_Fault%@BO: 71e00@% Hook_V86_Page%@BO: 7295c@% Set_NMI_Handler_Addr%@BO: 731cb@% %@AB@%Chapter 29%@AE@%%@BO: 733e5@% %@AB@%Information Services%@AE@% Get_Cur_VM_Handle%@BO: 73862@% Get_Next_VM_Handle%@BO: 73a98@% Get_Sys_VM_Handle%@BO: 73f7c@% Get_VMM_Reenter_Count%@BO: 7419f@% Get_VMM_Version%@BO: 7457f@% GetSet_HMA_Info%@BO: 747b1@% Test_Cur_VM_Handle%@BO: 74cdc@% Test_Debug_Installed%@BO: 74f66@% Test_Sys_VM_Handle%@BO: 751b3@% Validate_VM_Handle%@BO: 75442@% %@AB@%Chapter 30%@AE@%%@BO: 756a3@% %@AB@%Initialization Information Services%@AE@% Convert_Boolean_String (Initialization only)%@BO: 75c03@% Convert_Decimal_String (Initialization only)%@BO: 76007@% Convert_Fixed_Point_String (Initialization only)%@BO: 7654d@% Convert_Hex_String (Initialization only)%@BO: 76afc@% Get_Config_Directory (Initialization only)%@BO: 76f58@% Get_Environment_String (Initialization only)%@BO: 7725e@% Get_Exec_Path (Initialization only)%@BO: 777ef@% GetDOSVectors (Initialization only)%@BO: 77b5e@% Get_Machine_Info (Initialization only)%@BO: 77f06@% Get_Next_Profile_String (Initialization only)%@BO: 783fa@% Get_Profile_Boolean (Initialization only)%@BO: 78841@% Get_Profile_Decimal_Int (Initialization only)%@BO: 78e36@% Get_Profile_Fixed_Point (Initialization only)%@BO: 793e3@% Get_Profile_Hex_Int (Initialization only)%@BO: 79a0b@% Get_Profile_String (Initialization only)%@BO: 7a047@% Get_PSP_Segment (Initialization only)%@BO: 7a45d@% OpenFile (Initialization only)%@BO: 7a7b5@% %@AB@%Chapter 31%@AE@%%@BO: 7ac4d@% %@AB@%Linked List Services%@AE@% List_Allocate%@BO: 7aff8@% List_Attach%@BO: 7b3b8@% List_Attach_Tail%@BO: 7b71a@% List_Create%@BO: 7ba66@% List_Deallocate%@BO: 7c58d@% List_Destroy%@BO: 7c854@% List_Get_First%@BO: 7cada@% List_Get_Next%@BO: 7cd85@% List_Insert%@BO: 7d24c@% List_Remove%@BO: 7d6dd@% List_Remove_First%@BO: 7da23@% %@AB@%Chapter 32%@AE@%%@BO: 7dd75@% %@AB@%Error Condition Services%@AE@% Crash_Cur_VM%@BO: 7e0b1@% Fatal_Error_Handler%@BO: 7e39f@% Fatal_Memory_Error%@BO: 7e9b8@% %@AB@%Chapter 33%@AE@%%@BO: 7ed78@% %@AB@%Miscellaneous Services%@AE@% Begin_Reentrant_Execution%@BO: 7f1c7@% End_Reentrant_Execution%@BO: 7f689@% Hook_Device_Service%@BO: 7f8d6@% Hook_Device_V86_API, Hook_PM_Device_API%@BO: 80399@% Map_Flat%@BO: 80984@% MMGR_SetNULPageAddr%@BO: 8162b@% Set_System_Exit_Code%@BO: 81935@% Simulate_Pop%@BO: 81cc7@% Simulate_Push%@BO: 81f44@% System_Control%@BO: 821d7@% %@AB@%Chapter 34%@AE@%%@BO: 82ce5@% %@AB@%Shell Services%@AE@% SHELL_Event%@BO: 82fac@% SHELL_Get_Version%@BO: 83589@% SHELL_Message%@BO: 8379b@% SHELL_Resolve_Contention%@BO: 83d5f@% SHELL_SYSMODAL_Message%@BO: 8408e@% %@AB@%Chapter 35%@AE@%%@BO: 84418@% %@AB@%Virtual Display Device (VDD) Services%@AE@% 35.1%@BO: 847f8@% Displaying a VM's Video Memory in a Window 35.2%@BO: 84f36@% Message Mode Services VDD_Msg_BakColor%@BO: 850fd@% VDD_Msg_ClrScrn%@BO: 85336@% VDD_Msg_ForColor%@BO: 85692@% VDD_Msg_SetCursPos%@BO: 858cb@% VDD_Msg_TextOut%@BO: 85ae9@% Miscellaneous VDD Services%@BO: 85d7d@% VDD_Get_GrabRtn%@BO: 85eef@% VDD_Get_ModTime%@BO: 861fa@% VDD_Get_Version%@BO: 86455@% VDD_Hide_Cursor%@BO: 866a1@% VDD_PIF_State%@BO: 869e4@% VDD_Query_Access%@BO: 86bd8@% VDD_Set_HCurTrk%@BO: 86f33@% VDD_Set_VMType%@BO: 871b9@% VDD_Query_Access%@BO: 875ad@% %@AB@%Chapter 36%@AE@%%@BO: 877fe@% %@AB@%Virtual Keyboard Device (VKD) Services%@AE@% VKD_Cancel_Hot_Key_State%@BO: 87d3e@% VKD_Cancel_Paste%@BO: 87f2d@% VKD_Define_Hot_Key%@BO: 88122@% VKD_Define_Paste_Mode%@BO: 88f68@% VKD_Flush_Msg_Key_Queue%@BO: 8937b@% VKD_Force_Keys%@BO: 89587@% VKD_Get_Kbd_Owner%@BO: 89892@% VKD_Get_Msg_Key%@BO: 89a88@% VKD_Get_Version%@BO: 89de7@% VKD_Local_Disable_Hot_Key%@BO: 89fdd@% VKD_Local_Enable_Hot_Key%@BO: 8a22b@% VKD_Peek_Msg_Key%@BO: 8a477@% VKD_Reflect_Hot_Key%@BO: 8a7bf@% VKD_Remove_Hot_Key%@BO: 8abec@% VKD_Start_Paste%@BO: 8adcd@% %@AB@%Chapter 37%@AE@%%@BO: 8b715@% %@AB@%Virtual PIC Device (VPICD) Services%@AE@% 37.1%@BO: 8baf9@% Default Interrupt Handling 37.2%@BO: 8c121@% Virtualizing an IRQ 37.3%@BO: 8c751@% Virtualized IRQ Callback Procedures VID_Hw_Int_Proc%@BO: 8cb57@% VID_EOI_Proc%@BO: 8d140@% VID_Virt_Int_Proc%@BO: 8d63e@% VID_IRET_Proc%@BO: 8da51@% VID_Mask_Change_Proc%@BO: 8e499@% VPICD Services%@BO: 8e71d@% VPICD_Call_When_Hw_Int%@BO: 8e82f@% VPICD_Clear_Int_Request%@BO: 8eef7@% VPICD_Convert_Handle_To_IRQ%@BO: 8f242@% VPICD_Convert_Int_To_IRQ%@BO: 8f461@% VPICD_Convert_IRQ_To_Int%@BO: 8f7cc@% VPICD_Get_Complete_Status%@BO: 8fb2c@% VPICD_Get_IRQ_Complete_Status%@BO: 8fc2a@% VPICD_Get_Status%@BO: 90083@% VPICD_Get_Version%@BO: 90683@% VPICD_Phys_EOI%@BO: 90995@% VPICD_Physically_Mask%@BO: 90cbd@% VPICD_Physically_Unmask%@BO: 90f33@% VPICD_Set_Auto_Masking%@BO: 911b1@% VPICD_Set_Int_Request%@BO: 9151a@% VPICD_Test_Phys_Request%@BO: 91c78@% VPICD_Virtualize_IRQ%@BO: 91eb8@% %@AB@%Chapter 38%@AE@%%@BO: 924f0@% %@AB@%Virtual Sound Device (VSD) Services%@AE@% VSD_Bell%@BO: 92713@% VSD_Get_Version%@BO: 929af@% %@AB@%Chapter 39%@AE@%%@BO: 92bb6@% %@AB@%Virtual Timer Device (VTD) Services%@AE@% VTD_Begin_Min_Int_Period%@BO: 92ece@% VTD_Disable_Trapping%@BO: 935b2@% VTD_Enable_Trapping%@BO: 93c00@% VTD_End_Min_Int_Period%@BO: 93ed1@% VTD_Get_Interrupt_Period%@BO: 94257@% VTD_Get_Version%@BO: 94453@% VTD_Update_System_Clock%@BO: 94739@% %@AB@%Chapter 40%@AE@%%@BO: 9496e@% %@AB@%V86 Mode Memory Manager Device Services%@AE@% 40.1%@BO: 9512a@% Initialization Services V86MMGR_Get_Version%@BO: 9521f@% V86MMGR_Allocate_V86_Pages%@BO: 95434@% V86MMGR_Set_EMS_XMS_Limits%@BO: 95a01@% V86MMGR_Get_EMS_XMS_Limits%@BO: 95e97@% API Translation and Mapping%@BO: 9623c@% V86MMGR_Set_Mapping_Info%@BO: 999ba@% V86MMGR_Xlat_API%@BO: 9a02a@% V86MMGR_Load_Client_Ptr%@BO: 9c979@% V86MMGR_Allocate_Buffer%@BO: 9cf27@% V86MMGR_Free_Buffer%@BO: 9d580@% V86MMGR_Get_Xlat_Buff_State%@BO: 9d9a4@% V86MMGR_Set_Xlat_Buff_State%@BO: 9de0a@% V86MMGR_Get_VM_Flat_Sel%@BO: 9e238@% V86MMGR_Get_Mapping_Info%@BO: 9e633@% V86MMGR_Map_Pages%@BO: 9e85f@% V86MMGR_Free_Page_Map_Region%@BO: 9ebe1@% %@AB@%Chapter 41%@AE@%%@BO: 9ee33@% %@AB@%Virtual DMA Device (VDMAD) Services%@AE@% VDMAD_Copy_From_Buffer%@BO: 9f7a8@% VDMAD_Copy_To_Buffer%@BO: 9fb9d@% VDMAD_Default_Handler%@BO: 9ff72@% VDMAD_Disable_Translation%@BO: a0311@% VDMAD_Enable_Translation%@BO: a06b3@% VDMAD_Get_EISA_Adr_Mode%@BO: a09e5@% VDMAD_Get_Region_Info%@BO: a0d9a@% VDMAD_Get_Version%@BO: a113c@% VDMAD_Get_Virt_State%@BO: a13eb@% VDMAD_Lock_DMA_Region%@BO: a1a2a@% VDMAD_Mask_Channel%@BO: a24fd@% VDMAD_Release_Buffer%@BO: a270a@% VDMAD_Request_Buffer%@BO: a2a35@% VDMAD_Reserve_Buffer_Space%@BO: a2d5d@% VDMAD_Scatter_Lock%@BO: a3230@% VDMAD_Scatter_Unlock%@BO: a3776@% VDMAD_Set_EISA_Adr_Mode%@BO: a3c37@% VDMAD_Set_Phys_State%@BO: a3ee6@% VDMAD_Set_Region_Info%@BO: a41dc@% VDMAD_Set_Virt_State%@BO: a44ca@% VDMAD_Unlock_DMA_Region%@BO: a49ff@% VDMAD_UnMask_Channel%@BO: a4cfc@% VDMAD_Virtualize_Channel%@BO: a4f01@% %@AB@%Chapter 42%@AE@%%@BO: a5473@% %@AB@%Virtual DOSNET Device Services%@AE@% DOSNET_Get_Version%@BO: a574f@% DOSNET_Do_PSP_Adjust%@BO: a5979@% DOSNET_Send_FILESYSCHANGE%@BO: a6315@% %@AB@%Appendix A%@AE@%%@BO: a6a17@% %@AB@%Appendix A Terms and Acronyms%@AE@% %@AB@%Appendix B%@AE@%%@BO: a9f7c@% %@AB@%Understanding Modes%@AE@% B.1%@BO: aa0bd@% Windows Modes B.2%@BO: aa501@% Microprocessor Modes %@AB@%Appendix C%@AE@%%@BO: ab0dd@% %@AB@%Creating Distribution Disks for Drivers%@AE@% C.1%@BO: ab621@% What is an Information File? C.2%@BO: abc72@% Different Types of Information Files C.3%@BO: ac123@% General Format and Syntax for Information Files C.4%@BO: acd59@% File Location Information C.5%@BO: ad64e@% Creating .INF File Entries C.5.1%@BO: ad999@% Display Device C.5.2%@BO: af434@% Mouse or Other Pointing Device C.5.3%@BO: af7f2@% Network Device C.5.4%@BO: b0351@% Keyboard Device C.5.5%@BO: b0af2@% Machine-Dependent Configuration C.6%@BO: b1bae@% Creating .INF File Entries for Printer Drivers C.6.1%@BO: b1eeb@% .INF File Entries C.6.2%@BO: b2ff4@% Driver Description (.DEF) File C.6.3%@BO: b3892@% Special Considerations C.7%@BO: b3a75@% Testing the Installation of Your .INF File C.7.1%@BO: b3d81@% Testing with Setup C.7.2%@BO: b459f@% Testing with Control Panel C.8%@BO: b4c43@% Informing Microsoft About the Availability of Your Driver and/or Virtual Device C.9%@BO: b4fde@% Error Messages When Running Debug Setup %@AB@%Appendix D%@AE@%%@BO: b5a78@% %@AB@%Windows INT 2FH API%@AE@% D.1%@BO: b5f96@% Call-In Interfaces D.1.1%@BO: b6176@% Enhanced Windows Installation Check (AX=1600H) D.1.2%@BO: b67b2@% Releasing Current Virtual Machine's Time-Slice (AX=1680h) D.1.3%@BO: b6f59@% Begin Critical Section (AX=1681h) D.1.4%@BO: b711a@% End Critical Section (AX=1682h) D.1.5%@BO: b725a@% Get Current Virtual Machine ID (AX=1683h) D.1.6%@BO: b7434@% Get Device API Entry Point (AX=1684h) D.1.7%@BO: b7986@% Switch VMs and CallBack (AX=1685h) D.1.8%@BO: b7e26@% Detect Presence of INT 31H Services (AX=1686h) Call Out Interfaces%@BO: b8097@% Windows/386 Version 2.xx API Compatibility%@BO: baca8@% %@AB@%Index%@AE@%%@BO: bc2f7@% %@CR:C6A-Intro @%%@1@%%@AB@%Introduction to Virtual Devices%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% This document explains how to modify existing device drivers or create new virtual devices that will work with Microsoft(R) Windows(tm) 3.0 when running in 386(tm) enhanced mode. %@NL@% This introduction provides some background information that you should review before using this documentation. The topics are presented in the following order: %@NL@% ■ What you should know before you start%@NL@% ■ Organization of this document%@NL@% ■ Notational conventions %@NL@% %@2@%%@CR:C6A00000001 @%%@AB@%What You Should Know Before You Start%@AE@%%@EH@%%@NL@% To program virtual devices for Windows when running in 386 enhanced mode, you should be familiar with Chapter 1, "Overview of Windows," in the %@AI@%Microsoft Windows Device Driver Adaptation Guide%@AE@% and the following topics. Suggested reference materials are shown by topic: %@NL@% %@TH: 25 1549 02 40 40 @%Topic Reference%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%Intel(R) 80386 and 80486 architecture Introduction to the 80386, Intel Literature Sales P.O. Box 58130 Santa Clara, CA 95052-8130 Order Number: 231252-001 ISBN 0-917017-38-2 i486(tm) Microprocessor Programmer's Reference Manual, Intel Literature Sales P.O. Box 58130 Santa Clara, CA 95052-8130 Order Number: 240486-001 ISBN 1-5512-101-2MS-DOS(R) Duncan, Ray. %@AI@%Advanced MS-DOS%@AE@%. Microsoft Press, P.O. Box 97017, Redmond WA. 98073-9717. ISBN Number: 0-914845-77-2 %@AI@%MS-DOS Encyclopedia%@AE@%. Microsoft Press, P.O. Box 97017, Redmond WA. 98073-9717. ISBN Number: 1-5565-174-8Microsoft Windows 3.0 (especially the %@AI@%Microsoft Windows Software Development%@AE@%Memory Management topics) %@AI@%Kit%@AE@%, %@AI@%Programming Topics%@AE@%%@TE: 25 1549 02 40 40 @% To obtain the DOS Protected Mode Interface (DPMI) specification, contact Intel at 1-800-548-4725. For the Virtual DMA Services (VDS) specification, submit a service request via Microsoft OnLine. %@NL@% %@2@%%@CR:C6A00000002 @%%@AB@%Organization of This Document%@AE@%%@EH@%%@NL@% This document is divided into the following parts and chapters: %@NL@% Part 3, "Writing Virtual Devices," describes the requirements of a virtual device and the environment of Windows when running in 386 enhanced mode. It contains the following chapters: %@NL@% ■ Chapter 16, "Overview of Windows in 386 Enhanced Mode," which provides the conceptual foundation of the Windows virtual machine environment.%@NL@% ■ Chapter 17, "Virtual Device Programming Topics," which provides a more in-depth look at various programming topics.%@NL@% ■ Chapter 18, "The VDD and Grabber DLL," which describes the development of a Virtual Display Driver (VDD) and the dynamic-link library (DLL) needed to support a video adapter.%@NL@% Part 4, "Virtual Device Services," provides detailed descriptions of all the available services. It consists of the following 24 chapters: %@NL@% ■ Chapter 19, "Memory Management Services"%@NL@% ■ Chapter 20, "I/O Services and Macros"%@NL@% ■ Chapter 21, "VM Interrupt and Call Services"%@NL@% ■ Chapter 22, "Nested Execution Services"%@NL@% ■ Chapter 23, "Break Point and Callback Services"%@NL@% ■ Chapter 24, "Primary Scheduler Services"%@NL@% ■ Chapter 25, "Time-Slice Scheduler Services"%@NL@% ■ Chapter 26, "Event Services"%@NL@% ■ Chapter 27, "Timing Services"%@NL@% ■ Chapter 28, "Processor Fault and Interrupt Services"%@NL@% ■ Chapter 29, "Information Services"%@NL@% ■ Chapter 30, "Initialization Information Services"%@NL@% ■ Chapter 31, "Linked List Services"%@NL@% ■ Chapter 32, "Error Condition Services"%@NL@% ■ Chapter 33, "Miscellaneous Services"%@NL@% ■ Chapter 34, "Shell Services"%@NL@% ■ Chapter 35, "Virtual Display Device (VDD) Services"%@NL@% ■ Chapter 36, "Virtual Keyboard Device (VKD) Services"%@NL@% ■ Chapter 37, "Virtual PIC Device (VPICD) Services"%@NL@% ■ Chapter 38, "Virtual Sound Device (VSD) Services"%@NL@% ■ Chapter 39, "Virtual Timer Device (VTD) Services"%@NL@% ■ Chapter 40, "V86 Mode Memory Manager Device Services"%@NL@% ■ Chapter 41, "Virtual DMA Device (VDMAD) Services"%@NL@% ■ Chapter 42, "Virtual DOSNET Device Services"%@NL@% Part 5, "Appendixes," provides the following supplemental reference material: %@NL@% ■ Appendix A, "Terms and Acronyms"%@NL@% ■ Appendix B, "Understanding Modes"%@NL@% ■ Appendix C, "Creating Distribution Disks for Drivers"%@NL@% ■ Appendix D, "Windows INT 2FH API"%@NL@% %@2@%%@CR:C6A00000003 @%%@AB@%Notational Conventions%@AE@%%@EH@%%@NL@% The following notational conventions are used throughout the DDK documentation set. %@NL@% %@TH: 29 1747 02 34 44 @%Convention Meaning%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%%@AB@%bold%@AE@% Bold is used for keywords, such as function, register, macro, and data structure field names. These names are spelled exactly as they should appear in source programs. Notice the bold in the following example: %@AB@%Disable%@AE@% (%@AI@%lpDestDev%@AE@%) Here, %@AB@%Disable%@AE@% is bold to indicate that it is the name of a function.%@AI@%italics%@AE@% Italics are used to indicate a placeholder that should be replaced by an actual argument. In the preceding example, %@AI@%%@AE@% %@AI@%lpDestDev%@AE@% is italic to indicate that it should be replaced by an argument.(parentheses) Parentheses enclose the parameter or parameters that are to be passed to a function. In the preceding example, %@AI@%%@AE@% %@AI@%lpDestDev%@AE@% is the parameter.%@AS@%Monospace%@AE@% Monospace type is used for program code fragments and to illustrate the syntax of data structures.%@TE: 29 1747 02 34 44 @% %@CR:C6A-Part 03 @%%@1@%%@AB@%PART III Writing Virtual Devices%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% Microsoft Windows 3.0, while running in 386 enhanced mode, is a single-threaded multitasking environment. It can run unmodified, singletasking non-Windows applications by virtualizing system resources. A resource should be virtualized when multiple applications might use the resource. The software that does this, the %@AI@%virtual device%@AE@%, can also be used to provide other services, both to applications and other virtual devices. %@NL@% This part describes the enhanced Windows environment and details the writing of virtual devices. Part 4, "Virtual Device Services," describes the services provided by virtual devices. Chapter 1, "Overview of Windows," in the %@AI@%Microsoft Windows Device Driver Adaptation Guide%@AE@% also contains material of general interest to the virtual device author. %@NL@% %@CR:C6A00160001 @%%@1@%%@AB@%Chapter 16 Overview of Windows in 386 Enhanced Mode%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% When Microsoft Windows 3.0 is loaded and invoked on an appropriately configured system, it runs in an "enhanced" mode designed to capitalize on the power of the Intel 80386/80486 microprocessors. The 80386 and 80486 chips, support multiple, independent memory regions. Enhanced Windows uses this to build multiple, independent virtual machines, each capable of running an application program. %@NL@% Enhanced Windows supports this multitasking virtual machine environment with a sophisticated set of services that are provided by the virtual devices (VxDs). Virtual devices provide access to all the system resources, including memory management, scheduling, and all the hardware devices. %@NL@% By writing a VxD for a particular hardware device, the author integrates that device into the powerful, enhanced Windows environment. For instance, a properly implemented virtual printer device will, by serializing access to the hardware port, enable multiple applications to share a single printer. %@NL@% This chapter provides a general description of the virtual machine environment and introduces the components of a virtual device. However, detailed programming instructions for the 80386 and 80486 are not provided. Therefore, a VxD programmer should already be familiar with the topics described in the preceding "Introduction to Virtual Devices." %@NL@% In the September, 1987, issue of the %@AI@%Microsoft Systems Journal%@AE@%, the article entitled "Microsoft Windows/386: Creating a Virtual Machine Environment," discusses the structure of Windows/386(tm) version 2.x. It also contains an excellent description of the four modes of the Intel 80386 microprocessor. A portion of that discussion is included in Appendix B, "Understanding Modes," to help you understand the current version of Windows when running in 386 enhanced mode. %@NL@% %@2@%%@CR:C6A00160002 @%%@AB@%16.1 The Operating Environment%@AE@%%@EH@%%@NL@% Windows in 386 enhanced mode has a virtual machine (VM) architecture that provides preemptive multitasking for DOS applications on the 80386 and 80486 processor. %@NL@% The following three major components are also shown graphically in Figure 16.1: %@NL@% ■ Virtual machines%@NL@% ■ Virtual Machine Manager%@NL@% ■ Virtual devices%@NL@% Windows 3.0 virtual machines (VMs) consist of a virtual 8086 (V86) mode portion and, a optional protected-mode (PM) portion and a control block used by the environment. The first VM created is called the System VM. This is the virtual machine in which the Windows graphical user interface runs. Non-Windows applications run in VMs of their own.%@CR:C6A00160003 @%%@CR:C6A00160004 @%%@CR:C6A00160005 @%%@CR:C6A00160006 @%%@NL@% The Virtual Machine Manager (VMM) functions as a multitasking operating environment. The VMM provides services that control the main memory, the CPU execution time, and the peripheral devices. It runs, along with all the VxDs, in one, flat-model, 32-bit memory segment.%@CR:C6A00160007 @%%@CR:C6A00160008 @%%@NL@% The virtual devices (VxDs) either virtualize a peripheral device, provide services for the VMM and VxDs, or both. The "x" in VxD stands for an arbitrary device. In an actual device name, the "x" is replaced with the name of the virtualized device, e.g., VDD for Virtual Display Device and VDMAD for Virtual DMA Device.%@CR:C6A00160009 @%%@CR:C6A00160010 @%%@NL@% Internal hardware devices (e.g., the Programmable Interrupt Controller) and peripheral devices (e.g., a printer) are shown outside of the enhanced Windows environment in Figure 16.1. However, this is a simplified drawing since software routines such as BIOS may also be considered part of the peripheral device. %@NL@% %@AU@%(This figure may be found in the printed book).%@AE@%%@NL@% %@2@%%@CR:C6A00160011 @%%@AB@%16.2 Virtual Machines%@AE@%%@EH@%%@NL@% When Windows is running in 386 enhanced mode, it creates memory partitions that have a remarkable characteristic: programs that run within these partitions execute as though they were running on an 80386 in real mode. Each partition, called a %@AI@%virtual machine%@AE@%, comes complete with its own address space, I/0 port space, and interrupt vector table. Multiple virtual machines can be running simultaneously, with each under the illusion that it is in complete control of the computer. %@NL@% A VM initially runs in the %@AI@%Virtual-86 (V86) mode%@AE@% of the processor. In this mode, the application running in the VM can make use of all the functions associated with 8086 emulation and additional privileged instructions provided by the 80386. The application can also use the %@AI@%protected mode%@AE@% features of the 80386, but should do so via the DPMI (DOS Protected Mode Interface) specification (available from Intel at 1-800-548-4725). %@NL@% A virtual machine (VM) is a complete description of the state of an application. Each VM includes the following:%@CR:C6A00160012 @%%@NL@% ■ The memory associated with the application%@NL@% ■ The processor registers%@NL@% ■ The data structures associated with virtualization%@NL@% The data is used by the VMM and VxDs to virtualize the hardware and to provide services. It is maintained in a data structure called the Control Block. The processor registers are maintained on the VMM stack and can be accessed via the Client Register Structure. The memory can be accessed and manipulated by means of a number of VMM memory manager services.%@CR:C6A00160013 @%%@NL@% The code for MS-DOS and the Windows portion common to the three product modes (real, standard, and 386 enhanced) runs in the System VM. Most of MS-DOS, including all the MS-DOS device drivers and TSRs, is usually shared globally among the VMs. %@NL@% %@3@%%@CR:C6A00160014 @%%@AB@%16.2.1 The Privilege Rings of a VM%@AE@%%@EH@%%@NL@% A VM can have more than one privilege ring. Code executing in one privilege ring can only have access to memory in the same privilege ring or one with a higher number (i.e., lower privilege level).%@CR:C6A00160015 @%%@NL@% The virtual-8086 (V86) mode portion, shown in Figure 16.2, runs in privilege ring 3. This is the code and data most typically associated with MS-DOS applications.%@CR:C6A00160016 @%%@NL@% The second part is a protected-mode (PM) portion that runs at privilege ring 1, 2, or 3. This portion can be used by applications running under enhanced Windows. In the System VM (SYS VM), this portion is used to run the Windows graphical interface.%@CR:C6A00160017 @%%@NL@% The third part is code and data utilized by the VMM and the VxDs running at privilege ring 0. %@NL@% The ring 0 data has three subparts, each associated with a particular VM (per VM): %@NL@% 1. The stack, which contains the Client Register Structure (CRS). The ring 0 stack is used by the VMM and VxDs when a VM is running.%@NL@% 2. The control block, which contains other data (i.e., values associated with the virtualization of hardware for a VM) local to a VM. %@NL@% 3. Data owned by a VxD, which contains information that maintains the state, such as the state of the physical hardware, across all VMs.%@NL@% %@STUB@% %@AU@%(This figure may be found in the printed book).%@AE@%%@NL@% %@3@%%@CR:C6A00160018 @%%@AB@%16.2.2 VM Handles%@CR:C6A00160019 @%%@AE@%%@EH@%%@NL@% Enhanced Windows virtual devices refer to specific VMs by VM handles. By convention, VM handles are usually stored in the %@AB@%EBX%@AE@% register. A VM handle is actually a 32-bit linear address of the virtual machine's control block data structure. %@NL@% %@3@%%@CR:C6A00160020 @%%@AB@%16.2.3 The Client Register Structure %@CR:C6A00160021 @%%@AE@%%@EH@%%@NL@% The Client Register Structure (CRS), as shown in Figure 16.3, contains the virtual machine processor state including all the virtual machine's registers and flags. When a device wants to look at or modify a virtual machine's registers, it must modify the CRS. %@NL@% %@AU@%(This figure may be found in the printed book).%@AE@%%@NL@% %@2@%%@CR:C6A00160022 @%%@AB@%16.3 The Virtual Machine Manager%@CR:C6A00160023 @%%@AE@%%@EH@%%@NL@% The Virtual Machine Manager (VMM) is a device-independent layer of code that provides a framework upon which the virtual devices build virtualizations of physical devices or provide services for each of the VMs. In this sense, the VMM lies between the VMs and the VxDs. All interaction between the software running in the VMs and the VxDs occurs via the interface provided by the VMM. %@NL@% The VMM also provides a set of services that allows for creating, destroying, running, synchronizing, and altering the state of the VMs. The VMM, as shown in Figure 16.4, handles all the privilege ring transitions of VMs to privilege ring 0, provides scheduling services, manages memory, and provides services for such activities as trapping I/O and hooking software interrupts. %@NL@% %@AU@%(This figure may be found in the printed book).%@AE@%%@NL@% %@2@%%@CR:C6A00160024 @%%@AB@%16.4 Virtual Devices%@AE@%%@EH@%%@NL@% Enhanced Windows virtual devices (VxDs) are the interfaces between application software and the hardware. Most VxDs correspond to a hardware device, though not all do. For example, the VxDs for printers and displays simulate actual hardware interfaces, but the VxD called Shell provides access to the Windows graphical user interface. VxDs use services provided by the VMM and other VxDs.%@CR:C6A00160025 @%%@CR:C6A00160026 @%%@NL@% VxDs can provide control functions, service functions, API functions, and callback procedures that are used to virtualize, synchronize, and maintain the state of the hardware for the VMs. A callback procedure is a request for notification when a specified event occurs in the normal execution of the application code. %@NL@% There must be a VxD for each piece of hardware that can have a different state in each of the VMs. %@NL@% %@3@%%@CR:C6A00160027 @%%@AB@%16.4.1 VxD Components%@AE@%%@EH@%%@NL@% Installable virtual devices have the following five, distinct parts, which are shown graphically in Figure 16.5: %@NL@% 1. Real-mode initialization code and data, which is discarded after loading parts 2 - 5 %@NL@% 2. Protected-mode (PM) initialization code, which is discarded after initialization %@NL@% 3. Protected-mode (PM) initialization data, which is discarded after initialization %@NL@% 4. PM code, which contains the Device Control Procedure, API and callback procedures, and services%@NL@% 5. PM data, which contains the Device Descriptor Block, Service Table, and Global Data%@NL@% %@3@%%@CR:C6A00160028 @%%@AB@%16.4.2 The Device Control Procedure%@AE@%%@EH@%%@NL@% The Device Control Procedure (DCP) is the dispatch point for most of the VMM interaction with the VxD. Besides the initialization of the system, there are device control calls for creating, initializing, and destroying VMs; for setting the device focus to a VM; and for indicating a change in the state of the VM.%@CR:C6A00160029 @%%@CR:C6A00160030 @%%@CR:C6A00160031 @%%@NL@% The VMM broadcasts messages to all VxD DCPs indicating changes in the state of the system or of a VM. The DCP can then modify the device's data structure or the VM's state. The address of the DCP is specified in a special data structure called a Device Descriptor Block that all virtual devices must have. See Chapter 17, "Virtual Device Programming Topics," for details on messages passed to the DCP. %@NL@% %@3@%%@CR:C6A00160032 @%%@AB@%16.4.3 The Device Descriptor Block%@AE@%%@EH@%%@NL@% The Device Descriptor Block (DDB) is a VxD-unique data structure containing the VxD's name, version IDs, and entry points for the three code areas: the Device Control Procedure, V86-mode API procedure, and the PM API procedure. In addition, the DDB can contain a pointer to a table of services provided by the VxD. See Chapter 17, "Virtual Device Programming Topics, " for a detailed description of a DDB.%@CR:C6A00160033 @%%@CR:C6A00160034 @%%@CR:C6A00160035 @%%@CR:C6A00160036 @%%@NL@% %@AU@%(This figure may be found in the printed book).%@AE@%%@NL@% %@3@%%@CR:C6A00160037 @%%@AB@%16.4.4 VxD IDs%@AE@%%@EH@%%@NL@% VxD IDs uniquely identify a VxD. They are a 16-bit combination of the OEM number and the device number in the form: %@NL@% %@AS@% xOOOOOOOOOODDDDD%@AE@% The high bit of the VxD ID is reserved for future use. The next 10 bits are the OEM number, which should be requested from Microsoft. The last 5 bits are the VxD number. This enables each OEM to create 32 unique VxDs. If an OEM is creating a replacement for a standard VxD, then it should re-use the standard ID. VxDs that do not provide services or APIs or that do INT 2FH callouts should use the equate Undefined_Device_ID. See VMM.INC for other examples of device IDs. Microsoft has reserved the first 16 OEM numbers (0 through 0FH). %@NL@% %@3@%%@CR:C6A00160038 @%%@AB@%16.4.5 VxD Initialization Order%@AE@%%@EH@%%@NL@% VxDs are initialized in order from the %@AI@%lowest%@AE@% to the %@AI@%highest%@AE@% initialization order value. If two or more VxDs have the same initialization order value, then they are initialized in their order of occurence. Therefore, a specific order is not guaranteed. You should use the initialization order equates in VMM.INC to specify the initialization order for your VxD. If you want your VxD to be initialized slightly before or after a defined initialization order, use the equate plus an increment or minus a decrement.%@CR:C6A00160039 @%%@CR:C6A00160040 @%%@NL@% Most likely your VxD will not have any initialization ordering dependencies. In this case use the Undefined_Init_Order equate. %@NL@% %@2@%%@CR:C6A00160041 @%%@AB@%16.5 How VxDs Work%@AE@%%@EH@%%@NL@% The following sections contain general explanations of how VxDs work and provide information on the following topics: %@NL@% ■ Scheduling%@NL@% ■ Memory use%@NL@% ■ Services%@NL@% ■ Callback procedures%@NL@% ■ I/O port hooks%@NL@% ■ Interrupt hooks%@NL@% ■ Loading %@NL@% The following related topics are covered in Appendix D, "Windows INT 2FH API:"%@CR:C6A00160042 @%%@NL@% ■ Getting the address of a VxD API procedure%@NL@% ■ How a VxD calls out to a TSR or an MS-DOS device driver%@NL@% ■ How a TSR or MS-DOS device driver specifies a VxD to load when starting enhanced Windows %@NL@% %@3@%%@CR:C6A00160043 @%%@AB@%16.5.1 Enhanced Windows Execution Scheduling %@CR:C6A00160044 @%%@AE@%%@EH@%%@NL@% The following is a brief description of how events are scheduled and processed. The concepts are also described graphically in Figure 16.6. %@NL@% %@4@%%@AB@%Events%@CR:C6A00160045 @%%@AE@%%@EH@%%@NL@% The enhanced Windows VMM is a single-threaded, non-reentrant operating system. Because it is non-reentrant, virtual devices that hook interrupts must have some method of synchronizing their calls to the VMM. For this reason, enhanced Windows uses the concept of event processing.%@CR:C6A00160046 @%%@NL@% Event procedures are registered asynchronously and, then, called back just before the VMM returns to the application. At this point, the event procedure can use all the VMM services. %@NL@% VxDs can also use event procedures to perform some action on a VM that is not the current VM. Examples of this include restoring the display to a VM when the display focus changes or simulating an interrupt into a VM the next time the VM is scheduled. %@NL@% There are two types of events: global and VM specific. Global events are processed before returning to a virtual machine regardless of which VM is about to run. VM-specific events are only processed when the specified virtual machine is about to run. %@NL@% %@4@%%@AB@%Scheduler%@AE@%%@EH@%%@NL@% When Windows is running in 386 enhanced mode, each application runs in it own VM. Each VM can be given a share of the CPU time. To assign priority among the VMs, the VMM has a Scheduler.%@CR:C6A00160047 @%%@NL@% The Scheduler is the part of the VMM that determines which VM gets CPU time. It is divided into two parts. At the lowest level, the Primary Scheduler maintains execution priorities, and the VM with the highest priority is allowed to run. VxDs will raise and lower the execution priorities to affect task switching among the VMs. The second level of scheduling is handled by the Time Slicer, which boosts a VM's execution priority for a given time slice.%@CR:C6A00160048 @%%@CR:C6A00160049 @%%@NL@% With the Primary Scheduler, there are specific values assigned to execution priorities to accomplish task switching, without violating the need for some sections of code to execute exclusively until completion. Additionally, high-priority device events, such as interrupts that must be serviced in a timely manner, will boost execution priorities of VMs that need to be serviced. The VMM provides services and defines execution priorities to handle these cases.%@CR:C6A00160050 @%%@NL@% The enhanced Windows Time Slicer is the preemptive multitasking portion of the Scheduler. It relies on time-slice priorities and flags to determine how much CPU time should be allocated to various virtual machines. %@NL@% Every VM has a foreground and a background time-slice priority. These should be distinguished from a VM's %@AI@%execution%@AE@% priority. The VM with the largest execution priority will run, preventing other VMs from executing. The VM with the largest time-slice priority will run more often than other VMs but it will not necessarily prevent other VMs from executing. %@NL@% %@4@%%@AB@%Transitions Into and Out of the VMM and VxDs%@AE@%%@EH@%%@NL@% The enhanced Windows VMM uses the protection mechanism of the 80386 to force privilege ring transitions, as shown in Figure 16.6, whenever an application program issues a software interrupt or causes a protection fault. One example is when a VM performs I/O to a hooked port. The exact mechanisms used to make the transition into the VMM are not important to a virtual device developer. It is almost never necessary to directly intercept a processor fault or hardware interrupt. The only device that handles hardware interrupts directly is the Virtual PIC (Programmable Interrupt Controller) Device. Callback procedures have been provided to signal a calling routine when a specific event occurs. (See Section 16.5.4, "Callback Procedures," for more information.) %@NL@% Programmers familiar with the 80386 architecture may assume that, to hook an interrupt, a virtual device will hook the protected-mode Interrupt Descriptor Table (IDT) directly. However, this is not true for Windows in 386 enhanced mode. Services to hook interrupts at this level are provided by the VMM.%@CR:C6A00160051 @%%@CR:C6A00160052 @%%@CR:C6A00160053 @%%@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AU@%WARNING%@AE@% VxDs must never modify the actual IDT. To do so will cause enhanced Windows to crash. ────────────────────────────────────────────────────────────────────────────%@NL@% The sequence of events for entering the VMM from a virtual machine because of an interrupt is as follows: %@NL@% 1. The VM performs an operation that generates a fault.%@NL@% 2. A ring transition occurs, and the appropriate IDT interrupt handler is called. %@NL@% 3. The VMM dispatches the interrupt to the appropriate handler by a CALL. %@NL@% 4. The protected-mode handler processes the fault and executes a near RET. %@NL@% 5. The VMM processes any outstanding events. %@NL@% 6. An IRET is executed that causes a ring transition back to the VM.%@NL@% Notice that the VMM looks at the interrupt before any virtual devices and immediately before returning to the virtual machine. %@NL@% %@AU@%(This figure may be found in the printed book).%@AE@%%@NL@% %@3@%%@CR:C6A00160054 @%%@AB@%16.5.2 Memory Models%@AE@%%@EH@%%@NL@% Windows in 386 enhanced mode makes use of the 80386's ability to run within different memory models. Some devices may have initialization code that is run in real mode. See Section 16.5.7, "Loading Sequence," for the loading sequence description. After that code is run successfully, a transition is made to protected mode (using selector:offset addressing) in which the VMM is installed and begins executing. The VMM creates a separate VM that consists of a V86-mode portion and an optional, protected-mode (PM) portion for each application. %@NL@% The VMM and all the enhanced Windows VxDs run in a 32-bit, flat-model protected mode segment. This means that every VxD has complete access to 4 gigabytes of linear address space. A VxD can access any VM's memory at any time. %@NL@% Because enhanced Windows is flat model, virtual devices cannot change the %@AB@%CS%@AE@%, %@AB@%DS%@AE@%, %@AB@%ES%@AE@%, or %@AB@%SS%@AE@% segment registers. These segment registers always contain a selector that has a base of 0 and a limit of 4 gigabytes. Devices can use the %@AB@%FS%@AE@% and %@AB@%GS%@AE@% segment registers, but there usually is no reason to do so. VMM services will not modify the %@AB@%FS%@AE@% or %@AB@%GS%@AE@% segment registers. Pointers are always 32-bit linear addresses unless otherwise specified. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%Since the VMM (privilege ring 0 code) resides in a single, flat memory %@AI@%segment, the selector of the selector:offset PM addressing for the VMM and %@AI@%VxDs never changes.%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@4@%%@AB@%Modes%@AE@%%@EH@%%@NL@% Application programs typically run in a V86-mode portion of the enhanced Windows operating environment.%@CR:C6A00160055 @%%@CR:C6A00160056 @%%@NL@% As described in Appendix B, "Understanding Modes," V86 mode is similar to real mode. The crucial difference between the two is that memory protection, virtual memory, and privilege-checking mechanisms are in effect when code runs in V86 mode. Therefore, a program executing in V86 mode cannot interfere with the operating environment or damage other processes. If the program reads or writes memory addresses that have not been mapped into its VM or manipulates I/O ports to which it has not been allowed access, an exception (fault) is generated, and the operating environment regains control. %@NL@% An application may also run in protected mode (also described in Appendix B). An example of this is the the Windows graphical interface. %@NL@% However, non-Windows applications %@AI@%must use%@AE@% DPMI when using protected-mode features. The DPMI (DOS Protected Mode Interface) specification is available from Intel at 1-800-548-4725. By using DPMI, applications gain access to extended memory, the ability to run in a 16-bit or a 32-bit memory model, and other features of the 80386 protected mode. %@NL@% %@4@%%@AB@%Privilege Rings%@AE@%%@EH@%%@NL@% By running in ring 0, the VMM and all the VxDs have the most privileges. Protected-mode applications, such as Windows itself, run in rings 1, 2, or 3 and have lower privileges. Least privileged are MS-DOS and the applications running in V86 mode, which run only in ring 3. %@NL@% Figure 16.7 shows each of these components within there respective rings. Also shown are the Control Block and the Client Register Structure.%@CR:C6A00160057 @%%@NL@% Since all virtual devices run at ring 0, they have the ability to execute any 80386 instruction without producing a protection violation. However, devices should not execute protected instructions as they will usually cause Windows to crash immediately. The only exception to this is the Virtual Math Coprocessor Device, which is allowed to change the 80387 bits in the %@AB@%CR0%@AE@% register.%@CR:C6A00160058 @%%@CR:C6A00160059 @%%@CR:C6A00160060 @%%@NL@% %@AU@%(This figure may be found in the printed book).%@AE@%%@NL@% %@3@%%@CR:C6A00160061 @%%@AB@%16.5.3 Services%@AE@%%@EH@%%@NL@% Services are the shared routines of the VMM and VxDs. VxDs use services to handle interrupts, to initiate callback procedures, and to process exceptions/faults.%@CR:C6A00160062 @%%@NL@% Notice that there are some VxD services that the VMM requires. Most notable of these are the services provided by the Virtual Programmable Interrupt Controller Device (VPICD), which virtualizes the PIC for the VxDs (for requesting interrupts) and the VMs. %@NL@% Detailed descriptions of each service are provided in Part 4, "Virtual Device Services." The services are also categorized there as follows: %@NL@% ■ Memory Management services%@NL@% ■ I/O services and macros%@NL@% ■ VM Interrupt and Call services%@NL@% ■ Nested Execution services%@NL@% ■ Break Point and Callback services%@NL@% ■ Primary Scheduler services%@NL@% ■ Time-Slice Scheduler services%@NL@% ■ Event services%@NL@% ■ Timing services%@NL@% ■ Processor Fault and Interrupt services%@NL@% ■ Information services%@NL@% ■ Initialization Information services%@NL@% ■ Linked List services%@NL@% ■ Error Condition services%@NL@% ■ Miscellaneous services%@NL@% ■ Shell services%@NL@% ■ Virtual Display Device (VDD) services%@NL@% ■ Virtual Keyboard Device (VKD) services%@NL@% ■ Virtual PIC Device (VPICD) services%@NL@% ■ Virtual Sound Device (VSD) services%@NL@% ■ Virtual Timer Device (VTD) services%@NL@% ■ V86 Mode Memory Manager Device services%@NL@% ■ Virtual DMA Device (VDMAD) services%@NL@% ■ Virtual DOSNET Device services%@NL@% %@3@%%@CR:C6A00160063 @%%@AB@%16.5.4 Callback Procedures%@AE@%%@EH@%%@NL@% Some services enable a calling routine to register a procedure that will be called back when a particular event occurs. Callback procedures are used for maintaining the VM state via I/O and interrupt trapping, and for synchronizing with the VMM via the event services. %@NL@% The VMM includes services that enable virtual devices to install callback procedures to do the following:%@CR:C6A00160064 @%%@NL@% ■ Trap interrupts from virtual machines %@NL@% ■ Trap I/O to specific ports %@NL@% ■ Trap access to memory %@NL@% ■ Schedule per-VM or global time-outs %@NL@% ■ Schedule per-VM or global events %@NL@% ■ Detect when a VM returns from an interrupt or FAR call %@NL@% ■ Detect when a VM executes a particular piece of V86 code %@NL@% ■ Detect the release of the critical section %@NL@% ■ Detect changes to the VM's interrupt enable flag %@NL@% ■ Detect task switches%@NL@% %@3@%%@CR:C6A00160065 @%%@AB@%16.5.5 I/O Port Hooks%@AE@%%@EH@%%@NL@% The VMM provides a service called %@AB@%Install_IO_Handler%@AE@%. The service takes two parameters: the port to be hooked, and the address of the procedure to be called whenever the port is accessed.%@CR:C6A00160066 @%%@NL@% When a VxD calls %@AB@%Install_IO_Handler%@AE@%, the VMM sets the appropriate bit in the I/O permission map (IOPM) and registers the procedure. When a virtual machine executes an instruction that reads or writes data from an I/O port, the 80386 looks up the port number in the I/O permission map. If the corresponding bit in the IOPM is set, then the instruction will cause a protection fault that results in calling the registered procedure. %@AB@% %@AE@%%@NL@% %@3@%%@CR:C6A00160067 @%%@AB@%16.5.6 Interrupt Hooks%@AE@%%@EH@%%@NL@% The Virtual Programmable Interrupt Controller Device (VPICD) routes hardware interrupts to other virtual devices, provides services that enable virtual devices to request interrupts, and simulates hardware interrupts into virtual machines.%@CR:C6A00160068 @%%@NL@% When a virtual device needs to hook a specific IRQ, it must ask VPICD for permission. If another device has already virtualized the IRQ, then VPICD will refuse. Chapter 37, "Virtual PIC Device (VPICD) Services," details the workings of the VPICD. %@NL@% For services used in hooking software interrupts and supporting software interrupt hooks, see Chapter 21, "VM Interrupt and Call Services."%@CR:C6A00160069 @%%@CR:C6A00160070 @%%@CR:C6A00160071 @%%@CR:C6A00160072 @%%@NL@% %@3@%%@CR:C6A00160073 @%%@AB@%16.5.7 Loading Sequence%@AE@%%@EH@%%@NL@% The following is a generalized description of the loading sequence. Figures 16.8 and 16.9 are an example of a specific loading sequence.%@CR:C6A00160074 @%%@NL@% When Windows in 386 enhanced mode is first started, the following happens: %@NL@% 1. The loader allocates extended memory via the XMS driver, loads the VMM and all the specified virtual devices into extended memory.%@NL@% 2. The system switches to protected mode.%@NL@% 3. The loader passes control to the VMM initialization routine.%@NL@% 4. The initialization routine completes the initialization of the VMM and calls all the VxD initialization routines.%@NL@% 5. The System VM is created and initialized.%@NL@% 6. The Shell VxD executes WINSTART.BAT and, then, Windows.%@NL@% Each VxD can have different sections of code that are executed during various phases of initialization and normal program execution, as shown in Figure 16.8. %@NL@% The first phase of initialization is load time. During load time, the virtual device can abort the loading of the device, abort the loading of enhanced Windows, specify instance data, and exclude pages of memory from utilization by enhanced Windows. This load time code is in its own segment and is run in real mode and, then, discarded. See Chapter 17, "Virtual Device Programming Topics," for details on real-mode initialization. %@NL@% The rest of the virtual device is run in 32-bit, flat-model protected mode and is divided into the following four parts: %@NL@% ■ Initialization code%@NL@% ■ Initialization data%@NL@% ■ Code%@NL@% ■ Data%@NL@% The initialization code and data are purged from memory after initialization, as shown in Figure 16.9. These segments contain services and data that are accessed only during the three phases of enhanced Windows system initialization: %@AB@%Sys_Critical_Init%@AE@%, %@AB@%Device_Init%@AE@%, and %@AB@%Init_Complete%@AE@%. Some of the enhanced Windows VMM services are available only during initialization. %@NL@% The sections of code and data that are not specifically for initialization perform the device virtualization and can provide services for other devices. %@NL@% %@AU@%(This figure may be found in the printed book).%@AE@%%@NL@% %@AU@%(This figure may be found in the printed book).%@AE@%%@NL@% %@2@%%@CR:C6A00160075 @%%@AB@%16.6 VxD Examples%@AE@%%@EH@%%@NL@% Often, new VxDs are actually modifications of existing ones. To help with your VxD development, Microsoft includes with the DDK the source code for fully operational VxDs. We encourage you to use them as examples whenever convenient. See the DDK %@AI@% Installation and Update Guide%@AE@% for more detailed descriptions and a complete list of the source samples provided for this version of Windows. %@NL@% %@CR:C6A00170001 @%%@1@%%@AB@%Chapter 17 Virtual Device Programming Topics%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% This chapter presents details on writing and installing VxDs. You should be familiar with Chapter 16, "Overview of Windows in 386 Enhanced Mode," before proceeding with this material. For explanations on specific types of services provided by the Virtual Machine Manager (VMM), see the appropriate chapters in Part 4, "Virtual Device Services." This chapter is divided into the following general topics: %@NL@% ■ Writing VxDs%@NL@% ■ Building a VxD%@NL@% ■ Initializing a VxD%@NL@% ■ Tracking the VM states%@NL@% ■ Exiting Windows%@NL@% We recommend that you scan all the topics before beginning a VxD project. You should also review the sample VxDs supplied on the %@AI@%Microsoft Windows %@AI@%Device Development Kit%@AE@% (DDK) disks for examples of how to accomplish specific tasks. The following table suggests some VxDs to study when investigating specific service topics. %@NL@% %@TH: 8 396 02 34 42 @%Service topic Sample VxD%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%Memory management VDDHardware interrupts VKDI/O VPDScheduler VKDEvents VKDTimeouts VKD%@TE: 8 396 02 34 42 @% %@2@%%@CR:C6A00170002 @%%@AB@%17.1 Writing VxDs%@AE@%%@EH@%%@NL@% Enhanced Windows virtual devices are not "Windows" programs. You do not need to know anything about Windows programming to write a VxD.%@CR:C6A00170003 @%%@NL@% Often, new VxDs are simply modifications of existing ones. To help with your VxD development, Microsoft includes the code for many, fully operational VxDs in the %@AI@%Microsoft Windows Device Development Kit%@AE@%. We encourage you to use them as examples whenever convenient. %@NL@% However, some VxDs will require a significant effort to develop. The following can be used as a guideline when writing a complex VxD. %@NL@% 1. Build a skeleton. Using the supplied sources as a guide, build a skeleton of the VxD with the device control procedure, the services, and the API procedures defined but not functional. %@NL@% 2. Add the initialization functionality, including the control block and global memory allocation, physical page hooking, I/O hooking, and interrupt hooking.%@NL@% 3. Fill out the procedures that handle the various hooks.%@NL@% 4. Test the procedures.%@NL@% 5. Implement the APIs and services, if there are any.%@NL@% 6. Test the APIs and services. %@NL@% %@3@%%@CR:C6A00170004 @%%@AB@%17.1.1 VxD Memory Model%@AE@%%@EH@%%@NL@% The part of the enhanced Windows environment containing the VMM and all the VxDs (ring 0), is one, flat-model, 32-bit segment. This means that all the code and data belong to the same group. Two selectors are created: one for code and one for data. Both have a base of zero and a limit of four gigabytes, so all the segment registers point to the same address space (the entire virtual address space provided by the 80386 processor).%@CR:C6A00170005 @%%@NL@% When a VxD is loaded, all the offsets are fixed according to the the VxD's actual position. This is different from MS-DOS's loading of .EXE files, in which segments are fixed up and offsets are left untouched. %@NL@% All procedures are NEAR, and data pointers are 32-bit offsets. %@NL@% VxDs do not export routines or data. To access VMM or VxD services, a dynamic-link mechanism is employed using macros contained in VMM.INC. The VMM services are available with the %@AB@%VMMcall%@AE@% macro, and the VxD services with the %@AB@%VxDcall%@AE@% macro. Data is shared via declared services only. %@NL@% You must use the %@AB@%OFFSET32%@AE@% macro in your flat-model, 32-bit segments anywhere you would normally use the %@AB@%OFFSET%@AE@% assembler directive. That is, in all segments except for the real-mode initialization segment. This macro correctly defines all the offsets so that LINK386 will produce the correct offset fixup information. For example: %@NL@% %@AS@% mov esi, OFFSET32 My_Data%@AE@% %@3@%%@CR:C6A00170006 @%%@AB@%17.1.2 VxD Segmentation%@AE@%%@EH@%%@NL@% As discussed in Chapter 16, "Overview of Windows in 386 Enhanced Mode," VxDs have five functional parts. Each of these parts exists as a separate segment. Macros have been created to define segments for each of the parts.%@CR:C6A00170007 @%%@NL@% Each macro name consists of a segment name followed by "_SEG," which means that this macro begins the segment. A segment descriptor terminated by "_ENDS" is used for macros that end the segment. For example, macros used for defining a segment for real-mode load-time initialization would appear as %@AB@%VxD_REAL_INIT_SEG%@AE@% and %@AB@%VxD_REAL_INIT_ENDS%@AE@%. %@NL@% In some enhanced Windows installations, it is possible to demand page portions of VxDs. These installations require a dedicated swap device or a fully virtualized hard disk with a dedicated swap partition. This way, paging can be done without concern for reentering portions of MS-DOS, device drivers, or BIOS. To support paging, a VxD must place the following in locked memory: %@NL@% ■ Device Control Procedure (DCP)%@NL@% ■ Device Descriptor Block (DDB)%@NL@% ■ Hardware interrupt procedures (and the data accessed by them)%@NL@% ■ Asynchronous (Async) services that can be called from hardware interrupt procedures%@NL@% Some of the macros supplied in VMM.INC (e.g., %@AB@%Declare_Virtual_Device%@AE@%) correctly place code and data objects in locked segments. The following are the different segment descriptor types: %@NL@% %@AS@% VxD_REAL_INIT - Real-mode load-time initialization %@AS@% VxD_ICODE - Protected mode initialization code %@AS@% VxD_IDATA - Protected mode initialization data %@AS@% VxD_LOCKED_CODE - Code that cannot be paged %@AS@% VxD_LOCKED_DATA - Data that cannot be paged %@AS@% VxD_CODE - Pageable code %@AS@% VxD_DATA - Pageable data%@AE@% %@3@%%@CR:C6A00170008 @%%@AB@%17.1.3 VxD Declaration%@AE@%%@EH@%%@NL@% A VxD's first few lines of code must always be the assembler directive (".386p"), the INCLUDE files, and the Device Descriptor Block declaration.%@CR:C6A00170009 @%%@NL@% %@4@%%@AB@%Assembler Directive%@AE@%%@EH@%%@NL@% Every VxD must inform the assembler that the code is 80386 protected-mode code. This is done by including the following directive: %@NL@% %@AS@% .386p%@AE@% %@4@%%@AB@%INCLUDE Files%@AE@%%@EH@%%@NL@% INCLUDE files enable VxDs to use code located in other parts of enhanced Windows. The following INCLUDE files may be included: %@NL@% %@TH: 38 2531 02 34 44 @%Filename Description%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%VMM.INC (Required) Contains definitions of all the enhanced Window services, as well as required macros and equates. DEBUG.INC (Optional) Contains useful macros for dumping messages to a debugging terminal and performing checks on various data. The macros provided by this file produce code only when the VxD is assembled with the DEBUG switch. See the %@AI@%Microsoft Windows Software Development%@AE@% %@AI@%Kit%@AE@% (SDK) for information on the Windows debugging services.VPICD.INC (Optional) Contains equates and service declarations for the Virtual Programmable Interrupt Controller Device (VPICD). All enhanced Windows interrupts are handled by the VPICD. Most VxDs will require VPICD services. For example, the VPD uses the services to hook all the printer port's hardware interrupts.SHELL.INC (Optional) Contains definitions of the public services provided by the Shell VxD. The Shell device provides the VxDs with access to the Windows graphical user interface, thus giving the VxDs the ability to display dialog boxes to the user. For example, if two VMs attempted simultaneously to use the same peripheral device, the VxD could call %@AB@%%@AE@% %@AB@%Resolve_Contention%@AE@%, which would display a dialog box asking the user to choose between the two VM applications.%@TE: 38 2531 02 34 44 @% %@4@%%@AB@%Device Descriptor Block%@AE@%%@EH@%%@NL@% The declaration of the VxD is accomplished by its Device Descriptor Block (DDB). The DDB is generated automatically by the %@AB@%Declare_Virtual_Device%@AE@% macro. The following example is from the VPD sample provided with the DDK. %@NL@% %@AS@% DECLARE_VIRTUAL_DEVICE VPD,3,0,VPD_Control, VPD_Device_ID, %@AS@%VPD_Init_Order,, VPD_PM_API_Handler,, %@AE@% The table in Figure 17.1 describes each of the parameters:%@CR:C6A00170010 @%%@CR:C6A00170011 @%%@CR:C6A00170012 @%%@CR:C6A00170013 @%%@CR:C6A00170014 @%%@CR:C6A00170015 @%%@NL@% %@AU@%(This figure may be found in the printed book).%@AE@%%@NL@% %@4@%%@AB@%VxD IDs%@AE@%%@EH@%%@NL@% To ensure cooperation with current and future versions of enhanced Windows environment components, VxDs need to have unique ID numbers assigned. If you are directly replacing an existing VxD, use the previous ID. Otherwise, if you are creating a new VxD that provides any of the following: %@NL@% ■ Service(s)%@NL@% ■ V86 mode API (see Appendix D, Section D.1.6, "Get Device API Entry Point")%@NL@% ■ Protected Mode API (see Appendix D, Section D.2.3, "Device Call Out API")%@NL@% or if the VxD needs to call an MS-DOS device (listed in .SYS) or TSR, the VxD will need a new ID. Device IDs are a 16-bit combination of the OEM number and the device number in the form: %@NL@% %@AS@% xOOOOOOOOOODDDDD%@AE@% The high bit of the VxD ID is reserved for future use. The next ten bits are the OEM number that is assigned by Microsoft. The last five bits are the device number. This enables each OEM to create 32 unique VxDs. VxDs that do not provide services or APIs or that do INT 2FH call-outs should use the equate Undefined_Device_ID. %@NL@% See VMM.INC for other examples of device IDs. Microsoft reserves the first 16 OEM numbers (0 through 0FH). %@NL@% %@4@%%@AB@%Initialization Order%@AE@%%@EH@%%@NL@% VxDs are initialized in order from the %@AI@%lowest%@AE@% to the %@AI@%highest%@AE@% initialization order value. If two or more devices have the same initialization order value, then they are initialized in their order of occurence. Therefore, a specific order is not guaranteed. You should use the initialization order equates in VMM.INC to specify the initialization order for your VxD. If you want your VxD to be initialized slightly before or after a defined initialization order, use the equate plus an increment or minus a decrement. Most likely, your VxD will not have any initialization ordering dependencies. In this case, use the Undefined_Init_Order equate. %@NL@% %@3@%%@CR:C6A00170016 @%%@AB@%17.1.4 VxD Services%@AE@%%@EH@%%@NL@% The functionality a VxD provides, if either directly to the VMM or other VxDs, or through them to applications, is always via services. The services use a dynamic-linking mechanism using INT 20H. (This mechanism is not the same as the DLL protocol.) An example of a service call is shown below. %@NL@% This section contains descriptions on how to declare and call services, how to verify the presence of a VxD, and a comparison of standard vs. asynchronous services.%@CR:C6A00170017 @%%@NL@% %@4@%%@AB@%Service Calling Conventions%@AE@%%@EH@%%@NL@% All the enhanced Windows services use either a register-based calling convention or a 32-bit C-type calling convention. In general, all the memory manager calls use C calling conventions, and all other services are register based.%@CR:C6A00170018 @%%@NL@% The C convention services all begin with an underscore (_) in front of the service name. They are similar to the standard C conventions: all parameters are passed on the stack, and results are returned in the %@AB@%EAX%@AE@% and %@AB@%EDX%@AE@% registers. %@NL@% Unlike the standard C conventions, the %@AB@%EBX%@AE@%, %@AB@%ES%@AE@%, %@AB@%FS%@AE@%, and %@AB@%GS%@AE@% registers are preserved as well as the %@AB@%ESI%@AE@% and %@AB@%EDI%@AE@% registers. Only the flags and the %@AB@%EAX%@AE@%, %@AB@%ECX%@AE@%, and %@AB@%EDX%@AE@% registers are modified. %@NL@% The %@AB@%VMMcall%@AE@% and %@AB@%VxDcall%@AE@% macros support stack parameter passing like the standard C macro package. For example: %@NL@% %@AS@% VMMcall _HeapAllocate, <<SIZE Data_Node>, 0>>%@AE@% will generate the following code: %@NL@% %@AS@% push 0 %@AS@% push SIZE Data_Node %@AS@% int 20h %@AS@% dd _HeapAllocate %@AS@% add esp, 2*4%@AE@% Notice that the parameters are pushed on the stack from right to left as in the standard convention. %@NL@% All the Windows services for running in 386 enhanced mode that do not begin with an underscore (_) are register-based services. All the parameters to the services are passed in registers and all the results are returned in registers. If a service does not explicitly return a result in a register, than that register will be preserved. %@NL@% %@4@%%@AB@%Declaring Services%@AE@%%@EH@%%@NL@% Virtual devices use two macros, %@AB@%Begin_Service_Table%@AE@% and %@AB@%End_Service_Table%@AE@%, that are declared in VMM.INC to export services. The service table is normally declared in an INCLUDE file that other VxDs can include to import the services. For example, a typical service table declaration would look something like this for the Virtual "FOO" Device: %@NL@% %@AS@% Begin_Service_Table VFooD%@AE@% %@AS@% VFooD_Service vFooD_Get_Version, LOCAL %@AS@% VFooD_Service vFooD_Do_Something %@AS@% VFooD_Service vFooD_Do_Somthing_Else %@AS@% VFooD_Service vFooD_Do_Yet_Another_Thing, VxD_ICODE%@AE@% %@AS@% End_Service_Table VFooD%@AE@% The %@AB@%Begin_Service_Table%@AE@% macro uses a single argument to generate the macro used to declare individual services. %@AB@%Begin_Service_Table%@AE@% names the macro by taking the name of the device and appending "_Service" to it. In the preceding example, %@AB@%VFooD_Service%@AE@% is the name of the macro. %@NL@% The %@AB@%Device_Service%@AE@% macro can take one or two parameters. The first parameter is the name of the service (e.g., %@AB@%Get_Version%@AE@%). This must match the name of a procedure that was declared with the %@AB@%BeginProc%@AE@% macro using the "%@AB@%Service%@AE@%" or "%@AB@%Async_Service%@AE@%" options. The second parameter is optional. If it is omitted, then the service procedure is declared as an external reference in the VxD_CODE segment. %@NL@% If the special value "LOCAL" is used as the second parameter (as in the VFooD_Get_Version declaration), then the procedure is not declared as external. This option is used when the service is declared in the same file in which the service table will be created. If, in this case, it were to be declared external, then MASM would generate an error. %@NL@% If the service procedure is not in the same file as the one used to create the service table, and not in the VxD_CODE segment, then you must supply the name of the segment it resides in so that the proper external declaration can be made. In the above example, the %@AB@%VFooD_Do_Yet_Another_Thing%@AE@% service is declared to be in the VxD_INIT code segment. All others are left in the default VxD_CODE segment. %@NL@% The first service for every device %@AI@%must%@AE@% be a %@AB@%Get_Version%@AE@% service. This service must return with %@AB@%AX%@AE@% 0 and the Carry flag clear. See the following section, "%@AB@%VxD Presence Verification%@AE@%," for more details. %@NL@% Once the table of services has been created, you must force the table to be generated in one of the VxD source files by defining a special equate (EQU) called "%@AB@%Create_xxx_Service_Table%@AE@%," where %@AI@%xxx%@AE@% is the name of the device before including the service declaration INCLUDE file. For example, the main source file of the VFooD service table would contain the following INCLUDE statements:%@AB@% %@AE@%%@NL@% %@AS@% INCLUDE VMM.INC %@AS@% INCLUDE Debug.INC %@AS@% Create_VFooD_Service_Table EQU true %@AS@% INCLUDE VFooD.INC%@AE@% This must be done in the same source file that contains the device declaration. This table is automatically generated and the pointer to the table is stored in the device's DDB. %@NL@% Notice that, since the macros generate equates, you will now want to add service declarations to the end of the INCLUDE file. That is, never change the order of the declarations. Adding, removing, or changing the order of services changes the service numbering and all the VxDs that call these services will need to be rebuilt. %@NL@% %@4@%%@AB@%VxD Presence Verification%@AE@%%@EH@%%@NL@% Many VxDs will not load under certain circumstances. For example the EBIOS device will not load when the machine does not have an extended BIOS data area. Before calling VxD services, you should make sure that the VxD is loaded by calling the VxD %@AB@%Get_Version%@AE@% service. %@AB@%Get_Version%@AE@% for a VxD will return with %@AB@%AX%@AE@% = 0 and the Carry flag set if the VxD is not installed. %@NL@% %@4@%%@AB@%Standard Vs. Asynchronous Services%@AE@%%@EH@%%@NL@% Most services are not reentrant. This means they cannot be called from hardware interrupt procedures. However, a select group of services is declared as "Async" services and can be called from hardware interrupt procedures. You may declare services that can be called from interrupt handlers by using the "%@AB@%Async_Service%@AE@%" option for the %@AB@%BeginProc%@AE@% macro. %@NL@% When writing async services, do not call non-async services, and be sure the routine can handle reentrancy. %@NL@% %@3@%%@CR:C6A00170019 @%%@AB@%17.1.5 VxD APIs (Call-Ins)%@AE@%%@EH@%%@NL@% While VxD services are used to communicate with other enhanced Windows virtual devices, APIs are used to communicate with software running in a virtual machine. For example, the Shell device supports an API that is used to communicate with WinOldAp (the Windows support program for non-Windows applications) that runs in the System VM.%@CR:C6A00170020 @%%@CR:C6A00170021 @%%@NL@% A VxD can support API for V86-mode code, protected-mode code, or both. The procedure entry point(s) for the API is specified in the device declaration macro (see Section 17.1.3, "VxD Declaration," for more details on %@AB@%Declare_Virtual_Device%@AE@%). The VM software issues an INT 2FH with %@AB@%AX%@AE@% = 1684H and %@AB@%BX%@AE@% = Device_ID to get the address to call to access the API. See Appendix D, "Windows INT 2FH API," for more information.%@CR:C6A00170022 @%%@NL@% The application can then call this address, passing appropriate information in registers. The same address is used to call all API functions provided by a single VxD. %@NL@% When such a call is made, the VMM will in turn call the VxD's API procedure with the following parameters: %@NL@% %@AS@% EBX = Current VM handle %@AS@% EBP = Client register structure %@AS@% Client_CS:IP = Instruction following API call%@AE@% API procedures must examine the client registers (through the client register structure) to determine which API call was made. The normal calling convention uses %@AB@%AH%@AE@% = Major function number and %@AB@%AL%@AE@% = Minor function number. Other registers are used for parameters to the functions. However, a device can use any calling convention that is appropriate. If you want to return a value to the caller, then the API procedure should modify the client registers. %@NL@% API procedures may modify the %@AB@%EAX%@AE@%, %@AB@%EBX%@AE@%, %@AB@%ECX%@AE@%, %@AB@%EDX%@AE@%, %@AB@%ESI%@AE@%, and %@AB@%EDI%@AE@% registers. %@NL@% %@3@%%@CR:C6A00170023 @%%@AB@%17.1.6 VxD INT 2F Usage%@AE@%%@EH@%%@NL@% Appendix E, "The Windows INT 2F API," includes several INT 2F functions that are of interest to VxD writers. Specifically, there is an INT 2F to get the address for calling the VxD API procedure, an INT 2F for a VxD to call out to a T&SR or a DOS device driver, and an INT 2F by which a T&SR or DOS device driver can specify a VxD to load when starting enhanced mode Windows. If your VxD interacts with global software, be sure to study this appendix. %@NL@% %@2@%%@CR:C6A00170024 @%%@AB@%17.2 Building a VxD%@AE@%%@EH@%%@NL@% This section describes in general the steps necessary to build and install a VxD into the enhanced Windows environment. These steps are typically specified and executed from the MAKE file. Detailed examples are also included in a MAKE files located on the supplied DDK disks.%@CR:C6A00170025 @%%@NL@% There are three required steps for building a VxD, with each requiring a specific software tool: %@NL@% 1. Assemble the VxD code with MASM5.10B, which is the special version of the assembler used to handle a new pseudo group, FLAT. (%@AB@%.ASM %@AE@%.OBJ)%@NL@% 2. Link the .OBJ files utilizing a .DEF file, with LINK386. LINK386 is the linker used to create the special 32-bit .EXEs.(%@AB@%.OBJ %@AE@% %@AB@%.386%@AE@%, %@AB@%.MAP%@AE@%)%@NL@% 3. Declare the code to be a VxD with ADDHDR, which adds special VxD information into the .EXE produced with LINK386.(%@AB@%.386 %@AE@% %@AB@%.386%@AE@%)%@NL@% %@STUB@% An optional fourth step, is available for debugging:%@NL@% 4. Generate symbol files with MAPSYM32, which generates 32-bit symbol (.SYM) files for debugging.(%@AB@%.MAP .%@AE@%SYM)%@NL@% These four tools are included in this version of the DDK. See the following sections for detailed invocation instructions. %@NL@% The following MAKE file sample is from the Virtual Printer Device (VPD). The complete source for building the VPD is included on the DDK disks. %@NL@% %@AS@% vpd.obj: vpd.asm %@AS@% masm5 -p -w2 vpd; %@AS@% %@AS@% vpd.386: vpd.obj vpd.def %@AS@% link386 vpd, vpd.386/NOI /NOD /NOP,/MAP,,vpd.def %@AS@% addhdr vpd.386 %@AS@% mapsym32 vpd%@AE@% The MAKE file assumes that the four tools are included in the MS-DOS %@AB@%PATH%@AE@% command. If they are not, then you must modify the MAKE file to specify their exact locations. %@NL@% %@3@%%@CR:C6A00170026 @%%@AB@%17.2.1 MASM5.10B%@AE@%%@EH@%%@NL@% This is a special version of MASM that supports 32-bit, flat-model code. It has been named MASM5 to differentiate it from other versions of MASM you may already have. It has the same command-line options and format as MASM 5.1, so you can refer to version 5.1 documentation for information on this program.%@CR:C6A00170027 @%%@NL@% It is recommended that the %@AB@%-p%@AE@% and %@AB@%-w2%@AE@% options be used when assembling virtual devices. The %@AB@%-p%@AE@% option specifies that impure code segment references should generate warning messages. This is desirable, because it is illegal to write data with a %@AB@%CS%@AE@% override. The %@AB@%-w2%@AE@% option sets the warning level to 2, so that warning messages are generated for such things as jumps that are within SHORT range and for data size mismatches. %@NL@% MASM5 will look for INCLUDE files in the current directory and the INCLUDE path specified by the environment variable INCLUDE. Therefore, the DDK INCLUDE files (e.g., VMM.INC, VPICD.INC, and VDD.INC) should be either in the current directory or located along the INCLUDE path. %@NL@% %@3@%%@CR:C6A00170028 @%%@AB@%17.2.2 LINK386%@AE@%%@EH@%%@NL@% The LINK386 command line is as follows:%@CR:C6A00170029 @%%@NL@% %@AS@% LINK386 <object file>, <output file> {<options>}, <map file>, <def file>%@AE@% For example: %@NL@% %@AS@% link386 vpd, vpd.386/NOI /NOD /NOP, /MAP,,vpd.def%@AE@% LINK386 links into one device file the individual object (OBJ) files that make up a virtual device. By convention, Windows devices have the extension .386. The command line specifies the object files(s), the desired output file, option switches, and definition file. The following list describes the option switches used to link a VxD. %@NL@% %@TH: 17 929 02 12 24 40 @%Option Full Name Description%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%%@AB@%/NOI%@AE@% NOIGNORECASE Specifies that case should not be ignored.%@AB@%/NOD%@AE@% NODEFAULTLIBRARYSEARCH Specifies that LINK386 should not search for default libraries.%@AB@%/NOP%@AE@% NOPACKEDCODE Specifies that code segments should %@AB@%%@AE@% not be packed into one code segment in the .EXE file.%@AB@%/MAP%@AE@% Specifies that all public symbols should be included in the MAP file.%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%%@TE: 17 929 02 12 24 40 @% Definition (DEF) files are used by LINK386 to identify the device descriptor block within the device and the types of segments. DEF files for virtual devices all look similar to the following example: %@NL@% %@AS@% LIBRARY VPD%@AE@% %@AS@% DESCRIPTION 'Win386 VPD Device (Version 2.0)'%@AE@% %@AS@% EXETYPE DEV386%@AE@% %@AS@% SEGMENTS %@AS@% _LTEXT PRELOAD NONDISCARDABLE %@AS@% _LDATA PRELOAD NONDISCARDABLE %@AS@% _ITEXT CLASS 'ICODE' DISCARDABLE %@AS@% _IDATA CLASS 'ICODE' DISCARDABLE %@AS@% _TEXT CLASS 'PCODE' NONDISCARDABLE %@AS@% _DATA CLASS 'PCODE' NONDISCARDABLE%@AE@% %@AS@% EXPORTS %@AS@% VPD_DDB @1%@AE@% The LIBRARY line is required to identify the device as a module that is part of a system rather than an executable application. The DESCRIPTION line is optional and simply records the text string into the .386 file. The EXETYPE line is required to identify the .386 file as an enhanced Windows device file. %@NL@% The SEGMENTS section is identical for all devices, because it identifies the six possible types of protected-mode segments that can be part of a device. (If a device has a real-mode initialization section, then it can have seven types of segments. However, the real-mode section does not need any special identification in the DEF file.) %@NL@% The EXPORTS section is also required; it identifies the name and location of the device descriptor block for the virtual device. It must match the name used in the %@AB@%Declare_Virtual_Device%@AE@% statement in the device source, with _DDB appended to the end. It must also be identified as ordinal number 1 with the @ symbol. %@NL@% %@3@%%@CR:C6A00170030 @%%@AB@%17.2.3 ADDHDR%@AE@%%@EH@%%@NL@% The ADDHDR command line is as follows:%@CR:C6A00170031 @%%@NL@% %@AS@% addhdr <filename>%@AE@% For example: %@NL@% %@AS@% addhdr vpd.386%@AE@% ADDHDR simply reads the specified 32-bit .EXE file, performs some validation checks, and writes some additional header information needed by the enhanced Windows loader into the file's .EXE header. %@NL@% %@3@%%@CR:C6A00170032 @%%@AB@%17.2.4 MAPSYM32%@AE@%%@EH@%%@NL@% The MAPSYM32 command line is as follows:%@CR:C6A00170033 @%%@NL@% %@AS@% mapsym32 <device name>%@AE@% For example: %@NL@% %@AS@% mapsym32 vpd%@AE@% MAPSYM32 reads a MAP file and creates a 32-bit .SYM file for use with the Windows debugger, WDEB386. The %@AB@%/MAP%@AE@% option must be specified for LINK386 to generate the necessary MAP file. %@NL@% %@3@%%@CR:C6A00170034 @%%@AB@%17.2.5 Installing a VxD%@AE@%%@EH@%%@NL@% In order to install the newly created VxD with the rest of enhanced Windows, edit the SYSTEM.INI file. in the %@AB@%[386ENH]%@AE@% section by inserting %@AB@%DEVICE%@AE@% = <your VxD file name> and put your file in the Windows SYSTEM subdirectory.%@CR:C6A00170035 @%%@NL@% %@2@%%@CR:C6A00170036 @%%@AB@%17.3 Initializing a VxD%@AE@%%@EH@%%@NL@% As described in Chapter 16, "Overview of Windows in 386 Enhanced Mode," VxDs are initialized along with the enhanced Windows environment. Both real-mode and protected-mode code may be used and are described in the following subsections.%@CR:C6A00170037 @%%@NL@% %@3@%%@CR:C6A00170038 @%%@AB@%17.3.1 Real-Mode Initialization%@AE@%%@EH@%%@NL@% Each VxD can have a portion that is run in real mode at load time. This capability is provided to enable a VxD to determine whether or not it can operate in the current environment and to provide information to the loader about how it should vary the environment. This portion is only executed at load time and, then is discarded.%@CR:C6A00170039 @%%@CR:C6A00170040 @%%@NL@% A real-mode portion is included in the same binary file as the rest of the VxD code and data, but is located in a special 16-bit sement. It has a single entry point, declared as a NEAR procedure. At load time, if the loader determines that a real-mode portion is present, it loads it and calls its entry point as specified by the END statement at the end of the file (%@AB@%CS%@AE@%:0 if no entry point is found). Upon entry %@AB@%CS%@AE@% = %@AB@%DS%@AE@% = %@AB@%ES%@AE@%, so code and data must be mixed in the same segment. The code can then perform the checks that are necessary and return an exit code back to the loader. %@NL@% Valid exit codes are as follows (see VMM.INC for equates): %@NL@% ■ 0 - Everything is fine, and the loader should continue loading the protected-mode portion and the rest of the VxDs.%@NL@% ■ 1 - This device is not compatible with the current environment and will not be loaded, but the loader can continue to load other VxDs.%@NL@% ■ 2 - Something is wrong and the loader should abort the Windows load completely.%@NL@% If 1 or 2 is returned, then the loader will normally print an appropriate error message naming the VxD that failed. If the real-mode portion has already handled the message reporting or does not want any default error message, then it should set the high bit of the return code in %@AB@%AX%@AE@% (i.e., 8001H or 8002H.) %@NL@% The real-mode portion can also inform the loader to do the following: %@NL@% ■ Pass a DWORD of reference data to the protected-mode portion of the device.%@NL@% ■ Pass a table of pages in low memory (0-1Mb) that should be excluded from general use by the enhanced Windows memory manager.%@NL@% ■ Pass a table of pointers to data that should be instanced for each virtual machine. %@NL@% It is possible for a VxD to exclude pages and/or declare instance data without actually having a protected-mode portion; it should return 8001H as the return code, so that the loader will attempt no further loading of the device and will not display the default error message. %@NL@% The real-mode portion can perform most BIOS or MS-DOS interrupts and examine memory to check the environment of the machine. It cannot attempt to perform any type of MS-DOS exit calls because these will halt the loader in an unclean state, and it will be necessary to reboot the machine. Also, any open files should be closed before returning since they will not be closed by the loader. %@NL@% The following is a summary of entry assumption: %@NL@% CS = DS = ES = segment of loaded code and data IP = specified entry point or 0. SI = environment segment, passed to the loader from MS-DOS AX = VMM version number BX = flags bit 0: duplicate device ID already loaded bit 1: duplicate ID was from the INT 2F device list bit 2: this device is from the INT 2F device list %@AB@%EDX%@AE@% = reference data from INT 2F response, or 0 %@NL@% %@AB@%SS:SP%@AE@% point to loader's stack. %@NL@% The following is a summary of exit assumptions: %@NL@% Must return with a NEAR return %@AB@%AX%@AE@% = return code (see above) %@AB@%BX%@AE@% = ptr to list of pages to exclude (0, if none), where: list is = one or more words in the range 1 to 9FH (terminated) by a word of zero %@AB@%SI%@AE@% = ptr to list of Instance data items (0, if none), where: list is = one or more instance data items followed by three words of zero (note that 0-3FF, the interrupt vectors are always instanced). instance data item = pointer to data (word segment, word offset),word length of data %@NL@% %@AB@%EDX%@AE@% = DWORD of reference data to be passed to the protected-mode portion. (This can be a linear pointer to ROM data, a constant, etc. that will affect the way the protected portion might operate. For example, an EBIOS device can pass the EBIOS page number, so that the protected-mode portion does not have to look for the page again.) %@NL@% All the other registers except SS:SP can be modified. %@NL@% The macros %@AB@%VxD_REAL_INIT_SEG%@AE@% and %@AB@%VxD_REAL_INIT_ENDS%@AE@% are defined in VMM.INC to facilitate creating a real-mode portion of a device driver. The real-mode portion cannot access code or data outside of its segment. If this is attempted, the linker will generate warnings and a corrupt .386 file. Fixed segments such as the BIOS (40H) segments are an exception to this. It is possible to have declared in multiple source files real-mode portions that will all be linked together (e.g., separating message text from the code). %@NL@% The following is an example of real-mode initialization code: %@NL@% %@AS@% VxD_REAL_INIT_SEG %@AS@% BeginProc ebios_init %@AS@% mov ah, 0C0h %@AS@% int 15h %@AS@% test es:[bx.SD_feature1], EBIOS_allocated %@AS@% jz short no_ebios_fnd %@AS@% mov ah, 0C1h ; get segment adr of EBIOS %@AS@% int 15h %@AS@% %@AS@% jc short no_ebios_fnd %@AS@% mov ax, es ; get EBIOS segment address %@AS@% shr ax, 8 ; convert to a page # %@AS@% movzx edx, ax ; return EBIOS pg as ref %@AS@% ; data %@AS@% mov bx, OFFSET exc_ebios_page ; ptr to exclusion table %@AS@% mov [bx], ax ; exclude EBIOS page %@AS@% ; from memory manager use %@AS@% xor si, si ; no instance data to %@AS@% ; declare %@AS@% mov ax, Device_Load_Ok ; go ahead and load the %@AS@% ; device %@AS@% jmp short init_exit ; return to loader %@AS@% %@AS@% no_ebios_fnd: %@AS@% mov ah, 9 %@AS@% mov dx, OFFSET no_ebios_msg ; print message thru DOS %@AS@% int 21h %@AS@% xor bx, bx ; no exclusion table %@AS@% xor si, si ; no instance data table %@AS@% xor edx, edx ; no reference data %@AS@% mov ax, Abort_Device_Load + No_Fail_Message %@AS@% ; don't load pmode portion %@AS@% ; and don't display an %@AS@% ; error msg %@AS@% %@AS@% init_exit: %@AS@% ret %@AS@% exc_ebios_page dw 0, 0 %@AS@% no_ebios_msg db 'PS/2 type EBIOS not detected', 13, 10, '$' %@AS@% EndProc ebios_init %@AS@% VxD_REAL_INIT_ENDS %@AS@% END ebios_init ; specify real mode %@AS@% ; initialization entry point%@AE@% %@3@%%@CR:C6A00170041 @%%@AB@%17.3.2 Protected-Mode Initialization%@AE@%%@EH@%%@NL@% The enhanced Windows environment has a three-phase, protected-mode initialization. Returning a carry during any of the phases will abort the VxD load.%@CR:C6A00170042 @%%@NL@% %@4@%%@AB@%Phase 1. Sys_Critical_Init%@AE@%%@EH@%%@NL@% During the first phase of initialization, interrupts are not yet enabled. Therefore, this phase should accomplish the following tasks as quickly as possible. %@NL@% ■ Initialization of critical functions necessary when interrupts are enabled. %@NL@% ■ Claiming a particular range of V86 pages if necessary (such as the video memory for the VDD).%@NL@% ■ Initialization of data needed by the services provided by the VxD.%@NL@% ■ During this phase, the System VM %@AB@%Simulate_Int%@AE@% and %@AB@%Exec_Int%@AE@% commands must not be used.%@NL@% %@4@%%@AB@%Phase 2. Device_Init%@AE@%%@EH@%%@NL@% During this phase most VxDs do the bulk of their initialization. They will: %@NL@% ■ Allocate their Control Block area%@NL@% ■ Allocate other required memory areas%@NL@% ■ Hook interrupts%@NL@% ■ Hook I/O ports%@NL@% ■ Specify instance data%@NL@% ■ Initialize themselves%@NL@% The System VM's Control Block should be set up with the inital state of the VxD. Since the System VM has already been created, calls such as Simulate_Int or Exec_Int is allowed. %@NL@% %@4@%%@AB@%Phase 3. Init_Complete%@AE@%%@EH@%%@NL@% This is the final phase of %@AB@%Device_Init%@AE@% that is called just before the WIN386 INIT pages are released and the instance snapshot is taken. VxDs that want to search for a region of V86 memory to use should do so during this phase. Most devices, though, will not need to do anything here. %@NL@% %@2@%%@CR:C6A00170043 @%%@AB@%17.4 Tracking the VM States%@AE@%%@EH@%%@NL@% Most likely, the VxD that you are writing needs to keep track of the status of the different VMs that may need your VxD. This includes VM creation, initialization, and termination. The following subsections describe these and other possible VM states.%@CR:C6A00170044 @%%@NL@% %@3@%%@CR:C6A00170045 @%%@AB@%17.4.1 VM Creation and Initialization%@AE@%%@EH@%%@NL@% Like the initialization of the enhanced Windows environment, a VM's go through a multi-phase initialization process.%@CR:C6A00170046 @%%@NL@% %@4@%%@AB@%Phase 1. Create_VM%@AE@%%@EH@%%@NL@% This call creates a new VM. %@AB@%EBX%@AE@% = VM handle of the new VM. Returning Carry will fail the %@AB@%Create_VM%@AE@%. VxDs should initialize data associated with the VM, especially the control block. %@NL@% %@4@%%@AB@%Phase 2. VM_Critical_Init%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle of the new VM. Returning Carry will cause the VM to %@AB@%VM_Not_Executeable%@AE@%, then be destroyed (see Section 17.4.3). VM %@AB@%Simulate_Int%@AE@% or %@AB@%Exec_Int%@AE@% activity is not allowed. %@NL@% %@4@%%@AB@%Phase 3. VM_Init and Sys_VM_Init%@AE@%%@EH@%%@NL@% The VxD interacts with the VM in order to initialize the state of the software in the VM (e.g., the VDD does an INT 10H to set the initial display mode. %@NL@% System VM initialization is the same as other VM initializations except its Phase 1 and 2 are done at Device_Init and if Carry is returned, all of enhanced Windows will exit. %@NL@% %@3@%%@CR:C6A00170047 @%%@AB@%17.4.2 VM State Changes%@AE@%%@EH@%%@NL@% During the normal execution of enhanced Windows, VMs will go through state changes. Most state changes may be ignored by VxDs. However, depending on the purpose of the VxD, some may require VxD response. The following calls describe the possible VM state changes. %@NL@% %@4@%%@AB@%VM_Suspend%@AE@%%@EH@%%@NL@% The VM is not runnable until a resume. %@AB@%EBX%@AE@% = VM handle. The call cannot be failed. The VxD should unlock any resources associated with the VM. %@NL@% The VM_Suspend message is sent only once each time the VM is suspended. Note that there is a bit the the control block CB_VM_Status flags indicating the current state. See VMM.INC for details. %@NL@% %@4@%%@AB@%VM_Resume%@AE@%%@EH@%%@NL@% The VM is leaving a suspended state. %@AB@%EBX%@AE@% = VM handle. Returning a carry fails and backs out of the resume. Lock any resources and otherwise prepare internal data structures for the VM to start running again. %@NL@% The VM_Resume message is sent only once after a VM_Suspend message has been sent. %@NL@% %@4@%%@AB@%Set_Device_Focus%@AE@%%@EH@%%@NL@% This sets the focus of the specified VxD to the specified VM. %@AB@%EBX%@AE@% = VM handle of desired VM. %@AB@%EDX%@AE@% = VxD ID. For VxD specific set focus, %@AB@%EDX%@AE@% = 0 for device critical set focus (all devices). %@NL@% This call cannot be failed. Restore the hardware associated with the device to the state of the specified VM. As much as possible, remove VxD interaction with VM (such as disabling I/O trapping) so that VM can run as fast as possible. %@NL@% %@4@%%@AB@%Begin_Message_Mode%@AE@%%@EH@%%@NL@% This call prepares the device for message processing. This is only of interest to the keyboard, mouse, and display. When in message mode, special services provided by the display and keyboard are used to interact with the user. Message mode is used for the ALT+TAB screen and for message boxes when Windows is not available to process a message box. EBX = VM handle going into message mode. This call cannot be failed. %@NL@% %@4@%%@AB@%End_Message_Mode%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle leaving message mode. This call cannot be failed. %@NL@% %@4@%%@AB@%Reboot_Processor%@AE@%%@EH@%%@NL@% This call requests a machine reboot. The device (usually the keyboard device) that knows how to reboot the machine does the necessary operations. %@NL@% %@4@%%@AB@%Query_Destroy%@AE@%%@EH@%%@NL@% This call asks if it can destroy the running VM. %@AB@%Query_Destroy%@AE@% is an information call made by the Shell device before an attempt is made to initiate a destroy VM sequence on a running VM that has not exited normally. %@AB@%EBX%@AE@% = VM handle. Returning Carry indicates that a VxD has a problem with allowing this. It is recommended that the VxD returning the Carry indicating a problem call %@AB@%SHELL_Message%@AE@% to post an informational dialog about the reason for the problem. %@NL@% %@4@%%@AB@%Debug_Query%@AE@%%@EH@%%@NL@% %@AB@%Debug_Query%@AE@% is a special call for device-specific DEBUG information display and activity. This call is made in response to the user typing a period followed by the VxD name in response to the WDEB386 prompt. The VxD name is declared with the %@AB@%Declare_Virtual_Device%@AE@% macro (see Section 17.1.3, "VxD Declaration"). Use conditional assembly to remove this call from the final VxD. %@NL@% %@3@%%@CR:C6A00170048 @%%@AB@%17.4.3 VM Termination%@AE@%%@EH@%%@NL@% Graceful termination of a VM occurs in the following three steps:%@CR:C6A00170049 @%%@NL@% %@4@%%@AB@%Phase 1. VM_Terminate%@AE@%%@EH@%%@NL@% During this phase of normal VM termination. %@AB@%EBX%@AE@% = VM handle. Call cannot be failed. VM %@AB@%Simulate_Int%@AE@% and %@AB@%Exec_Int%@AE@% activity is allowed. %@NL@% %@4@%%@AB@%Sys_VM_Terminate%@AE@%%@EH@%%@NL@% Same as %@AB@%VM_Terminate%@AE@%, except terminates the System VM. System VM %@AB@%Simulate_Int%@AE@%, %@AB@%Exec_Int%@AE@% activity is allowed. System VM will always be the last VM terminated, and thereby indicates that enhanced Windows is terminating. This call is only made during a normal exit, during a crash exit this call is not made. %@NL@% %@4@%%@AB@%Phase 2. VM_Not_Executeable%@AE@%%@EH@%%@NL@% During the second phase of VM termination. %@AB@%EBX%@AE@% = VM handle, %@AB@%EDX%@AE@% = Flags (see VMM.INC). Notice that in the case of destroying a running VM, this is the first call made (i.e., the %@AB@%VM_Terminate%@AE@% call does not occur). Call cannot be failed. VM %@AB@%Simulate_Int%@AE@% and %@AB@%Exec_Int%@AE@% activity is %@AI@%not%@AE@% allowed. Flags for %@AB@%VM_Not_Executeable%@AE@% control call (passed in %@AB@%EDX%@AE@%) are as follows: %@NL@% %@TH: 7 501 02 22 54 @%Flag Meaning%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%%@AB@%VNE_Crashed%@AE@% VM has crashed.%@AB@%VNE_Nuked%@AE@% VM was destroyed while active.%@AB@%VNE_CreateFail%@AE@% Some device failed %@AB@%Create_VM%@AE@%.%@AB@%VNE_CrInitFail%@AE@% Some device failed %@AB@%VM_Critical_Init%@AE@%.%@AB@%VNE_InitFail%@AE@% Some device failed %@AB@%VM_Init%@AE@%.%@TE: 7 501 02 22 54 @% %@4@%%@AB@%Phase 3. Destroy_VM%@AE@%%@EH@%%@NL@% During this final phase of VM termination. %@AB@%EBX%@AE@% = VM handle. Notice that considerable time can elapse between the %@AB@%VM_Not_Executeable%@AE@% call and this call. Call cannot be failed. VM %@AB@%Simulate_Int%@AE@% and %@AB@%Exec_Int%@AE@% activity is not allowed. %@NL@% %@2@%%@CR:C6A00170050 @%%@AB@%17.5 Exiting Windows%@AE@%%@EH@%%@NL@% There are two calls that can alert a VxD that enhanced Windows is exiting: %@AB@%System_Exit%@AE@% and %@AB@%Sys_Critical_Exit%@AE@%. They both come after %@AB@%Sys_VM_Terminate%@AE@%, is Windows is exiting normally. %@NL@% %@4@%%@AB@%System_Exit%@AE@%%@EH@%%@NL@% This call is made when Windows is exiting either normally or via a crash. Interrupts are enabled. System VM %@AB@%Simulate_Int%@AE@% and %@AB@%Exec_Int%@AE@% activity is not allowed. However, the VxD may modify the System VM memory to restore the system state to allow a graceful exiting of Windows. %@NL@% %@4@%%@AB@%Sys_Critical_Exit%@AE@%%@EH@%%@NL@% This call is made when enhanced Windows is exiting either normally or via a crash. Interrupts are disabled. %@AB@%Simulate_Int%@AE@% and %@AB@%Exec_Int%@AE@% activity is not allowed. VxDs should reset their associated hardware to a quiescent state to allow a graceful return to real mode. %@NL@% %@2@%%@CR:C6A00170051 @%%@AB@%17.6 Debugging a VxD%@AE@%%@EH@%%@NL@% Their are a number of features built into the WDEB386 debugger and the debugging version of the 386 enhanced mode environment to aid you in debugging your VxD. These features require a terminal hooked up to a COM port, as described in the WDEB386 documentation in the Microsoft SDK. When making use of these features in your code, be sure to remove them from your final product. See DEBUG.INC for useful macros and the sample source for usage. %@NL@% %@3@%%@CR:C6A00170052 @%%@AB@%17.6.1 Entering WDEB386%@AE@%%@EH@%%@NL@% There are four ways to initially enter the debugger: %@NL@% 1. Type CTL+ALT+SYSREQ.%@NL@% 2. Generate a non-maskable interrupt (this can be disabled with the "V2" command).%@NL@% 3. Place an "INT 1" instruction in your code. This method should be used when debugging the real-mode portion of your VxD. An "INT 3" may also be used but the debugger will not automatically pass over it. %@NL@% 4. Specify "\b" as a command line parameter to WDEB386. This will pass control to the debugger just prior to VMM initialization, after all VxDs have been loaded and the processor is running in protected mode.%@NL@% %@3@%%@CR:C6A00170053 @%%@AB@%17.6.2 Tracing Paths of Execution%@AE@%%@EH@%%@NL@% You can dump strings of text and registers in hexadecimal to the debug terminal utilizing the %@AB@%TRACE_OUT%@AE@% and %@AB@%DEBUG_OUT%@AE@% macros. %@NL@% The %@AB@%Queue_out%@AE@% macro allows you to dump the same information to a trace queue. You can also send VMM entry and exit information to the queue by using the ".t" command, and send procedure logging information with the .VMM command. %@NL@% %@AB@%Trace_Out%@AE@% and %@AB@%Debug_Out%@AE@% strings have the following special characters defined: %@NL@% %@AS@% #<register>, where %@AS@% <register> is a 32 bit register, a 16 bit register %@AS@% or AL, BL, CL or DL. This will insert the hex value for %@AS@% the indicated register into the string that is output at %@AS@% the location where #<register> appears. %@AS@% ?[<16 bit register>:]<32 bit register>, where the 16 bit register is %@AS@% a selector and the 32 bit register is an offset within %@AS@% that selector. If the 16 bit register is not specified, %@AS@% then 28h, the VxD code segment, is assumed. This will insert %@AS@% the symbol table name of the closest previous symbol %@AS@% corresponding to the address specified. If no symbol is %@AS@% found, nothing is printed (e.g. ?AX:EBX).%@AE@% Additionally, a VxD can put data into the trace queue that is listed with the .LQ command. To do this use the %@AB@%Queue_Out%@AE@% macro: %@NL@% %@AS@% Queue_Out "<string>"[,<reg1>[,<reg2>»%@AE@% where reg1 and reg2 are 32-bit registers. Reg1 will be in the %@AB@%EAX%@AE@% register when the string is printed and Reg2 will be in the %@AB@%EBX%@AE@% register. You can use the special "#" and "?" characters in the string, identifying %@AB@%EAX%@AE@% (or a subset of E%@AB@%AX%@AE@%) and %@AB@%EBX%@AE@% (or a subset) to insert the values of reg1 and reg2 in the string. By default, reg1=%@AB@%EAX%@AE@% and reg2=%@AB@%EBX%@AE@%. The default is used if you do not specify the parameters to the macro. %@NL@% %@3@%%@CR:C6A00170054 @%%@AB@%17.6.3 Querying the VxD State%@AE@%%@EH@%%@NL@% As described previously, one of the messages sent to the %@AB@%VxD_Control%@AE@% routine is %@AB@%Debug_Query%@AE@%. This message is passed when you type ". name" to WDEB386. See the sample sources for examples on how to use trace-out and the %@AB@%In_Debug_Chr%@AE@% service to generate useful debugging information. %@NL@% The .VMM command will give you a menu of useful information on the state of the system as well as a way to toggle procedure logging. %@NL@% %@CR:C6A00180001 @%%@1@%%@AB@%Chapter 18 The VDD and Grabber DLL%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% This chapter describes the Virtual Display Device (VDD) and the Grabber DLL, a Microsoft Windows dynamic-link library. Software writers should be familiar with the terms and concepts covered in Chapter 16, "Overview of Windows in 386 Enhanced Mode," and Chapter 17, "Virtual Device Programming Topics," before continuing with this chapter. %@NL@% The topics in this chapter are presented in the following order: %@NL@% ■ Introduction to VDDs and the Grabber DLL%@NL@% ■ VDD programming and the Grabber API%@NL@% ■ Grabber DLL interfaces %@NL@% %@2@%%@CR:C6A00180002 @%%@AB@%18.1 Introduction to VDDs and the Grabber DLL%@AE@%%@EH@%%@NL@% The VDD and Grabber DLL are used by Windows when running in enhanced mode to support a video adapter. The %@AI@%VDD%@AE@% is the virtual device that emulates display hardware for applications running in virtual machines. The %@AI@%Grabber%@AE@%, like all dynamic-link libraries, provides a library of routines available to application programs. In this case, the application is the Windows WINOLDAP program, and the routines are used primarily for rendering the video display of a non-Windows application into a format that Windows can use. %@NL@% The Windows 3.0 DDK provides source code for a variety of VDDs and Grabbers. These should prove valuable as stubs and examples. %@NL@% %@3@%%@CR:C6A00180003 @%%@AB@%18.1.1 VDD Interaction with WINOLDAP%@AE@%%@EH@%%@NL@% When Windows detects the user starting a non-Windows application, it runs the Windows program called WINOLDAP and passes the name of the application to it. WINOLDAP searches for a .PIF file and, then, makes a call to the Shell device with all the parameters necessary to execute the application in a new VM. The Shell makes a series of system control calls with the appropriate messages to create and start the VM. It also calls the %@AB@%VDD_PIF_State%@AE@% and %@AB@%VDD_Set_VM_Type%@AE@% services to let the VDD know the user preferences for this VM. %@NL@% WINOLDAP also loads the Grabber DLL, which it uses for rendering the VM's display into the Windows display driver's bitmap format. The rendering is done both for a full screen grab into the Clipboard (the VDD's grab routine is called when this is done), and for displaying the VM in a window. This rendering occurs in response to changes in video state caused by either the VM's application or the user. %@NL@% %@TH: 29 1667 02 27 27 27 @%Cause of video state change Example Effect%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%Application Program Updating displayed VDD sends WINOLDAP a information screen update message. WINOLDAP calls the Grabber to update the window. Grabber calls the VDD to render the video state into the application's window.User Action Resizing a window Windows sends WINOLDAP a paint message. WINOLDAP calls the Grabber to paint the window. Grabber calls the VDD to render the video state into the application's window.%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%%@TE: 29 1667 02 27 27 27 @% Notice that the Grabber can be reentered. WINOLDAP may be in the process of handling a paint message when it receives an update message. Care must be exercised to ensure the correct handling of all the possible cases. %@NL@% %@3@%%@CR:C6A00180004 @%%@AB@%18.1.2 VDD User Messages%@AE@%%@EH@%%@NL@% When the VDD encounters a situation that requires a user's choice or interaction, it uses the Shell message services to print messages. For example, when there is not enough memory to save and restore a VM's video state, the user is informed of the problem and that a portion of the display may be lost. %@NL@% Messages are sent while in %@AI@%message mode%@AE@%, which is instigated with the %@AB@%Begin_Message_Mode%@AE@% control call. Message mode enables the Shell device to use the VDD message services to output text to the screen without changing the VM's video state. When the message is complete, an %@AB@%End_Message_Mode%@AE@% control call is made that restores the focus VM to the hardware. See Section 18.2.3, "Environment State Change Requirements for a VDD," for a description of the message mode services.%@CR:C6A00180005 @%%@AI@% %@AE@%%@NL@% %@3@%%@CR:C6A00180006 @%%@AB@%18.1.3 VDD I/O Trapping and Hooked Pages%@AE@%%@EH@%%@NL@% When an application is running in the background, the VDD traps all the video I/O, saving the output port values and emulating the input port values. In some cases, the detection of a mode change can result. In this case, the memory should be disabled and hooked to enable the page fault service to remap the memory. %@NL@% A VDD should detect mode changes and illegal memory accesses. This is done by disabling and hooking page faults that occur when the video memory is accessed by the VM. The page fault service determines how to map the accessed memory by both determining whether or not the VM has the display focus and by examining the VM's virtual controller state. The page fault service can also be used to demand page the video memory. It restores and maps the video pages needed to create the physical display and to satisfy the application's video memory accesses. %@NL@% %@3@%%@CR:C6A00180007 @%%@AB@%18.1.4 Grabber Naming Conventions%@AE@%%@EH@%%@NL@% The names of the various supplied grabbers indicate in which mode they are designed to run. For real and standard mode Windows, grabbers are named %@AI@%FOO.GR2%@AE@%. For 386 enhanced mode Windows, they are named %@AI@%FOO.GR3. %@AE@%%@NL@% %@2@%%@CR:C6A00180008 @%%@AB@%18.2 VDD Programming%@AE@%%@EH@%%@NL@% In addition to Chapter 17, "Virtual Device Programming Topics," which discusses the general requirements for writing a VxD, valuable information for the VDD author is located in Chapter 35, "Virtual Display Device (VDD) Services." %@NL@% The following are the recommended steps for developing a VDD: %@NL@% 1. Build a skeleton. Using the supplied sources as a guide, build a skeleton of the VDD with all the services and API procedures defined but not functional.%@NL@% 2. Add the initialization functionality, including the control block allocation, global memory needed, physical page hooking, I/O hooking, and interrupt hooking.%@NL@% 3. Fill out the services that handle the various hooks.%@NL@% 4. Test it while running Windows and other VMs, full screen.%@NL@% 5. Implement the Grabber API, including the procedures that report controller state, return video memory structures, and report video state modifications.%@NL@% 6. Test it while running VMs in a window. Do a thorough test, running many different applications in all the different states (i.e., exclusive, background, and windowed), while using ALT+TAB and directed hot keys to switch VMs. Be sure to test various error conditions such as being out of memory.%@AI@%%@AE@%%@NL@% %@3@%%@CR:C6A00180009 @%%@AB@%18.2.1 VDD Efficiency%@AE@%%@EH@%%@NL@% To maximize the efficiency of Windows, a VDD is, in many cases, tightly coupled with the Windows 3.0 display driver. For instance, the EGA display would normally have to be trapped at all times to maintain the controller state properly. Instead, an API has been defined for communications between the Windows display driver and the VDD. Additionally, the EGA Windows display driver uses a special portion of video memory and a special algorithm that allows for a subset of the video controller state to be saved and restored without explicitly saving away the current register values. When adapting a VDD to new displays, it is a good idea to look at alternatives to trapping all the display adapter access to maintain the video state. Notice also that the Grabber is usually tightly coupled to the Windows display driver, specifically to the display-dependent bitmap format. %@NL@% There are three PIF bits that the user can specify to disable trapping in VMs where the applications running in the VMs only modify registers that can be read. The VDD designer should use these PIF bits, if possible. There are additional PIF bits by which the user can specify the amount of video memory a VM will need. See the %@AI@%Microsoft Windows User's Guide%@AE@% for more information on PIF files. %@NL@% Another good area in which to consider optimizing is the API emulation, especially the INT 10H %@AB@%Write TTY%@AE@% function. The user can specify this emulation with a PIF bit. %@NL@% %@3@%%@CR:C6A00180010 @%%@AB@%18.2.2 Converting Your 2.x VDD%@AE@%%@EH@%%@NL@% Even though the general structure of Windows 3.0 VxDs is significantly different from 2.x versions, the low-level VDD routines of previous versions, such as the saving, restoring, and trapping routines, should work with little modification. However, significant changes have occured in how VxDs interact with the operating environment. For example, the VDD is now a separate .386 file linked dynamically to 386 enhanced mode Windows. Therefore, a recommended development strategy is to insert the 2.x routines into one of the supplied 3.0 VDD sources. %@NL@% The 3.0 Grabber's interface with WINOLDAP and the VDD is also different. The most significant change is that in version 2.x the Grabber was not a DLL. See Section 18.3, "Grabber DLL Interfaces," for more detailed information. %@NL@% The following topics describe areas of a 2.x VDD that will require modification. %@NL@% %@4@%%@AB@%INCLUDE Files%@AE@%%@EH@%%@NL@% Most of the modules only need VMM.INC, VDD.INC, DEBUG.INC, and a device specific INCLUDE file (e.g., EGA.INC). Some modules also require a file describing the interface between them and some external user of their functions (e.g., VMDAEGA.INC for the Grabber). By changing over to the new INCLUDE files, you will generate several undefined references. Modifying the references to use the equivalent Windows 3.0 functionality is a first step in creating your Windows 3.0 VDD. %@NL@% %@4@%%@AB@%System Interface%@AE@%%@EH@%%@NL@% Examine the parts of the supplied Windows 3.0 VDD to understand the new system interface. You will need the %@AB@%VDD_Init%@AE@%, %@AB@%VDD_New%@AE@%, %@AB@%VDD_Exit%@AE@%, %@AB@%VDD_Destroy%@AE@%, %@AB@%VDD_SetType%@AE@%, and %@AB@%VDD_SetFocus%@AE@% services to use the new device control interface. The functionality of %@AB@%VDD_Install%@AE@% should be handled by scheduling VM events. The %@AB@%VDD_Mem_Check%@AE@% service is replaced by the VDD specifically calling the Shell to give the user a message. %@AB@%VDD_CHK_Device%@AE@% is also replaced by sending WINOLDAP a message when the display needs to be updated and by scheduling time outs to do the detection. The register values and what you can and cannot do in an I/O trap, page fault, and interrupt trap are also changed. Mostly, there is much more flexibility allowed, and there are changes in register save/restore and parameter passing conventions. %@NL@% Previously, VDD provided a single %@AB@%VDD_Control%@AE@% with various subfunctions. Most of the %@AB@%VDD_Control%@AE@% calls are replaced by the device API mechanism. %@NL@% Notice that the definition of %@AI@%exclusive%@AE@% is different for Windows 3.0 and that the %@AB@%SetFocus%@AE@% service takes into account whether or not the VM is running in a window (i.e., VDD will get a %@AB@%SetFocus%@AE@% call for the System VM on a VM that is running in a window, instead of a %@AB@%SetFocus%@AE@% call to the VM itself). %@NL@% %@4@%%@AB@%Shell%@AE@%%@EH@%%@NL@% The Shell device requires a number of new functions that are implemented as device services. Additionally, the old ID call is device service 0. %@NL@% %@4@%%@AB@%Grabber%@AE@%%@EH@%%@NL@% Notice that the way that the services retrieve the Grabber DLL's registers is different (i.e., by using %@AB@%EBP%@AE@% and the %@AB@%Client_Reg%@AE@% definitions). Also notice the increased number of functions and other changes in the functionality of the Grabber DLL interface. %@NL@% %@4@%%@AB@%Memory Access%@AE@%%@EH@%%@NL@% Use the %@AB@%_MapPhysToLinear%@AE@% function rather than adding %@AB@%PhysToLinr%@AE@% to the physical addresses. You should also add the control block value %@AB@%CB_High_Linear%@AE@% to the BIOS memory address for accessing those memory locations. %@NL@% Since memory in the control block is allocated dynamically, the address of your portion of the control block must be formed at run time, not compile time. %@NL@% %@3@%%@CR:C6A00180011 @%%@AB@%18.2.3 Environment State Change Requirements for a VDD%@AE@%%@EH@%%@NL@% During Windows initialization, VM creation and termination, and other status changes of the Windows environment, there are certain programming requirements for display devices. The following includes descriptions of typical requirements for various states. Use the EGA/VGA and CGA sources as examples. Specific interfaces to the described routines are included in Section 17.1, "Writing VxDs." %@NL@% %@4@%%@AB@%Real Mode Initialization%@AB@%%@AE@%%@AE@%%@EH@%%@NL@% Most video adapters will not need any real-mode code to be functional. However, a few developers will want to add some real-mode code to query device state or to reserve portions of memory that may not be touched during the initialization of other devices or used for general system purposes. For example, you may have a memory-mapped interface that will be harmed by other code reading and writing at those addresses (Windows in 386 enhanced mode searches the area between C0000H and EFFFFH for the existence of RAM or ROM). If the VDD supports multiple display adapters, display-adapter detection can be done here by passing the result of the detection in the %@AB@%EDX%@AE@% register to the protected-mode initialization. %@NL@% %@4@%%@AB@%Sys_Critical_Init%@AE@%%@EH@%%@NL@% During %@AB@%Sys_Critical_Init%@AE@%, a VDD should allocate its control block data area, allocate V86 address space, allocate memory needed globally, and initialize any pointers or other data that are required for the VDD functionality. Remember that interrupts are disabled during this call, so keep it as short as possible. %@NL@% %@4@%%@AB@%Device_Init%@AE@%%@EH@%%@NL@% During %@AB@%Device_Init%@AE@%, a VDD should finish initializing its global state, set up the I/O and interrupt trapping needed, and specify instance data. As noted in Chapter 16, "Overview of Windows in 386 Enhanced Mode," this initialization call is equivalent to %@AB@%VMCreate%@AE@% for the System VM, along with the global device initialization. Finally, the VDD should set the display focus to the system VM internally. %@NL@% %@4@%%@AB@%Init_Complete%@AE@%%@EH@%%@NL@% During %@AB@%Init_Complete%@AE@%, a VDD should do any consistency checks that have to be done after all the other devices have completed their initialization. Normally, a VDD will not need to do anything with this control call. %@NL@% %@4@%%@AB@%Sys_VM_Init%@AE@%%@EH@%%@NL@% During %@AB@%Sys_VM_Init%@AE@%, a VDD should initialize the rest of the control block data for the system VM, and set the display focus to the system VM. %@NL@% %@4@%%@AB@%VM_Create%@AE@%%@EH@%%@NL@% During creation, initialize the control block and allocate any VM specific memory. If the allocation fails, return the Carry flag set to abort the VM creation. %@NL@% %@4@%%@AB@%VM_Init%@AE@%%@EH@%%@NL@% During initialization, set the video state of the VM, typically by making calls to the Video BIOS and trapping the I/O to set up the video state structure. %@NL@% %@4@%%@AB@%Destroy_VM%@AE@%%@EH@%%@NL@% During destruction, deallocate any memory allocated for the VM and make sure that there are no pointers left that refer to the destroyed VM. %@NL@% %@4@%%@AB@%Set_Device_Focus%@AE@%%@EH@%%@NL@% The %@AB@%SetFocus%@AE@% service is responsible for giving the specified VM the physical display. Notice that there is display %@AB@%SetFocus%@AE@% and critical %@AB@%SetFocus%@AE@%. Both should give the physical display to the indicated VM. Also notice that the actual restoring of the physical display should occur by executing the %@AB@%VDD_Restore%@AE@% service as an event. %@NL@% %@4@%%@AB@%VM_Suspend%@AE@%%@EH@%%@NL@% During %@AB@%VM_Suspend%@AE@%, a VDD should unlock any memory associated with the VM, such as the memory used to save and restore the video state. %@NL@% %@4@%%@AB@%VM_Resume%@AE@%%@EH@%%@NL@% During %@AB@%VM_Resume%@AE@%, a VDD should lock the memory unlocked during suspend. %@NL@% %@4@%%@AB@%System_Exit%@AE@%%@EH@%%@NL@% During %@AB@%System_Exit%@AE@%, a VDD should return the display to the state it should be in when Windows returns to MS-DOS. %@NL@% %@4@%%@AB@%Sys_Critical_Exit%@AE@%%@EH@%%@NL@% During %@AB@%Sys_Critical_Exit%@AE@%, a VDD should restore any hooks remaining in the V86 memory. %@NL@% %@4@%%@AB@%Begin_Message_Mode%@AE@%%@EH@%%@NL@% After saving the current VM's video state, the VDD should put the display adapter into a known text mode. If this is called prior to the point in initialization (System VM Initialization) at which a known text mode has been saved, call the video BIOS to set up the correct mode. %@NL@% The message mode services, %@AB@%VDD_Msg_ClrScrn%@AE@%, %@AB@%VDD_Msg_ForColor%@AE@%, %@AB@%VDD_Msg_BakColor%@AE@%, %@AB@%VDD_Msg_TextOut%@AE@%, and %@AB@%VDD_Msg_SetCursPos%@AE@% are only used after the %@AB@%Begin_Message_Mode%@AE@% message has been received. See Chapter 35, "Virtual Display Device (VDD) Services," for details. %@NL@% %@4@%%@AB@%End_Message_Mode%@AE@%%@EH@%%@NL@% During %@AB@%End_Message_Mode%@AE@%, a VDD should restore the focus VM's video state. %@NL@% %@4@%%@AB@%Debug_Query%@AE@%%@EH@%%@NL@% In a debug version of your VDD, use the %@AB@%Trace_Out%@AE@% macro to list the current display owner, other potentially interesting global data, and the video state for each VM. %@NL@% %@3@%%@CR:C6A00180012 @%%@AB@%18.2.4 Grabber API%@AE@%%@EH@%%@NL@% The Grabber uses the VDD's %@AB@%Get_Version%@AE@% service to verify that it is matched with the correct VDD. Whenever the Grabber needs access to the video memory or the video controller state, it queries the VDD. The VDD returns a data structure describing the requested memory or controller state. %@NL@% %@AB@%Get_Mem%@AE@% is used to get the current contents of the video memory while updating the windowed display. %@AB@%Get_GrbMem%@AE@% is used to get a snapshot of the entire screen in response to an ALT + PRTSCN command from the user in a full screen VM. %@AB@%Free_Mem%@AE@% and %@AB@%Free_Grab%@AE@% are used to tell the VDD that the grabber is no longer using this memory. %@AB@%Get_State%@AE@% and %@AB@%Get_GrbState%@AE@% return the current and grabbed controller states, respectively. %@NL@% %@AB@%Get_Mod%@AE@% is used to update the windowed display incrementally. %@AB@%Get_Mod%@AE@% returns a data structure that indicates modifications to the current display. The Grabber DLL modifies only those parts of the window that have changed and, then, issues a %@AB@%Clear_Mod%@AE@% call to inform the VDD that the modifications have been carried out. %@NL@% To make sure that the video memory or state will not change when the Grabber is accessing the memory, the VM should not be running after a %@AB@%Get_Mem%@AE@% or %@AB@%Get_Mod%@AE@% call. The VM can continue to run only after a %@AB@%Free_Mem%@AE@% call or an explicit %@AB@%Unlock_App%@AE@% call from the Grabber. %@NL@% %@2@%%@CR:C6A00180013 @%%@AB@%18.3 Grabber DLL Interfaces%@AE@%%@EH@%%@NL@% The Grabber is a dynamic-link library (DLL) primarily responsible for representing the VM's display state to the Windows display driver. It is the library of functions used by WINOLDAP, the Windows program responsible for creating, destroying, and changing the state of VMs. WINOLDAP makes private calls to the Shell device, which in turn calls the necessary VMM services. Therefore, it is WINOLDAP, using the Grabber (and through it the Windows display driver), that is actually responsible for windowing the display state of a VM. %@NL@% Each of the Grabber functions is a %@AB@%cProc%@AE@% and has to be exported. The function code can be shared by several instances of WINOLDAP, and therefore, the placement of VM-specific data must be deliberate. The Grabber DLL functions provide support for the following: %@NL@% ■ Screen grabbing%@NL@% ■ Marking and selecting%@NL@% ■ Painting non-Windows applications in a window%@NL@% ■ Doing other miscellaneous functions%@NL@% The Grabber generates data in the following situations: %@NL@% ■ When an Extended Paint structure (EXTPAINTSTRUC) is passed from WINOLDAP%@NL@% ■ When a procedure requires local data. (Local data is maintained on the stack.)%@CR:C6A00180014 @%%@CR:C6A00180015 @%%@NL@% %@3@%%@CR:C6A00180016 @%%@AB@%18.3.1 On-Screen Selection Functions%@AE@%%@EH@%%@NL@% The user can make on-screen selections with either the keyboard or mouse, or through a hot key. The keyboard or mouse are used only while in a window; a hot key (ALT+PRTSCRN) is used while in full-screen or windowed mode. %@NL@% The functions that handle on-screen selections are as follows: %@NL@% ■ %@AB@%BeginSelection%@AE@%%@NL@% ■ %@AB@%EndSelection%@AE@%%@NL@% ■ %@AB@%KeySelection%@AE@%%@NL@% ■ %@AB@%AdjustInitEndPt%@AE@%%@NL@% ■ %@AB@%MakeSelctRect%@AE@%%@NL@% To perform a selection by using the keyboard, the user performs the following steps: %@NL@% 1. Choose the Mark command.%@NL@% 2. Move the cursor to the start point of the selection.%@NL@% 3. Sweep through a selection using SHIFT + DIRECTION keys.%@NL@% 4. Press ENTER to end a selection and copy it to the Clipboard (or press ESC to end the selection without a copy).%@NL@% On choosing Mark from the menu, %@AB@%BeginSelection%@AE@% gets called with argument <0,0>. %@NL@% During the first phase, the cursor is moved to the actual start point. %@AB@%KeySelection%@AE@% handles the cursor movement. It returns the new start point every time a DIRECTION key is pressed. Notice that the selection could potentially begin at each cursor position. Therefore, every time the start point is changed, %@AB@%EndSelection%@AE@% is called to cancel the previous selection, and %@AB@%BeginSelection%@AE@% is called with the new start point. %@NL@% Once the cursor is positioned at the actual start point, the user sweeps through a selection area using SHIFT+DIRECTION keys. %@AB@%KeySelection%@AE@% handles the cursor movement. It returns the new end point of the selection. Now each call to %@AB@%KeySelection%@AE@% is followed by a call to %@AB@%MakeSelctRect%@AE@% to record the current selection rectangle. On pressing ENTER, the actual end point and the final selection rectangle are established. %@NL@% Therefore, the last call to %@AB@%BeginSelection%@AE@% establishes the actual start point, the last call to %@AB@%KeySelection%@AE@% returns the actual end point, and the final call to %@AB@%MakeSelctRect%@AE@% records the actual selection rectangle. If only DIRECTION keys are pressed, the user is shifting the start point. If SHIFT+DIRECTION keys are pressed, the user is changing the active end point. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%The start point and the end point of a selection have to be aligned on %@AI@%character boundaries in text mode. In graphics mode, the Grabber chooses %@AI@%some granularity for cursor movement (e.g., DWORD of pixels).%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% The coordinates of the start point and the end point are given in screen coordinates ─ a window client area position corrected by the scroll bar position. Client area coordinate = <0,0> corresponds to the screen coordinate <ColOrg,RowOrg>. (ColOrg and RowOrg are available in the extended paint structure.) %@NL@% %@3@%%@CR:C6A00180017 @%%@AB@%18.3.2 Selection Functions%@AE@%%@EH@%%@NL@% This section presents descriptions of the selection functions in alphabetical order. %@NL@% %@CR:C6A00180018 @% %@2@%%@CR:C6A00180019 @%%@AB@%AdjustInitEndPt%@CR:C6A00180020 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This function adjusts the initial selection end point. To start off, the start point and the end point are the same. (This is how %@AB@%BeginSelection%@AE@% records them). On the first SHIFT + DIRECTION key call to %@AB@%KeySelection%@AE@%, notice that %@AB@%KeySelection%@AE@% returns the wrong end point. This function returns the correct end point. It returns (X+DELTAx, Y+DELTAy) where <X,Y > is the given end point. DELTAx and DELTAy are as defined in %@AB@%KeySelection%@AE@%. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% lpPntStruct = EXTPAINTSTRUC %@NL@% YCoOrd,XCoOrd = (Y,X) point to be adjusted %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%DX%@AE@%,%@AB@%AX%@AE@% = (Y,X) end point adjust down and to right for initial selection. %@NL@% %@CR:C6A00180021 @% %@2@%%@CR:C6A00180022 @%%@AB@%BeginSelection%@CR:C6A00180023 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This function starts the selection at the indicated point. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% lpPntStruc = EXTPAINTSTRUC %@NL@% YCoOrd,XCoOrd = (Y,X) screen coord of start pt %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% [lpPntStruc.SelStruc.SelctSRect] Display rectangle in the EXTPAINTSTRUC selection structure set %@NL@% %@CR:C6A00180024 @% %@2@%%@CR:C6A00180025 @%%@AB@%ConsSelecRec%@CR:C6A00180026 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This function makes the display rectangle consistent with the selection. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% lpPntStruc = EXTPAINTSTRUC %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% [lpPntStruc.SelStruc.SelctSRect] Display rectangle in the EXTPAINTSTRUC selection structure set %@NL@% %@CR:C6A00180027 @% %@2@%%@CR:C6A00180028 @%%@AB@%EndSelection%@CR:C6A00180029 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This function stops the selection. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% lpPntStruc = EXTPAINTSTRUC %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@CR:C6A00180030 @% %@2@%%@CR:C6A00180031 @%%@AB@%InvertSelection%@CR:C6A00180032 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This function inverts the selection. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% lpPntStruc = EXTPAINTSTRUC %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%DX%@AE@%,%@AB@%AX%@AE@% = (Y,X) screen CoOrd of "active" selection endpoint %@NL@% %@CR:C6A00180033 @% %@2@%%@CR:C6A00180034 @%%@AB@%KeySelection%@CR:C6A00180035 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This function is for keyboard selection. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% lpPntStruc = EXTPAINTSTRUC %@NL@% StartType = 0 if SHIFT key UP != 0 if SHIFT key DOWN %@NL@% %@TH: 11 479 01 34 42 @%%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%MFunc = 0 To Right = 1 To Left = 2 Down = 3 UpMFunc = 0 To Right = 1 To Left = 2 Down = 3 Up%@TE: 11 479 01 34 42 @% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%DX%@AE@%,%@AB@%AY%@AE@% = (Y,X) screen CoOrd of new select end pt %@NL@% KeySelection responds to DIRECTION keys and SHIFT+DIRECTION keys. %@NL@% DIRECTION key response: (SHIFT key UP) %@NL@% if (LEFT Key) return (X-DELTAx, Y) else if (RIGHT Key) return (X+DELTAx, Y) else if (DOWN Key) return (X, Y+DELTAy) else if (UP Key) return (X, Y-DELTAy); %@NL@% where <X,Y> is current end point. %@NL@% DELTAx DELTAy are the font width and height in text mode and some appropriate value in graphics mode. %@NL@% SHIFT+DIRECTION key response: %@NL@% Similar to above except <X,Y> is current end point. %@NL@% %@CR:C6A00180036 @% %@2@%%@CR:C6A00180037 @%%@AB@%MakeSelctRect%@CR:C6A00180038 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This function sets a new selection. It is called after every call to %@AB@%KeySelection%@AE@% in response to SHIFT+DIRECTION key. Given a new end point, it adjusts the new end point to be character-aligned in text mode (and on a convenient boundary in the video memory in graphics mode). It also adjusts for screen maxima. It sets the Selection rectangle based on the current start point and end point. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% lpPntStruc = EXTPAINTSTRUC %@NL@% YCoOrd,XCoOrd = (Y,X) screen CoOrd of new end point %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% [lpPntStruc.SelStruc.SelctSRect], Display rect in extended paint selection structure set %@NL@% %@AB@%AX%@AE@% == 0, if no change was made to selection parameters %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%[lpPntStruc.SelStruc.SelctSRect] must still be set in this case.%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@CR:C6A00180039 @% %@2@%%@CR:C6A00180040 @%%@AB@%RenderSelection%@CR:C6A00180041 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This function renders the selection into the Clipboard format. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% lpPntStruc = EXTPAINTSTRUC %@NL@% %@TH: 3 255 01 10 66 @%%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%wParam Parameter from VDD message (= -1 if VMDOSAPP originlParam Parameter from VDD message (=0 if VMDOSAPP origin) Event ID%@TE: 3 255 01 10 66 @% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% if (DX < 0) Error else if (DX = 0) No Selection else if (DX > 0) DX = format, (CF_OEMTEXT or CF_BITMAP) AX = Handle, (Memory Handle or Bitmap Handle) %@NL@% %@3@%%@AB@%18.4.1 Application Painting Function%@AE@%%@EH@%%@NL@% This section presents a description of the non-Windows application painting function. %@NL@% %@CR:C6A00180042 @% %@2@%%@CR:C6A00180043 @%%@AB@%GetDisplayUpd%@CR:C6A00180044 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This function calls the VDD to get a display update (if any) and stores it in the PAINT structure. %@NL@% It prevents any further changes from occurring in the application. The application restarts after a call to one of the following; %@AB@%UpdateScreen%@AE@%, %@AB@%PaintScreen%@AE@%, or %@AB@%GrbUnLockApp%@AE@%. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% lpPntStruc = EXTPAINTSTRUC %@NL@% %@TH: 3 256 01 10 66 @%%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%wParam Parameter from VDD message (= -1 if VMDOSAPP origin)lParam Parameter from VDD message (=0 if VMDOSAPP origin) Event ID%@TE: 3 256 01 10 66 @% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%AX%@AE@% = Display update flags (see grabpnt.inc for fDisp_ flags) %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% This call "locks" the application (prevents further changes from occuring). The application can be started again by a call to one of the following: %@NL@% ■ %@AB@%UpdateScreen%@AE@%%@NL@% ■ %@AB@%PaintScreen%@AE@%%@NL@% ■ %@AB@%GrgUnLockApp%@AE@%%@NL@% %@3@%%@AB@%18.4.1 Miscellaneous Functions%@AE@%%@EH@%%@NL@% This section presents descriptions of miscellaneous functions in alphabetical order. %@NL@% %@CR:C6A00180045 @% %@2@%%@CR:C6A00180046 @%%@AB@%CheckGRBVersion%@CR:C6A00180047 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This function checks out the VDD version. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% lpPntStruc = EXTPAINTSTRUC %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If (AX == 0) OK AX == 1 Version # error AX == 2 Display type mismatch (VDD and Grabber are not compatible) DX = Grabber Version number %@NL@% %@2@%%@CR:C6A00180048 @%%@AB@%CursorOff%@CR:C6A00180049 @%%@CR:C6A00180050 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This function destroys the cursor for an application. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% lpPntStruc = EXTPAINTSTRUC %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Caret destroyed %@NL@% %@2@%%@CR:C6A00180051 @%%@AB@%CursorOn%@CR:C6A00180052 @%%@CR:C6A00180053 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This function creates the cursor for an application if it has one. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% lpPntStruc = EXTPAINTSTRUC %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Caret created %@NL@% %@2@%%@CR:C6A00180054 @%%@AB@%CursorPosit%@CR:C6A00180055 @%%@CR:C6A00180056 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This function returns the position of the cursor on the display. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% lpPntStruc = EXTPAINTSTRUC %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%DX%@AE@%,%@AB@%AX%@AE@% = (Y,X) screen CoOrd of upper left of cursor %@NL@% = (-1,-1) if no cursor %@NL@% %@2@%%@CR:C6A00180057 @%%@AB@%GetFontList%@CR:C6A00180058 @%%@CR:C6A00180059 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This function returns a pointer to the list of extra fonts you want loaded. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% lpFontBuf -> Buffer for font info %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Font Buffer filled in %@NL@% %@CR:C6A00180060 @% %@2@%%@CR:C6A00180061 @%%@AB@%GrabComplete%@CR:C6A00180062 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This function signals that you are finished with the grab. This is called after the grab is complete. It is time to call the VDD and have it free the grab memory. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% lpPntStruc = EXTPAINTSTRUC %@NL@% %@TH: 3 248 01 12 64 @%%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%wParam %@AI@%%@AE@% Parameter from VDD message (= -1 if VMDOSAPP origin)lParam Parameter from VDD message EVENT ID%@TE: 3 248 01 12 64 @% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@2@%%@CR:C6A00180063 @%%@AB@%GrabEvent%@CR:C6A00180064 @%%@CR:C6A00180065 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This function provides a private channel of event communication between the VDD and the Grabber to perform a hot key screen grab. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% lpPntStruc Extended paint structure %@NL@% %@TH: 3 235 01 18 58 @%%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%wParam %@AI@%%@AE@% Parameter from VDD message lParam Parameter from VDD message EVENT ID%@TE: 3 235 01 18 58 @% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@CR:C6A00180066 @% %@2@%%@CR:C6A00180067 @%%@AB@%GrbUnLockApp%@CR:C6A00180068 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Descripton%@AE@%%@EH@%%@NL@% This function undoes the implied application lock of %@AB@%GetDisplayUpd%@AE@%. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% lpPntStruc = EXTPAINTSTRUC %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@2@%%@CR:C6A00180069 @%%@AB@%InitGrabber%@CR:C6A00180070 @%%@CR:C6A00180071 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This is the library initialization function. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%DI%@AE@% = Module handle of the library %@NL@% %@AB@%CX%@AE@% = Size of local heap (should be 0) %@NL@% %@AB@%DS%@AE@% = Seg addr of library data segment (isn't one) %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% AX == 0 Init Error AX != 0 OK %@NL@% %@2@%%@CR:C6A00180072 @%%@AB@%PaintScreen%@CR:C6A00180073 @%%@CR:C6A00180074 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This function paints the indicated region of the screen. %@NL@% This procedure paints the non-Windows application screen into a window. The origin of this is a Windows paint as opposed to a display update, which is handled at %@AB@%UpdateScreen%@AE@%. When a non-Windows application receives a Windows paint message, %@AB@%Paint Screen%@AE@% gets called. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% lpPntStruc = EXTPAINTSTRUC %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%AX%@AE@% != 0 Screen Painted %@NL@% %@AB@%AX%@AE@% == 0 Screen not painted, probably insufficient Windows memory problem %@NL@% %@2@%%@CR:C6A00180075 @%%@AB@%ScreenFree%@CR:C6A00180076 @%%@CR:C6A00180077 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This function frees anything associated with this application. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% lpPntStruc = EXTPAINTSTRUC %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Any allocated stuff associated with the application is freed. %@NL@% %@2@%%@CR:C6A00180078 @%%@AB@%SetPaintFnt%@CR:C6A00180079 @%%@CR:C6A00180080 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This function sets the font for painting in the extended paint structure so that WINOLDAP can compute the paint rectangle for use on %@AB@%PaintScreen%@AE@% calls. This is called right before a call to %@AB@%PaintScreen%@AE@%. It is also called right before a call to %@AB@%UpdateScreen%@AE@%. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% lpPntStruc = EXTPAINTSTRUC %@NL@% %@TH: 3 234 01 25 51 @%%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%lpWidFullScr Word pointer for width returnlpHeightFullScr Word pointer for height return%@TE: 3 234 01 25 51 @% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% FntHgt and FntWid values in EXTPAINTSTRUC set %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%Values are set to 0 if it is a graphics screen.%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% [lpWidFullScr] = Width of full screen in pix (Text or Graphics) %@NL@% [lpHeightFullScr] = Height of full screen in pix (Text or Graphics) %@NL@% %@AB@%DX%@AE@% is height of full screen in scan lines if Graphics, in text lines if Text. %@NL@% %@AB@%AX%@AE@% is width of full screen in pix if Graphics, in chars if Text. %@NL@% %@CR:C6A00180081 @% %@2@%%@CR:C6A00180082 @%%@AB@%UpdateScreen%@CR:C6A00180083 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This function updates changed portions of the screen. When a non-Windows application modifies the display on its own, %@AB@%UpdateScreen%@AE@% is called. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% lpPntStruc = EXTPAINTSTRUC %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%AX%@AE@% == 1 if Screen Paint, unless fGrbProb bit set in EPStatusFlags %@NL@% %@AB@%AX%@AE@% == 0 if Screen not painted, probably low Windows memory problem %@NL@% %@CR:C6A-Part 04 @%%@1@%%@AB@%PART IV Virtual Device Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% This part documents all the enhanced Windows virtual machine environment services. They are grouped by service type and presented in the order shown on the following page. %@NL@% See Chapter 16, "Overview of Windows in 386 Enhanced Mode," and Chapter 17, "Virtual Device Programming Topics," for general environment discussions. %@NL@% %@CR:C6A00190001 @%%@1@%%@AB@%Chapter 19 Memory Management Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% Enhanced Windows supplies a rich set of memory management services. Since many of the services are unnecessary for most VxD development, only a commonly used subset is listed in this introduction. However, all the memory management services are documented in either this chapter or in Chapter 40, "V86 Mode Memory Manager Device Services." %@NL@% See also Chapter 16, "Overview of Windows in 386 Enhanced Mode," and Chapter 17, "Virtual Device Programming Topics," for general environment discussions. Memory management is also discussed in the %@AI@%Microsoft Windows %@AI@%Software Development Kit, Programming Tools%@AE@% and in Chapter 6, "Network Support," in the %@AI@%Microsoft Windows Device Driver Adaptation Guide%@AE@%. %@NL@% The enhanced Windows environment uses a virtual memory scheme capable of overcoming the limits of actual physical memory. Though it may not be physically present, a virtual memory of 4 gigabytes is theoretically addressable. This is done by swapping (paging) code and data to and from RAM and a secondary storage device. Since VxDs reside within the 32-bit protected-mode portion of the environment, they can directly access all of the memory, but should only access memory whose address was obtained through the memory management services. %@NL@% Windows determines the amount of virtual memory actually available based on the total amount of physical memory on the system and the amount of disk space available. This can be changed (downward) by modifying the swap file size specified in the SYSTEM.INI file, or by running the SWAPFILE program (documented in the %@AI@%Microsoft Windows User Guide%@AE@%). %@NL@% The memory manager will continue to allocate physical memory until it has been used up. Then, it will begin moving 4-kilobyte pages of code and data from physical memory to disk to make additional physical memory available. Windows pages in 4-kilobyte blocks, rather than unequal-sized code and data segments. The swapped 4-kilobyte block may be only part of a given code or data segment, or it may cross over two or more code or data segments. %@NL@% This memory paging is transparent to a program. If an attempt is made to access a code or data segment of which some part has been paged out to disk, the 80386 issues a page fault interrupt. The memory manager then swaps other pages out of memory and restores the pages that the program needs. %@NL@% The Windows memory management services are presented in the following categories. The services listed comprise the commonly used subset. %@NL@% ■ System Data Object Management%@NL@% %@STUB@% Allocate_Device_CB_Area%@AB@%%@AE@%%@NL@% ■ Device V86 Page Management %@NL@% %@STUB@% Assign_Device_V86_Pages%@AB@%%@AE@%%@NL@% ■ GDT/LDT Management %@NL@% ■ System Heap Allocator %@NL@% %@STUB@% HeapAllocate%@AB@%%@AE@%%@NL@% %@STUB@% HeapFree%@AB@%%@AE@%%@NL@% ■ System Page Allocator %@NL@% %@STUB@% CopyPageTable%@AB@%%@AE@%%@NL@% %@STUB@% MapIntoV86%@AB@%%@AE@%%@NL@% %@STUB@% ModifyPageBits%@AB@%%@AE@%%@NL@% %@STUB@% PageAllocate%@AB@%%@AE@%%@NL@% %@STUB@% PageFree%@AB@%%@AE@%%@NL@% %@STUB@% PageLock%@AB@%%@AE@%%@NL@% %@STUB@% PageUnlock%@AB@%%@AE@%%@NL@% %@STUB@% PageGetAllocInfo%@AB@%%@AE@%%@NL@% %@STUB@% PhysIntoV86%@AB@%%@AE@%%@NL@% ■ Looking at Physical Device Memory in Protected Mode %@NL@% %@STUB@% MapPhysToLinear %@AB@%%@AE@%%@NL@% ■ Data Access Services%@NL@% %@STUB@% GetFirstV86Page%@AB@%%@AE@%%@NL@% ■ Special Services for Protected Mode APIs %@NL@% ■ Instance Data Management %@NL@% ■ Looking at V86 Address Space %@NL@% %@2@%%@CR:C6A00190002 @%%@AB@%19.1 System Data Object Management%@AE@%%@EH@%%@NL@% These services provide support for allocating special system areas. The two areas managed are the Control Block and the Global V86 Addressable Area. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%All of these calls use the USE32 C calling convention. The true name of the %@AI@%procedure has an underscore in front (i.e., %@AB@%Allocate_Device_CB_Area%@AE@%%@AI@% is %@AI@%actually %@AE@%%@AI@%%@AB@%_Allocate_Device_CB_Area%@AE@%%@AE@%%@AI@%), and the arguments are pushed right to %@AI@%left (unlike the PL/M calling convention used by Windows, which is left to %@AI@%right). The return value(s) is returned in C standard %@AE@%%@AI@%%@AB@%EDX:EAX%@AE@%%@AE@%%@AI@%. It is the %@AI@%responsibility of the caller%@AE@%%@AI@%to clear the arguments off the stack. Registers %@AI@%%@AE@%%@AI@%%@AB@%EAX%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%ECX%@AE@%%@AE@%%@AI@%, and %@AE@%%@AI@%%@AB@%EDX%@AE@%%@AE@%%@AI@% are changed by calls. Registers %@AE@%%@AI@%%@AB@%DS%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%ES%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@% %@AI@%%@AB@%FS%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%GS%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%EBP%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%EDI%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%ESI%@AE@%%@AE@%%@AI@%, and %@AE@%%@AI@%%@AB@%EBX%@AE@%%@AE@%%@AI@% are preserved. %@AI@%%@AE@%%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@CR:C6A00190003 @%%@CR:C6A00190004 @% %@2@%%@CR:C6A00190005 @%%@AB@%Allocate_Device_CB_Area%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned Allocate_Device_CB_Area(nBytes,flags) %@AS@% unsigned nBytes; %@AS@% unsigned flags;%@AE@% This call is used to allocate a region of the Control Block data structure to a particular device. Devices typically want some data that is "per VM". For example, a device which is virtualizing a particular set of I/O ports for the VM needs a place to store each VMs "instance" of the I/O port state. This is done by allocating a region of the VM Control Block large enough to hold a device specific data structure which contains the state. For example, if the device specific data structure looks like this: %@NL@% %@AS@% FooDeviceCB Struc %@AS@% FooDevReg1 db ? ; Dev I/O register 1 %@AS@% FooDevReg2 db ? ; Dev I/O register 2 %@AS@% FooDevReg3 db ? ; Dev I/O register 3 %@AS@% FooDevReg4 db ? ; Dev I/O register 4 %@AS@% FooDevState dd ? ; State flags for device %@AS@% FooDeviceCB Ends%@AE@% Space in the VM Control Block would be allocated like this: %@NL@% %@AS@% VxD_DATA_SEG %@AS@% FooDevCBOffset dd ? %@AS@% VxD_DATA_ENDS %@AS@% VxD_ICODE_SEG %@AS@% ; %@AS@% ; Allocate the Control Block space. This is in Foo's INIT routine %@AS@% ; %@AS@% VMMCall _Allocate_Device_CB_Area,<<SIZE FooDeviceCB>,0> %@AS@% or eax,eax %@AS@% jz short No_CB_Space_Error ; Probably FATAL error %@AS@% mov [FooDevCBOffset],eax %@AS@% %@AS@% VxD_ICODE_ENDS %@AS@% %@AS@% VxD_CODE_SEG %@AS@% ; %@AS@% ; In VxD procedures the Control Block pointer is passed %@AS@% ; in EBX the control block may be pointed to like this. %@AS@% ; %@AS@% mov edx,ebx %@AS@% add edx,[FooDevCBOffset] %@AS@% mov al,[edx.FooDevReg1] %@AS@% ... %@AS@% %@AS@% VxD_CODE_ENDS%@AE@% The %@AI@%nBytes%@AE@% parameter specifies the number of bytes of space to be allocated. There are currently no bits defined in the flags, this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns nonzero Control Block Offset of the block allocated if successful, returns zero if the space could not be allocated (This is probably a fatal error, it is up to the caller to decide what is to be done in this case). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% Control block Offsets returned from this call will be DWORD aligned. The %@AI@%nBytes%@AE@% parameter does not have to be a multiple of 4, but if it isn't, it will currently be rounded up to a multiple of 4. This may change in a later releases, so do no depending one rounding. %@NL@% The above code sample is not the only way to do things. There are many other ways the control block offset value can be used to access your devices specific region of the control block. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%This routine itself is in the init segment of enhanced Windows. It can %@AI@%therefore only be called during system initialization. Trying to call it %@AI@%after system initialization and the system INIT segment space has been %@AI@%reclaimed will result in a fatal page fault.%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% When Control Block regions are allocated they are initialized with value 0 in all bytes. When new VMs are created, all bytes of the Control Block are set to 0. %@NL@% %@CR:C6A00190006 @%%@CR:C6A00190007 @% %@2@%%@CR:C6A00190008 @%%@AB@%Allocate_Global_V86_Data_Area%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned Allocate_Global_V86_Data_Area(nBytes,flags) %@AS@% unsigned nBytes; %@AS@% unsigned flags;%@AE@% This call is used to allocate a region of the Global V86 Addressable Area to a particular device. This area is used for device specific objects which must also be addressable by the Virtual mode code running in the Virtual Machine. %@NL@% An example is a Virtual mode software interrupt which is trapped by the device and causes the return of a Virtual mode pointer to some data associated with the device. The data must be in the VM's V86 address space since a Virtual mode pointer to it is returned. In this case there is no reason for the interrupt hook code to also be in the Global V86 Addressable Area, that can all be in the protected mode device. %@NL@% The %@AI@%nBytes%@AE@% parameter specifies the number of bytes of space to be allocated. Current flags bits: %@NL@% %@AS@% GVDAWordAlign EQU 00000000000000000000000000000001B GVDADWordAlign EQU %@AS@%00000000000000000000000000000010B GVDAParaAlign EQU %@AS@%00000000000000000000000000000100B GVDAPageAlign EQU %@AS@%00000000000000000000000000001000B GVDAInstance EQU %@AS@%00000000000000000000000100000000B GVDAZeroInit EQU %@AS@%00000000000000000000001000000000B GVDAReclaim EQU %@AS@%00000000000000000000010000000000B%@AE@% All unused bits must be zero. %@AB@%GVDA%@AE@%xxxx%@AB@%Align%@AE@% bits specify the indicated alignment (WORD, DWORD, PARAGRAPH, PAGE) for the start of the block. If none are set, BYTE alignment is assumed. %@AB@%GVDAInstance%@AE@%, if set, indicates that the block is an item of VM instance data for which each different VM has its own private values. If %@AB@%GVDAInstance%@AE@% is clear, the block is global data and all VMs share the same value setting. %@AB@%GVDAZeroInit%@AE@%, if set, indicates that the block is to initialized with value 0 in all bytes of the block. If %@AB@%GVDAZeroInit%@AE@% is clear, the block will have random values in it. %@NL@% %@AB@%GVDAReclaim%@AE@% is only valid if %@AB@%GVDAPageAlign%@AE@% is set. IF %@AB@%GVDAReclaim%@AE@% is set, then the physical pages of the region should be "reclaimed" by the MMGR (memory manager) and placed on the free list, and the NUL page should be mapped in the region. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns nonzero linear address of the block allocated if successful, returns zero if the space could not be allocated. This is probably a fatal error; it is up to the caller to decide what is to be done in this case. %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% The Flag bit equates are defined by including VMM.INC. The equates should be used. %@NL@% For blocks allocated with %@AB@%GVDAInstance%@AE@% set, the %@AB@%AddInstanceItem%@AE@% call is made by this routine for you. %@NL@% Note the interaction with %@AB@%Allocate_Temp_V86_Data_Area%@AE@%. %@NL@% Specifying multiple %@AB@%GVDA%@AE@%xxxx%@AB@%Align%@AE@% bits will result in random behavior. At most ONE of these bits must be set. %@NL@% The returned linear address is a ring 0 linear address. It is up to the caller to convert this into a Virtual mode SEG:OFFSET form if that is needed. %@NL@% The linear addresses returned by this call will be %@NL@% Generally only data needs to be placed in these blocks, but code can be placed if desired. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AU@%WARNING%@AE@% You must be %@AI@%very careful%@AE@% if allocating two blocks, one for code which is %@AI@%not %@AI@%%@AE@% instanced, and one for data which %@AI@%is%@AE@% Instanced because you %@AI@%cannot%@AE@% assume that the two blocks will be within 64K of each other and thus addressable with the same segment register in virtual-80 mode. ────────────────────────────────────────────────────────────────────────────%@NL@% If the VxD desires the values of Instance fields allocated with this call to have a set initial value whenever a new VM is created, the field must be initialized with the desired values immediately after making this call. The contents of the instance blocks at the time VxD initialization is completed is what each new VM is created with. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%This routine itself is in the init segment of enhanced Windows. It can %@AI@%therefore only be called during system initialization. Trying to call it %@AI@%after system initialization and the system INIT segment space has been %@AI@%reclaimed will result in a fatal page fault.%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@3@%%@AB@%Special notes for GVDAPageAlign%@AE@%%@EH@%%@NL@% This type of allocation is intended to support Vxds which need a global page aligned piece of V86 address space where they can %@AB@%MapIntoV86%@AE@% data. The best example of such a VxD is the %@AB@%PageSwap%@AE@% device. %@NL@% The %@AI@%nBytes%@AE@% parameter should be a multiple of 4096 (page size). %@NL@% Note that this page is global but that %@AB@%MapIntoV86%@AE@%, %@AB@%PhysIntoV86%@AE@%, and %@AB@%LinMapIntoV86%@AE@% are calls which are local to a specific VM. This means that a VxD which wishes to globally change the mapping of this region must traverse the VM list with %@AB@%Get_Next_VM_Handle%@AE@% and perform the map in each VM individually. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AU@%WARNING%@AE@% Do not issue any of the map calls on this region before SYS_VM_Init device call time. Failure to follow this rule can cause the page type bits in the page table to get set improperly. ────────────────────────────────────────────────────────────────────────────%@NL@% VxDs using this should set the correct initial VM state in their %@AB@%Create_VM%@AE@% device call code. The initial state of the region is actually a copy of the current state of %@AB@%SYS_VM_Handle%@AE@%, but you should not rely on this. Set the initial state you want explicitly by making a %@AB@%MapIntoV86,%@AE@% or %@AB@%PhysIntoV86%@AE@% call. %@NL@% The physical page(s) which are mapped into this region at the time you allocate it are not pages that the MMGR worries about. It is up to the VxD to put the physical pages to good use. The addresses of these physical pages(s) is found by doing a %@AB@%CopyPageTable%@AE@% call on the %@AB@%SYS_VM_Handle%@AE@% and looking at the physical address in the page table entries. %@NL@% Do not assume that the physical addresses of these pages equals the linear address returned. This will be true on most machines, but not on some. These pages by using are mapped with %@AB@%PhysIntoV86%@AE@%. %@NL@% If %@AB@%GVDAReclaim%@AE@% is set, then the physical pages that currently are mapped in the region will be reclaimed by the MMGR and placed on the free list. The NUL page will then be mapped in the region. %@NL@% If %@AB@%GVDAReclaim%@AE@% is clear, the %@AI@%physical%@AE@% page(s) which are mapped into this region at the time you allocate it are not pages that the MMGR worries about. It is up to the VxD to use these physical pages for something useful. Avoid wasting them. The addresses of these %@AI@%physical%@AE@% pages(s) is found by doing a %@AB@%CopyPageTable%@AE@% call on the %@AB@%SYS_VM_Handle%@AE@% and looking at the physical address in the page table entries. %@NL@% It is invalid to assume that the physical addresses of these pages = the linear address returned. This will be true on most machines, but on some it will not. These pages are mapped using %@AB@%PhysIntoV86%@AE@%. %@NL@% You will not be able to %@AB@%Assign_Device_V86_Pages%@AE@% the pages of this region. They are already marked as globally owned because they are below %@AB@%FirstV86Page%@AE@%. %@NL@% You cannot set both %@AB@%GVDAReclaim%@AE@% and %@AB@%GVDAInstance%@AE@%. Attempting to do so will result in an error. %@NL@% %@CR:C6A00190009 @%%@CR:C6A00190010 @% %@2@%%@CR:C6A00190011 @%%@AB@%Allocate_Temp_V86_Data_Area%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned Allocate_Temp_V86_Data_Area(nBytes,flags) %@AS@% unsigned nBytes; %@AS@% unsigned flags;%@AE@% This call is used to allocate a region of the Global V86 Addressable Area to a particular device during system initialization. %@NL@% The primary reason for allocating this area is to create a buffer into which data associated with some %@AB@%Simulate_Int%@AE@% activity (like an INT 21H MS-DOS system call) can be placed. The area allocated with this call only exists for a short period of time during initialization. The %@AI@%nBytes%@AE@% parameter specifies the number of bytes of space to be allocated. There are currently no bits defined in the %@AI@%flags%@AE@%, this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns nonzero linear address of the block allocated if successful, returns zero if the space could not be allocated (insufficient memory, or temp area already allocated). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% There is only one Temp area, therefore only one allocation will be allowed to be outstanding at a time. Attempts to allocate the Temp area when it is already allocated will result in an error. %@NL@% The %@AB@%Allocate_Global_V86_Data_Area%@AE@% call does not function while the Temp Area is allocated. The Temp Area must be released with %@AB@%Free_Temp_V86_Data_Area%@AE@% before the%@AB@% Allocate_Global_V86_Data_Area%@AE@% call can be made again. %@NL@% Make sure you %@AB@%Free_Temp_V86_Data_Area%@AE@% the temp area as soon as possible. %@NL@% The returned linear address is a ring 0 linear address. It is up to the caller to convert this into a Virtual mode SEG:OFFSET form if that is needed. %@NL@% The linear address returned by this call will be %@NL@% Since this area exists only temporarily, it doesn't make sense to instance any of it. %@NL@% The linear address returned from this call is paragraph aligned. %@NL@% The contents of the block will always be zero initialized by this call. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%This routine itself is in the init segment of enhanced Windows. It can %@AI@%therefore only be called during system initialization. Trying to call it %@AI@%after system initialization and the system INIT segment space has been %@AI@%reclaimed will result in a fatal page fault.%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@CR:C6A00190012 @%%@CR:C6A00190013 @% %@2@%%@CR:C6A00190014 @%%@AB@%Free_Temp_V86_Data_Area%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned Free_Temp_V86_Data_Area()%@AE@% This call is used to free the %@AB@%Temp_V86_Data_Area%@AE@% allocated with %@AB@%Allocate_Temp_V86_Data_Area.%@AE@% %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns nonzero if successful, returns zero if unsuccessful (Temp Area not allocated). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% The %@AB@%Allocate_Global_V86_Data_Area%@AE@% call does not function while the Temp Area is allocated. The Temp Area must be released with%@AB@% Free_Temp_V86_Data_Area%@AE@% before the %@AB@%Allocate_Global_V86_Data_Area%@AE@% call can be made again. %@NL@% Once this call is issued, the Linear Address that was returned from %@AB@%Allocate_Temp_V86_Data_Area%@AE@% can no longer be used for anything. The system will probably crash if this is attempted. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%This routine itself is in the init segment of enhanced Windows. It can %@AI@%therefore only be called during system initialization. Trying to call it %@AI@%after system initialization and the system INIT segment space has been %@AI@%reclaimed will result in a fatal page fault. %@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@2@%%@CR:C6A00190015 @%%@AB@%19.2 Device V86 Page Management%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% Certain types of VxDs may want to take control of certain regions of the VM's virtual-86 address space for use by the VxD. The best examples of this are as follows: %@NL@% ■ The display device (VDD), which wants to reserve those areas of the A0H to BFH page address range that are used by the display device.%@NL@% ■ The EMM device (part of V86MMGR), which wants to use a region of VM V86 address space between pages A0H and 100H for the high memory EMM 3.20 Mapping Window.%@NL@% ■ The device responsible for management of the EBIOS page, page 9FH, on machines like the IBM PS/2(R) Model 80. %@NL@% The following calls enable VxDs to allocate VM V86 address ranges for such purposes and cooperate with other VxDs that also might want to use them. There are two types of assignment that can be used: global, which applies to all VMs in the system, and local, which applies to only one VM. The VDD video and EBIOS page assignments are examples of global assignment (although these could be local depending on the specifics of the implementation). The EMM assignments are an example of local assignments. The EMM driver does not want to take over VM V86 page assignment in VMs that are not using EMM because then all those pages cannot be used by any other device. Thus, it waits until a specific VM makes an EMM call of a certain type at which point the EMM driver %@AI@%may%@AE@% do a local page assignment in that particular VM to assign the EMM pages of the V86 address space to the EMM device. The global versus local assignment is specified via the %@AI@%VMHandle%@AE@% parameter on the calls. If the handle is nonzero, it is local; if the handle is zero, it is global. %@NL@% No protection is provided with this mechanism; all that is provided is information so that devices can cooperate. There is nothing to prevent a VxD from mapping pages that it does not own or a page owned by some other VxD. A device that does these things is simply uncooperative and not correctly implemented. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%All of these calls use the USE32 C calling convention. The true name of the %@AI@%procedure has an underscore in front (i.e., %@AB@%Assign_Device _V86_Pages%@AE@%%@AI@% is %@AI@%actually %@AE@%%@AI@%%@AB@%_Assign_Device_V86_Pages%@AE@%%@AE@%%@AI@%), and the arguments are pushed right to %@AI@%left (unlike the PL/M calling convention used by Windows, which is left to %@AI@%right). The return value(s) is returned in C standard %@AE@%%@AI@%%@AB@%EDX:EAX%@AE@%%@AE@%%@AI@%. It is the %@AI@%responsibility of the caller%@AE@%%@AI@% to clear the arguments off the stack. Registers %@AI@%%@AE@%%@AI@%%@AB@%EAX%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%ECX%@AE@%%@AE@%%@AI@%, and %@AE@%%@AI@%%@AB@%EDX%@AE@%%@AE@%%@AI@% are changed by calls. Registers %@AE@%%@AI@%%@AB@%DS%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%ES%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@% %@AI@%%@AB@%FS%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%GS%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%EBP%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%EDI%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%ESI%@AE@%%@AE@%%@AI@%, and %@AE@%%@AI@%%@AB@%EBX%@AE@%%@AE@%%@AI@% are preserved.%@AE@% %@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@CR:C6A00190016 @% %@2@%%@CR:C6A00190017 @%%@AB@%Assign_Device_V86_Pages Assign_Device_V86_Pages service%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned Assign_Device_V86_Pages(VMLinrPage,nPages,VMHandle,flags) %@AS@% unsigned VMLinrPage; %@AS@% unsigned nPages; %@AS@% unsigned VMHandle; %@AS@% unsigned flags;%@AE@% This call is used to assign a region of VM V86 address space to a device. %@AI@%VMLinrPage%@AE@% specifies the linear page number (>=0, <=10Fh) of the first page of V86 address space to be assigned. %@AI@%nPages%@AE@% specifies the number of pages to be assigned starting at %@AI@%VMLinrPage%@AE@%. The entire specified range must be >=0, <=10Fh, an error will occur if it is not. All of the specified pages must be un-assigned, or an error will occur. %@AI@%VMHandle%@AE@% specifies the VM to Local assign the pages in, if this parameter is 0, it means the pages are to be Global assigned. There are currently no bits defined in the %@AI@%flags%@AE@%, this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns nonzero if the assignment was successful, returns zero if the assignment failed (at least one page in the specified range is already assigned, or invalid page range). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% During device initialization only Global Assignments are allowed, and there are restrictions on the pages which can be assigned. Pages between %@AB@%FirstV86Page%@AE@% and page 0A0h can only be top down, in order assigned during device initialization. Local Assignments, and General assignment between %@AB@%FirstV86Page%@AE@% and page 0A0h must wait until device initialization is complete. %@NL@% Note that Global Assignment of a page that is already assigned, either Local to any VM, or Global assigned will fail. Global assignment can only work on pages which are not currently assigned in any VM. %@NL@% %@CR:C6A00190018 @%%@CR:C6A00190019 @% %@2@%%@CR:C6A00190020 @%%@AB@%Deassign_Device_V86_Pages%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned DeAssign_Device_V86_Pages(VMLinrPage,nPages,VMHandle,flags) %@AS@% unsigned VMLinrPage; %@AS@% unsigned nPages; %@AS@% unsigned VMHandle; %@AS@% unsigned flags;%@AE@% This call is used to deassign a region of VM V86 address which was previously assigned with %@AB@%Assign_Device_V86_Pages%@AE@%. %@AI@%VMLinrPage%@AE@% specifies the linear page number (>=0, <=10Fh) of the first page to be deassigned. %@AI@%nPage%@AE@%s specifies the number of pages to be deassigned starting at %@AI@%VMLinrPage%@AE@%. The entire specified range must be >=0, <=10Fh, an error will occur if it is not. All of the specified pages must be assigned, or an error will occur. %@AI@%VMHandle%@AE@% specifies the VM to Local deassign the pages in, if this parameter is 0, it means the pages are to be Global deassigned. There are currently no bits defined in the %@AI@%flags%@AE@%, this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns nonzero if the deassignment was successful, returns zero if the deassignment failed (at least one page in the specified range is already deassigned, or invalid page range). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% During device initialization this call will always fail. This call only works after device initialization is complete. %@NL@% An extreme amount of chaos will occur if someone Global DeAssigns a range which is actually Local Assigned, or DeAssigns a region which was not obtained via a successful%@AB@% Assign_Device_V86_Pages. %@AE@% %@NL@% %@CR:C6A00190021 @%%@CR:C6A00190022 @% %@2@%%@CR:C6A00190023 @%%@AB@%Get_Device_V86_Pages_Array%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned Get_Device_V86_Pages_Array(VMHandle,ArrayBufPTR,flags) %@AS@% unsigned VMHandle; %@AS@% unsigned ArrayBufPTR; %@AS@% unsigned flags;%@AE@% This call is used to obtain a copy of the assignment bit map array for %@AB@%Device_V86_Pages%@AE@%. This allows the caller to determine which regions of the VM V86 address space are currently assigned, and which are available. %@AI@%VMHandle%@AE@% specifies the VM to get the assignment bit map of, if this parameter is 0, it means to get the Global assignment array. %@AI@%ArrayBufPTR%@AE@% points to a buffer large enough to contain the array. The assignment array is an array of 110h bits, one bit for each page in the range 0-10Fh. Thus the size of the array is ((110h/8)+3)/4 = 9 DWORDS. %@NL@% Bits in the array which are set (=1) indicate pages which are assigned, bits which are clear (=0) indicate pages which are not assigned. Thus to test the bit for page number N (0 N 10Fh) you could use code like this: %@NL@% %@AS@% mov ebx, N MOD 32 ; Bit number in DWORD %@AS@% mov eax, N / 32 ; DWORD index into array %@AS@% bt dword ptr ArrayBufPTR[eax*4],ebx ; Test bit for page N %@AS@% jnc short PageUnAssigned PageAssigned:%@AE@% Note that this code is mearly intended to illustrate how the bit array works. This code is not the most efficient, or the only way to implement this test. There are currently no bits defined in the %@AI@%flags%@AE@%, this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns nonzero if successful, returns zero if the bit array could not be returned (Invalid %@AI@%VMHandle%@AE@%). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% The Global Bit Array only indicates those pages which are currently Globally owned. Bits with 0 in them do not necessarily indicate pages which can be %@AB@%Global Assign_Device_V86_Paged%@AE@%. The reason is that one of the VMs in the system may have that page Local %@AB@%Assign_Device_V86_Paged%@AE@%. In order to determine if a page can be globally assigned, the Global array must be examined, AND all of the VM Local arrays must be examined. %@NL@% %@CR:C6A00190024 @%%@CR:C6A00190025 @% %@2@%%@CR:C6A00190026 @%%@AB@%Hook_V86_Page%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%This service does not use the C-calling Convention%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service allows VxDs to intercept page faults in portions of the V86 address space of every virtual machine. It is used by devices such as the Virtual Display Device to detect when particular address ranges are accessed. %@NL@% You must specify a page number and address of a call-back routine to this service. If it is installed successfully, your "hook" will be called every time a page fault occurs in ANY VM on that page. See the memory manager _Modify_Pages documentation for making hooked pages not present and for registering ownership of pages. %@NL@% The callback routine is responsible for mapping an memory at the location of the page fault or crashing the VM. In unusual circumstances it may be appropriate to map a null page at the faulting faulting address page. See the memory manager documentation for details on mapping memory and mapping null pages. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%Do not rely on the contents of the CR2 (page fault) register. Use the value %@AI@%passed to your call-back in EAX.%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% EAX = Page number (A0h - 0FFh) ESI = Address of trap routine %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry flag set then ERROR: Invalid page number or page already hooked else Page hooked %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% EAX = Faulting page number EBX = Current VM handle EBP does NOT point to the client register structure. %@NL@% %@2@%%@CR:C6A00190027 @%%@AB@%19.3 GDT/LDT Management%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% These services provide a way for VxDs to allocate Global Descriptor Table (GDT) selectors and set up a Local Descriptor Table (LDT) for protected-mode execution. Notice that the intent of these services is to support segmented environments in protected mode. In general, VxDs should never need to allocate GDT selectors or set up an LDT. The only reason these services are needed is to support protected-mode applications. Notice that the LDT is a per-VM object; each VM may have its own LDT. Since enhanced Windows is a flat model system, do not create multiple segments.%@CR:C6A00190028 @%%@CR:C6A00190029 @%%@CR:C6A00190030 @%%@NL@% %@CR:C6A00190031 @%%@CR:C6A00190032 @% %@2@%%@CR:C6A00190033 @%%@AB@%Allocate_GDT_Selector%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned Allocate_GDT_Selector(DescDWORD1,DescDWORD2,flags) %@AS@% unsigned DescDWORD1; %@AS@% unsigned DescDWORD2; %@AS@% unsigned flags;%@AE@% This call is used to create a new GDT selector. %@AI@%DescDWORD1%@AE@% and %@AI@%DescDWORD2%@AE@% form the 8 bytes of information to be placed in the new descriptor. %@AI@%DescDWORD1%@AE@% is the high order 4 bytes of the descriptor containing the high 16 bits of the base, the high 4 bits of the limit and the status and type bits. %@AI@%DescDWORD2%@AE@% is the low order 4 bytes for the descriptor containing the low 16 bits of the base and limit. Use %@AB@%BuildDescDWORDs%@AE@% to help you set up these arguments. There are currently no bits defined in the %@AI@%flags%@AE@%, this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns a 64 bit long which is actually two 32 bit DWORDs. The low DWORD (%@AB@%EAX%@AE@%) is the non-zero selector if succesfull. The high DWORD (%@AB@%EDX%@AE@%) is split into two 16 bit word returns. The low 16 bits of %@AB@%EDX%@AE@% is the GDT descriptor which describes the GDT itself. Unlike the LDT, it is strongly recommended that this selector %@AI@%not %@AE@%be used to edit the GDT. If you mess up editing the LDT, you will probably just crash one app, but if you mess up editing the GDT, you will crash the whole system. The high 16 bits of %@AB@%EDX%@AE@% is the number of selectors currently in the GDT (the "limit" of the GDT expressed as a number of selectors, (LIMIT+1)/8). Both DWORDS have value 0 if the allocation failed (Bad DescDWORD arguments, GDT is full, insufficient memory to grow GDT). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% The RPL of the selector returned from this call will be set to the DPL of the selector set in %@AI@%DescDWORD1%@AE@%. %@NL@% The low 16 bits of the %@AB@%EDX%@AE@% return does not change, but it is safest to save the value of the GDT selector after each %@AB@%Allocate_GDT_Selector%@AE@% call. This selector will have DPL = RPL = 0, and the TI bit (bit 2) will be clear. %@NL@% The high 16 bits of the %@AB@%EDX%@AE@% return must be saved after each call, if its value is important, because the size of the GDT may change on each call. %@NL@% The prefered method of changing a GDT descriptor is to use %@AB@%SetDescriptor%@AE@%, rather than using the GDT selector which is returned by this call. %@NL@% %@CR:C6A00190034 @%%@CR:C6A00190035 @% %@2@%%@CR:C6A00190036 @%%@AB@%Allocate_LDT_Selector%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned long %@AS@% Allocate_LDT_Selector(VMHandle,DescDWORD1,DescDWORD2,Count,flags) %@AS@% unsigned VMHandle; %@AS@% unsigned DescDWORD1; %@AS@% unsigned DescDWORD2; %@AS@% unsigned Count; %@AS@% unsigned flags;%@AE@% This call is used to create new LDT selector(s) in the specified VM context. %@AI@%VMHandle%@AE@% is a valid VM handle and indicates the VM context for which the selector(s) will be valid. %@AI@%DescDWORD1%@AE@% and %@AI@%DescDWORD2%@AE@% form the 8 bytes of information to be placed in the new descriptor(s). %@AI@%DescDWORD1%@AE@% is the high order 4 bytes of the descriptor containing the high 16 bits of the base, the high 4 bits of the limit and the status and type bits. %@AI@%DescDWORD2%@AE@% is the low order 4 bytes for the descriptor containing the low 16 bits of the base and limit. Use %@AB@%BuildDescDWORDs%@AE@% to help you set up these arguments. The %@AI@%Count %@AI@%%@AE@%parameter specifies the number of contiguous LDT selectors to allocate. This parameter supports Block Selector Assignment strategies. USE16 segmented applications cannot address objects larger than 64K Bytes in size without having multiple selectors that describe the sequential 64K Byte blocks of the object. For an object <=64K bytes in size, or instances where it is inappropriate, Count = 1. For an object >64K bytes in size, Count = (Size + (64K - 1))/64K. Notice that the selectors allocated for count >1 all have the same descriptor DWORDs in them. It is up to the caller to edit the base and limits of the individual selectors in a Block Selector Assignment using the LDT selector returned in the low 16 bits of %@AB@%EDX%@AE@%. There are currently no bits defined in the flags, this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns a 64 bit long which is actually two 32 bit DWORDs. The low DWORD (%@AB@%EAX%@AE@%) is the nonzero selector if successful, if Count was >1, this is the FIRST selector, the second is %@AB@%EAX%@AE@%+8, the third %@AB@%EAX%@AE@%+16, etc. The high DWORD (%@AB@%EDX%@AE@%) is split into two 16 bit word returns. The low 16 bits of %@AB@%EDX%@AE@% is the LDT descriptor which describes the LDT itself. The allows the caller to do things such as change the present bit of LDT selectors and change the base and limit. The high 16 bits of %@AB@%EDX%@AE@% is the number of selectors currently in the LDT (the "limit" of the LDT expressed as a number of selectors, (LIMIT+1)/8). Both DWORDS have value 0 if the allocation failed (Bad DescDWORD arguments, LDT is full, invalid %@AI@%VMHandle%@AE@% insufficient memory to grow LDT). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% The RPL of the selector returned from this call will be set to the DPL of the selector set in %@AI@%DescDWORD1%@AE@% and the TI bit (bit 2) will be set. %@NL@% The high 16 bits of the %@AB@%EAX%@AE@% return are zero since selectors are 16 bit quantities. %@NL@% Note that LDT selectors are PER VM and only valid in that VM context (VM must be current VM for selector to be valid). Use %@AB@%SelectorMapFlat%@AE@% to look at regions described by LDT selectors in VMs which are not the current VM. %@NL@% The low 16 bits of the %@AB@%EDX%@AE@% return does not change once the LDT of a particular VM is created, but it is safest to save the value of the LDT selector after each %@AB@% Allocate_LDT_Selector call.%@AE@% This selector will have DPL = RPL = Protected Mode Application Privilege, and the TI bit (bit 2) will be set. %@NL@% The high 16 bits of the %@AB@%EDX%@AE@% return %@AI@%must be saved%@AE@% after each call, if its value is important, because the size of the LDT may change on each call. %@NL@% The multiple selectors allocated with Count >1 must be individually freed. %@AB@%_Free_LDT_Selector%@AE@% does not have a count. %@NL@% The prefered method of changing an LDT descriptor is to use %@AB@%SetDescriptor%@AE@%. %@NL@% Use of ALDTSpecSel is not advised. Reliance on specific "hard coded" LDT selectors is contrary to good system design principals. Note that a bit like this does not exist for %@AB@%Allocate_GDT_Selector%@AE@%, this is intentional. A call with this bit set may always fail for some values of the Count parameter, and it may start failing for all values of the Count parameter in a later release of the product. %@NL@% %@CR:C6A00190037 @%%@CR:C6A00190038 @% %@2@%%@CR:C6A00190039 @%%@AB@%BuildDescDWORDs%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned long BuildDescDWORDs(DESCBase,DESCLimit,DESCType,DESCSize,flags) %@AS@% unsigned DESCBase; %@AS@% unsigned DESCLimit; %@AS@% unsigned DESCType; %@AS@% unsigned DESCSize; %@AS@% unsigned Flags%@AE@% This call is used to help you build the %@AI@%DescDWORD1%@AE@% and %@AI@%DescDWORD2%@AE@% arguments for calls to %@AB@%Allocate_LDT/GDT_Selector%@AE@%. DESCBase is the 32 bit BASE for the descriptor. DESCLimit is the 20 bit LIMIT for the descriptor. %@AI@%DESCType%@AE@% specifies the type BYTE (Only low 8 bits of the parameter are valid, other bits must be 0) for the descriptor. This is the byte that occupies bits 8-15 of the high DWORD of the descriptor (Present bit, DPL and TYPE fields). %@AI@%DESCSize%@AE@% specifies bits 20-23 of the high DWORD of the descriptor (Granularity, Big/Default). Notice that these bits occupy bits 4-7 of the %@AI@%DESCSize%@AE@% parameter, other bits must be 0. In other words %@AI@%DESCSize%@AE@% specifies a byte just like DESCType where only the high 4 bits of the byte are specified. %@NL@% Current flags bits: %@NL@% %@AS@% BDDExplicitDPL EQU 00000000000000000000000000000001B%@AE@% All unused bits must be zero. BDDExplicitDPL, if set, indicates that the DPL value specified in the DESCType field is to be used. If this bit is clear, then the DPL specified in the DESCType field is ignored and the DPL returned will be set to the protected mode application RPL. Since most selectors are built for the use by protected mode applications, this provides a convienient way to build descriptors without having to actually know which ring protected mode applications run in. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns the low DWORD of the descriptor (%@AI@%DescDWORD2%@AE@%) in %@AB@%EAX%@AE@%, and the high DWORD of the descriptor (%@AI@%DescDWORD1%@AE@%) in %@AB@%EDX%@AE@%. %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% If you are building selectors for use by Protected Mode applications use the built-in capability provided by not setting the BDDExplicitDPL bit. Do not make assumptions about which ring protected mode applications run in. The selection of a ring for PM applications will be changed in future revs of Windows. %@NL@% %@CR:C6A00190040 @%%@CR:C6A00190041 @% %@2@%%@CR:C6A00190042 @%%@AB@%Free_GDT_Selector%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned Free_GDT_Selector(Selector,flags) %@AS@% unsigned Selector; %@AS@% unsigned flags;%@AE@% This call is used to free a GDT selector allocated with a previous %@AB@%Allocate_GDT_Selector%@AE@% call. %@AI@%Selector%@AE@% is the return from a previous %@AB@%Allocate_GDT_Selector%@AE@% call. There are currently no bits defined in the %@AI@%flags%@AE@%, this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns nonzero value if successful, returns zero if the free failed (invalid %@AI@%Selector%@AE@%). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% Certain system selectors cannot be freed since they are required for operation of enhanced Windows. %@NL@% %@CR:C6A00190043 @%%@CR:C6A00190044 @% %@2@%%@CR:C6A00190045 @%%@AB@%Free_LDT_Selector%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned Free_LDT_Selector(VMHandle,Selector,flags) %@AS@% unsigned VMHandle; %@AS@% unsigned Selector; %@AS@% unsigned flags;%@AE@% This call is used to free a LDT selector allocated with a previous %@AB@%Allocate_LDT_Selector%@AE@% call. %@AI@%VMHandle%@AE@% indicates the VM context of the selector. %@AI@%Selector%@AE@% is the return from a previous %@AB@%Allocate_LDT_Selector%@AE@% call. There are currently no bits defined in the %@AI@%flags%@AE@%, this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns nonzero value if successful, returns zero if the free failed (invalid %@AI@%Selector%@AE@%, invalid %@AI@%VMHandle%@AE@%). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% The RPL bits of the passed Selector are ignored by this call. %@NL@% %@2@%%@CR:C6A00190046 @%%@AB@%GetDescriptor%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned long GetDescriptor(Selector,VMHandle,flags) unsigned Selector; %@AS@% unsigned VMHandle; %@AS@% unsigned flags;%@AE@% This call is used to get a copy of the two descriptor DWORDs associated with the given LDT or GDT Selector. Selector is a GDT or LDT selector value to get the descriptor of. The %@AI@%VMHandle%@AE@% parameter is ignored if Selector is a GDT selector. If Selector is an LDT selector, then %@AI@%VMHandle%@AE@% indicates the appropriate VM context for the Selector. There are currently no bits defined in the %@AI@%flags%@AE@%, this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns the low DWORD of the descriptor (%@AI@%DescDWORD2%@AE@%) in %@AB@%EAX%@AE@%, and the high DWORD of the descriptor (%@AI@%DescDWORD1%@AE@%) in %@AB@%EDX%@AE@%. Returns zero in both DWORDs if there was an error (invalid selector, invalid VM handle). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% The high 16 bits of the Selector argument are ignored (this is because the 80386 CPU often sets them to somewhat random values when DWORD operations are performed on segment registers). %@NL@% The RPL bits of Selector are ignored. %@NL@% The %@AI@%VMHandle%@AE@% parameter must be valid for LDT selectors. %@NL@% %@2@%%@CR:C6A00190047 @%%@AB@%SetDescriptor%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned SetDescriptor(Selector,VMHandle,DescDWORD1,DescDWORD2,flags) %@AS@%unsigned Selector; %@AS@% unsigned VMHandle; %@AS@% unsigned DescDWORD1; %@AS@% unsigned DescDWORD2; %@AS@% unsigned flags;%@AE@% This call is used to set (change) the descriptor of the given Selector. Selector is a GDT or LDT selector value to set the descriptor of. The %@AI@%VMHandle%@AE@% parameter is ignored if Selector is a GDT selector. If Selector is an LDT selector, then VMHandle indicates the appropriate VM context for the Selector. %@AI@%DescDWORD1%@AE@% and %@AI@%DescDWORD2%@AE@% form the 8 bytes of information to be placed in the descriptor. %@AI@%DescDWORD1%@AE@% is the high ORDER 4 bytes of the descriptor containing the high 16 bits of the base, the high 4 bits of the limit and the status and type bits. %@AI@%DescDWORD2%@AE@% is the low ORDER 4 bytes for the descriptor containing the low 16 bits of the base and limit. Use %@AB@%BuildDescriptorDWORDs%@AE@% to help you set up these arguments. There are currently no bits defined in the %@AI@%flags%@AE@%, this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns non-zero value if succesfull, returns zero if it failed (invalid %@AI@%Selector%@AE@%, invalid %@AI@%VMHandle%@AE@%). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% The high 16 bits of the Selector argument are ignored (this is because the 80386 CPU often sets them to somewhat random values when DWORD operations are performed on segment registers). %@NL@% The RPL bits of Selector are ignored. %@NL@% The %@AI@%VMHandle%@AE@% parameter must be valid for LDT selectors. %@NL@% %@2@%%@CR:C6A00190048 @%%@AB@%19.4 System Heap Allocator%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% The purpose of the heap allocator is to provide a memory manager service to system components to allocate small (i.e., less than a page size) blocks of memory for long term or short term use. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%All of these calls use the USE32 C calling convention. The true name of the %@AI@%procedure has an underscore in front (i.e., %@AB@%HeapAllocate%@AE@%%@AI@% is actually %@AI@%%@AE@%%@AI@%%@AB@%_HeapAllocate%@AE@%%@AE@%%@AI@%), and the arguments are pushed right to left (unlike the PL/M %@AI@%calling convention used by Windows, which is left to right). The return %@AI@%value(s) is returned in C standard %@AE@%%@AI@%%@AB@%EDX:EAX%@AE@%%@AE@%%@AI@%. It is the responsibility of the %@AI@%caller%@AE@%%@AI@%to clear the arguments off the stack. Registers %@AE@%%@AI@%%@AB@%EAX%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%ECX%@AE@%%@AE@%%@AI@%, and %@AE@%%@AI@%%@AB@%EDX%@AE@%%@AE@%%@AI@% are %@AI@%changed by calls. Registers %@AE@%%@AI@%%@AB@%DS%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%ES%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%FS%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%GS%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%EBP%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%EDI %@AB@%%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%ESI%@AE@%%@AE@%%@AI@%, and %@AE@%%@AI@%%@AB@%EBX%@AE@%%@AE@%%@AI@% are preserved.%@AE@%%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% The heap uses a boundary tag allocation scheme similar to the one used by the MS-DOS operating system. This has the benefit of not placing some fixed limit on the total number of heap blocks. It has the disadvantage of having a fixed overhead of extra space per block. The heap overhead is about 16 bytes per block. Users should keep this in mind when allocating lots of objects of small size. Try to combine such needs into larger heap blocks to cut down on the overhead. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AU@%WARNING %@AE@% You are strongly warned against making assumptions about the placement and size of the heap boundary tag structures. Future versions of enhanced Windows may change this behavior of the heap. ────────────────────────────────────────────────────────────────────────────%@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%4 byte (DWORD) alignment is maintained on heap blocks. This could be %@AI@%increased in a later version, but at least DWORD alignment is guaranteed. %@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@CR:C6A00190049 @%%@CR:C6A00190050 @% %@2@%%@CR:C6A00190051 @%%@AB@%HeapAllocate%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned HeapAllocate(nbytes,flags) %@AS@% unsigned nbytes; %@AS@% unsigned flags;%@AE@% This is the call to allocate a block from the heap. %@AI@%nbytes%@AE@% is a 32 bit unsigned integer which is the size, in bytes, of the block. Current flags bits: %@NL@% %@AS@% HeapZeroInit EQU 00000000000000000000000000000001B%@AE@% All unused bits %@AI@%must be zero%@AE@%. HeapZeroInit, if set, indicates that if the allocation is succesful, the memory is to be initialized with value 0 in all bytes of the block. If HeapZeroInit is clear, the block will have completely random values in it. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% The return value is the 32 bit RING 0 address (offset relative to standard enhanced Windows RING 0 DS) of the block. Value is 0 if the allocation failed (insufficient memory). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% Blocks are DWORD aligned as noted, but sizes do not have to be a multiple of 4. %@NL@% There is no "protection" of the heap. Care must be taken not to overrun the size of your block. Failure to do this will result in odd behavior and crashes. %@NL@% There is no "motion" of blocks in the heap (heap blocks are all fixed), except via %@AB@% HeapReAllocate%@AE@%, and therefore no compaction. You are advised not to use the heap in such a way as to severely fragment it. You will end up wasting lots of memory by doing this. %@NL@% The Flag bit equates are defined by including VMM.INC, please use the equates. %@NL@% Allocation of 0 length heap blocks is not allowed. %@NL@% %@CR:C6A00190052 @%%@CR:C6A00190053 @% %@2@%%@CR:C6A00190054 @%%@AB@%HeapFree%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned HeapFree(hAddress,flags) %@AS@% unsigned hAddress; %@AS@% unsigned flags;%@AE@% This call is used to free an existing block of heap. %@AI@%hAddress%@AE@% is the value returned from a previous call to %@AB@%HeapAllocate%@AE@% or %@AB@%HeapReAllocate%@AE@% and indicates the block to be freed. There are currently no bits defined in the %@AI@%flags%@AE@%, this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns nonzero value if the block was succesfully freed, zero if the free was unsuccesful (invalid %@AI@%hAddress%@AE@%). %@NL@% %@CR:C6A00190055 @%%@CR:C6A00190056 @% %@2@%%@CR:C6A00190057 @%%@AB@%HeapGetSize%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned HeapGetSize(hAddress,flags) %@AS@% unsigned hAddress; %@AS@% unsigned flags;%@AE@% This call is used to get the size of an existing block of heap.%@AI@% hAddress%@AE@% is the value returned from a previous call to %@AB@%HeapAllocate%@AE@% or %@AB@%HeapReAllocate%@AE@% and indicates the block to get the size of. There are currently no bits defined in the %@AI@%flags%@AE@%, this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns the size, in bytes, of the block. Returns zero if there was an error (invalid %@AI@%hAddress%@AE@%). %@NL@% %@CR:C6A00190058 @%%@CR:C6A00190059 @% %@2@%%@CR:C6A00190060 @%%@AB@%HeapReAllocate%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned HeapReAllocate(hAddress,nbytes,flags) %@AS@% unsigned hAddress; %@AS@% unsigned nbytes; %@AS@% unsigned flags;%@AE@% This call is used to grow or shrink or reinitialize an existing block of heap. %@AI@%hAddress%@AE@% is the value returned from a previous %@AB@%HeapAllocate%@AE@% or %@AB@%HeapReAllocate%@AE@% call and indicates the block to be reallocated. %@AI@%nbytes%@AE@% is a 32 bit unsigned integer which is the new size in bytes of the block. Current flags bits: %@NL@% %@AS@% HeapZeroInit EQU 00000000000000000000000000000001B HeapZeroReInit EQU %@AS@%00000000000000000000000000000010B HeapNoCopy EQU %@AS@%00000000000000000000000000000100B%@AE@% All unused bits %@AI@%must be zero.%@AE@% %@AB@%HeapZeroInit%@AE@%, if set, indicates that if the reallocation is succesful, and the reallocation is growing the size of the block, the "grow area" of the block is to be initialized with value 0 in all bytes. This bit is ignored on a reallocation which is not growing the size of the block. %@AB@%HeapZeroReInit%@AE@%, if set, indicates that the ENTIRE block is to be reinitialized with value zero in all bytes of the block. HeapNoCopy, if set, indicates that the previous contents of the block are irrelevant, and don't need to be copied into the newly sized block. There is no reason that more than one of these bits should be set. If none of the bits are set, the previous contents of the block are copied into the new block, up to the lesser of the size of the new block, and the size of the old block, and the "grow area", if any, is not initialized with anything. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% The return value is the 32 bit RING 0 address (offset relative to standard enhanced Windows RING 0 DS) of the new block. Value is 0 if the reallocation failed (insufficient memory, or invalid %@AI@%hAddress%@AE@%). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% Do not make assumptions about the relationship between the passed in %@AI@%hAddress%@AE@% and the %@AI@%hAddress%@AE@% returned. Assume that the returned%@AI@% hAddress%@AE@% is always different than the passed in %@AI@%hAddress%@AE@%. %@NL@% In the case where this call fails, the passed in %@AI@%hAddress%@AE@% block remains valid. In the case where this call works and returns a new %@AI@%hAddress%@AE@%, the passed in %@AI@%hAddress%@AE@% is no longer valid (old block has been HeapFreed). %@NL@% There is no "protection" of the heap. Care must be taken not to overrun the size of your block. Failure to do this will result in odd behavior and crashes. %@NL@% There is no "motion" of blocks in the heap (heap blocks are all fixed), and therefore no compaction. You are advised not to use the heap in such a way as to severely fragment it. You will end up wasting lots of memory by doing this. %@NL@% Note that this call can be used to reset the contents of an existing heap block to 0 by setting nbytes to the current size of the block and setting %@AB@%HeapZeroReInit%@AE@%. %@NL@% You cannot %@AB@%HeapReAllocate%@AE@% a block to size 0, use %@AB@%HeapFree%@AE@%. %@NL@% The Flag bit equates are defined by including VMM.INC, please use the equates. %@NL@% %@2@%%@CR:C6A00190061 @%%@AB@%19.5 System Page Allocator%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% The page allocator is the set of services by which system memory is allocated and mapped into a VM's linear address space. VxD's can also examine and modify the status of mapped pages and lock or unlock pages into physical memory. VxD's can also allocate pages for the VxD's exclusive use. For example, the current state of the video memory can be saved for clipboard operations. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%All of these calls use the USE32 C calling convention. The true name of the %@AI@%procedure has an underscore in front (i.e., %@AB@%PageAllocate%@AE@%%@AI@% is actually %@AI@%%@AE@%%@AI@%%@AB@%_PageAllocate%@AE@%%@AE@%%@AI@%), and the arguments are pushed right to left (unlike the PL/M %@AI@%calling convention used by Windows, which is left to right). The return %@AI@%value(s) is returned in C standard %@AE@%%@AI@%%@AB@%EDX:EAX%@AE@%%@AE@%%@AI@%. It is the responsibility of the %@AI@%caller%@AE@%%@AI@%to clear the arguments off the stack. Registers %@AE@%%@AI@%%@AB@%EAX%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%ECX%@AE@%%@AE@%%@AI@%, and %@AE@%%@AI@%%@AB@%EDX%@AE@%%@AE@%%@AI@% are %@AI@%changed by calls. Registers %@AE@%%@AI@%%@AB@%DS%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%ES%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%EBP%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%EDI%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%ESI%@AE@%%@AE@%%@AI@%, and %@AI@%@AE@%%@AI@%%@AB@%EBX%@AE@%%@AE@%%@AI@% are preserved.%@AE@%%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@CR:C6A00190062 @%%@CR:C6A00190063 @% %@2@%%@CR:C6A00190064 @%%@AB@%CopyPageTable%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned CopyPageTable(LinPgNum,nPages,PageBufPTR,flags) %@AS@% unsigned LinPgNum; %@AS@% unsigned nPages; %@AS@% unsigned *PageBufPTR; %@AS@% unsigned flags;%@AE@% This call is used to obtain a copy of an enhanced Windows page table. This call is intended as an assist to enhanced Windows system components that need to analyze the linear to physical mapping (such as DMA devices). %@AI@%LinPgNum%@AE@% is the page number of the first page of the range. This can be anything in the range 0 - 0FFFFFh. Thus addresses in the range 0-3FFh refer to addresses in the 1M V86 address space of the current VM. To compute the page number of any region simply take the address relative to the standard enhanced Windows RING 0 DS and shift it right by 12 bits. For example, the linear address 60001AB6h is in page number 60001h. Alignment considerations of this address (beyond 4K alignment) are the responsibility of the caller. %@AI@%nPages%@AE@% is the number of page table entries to copy. %@AI@%PageBufPTR%@AE@% is a 32 bit RING 0 offset relative to the standard RING 0 DS which is the address of a buffer where the page table will be copied. Caller must insure that this buffer is large enough. Each page table entry is a DWORD, so the buffer must be at least nPages*4 bytes long. There are currently no bits defined in the %@AI@%flags%@AE@%, this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns a nonzero value if the copy is succesful, returns 0 value if the copy was succesful, %@AI@%but%@AE@% at least a part of the range overlapped a region where the corresponding page directory entry is not present. %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% You get a copy of the page table; writing to your buffer has no effect. %@NL@% Note that V86 page tables stop at page 10Fh. %@NL@% To look at the page table of a VM that is not the current VM simply use the high linear address of the VM. For instance, to look at the page table starting at V86 address 0A000:0 of a VM which is not the current VM: %@NL@% %@AS@% mov eax,0A0000h ; V86 linear adress of 0A000:0 %@AS@% add eax,[ebx.CB_High_Linear] ; High linear address %@AS@% shr eax,12 ; Convert to page number%@AE@% Note that the above sequence always works correctly (works if the VM is the current VM as well). So simply doing this in all cases avoids the complication of worrying about whether the VM is the current VM. %@NL@% The intent of this call is for you to look at the physical addresses in the high 20 bits of the entries. The low 12 bits of system information may be examined however. %@NL@% You are warned to be careful about keeping this buffer for any length of time. The actual page table entries can change while the copy you have won't. The information in the copy should be analyzed quickly. %@NL@% %@CR:C6A00190065 @%%@CR:C6A00190066 @% %@2@%%@CR:C6A00190067 @%%@AB@%GetDemandPageInfo%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% void GetDemandPageInfo(BufPtr,flags) %@AS@% DemandInfoStruc *BufPtr; %@AS@% unsigned flags;%@AE@% This call is for use by the demand paging device. It provides information for the demand pager. %@NL@% %@AS@% DemandInfoStruc struc %@AS@% DILin_Total_Count dd ? ; Size of linear address space in pages %@AS@% DIPhys_Count dd ? ; Count of phys pages %@AS@% DIFree_Count dd ? ; Count of free phys pages %@AS@% DIUnlock_Count dd ? ; Count of unlocked phys Pages %@AS@% DILinear_Base_Addr dd ? ; Base of pageable address space %@AS@% DILin_Total_Free dd ? ; Total free linear pages %@AS@% DIReserved dd 12 DUP(?) ; Reserved %@AS@% DemandInfoStruc ends%@AE@% DILin_Total_Count is the size in pages of the linear address space subject to demand paging. DILinear_Base_Addr is the linear address of the start of the demand pageable region. Thus there are DILin_Total_Count pages starting at address DILinear_Base_Addr which are subject to demand paging. DILin_Total_Free is the number of the DILin_Total_Count pages which are currently free. Notice that this space may not be allocatable in a single block, it is the total free, not the size of the largest free block. Note that if DILinear_Base_Addr == 0, this means that the demand pageable region of the system is not contiguous. DIPhys_Count is the total number of physical pages under the control of the memory manager. DIFree_Count is the number of pages currently on the free list. DIUnlock_Count is the count of pages which are currently unlocked, notice that free pages are unlocked. There are currently no bits defined in the flags, this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% This call does not have a return value. It simply fills in the structure pointed to by %@AI@%BufPtr%@AE@%. %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% The reserved field is exactly that, reserved. Do not make any assumptions about what is in this region. Behavior will change in later releases. %@NL@% %@CR:C6A00190068 @%%@CR:C6A00190069 @% %@2@%%@CR:C6A00190070 @%%@AB@%GetFreePageCount%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned long (flags) %@AS@% unsigned flags;%@AE@% This call is used to obtain the count of free 4K pages. And the count of pages that can be allocated as PageLocked. There are currently no bits defined in the %@AI@%flags%@AE@%, this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% The return value is a 64 bit long which is actually two 32 bit DWORDS. The Low DWORD (%@AB@%EAX%@AE@%) is the 32 bit count of free 4K pages in the system which could be allocated with the %@AB@%PageAllocate%@AE@% call. The High DWORD (%@AB@%EDX%@AE@%) is the 32 bit count of pages available for allocation as PageLocked pages at the current time. %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% You should be careful about making assumptions about being able to turn around and issue a call to allocate all of the pages returned by this call. Besides any alignment considerations, it is possible someone could get in and allocate some or all of the pages before you. This call is intended to be advisory in nature. %@NL@% Note that, in a demand paged virtual memory system such as enhanced Windows, the free pages count is usually very close to 0. It is more relevant to use the %@AB@%EDX%@AE@% return to make judgements about allocation possibility. %@AB@%EDX%@AE@% contains the count of pages currently available for allocation as %@AB@%PageLocked%@AE@% pages. Note that many assumptions are not valid. %@AB@%EAX%@AE@%<=%@AB@%EDX%@AE@% is %@AI@%not%@AE@% a valid assumption for instance. %@NL@% Note that in a virtual memory environment it is not a good idea to go soaking up tons of virtual address space. Start with some, then %@AB@%PageReAllocate%@AE@% it to make it bigger if needed. %@NL@% %@CR:C6A00190071 @%%@CR:C6A00190072 @% %@2@%%@CR:C6A00190073 @%%@AB@%GetSetPageOutCount%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned GetSetPageOutCount(NewCount,flags) %@AS@% unsigned NewCount; %@AS@% unsigned flags;%@AE@% This call is for use by the demand paging device. It allows the paging device to manipulate a memory manager parameter associated with demand paging. This parameter is the "page out ahead" count. Whenever a page is paged out to satisfy a page in, an additional PageOutCount-1 pages are also paged out and put on the free list (if possible).There is one bit in the flags: %@NL@% %@AS@% GSPOC_F_Get equ 00000000000000000000000000000001B%@AE@% All other bits must be zero. If GSPOC_F_Get is set, the call returns the current value of the page out count in %@AB@%EAX%@AE@%, and the %@AI@%NewCount%@AE@% parameter is ignored. If GSPOC_F_Get is not set, the call sets the value of the page out count to %@AI@%NewCount%@AE@%. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns the page out count if GSPOC_F_Get is set, else it has no return. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AU@%WARNING%@AE@% This call is intended for use by the PageSwap device, others should not be calling it. Others making this call can disturb the operation of the PageSwap device. ────────────────────────────────────────────────────────────────────────────%@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% There is an equate for the flag bit in VMM.INC, use the equate. %@NL@% %@CR:C6A00190074 @%%@CR:C6A00190075 @% %@2@%%@CR:C6A00190076 @%%@AB@%GetSysPageCount%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned GetSysPageCount(flags) %@AS@% unsigned flags;%@AE@% This call is used to obtain the current count of system (PG_SYS) 4K pages. There are currently no bits defined in the %@AI@%flags%@AE@%, and this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% The return value is the 32 bit count of 4K pages allocated as PG_SYS pages in the system. %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% It is generally true that this number is the size of enhanced Windows. However, this is the general case only. %@NL@% %@CR:C6A00190077 @%%@CR:C6A00190078 @% %@2@%%@CR:C6A00190079 @%%@AB@%GetVMPgCount%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned long GetVMPgCount(VMHandle,flags) %@AS@% unsigned VMHandle; %@AS@% unsigned flags;%@AE@% This call is used to get the current count of 4K pages allocated to a particular VM. The %@AI@%VMHandle%@AE@% parameter must be a valid VM handle and indicates the VM to get the allocated page count of. There are currently no bits defined in the %@AI@%flags%@AE@%, this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% The return value is a 64 bit long which is actually two 32 bit DWORDS. The Low DWORD (%@AB@%EAX%@AE@%) is the total count of pages (of all types but PG_SYS) in the system allocated for this VM. The High DWORD (%@AB@%EDX%@AE@%) is the count of pages which are allocated to this VM, but which are not mapped into the VM's 1Meg address space at the current time. Value (both dwords) is 0 if the call failed (invalid %@AI@%VMHandle%@AE@%). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% You should be careful about assuming that %@AB@%EAX-EDX%@AE@% is the size of the VM. It is in one sense, but not in the standard MS-DOS senses. %@NL@% %@CR:C6A00190080 @%%@CR:C6A00190081 @% %@2@%%@CR:C6A00190082 @%%@AB@%MapIntoV86%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned MapIntoV86(hMem,VMHandle,VMLinPgNum,nPages,PageOff,flags) %@AS@% unsigned hMem; %@AS@% unsigned VMHandle; %@AS@% unsigned VMLinPgNum; %@AS@% unsigned nPages; %@AS@% unsigned PageOff; %@AS@% unsigned flags;%@AE@% This call is used to map some or all of the pages of a memory block into a specific VM's Virtual 8086 address space.%@AI@% hMem%@AE@% is the value returned from a previous call to %@AB@%PageAllocate%@AE@% or %@AB@%PageReAllocate%@AE@% and indicates the block to be mapped. %@AI@%VMHandle%@AE@% parameter must be a valid VM handle and indicates the VM into which the map is to occur. %@AI@%VMLinPgNum%@AE@% is the address in the 1M V86 address space where the map will start (this is a page number, thus linear address 60000h = page 60h). Alignment considerations of this address (beyond 4K alignment) are the responsibility of the caller. Map addresses below page 10h, or above 10Fh will cause an error. %@AI@%nPages%@AE@% is the number of pages to map. %@AI@%PageOff %@AE@%is the number of pages into the %@AI@%hMem%@AE@% block to the first page of the block which is to be mapped at %@AI@%VMLinPgNum%@AE@% (thus PageOff is 0 to map the first page of %@AI@%hMem%@AE@% at VMLinPgNum). %@AI@%nPages%@AE@% and %@AI@%PageOff%@AE@% allow one %@AI@%hMem%@AE@% block to be scatter mapped into different VM locations. An error will occur if %@AI@%PageOff%@AE@% +%@AI@% nPages%@AE@% is greater than the size of %@AI@%hMem%@AE@%. %@NL@% Current flags bits: %@NL@% %@AS@% PageDEBUGNulFault EQU 00000000000000000000000000010000B%@AE@% All unused bits must be zero. PageDEBUGNulFault, if set, indicates that if %@AI@%hMem%@AE@% is the handle of the NUL system page, and this is the DEBUG version of enhanced Windows, access to these pages should cause a page fault DEBUG exception. This bit is ignored if %@AI@%hMem%@AE@% is not the system NUL page handle, or this is not enhanced Windows DEBUG. %@NL@% It is generally true that %@AI@%hMem%@AE@% blocks mapped with this call should not be composed of PG_SYS pages. This is not disallowed, but is not advised. %@NL@% There is a special %@AI@%hMem%@AE@% handle that can be used with this call. The value of this handle is obtained by calling the routine %@AB@%GetNulPageHandle%@AE@% (actual name %@AB@%_GetNulPageHandle%@AE@%) which will return you this special %@AI@%hMem%@AE@% handle in %@AB@%EAX%@AE@%. This is the %@AI@%hMem %@AE@%of the system NUL page. This page is used to occupy regions of the address space which are "unused" but for which it is not desirable to cause a page fault if they are accessed. The NUL page is multiply mapped at many locations in the system, so its contents are always random. Under enhanced Windows DEBUG, a fault occurs if the NUL page is touched and the PageDEBUGNulFault bit was set on the call which mapped the page. %@NL@% If the %@AB@%PageSwap%@AE@% device is type one (%@AI@%not%@AE@% direct to hardware), there is an %@AI@%implied%@AE@% PageLock on the pages mapped with this call, and an %@AI@%implied%@AE@% %@AB@%PageUnlock%@AE@% on the pages which this call is mapping over. This is consistent with the fact that pages mapped into V86 address space must be locked (V86 memory cannot be demand paged). If the %@AB@%PageSwap%@AE@% device is type two (direct to hardware) than the implied lock and unlock done by this call are disabled because in the case of a type two %@AB@%PageSwap%@AE@% device V86 memory CAN be demand paged. See the %@AB@%PageAllocate%@AE@% documentation for a description of the different %@AB@%PageSwap%@AE@% device types and their relevance. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns a nonzero value if the map is succesful, returns 0 value if the map was unsuccesful (invalid %@AI@%hMem,%@AE@% invalid %@AI@%VMHandle%@AE@%, map range illegal, size discrepancy, insufficient memory on implied PageLock). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% The implied %@AB@%PageLock%@AE@%, which is performed on all of the pages mapped if the %@AB@%PageSwap%@AE@% device is type oneAg, is consistent with the fact that V86 memory cannot be Demand Paged while the VM is in a runable state. Whenever the V86 memory mapping is changed via %@AB@%MapIntoV86%@AE@%, the previous memory that was mapped in that region of the VM is unlocked. The correct way to think of this is that there is an implied %@AB@%PageLock%@AE@% whenever memory is mapped into a V86 context, and an implied %@AB@%PageUnlock%@AE@% whenever it is "unmapped" from the V86 context. This "unmapping" can occur when: A different handle (including the NulPageHandle) is %@AB@%MapIntoV86ed %@AE@%or %@AB@%LinMapIntoV86ed%@AE@% to the region, or a %@AB@%PhysIntoV86%@AE@% is performed to the region. %@NL@% There is nothing to prevent you from mapping the same block, or piece of a block, into multiple places in a VM, or into multiple VMs. Such operations are not particularly advisable though. For one thing, the reporting of memory owned by a VM will be disturbed. For this reason it is also not generally a good idea to map pages that were allocated as belonging to one VM into a different VM. The one exception to this general rule is the request for a map by one VM to look at the memory of a different VM. Such maps should be of a relatively short duration. %@NL@% The page attributes for these pages will be P_USER+P_PRES+P_WRITE. P_DIRTY and P_ACC will be cleared by the call. PG_TYPE will be set to whatever the type of the hMem pages are. %@NL@% The Flag bit equates are defined by including VMM.INC, please use the equates. %@NL@% The intent of %@AB@%MapIntoV86 %@AE@%support for pages between page 10h and FirstV86Page is to support WIN386 devices which have %@AB@%Allocate_Global_V86_Data_Area%@AE@% a %@AB@%GVDAPageAlign%@AE@% region. Use of mapping in this region to other addresses can easily crash the system and should be avoided. %@NL@% Regions which span across %@AB@%FirstV86Page%@AE@% are not allowed. %@NL@% The reason for the page 10h limitation is that on most versions of the Intel 80386 CPU there is an errata which prevents you from setting up a Linear != Physical address mapping in the first 64K of the address space. %@NL@% %@CR:C6A00190083 @%%@CR:C6A00190084 @% %@2@%%@CR:C6A00190085 @%%@AB@%ModifyPageBits%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned %@AS@%ModifyPageBits(VMHandle,VMLinPgNum,nPages,bitAND,bitOR,pType,flags) %@AS@% unsigned VMHandle; %@AS@% unsigned VMLinPgNum; %@AS@% unsigned nPages; %@AS@% unsigned bitAND; %@AS@% unsigned bitOR; %@AS@% unsigned pType; %@AS@% unsigned flags;%@AE@% This call is used to modify the page protection bits associated with PG_HOOKED pages in the V86 address space of a VM. It allows the P_PRES, P_WRITE, and P_USER bits of the pages to be modified along with PG_TYPE if appropriate. The %@AI@%VMHandle %@AE@%parameter must be a valid VM Handle and indicates the VM whose page bits are to be modified. %@AI@%VMLinPgNum%@AE@% is the page number in the 1M V86 VM address space where the modification will start (this is a page number, thus linear address A0000h = page A0h). When clearing the P_PRES bit (making pages not present), all of the pages specified (%@AI@%nPages%@AE@% starting at %@AI@%VMLinPgNum%@AE@%) must be PG_HOOKED pages for which a HOOK Page Fault handler has been registered, and %@AI@%pType%@AE@% must be PG_HOOKED. %@AI@%nPages%@AE@% is the number of pages to modify the bits of. Addresses below the start of VM specific memory, or above 10Fh will cause an error. %@AI@%bitAND%@AE@% is an AND mask for the bits, %@AI@%bitOR%@AE@% is an OR mask. Thus to clear P_PRES, P_WRITE, and P_USER, %@AI@%bitAND%@AE@% would be (%@AI@%not%@AE@% P_PRES+P_WRITE+P_USER), and %@AI@%bitOR%@AE@% would be zero. To set P_USER, and clear P_WRITE, leaving P_PRES unchanged, bitAND would be (NOT P_WRITE), and %@AI@%bitOR%@AE@% would be P_USER. Having bits other than P_WRITE, and P_USER set in %@AI@%bitOR%@AE@% will cause an error. Having bits other than P_PRES, P_WRITE, and P_USER clear in %@AI@%bitAND%@AE@% will cause an error. %@NL@% This call always has the side effect of clearing P_DIRTY and P_ACC. Thus to just clear these two bits, give a %@AI@%bitAND%@AE@% of 0FFFFFFFFh, and a %@AI@%bitOR%@AE@% of 0.%@AI@% %@AI@%pType%@AE@% indicates a value to be placed in the PG_TYPE field. The allowed values are: %@NL@% %@AS@% PG_HOOKED EQU 7 %@AS@% PG_IGNORE EQU -1 (0FFFFFFFFh)%@AE@% Any other value will cause an error. PG_IGNORE indicates that the PG_TYPE field is not to be modified by the call. This is the value that %@AI@%must%@AE@% be set if P_PRES bit is being set (or being left set). PG_HOOKED must be specified if the P_PRES bit is being cleared by the call. Recall that making a PhysIntoVM call sets the type field for the physical pages to PG_SYS. This parameter is provided so that the page types can be reset to PG_HOOKED when the mapping is changed to not present. Recall that MapIntoVM also resets the PG_TYPE field to the type of the pages of %@AI@%hMem.%@AE@% There are currently no bits defined in the %@AI@%flags%@AE@%, this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns a nonzero value if successful, returns 0 value if unsuccessful (invalid %@AI@%VMHandle,%@AE@% invalid bits in %@AI@%bitAND%@AE@% or %@AI@%bitOR,%@AE@% invalid %@AI@%pType,%@AE@% page range bad). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% You cannot use this call to set the Present bit. You may either clear the present bit, or leave it unaffected. Use %@AB@%MapIntoV86 %@AE@%or %@AB@%PhysIntoV86%@AE@% to make pages present. %@NL@% %@CR:C6A00190086 @%%@CR:C6A00190087 @% %@2@%%@CR:C6A00190088 @%%@AB@%PageAllocate%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned PageAllocate(nPages,pType,VMHandle,AlignMask,minPhys, %@AS@%maxPhys,PhysAddrPTR,flags) %@AS@% unsigned nPages; %@AS@% unsigned pType; %@AS@% unsigned VMHandle; %@AS@% unsigned AlignMask; %@AS@% unsigned minPhys; %@AS@% unsigned maxPhys; %@AS@% unsigned *PhysAddrPTR; %@AS@% unsigned flags;%@AE@% This is the call to allocate a block of memory. The memory allocated is actually just linear address space, whether there is actually physical memory mapped for this block as part of the allocation is specified by the flags.%@AI@% nPages%@AE@% is a 32 bit unsigned integer which is the size in 4K pages of the block. %@AI@%pType%@AE@% indicates the type of page(s) being allocated: %@NL@% %@AS@% PG_VM EQU 0 %@AS@% PG_SYS EQU 1 %@AS@% PG_HOOKED EQU 7 %@AE@% PG_VM pages are pages which are specific to a particular VM context. The handle of PG_VM memory blocks will typically be placed in the VM Control Block someplace. PG_HOOKED pages are pages which will be mapped into the VM at locations where the component has registered a HookPageFault handler. Like PG_VM pages, PG_HOOKED pages are specific to a particular VM context. The %@AI@%VMHandle%@AE@% parameter must be a valid VM Handle for all page types except PG_SYS. PG_SYS pages are global system pages which are valid in all VM contexts (pages are specific to the enhanced Windows system component which allocates them, rather than to a VM). The %@AI@%VMHandle%@AE@% parameter is not relevant to PG_SYS pages and it %@AI@%must%@AE@% be set to 0 when allocating PG_SYS pages. %@NL@% Current flags bits: %@NL@% %@AS@% PageZeroInit EQU 00000000000000000000000000000001B %@AS@% PageUseAlign EQU 00000000000000000000000000000010B %@AS@% PageContig EQU 00000000000000000000000000000100B %@AS@% PageFixed EQU 00000000000000000000000000001000B %@AS@% PageLocked EQU 00000000000000000000000010000000B PageLockedIfDP EQU %@AS@%00000000000000000000000100000000B%@AE@% All unused bits %@AI@%must be zero%@AE@%. %@AB@%PageLocked%@AE@%, if set, indicates that a %@AB@%PageLock%@AE@% is implied as part of the %@AB@%PageAllocate%@AE@% operation. This forces the allocate to make all pages of the handle present when the handle is allocated consistent with the implied %@AB@%PageLock%@AE@%. %@AB@%PageLockedIfDP%@AE@%, if set, indicates that a %@AB@%PageLock%@AE@% is implied as part of the %@AB@%PageAllocate%@AE@% %@AI@%only if the%@AE@% %@AB@%PageSwap %@AS@%%@AE@%%@AI@%device is not direct to hardware%@AE@%. There are two basic behavior types for the %@AB@%PageSwap%@AE@% device. Type one pages through MS-DOS and/or the ROM BIOS. This type of %@AB@%PageSwap%@AE@% device places restrictions on the ability to demand page certain types of system memory because of the fact that it runs partly in V86 mode as part of its operation. %@AB@%PageSwap%@AE@% type two pages by talking directly to the disk hardware. This second type of %@AB@%PageSwap%@AE@% device removes some of the restrictions because it runs completely in protected mode when accessing the paging device. %@AB@%PageLocked%@AE@% indicates that the memory should be locked regardless of which type of %@AB@%PageSwap%@AE@% device is present. %@AB@%PageLockedIfDP%@AE@% indicates that this memory only needs to be locked if the %@AB@%PageSwap%@AE@% device is type one. PageFixed, if set, indicates behavior similar to %@AB@%PageLocked%@AE@% as far as the implied %@AB@%PageLock%@AE@% is concerned, and in addition a Fixed handle can %@AI@%never%@AE@% be unlocked, and its linear address will %@AI@%never %@AE@%change (via %@AB@%PageReAllocate%@AE@%). Note that ReAllocation of a Fixed handle will generally not succeed due to the Fixed restriction on the ability to change the linear address of the handle. Note that an allocation without an implied %@AB@%PageLock%@AE@% via %@AB@%PageLocked%@AE@%, %@AB@%PageLockedIfDP%@AE@%, or %@AB@%PageFixed%@AE@% will simply allocate linear address space. The pages of such a handle will be made present "on demand" when the address space is touched. If it is desired to make part of the handle present to perform some function, use %@AB@%PageLock%@AE@% to force the contents to be loaded. PageUseAlign, if set, indicates that the %@AI@%AlignMask%@AE@%, %@AI@%minPhys%@AE@%, %@AI@%maxPhys%@AE@%, and %@AI@%PhysAddrPTR%@AE@% parameters are specified. If PageUseAlign is clear, the %@AI@%AlignMask%@AE@%, %@AI@%minPhys%@AE@%, %@AI@%maxPhys%@AE@%, and %@AI@%PhysAddrPTR%@AE@% parameters are set to 0 and ignored. Note that if PageUseAlign is set, PageFixed must also be specified. It makes no sense to have an aligned memory handle which is not fixed. PageZeroInit, if set, indicates that if the allocation is succesful, the memory is to be initialized with value 0 in all bytes of the block. If PageZeroInit is clear, the block will have completely random values in it. PageContig, if set, indicates that the Physical memory pages of the block are to occupy sequential Physical memory addresses (memory is "physically contiguous"). %@AI@%PageContig is ignored if PageUseAlign is not set.%@AE@% %@NL@% PageUseAlign is provided to assist device drivers that wish to allocate buffers for use by the device which have additional alignment restrictions enforced by the hardware (such as 64K and 128K alignment for DMA). If the PageUseAlign bit is set, AlignMask specifies an alignment (power of 2> 4k) requirement for the first physical page of the block. Physical page numbers are the physical address of the page shifted right by 12. Correct alignment is tested for by ANDing %@AI@%AlignMask%@AE@% with the first physical page number and testing for zero. If the AND is zero, the page has the correct alignment. Thus: %@NL@% %@AS@% 00000000h = 4K alignment (ignore AlignMask) %@AS@% 00000001h = 8K alignment %@AS@% 00000003h = 16K alignment %@AS@% 00000007h = 32K alignment %@AS@% 0000000Fh = 64K alignment %@AS@% 0000001Fh = 128K alignment%@AE@% Remember that you will probably also want to set the PageContig bit. %@AI@%minPhys%@AE@% and %@AI@%maxPhys%@AE@% place additional physical address restrictions on the physical pages of the memory block. These specify the minimum and maximum allowed physical page numbers. All physical page numbers of the block must be >=minPhys, and <maxPhys. For instance, for setting up a DMA buffer for an 80386 accelerator card in a PC XT, the buffer needs to be physically restricted to pages less than 1 MB since the XT DMA controller cannot DMA into pages above 1 MB. In this case, minPhys would be 0, and maxPhys would be 100h. If you don't want to specify this (i.e. you just want %@AI@%AlignMask%@AE@%), set %@AI@%minPhys%@AE@% to 0, and maxPhys to 0FFFFFFFFh. Note that when PageUseAlign is set, the physical page address (physical page number shifted left by 12) of the start of the block will be returned via the %@AI@%PhysAddrPTR%@AE@% pointer parameter. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%PageUseAlign PageAllocations can only be performed during device %@AI@%initialization. Aligned PageAllocations will fail if done after device %@AI@%initialization.%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% The return value is a 64 bit long which is actually two 32 bit DWORDS. The Low DWORD (%@AB@%EAX%@AE@%) is the memory handle of the block. The High DWORD (%@AB@%EDX%@AE@%) is the 32 bit RING 0 address (offset relative to standard enhanced Windows Ring 0 DS) of the block. If %@AB@%PageUseAlign%@AE@% was specified, the physical address of the start of the block is placed in the DWORD pointed to by %@AB@%PhysAddrPTR%@AE@%. Value (both DWORDs) is 0 if the allocation failed (insufficient memory). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% You should be careful about making assumptions about any apparent relationship between the memory handle and the blocks RING 0 or physical address. Any such apparent relationship is subject to change in a later release. %@NL@% PhysAddrPTR had better point somewhere reasonable when PageUseAlign is specified. There is no way to check its validity, if it's garbage you'll either cause a page fault or stomp on something you shouldn't. %@NL@% %@AB@%PageAllocation%@AE@% of 0 length blocks is not allowed. %@NL@% %@AB@%PageLocked%@AE@% and %@AB@%PageLockedIfDP%@AE@% should not both be set. Only one, or the other, or neither are valid settings. %@AI@%Note also that%@AE@% %@AB@%PageLockedIfDP%@AE@% %@AI@%cannot %@AI@%be set on calls made before the init complete system control call is made%@AE@%. This is because it is not possible to ask the %@AB@%PageSwap%@AE@% device what type it is before it has been initialized. %@NL@% The Flag bit equates are defined by including VMM.INC, please use the equates. %@NL@% %@CR:C6A00190089 @%%@CR:C6A00190090 @% %@2@%%@CR:C6A00190091 @%%@AB@%PageFree%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned PageFree(hMem,flags) %@AS@% unsigned hMem; %@AS@% unsigned flags;%@AE@% This call is used to free an existing block of pages. %@AI@%hMem%@AE@% is the value returned from a previous call to %@AB@%PageAllocate%@AE@% or %@AB@%PageReAllocate%@AE@% and indicates the block to be freed. There are currently no bits defined in the flags, this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns nonzero value if the block was succesfully freed, zero if the free was unsuccesful (invalid %@AI@%hMem%@AE@%). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% It is the responsibility of the enhanced Windows system components which allocate non-PG_SYS pages to free them when the VM they are associated with is destroyed. There is no "automatic" freeing of such memory done by the memory manager. PG_SYS pages do not need to be freed before enhanced Windows exits. %@NL@% It is not an error to %@AB@%PageFree%@AE@% a handle which is all or partially locked. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AU@%WARNING%@AE@% Be very careful about PageFreeing blocks which are currently MapIntoV86ed to some VM context. Doing this can result in a crash. ────────────────────────────────────────────────────────────────────────────%@NL@% %@CR:C6A00190092 @%%@CR:C6A00190093 @% %@2@%%@CR:C6A00190094 @%%@AB@%PageGetAllocInfo%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned long PageGetAllocInfo(flags) %@AS@% unsigned flags;%@AE@% This call is used to obtain information prior to a %@AB@%PageAllocate%@AE@% or %@AB@%PageReallocate%@AE@% call. It returns the largest block of linear address space that could be allocated, together with information relating to allocation of Locked or Fixed memory. There are currently no bits defined in the flags, this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% The return value is a 64 bit long which is actually two 32 bit DWORDs. The Low DWORD (%@AB@%EAX%@AE@%) is the 32 bit count of free 4K pages in the system which could be allocated with the %@AB@%PageAllocate%@AE@% as %@AI@%not %@AE@%%@AB@%PageLocked%@AE@% or %@AB@%PageFixed%@AE@% memory. The High DWORD (%@AB@%EDX%@AE@%) is the 32 bit count of pages available for allocation as %@AB@%PageLocked%@AE@% pages at the current time. %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% You should be careful about making assumptions about being able to turn around and issue a call to allocate all of the pages returned by this call. Besides any alignment considerations, it is possible someone could get in and allocate some or all of the pages before you. This call is intended to be advisory in nature. %@NL@% %@AB@%EAX%@AE@% contains the size of the largest available region of linear address space. %@AB@%EDX%@AE@% contains the count of pages currently available for allocation as %@AB@%PageLocked%@AE@% pages. Notice that many assumptions are not valid. %@AB@%EAX%@AE@% >= %@AB@%EDX%@AE@% is %@AI@%not%@AE@% a valid assumption for instance. %@NL@% You should be very careful about turning around and doing a %@AB@%PageAllocate%@AE@% with the %@AB@%EAX%@AE@% return from this call. You can cause all sorts of odd behavior if you take up all of the linear address space. You should allocate memory on an as needed basis instead of allocating huge blocks of memory most of which you do not use. %@NL@% %@CR:C6A00190095 @%%@CR:C6A00190096 @% %@2@%%@CR:C6A00190097 @%%@AB@%PageGetSizeAddr%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned long PageGetSizeAddr(hMem,flags) %@AS@% unsigned hMem; %@AS@% unsigned flags;%@AE@% This call is used to get the size and linear address of an existing block of pages. %@AI@%hMem%@AE@% is the value returned from a previous call to %@AB@%PageAllocate%@AE@% or %@AB@%PageReAllocate%@AE@% and indicates the block to get the size and address of. There are currently no bits defined in the flags, this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% The return value is a 64 bit long which is actually two 32 bit DWORDS. The Low DWORD (%@AB@%EAX%@AE@%) is the size in 4K pages of the block. The High DWORD (%@AB@%EDX%@AE@%) is the 32 bit RING 0 address (offset relative to standard enhanced Windows Ring 0 DS) of the block. Value (both DWORDs) is 0 if the call failed (invalid %@AI@%hMem%@AE@%). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% Note that the size of a handle is the total size of the handle and has nothing to do with what pieces of the handle may or may not be present. %@NL@% %@CR:C6A00190098 @%%@CR:C6A00190099 @% %@2@%%@CR:C6A00190100 @%%@AB@%PageLock%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned PageLock(hMem,nPages,PageOff,flags) %@AS@% unsigned hMem; %@AS@% unsigned nPages; %@AS@% unsigned PageOff; %@AS@% unsigned flags;%@AE@% This call is used to lock (make present) all or part of an existing memory handle. %@AI@%hMem%@AE@% is the value returned from a previous call to %@AB@%PageAllocate%@AE@% or %@AB@%PageReAllocate%@AE@% and indicates the block to be locked. %@AI@%nPages%@AE@% specifies the count of pages to be locked. %@AI@%PageOff%@AE@% specifies the page offset from the start of the block of the first page to be locked. %@AI@%nPages%@AE@% together with %@AI@%PageOff%@AE@% allow all or only part of the%@AI@% hMem%@AE@% block to be locked. An error will occur if %@AI@%PageOff%@AE@%+%@AI@%nPages%@AE@% is greater than the size of %@AI@%hMem%@AE@%. There are currently no bits defined in the %@AI@%flags%@AE@%, this parameter must be set to 0. %@NL@% Current flags bits: %@NL@% %@AS@% PageLockedIfDP EQU 00000000000000000000000100000000B%@AE@% All unused bits %@AI@%must be zero%@AE@%. %@AB@%PageLockedIfDP%@AE@%, if set, indicates that the lock only needs to be done if the %@AB@%PageSwap%@AE@% device is not direct to hardware. In the case where the %@AB@%PageSwap%@AE@% device is of type two (direct to hardware), calls to this routine with %@AB@%PageLockedIfDP%@AE@% set are effectively NOPs. See the %@AB@%PageAllocate%@AE@% documentation for a description of the different %@AB@%PageSwap %@AB@%%@AE@%device types and their relevance. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns nonzero value if the block was succesfully locked, zero if the lock was unsuccesful (invalid %@AI@%hMem%@AE@%, insufficient memory). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% This call may be issued on %@AI@%hMem%@AE@% blocks which are %@AB@%PageFixed%@AE@%, but this is a wasted call since %@AB@%PageFixed%@AE@% blocks are always locked (present). %@NL@% Because of the overcommit associated with demand paging, callers must be prepared for this call to fail due to unavailability of sufficient memory to make the region present. %@NL@% %@AI@%Note that%@AE@% %@AB@%PageLockedIfDP%@AE@% %@AI@%cannot be set on calls made before the init %@AI@%complete system control call is made%@AE@%. This is because it is not possible to ask the %@AB@%PageSwap%@AE@% device what type it is before it has been initialized. %@NL@% Each Page of a handle has an individual lock count. Each lock increments the counter. The counter must go to 0 for the page to be unlocked. This means that if the handle is locked 5 times, it has to be unlocked 5 times. %@NL@% Do not leave handles locked when they don't need to be, unlock handles as soon as possible to make the physical memory associated available for use by demand paging. %@NL@% The Flag bit equates are defined by including VMM.INC, please use the equates. %@NL@% %@CR:C6A00190101 @%%@CR:C6A00190102 @% %@2@%%@CR:C6A00190103 @%%@AB@%PageOutDirtyPages%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned PageOutDirtyPages(nPages,flags) %@AS@% unsigned nPages; %@AS@% unsigned flags;%@AE@% This call is for use by the demand paging device. It allows the paging device to periodically "flush" out dirty pages to prevent a large number of dirty pages from accumulating in the system. %@AI@%nPages%@AE@% is the maximum number of dirty pages to flush at this time. %@NL@% Current flags bits: %@NL@% %@AS@% PagePDPSetBase EQU 00000000000000000100000000000000B %@AS@% PagePDPClearBase EQU 00000000000000001000000000000000B %@AS@% PagePDPQueryDirty EQU 00000000000000100000000000000000B%@AE@% All unused bits %@AI@%must be zero%@AE@%. The %@AB@%PageSwap%@AE@% device may wish to flush out all dirty pages in the system as part of a "background" activity ("write out ahead"). These two bits allow this to be done, it allows the caller to manipulate a variable associated with the page out scan which will cause the scan to stop. This "base" page number that is set allows the %@AB@%PageSwap%@AE@% device to tell when the %@AB@%PageOutDirtyPages%@AE@% call has completed a scan of the entire address space looking for dirty pages. %@AB@%PagePDPSetBase%@AE@% tells %@AB@%PageOutDirtyPages%@AE@% to set the base page number to the current scan start point. %@AB@%PagePDPClearBase%@AE@% tells %@AB@%PageOutDirtyPages%@AE@% to clear the base page number, setting it to NONE. A return value of 0 is used to detect when a %@AB@%PageOutDirtyPages%@AE@% call has stoped because it has hit the base page. This is not totally reliable, but is a reasonable approximation, since %@AB@%PageOutDirtyPages%@AE@% can return 0 because there are no dirty pages (this is rather unlikely). %@AB@%PagePDPQueryDirty%@AE@%, if set, indicates that the call is to return the current count of DIRTY demand pageable pages, the %@AI@%nPages %@AE@%argument and all other flags are ignored if this bit is set (call returns the count of dirty pages as its sole function). %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns the actual count of dirty pages flushed by the call (0 is valid). %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AU@%WARNING%@AE@% This call is intended for use by the PageSwap device, others should not be calling it. Others making this call can disturb the operation of the PageSwap device. ────────────────────────────────────────────────────────────────────────────%@NL@% %@3@%%@AB@%Notes%@AE@%%@EH@%%@NL@% This call functions something like a partial "commit" of the dirty pages in the system. Note that ALL of the dirty demand pages can be flushed by specifying a large value for %@AI@%nPages%@AE@% (like 0FFFFFFFFh). %@NL@% This call operates only on current page out candidates. %@NL@% The Flag bit equates are defined by including VMM.INC, please use the equates. %@NL@% %@CR:C6A00190104 @%%@CR:C6A00190105 @% %@2@%%@CR:C6A00190106 @%%@AB@%PageReAllocate%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned PageReAllocate(hMem,nPages,flags) %@AS@% unsigned hMem; %@AS@% unsigned nPages; %@AS@% unsigned flags;%@AE@% This call is used to grow or shrink or reinitialize an existing block of memory. %@AI@%hMem%@AE@% is the value returned from a previous %@AB@%PageAllocate%@AE@% or %@AB@%PageReAllocate%@AE@% call and indicates the block to be reallocated. %@AI@%Note that %@AI@%handles allocated with%@AE@% %@AB@%PageUseAlign%@AE@% %@AI@%set cannot be%@AE@% %@AB@%PageReAllocated%@AE@%. %@AI@%nPages%@AE@% is a 32 bit unsigned integer which is the new size in 4K pages of the block. %@NL@% Current flags bits: %@NL@% %@AS@% PageZeroInit EQU 00000000000000000000000000000001B %@AS@% PageZeroReInit EQU 00000000000000000000000000100000B %@AS@% PageNoCopy EQU 00000000000000000000000001000000B %@AS@% PageLocked EQU 00000000000000000000000010000000B %@AS@% PageLockedIfDP EQU 00000000000000000000000100000000B%@AE@% All unused bits %@AI@%must be zero%@AE@%. %@AB@%PageLocked%@AE@% and %@AB@%PageLockedIfDP%@AE@%, if set, indicates that if this %@AB@%PageReAllocation%@AE@% is growing the size of the handle, the pages added to the handle are to be %@AB@%PageLocked%@AE@% or %@AB@%PageLockedIfDP%@AE@% (see %@AB@%PageAllocate%@AE@% for explanation). If the %@AB@%PageReAllocation%@AE@% is not growing the handle these bits are ignored. %@AI@%Note that%@AE@% %@AB@%PageFixed%@AE@% %@AI@%is not%@AE@% %@AI@%specified%@AE@%, %@AB@%PageReAllocation%@AE@% of a %@AB@%PageFixed%@AE@% handle is implied as %@AB@%PageFixed%@AE@% by the handle itself. %@AB@%PageZeroInit%@AE@%, if set, indicates that if the reallocation is succesful, and the re-allocation is growing the size of the block, the "grow area" of the block is to be initialized with value 0 in all bytes. This bit is ignored on a re-allocation which is not growing the size of the block. %@AB@%PageZeroReInit%@AE@% , if set, indicates that the entire block is to be reinitialized with value zero in all bytes of the block. %@AB@%PageNoCopy%@AE@%, if set, indicates that the previous contents of the block are irrelevant, and don't need to be copied into the newly sized block. There is no reason that more than one of these three bits should be set. If none of the bits are set, the previous contents of the block are copied into the new block, up to the lesser of the size of the new block, and the size of the old block, and the "grow area", if any, is not initialized with anything. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% The return value is a 64 bit long which is actually two 32 bit DWORDS. The Low DWORD (%@AB@%EAX%@AE@%) is the memory handle of the new block. The High DWORD (%@AB@%EDX%@AE@%) is the 32 bit RING 0 address (offset relative to standard enhanced Windows Ring 0 DS) of the block. Value (both DWORDs) is 0 if the reallocation failed (insufficient memory, handle wrong type, invalid handle). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% Do not make assumptions about the relationship between the passed in %@AI@%hMem%@AE@% and the Address returned, if specified. Assume that the returned %@AI@%hMem%@AE@% and address are always different than the passed in %@AI@%hMem%@AE@% and previous address. %@NL@% In the case where this call fails, the passed in %@AI@%hMem%@AE@% and previous address of the block remain valid. In the case where this call works and returns a new %@AI@%hMem%@AE@% and address, the passed in%@AI@% hMem%@AE@% and previous address are no longer valid (old block has been PageFreed). %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AU@%WARNING%@AE@% Be very careful about PageReAllocating blocks which are currently MapIntoV86ed to some VM context. Doing this can result in a crash. ────────────────────────────────────────────────────────────────────────────%@NL@% %@AB@%PageLocked%@AE@% and %@AB@%PageLockedIfDP%@AE@% should not both be set. Only one, or the other, or neither are valid settings. Note also that %@AB@%PageLockedIfDP%@AE@% cannot be set on calls made before the init complete system control call is made. This is because it is not possible to ask the %@AB@%PageSwap%@AE@% device what type it is before it has been initialized. %@NL@% Note that this call can be used to reset the contents of an existing block to 0 by setting %@AI@%nPages%@AE@% to the current size of the block and setting PageZeroReInit. %@NL@% You cannot %@AB@%PageReAllocate%@AE@% a block to size 0, use %@AB@%PageFree%@AE@%. %@NL@% The Flag bit equates are defined by including VMM.INC, please use the equates. %@NL@% %@CR:C6A00190107 @%%@CR:C6A00190108 @% %@2@%%@CR:C6A00190109 @%%@AB@%PageUnLock%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned PageUnLock(hMem,nPages,PageOff,flags) %@AS@% unsigned hMem; %@AS@% unsigned nPages; %@AS@% unsigned PageOff; %@AS@% unsigned flags;%@AE@% This call is used to unlock all or part of an existing memory handle that was previously locked. %@AI@%hMem%@AE@% is the value returned from a previous call to %@AB@%PageAllocate%@AE@% or %@AB@%PageReAllocate%@AE@% and indicates the block to be unlocked. %@AI@%nPages%@AE@% specifies the count of pages to be unlocked.%@AI@% PageOff%@AE@% specifies the page offset from the start of the block of the first page to be unlocked. %@AI@%nPages%@AE@% together with %@AI@%PageOff %@AE@%allow all or only part of the %@AI@%hMem%@AE@% block to be unlocked. An error will occur if %@AI@%PageOff%@AE@%+%@AI@%nPages %@AE@%is greater than the size of %@AI@%hMem%@AE@%. %@NL@% Current flags bits: %@NL@% %@AS@% PageLockedIfDP EQU 00000000000000000000000100000000B %@AS@% PageMarkPageOut EQU 00000000000000000010000000000000B%@AE@% All unused bits must be zero. %@AB@%PageLockedIfDP%@AE@%, if set, indicates that the unlock only needs to be done if the %@AB@%PageSwap%@AE@% device is not direct to hardware. In the case where the %@AB@%PageSwap%@AE@% device is of type two (direct to hardware), calls to this routine with %@AB@%PageLockedIfDP%@AE@% set are effectively NOPs. See the %@AB@%PageAllocat%@AE@%e documentation for a description of the different %@AB@%PageSwap%@AE@% device types and their relevance. %@AB@%PageMarkPageOut%@AE@%, if set, indicates that if this unlock actually does unlock the pages (lock count goes to 0) the pages are to be made prime candidates for page out. This flag should only be set if it is unlikely that these pages are going to be touched for a while. Effectively what this does is clear the P_ACC bits of the pages which causes them to be first level page out candidates. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns nonzero value if the block was succesfully unlocked, zero if the lock was unsuccesful (invalid %@AI@%hMem,%@AE@% no part of range is locked). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% This call %@AI@%may%@AE@% be issued on %@AI@%hMem%@AE@% blocks which are %@AB@%PageFixed%@AE@%, but this is a wasted call since %@AB@%PageFixed%@AE@% blocks cannot be unlocked. %@NL@% Note that %@AB@%PageLockedIfDP%@AE@% cannot be set on calls made before the init complete system control call is made. This is because it is not possible to ask the %@AB@%PageSwap%@AE@% device what type it is before it has been initialized. %@NL@% Each page of a handle has an individual lock count. Each lock increments the counter. The counter must go to 0 for the page to be unlocked. This means that if the handle is locked 5 times, it has to be unlocked 5 times. %@NL@% The Flag bit equates are defined by including VMM.INC, please use the equates. %@NL@% %@CR:C6A00190110 @%%@CR:C6A00190111 @% %@2@%%@CR:C6A00190112 @%%@AB@%PhysIntoV86%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned PhysIntoV86(PhysPage,VMHandle,VMLinPgNum,nPages,flags) %@AS@% unsigned PhysPage; %@AS@% unsigned VMHandle; %@AS@% unsigned VMLinPgNum; %@AS@% unsigned nPages; %@AS@% unsigned flags;%@AE@% This call is very similar to the %@AB@%MapIntoV86%@AE@% call only instead of taking a memory handle argument, it takes a Physical address (page number). The intent of this call is to "hook up" a particular VM to the actual Physical device memory of a device (such as the video memory of a display adaptor). %@AI@%PhysPage%@AE@% is the physical page number of the start of the region to be mapped, and indicates the block of physical memory to be mapped. For instance, to hook up to the 64K of video memory at A000:000, PhysPage would be A0h and %@AI@%nPage%@AE@%s would be 10h. The %@AI@%VMHandle%@AE@% parameter must be a valid %@AI@%VM %@AI@%handle%@AE@% and indicates the VM into which the map is to occur. %@AI@%VMLinPgNum%@AE@% is the address in the 1Meg V86 address space of the VM where the map will start (this is a page number, thus linear address A0000h = page A0h). Alignment considerations of this address (beyond 4K alignment) are the responsibility of the caller. Map addresses below page 10h, or above 10Fh will cause an error. %@AI@%nPages%@AE@% is the number of pages to map. The physical region is assumed to be contiguous (thus if mapping three pages, they will be PhysPage, PhysPage+1 and PhysPage+2 in that order). If the physical region is not contiguous, you will have to issue multiple calls in succession. There are currently no bits defined in the flags, this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns a nonzero value if the map is succesful, returns 0 value if the map was unsuccesful (invalid %@AI@%VMHandle%@AE@%, map range illegal). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% You are warned to be careful with this call. Very strange things will happen if you specify a physical region which is unoccupied, or belongs to some other device. %@NL@% The page attributes for these pages will be P_USER+P_PRES+P_WRITE. P_DIRTY and P_ACC will be cleared by the call. PG_TYPE will be set to PG_SYS. %@NL@% The intent of %@AB@%PhysIntoV86%@AE@% support for pages between page 10h and FirstV86Page is to support enhanced Windows devices which have %@AB@%Allocate_Global_V86_Data_Area%@AE@% a %@AB@%GVDAPageAlign%@AE@% region. Use of mapping in this region to other addresses can easily crash the system and should be avoided. %@NL@% Regions which span across %@AB@%FirstV86Page%@AE@% are not allowed. %@NL@% The reason for the page 10h limitation is that on most versions of the Intel 80386 CPU there is an errata which prevents you from setting up a Linear Physical address mapping in the first 64k of the address space. %@NL@% %@CR:C6A00190113 @%%@CR:C6A00190114 @% %@2@%%@CR:C6A00190115 @%%@AB@%TestGlobalV86Mem%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned TestGlobalV86Mem(VMLinAddr,nBytes,flags) %@AS@% unsigned VMLinAddr; %@AS@% unsigned nBytes; %@AS@% unsigned flags;%@AE@% Some enhanced Windows devices wish to test whether a given piece of V86 address space is LOCAL to a particular VM, or GLOBAL. The reason for this test is that GLOBAL V86 address ranges are valid and identical in ALL VM contexts, while LOCAL V86 address ranges are valid in only one VM context. This difference can yield optimizations. For instance, operations involving GLOBAL address ranges will typically not need to be "virtualized" in any way since the range is valid and addressable in ALL VM contexts. LOCAL address range operations may have to be "virtualized" though since it is possible for a piece of Virtual Mode code to try and use the address in the "wrong" VM context where the address range is invalid, or points to the wrong memory. This call can be used to test whether a V86 address range is GLOBAL or LOCAL. %@AI@%VMLinAddr%@AE@% is the linear address of the first byte of the V86 address range. This address is relative to the standard RING 0 DS (ie. the linear address of 02C1:0FC5 would be 02C10 + 0FC5 = 3BD5). %@AI@%nBytes%@AE@% is the length of the V86 address range in bytes. There are currently no bits defined in the flags, this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns 0 if the address is not a valid V86 address range, or the address range is LOCAL. Returns 1 if the address range is GLOBAL. Returns 2 if the address range is partly LOCAL and partly GLOBAL (range overlaps a GLOBAL/LOCAL boundary). Returns 3 if the address range is GLOBAL but overlaps with an Instance data region. %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% The distinction between GLOBAL and INSTANCE is rather subtle because INSTANCE pages are "physically global" even though their content is LOCAL. The physical address of instance data pages never changes, thus instance pages are GLOBAL in the physical address sense. The content of instance data regions is per VM though which means they are LOCAL in the sense of "what is in them". %@NL@% The MMGR does not know any of the specifics about what is going on in the regions above FirstV86Page. This routine will return LOCAL for all regions above FirstV86Page, INCLUDING the A0-FF adapter/ROM BIOS area. Some pieces of this region may actually be GLOBAL in terms of how they are used, but this service doesn't know any of the details so it cannot determine this. %@NL@% %@2@%%@CR:C6A00190116 @%%@AB@%19.6 Looking At Physical Device Memory From a VxD%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% VxDs, such as virtual display drivers, that have a certain region of physical address space associated with them, such as Video Memory, need a way to look at the device-specific memory when the device is running. The method by which this is done is by using a service that returns the correct linear address (relative to the standard Ring 0 %@AB@%DS%@AE@%). %@NL@% It may seem to be possible for a VxD together with a Protected Mode application to implement its own private "virtual memory" system by hooking into the IDT and handling page faults itself. You are strongly warned not to try and undertake an implementation of this sort at this time. It is realized that support of such an architecture is a desirable feature for implementation of such things as "virtual files" and "virtual memory mapped devices". This feature will be addressed in a future version of Windows by adding new VMM services, and/or modifying existing services to support it. Since support for this is planned, any and all work that you might undertake on the current version of Windows to implement this will be rendered obsolete when support for it is added to the VMM. %@NL@% %@CR:C6A00190117 @%%@CR:C6A00190118 @% %@2@%%@CR:C6A00190119 @%%@AB@%MapPhysToLinear%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned MapPhysToLinear(PhysAddr,nBytes,flags) %@AS@% unsigned PhysAddr; %@AS@% unsigned nBytes; %@AS@% unsigned flags;%@AE@% %@AI@%PhysAddr %@AE@%is the physical address of the start of the region to be looked at. This is simply the 32 bit physical address, there are no alignment considerations. Physical addresses start at 0, thus the address of physical page 0A0h is 0A0000h. %@AI@%nBytes%@AE@% is the length of the physical region in bytes starting from %@AI@%PhysAddr.%@AE@% This parameter is used to verify that the entire range is addressable. There are currently no bits defined in the %@AI@%flags,%@AE@% this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns the RING 0 DS offset of the first byte of the physical region. Will return 0FFFFFFFFh if the specified range is not addressable. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AU@%WARNING%@AE@% You are warned to be careful with this method. Use of this for purposes beyond looking at device specific physical memory is extremely dangerous and is not approved. ────────────────────────────────────────────────────────────────────────────%@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% Physical addresses do not move. It is perfectly fine to get the linear address of a physical region at Device_Init device call time and then use it later. You do not have to keep recalling %@AB@%MapPhysToLinear%@AE@% every time you want to look at the region. %@NL@% For instance to look at physical page A0h you would do this: %@NL@% %@AS@% VMMCall _MapPhysToLinear,<0A0000h,10000h,0>%@AE@% %@AB@%DS:[EAX]%@AE@% now addresses this physical page. Physical memory is mapped contiguously at this selector so Page 0A1h would be 4096 bytes beyond the above address. %@NL@% %@2@%%@CR:C6A00190120 @%%@AB@%19.7 Data Access Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% These services are used to get the contents of public memory manager variables. All of these services return the value of the associated variable in %@AB@%EAX%@AE@%. %@NL@% %@CR:C6A00190121 @%%@CR:C6A00190122 @% %@2@%%@CR:C6A00190123 @%%@AB@%GetFirstV86Page%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned GetFirstV86Page()%@AE@% This call returns the page number of the first page of VM specific V86 memory. %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% %@AB@%FirstV86Page%@AE@% MOVES during device initialization. Do not get the value at device init time, and then use it later, as the value is invalid. %@NL@% %@CR:C6A00190124 @%%@CR:C6A00190125 @% %@2@%%@CR:C6A00190126 @%%@AB@%GetNulPageHandle%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned GetNulPageHandle()%@AE@% This call returns the memory handle of the system NUL page. %@NL@% %@CR:C6A00190127 @%%@CR:C6A00190128 @% %@2@%%@CR:C6A00190129 @%%@AB@%GetAppFlatDSAlias()%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned GetAppFlatDSAlias()%@AE@% This call returns a selector which can be used by protected mode applications to look at the same data that the standard RING 0 DS looks at. This is useful when a VxD wishes to provide a protected mode service to applications and wants the application to be able to address the same memory that the VxD does. %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% This selector is %@AI@%read only%@AE@%. This is so that the Windows address space is protected from a misbehaved application. It is not recommended that you build a read/write version of this selector. If the application needs to WRITE you should build a descriptor with a much more restricted Base and Limit so that the application can only modify those things which it is allowed to modify. %@NL@% This selector is RPL = DPL = Protected Mode Application Privilege. Notice that a VxD can also use this selector if desired even though the devices run at a different privilege level. Its type is "USE 16", this doesn't mean much since it is a data selector. %@NL@% This is a GDT selector. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AU@%WARNING%@AE@% You must not do a Free_GDT_Selector on this selector. It is not protected, and so it will get freed. Then anyone using it will fault and crash the system. This selector is provided to prevent multiple devices from creating multiple versions of the same selector and wasting GDT entries unnecessarily. ────────────────────────────────────────────────────────────────────────────%@NL@% Notice that enhanced Windows is "USE 32", therefore a protected application, which is "USE 16", will have to use the DB 67h addressing mode override on its instructions to get 32 bit addressing (MASM will do this for you automatically if you set things up correctly). %@NL@% This service can be used to discover what protection ring protectedmode applications run at by doing a LAR on the returned selector. Be very careful about what you do with this bit of information. %@NL@% %@2@%%@CR:C6A00190130 @%%@AB@%19.8 Special Services For Protected Mode APIs%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% These services are provided to support VxDs that need to manipulate protected-mode address space. For example, applications running in protected mode need a way to map regions of protected mode, segmented address space into the virtual machine's virtual 8086 context. A specific example is the MS-DOS INT 21 API. The data pointed to on the INT 21 calls needs to be mapped into the VM's V86 address space so that MS-DOS can access it and perform the requested operation. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AU@%WARNING%@AE@% Do not use these services for purposes other than their intended use. These calls can be quite dangerous and can result in strange behavior or crashes if misused. ────────────────────────────────────────────────────────────────────────────%@NL@% %@2@%%@CR:C6A00190131 @%%@AB@%GetV86PageableArray%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned GetV86PageableArray(VMHandle,ArrayBufPTR,flags) %@AS@% unsigned VMHandle; %@AS@% unsigned ArrayBufPTR; %@AS@% unsigned flags;%@AE@% This call is used to obtain a copy of the bit array of pages whose behavior has been modified via %@AB@%SetResetV86Pageable%@AE@%. This allows the caller to determine which regions of the VM V86 address space have had the normal lock/unlock behavior modified. VMHandle specifies the VM to get the bit map of. ArrayBufPTR points to a buffer large enough to contain the array. The assignment array is an array of 100h bits, one bit for each page in the range 0-100h. Thus the size of the array is ((100h/8)+3)/4 = 8 DWORDS. Bits in the array which are set (=1) indicate pages whose normal lock/unlock behavior is disabled, bits which are clear (=0) indicate pages whose behavior is normal. Thus to test the bit for page number N (0 %@NL@% %@AS@% mov ebx, N MOD 32 ; Bit number in DWORD %@AS@% mov eax, N / 32 ; DWORD index into array %@AS@% bt dword ptr ArrayBufPTR[eax*4],ebx ; Test bit for page N %@AS@% jnc short PageNormal %@AS@% PageModified:%@AE@% Note that this code is mearly intended to illustrate how the bit array works. This code is not the most efficient, or the only way to implement this test. There are currently no bits defined in the flags, this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns non-zero if succesfull, returns zero if the bit array could not be returned (Invalid VMHandle). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% Making this call on a VM whose %@AB@%VMStat_PageableV86%@AE@% bit is clear is not an error, it simply returns a bit array whose bits are all 0. %@NL@% %@CR:C6A00190132 @%%@CR:C6A00190133 @% %@2@%%@CR:C6A00190134 @%%@AB@%LinMapIntoV86%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned long LinMapIntoV86(HLinPgNum,VMHandle,VMLinPgNum,nPages,flags) %@AS@% unsigned HLinPgNum; %@AS@% unsigned VMHandle; %@AS@% unsigned VMLinPgNum; %@AS@% unsigned nPages; %@AS@% unsigned flags;%@AE@% This call is provided to assist the interface address mapper functions. Its purpose is to provide a way for the address mapper to map regions of protected mode address space into a VM V86 address space so that API calls can be performed. This calls operation is very similar to %@AB@%MapIntoV86%@AE@%, the difference being that instead of taking a memory handle, it takes a linear address. The call duplicates the memory map down into the indicated VM's V86 address range. %@AI@%HLinPgNum%@AE@%, together with %@AI@%nPages%@AE@%, indicates the region of protected mode address space, or V86 address space that is to be mapped. This is a page number, linear address 60610000h would be passed in as 60610h. As with %@AB@%MapIntoV86%@AE@% there are implied %@AB@%PageLock%@AE@% and %@AB@%PageUnlocks%@AE@%. Note that the linear address is relative to the standard enhanced Windows Ring 0 DS selector. The %@AI@%VMHandle%@AE@% parameter must be a valid %@AI@%VM handle%@AE@% and indicates the V86 space into which the map is to occur. %@AI@%VMLinPgNum%@AE@% is the address in the 1Meg VM V86 address space where the map will start (this is a page number, thus linear address 60000h = page 60h). Alignment considerations of this address (beyond 4K alignment) are the responsibility of the caller. Map addresses below page 10h, or above 10Fh will cause an error. %@AI@%nPages%@AE@% is the number of pages to map. Note that if %@AI@%HLinPgNum%@AE@% is a V86 page number (at the LOW V86 address (at the LOW V86 address <= page 100h) the call does nothing except return the %@AI@%HLinPgNum%@AE@% parameter in %@AB@%EDX%@AE@%. There are currently no bits defined in the flags. This parameter must be 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% The return value is a 64 bit long which is actually two 32 bit DWORDS. The Low DWORD (%@AB@%EAX%@AE@%) is a nonzero value if the map is succesful, returns 0 in eax if the map was unsuccesful (invalid address range, invalid %@AI@%VMHandle%@AE@%, map range illegal, size discrepancy, insufficient memory for implied %@AB@%PageLock%@AE@%). The High DWORD (%@AB@%EDX%@AE@%) is only valid if %@AB@%EAX%@AE@% is nonzero. It is set to the %@AI@%VMLinPgNum%@AE@% parameter if the %@AI@%HLinPgNum%@AE@% parameter was not a LOW V86 space address, otherwise it is set to the %@AI@%HLinPgNum%@AE@% parameter. In short, %@AB@%EDX%@AE@% is the V86 address where the memory is mapped. %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% As with %@AB@%MapIntoV86%@AE@% there is an implied %@AB@%PageLock%@AE@% which is performed on all of the pages mapped. This is consistent with the fact that V86 memory cannot be Demand Paged while the VM is in a runable state. Whenever the V86 memory mapping is changed via %@AB@%LinMapIntoV86%@AE@%, the previous memory that was mapped in the VM is unlocked. The correct way to think of this is that there is an implied %@AB@%PageLock%@AE@% whenever memory is mapped into a V86 context, and an implied %@AB@%PageUnlock%@AE@% whenever it is "unmapped" from the V86 context. This "unmapping" can occur when: A different handle (including the NulPageHandle) is MapIntoV86ed to the region, or a %@AB@%PhysIntoV86%@AE@% is performed to the region. %@NL@% The V86 region mappped into by this call should be %@AB@%MapIntoV86ed %@AE@%with the NulPageHandle when the V86 mapping region is no longer needed. There is nothing to prevent you from mapping the same protected mode linear address into multiple places in a VM, or into multiple VMs. Such operations are not particularly advisable though. For one thing, the reporting of memory owned by a VM will be disturbed. %@NL@% The reason this call exists is because a protected mode API mapper does not have access to the memory handles associated with the various regions of protected mode address space. VxDs which do have access to the memory handles of the memory to be mapped should be using %@AB@%MapIntoV86%@AE@% to map the memory, not this routine. %@NL@% For regions in the Physical addressing region this call will convert into a %@AB@%PhysIntoV86%@AE@% call. %@NL@% For regions in the HIGH VM Linear addressing region this call will perform a map of the memory from one VM into another VM (or into a different location in the same VM). NOTE CAREFULLY: The intent of this support is to provide a way for the V86MMGR device to map a region of V86 address space which is currently LOCAL to one VM into a GLOBAL region that is addressable by all VMs. This type of API is needed by network API mappers. Do not use this capability in your VxD, use the V86MMGR service. The details of this aspect of operation will change in a later release and code using the old method will not function properly. %@NL@% The page attributes for these pages will be P_USER+P_PRES+P_WRITE. P_DIRTY and P_ACC will be cleared by the call. PG_TYPE will be set to whatever the type of the pages are at its protected mode linear address. %@NL@% The intent of %@AB@%LinMapIntoV86 %@AE@%support for pages between page 10h and %@AB@%FirstV86Page%@AE@% is to support enhanced Windows devices which have %@AB@%Allocate_Global_V86_Data_Area%@AE@% a GVDAPageAlign region. Use of mapping in this region to other addresses can easily crash the system and should be avoided. %@NL@% Regions which span across %@AB@%FirstV86Page%@AE@% are not allowed. %@NL@% The reason for the page 10h limitation is that on most versions of the Intel 80386 CPU there is an errata which prevents you from setting up a Linear != Physical address mapping in the first 64k of the address space. %@NL@% %@CR:C6A00190135 @%%@CR:C6A00190136 @% %@2@%%@CR:C6A00190137 @%%@AB@%LinPageLock%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned LinPageLock(HLinPgNum,nPages,flags) %@AS@% unsigned HLinPgNum; %@AS@% unsigned nPages; %@AS@% unsigned flags;%@AE@% This call is provided to assist the interface address mapper functions. Its purpose is to provide a way for the address mapper to lock regions of protected mode address space so that API calls can be performed. This calls operation is very similar to %@AB@%PageLock%@AE@%, the difference being that instead of taking a memory handle, it takes a linear address. %@AI@%HLinPgNum%@AE@%, together with %@AI@%nPages%@AE@%, indicates the region of protected mode address space that is to be locked. This is a page number, linear address 60610000h would be passed in as 60610h. Note that the linear address is relative to the standard enhanced Windows Ring 0 DS selector. %@NL@% Current flags bits: %@NL@% %@AS@% PageLockedIfDP EQU 00000000000000000000000100000000B%@AE@% All unused bits must be zero. %@AB@%PageLockedIfDP%@AE@%, if set, indicates that the lock only needs to be done if the %@AB@%PageSwap%@AE@% device is not direct to hardware. In the case where the %@AB@%PageSwap%@AE@% device is of type two (direct to hardware), calls to this routine with %@AB@%PageLockedIfDP%@AE@% set are effectively NOPs. See the %@AB@%PageAllocate%@AE@% documentation for a description of the different %@AB@%PageSwap%@AE@% device types and their relevance. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns a nonzero value if the lock is succesful, returns 0 value if the lock was unsuccesful (invalid address range, insufficient memory for lock). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% SEE %@AB@%PageLock%@AE@%. %@NL@% %@CR:C6A00190138 @%%@CR:C6A00190139 @% %@2@%%@CR:C6A00190140 @%%@AB@%LinPageUnLock%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned LinPageUnLock(HLinPgNum,nPages,flags) %@AS@% unsigned HLinPgNum; %@AS@% unsigned nPages; %@AS@% unsigned flags;%@AE@% This call is provided to assist the interface address mapper functions. Its purpose is to provide a way for the address mapper to unlock regions of protected mode address space after API calls are performed. This calls operation is very similar to %@AB@%PageUnLock%@AE@%, the difference being that instead of taking a memory handle, it takes a linear address.%@AI@% HLinPgNum%@AE@%, together with %@AI@%nPages%@AE@%, indicates the region of protected mode address space that is to be unlocked. This is a page number, linear address 60610000h would be passed in as 60610h. Note that the linear address is relative to the standard enhanced Windows Ring 0 DS selector. %@NL@% Current flags bits: %@NL@% %@AS@% PageLockedIfDP EQU 00000000000000000000000100000000B %@AS@% PageMarkPageOut EQU 00000000000000000010000000000000B%@AE@% All unused bits %@AI@%must be zero%@AE@%. %@AB@%PageLockedIfDP%@AE@%, if set, indicates that the unlock only needs to be done if the %@AB@%PageSwap%@AE@% device is not direct to hardware. In the case where the %@AB@%PageSwap%@AE@% device is of type two (direct to hardware), calls to this routine with %@AB@%PageLockedIfDP%@AE@% set are effectively NOPs. See the %@AB@%PageAllocate%@AE@% documentation for a description of the different %@AB@%PageSwap%@AE@% device types and their relevance. %@AB@%PageMarkPageOut%@AE@%, if set, indicates that if this unlock actually does unlock the pages (lock count goes to 0) the pages are to be made prime candidates for page out. This flag should only be set if it is unlikely that these pages are going to be touched for a while. Effectively what this does is clear the P_ACC bits of the pages which causes them to be first level page out candidates. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns a nonzero value if the unlock is succesful, returns 0 value if the unlock was unsuccesful (invalid address range). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% SEE %@AB@%PageUnLock%@AE@%. %@NL@% %@CR:C6A00190141 @%%@CR:C6A00190142 @% %@2@%%@CR:C6A00190143 @%%@AB@%PageCheckLinRange%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned PageCheckLinRange(HLinPgNum,nPages,flags) %@AS@% unsigned HLinPgNum; %@AS@% unsigned nPages; %@AS@% unsigned flags;%@AE@% This call is provided to assist the interface address mapper functions. Its purpose is to provide a way for the address mapper to validate an intended range for %@AB@%LinPageLock%@AE@% or %@AB@%LinMapIntoV86%@AE@%. Sometimes a MAXIMUM length range is specified because the true range is unknown. This call will return an adjusted %@AI@%nPages%@AE@% argument which will be adjusted down in size if the specified range crosses an unreasonable boundary. %@AI@%HLinPgNum%@AE@%, together with %@AI@%nPages%@AE@%, indicates the region of protected mode address space that is to be checked. This is a page number, linear address 60610000h would be passed in as 60610h. Note that the linear address is relative to the standard enhanced Windows Ring 0 DS selector. There are currently no bits defined in the flags, this parameter must be 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns an adjusted %@AI@%nPages%@AE@% agrument. This will be %@AI@%zero%@AE@% if the range is totally unreasonable, and will return %@AI@%nPages%@AE@% if no adjustment was needed. %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% The end of a handle is a boundary that will result in an adjustment. %@NL@% %@2@%%@CR:C6A00190144 @%%@AB@%PageDiscardPages%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned PageDiscardPages(LinPgNum,VMHandle,nPages,flags) %@AS@% unsigned LinPgNum; %@AS@% unsigned VMHandle; %@AS@% unsigned nPages; %@AS@% unsigned flags;%@AE@% This call is provided to assist management of PM applications by providing a way to mark pages as "no longer in use". What this does is allow regions which were previously "in use" to be "discarded". This means that the page does not have to be "paged in" to make it present, thus eliminating the disk access required for the page in. LinPgNum and nPages together specify the range to be discarded. LinPgNum is a page NUMBER. If LinPgNum is < 110h, or at a VM high linear address, then the range lies in a VM and the %@AI@%VMHandle%@AE@% parameter specifies the VM. In this case, all pages of the range must be marked V86Pageable or the call will fail. Pages in the range which are not present or are locked are ignored, this call effects only demand pageable pages. %@NL@% Current flags bits: %@NL@% %@AS@% PageZeroInit EQU 00000000000000000000000000000001B %@AS@% PageDiscard EQU 00000000000000010000000000000000B%@AE@% Setting PageDiscard indicates that a full discard is to take place, the P_ACC and P_DIRTY bits in the page table entrys for the pages are both cleared. If PageDiscard is clear, all the call does is clear the P_ACC bit in the page table entrys for the pages making them primary page out candidates (the DIRTYness and content of the pages is preserved in this case). Setting PageZeroInit is relevant only if PageDiscard is also set, and it indicates that the pages are to be marked "zero the contents of this page the next time it is paged in". In this case this subsequent page in is a NOP since the pages have been discarded, this simply causes the pages to come back in with a known value (0) in them instead of random garbage. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns a non-zero value if successful, otherwise it returns zero (invalid range or VM handle). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% The Flag bit equates are defined by including VMM.INC, please use the equates. %@NL@% %@CR:C6A00190145 @%%@CR:C6A00190146 @% %@2@%%@CR:C6A00190147 @%%@AB@%SelectorMapFlat%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned SelectorMapFlat(VMHandle,Selector,flags) %@AS@% unsigned VMHandle; %@AS@% unsigned Selector; %@AS@% unsigned flags;%@AE@% This call is provided to assist the interface address mapper functions. Its purpose is to provide a way for the address mapper to get the RING 0 DS offset of the base of a particular GDT or LDT selector. This call assists the address mapper in converting a Selector:Offset16 or Selector:Offset32 pointer into its "flat model" linear address which can then be passed to %@AB@%LinMapIntoVM%@AE@%. Selector is a GDT or LDT selector (note that the argument is a DWORD not a WORD) value to get the base address of. The %@AI@%VMHandle%@AE@% parameter is ignored if Selector is a GDT selector. If Selector is an LDT selector, then %@AI@%VMHandle%@AE@% indicates the appropriate VM context for the Selector. There are currently no bits defined in the flags, this parameter must be 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns the linear address of the base of the selector if succesful, returns FFFFFFFFh if it is unsuccesful (invalid selector). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% You can pass this routine the standard enhanced Windows RING 0 DS selector, and it will return 0 as the base. This is a silly thing to do, but it does work. %@NL@% The %@AI@%VMHandle%@AE@% parameter must be valid for LDT selectors. %@NL@% %@2@%%@CR:C6A00190148 @%%@AB@%SetResetV86Pageable%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned SetResetV86Pageable(VMHandle,VMLinPgNum,nPages,flags) %@AS@% unsigned VMHandle; %@AS@% unsigned VMLinPgNum; %@AS@% unsigned nPages; %@AS@% unsigned flags;%@AE@% This call allows the normal locking/unlocking behavior associated with a specific range of V86 memory to be modified. %@AI@%VMHandle%@AE@% is the VM in which the behavior is being modified. %@AI@%VMLinPgNum%@AE@% is the address in the 1Meg V86 address space where the behavior modification will start (this is a page number, thus linear address 60000h = page 60h). Alignment considerations of this address (beyond 4K alignment) are the responsibility of the caller. Map addresses below %@AB@%FirstV86Page%@AE@%, or above 100h will cause an error. %@AI@%nPages%@AE@% is the number of pages to modify the behavior of. Normally a %@AB@%MapIntoV86%@AE@% causes the memory that is mapped to be locked. In the case where this particular VM is currently running a Protected Mode application, it is desirable to undo the lock, and change this normal lock/unlock behavior. This allows those unused pieces of the V86 address space to be paged out and the memory they are using to be used by someone else. Note that we can only undo this normal behavior because the behavior of the protected mode application is well known. In particular, we know that none of the V86 memory that is being unlocked contains code that is executed, or data that is touched, at interrupt time (including software interrupt time). The typical use of this call is by the enhanced Windows device which loads a protected mode application. When the PM app is loaded, the device calls %@AB@%SetRestV86Pageable%@AE@% with the %@AB@%PageSetV86Pageable%@AE@% bit set on those pieces of the V86 address space above %@AB@%FirstV86Page%@AE@% which can be unlocked; this is typically all of the V86 memory above FirstV86Page which is currently MS-DOS Free. NOTE that MS-DOS data areas such as the 100h byte Program Header Prefix %@AI@%must not be included%@AE@% in the ranges because they are accessed by MS-DOS. Similarly, when the Protected Mode application Exits, the application loader calls %@AB@%SetResetV86Pageable%@AE@% with PageClearV86Pageable set, on the V86 memory it had initially modified during the load. %@NL@% The other aspect of the behavior that can be modified has to do with the "other memory" (the memory that is %@AI@%not%@AE@% V86Pageable) in the VM. Normally this memory is locked, except when the pager is type 2 (direct to hardware). Not locking the V86 memory allows VM's V86 pages to also be Demand Paged. This has the benefit of allowing MS-DOS applications to also run in a Demand Paged environment. Sometimes though, this is an undesired behavior because of the paging latency which it introduces in the VM. The V86IntsLocked bit of a VM allows this aspect to be controled. Setting the V86IntsLocked behavior causes the "other memory" to %@AI@%always%@AE@% be locked, even if the pager is type 2. Setting this behavior has two important effects: %@NL@% ■ There is never any "paging latency" while the virtual mode code in this VM is running. This prevents time critical V86 code from having its timing severly disturbed due to the paging overhead.%@NL@% ■ The paging device can enable interrupts in this VM when it is performing paging operations because %@AI@%it knows%@AE@% that a nested page fault will not occur from this VM since all of its interrupt time code is always locked.%@NL@% Current flags bits: %@NL@% %@AS@% PageSetV86Pageable EQU 00000000000000000000001000000000B %@AS@% PageClearV86Pageable EQU 00000000000000000000010000000000B %@AS@% PageSetV86IntsLocked EQU 00000000000000000000100000000000B %@AS@% PageClearV86IntsLocked EQU 00000000000000000001000000000000B%@AE@% All unused bits %@AI@%must be zero%@AE@%. %@AB@%PageSetV86Pageable%@AE@%, if set, indicates that the normal locking behavior of %@AB@%MapIntoV86%@AE@% is to be disabled (V86 memory can be paged) for the indicated region. %@AB@%PageClearV86Pageable%@AE@%, if set, indicates that the normal locking behavior is to be enabled on the indicated region. %@AB@%PageSetV86IntsLocked%@AE@%, if set, indicates that the "lock all V86 memory that is not V86Pageable regardless of pager type" behavior is to be enabled. PageClearV86IntsLocked, if set, indicates that the "lock all V86 memory that is not V86Pageable regardless of pager type" behavior is to be disabled. %@AI@%Note%@AE@% that only %@AI@%one %@AE@%of these bits can be set on a call. Setting more than one bit will result in an error. There are two bits in %@AB@%CB_VM_Status%@AE@% that indicate the current state of these behaviors: %@NL@% %@AS@% VMStat_PageableV86 EQU 00000000000000000000100000000000B %@AS@% VMStat_V86IntsLocked EQU 00000000000000000001000000000000B%@AE@% The %@AB@%VMStat_PageableV86%@AE@% bit is set if any regions behavior has been modified (there is at least one non zero bit in the array returned by %@AB@%GetV86PageableArray%@AE@%). The %@AB@%VMStat_V86IntsLocked%@AE@% bit is set if the "lock regardless of pager type" behavior has been enabled in this VM. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns non-zero value if the set or clear worked, zero if the current state of the VM was not consistent with the call (invalid VMHandle, %@AB@%VMStat_PageableV86%@AE@% or %@AB@%VMStat_V86IntsLocked%@AE@% state inconsistent with setting of %@AB@%PageSet/ClearV86Pageable%@AE@% or %@AB@%PageSet/ClearV86IntsLocked%@AE@% bit in flags, range invalid) or the lock of the memory associated with %@AB@%PageClearV86Pageable%@AE@% or %@AB@%PageSetV86IntsLocked%@AE@% failed. %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% The intent of this call is to better support Protected mode applications running in a VM, not to allow you to randomly make v86 parts of VMs pageable! Do not issue this call on a VM unless you are loading a Protected mode app into it. %@NL@% The V86MMGR device makes a %@AB@%PageSetV86IntsLocked%@AE@% call on VMs which are created with their base memory specified as %@AI@%locked%@AE@%. %@NL@% Extreme care must be used when manipulating the PageableV86 behavior of regions above A000:0. This should not be done unless the region is GLOBAL or LOCAL %@AB@%Assign_Device_V86_Pages%@AE@% owned by the caller. %@NL@% There is no REGION associated with %@AB@%PageSetV86IntsLocked%@AE@% and %@AB@%PageClearV86IntsLocked%@AE@% calls. The IMPLIED region is always "everything that isn't V86Pageable". For this reason the %@AI@%HLinPgNum%@AE@% and %@AI@%nPages%@AE@% arguments should be set to 0 on these calls. %@NL@% VMM.INC contains equates for all of the flag bits described, use the equates. %@NL@% %@2@%%@CR:C6A00190149 @%%@AB@%19.9 Instance Data Management%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% The purpose of these services is to provide a means of identifying to the system those areas of virtual 8086 mode memory (V86 memory) that contain per Virtual Machine or "Instance" data. Each of the VMs in the system has its own, private instance of this data and anything the VM does to the values in these locations has no effect on other VMs since the values are different in each VM. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%All of these calls use the USE32 C calling convention. The true name of the %@AI@%procedure has an underscore in front (i.e., %@AB@%AddInstanceItem%@AE@%%@AI@% is actually%@AE@%%@AI@%%@AB@% %@AB@%_AddInstanceItem%@AE@%%@AE@%%@AI@%), and the arguments are pushed right to left (unlike the %@AI@%PL/M calling convention used by Windows, which is left to right). The return %@AI@%value(s) is returned in C standard %@AE@%%@AI@%%@AB@%EDX:EAX%@AE@%%@AE@%%@AI@%. It is the responsibility of the %@AI@%caller%@AE@%%@AI@%to clear the arguments off the stack. Registers %@AE@%%@AI@%%@AB@%EAX%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%ECX%@AE@%%@AE@%%@AI@%, and %@AE@%%@AI@%%@AB@%EDX%@AE@%%@AE@%%@AI@% are %@AI@%changed by calls. Registers %@AE@%%@AI@%%@AB@%DS%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%ES%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%EBP%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%EDI%@AE@%%@AE@%%@AI@%, %@AE@%%@AI@%%@AB@%ESI%@AE@%%@AE@%%@AI@%, and %@AI@%@AE@%%@AI@%%@AB@%EBX%@AE@%%@AE@%%@AI@% are preserved.%@AE@%%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@CR:C6A00190150 @%%@CR:C6A00190151 @% %@2@%%@CR:C6A00190152 @%%@AB@%AddInstanceItem%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned AddInstanceItem(InstStrucPTR,flags) %@AS@% unsigned InstStrucPTR; %@AS@% unsigned flags;%@AE@% This call is used to identify a region of instance data in the V86 address space. %@AI@%InstStrucPTR%@AE@% is a pointer to an instance data identification structure which has this form: %@NL@% %@AS@% InstDataStruc struc %@AS@% InstLinkF dd ? ; RESERVED SET TO 0 %@AS@% InstLinkB dd ? ; RESERVED SET TO 0 %@AS@% InstLinAddr dd ? ; Linear address of start of block %@AS@% InstSize dd ? ; Size of block in bytes %@AS@% InstType dd ? ; Type of the block %@AS@% InstDataStruc ends%@AE@% The InstLinkF and InstLinkB fields are filled in by the Instance data manager and cannot be used by the caller. InstLinAddr defines the start of the block of instance data, NOTE THAT THIS IS NOT IN SEG:OFFSET FORM, it is a linear address. Thus the correct value for 40:2F would be 42F. InstSize is the size of the instance data block in bytes starting at InstLinAddr. InstType defines one of two types of instance data: %@NL@% %@AS@% INDOS_Field equ 100h ; Bit indicating INDOS switch requirements %@AS@% ALWAYS_Field equ 200h ; Bit indicating ALWAYS switch requirements%@AE@% ALWAYS_Field type indicates that the field must always be switched when a VM is switched. All instance data sepcified by VxDs should be of this type. INDOS_Field type is reserved for special types of MS-DOS internal data which only need to be switched with the VM if the VM is currently INDOS. %@NL@% There are currently no bits defined in the flags, this parameter must be set to 0. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% Returns nonzero value if the instance data block was succesfully added to the instance list, zero if the block was unsuccesful added (This is probably a FATAL error). %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%There are two basic ways to allocate the space for the InstDataStrucs %@AI@%pointed to with InstStrucPTR. The first is to simply staticly allocate them %@AI@%in the INIT data segment. The space they occupy will then be reclaimed when %@AI@%the INIT space is reclaimed. The other way is to allocate them on the System %@AI@%heap using HeapAllocate. The space can then be freed by HeapFreeing all of %@AI@%the heap handles in the device Sys_VM_Init code which is called after all of %@AI@%the system initialization (including the instance data initialization) is %@AI@%done.%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AU@%WARNING%@AE@% If you allocate space for InstDataStrucs on the heap you must be sure NOT to HeapReAllocate the heap blocks after passing the address to AddInstanceItem because this will invalidate the InstStrucPTR value you previously passed to AddInstanceItem. ────────────────────────────────────────────────────────────────────────────%@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%This routine is in the init segment of enhanced Windows. It can therefore %@AI@%only be called during system initialization. Trying to call it after system %@AI@%initialization and the system INIT segment space has been reclaimed will %@AI@%result in a fatal page fault.%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% Once this call is made, the caller %@AB@%must not %@AE@%ever touch the InstDataStruc pointed to again. The caller has passed control of this data block to the instrance data manager and tampering with it will result in the instance data manager failing to identify the instance data correctly. %@NL@% Note that only one, contiguous region of instance data can be identified with each structure. It is a good idea for the caller to coalesce adjacent blocks of instance data it is identifying in order to cut down the call overhead and data space requirements, but this is not required. %@NL@% There is a declaration of the InstDataStruc data structure in VMM.INC. %@NL@% %@CR:C6A00190153 @%%@CR:C6A00190154 @% %@2@%%@CR:C6A00190155 @%%@AB@%MMGR_Toggle_HMA%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@AS@% unsigned MMGR_Toggle_HMA(VMHandle,flags) %@AS@% unsigned VMHandle; %@AS@% unsigned flags;%@AE@% This call is an interface to the Instance data manager which allows devices such as the V86MMGR XMS device to control the behavior of the "highmem" memory area, or "HMA", of a VM (V86 linear pages 100h through 10Fh). Any device which wishes to modify the "1Meg Address Wrap" behavior of a VM MUST use this call to inform the Instance data manager what is going on. This is because the Instance manager must know whether 1Meg Address Wrap is on or off to manage the instance data correctly for a VM. %@AI@%VMHandle%@AE@% is a valid enhanced Windows VM handle which indicates the VM to which the call is to be applied. Current flags bits: %@NL@% %@AS@% MMGRHMAPhysical EQU 00000000000000000000000000000001B %@AS@% MMGRHMAEnable EQU 00000000000000000000000000000010B %@AS@% MMGRHMADisable EQU 00000000000000000000000000000100B %@AS@% MMGRHMAQuerry EQU 00000000000000000000000000001000B%@AE@% All unused bits must be zero. One, and only one of MMGRHMAEnable, MMGRHMADisable, MMGRHMAQuerry BITS must be specified, the call will have random results if this is not true. MMGRHMAPhysical bit is a modifier which modifies the operation of the MMGRHMAEnable bit: See discussion of MMGRHMAEnable. MMGRHMADisable, if set, causes the Instance manager to restore the normal Wrap mapping for pages 100 through 10F thus Disabling the HMA. This is a REMAP of pages 00h through 0Fh of the VM and causes the VMs address space to "wrap" back to address zero for addresses >1Meg as it does on an 8086 processor. MMGRHMAEnable, if set, disables 1Meg address wrap in the VM, thus Enabling the HMA. Exactly what this does is controlled by the MMGRHMAPhysical bit. If MMGRHMAPhysical is set, MMGRHMAEnable causes PHYSICAL pages 100h through 10Fh to be mapped in Linear pages 100h through 10Fh of the VM consistent with the operation of a Global HMA which is shared by all VMs. If MMGRHMAPhysical is not set, Linear pages 100h through 10Fh will be marked as not present System Pages in the VM. It is then up to the CALLER to map some other memory handle into this region of the VM after this call. This is consistent with the operation of a per VM HMA. Note that if the VM accesses these pages before this mapping is set up, an erroneaous page fault will occur which will crash the VM, or the system. MMGRHMAQuerry, if set, returns the current state of the HMA in the VM. %@NL@% %@3@%%@AB@%Return Value%@AE@%%@EH@%%@NL@% This call has no return value unless MMGRHMAQuerry was specified in the flags. In this case the call will return value 0 if the HMA is Disabled (1Meg address wrap is enabled), and it will return a nonzero value if the HMA is Enabled (1Meg address wrap is disabled). %@NL@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% This call is reserved for the V86MMGR XMS device. Other devices should not be using this call. Modifying the Wrap state of a VM without the V86MMGR XMS device knowing about it will probably result in a state error and a crash. %@NL@% The device issuing this call must be a device which has succesfully Globally or Locally %@AB@%Assign_Device_VM_Paged%@AE@% pages 100h through 10Fh in the indicated VM. This is not a call which multiple devices should make for a VM as doing so will cause confusion between the devices. %@NL@% When VMs are created, they are created with the HMA Disabled (1Meg Address Wrap enabled) consistent with normal operation on an 8086 processor. The device responsible for the HMA in a VM must adjust this in its %@AB@%Create_VM%@AE@% device call if needed. %@NL@% Note that no distinction is drawn on the MMGRHMAQuerry return between MMGRHMAPhysical being specified, or not specified on a previous MMGRHMADisable call. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%Instance data is not allowed in the hma.%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% The flag bit equates are in VMM.INC, please use the equates. %@NL@% %@2@%%@CR:C6A00190156 @%%@AB@%19.10 Looking At V86 Address Space%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% From time to time, VxDs may wish to look at or modify some piece of the virtual 8086 mode address space of a VM that is not the current VM. The documented way to do this is as follows. %@NL@% %@CR:C6A00190157 @%%@CR:C6A00190158 @% %@2@%%@CR:C6A00190159 @%%@AB@%CB_High_Linear%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% There is a Control Block variable which is a linear address of the start of the VM's address space. Thus to look at VM linear adress 40:17 with %@AB@%EBX%@AE@% being the VM Handle of the VM you're interested in you would do this: %@NL@% %@AS@% mov esi,(40h SHL 4) + 17h %@AS@% add esi,[ebx.CB_High_Linear]%@AE@% %@AB@%ESI%@AE@% now points to this location in the V86 address space. This can be used to look at, modify any V86 address including instance data addresses. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%No code should EVER touch a part of V86 address space at its "low" address %@AI@%(>=0,<=400000h) EVEN FOR THE CURRENT VM. There is NO REASON to do this, use %@AI@%CB_High_Linear in ALL cases to look at V86 addresses.%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@CR:C6A00200001 @%%@1@%%@AB@%Chapter 20 I/O Services and Macros%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% This chapter documents the services available for I/O. Also included are two macros and a discussion explaining their usefulness. %@NL@% See Chapter 16, "Overview of Windows in 386 Enhanced Mode," and Chapter 17, "Virtual Device Programming Topics," for general environment discussions. %@NL@% When a virtual machine executes an instruction that reads or writes data from an I/O port, the 80386 looks up the port number in the I/O Permission Map (IOPM). If the corresponding bit in the IOPM is set, then the instruction will cause a protection fault. %@NL@% Enhanced Windows provides services that virtual devices use to trap I/O. The first thing a virtual device must do is hook the port while the device is being initialized. This is done by calling a service called %@AB@%Install_IO_Handler%@AE@%. It takes two parameters: the number of the I/O port to hook and the address of a callback procedure. %@NL@% The I/O services and macros supported by enhanced Windows are described in this chapter in the following order: %@NL@% ■ %@AB@%Enable_Global_Trapping%@AE@%%@NL@% ■ %@AB@%Disable_Global_Trapping%@AE@%%@NL@% ■ %@AB@%Enable_Local_Trapping%@AE@%%@NL@% ■ %@AB@%Disable_Local_Trapping%@AE@%%@NL@% ■ %@AB@%Install_IO_Handler%@AE@%%@NL@% ■ %@AB@%Install_Mult_IO_Handlers%@AE@%%@NL@% ■ %@AB@%Simulate_IO%@AE@%%@NL@% %@2@%%@CR:C6A00200002 @%%@AB@%20.1 Handling Different I/O Types%@AE@%%@EH@%%@NL@% The value passed in %@AB@%ECX%@AE@% determines the type of input or output as specified by Table 20.1. %@NL@% Table 20.1 I/O Register Values %@TH: 9 464 02 22 54 @%Value Type of input/output%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%00H Byte input04H Byte output08H WORD input0CH WORD output10H DWORD input14H DWORD output%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%%@TE: 9 464 02 22 54 @% Masks that apply only to string I/O are shown in Table 20.2. %@NL@% Table 20.2 String I/O Register Values %@TH: 7 417 02 13 63 @%Value Type of input/output%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%20H String I/O40H Repeated string I/O80H 32-bit addressing mode string I/O100H Reverse string I/O (VM's direction flag is set)%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%%@TE: 7 417 02 13 63 @% For all string I/O operations, the high WORD of %@AB@%ECX%@AE@% contains the segment for the string I/O. This allows VxDs to ignore the issues of segment overrides on these instructions; VMM has already determined the correct segment value. Thus, a value of 3247016CH would specify that the VM is doing word reverse repeated string output from 3247:SI. %@NL@% For example: %@NL@% High word = segment 3247 0Ch = Word output 20h = String I/O 40h = Repeated string I/O 100h = Reverse I/O %@NL@% It would be unreasonable to expect every VxD to support 48 different types of I/O. Therefore, the VxD environment only requires VxDs to support byte input and output, even though a VxD can directly support any type of I/O that is appropriate. For example, there is no reason for the Virtual Printer Device (VPD) to support WORD input and output since printer ports are only 8-bits wide. %@NL@% However, the VxDs for devices with 16-bit ports can directly support WORD I/O as well as byte I/O. %@NL@% Furthermore, devices such as disk drives might need to directly emulate string I/O for some ports to achieve acceptable performance. A device can emulate some types of I/O and ignore others. %@NL@% But what happens if someone does WORD string output to a printer port? You canot just throw the I/O away! For this reason, enhanced Windows has a catch-all routine called %@AB@%Simulate_IO%@AE@% that converts I/O into something the virtual device can understand. Notice in the port trap code of the VPD example that entry points start with the %@AB@%Emulate_Non_Byte_IO%@AE@% macro. This macro generates the following code: %@NL@% %@AS@% cmp ecx, 4 %@AS@% jbe SHORT Foo %@AS@% VMMjmp Simulate_IO %@AS@% %@AS@% Foo:%@AE@% So, if a VM attempted to do non-repeated forward %@AB@%word%@AE@% string I/O, the following sequence of calls to the VPD trap code would be issued: %@NL@% Call VPD trap with: %@NL@% %@AB@%EBX%@AE@% = VM handle %@AB@%EDX%@AE@% = 358h (Port #) %@AB@%ECX%@AE@% = 23A8002Ch (String I/O from segment 23A8h) %@AB@%EBP%@AE@% = Client register structure %@NL@% VPD jumps to %@AB@%Simulate_I/O%@AE@% which calls VPD again with: %@NL@% %@AB@%EBX%@AE@% = VM handle %@AB@%EDX%@AE@% = 358h (Port #) %@AB@%ECX%@AE@% = 0Ch (0Ch = Word output) %@AB@%AX %@AE@%= Word to output %@AB@%EBP%@AE@% = Client register structure %@NL@% VPD jumps to %@AB@%Simulate_I/O%@AE@% which calls VPD again with: %@NL@% %@AB@%EBX%@AE@% = VM handle %@AB@%EDX%@AE@% = 358h (Port #) %@AB@%ECX%@AE@% = 04h (04h = Byte output) %@AB@%AL%@AE@% = Byte to output %@AB@%EBP%@AE@% = Client register structure %@NL@% VPD then simulates the byte output and returns. %@NL@% Notice that the high-order byte of the word output would be sent to the trap routine for VPD trap port # +1. So, if VPD is trapping port 358H, then word output to this port will be converted into byte output to ports 358H and 359H (exactly the way the hardware works). %@NL@% %@2@%%@CR:C6A00200003 @%%@AB@%20.2 I/O Macros%@AE@%%@EH@%%@NL@% There are two useful macros for I/O trap routines. The first macro, %@AB@%Emulate_Non_Byte_IO%@AE@%, generates the following code: %@NL@% %@AS@% cmp ecx, Byte_Output %@AS@% jbe SHORT Is_Byte_IO %@AS@% VMMjmp Simulate_IO %@AS@% jnz Is_Byte_Input %@AS@% Is_Byte_IO:%@AE@% %@AB@%Dispatch_Byte_IO%@AE@%, the second useful macro, takes two arguments. The first is the destination for byte input, and the second is the destination for byte output. This macro passes back all non-byte I/O to %@AB@%Simulate_IO%@AE@%. A typical I/O trap routine looks like the following: %@NL@% %@AS@% BeginProc VfooD_Trap_Data %@AS@% Dispatch_Byte_IO Fall_Through, VFood_Out_Data %@AS@% ... %@AS@% (Code for byte input) %@AS@% ... %@AS@% ret %@AS@% %@AS@% VfooD_Out_Data: %@AS@% ... %@AS@% (Code for byte output) %@AS@% ... %@AS@% ret %@AS@% EndProc VfooD_Trap_Data%@AE@% Notice the special value %@AB@%Fall_Through%@AE@% that instructs the %@AB@%Dispatch_Byte_IO%@AE@% macro that byte input should fall through to the following code. You can substitute %@AB@%Fall_Through%@AE@% for either the input or output parameter (but not both) or specify two labels. %@NL@% %@2@%%@CR:C6A00200004 @%%@AB@%20.3 I/O Services%@AE@%%@EH@%%@NL@% This section presents detailed information on each of the following I/O services: %@NL@% ■ %@AB@%Enable_Global_Trapping%@AE@%%@NL@% ■ %@AB@%Disable_Global_Trapping%@AE@%%@NL@% ■ %@AB@%Enable_Local_Trapping%@AE@%%@NL@% ■ %@AB@%Disable_Local_Trapping%@AE@%%@NL@% ■ %@AB@%Install_IO_Handler%@AE@%%@NL@% ■ %@AB@%Install_Mult_IO_Handlers%@AE@%%@NL@% ■ %@AB@%Simulate_IO%@AE@%%@NL@% %@CR:C6A00200005 @%%@CR:C6A00200006 @%%@CR:C6A00200007 @%%@CR:C6A00200008 @% %@2@%%@CR:C6A00200009 @%%@AB@%Enable_Global_Trapping, Disable_Global_Trapping%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% These services enable and disable I/O port trapping in every VM. A callback hook must have been installed during initialization before either of these services is used. %@NL@% The global trapping state is by default enabled. When a VM is created, it will be created with the current global trapping state. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EDX%@AE@% = I/O port number %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00200010 @%%@CR:C6A00200011 @%%@CR:C6A00200012 @%%@CR:C6A00200013 @% %@2@%%@CR:C6A00200014 @%%@AB@%Enable_Local_Trapping, Disable_Local_Trapping%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% These services enable and disable I/O port trapping in a specific VM. A callback hook must have been installed during initialization before either of these services is used. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX %@AE@%= VM handle %@AB@%EDX%@AE@% = I/O port number %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00200015 @%%@CR:C6A00200016 @% %@2@%%@CR:C6A00200017 @%%@AB@%Install_IO_Handler (Initialization only)%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service installs a callback procedure for I/O port trapping and enables trapping for the specified port in all VM's. Only one procedure may be installed for each port. %@NL@% When an I/O callback is installed, the default global trapping state is enabled. You can disable trapping of a port for every or specific VMs using the %@AB@%Enable/Disable_Global_Trapping%@AE@% and %@AB@%Enable/Disable_Local_Trapping%@AE@% services. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = Address of procedure to call %@AB@%EDX%@AE@% = I/O port %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry set then ERROR: Port already hooked by another device or unable to hook any more ports (out of hooks) else Port hooked successfully %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = Current VM handle %@AB@%ECX%@AE@% = Type of I/O %@AB@%EDX%@AE@% = Port number %@AB@%EBP%@AE@% -> Client register structure %@NL@% If output then EAX/AX/AL = Data output to port els e (input) Callback procedure must return EAX/AX/AL for data input from port %@NL@% %@CR:C6A00200018 @%%@CR:C6A00200019 @% %@2@%%@CR:C6A00200020 @%%@AB@%Install_Mult_IO_Handlers (Initialization only)%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service makes repeated calls to the %@AB@%Install_IO_Handler%@AE@% service with the entries in a table built using macros as follows: %@NL@% Begin_Vxd_IO_Table Table_Name Vxd_IO <port#>, <procedure name> ... Vxd_IO <port #>, <procedure name> Vxd_IO <port #>, <procedure name> End_Vxd_IO_Table Table_Name %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EDI%@AE@% = Address of VxD_IO_Table %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry set then ERROR: One or more ports already hooked by another device or unable to hook any more ports (out of hooks) EDX = Number of port that could not be hooked else Ports hooked successfully %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Data for output instructions %@AB@%EBX%@AE@% = Current VM handle %@AB@%ECX%@AE@% = Type of I/O %@AB@%EDX%@AE@% = Port number %@AB@%EBP%@AE@% -> Client register structure %@NL@% Callback procedure must return EAX/AX/AL for data input from port %@NL@% %@CR:C6A00200021 @%%@CR:C6A00200022 @% %@2@%%@CR:C6A00200023 @%%@AB@%Simulate_IO%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used to break complex I/O instructions into simpler types of I/O. An I/O handler should jump to this service using %@AB@%VMMjmp Simulate_IO%@AE@% whenever the handler is called with a type of I/O that it does not directly support. A typical I/O trap handler would start with code similar to the following: %@NL@% %@AS@% Sample_IO_Handler: %@AS@% cmp ecx, Byte_Output %@AS@% je SHORT SIH_Simulate_Output %@AS@% jb SHORT SIH_Simulate_Input %@AS@% VMMjmp Simulate_IO %@AE@% Since byte input is 0 and byte output is 4, a single compare can be used to determine if the I/O is byte input, output, or not supported. When %@AB@%Simulate_IO%@AE@% is invoked, it will break the I/O into simpler I/O types and recursively call %@AB@%Sample_IO_Handler%@AE@%. %@NL@% For example, assume %@AB@%Sample_IO_Handler%@AE@% is the I/O trap handler for port 534H. If it was called with %@AB@%ECX = Word_Output%@AE@%, then it would immediately jump to the %@AB@%Simulate_IO%@AE@% service. %@AB@%Simulate_IO%@AE@% would then break the I/O instruction into byte output to ports 534H and 535H. When %@AB@%Sample_IO_Handler%@AE@% was called again, it would be able to virtualize the byte output to port 534H. The output to port 535H would be handled by another port trap routine, or, if there was not one installed, the output would be reflected directly to hardware port 535H. %@NL@% Two macros, %@AB@%Emulate_Non_Byte_IO%@AE@% and %@AB@%Dispatch_Byte_IO%@AE@%, are provided as convenient ways to invoke this service. %@NL@% %@AB@%Emulate_Non_Byte_IO%@AE@% is usually the first line of an I/O trap handler. It simply compares %@AB@%ECX%@AE@% to %@AB@%Byte_Output%@AE@% and, if it is greater, it jumps to the %@AB@%Simulate_IO%@AE@% service. For example: %@NL@% %@AS@% Sample_IO_Handler: %@AS@% Emulate_Non_Byte_IO %@AS@% (Here ECX will be 0 for byte input or 4 for byte output) %@AE@% %@AB@%Dispatch_Byte_IO%@AE@% is usually more convenient since it will also jump to the appropriate code for byte input or output. The macro takes two parameters. The first parameter specifies the label to jump to for byte input, and the second specifies the label to jump to for byte output. Either parameter (but not both) can have the special value %@AB@%Fall_Through%@AE@%, which specifies that the code to handle that I/O type immediately follows the macro. For example: %@NL@% %@AS@% Sample_IO_Handler: %@AS@% Dispatch_Byte_IO Fall_Through, <SHORT SIH_Output> %@AS@% (...Code here for handling byte input...) %@AS@% ret %@AE@% %@AS@% SIH_Output: %@AS@% (...Code here for handling byte output...) %@AS@% ret %@AE@% If, for efficiency reasons, you want to provide code to virtualize I/O other than byte input and output, test for the types that you can handle and then jump to this service to emulate other types of I/O. %@NL@% Notice that the entry parameters to this service are identical to the parameters passed to your I/O trap routine. You should jump to this service using the %@AB@%VMMjmp%@AE@% macro with all of the registers in the same state as when your I/O trap routine was called (although you may modify %@AB@%ESI%@AE@% and %@AB@%EDI%@AE@% since they are not parameters). %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Data for output instructions %@AB@%EBX%@AE@% = Current VM handle %@AB@%ECX %@AE@%= Type of I/O (same as passed to I/O trap routine) %@AB@%EDX%@AE@% = I/O port %@AB@%EBP%@AE@% -> Client Register Structure %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% All registers modified. If input, then %@AB@%AX%@AE@% or %@AB@%EAX%@AE@% will contain virtualized input value. %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%,%@AB@% EBX%@AE@%, %@AB@%ECX%@AE@%,%@AB@% EDX%@AE@%,%@AB@% ESI, EDI%@AE@%, Flags %@NL@% %@CR:C6A00210001 @%%@1@%%@AB@%Chapter 21 VM Interrupt and Call Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% The VM Interrupt and Call Services supported by enhanced Windows are described in this chapter in the following order: %@NL@% ■ %@AB@%Build_Int_Stack_Frame%@AE@%%@NL@% ■ %@AB@%Call_When_Idle%@AE@%%@NL@% ■ %@AB@%Call_When_VM_Ints_Enabled%@AE@%%@NL@% ■ %@AB@%Disable_VM_Ints%@AE@%%@NL@% ■ %@AB@%Enable_VM_Ints%@AE@%%@NL@% ■ %@AB@%Get_PM_Int_Type%@AE@%%@NL@% ■ %@AB@%Get_V86_Int_Vector%@AE@%%@NL@% ■ %@AB@%Get_PM_Int_Vector%@AE@%%@NL@% ■ %@AB@%Hook_V86_Int_Chain%@AE@%%@NL@% ■ %@AB@%Set_PM_Int_Type%@AE@%%@NL@% ■ %@AB@%Set_V86_Int_Vector%@AE@%%@NL@% ■ %@AB@%Set_PM_Int_Vector%@AE@%%@NL@% ■ %@AB@%Simulate_Far_Call%@AE@%%@NL@% ■ %@AB@%Simulate_Far_Jmp%@AE@%%@NL@% ■ %@AB@%Simulate_Far_Ret%@AE@%%@NL@% ■ %@AB@%Simulate_Far_Ret_N%@AE@%%@NL@% ■ %@AB@%Simulate_Int%@AE@%%@NL@% ■ %@AB@%Simulate_Iret%@AE@%%@NL@% See Chapter 16, "Overview of Windows in 386 Enhanced Mode," and Chapter 17, "Virtual Device (VxD) Programming Topics," for general discussions on VM Interrupts and Call Services. %@NL@% %@CR:C6A00210002 @%%@CR:C6A00210003 @% %@2@%%@CR:C6A00210004 @%%@AB@%Build_Int_Stack_Frame%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service will save the current %@AB@%CS:IP%@AE@% and flags on the VM's stack and, then, set the %@AB@%CS:IP%@AE@% to the value passed to the routine. The next time the VM is entered, the effect will be that an interrupt occurred, directing control to the procedure specified. %@NL@% The procedure that is called must do an IRET to return. %@NL@% Sample code: %@NL@% %@AS@% VMMcall Begin_Nest_Exec %@AS@% mov cx, [My_Private_VM_Proc_Segment] %@AS@% mov edx, [My_Private_VM_Proc_Offset] %@AS@% VMMcall Build_Int_Stack_Frame %@AS@% VMMcall Resume_exec %@AS@% VMMcall End_Nest_Exec%@AE@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%CX%@AE@% = Code segment of procedure to call %@AB@%EDX%@AE@% = Offset of procedure to call (high word must be 0 for 16-bit apps) %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%Client_CS%@AE@%, %@AB@%Client_EIP%@AE@%, %@AB@%Client_ESP%@AE@%, %@AB@%Client_Flags%@AE@%, Flags %@NL@% %@CR:C6A00210005 @%%@CR:C6A00210006 @% %@2@%%@CR:C6A00210007 @%%@AB@%Call_When_Idle%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used by devices that want to perform background operations with the system is "idle". For example, this service is used by the pageswap device to asynchronously write dirty pages to the swap file. Windows is considered idle when all VMs have released their time-slice. When the Windows kernel signals that Windows is idle and all other VMs are idle, the idle callback procedures will be called. Each callback can either consume the idle call or pass it on to the next idle callback in the list. Idle calls should be consumed if the device performs an operation that takes a significant amount of time. For example, if the pageswap device writes a dirty page to the swap file then it will consume the idle call to prevent sluggish performance. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% -> Procedure to call when all VMs idle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry clear then Callback procedure installed else Error: Could not install call-back procedure %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% %@AB@%EBX %@AE@%= System VM Handle (current VM is always the system VM) %@AB@%EBP%@AE@% -> Client register structure Return with carry SET to pass the call to next handler Return with carry CLEAR to consume the callback and indicate Sys VM is not idle. Callback procedure can modify %@AB@%EAX%@AE@%, %@AB@%EBX%@AE@%, %@AB@%ECX%@AE@%, %@AB@%EDX%@AE@%, %@AB@%ESI%@AE@%, %@AB@%EDI%@AE@%, and Flags. %@NL@% %@CR:C6A00210008 @%%@CR:C6A00210009 @% %@2@%%@CR:C6A00210010 @%%@AB@%Call_When_VM_Ints_Enabled%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% If a VxD needs to be called when interrupts are enabled, it can use this service to be notified when the VM enables interrupts. If the current VM's interrupts are already enabled when this service is called, your callback procedure will be called immediately. %@NL@% It is usually more convenient to use the %@AB@%Call_Priority_VM_event%@AE@% service instead of calling this service directly. However, this service is faster. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EDX%@AE@% = Reference data %@AB@%ESI%@AE@% = Offset of procedure to call %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%Client_Flags%@AE@%, Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = Handle of current VM %@AB@%EDX%@AE@% = Reference data passed to this service %@AB@%EBP%@AE@% -> Client register structure Called procedure may destroy %@AB@%EAX%@AE@%, %@AB@%EBX%@AE@%, %@AB@%ECX%@AE@%, %@AB@%EDX%@AE@%, %@AB@%ESI%@AE@%, %@AB@%EDI%@AE@%, and Flags %@NL@% %@CR:C6A00210011 @%%@CR:C6A00210012 @% %@2@%%@CR:C6A00210013 @%%@AB@%Disable_VM_Ints%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service will disable interrupts during VM execution for the current virtual machine. This has the same effect as the VM executing a CLI instruction. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00210014 @%%@CR:C6A00210015 @% %@2@%%@CR:C6A00210016 @%%@AB@%Enable_VM_Ints%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service will enable interrupts during VM execution for the current virtual machine. This has the same effect as the VM executing an STI instruction. This service allows events scheduled using the %@AB@%Call_When_Ints_Enabled%@AE@% or %@AB@%Call_Proirity_VM_Event%@AE@% services to be serviced. Note, however, that they will not be serviced immediately. They will be serviced at event time. This means that VxDs calling this service do not need to worry about the VM's state changing during this call. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00210017 @% %@2@%%@CR:C6A00210018 @%%@AB@%Get_PM_Int_Type%@CR:C6A00210019 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used to determine if a PM interrupt vector is an interrupt gate or trap gate type interrupt. Interrupt gate interrupts clear the interrupt flag bit to disable interrupts when the interrupt occurs. Trap gate interrupts don't modify the interrupt bit. All PM interrupts default to the trap gate type, but VxD's such as VPICD need to change some of them to interrupt gates so that hardware interrupts disable interrupts. Other software interrupts such as INT 21h are left as trap gates, so that their handlers don't need to execute an STI and thus avoid the extra overhead of an unnecessary ring transition. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Interrupt number %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EDX%@AE@% = 0 if vector is a trap gate (interrupt flag is not changed) 0 if vector is an interupt gate (interrupt flag is cleared) %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EDX%@AE@%, Flags %@NL@% %@CR:C6A00210020 @%%@CR:C6A00210021 @%%@CR:C6A00210022 @%%@CR:C6A00210023 @% %@2@%%@CR:C6A00210024 @%%@AB@%Get_V86_Int_Vector, Get_PM_Int_Vector%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% These services return the current VM's interrupt vector for the mode specified. For V86 mode, this is the DWORD located in the real mode interrupt vector. A PM interrupt vector table is maintained by the VMM for every virtual machine. %@NL@% Notice that for PM interrupts, a return with ZF set indicates that the interrupt has not been hooked. The %@AB@%CS:EIP%@AE@% returned will point to a PM callback break point. The break point will invoke code that reflects the interrupt to V86 mode. VxDs can chain to this break point just as they would any other protected mode address (using Simulate_Far_Jmp or Build_Int_Stack_Frame) although it is also acceptable to reflect the interrupt to V86 immediately for optimal performance. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Interrupt number %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%CX%@AE@% = %@AB@%CS%@AE@% in vector (high word zero) %@AB@%EDX%@AE@% = %@AB@%EIP%@AE@% in interrupt vector (for V86 mode and 16-bit protected mode programs the high word will be zero) For PM vectors, if interrupt vector points to reflection code (default) then Zero flag is set else Zero flag is clear %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%ECX%@AE@%, %@AB@%EDX%@AE@%, Flags %@NL@% %@CR:C6A00210025 @% %@2@%%@CR:C6A00210026 @%%@AB@%Hook_V86_Int_Chain (Initialization only)%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@CR:C6A00210027 @%Description %@NL@% These services are used to monitor software interrupts and simulated hardware interrupts in Virtual-8086 mode. More than one VxD is allowed to hook an interrupt. The last interrupt hook will be the first one called. Every interrupt hook can either service the interrupt or allow the interrupt to be reflected to the next handler in the chain. If no interrupt hook procedure consumes the interrupt, then it will be reflected to the virtual machine. %@NL@% To consume an interrupt, a hook procedure must return with the Carry flag clear. If the Carry flag is set when an interrupt hook returns, then the interrupt will be passed on to the next handler in the chain or, if the end of the chain is reached, reflected to the current virtual machine. %@NL@% If a VxD calls the %@AB@%Simulate_Int%@AE@% service, then all interrupt chain hooks will be called before the interrupt is reflected into the virtual machine. Simulated hardware interrupts will also be routed through the interrupt hooks. Therefore, your code should not assume that the VM has just executed a software interrupt instruction. %@NL@% Notice that there is no corresponding service to hook Protected Mode interrupts. PM interrupts must be hooked by hooking the interrupt vector. This service is faster than hooking the V86 interrupt vector since the VMM must intercept every V86 interrupt. This prevents a switch to V86 mode and then back to Ring 0 for every V86 interrupt hook. %@NL@% %@3@%%@AB@%Example%@AE@%%@EH@%%@NL@% Windows running in enhanced mode supports an API using software interrupt 2FH. The code to handle the Release Time-Slice API looks like this: %@NL@% %@AS@% Win386_Partial_API_initialization: %@AS@% mov eax, 2fh %@AS@% mov esi, OFFSET32 Win386_Partial_API_Hook %@AS@% VMMcall Hook_V86_Int_Chain %@AS@% clc %@AS@% ret %@AS@% %@AS@% Win386_Partial_API_Hook %@AS@% cmp [epb.Client_AX], 1680h %@AS@% je SHORT W386_PA_Our_Call %@AS@% stc %@AS@% ret %@AS@% W386_PA_Our_Call: %@AS@% VMMcall Release_Time_Slice %@AS@% clc %@AS@% ret%@AE@% When %@AB@%Win386_Partial_API_Hook%@AE@% is called, it checks for 1680H in the VM's %@AB@%AX%@AE@% register. If %@AB@%Client_AX%@AE@% <> 1680H, then it returns with Carry set, and the interrupt will be reflected to the next handler in the interrupt chain. However, if %@AB@%Client_AX%@AE@% = 1680H, then it releases the current virtual machine's time-slice and consumes the interrupt by returning with Carry clear. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Interrupt # %@AB@%ESI%@AE@% Procedure to call %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry set then ERROR: Invalid interrupt number else Interrupt hook installed %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Interrupt # %@AB@%EBX%@AE@% = Current VM handle %@AB@%EBP%@AE@% -> Client register structure %@NL@% If the callback procedure returns with carry clear then The interrupt is NOT passed to the next interrupt hook else (if carry set) The interrupt is passed to the next interrupt hook %@NL@% %@CR:C6A00210028 @%%@CR:C6A00210029 @% %@2@%%@CR:C6A00210030 @%%@AB@%Set_PM_Int_Type%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used to specify if a PM interrupt vector should either be an interrupt gate or trap gate type interrupt. Interrupt gate interrupts clear the interrupt flag bit to disable interrupts when the interrupt occurs. Trap gate interrupts don't modify the interrupt bit. %@NL@% All PM interrupts default to the trap gate type, but VxD's such as VPICD need to change some of them to interrupt gates so that hardware interrupts disable interrupts. %@NL@% Other software interrupts such as INT 21H are left as trap gates, so that their handlers don't need to execute an STI and thus avoid the extra overhead of an unnecessary ring transition. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Interrupt number %@AB@%EDX%@AE@% = 0, if vector is a trap gate (interrupt flag is not changed) 0, if vector is an interupt gate (interrupt flag is cleared) %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00210031 @%%@CR:C6A00210032 @%%@CR:C6A00210033 @%%@CR:C6A00210034 @% %@2@%%@CR:C6A00210035 @%%@AB@%Set_V86_Int_Vector, Set_PM_Int_Vector%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service sets the current interrupt vector for the mode specified. If a VxD calls %@AB@%Set_%@AE@%xxx%@AB@%_Int_Vector%@AE@% before the %@AB@%Sys_VM_Int%@AE@% control call is made, then the installed handler will become part of the default interrupt vector table. In other words, every VM will be created with interrupt vectors set during enhanced Windows initialization. If this service is called after %@AB@%Sys_VM_Init%@AE@%, then the handler will only be installed in the current virtual machine. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Interrupt number %@AB@%CX%@AE@% = CS to set into vector %@AB@%EDX%@AE@% = EIP to set interrupt vector (for V86 mode and 16-bit protected mode programs the `1`high word should be zero) %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00210036 @%%@CR:C6A00210037 @% %@2@%%@CR:C6A00210038 @%%@AB@%Simulate_Far_Call%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service places the current VM's %@AB@%CS:IP%@AE@% on the VM's stack and puts the %@AB@%CS:IP%@AE@% specified in %@AB@%CX:EDX%@AE@% in the client frame. The next time the VM is executed, it will be as if a FAR call had been inserted in the VM's instruction stream. %@NL@% %@AU@%(This figure may be found in the printed book).%@AE@%%@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%CX%@AE@% = Segment of procedure to call %@AB@%EDX%@AE@% = Offset of procedure to call (high word 0 if 16-bit application) %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%Old Client_CS%@AE@%:(%@AB@%E%@AE@%)%@AB@%IP%@AE@% on stack. Specified %@AB@%CS%@AE@%:%@AB@%EIP%@AE@% is current %@AB@%CS%@AE@%:%@AB@%EIP%@AE@%. %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%Client_CS%@AE@%, %@AB@%Client_EIP%@AE@%, %@AB@%Client_SP%@AE@%, Flags ; %@NL@% %@CR:C6A00210039 @%%@CR:C6A00210040 @% %@2@%%@CR:C6A00210041 @%%@AB@%Simulate_Far_Jmp%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service places the specified %@AB@%CS:IP%@AE@% into the VM's %@AB@%CS:IP%@AE@% to simulate a FAR jmp instruction. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%CX%@AE@% = %@AB@%CS%@AE@% to jump to%@AB@% EDX%@AE@% = %@AB@%EIP%@AE@% to jump to (High word should be zero for 16-bit or V86 apps) %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%Client_EIP%@AE@%, %@AB@%Client_CS%@AE@%, Flags %@NL@% %@CR:C6A00210042 @%%@CR:C6A00210043 @% %@2@%%@CR:C6A00210044 @%%@AB@%Simulate_Far_Ret%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Decsription%@AE@%%@EH@%%@NL@% This procedure pops the top two WORDs orDWORDs on the current VM's stack into the client's %@AB@%CS:(E)IP%@AE@%. %@NL@% %@AU@%(This figure may be found in the printed book).%@AE@%%@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%Client_CS%@AE@%, %@AB@%Client_EIP%@AE@%, %@AB@%Client_ESP%@AE@%, Flags %@NL@% %@CR:C6A00210045 @%%@CR:C6A00210046 @% %@2@%%@CR:C6A00210047 @%%@AB@%Simulate_Far_Ret_N%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This procedure pops the top two WORDs or DWORDs on the current VM's stack into the client's %@AB@%CS:(E)IP%@AE@%, then subtracts %@AB@%EAX%@AE@% from the VM's stack pointer. %@NL@% %@AU@%(This figure may be found in the printed book).%@AE@%%@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Number of bytes to pop after far ret %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%Client_CS%@AE@%, %@AB@%Client_EIP%@AE@%, %@AB@%Client_ESP%@AE@%, Flags %@NL@% %@CR:C6A00210048 @% %@2@%%@CR:C6A00210049 @%%@AB@%Simulate_Int%@CR:C6A00210050 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used mainly by the Virtual Programmable Interrupt Controller Device (VPICD) to simulate hardware interrupts. Most VxD writers will want to use the %@AB@%Exec_Int%@AE@% service to simulate interrupts. %@NL@% This service has exactly the same effect as a VM executing an %@AB@%Int nn%@AE@% instruction. All VxD interrupt chain hooks are called and, if the interrupt is not consumed by one of these hooks, an IRET frame is built on the VM's stack. Notice, however, that the VM interrupt code will not be executed until the enhanced Windows environment returns to the virtual machine. If you want to %@AI@%execute%@AE@% an interrupt, then you should use the nested execution services (%@AB@%Exec_Int%@AE@%). %@NL@% This service is mode sensitive. Therefore, if the VM is currently in V86 mode, then a V86 interrupt will be simulated. Otherwise, a PM interrupt will be simulated. Since reflecting a PM interrupt may force a mode change to V86 mode, VxD writers must be very careful when calling this service while running a protected-mode application. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Interrupt number %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If %@AB@%Simulate_Int%@AE@% is called while running a PM application and the PM interrupt vector is not hooked, then the mode is changed to V86. %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%Client_CS%@AE@%, %@AB@%Client_EIP%@AE@%, %@AB@%Client_Flags%@AE@%, Flags %@NL@% %@CR:C6A00210051 @%%@CR:C6A00210052 @% %@2@%%@CR:C6A00210053 @%%@AB@%Simulate_Iret%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service pops the values at the top of the current VM's stack into the current VM's %@AB@%CS:IP%@AE@% and flags. If the current VM is a 32-bit protected-mode application, then this service will pop three DWORDs instead of WORDs (simulate an IRETD). %@NL@% %@AU@%(This figure may be found in the printed book).%@AE@%%@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%Client_CS%@AE@%, %@AB@%Client_EIP%@AE@%, %@AB@%Client_ESP%@AE@%, %@AB@%Client_Flags%@AE@%, Flags %@NL@% %@CR:C6A00220001 @%%@1@%%@AB@%Chapter 22 Nested Execution Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% These services provide a way for VxDs to call routines in a VM. Notice that the VxD must make sure that the service being called is in a callable state (i.e., you must not reenter services that do not expect to be reentered). The services are described here in alphabetical order. %@NL@% ■ %@AB@%Begin_Nest_Exec%@AE@%%@NL@% ■ %@AB@%Begin_Nest_V86_Exec%@AE@%%@NL@% ■ %@AB@%Begin_Use_Locked_PM_Stack%@AE@%%@NL@% ■ %@AB@%End_Nest_Exec%@AE@%%@NL@% ■ %@AB@%End_Use_Locked_PM_Stack%@AE@%%@NL@% ■ %@AB@%Exec_Stack%@AE@%%@NL@% ■ %@AB@%Exec_VxD_Int%@AE@%%@NL@% ■ %@AB@%Restore_Client_State%@AE@%%@NL@% ■ %@AB@%Resume_Exec%@AE@%%@NL@% ■ %@AB@%Save_Client_State%@AE@%%@NL@% ■ %@AB@%Set_PM_Exec_Mode%@AE@%%@NL@% ■ %@AB@%Set_V86_Exec_Mode%@AE@%%@NL@% %@CR:C6A00220002 @%%@CR:C6A00220003 @% %@2@%%@CR:C6A00220004 @%%@AB@%Begin_Nest_Exec%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used by VxDs that need to call software in a VM. %@NL@% For example: %@NL@% %@AS@% VMMcall Begin_Nest_Exec ; Start nested execution %@AS@% mov [ebp.Client_AH], 30h ; 30h = Get MS-DOS Version # %@AS@% mov eax, 21h ; Execute an Int 21h in the %@AS@% VMMcall Exec_Int ; current VM to call MS-DOS %@AS@% VMMcall End_Nest_Exec ; End of nested exec calls%@AE@% This will make the MS-DOS %@AB@%Get_Version%@AE@% call. The version will be in the %@AB@%Client_AH%@AE@% and %@AB@%Client_AL%@AE@% registers. %@NL@% This service only works for the current VM. The VM registers changed by the call Will be changes in the VM. If you want to save and restore a VM's registers you should use the %@AB@%Save_Client_ State%@AE@% and %@AB@%Restore_Client_State%@AE@% services or the %@AB@%Push_Client_State%@AE@% and %@AB@%Pop_Client_State%@AE@% macros documneted under %@AB@%Save_Client_State%@AE@% and %@AB@%Restore_Client_State%@AE@%. %@NL@% You may execute any number of interrupts between a %@AB@%Begin/End_Nest_Exec%@AE@% pair. For example the following is valid: %@NL@% %@AS@% Push_Client_State %@AS@% VMMcall Begin_Nest_Exec %@AS@% ... %@AS@% VMMcall Exec_Int %@AS@% ... %@AS@% VMMcall Exec_Int %@AS@% ... %@AS@% VMMcall Simulate_Far_Call %@AS@% VMMcall Resume_Exec %@AS@% ... %@AS@% VMMcall Exec_Int %@AS@% VMMcall End_Nest_Exec %@AS@% Pop_Client_State%@AE@% This service will force the VM into protected-mode execution if there is a protected-mode application running in the current VM. If there is no protected mode application, then the VM will remain in V86 mode. When %@AB@%End_Nest_Exec%@AE@% is called, the VM will be returned to whatever mode it was in when %@AB@%Begin_Nest_Exec %@AE@%was called. For more information on what is entailed in a mode switch refer to the documentation for %@AB@%Set_PM_Exec_Mode%@AE@% and %@AB@%Set_V86_Exec_Mode%@AE@% later in this chapter. %@NL@% If there is a protected-mode application in the current VM, then this service will automatically switch the VM to the locked PM stack (and %@AB@%End_Nest_Exec%@AE@% will switch it back). This allows most devices to change execution modes without worrying about demand paging issues. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%Client_CS:IP%@AE@% contains a break point (used by nested exec services). %@NL@% If a protected mode application is running then VM execution mode is protected mode else VM execution mode is Virtual-8086 mode %@AB@%Exec_Int%@AE@% and %@AB@%Resume_Exec%@AE@% services may be called. %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%Client_CS%@AE@%, %@AB@%Client_IP%@AE@%, Flags %@NL@% %@CR:C6A00220005 @%%@CR:C6A00220006 @% %@2@%%@CR:C6A00220007 @%%@AB@%Begin_Nest_V86_Exec%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service will set the the current VM in Virtual-8086 mode and prepare the VM for nested execution. This service is normally used by VxDs that want to convert protected mode calls into V86 calls. For example, the DOSMGR device uses this call to map INT 21H MS-DOS calls issued from protected mode programs into Virtual-8086 mode MS-DOS calls. %@NL@% This call, like %@AB@%Begin_Nest_Exec%@AE@%, saves the current execution mode of the virtual machine (either V86 or PM), and %@AB@%End_Nest_Exec%@AE@% will restore the mode. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%Client_CS:IP%@AE@% contains a break point (used by nested exec services) VM is in Virtual 8086 mode. %@AB@%Exec_Int%@AE@% and %@AB@%Resume_Exec %@AE@%services may be called. %@NL@% %@3@%%@AB@%USES%@AE@%%@EH@%%@NL@% %@AB@%Client_CS%@AE@%, %@AB@%Client_IP%@AE@%, Flags %@NL@% %@CR:C6A00220008 @%%@CR:C6A00220009 @% %@2@%%@CR:C6A00220010 @%%@AB@%Begin_Use_Locked_PM_Stack%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used by VxDs that need to ensure that a protectedmode program is running on a stack that will not be demand paged. Most devices can rely on %@AB@%Begin_Nest_Exec%@AE@% to switch stacks automatically, and so this service is only important for devices, such as the Virtual Programmable Interrupt Controller Device (VPICD), which explicitly changes the execution mode of a VM. %@NL@% A call to this service must be followed by a call to %@AB@%End_Use_Locked_PM_Stack%@AE@%. Note that this service may be called repeatedly, but only the first call will switch stacks. Subsequent calls will increment a counter but remain on the current locked stack. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% Current execution mode of VM must be protected mode (%@AB@%VMStat_PM_Exec%@AE@% status bit must be set). %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If locked stack not already in use then Client's SS:SP will be changed to locked protected mode stack else Client's SS:SP will be unchanged %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00220011 @% %@2@%%@CR:C6A00220012 @%%@AB@%End_Nest_Exec%@CR:C6A00220013 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service must be called after a call to %@AB@%Begin_Nest_Exec%@AE@%. A VxD must never return to the VMM while still in nested execution. If %@AB@%Begin_Nest_Exec%@AE@% changed the execution mode of the VM then this service will restore it to the previous mode. Notice that this service %@AI@%will%@AE@% %@AI@%not%@AE@% restore the client's registers (except %@AB@%CS:IP%@AE@%) to the values they were when %@AB@%Begin_Nest_Exec %@AE@%was called. If you need to preserve the VM's registers, you must use the %@AB@%Push_Client_State%@AE@% and %@AB@%Pop_Client_State%@AE@% macros. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% VM execution mode restored to previous execution mode (before %@AB@%Begin_Nest_Exec%@AE@% was called) Client's original %@AB@%CS:IP%@AE@% restored %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%Client_CS%@AE@%, %@AB@%Client_IP%@AE@%, Flags %@NL@% %@CR:C6A00220014 @%%@CR:C6A00220015 @% %@2@%%@CR:C6A00220016 @%%@AB@%End_Use_Locked_PM_Stack%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service must be called once for every call made to %@AB@%Begin_Use_Locked_PM_Stack.%@AE@% It will decrement the locked stack use counter and, if it is decremented to zero then it will switch the VM back to its original %@AB@%SS:SP%@AE@%. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If locked stack count decremented to 0 then Client's SS:SP will be restored to original values before %@AB@%Begin_Use_Locked_PM_Stack%@AE@% was called. else Client's SS:SP will be unchanged %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00220017 @% %@2@%%@CR:C6A00220018 @%%@AB@%Exec_Int%@CR:C6A00220019 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% You must call %@AB@%Begin_Nest_Exec%@AE@% or %@AB@%Begin_Nest_V86_Exec%@AE@% before calling this service. It may be called any number of times between a %@AB@%Begin_Nest_Exec%@AE@% and %@AB@%End_Nest_Exec%@AE@% pair. %@NL@% This service simulates an interrupt and then resumes VM execution. It has exactly the same effect as calling: %@NL@% %@AS@% mov eax, (Int #) %@AS@% VMMcall Simulate_Int %@AS@% VMMcall Resume_Exec%@AE@% Since most nested execution calls simulate interrupts, this service is provided for convenience. See %@AB@%Resume_Exec%@AE@% later in this chapter for more details on how this service is used. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = # of interrupt to execute %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Interrupt has been executed %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00220020 @% %@2@%%@CR:C6A00220021 @%%@AB@%Exec_VxD_Int%@CR:C6A00220022 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used by virtual devices to call MS-DOS or BIOS services as though they were an application program. For example, the following code gets the current MS-DOS version: %@NL@% %@AS@% mov ax, 3000h %@AS@% push DWORD PTR 21h %@AS@% VMMcall Exec_VxD_Int %@AS@% (AL = Major MS-DOS version, AL = Minor MS-DOS version)%@AE@% All MS-DOS and BIOS calls that are supported in protected-mode programs will be supported by this service. The VM's registers and flags will not be changed by this service so there is no need for the caller to save and restore the client register structure. The interrupt number on the stack will be removed by this service so the caller should %@AI@%not%@AE@% add four to %@AB@%ESP%@AE@% after calling this service. %@NL@% To make calling this service easier, a macro called %@AB@%VxDint%@AE@% is defined in VMM.INC as follows: %@NL@% %@AS@% VxDint MACRO Int_Number %@AS@% push Int_Number %@AS@% VMMcall Exec_VxD_Int %@AS@% ENDM %@AE@% This service makes it possible to write code in a VxD that is very similar to real mode code. For example, below is the code that opens a file named "FOO.TXT" and reads the first 100 bytes: %@NL@% %@AS@% VxD_DATA_SEG %@AS@% Foo_File_Name db "FOO.TXT", 0 %@AS@% Read_Buffer db 100 dup (?) %@AS@% VxD_DATA_ENDS%@AE@% %@AS@% VxD_CODE_SEG %@AS@% BeginProc Sample_File_Read %@AS@% mov ax, 3D00h ; Open file with handle %@AS@% mov edx, OFFSET32 Foo_File_Name ; DS:EDX - File name %@AS@% VxDint 21h ; Call MS-DOS %@AS@% jc Error ; If carry then error %@AS@% ; else AX = File handle %@AS@% mov bx, ax ; BX = File handle %@AS@% mov ecx, 100 ; Read 100 bytes %@AS@% mov edx, OFFSET32 Read_Buffer ; Into this buffer %@AS@% mov ah, 3Fh ; MS-DOS Read %@AS@% VxDint 21h ; Call MS-DOS %@AS@% jc Error ; Error if carry else %@AS@% ; EAX = # bytes read %@AS@% (Do stuff with the data here)%@AE@% %@AS@% EndProc Sample_File_Read %@AS@% VxD_CODE_ENDS%@AE@% %@3@%%@AB@%Comments%@AE@%%@EH@%%@NL@% Interrupts will only be routed through VxD interrupt hooks. They will bypass any hook the application has installed in protected mode. This may be a problem, for example, if an application hooks INT 21h to watch for a file open and, then, a VxD uses this service to open a file (the application would not see the file open). Do not use this service until the %@AB@%Init_Complete%@AE@% control call is made. %@NL@% Do not change %@AB@%DS%@AE@% or %@AB@%ES%@AE@% before calling this service. You should always use the ring 0 linear address of the data instead of changing the selector value. This may require using the %@AB@%_SelectorMapFlat%@AE@% service to determine the base of a selector. %@NL@% Do not call services that will change %@AB@%DS%@AE@% or %@AB@%ES%@AE@%. Mappers should return valid pointers without changing the segment register value, but calls that explicitly change the %@AB@%DS%@AE@% or %@AB@%ES%@AE@% selectors should never be called. For example, if a call returns a pointer in %@AB@%DS:(E)DX%@AE@% then this would be OK to call since the mapper would convert the ponter to use the ring 0 linear address in %@AB@%EDX%@AE@% without modifying %@AB@%DS%@AE@%. However, if a service returns a selector only then you should not use %@AB@%Exec_VxD_Int %@AE@%to call it. This can normally be made to work by using code similar to the following: %@NL@% %@AS@% Push_Client_State %@AS@% VMMcall Begin_Nest_(V86_)Exec %@AS@% . . . %@AS@% (Fiddle with client registers) %@AS@% . . . %@AS@% VMMcall Exec_Int %@AS@% . . . %@AS@% (Get segments/selectors) %@AS@% . . . %@AS@% VMMcall End_Nest_Exec %@AS@% Pop_Client_State%@AE@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% DWORD at [ESP+4] is number of interrupt to execute %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% All registers and flags modified by interrupt will be changed. The interrupt number on the stack will have been removed. %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% All registers and flags modified by interrupt will be changed. %@NL@% %@CR:C6A00220023 @%%@CR:C6A00220024 @% %@2@%%@CR:C6A00220025 @%%@AB@%Restore_Client_State%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service restores a VM execution state that was saved using the %@AB@%Save_Client_State%@AE@% service. If the client state was saved using the %@AB@%Push_Client_State%@AE@% macro then you should use %@AB@%Pop_Client_State%@AE@% to restore the VM's execution state. The %@AB@%Pop_Client_State%@AE@% macro looks like: %@NL@% %@AS@% Pop_Client_State MACRO %@AS@% push esi %@AS@% lea esi, [esp+4] %@AS@% VMMcall Restore_Client_State %@AS@% pop esi %@AS@% add esp, SIZE Client_Reg_Struc %@AS@% ENDM%@AE@% Notice that this service can have side effects if it is not used carefully. For instance, it will change modes from V86 to protected mode or from protected to V86 mode if the state being restored is in a different execution mode from the current one. Also, it may change the state of the current virtual machine's interrupt flag and so it may cause callbacks to events scheduled through the %@AB@%Call_When_VM_Ints_Enabled%@AE@% or %@AB@%Call_Priority_VM_Event%@AE@% services. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI %@AE@%-> Buffer %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% VM execution state is restored %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00220026 @% %@2@%%@CR:C6A00220027 @%%@AB@%Resume_Exec%@CR:C6A00220028 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% You must call %@AB@%Begin_Nest_Exec%@AE@% or %@AB@%Begin_Nest_V86_Exec%@AE@% before calling this service. It may be called any number of times between a %@AB@%Begin_Nest_Exec%@AE@% and %@AB@%End_Nest_Exec%@AE@% pair. %@NL@% This service immediately executes the current VM. When the VM returns to the same point it was at when %@AB@%Begin_ Nest_Exec%@AE@% was called, this service will return. The following example: %@NL@% %@AS@% Push_Client_State %@AS@% VMMcall Begin_Nest_Exec %@AS@% mov cx, [Target_CS] %@AS@% mov eax, [Target_CS_EIP] %@AS@% VMMcall Simulate_Far_Call %@AS@% VMMcall Resume_Exec %@AS@% (Examine results returnd in Client registers) %@AS@% VMMcall End_Nest_Exec %@AS@% Pop_Client_State%@AE@% will return when the called procedure returns.The following code will process any outstanding events and immediately return: %@NL@% %@AS@% VMMcall Begin_Nest_Exec %@AS@% VMMcall Resume_Exec %@AS@% VMMcall End_Nest_Exec%@AE@% Since the %@AB@%Resume_Exec%@AE@% resumes execution at the same point that %@AB@%Begin_Nest_Exec%@AE@% was called it will return immediately. %@NL@% This service is also useful for VxDs that must wait for an external event (such as a hardware interrupt) to occur before returning to the VM. Since %@AB@%Resume_Exec%@AE@% allows outstanding events to be processed, simulated harware interrupts can be sent to the VM while waiting: %@NL@% %@AS@% (Push_Client_State is not needed) %@AS@% VMMcall Begin_Nest_Exec %@AS@% Wait_Loop: %@AS@% test [My_Status], Done %@AS@% je Exit_My_Wait_Loop %@AS@% VMMcall Resume_Exec %@AS@% VMMcall Release_Time_Slice %@AS@% jmp My_Wait_Loop %@AS@% Exit_Wait_Loop: %@AS@% VMMcall End_Nest_Exec %@AS@% (Pop_Client_State is not needed)%@AE@% Notice that you do not need to save and restore the client registers in this loop since simulated hardware interrupts and events will not modify the client registers. You should only use the %@AB@%Push/ Pop_Client_State%@AE@% macros when your VxD code explicitly calls code in a VM or directly modifies any client register. %@NL@% This service and %@AB@%Exec_Int%@AE@% may be called multiple times in between calls to Begin/End nest exec. For example the following code is valid: %@NL@% %@AS@% Push_Client_State %@AS@% VMMcall Begin_Nest_Exec %@AS@% mov eax, (Int #) %@AS@% VMMcall Exec_Int %@AS@% mov cx, [Target_CS] %@AS@% mov eax, [Target_CS_EIP] %@AS@% VMMcall Simulate_Far_Call %@AS@% VMMcall Resume_Exec %@AS@% VMMcall End_Nest_Exec %@AS@% Pop_Client_State%@AE@% Since events are processed when %@AB@%Resume_Exec%@AE@% (or %@AB@%Exec_Int%@AE@%) is called, a task switch may occur. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00220029 @%%@CR:C6A00220030 @% %@2@%%@CR:C6A00220031 @%%@AB@%Save_Client_State%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service will copy the contents of the current VM's Client Register Structure to the specified buffer. The buffer must be the size of the structure named %@AB@%Client_Reg_Struc%@AE@% which is defined in VMM.INC. The saved state can later be restored by calling %@AB@%Restore_Client_State.%@AE@% %@NL@% Most of the time, it is easier to use the %@AB@%Push_Client_State %@AE@%macro than to call this service directly. %@AB@%Push_Client_State%@AE@% copies the client's state onto the protected mode stack. The macro code is as follows: %@NL@% %@AS@% Push_Client_State MACRO %@AS@% sub esp, SIZE Client_Reg_Struc %@AS@% push edi %@AS@% lea edi, [esp+4] %@AS@% VMMcall Save_Client_State %@AS@% pop edi %@AS@% ENDM%@AE@% As you can see, this macro will reserve space on the caller's stack for the buffer. You must use the %@AB@%Pop_Client_State%@AE@% macro to get rid of the contents saved on your stack. The macro will not change any registers. %@NL@% This service is typically used by VxDs that need to make calls to code in a virtual machine that are unrelated to the current VM's thread of execution. For example, the demand paging device (PageSwap) does the following: %@NL@% %@AS@% Push_Client_State %@AS@% VMMcall Begin_Nest_Exec %@AS@% . . . %@AS@% (Perform disk I/O) %@AS@% . . . %@AS@% VMMcall End_Nest_Exec %@AS@% Pop_Client_State%@AE@% Notice that the %@AB@%Push_Client_State%@AE@% macro is placed %@AI@%before%@AE@% the call to %@AB@%Begin_Nest_Exec%@AE@% and the %@AB@%Pop_Client_State%@AE@% macro is %@AI@%after%@AE@% the call to %@AB@%End_Nest_Exec%@AE@%. Any other combination would probably crash enhanced Windows. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AU@%WARNING%@AE@% Always use this service to save the client state. Don't just copy the VM's client register structure and later copy it back as this will almost certianly cause enhanced Windows to hang or crash. ────────────────────────────────────────────────────────────────────────────%@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EDI%@AE@% -> Buffer %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Buffer contains a copy of the current VM's client register structure %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00220032 @%%@CR:C6A00220033 @% %@2@%%@CR:C6A00220034 @%%@AB@%Set_PM_Exec_Mode%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service forces the current VM into protected mode. Most devices will want to use %@AB@%Begin_Nest_Exec%@AE@% instead of this service. %@NL@% Changing the execution mode of a VM will not change the VM's %@AB@%EAX%@AE@%, %@AB@%EBX%@AE@%, %@AB@%ECX%@AE@%, %@AB@%EDX%@AE@%, %@AB@%ESI%@AE@%, %@AB@%EDI%@AE@%, and %@AB@%EBP%@AE@% registers or %@AI@%most%@AE@% flags. The VM flag and IOPL flags will change. %@AB@%DS%@AE@%, %@AB@%ES%@AE@%, %@AB@%FS%@AE@%, %@AB@%GS%@AE@%, %@AB@%SS%@AE@%, %@AB@%ESP%@AE@%, %@AB@%CS%@AE@%, and %@AB@%EIP%@AE@% will be restored to the previous values for protected mode. %@NL@% If the current VM is already in protected mode, then this service has no effect. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% VM is in PM execution mode %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00220035 @%%@CR:C6A00220036 @% %@2@%%@CR:C6A00220037 @%%@AB@%Set_V86_Exec_Mode%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service forces the current VM into V86 mode. Most VxDs will want to use %@AB@%Begin_Nest_V86_Exec%@AE@% instead of this service. %@NL@% Changing the execution mode of a VM will not change the VM's %@AB@%EAX%@AE@%, %@AB@%EBX%@AE@%, %@AB@%ECX%@AE@%, %@AB@%EDX%@AE@%, %@AB@%ESI%@AE@%, %@AB@%EDI%@AE@%, and %@AB@%EBP%@AE@% registers or most flags. The VM flag and IOPL flags will change. %@AB@%DS%@AE@%, %@AB@%ES%@AE@%, %@AB@%FS%@AE@%, %@AB@%GS%@AE@%, %@AB@%SS%@AE@%, %@AB@%ESP%@AE@%, %@AB@%CS%@AE@%, and %@AB@%EIP%@AE@% will be restored to the previous values for V86 mode. %@NL@% If the current VM is already in V86 mode, then this service has no effect. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% VM is in V86 execution mode %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00230001 @%%@1@%%@AB@%Chapter 23 Break Point and Callback Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% The services described in this chapter are used to handle breakpoint and callback procedures. %@NL@% The discussion of these services is presented in the following order: %@NL@% ■ %@AB@%Allocate_V86_Call_Back%@AE@%%@NL@% ■ %@AB@%Allocate_PM_Call_Back%@AE@%%@NL@% ■ %@AB@%Call_When_Idle%@AE@%%@NL@% ■ %@AB@%Call_When_VM_Returns%@AE@%%@NL@% ■ %@AB@%Install_V86_Break_Point%@AE@%%@NL@% ■ %@AB@%Remove_V86_Break_Point%@AE@%%@NL@% See Chapter 16, "Overview of Windows in 386 Enhanced Mode," and Chapter 17, "Virtual Device Programming Topics," for general environment discussions. %@NL@% %@CR:C6A00230002 @%%@CR:C6A00230003 @%%@CR:C6A00230004 @%%@CR:C6A00230005 @% %@2@%%@CR:C6A00230006 @%%@AB@%Allocate_V86_Call_Back, Allocate_PM_Call_Back%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% A %@AI@%V86 callback%@AE@% is used to transition from V86 mode into a protected mode VxD. The callback is a SEGMENT:OFFSET that, when executed by a V86 machine, will cause a procedure in a virtual device to be called. %@NL@% A %@AI@%PM callback%@AE@% is used to transition from a protected-mode application to a VxD. The callback is a SELECTOR:OFFSET that, when executed, will cause a procedure in a virtual device to be called. %@NL@% These services are typically used by devices that need to be called by software running in a virtual machine. When the VM software calls the callback address, the VxD gets control and can service the VM's request. %@NL@% %@AS@% Initialization: %@AS@% mov edx, My_Ref_Data %@AS@% mov esi, OFFSET33 My_API_Procedure %@AS@% VMMcall Allocate_V86_Call_Back %@AS@% mov [My_V86_Call_Back], eax %@AS@% mov [ebp.Client_DI], ax %@AS@% shr eax, 16 %@AS@% mov [ebp.Client_ES], ax %@AS@% ret%@AE@% %@AS@% My_API_Procedure: %@AS@% . . . (Do something here) . . . %@AS@% VMMcall Simulate_Far_Ret %@AS@% ret%@AE@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EDX%@AE@% = Reference data (any DWORD) %@AB@%ESI%@AE@% = Procedure to call %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = CS:IP of V86 callback address %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = Current VM handle %@AB@%EDX%@AE@% = Reference data %@AB@%EBP%@AE@% -> Current VM's client register structure %@NL@% %@CR:C6A00230007 @%%@CR:C6A00230008 @% %@2@%%@CR:C6A00230009 @%%@AB@%Call_When_Idle%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used by devices that want to perform background operations with the system is "idle". For example, this service is used by the pageswap device to asynchronously write dirty pages to the backing store. Windows is considered idle when all VMs have released their time-slice. When the Windows kernel signals that Windows is idle and all other VMs are idle, the idle callback procedures will be called. Each callback can either consume the idle call or pass it on to the next idle callback in the list. Idle calls should be consumed if the device performs an operation that takes a significant amount of time. For example, if the pageswap device writes a dirty page to the backing store then it will consume the idle call to prevent slugish performance. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% ESI -> Procedure to call when all VMs idle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry clear then Callback procedure installed else Error: Could not install call-back procedure %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% EBX = System VM Handle (current VM is always the system VM) EBP -> Client register structure Return with carry SET to pass the call to next handler Return with carry CLEAR to consume the callback and indicate Sys VM is not idle. Callback procedure can modify EAX, EBX, ECX, EDX, ESI, EDI, and Flags. %@NL@% %@CR:C6A00230010 @%%@CR:C6A00230011 @% %@2@%%@CR:C6A00230012 @%%@AB@%Call_When_VM_Returns%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is normally used to watch the "back end" of a software interrupt. For example, assume that the procedure %@AB@%I16_Hook%@AE@% has been placed in the V86 interrupt chain (using the %@AB@%Hook_V86_Int_Chain%@AE@% service). If the procedure wants to look at the return value from INT 16H, it would use the following code: %@NL@% %@AS@% I16_Hook: %@AS@% xor eax, eax ; No time-out %@AS@% mov esi, OFFSET32 I16_Return ; Call this when iret executed %@AS@% VMMcall Call_When_VM_Returns ; Hook the return %@AS@% stc ; Reflect to next int handler %@AS@% ret%@AE@% %@AS@% I16_Return: %@AS@% (Examine results of Int 16h) %@AS@% ret%@AE@% This service actually replaces the client's %@AB@%CS:IP%@AE@% with a callback. Since at the point %@AB@%I16_Hook%@AE@% is executed the interrupt IRET frame has not yet been built on the client's stack, the callback will be pushed on the client's IRET frame. When the VM executes an IRET to return from the interrupt, the callback break point will be executed and control will be transferred to %@AB@%I16_Return%@AE@%. This service will take care of restoring the client's %@AB@%CS:IP%@AE@% registers to their original value. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Milliseconds until time-out (0 if no time-out) If negative value then callback will be called for both time out AND return (unless return before time-out). %@AB@%EDX%@AE@% = Reference data %@AB@%ESI%@AE@% = Address of procedure to call %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%Client_CS:EIP%@AE@% replaced with callback address %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%Client_CS%@AE@%, %@AB@%Client_EIP%@AE@%, Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = Current VM handle %@AB@%EDX%@AE@% = Reference data %@AB@%EBP%@AE@% -> Client register structure %@NL@% If carry set then Time-out occurred before VM returned else %@AB@%Client_CS:IP%@AE@% restored to original value VM returned and executed break point If time-out value specified was negative then If Zero flag set then Time-out DID occur. Second call to this callback else Time-out did not and will not occur. %@NL@% %@CR:C6A00230013 @%%@CR:C6A00230014 @% %@2@%%@CR:C6A00230015 @%%@AB@%Install_V86_Break_Point%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used to patch V86 code in a VM. It is primarily used by the DOSMGR device to place patches in the MS-DOS BIOS. Most VxD will have no use for this service. A good example of a typical use for this service is the Windows XMS virtual device. Since there is already a real mode XMS driver when the enhanced Windows environment starts, the virtual XMS device must place a V86 break point at the real XMS driver entry point so that it can intercept all XMS calls. %@NL@% This service places an enhanced Windows V86 break point instruction at the specified SEGMENT:OFFSET in the current virtual machine. V86 break points will normally be placed in global VM memory during device initialization. V86 break points must be placed only in RAM that will have a constant linear address (they cannot move or be placed in ROM). %@NL@% When a VM executes the break point, control will be passed to the VxD that installed it. The client's (VM's) %@AB@%CS:IP%@AE@% will still point to the break point that caused the fault. Therefore, the virtual device must change the %@AB@%CS:IP%@AE@% or else the break point will be executed again when the VxD environment returns to the VM. In the case of the virtual XMS device, it would call %@AB@%Simulate_Far_Ret%@AE@% to return to the code that called the XMS driver. Other devices may want to simulate the instruction that was patched out and increment the %@AB@%IP%@AE@% past the patch, jump to another %@AB@%CS:IP%@AE@% using %@AB@%Simulate_Far_Jmp%@AE@%, or return from an interrupt handler using %@AB@%Simulate_Iret%@AE@%. %@NL@% If a particular V86 break point is no longer needed, then the VxD should call %@AB@%Remove_V86_Break_Point%@AE@%. Also, any break points that are placed in global V86 code (code loaded before Windows/386 was loaded) %@AI@%must%@AE@% be removed at %@AB@%System_Exit%@AE@% time. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%The segment used to install a V86 break point must be the code segment the %@AI@%virtual machine will use when it executes the code that is being patched. %@AI@%For example, if you place a patch at 0100:0010 and the virtual machine hits %@AI@%the break point at 0101:0000h (which is the same linear address as %@AI@%0100:0010), then an error will occur even though the VM executed a valid %@AI@%break point. %@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX %@AE@% = %@AB@%CS:IP%@AE@% %@AB@%EDX%@AE@% = Reference data (any DWORD) %@AB@%ESI%@AE@% = Offset of procedure to call %@NL@% %@3@%%@AB@%Exit:%@AE@%%@EH@%%@NL@% %@AS@% If carry set then %@AS@% Could not install break point %@AS@% else %@AS@% V86 break point successfully installed%@AE@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = %@AB@%Client CS:IP%@AE@% that faulted %@AB@%EBX %@AE@%= Handle of current VM %@AB@%EDX%@AE@% = Reference data %@AB@%ESI%@AE@% = Linear address of break point (CS << 4 + IP) %@AB@%EBP%@AE@% -> Client register structure %@NL@% %@CR:C6A00230016 @%%@CR:C6A00230017 @% %@2@%%@CR:C6A00230018 @%%@AB@%Remove_V86_Break_Point%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used to remove a V86 break point that was installed using the %@AB@%Install_V86_Break_Point%@AE@% service. It will restore the original contents of the memory automatically. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = %@AB@%CS:IP%@AE@% of break point to remove %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AS@% If carry set then %@AS@% ERROR: Not a valid V86 break point %@AS@% else %@AS@% Previous value restored at break point SEG:OFFSET%@AE@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00240001 @%%@1@%%@AB@%Chapter 24 Primary Scheduler Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% Each virtual machine is a separate task in the enhanced Windows environment. There are several services that are used to control the scheduling of virtual machines. %@NL@% Every VM has an execution priority. The VM with the highest execution priority is allowed to run unless the VM is suspended or is blocked waiting for a critical section to be freed. A VM's execution priority can be raised or lowered using the %@AB@%Adjust_Execution_Priority %@AE@%service. %@NL@% A VxD can force a particular virtual machine to run by boosting its execution priority. However, VxD authors should take care when changing the priority of a VM since doing so can radically effect the behavior of the Windows time-slicer.%@CR:C6A00240002 @%%@NL@% To allow the mutual exclusion of non-reentrant code, the scheduler supports a single critical section. The current VM can claim the critical section at any time by calling %@AB@%Begin_Critical_Section%@AE@%. If another VM owns the critical section, then the current VM will block until the critical section is released. Once the critical section is claimed, the VM's execution priority is boosted. However, VMs with higher priorities will still be allowed to execute. Normally, VMs are only boosted higher than the critical section priority when a hardware interrupt is simulated. %@NL@% A VM may be suspended if it is not in a critical section. However, the system VM can never be suspended. A suspended VM will never be scheduled, regardless of its execution priority, until it is resumed. %@NL@% An important thing to keep in mind is that since the enhanced Windows environment is a single-threaded operating system, you do not have to be concerned with a task switch from within a procedure. For example, another VM will not be scheduled while in a virtual device I/O trap handler. Task switches take place when a VxD makes an explicit call to the scheduler (i.e., %@AB@%End_Critical_Section%@AE@%) or at event processing time. Notice that since events are processed when %@AB@%Resume_Exec%@AE@% or %@AB@%Exec_Int%@AE@% are called, a task switch may occur while performing nested VM execution. Also, touching or locking unlocked demand-paged memory may cause a task-switch. In summary, the times when a task switch may occur are as follows:%@CR:C6A00240003 @%%@NL@% ■ Explicit calls to the scheduler%@NL@% ■ Performing nested execution (%@AB@%Resume_Exec%@AE@% or %@AB@%Exec_Int)%@AE@% %@NL@% ■ Touching or locking demand-paged memory %@NL@% The discussion of services providing support for the Primary Scheduler is presented in the following order: %@NL@% ■ %@AB@%Adjust_Exec_Priority%@AE@%%@NL@% ■ %@AB@%Begin_Critical_Section%@AE@%%@NL@% ■ %@AB@%Call_When_Not_Critical%@AE@%%@NL@% ■ %@AB@%Call_When_Task_Switched%@AE@%%@NL@% ■ %@AB@%Claim_Critical_Section%@AE@%%@NL@% ■ %@AB@%Create_Semaphore%@AE@%%@NL@% ■ %@AB@%Destroy_Semaphore,D%@AE@%%@NL@% ■ %@AB@%End_Crit_And_Suspend%@AE@%%@NL@% ■ %@AB@%End_Critical_Section%@AE@%%@NL@% ■ %@AB@%Get_Crit_Section_Status%@AE@%%@NL@% ■ %@AB@%No_Fail_Resume_VM%@AE@%%@NL@% ■ %@AB@%Nuke_VM%@AE@%%@NL@% ■ %@AB@%Release_Critical_Section%@AE@%%@NL@% ■ %@AB@%Resume_VM%@AE@%%@NL@% ■ %@AB@%Signal_Semaphore%@AE@%%@NL@% ■ %@AB@%Suspend_VM%@AE@%%@NL@% ■ %@AB@%Wait_Semaphore%@AE@% %@NL@% See Chapter 16, "Overview of Windows in 386 Enhanced Mode," and Chapter 17, "Virtual Device Programming Topics," for general environment discussions. %@NL@% %@CR:C6A00240004 @%%@CR:C6A00240005 @% %@2@%%@CR:C6A00240006 @%%@AB@%Adjust_Exec_Priority%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used to raise or lower the execution priority of the specified VM. Since the non-suspended VM with the highest execution priority is always the current VM, this service will cause a task switch under two circumstances: %@NL@% 1. The execution priority of the current VM is lowered (%@AB@%EAX%@AE@% is negative), and there is another VM with a higher priority that is not suspended.%@NL@% 2. The execution priority of a non-suspended VM which is not the current VM is raised (%@AB@%EAX%@AE@% is positive) higher than the current VM's execution priority. %@NL@% Note that even if the current VM is in a critical section, a task switch will still occur if the priority of another non-suspended VM is raised higher than the current VM's priority. However, this will only happen when a VM is given a time-critical boost, for example, to simulate a hardware interrupt. There are equates defined in VMM.INC that should be used when adjusting a VM's priority. They are listed below in order from lowest to highest. %@NL@% %@TH: 27 1535 02 34 44 @%Equate Name Description%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%%@AB@%Reserved_Low_Boost%@AE@% Reserved for use by system.%@AB@%Cur_Run_VM_Boost%@AE@% Time-slice scheduler boosts each VM in turn by this value to force them to run for their alloted time-slice.%@AB@%Low_Pri_Device_Boost%@AE@% Used by VxDs that need an event to be processed in a timely fashion but that are not extremely time critical.%@AB@%High_Pri_Device_Boost%@AE@% Time critical operations that should not circumvent the critical section boost should use this boost.%@AB@%Critical_Section_Boost%@AE@% VM priority is boosted by this value when %@AB@%%@AE@% %@AB@%%@AE@% %@AB@%Begin_Critical_Section%@AE@% is called.%@AB@%Time_Critical_Boost%@AE@% Events that must be processed even when another VM is in a critical section should use this boost. For example, VPICD uses this when simulating hardware interrupts.%@AB@%Reserved_High_Boost%@AE@% Reserved for use by system.%@TE: 27 1535 02 34 44 @% It is often more convienient to call %@AB@%Call_Priority_VM_Event%@AE@% than to call this service directly. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = + or - priority boost (signed long integer) %@AB@%EBX%@AE@% = VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00240007 @%%@CR:C6A00240008 @% %@2@%%@CR:C6A00240009 @%%@AB@%Begin_Critical_Section%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Use of this service causes the current VM to enter a global critical section. Only one VM can own the critical section at a time. If a VM calls this service while another VM owns the critical section, then the current VM will block until the critical section is released. %@NL@% The critical section is maintained as a count and so %@AI@%n %@AE@%calls to %@AB@%Begin_Critical_Section%@AE@% must be followed by%@AI@% n%@AE@% calls to %@AB@%End_Critical_Section%@AE@% before the VM will leave the critical section. %@NL@% When the critical section is first claimed, the execution priority of the current VM is boosted by the %@AB@%Critical_Section_Boost%@AE@% value defined in VMM.INC. This means that task switches to other VMs will only occur for time-critical operations such as simulating hardware interrupts. %@NL@% Critical sections are used for code that must not be entered in more than one VM. For example, while in MS-DOS, the DOSMGR VxD places the VM in a critical section. If another VM makes a MS-DOS call, then it will block until the critical section owner's MS-DOS call completes. However, this scenario is unlikely since a VM has an extremely high execution priority while it owns the critical section, and, therefore, other VMs will not run until the critical section is released. A scenario that%@AI@% would %@AE@%cause a VM to block is as follows: %@NL@% %@AS@% VM X calls MS-DOS to read a file. %@AS@% The DOSMGR calls Begin_Critical_Section for VM X. This raises %@AS@% VM X's priority by the Critical_Section_Boost. %@AS@% The Virtual Keyboard Device simulates an interrupt to VM Y. %@AS@% VM Y is sceduled since it has a higher execution priority %@AS@% (simulated interrupts use the Time_Critical_Boost). %@AS@% A T&SR program "wakes up" on the keyboard interrupt and calls DOS. %@AS@% The DOSMGR calls Begin_Critical_Section for VM Y. %@AS@% VM Y blocks since another VM owns the critical section. %@AS@% VM X is scheduled since it has the highest exectution priority. %@AS@% The MS-DOS read for VM X completes. %@AS@% DOSMGR calls End_Critical_Section for VM X. This lowers %@AS@% VM X's priority by the Critical_Section_Boost. %@AS@% VM Y is un-blocked and scheduled since it has the highest priority. %@AS@% VM Y continues execution at the instruction immediately after the %@AS@% call to Begin_Critical_Section and executes the MS-DOS call.%@AE@% Sometimes it is preferable to boost the current VM by the %@AB@%Time_Critical_Boost%@AE@% value instead of entering a critical section. This prevents the main thread of execution from running in all but the current VM but avoids blocking a VM when it is not really necessary. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00240010 @%%@CR:C6A00240011 @% %@2@%%@CR:C6A00240012 @%%@AB@%Call_When_Not_Critical%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service will call a VxD when the critical section is released. Notice that it will not execute the callback until the current VM's execution priority is less than the %@AB@%Critical_Section_Boost%@AE@% even when the current VM is %@AI@%not%@AE@% in a critical section. This is done because most VxDs that use this service will want to wait until the critical section is free and no hardware interrupts are being simulated. %@NL@% Normally it is more convenient to use the %@AB@%Call_Priority_VM_Event %@AE@%service than to call this service directly. %@AB@% %@AE@%%@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = Address of call-back procedure %@AB@%EDX%@AE@% = Reference data to pass to callback procedure %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% %@AB@%EBX %@AE@%= Current VM handle %@AB@%EDX%@AE@% = Reference data %@AB@%EBP%@AE@% -> Client register structure %@NL@% Procedure can corrupt %@AB@%EAX%@AE@%, %@AB@%EBX%@AE@%, %@AB@% ECX%@AE@%,%@AB@% EDX%@AE@%, %@AB@%ESI%@AE@%, %@AB@%EDI%@AE@%, and Flags %@NL@% %@CR:C6A00240013 @%%@CR:C6A00240014 @% %@2@%%@CR:C6A00240015 @%%@AB@%Call_When_Task_Switched%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service provides a way to be informed each time a different VM is to be executed. The specified procedure will be called %@AI@%every time%@AE@% a task switch occurs. Since this is a frequent operation in most environments, this service should be used sparingly, and the callback procedure should be optimized for speed. %@NL@% VxDs must sometimes save the state of a hardware device every time a task switch occurs and restore the hardware state for the VM that is about to be run. However, VM events can often be used in place of using this service. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = Pointer to procedure to call at task switch time %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Handle of VM switching away from (old %@AB@%Cur_VM_Handle%@AE@%) %@AB@%EBX%@AE@% = Current VM (just switched to) %@NL@% Procedure can destroy %@AB@%EAX%@AE@%, %@AB@%EBX%@AE@%, %@AB@%ECX%@AE@%, %@AB@%EDX%@AE@%, %@AB@%ESI%@AE@%, %@AB@%EDI%@AE@% and Flags %@NL@% %@CR:C6A00240016 @%%@CR:C6A00240017 @% %@2@%%@CR:C6A00240018 @%%@AB@%Claim_Critical_Section%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service will increment the critical section count by the specified value. It has the same effect as calling %@AB@%Begin_Critical_Section%@AE@% repeatedly but is faster. Refer to the documentation for %@AB@%Begin_Critical_Section%@AE@% for more information on the various side effects of entering a critical section. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ECX%@AE@% = # of times to claim the critical section (0 is valid & ignored) %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00240019 @%%@CR:C6A00240020 @% %@2@%%@CR:C6A00240021 @%%@AB@%Create_Semaphore%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Do not use. Reserved for future release. %@NL@% %@CR:C6A00240022 @%%@CR:C6A00240023 @% %@2@%%@CR:C6A00240024 @%%@AB@%Destroy_Semaphore%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Do not use. Reserved for future release. %@NL@% %@CR:C6A00240025 @%%@CR:C6A00240026 @% %@2@%%@CR:C6A00240027 @%%@AB@%End_Crit_And_Suspend%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service will release the critical section and immediately suspend the current VM. It is used to block a VM until another event can be processed. This service is used by the Shell VxD to display Windows dialog boxes using code similar to this: %@NL@% %@AS@% Show_Dialog_Box: %@AS@% VMMcall Get_Crit_Section_Status %@AS@% jc Cant_Do_It! %@AS@% VMMcall Begin_Critical_Section %@AS@% mov eax, Low_Pri_Device_Boost %@AS@% VMMcall Get_Sys_VM_Handle %@AS@% mov ecx, 11b %@AS@% mov edx, OFFSET32 (Dialog_Box_Data_Structure) %@AS@% mov esi, OFFSET32 Show_Dialog_Event %@AS@% VMMcall Call_Priority_VM_Event %@AS@% VMMcall End_Crit_And_Suspend %@AS@% jc Did_Not_Work! %@AS@% ; (When End_Crit_And_Suspend returns the dialog box %@AS@% ; will have been displayed)%@AE@% %@AS@% Show_Dialog_Event: %@AS@% (Call Windows to display the dialog box) %@AS@% mov ebx, [Handle_Of_VM_That_Called_Show_Dialog_Box] %@AS@% VMMcall Resume_VM %@AS@% jc Error! %@AS@% ret%@AE@% The %@AB@%Show_Dialog_Box%@AE@% procedure enters a critical section to prevent the %@AB@%Call_Priority_VM_Event %@AE@%service from switching to the system VM immediately. It then calls%@AB@% End_Crit_And_Suspend%@AE@%, which blocks the current VM. The %@AB@%Show_Dialog_Event%@AE@% procedure runs in the system (Windows) VM and actually displays the dialog box. When it is finished, it resumes the VM that called %@AB@%Show_Dialog_Box%@AE@%. %@AB@% %@AE@%%@NL@% This service must only be called when the critical section has been claimed %@AI@%once%@AE@%. That is the reason for the initial test of the critical section state in the %@AB@%Show_Dialog_Box%@AE@% procedure in the sample code. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry set then ERROR: Could not suspend VM or could not release critical section (crit claim count != 1) else Call worked. VM execution restarted by another VM calling "Resume_VM". %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00240028 @%%@CR:C6A00240029 @% %@2@%%@CR:C6A00240030 @%%@AB@%End_Critical_Section%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used to release the global critical section after a call to %@AB@%Begin_Critical_Section%@AE@% has been issued. If the critical section ownership count is decremented to 0, then ownership of the critical section is released. Since releasing the critical section lowers the execution priority of the current VM, this service will cause a task switch if a non-suspended VM has a higher priority. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00240031 @%%@CR:C6A00240032 @% %@2@%%@CR:C6A00240033 @%%@AB@%Get_Crit_Section_Status%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the critical section claim count in %@AB@%ECX%@AE@% and the owner of the critical section in %@AB@%EBX%@AE@%. If %@AB@%ECX%@AE@% is 0, then the current VM handle will be returned in %@AB@%EBX%@AE@%. %@NL@% If this service returns with the Carry flag set, then the VM is in a time-critical operation such as a hardware interrupt simulation. (It has an execution priority = %@AB@%Critical_Section_Boost%@AE@%.) %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EBX %@AE@%= VM handle of current owner (Current VM if %@AB@%ECX%@AE@% = 0) %@AB@%ECX%@AE@% = # of times critical section claimed If carry set then VM is in a time-critical operation or critical section. %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00240034 @% %@2@%%@CR:C6A00240035 @%%@AB@%No_Fail_Resume_VM%@CR:C6A00240036 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used to resume the execution of a VM that was previously suspended by a call to %@AB@%Suspend_VM%@AE@%. It differs from the normal %@AB@%Resume_VM%@AE@% service in that it will never return an error. If theVM can not be resumed, the scheduler will handle the error condition automatically and the user will be notified of the problem. The VM will then be resumed when there is sufficient memory available. A task switch will occur to the resumed VM if it has a higher priority than the current VM. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00240037 @% %@2@%%@CR:C6A00240038 @%%@AB@%Nuke_VM%@CR:C6A00240039 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used to close a VM that has not yet terminated normally. It is usually called by the Shell VxD to close VMs that the user has selected to terminate using the Window Close option on the VM's system menu. %@NL@% Needless to say, this service should be used very cautiously. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = Handle of VM to destroy %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If entry EBX = Current VM handle then This service will never return (same as Crash_Cur_VM) else If EBX = System VM handle then This service will never return (fatal error─crash to DOS) else VM has been nuked %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00240040 @%%@CR:C6A00240041 @% %@2@%%@CR:C6A00240042 @%%@AB@%Release_Critical_Section%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service will decrement the critical section count by the specified value. It has the same effect as calling %@AB@%End_Critical_Section%@AE@% repeatedly but is faster. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ECX%@AE@% = # of times to release ownership of critical section (0 valid) %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00240043 @% %@2@%%@CR:C6A00240044 @%%@AB@%Resume_VM%@CR:C6A00240045 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used to resume the execution of a VM that was previously suspended by a call to %@AB@%Suspend_VM.%@AE@% If the suspend count is decremented to 0, the VM will be placed on the queue of ready processes. A task switch will occur to the resumed VM if it has a higher priority than the current VM. %@NL@% It is sometimes not possible to resume a VM. Normally, this is because a VxD is unable to lock the VM's memory handles. Every VxD is notified when a VM is resumed and can fail the call. In this case, this service will return with Carry set, and the VM will remain suspended with a suspend count of 1. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry clear then If suspend count decremented to 0 then VM is runnable else Error could not resume (Suspend count remains 1) %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00240046 @%%@CR:C6A00240047 @% %@2@%%@CR:C6A00240048 @%%@AB@%Signal_Semaphore%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Do not use. Reserved for future release. %@NL@% %@CR:C6A00240049 @% %@2@%%@CR:C6A00240050 @%%@AB@%Suspend_VM%@CR:C6A00240051 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service will suspend the execution of a specified Virtual Machine. Any VM, except the system VM, that is not in a critical section can be suspended. This service will fail if the specified VM is the critical section owner or the system VM. The system VM can never be suspended. %@NL@% This service maintains a count that is incremented each time a VM is suspended. Therefore, if this service is called %@AI@%n%@AE@% times for a given VM, %@AB@%Resume_VM%@AE@% must be called %@AI@%n %@AE@%times before the VM will be executed. %@NL@% When a VM is being suspended for the first time (its suspend count is incremented from 0 to 1), all devices will receive a control call with %@AB@%EAX%@AE@% = %@AB@%VM_Suspend%@AE@%. Devices may %@AI@%not%@AE@% refuse to suspend a VM. However, VxDs are allowed to fail the %@AB@%VM_Resume%@AE@% control call. Subsequent calls to %@AB@%Suspend_VM%@AE@% will not result in a %@AB@%VM_Suspend%@AE@% control call until the VM has been resumed. %@NL@% When a VM is suspended, the %@AB@%CB_VM_Status%@AE@% field in the control block will have the %@AB@%VMStat_Suspended%@AE@% bit set. When a VM is suspended, VxDs should not touch any memory owned by that VM unless the VxD has previously locked the memory. You %@AI@%may, %@AE@%however, examine or modify the contents of a suspended VM's control block. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX %@AE@%= VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry flag clear then VM suspended else Error: Could not suspend VM (VM is in a critical section or is the system VM) %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00240052 @%%@CR:C6A00240053 @% %@2@%%@CR:C6A00240054 @%%@AB@%Wait_Semaphore%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Do not use. Reserved for future release. %@NL@% %@CR:C6A00250001 @%%@1@%%@AB@%Chapter 25 Time-Slice Scheduler Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% The enhanced Windows time-slice scheduler is the preemptive multitasking portion of the scheduler. It relies on time-slice priorities and flags to determine how much CPU time should be allocated to various virtual machines. %@NL@% Every VM has a %@AB@%foreground%@AE@% (focus) and a %@AB@%background%@AE@% time-slice priority. These should be distinguished from a VM's Execution Priority (described in previous chapter). A VM with the largest Execution Priority will run, preventing other VMs from executing. The VM with the largest time-slice priority will run more often than other VMs but it will not necessarily prevent other VMs from executing. %@NL@% There are three flags that affect the way the time-slicer schedules virtual machines: %@AB@%VMStat_Exclusive%@AE@%, %@AB@%VMStat_Background%@AE@%, and %@AB@%VMStat_High_Pri_Background%@AE@%. These flags are saved in the %@AB@%CB_VM_Status%@AE@% field of each VM's control block. You may examine these flags but you must never modify them directly. To change any of the flags, you must call the %@AB@%Set_Time_Slice_Priority%@AE@% service. %@NL@% If a VM that has the %@AB@%VMStat_Exclusive%@AE@% bit set is assigned the execution focus, then it will become the only VM that is allowed to run. In this case, foreground and background priorities are meaningless since the VM is using 100 percent of the CPU time. The %@AB@%Release_Time_Slice%@AE@% service has no effect on an exclusive virtual machine. High-priority background VMs will not run when an exclusive VM has the execution focus. %@NL@% The only exception to this is that Windows must be notified of certain operations in a VM and will run momentarily in the background when these operations occur. For example, if an exclusive VM is running in a window the Windows VM will wake up occasionally to update the display. %@NL@% The only exception to this is that Windows must be notified of certain operations in a VM and will run momentarily in the background when these operations occur. For example, if an exclusive VM is running in a window, the Windows VM will wake up occasionally to update the display. %@NL@% If the VM with the focus is %@AI@%not%@AE@% exclusive, then any VM that has the %@AB@%VMStat_Background%@AE@% flag set will be allowed to run based on their background time-slice priority. The VM with the focus will be scheduled based on its foreground time-slice priority. %@NL@% For this scheduler, a higher priority indicates that the VM should get %@AI@%more%@AE@% CPU time. The larger the priority, the faster the VM will run. %@NL@% The algorithm used to allocate time determines the percentage of CPU time each VM should get based on their percentage of the total of all the time-slice priorities. For example, assume the following VMs exist: %@NL@% %@TH: 14 624 02 04 20 20 32 @% Foreground Background VM Priority Priority Flags%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%1 100 50 Exclusive, Background2 100 50 Background3 50 25 (None ─ Foreground, non-exclusive)4 250 75 Background%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%%@TE: 14 624 02 04 20 20 32 @% If the execution focus is set to VM 1, then it will use 100 percent of the CPU time since it has the exclusive flag set. If the execution focus is set to VM 2, then VMs 1, 2, and 4 will run.VM 3 would not be scheduled since it does not have the background flag set. %@NL@% To determine how much time each VM should be allocated, the time-slicer first sums all the VM priorities and, then, calculates the percentage of CPU time each VM should receive as follows: %@NL@% VM 2 foreground pri = 100 / 225 * 100 = 45% of CPU %@NL@% VM 1 background pri = 50 / 225 * 100 = 22% of CPU %@NL@% VM 4 background pri = 75 / 225 * 100 = 33% of CPU ─── Total 225 %@NL@% Notice that a foreground priority of 10,000 (the maximum allowed) is special. When a VM with priority 10,000 is the execution focus VM, only high-priority background VMs will run unless the focus VM explicitly releases its time slice. This is different from an exclusive VM since other VMs %@AI@%can%@AE@% run if the focus gives up its time. %@NL@% When a VM has the %@AB@%VMStat_High_Pri_Back%@AE@% flag set it will execute in the background even if the current-focus VM has a priority of 10,000 or is exclusive. %@NL@% The discussion of services providing support for the Time-Slice Scheduler is presented in the following order: %@NL@% ■ %@AB@%Adjust_Execution_Time%@AE@%%@NL@% ■ %@AB@%Call_When_Idle%@AE@%%@NL@% ■ %@AB@%Get_Execution_Focus %@AE@%%@NL@% ■ %@AB@%Get_Time_Slice_Granularity%@AE@%%@NL@% ■ %@AB@%Get_Time_Slice_Info%@AE@%%@NL@% ■ %@AB@%Get_Time_Slice_Priority%@AE@%%@NL@% ■ %@AB@%Release_Time_Slice%@AE@%%@NL@% ■ %@AB@%Set_Execution_Focus%@AE@%%@NL@% ■ %@AB@%Set_Time_Slice_Granularity%@AE@%%@NL@% ■ %@AB@%Set_Time_Slice_Priority%@AE@%%@NL@% ■ %@AB@%Wake_Up_VM%@AE@%%@NL@% See Chapter 16, "Overview of Windows in 386 Enhanced Mode," and Chapter 17, "Virtual Device Programming Topics," for general environment discussions. %@NL@% %@CR:C6A00250002 @%%@CR:C6A00250003 @% %@2@%%@CR:C6A00250004 @%%@AB@%Adjust_Execution_Time%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service allows a VxD to change the amount of time a VM will be allowed to execute regardless of the VM's time-slice priority. Usually this service is used by VxDs such as the Virtual COM Device to boost temporarily the priority of a VM that is receiving lots of interrupts. This service can also be used to reduce the amount of time a VM will be allowed to run by passing a negative value in %@AB@%EAX%@AE@%. However, this is likely to cause execution starvation and is discouraged. %@NL@% The value specified in %@AB@%EAX%@AE@% is the number of additional (or fewer) milliseconds the VM will be allowed to run. It has the same effect on all VMs regardless of their time-slice priority. This means that if a VxD calls this service with %@AB@%EAX%@AE@% = 1000, then the specified VM will be allowed to run an additional second regardless of its time-slice priority. %@NL@% Notice that if the specified VM is not on the time-slice execution list, then this service will do nothing. It will %@AI@%not%@AE@% force a non-runnable VM to execute. In other words, a non-background VM cannot be forced to run in the background by boosting its execution time. %@NL@% Be careful using this service. It can result in starvation for other processes. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = + or - milliseconds to adjust execution time by %@AB@%EBX%@AE@% = VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00250005 @%%@CR:C6A00250006 @% %@2@%%@CR:C6A00250007 @%%@AB@%Call_When_Idle%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used by VxDs that want to perform background operations when the system is "idle". For example, this service is used by the pageswap device to asynchronously write dirty pages to the backing store. Windows is considered idle when all VMs have released their time-slice. When the Windows kernel signals that Windows is idle and all other VMs are idle, the idle call-back procedures will be called. Each call-back can either consume the idle call or pass it on to the next idle call-back in the list. Idle calls should be consumed if the VxD performs an operation that takes a significant amount of time. For example, if the pageswap device writes a dirty page to the backing store then it will consume the idle call to prevent sluggish performance. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% - Procedure to call when all VMs idle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry clear then Call-back procedure installed else Error: Could not install call-back procedure %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@3@%%@AB@%Call-Back%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = System VM Handle (current VM is always the system VM) %@AB@%EBP%@AE@% - Client register structure Return with carry SET to pass the call to next handler Return with carry CLEAR to "eat" the call-back and indicate Sys VM is not idle. Call-back procedure can modify %@AB@%EAX%@AE@%, %@AB@%EBX%@AE@%, %@AB@%ECX%@AE@%, %@AB@%EDX%@AE@%, %@AB@%ESI%@AE@%, %@AB@%EDI%@AE@%, and Flags. %@NL@% %@CR:C6A00250008 @%%@CR:C6A00250009 @% %@2@%%@CR:C6A00250010 @%%@AB@%Get_Execution_Focus%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the handle of the VM that is the focus (foreground) VM. This service can be called from an interrupt handler. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = Handle of VM with execution focus %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@%, Flags %@NL@% %@CR:C6A00250011 @%%@CR:C6A00250012 @% %@2@%%@CR:C6A00250013 @%%@AB@%Get_Time_Slice_Granularity%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the current time-slice granularity in %@AB@%EAX%@AE@%. The value returned is the minimum number of milliseconds a VM will be allowed to run before being rescheduled. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Minimum time-slice size in milliseconds %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, Flags %@NL@% %@CR:C6A00250014 @%%@CR:C6A00250015 @% %@2@%%@CR:C6A00250016 @%%@AB@%Get_Time_Slice_Info%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns information about the number of virtual machines currently scheduled by the time-slicer and the number of VMs that are idle. %@NL@% This service can be called at interrupt time. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Number of VMs scheduled %@AB@%EBX%@AE@% = Handle of VM currently scheduled %@AB@%ECX%@AE@% = Number of scheduled VMs that are currently idle %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Nothing %@NL@% %@CR:C6A00250017 @%%@CR:C6A00250018 @% %@2@%%@CR:C6A00250019 @%%@AB@%Get_Time_Slice_Priority%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the time-slice execution flags, the foreground and background priorities, and the percent of CPU usage for a specified VM. Notice that the percent of CPU time returned indicates the amount of time the VM is allowed to run, but this number will not reflect the actual amount of CPU time if any VM releases its time slice since other VMs will be allowed to execute during that VM's time slice. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Flags (Appropriate flags from CB_VM_Status control block field) %@AB@%VMMStat_Exclusive%@AE@% %@AB@%VMStat_Background%@AE@% %@AB@%VMStat_High_Pri_Back%@AE@% %@AB@%ECX %@AE@%= Foreground time-slice priority (high word 0) %@AB@%EDX%@AE@% = Background time-slice priority (high word 0) %@AB@%ESI%@AE@% = % of total CPU time used by VM %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00250020 @%%@CR:C6A00250021 @% %@2@%%@CR:C6A00250022 @%%@AB@%Release_Time_Slice%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service causes the current VM to give up any time remaining in its current time slice and allows the next VM in the time-slice queue to run. This service should be called whenever a VM is idle to allow other VMs to execute faster. If there is only one VM in the time-slice queue, this service will do nothing. %@NL@% When this service is called for a background VM, it will release the VM's time-slice, and adjust the VM's execution time by -500 milliseconds. This assures that idle background-VMs will take up very little CPU time. %@NL@% If the focus VM or a high priority background VM calls this service, it will only give up it's time slice. It's execution time will not be adjusted. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00250023 @%%@CR:C6A00250024 @% %@2@%%@CR:C6A00250025 @%%@AB@%Set_Execution_Focus%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service changes the time-slice exection focus to the specified virtual machine. The VM with the focus executes with its foreground priority. If the %@AB@%VMStat_Exclusive%@AE@% flag is set, then it will be the only VM scheduled. Otherwise, background VMs will be allowed to run. All VMs except the focus VM, background VMs, and the system VM will be suspended. %@NL@% This service must only be called in the system VM or when the new focus is the same as the current VM (%@AB@%EBX%@AE@% = Cur_VM_Handle). %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry set then ERROR: Could not set focus else Focus set successfully %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00250026 @%%@CR:C6A00250027 @% %@2@%%@CR:C6A00250028 @%%@AB@%Set_Time_Slice_Granularity%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used to change the minimum amount of time the time-slice scheduler will allocate to a VM. Smaller values will make multitasking appear smoother but will increase overhead due to the large number of task switches required. Larger values will allow more time for the VMs to execute but may make execution appear sporadic to the user. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Minimum time-slice size in milliseconds %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00250029 @%%@CR:C6A00250030 @% %@2@%%@CR:C6A00250031 @%%@AB@%Set_Time_Slice_Priority%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service sets the time-slice execution flags and the foreground and background priorities for a specified VM. %@NL@% To change part of a VM's time-slice priority status, first call %@AB@%Get_Time_Slice_Priority%@AE@%, then change only the values you are interested in and call this service. For example, to set a VM into background mode, you would do the following: %@NL@% %@AS@% mov ebx, [Handle_Of_VM_To_Change] %@AS@% VMMcall Get_Time_Slice_Priority %@AS@% or eax, VMStat_Background %@AS@% VMMcall Set_Time_Slice_Priority%@AE@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Flags %@AB@%VMStat_Exclusive%@AE@% %@AB@%VMStat_Background%@AE@% %@AB@%VMStat_High_Pri_Back%@AE@% %@AB@%EBX%@AE@% = VM handle %@AB@%ECX%@AE@% = Foreground priority (high word must be 0) %@AB@%EDX%@AE@% = Background priority (high word must be 0) %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry set then ERROR: Could not change priority / flags for VM else Priority and flags changed %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00250032 @%%@CR:C6A00250033 @% %@2@%%@CR:C6A00250034 @%%@AB@%Wake_Up_VM%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used to "wake up" a VM that called the %@AB@%Release_Time_Slice%@AE@% service and has the VMStat_Idle flag set. If the specified VM is not idle, this service will do nothing. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = Handle of VM begin woken up %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00260001 @%%@1@%%@AB@%Chapter 26 Event Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% Enhanced Windows is a single-threaded, non-reentrant operating environment. Because it is non-reentrant, VxDs that hook hardware interrupts must have some method of synchronizing their calls to VMM. For this reason, enhanced Windows has the concept of "event" processing.%@CR:C6A00260002 @%%@NL@% When a VxD is entered due to an asynchronous interrupt, such as a hardware interrupt, the VxD is limited to a very specific subset of functions. It is allowed to do only the following: %@NL@% ■ Call any Virtual PIC Device (VPICD) service%@NL@% ■ Call any asynchronous VMM service (see individual services for details)%@NL@% ■ Schedule events%@NL@% Obviously, VxDs that service hardware interrupts will often need to use services other than the ones listed above. When this is the case, the VxD will need to schedule an event. When an event is scheduled, the caller defines a procedure to call when it is OK to make any VMM call. When VMM calls this procedure, the VxD can finish processing the asynchronous event. %@NL@% VM events are often useful for VxDs that do not service hardware interrupts and can be scheduled at any time except during a Non-Maskable Interrupt (NMI). %@NL@% When an event service routine is called, it is entered with the following: %@NL@% ■ %@AB@%EBX%@AE@% = Current VM handle %@NL@% ■ %@AB@%EDX%@AE@% = Reference data passed when the routine was set up%@NL@% ■ %@AB@%EBP%@AE@% -> Client register structure%@NL@% The event callback procedure can modify %@AB@%EAX%@AE@%, %@AB@%EBX%@AE@%, %@AB@%ECX%@AE@%, %@AB@%EDX%@AE@%, %@AB@%ESI%@AE@%, and %@AB@%EDI%@AE@%. %@NL@% The discussion of services providing support for events is presented in the following order: %@NL@% ■ %@AB@%Call_Global_Event%@AE@%%@NL@% ■ %@AB@%Call_Priority_VM_Event%@AE@%%@NL@% ■ %@AB@%Call_VM_Event%@AE@%%@NL@% ■ %@AB@%Cancel_Global_Event%@AE@%%@NL@% ■ %@AB@%Cancel_Priority_VM_Event%@AE@%%@NL@% ■ %@AB@%Cancel_VM_Event%@AE@%%@NL@% ■ %@AB@%Hook_NMI_Event%@AE@%%@NL@% ■ %@AB@%Schedule_Global_Event%@AE@%%@NL@% ■ %@AB@%Schedule_VM_Event%@AE@%%@NL@% See Chapter 16, "Overview of Windows in 386 Enhanced Mode," and Chapter 17, "Virtual Device Programming Topics," for general environment discussions. %@NL@% %@CR:C6A00260003 @% %@2@%%@CR:C6A00260004 @%%@AB@%Call_Global_Event%@CR:C6A00260005 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This procedure is a faster method of servicing asynchronous events. If the current thread of execution begins in a VM (it was %@AI@%not%@AE@% an interrupt from within the VMM), then the event procedure will be called immediately. Otherwise, the event will be scheduled. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = Offset of procedure to call %@AB@%EDX%@AE@% = Reference data (will be passed back to procedure) %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If %@AB@%ESI %@AE@%= 0 then Event procedure was called else %@AB@%ESI%@AE@% = Event handle (can be used to cancel events) %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@%, Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = Current VM handle %@AB@%EDX%@AE@% = Reference data %@AB@%EBP%@AE@% -> Client Register Structure %@NL@% %@CR:C6A00260006 @%%@CR:C6A00260007 @% %@2@%%@CR:C6A00260008 @%%@AB@%Call_Priority_VM_Event%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service combines the functionality of %@AB@%Call_VM_Event, %@AB@%Call_When_VM_Ints_Enabled, Call_When_Not_Critical%@AE@%, and %@AB@%Adjust_Exec_Priority%@AE@% into one, easy to use service. As with all event services, this service can be called from an interrupt handler. %@NL@% %@AB@%Call_Priority_VM_Event%@AE@% is used by VxDs for several purposes. The most common uses are as follows: %@NL@% ■ To wait until a VM enables interrupts and the critical section is free so the VxD can call DOS or some other non-reentrant code. %@NL@% ■ To boost a VM's priority and wait until the VM enables interrupts to simulate an interrupt type event. For example, the VNETBIOS uses this service for asynchronous network request POST callbacks. %@NL@% ■ To force an event to be processed in another VM by boosting the VM's Execution Priority.%@NL@% %@3@%%@AB@%Example%@AE@%%@EH@%%@NL@% Assume a VxD implements a print spooler that will call a VM back when a buffer has been sent to the printer. It could use this service to notify the appropriate VM that its buffer has been printed as follows: %@NL@% %@AS@% VxD_Code_SEG %@AS@% BeginProc Print_Buff_Empty %@AS@% mov eax, Low_pri_Device_boost %@AS@% mov ebx, [Call_Back_VM_Handle] %@AS@% mov ecx, PEF_Wait_ForSTI or PEF_Wait_Not_Crit %@AS@% mov edx, [Call_back_CS_IP] %@AS@% mov esi, Buff_Empty_Call_Back_Event %@AS@% VMMcall Call_Priority_Event %@AS@% ret %@AS@% EndProc Print_Buff_Empty %@AS@% BeginProc Buff_Empty_Call_Back_Event %@AS@% VMMcall Begin_Nest_Exec ;Get ready to call VM %@AS@% mov ecx, edx %@AS@% shr edx, 16 ;ECX = Segment to call %@AS@% movzx edx, dx ;EDX = Offset to call %@AS@% VMMcall Build_Int_Stack_Frame %@AS@% VMMcall Resume_Exec ;call the VMM's callback %@AS@% VMMcall End_Nest_Exec %@AS@% ret %@AS@% EndProc Buff_Empty_Call_Back_Event%@AE@% The %@AB@%Print_Buff_Empty%@AE@% procedure could be called from a hardware interrupt handler in any VM. It uses %@AB@%Call_Priority_VM_Event%@AE@% to force the correct VM to be scheduled. The priority boost specified in %@AB@%EAX %@AE@%will force the event to be processed quickly although not as fast as a hardware interrupt. The options specified in the %@AB@%ECX%@AE@% register will force the event to be delayed until the critical section is free and the VM's interrupts are enabled. The reference data in %@AB@%EDX%@AE@% contains the %@AB@%CS:IP %@AE@%of the procedure to call in the VM. %@NL@% When %@AB@%Buff_Empty_Call_Back_Event%@AE@% is called it can make several assumptions: it is running in the desired VM, the critical section is not owned, and the VM has enabled interrupts. It uses the %@AB@%CS:IP%@AE@% value passed in %@AB@%EDX%@AE@% to simulate a pseudo-interrupt in the VM. The procedure called in the VM would have to execute an IRET to return from the callback. When %@AB@%Buff_Empty_Call_Back_Event%@AE@% returns, the execution priority boost is automatically deducted. %@NL@% Notice this example is incomplete ─ An actual VxD handler would need to do more work. It does not address several problems. For example %@AB@%Buff_Empty_Call_Back_Event%@AE@% does not take into account whether the call should be made to a V86 CS:IP or protected mode CS:IP. It also would not work for 32-bit protected mode programs since it would need to pass a 32-bit offset (EIP) to Simulate_Far_Call. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Priority boost (can be 0) %@AB@%EBX%@AE@% = VM handle %@AB@%ECX%@AE@% = Option flags (defined in VMM.INC) PEF_Wait_For_STI - Event will not be called until VM enables interrupts PEF_Wait_Not_Crit - Event will not be called until VM is not in a critical section or time-critical operation. PEF_Dont_Unboost - Priority of VM will not be reduced after return from event procedure. PEF_Always_Sched - Always schedule the event. This means the event procedure will never be called immediately. All other bits are reserved and must be 0. %@AB@%EDX%@AE@% = Reference data (will be passed back to procedure) %@AB@%ESI%@AE@% = Offset of procedure to call %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If ESI = 0 then Event procedure already called else Event procedure will be called later ESI = Event handle (can cancel using Cancel_Priority_VM_Event) %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = Current VM handle %@AB@%EDX%@AE@% = Reference data %@AB@%EBP%@AE@% -> Client register structure %@NL@% Procedure can modify %@AB@%EAX%@AE@%, %@AB@%EBX%@AE@%, %@AB@%ECX%@AE@%,%@AB@% EDX%@AE@%, %@AB@%ESI%@AE@%, %@AB@%EDI%@AE@%, and Flags %@NL@% %@CR:C6A00260009 @% %@2@%%@CR:C6A00260010 @%%@AB@%Call_VM_Event%@CR:C6A00260011 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This procedure is a faster method of servicing asynchronous events. If the current thread of execution begins in a virtual machine (it was %@AI@%not %@AE@%an interrupt from within the VMM) %@AI@%and%@AE@% the event is for the current VM, then the event procedure will be called immediately. Otherwise, the event will be scheduled. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle %@AB@%ESI%@AE@% = Offset of procedure to call %@AB@%EDX%@AE@% = Reference data (will be passed back to procedure) %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If ESI = 0 then Event procedure was called else ESI = Event handle (can be used to cancel events) %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% %@AB@%EBX %@AE@%= Current VM handle %@AB@%EDX%@AE@% = Reference data %@AB@%EBP%@AE@% -> Client register structure %@NL@% %@CR:C6A00260012 @%%@CR:C6A00260013 @% %@2@%%@CR:C6A00260014 @%%@AB@%Cancel_Global_Event%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used to cancel an event that was previously scheduled by %@AB@%Schedule_Global_Event%@AE@% or %@AB@%Call_Global_Event%@AE@%. Notice that, once a scheduled event is serviced, you must not attempt to cancel that event. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%It is valid to pass %@AB@%ESI%@AE@%%@AI@% = 0 to this service (it will do nothing). This is %@AI@%provided so that code that uses this service can use 0 to indicate no event %@AI@%scheduled and not have to perform a test every time it wants to cancel an %@AI@%event. For example: %@AE@%%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AS@% xor esi, esi %@AS@% xchg esi, [My_Event_Handle] %@AS@% VMMcall Cancel_Global_Event%@AE@% %@AI@%will always work even if no event was scheduled. You will also need to set [%@AB@%My_Event_Handle%@AE@%] to 0 in your event procedure. %@AE@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = Event handle (0 is acceptable) %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Global event has been canceled %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00260015 @%%@CR:C6A00260016 @% %@2@%%@CR:C6A00260017 @%%@AB@%Cancel_Priority_VM_Event%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used to cancel an event that was previously scheduled by %@AB@%Call_Priority_VM_Event.%@AE@% Notice that once a scheduled event is serviced, you must not attempt to cancel that event. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%It is valid to pass %@AB@%ESI%@AE@%%@AI@% = 0 to this service (it will do nothing). This is %@AI@%provided so that code that uses this service can use 0 to indicate no event %@AI@%scheduled and not have to perform a test every time it wants to cancel an %@AI@%event. For example: %@AE@%%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AS@% xor esi, esi %@AS@% xchg esi, [My_Event_Handle] %@AS@% VMMcall Cancel_VM_Event%@AE@% %@AI@%will always work even if no event was scheduled. You will also need to set [%@AB@%My_Event_Handle%@AE@%] to 0 in your event procedure. %@AE@% Any priority boost associated with this event will be canceled even if the %@AB@%PEF_DONT_UNBOOST%@AE@% flag was set when the event was scheduled. %@NL@% Do not use this service to cancel events scheduled using the %@AB@%Call_VM_Event %@AB@%%@AE@%or %@AB@%Schedule_VM_Event%@AE@% services. You must cancel normal VM events using the %@AB@%Cancel_VM_Event%@AE@% service. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = Priority event handle (0 is valid) %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Event canceled, %@AB@%ESI%@AE@% contains garbage %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags, %@AB@%ESI%@AE@% %@NL@% %@CR:C6A00260018 @% %@2@%%@CR:C6A00260019 @%%@AB@%Cancel_VM_Event%@CR:C6A00260020 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used to cancel an event that was previously scheduled by %@AB@%Schedule_VM_Event%@AE@% or %@AB@%Call_VM_Event%@AE@%. Notice that, once a scheduled event is serviced, you must not attempt to cancel that event. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%It is valid to pass %@AB@%ESI%@AE@%%@AI@% = 0 to this service (it will do nothing). This is %@AI@%provided so that code that uses this service can use 0 to indicate no event %@AI@%scheduled and not have to perform a test every time it wants to cancel an %@AI@%event. For example:%@AE@%%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AS@% xor esi, esi %@AS@% xchg esi, [My_Event_Handle] %@AS@% VMMcall Cancel_VM_Event%@AE@% %@AI@%will always work even if no event was scheduled. You will also need to set [%@AB@%My_Event_Handle%@AE@%] to 0 in your event procedure. %@AE@% Do not use this service to cancel events scheduled using the %@AB@%Call_Priority_VM_Event%@AE@% service. You must cancel priority events using the %@AB@%Cancel_Priority_VM_Event%@AE@% service. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle %@AB@%ESI%@AE@% = Event handle (0 is acceptable) %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00260021 @% %@2@%%@CR:C6A00260022 @%%@AB@%Hook_NMI_Event%@CR:C6A00260023 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% See documentation for Get_NMI_Handler_Addr for information on this service. This service must only be called during initialization. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = Address of NMI event procedure %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = Current VM handle %@AB@%EBP%@AE@% -> Client Register Structure %@NL@% %@CR:C6A00260024 @%%@CR:C6A00260025 @% %@2@%%@CR:C6A00260026 @%%@AB@%Schedule_Global_Event%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This procedure is used to schedule asynchronous events that are not VM specific. The events will be processed immediately before the VMM IRETs to any VM. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = Offset of procedure to call %@AB@%EDX%@AE@% = Reference data (will be passed back to procedure) %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%ESI %@AE@%= Event handle (can be used to cancel event) %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@%, Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = Current VM handle %@AB@%EDX%@AE@% = Reference data %@AB@%EBP%@AE@% -> Client register structure %@NL@% %@CR:C6A00260027 @% %@2@%%@CR:C6A00260028 @%%@AB@%Schedule_VM_Event%@CR:C6A00260029 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This procedure is used to schedule asynchronous events that are VM specific. The events will be processed immediately before the VMM IRETs to the specified VM. %@NL@% VM events will only be executed in the VM for which they were scheduled for. Therefore, if a VM event is scheduled for a VM other than the current virtual machine, it will not be processed until a task switch occurs to that VM. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle %@AB@%ESI%@AE@% = Offset of procedure to call %@AB@%EDX%@AE@% = Reference data (will be passed back to procedure) %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = Event handle (can be used to cancel event) %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@%, Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = Current VM handle (VM event was scheduled for) %@AB@%EDX%@AE@% = Reference data %@AB@%EBP%@AE@% -> Client register structure %@NL@% %@CR:C6A00270001 @%%@1@%%@AB@%Chapter 27 Timing Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% Timing services are provided for use by VxDs that need to perform periodic operations or need to establish the amount of time elapsed since a particular event. They are described here in the following order: %@NL@% ■ %@AB@%Cancel_Time_Out%@AE@%%@NL@% ■ %@AB@%Get_Last_Updated_System_Time%@AE@%%@NL@% ■ %@AB@%Get_Last_Updated_VM_Exec_Time%@AE@%%@NL@% ■ %@AB@%Get_System_Time%@AE@%%@NL@% ■ %@AB@%Get_VM_Exec_Time%@AE@%%@NL@% ■ %@AB@%Set_Global_Time_Out%@AE@%%@NL@% ■ %@AB@%Set_VM_Time_Out%@AE@%%@NL@% ■ %@AB@%Update_System_Clock%@AE@%%@NL@% See Chapter 16, "Overview of Windows in Enhanced Mode," and Chapter 17, "Virtual Device Programming Topics," for general environment discussions. %@NL@% %@CR:C6A00270002 @% %@2@%%@CR:C6A00270003 @%%@AB@%Cancel_Time_Out%@CR:C6A00270004 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used to cancel a time-out that was scheduled through either %@AB@%Set_VM_Time_Out%@AE@% or %@AB@%Set_Global_Time_Out%@AE@%. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%It is valid to pass ESI = 0 to this service (it will do nothing). This is %@AI@%provided so that code that uses this service can use 0 to indicate no %@AI@%time-out scheduled and not have to perform a test every time it wants to %@AI@%cancel a time-out. For example:%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AS@% xor esi, esi %@AS@% xchg esi, [Local_Time_Out_Handle] %@AS@% call Cancel_Time_Out %@AE@% %@AI@%will always work even if no time-out was scheduled. %@AE@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = Time-out handle to cancel OR 0 if no time-out to be canceled %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Time-out is canceled, old time-out handle now invalid %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00270005 @%%@CR:C6A00270006 @% %@2@%%@CR:C6A00270007 @%%@AB@%Get_Last_Updated_System_Time%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%The description for this service has been identified as out of date and the %@AI@%updated information was unavailable for this release.%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@CR:C6A00270008 @%%@CR:C6A00270009 @% %@2@%%@CR:C6A00270010 @%%@AB@%Get_Last_Updated_VM_Exec_Time%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%The description for this service has been identified as out of date and the %@AI@%updated information was unavailable for this release.%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@CR:C6A00270011 @% %@2@%%@CR:C6A00270012 @%%@AB@%Get_System_Time%@CR:C6A00270013 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service will return the time in milliseconds since the enhanced Windows environment was started. There is no way to detect rollover of the clock through this function but the clock will take 49.5 days to roll over. %@NL@% If you are concerned about rollover, you should schedule a time-out every 30 days. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Elapsed time in milliseconds since enhanced Windows was started %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, Flags %@NL@% %@CR:C6A00270014 @% %@2@%%@CR:C6A00270015 @%%@AB@%Get_VM_Exec_Time%@CR:C6A00270016 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the amount of time that a particular VM has executed. Every VM starts with an %@AB@%Exec_Time%@AE@% of 0 when it is created, and the %@AB@%Exec_Time%@AE@% is only increased when the VM is actually executed. Therefore, the value returned does %@AI@%not%@AE@% reflect the length of time the VM has existed. Instead, it indicates the amount of time that task has actually been the currently running VM. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EAX %@AE@%= Amount of time in milliseconds that VM has executed %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX,%@AE@% Flags %@NL@% %@CR:C6A00270017 @%%@CR:C6A00270018 @% %@2@%%@CR:C6A00270019 @%%@AB@%Set_Global_Time_Out%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Schedules a time-out that will occur after %@AB@%EAX%@AE@% milliseconds have elapsed. %@NL@% The callback procedure will be called with %@AB@%ECX%@AE@% equal to the number of milliseconds that have elapsed since the actual time-out occurred. Time-outs are often delayed by 10 milliseconds or more since the normal system timer runs at 20 milliseconds or slower. If you need more accurate time-outs, then you must increase the timer interrupt frequency. See the VTD documentation for more details on setting the timer interrupt period. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Number of milliseconds to wait until time-out %@AB@%EDX%@AE@% = Reference data to return to procedure %@AB@%ESI%@AE@% = Address of procedure to call when time-out occurs %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If time-out was NOT scheduled then ESI = 0 (This is useful since 0 = NO TIME-OUT SCHEDULED) else ESI = Time-out handle (used to cancel time-out) %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@%, Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = Current VM handle %@AB@%ECX%@AE@% = Number of EXTRA milliseconds that have elapsed %@AB@%EDX %@AE@%= Reference data %@AB@%EBP%@AE@% -> Client register structure Procedure may corrupt %@AB@%EAX%@AE@%, %@AB@%EBX%@AE@%, %@AB@%ECX%@AE@%, %@AB@%EDX%@AE@%, %@AB@%ESI%@AE@%, %@AB@%EDI%@AE@%, and Flags %@NL@% %@CR:C6A00270020 @% %@2@%%@CR:C6A00270021 @%%@AB@%Set_VM_Time_Out%@CR:C6A00270022 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Schedules a time-out that will occur after a VM has executed for the specified length of time. Notice that the time-out will occur after the VM has run for %@AB@%EAX%@AE@% milliseconds. Therefore, if there is more that one VM executing, it may take more than%@AB@% EAX%@AE@% milliseconds to occur. %@NL@% The callback procedure will be called with %@AB@%ECX%@AE@% equal to the number of milliseconds that have elapsed since the actual time-out occurred. Time-outs are often delayed by 10 milliseconds or more since the normal system timer runs at 20 milliseconds or slower. If you need more accurate time-outs, then you must increase the timer interrupt frequency. See the VTD documentation for more details on setting the timer interrupt period. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Number of milliseconds to wait until time-out %@AB@%EBX %@AE@%= VM handle %@AB@%EDX%@AE@% = Reference data to return to procedure %@AB@%ESI%@AE@% = Address of procedure to call when time-out occurs %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AS@% If time-out was NOT scheduled then %@AS@% ESI = 0 (This is useful since 0 = NO TIME-OUT SCHEDULED) %@AS@% else %@AS@% ESI = Time-out handle (used to cancel time-out)%@AE@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@%, Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = Current VM handle (VM time-out was scheduled for) %@AB@%ECX%@AE@% = Number of EXTRA milliseconds that have elapsed %@AB@%EDX %@AE@%= Reference data %@AB@%EBP%@AE@% -> Client register structure Procedure may corrupt %@AB@%EAX%@AE@%, E%@AB@%BX%@AE@%, %@AB@%ECX%@AE@%, %@AB@%EDX%@AE@%, %@AB@%ESI%@AE@%, %@AB@%EDI%@AE@%, and Flags. %@NL@% %@CR:C6A00270023 @%%@CR:C6A00270024 @% %@2@%%@CR:C6A00270025 @%%@AB@%Update_System_Clock%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service must be called only by the Virtual Timer Device. If more than one device calls this service, then the VMM timing services will not behave correctly. The timer calls this procedure to update the current system time and the current VM's execution time. The value passed in %@AB@%ECX%@AE@% is the number of milliseconds that have elapsed since the last call to this service. In other words, if the current system time is%@AI@% n%@AE@%, then, after a call to %@AB@%Update_System_Clock,%@AE@% the current system time would be %@AI@%n%@AE@%+%@AB@%ECX%@AE@%. %@NL@% This service assumes interrupts are disabled! %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ECX%@AE@% = Elapsed time in milliseconds %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00280001 @%%@1@%%@AB@%Chapter 28 Processor Fault and Interrupt Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% The discussion of services providing general support for processor faults and interrupts are presented in the following order: %@NL@% ■ %@AB@%Get_Fault_Hook_Addrs%@AE@%%@NL@% ■ %@AB@%Get_NMI_Handler_Addr%@AE@%%@NL@% @lb1 = %@AB@%Hook_PM_Fault%@AE@% %@NL@% ■ %@AB@%Hook_NMI_Event%@AE@%%@NL@% @lb1 = %@AB@%Hook_V86_Fault %@AE@%%@NL@% ■ %@AB@%Hook_V86_Page%@AE@%%@NL@% @lb1 = %@AB@%Hook_VMM_Fault %@AE@%%@NL@% ■ %@AB@%Set_NMI_Handler_Addr%@AE@%%@NL@% See Chapter 16, "Overview of Windows in 386 Enhanced Mode," and Chapter 17, "Virtual Device Programming Topics," for general environment discussions. %@NL@% %@CR:C6A00280002 @% %@2@%%@CR:C6A00280003 @%%@AB@%Get_Fault_Hook_Addrs%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Returns the address of the V86 mode, PM application, and VMM reenter fault handlers for a specified fault. If the fault does not have a handler, then this procedure will return 0. You cannot get the hook address for interrupt 2 (NMI). You must use the %@AB@%Get/Set_NMI_Handler_Addr%@AE@% services to hook interrupt 2. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Interrupt number %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry clear then EDX = Address of V86 Mode App fault handler (0 if none installed) ESI = Address of Prot Mode App fault handler (0 if none installed) EDI = Address of VMM Re-enter fault handler (0 if none installed) else ERROR: Invalid fault number %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00280004 @% %@2@%%@CR:C6A00280005 @%%@AB@%Get_NMI_Handler_Addr%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% If a VxD needs to hook the Non-Maskable Interrupt (NMI), it must first call this service to get the current NMI handler address, save the address so the current handler can be chained to it, and then set the new address. %@NL@% Notice that your NMI interrupt handler can only touch local data in the device's VxD_LOCKED_DATA_SEG. It cannot touch memory in a VM handle, V86 memory, or any other memory. It also cannot call %@AI@%any%@AE@% services, %@AI@%including%@AE@% services that can be called during normal hardware interrupts. Because an NMI can occur at any time, it is difficult to do much of anything during interrupt time that is guaranteed not to reenter a non-reentrant procedure or affect a data structure. %@NL@% Most NMI handlers will want to have an NMI event handler. This handler is similar to a normal event handler except that you only need to hook the NMI event chain once instead of scheduling an event every time. Every NMI event handler will be called every time an NMI occurs. Thus, most NMI interrupt routines simply detect that the NMI is for them and set a variable that their NMI event handler uses to perform some function. For example: %@NL@% %@AS@% Initialization: %@AS@% VMMcall Get_NMI_Handler_Addr %@AS@% mov [NMI_Chain_Addr], esi %@AS@% mov esi, OFFSET32 My_NMI_Handler %@AS@% VMMcall Set_NMI_Handler_Addr %@AS@% mov esi, OFFSET32 My_NMI_Event %@AS@% VMMcall Hook_NMI_Event %@AS@% clc %@AS@% ret%@AE@% %@AS@% My_NMI_Handler: %@AS@% in al, My_Stat_Port %@AS@% test al, My_Int_Mask %@AS@% jz SHORT MNH_Exit %@AS@% inc [NMI_From_Me] %@AS@% MNH_Chain: %@AS@% jmp [NMI_Chain_Addr]%@AE@% %@AS@% My_NMI_Event: %@AS@% xor al, al %@AS@% xchg al, [NMI_From_Me] %@AS@% test al, al %@AS@% jz SHORT NME_Exit %@AS@% (Do something here ─ NMI from my device) %@AS@% MNE_Exit: %@AS@% ret%@AE@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = Offset of current NMI handler %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@%, Flags %@NL@% %@CR:C6A00280006 @% %@2@%%@CR:C6A00280007 @%%@AB@%Hook_NMI_Event%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% See the documentation mentioned earlier in this chapter on %@AB@%Get_NMI_Handler_Addr%@AE@% for information on this service. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI %@AE@%= Address of NMI event procedure %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = Current VM handle %@AB@%EBP%@AE@% -> Client register structure %@NL@% Procedure may corrupt %@AB@%EAX%@AE@%, %@AB@%EBX%@AE@%, %@AB@%ECX%@AE@%, %@AB@%EDX%@AE@% %@NL@% %@CR:C6A00280008 @%%@CR:C6A00280009 @%%@CR:C6A00280010 @% %@2@%%@CR:C6A00280011 @%%@AB@%Hook_V86_Fault, Hook_PM_Fault, Hook_VMM_Fault%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% These services replace the fault handler procedure address with the procedure supplied. They will return the old fault handler's address or 0 to indicate that there was no previous fault handler. If the value returned in ESI is non-zero, then you may chain to the next handler with ALL REGISTERS PRESERVED. Your handler can "eat" a fault without chaining by executing a near return (not an IRET) and can modify %@AB@%EAX%@AE@%, %@AB@%EBX%@AE@%, %@AB@%ECX%@AE@%, %@AB@%EDX%@AE@%, %@AB@%ESI%@AE@%, and %@AB@%EDI%@AE@%. %@NL@% If you hook a fault during the %@AB@%Sys_Critical_Init%@AE@% phase of device initialization, your fault handler will be "behind" any VMM fault handler. If the VMM cannot properly handle a fault (for example, a General Protection fault), then it will chain to the next handler. By hooking GP faults during %@AB@%Sys_Critical_Init%@AE@% your VxD can intercept any GP fault that would otherwise crash the current VM. Any hooks installed after %@AB@%Sys_Critical_Init%@AE@% will be placed "in front of" the default VMM fault handlers. This allows devices to examine faults before they are processed by the VMM. %@NL@% Note that the processor Non-Maskable Interrupt (NMI) must be hooked using the %@AB@%Get/Set_NMI_Addr%@AE@% services (do not call Hook_xxx_Fault with %@AB@%EAX%@AE@% = 2). Also, hardware interrupts should be hooked using the Virtual Programmable Interrupt Controller Device (VPICD). A VxD should NOT attempt to circumvent the VPICD using these services. %@NL@% For version 3.0 of enhanced Windows, the largest interrupt number available is 4FH. Interrupts 00H-1FH are reserved by Intel for processor faults. Interrupts 20H-2FH are reserved by enhanced Windows. Interrupts 50H-5FH are used by the VPICD. Interrupts 40H and 41H are used by the debugger. Interrupts 42H-4FH are free for use by VxDs. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Interrupt number %@AB@%ESI%@AE@% = Procedure offset %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry clear then %@AB@%ESI%@AE@% = Old procedure offset (0 if none) else ERROR: Invalid fault number in EAX %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@%, Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% Interrupts disabled %@AB@%EBX%@AE@% = Current VM handle If fault from V86 or PM app then %@AB@%EBP%@AE@% -> Client_Register_Strucuture else VMM reentered ─ Only asynchronous services may be called. %@AB@%EBP%@AE@% -> VMM re-entrant fault stack frame %@NL@% If your handler chains, then it must preserve %@AI@%all%@AE@% registers (even registers %@AI@%not%@AE@% documented as entry conditions to this callback). %@NL@% %@CR:C6A00280012 @% %@2@%%@CR:C6A00280013 @%%@AB@%Hook_V86_Page%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service allows VxDs to intercept page faults in portions of the V86 address space of every virtual machine. It is used by devices such as the Virtual Display Device to detect when particular address ranges are accessed. %@NL@% You must specify a page number and address of a callback routine to this service. If it is installed successfully, your hook will be called every time a page fault occurs in %@AI@%any%@AE@% VM on that page. See the memory manager %@AB@%_Modify_Pages%@AE@% documentation in Chapter 19, "Memory Management Services," for making hooked pages not present and for registering the ownership of pages. %@NL@% The callback routine is responsible for mapping memory at the location of the page fault or crashing the VM. In unusual circumstances, it may be appropriate to map a NULL page at the faulting address page. See the memory manager documentation for details on mapping memory and mapping NULL pages. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%Do not rely on the contents of the %@AB@%CR2%@AE@%%@AI@% (page fault) register. Use the value %@AI@%passed to your callback in %@AE@%%@AI@%%@AB@%EAX%@AE@%%@AE@%%@AI@%. %@AE@%%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Page number (A0h - FFh) %@AB@%ESI = Address of trap routine %@AE@%%@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry flag set then ERROR: Invalid page number or page already hooked else Page hooked %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Procedure may corrupt %@AB@%EAX%@AE@%, %@AB@%EBX%@AE@%, %@AB@%ECX%@AE@%, %@AB@%EDX%@AE@%, %@AB@%ESI%@AE@%, %@AB@%EDI%@AE@%, and Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Faulting page number %@AB@%EBX%@AE@% = Current VM handle %@AB@%EBP%@AE@% does NOT point to the client register structure. %@NL@% %@CR:C6A00280014 @% %@2@%%@CR:C6A00280015 @%%@AB@%Set_NMI_Handler_Addr%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% See the documentation mentioned earlier in this chapter on %@AB@%Get_NMI_Handler_Addr%@AE@% for information on this service. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = Offset of new NMI handler %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00290001 @%%@1@%%@AB@%Chapter 29 Information Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% These services return the requested information without instigating any other action. %@NL@% They provide information on the following: %@NL@% ■ VM handles%@NL@% ■ The VMM reenter count%@NL@% ■ HMA XMS%@NL@% ■ Installation status of the debugger%@NL@% They are described here in the following order: %@NL@% ■ %@AB@%Get_Cur_VM_Handle%@AE@%%@NL@% ■ %@AB@%Get_Next_VM_Handle%@AE@%%@NL@% ■ %@AB@%Get_Sys_VM_Handle%@AE@%%@NL@% ■ %@AB@%Get_VMM_Reenter_Count%@AE@%%@NL@% ■ %@AB@%Get_VMM_Version%@AE@%%@NL@% ■ %@AB@%GetSet_HMA_Info%@AE@%%@NL@% ■ %@AB@%Test_Cur_VM_Handle%@AE@%%@NL@% ■ %@AB@%Test_Debug_Installed%@AE@%%@NL@% ■ %@AB@%Test_Sys_VM_Handle%@AE@%%@NL@% ■ %@AB@%Validate_VM_Handle%@AE@%%@NL@% See Chapter 16, "Overview of Windows in 386 Enhanced Mode," and Chapter 17, "Virtual Device Programming Topics," for general environment discussions. %@NL@% %@CR:C6A00290002 @%%@CR:C6A00290003 @% %@2@%%@CR:C6A00290004 @%%@AB@%Get_Cur_VM_Handle%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the handle to the currently running VM. It is valid to call this service at interrupt time. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = Current VM handle %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@%, Flags %@NL@% %@CR:C6A00290005 @%%@CR:C6A00290006 @% %@2@%%@CR:C6A00290007 @%%@AB@%Get_Next_VM_Handle%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% VMM maintains a list of all valid VM handles. This service provides a means of scanning the list easily. Normally, code that uses this service looks something like this: %@NL@% %@AS@% VMMcall Get_Cur_VM_Handle %@AS@% Scan_Loop: %@AS@% ... %@AS@% (Do something to VM state) %@AS@% ... %@AS@% VMMcall Get_Next_VM_Handle %@AS@% VMMcall Test_Cur_VM_Handle %@AS@% jne Scan_Loop%@AE@% This allows the state of every VM to be modified. However, there are also other uses for this service. There is no guaranteed ordering of the list other than the fact that each VM will appear in the list only once. Notice also that the list is circular so you will need to test for the end case (Next VM = First VM). It is valid to call this service at interrupt time. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = Next VM handle in VM list %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@%, Flags %@NL@% %@CR:C6A00290008 @%%@CR:C6A00290009 @% %@2@%%@CR:C6A00290010 @%%@AB@%Get_Sys_VM_Handle%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the System VM handle. It is valid to call this service at interrupt time. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = System VM handle %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@%, Flags %@NL@% %@CR:C6A00290011 @%%@CR:C6A00290012 @% %@2@%%@CR:C6A00290013 @%%@AB@%Get_VMM_Reenter_Count%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used to determine if the VMM has been reentered from an interrupt. The normal situation for reentering VMM is from a hardware interrupt, page fault, or other processor exception. Since most VMM services are non-reentrant, this test should be used to determine if other VMM services can be called or if a global event should be scheduled. Notice that the %@AB@%Call_Global_Event%@AE@% service tests this condition automatically and will schedule an event if VMM has been reentered. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%ECX%@AE@% = 0 indicates VMM has NOT been re-entered. If 0 then %@AB@%ECX%@AE@% = # of times re-entered %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00290014 @% %@2@%%@CR:C6A00290015 @%%@AB@%Get_VMM_Version%@CR:C6A00290016 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the Windows VMM version. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%AH%@AE@% = Major version number (3) %@AB@%AL%@AE@% = Minor version number (0) Carry flag clear %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% , Flags %@NL@% %@CR:C6A00290017 @% %@2@%%@CR:C6A00290018 @%%@AB@%GetSet_HMA_Info%@CR:C6A00290019 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns and sets information related to the HMA XMS region. %@NL@% This service is intended to assist the XMS driver that is part of the V86MMGR device. It allows the protected-mode XMS code to find out if there was a global HMA user in before enhanced Windows was started and allows access to the Enable count variable (Get and Set). This service is always valid (i.e., not restricted to initialization). %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ECX%@AE@% == 0 Get %@AB@%ECX%@AE@% 0 Set %@AB@%DX%@AE@% = A20 enable count to set for enhanced Windows loader NOTE THAT THE GLOBAL HMA FLAG CANNOT BE SET. It is not appropriate or valid to set this. %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If Get %@AB@% EAX%@AE@% == 0 if enhanced Windows DID NOT allocate the HMA (GLOBAL HMA User) %@AB@% EAX%@AE@% 0 if enhanced Windows allocated the HMA (NO GLOBAL HMA User) %@AB@%EDX%@AE@% = A20 enable count before enhanced Windows came in If Set %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, %@AB@%EDX%@AE@%, Flags %@NL@% %@CR:C6A00290020 @%%@CR:C6A00290021 @% %@2@%%@CR:C6A00290022 @%%@AB@%Test_Cur_VM_Handle%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This routine tests to see if the given VM handle is the handle of the currently running VM. It is valid to call this service at interrupt time. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle to test %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Zero flag is set if VM handle passed in is currently running VM's handle. %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00290023 @%%@CR:C6A00290024 @% %@2@%%@CR:C6A00290025 @%%@AB@%Test_Debug_Installed%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Tests internal flag that indicates whether a debugger exists or not. It is valid to call this service at interrupt time. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Zero flag = Debugger NOT installed (i.e., jz No_Debug_Installed) %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00290026 @%%@CR:C6A00290027 @% %@2@%%@CR:C6A00290028 @%%@AB@%Test_Sys_VM_Handle%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This routine tests to see if the given VM handle is the handle of the system VM. It is valid to call this service at interrupt time. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle to test %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Zero flag is set if VM handle passed in is system VM's handle. (je %@AB@%Is_Sys_VM%@AE@%) %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00290029 @%%@CR:C6A00290030 @% %@2@%%@CR:C6A00290031 @%%@AB@%Validate_VM_Handle%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used to test the validity of a VM handle. This service can be called at interrupt time. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle to test %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry flag set then ERROR:VM handle is invalid else Value in %@AB@%EBX%@AE@% is a valid VM handle %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00300001 @%%@1@%%@AB@%Chapter 30 Initialization Information Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% These services provide access to the SYSTEM.INI file and the environment variables. Configurable VxDs will use these services to get their configuration parameters. They are described here in the following order: %@NL@% ■ %@AB@%Convert_Boolean_String%@AE@%%@NL@% ■ %@AB@%Convert_Decimal_String%@AE@%%@NL@% ■ %@AB@%Convert_Fixed_Point_String%@AE@%%@NL@% ■ %@AB@%Convert_Hex_String%@AE@%%@NL@% ■ %@AB@%Get_Config_Directory%@AE@%%@NL@% ■ %@AB@%GetDOSVectors%@AE@%%@NL@% ■ %@AB@%Get_Environment_String%@AE@%%@NL@% ■ %@AB@%Get_Exec_Path%@AE@%%@NL@% ■ %@AB@%Get_Machine_Info%@AE@%%@NL@% ■ %@AB@%Get_Next_Profile_String%@AE@%%@NL@% ■ %@AB@%Get_Profile_Boolean%@AE@%%@NL@% ■ %@AB@%Get_Profile_Decimal_Int%@AE@%%@NL@% ■ %@AB@%Get_Profile_Fixed_Point%@AE@%%@NL@% ■ %@AB@%Get_Profile_Hex_Int%@AE@%%@NL@% ■ %@AB@%Get_Profile_String%@AE@%%@NL@% ■ %@AB@%Get_PSP_Segment%@AE@%%@NL@% ■ %@AB@%OpenFile%@AE@%%@NL@% See Chapter 16, "Overview of Windows in 386 Enhanced Mode," and Chapter 17, "Virtual Device Programming Topics," for general environment discussions. %@NL@% %@CR:C6A00300002 @%%@CR:C6A00300003 @% %@2@%%@CR:C6A00300004 @%%@AB@%Convert_Boolean_String (Initialization only)%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service attempts to determine if the string pointed to by%@AB@% EDX%@AE@% is TRUE or FALSE. There are many valid values for TRUE and FALSE. A short list of valid values for TRUE are: %@NL@% True, Yes, On, 1 %@NL@% For false they include: %@NL@% False, No, Off, 0 %@NL@% This list may grow to include other words such as "oui" and "ja." This service is only valid during initialization. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EDX%@AE@% = Pointer to ASCIIZ string to convert to boolean %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry clear then EAX = 0 if FALSE, -1 if TRUE, zero flag NOT set else String was not a valid boolean (EAX not changed) %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags, %@AB@%EAX%@AE@% %@NL@% %@CR:C6A00300005 @%%@CR:C6A00300006 @% %@2@%%@CR:C6A00300007 @%%@AB@%Convert_Decimal_String (Initialization only)%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service converts a string that contains a decimal value and returns the value in %@AB@%EAX%@AE@%. It also returns a pointer to the character that terminated the decimal integer value. This is useful for parsing entries such as: %@NL@% FOO=100,300 %@NL@% since the 100 would be returned with %@AB@%EDX %@AE@%pointing to the ",". The pointer could be incremented one byte and, then, this service called again to evaluate the second number. %@NL@% Notice that a NULL string or a string that does not contain a valid decimal integer will return 0 and %@AB@%EDX%@AE@% will not be advanced since the first character of the string terminated the analysis. This service is only valid during initialization. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EDX %@AE@%= Pointer to ASCIIZ string to convert to integer %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Value of decimal string %@AB@%EDX%@AE@% = Pointer to terminating character (non-valid decimal char) %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, %@AB@%EDX%@AE@%, Flags %@NL@% %@CR:C6A00300008 @%%@CR:C6A00300009 @% %@2@%%@CR:C6A00300010 @%%@AB@%Convert_Fixed_Point_String (Initialization only)%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the value of a fixed point decimal number string pointed to by %@AB@%EDX.%@AE@% Use %@AB@%Get_Profile_String%@AE@% to initialize %@AB@%EDX%@AE@% to point to the string to be parsed. Fixed Point is zero or more decimal digits followed by a terminator or a decimal point followed by zero or more decimal digits. The value returned is %@AB@%ECX%@AE@%*10*>. Note that decimal digits beyond the accuracy specified by %@AB@%ECX%@AE@% are ignored in the value returned in %@AB@%EAX,%@AE@% but %@AB@%EDX%@AE@% points to the byte following the last valid ASCII decimal digit. Values that begin with a minus will evaluate to negative numbers. Positive values may optionally begin with a plus sign. %@NL@% This service is only valid during initialization. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ECX%@AE@% = Number of decimal places %@AB@%EDX%@AE@% = Pointer to ASCIIZ string to convert to integer %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Value of fixed point string %@AB@%EDX%@AE@% = Pointer to terminating character (non-valid character) %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, %@AB@%EDX%@AE@%, Flags %@NL@% %@CR:C6A00300011 @%%@CR:C6A00300012 @% %@2@%%@CR:C6A00300013 @%%@AB@%Convert_Hex_String (Initialization only)%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service converts the string pointed to by %@AB@%EDX%@AE@% to Hexadecimal. Hexadecimal is zero or more hexadecimal digits (0-9, A-F) followed by a terminating character or a small or capital letter "h". The "h" has no effect on the value. %@AB@%EDX%@AE@% is left pointing to the next byte after the "h" or, if the "h" is not present, after the last valid hexadecimal digit. Use %@AB@%Get_Profile_String%@AE@% to set up %@AB@%EDX%@AE@% to point to the string to be parsed. This service is only valid during initialization. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EDX%@AE@% -> ASCIIZ string to convert to integer %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Value of hexadecimal string %@AB@%EDX%@AE@% advanced to terminating character (non-valid hex char) %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00300014 @%%@CR:C6A00300015 @% %@2@%%@CR:C6A00300016 @%%@AB@%Get_Config_Directory (Initialization only)%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns a pointer to the directory that contains the configuration files for the enhanced Windows environment (such as SYSTEM.INI). The string returned is guaranteed to be a valid, fully qualified pathname that ends with a terminating "\" followed by a NULL (0) byte. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EDX%@AE@% = Pointer to ASCIIZ directory name %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EDX%@AE@%, Flags %@NL@% %@CR:C6A00300017 @%%@CR:C6A00300018 @% %@2@%%@CR:C6A00300019 @%%@AB@%Get_Environment_String (Initialization only)%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service takes a pointer to an ASCIIZ string that is the name of an environment variable and returns a pointer to an ASCIIZ string that is the value of that environment variable. Environment variables are set using the MS-DOS %@AB@%SET%@AE@% command and should be of the format "%@AB@%SET%@AE@% <%@AI@%variable %@AS@%name%@AE@%>=<%@AI@%variable value%@AE@%>" with no intervening spaces between the variable name, the equal sign, and the variable value. Environment strings are an alternative way of setting parameters for virtual device drivers. In general, these should be used sparingly, as the environment is of limited size. Use environment strings only when the value is a global entity, used by more than one program or device driver. This service is only valid during initialization. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = pointer to ASCIIZ string environment variable name %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry is set then Environment string was not found else EDX = pointer to ASCIIZ string value of environment variable %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EDX%@AE@%, Flags %@NL@% %@CR:C6A00300020 @%%@CR:C6A00300021 @% %@2@%%@CR:C6A00300022 @%%@AB@%Get_Exec_Path (Initialization only)%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns a pointer to an ASCIIZ string that gives the full path by which WIN386.EXE was executed. It is used to locate files associated with the enhanced Windows environment or the virtual device drivers that are not in subdirectories indicated by the PATH environment variable. This service is only valid during initialization. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EDX%@AE@% = Pointer to ASCIIZ string of full path name + program name (program name is "WIN386.EXE") %@AB@%ECX%@AE@% = Number of characters in string up to and including the last "\" %@NL@% %@CR:C6A00300023 @% %@2@%%@CR:C6A00300024 @%%@AB@%GetDOSVectors (Initialization only)%@CR:C6A00300025 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the "true" INT 23 and INT 24 MS-DOS vectors. The enhanced Windows loader points these vectors at its own handlers which have the correct behavior for the enhanced Windows LOAD. When a VM is started up we wish to reset these vectors to the handlers that were in place before the loader changed them. %@NL@% THIS SERVICE SHOULD ONLY BE USED BY THE DOSMGR DEVICE. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% EAX = Segment:Offset (V86 address) that INT 23 pointed to before loader EDX = Segment:Offset (V86 address) that INT 24 pointed to before loader %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@CR:C6A00300026 @%%@CR:C6A00300027 @% %@2@%%@CR:C6A00300028 @%%@AB@%Get_Machine_Info (Initialization only)%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns information about the computer system running enhanced Windows. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%AH%@AE@% = MS-DOS Major Version %@AB@%AL%@AE@% = MS-DOS Minor Version %@AB@%BH%@AE@% = MS-DOS OEM serial number %@AB@%BL%@AE@% = Machine Model Byte (at F000:FFFE in system ROM) HIGH 16 bits of %@AB@%EBX%@AE@% are other flags GMIF_80486 EQU 10000h 80486 processor GMIF_PCXT EQU 20000h PC/XT(tm) accelerator GMIF_MCA EQU 40000h Micro Channel(tm) GMIF_EISA EQU 80000h EISA %@AB@%EDX%@AE@% = Equipment flags (as returned from Int 11h) %@AB@%ECX%@AE@% = 0 if not PS/2 or extended BIOS, else %@AB@%ECX%@AE@% contains a ring 0 linear address to System Configuration Parameters returned from BIOS service Int 15h, AH=C0h. See the PS/2 BIOS documentation for details on this structure. %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, %@AB@%EBX%@AE@%, %@AB@%ECX%@AE@%, %@AB@%EDX%@AE@%, Flags %@NL@% %@CR:C6A00300029 @%%@CR:C6A00300030 @% %@2@%%@CR:C6A00300031 @%%@AB@%Get_Next_Profile_String (Initialization only)%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service, given a pointer to a profile string, will return a pointer to the next profile string with the key name provided. It is used by devices that have multiple entries with the same key name. First, use %@AB@%Get_Profile_String%@AE@% to get the first entry with a given key name and, then, use this service to get subsequent entries. Do not modify the string returned. This service is only valid during initialization. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EDX%@AE@% = Pointer returned from previous %@AB@%Get_(Next)_Profile_String %@AE@% %@AB@%EDI %@AE@% = Pointer to key name string %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry clear then EDX = NEXT string from SYSTEM.INI else No more matching entries found %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EDX%@AE@%, Flags %@NL@% %@CR:C6A00300032 @%%@CR:C6A00300033 @% %@2@%%@CR:C6A00300034 @%%@AB@%Get_Profile_Boolean (Initialization only)%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the value of a Boolean profile entry from the SYSTEM.INI file in %@AB@%EAX%@AE@%. If the profile string is not found, then %@AB@%EAX%@AE@% will not be modified. Profile entries are of the form: %@NL@% [SectionName] KeyName=> %@NL@% That is, Section Name is delineated by square brackets and KeyName is followed by an equal sign. Neither name should have any spaces or nonprintable characters. The value following the equal sign can be in a number of formats. Boolean is "Yes," "No," "Y," "N," "True," "False," "On," "Off," "1," or "0"(foreign versions of Windows may add other language equivalents to the above). Logical TRUE returns -1 and logical FALSE returns 0. %@NL@% This service is only valid during initialization. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX %@AE@%= Default value %@AB@%ESI%@AE@% = Pointer to section name string or 0 for [386enh] %@AB@%EDI%@AE@% = Pointer to key name string %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry set Entry not found or invalid boolean value EAX = Default value else If value string was null, zero flag is set and EAX = Default value else EAX = 0 if FALSE, -1 if TRUE SYSTEM.INI entry value %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00300035 @%%@CR:C6A00300036 @% %@2@%%@CR:C6A00300037 @%%@AB@%Get_Profile_Decimal_Int (Initialization only)%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the value of a decimal profile entry from the SYSTEM.INI file in %@AB@%EAX%@AE@%. If the profile string is not found, then %@AB@%EAX%@AE@% will not be modified. Profile entries are of the form: %@NL@% [SectionName] KeyName=> %@NL@% That is, SectionName is delineated by square brackets and KeyName is followed by an equal sign. Neither name should have any spaces or non-printable characters. The value following the equal sign must be a decimal value. It can begin optionally with a plus (+) or minus (-) and must contain all decimal digits with no embedded spaces or decimal points. %@NL@% This service is only valid during initialization. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX %@AE@%= Default value (optional) %@AB@%ESI %@AE@%= Pointer to section name string or 0 for [386enh] %@AB@%EDI %@AE@%= Pointer to key name string %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry is set Entry was NOT found EAX = Default value (value passed to this procedure) else If value string was null, zero flag is set and EAX = Default value else EAX = Value of SYSTEM.INI entry %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00300038 @%%@CR:C6A00300039 @% %@2@%%@CR:C6A00300040 @%%@AB@%Get_Profile_Fixed_Point (Initialization only)%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the value of a fixed point decimal number profile entry from the SYSTEM.INI file in %@AB@%EAX%@AE@%. If the profile string is not found, then %@AB@%EAX%@AE@% will not be modified. Profile entries are of the form: %@NL@% [SectionName] KeyName=> %@NL@% That is, SectionName is delineated by square brackets and KeyName is followed by an equal sign. Neither name should have any spaces or nonprintable characters. The value following the equal sign can be in a number of formats. Fixed Point values may begin with an optional plus (+) or minus (-) followed by zero or more decimal digits followed by a terminating character or by a decimal point followed by zero or more decimal digits. The value returned is 10^%@AB@%ECX%@AE@%*>. %@NL@% This service is only valid during initialization. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Default value %@AB@%ECX%@AE@% = Number of decimal places %@AB@%ESI%@AE@% = Pointer to section name string or 0 for [386enh] %@AB@%EDI%@AE@% = Pointer to key name string %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry is set Entry was NOT found EAX = Default value (value passed to this procedure) else If value string was null, zero flag is set and EAX = Default value else EAX = Value of SYSTEM.INI entry %@NL@% %@CR:C6A00300041 @%%@CR:C6A00300042 @% %@2@%%@CR:C6A00300043 @%%@AB@%Get_Profile_Hex_Int (Initialization only)%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the value of a hexadecimal number profile entry from the SYSTEM.INI file in %@AB@%EAX%@AE@%. If the profile string is not found, then %@AB@%EAX%@AE@% will not be modified. Profile entries are of the form: %@NL@% [SectionName] KeyName=> %@NL@% That is, SectionName is delineated by square brackets and KeyName is followed by an equal sign. Neither name should have any spaces or nonprintable characters. The value following the equal sign can be in a number of formats. Hexadecimal is zero or more hexadecimal digits (0-9, A-F) followed by a terminating character or a small or capital letter "h." The "h" has no effect on the value. If the value following the equal sign is not a valid hexadecimal number, %@AB@%EAX%@AE@% is unchanged. %@NL@% This service is only valid during initialization. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Default value (optional) %@AB@%ESI%@AE@% = Pointer to section name string or 0 for [386enh] %@AB@%EDI%@AE@% = Pointer to key name string %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry is set Entry was NOT found EAX = Default value (value passed to this procedure) else If value string was null zero flag is set EAX = Default value else EAX = Value of SYSTEM.INI entry %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00300044 @%%@CR:C6A00300045 @% %@2@%%@CR:C6A00300046 @%%@AB@%Get_Profile_String (Initialization only)%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service searches the initialization file for a specified entry and returns a pointer to a string. Do %@AI@%not%@AE@% modify the string in place. The pointer returned points into the initialization file data area. If you need to modify the string, you must first copy it and, then, modify it. This service is only valid during initialization. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EDX%@AE@% = Pointer to default string (optional) %@AB@%ESI%@AE@% = Pointer to program name string or 0 for [386enh] %@AB@%EDI%@AE@% = Pointer to key name string %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry clear EDX = Pointer to ASCIIZ string from SYSTEM.INI else EDX is unchanged %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags, may change %@AB@%EDX%@AE@% %@NL@% %@CR:C6A00300047 @%%@CR:C6A00300048 @% %@2@%%@CR:C6A00300049 @%%@AB@%Get_PSP_Segment (Initialization only)%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the segment of the WIN386.EXE PSP. Use it to locate PSP values other than the EXEC path and environment variables since separate services are available for retrieving those ASCIIZ strings. Notice that a segment value is returned. To convert the segment to an address, shift the value left by 4 bits. This service is only valid during initialization. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EAX %@AE@%= Segment of WIN386.EXE PSP (high word always = 0) %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, Flags %@NL@% %@CR:C6A00300050 @% %@2@%%@CR:C6A00300051 @%%@AB@%OpenFile (Initialization only)%@CR:C6A00300052 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Open a file via searching in the standard Windows Places: %@NL@% WINDIR= ARGV[0] Current Working Directory Path %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% EDX -> Name to open. If this string contains a drive letter or path seps this routine does not search. Else the above search strategy is employed. EDI -> Buffer to hold name of file opened (at least 128 bytes) Notice that this buffer should contain a correctly formed path for the file but this is not guarenteed. This aspect of the behavior is dependent on the WINDIR and PATH environment variables being well formed. %@NL@% Must be able to do Exec_Int activity in the current VM. Temp_V86_Data_Area must not be allocated. %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Carry Set File could not be opened (file not found) Carry Clear EAX = DOS File handle (low 16 bits) OPEN IN MODE 0 (for read only) %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% EAX, FLAGS %@NL@% %@CR:C6A00310001 @%%@1@%%@AB@%Chapter 31 Linked List Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% These services provide a convenient set of routines for managing a linked-list data structure. They are described here in the following order: %@NL@% ■ %@AB@%List_Allocate%@AE@%%@NL@% ■ %@AB@%List_Attach%@AE@%%@NL@% ■ %@AB@%List_Attach_Tail%@AE@%%@NL@% ■ %@AB@%List_Create%@AE@%%@NL@% ■ %@AB@%List_Deallocate%@AE@%%@NL@% ■ %@AB@%List_Destroy%@AE@%%@NL@% ■ %@AB@%List_Get_First%@AE@%%@NL@% ■ %@AB@%List_Get_Next%@AE@%%@NL@% ■ %@AB@%List_Insert%@AE@%%@NL@% ■ %@AB@%List_Remove%@AE@%%@NL@% ■ %@AB@%List_Remove_First%@AE@%%@NL@% See Chapter 16, "Overview of Windows in 386 Enhanced Mode," and Chapter 17, "Virtual Device Programming Topics," for general environment discussions. %@NL@% %@CR:C6A00310002 @% %@2@%%@CR:C6A00310003 @%%@AB@%List_Allocate%@CR:C6A00310004 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service allocates a new node for the list specified by %@AB@%ESI%@AE@%. The contents of the node are undefined (probably nonzero). Normally, a node is immediately attached to the list through the %@AB@%List_Attach%@AE@% or %@AB@%List_Insert%@AE@% services after it has been allocated. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = List handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If list was created with LF_Alloc_Error flag then If carry clear then EAX -> New node else Error:Could not allocate node else EAX -> New node (Current VM crashed if node can not be allocated ─ Service never returns to caller) %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, Flags %@NL@% %@CR:C6A00310005 @% %@2@%%@CR:C6A00310006 @%%@AB@%List_Attach%@CR:C6A00310007 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service attaches a list node to the head (i.e., front) of a list. Notice that %@AB@%EAX%@AE@% must point to a node that was allocated using %@AB@%List_Allocate%@AE@%. %@NL@% Nodes can be attached to any list that has the same size node. This can be used, for example, to move a node from one list to another. %@NL@% %@AU@%(This figure may be found in the printed book).%@AE@%%@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = List handle %@AB@%EAX %@AE@%-> Node %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Node attached to list %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00310008 @%%@CR:C6A00310009 @% %@2@%%@CR:C6A00310010 @%%@AB@%List_Attach_Tail%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service attaches a list node to the tail (i.e., end) of a list. %@AB@%EAX%@AE@% must point to a node that was allocated using %@AB@%List_Allocate%@AE@%. %@NL@% Nodes can be attached to any list that has the same size node. This can be used, for example, to move a node from one list to another. %@NL@% %@AU@%(This figure may be found in the printed book).%@AE@%%@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = List handle %@AB@%EAX %@AE@%-> Node to insert %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Node inserted at tail (end) of list %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00310011 @% %@2@%%@CR:C6A00310012 @%%@AB@%List_Create%@CR:C6A00310013 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used to create a new list structure. This service returns a list handle that is used when calling all subsequent list services. %@NL@% Lists normally allocate nodes from a "pool" of free nodes. This prevents the overhead that would be incurred by calling %@AB@%_HeapAlloc%@AE@% and%@AB@% _HeapFree%@AE@% for every list allocation and deallocation. Once a node is created, it is never destroyed. Instead, %@AB@%List_Deallocate%@AE@% places the node back in the free pool. The node can then be reclaimed quickly when %@AB@%List_Allocate%@AE@% is called. %@NL@% If the size of the list nodes are large, you should force them to be allocated from the system heap by setting the %@AB@%LF_Use_Heap%@AE@% flag. All allocate/deallocate calls for lists created in this way will use %@AB@%_HeapAlloc%@AE@% and %@AB@%_HeapFree%@AE@% to create and destroy nodes. %@NL@% If you want to be able to access a list during hardware interrupts, you should set the %@AB@%LF_Async%@AE@% flag. This forces list operations to be atomic operations (they cannot be re-entered). If you select this option, you must call list services with %@AI@%INTERRUPTS DISABLED%@AE@% or an error will occur. You must disable interrupts even if you are not calling the list service from an interrupt. Remember, always use %@AB@%pushf/CLI/popf%@AE@% to disable interrupts. Never explicitly use STI unless other documentation states that this is permissable. Notice that since %@AB@%_HeapAllocate%@AE@% and %@AB@%_HeapFree%@AE@% cannot be called from a hardware interrupt, you cannot select this option and %@AB@%LF_Use_Heap%@AE@%. %@NL@% The%@AB@% LF_Alloc_Error%@AE@% flag should be used if you would like to recover from an allocation error (i.e., out of memory). The default behavior for a failed allocation is to crash the current VM. However, if your VxD would like to have the allocation return an error, set this flag. If this option is selected, then %@AB@%List_Allocate%@AE@% will return with the Carry flag set when an allocation fails. Otherwise, it will crash the current virtual machine whenever it cannot allocate a new node. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Flags LF_Use_Heap - All data on system heap (Can't use with LF_Async) LF_Async - List services can be called at interrupt time LF_Alloc_Error - Return from alloc with carry set if can't allocate %@AB@%ECX%@AE@% = Node size %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If Carry Flag is clear then ESI = List handle else Error: Unable to create list %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@%, Flags %@NL@% %@CR:C6A00310014 @% %@2@%%@CR:C6A00310015 @%%@AB@%List_Deallocate%@CR:C6A00310016 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service places a list node in the free memory pool. Once a node has been deallocated, it should not be referenced again. You must remove the node from any list to which it is attached before deallocating it. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = List handle %@AB@%EAX%@AE@% -> List node %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% is undefined %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, Flags %@NL@% %@CR:C6A00310017 @% %@2@%%@CR:C6A00310018 @%%@AB@%List_Destroy%@CR:C6A00310019 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service deallocates all nodes on a list and destroys the list handle. Once a list has been destroyed, its handle is no longer valid. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = List handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%ESI %@AE@%is undefined List is destroyed, all nodes deallocated. %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@%, Flags %@NL@% %@CR:C6A00310020 @% %@2@%%@CR:C6A00310021 @%%@AB@%List_Get_First%@CR:C6A00310022 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns a pointer to the first node in a list. If the list is empty, it will return 0 and the Zero Flag will be set. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = List handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AS@% If ZF is clear then %@AS@% EAX -> First node in list %@AS@% else %@AS@% List is empty. EAX = 0.%@AE@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, Flags %@NL@% %@CR:C6A00310023 @% %@2@%%@CR:C6A00310024 @%%@AB@%List_Get_Next%@CR:C6A00310025 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the next node in a list. It is used to traverse the list when searching for a specific element. If the end of the list is reached, it will return 0 and the Zero Flag will be set. %@NL@% Typically, this service is used in conjunction with %@AB@%List_Get_First%@AE@% to scan an entire list. %@NL@% %@AS@% EXAMPLE: %@AS@% BeginProc Scan_My_List %@AS@% mov esi, [My_List_Handle] %@AS@% VMMcall List_Get_First %@AS@% jz SHORT Scan_Done %@AS@% Scan_Loop: %@AS@% (Do something with EAX here) %@AS@% VMMcall List_Get_Next %@AS@% jnz Scan_Loop %@AS@% Scan_Done: %@AS@% ret %@AS@% EndProc Scan_My_List%@AE@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = List handle %@AB@%EAX%@AE@% -> Node %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If ZF is clear then %@AB@%EAX%@AE@% -> Next node in list else End of list reached. %@AB@%EAX%@AE@% = 0. %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, Flags %@NL@% %@CR:C6A00310026 @% %@2@%%@CR:C6A00310027 @%%@AB@%List_Insert%@CR:C6A00310028 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service inserts a node at a specified point in a list. The caller must specify two nodes: the node to be inserted in %@AB@%EAX%@AE@%, and a position to insert the node %@AI@%after%@AE@% in %@AB@%ECX%@AE@%. This means that node %@AB@%EAX%@AE@% will occupy the position in the list immediately after node %@AB@%ECX%@AE@%. If %@AB@%ECX%@AE@% is zero, then node %@AB@%EAX%@AE@% will be inserted at the head of the list. %@NL@% Nodes can be inserted in any list that has the same size node. This can be used, for example, to move a node from one list to another. %@NL@% %@AU@%(This figure may be found in the printed book).%@AE@%%@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = List handle %@AB@%EAX%@AE@% -> Node to insert %@AB@%ECX%@AE@% -> Node to insert after (0 to attach to head) %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Node inserted in list %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00310029 @% %@2@%%@CR:C6A00310030 @%%@AB@%List_Remove%@CR:C6A00310031 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service removes a specified node from a list.The node will %@AI@%not%@AE@% be deallocated by this service. It is up to the caller to deallocate the node or attach it to another list (it can only be attached to a list with node size equal to the original list). %@NL@% %@AU@%(This figure may be found in the printed book).%@AE@%%@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = List handle %@AB@%EAX%@AE@% -> Node to remove from list %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Node removed from list %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00310032 @%%@CR:C6A00310033 @% %@2@%%@CR:C6A00310034 @%%@AB@%List_Remove_First%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service removes the first node from a list. Notice that the node is %@AI@%not%@AE@% deallocated by this service. It is up to the caller to deallocate the node or attach it to another list (it can only be attached to a list with node size equal to the original list). %@NL@% %@AU@%(This figure may be found in the printed book).%@AE@%%@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI %@AE@%= List handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If Zero Flag is clear then EAX -> Node that has been removed from list else List is empty and EAX = 0 %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, Flags %@NL@% %@CR:C6A00320001 @%%@1@%%@AB@%Chapter 32 Error Condition Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% These error services are used by VxDs when they have detected the VM to be in an unrecoverable state. Examples of situations that might lead to such a state include an attempted VM execution of a protected instruction or an operation which might fail due to lack of memory. The services are described here in the following order: %@NL@% ■ %@AB@%Crash_Cur_VM%@AE@%%@NL@% ■ %@AB@%Fatal_Error_Handler%@AE@%%@NL@% ■ %@AB@%Fatal_Memory_Error%@AE@%%@NL@% See Chapter 16, "Overview of Windows in 386 Enhanced Mode," and Chapter 17, "Virtual Device Programming Topics," for general environment discussions. %@NL@% %@CR:C6A00320002 @% %@2@%%@CR:C6A00320003 @%%@AB@%Crash_Cur_VM%@CR:C6A00320004 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service will crash the current VM. It is to be called when a catastrophic error has occured in the VM, such as executing an illegal instruction or attempting to program a piece of hardware in a way incompatible with the device virtualization. %@NL@% If the system VM is the current VM, enhanced Windows will exit with a fatal error without explicitly crashing the other VMs. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@CR:C6A00320005 @%%@CR:C6A00320006 @% %@2@%%@CR:C6A00320007 @%%@AB@%Fatal_Error_Handler%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is called (or jumped to) when a fatal error is detected. It returns to real mode and, optionally, prints out an error message. You can hang the computer by selecting the "EF_Hang_On_Exit" flag (defined in VMM.INC). All of the devices that have been initialized are informed about the exit before returning to real mode. %@NL@% The "Fatal_Error" macro supplied in VMM.INC is a convienient way of calling this service. Examples: %@NL@% %@AS@% Fatal_Error ; %@AS@% This exits with no error message %@AS@% Fatal_Error OFFSET32 My_Err_Msg ; %@AS@% Exits and prints error message%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%Since this routine can be called by _InitializeMemoryManager, no assumptions %@AI@%about the contents of any registers or data structures should be made.%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% ESI = Ptr ASCIIZ string to display (0 if none) EAX = Exit flags to send to the loader (real mode exit code) Bit 0 = 1 - Hang system on exit to real mode Others undefined and must be 0 %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Does not return %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% All registers %@NL@% %@CR:C6A00320008 @%%@CR:C6A00320009 @% %@2@%%@CR:C6A00320010 @%%@AB@%Fatal_Memory_Error%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This routine calls the Fatal_Error_Handler with exit flags equal to zero and the message "Insufficient Memory to Initialize Windows in 386 enhanced mode." It should be called during intialization if there is not enough memory to initialize. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%Since this routine can be called by _InitializeMemoryManager, no assumptions %@AI@%about the contents of any registers or data structures should be made.%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% All registers %@NL@% %@CR:C6A00330001 @%%@1@%%@AB@%Chapter 33 Miscellaneous Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% The services discussed in this chapter provide functions not easily categorized such as hooking another VxDs API and sending system control messages. They are provided here in the following order: %@NL@% ■ %@AB@%Begin_Reentrant_Execution%@AE@%%@NL@% ■ %@AB@%End_Reentrant_Execution%@AE@%%@NL@% ■ %@AB@%Hook_Device_Service%@AE@%%@NL@% ■ %@AB@%Hook_Device_V86_API%@AE@%%@NL@% ■ %@AB@%Hook_PM_Device_API%@AE@%%@NL@% ■ %@AB@%Map_Flat%@AE@%%@NL@% ■ %@AB@%Map_Lin_To_VM_Addr%@AE@%%@NL@% ■ %@AB@%MMGR_SetNULPageAddr%@AE@%%@NL@% ■ %@AB@%Set_System_Exit_Code%@AE@%%@NL@% ■ %@AB@%Simulate_Pop%@AE@%%@NL@% ■ %@AB@%Simulate_Push%@AE@%%@NL@% ■ %@AB@%System_Control%@AE@%%@NL@% See Chapter 16. "Overview of Windows in 386 Enhanced Mode" and Chapter 17, "Virtual Device Programming Topics" for general environment discussions. %@NL@% %@CR:C6A00330002 @%%@CR:C6A00330003 @% %@2@%%@CR:C6A00330004 @%%@AB@%Begin_Reentrant_Execution%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% THIS IS A VERY DANGEROUS SERVICE. BE VERY CAREFUL WHEN CALLING IT. Most virtual devices have no reason to use this service. Do NOT use this service to avoid scheduling events on hardware interrupts. %@NL@% It is intended to be used by devices that hook VMM Faults (re-entrant processor exeptions) that must call non-asynchronous VMM or VxD services or execute a VM. This would be valid to use, for example, if a VxD provided a ring 0 software interrupt interface (although this is not recommended ─ You should provide device services through the enhanced Windows dynamic-linking mechanism). It would be INVALID to use this service during a hardware interrupt (such as a timer or disk interrupt). %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%ECX%@AE@% = Old reentrancy count (must be passed to %@AB@%End_Reentrant_Execution%@AE@%) %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%ECX%@AE@%, Flags %@NL@% %@CR:C6A00330005 @%%@CR:C6A00330006 @% %@2@%%@CR:C6A00330007 @%%@AB@%End_Reentrant_Execution%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% A VxD that calls %@AB@%Begin_Reentrant_Execution%@AE@% must call this service before returning. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ECX%@AE@% = Reentrancy count returned from %@AB@%Begin_Reentrant_Execution%@AE@% %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00330008 @%%@CR:C6A00330009 @% %@2@%%@CR:C6A00330010 @%%@AB@%Hook_Device_Service%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service allows one device to monitor or replace a device service. %@AI@%extreme care%@AE@% must be taken here not to destroy the functionality of the device whose routine is being monitored or replaced. This service also allows VMM services to be hooked (the VMM is device 1). %@NL@% Hooking a service is often useful for monitoring the activities of other devices. For example, if a device needed to know whenever a VM was set into background mode, it could use the following code: %@NL@% %@AS@% (Initialization code) %@AS@% mov eax, Set_Time_Slice_Priority %@AS@% mov esi, OFFSET32 My_Hook_Proc %@AS@% VMMcall Hook_Device_Service %@AS@% jc Error! %@AS@% mov [Real_Proc], esi%@AE@% %@AS@% BeginProc My_Hook_Proc %@AS@% test eax, VMStat_Background %@AS@% jz SHORT MHP_Chain %@AS@% pushad %@AS@% (Do something here) %@AS@% popad %@AS@% MHP_Chain: %@AS@% jmp [Real_Proc] %@AS@% EndProc My_Hook_Proc%@AE@% Every time a VxD calls %@AB@%Set_Time_Slice_Priority%@AE@%, the %@AB@%My_Hook_Proc%@AE@% procedure will be called. The hook procedure should normally chain to the actual device or VMM service although this is not required. Also, be sure to save and restore any registers in your hook procedure. %@NL@% You will notice that the sample initialization code moves %@AB@%Set_Time_Slice_Priority%@AE@% into %@AB@%EAX%@AE@%. Remember, services are defined as EQUATES, not external procedure references. Thus, %@AB@%Set_Time_Slice_Priority%@AE@% is just a number. (VMM device ID%@NL@% Your hook must preserve all registers that are not modified by the service you have hooked. Also, if flags are passed as an entry or exit parameter, your hook procedure must also preserve the flags. %@NL@% Be careful about hooking C calling convention (stack-based) services. If you want to examine the "back end" of a C calling convention service, you will need to copy the entire parameter stack frame before calling the actual service. %@NL@% More than one VxD can hook a device service. The last hook installed will be the first one called. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Device ID %@AB@%ESI%@AE@% = New procedure %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry clear then ESI = Old dynalink procedure else ERROR. Invalid Device or Service number %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@%, Flags %@NL@% %@CR:C6A00330011 @%%@CR:C6A00330012 @%%@CR:C6A00330013 @%%@CR:C6A00330014 @% %@2@%%@CR:C6A00330015 @%%@AB@%Hook_Device_V86_API, Hook_PM_Device_API%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% These services allow a VxD to hook another virtual device's V86 or protected mode API interface.You are responsible for chaining to the real API handler. Be careful to preserve the %@AB@%EBX%@AE@% and %@AB@%EBP%@AE@% registers when calling the next handler in the chain. %@NL@% Most VxDs will never need to hook another virtual device's API procedure. These services are provided mainly as a mechanism for devices that may be developed in the future to intercept API calls to other virtual devices. For example, a new version of the Virtual Mouse Device may need to intercept calls to the Virtual Display Device so that it can save and restore the mouse cursor. In such a case, these services could be used. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Device ID %@AB@%ESI %@AE@%= Offset of new API handler %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry clear then ESI = Offset of previous API handler (used to chain to next handler) else ERROR: Device does not support API interface %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@%, Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = Current VM handle %@AB@%EBP%@AE@% -> Client register structure (Same parameters as standard API entry point) %@NL@% %@CR:C6A00330016 @% %@2@%%@CR:C6A00330017 @%%@AB@%Map_Flat%@CR:C6A00330018 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service provides a convenient way of converting a SEGMENT:OFFSET or SELECTOR:OFFSET pair into a linear address. %@AB@%Map_Flat%@AE@% works only for the current VM. It determines whether the value passed to it is a V86 segment or a PM selector by the execution mode of the current VM. This allows VxDs to use identical code for PM and V86 handlers. For example, assume a VxD wanted to simulate MS-DOS reads in both V86 and protected mode. It would hook both the V86 and PM %@AB@%int%@AE@% chains with the same procedure: %@NL@% %@AS@% VxD_DOS_Read_Hook: %@AS@% cmp [ebp.Client_AH], 3Fh ; Q: Is it a read %@AS@% jne SHORT VxD_DRH_Reflect ; N: Reflect it %@AS@% ; Y: DS:DX -> Read buffer %@AS@% mov ax, (Client_DS SHL 8) + Client_DX %@AS@% VMMcall Map_Flat ; EAX = Lin addr of DS:DX %@AS@% . . . %@AS@% (Do something useful here) %@AS@% . . . %@AS@% clc ; Eat this int 21h %@AS@% ret %@AS@% VxD_DRH_Reflect: %@AS@% stc %@AS@% ret%@AE@% Notice that the above procedure does not need to examine the VM's execution state. By calling %@AB@%Map_Flat%@AE@% it converts the DS:DX pointer into a valid linear address regardless of the VM's execution mode. If the VM was running a 32-bit protected mode application, it would convert the client's DS:EDX into a linear address. For V86 and 16-bit protected-mode applications, it would ignore the high word of the Client_EDX. %@NL@% There is a macro called %@AB@%Client_Ptr_Flat%@AE@% that will generate this code automatically. For the example above you would use: %@NL@% %@AS@% Client_Ptr_Flat eax, DS, DX%@AE@% The first parameter specifies the 32-bit register to contain the linear address. The second parameter specifies the client's segment. The third parameter is optional and specifies the offset register (if blank then an offset of 0 is assumed). %@NL@% You must set %@AB@%AH%@AE@% to the equate for the client segment register you want to map flat and AL to the offset register to add to the pointer base. Alternately, if you do not want an offset added to the segment base you should set AL to -1 (0FFh). This will just convert the segment to a linear address. %@NL@% Notice that during the running of 32-bit protected mode applications, or while in "VxD_Exec" mode, pointers will use the 32-bit offset register. Therefore, the above example would use %@AB@%DS:EDX%@AE@% when the %@AB@%CB_VM_Status%@AE@% field of a VM's control block has either bit set in %@AB@%VMStat_Use32_Mask%@AE@%. This makes %@AB@%Map_Flat%@AE@% work for V86, 16-bit protected mode, and 32-bit protected mode programs. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% AH = Offset in client structure of segment register to use. AL = Offset in client structure of offset register to use OR -1 if no offset to be added to segment base %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Ring 0 linear address %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags, %@AB@%EAX%@AE@% %@NL@% %@CR:C6A00330019 @%%@CR:C6A00330020 @% %@2@%%@CR:C6A00330021 @%%@AB@%MMGR_SetNULPageAddr%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This call is used to set the physical address of the system nul page. %@NL@% It can be called at device INIT time to set the address of a KNOWN non-existant page in the system. This is usually called by the V86MMGR device because he does memory scans and therefore has a good idea about what a good page will be. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% is PHYSICAL address for NUL Page (Page number %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00330022 @%%@CR:C6A00330023 @% %@2@%%@CR:C6A00330024 @%%@AB@%Set_System_Exit_Code%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service sets the DOS system call 4Ch return code value passed in AL on the EXIT call made by the loader. Thus this sets the MS-DOS exit code that Windows Enhanced Mode exits with. This service is intended for use by the SHELL device. %@NL@% Notice that this exit code is associated only with the EXIT of the the system (i.e. the SYS VM). %@NL@% Nice that in the case of an abnormal termination the LOADER may set its own exit code, which will cause the one set with this service to be ignored. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% AL == Exit Code to set %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% EDX,FLAGS %@NL@% %@CR:C6A00330025 @% %@2@%%@CR:C6A00330026 @%%@AB@%Simulate_Pop%@CR:C6A00330027 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Returns the WORD or DWORD at the top of the current VM's client stack and adds 2 or 4 to the client's %@AB@%SP%@AE@%. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Word popped from application's stack (high word 0 if use 16 app) %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, %@AB@%Client_ESP%@AE@%, Flags %@NL@% %@CR:C6A00330028 @% %@2@%%@CR:C6A00330029 @%%@AB@%Simulate_Push%@CR:C6A00330030 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Pushes a WORD or DWORD onto the current VM's client stack and decrements the VM's %@AB@%SP%@AE@% by 2 or 4. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% If in V86 mode or 16 bit PM application then AX = WORD to push else EAX = DWORD to push %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% (D)WORD pushed on application program's stack %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%Client_ESP%@AE@%, Flags %@NL@% %@CR:C6A00330031 @% %@2@%%@CR:C6A00330032 @%%@AB@%System_Control%@CR:C6A00330033 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service sends system control messages to all the VxD's and for some messages, to parts of VMM as well. Notice that incorrect usage of the system control messages can cause erratic behavior by the system. For example, only the Shell device should initiate %@AB@%Create_VM%@AE@% and %@AB@%Destroy_VM%@AE@% messages. Also notice that when a %@AB@%Set_Device_Focus%@AE@% message is done with a device ID of zero, all devices with a settable focus must set their focus to the VM indicated. %@NL@% The valid %@AB@%System_Control %@AE@%messages are as follows: %@NL@% %@TH: 26 1162 02 23 53 @%Initialization %@AB@%Sys_Critical_Init%@AE@%%@AB@%%@AE@% %@AB@%Device_Init%@AE@%%@AB@%%@AE@% %@AB@%Init_Complete%@AE@%%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%System VM creation %@AB@%Sys_VM_Init%@AE@%%@AB@%%@AE@% %@AB@%Sys_VM_Terminate%@AE@%System VM destruction %@AB@%System_Exit%@AE@%%@AB@%%@AE@%(enhanced Windows %@AB@%Sys_Critical_Exit%@AE@%exit) Other VM creation %@AB@%Create_VM%@AE@%%@AB@%%@AE@% %@AB@%VM_Critical_Init%@AE@%%@AB@%%@AE@% %@AB@%VM_Init%@AE@%Other VM destruction %@AB@%VM_Terminate%@AE@%%@AB@%%@AE@% %@AB@%VM_Not_Executable%@AE@%%@AB@%%@AE@% %@AB@%Destroy_VM%@AE@%VM state changes %@AB@%VM_Suspend%@AE@%%@AB@%%@AE@% %@AB@%VM_Resume%@AE@%%@AB@%%@AE@% %@AB@%Set_Device_Focus%@AE@%Special messages %@AB@%Reboot_Processor%@AE@%%@AB@%%@AE@% %@AB@%Debug_Query%@AE@%%@TE: 26 1162 02 23 53 @% The control calls that are valid for devices to issue are as follows: %@NL@% %@AB@%Create_VM %@AE@% (used by SHELL) %@AB@%Destroy_VM%@AE@% (used by SHELL) %@AB@%Set_Device_Focus%@AE@% %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = System control message %@AB@%EBX%@AE@% = VM handle (if needed by message) %@AB@%ESI%@AE@%,%@AB@%EDI%@AE@%,%@AB@%EDX%@AE@% = message specific parameter, such as Device ID (for Set_Device_Focus message) %@AB@%ECX%@AE@% register is used by this service and cannot contain any parameter that will be passed through to the devices. %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Carry Set Call failed Carry Clear Call Succeeded If Entry EAX = %@AB@%Create_VM%@AE@% EBX = New VM handle created %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags, %@AB@%EBX%@AE@% if %@AB@%Create_VM%@AE@% %@NL@% %@CR:C6A00340001 @%%@1@%%@AB@%Chapter 34 Shell Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% The Shell services provide a way for VxDs to communicate with the user. This chapter presents descriptions of the Shell services in the following order: %@NL@% ■ %@AB@%SHELL_Event%@AE@%%@NL@% ■ %@AB@%SHELL_Get_Version%@AE@%%@NL@% ■ %@AB@%SHELL_Message%@AE@%%@NL@% ■ %@AB@%SHELL_Resolve_Contention%@AE@%%@NL@% ■ %@AB@%SHELL_SYSMODAL_Message%@AE@%%@NL@% See Chapter 16, "Overview of Windows in 386 Enhanced Mode," and Chapter 17, "Virtual Device Programming Topics," for general environment discussions. %@NL@% %@2@%%@CR:C6A00340002 @%%@AB@%SHELL_Event%@CR:C6A00340003 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This procedure posts an event occuring in the windows shell to VMDOSAPP. This service is primarily for SHELL to WINOLDAPP communication. The VDD also sends a couple messages to WINOLDAPP, other VxDs should have no use for this service. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% is VM Handle for Event %@AB@%ECX%@AE@% is event # %@AB@%AX%@AE@% = wParam for event High 16 bits %@AB@%EAX%@AE@% special boost flags %@AB@%ESI%@AE@% is callback procedure for event (==0 if none) %@AB@%EDX%@AE@% is reference data for event callback %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Carry Clear Event placed in queue %@AB@%EAX%@AE@% is "Event Handle" of event (only if valid entry %@AB@%ESI %@AE@% 0) Carry Set Event not placed VMDOSAPP not present Insufficient memory for placement %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% Carry Set Event could not be placed in VMDOSAPP queue %@AB@%EDX%@AE@% = reference data NOTE THAT %@AB@%EBX%@AE@% != VM Handle of event! Carry Clear Called when VMDOSAPP signals event processing complete %@AB@%EBP%@AE@% -> VMDOSAPP Client frame so registers can be accessed %@AB@%EDX%@AE@% = reference data NOTE THAT %@AB@%EBX%@AE@% != VM Handle of event! %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags, %@AB@%EAX%@AE@% %@NL@% %@2@%%@CR:C6A00340004 @%%@AB@%SHELL_Get_Version%@CR:C6A00340005 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This procedure returns the version of the Shell VxD. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%AH%@AE@% = Major version %@AB@%AL%@AE@% = Minor version Carry Flag clear %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, Flags %@NL@% %@2@%%@CR:C6A00340006 @%%@AB@%SHELL_Message%@CR:C6A00340007 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This procedure is called to put up messages. Refer to SHELL.INC and the %@AI@%Microsoft Windows Software Development Kit%@AE@% for information on message box parameters. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM Handle of VM responsible for message %@AB@%EAX%@AE@% = Message box flags (SEE MB_xxxx in SHELL.INC) %@AB@%ECX%@AE@% -> NUL terminated Message Text %@AB@%EDI%@AE@% -> NUL terminated caption Text == 0 for standard caption -> NUL for No caption %@AB@%ESI%@AE@% -> Callback procedure to call with response when dialog is finished == 0 if no call back desired %@AB@%EDX%@AE@% = Reference data for callback %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Carry Clear %@AB@%EAX%@AE@% is "Event Handle" of message Carry Set Message cannot be displayed (insufficient memory) Caller may wish to call %@AB@%SHELL_SYSMODAL_MESSAGE%@AE@% in this csae. %@AB@%SHELL_Sysmodal_Message%@AE@% will not fail. %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% Called when message box is complete %@AB@%EAX%@AE@% = Response code from dialog box (SEE IDxx in SHELL.INC) %@AB@%EDX%@AE@% = reference data %@AB@%EBX%@AE@% VM Handle of message VM %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags,%@AB@% EAX%@AE@% %@NL@% %@CR:C6A00340008 @% %@2@%%@CR:C6A00340009 @%%@AB@%SHELL_Resolve_Contention%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This procedure is called to resolve contention. It displays a dialog box in which the user chooses which VM should get ownership of the device. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = VM handle of current device owner %@AB@%EBX%@AE@% = VM handle of contending VM (Must be %@AB@%Cur_VM_Handle%@AE@%) %@AB@%ESI%@AE@% -> 8 byte device name SPACE PADDED!!! %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle of contention winner If carry is set then contention could not be resolved %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@%, Flags %@NL@% %@2@%%@CR:C6A00340010 @%%@AB@%SHELL_SYSMODAL_Message%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This procedure is called to put up SYSMODAL messages. Refer to SHELL.INC and the %@AI@%Windows SDK%@AE@% for information on message box parameters. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM Handle of VM responsible for message %@AB@%EAX%@AE@% = Message box flags (SEE MB_xxxx in SHELL.INC) NOTE THAT MB_SYSTEMMODAL MUST BE SET. %@AB@%ECX%@AE@% -> NUL terminated Message Text %@AB@%EDI%@AE@% -> NUL terminated Caption Text == 0 for standard caption -> NUL for No caption %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Response code from dialog box (SEE IDxx in SHELL.INC) %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags, %@AB@%EAX%@AE@% %@NL@% %@CR:C6A00350001 @%%@1@%%@AB@%Chapter 35 Virtual Display Device (VDD) Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% These are the Virtual Display Device (VDD) services. See Chapter 18, "The VDD and Grabber DLL," for a more detailed explanation.%@CR:C6A00350002 @%%@NL@% The services are described in the following order: %@NL@% ■ %@AB@%VDD_Msg_BakColor%@AE@%%@NL@% ■ %@AB@%VDD_Msg_ClrScrn%@AE@%%@NL@% ■ %@AB@%VDD_Msg_ForColor%@AE@%%@NL@% ■ %@AB@%VDD_Msg_SetCursorPos%@AE@%%@NL@% ■ %@AB@%VDD_Msg_TextOut%@AE@%%@NL@% ■ %@AB@%VDD_Get_GrabRtn%@AE@%%@NL@% ■ %@AB@%VDD_Get_ModTime%@AE@%%@NL@% ■ %@AB@%VDD_Get_Version%@AE@%%@NL@% ■ %@AB@%VDD_Hide_Cursor%@AE@%%@NL@% ■ %@AB@%VDD_PIF_State%@AE@%%@NL@% ■ %@AB@%VDD_Query_Access%@AE@%%@NL@% ■ %@AB@%VDD_Set_HCurTrk%@AE@%%@NL@% ■ %@AB@%VDD_Set_VMType%@AE@%%@NL@% ■ %@AB@%VDD_Query_Access%@AE@%%@NL@% %@2@%%@CR:C6A00350003 @%%@AB@%35.1 Displaying a VM's Video Memory in a Window%@AE@%%@EH@%%@NL@% There are several API services supplied to render efficiently a VM's video memory into a window. These routines are called by the Grabber. Since the Grabber runs in the Windows virtual machine, parameters are passed in the Client Registers and in VM memory pointed to by the Client Registers. %@NL@% The first step in updating windowed VMs is for the Shell to call %@AB@%Set_VMState%@AE@% with a parameter indicating that the VM is to be windowed. This will enable the VDD controller and memory state tracking and reporting of changes. When the VM is no longer windowed, %@AB@%Set_VMState%@AE@% is called again. When the VMState is not windowed, the %@AB@%Get_Mod%@AE@% call will always return no changes, and the video update message will never be generated. %@NL@% The Grabber has to be assured that the call to get the video memory is consistent with the call to get the video state; for example, displaying a mode 3 VM in mode 10 is inconsistent. To support this, the VM will not run after a %@AB@%Get_Mod%@AE@% or %@AB@%Get_Mem%@AE@% call (an exception is hardware interrupts). The VM resumes only after a %@AB@%Free_Mem%@AE@% or %@AB@%UnLock_App%@AE@% call. This way the VM's state will not change during the process of window updating. %@NL@% An exception is a VM that may update it's video memory during a timer interrupt. %@NL@% Notice that when a VM's video state changes, including controller state changes such as cursor movement and memory modification, the VDD will send WINOLDAPP a display update message. All the changes made to the video state will accumulate and be reported by %@AB@%Get_Mod%@AE@% until a %@AB@%Clear_Mod%@AE@% call is made. There will only be one display update message per %@AB@%Clear_Mod%@AE@% call. %@NL@% %@2@%%@CR:C6A00350004 @%%@AB@%35.2 Message Mode Services%@AE@%%@EH@%%@NL@% When a %@AB@%Begin_Message_Mode%@AE@% control call is made, the VDD goes into a special mode that allows the Shell device to use the VDD message services to output text to the screen without changing the VM's video state. When the message is complete, an %@AB@%End_Message_Mode%@AE@% control call is made that restores the focus VM to the hardware. %@NL@% %@CR:C6A00350005 @% %@2@%%@CR:C6A00350006 @%%@AB@%VDD_Msg_BakColor%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% After calling %@AB@%Begin_Message_Mode%@AE@%, this service sets up the background attribute. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Color (for EGA/VGA driver, a text mode attribute) %@AB@%EBX%@AE@% = VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00350007 @% %@2@%%@CR:C6A00350008 @%%@AB@%VDD_Msg_ClrScrn%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This routine is called by the Shell to initialize the screen for putting up messages. If the focus VM is the current VM, it will clear the screen immediately. Otherwise, the screen will be initialized when the focus changes. A %@AB@%Begin_Message_Mode%@AE@% device control must be issued before this service is used. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle %@AB@%EAX%@AE@% = background attribute %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = width in columns %@AB@%EDX%@AE@% = height in rows %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags, %@AB@%EAX%@AE@%, %@AB@%EDX%@AE@% %@NL@% %@CR:C6A00350009 @% %@2@%%@CR:C6A00350010 @%%@AB@%VDD_Msg_ForColor%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% After calling %@AB@%Begin_Message_Mode%@AE@%, this service sets up the foreground attribute. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Color (for EGA/VGA driver, a text mode attribute) %@AB@%EBX%@AE@% = VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00350011 @% %@2@%%@CR:C6A00350012 @%%@AB@%VDD_Msg_SetCursPos%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% After calling %@AB@%Begin_Message_Mode%@AE@%, this routine sets the cursor position. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = row %@AB@%EDX%@AE@% = column %@AB@%EBX%@AE@% = VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00350013 @% %@2@%%@CR:C6A00350014 @%%@AB@%VDD_Msg_TextOut%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% After calling %@AB@%Begin_Message_Mode%@AE@% and setting up the foreground and background colors, this service puts characters on the screen. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = address of string %@AB@%ECX%@AE@% = length of string %@AB@%EAX%@AE@% = row start %@AB@%EDX%@AE@% = column start %@AB@%EBX%@AE@% = VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@2@%%@CR:C6A00350015 @%%@AB@%35.3 Miscellaneous VDD Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% The services discussed in this section provide other VDD functions not easily catagorized, such as hiding the cursor. They are provided here in alphabetical order. %@NL@% %@CR:C6A00350016 @% %@2@%%@CR:C6A00350017 @%%@AB@%VDD_Get_GrabRtn%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the address of video grab routine. The grab routine is called by the Shell device when the appropriate hot key is pressed by the user. It makes a copy of the visible screen and controller state of the current VM. That copy is then accessible via the %@AB@%GRB_Get_GrbState%@AE@% and %@AB@%GRB_Get_GrbMem%@AE@% services. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = address of grab routine %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags, %@AB@%ESI%@AE@% %@NL@% %@CR:C6A00350018 @% %@2@%%@CR:C6A00350019 @%%@AB@%VDD_Get_ModTime%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This routine is used to determine if any video activity has occurred. The poll device uses it to determine if the VM is idle. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = System Timer at last video modification %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags, %@AB@%EAX%@AE@% %@NL@% %@CR:C6A00350020 @% %@2@%%@CR:C6A00350021 @%%@AB@%VDD_Get_Version%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the version number and device ID. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%ESI %@AE@%= ptr to 8 byte ID string %@AB@%AH%@AE@% = major version %@AB@%AL%@AE@% = minor version Carry Flag clear %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags, %@AB@%AX%@AE@%, %@AB@%ESI%@AE@% %@NL@% %@CR:C6A00350022 @% %@2@%%@CR:C6A00350023 @%%@AB@%VDD_Hide_Cursor%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service hides/shows the cursor in a window. If %@AB@%EAX%@AE@% is nonzero, then this service sets a hide cursor flag or else clears the flag. This is so that, if the mouse is using a hardware cursor, it can turn off that cursor while the VM is windowed (since the VM will no longer own the mouse). %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = 0 if cursor SHOULD be displayed in a window 0 if cursor SHOULD NOT be displayed in a window %@AB@%EBX%@AE@% = control block pointer %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00350024 @% %@2@%%@CR:C6A00350025 @%%@AB@%VDD_PIF_State%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service informs the VDD about PIF bits for the VM just created. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle %@AB@%AX%@AE@% = PIF bits %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00350026 @% %@2@%%@CR:C6A00350027 @%%@AB@%VDD_Query_Access%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Returns error if there is an attempt by the specified VM by the specified VM to access the video memory. This is used by the Virtual Mouse Device to decide whether or not to turn off the mouse cursor when a VM no longer has the mouse focus. This service should only be called in a VM Event just before returning to the VM, e.g. %@AB@%Exec_Int%@AE@% to the mouse driver. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM Handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If video access OK Carry Flag Clear else Carry Flag Set %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags Returns error if an attempt %@NL@% %@CR:C6A00350028 @% %@2@%%@CR:C6A00350029 @%%@AB@%VDD_Set_HCurTrk%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service sets flag passed to VMDOSAPP indicating that VMDOSAPP should maintain the cursor position within the display window for this application. This is called by the Keyboard driver when a keyboard interrupt is simulated into a VM. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00350030 @% %@2@%%@CR:C6A00350031 @%%@AB@%VDD_Set_VMType%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used to inform the VDD of a VM's type. The parameter explicitly passed is the windowed flag. The VM status flags, Exclusive and Background, are implicity passed. This should be called prior to running the VM and each time thereafter that any of the VM parameters are modified. Notice that, for a system critical %@AB@%Set_Focus%@AE@%, this routine may not be called before the %@AB@%Set_Focus%@AE@%. In that case, the VDD is responsible for doing an implied %@AB@%Set_VMType%@AE@% (not windowed). %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = state flag (= nonzero if changing to windowed VM) %@AB@%EBX%@AE@% = VM handle whose state is to change %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00350032 @% %@2@%%@CR:C6A00350033 @%%@AB@%VDD_Query_Access%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used by the other VxDs when they want to access video memory. The VxD should not access video memory unless this routine says it is OK. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% if access is OK, carry flag = 0 else carry flag = 1 %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00360001 @%%@1@%%@AB@%Chapter 36 Virtual Keyboard Device (VKD) Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% The Virtual Keyboard Device (VKD) provides services that support hot keys, Message Mode key handling, and keyed input to VMs. The services are presented in the following order:%@CR:C6A00360002 @%%@NL@% ■ %@AB@%VKD_Cancel_Hot_Key_State%@AE@%%@NL@% ■ %@AB@%VKD_Cancel_Paste%@AE@%%@NL@% ■ %@AB@%VKD_Define_Hot_Key%@AE@%%@NL@% ■ %@AB@%VKD_Define_Paste_Mode%@AE@%%@NL@% ■ %@AB@%VKD_Flush_Msg_Key_Queue%@AE@%%@NL@% ■ %@AB@%VKD_Force_Keys%@AE@%%@NL@% ■ %@AB@%VKD_Get_Kbd_Owner%@AE@%%@NL@% ■ %@AB@%VKD_Get_Msg_Key%@AE@%%@NL@% ■ %@AB@%VKD_Get_Version%@AE@%%@NL@% ■ %@AB@%VKD_Local_Disable_Hot_Key%@AE@%%@NL@% ■ %@AB@%VKD_Local_Enable_Hot_Key%@AE@%%@NL@% ■ %@AB@%VKD_Peek_Msg_Key%@AE@%%@NL@% ■ %@AB@%VKD_Reflect_Hot_Key%@AE@%%@NL@% ■ %@AB@%VKD_Remove_Hot_Key%@AE@%%@NL@% ■ %@AB@%VKD_Start_Paste%@AE@%%@NL@% These are protected-mode API services used by WINOLDAP to send keys to a windowed VM. %@NL@% See Chapter 16, "Overview of Windows in 386 Enhanced Mode," and Chapter 17, "Virtual Device Programming Topics," for general environment discussions. %@NL@% %@CR:C6A00360003 @% %@2@%%@CR:C6A00360004 @%%@AB@%VKD_Cancel_Hot_Key_State%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service causes the VKD to exit the hot key state. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Keys will start being passed into the focus VM again %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% None %@NL@% %@CR:C6A00360005 @% %@2@%%@CR:C6A00360006 @%%@AB@%VKD_Cancel_Paste%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service cancels the paste that was started in the VM with %@AB@%VKD_Start_Paste%@AE@%. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% is VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00360007 @% %@2@%%@CR:C6A00360008 @%%@AB@%VKD_Define_Hot_Key%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service defines a hot key notification routine. Hot keys are detected by ANDing the shift state mask with the global shift state, then comparing the resulting state with the shift state compare value. If this matches, and the key code matches, then the callback routine is called with the specified reference data in %@AB@%EDX%@AE@%. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%AL%@AE@% = scan code of the main key %@AB@%AH%@AE@% = 0, if normal code %@AB@%AH%@AE@% = 1, if extended code (ExtendedKey_B) %@AB@%AH%@AE@% = 0FFh, if either (AllowExtended_B) %@AB@%EBX%@AE@% = shift state high word is mask that is ANDed with the global shift state when checking for this hot key; low word is masked shift state compare value. Equates for common shift mask and compare values are defined in VKD.INC: HKSS_Shift for either shift key HKSS_Ctrl for either control key HKSS_Alt for either ALT key The macro ShiftState is also defined to load %@AB@%EBX%@AE@% with the mask and compare value. e.g., ShiftState <SS_ALT + SS_Toggle_mask>, SS_RAlt loads %@AB@%EBX%@AE@% so that the hot key will only be recognized when the Right ALT key is held down. VKD>INC also defines "SS_" equates for the different shift state bits and common combinations of bits. %@AB@%CL%@AE@% = flags CallOnPress - Call callback when key press is detected CallOnRelease - Call callback when key release is detected (keyboard may still be in hot-key hold state) CallOnRepeat - Call callback when repeated press is detected CallOnComplete - Call callback when the hot key state is ended(all shift modifier keys are released) or when a different hot key is entered (i.e. pressing ALT 1 2, if both ALT+1 and ALT+2 are defined hot keys, then ALT+1's callback will be called before ALT+2's to indicate that the ALT+1 is complete even though the ALT key is still down) CallOnUpDwn - Call on both press and release CallOnAll - Call on press, release and repeats PriorityNotify - Used with one of the call options to specify that the callback can only be called when interrupts are enabled and the critical section is un-owned Local_Key - Key can be locally enabled/disabled %@NL@% %@AB@%ESI%@AE@% = offset of callback routine %@AB@%EDX%@AE@% = reference data %@AB@%EDI%@AE@% = maximum notification delay if PriorityNotify is set, 0, means always notify (milliseconds) %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If Carry clear then EAX = definition handle else the definition failed (no more room) %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% Called when hot key is detected, and detection meets mask requirements. (CallOnPress, CallOnRelease, CallOnRepeat, CallOnUpDwn, or CallOnAll) %@AB@%AL%@AE@% = scan code of key %@AB@%AH%@AE@% = 0, if key just pressed (Hot_Key_Pressed) = 1, if key just released (Hot_Key_Released) = 2, if key is an auto-repeat press (Hot_Key_Repeated) = 3, hot key state ended (Hot_Key_Completed) %@AB@%EBX%@AE@% is hot key handle %@AB@%ECX%@AE@% = global shift state %@AB@%EDX%@AE@% is reference data %@AB@%EDI%@AE@% = elapsed time for delayed notification (milliseconds) (normally 0, but if PriorityNotify is specified then this value could be larger) This procedure can modify %@AB@%EAX%@AE@%, %@AB@%EBX%@AE@%, %@AB@%ECX%@AE@%, %@AB@%EDX%@AE@%, %@AB@%ESI%@AE@%, %@AB@%EDI, %@AE@%and Flags%@AB@% %@AE@%%@NL@% %@CR:C6A00360009 @% %@2@%%@CR:C6A00360010 @%%@AB@%VKD_Define_Paste_Mode%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service selects the VM's paste mode, whether INT 16 pasting can be attempted or not. Some applications hook INT 9 and do things that will not allow pasting to be done through INT 16H. Normally, VKD can detect this by setting a timeout to see if any INT 16s are being done by the application, and if not, then switching to INT 9 paste. But, some applications may do some INT 16s, in which case the paste would be broken. Therefore, this service is provided to allow the Shell device to force a VM into INT 9 paste, based only on a PIF bit. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%AL%@AE@% = 0 allow INT 16 paste attempts %@AB@%AL%@AE@% = 1 force INT 9 pasting %@AB@%EBX%@AE@% = VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00360011 @% %@2@%%@CR:C6A00360012 @%%@AB@%VKD_Flush_Msg_Key_Queue%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service flushes any available keys from the special message mode input buffer. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Input buffer has been cleared %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00360013 @% %@2@%%@CR:C6A00360014 @%%@AB@%VKD_Force_Keys%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service forces scan codes into the keyboard buffer that look exactly like they had been typed on the physical keyboard. These keys will be processed in the context of the focus VM. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% points to a buffer of scan codes %@AB@%ECX%@AE@% is # of scan codes in the buffer %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If the keyboard buffer was overflowed, then Carry set ECX is # of remaining scan codes that did not fit %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%ECX%@AE@%,Flags %@NL@% %@CR:C6A00360015 @% %@2@%%@CR:C6A00360016 @%%@AB@%VKD_Get_Kbd_Owner%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service gets the VM Handle of the keyboard focus VM. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM Handle of keyboard owner %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags, %@AB@%EBX%@AE@% %@NL@% %@CR:C6A00360017 @% %@2@%%@CR:C6A00360018 @%%@AB@%VKD_Get_Msg_Key%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the next available key from the special message mode input buffer and removes it from the buffer. If no key is available, then it returns with the Z flag set. (This is not a blocking read!) %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Z flag clear, if key was read AL = scan code AH = modifier flags MK_Shift - a SHIFT key is down MK_Ctrl - a CTRL key is down MK_Alt - an ALT key is down MK_Extended - the key is an extended key Z flag set, if no key available %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, Flags %@NL@% %@CR:C6A00360019 @% %@2@%%@CR:C6A00360020 @%%@AB@%VKD_Get_Version%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service gets the VKD version number. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%AH%@AE@% = major, %@AB@%AL%@AE@% = minor Carry Flag clear %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, Flags %@NL@% %@CR:C6A00360021 @% %@2@%%@CR:C6A00360022 @%%@AB@%VKD_Local_Disable_Hot_Key%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service disables a hot key in the specified VM. It is only allowed on hot keys which were declared with the Local_Key bit set in CL. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% is hot key handle %@AB@%EBX%@AE@% is VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00360023 @% %@2@%%@CR:C6A00360024 @%%@AB@%VKD_Local_Enable_Hot_Key%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service enables a hot key in the specified VM. It is only allowed on hot keys which were declared with the local key bit set in CL. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% is hot key handle %@AB@%EBX%@AE@% is VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00360025 @% %@2@%%@CR:C6A00360026 @%%@AB@%VKD_Peek_Msg_Key%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the next available key from the special message mode input buffer without removing it from the buffer. If no key is available, then it returns with the Z flag set. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Z flag clear, if key available AL = scan code AH = modifier flags MK_Shift - a shift key is down MK_Ctrl - a control key is down MK_Alt - an alt key is down MK_Extended - the key is an extended key Z flag set, if no key available %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, Flags %@NL@% %@CR:C6A00360027 @% %@2@%%@CR:C6A00360028 @%%@AB@%VKD_Reflect_Hot_Key%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service reflects a hot key into a specified VM and exits the hot key state. This service is normally called by a hot key notification callback routine. It enables the callback to send the hot key into a VM and pretend that it wasn't really recognized as a hot key. VKD will simulate the required key strokes to get the VM into the state of this specified shift state, then it will simulate the key strokes for the hot key itself, and finally simulate key strokes to get the VM to match the current global shift state. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% is hot key handle %@AB@%EBX%@AE@% is VM handle %@AB@%CX%@AE@% is required shift state %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Hot key has been reflected, and VKD is no longer in hot key state %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00360029 @% %@2@%%@CR:C6A00360030 @%%@AB@%VKD_Remove_Hot_Key%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service removes a defined hot key. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% is hot key definition handle to be removed %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00360031 @% %@2@%%@CR:C6A00360032 @%%@AB@%VKD_Start_Paste%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service puts a VM into paste mode by simulating keyboard activity with keystrokes taken from the specified paste buffer. Depending on the mode set with the service %@AB@%VKD_Define_Paste_Mode%@AE@% (default is to try INT 16 pasting), VKD waits for the VM to poll the keyboard BIOS through its INT 16 interface. If the VM does keyboard input through the BIOS, then VKD will simulate the keyboard input at this high level (plugging in ASCII codes.) If the VM fails to perform any INT 16s within in a timeout period, or the mode has been set to avoid INT 16 pasting, then VKD will simulate the necessary hardware interrupts to perform the pasting. Physically typed hot keys are still processed while pasting is in progress. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% is linear address of paste buffer the paste buffer contains an array of key structures: OEM_ASCII_value db ? scan_code db ? shift_state dw ? shift state bits are: 0000000000000010b shift key depressed 0000000000000100b ctrl key depressed The scan code should be FFh and the shift state FFFFh, if VKD should convert the key to a ALT+numpad sequence. (this information is identical to what is given by the Window's keyboard routine %@AB@%OEMKeyScan%@AE@%) %@AB@%EBX%@AE@% is VM handle %@AB@%ECX%@AE@% is number of paste entries in the paste buffer %@AB@%ESI%@AE@% is call back address (can be 0) %@AB@%EDX%@AE@% is reference data %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Carry clear paste is started Carry set paste failed, unable to allocate memory for buffer copy %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% Called when paste is completed or cancelled %@AB@%EAX%@AE@% is completion flags %@AB@%Paste_Complete%@AE@% - paste completed successfully %@AB@%Paste_Aborted%@AE@% - paste cancelled by user %@AB@%Paste_VM_Term%@AE@% - paste aborted because VM terminated %@AB@%EBX%@AE@% is VM handle of VM that was receiving the paste %@AB@%EDX%@AE@% is reference data Procedure can modify %@AB@%EAX%@AE@%, %@AB@%EBX%@AE@%, %@AB@%ECX%@AE@%, %@AB@%EDX%@AE@%, %@AB@%ESI%@AE@%, %@AB@%EDI%@AE@%, and Flags %@NL@% %@CR:C6A00370001 @%%@1@%%@AB@%Chapter 37 Virtual PIC Device (VPICD) Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% The Virtual Programmable Interrupt Controller Device (VPICD) routes hardware interrupts to other virtual devices, provides services that allow virtual devices to request interrupts, and simulates hardware interrupts into virtual machines. See Chapter 16, "Overview of Windows in 386 Enhanced Mode," and Chapter 17, "Virtual Device Programming Topics," for general discussions of the VPICD.%@CR:C6A00370002 @%%@NL@% Peripherals, such as disk drives and COM ports, use hardware (physical) interrupts to notify software of changes in their status. %@NL@% The topics in this chapter are presented in the following order: %@NL@% ■ Default Interrupt Handling%@NL@% ■ Virtualizing an IRQ%@NL@% ■ Virtualized IRQ Callback Procedures%@NL@% ■ VPICD Services%@NL@% ■ Grabber %@NL@% %@2@%%@CR:C6A00370003 @%%@AB@%37.1 Default Interrupt Handling%@AE@%%@EH@%%@NL@% The most basic function of VPICD is to emulate the functions of the physical interrupt controller (PIC). This entails reflecting interrupts into virtual machines and simulating I/O such as recognizing when a VM issues an EOI (End Of Interrupt), reading the mask register, etc. When VPICD is initialized, it sets up a default interrupt handler for every Interrupt ReQuest (IRQ). These handlers determine which VM an interrupt should be reflected into, and they arbitrate conflicts between virtual machines that attempt to unmask the same interrupt. %@NL@% An interrupt that is unmasked when enhanced Windows is initialized is considered a global interrupt. A global interrupt will always be reflected into the currently executing virtual machine, and any VM can mask or unmask the IRQ. If a virtual machine unmasks an IRQ that was masked when the enhanced Windows environment was initialized, it will own that IRQ. All interrupts for an owned IRQ will be reflected only to the IRQ's owner. If another virtual machine attempts to unmask the interrupt, the second VM will be terminated and the user will see a dialog box that tells him to reboot his computer. %@NL@% It is important to remember that this is only the default behavior of VPICD. If another virtual device virtualizes an IRQ it is up to the device that virtualized the interrupt to determine which VMs receive interrupts and arbitrate conflicts. Once an IRQ is virtualized, VPICD's default handling for that IRQ stops. %@NL@% %@2@%%@CR:C6A00370004 @%%@AB@%37.2 Virtualizing an IRQ%@AE@%%@EH@%%@NL@% When a virtual device needs to hook a specific IRQ (Interrupt ReQuest), it must ask VPICD for permission. If another device has already virtualized the IRQ, then the call will fail if either of the VxDs is unable to share the IRQ (both must have the %@AB@%Can_Share%@AE@% option set for two VxDs to use the same IRQ). %@NL@% When a VxD calls%@AB@% VPICD_Virtualize_IRQ%@AE@%, it passes a pointer to a structure called an IRQ Descriptor that contains the number of the IRQ and the address of several callback procedures. This structure is included in the file VPICD.INC: %@NL@% %@AS@% VPICD_IRQ_Descriptor STRUC %@AS@% VID_IRQ_Number dw ? %@AS@% VID_Options dw 0 %@AS@% VID_Hw_Int_Proc dd ? %@AS@% VID_Virt_Int_Proc dd 0 %@AS@% VID_EOI_Proc dd 0 %@AS@% VID_Mask_Change_Proc dd 0 %@AS@% VID_IRET_Proc dd 0 %@AS@% VID_IRET_Time_Out dd 500 %@AS@% VPICD_IRQ_Descriptor ENDS%@AE@% The %@AB@%VID_IRQ_Number%@AE@% contains the number of the IRQ the VxD wishes to virtualize. %@AB@%VID_Options%@AE@% is a bit field that is used to specify special options. The next five fields specify the address of various callback procedures. The final field determines the maximum amount of time in milliseconds that VPICD will allow before the interrupt is timed-out. Time-outs are very important to prevent the enhanced Windows environment from hanging while simulating a hardware interrupt. %@NL@% %@2@%%@CR:C6A00370005 @%%@AB@%37.3 Virtualized IRQ Callback Procedures%@AE@%%@EH@%%@NL@% A virtual device may specify up to five callback procedures in its %@AB@%IRQ_Descriptor%@AE@% structure. One of these, %@AB@%Hw_Int_Proc%@AE@%, is required. The other callback procedures are optional and are simply used to inform a virtual device whenever the state of the virtualized IRQ changes. For example, the %@AB@%Virt_Int_Proc%@AE@% procedure will be called whenever an interrupt is simulated into a VM; the %@AB@%Mask_Change_Proc%@AE@% is called whenever a virtual machine masks or unmasks the interrupt, etc. Each of the callback procedures is described in this section in detail and in alphabetical order. Callback procedures may modify %@AB@%EAX%@AE@%, %@AB@%EBX%@AE@%, %@AB@%ECX%@AE@%, %@AB@%EDX%@AE@%, %@AB@%ESI%@AE@%, and Flags. Although they will be called with interrupts disabled, they are allowed to enable them. If the procedures perform a lot of processing, interrupts should be executed. %@NL@% %@CR:C6A00370006 @% %@2@%%@CR:C6A00370007 @%%@AB@%VID_Hw_Int_Proc%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% The %@AB@%VID_Hw_Int_Proc%@AE@% procedure is called whenever a hardware interrupt occurs. Notice that the procedure is just that, a procedure that returns using a near return ─ not an IRET. Since the the VxD environment kernel is single-threaded, the services that this procedure is allowed to call are limited because it is possible for an interrupt to occur while executing in the VMM. Therefore, many interrupt procedures will need to use the %@AB@%Schedule_Call_Global_Event%@AE@% services to perform additional processing of an interrupt. A typical %@AB@%VID_Hw_Int_Proc%@AE@% will service the physical device, call %@AB@%VPICD_Phys_EOI%@AE@% to end the physical interrupt, and set the virtual IRQ request for a specific virtual machine. Some VxDs may never request an interrupt for a virtual machine and others may request more than one interrupt per physical interrupt. In any case, every physical interrupt does not need to be reflected 1-1 into a virtual machine. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% Interrupts Disabled %@AB@%EAX%@AE@% = IRQ handle %@AB@%EBX%@AE@% = Current VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If the IRQ is shareable then Carry Set indicates that the interrupt was not handled by VxD Carry Clear indicates that the interrupt was handled by VxD %@NL@% %@2@%%@CR:C6A00370008 @%%@AB@%VID_EOI_Proc%@CR:C6A00370009 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% The %@AB@%VID_EOI_Proc%@AE@% callback is normally used for devices that are partially virtualized. For example, the Virtual Mouse Device (VMD) lets the MS-DOS mouse driver handle all I/O with the mouse hardware. The VMD just reflects the interrupt to the VM that owns the mouse. Since it doesn't service the device during the %@AB@%VMD_Hw_Int%@AE@% procedure, it can't call %@AB@%VPICD_Phys_EOI%@AE@% at this point (since it's not the end of the interrupt). Once a virtual machine has serviced the interrupt, it will issue an EOI and, at this point, the VMD calls %@AB@%VPICD_Clear_Int_Request%@AE@% followed by %@AB@%VPICD_Phys_EOI%@AE@%. The default interrupt routines need the %@AB@%VID_EOI_Proc%@AE@% callback for the same reason ─ they have to wait for the VM to service the interrupting device before they physically signal an EOI to the IRQ. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% Interrupts Disabled %@AB@%EAX%@AE@% = IRQ handle %@AB@%EBX%@AE@% = Current VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@CR:C6A00370010 @% %@2@%%@CR:C6A00370011 @%%@AB@%VID_Virt_Int_Proc%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% The %@AB@%VID_Virt_Int_Proc%@AE@% callback can be useful for implementing critical sections around a simulated hardware interrupt. A VxD will request an interrupt, and that interrupt may be simulated at a later point in time. This callback is issued at the point when the interrupt is actually being simulated into the virtual machine. This call is made after the "point of no return" has been passed. Therefore, it is impossible for a virtual device to stop the interrupt once this call has been issued. A VxD that uses this callback will usually also use the %@AB@%VID_Virt_IRET_Proc%@AE@% callback to detect the end of the simulated interrupt. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% Interrupts Disabled %@AB@%EAX%@AE@% = IRQ handle %@AB@%EBX%@AE@% = Current VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@2@%%@CR:C6A00370012 @%%@AB@%VID_IRET_Proc%@CR:C6A00370013 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This callback is useful for devices that must simulate large numbers of interrupts in a short period of time. For example, the Virtual COM Device will simulate an interrupt, allow one character to be read from the COM port, and wait for the virtual machine to IRET before putting more data into the virtual COM receive buffer. This is because many programs would crash if too many bytes of data were queued and shovelled into the virtual machine too quickly. The crash would occur because the program's stack would overflow. For example, assume that a terminal program has an interrupt routine that looks like this: %@NL@% %@AS@% push ax ; (Push AX, DX is the %@AS@% push dx ; minimum possible) %@AS@% (Read a byte from the COM port) %@AS@% mov al, 20h ; Non-Specific EOI %@AS@% out 20h, al ; EOI the PIC %@AS@% sti ; Enable interrupts %@AS@% (Do other stuff) %@AS@% pop dx %@AS@% pop ax %@AS@% iret%@AE@% This is a perfectly valid interrupt procedure and, in fact, it is very common in actual terminal programs. Now consider what would happen if the Virtual COM Device (VCD) had 500 bytes of data queued, and it did not use the %@AB@%VID_IRET_Proc%@AE@% callback. When the VM reads a byte of data, VCD puts the next byte of data into the receive buffer and request another interrupt. When the terminal program executes the STI instruction, VPICD immediately simulates another COM interrupt. This sequence of events is repeated 499 times, each time nesting an interrupt while in the terminal program's interrupt routine. The problem is that the IRET frame on the stack requires 6 bytes per interrupt, and the 2 pushed registers take up 4 more bytes for a total of 10 bytes per interrupt. Since we would nest 500 interrupts, 5K bytes of stack space would be required. %@NL@% Since this is obviously unacceptable, VCD waits for the terminal program to IRET before simulating another interrupt. The Virtual Timer uses similar logic to prevent shoving too many timer interrupts into a virtual machine. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% Interrupts Disabled %@AB@%EAX %@AE@%= IRQ handle %@AB@%EBX%@AE@% = Current VM handle If carry is set then interrupt timed-out %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@CR:C6A00370014 @% %@2@%%@CR:C6A00370015 @%%@AB@%VID_Mask_Change_Proc%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% The %@AB@%VID_Mask_Change_Proc%@AE@% is often used to detect contention for a device. The default interrupt routines use this callback to detect conflicts with nonglobal interrupts. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% Interrupts Disabled %@AB@%EAX%@AE@% = IRQ handle %@AB@%EBX%@AE@% = Current VM handle %@AB@%ECX%@AE@% = 0 if VM is unmasking IRQ, 0 if masking IRQ %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@2@%%@CR:C6A00370016 @%%@AB@%37.4 VPICD Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% This section presents descriptions of the VPICD services in alphabetical order. %@NL@% %@CR:C6A00370017 @% %@2@%%@CR:C6A00370018 @%%@AB@%VPICD_Call_When_Hw_Int%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% You must call this procedure with interrupts %@AI@%disabled%@AE@%. This service enables other VxDs to be notified when every hardware interrupt occurs. It is intended to be used by the Virtual DMA Device (VDMAD) to detect when a DMA transfer is complete. However, any VxD can use this service. It should be noted though, that since your callback will be called for every hardware interrupt, it could have a major performance impact on systems with devices that interrupt frequently. Therefore, you should avoid using this service. %@NL@% A callback installed by this service is responsible for chaining to the next handler in the interrupt filter chain, and it must preserve the %@AB@%EBX%@AE@% register for the next handler. %@NL@% %@AS@% Sample_Hook_Init: %@AS@% pushfd %@AS@% cli %@AS@% mov esi, OFFSET32 My_Int_Hook %@AS@% VxDcall VPICD_Call_When_Hw_Int %@AS@% popfd %@AS@% mov [Next_Int_Hook_Addr], esi %@AS@% clc %@AS@% ret %@AS@% %@AS@% My_Int_Hook: %@AS@% push ebx %@AS@% (Do something useful here) %@AS@% pop ebx %@AS@% jmp [Next_Int_Hook_Addr]%@AE@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% -> Procedure to call %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% -> Procedure to chain to %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@%, Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = %@AB@%Cur_VM_Handle%@AE@% %@NL@% %@CR:C6A00370019 @% %@2@%%@CR:C6A00370020 @%%@AB@%VPICD_Clear_Int_Request%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service resets an IRQ request that was previously set by a call to %@AB@%VPICD_Set_Int_Request%@AE@%. If the IRQ is being shared with another device, then this service may not reset the virtual request if another device has also set the virtual IRQ. However, the request will be cleared when all devices that have called %@AB@%Set_Int_Request%@AE@% call this service. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = IRQ handle %@AB@%EBX%@AE@% = VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Virtual IRQ request is cleared %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00370021 @% %@2@%%@CR:C6A00370022 @%%@AB@%VPICD_Convert_Handle_To_IRQ%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the number of the IRQ for the IRQ handle in %@AB@%EAX%@AE@%. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = IRQ Handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = IRQ Number %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@%, Flags %@NL@% %@CR:C6A00370023 @% %@2@%%@CR:C6A00370024 @%%@AB@%VPICD_Convert_Int_To_IRQ%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service takes an interrupt vector number and returns the number of the IRQ that is mapped to that interrupt. For example, INT 8 will typically be converted to IRQ 0. However, VMs are allowed to remap the virtual PIC to any interrupt vector they wish. Therefore, devices should never make assumptions about to which interrupt vector a particular IRQ is mapped. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Interrupt vector number %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry is clear then EAX = IRQ number else Interrupt vector not mapped to any IRQ %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% None %@NL@% %@CR:C6A00370025 @% %@2@%%@CR:C6A00370026 @%%@AB@%VPICD_Convert_IRQ_To_Int%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service accepts an IRQ number and returns an interrupt vector number for a specified VM. For example, typically IRQ 0 will be converted to INT 8 on an IBM PC. However, VMs are allowed to remap the virtual PIC to any interrupt vector they wish. Therefore, devices should never make assumptions about to which interrupt vector a particular IRQ is mapped. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = IRQ number ─ NOT HANDLE! %@AB@%EBX%@AE@% = VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Interrupt vector %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, Flags %@NL@% %@CR:C6A00370027 @% %@2@%%@CR:C6A00370028 @%%@AB@%VPICD_Get_Complete_Status%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% Refer to %@AB@%VPICD_Get_Status%@AE@% for description. %@NL@% %@CR:C6A00370029 @% %@2@%%@CR:C6A00370030 @%%@AB@%VPICD_Get_IRQ_Complete_Status%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is similar to %@AB@%VPICD_Get_Complete_Status%@AE@% except that it takes an IRQ number as a parameter instead of an IRQ handle. This is useful for devices to inspect an IRQ before attempting to virtualize it or for inspecting the state of another device's interrupt. Also, since it indicates whether or not an IRQ has been virtualized already, it can be used by devices to prevent conflicts when more than one device may want to use an IRQ. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = IRQ number %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%ECX%@AE@% = Status as described for %@AB@%VPICD_Get_Complete_Status%@AE@% %@NL@% %@AS@% If the carry flag is set then %@AS@% The IRQ has been virtualized %@AS@% else %@AS@% The IRQ has not been virtualized%@AE@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%ECX%@AE@%, Flags %@NL@% %@CR:C6A00370031 @% %@2@%%@CR:C6A00370032 @%%@AB@%VPICD_Get_Status%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% These services return the status of a virtual IRQ for a specified VM. The status returned in %@AB@%ECX%@AE@% is defined by equates in the VPICD.INC file. %@AB@%VPICD_Get_Status%@AE@% will only return the Virtual %@AB@%In_Service%@AE@% and %@AB@%IRET_Pending%@AE@% status bits. %@AB@%VPICD_Get_Complete_Status%@AE@% will return with all status bits defined. The shorter version is supplied because it is much faster, and the status returned contains the most commonly used information. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = IRQ handle %@AB@%EBX%@AE@% = VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%ECX%@AE@% = Status flags (see equates VPICD.INI) %@NL@% %@TH: 10 518 02 16 60 @%Bit Description%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%0 = 1 A Virtual IRET is pending1 = 1 The IRQ is virtually in service2 = 1 The IRQ is physically masked3 = 1 The IRQ is physically in service4 = 1 VM has masked the IRQ5 = 1 The Virtual IRQ is set (by any VxD)6 = 1 The physical IRQ is set7 = 1 Tha calling VxD's Virtual IRQ is set%@TE: 10 518 02 16 60 @% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%ECX%@AE@%, Flags %@NL@% %@CR:C6A00370033 @% %@2@%%@CR:C6A00370034 @%%@AB@%VPICD_Get_Version%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the VPICD major and minor version numbers. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%AH%@AE@% = Major version %@AB@%AL%@AE@% = Minor version %@AB@%EBX%@AE@% = Flags Bit 0 = 1 - Master/Slave PC/AT type configuration 0 - PC/XT type single PIC configuration Other bits reserved for future versions. %@AB@%ECX%@AE@% = Maximum IRQ supported (07H or 0FH) Carry flag clear %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, %@AB@%EBX%@AE@%, %@AB@%ECX%@AE@%, Flags %@NL@% %@CR:C6A00370035 @% %@2@%%@CR:C6A00370036 @%%@AB@%VPICD_Phys_EOI%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Calling this procedure will end a physical interrupt and will allow further hardware interrupts from the specified IRQ. Notice that an interrupt that is physically in service will %@AI@%not%@AE@% suppress interrupts to "lower priority" IRQs, since VPICD does not prioritize hardware interrupts. Therefore, it is acceptable for an interrupt to be physically in service for an arbitrary length of time. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = IRQ handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00370037 @% %@2@%%@CR:C6A00370038 @%%@AB@%VPICD_Physically_Mask%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service will mask the specified IRQ on the hardware PIC. This will suppress all hardware interrupts on the IRQ until %@AB@%VPICD_Physically_Unmask%@AE@% or %@AB@%VPICD_Set_Auto_Masking%@AE@% is called. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = IRQ handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% IRQ is masked %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00370039 @% %@2@%%@CR:C6A00370040 @%%@AB@%VPICD_Physically_Unmask%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service will unmask the specified IRQ on the hardware PIC regardless of the mask state of virtual machines. This means that even if every VM has masked the virtual IRQ, the physical IRQ will remain unmasked. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = IRQ handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% IRQ is masked %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00370041 @% %@2@%%@CR:C6A00370042 @%%@AB@%VPICD_Set_Auto_Masking%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Automatic masking is the default state for every IRQ. It can be overridden by %@AB@%VPICD_Physically_Mask/Unmask%@AE@%. When automatic masking is used, the state of the physical mask is determined by the state of every virtual machine's virtual mask. If at least one VM has the IRQ unmasked, then the physical IRQ will remain unmasked. Otherwise, the IRQ will be masked on the hardware PIC. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = IRQ handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% IRQ will be physically unmasked if at least one VM has unmasked the IRQ. %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00370043 @% %@2@%%@CR:C6A00370044 @%%@AB@%VPICD_Set_Int_Request%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service sets the virtual interrupt request for the specified IRQ and VM. It may cause an interrupt to be simulated immediately. However, in many cases, the interrupt will %@AI@%not%@AE@% be simulated until a later point in time. The interrupt will not be simulated immediately if: %@NL@% ■ The virtual machine has interrupts disabled. %@NL@% ■ The virtual machine has masked the IRQ. %@NL@% ■ A higher priority virtual IRQ is in service. %@NL@% ■ It is not possible to run the specified VM (it is suspended, etc). %@NL@% ■ There are other reasons the interrupt may be postponed.%@NL@% However, since the interrupt may be simulated immediately, virtual devices that have a virtual interrupt handler must be able to handle the case when their virtual interrupt procedure is called before this service returns. %@NL@% Setting an interrupt request is not a guarantee that the interrupt will ever be simulated. For example, if the VM has masked the interrupt and never unmasks it, the interrupt will never be simulated. Also, a call to %@AB@%VPICD_Clear_Int_Request%@AE@% that is made before the virtual interrupt is simulated will prevent the interrupt simulation. %@NL@% It is important to keep in mind that VPICD simulates a level triggered PIC. This means that once a virtual EOI occurs, another interrupt will be simulated immediately unless the virtual interrupt request is cleared. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = IRQ handle %@AB@%EBX%@AE@% = VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Virtual IRQ request is set %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00370045 @% %@2@%%@CR:C6A00370046 @%%@AB@%VPICD_Test_Phys_Request%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service will return with Carry set if the physical (hardware PIC) interrupt request is set for the specified IRQ. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = IRQ handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Carry flag = Physical Interrupt Request state %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00370047 @% %@2@%%@CR:C6A00370048 @%%@AB@%VPICD_Virtualize_IRQ%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This is not an async service; it cannot be called during an interrupt. This service is used to gain access to a specified virtual interrupt request. The caller passes this procedure a pointer to the IRQ descriptor (the structure declared in VPICD.INC) which specifies: %@NL@% ■ IRQ number (required)%@NL@% ■ Options%@NL@% ■ Hardware interrupt handler (required)%@NL@% ■ Virtual interrupt handler%@NL@% ■ Virtual EOI handler%@NL@% ■ Virtual mask change handler%@NL@% ■ Virtual IRET handler%@NL@% ■ Virtual IRET time-out (0 for no time-out)%@NL@% For more information on the various options and parameters to this service see Section 37.3 "Virtualizing an IRQ," earlier in this chapter. When this service returns, if Carry is set, then the IRQ cannot be virtualized. Otherwise, %@AB@%EAX%@AE@% contains an IRQ handle. This handle is used for all subsequent communication with VPICD. %@NL@% If every device that virtualizes the IRQ has the %@AB@%Can_Share%@AE@% option set then the IRQ can be shared by up to 32 devices. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EDI%@AE@% -> %@AB@%VPICD_IRQ_Descriptor%@AE@% %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry clear then EAX = IRQ Handle else Error ─ Handle already allocated or invalid IRQ # %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% , Flags %@NL@% %@CR:C6A00380001 @%%@1@%%@AB@%Chapter 38 Virtual Sound Device (VSD) Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% These two services enable VxDs to generate a warning beep or return the VSD version number:%@CR:C6A00380002 @%%@NL@% ■ %@AB@%VSD_Bell%@AE@%%@NL@% ■ %@AB@%VSD_Get_Version%@AE@%%@NL@% See Chapter 16, "Overview of Windows in 386 Enhanced Mode," and Chapter 17, "Virtual Device Programming Topics," for general environment discussions. %@NL@% %@2@%%@CR:C6A00380003 @%%@AB@%VSD_Bell%@CR:C6A00380004 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is provided so that devices can generate a warning beep. This is normally used when the user presses an invalid key or when an error occurs. Notice that this service will produce a 1/2-second tone, but it will then return immediately (it does not busy wait). %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00380005 @% %@2@%%@CR:C6A00380006 @%%@AB@%VSD_Get_Version%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the version number of the Virtual Sound Device. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% AH = Major version number AL = Minor version number Carry flag clear %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, Flags %@NL@% %@CR:C6A00390001 @%%@1@%%@AB@%Chapter 39 Virtual Timer Device (VTD) Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% This chapter presents descriptions of the following VTD services:%@CR:C6A00390002 @%%@NL@% ■ %@AB@%VTD_Begin_Min_Int_Period%@AE@%%@NL@% ■ %@AB@%VTD_Disable_Trapping%@AE@%%@NL@% ■ %@AB@%VTD_Enable_Trapping%@AE@%%@NL@% ■ %@AB@%VTD_End_Min_Int_Period%@AE@%%@NL@% ■ %@AB@%VTD_Get_Interrupt_Rate%@AE@%%@NL@% ■ %@AB@%VTD_Get_Version%@AE@%%@NL@% ■ %@AB@%VTD_Update_System_Clock%@AE@%%@NL@% See Chapter 16, "Overview of Windows in 386 Enhanced Mode," and Chapter 17, "Virtual Device Programming Topics," for general environment discussions. %@NL@% %@CR:C6A00390003 @% %@2@%%@CR:C6A00390004 @%%@AB@%VTD_Begin_Min_Int_Period%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used by VxDs to ensure a minimum accuracy for system timing. When this service is called, if the interrupt period specified is lower than the current timer interrupt period, the interrupt period will be set to the new frequency. %@NL@% Until a matching %@AB@%VTD_End_Min_Int_Period%@AE@% call is made, the timer interrupt period is guaranteed never to be slower than the value specified. %@NL@% A VxD should call this service only once before calling %@AB@%VTD_End_Min_Int_Period%@AE@%. %@NL@% Typically the %@AB@%Begin/End_Min_Int_Period%@AE@% services are used by devices such as execution profilers that need extremely accurate timing. VMM system time-out services rely on the VTD to keep time. Therefore, more frequent timer interrupts will allow the time out services to be more accurate. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AU@%WARNING%@AE@% Fast timer interrupt periods can be very, very expensive in terms of total system performance. For example, on some machines a timer interrupt of 1 millisecond will degrade total machine throughput by 10 percent and disk I/O by up to 50 percent. ────────────────────────────────────────────────────────────────────────────%@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX %@AE@%= Desired interrupt period %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry clear then Interrupt period set else Specified interrupt period is not valid %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00390005 @% %@2@%%@CR:C6A00390006 @%%@AB@%VTD_Disable_Trapping%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service will force VTD to stop I/O trapping on the timer ports for a specified virtual machine. %@AB@%VTD_Enable_Trapping%@AE@% must be called once for every call made to this service. By default, timer port trapping is enabled when a VM is created. %@NL@% It is sometimes necessary to disable temporarily I/O trapping for virtual machine code that reads the timer in extremely tight timing loops. A good example is the hard disk BIOS code that reads the ports hundreds of times per disk transfer. The overhead for servicing the I/O traps would cause disk performance to slow to a crawl. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AU@%WARNING%@AE@% This service must be used very carefully. If a VM reprograms the timer while port trapping is disabled, system timing will behave randomly. Only "trusted" code should be executed when timer port trapping is disabled. ────────────────────────────────────────────────────────────────────────────%@NL@% If this service is called N times, then %@AB@%VTD_Enable_Trapping%@AE@% must also be called N times before trapping is reenabled. This allows nested calls to this service by more than one VxD. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX %@AE@%= VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00390007 @% %@2@%%@CR:C6A00390008 @%%@AB@%VTD_Enable_Trapping%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service must be called to re-enable timer I/O port trapping after calling %@AB@%VTD_Disable_Trapping%@AE@%. Notice that this call must be made once for every call to %@AB@%VTD_Disable_Trapping%@AE@%. Only when every disable call has been matched by a call to this service will port trapping be reenabled. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00390009 @% %@2@%%@CR:C6A00390010 @%%@AB@%VTD_End_Min_Int_Period%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service allows a device to "unrequest" a timer interrupt period that it set earlier through the %@AB@%VTD_Begin_Min_Int_Period%@AE@% service. See the documentation for %@AB@%VTD_Begin_Min_Int_Period%@AE@% earlier in this chapter for more information on the proper use of this service. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Value passed earlier to %@AB@%Begin_Begin_Min_Int_Period%@AE@% %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AS@% If carry clear then %@AS@% Interrupt period request removed successfully %@AS@% else %@AS@% Specified interrupt period is not valid%@AE@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00390011 @% %@2@%%@CR:C6A00390012 @%%@AB@%VTD_Get_Interrupt_Period%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the current timer interrupt period. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EAX %@AE@%= Length of time between ticks in milliseconds %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00390013 @% %@2@%%@CR:C6A00390014 @%%@AB@%VTD_Get_Version%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the version number and the range of interrupt periods allowable by this device. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Version number (AH = Major, AL = Minor) %@AB@%EBX%@AE@% = Fastest possible interrupt period in milliseconds %@AB@%ECX%@AE@% = Slowest possible interrupt period in milliseconds Carry flag clear %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, %@AB@%EBX%@AE@%, %@AB@%ECX%@AE@%, Flags %@NL@% %@CR:C6A00390015 @% %@2@%%@CR:C6A00390016 @%%@AB@%VTD_Update_System_Clock%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service should %@AI@%only%@AE@% be called by the VMM. Devices should call the %@AB@%Get_System_Time%@AE@% VMM service. The VMM will then call this service to update the system clock. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00400001 @%%@1@%%@AB@%Chapter 40 V86 Mode Memory Manager Device Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% The V86MMGR is responsible for managing memory in the Virtual 8086 portion of each VM. It supports EMS and XMS, is responsible for allocating the base memory for VMs when they are created, and translates APIs from protected-mode applications into V86 calls for other VxDs.%@CR:C6A00400002 @%%@NL@% See Chapter 16, "Overview of Windows in 386 Enhanced Mode," and Chapter 17, "Virtual Device Programming Topics," for general environment discussions. Other chapters that discuss memory management are Chapter 19, "Memory Management Services," and Chapter 6, "Network Support," in the %@AI@%Microsoft %@AI@%Windows Device Driver Adaptation Guide%@AE@%. Memory management is also discussed in the %@AI@%Microsoft Windows Software Development Kit, Programming Tools%@AE@%. %@NL@% The V86MMGR services are presented as follows: %@NL@% ■ Initialization Services%@NL@% %@STUB@% %@AB@%V886MMGR_Get_Version%@AE@%%@NL@% %@STUB@% %@AB@%V86MMGR_Allocate_V86_Pages%@AE@%%@NL@% %@STUB@% %@AB@%V86MMGR_Set_EMS_XMS_Limits%@AE@%%@NL@% %@STUB@% %@AB@%V86MMGR_Get_EMS_XMS_Limits%@AE@%%@NL@% ■ API Translation and Mapping Services%@NL@% %@STUB@% %@AB@%V886MMGR_Set_Mapping_Info%@AE@%%@NL@% %@STUB@% %@AB@%V86MMGR_Xlat_API%@AE@%%@NL@% %@STUB@% %@AB@%V86MMGR_Load_Client_Ptr%@AE@%%@NL@% %@STUB@% %@AB@%V86MMGR_Allocate_Buffer%@AE@%%@NL@% %@STUB@% %@AB@%V886MMGR_Free_Buffer%@AE@%%@NL@% %@STUB@% %@AB@%V86MMGR_Get_Xlat_Buff_State%@AE@%%@NL@% %@STUB@% %@AB@%V86MMGR_Set_Xlat_Buff_State%@AE@%%@NL@% %@STUB@% %@AB@%V86MMGR_Get_VM_Flat_Sel%@AE@%%@NL@% %@STUB@% %@AB@%V86MMGR_Get_Mapping_Info%@AE@%%@NL@% %@STUB@% %@AB@%V86MMGR_Map_Pages%@AE@%%@NL@% %@STUB@% %@AB@%V86MMGR_Free_Page_Map_Region%@AE@%%@NL@% %@2@%%@CR:C6A00400003 @%%@AB@%40.1 Initialization Services%@AE@%%@EH@%%@NL@% These services are used when a VM is created except for the %@AB@%V86MMGR_Get_Version%@AE@%, which may be used anytime.%@CR:C6A00400004 @%%@NL@% %@CR:C6A00400005 @% %@2@%%@CR:C6A00400006 @%%@AB@%V86MMGR_Get_Version%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Returns the version of the V86MMGR VxD. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%AH %@AE@%= Major version number %@AB@%AL%@AE@% = Minor version number Carry flag clear %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, Flags %@NL@% %@CR:C6A00400007 @% %@2@%%@CR:C6A00400008 @%%@AB@%V86MMGR_Allocate_V86_Pages%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used by the SHELL VxD to set up the initial base memory of a VM when it is created. It allocates the memory, maps it into the virtual machine, and does a local %@AB@%Assign_Device_V86_Pages%@AE@% for the region allocated. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle %@AB@%ESI%@AE@% = Desired size of VM address space in K bytes %@AB@%EDI %@AE@% = Minimum size of VM address space in K bytes %@AB@%ECX%@AE@% = Flags, see bit definitions in V86MMGR.INC %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%The %@AB@%ESI%@AE@%%@AI@% and %@AE@%%@AI@%%@AB@%EDI%@AE@%%@AE@%%@AI@% sizes include the %@AE@%%@AI@%%@AB@%0-First_VM_Page%@AE@%%@AE@%%@AI@% region of V86 address %@AI@%space.%@AE@%%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry set then ERROR: Could not allocate memory else Memory allocated and mapped into VM %@AB@%EAX%@AE@% = ACTUAL number of pages allocated and mapped (size of VM). Notice that this size %@AI@%does not%@AE@% include the space from 0-%@AB@%First_VM_Page%@AE@% %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%,Flags %@NL@% %@CR:C6A00400009 @% %@2@%%@CR:C6A00400010 @%%@AB@%V86MMGR_Set_EMS_XMS_Limits%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used by the SHELL VxD to set the EMS and XMS limit parameters for a VM. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle to set limits of %@AB@% EAX%@AE@% = Min EMS kilobytes %@AB@% EDX%@AE@% = Max EMS kilobytes %@AB@% ESI%@AE@% = Min XMS kilobytes %@AB@% EDI %@AE@% = Max XMS kilobytes %@AB@% ECX%@AE@% = Flag bits, see V86MMGR.INC %@NL@% %@3@%%@AB@%Notes%@AE@%%@EH@%%@NL@% To disable access to XMS or EMS memory, set Max = Min = 0 To set only %@AI@%one%@AE@% of the two limits, set the OTHER Max = Min = -1 The XMS Limit %@AI@%does not%@AE@% include the HMA. %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry set then could not set limits Insufficient memory for Min allocation request note that some of the limits may have been set. To Find out what happened, use %@AB@%V86MMGR_Get_EMS_XMS_Limits%@AE@% else limits set %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00400011 @% %@2@%%@CR:C6A00400012 @%%@AB@%V86MMGR_Get_EMS_XMS_Limits%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used by the SHELL VxD to get the EMS and XMS limit parameters for a VM. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle to get limits of %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Min EMS kilobytes (always a multiple of 4) %@AB@%EDX%@AE@% = Max EMS kilobytes (always a multiple of 4) %@AB@%ESI%@AE@% = Min XMS kilobytes (always a multiple of 4) %@AB@%EDI%@AE@% = Max XMS kilobytes (always a multiple of 4) %@AB@%ECX%@AE@% = 0 if access to the HMA is disabled %@AB@%ECX%@AE@% = 1 if access to the HMA is enabled %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, %@AB@%ECX%@AE@%, %@AB@%EDX%@AE@%, %@AB@%ESI%@AE@%, %@AB@%EDI%@AE@%, Flags %@NL@% %@2@%%@CR:C6A00400013 @%%@AB@%40.2 API Translation and Mapping%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% One of the major roles of the V86MMGR is to provide a mechanism for other VxDs to translate API calls made from application software running in protected mode into the V86 portion of the virtual machine. The term "API translation" is used in this document to describe the conversion of an API call in protected mode into a corresponding V86 mode call. Because enhanced Windows runs under a standard MS-DOS, MS-DOS and BIOS calls must be reflected to V86 mode code to handle the call. There is a layer of code in the DOSMGR device that converts protected mode MS-DOS calls into V86 calls.%@CR:C6A00400014 @%%@CR:C6A00400015 @%%@NL@% The main translation service, %@AB@%V86MMGR_Xlat_API%@AE@%, is a simple interpreter that copies data into a buffer in the V86 address space and converts pointers to point to the copied data. Note that the data is %@AI@%copied%@AE@%. The memory is not mapped into V86 memory by changing page tables. %@NL@% Other services are provided to allocate buffer space, map memory into global V86 address space, and perform other functions necessary for API translation. %@NL@% Translations services work only for the current VM, and most are only available from the protected-mode portion of a VM. %@NL@% Only one VxD should translate a given API call. %@NL@% DPMI provides a way for an application to do translation without installing a VxD to do the transition. %@NL@% %@3@%%@AB@%40.2.1 Basic API Translation%@AE@%%@EH@%%@NL@% Many APIs require little or no translation. Others are extremely complex and require a great deal of coding. The simplest API is one that has no pointers. A software interrupt based API, in which all parameters are passed in the %@AB@%EAX%@AE@%, %@AB@%EBX%@AE@%, %@AB@%ECX%@AE@%, %@AB@%EDX%@AE@%, %@AB@%ESI%@AE@%, %@AB@%EDI%@AE@%, and %@AB@%EBP %@AE@%registers and flags, requires no special translation software. By default, enhanced Windows will reflect an interrupt that is executed in protected mode into V86 mode. For example, the BIOS printer interface (Int 17h) requires no translation code since all APIs are register-based with no pointers. %@NL@% However, most APIs have at least some calls that take pointers as parameters. For example, to open a file through MS-DOS, you must point at the name of the file to open with the %@AB@%DS:DX%@AE@% registers. Since the address that a protected mode program will pass in %@AB@%DS:DX%@AE@% is not usually addressable in the V86 portion of the VM, there must be code that copies the filename into a buffer that is addressable in V86 mode so that MS-DOS can access the filename. %@NL@% %@3@%%@AB@%40.2.2 Complex API Translation%@AE@%%@EH@%%@NL@% Some APIs are too complex or their buffers are too large to be handled by the %@AB@%V86MMGR_Xlat_API%@AE@% service. The MS-DOS Exec function takes a pointer to a data structure that contains more pointers. This API requires special code to translate the pointers in the data structure and to copy the data that those pointers point to into V86 mode memory. %@NL@% The MS-DOS read and write file functions can have buffers as large as 64K. The typical V86MMGR translation copy buffer is 4K. Therefore, these calls require code to divide the call into several smaller reads or writes in V86 mode. %@NL@% %@3@%%@AB@%40.2.3 Hooking the Interrupt%@AE@%%@EH@%%@NL@% Since the translation code should be the last protected mode handler you will need to hook the PM interrupt vector (using the %@AB@%Hook_PM_Int_Vector%@AE@% service) during the %@AB@%Sys_Critical_Init%@AE@% or %@AB@%Device_Init%@AE@% phases of initialization. All translation code should be initialized before the Init_Complete phase of initialization so that the %@AB@%Exec_VxD_Int%@AE@% service (provided by the VMM) can be used during this phase. Note that the V86MMGR translation services (except for %@AB@%Set_Mapping_Info%@AE@%) should not be called during %@AB@%Sys_Critical_Init%@AE@% or %@AB@%Device_Init%@AE@%. %@NL@% By hooking the interrupt vector instead of using the %@AB@%Hook_PM_Int_Chain%@AE@% service you will allow protected mode applications to hook software interrupts "in front" of your translation code. This is very important for the Windows kernel since it needs to monitor the activity of Windows applications' API calls. %@NL@% %@4@%%@AB@%Sample Code%@AE@%%@EH@%%@NL@% The code for a typical translation VxD looks like this: %@NL@% %@AS@% VxD_ICODE_SEG %@AS@% BeginProc My_Xlat_Init %@AS@% mov eax, My_Translation_Int_Number %@AS@% VMMcall Get_PM_Int_Vector %@AS@% mov [Chain_Segment], cx %@AS@% mov [Chain_Offset], edx %@AS@% mov esi, OFFSET32 My_Xlat_Procedure %@AS@% VMMcall Allocate_PM_Call_Back %@AS@% mov ecx, eax %@AS@% movzx edx, cx %@AS@% shr ecx, 16 %@AS@% mov eax, My_Translation_Int_Number %@AS@% VMMcall Set_PM_Int_Vector %@AS@% clc %@AS@% ret %@AS@% EndProc My_Xlat_Init %@AS@% VxD_ICODE_ENDS %@AS@% %@AS@% VxD_CODE_SEG %@AS@% BeginProc My_Xlat_Procedure %@AS@% movzx eax, [ebp.Client_AH] %@AS@% cmp eax, My_Max_API_Number %@AS@% ja Chain_To_Next_Handler %@AS@% VMMcall Simulate_Iret %@AS@% mov edx, My_Trans_Script_Table[eax*4] %@AS@% VxDcall V86MMGR_Xlat_API %@AS@% ret %@AS@% Chain_To_Next_Handler: %@AS@% movzx ecx, [Chain_Segment] %@AS@% jecxz Reflect_To_V86_Now %@AS@% mov edx, [Chain_Offset] %@AS@% VMMcall Simulate_Far_Jmp %@AS@% ret %@AS@% Reflect_To_V86_Now: %@AS@% VMMcall Begin_Nest_V86_Exec %@AS@% mov eax, My_Translation_Int_Number %@AS@% VMMcall Exec_Int %@AS@% VMMcall End_Nest_Exec %@AS@% ret %@AS@% EndProc My_Xlat_Procedure %@AS@% VxD_CODE_ENDS%@AE@% If the value in AH is not translated by this handler then it will be reflected to the next protected mode interrupt handler. If there is not another PM interrupt handler (code segment is zero) then the interrupt is immediately reflected to V86 mode. %@NL@% You will note that My_Xlat_Procedure calls the %@AB@%Simulate_Iret%@AE@% service before it calls %@AB@%V86MMGR_Xlat_API%@AE@%. If you plan to "eat" an interrupt it is usually best to call this service first. If the iret was simulated after the call to %@AB@%V86MMGR_Xlat_API%@AE@% then any flags returned by the V86 interrupt handler would be destroyed (an iret pops flags from the interrupt stack frame). %@NL@% %@3@%%@AB@%40.2.4 Mapping vs. Copying%@AE@%%@EH@%%@NL@% Some VxDs need to use the paging mechanism of the 386 to map pages from extended address space into the 1MB V86 address space of every virtual machine. The Virtual NetBIOS Device uses the mapping services when an asynchronous receive is issued so that the proper physical memory will be updated regardless of which VM is currently running. When memory is mapped using %@AB@%V86MMGR_Map_Pages%@AE@% it will be mapped to the same linear address in every virtual machine. Thus it is best to avoid using these services. %@NL@% Do not use mapping as an alternative to copying just because you think mapping seems easier. It is faster to copy memory than to map it since the memory manager does not need to perform any page table mapping and locking. Mapping also uses a lot of address space (although it requires no memory). The mapping services should only be used for APIs that require memory mapped to the same address in every VM. %@NL@% Note that the mapping services allow memory from one VM's V86 address space to be mapped into all VMs at a common address. %@AI@%Don't use this for %@AI@%interprocess communication.%@AE@% It will eat mapping space that may be required by other devices. If you want to design an IPC interface, either make it work for PM applications (which can share memory) or copy the data. %@NL@% %@3@%%@AB@%40.2.5 Writing Your Own Translation Procedures%@AE@%%@EH@%%@NL@% Often, it is impossible to translate part or all of an API using the supplied macro interpreter. Therefore you may need to write procedures that do all or part of the translation. Examples of calls that require extra code are the MS-DOS read and write commands and the get and set interrupt vector commands. The MS-DOS commands to get and set interrupt vectors behave differently in protected mode since they must hook the protected mode interrupt vectors. These calls are never reflected to the "real" MS-DOS running in V86 mode. %@NL@% The MS-DOS read and write file commands can use a buffer as large as 64K. Since the translation buffers can be as small as 4K, reads and writes must be divided before being reflected to MS-DOS. %@NL@% Since most APIs have some interfaces that can be handled by the %@AB@%V86MMGR_Xlat_API%@AE@% script language and others that must be translated by custom procedures you will probably want to dispatch to the custom procedures using the %@AB@%Xlat_API_Jmp_To_Proc%@AE@% macro. %@NL@% To adjust V86 segment registers you should leave the VM in %@AB@%PM_Exec_Mode%@AE@% and change the %@AB@%Alt_Client%@AE@% registers. When in %@AB@%PM_Exec_Mode%@AE@% these registers contain the V86 segment registers and stack pointer. They will contain the PM segment registers and stack pointer when the VM is in %@AB@%V86_Exec_Mode%@AE@%. %@NL@% %@3@%%@AB@%40.2.6 Sample API Translation%@AE@%%@EH@%%@NL@% This sample API is for an imaginary, incredibly simple network. The functions allow you to connect to a server and send or receive data. Assume that the network supports the following API from software interrupt 92h: %@NL@% %@4@%%@AB@%%@AB@%Function 0: Get version%@AE@%%@AE@%%@EH@%%@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%AH%@AE@% = 0 %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%AH%@AE@% = Major version %@AB@%AL%@AE@% = Minor version %@NL@% %@4@%%@AB@%%@AB@%Function 1: Get Server Name%@AE@%%@AE@%%@EH@%%@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%AH %@AE@%= 1 %@AB@%DS:DX%@AE@% = Pointer to a 16 byte buffer to hold name %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@4@%%@AB@%%@AB@%Function 2: Connect To New Server%@AE@%%@AE@%%@EH@%%@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%AH%@AE@% = 2 %@AB@%DS:DX%@AE@% = Pointer to null terminated string that is name of server %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@4@%%@AB@%%@AB@%Function 3: Read/Write Data%@AE@%%@AE@%%@EH@%%@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%AH %@AE@%= 3 %@AB@%ES:BX%@AE@% = Pointer to command block with following structure: %@NL@% %@TH: 5 229 02 08 06 62 @%Offset Size Description%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%0 1 Command1 2 Buffer size3 4 Buffer pointer%@TE: 5 229 02 08 06 62 @% Command field values: 0 = Read data from server 1 = Write data to server %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% Since function 0 is register based it requires no translation other than reflecting the interrupt to V86 mode. Functions 1 and 2 both can be translated by scripts using the %@AB@%V86MMGR_Xlat_API%@AE@% service. Function 3 requires a custom translation procedure. %@NL@% %@AS@% VxD_DATA_SEG %@AS@% Fctn_0_Script: %@AS@% Xlat_API_Exec_Int 92h %@AS@% Fctn_1_Script: Xlat_API_Fixed_Len ds, dx, 16 %@AS@% Xlat_API_Exec_Int 92h %@AS@% Fctn_2_Script: Xlat_API_ASCIIZ ds, dx %@AS@% Xlat_API_Exec_Int 92h %@AS@% Fctn_3_Script: %@AS@% Xlat_API_Jmp_To_Proc Trans_Fctn_3 %@AS@% Copy_Command_Block_Script: %@AS@% Xlat_API_Fixed_Len es, bx, 7 %@AS@% Xlat_API_Exec_Int 92h%@AE@% %@AS@% Xlat_Ptr_Table: %@AS@% dd OFFSET32 Fctn_0_Script %@AS@% dd OFFSET32 Fctn_1_Script dd OFFSET32 Fctn_2_Script %@AS@% dd OFFSET32 Fctn_3_Script %@AS@% VxD_DATA_ENDS%@AE@% %@AS@% VxD_CODE_SEG %@AS@% BeginProc Translate_Sample_API %@AS@% movzx edx, [ebp.Client_AH] %@AS@% cmp edx, 3 %@AS@% ja Chain_To_Next_Handler %@AS@% VMMcall Simulate_Iret %@AS@% mov edx, Xlat_Ptr_Table[edx*4] %@AS@% VxDcall V86MMGR_Xlat_API %@AS@% jc Translation_Error ret %@AS@% Chain_To_Next_Handler: %@AS@% movzx ecx, [Chain_Segment] %@AS@% jecxz Reflect_To_V86_Now %@AS@% mov edx, [Chain_Offset] %@AS@% VMMcall Simulate_Far_Jmp %@AS@% ret %@AS@% Reflect_To_V86_Now: %@AS@% VMMcall Begin_Nest_V86_Exec %@AS@% mov eax, 92h %@AS@% VMMcall Exec_Int VMMcall %@AS@% End_Nest_Exec %@AS@% ret %@AS@% Translation_Error: %@AS@% Debug_Out "Unable to translate sample API" %@AS@% VMMjmp Crash_Cur_VM %@AS@% EndProc Translate_Sample_API%@AE@% %@AS@% BeginProc Trans_Fctn_3 %@AS@% push fs %@AS@% push gs %@AS@% pushad %@AS@% ; Get pointer to command block %@AS@% mov ax, (Client_ES*100h)+Client_BX %@AS@% VxDcall V86MMGR_Load_Client_Ptr %@AS@% ; If command is invalid then fail the call %@AS@% mov al, BYTE PTR fs:[esi] %@AS@% cmp al, 1 %@AS@% ja Can_Not_Translate %@AS@% ; Get buffer size and pointer from command block %@AS@% mov dx, fs %@AS@% mov gs, dx %@AS@% mov edx, esi movzx ecx, WORD PTR gs:[edx+1] %@AS@% mov fs, WORD PTR gs:[edx+5] %@AS@% movzx esi, WORD PTR gs:[edx+3] %@AS@% ; Allocate a buffer, copying data if command is a write %@AS@% bt eax, 0 %@AS@% VxDcall V86MMGR_Allocate_Buffer %@AS@% jc Can_Not_Translate %@AS@% mov DWORD PTR gs:[edx+3], edi %@AS@% ; Copy the command block and execute the interrupt %@AS@% push edx %@AS@% mov edx, OFFSET32 Copy_Command_Block_Script %@AS@% VxDcall V86MMGR_Xlat_API %@AS@% pop edx %@AS@% jc Can_Not_Translate %@AS@% ; Free the buffer, copying data if command is a read %@AS@% mov al, BYTE PTR gs:[edx] %@AS@% bt eax, 0 %@AS@% cmc %@AS@% VxDcall V86MMGR_Free_Buffer %@AS@% ; Restore original pointer in command block %@AS@% mov WORD PTR gs:[edx+5], fs %@AS@% mov WORD PTR gs:[edx+3], si %@AS@% clc %@AS@% Trans_F3_Exit: %@AS@% popad %@AS@% pop gs %@AS@% pop fs %@AS@% ret %@AS@% Can_Not_Translate: stc %@AS@% jmp Trans_F3_Exit %@AS@% EndProc Trans_Fctn_3 %@AS@% %@AS@% VxD_CODE_ENDS%@AE@% %@CR:C6A00400016 @% %@2@%%@CR:C6A00400017 @%%@AB@%V86MMGR_Set_Mapping_Info%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service must be called during the %@AB@%Sys_Critical_Init %@AE@%or %@AB@%Device_Init %@AB@%%@AE@%phase of device initialization. It is used to define the minimum amount of translation buffer and global V86 map address space that will be required. VxDs such as the VNETBIOS use this service to ensure that there will be adequate global page mapping space to map network buffers. By default the translation copy buffer size is 4K and there are no global mapping pages. %@NL@% Multiple VxDs may call this service. The V86MMGR will use the largest value for each of the parameters when allocating buffer space. In other words, if 10 VxDs request a two-page copy buffer then the copy buffer will be two pages (not 20). %@NL@% Note that while a large copy buffer can speed up operations such as MS-DOS reads, it requires extra memory to be allocated for every VM. Therefore, you should try to get by with a copy buffer size of one page if possible. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%AL%@AE@% = Minimum number of pages required for default copy buffer %@AB@%AH%@AE@% = Maximum number of pages desired for default copy buffer %@AB@%BL%@AE@% = Minimum number of pages required for global page mapping region %@AB@%BH%@AE@% = Maximum number of pages desired for global page mapping region %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00400018 @% %@2@%%@CR:C6A00400019 @%%@AB@%V86MMGR_Xlat_API%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is actually a simple interpreter that executes scripts that are created using macros defined in V86MMGR.INC. The macros are described in detail below. %@NL@% You can combine any of the macros, although you should keep in mind that %@AB@%Xlat_API_Exec_Int%@AE@% and %@AB@%Xlat_API_Jmp_To_Proc%@AE@% both terminate interpretation of the current script. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AU@%WARNING%@AE@% You should always specify the exact length of a buffer or else strange things may occur. For example, it is incorrect to translate an API that has a maximum buffer size of 128 bytes by using the Xlat_API_Fixed_Len macro if the buffer can be smaller than 128 bytes. This can cause bugs if the program has data that is updated at interrupt time that is located past the end of the buffer. ────────────────────────────────────────────────────────────────────────────%@NL@% For example, assume a program has the following data: %@NL@% %@AS@% Buffer_Length db 64 %@AS@% Buffer_Data db 64 dup (?) %@AS@% Time_Of_Day dd 0 %@AS@% Other_Stuff db 500 dup (?)%@AE@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = Current VM handle %@AB@%EBP%@AE@% -> Client register structure %@AB@%EDX%@AE@% -> Script to translate %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EDX%@AE@% is destroyed If carry set then Error while executing script else Script has been executed successfully %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EDX%@AE@%, Flags %@NL@% %@3@%%@AB@%Macro5%@AE@%%@EH@%%@NL@% The following define the translation scripts. %@NL@% %@4@%%@AB@%Xlat_API_Exec_Int [Int Number]%@AE@%%@EH@%%@NL@% Terminates the interpretation of the translation script and reflects the specified interrupt into Virtual 8086 mode. When the interrupt returns then it will return to the caller. %@NL@% %@AS@% DOS_No_Xlat_API: %@AS@% Xlat_API_Exec_Int 21h%@AE@% %@4@%%@AB@%Xlat_API_Fixed_Len [Segment], [Offset], [Length Constant]%@AE@%%@EH@%%@NL@% Copies a fixed length buffer from extended memory into the translation buffer and fixes up the V86 Seg:Offset. %@NL@% This service will fail if there is not enough room in the translation buffer to copy the data. %@NL@% For example, the MS-DOS Get Current Directory function (%@AB@%AH%@AE@%=47h), must be called with %@AB@%DS:SI%@AE@% pointing to a 64-byte buffer. The following script would perform the appropriate translation: %@NL@% %@AS@% DOS_Get_Current_Directory_API: %@AS@% Xlat_API_Fixed_Len ds, si, 64 %@AS@% Xlat_API_Exec_Int 21h%@AE@% %@4@%%@AB@%Xlat_API_Var_Len [Segment], [Offset], [Length Register]%@AE@%%@EH@%%@NL@% Copies a variable number of bytes from extended memory into the translation buffer. This is used for APIs where the caller places the buffer size in a register. %@NL@% This service will fail if there is not enough room in the translation buffer to copy the data. %@NL@% For example, the Int 10h write string function (AH=0Eh), must be called with %@AB@%ES:BP%@AE@% pointing to the string to print and %@AB@%CX%@AE@% equal to the number of bytes to display. The following script would translate this call: %@NL@% %@AS@% Int_10h_Write_String: %@AS@% Xlat_API_Var_Len es, bp, cx %@AS@% Xlat_API_Exec_Int 10h%@AE@% %@4@%%@AB@%Xlat_API_Calc_Len [Segment], [Ptr_Off], [Calc_Proc_Addr]%@AE@%%@EH@%%@NL@% Used to copy buffers that change in size. You must specify the selector:offset register pair that points to the buffer and the name of a procedure that will calculate the actual buffer size. The procedure will be called with %@AB@%FS:ESI%@AE@% pointing to the buffer and must return with %@AB@%ECX%@AE@% equal to the number of bytes to copy. The procedure must preserve all registers except %@AB@%ECX%@AE@%. %@NL@% This service will fail if there is not enough room in the translation buffer to copy the data. %@NL@% For example, the MS-DOS buffered keyboard input command (AH=0Ah) can have a buffer size from 3 to 257 bytes long. The first byte of the buffer specifies the length of the input buffer as follows: %@NL@% %@TH: 12 643 02 34 44 @%Byte Contents%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%0 Maximum number of characters to read (1-255); this value must be set by the process before Function 0Ah is called.1 Count of characters read.2-(n+2) Actual string of characters read, including the carriage return; n = number of bytes read.%@TE: 12 643 02 34 44 @% The translation code for this API would look something like this: %@NL@% %@AS@% VxD_DATA_SEG %@AS@% Buff_Keyboard_Input_API: %@AS@% Xlat_API_Calc_Len ds, dx, Calc_Input_Buff_Size %@AS@% Xlat_API_Exec_Int 21h %@AS@% VxD_DATA_ENDS %@AS@% %@AS@% VxD_CODE_SEG %@AS@% BeginProc Int_21_PM_To_V86_Translator %@AS@% %@AS@% cmp [ebp.Client_AH], 0Ah %@AS@% jne Not_Buffered_Keyboard_Input %@AS@% VMMcall Simulate_Iret %@AS@% mov edx, OFFSET32 Buff_Keyboard_Input_API %@AS@% VxDcall V86MMGR_Xlat_API %@AS@% ret %@AS@% %@AS@% EndProc Int_21_PM_To_V86_Translator %@AS@% %@AS@% BeginProc Calc_Input_Buff_Size %@AS@% %@AS@% movzx ecx, BYTE PTR fs:[esi] %@AS@% add ecx, 2 %@AS@% ret %@AS@% %@AS@% EndProc Calc_Input_Buff_Size %@AS@% VxD_CODE_ENDS%@AE@% %@4@%%@AB@%Xlat_API_ASCIIZ [Ptr_Seg], [Ptr_Off]%@AE@%%@EH@%%@NL@% Copies a null-terminated string into V86 memory and adjusts the V86 pointer appropriately. Note that the string will not be copied back after the call is complete. %@NL@% This service will fail if there is not enough room in the translation buffer to copy the string. %@NL@% For example, the MS-DOS Open File With Handle function (AH=3Dh), must be called with %@AB@%DS:DX%@AE@% pointing to the name of the file to open. The following script could be used translate the API: %@NL@% %@AS@% DOS_Open_File_With_Handle: %@AS@% Xlat_API_ASCIIZ ds, dx %@AS@% Xlat_API_Exec_Int 21h%@AE@% The interpreter can copy multiple buffers. For example, the following translation table translates the MS-DOS rename file call (AH = 56h): %@NL@% %@AS@% Rename_API: %@AS@% Xlat_API_ASCIIZ ds, dx %@AS@% Xlat_API_ASCIIZ es, di %@AS@% Xlat_API_Exec_Int 21h%@AE@% The first instruction copies the null-terminated string (ASCIIZ string) that %@AB@%DS:DX%@AE@% points to into the translation buffer in V86 memory, sets the V86 DS to the translation buffer segment, and changes %@AB@%DX%@AE@% to the offset in the buffer. %@NL@% The second macro copies the ASCIIZ string that is pointed to by %@AB@%ES:(E)DI%@AE@% into V86 memory and adjusts the pointer accordingly. %@NL@% The final macro terminates the interpretation of the script and reflects an Int 21h into the V86 portion of the VM. When the Int 21h returns, both buffers will be freed. %@NL@% %@4@%%@AB@%Xlat_API_Jmp_To_Proc [Proc_Name]%@AE@%%@EH@%%@NL@% Terminates the interpretation of the translation script and transfers control to a user defined procedure. The procedure can completely handle the API translation or can call %@AB@%V86MMGR_Xlat_API%@AE@% again. This can be useful for APIs that have several sub-APIs such as the DOS IOCTL calls. %@NL@% The procedure will be called with %@AB@%EBX%@AE@% equal to Current VM Handle, %@AB@%EBP%@AE@% pointing to Client register structure, and %@AB@%EDX%@AE@% points to the next entry in the translation script (if there is one). It must preserve every register except for %@AB@%EDX%@AE@%. Therefore the procedure must preserve %@AB@%EAX%@AE@%, %@AB@%EBX%@AE@%, %@AB@%ECX%@AE@%, %@AB@%ESI%@AE@%, %@AB@%EDI%@AE@%, %@AB@%EBP%@AE@%, %@AB@%DS%@AE@%, %@AB@%ES%@AE@%, %@AB@%FS%@AE@%, and %@AB@%GS%@AE@%. %@NL@% Your procedure should return with the carry flag clear if the translation was successful. Otherwise, it should return with carry set to indicate an error. %@NL@% %@4@%%@AB@%Xlat_API_Return_Ptr [Ptr_Seg], [Ptr_Off]%@AE@%%@EH@%%@NL@% Used for calls that return a pointer to a structure. For 16-bit protected mode programs, if an appropriate selector does not exist to map the call, then this service automatically creates one. For 32-bit protected mode programs the selector returned will always be the %@AB@%V86MMGR_VM_Flat_Selector%@AE@% and the offset will be adjusted. Note that although this macro is placed before the %@AB@%Exec_Int%@AE@% macro in a translation script, the pointer is created after the interrupt has been executed. %@NL@% This service will fail if it can not create an appropriate LDT selector. %@NL@% For example, this service is used to translate Int 15h with AH=C0h, which returns a pointer in %@AB@%ES:BX%@AE@% that points to a hardware information structure on PS/2 machines. The following script would return the appropriate pointer: %@NL@% %@AS@% Get_Machine_Info: %@AS@% Xlat_API_Return_Ptr es, bx %@AS@% Xlat_API_Exec_Int 15h%@AE@% %@4@%%@AB@%Xlat_API_Return_Seg [Ptr_Seg]%@AE@%%@EH@%%@NL@% Used for calls that return a segment. If an appropriate selector does not exist to map the call then this service automatically creates one. Note that although this macro is placed before the %@AB@%Exec_Int%@AE@% macro in a translation script, the selector is created after the interrupt has been executed. %@NL@% This service will fail if it can not create an appropriate LDT selector. %@NL@% For example, this service is used to translate Int 15h with %@AB@%AH%@AE@%=C1h, which returns the segment of the EBIOS data area in %@AB@%ES%@AE@%. The following script would return a selector that points to the EBIOS data area: %@NL@% %@AS@% Get_EBIOS_Selector: %@AS@% Xlat_API_Return_Seg es %@AS@% Xlat_API_Exec_Int 15h%@AE@% Assume the program updates the Time_Of_Day field from the timer interrupt. If the translation code copies 128 bytes of data starting with Buffer_Length into V86 mode memory and while processing the call a timer interrupt executes then the Time_Of_Day field will be incremented. However, when the buffer is copied back the old time will be copied on top of the current (correct) Time_Of_Day field. %@NL@% %@CR:C6A00400020 @% %@2@%%@CR:C6A00400021 @%%@AB@%V86MMGR_Load_Client_Ptr%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service will load %@AB@%FS:ESI%@AE@% with the specified Client_Seg:Offset. If the VM is running a 16-bit protected mode then the high word of the offset in %@AB@%ESI%@AE@% will be zeroed. Otherwise, if the VM is running a 32-bit program or is in %@AB@%VxD_Exec_Mode%@AE@% then the high word of %@AB@%ESI%@AE@% will not be zeroed. This allows most translation procedures to operate correctly without the need to test the execution mode of the current VM. %@NL@% The value passed in %@AB@%AX%@AE@% should be formed from the Client Register Structure equates. For example, to load the VM's %@AB@%DS:(E)DX%@AE@% you would use the following code: %@NL@% %@AS@% mov ax, (Client_DS * 100h) + Client_DX %@AS@% VxDcall V86MMGR_Load_Client_Ptr %@AS@% (FS:ESI -> Same address as Client_DS:(E)DX).%@AE@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% VM must be in protected mode %@AB@%AH%@AE@% = Client segment register equate %@AB@%AL%@AE@% = Client offset register equate %@AB@%EBX%@AE@% = Current VM Handle %@AB@%EBP%@AE@% -> Client register structure %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%FS:ESI%@AE@% -> Client's buffer %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%FS%@AE@%, %@AB@%ESI%@AE@%, Flags %@NL@% %@CR:C6A00400022 @% %@2@%%@CR:C6A00400023 @%%@AB@%V86MMGR_Allocate_Buffer%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Allocates a portion of the current VM's translation buffer and optionally copies data from the PM pointer in %@AB@%FS:ESI%@AE@% into the allocated buffer. %@NL@% Note that this service will map fewer bytes than the value specified in the %@AB@%ECX%@AE@% parameter if the length of the buffer extends past the FS segment limit. Therefore, you need to preserve the value returned in ECX from this service to use when deallocating the buffer using %@AB@%V86MMGR_Free_Buffer%@AE@%. %@NL@% The buffers are maintained as a stack. Therefore, the last buffer allocated must be the first buffer freed. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% Current VM must be in protected mode %@AB@%EBX%@AE@% = Current VM Handle %@AB@%EBP%@AE@% -> Client register structure %@AB@%ECX%@AE@% = Number of bytes to allocate %@AB@%FS:ESI %@AE@%= Pointer to extended memory to copy If carry flag is set then Source buffer will be copied into V86 buffer else Source buffer will not be copied into V86 memory %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry set then ERROR: Could not allocate buffer (out of space) else ECX = Actual number of bytes allocated (<= original %@AB@%ECX%@AE@%) High WORD of %@AB@%EDI%@AE@% = V86 segment of translation buffer Low WORD of %@AB@%EDI%@AE@% = Offset of allocated buffer %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%ECX%@AE@%, %@AB@%EDI%@AE@%, Flags %@NL@% %@CR:C6A00400024 @% %@2@%%@CR:C6A00400025 @%%@AB@%V86MMGR_Free_Buffer%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Deallocates a buffer that was allocated by the %@AB@%V86MMGR_Allocate_Buffer%@AE@% service. It will optionally copy data from the translation buffer to the buffer pointed to by %@AB@%FS:ESI%@AE@%. %@NL@% The buffers are maintained as a stack. Therefore, the last buffer allocated must be the first buffer freed. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% Current VM must be in protected mode %@AB@%EBX%@AE@% = Current VM Handle %@AB@%EBP%@AE@% -> Client register structure %@AB@%ECX%@AE@% = Number of bytes to free (returned from Allocate_Buffer) %@AB@%FS:ESI%@AE@% = Pointer to extended memory buffer If carry flag is set then Buffer will be copied from V86 memory before buffer freed else Buffer will not be copied %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00400026 @% %@2@%%@CR:C6A00400027 @%%@AB@%V86MMGR_Get_Xlat_Buff_State%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns information about the current mapping buffer status. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AU@%WARNING%@AE@% Always call this service to find the segment of the translation buffer. Since the buffer can move at any time you should never make any assumptions about the size or location of the buffer. ────────────────────────────────────────────────────────────────────────────%@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX %@AE@%= VM handle (any VM handle valid) %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = V86 segment of translation buffer (high word 0) %@AB@%ECX%@AE@% = Number of bytes of buffer not in use %@AB@%EDX%@AE@% = Total size of buffer in bytes (max size 10000h) %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, %@AB@%EBX%@AE@%, %@AB@%ECX%@AE@%, Flags %@NL@% %@CR:C6A00400028 @% %@2@%%@CR:C6A00400029 @%%@AB@%V86MMGR_Set_Xlat_Buff_State%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service is used to switch to an alternate mapping buffer. This feature is provided for protected mode terminated-and-stay resident programs which may need to switch to a private translation buffer before executing protected mode MS-DOS calls since the default buffer may be full. %@NL@% You should get the current translation buffer state, set the new state, perform any MS-DOS call, and then set the state back to the original values. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM handle (any VM handle valid) %@AB@%EAX %@AE@%= V86 segment of translation buffer (high word 0) %@AB@%ECX%@AE@% = Number of bytes of buffer not in use %@AB@%EDX%@AE@% = Total size of buffer in bytes (max size 10000h) %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00400030 @% %@2@%%@CR:C6A00400031 @%%@AB@%V86MMGR_Get_VM_Flat_Sel%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns a selector that points to the base of the specified VM's V86 address space. This is useful for 32-bit applications since this selector can be used to point to any address in the VM's V86 address space. The selector is writeable and has a limit of 11,000h bytes so that the high memory area is also addressable. %@NL@% The selector returned is in the specified VM's LDT. Therefore, the selector is only valid to use when the VM is running (is the current VM). %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX %@AE@%= VM handle (any VM handle is valid) %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EAX %@AE@%= Selector with base at high linear addr of V86 memory (high word 0) %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, Flags %@NL@% %@CR:C6A00400032 @% %@2@%%@CR:C6A00400033 @%%@AB@%V86MMGR_Get_Mapping_Info%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service will return information about the current page mapping areas. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%CH%@AE@% = Number of pages reserved for global mapping (total) %@AB@%CL%@AE@% = Number of pages available (not in use) for global mapping %@NL@% %@CR:C6A00400034 @% %@2@%%@CR:C6A00400035 @%%@AB@%V86MMGR_Map_Pages%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service maps the specified buffer into every VM at the same address using page mapping. If the contents of memory are changed in one VM, the change will be reflected in the original buffer as well in all other VMs. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI %@AE@%-> Linear address to map %@AB@%ECX%@AE@% = Number of bytes to map %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If carry flag is set then ERROR: Could not map memory else Memory is mapped %@AB@%ESI%@AE@% = Map handle (used to free the map region) %@AB@%EDI %@AE@%= Linear address of map buffer (%@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@%, %@AB@%EDI%@AE@%, Flags %@NL@% %@CR:C6A00400036 @% %@2@%%@CR:C6A00400037 @%%@AB@%V86MMGR_Free_Page_Map_Region%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service will "unmap" pages that were mapped by the %@AB@%V86MMGR_Map_Pages%@AE@% service. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = Map handle to free %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Old map buffer address contains null memory %@AB@%ESI%@AE@% is undefined %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@%, Flags %@NL@% %@CR:C6A00410001 @%%@1@%%@AB@%Chapter 41 Virtual DMA Device (VDMAD) Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% The VDMAD is the Microsoft Windows virtual device providing DMA services according to the VDS specifications. This VxD should be used in the enhanced Windows environment rather than using the VDS services directely. By default, it handles all programmed I/O for the DMA controllers and arbitrates I/O to the physical DMA ports so that more than one VM can be using the same DMA channels at the same time. In some cases, the default handling of DMA channels is not desirable. To handle these cases, VDMAD provides a number of services to enable another VxD to take control of the virtualization of specific DMA channels.%@CR:C6A00410002 @%%@NL@% VDMAD also provides some services that can be used by Bus Master devices that have their own DMA controllers. These devices still need to be able to lock and unlock DMA regions in memory and determine the physical addresses of these regions. Bus Master devices can also make use of the buffer services, if they cannot otherwise scatter/gather a linear region that is not physically contiguous. %@NL@% The VDMAD services available for Bus Master use are as follows: %@NL@% ■ %@AB@%VDMAD_Copy_From_Buffer%@AE@%%@NL@% ■ %@AB@%VDMAD_Copy_To_Buffer%@AE@%%@NL@% ■ %@AB@%VDMAD_Default_Handler%@AE@%%@NL@% ■ %@AB@%VDMAD_Disable_Translation%@AE@%%@NL@% ■ %@AB@%VDMAD_Enable_Translation%@AE@%%@NL@% ■ %@AB@%VDMAD_Get_EISA_Adr_Mode%@AE@%%@NL@% ■ %@AB@%VDMAD_Get_Region_Info%@AE@%%@NL@% ■ %@AB@%VDMAD_Get_Version%@AE@%%@NL@% ■ %@AB@%VDMAD_Get_Virt_State%@AE@%%@NL@% ■ %@AB@%VDMAD_Lock_DMA_Region%@AE@%%@NL@% ■ %@AB@%VDMAD_Mask_Channel%@AE@%%@NL@% ■ %@AB@%VDMAD_Release_Buffer%@AE@%%@NL@% ■ %@AB@%VDMAD_Request_Buffer%@AE@%%@NL@% ■ %@AB@%VDMAD_Reserve_Buffer_Space%@AE@%%@NL@% ■ %@AB@%VDMAD_Scatter_Lock%@AE@%%@NL@% ■ %@AB@%VDMAD_Scatter_Unlock%@AE@%%@NL@% ■ %@AB@%VDMAD_Set_EISA_Adr_Mode%@AE@%%@NL@% ■ %@AB@%VDMAD_Set_Phys_State%@AE@%%@NL@% ■ %@AB@%VDMAD_Set_Region_Info%@AE@%%@NL@% ■ %@AB@%VDMAD_Set_Virt_State%@AE@%%@NL@% ■ %@AB@%VDMAD_Unlock_DMA_Region%@AE@%%@NL@% ■ %@AB@%VDMAD_UnMask_Channel%@AE@%%@NL@% ■ %@AB@%VDMAD_Virtualize_Channel%@AE@%%@NL@% %@CR:C6A00410003 @% %@2@%%@CR:C6A00410004 @%%@AB@%VDMAD_Copy_From_Buffer%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service allows another device to copy data from the VDMAD buffer to the actual DMA region associated with the buffer. This service is called after %@AB@%VDMAD_Request_Buffer%@AE@%, after a memory write transfer and before %@AB@%VDMAD_Release_Buffer%@AE@%. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = buffer ID %@AB@%ESI%@AE@% = region linear %@AB@%EDI %@AE@%= offset within buffer for start of copy %@AB@%ECX%@AE@% = size %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Carry clear data copied from buffer into DMA region Carry set %@AB@%AL%@AE@% = 0Ah (DMA_Invalid_Buffer) - invalid buffer id supplied = 0Bh (DMA_Copy_Out_Range) - (%@AB@%ESI %@AE@%+ %@AB@%ECX%@AE@%) is greater than buffer size %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00410005 @% %@2@%%@CR:C6A00410006 @%%@AB@%VDMAD_Copy_To_Buffer%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service allows another device to copy data into the VDMAD buffer from the actual DMA region associated with the buffer.This service is called after %@AB@%VDMAD_Request_Buffer%@AE@% and before starting a memory read transfer. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = buffer id %@AB@%ESI %@AE@% = region linear %@AB@%EDI %@AE@%= offset within buffer for start of copy %@AB@%ECX%@AE@% = size %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Carry clear data copied from DMA region into buffer Carry set %@AB@%AL%@AE@% = 0Ah (DMA_Invalid_Buffer) - invalid buffer id supplied = 0Bh (DMA_Copy_Out_Range) - (%@AB@%ESI%@AE@% + %@AB@%ECX%@AE@%) is greater than buffer size %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00410007 @% %@2@%%@CR:C6A00410008 @%%@AB@%VDMAD_Default_Handler%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Default DMA channel I/O callback routine. This routine receives notifications of virtual state changes and handles setting up the physical state to start DMA transfers. %@NL@% %@AS@% get virtual state %@AS@% If channel virtually unmasked then %@AS@% lock region %@AS@% If lock fails then %@AS@% request buffer %@AS@% If memory read operation then %@AS@% copy data to buffer %@AS@% set phyical state %@AS@% physically unmask channel%@AE@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = DMA handle %@AB@%EBX%@AE@% = VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Anything %@NL@% %@CR:C6A00410009 @% %@2@%%@CR:C6A00410010 @%%@AB@%VDMAD_Disable_Translation%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service disables the automatic translation done for the standard DMA channels.It is necessary, if a V86 app or driver, or a PM app uses the DMA services thru INT 4BH to determine actual physical addresses for DMA transfers. A disable count is maintained, so a matching call to %@AB@%VDMAD_Enable_Translation%@AE@% is required for each call to this service to re-enable translation. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = DMA handle %@AB@%EBX%@AE@% = VM Handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Carry clear automatic translation is disable for the channel Carry set the disable count overflowed %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00410011 @% %@2@%%@CR:C6A00410012 @%%@AB@%VDMAD_Enable_Translation%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This decrements the disable count associated with a standard DMA channel. If the disable count goes to 0, then automatic translation is re-enabled. See %@AB@%VDMAD_Disable_Translation%@AE@% for further information. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX %@AE@%= DMA handle %@AB@%EBX%@AE@% = VM Handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Carry clear service completed successfully Z-flag clear, if automatic translation is re-enabled Carry set attempt to enable when translation already enabled %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00410013 @% %@2@%%@CR:C6A00410014 @%%@AB@%VDMAD_Get_EISA_Adr_Mode%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Get EISA extended mode - the hardware doesn't allow for reading the extended mode for a channel, so VDMAD defaults to the ISA defaults (channels 0-3 are byte channels and 5-7 are word channels with word addresses and counts) An INI switch can specify an alternate setting. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Channel # (0..7) or DMA Handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%CL%@AE@% = 0 - 8-bit I/O, with count in bytes %@AB@%CL%@AE@% = 1 - 16-bit I/O, with count in words and adr shifted %@AB@%CL%@AE@% = 2 - 32-bit I/O, with count in bytes %@AB@%CL%@AE@% = 3 - 16-bit I/O, with count in bytes %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%ECX%@AE@%, Flags %@NL@% %@CR:C6A00410015 @% %@2@%%@CR:C6A00410016 @%%@AB@%VDMAD_Get_Region_Info%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Get information about the current region assigned to a DMA handle. This information can be used by a handler to call the following services: %@NL@% ■ %@AB@%VDMAD_Unlock_DMA_Region%@AE@%%@NL@% ■ %@AB@%VDMAD_Release_Buffer%@AE@%%@NL@% ■ %@AB@%VDMAD_Copy_To_Buffer%@AE@%%@NL@% ■ %@AB@%VDMAD_Copy_From_Buffer%@AE@%%@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = DMA handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%BL %@AE@%= buffer id %@AB@%BH%@AE@% = pages locked (0 = FALSE, else TRUE) %@AB@%ESI %@AE@% = region linear %@AB@%ECX%@AE@% = size in bytes %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@%, %@AB@%ECX%@AE@%, %@AB@%ESI%@AE@% %@NL@% %@CR:C6A00410017 @% %@2@%%@CR:C6A00410018 @%%@AB@%VDMAD_Get_Version%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Returns the version of the Virtual DMA Device %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%AH%@AE@% = Major version number %@AB@%AL%@AE@% = Minor version number %@AB@%ECX%@AE@% = Buffer size in bytes (0, if not allocated; a buffer will always be allocated, but it doesn't happen until %@AB@%Device_Init%@AE@%) Carry flag clear %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, Flags %@NL@% %@CR:C6A00410019 @% %@2@%%@CR:C6A00410020 @%%@AB@%VDMAD_Get_Virt_State%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service allows a channel owner to determine the current virtual state of the channel. The virtual state consists of all the information necessary to physically program the DMA channel for a DMA transfer (linear address of target region, byte length of region, mode of transfer, and state of mask bit and software request bit) This state information reflects how the VM thinks the hardware is currently programmed. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = DMA handle %@AB@%EBX%@AE@% = VM handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If translation is enabled %@AB@%ESI%@AE@% = high linear address of the user's DMA region (high linear is used so that the DMA can proceed even if a different VM is actually running at the time of the transfer) Else %@AB@%ESI%@AE@% = physical byte address programmed (shifted left 1, for word ports) %@AB@%ECX%@AE@% = count in bytes %@AB@%DL%@AE@%= mode (same as 8042 mode byte with channel # removed and DMA_masked & DMA_requested set as appropriate: DMA_masked channel masked and not ready for a transfer DMA_requested software request flag set) %@AB@%DH%@AE@%= extended mode (ignored on non-PS2 machines that don't have extended DMA capabilities) %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@%, %@AB@%ECX%@AE@%, %@AB@%EDX%@AE@%, flags %@NL@% %@CR:C6A00410021 @% %@2@%%@CR:C6A00410022 @%%@AB@%VDMAD_Lock_DMA_Region%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service attempts to lock a region of memory for a DMA transfer. It is called before a DMA transfer is started (before the physical state is set for a channel and before it is unmasked.) %@NL@% It first verifies that the region is mapped to contiguous pages of physical memory. %@NL@% Then it determines whether the region will result in a DMA bank (page) %@NL@% wrap %@NL@% %@STUB@% On AT(R) class machines each channel has a base address register and a page address register. The base address register is incremented after each byte or word transfered. If the increment of this 16 bit register results in the roll over from FFFFh to 0, then the transfer wraps to the start of the DMA bank because the page register is not updated. Normally MS-DOS watches for this condition and adjusts INT 13h parameters to split transfers to avoid this wrap, but MS-DOS doesn't know anything about the difference between linear and physical addresses under enhanced Windows, so VDMAD checks again to prevent wrap from occurring undesirably.%@NL@% If all of these checks are okay, then the service calls the memory manager to lock the physical pages. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%This routine does not check to see if the region is within some physical %@AI@%maximum constraint. If the region is lockable, then it locks the memory, and %@AI@%it is up to the caller to check to see if the physical region is acceptable. %@AI@%If the region is not acceptable, then the caller should unlock the region %@AI@%and perform a buffered DMA transfer.%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI %@AE@% = linear address of actual DMA region %@AB@%ECX%@AE@% = # of bytes in DMA region %@AB@%DL %@AB@%%@AE@% = 1b, if region must be aligned on 64K page boundary = 10b, if region must be aligned on 128K page boundary %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Carry set, if lock failed %@AB@%ECX%@AE@% = # of bytes that are lockable in the region (starting from ESI) %@AB@%AL%@AE@% = 1 (DMA_Not_Contiguous), region not contiguous = 2 (DMA_Not_Aligned), region crossed physical alignment boundary = 3 (DMA_Lock_Failed), unable to lock pages ELSE %@AB@%EDX%@AE@% = physical address of the DMA region the region has been locked %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, %@AB@%ECX%@AE@%, %@AB@%EDX%@AE@%, Flags %@NL@% %@CR:C6A00410023 @% %@2@%%@CR:C6A00410024 @%%@AB@%VDMAD_Mask_Channel%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service physically masks a channel so that it will not attempt any further DMA transfers. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = DMA handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00410025 @%%@CR:C6A00410026 @% %@2@%%@CR:C6A00410027 @%%@AB@%VDMAD_Release_Buffer%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Release the VDMAD buffer assigned to a DMA channel from a previous %@AB@%VDMAD_Request_Buffer%@AE@% call. This routine exits from a critical section and the DMA buffer will now be available for other users. Any data in the buffer is not automatically copied, so %@AB@%VDMAD_Copy_From_Buffer%@AE@% must be called if the data is important. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = Buffer ID %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Carry clear buffer released Carry set bad ID %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00410028 @%%@CR:C6A00410029 @% %@2@%%@CR:C6A00410030 @%%@AB@%VDMAD_Request_Buffer%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service reserves the DMA buffer for a DMA transfer. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = linear address of actual DMA region %@AB@%ECX%@AE@% = # of bytes in DMA region %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Carry clear %@AB@%EBX%@AE@% = buffer ID %@AB@%EDX%@AE@% = the physical address of the buffer Carry set AL = 5 (DMA_Buffer_Too_Small), region request is too large for buffer = 6 (DMA_Buffer_In_Use), buffer already in use %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@%, %@AB@%EBX%@AE@%, %@AB@%ESI%@AE@%, Flags %@NL@% %@CR:C6A00410031 @% %@2@%%@CR:C6A00410032 @%%@AB@%VDMAD_Reserve_Buffer_Space%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service allows other devices that are going to handle DMA to make sure that VDMAD allocates a buffer large enough for any transfers that they might require. It also allows a device to specify a maximum physical address that would be valid for the device's DMA requests (such as 1Mb for an XT.) During the %@AB@%Device_Init%@AE@% phase of initialization, VDMAD will allocate the DMA buffer using all of the contraints specified by other devices.i.e. the buffer will be at least as big as the largest size specified by the calls to this service, and it will be allocate below the lowest maximum physical addresses specified. %@NL@% This service is only available during %@AB@%Sys_Critical_Init%@AE@%. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = # of pages requested %@AB@%ECX%@AE@% = maximum physical address that can be included in a DMA transfer; 0, if no limit. %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00410033 @% %@2@%%@CR:C6A00410034 @%%@AB@%VDMAD_Scatter_Lock%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service attempts to lock all pages mapped to a DMA region and return the actual physical addresses of the pages. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM Handle %@AB@%AL%@AE@% = 0, if the DDS table should be filled with physical addresses and sizes of the physical regions that make up the DMA region %@AB@%AL%@AE@% = 1, if the DDS table should be filled with the actual page table entries %@AB@%AL%@AE@% = 3, if the DDS table should be filled with the actual page table entries and not present pages should not be locked %@AB@%EDI%@AE@% -> extended DDS (DMA Descriptor Structure) %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Carry clear Z-flag set whole region was locked successfully Z-flag clear partial region locked Carry set nothing locked %@AB@%EDX %@AE@%= # of table entries needed to describe whole region DDS_size = # of bytes locked DDS table has been updated if request was for page table copy (AL=1 OR 3), then %@AB@%ESI%@AE@% = offset into first page for start of the region %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% %@AB@%EDX%@AE@%, %@AB@%ESI%@AE@%, Flags %@NL@% %@CR:C6A00410035 @% %@2@%%@CR:C6A00410036 @%%@AB@%VDMAD_Scatter_Unlock%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service attempts to unlock all pages locked by a previous call to %@AB@%VDMAD_Scatter_Lock%@AE@% %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EBX%@AE@% = VM Handle %@AB@%AL%@AE@% = 0, if the DDS table should be filled with physical addresses and sizes of the physical regions that make up the DMA region %@AB@%AL %@AB@%%@AE@%= 1, if the DDS table should be filled with the actual page table entries %@AB@%AL %@AE@%= 3, if the DDS table should be filled with the actual page table entries and not present pages should not be locked %@AB@%EDI%@AE@% -> extended DDS (DMA Descriptor Structure) (The table at the end of the DDS is not required, so it is not necessary to maintain the table for this unlock call.) %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Carry clear Lock counts have been decremented. If no other VxD's had pages locked, then the pages have been unlocked. Carry set The memory was not locked. %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00410037 @% %@2@%%@CR:C6A00410038 @%%@AB@%VDMAD_Set_EISA_Adr_Mode%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Set EISA extended mode %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Channel # (0..7) or DMA Handle %@AB@%CL%@AE@% = 0 - 8-bit I/O, with count in bytes %@AB@%CL%@AE@% = 1 - 16-bit I/O, with count in words and adr shifted %@AB@%CL%@AE@% = 2 - 32-bit I/O, with count in bytes %@AB@%CL %@AE@%= 3 - 16-bit I/O, with count in bytes %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00410039 @% %@2@%%@CR:C6A00410040 @%%@AB@%VDMAD_Set_Phys_State%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service programs the DMA controller state for a channel. All that it needs to know is the desired mode. The location and size of the buffer is taken from the information passed to the service %@AB@%VDMAD_Set_Region_Info%@AE@% which must be called previously. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX %@AE@%= DMA handle %@AB@%EBX %@AE@%= VM handle %@AB@%DL%@AE@% = mode %@AB@%DH %@AE@%= extended mode %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00410041 @% %@2@%%@CR:C6A00410042 @%%@AB@%VDMAD_Set_Region_Info%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Set information about the current region assigned to a DMA handle. This service must be called before calling %@AB@%VDMAD_Set_Phys_State%@AE@%. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX %@AE@%= DMA handle %@AB@%BL %@AE@%= buffer id %@AB@%BH %@AE@%= pages locked (0 = FALSE, else TRUE) %@AB@%ESI%@AE@% = region linear %@AB@%ECX %@AE@%= size in bytes %@AB@%EDX%@AE@% = physical address for transfer %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00410043 @% %@2@%%@CR:C6A00410044 @%%@AB@%VDMAD_Set_Virt_State%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% Modify the virtual state of a DMA channel. This is service is used when a channel owner wants to change the virtual state of a channel from how the VM programmed it.This might be used to split a DMA request into smaller pieces, etc. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = DMA handle %@AB@%EBX%@AE@% = VM handle If translation is enabled %@AB@%ESI%@AE@% = high linear address of the user's DMA region (high linear is used so that the DMA can proceed even if a different VM is actually running at the time of the transfer) Else %@AB@%ESI%@AE@% = physical byte address programmed (shifted left 1, for word ports) %@AB@%ECX%@AE@% = count in bytes %@AB@%DL%@AE@%= mode (same as 8042 mode byte with channel # removed and DMA_masked & DMA_requested set as appropriate: DMA_masked channel masked and not ready for a transfer DMA_requested software request flag set) %@AB@%DH%@AE@%= extended mode (ignored on non-PS2 machines that don't have extended DMA capabilities) %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00410045 @% %@2@%%@CR:C6A00410046 @%%@AB@%VDMAD_Unlock_DMA_Region%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service unlocks the DMA region previously locked to a channel. It is called after a DMA transfer is complete and the channel has been masked. So that the controller will not attempt any further transfers to the programmed address. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%ESI%@AE@% = linear address of actual DMA region %@AB@%ECX%@AE@% = # of bytes in DMA region %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Carry clear memory unlocked Carry set error %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00410047 @% %@2@%%@CR:C6A00410048 @%%@AB@%VDMAD_UnMask_Channel%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service physically unmasks a channel so that DMA transfers can proceed. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = DMA handle %@AB@%EBX %@AE@%= VM Handle %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A00410049 @% %@2@%%@CR:C6A00410050 @%%@AB@%VDMAD_Virtualize_Channel%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service allows another VxD to claim ownership of a standard DMA channel. The new owner registers a callback routine that will be called whenever the virtual state of the channel is changed as a result of I/O done in a VM. In some cases a device doesn't want to allow a VM to perform DMA to a channel at all (they will handle programming based on a private API, etc. instead of virtualized hardware I/O), so it is possible to pass a 0 to specify a null callback routine. VDMAD will continue to trap the I/O for the channel, but won't ever change the physical state of the channel as a result of any VM I/O. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% is Channel # %@AB@%ESI%@AE@% is I/O Callback procedure (0 = none) %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Carry set if channel is already owned ELSE %@AB@%EAX%@AE@% is DMA handle %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@3@%%@AB@%Callback%@AE@%%@EH@%%@NL@% ENTRY %@AB@%EAX%@AE@% = DMA handle %@AB@%EBX%@AE@% = VM handle Proc can modify %@AB@%EAX%@AE@%, %@AB@%EBX%@AE@%, %@AB@%ECX%@AE@%, %@AB@%EDX%@AE@%, %@AB@%ESI%@AE@%, %@AB@%EDI%@AE@%, and flags EXIT None %@NL@% %@CR:C6A00420001 @%%@1@%%@AB@%Chapter 42 Virtual DOSNET Device Services%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% The DOSNET device manages the network drives. To do so, it has a service (%@AB@%DOSNET_Do_PSP_Adjust%@AE@%) that enables it to indicate that the network server uses PSP addresses to identify tasks uniquely. Therefore, each VM's address space should start at a unique address. It has another service (%@AB@%DOSNET_Send_FILESYSCHANGE%@AE@%) that enables the Shell to determine whether or not a particular drive is redirected in the System VM. These services are required when network software is loaded with Windows in 386 enhanced mode. %@NL@% %@2@%%@CR:C6A00420002 @%%@AB@%DOSNET_Get_Version%@CR:C6A00420003 @%%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service returns the DOSNET device version. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% = Version, Major in %@AB@%AH%@AE@%, Minor in %@AB@%AL%@AE@% Carry clear %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags, %@AB@%EAX%@AE@% %@NL@% %@CR:C6A00420004 @% %@2@%%@CR:C6A00420005 @%%@AB@%DOSNET_Do_PSP_Adjust%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% This service enables the DOSMGR device to ask whether or not it should perform adjustments to try to give each VM in the system a different starting MS-DOS PSP address. This needs to be done on networks (such as MSNET) that use the PSP address as part of an ID to identify uniquely different processes talking to the server (this effects the behavior of DOS SHARE on the server end). On a network that uses MS-DOS PSP addresses as part of an ID, enhanced Windows can cause the ID to be non-unique since there are now multiple VMs that can all have an application in them that has the same PSP address. If the PSP adjust is enabled by this service, the DOSMGR device causes each VM to start at a different paragraph address (VMID is the basis of the adjustment value) and thus have a different PSP address. This has the cost of wasting some memory and the benefit of making the PSP addresses different in all the VMs. %@NL@% For a network that does not use MS-DOS PSP addresses for anything, or for one that is enhanced-Windows aware and uses the %@AB@%Get_VMID%@AE@% INT 2F service of enhanced Windows to deal with this problem, a return of Carry SET, %@AB@%EAX%@AE@% 0 is appropriate. %@NL@% Notice that the uniqueness of PSPs is not guaranteed by this. It will deal with the case on most configurations, but on some it will not. The only absolutely correct solution is to make the network software enhanced-Windows aware and work the VMID into the network ID, in addition to the PSP address, by using the %@AB@%Get_VMID%@AE@% INT 2F service of enhanced Windows. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% None %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Carry Set Do %@AI@%not%@AE@% do PSP adjustment %@AB@% EAX%@AE@% == 0 if SYSTEM.INI override of this is allowed %@AB@%EAX%@AE@% 0 if SYSTEM.INI override of this is %@AI@%not%@AE@% allowed Carry Clear DO PSP adjustment %@AB@%EAX%@AE@% == 0 if SYSTEM.INI override of this is allowed %@AB@%EAX %@AE@%0 if SYSTEM.INI override of this is %@AI@%not%@AE@% allowed %@NL@% Notice that the behavior of DOSMGR, if the DOSNET device is not loaded, is a return of carry Set, %@AB@%EAX %@AE@%= 0. %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags, %@AB@%EAX%@AE@% %@NL@% %@CR:C6A00420006 @% %@2@%%@CR:C6A00420007 @%%@AB@%DOSNET_Send_FILESYSCHANGE%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% %@3@%%@AB@%Description%@AE@%%@EH@%%@NL@% It is incorrect to send the WM_FILESYSCHANGE message to the Windows Shell on drives about which Windows knows nothing. This routine tells the caller whether this is a "local to this VM" drive or not. The message enables Windows applications to be told when a change is made to the file volume name space so that they can update portions of their display that may be showing that part of the file volume. %@NL@% Sending a WM_FILESYSCHANGE message on a drive incorrectly can result in all sorts of misbehavior. If the indicated drive letter is invalid in the System VM, the Windows application may get an error that it is not expecting. If the indicated drive letter actually maps a different file system volume in the System VM, all sorts of other unexpected errors may occur. %@NL@% Notice that this is a DOSNET device service and cannot be implemented directly in another VxD. Another VxD that also wishes to effect the WM_FILESYSCHANGE behavior must hook this service. Notice also that the DOSNET device does not install if there is no REDIR, so a VxD that wants to hook this service must ship with a modified DOSNET device that always loads (i.e., with the real-mode init code removed). %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%EAX%@AE@% (AL) = Drive number (0 = A) %@AB@%EBX%@AE@% is VM Handle of VM involved %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% Carry Set WM_FILESYSCHANGE should %@AI@%not%@AE@% be sent on this drive Carry Clear WM_FILESYSCHANGE %@AI@%should%@AE@% be sent on this drive %@NL@% %@3@%%@AB@%Uses%@AE@%%@EH@%%@NL@% Flags %@NL@% %@CR:C6A-A0001 @%%@1@%%@AB@%Appendix A Appendix A Terms and Acronyms%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% The following list explains the terms and acronyms that are found in the %@AI@%Microsoft Windows Device Development Kit%@AE@% for Windows 3.0. %@NL@% %@2@%%@AB@%Banding%@AE@%%@EH@%%@NL@% %@3@%The process of dividing a display surface such as a page into smaller%@EH@% horizontal rectangles, composing those individual bands within memory, and then sending the output to the printer one band at a time.%@NL@% %@2@%%@AB@%Clipping%@AE@%%@EH@%%@NL@% %@3@%The process of removing any portion of a graphic image that extends beyond a%@EH@% specified boundary.%@NL@% %@2@%%@AB@%Control Block%@AE@%%@EH@%%@NL@% %@3@%A per Virtual Machine data structure in which Virtual Devices and the%@EH@% Virtual Machine Manager can maintain the VM's state information. The control block shares the flat segment with the VMM and VxDs. It is pointed to by the VM Handle.%@NL@% %@2@%%@AB@%Control Panel%@AE@%%@EH@%%@NL@% %@3@%A Windows application that lets you change system settings, including%@EH@% printer assignments and system characteristics.%@NL@% %@2@%%@AB@%Descriptor Table%@AE@%%@EH@%%@NL@% %@3@%An array of segment descriptors. There are two kinds of descriptor tables:%@EH@% the unique Global Descriptor Table, and the per-VM Local Descriptor Table.%@NL@% %@2@%%@AB@%Device Driver%@AE@%%@EH@%%@NL@% %@3@%The dynamic-link library that provides the hardware-dependent, low-level%@EH@% interface between Windows GDI functions and the graphics output device.%@NL@% %@2@%%@AB@%Device Independent Bitmap (DIB)%@AE@%%@EH@%%@NL@% %@3@%A bitmap format that can be interpreted and converted by a device driver%@EH@% into its own specific format. It is called "device independent" because any driver capable of using DIBs can display (or otherwise use) the DIB to the best of its ability.%@NL@% %@2@%%@AB@%Direct Memory Access (DMA) %@AE@%%@EH@%%@NL@% %@3@%An accelerated memory access technique that enables peripheral devices to%@EH@% take control of the bus. See also Virtual DMA Services (VDS).%@NL@% %@2@%%@AB@%DOS Protected Mode Interface (DPMI) %@AE@%%@EH@%%@NL@% %@3@%The industry standard for non-Windows applications using protected mode. It%@EH@% is available from Intel at 1-800-548-4725.%@NL@% %@2@%%@AB@%Dynamic Data Exchange (DDE)%@AE@%%@EH@%%@NL@% %@3@%A protocol that cooperating programs can use to exchange data without user%@EH@% intervention.%@NL@% %@2@%%@AB@%Dynamic-Link Library (DLL) %@AE@%%@EH@%%@NL@% %@3@%An executable module that contains functions available to applications and%@EH@% that is linked at run time, rather than at link time.%@NL@% %@2@%%@AB@%Enhanced Windows%@AE@%%@EH@%%@NL@% %@3@%Windows 3.0 when running in 386 enhanced mode.%@NL@%%@EH@% %@2@%%@AB@%Escape%@AE@%%@EH@%%@NL@% %@3@%A device-dependent operation that is not supported by the device-independent%@EH@% GDI module. The entry point in the device driver is called %@AB@%Control()%@AE@%; in GDI (i.e., to the application), it is called %@AB@%Escape()%@AE@%.%@NL@% %@2@%%@AB@%Extended Memory Specification (XMS)%@AE@%%@EH@%%@NL@% %@3@%The XMS driver provides an API for managing extended memory. Windows uses%@EH@% XMS to load its code and data into extended memory.%@NL@% %@2@%%@AB@%Flat Model%@AE@%%@EH@%%@NL@% %@3@%A memory organization in which there is only one segment.%@NL@%%@EH@% %@2@%%@AB@%Font Resource%@AE@%%@EH@%%@NL@% %@3@%A group of individual fonts that have various combinations of heights,%@EH@% widths, and pitches.%@NL@% %@2@%%@AB@%GDI Library%@AE@%%@EH@%%@NL@% %@3@%A set of supporting functions for device drivers. These utilities include%@EH@% versions of output functions such as %@AB@%BitBlt%@AE@% and %@AB@%StrBlt%@AE@%, a Transpose function for banding devices, and priority queue functions for daisywheel printers.%@NL@% %@2@%%@AB@%Global Descriptor Table (GDT)%@AE@%%@EH@%%@NL@% %@3@%See Descriptor Table.%@NL@%%@EH@% %@2@%%@AB@%Graphics Device Interface (GDI)%@AE@%%@EH@%%@NL@% %@3@%A device-independent, high-level graphics manager. GDI provides the%@EH@% interface that feeds graphics commands from Windows application programs to the device driver.%@NL@% %@2@%%@AB@%IOPM%@AE@%%@EH@%%@NL@% %@3@%I/O Permission Map%@NL@%%@EH@% %@2@%%@AB@%Local Descriptor Table (LDT)%@AE@%%@EH@%%@NL@% %@3@%See Descriptor Table.%@NL@%%@EH@% %@2@%%@AB@%Metafile%@AE@%%@EH@%%@NL@% %@3@%A collection of GDI function calls stored in a binary coded form and used to%@EH@% transfer device-independent pictures between programs.%@NL@% %@2@%%@AB@%Microsoft Macro Assembler (MASM)%@AE@%%@EH@%%@NL@% %@3@%An assembly language compiler.%@NL@%%@EH@% %@2@%%@AB@%Non-Windows Application%@AE@%%@EH@%%@NL@% %@3@%A program that does not make use of the Windows environment. Instead, it%@EH@% calls MS-DOS and the BIOS, and accesses the hardware directly.%@NL@% %@2@%%@AB@%Page%@AE@%%@EH@%%@NL@% %@3@%A 4K block of contiguous memory locations.%@NL@%%@EH@% %@2@%%@AB@%Paging%@AE@%%@EH@%%@NL@% %@3@%A memory-management technique used by enhanced Windows to support virtual%@EH@% memory. It simulates a large, unsegmented address space by using a small, fragmented address space and some disk storage. Paging accomplishes this by keeping the available memory space partly in memory and partly on disk.%@NL@% %@2@%%@AB@%Palette%@AE@%%@EH@%%@NL@% %@3@%The range of colors that the video adapter can display and manage.%@NL@%%@EH@% %@2@%%@AB@%Pixel%@AE@%%@EH@%%@NL@% %@3@%The smallest element of a physical display surface that can be independently%@EH@% assigned color or intensity.%@NL@% %@2@%%@AB@%Pixel Array%@AE@%%@EH@%%@NL@% %@3@%A matrix of pixels that defines the color for a region on an actual display.%@EH@% There is exactly one pixel definition for each addressable picture element of a raster display covered by the pixel array.%@NL@% %@2@%%@AB@%Primitive%@AE@%%@EH@%%@NL@% %@3@%A basic graphic function to be performed.%@NL@%%@EH@% %@2@%%@AB@%Print Manager%@AE@%%@EH@%%@NL@% %@3@%The Windows utility that prints files without suspending the operation of%@EH@% other programs. It also enables you to change the priority of print jobs or to cancel them.%@NL@% %@2@%%@AB@%Printer Command Language (PCL)%@AE@%%@EH@%%@NL@% %@3@%The language used by Hewlett-Packard (R) Laserjet (R) and compatible%@EH@% printers.%@NL@% %@2@%%@AB@%Privilege Rings%@AE@%%@EH@%%@NL@% %@3@%The protection value applied to segments and segment selectors. Enhanced%@EH@% Windows uses the most privileged level (ring 0) for the VMM and VxDs. Code and data for applications running in virtual-86 mode use the least privileged level (ring 3). Protected-mode applications run in rings 1, 2, or 3.%@NL@% %@2@%%@AB@%Protected Mode (PM)%@AE@%%@EH@%%@NL@% %@3@%A mode of the 80386 and 80486 processors that provides, among other%@EH@% capabilities, arbitrary mapping of segment register values to physical memory. See Appendix B, "Understanding Modes," for a detailed description. Applications that want to use protected mode must conform to the DPMI specification.%@NL@% %@2@%%@AB@%Raster Device%@AE@%%@EH@%%@NL@% %@3@%A device that uses a matrix of pixels covering the entire screen or page%@EH@% area (display or printed surface) to draw graphics. Pixels (points) are turned on and off, bit-by-bit.%@NL@% %@2@%%@AB@%Real Mode%@AE@%%@EH@%%@NL@% %@3@%An execution mode of an Intel processor that functions as an 8086; also%@EH@% called "real-address mode." The 80286, 80386, and 80486 processors run in this mode when started up. See also Appendix B, "Understanding Modes."%@NL@% %@2@%%@AB@%Red, Green, Blue (RGB)%@AE@%%@EH@%%@NL@% %@3@%Values from a color table. This color table is used in mapping from a color%@EH@% index to corresponding color values.%@NL@% %@2@%%@AB@%Resolution%@AE@%%@EH@%%@NL@% %@3@%The number of visibly distinct dots that can be displayed in a given area of%@EH@% the screen. Typical resolution is 100 dots per inch.%@NL@% %@2@%%@AB@%Scaling%@AE@%%@EH@%%@NL@% %@3@%Coordinate scaling transforms points from one level to another. GDI scales%@EH@% coordinates from NDC space to values appropriate for your graphics device.%@NL@% %@2@%%@AB@%%@AB@%SETUP.INF%@AE@%%@AE@%%@EH@%%@NL@% %@3@%A file containing all the information needed to set up a device driver for%@EH@% Windows. See also Appendix C, "Creating Distribution Disks for Drivers."%@NL@% %@2@%%@AB@%%@AB@%SYSTEM.INI%@AE@%%@AE@%%@EH@%%@NL@% %@3@%A file in the Windows directory that holds the Windows configuration%@EH@% information that is used when starting up Windows. It differs from WIN.INI, which is mainly for storing user preferences, by containing hardware and software descriptions.%@NL@% %@2@%%@AB@%System VM%@AE@%%@EH@%%@NL@% %@3@%The first Virtual Machine (VM) under enhanced Windows. The VM in which%@EH@% Windows runs.%@NL@% %@2@%%@AB@%Task%@AE@%%@EH@%%@NL@% %@3@%A program that is running or waiting to run.%@NL@%%@EH@% %@2@%%@AB@%Task Switch%@AE@%%@EH@%%@NL@% %@3@%A transfer of execution between tasks (i.e., a context switch). Unlike%@EH@% procedure calls, which saves only the contents of the general registers, a task switch saves most of the processor state. For example, the registers used for address translation are reloaded, so that each task can have a different logical-to-physical address mapping.%@NL@% %@2@%%@AB@%TSRs%@AE@%%@EH@%%@NL@% %@3@%Terminate-and-Stay Resident applications.%@NL@%%@EH@% %@2@%%@AB@%VCD%@AE@%%@EH@%%@NL@% %@3@%Virtual Comm Device%@NL@%%@EH@% %@2@%%@AB@%VDD%@AE@%%@EH@%%@NL@% %@3@%Virtual Display Device%@NL@%%@EH@% %@2@%%@AB@%VDMAD%@AE@%%@EH@%%@NL@% %@3@%Virtual DMA Device%@NL@%%@EH@% %@2@%%@AB@%VFD%@AE@%%@EH@%%@NL@% %@3@%Virtual Floppy Drive Device%@NL@%%@EH@% %@2@%%@AB@%VHD%@AE@%%@EH@%%@NL@% %@3@%Virtual Hard Disk Device%@NL@%%@EH@% %@2@%%@AB@%VKD%@AE@%%@EH@%%@NL@% %@3@%Virtual Keyboard Device%@NL@%%@EH@% %@2@%%@AB@%VMD%@AE@%%@EH@%%@NL@% %@3@%Virtual Mouse Device%@NL@%%@EH@% %@2@%%@AB@%VPD%@AE@%%@EH@%%@NL@% %@3@%Virtual Printer Device%@NL@%%@EH@% %@2@%%@AB@%VPICD%@AE@%%@EH@%%@NL@% %@3@%Virtual Programmable Interrupt Controller Device%@NL@%%@EH@% %@2@%%@AB@%Vector Device%@AE@%%@EH@%%@NL@% %@3@%A device that draws graphics with lines. Beginning and ending points are set%@EH@% and a line is drawn between them.%@NL@% %@2@%%@AB@%Virtual 8086 mode (V86)%@AE@%%@EH@%%@NL@% %@3@%A mode of the 80386 processor by which the 80386 emulates the function of%@EH@% the 8086 processor. In this mode, each segment has a linear address limit of 64K, and the applications can address a total of 1M + 64K - 16 bytes. Software running in V86 mode, however, can use the 80386's 32-bit registers.%@NL@% %@2@%%@AB@%Virtual DMA Device (VDMAD) %@AE@%%@EH@%%@NL@% %@3@%The VDMAD is the Windows virtual device that supports standard DMA devices%@EH@% on ISA machines as well as the VDS API for non-ISA devices.%@NL@% %@2@%%@AB@%Virtual DMA Services (VDS) %@AE@%%@EH@%%@NL@% %@3@%The VDS specification describes how an MS-DOS DMA device driver can perform%@EH@% DMA. VxD authors should use the services of the VDMAD rather than work directly from this specification.%@NL@% %@2@%%@AB@%Virtual "x" Device (VxD)%@AE@%%@EH@%%@NL@% %@3@%The name of the device virtualized replaces the "x" in this name. There must%@EH@% be a VxD for each piece of hardware that can have a different state in each of the VMs. Any piece of hardware that does not have an associated VxD is global. It must handle interleaved access from multiple VMs or have a global piece of software (such as a DOS device driver or TSR) that serializes access to the hardware. All the VxDs run in the same, flat-model, 32-bit segment as the rest of the VMM. A VxD can also provide services that are not directly associated with a piece of hardware (e.g., a piece of code that replaces an MS-DOS or BIOS service).%@NL@% %@2@%%@AB@%Virtual Machine (VM)%@AE@%%@EH@%%@NL@% %@3@%The part of the enhanced Windows environment in which Windows and%@EH@% non-Windows applications execute. A VM consists of all the resources (physical and/or virtualized) available to the application, plus the state of the application. The state of the application includes the memory, the processor state, and the state of the VMM and VxDs as maintained in the VM control block.%@NL@% %@2@%%@AB@%Virtual Machine Manager (VMM)%@AE@%%@EH@%%@NL@% %@3@%The core of enhanced Windows. It runs, along with all the VxDs, in one,%@EH@% flat-model, 32-bit segment.%@NL@% %@2@%%@AB@%Virtual Memory%@AE@%%@EH@%%@NL@% %@3@%Memory that an application can access that is greater than the actual%@EH@% physical memory present. To support this, enhanced Windows transparently pages 4K memory blocks to and from physical memory on behalf of the applications. %@NL@% %@2@%%@AB@%WDEB386%@AE@%%@EH@%%@NL@% %@3@%A Windows 3.0 debugger program that can be used in protected mode with%@EH@% either an 80286, 80386, or 80486 processor.%@NL@% %@2@%%@AB@%Window%@AE@%%@EH@%%@NL@% %@3@%A rectangular region on a display screen in which the system displays the%@EH@% contents of an application.%@NL@% %@2@%%@AB@%Windows Application%@AE@%%@EH@%%@NL@% %@3@%Any program that has been specifically designed to run under Microsoft%@EH@% Windows.%@NL@% %@2@%%@AB@%WIN.INI%@AE@%%@EH@%%@NL@% %@3@%The Windows initialization file in which you maintain the system-wide%@EH@% settings for user preferences. The SYSTEM.INI file contains the hardware and software descriptions. WIN.INI is a text-based file that resides in the Windows software directory.%@NL@% %@2@%%@AB@%XMS%@AE@%%@EH@%%@NL@% %@3@%See Extended Memory Specification. %@NL@%%@EH@% %@CR:C6A-B0001 @%%@1@%%@AB@%Appendix B Understanding Modes%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% Microsoft Windows 3.0 documentation uses the term "mode" in overlapping ways. This appendix is provided to clarify the different uses. %@NL@% %@2@%%@CR:C6A-B0002 @%%@AB@%B.1 Windows Modes%@AE@%%@EH@%%@NL@% To provide the greatest features for the available hardware, Windows 3.0 can run in three software modes: real, standard, or 386 enhanced. The following table compares the memory models and required microprocessor for each of these Windows modes.%@CR:C6A-B0003 @%%@NL@% %@TH: 15 715 02 13 11 15 37 @%Windows 3.0 Real Mode Standard Mode 386 Enhanced Mode%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%Supported Real Mode Real Mode Real Mode Memory Protected Protected Mode (32-bit) Model Mode (16-bit) V86 Mode%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%Required 8086 Hardware 80286 80286 80386 80386 80386 80486 80486 80486 %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%%@TE: 15 715 02 13 11 15 37 @% %@2@%%@CR:C6A-B0004 @%%@AB@%B.2 Microprocessor Modes%@AE@%%@EH@%%@NL@% As the Intel microprocessors evolved greater capabilities, they continued to support the programs and operating systems of the earlier architectures. As a result, the 80386 has no fewer than four modes. Each is compared below to the earlier architectures. %@NL@% The first is the familiar %@AI@%real mode%@AE@%, wherein the 80386 functions as a fast 8086/88-compatible processor with some bonus opcodes. Like the 80286, the 80386 always powers up in real mode and can, therefore, run any existing 8086 operating systems and software.%@CR:C6A-B0005 @%%@NL@% In %@AI@%protected mode%@AE@%, the 80386 can take on two different personalities. It can execute a logical superset of the 80286 protected-mode instructions and run 16-bit programs. Or, while in its native protected mode, it can use 32-bit instructions, registers, and stacks and can allow individual memory segments as large as 4GB. The native protected mode also has an additional level of address translation─supported in hardware by page tables─that allows much greater flexibility in mapping the linear address onto physical memory. In either protected mode, the 80386 translates selectors and offsets to linear addresses using descriptor tables in much the same manner as the 80286.%@CR:C6A-B0006 @%%@NL@% The forth operating mode, %@AI@%virtual 86 mode%@AE@% (V86), provides another form of 8086 emulation. But now, instead of a single program running in a single memory partition, the 80386 can create multiple partitions, each capable of running a real-mode program. Each partition has its own address space, I/O port space, and interrupt vector table. Enhanced Windows uses the V86-mode partitions to create virtual machines, the fundamental components in its virtual machine architecture. The architecture is described in Chapter 16, "Overview of Windows in 386 Enhanced Mode."%@CR:C6A-B0007 @%%@NL@% The following table summarizes the four modes of the 80386 microprocessor: %@NL@% %@TH: 18 963 02 40 40 @%Mode Description%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%Real Mode Functions as a very fast 8086/88-compatible processor.Protected Mode (16-bit) Functions in protected mode as an enhanced 286 processor.Protected Mode (32-bit, native mode) Functions in protected mode using full 32-bit instructions, registers, and stacks.Virtual 86 Mode Runs multiple, protected, virtual 8086 machines, each with its own 1MB of memory space.%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%%@TE: 18 963 02 40 40 @% %@CR:C6A-C0001 @%%@1@%%@AB@%Appendix C Creating Distribution Disks for Drivers%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% Once you have developed your device driver and/or virtual device, you must create a distribution disk for installing it into the user's Windows environment. %@NL@% In Windows 3.0, we have included two Windows utilities (i.e., Setup and Control Panel) that make installing device drivers and virtual devices that are not available in the retail product much easier for the user. These utilities do this by using the data stored in the Information (.INF) file that is provided in the Windows retail product. %@NL@% This appendix provides information on the following topics: %@NL@% ■ How Setup and Control Panel use Information files%@NL@% ■ The various components of the Information file %@NL@% ■ How to create an Information file for installing your device driver and/or virtual device%@NL@% ■ Syntax and examples of the data in an Information file, given by device type%@NL@% ■ How to use Setup and Control Panel to test the installation of your device driver and/or virtual device%@NL@% ■ How to inform Microsoft about the availability of your device driver and/or virtual device %@NL@% %@2@%%@CR:C6A-C0002 @%%@AB@%C.1 What is an Information File?%@AE@%%@EH@%%@NL@% An Information (.INF) file provides the data required for Windows to install drivers and virtual devices that are provided on a set of disks. %@NL@% It contains the following type of information: %@NL@% ■ The location of the driver and virtual device files (e.g., disk)%@NL@% ■ The device description string to be presented to the end user%@NL@% ■ Which driver and/or virtual device or other dependent files to install, depending on the device. For example, which screen fonts to install for a particular display and the associated virtual device (when setting up on an 80386 machine)%@NL@% ■ System configuration data for various machine types%@NL@% The Setup utility uses the data in the Information (.INF) file to install the following types of configuration information, device drivers, and virtual devices: %@NL@% ■ Displays and associated font files%@NL@% ■ Mice or other pointing devices%@NL@% ■ Networks%@NL@% ■ Keyboard types, subtypes, and layouts%@NL@% ■ 386 enhanced mode virtual devices%@NL@% ■ Machine dependent configurations:%@NL@% %@STUB@% Display%@NL@% %@STUB@% Mouse or other pointing device%@NL@% %@STUB@% Keyboard%@NL@% %@STUB@% Comm%@NL@% %@STUB@% Sound%@NL@% %@STUB@% System%@NL@% %@STUB@% Any required 386 enhanced mode virtual devices and switches %@NL@% Control Panel uses the data in the Information (.INF) file to install printer drivers and Windows raster (or screen) fonts. %@NL@% %@2@%%@CR:C6A-C0003 @%%@AB@%C.2 Different Types of Information Files%@AE@%%@EH@%%@NL@% The .INF file provided with Windows is named SETUP.INF and is stored in the Windows ..\SYSTEM subdirectory. The SETUP.INF filename is unique and used by Setup and Control Panel for standard Windows operations. This name is reserved for Windows and should not be used on your distribution disk. %@NL@% A second type of .INF file that is used by Setup and Control Panel is called OEMSETUP.INF. This name is to be used specifically for installing additional drivers on a distribution disk. %@NL@% Setup and Control Panel look for this filename, OEMSETUP.INF, when installing drivers and virtual devices that are not part of the retail package. In general, the OEMSETUP.INF file you create will contain a subset of the information provided in the SETUP.INF file. %@NL@% You may want to print a copy of the SETUP.INF file to use as a reference for the following sections. The file is in ASCII text format and can be printed on most printers. %@NL@% The steps for installing additional drivers are described in more detail later in Section C.7, "Testing the Installation of Your Information File." %@NL@% %@2@%%@CR:C6A-C0004 @%%@AB@%C.3 General Format and Syntax for Information Files%@AE@%%@EH@%%@NL@% .INF files are broken up into %@AI@%sections%@AE@%, with each section generally containing information pertaining to a specific set of Windows driver or system files. Section names are always enclosed in square brackets ([]). %@NL@% Sections are further broken up into %@AI@%lines%@AE@%, with each line generally containing information about a single Windows system or driver file. %@NL@% Finally, the lines within sections are further broken up into %@AI@%fields%@AE@%, with each field within a line generally containing information specific to the system or driver file listed on that line. Fields are always separated by commas (,). %@NL@% The following is a generalized syntax line and, then, a sample section from the SETUP.INF file: %@NL@% Profile_string = Disk:Filename,"Text_Description",Disk:Virtual_Device %@NL@% %@AS@% [pointing.device] %@AS@% nomouse = 2:nomouse.drv, "No mouse or pointing device", 3:*vmd %@AS@% ps2mouse = 1:mouse.drv, "Microsoft, or IBM PS/2", 3:*vmd %@AS@% msmouse1 = 2:msmouse1.drv, "Mouse Systems (or VisiOn) COM1:", 3:*vmd %@AS@% msmouse2 = 2:msmouse2.drv, "Mouse Systems (or VisiOn) COM2:", 3:*vmd %@AS@% lmouse = 2:lmouse.drv, "Logitech", 3:*vmd %@AS@% kbdmouse = 2:kbdmouse.drv, "AT&T/Olivetti Keyboard Mouse", 3:*vmd %@AS@% hpmouse = 2:hpmouse.drv, "HP Mouse (HP-HIL)", 3:*vmd%@AE@% In the above example, the section name is [pointing.device]. Each line in the section contains information pertaining to the mouse driver listed in the first field of the line. %@NL@% The string on the lefthand side of the equal sign (=) in the first field is a %@AI@%profile%@AE@% string. The profile string is the unique "handle" that Setup uses to parse a line from the .INF file that matches the hardware for which Setup is configuring Windows. For example, if Setup detects that a Logitech mouse is connected to the computer for which it is configuring Windows, it will look for the string "lmouse" in the [pointing.device] section of the .INF file. Once found, Setup uses the information on that line to determine how to configure Windows for the Logitech mouse. The profile string portion of the first field is considered to be field zero or may be referred to as the profile field. Profile strings are limited to 15 characters. %@NL@% The second field of each line is a %@AI@%Text_Description%@AE@% string for the mouse driver on that line. Description strings are limited to 48 characters. %@NL@% The third field is the name of the %@AI@%Virtual_Device%@AE@% file required for that mouse to operate correctly under the 386 enhanced mode of Windows. If the first character of any virtual device name is an asterisk (*), then that driver is part of the WIN386.EXE file. If the virtual device name does not contain an asterisk, then that file is separate from WIN386.EXE. 386 enhanced mode VxD files generally have the file extension .386 to identify then as 386 enhanced mode VxDs. %@NL@% %@2@%%@CR:C6A-C0005 @%%@AB@%C.4 File Location Information%@AE@%%@EH@%%@NL@% All the files that are listed in the .INF file have associated with them a logical disk ID. The logical disk ID is a single character (1-9 A-Z). Therefore, there are 1-9 + A-Z = 35 possible logical disk IDs. The logical disk ID is added to the beginning of every filename listed in the .INF file and separated from the filename by a colon (:) in the form %@AI@%x:filename%@AE@% where %@AI@%x%@AE@% is the logical disk ID. The logical disk ID zero (0) is reserved for use by Setup. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% NOTE %@AI@%You must use a unique filename. We also suggest that this name be different %@AI@%from the names of files defined in SETUP.INF.%@AE@% ────────────────────────────────────────────────────────────────────────────%@NL@% The logical disk ID is mapped to a physical disk in the [disks] section of the .INF file. The following is a generalized syntax line and, then, a sample of a .INF file's [disks] section that maps the logical to physical disk location of the mouse drivers listed in the [pointing.device] section. %@NL@% Disk_ID = Drive,"Text_Description" %@NL@% %@AS@% [disks] %@AS@% 1 =.\, "Microsoft Windows 3.0 Disk #1" %@AS@% 2 =.\disk2, "Microsoft Windows 3.0 Disk #2"%@AE@% In the preceding [disks] section example, the profile string corresponds to a logical disk ID. For every logical disk ID used in the .INF file, there must be a line in the [disks] section that maps that logical disk ID to a physical disk location. %@NL@% The first field in the [disks] section is the physical location that corresponds to the logical disk ID in the profile string. In the preceding example, all the filenames that start with logical disk ID 1 will exist in the physical root of the current drive (.\). All the filenames that start with logical disk ID 2 will exist in the physical subdirectory \disk2 of the current drive. %@NL@% The second field is a %@AI@%Text_Description%@AE@% string used to identify the physical disk location. This is used by Setup and Control Panel for disk prompting if the physical disk locations for different logical disk IDs are on different floppy disks, which is normal. %@NL@% %@2@%%@CR:C6A-C0006 @%%@AB@%C.5 Creating .INF File Entries%@AE@%%@EH@%%@NL@% The following .INF file entries are examples to follow when creating an OEMSETUP.INF file for displays, mice or other pointing devices, networks, keyboards, and machine-dependent configurations. %@NL@% See Section C.6, "Creating .INF File Entries for Printer Drivers," for information on how to create an OEMSETUP.INF file for printer devices. %@NL@% See Section C.3, "General Format and Syntax for Information Files," and Section C.4, "File Location Information," for more information about profile strings, text descriptions, driver filenames, and disk location descriptions. These fields are referenced throughout the following examples. %@NL@% The colons, commas, and quotes shown in the following examples are required as part of the format. %@NL@% %@3@%%@CR:C6A-C0007 @%%@AB@%C.5.1 Display Device%@AE@%%@EH@%%@NL@% The following is a generalized example of the syntax used for display devices along with definitions of each of the terms presented. %@NL@% [display] Profile_string = Disk:Filename,"Text_Description","Aspect_Ratio", Disk:Grabber,Disk:Logo_Code,Disk:Virtual_Display_Device, Disk:386_Grabber,[Disk:EGA_DOS_Driver],Disk:Logo_Data %@NL@% Where: %@NL@% %@AI@%Filename%@AE@% is the MS-DOS filename of the driver file. %@NL@% %@AI@%Text_Description%@AE@% is a character string describing the device on that line. %@NL@% %@AI@%Aspect_Ratio%@AE@% is information that is used to determine which raster (or screen) fonts to install for use by the device. Any fonts found with matching aspect values in the [sysfonts], [fixedfonts], [oemfonts], or [fonts] sections of the .INF file will be installed in the [fonts] section of the WIN.INI file. %@NL@% Aspect_Ratio includes the following three values: %@NL@% ■ X and Y aspect ratio%@NL@% ■ X pixels-per-inch%@NL@% ■ Y pixels-per-inch%@NL@% The three values are separated by commas and enclosed within quotation marks. For example, for a VGA display, the values would be as follows: %@NL@% "100,96,96" %@NL@% Where: %@NL@% %@AI@%100%@AE@% is the X and Y aspect ratio (1-to-1). %@NL@% %@AI@%96%@AE@% is the X (horizontal) pixels-per-inch. %@NL@% %@AI@%96%@AE@% is the Y (vertical) pixels-per-inch. %@NL@% See the description of the GDIINFO data structure in Chapter 2, "Display Drivers," in the %@AI@%Microsoft Windows Device Driver Adaptation Guide%@AE@% for more information on calculating these values. %@NL@% %@AI@%Grabber%@AE@% is the MS-DOS filename of the grabber used when Windows is running in real and standard mode. %@NL@% %@AI@%Logo_Code%@AE@% is the MS-DOS filename of the logo display code that is used by Setup to build the WIN.COM file. %@NL@% %@AI@%Virtual_Display_Device%@AE@% is the MS-DOS filename of the VDD that Windows will use in 386 enhanced mode. %@NL@% %@AI@%386_Grabber%@AE@% is the MS-DOS filename of the grabber used when Windows is running in 386 enhanced mode. %@NL@% %@AI@%EGA_DOS_Driver%@AE@% is an optional field. It is the MS-DOS filename of an MS-DOS installable device driver used to virtualize the write-only registers on EGA display cards so that they can be read. %@NL@% %@AI@%Logo_Data%@AE@% is the MS-DOS filename of the logo data that is used by Setup to build the WIN.COM file. %@NL@% The following is an example of what a .INF file for a specific EGA display driver would look like. %@NL@% %@AS@% [data] %@AS@% defxlat = 437%@AE@% %@AS@% [disks] %@AS@% 1 =. ,"OEM Display Driver Disk #1"%@AE@% %@AS@% [display] %@AS@% oemega = 1:ega.drv,"OEM EGA Color","133,96,72", %@AS@% 1:egacolor.gr2,1:egalogo.lgo,1:vddega.386, %@AS@% 1:ega.gr3,1:ega.sys,1:egalogo.rle%@AE@% %@AS@% [EGA.GR3] %@AS@% 1:CGA40WOA.FON,1:CGA40850.FON %@AS@% 1:CGA80WOA.FON,1:CGA80850.FON %@AS@% 1:EGA40WOA.FON,1:EGA40850.FON %@AS@% 1:EGA80WOA.FON,1:EGA80850.FON%@AE@% %@AS@% [codepages] %@AS@% ; Xlat Table OEM Font description. %@AS@% 863 = 2:xlat863.bin, 2:vga863.fon, "French Canadian (863)" %@AS@% 861 = 2:xlat861.bin, 2:vga861.fon, "Icelandic (861)" %@AS@% 865 = 2:xlat865.bin, 2:vga865.fon, "Norway & Denmark (865)" %@AS@% 850 = 2:xlat850.bin, 2:vga850.fon, "International (850)" %@AS@% 860 = 2:xlat860.bin, 2:vga860.fon, "Portuguese (860)" %@AS@% 437 = , , "Standard (437)"%@AE@% %@AS@% [sysfonts] %@AS@% 1:egasys.fon,"EGA (640x350) resolution System Font","133,96,72"%@AE@% %@AS@% [fixedfonts] %@AS@% 1:egafix.fon,"EGA (640x350) resolution Fixed System Font","133,96,72"%@AE@% %@AS@% [oemfonts] %@AS@% 1:egaoem.fon,"EGA (640x350) resolution Terminal Font %@AS@%(USA/Europe)","133,96,72",1%@AE@% %@AS@% [fonts] %@AS@% 1:HELVB.FON, "Helv 8,10,12,14,18,24 (EGA res)", "133,96,72" %@AS@% 1:COURB.FON, "Courier 10,12,15 (EGA res)", "133,96,72" %@AS@% 1:TMSRB.FON, "Tms Rmn 8,10,12,14,18,24 (EGA res)", "133,96,72" %@AS@% 1:SYMBOLB.FON, "Symbol 8,10,12,14,18,24 (EGA res)", "133,96,72" %@AS@% 1:ROMAN.FON, "Roman (All res)", "CONTINUOUSSCALING" %@AS@% 1:SCRIPT.FON, "Script (All res)", "CONTINUOUSSCALING" %@AS@% 1:MODERN.FON, "Modern (All res)", "CONTINUOUSSCALING"%@AE@% Because there are many display-dependent files, the .INF file for installing display drivers is more complicated. For any given Windows display driver, the following related files are also required by Windows 3.0. %@NL@% %@TH: 12 619 02 32 44 @%File Needed by%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%Display driver All modesStandard-mode grabber Standard and real modeEnhanced-mode grabber Enhanced modeLogo display code All modesLogo display data All modesSystem font All modesFixed font All modesOEM/Terminal font Standard and real mode386 OEM/Terminal font Enhanced modeUser fonts All modes%@TE: 12 619 02 32 44 @% The profile string for the display driver must be unique from all the other display profile strings, including those listed in the Microsoft Windows 3.0 SETUP.INF file. %@NL@% Setup selects fonts by matching the aspect ratio of the display to that of the font. Setup will, however, ignore aspect ratio information for configurations using a code page other than 437. For these configurations, Setup asks MS-DOS for code page information and selects an OEM/Terminal font from the [codepages] section based on that information. Since only MS-DOS version 3.30 and higher supports the call for code page information, Setup may (depending on the MS-DOS version) rely on the %@AI@%defxlat%@AE@% profile string (under the [data] section) to get code page information. %@NL@% When preparing your distribution disks, you may choose one of the following three methods for providing .FON font files: %@NL@% ■ Include the appropriate Windows .FON font files from the Windows 3.0 retail product.%@NL@% ■ Refer in the [disks] section of your OEMSETUP.INF file to the Windows 3.0 retail disk(s) containing these files.%@NL@% ■ Distribute your own .FON font files if your display requires fonts that are tuned for a particular aspect ratio and not supported by the Windows .FON font files.%@NL@% See the "Grant of License to Use" section, in the Microsoft License Agreement that is printed on the DDK disk envelope, for information on your rights to distribute these font files should you choose to include them on your distribution disk. %@NL@% %@3@%%@CR:C6A-C0008 @%%@AB@%C.5.2 Mouse or Other Pointing Device%@AE@%%@EH@%%@NL@% The following is a generalized example of the syntax used for mice or other pointing devices along with definitions of each of the terms presented. %@NL@% [pointing.device] Profile_string = Disk:Filename,"Text_Description",Disk:Virtual_Mouse_Driver %@NL@% Where: %@NL@% %@AI@%Filename%@AE@% is the MS-DOS filename of the driver file. %@NL@% %@AI@%Text_Description%@AE@% is a character string describing the device on that line. %@NL@% %@AI@%Virtual_Mouse_Driver%@AE@% is the MS-DOS filename of the associated virtual device to be installed for running Windows in 386 enhanced mode. %@NL@% The following is an example of what a .INF file for a specific OEM mouse driver would look like. %@NL@% %@AS@% [disks] %@AS@% 1 =. ,"OEM Mouse driver disk #1"%@AE@% %@AS@% [pointing.device] %@AS@% oemmouse = 1:oemmouse.drv,"OEM Mouse driver",1:oemvmd.386%@AE@% %@3@%%@CR:C6A-C0009 @%%@AB@%C.5.3 Network Device%@AE@%%@EH@%%@NL@% The following is a generalized example of the syntax used for network devices along with definitions of each of the terms presented. %@NL@% Notice that all the fields in brackets ([ ]) are optional. All other fields are required. The quotes, commas, and colons are required as well. %@NL@% Profile_string = Disk:Filename,"Text_Description", [Disk:Help_File], [Disk:Optional_File],[WIN.INI_ Mods], [SYSTEM.INI_ Mods],[Disk:Virtual_Net_Device ...] %@NL@% Where: %@NL@% %@AI@%Filename%@AE@% is the MS-DOS filename of the driver file. %@NL@% %@AI@%Text_Description%@AE@% is a character string describing the device on that line. %@NL@% %@AI@%Help_File%@AE@% is the MS-DOS filename of an associated Help file. Setup copies this file to the Windows installation directory. This file is optional. %@NL@% %@AI@%Optional_File%@AE@% is the MS-DOS filename of an optional file, which may be necessary for your network. Setup copies this file to the Windows installation directory. This file is optional. %@NL@% %@AI@%WIN.INI_Mods%@AE@% is the name of a section within the OEMSETUP.INF file that describes modifications to be made to the user's WIN.INI file. %@NL@% %@AI@%SYSTEM.INI_Mods%@AE@% is the name of a section within the OEMSETUP.INF file that describes modifications to be made to the user's SYSTEM.INI file. %@NL@% %@AI@%Virtual_Net_Device%@AE@% is the MS-DOS filename of an associated virtual device to be installed for running Windows in 386 enhanced mode. %@NL@% The following is an example of what a .INF file for a specific network driver would look like. %@NL@% %@AS@% [disks] %@AS@% 1 = . ,"Oem Network driver disk #1"%@AE@% %@AS@% [network] %@AS@% oem_net = 1:oem.drv,"OEM Network Driver", %@AS@%1:oemnet.hlp,1:oem_app.exe,oem_winini,oem_sysini, %@AS@% 1:oem1.386,1:oem2.386%@AE@% %@AS@% [oem_winini] %@AS@% Windows,load,oem_app.exe%@AE@% %@AS@% [oem_sysini] %@AS@% 386enh,TimerCriticalSection,500%@AE@% The %@AI@%oem_sysini%@AE@% and %@AI@%oem_winini%@AE@% sections describe modifications to be made in the WIN.INI and SYSTEM.INI files. A .INI modification description section is comprised of lines that contain three fields describing a new entry to be made to the .INI file. The fields in each line are as follows: %@NL@% ■ Field 1 = .INI file section name%@NL@% ■ Field 2 = Profile string or descriptor to the lefthand side of the equal sign%@NL@% ■ Field 3 = Descriptor to the righthand side of the equal sign%@NL@% In the preceding example, Setup would add the string "load=oem_app.exe" to the [windows] section of WIN.INI. If a "load=" line already existed in WIN.INI, then Setup would add "oem_app.exe" to the righthand side of the "load=" line. %@NL@% Setup would also add the string "TimerCriticalSection=500" to the [386enh] section of SYSTEM.INI. %@NL@% %@3@%%@CR:C6A-C0010 @%%@AB@%C.5.4 Keyboard Device%@AE@%%@EH@%%@NL@% The following are generalized examples of the layout, type, and subtype syntax used for keyboard devices along with definitions of each of the terms presented. %@NL@% The layout syntax is as follows: %@NL@% Profile_string = Disk:Filename,"Text_Description" %@NL@% The type and subtype syntax is as follows : %@NL@% Type_Subtype_Profile_string = "Text_Description" %@NL@% Where: %@NL@% %@AI@%Filename%@AE@% is the MS-DOS filename of the driver file. %@NL@% %@AI@%Text_Description%@AE@% is a character string describing the device on that line. %@NL@% %@AI@%Type_Subtype_Profile_string%@AE@% is a combination of type/subtype and profile string information. The type/subtype information is represented in the form of "t##s##." The remaining characters represent the profile string information. %@NL@% The following is an example of what a .INF file for a specific keyboard driver would look like. %@NL@% %@AS@% [data] %@AS@% defkeydll = ussrdll%@AE@% %@AS@% [disks] %@AS@% 1 = . ,"Oem Keyboard disk #1"%@AE@% %@AS@% [keyboard.types] %@AS@% t3s9oem = "Russian OEM Keyboard"%@AE@% %@AS@% [keyboard.tables] %@AS@% ussrdll = 1:kbdussr.dll,"Russian"%@AE@% The keyboard type entry is unique because it involves only SYSTEM.INI settings. No driver files are copied. The keyboard type and subtype entries in SYSTEM.INI are used by the Windows 3.0 keyboard driver during boot time to determine the keyboard type. %@NL@% If the keyboard type is selected during a first time installation, Setup will also select a keyboard layout (DLL or dynamic-link library). Setup selects a keyboard DLL by looking at the data on the righthand side of the equal sign of %@AI@%defkeydll%@AE@% in the [data] section of the .INF file. Using the profile string obtained from this data, Setup selects a keyboard DLL from the [keyboard.tables] section of the .INF file. %@NL@% %@3@%%@CR:C6A-C0011 @%%@AB@%C.5.5 Machine-Dependent Configuration%@AE@%%@EH@%%@NL@% Setup installs machine-dependent configuration information for the display, keyboard, mouse, sound, comm, system, and 386 enhanced-mode BIOS devices, and their related files, other virtual devices, and special SYSTEM.INI switches. %@NL@% The following is an example of how to define a machine-dependent configuration in a .INF file by combining the information discussed in the previous sections. %@NL@% %@AS@% [data] %@AS@% defxlat = 437 %@AS@% deflang = rus%@AE@% %@AS@% [disks] %@AS@% 1 =. ,"OEM Display Driver Disk #1"%@AE@% %@AS@% [display] %@AS@% oemega = 1:ega.drv,"OEM EGA Color","133,96,72", %@AS@% 1:egacolor.gr2,1:egalogo.lgo,1:vddega.386, %@AS@% 1:ega.gr3,1:ega.sys,1:egalogo.rle%@AE@% %@AS@% [EGA.GR3] %@AS@% 1:CGA40WOA.FON,1:CGA40850.FON %@AS@% 1:CGA80WOA.FON,1:CGA80850.FON %@AS@% 1:EGA40WOA.FON,1:EGA40850.FON %@AS@% 1:EGA80WOA.FON,1:EGA80850.FON%@AE@% %@AS@% [sysfonts] %@AS@% 1:egasys.fon,"EGA (640x350) resolution System Font","133,96,72"%@AE@% %@AS@% [fixedfonts] %@AS@% 1:egafix.fon,"EGA (640x350) resolution Fixed System Font","133,96,72"%@AE@% %@AS@% [oemfonts] %@AS@% 1:egaoem.fon,"EGA (640x350) resolution Terminal Font %@AS@%(USA/Europe)","133,96,72",1%@AE@% %@AS@% [codepages] %@AS@% ; Xlat Table OEM Font description. %@AS@% 863 = 2:xlat863.bin, 2:vga863.fon, "French Canadian (863)" %@AS@% 861 = 2:xlat861.bin, 2:vga861.fon, "Icelandic (861)" %@AS@% 865 = 2:xlat865.bin, 2:vga865.fon, "Norway & Denmark (865)" %@AS@% 850 = 2:xlat850.bin, 2:vga850.fon, "International (850)" %@AS@% 860 = 2:xlat860.bin, 2:vga860.fon, "Portuguese (860)" %@AS@% 437 = , , "Standard (437)"%@AE@% %@AS@% [fonts] %@AS@% 1:HELVB.FON, "Helv 8,10,12,14,18,24 (EGA res)", "133,96,72" %@AS@% 1:COURB.FON, "Courier 10,12,15 (EGA res)", "133,96,72" %@AS@% 1:TMSRB.FON, "Tms Rmn 8,10,12,14,18,24 (EGA res)", "133,96,72" %@AS@% 1:SYMBOLB.FON, "Symbol 8,10,12,14,18,24 (EGA res)", "133,96,72" %@AS@% 1:ROMAN.FON, "Roman (All res)", "CONTINUOUSSCALING" %@AS@% 1:SCRIPT.FON, "Script (All res)", "CONTINUOUSSCALING" %@AS@% 1:MODERN.FON, "Modern (All res)", "CONTINUOUSSCALING"%@AE@% %@AS@% [pointing.device] %@AS@% oemmouse = 1:oemmouse.drv, "Mouse driver for OEM machine", 1:oemvmd.386%@AE@% %@AS@% [language] %@AS@% rus = 1:langussr.dll, "Russian"%@AE@% %@AS@% [keyboard.types] %@AS@% t4s8enha = "Super OEM 200 key Keyboard"%@AE@% %@AS@% [keyboard.drivers] %@AS@% oemkbd = 1:oemkbd.drv%@AE@% %@AS@% [system] %@AS@% oemsys = 1:oemsys.drv %@AS@% oemsnd = 1:oemsnd.drv %@AS@% oemcomm = 1:oemcom.drv%@AE@% %@AS@% [ebios] %@AS@% oemebios = 1:oemebios.386,x:*ebios%@AE@% %@AS@% [machine]%@AE@% %@AS@% "386 OEM Machine","78" %@AS@% oemsys ;1 %@AS@% oemkbd ;2 %@AS@% t4s8enha ;3 %@AS@% oemmouse ;4 %@AS@% oemega ;5 %@AS@% oemsnd ;6 %@AS@% oemcomm ;7 %@AS@% nohimemswitch ;8 %@AS@% oemebios ;9 %@AS@% "emmexclude=c700-c800" ;10 %@AS@% "device=",1:oemvxd.386" ;11 %@AS@% ;n%@AE@% Setup may or may not use all the configuration information given in the [machine] section. It does use the information provided to install the system, keyboard layout, sound, comm, and BIOS drivers. However, only if Setup is unable to detect the hardware in question, is the information for the mouse, display, and keyboard type/subtype used. %@NL@% In the preceding example, lines 10 and 11 under the [machine] section are optional. These lines are provided for the installation of special virtual devices or SYSTEM.INI [386enh] section switches. Up to six of these lines may be added as needed. %@NL@% Setup also uses code page information (obtained either by means of an MS-DOS call, on MS-DOS versions 3.30 or later, or from the %@AI@%defxlat%@AE@% profile string in the [data] section) to install a keyboard translation table. This information is obtained from the .INF file in the [codepages] section. %@NL@% Finally, Setup also selects a language driver based on the profile string given on the righthand side of the equal sign of the %@AI@%deflang%@AE@% entry in the [data] section of the .INF file. %@NL@% %@2@%%@CR:C6A-C0012 @%%@AB@%C.6 Creating .INF File Entries for Printer Drivers%@AE@%%@EH@%%@NL@% Control Panel does not require an OEMSETUP.INF file for installing a printer driver. In Windows 3.0, Control Panel only uses the OEMSETUP.INF file to install more than one set of raster (or screen) fonts and to install dependent files (e.g., Help files or a font installer). Otherwise, it is not required. %@NL@% Control Panel scans the driver files for the driver description regardless of whether an OEMSETUP.INF file is present or not. Therefore, it is important for you to properly define your driver description in the definition (.DEF) file. %@NL@% The following subsections contain information on creating .INF entries for OEMSETUP.INF and on the format of the driver's description string in the .DEF file. %@NL@% %@3@%%@CR:C6A-C0013 @%%@AB@%C.6.1 .INF File Entries%@AE@%%@EH@%%@NL@% The following are generalized examples of the syntax used for printer devices along with definitions of each of the terms presented. The colons, commas, and quotes shown in the examples are required as part of the format. The brackets ([ ]) represent optional fields, except in the case of section names. %@NL@% [io.device] Disk:Filename,"Text_Description", "Aspect_Ratio"[,"Aspect_Ratio"...] %@NL@% [io.dependent] Filename=Disk:File1[,Disk:File2...] %@NL@% Where: %@NL@% %@AI@%Filename%@AE@% is the MS-DOS filename of the driver file. It is used by Control Panel to check on whether or not the driver has been installed previously and to copy the driver from the distribution disk to the Windows ..\SYSTEM directory. This driver name is also the first element on the righthand side of the equal sign (=) in the entries under the [devices] and [PrinterPorts] sections of the WIN.INI file. %@AI@%Filename%@AE@% in the [io.dependent] section must match (case insensitive) the %@AI@%Filename%@AE@% element of the [io.device] section. %@NL@% %@AI@%Text_Description%@AE@% is displayed in the printers listbox (without the quotation marks) once the driver is installed. It is placed on the lefthand side of the equal sign-in the entries under the [devices] and [PrinterPorts] sections of the WIN.INI file. It should also match the %@AI@%Text_Description%@AE@% string in the .DEF file of the driver (see the following section for more information on the .DEF file). If there is a portion within the text description that is enclosed in square brackets, it will be used as the lefthand side of the equal sign (=) in the WIN.INI entries. The text in the brackets would normally be used to provide a "generic" name for a driver that may support many printer models (see the following example for the XYZ Ink Jet printer). %@NL@% %@AI@%Aspect_Ratio%@AE@% is information used to determine which raster (or screen) fonts to install for use by the device. Any fonts found with matching aspect values are installed in the [fonts] section of the WIN.INI file. Up to 5 different aspect ratio values may be listed. At least one must be listed. If no raster font installation is desired, use "DEVICESPECIFIC" as the only value. %@NL@% Aspect_Ratio includes the following three values: %@NL@% ■ X and Y aspect ratio%@NL@% ■ X pixels-per-inch%@NL@% ■ Y pixels-per-inch%@NL@% The three values are separated by commas and enclosed within quotation marks. For example, for a VGA display, the values would be as follows: %@NL@% "100,96,96" %@NL@% Where: %@NL@% %@AI@%100%@AE@% is the X and Y aspect ratio (1-to-1). %@NL@% %@AI@%96%@AE@% is the X (horizontal) pixels-per-inch. %@NL@% %@AI@%96%@AE@% is the Y (vertical) pixels-per-inch. %@NL@% See the description of the GDIINFO data structure in Chapter 2, "Display Drivers," in the %@AI@%Microsoft Windows Device Driver Adaptation Guide%@AE@% for more information on calculating these values. %@NL@% %@AI@%File1 %@AE@%is the MS-DOS filename of the dependent file. This might include a help (.HLP) file or a font installer that is associated with File1. You can have more than one dependent file listed, but each must have a unique name. %@NL@% See Section C.6.3, "Special Considerations," for information on how Control Panel installs font files. %@NL@% The following is an example of what a .INF file for a specific printer driver would look like. %@NL@% %@AS@% [disk] %@AS@% 1 = . ,"XYZ Printers Disk"%@AE@% %@AS@% [io.device] %@AS@% 1:XYZLASER.DRV,"XYZ Laser Printer","DEVICESPECIFIC" %@AS@% 1:XYZINK.DRV,"XYZ Ink Jet Printer [XYZ Series]", %@AS@% "100,120,120","100,96,96"%@AE@% %@AS@% [io.dependent] %@AS@% XYZLASER.DRV= 1:XYZLASER.HLP,1:SFXYZ.DLL%@AE@% If the driver is not found in the current drive, Control Panel will prompt the user for that disk. %@NL@% The following is an example of a WIN.INI file after installation. %@NL@% %@AS@% [windows] %@AS@% | %@AS@% device=XYZ Series,XYZINK,LPT1: ; Default printer, only one allowed at %@AS@% a time %@AS@% |%@AE@% %@AS@% [printerports] %@AS@% XYZ Series=XYZINK,LPT1:,15,45 %@AS@% XYZ Laser Printer=XYZLASER,LPT2:,15,45%@AE@% %@AS@% [devices] %@AS@% XYZ Series=XYZINK,LPT1: %@AS@% XYZ Laser Printer=XYZLASER,LPT2:%@AE@% %@3@%%@CR:C6A-C0014 @%%@AB@%C.6.2 Driver Description (.DEF) File%@AE@%%@EH@%%@NL@% All drivers must provide a description string in the printer driver's .DEF file. The following are a generalized example of the syntax used for printer devices and a specific example along with definitions of each of the terms presented. %@NL@% DESCRIPTION 'DDRV Text_Description:Aspect_Ratio %@NL@% DESCRIPTION 'DDRV PCL / HP LaserJet:100,300,300' %@NL@% Where: %@NL@% The character immediately following DDRV can be anything and is always ignored. %@NL@% %@AI@%DDRV%@AE@% must be capitalized. %@NL@% %@AI@%Text_Description%@AE@%, up to but not including the colon, is placed on the lefthand side of the equal sign for the entries in the [devices] and [PrinterPorts] sections of the WIN.INI file. It is also the first element on the righthand side of the "device=" line in the [windows] section. Because the righthand side of the "device=" line is parsed using commas, if %@AI@%Text_Description%@AE@% includes a comma, it will be terminated there. For example: %@NL@% DESCRIPTION 'Printer 1, Printer2:100,300,300' %@NL@% %@AI@%Printer 1%@AE@% will be used as the lefthand and righthand sides in the above mentioned sections. This will cause problems when installing with the Control Panel. If you need to list more than one printer, we suggest you use a delimiter other than a comma. For example: %@NL@% DESCRIPTION 'Printer 1/Printer2:100,300,300' %@NL@% Aspect_Ratio includes the following three values: %@NL@% ■ X and Y aspect ratio%@NL@% ■ X pixels-per-inch%@NL@% ■ Y pixels-per-inch%@NL@% The three values are separated by commas and enclosed within quotation marks. For example, for a VGA display, the values would be as follows: %@NL@% "100,96,96" %@NL@% Where: %@NL@% %@AI@%100%@AE@% is the X and Y aspect ratio (1-to-1). %@NL@% %@AI@%96%@AE@% is the X (horizontal) pixels-per-inch. %@NL@% %@AI@%96%@AE@% is the Y (vertical) pixels-per-inch. %@NL@% See the description of the GDIINFO data structure in Chapter 2, "Display Drivers," in the %@AI@%Microsoft Windows Device Driver Adaptation Guide%@AE@% for more information on calculating these values. %@NL@% %@3@%%@CR:C6A-C0015 @%%@AB@%C.6.3 Special Considerations%@AE@%%@EH@%%@NL@% Control Panel references the SETUP.INF file in the Windows ..\SYSTEM subdirectory for the raster font files. Control Panel will prompt the user as necessary for the Microsoft Windows disk defined in the SETUP.INF file if a font matching the %@AI@%Aspect_Ratio%@AE@% is available. %@NL@% If dependent files exist, the OEMSETUP.INF file needs to exist in the same directory as the driver file. %@NL@% %@2@%%@CR:C6A-C0016 @%%@AB@%C.7 Testing the Installation of Your .INF File%@AE@%%@EH@%%@NL@% Before testing, you need to create a .INF file according to the instructions given in Section C.5, "Creating .INF File Entries," and Section C.6, "Creating .INF File Entries for Printer Drivers." The .INF file and other associated driver and virtual device files should then be copied to a disk (or any other form on which you plan to distribute them). %@NL@% Depending on the type of device you support, you will need to run either Setup or Control Panel to test your .INF file. %@NL@% Setup installs display, mouse or other pointing device, network, keyboard, or machine-dependent drivers and virtual devices. %@NL@% Printer drivers are installed by Control Panel. %@NL@% %@3@%%@CR:C6A-C0017 @%%@AB@%C.7.1 Testing with Setup%@AE@%%@EH@%%@NL@% You must run the Setup utility from MS-DOS when installing additional device support (via an OEMSETUP.INF file). If you run Setup directly from Windows, you can install only device drivers and virtual devices that are supplied with Windows (i.e., defined in the SETUP.INF file). %@NL@% During debugging, we suggest you use the debugging version of the Setup utility, which is provided on the DDK disks. For more information on the error messages that might appear, see Section C.9, "Error Messages When Running Debug Setup." %@NL@% Follow these steps to install additional drivers and virtual devices with Setup: %@NL@% 1. Exit Windows.%@NL@% %@STUB@% Do not use the DOS Prompt icon in the Main Group window. Using this icon will result in an incorrect setup.%@NL@% 2. Type %@AI@%setup%@AE@% and press ENTER.%@NL@% %@STUB@% Setup lists your current Windows configuration.%@NL@% 3. Press the UP or DOWN ARROW key to select the setting you want to change and press ENTER.%@NL@% %@STUB@% A list of choices is displayed.%@NL@% 4. Scroll to the bottom of the list using the DOWN ARROW key.%@NL@% 5. Select Other and press ENTER.%@NL@% %@STUB@% Setup prompts you for the disk containing the device driver or virtual device.%@NL@% 6. Insert your distribution disk into drive A. Setup displays a list of the device drivers or virtual devices defined in the OEMSETUP.INF file on that disk. Then select the appropriate driver or virtual device and press ENTER.%@NL@% %@STUB@% Or type the pathname of the device driver or virtual device and press ENTER.%@NL@% 7. Press ENTER to complete the process.%@NL@% Be sure to install and test all the files described in your OEMSETUP.INF file. %@NL@% Setup automatically expands your files if you choose to use the COMPRESS.EXE utility supplied in the SDK to compress your files. Notice, however, that OEMSETUP.INF should %@AI@%not%@AE@% be compressed. %@NL@% %@3@%%@CR:C6A-C0018 @%%@AB@%C.7.2 Testing with Control Panel%@AE@%%@EH@%%@NL@% To test your OEMSETUP.INF file and the DESCRIPTION in your printer driver's .DEF file, you need to run Control Panel. %@NL@% Additional printer drivers are installed the same way you would install a driver supplied by Windows. Instead of selecting a printer from the list (of those defined in the SETUP.INF file) to install, you would select Unlisted Printer from the bottom of the list. %@NL@% Follow these steps to install an additional printer driver: %@NL@% 1. Run Control Panel and select the Printers Icon.%@NL@% 2. Choose the Add Printer button.%@NL@% 3. Select Unlisted Printer from the bottom of the printers list.%@NL@% 4. Choose the Install button.%@NL@% 5. Insert your distribution disk, if necessary.%@NL@% 6. Select the appropriate drive and directory path.%@NL@% 7. Select OK.%@NL@% 8. Select the appropriate driver filename from the Driver Files list.%@NL@% 9. Select OK.%@NL@% At this point, Control Panel looks for OEMSETUP.INF. If found, Control Panel will install all the raster font and associated files defined in the [io.dependent] section (if applicable to the driver file that you selected). %@NL@% If OEMSETUP.INF does not exist on this disk or in the specified directory, Control Panel inspects the DESCRIPTION line within the driver and copies the raster fonts that match exactly the values defined there. %@NL@% Control Panel expands your files automatically if you choose to use the COMPRESS.EXE utility supplied in the SDK to compress your files. Notice, however, that the OEMSETUP.INF file should %@AI@%not%@AE@% be compressed. %@NL@% %@2@%%@CR:C6A-C0019 @%%@AB@%C.8 Informing Microsoft About the Availability of Your Driver and/or%@EH@% %@AB@%Virtual Device%@AE@%%@NL@% Microsoft publishes the %@AI@%Microsoft Windows Software and Hardware Directory%@AE@%. This publication is available to both developers and Windows users. The directory contains information on the following: %@NL@% ■ Windows-compatible applications%@NL@% ■ Windows device drivers%@NL@% ■ Windows virtual devices%@NL@% ■ Windows-based consultants%@NL@% Included in this package is a %@AI@%Microsoft Windows Directory Survey%@AE@%. If you want to publish information in the directory about your device drivers and/or virtual devices, please complete this survey and return it to the address listed on the survey form. There is no fee for taking advantage of this opportunity to tell Microsoft Windows 3.0 users all about the support for your product. %@NL@% %@2@%%@CR:C6A-C0020 @%%@AB@%C.9 Error Messages When Running Debug Setup%@AE@%%@EH@%%@NL@% When using the debug version of Setup that is provided on the DDK disks, you may see several error messages regarding possible Setup assertion failures. The following list provides the error message numbers and a brief description of each along with possible solutions: %@NL@% %@TH: 37 2307 02 34 44 @%Message Description%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%SUINF.C:68: Setup could not find a suitable (correct aspect ratio) system font for the display driver selected. Ensure that a matching aspect ratio font is available in the [sysfonts] section of the .INF file.SUINF.C:77: Setup could not find a suitable (correct aspect ratio) OEM font for the display driver selected. Ensure that a matching aspect ratio font is available in the [oemfonts] section of the .INF file.SUINF.C:80: Setup could not find a suitable (correct aspect ratio) OEM font for the display driver selected. Ensure that a matching aspect ratio font is available in the [oemfonts] section of the .INF file.SUINF.C:84: Setup could not find a suitable (correct aspect ratio) fixed font for the display driver selected. Ensure that a matching aspect ratio font is available in the [fixedfonts] section of the .INF file.SUINF.C:165: Setup detected a machine for which it could not find a machine entry in the [machine] section of the .INF file. SUUTIL.C:451: Setup cannot find a disk entry in the [disks] section of SETUP.INF for a logical disk ID given in the .INF file. Check to see that all logical disk ID values have a corresponding entry in the [disks] section of the .INF file.%@TE: 37 2307 02 34 44 @% %@CR:C6A-D0001 @%%@1@%%@AB@%Appendix D Windows INT 2FH API%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% Enhanced Windows 3.0 supports an application program interface (API) designed to enable MS-DOS device drivers, TSR programs, and application programs to take full advantage of the multitasking abilities of the enhanced Windows environment. %@NL@% Most application program writers will use the interface that releases the current virtual machine's time-slice. This API allows enhanced Windows and OS/2 to multitask non-Windows specific MS-DOS applications more efficiently. The Release Time Slice API should be used by applications even if they are not running under enhanced Windows. This allows OS/2 to detect idleness in MS-DOS applications. OS/2 will recognize the enhanced Windows release time-slice call but it does not support other enhanced Windows APIs. %@NL@% The Microsoft 80286 DOS extender will issue the initialization and exit INT 2FH API calls so that real mode software can free extended memory through XMS. The 286 DOS extender also supports the Int 31h service detection Int 2FH API call. %@NL@% Other APIs are used by MS-DOS device drivers and TSRs that have enhanced Windows specific requirements. %@NL@% %@2@%%@CR:C6A-D0002 @%%@AB@%D.1 Call-In Interfaces%@AE@%%@EH@%%@NL@% Call-in interfaces are APIs that real mode MS-DOS device drivers, TSRs, and applications use to communicate with enhanced Windows. These include: %@NL@% ■ Get Windows version%@NL@% ■ Get virtual machine ID%@NL@% ■ Begin critical section%@NL@% ■ End critical section%@NL@% ■ Release time slice%@NL@% ■ Get device API entry point%@NL@% ■ Switch VMs and callback %@NL@% %@3@%%@CR:C6A-D0003 @%%@AB@%D.1.1 Enhanced Windows Installation Check (AX=1600H)%@AE@%%@EH@%%@NL@% This API call is valid under all versions of enhanced Windows. If a program intends to use a enhanced Windows API, it must first make sure that the enhanced Windows environment is running. To do this, issue: %@NL@% %@AS@% mov ax, 1600h %@AS@% int 2Fh %@AS@% test al, 7Fh %@AS@% jz Not_Running_Win386 %@AS@% (Otherwise enhanced Windows is running) %@AS@% cmp al, 1 %@AS@% je Running_Ver_2xx %@AS@% cmp al, -1 %@AS@% je Running_Ver_2xx %@AS@% (Else al contains major version, AH contains minor)%@AE@% If 0 or 80H is returned in AL, enhanced Windows is not running. Any other value means that enhanced Windows is running. A value of 1 or -1 (0FFH) indicates that the application is running under enhanced Windows version 2.0 or 3.0. Otherwise, %@AB@%AL%@AE@% will contain the major version number (3 or higher) and %@AB@%AH%@AE@% will contain the minor version number. The table below summarizes the possible return values: %@NL@% %@TH: 14 517 02 15 51 12 @%Value in AL Meaning%@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@%00H Enhanced Windows 3.x or Windows/386 version 2.xx is not running80H Enhanced Windows 3.x or Windows/386 version 2.xx is not running01H Windows/386 version 2.xx runningFFH Windows/386 version 2.xx runningAnything else AL = Major version number AH = Minor%@TE: 14 517 02 15 51 12 @% %@3@%%@CR:C6A-D0004 @%%@AB@%D.1.2 Releasing Current Virtual Machine's Time-Slice (AX=1680h)%@AE@%%@EH@%%@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AB@%NOTE %@AE@%%@AI@% %@AI@%%@AI@%This API should be used only by non-Windows specific applications. Windows %@AI@%programs should yield their time by calling the WaitMessage%@AI@% function.%@AE@%%@AE@% %@AE@%────────────────────────────────────────────────────────────────────────────%@NL@% This API is used by programs to indicate that the program is idle (usually waiting for the user to type something). By issuing this interrupt, applications prevent enhanced Windows from wasting time running a program that is essentially doing nothing. This allows other programs to use the time. %@NL@% Programs should always use this API even if they are not Windows-specific applications and even if they are not currently running under Windows in 386 enhanced mode. This allows OS/2 to detect idleness even though it does not support the complete enhanced Windows API. The only check you should make before issuing the API call is to make sure that the INT 2FH interrupt vector is not zero. %@NL@% Sample code: %@NL@% %@AS@% mov ax, 352Fh %@AS@% int 21h ; DOS get vector 2Fh %@AS@% mov ax, es ; ES:BX = Vector %@AS@% or ax, bx ; Q: Is it zero? %@AS@% jz Skip_Idle_Call ; Y: Skip this %@AS@% mov ax, 1680h ; N: Tell Win %@AS@% int 2Fh ; we're idle. %@AS@% Skip_Idle_Call:%@AE@% If the API is supported, the INT 2FH will return with %@AB@%AL%@AE@%=0, otherwise it will return with AL unchanged (80h). Usually application programs will not be interested in the return value. %@NL@% Note that when an application uses this API it will continue to run occasionally so your program should re-issue the interrupt in the program's idle loop. In other words, this API does NOT block your application until a key is pressed. %@NL@% %@3@%%@CR:C6A-D0005 @%%@AB@%D.1.3 Begin Critical Section (AX=1681h)%@AE@%%@EH@%%@NL@% If an MS-DOS device driver or TSR needs to prevent a task-switch from occurring, it should call this interface. When a virtual machine is in a critical section, no other task will be allowed to run except to service hardware interrupts. For this reason, the critical section should be freed (using the end critical section API) as soon as possible. %@NL@% %@3@%%@CR:C6A-D0006 @%%@AB@%D.1.4 End Critical Section (AX=1682h)%@AE@%%@EH@%%@NL@% This API must be called to release ownership of the critical section that was claimed using the Begin Critical Section API. Every call to Begin Critical Section must be followed by a matching call to End Critical Section. %@NL@% %@3@%%@CR:C6A-D0007 @%%@AB@%D.1.5 Get Current Virtual Machine ID (AX=1683h)%@AE@%%@EH@%%@NL@% This API returns with %@AB@%BX%@AE@% = Current virtual machine ID. The ID is unique for each virtual machine. Although Windows currently runs in VM 1, your software should not rely on this. Also, if a VM is destroyed, its ID may be reused by another new virtual machine. Be sure to treat VM IDs as a word (not a byte). An ID of 0 will %@AI@%never%@AE@% be returned. %@NL@% %@3@%%@CR:C6A-D0008 @%%@AB@%D.1.6 Get Device API Entry Point (AX=1684h)%@AE@%%@EH@%%@NL@% Some VxDs (enhanced Windows device drivers) provide a set of services that application programs can access. For example, the Virtual Display Device provides services that the Windows old application program uses to display MS-DOS programs in a window. Any VxD can support an API for MS-DOS applications. Your program must issue an INT 2FH with %@AB@%AX%@AE@%=1684h and %@AB@%BX%@AE@% = Virtual device ID. The entry point address will be returned in %@AB@%ES:DI%@AE@%. Your application must execute a FAR CALL to this address to call the virtual device. If the value returned is 0:0 then the device does not support an API, otherwise %@AB@%ES:DI%@AE@% is the address of the procedure to call. You should either make sure your application is running on version 3.0 or zero %@AB@%ES%@AE@% and %@AB@%DI%@AE@% before using this API. %@NL@% %@AS@% xor di, di ; * Only necessary if you have * %@AS@% mov es, di ; * not checked for Win ver 3.0 * %@AS@% mov ax, 1684h %@AS@% mov bx, My_Device_ID %@AS@% int 2Fh %@AS@% mov ax, es %@AS@% or ax, di %@AS@% jz API_Is_Not_Supported %@AS@% (else API address in ES:DI)%@AE@% The definition of a device API is specified by the virtual device driver. Refer to individual virtual device documentation for details. %@NL@% %@3@%%@CR:C6A-D0009 @%%@AB@%D.1.7 Switch VMs and CallBack (AX=1685h)%@AE@%%@EH@%%@NL@% Some MS-DOS devices, such as networks, need to perform functions in a specific virtual machine. These devices can use this interface to force the appropriate virtual machine to be installed so that they can modify the VM's data. Refer to Chapter 24, "Primary Scheduler Services," for information on appropriate priority boosts. %@NL@% Entry: %@AB@%AX%@AE@% = 1685h %@AB@% BX %@AE@%= VM ID of virtual machine to switch to %@AB@% CX%@AE@% = Flags Bit 0 = 1 if wait until interrupts enabled Bit 1 = 1 if wait until critical section unowned All other bits must be 0 %@AB@% DX:SI%@AE@% = Priority boost (%@AB@%DX%@AE@%=High word, %@AB@%SI%@AE@%=Low word) %@AB@% ES:DI%@AE@% = %@AB@%CS:IP%@AE@% of procedure to call %@NL@% Exit: %@NL@% %@AS@% If carry set then %@AS@% AX = Error code %@AS@% else %@AS@% Event will be called or has been called already.%@AE@% Error codes: 1 = Invalid VM ID 2 = Invalid priority boost 3 = Invalid flags %@NL@% Callback procedure: Must save all registers modified Must IRET to caller Priority will remain boosted until procedure irets %@NL@% %@3@%%@CR:C6A-D0010 @%%@AB@%D.1.8 Detect Presence of INT 31H Services (AX=1686h)%@AE@%%@EH@%%@NL@% If a program needs to detect the presence of the INT 31H protected mode API, it can use this INT 2FH. Note that this particular API is also supported by the Microsoft 80286 DOS extender for protected mode Windows. INT 31H services are only supported for protected mode programs. %@NL@% %@3@%%@AB@%Entry%@AE@%%@EH@%%@NL@% %@AB@%AX%@AE@% = 1686h %@NL@% %@3@%%@AB@%Exit%@AE@%%@EH@%%@NL@% If AX = 0 then INT 31H services are available and can be called else (AX 0) zINT 31H services are not available %@NL@% %@2@%%@CR:C6A-D0011 @%%@AB@%D.2 Call Out Interfaces%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% Enhanced Windows will broadcast INT 2FH to real mode device drivers and TSRs to inform them of various activities. These can be used to load enhanced Windows installable devices, free extended memory, instance per-VM data structures, and turn on or off various device services or features. For example, SmartDrv can free extended memory for enhanced Windows to use when the initialization call is made and then reclaim it when it receives the termination call. MS-DOS devices such as networks can inform the enhanced Windows loader to load a special protected mode installable device that cooperates with the real mode network device driver. %@NL@% %@3@%%@AB@%D.2.1 Enhanced Windows and 286 DOS Extender Initialization (AX=1605h)%@AE@%%@EH@%%@NL@% The enhanced Windows loader and the Microsoft 286 DOS extender will broadcast an INT 2FH with the following parameters: %@NL@% %@AB@%AX%@AE@% = 1605h %@AB@%ES:BX%@AE@% = 0:0 %@AB@%DS:SI%@AE@% = 0:0 %@AB@%CX%@AE@% = 0 %@AB@%DX%@AE@% = Flags Bit 0 = 0 if enhanced Windows initialization 1 if Microsoft 286 DOS extender initialization All other bits reserved and undefined. %@AB@%DI%@AE@% = Version #: major version in upper byte, minor version in lower byte %@NL@% Any MS-DOS device driver or TSR can hook Int 2FH and watch for this particular broadcast. When this broadcast is received, the real mode software can inform enhanced Windows or the 286 DOS extender that it should not load by returning with %@AB@%CX%@AE@% 0. The TSR or device that fails the initialization should print an error message so the user can take appropriate steps to reconfigure the machine. Enhanced Windows and the Microsoft DOS extender will not print an error message─they will only issue the termination API call and return to MS-DOS. %@NL@% If it is OK for enhanced Windows or the DOS extender to load, the real mode software should not modify CX and may want to do one or more of the following: %@NL@% ■ Release extended memory through the XMS interface.%@NL@% ■ Switch back to real mode (if currently in virtual 8086 mode) or set %@AB@%DS:SI%@AE@% to the Virtual 8086 mode enable/disable routine address.%@NL@% ■ Load an installable device (enhanced Windows only).%@NL@% ■ Instance private data structures (enhanced Windows only).%@NL@% The DOS extender only pays attention to the value returned in %@AB@%CX%@AE@%. It will not instance any data or load enhanced Windows installable device drivers. The DOS extender only issues this call so that extended memory can be released and the machine can be placed in real mode if it is currently in virtual 8086 mode. %@NL@% Instance data refers to data in a TSR or MS-DOS device driver that must have a private copy in each VM. Normally, all TSRs and devices loaded before enhanced Windows is run are considered global memory. That means that all of the data is shared between virtual machines. However, there are some pieces of data that actually should be maintained on a per-VM basis. For example, the MS-DOS command line buffer needs to be instanced (this is done automatically by enhanced Windows). However, TSRs such as the MS-DOS command line editors will not function properly unless they identify the data that needs to be instanced. %@NL@% The first two options (release extended memory, or switch from V86 to real mode) are up to the device to handle on its own. The last options require returning a pointer to a list of structures to load. Your INT 2FH hook must first chain to the next INT 2FH handler with all registers unmodified. When the handler returns you must take the %@AB@%ES:BX %@AE@%value returned and place it in the following data structure in the %@AI@%Next_Dev_Ptr%@AE@% field: %@NL@% %@AS@% Win386_Startup_Info_Struc STRUC %@AS@% SIS_Version db 3, 0 %@AS@% SIS_Next_Dev_Ptr dd ? %@AS@% SIS_Virt_Dev_File_Ptr dd 0 %@AS@% SIS_Reference_Data dd ? %@AS@% SIS_Instance_Data_Ptr dd 0 %@AS@% Win386_Startup_Info_Struc ENDS%@AE@% Your software must point %@AB@%ES:BX%@AE@% at this structure and return. This allows multiple enhanced Windows installable devices to be loaded through a single INT 2FH call. %@NL@% The %@AB@%SIS_Version%@AE@% field is used by enhanced Windows to determine the size of the structure. This field should always contain 3, 0 to indicate that it is version 3.0. %@NL@% The %@AB@%SIS_Next_Dev_Ptr%@AE@% points to the next structure in the list. This field must be filled in with the returned %@AB@%ES:BX%@AE@% after your software chains to the next INT 2FH handler. %@NL@% %@AB@%SIS_Virt_Dev_File_Ptr%@AE@% is a pointer to an ASCIIZ string that contains the name of a enhanced Windows virtual device file. MS-DOS devices such as networks use this to force a special enhanced Windows protected mode virtual device to be loaded. If this field is zero, then no device will be loaded. %@NL@% The %@AB@%SIS_Reference_Data%@AE@% is only used when the %@AB@%SIS_Virt_Dev_File_Ptr%@AE@% is non-zero. This DWORD will be passed to the virtual device when it is initialized. The DWORD can contain any value. Often it contains a pointer to some device specific data structure. %@NL@% The %@AB@%SIS_Instance_Data_Ptr%@AE@% field points to a list of data to be instanced. If the field is zero, then no data will be instanced. Each entry in the list has the following structure: %@NL@% %@AS@% Instance_Item_Struc STRUC %@AS@% IIS_Ptr dd ? %@AS@% IIS_Size dw ? %@AS@% Instance_Item_Struc ENDS%@AE@% The list is terminated with a zero DWORD. %@NL@% Your handler must preserve all registers except the values returned in %@AB@%ES, %@AB@%BX,%@AE@% and %@AB@%CX%@AE@%. It must also preserve %@AB@%DS%@AE@% and %@AB@%SI%@AE@% unless it explicitly changes them to return the address of the virtual 8086 mode enable/disable routine. Remember, any device that returns with %@AB@%CX%@AE@% 0 will force enhanced Windows or the 286 DOS extender to abort. If the load is aborted, the termination INT 2FH will be issued immediately. %@NL@% Enhanced Windows supports loading with a virtual mode program such as an EMM "LIMulator" running provided that the program supports a virtual 8086 mode enable/disable callback routine. The address of the routine must be returned in %@AB@%DS:SI%@AE@%. If your TSR or device driver sets this return parameter, it should first check to make sure that %@AB@%DS%@AE@% and%@AB@% SI%@AE@% are both zero. If they are non-zero, then fail the initialization by setting CX=non-zero. Notice that the Microsoft 286 DOS extender will not call this routine. Therefore, you must either set the processor into real mode during the initialization INT 2FH or set CX=non-zero to abort the load. %@NL@% The virtual mode enable/disable callback will be called with %@AB@%AX%@AE@%=0 to disable V86 mode (return to real mode) and %@AB@%AX%@AE@%=1 to re-enable V86 mode. Just before attempting to enter protected mode enhanced Windows will disable V86 mode after every VxD has been loaded. It will call the enable/disable routine with %@AB@%AX%@AE@%=0 and with interrupts disabled. Do not enable interrupts in your routine unless the routine will return with Carry set to indicate failure. After enhanced Windows exits, it will call the enable/disable routine in real mode with %@AB@%AX%@AE@%=1 and with interrupts disabled to set the machine back into V86 mode. %@NL@% The enable/disable routine will be called with a FAR return frame. It must return with the carry flag clear to indicate success or Carry set to indicate an error. If an error is returned from the disable call, then enhanced Windows will abort. The error return from the enable V86 call will be ignored and the machine will be left in real mode. It is the responsibility of the enable/disable routine to print an error message. %@NL@% %@3@%%@AB@%D.2.2 Enhanced Windows and 286 DOS Extender Exit (AX=1606h)%@AE@%%@EH@%%@NL@% When enhanced Windows or the 286 DOS extender terminates, it will broadcast an INT 2FH with the following parameters: %@NL@% %@AB@%AX%@AE@% = 1606H. %@AB@%DX%@AE@% = Flags Bit 0 = 0 if enhanced Windows exit 1 if Microsoft 286 DOS extender exit All other bits reserved and undefined. %@NL@% This call will be issued in real mode. It allows devices and TSRs to undo anything they did when enhanced Windows or the DOS extender initialized. For example, a device like SmartDrv may re-allocate extended memory that it released during initialization. %@NL@% If the initialization broadcast fails (returns with %@AB@%CX%@AE@% 0) then this broadcast will be issued immediately. %@NL@% %@3@%%@AB@%D.2.3 Device Call Out API (AX=1607h)%@AE@%%@EH@%%@NL@% This API is, in reality, more of a convention than an API. It specifies a standard mechanism for enhanced Windows virtual devices to talk to MS-DOS device drivers and TSRs. %@NL@% Some devices need to ask real-mode MS-DOS software for information. For example, the Virtual NetBIOS mapper VxD will issue an INT 2FH to determine if a network supports an extended NetBIOS API. The standard device call out will have %@AB@%AX%@AE@%=1607H and %@AB@%BX%@AE@%=Device ID. As with the device API entry point call-in interface, the details of the interface are specified by the device that issues the interrupt. %@NL@% This interrupt may be issued at any time, either in real mode or after enhanced Windows has begun execution. %@NL@% %@3@%%@AB@%D.2.4 Enhanced Windows Initialization Complete (AX=1608h)%@AE@%%@EH@%%@NL@% This API call is made by enhanced Windows after all the installable devices have initialized. At this point, it is still possible to identify instance data and perform other functions that are restricted to enhanced Windows initialization time. The enhanced Windows device initialization phase is complete, so it is possible to call enhanced Windows device API entry points. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AU@%WARNING%@AE@% Real mode software such as a TSR or DOS device driver may be called after the enhanced Windows initialization call and before this API call is made. It is the responsibility of the real mode software to detect and properly handle this situation. ────────────────────────────────────────────────────────────────────────────%@NL@% %@3@%%@AB@%D.2.5 Enhanced Windows Begin Exit (AX=1609H)%@AE@%%@EH@%%@NL@% This API call is issued at the beginning of a normal Enhanced Windows exit sequence. It is sent at the start of the %@AB@%Sys_VM_Terminate%@AE@% device control call phase. All VxDs still exist so calls to device API entry points are still valid. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AU@%WARNING%@AE@% This call will not be made in the event of a fatal system crash. Also, real mode code may be executed after this API call has been made and before enhanced Windows has returned to real mode. It is the responsibility of the real mode software to detect and properly handle these situations. ────────────────────────────────────────────────────────────────────────────%@NL@% %@2@%%@CR:C6A-D0012 @%%@AB@%D.3 Windows/386 Version 2.xx API Compatibility%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────────%@AE@%%@NL@% The release of Windows/386 (version 2.xx) had a limited Application Program Interface that was defined to help support real mode MS-DOS device drivers such as networks. The 2.xx API allows MS-DOS programs to: %@NL@% ■ Determine if Windows/386 or enhanced Windows (version 3.0) is running%@NL@% ■ Get the ID of the current Virtual Machine%@NL@% ■ Enter and leave a global critical section%@NL@% The APIs used under version 2.xx are fairly complex and inflexible. We suggest that, unless your application or device driver absolutely needs to run under version 2.xx, you ignore all version 2.xx APIs and use the 3.0 APIs instead. %@NL@% %@3@%%@AB@%D.3.1 Installation Check%@AE@%%@EH@%%@NL@% To test for Windows/386 version 2.xx, you should issue an Int 2fh with %@AB@%AX%@AE@%=1600h. Refer to Windows Installation Check for complete documentation for this API call. %@NL@% %@3@%%@AB@%D.3.2 Determining the Current Virtual Machine (Get VM ID)%@AE@%%@EH@%%@NL@% Once the software has determined that it is running under Windows/386 version 2.xx, it must make another call to get the API procedure address. To do this, issue: %@NL@% %@AS@% mov ax, 1602h %@AS@% int 2fh %@AS@% (ES:DI -> Windows/386 API procedure)%@AE@% The API procedure is the same address for every virtual machine, so you will need to issue this call only once (although you can issue it as often as you want). %@NL@% To get the ID of the current virtual machine %@AI@%jump%@AE@% to the Windows/386 API procedure with %@AB@%AX%@AE@% = 0 and %@AB@%ES:DI%@AE@% - the address to return to. %@NL@% Sample code: %@NL@% %@AS@% mov di, cs %@AS@% mov es, di %@AS@% mov di, OFFSET Win386_AIP_Return %@AS@% xor ax, ax ; AX = 0 %@AS@% jmp [Win386_API_Proc] %@AS@% Win386_API_Return: %@AS@% (Now BX contains the current VM ID)%@AE@% Note that you must place the return address in %@AB@%ES:DI%@AE@% and JUMP to the API procedure. When enhanced Windows returns control to your program it will return to %@AB@%ES:DI%@AE@%. %@NL@% This interface is supported under version 3.0 only for compatibility reasons. New MS-DOS devices or applications should use the version 3.0 interface. %@NL@% %@3@%%@AB@%D.3.3 Critical Section Handling%@AE@%%@EH@%%@NL@% Windows/386 version 2.xx does not support API calls to enter and leave a critical section. However, by incrementing and decrementing a special DOS critical section counter called the InDOS flag, you can force the current virtual machine into a critical section. Incrementing InDOS is not sufficient to enter a critical section in version 3.0. You will need to make an API call first and then, if it fails, increment the InDOS flag. %@NL@% To get the address of the InDOS flag, issue the following MS-DOS call (documented in %@AI@%The MS-DOS Encyclopedia%@AE@% ): %@NL@% %@AS@% mov ah, 34h %@AS@% int 21h %@AS@% (ES:BX -> InDOS flag)%@AE@% The InDOS flag is a byte within the MS-DOS kernel. The value in InDOS is incremented when MS-DOS begins execution of an Interrupt 21H and decremented when MS-DOS's processing of that function has completed. When you increment the byte, current versions of enhanced Windows will not switch to another virtual machine. Therefore, to enter a critical section, you need to increment the byte and to leave a critical section you should decrement the InDOS flag. %@NL@% ────────────────────────────────────────────────────────────────────────────%@NL@% %@AU@%WARNING%@AE@% You must make sure your code never decrements the InDOS flag through zero. MS-DOS will set the InDOS flag to zero under some error conditions (for example, the user types CTRL+C). Also, even if the InDOS flag is non-zero, an Int 28H may cause the VM to be rescheduled. ────────────────────────────────────────────────────────────────────────────%@NL@% For versions 3.xx and greater of Windows you will need to issue an INT 2FH %@AB@%AX%@AE@% = 1681H to begin a critical section and %@AB@%AX%@AE@% = 1682H to end a critical section. Note that if a program enters the critical section N times, it must also issue the end critical section interrupt N times before the critical section is actually released. Thus, nested begin/end critical section calls are valid. Both of these APIs will zero the %@AB@%AL%@AE@% register to indicate that the critical section API is supported. You should %@AI@%not%@AE@% increment and decrement InDOS under versions of Windows that support these API calls. %@NL@% Unlike the InDOS critical section method, an INT 28H will%@AI@% not %@AE@%reschedule the current virtual machine. The only way a task switch will occur is by completely releasing the critical section. %@NL@% Since you need to call the Windows API or increment the InDOS flag you will probably want to write two procedures similar to the following: %@NL@% %@AS@% Begin_Win_Critical_Section: %@AS@% push ax %@AS@% mov ax, 1681h %@AS@% int 2Fh %@AS@% test al, al %@AS@% jz BCS_Quick_Exit %@AS@% push es %@AS@% les ax, [InDOS_Address] %@AS@% inc BYTE PTR es:[ax] %@AS@% pop es %@AS@% BCS_Quick_Exit: %@AS@% pop ax %@AS@% ret %@AS@% %@AS@% End_Win_Critical_Section: %@AS@% push ax %@AS@% mov ax, 1682h %@AS@% int 2Fh %@AS@% test al, al %@AS@% jz ECS_Quick_Exit %@AS@% push es %@AS@% les ax, [InDOS_Address] %@AS@% cmp BYTE PTR es:[ax], 0 %@AS@% je (Error handler routine) %@AS@% dec BYTE PTR es:[ax] %@AS@% pop es %@AS@% ECS_Quick_Exit: %@AS@% pop ax %@AS@% ret %@AE@% %@AS@% %@AE@% %@CR:GeneralIndex@% %@1@%%@AB@%INDEX%@AE@%%@EH@%%@NL@% %@AB@%────────────────────────────────────────────────────────────────────────── %@2@%%@AB@% A%@AE@%%@EH@%%@NL@% ADDHDR, defined%@BO: 17bcf@% AddInstanceItem service%@BO: 4bee4@% AdjustInitEndPt function%@BO: 23530@% Adjust_Execution_Time service%@BO: 6734f@% Adjust_Exec_Priority service%@BO: 60bf8@% Allocate_Device_CB_Area service%@BO: 28edf@% Allocate_GDT_Selector service%@BO: 2fdf7@% Allocate_Global_V86_Data_Area service%@BO: 29cc5@% Allocate_LDT_Selector service%@BO: 30824@% Allocate_PM_Call_Back service%@BO: 5d5cf@% Allocate_Temp_V86_Data_Area service%@BO: 2bcb5@% Allocate_V86_Call_Back service%@BO: 5d5cf@% API translation%@BO: 964ee@% %@2@%%@AB@% B%@AE@%%@EH@%%@NL@% BeginSelection function%@BO: 23919@% Begin_Critical_Section service%@BO: 61895@% Begin_Nest_Exec service%@BO: 57b24@% Begin_Nest_V86_Exec service%@BO: 586ec@% Begin_Reentrant_Execution service%@BO: 7f1a0@% Begin_Use_Locked_PM_Stack service%@BO: 58b70@% Break Point and Callback services Allocate_PM_Call_Back%@BO: 5d5cf@% Allocate_V86_Call_Back%@BO: 5d5cf@% Call_When_Idle%@BO: 5dd07@% Call_When_VM_Returns%@BO: 5e379@% Install_V86_Break_Point%@BO: 5ed0b@% Remove_V86_Break_Point%@BO: 5fa54@% BuildDescDWORDs service%@BO: 319f1@% Build_Int_Stack_Frame service%@BO: 528fa@% %@2@%%@AB@% C%@AE@%%@EH@%%@NL@% Callback procedures%@BO: fac1@% Calling conventions, defined%@BO: 14100@% Call_Global_Event service%@BO: 6aa5d@% Call_Priority_VM_Event service%@BO: 6ae98@% Call_VM_Event service%@BO: 6c204@% Call_When_Idle service%@BO: 52df0@%%@BO: 5dd07@%%@BO: 67a21@% Call_When_Not_Critical service%@BO: 624c1@% Call_When_Task_Switched service%@BO: 62a34@% Call_When_VM_Ints_Enabled service%@BO: 534c7@% Call_When_VM_Returns service%@BO: 5e379@% Cancel_Global_Event service%@BO: 6c66b@% Cancel_Priority_VM_Event service%@BO: 6cc11@% Cancel_Time_Out service%@BO: 6e834@% Cancel_VM_Event service%@BO: 6d33b@% CB_High_Linear service%@BO: 4e22c@% CheckGRBVersion function%@BO: 255fd@% Claim_Critical_Section service%@BO: 62f7e@% ConsSelecRec function%@BO: 23b5c@% Convert_Boolean_String service%@BO: 75bdc@% Convert_Decimal_String service%@BO: 75fe0@% Convert_Fixed_Point_String service%@BO: 76526@% Convert_Hex_String service%@BO: 76ad5@% CopyPageTable service%@BO: 363e2@% Crash_Cur_VM service%@BO: 7e09d@% Create_Semaphore service%@BO: 632a5@% CursorOff function%@BO: 25824@% CursorOn function%@BO: 259d5@% CursorPosit function%@BO: 25b90@% %@2@%%@AB@% D%@AE@%%@EH@%%@NL@% DCP. See Device control procedure%@BO: bfc4@% DDB. See Device descriptor block%@BO: c377@% DeAssign_Device_V86_Pages service%@BO: 2e286@% Destroy_Semaphore service%@BO: 633ca@% Device control procedure, defined%@BO: bfc4@% Device descriptor block, defined%@BO: c377@% Disable_Global_Trapping service%@BO: 503d0@% Disable_Local_Trapping service%@BO: 506fa@% Disable_VM_Ints service%@BO: 539be@% DPMI. See DOS protected mode interface%@BO: f1f1@% %@2@%%@AB@% E%@AE@%%@EH@%%@NL@% Enable_Global_Trapping service%@BO: 503d0@% Enable_Local_Trapping service%@BO: 506fa@% Enable_VM_Ints service%@BO: 53beb@% EndSelection function%@BO: 23d73@% End_Critical_Section service%@BO: 63df2@% End_Crit_And_Suspend service%@BO: 634f0@% End_Nest_Exec service%@BO: 59092@% End_Reentrant_Execution service%@BO: 7f662@% End_Use_Locked_PM_Stack service%@BO: 59525@% Error Condition services Crash_Cur_VM%@BO: 7e0b1@% Fatal_Error_Handler%@BO: 7e378@% Fatal_Memory_Error%@BO: 7e991@% Event services Call_Global_Event%@BO: 6aa71@% Call_Priority_VM_Event%@BO: 6ae98@% Call_VM_Events%@BO: 6c218@% Cancel_Global_Event%@BO: 6c66b@% Cancel_Priority_VM_Event%@BO: 6cc11@% Cancel_VM_Event%@BO: 6d34f@% Hook_NMI_Event%@BO: 6d9b1@% Schedule_Global_Event%@BO: 6dc61@% Schedule_VM_Event%@BO: 6e001@% Event defined%@BO: ce2a@%%@BO: 6a244@% Exec_Int service%@BO: 5986e@% Exec_VxD_Int service%@BO: 59cb7@% %@2@%%@AB@% F%@AE@%%@EH@%%@NL@% Fatal_Error_Handler service%@BO: 7e378@% Fatal_Memory_Error service%@BO: 7e991@% Free_GDT_Selector service%@BO: 32374@% Free_LDT_Selector service%@BO: 32709@% Free_Temp_V86_Data_Area service%@BO: 2c73b@% %@2@%%@AB@% G%@AE@%%@EH@%%@NL@% GetAppFlatDSAlias service%@BO: 44bb2@% GetDemandPageInfo service%@BO: 36fd0@% GetDisplayUpd function%@BO: 25015@% GetDOSVectors service%@BO: 77b5e@% GetFirstV86Page service%@BO: 44869@% GetFontList function%@BO: 25daa@% GetFreePageCount service%@BO: 37896@% GetNulPageHandle service%@BO: 44a7a@% GetSetPageOutCount service%@BO: 38022@% GetSet_HMA_Info service%@BO: 7479d@% GetSysPageCount service%@BO: 3868b@% GetVMPageCount service%@BO: 38983@% Get_Config_Directory service%@BO: 76f31@% Get_Crit_Section_Status service%@BO: 64124@% Get_Cur_VM_Handle service%@BO: 7383b@% Get_Device_V86_Pages_Array service%@BO: 2e960@% Get_Environment_String service%@BO: 77237@% Get_Execution_Focus service%@BO: 680fe@% Get_Exec_Path service%@BO: 777c8@% Get_Last_Updated_System_Time service%@BO: 6ed4a@% Get_Last_Updated_VM_Exec_Time service%@BO: 6ef5f@% Get_Machine_Info service%@BO: 77edf@% Get_Next_Profile_String service%@BO: 783d3@% Get_Next_VM_Handle service%@BO: 73a71@% Get_PM_Int_Type service%@BO: 53f77@% Get_PM_Int_Vector service%@BO: 5442b@% Get_Profile_Boolean service%@BO: 7881a@% Get_Profile_Decimal_Int service%@BO: 78e0f@% Get_Profile_Fixed_Point service%@BO: 793bc@% Get_Profile_Hex_Int service%@BO: 799e4@% Get_Profile_String service%@BO: 7a020@% Get_PSP_Segment service%@BO: 7a436@% Get_System_Time service%@BO: 6f175@% Get_Sys_VM_Handle service%@BO: 73f55@% Get_Time_Slice_Granularity service%@BO: 68358@% Get_Time_Slice_Info service%@BO: 685f7@% Get_Time_Slice_Priority service%@BO: 688f2@% Get_V86_Int_Vector service%@BO: 5442b@% Get_VMM_Reenter_Count service%@BO: 74178@% Get_VMM_Version service%@BO: 7456b@% Get_VM_Exec_Time service%@BO: 6f49e@% Global descriptor table, defined%@BO: 2fd83@% Grabber DLL functions AdjustInitEndPt%@BO: 23544@% BeginSelection%@BO: 2392d@% CheckGRBVersion%@BO: 25611@% ConsSelecRec%@BO: 23b70@% CursorOff%@BO: 25824@% CursorOn%@BO: 259d5@% CursorPosit%@BO: 25b90@% EndSelection%@BO: 23d87@% GetDisplayUpd%@BO: 25029@% GetFontList%@BO: 25daa@% GrabComplete%@BO: 25f92@% GrabEvent%@BO: 262aa@% GrbUnLockApp%@BO: 265c0@% InitGrabber%@BO: 2676f@% InvertSelection%@BO: 23f1d@% KeySelection%@BO: 24105@% MakeSelctRect%@BO: 24740@% PaintScreen%@BO: 269be@% RenderSelection%@BO: 24c1f@% ScreenFree%@BO: 26d11@% SetPaintFnt%@BO: 26efa@% UpdateScreen%@BO: 2750d@% Grabber%@BO: 227fa@% GrabComplete function%@BO: 25f7e@% GrabEvent function%@BO: 262aa@% GrbUnLockApp function%@BO: 265ac@% %@2@%%@AB@% H%@AE@%%@EH@%%@NL@% Hardware interrupt hooks%@BO: 10129@% HeapAllocate service%@BO: 342b0@% HeapFree service%@BO: 34995@% HeapGetSize service%@BO: 34cac@% HeapReAllocate service%@BO: 34fcc@% Hook_Device_Service service%@BO: 7f8af@% Hook_Device_V86_API service%@BO: 8034c@% Hook_NMI_Event service%@BO: 6d99d@% Hook_PM_Device_API service%@BO: 8034c@% Hook_V86_Int_Chain service%@BO: 54b13@% Hook_V86_Page service%@BO: 2f294@% %@2@%%@AB@% I%@AE@%%@EH@%%@NL@% I/O port traps%@BO: fdf0@% I/O services and macros Disable_Global_Trapping%@BO: 503d0@% Disable_Local_Trapping%@BO: 506fa@% Enable_Global_Trapping%@BO: 503d0@% Enable_Local_Trapping%@BO: 506fa@% Install_IO_Handler%@BO: 509b8@% Install_Mult_IO_Handlers%@BO: 50f2e@% Simulate_IO%@BO: 51442@% IDT. See Interrupt descriptor table%@BO: de08@% Information services GetSet_HMA_Info%@BO: 747b1@% Get_Cur_VM_Handle%@BO: 7383b@% Get_Next_VM_Handle%@BO: 73a71@% Get_Sys_VM_Handle%@BO: 73f55@% Get_VMM_Reenter_Count%@BO: 74178@% Get_VMM_Version%@BO: 7457f@% Test_Cur_VM_Handle%@BO: 74cb5@% Test_Debug_Installed%@BO: 74f3f@% Test_Sys_VM_Handle%@BO: 7518c@% Validate_VM_Handle%@BO: 7541b@% InitGrabber function%@BO: 2676f@% Initialization Information services Convert_Boolean_String%@BO: 75bdc@% Convert_Decimal_String%@BO: 75fe0@% Convert_Fixed_Point_String%@BO: 76526@% Convert_Hex_String%@BO: 76ad5@% GetDOSVectors%@BO: 77b4a@% Get_Config_Directory%@BO: 76f31@% Get_Environment_String%@BO: 77237@% Get_Exec_Path%@BO: 777c8@% Get_Machine_Info%@BO: 77edf@% Get_Next_Profile_String%@BO: 783d3@% Get_Profile_Boolean%@BO: 7881a@% Get_Profile_Decimal_Int%@BO: 78e0f@% Get_Profile_Fixed_Point%@BO: 793bc@% Get_Profile_Hex_Int%@BO: 799e4@% Get_Profile_String%@BO: 7a020@% Get_PSP_Segment%@BO: 7a436@% OpenFile%@BO: 7a7a1@% Install_IO_Handler service%@BO: 509b8@% Install_Mult_IO_Handlers service%@BO: 50f2e@% Install_V86_Break_Point service%@BO: 5ed0b@% INT 2FH%@BO: cc14@%%@BO: 15c12@% Interrupt descriptor table In protected mode%@BO: de08@% Interrupt request%@BO: 1029e@% InvertSelection function%@BO: 23f09@% IRQ. See Interrupt Request%@BO: 1029e@% %@2@%%@AB@% K%@AE@%%@EH@%%@NL@% KeySelection function%@BO: 240f1@% %@2@%%@AB@% L%@AE@%%@EH@%%@NL@% LDT. See Local descriptor table%@BO: 2fd83@% Link386, defined%@BO: 16f12@% Linked List services List_Allocate%@BO: 7aff8@% List_Attach%@BO: 7b3b8@% List_Attach_Tail%@BO: 7b6f3@% List_Create%@BO: 7ba66@% List_Deallocate%@BO: 7c58d@% List_Destroy%@BO: 7c854@% List_Get_First%@BO: 7cada@% List_Get_Next%@BO: 7cd85@% List_Insert%@BO: 7d24c@% List_Remove%@BO: 7d6dd@% List_Remove_First%@BO: 7d9fc@% LinMapIntoV86 service%@BO: 45ff4@% LinPageLock service%@BO: 4776c@% LinPageUnLock service%@BO: 47ec0@% List_Allocate service%@BO: 7afe4@% List_Attach service%@BO: 7b3a4@% List_Attach_Tail service%@BO: 7b6f3@% List_Create service%@BO: 7ba52@% List_Deallocate service%@BO: 7c579@% List_Destroy service%@BO: 7c840@% List_Get_First service%@BO: 7cac6@% List_Get_Next service%@BO: 7cd71@% List_Insert service%@BO: 7d238@% List_Remove service%@BO: 7d6c9@% List_Remove_First service%@BO: 7d9fc@% Local descriptor table, defined%@BO: 2fd83@% %@2@%%@AB@% M%@AE@%%@EH@%%@NL@% MakeSelctRect function%@BO: 2472c@% MapIntoV86 service%@BO: 38e97@% MapPhysToLinear service%@BO: 43f18@% MAPSYM32, defined%@BO: 17d77@% Map_Flat service%@BO: 80970@% MASM5, defined%@BO: 16ba4@% Memory Management services Data Access services GetAppFlatDSAlias%@BO: 44bb2@% GetFirstV86Page%@BO: 44869@% Memory management services Data Access services GetNulPageHandle%@BO: 44a7a@% Memory Management services Device V86 Page Management services Assign_Device_V86_Pages%@BO: 2dac4@% DeAssign_Device_V86_Pages%@BO: 2e286@% Get_Device_V86_Pages_Array%@BO: 2e960@% Hook_V86_Page%@BO: 2f294@% GDT/LDT Management services Allocate_GDT_Selector%@BO: 2fdf7@% Allocate_LDT_Selector%@BO: 30824@% BuildDescDWORDs%@BO: 319f1@% Free_GDT_Selector%@BO: 32374@% Free_LDT_Selector%@BO: 32709@% Instance Data Management services AddInstanceItem%@BO: 4bee4@% MMGR_Toggle_HMA%@BO: 4cff1@% Physical Device Memory in PM services MapPhysToLinear%@BO: 43f18@% Special services for PM APIs LinMapIntoV86%@BO: 45ff4@% LinPageLock%@BO: 4776c@% LinPageUnLock%@BO: 47ec0@% PageCheckLinRange%@BO: 487de@% SelectorMapFlat%@BO: 496d4@% System Data Object Management services Allocate_Device_CB_Area%@BO: 28edf@% Allocate_Global_V86_Data_Area%@BO: 29cc5@% Allocate_Temp_V86_Data_Area%@BO: 2bcb5@% Free_Temp_V86_Data_Area%@BO: 2c73b@% System Heap Allocator services HeapAllocate%@BO: 342b0@% HeapFree%@BO: 34995@% HeapGetSize%@BO: 34cac@% HeapReAllocate%@BO: 34fcc@% System Page Allocator services CopyPageTable%@BO: 363e2@% GetDemandPageInfo%@BO: 36fd0@% GetFreePageCount%@BO: 37896@% GetSetPageOutCount%@BO: 38022@% GetSysPageCount%@BO: 3868b@% GetVMPageCount%@BO: 38983@% MapIntoV86%@BO: 38e97@% ModifyPageBits%@BO: 3a7a5@% PageAllocate%@BO: 3b570@% PageFree%@BO: 3d91f@% PageGetAllocInfo%@BO: 3df18@% PageGetSizeAddr%@BO: 3e79e@% PageLock%@BO: 3ec7f@% PageOutDirtyPages%@BO: 3f883@% PageReAllocate%@BO: 4047b@% PageUnLock%@BO: 41741@% PhysIntoV86%@BO: 42347@% TestGlobalV86Mem%@BO: 42f20@% V86 Address Space services CB_High_Linear%@BO: 4e22c@% Memory management, V86 mode API translation%@BO: 964ee@% Memory management defined%@BO: 951b5@% Message mode, defined%@BO: 1e6f8@% Miscellaneous services Begin_Reentrant_Execution%@BO: 7f1a0@% End_Reentrant_Execution%@BO: 7f662@% Hook_Device_Service%@BO: 7f8af@% Hook_Device_V86_API%@BO: 8034c@% Hook_PM_Device_API%@BO: 8034c@% Map_Flat%@BO: 80984@% MMGR_SetNULPageAddr%@BO: 81604@% Set_System_Exit_code%@BO: 8190e@% Simulate_Pop%@BO: 81cc7@% Simulate_Push%@BO: 81f44@% System_Control%@BO: 821d7@% MMGR_SetNULPageAddr service%@BO: 81604@% MMGR_Toggle_HMA service%@BO: 4cff1@% Mode Protected%@BO: ade5@%%@BO: f1f1@% Real%@BO: 18309@%%@BO: aa1e3@% Virtual-86%@BO: acd8@%%@BO: f1f1@% ModifyPageBits service%@BO: 3a7a5@% %@2@%%@AB@% N%@AE@%%@EH@%%@NL@% Nested Execution services Begin_Nest_Exec%@BO: 57b24@% Begin_Nest_V86_Exec%@BO: 586ec@% Begin_Use_Locked_PM_Stack%@BO: 58b70@% End_Nest_Exec%@BO: 590a6@% End_Use_Locked_PM_Stack%@BO: 59525@% Exec_Int%@BO: 59882@% Exec_VxD_Int%@BO: 59ccb@% Restore_Client_State%@BO: 5ae0a@% Resume_Exec%@BO: 5b3f0@% Save_Client_State%@BO: 5bfed@% Set_PM_Exec_Mode%@BO: 5ca00@% Set_V86_Exec_Mode%@BO: 5ce5d@% No_Fail_Resume_VM service%@BO: 6453b@% Nuke_VM service%@BO: 648e9@% %@2@%%@AB@% O%@AE@%%@EH@%%@NL@% OpenFile service%@BO: 7a7b5@% %@2@%%@AB@% P%@AE@%%@EH@%%@NL@% PageAllocate service%@BO: 3b570@% PageCheckLinRange service%@BO: 487de@% PageFree service%@BO: 3d91f@% PageGetAllocInfo service%@BO: 3df18@% PageGetSizeAddr service%@BO: 3e79e@% PageLock service%@BO: 3ec7f@% PageOutDirtyPages service%@BO: 3f883@% PageReAllocate service%@BO: 4047b@% PageUnLock service%@BO: 41741@% PaintScreen function%@BO: 269be@% PhysIntoV86 service%@BO: 42347@% PM. See Protected mode%@BO: 9ea7@% Primary Scheduler services Adjust_Exec_Priority%@BO: 60bf8@% Begin_Critical_Section%@BO: 61895@% Call_When_Not_Critical%@BO: 624c1@% Call_When_Task_Switched%@BO: 62a34@% Claim_Critical_Section%@BO: 62f7e@% Create_Semaphore%@BO: 632a5@% Destroy_Semaphore%@BO: 633ca@% End_Critical_Section%@BO: 63df2@% End_Crit_And_Suspend%@BO: 634f0@% Get_Crit_Section_Status%@BO: 64124@% No_Fail_Resume_VM%@BO: 6454f@% Nuke_VM%@BO: 648fd@% Release_Critical_Section%@BO: 64c8e@% Resume_VM%@BO: 64f35@% Signal_Semaphore%@BO: 653ac@% Suspend_VM%@BO: 654e5@% Wait_Semaphore%@BO: 65c2c@% Privilege rings%@BO: f011@% Processor Fault and Interrupt services Get_Fault_Hook_Addrs%@BO: 70d86@% Get_NMI_Handler_Addr%@BO: 71164@% Hook_NMI_Event%@BO: 71aba@% Hook_PM_Fault%@BO: 71dc6@% Hook_V86_Fault%@BO: 71dc6@% Hook_V86_Page%@BO: 72948@% Hook_VMM_Fault%@BO: 71dc6@% Set_NMI_Handler_Addr%@BO: 731b7@% Protected mode defined%@BO: e9d5@%%@BO: aa9e7@% Initialization%@BO: 19c75@% Interrupt descriptor table%@BO: de08@% %@2@%%@AB@% R%@AE@%%@EH@%%@NL@% Real mode defined%@BO: aa73f@% initialization%@BO: 18309@% Release_Critical_Section service%@BO: 64c8e@% Release_Time_Slice service%@BO: 68daf@% Remove_V86_Break_Point service%@BO: 5fa54@% RenderSelection function%@BO: 24c0b@% Restore_Client_State service%@BO: 5ae0a@% Resume_Exec service%@BO: 5b3dc@% Resume_VM service%@BO: 64f21@% %@2@%%@AB@% S%@AE@%%@EH@%%@NL@% Save_Client_State service%@BO: 5bfed@% Schedule_Global_Event service%@BO: 6dc61@% Schedule_VM_Event service%@BO: 6dfed@% Scheduling defined%@BO: 600e0@%%@BO: 606ef@% Enhanced Windows execution%@BO: cd21@% Primary scheduler%@BO: d51a@%%@BO: d708@% Time-slice scheduler%@BO: d51a@% ScreenFree function%@BO: 26d11@% SelectorMapFlat service%@BO: 496d4@% Services, defined%@BO: f34f@% SetPaintFnt function%@BO: 26efa@% Set_Execution_Focus service%@BO: 691ff@% Set_Global_Time_Out service%@BO: 6f829@% Set_PM_Exec_Mode service%@BO: 5ca00@% Set_PM_Int_Type service%@BO: 5578a@% Set_PM_Int_Vector service%@BO: 55c52@% Set_System_Exit_code service%@BO: 8190e@% Set_Time_Slice_Granularity service%@BO: 695f3@% Set_Time_Slice_Priority service%@BO: 69922@% Set_V86_Exec_Mode service%@BO: 5ce5d@% Set_V86_Int_Vector service%@BO: 55c52@% Set_VM_Time_Out service%@BO: 6fe99@% Shell services SHELL_Event%@BO: 82fac@% SHELL_Get_Version%@BO: 83589@% SHELL_Message%@BO: 8379b@% SHELL_Resolve_Contention%@BO: 83d4b@% Shell, defined%@BO: b971@% Signal_Semaphore service%@BO: 653ac@% Simulate_Far_Call service%@BO: 560e1@% Simulate_Far_Jmp service%@BO: 5651a@% Simulate_Far_Ret service%@BO: 567d9@% Simulate_Far_Ret_N service%@BO: 56a68@% Simulate_Int service%@BO: 56d67@% Simulate_IO service%@BO: 51442@% Simulate_Iret service%@BO: 57415@% Simulate_Pop service%@BO: 81cb3@% Simulate_Push service%@BO: 81f30@% Software interrupt hooks%@BO: 1029e@% Suspend_VM service%@BO: 654d1@% System_Controls service%@BO: 821c3@% %@2@%%@AB@% T%@AE@%%@EH@%%@NL@% TestGlobalV86Mem service%@BO: 42f20@% Test_Cur_VM_Handle service%@BO: 74cb5@% Test_Debug_Installed service%@BO: 74f3f@% Test_Sys_VM_Handle service%@BO: 7518c@% Time-Slice Scheduler services Adjust_Execution_Time%@BO: 6734f@% Call_When_Idle%@BO: 67a21@% Get_Execution_Focus%@BO: 680fe@% Get_Time_Slice_Granularity%@BO: 68358@% Get_Time_Slice_Info%@BO: 685f7@% Get_Time_Slice_Priority%@BO: 688f2@% Release_Time_Slice%@BO: 68daf@% Set_Execution_Focus%@BO: 691ff@% Set_Time_Slice_Granularity%@BO: 695f3@% Set_Time_Slice_Priority%@BO: 69922@% Wake_Up_VM%@BO: 69e3d@% Timing services Cancel_Time_Out%@BO: 6e848@% Get_Last_Updated_System_Time%@BO: 6ed4a@% Get_Last_Updated_VM_Exec_Time%@BO: 6ef5f@% Get_System_Time%@BO: 6f189@% Get_VM_Exec_Time%@BO: 6f4b2@% Set_Global_Time_Out%@BO: 6f829@% Set_VM_Time_Out%@BO: 6fead@% Update_System_Clock%@BO: 7063b@% %@2@%%@AB@% U%@AE@%%@EH@%%@NL@% UpdateScreen function%@BO: 274f9@% Update_System_Clock service%@BO: 7063b@% %@2@%%@AB@% V%@AE@%%@EH@%%@NL@% V86 Mode Memory Manager Device services V86MMGR_Allocate_Buffer%@BO: 9cf13@% V86MMGR_Allocate_V86_Pages%@BO: 95420@% V86MMGR_Free_Buffer%@BO: 9d56c@% V86MMGR_Free_Page_Map_Region%@BO: 9ebcd@% V86MMGR_Get_EMS_XMS_Limits%@BO: 95e83@% V86MMGR_Get_Mapping_Info%@BO: 9e61f@% V86MMGR_Get_Version%@BO: 9520b@% V86MMGR_Get_VM_Flat_Sel%@BO: 9e224@% V86MMGR_Get_Xlat_Buff_State%@BO: 9d990@% V86MMGR_Load_Client_Ptr%@BO: 9c965@% V86MMGR_Map_Pages%@BO: 9e84b@% V86MMGR_Set_EMS_XMS_Limits%@BO: 959ed@% V86MMGR_Set_Mapping_Info%@BO: 999a6@% V86MMGR_Set_Xlat_Buff_State%@BO: 9ddf6@% V86MMGR_Xlat_API%@BO: 9a016@% V86. See Virtual-86 mode%@BO: 9ea7@% V86MMGR services. See V86 Mode Memory Manager Device services%@BO: 94b08@% Validate_VM_Handle service%@BO: 7541b@% VDD services. See Virtual Display Device services%@BO: 84524@% VDMAD services. See Virtual DMA Device services%@BO: 9f136@% VDMAD_Request_Buffer service%@BO: a26e3@%%@BO: a2a0e@% Virtual device API procedure%@BO: c377@%%@BO: 1350f@% API%@BO: 15a2e@% Building%@BO: 163c5@% Declaration%@BO: 12781@% defined%@BO: a188@%%@BO: b971@% Device control procedure name%@BO: 1350f@% Device control procedure%@BO: bfc4@% Device descriptor block%@BO: c377@% ID%@BO: 1350f@% IDS%@BO: c95b@% Initialization order%@BO: c95b@% Initialization%@BO: 1350f@%%@BO: 18166@% Installing%@BO: 17fd6@% Memory model%@BO: 11b28@% Segmentation%@BO: 12054@% Service table%@BO: 1350f@% Services%@BO: 13fb4@% Version%@BO: 1350f@% Writing strategy%@BO: 1150e@% Virtual Display Device services VDD_Get_GrabRtn%@BO: 85edb@% VDD_Get_ModTime%@BO: 861e6@% VDD_Get_Version%@BO: 86441@% VDD_Hide_Cursor%@BO: 8668d@% VDD_Msg_BakColor%@BO: 850e9@% VDD_Msg_ClrScrn%@BO: 85322@% VDD_Msg_ForColor%@BO: 8567e@% VDD_Msg_SetCursPos%@BO: 858b7@% VDD_Msg_TextOut%@BO: 85ad5@% VDD_PIF_State%@BO: 869d0@% VDD_Query_Access%@BO: 86bc4@% VDD_Set_HCurTrk%@BO: 86f1f@% VDD_Set_VMType%@BO: 871a5@%%@BO: 87599@% Virtual DMA Device services VDMAD_Copy_From_Buffer%@BO: 9f794@% VDMAD_Copy_To_Buffer%@BO: 9fb89@% VDMAD_Default_Handler%@BO: 9ff5e@% VDMAD_Disable_Translation%@BO: a02fd@% VDMAD_Enable_Translation%@BO: a069f@% VDMAD_Get_EISA_Adr_Mode%@BO: a09d1@% VDMAD_Get_Region_Info%@BO: a0d86@% VDMAD_Get_Version%@BO: a1128@% VDMAD_Get_Virt_State%@BO: a13d7@% VDMAD_Lock_DMA_Region%@BO: a1a16@% VDMAD_Mask_Channel%@BO: a24e9@% VDMAD_Release_Buffer%@BO: a26e3@% VDMAD_Request_Buffer%@BO: a2a0e@% VDMAD_Reserve_Buffer_Space%@BO: a2d49@% VDMAD_Scatter_Lock%@BO: a321c@% VDMAD_Scatter_Unlock%@BO: a3762@% VDMAD_Set_EISA_Adr_Mode%@BO: a3c23@% VDMAD_Set_Phys_State%@BO: a3ed2@% VDMAD_Set_Region_Info%@BO: a41c8@% VDMAD_Set_Virt_State%@BO: a44b6@% VDMAD_Unlock_DMA_Region%@BO: a49eb@% VDMAD_UnMask_Channel%@BO: a4ce8@% VDMAD_Virtualize_Channel%@BO: a4eed@% Virtual DOSNET device services DOSNET_Do_PSP_Adjust%@BO: a5965@% DOSNET_Get_Version%@BO: a574f@% DOSNET_Send_FILESYSCHANGE%@BO: a6301@% Virtual Keyboard Device services VKD_Cancel_Hot_Key_State%@BO: 87d2a@% VKD_Cancel_Paste%@BO: 87f19@% VKD_Define_Hot_Key%@BO: 8810e@% VKD_Define_Paste_Mode%@BO: 88f54@% VKD_Flush_Msg_Key_Queue%@BO: 89367@% VKD_Force_Keys%@BO: 89573@% VKD_Get_Kbd_Owner%@BO: 8987e@% VKD_Get_Msg_Key%@BO: 89a74@% VKD_Get_Version%@BO: 89dd3@% VKD_Local_Disable_Hot_Key%@BO: 89fc9@% VKD_Local_Enable_Hot_Key%@BO: 8a217@% VKD_Peek_Msg_Key%@BO: 8a463@% VKD_Reflect_Hot_Key%@BO: 8a7ab@% VKD_Remove_Hot_Key%@BO: 8abd8@% VKD_Start_Paste%@BO: 8adb9@% Virtual machine manager, defined%@BO: a009@%%@BO: b408@% Virtual machine Client Register structure%@BO: a9b5@%%@BO: b24c@% defined%@BO: 9ea7@%%@BO: a7a9@% Events%@BO: cf3b@% Initialization%@BO: 1a4b0@% Loading sequence%@BO: 103cb@% Privilege rings%@BO: abfc@% Scheduling%@BO: d319@% States%@BO: 1a3d8@% Termination%@BO: 1b691@% VM handle%@BO: b0f0@% Virtual PIC Device services VID_EOI_Proc%@BO: 8d140@% VID_Hw_Int_Proc%@BO: 8cb43@% VID_IRET_Proc%@BO: 8da51@% VID_Mask_Change_Proc%@BO: 8e485@% VID_Virt_Int_Proc%@BO: 8d62a@% VPICD_Call_When_Hw_Int%@BO: 8e81b@% VPICD_Clear_Int_Request%@BO: 8eee3@% VPICD_Convert_Handle_To_IRQ%@BO: 8f22e@% VPICD_Convert_Int_To_IRQ%@BO: 8f44d@% VPICD_Convert_IRQ_To_Int%@BO: 8f7b8@% VPICD_Get_Complete_Status%@BO: 8fb18@% VPICD_Get_IRQ_Complete_Status%@BO: 8fc16@% VPICD_Get_Status%@BO: 9006f@% VPICD_Get_Version%@BO: 9066f@% VPICD_Physically_Mask%@BO: 90ca9@% VPICD_Physically_Unmask%@BO: 90f1f@% VPICD_Phys_EOI%@BO: 90981@% VPICD_Set_Auto_Masking%@BO: 9119d@% VPICD_Set_Int_Request%@BO: 91506@% VPICD_Test_Phys_Request%@BO: 91c64@% VPICD_Virtualize_IRQ%@BO: 91ea4@% Virtual PIC Device defined%@BO: 1029e@% Virtual Sound Device services VSD_Bell%@BO: 92713@% VSD_Get_Version%@BO: 9299b@% Virtual Timer Device services VTD_Begin_Min_Int_Period%@BO: 92eba@% VTD_Disable_Trapping%@BO: 9359e@% VTD_Enable_Trapping%@BO: 93bec@% VTD_End_Min_Int_Period%@BO: 93ebd@% VTD_Get_Interupt_Period%@BO: 94243@% VTD_Get_Version%@BO: 9443f@% VTD_Update_System_Clock%@BO: 94725@% Virtual-86 mode, defined%@BO: e9d5@%%@BO: aac5e@% VKD services. See Virtual Keyboard Device services%@BO: 87950@% VM Interrupt and Call services Build_Int_Stack_Frame%@BO: 528fa@% Call_When_Idle%@BO: 52df0@% Call_When_VM_Ints_Enabled%@BO: 534c7@% Disable_VM_Ints%@BO: 539be@% Enable_VM_Ints%@BO: 53beb@% Get_PM_Int_Type%@BO: 53f8b@% Get_PM_Int_Vector%@BO: 5442b@% Get_V86_Int_Vector%@BO: 5442b@% Hook_V86_Int_Chain%@BO: 54a46@% Set_PM_Int_Type%@BO: 5578a@% Set_PM_Int_Vector%@BO: 55c52@% Set_V86_Int_Vector%@BO: 55c52@% Simulate_Far_Call%@BO: 560e1@% Simulate_Far_Jmp%@BO: 5651a@% Simulate_Far_Ret%@BO: 567d9@% Simulate_Far_Ret_N%@BO: 56a68@% Simulate_Int%@BO: 56d7b@% Simulate_Iret%@BO: 57415@% VM. See Virtual machine%@BO: 9ea7@% VMM. See Virtual machine manager%@BO: a009@% VPICD services. See Virtual PIC Device services%@BO: 8b941@% VSD services. See Virtual Sound Device services%@BO: 925fc@% VTD services. See Virtual Timer Device services%@BO: 92c76@% VxD. See Virtual device%@BO: a188@% %@2@%%@AB@% W%@AE@%%@EH@%%@NL@% Wait_Semaphore service%@BO: 65c2c@% Wake_Up_VM service%@BO: 69e3d@% WINOLDAP%@BO: 15a2e@%%@BO: 227fa@%