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.

807 lines
18 KiB

  1. /*--
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. portamd64.c
  5. Abstract:
  6. This is the AMD64 specific part of the video port driver.
  7. Author:
  8. Andre Vachon (andreva) 10-Jan-1991
  9. Environment:
  10. kernel mode only
  11. --*/
  12. #include "videoprt.h"
  13. #include "emulate.h"
  14. #define LOW_MEM_SEGMET 0
  15. #define LOW_MEM_OFFSET 0
  16. #define SIZE_OF_VECTOR_TABLE 0x400
  17. #define SIZE_OF_BIOS_DATA_AREA 0x400
  18. VOID
  19. InitIoMemoryBase(
  20. VOID
  21. );
  22. extern XM_STATUS x86BiosExecuteInterrupt (
  23. IN UCHAR Number,
  24. IN OUT PXM86_CONTEXT Context,
  25. IN PVOID BiosIoSpace OPTIONAL,
  26. IN PVOID BiosIoMemory OPTIONAL
  27. );
  28. extern PVOID x86BiosTranslateAddress (
  29. IN USHORT Segment,
  30. IN USHORT Offset
  31. );
  32. BOOLEAN
  33. CallBiosEx (
  34. IN ULONG BiosCommand,
  35. IN OUT PULONG Eax,
  36. IN OUT PULONG Ebx,
  37. IN OUT PULONG Ecx,
  38. IN OUT PULONG Edx,
  39. IN OUT PULONG Esi,
  40. IN OUT PULONG Edi,
  41. IN OUT PULONG Ebp,
  42. IN OUT PUSHORT SegDs,
  43. IN OUT PUSHORT SegEs
  44. );
  45. VOID
  46. InitializeX86Int10CallEx(
  47. PUCHAR BiosTransferArea,
  48. ULONG BiosTransferLength
  49. );
  50. VOID
  51. InitializeX86Int10Call(
  52. PUCHAR BiosTransferArea,
  53. ULONG BiosTransferLength
  54. );
  55. #pragma alloc_text(PAGE,InitIoMemoryBase)
  56. #pragma alloc_text(PAGE,pVideoPortEnableVDM)
  57. #pragma alloc_text(PAGE,VideoPortInt10)
  58. #pragma alloc_text(PAGE,pVideoPortRegisterVDM)
  59. #pragma alloc_text(PAGE,pVideoPortSetIOPM)
  60. #pragma alloc_text(PAGE,VideoPortSetTrappedEmulatorPorts)
  61. #pragma alloc_text(PAGE,pVideoPortInitializeInt10)
  62. #pragma alloc_text(PAGE,CallBiosEx)
  63. #pragma alloc_text(PAGE,InitializeX86Int10Call)
  64. #pragma alloc_text(PAGE,VpInt10AllocateBuffer)
  65. #pragma alloc_text(PAGE,VpInt10FreeBuffer)
  66. #pragma alloc_text(PAGE,VpInt10ReadMemory)
  67. #pragma alloc_text(PAGE,VpInt10WriteMemory)
  68. #pragma alloc_text(PAGE,VpInt10CallBios)
  69. //
  70. // Initialize Default X86 bios spaces
  71. //
  72. PVOID IoControlBase = NULL;
  73. PVOID IoMemoryBase = NULL;
  74. //
  75. // Define global data.
  76. //
  77. ULONG X86BiosInitialized = FALSE;
  78. ULONG EnableInt10Calls = FALSE;
  79. VOID
  80. InitIoMemoryBase(
  81. VOID
  82. )
  83. /*++
  84. Routine Description:
  85. Arguements:
  86. Return Value:
  87. --*/
  88. {
  89. PHYSICAL_ADDRESS COMPATIBLE_PCI_PHYSICAL_BASE_ADDRESS = { 0x0};
  90. IoMemoryBase = (PUCHAR)MmMapIoSpace(COMPATIBLE_PCI_PHYSICAL_BASE_ADDRESS,
  91. 0x100000,
  92. (MEMORY_CACHING_TYPE)MmNonCached);
  93. ASSERT(IoMemoryBase);
  94. return;
  95. }
  96. NTSTATUS
  97. pVideoPortEnableVDM(
  98. IN PFDO_EXTENSION DeviceExtension,
  99. IN BOOLEAN Enable,
  100. IN PVIDEO_VDM VdmInfo,
  101. IN ULONG VdmInfoSize
  102. )
  103. /*++
  104. Routine Description:
  105. This routine allows the kernel video driver to unhook I/O ports or
  106. specific interrupts from the V86 fault handler. Operations on the
  107. specified ports will be forwarded back to the user-mode VDD once
  108. disconnection is completed.
  109. Arguments:
  110. DeviceExtension - Pointer to the port driver's device extension.
  111. Enable - Determines if the VDM should be enabled (TRUE) or disabled
  112. (FALSE).
  113. VdmInfo - Pointer to the VdmInfo passed by the caller.
  114. VdmInfoSize - Size of the VdmInfo struct passed by the caller.
  115. Return Value:
  116. STATUS_NOT_IMPLEMENTED
  117. --*/
  118. {
  119. return STATUS_NOT_IMPLEMENTED;
  120. }
  121. VP_STATUS
  122. VideoPortInt10(
  123. PVOID HwDeviceExtension,
  124. PVIDEO_X86_BIOS_ARGUMENTS BiosArguments
  125. )
  126. /*++
  127. Routine Description:
  128. This function allows a miniport driver to call the kernel to perform
  129. an int10 operation.
  130. This will execute natively the BIOS ROM code on the device.
  131. THIS FUNCTION IS FOR X86 ONLY.
  132. Arguments:
  133. HwDeviceExtension - Pointer to the miniport driver's device extension.
  134. BiosArguments - Pointer to a structure containing the value of the
  135. basic x86 registers that should be set before calling the BIOS routine.
  136. 0 should be used for unused registers.
  137. Return Value:
  138. ERROR_INVALID_PARAMETER
  139. --*/
  140. {
  141. BOOLEAN bStatus;
  142. PFDO_EXTENSION deviceExtension = GET_FDO_EXT(HwDeviceExtension);
  143. ULONG inIoSpace = 0;
  144. PVOID virtualAddress;
  145. ULONG length;
  146. CONTEXT context;
  147. //
  148. // Must make sure the caller is a trusted subsystem with the
  149. // appropriate address space set up.
  150. //
  151. if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_TCB_PRIVILEGE),
  152. deviceExtension->CurrentIrpRequestorMode)) {
  153. return ERROR_INVALID_PARAMETER;
  154. }
  155. //
  156. // Now call the HAL to actually perform the int 10 operation.
  157. //
  158. pVideoDebugPrint((3, "VIDEOPRT: Int10: edi %x esi %x eax %x ebx %x \n\t ecx %x edx %x ebp %x\n",
  159. BiosArguments->Edi,
  160. BiosArguments->Esi,
  161. BiosArguments->Eax,
  162. BiosArguments->Ebx,
  163. BiosArguments->Ecx,
  164. BiosArguments->Edx,
  165. BiosArguments->Ebp));
  166. //
  167. // Need to protect HalCallBios fro reentrance
  168. //
  169. KeWaitForSingleObject(&VpInt10Mutex,
  170. Executive,
  171. KernelMode,
  172. FALSE,
  173. (PTIME)NULL);
  174. bStatus = HalCallBios(0x10,
  175. &(BiosArguments->Eax),
  176. &(BiosArguments->Ebx),
  177. &(BiosArguments->Ecx),
  178. &(BiosArguments->Edx),
  179. &(BiosArguments->Esi),
  180. &(BiosArguments->Edi),
  181. &(BiosArguments->Ebp));
  182. KeReleaseMutex(&VpInt10Mutex, FALSE);
  183. if (bStatus) {
  184. pVideoDebugPrint ((3, "VIDEOPRT: Int10: Int 10 succeded properly\n"));
  185. return NO_ERROR;
  186. } else {
  187. pVideoDebugPrint ((0, "VIDEOPRT: Int10: Int 10 failed\n"));
  188. return ERROR_INVALID_PARAMETER;
  189. }
  190. }
  191. NTSTATUS
  192. pVideoPortRegisterVDM(
  193. IN PFDO_EXTENSION DeviceExtension,
  194. IN PVIDEO_VDM VdmInfo,
  195. IN ULONG VdmInfoSize,
  196. OUT PVIDEO_REGISTER_VDM RegisterVdm,
  197. IN ULONG RegisterVdmSize,
  198. OUT PULONG_PTR OutputSize
  199. )
  200. /*++
  201. Routine Description:
  202. This routine is used to register a VDM when it is started up.
  203. What this routine does is map the VIDEO BIOS into the VDM address space
  204. so that DOS apps can use it directly. Since the BIOS is READ_ONLY, we
  205. have no problem in mapping it as many times as we want.
  206. It returns the size of the save state buffer that must be allocated by
  207. the caller.
  208. Arguments:
  209. Return Value:
  210. STATUS_NOT_IMPLEMENTED
  211. --*/
  212. {
  213. return STATUS_NOT_IMPLEMENTED;
  214. }
  215. NTSTATUS
  216. pVideoPortSetIOPM(
  217. IN ULONG NumAccessRanges,
  218. IN PVIDEO_ACCESS_RANGE AccessRange,
  219. IN BOOLEAN Enable,
  220. IN ULONG IOPMNumber
  221. )
  222. /*++
  223. Routine Description:
  224. This routine is used to change the IOPM.
  225. This routine is x86 specific.
  226. Arguments:
  227. Return Value:
  228. STATUS_NOT_IMPLEMENTED
  229. --*/
  230. {
  231. return STATUS_NOT_IMPLEMENTED;
  232. }
  233. VP_STATUS
  234. VideoPortSetTrappedEmulatorPorts(
  235. PVOID HwDeviceExtension,
  236. ULONG NumAccessRanges,
  237. PVIDEO_ACCESS_RANGE AccessRange
  238. )
  239. /*++
  240. Routine Description:
  241. VideoPortSetTrappedEmulatorPorts (x86 machines only) allows a miniport
  242. driver to dynamically change the list of I/O ports that are trapped when
  243. a VDM is running in full-screen mode. The default set of ports being
  244. trapped by the miniport driver is defined to be all ports in the
  245. EMULATOR_ACCESS_ENTRY structure of the miniport driver.
  246. I/O ports not listed in the EMULATOR_ACCESS_ENTRY structure are
  247. unavailable to the MS-DOS application. Accessing those ports causes a
  248. trap to occur in the system, and the I/O operation to be reflected to a
  249. user-mode virtual device driver.
  250. The ports listed in the specified VIDEO_ACCESS_RANGE structure will be
  251. enabled in the I/O Permission Mask (IOPM) associated with the MS-DOS
  252. application. This will enable the MS-DOS application to access those I/O
  253. ports directly, without having the IO instruction trap and be passed down
  254. to the miniport trap handling functions (for example EmulatorAccessEntry
  255. functions) for validation. However, the subset of critical IO ports must
  256. always remain trapped for robustness.
  257. All MS-DOS applications use the same IOPM, and therefore the same set of
  258. enabled/disabled I/O ports. Thus, on each switch of application, the
  259. set of trapped I/O ports is reinitialized to be the default set of ports
  260. (all ports in the EMULATOR_ACCESS_ENTRY structure).
  261. Arguments:
  262. HwDeviceExtension - Points to the miniport driver's device extension.
  263. NumAccessRanges - Specifies the number of entries in the VIDEO_ACCESS_RANGE
  264. structure specified in AccessRange.
  265. AccessRange - Points to an array of access ranges (VIDEO_ACCESS_RANGE)
  266. defining the ports that can be untrapped and accessed directly by
  267. the MS-DOS application.
  268. Return Value:
  269. This function returns the final status of the operation.
  270. Environment:
  271. This routine cannot be called from a miniport routine synchronized with
  272. VideoPortSynchronizeRoutine or from an ISR.
  273. --*/
  274. {
  275. return ERROR_INVALID_PARAMETER;
  276. }
  277. VOID
  278. VideoPortZeroDeviceMemory(
  279. IN PVOID Destination,
  280. IN ULONG Length
  281. )
  282. /*++
  283. Routine Description:
  284. VideoPortZeroDeviceMemory zeroes a block of device memory of a certain
  285. length (Length) located at the address specified in Destination.
  286. Arguments:
  287. Destination - Specifies the starting address of the block of memory to be
  288. zeroed.
  289. Length - Specifies the length, in bytes, of the memory to be zeroed.
  290. Return Value:
  291. None.
  292. --*/
  293. {
  294. RtlZeroMemory(Destination,Length);
  295. return;
  296. }
  297. VOID
  298. pVideoPortInitializeInt10(
  299. PFDO_EXTENSION FdoExtension
  300. )
  301. {
  302. if (ServerBiosAddressSpaceInitialized) {
  303. return;
  304. }
  305. BiosTransferArea = ExAllocatePool(PagedPool, 0x1000 + 3);
  306. InitializeX86Int10Call(BiosTransferArea, 0x1000);
  307. ServerBiosAddressSpaceInitialized = TRUE;
  308. return;
  309. }
  310. BOOLEAN
  311. CallBiosEx (
  312. IN ULONG BiosCommand,
  313. IN OUT PULONG Eax,
  314. IN OUT PULONG Ebx,
  315. IN OUT PULONG Ecx,
  316. IN OUT PULONG Edx,
  317. IN OUT PULONG Esi,
  318. IN OUT PULONG Edi,
  319. IN OUT PULONG Ebp,
  320. IN OUT PUSHORT SegDs,
  321. IN OUT PUSHORT SegEs
  322. )
  323. /*++
  324. Routine Description:
  325. This function provides the platform specific interface between a device
  326. driver and the execution of the x86 ROM bios code for the specified ROM
  327. bios command.
  328. Arguments:
  329. BiosCommand - Supplies the ROM bios command to be emulated.
  330. Eax to Ebp - Supplies the x86 emulation context.
  331. Return Value:
  332. A value of TRUE is returned if the specified function is executed.
  333. Otherwise, a value of FALSE is returned.
  334. --*/
  335. {
  336. XM86_CONTEXT Context;
  337. //
  338. // If the x86 BIOS Emulator has not been initialized, then return FALSE.
  339. //
  340. if (X86BiosInitialized == FALSE) {
  341. return FALSE;
  342. }
  343. //
  344. // If the Adapter BIOS initialization failed and an Int10 command is
  345. // specified, then return FALSE.
  346. //
  347. if ((BiosCommand == 0x10) && (EnableInt10Calls == FALSE)) {
  348. return FALSE;
  349. }
  350. //
  351. // Copy the x86 bios context and emulate the specified command.
  352. //
  353. Context.Eax = *Eax;
  354. Context.Ebx = *Ebx;
  355. Context.Ecx = *Ecx;
  356. Context.Edx = *Edx;
  357. Context.Esi = *Esi;
  358. Context.Edi = *Edi;
  359. Context.Ebp = *Ebp;
  360. Context.SegDs = *SegDs;
  361. Context.SegEs = *SegEs;
  362. if (x86BiosExecuteInterrupt((UCHAR)BiosCommand,
  363. &Context,
  364. (PVOID)IoControlBase,
  365. (PVOID)IoMemoryBase) != XM_SUCCESS) {
  366. return FALSE;
  367. }
  368. //
  369. // Copy the x86 bios context and return TRUE.
  370. //
  371. *Eax = Context.Eax;
  372. *Ebx = Context.Ebx;
  373. *Ecx = Context.Ecx;
  374. *Edx = Context.Edx;
  375. *Esi = Context.Esi;
  376. *Edi = Context.Edi;
  377. *Ebp = Context.Ebp;
  378. *SegDs = Context.SegDs;
  379. *SegEs = Context.SegEs;
  380. return TRUE;
  381. }
  382. VOID
  383. InitializeX86Int10Call(
  384. PUCHAR BiosTransferArea,
  385. ULONG BiosTransferLength
  386. )
  387. /*++
  388. Routine Description:
  389. This function initializes x86 bios emulator, display data area and
  390. interrupt vector area.
  391. Arguments:
  392. None.
  393. Return Value:
  394. None.
  395. --*/
  396. {
  397. XM86_CONTEXT State;
  398. PXM86_CONTEXT Context;
  399. PULONG x86BiosLowMemoryPtr, PhysicalMemoryPtr;
  400. //
  401. // Initialize the x86 bios emulator.
  402. //
  403. InitIoMemoryBase();
  404. x86BiosInitializeBiosEx(IoControlBase,
  405. IoMemoryBase,
  406. NULL,
  407. BiosTransferArea,
  408. BiosTransferLength);
  409. x86BiosLowMemoryPtr = (PULONG)(x86BiosTranslateAddress(LOW_MEM_SEGMET, LOW_MEM_OFFSET));
  410. PhysicalMemoryPtr = (PULONG) IoMemoryBase;
  411. //
  412. // Copy the VECTOR TABLE from 0 to 2k. This is because we are not executing
  413. // the initialization of Adapter since SAL takes care of it. However, the
  414. // emulation memory needs to be updated from the interrupt vector and BIOS
  415. // data area.
  416. //
  417. RtlCopyMemory(x86BiosLowMemoryPtr,
  418. PhysicalMemoryPtr,
  419. (SIZE_OF_VECTOR_TABLE+SIZE_OF_BIOS_DATA_AREA));
  420. X86BiosInitialized = TRUE;
  421. EnableInt10Calls = TRUE;
  422. return;
  423. }
  424. VP_STATUS
  425. VpInt10AllocateBuffer(
  426. IN PVOID Context,
  427. OUT PUSHORT Seg,
  428. OUT PUSHORT Off,
  429. IN OUT PULONG Length
  430. )
  431. {
  432. VP_STATUS Status = STATUS_INSUFFICIENT_RESOURCES;
  433. if (Int10BufferAllocated == FALSE) {
  434. if (*Length <= 0x1000) {
  435. *Seg = VDM_TRANSFER_SEGMENT;
  436. *Off = VDM_TRANSFER_OFFSET;
  437. Int10BufferAllocated = TRUE;
  438. Status = NO_ERROR;
  439. }
  440. }
  441. *Length = VDM_TRANSFER_LENGTH;
  442. return Status;
  443. }
  444. VP_STATUS
  445. VpInt10FreeBuffer(
  446. IN PVOID Context,
  447. IN USHORT Seg,
  448. IN USHORT Off
  449. )
  450. {
  451. VP_STATUS Status = STATUS_INVALID_PARAMETER;
  452. if ((VDM_TRANSFER_SEGMENT == Seg) && (VDM_TRANSFER_OFFSET == Off)) {
  453. if (Int10BufferAllocated == TRUE) {
  454. Int10BufferAllocated = FALSE;
  455. Status = NO_ERROR;
  456. }
  457. }
  458. return Status;
  459. }
  460. VP_STATUS
  461. VpInt10ReadMemory(
  462. IN PVOID Context,
  463. IN USHORT Seg,
  464. IN USHORT Off,
  465. OUT PVOID Buffer,
  466. IN ULONG Length
  467. )
  468. {
  469. ULONG_PTR Address = ((Seg << 4) + Off);
  470. if ((Address >= (VDM_TRANSFER_SEGMENT << 4)) &&
  471. ((Address + Length) <= ((VDM_TRANSFER_SEGMENT << 4) + VDM_TRANSFER_LENGTH))) {
  472. PUCHAR Memory = BiosTransferArea + Address - (VDM_TRANSFER_SEGMENT << 4);
  473. RtlCopyMemory(Buffer, Memory, Length);
  474. } else {
  475. RtlCopyMemory(Buffer, (PUCHAR)IoMemoryBase + Address, Length);
  476. }
  477. return NO_ERROR;
  478. }
  479. VP_STATUS
  480. VpInt10WriteMemory(
  481. IN PVOID Context,
  482. IN USHORT Seg,
  483. IN USHORT Off,
  484. IN PVOID Buffer,
  485. IN ULONG Length
  486. )
  487. {
  488. ULONG_PTR Address = ((Seg << 4) + Off);
  489. if ((Address >= (VDM_TRANSFER_SEGMENT << 4)) &&
  490. ((Address + Length) <= ((VDM_TRANSFER_SEGMENT << 4) + VDM_TRANSFER_LENGTH))) {
  491. PUCHAR Memory = BiosTransferArea + Address - (VDM_TRANSFER_SEGMENT << 4);
  492. RtlCopyMemory(Memory, Buffer, Length);
  493. } else {
  494. return STATUS_INVALID_PARAMETER;
  495. }
  496. return NO_ERROR;
  497. }
  498. VP_STATUS
  499. VpInt10CallBios(
  500. PVOID HwDeviceExtension,
  501. PINT10_BIOS_ARGUMENTS BiosArguments
  502. )
  503. /*++
  504. Routine Description:
  505. This function allows a miniport driver to call the kernel to perform
  506. an int10 operation.
  507. This will execute natively the BIOS ROM code on the device.
  508. THIS FUNCTION IS FOR X86 ONLY.
  509. Arguments:
  510. HwDeviceExtension - Pointer to the miniport driver's device extension.
  511. BiosArguments - Pointer to a structure containing the value of the
  512. basic x86 registers that should be set before calling the BIOS routine.
  513. 0 should be used for unused registers.
  514. Return Value:
  515. ERROR_INVALID_PARAMETER
  516. --*/
  517. {
  518. BOOLEAN bStatus;
  519. PFDO_EXTENSION deviceExtension = GET_FDO_EXT(HwDeviceExtension);
  520. ULONG inIoSpace = 0;
  521. PVOID virtualAddress;
  522. ULONG length;
  523. CONTEXT context;
  524. //
  525. // Must make sure the caller is a trusted subsystem with the
  526. // appropriate address space set up.
  527. //
  528. if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(
  529. SE_TCB_PRIVILEGE),
  530. deviceExtension->CurrentIrpRequestorMode)) {
  531. return ERROR_INVALID_PARAMETER;
  532. }
  533. if (ServerBiosAddressSpaceInitialized == 0) {
  534. ASSERT(FALSE);
  535. return ERROR_INVALID_PARAMETER;
  536. }
  537. //
  538. // Now call the HAL to actually perform the int 10 operation.
  539. //
  540. pVideoDebugPrint((3, "VIDEOPRT: Int10: edi %x esi %x eax %x ebx %x \n\t ecx %x edx %x ebp %x ds %x es %x\n",
  541. BiosArguments->Edi,
  542. BiosArguments->Esi,
  543. BiosArguments->Eax,
  544. BiosArguments->Ebx,
  545. BiosArguments->Ecx,
  546. BiosArguments->Edx,
  547. BiosArguments->Ebp,
  548. BiosArguments->SegDs,
  549. BiosArguments->SegEs ));
  550. KeWaitForSingleObject(&VpInt10Mutex,
  551. Executive,
  552. KernelMode,
  553. FALSE,
  554. (PTIME)NULL);
  555. bStatus = CallBiosEx(0x10,
  556. &(BiosArguments->Eax),
  557. &(BiosArguments->Ebx),
  558. &(BiosArguments->Ecx),
  559. &(BiosArguments->Edx),
  560. &(BiosArguments->Esi),
  561. &(BiosArguments->Edi),
  562. &(BiosArguments->Ebp),
  563. &(BiosArguments->SegDs),
  564. &(BiosArguments->SegEs));
  565. KeReleaseMutex(&VpInt10Mutex, FALSE);
  566. if (bStatus) {
  567. pVideoDebugPrint ((3, "VIDEOPRT: Int10: Int 10 succeded properly\n"));
  568. return NO_ERROR;
  569. } else {
  570. pVideoDebugPrint ((0, "VIDEOPRT: Int10: Int 10 failed\n"));
  571. return ERROR_INVALID_PARAMETER;
  572. }
  573. }