Skip to content

Commit 25b745b

Browse files
committed
[VIDEOPRT] Expand how resource usage is handled in videoprt
1 parent 7c801c2 commit 25b745b

3 files changed

Lines changed: 379 additions & 38 deletions

File tree

win32ss/drivers/videoprt/resource.c

Lines changed: 227 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626

2727
extern BOOLEAN VpBaseVideo;
2828

29+
static UNICODE_STRING VideoClassName = RTL_CONSTANT_STRING(L"VIDEO");
30+
2931
/* PRIVATE FUNCTIONS **********************************************************/
3032

3133
static BOOLEAN
@@ -209,21 +211,41 @@ IntVideoPortReleaseResources(
209211
// An empty CM_RESOURCE_LIST
210212
UCHAR EmptyResourceList[FIELD_OFFSET(CM_RESOURCE_LIST, List)] = {0};
211213

212-
Status = IoReportResourceForDetection(
213-
DeviceExtension->DriverObject,
214-
NULL, 0, /* Driver List */
215-
DeviceExtension->PhysicalDeviceObject,
216-
(PCM_RESOURCE_LIST)EmptyResourceList,
217-
sizeof(EmptyResourceList),
218-
&ConflictDetected);
214+
if (DeviceExtension->IsLegacyDevice || DeviceExtension->IsLegacyDetect || DeviceExtension->IsVgaDetect)
215+
{
216+
Status = IoReportResourceForDetection(
217+
DeviceExtension->DriverObject,
218+
NULL, 0, /* Driver List */
219+
DeviceExtension->PhysicalDeviceObject,
220+
(PCM_RESOURCE_LIST)EmptyResourceList,
221+
sizeof(EmptyResourceList),
222+
&ConflictDetected);
219223

220-
if (!NT_SUCCESS(Status))
224+
if (!NT_SUCCESS(Status))
225+
{
226+
ERR_(VIDEOPRT,
227+
"VideoPortReleaseResources (Detect) failed with 0x%08lx ; ConflictDetected: %s\n",
228+
Status, ConflictDetected ? "TRUE" : "FALSE");
229+
}
230+
}
231+
else
221232
{
222-
ERR_(VIDEOPRT,
223-
"VideoPortReleaseResources IoReportResource failed with 0x%08lx ; ConflictDetected: %s\n",
224-
Status, ConflictDetected ? "TRUE" : "FALSE");
233+
Status = IoReportResourceUsage(&VideoClassName,
234+
DeviceExtension->DriverObject,
235+
NULL,
236+
0,
237+
DeviceExtension->PhysicalDeviceObject,
238+
(PCM_RESOURCE_LIST)EmptyResourceList,
239+
sizeof(EmptyResourceList),
240+
FALSE,
241+
&ConflictDetected);
242+
if (!NT_SUCCESS(Status))
243+
{
244+
ERR_(VIDEOPRT,
245+
"VideoPortReleaseResources (Usage) failed with 0x%08lx ; ConflictDetected: %s\n",
246+
Status, ConflictDetected ? "TRUE" : "FALSE");
247+
}
225248
}
226-
/* Ignore the returned status however... */
227249
}
228250

229251
NTSTATUS NTAPI
@@ -276,6 +298,38 @@ IntVideoPortMapPhysicalMemory(
276298
return Status;
277299
}
278300

301+
static BOOLEAN
302+
IntAccessRangeIsInAllocatedResources(
303+
_In_ PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension,
304+
_In_ PVIDEO_ACCESS_RANGE Range)
305+
{
306+
CM_RESOURCE_LIST *Res = DeviceExtension->AllocatedResources;
307+
CM_FULL_RESOURCE_DESCRIPTOR *Full;
308+
CM_PARTIAL_RESOURCE_DESCRIPTOR *Desc;
309+
310+
if (!Res || Res->Count == 0)
311+
return FALSE;
312+
Full = &Res->List[0];
313+
for (Desc = Full->PartialResourceList.PartialDescriptors;
314+
Desc < Full->PartialResourceList.PartialDescriptors + Full->PartialResourceList.Count;
315+
++Desc)
316+
{
317+
if (Range->RangeInIoSpace && Desc->Type == CmResourceTypePort)
318+
{
319+
if (Desc->u.Port.Start.QuadPart == Range->RangeStart.QuadPart &&
320+
Desc->u.Port.Length == Range->RangeLength)
321+
return TRUE;
322+
}
323+
else if (!Range->RangeInIoSpace && Desc->Type == CmResourceTypeMemory)
324+
{
325+
if (Desc->u.Memory.Start.QuadPart == Range->RangeStart.QuadPart &&
326+
Desc->u.Memory.Length == Range->RangeLength)
327+
return TRUE;
328+
}
329+
}
330+
return FALSE;
331+
}
332+
279333

