Source code of Windows XP (NT5)
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.

908 lines
19 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. //
  19. // Define the size of low memory.
  20. //
  21. #define LOW_MEMORY_SIZE 0x800
  22. //
  23. // Define storage for low emulated memory.
  24. //
  25. UCHAR x86BiosLowMemory[LOW_MEMORY_SIZE + 3];
  26. ULONG x86BiosScratchMemory;
  27. //
  28. // Define storage to capture the base address of I/O space, the base address
  29. // of I/O memory space, and the base address of the video frame buffer.
  30. //
  31. ULONG_PTR x86BiosFrameBuffer;
  32. ULONG_PTR x86BiosIoMemory;
  33. ULONG_PTR x86BiosIoSpace;
  34. //
  35. // Define an area of storage to allow for buffer passing between the BIOS
  36. // and native mode code.
  37. //
  38. ULONG_PTR x86BiosTransferMemory = 0;
  39. ULONG x86BiosTransferLength = 0;
  40. //
  41. // Define BIOS initialized state.
  42. //
  43. BOOLEAN x86BiosInitialized = FALSE;
  44. //
  45. // Define storage for PCI BIOS initialization state.
  46. //
  47. UCHAR XmNumberPciBusses = 0;
  48. BOOLEAN XmPciBiosPresent = FALSE;
  49. PGETSETPCIBUSDATA XmGetPciData;
  50. PGETSETPCIBUSDATA XmSetPciData;
  51. ULONG
  52. x86BiosReadIoSpace (
  53. IN XM_OPERATION_DATATYPE DataType,
  54. IN USHORT PortNumber
  55. )
  56. /*++
  57. Routine Description:
  58. This function reads from emulated I/O space.
  59. Arguments:
  60. DataType - Supplies the datatype for the read operation.
  61. PortNumber - Supplies the port number in I/O space to read from.
  62. Return Value:
  63. The value read from I/O space is returned as the function value.
  64. N.B. If an aligned operation is specified, then the individual
  65. bytes are read from the specified port one at a time and
  66. assembled into the specified datatype.
  67. --*/
  68. {
  69. ULONG Result;
  70. union {
  71. PUCHAR Byte;
  72. PUSHORT Word;
  73. PULONG Long;
  74. } u;
  75. //
  76. // Compute port address and read port.
  77. //
  78. u.Long = (PULONG)(x86BiosIoSpace + PortNumber);
  79. if (DataType == BYTE_DATA) {
  80. Result = READ_PORT_UCHAR(u.Byte);
  81. } else if (DataType == LONG_DATA) {
  82. if (((ULONG_PTR)u.Long & 0x3) != 0) {
  83. Result = (READ_PORT_UCHAR(u.Byte + 0)) |
  84. (READ_PORT_UCHAR(u.Byte + 1) << 8) |
  85. (READ_PORT_UCHAR(u.Byte + 2) << 16) |
  86. (READ_PORT_UCHAR(u.Byte + 3) << 24);
  87. } else {
  88. Result = READ_PORT_ULONG(u.Long);
  89. }
  90. } else {
  91. if (((ULONG_PTR)u.Word & 0x1) != 0) {
  92. Result = (READ_PORT_UCHAR(u.Byte + 0)) |
  93. (READ_PORT_UCHAR(u.Byte + 1) << 8);
  94. } else {
  95. Result = READ_PORT_USHORT(u.Word);
  96. }
  97. }
  98. return Result;
  99. }
  100. VOID
  101. x86BiosWriteIoSpace (
  102. IN XM_OPERATION_DATATYPE DataType,
  103. IN USHORT PortNumber,
  104. IN ULONG Value
  105. )
  106. /*++
  107. Routine Description:
  108. This function write to emulated I/O space.
  109. N.B. If an aligned operation is specified, then the individual
  110. bytes are written to the specified port one at a time.
  111. Arguments:
  112. DataType - Supplies the datatype for the write operation.
  113. PortNumber - Supplies the port number in I/O space to write to.
  114. Value - Supplies the value to write.
  115. Return Value:
  116. None.
  117. --*/
  118. {
  119. union {
  120. PUCHAR Byte;
  121. PUSHORT Word;
  122. PULONG Long;
  123. } u;
  124. //
  125. // Compute port address and read port.
  126. //
  127. u.Long = (PULONG)(x86BiosIoSpace + PortNumber);
  128. if (DataType == BYTE_DATA) {
  129. WRITE_PORT_UCHAR(u.Byte, (UCHAR)Value);
  130. } else if (DataType == LONG_DATA) {
  131. if (((ULONG_PTR)u.Long & 0x3) != 0) {
  132. WRITE_PORT_UCHAR(u.Byte + 0, (UCHAR)(Value));
  133. WRITE_PORT_UCHAR(u.Byte + 1, (UCHAR)(Value >> 8));
  134. WRITE_PORT_UCHAR(u.Byte + 2, (UCHAR)(Value >> 16));
  135. WRITE_PORT_UCHAR(u.Byte + 3, (UCHAR)(Value >> 24));
  136. } else {
  137. WRITE_PORT_ULONG(u.Long, Value);
  138. }
  139. } else {
  140. if (((ULONG_PTR)u.Word & 0x1) != 0) {
  141. WRITE_PORT_UCHAR(u.Byte + 0, (UCHAR)(Value));
  142. WRITE_PORT_UCHAR(u.Byte + 1, (UCHAR)(Value >> 8));
  143. } else {
  144. WRITE_PORT_USHORT(u.Word, (USHORT)Value);
  145. }
  146. }
  147. return;
  148. }
  149. PVOID
  150. x86BiosTranslateAddress (
  151. IN USHORT Segment,
  152. IN USHORT Offset
  153. )
  154. /*++
  155. Routine Description:
  156. This translates a segment/offset address into a memory address.
  157. Arguments:
  158. Segment - Supplies the segment register value.
  159. Offset - Supplies the offset within segment.
  160. Return Value:
  161. The memory address of the translated segment/offset pair is
  162. returned as the function value.
  163. --*/
  164. {
  165. ULONG Value;
  166. //
  167. // Compute the logical memory address and case on high hex digit of
  168. // the resultant address.
  169. //
  170. Value = Offset + (Segment << 4);
  171. Offset = (USHORT)(Value & 0xffff);
  172. Value &= 0xf0000;
  173. switch ((Value >> 16) & 0xf) {
  174. //
  175. // Interrupt vector/stack space.
  176. //
  177. case 0x0:
  178. if (Offset > LOW_MEMORY_SIZE) {
  179. x86BiosScratchMemory = 0;
  180. return (PVOID)&x86BiosScratchMemory;
  181. } else {
  182. return (PVOID)(&x86BiosLowMemory[0] + Offset);
  183. }
  184. //
  185. // The memory range from 0x10000 to 0x8ffff reads as zero
  186. // and writes are ignored.
  187. //
  188. case 0x1:
  189. case 0x3:
  190. case 0x4:
  191. case 0x5:
  192. case 0x6:
  193. case 0x7:
  194. case 0x8:
  195. x86BiosScratchMemory = 0;
  196. return (PVOID)&x86BiosScratchMemory;
  197. case 0x9:
  198. //
  199. // BUGBUG: Found a VGA adapter loaded in segment 9
  200. // Emulator assumptions about video adapters needs to be
  201. // looked at
  202. //
  203. return (PVOID)(x86BiosIoMemory + Offset + Value);
  204. //
  205. // The memory range from 0x20000 to 0x20fff is used to transfer
  206. // buffers between native mode and emulated mode.
  207. //
  208. case 0x2:
  209. if (Offset < x86BiosTransferLength) {
  210. return (PVOID)(x86BiosTransferMemory + Offset);
  211. } else {
  212. x86BiosScratchMemory = 0;
  213. return (PVOID)&x86BiosScratchMemory;
  214. }
  215. //
  216. // The memory range from 0xa0000 to 0xbffff maps to the
  217. // framebuffer if previously specified, otherwise I/O memory.
  218. //
  219. case 0xa:
  220. case 0xb:
  221. if (x86BiosFrameBuffer != 0) {
  222. return (PVOID)(x86BiosFrameBuffer + Offset + Value);
  223. }
  224. //
  225. // The memory range from 0xc0000 to 0xfffff maps to I/O memory
  226. //
  227. case 0xc:
  228. case 0xd:
  229. case 0xe:
  230. case 0xf:
  231. return (PVOID)(x86BiosIoMemory + Offset + Value);
  232. DEFAULT_UNREACHABLE;
  233. }
  234. }
  235. VOID
  236. x86BiosInitializeBios (
  237. IN PVOID BiosIoSpace,
  238. IN PVOID BiosIoMemory
  239. )
  240. /*++
  241. Routine Description:
  242. This function initializes x86 BIOS emulation.
  243. Arguments:
  244. BiosIoSpace - Supplies the base address of the I/O space to be used
  245. for BIOS emulation.
  246. BiosIoMemory - Supplies the base address of the I/O memory to be
  247. used for BIOS emulation.
  248. Return Value:
  249. None.
  250. --*/
  251. {
  252. //
  253. // Initialize x86 BIOS emulation.
  254. //
  255. x86BiosInitializeBiosShadowed(BiosIoSpace,
  256. BiosIoMemory,
  257. NULL);
  258. return;
  259. }
  260. VOID
  261. x86BiosInitializeBiosEx (
  262. IN PVOID BiosIoSpace,
  263. IN PVOID BiosIoMemory,
  264. IN PVOID BiosTransferMemory,
  265. IN ULONG TransferLength
  266. )
  267. /*++
  268. Routine Description:
  269. This function initializes x86 BIOS emulation.
  270. Arguments:
  271. BiosIoSpace - Supplies the base address of the I/O space to be used
  272. for BIOS emulation.
  273. BiosIoMemory - Supplies the base address of the I/O memory to be
  274. used for BIOS emulation.
  275. Return Value:
  276. None.
  277. --*/
  278. {
  279. //
  280. // Initialize x86 BIOS emulation.
  281. //
  282. x86BiosInitializeBiosShadowed(BiosIoSpace,
  283. BiosIoMemory,
  284. NULL);
  285. x86BiosTransferMemory = (ULONG_PTR)BiosTransferMemory;
  286. x86BiosTransferLength = TransferLength;
  287. return;
  288. }
  289. VOID
  290. x86BiosInitializeBiosShadowed (
  291. IN PVOID BiosIoSpace,
  292. IN PVOID BiosIoMemory,
  293. IN PVOID BiosFrameBuffer
  294. )
  295. /*++
  296. Routine Description:
  297. This function initializes x86 BIOS emulation.
  298. Arguments:
  299. BiosIoSpace - Supplies the base address of the I/O space to be used
  300. for BIOS emulation.
  301. BiosIoMemory - Supplies the base address of the I/O memory to be
  302. used for BIOS emulation.
  303. BiosFrameBuffer - Supplies the base address of the video frame buffer
  304. to be used for bios emulation.
  305. Return Value:
  306. None.
  307. --*/
  308. {
  309. //
  310. // Zero low memory.
  311. //
  312. memset(&x86BiosLowMemory, 0, LOW_MEMORY_SIZE);
  313. //
  314. // Save base address of I/O memory and I/O space.
  315. //
  316. x86BiosIoSpace = (ULONG_PTR)BiosIoSpace;
  317. x86BiosIoMemory = (ULONG_PTR)BiosIoMemory;
  318. x86BiosFrameBuffer = (ULONG_PTR)BiosFrameBuffer;
  319. //
  320. // Initialize the emulator and the BIOS.
  321. //
  322. XmInitializeEmulator(0,
  323. LOW_MEMORY_SIZE,
  324. x86BiosReadIoSpace,
  325. x86BiosWriteIoSpace,
  326. x86BiosTranslateAddress);
  327. x86BiosInitialized = TRUE;
  328. return;
  329. }
  330. VOID
  331. x86BiosInitializeBiosShadowedPci (
  332. IN PVOID BiosIoSpace,
  333. IN PVOID BiosIoMemory,
  334. IN PVOID BiosFrameBuffer,
  335. IN UCHAR NumberPciBusses,
  336. IN PGETSETPCIBUSDATA GetPciData,
  337. IN PGETSETPCIBUSDATA SetPciData
  338. )
  339. /*++
  340. Routine Description:
  341. This function initializes x86 BIOS emulation and also sets up the
  342. emulator with BIOS shadowed and PCI functions enabled. Since the
  343. PCI specification requires BIOS shadowing, there isn't any need
  344. to provide a function that turns on the PCI functions, but doesn't
  345. shadow the BIOS.
  346. Arguments:
  347. BiosIoSpace - Supplies the base address of the I/O space to be used
  348. for BIOS emulation.
  349. BiosIoMemory - Supplies the base address of the I/O memory to be
  350. used for BIOS emulation.
  351. BiosFrameBuffer - Supplies the base address of the video frame buffer
  352. to be used for bios emulation.
  353. NumberPciBusses - Supplies the number of PCI busses in the system.
  354. GetPciData - Supplies the address of a function to read the PCI
  355. configuration space.
  356. SetPciData - Supplies the address of a function to write the PCI
  357. configuration space.
  358. Return Value:
  359. None.
  360. --*/
  361. {
  362. //
  363. // Enable PCI BIOS support.
  364. //
  365. XmPciBiosPresent = TRUE;
  366. XmGetPciData = GetPciData;
  367. XmSetPciData = SetPciData;
  368. XmNumberPciBusses = NumberPciBusses;
  369. //
  370. // Initialize x86 BIOS emulation.
  371. //
  372. x86BiosInitializeBiosShadowed(BiosIoSpace,
  373. BiosIoMemory,
  374. BiosFrameBuffer);
  375. return;
  376. }
  377. XM_STATUS
  378. x86BiosExecuteInterrupt (
  379. IN UCHAR Number,
  380. IN OUT PXM86_CONTEXT Context,
  381. IN PVOID BiosIoSpace OPTIONAL,
  382. IN PVOID BiosIoMemory OPTIONAL
  383. )
  384. /*++
  385. Routine Description:
  386. This function executes an interrupt by calling the x86 emulator.
  387. Arguments:
  388. Number - Supplies the number of the interrupt that is to be emulated.
  389. Context - Supplies a pointer to an x86 context structure.
  390. BiosIoSpace - Supplies an optional base address of the I/O space
  391. to be used for BIOS emulation.
  392. BiosIoMemory - Supplies an optional base address of the I/O memory
  393. to be used for BIOS emulation.
  394. Return Value:
  395. The emulation completion status.
  396. --*/
  397. {
  398. //
  399. // Execute x86 interrupt.
  400. //
  401. return x86BiosExecuteInterruptShadowed(Number,
  402. Context,
  403. BiosIoSpace,
  404. BiosIoMemory,
  405. NULL);
  406. }
  407. XM_STATUS
  408. x86BiosExecuteInterruptShadowed (
  409. IN UCHAR Number,
  410. IN OUT PXM86_CONTEXT Context,
  411. IN PVOID BiosIoSpace OPTIONAL,
  412. IN PVOID BiosIoMemory OPTIONAL,
  413. IN PVOID BiosFrameBuffer OPTIONAL
  414. )
  415. /*++
  416. Routine Description:
  417. This function executes an interrupt by calling the x86 emulator.
  418. Arguments:
  419. Number - Supplies the number of the interrupt that is to be emulated.
  420. Context - Supplies a pointer to an x86 context structure.
  421. BiosIoSpace - Supplies an optional base address of the I/O space
  422. to be used for BIOS emulation.
  423. BiosIoMemory - Supplies an optional base address of the I/O memory
  424. to be used for BIOS emulation.
  425. BiosFrameBuffer - Supplies an optional base address of the video
  426. frame buffer to be used for bios emulation.
  427. Return Value:
  428. The emulation completion status.
  429. --*/
  430. {
  431. XM_STATUS Status;
  432. //
  433. // If a new base address is specified, then set the appropriate base.
  434. //
  435. if (BiosIoSpace != NULL) {
  436. x86BiosIoSpace = (ULONG_PTR)BiosIoSpace;
  437. }
  438. if (BiosIoMemory != NULL) {
  439. x86BiosIoMemory = (ULONG_PTR)BiosIoMemory;
  440. }
  441. if (BiosFrameBuffer != NULL) {
  442. x86BiosFrameBuffer = (ULONG_PTR)BiosFrameBuffer;
  443. }
  444. //
  445. // Execute the specified interrupt.
  446. //
  447. Status = XmEmulateInterrupt(Number, Context);
  448. if (Status != XM_SUCCESS) {
  449. DbgPrint("HAL: Interrupt emulation failed, status %lx\n", Status);
  450. }
  451. return Status;
  452. }
  453. XM_STATUS
  454. x86BiosExecuteInterruptShadowedPci (
  455. IN UCHAR Number,
  456. IN OUT PXM86_CONTEXT Context,
  457. IN PVOID BiosIoSpace OPTIONAL,
  458. IN PVOID BiosIoMemory OPTIONAL,
  459. IN PVOID BiosFrameBuffer OPTIONAL,
  460. IN UCHAR NumberPciBusses,
  461. IN PGETSETPCIBUSDATA GetPciData,
  462. IN PGETSETPCIBUSDATA SetPciData
  463. )
  464. /*++
  465. Routine Description:
  466. This function executes an interrupt by calling the x86 emulator.
  467. Arguments:
  468. Number - Supplies the number of the interrupt that is to be emulated.
  469. Context - Supplies a pointer to an x86 context structure.
  470. BiosIoSpace - Supplies an optional base address of the I/O space
  471. to be used for BIOS emulation.
  472. BiosIoMemory - Supplies an optional base address of the I/O memory
  473. to be used for BIOS emulation.
  474. NumberPciBusses - Supplies the number of PCI busses in the system.
  475. GetPciData - Supplies the address of a function to read the PCI
  476. configuration space.
  477. SetPciData - Supplies the address of a function to write the PCI
  478. configuration space.
  479. Return Value:
  480. The emulation completion status.
  481. --*/
  482. {
  483. //
  484. // Enable PCI BIOS support.
  485. //
  486. XmPciBiosPresent = TRUE;
  487. XmGetPciData = GetPciData;
  488. XmSetPciData = SetPciData;
  489. XmNumberPciBusses = NumberPciBusses;
  490. //
  491. // Execute x86 interrupt.
  492. //
  493. return x86BiosExecuteInterruptShadowed(Number,
  494. Context,
  495. BiosIoSpace,
  496. BiosIoMemory,
  497. BiosFrameBuffer);
  498. }
  499. XM_STATUS
  500. x86BiosInitializeAdapter(
  501. IN ULONG Adapter,
  502. IN OUT PXM86_CONTEXT Context OPTIONAL,
  503. IN PVOID BiosIoSpace OPTIONAL,
  504. IN PVOID BiosIoMemory OPTIONAL
  505. )
  506. /*++
  507. Routine Description:
  508. This function initializes the adapter whose BIOS starts at the
  509. specified 20-bit address.
  510. Arguments:
  511. Adpater - Supplies the 20-bit address of the BIOS for the adapter
  512. to be initialized.
  513. Return Value:
  514. The emulation completion status.
  515. --*/
  516. {
  517. //
  518. // Initialize the specified adapter.
  519. //
  520. return x86BiosInitializeAdapterShadowed(Adapter,
  521. Context,
  522. BiosIoSpace,
  523. BiosIoMemory,
  524. NULL);
  525. }
  526. XM_STATUS
  527. x86BiosInitializeAdapterShadowed (
  528. IN ULONG Adapter,
  529. IN OUT PXM86_CONTEXT Context OPTIONAL,
  530. IN PVOID BiosIoSpace OPTIONAL,
  531. IN PVOID BiosIoMemory OPTIONAL,
  532. IN PVOID BiosFrameBuffer OPTIONAL
  533. )
  534. /*++
  535. Routine Description:
  536. This function initializes the adapter whose BIOS starts at the
  537. specified 20-bit address.
  538. Arguments:
  539. Adpater - Supplies the 20-bit address of the BIOS for the adapter
  540. to be initialized.
  541. Return Value:
  542. The emulation completion status.
  543. --*/
  544. {
  545. PUCHAR Byte;
  546. XM86_CONTEXT State;
  547. USHORT Offset;
  548. USHORT Segment;
  549. XM_STATUS Status;
  550. //
  551. // If BIOS emulation has not been initialized, then return an error.
  552. //
  553. if (x86BiosInitialized == FALSE) {
  554. return XM_EMULATOR_NOT_INITIALIZED;
  555. }
  556. //
  557. // If an emulator context is not specified, then use a default
  558. // context.
  559. //
  560. if (ARGUMENT_PRESENT(Context) == FALSE) {
  561. State.Eax = 0;
  562. State.Ecx = 0;
  563. State.Edx = 0;
  564. State.Ebx = 0;
  565. State.Ebp = 0;
  566. State.Esi = 0;
  567. State.Edi = 0;
  568. Context = &State;
  569. }
  570. //
  571. // If a new base address is specified, then set the appropriate base.
  572. //
  573. if (BiosIoSpace != NULL) {
  574. x86BiosIoSpace = (ULONG_PTR)BiosIoSpace;
  575. }
  576. if (BiosIoMemory != NULL) {
  577. x86BiosIoMemory = (ULONG_PTR)BiosIoMemory;
  578. }
  579. if (BiosFrameBuffer != NULL) {
  580. x86BiosFrameBuffer = (ULONG_PTR)BiosFrameBuffer;
  581. }
  582. //
  583. // If the specified adpater is not BIOS code, then return an error.
  584. //
  585. Segment = (USHORT)((Adapter >> 4) & 0xf000);
  586. Offset = (USHORT)(Adapter & 0xffff);
  587. Byte = (PUCHAR)x86BiosTranslateAddress(Segment, Offset);
  588. if ((*Byte++ != 0x55) || (*Byte != 0xaa)) {
  589. return XM_ILLEGAL_CODE_SEGMENT;
  590. }
  591. //
  592. // Call the BIOS code to initialize the specified adapter.
  593. //
  594. Adapter += 3;
  595. Segment = (USHORT)((Adapter >> 4) & 0xf000);
  596. Offset = (USHORT)(Adapter & 0xffff);
  597. Status = XmEmulateFarCall(Segment, Offset, Context);
  598. if (Status != XM_SUCCESS) {
  599. DbgPrint("HAL: Adapter initialization falied, status %lx\n", Status);
  600. }
  601. return Status;
  602. }
  603. XM_STATUS
  604. x86BiosInitializeAdapterShadowedPci(
  605. IN ULONG Adapter,
  606. IN OUT PXM86_CONTEXT Context OPTIONAL,
  607. IN PVOID BiosIoSpace OPTIONAL,
  608. IN PVOID BiosIoMemory OPTIONAL,
  609. IN PVOID BiosFrameBuffer OPTIONAL,
  610. IN UCHAR NumberPciBusses,
  611. IN PGETSETPCIBUSDATA GetPciData,
  612. IN PGETSETPCIBUSDATA SetPciData
  613. )
  614. /*++
  615. Routine Description:
  616. This function initializes the adapter whose BIOS starts at the
  617. specified 20-bit address.
  618. Arguments:
  619. Adpater - Supplies the 20-bit address of the BIOS for the adapter
  620. to be initialized.
  621. Return Value:
  622. The emulation completion status.
  623. --*/
  624. {
  625. //
  626. // Enable PCI BIOS support.
  627. //
  628. XmPciBiosPresent = TRUE;
  629. XmGetPciData = GetPciData;
  630. XmSetPciData = SetPciData;
  631. XmNumberPciBusses = NumberPciBusses;
  632. //
  633. // Initialize the specified adapter.
  634. //
  635. return x86BiosInitializeAdapterShadowed(Adapter,
  636. Context,
  637. BiosIoSpace,
  638. BiosIoMemory,
  639. BiosFrameBuffer);
  640. }