Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2125 lines
58 KiB

  1. /*++
  2. Copyright (c) 1990-2000 Microsoft Corporation
  3. Module Name:
  4. porti386.c
  5. Abstract:
  6. This is the x86 specific part of the video port driver.
  7. Author:
  8. Andre Vachon (andreva) 10-Jan-1991
  9. Environment:
  10. kernel mode only
  11. Notes:
  12. This module is a driver which implements OS dependant functions on the
  13. behalf of the video drivers
  14. Revision History:
  15. --*/
  16. #include "videoprt.h"
  17. #include "vdm.h"
  18. //#include "..\..\..\nthals\x86new\xm86.h"
  19. //#include "..\..\..\nthals\x86new\x86new.h"
  20. VP_STATUS
  21. SymmetryDeviceDataCallback(
  22. PVOID HwDeviceExtension,
  23. PVOID Context,
  24. VIDEO_DEVICE_DATA_TYPE DeviceDataType,
  25. PVOID Identifier,
  26. ULONG IdentifierLength,
  27. PVOID ConfigurationData,
  28. ULONG ConfigurationDataLength,
  29. PVOID ComponentInformation,
  30. ULONG ComponentInformationLength
  31. );
  32. #ifdef ALLOC_PRAGMA
  33. #pragma alloc_text(PAGE,pVideoPortEnableVDM)
  34. #pragma alloc_text(PAGE,pVideoPortInitializeInt10)
  35. #pragma alloc_text(PAGE,VideoPortInt10)
  36. #pragma alloc_text(PAGE,SymmetryDeviceDataCallback)
  37. #pragma alloc_text(PAGE,pVideoPortRegisterVDM)
  38. #pragma alloc_text(PAGE,pVideoPortSetIOPM)
  39. #pragma alloc_text(PAGE,VideoPortSetTrappedEmulatorPorts)
  40. #pragma alloc_text(PAGE,VpInt10AllocateBuffer)
  41. #pragma alloc_text(PAGE,VpInt10FreeBuffer)
  42. #pragma alloc_text(PAGE,VpInt10ReadMemory)
  43. #pragma alloc_text(PAGE,VpInt10WriteMemory)
  44. #pragma alloc_text(PAGE,VpInt10CallBios)
  45. #pragma alloc_text(PAGE,pVideoPortGetVDMBiosData)
  46. #pragma alloc_text(PAGE,pVideoPortPutVDMBiosData)
  47. #endif
  48. VP_STATUS
  49. SymmetryDeviceDataCallback(
  50. PVOID HwDeviceExtension,
  51. PVOID Context,
  52. VIDEO_DEVICE_DATA_TYPE DeviceDataType,
  53. PVOID Identifier,
  54. ULONG IdentifierLength,
  55. PVOID ConfigurationData,
  56. ULONG ConfigurationDataLength,
  57. PVOID ComponentInformation,
  58. ULONG ComponentInformationLength
  59. )
  60. {
  61. if (RtlCompareMemory(L"SEQUENT Symmetry",
  62. Identifier,
  63. sizeof(L"SEQUENT Symmetry")) ==
  64. sizeof(L"SEQUENT Symmetry"))
  65. {
  66. return NO_ERROR;
  67. }
  68. return ERROR_INVALID_PARAMETER;
  69. }
  70. NTSTATUS
  71. pVideoPortEnableVDM(
  72. IN PFDO_EXTENSION FdoExtension,
  73. IN BOOLEAN Enable,
  74. IN PVIDEO_VDM VdmInfo,
  75. IN ULONG VdmInfoSize
  76. )
  77. /*++
  78. Routine Description:
  79. This routine allows the kernel video driver to hook out I/O ports or
  80. specific interrupts from the V86 fault handler. Operations on the
  81. specified ports which are intercepted by the V86 fault handler will be
  82. forwarded to the kernel driver directly.
  83. Arguments:
  84. DeviceExtension - Pointer to the port driver's device extension.
  85. Enable - Determines if the VDM should be enabled (TRUE) or disabled
  86. (FALSE).
  87. VdmInfo - Pointer to the VdmInfo passed by the caller.
  88. VdmInfoSize - Size of the VdmInfo struct passed by the caller.
  89. Return Value:
  90. Return the value returned by ZwSetInformationProcess().
  91. --*/
  92. {
  93. PROCESS_IO_PORT_HANDLER_INFORMATION processHandlerInfo;
  94. NTSTATUS ntStatus;
  95. PEPROCESS process;
  96. PVOID virtualAddress;
  97. ULONG length;
  98. ULONG defaultMask = 0;
  99. ULONG inIoSpace = VIDEO_MEMORY_SPACE_MEMORY |
  100. VIDEO_MEMORY_SPACE_USER_MODE;
  101. //
  102. // Must make sure the caller is a trusted subsystem with the
  103. // appropriate privilege level before executing this call.
  104. // If the calls returns FALSE we must return an error code.
  105. //
  106. if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(
  107. SE_TCB_PRIVILEGE),
  108. FdoExtension->CurrentIrpRequestorMode)) {
  109. return STATUS_PRIVILEGE_NOT_HELD;
  110. }
  111. //
  112. // Test to see if the parameter size is valid
  113. //
  114. if (VdmInfoSize < sizeof(VIDEO_VDM) ) {
  115. return STATUS_BUFFER_TOO_SMALL;
  116. }
  117. //
  118. // Set the enable flag in the process struct and put in the length and
  119. // pointer to the emulator info struct.
  120. //
  121. if (Enable) {
  122. processHandlerInfo.Install = TRUE;
  123. } else {
  124. processHandlerInfo.Install = FALSE;
  125. }
  126. processHandlerInfo.NumEntries =
  127. FdoExtension->NumEmulatorAccessEntries;
  128. processHandlerInfo.EmulatorAccessEntries =
  129. FdoExtension->EmulatorAccessEntries;
  130. processHandlerInfo.Context = FdoExtension->EmulatorAccessEntriesContext;
  131. //
  132. // Call SetInformationProcess
  133. //
  134. ntStatus = ZwSetInformationProcess(VdmInfo->ProcessHandle,
  135. ProcessIoPortHandlers,
  136. &processHandlerInfo,
  137. sizeof(PROCESS_IO_PORT_HANDLER_INFORMATION));
  138. if (!NT_SUCCESS(ntStatus)) {
  139. return ntStatus;
  140. }
  141. //
  142. // If we are disabling the DOS application, give it the original IOPM
  143. // it had (which is mask zero.
  144. // If we are enabling it, then wait for the miniport to call to set it up
  145. // appropriately.
  146. //
  147. ntStatus = ObReferenceObjectByHandle(VdmInfo->ProcessHandle,
  148. 0,
  149. *(PVOID *)PsProcessType,
  150. FdoExtension->CurrentIrpRequestorMode,
  151. (PVOID *)&process,
  152. NULL);
  153. if (NT_SUCCESS(ntStatus)) {
  154. if (Enable) {
  155. defaultMask = 1;
  156. //
  157. // This will be used later while saving the hardware state
  158. //
  159. FdoExtension->VdmProcess = process;
  160. } // otherwise we are disabling and the mask number is 0;
  161. if (!Ke386IoSetAccessProcess(PEProcessToPKProcess(process),
  162. defaultMask)) {
  163. ntStatus = STATUS_IO_PRIVILEGE_FAILED;
  164. }
  165. ObDereferenceObject(process);
  166. }
  167. if (!NT_SUCCESS(ntStatus)) {
  168. if (Enable) {
  169. processHandlerInfo.Install = FALSE;
  170. ZwSetInformationProcess(VdmInfo->ProcessHandle,
  171. ProcessIoPortHandlers,
  172. &processHandlerInfo,
  173. sizeof(PROCESS_IO_PORT_HANDLER_INFORMATION));
  174. }
  175. return ntStatus;
  176. }
  177. //
  178. // We can now map (or unmap) the video frame buffer into the VDM's
  179. // address space.
  180. //
  181. virtualAddress = (PVOID) FdoExtension->VdmPhysicalVideoMemoryAddress.LowPart;
  182. //
  183. // Override this with A0000 for the Sequent Symmetry machine.
  184. //
  185. if (VideoPortGetDeviceData(FdoExtension->HwDeviceExtension,
  186. VpMachineData,
  187. &SymmetryDeviceDataCallback,
  188. NULL) == NO_ERROR)
  189. {
  190. virtualAddress = (PVOID) 0xA0000;
  191. }
  192. length = FdoExtension->VdmPhysicalVideoMemoryLength;
  193. if (Enable) {
  194. return pVideoPortMapUserPhysicalMem(FdoExtension,
  195. VdmInfo->ProcessHandle,
  196. FdoExtension->VdmPhysicalVideoMemoryAddress,
  197. &length,
  198. &inIoSpace,
  199. (PVOID *) &virtualAddress);
  200. } else {
  201. return ZwUnmapViewOfSection(VdmInfo->ProcessHandle,
  202. (PVOID)( ((ULONG)virtualAddress) & (~(PAGE_SIZE - 1))) );
  203. }
  204. } // pVideoPortEnableVDM()
  205. VP_STATUS
  206. VpInt10AllocateBuffer(
  207. IN PVOID Context,
  208. OUT PUSHORT Seg,
  209. OUT PUSHORT Off,
  210. IN OUT PULONG Length
  211. )
  212. {
  213. VP_STATUS Status = STATUS_INSUFFICIENT_RESOURCES;
  214. if (Int10BufferAllocated == FALSE) {
  215. if (*Length <= 0x1000) {
  216. *Seg = VDM_TRANSFER_SEGMENT;
  217. *Off = VDM_TRANSFER_OFFSET;
  218. Int10BufferAllocated = TRUE;
  219. Status = NO_ERROR;
  220. }
  221. }
  222. *Length = VDM_TRANSFER_LENGTH;
  223. return Status;
  224. }
  225. VP_STATUS
  226. VpInt10FreeBuffer(
  227. IN PVOID Context,
  228. IN USHORT Seg,
  229. IN USHORT Off
  230. )
  231. {
  232. VP_STATUS Status = STATUS_INVALID_PARAMETER;
  233. if ((VDM_TRANSFER_SEGMENT == Seg) && (VDM_TRANSFER_OFFSET == Off)) {
  234. if (Int10BufferAllocated == TRUE) {
  235. Int10BufferAllocated = FALSE;
  236. Status = NO_ERROR;
  237. }
  238. }
  239. return Status;
  240. }
  241. VP_STATUS
  242. VpInt10ReadMemory(
  243. IN PVOID Context,
  244. IN USHORT Seg,
  245. IN USHORT Off,
  246. OUT PVOID Buffer,
  247. IN ULONG Length
  248. )
  249. {
  250. BOOLEAN bAttachProcess = FALSE;
  251. PVOID Memory = (PVOID)((Seg << 4) + Off);
  252. VP_STATUS Status = NO_ERROR;
  253. if(!CsrProcess) return STATUS_INVALID_PARAMETER;
  254. if (PsGetCurrentProcess() != CsrProcess)
  255. {
  256. bAttachProcess = TRUE;
  257. KeAttachProcess(PEProcessToPKProcess(CsrProcess));
  258. }
  259. try {
  260. RtlCopyMemory(Buffer, Memory, Length);
  261. } except (EXCEPTION_EXECUTE_HANDLER) {
  262. Status = STATUS_INVALID_PARAMETER;
  263. }
  264. if (bAttachProcess) {
  265. KeDetachProcess();
  266. }
  267. return Status;
  268. }
  269. VP_STATUS
  270. VpInt10WriteMemory(
  271. IN PVOID Context,
  272. IN USHORT Seg,
  273. IN USHORT Off,
  274. IN PVOID Buffer,
  275. IN ULONG Length
  276. )
  277. {
  278. BOOLEAN bAttachProcess = FALSE;
  279. PVOID Memory = (PVOID)((Seg << 4) + Off);
  280. VP_STATUS Status = NO_ERROR;
  281. if(!CsrProcess) return STATUS_INVALID_PARAMETER;
  282. if (PsGetCurrentProcess() != CsrProcess)
  283. {
  284. bAttachProcess = TRUE;
  285. KeAttachProcess(PEProcessToPKProcess(CsrProcess));
  286. }
  287. try {
  288. RtlCopyMemory(Memory, Buffer, Length);
  289. } except (EXCEPTION_EXECUTE_HANDLER) {
  290. Status = STATUS_INVALID_PARAMETER;
  291. }
  292. if (bAttachProcess) {
  293. KeDetachProcess();
  294. }
  295. return Status;
  296. }
  297. #define BAD_BIOS_SIGNATURE 0xB105
  298. VP_STATUS
  299. VpInt10CallBios(
  300. PVOID HwDeviceExtension,
  301. PINT10_BIOS_ARGUMENTS BiosArguments
  302. )
  303. /*++
  304. Routine Description:
  305. This function allows a miniport driver to call the kernel to perform
  306. an int10 operation.
  307. This will execute natively the BIOS ROM code on the device.
  308. THIS FUNCTION IS FOR X86 ONLY.
  309. Arguments:
  310. HwDeviceExtension - Pointer to the miniport driver's device extension.
  311. BiosArguments - Pointer to a structure containing the value of the
  312. basic x86 registers that should be set before calling the BIOS routine.
  313. 0 should be used for unused registers.
  314. Return Value:
  315. Restrictions:
  316. Device uses IO ports ONLY.
  317. --*/
  318. {
  319. NTSTATUS ntStatus;
  320. CONTEXT context;
  321. BOOLEAN bAttachProcess = FALSE;
  322. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
  323. //
  324. // Must make sure the caller is a trusted subsystem with the
  325. // appropriate address space set up.
  326. //
  327. if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(
  328. SE_TCB_PRIVILEGE),
  329. fdoExtension->CurrentIrpRequestorMode)) {
  330. return ERROR_INVALID_PARAMETER;
  331. }
  332. if (ServerBiosAddressSpaceInitialized == 0) {
  333. ASSERT(FALSE);
  334. return ERROR_INVALID_PARAMETER;
  335. }
  336. if (CsrProcess == 0) {
  337. // This might happen if we're shutting down the system.
  338. return NO_ERROR;
  339. }
  340. if (PsGetCurrentProcess() != CsrProcess)
  341. {
  342. bAttachProcess = TRUE;
  343. KeAttachProcess(PEProcessToPKProcess(CsrProcess));
  344. }
  345. //
  346. // Zero out the context and initialize the required values with the
  347. // miniport's requested register values.
  348. //
  349. RtlZeroMemory(&context, sizeof(CONTEXT));
  350. context.Edi = BiosArguments->Edi;
  351. context.Esi = BiosArguments->Esi;
  352. context.Eax = BiosArguments->Eax;
  353. context.Ebx = BiosArguments->Ebx;
  354. context.Ecx = BiosArguments->Ecx;
  355. context.Edx = BiosArguments->Edx;
  356. context.Ebp = BiosArguments->Ebp;
  357. context.SegDs = BiosArguments->SegDs;
  358. context.SegEs = BiosArguments->SegEs;
  359. //
  360. // Now call the kernel to actually perform the int 10 operation.
  361. // We wrap thiw with a try/except in case csrss is gone.
  362. //
  363. KeWaitForSingleObject(&VpInt10Mutex,
  364. Executive,
  365. KernelMode,
  366. FALSE,
  367. (PTIME)NULL);
  368. try {
  369. ntStatus = Ke386CallBios(0x10, &context);
  370. } except (EXCEPTION_EXECUTE_HANDLER) {
  371. ntStatus = GetExceptionCode();
  372. }
  373. KeReleaseMutex(&VpInt10Mutex, FALSE);
  374. if (bAttachProcess) {
  375. KeDetachProcess();
  376. }
  377. //
  378. // fill in struct with any return values from the context
  379. //
  380. BiosArguments->Edi = context.Edi;
  381. BiosArguments->Esi = context.Esi;
  382. BiosArguments->Eax = context.Eax;
  383. BiosArguments->Ebx = context.Ebx;
  384. BiosArguments->Ecx = context.Ecx;
  385. BiosArguments->Edx = context.Edx;
  386. BiosArguments->Ebp = context.Ebp;
  387. BiosArguments->SegDs = (USHORT)context.SegDs;
  388. BiosArguments->SegEs = (USHORT)context.SegEs;
  389. //
  390. // Return that status we got when calling the BIOS (writting to the
  391. // is secondary at best).
  392. //
  393. if (NT_SUCCESS(ntStatus)) {
  394. pVideoDebugPrint ((2, "VIDEOPRT: Int10: Int 10 succeded properly\n"));
  395. } else {
  396. pVideoDebugPrint ((0, "VIDEOPRT: Int10 failed - status %08lx\n", ntStatus));
  397. }
  398. if (((BiosArguments->Eax & 0xffff) == 0x014f) &&
  399. ((BiosArguments->Ebx & 0xffff) == BAD_BIOS_SIGNATURE) ) {
  400. pVideoDebugPrint ((0, "VIDEOPRT: Video bios error detected at CS:IP = %4x:%4x\n",
  401. (USHORT) BiosArguments->Ecx, (USHORT) BiosArguments->Edx));
  402. ASSERT(FALSE);
  403. return ERROR_INVALID_PARAMETER;
  404. }
  405. return ntStatus;
  406. }
  407. VP_STATUS
  408. VideoPortInt10(
  409. PVOID HwDeviceExtension,
  410. PVIDEO_X86_BIOS_ARGUMENTS BiosArguments
  411. )
  412. /*++
  413. Routine Description:
  414. This function allows a miniport driver to call the kernel to perform
  415. an int10 operation.
  416. This will execute natively the BIOS ROM code on the device.
  417. THIS FUNCTION IS FOR X86 ONLY.
  418. Arguments:
  419. HwDeviceExtension - Pointer to the miniport driver's device extension.
  420. BiosArguments - Pointer to a structure containing the value of the
  421. basic x86 registers that should be set before calling the BIOS routine.
  422. 0 should be used for unused registers.
  423. Return Value:
  424. Restrictions:
  425. Device uses IO ports ONLY.
  426. --*/
  427. {
  428. NTSTATUS ntStatus;
  429. CONTEXT context;
  430. BOOLEAN bAttachProcess = FALSE;
  431. PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
  432. //
  433. // Must make sure the caller is a trusted subsystem with the
  434. // appropriate address space set up.
  435. //
  436. if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(
  437. SE_TCB_PRIVILEGE),
  438. fdoExtension->CurrentIrpRequestorMode)) {
  439. return ERROR_INVALID_PARAMETER;
  440. }
  441. if (ServerBiosAddressSpaceInitialized == 0) {
  442. pVideoDebugPrint((0, "Warning: Attempt to call VideoPortInt10 before Int10 support is initialized.\n"));
  443. return ERROR_INVALID_PARAMETER;
  444. }
  445. if (CsrProcess == 0) {
  446. // This might happen if we're shutting down the system.
  447. return NO_ERROR;
  448. }
  449. if (PsGetCurrentProcess() != CsrProcess)
  450. {
  451. bAttachProcess = TRUE;
  452. KeAttachProcess(PEProcessToPKProcess(CsrProcess));
  453. }
  454. //
  455. // Zero out the context and initialize the required values with the
  456. // miniport's requested register values.
  457. //
  458. RtlZeroMemory(&context, sizeof(CONTEXT));
  459. context.Edi = BiosArguments->Edi;
  460. context.Esi = BiosArguments->Esi;
  461. context.Eax = BiosArguments->Eax;
  462. context.Ebx = BiosArguments->Ebx;
  463. context.Ecx = BiosArguments->Ecx;
  464. context.Edx = BiosArguments->Edx;
  465. context.Ebp = BiosArguments->Ebp;
  466. //
  467. // Now call the kernel to actually perform the int 10 operation.
  468. // We wrap thiw with a try/except in case csrss is gone.
  469. // And we need to protect Ke386CallBios from reentrance.
  470. //
  471. KeWaitForSingleObject(&VpInt10Mutex,
  472. Executive,
  473. KernelMode,
  474. FALSE,
  475. (PTIME)NULL);
  476. try {
  477. ntStatus = Ke386CallBios(0x10, &context);
  478. } except (EXCEPTION_EXECUTE_HANDLER) {
  479. ntStatus = GetExceptionCode();
  480. }
  481. KeReleaseMutex(&VpInt10Mutex, FALSE);
  482. if (bAttachProcess) {
  483. KeDetachProcess();
  484. }
  485. //
  486. // fill in struct with any return values from the context
  487. //
  488. BiosArguments->Edi = context.Edi;
  489. BiosArguments->Esi = context.Esi;
  490. BiosArguments->Eax = context.Eax;
  491. BiosArguments->Ebx = context.Ebx;
  492. BiosArguments->Ecx = context.Ecx;
  493. BiosArguments->Edx = context.Edx;
  494. BiosArguments->Ebp = context.Ebp;
  495. //
  496. // Return that status we got when calling the BIOS (writting to the
  497. // is secondary at best).
  498. //
  499. if (NT_SUCCESS(ntStatus)) {
  500. pVideoDebugPrint ((2, "VIDEOPRT: Int10: Int 10 succeded properly\n"));
  501. } else {
  502. pVideoDebugPrint ((0, "VIDEOPRT: Int10 failed - status %08lx\n", ntStatus));
  503. }
  504. if (((BiosArguments->Eax & 0xffff) == 0x014f) &&
  505. ((BiosArguments->Ebx & 0xffff) == BAD_BIOS_SIGNATURE) ) {
  506. pVideoDebugPrint ((0, "VIDEOPRT: Video bios error detected at CS:IP = %4x:%4x\n",
  507. (USHORT) BiosArguments->Ecx, (USHORT) BiosArguments->Edx));
  508. ASSERT(FALSE);
  509. return ERROR_INVALID_PARAMETER;
  510. }
  511. // We have to return NO_ERROR even when we failed the int10,
  512. // because some drivers expect us to always return NO_ERROR.
  513. return NO_ERROR;
  514. } // end VideoPortInt10()
  515. //
  516. // Internal definitions
  517. //
  518. #define KEY_VALUE_BUFFER_SIZE 1024
  519. #define ONE_MEG 0x100000
  520. #define ROM_BIOS_START 0xC0000
  521. #define VIDEO_BUFFER_START 0xA0000
  522. #define DOS_LOADED_ADDRESS 0x700
  523. #define EBIOS_AREA_INFORMATION 0x40
  524. #define INT00_VECTOR_ADDRESS (0x00*4)
  525. #define INTCD_VECTOR_ADDRESS (0xCD*4)
  526. #define INT1A_VECTOR_ADDRESS (0x1A*4)
  527. #define ERROR_HANDLER_SEGMENT 0x3000
  528. #define ERROR_HANDLER_OFFSET 0x0
  529. typedef struct _EBIOS_INFORMATION {
  530. ULONG EBiosAddress;
  531. ULONG EBiosSize;
  532. } EBIOS_INFORMATION, *PEBIOS_INFORMATION;
  533. UCHAR ErrorHandler[] = {
  534. 0x89, 0xe5, // mov bp, sp
  535. 0xb8, 0x4f, 0x01, // mov ax, 0x014f
  536. 0xbb, 0x05, 0xb1, // mov bx, BAD_BIOS_SIGNATURE
  537. 0x8b, 0x56, 0x00, // mov dx,[bp]
  538. 0x8b, 0x4e, 0x02, // mov cx,[bp+0x2]
  539. 0xc4, 0xc4, 0xfe, // BOP 0xfe
  540. 0xcf // iret
  541. };
  542. VOID
  543. pVideoPortInitializeInt10(
  544. PFDO_EXTENSION FdoExtension
  545. )
  546. /*++
  547. Routine Description:
  548. Initializes the CSR address space so we can do an int 10.
  549. Arguments:
  550. HwDeviceExtension - Pointer to the miniport driver's device extension.
  551. Return Value:
  552. Restrictions:
  553. THIS FUNCTION IS FOR X86 ONLY.
  554. THIS FUNCTION MUST BE RUN IN THE CONTEXT OF CSR
  555. This function goes thru ROM BIOS area to map in all the ROM blocks and
  556. allocates memory for the holes inside the BIOS area. The reason we
  557. allocate memory for the holes in BIOS area is because some int 10 BIOS
  558. code touches the nonexisting memory. Under Nt, this triggers page fault
  559. and the int 10 is terminated.
  560. Note: the code is adapted from VdmpInitialize().
  561. --*/
  562. {
  563. NTSTATUS ntStatus;
  564. ULONG inIoSpace = VIDEO_MEMORY_SPACE_MEMORY |
  565. VIDEO_MEMORY_SPACE_USER_MODE;
  566. PVOID virtualAddress;
  567. ULONG length;
  568. ULONG size;
  569. PVOID baseAddress;
  570. OBJECT_ATTRIBUTES ObjectAttributes;
  571. UNICODE_STRING SectionName;
  572. UNICODE_STRING WorkString;
  573. ULONG ViewSize;
  574. LARGE_INTEGER ViewBase;
  575. PVOID BaseAddress;
  576. PVOID destination;
  577. HANDLE SectionHandle, RegistryHandle;
  578. ULONG ResultLength, EndingAddress;
  579. ULONG Index;
  580. PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor;
  581. PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResourceDescriptor;
  582. PKEY_VALUE_FULL_INFORMATION KeyValueBuffer;
  583. CM_ROM_BLOCK RomBlock;
  584. PCM_ROM_BLOCK BiosBlock;
  585. ULONG LastMappedAddress;
  586. PHYSICAL_ADDRESS PhysicalAddress;
  587. PHYSICAL_ADDRESS PhysicalAddressLow, PhysicalAddressHigh, BoundaryAddress;
  588. ULONG AddressSpace = VIDEO_MEMORY_SPACE_MEMORY;
  589. ULONG dwCrc = 0xFFFFFFFF;
  590. PULONG ExtendedBiosLocationInfo;
  591. ULONG ExtendedBiosAddress, ExtendedBiosSize, *IntVectorAddress;
  592. ULONG Int1ACodeAddress;
  593. BOOLEAN Int1AIsValid = FALSE;
  594. //
  595. // NOTE Due to the way compiler optimization code works, I have
  596. // to declare EBiosInformation to be volatile. Otherwise, no
  597. // code will be generated for the EBiosInformation.
  598. // It should be removed once the C compiler is fixed.
  599. //
  600. volatile PEBIOS_INFORMATION EBiosInformation = (PEBIOS_INFORMATION)
  601. (DOS_LOADED_ADDRESS + EBIOS_AREA_INFORMATION);
  602. BOOLEAN EBiosInitialized = FALSE;
  603. //
  604. // If we have already initialized, or for some reason can not, return
  605. // right here.
  606. //
  607. if ((ServerBiosAddressSpaceInitialized == 1) ||
  608. (VpC0000Compatible == 0) ||
  609. (FdoExtension->VdmPhysicalVideoMemoryAddress.LowPart == 0) ||
  610. (CsrProcess == 0))
  611. {
  612. return;
  613. }
  614. //
  615. // It is possible that this routine will end up failing below if
  616. // the 0xA0000 memory range isn't visible to the current display device.
  617. // However, failing half way through the routine is bad because we've
  618. // already done the MEM_COMMIT in csrss. So a subsequent call will
  619. // also fail. So lets try to determine now if we are going to fail.
  620. // This is easier than backing out changes if we do fail!
  621. //
  622. if (!HalTranslateBusAddress(FdoExtension->AdapterInterfaceType,
  623. FdoExtension->SystemIoBusNumber,
  624. FdoExtension->VdmPhysicalVideoMemoryAddress,
  625. &AddressSpace,
  626. &PhysicalAddress)) {
  627. pVideoDebugPrint((1, "This device isn't the VGA.\n"));
  628. return;
  629. }
  630. size = 0x00100000 - 1; // 1 MEG
  631. //
  632. // We pass an address of 1, so Memory Management will round it down to 0.
  633. // if we passed in 0, memory management would think the argument was
  634. // not present.
  635. //
  636. baseAddress = (PVOID) 0x00000001;
  637. // N.B. We expect that process creation has reserved the first 16 MB
  638. // for us already. If not, then this won't work worth a darn
  639. ntStatus = ZwAllocateVirtualMemory( NtCurrentProcess(),
  640. &baseAddress,
  641. 0L,
  642. &size,
  643. MEM_COMMIT,
  644. PAGE_EXECUTE_READWRITE );
  645. if (!NT_SUCCESS(ntStatus)) {
  646. pVideoDebugPrint ((1, "VIDEOPRT: Int10: Failed to allocate 1MEG of memory for the VDM\n"));
  647. return;
  648. }
  649. //
  650. // Map in the physical memory into the caller's address space so that
  651. // any memory references from the BIOS will work properly.
  652. //
  653. virtualAddress = (PVOID) FdoExtension->VdmPhysicalVideoMemoryAddress.LowPart;
  654. length = FdoExtension->VdmPhysicalVideoMemoryLength;
  655. ntStatus = ZwFreeVirtualMemory(NtCurrentProcess(),
  656. &virtualAddress,
  657. &length,
  658. MEM_RELEASE);
  659. if (!NT_SUCCESS(ntStatus)) {
  660. pVideoDebugPrint ((1, "VIDEOPRT: Int10: Failed to free memory space for video memory to be mapped\n"));
  661. return;
  662. }
  663. virtualAddress = (PVOID) FdoExtension->VdmPhysicalVideoMemoryAddress.LowPart;
  664. length = FdoExtension->VdmPhysicalVideoMemoryLength;
  665. ntStatus = pVideoPortMapUserPhysicalMem(FdoExtension,
  666. NtCurrentProcess(),
  667. FdoExtension->VdmPhysicalVideoMemoryAddress,
  668. &length,
  669. &inIoSpace,
  670. &virtualAddress);
  671. if (!NT_SUCCESS(ntStatus)) {
  672. pVideoDebugPrint ((1, "VIDEOPRT: Int10: Failed to Map video memory in address space\n"));
  673. return;
  674. }
  675. //
  676. // Initialize the default bios block which will be used if we can NOT
  677. // find any valid bios block.
  678. //
  679. RomBlock.Address = ROM_BIOS_START;
  680. RomBlock.Size = 0x40000;
  681. BiosBlock = &RomBlock;
  682. Index = 1;
  683. RtlInitUnicodeString(
  684. &SectionName,
  685. L"\\Device\\PhysicalMemory"
  686. );
  687. InitializeObjectAttributes(
  688. &ObjectAttributes,
  689. &SectionName,
  690. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  691. (HANDLE) NULL,
  692. (PSECURITY_DESCRIPTOR) NULL
  693. );
  694. ntStatus = ZwOpenSection(
  695. &SectionHandle,
  696. SECTION_ALL_ACCESS,
  697. &ObjectAttributes
  698. );
  699. if (!NT_SUCCESS(ntStatus)) {
  700. return;
  701. }
  702. //
  703. // Initialize the first unused memory with "int cd" so we will catch
  704. // a bios that starts executing from this region by hooking up our
  705. // own int cd code.
  706. //
  707. memset(0, 0xCD, 0xa0000);
  708. //
  709. // Copy the first page of physical memory into the CSR's address space
  710. //
  711. BaseAddress = 0;
  712. destination = 0;
  713. ViewSize = 0x1000;
  714. ViewBase.LowPart = 0;
  715. ViewBase.HighPart = 0;
  716. ntStatus =ZwMapViewOfSection(
  717. SectionHandle,
  718. NtCurrentProcess(),
  719. &BaseAddress,
  720. 0,
  721. ViewSize,
  722. &ViewBase,
  723. &ViewSize,
  724. ViewUnmap,
  725. 0,
  726. PAGE_READWRITE
  727. );
  728. if (!NT_SUCCESS(ntStatus)) {
  729. ZwClose(SectionHandle);
  730. return;
  731. }
  732. #pragma prefast(suppress:11, "We ARE using a NULL pointer here (PREfast bug 531472)")
  733. RtlMoveMemory(
  734. destination,
  735. BaseAddress,
  736. ViewSize
  737. );
  738. //
  739. // Copy the info from 0x700 to 0x717 into the registry.
  740. // These correspond to the 6 font pointers needed for
  741. // vdm support.
  742. //
  743. // Note: Will not return if registry calls fail. This
  744. // function needs to continue; it would be bad if we
  745. // could not perform an int 0x10.
  746. //
  747. RtlInitUnicodeString(
  748. &WorkString,
  749. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Wow"
  750. );
  751. InitializeObjectAttributes(
  752. &ObjectAttributes,
  753. &WorkString,
  754. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  755. (HANDLE)NULL,
  756. NULL
  757. );
  758. ntStatus = ZwOpenKey(
  759. &RegistryHandle,
  760. KEY_ALL_ACCESS,
  761. &ObjectAttributes
  762. );
  763. if (NT_SUCCESS(ntStatus)) {
  764. RtlInitUnicodeString(
  765. &WorkString,
  766. L"RomFontPointers"
  767. );
  768. destination = (PVOID) 0x700;
  769. ntStatus = ZwSetValueKey(
  770. RegistryHandle,
  771. &WorkString,
  772. 0,
  773. REG_BINARY,
  774. destination,
  775. 24
  776. );
  777. //
  778. // We won't return here if this fails. The function should
  779. // continue in order to enable int 0x10 support.
  780. //
  781. ZwClose(RegistryHandle);
  782. }
  783. ntStatus = ZwUnmapViewOfSection(
  784. NtCurrentProcess(),
  785. BaseAddress
  786. );
  787. if (!NT_SUCCESS(ntStatus)) {
  788. ZwClose(SectionHandle);
  789. return;
  790. }
  791. //
  792. // Hook error handler to int 0
  793. //
  794. IntVectorAddress = (ULONG *) (INT00_VECTOR_ADDRESS);
  795. #pragma prefast(suppress:11, "We ARE using a NULL pointer here (PREfast bug 531472)")
  796. if(*IntVectorAddress >= 0xF0000000) {
  797. //
  798. // Only replace the int0 handler if it is pointing to F000 segment
  799. // where system bios lives
  800. //
  801. RtlMoveMemory((PVOID)((ERROR_HANDLER_SEGMENT << 4) | ERROR_HANDLER_OFFSET),
  802. ErrorHandler,
  803. sizeof(ErrorHandler)
  804. );
  805. #pragma prefast(suppress:11, "We ARE using a NULL pointer here (PREfast bug 531472)")
  806. *IntVectorAddress =
  807. (ERROR_HANDLER_SEGMENT << 16) | ERROR_HANDLER_OFFSET;
  808. }
  809. //
  810. // Hook error handler to int cd
  811. //
  812. IntVectorAddress = (ULONG *) (INTCD_VECTOR_ADDRESS);
  813. if(*IntVectorAddress == 0) {
  814. RtlMoveMemory((PVOID)((ERROR_HANDLER_SEGMENT << 4) | ERROR_HANDLER_OFFSET),
  815. ErrorHandler,
  816. sizeof(ErrorHandler)
  817. );
  818. *IntVectorAddress =
  819. (ERROR_HANDLER_SEGMENT << 16) | ERROR_HANDLER_OFFSET;
  820. }
  821. {
  822. USHORT seg, offset;
  823. offset = *(USHORT *)(INT1A_VECTOR_ADDRESS);
  824. seg = *(USHORT *)(INT1A_VECTOR_ADDRESS + 2);
  825. Int1ACodeAddress = (seg << 4) + offset;
  826. Int1AIsValid = FALSE;
  827. }
  828. //
  829. // Copy the exteneded Bios region into the CSR's address space
  830. //
  831. ExtendedBiosLocationInfo = (PVOID) EXTENDED_BIOS_INFO_LOCATION;
  832. ExtendedBiosAddress = *ExtendedBiosLocationInfo++;
  833. ExtendedBiosSize = *ExtendedBiosLocationInfo;
  834. //
  835. // Round to page boundary
  836. //
  837. ExtendedBiosSize += (ExtendedBiosAddress & (PAGE_SIZE - 1));
  838. ExtendedBiosAddress &= ~(PAGE_SIZE - 1);
  839. if (ExtendedBiosSize) {
  840. BaseAddress = 0;
  841. destination = (PVOID) ExtendedBiosAddress;
  842. ViewSize = ExtendedBiosSize;
  843. ViewBase.LowPart = ExtendedBiosAddress;
  844. ViewBase.HighPart = 0;
  845. ntStatus = ZwMapViewOfSection(SectionHandle,
  846. NtCurrentProcess(),
  847. &BaseAddress,
  848. 0,
  849. ViewSize,
  850. &ViewBase,
  851. &ViewSize,
  852. ViewUnmap,
  853. 0,
  854. PAGE_READWRITE);
  855. if (!NT_SUCCESS(ntStatus)) {
  856. ZwClose(SectionHandle);
  857. return;
  858. }
  859. RtlMoveMemory(destination, BaseAddress, ViewSize);
  860. ntStatus = ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
  861. if (!NT_SUCCESS(ntStatus)) {
  862. ZwClose(SectionHandle);
  863. return;
  864. }
  865. if(Int1ACodeAddress >= ExtendedBiosAddress &&
  866. Int1ACodeAddress < ExtendedBiosAddress + ExtendedBiosSize) {
  867. Int1AIsValid = TRUE;
  868. }
  869. }
  870. //
  871. // Copy the e000:0000 segment of physical memory into the CSR's address space
  872. // This is because some bios code can live in the e000:0000 segment.
  873. //
  874. // We are doing a copy instead of mapping the physical e000:0000 segment
  875. // because we don't know how the real e000:0000 segment will be used in
  876. // all machines.
  877. //
  878. // See bugbug comment in \nt\base\hals\x86new\x86bios.c. we are adding
  879. // this to be consisten with that code. JeffHa added that code.
  880. //
  881. // Should we just copy the whole 640K?
  882. //
  883. BaseAddress = 0;
  884. destination = (PVOID) 0xe0000;
  885. ViewSize = 0x10000;
  886. ViewBase.LowPart = 0xe0000;
  887. ViewBase.HighPart = 0;
  888. ntStatus =ZwMapViewOfSection(
  889. SectionHandle,
  890. NtCurrentProcess(),
  891. &BaseAddress,
  892. 0,
  893. ViewSize,
  894. &ViewBase,
  895. &ViewSize,
  896. ViewUnmap,
  897. 0,
  898. PAGE_READWRITE
  899. );
  900. if (!NT_SUCCESS(ntStatus)) {
  901. ZwClose(SectionHandle);
  902. return;
  903. }
  904. RtlMoveMemory(
  905. destination,
  906. BaseAddress,
  907. ViewSize
  908. );
  909. ntStatus = ZwUnmapViewOfSection(
  910. NtCurrentProcess(),
  911. BaseAddress
  912. );
  913. if (!NT_SUCCESS(ntStatus)) {
  914. ZwClose(SectionHandle);
  915. return;
  916. }
  917. if(Int1ACodeAddress >= (ULONG)destination &&
  918. Int1ACodeAddress < (ULONG)destination + ViewSize) {
  919. Int1AIsValid = TRUE;
  920. }
  921. //
  922. // Set up and open KeyPath
  923. //
  924. RtlInitUnicodeString(
  925. &WorkString,
  926. L"\\Registry\\Machine\\Hardware\\Description\\System"
  927. );
  928. InitializeObjectAttributes(
  929. &ObjectAttributes,
  930. &WorkString,
  931. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  932. (HANDLE)NULL,
  933. NULL
  934. );
  935. ntStatus = ZwOpenKey(
  936. &RegistryHandle,
  937. KEY_READ,
  938. &ObjectAttributes
  939. );
  940. if (!NT_SUCCESS(ntStatus)) {
  941. ZwClose(SectionHandle);
  942. return;
  943. }
  944. //
  945. // Allocate space for the data
  946. //
  947. KeyValueBuffer = ExAllocatePoolWithTag(
  948. PagedPool,
  949. KEY_VALUE_BUFFER_SIZE,
  950. VP_TAG
  951. );
  952. if (KeyValueBuffer == NULL) {
  953. ZwClose(SectionHandle);
  954. ZwClose(RegistryHandle);
  955. return;
  956. }
  957. //
  958. // Get the data for the rom information
  959. //
  960. RtlInitUnicodeString(
  961. &WorkString,
  962. L"Configuration Data"
  963. );
  964. ntStatus = ZwQueryValueKey(
  965. RegistryHandle,
  966. &WorkString,
  967. KeyValueFullInformation,
  968. KeyValueBuffer,
  969. KEY_VALUE_BUFFER_SIZE,
  970. &ResultLength
  971. );
  972. if (!NT_SUCCESS(ntStatus)) {
  973. ZwClose(SectionHandle);
  974. ZwClose(RegistryHandle);
  975. ExFreePool(KeyValueBuffer);
  976. return;
  977. }
  978. ResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)
  979. ((PUCHAR) KeyValueBuffer + KeyValueBuffer->DataOffset);
  980. if ((KeyValueBuffer->DataLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) &&
  981. (ResourceDescriptor->PartialResourceList.Count >= 2) ) {
  982. PartialResourceDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)
  983. ((PUCHAR)ResourceDescriptor +
  984. sizeof(CM_FULL_RESOURCE_DESCRIPTOR) +
  985. ResourceDescriptor->PartialResourceList.PartialDescriptors[0]
  986. .u.DeviceSpecificData.DataSize);
  987. if (KeyValueBuffer->DataLength >= ((PUCHAR)PartialResourceDescriptor -
  988. (PUCHAR)ResourceDescriptor + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
  989. + sizeof(CM_ROM_BLOCK))) {
  990. BiosBlock = (PCM_ROM_BLOCK)((PUCHAR)PartialResourceDescriptor +
  991. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
  992. Index = PartialResourceDescriptor->u.DeviceSpecificData.DataSize /
  993. sizeof(CM_ROM_BLOCK);
  994. }
  995. }
  996. //
  997. // First check if there is any Extended BIOS Data area. If yes, we need
  998. // to map in the physical memory and copy the content to our virtual addr.
  999. //
  1000. LastMappedAddress = 0;
  1001. while (Index && BiosBlock->Address < ROM_BIOS_START) {
  1002. EBiosInitialized = TRUE;
  1003. destination = (PVOID)(BiosBlock->Address & ~(PAGE_SIZE - 1));
  1004. BaseAddress = (PVOID)0;
  1005. EndingAddress = (BiosBlock->Address + BiosBlock->Size + PAGE_SIZE - 1) &
  1006. ~(PAGE_SIZE - 1);
  1007. ViewSize = EndingAddress - (ULONG)destination;
  1008. if ((ULONG)destination < LastMappedAddress) {
  1009. if (ViewSize > (LastMappedAddress - (ULONG)destination)) {
  1010. ViewSize = ViewSize - (LastMappedAddress - (ULONG)destination);
  1011. destination = (PVOID)LastMappedAddress;
  1012. } else {
  1013. ViewSize = 0;
  1014. }
  1015. }
  1016. if (ViewSize > 0) {
  1017. ViewBase.LowPart = (ULONG)destination;
  1018. ViewBase.HighPart = 0;
  1019. ntStatus =ZwMapViewOfSection(
  1020. SectionHandle,
  1021. NtCurrentProcess(),
  1022. &BaseAddress,
  1023. 0,
  1024. ViewSize,
  1025. &ViewBase,
  1026. &ViewSize,
  1027. ViewUnmap,
  1028. MEM_DOS_LIM,
  1029. PAGE_READWRITE
  1030. );
  1031. if (NT_SUCCESS(ntStatus)) {
  1032. ViewSize = EndingAddress - (ULONG)destination; // only copy what we need
  1033. LastMappedAddress = (ULONG)destination + ViewSize;
  1034. RtlMoveMemory(destination, BaseAddress, ViewSize);
  1035. ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
  1036. if(Int1ACodeAddress >= (ULONG)destination &&
  1037. Int1ACodeAddress < (ULONG)destination + ViewSize) {
  1038. Int1AIsValid = TRUE;
  1039. }
  1040. }
  1041. }
  1042. BiosBlock++;
  1043. Index--;
  1044. }
  1045. //
  1046. // NOTE - The code should be removed after product 1.
  1047. // Due to some problem in VDM initialization, if we pass EBIOS data
  1048. // area information thru ROM block list, vdm init will fail and our
  1049. // subsequential int10 mode set will fail. This prevents new ntdetect
  1050. // from working with beta versions of NT. To solve this problem, the
  1051. // EBIOS information is passed to VDM with fonts information thru DOS
  1052. // loaded area.
  1053. //
  1054. // We've shipped two products (about to be 3) and this works fine,
  1055. // don't mess with it.
  1056. //
  1057. if (EBiosInitialized == FALSE &&
  1058. EBiosInformation->EBiosAddress != 0 &&
  1059. EBiosInformation->EBiosAddress <= VIDEO_BUFFER_START &&
  1060. EBiosInformation->EBiosSize != 0 &&
  1061. (EBiosInformation->EBiosSize & 0x3ff) == 0 &&
  1062. EBiosInformation->EBiosSize < 0x40000) {
  1063. EndingAddress = EBiosInformation->EBiosAddress +
  1064. EBiosInformation->EBiosSize;
  1065. if (EndingAddress <= VIDEO_BUFFER_START &&
  1066. (EndingAddress & 0x3FF) == 0) {
  1067. destination = (PVOID)(EBiosInformation->EBiosAddress & ~(PAGE_SIZE - 1));
  1068. BaseAddress = (PVOID)0;
  1069. EndingAddress = (EndingAddress + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
  1070. ViewSize = EndingAddress - (ULONG)destination;
  1071. ViewBase.LowPart = (ULONG)destination;
  1072. ViewBase.HighPart = 0;
  1073. ntStatus =ZwMapViewOfSection(
  1074. SectionHandle,
  1075. NtCurrentProcess(),
  1076. &BaseAddress,
  1077. 0,
  1078. ViewSize,
  1079. &ViewBase,
  1080. &ViewSize,
  1081. ViewUnmap,
  1082. MEM_DOS_LIM,
  1083. PAGE_READWRITE
  1084. );
  1085. if (NT_SUCCESS(ntStatus)) {
  1086. ViewSize = EndingAddress - (ULONG)destination; // only copy what we need
  1087. RtlMoveMemory(destination, BaseAddress, ViewSize);
  1088. ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
  1089. if(Int1ACodeAddress >= (ULONG)destination &&
  1090. Int1ACodeAddress < (ULONG)destination + ViewSize) {
  1091. Int1AIsValid = TRUE;
  1092. }
  1093. }
  1094. }
  1095. }
  1096. //
  1097. // N.B. Rom blocks begin on 2K (not necessarily page) boundaries
  1098. // They end on 512 byte boundaries. This means that we have
  1099. // to keep track of the last page mapped, and round the next
  1100. // Rom block up to the next page boundary if necessary.
  1101. //
  1102. LastMappedAddress = ROM_BIOS_START;
  1103. while (Index) {
  1104. if ((Index > 1) &&
  1105. ((BiosBlock->Address + BiosBlock->Size) == BiosBlock[1].Address)) {
  1106. //
  1107. // Coalesce adjacent blocks
  1108. //
  1109. BiosBlock[1].Address = BiosBlock[0].Address;
  1110. BiosBlock[1].Size += BiosBlock[0].Size;
  1111. Index--;
  1112. BiosBlock++;
  1113. continue;
  1114. }
  1115. BaseAddress = (PVOID)(BiosBlock->Address & ~(PAGE_SIZE - 1));
  1116. EndingAddress = (BiosBlock->Address + BiosBlock->Size + PAGE_SIZE - 1) &
  1117. ~(PAGE_SIZE - 1);
  1118. ViewSize = EndingAddress - (ULONG)BaseAddress;
  1119. if ((ULONG)BaseAddress < LastMappedAddress) {
  1120. if (ViewSize > (LastMappedAddress - (ULONG)BaseAddress)) {
  1121. ViewSize = ViewSize - (LastMappedAddress - (ULONG)BaseAddress);
  1122. BaseAddress = (PVOID)LastMappedAddress;
  1123. } else {
  1124. ViewSize = 0;
  1125. }
  1126. }
  1127. ViewBase.LowPart = (ULONG)BaseAddress;
  1128. if (ViewSize > 0) {
  1129. //
  1130. // Move FF to the non-ROM area to make it like nonexisting memory
  1131. //
  1132. #if 0
  1133. if ((ULONG)BaseAddress - LastMappedAddress > 0) {
  1134. RtlFillMemory((PVOID)LastMappedAddress,
  1135. (ULONG)BaseAddress - LastMappedAddress,
  1136. 0xFF
  1137. );
  1138. }
  1139. #endif
  1140. //
  1141. // First unmap the reserved memory. This must be done here to prevent
  1142. // the virtual memory in question from being consumed by some other
  1143. // alloc vm call.
  1144. //
  1145. ntStatus = ZwFreeVirtualMemory(
  1146. NtCurrentProcess(),
  1147. &BaseAddress,
  1148. &ViewSize,
  1149. MEM_RELEASE
  1150. );
  1151. // N.B. This should probably take into account the fact that there are
  1152. // a handfull of error conditions that are ok. (such as no memory to
  1153. // release.)
  1154. if (!NT_SUCCESS(ntStatus)) {
  1155. ZwClose(SectionHandle);
  1156. ZwClose(RegistryHandle);
  1157. ExFreePool(KeyValueBuffer);
  1158. return;
  1159. }
  1160. ntStatus = ZwMapViewOfSection(
  1161. SectionHandle,
  1162. NtCurrentProcess(),
  1163. &BaseAddress,
  1164. 0,
  1165. ViewSize,
  1166. &ViewBase,
  1167. &ViewSize,
  1168. ViewUnmap,
  1169. MEM_DOS_LIM,
  1170. PAGE_EXECUTE_READWRITE
  1171. );
  1172. if (!NT_SUCCESS(ntStatus)) {
  1173. break;
  1174. }
  1175. if(Int1ACodeAddress >= (ULONG)ViewBase.LowPart &&
  1176. Int1ACodeAddress < (ULONG)ViewBase.LowPart + ViewSize) {
  1177. Int1AIsValid = TRUE;
  1178. }
  1179. LastMappedAddress = (ULONG)BaseAddress + ViewSize;
  1180. }
  1181. Index--;
  1182. BiosBlock++;
  1183. }
  1184. //
  1185. // If some one hooked int1a but didn't report the hooked code as
  1186. // extended bios, we have to set int1a vector to its original value.
  1187. // We've seen many instance of this problem in RIS setup.
  1188. //
  1189. if(!Int1AIsValid) {
  1190. IntVectorAddress = (ULONG *) INT1A_VECTOR_ADDRESS;
  1191. *IntVectorAddress = 0xF000FE6E;
  1192. }
  1193. #if 0
  1194. if (LastMappedAddress < ONE_MEG) {
  1195. RtlFillMemory((PVOID)LastMappedAddress,
  1196. (ULONG)ONE_MEG - LastMappedAddress,
  1197. 0xFF
  1198. );
  1199. }
  1200. #endif
  1201. //#if DBG
  1202. // BaseAddress = 0;
  1203. // RegionSize = 0x1000;
  1204. // ZwProtectVirtualMemory ( NtCurrentProcess(),
  1205. // &BaseAddress,
  1206. // &RegionSize,
  1207. // PAGE_NOACCESS,
  1208. // &OldProtect
  1209. // );
  1210. //#endif
  1211. //
  1212. // Free up the handles
  1213. //
  1214. ZwClose(SectionHandle);
  1215. ZwClose(RegistryHandle);
  1216. ExFreePool(KeyValueBuffer);
  1217. KeAttachProcess(PEProcessToPKProcess(CsrProcess));
  1218. // Crc324 - Calculate the Crc32 value of a string in 4 bit nibbles.
  1219. //
  1220. // dwCrc - initial value of CRC
  1221. // cbBuffer - count in bytes of length of buffer
  1222. // pbBuffer - pointer to buffer to checksum
  1223. //
  1224. // returns: value of crc32
  1225. //
  1226. // this table is derived from the 256 element CRCTable in
  1227. // \\orville\razzle\src\net\svcdlls\ntlmssp\client\crc32.c
  1228. // This table contains every 16th element since we do 4 bits
  1229. // at a time, not 8
  1230. //
  1231. {
  1232. ULONG CRCTable4[16] = {
  1233. 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
  1234. 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
  1235. 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
  1236. 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c,
  1237. };
  1238. UCHAR byte;
  1239. UCHAR index;
  1240. ULONG cBuffer = 0x1000;
  1241. PUCHAR pBuffer = (PUCHAR) 0x000C0000;
  1242. while (cBuffer-- != 0)
  1243. {
  1244. byte = *pBuffer++;
  1245. index = (byte ^ (UCHAR)(dwCrc) ) & 0xf;
  1246. dwCrc = (dwCrc >> 4) ^ CRCTable4[index];
  1247. byte = byte >> 4;
  1248. index = (byte ^ (UCHAR)(dwCrc) ) & 0xf;
  1249. dwCrc = (dwCrc >> 4) ^ CRCTable4[index];
  1250. }
  1251. dwCrc ^= 0xFFFFFFFF;
  1252. }
  1253. KeDetachProcess();
  1254. //
  1255. // Write the Crc value into the registry.
  1256. //
  1257. VideoPortSetRegistryParameters(FdoExtension->HwDeviceExtension,
  1258. L"HardwareInformation.Crc32",
  1259. &dwCrc,
  1260. sizeof(ULONG));
  1261. //
  1262. // Everything worked !
  1263. //
  1264. ServerBiosAddressSpaceInitialized = 1;
  1265. return;
  1266. }
  1267. NTSTATUS
  1268. pVideoPortRegisterVDM(
  1269. IN PFDO_EXTENSION FdoExtension,
  1270. IN PVIDEO_VDM VdmInfo,
  1271. IN ULONG VdmInfoSize,
  1272. OUT PVIDEO_REGISTER_VDM RegisterVdm,
  1273. IN ULONG RegisterVdmSize,
  1274. OUT PULONG_PTR OutputSize
  1275. )
  1276. /*++
  1277. Routine Description:
  1278. This routine is used to register a VDM when it is started up.
  1279. What this routine does is map the VIDEO BIOS into the VDM address space
  1280. so that DOS apps can use it directly. Since the BIOS is READ_ONLY, we
  1281. have no problem in mapping it as many times as we want.
  1282. It returns the size of the save state buffer that must be allocated by
  1283. the caller.
  1284. Arguments:
  1285. DeviceExtension - Pointer to the port driver's device extension.
  1286. VdmInfo - Pointer to the VDM information necessary to perform the
  1287. operation.
  1288. VdmInfoSize - Length of the information buffer.
  1289. RegisterVdm - Pointer to the output buffer into which the save state
  1290. size is stored.
  1291. RegisterVdmSize - Length of the passed in output buffer.
  1292. OutputSize - Pointer to the size of the data stored in the output buffer.
  1293. Can also be the minimum required size of the output buffer is the
  1294. passed in buffer was too small.
  1295. Return Value:
  1296. STATUS_SUCCESS if the call completed successfully.
  1297. --*/
  1298. {
  1299. //
  1300. // Must make sure the caller is a trusted subsystem with the
  1301. // appropriate privilege level before executing this call.
  1302. // If the calls returns FALSE we must return an error code.
  1303. //
  1304. if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(
  1305. SE_TCB_PRIVILEGE),
  1306. FdoExtension->CurrentIrpRequestorMode)) {
  1307. return STATUS_PRIVILEGE_NOT_HELD;
  1308. }
  1309. //
  1310. // Check the size of the output buffer.
  1311. //
  1312. if (RegisterVdmSize < sizeof(VIDEO_REGISTER_VDM)) {
  1313. return STATUS_INSUFFICIENT_RESOURCES;
  1314. }
  1315. //
  1316. // Return the size required for the save/restore state call.
  1317. //
  1318. *OutputSize = sizeof(VIDEO_REGISTER_VDM);
  1319. RegisterVdm->MinimumStateSize = FdoExtension->HardwareStateSize;
  1320. return STATUS_SUCCESS;
  1321. } // end pVideoPortRegisterVDM()
  1322. NTSTATUS
  1323. pVideoPortSetIOPM(
  1324. IN ULONG NumAccessRanges,
  1325. IN PVIDEO_ACCESS_RANGE AccessRange,
  1326. IN BOOLEAN Enable,
  1327. IN ULONG IOPMNumber
  1328. )
  1329. /*++
  1330. Routine Description:
  1331. This routine is used to change the IOPM. It modifies the IOPM based on
  1332. the valid IO ports for the particular device.
  1333. It retrieves the video IOPM mask, changes the access to the I/O ports of
  1334. the specified device and stores the updated mask.
  1335. -- This call can only be performed if the requesting process has the
  1336. appropriate privileges, as determined by the security subsystem. --
  1337. Arguments:
  1338. NumAccessRanges - Number of entries in the array of access ranges.
  1339. AccessRange - Pointer to the array of access ranges.
  1340. Enable - Determine if the port listed must be enabled or disabled in the
  1341. mask.
  1342. IOPMNumber - Number of the mask being manipulated.
  1343. Return Value:
  1344. STATUS_SUCCESS if the call completed successfully.
  1345. The status from the VideoPortQueryIOPM call if it failed.
  1346. ...
  1347. The return value is also stored in the StatusBlock.
  1348. --*/
  1349. {
  1350. NTSTATUS ntStatus;
  1351. PKIO_ACCESS_MAP accessMap;
  1352. ULONG port;
  1353. ULONG entries;
  1354. //
  1355. // Retrieve the existing permission mask. If this fails, return
  1356. // immediately.
  1357. //
  1358. if ((accessMap = (PKIO_ACCESS_MAP)ExAllocatePoolWithTag(NonPagedPool,
  1359. IOPM_SIZE,
  1360. VP_TAG)) == NULL) {
  1361. return STATUS_INSUFFICIENT_RESOURCES;
  1362. }
  1363. //
  1364. // Get the kernel map copied into our buffer.
  1365. //
  1366. if (!Ke386QueryIoAccessMap(IOPMNumber,
  1367. accessMap)) {
  1368. //
  1369. // An error occured while *accessing* the map in the
  1370. // kernel. Return an error and exit normally.
  1371. //
  1372. ExFreePool(accessMap);
  1373. return STATUS_IO_PRIVILEGE_FAILED;
  1374. }
  1375. //
  1376. // Give the calling process access to all the IO ports enabled by the
  1377. // miniport driver in the access range.
  1378. //
  1379. for (entries = 0; entries < NumAccessRanges; entries++) {
  1380. for (port = AccessRange[entries].RangeStart.LowPart;
  1381. (AccessRange[entries].RangeInIoSpace) &&
  1382. (port < AccessRange[entries].RangeStart.LowPart +
  1383. AccessRange[entries].RangeLength);
  1384. port++) {
  1385. //
  1386. // Change the port access in the mask:
  1387. // Shift the port address by three to get the index in bytes into
  1388. // the mask. Then take the bottom three bits of the port address
  1389. // and shift 0x01 by that amount to get the right bit in that
  1390. // byte. the bit values are:
  1391. // 0 - access to the port
  1392. // 1 - no access to the port
  1393. //
  1394. if (Enable && AccessRange[entries].RangeVisible) {
  1395. //
  1396. // To give access to a port, NAND 1 with the original port.
  1397. // ex: 11111111 ~& 00001000 = 11110111
  1398. // which gives you access to the port who's bit was 1.
  1399. // If the port we are enabling is in the current IOPM mask,
  1400. // return an error instead.
  1401. //
  1402. (*accessMap)[port >> 3] &= ~(0x01 << (port & 0x07));
  1403. } else { // disable mask
  1404. //
  1405. // To remove access to a port, OR 1 with the original port.
  1406. // ex: 11110100 | 00001000 = 11111100
  1407. // which removes access to the port who's bit was 1.
  1408. // If the port we are disabling is not in the current IOPM mask,
  1409. // return an error instead.
  1410. //
  1411. (*accessMap)[port >> 3] |= (0x01 << (port &0x07));
  1412. } // if (Enable) ... else
  1413. } // for (port == ...
  1414. } // for (entries = 0; ...
  1415. //
  1416. // If the mask was updated properly, with no errors, set the new mask.
  1417. // Otherwise, leave the existing one.
  1418. //
  1419. if (Ke386SetIoAccessMap(IOPMNumber,
  1420. accessMap)) {
  1421. //
  1422. // If the map was created correctly, associate the map to the
  1423. // requesting process. We only need to do this once when the
  1424. // IOPM is first assigned. But we don't know when the first time
  1425. // is.
  1426. //
  1427. if (Ke386IoSetAccessProcess(PEProcessToPKProcess(PsGetCurrentProcess()),
  1428. IOPMNumber)) {
  1429. ntStatus = STATUS_SUCCESS;
  1430. } else {
  1431. //
  1432. // An error occured while *assigning* the map to
  1433. // the process. Return an error and exit normally.
  1434. //
  1435. ntStatus = STATUS_IO_PRIVILEGE_FAILED;
  1436. }
  1437. } else {
  1438. //
  1439. // An error occured while *creating* the map in the
  1440. // kernel. Return an error and exit normally.
  1441. //
  1442. ntStatus = STATUS_IO_PRIVILEGE_FAILED;
  1443. } // if (Ke386Set ...) ... else
  1444. //
  1445. // Free the memory allocated for the map by the VideoPortQueryIOPM call
  1446. // since the mask has been copied in the kernel TSS.
  1447. //
  1448. ExFreePool(accessMap);
  1449. return ntStatus;
  1450. } // end pVideoPortSetIOPM();
  1451. VP_STATUS
  1452. VideoPortSetTrappedEmulatorPorts(
  1453. PVOID HwDeviceExtension,
  1454. ULONG NumAccessRanges,
  1455. PVIDEO_ACCESS_RANGE AccessRange
  1456. )
  1457. /*++
  1458. VideoPortSetTrappedEmulatorPorts (x86 machines only) allows a miniport
  1459. driver to dynamically change the list of I/O ports that are trapped when
  1460. a VDM is running in full-screen mode. The default set of ports being
  1461. trapped by the miniport driver is defined to be all ports in the
  1462. EMULATOR_ACCESS_ENTRY structure of the miniport driver.
  1463. I/O ports not listed in the EMULATOR_ACCESS_ENTRY structure are
  1464. unavailable to the MS-DOS application. Accessing those ports causes a
  1465. trap to occur in the system, and the I/O operation to be reflected to a
  1466. user-mode virtual device driver.
  1467. The ports listed in the specified VIDEO_ACCESS_RANGE structure will be
  1468. enabled in the I/O Permission Mask (IOPM) associated with the MS-DOS
  1469. application. This will enable the MS-DOS application to access those I/O
  1470. ports directly, without having the IO instruction trap and be passed down
  1471. to the miniport trap handling functions (for example EmulatorAccessEntry
  1472. functions) for validation. However, the subset of critical IO ports must
  1473. always remain trapped for robustness.
  1474. All MS-DOS applications use the same IOPM, and therefore the same set of
  1475. enabled/disabled I/O ports. Thus, on each switch of application, the
  1476. set of trapped I/O ports is reinitialized to be the default set of ports
  1477. (all ports in the EMULATOR_ACCESS_ENTRY structure).
  1478. Arguments:
  1479. HwDeviceExtension - Points to the miniport driver's device extension.
  1480. NumAccessRanges - Specifies the number of entries in the VIDEO_ACCESS_RANGE
  1481. structure specified in AccessRange.
  1482. AccessRange - Points to an array of access ranges (VIDEO_ACCESS_RANGE)
  1483. defining the ports that can be untrapped and accessed directly by
  1484. the MS-DOS application.
  1485. Return Value:
  1486. This function returns the final status of the operation.
  1487. Environment:
  1488. This routine cannot be called from a miniport routine synchronized with
  1489. VideoPortSynchronizeRoutine or from an ISR.
  1490. --*/
  1491. {
  1492. if (NT_SUCCESS(pVideoPortSetIOPM(NumAccessRanges,
  1493. AccessRange,
  1494. TRUE,
  1495. 1))) {
  1496. return NO_ERROR;
  1497. } else {
  1498. return ERROR_INVALID_PARAMETER;
  1499. }
  1500. } // end VideoPortSetTrappedEmulatorPorts()
  1501. NTSTATUS
  1502. pVideoPortGetVDMBiosData(
  1503. PFDO_EXTENSION FdoExtension,
  1504. PCHAR Buffer,
  1505. ULONG Length
  1506. )
  1507. {
  1508. NTSTATUS NtStatus = STATUS_SUCCESS;
  1509. BOOLEAN bAttachProcess = FALSE;
  1510. PCHAR Memory;
  1511. ULONG i;
  1512. UCHAR uchar;
  1513. if(!CsrProcess) return STATUS_INVALID_PARAMETER;
  1514. ObReferenceObject(FdoExtension->VdmProcess);
  1515. if (PsGetCurrentProcess() != FdoExtension->VdmProcess) {
  1516. bAttachProcess = TRUE;
  1517. KeAttachProcess(PEProcessToPKProcess(FdoExtension->VdmProcess));
  1518. }
  1519. //
  1520. // Copy over Length bytes from VDM's Bios data area
  1521. //
  1522. Memory = (PCHAR) 0x400;
  1523. try {
  1524. RtlCopyMemory(Buffer, Memory, Length);
  1525. } except (EXCEPTION_EXECUTE_HANDLER) {
  1526. NtStatus = GetExceptionCode();
  1527. }
  1528. if (bAttachProcess) {
  1529. KeDetachProcess();
  1530. }
  1531. ObDereferenceObject(FdoExtension->VdmProcess);
  1532. if (NtStatus != STATUS_SUCCESS)
  1533. return NtStatus;
  1534. if (PsGetCurrentProcess() != CsrProcess)
  1535. {
  1536. bAttachProcess = TRUE;
  1537. KeAttachProcess(PEProcessToPKProcess(CsrProcess));
  1538. }
  1539. //
  1540. // Replace the Bios data area in CSRSS with that from VDM. At the
  1541. // same time we save the original bios data in CSRSS. The
  1542. // subsequent int10 calls from the driver could get the status
  1543. // of the hardware in VDM environment.
  1544. //
  1545. // We'll improve this when we have a better approach
  1546. //
  1547. try {
  1548. for (i = 0; i < Length; i++) {
  1549. uchar = *Memory;
  1550. *Memory++ = Buffer[i];
  1551. Buffer[i] = uchar;
  1552. }
  1553. } except (EXCEPTION_EXECUTE_HANDLER) {
  1554. NtStatus = GetExceptionCode();
  1555. }
  1556. if (bAttachProcess) {
  1557. KeDetachProcess();
  1558. }
  1559. return NtStatus;
  1560. }
  1561. NTSTATUS
  1562. pVideoPortPutVDMBiosData(
  1563. PFDO_EXTENSION FdoExtension,
  1564. PCHAR Buffer,
  1565. ULONG Length
  1566. )
  1567. {
  1568. BOOLEAN bAttachProcess = FALSE;
  1569. NTSTATUS NtStatus = STATUS_SUCCESS;
  1570. PCHAR Memory;
  1571. if(!CsrProcess) return STATUS_INVALID_PARAMETER;
  1572. if (PsGetCurrentProcess() != CsrProcess) {
  1573. bAttachProcess = TRUE;
  1574. KeAttachProcess(PEProcessToPKProcess(CsrProcess));
  1575. }
  1576. //
  1577. // Copy over Length bytes from VDM's Bios data area
  1578. //
  1579. Memory = (PCHAR) 0x400;
  1580. try {
  1581. RtlCopyMemory(Memory, Buffer, Length);
  1582. } except (EXCEPTION_EXECUTE_HANDLER) {
  1583. NtStatus = GetExceptionCode();
  1584. }
  1585. if (bAttachProcess) {
  1586. KeDetachProcess();
  1587. }
  1588. return NtStatus;
  1589. }