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.

1315 lines
30 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. x86bios.c
  5. Abstract:
  6. This module implements supplies the HAL interface to the 386/486
  7. real mode emulator for the purpose of emulating BIOS calls..
  8. Author:
  9. David N. Cutler (davec) 13-Nov-1994
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. --*/
  14. #include "nthal.h"
  15. #include "hal.h"
  16. #include "xm86.h"
  17. #include "x86new.h"
  18. #include "pci.h"
  19. //
  20. // Define the size of low memory.
  21. //
  22. #define LOW_MEMORY_SIZE 0x800
  23. //
  24. // Define storage for low emulated memory.
  25. //
  26. UCHAR x86BiosLowMemory[LOW_MEMORY_SIZE + 3];
  27. ULONG x86BiosScratchMemory;
  28. //
  29. // Define storage to capture the base address of I/O space, the base address
  30. // of I/O memory space, and the base address of the video frame buffer.
  31. //
  32. ULONG_PTR x86BiosFrameBuffer;
  33. ULONG_PTR x86BiosIoMemory;
  34. ULONG_PTR x86BiosIoSpace;
  35. //
  36. // Define an area of storage to allow for buffer passing between the BIOS
  37. // and native mode code.
  38. //
  39. ULONG_PTR x86BiosTransferMemory = 0;
  40. ULONG x86BiosTransferLength = 0;
  41. //
  42. // Define BIOS initialized state.
  43. //
  44. BOOLEAN x86BiosInitialized = FALSE;
  45. //
  46. // Define storage for PCI BIOS initialization state.
  47. //
  48. UCHAR XmNumberPciBusses = 0;
  49. BOOLEAN XmPciBiosPresent = FALSE;
  50. PGETSETPCIBUSDATA XmGetPciData;
  51. PGETSETPCIBUSDATA XmSetPciData;
  52. ULONG XmPCIConfigAddress = 0; // Current Value of emulated PCI Address Port
  53. ULONG
  54. x86BiosReadPciAddressPort(
  55. IN XM_OPERATION_DATATYPE DataType,
  56. IN USHORT PortNumber
  57. );
  58. VOID
  59. x86BiosWritePciAddressPort(
  60. IN XM_OPERATION_DATATYPE DataType,
  61. IN USHORT PortNumber,
  62. IN ULONG Value
  63. );
  64. ULONG
  65. x86BiosReadPciDataPort(
  66. IN XM_OPERATION_DATATYPE DataType,
  67. IN USHORT PortNumber
  68. );
  69. VOID
  70. x86BiosWritePciDataPort(
  71. IN XM_OPERATION_DATATYPE DataType,
  72. IN USHORT PortNumber,
  73. IN ULONG Value
  74. );
  75. ULONG
  76. x86BiosReadIoSpace (
  77. IN XM_OPERATION_DATATYPE DataType,
  78. IN USHORT PortNumber
  79. )
  80. /*++
  81. Routine Description:
  82. This function reads from emulated I/O space.
  83. Arguments:
  84. DataType - Supplies the datatype for the read operation.
  85. PortNumber - Supplies the port number in I/O space to read from.
  86. Return Value:
  87. The value read from I/O space is returned as the function value.
  88. N.B. If an aligned operation is specified, then the individual
  89. bytes are read from the specified port one at a time and
  90. assembled into the specified datatype.
  91. --*/
  92. {
  93. ULONG Result;
  94. union {
  95. PUCHAR Byte;
  96. PUSHORT Word;
  97. PULONG Long;
  98. } u;
  99. //
  100. // If we have access to the HAL config space routines intercept accesses to
  101. // the PCI Config Ports and emulate them.
  102. //
  103. if (XmPciBiosPresent) {
  104. if ((PCI_TYPE1_ADDR_PORT <= PortNumber) &&
  105. (PortNumber <= (PCI_TYPE1_ADDR_PORT + 3))) {
  106. return x86BiosReadPciAddressPort(DataType,
  107. PortNumber - PCI_TYPE1_ADDR_PORT);
  108. } else if ((XmPCIConfigAddress & (1 << 31)) &&
  109. (PCI_TYPE1_DATA_PORT <= PortNumber) &&
  110. (PortNumber <= (PCI_TYPE1_DATA_PORT + 3))) {
  111. return x86BiosReadPciDataPort(DataType,
  112. PortNumber - PCI_TYPE1_DATA_PORT);
  113. }
  114. }
  115. //
  116. // Compute port address and read port.
  117. //
  118. u.Long = (PULONG)(x86BiosIoSpace + PortNumber);
  119. if (DataType == BYTE_DATA) {
  120. Result = READ_PORT_UCHAR(u.Byte);
  121. } else if (DataType == LONG_DATA) {
  122. if (((ULONG_PTR)u.Long & 0x3) != 0) {
  123. Result = (READ_PORT_UCHAR(u.Byte + 0)) |
  124. (READ_PORT_UCHAR(u.Byte + 1) << 8) |
  125. (READ_PORT_UCHAR(u.Byte + 2) << 16) |
  126. (READ_PORT_UCHAR(u.Byte + 3) << 24);
  127. } else {
  128. Result = READ_PORT_ULONG(u.Long);
  129. }
  130. } else {
  131. if (((ULONG_PTR)u.Word & 0x1) != 0) {
  132. Result = (READ_PORT_UCHAR(u.Byte + 0)) |
  133. (READ_PORT_UCHAR(u.Byte + 1) << 8);
  134. } else {
  135. Result = READ_PORT_USHORT(u.Word);
  136. }
  137. }
  138. return Result;
  139. }
  140. VOID
  141. x86BiosWriteIoSpace (
  142. IN XM_OPERATION_DATATYPE DataType,
  143. IN USHORT PortNumber,
  144. IN ULONG Value
  145. )
  146. /*++
  147. Routine Description:
  148. This function write to emulated I/O space.
  149. N.B. If an aligned operation is specified, then the individual
  150. bytes are written to the specified port one at a time.
  151. Arguments:
  152. DataType - Supplies the datatype for the write operation.
  153. PortNumber - Supplies the port number in I/O space to write to.
  154. Value - Supplies the value to write.
  155. Return Value:
  156. None.
  157. --*/
  158. {
  159. union {
  160. PUCHAR Byte;
  161. PUSHORT Word;
  162. PULONG Long;
  163. } u;
  164. //
  165. // If we have access to the HAL config space routines intercept accesses to
  166. // the PCI Config Ports and emulate them.
  167. //
  168. if (XmPciBiosPresent) {
  169. if ((PCI_TYPE1_ADDR_PORT <= PortNumber) &&
  170. (PortNumber <= (PCI_TYPE1_ADDR_PORT + 3))) {
  171. x86BiosWritePciAddressPort(DataType,
  172. PortNumber - PCI_TYPE1_ADDR_PORT,
  173. Value);
  174. return;
  175. } else if ((XmPCIConfigAddress & (1 << 31)) &&
  176. (PCI_TYPE1_DATA_PORT <= PortNumber) &&
  177. (PortNumber <= (PCI_TYPE1_DATA_PORT + 3))) {
  178. x86BiosWritePciDataPort(DataType,
  179. PortNumber - PCI_TYPE1_DATA_PORT,
  180. Value);
  181. return;
  182. }
  183. }
  184. //
  185. // Compute port address and read port.
  186. //
  187. u.Long = (PULONG)(x86BiosIoSpace + PortNumber);
  188. if (DataType == BYTE_DATA) {
  189. WRITE_PORT_UCHAR(u.Byte, (UCHAR)Value);
  190. } else if (DataType == LONG_DATA) {
  191. if (((ULONG_PTR)u.Long & 0x3) != 0) {
  192. WRITE_PORT_UCHAR(u.Byte + 0, (UCHAR)(Value));
  193. WRITE_PORT_UCHAR(u.Byte + 1, (UCHAR)(Value >> 8));
  194. WRITE_PORT_UCHAR(u.Byte + 2, (UCHAR)(Value >> 16));
  195. WRITE_PORT_UCHAR(u.Byte + 3, (UCHAR)(Value >> 24));
  196. } else {
  197. WRITE_PORT_ULONG(u.Long, Value);
  198. }
  199. } else {
  200. if (((ULONG_PTR)u.Word & 0x1) != 0) {
  201. WRITE_PORT_UCHAR(u.Byte + 0, (UCHAR)(Value));
  202. WRITE_PORT_UCHAR(u.Byte + 1, (UCHAR)(Value >> 8));
  203. } else {
  204. WRITE_PORT_USHORT(u.Word, (USHORT)Value);
  205. }
  206. }
  207. return;
  208. }
  209. PVOID
  210. x86BiosTranslateAddress (
  211. IN USHORT Segment,
  212. IN USHORT Offset
  213. )
  214. /*++
  215. Routine Description:
  216. This translates a segment/offset address into a memory address.
  217. Arguments:
  218. Segment - Supplies the segment register value.
  219. Offset - Supplies the offset within segment.
  220. Return Value:
  221. The memory address of the translated segment/offset pair is
  222. returned as the function value.
  223. --*/
  224. {
  225. ULONG Value;
  226. //
  227. // Compute the logical memory address and case on high hex digit of
  228. // the resultant address.
  229. //
  230. Value = Offset + (Segment << 4);
  231. Offset = (USHORT)(Value & 0xffff);
  232. Value &= 0xf0000;
  233. switch ((Value >> 16) & 0xf) {
  234. //
  235. // Interrupt vector/stack space.
  236. //
  237. case 0x0:
  238. if (Offset > LOW_MEMORY_SIZE) {
  239. x86BiosScratchMemory = 0;
  240. return (PVOID)&x86BiosScratchMemory;
  241. } else {
  242. return (PVOID)(&x86BiosLowMemory[0] + Offset);
  243. }
  244. //
  245. // The memory range from 0x10000 to 0x8ffff reads as zero
  246. // and writes are ignored.
  247. //
  248. case 0x1:
  249. case 0x3:
  250. case 0x4:
  251. case 0x5:
  252. case 0x6:
  253. case 0x7:
  254. case 0x8:
  255. x86BiosScratchMemory = 0;
  256. return (PVOID)&x86BiosScratchMemory;
  257. case 0x9:
  258. //
  259. // BUGBUG: Found a VGA adapter loaded in segment 9
  260. // Emulator assumptions about video adapters needs to be
  261. // looked at
  262. //
  263. return (PVOID)(x86BiosIoMemory + Offset + Value);
  264. //
  265. // The memory range from 0x20000 to 0x20fff is used to transfer
  266. // buffers between native mode and emulated mode.
  267. //
  268. case 0x2:
  269. if (Offset < x86BiosTransferLength) {
  270. return (PVOID)(x86BiosTransferMemory + Offset);
  271. } else {
  272. x86BiosScratchMemory = 0;
  273. return (PVOID)&x86BiosScratchMemory;
  274. }
  275. //
  276. // The memory range from 0xa0000 to 0xbffff maps to the
  277. // framebuffer if previously specified, otherwise I/O memory.
  278. //
  279. case 0xa:
  280. case 0xb:
  281. if (x86BiosFrameBuffer != 0) {
  282. return (PVOID)(x86BiosFrameBuffer + Offset + Value);
  283. }
  284. //
  285. // The memory range from 0xc0000 to 0xfffff maps to I/O memory
  286. //
  287. case 0xc:
  288. case 0xd:
  289. case 0xe:
  290. case 0xf:
  291. return (PVOID)(x86BiosIoMemory + Offset + Value);
  292. DEFAULT_UNREACHABLE;
  293. }
  294. }
  295. VOID
  296. x86BiosInitializeBios (
  297. IN PVOID BiosIoSpace,
  298. IN PVOID BiosIoMemory
  299. )
  300. /*++
  301. Routine Description:
  302. This function initializes x86 BIOS emulation.
  303. Arguments:
  304. BiosIoSpace - Supplies the base address of the I/O space to be used
  305. for BIOS emulation.
  306. BiosIoMemory - Supplies the base address of the I/O memory to be
  307. used for BIOS emulation.
  308. Return Value:
  309. None.
  310. --*/
  311. {
  312. //
  313. // Initialize x86 BIOS emulation.
  314. //
  315. x86BiosInitializeBiosShadowed(BiosIoSpace,
  316. BiosIoMemory,
  317. NULL);
  318. return;
  319. }
  320. VOID
  321. x86BiosInitializeBiosEx (
  322. IN PVOID BiosIoSpace,
  323. IN PVOID BiosIoMemory,
  324. IN PVOID BiosFrameBuffer,
  325. IN PVOID BiosTransferMemory,
  326. IN ULONG TransferLength
  327. )
  328. /*++
  329. Routine Description:
  330. This function initializes x86 BIOS emulation.
  331. Arguments:
  332. BiosIoSpace - Supplies the base address of the I/O space to be used
  333. for BIOS emulation.
  334. BiosIoMemory - Supplies the base address of the I/O memory to be
  335. used for BIOS emulation.
  336. Return Value:
  337. None.
  338. --*/
  339. {
  340. //
  341. // Initialize x86 BIOS emulation.
  342. //
  343. x86BiosInitializeBiosShadowed(BiosIoSpace,
  344. BiosIoMemory,
  345. BiosFrameBuffer
  346. );
  347. x86BiosTransferMemory = (ULONG_PTR)BiosTransferMemory;
  348. x86BiosTransferLength = TransferLength;
  349. return;
  350. }
  351. VOID
  352. x86BiosInitializeBiosShadowed (
  353. IN PVOID BiosIoSpace,
  354. IN PVOID BiosIoMemory,
  355. IN PVOID BiosFrameBuffer
  356. )
  357. /*++
  358. Routine Description:
  359. This function initializes x86 BIOS emulation.
  360. Arguments:
  361. BiosIoSpace - Supplies the base address of the I/O space to be used
  362. for BIOS emulation.
  363. BiosIoMemory - Supplies the base address of the I/O memory to be
  364. used for BIOS emulation.
  365. BiosFrameBuffer - Supplies the base address of the video frame buffer
  366. to be used for bios emulation.
  367. Return Value:
  368. None.
  369. --*/
  370. {
  371. //
  372. // Zero low memory.
  373. //
  374. memset(&x86BiosLowMemory, 0, LOW_MEMORY_SIZE);
  375. //
  376. // Save base address of I/O memory and I/O space.
  377. //
  378. x86BiosIoSpace = (ULONG_PTR)BiosIoSpace;
  379. x86BiosIoMemory = (ULONG_PTR)BiosIoMemory;
  380. x86BiosFrameBuffer = (ULONG_PTR)BiosFrameBuffer;
  381. //
  382. // Initialize the emulator and the BIOS.
  383. //
  384. XmInitializeEmulator(0,
  385. LOW_MEMORY_SIZE,
  386. x86BiosReadIoSpace,
  387. x86BiosWriteIoSpace,
  388. x86BiosTranslateAddress);
  389. x86BiosInitialized = TRUE;
  390. return;
  391. }
  392. VOID
  393. x86BiosInitializeBiosShadowedPci (
  394. IN PVOID BiosIoSpace,
  395. IN PVOID BiosIoMemory,
  396. IN PVOID BiosFrameBuffer,
  397. IN UCHAR NumberPciBusses,
  398. IN PGETSETPCIBUSDATA GetPciData,
  399. IN PGETSETPCIBUSDATA SetPciData
  400. )
  401. /*++
  402. Routine Description:
  403. This function initializes x86 BIOS emulation and also sets up the
  404. emulator with BIOS shadowed and PCI functions enabled. Since the
  405. PCI specification requires BIOS shadowing, there isn't any need
  406. to provide a function that turns on the PCI functions, but doesn't
  407. shadow the BIOS.
  408. Arguments:
  409. BiosIoSpace - Supplies the base address of the I/O space to be used
  410. for BIOS emulation.
  411. BiosIoMemory - Supplies the base address of the I/O memory to be
  412. used for BIOS emulation.
  413. BiosFrameBuffer - Supplies the base address of the video frame buffer
  414. to be used for bios emulation.
  415. NumberPciBusses - Supplies the number of PCI busses in the system.
  416. GetPciData - Supplies the address of a function to read the PCI
  417. configuration space.
  418. SetPciData - Supplies the address of a function to write the PCI
  419. configuration space.
  420. Return Value:
  421. None.
  422. --*/
  423. {
  424. //
  425. // Enable PCI BIOS support.
  426. //
  427. XmPciBiosPresent = TRUE;
  428. XmGetPciData = GetPciData;
  429. XmSetPciData = SetPciData;
  430. XmNumberPciBusses = NumberPciBusses;
  431. //
  432. // Initialize x86 BIOS emulation.
  433. //
  434. x86BiosInitializeBiosShadowed(BiosIoSpace,
  435. BiosIoMemory,
  436. BiosFrameBuffer);
  437. return;
  438. }
  439. XM_STATUS
  440. x86BiosExecuteInterrupt (
  441. IN UCHAR Number,
  442. IN OUT PXM86_CONTEXT Context,
  443. IN PVOID BiosIoSpace OPTIONAL,
  444. IN PVOID BiosIoMemory OPTIONAL
  445. )
  446. /*++
  447. Routine Description:
  448. This function executes an interrupt by calling the x86 emulator.
  449. Arguments:
  450. Number - Supplies the number of the interrupt that is to be emulated.
  451. Context - Supplies a pointer to an x86 context structure.
  452. BiosIoSpace - Supplies an optional base address of the I/O space
  453. to be used for BIOS emulation.
  454. BiosIoMemory - Supplies an optional base address of the I/O memory
  455. to be used for BIOS emulation.
  456. Return Value:
  457. The emulation completion status.
  458. --*/
  459. {
  460. //
  461. // Execute x86 interrupt.
  462. //
  463. return x86BiosExecuteInterruptShadowed(Number,
  464. Context,
  465. BiosIoSpace,
  466. BiosIoMemory,
  467. NULL);
  468. }
  469. XM_STATUS
  470. x86BiosExecuteInterruptShadowed (
  471. IN UCHAR Number,
  472. IN OUT PXM86_CONTEXT Context,
  473. IN PVOID BiosIoSpace OPTIONAL,
  474. IN PVOID BiosIoMemory OPTIONAL,
  475. IN PVOID BiosFrameBuffer OPTIONAL
  476. )
  477. /*++
  478. Routine Description:
  479. This function executes an interrupt by calling the x86 emulator.
  480. Arguments:
  481. Number - Supplies the number of the interrupt that is to be emulated.
  482. Context - Supplies a pointer to an x86 context structure.
  483. BiosIoSpace - Supplies an optional base address of the I/O space
  484. to be used for BIOS emulation.
  485. BiosIoMemory - Supplies an optional base address of the I/O memory
  486. to be used for BIOS emulation.
  487. BiosFrameBuffer - Supplies an optional base address of the video
  488. frame buffer to be used for bios emulation.
  489. Return Value:
  490. The emulation completion status.
  491. --*/
  492. {
  493. XM_STATUS Status;
  494. //
  495. // If a new base address is specified, then set the appropriate base.
  496. //
  497. if (BiosIoSpace != NULL) {
  498. x86BiosIoSpace = (ULONG_PTR)BiosIoSpace;
  499. }
  500. if (BiosIoMemory != NULL) {
  501. x86BiosIoMemory = (ULONG_PTR)BiosIoMemory;
  502. }
  503. if (BiosFrameBuffer != NULL) {
  504. x86BiosFrameBuffer = (ULONG_PTR)BiosFrameBuffer;
  505. }
  506. //
  507. // Execute the specified interrupt.
  508. //
  509. Status = XmEmulateInterrupt(Number, Context);
  510. if (Status != XM_SUCCESS) {
  511. DbgPrint("HAL: Interrupt emulation failed, status %lx\n", Status);
  512. }
  513. return Status;
  514. }
  515. XM_STATUS
  516. x86BiosExecuteInterruptShadowedPci (
  517. IN UCHAR Number,
  518. IN OUT PXM86_CONTEXT Context,
  519. IN PVOID BiosIoSpace OPTIONAL,
  520. IN PVOID BiosIoMemory OPTIONAL,
  521. IN PVOID BiosFrameBuffer OPTIONAL,
  522. IN UCHAR NumberPciBusses,
  523. IN PGETSETPCIBUSDATA GetPciData,
  524. IN PGETSETPCIBUSDATA SetPciData
  525. )
  526. /*++
  527. Routine Description:
  528. This function executes an interrupt by calling the x86 emulator.
  529. Arguments:
  530. Number - Supplies the number of the interrupt that is to be emulated.
  531. Context - Supplies a pointer to an x86 context structure.
  532. BiosIoSpace - Supplies an optional base address of the I/O space
  533. to be used for BIOS emulation.
  534. BiosIoMemory - Supplies an optional base address of the I/O memory
  535. to be used for BIOS emulation.
  536. NumberPciBusses - Supplies the number of PCI busses in the system.
  537. GetPciData - Supplies the address of a function to read the PCI
  538. configuration space.
  539. SetPciData - Supplies the address of a function to write the PCI
  540. configuration space.
  541. Return Value:
  542. The emulation completion status.
  543. --*/
  544. {
  545. //
  546. // Enable PCI BIOS support.
  547. //
  548. XmPciBiosPresent = TRUE;
  549. XmGetPciData = GetPciData;
  550. XmSetPciData = SetPciData;
  551. XmNumberPciBusses = NumberPciBusses;
  552. //
  553. // Execute x86 interrupt.
  554. //
  555. return x86BiosExecuteInterruptShadowed(Number,
  556. Context,
  557. BiosIoSpace,
  558. BiosIoMemory,
  559. BiosFrameBuffer);
  560. }
  561. XM_STATUS
  562. x86BiosInitializeAdapter(
  563. IN ULONG Adapter,
  564. IN OUT PXM86_CONTEXT Context OPTIONAL,
  565. IN PVOID BiosIoSpace OPTIONAL,
  566. IN PVOID BiosIoMemory OPTIONAL
  567. )
  568. /*++
  569. Routine Description:
  570. This function initializes the adapter whose BIOS starts at the
  571. specified 20-bit address.
  572. Arguments:
  573. Adpater - Supplies the 20-bit address of the BIOS for the adapter
  574. to be initialized.
  575. Return Value:
  576. The emulation completion status.
  577. --*/
  578. {
  579. //
  580. // Initialize the specified adapter.
  581. //
  582. return x86BiosInitializeAdapterShadowed(Adapter,
  583. Context,
  584. BiosIoSpace,
  585. BiosIoMemory,
  586. NULL);
  587. }
  588. XM_STATUS
  589. x86BiosInitializeAdapterShadowed (
  590. IN ULONG Adapter,
  591. IN OUT PXM86_CONTEXT Context OPTIONAL,
  592. IN PVOID BiosIoSpace OPTIONAL,
  593. IN PVOID BiosIoMemory OPTIONAL,
  594. IN PVOID BiosFrameBuffer OPTIONAL
  595. )
  596. /*++
  597. Routine Description:
  598. This function initializes the adapter whose BIOS starts at the
  599. specified 20-bit address.
  600. Arguments:
  601. Adpater - Supplies the 20-bit address of the BIOS for the adapter
  602. to be initialized.
  603. Return Value:
  604. The emulation completion status.
  605. --*/
  606. {
  607. PUCHAR Byte;
  608. XM86_CONTEXT State;
  609. USHORT Offset;
  610. USHORT Segment;
  611. XM_STATUS Status;
  612. //
  613. // If BIOS emulation has not been initialized, then return an error.
  614. //
  615. if (x86BiosInitialized == FALSE) {
  616. return XM_EMULATOR_NOT_INITIALIZED;
  617. }
  618. //
  619. // If an emulator context is not specified, then use a default
  620. // context.
  621. //
  622. if (ARGUMENT_PRESENT(Context) == FALSE) {
  623. State.Eax = 0;
  624. State.Ecx = 0;
  625. State.Edx = 0;
  626. State.Ebx = 0;
  627. State.Ebp = 0;
  628. State.Esi = 0;
  629. State.Edi = 0;
  630. Context = &State;
  631. }
  632. //
  633. // If a new base address is specified, then set the appropriate base.
  634. //
  635. if (BiosIoSpace != NULL) {
  636. x86BiosIoSpace = (ULONG_PTR)BiosIoSpace;
  637. }
  638. if (BiosIoMemory != NULL) {
  639. x86BiosIoMemory = (ULONG_PTR)BiosIoMemory;
  640. }
  641. if (BiosFrameBuffer != NULL) {
  642. x86BiosFrameBuffer = (ULONG_PTR)BiosFrameBuffer;
  643. }
  644. //
  645. // If the specified adpater is not BIOS code, then return an error.
  646. //
  647. Segment = (USHORT)((Adapter >> 4) & 0xf000);
  648. Offset = (USHORT)(Adapter & 0xffff);
  649. Byte = (PUCHAR)x86BiosTranslateAddress(Segment, Offset);
  650. if ((*Byte++ != 0x55) || (*Byte != 0xaa)) {
  651. return XM_ILLEGAL_CODE_SEGMENT;
  652. }
  653. //
  654. // Call the BIOS code to initialize the specified adapter.
  655. //
  656. Adapter += 3;
  657. Segment = (USHORT)((Adapter >> 4) & 0xf000);
  658. Offset = (USHORT)(Adapter & 0xffff);
  659. Status = XmEmulateFarCall(Segment, Offset, Context);
  660. if (Status != XM_SUCCESS) {
  661. DbgPrint("HAL: Adapter initialization falied, status %lx\n", Status);
  662. }
  663. return Status;
  664. }
  665. XM_STATUS
  666. x86BiosInitializeAdapterShadowedPci(
  667. IN ULONG Adapter,
  668. IN OUT PXM86_CONTEXT Context OPTIONAL,
  669. IN PVOID BiosIoSpace OPTIONAL,
  670. IN PVOID BiosIoMemory OPTIONAL,
  671. IN PVOID BiosFrameBuffer OPTIONAL,
  672. IN UCHAR NumberPciBusses,
  673. IN PGETSETPCIBUSDATA GetPciData,
  674. IN PGETSETPCIBUSDATA SetPciData
  675. )
  676. /*++
  677. Routine Description:
  678. This function initializes the adapter whose BIOS starts at the
  679. specified 20-bit address.
  680. Arguments:
  681. Adpater - Supplies the 20-bit address of the BIOS for the adapter
  682. to be initialized.
  683. Return Value:
  684. The emulation completion status.
  685. --*/
  686. {
  687. //
  688. // Enable PCI BIOS support.
  689. //
  690. XmPciBiosPresent = TRUE;
  691. XmGetPciData = GetPciData;
  692. XmSetPciData = SetPciData;
  693. XmNumberPciBusses = NumberPciBusses;
  694. //
  695. // Initialize the specified adapter.
  696. //
  697. return x86BiosInitializeAdapterShadowed(Adapter,
  698. Context,
  699. BiosIoSpace,
  700. BiosIoMemory,
  701. BiosFrameBuffer);
  702. }
  703. ULONG
  704. x86BiosReadPciAddressPort(
  705. IN XM_OPERATION_DATATYPE DataType,
  706. IN USHORT PortNumber
  707. )
  708. /*++
  709. Routine Description:
  710. This function reads from emulated I/O space.
  711. Arguments:
  712. DataType - Supplies the datatype for the read operation.
  713. PortNumber - Supplies the port number in I/O space to read from.
  714. Return Value:
  715. The value read from I/O space is returned as the function value.
  716. N.B. If an aligned operation is specified, then the individual
  717. bytes are read from the specified port one at a time and
  718. assembled into the specified datatype.
  719. --*/
  720. {
  721. ULONG Result;
  722. //
  723. // We assume that DataType is the number of bytes - 1. If this ever changes
  724. // then this routine needs to be rewritten.
  725. //
  726. C_ASSERT(BYTE_DATA == 0);
  727. C_ASSERT(WORD_DATA == 1);
  728. C_ASSERT(LONG_DATA == 3);
  729. //
  730. // If we don't have access to the HAL config space routines just return 0.
  731. //
  732. if (!XmPciBiosPresent) {
  733. return 0;
  734. }
  735. //
  736. // Make sure they aren't trying to read past the end of the register, we'll
  737. // fill any extra bytes with zeroes.
  738. //
  739. if ((PortNumber + DataType) > 3) {
  740. ASSERT(0);
  741. DataType = 3 - PortNumber;
  742. }
  743. //
  744. // Compute port address and read port.
  745. //
  746. switch (DataType) {
  747. case BYTE_DATA:
  748. Result = (ULONG)*(((PUCHAR)&XmPCIConfigAddress) + PortNumber);
  749. break;
  750. case WORD_DATA:
  751. Result = (ULONG)*(USHORT UNALIGNED *)(((PUCHAR)&XmPCIConfigAddress) + PortNumber);
  752. break;
  753. case 2: // Special case that results from reading 4 bytes starting at port CF9
  754. Result = (ULONG)*(USHORT UNALIGNED *)(((PUCHAR)&XmPCIConfigAddress) + PortNumber);
  755. Result |= ((ULONG)*(((PUCHAR)&XmPCIConfigAddress) + 3)) << 16;
  756. break;
  757. case LONG_DATA:
  758. ASSERT(PortNumber == 0);
  759. Result = (ULONG)XmPCIConfigAddress;
  760. break;
  761. default:
  762. ASSERT(0);
  763. Result = 0;
  764. break;
  765. }
  766. return Result;
  767. }
  768. VOID
  769. x86BiosWritePciAddressPort(
  770. IN XM_OPERATION_DATATYPE DataType,
  771. IN USHORT PortNumber,
  772. IN ULONG Value
  773. )
  774. /*++
  775. Routine Description:
  776. This function write to emulated I/O space.
  777. N.B. If an aligned operation is specified, then the individual
  778. bytes are written to the specified port one at a time.
  779. Arguments:
  780. DataType - Supplies the datatype for the write operation.
  781. PortNumber - Supplies the port number in I/O space to write to.
  782. Value - Supplies the value to write.
  783. Return Value:
  784. None.
  785. --*/
  786. {
  787. //
  788. // We assume that DataType is the number of bytes - 1. If this ever changes
  789. // then this routine needs to be rewritten.
  790. //
  791. C_ASSERT(BYTE_DATA == 0);
  792. C_ASSERT(WORD_DATA == 1);
  793. C_ASSERT(LONG_DATA == 3);
  794. //
  795. // If we don't have access to the HAL config space routines just ignore.
  796. //
  797. if (!XmPciBiosPresent) {
  798. return;
  799. }
  800. //
  801. // Make sure they aren't trying to write past the end of the register, we'll
  802. // ignore any extra bytes.
  803. //
  804. if ((PortNumber + DataType) > 3) {
  805. ASSERT(0);
  806. DataType = 3 - PortNumber;
  807. }
  808. //
  809. // Compute port address and write port.
  810. //
  811. switch (DataType) {
  812. case BYTE_DATA:
  813. *(((PUCHAR)&XmPCIConfigAddress) + PortNumber) = (UCHAR)Value;
  814. break;
  815. case WORD_DATA:
  816. *(USHORT UNALIGNED *)(((PUCHAR)&XmPCIConfigAddress) + PortNumber) = (USHORT)Value;
  817. break;
  818. case 2: // Special case that results from reading 4 bytes starting at port CF9
  819. *(USHORT UNALIGNED *)(((PUCHAR)&XmPCIConfigAddress) + PortNumber) = (USHORT)Value;
  820. *(((PUCHAR)&XmPCIConfigAddress) + 3) = (UCHAR)(Value >> 16);
  821. break;
  822. case LONG_DATA:
  823. ASSERT(PortNumber == 0);
  824. XmPCIConfigAddress = Value;
  825. break;
  826. default:
  827. ASSERT(0);
  828. break;
  829. }
  830. //
  831. // Clean up low order two bits, these are forced to zero in the real
  832. // hardware.
  833. //
  834. XmPCIConfigAddress &= ~0x3;
  835. return;
  836. }
  837. ULONG
  838. x86BiosReadPciDataPort(
  839. IN XM_OPERATION_DATATYPE DataType,
  840. IN USHORT PortNumber
  841. )
  842. /*++
  843. Routine Description:
  844. This function reads from emulated I/O space.
  845. Arguments:
  846. DataType - Supplies the datatype for the read operation.
  847. PortNumber - Supplies the port number in I/O space to read from.
  848. Return Value:
  849. The value read from I/O space is returned as the function value.
  850. N.B. If an aligned operation is specified, then the individual
  851. bytes are read from the specified port one at a time and
  852. assembled into the specified datatype.
  853. --*/
  854. {
  855. ULONG Result;
  856. PCI_SLOT_NUMBER Slot;
  857. //
  858. // We assume that DataType is the number of bytes - 1. If this ever changes
  859. // then this routine needs to be rewritten.
  860. //
  861. C_ASSERT(BYTE_DATA == 0);
  862. C_ASSERT(WORD_DATA == 1);
  863. C_ASSERT(LONG_DATA == 3);
  864. //
  865. // Make sure they aren't trying to read past the end of the register, we'll
  866. // ignore any extra bytes.
  867. //
  868. if ((PortNumber + DataType) > 3) {
  869. ASSERT(0);
  870. DataType = 3 - PortNumber;
  871. }
  872. //
  873. // Unpack the Slot/Function information
  874. //
  875. Slot.u.AsULONG = 0;
  876. Slot.u.bits.DeviceNumber = (XmPCIConfigAddress >> 11) & 0x1F;
  877. Slot.u.bits.FunctionNumber = (XmPCIConfigAddress >> 8) & 0x07;
  878. if (XmGetPciData((XmPCIConfigAddress >> 16) & 0xFF, // Bus Number
  879. Slot.u.AsULONG, // Device, Function
  880. &Result,
  881. (XmPCIConfigAddress & 0xFF) | PortNumber, // Offset
  882. DataType + 1 // Length
  883. ) == 0)
  884. {
  885. Result = (ULONG)(1 << ((DataType + 1) << 3)) - 1;
  886. }
  887. return Result;
  888. }
  889. VOID
  890. x86BiosWritePciDataPort(
  891. IN XM_OPERATION_DATATYPE DataType,
  892. IN USHORT PortNumber,
  893. IN ULONG Value
  894. )
  895. /*++
  896. Routine Description:
  897. This function write to emulated I/O space.
  898. N.B. If an aligned operation is specified, then the individual
  899. bytes are written to the specified port one at a time.
  900. Arguments:
  901. DataType - Supplies the datatype for the write operation.
  902. PortNumber - Supplies the port number in I/O space to write to.
  903. Value - Supplies the value to write.
  904. Return Value:
  905. None.
  906. --*/
  907. {
  908. PCI_SLOT_NUMBER Slot;
  909. //
  910. // We assume that DataType is the number of bytes - 1. If this ever changes
  911. // then this routine needs to be rewritten.
  912. //
  913. C_ASSERT(BYTE_DATA == 0);
  914. C_ASSERT(WORD_DATA == 1);
  915. C_ASSERT(LONG_DATA == 3);
  916. //
  917. // Make sure they aren't trying to write past the end of the register, we'll
  918. // ignore any extra bytes.
  919. //
  920. if ((PortNumber + DataType) > 3) {
  921. ASSERT(0);
  922. DataType = 3 - PortNumber;
  923. }
  924. //
  925. // Unpack the Slot/Function information
  926. //
  927. Slot.u.AsULONG = 0;
  928. Slot.u.bits.DeviceNumber = (XmPCIConfigAddress >> 11) & 0x1F;
  929. Slot.u.bits.FunctionNumber = (XmPCIConfigAddress >> 8) & 0x07;
  930. if (XmSetPciData((XmPCIConfigAddress >> 16) & 0xFF, // Bus Number
  931. Slot.u.AsULONG, // Device, Function
  932. &Value,
  933. (XmPCIConfigAddress & 0xFF) | PortNumber, // Offset
  934. DataType + 1 // Length
  935. ) == 0)
  936. {
  937. ASSERT(0);
  938. }
  939. }