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.

618 lines
14 KiB

  1. /*++
  2. Module Name:
  3. pcibios.c
  4. Abstract:
  5. This module implements the INT 1a functions of the
  6. PCI BIOS Specification revision 2.1, which makes
  7. it possible to support video BIOSes that expect
  8. to be able to read and write PCI configuration
  9. space.
  10. In order to read and write to PCI configuration
  11. space, this code needs to call functions in the
  12. HAL that know how configuration space is
  13. implemented in the specific machine. There are
  14. standard functions exported by the HAL to do
  15. this, but they aren't usually available (i.e.
  16. the bus handler code hasn't been set up yet) by
  17. the time that the video needs to be initialized.
  18. So the PCI BIOS functions in the emulator make
  19. calls to XmGetPciData and XmSetPciData, which
  20. are pointers to functions passed into the
  21. emulator by the HAL. It is the responsibility of
  22. the calling code to provide functions which match
  23. these prototypes.
  24. Author:
  25. Jake Oshins (joshins@vnet.ibm.com) 3-15-96
  26. Environment:
  27. Kernel mode only.
  28. Revision History:
  29. --*/
  30. #include "nthal.h"
  31. #include "emulate.h"
  32. #include "pci.h"
  33. BOOLEAN
  34. XmExecuteInt1a (
  35. IN OUT PRXM_CONTEXT Context
  36. )
  37. /*++
  38. Routine Description:
  39. The function calls the specific worker functions
  40. based upon the contents of the registers in Context.
  41. Arguments:
  42. Context - State of the emulator
  43. Return Value:
  44. None.
  45. --*/
  46. {
  47. //
  48. // If we aren't emulating PCI BIOS,
  49. // return.
  50. if (!XmPciBiosPresent) {
  51. return FALSE;
  52. }
  53. //
  54. // If this is not a call to PCI BIOS,
  55. // ignore it.
  56. //
  57. if (Context->Gpr[EAX].Xh != PCI_FUNCTION_ID) {
  58. return FALSE;
  59. }
  60. //
  61. // Switch on AL to see which PCI BIOS function
  62. // has been requested.
  63. //
  64. switch (Context->Gpr[EAX].Xl) {
  65. case PCI_BIOS_PRESENT:
  66. XmInt1aPciBiosPresent(Context);
  67. break;
  68. case PCI_FIND_DEVICE:
  69. XmInt1aFindPciDevice(Context);
  70. break;
  71. case PCI_FIND_CLASS_CODE:
  72. XmInt1aFindPciClassCode(Context);
  73. break;
  74. case PCI_GENERATE_CYCLE:
  75. XmInt1aGenerateSpecialCycle(Context);
  76. break;
  77. case PCI_GET_IRQ_ROUTING:
  78. XmInt1aGetRoutingOptions(Context);
  79. break;
  80. case PCI_SET_IRQ:
  81. XmInt1aSetPciIrq(Context);
  82. break;
  83. case PCI_READ_CONFIG_BYTE:
  84. case PCI_READ_CONFIG_WORD:
  85. case PCI_READ_CONFIG_DWORD:
  86. XmInt1aReadConfigRegister(Context);
  87. break;
  88. case PCI_WRITE_CONFIG_BYTE:
  89. case PCI_WRITE_CONFIG_WORD:
  90. case PCI_WRITE_CONFIG_DWORD:
  91. XmInt1aWriteConfigRegister(Context);
  92. break;
  93. default:
  94. return FALSE;
  95. }
  96. return TRUE;
  97. }
  98. VOID
  99. XmInt1aPciBiosPresent(
  100. IN OUT PRXM_CONTEXT Context
  101. )
  102. /*++
  103. Routine Description:
  104. This function implements PCI_BIOS_PRESENT.
  105. Arguments:
  106. Context - State of the emulator
  107. Return Value:
  108. None.
  109. --*/
  110. {
  111. Context->Gpr[EDX].Exx = *(PULONG)(&"PCI ");
  112. // Present status is good:
  113. Context->Gpr[EAX].Xh = 0x0;
  114. // Hardware mechanism is:
  115. // Standard config mechanisms not supported,
  116. // Special cycles not supported
  117. // i.e. We want all accesses to be done through software
  118. Context->Gpr[EAX].Xl = 0x0;
  119. // Interface level major version
  120. Context->Gpr[EBX].Xh = 0x2;
  121. // Interface level minor version
  122. Context->Gpr[EBX].Xl = 0x10;
  123. // Number of last PCI bus in system
  124. Context->Gpr[ECX].Xl = XmNumberPciBusses;
  125. // Present status good:
  126. Context->Eflags.EFLAG_CF = 0x0;
  127. }
  128. VOID
  129. XmInt1aFindPciDevice(
  130. IN OUT PRXM_CONTEXT Context
  131. )
  132. /*++
  133. Routine Description:
  134. This function implements FIND_PCI_DEVICE.
  135. Arguments:
  136. Context - State of the emulator
  137. [AH] PCI_FUNCTION_ID
  138. [AL] FIND_PCI_DEVICE
  139. [CX] Device ID (0...65535)
  140. [DX] Vendor ID (0...65534)
  141. [SI] Index (0..N)
  142. Return Value:
  143. [BH] Bus Number
  144. [BL] Device Number, Function Number
  145. [AH] return code
  146. [CF] completion status
  147. --*/
  148. {
  149. UCHAR Bus;
  150. PCI_SLOT_NUMBER Slot;
  151. ULONG Device;
  152. ULONG Function;
  153. ULONG Index = 0;
  154. ULONG buffer;
  155. if (Context->Gpr[EAX].Xx == PCI_ILLEGAL_VENDOR_ID) {
  156. Context->Gpr[EAX].Xh = PCI_BAD_VENDOR_ID;
  157. Context->Eflags.EFLAG_CF = 1;
  158. return;
  159. }
  160. Slot.u.AsULONG = 0;
  161. for (Bus = 0; Bus < XmNumberPciBusses; Bus++) {
  162. for (Device = 0; Device < 32; Device++) {
  163. for (Function = 0; Function < 8; Function++) {
  164. Slot.u.bits.DeviceNumber = Device;
  165. Slot.u.bits.FunctionNumber = Function;
  166. if (4 != XmGetPciData(Bus,
  167. Slot.u.AsULONG,
  168. &buffer,
  169. 0, //offset of vendor ID
  170. 4)) {
  171. buffer = 0xffffffff;
  172. }
  173. //
  174. // Did we find the right one?
  175. //
  176. if (((buffer & 0xffff) == Context->Gpr[EDX].Xx) &&
  177. (((buffer >> 16) & 0xffff) == Context->Gpr[ECX].Xx)) {
  178. //
  179. // Did we find the right occurrence?
  180. //
  181. if (Index++ == Context->Gpr[ESI].Xx) {
  182. Context->Gpr[EBX].Xh = Bus;
  183. Context->Gpr[EBX].Xl = (UCHAR)((Device << 3) | Function);
  184. Context->Gpr[EAX].Xh = PCI_SUCCESS;
  185. Context->Eflags.EFLAG_CF = 0;
  186. return;
  187. }
  188. }
  189. }
  190. }
  191. }
  192. Context->Gpr[EAX].Xh = PCI_DEVICE_NOT_FOUND;
  193. Context->Eflags.EFLAG_CF = 1;
  194. }
  195. VOID
  196. XmInt1aFindPciClassCode(
  197. IN OUT PRXM_CONTEXT Context
  198. )
  199. /*++
  200. Routine Description:
  201. This function implements FIND_PCI_CLASS_CODE.
  202. Arguments:
  203. Context - State of the emulator
  204. [AH] PCI_FUNCTION_ID
  205. [AL] FIND_PCI_CLASS_CODE
  206. [ECX] Class Code (in lower three bytes)
  207. [SI] Index (0..N)
  208. Return Value:
  209. [BH] Bus Number
  210. [BL] Device Number, Function Number
  211. [AH] return code
  212. [CF] completion status
  213. --*/
  214. {
  215. UCHAR Bus;
  216. PCI_SLOT_NUMBER Slot;
  217. ULONG Index = 0;
  218. ULONG class_code;
  219. ULONG Device;
  220. ULONG Function;
  221. Slot.u.AsULONG = 0;
  222. for (Bus = 0; Bus < XmNumberPciBusses; Bus++) {
  223. for (Device = 0; Device < 32; Device++) {
  224. for (Function = 0; Function < 8; Function++) {
  225. Slot.u.bits.DeviceNumber = Device;
  226. Slot.u.bits.FunctionNumber = Function;
  227. if (4 != XmGetPciData(Bus,
  228. Slot.u.AsULONG,
  229. &class_code,
  230. 8, //offset of vendor ID
  231. 4)) {
  232. class_code = 0xffffffff;
  233. }
  234. class_code >>= 8;
  235. //
  236. // Did we find the right one?
  237. //
  238. if (class_code == (Context->Gpr[ECX].Exx & 0xFFFFFF)) {
  239. //
  240. // Did we find the right occurrence?
  241. //
  242. if (Index++ == Context->Gpr[ESI].Xx) {
  243. Context->Gpr[EBX].Xh = Bus;
  244. Context->Gpr[EBX].Xl = (UCHAR)((Device << 3) | (Function));
  245. Context->Gpr[EAX].Xh = PCI_SUCCESS;
  246. Context->Eflags.EFLAG_CF = 0;
  247. return;
  248. }
  249. }
  250. }
  251. }
  252. }
  253. Context->Gpr[EAX].Xh = PCI_DEVICE_NOT_FOUND;
  254. Context->Eflags.EFLAG_CF = 1;
  255. }
  256. VOID
  257. XmInt1aGenerateSpecialCycle(
  258. IN OUT PRXM_CONTEXT Context
  259. )
  260. /*++
  261. Routine Description:
  262. This function implements GENERATE_SPECIAL_CYCLE. Since
  263. there is no uniform way to support special cycles from
  264. the NT HAL, we won't support this function.
  265. Arguments:
  266. Context - State of the emulator
  267. Return Value:
  268. [AH] PCI_NOT_SUPPORTED
  269. --*/
  270. {
  271. Context->Gpr[EAX].Xh = PCI_NOT_SUPPORTED;
  272. Context->Eflags.EFLAG_CF = 1;
  273. }
  274. VOID
  275. XmInt1aGetRoutingOptions(
  276. IN OUT PRXM_CONTEXT Context
  277. )
  278. /*++
  279. Routine Description:
  280. This function implements GET_IRQ_ROUTING_OPTIONS. We
  281. won't allow devices to try to specify their own interrupt
  282. routing, partly because there isn't an easy way to do it,
  283. partly because this is done later by the HAL, and partly
  284. because almost no video devices generate interrupts.
  285. Arguments:
  286. Context - State of the emulator
  287. Return Value:
  288. [AH] PCI_NOT_SUPPORTED
  289. --*/
  290. {
  291. Context->Gpr[EAX].Xh = PCI_NOT_SUPPORTED;
  292. Context->Eflags.EFLAG_CF = 1;
  293. }
  294. VOID
  295. XmInt1aSetPciIrq(
  296. IN OUT PRXM_CONTEXT Context
  297. )
  298. /*++
  299. Routine Description:
  300. This function implements SET_PCI_IRQ. We
  301. won't allow devices to try to specify their own interrupt
  302. routing, partly because there isn't an easy way to do it,
  303. partly because this is done later by the HAL, and partly
  304. because almost no video devices generate interrupts.
  305. Arguments:
  306. Context - State of the emulator
  307. Return Value:
  308. [AH] PCI_NOT_SUPPORTED
  309. --*/
  310. {
  311. Context->Gpr[EAX].Xh = PCI_NOT_SUPPORTED;
  312. Context->Eflags.EFLAG_CF = 1;
  313. }
  314. VOID
  315. XmInt1aReadConfigRegister(
  316. IN OUT PRXM_CONTEXT Context
  317. )
  318. /*++
  319. Routine Description:
  320. This function implements READ_CONFIG_BYTE,
  321. READ_CONFIG_WORD and READ_CONFIG_DWORD.
  322. Arguments:
  323. Context - State of the emulator
  324. [AH] PCI_FUNCTION_ID
  325. [AL] function
  326. [BH] bus number
  327. [BL] device number/function number
  328. [DI] Register number
  329. Return Value:
  330. [ECX] data read
  331. [AH] return code
  332. [CF] completion status
  333. --*/
  334. {
  335. UCHAR length;
  336. PCI_SLOT_NUMBER Slot;
  337. ULONG buffer;
  338. //
  339. // First, make sure that the register number is valid.
  340. //
  341. if (((Context->Gpr[EAX].Xl == PCI_READ_CONFIG_WORD) &&
  342. (Context->Gpr[EBX].Xl % 2)) ||
  343. ((Context->Gpr[EAX].Xl == PCI_READ_CONFIG_DWORD) &&
  344. (Context->Gpr[EBX].Xl % 4))
  345. )
  346. {
  347. Context->Gpr[EAX].Xh = PCI_BAD_REGISTER;
  348. Context->Eflags.EFLAG_CF = 1;
  349. }
  350. switch (Context->Gpr[EAX].Xl) {
  351. case PCI_READ_CONFIG_BYTE:
  352. length = 1;
  353. break;
  354. case PCI_READ_CONFIG_WORD:
  355. length = 2;
  356. break;
  357. case PCI_READ_CONFIG_DWORD:
  358. length = 4;
  359. }
  360. Slot.u.AsULONG = 0;
  361. Slot.u.bits.DeviceNumber = Context->Gpr[EBX].Xl >> 3;
  362. Slot.u.bits.FunctionNumber = Context->Gpr[EBX].Xl;
  363. if (XmGetPciData(Context->Gpr[EBX].Xh,
  364. Slot.u.AsULONG,
  365. &buffer,
  366. Context->Gpr[EDI].Xx,
  367. length
  368. ) == 0)
  369. {
  370. // This is the only error code supported by this function
  371. Context->Gpr[EAX].Xh = PCI_BAD_REGISTER;
  372. Context->Eflags.EFLAG_CF = 1;
  373. return;
  374. }
  375. switch (Context->Gpr[EAX].Xl) {
  376. case PCI_READ_CONFIG_BYTE:
  377. Context->Gpr[ECX].Xl = (UCHAR)(buffer & 0xff);
  378. break;
  379. case PCI_READ_CONFIG_WORD:
  380. Context->Gpr[ECX].Xx = (USHORT)(buffer & 0xffff);
  381. break;
  382. case PCI_READ_CONFIG_DWORD:
  383. Context->Gpr[ECX].Exx = buffer;
  384. }
  385. Context->Gpr[EAX].Xh = PCI_SUCCESS;
  386. Context->Eflags.EFLAG_CF = 0;
  387. }
  388. VOID
  389. XmInt1aWriteConfigRegister(
  390. IN OUT PRXM_CONTEXT Context
  391. )
  392. /*++
  393. Routine Description:
  394. This function implements WRITE_CONFIG_BYTE,
  395. WRITE_CONFIG_WORD and WRITE_CONFIG_DWORD.
  396. Arguments:
  397. Context - State of the emulator
  398. [AH] PCI_FUNCTION_ID
  399. [AL] function
  400. [BH] bus number
  401. [BL] device number/function number
  402. [DI] Register number
  403. Return Value:
  404. [ECX] data read
  405. [AH] return code
  406. [CF] completion status
  407. --*/
  408. {
  409. UCHAR length;
  410. PCI_SLOT_NUMBER Slot;
  411. ULONG buffer;
  412. //
  413. // First, make sure that the register number is valid.
  414. //
  415. if (((Context->Gpr[EAX].Xl == PCI_WRITE_CONFIG_WORD) &&
  416. (Context->Gpr[EBX].Xl % 2)) ||
  417. ((Context->Gpr[EAX].Xl == PCI_WRITE_CONFIG_DWORD) &&
  418. (Context->Gpr[EBX].Xl % 4))
  419. )
  420. {
  421. Context->Gpr[EAX].Xh = PCI_BAD_REGISTER;
  422. Context->Eflags.EFLAG_CF = 1;
  423. }
  424. //
  425. // Find out how many bytes to write
  426. //
  427. switch (Context->Gpr[EAX].Xl) {
  428. case PCI_WRITE_CONFIG_BYTE:
  429. length = 1;
  430. buffer = Context->Gpr[ECX].Xl;
  431. break;
  432. case PCI_WRITE_CONFIG_WORD:
  433. length = 2;
  434. buffer = Context->Gpr[ECX].Xx;
  435. break;
  436. case PCI_WRITE_CONFIG_DWORD:
  437. length = 4;
  438. buffer = Context->Gpr[ECX].Exx;
  439. }
  440. //
  441. // Unpack the Slot/Function information
  442. //
  443. Slot.u.AsULONG = 0;
  444. Slot.u.bits.DeviceNumber = Context->Gpr[EBX].Xl >> 3;
  445. Slot.u.bits.FunctionNumber = Context->Gpr[EBX].Xl;
  446. if (XmSetPciData(Context->Gpr[EBX].Xh,
  447. Slot.u.AsULONG,
  448. &buffer,
  449. Context->Gpr[EDI].Xx,
  450. length
  451. ) == 0)
  452. {
  453. Context->Gpr[EAX].Xh = PCI_SUCCESS;
  454. Context->Eflags.EFLAG_CF = 0;
  455. } else {
  456. // This is the only error code supported by this function
  457. Context->Gpr[EAX].Xh = PCI_BAD_REGISTER;
  458. Context->Eflags.EFLAG_CF = 1;
  459. }
  460. }