Windows NT 4.0 source code leak
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.

837 lines
17 KiB

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