summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Rozenfeld <vrozenfe@redhat.com>2014-09-02 17:36:27 +1000
committerVadim Rozenfeld <vrozenfe@redhat.com>2014-09-02 17:36:27 +1000
commit5c52e50bf86f1bee0c0fbab5049dcb5fd6b8bd21 (patch)
tree19321b1d155f17a507d5f1c3a6b93157bdc02a24
parentcb3cacc51db0ae1daf580a08c94c663a3eaa7309 (diff)
initial commitv06
-rw-r--r--README.md5
-rwxr-xr-xqxldod Package/qxldod Package.vcxproj165
-rwxr-xr-xqxldod Package/qxldod Package.vcxproj.filters9
-rwxr-xr-xqxldod.sln75
-rwxr-xr-xqxldod/BaseObject.cpp70
-rwxr-xr-xqxldod/BaseObject.h59
-rwxr-xr-xqxldod/QxlDod.cpp4487
-rwxr-xr-xqxldod/QxlDod.h717
-rwxr-xr-xqxldod/buildAll.bat31
-rwxr-xr-xqxldod/callVisualStudio.bat28
-rwxr-xr-xqxldod/checkWin8Tools.bat16
-rwxr-xr-xqxldod/clean.bat12
-rwxr-xr-xqxldod/driver.cpp676
-rwxr-xr-xqxldod/driver.h255
-rwxr-xr-xqxldod/getVisualStudioCmdLine.vbs28
-rwxr-xr-xqxldod/include/barrier.h55
-rwxr-xr-xqxldod/include/end-packed.h38
-rwxr-xr-xqxldod/include/enums.h613
-rwxr-xr-xqxldod/include/ipc_ring.h136
-rwxr-xr-xqxldod/include/qxl_dev.h808
-rwxr-xr-xqxldod/include/start-packed.h64
-rwxr-xr-xqxldod/include/stdint.h397
-rwxr-xr-xqxldod/include/types.h41
-rwxr-xr-xqxldod/mspace.c2437
-rwxr-xr-xqxldod/mspace.h150
-rwxr-xr-xqxldod/qxldod.infbin0 -> 4140 bytes
-rwxr-xr-xqxldod/qxldod.rcbin0 -> 696 bytes
-rwxr-xr-xqxldod/qxldod.vcxproj290
-rwxr-xr-xqxldod/qxldod.vcxproj.filters59
-rwxr-xr-xqxldod/resource.h14
30 files changed, 11735 insertions, 0 deletions
diff --git a/README.md b/README.md
index 5495b0e..f17b908 100644
--- a/README.md
+++ b/README.md
@@ -2,3 +2,8 @@ qxl-dod
=======
QXL WDDM DOD driver
+
+Heavily based on Microsoft KMDOD example and XDDM QXL driver
+
+The most recent binaries can be found at http://people.redhat.com/~vrozenfe/qxlwddm/
+
diff --git a/qxldod Package/qxldod Package.vcxproj b/qxldod Package/qxldod Package.vcxproj
new file mode 100755
index 0000000..f71e4c6
--- /dev/null
+++ b/qxldod Package/qxldod Package.vcxproj
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Win8.1 Debug|Win32">
+ <Configuration>Win8.1 Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win8 Debug|Win32">
+ <Configuration>Win8 Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win8.1 Release|Win32">
+ <Configuration>Win8.1 Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win8 Release|Win32">
+ <Configuration>Win8 Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win7 Debug|Win32">
+ <Configuration>Win7 Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win7 Release|Win32">
+ <Configuration>Win7 Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win8.1 Debug|x64">
+ <Configuration>Win8.1 Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win8 Debug|x64">
+ <Configuration>Win8 Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win8.1 Release|x64">
+ <Configuration>Win8.1 Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win8 Release|x64">
+ <Configuration>Win8 Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win7 Debug|x64">
+ <Configuration>Win7 Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win7 Release|x64">
+ <Configuration>Win7 Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{B8C04B51-4207-491D-A7DD-C54861E8B528}</ProjectGuid>
+ <TemplateGuid>{4605da2c-74a5-4865-98e1-152ef136825f}</TemplateGuid>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
+ <Configuration>Win8 Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ </PropertyGroup>
+ <PropertyGroup Label="Globals">
+ <RootNamespace>qxldod_Package</RootNamespace>
+ <VCTargetsPath Condition="'$(VCTargetsPath11)' != '' and '$(VisualStudioVersion)' == '11.0'">$(VCTargetsPath11)</VCTargetsPath>
+ </PropertyGroup>
+ <PropertyGroup Label="PropertySheets">
+ <ConfigurationType>Utility</ConfigurationType>
+ <DriverType>Package</DriverType>
+ <DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Win8.1 Debug|Win32'">
+ <TargetVersion>WindowsV6.3</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'" Label="Configuration">
+ <TargetVersion>Windows8</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Win8.1 Release|Win32'">
+ <TargetVersion>WindowsV6.3</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'" Label="Configuration">
+ <TargetVersion>Windows8</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'" Label="Configuration">
+ <TargetVersion>Windows7</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'" Label="Configuration">
+ <TargetVersion>Windows7</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Win8.1 Debug|x64'">
+ <TargetVersion>WindowsV6.3</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'" Label="Configuration">
+ <TargetVersion>Windows8</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Win8.1 Release|x64'">
+ <TargetVersion>WindowsV6.3</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'" Label="Configuration">
+ <TargetVersion>Windows8</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'" Label="Configuration">
+ <TargetVersion>Windows7</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'" Label="Configuration">
+ <TargetVersion>Windows7</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup />
+ <PropertyGroup>
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ <EnableDeployment>False</EnableDeployment>
+ <RemoveDriver>True</RemoveDriver>
+ <HardwareIdString />
+ <CommandLine />
+ <DeployFiles />
+ <EnableVerifier>False</EnableVerifier>
+ <AllDrivers>False</AllDrivers>
+ <VerifyProjectOutput>True</VerifyProjectOutput>
+ <VerifyDrivers />
+ <VerifyFlags>133563</VerifyFlags>
+ </PropertyGroup>
+ <ItemDefinitionGroup>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\qxldod\qxldod.vcxproj">
+ <Project>{a6f48fc7-97e9-48ec-bcdf-1e4f9b43aadd}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/qxldod Package/qxldod Package.vcxproj.filters b/qxldod Package/qxldod Package.vcxproj.filters
new file mode 100755
index 0000000..73af436
--- /dev/null
+++ b/qxldod Package/qxldod Package.vcxproj.filters
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Driver Files">
+ <UniqueIdentifier>{8E41214B-6785-4CFE-B992-037D68949A14}</UniqueIdentifier>
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ </Filter>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/qxldod.sln b/qxldod.sln
new file mode 100755
index 0000000..494614b
--- /dev/null
+++ b/qxldod.sln
@@ -0,0 +1,75 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qxldod", "qxldod\qxldod.vcxproj", "{A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qxldod Package", "qxldod Package\qxldod Package.vcxproj", "{B8C04B51-4207-491D-A7DD-C54861E8B528}"
+ ProjectSection(ProjectDependencies) = postProject
+ {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD} = {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Win8.1 Debug|Win32 = Win8.1 Debug|Win32
+ Win8.1 Debug|x64 = Win8.1 Debug|x64
+ Win8.1 Release|Win32 = Win8.1 Release|Win32
+ Win8.1 Release|x64 = Win8.1 Release|x64
+ Win8 Debug|Win32 = Win8 Debug|Win32
+ Win8 Debug|x64 = Win8 Debug|x64
+ Win8 Release|Win32 = Win8 Release|Win32
+ Win8 Release|x64 = Win8 Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8.1 Debug|Win32.ActiveCfg = Win8.1 Debug|Win32
+ {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8.1 Debug|Win32.Build.0 = Win8.1 Debug|Win32
+ {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8.1 Debug|Win32.Deploy.0 = Win8.1 Debug|Win32
+ {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8.1 Debug|x64.ActiveCfg = Win8.1 Debug|x64
+ {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8.1 Debug|x64.Build.0 = Win8.1 Debug|x64
+ {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8.1 Debug|x64.Deploy.0 = Win8.1 Debug|x64
+ {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8.1 Release|Win32.ActiveCfg = Win8.1 Release|Win32
+ {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8.1 Release|Win32.Build.0 = Win8.1 Release|Win32
+ {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8.1 Release|Win32.Deploy.0 = Win8.1 Release|Win32
+ {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8.1 Release|x64.ActiveCfg = Win8.1 Release|x64
+ {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8.1 Release|x64.Build.0 = Win8.1 Release|x64
+ {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8.1 Release|x64.Deploy.0 = Win8.1 Release|x64
+ {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8.1 Debug|Win32.ActiveCfg = Win8.1 Debug|Win32
+ {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8.1 Debug|Win32.Build.0 = Win8.1 Debug|Win32
+ {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8.1 Debug|Win32.Deploy.0 = Win8.1 Debug|Win32
+ {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8.1 Debug|x64.ActiveCfg = Win8.1 Debug|x64
+ {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8.1 Debug|x64.Build.0 = Win8.1 Debug|x64
+ {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8.1 Debug|x64.Deploy.0 = Win8.1 Debug|x64
+ {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8.1 Release|Win32.ActiveCfg = Win8.1 Release|Win32
+ {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8.1 Release|Win32.Build.0 = Win8.1 Release|Win32
+ {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8.1 Release|Win32.Deploy.0 = Win8.1 Release|Win32
+ {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8.1 Release|x64.ActiveCfg = Win8.1 Release|x64
+ {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8.1 Release|x64.Build.0 = Win8.1 Release|x64
+ {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8.1 Release|x64.Deploy.0 = Win8.1 Release|x64
+ {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8 Debug|Win32.ActiveCfg = Win8 Debug|Win32
+ {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8 Debug|Win32.Build.0 = Win8 Debug|Win32
+ {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8 Debug|Win32.Deploy.0 = Win8 Debug|Win32
+ {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8 Debug|x64.ActiveCfg = Win8 Debug|x64
+ {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8 Debug|x64.Build.0 = Win8 Debug|x64
+ {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8 Debug|x64.Deploy.0 = Win8 Debug|x64
+ {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8 Release|Win32.ActiveCfg = Win8 Release|Win32
+ {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8 Release|Win32.Build.0 = Win8 Release|Win32
+ {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8 Release|Win32.Deploy.0 = Win8 Release|Win32
+ {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8 Release|x64.ActiveCfg = Win8 Release|x64
+ {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8 Release|x64.Build.0 = Win8 Release|x64
+ {A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}.Win8 Release|x64.Deploy.0 = Win8 Release|x64
+ {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8 Debug|Win32.ActiveCfg = Win8 Debug|Win32
+ {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8 Debug|Win32.Build.0 = Win8 Debug|Win32
+ {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8 Debug|Win32.Deploy.0 = Win8 Debug|Win32
+ {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8 Debug|x64.ActiveCfg = Win8 Debug|x64
+ {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8 Debug|x64.Build.0 = Win8 Debug|x64
+ {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8 Debug|x64.Deploy.0 = Win8 Debug|x64
+ {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8 Release|Win32.ActiveCfg = Win8 Release|Win32
+ {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8 Release|Win32.Build.0 = Win8 Release|Win32
+ {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8 Release|Win32.Deploy.0 = Win8 Release|Win32
+ {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8 Release|x64.ActiveCfg = Win8 Release|x64
+ {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8 Release|x64.Build.0 = Win8 Release|x64
+ {B8C04B51-4207-491D-A7DD-C54861E8B528}.Win8 Release|x64.Deploy.0 = Win8 Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/qxldod/BaseObject.cpp b/qxldod/BaseObject.cpp
new file mode 100755
index 0000000..da9dfc8
--- /dev/null
+++ b/qxldod/BaseObject.cpp
@@ -0,0 +1,70 @@
+#include "BaseObject.h"
+
+#pragma code_seg("PAGE")
+
+#define QXLTAG 'LXQd'
+
+//
+// New and delete operators
+//
+_When_((PoolType & NonPagedPoolMustSucceed) != 0,
+ __drv_reportError("Must succeed pool allocations are forbidden. "
+ "Allocation failures cause a system crash"))
+void* __cdecl operator new(size_t Size, POOL_TYPE PoolType)
+{
+ PAGED_CODE();
+
+ Size = (Size != 0) ? Size : 1;
+
+ void* pObject = ExAllocatePoolWithTag(PoolType, Size, QXLTAG);
+
+#if DBG
+ if (pObject != NULL)
+ {
+ RtlFillMemory(pObject, Size, 0xCD);
+ }
+#endif // DBG
+
+ return pObject;
+}
+
+_When_((PoolType & NonPagedPoolMustSucceed) != 0,
+ __drv_reportError("Must succeed pool allocations are forbidden. "
+ "Allocation failures cause a system crash"))
+void* __cdecl operator new[](size_t Size, POOL_TYPE PoolType)
+{
+ PAGED_CODE();
+
+ Size = (Size != 0) ? Size : 1;
+
+ void* pObject = ExAllocatePoolWithTag(PoolType, Size, QXLTAG);
+
+#if DBG
+ if (pObject != NULL)
+ {
+ RtlFillMemory(pObject, Size, 0xCD);
+ }
+#endif // DBG
+
+ return pObject;
+}
+
+void __cdecl operator delete(void* pObject)
+{
+ PAGED_CODE();
+
+ if (pObject != NULL)
+ {
+ ExFreePool(pObject);
+ }
+}
+
+void __cdecl operator delete[](void* pObject)
+{
+ PAGED_CODE();
+
+ if (pObject != NULL)
+ {
+ ExFreePool(pObject);
+ }
+}
diff --git a/qxldod/BaseObject.h b/qxldod/BaseObject.h
new file mode 100755
index 0000000..66e66e4
--- /dev/null
+++ b/qxldod/BaseObject.h
@@ -0,0 +1,59 @@
+#pragma once
+extern "C"
+{
+ #define __CPLUSPLUS
+
+ // Standard C-runtime headers
+ #include <stddef.h>
+ #include <string.h>
+ #include <stdarg.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ #include <initguid.h>
+
+ // NTOS headers
+ #include <ntddk.h>
+
+ #ifndef FAR
+ #define FAR
+ #endif
+
+ // Windows headers
+ #include <windef.h>
+ #include <winerror.h>
+
+ // Windows GDI headers
+ #include <wingdi.h>
+
+ // Windows DDI headers
+ #include <winddi.h>
+ #include <ntddvdeo.h>
+
+ #include <d3dkmddi.h>
+ #include <d3dkmthk.h>
+
+ #include <ntstrsafe.h>
+ #include <ntintsafe.h>
+
+ #include <dispmprt.h>
+};
+
+//
+// Memory handling
+//
+
+// Defaulting the value of PoolType means that any call to new Foo()
+// will raise a compiler error for being ambiguous. This is to help keep
+// any calls to allocate memory from accidentally NOT going through
+// these functions.
+_When_((PoolType & NonPagedPoolMustSucceed) != 0,
+ __drv_reportError("Must succeed pool allocations are forbidden. "
+ "Allocation failures cause a system crash"))
+void* __cdecl operator new(size_t Size, POOL_TYPE PoolType = PagedPool);
+_When_((PoolType & NonPagedPoolMustSucceed) != 0,
+ __drv_reportError("Must succeed pool allocations are forbidden. "
+ "Allocation failures cause a system crash"))
+void* __cdecl operator new[](size_t Size, POOL_TYPE PoolType = PagedPool);
+void __cdecl operator delete(void* pObject);
+void __cdecl operator delete[](void* pObject);
diff --git a/qxldod/QxlDod.cpp b/qxldod/QxlDod.cpp
new file mode 100755
index 0000000..0514643
--- /dev/null
+++ b/qxldod/QxlDod.cpp
@@ -0,0 +1,4487 @@
+#include "driver.h"
+#include "qxldod.h"
+
+#pragma code_seg(push)
+#pragma code_seg()
+// BEGIN: Non-Paged Code
+
+// Bit is 1 from Idx to end of byte, with bit count starting at high order
+BYTE lMaskTable[BITS_PER_BYTE] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
+
+// Bit is 1 from Idx to start of byte, with bit count starting at high order
+BYTE rMaskTable[BITS_PER_BYTE] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
+
+// Bit of Idx is 1, with bit count starting at high order
+BYTE PixelMask[BITS_PER_BYTE] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
+
+
+// For the following macros, pPixel must be a BYTE* pointing to the start of a 32 bit pixel
+#define CONVERT_32BPP_TO_16BPP(pPixel) ((UPPER_5_BITS(pPixel[2]) << SHIFT_FOR_UPPER_5_IN_565) | \
+ (UPPER_6_BITS(pPixel[1]) << SHIFT_FOR_MIDDLE_6_IN_565) | \
+ (UPPER_5_BITS(pPixel[0])))
+
+// 8bpp is done with 6 levels per color channel since this gives true grays, even if it leaves 40 empty palette entries
+// The 6 levels per color is the reason for dividing below by 43 (43 * 6 == 258, closest multiple of 6 to 256)
+// It is also the reason for multiplying the red channel by 36 (== 6*6) and the green channel by 6, as this is the
+// equivalent to bit shifting in a 3:3:2 model. Changes to this must be reflected in vesasup.cxx with the Blues/Greens/Reds arrays
+#define CONVERT_32BPP_TO_8BPP(pPixel) (((pPixel[2] / 43) * 36) + \
+ ((pPixel[1] / 43) * 6) + \
+ ((pPixel[0] / 43)))
+
+// 4bpp is done with strict grayscale since this has been found to be usable
+// 30% of the red value, 59% of the green value, and 11% of the blue value is the standard way to convert true color to grayscale
+#define CONVERT_32BPP_TO_4BPP(pPixel) ((BYTE)(((pPixel[2] * 30) + \
+ (pPixel[1] * 59) + \
+ (pPixel[0] * 11)) / (100 * 16)))
+
+
+// For the following macro, Pixel must be a WORD representing a 16 bit pixel
+#define CONVERT_16BPP_TO_32BPP(Pixel) (((ULONG)LOWER_5_BITS((Pixel) >> SHIFT_FOR_UPPER_5_IN_565) << SHIFT_UPPER_5_IN_565_BACK) | \
+ ((ULONG)LOWER_6_BITS((Pixel) >> SHIFT_FOR_MIDDLE_6_IN_565) << SHIFT_MIDDLE_6_IN_565_BACK) | \
+ ((ULONG)LOWER_5_BITS((Pixel)) << SHIFT_LOWER_5_IN_565_BACK))
+
+
+#pragma code_seg(pop)
+
+
+
+QxlDod::QxlDod(_In_ DEVICE_OBJECT* pPhysicalDeviceObject) : m_pPhysicalDevice(pPhysicalDeviceObject),
+ m_MonitorPowerState(PowerDeviceD0),
+ m_AdapterPowerState(PowerDeviceD0)
+{
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__));
+ *((UINT*)&m_Flags) = 0;
+ RtlZeroMemory(&m_DxgkInterface, sizeof(m_DxgkInterface));
+ RtlZeroMemory(&m_DeviceInfo, sizeof(m_DeviceInfo));
+ RtlZeroMemory(m_CurrentModes, sizeof(m_CurrentModes));
+ RtlZeroMemory(&m_PointerShape, sizeof(m_PointerShape));
+ m_pHWDevice = NULL;
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__));
+}
+
+
+QxlDod::~QxlDod(void)
+{
+ PAGED_CODE();
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ CleanUp();
+ delete m_pHWDevice;
+ m_pHWDevice = NULL;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+}
+
+NTSTATUS QxlDod::CheckHardware()
+{
+ PAGED_CODE();
+
+ NTSTATUS Status;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+
+ // Get the Vendor & Device IDs on PCI system
+ PCI_COMMON_HEADER Header = {0};
+ ULONG BytesRead;
+
+ Status = m_DxgkInterface.DxgkCbReadDeviceSpace(m_DxgkInterface.DeviceHandle,
+ DXGK_WHICHSPACE_CONFIG,
+ &Header,
+ 0,
+ sizeof(Header),
+ &BytesRead);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("DxgkCbReadDeviceSpace failed with status 0x%X\n", Status));
+ return Status;
+ }
+
+ Status = STATUS_GRAPHICS_DRIVER_MISMATCH;
+ if (Header.VendorID == REDHAT_PCI_VENDOR_ID &&
+ Header.DeviceID == 0x0100 &&
+ Header.RevisionID == 4)
+ {
+ Status = STATUS_SUCCESS;
+ }
+
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s returned with status 0x%X\n", __FUNCTION__, Status));
+ return Status;
+}
+
+NTSTATUS QxlDod::StartDevice(_In_ DXGK_START_INFO* pDxgkStartInfo,
+ _In_ DXGKRNL_INTERFACE* pDxgkInterface,
+ _Out_ ULONG* pNumberOfViews,
+ _Out_ ULONG* pNumberOfChildren)
+{
+ PAGED_CODE();
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__));
+ QXL_ASSERT(pDxgkStartInfo != NULL);
+ QXL_ASSERT(pDxgkInterface != NULL);
+ QXL_ASSERT(pNumberOfViews != NULL);
+ QXL_ASSERT(pNumberOfChildren != NULL);
+//CHECK ME!!!!!!!!!!!!!
+ RtlCopyMemory(&m_DxgkInterface, pDxgkInterface, sizeof(m_DxgkInterface));
+ RtlZeroMemory(m_CurrentModes, sizeof(m_CurrentModes));
+//CHECK ME!!!!!!!!!!!!!
+ m_CurrentModes[0].DispInfo.TargetId = D3DDDI_ID_UNINITIALIZED;
+ // Get device information from OS.
+ NTSTATUS Status = m_DxgkInterface.DxgkCbGetDeviceInformation(m_DxgkInterface.DeviceHandle, &m_DeviceInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ QXL_LOG_ASSERTION1("DxgkCbGetDeviceInformation failed with status 0x%X\n",
+ Status);
+ return Status;
+ }
+
+ Status = RegisterHWInfo();
+ if (!NT_SUCCESS(Status))
+ {
+ QXL_LOG_ASSERTION1("RegisterHWInfo failed with status 0x%X\n",
+ Status);
+ return Status;
+ }
+
+ // This sample driver only uses the frame buffer of the POST device. DxgkCbAcquirePostDisplayOwnership
+ // gives you the frame buffer address and ensures that no one else is drawing to it. Be sure to give it back!
+ Status = m_DxgkInterface.DxgkCbAcquirePostDisplayOwnership(m_DxgkInterface.DeviceHandle, &(m_CurrentModes[0].DispInfo));
+ if (!NT_SUCCESS(Status) || m_CurrentModes[0].DispInfo.Width == 0)
+ {
+ // The most likely cause of failure is that the driver is simply not running on a POST device, or we are running
+ // after a pre-WDDM 1.2 driver. Since we can't draw anything, we should fail to start.
+ DbgPrint(TRACE_LEVEL_ERROR, ("DxgkCbAcquirePostDisplayOwnership failed with status 0x%X Width = %d\n",
+ Status, m_CurrentModes[0].DispInfo.Width));
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ Status = CheckHardware();
+ if (NT_SUCCESS(Status))
+ {
+ m_pHWDevice = new(PagedPool) QxlDevice(this);
+ }
+ else
+ {
+ m_pHWDevice = new(PagedPool) VgaDevice(this);
+ }
+
+ Status = m_pHWDevice->HWInit(m_DeviceInfo.TranslatedResourceList, &m_CurrentModes[0].DispInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("HWInit failed with status 0x%X\n", Status));
+ return Status;
+ }
+
+ *pNumberOfViews = MAX_VIEWS;
+ *pNumberOfChildren = MAX_CHILDREN;
+ m_Flags.DriverStarted = TRUE;
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__));
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS QxlDod::StopDevice(VOID)
+{
+ PAGED_CODE();
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__));
+ m_Flags.DriverStarted = FALSE;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return STATUS_SUCCESS;
+}
+
+VOID QxlDod::CleanUp(VOID)
+{
+ PAGED_CODE();
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ for (UINT Source = 0; Source < MAX_VIEWS; ++Source)
+ {
+ if (m_CurrentModes[Source].FrameBuffer.Ptr)
+ {
+ UnmapFrameBuffer(m_CurrentModes[Source].FrameBuffer.Ptr, m_CurrentModes[Source].DispInfo.Height * m_CurrentModes[Source].DispInfo.Pitch);
+ m_CurrentModes[Source].FrameBuffer.Ptr = NULL;
+ m_CurrentModes[Source].Flags.FrameBufferIsActive = FALSE;
+ }
+ }
+}
+
+
+NTSTATUS QxlDod::DispatchIoRequest(_In_ ULONG VidPnSourceId,
+ _In_ VIDEO_REQUEST_PACKET* pVideoRequestPacket)
+{
+ PAGED_CODE();
+ UNREFERENCED_PARAMETER(VidPnSourceId);
+ UNREFERENCED_PARAMETER(pVideoRequestPacket);
+
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__));
+ return STATUS_SUCCESS;
+}
+
+PCHAR
+DbgDevicePowerString(
+ __in DEVICE_POWER_STATE Type
+ )
+{
+ switch (Type)
+ {
+ case PowerDeviceUnspecified:
+ return "PowerDeviceUnspecified";
+ case PowerDeviceD0:
+ return "PowerDeviceD0";
+ case PowerDeviceD1:
+ return "PowerDeviceD1";
+ case PowerDeviceD2:
+ return "PowerDeviceD2";
+ case PowerDeviceD3:
+ return "PowerDeviceD3";
+ case PowerDeviceMaximum:
+ return "PowerDeviceMaximum";
+ default:
+ return "UnKnown Device Power State";
+ }
+}
+
+PCHAR
+DbgPowerActionString(
+ __in POWER_ACTION Type
+ )
+{
+ switch (Type)
+ {
+ case PowerActionNone:
+ return "PowerActionNone";
+ case PowerActionReserved:
+ return "PowerActionReserved";
+ case PowerActionSleep:
+ return "PowerActionSleep";
+ case PowerActionHibernate:
+ return "PowerActionHibernate";
+ case PowerActionShutdown:
+ return "PowerActionShutdown";
+ case PowerActionShutdownReset:
+ return "PowerActionShutdownReset";
+ case PowerActionShutdownOff:
+ return "PowerActionShutdownOff";
+ case PowerActionWarmEject:
+ return "PowerActionWarmEject";
+ default:
+ return "UnKnown Device Power State";
+ }
+}
+
+NTSTATUS QxlDod::SetPowerState(_In_ ULONG HardwareUid,
+ _In_ DEVICE_POWER_STATE DevicePowerState,
+ _In_ POWER_ACTION ActionType)
+{
+ PAGED_CODE();
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s HardwareUid = 0x%x ActionType = %s DevicePowerState = %s AdapterPowerState = %s\n", __FUNCTION__, HardwareUid, DbgPowerActionString(ActionType), DbgDevicePowerString(DevicePowerState), DbgDevicePowerString(m_AdapterPowerState)));
+
+ if (HardwareUid == DISPLAY_ADAPTER_HW_ID)
+ {
+ if (DevicePowerState == PowerDeviceD0)
+ {
+
+ // When returning from D3 the device visibility defined to be off for all targets
+ if (m_AdapterPowerState == PowerDeviceD3)
+ {
+ DXGKARG_SETVIDPNSOURCEVISIBILITY Visibility;
+ Visibility.VidPnSourceId = D3DDDI_ID_ALL;
+ Visibility.Visible = FALSE;
+ SetVidPnSourceVisibility(&Visibility);
+ }
+ }
+
+ // Store new adapter power state
+ m_AdapterPowerState = DevicePowerState;
+
+ // There is nothing to do to specifically power up/down the display adapter
+ return m_pHWDevice->SetPowerState(DevicePowerState, &(m_CurrentModes[0].DispInfo));
+ }
+ // TODO: This is where the specified monitor should be powered up/down
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS QxlDod::QueryChildRelations(_Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations,
+ _In_ ULONG ChildRelationsSize)
+{
+ PAGED_CODE();
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ QXL_ASSERT(pChildRelations != NULL);
+
+ // The last DXGK_CHILD_DESCRIPTOR in the array of pChildRelations must remain zeroed out, so we subtract this from the count
+ ULONG ChildRelationsCount = (ChildRelationsSize / sizeof(DXGK_CHILD_DESCRIPTOR)) - 1;
+ QXL_ASSERT(ChildRelationsCount <= MAX_CHILDREN);
+
+ for (UINT ChildIndex = 0; ChildIndex < ChildRelationsCount; ++ChildIndex)
+ {
+ pChildRelations[ChildIndex].ChildDeviceType = TypeVideoOutput;
+ pChildRelations[ChildIndex].ChildCapabilities.HpdAwareness = HpdAwarenessAlwaysConnected;
+ pChildRelations[ChildIndex].ChildCapabilities.Type.VideoOutput.InterfaceTechnology = D3DKMDT_VOT_INTERNAL;
+ pChildRelations[ChildIndex].ChildCapabilities.Type.VideoOutput.MonitorOrientationAwareness = D3DKMDT_MOA_NONE;
+ pChildRelations[ChildIndex].ChildCapabilities.Type.VideoOutput.SupportsSdtvModes = FALSE;
+ // TODO: Replace 0 with the actual ACPI ID of the child device, if available
+ pChildRelations[ChildIndex].AcpiUid = 0;
+ pChildRelations[ChildIndex].ChildUid = ChildIndex;
+ }
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS QxlDod::QueryChildStatus(_Inout_ DXGK_CHILD_STATUS* pChildStatus,
+ _In_ BOOLEAN NonDestructiveOnly)
+{
+ PAGED_CODE();
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ UNREFERENCED_PARAMETER(NonDestructiveOnly);
+ QXL_ASSERT(pChildStatus != NULL);
+ QXL_ASSERT(pChildStatus->ChildUid < MAX_CHILDREN);
+
+ switch (pChildStatus->Type)
+ {
+ case StatusConnection:
+ {
+ // HpdAwarenessInterruptible was reported since HpdAwarenessNone is deprecated.
+ // However, BDD has no knowledge of HotPlug events, so just always return connected.
+ pChildStatus->HotPlug.Connected = IsDriverActive();
+ return STATUS_SUCCESS;
+ }
+
+ case StatusRotation:
+ {
+ // D3DKMDT_MOA_NONE was reported, so this should never be called
+ DbgPrint(TRACE_LEVEL_ERROR, ("Child status being queried for StatusRotation even though D3DKMDT_MOA_NONE was reported"));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ default:
+ {
+ DbgPrint(TRACE_LEVEL_WARNING, ("Unknown pChildStatus->Type (0x%I64x) requested.", pChildStatus->Type));
+ return STATUS_NOT_SUPPORTED;
+ }
+ }
+}
+
+// EDID retrieval
+NTSTATUS QxlDod::QueryDeviceDescriptor(_In_ ULONG ChildUid,
+ _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor)
+{
+ PAGED_CODE();
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ QXL_ASSERT(pDeviceDescriptor != NULL);
+ QXL_ASSERT(ChildUid < MAX_CHILDREN);
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA;
+}
+
+NTSTATUS QxlDod::QueryAdapterInfo(_In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo)
+{
+ PAGED_CODE();
+
+ QXL_ASSERT(pQueryAdapterInfo != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ switch (pQueryAdapterInfo->Type)
+ {
+ case DXGKQAITYPE_DRIVERCAPS:
+ {
+ if (!pQueryAdapterInfo->OutputDataSize/* < sizeof(DXGK_DRIVERCAPS)*/)
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pQueryAdapterInfo->OutputDataSize (0x%u) is smaller than sizeof(DXGK_DRIVERCAPS) (0x%u)\n", pQueryAdapterInfo->OutputDataSize, sizeof(DXGK_DRIVERCAPS)));
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ DXGK_DRIVERCAPS* pDriverCaps = (DXGK_DRIVERCAPS*)pQueryAdapterInfo->pOutputData;
+
+ RtlZeroMemory(pDriverCaps, pQueryAdapterInfo->OutputDataSize/*sizeof(DXGK_DRIVERCAPS)*/);
+
+ pDriverCaps->WDDMVersion = DXGKDDI_WDDMv1_2;
+ pDriverCaps->HighestAcceptableAddress.QuadPart = -1;
+
+ if (m_pHWDevice->EnablePointer()) {
+ pDriverCaps->MaxPointerWidth = POINTER_SIZE;
+ pDriverCaps->MaxPointerHeight = POINTER_SIZE;
+ pDriverCaps->PointerCaps.Monochrome = 1;
+ pDriverCaps->PointerCaps.Color = 1;
+ }
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s 1\n", __FUNCTION__));
+ return STATUS_SUCCESS;
+ }
+
+ default:
+ {
+ // BDD does not need to support any other adapter information types
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return STATUS_NOT_SUPPORTED;
+ }
+ }
+}
+
+NTSTATUS QxlDod::SetPointerPosition(_In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition)
+{
+ PAGED_CODE();
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ QXL_ASSERT(pSetPointerPosition != NULL);
+ QXL_ASSERT(pSetPointerPosition->VidPnSourceId < MAX_VIEWS);
+
+ if (!(pSetPointerPosition->Flags.Visible))
+ {
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s Cursor is not visible\n", __FUNCTION__));
+ return STATUS_SUCCESS;
+ }
+ return m_pHWDevice->SetPointerPosition(pSetPointerPosition);
+}
+
+// Basic Sample Display Driver does not support hardware cursors, and reports such
+// in QueryAdapterInfo. Therefore this function should never be called.
+NTSTATUS QxlDod::SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape)
+{
+ PAGED_CODE();
+ QXL_ASSERT(pSetPointerShape != NULL);
+
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s Height = %d, Width = %d, XHot= %d, YHot = %d SourceId = %d\n",
+ __FUNCTION__, pSetPointerShape->Height, pSetPointerShape->Width, pSetPointerShape->XHot, pSetPointerShape->YHot, pSetPointerShape->VidPnSourceId));
+ return m_pHWDevice->SetPointerShape(pSetPointerShape);
+}
+
+NTSTATUS QxlDod::Escape(_In_ CONST DXGKARG_ESCAPE* pEscape)
+{
+ PAGED_CODE();
+ QXL_ASSERT(pEscape != NULL);
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s Flags = %d\n", __FUNCTION__, pEscape->Flags));
+
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+
+NTSTATUS QxlDod::PresentDisplayOnly(_In_ CONST DXGKARG_PRESENT_DISPLAYONLY* pPresentDisplayOnly)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_SUCCESS;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ QXL_ASSERT(pPresentDisplayOnly != NULL);
+ QXL_ASSERT(pPresentDisplayOnly->VidPnSourceId < MAX_VIEWS);
+
+ if (pPresentDisplayOnly->BytesPerPixel < 4)
+ {
+ // Only >=32bpp modes are reported, therefore this Present should never pass anything less than 4 bytes per pixel
+ DbgPrint(TRACE_LEVEL_ERROR, ("pPresentDisplayOnly->BytesPerPixel is 0x%d, which is lower than the allowed.\n", pPresentDisplayOnly->BytesPerPixel));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ // If it is in monitor off state or source is not supposed to be visible, don't present anything to the screen
+ if ((m_MonitorPowerState > PowerDeviceD0) ||
+ (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].Flags.SourceNotVisible))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("<--- %s\n", __FUNCTION__));
+ return STATUS_SUCCESS;
+ }
+
+ if (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].Flags.FrameBufferIsActive)
+ {
+
+ // If actual pixels are coming through, will need to completely zero out physical address next time in BlackOutScreen
+ m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].ZeroedOutStart.QuadPart = 0;
+ m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].ZeroedOutEnd.QuadPart = 0;
+
+
+ D3DKMDT_VIDPN_PRESENT_PATH_ROTATION RotationNeededByFb = pPresentDisplayOnly->Flags.Rotate ?
+ m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].Rotation :
+ D3DKMDT_VPPR_IDENTITY;
+ BYTE* pDst = (BYTE*)m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].FrameBuffer.Ptr;
+ UINT DstBitPerPixel = BPPFromPixelFormat(m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].DispInfo.ColorFormat);
+ if (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].Scaling == D3DKMDT_VPPS_CENTERED)
+ {
+ UINT CenterShift = (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].DispInfo.Height -
+ m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].SrcModeHeight)*m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].DispInfo.Pitch;
+ CenterShift += (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].DispInfo.Width -
+ m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].SrcModeWidth)*DstBitPerPixel/8;
+ pDst += (int)CenterShift/2;
+ }
+ Status = m_pHWDevice->ExecutePresentDisplayOnly(
+ pDst,
+ DstBitPerPixel,
+ (BYTE*)pPresentDisplayOnly->pSource,
+ pPresentDisplayOnly->BytesPerPixel,
+ pPresentDisplayOnly->Pitch,
+ pPresentDisplayOnly->NumMoves,
+ pPresentDisplayOnly->pMoves,
+ pPresentDisplayOnly->NumDirtyRects,
+ pPresentDisplayOnly->pDirtyRect,
+ RotationNeededByFb,
+ &m_CurrentModes[0]);
+ }
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return Status;
+}
+
+NTSTATUS QxlDod::QueryInterface(_In_ CONST PQUERY_INTERFACE pQueryInterface)
+{
+ PAGED_CODE();
+ QXL_ASSERT(pQueryInterface != NULL);
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s Version = %d\n", __FUNCTION__, pQueryInterface->Version));
+
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS QxlDod::StopDeviceAndReleasePostDisplayOwnership(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
+ _Out_ DXGK_DISPLAY_INFORMATION* pDisplayInfo)
+{
+ PAGED_CODE();
+
+ UNREFERENCED_PARAMETER(pDisplayInfo);
+ QXL_ASSERT(TargetId < MAX_CHILDREN);
+ D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId = FindSourceForTarget(TargetId, TRUE);
+
+ // In case BDD is the next driver to run, the monitor should not be off, since
+ // this could cause the BIOS to hang when the EDID is retrieved on Start.
+ if (m_MonitorPowerState > PowerDeviceD0)
+ {
+ SetPowerState(TargetId, PowerDeviceD0, PowerActionNone);
+ }
+
+ // The driver has to black out the display and ensure it is visible when releasing ownership
+ m_pHWDevice->BlackOutScreen(&m_CurrentModes[SourceId]);
+
+ *pDisplayInfo = m_CurrentModes[SourceId].DispInfo;
+
+ return StopDevice();
+}
+
+
+NTSTATUS QxlDod::QueryVidPnHWCapability(_Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps)
+{
+ PAGED_CODE();
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ QXL_ASSERT(pVidPnHWCaps != NULL);
+ QXL_ASSERT(pVidPnHWCaps->SourceId < MAX_VIEWS);
+ QXL_ASSERT(pVidPnHWCaps->TargetId < MAX_CHILDREN);
+
+ pVidPnHWCaps->VidPnHWCaps.DriverRotation = 1; // BDD does rotation in software
+ pVidPnHWCaps->VidPnHWCaps.DriverScaling = 0; // BDD does not support scaling
+ pVidPnHWCaps->VidPnHWCaps.DriverCloning = 0; // BDD does not support clone
+ pVidPnHWCaps->VidPnHWCaps.DriverColorConvert = 1; // BDD does color conversions in software
+ pVidPnHWCaps->VidPnHWCaps.DriverLinkedAdapaterOutput = 0; // BDD does not support linked adapters
+ pVidPnHWCaps->VidPnHWCaps.DriverRemoteDisplay = 0; // BDD does not support remote displays
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return STATUS_SUCCESS;
+}
+
+
+// TODO: Need to also check pinned modes and the path parameters, not just topology
+NTSTATUS QxlDod::IsSupportedVidPn(_Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn)
+{
+ PAGED_CODE();
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ QXL_ASSERT(pIsSupportedVidPn != NULL);
+
+ if (pIsSupportedVidPn->hDesiredVidPn == 0)
+ {
+ // A null desired VidPn is supported
+ pIsSupportedVidPn->IsVidPnSupported = TRUE;
+ return STATUS_SUCCESS;
+ }
+
+ // Default to not supported, until shown it is supported
+ pIsSupportedVidPn->IsVidPnSupported = FALSE;
+
+ CONST DXGK_VIDPN_INTERFACE* pVidPnInterface;
+ NTSTATUS Status = m_DxgkInterface.DxgkCbQueryVidPnInterface(pIsSupportedVidPn->hDesiredVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("DxgkCbQueryVidPnInterface failed with Status = 0x%X, hDesiredVidPn = 0x%I64x\n", Status, pIsSupportedVidPn->hDesiredVidPn));
+ return Status;
+ }
+
+ D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology;
+ CONST DXGK_VIDPNTOPOLOGY_INTERFACE* pVidPnTopologyInterface;
+ Status = pVidPnInterface->pfnGetTopology(pIsSupportedVidPn->hDesiredVidPn, &hVidPnTopology, &pVidPnTopologyInterface);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnGetTopology failed with Status = 0x%X, hDesiredVidPn = 0x%I64x\n", Status, pIsSupportedVidPn->hDesiredVidPn));
+ return Status;
+ }
+
+ // For every source in this topology, make sure they don't have more paths than there are targets
+ for (D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId = 0; SourceId < MAX_VIEWS; ++SourceId)
+ {
+ SIZE_T NumPathsFromSource = 0;
+ Status = pVidPnTopologyInterface->pfnGetNumPathsFromSource(hVidPnTopology, SourceId, &NumPathsFromSource);
+ if (Status == STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY)
+ {
+ continue;
+ }
+ else if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnGetNumPathsFromSource failed with Status = 0x%X hVidPnTopology = 0x%I64x, SourceId = 0x%I64x",
+ Status, hVidPnTopology, SourceId));
+ return Status;
+ }
+ else if (NumPathsFromSource > MAX_CHILDREN)
+ {
+ // This VidPn is not supported, which has already been set as the default
+ return STATUS_SUCCESS;
+ }
+ }
+
+ // All sources succeeded so this VidPn is supported
+ pIsSupportedVidPn->IsVidPnSupported = TRUE;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS QxlDod::RecommendFunctionalVidPn(_In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn)
+{
+ PAGED_CODE();
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QXL_ASSERT(pRecommendFunctionalVidPn == NULL);
+
+ return STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN;
+}
+
+NTSTATUS QxlDod::RecommendVidPnTopology(_In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology)
+{
+ PAGED_CODE();
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QXL_ASSERT(pRecommendVidPnTopology == NULL);
+
+ return STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN;
+}
+
+NTSTATUS QxlDod::RecommendMonitorModes(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes)
+{
+ PAGED_CODE();
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ return AddSingleMonitorMode(pRecommendMonitorModes);
+}
+
+
+NTSTATUS QxlDod::AddSingleSourceMode(_In_ CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface,
+ D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet,
+ D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId)
+{
+ PAGED_CODE();
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ UNREFERENCED_PARAMETER(SourceId);
+
+ // There is only one source format supported by display-only drivers, but more can be added in a
+ // full WDDM driver if the hardware supports them
+ for (ULONG idx = 0; idx < m_pHWDevice->GetModeCount(); ++idx)
+ {
+ // Create new mode info that will be populated
+ D3DKMDT_VIDPN_SOURCE_MODE* pVidPnSourceModeInfo = NULL;
+ PVIDEO_MODE_INFORMATION pModeInfo = m_pHWDevice->GetModeInfo(idx);
+ NTSTATUS Status = pVidPnSourceModeSetInterface->pfnCreateNewModeInfo(hVidPnSourceModeSet, &pVidPnSourceModeInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ // If failed to create a new mode info, mode doesn't need to be released since it was never created
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnCreateNewModeInfo failed with Status = 0x%X, hVidPnSourceModeSet = 0x%I64x", Status, hVidPnSourceModeSet));
+ return Status;
+ }
+
+ // Populate mode info with values from current mode and hard-coded values
+ // Always report 32 bpp format, this will be color converted during the present if the mode is < 32bpp
+ pVidPnSourceModeInfo->Type = D3DKMDT_RMT_GRAPHICS;
+ pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cx = pModeInfo->VisScreenWidth;
+ pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cy = pModeInfo->VisScreenHeight;
+ pVidPnSourceModeInfo->Format.Graphics.VisibleRegionSize = pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize;
+ pVidPnSourceModeInfo->Format.Graphics.Stride = pModeInfo->ScreenStride;
+ pVidPnSourceModeInfo->Format.Graphics.PixelFormat = D3DDDIFMT_A8R8G8B8;
+ pVidPnSourceModeInfo->Format.Graphics.ColorBasis = D3DKMDT_CB_SCRGB;
+ pVidPnSourceModeInfo->Format.Graphics.PixelValueAccessMode = D3DKMDT_PVAM_DIRECT;
+
+ // Add the mode to the source mode set
+ Status = pVidPnSourceModeSetInterface->pfnAddMode(hVidPnSourceModeSet, pVidPnSourceModeInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ // If adding the mode failed, release the mode, if this doesn't work there is nothing that can be done, some memory will get leaked
+ NTSTATUS TempStatus = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnSourceModeInfo);
+ UNREFERENCED_PARAMETER(TempStatus);
+ NT_ASSERT(NT_SUCCESS(TempStatus));
+
+ if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET)
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnAddMode failed with Status = 0x%X, hVidPnSourceModeSet = 0x%I64x, pVidPnSourceModeInfo = 0x%I64x", Status, hVidPnSourceModeSet, pVidPnSourceModeInfo));
+ return Status;
+ }
+ }
+ }
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return STATUS_SUCCESS;
+}
+
+// Add the current mode information (acquired from the POST frame buffer) as the target mode.
+NTSTATUS QxlDod::AddSingleTargetMode(_In_ CONST DXGK_VIDPNTARGETMODESET_INTERFACE* pVidPnTargetModeSetInterface,
+ D3DKMDT_HVIDPNTARGETMODESET hVidPnTargetModeSet,
+ _In_opt_ CONST D3DKMDT_VIDPN_SOURCE_MODE* pVidPnPinnedSourceModeInfo,
+ D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId)
+{
+ PAGED_CODE();
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ UNREFERENCED_PARAMETER(pVidPnPinnedSourceModeInfo);
+
+ D3DKMDT_VIDPN_TARGET_MODE* pVidPnTargetModeInfo = NULL;
+ NTSTATUS Status = STATUS_SUCCESS;
+//FIXME !!!!!!
+ for (UINT ModeIndex = 0; ModeIndex < m_pHWDevice->GetModeCount(); ++ModeIndex)
+ {
+ PVIDEO_MODE_INFORMATION pModeInfo = m_pHWDevice->GetModeInfo(SourceId);
+ pVidPnTargetModeInfo = NULL;
+ Status = pVidPnTargetModeSetInterface->pfnCreateNewModeInfo(hVidPnTargetModeSet, &pVidPnTargetModeInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ // If failed to create a new mode info, mode doesn't need to be released since it was never created
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnCreateNewModeInfo failed with Status = 0x%I64x, hVidPnTargetModeSet = 0x%I64x", Status, hVidPnTargetModeSet));
+ return Status;
+ }
+ pVidPnTargetModeInfo->VideoSignalInfo.VideoStandard = D3DKMDT_VSS_OTHER;
+ pVidPnTargetModeInfo->VideoSignalInfo.TotalSize.cx = pModeInfo->VisScreenWidth;
+ pVidPnTargetModeInfo->VideoSignalInfo.TotalSize.cy = pModeInfo->VisScreenHeight;
+ pVidPnTargetModeInfo->VideoSignalInfo.ActiveSize = pVidPnTargetModeInfo->VideoSignalInfo.TotalSize;
+ pVidPnTargetModeInfo->VideoSignalInfo.VSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
+ pVidPnTargetModeInfo->VideoSignalInfo.VSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
+ pVidPnTargetModeInfo->VideoSignalInfo.HSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
+ pVidPnTargetModeInfo->VideoSignalInfo.HSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
+ pVidPnTargetModeInfo->VideoSignalInfo.PixelRate = D3DKMDT_FREQUENCY_NOTSPECIFIED;
+ pVidPnTargetModeInfo->VideoSignalInfo.ScanLineOrdering = D3DDDI_VSSLO_PROGRESSIVE;
+ // We add this as PREFERRED since it is the only supported target
+ pVidPnTargetModeInfo->Preference = D3DKMDT_MP_NOTPREFERRED; // TODO: another logic for prefferred mode. Maybe the pinned source mode
+
+ Status = pVidPnTargetModeSetInterface->pfnAddMode(hVidPnTargetModeSet, pVidPnTargetModeInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET)
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnAddMode failed with Status = 0x%I64x, hVidPnTargetModeSet = 0x%I64x, pVidPnTargetModeInfo = 0x%I64x", Status, hVidPnTargetModeSet, pVidPnTargetModeInfo));
+ }
+
+ // If adding the mode failed, release the mode, if this doesn't work there is nothing that can be done, some memory will get leaked
+ Status = pVidPnTargetModeSetInterface->pfnReleaseModeInfo(hVidPnTargetModeSet, pVidPnTargetModeInfo);
+ NT_ASSERT(NT_SUCCESS(Status));
+ }
+ }
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS QxlDod::AddSingleMonitorMode(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_SUCCESS;
+ D3DKMDT_MONITOR_SOURCE_MODE* pMonitorSourceMode = NULL;
+ PVIDEO_MODE_INFORMATION pVbeModeInfo = NULL;
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ Status = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnCreateNewModeInfo(pRecommendMonitorModes->hMonitorSourceModeSet, &pMonitorSourceMode);
+ if (!NT_SUCCESS(Status))
+ {
+ // If failed to create a new mode info, mode doesn't need to be released since it was never created
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnCreateNewModeInfo failed with Status = 0x%X, hMonitorSourceModeSet = 0x%I64x", Status, pRecommendMonitorModes->hMonitorSourceModeSet));
+ return Status;
+ }
+
+ pVbeModeInfo = m_pHWDevice->GetModeInfo(m_pHWDevice->GetCurrentModeIndex());
+
+ // Since we don't know the real monitor timing information, just use the current display mode (from the POST device) with unknown frequencies
+ pMonitorSourceMode->VideoSignalInfo.VideoStandard = D3DKMDT_VSS_OTHER;
+ pMonitorSourceMode->VideoSignalInfo.TotalSize.cx = pVbeModeInfo->VisScreenWidth;
+ pMonitorSourceMode->VideoSignalInfo.TotalSize.cy = pVbeModeInfo->VisScreenHeight;
+ pMonitorSourceMode->VideoSignalInfo.ActiveSize = pMonitorSourceMode->VideoSignalInfo.TotalSize;
+ pMonitorSourceMode->VideoSignalInfo.VSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
+ pMonitorSourceMode->VideoSignalInfo.VSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
+ pMonitorSourceMode->VideoSignalInfo.HSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
+ pMonitorSourceMode->VideoSignalInfo.HSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
+ pMonitorSourceMode->VideoSignalInfo.PixelRate = D3DKMDT_FREQUENCY_NOTSPECIFIED;
+ pMonitorSourceMode->VideoSignalInfo.ScanLineOrdering = D3DDDI_VSSLO_PROGRESSIVE;
+
+ // We set the preference to PREFERRED since this is the only supported mode
+ pMonitorSourceMode->Origin = D3DKMDT_MCO_DRIVER;
+ pMonitorSourceMode->Preference = D3DKMDT_MP_PREFERRED;
+ pMonitorSourceMode->ColorBasis = D3DKMDT_CB_SRGB;
+ pMonitorSourceMode->ColorCoeffDynamicRanges.FirstChannel = 8;
+ pMonitorSourceMode->ColorCoeffDynamicRanges.SecondChannel = 8;
+ pMonitorSourceMode->ColorCoeffDynamicRanges.ThirdChannel = 8;
+ pMonitorSourceMode->ColorCoeffDynamicRanges.FourthChannel = 8;
+
+ Status = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnAddMode(pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode);
+ if (!NT_SUCCESS(Status))
+ {
+ if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET)
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnAddMode failed with Status = 0x%X, hMonitorSourceModeSet = 0x%I64x, pMonitorSourceMode = 0x%I64x",
+ Status, pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode));
+ }
+ else
+ {
+ Status = STATUS_SUCCESS;
+ }
+
+ // If adding the mode failed, release the mode, if this doesn't work there is nothing that can be done, some memory will get leaked
+ NTSTATUS TempStatus = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnReleaseModeInfo(pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode);
+ UNREFERENCED_PARAMETER(TempStatus);
+ NT_ASSERT(NT_SUCCESS(TempStatus));
+ return Status;
+ }
+ // If AddMode succeeded with something other than STATUS_SUCCESS treat it as such anyway when propagating up
+ for (UINT Idx = 0; Idx < m_pHWDevice->GetModeCount(); ++Idx)
+ {
+ // There is only one source format supported by display-only drivers, but more can be added in a
+ // full WDDM driver if the hardware supports them
+
+ pVbeModeInfo = m_pHWDevice->GetModeInfo(Idx);
+ // TODO: add routine for filling Monitor modepMonitorSourceMode = NULL;
+ Status = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnCreateNewModeInfo(pRecommendMonitorModes->hMonitorSourceModeSet, &pMonitorSourceMode);
+ if (!NT_SUCCESS(Status))
+ {
+ // If failed to create a new mode info, mode doesn't need to be released since it was never created
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnCreateNewModeInfo failed with Status = 0x%I64x, hMonitorSourceModeSet = 0x%I64x", Status, pRecommendMonitorModes->hMonitorSourceModeSet));
+ return Status;
+ }
+
+
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("%s: add pref mode, dimensions %ux%u, taken from DxgkCbAcquirePostDisplayOwnership at StartDevice\n", __FUNCTION__,
+ pVbeModeInfo->VisScreenWidth, pVbeModeInfo->VisScreenHeight));
+
+ // Since we don't know the real monitor timing information, just use the current display mode (from the POST device) with unknown frequencies
+ pMonitorSourceMode->VideoSignalInfo.VideoStandard = D3DKMDT_VSS_OTHER;
+ pMonitorSourceMode->VideoSignalInfo.TotalSize.cx = pVbeModeInfo->VisScreenWidth;
+ pMonitorSourceMode->VideoSignalInfo.TotalSize.cy = pVbeModeInfo->VisScreenHeight;
+ pMonitorSourceMode->VideoSignalInfo.ActiveSize = pMonitorSourceMode->VideoSignalInfo.TotalSize;
+ pMonitorSourceMode->VideoSignalInfo.VSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
+ pMonitorSourceMode->VideoSignalInfo.VSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
+ pMonitorSourceMode->VideoSignalInfo.HSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
+ pMonitorSourceMode->VideoSignalInfo.HSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
+ pMonitorSourceMode->VideoSignalInfo.PixelRate = D3DKMDT_FREQUENCY_NOTSPECIFIED;
+ pMonitorSourceMode->VideoSignalInfo.ScanLineOrdering = D3DDDI_VSSLO_PROGRESSIVE; //???
+
+ pMonitorSourceMode->Origin = D3DKMDT_MCO_DRIVER; // ????
+ pMonitorSourceMode->Preference = D3DKMDT_MP_NOTPREFERRED; // TODO...
+ pMonitorSourceMode->ColorBasis = D3DKMDT_CB_SRGB; // ????
+ pMonitorSourceMode->ColorCoeffDynamicRanges.FirstChannel = 8;
+ pMonitorSourceMode->ColorCoeffDynamicRanges.SecondChannel = 8;
+ pMonitorSourceMode->ColorCoeffDynamicRanges.ThirdChannel = 8;
+ pMonitorSourceMode->ColorCoeffDynamicRanges.FourthChannel = 8;
+
+ Status = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnAddMode(pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode);
+ if (!NT_SUCCESS(Status))
+ {
+ if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET)
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnAddMode failed with Status = 0x%I64x, hMonitorSourceModeSet = 0x%I64x, pMonitorSourceMode = 0x%I64x",
+ Status, pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode));
+ }
+
+ // If adding the mode failed, release the mode, if this doesn't work there is nothing that can be done, some memory will get leaked
+ Status = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnReleaseModeInfo(pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode);
+ NT_ASSERT(NT_SUCCESS(Status));
+ }
+ }
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return Status;
+}
+
+// Tell DMM about all the modes, etc. that are supported
+NTSTATUS QxlDod::EnumVidPnCofuncModality(_In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality)
+{
+ PAGED_CODE();
+
+ QXL_ASSERT(pEnumCofuncModality != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology = 0;
+ D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet = 0;
+ D3DKMDT_HVIDPNTARGETMODESET hVidPnTargetModeSet = 0;
+ CONST DXGK_VIDPN_INTERFACE* pVidPnInterface = NULL;
+ CONST DXGK_VIDPNTOPOLOGY_INTERFACE* pVidPnTopologyInterface = NULL;
+ CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface = NULL;
+ CONST DXGK_VIDPNTARGETMODESET_INTERFACE* pVidPnTargetModeSetInterface = NULL;
+ CONST D3DKMDT_VIDPN_PRESENT_PATH* pVidPnPresentPath = NULL;
+ CONST D3DKMDT_VIDPN_PRESENT_PATH* pVidPnPresentPathTemp = NULL; // Used for AcquireNextPathInfo
+ CONST D3DKMDT_VIDPN_SOURCE_MODE* pVidPnPinnedSourceModeInfo = NULL;
+ CONST D3DKMDT_VIDPN_TARGET_MODE* pVidPnPinnedTargetModeInfo = NULL;
+
+ // Get the VidPn Interface so we can get the 'Source Mode Set', 'Target Mode Set' and 'VidPn Topology' interfaces
+ NTSTATUS Status = m_DxgkInterface.DxgkCbQueryVidPnInterface(pEnumCofuncModality->hConstrainingVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("DxgkCbQueryVidPnInterface failed with Status = 0x%X, hFunctionalVidPn = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn));
+ return Status;
+ }
+
+ // Get the VidPn Topology interface so we can enumerate all paths
+ Status = pVidPnInterface->pfnGetTopology(pEnumCofuncModality->hConstrainingVidPn, &hVidPnTopology, &pVidPnTopologyInterface);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnGetTopology failed with Status = 0x%X, hFunctionalVidPn = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn));
+ return Status;
+ }
+
+ // Get the first path before we start looping through them
+ Status = pVidPnTopologyInterface->pfnAcquireFirstPathInfo(hVidPnTopology, &pVidPnPresentPath);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquireFirstPathInfo failed with Status =0x%X, hVidPnTopology = 0x%I64x", Status, hVidPnTopology));
+ return Status;
+ }
+
+ // Loop through all available paths.
+ while (Status != STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET)
+ {
+ // Get the Source Mode Set interface so the pinned mode can be retrieved
+ Status = pVidPnInterface->pfnAcquireSourceModeSet(pEnumCofuncModality->hConstrainingVidPn,
+ pVidPnPresentPath->VidPnSourceId,
+ &hVidPnSourceModeSet,
+ &pVidPnSourceModeSetInterface);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquireSourceModeSet failed with Status = 0x%X, hConstrainingVidPn = 0x%I64x, SourceId = 0x%I64x",
+ Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId));
+ break;
+ }
+
+ // Get the pinned mode, needed when VidPnSource isn't pivot, and when VidPnTarget isn't pivot
+ Status = pVidPnSourceModeSetInterface->pfnAcquirePinnedModeInfo(hVidPnSourceModeSet, &pVidPnPinnedSourceModeInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquirePinnedModeInfo failed with Status = 0x%X, hVidPnSourceModeSet = 0x%I64x", Status, hVidPnSourceModeSet));
+ break;
+ }
+
+ // SOURCE MODES: If this source mode isn't the pivot point, do work on the source mode set
+ if (!((pEnumCofuncModality->EnumPivotType == D3DKMDT_EPT_VIDPNSOURCE) &&
+ (pEnumCofuncModality->EnumPivot.VidPnSourceId == pVidPnPresentPath->VidPnSourceId)))
+ {
+ // If there's no pinned source add possible modes (otherwise they've already been added)
+ if (pVidPnPinnedSourceModeInfo == NULL)
+ {
+ // Release the acquired source mode set, since going to create a new one to put all modes in
+ Status = pVidPnInterface->pfnReleaseSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnReleaseSourceModeSet failed with Status = 0x%X, hConstrainingVidPn = 0x%I64x, hVidPnSourceModeSet = 0x%I64x",
+ Status, pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet));
+ break;
+ }
+ hVidPnSourceModeSet = 0; // Successfully released it
+
+ // Create a new source mode set which will be added to the constraining VidPn with all the possible modes
+ Status = pVidPnInterface->pfnCreateNewSourceModeSet(pEnumCofuncModality->hConstrainingVidPn,
+ pVidPnPresentPath->VidPnSourceId,
+ &hVidPnSourceModeSet,
+ &pVidPnSourceModeSetInterface);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnCreateNewSourceModeSet failed with Status = 0x%X, hConstrainingVidPn = 0x%I64x, SourceId = 0x%I64x",
+ Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId));
+ break;
+ }
+
+ // Add the appropriate modes to the source mode set
+ {
+ Status = AddSingleSourceMode(pVidPnSourceModeSetInterface, hVidPnSourceModeSet, pVidPnPresentPath->VidPnSourceId);
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("AddSingleSourceMode failed with Status = 0x%X, hFunctionalVidPn = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn));
+ break;
+ }
+
+ // Give DMM back the source modes just populated
+ Status = pVidPnInterface->pfnAssignSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId, hVidPnSourceModeSet);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnAssignSourceModeSet failed with Status = 0x%X, hConstrainingVidPn = 0x%I64x, SourceId = 0x%I64x, hVidPnSourceModeSet = 0x%I64x",
+ Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId, hVidPnSourceModeSet));
+ break;
+ }
+ hVidPnSourceModeSet = 0; // Successfully assigned it (equivalent to releasing it)
+ }
+ }// End: SOURCE MODES
+
+ // TARGET MODES: If this target mode isn't the pivot point, do work on the target mode set
+ if (!((pEnumCofuncModality->EnumPivotType == D3DKMDT_EPT_VIDPNTARGET) &&
+ (pEnumCofuncModality->EnumPivot.VidPnTargetId == pVidPnPresentPath->VidPnTargetId)))
+ {
+ // Get the Target Mode Set interface so modes can be added if necessary
+ Status = pVidPnInterface->pfnAcquireTargetModeSet(pEnumCofuncModality->hConstrainingVidPn,
+ pVidPnPresentPath->VidPnTargetId,
+ &hVidPnTargetModeSet,
+ &pVidPnTargetModeSetInterface);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquireTargetModeSet failed with Status = 0x%X, hConstrainingVidPn = 0x%I64x, TargetId = 0x%I64x",
+ Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId));
+ break;
+ }
+
+ Status = pVidPnTargetModeSetInterface->pfnAcquirePinnedModeInfo(hVidPnTargetModeSet, &pVidPnPinnedTargetModeInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquirePinnedModeInfo failed with Status = 0x%X, hVidPnTargetModeSet = 0x%I64x", Status, hVidPnTargetModeSet));
+ break;
+ }
+
+ // If there's no pinned target add possible modes (otherwise they've already been added)
+ if (pVidPnPinnedTargetModeInfo == NULL)
+ {
+ // Release the acquired target mode set, since going to create a new one to put all modes in
+ Status = pVidPnInterface->pfnReleaseTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnReleaseTargetModeSet failed with Status = 0x%X, hConstrainingVidPn = 0x%I64x, hVidPnTargetModeSet = 0x%I64x",
+ Status, pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet));
+ break;
+ }
+ hVidPnTargetModeSet = 0; // Successfully released it
+
+ // Create a new target mode set which will be added to the constraining VidPn with all the possible modes
+ Status = pVidPnInterface->pfnCreateNewTargetModeSet(pEnumCofuncModality->hConstrainingVidPn,
+ pVidPnPresentPath->VidPnTargetId,
+ &hVidPnTargetModeSet,
+ &pVidPnTargetModeSetInterface);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnCreateNewTargetModeSet failed with Status = 0x%X, hConstrainingVidPn = 0x%I64x, TargetId = 0x%I64x",
+ Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId));
+ break;
+ }
+
+ Status = AddSingleTargetMode(pVidPnTargetModeSetInterface, hVidPnTargetModeSet, pVidPnPinnedSourceModeInfo, pVidPnPresentPath->VidPnSourceId);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("AddSingleTargetMode failed with Status = 0x%X, hFunctionalVidPn = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn));
+ break;
+ }
+
+ // Give DMM back the source modes just populated
+ Status = pVidPnInterface->pfnAssignTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId, hVidPnTargetModeSet);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnAssignTargetModeSet failed with Status = 0x%X, hConstrainingVidPn = 0x%I64x, TargetId = 0x%I64x, hVidPnTargetModeSet = 0x%I64x",
+ Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId, hVidPnTargetModeSet));
+ break;
+ }
+ hVidPnTargetModeSet = 0; // Successfully assigned it (equivalent to releasing it)
+ }
+ else
+ {
+ // Release the pinned target as there's no other work to do
+ Status = pVidPnTargetModeSetInterface->pfnReleaseModeInfo(hVidPnTargetModeSet, pVidPnPinnedTargetModeInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnReleaseModeInfo failed with Status = 0x%X, hVidPnTargetModeSet = 0x%I64x, pVidPnPinnedTargetModeInfo = 0x%I64x",
+ Status, hVidPnTargetModeSet, pVidPnPinnedTargetModeInfo));
+ break;
+ }
+ pVidPnPinnedTargetModeInfo = NULL; // Successfully released it
+
+ // Release the acquired target mode set, since it is no longer needed
+ Status = pVidPnInterface->pfnReleaseTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnReleaseTargetModeSet failed with Status = 0x%X, hConstrainingVidPn = 0x%I64x, hVidPnTargetModeSet = 0x%I64x",
+ Status, pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet));
+ break;
+ }
+ hVidPnTargetModeSet = 0; // Successfully released it
+ }
+ }// End: TARGET MODES
+
+ // Nothing else needs the pinned source mode so release it
+ if (pVidPnPinnedSourceModeInfo != NULL)
+ {
+ Status = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnPinnedSourceModeInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnReleaseModeInfo failed with Status = 0x%X, hVidPnSourceModeSet = 0x%I64x, pVidPnPinnedSourceModeInfo = 0x%I64x",
+ Status, hVidPnSourceModeSet, pVidPnPinnedSourceModeInfo));
+ break;
+ }
+ pVidPnPinnedSourceModeInfo = NULL; // Successfully released it
+ }
+
+ // With the pinned source mode now released, if the source mode set hasn't been released, release that as well
+ if (hVidPnSourceModeSet != 0)
+ {
+ Status = pVidPnInterface->pfnReleaseSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnReleaseSourceModeSet failed with Status = 0x%X, hConstrainingVidPn = 0x%I64x, hVidPnSourceModeSet = 0x%I64x",
+ Status, pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet));
+ break;
+ }
+ hVidPnSourceModeSet = 0; // Successfully released it
+ }
+
+ // If modifying support fields, need to modify a local version of a path structure since the retrieved one is const
+ D3DKMDT_VIDPN_PRESENT_PATH LocalVidPnPresentPath = *pVidPnPresentPath;
+ BOOLEAN SupportFieldsModified = FALSE;
+
+ // SCALING: If this path's scaling isn't the pivot point, do work on the scaling support
+ if (!((pEnumCofuncModality->EnumPivotType == D3DKMDT_EPT_SCALING) &&
+ (pEnumCofuncModality->EnumPivot.VidPnSourceId == pVidPnPresentPath->VidPnSourceId) &&
+ (pEnumCofuncModality->EnumPivot.VidPnTargetId == pVidPnPresentPath->VidPnTargetId)))
+ {
+ // If the scaling is unpinned, then modify the scaling support field
+ if (pVidPnPresentPath->ContentTransformation.Scaling == D3DKMDT_VPPS_UNPINNED)
+ {
+ // Identity and centered scaling are supported, but not any stretch modes
+ RtlZeroMemory(&(LocalVidPnPresentPath.ContentTransformation.ScalingSupport), sizeof(D3DKMDT_VIDPN_PRESENT_PATH_SCALING_SUPPORT));
+ LocalVidPnPresentPath.ContentTransformation.ScalingSupport.Identity = 1;
+ LocalVidPnPresentPath.ContentTransformation.ScalingSupport.Centered = 1;
+ SupportFieldsModified = TRUE;
+ }
+ } // End: SCALING
+
+ // ROTATION: If this path's rotation isn't the pivot point, do work on the rotation support
+ if (!((pEnumCofuncModality->EnumPivotType != D3DKMDT_EPT_ROTATION) &&
+ (pEnumCofuncModality->EnumPivot.VidPnSourceId == pVidPnPresentPath->VidPnSourceId) &&
+ (pEnumCofuncModality->EnumPivot.VidPnTargetId == pVidPnPresentPath->VidPnTargetId)))
+ {
+ // If the rotation is unpinned, then modify the rotation support field
+ if (pVidPnPresentPath->ContentTransformation.Rotation == D3DKMDT_VPPR_UNPINNED)
+ {
+ LocalVidPnPresentPath.ContentTransformation.RotationSupport.Identity = 1;
+ // Sample supports only Rotate90
+ LocalVidPnPresentPath.ContentTransformation.RotationSupport.Rotate90 = 1;
+ LocalVidPnPresentPath.ContentTransformation.RotationSupport.Rotate180 = 0;
+ LocalVidPnPresentPath.ContentTransformation.RotationSupport.Rotate270 = 0;
+ SupportFieldsModified = TRUE;
+ }
+ } // End: ROTATION
+
+ if (SupportFieldsModified)
+ {
+ // The correct path will be found by this function and the appropriate fields updated
+ Status = pVidPnTopologyInterface->pfnUpdatePathSupportInfo(hVidPnTopology, &LocalVidPnPresentPath);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnUpdatePathSupportInfo failed with Status = 0x%X, hVidPnTopology = 0x%I64x", Status, hVidPnTopology));
+ break;
+ }
+ }
+
+ // Get the next path...
+ // (NOTE: This is the value of Status that will return STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET when it's time to quit the loop)
+ pVidPnPresentPathTemp = pVidPnPresentPath;
+ Status = pVidPnTopologyInterface->pfnAcquireNextPathInfo(hVidPnTopology, pVidPnPresentPathTemp, &pVidPnPresentPath);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquireNextPathInfo failed with Status = 0x%X, hVidPnTopology = 0x%I64x, pVidPnPresentPathTemp = 0x%I64x", Status, hVidPnTopology, pVidPnPresentPathTemp));
+ break;
+ }
+
+ // ...and release the last path
+ NTSTATUS TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPathTemp);
+ if (!NT_SUCCESS(TempStatus))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnReleasePathInfo failed with Status = 0x%X, hVidPnTopology = 0x%I64x, pVidPnPresentPathTemp = 0x%I64x", TempStatus, hVidPnTopology, pVidPnPresentPathTemp));
+ Status = TempStatus;
+ break;
+ }
+ pVidPnPresentPathTemp = NULL; // Successfully released it
+ }// End: while loop for paths in topology
+
+ // If quit the while loop normally, set the return value to success
+ if (Status == STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET)
+ {
+ Status = STATUS_SUCCESS;
+ }
+
+ // Release any resources hanging around because the loop was quit early.
+ // Since in normal execution everything should be released by this point, TempStatus is initialized to a bogus error to be used as an
+ // assertion that if anything had to be released now (TempStatus changing) Status isn't successful.
+ NTSTATUS TempStatus = STATUS_NOT_FOUND;
+
+ if ((pVidPnSourceModeSetInterface != NULL) &&
+ (pVidPnPinnedSourceModeInfo != NULL))
+ {
+ TempStatus = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnPinnedSourceModeInfo);
+ QXL_ASSERT_CHK(NT_SUCCESS(TempStatus));
+ }
+
+ if ((pVidPnTargetModeSetInterface != NULL) &&
+ (pVidPnPinnedTargetModeInfo != NULL))
+ {
+ TempStatus = pVidPnTargetModeSetInterface->pfnReleaseModeInfo(hVidPnTargetModeSet, pVidPnPinnedTargetModeInfo);
+ QXL_ASSERT_CHK(NT_SUCCESS(TempStatus));
+ }
+
+ if (pVidPnPresentPath != NULL)
+ {
+ TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPath);
+ QXL_ASSERT_CHK(NT_SUCCESS(TempStatus));
+ }
+
+ if (pVidPnPresentPathTemp != NULL)
+ {
+ TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPathTemp);
+ QXL_ASSERT_CHK(NT_SUCCESS(TempStatus));
+ }
+
+ if (hVidPnSourceModeSet != 0)
+ {
+ TempStatus = pVidPnInterface->pfnReleaseSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet);
+ QXL_ASSERT_CHK(NT_SUCCESS(TempStatus));
+ }
+
+ if (hVidPnTargetModeSet != 0)
+ {
+ TempStatus = pVidPnInterface->pfnReleaseTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet);
+ QXL_ASSERT_CHK(NT_SUCCESS(TempStatus));
+ }
+
+ QXL_ASSERT_CHK(TempStatus == STATUS_NOT_FOUND || Status != STATUS_SUCCESS);
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return Status;
+}
+
+NTSTATUS QxlDod::SetVidPnSourceVisibility(_In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility)
+{
+ PAGED_CODE();
+// DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ QXL_ASSERT(pSetVidPnSourceVisibility != NULL);
+ QXL_ASSERT((pSetVidPnSourceVisibility->VidPnSourceId < MAX_VIEWS) ||
+ (pSetVidPnSourceVisibility->VidPnSourceId == D3DDDI_ID_ALL));
+
+ UINT StartVidPnSourceId = (pSetVidPnSourceVisibility->VidPnSourceId == D3DDDI_ID_ALL) ? 0 : pSetVidPnSourceVisibility->VidPnSourceId;
+ UINT MaxVidPnSourceId = (pSetVidPnSourceVisibility->VidPnSourceId == D3DDDI_ID_ALL) ? MAX_VIEWS : pSetVidPnSourceVisibility->VidPnSourceId + 1;
+
+ for (UINT SourceId = StartVidPnSourceId; SourceId < MaxVidPnSourceId; ++SourceId)
+ {
+ if (pSetVidPnSourceVisibility->Visible)
+ {
+ m_CurrentModes[SourceId].Flags.FullscreenPresent = TRUE;
+ }
+ else
+ {
+ m_pHWDevice->BlackOutScreen(&m_CurrentModes[SourceId]);
+ }
+
+ // Store current visibility so it can be dealt with during Present call
+ m_CurrentModes[SourceId].Flags.SourceNotVisible = !(pSetVidPnSourceVisibility->Visible);
+ }
+
+// DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return STATUS_SUCCESS;
+}
+
+// NOTE: The value of pCommitVidPn->MonitorConnectivityChecks is ignored, since BDD is unable to recognize whether a monitor is connected or not
+// The value of pCommitVidPn->hPrimaryAllocation is also ignored, since BDD is a display only driver and does not deal with allocations
+NTSTATUS QxlDod::CommitVidPn(_In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn)
+{
+ PAGED_CODE();
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ QXL_ASSERT(pCommitVidPn != NULL);
+ QXL_ASSERT(pCommitVidPn->AffectedVidPnSourceId < MAX_VIEWS);
+
+ NTSTATUS Status;
+ SIZE_T NumPaths = 0;
+ D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology = 0;
+ D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet = 0;
+ CONST DXGK_VIDPN_INTERFACE* pVidPnInterface = NULL;
+ CONST DXGK_VIDPNTOPOLOGY_INTERFACE* pVidPnTopologyInterface = NULL;
+ CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface = NULL;
+ CONST D3DKMDT_VIDPN_PRESENT_PATH* pVidPnPresentPath = NULL;
+ CONST D3DKMDT_VIDPN_SOURCE_MODE* pPinnedVidPnSourceModeInfo = NULL;
+
+ // Check this CommitVidPn is for the mode change notification when monitor is in power off state.
+ if (pCommitVidPn->Flags.PathPoweredOff)
+ {
+ // Ignore the commitVidPn call for the mode change notification when monitor is in power off state.
+ Status = STATUS_SUCCESS;
+ goto CommitVidPnExit;
+ }
+
+ // Get the VidPn Interface so we can get the 'Source Mode Set' and 'VidPn Topology' interfaces
+ Status = m_DxgkInterface.DxgkCbQueryVidPnInterface(pCommitVidPn->hFunctionalVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("DxgkCbQueryVidPnInterface failed with Status = 0x%X, hFunctionalVidPn = 0x%I64x", Status, pCommitVidPn->hFunctionalVidPn));
+ goto CommitVidPnExit;
+ }
+
+ // Get the VidPn Topology interface so can enumerate paths from source
+ Status = pVidPnInterface->pfnGetTopology(pCommitVidPn->hFunctionalVidPn, &hVidPnTopology, &pVidPnTopologyInterface);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnGetTopology failed with Status = 0x%X, hFunctionalVidPn = 0x%I64x", Status, pCommitVidPn->hFunctionalVidPn));
+ goto CommitVidPnExit;
+ }
+
+ // Find out the number of paths now, if it's 0 don't bother with source mode set and pinned mode, just clear current and then quit
+ Status = pVidPnTopologyInterface->pfnGetNumPaths(hVidPnTopology, &NumPaths);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnGetNumPaths failed with Status = 0x%X, hVidPnTopology = 0x%I64x", Status, hVidPnTopology));
+ goto CommitVidPnExit;
+ }
+
+ if (NumPaths != 0)
+ {
+ // Get the Source Mode Set interface so we can get the pinned mode
+ Status = pVidPnInterface->pfnAcquireSourceModeSet(pCommitVidPn->hFunctionalVidPn,
+ pCommitVidPn->AffectedVidPnSourceId,
+ &hVidPnSourceModeSet,
+ &pVidPnSourceModeSetInterface);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquireSourceModeSet failed with Status = 0x%X, hFunctionalVidPn = 0x%I64x, SourceId = 0x%I64x", Status, pCommitVidPn->hFunctionalVidPn, pCommitVidPn->AffectedVidPnSourceId));
+ goto CommitVidPnExit;
+ }
+
+ // Get the mode that is being pinned
+ Status = pVidPnSourceModeSetInterface->pfnAcquirePinnedModeInfo(hVidPnSourceModeSet, &pPinnedVidPnSourceModeInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquirePinnedModeInfo failed with Status = 0x%X, hFunctionalVidPn = 0x%I64x", Status, pCommitVidPn->hFunctionalVidPn));
+ goto CommitVidPnExit;
+ }
+ }
+ else
+ {
+ // This will cause the successful quit below
+ pPinnedVidPnSourceModeInfo = NULL;
+ }
+
+ if (m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].FrameBuffer.Ptr &&
+ !m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].Flags.DoNotMapOrUnmap)
+ {
+ Status = UnmapFrameBuffer(m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].FrameBuffer.Ptr,
+ m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].DispInfo.Pitch * m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].DispInfo.Height);
+ m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].FrameBuffer.Ptr = NULL;
+ m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].Flags.FrameBufferIsActive = FALSE;
+
+ if (!NT_SUCCESS(Status))
+ {
+ goto CommitVidPnExit;
+ }
+ }
+
+ if (pPinnedVidPnSourceModeInfo == NULL)
+ {
+ // There is no mode to pin on this source, any old paths here have already been cleared
+ Status = STATUS_SUCCESS;
+ goto CommitVidPnExit;
+ }
+
+ Status = IsVidPnSourceModeFieldsValid(pPinnedVidPnSourceModeInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ goto CommitVidPnExit;
+ }
+
+ // Get the number of paths from this source so we can loop through all paths
+ SIZE_T NumPathsFromSource = 0;
+ Status = pVidPnTopologyInterface->pfnGetNumPathsFromSource(hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, &NumPathsFromSource);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnGetNumPathsFromSource failed with Status = 0x%X, hVidPnTopology = 0x%I64x", Status, hVidPnTopology));
+ goto CommitVidPnExit;
+ }
+
+ // Loop through all paths to set this mode
+ for (SIZE_T PathIndex = 0; PathIndex < NumPathsFromSource; ++PathIndex)
+ {
+ // Get the target id for this path
+ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId = D3DDDI_ID_UNINITIALIZED;
+ Status = pVidPnTopologyInterface->pfnEnumPathTargetsFromSource(hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, PathIndex, &TargetId);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnEnumPathTargetsFromSource failed with Status = 0x%X, hVidPnTopology = 0x%I64x, SourceId = 0x%I64x, PathIndex = 0x%I64x",
+ Status, hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, PathIndex));
+ goto CommitVidPnExit;
+ }
+
+ // Get the actual path info
+ Status = pVidPnTopologyInterface->pfnAcquirePathInfo(hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, TargetId, &pVidPnPresentPath);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnAcquirePathInfo failed with Status = 0x%X, hVidPnTopology = 0x%I64x, SourceId = 0x%I64x, TargetId = 0x%I64x",
+ Status, hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, TargetId));
+ goto CommitVidPnExit;
+ }
+
+ Status = IsVidPnPathFieldsValid(pVidPnPresentPath);
+ if (!NT_SUCCESS(Status))
+ {
+ goto CommitVidPnExit;
+ }
+
+ Status = SetSourceModeAndPath(pPinnedVidPnSourceModeInfo, pVidPnPresentPath);
+ if (!NT_SUCCESS(Status))
+ {
+ goto CommitVidPnExit;
+ }
+
+ Status = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPath);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pfnReleasePathInfo failed with Status = 0x%X, hVidPnTopoogy = 0x%I64x, pVidPnPresentPath = 0x%I64x",
+ Status, hVidPnTopology, pVidPnPresentPath));
+ goto CommitVidPnExit;
+ }
+ pVidPnPresentPath = NULL; // Successfully released it
+ }
+
+CommitVidPnExit:
+
+ NTSTATUS TempStatus;
+ UNREFERENCED_PARAMETER(TempStatus);
+
+ if ((pVidPnSourceModeSetInterface != NULL) &&
+ (hVidPnSourceModeSet != 0) &&
+ (pPinnedVidPnSourceModeInfo != NULL))
+ {
+ TempStatus = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pPinnedVidPnSourceModeInfo);
+ NT_ASSERT(NT_SUCCESS(TempStatus));
+ }
+
+ if ((pVidPnInterface != NULL) &&
+ (pCommitVidPn->hFunctionalVidPn != 0) &&
+ (hVidPnSourceModeSet != 0))
+ {
+ TempStatus = pVidPnInterface->pfnReleaseSourceModeSet(pCommitVidPn->hFunctionalVidPn, hVidPnSourceModeSet);
+ NT_ASSERT(NT_SUCCESS(TempStatus));
+ }
+
+ if ((pVidPnTopologyInterface != NULL) &&
+ (hVidPnTopology != 0) &&
+ (pVidPnPresentPath != NULL))
+ {
+ TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPath);
+ NT_ASSERT(NT_SUCCESS(TempStatus));
+ }
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return Status;
+}
+
+NTSTATUS QxlDod::SetSourceModeAndPath(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode,
+ CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath)
+{
+ PAGED_CODE();
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s SourceId = %d\n", __FUNCTION__, pPath->VidPnSourceId));
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ CURRENT_BDD_MODE* pCurrentBddMode = &m_CurrentModes[pPath->VidPnSourceId];
+
+ pCurrentBddMode->Scaling = pPath->ContentTransformation.Scaling;
+ pCurrentBddMode->SrcModeWidth = pSourceMode->Format.Graphics.VisibleRegionSize.cx;
+ pCurrentBddMode->SrcModeHeight = pSourceMode->Format.Graphics.VisibleRegionSize.cy;
+ pCurrentBddMode->Rotation = pPath->ContentTransformation.Rotation;
+
+ pCurrentBddMode->DispInfo.Width = pSourceMode->Format.Graphics.PrimSurfSize.cx;
+ pCurrentBddMode->DispInfo.Height = pSourceMode->Format.Graphics.PrimSurfSize.cy;
+ pCurrentBddMode->DispInfo.Pitch = pSourceMode->Format.Graphics.PrimSurfSize.cx * BPPFromPixelFormat(pCurrentBddMode->DispInfo.ColorFormat) / BITS_PER_BYTE;
+
+
+ if (!pCurrentBddMode->Flags.DoNotMapOrUnmap)
+ {
+ // Map the new frame buffer
+ QXL_ASSERT(pCurrentBddMode->FrameBuffer.Ptr == NULL);
+ Status = MapFrameBuffer(pCurrentBddMode->DispInfo.PhysicAddress,
+ pCurrentBddMode->DispInfo.Pitch * pCurrentBddMode->DispInfo.Height,
+ &(pCurrentBddMode->FrameBuffer.Ptr));
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+
+ pCurrentBddMode->Flags.FrameBufferIsActive = TRUE;
+ m_pHWDevice->BlackOutScreen(&m_CurrentModes[pPath->VidPnSourceId]);
+
+ // Mark that the next present should be fullscreen so the screen doesn't go from black to actual pixels one dirty rect at a time.
+ pCurrentBddMode->Flags.FullscreenPresent = TRUE;
+ for (USHORT ModeIndex = 0; ModeIndex < m_pHWDevice->GetModeCount(); ++ModeIndex)
+ {
+ PVIDEO_MODE_INFORMATION pModeInfo = m_pHWDevice->GetModeInfo(ModeIndex);
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("%d\t%d x %d\t%d x %d\n", ModeIndex, pCurrentBddMode->DispInfo.Width, pCurrentBddMode->DispInfo.Height,
+ pModeInfo->VisScreenWidth, pModeInfo->VisScreenHeight));
+ if (pCurrentBddMode->DispInfo.Width == pModeInfo->VisScreenWidth &&
+ pCurrentBddMode->DispInfo.Height == pModeInfo->VisScreenHeight )
+ {
+ Status = m_pHWDevice->SetCurrentMode(m_pHWDevice->GetModeNumber(ModeIndex));
+ if (NT_SUCCESS(Status))
+ {
+ m_pHWDevice->SetCurrentModeIndex(ModeIndex);
+ }
+ break;
+ }
+ }
+ }
+
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__));
+ return Status;
+}
+
+NTSTATUS QxlDod::IsVidPnPathFieldsValid(CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath) const
+{
+ PAGED_CODE();
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ if (pPath->VidPnSourceId >= MAX_VIEWS)
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("VidPnSourceId is 0x%I64x is too high (MAX_VIEWS is 0x%I64x)",
+ pPath->VidPnSourceId, MAX_VIEWS));
+ return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE;
+ }
+ else if (pPath->VidPnTargetId >= MAX_CHILDREN)
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("VidPnTargetId is 0x%I64x is too high (MAX_CHILDREN is 0x%I64x)",
+ pPath->VidPnTargetId, MAX_CHILDREN));
+ return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET;
+ }
+ else if (pPath->GammaRamp.Type != D3DDDI_GAMMARAMP_DEFAULT)
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pPath contains a gamma ramp (0x%I64x)", pPath->GammaRamp.Type));
+ return STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED;
+ }
+ else if ((pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_IDENTITY) &&
+ (pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_CENTERED) &&
+ (pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_NOTSPECIFIED) &&
+ (pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_UNINITIALIZED))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pPath contains a non-identity scaling (0x%I64x)", pPath->ContentTransformation.Scaling));
+ return STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED;
+ }
+ else if ((pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_IDENTITY) &&
+ (pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_ROTATE90) &&
+ (pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_NOTSPECIFIED) &&
+ (pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_UNINITIALIZED))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pPath contains a not-supported rotation (0x%I64x)", pPath->ContentTransformation.Rotation));
+ return STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED;
+ }
+ else if ((pPath->VidPnTargetColorBasis != D3DKMDT_CB_SCRGB) &&
+ (pPath->VidPnTargetColorBasis != D3DKMDT_CB_UNINITIALIZED))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pPath has a non-linear RGB color basis (0x%I64x)", pPath->VidPnTargetColorBasis));
+ return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE;
+ }
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS QxlDod::IsVidPnSourceModeFieldsValid(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode) const
+{
+ PAGED_CODE();
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ if (pSourceMode->Type != D3DKMDT_RMT_GRAPHICS)
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pSourceMode is a non-graphics mode (0x%I64x)", pSourceMode->Type));
+ return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE;
+ }
+ else if ((pSourceMode->Format.Graphics.ColorBasis != D3DKMDT_CB_SCRGB) &&
+ (pSourceMode->Format.Graphics.ColorBasis != D3DKMDT_CB_UNINITIALIZED))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pSourceMode has a non-linear RGB color basis (0x%I64x)", pSourceMode->Format.Graphics.ColorBasis));
+ return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE;
+ }
+ else if (pSourceMode->Format.Graphics.PixelValueAccessMode != D3DKMDT_PVAM_DIRECT)
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pSourceMode has a palettized access mode (0x%I64x)", pSourceMode->Format.Graphics.PixelValueAccessMode));
+ return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE;
+ }
+ else
+ {
+ if (pSourceMode->Format.Graphics.PixelFormat == D3DDDIFMT_A8R8G8B8)
+ {
+ return STATUS_SUCCESS;
+ }
+ }
+ DbgPrint(TRACE_LEVEL_ERROR, ("pSourceMode has an unknown pixel format (0x%I64x)", pSourceMode->Format.Graphics.PixelFormat));
+ return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE;
+}
+
+NTSTATUS QxlDod::UpdateActiveVidPnPresentPath(_In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath)
+{
+ PAGED_CODE();
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ QXL_ASSERT(pUpdateActiveVidPnPresentPath != NULL);
+ NTSTATUS Status = IsVidPnPathFieldsValid(&(pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo));
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ // Mark the next present as fullscreen to make sure the full rotation comes through
+ m_CurrentModes[pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo.VidPnSourceId].Flags.FullscreenPresent = TRUE;
+
+ m_CurrentModes[pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo.VidPnSourceId].Rotation = pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo.ContentTransformation.Rotation;
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return STATUS_SUCCESS;
+}
+
+
+
+//
+// Non-Paged Code
+//
+#pragma code_seg(push)
+#pragma code_seg()
+
+VOID QxlDod::DpcRoutine(VOID)
+{
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__));
+ m_pHWDevice->DpcRoutine(&m_DxgkInterface);
+ m_DxgkInterface.DxgkCbNotifyDpc((HANDLE)m_DxgkInterface.DeviceHandle);
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__));
+}
+
+BOOLEAN QxlDod::InterruptRoutine(_In_ ULONG MessageNumber)
+{
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("<--> 0 %s\n", __FUNCTION__));
+ return m_pHWDevice->InterruptRoutine(&m_DxgkInterface, MessageNumber);
+}
+
+VOID QxlDod::ResetDevice(VOID)
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+ m_pHWDevice->ResetDevice();
+}
+
+// Must be Non-Paged, as it sets up the display for a bugcheck
+NTSTATUS QxlDod::SystemDisplayEnable(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
+ _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags,
+ _Out_ UINT* pWidth,
+ _Out_ UINT* pHeight,
+ _Out_ D3DDDIFORMAT* pColorFormat)
+{
+ UNREFERENCED_PARAMETER(Flags);
+
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__));
+ m_SystemDisplaySourceId = D3DDDI_ID_UNINITIALIZED;
+
+ QXL_ASSERT((TargetId < MAX_CHILDREN) || (TargetId == D3DDDI_ID_UNINITIALIZED));
+
+ // Find the frame buffer for displaying the bugcheck, if it was successfully mapped
+ if (TargetId == D3DDDI_ID_UNINITIALIZED)
+ {
+ for (UINT SourceIdx = 0; SourceIdx < MAX_VIEWS; ++SourceIdx)
+ {
+ if (m_CurrentModes[SourceIdx].FrameBuffer.Ptr != NULL)
+ {
+ m_SystemDisplaySourceId = SourceIdx;
+ break;
+ }
+ }
+ }
+ else
+ {
+ m_SystemDisplaySourceId = FindSourceForTarget(TargetId, FALSE);
+ }
+
+ if (m_SystemDisplaySourceId == D3DDDI_ID_UNINITIALIZED)
+ {
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ if ((m_CurrentModes[m_SystemDisplaySourceId].Rotation == D3DKMDT_VPPR_ROTATE90) ||
+ (m_CurrentModes[m_SystemDisplaySourceId].Rotation == D3DKMDT_VPPR_ROTATE270))
+ {
+ *pHeight = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Width;
+ *pWidth = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Height;
+ }
+ else
+ {
+ *pWidth = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Width;
+ *pHeight = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Height;
+ }
+
+ *pColorFormat = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.ColorFormat;
+
+
+ return STATUS_SUCCESS;
+}
+
+// Must be Non-Paged, as it is called to display the bugcheck screen
+VOID QxlDod::SystemDisplayWrite(_In_reads_bytes_(SourceHeight * SourceStride) VOID* pSource,
+ _In_ UINT SourceWidth,
+ _In_ UINT SourceHeight,
+ _In_ UINT SourceStride,
+ _In_ INT PositionX,
+ _In_ INT PositionY)
+{
+ UNREFERENCED_PARAMETER(pSource);
+ UNREFERENCED_PARAMETER(SourceStride);
+ // Rect will be Offset by PositionX/Y in the src to reset it back to 0
+ RECT Rect;
+ Rect.left = PositionX;
+ Rect.top = PositionY;
+ Rect.right = Rect.left + SourceWidth;
+ Rect.bottom = Rect.top + SourceHeight;
+
+ // Set up destination blt info
+ BLT_INFO DstBltInfo;
+ DstBltInfo.pBits = m_CurrentModes[m_SystemDisplaySourceId].FrameBuffer.Ptr;
+ DstBltInfo.Pitch = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Pitch;
+ DstBltInfo.BitsPerPel = BPPFromPixelFormat(m_CurrentModes[m_SystemDisplaySourceId].DispInfo.ColorFormat);
+ DstBltInfo.Offset.x = 0;
+ DstBltInfo.Offset.y = 0;
+ DstBltInfo.Rotation = m_CurrentModes[m_SystemDisplaySourceId].Rotation;
+ DstBltInfo.Width = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Width;
+ DstBltInfo.Height = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Height;
+
+ // Set up source blt info
+ BLT_INFO SrcBltInfo;
+ SrcBltInfo.pBits = pSource;
+ SrcBltInfo.Pitch = SourceStride;
+ SrcBltInfo.BitsPerPel = 32;
+
+ SrcBltInfo.Offset.x = -PositionX;
+ SrcBltInfo.Offset.y = -PositionY;
+ SrcBltInfo.Rotation = D3DKMDT_VPPR_IDENTITY;
+ SrcBltInfo.Width = SourceWidth;
+ SrcBltInfo.Height = SourceHeight;
+
+ BltBits(&DstBltInfo,
+ &SrcBltInfo,
+ 1, // NumRects
+ &Rect);
+
+}
+
+#pragma code_seg(pop) // End Non-Paged Code
+
+NTSTATUS QxlDod::WriteHWInfoStr(_In_ HANDLE DevInstRegKeyHandle, _In_ PCWSTR pszwValueName, _In_ PCSTR pszValue)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status;
+ ANSI_STRING AnsiStrValue;
+ UNICODE_STRING UnicodeStrValue;
+ UNICODE_STRING UnicodeStrValueName;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ // ZwSetValueKey wants the ValueName as a UNICODE_STRING
+ RtlInitUnicodeString(&UnicodeStrValueName, pszwValueName);
+
+ // REG_SZ is for WCHARs, there is no equivalent for CHARs
+ // Use the ansi/unicode conversion functions to get from PSTR to PWSTR
+ RtlInitAnsiString(&AnsiStrValue, pszValue);
+ Status = RtlAnsiStringToUnicodeString(&UnicodeStrValue, &AnsiStrValue, TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("RtlAnsiStringToUnicodeString failed with Status: 0x%X\n", Status));
+ return Status;
+ }
+
+ // Write the value to the registry
+ Status = ZwSetValueKey(DevInstRegKeyHandle,
+ &UnicodeStrValueName,
+ 0,
+ REG_SZ,
+ UnicodeStrValue.Buffer,
+ UnicodeStrValue.MaximumLength);
+
+ // Free the earlier allocated unicode string
+ RtlFreeUnicodeString(&UnicodeStrValue);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("ZwSetValueKey failed with Status: 0x%X\n", Status));
+ }
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return Status;
+}
+
+NTSTATUS QxlDod::RegisterHWInfo()
+{
+ PAGED_CODE();
+
+ NTSTATUS Status;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ // TODO: Replace these strings with proper information
+ PCSTR StrHWInfoChipType = "QEMU QXL";
+ PCSTR StrHWInfoDacType = "QXL 1B36";
+ PCSTR StrHWInfoAdapterString = "QXL";
+ PCSTR StrHWInfoBiosString = "SEABIOS QXL";
+
+ HANDLE DevInstRegKeyHandle;
+ Status = IoOpenDeviceRegistryKey(m_pPhysicalDevice, PLUGPLAY_REGKEY_DRIVER, KEY_SET_VALUE, &DevInstRegKeyHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("IoOpenDeviceRegistryKey failed for PDO: 0x%I64x, Status: 0x%I64x", m_pPhysicalDevice, Status));
+ return Status;
+ }
+
+ Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.ChipType", StrHWInfoChipType);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.DacType", StrHWInfoDacType);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.AdapterString", StrHWInfoAdapterString);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.BiosString", StrHWInfoBiosString);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ // MemorySize is a ULONG, unlike the others which are all strings
+ UNICODE_STRING ValueNameMemorySize;
+ RtlInitUnicodeString(&ValueNameMemorySize, L"HardwareInformation.MemorySize");
+ DWORD MemorySize = 0; // BDD has no access to video memory
+ Status = ZwSetValueKey(DevInstRegKeyHandle,
+ &ValueNameMemorySize,
+ 0,
+ REG_DWORD,
+ &MemorySize,
+ sizeof(MemorySize));
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("ZwSetValueKey for MemorySize failed with Status: 0x%X\n", Status));
+ return Status;
+ }
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return Status;
+}
+
+
+//
+// Non-Paged Code
+//
+#pragma code_seg(push)
+#pragma code_seg()
+D3DDDI_VIDEO_PRESENT_SOURCE_ID QxlDod::FindSourceForTarget(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, BOOLEAN DefaultToZero)
+{
+ UNREFERENCED_PARAMETER(TargetId);
+ for (UINT SourceId = 0; SourceId < MAX_VIEWS; ++SourceId)
+ {
+ if (m_CurrentModes[SourceId].FrameBuffer.Ptr != NULL)
+ {
+ return SourceId;
+ }
+ }
+
+ return DefaultToZero ? 0 : D3DDDI_ID_UNINITIALIZED;
+}
+
+#pragma code_seg(pop) // End Non-Paged Code
+
+//
+// Frame buffer map/unmap
+//
+
+NTSTATUS
+MapFrameBuffer(
+ _In_ PHYSICAL_ADDRESS PhysicalAddress,
+ _In_ ULONG Length,
+ _Outptr_result_bytebuffer_(Length) VOID** VirtualAddress)
+{
+ PAGED_CODE();
+
+ //
+ // Check for parameters
+ //
+ if ((PhysicalAddress.QuadPart == (ULONGLONG)0) ||
+ (Length == 0) ||
+ (VirtualAddress == NULL))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("One of PhysicalAddress.QuadPart (0x%I64x), Length (0x%I64x), VirtualAddress (0x%I64x) is NULL or 0",
+ PhysicalAddress.QuadPart, Length, VirtualAddress));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ *VirtualAddress = MmMapIoSpace(PhysicalAddress,
+ Length,
+ MmWriteCombined);
+ if (*VirtualAddress == NULL)
+ {
+ // The underlying call to MmMapIoSpace failed. This may be because, MmWriteCombined
+ // isn't supported, so try again with MmNonCached
+
+ *VirtualAddress = MmMapIoSpace(PhysicalAddress,
+ Length,
+ MmNonCached);
+ if (*VirtualAddress == NULL)
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("MmMapIoSpace returned a NULL buffer when trying to allocate 0x%I64x bytes", Length));
+ return STATUS_NO_MEMORY;
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+UnmapFrameBuffer(
+ _In_reads_bytes_(Length) VOID* VirtualAddress,
+ _In_ ULONG Length)
+{
+ PAGED_CODE();
+
+
+ //
+ // Check for parameters
+ //
+ if ((VirtualAddress == NULL) && (Length == 0))
+ {
+ // Allow this function to be called when there's no work to do, and treat as successful
+ return STATUS_SUCCESS;
+ }
+ else if ((VirtualAddress == NULL) || (Length == 0))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("Only one of Length (0x%I64x), VirtualAddress (0x%I64x) is NULL or 0",
+ Length, VirtualAddress));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ MmUnmapIoSpace(VirtualAddress,
+ Length);
+
+ return STATUS_SUCCESS;
+}
+
+
+
+
+// HW specific code
+
+VOID GetPitches(_In_ CONST BLT_INFO* pBltInfo, _Out_ LONG* pPixelPitch, _Out_ LONG* pRowPitch)
+{
+ switch (pBltInfo->Rotation)
+ {
+ case D3DKMDT_VPPR_IDENTITY:
+ {
+ *pPixelPitch = (pBltInfo->BitsPerPel / BITS_PER_BYTE);
+ *pRowPitch = pBltInfo->Pitch;
+ return;
+ }
+ case D3DKMDT_VPPR_ROTATE90:
+ {
+ *pPixelPitch = -((LONG)pBltInfo->Pitch);
+ *pRowPitch = (pBltInfo->BitsPerPel / BITS_PER_BYTE);
+ return;
+ }
+ case D3DKMDT_VPPR_ROTATE180:
+ {
+ *pPixelPitch = -((LONG)pBltInfo->BitsPerPel / BITS_PER_BYTE);
+ *pRowPitch = -((LONG)pBltInfo->Pitch);
+ return;
+ }
+ case D3DKMDT_VPPR_ROTATE270:
+ {
+ *pPixelPitch = pBltInfo->Pitch;
+ *pRowPitch = -((LONG)pBltInfo->BitsPerPel / BITS_PER_BYTE);
+ return;
+ }
+ default:
+ {
+ QXL_LOG_ASSERTION1("Invalid rotation (0x%I64x) specified", pBltInfo->Rotation);
+ *pPixelPitch = 0;
+ *pRowPitch = 0;
+ return;
+ }
+ }
+}
+
+BYTE* GetRowStart(_In_ CONST BLT_INFO* pBltInfo, CONST RECT* pRect)
+{
+ BYTE* pRet = NULL;
+ LONG OffLeft = pRect->left + pBltInfo->Offset.x;
+ LONG OffTop = pRect->top + pBltInfo->Offset.y;
+ LONG BytesPerPixel = (pBltInfo->BitsPerPel / BITS_PER_BYTE);
+ switch (pBltInfo->Rotation)
+ {
+ case D3DKMDT_VPPR_IDENTITY:
+ {
+ pRet = ((BYTE*)pBltInfo->pBits +
+ OffTop * pBltInfo->Pitch +
+ OffLeft * BytesPerPixel);
+ break;
+ }
+ case D3DKMDT_VPPR_ROTATE90:
+ {
+ pRet = ((BYTE*)pBltInfo->pBits +
+ (pBltInfo->Height - 1 - OffLeft) * pBltInfo->Pitch +
+ OffTop * BytesPerPixel);
+ break;
+ }
+ case D3DKMDT_VPPR_ROTATE180:
+ {
+ pRet = ((BYTE*)pBltInfo->pBits +
+ (pBltInfo->Height - 1 - OffTop) * pBltInfo->Pitch +
+ (pBltInfo->Width - 1 - OffLeft) * BytesPerPixel);
+ break;
+ }
+ case D3DKMDT_VPPR_ROTATE270:
+ {
+ pRet = ((BYTE*)pBltInfo->pBits +
+ OffLeft * pBltInfo->Pitch +
+ (pBltInfo->Width - 1 - OffTop) * BytesPerPixel);
+ break;
+ }
+ default:
+ {
+ QXL_LOG_ASSERTION1("Invalid rotation (0x%I64x) specified", pBltInfo->Rotation);
+ break;
+ }
+ }
+
+ return pRet;
+}
+
+/****************************Internal*Routine******************************\
+ * CopyBitsGeneric
+ *
+ *
+ * Blt function which can handle a rotated dst/src, offset rects in dst/src
+ * and bpp combinations of:
+ * dst | src
+ * 32 | 32 // For identity rotation this is much faster in CopyBits32_32
+ * 32 | 24
+ * 32 | 16
+ * 24 | 32
+ * 16 | 32
+ * 8 | 32
+ * 24 | 24 // untested
+ *
+\**************************************************************************/
+
+VOID CopyBitsGeneric(
+ BLT_INFO* pDst,
+ CONST BLT_INFO* pSrc,
+ UINT NumRects,
+ _In_reads_(NumRects) CONST RECT *pRects)
+{
+ LONG DstPixelPitch = 0;
+ LONG DstRowPitch = 0;
+ LONG SrcPixelPitch = 0;
+ LONG SrcRowPitch = 0;
+
+ DbgPrint(TRACE_LEVEL_VERBOSE , ("---> %s NumRects = %d Dst = %p Src = %p\n", __FUNCTION__, NumRects, pDst->pBits, pSrc->pBits));
+
+ GetPitches(pDst, &DstPixelPitch, &DstRowPitch);
+ GetPitches(pSrc, &SrcPixelPitch, &SrcRowPitch);
+
+ for (UINT iRect = 0; iRect < NumRects; iRect++)
+ {
+ CONST RECT* pRect = &pRects[iRect];
+
+ NT_ASSERT(pRect->right >= pRect->left);
+ NT_ASSERT(pRect->bottom >= pRect->top);
+
+ UINT NumPixels = pRect->right - pRect->left;
+ UINT NumRows = pRect->bottom - pRect->top;
+
+ BYTE* pDstRow = GetRowStart(pDst, pRect);
+ CONST BYTE* pSrcRow = GetRowStart(pSrc, pRect);
+
+ for (UINT y=0; y < NumRows; y++)
+ {
+ BYTE* pDstPixel = pDstRow;
+ CONST BYTE* pSrcPixel = pSrcRow;
+
+ for (UINT x=0; x < NumPixels; x++)
+ {
+ if ((pDst->BitsPerPel == 24) ||
+ (pSrc->BitsPerPel == 24))
+ {
+ pDstPixel[0] = pSrcPixel[0];
+ pDstPixel[1] = pSrcPixel[1];
+ pDstPixel[2] = pSrcPixel[2];
+ // pPixel[3] is the alpha channel and is ignored for whichever of Src/Dst is 32bpp
+ }
+ else if (pDst->BitsPerPel == 32)
+ {
+ if (pSrc->BitsPerPel == 32)
+ {
+ UINT32* pDstPixelAs32 = (UINT32*)pDstPixel;
+ UINT32* pSrcPixelAs32 = (UINT32*)pSrcPixel;
+ *pDstPixelAs32 = *pSrcPixelAs32;
+ }
+ else if (pSrc->BitsPerPel == 16)
+ {
+ UINT32* pDstPixelAs32 = (UINT32*)pDstPixel;
+ UINT16* pSrcPixelAs16 = (UINT16*)pSrcPixel;
+
+ *pDstPixelAs32 = CONVERT_16BPP_TO_32BPP(*pSrcPixelAs16);
+ }
+ else
+ {
+ // Invalid pSrc->BitsPerPel on a pDst->BitsPerPel of 32
+ NT_ASSERT(FALSE);
+ }
+ }
+ else if (pDst->BitsPerPel == 16)
+ {
+ NT_ASSERT(pSrc->BitsPerPel == 32);
+
+ UINT16* pDstPixelAs16 = (UINT16*)pDstPixel;
+ *pDstPixelAs16 = CONVERT_32BPP_TO_16BPP(pSrcPixel);
+ }
+ else if (pDst->BitsPerPel == 8)
+ {
+ NT_ASSERT(pSrc->BitsPerPel == 32);
+
+ *pDstPixel = CONVERT_32BPP_TO_8BPP(pSrcPixel);
+ }
+ else
+ {
+ // Invalid pDst->BitsPerPel
+ NT_ASSERT(FALSE);
+ }
+ pDstPixel += DstPixelPitch;
+ pSrcPixel += SrcPixelPitch;
+ }
+
+ pDstRow += DstRowPitch;
+ pSrcRow += SrcRowPitch;
+ }
+ }
+}
+
+
+VOID CopyBits32_32(
+ BLT_INFO* pDst,
+ CONST BLT_INFO* pSrc,
+ UINT NumRects,
+ _In_reads_(NumRects) CONST RECT *pRects)
+{
+ NT_ASSERT((pDst->BitsPerPel == 32) &&
+ (pSrc->BitsPerPel == 32));
+ NT_ASSERT((pDst->Rotation == D3DKMDT_VPPR_IDENTITY) &&
+ (pSrc->Rotation == D3DKMDT_VPPR_IDENTITY));
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ for (UINT iRect = 0; iRect < NumRects; iRect++)
+ {
+ CONST RECT* pRect = &pRects[iRect];
+
+ NT_ASSERT(pRect->right >= pRect->left);
+ NT_ASSERT(pRect->bottom >= pRect->top);
+
+ UINT NumPixels = pRect->right - pRect->left;
+ UINT NumRows = pRect->bottom - pRect->top;
+ UINT BytesToCopy = NumPixels * 4;
+ BYTE* pStartDst = ((BYTE*)pDst->pBits +
+ (pRect->top + pDst->Offset.y) * pDst->Pitch +
+ (pRect->left + pDst->Offset.x) * 4);
+ CONST BYTE* pStartSrc = ((BYTE*)pSrc->pBits +
+ (pRect->top + pSrc->Offset.y) * pSrc->Pitch +
+ (pRect->left + pSrc->Offset.x) * 4);
+
+ for (UINT i = 0; i < NumRows; ++i)
+ {
+ RtlCopyMemory(pStartDst, pStartSrc, BytesToCopy);
+ pStartDst += pDst->Pitch;
+ pStartSrc += pSrc->Pitch;
+ }
+ }
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+}
+
+
+VOID BltBits (
+ BLT_INFO* pDst,
+ CONST BLT_INFO* pSrc,
+ UINT NumRects,
+ _In_reads_(NumRects) CONST RECT *pRects)
+{
+ // pSrc->pBits might be coming from user-mode. User-mode addresses when accessed by kernel need to be protected by a __try/__except.
+ // This usage is redundant in the sample driver since it is already being used for MmProbeAndLockPages. However, it is very important
+ // to have this in place and to make sure developers don't miss it, it is in these two locations.
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ __try
+ {
+ if (pDst->BitsPerPel == 32 &&
+ pSrc->BitsPerPel == 32 &&
+ pDst->Rotation == D3DKMDT_VPPR_IDENTITY &&
+ pSrc->Rotation == D3DKMDT_VPPR_IDENTITY)
+ {
+ // This is by far the most common copy function being called
+ CopyBits32_32(pDst, pSrc, NumRects, pRects);
+ }
+ else
+ {
+ CopyBitsGeneric(pDst, pSrc, NumRects, pRects);
+ }
+ }
+ #pragma prefast(suppress: __WARNING_EXCEPTIONEXECUTEHANDLER, "try/except is only able to protect against user-mode errors and these are the only errors we try to catch here");
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("Either dst (0x%I64x) or src (0x%I64x) bits encountered exception during access.\n", pDst->pBits, pSrc->pBits));
+ }
+}
+
+VgaDevice::VgaDevice(_In_ QxlDod* pQxlDod)
+{
+ m_pQxlDod = pQxlDod;
+ m_ModeInfo = NULL;
+ m_ModeCount = 0;
+ m_ModeNumbers = NULL;
+ m_CurrentMode = 0;
+}
+
+VgaDevice::~VgaDevice(void)
+{
+ delete [] reinterpret_cast<BYTE*>(m_ModeInfo);
+ delete [] reinterpret_cast<BYTE*>(m_ModeNumbers);
+ m_ModeInfo = NULL;
+ m_ModeNumbers = NULL;
+ m_CurrentMode = 0;
+ m_ModeCount = 0;
+}
+
+BOOL VgaDevice::SetVideoModeInfo(UINT Idx, PVBE_MODEINFO pModeInfo)
+{
+ PVIDEO_MODE_INFORMATION pMode = NULL;
+ PAGED_CODE();
+
+ pMode = &m_ModeInfo[Idx];
+ pMode->Length = sizeof(VIDEO_MODE_INFORMATION);
+ pMode->ModeIndex = Idx;//m_ModeNumbers[Idx];
+ pMode->VisScreenWidth = pModeInfo->XResolution;
+ pMode->VisScreenHeight = pModeInfo->YResolution;
+ pMode->ScreenStride = pModeInfo->LinBytesPerScanLine;
+ pMode->NumberOfPlanes = pModeInfo->NumberOfPlanes;
+ pMode->BitsPerPlane = pModeInfo->BitsPerPixel / pModeInfo->NumberOfPlanes;
+ pMode->Frequency = 60;
+ pMode->XMillimeter = pModeInfo->XResolution * 254 / 720;
+ pMode->YMillimeter = pModeInfo->YResolution * 254 / 720;
+
+ if (pModeInfo->BitsPerPixel == 15 && pModeInfo->NumberOfPlanes == 1)
+ {
+ pMode->BitsPerPlane = 16;
+ }
+
+ pMode->NumberRedBits = pModeInfo->LinRedMaskSize;
+ pMode->NumberGreenBits = pModeInfo->LinGreenMaskSize;
+ pMode->NumberBlueBits = pModeInfo->LinBlueMaskSize;
+ pMode->RedMask = ((1 << pModeInfo->LinRedMaskSize) - 1) << pModeInfo->LinRedFieldPosition;
+ pMode->GreenMask = ((1 << pModeInfo->LinGreenMaskSize) - 1) << pModeInfo->LinGreenFieldPosition;
+ pMode->BlueMask = ((1 << pModeInfo->LinBlueMaskSize) - 1) << pModeInfo->LinBlueFieldPosition;
+
+ pMode->AttributeFlags = VIDEO_MODE_COLOR | VIDEO_MODE_GRAPHICS | VIDEO_MODE_NO_OFF_SCREEN;
+ pMode->VideoMemoryBitmapWidth = pModeInfo->XResolution;
+ pMode->VideoMemoryBitmapHeight = pModeInfo->YResolution;
+ pMode->DriverSpecificAttributeFlags = 0;
+
+ return TRUE;
+}
+
+NTSTATUS VgaDevice::GetModeList(DXGK_DISPLAY_INFORMATION* pDispInfo)
+{
+ PAGED_CODE();
+ USHORT m_Segment;
+ USHORT m_Offset;
+ USHORT ModeCount;
+ ULONG SuitableModeCount;
+ USHORT ModeTemp;
+ USHORT CurrentMode;
+ VBE_INFO VbeInfo = {0};
+ ULONG Length;
+ VBE_MODEINFO tmpModeInfo;
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+//Get VBE Mode List
+ Length = 0x400;
+ Status = x86BiosAllocateBuffer (&Length, &m_Segment, &m_Offset);
+ if (!NT_SUCCESS (Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosAllocateBuffer failed with Status: 0x%X\n", Status));
+ return Status;
+ }
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("x86BiosAllocateBuffer 0x%x (%x.%x)\n", VbeInfo.VideoModePtr, m_Segment, m_Offset));
+
+ Status = x86BiosWriteMemory (m_Segment, m_Offset, "VBE2", 4);
+
+ if (!NT_SUCCESS (Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosWriteMemory failed with Status: 0x%X\n", Status));
+ return Status;
+ }
+
+ X86BIOS_REGISTERS regs = {0};
+ regs.SegEs = m_Segment;
+ regs.Edi = m_Offset;
+ regs.Eax = 0x4F00;
+ if (!x86BiosCall (0x10, &regs) /* || (regs.Eax & 0xFF00) != 0x4F00 */)
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosCall failed\n"));
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ Status = x86BiosReadMemory (m_Segment, m_Offset, &VbeInfo, sizeof (VbeInfo));
+ if (!NT_SUCCESS (Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosReadMemory failed with Status: 0x%X\n", Status));
+ return Status;
+ }
+
+ if (!RtlEqualMemory(VbeInfo.Signature, "VESA", 4))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("No VBE BIOS present\n"));
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("VBE BIOS Present (%d.%d, %8ld Kb)\n", VbeInfo.Version / 0x100, VbeInfo.Version & 0xFF, VbeInfo.TotalMemory * 64));
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("Capabilities = 0x%x\n", VbeInfo.Capabilities));
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("VideoModePtr = 0x%x (0x%x.0x%x)\n", VbeInfo.VideoModePtr, HIWORD( VbeInfo.VideoModePtr), LOWORD( VbeInfo.VideoModePtr)));
+
+ for (ModeCount = 0; ; ModeCount++)
+ {
+ /* Read the VBE mode number. */
+ Status = x86BiosReadMemory (
+ HIWORD(VbeInfo.VideoModePtr),
+ LOWORD(VbeInfo.VideoModePtr) + (ModeCount << 1),
+ &ModeTemp,
+ sizeof(ModeTemp));
+
+ if (!NT_SUCCESS (Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosReadMemory failed with Status: 0x%X\n", Status));
+ break;
+ }
+ /* End of list? */
+ if (ModeTemp == 0xFFFF || ModeTemp == 0)
+ {
+ break;
+ }
+ }
+
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("ModeCount %d\n", ModeCount));
+
+ m_ModeInfo = reinterpret_cast<PVIDEO_MODE_INFORMATION> (new (PagedPool) BYTE[sizeof (VIDEO_MODE_INFORMATION) * ModeCount]);
+ m_ModeNumbers = reinterpret_cast<PUSHORT> (new (PagedPool) BYTE [sizeof (USHORT) * ModeCount]);
+ m_CurrentMode = 0;
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("m_ModeInfo = 0x%p, m_ModeNumbers = 0x%p\n", m_ModeInfo, m_ModeNumbers));
+ for (CurrentMode = 0, SuitableModeCount = 0;
+ CurrentMode < ModeCount;
+ CurrentMode++)
+ {
+ Status = x86BiosReadMemory (
+ HIWORD(VbeInfo.VideoModePtr),
+ LOWORD(VbeInfo.VideoModePtr) + (CurrentMode << 1),
+ &ModeTemp,
+ sizeof(ModeTemp));
+
+ if (!NT_SUCCESS (Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosReadMemory failed with Status: 0x%X\n", Status));
+ break;
+ }
+
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("ModeTemp = 0x%X\n", ModeTemp));
+ RtlZeroMemory(&regs, sizeof(regs));
+ regs.Eax = 0x4F01;
+ regs.Ecx = ModeTemp;
+ regs.Edi = m_Offset + sizeof (VbeInfo);
+ regs.SegEs = m_Segment;
+ if (!x86BiosCall (0x10, &regs))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosCall failed\n"));
+ return STATUS_UNSUCCESSFUL;
+ }
+ Status = x86BiosReadMemory (
+ m_Segment,
+ m_Offset + sizeof (VbeInfo),
+ &tmpModeInfo,
+ sizeof(VBE_MODEINFO));
+
+ UINT Height = pDispInfo->Height;
+ UINT Width = pDispInfo->Width;
+ UINT BitsPerPixel = BPPFromPixelFormat(pDispInfo->ColorFormat);
+
+ if (tmpModeInfo.XResolution >= Width &&
+ tmpModeInfo.YResolution >= Height &&
+ tmpModeInfo.BitsPerPixel == BitsPerPixel &&
+ tmpModeInfo.PhysBasePtr != 0)
+ {
+ m_ModeNumbers[SuitableModeCount] = ModeTemp;
+ SetVideoModeInfo(SuitableModeCount, &tmpModeInfo);
+ if (tmpModeInfo.XResolution == 1024 &&
+ tmpModeInfo.YResolution == 768)
+ {
+ m_CurrentMode = (USHORT)SuitableModeCount;
+ }
+ SuitableModeCount++;
+ }
+ }
+
+ if (SuitableModeCount == 0)
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("No video modes supported\n"));
+ Status = STATUS_UNSUCCESSFUL;
+ }
+
+ m_ModeCount = SuitableModeCount;
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("ModeCount filtered %d\n", m_ModeCount));
+ for (ULONG idx = 0; idx < m_ModeCount; idx++)
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("type %x, XRes = %d, YRes = %d, BPP = %d\n",
+ m_ModeNumbers[idx],
+ m_ModeInfo[idx].VisScreenWidth,
+ m_ModeInfo[idx].VisScreenHeight,
+ m_ModeInfo[idx].BitsPerPlane));
+ }
+
+ if (m_Segment != 0)
+ {
+ x86BiosFreeBuffer (m_Segment, m_Offset);
+ }
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return Status;
+}
+
+NTSTATUS VgaDevice::QueryCurrentMode(PVIDEO_MODE RequestedMode)
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ NTSTATUS Status = STATUS_SUCCESS;
+ UNREFERENCED_PARAMETER(RequestedMode);
+
+// PVBE_MODEINFO VBEMode = &m_ModeInfo[m_CurrentMode];
+ return Status;
+}
+
+NTSTATUS VgaDevice::SetCurrentMode(ULONG Mode)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s Mode = %x\n", __FUNCTION__, Mode));
+ X86BIOS_REGISTERS regs = {0};
+ regs.Eax = 0x4F02;
+ regs.Ebx = Mode | 0x000;
+ if (!x86BiosCall (0x10, &regs))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosCall failed\n"));
+ return STATUS_UNSUCCESSFUL;
+ }
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__));
+ return Status;
+}
+
+NTSTATUS VgaDevice::GetCurrentMode(ULONG* pMode)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__));
+ X86BIOS_REGISTERS regs = {0};
+ regs.Eax = 0x4F03;
+ if (!x86BiosCall (0x10, &regs))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosCall failed\n"));
+ return STATUS_UNSUCCESSFUL;
+ }
+ *pMode = regs.Ebx;
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> EAX = %x, EBX = %x Mode = %x\n", regs.Eax, regs.Ebx, *pMode));
+ return Status;
+}
+
+NTSTATUS VgaDevice::HWInit(PCM_RESOURCE_LIST pResList, DXGK_DISPLAY_INFORMATION* pDispInfo)
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ UNREFERENCED_PARAMETER(pResList);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return GetModeList(pDispInfo);
+}
+
+NTSTATUS VgaDevice::HWClose(void)
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS VgaDevice::SetPowerState(_In_ DEVICE_POWER_STATE DevicePowerState, DXGK_DISPLAY_INFORMATION* pDispInfo)
+{
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__));
+
+ X86BIOS_REGISTERS regs = {0};
+ regs.Eax = 0x4F10;
+ regs.Ebx = 0;
+ switch (DevicePowerState)
+ {
+ case PowerDeviceUnspecified:
+ case PowerDeviceD0: regs.Ebx |= 0x1; break;
+ case PowerDeviceD1:
+ case PowerDeviceD2:
+ case PowerDeviceD3: regs.Ebx |= 0x400; break;
+ }
+ if (!x86BiosCall (0x10, &regs))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("x86BiosCall failed\n"));
+ return STATUS_UNSUCCESSFUL;
+ }
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__));
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+VgaDevice::ExecutePresentDisplayOnly(
+ _In_ BYTE* DstAddr,
+ _In_ UINT DstBitPerPixel,
+ _In_ BYTE* SrcAddr,
+ _In_ UINT SrcBytesPerPixel,
+ _In_ LONG SrcPitch,
+ _In_ ULONG NumMoves,
+ _In_ D3DKMT_MOVE_RECT* Moves,
+ _In_ ULONG NumDirtyRects,
+ _In_ RECT* DirtyRect,
+ _In_ D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation,
+ _In_ const CURRENT_BDD_MODE* pModeCur)
+/*++
+
+ Routine Description:
+
+ The method creates present worker thread and provides context
+ for it filled with present commands
+
+ Arguments:
+
+ DstAddr - address of destination surface
+ DstBitPerPixel - color depth of destination surface
+ SrcAddr - address of source surface
+ SrcBytesPerPixel - bytes per pixel of source surface
+ SrcPitch - source surface pitch (bytes in a row)
+ NumMoves - number of moves to be copied
+ Moves - moves' data
+ NumDirtyRects - number of rectangles to be copied
+ DirtyRect - rectangles' data
+ Rotation - roatation to be performed when executing copy
+ CallBack - callback for present worker thread to report execution status
+
+ Return Value:
+
+ Status
+
+--*/
+{
+
+ PAGED_CODE();
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SIZE_T sizeMoves = NumMoves*sizeof(D3DKMT_MOVE_RECT);
+ SIZE_T sizeRects = NumDirtyRects*sizeof(RECT);
+ SIZE_T size = sizeof(DoPresentMemory) + sizeMoves + sizeRects;
+
+ DoPresentMemory* ctx = reinterpret_cast<DoPresentMemory*>
+ (new (NonPagedPoolNx) BYTE[size]);
+
+ if (!ctx)
+ {
+ return STATUS_NO_MEMORY;
+ }
+
+ RtlZeroMemory(ctx,size);
+
+// const CURRENT_BDD_MODE* pModeCur = &m_CurrentModes[0];
+ ctx->DstAddr = DstAddr;
+ ctx->DstBitPerPixel = DstBitPerPixel;
+ ctx->DstStride = pModeCur->DispInfo.Pitch;
+ ctx->SrcWidth = pModeCur->SrcModeWidth;
+ ctx->SrcHeight = pModeCur->SrcModeHeight;
+ ctx->SrcAddr = NULL;
+ ctx->SrcPitch = SrcPitch;
+ ctx->Rotation = Rotation;
+ ctx->NumMoves = NumMoves;
+ ctx->Moves = Moves;
+ ctx->NumDirtyRects = NumDirtyRects;
+ ctx->DirtyRect = DirtyRect;
+// ctx->SourceID = m_SourceId;
+// ctx->hAdapter = m_DevExt;
+ ctx->Mdl = NULL;
+ ctx->DisplaySource = this;
+
+ // Alternate between synch and asynch execution, for demonstrating
+ // that a real hardware implementation can do either
+
+ {
+ // Map Source into kernel space, as Blt will be executed by system worker thread
+ UINT sizeToMap = SrcBytesPerPixel * ctx->SrcWidth * ctx->SrcHeight;
+
+ PMDL mdl = IoAllocateMdl((PVOID)SrcAddr, sizeToMap, FALSE, FALSE, NULL);
+ if(!mdl)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ KPROCESSOR_MODE AccessMode = static_cast<KPROCESSOR_MODE>(( SrcAddr <=
+ (BYTE* const) MM_USER_PROBE_ADDRESS)?UserMode:KernelMode);
+ __try
+ {
+ // Probe and lock the pages of this buffer in physical memory.
+ // We need only IoReadAccess.
+ MmProbeAndLockPages(mdl, AccessMode, IoReadAccess);
+ }
+ #pragma prefast(suppress: __WARNING_EXCEPTIONEXECUTEHANDLER, "try/except is only able to protect against user-mode errors and these are the only errors we try to catch here");
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = GetExceptionCode();
+ IoFreeMdl(mdl);
+ return Status;
+ }
+
+ // Map the physical pages described by the MDL into system space.
+ // Note: double mapping the buffer this way causes lot of system
+ // overhead for large size buffers.
+ ctx->SrcAddr = reinterpret_cast<BYTE*>
+ (MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority ));
+
+ if(!ctx->SrcAddr) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ MmUnlockPages(mdl);
+ IoFreeMdl(mdl);
+ return Status;
+ }
+
+ // Save Mdl to unmap and unlock the pages in worker thread
+ ctx->Mdl = mdl;
+ }
+
+ BYTE* rects = reinterpret_cast<BYTE*>(ctx+1);
+
+ // copy moves and update pointer
+ if (Moves)
+ {
+ memcpy(rects,Moves,sizeMoves);
+ ctx->Moves = reinterpret_cast<D3DKMT_MOVE_RECT*>(rects);
+ rects += sizeMoves;
+ }
+
+ // copy dirty rects and update pointer
+ if (DirtyRect)
+ {
+ memcpy(rects,DirtyRect,sizeRects);
+ ctx->DirtyRect = reinterpret_cast<RECT*>(rects);
+ }
+
+
+// HwExecutePresentDisplayOnly((PVOID)ctx);
+
+
+ // Set up destination blt info
+ BLT_INFO DstBltInfo;
+ DstBltInfo.pBits = ctx->DstAddr;
+ DstBltInfo.Pitch = ctx->DstStride;
+ DstBltInfo.BitsPerPel = ctx->DstBitPerPixel;
+ DstBltInfo.Offset.x = 0;
+ DstBltInfo.Offset.y = 0;
+ DstBltInfo.Rotation = ctx->Rotation;
+ DstBltInfo.Width = ctx->SrcWidth;
+ DstBltInfo.Height = ctx->SrcHeight;
+
+ // Set up source blt info
+ BLT_INFO SrcBltInfo;
+ SrcBltInfo.pBits = ctx->SrcAddr;
+ SrcBltInfo.Pitch = ctx->SrcPitch;
+ SrcBltInfo.BitsPerPel = 32;
+ SrcBltInfo.Offset.x = 0;
+ SrcBltInfo.Offset.y = 0;
+ SrcBltInfo.Rotation = D3DKMDT_VPPR_IDENTITY;
+ if (ctx->Rotation == D3DKMDT_VPPR_ROTATE90 ||
+ ctx->Rotation == D3DKMDT_VPPR_ROTATE270)
+ {
+ SrcBltInfo.Width = DstBltInfo.Height;
+ SrcBltInfo.Height = DstBltInfo.Width;
+ }
+ else
+ {
+ SrcBltInfo.Width = DstBltInfo.Width;
+ SrcBltInfo.Height = DstBltInfo.Height;
+ }
+
+
+ // Copy all the scroll rects from source image to video frame buffer.
+ for (UINT i = 0; i < ctx->NumMoves; i++)
+ {
+ POINT* pSourcePoint = &ctx->Moves[i].SourcePoint;
+ RECT* pDestRect = &ctx->Moves[i].DestRect;
+
+// DbgPrint(TRACE_LEVEL_FATAL, ("--- %d SourcePoint.x = %ld, SourcePoint.y = %ld, DestRect.bottom = %ld, DestRect.left = %ld, DestRect.right = %ld, DestRect.top = %ld\n",
+// i , pSourcePoint->x, pSourcePoint->y, pDestRect->bottom, pDestRect->left, pDestRect->right, pDestRect->top));
+
+ BltBits(&DstBltInfo,
+ &SrcBltInfo,
+ 1, // NumRects
+ pDestRect);
+ }
+
+ // Copy all the dirty rects from source image to video frame buffer.
+ for (UINT i = 0; i < ctx->NumDirtyRects; i++)
+ {
+ RECT* pDirtyRect = &ctx->DirtyRect[i];
+// DbgPrint(TRACE_LEVEL_FATAL, ("--- %d pDirtyRect->bottom = %ld, pDirtyRect->left = %ld, pDirtyRect->right = %ld, pDirtyRect->top = %ld\n",
+// i, pDirtyRect->bottom, pDirtyRect->left, pDirtyRect->right, pDirtyRect->top));
+
+ BltBits(&DstBltInfo,
+ &SrcBltInfo,
+ 1, // NumRects
+ pDirtyRect);
+ }
+
+ // Unmap unmap and unlock the pages.
+ if (ctx->Mdl)
+ {
+ MmUnlockPages(ctx->Mdl);
+ IoFreeMdl(ctx->Mdl);
+ }
+ delete [] reinterpret_cast<BYTE*>(ctx);
+
+ return STATUS_SUCCESS;
+}
+
+VOID VgaDevice::BlackOutScreen(CURRENT_BDD_MODE* pCurrentBddMod)
+{
+ PAGED_CODE();
+
+ UINT ScreenHeight = pCurrentBddMod->DispInfo.Height;
+ UINT ScreenPitch = pCurrentBddMod->DispInfo.Pitch;
+
+ PHYSICAL_ADDRESS NewPhysAddrStart = pCurrentBddMod->DispInfo.PhysicAddress;
+ PHYSICAL_ADDRESS NewPhysAddrEnd;
+ NewPhysAddrEnd.QuadPart = NewPhysAddrStart.QuadPart + (ScreenHeight * ScreenPitch);
+
+ if (pCurrentBddMod->Flags.FrameBufferIsActive)
+ {
+ BYTE* MappedAddr = reinterpret_cast<BYTE*>(pCurrentBddMod->FrameBuffer.Ptr);
+
+ // Zero any memory at the start that hasn't been zeroed recently
+ if (NewPhysAddrStart.QuadPart < pCurrentBddMod->ZeroedOutStart.QuadPart)
+ {
+ if (NewPhysAddrEnd.QuadPart < pCurrentBddMod->ZeroedOutStart.QuadPart)
+ {
+ // No overlap
+ RtlZeroMemory(MappedAddr, ScreenHeight * ScreenPitch);
+ }
+ else
+ {
+ RtlZeroMemory(MappedAddr, (UINT)(pCurrentBddMod->ZeroedOutStart.QuadPart - NewPhysAddrStart.QuadPart));
+ }
+ }
+
+ // Zero any memory at the end that hasn't been zeroed recently
+ if (NewPhysAddrEnd.QuadPart > pCurrentBddMod->ZeroedOutEnd.QuadPart)
+ {
+ if (NewPhysAddrStart.QuadPart > pCurrentBddMod->ZeroedOutEnd.QuadPart)
+ {
+ // No overlap
+ // NOTE: When actual pixels were the most recent thing drawn, ZeroedOutStart & ZeroedOutEnd will both be 0
+ // and this is the path that will be used to black out the current screen.
+ RtlZeroMemory(MappedAddr, ScreenHeight * ScreenPitch);
+ }
+ else
+ {
+ RtlZeroMemory(MappedAddr, (UINT)(NewPhysAddrEnd.QuadPart - pCurrentBddMod->ZeroedOutEnd.QuadPart));
+ }
+ }
+ }
+
+ pCurrentBddMod->ZeroedOutStart.QuadPart = NewPhysAddrStart.QuadPart;
+ pCurrentBddMod->ZeroedOutEnd.QuadPart = NewPhysAddrEnd.QuadPart;
+}
+
+BOOLEAN VgaDevice::InterruptRoutine(_In_ PDXGKRNL_INTERFACE pDxgkInterface, _In_ ULONG MessageNumber)
+{
+ UNREFERENCED_PARAMETER(pDxgkInterface);
+ UNREFERENCED_PARAMETER(MessageNumber);
+ return FALSE;
+}
+
+VOID VgaDevice::DpcRoutine(PVOID)
+{
+}
+
+VOID VgaDevice::ResetDevice(VOID)
+{
+}
+
+NTSTATUS VgaDevice::SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape)
+{
+ return STATUS_NOT_SUPPORTED;
+}
+
+NTSTATUS VgaDevice::SetPointerPosition(_In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition)
+{
+ return STATUS_SUCCESS;
+}
+
+QxlDevice::QxlDevice(_In_ QxlDod* pQxlDod)
+{
+ m_pQxlDod = pQxlDod;
+ m_ModeInfo = NULL;
+ m_ModeCount = 0;
+ m_ModeNumbers = NULL;
+ m_CurrentMode = 0;
+ m_FreeOutputs = 0;
+ m_Pending = 0;
+}
+
+QxlDevice::~QxlDevice(void)
+{
+ delete [] reinterpret_cast<BYTE*>(m_ModeInfo);
+ delete [] reinterpret_cast<BYTE*>(m_ModeNumbers);
+ m_ModeInfo = NULL;
+ m_ModeNumbers = NULL;
+ m_CurrentMode = 0;
+ m_ModeCount = 0;
+}
+
+BOOL QxlDevice::SetVideoModeInfo(UINT Idx, QXLMode* pModeInfo)
+{
+ PVIDEO_MODE_INFORMATION pMode = NULL;
+ ULONG color_bits;
+ PAGED_CODE();
+
+ pMode = &m_ModeInfo[Idx];
+ pMode->Length = sizeof(VIDEO_MODE_INFORMATION);
+ pMode->ModeIndex = Idx;//m_ModeNumbers[Idx];
+ pMode->VisScreenWidth = pModeInfo->x_res;
+ pMode->VisScreenHeight = pModeInfo->y_res;
+ pMode->ScreenStride = pModeInfo->stride;
+ pMode->NumberOfPlanes = 1;
+ pMode->BitsPerPlane = pModeInfo->bits;
+ pMode->Frequency = 100;
+ pMode->XMillimeter = pModeInfo->x_mili;
+ pMode->YMillimeter = pModeInfo->y_mili;
+ color_bits = (pModeInfo->bits == 16) ? 5 : 8;
+ pMode->NumberRedBits = color_bits;
+ pMode->NumberGreenBits = color_bits;
+ pMode->NumberBlueBits = color_bits;
+
+ pMode->BlueMask = (1 << color_bits) - 1;
+ pMode->GreenMask = pMode->BlueMask << color_bits;
+ pMode->RedMask = pMode->GreenMask << color_bits;
+
+ pMode->AttributeFlags = VIDEO_MODE_COLOR | VIDEO_MODE_GRAPHICS;
+ pMode->VideoMemoryBitmapWidth = pModeInfo->x_res;
+ pMode->VideoMemoryBitmapHeight = pModeInfo->y_res;
+ pMode->DriverSpecificAttributeFlags = pModeInfo->orientation;
+ return TRUE;
+}
+
+NTSTATUS QxlDevice::GetModeList(DXGK_DISPLAY_INFORMATION* pDispInfo)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_SUCCESS;
+ QXLModes *modes;
+ ULONG ModeCount;
+ ULONG SuitableModeCount;
+ USHORT CurrentMode;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ modes = (QXLModes *)((UCHAR*)m_RomHdr + m_RomHdr->modes_offset);
+ if (m_RomSize < m_RomHdr->modes_offset + sizeof(QXLModes) ||
+ (ModeCount = modes->n_modes) == 0 || m_RomSize <
+ m_RomHdr->modes_offset + sizeof(QXLModes) + ModeCount * sizeof(QXLMode)) {
+ DbgPrint(TRACE_LEVEL_ERROR, ("%s: bad rom size\n", __FUNCTION__));
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ DbgPrint(TRACE_LEVEL_ERROR, ("%s: ModeCount = %d\n", __FUNCTION__, ModeCount));
+
+ ModeCount += 2;
+ m_ModeInfo = reinterpret_cast<PVIDEO_MODE_INFORMATION> (new (PagedPool) BYTE[sizeof (VIDEO_MODE_INFORMATION) * ModeCount]);
+ m_ModeNumbers = reinterpret_cast<PUSHORT> (new (PagedPool) BYTE [sizeof (USHORT) * ModeCount]);
+ m_CurrentMode = 0;
+
+ UINT Height = pDispInfo->Height;
+ UINT Width = pDispInfo->Width;
+ UINT BitsPerPixel = BPPFromPixelFormat(pDispInfo->ColorFormat);
+ for (CurrentMode = 0, SuitableModeCount = 0;
+ CurrentMode < ModeCount;
+ CurrentMode++)
+ {
+
+ QXLMode* tmpModeInfo = &modes->modes[CurrentMode];
+
+ DbgPrint(TRACE_LEVEL_ERROR, ("%s: modes[%d] x_res = %d, y_res = %d, bits = %d BitsPerPixel = %d\n", __FUNCTION__, CurrentMode, tmpModeInfo->x_res, tmpModeInfo->y_res, tmpModeInfo->bits, BitsPerPixel));
+
+ if (tmpModeInfo->x_res >= Width &&
+ tmpModeInfo->y_res >= Height &&
+ tmpModeInfo->bits == 32)
+ {
+ m_ModeNumbers[SuitableModeCount] = CurrentMode;
+ SetVideoModeInfo(SuitableModeCount, tmpModeInfo);
+ if (tmpModeInfo->x_res == 1024 &&
+ tmpModeInfo->y_res == 768)
+ {
+ m_CurrentMode = (USHORT)SuitableModeCount;
+ }
+ SuitableModeCount++;
+ }
+ }
+
+ if (SuitableModeCount == 0)
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("No video modes supported\n"));
+ Status = STATUS_UNSUCCESSFUL;
+ }
+
+// m_CurrentMode = m_ModeNumbers[0];
+ m_ModeCount = SuitableModeCount;
+ DbgPrint(TRACE_LEVEL_ERROR, ("ModeCount filtered %d\n", m_ModeCount));
+ for (ULONG idx = 0; idx < m_ModeCount; idx++)
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("type %x, XRes = %d, YRes = %d, BPP = %d\n",
+ m_ModeNumbers[idx],
+ m_ModeInfo[idx].VisScreenWidth,
+ m_ModeInfo[idx].VisScreenHeight,
+ m_ModeInfo[idx].BitsPerPlane));
+ }
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return Status;
+}
+
+NTSTATUS QxlDevice::QueryCurrentMode(PVIDEO_MODE RequestedMode)
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ NTSTATUS Status = STATUS_SUCCESS;
+ UNREFERENCED_PARAMETER(RequestedMode);
+ return Status;
+}
+
+NTSTATUS QxlDevice::SetCurrentMode(ULONG Mode)
+{
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s Mode = %x\n", __FUNCTION__, Mode));
+ for (ULONG idx = 0; idx < m_ModeCount; idx++)
+ {
+ if (Mode == m_ModeNumbers[idx])
+ {
+ DestroyPrimarySurface();
+ CreatePrimarySurface(&m_ModeInfo[idx]);
+ return STATUS_SUCCESS;
+ }
+ }
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS QxlDevice::GetCurrentMode(ULONG* pMode)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__));
+ UNREFERENCED_PARAMETER(pMode);
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__));
+ return Status;
+}
+
+NTSTATUS QxlDevice::SetPowerState(_In_ DEVICE_POWER_STATE DevicePowerState, DXGK_DISPLAY_INFORMATION* pDispInfo)
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ switch (DevicePowerState)
+ {
+ case PowerDeviceUnspecified:
+ case PowerDeviceD0: QxlInit(pDispInfo); break;
+ case PowerDeviceD1:
+ case PowerDeviceD2:
+ case PowerDeviceD3: QxlClose(); break;
+ }
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS QxlDevice::HWInit(PCM_RESOURCE_LIST pResList, DXGK_DISPLAY_INFORMATION* pDispInfo)
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ NTSTATUS Status = STATUS_SUCCESS;
+ PDXGKRNL_INTERFACE pDxgkInterface = m_pQxlDod->GetDxgkInterrface();
+ UINT pci_range = QXL_RAM_RANGE_INDEX;
+ for (ULONG i = 0; i < pResList->Count; ++i)
+ {
+ PCM_FULL_RESOURCE_DESCRIPTOR pFullResDescriptor = &pResList->List[i];
+ for (ULONG j = 0; j < pFullResDescriptor->PartialResourceList.Count; ++j)
+ {
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR pResDescriptor = &pFullResDescriptor->PartialResourceList.PartialDescriptors[j];
+ switch (pResDescriptor->Type)
+ {
+ case CmResourceTypePort:
+ {
+ PVOID IoBase = NULL;
+ ULONG IoLength = pResDescriptor->u.Port.Length;
+ NTSTATUS Status = STATUS_SUCCESS;
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("IO Port Info [%08I64X-%08I64X]\n",
+ pResDescriptor->u.Port.Start.QuadPart,
+ pResDescriptor->u.Port.Start.QuadPart +
+ pResDescriptor->u.Port.Length));
+ m_IoMapped = (pResDescriptor->Flags & CM_RESOURCE_PORT_IO) ? FALSE : TRUE;
+ if(m_IoMapped)
+ {
+ Status = pDxgkInterface->DxgkCbMapMemory(pDxgkInterface->DeviceHandle,
+ pResDescriptor->u.Port.Start,
+ IoLength,
+ TRUE, /* IN BOOLEAN InIoSpace */
+ FALSE, /* IN BOOLEAN MapToUserMode */
+ MmNonCached, /* IN MEMORY_CACHING_TYPE CacheType */
+ &IoBase /*OUT PVOID *VirtualAddress*/
+ );
+ if (Status == STATUS_SUCCESS)
+ {
+ m_IoBase = (PUCHAR)IoBase;
+ m_IoSize = IoLength;
+ }
+ else
+ {
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("DxgkCbMapMemor failed with status 0x%X\n", Status));
+ }
+ }
+ else
+ {
+ m_IoBase = (PUCHAR)(ULONG_PTR)pResDescriptor->u.Port.Start.QuadPart;
+ m_IoSize = pResDescriptor->u.Port.Length;
+ }
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("io_base [%X-%X]\n",
+ m_IoBase,
+ m_IoBase +
+ m_IoSize));
+ }
+ break;
+ case CmResourceTypeInterrupt:
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("Interrupt level: 0x%0x, Vector: 0x%0x\n",
+ pResDescriptor->u.Interrupt.Level,
+ pResDescriptor->u.Interrupt.Vector));
+ break;
+ case CmResourceTypeMemory:
+ {
+ PVOID MemBase = NULL;
+ ULONG MemLength = pResDescriptor->u.Memory.Length;
+ NTSTATUS Status = STATUS_SUCCESS;
+ DbgPrint( TRACE_LEVEL_INFORMATION, ("Memory mapped: (%x:%x) Length:(%x)\n",
+ pResDescriptor->u.Memory.Start.LowPart,
+ pResDescriptor->u.Memory.Start.HighPart,
+ pResDescriptor->u.Memory.Length));
+ Status = pDxgkInterface->DxgkCbMapMemory(pDxgkInterface->DeviceHandle,
+ pResDescriptor->u.Memory.Start,
+ MemLength,
+ FALSE, /* IN BOOLEAN InIoSpace */
+ FALSE, /* IN BOOLEAN MapToUserMode */
+ MmNonCached, /* IN MEMORY_CACHING_TYPE CacheType */
+ &MemBase /*OUT PVOID *VirtualAddress*/
+ );
+ if (Status == STATUS_SUCCESS)
+ {
+ switch (pci_range)
+ {
+ case QXL_RAM_RANGE_INDEX:
+ m_RamPA = pResDescriptor->u.Memory.Start;
+ m_RamStart = (UINT8*)MemBase;
+ m_RamSize = MemLength;
+ pci_range = QXL_VRAM_RANGE_INDEX;
+ break;
+ case QXL_VRAM_RANGE_INDEX:
+ m_VRamPA = pResDescriptor->u.Memory.Start;
+ m_VRamStart = (UINT8*)MemBase;
+ m_VRamSize = MemLength;
+ pci_range = QXL_ROM_RANGE_INDEX;
+ break;
+ case QXL_ROM_RANGE_INDEX:
+ m_RomHdr = (QXLRom*)MemBase;
+ m_RomSize = MemLength;
+ pci_range = QXL_PCI_RANGES;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ break;
+ case CmResourceTypeDma:
+ DbgPrint( TRACE_LEVEL_INFORMATION, ("Dma\n"));
+ break;
+ case CmResourceTypeDeviceSpecific:
+ DbgPrint( TRACE_LEVEL_INFORMATION, ("Device Specific\n"));
+ break;
+ case CmResourceTypeBusNumber:
+ DbgPrint( TRACE_LEVEL_INFORMATION, ("Bus number\n"));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ if (m_IoBase == NULL || m_IoSize == 0 ||
+ m_RomHdr == NULL || m_RomSize == 0 ||
+ m_RomHdr->magic != QXL_ROM_MAGIC ||
+ m_RamStart == NULL || m_RamSize == 0 ||
+ m_VRamStart == NULL || m_VRamSize == 0 ||
+ (m_RamHdr = (QXLRam *)(m_RamStart + m_RomHdr->ram_header_offset)) == NULL ||
+ m_RamHdr->magic != QXL_RAM_MAGIC)
+ {
+ UnmapMemory();
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ m_LogBuf = m_RamHdr->log_buf;
+ m_LogPort = m_IoBase + QXL_IO_LOG;
+
+ CreateEvents();
+
+ return QxlInit(pDispInfo);
+}
+
+NTSTATUS QxlDevice::QxlInit(DXGK_DISPLAY_INFORMATION* pDispInfo)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (!InitMemSlots()) {
+ DestroyMemSlots();
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ Status = GetModeList(pDispInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("GetModeList failed with status 0x%X\n",
+ Status));
+ return Status;
+ }
+
+ WRITE_PORT_UCHAR((PUCHAR)(m_IoBase + QXL_IO_RESET), 0);
+ CreateRings();
+ m_RamHdr->int_mask = QXL_INTERRUPT_MASK;
+ CreateMemSlots();
+ InitDeviceMemoryResources();
+ return Status;
+}
+
+void QxlDevice::QxlClose()
+{
+ DestroyMemSlots();
+}
+
+void QxlDevice::UnmapMemory(void)
+{
+ PDXGKRNL_INTERFACE pDxgkInterface = m_pQxlDod->GetDxgkInterrface();
+ if (m_IoMapped && m_IoBase)
+ {
+ pDxgkInterface->DxgkCbUnmapMemory( pDxgkInterface->DeviceHandle, &m_IoBase);
+ }
+ m_IoBase = NULL;
+ if (m_RomHdr)
+ {
+ pDxgkInterface->DxgkCbUnmapMemory( pDxgkInterface->DeviceHandle, &m_RomHdr);
+ m_RomHdr = NULL;
+ }
+
+ if (m_RamStart)
+ {
+ pDxgkInterface->DxgkCbUnmapMemory( pDxgkInterface->DeviceHandle, &m_RamStart);
+ m_RamStart = NULL;
+ }
+
+ if (m_VRamStart)
+ {
+ pDxgkInterface->DxgkCbUnmapMemory( pDxgkInterface->DeviceHandle, &m_VRamStart);
+ m_VRamStart = NULL;
+ }
+}
+
+BOOL QxlDevice::InitMemSlots(void)
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ m_NumMemSlots = m_RomHdr->slots_end;
+ m_SlotGenBits = m_RomHdr->slot_gen_bits;
+ m_SlotIdBits = m_RomHdr->slot_id_bits;
+ m_VaSlotMask = (~(uint64_t)0) >> (m_SlotIdBits + m_SlotGenBits);
+ size_t size = m_NumMemSlots * sizeof(MemSlot);
+ m_MemSlots = reinterpret_cast<MemSlot*>
+ (new (PagedPool) BYTE[size]);
+ if (m_MemSlots)
+ {
+ RtlZeroMemory(m_MemSlots, size);
+ return TRUE;
+ }
+ DbgPrint(TRACE_LEVEL_ERROR, ("---> %s Failed to init mem slot\n", __FUNCTION__));
+ return FALSE;
+}
+
+void QxlDevice::DestroyMemSlots(void)
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ delete [] reinterpret_cast<BYTE*>(m_MemSlots);
+ m_MemSlots = NULL;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+}
+
+void QxlDevice::CreatePrimarySurface(PVIDEO_MODE_INFORMATION pModeInfo)
+{
+ QXLSurfaceCreate *primary_surface_create;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ primary_surface_create = &m_RamHdr->create_surface;
+ primary_surface_create->format = pModeInfo->BitsPerPlane;
+ primary_surface_create->width = pModeInfo->VisScreenWidth;
+ primary_surface_create->height = pModeInfo->VisScreenHeight;
+ primary_surface_create->stride = pModeInfo->ScreenStride;
+
+ primary_surface_create->mem = PA( m_RamStart, m_MainMemSlot);
+
+ primary_surface_create->flags = QXL_SURF_FLAG_KEEP_DATA;
+ primary_surface_create->type = QXL_SURF_TYPE_PRIMARY;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--> %s format = %d, width = %d, height = %d, stride = %d\n", __FUNCTION__, pModeInfo->BitsPerPlane, pModeInfo->VisScreenWidth, pModeInfo->VisScreenHeight,
+ pModeInfo->ScreenStride));
+// AsyncIo(QXL_IO_CREATE_PRIMARY_ASYNC, 0);
+ SyncIo(QXL_IO_CREATE_PRIMARY, 0);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+}
+
+void QxlDevice::DestroyPrimarySurface(void)
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+// AsyncIo(QXL_IO_DESTROY_PRIMARY_ASYNC, 0);
+ SyncIo(QXL_IO_DESTROY_PRIMARY, 0);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+}
+
+_inline QXLPHYSICAL QxlDevice::PA(PVOID virt, UINT8 slot_id)
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--> %s\n", __FUNCTION__));
+ MemSlot *pSlot = &m_MemSlots[slot_id];;
+ return pSlot->high_bits | ((UINT64)virt - pSlot->start_virt_addr);
+}
+
+_inline UINT64 QxlDevice::VA(QXLPHYSICAL paddr, UINT8 slot_id)
+{
+ UINT64 virt;
+ MemSlot *pSlot = &m_MemSlots[slot_id];;
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ virt = paddr & m_VaSlotMask;
+ virt += pSlot->start_virt_addr;;
+
+ return virt;
+}
+
+void QxlDevice::SetupHWSlot(UINT8 Idx, MemSlot *pSlot)
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ m_RamHdr->mem_slot.mem_start = pSlot->start_phys_addr;
+ m_RamHdr->mem_slot.mem_end = pSlot->end_phys_addr;
+ WRITE_PORT_UCHAR((PUCHAR)(m_IoBase + QXL_IO_MEMSLOT_ADD), Idx);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+}
+
+BOOL QxlDevice::CreateEvents()
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ KeInitializeEvent(&m_DisplayEvent,
+ SynchronizationEvent,
+ FALSE);
+ KeInitializeEvent(&m_CursorEvent,
+ SynchronizationEvent,
+ FALSE);
+ KeInitializeEvent(&m_IoCmdEvent,
+ SynchronizationEvent,
+ FALSE);
+ KeInitializeMutex(&m_MemLock,1);
+ KeInitializeMutex(&m_CmdLock,1);
+ KeInitializeMutex(&m_IoLock,1);
+ KeInitializeMutex(&m_CrsLock,1);
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return TRUE;
+}
+
+BOOL QxlDevice::CreateRings()
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ m_CommandRing = &(m_RamHdr->cmd_ring);
+ m_CursorRing = &(m_RamHdr->cursor_ring);
+ m_ReleaseRing = &(m_RamHdr->release_ring);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return TRUE;
+}
+
+void QxlDevice::AsyncIo(UCHAR Port, UCHAR Value)
+{
+ LARGE_INTEGER timeout;
+ KeWaitForSingleObject
+ (
+ &m_IoLock,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+ WRITE_PORT_UCHAR(m_IoBase + Port, Value);
+ timeout.QuadPart = -60000L * 1000 * 10;
+ WAIT_FOR_EVENT(m_IoCmdEvent, &timeout);
+ KeReleaseMutex(&m_IoLock,FALSE);
+}
+
+void QxlDevice::SyncIo(UCHAR Port, UCHAR Value)
+{
+ KeWaitForSingleObject
+ (
+ &m_IoLock,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+ WRITE_PORT_UCHAR(m_IoBase + Port, Value);
+ KeReleaseMutex(&m_IoLock,FALSE);
+}
+
+UINT8 QxlDevice::SetupMemSlot(UINT8 Idx, UINT64 pastart, UINT64 paend, UINT64 vastart, UINT64 vaend)
+{
+ UINT64 high_bits;
+ MemSlot *pSlot;
+ UINT8 slot_index;
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ slot_index = m_RomHdr->slots_start + Idx;
+ pSlot = &m_MemSlots[slot_index];
+ pSlot->start_phys_addr = pastart;
+ pSlot->end_phys_addr = paend;
+ pSlot->start_virt_addr = vastart;
+ pSlot->end_virt_addr = vaend;
+
+ SetupHWSlot(Idx + 1, pSlot);
+
+ pSlot->generation = m_RomHdr->slot_generation;
+ high_bits = slot_index << m_SlotGenBits;
+ high_bits |= pSlot->generation;
+ high_bits <<= (64 - (m_SlotGenBits + m_SlotIdBits));
+ pSlot->high_bits = high_bits;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return slot_index;
+}
+
+BOOL QxlDevice::CreateMemSlots(void)
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s 3\n", __FUNCTION__));
+ UINT64 len = m_RomHdr->surface0_area_size + m_RomHdr->num_pages * PAGE_SIZE;
+ m_MainMemSlot = SetupMemSlot(0,
+ (UINT64)m_RamPA.QuadPart,
+ (UINT64)(m_RamPA.QuadPart + len),
+ (UINT64)m_RamStart,
+ (UINT64)(m_RamStart + len));
+ len = m_VRamSize;
+ m_SurfaceMemSlot = SetupMemSlot(1,
+ (UINT64)m_VRamPA.QuadPart,
+ (UINT64)(m_VRamPA.QuadPart + len),
+ (UINT64)m_VRamStart,
+ (UINT64)(m_VRamStart + len));
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return TRUE;
+}
+
+void QxlDevice::InitDeviceMemoryResources(void)
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s num_pages = %d\n", __FUNCTION__, m_RomHdr->num_pages));
+ InitMspace(MSPACE_TYPE_DEVRAM, (m_RamStart + m_RomHdr->surface0_area_size), (size_t)(m_RomHdr->num_pages * PAGE_SIZE));
+ InitMspace(MSPACE_TYPE_VRAM, m_VRamStart, m_VRamSize);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+}
+
+void QxlDevice::InitMspace(UINT32 mspace_type, UINT8 *start, size_t capacity)
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s type = %d, start = %p, capacity = %d\n", __FUNCTION__, mspace_type, start, capacity));
+ m_MSInfo[mspace_type]._mspace = create_mspace_with_base(start, capacity, 0, this);
+ m_MSInfo[mspace_type].mspace_start = start;
+ m_MSInfo[mspace_type].mspace_end = start + capacity;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s _mspace = %p\n", __FUNCTION__, m_MSInfo[mspace_type]._mspace));
+}
+
+void QxlDevice::ResetDevice(void)
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ m_RamHdr->int_mask = ~0;
+ WRITE_PORT_UCHAR(m_IoBase + QXL_IO_MEMSLOT_ADD, 0);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+}
+
+NTSTATUS
+QxlDevice::ExecutePresentDisplayOnly(
+ _In_ BYTE* DstAddr,
+ _In_ UINT DstBitPerPixel,
+ _In_ BYTE* SrcAddr,
+ _In_ UINT SrcBytesPerPixel,
+ _In_ LONG SrcPitch,
+ _In_ ULONG NumMoves,
+ _In_ D3DKMT_MOVE_RECT* Moves,
+ _In_ ULONG NumDirtyRects,
+ _In_ RECT* DirtyRect,
+ _In_ D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation,
+ _In_ const CURRENT_BDD_MODE* pModeCur)
+{
+ PAGED_CODE();
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SIZE_T sizeMoves = NumMoves*sizeof(D3DKMT_MOVE_RECT);
+ SIZE_T sizeRects = NumDirtyRects*sizeof(RECT);
+ SIZE_T size = sizeof(DoPresentMemory) + sizeMoves + sizeRects;
+
+ DoPresentMemory* ctx = reinterpret_cast<DoPresentMemory*>
+ (new (NonPagedPoolNx) BYTE[size]);
+
+ if (!ctx)
+ {
+ return STATUS_NO_MEMORY;
+ }
+
+ RtlZeroMemory(ctx,size);
+
+// const CURRENT_BDD_MODE* pModeCur = &m_CurrentModes[0];
+ ctx->DstAddr = DstAddr;
+ ctx->DstBitPerPixel = DstBitPerPixel;
+ ctx->DstStride = pModeCur->DispInfo.Pitch;
+ ctx->SrcWidth = pModeCur->SrcModeWidth;
+ ctx->SrcHeight = pModeCur->SrcModeHeight;
+ ctx->SrcAddr = NULL;
+ ctx->SrcPitch = SrcPitch;
+ ctx->Rotation = Rotation;
+ ctx->NumMoves = NumMoves;
+ ctx->Moves = Moves;
+ ctx->NumDirtyRects = NumDirtyRects;
+ ctx->DirtyRect = DirtyRect;
+// ctx->SourceID = m_SourceId;
+// ctx->hAdapter = m_DevExt;
+ ctx->Mdl = NULL;
+ ctx->DisplaySource = this;
+
+ // Alternate between synch and asynch execution, for demonstrating
+ // that a real hardware implementation can do either
+
+ {
+ // Map Source into kernel space, as Blt will be executed by system worker thread
+ UINT sizeToMap = SrcBytesPerPixel * ctx->SrcWidth * ctx->SrcHeight;
+
+ PMDL mdl = IoAllocateMdl((PVOID)SrcAddr, sizeToMap, FALSE, FALSE, NULL);
+ if(!mdl)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ KPROCESSOR_MODE AccessMode = static_cast<KPROCESSOR_MODE>(( SrcAddr <=
+ (BYTE* const) MM_USER_PROBE_ADDRESS)?UserMode:KernelMode);
+ __try
+ {
+ // Probe and lock the pages of this buffer in physical memory.
+ // We need only IoReadAccess.
+ MmProbeAndLockPages(mdl, AccessMode, IoReadAccess);
+ }
+ #pragma prefast(suppress: __WARNING_EXCEPTIONEXECUTEHANDLER, "try/except is only able to protect against user-mode errors and these are the only errors we try to catch here");
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = GetExceptionCode();
+ IoFreeMdl(mdl);
+ return Status;
+ }
+
+ // Map the physical pages described by the MDL into system space.
+ // Note: double mapping the buffer this way causes lot of system
+ // overhead for large size buffers.
+ ctx->SrcAddr = reinterpret_cast<BYTE*>
+ (MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority ));
+
+ if(!ctx->SrcAddr) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ MmUnlockPages(mdl);
+ IoFreeMdl(mdl);
+ return Status;
+ }
+
+ // Save Mdl to unmap and unlock the pages in worker thread
+ ctx->Mdl = mdl;
+ }
+
+ BYTE* rects = reinterpret_cast<BYTE*>(ctx+1);
+
+ // copy moves and update pointer
+ if (Moves)
+ {
+ memcpy(rects,Moves,sizeMoves);
+ ctx->Moves = reinterpret_cast<D3DKMT_MOVE_RECT*>(rects);
+ rects += sizeMoves;
+ }
+
+ // copy dirty rects and update pointer
+ if (DirtyRect)
+ {
+ memcpy(rects,DirtyRect,sizeRects);
+ ctx->DirtyRect = reinterpret_cast<RECT*>(rects);
+ }
+
+ // Set up destination blt info
+ BLT_INFO DstBltInfo;
+ DstBltInfo.pBits = ctx->DstAddr;
+ DstBltInfo.Pitch = ctx->DstStride;
+ DstBltInfo.BitsPerPel = ctx->DstBitPerPixel;
+ DstBltInfo.Offset.x = 0;
+ DstBltInfo.Offset.y = 0;
+ DstBltInfo.Rotation = ctx->Rotation;
+ DstBltInfo.Width = ctx->SrcWidth;
+ DstBltInfo.Height = ctx->SrcHeight;
+
+ // Set up source blt info
+ BLT_INFO SrcBltInfo;
+ SrcBltInfo.pBits = ctx->SrcAddr;
+ SrcBltInfo.Pitch = ctx->SrcPitch;
+ SrcBltInfo.BitsPerPel = 32;
+ SrcBltInfo.Offset.x = 0;
+ SrcBltInfo.Offset.y = 0;
+ SrcBltInfo.Rotation = D3DKMDT_VPPR_IDENTITY;
+ if (ctx->Rotation == D3DKMDT_VPPR_ROTATE90 ||
+ ctx->Rotation == D3DKMDT_VPPR_ROTATE270)
+ {
+ SrcBltInfo.Width = DstBltInfo.Height;
+ SrcBltInfo.Height = DstBltInfo.Width;
+ }
+ else
+ {
+ SrcBltInfo.Width = DstBltInfo.Width;
+ SrcBltInfo.Height = DstBltInfo.Height;
+ }
+
+
+ // Copy all the scroll rects from source image to video frame buffer.
+ for (UINT i = 0; i < ctx->NumMoves; i++)
+ {
+ POINT* pSourcePoint = &ctx->Moves[i].SourcePoint;
+ RECT* pDestRect = &ctx->Moves[i].DestRect;
+
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("--- %d SourcePoint.x = %ld, SourcePoint.y = %ld, DestRect.bottom = %ld, DestRect.left = %ld, DestRect.right = %ld, DestRect.top = %ld\n",
+ i , pSourcePoint->x, pSourcePoint->y, pDestRect->bottom, pDestRect->left, pDestRect->right, pDestRect->top));
+
+ BltBits(&DstBltInfo,
+ &SrcBltInfo,
+ 1, // NumRects
+ pDestRect);
+ }
+
+ // Copy all the dirty rects from source image to video frame buffer.
+ for (UINT i = 0; i < ctx->NumDirtyRects; i++)
+ {
+ RECT* pDirtyRect = &ctx->DirtyRect[i];
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("--- %d pDirtyRect->bottom = %ld, pDirtyRect->left = %ld, pDirtyRect->right = %ld, pDirtyRect->top = %ld\n",
+ i, pDirtyRect->bottom, pDirtyRect->left, pDirtyRect->right, pDirtyRect->top));
+
+ BltBits(&DstBltInfo,
+ &SrcBltInfo,
+ 1, // NumRects
+ pDirtyRect);
+ }
+
+ // Unmap unmap and unlock the pages.
+ if (ctx->Mdl)
+ {
+ MmUnlockPages(ctx->Mdl);
+ IoFreeMdl(ctx->Mdl);
+ }
+ delete [] reinterpret_cast<BYTE*>(ctx);
+
+ return STATUS_SUCCESS;
+}
+
+void QxlDevice::WaitForReleaseRing(void)
+{
+ int wait;
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("--->%s\n", __FUNCTION__));
+
+ for (;;) {
+ LARGE_INTEGER timeout;
+
+ if (SPICE_RING_IS_EMPTY(m_ReleaseRing)) {
+ QXL_SLEEP(10);
+ if (!SPICE_RING_IS_EMPTY(m_ReleaseRing)) {
+ break;
+ }
+ SyncIo(QXL_IO_NOTIFY_OOM, 0);
+ }
+ SPICE_RING_CONS_WAIT(m_ReleaseRing, wait);
+
+ if (!wait) {
+ break;
+ }
+
+ timeout.QuadPart = -30 * 1000 * 10; //30ms
+ WAIT_FOR_EVENT(m_DisplayEvent, &timeout);
+
+ if (SPICE_RING_IS_EMPTY(m_ReleaseRing)) {
+ SyncIo(QXL_IO_NOTIFY_OOM, 0);
+ }
+ }
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("%s: <---\n", __FUNCTION__));
+}
+
+void QxlDevice::FlushReleaseRing()
+{
+ UINT64 output;
+ int notify;
+ int num_to_release = 50;
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ output = m_FreeOutputs;
+
+ while (1) {
+ while (output != 0) {
+ output = ReleaseOutput(output);
+ if (--num_to_release == 0) {
+ break;
+ }
+ }
+
+ if (output != 0 ||
+ SPICE_RING_IS_EMPTY(m_ReleaseRing)) {
+ break;
+ }
+
+ output = *SPICE_RING_CONS_ITEM(m_ReleaseRing);
+ SPICE_RING_POP(m_ReleaseRing, notify);
+ }
+
+ m_FreeOutputs = output;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+}
+
+void QxlDevice::EmptyReleaseRing()
+{
+ KeWaitForSingleObject
+ (
+ &m_MemLock,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+ while (m_FreeOutputs || !SPICE_RING_IS_EMPTY(m_ReleaseRing)) {
+ FlushReleaseRing();
+ }
+ KeReleaseMutex(&m_MemLock,FALSE);
+}
+
+UINT64 QxlDevice::ReleaseOutput(UINT64 output_id)
+{
+ QXLOutput *output = (QXLOutput *)output_id;
+ Resource **now;
+ Resource **end;
+ UINT64 next;
+
+ ASSERT(output_id);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("--->%s 0x%x\n", __FUNCTION__, output));
+
+ for (now = output->resources, end = now + output->num_res; now < end; now++) {
+ RELEASE_RES(*now);
+ }
+ next = *(UINT64*)output->data;
+ FreeMem(MSPACE_TYPE_DEVRAM, output);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---%s\n", __FUNCTION__));
+ return next;
+}
+
+void *QxlDevice::AllocMem(UINT32 mspace_type, size_t size, BOOL force)
+{
+ PVOID ptr;
+
+ ASSERT(m_MSInfo[mspace_type]._mspace);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("--->%s: %p(%d) size %u\n", __FUNCTION__,
+ m_MSInfo[mspace_type]._mspace,
+ mspace_footprint(m_MSInfo[mspace_type]._mspace),
+ size));
+#ifdef DBG
+ mspace_malloc_stats(m_MSInfo[mspace_type]._mspace);
+#endif
+
+ KeWaitForSingleObject
+ (
+ &m_MemLock,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+
+ while (1) {
+ /* Release lots of queued resources, before allocating, as we
+ want to release early to minimize fragmentation risks. */
+ FlushReleaseRing();
+
+ ptr = mspace_malloc(m_MSInfo[mspace_type]._mspace, size);
+ if (ptr) {
+ break;
+ }
+
+ if (m_FreeOutputs != 0 ||
+ !SPICE_RING_IS_EMPTY(m_ReleaseRing)) {
+ /* We have more things to free, try that */
+ continue;
+ }
+
+ if (force) {
+ /* Ask spice to free some stuff */
+ WaitForReleaseRing();
+ } else {
+ /* Fail */
+ break;
+ }
+ }
+ KeReleaseMutex(&m_MemLock,FALSE);
+
+ ASSERT((!ptr && !force) || (ptr >= m_MSInfo[mspace_type].mspace_start &&
+ ptr < m_MSInfo[mspace_type].mspace_end));
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---%s: ptr 0x%x\n", __FUNCTION__, ptr));
+ return ptr;
+}
+
+void QxlDevice::FreeMem(UINT32 mspace_type, void *ptr)
+{
+ ASSERT(m_MSInfo[mspace_type]._mspace);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+#ifdef DBG
+ if (!((UINT8 *)ptr >= m_MSInfo[mspace_type].mspace_start &&
+ (UINT8 *)ptr < m_MSInfo[mspace_type].mspace_end)) {
+ DbgPrint(TRACE_LEVEL_ERROR, ("ASSERT failed @ %s, %p not in [%p, %p) (%d)\n", __FUNCTION__,
+ ptr, m_MSInfo[mspace_type].mspace_start,
+ m_MSInfo[mspace_type].mspace_end, mspace_type));
+ }
+#endif
+ KeWaitForSingleObject
+ (
+ &m_MemLock,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+ mspace_free(m_MSInfo[mspace_type]._mspace, ptr);
+ KeReleaseMutex(&m_MemLock,FALSE);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+}
+
+QXLDrawable *QxlDevice::GetDrawable()
+{
+ QXLOutput *output;
+
+ output = (QXLOutput *)AllocMem(MSPACE_TYPE_DEVRAM, sizeof(QXLOutput) + sizeof(QXLDrawable), TRUE);
+ output->num_res = 0;
+ RESOURCE_TYPE(output, RESOURCE_TYPE_DRAWABLE);
+ ((QXLDrawable *)output->data)->release_info.id = (UINT64)output;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--> %s 0x%x\n", __FUNCTION__, output));
+ return(QXLDrawable *)output->data;
+}
+
+QXLCursorCmd *QxlDevice::CursorCmd()
+{
+ QXLCursorCmd *cursor_cmd;
+ QXLOutput *output;
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ output = (QXLOutput *)AllocMem(MSPACE_TYPE_DEVRAM, sizeof(QXLOutput) + sizeof(QXLCursorCmd), TRUE);
+ output->num_res = 0;
+ RESOURCE_TYPE(output, RESOURCE_TYPE_CURSOR);
+ cursor_cmd = (QXLCursorCmd *)output->data;
+ cursor_cmd->release_info.id = (UINT64)output;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return cursor_cmd;
+}
+
+BOOL QxlDevice::SetClip(const RECT *clip, QXLDrawable *drawable)
+{
+ Resource *rects_res;
+
+ if (clip == NULL) {
+ drawable->clip.type = SPICE_CLIP_TYPE_NONE;
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("%s QXL_CLIP_TYPE_NONE\n", __FUNCTION__));
+ return TRUE;
+ }
+
+ QXLClipRects *rects;
+ rects_res = (Resource *)AllocMem(MSPACE_TYPE_DEVRAM, sizeof(Resource) + sizeof(QXLClipRects) +
+ sizeof(QXLRect), TRUE);
+ rects_res->refs = 1;
+ rects_res->free = FreeClipRectsEx;
+ rects_res->ptr = this;
+ rects = (QXLClipRects *)rects_res->res;
+ rects->num_rects = 1;
+ rects->chunk.data_size = sizeof(QXLRect);
+ rects->chunk.prev_chunk = 0;
+ rects->chunk.next_chunk = 0;
+ CopyRect((QXLRect *)rects->chunk.data, clip);
+
+ DrawableAddRes(drawable, rects_res);
+ drawable->clip.type = SPICE_CLIP_TYPE_RECTS;
+ drawable->clip.data = PA(rects_res->res, m_MainMemSlot);
+ return TRUE;
+}
+
+void QxlDevice::AddRes(QXLOutput *output, Resource *res)
+{
+ res->refs++;
+ output->resources[output->num_res++] = res;
+}
+
+void QxlDevice::DrawableAddRes(QXLDrawable *drawable, Resource *res)
+{
+ QXLOutput *output;
+
+ output = (QXLOutput *)((UINT8 *)drawable - sizeof(QXLOutput));
+ AddRes(output, res);
+}
+
+void QxlDevice::CursorCmdAddRes(QXLCursorCmd *cmd, Resource *res)
+{
+ QXLOutput *output;
+
+ output = (QXLOutput *)((UINT8 *)cmd - sizeof(QXLOutput));
+ AddRes(output, res);
+}
+
+void QxlDevice::FreeClipRectsEx(Resource *res)
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--> %s\n", __FUNCTION__));
+ QxlDevice* pqxl = (QxlDevice*)res->ptr;
+ pqxl->FreeClipRects(res);
+}
+
+void QxlDevice::FreeClipRects(Resource *res)
+{
+ QXLPHYSICAL chunk_phys;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ chunk_phys = ((QXLClipRects *)res->res)->chunk.next_chunk;
+ while (chunk_phys) {
+ QXLDataChunk *chunk = (QXLDataChunk *)VA(chunk_phys, m_MainMemSlot);
+ chunk_phys = chunk->next_chunk;
+ FreeMem(MSPACE_TYPE_DEVRAM, chunk);
+ }
+ FreeMem(MSPACE_TYPE_DEVRAM, res);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+}
+
+void QxlDevice::FreeBitmapImageEx(Resource *res)
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--> %s\n", __FUNCTION__));
+ QxlDevice* pqxl = (QxlDevice*)res->ptr;
+ pqxl->FreeBitmapImage(res);
+}
+
+void QxlDevice::FreeBitmapImage(Resource *res)
+{
+ InternalImage *internal;
+ QXLPHYSICAL chunk_phys;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ internal = (InternalImage *)res->res;
+
+ chunk_phys = ((QXLDataChunk *)(&internal->image.bitmap + 1))->next_chunk;
+ while (chunk_phys) {
+ QXLDataChunk *chunk = (QXLDataChunk *)VA(chunk_phys, m_MainMemSlot);
+ chunk_phys = chunk->next_chunk;
+ FreeMem(MSPACE_TYPE_DEVRAM, chunk);
+ }
+
+ FreeMem(MSPACE_TYPE_DEVRAM, res);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+}
+
+void QxlDevice::FreeCursorEx(Resource *res)
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--> %s\n", __FUNCTION__));
+ QxlDevice* pqxl = (QxlDevice*)res->ptr;
+ pqxl->FreeCursor(res);
+}
+
+void QxlDevice::FreeCursor(Resource *res)
+{
+ QXLPHYSICAL chunk_phys;
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ chunk_phys = ((InternalCursor *)res->res)->cursor.chunk.next_chunk;
+ while (chunk_phys) {
+ QXLDataChunk *chunk = (QXLDataChunk *)VA(chunk_phys, m_MainMemSlot);
+ chunk_phys = chunk->next_chunk;
+ FreeMem(MSPACE_TYPE_DEVRAM, chunk);
+ }
+
+ FreeMem(MSPACE_TYPE_DEVRAM, res);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+}
+
+QXLDrawable *QxlDevice::Drawable(UINT8 type, CONST RECT *area, CONST RECT *clip, UINT32 surface_id)
+{
+ QXLDrawable *drawable;
+
+ ASSERT(area);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ drawable = GetDrawable();
+ drawable->surface_id = surface_id;
+ drawable->type = type;
+ drawable->effect = QXL_EFFECT_OPAQUE;
+ drawable->self_bitmap = 0;
+ drawable->mm_time = m_RomHdr->mm_clock;
+ drawable->surfaces_dest[0] = -1;
+ drawable->surfaces_dest[1] = - 1;
+ drawable->surfaces_dest[2] = -1;
+ CopyRect(&drawable->bbox, area);
+
+ if (!SetClip(clip, drawable)) {
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("%s: set clip failed\n", __FUNCTION__));
+ ReleaseOutput(drawable->release_info.id);
+ drawable = NULL;
+ }
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return drawable;
+}
+
+void QxlDevice::PushDrawable(QXLDrawable *drawable) {
+ QXLCommand *cmd;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ KeWaitForSingleObject
+ (
+ &m_CmdLock,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+ WaitForCmdRing();
+ cmd = SPICE_RING_PROD_ITEM(m_CommandRing);
+ cmd->type = QXL_CMD_DRAW;
+ cmd->data = PA(drawable, m_MainMemSlot);
+ PushCmd();
+ KeReleaseMutex(&m_CmdLock,FALSE);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+}
+
+void QxlDevice::PushCursorCmd(QXLCursorCmd *cursor_cmd)
+{
+ QXLCommand *cmd;
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ KeWaitForSingleObject
+ (
+ &m_CrsLock,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+ WaitForCursorRing();
+ cmd = SPICE_RING_PROD_ITEM(m_CursorRing);
+ cmd->type = QXL_CMD_CURSOR;
+ cmd->data = PA(cursor_cmd, m_MainMemSlot);
+ PushCursor();
+ KeReleaseMutex(&m_CrsLock,FALSE);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+}
+
+VOID QxlDevice::SetImageId(InternalImage *internal,
+ BOOL cache_me,
+ LONG width,
+ LONG height,
+ UINT8 format, UINT32 key)
+{
+ UINT32 image_info = IMAGE_HASH_INIT_VAL(width, height, format);
+
+ if (cache_me) {
+ QXL_SET_IMAGE_ID(&internal->image, ((UINT32)QXL_IMAGE_GROUP_DRIVER << 30) |
+ image_info, key);
+ internal->image.descriptor.flags = QXL_IMAGE_CACHE;
+ } else {
+ QXL_SET_IMAGE_ID(&internal->image, ((UINT32)QXL_IMAGE_GROUP_DRIVER_DONT_CACHE << 30) |
+ image_info, key);
+ internal->image.descriptor.flags = 0;
+ }
+}
+
+VOID QxlDevice::BltBits (
+ BLT_INFO* pDst,
+ CONST BLT_INFO* pSrc,
+ UINT NumRects,
+ _In_reads_(NumRects) CONST RECT *pRects)
+{
+ QXLDrawable *drawable;
+ Resource *image_res;
+ InternalImage *internal;
+ size_t alloc_size;
+ QXLDataChunk *chunk;
+ UINT32 line_size;
+ LONG width;
+ LONG height;
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ if (!(drawable = Drawable(QXL_DRAW_COPY, pRects, NULL, 0))) {
+ DbgPrint(TRACE_LEVEL_ERROR, ("Cannot get Drawable.\n"));
+ }
+
+ CONST RECT* pRect = &pRects[0];
+// UpdateArea(pRect, 0);
+ drawable->u.copy.scale_mode = SPICE_IMAGE_SCALE_MODE_NEAREST;
+ drawable->u.copy.mask.bitmap = 0;
+ drawable->u.copy.rop_descriptor = SPICE_ROPD_OP_PUT;
+
+ drawable->surfaces_dest[0] = 0;
+ CopyRect(&drawable->surfaces_rects[0], pRect);
+
+ drawable->self_bitmap = TRUE;
+ CopyRect(&drawable->self_bitmap_area, pRect);
+
+ height = pRect->bottom - pRect->top;
+ width = pRect->right - pRect->left;
+ line_size = width * 4;
+
+ drawable->u.copy.src_area.bottom = height;
+ drawable->u.copy.src_area.left = 0;
+ drawable->u.copy.src_area.top = 0;
+ drawable->u.copy.src_area.right = width;
+
+ alloc_size = BITMAP_ALLOC_BASE + BITS_BUF_MAX - BITS_BUF_MAX % line_size;
+ alloc_size = MIN(BITMAP_ALLOC_BASE + height * line_size, alloc_size);
+ image_res = (Resource*)AllocMem(MSPACE_TYPE_DEVRAM, alloc_size, TRUE);
+
+ image_res->refs = 1;
+ image_res->free = FreeBitmapImageEx;
+ image_res->ptr = this;
+
+ internal = (InternalImage *)image_res->res;
+ SetImageId(internal, FALSE, width, height, SPICE_BITMAP_FMT_32BIT, 0);
+ internal->image.descriptor.flags = 0;
+ internal->image.descriptor.type = SPICE_IMAGE_TYPE_BITMAP;
+ chunk = (QXLDataChunk *)(&internal->image.bitmap + 1);
+ chunk->data_size = 0;
+ chunk->prev_chunk = 0;
+ chunk->next_chunk = 0;
+ internal->image.bitmap.data = PA(chunk, m_MainMemSlot);
+ internal->image.bitmap.flags = 0;
+ internal->image.descriptor.width = internal->image.bitmap.x = width;
+ internal->image.descriptor.height = internal->image.bitmap.y = height;
+ internal->image.bitmap.format = SPICE_BITMAP_FMT_RGBA;
+ internal->image.bitmap.stride = line_size;
+
+ UINT8* src = (UINT8*)pSrc->pBits+
+ (pRect->top) * pSrc->Pitch +
+ (pRect->left * 4);
+ UINT8* src_end = src - pSrc->Pitch;
+ src += pSrc->Pitch * (height - 1);
+ UINT8* dest = chunk->data;
+ UINT8* dest_end = (UINT8 *)image_res + alloc_size;
+ alloc_size = height * line_size;
+
+ for (; src != src_end; src -= pSrc->Pitch, alloc_size -= line_size) {
+ PutBytesAlign(&chunk, &dest, &dest_end, src,
+ line_size, alloc_size, line_size);
+ }
+
+ internal->image.bitmap.palette = 0;
+
+ drawable->u.copy.src_bitmap = PA(&internal->image, m_MainMemSlot);
+
+ CopyRect(&drawable->surfaces_rects[1], pRect);
+ DrawableAddRes(drawable, image_res);
+ RELEASE_RES(image_res);
+
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("%s drawable= %p type = %d, effect = %d Dest right(%d) left(%d) top(%d) bottom(%d) src_bitmap= %p.\n", __FUNCTION__,
+ drawable, drawable->type, drawable->effect, drawable->surfaces_rects[0].right, drawable->surfaces_rects[0].left,
+ drawable->surfaces_rects[0].top, drawable->surfaces_rects[0].bottom,
+ drawable->u.copy.src_bitmap));
+
+ PushDrawable(drawable);
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+}
+
+VOID QxlDevice::PutBytesAlign(QXLDataChunk **chunk_ptr, UINT8 **now_ptr,
+ UINT8 **end_ptr, UINT8 *src, int size,
+ size_t alloc_size, uint32_t alignment)
+{
+ QXLDataChunk *chunk = *chunk_ptr;
+ UINT8 *now = *now_ptr;
+ UINT8 *end = *end_ptr;
+ int offset;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ while (size) {
+ int cp_size = (int)MIN(end - now, size);
+ if (!cp_size) {
+ size_t aligned_size;
+ aligned_size = (int)MIN(alloc_size + alignment - 1, BITS_BUF_MAX);
+ aligned_size -= aligned_size % alignment;
+
+ void *ptr = AllocMem(MSPACE_TYPE_DEVRAM, size + sizeof(QXLDataChunk), TRUE);
+ chunk->next_chunk = PA(ptr, m_MainMemSlot);
+ ((QXLDataChunk *)ptr)->prev_chunk = PA(chunk, m_MainMemSlot);
+ chunk = (QXLDataChunk *)ptr;
+ chunk->data_size = 0;
+ chunk->next_chunk = 0;
+ now = chunk->data;
+ end = now + size;
+
+ cp_size = (int)MIN(end - now, size);
+ }
+ RtlCopyMemory(now, src, cp_size);
+ src += cp_size;
+ now += cp_size;
+ chunk->data_size += cp_size;
+ size -= cp_size;
+ }
+ *chunk_ptr = chunk;
+ *now_ptr = now;
+ *end_ptr = end;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+}
+
+VOID QxlDevice::BlackOutScreen(CURRENT_BDD_MODE* pCurrentBddMod)
+{
+ QXLDrawable *drawable;
+ RECT Rect;
+ PAGED_CODE();
+return;
+ DbgPrint(TRACE_LEVEL_FATAL, ("---> %s\n", __FUNCTION__));
+ Rect.bottom = pCurrentBddMod->SrcModeHeight;
+ Rect.top = 0;
+ Rect.left = 0;
+ Rect.right = pCurrentBddMod->SrcModeWidth;
+ if (!(drawable = Drawable(QXL_DRAW_FILL, &Rect, NULL, 0))) {
+ DbgPrint(TRACE_LEVEL_ERROR, ("Cannot get Drawable.\n"));
+ }
+
+ drawable->u.fill.brush.type = SPICE_BRUSH_TYPE_SOLID;
+ drawable->u.fill.brush.u.color = 0;
+ drawable->u.fill.rop_descriptor = SPICE_ROPD_OP_PUT;
+ drawable->u.fill.mask.flags = 0;
+ drawable->u.fill.mask.pos.x = 0;
+ drawable->u.fill.mask.pos.y = 0;
+ drawable->u.fill.mask.bitmap = 0;
+ PushDrawable(drawable);
+
+ DbgPrint(TRACE_LEVEL_FATAL, ("<--- %s\n", __FUNCTION__));
+}
+
+NTSTATUS QxlDevice::HWClose(void)
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ QxlClose();
+ UnmapMemory();
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS QxlDevice::SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape)
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s flag = %x\n", __FUNCTION__, pSetPointerShape->Flags.Value));
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("<--> %s flag = %d pitch = %d, pixels = %p, id = %d, w = %d, h = %d, x = %d, y = %d\n", __FUNCTION__,
+ pSetPointerShape->Flags.Value,
+ pSetPointerShape->Pitch,
+ pSetPointerShape->pPixels,
+ pSetPointerShape->VidPnSourceId,
+ pSetPointerShape->Width,
+ pSetPointerShape->Height,
+ pSetPointerShape->XHot,
+ pSetPointerShape->YHot));
+ if (!EnablePointer() || (!pSetPointerShape->Flags.Monochrome && !pSetPointerShape->Flags.Color))
+ return STATUS_UNSUCCESSFUL;
+
+ QXLCursorCmd *cursor_cmd;
+ InternalCursor *internal;
+ QXLCursor *cursor;
+ Resource *res;
+ QXLDataChunk *chunk;
+ ULONG unique;
+ UINT8 *src;
+ UINT8 *src_end;
+ UINT8 *now;
+ UINT8 *end;
+ int line_size;
+
+ cursor_cmd = CursorCmd();
+ cursor_cmd->type = QXL_CURSOR_SET;
+
+ cursor_cmd->u.set.visible = TRUE;
+ cursor_cmd->u.set.position.x = 0;
+ cursor_cmd->u.set.position.y = 0;
+
+ res = (Resource *)AllocMem(MSPACE_TYPE_DEVRAM, CURSOR_ALLOC_SIZE, TRUE);
+ res->refs = 1;
+ res->free = FreeCursorEx;
+ res->ptr = this;
+ RESOURCE_TYPE(res, RESOURCE_TYPE_CURSOR);
+
+ internal = (InternalCursor *)res->res;
+
+ cursor = &internal->cursor;
+ cursor->header.type = pSetPointerShape->Flags.Monochrome ? SPICE_CURSOR_TYPE_MONO : SPICE_CURSOR_TYPE_ALPHA;
+ cursor->header.unique = 0;
+ cursor->header.width = (UINT16)pSetPointerShape->Width;
+ cursor->header.height = (UINT16)pSetPointerShape->Height;
+ if (cursor->header.type == SPICE_CURSOR_TYPE_MONO) {
+ cursor->header.height >>= 1;
+ line_size = ALIGN(cursor->header.width, 8) >> 3;
+ } else {
+ line_size = cursor->header.width << 2;
+ }
+
+ cursor->header.hot_spot_x = (UINT16)pSetPointerShape->XHot;
+ cursor->header.hot_spot_y = (UINT16)pSetPointerShape->YHot;
+
+ cursor->data_size = line_size * pSetPointerShape->Height;
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("<--> %s %d::%d::%d::%d::%d\n", __FUNCTION__, cursor->header.width, cursor->header.height, cursor->header.hot_spot_x, cursor->header.hot_spot_y, cursor->data_size));
+
+ chunk = &cursor->chunk;
+ chunk->data_size = 0;
+ chunk->prev_chunk = 0;
+ chunk->next_chunk = 0;
+
+ src = (UINT8*)pSetPointerShape->pPixels;
+ now = chunk->data;
+ end = (UINT8 *)res + CURSOR_ALLOC_SIZE;
+
+ src_end = src + (pSetPointerShape->Pitch * pSetPointerShape->Height);
+ for (; src != src_end; src += pSetPointerShape->Pitch) {
+ PutBytesAlign(&chunk, &now, &end, src, line_size,
+ PAGE_SIZE, 1);
+ }
+ CursorCmdAddRes(cursor_cmd, res);
+ RELEASE_RES(res);
+ cursor_cmd->u.set.shape = PA(&internal->cursor, m_MainMemSlot);
+ PushCursorCmd(cursor_cmd);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS QxlDevice::SetPointerPosition(_In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition)
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("<--> %s flag = %d id = %d, x = %d, y = %d\n", __FUNCTION__,
+ pSetPointerPosition->Flags.Value,
+ pSetPointerPosition->VidPnSourceId,
+ pSetPointerPosition->X,
+ pSetPointerPosition->Y));
+ if (EnablePointer()) {
+ QXLCursorCmd *cursor_cmd = CursorCmd();
+ if (pSetPointerPosition->X < 0) {
+ cursor_cmd->type = QXL_CURSOR_HIDE;
+ } else {
+ cursor_cmd->type = QXL_CURSOR_MOVE;
+ cursor_cmd->u.position.x = (INT16)pSetPointerPosition->X;
+ cursor_cmd->u.position.y = (INT16)pSetPointerPosition->Y;
+ }
+ PushCursorCmd(cursor_cmd);
+ }
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return STATUS_SUCCESS;
+}
+
+VOID QxlDevice::WaitForCmdRing()
+{
+ int wait;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ for (;;) {
+ SPICE_RING_PROD_WAIT(m_CommandRing, wait);
+
+ if (!wait) {
+ break;
+ }
+ WAIT_FOR_EVENT(m_DisplayEvent, NULL);
+ }
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+}
+
+VOID QxlDevice::PushCmd()
+{
+ int notify;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ SPICE_RING_PUSH(m_CommandRing, notify);
+ if (notify) {
+ SyncIo(QXL_IO_NOTIFY_CMD, 0);
+ }
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s notify = %d\n", __FUNCTION__, notify));
+}
+
+VOID QxlDevice::WaitForCursorRing(VOID)
+{
+ int wait;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ for (;;) {
+ SPICE_RING_PROD_WAIT(m_CursorRing, wait);
+
+ if (!wait) {
+ break;
+ }
+
+ LARGE_INTEGER timeout; // 1 => 100 nanoseconds
+ timeout.QuadPart = -1 * (1000 * 1000 * 10); //negative => relative // 1s
+ WAIT_FOR_EVENT(m_CursorEvent, &timeout);
+
+ if (SPICE_RING_IS_FULL(m_CursorRing)) {
+ DbgPrint(TRACE_LEVEL_ERROR, ("%s: timeout\n", __FUNCTION__));
+ }
+ }
+}
+
+VOID QxlDevice::PushCursor(VOID)
+{
+ int notify;
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ SPICE_RING_PUSH(m_CursorRing, notify);
+ if (notify) {
+ SyncIo(QXL_IO_NOTIFY_CURSOR, 0);
+ }
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s notify = %d\n", __FUNCTION__, notify));
+}
+
+BOOLEAN QxlDevice::InterruptRoutine(_In_ PDXGKRNL_INTERFACE pDxgkInterface, _In_ ULONG MessageNumber)
+{
+ UNREFERENCED_PARAMETER(MessageNumber);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ if (!(m_RamHdr->int_pending & m_RamHdr->int_mask)) {
+ return FALSE;
+ }
+ m_RamHdr->int_mask = 0;
+ WRITE_PORT_UCHAR((PUCHAR)(m_IoBase + QXL_IO_UPDATE_IRQ), 0);
+ m_Pending |= m_RamHdr->int_pending;
+ m_RamHdr->int_pending = 0;
+
+ DXGKARGCB_NOTIFY_INTERRUPT_DATA notifyInt;// = {0};
+ notifyInt.InterruptType = DXGK_INTERRUPT_DISPLAYONLY_PRESENT_PROGRESS;
+ notifyInt.DisplayOnlyPresentProgress.VidPnSourceId = 0;//FIXME pPath->VidPnSourceId;
+
+ pDxgkInterface->DxgkCbNotifyInterrupt(pDxgkInterface->DeviceHandle,&notifyInt);
+ if (!pDxgkInterface->DxgkCbQueueDpc(pDxgkInterface->DeviceHandle)) {
+ m_RamHdr->int_mask = QXL_INTERRUPT_MASK;
+ WRITE_PORT_UCHAR((PUCHAR)(m_IoBase + QXL_IO_UPDATE_IRQ), 0);
+ DbgPrint(TRACE_LEVEL_FATAL, ("---> %s DxgkCbQueueDpc failed\n", __FUNCTION__));
+ }
+ return TRUE;
+}
+
+VOID QxlDevice::DpcRoutine(PVOID ptr)
+{
+ PDXGKRNL_INTERFACE pDxgkInterface = (PDXGKRNL_INTERFACE)ptr;
+
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__));
+ DPC_CB_CONTEXT ctx;
+ BOOLEAN dummy;
+ ctx.ptr = this;
+ NTSTATUS Status = pDxgkInterface->DxgkCbSynchronizeExecution(
+ pDxgkInterface->DeviceHandle,
+ DpcCallbackEx,
+ &ctx,
+ 0,
+ &dummy);
+ ASSERT(Status == STATUS_SUCCESS);
+
+ if (ctx.data & QXL_INTERRUPT_DISPLAY) {
+ DbgPrint(TRACE_LEVEL_FATAL, ("---> %s m_DisplayEvent\n", __FUNCTION__));
+ KeSetEvent (&m_DisplayEvent, IO_NO_INCREMENT, FALSE);
+ }
+ if (ctx.data & QXL_INTERRUPT_CURSOR) {
+ DbgPrint(TRACE_LEVEL_FATAL, ("---> %s m_CursorEvent\n", __FUNCTION__));
+ KeSetEvent (&m_CursorEvent, IO_NO_INCREMENT, FALSE);
+ }
+ if (ctx.data & QXL_INTERRUPT_IO_CMD) {
+ DbgPrint(TRACE_LEVEL_FATAL, ("---> %s m_IoCmdEvent\n", __FUNCTION__));
+ KeSetEvent (&m_IoCmdEvent, IO_NO_INCREMENT, FALSE);
+ }
+ m_RamHdr->int_mask = QXL_INTERRUPT_MASK;
+ WRITE_PORT_UCHAR((PUCHAR)(m_IoBase + QXL_IO_UPDATE_IRQ), 0);
+
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__));
+}
+
+VOID QxlDevice::UpdateArea(CONST RECT* area, UINT32 surface_id)
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+ CopyRect(&m_RamHdr->update_area, area);
+ m_RamHdr->update_surface = surface_id;
+// AsyncIo(QXL_IO_UPDATE_AREA_ASYNC, 0);
+ SyncIo(QXL_IO_UPDATE_AREA, 0);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+}
+
+BOOLEAN QxlDevice:: DpcCallbackEx(PVOID ptr)
+{
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--> %s\n", __FUNCTION__));
+ PDPC_CB_CONTEXT ctx = (PDPC_CB_CONTEXT) ptr;
+ QxlDevice* pqxl = (QxlDevice*)ctx->ptr;
+ pqxl->DpcCallback(ctx);
+ return TRUE;
+}
+
+VOID QxlDevice::DpcCallback(PDPC_CB_CONTEXT ctx)
+{
+ ctx->data = m_Pending;
+ m_Pending = 0;
+
+}
+
+UINT BPPFromPixelFormat(D3DDDIFORMAT Format)
+{
+ switch (Format)
+ {
+ case D3DDDIFMT_UNKNOWN: return 0;
+ case D3DDDIFMT_P8: return 8;
+ case D3DDDIFMT_R5G6B5: return 16;
+ case D3DDDIFMT_R8G8B8: return 24;
+ case D3DDDIFMT_X8R8G8B8: // fall through
+ case D3DDDIFMT_A8R8G8B8: return 32;
+ default: QXL_LOG_ASSERTION1("Unknown D3DDDIFORMAT 0x%I64x", Format); return 0;
+ }
+}
+
+// Given bits per pixel, return the pixel format at the same bpp
+D3DDDIFORMAT PixelFormatFromBPP(UINT BPP)
+{
+ switch (BPP)
+ {
+ case 8: return D3DDDIFMT_P8;
+ case 16: return D3DDDIFMT_R5G6B5;
+ case 24: return D3DDDIFMT_R8G8B8;
+ case 32: return D3DDDIFMT_X8R8G8B8;
+ default: QXL_LOG_ASSERTION1("A bit per pixel of 0x%I64x is not supported.", BPP); return D3DDDIFMT_UNKNOWN;
+ }
+}
+
+UINT SpiceFromPixelFormat(D3DDDIFORMAT Format)
+{
+ switch (Format)
+ {
+ case D3DDDIFMT_UNKNOWN:
+ case D3DDDIFMT_P8: QXL_LOG_ASSERTION1("Bad format type 0x%I64x", Format); return 0;
+ case D3DDDIFMT_R5G6B5: return SPICE_SURFACE_FMT_16_555;
+ case D3DDDIFMT_R8G8B8:
+ case D3DDDIFMT_X8R8G8B8:
+ case D3DDDIFMT_A8R8G8B8: return SPICE_SURFACE_FMT_32_xRGB;
+ default: QXL_LOG_ASSERTION1("Unknown D3DDDIFORMAT 0x%I64x", Format); return 0;
+ }
+}
diff --git a/qxldod/QxlDod.h b/qxldod/QxlDod.h
new file mode 100755
index 0000000..ae0b4c0
--- /dev/null
+++ b/qxldod/QxlDod.h
@@ -0,0 +1,717 @@
+#pragma once
+#include "baseobject.h"
+#include "qxl_dev.h"
+#include "mspace.h"
+
+#define MAX_CHILDREN 1
+#define MAX_VIEWS 1
+#define BITS_PER_BYTE 8
+
+#define POINTER_SIZE 64
+
+typedef struct _QXL_FLAGS
+{
+ UINT DriverStarted : 1; // ( 1) 1 after StartDevice and 0 after StopDevice
+ UINT Unused : 31;
+} QXL_FLAGS;
+
+// For the following macros, c must be a UCHAR.
+#define UPPER_6_BITS(c) (((c) & rMaskTable[6 - 1]) >> 2)
+#define UPPER_5_BITS(c) (((c) & rMaskTable[5 - 1]) >> 3)
+#define LOWER_6_BITS(c) (((BYTE)(c)) & lMaskTable[BITS_PER_BYTE - 6])
+#define LOWER_5_BITS(c) (((BYTE)(c)) & lMaskTable[BITS_PER_BYTE - 5])
+
+
+#define SHIFT_FOR_UPPER_5_IN_565 (6 + 5)
+#define SHIFT_FOR_MIDDLE_6_IN_565 (5)
+#define SHIFT_UPPER_5_IN_565_BACK ((BITS_PER_BYTE * 2) + (BITS_PER_BYTE - 5))
+#define SHIFT_MIDDLE_6_IN_565_BACK ((BITS_PER_BYTE * 1) + (BITS_PER_BYTE - 6))
+#define SHIFT_LOWER_5_IN_565_BACK ((BITS_PER_BYTE * 0) + (BITS_PER_BYTE - 5))
+
+#pragma pack(push)
+#pragma pack(1)
+
+typedef struct
+{
+ CHAR Signature[4];
+ USHORT Version;
+ ULONG OemStringPtr;
+ LONG Capabilities;
+ ULONG VideoModePtr;
+ USHORT TotalMemory;
+ USHORT OemSoftwareRevision;
+ ULONG OemVendorNamePtr;
+ ULONG OemProductNamePtr;
+ ULONG OemProductRevPtr;
+ CHAR Reserved[222];
+// CHAR OemData[256];
+} VBE_INFO, *PVBE_INFO;
+
+typedef struct
+{
+/* Mandatory information for all VBE revisions */
+ USHORT ModeAttributes;
+ UCHAR WinAAttributes;
+ UCHAR WinBAttributes;
+ USHORT WinGranularity;
+ USHORT WinSize;
+ USHORT WinASegment;
+ USHORT WinBSegment;
+ ULONG WinFuncPtr;
+ USHORT BytesPerScanLine;
+/* Mandatory information for VBE 1.2 and above */
+ USHORT XResolution;
+ USHORT YResolution;
+ UCHAR XCharSize;
+ UCHAR YCharSize;
+ UCHAR NumberOfPlanes;
+ UCHAR BitsPerPixel;
+ UCHAR NumberOfBanks;
+ UCHAR MemoryModel;
+ UCHAR BankSize;
+ UCHAR NumberOfImagePages;
+ UCHAR Reserved1;
+/* Direct Color fields (required for Direct/6 and YUV/7 memory models) */
+ UCHAR RedMaskSize;
+ UCHAR RedFieldPosition;
+ UCHAR GreenMaskSize;
+ UCHAR GreenFieldPosition;
+ UCHAR BlueMaskSize;
+ UCHAR BlueFieldPosition;
+ UCHAR ReservedMaskSize;
+ UCHAR ReservedFieldPosition;
+ UCHAR DirectColorModeInfo;
+/* Mandatory information for VBE 2.0 and above */
+ ULONG PhysBasePtr;
+ ULONG Reserved2;
+ USHORT Reserved3;
+ /* Mandatory information for VBE 3.0 and above */
+ USHORT LinBytesPerScanLine;
+ UCHAR BnkNumberOfImagePages;
+ UCHAR LinNumberOfImagePages;
+ UCHAR LinRedMaskSize;
+ UCHAR LinRedFieldPosition;
+ UCHAR LinGreenMaskSize;
+ UCHAR LinGreenFieldPosition;
+ UCHAR LinBlueMaskSize;
+ UCHAR LinBlueFieldPosition;
+ UCHAR LinReservedMaskSize;
+ UCHAR LinReservedFieldPosition;
+ ULONG MaxPixelClock;
+ CHAR Reserved4[189];
+} VBE_MODEINFO, *PVBE_MODEINFO;
+
+#pragma pack(pop)
+
+typedef struct _X86BIOS_REGISTERS // invented names
+{
+ ULONG Eax;
+ ULONG Ecx;
+ ULONG Edx;
+ ULONG Ebx;
+ ULONG Ebp;
+ ULONG Esi;
+ ULONG Edi;
+ USHORT SegDs;
+ USHORT SegEs;
+} X86BIOS_REGISTERS, *PX86BIOS_REGISTERS;
+
+/* Undocumented imports from the HAL */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+NTHALAPI BOOLEAN x86BiosCall (ULONG, PX86BIOS_REGISTERS);
+
+NTHALAPI NTSTATUS x86BiosAllocateBuffer (ULONG *, USHORT *, USHORT *);
+NTHALAPI NTSTATUS x86BiosFreeBuffer (USHORT, USHORT);
+
+NTHALAPI NTSTATUS x86BiosReadMemory (USHORT, USHORT, PVOID, ULONG);
+NTHALAPI NTSTATUS x86BiosWriteMemory (USHORT, USHORT, PVOID, ULONG);
+
+#ifdef __cplusplus
+}
+#endif
+
+struct DoPresentMemory
+{
+ PVOID DstAddr;
+ UINT DstStride;
+ ULONG DstBitPerPixel;
+ UINT SrcWidth;
+ UINT SrcHeight;
+ BYTE* SrcAddr;
+ LONG SrcPitch;
+ ULONG NumMoves; // in: Number of screen to screen moves
+ D3DKMT_MOVE_RECT* Moves; // in: Point to the list of moves
+ ULONG NumDirtyRects; // in: Number of direct rects
+ RECT* DirtyRect; // in: Point to the list of dirty rects
+ D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation;
+ D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceID;
+ HANDLE hAdapter;
+ PMDL Mdl;
+ PVOID DisplaySource;
+};
+
+typedef struct _BLT_INFO
+{
+ PVOID pBits;
+ UINT Pitch;
+ UINT BitsPerPel;
+ POINT Offset; // To unrotated top-left of dirty rects
+ D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation;
+ UINT Width; // For the unrotated image
+ UINT Height; // For the unrotated image
+} BLT_INFO;
+
+// Represents the current mode, may not always be set (i.e. frame buffer mapped) if representing the mode passed in on single mode setups.
+typedef struct _CURRENT_BDD_MODE
+{
+ // The source mode currently set for HW Framebuffer
+ // For sample driver this info filled in StartDevice by the OS and never changed.
+ DXGK_DISPLAY_INFORMATION DispInfo;
+
+ // The rotation of the current mode. Rotation is performed in software during Present call
+ D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation;
+
+ D3DKMDT_VIDPN_PRESENT_PATH_SCALING Scaling;
+ // This mode might be different from one which are supported for HW frame buffer
+ // Scaling/displasment might be needed (if supported)
+ UINT SrcModeWidth;
+ UINT SrcModeHeight;
+
+ // Various boolean flags the struct uses
+ struct _CURRENT_BDD_MODE_FLAGS
+ {
+ UINT SourceNotVisible : 1; // 0 if source is visible
+ UINT FullscreenPresent : 1; // 0 if should use dirty rects for present
+ UINT FrameBufferIsActive : 1; // 0 if not currently active (i.e. target not connected to source)
+ UINT DoNotMapOrUnmap : 1; // 1 if the FrameBuffer should not be (un)mapped during normal execution
+ UINT IsInternal : 1; // 1 if it was determined (i.e. through ACPI) that an internal panel is being driven
+ UINT Unused : 27;
+ } Flags;
+
+ // The start and end of physical memory known to be all zeroes. Used to optimize the BlackOutScreen function to not write
+ // zeroes to memory already known to be zero. (Physical address is located in DispInfo)
+ PHYSICAL_ADDRESS ZeroedOutStart;
+ PHYSICAL_ADDRESS ZeroedOutEnd;
+
+ // Linear frame buffer pointer
+ // A union with a ULONG64 is used here to ensure this struct looks the same on 32bit and 64bit builds
+ // since the size of a VOID* changes depending on the build.
+ union
+ {
+ VOID* Ptr;
+ ULONG64 Force8Bytes;
+ } FrameBuffer;
+} CURRENT_BDD_MODE;
+
+class QxlDod;
+
+class HwDeviceIntrface {
+public:
+ virtual NTSTATUS QueryCurrentMode(PVIDEO_MODE RequestedMode) = 0;
+ virtual NTSTATUS SetCurrentMode(ULONG Mode) = 0;
+ virtual NTSTATUS GetCurrentMode(ULONG* Mode) = 0;
+ virtual NTSTATUS SetPowerState(DEVICE_POWER_STATE DevicePowerState, DXGK_DISPLAY_INFORMATION* pDispInfo) = 0;
+ virtual NTSTATUS HWInit(PCM_RESOURCE_LIST pResList, DXGK_DISPLAY_INFORMATION* pDispInfo) = 0;
+ virtual NTSTATUS HWClose(void) = 0;
+ virtual BOOLEAN InterruptRoutine(_In_ PDXGKRNL_INTERFACE pDxgkInterface, _In_ ULONG MessageNumber) = 0;
+ virtual VOID DpcRoutine(PVOID) = 0;
+ virtual VOID ResetDevice(void) = 0;
+
+ ULONG GetModeCount(void) {return m_ModeCount;}
+ PVIDEO_MODE_INFORMATION GetModeInfo(UINT idx) {return &m_ModeInfo[idx];}
+ USHORT GetModeNumber(USHORT idx) {return m_ModeNumbers[idx];}
+ USHORT GetCurrentModeIndex(void) {return m_CurrentMode;}
+ VOID SetCurrentModeIndex(USHORT idx) {m_CurrentMode = idx;}
+ virtual BOOLEAN EnablePointer(void) = 0;
+ virtual NTSTATUS ExecutePresentDisplayOnly(_In_ BYTE* DstAddr,
+ _In_ UINT DstBitPerPixel,
+ _In_ BYTE* SrcAddr,
+ _In_ UINT SrcBytesPerPixel,
+ _In_ LONG SrcPitch,
+ _In_ ULONG NumMoves,
+ _In_ D3DKMT_MOVE_RECT* pMoves,
+ _In_ ULONG NumDirtyRects,
+ _In_ RECT* pDirtyRect,
+ _In_ D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation,
+ _In_ const CURRENT_BDD_MODE* pModeCur) = 0;
+
+ virtual VOID BlackOutScreen(CURRENT_BDD_MODE* pCurrentBddMod) = 0;
+ virtual NTSTATUS SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape) = 0;
+ virtual NTSTATUS SetPointerPosition(_In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition) = 0;
+protected:
+ virtual NTSTATUS GetModeList(DXGK_DISPLAY_INFORMATION* pDispInfo) = 0;
+protected:
+ QxlDod* m_pQxlDod;
+ PVIDEO_MODE_INFORMATION m_ModeInfo;
+ ULONG m_ModeCount;
+ PUSHORT m_ModeNumbers;
+ USHORT m_CurrentMode;
+};
+
+class VgaDevice :
+ public HwDeviceIntrface
+{
+public:
+ VgaDevice(_In_ QxlDod* pQxlDod);
+ virtual ~VgaDevice(void);
+ NTSTATUS QueryCurrentMode(PVIDEO_MODE RequestedMode);
+ NTSTATUS SetCurrentMode(ULONG Mode);
+ NTSTATUS GetCurrentMode(ULONG* Mode);
+ NTSTATUS SetPowerState(DEVICE_POWER_STATE DevicePowerState, DXGK_DISPLAY_INFORMATION* pDispInfo);
+ NTSTATUS HWInit(PCM_RESOURCE_LIST pResList, DXGK_DISPLAY_INFORMATION* pDispInfo);
+ NTSTATUS HWClose(void);
+ BOOLEAN EnablePointer(void) { return FALSE; }
+ NTSTATUS ExecutePresentDisplayOnly(_In_ BYTE* DstAddr,
+ _In_ UINT DstBitPerPixel,
+ _In_ BYTE* SrcAddr,
+ _In_ UINT SrcBytesPerPixel,
+ _In_ LONG SrcPitch,
+ _In_ ULONG NumMoves,
+ _In_ D3DKMT_MOVE_RECT* pMoves,
+ _In_ ULONG NumDirtyRects,
+ _In_ RECT* pDirtyRect,
+ _In_ D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation,
+ _In_ const CURRENT_BDD_MODE* pModeCur);
+ VOID BlackOutScreen(CURRENT_BDD_MODE* pCurrentBddMod);
+ BOOLEAN InterruptRoutine(_In_ PDXGKRNL_INTERFACE pDxgkInterface, _In_ ULONG MessageNumber);
+ VOID DpcRoutine(PVOID);
+ VOID ResetDevice(VOID);
+ NTSTATUS SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape);
+ NTSTATUS SetPointerPosition(_In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition);
+protected:
+ NTSTATUS GetModeList(DXGK_DISPLAY_INFORMATION* pDispInfo);
+private:
+ BOOL SetVideoModeInfo(UINT Idx, PVBE_MODEINFO pModeInfo);
+};
+
+typedef struct _MemSlot {
+ UINT8 generation;
+ UINT64 start_phys_addr;
+ UINT64 end_phys_addr;
+ UINT64 start_virt_addr;
+ UINT64 end_virt_addr;
+ QXLPHYSICAL high_bits;
+} MemSlot;
+
+typedef struct MspaceInfo {
+ mspace _mspace;
+ UINT8 *mspace_start;
+ UINT8 *mspace_end;
+} MspaceInfo;
+
+enum {
+ MSPACE_TYPE_DEVRAM,
+ MSPACE_TYPE_VRAM,
+ NUM_MSPACES,
+};
+
+#define RELEASE_RES(res) if (!--(res)->refs) (res)->free(res);
+#define GET_RES(res) (++(res)->refs)
+
+/* Debug helpers - tag each resource with this enum */
+enum {
+ RESOURCE_TYPE_DRAWABLE = 1,
+ RESOURCE_TYPE_SURFACE,
+ RESOURCE_TYPE_PATH,
+ RESOURCE_TYPE_CLIP_RECTS,
+ RESOURCE_TYPE_QUIC_IMAGE,
+ RESOURCE_TYPE_BITMAP_IMAGE,
+ RESOURCE_TYPE_SURFACE_IMAGE,
+ RESOURCE_TYPE_SRING,
+ RESOURCE_TYPE_CURSOR,
+ RESOURCE_TYPE_BUF,
+ RESOURCE_TYPE_UPDATE,
+};
+
+#ifdef DBG
+#define RESOURCE_TYPE(res, val) do { res->type = val; } while (0)
+#else
+#define RESOURCE_TYPE(res, val)
+#endif
+
+typedef struct Resource Resource;
+struct Resource {
+ UINT32 refs;
+ void* ptr;
+#ifdef DBG
+ UINT32 type;
+#endif
+ void (*free)(Resource *res);
+ UINT8 res[0];
+};
+
+#define TIMEOUT_TO_MS ((LONGLONG) 1 * 10 * 1000)
+
+#define WAIT_FOR_EVENT(event, timeout) do { \
+ NTSTATUS status; \
+ status = KeWaitForSingleObject ( \
+ &event, \
+ Executive, \
+ KernelMode, \
+ FALSE, \
+ timeout); \
+ ASSERT(NT_SUCCESS(status)); \
+} while (0);
+
+#define QXL_SLEEP(msec) do { \
+ LARGE_INTEGER timeout; \
+ timeout.QuadPart = -msec * TIMEOUT_TO_MS; \
+ KeDelayExecutionThread (KernelMode, FALSE, &timeout);\
+} while (0);
+
+#define IMAGE_HASH_INIT_VAL(width, height, format) \
+ ((UINT32)((width) & 0x1FFF) | ((UINT32)((height) & 0x1FFF) << 13) |\
+ ((UINT32)(format) << 26))
+
+#define MAX_OUTPUT_RES 6
+
+typedef struct QXLOutput {
+ UINT32 num_res;
+#ifdef DBG
+ UINT32 type;
+#endif
+ Resource *resources[MAX_OUTPUT_RES];
+ UINT8 data[0];
+} QXLOutput;
+
+typedef struct Ring RingItem;
+typedef struct Ring {
+ RingItem *prev;
+ RingItem *next;
+} Ring;
+
+typedef struct InternalImage {
+ QXLImage image;
+} InternalImage;
+
+typedef struct InternalCursor {
+ QXLCursor cursor;
+} InternalCursor;
+
+#define CURSOR_ALLOC_SIZE (PAGE_SIZE << 1)
+
+typedef struct DpcCbContext {
+ void* ptr;
+ UINT32 data;
+} DPC_CB_CONTEXT,* PDPC_CB_CONTEXT;
+
+#define BITMAP_ALLOC_BASE (sizeof(Resource) + sizeof(InternalImage) + sizeof(QXLDataChunk))
+#define BITS_BUF_MAX (64 * 1024)
+#define MIN(x, y) (((x) <= (y)) ? (x) : (y))
+#define MAX(x, y) (((x) >= (y)) ? (x) : (y))
+#define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1))
+
+class QxlDevice :
+ public HwDeviceIntrface
+{
+public:
+ QxlDevice(_In_ QxlDod* pQxlDod);
+ virtual ~QxlDevice(void);
+ NTSTATUS QueryCurrentMode(PVIDEO_MODE RequestedMode);
+ NTSTATUS SetCurrentMode(ULONG Mode);
+ NTSTATUS GetCurrentMode(ULONG* Mode);
+ NTSTATUS SetPowerState(DEVICE_POWER_STATE DevicePowerState, DXGK_DISPLAY_INFORMATION* pDispInfo);
+ NTSTATUS HWInit(PCM_RESOURCE_LIST pResList, DXGK_DISPLAY_INFORMATION* pDispInfo);
+ NTSTATUS HWClose(void);
+ BOOLEAN EnablePointer(void) { return FALSE; }
+ NTSTATUS ExecutePresentDisplayOnly(_In_ BYTE* DstAddr,
+ _In_ UINT DstBitPerPixel,
+ _In_ BYTE* SrcAddr,
+ _In_ UINT SrcBytesPerPixel,
+ _In_ LONG SrcPitch,
+ _In_ ULONG NumMoves,
+ _In_ D3DKMT_MOVE_RECT* pMoves,
+ _In_ ULONG NumDirtyRects,
+ _In_ RECT* pDirtyRect,
+ _In_ D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation,
+ _In_ const CURRENT_BDD_MODE* pModeCur);
+ VOID BlackOutScreen(CURRENT_BDD_MODE* pCurrentBddMod);
+ BOOLEAN InterruptRoutine(_In_ PDXGKRNL_INTERFACE pDxgkInterface, _In_ ULONG MessageNumber);
+ VOID DpcRoutine(PVOID);
+ VOID ResetDevice(VOID);
+ NTSTATUS SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape);
+ NTSTATUS SetPointerPosition(_In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition);
+protected:
+ NTSTATUS GetModeList(DXGK_DISPLAY_INFORMATION* pDispInfo);
+ VOID BltBits (BLT_INFO* pDst,
+ CONST BLT_INFO* pSrc,
+ UINT NumRects,
+ _In_reads_(NumRects) CONST RECT *pRects);
+ QXLDrawable *Drawable(UINT8 type,
+ CONST RECT *area,
+ CONST RECT *clip,
+ UINT32 surface_id);
+ void PushDrawable(QXLDrawable *drawable);
+ void PushCursorCmd(QXLCursorCmd *cursor_cmd);
+ QXLDrawable *GetDrawable();
+ QXLCursorCmd *CursorCmd();
+ void *AllocMem(UINT32 mspace_type, size_t size, BOOL force);
+ VOID UpdateArea(CONST RECT* area, UINT32 surface_id);
+ VOID SetImageId(InternalImage *internal,
+ BOOL cache_me,
+ LONG width,
+ LONG height,
+ UINT8 format, UINT32 key);
+private:
+ NTSTATUS QxlInit(DXGK_DISPLAY_INFORMATION* pDispInfo);
+ void QxlClose(void);
+ void UnmapMemory(void);
+ BOOL SetVideoModeInfo(UINT Idx, QXLMode* pModeInfo);
+ BOOL InitMemSlots(void);
+ BOOL CreateMemSlots(void);
+ void DestroyMemSlots(void);
+ void CreatePrimarySurface(PVIDEO_MODE_INFORMATION pModeInfo);
+ void DestroyPrimarySurface(void);
+ void SetupHWSlot(UINT8 Idx, MemSlot *pSlot);
+ UINT8 SetupMemSlot(UINT8 Idx, UINT64 pastart, UINT64 paend, UINT64 vastart, UINT64 vaend);
+ BOOL CreateEvents(void);
+ BOOL CreateRings(void);
+ UINT64 VA(QXLPHYSICAL paddr, UINT8 slot_id);
+ QXLPHYSICAL PA(PVOID virt, UINT8 slot_id);
+ void InitDeviceMemoryResources(void);
+ void InitMspace(UINT32 mspace_type, UINT8 *start, size_t capacity);
+ void FlushReleaseRing();
+ void FreeMem(UINT32 mspace_type, void *ptr);
+ UINT64 ReleaseOutput(UINT64 output_id);
+ void WaitForReleaseRing(void);
+ void EmptyReleaseRing(void);
+ BOOL SetClip(const RECT *clip, QXLDrawable *drawable);
+ void AddRes(QXLOutput *output, Resource *res);
+ void DrawableAddRes(QXLDrawable *drawable, Resource *res);
+ void CursorCmdAddRes(QXLCursorCmd *cmd, Resource *res);
+ void FreeClipRects(Resource *res);
+ void static FreeClipRectsEx(Resource *res);
+ void FreeBitmapImage(Resource *res);
+ void static FreeBitmapImageEx(Resource *res);
+ void static FreeCursorEx(Resource *res);
+ void FreeCursor(Resource *res);
+ void WaitForCmdRing(void);
+ void PushCmd(void);
+ void WaitForCursorRing(void);
+ void PushCursor(void);
+ void PutBytesAlign(QXLDataChunk **chunk_ptr, UINT8 **now_ptr,
+ UINT8 **end_ptr, UINT8 *src, int size,
+ size_t alloc_size, uint32_t alignment);
+ BOOLEAN static DpcCallbackEx(PVOID);
+ void DpcCallback(PDPC_CB_CONTEXT);
+ void AsyncIo(UCHAR Port, UCHAR Value);
+ void SyncIo(UCHAR Port, UCHAR Value);
+private:
+ PUCHAR m_IoBase;
+ BOOLEAN m_IoMapped;
+ ULONG m_IoSize;
+
+ PHYSICAL_ADDRESS m_RamPA;
+ UINT8 *m_RamStart;
+ QXLRam *m_RamHdr;
+ ULONG m_RamSize;
+
+ PHYSICAL_ADDRESS m_VRamPA;
+ UINT8 *m_VRamStart;
+ ULONG m_VRamSize;
+
+ QXLRom *m_RomHdr;
+ ULONG m_RomSize;
+
+ MemSlot *m_MemSlots;
+ UINT8 m_NumMemSlots;
+ UINT8 m_MainMemSlot;
+ UINT8 m_SurfaceMemSlot;
+ UINT8 m_SlotIdBits;
+ UINT8 m_SlotGenBits;
+ QXLPHYSICAL m_VaSlotMask;
+
+ QXLCommandRing *m_CommandRing;
+ QXLCursorRing *m_CursorRing;
+ QXLReleaseRing *m_ReleaseRing;
+
+ KEVENT m_DisplayEvent;
+ KEVENT m_CursorEvent;
+ KEVENT m_IoCmdEvent;
+
+ PUCHAR m_LogPort;
+ PUCHAR m_LogBuf;
+
+ KMUTEX m_MemLock;
+ KMUTEX m_CmdLock;
+ KMUTEX m_IoLock;
+ KMUTEX m_CrsLock;
+ MspaceInfo m_MSInfo[NUM_MSPACES];
+
+ UINT64 m_FreeOutputs;
+ UINT32 m_Pending;
+};
+
+class QxlDod {
+private:
+ DEVICE_OBJECT* m_pPhysicalDevice;
+ DXGKRNL_INTERFACE m_DxgkInterface;
+ DXGK_DEVICE_INFO m_DeviceInfo;
+
+ DEVICE_POWER_STATE m_MonitorPowerState;
+ DEVICE_POWER_STATE m_AdapterPowerState;
+ QXL_FLAGS m_Flags;
+
+ CURRENT_BDD_MODE m_CurrentModes[MAX_VIEWS];
+
+ D3DDDI_VIDEO_PRESENT_SOURCE_ID m_SystemDisplaySourceId;
+ DXGKARG_SETPOINTERSHAPE m_PointerShape;
+ HwDeviceIntrface* m_pHWDevice;
+public:
+ QxlDod(_In_ DEVICE_OBJECT* pPhysicalDeviceObject);
+ ~QxlDod(void);
+#pragma code_seg(push)
+#pragma code_seg()
+ BOOLEAN IsDriverActive() const
+ {
+ return m_Flags.DriverStarted;
+ }
+#pragma code_seg(pop)
+
+ NTSTATUS StartDevice(_In_ DXGK_START_INFO* pDxgkStartInfo,
+ _In_ DXGKRNL_INTERFACE* pDxgkInterface,
+ _Out_ ULONG* pNumberOfViews,
+ _Out_ ULONG* pNumberOfChildren);
+ NTSTATUS StopDevice(VOID);
+ // Must be Non-Paged
+ VOID ResetDevice(VOID);
+
+ NTSTATUS DispatchIoRequest(_In_ ULONG VidPnSourceId,
+ _In_ VIDEO_REQUEST_PACKET* pVideoRequestPacket);
+ NTSTATUS SetPowerState(_In_ ULONG HardwareUid,
+ _In_ DEVICE_POWER_STATE DevicePowerState,
+ _In_ POWER_ACTION ActionType);
+ // Report back child capabilities
+ NTSTATUS QueryChildRelations(_Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations,
+ _In_ ULONG ChildRelationsSize);
+
+ NTSTATUS QueryChildStatus(_Inout_ DXGK_CHILD_STATUS* pChildStatus,
+ _In_ BOOLEAN NonDestructiveOnly);
+
+ // Return EDID if previously retrieved
+ NTSTATUS QueryDeviceDescriptor(_In_ ULONG ChildUid,
+ _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor);
+
+ // Must be Non-Paged
+ // BDD doesn't have interrupts, so just returns false
+ BOOLEAN InterruptRoutine(_In_ ULONG MessageNumber);
+
+ VOID DpcRoutine(VOID);
+
+ // Return DriverCaps, doesn't support other queries though
+ NTSTATUS QueryAdapterInfo(_In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo);
+
+ NTSTATUS SetPointerPosition(_In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition);
+
+ NTSTATUS SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape);
+
+ NTSTATUS Escape(_In_ CONST DXGKARG_ESCAPE* pEscape);
+
+ NTSTATUS PresentDisplayOnly(_In_ CONST DXGKARG_PRESENT_DISPLAYONLY* pPresentDisplayOnly);
+
+ NTSTATUS QueryInterface(_In_ CONST PQUERY_INTERFACE QueryInterface);
+
+ NTSTATUS IsSupportedVidPn(_Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn);
+
+ NTSTATUS RecommendFunctionalVidPn(_In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn);
+
+ NTSTATUS RecommendVidPnTopology(_In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology);
+
+ NTSTATUS RecommendMonitorModes(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes);
+
+ NTSTATUS EnumVidPnCofuncModality(_In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality);
+
+ NTSTATUS SetVidPnSourceVisibility(_In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility);
+
+ NTSTATUS CommitVidPn(_In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn);
+
+ NTSTATUS UpdateActiveVidPnPresentPath(_In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath);
+
+ NTSTATUS QueryVidPnHWCapability(_Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps);
+
+ // Part of PnPStop (PnP instance only), returns current mode information (which will be passed to fallback instance by dxgkrnl)
+ NTSTATUS StopDeviceAndReleasePostDisplayOwnership(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
+ _Out_ DXGK_DISPLAY_INFORMATION* pDisplayInfo);
+
+ // Must be Non-Paged
+ // Call to initialize as part of bugcheck
+ NTSTATUS SystemDisplayEnable(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
+ _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags,
+ _Out_ UINT* pWidth,
+ _Out_ UINT* pHeight,
+ _Out_ D3DDDIFORMAT* pColorFormat);
+
+ // Must be Non-Paged
+ // Write out pixels as part of bugcheck
+ VOID SystemDisplayWrite(_In_reads_bytes_(SourceHeight * SourceStride) VOID* pSource,
+ _In_ UINT SourceWidth,
+ _In_ UINT SourceHeight,
+ _In_ UINT SourceStride,
+ _In_ INT PositionX,
+ _In_ INT PositionY);
+ PDXGKRNL_INTERFACE GetDxgkInterrface(void) { return &m_DxgkInterface;}
+private:
+ VOID CleanUp(VOID);
+ NTSTATUS CheckHardware();
+ NTSTATUS WriteHWInfoStr(_In_ HANDLE DevInstRegKeyHandle, _In_ PCWSTR pszwValueName, _In_ PCSTR pszValue);
+ // Set the given source mode on the given path
+ NTSTATUS SetSourceModeAndPath(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode,
+ CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath);
+
+ // Add the current mode to the given monitor source mode set
+ NTSTATUS AddSingleMonitorMode(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes);
+
+ // Add the current mode to the given VidPn source mode set
+ NTSTATUS AddSingleSourceMode(_In_ CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface,
+ D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet,
+ D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId);
+
+ // Add the current mode (or the matching to pinned source mode) to the give VidPn target mode set
+ NTSTATUS AddSingleTargetMode(_In_ CONST DXGK_VIDPNTARGETMODESET_INTERFACE* pVidPnTargetModeSetInterface,
+ D3DKMDT_HVIDPNTARGETMODESET hVidPnTargetModeSet,
+ _In_opt_ CONST D3DKMDT_VIDPN_SOURCE_MODE* pVidPnPinnedSourceModeInfo,
+ D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId);
+ D3DDDI_VIDEO_PRESENT_SOURCE_ID FindSourceForTarget(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, BOOLEAN DefaultToZero);
+ NTSTATUS IsVidPnSourceModeFieldsValid(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode) const;
+ NTSTATUS IsVidPnPathFieldsValid(CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath) const;
+ NTSTATUS RegisterHWInfo();
+};
+
+NTSTATUS
+MapFrameBuffer(
+ _In_ PHYSICAL_ADDRESS PhysicalAddress,
+ _In_ ULONG Length,
+ _Outptr_result_bytebuffer_(Length) VOID** VirtualAddress);
+
+NTSTATUS
+UnmapFrameBuffer(
+ _In_reads_bytes_(Length) VOID* VirtualAddress,
+ _In_ ULONG Length);
+
+UINT BPPFromPixelFormat(D3DDDIFORMAT Format);
+D3DDDIFORMAT PixelFormatFromBPP(UINT BPP);
+UINT SpiceFromPixelFormat(D3DDDIFORMAT Format);
+
+VOID CopyBitsGeneric(
+ BLT_INFO* pDst,
+ CONST BLT_INFO* pSrc,
+ UINT NumRects,
+ _In_reads_(NumRects) CONST RECT *pRects);
+
+VOID CopyBits32_32(
+ BLT_INFO* pDst,
+ CONST BLT_INFO* pSrc,
+ UINT NumRects,
+ _In_reads_(NumRects) CONST RECT *pRects);
+VOID BltBits (
+ BLT_INFO* pDst,
+ CONST BLT_INFO* pSrc,
+ UINT NumRects,
+ _In_reads_(NumRects) CONST RECT *pRects);
+
+BYTE* GetRowStart(_In_ CONST BLT_INFO* pBltInfo, CONST RECT* pRect);
+VOID GetPitches(_In_ CONST BLT_INFO* pBltInfo, _Out_ LONG* pPixelPitch, _Out_ LONG* pRowPitch);
diff --git a/qxldod/buildAll.bat b/qxldod/buildAll.bat
new file mode 100755
index 0000000..072a2b4
--- /dev/null
+++ b/qxldod/buildAll.bat
@@ -0,0 +1,31 @@
+@echo off
+
+call clean.bat
+
+rem WIN8_64
+setlocal
+if exist Install\win8\amd64 rmdir Install\win8\amd64 /s /q
+call callVisualStudio.bat 12 qxldod.vcxproj /Rebuild "Win8 Release|x64" /Out buildfre_win8_amd64.log
+mkdir .\Install\Win8\x64
+del /Q .\Install\Win8\x64\*
+copy /Y objfre_win8_amd64\amd64\qxldod.sys .\Install\Win8\x64
+copy /Y objfre_win8_amd64\amd64\qxldod.inf .\Install\Win8\x64
+copy /Y objfre_win8_amd64\amd64\qxldod.cat .\Install\Win8\x64
+copy /Y objfre_win8_amd64\amd64\qxldod.pdb .\Install\Win8\x64
+endlocal
+if %ERRORLEVEL% NEQ 0 goto :eof
+
+rem WIN8_32
+setlocal
+if exist Install\win8\x86 rmdir Install\win8\x86 /s /q
+call callVisualStudio.bat 12 qxldod.vcxproj /Rebuild "Win8 Release|Win32" /Out buildfre_win8_x86.log
+mkdir .\Install\Win8\x86
+del /Q .\Install\Win8\x86\*
+copy /Y objfre_win8_x86\i386\qxldod.sys .\Install\Win8\x86
+copy /Y objfre_win8_x86\i386\qxldod.inf .\Install\Win8\x86
+copy /Y objfre_win8_x86\i386\qxldod.cat .\Install\Win8\x86
+copy /Y objfre_win8_x86\i386\qxldod.pdb .\Install\Win8\x86
+endlocal
+if %ERRORLEVEL% NEQ 0 goto :eof
+
+:eof
diff --git a/qxldod/callVisualStudio.bat b/qxldod/callVisualStudio.bat
new file mode 100755
index 0000000..5f1976e
--- /dev/null
+++ b/qxldod/callVisualStudio.bat
@@ -0,0 +1,28 @@
+@echo off
+
+call %~dp0\checkWin8Tools.bat
+
+for /f "tokens=*" %%a in (
+'cscript.exe /nologo "%~dp0\getVisualStudioCmdLine.vbs" %*'
+) do (
+set vs_cmd=%%a
+)
+
+IF NOT DEFINED vs_cmd (
+echo Visual Studio not found
+EXIT /b 1
+)
+
+SET vs_cmd_no_quotes="%vs_cmd:"=%"
+IF "vs_cmd_no_quotes" == "" (
+echo Visual Studio not found
+EXIT /b 2
+)
+
+call %vs_cmd%
+if %ERRORLEVEL% GEQ 1 (
+echo Build with Visual Studio FAILED
+exit /b %ERRORLEVEL%
+)
+
+exit /b 0
diff --git a/qxldod/checkWin8Tools.bat b/qxldod/checkWin8Tools.bat
new file mode 100755
index 0000000..c8008db
--- /dev/null
+++ b/qxldod/checkWin8Tools.bat
@@ -0,0 +1,16 @@
+@echo off
+
+reg query "HKLM\Software\Microsoft\Windows Kits\WDK" /v WDKProductVersion >nul 2>nul
+if %ERRORLEVEL% EQU 0 goto checkVS12
+reg query "HKLM\Software\Wow6432Node\Microsoft\Windows Kits\WDK" /v WDKProductVersion > nul 2>nul
+if %ERRORLEVEL% EQU 0 goto checkVS12
+echo ERROR building Win8 drivers: Win8 WDK is not installed
+exit /b 1
+
+:checkVS12
+reg query HKLM\Software\Microsoft\VisualStudio\12.0 /v InstallDir > nul 2>nul
+if %ERRORLEVEL% EQU 0 exit /b 0
+reg query HKLM\Software\Wow6432Node\Microsoft\VisualStudio\12.0 /v InstallDir > nul 2>nul
+if %ERRORLEVEL% EQU 0 exit /b 0
+echo ERROR building Win8 drivers: VS11 is not installed
+exit /b 2 \ No newline at end of file
diff --git a/qxldod/clean.bat b/qxldod/clean.bat
new file mode 100755
index 0000000..83da6de
--- /dev/null
+++ b/qxldod/clean.bat
@@ -0,0 +1,12 @@
+@echo on
+
+rmdir /S /Q .\Install
+
+rmdir /S /Q objfre_win8_x86
+rmdir /S /Q objfre_win8_amd64
+rmdir /S /Q objchk_win8_x86
+rmdir /S /Q objchk_win8_amd64
+
+del /F *.log *.wrn *.err
+
+
diff --git a/qxldod/driver.cpp b/qxldod/driver.cpp
new file mode 100755
index 0000000..e8f48f2
--- /dev/null
+++ b/qxldod/driver.cpp
@@ -0,0 +1,676 @@
+#include "driver.h"
+#include "QxlDod.h"
+
+#pragma code_seg(push)
+#pragma code_seg("INIT")
+// BEGIN: Init Code
+
+//
+// Driver Entry point
+//
+
+int nDebugLevel = TRACE_LEVEL_ERROR;
+
+
+extern "C"
+NTSTATUS
+DriverEntry(
+ _In_ DRIVER_OBJECT* pDriverObject,
+ _In_ UNICODE_STRING* pRegistryPath)
+{
+ PAGED_CODE();
+
+ DbgPrint(TRACE_LEVEL_FATAL, ("---> KMDOD build on on %s %s\n", __DATE__, __TIME__));
+
+#ifdef DBG
+// KdBreakPoint();
+#endif
+ // Initialize DDI function pointers and dxgkrnl
+ KMDDOD_INITIALIZATION_DATA InitialData = {0};
+
+ InitialData.Version = DXGKDDI_INTERFACE_VERSION;
+
+ InitialData.DxgkDdiAddDevice = DodAddDevice;
+ InitialData.DxgkDdiStartDevice = DodStartDevice;
+ InitialData.DxgkDdiStopDevice = DodStopDevice;
+ InitialData.DxgkDdiResetDevice = DodResetDevice;
+ InitialData.DxgkDdiRemoveDevice = DodRemoveDevice;
+ InitialData.DxgkDdiDispatchIoRequest = DodDispatchIoRequest;
+ InitialData.DxgkDdiInterruptRoutine = DodInterruptRoutine;
+ InitialData.DxgkDdiDpcRoutine = DodDpcRoutine;
+ InitialData.DxgkDdiQueryChildRelations = DodQueryChildRelations;
+ InitialData.DxgkDdiQueryChildStatus = DodQueryChildStatus;
+ InitialData.DxgkDdiQueryDeviceDescriptor = DodQueryDeviceDescriptor;
+ InitialData.DxgkDdiSetPowerState = DodSetPowerState;
+ InitialData.DxgkDdiUnload = DodUnload;
+ InitialData.DxgkDdiQueryInterface = DodQueryInterface;
+ InitialData.DxgkDdiQueryAdapterInfo = DodQueryAdapterInfo;
+ InitialData.DxgkDdiSetPointerPosition = DodSetPointerPosition;
+ InitialData.DxgkDdiSetPointerShape = DodSetPointerShape;
+ InitialData.DxgkDdiEscape = DodEscape;
+ InitialData.DxgkDdiIsSupportedVidPn = DodIsSupportedVidPn;
+ InitialData.DxgkDdiRecommendFunctionalVidPn = DodRecommendFunctionalVidPn;
+ InitialData.DxgkDdiEnumVidPnCofuncModality = DodEnumVidPnCofuncModality;
+ InitialData.DxgkDdiSetVidPnSourceVisibility = DodSetVidPnSourceVisibility;
+ InitialData.DxgkDdiCommitVidPn = DodCommitVidPn;
+ InitialData.DxgkDdiUpdateActiveVidPnPresentPath = DodUpdateActiveVidPnPresentPath;
+ InitialData.DxgkDdiRecommendMonitorModes = DodRecommendMonitorModes;
+ InitialData.DxgkDdiQueryVidPnHWCapability = DodQueryVidPnHWCapability;
+ InitialData.DxgkDdiPresentDisplayOnly = DodPresentDisplayOnly;
+ InitialData.DxgkDdiStopDeviceAndReleasePostDisplayOwnership = DodStopDeviceAndReleasePostDisplayOwnership;
+ InitialData.DxgkDdiSystemDisplayEnable = DodSystemDisplayEnable;
+ InitialData.DxgkDdiSystemDisplayWrite = DodSystemDisplayWrite;
+
+ NTSTATUS Status = DxgkInitializeDisplayOnlyDriver(pDriverObject, pRegistryPath, &InitialData);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("DxgkInitializeDisplayOnlyDriver failed with Status: 0x%X\n", Status));
+ }
+
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__));
+ return Status;
+}
+// END: Init Code
+#pragma code_seg(pop)
+
+#pragma code_seg(push)
+#pragma code_seg("PAGE")
+
+//
+// PnP DDIs
+//
+
+VOID
+DodUnload(VOID)
+{
+ PAGED_CODE();
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("<--> %s\n", __FUNCTION__));
+}
+
+NTSTATUS
+DodAddDevice(
+ _In_ DEVICE_OBJECT* pPhysicalDeviceObject,
+ _Outptr_ PVOID* ppDeviceContext)
+{
+ PAGED_CODE();
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ if ((pPhysicalDeviceObject == NULL) ||
+ (ppDeviceContext == NULL))
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("One of pPhysicalDeviceObject (0x%I64x), ppDeviceContext (0x%I64x) is NULL",
+ pPhysicalDeviceObject, ppDeviceContext));
+ return STATUS_INVALID_PARAMETER;
+ }
+ *ppDeviceContext = NULL;
+
+ QxlDod* pQxl = new(NonPagedPoolNx) QxlDod(pPhysicalDeviceObject);
+ if (pQxl == NULL)
+ {
+ DbgPrint(TRACE_LEVEL_ERROR, ("pQxl failed to be allocated"));
+ return STATUS_NO_MEMORY;
+ }
+
+ *ppDeviceContext = pQxl;
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+DodRemoveDevice(
+ _In_ VOID* pDeviceContext)
+{
+ PAGED_CODE();
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(pDeviceContext);
+
+ if (pQxl)
+ {
+ delete pQxl;
+ pQxl = NULL;
+ }
+
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+DodStartDevice(
+ _In_ VOID* pDeviceContext,
+ _In_ DXGK_START_INFO* pDxgkStartInfo,
+ _In_ DXGKRNL_INTERFACE* pDxgkInterface,
+ _Out_ ULONG* pNumberOfViews,
+ _Out_ ULONG* pNumberOfChildren)
+{
+ PAGED_CODE();
+ QXL_ASSERT_CHK(pDeviceContext != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(pDeviceContext);
+ return pQxl->StartDevice(pDxgkStartInfo, pDxgkInterface, pNumberOfViews, pNumberOfChildren);
+}
+
+NTSTATUS
+DodStopDevice(
+ _In_ VOID* pDeviceContext)
+{
+ PAGED_CODE();
+ QXL_ASSERT_CHK(pDeviceContext != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(pDeviceContext);
+ return pQxl->StopDevice();
+}
+
+
+NTSTATUS
+DodDispatchIoRequest(
+ _In_ VOID* pDeviceContext,
+ _In_ ULONG VidPnSourceId,
+ _In_ VIDEO_REQUEST_PACKET* pVideoRequestPacket)
+{
+ PAGED_CODE();
+ QXL_ASSERT_CHK(pDeviceContext != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(pDeviceContext);
+ if (!pQxl->IsDriverActive())
+ {
+ QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pQxl->DispatchIoRequest(VidPnSourceId, pVideoRequestPacket);
+}
+
+NTSTATUS
+DodSetPowerState(
+ _In_ VOID* pDeviceContext,
+ _In_ ULONG HardwareUid,
+ _In_ DEVICE_POWER_STATE DevicePowerState,
+ _In_ POWER_ACTION ActionType)
+{
+ PAGED_CODE();
+ QXL_ASSERT_CHK(pDeviceContext != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(pDeviceContext);
+ if (!pQxl->IsDriverActive())
+ {
+ // If the driver isn't active, SetPowerState can still be called, however in QXL's case
+ // this shouldn't do anything, as it could for instance be called on QXL Fallback after
+ // Fallback has been stopped and QXL PnP is being started. Fallback doesn't have control
+ // of the hardware in this case.
+ return STATUS_SUCCESS;
+ }
+ return pQxl->SetPowerState(HardwareUid, DevicePowerState, ActionType);
+}
+
+NTSTATUS
+DodQueryChildRelations(
+ _In_ VOID* pDeviceContext,
+ _Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations,
+ _In_ ULONG ChildRelationsSize)
+{
+ PAGED_CODE();
+ QXL_ASSERT_CHK(pDeviceContext != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(pDeviceContext);
+ return pQxl->QueryChildRelations(pChildRelations, ChildRelationsSize);
+}
+
+NTSTATUS
+DodQueryChildStatus(
+ _In_ VOID* pDeviceContext,
+ _Inout_ DXGK_CHILD_STATUS* pChildStatus,
+ _In_ BOOLEAN NonDestructiveOnly)
+{
+ PAGED_CODE();
+ QXL_ASSERT_CHK(pDeviceContext != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(pDeviceContext);
+ return pQxl->QueryChildStatus(pChildStatus, NonDestructiveOnly);
+}
+
+NTSTATUS
+DodQueryDeviceDescriptor(
+ _In_ VOID* pDeviceContext,
+ _In_ ULONG ChildUid,
+ _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor)
+{
+ PAGED_CODE();
+ QXL_ASSERT_CHK(pDeviceContext != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(pDeviceContext);
+ if (!pQxl->IsDriverActive())
+ {
+ // During stress testing of PnPStop, it is possible for QXL Fallback to get called to start then stop in quick succession.
+ // The first call queues a worker thread item indicating that it now has a child device, the second queues a worker thread
+ // item that it no longer has any child device. This function gets called based on the first worker thread item, but after
+ // the driver has been stopped. Therefore instead of asserting like other functions, we only warn.
+ DbgPrint(TRACE_LEVEL_WARNING, ("QXL (0x%I64x) is being called when not active!", pQxl));
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pQxl->QueryDeviceDescriptor(ChildUid, pDeviceDescriptor);
+}
+
+
+//
+// WDDM Display Only Driver DDIs
+//
+
+NTSTATUS
+APIENTRY
+DodQueryAdapterInfo(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo)
+{
+ PAGED_CODE();
+ QXL_ASSERT_CHK(hAdapter != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
+ return pQxl->QueryAdapterInfo(pQueryAdapterInfo);
+}
+
+NTSTATUS
+APIENTRY
+DodSetPointerPosition(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition)
+{
+ PAGED_CODE();
+ QXL_ASSERT_CHK(hAdapter != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
+ if (!pQxl->IsDriverActive())
+ {
+ QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pQxl->SetPointerPosition(pSetPointerPosition);
+}
+
+NTSTATUS
+APIENTRY
+DodSetPointerShape(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape)
+{
+ PAGED_CODE();
+ QXL_ASSERT_CHK(hAdapter != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
+ if (!pQxl->IsDriverActive())
+ {
+ QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pQxl->SetPointerShape(pSetPointerShape);
+}
+
+NTSTATUS
+APIENTRY
+DodEscape(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_ESCAPE* pEscape
+ )
+{
+ PAGED_CODE();
+ QXL_ASSERT_CHK(hAdapter != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
+ return pQxl->Escape(pEscape);
+}
+
+NTSTATUS
+DodQueryInterface(
+ _In_ CONST PVOID pDeviceContext,
+ _In_ CONST PQUERY_INTERFACE QueryInterface
+ )
+{
+ PAGED_CODE();
+ QXL_ASSERT_CHK(pDeviceContext != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(pDeviceContext);
+ return pQxl->QueryInterface(QueryInterface);
+}
+
+NTSTATUS
+APIENTRY
+DodPresentDisplayOnly(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_PRESENT_DISPLAYONLY* pPresentDisplayOnly)
+{
+ PAGED_CODE();
+ QXL_ASSERT_CHK(hAdapter != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
+ if (!pQxl->IsDriverActive())
+ {
+ QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pQxl->PresentDisplayOnly(pPresentDisplayOnly);
+}
+
+NTSTATUS
+APIENTRY
+DodStopDeviceAndReleasePostDisplayOwnership(
+ _In_ VOID* pDeviceContext,
+ _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
+ _Out_ DXGK_DISPLAY_INFORMATION* DisplayInfo)
+{
+ PAGED_CODE();
+ QXL_ASSERT_CHK(pDeviceContext != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(pDeviceContext);
+ return pQxl->StopDeviceAndReleasePostDisplayOwnership(TargetId, DisplayInfo);
+}
+
+NTSTATUS
+APIENTRY
+DodIsSupportedVidPn(
+ _In_ CONST HANDLE hAdapter,
+ _Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn)
+{
+ PAGED_CODE();
+ QXL_ASSERT_CHK(hAdapter != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
+ if (!pQxl->IsDriverActive())
+ {
+ // This path might hit because win32k/dxgport doesn't check that an adapter is active when taking the adapter lock.
+ // The adapter lock is the main thing QXL Fallback relies on to not be called while it's inactive. It is still a rare
+ // timing issue around PnpStart/Stop and isn't expected to have any effect on the stability of the system.
+ DbgPrint(TRACE_LEVEL_WARNING, ("QXL (0x%I64x) is being called when not active!", pQxl));
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pQxl->IsSupportedVidPn(pIsSupportedVidPn);
+}
+
+NTSTATUS
+APIENTRY
+DodRecommendFunctionalVidPn(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn)
+{
+ PAGED_CODE();
+ QXL_ASSERT_CHK(hAdapter != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
+ if (!pQxl->IsDriverActive())
+ {
+ QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pQxl->RecommendFunctionalVidPn(pRecommendFunctionalVidPn);
+}
+
+NTSTATUS
+APIENTRY
+DodRecommendVidPnTopology(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology)
+{
+ PAGED_CODE();
+ QXL_ASSERT_CHK(hAdapter != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
+ if (!pQxl->IsDriverActive())
+ {
+ QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pQxl->RecommendVidPnTopology(pRecommendVidPnTopology);
+}
+
+NTSTATUS
+APIENTRY
+DodRecommendMonitorModes(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes)
+{
+ PAGED_CODE();
+ QXL_ASSERT_CHK(hAdapter != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
+ if (!pQxl->IsDriverActive())
+ {
+ QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pQxl->RecommendMonitorModes(pRecommendMonitorModes);
+}
+
+NTSTATUS
+APIENTRY
+DodEnumVidPnCofuncModality(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality)
+{
+ PAGED_CODE();
+ QXL_ASSERT_CHK(hAdapter != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
+ if (!pQxl->IsDriverActive())
+ {
+ QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pQxl->EnumVidPnCofuncModality(pEnumCofuncModality);
+}
+
+NTSTATUS
+APIENTRY
+DodSetVidPnSourceVisibility(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility)
+{
+ PAGED_CODE();
+ QXL_ASSERT_CHK(hAdapter != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
+ if (!pQxl->IsDriverActive())
+ {
+ QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pQxl->SetVidPnSourceVisibility(pSetVidPnSourceVisibility);
+}
+
+NTSTATUS
+APIENTRY
+DodCommitVidPn(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn)
+{
+ PAGED_CODE();
+ QXL_ASSERT_CHK(hAdapter != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
+ if (!pQxl->IsDriverActive())
+ {
+ QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pQxl->CommitVidPn(pCommitVidPn);
+}
+
+NTSTATUS
+APIENTRY
+DodUpdateActiveVidPnPresentPath(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath)
+{
+ PAGED_CODE();
+ QXL_ASSERT_CHK(hAdapter != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
+ if (!pQxl->IsDriverActive())
+ {
+ QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pQxl->UpdateActiveVidPnPresentPath(pUpdateActiveVidPnPresentPath);
+}
+
+NTSTATUS
+APIENTRY
+DodQueryVidPnHWCapability(
+ _In_ CONST HANDLE hAdapter,
+ _Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps)
+{
+ PAGED_CODE();
+ QXL_ASSERT_CHK(hAdapter != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(hAdapter);
+ if (!pQxl->IsDriverActive())
+ {
+ QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pQxl->QueryVidPnHWCapability(pVidPnHWCaps);
+}
+
+//END: Paged Code
+#pragma code_seg(pop)
+
+#pragma code_seg(push)
+#pragma code_seg()
+// BEGIN: Non-Paged Code
+
+VOID
+DodDpcRoutine(
+ _In_ VOID* pDeviceContext)
+{
+ QXL_ASSERT_CHK(pDeviceContext != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(pDeviceContext);
+ if (!pQxl->IsDriverActive())
+ {
+ QXL_LOG_ASSERTION1("QXL (0x%I64x) is being called when not active!", pQxl);
+ return;
+ }
+ pQxl->DpcRoutine();
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
+}
+
+BOOLEAN
+DodInterruptRoutine(
+ _In_ VOID* pDeviceContext,
+ _In_ ULONG MessageNumber)
+{
+ QXL_ASSERT_CHK(pDeviceContext != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(pDeviceContext);
+ return pQxl->InterruptRoutine(MessageNumber);
+}
+
+VOID
+DodResetDevice(
+ _In_ VOID* pDeviceContext)
+{
+ QXL_ASSERT_CHK(pDeviceContext != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(pDeviceContext);
+ pQxl->ResetDevice();
+}
+
+NTSTATUS
+APIENTRY
+DodSystemDisplayEnable(
+ _In_ VOID* pDeviceContext,
+ _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
+ _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags,
+ _Out_ UINT* Width,
+ _Out_ UINT* Height,
+ _Out_ D3DDDIFORMAT* ColorFormat)
+{
+ QXL_ASSERT_CHK(pDeviceContext != NULL);
+ DbgPrint(TRACE_LEVEL_VERBOSE, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(pDeviceContext);
+ return pQxl->SystemDisplayEnable(TargetId, Flags, Width, Height, ColorFormat);
+}
+
+VOID
+APIENTRY
+DodSystemDisplayWrite(
+ _In_ VOID* pDeviceContext,
+ _In_ VOID* Source,
+ _In_ UINT SourceWidth,
+ _In_ UINT SourceHeight,
+ _In_ UINT SourceStride,
+ _In_ UINT PositionX,
+ _In_ UINT PositionY)
+{
+ QXL_ASSERT_CHK(pDeviceContext != NULL);
+ DbgPrint(TRACE_LEVEL_INFORMATION, ("<---> %s\n", __FUNCTION__));
+
+ QxlDod* pQxl = reinterpret_cast<QxlDod*>(pDeviceContext);
+ pQxl->SystemDisplayWrite(Source, SourceWidth, SourceHeight, SourceStride, PositionX, PositionY);
+}
+
+#if defined(DBG)
+
+#define RHEL_DEBUG_PORT ((PUCHAR)0x3F8)
+#define TEMP_BUFFER_SIZE 256
+
+void DebugPrintFuncSerial(const char *format, ...)
+{
+ char buf[TEMP_BUFFER_SIZE];
+ NTSTATUS status;
+ size_t len;
+ va_list list;
+ va_start(list, format);
+ status = RtlStringCbVPrintfA(buf, sizeof(buf), format, list);
+ if (status == STATUS_SUCCESS)
+ {
+ len = strlen(buf);
+ }
+ else
+ {
+ len = 2;
+ buf[0] = 'O';
+ buf[1] = '\n';
+ }
+ if (len)
+ {
+ WRITE_PORT_BUFFER_UCHAR(RHEL_DEBUG_PORT, (PUCHAR)buf, (ULONG)len);
+ WRITE_PORT_UCHAR(RHEL_DEBUG_PORT, '\r');
+ }
+}
+
+void DebugPrintFunc(const char *format, ...)
+{
+ va_list list;
+ va_start(list, format);
+ vDbgPrintEx(DPFLTR_DEFAULT_ID, 9 | DPFLTR_MASK, format, list);
+}
+#endif
+
+#pragma code_seg(pop) // End Non-Paged Code
+
diff --git a/qxldod/driver.h b/qxldod/driver.h
new file mode 100755
index 0000000..72a8b46
--- /dev/null
+++ b/qxldod/driver.h
@@ -0,0 +1,255 @@
+#pragma once
+#include "BaseObject.h"
+
+
+extern "C"
+DRIVER_INITIALIZE DriverEntry;
+
+//
+// PnP DDIs
+//
+
+VOID
+DodUnload(VOID);
+
+// If uncommenting ENABLE_DXGK_SAL in the sources file, all the below function prototypes should be updated to use
+// the function typedef's from the header files. Additionally, annotations on the function definitions can be removed
+// as they are inherited from the prototype definition here. As an example the entire 4-line prototype for BddDdiAddDevice
+// is replaced by the single commented line below:
+// DXGKDDI_ADD_DEVICE BddDdiAddDevice;
+NTSTATUS
+DodAddDevice(
+ _In_ DEVICE_OBJECT* pPhysicalDeviceObject,
+ _Outptr_ PVOID* ppDeviceContext);
+
+NTSTATUS
+DodRemoveDevice(
+ _In_ VOID* pDeviceContext);
+
+NTSTATUS
+DodStartDevice(
+ _In_ VOID* pDeviceContext,
+ _In_ DXGK_START_INFO* pDxgkStartInfo,
+ _In_ DXGKRNL_INTERFACE* pDxgkInterface,
+ _Out_ ULONG* pNumberOfViews,
+ _Out_ ULONG* pNumberOfChildren);
+
+NTSTATUS
+DodStopDevice(
+ _In_ VOID* pDeviceContext);
+
+VOID
+DodResetDevice(
+ _In_ VOID* pDeviceContext);
+
+
+NTSTATUS
+DodDispatchIoRequest(
+ _In_ VOID* pDeviceContext,
+ _In_ ULONG VidPnSourceId,
+ _In_ VIDEO_REQUEST_PACKET* pVideoRequestPacket);
+
+NTSTATUS
+DodSetPowerState(
+ _In_ VOID* pDeviceContext,
+ _In_ ULONG HardwareUid,
+ _In_ DEVICE_POWER_STATE DevicePowerState,
+ _In_ POWER_ACTION ActionType);
+
+NTSTATUS
+DodQueryChildRelations(
+ _In_ VOID* pDeviceContext,
+ _Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations,
+ _In_ ULONG ChildRelationsSize);
+
+NTSTATUS
+DodQueryChildStatus(
+ _In_ VOID* pDeviceContext,
+ _Inout_ DXGK_CHILD_STATUS* pChildStatus,
+ _In_ BOOLEAN NonDestructiveOnly);
+
+NTSTATUS
+DodQueryDeviceDescriptor(
+ _In_ VOID* pDeviceContext,
+ _In_ ULONG ChildUid,
+ _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor);
+
+// Must be Non-Paged
+BOOLEAN
+DodInterruptRoutine(
+ _In_ VOID* pDeviceContext,
+ _In_ ULONG MessageNumber);
+
+VOID
+DodDpcRoutine(
+ _In_ VOID* pDeviceContext);
+
+//
+// WDDM Display Only Driver DDIs
+//
+
+NTSTATUS
+APIENTRY
+DodQueryAdapterInfo(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo);
+
+NTSTATUS
+APIENTRY
+DodSetPointerPosition(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition);
+
+NTSTATUS
+APIENTRY
+DodSetPointerShape(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape);
+
+NTSTATUS
+APIENTRY
+DodEscape(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_ESCAPE* pEscape);
+
+NTSTATUS
+DodQueryInterface(
+ _In_ CONST PVOID pDeviceContext,
+ _In_ CONST PQUERY_INTERFACE pQueryInterface);
+
+NTSTATUS
+APIENTRY
+DodPresentDisplayOnly(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_PRESENT_DISPLAYONLY* pPresentDisplayOnly);
+
+NTSTATUS
+APIENTRY
+DodIsSupportedVidPn(
+ _In_ CONST HANDLE hAdapter,
+ _Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn);
+
+NTSTATUS
+APIENTRY
+DodRecommendFunctionalVidPn(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn);
+
+NTSTATUS
+APIENTRY
+DodRecommendVidPnTopology(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology);
+
+NTSTATUS
+APIENTRY
+DodRecommendMonitorModes(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes);
+
+NTSTATUS
+APIENTRY
+DodEnumVidPnCofuncModality(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality);
+
+NTSTATUS
+APIENTRY
+DodSetVidPnSourceVisibility(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility);
+
+NTSTATUS
+APIENTRY
+DodCommitVidPn(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn);
+
+NTSTATUS
+APIENTRY
+DodUpdateActiveVidPnPresentPath(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath);
+
+NTSTATUS
+APIENTRY
+DodQueryVidPnHWCapability(
+ _In_ CONST HANDLE hAdapter,
+ _Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps);
+
+NTSTATUS
+APIENTRY
+DodStopDeviceAndReleasePostDisplayOwnership(
+ _In_ VOID* pDeviceContext,
+ _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
+ _Out_ DXGK_DISPLAY_INFORMATION* DisplayInfo);
+
+// Must be Non-Paged
+NTSTATUS
+APIENTRY
+DodSystemDisplayEnable(
+ _In_ VOID* pDeviceContext,
+ _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
+ _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags,
+ _Out_ UINT* Width,
+ _Out_ UINT* Height,
+ _Out_ D3DDDIFORMAT* ColorFormat);
+
+// Must be Non-Paged
+VOID
+APIENTRY
+DodSystemDisplayWrite(
+ _In_ VOID* pDeviceContext,
+ _In_ VOID* Source,
+ _In_ UINT SourceWidth,
+ _In_ UINT SourceHeight,
+ _In_ UINT SourceStride,
+ _In_ UINT PositionX,
+ _In_ UINT PositionY);
+
+
+
+#if DBG
+
+extern int nDebugLevel;
+void DebugPrintFuncSerial(const char *format, ...);
+
+void DebugPrintFunc(const char *format, ...);
+
+#define DbgPrint(level, line) \
+ if (level > nDebugLevel) {} \
+ else DebugPrintFuncSerial line
+#else
+#define DbgPrint(level, line)
+#endif
+
+// else if (0) DebugPrintFuncSerial line \
+
+
+#ifndef TRACE_LEVEL_INFORMATION
+#define TRACE_LEVEL_NONE 0 // Tracing is not on
+#define TRACE_LEVEL_FATAL 1 // Abnormal exit or termination
+#define TRACE_LEVEL_ERROR 2 // Severe errors that need logging
+#define TRACE_LEVEL_WARNING 3 // Warnings such as allocation failure
+#define TRACE_LEVEL_INFORMATION 4 // Includes non-error cases(e.g.,Entry-Exit)
+#define TRACE_LEVEL_VERBOSE 5 // Detailed traces from intermediate steps
+#define TRACE_LEVEL_RESERVED6 6
+#define TRACE_LEVEL_RESERVED7 7
+#define TRACE_LEVEL_RESERVED8 8
+#define TRACE_LEVEL_RESERVED9 9
+#endif // TRACE_LEVEL_INFORMATION
+
+#define QXL_LOG_ASSERTION0(Msg) NT_ASSERT(FALSE)
+#define QXL_LOG_ASSERTION1(Msg,Param1) NT_ASSERT(FALSE)
+#define QXL_LOG_ASSERTION2(Msg,Param1,Param2) NT_ASSERT(FALSE)
+#define QXL_LOG_ASSERTION3(Msg,Param1,Param2,Param3) NT_ASSERT(FALSE)
+#define QXL_LOG_ASSERTION4(Msg,Param1,Param2,Param3,Param4) NT_ASSERT(FALSE)
+#define QXL_LOG_ASSERTION5(Msg,Param1,Param2,Param3,Param4,Param5) NT_ASSERT(FALSE)
+#define QXL_ASSERT(exp) {if (!(exp)) {QXL_LOG_ASSERTION0(#exp);}}
+
+
+#if DBG
+#define QXL_ASSERT_CHK(exp) QXL_ASSERT(exp)
+#else
+#define QXL_ASSERT_CHK(exp) {}
+#endif
diff --git a/qxldod/getVisualStudioCmdLine.vbs b/qxldod/getVisualStudioCmdLine.vbs
new file mode 100755
index 0000000..4d2f2a1
--- /dev/null
+++ b/qxldod/getVisualStudioCmdLine.vbs
@@ -0,0 +1,28 @@
+' $1 - Visual studio version to run (10 or 11)
+' $2 ... Parameters to pass
+
+Dim strCmdLine, strTemp
+Set WshShell = Wscript.CreateObject("Wscript.Shell")
+
+On Error Resume Next
+strCmdLine = WshShell.RegRead("HKLM\SOFTWARE\Microsoft\VisualStudio\" + Wscript.Arguments(0) + ".0\InstallDir")
+' In case of error assume WoW64 case
+If Err <> 0 Then
+ On Error Goto 0
+ strCmdLine = WshShell.RegRead("HKLM\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\" + Wscript.Arguments(0) + ".0\InstallDir")
+End If
+
+On Error Goto 0
+strCmdLine = chr(34) + strCmdLine + "devenv.com" + chr(34)
+For i = 0 to (Wscript.Arguments.Count - 1)
+ If i > 0 Then
+ strTemp = Wscript.Arguments(i)
+ If InStr(strTemp, " ") Or InStr(strTemp, "|") Then
+ strCmdLine = strCmdLine + " " + chr(34) + strTemp + chr(34)
+ Else
+ strCmdLine = strCmdLine + " " + strTemp
+ End If
+ End If
+Next
+
+WScript.Echo strCmdLine + vbCrLf
diff --git a/qxldod/include/barrier.h b/qxldod/include/barrier.h
new file mode 100755
index 0000000..710da09
--- /dev/null
+++ b/qxldod/include/barrier.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ Copyright (C) 2009 Red Hat, Inc.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS
+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _H_SPICE_BARRIER
+#define _H_SPICE_BARRIER
+
+#ifdef __GNUC__
+
+#ifdef __i386__
+#define spice_mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
+#else
+//mfence
+#define spice_mb() __asm__ __volatile__ ("lock; addl $0,0(%%rsp)": : :"memory")
+#endif
+
+#else
+
+#ifdef _WIN64
+//__asm not supported on _WIN64, so use macro instead.
+#define spice_mb MemoryBarrier
+#else
+#define spice_mb() __asm {lock add [esp], 0}
+#endif
+
+#endif
+
+#endif /* _H_SPICE_BARRIER */
diff --git a/qxldod/include/end-packed.h b/qxldod/include/end-packed.h
new file mode 100755
index 0000000..1acea18
--- /dev/null
+++ b/qxldod/include/end-packed.h
@@ -0,0 +1,38 @@
+/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ Copyright (C) 2009 Red Hat, Inc.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS
+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* See start-packed.h for details */
+
+#undef SPICE_ATTR_PACKED
+
+#if defined(__MINGW32__) || !defined(__GNUC__)
+#pragma pack(pop)
+#endif
diff --git a/qxldod/include/enums.h b/qxldod/include/enums.h
new file mode 100755
index 0000000..cf5715f
--- /dev/null
+++ b/qxldod/include/enums.h
@@ -0,0 +1,613 @@
+/* this is a file autogenerated by spice_codegen.py */
+#ifndef _H_SPICE_ENUMS
+#define _H_SPICE_ENUMS
+
+/* Generated from spice.proto, don't edit */
+
+typedef enum SpiceLinkErr {
+ SPICE_LINK_ERR_OK,
+ SPICE_LINK_ERR_ERROR,
+ SPICE_LINK_ERR_INVALID_MAGIC,
+ SPICE_LINK_ERR_INVALID_DATA,
+ SPICE_LINK_ERR_VERSION_MISMATCH,
+ SPICE_LINK_ERR_NEED_SECURED,
+ SPICE_LINK_ERR_NEED_UNSECURED,
+ SPICE_LINK_ERR_PERMISSION_DENIED,
+ SPICE_LINK_ERR_BAD_CONNECTION_ID,
+ SPICE_LINK_ERR_CHANNEL_NOT_AVAILABLE,
+
+ SPICE_LINK_ERR_ENUM_END
+} SpiceLinkErr;
+
+typedef enum SpiceWarnCode {
+ SPICE_WARN_GENERAL,
+
+ SPICE_WARN_CODE_ENUM_END
+} SpiceWarnCode;
+
+typedef enum SpiceInfoCode {
+ SPICE_INFO_GENERAL,
+
+ SPICE_INFO_CODE_ENUM_END
+} SpiceInfoCode;
+
+typedef enum SpiceMigrateFlags {
+ SPICE_MIGRATE_NEED_FLUSH = (1 << 0),
+ SPICE_MIGRATE_NEED_DATA_TRANSFER = (1 << 1),
+
+ SPICE_MIGRATE_FLAGS_MASK = 0x3
+} SpiceMigrateFlags;
+
+typedef enum SpiceCompositeFlags {
+ SPICE_COMPOSITE_OP0 = (1 << 0),
+ SPICE_COMPOSITE_OP1 = (1 << 1),
+ SPICE_COMPOSITE_OP2 = (1 << 2),
+ SPICE_COMPOSITE_OP3 = (1 << 3),
+ SPICE_COMPOSITE_OP4 = (1 << 4),
+ SPICE_COMPOSITE_OP5 = (1 << 5),
+ SPICE_COMPOSITE_OP6 = (1 << 6),
+ SPICE_COMPOSITE_OP7 = (1 << 7),
+ SPICE_COMPOSITE_SRC_FILTER0 = (1 << 8),
+ SPICE_COMPOSITE_SRC_FILTER1 = (1 << 9),
+ SPICE_COMPOSITE_SRC_FILTER2 = (1 << 10),
+ SPICE_COMPOSITE_MASK_FILTER0 = (1 << 11),
+ SPICE_COMPOSITE_MASK_FITLER1 = (1 << 12),
+ SPICE_COMPOSITE_MASK_FILTER2 = (1 << 13),
+ SPICE_COMPOSITE_SRC_REPEAT0 = (1 << 14),
+ SPICE_COMPOSITE_SRC_REPEAT1 = (1 << 15),
+ SPICE_COMPOSITE_MASK_REPEAT0 = (1 << 16),
+ SPICE_COMPOSITE_MASK_REPEAT1 = (1 << 17),
+ SPICE_COMPOSITE_COMPONENT_ALPHA = (1 << 18),
+ SPICE_COMPOSITE_HAS_MASK = (1 << 19),
+ SPICE_COMPOSITE_HAS_SRC_TRANSFORM = (1 << 20),
+ SPICE_COMPOSITE_HAS_MASK_TRANSFORM = (1 << 21),
+ SPICE_COMPOSITE_SOURCE_OPAQUE = (1 << 22),
+ SPICE_COMPOSITE_MASK_OPAQUE = (1 << 23),
+ SPICE_COMPOSITE_DEST_OPAQUE = (1 << 24),
+
+ SPICE_COMPOSITE_FLAGS_MASK = 0x1ffffff
+} SpiceCompositeFlags;
+
+typedef enum SpiceNotifySeverity {
+ SPICE_NOTIFY_SEVERITY_INFO,
+ SPICE_NOTIFY_SEVERITY_WARN,
+ SPICE_NOTIFY_SEVERITY_ERROR,
+
+ SPICE_NOTIFY_SEVERITY_ENUM_END
+} SpiceNotifySeverity;
+
+typedef enum SpiceNotifyVisibility {
+ SPICE_NOTIFY_VISIBILITY_LOW,
+ SPICE_NOTIFY_VISIBILITY_MEDIUM,
+ SPICE_NOTIFY_VISIBILITY_HIGH,
+
+ SPICE_NOTIFY_VISIBILITY_ENUM_END
+} SpiceNotifyVisibility;
+
+typedef enum SpiceMouseMode {
+ SPICE_MOUSE_MODE_SERVER = (1 << 0),
+ SPICE_MOUSE_MODE_CLIENT = (1 << 1),
+
+ SPICE_MOUSE_MODE_MASK = 0x3
+} SpiceMouseMode;
+
+typedef enum SpicePubkeyType {
+ SPICE_PUBKEY_TYPE_INVALID,
+ SPICE_PUBKEY_TYPE_RSA,
+ SPICE_PUBKEY_TYPE_RSA2,
+ SPICE_PUBKEY_TYPE_DSA,
+ SPICE_PUBKEY_TYPE_DSA1,
+ SPICE_PUBKEY_TYPE_DSA2,
+ SPICE_PUBKEY_TYPE_DSA3,
+ SPICE_PUBKEY_TYPE_DSA4,
+ SPICE_PUBKEY_TYPE_DH,
+ SPICE_PUBKEY_TYPE_EC,
+
+ SPICE_PUBKEY_TYPE_ENUM_END
+} SpicePubkeyType;
+
+typedef enum SpiceClipType {
+ SPICE_CLIP_TYPE_NONE,
+ SPICE_CLIP_TYPE_RECTS,
+
+ SPICE_CLIP_TYPE_ENUM_END
+} SpiceClipType;
+
+typedef enum SpicePathFlags {
+ SPICE_PATH_BEGIN = (1 << 0),
+ SPICE_PATH_END = (1 << 1),
+ SPICE_PATH_CLOSE = (1 << 3),
+ SPICE_PATH_BEZIER = (1 << 4),
+
+ SPICE_PATH_FLAGS_MASK = 0x1b
+} SpicePathFlags;
+
+typedef enum SpiceVideoCodecType {
+ SPICE_VIDEO_CODEC_TYPE_MJPEG = 1,
+
+ SPICE_VIDEO_CODEC_TYPE_ENUM_END
+} SpiceVideoCodecType;
+
+typedef enum SpiceStreamFlags {
+ SPICE_STREAM_FLAGS_TOP_DOWN = (1 << 0),
+
+ SPICE_STREAM_FLAGS_MASK = 0x1
+} SpiceStreamFlags;
+
+typedef enum SpiceBrushType {
+ SPICE_BRUSH_TYPE_NONE,
+ SPICE_BRUSH_TYPE_SOLID,
+ SPICE_BRUSH_TYPE_PATTERN,
+
+ SPICE_BRUSH_TYPE_ENUM_END
+} SpiceBrushType;
+
+typedef enum SpiceMaskFlags {
+ SPICE_MASK_FLAGS_INVERS = (1 << 0),
+
+ SPICE_MASK_FLAGS_MASK = 0x1
+} SpiceMaskFlags;
+
+typedef enum SpiceImageType {
+ SPICE_IMAGE_TYPE_BITMAP,
+ SPICE_IMAGE_TYPE_QUIC,
+ SPICE_IMAGE_TYPE_RESERVED,
+ SPICE_IMAGE_TYPE_LZ_PLT = 100,
+ SPICE_IMAGE_TYPE_LZ_RGB,
+ SPICE_IMAGE_TYPE_GLZ_RGB,
+ SPICE_IMAGE_TYPE_FROM_CACHE,
+ SPICE_IMAGE_TYPE_SURFACE,
+ SPICE_IMAGE_TYPE_JPEG,
+ SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS,
+ SPICE_IMAGE_TYPE_ZLIB_GLZ_RGB,
+ SPICE_IMAGE_TYPE_JPEG_ALPHA,
+
+ SPICE_IMAGE_TYPE_ENUM_END
+} SpiceImageType;
+
+typedef enum SpiceImageFlags {
+ SPICE_IMAGE_FLAGS_CACHE_ME = (1 << 0),
+ SPICE_IMAGE_FLAGS_HIGH_BITS_SET = (1 << 1),
+ SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME = (1 << 2),
+
+ SPICE_IMAGE_FLAGS_MASK = 0x7
+} SpiceImageFlags;
+
+typedef enum SpiceBitmapFmt {
+ SPICE_BITMAP_FMT_INVALID,
+ SPICE_BITMAP_FMT_1BIT_LE,
+ SPICE_BITMAP_FMT_1BIT_BE,
+ SPICE_BITMAP_FMT_4BIT_LE,
+ SPICE_BITMAP_FMT_4BIT_BE,
+ SPICE_BITMAP_FMT_8BIT,
+ SPICE_BITMAP_FMT_16BIT,
+ SPICE_BITMAP_FMT_24BIT,
+ SPICE_BITMAP_FMT_32BIT,
+ SPICE_BITMAP_FMT_RGBA,
+ SPICE_BITMAP_FMT_8BIT_A,
+
+ SPICE_BITMAP_FMT_ENUM_END
+} SpiceBitmapFmt;
+
+typedef enum SpiceBitmapFlags {
+ SPICE_BITMAP_FLAGS_PAL_CACHE_ME = (1 << 0),
+ SPICE_BITMAP_FLAGS_PAL_FROM_CACHE = (1 << 1),
+ SPICE_BITMAP_FLAGS_TOP_DOWN = (1 << 2),
+
+ SPICE_BITMAP_FLAGS_MASK = 0x7
+} SpiceBitmapFlags;
+
+typedef enum SpiceJpegAlphaFlags {
+ SPICE_JPEG_ALPHA_FLAGS_TOP_DOWN = (1 << 0),
+
+ SPICE_JPEG_ALPHA_FLAGS_MASK = 0x1
+} SpiceJpegAlphaFlags;
+
+typedef enum SpiceImageScaleMode {
+ SPICE_IMAGE_SCALE_MODE_INTERPOLATE,
+ SPICE_IMAGE_SCALE_MODE_NEAREST,
+
+ SPICE_IMAGE_SCALE_MODE_ENUM_END
+} SpiceImageScaleMode;
+
+typedef enum SpiceRopd {
+ SPICE_ROPD_INVERS_SRC = (1 << 0),
+ SPICE_ROPD_INVERS_BRUSH = (1 << 1),
+ SPICE_ROPD_INVERS_DEST = (1 << 2),
+ SPICE_ROPD_OP_PUT = (1 << 3),
+ SPICE_ROPD_OP_OR = (1 << 4),
+ SPICE_ROPD_OP_AND = (1 << 5),
+ SPICE_ROPD_OP_XOR = (1 << 6),
+ SPICE_ROPD_OP_BLACKNESS = (1 << 7),
+ SPICE_ROPD_OP_WHITENESS = (1 << 8),
+ SPICE_ROPD_OP_INVERS = (1 << 9),
+ SPICE_ROPD_INVERS_RES = (1 << 10),
+
+ SPICE_ROPD_MASK = 0x7ff
+} SpiceRopd;
+
+typedef enum SpiceLineFlags {
+ SPICE_LINE_FLAGS_START_WITH_GAP = (1 << 2),
+ SPICE_LINE_FLAGS_STYLED = (1 << 3),
+
+ SPICE_LINE_FLAGS_MASK = 0xc
+} SpiceLineFlags;
+
+typedef enum SpiceStringFlags {
+ SPICE_STRING_FLAGS_RASTER_A1 = (1 << 0),
+ SPICE_STRING_FLAGS_RASTER_A4 = (1 << 1),
+ SPICE_STRING_FLAGS_RASTER_A8 = (1 << 2),
+ SPICE_STRING_FLAGS_RASTER_TOP_DOWN = (1 << 3),
+
+ SPICE_STRING_FLAGS_MASK = 0xf
+} SpiceStringFlags;
+
+typedef enum SpiceSurfaceFlags {
+ SPICE_SURFACE_FLAGS_PRIMARY = (1 << 0),
+
+ SPICE_SURFACE_FLAGS_MASK = 0x1
+} SpiceSurfaceFlags;
+
+typedef enum SpiceSurfaceFmt {
+ SPICE_SURFACE_FMT_INVALID,
+ SPICE_SURFACE_FMT_1_A,
+ SPICE_SURFACE_FMT_8_A = 8,
+ SPICE_SURFACE_FMT_16_555 = 16,
+ SPICE_SURFACE_FMT_32_xRGB = 32,
+ SPICE_SURFACE_FMT_16_565 = 80,
+ SPICE_SURFACE_FMT_32_ARGB = 96,
+
+ SPICE_SURFACE_FMT_ENUM_END
+} SpiceSurfaceFmt;
+
+typedef enum SpiceAlphaFlags {
+ SPICE_ALPHA_FLAGS_DEST_HAS_ALPHA = (1 << 0),
+ SPICE_ALPHA_FLAGS_SRC_SURFACE_HAS_ALPHA = (1 << 1),
+
+ SPICE_ALPHA_FLAGS_MASK = 0x3
+} SpiceAlphaFlags;
+
+typedef enum SpiceResourceType {
+ SPICE_RES_TYPE_INVALID,
+ SPICE_RES_TYPE_PIXMAP,
+
+ SPICE_RESOURCE_TYPE_ENUM_END
+} SpiceResourceType;
+
+typedef enum SpiceKeyboardModifierFlags {
+ SPICE_KEYBOARD_MODIFIER_FLAGS_SCROLL_LOCK = (1 << 0),
+ SPICE_KEYBOARD_MODIFIER_FLAGS_NUM_LOCK = (1 << 1),
+ SPICE_KEYBOARD_MODIFIER_FLAGS_CAPS_LOCK = (1 << 2),
+
+ SPICE_KEYBOARD_MODIFIER_FLAGS_MASK = 0x7
+} SpiceKeyboardModifierFlags;
+
+typedef enum SpiceMouseButton {
+ SPICE_MOUSE_BUTTON_INVALID,
+ SPICE_MOUSE_BUTTON_LEFT,
+ SPICE_MOUSE_BUTTON_MIDDLE,
+ SPICE_MOUSE_BUTTON_RIGHT,
+ SPICE_MOUSE_BUTTON_UP,
+ SPICE_MOUSE_BUTTON_DOWN,
+
+ SPICE_MOUSE_BUTTON_ENUM_END
+} SpiceMouseButton;
+
+typedef enum SpiceMouseButtonMask {
+ SPICE_MOUSE_BUTTON_MASK_LEFT = (1 << 0),
+ SPICE_MOUSE_BUTTON_MASK_MIDDLE = (1 << 1),
+ SPICE_MOUSE_BUTTON_MASK_RIGHT = (1 << 2),
+
+ SPICE_MOUSE_BUTTON_MASK_MASK = 0x7
+} SpiceMouseButtonMask;
+
+typedef enum SpiceCursorType {
+ SPICE_CURSOR_TYPE_ALPHA,
+ SPICE_CURSOR_TYPE_MONO,
+ SPICE_CURSOR_TYPE_COLOR4,
+ SPICE_CURSOR_TYPE_COLOR8,
+ SPICE_CURSOR_TYPE_COLOR16,
+ SPICE_CURSOR_TYPE_COLOR24,
+ SPICE_CURSOR_TYPE_COLOR32,
+
+ SPICE_CURSOR_TYPE_ENUM_END
+} SpiceCursorType;
+
+typedef enum SpiceCursorFlags {
+ SPICE_CURSOR_FLAGS_NONE = (1 << 0),
+ SPICE_CURSOR_FLAGS_CACHE_ME = (1 << 1),
+ SPICE_CURSOR_FLAGS_FROM_CACHE = (1 << 2),
+
+ SPICE_CURSOR_FLAGS_MASK = 0x7
+} SpiceCursorFlags;
+
+typedef enum SpiceAudioDataMode {
+ SPICE_AUDIO_DATA_MODE_INVALID,
+ SPICE_AUDIO_DATA_MODE_RAW,
+ SPICE_AUDIO_DATA_MODE_CELT_0_5_1,
+
+ SPICE_AUDIO_DATA_MODE_ENUM_END
+} SpiceAudioDataMode;
+
+typedef enum SpiceAudioFmt {
+ SPICE_AUDIO_FMT_INVALID,
+ SPICE_AUDIO_FMT_S16,
+
+ SPICE_AUDIO_FMT_ENUM_END
+} SpiceAudioFmt;
+
+typedef enum SpiceTunnelServiceType {
+ SPICE_TUNNEL_SERVICE_TYPE_INVALID,
+ SPICE_TUNNEL_SERVICE_TYPE_GENERIC,
+ SPICE_TUNNEL_SERVICE_TYPE_IPP,
+
+ SPICE_TUNNEL_SERVICE_TYPE_ENUM_END
+} SpiceTunnelServiceType;
+
+typedef enum SpiceTunnelIpType {
+ SPICE_TUNNEL_IP_TYPE_INVALID,
+ SPICE_TUNNEL_IP_TYPE_IPv4,
+
+ SPICE_TUNNEL_IP_TYPE_ENUM_END
+} SpiceTunnelIpType;
+
+typedef enum SpiceVscMessageType {
+ SPICE_VSC_MESSAGE_TYPE_Init = 1,
+ SPICE_VSC_MESSAGE_TYPE_Error,
+ SPICE_VSC_MESSAGE_TYPE_ReaderAdd,
+ SPICE_VSC_MESSAGE_TYPE_ReaderRemove,
+ SPICE_VSC_MESSAGE_TYPE_ATR,
+ SPICE_VSC_MESSAGE_TYPE_CardRemove,
+ SPICE_VSC_MESSAGE_TYPE_APDU,
+ SPICE_VSC_MESSAGE_TYPE_Flush,
+ SPICE_VSC_MESSAGE_TYPE_FlushComplete,
+
+ SPICE_VSC_MESSAGE_TYPE_ENUM_END
+} SpiceVscMessageType;
+
+enum {
+ SPICE_CHANNEL_MAIN = 1,
+ SPICE_CHANNEL_DISPLAY,
+ SPICE_CHANNEL_INPUTS,
+ SPICE_CHANNEL_CURSOR,
+ SPICE_CHANNEL_PLAYBACK,
+ SPICE_CHANNEL_RECORD,
+ SPICE_CHANNEL_TUNNEL,
+ SPICE_CHANNEL_SMARTCARD,
+ SPICE_CHANNEL_USBREDIR,
+ SPICE_CHANNEL_PORT,
+
+ SPICE_END_CHANNEL
+};
+
+enum {
+ SPICE_MSG_MIGRATE = 1,
+ SPICE_MSG_MIGRATE_DATA,
+ SPICE_MSG_SET_ACK,
+ SPICE_MSG_PING,
+ SPICE_MSG_WAIT_FOR_CHANNELS,
+ SPICE_MSG_DISCONNECTING,
+ SPICE_MSG_NOTIFY,
+ SPICE_MSG_LIST,
+};
+
+enum {
+ SPICE_MSGC_ACK_SYNC = 1,
+ SPICE_MSGC_ACK,
+ SPICE_MSGC_PONG,
+ SPICE_MSGC_MIGRATE_FLUSH_MARK,
+ SPICE_MSGC_MIGRATE_DATA,
+ SPICE_MSGC_DISCONNECTING,
+};
+
+enum {
+ SPICE_MSG_MAIN_MIGRATE_BEGIN = 101,
+ SPICE_MSG_MAIN_MIGRATE_CANCEL,
+ SPICE_MSG_MAIN_INIT,
+ SPICE_MSG_MAIN_CHANNELS_LIST,
+ SPICE_MSG_MAIN_MOUSE_MODE,
+ SPICE_MSG_MAIN_MULTI_MEDIA_TIME,
+ SPICE_MSG_MAIN_AGENT_CONNECTED,
+ SPICE_MSG_MAIN_AGENT_DISCONNECTED,
+ SPICE_MSG_MAIN_AGENT_DATA,
+ SPICE_MSG_MAIN_AGENT_TOKEN,
+ SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST,
+ SPICE_MSG_MAIN_MIGRATE_END,
+ SPICE_MSG_MAIN_NAME,
+ SPICE_MSG_MAIN_UUID,
+ SPICE_MSG_MAIN_AGENT_CONNECTED_TOKENS,
+ SPICE_MSG_MAIN_MIGRATE_BEGIN_SEAMLESS,
+ SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_ACK,
+ SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_NACK,
+
+ SPICE_MSG_END_MAIN
+};
+
+enum {
+ SPICE_MSGC_MAIN_CLIENT_INFO = 101,
+ SPICE_MSGC_MAIN_MIGRATE_CONNECTED,
+ SPICE_MSGC_MAIN_MIGRATE_CONNECT_ERROR,
+ SPICE_MSGC_MAIN_ATTACH_CHANNELS,
+ SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST,
+ SPICE_MSGC_MAIN_AGENT_START,
+ SPICE_MSGC_MAIN_AGENT_DATA,
+ SPICE_MSGC_MAIN_AGENT_TOKEN,
+ SPICE_MSGC_MAIN_MIGRATE_END,
+ SPICE_MSGC_MAIN_MIGRATE_DST_DO_SEAMLESS,
+ SPICE_MSGC_MAIN_MIGRATE_CONNECTED_SEAMLESS,
+
+ SPICE_MSGC_END_MAIN
+};
+
+enum {
+ SPICE_MSG_DISPLAY_MODE = 101,
+ SPICE_MSG_DISPLAY_MARK,
+ SPICE_MSG_DISPLAY_RESET,
+ SPICE_MSG_DISPLAY_COPY_BITS,
+ SPICE_MSG_DISPLAY_INVAL_LIST,
+ SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS,
+ SPICE_MSG_DISPLAY_INVAL_PALETTE,
+ SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES,
+ SPICE_MSG_DISPLAY_STREAM_CREATE = 122,
+ SPICE_MSG_DISPLAY_STREAM_DATA,
+ SPICE_MSG_DISPLAY_STREAM_CLIP,
+ SPICE_MSG_DISPLAY_STREAM_DESTROY,
+ SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL,
+ SPICE_MSG_DISPLAY_DRAW_FILL = 302,
+ SPICE_MSG_DISPLAY_DRAW_OPAQUE,
+ SPICE_MSG_DISPLAY_DRAW_COPY,
+ SPICE_MSG_DISPLAY_DRAW_BLEND,
+ SPICE_MSG_DISPLAY_DRAW_BLACKNESS,
+ SPICE_MSG_DISPLAY_DRAW_WHITENESS,
+ SPICE_MSG_DISPLAY_DRAW_INVERS,
+ SPICE_MSG_DISPLAY_DRAW_ROP3,
+ SPICE_MSG_DISPLAY_DRAW_STROKE,
+ SPICE_MSG_DISPLAY_DRAW_TEXT,
+ SPICE_MSG_DISPLAY_DRAW_TRANSPARENT,
+ SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND,
+ SPICE_MSG_DISPLAY_SURFACE_CREATE,
+ SPICE_MSG_DISPLAY_SURFACE_DESTROY,
+ SPICE_MSG_DISPLAY_STREAM_DATA_SIZED,
+ SPICE_MSG_DISPLAY_MONITORS_CONFIG,
+ SPICE_MSG_DISPLAY_DRAW_COMPOSITE,
+
+ SPICE_MSG_END_DISPLAY
+};
+
+enum {
+ SPICE_MSGC_DISPLAY_INIT = 101,
+
+ SPICE_MSGC_END_DISPLAY
+};
+
+enum {
+ SPICE_MSG_INPUTS_INIT = 101,
+ SPICE_MSG_INPUTS_KEY_MODIFIERS,
+ SPICE_MSG_INPUTS_MOUSE_MOTION_ACK = 111,
+
+ SPICE_MSG_END_INPUTS
+};
+
+enum {
+ SPICE_MSGC_INPUTS_KEY_DOWN = 101,
+ SPICE_MSGC_INPUTS_KEY_UP,
+ SPICE_MSGC_INPUTS_KEY_MODIFIERS,
+ SPICE_MSGC_INPUTS_KEY_SCANCODE,
+ SPICE_MSGC_INPUTS_MOUSE_MOTION = 111,
+ SPICE_MSGC_INPUTS_MOUSE_POSITION,
+ SPICE_MSGC_INPUTS_MOUSE_PRESS,
+ SPICE_MSGC_INPUTS_MOUSE_RELEASE,
+
+ SPICE_MSGC_END_INPUTS
+};
+
+enum {
+ SPICE_MSG_CURSOR_INIT = 101,
+ SPICE_MSG_CURSOR_RESET,
+ SPICE_MSG_CURSOR_SET,
+ SPICE_MSG_CURSOR_MOVE,
+ SPICE_MSG_CURSOR_HIDE,
+ SPICE_MSG_CURSOR_TRAIL,
+ SPICE_MSG_CURSOR_INVAL_ONE,
+ SPICE_MSG_CURSOR_INVAL_ALL,
+
+ SPICE_MSG_END_CURSOR
+};
+
+enum {
+ SPICE_MSG_PLAYBACK_DATA = 101,
+ SPICE_MSG_PLAYBACK_MODE,
+ SPICE_MSG_PLAYBACK_START,
+ SPICE_MSG_PLAYBACK_STOP,
+ SPICE_MSG_PLAYBACK_VOLUME,
+ SPICE_MSG_PLAYBACK_MUTE,
+
+ SPICE_MSG_END_PLAYBACK
+};
+
+enum {
+ SPICE_MSG_RECORD_START = 101,
+ SPICE_MSG_RECORD_STOP,
+ SPICE_MSG_RECORD_VOLUME,
+ SPICE_MSG_RECORD_MUTE,
+
+ SPICE_MSG_END_RECORD
+};
+
+enum {
+ SPICE_MSGC_RECORD_DATA = 101,
+ SPICE_MSGC_RECORD_MODE,
+ SPICE_MSGC_RECORD_START_MARK,
+
+ SPICE_MSGC_END_RECORD
+};
+
+enum {
+ SPICE_MSG_TUNNEL_INIT = 101,
+ SPICE_MSG_TUNNEL_SERVICE_IP_MAP,
+ SPICE_MSG_TUNNEL_SOCKET_OPEN,
+ SPICE_MSG_TUNNEL_SOCKET_FIN,
+ SPICE_MSG_TUNNEL_SOCKET_CLOSE,
+ SPICE_MSG_TUNNEL_SOCKET_DATA,
+ SPICE_MSG_TUNNEL_SOCKET_CLOSED_ACK,
+ SPICE_MSG_TUNNEL_SOCKET_TOKEN,
+
+ SPICE_MSG_END_TUNNEL
+};
+
+enum {
+ SPICE_MSGC_TUNNEL_SERVICE_ADD = 101,
+ SPICE_MSGC_TUNNEL_SERVICE_REMOVE,
+ SPICE_MSGC_TUNNEL_SOCKET_OPEN_ACK,
+ SPICE_MSGC_TUNNEL_SOCKET_OPEN_NACK,
+ SPICE_MSGC_TUNNEL_SOCKET_FIN,
+ SPICE_MSGC_TUNNEL_SOCKET_CLOSED,
+ SPICE_MSGC_TUNNEL_SOCKET_CLOSED_ACK,
+ SPICE_MSGC_TUNNEL_SOCKET_DATA,
+ SPICE_MSGC_TUNNEL_SOCKET_TOKEN,
+
+ SPICE_MSGC_END_TUNNEL
+};
+
+enum {
+ SPICE_MSG_SMARTCARD_DATA = 101,
+
+ SPICE_MSG_END_SMARTCARD
+};
+
+enum {
+ SPICE_MSGC_SMARTCARD_DATA = 101,
+ SPICE_MSGC_SMARTCARD_HEADER = 101,
+ SPICE_MSGC_SMARTCARD_ERROR = 101,
+ SPICE_MSGC_SMARTCARD_ATR = 101,
+ SPICE_MSGC_SMARTCARD_READER_ADD = 101,
+
+ SPICE_MSGC_END_SMARTCARD
+};
+
+enum {
+ SPICE_MSG_SPICEVMC_DATA = 101,
+
+ SPICE_MSG_END_SPICEVMC
+};
+
+enum {
+ SPICE_MSGC_SPICEVMC_DATA = 101,
+
+ SPICE_MSGC_END_SPICEVMC
+};
+
+enum {
+ SPICE_MSG_PORT_INIT = 201,
+ SPICE_MSG_PORT_EVENT,
+
+ SPICE_MSG_END_PORT
+};
+
+enum {
+ SPICE_MSGC_PORT_EVENT = 201,
+
+ SPICE_MSGC_END_PORT
+};
+
+#endif /* _H_SPICE_ENUMS */
diff --git a/qxldod/include/ipc_ring.h b/qxldod/include/ipc_ring.h
new file mode 100755
index 0000000..b751c68
--- /dev/null
+++ b/qxldod/include/ipc_ring.h
@@ -0,0 +1,136 @@
+/*
+ Copyright (C) 2009 Red Hat, Inc.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS
+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef _H_SPICE_RING
+#define _H_SPICE_RING
+
+#include <include/types.h>
+
+#define _SPICE_MSB_MASK4(x) \
+ (((x) & 0x8) ? 0x8 : \
+ ((x) & 0x4) ? 0x4 : \
+ ((x) & 0x2) ? 0x2 : \
+ ((x) & 0x1) ? 0x1 : 0)
+
+#define _SPICE_MSB_MASK8(x) \
+ (((x) & 0xf0) ? _SPICE_MSB_MASK4((x) >> 4) << 4 : _SPICE_MSB_MASK4(x))
+
+#define _SPICE_MSB_MASK16(x) \
+ (((x) & 0xff00) ? _SPICE_MSB_MASK8((x) >> 8) << 8 : _SPICE_MSB_MASK8(x))
+
+#define _SPICE_MSB_MASK(x) \
+ (((x) & 0xffff0000) ? _SPICE_MSB_MASK16((x) >> 16) << 16 : _SPICE_MSB_MASK16(x))
+
+#define _SPICE_POWER2_ALIGN(x) _SPICE_MSB_MASK((x) * 2 - 1)
+
+
+#define _SPICE_TOSHIFT_4(x) \
+ (((x) & 0x8) ? 3 : \
+ ((x) & 0x4) ? 2 : \
+ ((x) & 0x2) ? 1 : 0)
+
+#define _SPICE_TOSHIFT_8(x) \
+ (((x) & 0xf0) ? _SPICE_TOSHIFT_4((x) >> 4) + 4 : _SPICE_TOSHIFT_4(x))
+
+#define _SPICE_TOSHIFT_16(x) \
+ (((x) & 0xff00) ? _SPICE_TOSHIFT_8((x) >> 8) + 8 : _SPICE_TOSHIFT_8(x))
+
+#define _SPICE_POWER2_TO_SHIFT(x) \
+ (((x) & 0xffff0000) ? _SPICE_TOSHIFT_16((x) >> 16) + 16 : _SPICE_TOSHIFT_16(x))
+
+
+
+#define SPICE_RING_DECLARE(name, el_type, size) \
+typedef struct SPICE_ATTR_PACKED name##_ring_el { \
+ union { \
+ el_type el; \
+ uint8_t data[_SPICE_POWER2_ALIGN(sizeof(el_type))]; \
+ } ; \
+} name##_ring_el; \
+ \
+typedef struct SPICE_ATTR_PACKED name { \
+ uint32_t num_items; \
+ uint32_t prod; \
+ uint32_t notify_on_prod; \
+ uint32_t cons; \
+ uint32_t notify_on_cons; \
+ name##_ring_el items[_SPICE_POWER2_ALIGN(size)]; \
+} name;
+
+
+#define SPICE_RING_INIT(r) \
+ (r)->num_items = sizeof((r)->items) >> \
+ _SPICE_POWER2_TO_SHIFT(sizeof((r)->items[0])); \
+ (r)->prod = (r)->cons = 0; \
+ (r)->notify_on_prod = 1; \
+ (r)->notify_on_cons = 0;
+
+
+#define SPICE_RING_INDEX_MASK(r) ((r)->num_items - 1)
+
+#define SPICE_RING_IS_PACKED(r) (sizeof((r)->items[0]) == sizeof((r)->items[0]).el)
+
+#define SPICE_RING_IS_EMPTY(r) ((r)->cons == (r)->prod)
+
+#define SPICE_RING_IS_FULL(r) (((r)->prod - (r)->cons) == (r)->num_items)
+
+#define SPICE_RING_PROD_ITEM(r) (&(r)->items[(r)->prod & SPICE_RING_INDEX_MASK(r)].el)
+
+#define SPICE_RING_PROD_WAIT(r, wait) \
+ if (((wait) = SPICE_RING_IS_FULL(r))) { \
+ (r)->notify_on_cons = (r)->cons + 1; \
+ spice_mb(); \
+ (wait) = SPICE_RING_IS_FULL(r); \
+ }
+
+#define SPICE_RING_PUSH(r, notify) \
+ (r)->prod++; \
+ spice_mb(); \
+ (notify) = ((r)->prod == (r)->notify_on_prod);
+
+
+#define SPICE_RING_CONS_ITEM(r) (&(r)->items[(r)->cons & SPICE_RING_INDEX_MASK(r)].el)
+
+#define SPICE_RING_CONS_WAIT(r, wait) \
+ if (((wait) = SPICE_RING_IS_EMPTY(r))) { \
+ (r)->notify_on_prod = (r)->prod + 1; \
+ spice_mb(); \
+ (wait) = SPICE_RING_IS_EMPTY(r); \
+ }
+
+#define SPICE_RING_POP(r, notify) \
+ (r)->cons++; \
+ spice_mb(); \
+ (notify) = ((r)->cons == (r)->notify_on_cons);
+
+
+
+#endif /* _H_SPICE_RING */
diff --git a/qxldod/include/qxl_dev.h b/qxldod/include/qxl_dev.h
new file mode 100755
index 0000000..10cf363
--- /dev/null
+++ b/qxldod/include/qxl_dev.h
@@ -0,0 +1,808 @@
+/*
+ Copyright (C) 2009 Red Hat, Inc.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS
+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef _H_QXL_DEV
+#define _H_QXL_DEV
+
+//#include <spice/types.h>
+#include "barrier.h"
+#include "ipc_ring.h"
+#include "enums.h"
+
+//
+#include "start-packed.h"
+#include "stdint.h"
+
+
+#define CopyRectPoint(dest, src, width, height) \
+ (dest)->left = (src)->x; \
+ (dest)->right = (src)->x + width; \
+ (dest)->top = (src)->y; \
+ (dest)->bottom = (src)->y + height;
+
+#define CopyRect(dest, src) \
+ (dest)->top = (src)->top; \
+ (dest)->left = (src)->left; \
+ (dest)->bottom = (src)->bottom; \
+ (dest)->right = (src)->right;
+
+#define CopyPoint(dest, src) \
+ (dest)->x = (src)->x; \
+ (dest)->y = (src)->y;
+
+
+#define REDHAT_PCI_VENDOR_ID 0x1b36
+
+/* 0x100-0x11f reserved for spice, 0x1ff used for unstable work */
+#define QXL_DEVICE_ID_STABLE 0x0100
+
+enum {
+ QXL_REVISION_STABLE_V04=0x01,
+ QXL_REVISION_STABLE_V06=0x02,
+ QXL_REVISION_STABLE_V10=0x03,
+ QXL_REVISION_STABLE_V12=0x04,
+};
+
+#define QXL_DEVICE_ID_DEVEL 0x01ff
+#define QXL_REVISION_DEVEL 0x01
+
+#define QXL_ROM_MAGIC (*(const uint32_t*)"QXRO")
+#define QXL_RAM_MAGIC (*(const uint32_t*)"QXRA")
+
+enum {
+ QXL_RAM_RANGE_INDEX,
+ QXL_VRAM_RANGE_INDEX,
+ QXL_ROM_RANGE_INDEX,
+ QXL_IO_RANGE_INDEX,
+
+ QXL_PCI_RANGES
+};
+
+/* qxl-1 compat: append only */
+enum {
+ QXL_IO_NOTIFY_CMD,
+ QXL_IO_NOTIFY_CURSOR,
+ QXL_IO_UPDATE_AREA,
+ QXL_IO_UPDATE_IRQ,
+ QXL_IO_NOTIFY_OOM,
+ QXL_IO_RESET,
+ QXL_IO_SET_MODE, /* qxl-1 */
+ QXL_IO_LOG,
+ /* appended for qxl-2 */
+ QXL_IO_MEMSLOT_ADD,
+ QXL_IO_MEMSLOT_DEL,
+ QXL_IO_DETACH_PRIMARY,
+ QXL_IO_ATTACH_PRIMARY,
+ QXL_IO_CREATE_PRIMARY,
+ QXL_IO_DESTROY_PRIMARY,
+ QXL_IO_DESTROY_SURFACE_WAIT,
+ QXL_IO_DESTROY_ALL_SURFACES,
+ /* appended for qxl-3 */
+ QXL_IO_UPDATE_AREA_ASYNC,
+ QXL_IO_MEMSLOT_ADD_ASYNC,
+ QXL_IO_CREATE_PRIMARY_ASYNC,
+ QXL_IO_DESTROY_PRIMARY_ASYNC,
+ QXL_IO_DESTROY_SURFACE_ASYNC,
+ QXL_IO_DESTROY_ALL_SURFACES_ASYNC,
+ QXL_IO_FLUSH_SURFACES_ASYNC,
+ QXL_IO_FLUSH_RELEASE,
+ /* appended for qxl-4 */
+ QXL_IO_MONITORS_CONFIG_ASYNC,
+
+ QXL_IO_RANGE_SIZE
+};
+
+typedef uint64_t QXLPHYSICAL;
+typedef int32_t QXLFIXED; //fixed 28.4
+
+//typedef struct SPICE_ATTR_PACKED QXLPointFix {
+typedef struct SPICE_ATTR_PACKED QXLPointFix {
+ QXLFIXED x;
+ QXLFIXED y;
+} QXLPointFix;
+
+typedef struct SPICE_ATTR_PACKED QXLPoint {
+ int32_t x;
+ int32_t y;
+} QXLPoint;
+
+typedef struct SPICE_ATTR_PACKED QXLPoint16 {
+ int16_t x;
+ int16_t y;
+} QXLPoint16;
+
+typedef struct SPICE_ATTR_PACKED QXLRect {
+ int32_t top;
+ int32_t left;
+ int32_t bottom;
+ int32_t right;
+} QXLRect;
+
+typedef struct SPICE_ATTR_PACKED QXLURect {
+ uint32_t top;
+ uint32_t left;
+ uint32_t bottom;
+ uint32_t right;
+} QXLURect;
+
+/* qxl-1 compat: append only */
+typedef struct SPICE_ATTR_PACKED QXLRom {
+ uint32_t magic;
+ uint32_t id;
+ uint32_t update_id;
+ uint32_t compression_level;
+ uint32_t log_level;
+ uint32_t mode; /* qxl-1 */
+ uint32_t modes_offset;
+ uint32_t num_pages;
+ uint32_t pages_offset; /* qxl-1 */
+ uint32_t draw_area_offset; /* qxl-1 */
+ uint32_t surface0_area_size; /* qxl-1 name: draw_area_size */
+ uint32_t ram_header_offset;
+ uint32_t mm_clock;
+ /* appended for qxl-2 */
+ uint32_t n_surfaces;
+ uint64_t flags;
+ uint8_t slots_start;
+ uint8_t slots_end;
+ uint8_t slot_gen_bits;
+ uint8_t slot_id_bits;
+ uint8_t slot_generation;
+ /* appended for qxl-4 */
+ uint8_t client_present;
+ uint8_t client_capabilities[58];
+ uint32_t client_monitors_config_crc;
+ struct {
+ uint16_t count;
+ uint16_t padding;
+ QXLURect heads[64];
+ } client_monitors_config;
+} QXLRom;
+
+#define CLIENT_MONITORS_CONFIG_CRC32_POLY 0xedb88320
+
+/* qxl-1 compat: fixed */
+typedef struct SPICE_ATTR_PACKED QXLMode {
+ uint32_t id;
+ uint32_t x_res;
+ uint32_t y_res;
+ uint32_t bits;
+ uint32_t stride;
+ uint32_t x_mili;
+ uint32_t y_mili;
+ uint32_t orientation;
+} QXLMode;
+
+/* qxl-1 compat: fixed */
+typedef struct SPICE_ATTR_PACKED QXLModes {
+ uint32_t n_modes;
+ QXLMode modes[0];
+} QXLModes;
+
+/* qxl-1 compat: append only */
+typedef enum QXLCmdType {
+ QXL_CMD_NOP,
+ QXL_CMD_DRAW,
+ QXL_CMD_UPDATE,
+ QXL_CMD_CURSOR,
+ QXL_CMD_MESSAGE,
+ QXL_CMD_SURFACE,
+} QXLCmdType;
+
+/* qxl-1 compat: fixed */
+typedef struct SPICE_ATTR_PACKED QXLCommand {
+ QXLPHYSICAL data;
+ uint32_t type;
+ uint32_t padding;
+} QXLCommand;
+
+#define QXL_COMMAND_FLAG_COMPAT (1<<0)
+#define QXL_COMMAND_FLAG_COMPAT_16BPP (2<<0)
+
+typedef struct SPICE_ATTR_PACKED QXLCommandExt {
+ QXLCommand cmd;
+ uint32_t group_id;
+ uint32_t flags;
+} QXLCommandExt;
+
+typedef struct SPICE_ATTR_PACKED QXLMemSlot {
+ uint64_t mem_start;
+ uint64_t mem_end;
+} QXLMemSlot;
+
+#define QXL_SURF_TYPE_PRIMARY 0
+
+#define QXL_SURF_FLAG_KEEP_DATA (1 << 0)
+
+typedef struct SPICE_ATTR_PACKED QXLSurfaceCreate {
+ uint32_t width;
+ uint32_t height;
+ int32_t stride;
+ uint32_t format;
+ uint32_t position;
+ uint32_t mouse_mode;
+ uint32_t flags;
+ uint32_t type;
+ QXLPHYSICAL mem;
+} QXLSurfaceCreate;
+
+#define QXL_COMMAND_RING_SIZE 32
+#define QXL_CURSOR_RING_SIZE 32
+#define QXL_RELEASE_RING_SIZE 8
+
+SPICE_RING_DECLARE(QXLCommandRing, QXLCommand, QXL_COMMAND_RING_SIZE);
+SPICE_RING_DECLARE(QXLCursorRing, QXLCommand, QXL_CURSOR_RING_SIZE);
+
+SPICE_RING_DECLARE(QXLReleaseRing, uint64_t, QXL_RELEASE_RING_SIZE);
+
+#define QXL_LOG_BUF_SIZE 4096
+
+#define QXL_INTERRUPT_DISPLAY (1 << 0)
+#define QXL_INTERRUPT_CURSOR (1 << 1)
+#define QXL_INTERRUPT_IO_CMD (1 << 2)
+#define QXL_INTERRUPT_ERROR (1 << 3)
+#define QXL_INTERRUPT_CLIENT (1 << 4)
+#define QXL_INTERRUPT_CLIENT_MONITORS_CONFIG (1 << 5)
+
+#define QXL_INTERRUPT_MASK (\
+ QXL_INTERRUPT_DISPLAY |\
+ QXL_INTERRUPT_CURSOR |\
+ QXL_INTERRUPT_IO_CMD |\
+ QXL_INTERRUPT_CLIENT_MONITORS_CONFIG)
+
+/* qxl-1 compat: append only */
+typedef struct SPICE_ATTR_PACKED QXLRam {
+ uint32_t magic;
+ uint32_t int_pending;
+ uint32_t int_mask;
+ uint8_t log_buf[QXL_LOG_BUF_SIZE];
+ QXLCommandRing cmd_ring;
+ QXLCursorRing cursor_ring;
+ QXLReleaseRing release_ring;
+ QXLRect update_area;
+ /* appended for qxl-2 */
+ uint32_t update_surface;
+ QXLMemSlot mem_slot;
+ QXLSurfaceCreate create_surface;
+ uint64_t flags;
+
+ /* appended for qxl-4 */
+
+ /* used by QXL_IO_MONITORS_CONFIG_ASYNC */
+ QXLPHYSICAL monitors_config;
+
+} QXLRam;
+
+typedef union QXLReleaseInfo {
+ uint64_t id; // in
+ uint64_t next; // out
+} QXLReleaseInfo;
+
+typedef struct QXLReleaseInfoExt {
+ QXLReleaseInfo *info;
+ uint32_t group_id;
+} QXLReleaseInfoExt;
+
+typedef struct SPICE_ATTR_PACKED QXLDataChunk {
+ uint32_t data_size;
+ QXLPHYSICAL prev_chunk;
+ QXLPHYSICAL next_chunk;
+ uint8_t data[0];
+} QXLDataChunk;
+
+typedef struct SPICE_ATTR_PACKED QXLMessage {
+ QXLReleaseInfo release_info;
+ uint8_t data[0];
+} QXLMessage;
+
+typedef struct SPICE_ATTR_PACKED QXLCompatUpdateCmd {
+ QXLReleaseInfo release_info;
+ QXLRect area;
+ uint32_t update_id;
+} QXLCompatUpdateCmd;
+
+typedef struct SPICE_ATTR_PACKED QXLUpdateCmd {
+ QXLReleaseInfo release_info;
+ QXLRect area;
+ uint32_t update_id;
+ uint32_t surface_id;
+} QXLUpdateCmd;
+
+typedef struct SPICE_ATTR_PACKED QXLCursorHeader {
+ uint64_t unique;
+ uint16_t type;
+ uint16_t width;
+ uint16_t height;
+ uint16_t hot_spot_x;
+ uint16_t hot_spot_y;
+} QXLCursorHeader;
+
+typedef struct SPICE_ATTR_PACKED QXLCursor {
+ QXLCursorHeader header;
+ uint32_t data_size;
+ QXLDataChunk chunk;
+} QXLCursor;
+
+enum {
+ QXL_CURSOR_SET,
+ QXL_CURSOR_MOVE,
+ QXL_CURSOR_HIDE,
+ QXL_CURSOR_TRAIL,
+};
+
+#define QXL_CURSUR_DEVICE_DATA_SIZE 128
+
+typedef struct SPICE_ATTR_PACKED QXLCursorCmd {
+ QXLReleaseInfo release_info;
+ uint8_t type;
+ union {
+ struct SPICE_ATTR_PACKED {
+ QXLPoint16 position;
+ uint8_t visible;
+ QXLPHYSICAL shape;
+ } set;
+ struct SPICE_ATTR_PACKED {
+ uint16_t length;
+ uint16_t frequency;
+ } trail;
+ QXLPoint16 position;
+ } u;
+ uint8_t device_data[QXL_CURSUR_DEVICE_DATA_SIZE]; //todo: dynamic size from rom
+} QXLCursorCmd;
+
+enum {
+ QXL_DRAW_NOP,
+ QXL_DRAW_FILL,
+ QXL_DRAW_OPAQUE,
+ QXL_DRAW_COPY,
+ QXL_COPY_BITS,
+ QXL_DRAW_BLEND,
+ QXL_DRAW_BLACKNESS,
+ QXL_DRAW_WHITENESS,
+ QXL_DRAW_INVERS,
+ QXL_DRAW_ROP3,
+ QXL_DRAW_STROKE,
+ QXL_DRAW_TEXT,
+ QXL_DRAW_TRANSPARENT,
+ QXL_DRAW_ALPHA_BLEND,
+ QXL_DRAW_COMPOSITE
+};
+
+typedef struct SPICE_ATTR_PACKED QXLRasterGlyph {
+ QXLPoint render_pos;
+ QXLPoint glyph_origin;
+ uint16_t width;
+ uint16_t height;
+ uint8_t data[0];
+} QXLRasterGlyph;
+
+typedef struct SPICE_ATTR_PACKED QXLString {
+ uint32_t data_size;
+ uint16_t length;
+ uint16_t flags;
+ QXLDataChunk chunk;
+} QXLString;
+
+typedef struct SPICE_ATTR_PACKED QXLCopyBits {
+ QXLPoint src_pos;
+} QXLCopyBits;
+
+typedef enum QXLEffectType
+{
+ QXL_EFFECT_BLEND = 0,
+ QXL_EFFECT_OPAQUE = 1,
+ QXL_EFFECT_REVERT_ON_DUP = 2,
+ QXL_EFFECT_BLACKNESS_ON_DUP = 3,
+ QXL_EFFECT_WHITENESS_ON_DUP = 4,
+ QXL_EFFECT_NOP_ON_DUP = 5,
+ QXL_EFFECT_NOP = 6,
+ QXL_EFFECT_OPAQUE_BRUSH = 7
+} QXLEffectType;
+
+typedef struct SPICE_ATTR_PACKED QXLPattern {
+ QXLPHYSICAL pat;
+ QXLPoint pos;
+} QXLPattern;
+
+typedef struct SPICE_ATTR_PACKED QXLBrush {
+ uint32_t type;
+ union {
+ uint32_t color;
+ QXLPattern pattern;
+ } u;
+} QXLBrush;
+
+typedef struct SPICE_ATTR_PACKED QXLQMask {
+ uint8_t flags;
+ QXLPoint pos;
+ QXLPHYSICAL bitmap;
+} QXLQMask;
+
+typedef struct SPICE_ATTR_PACKED QXLFill {
+ QXLBrush brush;
+ uint16_t rop_descriptor;
+ QXLQMask mask;
+} QXLFill;
+
+typedef struct SPICE_ATTR_PACKED QXLOpaque {
+ QXLPHYSICAL src_bitmap;
+ QXLRect src_area;
+ QXLBrush brush;
+ uint16_t rop_descriptor;
+ uint8_t scale_mode;
+ QXLQMask mask;
+} QXLOpaque;
+
+typedef struct SPICE_ATTR_PACKED QXLCopy {
+ QXLPHYSICAL src_bitmap;
+ QXLRect src_area;
+ uint16_t rop_descriptor;
+ uint8_t scale_mode;
+ QXLQMask mask;
+} QXLCopy, QXLBlend;
+
+typedef struct SPICE_ATTR_PACKED QXLTransparent {
+ QXLPHYSICAL src_bitmap;
+ QXLRect src_area;
+ uint32_t src_color;
+ uint32_t true_color;
+} QXLTransparent;
+
+typedef struct SPICE_ATTR_PACKED QXLAlphaBlend {
+ uint16_t alpha_flags;
+ uint8_t alpha;
+ QXLPHYSICAL src_bitmap;
+ QXLRect src_area;
+} QXLAlphaBlend;
+
+typedef struct SPICE_ATTR_PACKED QXLCompatAlphaBlend {
+ uint8_t alpha;
+ QXLPHYSICAL src_bitmap;
+ QXLRect src_area;
+} QXLCompatAlphaBlend;
+
+typedef struct SPICE_ATTR_PACKED QXLRop3 {
+ QXLPHYSICAL src_bitmap;
+ QXLRect src_area;
+ QXLBrush brush;
+ uint8_t rop3;
+ uint8_t scale_mode;
+ QXLQMask mask;
+} QXLRop3;
+
+typedef struct SPICE_ATTR_PACKED QXLLineAttr {
+ uint8_t flags;
+ uint8_t join_style;
+ uint8_t end_style;
+ uint8_t style_nseg;
+ QXLFIXED width;
+ QXLFIXED miter_limit;
+ QXLPHYSICAL style;
+} QXLLineAttr;
+
+typedef struct SPICE_ATTR_PACKED QXLStroke {
+ QXLPHYSICAL path;
+ QXLLineAttr attr;
+ QXLBrush brush;
+ uint16_t fore_mode;
+ uint16_t back_mode;
+} QXLStroke;
+
+typedef struct SPICE_ATTR_PACKED QXLText {
+ QXLPHYSICAL str;
+ QXLRect back_area;
+ QXLBrush fore_brush;
+ QXLBrush back_brush;
+ uint16_t fore_mode;
+ uint16_t back_mode;
+} QXLText;
+
+typedef struct SPICE_ATTR_PACKED QXLBlackness {
+ QXLQMask mask;
+} QXLBlackness, QXLInvers, QXLWhiteness;
+
+typedef struct SPICE_ATTR_PACKED QXLClip {
+ uint32_t type;
+ QXLPHYSICAL data;
+} QXLClip;
+
+typedef enum {
+ QXL_OP_CLEAR = 0x00,
+ QXL_OP_SOURCE = 0x01,
+ QXL_OP_DST = 0x02,
+ QXL_OP_OVER = 0x03,
+ QXL_OP_OVER_REVERSE = 0x04,
+ QXL_OP_IN = 0x05,
+ QXL_OP_IN_REVERSE = 0x06,
+ QXL_OP_OUT = 0x07,
+ QXL_OP_OUT_REVERSE = 0x08,
+ QXL_OP_ATOP = 0x09,
+ QXL_OP_ATOP_REVERSE = 0x0a,
+ QXL_OP_XOR = 0x0b,
+ QXL_OP_ADD = 0x0c,
+ QXL_OP_SATURATE = 0x0d,
+ /* Note the jump here from 0x0d to 0x30 */
+ QXL_OP_MULTIPLY = 0x30,
+ QXL_OP_SCREEN = 0x31,
+ QXL_OP_OVERLAY = 0x32,
+ QXL_OP_DARKEN = 0x33,
+ QXL_OP_LIGHTEN = 0x34,
+ QXL_OP_COLOR_DODGE = 0x35,
+ QXL_OP_COLOR_BURN = 0x36,
+ QXL_OP_HARD_LIGHT = 0x37,
+ QXL_OP_SOFT_LIGHT = 0x38,
+ QXL_OP_DIFFERENCE = 0x39,
+ QXL_OP_EXCLUSION = 0x3a,
+ QXL_OP_HSL_HUE = 0x3b,
+ QXL_OP_HSL_SATURATION = 0x3c,
+ QXL_OP_HSL_COLOR = 0x3d,
+ QXL_OP_HSL_LUMINOSITY = 0x3e
+} QXLOperator;
+
+typedef struct {
+ uint32_t t00;
+ uint32_t t01;
+ uint32_t t02;
+ uint32_t t10;
+ uint32_t t11;
+ uint32_t t12;
+} QXLTransform;
+
+/* The flags field has the following bit fields:
+ *
+ * operator: [ 0 - 7 ]
+ * src_filter: [ 8 - 10 ]
+ * mask_filter: [ 11 - 13 ]
+ * src_repeat: [ 14 - 15 ]
+ * mask_repeat: [ 16 - 17 ]
+ * component_alpha: [ 18 - 18 ]
+ * reserved: [ 19 - 31 ]
+ *
+ * The repeat and filter values are those of pixman:
+ * REPEAT_NONE = 0
+ * REPEAT_NORMAL = 1
+ * REPEAT_PAD = 2
+ * REPEAT_REFLECT = 3
+ *
+ * The filter values are:
+ * FILTER_NEAREST = 0
+ * FILTER_BILINEAR = 1
+ */
+typedef struct SPICE_ATTR_PACKED QXLComposite {
+ uint32_t flags;
+
+ QXLPHYSICAL src;
+ QXLPHYSICAL src_transform; /* May be NULL */
+ QXLPHYSICAL mask; /* May be NULL */
+ QXLPHYSICAL mask_transform; /* May be NULL */
+ QXLPoint16 src_origin;
+ QXLPoint16 mask_origin;
+} QXLComposite;
+
+typedef struct SPICE_ATTR_PACKED QXLCompatDrawable {
+ QXLReleaseInfo release_info;
+ uint8_t effect;
+ uint8_t type;
+ uint16_t bitmap_offset;
+ QXLRect bitmap_area;
+ QXLRect bbox;
+ QXLClip clip;
+ uint32_t mm_time;
+ union {
+ QXLFill fill;
+ QXLOpaque opaque;
+ QXLCopy copy;
+ QXLTransparent transparent;
+ QXLCompatAlphaBlend alpha_blend;
+ QXLCopyBits copy_bits;
+ QXLBlend blend;
+ QXLRop3 rop3;
+ QXLStroke stroke;
+ QXLText text;
+ QXLBlackness blackness;
+ QXLInvers invers;
+ QXLWhiteness whiteness;
+ } u;
+} QXLCompatDrawable;
+
+typedef struct SPICE_ATTR_PACKED QXLDrawable {
+ QXLReleaseInfo release_info;
+ uint32_t surface_id;
+ uint8_t effect;
+ uint8_t type;
+ uint8_t self_bitmap;
+ QXLRect self_bitmap_area;
+ QXLRect bbox;
+ QXLClip clip;
+ uint32_t mm_time;
+ int32_t surfaces_dest[3];
+ QXLRect surfaces_rects[3];
+ union {
+ QXLFill fill;
+ QXLOpaque opaque;
+ QXLCopy copy;
+ QXLTransparent transparent;
+ QXLAlphaBlend alpha_blend;
+ QXLCopyBits copy_bits;
+ QXLBlend blend;
+ QXLRop3 rop3;
+ QXLStroke stroke;
+ QXLText text;
+ QXLBlackness blackness;
+ QXLInvers invers;
+ QXLWhiteness whiteness;
+ QXLComposite composite;
+ } u;
+} QXLDrawable;
+
+typedef enum QXLSurfaceCmdType {
+ QXL_SURFACE_CMD_CREATE,
+ QXL_SURFACE_CMD_DESTROY,
+} QXLSurfaceCmdType;
+
+typedef struct SPICE_ATTR_PACKED QXLSurface {
+ uint32_t format;
+ uint32_t width;
+ uint32_t height;
+ int32_t stride;
+ QXLPHYSICAL data;
+} QXLSurface;
+
+typedef struct SPICE_ATTR_PACKED QXLSurfaceCmd {
+ QXLReleaseInfo release_info;
+ uint32_t surface_id;
+ uint8_t type;
+ uint32_t flags;
+ union {
+ QXLSurface surface_create;
+ } u;
+} QXLSurfaceCmd;
+
+typedef struct SPICE_ATTR_PACKED QXLClipRects {
+ uint32_t num_rects;
+ QXLDataChunk chunk;
+} QXLClipRects;
+
+enum {
+ QXL_PATH_BEGIN = (1 << 0),
+ QXL_PATH_END = (1 << 1),
+ QXL_PATH_CLOSE = (1 << 3),
+ QXL_PATH_BEZIER = (1 << 4),
+};
+
+typedef struct SPICE_ATTR_PACKED QXLPathSeg {
+ uint32_t flags;
+ uint32_t count;
+ QXLPointFix points[0];
+} QXLPathSeg;
+
+typedef struct SPICE_ATTR_PACKED QXLPath {
+ uint32_t data_size;
+ QXLDataChunk chunk;
+} QXLPath;
+
+enum {
+ QXL_IMAGE_GROUP_DRIVER,
+ QXL_IMAGE_GROUP_DEVICE,
+ QXL_IMAGE_GROUP_RED,
+ QXL_IMAGE_GROUP_DRIVER_DONT_CACHE,
+};
+
+typedef struct SPICE_ATTR_PACKED QXLImageID {
+ uint32_t group;
+ uint32_t unique;
+} QXLImageID;
+
+typedef union {
+ QXLImageID id;
+ uint64_t value;
+} QXLImageIDUnion;
+
+typedef enum QXLImageFlags {
+ QXL_IMAGE_CACHE = (1 << 0),
+ QXL_IMAGE_HIGH_BITS_SET = (1 << 1),
+} QXLImageFlags;
+
+typedef enum QXLBitmapFlags {
+ QXL_BITMAP_DIRECT = (1 << 0),
+ QXL_BITMAP_UNSTABLE = (1 << 1),
+ QXL_BITMAP_TOP_DOWN = (1 << 2), // == SPICE_BITMAP_FLAGS_TOP_DOWN
+} QXLBitmapFlags;
+
+#define QXL_SET_IMAGE_ID(image, _group, _unique) { \
+ (image)->descriptor.id = (((uint64_t)_unique) << 32) | _group; \
+}
+
+typedef struct SPICE_ATTR_PACKED QXLImageDescriptor {
+ uint64_t id;
+ uint8_t type;
+ uint8_t flags;
+ uint32_t width;
+ uint32_t height;
+} QXLImageDescriptor;
+
+typedef struct SPICE_ATTR_PACKED QXLPalette {
+ uint64_t unique;
+ uint16_t num_ents;
+ uint32_t ents[0];
+} QXLPalette;
+
+typedef struct SPICE_ATTR_PACKED QXLBitmap {
+ uint8_t format;
+ uint8_t flags;
+ uint32_t x;
+ uint32_t y;
+ uint32_t stride;
+ QXLPHYSICAL palette;
+ QXLPHYSICAL data; //data[0] ?
+} QXLBitmap;
+
+typedef struct SPICE_ATTR_PACKED QXLSurfaceId {
+ uint32_t surface_id;
+} QXLSurfaceId;
+
+typedef struct SPICE_ATTR_PACKED QXLQUICData {
+ uint32_t data_size;
+ uint8_t data[0];
+} QXLQUICData, QXLLZRGBData, QXLJPEGData;
+
+typedef struct SPICE_ATTR_PACKED QXLImage {
+ QXLImageDescriptor descriptor;
+ union { // variable length
+ QXLBitmap bitmap;
+ QXLQUICData quic;
+ QXLSurfaceId surface_image;
+ };
+} QXLImage;
+
+/* A QXLHead is a single monitor output backed by a QXLSurface.
+ * x and y offsets are unsigned since they are used in relation to
+ * the given surface, not the same as the x, y coordinates in the guest
+ * screen reference frame. */
+typedef struct SPICE_ATTR_PACKED QXLHead {
+ uint32_t id;
+ uint32_t surface_id;
+ uint32_t width;
+ uint32_t height;
+ uint32_t x;
+ uint32_t y;
+ uint32_t flags;
+} QXLHead;
+
+typedef struct SPICE_ATTR_PACKED QXLMonitorsConfig {
+ uint16_t count;
+ uint16_t max_allowed; /* If it is 0 no fixed limit is given by the driver */
+ QXLHead heads[0];
+} QXLMonitorsConfig;
+
+#include "include/end-packed.h"
+
+#endif /* _H_QXL_DEV */
diff --git a/qxldod/include/start-packed.h b/qxldod/include/start-packed.h
new file mode 100755
index 0000000..ab3fa98
--- /dev/null
+++ b/qxldod/include/start-packed.h
@@ -0,0 +1,64 @@
+/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ Copyright (C) 2009 Red Hat, Inc.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS
+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* Ideally this should all have been macros in a common headers, but
+ * its not possible to put pragmas into header files, so we have
+ * to use include magic.
+ *
+ * Use it like this:
+ *
+ * #include <spice/start-packed.h>
+ *
+ * typedef struct SPICE_ATTR_PACKED {
+ * ...
+ * } Type;
+ *
+ * #include <spice/end-packed.h>
+ *
+ */
+
+#ifdef __GNUC__
+
+#define SPICE_ATTR_PACKED __attribute__ ((__packed__))
+
+#ifdef __MINGW32__
+#pragma pack(push,1)
+#endif
+
+#else
+
+#pragma pack(push)
+#pragma pack(1)
+#define SPICE_ATTR_PACKED
+#pragma warning(disable:4200)
+#pragma warning(disable:4103)
+
+#endif
diff --git a/qxldod/include/stdint.h b/qxldod/include/stdint.h
new file mode 100755
index 0000000..f825d4b
--- /dev/null
+++ b/qxldod/include/stdint.h
@@ -0,0 +1,397 @@
+/* ISO C9x 7.18 Integer types <stdint.h>
+
+ * Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794)
+
+ *
+
+ * THIS SOFTWARE IS NOT COPYRIGHTED
+
+ *
+
+ * Contributor: Danny Smith <danny_r_smith_2001@yahoo.co.nz>
+
+ *
+
+ * This source code is offered for use in the public domain. You may
+
+ * use, modify or distribute it freely.
+
+ *
+
+ * This code is distributed in the hope that it will be useful but
+
+ * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+
+ * DISCLAIMED. This includes but is not limited to warranties of
+
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ *
+
+ * Date: 2000-12-02
+
+ */
+
+
+
+
+
+#ifndef _STDINT_H
+
+#define _STDINT_H
+
+#define __need_wint_t
+
+#define __need_wchar_t
+
+#include <stddef.h>
+
+
+
+#ifdef _WIN32_WCE
+
+typedef _int64 int64_t;
+
+typedef unsigned _int64 uint64_t;
+
+#else
+
+typedef long long int64_t;
+
+typedef unsigned long long uint64_t;
+
+#endif /* _WIN32_WCE */
+
+
+
+/* 7.18.1.1 Exact-width integer types */
+
+typedef signed char int8_t;
+
+typedef unsigned char uint8_t;
+
+typedef short int16_t;
+
+typedef unsigned short uint16_t;
+
+typedef int int32_t;
+
+typedef unsigned uint32_t;
+
+
+
+/* 7.18.1.2 Minimum-width integer types */
+
+typedef signed char int_least8_t;
+
+typedef unsigned char uint_least8_t;
+
+typedef short int_least16_t;
+
+typedef unsigned short uint_least16_t;
+
+typedef int int_least32_t;
+
+typedef unsigned uint_least32_t;
+
+#ifndef _WIN32_WCE
+
+typedef long long int_least64_t;
+
+typedef unsigned long long uint_least64_t;
+
+#endif
+
+
+
+/* 7.18.1.3 Fastest minimum-width integer types
+
+ * Not actually guaranteed to be fastest for all purposes
+
+ * Here we use the exact-width types for 8 and 16-bit ints.
+
+ */
+
+typedef char int_fast8_t;
+
+typedef unsigned char uint_fast8_t;
+
+typedef short int_fast16_t;
+
+typedef unsigned short uint_fast16_t;
+
+typedef int int_fast32_t;
+
+typedef unsigned int uint_fast32_t;
+
+#ifndef _WIN32_WCE
+
+typedef long long int_fast64_t;
+
+typedef unsigned long long uint_fast64_t;
+
+#endif
+
+
+
+/* 7.18.1.4 Integer types capable of holding object pointers */
+
+#ifndef _WIN64
+
+typedef int intptr_t;
+
+typedef unsigned uintptr_t;
+
+#endif
+
+/* 7.18.1.5 Greatest-width integer types */
+
+#ifndef _WIN32_WCE
+
+typedef long long intmax_t;
+
+typedef unsigned long long uintmax_t;
+
+#endif
+
+
+
+/* 7.18.2 Limits of specified-width integer types */
+
+#if !defined ( __cplusplus) || defined (__STDC_LIMIT_MACROS)
+
+
+
+/* 7.18.2.1 Limits of exact-width integer types */
+
+#define INT8_MIN (-128)
+
+#define INT16_MIN (-32768)
+
+#define INT32_MIN (-2147483647 - 1)
+
+#define INT64_MIN (-9223372036854775807LL - 1)
+
+
+
+#define INT8_MAX 127
+
+#define INT16_MAX 32767
+
+#define INT32_MAX 2147483647
+
+#define INT64_MAX 9223372036854775807LL
+
+
+
+#define UINT8_MAX 0xff /* 255U */
+
+#define UINT16_MAX 0xffff /* 65535U */
+
+#define UINT32_MAX 0xffffffff /* 4294967295U */
+
+#define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */
+
+
+
+/* 7.18.2.2 Limits of minimum-width integer types */
+
+#define INT_LEAST8_MIN INT8_MIN
+
+#define INT_LEAST16_MIN INT16_MIN
+
+#define INT_LEAST32_MIN INT32_MIN
+
+#define INT_LEAST64_MIN INT64_MIN
+
+
+
+#define INT_LEAST8_MAX INT8_MAX
+
+#define INT_LEAST16_MAX INT16_MAX
+
+#define INT_LEAST32_MAX INT32_MAX
+
+#define INT_LEAST64_MAX INT64_MAX
+
+
+
+#define UINT_LEAST8_MAX UINT8_MAX
+
+#define UINT_LEAST16_MAX UINT16_MAX
+
+#define UINT_LEAST32_MAX UINT32_MAX
+
+#define UINT_LEAST64_MAX UINT64_MAX
+
+
+
+/* 7.18.2.3 Limits of fastest minimum-width integer types */
+
+#define INT_FAST8_MIN INT8_MIN
+
+#define INT_FAST16_MIN INT16_MIN
+
+#define INT_FAST32_MIN INT32_MIN
+
+#define INT_FAST64_MIN INT64_MIN
+
+
+
+#define INT_FAST8_MAX INT8_MAX
+
+#define INT_FAST16_MAX INT16_MAX
+
+#define INT_FAST32_MAX INT32_MAX
+
+#define INT_FAST64_MAX INT64_MAX
+
+
+
+#define UINT_FAST8_MAX UINT8_MAX
+
+#define UINT_FAST16_MAX UINT16_MAX
+
+#define UINT_FAST32_MAX UINT32_MAX
+
+#define UINT_FAST64_MAX UINT64_MAX
+
+
+
+/* 7.18.2.4 Limits of integer types capable of holding
+
+ object pointers */
+
+#define INTPTR_MIN INT32_MIN
+
+#define INTPTR_MAX INT32_MAX
+
+#define UINTPTR_MAX UINT32_MAX
+
+
+
+/* 7.18.2.5 Limits of greatest-width integer types */
+
+#define INTMAX_MIN INT64_MIN
+
+#define INTMAX_MAX INT64_MAX
+
+#define UINTMAX_MAX UINT64_MAX
+
+
+
+/* 7.18.3 Limits of other integer types */
+
+#define PTRDIFF_MIN INT32_MIN
+
+#define PTRDIFF_MAX INT32_MAX
+
+
+
+#define SIG_ATOMIC_MIN INT32_MIN
+
+#define SIG_ATOMIC_MAX INT32_MAX
+
+
+
+#ifndef SIZE_MAX
+#define SIZE_MAX UINT32_MAX
+#endif
+
+
+#ifndef WCHAR_MIN /* also in wchar.h */
+
+#define WCHAR_MIN 0
+
+#define WCHAR_MAX 0xffff /* UINT16_MAX */
+
+#endif
+
+
+
+/*
+
+ * wint_t is unsigned short for compatibility with MS runtime
+
+ */
+
+#define WINT_MIN 0
+
+#define WINT_MAX 0xffff /* UINT16_MAX */
+
+
+
+#endif /* !defined ( __cplusplus) || defined __STDC_LIMIT_MACROS */
+
+
+
+
+
+/* 7.18.4 Macros for integer constants */
+
+#if !defined ( __cplusplus) || defined (__STDC_CONSTANT_MACROS)
+
+
+
+/* 7.18.4.1 Macros for minimum-width integer constants
+
+
+
+ Accoding to Douglas Gwyn <gwyn@arl.mil>:
+
+ "This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC
+
+ 9899:1999 as initially published, the expansion was required
+
+ to be an integer constant of precisely matching type, which
+
+ is impossible to accomplish for the shorter types on most
+
+ platforms, because C99 provides no standard way to designate
+
+ an integer constant with width less than that of type int.
+
+ TC1 changed this to require just an integer constant
+
+ *expression* with *promoted* type."
+
+*/
+
+
+
+#define INT8_C(val) ((int8_t) + (val))
+
+#define UINT8_C(val) ((uint8_t) + (val##U))
+
+#define INT16_C(val) ((int16_t) + (val))
+
+#define UINT16_C(val) ((uint16_t) + (val##U))
+
+
+
+#define INT32_C(val) val##L
+
+#define UINT32_C(val) val##UL
+
+#define INT64_C(val) val##LL
+
+#define UINT64_C(val) val##ULL
+
+
+
+/* 7.18.4.2 Macros for greatest-width integer constants */
+
+#define INTMAX_C(val) INT64_C(val)
+
+#define UINTMAX_C(val) UINT64_C(val)
+
+
+
+#endif /* !defined ( __cplusplus) || defined __STDC_CONSTANT_MACROS */
+
+
+
+#endif
+
+
+
diff --git a/qxldod/include/types.h b/qxldod/include/types.h
new file mode 100755
index 0000000..b4583c2
--- /dev/null
+++ b/qxldod/include/types.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ Copyright (C) 2009 Red Hat, Inc.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS
+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _H_SPICE_TYPES
+#define _H_SPICE_TYPES
+
+/* We always want the standard int types
+ * If they are not in stdint.h on your system,
+ * include the right one here. */
+#include <include/stdint.h>
+//#include <limits.h>
+
+#endif /* _H_SPICE_TYPES */
diff --git a/qxldod/mspace.c b/qxldod/mspace.c
new file mode 100755
index 0000000..d0ba123
--- /dev/null
+++ b/qxldod/mspace.c
@@ -0,0 +1,2437 @@
+// based on dlmalloc from Doug Lea
+
+
+// quote from the Doug Lea original file
+ /*
+ This is a version (aka dlmalloc) of malloc/free/realloc written by
+ Doug Lea and released to the public domain, as explained at
+ http://creativecommons.org/licenses/publicdomain. Send questions,
+ comments, complaints, performance data, etc to dl@cs.oswego.edu
+
+ * Version 2.8.3 Thu Sep 22 11:16:15 2005 Doug Lea (dl at gee)
+
+ Note: There may be an updated version of this malloc obtainable at
+ ftp://gee.cs.oswego.edu/pub/misc/malloc.c
+ Check before installing!
+ */
+
+
+#include <ntddk.h>
+
+#include "mspace.h"
+
+#pragma warning( disable : 4146 ) /* no "unsigned" warnings */
+
+#define MALLOC_ALIGNMENT ((size_t)8U)
+#define USE_LOCKS 0
+#define malloc_getpagesize ((size_t)4096U)
+#define DEFAULT_GRANULARITY malloc_getpagesize
+#define MAX_SIZE_T (~(size_t)0)
+#define MALLOC_FAILURE_ACTION
+#define MALLINFO_FIELD_TYPE size_t
+#define FOOTERS 0
+#define INSECURE 0
+#define PROCEED_ON_ERROR 0
+#define DEBUG 0
+#define ABORT_ON_ASSERT_FAILURE 1
+#define ABORT(user_data) abort_func(user_data)
+#define USE_BUILTIN_FFS 0
+#define USE_DEV_RANDOM 0
+#define PRINT(params) print_func params
+
+
+#define MEMCPY(dest, src, n) RtlCopyMemory(dest, src, n)
+#define MEMCLEAR(dest, n) RtlZeroMemory(dest, n)
+
+
+#define M_GRANULARITY (-1)
+
+void default_abort_func(void *user_data)
+{
+ for (;;);
+}
+
+void default_print_func(void *user_data, char *format, ...)
+{
+}
+
+static mspace_abort_t abort_func = default_abort_func;
+static mspace_print_t print_func = default_print_func;
+
+void mspace_set_abort_func(mspace_abort_t f)
+{
+ abort_func = f;
+}
+
+void mspace_set_print_func(mspace_print_t f)
+{
+ print_func = f;
+}
+
+/* ------------------------ Mallinfo declarations ------------------------ */
+
+#if !NO_MALLINFO
+/*
+ This version of malloc supports the standard SVID/XPG mallinfo
+ routine that returns a struct containing usage properties and
+ statistics. It should work on any system that has a
+ /usr/include/malloc.h defining struct mallinfo. The main
+ declaration needed is the mallinfo struct that is returned (by-copy)
+ by mallinfo(). The malloinfo struct contains a bunch of fields that
+ are not even meaningful in this version of malloc. These fields are
+ are instead filled by mallinfo() with other numbers that might be of
+ interest.
+
+ HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
+ /usr/include/malloc.h file that includes a declaration of struct
+ mallinfo. If so, it is included; else a compliant version is
+ declared below. These must be precisely the same for mallinfo() to
+ work. The original SVID version of this struct, defined on most
+ systems with mallinfo, declares all fields as ints. But some others
+ define as unsigned long. If your system defines the fields using a
+ type of different width than listed here, you MUST #include your
+ system version and #define HAVE_USR_INCLUDE_MALLOC_H.
+*/
+
+/* #define HAVE_USR_INCLUDE_MALLOC_H */
+
+
+struct mallinfo {
+ MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */
+ MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */
+ MALLINFO_FIELD_TYPE smblks; /* always 0 */
+ MALLINFO_FIELD_TYPE hblks; /* always 0 */
+ MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */
+ MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */
+ MALLINFO_FIELD_TYPE fsmblks; /* always 0 */
+ MALLINFO_FIELD_TYPE uordblks; /* total allocated space */
+ MALLINFO_FIELD_TYPE fordblks; /* total free space */
+ MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */
+};
+
+#endif /* NO_MALLINFO */
+
+
+
+#ifdef DEBUG
+#if ABORT_ON_ASSERT_FAILURE
+#define assert(user_data, x) if(!(x)) ABORT(user_data)
+#else /* ABORT_ON_ASSERT_FAILURE */
+#include <assert.h>
+#endif /* ABORT_ON_ASSERT_FAILURE */
+#else /* DEBUG */
+#define assert(user_data, x)
+#endif /* DEBUG */
+
+/* ------------------- size_t and alignment properties -------------------- */
+
+/* The byte and bit size of a size_t */
+#define SIZE_T_SIZE (sizeof(size_t))
+#define SIZE_T_BITSIZE (sizeof(size_t) << 3)
+
+/* Some constants coerced to size_t */
+/* Annoying but necessary to avoid errors on some plaftorms */
+#define SIZE_T_ZERO ((size_t)0)
+#define SIZE_T_ONE ((size_t)1)
+#define SIZE_T_TWO ((size_t)2)
+#define TWO_SIZE_T_SIZES (SIZE_T_SIZE<<1)
+#define FOUR_SIZE_T_SIZES (SIZE_T_SIZE<<2)
+#define SIX_SIZE_T_SIZES (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES)
+#define HALF_MAX_SIZE_T (MAX_SIZE_T / 2U)
+
+/* The bit mask value corresponding to MALLOC_ALIGNMENT */
+#define CHUNK_ALIGN_MASK (MALLOC_ALIGNMENT - SIZE_T_ONE)
+
+/* True if address a has acceptable alignment */
+#define is_aligned(A) (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0)
+
+/* the number of bytes to offset an address to align it */
+#define align_offset(A)\
+ ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\
+ ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK))
+
+/* --------------------------- Lock preliminaries ------------------------ */
+
+#if USE_LOCKS
+
+/*
+ When locks are defined, there are up to two global locks:
+
+ * If HAVE_MORECORE, morecore_mutex protects sequences of calls to
+ MORECORE. In many cases sys_alloc requires two calls, that should
+ not be interleaved with calls by other threads. This does not
+ protect against direct calls to MORECORE by other threads not
+ using this lock, so there is still code to cope the best we can on
+ interference.
+
+ * magic_init_mutex ensures that mparams.magic and other
+ unique mparams values are initialized only once.
+*/
+
+
+#define USE_LOCK_BIT (2U)
+#else /* USE_LOCKS */
+#define USE_LOCK_BIT (0U)
+#define INITIAL_LOCK(l)
+#endif /* USE_LOCKS */
+
+#if USE_LOCKS
+#define ACQUIRE_MAGIC_INIT_LOCK() ACQUIRE_LOCK(&magic_init_mutex);
+#define RELEASE_MAGIC_INIT_LOCK() RELEASE_LOCK(&magic_init_mutex);
+#else /* USE_LOCKS */
+#define ACQUIRE_MAGIC_INIT_LOCK()
+#define RELEASE_MAGIC_INIT_LOCK()
+#endif /* USE_LOCKS */
+
+
+
+/* ----------------------- Chunk representations ------------------------ */
+
+/*
+ (The following includes lightly edited explanations by Colin Plumb.)
+
+ The malloc_chunk declaration below is misleading (but accurate and
+ necessary). It declares a "view" into memory allowing access to
+ necessary fields at known offsets from a given base.
+
+ Chunks of memory are maintained using a `boundary tag' method as
+ originally described by Knuth. (See the paper by Paul Wilson
+ ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such
+ techniques.) Sizes of free chunks are stored both in the front of
+ each chunk and at the end. This makes consolidating fragmented
+ chunks into bigger chunks fast. The head fields also hold bits
+ representing whether chunks are free or in use.
+
+ Here are some pictures to make it clearer. They are "exploded" to
+ show that the state of a chunk can be thought of as extending from
+ the high 31 bits of the head field of its header through the
+ prev_foot and PINUSE_BIT bit of the following chunk header.
+
+ A chunk that's in use looks like:
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk (if P = 1) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
+ | Size of this chunk 1| +-+
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ +- -+
+ | |
+ +- -+
+ | :
+ +- size - sizeof(size_t) available payload bytes -+
+ : |
+ chunk-> +- -+
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1|
+ | Size of next chunk (may or may not be in use) | +-+
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ And if it's free, it looks like this:
+
+ chunk-> +- -+
+ | User payload (must be in use, or we would have merged!) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
+ | Size of this chunk 0| +-+
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Next pointer |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Prev pointer |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | :
+ +- size - sizeof(struct chunk) unused bytes -+
+ : |
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of this chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0|
+ | Size of next chunk (must be in use, or we would have merged)| +-+
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | :
+ +- User payload -+
+ : |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |0|
+ +-+
+ Note that since we always merge adjacent free chunks, the chunks
+ adjacent to a free chunk must be in use.
+
+ Given a pointer to a chunk (which can be derived trivially from the
+ payload pointer) we can, in O(1) time, find out whether the adjacent
+ chunks are free, and if so, unlink them from the lists that they
+ are on and merge them with the current chunk.
+
+ Chunks always begin on even word boundaries, so the mem portion
+ (which is returned to the user) is also on an even word boundary, and
+ thus at least double-word aligned.
+
+ The P (PINUSE_BIT) bit, stored in the unused low-order bit of the
+ chunk size (which is always a multiple of two words), is an in-use
+ bit for the *previous* chunk. If that bit is *clear*, then the
+ word before the current chunk size contains the previous chunk
+ size, and can be used to find the front of the previous chunk.
+ The very first chunk allocated always has this bit set, preventing
+ access to non-existent (or non-owned) memory. If pinuse is set for
+ any given chunk, then you CANNOT determine the size of the
+ previous chunk, and might even get a memory addressing fault when
+ trying to do so.
+
+ The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of
+ the chunk size redundantly records whether the current chunk is
+ inuse. This redundancy enables usage checks within free and realloc,
+ and reduces indirection when freeing and consolidating chunks.
+
+ Each freshly allocated chunk must have both cinuse and pinuse set.
+ That is, each allocated chunk borders either a previously allocated
+ and still in-use chunk, or the base of its memory arena. This is
+ ensured by making all allocations from the the `lowest' part of any
+ found chunk. Further, no free chunk physically borders another one,
+ so each free chunk is known to be preceded and followed by either
+ inuse chunks or the ends of memory.
+
+ Note that the `foot' of the current chunk is actually represented
+ as the prev_foot of the NEXT chunk. This makes it easier to
+ deal with alignments etc but can be very confusing when trying
+ to extend or adapt this code.
+
+ The exceptions to all this are
+
+ 1. The special chunk `top' is the top-most available chunk (i.e.,
+ the one bordering the end of available memory). It is treated
+ specially. Top is never included in any bin, is used only if
+ no other chunk is available, and is released back to the
+ system if it is very large (see M_TRIM_THRESHOLD). In effect,
+ the top chunk is treated as larger (and thus less well
+ fitting) than any other available chunk. The top chunk
+ doesn't update its trailing size field since there is no next
+ contiguous chunk that would have to index off it. However,
+ space is still allocated for it (TOP_FOOT_SIZE) to enable
+ separation or merging when space is extended.
+
+ 3. Chunks allocated via mmap, which have the lowest-order bit
+ (IS_MMAPPED_BIT) set in their prev_foot fields, and do not set
+ PINUSE_BIT in their head fields. Because they are allocated
+ one-by-one, each must carry its own prev_foot field, which is
+ also used to hold the offset this chunk has within its mmapped
+ region, which is needed to preserve alignment. Each mmapped
+ chunk is trailed by the first two fields of a fake next-chunk
+ for sake of usage checks.
+
+*/
+
+struct malloc_chunk {
+ size_t prev_foot; /* Size of previous chunk (if free). */
+ size_t head; /* Size and inuse bits. */
+ struct malloc_chunk* fd; /* double links -- used only if free. */
+ struct malloc_chunk* bk;
+};
+
+typedef struct malloc_chunk mchunk;
+typedef struct malloc_chunk* mchunkptr;
+typedef struct malloc_chunk* sbinptr; /* The type of bins of chunks */
+typedef unsigned int bindex_t; /* Described below */
+typedef unsigned int binmap_t; /* Described below */
+typedef unsigned int flag_t; /* The type of various bit flag sets */
+
+
+/* ------------------- Chunks sizes and alignments ----------------------- */
+
+#define MCHUNK_SIZE (sizeof(mchunk))
+
+#if FOOTERS
+#define CHUNK_OVERHEAD (TWO_SIZE_T_SIZES)
+#else /* FOOTERS */
+#define CHUNK_OVERHEAD (SIZE_T_SIZE)
+#endif /* FOOTERS */
+
+/* The smallest size we can malloc is an aligned minimal chunk */
+#define MIN_CHUNK_SIZE\
+ ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
+
+/* conversion from malloc headers to user pointers, and back */
+#define chunk2mem(p) ((void*)((char*)(p) + TWO_SIZE_T_SIZES))
+#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES))
+/* chunk associated with aligned address A */
+#define align_as_chunk(A) (mchunkptr)((A) + align_offset(chunk2mem(A)))
+
+/* Bounds on request (not chunk) sizes. */
+#define MAX_REQUEST ((-MIN_CHUNK_SIZE) << 2)
+#define MIN_REQUEST (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE)
+
+/* pad request bytes into a usable size */
+#define pad_request(req) \
+ (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
+
+/* pad request, checking for minimum (but not maximum) */
+#define request2size(req) \
+ (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req))
+
+/* ------------------ Operations on head and foot fields ----------------- */
+
+/*
+ The head field of a chunk is or'ed with PINUSE_BIT when previous
+ adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in
+ use. If the chunk was obtained with mmap, the prev_foot field has
+ IS_MMAPPED_BIT set, otherwise holding the offset of the base of the
+ mmapped region to the base of the chunk.
+*/
+
+#define PINUSE_BIT (SIZE_T_ONE)
+#define CINUSE_BIT (SIZE_T_TWO)
+#define INUSE_BITS (PINUSE_BIT|CINUSE_BIT)
+
+/* Head value for fenceposts */
+#define FENCEPOST_HEAD (INUSE_BITS|SIZE_T_SIZE)
+
+/* extraction of fields from head words */
+#define cinuse(p) ((p)->head & CINUSE_BIT)
+#define pinuse(p) ((p)->head & PINUSE_BIT)
+#define chunksize(p) ((p)->head & ~(INUSE_BITS))
+
+#define clear_pinuse(p) ((p)->head &= ~PINUSE_BIT)
+#define clear_cinuse(p) ((p)->head &= ~CINUSE_BIT)
+
+/* Treat space at ptr +/- offset as a chunk */
+#define chunk_plus_offset(p, s) ((mchunkptr)(((char*)(p)) + (s)))
+#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s)))
+
+/* Ptr to next or previous physical malloc_chunk. */
+#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~INUSE_BITS)))
+#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) ))
+
+/* extract next chunk's pinuse bit */
+#define next_pinuse(p) ((next_chunk(p)->head) & PINUSE_BIT)
+
+/* Get/set size at footer */
+#define get_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot)
+#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s))
+
+/* Set size, pinuse bit, and foot */
+#define set_size_and_pinuse_of_free_chunk(p, s)\
+ ((p)->head = (s|PINUSE_BIT), set_foot(p, s))
+
+/* Set size, pinuse bit, foot, and clear next pinuse */
+#define set_free_with_pinuse(p, s, n)\
+ (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s))
+
+/* Get the internal overhead associated with chunk p */
+#define overhead_for(p) CHUNK_OVERHEAD
+
+/* Return true if malloced space is not necessarily cleared */
+#define calloc_must_clear(p) (1)
+
+
+/* ---------------------- Overlaid data structures ----------------------- */
+
+/*
+ When chunks are not in use, they are treated as nodes of either
+ lists or trees.
+
+ "Small" chunks are stored in circular doubly-linked lists, and look
+ like this:
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `head:' | Size of chunk, in bytes |P|
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Forward pointer to next chunk in list |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Back pointer to previous chunk in list |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Unused space (may be 0 bytes long) .
+ . .
+ . |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `foot:' | Size of chunk, in bytes |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ Larger chunks are kept in a form of bitwise digital trees (aka
+ tries) keyed on chunksizes. Because malloc_tree_chunks are only for
+ free chunks greater than 256 bytes, their size doesn't impose any
+ constraints on user chunk sizes. Each node looks like:
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `head:' | Size of chunk, in bytes |P|
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Forward pointer to next chunk of same size |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Back pointer to previous chunk of same size |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Pointer to left child (child[0]) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Pointer to right child (child[1]) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Pointer to parent |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | bin index of this chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Unused space .
+ . |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `foot:' | Size of chunk, in bytes |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ Each tree holding treenodes is a tree of unique chunk sizes. Chunks
+ of the same size are arranged in a circularly-linked list, with only
+ the oldest chunk (the next to be used, in our FIFO ordering)
+ actually in the tree. (Tree members are distinguished by a non-null
+ parent pointer.) If a chunk with the same size an an existing node
+ is inserted, it is linked off the existing node using pointers that
+ work in the same way as fd/bk pointers of small chunks.
+
+ Each tree contains a power of 2 sized range of chunk sizes (the
+ smallest is 0x100 <= x < 0x180), which is is divided in half at each
+ tree level, with the chunks in the smaller half of the range (0x100
+ <= x < 0x140 for the top nose) in the left subtree and the larger
+ half (0x140 <= x < 0x180) in the right subtree. This is, of course,
+ done by inspecting individual bits.
+
+ Using these rules, each node's left subtree contains all smaller
+ sizes than its right subtree. However, the node at the root of each
+ subtree has no particular ordering relationship to either. (The
+ dividing line between the subtree sizes is based on trie relation.)
+ If we remove the last chunk of a given size from the interior of the
+ tree, we need to replace it with a leaf node. The tree ordering
+ rules permit a node to be replaced by any leaf below it.
+
+ The smallest chunk in a tree (a common operation in a best-fit
+ allocator) can be found by walking a path to the leftmost leaf in
+ the tree. Unlike a usual binary tree, where we follow left child
+ pointers until we reach a null, here we follow the right child
+ pointer any time the left one is null, until we reach a leaf with
+ both child pointers null. The smallest chunk in the tree will be
+ somewhere along that path.
+
+ The worst case number of steps to add, find, or remove a node is
+ bounded by the number of bits differentiating chunks within
+ bins. Under current bin calculations, this ranges from 6 up to 21
+ (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case
+ is of course much better.
+*/
+
+struct malloc_tree_chunk {
+ /* The first four fields must be compatible with malloc_chunk */
+ size_t prev_foot;
+ size_t head;
+ struct malloc_tree_chunk* fd;
+ struct malloc_tree_chunk* bk;
+
+ struct malloc_tree_chunk* child[2];
+ struct malloc_tree_chunk* parent;
+ bindex_t index;
+};
+
+typedef struct malloc_tree_chunk tchunk;
+typedef struct malloc_tree_chunk* tchunkptr;
+typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */
+
+/* A little helper macro for trees */
+#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1])
+
+/* ----------------------------- Segments -------------------------------- */
+
+/*
+ Each malloc space may include non-contiguous segments, held in a
+ list headed by an embedded malloc_segment record representing the
+ top-most space. Segments also include flags holding properties of
+ the space. Large chunks that are directly allocated by mmap are not
+ included in this list. They are instead independently created and
+ destroyed without otherwise keeping track of them.
+
+ Segment management mainly comes into play for spaces allocated by
+ MMAP. Any call to MMAP might or might not return memory that is
+ adjacent to an existing segment. MORECORE normally contiguously
+ extends the current space, so this space is almost always adjacent,
+ which is simpler and faster to deal with. (This is why MORECORE is
+ used preferentially to MMAP when both are available -- see
+ sys_alloc.) When allocating using MMAP, we don't use any of the
+ hinting mechanisms (inconsistently) supported in various
+ implementations of unix mmap, or distinguish reserving from
+ committing memory. Instead, we just ask for space, and exploit
+ contiguity when we get it. It is probably possible to do
+ better than this on some systems, but no general scheme seems
+ to be significantly better.
+
+ Management entails a simpler variant of the consolidation scheme
+ used for chunks to reduce fragmentation -- new adjacent memory is
+ normally prepended or appended to an existing segment. However,
+ there are limitations compared to chunk consolidation that mostly
+ reflect the fact that segment processing is relatively infrequent
+ (occurring only when getting memory from system) and that we
+ don't expect to have huge numbers of segments:
+
+ * Segments are not indexed, so traversal requires linear scans. (It
+ would be possible to index these, but is not worth the extra
+ overhead and complexity for most programs on most platforms.)
+ * New segments are only appended to old ones when holding top-most
+ memory; if they cannot be prepended to others, they are held in
+ different segments.
+
+ Except for the top-most segment of an mstate, each segment record
+ is kept at the tail of its segment. Segments are added by pushing
+ segment records onto the list headed by &mstate.seg for the
+ containing mstate.
+
+ Segment flags control allocation/merge/deallocation policies:
+ * If EXTERN_BIT set, then we did not allocate this segment,
+ and so should not try to deallocate or merge with others.
+ (This currently holds only for the initial segment passed
+ into create_mspace_with_base.)
+ * If IS_MMAPPED_BIT set, the segment may be merged with
+ other surrounding mmapped segments and trimmed/de-allocated
+ using munmap.
+ * If neither bit is set, then the segment was obtained using
+ MORECORE so can be merged with surrounding MORECORE'd segments
+ and deallocated/trimmed using MORECORE with negative arguments.
+*/
+
+struct malloc_segment {
+ char* base; /* base address */
+ size_t size; /* allocated size */
+ struct malloc_segment* next; /* ptr to next segment */
+};
+
+typedef struct malloc_segment msegment;
+typedef struct malloc_segment* msegmentptr;
+
+/* ---------------------------- malloc_state ----------------------------- */
+
+/*
+ A malloc_state holds all of the bookkeeping for a space.
+ The main fields are:
+
+ Top
+ The topmost chunk of the currently active segment. Its size is
+ cached in topsize. The actual size of topmost space is
+ topsize+TOP_FOOT_SIZE, which includes space reserved for adding
+ fenceposts and segment records if necessary when getting more
+ space from the system. The size at which to autotrim top is
+ cached from mparams in trim_check, except that it is disabled if
+ an autotrim fails.
+
+ Designated victim (dv)
+ This is the preferred chunk for servicing small requests that
+ don't have exact fits. It is normally the chunk split off most
+ recently to service another small request. Its size is cached in
+ dvsize. The link fields of this chunk are not maintained since it
+ is not kept in a bin.
+
+ SmallBins
+ An array of bin headers for free chunks. These bins hold chunks
+ with sizes less than MIN_LARGE_SIZE bytes. Each bin contains
+ chunks of all the same size, spaced 8 bytes apart. To simplify
+ use in double-linked lists, each bin header acts as a malloc_chunk
+ pointing to the real first node, if it exists (else pointing to
+ itself). This avoids special-casing for headers. But to avoid
+ waste, we allocate only the fd/bk pointers of bins, and then use
+ repositioning tricks to treat these as the fields of a chunk.
+
+ TreeBins
+ Treebins are pointers to the roots of trees holding a range of
+ sizes. There are 2 equally spaced treebins for each power of two
+ from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything
+ larger.
+
+ Bin maps
+ There is one bit map for small bins ("smallmap") and one for
+ treebins ("treemap). Each bin sets its bit when non-empty, and
+ clears the bit when empty. Bit operations are then used to avoid
+ bin-by-bin searching -- nearly all "search" is done without ever
+ looking at bins that won't be selected. The bit maps
+ conservatively use 32 bits per map word, even if on 64bit system.
+ For a good description of some of the bit-based techniques used
+ here, see Henry S. Warren Jr's book "Hacker's Delight" (and
+ supplement at http://hackersdelight.org/). Many of these are
+ intended to reduce the branchiness of paths through malloc etc, as
+ well as to reduce the number of memory locations read or written.
+
+ Segments
+ A list of segments headed by an embedded malloc_segment record
+ representing the initial space.
+
+ Address check support
+ The least_addr field is the least address ever obtained from
+ MORECORE or MMAP. Attempted frees and reallocs of any address less
+ than this are trapped (unless INSECURE is defined).
+
+ Magic tag
+ A cross-check field that should always hold same value as mparams.magic.
+
+ Flags
+ Bits recording whether to use MMAP, locks, or contiguous MORECORE
+
+ Statistics
+ Each space keeps track of current and maximum system memory
+ obtained via MORECORE or MMAP.
+
+ Locking
+ If USE_LOCKS is defined, the "mutex" lock is acquired and released
+ around every public call using this mspace.
+*/
+
+/* Bin types, widths and sizes */
+#define NSMALLBINS (32U)
+#define NTREEBINS (32U)
+#define SMALLBIN_SHIFT (3U)
+#define SMALLBIN_WIDTH (SIZE_T_ONE << SMALLBIN_SHIFT)
+#define TREEBIN_SHIFT (8U)
+#define MIN_LARGE_SIZE (SIZE_T_ONE << TREEBIN_SHIFT)
+#define MAX_SMALL_SIZE (MIN_LARGE_SIZE - SIZE_T_ONE)
+#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD)
+
+struct malloc_state {
+ binmap_t smallmap;
+ binmap_t treemap;
+ size_t dvsize;
+ size_t topsize;
+ char* least_addr;
+ mchunkptr dv;
+ mchunkptr top;
+ size_t magic;
+ mchunkptr smallbins[(NSMALLBINS+1)*2];
+ tbinptr treebins[NTREEBINS];
+ size_t footprint;
+ size_t max_footprint;
+ flag_t mflags;
+ void *user_data;
+#if USE_LOCKS
+ MLOCK_T mutex; /* locate lock among fields that rarely change */
+#endif /* USE_LOCKS */
+ msegment seg;
+};
+
+typedef struct malloc_state* mstate;
+
+/* ------------- Global malloc_state and malloc_params ------------------- */
+
+/*
+ malloc_params holds global properties, including those that can be
+ dynamically set using mallopt. There is a single instance, mparams,
+ initialized in init_mparams.
+*/
+
+struct malloc_params {
+ size_t magic;
+ size_t page_size;
+ size_t granularity;
+ flag_t default_mflags;
+};
+
+static struct malloc_params mparams;
+
+/* The global malloc_state used for all non-"mspace" calls */
+//static struct malloc_state _gm_;
+//#define gm (&_gm_)
+//#define is_global(M) ((M) == &_gm_)
+#define is_initialized(M) ((M)->top != 0)
+
+/* -------------------------- system alloc setup ------------------------- */
+
+/* Operations on mflags */
+
+#define use_lock(M) ((M)->mflags & USE_LOCK_BIT)
+#define enable_lock(M) ((M)->mflags |= USE_LOCK_BIT)
+#define disable_lock(M) ((M)->mflags &= ~USE_LOCK_BIT)
+
+#define set_lock(M,L)\
+ ((M)->mflags = (L)?\
+ ((M)->mflags | USE_LOCK_BIT) :\
+ ((M)->mflags & ~USE_LOCK_BIT))
+
+/* page-align a size */
+#define page_align(S)\
+ (((S) + (mparams.page_size)) & ~(mparams.page_size - SIZE_T_ONE))
+
+/* granularity-align a size */
+#define granularity_align(S)\
+ (((S) + (mparams.granularity)) & ~(mparams.granularity - SIZE_T_ONE))
+
+#define is_page_aligned(S)\
+ (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0)
+#define is_granularity_aligned(S)\
+ (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0)
+
+/* True if segment S holds address A */
+#define segment_holds(S, A)\
+ ((char*)(A) >= S->base && (char*)(A) < S->base + S->size)
+
+/* Return segment holding given address */
+static msegmentptr segment_holding(mstate m, char* addr) {
+ msegmentptr sp = &m->seg;
+ for (;;) {
+ if (addr >= sp->base && addr < sp->base + sp->size)
+ return sp;
+ if ((sp = sp->next) == 0)
+ return 0;
+ }
+}
+
+/* Return true if segment contains a segment link */
+static int has_segment_link(mstate m, msegmentptr ss) {
+ msegmentptr sp = &m->seg;
+ for (;;) {
+ if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size)
+ return 1;
+ if ((sp = sp->next) == 0)
+ return 0;
+ }
+}
+
+
+
+/*
+ TOP_FOOT_SIZE is padding at the end of a segment, including space
+ that may be needed to place segment records and fenceposts when new
+ noncontiguous segments are added.
+*/
+#define TOP_FOOT_SIZE\
+ (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE)
+
+
+/* ------------------------------- Hooks -------------------------------- */
+
+/*
+ PREACTION should be defined to return 0 on success, and nonzero on
+ failure. If you are not using locking, you can redefine these to do
+ anything you like.
+*/
+
+#if USE_LOCKS
+
+/* Ensure locks are initialized */
+#define GLOBALLY_INITIALIZE() (mparams.page_size == 0 && init_mparams())
+
+#define PREACTION(M) ((GLOBALLY_INITIALIZE() || use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0)
+#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); }
+#else /* USE_LOCKS */
+
+#ifndef PREACTION
+#define PREACTION(M) (0)
+#endif /* PREACTION */
+
+#ifndef POSTACTION
+#define POSTACTION(M)
+#endif /* POSTACTION */
+
+#endif /* USE_LOCKS */
+
+/*
+ CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses.
+ USAGE_ERROR_ACTION is triggered on detected bad frees and
+ reallocs. The argument p is an address that might have triggered the
+ fault. It is ignored by the two predefined actions, but might be
+ useful in custom actions that try to help diagnose errors.
+*/
+
+#if PROCEED_ON_ERROR
+
+/* A count of the number of corruption errors causing resets */
+int malloc_corruption_error_count;
+
+/* default corruption action */
+static void reset_on_error(mstate m);
+
+#define CORRUPTION_ERROR_ACTION(m) reset_on_error(m)
+#define USAGE_ERROR_ACTION(m, p)
+
+#else /* PROCEED_ON_ERROR */
+
+#ifndef CORRUPTION_ERROR_ACTION
+#define CORRUPTION_ERROR_ACTION(m) ABORT(m->user_data)
+#endif /* CORRUPTION_ERROR_ACTION */
+
+#ifndef USAGE_ERROR_ACTION
+#define USAGE_ERROR_ACTION(m,p) ABORT(m->user_data)
+#endif /* USAGE_ERROR_ACTION */
+
+#endif /* PROCEED_ON_ERROR */
+
+/* -------------------------- Debugging setup ---------------------------- */
+
+#if ! DEBUG
+
+#define check_free_chunk(M,P)
+#define check_inuse_chunk(M,P)
+#define check_malloced_chunk(M,P,N)
+#define check_malloc_state(M)
+#define check_top_chunk(M,P)
+
+#else /* DEBUG */
+#define check_free_chunk(M,P) do_check_free_chunk(M,P)
+#define check_inuse_chunk(M,P) do_check_inuse_chunk(M,P)
+#define check_top_chunk(M,P) do_check_top_chunk(M,P)
+#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N)
+#define check_malloc_state(M) do_check_malloc_state(M)
+
+static void do_check_any_chunk(mstate m, mchunkptr p);
+static void do_check_top_chunk(mstate m, mchunkptr p);
+static void do_check_inuse_chunk(mstate m, mchunkptr p);
+static void do_check_free_chunk(mstate m, mchunkptr p);
+static void do_check_malloced_chunk(mstate m, void* mem, size_t s);
+static void do_check_tree(mstate m, tchunkptr t);
+static void do_check_treebin(mstate m, bindex_t i);
+static void do_check_smallbin(mstate m, bindex_t i);
+static void do_check_malloc_state(mstate m);
+static int bin_find(mstate m, mchunkptr x);
+static size_t traverse_and_check(mstate m);
+#endif /* DEBUG */
+
+/* ---------------------------- Indexing Bins ---------------------------- */
+
+#define is_small(s) (((s) >> SMALLBIN_SHIFT) < NSMALLBINS)
+#define small_index(s) ((s) >> SMALLBIN_SHIFT)
+#define small_index2size(i) ((i) << SMALLBIN_SHIFT)
+#define MIN_SMALL_INDEX (small_index(MIN_CHUNK_SIZE))
+
+/* addressing by index. See above about smallbin repositioning */
+#define smallbin_at(M, i) ((sbinptr)((char*)&((M)->smallbins[(i)<<1])))
+#define treebin_at(M,i) (&((M)->treebins[i]))
+
+/* assign tree index for size S to variable I */
+#if defined(__GNUC__) && defined(i386)
+#define compute_tree_index(S, I)\
+{\
+ size_t X = S >> TREEBIN_SHIFT;\
+ if (X == 0)\
+ I = 0;\
+ else if (X > 0xFFFF)\
+ I = NTREEBINS-1;\
+ else {\
+ unsigned int K;\
+ __asm__("bsrl %1,%0\n\t" : "=r" (K) : "rm" (X));\
+ I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
+ }\
+}
+#else /* GNUC */
+#define compute_tree_index(S, I)\
+{\
+ size_t X = S >> TREEBIN_SHIFT;\
+ if (X == 0)\
+ I = 0;\
+ else if (X > 0xFFFF)\
+ I = NTREEBINS-1;\
+ else {\
+ unsigned int Y = (unsigned int)X;\
+ unsigned int N = ((Y - 0x100) >> 16) & 8;\
+ unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\
+ N += K;\
+ N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\
+ K = 14 - N + ((Y <<= K) >> 15);\
+ I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\
+ }\
+}
+#endif /* GNUC */
+
+/* Bit representing maximum resolved size in a treebin at i */
+#define bit_for_tree_index(i) \
+ (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2)
+
+/* Shift placing maximum resolved bit in a treebin at i as sign bit */
+#define leftshift_for_tree_index(i) \
+ ((i == NTREEBINS-1)? 0 : \
+ ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2)))
+
+/* The size of the smallest chunk held in bin with index i */
+#define minsize_for_tree_index(i) \
+ ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) | \
+ (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1)))
+
+/* ------------------------ Operations on bin maps ----------------------- */
+
+/* bit corresponding to given index */
+#define idx2bit(i) ((binmap_t)(1) << (i))
+
+/* Mark/Clear bits with given index */
+#define mark_smallmap(M,i) ((M)->smallmap |= idx2bit(i))
+#define clear_smallmap(M,i) ((M)->smallmap &= ~idx2bit(i))
+#define smallmap_is_marked(M,i) ((M)->smallmap & idx2bit(i))
+
+#define mark_treemap(M,i) ((M)->treemap |= idx2bit(i))
+#define clear_treemap(M,i) ((M)->treemap &= ~idx2bit(i))
+#define treemap_is_marked(M,i) ((M)->treemap & idx2bit(i))
+
+/* index corresponding to given bit */
+
+#if defined(__GNUC__) && defined(i386)
+#define compute_bit2idx(X, I)\
+{\
+ unsigned int J;\
+ __asm__("bsfl %1,%0\n\t" : "=r" (J) : "rm" (X));\
+ I = (bindex_t)J;\
+}
+
+#else /* GNUC */
+#if USE_BUILTIN_FFS
+#define compute_bit2idx(X, I) I = ffs(X)-1
+
+#else /* USE_BUILTIN_FFS */
+#define compute_bit2idx(X, I)\
+{\
+ unsigned int Y = X - 1;\
+ unsigned int K = Y >> (16-4) & 16;\
+ unsigned int N = K; Y >>= K;\
+ N += K = Y >> (8-3) & 8; Y >>= K;\
+ N += K = Y >> (4-2) & 4; Y >>= K;\
+ N += K = Y >> (2-1) & 2; Y >>= K;\
+ N += K = Y >> (1-0) & 1; Y >>= K;\
+ I = (bindex_t)(N + Y);\
+}
+#endif /* USE_BUILTIN_FFS */
+#endif /* GNUC */
+
+/* isolate the least set bit of a bitmap */
+#define least_bit(x) ((x) & -(x))
+
+/* mask with all bits to left of least bit of x on */
+#define left_bits(x) ((x<<1) | -(x<<1))
+
+/* mask with all bits to left of or equal to least bit of x on */
+#define same_or_left_bits(x) ((x) | -(x))
+
+
+/* ----------------------- Runtime Check Support ------------------------- */
+
+/*
+ For security, the main invariant is that malloc/free/etc never
+ writes to a static address other than malloc_state, unless static
+ malloc_state itself has been corrupted, which cannot occur via
+ malloc (because of these checks). In essence this means that we
+ believe all pointers, sizes, maps etc held in malloc_state, but
+ check all of those linked or offsetted from other embedded data
+ structures. These checks are interspersed with main code in a way
+ that tends to minimize their run-time cost.
+
+ When FOOTERS is defined, in addition to range checking, we also
+ verify footer fields of inuse chunks, which can be used guarantee
+ that the mstate controlling malloc/free is intact. This is a
+ streamlined version of the approach described by William Robertson
+ et al in "Run-time Detection of Heap-based Overflows" LISA'03
+ http://www.usenix.org/events/lisa03/tech/robertson.html The footer
+ of an inuse chunk holds the xor of its mstate and a random seed,
+ that is checked upon calls to free() and realloc(). This is
+ (probablistically) unguessable from outside the program, but can be
+ computed by any code successfully malloc'ing any chunk, so does not
+ itself provide protection against code that has already broken
+ security through some other means. Unlike Robertson et al, we
+ always dynamically check addresses of all offset chunks (previous,
+ next, etc). This turns out to be cheaper than relying on hashes.
+*/
+
+#if !INSECURE
+/* Check if address a is at least as high as any from MORECORE or MMAP */
+#define ok_address(M, a) ((char*)(a) >= (M)->least_addr)
+/* Check if address of next chunk n is higher than base chunk p */
+#define ok_next(p, n) ((char*)(p) < (char*)(n))
+/* Check if p has its cinuse bit on */
+#define ok_cinuse(p) cinuse(p)
+/* Check if p has its pinuse bit on */
+#define ok_pinuse(p) pinuse(p)
+
+#else /* !INSECURE */
+#define ok_address(M, a) (1)
+#define ok_next(b, n) (1)
+#define ok_cinuse(p) (1)
+#define ok_pinuse(p) (1)
+#endif /* !INSECURE */
+
+#if (FOOTERS && !INSECURE)
+/* Check if (alleged) mstate m has expected magic field */
+#define ok_magic(M) ((M)->magic == mparams.magic)
+#else /* (FOOTERS && !INSECURE) */
+#define ok_magic(M) (1)
+#endif /* (FOOTERS && !INSECURE) */
+
+
+/* In gcc, use __builtin_expect to minimize impact of checks */
+#if !INSECURE
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define RTCHECK(e) __builtin_expect(e, 1)
+#else /* GNUC */
+#define RTCHECK(e) (e)
+#endif /* GNUC */
+#else /* !INSECURE */
+#define RTCHECK(e) (1)
+#endif /* !INSECURE */
+
+/* macros to set up inuse chunks with or without footers */
+
+#if !FOOTERS
+
+#define mark_inuse_foot(M,p,s)
+
+/* Set cinuse bit and pinuse bit of next chunk */
+#define set_inuse(M,p,s)\
+ ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
+ ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
+
+/* Set cinuse and pinuse of this chunk and pinuse of next chunk */
+#define set_inuse_and_pinuse(M,p,s)\
+ ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
+ ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
+
+/* Set size, cinuse and pinuse bit of this chunk */
+#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
+ ((p)->head = (s|PINUSE_BIT|CINUSE_BIT))
+
+#else /* FOOTERS */
+
+/* Set foot of inuse chunk to be xor of mstate and seed */
+#define mark_inuse_foot(M,p,s)\
+ (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic))
+
+#define get_mstate_for(p)\
+ ((mstate)(((mchunkptr)((char*)(p) +\
+ (chunksize(p))))->prev_foot ^ mparams.magic))
+
+#define set_inuse(M,p,s)\
+ ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
+ (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \
+ mark_inuse_foot(M,p,s))
+
+#define set_inuse_and_pinuse(M,p,s)\
+ ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
+ (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\
+ mark_inuse_foot(M,p,s))
+
+#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
+ ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
+ mark_inuse_foot(M, p, s))
+
+#endif /* !FOOTERS */
+
+/* ---------------------------- setting mparams -------------------------- */
+
+/* Initialize mparams */
+static int init_mparams(void) {
+ if (mparams.page_size == 0) {
+ size_t s;
+
+ mparams.default_mflags = USE_LOCK_BIT;
+
+#if (FOOTERS && !INSECURE)
+ {
+#if USE_DEV_RANDOM
+ int fd;
+ unsigned char buf[sizeof(size_t)];
+ /* Try to use /dev/urandom, else fall back on using time */
+ if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 &&
+ read(fd, buf, sizeof(buf)) == sizeof(buf)) {
+ s = *((size_t *) buf);
+ close(fd);
+ }
+ else
+#endif /* USE_DEV_RANDOM */
+ s = (size_t)(time(0) ^ (size_t)0x55555555U);
+
+ s |= (size_t)8U; /* ensure nonzero */
+ s &= ~(size_t)7U; /* improve chances of fault for bad values */
+
+ }
+#else /* (FOOTERS && !INSECURE) */
+ s = (size_t)0x58585858U;
+#endif /* (FOOTERS && !INSECURE) */
+ ACQUIRE_MAGIC_INIT_LOCK();
+ if (mparams.magic == 0) {
+ mparams.magic = s;
+ /* Set up lock for main malloc area */
+ //INITIAL_LOCK(&gm->mutex);
+ //gm->mflags = mparams.default_mflags;
+ }
+ RELEASE_MAGIC_INIT_LOCK();
+
+
+ mparams.page_size = malloc_getpagesize;
+ mparams.granularity = ((DEFAULT_GRANULARITY != 0)?
+ DEFAULT_GRANULARITY : mparams.page_size);
+
+ /* Sanity-check configuration:
+ size_t must be unsigned and as wide as pointer type.
+ ints must be at least 4 bytes.
+ alignment must be at least 8.
+ Alignment, min chunk size, and page size must all be powers of 2.
+ */
+ if ((sizeof(size_t) != sizeof(char*)) ||
+ (MAX_SIZE_T < MIN_CHUNK_SIZE) ||
+ (sizeof(int) < 4) ||
+ (MALLOC_ALIGNMENT < (size_t)8U) ||
+ ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-SIZE_T_ONE)) != 0) ||
+ ((MCHUNK_SIZE & (MCHUNK_SIZE-SIZE_T_ONE)) != 0) ||
+ ((mparams.granularity & (mparams.granularity-SIZE_T_ONE)) != 0) ||
+ ((mparams.page_size & (mparams.page_size-SIZE_T_ONE)) != 0))
+ ABORT(NULL);
+ }
+ return 0;
+}
+
+/* support for mallopt */
+static int change_mparam(int param_number, int value) {
+ size_t val = (size_t)value;
+ init_mparams();
+ switch(param_number) {
+ case M_GRANULARITY:
+ if (val >= mparams.page_size && ((val & (val-1)) == 0)) {
+ mparams.granularity = val;
+ return 1;
+ }
+ else
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+#if DEBUG
+/* ------------------------- Debugging Support --------------------------- */
+
+/* Check properties of any chunk, whether free, inuse, mmapped etc */
+static void do_check_any_chunk(mstate m, mchunkptr p) {
+ assert(m->user_data, (is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
+ assert(m->user_data, ok_address(m, p));
+}
+
+/* Check properties of top chunk */
+static void do_check_top_chunk(mstate m, mchunkptr p) {
+ msegmentptr sp = segment_holding(m, (char*)p);
+ size_t sz = chunksize(p);
+ assert(m->user_data, sp != 0);
+ assert(m->user_data, (is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
+ assert(m->user_data, ok_address(m, p));
+ assert(m->user_data, sz == m->topsize);
+ assert(m->user_data, sz > 0);
+ assert(m->user_data, sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE);
+ assert(m->user_data, pinuse(p));
+ assert(m->user_data, !next_pinuse(p));
+}
+
+/* Check properties of inuse chunks */
+static void do_check_inuse_chunk(mstate m, mchunkptr p) {
+ do_check_any_chunk(m, p);
+ assert(m->user_data, cinuse(p));
+ assert(m->user_data, next_pinuse(p));
+ /* If not pinuse, previous chunk has OK offset */
+ assert(m->user_data, pinuse(p) || next_chunk(prev_chunk(p)) == p);
+}
+
+/* Check properties of free chunks */
+static void do_check_free_chunk(mstate m, mchunkptr p) {
+ size_t sz = p->head & ~(PINUSE_BIT|CINUSE_BIT);
+ mchunkptr next = chunk_plus_offset(p, sz);
+ do_check_any_chunk(m, p);
+ assert(m->user_data, !cinuse(p));
+ assert(m->user_data, !next_pinuse(p));
+ if (p != m->dv && p != m->top) {
+ if (sz >= MIN_CHUNK_SIZE) {
+ assert(m->user_data, (sz & CHUNK_ALIGN_MASK) == 0);
+ assert(m->user_data, is_aligned(chunk2mem(p)));
+ assert(m->user_data, next->prev_foot == sz);
+ assert(m->user_data, pinuse(p));
+ assert(m->user_data, next == m->top || cinuse(next));
+ assert(m->user_data, p->fd->bk == p);
+ assert(m->user_data, p->bk->fd == p);
+ }
+ else /* markers are always of size SIZE_T_SIZE */
+ assert(m->user_data, sz == SIZE_T_SIZE);
+ }
+}
+
+/* Check properties of malloced chunks at the point they are malloced */
+static void do_check_malloced_chunk(mstate m, void* mem, size_t s) {
+ if (mem != 0) {
+ mchunkptr p = mem2chunk(mem);
+ size_t sz = p->head & ~(PINUSE_BIT|CINUSE_BIT);
+ do_check_inuse_chunk(m, p);
+ assert(m->user_data, (sz & CHUNK_ALIGN_MASK) == 0);
+ assert(m->user_data, sz >= MIN_CHUNK_SIZE);
+ assert(m->user_data, sz >= s);
+ /* size is less than MIN_CHUNK_SIZE more than request */
+ assert(m->user_data, sz < (s + MIN_CHUNK_SIZE));
+ }
+}
+
+/* Check a tree and its subtrees. */
+static void do_check_tree(mstate m, tchunkptr t) {
+ tchunkptr head = 0;
+ tchunkptr u = t;
+ bindex_t tindex = t->index;
+ size_t tsize = chunksize(t);
+ bindex_t idx;
+ compute_tree_index(tsize, idx);
+ assert(m->user_data, tindex == idx);
+ assert(m->user_data, tsize >= MIN_LARGE_SIZE);
+ assert(m->user_data, tsize >= minsize_for_tree_index(idx));
+ assert(m->user_data, (idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1))));
+
+ do { /* traverse through chain of same-sized nodes */
+ do_check_any_chunk(m, ((mchunkptr)u));
+ assert(m->user_data, u->index == tindex);
+ assert(m->user_data, chunksize(u) == tsize);
+ assert(m->user_data, !cinuse(u));
+ assert(m->user_data, !next_pinuse(u));
+ assert(m->user_data, u->fd->bk == u);
+ assert(m->user_data, u->bk->fd == u);
+ if (u->parent == 0) {
+ assert(m->user_data, u->child[0] == 0);
+ assert(m->user_data, u->child[1] == 0);
+ }
+ else {
+ assert(m->user_data, head == 0); /* only one node on chain has parent */
+ head = u;
+ assert(m->user_data, u->parent != u);
+ assert(m->user_data, u->parent->child[0] == u ||
+ u->parent->child[1] == u ||
+ *((tbinptr*)(u->parent)) == u);
+ if (u->child[0] != 0) {
+ assert(m->user_data, u->child[0]->parent == u);
+ assert(m->user_data, u->child[0] != u);
+ do_check_tree(m, u->child[0]);
+ }
+ if (u->child[1] != 0) {
+ assert(m->user_data, u->child[1]->parent == u);
+ assert(m->user_data, u->child[1] != u);
+ do_check_tree(m, u->child[1]);
+ }
+ if (u->child[0] != 0 && u->child[1] != 0) {
+ assert(m->user_data, chunksize(u->child[0]) < chunksize(u->child[1]));
+ }
+ }
+ u = u->fd;
+ } while (u != t);
+ assert(m->user_data, head != 0);
+}
+
+/* Check all the chunks in a treebin. */
+static void do_check_treebin(mstate m, bindex_t i) {
+ tbinptr* tb = treebin_at(m, i);
+ tchunkptr t = *tb;
+ int empty = (m->treemap & (1U << i)) == 0;
+ if (t == 0)
+ assert(m->user_data, empty);
+ if (!empty)
+ do_check_tree(m, t);
+}
+
+/* Check all the chunks in a smallbin. */
+static void do_check_smallbin(mstate m, bindex_t i) {
+ sbinptr b = smallbin_at(m, i);
+ mchunkptr p = b->bk;
+ unsigned int empty = (m->smallmap & (1U << i)) == 0;
+ if (p == b)
+ assert(m->user_data, empty);
+ if (!empty) {
+ for (; p != b; p = p->bk) {
+ size_t size = chunksize(p);
+ mchunkptr q;
+ /* each chunk claims to be free */
+ do_check_free_chunk(m, p);
+ /* chunk belongs in bin */
+ assert(m->user_data, small_index(size) == i);
+ assert(m->user_data, p->bk == b || chunksize(p->bk) == chunksize(p));
+ /* chunk is followed by an inuse chunk */
+ q = next_chunk(p);
+ if (q->head != FENCEPOST_HEAD)
+ do_check_inuse_chunk(m, q);
+ }
+ }
+}
+
+/* Find x in a bin. Used in other check functions. */
+static int bin_find(mstate m, mchunkptr x) {
+ size_t size = chunksize(x);
+ if (is_small(size)) {
+ bindex_t sidx = small_index(size);
+ sbinptr b = smallbin_at(m, sidx);
+ if (smallmap_is_marked(m, sidx)) {
+ mchunkptr p = b;
+ do {
+ if (p == x)
+ return 1;
+ } while ((p = p->fd) != b);
+ }
+ }
+ else {
+ bindex_t tidx;
+ compute_tree_index(size, tidx);
+ if (treemap_is_marked(m, tidx)) {
+ tchunkptr t = *treebin_at(m, tidx);
+ size_t sizebits = size << leftshift_for_tree_index(tidx);
+ while (t != 0 && chunksize(t) != size) {
+ t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
+ sizebits <<= 1;
+ }
+ if (t != 0) {
+ tchunkptr u = t;
+ do {
+ if (u == (tchunkptr)x)
+ return 1;
+ } while ((u = u->fd) != t);
+ }
+ }
+ }
+ return 0;
+}
+
+/* Traverse each chunk and check it; return total */
+static size_t traverse_and_check(mstate m) {
+ size_t sum = 0;
+ if (is_initialized(m)) {
+ msegmentptr s = &m->seg;
+ sum += m->topsize + TOP_FOOT_SIZE;
+ while (s != 0) {
+ mchunkptr q = align_as_chunk(s->base);
+ mchunkptr lastq = 0;
+ assert(m->user_data, pinuse(q));
+ while (segment_holds(s, q) &&
+ q != m->top && q->head != FENCEPOST_HEAD) {
+ sum += chunksize(q);
+ if (cinuse(q)) {
+ assert(m->user_data, !bin_find(m, q));
+ do_check_inuse_chunk(m, q);
+ }
+ else {
+ assert(m->user_data, q == m->dv || bin_find(m, q));
+ assert(m->user_data, lastq == 0 || cinuse(lastq)); /* Not 2 consecutive free */
+ do_check_free_chunk(m, q);
+ }
+ lastq = q;
+ q = next_chunk(q);
+ }
+ s = s->next;
+ }
+ }
+ return sum;
+}
+
+/* Check all properties of malloc_state. */
+static void do_check_malloc_state(mstate m) {
+ bindex_t i;
+ size_t total;
+ /* check bins */
+ for (i = 0; i < NSMALLBINS; ++i)
+ do_check_smallbin(m, i);
+ for (i = 0; i < NTREEBINS; ++i)
+ do_check_treebin(m, i);
+
+ if (m->dvsize != 0) { /* check dv chunk */
+ do_check_any_chunk(m, m->dv);
+ assert(m->user_data, m->dvsize == chunksize(m->dv));
+ assert(m->user_data, m->dvsize >= MIN_CHUNK_SIZE);
+ assert(m->user_data, bin_find(m, m->dv) == 0);
+ }
+
+ if (m->top != 0) { /* check top chunk */
+ do_check_top_chunk(m, m->top);
+ assert(m->user_data, m->topsize == chunksize(m->top));
+ assert(m->user_data, m->topsize > 0);
+ assert(m->user_data, bin_find(m, m->top) == 0);
+ }
+
+ total = traverse_and_check(m);
+ assert(m->user_data, total <= m->footprint);
+ assert(m->user_data, m->footprint <= m->max_footprint);
+}
+#endif /* DEBUG */
+
+/* ----------------------------- statistics ------------------------------ */
+
+#if !NO_MALLINFO
+static struct mallinfo internal_mallinfo(mstate m) {
+ struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ if (!PREACTION(m)) {
+ check_malloc_state(m);
+ if (is_initialized(m)) {
+ size_t nfree = SIZE_T_ONE; /* top always free */
+ size_t mfree = m->topsize + TOP_FOOT_SIZE;
+ size_t sum = mfree;
+ msegmentptr s = &m->seg;
+ while (s != 0) {
+ mchunkptr q = align_as_chunk(s->base);
+ while (segment_holds(s, q) &&
+ q != m->top && q->head != FENCEPOST_HEAD) {
+ size_t sz = chunksize(q);
+ sum += sz;
+ if (!cinuse(q)) {
+ mfree += sz;
+ ++nfree;
+ }
+ q = next_chunk(q);
+ }
+ s = s->next;
+ }
+
+ nm.arena = sum;
+ nm.ordblks = nfree;
+ nm.hblkhd = m->footprint - sum;
+ nm.usmblks = m->max_footprint;
+ nm.uordblks = m->footprint - mfree;
+ nm.fordblks = mfree;
+ nm.keepcost = m->topsize;
+ }
+
+ POSTACTION(m);
+ }
+ return nm;
+}
+#endif /* !NO_MALLINFO */
+
+static void internal_malloc_stats(mstate m) {
+ if (!PREACTION(m)) {
+ size_t maxfp = 0;
+ size_t fp = 0;
+ size_t used = 0;
+ check_malloc_state(m);
+ if (is_initialized(m)) {
+ msegmentptr s = &m->seg;
+ maxfp = m->max_footprint;
+ fp = m->footprint;
+ used = fp - (m->topsize + TOP_FOOT_SIZE);
+
+ while (s != 0) {
+ mchunkptr q = align_as_chunk(s->base);
+ while (segment_holds(s, q) &&
+ q != m->top && q->head != FENCEPOST_HEAD) {
+ if (!cinuse(q))
+ used -= chunksize(q);
+ q = next_chunk(q);
+ }
+ s = s->next;
+ }
+ }
+
+ PRINT((m->user_data, "max system bytes = %10lu\n", (unsigned long)(maxfp)));
+ PRINT((m->user_data, "system bytes = %10lu\n", (unsigned long)(fp)));
+ PRINT((m->user_data, "in use bytes = %10lu\n", (unsigned long)(used)));
+
+ POSTACTION(m);
+ }
+}
+
+/* ----------------------- Operations on smallbins ----------------------- */
+
+/*
+ Various forms of linking and unlinking are defined as macros. Even
+ the ones for trees, which are very long but have very short typical
+ paths. This is ugly but reduces reliance on inlining support of
+ compilers.
+*/
+
+/* Link a free chunk into a smallbin */
+#define insert_small_chunk(M, P, S) {\
+ bindex_t I = small_index(S);\
+ mchunkptr B = smallbin_at(M, I);\
+ mchunkptr F = B;\
+ assert((M)->user_data, S >= MIN_CHUNK_SIZE);\
+ if (!smallmap_is_marked(M, I))\
+ mark_smallmap(M, I);\
+ else if (RTCHECK(ok_address(M, B->fd)))\
+ F = B->fd;\
+ else {\
+ CORRUPTION_ERROR_ACTION(M);\
+ }\
+ B->fd = P;\
+ F->bk = P;\
+ P->fd = F;\
+ P->bk = B;\
+}
+
+/* Unlink a chunk from a smallbin */
+#define unlink_small_chunk(M, P, S) {\
+ mchunkptr F = P->fd;\
+ mchunkptr B = P->bk;\
+ bindex_t I = small_index(S);\
+ assert((M)->user_data, P != B);\
+ assert((M)->user_data, P != F);\
+ assert((M)->user_data, chunksize(P) == small_index2size(I));\
+ if (F == B)\
+ clear_smallmap(M, I);\
+ else if (RTCHECK((F == smallbin_at(M,I) || ok_address(M, F)) &&\
+ (B == smallbin_at(M,I) || ok_address(M, B)))) {\
+ F->bk = B;\
+ B->fd = F;\
+ }\
+ else {\
+ CORRUPTION_ERROR_ACTION(M);\
+ }\
+}
+
+/* Unlink the first chunk from a smallbin */
+#define unlink_first_small_chunk(M, B, P, I) {\
+ mchunkptr F = P->fd;\
+ assert((M)->user_data, P != B);\
+ assert((M)->user_data, P != F);\
+ assert((M)->user_data, chunksize(P) == small_index2size(I));\
+ if (B == F)\
+ clear_smallmap(M, I);\
+ else if (RTCHECK(ok_address(M, F))) {\
+ B->fd = F;\
+ F->bk = B;\
+ }\
+ else {\
+ CORRUPTION_ERROR_ACTION(M);\
+ }\
+}
+
+/* Replace dv node, binning the old one */
+/* Used only when dvsize known to be small */
+#define replace_dv(M, P, S) {\
+ size_t DVS = M->dvsize;\
+ if (DVS != 0) {\
+ mchunkptr DV = M->dv;\
+ assert((M)->user_data, is_small(DVS));\
+ insert_small_chunk(M, DV, DVS);\
+ }\
+ M->dvsize = S;\
+ M->dv = P;\
+}
+
+
+/* ------------------------- Operations on trees ------------------------- */
+
+/* Insert chunk into tree */
+#define insert_large_chunk(M, X, S) {\
+ tbinptr* H;\
+ bindex_t I;\
+ compute_tree_index(S, I);\
+ H = treebin_at(M, I);\
+ X->index = I;\
+ X->child[0] = X->child[1] = 0;\
+ if (!treemap_is_marked(M, I)) {\
+ mark_treemap(M, I);\
+ *H = X;\
+ X->parent = (tchunkptr)H;\
+ X->fd = X->bk = X;\
+ }\
+ else {\
+ tchunkptr T = *H;\
+ size_t K = S << leftshift_for_tree_index(I);\
+ for (;;) {\
+ if (chunksize(T) != S) {\
+ tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\
+ K <<= 1;\
+ if (*C != 0)\
+ T = *C;\
+ else if (RTCHECK(ok_address(M, C))) {\
+ *C = X;\
+ X->parent = T;\
+ X->fd = X->bk = X;\
+ break;\
+ }\
+ else {\
+ CORRUPTION_ERROR_ACTION(M);\
+ break;\
+ }\
+ }\
+ else {\
+ tchunkptr F = T->fd;\
+ if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\
+ T->fd = F->bk = X;\
+ X->fd = F;\
+ X->bk = T;\
+ X->parent = 0;\
+ break;\
+ }\
+ else {\
+ CORRUPTION_ERROR_ACTION(M);\
+ break;\
+ }\
+ }\
+ }\
+ }\
+}
+
+/*
+ Unlink steps:
+
+ 1. If x is a chained node, unlink it from its same-sized fd/bk links
+ and choose its bk node as its replacement.
+ 2. If x was the last node of its size, but not a leaf node, it must
+ be replaced with a leaf node (not merely one with an open left or
+ right), to make sure that lefts and rights of descendents
+ correspond properly to bit masks. We use the rightmost descendent
+ of x. We could use any other leaf, but this is easy to locate and
+ tends to counteract removal of leftmosts elsewhere, and so keeps
+ paths shorter than minimally guaranteed. This doesn't loop much
+ because on average a node in a tree is near the bottom.
+ 3. If x is the base of a chain (i.e., has parent links) relink
+ x's parent and children to x's replacement (or null if none).
+*/
+
+#define unlink_large_chunk(M, X) {\
+ tchunkptr XP = X->parent;\
+ tchunkptr R;\
+ if (X->bk != X) {\
+ tchunkptr F = X->fd;\
+ R = X->bk;\
+ if (RTCHECK(ok_address(M, F))) {\
+ F->bk = R;\
+ R->fd = F;\
+ }\
+ else {\
+ CORRUPTION_ERROR_ACTION(M);\
+ }\
+ }\
+ else {\
+ tchunkptr* RP;\
+ if (((R = *(RP = &(X->child[1]))) != 0) ||\
+ ((R = *(RP = &(X->child[0]))) != 0)) {\
+ tchunkptr* CP;\
+ while ((*(CP = &(R->child[1])) != 0) ||\
+ (*(CP = &(R->child[0])) != 0)) {\
+ R = *(RP = CP);\
+ }\
+ if (RTCHECK(ok_address(M, RP)))\
+ *RP = 0;\
+ else {\
+ CORRUPTION_ERROR_ACTION(M);\
+ }\
+ }\
+ }\
+ if (XP != 0) {\
+ tbinptr* H = treebin_at(M, X->index);\
+ if (X == *H) {\
+ if ((*H = R) == 0) \
+ clear_treemap(M, X->index);\
+ }\
+ else if (RTCHECK(ok_address(M, XP))) {\
+ if (XP->child[0] == X) \
+ XP->child[0] = R;\
+ else \
+ XP->child[1] = R;\
+ }\
+ else\
+ CORRUPTION_ERROR_ACTION(M);\
+ if (R != 0) {\
+ if (RTCHECK(ok_address(M, R))) {\
+ tchunkptr C0, C1;\
+ R->parent = XP;\
+ if ((C0 = X->child[0]) != 0) {\
+ if (RTCHECK(ok_address(M, C0))) {\
+ R->child[0] = C0;\
+ C0->parent = R;\
+ }\
+ else\
+ CORRUPTION_ERROR_ACTION(M);\
+ }\
+ if ((C1 = X->child[1]) != 0) {\
+ if (RTCHECK(ok_address(M, C1))) {\
+ R->child[1] = C1;\
+ C1->parent = R;\
+ }\
+ else\
+ CORRUPTION_ERROR_ACTION(M);\
+ }\
+ }\
+ else\
+ CORRUPTION_ERROR_ACTION(M);\
+ }\
+ }\
+}
+
+/* Relays to large vs small bin operations */
+
+#define insert_chunk(M, P, S)\
+ if (is_small(S)) insert_small_chunk(M, P, S)\
+ else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); }
+
+#define unlink_chunk(M, P, S)\
+ if (is_small(S)) unlink_small_chunk(M, P, S)\
+ else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); }
+
+
+/* Relays to internal calls to malloc/free from realloc, memalign etc */
+
+#define internal_malloc(m, b) mspace_malloc(m, b)
+#define internal_free(m, mem) mspace_free(m,mem);
+
+
+/* -------------------------- mspace management -------------------------- */
+
+/* Initialize top chunk and its size */
+static void init_top(mstate m, mchunkptr p, size_t psize) {
+ /* Ensure alignment */
+ size_t offset = align_offset(chunk2mem(p));
+ p = (mchunkptr)((char*)p + offset);
+ psize -= offset;
+
+ m->top = p;
+ m->topsize = psize;
+ p->head = psize | PINUSE_BIT;
+ /* set size of fake trailing chunk holding overhead space only once */
+ chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE;
+}
+
+/* Initialize bins for a new mstate that is otherwise zeroed out */
+static void init_bins(mstate m) {
+ /* Establish circular links for smallbins */
+ bindex_t i;
+ for (i = 0; i < NSMALLBINS; ++i) {
+ sbinptr bin = smallbin_at(m,i);
+ bin->fd = bin->bk = bin;
+ }
+}
+
+#if PROCEED_ON_ERROR
+
+/* default corruption action */
+static void reset_on_error(mstate m) {
+ int i;
+ ++malloc_corruption_error_count;
+ /* Reinitialize fields to forget about all memory */
+ m->smallbins = m->treebins = 0;
+ m->dvsize = m->topsize = 0;
+ m->seg.base = 0;
+ m->seg.size = 0;
+ m->seg.next = 0;
+ m->top = m->dv = 0;
+ for (i = 0; i < NTREEBINS; ++i)
+ *treebin_at(m, i) = 0;
+ init_bins(m);
+}
+#endif /* PROCEED_ON_ERROR */
+
+/* Allocate chunk and prepend remainder with chunk in successor base. */
+static void* prepend_alloc(mstate m, char* newbase, char* oldbase,
+ size_t nb) {
+ mchunkptr p = align_as_chunk(newbase);
+ mchunkptr oldfirst = align_as_chunk(oldbase);
+ size_t psize = (char*)oldfirst - (char*)p;
+ mchunkptr q = chunk_plus_offset(p, nb);
+ size_t qsize = psize - nb;
+ set_size_and_pinuse_of_inuse_chunk(m, p, nb);
+
+ assert(m->user_data, (char*)oldfirst > (char*)q);
+ assert(m->user_data, pinuse(oldfirst));
+ assert(m->user_data, qsize >= MIN_CHUNK_SIZE);
+
+ /* consolidate remainder with first chunk of old base */
+ if (oldfirst == m->top) {
+ size_t tsize = m->topsize += qsize;
+ m->top = q;
+ q->head = tsize | PINUSE_BIT;
+ check_top_chunk(m, q);
+ }
+ else if (oldfirst == m->dv) {
+ size_t dsize = m->dvsize += qsize;
+ m->dv = q;
+ set_size_and_pinuse_of_free_chunk(q, dsize);
+ }
+ else {
+ if (!cinuse(oldfirst)) {
+ size_t nsize = chunksize(oldfirst);
+ unlink_chunk(m, oldfirst, nsize);
+ oldfirst = chunk_plus_offset(oldfirst, nsize);
+ qsize += nsize;
+ }
+ set_free_with_pinuse(q, qsize, oldfirst);
+ insert_chunk(m, q, qsize);
+ check_free_chunk(m, q);
+ }
+
+ check_malloced_chunk(m, chunk2mem(p), nb);
+ return chunk2mem(p);
+}
+
+/* -------------------------- System allocation -------------------------- */
+
+/* Get memory from system using MORECORE or MMAP */
+static void* sys_alloc(mstate m, size_t nb) {
+ MALLOC_FAILURE_ACTION;
+ return 0;
+}
+
+/* ---------------------------- malloc support --------------------------- */
+
+/* allocate a large request from the best fitting chunk in a treebin */
+static void* tmalloc_large(mstate m, size_t nb) {
+ tchunkptr v = 0;
+ size_t rsize = -nb; /* Unsigned negation */
+ tchunkptr t;
+ bindex_t idx;
+ compute_tree_index(nb, idx);
+
+ if ((t = *treebin_at(m, idx)) != 0) {
+ /* Traverse tree for this bin looking for node with size == nb */
+ size_t sizebits = nb << leftshift_for_tree_index(idx);
+ tchunkptr rst = 0; /* The deepest untaken right subtree */
+ for (;;) {
+ tchunkptr rt;
+ size_t trem = chunksize(t) - nb;
+ if (trem < rsize) {
+ v = t;
+ if ((rsize = trem) == 0)
+ break;
+ }
+ rt = t->child[1];
+ t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
+ if (rt != 0 && rt != t)
+ rst = rt;
+ if (t == 0) {
+ t = rst; /* set t to least subtree holding sizes > nb */
+ break;
+ }
+ sizebits <<= 1;
+ }
+ }
+
+ if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */
+ binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap;
+ if (leftbits != 0) {
+ bindex_t i;
+ binmap_t leastbit = least_bit(leftbits);
+ compute_bit2idx(leastbit, i);
+ t = *treebin_at(m, i);
+ }
+ }
+
+ while (t != 0) { /* find smallest of tree or subtree */
+ size_t trem = chunksize(t) - nb;
+ if (trem < rsize) {
+ rsize = trem;
+ v = t;
+ }
+ t = leftmost_child(t);
+ }
+
+ /* If dv is a better fit, return 0 so malloc will use it */
+ if (v != 0 && rsize < (size_t)(m->dvsize - nb)) {
+ if (RTCHECK(ok_address(m, v))) { /* split */
+ mchunkptr r = chunk_plus_offset(v, nb);
+ assert(m->user_data, chunksize(v) == rsize + nb);
+ if (RTCHECK(ok_next(v, r))) {
+ unlink_large_chunk(m, v);
+ if (rsize < MIN_CHUNK_SIZE)
+ set_inuse_and_pinuse(m, v, (rsize + nb));
+ else {
+ set_size_and_pinuse_of_inuse_chunk(m, v, nb);
+ set_size_and_pinuse_of_free_chunk(r, rsize);
+ insert_chunk(m, r, rsize);
+ }
+ return chunk2mem(v);
+ }
+ }
+ CORRUPTION_ERROR_ACTION(m);
+ }
+ return 0;
+}
+
+/* allocate a small request from the best fitting chunk in a treebin */
+static void* tmalloc_small(mstate m, size_t nb) {
+ tchunkptr t, v;
+ size_t rsize;
+ bindex_t i;
+ binmap_t leastbit = least_bit(m->treemap);
+ compute_bit2idx(leastbit, i);
+
+ v = t = *treebin_at(m, i);
+ rsize = chunksize(t) - nb;
+
+ while ((t = leftmost_child(t)) != 0) {
+ size_t trem = chunksize(t) - nb;
+ if (trem < rsize) {
+ rsize = trem;
+ v = t;
+ }
+ }
+
+ if (RTCHECK(ok_address(m, v))) {
+ mchunkptr r = chunk_plus_offset(v, nb);
+ assert(m->user_data, chunksize(v) == rsize + nb);
+ if (RTCHECK(ok_next(v, r))) {
+ unlink_large_chunk(m, v);
+ if (rsize < MIN_CHUNK_SIZE)
+ set_inuse_and_pinuse(m, v, (rsize + nb));
+ else {
+ set_size_and_pinuse_of_inuse_chunk(m, v, nb);
+ set_size_and_pinuse_of_free_chunk(r, rsize);
+ replace_dv(m, r, rsize);
+ }
+ return chunk2mem(v);
+ }
+ }
+
+ CORRUPTION_ERROR_ACTION(m);
+ return 0;
+}
+
+/* --------------------------- realloc support --------------------------- */
+
+static void* internal_realloc(mstate m, void* oldmem, size_t bytes) {
+ if (bytes >= MAX_REQUEST) {
+ MALLOC_FAILURE_ACTION;
+ return 0;
+ }
+ if (!PREACTION(m)) {
+ mchunkptr oldp = mem2chunk(oldmem);
+ size_t oldsize = chunksize(oldp);
+ mchunkptr next = chunk_plus_offset(oldp, oldsize);
+ mchunkptr newp = 0;
+ void* extra = 0;
+
+ /* Try to either shrink or extend into top. Else malloc-copy-free */
+
+ if (RTCHECK(ok_address(m, oldp) && ok_cinuse(oldp) &&
+ ok_next(oldp, next) && ok_pinuse(next))) {
+ size_t nb = request2size(bytes);
+ if (oldsize >= nb) { /* already big enough */
+ size_t rsize = oldsize - nb;
+ newp = oldp;
+ if (rsize >= MIN_CHUNK_SIZE) {
+ mchunkptr remainder = chunk_plus_offset(newp, nb);
+ set_inuse(m, newp, nb);
+ set_inuse(m, remainder, rsize);
+ extra = chunk2mem(remainder);
+ }
+ }
+ else if (next == m->top && oldsize + m->topsize > nb) {
+ /* Expand into top */
+ size_t newsize = oldsize + m->topsize;
+ size_t newtopsize = newsize - nb;
+ mchunkptr newtop = chunk_plus_offset(oldp, nb);
+ set_inuse(m, oldp, nb);
+ newtop->head = newtopsize |PINUSE_BIT;
+ m->top = newtop;
+ m->topsize = newtopsize;
+ newp = oldp;
+ }
+ }
+ else {
+ USAGE_ERROR_ACTION(m, oldmem);
+ POSTACTION(m);
+ return 0;
+ }
+
+ POSTACTION(m);
+
+ if (newp != 0) {
+ if (extra != 0) {
+ internal_free(m, extra);
+ }
+ check_inuse_chunk(m, newp);
+ return chunk2mem(newp);
+ }
+ else {
+ void* newmem = internal_malloc(m, bytes);
+ if (newmem != 0) {
+ size_t oc = oldsize - overhead_for(oldp);
+ MEMCPY(newmem, oldmem, (oc < bytes)? oc : bytes);
+ internal_free(m, oldmem);
+ }
+ return newmem;
+ }
+ }
+ return 0;
+}
+
+/* --------------------------- memalign support -------------------------- */
+
+static void* internal_memalign(mstate m, size_t alignment, size_t bytes) {
+ if (alignment <= MALLOC_ALIGNMENT) /* Can just use malloc */
+ return internal_malloc(m, bytes);
+ if (alignment < MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */
+ alignment = MIN_CHUNK_SIZE;
+ if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */
+ size_t a = MALLOC_ALIGNMENT << 1;
+ while (a < alignment) a <<= 1;
+ alignment = a;
+ }
+
+ if (bytes >= MAX_REQUEST - alignment) {
+ if (m != 0) { /* Test isn't needed but avoids compiler warning */
+ MALLOC_FAILURE_ACTION;
+ }
+ }
+ else {
+ size_t nb = request2size(bytes);
+ size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD;
+ char* mem = (char*)internal_malloc(m, req);
+ if (mem != 0) {
+ void* leader = 0;
+ void* trailer = 0;
+ mchunkptr p = mem2chunk(mem);
+
+ if (PREACTION(m)) return 0;
+ if ((((size_t)(mem)) % alignment) != 0) { /* misaligned */
+ /*
+ Find an aligned spot inside chunk. Since we need to give
+ back leading space in a chunk of at least MIN_CHUNK_SIZE, if
+ the first calculation places us at a spot with less than
+ MIN_CHUNK_SIZE leader, we can move to the next aligned spot.
+ We've allocated enough total room so that this is always
+ possible.
+ */
+ char* br = (char*)mem2chunk((size_t)(((size_t)(mem +
+ alignment -
+ SIZE_T_ONE)) &
+ -alignment));
+ char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)?
+ br : br+alignment;
+ mchunkptr newp = (mchunkptr)pos;
+ size_t leadsize = pos - (char*)(p);
+ size_t newsize = chunksize(p) - leadsize;
+
+ /* Otherwise, give back leader, use the rest */
+ set_inuse(m, newp, newsize);
+ set_inuse(m, p, leadsize);
+ leader = chunk2mem(p);
+
+ p = newp;
+ }
+
+ assert(m->user_data, chunksize(p) >= nb);
+ assert(m->user_data, (((size_t)(chunk2mem(p))) % alignment) == 0);
+ check_inuse_chunk(m, p);
+ POSTACTION(m);
+ if (leader != 0) {
+ internal_free(m, leader);
+ }
+ if (trailer != 0) {
+ internal_free(m, trailer);
+ }
+ return chunk2mem(p);
+ }
+ }
+ return 0;
+}
+
+/* ----------------------------- user mspaces ---------------------------- */
+
+static mstate init_user_mstate(char* tbase, size_t tsize, void *user_data) {
+ size_t msize = pad_request(sizeof(struct malloc_state));
+ mchunkptr mn;
+ mchunkptr msp = align_as_chunk(tbase);
+ mstate m = (mstate)(chunk2mem(msp));
+ MEMCLEAR(m, msize);
+ INITIAL_LOCK(&m->mutex);
+ msp->head = (msize|PINUSE_BIT|CINUSE_BIT);
+ m->seg.base = m->least_addr = tbase;
+ m->seg.size = m->footprint = m->max_footprint = tsize;
+ m->magic = mparams.magic;
+ m->mflags = mparams.default_mflags;
+ m->user_data = user_data;
+ init_bins(m);
+ mn = next_chunk(mem2chunk(m));
+ init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE);
+ check_top_chunk(m, m->top);
+ return m;
+}
+
+mspace create_mspace_with_base(void* base, size_t capacity, int locked, void *user_data) {
+ mstate m = 0;
+ size_t msize = pad_request(sizeof(struct malloc_state));
+ init_mparams(); /* Ensure pagesize etc initialized */
+
+ if (capacity > msize + TOP_FOOT_SIZE &&
+ capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {
+ m = init_user_mstate((char*)base, capacity, user_data);
+ set_lock(m, locked);
+ }
+ return (mspace)m;
+}
+
+/*
+ mspace versions of routines are near-clones of the global
+ versions. This is not so nice but better than the alternatives.
+*/
+
+
+void* mspace_malloc(mspace msp, size_t bytes) {
+ mstate ms = (mstate)msp;
+ if (!ok_magic(ms)) {
+ USAGE_ERROR_ACTION(ms,ms);
+ return 0;
+ }
+ if (!PREACTION(ms)) {
+ void* mem;
+ size_t nb;
+ if (bytes <= MAX_SMALL_REQUEST) {
+ bindex_t idx;
+ binmap_t smallbits;
+ nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);
+ idx = small_index(nb);
+ smallbits = ms->smallmap >> idx;
+
+ if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
+ mchunkptr b, p;
+ idx += ~smallbits & 1; /* Uses next bin if idx empty */
+ b = smallbin_at(ms, idx);
+ p = b->fd;
+ assert(ms->user_data, chunksize(p) == small_index2size(idx));
+ unlink_first_small_chunk(ms, b, p, idx);
+ set_inuse_and_pinuse(ms, p, small_index2size(idx));
+ mem = chunk2mem(p);
+ check_malloced_chunk(ms, mem, nb);
+ goto postaction;
+ }
+
+ else if (nb > ms->dvsize) {
+ if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
+ mchunkptr b, p, r;
+ size_t rsize;
+ bindex_t i;
+ binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
+ binmap_t leastbit = least_bit(leftbits);
+ compute_bit2idx(leastbit, i);
+ b = smallbin_at(ms, i);
+ p = b->fd;
+ assert(ms->user_data, chunksize(p) == small_index2size(i));
+ unlink_first_small_chunk(ms, b, p, i);
+ rsize = small_index2size(i) - nb;
+ /* Fit here cannot be remainderless if 4byte sizes */
+ if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
+ set_inuse_and_pinuse(ms, p, small_index2size(i));
+ else {
+ set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
+ r = chunk_plus_offset(p, nb);
+ set_size_and_pinuse_of_free_chunk(r, rsize);
+ replace_dv(ms, r, rsize);
+ }
+ mem = chunk2mem(p);
+ check_malloced_chunk(ms, mem, nb);
+ goto postaction;
+ }
+
+ else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) {
+ check_malloced_chunk(ms, mem, nb);
+ goto postaction;
+ }
+ }
+ }
+ else if (bytes >= MAX_REQUEST)
+ nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
+ else {
+ nb = pad_request(bytes);
+ if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) {
+ check_malloced_chunk(ms, mem, nb);
+ goto postaction;
+ }
+ }
+
+ if (nb <= ms->dvsize) {
+ size_t rsize = ms->dvsize - nb;
+ mchunkptr p = ms->dv;
+ if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
+ mchunkptr r = ms->dv = chunk_plus_offset(p, nb);
+ ms->dvsize = rsize;
+ set_size_and_pinuse_of_free_chunk(r, rsize);
+ set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
+ }
+ else { /* exhaust dv */
+ size_t dvs = ms->dvsize;
+ ms->dvsize = 0;
+ ms->dv = 0;
+ set_inuse_and_pinuse(ms, p, dvs);
+ }
+ mem = chunk2mem(p);
+ check_malloced_chunk(ms, mem, nb);
+ goto postaction;
+ }
+
+ else if (nb < ms->topsize) { /* Split top */
+ size_t rsize = ms->topsize -= nb;
+ mchunkptr p = ms->top;
+ mchunkptr r = ms->top = chunk_plus_offset(p, nb);
+ r->head = rsize | PINUSE_BIT;
+ set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
+ mem = chunk2mem(p);
+ check_top_chunk(ms, ms->top);
+ check_malloced_chunk(ms, mem, nb);
+ goto postaction;
+ }
+
+ mem = sys_alloc(ms, nb);
+
+ postaction:
+ POSTACTION(ms);
+ return mem;
+ }
+
+ return 0;
+}
+
+void mspace_free(mspace msp, void* mem) {
+ if (mem != 0) {
+ mchunkptr p = mem2chunk(mem);
+#if FOOTERS
+ mstate fm = get_mstate_for(p);
+#else /* FOOTERS */
+ mstate fm = (mstate)msp;
+#endif /* FOOTERS */
+ if (!ok_magic(fm)) {
+ USAGE_ERROR_ACTION(fm, p);
+ return;
+ }
+ if (!PREACTION(fm)) {
+ check_inuse_chunk(fm, p);
+ if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) {
+ size_t psize = chunksize(p);
+ mchunkptr next = chunk_plus_offset(p, psize);
+ if (!pinuse(p)) {
+ size_t prevsize = p->prev_foot;
+
+ mchunkptr prev = chunk_minus_offset(p, prevsize);
+ psize += prevsize;
+ p = prev;
+ if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
+ if (p != fm->dv) {
+ unlink_chunk(fm, p, prevsize);
+ }
+ else if ((next->head & INUSE_BITS) == INUSE_BITS) {
+ fm->dvsize = psize;
+ set_free_with_pinuse(p, psize, next);
+ goto postaction;
+ }
+ }
+ else
+ goto erroraction;
+ }
+
+ if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
+ if (!cinuse(next)) { /* consolidate forward */
+ if (next == fm->top) {
+ size_t tsize = fm->topsize += psize;
+ fm->top = p;
+ p->head = tsize | PINUSE_BIT;
+ if (p == fm->dv) {
+ fm->dv = 0;
+ fm->dvsize = 0;
+ }
+ goto postaction;
+ }
+ else if (next == fm->dv) {
+ size_t dsize = fm->dvsize += psize;
+ fm->dv = p;
+ set_size_and_pinuse_of_free_chunk(p, dsize);
+ goto postaction;
+ }
+ else {
+ size_t nsize = chunksize(next);
+ psize += nsize;
+ unlink_chunk(fm, next, nsize);
+ set_size_and_pinuse_of_free_chunk(p, psize);
+ if (p == fm->dv) {
+ fm->dvsize = psize;
+ goto postaction;
+ }
+ }
+ }
+ else
+ set_free_with_pinuse(p, psize, next);
+ insert_chunk(fm, p, psize);
+ check_free_chunk(fm, p);
+ goto postaction;
+ }
+ }
+ erroraction:
+ USAGE_ERROR_ACTION(fm, p);
+ postaction:
+ POSTACTION(fm);
+ }
+ }
+}
+
+void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) {
+ void* mem;
+ size_t req = 0;
+ mstate ms = (mstate)msp;
+ if (!ok_magic(ms)) {
+ USAGE_ERROR_ACTION(ms,ms);
+ return 0;
+ }
+ if (n_elements != 0) {
+ req = n_elements * elem_size;
+ if (((n_elements | elem_size) & ~(size_t)0xffff) &&
+ (req / n_elements != elem_size))
+ req = MAX_SIZE_T; /* force downstream failure on overflow */
+ }
+ mem = internal_malloc(ms, req);
+ if (mem != 0 && calloc_must_clear(mem2chunk(mem)))
+ MEMCLEAR(mem, req);
+ return mem;
+}
+
+void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) {
+ if (oldmem == 0)
+ return mspace_malloc(msp, bytes);
+#ifdef REALLOC_ZERO_BYTES_FREES
+ if (bytes == 0) {
+ mspace_free(msp, oldmem);
+ return 0;
+ }
+#endif /* REALLOC_ZERO_BYTES_FREES */
+ else {
+#if FOOTERS
+ mchunkptr p = mem2chunk(oldmem);
+ mstate ms = get_mstate_for(p);
+#else /* FOOTERS */
+ mstate ms = (mstate)msp;
+#endif /* FOOTERS */
+ if (!ok_magic(ms)) {
+ USAGE_ERROR_ACTION(ms,ms);
+ return 0;
+ }
+ return internal_realloc(ms, oldmem, bytes);
+ }
+}
+
+void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) {
+ mstate ms = (mstate)msp;
+ if (!ok_magic(ms)) {
+ USAGE_ERROR_ACTION(ms,ms);
+ return 0;
+ }
+ return internal_memalign(ms, alignment, bytes);
+}
+
+void mspace_malloc_stats(mspace msp) {
+ mstate ms = (mstate)msp;
+ if (ok_magic(ms)) {
+ internal_malloc_stats(ms);
+ }
+ else {
+ USAGE_ERROR_ACTION(ms,ms);
+ }
+}
+
+size_t mspace_footprint(mspace msp) {
+ size_t result;
+ mstate ms = (mstate)msp;
+ if (ok_magic(ms)) {
+ result = ms->footprint;
+ } else {
+ USAGE_ERROR_ACTION(ms,ms);
+ }
+ return result;
+}
+
+
+size_t mspace_max_footprint(mspace msp) {
+ size_t result;
+ mstate ms = (mstate)msp;
+ if (ok_magic(ms)) {
+ result = ms->max_footprint;
+ } else {
+ USAGE_ERROR_ACTION(ms,ms);
+ }
+ return result;
+}
+
+
+#if !NO_MALLINFO
+struct mallinfo mspace_mallinfo(mspace msp) {
+ mstate ms = (mstate)msp;
+ if (!ok_magic(ms)) {
+ USAGE_ERROR_ACTION(ms,ms);
+ }
+ return internal_mallinfo(ms);
+}
+#endif /* NO_MALLINFO */
+
+int mspace_mallopt(int param_number, int value) {
+ return change_mparam(param_number, value);
+}
+
diff --git a/qxldod/mspace.h b/qxldod/mspace.h
new file mode 100755
index 0000000..16e20bf
--- /dev/null
+++ b/qxldod/mspace.h
@@ -0,0 +1,150 @@
+#ifndef _H_MSPACE
+#define _H_MSPACE
+
+#define NO_MALLINFO 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+//typedef unsigned long size_t;
+typedef void (*mspace_abort_t)(void *user_data);
+typedef void (*mspace_print_t)(void *user_data, char *format, ...);
+
+void mspace_set_abort_func(mspace_abort_t f);
+void mspace_set_print_func(mspace_print_t f);
+
+/*
+ mspace is an opaque type representing an independent
+ region of space that supports mspace_malloc, etc.
+*/
+typedef void* mspace;
+
+/*
+ create_mspace creates and returns a new independent space with the
+ given initial capacity, or, if 0, the default granularity size. It
+ returns null if there is no system memory available to create the
+ space. If argument locked is non-zero, the space uses a separate
+ lock to control access. The capacity of the space will grow
+ dynamically as needed to service mspace_malloc requests. You can
+ control the sizes of incremental increases of this space by
+ compiling with a different DEFAULT_GRANULARITY or dynamically
+ setting with mallopt(M_GRANULARITY, value).
+*/
+//mspace create_mspace(size_t capacity, int locked);
+
+/*
+ destroy_mspace destroys the given space, and attempts to return all
+ of its memory back to the system, returning the total number of
+ bytes freed. After destruction, the results of access to all memory
+ used by the space become undefined.
+*/
+//size_t destroy_mspace(mspace msp);
+
+/*
+ create_mspace_with_base uses the memory supplied as the initial base
+ of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this
+ space is used for bookkeeping, so the capacity must be at least this
+ large. (Otherwise 0 is returned.) When this initial space is
+ exhausted, additional memory will be obtained from the system.
+ Destroying this space will deallocate all additionally allocated
+ space (if possible) but not the initial base.
+*/
+mspace create_mspace_with_base(void* base, size_t capacity, int locked, void *user_data);
+
+/*
+ mspace_malloc behaves as malloc, but operates within
+ the given space.
+*/
+void* mspace_malloc(mspace msp, size_t bytes);
+
+/*
+ mspace_free behaves as free, but operates within
+ the given space.
+
+ If compiled with FOOTERS==1, mspace_free is not actually needed.
+ free may be called instead of mspace_free because freed chunks from
+ any space are handled by their originating spaces.
+*/
+void mspace_free(mspace msp, void* mem);
+
+/*
+ mspace_realloc behaves as realloc, but operates within
+ the given space.
+
+ If compiled with FOOTERS==1, mspace_realloc is not actually
+ needed. realloc may be called instead of mspace_realloc because
+ realloced chunks from any space are handled by their originating
+ spaces.
+*/
+void* mspace_realloc(mspace msp, void* mem, size_t newsize);
+
+/*
+ mspace_calloc behaves as calloc, but operates within
+ the given space.
+*/
+void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);
+
+/*
+ mspace_memalign behaves as memalign, but operates within
+ the given space.
+*/
+void* mspace_memalign(mspace msp, size_t alignment, size_t bytes);
+
+/*
+ mspace_independent_calloc behaves as independent_calloc, but
+ operates within the given space.
+*/
+//void** mspace_independent_calloc(mspace msp, size_t n_elements,
+// size_t elem_size, void* chunks[]);
+
+/*
+ mspace_independent_comalloc behaves as independent_comalloc, but
+ operates within the given space.
+*/
+//void** mspace_independent_comalloc(mspace msp, size_t n_elements,
+// size_t sizes[], void* chunks[]);
+
+/*
+ mspace_footprint() returns the number of bytes obtained from the
+ system for this space.
+*/
+size_t mspace_footprint(mspace msp);
+
+/*
+ mspace_max_footprint() returns the peak number of bytes obtained from the
+ system for this space.
+*/
+size_t mspace_max_footprint(mspace msp);
+
+
+#if !NO_MALLINFO
+/*
+ mspace_mallinfo behaves as mallinfo, but reports properties of
+ the given space.
+*/
+struct mallinfo mspace_mallinfo(mspace msp);
+#endif /* NO_MALLINFO */
+
+/*
+ mspace_malloc_stats behaves as malloc_stats, but reports
+ properties of the given space.
+*/
+void mspace_malloc_stats(mspace msp);
+
+/*
+ mspace_trim behaves as malloc_trim, but
+ operates within the given space.
+*/
+//int mspace_trim(mspace msp, size_t pad);
+
+/*
+ An alias for mallopt.
+*/
+int mspace_mallopt(int, int);
+
+#ifdef __cplusplus
+}; /* end of extern "C" */
+#endif /* __cplusplus */
+
+#endif
diff --git a/qxldod/qxldod.inf b/qxldod/qxldod.inf
new file mode 100755
index 0000000..af324ea
--- /dev/null
+++ b/qxldod/qxldod.inf
Binary files differ
diff --git a/qxldod/qxldod.rc b/qxldod/qxldod.rc
new file mode 100755
index 0000000..ba45879
--- /dev/null
+++ b/qxldod/qxldod.rc
Binary files differ
diff --git a/qxldod/qxldod.vcxproj b/qxldod/qxldod.vcxproj
new file mode 100755
index 0000000..510d748
--- /dev/null
+++ b/qxldod/qxldod.vcxproj
@@ -0,0 +1,290 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Win8.1 Debug|Win32">
+ <Configuration>Win8.1 Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win8 Debug|Win32">
+ <Configuration>Win8 Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win8.1 Release|Win32">
+ <Configuration>Win8.1 Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win8 Release|Win32">
+ <Configuration>Win8 Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win8.1 Debug|x64">
+ <Configuration>Win8.1 Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win8 Debug|x64">
+ <Configuration>Win8 Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win8.1 Release|x64">
+ <Configuration>Win8.1 Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win8 Release|x64">
+ <Configuration>Win8 Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{A6F48FC7-97E9-48EC-BCDF-1E4F9B43AADD}</ProjectGuid>
+ <TemplateGuid>{dd38f7fc-d7bd-488b-9242-7d8754cde80d}</TemplateGuid>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
+ <Configuration>Win8 Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ </PropertyGroup>
+ <PropertyGroup Label="Globals">
+ <RootNamespace>qxldod</RootNamespace>
+ <VCTargetsPath Condition="'$(VCTargetsPath11)' != '' and '$(VisualStudioVersion)' == '11.0'">$(VCTargetsPath11)</VCTargetsPath>
+ </PropertyGroup>
+ <PropertyGroup Label="PropertySheets">
+ <ConfigurationType>Driver</ConfigurationType>
+ <DriverType>WDM</DriverType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Win8.1 Debug|Win32'">
+ <TargetVersion>WindowsV6.3</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'" Label="Configuration">
+ <TargetVersion>Windows8</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Win8.1 Release|Win32'">
+ <TargetVersion>WindowsV6.3</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'" Label="Configuration">
+ <TargetVersion>Windows8</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Win8.1 Debug|x64'">
+ <TargetVersion>WindowsV6.3</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'" Label="Configuration">
+ <TargetVersion>Windows8</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Win8.1 Release|x64'">
+ <TargetVersion>WindowsV6.3</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'" Label="Configuration">
+ <TargetVersion>Windows8</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8.1 Debug|Win32'">
+ <OutDir>objchk_win8_x86\i386\</OutDir>
+ <IntDir>objchk_win8_x86\i386\</IntDir>
+ <TargetName>qxldod</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">
+ <OutDir>objchk_win8_x86\i386\</OutDir>
+ <IntDir>objchk_win8_x86\i386\</IntDir>
+ <TargetName>qxldod</TargetName>
+ </PropertyGroup>
+ <PropertyGroup>
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8.1 Release|Win32'">
+ <OutDir>objfre_win8_x86\i386\</OutDir>
+ <IntDir>objfre_win8_x86\i386\</IntDir>
+ <TargetName>qxldod</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">
+ <OutDir>objfre_win8_x86\i386\</OutDir>
+ <IntDir>objfre_win8_x86\i386\</IntDir>
+ <TargetName>qxldod</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8.1 Release|x64'">
+ <OutDir>objfre_win8_amd64\amd64\</OutDir>
+ <IntDir>objfre_win8_amd64\amd64\</IntDir>
+ <TargetName>qxldod</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">
+ <OutDir>objfre_win8_amd64\amd64\</OutDir>
+ <IntDir>objfre_win8_amd64\amd64\</IntDir>
+ <TargetName>qxldod</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8.1 Debug|x64'">
+ <OutDir>objchk_win8_amd64\amd64\</OutDir>
+ <IntDir>objchk_win8_amd64\amd64\</IntDir>
+ <TargetName>qxldod</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">
+ <OutDir>objchk_win8_amd64\amd64\</OutDir>
+ <IntDir>objchk_win8_amd64\amd64\</IntDir>
+ <TargetName>qxldod</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Win8.1 Debug|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\hal.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH);.\Include</AdditionalIncludeDirectories>
+ <WarningLevel>Level3</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <PostBuildEvent>
+ <Command>Inf2Cat /driver:$(OutDir) /os:8_X86</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\hal.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH);.\Include</AdditionalIncludeDirectories>
+ <WarningLevel>Level3</WarningLevel>
+ <ExceptionHandling />
+ </ClCompile>
+ <PostBuildEvent>
+ <Command>Inf2Cat /driver:$(OutDir) /os:8_X86</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Win8.1 Release|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\hal.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH);.\Include</AdditionalIncludeDirectories>
+ <WarningLevel>Level3</WarningLevel>
+ </ClCompile>
+ <PostBuildEvent>
+ <Command>Inf2Cat /driver:$(OutDir) /os:8_X86</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\hal.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH);.\Include</AdditionalIncludeDirectories>
+ <WarningLevel>Level3</WarningLevel>
+ </ClCompile>
+ <PostBuildEvent>
+ <Command>Inf2Cat /driver:$(OutDir) /os:8_X86</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Win8.1 Debug|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\hal.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH);.\Include</AdditionalIncludeDirectories>
+ </ClCompile>
+ <PostBuildEvent>
+ <Command>Inf2Cat /driver:$(OutDir) /os:8_X64</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\hal.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH);.\Include</AdditionalIncludeDirectories>
+ </ClCompile>
+ <PostBuildEvent>
+ <Command>Inf2Cat /driver:$(OutDir) /os:8_X64</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Win8.1 Release|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\hal.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH);.\Include</AdditionalIncludeDirectories>
+ <WarningLevel>Level3</WarningLevel>
+ </ClCompile>
+ <PostBuildEvent>
+ <Command>Inf2Cat /driver:$(OutDir) /os:8_X64</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\hal.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH);.\Include</AdditionalIncludeDirectories>
+ <WarningLevel>Level3</WarningLevel>
+ </ClCompile>
+ <PostBuildEvent>
+ <Command>Inf2Cat /driver:$(OutDir) /os:8_X64</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <Inf Include="qxldod.inf" />
+ </ItemGroup>
+ <ItemGroup>
+ <FilesToPackage Include="$(TargetPath)" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="BaseObject.h" />
+ <ClInclude Include="driver.h" />
+ <ClInclude Include="QxlDod.h" />
+ <ClInclude Include="resource.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="BaseObject.cpp" />
+ <ClCompile Include="driver.cpp" />
+ <ClCompile Include="mspace.c" />
+ <ClCompile Include="QxlDod.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="qxldod.rc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/qxldod/qxldod.vcxproj.filters b/qxldod/qxldod.vcxproj.filters
new file mode 100755
index 0000000..4b444ed
--- /dev/null
+++ b/qxldod/qxldod.vcxproj.filters
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ <Filter Include="Driver Files">
+ <UniqueIdentifier>{8E41214B-6785-4CFE-B992-037D68949A14}</UniqueIdentifier>
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Include="qxldod.inf">
+ <Filter>Driver Files</Filter>
+ </Inf>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="BaseObject.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="driver.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="QxlDod.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="BaseObject.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="driver.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="QxlDod.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="mspace.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="qxldod.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/qxldod/resource.h b/qxldod/resource.h
new file mode 100755
index 0000000..4c0462f
--- /dev/null
+++ b/qxldod/resource.h
@@ -0,0 +1,14 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by qxldod.rc
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif