jzef

gopmini.c fixed 32/64-bit

Nov 7th, 2026
8
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 42.75 KB | None | 0 0
  1. /* VGAGOP 1.2: GOP branch for the user-supplied original VGA miniport.
  2. * Reuses the BSE4 0.4.2.1 reserved-system-PTE mapping workaround, with runtime
  3. * geometry, generic PCI identity, a checked CSM35 record, and physical-width
  4. * checks. This is experimental XP x86 kernel code; hardware test required.
  5. * The legacy VGA code remains in vga.c/modeset.c/vesa.c/vgadata.c.
  6. */
  7. #if defined(VGAGOP_HOST_TEST)
  8. # define __stdcall __attribute__((stdcall))
  9. # define __cdecl __attribute__((cdecl))
  10. # define __declspec(x)
  11. #endif
  12. typedef unsigned char UCHAR;
  13. typedef unsigned char BOOLEAN;
  14. typedef unsigned short USHORT;
  15. #if defined(_MSC_VER)
  16. typedef unsigned __int64 ULONGLONG;
  17. typedef __int64 LONGLONG;
  18. #else
  19. typedef unsigned long long ULONGLONG;
  20. typedef long long LONGLONG;
  21. #endif
  22. typedef unsigned long ULONG;
  23. typedef signed long LONG;
  24. typedef signed short CSHORT;
  25. typedef unsigned long ULONG_PTR;
  26. typedef unsigned long SIZE_T;
  27. typedef void VOID;
  28. typedef void *PVOID;
  29. typedef unsigned char *PUCHAR;
  30. typedef unsigned long *PULONG;
  31. typedef unsigned short *PWSTR;
  32. typedef void *HANDLE;
  33. typedef LONG VP_STATUS;
  34. typedef unsigned long INTERFACE_TYPE;
  35. typedef int MEMORY_CACHING_TYPE;
  36.  
  37. #ifndef NULL
  38. #define NULL ((void*)0)
  39. #endif
  40. #define TRUE 1
  41. #define FALSE 0
  42.  
  43. #define NO_ERROR 0L
  44. #define ERROR_INVALID_FUNCTION 1L
  45. #define ERROR_INVALID_PARAMETER 87L
  46. #define ERROR_INSUFFICIENT_BUFFER 122L
  47.  
  48. /* INTERFACE_TYPE::Internal */
  49. #define Internal 0
  50. #define PCIBus 5
  51.  
  52. /* video.h */
  53. #define VIDEO_MEMORY_SPACE_MEMORY 0x00
  54. #define VIDEO_MEMORY_SPACE_P6CACHE 0x08
  55.  
  56. /* ntddvdeo.h IOCTLs */
  57. #define FILE_DEVICE_VIDEO 0x00000023
  58. #define METHOD_BUFFERED 0
  59. #define FILE_ANY_ACCESS 0
  60. #define CTL_CODE(DeviceType, Function, Method, Access) \
  61. (((DeviceType)<<16) | ((Access)<<14) | ((Function)<<2) | (Method))
  62.  
  63. #define IOCTL_VIDEO_QUERY_AVAIL_MODES CTL_CODE(FILE_DEVICE_VIDEO,0x100,METHOD_BUFFERED,FILE_ANY_ACCESS)
  64. #define IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES CTL_CODE(FILE_DEVICE_VIDEO,0x101,METHOD_BUFFERED,FILE_ANY_ACCESS)
  65. #define IOCTL_VIDEO_QUERY_CURRENT_MODE CTL_CODE(FILE_DEVICE_VIDEO,0x102,METHOD_BUFFERED,FILE_ANY_ACCESS)
  66. #define IOCTL_VIDEO_SET_CURRENT_MODE CTL_CODE(FILE_DEVICE_VIDEO,0x103,METHOD_BUFFERED,FILE_ANY_ACCESS)
  67. #define IOCTL_VIDEO_RESET_DEVICE CTL_CODE(FILE_DEVICE_VIDEO,0x104,METHOD_BUFFERED,FILE_ANY_ACCESS)
  68. #define IOCTL_VIDEO_MAP_VIDEO_MEMORY CTL_CODE(FILE_DEVICE_VIDEO,0x116,METHOD_BUFFERED,FILE_ANY_ACCESS)
  69. #define IOCTL_VIDEO_UNMAP_VIDEO_MEMORY CTL_CODE(FILE_DEVICE_VIDEO,0x117,METHOD_BUFFERED,FILE_ANY_ACCESS)
  70.  
  71. /* VIDEO_MODE_INFORMATION flags. Deliberately match generic NT/ReactOS fb. */
  72. #define VIDEO_MODE_COLOR 0x0001
  73. #define VIDEO_MODE_GRAPHICS 0x0002
  74. #define VIDEO_MODE_NO_OFF_SCREEN 0x0020
  75.  
  76. /* Exactly one firmware-established graphics mode is exposed. */
  77. #define BSE_MODECOUNT 1UL
  78. #include "gop35_record.h"
  79. #include "gop36_record.h"
  80. #include "gop35_diag.h"
  81. #include "gop35_screen.h"
  82. /* MmMapIoSpace cache types used by NT5. */
  83. #define MmNonCached 0
  84. #define MmWriteCombined 2
  85.  
  86. #pragma pack(push,8)
  87. typedef union _PHYSICAL_ADDRESS {
  88. struct { ULONG LowPart; LONG HighPart; } u;
  89. LONGLONG QuadPart;
  90. } PHYSICAL_ADDRESS;
  91. #pragma pack(pop)
  92.  
  93. #define PAGE_SHIFT 12
  94. #define PAGE_SIZE 4096UL
  95. #define NonPagedPool 0UL
  96. /* XP x86 PAE self-map verified by WinDbg: PTE(VA)=0xC0000000+(VA>>12)*8. */
  97. #define VGAGOP_PTE_BASE 0xC0000000UL
  98. #define VGAGOP_PDE_BASE 0xC0600000UL
  99. /* P|RW|PWT|PCD|Global. Do not use XP's 26-bit PageFrameNumber bitfield. */
  100. #define VGAGOP_PTE_UC_FLAGS 0x000000000000011BULL
  101. #define VGAGOP_PTE_PHYS_MASK 0x000FFFFFFFFFF000ULL
  102. #define VGAGOP_MAP_TAG 0x504F4756UL /* 'VGOP' little endian */
  103. #define VGAGOP_SAVE_TAG 0x50534542UL /* 'BESP' */
  104.  
  105. typedef struct _STATUS_BLOCK {
  106. union { VP_STATUS Status; PVOID Pointer; } u;
  107. ULONG_PTR Information;
  108. } STATUS_BLOCK, *PSTATUS_BLOCK;
  109.  
  110. typedef struct _VIDEO_REQUEST_PACKET {
  111. ULONG IoControlCode;
  112. PSTATUS_BLOCK StatusBlock;
  113. PVOID InputBuffer;
  114. ULONG InputBufferLength;
  115. PVOID OutputBuffer;
  116. ULONG OutputBufferLength;
  117. } VIDEO_REQUEST_PACKET, *PVIDEO_REQUEST_PACKET;
  118.  
  119. typedef struct _VIDEO_MEMORY {
  120. PVOID RequestedVirtualAddress;
  121. } VIDEO_MEMORY, *PVIDEO_MEMORY;
  122.  
  123. typedef struct _VIDEO_MEMORY_INFORMATION {
  124. PVOID VideoRamBase;
  125. ULONG VideoRamLength;
  126. PVOID FrameBufferBase;
  127. ULONG FrameBufferLength;
  128. } VIDEO_MEMORY_INFORMATION, *PVIDEO_MEMORY_INFORMATION;
  129.  
  130. typedef struct _VIDEO_MODE {
  131. ULONG RequestedMode;
  132. } VIDEO_MODE, *PVIDEO_MODE;
  133.  
  134. typedef struct _VIDEO_NUM_MODES {
  135. ULONG NumModes;
  136. ULONG ModeInformationLength;
  137. } VIDEO_NUM_MODES, *PVIDEO_NUM_MODES;
  138.  
  139. typedef struct _VIDEO_MODE_INFORMATION {
  140. ULONG Length;
  141. ULONG ModeIndex;
  142. ULONG VisScreenWidth;
  143. ULONG VisScreenHeight;
  144. ULONG ScreenStride;
  145. ULONG NumberOfPlanes;
  146. ULONG BitsPerPlane;
  147. ULONG Frequency;
  148. ULONG XMillimeter;
  149. ULONG YMillimeter;
  150. ULONG NumberRedBits;
  151. ULONG NumberGreenBits;
  152. ULONG NumberBlueBits;
  153. ULONG RedMask;
  154. ULONG GreenMask;
  155. ULONG BlueMask;
  156. ULONG AttributeFlags;
  157. ULONG VideoMemoryBitmapWidth;
  158. ULONG VideoMemoryBitmapHeight;
  159. ULONG DriverSpecificAttributeFlags;
  160. } VIDEO_MODE_INFORMATION, *PVIDEO_MODE_INFORMATION;
  161.  
  162. /* Only the prefix actually accessed. Layout matches XP x86 video.h. */
  163. typedef struct _VIDEO_PORT_CONFIG_INFO_MIN {
  164. ULONG Length;
  165. ULONG SystemIoBusNumber;
  166. INTERFACE_TYPE AdapterInterfaceType;
  167. ULONG BusInterruptLevel;
  168. ULONG BusInterruptVector;
  169. } VIDEO_PORT_CONFIG_INFO_MIN, *PVIDEO_PORT_CONFIG_INFO;
  170.  
  171. typedef struct _VIDEO_POWER_MANAGEMENT {
  172. ULONG Length, DPMSVersion, PowerState;
  173. } VIDEO_POWER_MANAGEMENT;
  174. typedef struct _VIDEO_CHILD_ENUM_INFO {
  175. ULONG Size, ChildDescriptorSize, ChildIndex, ACPIHwId;
  176. PVOID ChildHwDeviceExtension;
  177. } VIDEO_CHILD_ENUM_INFO;
  178. typedef VP_STATUS (__stdcall *VG_POWER)(PVOID,ULONG,VIDEO_POWER_MANAGEMENT*);
  179. typedef VP_STATUS (__stdcall *VG_CHILD)(PVOID,VIDEO_CHILD_ENUM_INFO*,PULONG,PUCHAR,PULONG,PULONG);
  180.  
  181. typedef VP_STATUS (__stdcall *PVIDEO_HW_FIND_ADAPTER)(PVOID,PVOID,PWSTR,PVIDEO_PORT_CONFIG_INFO,PUCHAR);
  182. typedef BOOLEAN (__stdcall *PVIDEO_HW_INITIALIZE)(PVOID);
  183. typedef BOOLEAN (__stdcall *PVIDEO_HW_INTERRUPT)(PVOID);
  184. typedef BOOLEAN (__stdcall *PVIDEO_HW_START_IO)(PVOID,PVIDEO_REQUEST_PACKET);
  185. typedef BOOLEAN (__stdcall *PVIDEO_HW_RESET_HW)(PVOID,ULONG,ULONG);
  186.  
  187. typedef struct _VIDEO_HW_INITIALIZATION_DATA {
  188. ULONG HwInitDataSize;
  189. INTERFACE_TYPE AdapterInterfaceType;
  190. PVIDEO_HW_FIND_ADAPTER HwFindAdapter;
  191. PVIDEO_HW_INITIALIZE HwInitialize;
  192. PVIDEO_HW_INTERRUPT HwInterrupt;
  193. PVIDEO_HW_START_IO HwStartIO;
  194. ULONG HwDeviceExtensionSize;
  195. ULONG StartingDeviceNumber;
  196. PVIDEO_HW_RESET_HW HwResetHw;
  197. PVOID HwTimer;
  198. PVOID HwStartDma;
  199. VG_POWER HwSetPowerState;
  200. VG_POWER HwGetPowerState;
  201. VG_CHILD HwGetVideoChildDescriptor;
  202. PVOID HwQueryInterface;
  203. ULONG HwChildDeviceExtensionSize;
  204. PVOID HwLegacyResourceList;
  205. ULONG HwLegacyResourceCount;
  206. PVOID HwGetLegacyResources;
  207. BOOLEAN AllowEarlyEnumeration;
  208. UCHAR _pad[3];
  209. ULONG Reserved;
  210. } VIDEO_HW_INITIALIZATION_DATA, *PVIDEO_HW_INITIALIZATION_DATA;
  211.  
  212. /* Compile-time ABI guards for XP x86 / x64. */
  213. typedef char bse_assert_mode_info_80[(sizeof(VIDEO_MODE_INFORMATION)==80)?1:-1];
  214. typedef char bse_assert_num_modes_8[(sizeof(VIDEO_NUM_MODES)==8)?1:-1];
  215. #if defined(_WIN64)
  216. typedef char bse_assert_hw_init_144[(sizeof(VIDEO_HW_INITIALIZATION_DATA)==144)?1:-1];
  217. typedef char bse_assert_mem_info_32[(sizeof(VIDEO_MEMORY_INFORMATION)==32)?1:-1];
  218. #else
  219. typedef char bse_assert_hw_init_84[(sizeof(VIDEO_HW_INITIALIZATION_DATA)==84)?1:-1];
  220. typedef char bse_assert_mem_info_16[(sizeof(VIDEO_MEMORY_INFORMATION)==16)?1:-1];
  221. #endif
  222. typedef char vg_assert_config_prefix_20[(sizeof(VIDEO_PORT_CONFIG_INFO_MIN)==20)?1:-1];
  223. typedef char vg_assert_power_12[(sizeof(VIDEO_POWER_MANAGEMENT)==12)?1:-1];
  224. #if defined(_WIN64)
  225. typedef char vg_assert_child_24[(sizeof(VIDEO_CHILD_ENUM_INFO)==24)?1:-1];
  226. #else
  227. typedef char vg_assert_child_20[(sizeof(VIDEO_CHILD_ENUM_INFO)==20)?1:-1];
  228. #endif
  229.  
  230. /* VGAGOP target and status definitions. */
  231. #define ERROR_DEV_NOT_EXIST 55L
  232. #define ERROR_BUSY 170L
  233. #define ERROR_IO_DEVICE 1117L
  234. #define VGAGOP_PATTERN_A 0xAA55AA55UL
  235. #define VGAGOP_PATTERN_B 0x55AA55AAUL
  236. #define VGAGOP_POLL_US 10UL
  237. #define VGAGOP_MAX_WAITS 100UL
  238.  
  239. typedef struct _VIDEO_ACCESS_RANGE {
  240. PHYSICAL_ADDRESS RangeStart;
  241. ULONG RangeLength;
  242. UCHAR RangeInIoSpace, RangeVisible, RangeShareable, RangePassive;
  243. } VIDEO_ACCESS_RANGE;
  244.  
  245. typedef struct _VGAGOP_EXTENSION {
  246. ULONG Claimed;
  247. ULONG GopValid;
  248. ULONG CurrentMode;
  249. G35_RECORD Record;
  250. ULONG MapUsers;
  251. ULONG PixelTestDone,Cr4,PhysicalBits;
  252. G35_PIXEL_RESULT Pixels;
  253. ULONGLONG FbPhysical;
  254. ULONG FbLength;
  255. PVOID MappingAddress;
  256. ULONGLONG *SavedPtes;
  257. ULONG MapPages;
  258. ULONG MapLength;
  259. PVOID MappedBase;
  260. volatile LONG Busy;
  261. } VGAGOP_EXTENSION;
  262.  
  263. __declspec(dllimport) ULONG __stdcall VideoPortInitialize(PVOID,PVOID,PVIDEO_HW_INITIALIZATION_DATA,PVOID);
  264. __declspec(dllimport) VP_STATUS __stdcall VideoPortVerifyAccessRanges(PVOID,ULONG,VIDEO_ACCESS_RANGE*);
  265. __declspec(dllimport) VP_STATUS __stdcall VideoPortGetAccessRanges(PVOID,ULONG,PVOID,ULONG,VIDEO_ACCESS_RANGE*,PVOID,PVOID,PULONG);
  266. __declspec(dllimport) VOID __stdcall VideoPortStallExecution(ULONG);
  267. __declspec(dllimport) ULONG __stdcall HalGetBusDataByOffset(ULONG,ULONG,ULONG,PVOID,ULONG,ULONG);
  268. __declspec(dllimport) PVOID __stdcall MmMapIoSpace(PHYSICAL_ADDRESS,SIZE_T,MEMORY_CACHING_TYPE);
  269. __declspec(dllimport) VOID __stdcall MmUnmapIoSpace(PVOID,SIZE_T);
  270. __declspec(dllimport) PVOID __stdcall MmAllocateMappingAddress(SIZE_T,ULONG);
  271. __declspec(dllimport) VOID __stdcall MmFreeMappingAddress(PVOID,ULONG);
  272. __declspec(dllimport) PVOID __stdcall ExAllocatePoolWithTag(ULONG,SIZE_T,ULONG);
  273. __declspec(dllimport) VOID __stdcall ExFreePool(PVOID);
  274. __declspec(dllimport) VOID __stdcall KeFlushEntireTb(BOOLEAN,BOOLEAN);
  275. __declspec(dllimport) ULONG __cdecl DbgPrint(const char*,...);
  276.  
  277. #if defined(_MSC_VER)
  278. LONG __cdecl _InterlockedCompareExchange(volatile LONG*,LONG,LONG);
  279. #pragma intrinsic(_InterlockedCompareExchange)
  280. #if defined(_M_AMD64) || defined(_M_X64)
  281. unsigned __int64 __readcr4(void);
  282. #pragma intrinsic(__readcr4)
  283. void __cpuid(int cpuInfo[4], int function_id);
  284. #pragma intrinsic(__cpuid)
  285. #endif
  286. #endif
  287.  
  288. /* Stable, exported diagnostic ABI: dd vgagop!VgaGopDiag L40 (hex length). */
  289. enum {
  290. D_MAGIC, D_VERSION, D_BYTES, D_STAGE, D_ERROR, D_IOCTL, D_STATUS,
  291. D_ENTRY_STATUS, D_BAR_OLD_LO, D_BAR_OLD_HI, D_BAR_NOW_LO, D_BAR_NOW_HI,
  292. D_CMD_OLD, D_CMD_NOW, D_SUBSYS, D_TOLUD, D_CLAIM_STATUS,
  293. D_FB_PHYSICAL, D_FB_LENGTH, D_FB_VIRTUAL, D_MAP_COUNT, D_UNMAP_COUNT,
  294. D_SET_COUNT, D_TEST_COUNT, D_TEST_A, D_TEST_B, D_SAVED_PIXEL,
  295. D_RELOCATIONS, D_FAILURES, D_CONFLICT_BDF, D_CONFLICT_BASE,
  296. D_GOP_RECORD, D_GOP_FLAGS, D_GOP_FB_LO, D_GOP_FB_HI, D_MODE,
  297. D_EXTENSION, D_LOCK, D_ROLLBACK, D_MAP_STATUS, D_HISTORY_NEXT,
  298. D_HISTORY, /* 16 DWORDs: indices 41..56; new fields begin at 57. */
  299. D_FIRST_A = 57, D_FIRST_B, D_WAITS_A, D_WAITS_B,
  300. D_PRIME_READ, D_PRIME_WAITS, D_PROBE_STATE
  301. };
  302. enum {
  303. E_NONE, E_PCI_READ, E_GPU, E_BOARD, E_BAR, E_RAM, E_GOP, E_CLAIM,
  304. E_CONFLICT, E_COMMAND, E_PCI_WRITE, E_READBACK, E_ROLLBACK,
  305. E_MAP, E_PIXEL_TEST, E_LOCK, E_ARGUMENT, E_BRIDGE
  306. };
  307. __declspec(dllexport) volatile ULONG VgaGopDiag[64] = {0x504F4756UL,0x00010000UL,256UL};
  308. /* Separate diagnostic ABI; old VgaGopDiag offsets are unchanged.
  309. * 0 magic,1 version,2 bytes,3 path (1 legacy high,2 PCI/PnP low),
  310. * 4 bus,5 interface,6 slot,7 GetAccessRanges result,8 matched index,
  311. * 9 error (1 config,2 bus,3 API,4 slot,5 containment,6 identity),
  312. * 10/11 framebuffer,12 length,13 matching range low,14 high,15 length.
  313. */
  314. __declspec(dllexport) volatile ULONG VgaGopPciDiag[16] = {0x49435056UL,0x00010200UL,64UL};
  315. static volatile LONG VgaGopFenceWord;
  316.  
  317. #if defined(_WIN64)
  318. typedef char check_pointer_64[(sizeof(PVOID)==8)?1:-1];
  319. /* BankSwitch is x86-only (i386\banking.asm). Export dummy symbols to satisfy vga.obj on AMD64. */
  320. UCHAR BankSwitchStart = 0;
  321. UCHAR BankSwitchEnd = 0;
  322. #else
  323. typedef char check_pointer_32[(sizeof(PVOID)==4)?1:-1];
  324. #endif
  325. typedef char check_access_range[(sizeof(VIDEO_ACCESS_RANGE)==16)?1:-1];
  326. typedef char check_ulong_32[(sizeof(ULONG)==4)?1:-1];
  327. typedef char check_physical_address_8[(sizeof(PHYSICAL_ADDRESS)==8)?1:-1];
  328. typedef char check_diag_64[(D_PROBE_STATE==63)?1:-1];
  329.  
  330. static LONG vgagop_cas(volatile LONG *p, LONG n, LONG old)
  331. {
  332. #if defined(__GNUC__)
  333. return __sync_val_compare_and_swap(p,old,n);
  334. #else
  335. return _InterlockedCompareExchange(p,n,old);
  336. #endif
  337. }
  338. static void vgagop_fence(void) { (void)vgagop_cas(&VgaGopFenceWord,0,0); }
  339. static void vgagop_stall(G35_U32 us){VideoPortStallExecution(us);}
  340. static void bse_zero(PVOID p, ULONG n)
  341. {
  342. UCHAR *q=(UCHAR*)p;
  343. while(n--) *q++=0;
  344. }
  345. static ULONG rd32(const UCHAR *p)
  346. {
  347. return (ULONG)p[0]|((ULONG)p[1]<<8)|((ULONG)p[2]<<16)|((ULONG)p[3]<<24);
  348. }
  349. static USHORT rd16(const UCHAR *p) { return (USHORT)(p[0]|((USHORT)p[1]<<8)); }
  350. static VP_STATUS fail(ULONG e, VP_STATUS status)
  351. {
  352. VgaGopDiag[D_ERROR]=e; ++VgaGopDiag[D_FAILURES];
  353. DbgPrint("VGAGOP: fail=%lu stage=%lu ioctl=%08lx status=%lu\n",
  354. e,VgaGopDiag[D_STAGE],VgaGopDiag[D_IOCTL],(ULONG)status);
  355. return status;
  356. }
  357. /* The dispatcher only falls back to the original VGA driver when NO CSM
  358. * graphics handoff is present. An invalid/old CSM handoff never triggers
  359. * legacy VGA port accesses on a Class 3 machine. */
  360. static G35_RECORD VgaGopRecord;
  361. static G36_RECORD VgaGopBridgeRecord;
  362. static int VgaGopRecordReady;
  363. static int read_handoff(void)
  364. {
  365. PHYSICAL_ADDRESS pa;
  366. UCHAR *p;
  367. ULONG i,j,count=0,invalid=0,old=0;
  368. G35_RECORD r;
  369. pa.QuadPart=0x80000;
  370. p=(UCHAR*)MmMapIoSpace(pa,0x20000,1);
  371. if(!p)return -1;
  372. for(i=0;i<=0x20000-8;i+=8) {
  373. if(g35_equal(p+i,"GOP23V1\0",8))old=1;
  374. if(i>0x20000-sizeof(r)||!g35_equal(p+i,G35_SIGNATURE,8))continue;
  375. for(j=0;j<sizeof(r);j++)((UCHAR*)&r)[j]=p[i+j];
  376. if(g35_validate(&r)){invalid=1;continue;}
  377. if(r.Flags&G35_BRIDGE_VALID) {
  378. if(i+sizeof(r)+sizeof(VgaGopBridgeRecord)>0x20000){invalid=1;continue;}
  379. for(j=0;j<sizeof(VgaGopBridgeRecord);j++)
  380. ((UCHAR*)&VgaGopBridgeRecord)[j]=p[i+sizeof(r)+j];
  381. if(g36_validate(&VgaGopBridgeRecord,&r)){invalid=1;continue;}
  382. }
  383. ++count;
  384. VgaGopRecord=r;
  385. VgaGopDiag[D_GOP_RECORD]=0x80000+i;
  386. }
  387. MmUnmapIoSpace(p,0x20000);
  388. if(count==1&&!invalid)return 1;
  389. return (count||invalid||old)?-1:0;
  390. }
  391. static VP_STATUS identify(VGAGOP_EXTENSION *e,UCHAR *cfg)
  392. {
  393. ULONG slot,i;
  394. const G35_RECORD *r=&e->Record;
  395. slot=r->Device|(r->Function<<5);
  396. if(HalGetBusDataByOffset(4,r->Bus,slot,cfg,0,64)!=64)
  397. return fail(E_PCI_READ,ERROR_IO_DEVICE);
  398. if(rd32(cfg)!=r->PciId||rd32(cfg+8)!=r->ClassRevision||
  399. rd32(cfg+0x2c)!=r->Subsystem||(cfg[0x0e]&0x7f)!=0)
  400. return fail(E_GPU,ERROR_DEV_NOT_EXIST);
  401. for(i=0;i<6;i++) if(rd32(cfg+0x10+i*4)!=r->Bars[i]) {
  402. VgaGopDiag[D_BAR_OLD_LO]=r->Bars[i];
  403. VgaGopDiag[D_BAR_NOW_LO]=rd32(cfg+0x10+i*4);
  404. VgaGopDiag[D_CONFLICT_BDF]=i;
  405. return fail(E_BAR,ERROR_INVALID_PARAMETER);
  406. }
  407. VgaGopDiag[D_CMD_OLD]=r->Command;
  408. VgaGopDiag[D_CMD_NOW]=rd16(cfg+4);
  409. if(!(rd16(cfg+4)&2))return fail(E_COMMAND,ERROR_DEV_NOT_EXIST);
  410. VgaGopDiag[D_SUBSYS]=r->Subsystem;
  411. return NO_ERROR;
  412. }
  413. #include "gop36_xp.h"
  414.  
  415. static ULONG mask_bits(ULONG m)
  416. {
  417. ULONG n=0;
  418. while(m){n+=m&1;m>>=1;}
  419. return n;
  420. }
  421. static void fill_mode(VGAGOP_EXTENSION *e,VIDEO_MODE_INFORMATION *m,ULONG i)
  422. {
  423. const G35_GOP *g=&e->Record.Gop;
  424. bse_zero(m,sizeof(*m));
  425. m->Length=sizeof(*m);m->ModeIndex=i;
  426. m->VisScreenWidth=g->Width;m->VisScreenHeight=g->Height;
  427. m->ScreenStride=g->PixelsPerScanLine*4;m->NumberOfPlanes=1;m->BitsPerPlane=32;
  428. /* GOP does not expose refresh or physical monitor size. 60 Hz is the
  429. * XP display-mode descriptor value, never a hardware mode-set request. */
  430. m->Frequency=60;m->XMillimeter=0;m->YMillimeter=0;
  431. m->NumberRedBits=mask_bits(g->RedMask);m->NumberGreenBits=mask_bits(g->GreenMask);
  432. m->NumberBlueBits=mask_bits(g->BlueMask);
  433. m->RedMask=g->RedMask;m->GreenMask=g->GreenMask;m->BlueMask=g->BlueMask;
  434. m->AttributeFlags=VIDEO_MODE_COLOR|VIDEO_MODE_GRAPHICS|VIDEO_MODE_NO_OFF_SCREEN;
  435. m->VideoMemoryBitmapWidth=g->PixelsPerScanLine;m->VideoMemoryBitmapHeight=g->Height;
  436. }
  437. /* Write ONCE, then read until two successive samples agree with the pattern.
  438. * Each sample after the first follows a 10-us stall and a CPU memory barrier.
  439. * A barrier alone did not make BSE2's readback reliable on the target.
  440. * No unbounded loop and no repeated writes that could hide a stuck readback.
  441. * Maximum requested stall time: 100 * 10 us per pattern, 3 ms per MAP.
  442. * That limit is a test-build policy, not a measured hardware latency bound.
  443. */
  444. static int write_and_wait(volatile ULONG *pixel,ULONG expected,
  445. volatile ULONG *first,volatile ULONG *last,
  446. volatile ULONG *waits)
  447. {
  448. ULONG i,value,matching=0;
  449. *pixel=expected;
  450. vgagop_fence();
  451. for(i=0;i<=VGAGOP_MAX_WAITS;i++) {
  452. value=*pixel;
  453. if(i==0 && first) *first=value;
  454. *last=value;
  455. *waits=i;
  456. if(value==expected) {
  457. ++matching;
  458. if(matching==2) return 1;
  459. } else {
  460. matching=0;
  461. }
  462. if(i==VGAGOP_MAX_WAITS) break;
  463. VideoPortStallExecution(VGAGOP_POLL_US);
  464. vgagop_fence();
  465. }
  466. return 0;
  467. }
  468.  
  469. static int probe_and_prime(volatile ULONG *pixel)
  470. {
  471. ULONG old,i;
  472. old=*pixel;
  473. VgaGopDiag[D_SAVED_PIXEL]=old;
  474. VgaGopDiag[D_TEST_A]=0;
  475. VgaGopDiag[D_TEST_B]=0;
  476. for(i=D_FIRST_A;i<=D_PROBE_STATE;i++) VgaGopDiag[i]=0;
  477. ++VgaGopDiag[D_TEST_COUNT];
  478.  
  479. VgaGopDiag[D_PROBE_STATE]=1;
  480. if(!write_and_wait(pixel,VGAGOP_PATTERN_A,&VgaGopDiag[D_FIRST_A],
  481. &VgaGopDiag[D_TEST_A],&VgaGopDiag[D_WAITS_A])) goto failed;
  482. VgaGopDiag[D_PROBE_STATE]=2;
  483. if(!write_and_wait(pixel,VGAGOP_PATTERN_B,&VgaGopDiag[D_FIRST_B],
  484. &VgaGopDiag[D_TEST_B],&VgaGopDiag[D_WAITS_B])) goto failed;
  485.  
  486. /* The supplied framebuf bInitSURF writes AA55AA55 and immediately compares
  487. * it. A miniport delay before returning cannot delay that later CMP.
  488. * Instead, establish and confirm its expected starting value here AFTER
  489. * testing a real A -> B transition. Do NOT restore the old pixel on success:
  490. * that would recreate the observed delayed-read failure in framebuf.dll.
  491. * The A -> B -> A checks must all pass; no unconditional success branch.
  492. * Only the first 32-bit pixel changes. No framebuf code or flags are patched.
  493. */
  494. VgaGopDiag[D_PROBE_STATE]=3;
  495. if(!write_and_wait(pixel,VGAGOP_PATTERN_A,NULL,
  496. &VgaGopDiag[D_PRIME_READ],&VgaGopDiag[D_PRIME_WAITS])) goto failed;
  497. VgaGopDiag[D_PROBE_STATE]=4;
  498. DbgPrint("VGAGOP: probe OK; waits A/B/prime=%lu/%lu/%lu; framebuf seed=%08lx\n",
  499. VgaGopDiag[D_WAITS_A],VgaGopDiag[D_WAITS_B],
  500. VgaGopDiag[D_PRIME_WAITS],VgaGopDiag[D_PRIME_READ]);
  501. return 1;
  502. failed:
  503. VgaGopDiag[D_PROBE_STATE]|=0x80UL;
  504. *pixel=old; /* Best-effort restoration on failure, not claimed as verified. */
  505. vgagop_fence();
  506. return 0;
  507. }
  508.  
  509. static ULONGLONG vgagop_load_pte(volatile ULONG *p)
  510. {
  511. return ((ULONGLONG)p[1]<<32)|(ULONGLONG)p[0];
  512. }
  513. /* Present bit is published last, matching the already-proven GOP8 PAE writer. */
  514. static void vgagop_store_pte(volatile ULONG *p,ULONGLONG v)
  515. {
  516. p[0]=0;
  517. vgagop_fence();
  518. p[1]=(ULONG)(v>>32);
  519. vgagop_fence();
  520. p[0]=(ULONG)v;
  521. }
  522. #if defined(VGAGOP_HOST_TEST)
  523. extern volatile ULONG *test_pte_for_va(PVOID);
  524. extern volatile ULONG *test_pde_for_va(PVOID);
  525. extern ULONG test_read_cr4(void);
  526. extern ULONG test_phys_bits(void);
  527. #define vgagop_pte_for_va test_pte_for_va
  528. #define vgagop_pde_for_va test_pde_for_va
  529. #define vgagop_read_cr4 test_read_cr4
  530. #define vgagop_phys_bits test_phys_bits
  531. #else
  532. static volatile ULONG *vgagop_pte_for_va(PVOID va)
  533. {
  534. return (volatile ULONG*)(VGAGOP_PTE_BASE+(((ULONG_PTR)va>>PAGE_SHIFT)<<3));
  535. }
  536. static volatile ULONG *vgagop_pde_for_va(PVOID va)
  537. {
  538. return (volatile ULONG*)(VGAGOP_PDE_BASE+(((ULONG_PTR)va>>21)<<3));
  539. }
  540. static ULONG vgagop_read_cr4(void)
  541. {
  542. ULONG value;
  543. #if defined(__GNUC__)
  544. __asm__ __volatile__("mov %%cr4, %0" : "=r"(value));
  545. #elif defined(_M_AMD64) || defined(_M_X64)
  546. value = (ULONG)__readcr4();
  547. #else
  548. __asm {
  549. xor eax,eax
  550. _emit 0x0f
  551. _emit 0x20
  552. _emit 0xe0
  553. mov value,eax
  554. }
  555. #endif
  556. return value;
  557. }
  558. static ULONG vgagop_cpuid_eax(ULONG leaf)
  559. {
  560. ULONG a;
  561. #if defined(__GNUC__)
  562. ULONG b,c,d;
  563. __asm__ __volatile__("cpuid":"=a"(a),"=b"(b),"=c"(c),"=d"(d):"a"(leaf),"c"(0));
  564. #elif defined(_M_AMD64) || defined(_M_X64)
  565. int cpuInfo[4];
  566. __cpuid(cpuInfo, (int)leaf);
  567. a = (ULONG)cpuInfo[0];
  568. #else
  569. __asm {
  570. mov eax,leaf
  571. xor ecx,ecx
  572. cpuid
  573. mov a,eax
  574. }
  575. #endif
  576. return a;
  577. }
  578. static ULONG vgagop_phys_bits(void)
  579. {
  580. ULONG bits;
  581. if(vgagop_cpuid_eax(0x80000000UL)<0x80000008UL)return 36;
  582. bits=vgagop_cpuid_eax(0x80000008UL)&255;
  583. return (bits>=32&&bits<=52)?bits:0;
  584. }
  585. #endif
  586.  
  587. /*
  588. * XP SP3 PAE's documented/internal MDL/MMIO mapper on this kernel truncates
  589. * the PFN with 0x03FFFFFF. For framebuffer 0xA000800000 that produces PFN
  590. * 0x02000800 -> physical 0x2000800000, which WinDbg proved is wrong.
  591. *
  592. * 0.4.1 incorrectly replaced the RAM PTEs of a nonpaged-pool allocation.
  593. * MiFreePoolPages can inspect an adjacent allocation's PFN while coalescing
  594. * free pool pages. A device PFN has no ordinary RAM/pool PFN metadata there.
  595. * Restoring those RAM PTEs only when UNMAP arrives is too late.
  596. *
  597. * 0.4.2 reserves VA/system PTEs with MmAllocateMappingAddress instead. This
  598. * allocation is not pool RAM. Save the INVALID reserved PTEs, and change
  599. * only the requested range; allocator metadata outside that range is left
  600. * untouched. Restore the invalid PTEs and flush all CPUs before releasing
  601. * the reservation with MmFreeMappingAddress. ExFreePool is used only for
  602. * the separate saved-PTE array, whose RAM mapping is never modified.
  603. *
  604. * Called by HwVidStartIO (pageable context); mapping reservation/free require
  605. * IRQL <= APC_LEVEL. The direct PTE writes remain an XP-x86-PAE-specific
  606. * experimental workaround, not the documented reserved-MDL mapping path.
  607. */
  608. static void unmap_high_fb(VGAGOP_EXTENSION *e);
  609. static int map_high_fb(VGAGOP_EXTENSION *e)
  610. {
  611. ULONGLONG phys,base,newpte,oldpte,pde,last;
  612. ULONG off,total,pages,i,bits;
  613. UCHAR *reserve;
  614. ULONGLONG *saved;
  615. volatile ULONG *pte;
  616.  
  617. if(e->MappedBase) return 1;
  618. VgaGopDiag[D_STAGE]=6;
  619. e->Cr4=vgagop_read_cr4();
  620. if(!(e->Cr4&0x20UL)) {
  621. DbgPrint("VGAGOP: map rejected: CR4.PAE is not set\n");
  622. return 0;
  623. }
  624. bits=vgagop_phys_bits();e->PhysicalBits=bits;
  625. if(bits<32||bits>52)return 0;
  626. phys=e->FbPhysical;
  627. off=(ULONG)(phys & (PAGE_SIZE-1));
  628. base=phys-(ULONGLONG)off;
  629. if(!e->FbLength || e->FbLength>0xFFFFFFFFUL-off-(PAGE_SIZE-1)) return 0;
  630. total=(e->FbLength+off+PAGE_SIZE-1)&~(PAGE_SIZE-1);
  631. if(!total || total<e->FbLength) return 0;
  632. pages=total>>PAGE_SHIFT;
  633. if(!pages || pages>0x4000UL) return 0;
  634. last=base+((ULONGLONG)(pages-1)<<PAGE_SHIFT);
  635. if(last<base || (base&~VGAGOP_PTE_PHYS_MASK) || (last&~VGAGOP_PTE_PHYS_MASK)) return 0;
  636.  
  637. if(last>=((ULONGLONG)1<<bits))return 0;
  638.  
  639. reserve=(UCHAR*)MmAllocateMappingAddress(total,VGAGOP_MAP_TAG);
  640. if(!reserve) {
  641. DbgPrint("VGAGOP: MmAllocateMappingAddress failed for %08lx bytes\n",total);
  642. return 0;
  643. }
  644. /* The mapping reservation must start on a page boundary. */
  645. if(((ULONG_PTR)reserve & (PAGE_SIZE-1))!=0) {
  646. MmFreeMappingAddress(reserve,VGAGOP_MAP_TAG);
  647. return 0;
  648. }
  649. VgaGopDiag[D_STAGE]=7;
  650. saved=(ULONGLONG*)ExAllocatePoolWithTag(NonPagedPool,pages*sizeof(ULONGLONG),VGAGOP_SAVE_TAG);
  651. if(!saved) {
  652. MmFreeMappingAddress(reserve,VGAGOP_MAP_TAG);
  653. return 0;
  654. }
  655.  
  656. /* Verify the entire reservation before changing ANY PTE. Check the PDE
  657. * before dereferencing its PTE page; reject absent/large-page mappings. */
  658. for(i=0;i<pages;i++) {
  659. pde=vgagop_load_pte(vgagop_pde_for_va(reserve+(i<<PAGE_SHIFT)));
  660. if(!(pde&1ULL) || (pde&0x80ULL)) {
  661. DbgPrint("VGAGOP: reserved VA has unsuitable PDE at page %lu\n",i);
  662. ExFreePool(saved);
  663. MmFreeMappingAddress(reserve,VGAGOP_MAP_TAG);
  664. return 0;
  665. }
  666. pte=vgagop_pte_for_va(reserve+(i<<PAGE_SHIFT));
  667. oldpte=vgagop_load_pte(pte);
  668. if(oldpte&1ULL) {
  669. DbgPrint("VGAGOP: reserved PTE unexpectedly present at page %lu\n",i);
  670. ExFreePool(saved);
  671. MmFreeMappingAddress(reserve,VGAGOP_MAP_TAG);
  672. return 0;
  673. }
  674. saved[i]=oldpte;
  675. }
  676.  
  677. e->MappingAddress=reserve;
  678. e->SavedPtes=saved;
  679. e->MapPages=pages;
  680. e->MapLength=total;
  681.  
  682. for(i=0;i<pages;i++) {
  683. pte=vgagop_pte_for_va(reserve+(i<<PAGE_SHIFT));
  684. newpte=((base+((ULONGLONG)i<<PAGE_SHIFT))&VGAGOP_PTE_PHYS_MASK)|VGAGOP_PTE_UC_FLAGS;
  685. vgagop_store_pte(pte,newpte);
  686. }
  687. /* Verify every raw 64-bit value before exposing the VA to GDI. */
  688. for(i=0;i<pages;i++) {
  689. newpte=(base+((ULONGLONG)i<<PAGE_SHIFT))|VGAGOP_PTE_UC_FLAGS;
  690. if(vgagop_load_pte(vgagop_pte_for_va(reserve+(i<<PAGE_SHIFT)))!=newpte) {
  691. unmap_high_fb(e);return 0;
  692. }
  693. }
  694. KeFlushEntireTb(TRUE,TRUE);
  695. e->MappedBase=reserve+off;
  696. pte=vgagop_pte_for_va(reserve);
  697. newpte=vgagop_load_pte(pte);
  698. DbgPrint("VGAGOP 1.0: reserved system VA=%08lx bytes=%08lx PTE=%08lx raw=%08lx%08lx\n",
  699. (ULONG_PTR)e->MappedBase,total,(ULONG_PTR)pte,
  700. (ULONG)(newpte>>32),(ULONG)newpte);
  701. return 1;
  702. }
  703.  
  704. static void unmap_high_fb(VGAGOP_EXTENSION *e)
  705. {
  706. ULONG i;
  707. UCHAR *reserve=(UCHAR*)e->MappingAddress;
  708. if(reserve && e->SavedPtes && e->MapPages) {
  709. for(i=0;i<e->MapPages;i++)
  710. vgagop_store_pte(vgagop_pte_for_va(reserve+(i<<PAGE_SHIFT)),e->SavedPtes[i]);
  711. KeFlushEntireTb(TRUE,TRUE);
  712. }
  713. e->MappedBase=NULL;
  714. e->PixelTestDone=0;
  715. e->MapLength=0;
  716. e->MapPages=0;
  717. if(e->SavedPtes) ExFreePool(e->SavedPtes);
  718. e->SavedPtes=NULL;
  719. if(e->MappingAddress) MmFreeMappingAddress(e->MappingAddress,VGAGOP_MAP_TAG);
  720. e->MappingAddress=NULL;
  721. }
  722.  
  723. static void vgagop_draw_screen(VGAGOP_EXTENSION *e) {
  724. G35_SCREEN s;ULONGLONG pte=vgagop_load_pte(vgagop_pte_for_va(e->MappingAddress));
  725. g35_begin(&s,(volatile G35_U32*)e->MappedBase,&e->Record.Gop,"VGAGOP 1.0 / XP DRIVER TESTS");
  726. g35_common(&s,&e->Record,&e->Pixels);
  727. g35_text(&s,"XP CR4 ");g35_hex(&s,e->Cr4,8);g35_text(&s," PAE ");g35_text(&s,e->Cr4&0x20?"PASS":"FAIL");
  728. g35_text(&s," PHYSICAL BITS ");g35_num(&s,e->PhysicalBits);g35_char(&s,'\n');
  729. g35_text(&s,"SYSTEM VA ");g35_hex(&s,(ULONG_PTR)e->MappedBase,8);g35_text(&s," PAGES ");g35_num(&s,e->MapPages);g35_char(&s,'\n');
  730. g35_text(&s,"FIRST RAW PTE 0X");g35_hex(&s,pte,16);g35_char(&s,'\n');
  731. g35_text(&s,"PCI ID / ALL SIX BARS / MEMORY DECODE: PASS\n");
  732. g35_text(&s,"VIDEOPORT RESOURCE CLAIM STATUS ");g35_num(&s,VgaGopDiag[D_CLAIM_STATUS]);g35_char(&s,'\n');
  733. g35_text(&s,"RESERVED SYSTEM PTE CHECKS / 64 BIT ADDRESS: PASS\n");
  734. g35_text(&s,"GDI DESKTOP: NOT YET CONFIRMED\n");
  735. g35_text(&s,"THIS PAGE MAY BE REPLACED BY XP. RUN GOPDIAG.EXE\n");
  736. }
  737. static void vgagop_snapshot(VGAGOP_EXTENSION *e,G35_DIAG_PACKET *p) {
  738. ULONG i;ULONGLONG raw=0;
  739. bse_zero(p,sizeof(*p));p->Magic=G35_DIAG_MAGIC;p->Size=sizeof(*p);p->Version=G35_VERSION;
  740. p->Cr4=e->Cr4;p->PhysicalBits=e->PhysicalBits;p->PixelTestDone=e->PixelTestDone;p->MapUsers=e->MapUsers;
  741. if(e->MappingAddress)raw=vgagop_load_pte(vgagop_pte_for_va(e->MappingAddress));
  742. p->RawPteLow=(G35_U32)raw;p->RawPteHigh=(G35_U32)(raw>>32);
  743. for(i=0;i<64;i++)p->Diag[i]=VgaGopDiag[i];p->Record=e->Record;p->Pixels=e->Pixels;
  744. }
  745. static void vgagop_seed_note(VGAGOP_EXTENSION *e,int ok) {
  746. G35_SCREEN s;
  747. if(e->MapUsers||!e->PixelTestDone)return;
  748. s.G=&e->Record.Gop;s.Fb=(volatile G35_U32*)e->MappedBase;
  749. s.Scale=s.G->Width>=1000&&s.G->Height>=720?2:1;
  750. s.X=18;s.Y=s.G->Height-120;s.Ink=g35_color(&s,ok?0x64e3ff:0xffdd77);
  751. g35_rect(&s,18,s.Y,s.G->Width-36,20,g35_color(&s,0x081727));
  752. g35_text(&s,ok?"GDI SEED PASS A ":"GDI SEED FAIL A ");g35_hex(&s,VgaGopDiag[D_TEST_A],8);
  753. g35_text(&s," B ");g35_hex(&s,VgaGopDiag[D_TEST_B],8);
  754. g35_text(&s," FINAL ");g35_hex(&s,VgaGopDiag[D_PRIME_READ],8);vgagop_fence();
  755. }
  756.  
  757. static VP_STATUS map_fb(VGAGOP_EXTENSION *e,VIDEO_REQUEST_PACKET *r)
  758. {
  759. VIDEO_MEMORY_INFORMATION *mi;
  760. volatile ULONG *pixel;
  761. UCHAR cfg[64];
  762. VP_STATUS identity_status;
  763. if(r->InputBufferLength<sizeof(VIDEO_MEMORY) || !r->InputBuffer ||
  764. r->OutputBufferLength<sizeof(VIDEO_MEMORY_INFORMATION) || !r->OutputBuffer)
  765. return fail(E_ARGUMENT,ERROR_INSUFFICIENT_BUFFER);
  766. /* This version supports the system-space mapping requested by framebuf.dll. */
  767. if(((VIDEO_MEMORY*)r->InputBuffer)->RequestedVirtualAddress)
  768. return fail(E_ARGUMENT,ERROR_INVALID_PARAMETER);
  769. bse_zero(r->OutputBuffer,sizeof(VIDEO_MEMORY_INFORMATION));
  770. if(e->MapUsers==0xffffffffUL)return fail(E_ARGUMENT,ERROR_BUSY);
  771. if(!e->MappedBase) {
  772. identity_status=identify(e,cfg);
  773. if(identity_status)return identity_status;
  774. VgaGopDiag[D_STAGE]=6;
  775. identity_status=vgagop_restore_bridges(e);
  776. if(identity_status)return identity_status;
  777. identity_status=identify(e,cfg);
  778. if(identity_status)return identity_status;
  779. if(!map_high_fb(e)) return fail(E_MAP,ERROR_IO_DEVICE);
  780. ++VgaGopDiag[D_MAP_COUNT];
  781. }
  782. VgaGopDiag[D_STAGE]=8;
  783. VgaGopDiag[D_FB_VIRTUAL]=(ULONG_PTR)e->MappedBase;
  784. pixel=(volatile ULONG*)e->MappedBase;
  785. if(!e->PixelTestDone) {
  786. if(!g35_pixel_test(&e->Record.Gop,(volatile G35_U32*)pixel,vgagop_fence,vgagop_stall,&e->Pixels)) {
  787. VgaGopDiag[D_MAP_STATUS]=ERROR_IO_DEVICE;
  788. if(!e->MapUsers){unmap_high_fb(e);VgaGopDiag[D_FB_VIRTUAL]=0;}
  789. return fail(E_PIXEL_TEST,ERROR_IO_DEVICE);
  790. }
  791. e->PixelTestDone=1;
  792. vgagop_draw_screen(e);
  793. }
  794. if(!probe_and_prime(pixel)) {
  795. VgaGopDiag[D_MAP_STATUS]=ERROR_IO_DEVICE;
  796. vgagop_seed_note(e,0);
  797. if(!e->MapUsers) {unmap_high_fb(e);VgaGopDiag[D_FB_VIRTUAL]=0;}
  798. return fail(E_PIXEL_TEST,ERROR_IO_DEVICE);
  799. }
  800. vgagop_seed_note(e,1);
  801. VgaGopDiag[D_STAGE]=9; VgaGopDiag[D_MAP_STATUS]=NO_ERROR;
  802. mi=(VIDEO_MEMORY_INFORMATION*)r->OutputBuffer;
  803. mi->VideoRamBase=mi->FrameBufferBase=e->MappedBase;
  804. mi->VideoRamLength=mi->FrameBufferLength=e->FbLength;
  805. ++e->MapUsers;
  806. r->StatusBlock->Information=sizeof(*mi);
  807. return NO_ERROR;
  808. }
  809.  
  810. /* Use the resources of the PnP device, not a second Internal-bus claim.
  811. * A successful API result alone is insufficient: validate bus/slot,
  812. * framebuffer containment and unchanged live PCI identity/BARs.
  813. */
  814. static VP_STATUS claim_pnp(VGAGOP_EXTENSION *e,PVIDEO_PORT_CONFIG_INFO ci)
  815. {
  816. VIDEO_ACCESS_RANGE ranges[16];
  817. ULONG slot=0xffffffffUL,i;
  818. ULONGLONG base,delta;
  819. UCHAR cfg[64];
  820. VP_STATUS st;
  821. VgaGopPciDiag[3]=2;VgaGopPciDiag[8]=0xffffffffUL;VgaGopPciDiag[9]=0;
  822. VgaGopPciDiag[10]=(ULONG)e->FbPhysical;
  823. VgaGopPciDiag[11]=(ULONG)(e->FbPhysical>>32);
  824. VgaGopPciDiag[12]=e->FbLength;
  825. if(!ci||ci->Length<sizeof(*ci)) {VgaGopPciDiag[9]=1;return ERROR_INVALID_PARAMETER;}
  826. VgaGopPciDiag[4]=ci->SystemIoBusNumber;VgaGopPciDiag[5]=ci->AdapterInterfaceType;
  827. if(ci->AdapterInterfaceType!=PCIBus||ci->SystemIoBusNumber!=e->Record.Bus) {
  828. VgaGopPciDiag[9]=2;return ERROR_DEV_NOT_EXIST;
  829. }
  830. bse_zero(ranges,sizeof(ranges));
  831. st=VideoPortGetAccessRanges(e,0,NULL,16,ranges,NULL,NULL,&slot);
  832. ci->BusInterruptLevel=0;ci->BusInterruptVector=0;
  833. VgaGopPciDiag[6]=slot;VgaGopPciDiag[7]=(ULONG)st;
  834. DbgPrint("VGAGOP 1.2: PCI/PnP bus=%lu slot=%08lx GetAccessRanges=%lu FB=%08lx%08lx bytes=%08lx\n",
  835. ci->SystemIoBusNumber,slot,(ULONG)st,(ULONG)(e->FbPhysical>>32),(ULONG)e->FbPhysical,e->FbLength);
  836. if(st) {VgaGopPciDiag[9]=3;return st;}
  837. if(slot!=(e->Record.Device|(e->Record.Function<<5))) {
  838. VgaGopPciDiag[9]=4;return ERROR_DEV_NOT_EXIST;
  839. }
  840. for(i=0;i<16;i++) {
  841. if(ranges[i].RangeInIoSpace||!ranges[i].RangeLength)continue;
  842. base=(ULONGLONG)ranges[i].RangeStart.QuadPart;
  843. if(e->FbPhysical<base)continue;
  844. delta=e->FbPhysical-base;
  845. if(delta>ranges[i].RangeLength||e->FbLength>ranges[i].RangeLength-delta)continue;
  846. VgaGopPciDiag[8]=i;VgaGopPciDiag[13]=(ULONG)base;
  847. VgaGopPciDiag[14]=(ULONG)(base>>32);VgaGopPciDiag[15]=ranges[i].RangeLength;
  848. st=identify(e,cfg);
  849. if(st) {VgaGopPciDiag[9]=6;return st;}
  850. DbgPrint("VGAGOP 1.2: framebuffer is inside this PCI device's assigned memory range %lu\n",i);
  851. return NO_ERROR;
  852. }
  853. VgaGopPciDiag[9]=5;return ERROR_INVALID_PARAMETER;
  854. }
  855.  
  856. static VP_STATUS __stdcall VgaGopFindAdapter(PVOID hw,PVOID context,PWSTR args,
  857. PVIDEO_PORT_CONFIG_INFO ci,PUCHAR again)
  858. {
  859. VGAGOP_EXTENSION *e=(VGAGOP_EXTENSION*)hw;
  860. UCHAR cfg[64];
  861. VIDEO_ACCESS_RANGE range;
  862. VP_STATUS st;
  863. (void)context; (void)args;
  864. *again=FALSE; bse_zero(e,sizeof(*e));
  865. VgaGopDiag[D_STAGE]=2; VgaGopDiag[D_EXTENSION]=(ULONG_PTR)e;
  866. if(!VgaGopRecordReady)return fail(E_GOP,ERROR_DEV_NOT_EXIST);
  867. e->Record=VgaGopRecord;
  868. if(g35_validate(&e->Record))return fail(E_GOP,ERROR_INVALID_PARAMETER);
  869. st=identify(e,cfg); if(st)return st;
  870. e->GopValid=1;
  871. e->FbPhysical=e->Record.Gop.FrameBufferBase;
  872. e->FbLength=e->Record.Gop.PixelsPerScanLine*4*e->Record.Gop.Height;
  873. VgaGopDiag[D_GOP_FLAGS]=e->Record.Gop.Flags;
  874. VgaGopDiag[D_GOP_FB_LO]=(ULONG)e->FbPhysical;
  875. VgaGopDiag[D_GOP_FB_HI]=(ULONG)(e->FbPhysical>>32);
  876. bse_zero(&range,sizeof(range));
  877. range.RangeStart.QuadPart=e->FbPhysical;range.RangeLength=e->FbLength;
  878. range.RangeVisible=1;
  879. VgaGopDiag[D_STAGE]=4;
  880. if((e->FbPhysical>>32)==0)st=claim_pnp(e,ci);
  881. else {
  882. VgaGopPciDiag[3]=1;
  883. st=VideoPortVerifyAccessRanges(hw,1,&range);
  884. }
  885. VgaGopDiag[D_CLAIM_STATUS]=(ULONG)st;
  886. /* Retain the BSE4 high-MMIO workaround ONLY after the checksummed CSM
  887. * record, PCI owner, all six live BAR DWORDs and memory decode match.
  888. * With a low physical range a claim failure is a hard stop. */
  889. if(st && (e->FbPhysical>>32)==0) {
  890. DbgPrint("VGAGOP 1.2: PnP resource validation rejected, detail=%lu\n",VgaGopPciDiag[9]);
  891. /* Relinquish a successfully obtained claim when later validation
  892. * rejects this adapter. Never release on a failed retrieval. */
  893. if(VgaGopPciDiag[7]==0 && VgaGopPciDiag[9]>=4)
  894. VideoPortVerifyAccessRanges(hw,0,NULL);
  895. return fail(E_CLAIM,st);
  896. }
  897. if(st)DbgPrint("VGAGOP: high resource claim=%lu; verified firmware owner and unchanged BARs\n",(ULONG)st);
  898. e->Claimed=1;
  899. VgaGopDiag[D_FB_PHYSICAL]=(ULONG)e->FbPhysical;VgaGopDiag[D_FB_LENGTH]=e->FbLength;
  900. DbgPrint("VGAGOP: PCI %lu:%lu.%lu ID=%08lx mode=%lux%lu pitch=%lu FB=%08lx%08lx\n",
  901. e->Record.Bus,e->Record.Device,e->Record.Function,e->Record.PciId,
  902. e->Record.Gop.Width,e->Record.Gop.Height,e->Record.Gop.PixelsPerScanLine*4,
  903. (ULONG)(e->FbPhysical>>32),(ULONG)e->FbPhysical);
  904. return NO_ERROR;
  905. }
  906. static BOOLEAN __stdcall VgaGopInitialize(PVOID hw)
  907. {
  908. VGAGOP_EXTENSION *e=(VGAGOP_EXTENSION*)hw;
  909. VgaGopDiag[D_STAGE]=5;
  910. return (BOOLEAN)(e->Claimed && e->GopValid);
  911. }
  912. static BOOLEAN __stdcall VgaGopResetHw(PVOID hw,ULONG columns,ULONG rows)
  913. {
  914. (void)hw; (void)columns; (void)rows;
  915. return TRUE; /* Preserve firmware scanout; no VGA or INT10 transition. */
  916. }
  917. /* This firmware-scanout driver cannot restore GPU state after sleep.
  918. * Advertise only On and Shutdown. No fake successful D3/resume operation. */
  919. static VP_STATUS __stdcall VgaGopPower(PVOID hw,ULONG id,VIDEO_POWER_MANAGEMENT *p)
  920. {
  921. (void)hw;
  922. if(!p||p->Length<sizeof(*p))return ERROR_INVALID_PARAMETER;
  923. if(id!=0xffffffffUL&&id!=1)return ERROR_INVALID_PARAMETER;
  924. return (p->PowerState==1||p->PowerState==6)?NO_ERROR:ERROR_INVALID_FUNCTION;
  925. }
  926. static VP_STATUS __stdcall VgaGopChild(PVOID hw,VIDEO_CHILD_ENUM_INFO *info,
  927. PULONG type,PUCHAR descriptor,PULONG uid,PULONG unused)
  928. {
  929. (void)hw;(void)descriptor;
  930. if(unused)*unused=0;
  931. if(!info||info->Size<sizeof(*info)||!type||!uid||!unused)return 1248L;
  932. if(info->ChildIndex==0xffffffffUL) {*type=3;*uid=0xffffffffUL;return 1246L;}
  933. if(info->ChildIndex==1) {*type=1;*uid=1;return 1246L;}
  934. return 1248L; /* One firmware-selected monitor; no fabricated EDID. */
  935. }
  936. static BOOLEAN __stdcall VgaGopStartIO(PVOID hw,PVIDEO_REQUEST_PACKET r)
  937. {
  938. VGAGOP_EXTENSION *e=(VGAGOP_EXTENSION*)hw;
  939. VP_STATUS st=ERROR_INVALID_FUNCTION;
  940. ULONG i,mode,need;
  941. PVOID requested;
  942. VIDEO_NUM_MODES *n;
  943. if(!r || !r->StatusBlock) return FALSE;
  944. r->StatusBlock->Information=0;
  945. /* A diagnostic read must not overwrite the last operational error. */
  946. if(r->IoControlCode==G35_IOCTL_DIAG) {
  947. if(!r->OutputBuffer||r->OutputBufferLength<sizeof(G35_DIAG_PACKET))st=ERROR_INSUFFICIENT_BUFFER;
  948. else if(vgagop_cas(&e->Busy,1,0))st=ERROR_BUSY;
  949. else {
  950. vgagop_snapshot(e,(G35_DIAG_PACKET*)r->OutputBuffer);
  951. r->StatusBlock->Information=sizeof(G35_DIAG_PACKET);st=NO_ERROR;
  952. vgagop_fence();(void)vgagop_cas(&e->Busy,0,1);
  953. }
  954. r->StatusBlock->u.Status=st;return TRUE;
  955. }
  956. VgaGopDiag[D_IOCTL]=r->IoControlCode;
  957. i=VgaGopDiag[D_HISTORY_NEXT]++ & 15;
  958. VgaGopDiag[D_HISTORY+i]=r->IoControlCode;
  959. if(vgagop_cas(&e->Busy,1,0)) {
  960. r->StatusBlock->u.Status=fail(E_LOCK,ERROR_BUSY); return TRUE;
  961. }
  962. VgaGopDiag[D_LOCK]=1;
  963. switch(r->IoControlCode) {
  964. case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
  965. if(!r->OutputBuffer || r->OutputBufferLength<sizeof(VIDEO_NUM_MODES)) {st=ERROR_INSUFFICIENT_BUFFER; break;}
  966. n=(VIDEO_NUM_MODES*)r->OutputBuffer;
  967. n->NumModes=BSE_MODECOUNT; n->ModeInformationLength=sizeof(VIDEO_MODE_INFORMATION);
  968. r->StatusBlock->Information=sizeof(*n); st=NO_ERROR; break;
  969. case IOCTL_VIDEO_QUERY_AVAIL_MODES:
  970. need=BSE_MODECOUNT*sizeof(VIDEO_MODE_INFORMATION);
  971. if(!r->OutputBuffer || r->OutputBufferLength<need) {st=ERROR_INSUFFICIENT_BUFFER; break;}
  972. for(i=0;i<BSE_MODECOUNT;i++) fill_mode(e,(VIDEO_MODE_INFORMATION*)r->OutputBuffer+i,i);
  973. r->StatusBlock->Information=need; st=NO_ERROR; break;
  974. case IOCTL_VIDEO_QUERY_CURRENT_MODE:
  975. if(!r->OutputBuffer || r->OutputBufferLength<sizeof(VIDEO_MODE_INFORMATION)) {st=ERROR_INSUFFICIENT_BUFFER; break;}
  976. fill_mode(e,(VIDEO_MODE_INFORMATION*)r->OutputBuffer,e->CurrentMode);
  977. r->StatusBlock->Information=sizeof(VIDEO_MODE_INFORMATION); st=NO_ERROR; break;
  978. case IOCTL_VIDEO_SET_CURRENT_MODE:
  979. if(!r->InputBuffer || r->InputBufferLength<sizeof(VIDEO_MODE)) {st=ERROR_INSUFFICIENT_BUFFER; break;}
  980. mode=((VIDEO_MODE*)r->InputBuffer)->RequestedMode&0x3FFFFFFFUL;
  981. if(mode>=BSE_MODECOUNT) {st=ERROR_INVALID_PARAMETER; break;}
  982. ++VgaGopDiag[D_SET_COUNT]; st=NO_ERROR;
  983. e->CurrentMode=mode; VgaGopDiag[D_MODE]=mode;
  984. break;
  985. case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
  986. st=map_fb(e,r); break;
  987. case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
  988. if(!r->InputBuffer || r->InputBufferLength<sizeof(VIDEO_MEMORY)) {st=ERROR_INSUFFICIENT_BUFFER; break;}
  989. requested=((VIDEO_MEMORY*)r->InputBuffer)->RequestedVirtualAddress;
  990. if(requested && requested!=e->MappedBase) {st=ERROR_INVALID_PARAMETER; break;}
  991. if(!e->MapUsers){st=ERROR_INVALID_PARAMETER;break;}
  992. --e->MapUsers;
  993. if(!e->MapUsers && e->MappedBase) {unmap_high_fb(e); ++VgaGopDiag[D_UNMAP_COUNT];VgaGopDiag[D_FB_VIRTUAL]=0;}
  994. st=NO_ERROR; break;
  995. case IOCTL_VIDEO_RESET_DEVICE:
  996. st=NO_ERROR; break;
  997. default:
  998. break; /* Optional pointer/color IOCTLs: framebuf uses software/defaults. */
  999. }
  1000. r->StatusBlock->u.Status=st; VgaGopDiag[D_STATUS]=(ULONG)st;
  1001. VgaGopDiag[D_LOCK]=0; vgagop_fence(); (void)vgagop_cas(&e->Busy,0,1);
  1002. return TRUE;
  1003. }
  1004.  
  1005. static ULONG __stdcall VgaGopStart(PVOID context1,PVOID context2)
  1006. {
  1007. VIDEO_HW_INITIALIZATION_DATA init;
  1008. ULONG status;
  1009. bse_zero(&init,sizeof(init));
  1010. VgaGopDiag[D_STAGE]=1;
  1011. init.HwInitDataSize=sizeof(init); init.AdapterInterfaceType=Internal;
  1012. init.HwFindAdapter=VgaGopFindAdapter; init.HwInitialize=VgaGopInitialize;
  1013. init.HwStartIO=VgaGopStartIO; init.HwResetHw=VgaGopResetHw;
  1014. init.HwDeviceExtensionSize=sizeof(VGAGOP_EXTENSION);
  1015. /* Keep the high-address workaround's entry path; low MMIO uses PnP.
  1016. * XP recognizes PnP miniports through these three callbacks. */
  1017. if((VgaGopRecord.Gop.FrameBufferBase>>32)==0) {
  1018. init.AdapterInterfaceType=PCIBus;
  1019. init.HwSetPowerState=VgaGopPower;init.HwGetPowerState=VgaGopPower;
  1020. init.HwGetVideoChildDescriptor=VgaGopChild;
  1021. VgaGopPciDiag[3]=2;
  1022. } else VgaGopPciDiag[3]=1;
  1023. DbgPrint("VGAGOP 1.2 / CSM36: resource path=%lu (1=legacy high, 2=PCI/PnP low)\n",VgaGopPciDiag[3]);
  1024. status=VideoPortInitialize(context1,context2,&init,NULL);
  1025. VgaGopDiag[D_ENTRY_STATUS]=status;
  1026. if(status) DbgPrint("VGAGOP: VideoPortInitialize failed, NTSTATUS=%08lx\n",status);
  1027. return status;
  1028. }
  1029.  
  1030. /* DriverEntry in the ORIGINAL vga.c calls this before its legacy code. */
  1031. int __stdcall VgaGopTryStart(PVOID context1,PVOID context2,PULONG status)
  1032. {
  1033. int found;
  1034. VgaGopRecordReady=0;
  1035. found=read_handoff();
  1036. if(!found)return 0;
  1037. if(found<0){
  1038. VgaGopDiag[D_ERROR]=E_GOP;
  1039. DbgPrint("VGAGOP: invalid, ambiguous or old CSM handoff. Need matching csm35/csm36 handoff. Legacy VGA path blocked.\n");
  1040. *status=0xc000000dUL;return 1;
  1041. }
  1042. VgaGopRecordReady=1;
  1043. *status=VgaGopStart(context1,context2);
  1044. return 1;
  1045. }
Advertisement
Add Comment
Please, Sign In to add comment