diff options
author | Yonit Halperin <yhalperi@redhat.com> | 2013-05-13 15:39:24 -0400 |
---|---|---|
committer | Yonit Halperin <yhalperi@redhat.com> | 2013-05-13 15:39:24 -0400 |
commit | 1ef0bee1ef095aec6c0a85b9d60353355e39165c (patch) | |
tree | 428673f6b6a453cb8aadab5b57860940c2c5f85e | |
parent | a4ddf412b83dfc70e829b0e83423b3dbc0b50c66 (diff) |
map qxl memory and io port
-rw-r--r-- | C++/bdd.cxx | 261 | ||||
-rw-r--r-- | C++/bdd.hxx | 23 |
2 files changed, 279 insertions, 5 deletions
diff --git a/C++/bdd.cxx b/C++/bdd.cxx index a0b4524..02c2afe 100644 --- a/C++/bdd.cxx +++ b/C++/bdd.cxx @@ -9,6 +9,7 @@ #include "BDD.hxx"
+#include "qxl.hxx"
#pragma code_seg("PAGE")
@@ -24,7 +25,9 @@ BASIC_DISPLAY_DRIVER::BASIC_DISPLAY_DRIVER(_In_ DEVICE_OBJECT* pPhysicalDeviceOb RtlZeroMemory(&m_StartInfo, sizeof(m_StartInfo));
RtlZeroMemory(m_CurrentModes, sizeof(m_CurrentModes));
RtlZeroMemory(&m_DeviceInfo, sizeof(m_DeviceInfo));
-
+ RtlZeroMemory(&m_mem_regions, sizeof(m_mem_regions));
+ m_ram_header = NULL;
+ m_rom = NULL;
for (UINT i=0;i<MAX_VIEWS;i++)
{
@@ -40,14 +43,196 @@ BASIC_DISPLAY_DRIVER::~BASIC_DISPLAY_DRIVER() CleanUp();
}
+NTSTATUS BASIC_DISPLAY_DRIVER::QxlInitRom()
+{
+ NTSTATUS status;
+ QXLRom *rom;
+
+ PAGED_CODE();
+ LogMessage("%s\n", __FUNCTION__);
+ if (m_mem_regions[QXL_ROM_RANGE_INDEX].size < sizeof(QXLRom)) {
+ LogMessage("%s: bad rom size - too small\n", __FUNCTION__);
+ return STATUS_BAD_DATA;
+ }
+ status = m_DxgkInterface.DxgkCbMapMemory(m_DxgkInterface.DeviceHandle,
+ m_mem_regions[QXL_ROM_RANGE_INDEX].phys_start,
+ m_mem_regions[QXL_ROM_RANGE_INDEX].size,
+ FALSE, FALSE,
+ MmNonCached,
+ &m_mem_regions[QXL_ROM_RANGE_INDEX].mapped_start);
+ if (!NT_SUCCESS(status)) {
+ LogMessage("%s: error mapping rom\n", __FUNCTION__);
+ return status;
+ }
+
+ rom = (QXLRom*)m_mem_regions[QXL_ROM_RANGE_INDEX].mapped_start;
+ if (rom->magic != QXL_ROM_MAGIC) { + LogMessage("%s: bad rom magic\n", __FUNCTION__); + status = STATUS_BAD_DATA; + goto error; + }
+ m_rom = rom;
+
+ return STATUS_SUCCESS;
+error:
+ m_DxgkInterface.DxgkCbUnmapMemory(m_DxgkInterface.DeviceHandle,
+ m_mem_regions[QXL_ROM_RANGE_INDEX].mapped_start);
+ m_mem_regions[QXL_ROM_RANGE_INDEX].mapped_start = NULL;
+ return status;
+}
+
+NTSTATUS BASIC_DISPLAY_DRIVER::QxlInitRam()
+{
+ QXLRam *ram_header;
+ NTSTATUS status;
+
+ PAGED_CODE();
+ LogMessage("%s\n", __FUNCTION__);
+ if (m_rom == NULL) {
+ LogMessage("%s: Error, rom not initialized\n", __FUNCTION__);
+ return STATUS_BAD_DATA;
+ }
+ if (m_mem_regions[QXL_RAM_RANGE_INDEX].size < sizeof(QXLRam) + m_rom->ram_header_offset) {
+ LogMessage("%s: Error, ram size too small (1)\n", __FUNCTION__);
+ return STATUS_BAD_DATA;
+ }
+
+ if (m_mem_regions[QXL_RAM_RANGE_INDEX].size < m_rom->num_pages << QXL_PAGE_SHIFT) {
+ LogMessage("%s: Error, ram size too small (2)\n", __FUNCTION__);
+ return STATUS_BAD_DATA;
+ }
+
+ status = m_DxgkInterface.DxgkCbMapMemory(m_DxgkInterface.DeviceHandle,
+ m_mem_regions[QXL_RAM_RANGE_INDEX].phys_start,
+ m_mem_regions[QXL_RAM_RANGE_INDEX].size,
+ FALSE, FALSE,
+ MmNonCached,
+ &m_mem_regions[QXL_RAM_RANGE_INDEX].mapped_start);
+ if (!NT_SUCCESS(status)) {
+ LogMessage("%s: error mapping ram\n", __FUNCTION__);
+ return status;
+ }
+ ram_header = (QXLRam *)((UINT8 *)m_mem_regions[QXL_RAM_RANGE_INDEX].mapped_start + m_rom->ram_header_offset); + if (ram_header->magic != QXL_RAM_MAGIC) { + LogMessage("%s: bad rom magic\n", __FUNCTION__); + status = STATUS_BAD_DATA; + goto error; + }
+ m_ram_header = ram_header;
+ return STATUS_SUCCESS;
+error:
+ m_DxgkInterface.DxgkCbUnmapMemory(m_DxgkInterface.DeviceHandle,
+ m_mem_regions[QXL_RAM_RANGE_INDEX].mapped_start);
+ m_mem_regions[QXL_RAM_RANGE_INDEX].mapped_start = NULL;
+ return status;
+}
+
+NTSTATUS BASIC_DISPLAY_DRIVER::QxlInitVram()
+{
+ NTSTATUS status;
+
+ PAGED_CODE();
+ LogMessage("%s\n", __FUNCTION__);
+
+ status = m_DxgkInterface.DxgkCbMapMemory(m_DxgkInterface.DeviceHandle,
+ m_mem_regions[QXL_VRAM_RANGE_INDEX].phys_start,
+ m_mem_regions[QXL_VRAM_RANGE_INDEX].size,
+ FALSE, FALSE,
+ MmNonCached,
+ &m_mem_regions[QXL_VRAM_RANGE_INDEX].mapped_start);
+ if (!NT_SUCCESS(status)) {
+ LogMessage("%s: error mapping vram\n", __FUNCTION__);
+ return status;
+ }
+ return STATUS_SUCCESS;
+}
+
+// TODO: not sure if it should even be mapped. What address to use in WRITE_PORT_<x>? the physical low part, or the mapped one?
+NTSTATUS BASIC_DISPLAY_DRIVER::QxlInitIoPort()
+{
+ NTSTATUS status;
+ // TODO: check length according to qxl revision // how to retreive them?
+
+ PAGED_CODE();
+ LogMessage("%s\n", __FUNCTION__);
+
+ status = m_DxgkInterface.DxgkCbMapMemory(m_DxgkInterface.DeviceHandle,
+ m_mem_regions[QXL_IO_RANGE_INDEX].phys_start,
+ m_mem_regions[QXL_IO_RANGE_INDEX].size,
+ TRUE, FALSE,
+ MmNonCached,
+ &m_mem_regions[QXL_IO_RANGE_INDEX].mapped_start);
+ if (!NT_SUCCESS(status)) {
+ LogMessage("%s: error mapping vram\n", __FUNCTION__);
+ return status;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS BASIC_DISPLAY_DRIVER::QxlInit()
+{
+ NTSTATUS status;
+ PAGED_CODE();
+
+ // TODO: see Prob in xddm miniport (get qxl revision data, etc.)
+ status = QxlInitRom();
+ if (!NT_SUCCESS(status)) {
+ LogMessage("%s: init rom failed\n", __FUNCTION__);
+ goto error;
+ }
+
+ status = QxlInitRam();
+ if (!NT_SUCCESS(status)) {
+ LogMessage("%s: init ram failed\n", __FUNCTION__);
+ goto error;
+ }
+
+ status = QxlInitVram();
+ if (!NT_SUCCESS(status)) {
+ LogMessage("%s: init vram failed\n", __FUNCTION__);
+ goto error;
+ }
+
+ status = QxlInitIoPort();
+ if (!NT_SUCCESS(status)) {
+ LogMessage("%s: init ioport failed\n", __FUNCTION__);
+ goto error;
+ }
+
+ // TODO: memslots
+ return STATUS_SUCCESS;
+ // TODO: share validity check code with XDDM. XDDM assumes the rom is mapped before the ram
+
+ // TODO: error if a memory region is mapped twice
+
+ // TODO: unmap in cleanup
+error:
+ QxlCleanup();
+ return status;
+}
+
+VOID BASIC_DISPLAY_DRIVER::QxlCleanup()
+{
+ for (int i = 0; i < QXL_PCI_RANGES; i++) {
+ if (m_mem_regions[i].mapped_start) {
+ m_DxgkInterface.DxgkCbUnmapMemory(m_DxgkInterface.DeviceHandle,
+ m_mem_regions[i].mapped_start);
+ }
+ }
+ RtlZeroMemory(m_mem_regions, sizeof(m_mem_regions));
+ m_rom = NULL;
+ m_ram_header = NULL;
+}
NTSTATUS BASIC_DISPLAY_DRIVER::StartDevice(_In_ DXGK_START_INFO* pDxgkStartInfo,
_In_ DXGKRNL_INTERFACE* pDxgkInterface,
_Out_ ULONG* pNumberOfViews,
_Out_ ULONG* pNumberOfChildren)
{
+ UINT32 mem_range_index = QXL_RAM_RANGE_INDEX;
PAGED_CODE();
-
+ LogMessage("%s", __FUNCTION__);
BDD_ASSERT(pDxgkStartInfo != NULL);
BDD_ASSERT(pDxgkInterface != NULL);
BDD_ASSERT(pNumberOfViews != NULL);
@@ -67,16 +252,78 @@ NTSTATUS BASIC_DISPLAY_DRIVER::StartDevice(_In_ DXGK_START_INFO* pDxgkStartIn return Status;
}
+ // yonit: I don't think we need it
// Ignore return value, since it's not the end of the world if we failed to write these values to the registry
- RegisterHWInfo();
+ // RegisterHWInfo();
- // TODO: Uncomment the line below after updating the TODOs in the function CheckHardware
+
+ // TODO: test revision and other do other validity checks (see xddm FindAdapter and Prob)
+ PCM_RESOURCE_LIST res_list = m_DeviceInfo.TranslatedResourceList;
+ ULONG i, j;
+ LogMessage("%s: Full resources count %lu\n", __FUNCTION__, res_list->Count);
+ for (i = 0; i < res_list->Count; ++i)
+ {
+ PCM_FULL_RESOURCE_DESCRIPTOR res = &res_list->List[i];
+
+ LogMessage("%s: res %lu, PartialResourceList.Count %lu\n",
+ __FUNCTION__, i, res->PartialResourceList.Count);
+ for (j = 0; j < res->PartialResourceList.Count; j++) {
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR prt_res = &res->PartialResourceList.PartialDescriptors[j];
+
+ LogMessage("%s: partial res %lu, type %u, flags %u share %u\n",
+ __FUNCTION__, j, prt_res->Type, prt_res->Flags, prt_res->ShareDisposition);
+ switch (prt_res->Type) {
+ case CmResourceTypePort:
+ LogMessage("%s: port start %X\n", __FUNCTION__, prt_res->u.Port.Start.QuadPart);
+ LogMessage("%s: port size %lu\n", __FUNCTION__, prt_res->u.Port.Length);
+ m_mem_regions[QXL_IO_RANGE_INDEX].phys_start = prt_res->u.Port.Start;
+ m_mem_regions[QXL_IO_RANGE_INDEX].size = prt_res->u.Port.Length;
+
+ // TODO: check validity
+ // I don't know if it should be mapped to IO space. There is a function called WRITE_PORT_<X> (x=UCHAR, etc).
+ // but I'm not sure what its getting
+ break;
+ case CmResourceTypeMemory:
+ // TODO: error if RAM/VRAM/ROM/PORT where already set
+
+ if (mem_range_index < QXL_PCI_RANGES) {
+ m_mem_regions[mem_range_index].phys_start = prt_res->u.Memory.Start;
+ m_mem_regions[mem_range_index].size = prt_res->u.Memory.Length;
+ }
+ switch (mem_range_index) {
+ case QXL_RAM_RANGE_INDEX:
+ LogMessage("%s: RAM\n", __FUNCTION__);
+ mem_range_index = QXL_VRAM_RANGE_INDEX;
+ break;
+ case QXL_VRAM_RANGE_INDEX:
+ LogMessage("%s: VRAM\n", __FUNCTION__);
+ mem_range_index = QXL_ROM_RANGE_INDEX;
+ break;
+ case QXL_ROM_RANGE_INDEX:
+ LogMessage("%s: ROM\n", __FUNCTION__);
+ mem_range_index = QXL_PCI_RANGES;
+ break;
+ default:
+ LogMessage("%s: OTHER\n", __FUNCTION__);
+ // TODO: error?
+ }
+ LogMessage("%s: memory start %X\n", __FUNCTION__, prt_res->u.Memory.Start.QuadPart);
+ LogMessage("%s: memory size %lu\n", __FUNCTION__, prt_res->u.Memory.Length);
+
+ break;
+ default:
+ break;
+ }
+ }
+ }
+// TODO: Uncomment the line below after updating the TODOs in the function CheckHardware
// Status = CheckHardware();
if (!NT_SUCCESS(Status))
{
return Status;
}
+ QxlInit();
// 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));
@@ -86,6 +333,8 @@ NTSTATUS BASIC_DISPLAY_DRIVER::StartDevice(_In_ DXGK_START_INFO* pDxgkStartIn // after a pre-WDDM 1.2 driver. Since we can't draw anything, we should fail to start.
return STATUS_UNSUCCESSFUL;
}
+ LogMessage("%s PostDisplay %ux%u addr %x\n", __FUNCTION__, m_CurrentModes[0].DispInfo.Width, m_CurrentModes[0].DispInfo.Height,
+ m_CurrentModes[0].DispInfo.PhysicAddress.QuadPart);
m_Flags.DriverStarted = TRUE;
*pNumberOfViews = MAX_VIEWS;
*pNumberOfChildren = MAX_CHILDREN;
@@ -117,6 +366,7 @@ VOID BASIC_DISPLAY_DRIVER::CleanUp() m_CurrentModes[Source].Flags.FrameBufferIsActive = FALSE;
}
}
+ QxlCleanup();
}
@@ -145,8 +395,9 @@ NTSTATUS BASIC_DISPLAY_DRIVER::SetPowerState(_In_ ULONG HardwareUi {
if (DevicePowerState == PowerDeviceD0)
{
-
+
// When returning from D3 the device visibility defined to be off for all targets
+ // yonit: see http://msdn.microsoft.com/en-us/library/windows/hardware/jj602806(v=vs.85).aspx
if (m_AdapterPowerState == PowerDeviceD3)
{
DXGKARG_SETVIDPNSOURCEVISIBILITY Visibility;
diff --git a/C++/bdd.hxx b/C++/bdd.hxx index c74c58b..6afdad5 100644 --- a/C++/bdd.hxx +++ b/C++/bdd.hxx @@ -48,6 +48,8 @@ extern "C" #include <ntintsafe.h>
#include <dispmprt.h>
+
+ #include "spice/qxl_dev.h"
};
#include "BDD_ErrorLog.hxx"
@@ -168,6 +170,12 @@ public: };
+typedef struct QxlMemRegionInfo {
+ PHYSICAL_ADDRESS phys_start;
+ PVOID mapped_start;
+ ULONG size;
+} QxlMemRegionInfo;
+
class BASIC_DISPLAY_DRIVER
{
private:
@@ -201,6 +209,11 @@ private: // Device information
DXGK_DEVICE_INFO m_DeviceInfo;
+ QxlMemRegionInfo m_mem_regions[QXL_PCI_RANGES];
+
+ QXLRom *m_rom;
+ QXLRam *m_ram_header;
+
public:
BASIC_DISPLAY_DRIVER(_In_ DEVICE_OBJECT* pPhysicalDeviceObject);
~BASIC_DISPLAY_DRIVER();
@@ -387,6 +400,16 @@ private: // Set the information in the registry as described here: http://msdn.microsoft.com/en-us/library/windows/hardware/ff569240(v=vs.85).aspx
NTSTATUS RegisterHWInfo();
+
+ NTSTATUS QxlInit();
+ NTSTATUS QxlInitRam();
+ NTSTATUS QxlInitRom();
+ NTSTATUS QxlInitVram();
+
+ NTSTATUS QxlInitIoPort();
+
+ VOID QxlCleanup();
+
};
//
|