280334
PVOID NTAPI
281335
IntVideoPortMapMemory(
@@ -952,12 +1006,82 @@ VideoPortVerifyAccessRanges(
9521006
{
9531007
/* Release the resources and do nothing more for now... */
9541008
IntVideoPortReleaseResources(DeviceExtension);
1009+
/* If releasing VGA device resources, clear tracked ranges */
1010+
if (DeviceExtension->IsVgaDriver)
1011+
{
1012+
KeWaitForMutexObject(&VgaSyncLock, Executive, KernelMode, FALSE, NULL);
1013+
if (VgaRanges)
1014+
{
1015+
ExFreePoolWithTag(VgaRanges, TAG_VIDEO_PORT);
1016+
VgaRanges = NULL;
1017+
}
1018+
NumOfVgaRanges = 0;
1019+
VgaDeviceExtension = NULL;
1020+
KeReleaseMutex(&VgaSyncLock, FALSE);
1021+
}
1022+
return NO_ERROR;
1023+
}
1024+
1025+
/*
1026+
* For non-legacy PCI devices, validate that the relevant I/O or memory
1027+
* decoding bits are enabled in the PCI command register before claiming
1028+
*/
1029+
if (!DeviceExtension->IsLegacyDevice && DeviceExtension->AdapterInterfaceType == PCIBus)
1030+
{
1031+
USHORT PciCommand;
1032+
ULONG BytesRead;
1033+
1034+
BytesRead = HalGetBusDataByOffset(PCIConfiguration,
1035+
DeviceExtension->SystemIoBusNumber,
1036+
DeviceExtension->SystemIoSlotNumber,
1037+
&PciCommand,
1038+
FIELD_OFFSET(PCI_COMMON_CONFIG, Command),
1039+
sizeof(PciCommand));
1040+
if (BytesRead == sizeof(PciCommand))
1041+
{
1042+
for (i = 0; i < NumAccessRanges; i++)
1043+
{
1044+
if (AccessRanges[i].RangeInIoSpace)
1045+
{
1046+
if ((PciCommand & PCI_ENABLE_IO_SPACE) == 0)
1047+
{
1048+
WARN_(VIDEOPRT, "PCI I/O space disabled; refusing access range claim\n");
1049+
return ERROR_INVALID_PARAMETER;
1050+
}
1051+
}
1052+
else
1053+
{
1054+
if ((PciCommand & PCI_ENABLE_MEMORY_SPACE) == 0)
1055+
{
1056+
WARN_(VIDEOPRT, "PCI memory space disabled; refusing access range claim\n");
1057+
return ERROR_INVALID_PARAMETER;
1058+
}
1059+
}
1060+
}
1061+
}
1062+
}
1063+
1064+
/* Determine which ranges need to be claimed (exclude PnP-assigned ones) */
1065+
ULONG Needed = 0;
1066+
for (i = 0; i < NumAccessRanges; ++i)
1067+
{
1068+
if (DeviceExtension->PhysicalDeviceObject && !DeviceExtension->IsLegacyDevice)
1069+
{
1070+
if (IntAccessRangeIsInAllocatedResources(DeviceExtension, &AccessRanges[i]))
1071+
continue;
1072+
}
1073+
++Needed;
1074+
}
1075+
1076+
if (Needed == 0)
1077+
{
1078+
/* Nothing to report/claim */
9551079
return NO_ERROR;
9561080
}
9571081

958-
/* Create the resource list */
1082+
/* Create the resource list for the non-PnP-assigned ranges */
9591083
ResourceListSize = sizeof(CM_RESOURCE_LIST)
960-
+ (NumAccessRanges - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1084+
+ (Needed - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
9611085
ResourceList = ExAllocatePoolWithTag(PagedPool, ResourceListSize, TAG_VIDEO_PORT);
9621086
if (!ResourceList)
9631087
{
@@ -971,47 +1095,86 @@ VideoPortVerifyAccessRanges(
9711095
ResourceList->List[0].BusNumber = DeviceExtension->SystemIoBusNumber;
9721096
ResourceList->List[0].PartialResourceList.Version = 1;
9731097
ResourceList->List[0].PartialResourceList.Revision = 1;
974-
ResourceList->List[0].PartialResourceList.Count = NumAccessRanges;
975-
for (i = 0; i < NumAccessRanges; i++, AccessRanges++)
1098+
ResourceList->List[0].PartialResourceList.Count = Needed;
1099+
1100+
ULONG j = 0;
1101+
for (i = 0; i < NumAccessRanges; ++i)
9761102
{
977-
PartialDescriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[i];
978-
if (AccessRanges->RangeInIoSpace)
1103+
if (DeviceExtension->PhysicalDeviceObject && !DeviceExtension->IsLegacyDevice)
1104+
{
1105+
if (IntAccessRangeIsInAllocatedResources(DeviceExtension, &AccessRanges[i]))
1106+
continue;
1107+
}
1108+
1109+
PartialDescriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[j++];
1110+
if (AccessRanges[i].RangeInIoSpace)
9791111
{
9801112
PartialDescriptor->Type = CmResourceTypePort;
981-
PartialDescriptor->u.Port.Start = AccessRanges->RangeStart;
982-
PartialDescriptor->u.Port.Length = AccessRanges->RangeLength;
1113+
PartialDescriptor->u.Port.Start = AccessRanges[i].RangeStart;
1114+
PartialDescriptor->u.Port.Length = AccessRanges[i].RangeLength;
9831115
}
9841116
else
9851117
{
9861118
PartialDescriptor->Type = CmResourceTypeMemory;
987-
PartialDescriptor->u.Memory.Start = AccessRanges->RangeStart;
988-
PartialDescriptor->u.Memory.Length = AccessRanges->RangeLength;
1119+
PartialDescriptor->u.Memory.Start = AccessRanges[i].RangeStart;
1120+
PartialDescriptor->u.Memory.Length = AccessRanges[i].RangeLength;
9891121
}
990-
if (AccessRanges->RangeShareable)
991-
PartialDescriptor->ShareDisposition = CmResourceShareShared;
992-
else
993-
PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1122+
PartialDescriptor->ShareDisposition = AccessRanges[i].RangeShareable ?
1123+
CmResourceShareShared : CmResourceShareDeviceExclusive;
9941124
PartialDescriptor->Flags = 0;
995-
if (AccessRanges->RangePassive & VIDEO_RANGE_PASSIVE_DECODE)
1125+
if (AccessRanges[i].RangePassive & VIDEO_RANGE_PASSIVE_DECODE)
9961126
PartialDescriptor->Flags |= CM_RESOURCE_PORT_PASSIVE_DECODE;
997-
if (AccessRanges->RangePassive & VIDEO_RANGE_10_BIT_DECODE)
1127+
if (AccessRanges[i].RangePassive & VIDEO_RANGE_10_BIT_DECODE)
9981128
PartialDescriptor->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE;
9991129
}
10001130

1001-
/* Try to acquire all resource ranges */
1002-
Status = IoReportResourceForDetection(
1003-
DeviceExtension->DriverObject,
1004-
NULL, 0, /* Driver List */
1005-
DeviceExtension->PhysicalDeviceObject,
1006-
ResourceList, ResourceListSize,
1007-
&ConflictDetected);
1008-
1131+
if (DeviceExtension->IsLegacyDevice || DeviceExtension->IsLegacyDetect || DeviceExtension->IsVgaDetect)
1132+
{
1133+
Status = IoReportResourceForDetection(
1134+
DeviceExtension->DriverObject,
1135+
NULL, 0, /* Driver List */
1136+
DeviceExtension->PhysicalDeviceObject,
1137+
ResourceList, ResourceListSize,
1138+
&ConflictDetected);
1139+
1140+
/* IntIsVgaSaveDriver() will later ignore STATUS_CONFLICTING_ADDRESSES, but we still claim it */
1141+
if (!NT_SUCCESS(Status) && IntIsVgaSaveDriver(DeviceExtension))
1142+
{
1143+
NTSTATUS fbStatus;
1144+
BOOLEAN fbConflict = FALSE;
1145+
fbStatus = IoReportResourceUsage(&VideoClassName,
1146+
DeviceExtension->DriverObject,
1147+
NULL,
1148+
0,
1149+
DeviceExtension->PhysicalDeviceObject,
1150+
ResourceList,
1151+
ResourceListSize,
1152+
FALSE,
1153+
&fbConflict);
1154+
INFO_(VIDEOPRT, "VGA detect->usage fallback: Status=0x%lx Conflict=%d fbStatus=0x%lx fbConflict=%d\n",
1155+
Status, ConflictDetected, fbStatus, fbConflict);
1156+
Status = fbStatus;
1157+
ConflictDetected = fbConflict;
1158+
}
1159+
}
1160+
else
1161+
{
1162+
Status = IoReportResourceUsage(&VideoClassName,
1163+
DeviceExtension->DriverObject,
1164+
NULL,
1165+
0,
1166+
DeviceExtension->PhysicalDeviceObject,
1167+
ResourceList,
1168+
ResourceListSize,
1169+
FALSE,
1170+
&ConflictDetected);
1171+
}
10091172
ExFreePoolWithTag(ResourceList, TAG_VIDEO_PORT);
10101173

10111174
/* If VgaSave driver is conflicting and we don't explicitely want
10121175
* to use it, ignore the problem (because win32k will try to use
10131176
* this driver only if all other ones are failing). */
1014-
if (Status == STATUS_CONFLICTING_ADDRESSES &&
1177+
if ((Status == STATUS_CONFLICTING_ADDRESSES || ConflictDetected) &&
10151178
IntIsVgaSaveDriver(DeviceExtension) &&
10161179
!VpBaseVideo)
10171180
{
@@ -1021,7 +1184,34 @@ VideoPortVerifyAccessRanges(
10211184
if (!NT_SUCCESS(Status) || ConflictDetected)
10221185
return ERROR_INVALID_PARAMETER;
10231186
else
1187+
{
1188+
/* Track VGA access ranges on success for fallback handling */
1189+
if (DeviceExtension->IsVgaDriver)
1190+
{
1191+
KeWaitForMutexObject(&VgaSyncLock, Executive, KernelMode, FALSE, NULL);
1192+
if (VgaRanges)
1193+
{
1194+
ExFreePoolWithTag(VgaRanges, TAG_VIDEO_PORT);
1195+
VgaRanges = NULL;
1196+
NumOfVgaRanges = 0;
1197+
}
1198+
if (NumAccessRanges)
1199+
{
1200+
SIZE_T sz = NumAccessRanges * sizeof(VIDEO_ACCESS_RANGE);
1201+
VgaRanges = ExAllocatePoolWithTag(PagedPool, sz, TAG_VIDEO_PORT);
1202+
if (VgaRanges)
1203+
{
1204+
RtlCopyMemory(VgaRanges, AccessRanges, sz);
1205+
NumOfVgaRanges = NumAccessRanges;
1206+
VgaDeviceExtension = DeviceExtension;
1207+
}
1208+
}
1209+
KeReleaseMutex(&VgaSyncLock, FALSE);
1210+
}
1211+
/* Leave VGA detect phase after first successful claim */
1212+
DeviceExtension->IsVgaDetect = FALSE;
10241213
return NO_ERROR;
1214+
}
10251215
}
10261216

10271217
/*

0 commit comments

Comments
 (0)