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.

1367 lines
33 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. apic.c
  5. Abstract:
  6. WinDbg Extension Api
  7. Author:
  8. Ken Reneris (kenr) 06-June-1994
  9. Environment:
  10. User Mode.
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. //#include "apic.h"
  15. //#include <ntapic.inc>
  16. #pragma hdrstop
  17. #define LU_SIZE 0x400
  18. #define LU_ID_REGISTER 0x00000020
  19. #define LU_VERS_REGISTER 0x00000030
  20. #define LU_TPR 0x00000080
  21. #define LU_APR 0x00000090
  22. #define LU_PPR 0x000000A0
  23. #define LU_EOI 0x000000B0
  24. #define LU_REMOTE_REGISTER 0x000000C0
  25. #define LU_DEST 0x000000D0
  26. #define LU_DEST_FORMAT 0x000000E0
  27. #define LU_SPURIOUS_VECTOR 0x000000F0
  28. #define LU_FAULT_VECTOR 0x00000370
  29. #define LU_ISR_0 0x00000100
  30. #define LU_TMR_0 0x00000180
  31. #define LU_IRR_0 0x00000200
  32. #define LU_ERROR_STATUS 0x00000280
  33. #define LU_INT_CMD_LOW 0x00000300
  34. #define LU_INT_CMD_HIGH 0x00000310
  35. #define LU_TIMER_VECTOR 0x00000320
  36. #define LU_INT_VECTOR_0 0x00000350
  37. #define LU_INT_VECTOR_1 0x00000360
  38. #define LU_INITIAL_COUNT 0x00000380
  39. #define LU_CURRENT_COUNT 0x00000390
  40. #define LU_DIVIDER_CONFIG 0x000003E0
  41. #define IO_REGISTER_SELECT 0x00000000
  42. #define IO_REGISTER_WINDOW 0x00000010
  43. #define IO_ID_REGISTER 0x00000000
  44. #define IO_VERS_REGISTER 0x00000001
  45. #define IO_ARB_ID_REGISTER 0x00000002
  46. #define IO_REDIR_BASE 0x00000010
  47. #define NMI_VECTOR 0xff
  48. #define DESTINATION_SHIFT 24
  49. BOOLEAN
  50. GetPhysicalAddress (
  51. IN ULONG64 Address,
  52. OUT PULONG64 PhysAddress
  53. );
  54. ULONG
  55. ApicRead (
  56. ULONG64 Address,
  57. ULONG Offset
  58. )
  59. {
  60. ULONG Data, result;
  61. ReadMemoryUncached(Address + Offset, &Data, sizeof (ULONG), &result);
  62. return Data;
  63. }
  64. ULONG
  65. IoApicRead (
  66. ULONG64 VirtualAddress,
  67. ULONG Offset
  68. )
  69. {
  70. ULONG Data = 0, result;
  71. WriteMemoryUncached(VirtualAddress + IO_REGISTER_SELECT, &Offset, sizeof(Offset), &result);
  72. ReadMemoryUncached(VirtualAddress + IO_REGISTER_WINDOW, &Data, sizeof(Data), &result);
  73. return Data;
  74. }
  75. ULONG
  76. ApicDumpSetBits (
  77. PUCHAR Desc,
  78. PULONG Bits
  79. )
  80. {
  81. PULONG p;
  82. ULONG i;
  83. BOOLEAN FoundOne;
  84. BOOLEAN InSetRange;
  85. BOOLEAN MultipleBitsInRange;
  86. BOOLEAN status;
  87. dprintf(Desc);
  88. i = 0;
  89. p = Bits;
  90. FoundOne = FALSE;
  91. InSetRange = FALSE;
  92. for (i = 0; i < 0x100; i++) {
  93. if (*p & (1 << (i & 0x1F))) {
  94. if (!InSetRange) {
  95. InSetRange = TRUE;
  96. MultipleBitsInRange = FALSE;
  97. if (FoundOne) {
  98. dprintf(", ");
  99. }
  100. dprintf("%.2X", i);
  101. FoundOne = TRUE;
  102. } else if (!MultipleBitsInRange) {
  103. MultipleBitsInRange = TRUE;
  104. dprintf("-");
  105. }
  106. } else {
  107. if (InSetRange) {
  108. if (MultipleBitsInRange == TRUE) {
  109. dprintf("%x",i-1);
  110. }
  111. InSetRange = FALSE;
  112. }
  113. }
  114. if ((i & 0x1F) == 0x1F) {
  115. p++;
  116. }
  117. }
  118. if (InSetRange && MultipleBitsInRange) {
  119. if (MultipleBitsInRange == TRUE) {
  120. dprintf("%x", i - 1);
  121. }
  122. }
  123. dprintf ("\n");
  124. return 0;
  125. }
  126. ULONG
  127. ApicReadAndDumpBits (
  128. PUCHAR Desc,
  129. ULONG64 Address,
  130. ULONG Offset
  131. )
  132. {
  133. #define SETREGISTERS (256 / 32)
  134. ULONG Bits [SETREGISTERS];
  135. PULONG p;
  136. ULONG i, result;
  137. ULONG64 MemAddr;
  138. BOOLEAN status;
  139. //
  140. // Read the bytes
  141. //
  142. MemAddr = Address + Offset;
  143. for (i = 0; i < SETREGISTERS; i++) {
  144. status = ReadMemoryUncached(MemAddr, &Bits[i], sizeof(DWORD), &result);
  145. if (status == FALSE) {
  146. dprintf("Unable to read 4 bytes at offset %UI64\n",
  147. MemAddr);
  148. return E_INVALIDARG;
  149. }
  150. MemAddr += 0x10;
  151. }
  152. ApicDumpSetBits(Desc, Bits);
  153. return 0;
  154. }
  155. ULONG
  156. ApicDumpRedir (
  157. PUCHAR Desc,
  158. BOOLEAN CommandReg,
  159. BOOLEAN DestSelf,
  160. ULONG lh,
  161. ULONG ll
  162. )
  163. {
  164. static PUCHAR DelMode[] = {
  165. "FixedDel",
  166. "LowestDl",
  167. "res010 ",
  168. "remoterd",
  169. "NMI ",
  170. "RESET ",
  171. "res110 ",
  172. "ExtINTA "
  173. };
  174. static PUCHAR DesShDesc[] = { "",
  175. " Dest=Self",
  176. " Dest=ALL",
  177. " Dest=Othrs"
  178. };
  179. ULONG del, dest, delstat, rirr, trig, masked, destsh, pol;
  180. del = (ll >> 8) & 0x7;
  181. dest = (ll >> 11) & 0x1;
  182. delstat = (ll >> 12) & 0x1;
  183. pol = (ll >> 13) & 0x1;
  184. rirr = (ll >> 14) & 0x1;
  185. trig = (ll >> 15) & 0x1;
  186. masked = (ll >> 16) & 0x1;
  187. destsh = (ll >> 18) & 0x3;
  188. if (CommandReg) {
  189. // command reg's don't have a mask
  190. masked = 0;
  191. }
  192. dprintf ("%s: %08x Vec:%02X %s ",
  193. Desc,
  194. ll,
  195. ll & 0xff,
  196. DelMode [ del ]
  197. );
  198. if (DestSelf) {
  199. dprintf (DesShDesc[1]);
  200. } else if (CommandReg && destsh) {
  201. dprintf (DesShDesc[destsh]);
  202. } else {
  203. if (dest) {
  204. dprintf ("Lg:%08x", lh);
  205. } else {
  206. dprintf ("PhysDest:%02X", (lh >> 56) & 0xFF);
  207. }
  208. }
  209. dprintf ("%s %s %s %s %s\n",
  210. delstat ? "-Pend" : " ",
  211. trig ? "lvl" : "edg",
  212. pol ? "low " : "high",
  213. rirr ? "rirr" : " ",
  214. masked ? "masked" : " "
  215. );
  216. return 0;
  217. }
  218. #define IA64_DEBUG_CONTROL_SPACE_KSPECIAL 3
  219. typedef struct _REGISTER_LOOKUP_TABLE
  220. {
  221. LPSTR FieldName;
  222. PULONGLONG Variable;
  223. } REGISTER_LOOKUP_TABLE, *PREGISTER_LOOKUP_TABLE;
  224. BOOL
  225. ReadKSpecialRegisters(DWORD Cpu, PREGISTER_LOOKUP_TABLE Table, ULONG TableSize)
  226. {
  227. PUCHAR buffer;
  228. ULONG size;
  229. ULONG offset;
  230. ULONG i;
  231. size = GetTypeSize("nt!KSPECIAL_REGISTERS");
  232. if (size == 0) {
  233. dprintf("Can't find the size of KSPECIAL_REGISTERS\n");
  234. return FALSE;
  235. }
  236. if ((buffer = LocalAlloc(LPTR, size)) == NULL) {
  237. dprintf("Can't allocate memory for KSPECIAL_REGISTERS\n");
  238. return FALSE;
  239. }
  240. ReadControlSpace64((USHORT)Cpu, IA64_DEBUG_CONTROL_SPACE_KSPECIAL, buffer, size);
  241. for (i = 0; i < TableSize; i++) {
  242. if (GetFieldOffsetEx("KSPECIAL_REGISTERS", Table[i].FieldName, &offset, &size) != S_OK) {
  243. dprintf("Can't get offset of %s\n", Table[i].FieldName);
  244. return FALSE;
  245. }
  246. if (size != sizeof(ULONGLONG)) {
  247. dprintf("Sizeof %s (%d) is not sizeof(ULONGLONG)\n", Table[i].FieldName, size);
  248. return FALSE;
  249. }
  250. *Table[i].Variable = *(PULONGLONG)&buffer[offset];
  251. }
  252. LocalFree(buffer);
  253. return TRUE;
  254. }
  255. PUCHAR DeliveryModes[8] = {
  256. "INT", "INT w/Hint", "PMI", "RSV3", "NMI", "INIT", "RSV6", "ExtINT"
  257. };
  258. void
  259. DumpSApicRedir(
  260. PUCHAR Description,
  261. ULONG HighHalf,
  262. ULONG LowHalf
  263. )
  264. {
  265. dprintf("%s: %.8X Vec:%.2X %-10s %.2X%.2X%s %s %s %s\n",
  266. Description,
  267. LowHalf,
  268. (ULONG)(LowHalf & 0xFF),
  269. DeliveryModes[(ULONG)(LowHalf >> 8) & 0x7],
  270. (HighHalf >> 24) & 0xFF,
  271. (HighHalf >> 16) & 0xFF,
  272. (LowHalf & (1 << 12)) ? "-Pend" : " ",
  273. (LowHalf & (1 << 15)) ? "lvl" : "edg",
  274. (LowHalf & (1 << 13)) ? "low" : "high",
  275. (LowHalf & (1 << 16)) ? "masked" : " "
  276. );
  277. }
  278. void
  279. DumpLocalSapic(ULONG Processor, LPCSTR Args)
  280. {
  281. DWORD cpu;
  282. ULONGLONG SaLID;
  283. ULONGLONG SaTPR;
  284. ULONGLONG SaIRR[4];
  285. ULONGLONG SaITV;
  286. ULONGLONG SaPMV;
  287. ULONGLONG SaCMCV;
  288. ULONGLONG SaLRR[2];
  289. REGISTER_LOOKUP_TABLE registerTable[] = {
  290. { "SaLID", &SaLID },
  291. { "SaTPR", &SaTPR },
  292. { "SaIRR0", &SaIRR[0] },
  293. { "SaIRR1", &SaIRR[1] },
  294. { "SaIRR2", &SaIRR[2] },
  295. { "SaIRR3", &SaIRR[3] },
  296. { "SaITV", &SaITV },
  297. { "SaPMV", &SaPMV },
  298. { "SaCMCV", &SaCMCV },
  299. { "SaLRR0", &SaLRR[0] },
  300. { "SaLRR1", &SaLRR[1] }
  301. };
  302. if (Args[0] == '\0') {
  303. cpu = Processor;
  304. }
  305. else {
  306. cpu = atoi(Args);
  307. }
  308. if (!ReadKSpecialRegisters(cpu, registerTable, sizeof(registerTable) / sizeof(registerTable[0]))) {
  309. return;
  310. }
  311. dprintf("Local Sapic for processor %d\n", cpu);
  312. dprintf("LID: EID = 0x%.2X, ID = 0x%.2X\n", (ULONG)((SaLID >> 16) & 0xFF), (ULONG)((SaLID >> 24) & 0xFF));
  313. dprintf("TPR: Mask Interrupt Class = %d, Mask Maskable Interrupts = %s\n", (ULONG)(SaTPR >> 4) & 0xF, (SaTPR & (1 << 16)) ? "TRUE" : "FALSE");
  314. ApicDumpSetBits("IRR: ", (PULONG)&SaIRR[0]);
  315. dprintf("ITV: Vector = 0x%.2X, Masked = %s\n", (ULONG)(SaITV & 0xFF), (SaITV & (1 << 16)) ? "TRUE" : "FALSE");
  316. dprintf("PMV: Vector = 0x%.2X, Masked = %s\n", (ULONG)(SaPMV & 0xFF), (SaPMV & (1 << 16)) ? "TRUE" : "FALSE");
  317. dprintf("CMCV: Vector = 0x%.2X, Masked = %s\n", (ULONG)(SaCMCV & 0xFF), (SaCMCV & (1 << 16)) ? "TRUE" : "FALSE");
  318. DumpSApicRedir("LRR0", (ULONG)(SaLRR[0] >> 32), (ULONG)SaLRR[0]);
  319. DumpSApicRedir("LRR1", (ULONG)(SaLRR[1] >> 32), (ULONG)SaLRR[1]);
  320. }
  321. DECLARE_API( apic )
  322. /*++
  323. Routine Description:
  324. Dumps local apic
  325. Arguments:
  326. args - Supplies the address in hex.
  327. Return Value:
  328. None
  329. --*/
  330. {
  331. static PUCHAR divbase[] = { "2", "4", "8", "f" };
  332. static PUCHAR clktype[] = { "clk", "tmbase", "%s/%s", "??%s/%s" };
  333. ULONG64 Address;
  334. ULONG result, junk, l, ll, lh, clkvec;
  335. UCHAR s[40];
  336. INIT_API();
  337. if (TargetMachine == IMAGE_FILE_MACHINE_IA64) {
  338. ULONG processor;
  339. GetCurrentProcessor(Client, &processor, NULL);
  340. DumpLocalSapic(processor, args);
  341. EXIT_API();
  342. return S_OK;
  343. }
  344. if (TargetMachine != IMAGE_FILE_MACHINE_I386 &&
  345. TargetMachine != IMAGE_FILE_MACHINE_AMD64) {
  346. dprintf("X86 and AMD64 only API.\n");
  347. EXIT_API();
  348. return E_INVALIDARG;
  349. }
  350. if ((Address = GetExpression(args)) == 0) {
  351. //
  352. // Default Apic address
  353. //
  354. Address = 0xfffe0000;
  355. }
  356. if (Address == 0) {
  357. //
  358. // Use default for MPS systems.
  359. //
  360. Address = 0xfffe0000;
  361. }
  362. Address = (ULONG64) (LONG64) (LONG) Address;
  363. if ( !ReadMemoryUncached(
  364. Address + LU_ID_REGISTER,
  365. (PVOID)&junk,
  366. 4,
  367. &result
  368. ) ) {
  369. dprintf("Unable to read lapic\n");
  370. EXIT_API();
  371. return E_INVALIDARG;
  372. }
  373. if ( !ReadMemoryUncached(
  374. Address + LU_DIVIDER_CONFIG,
  375. (PVOID)&junk,
  376. 4,
  377. &result
  378. ) ) {
  379. dprintf("Unable to read lapic\n");
  380. EXIT_API();
  381. return E_INVALIDARG;
  382. }
  383. dprintf ("Apic @ %08x ID:%x (%x) LogDesc:%08x DestFmt:%08x TPR %02X\n",
  384. (ULONG)Address,
  385. ApicRead (Address, LU_ID_REGISTER) >> 24,
  386. ApicRead (Address, LU_VERS_REGISTER),
  387. ApicRead (Address, LU_DEST),
  388. ApicRead (Address, LU_DEST_FORMAT),
  389. ApicRead (Address, LU_TPR)
  390. );
  391. l = ApicRead (Address, LU_SPURIOUS_VECTOR);
  392. ll = ApicRead (Address, LU_DIVIDER_CONFIG);
  393. clkvec = ApicRead (Address, LU_TIMER_VECTOR);
  394. sprintf (s, clktype[ (clkvec >> 18) & 0x3 ],
  395. clktype [ (ll >> 2) & 0x1 ],
  396. divbase [ ll & 0x3]
  397. );
  398. dprintf ("TimeCnt: %08x%s%s SpurVec:%02x FaultVec:%02x error:%x%s\n",
  399. ApicRead (Address, LU_INITIAL_COUNT),
  400. s,
  401. ((clkvec >> 17) & 1) ? "" : "-oneshot",
  402. l & 0xff,
  403. ApicRead (Address, LU_FAULT_VECTOR),
  404. ApicRead (Address, LU_ERROR_STATUS),
  405. l & 0x100 ? "" : " DISABLED"
  406. );
  407. ll = ApicRead (Address, LU_INT_CMD_LOW);
  408. lh = ApicRead (Address, LU_INT_CMD_HIGH);
  409. ApicDumpRedir ("Ipi Cmd", TRUE, FALSE, lh, ll);
  410. ApicDumpRedir ("Timer..", FALSE, TRUE, 0, clkvec);
  411. ApicDumpRedir ("Linti0.", FALSE, TRUE, 0, ApicRead (Address, LU_INT_VECTOR_0));
  412. ApicDumpRedir ("Linti1.", FALSE, TRUE, 0, ApicRead (Address, LU_INT_VECTOR_1));
  413. ApicReadAndDumpBits ("TMR: ", Address, LU_TMR_0);
  414. ApicReadAndDumpBits ("IRR: ", Address, LU_IRR_0);
  415. ApicReadAndDumpBits ("ISR: ", Address, LU_ISR_0);
  416. EXIT_API();
  417. return S_OK;
  418. }
  419. void
  420. DumpIoSApic(
  421. IN LPCSTR Args
  422. )
  423. {
  424. ULONG64 address;
  425. ULONG ioSapicCount;
  426. ULONG index;
  427. ULONG64 apicDebugAddresses;
  428. ULONG apicDebugSize;
  429. ULONG64 apicVirtualAddress;
  430. ULONG64 apicPhysicalAddress;
  431. ULONG ll, lh;
  432. ULONG i, max;
  433. UCHAR s[40];
  434. address = GetExpression("hal!HalpMpInfo");
  435. if (address == 0) {
  436. dprintf("Can't find hal!HalpMpInfo\n");
  437. return;
  438. }
  439. if (GetFieldValue(address, "hal!_MPINFO", "IoSapicCount", ioSapicCount) != 0) {
  440. dprintf("Error reading IoSapicCount\n");
  441. return;
  442. }
  443. address = GetExpression("Hal!HalpApicDebugAddresses");
  444. if (address == 0) {
  445. dprintf("Can't find Hal!HalpApicDebugAddresses\n");
  446. return;
  447. }
  448. if (ReadPointer(address, &apicDebugAddresses) == 0) {
  449. dprintf("Error reading Hal!HalpApicDebugAddresses\n");
  450. return;
  451. }
  452. apicDebugSize = GetTypeSize("hal!_IOAPIC_DEBUG_TABLE");
  453. if (apicDebugSize == 0) {
  454. dprintf("Can't find hal!_IOAPIC_DEBUG_TABLE\n");
  455. return;
  456. }
  457. for (index = 0; index < ioSapicCount; index++) {
  458. GetFieldValue(apicDebugAddresses + (index * apicDebugSize),
  459. "hal!_IOAPIC_DEBUG_TABLE", "IoSapicRegs",
  460. apicVirtualAddress);
  461. apicPhysicalAddress = 0;
  462. GetPhysicalAddress(apicVirtualAddress, &apicPhysicalAddress);
  463. ll = IoApicRead(apicVirtualAddress, IO_VERS_REGISTER);
  464. dprintf("I/O SAPIC @ %.8X, Version = %.2X (0x%.8X)\n", (ULONG)apicPhysicalAddress, (ll & 0xFF), ll);
  465. max = (ll >> 16) & 0xff;
  466. //
  467. // Dump inti table
  468. //
  469. max *= 2;
  470. for (i = 0; i <= max; i += 2) {
  471. ll = IoApicRead(apicVirtualAddress, IO_REDIR_BASE + i + 0);
  472. lh = IoApicRead(apicVirtualAddress, IO_REDIR_BASE + i + 1);
  473. sprintf(s, "Inti%02X", i / 2);
  474. DumpSApicRedir(s, lh, ll);
  475. }
  476. }
  477. }
  478. ULONG
  479. GetFieldInfo(
  480. IN LPCSTR Type,
  481. IN LPCSTR Field,
  482. OUT PULONG pOffset,
  483. OUT PULONG pSize
  484. )
  485. {
  486. FIELD_INFO flds = {
  487. (PUCHAR)Field,
  488. (PUCHAR)"",
  489. 0,
  490. DBG_DUMP_FIELD_FULL_NAME | DBG_DUMP_FIELD_RETURN_ADDRESS,
  491. 0,
  492. NULL};
  493. SYM_DUMP_PARAM Sym = {
  494. sizeof (SYM_DUMP_PARAM),
  495. (PUCHAR)Type,
  496. DBG_DUMP_NO_PRINT,
  497. 0,
  498. NULL,
  499. NULL,
  500. NULL,
  501. 1,
  502. &flds
  503. };
  504. ULONG Err;
  505. Sym.nFields = 1;
  506. Err = Ioctl( IG_DUMP_SYMBOL_INFO, &Sym, Sym.size );
  507. if (Err == 0) {
  508. *pOffset = (ULONG) (flds.address - Sym.addr);
  509. *pSize = (ULONG) (flds.size);
  510. }
  511. return Err;
  512. }
  513. ULONG
  514. ReadArrayPointer(
  515. ULONG64 Address,
  516. PUCHAR StructureType,
  517. PUCHAR FieldName,
  518. int ArrayIndex,
  519. PULONG64 Pointer
  520. )
  521. {
  522. ULONG64 addrPointer;
  523. ULONG offset;
  524. ULONG size;
  525. ULONG result;
  526. if (StructureType != NULL) {
  527. result = GetFieldInfo(StructureType, FieldName, &offset, &size);
  528. if (result != 0) {
  529. return result;
  530. }
  531. } else {
  532. offset = 0;
  533. size = IsPtr64() ? 8 : 4;
  534. }
  535. Address += offset + ArrayIndex * size;
  536. return !ReadPointer(Address, Pointer);
  537. }
  538. DECLARE_API( ioapic )
  539. /*++
  540. Routine Description:
  541. Dumps io apic
  542. Arguments:
  543. args - Supplies the address in hex, if no address is specified, all IOApics will be dumped.
  544. Return Value:
  545. None
  546. --*/
  547. {
  548. ULONG64 PhysAddress;
  549. ULONG64 Address;
  550. ULONG i, ll, lh, max, IOApicCount;
  551. UCHAR s[40];
  552. ULONG64 addr;
  553. UCHAR count;
  554. INIT_API();
  555. if (TargetMachine == IMAGE_FILE_MACHINE_IA64) {
  556. DumpIoSApic(args);
  557. EXIT_API();
  558. return S_OK;
  559. }
  560. if (TargetMachine != IMAGE_FILE_MACHINE_I386 &&
  561. TargetMachine != IMAGE_FILE_MACHINE_AMD64) {
  562. dprintf("X86 or AMD64 only API.\n");
  563. EXIT_API();
  564. return E_INVALIDARG;
  565. }
  566. Address = GetExpression(args);
  567. if (Address != 0) {
  568. IOApicCount = 1;
  569. } else {
  570. //
  571. // Get a copy of the global data structure Hal!HalpMpInfoTable.
  572. //
  573. addr = GetExpression("Hal!HalpMpInfoTable");
  574. if (addr == 0) {
  575. dprintf ("Error retrieving address of HalpMpInfoTable\n");
  576. EXIT_API();
  577. return E_INVALIDARG;
  578. }
  579. if (GetFieldValue(addr, "Hal!HalpMpInfo", "IOApicCount", IOApicCount) != 0) {
  580. dprintf ("Error reading HalpMpInfoTable.IOApicCount\n");
  581. EXIT_API();
  582. return E_INVALIDARG;
  583. }
  584. if (ReadArrayPointer(addr, "Hal!HalpMpInfo", "IoApicBase", 0, &Address) != 0) {
  585. dprintf ("Error reading HalpMpInfoTable.IOApicBase[0]\n");
  586. EXIT_API();
  587. return E_INVALIDARG;
  588. }
  589. }
  590. for (count = 0; count < IOApicCount; count++) {
  591. if (!GetPhysicalAddress(Address, &PhysAddress)) {
  592. dprintf("Can't convert address 0x%P to physical\n", Address);
  593. break;
  594. }
  595. if (CheckControlC()) {
  596. break;
  597. }
  598. ll = IoApicRead(Address, IO_VERS_REGISTER),
  599. max = (ll >> 16) & 0xff;
  600. dprintf ("IoApic @ %08X ID:%X (%X) Arb:%X\n",
  601. (ULONG)PhysAddress,
  602. IoApicRead(Address, IO_ID_REGISTER) >> 24,
  603. ll & 0xFF,
  604. IoApicRead(Address, IO_ARB_ID_REGISTER)
  605. );
  606. if (max <= 120) {
  607. //
  608. // Dump inti table
  609. //
  610. max *= 2;
  611. for (i=0; i <= max; i += 2) {
  612. ll = IoApicRead(Address, IO_REDIR_BASE+i+0);
  613. lh = IoApicRead(Address, IO_REDIR_BASE+i+1);
  614. sprintf(s, "Inti%02X.", i / 2);
  615. ApicDumpRedir(s, FALSE, FALSE, lh, ll);
  616. }
  617. } else {
  618. //
  619. // The maximum number of entries is exceeded. Either the IOAPIC
  620. // has disappeared or this address isn't an IOAPIC.
  621. //
  622. dprintf("\nThe version register claims there are %d redir entries. Since this exceeds\n", max);
  623. dprintf("the maximum in the specification, this device is probably not an IO APIC.\n\n");
  624. }
  625. //
  626. // Get the next IoApic Virtual Address
  627. //
  628. if (ReadArrayPointer(addr, "Hal!HalpMpInfo", "IoApicBase", count + 1, &Address) != 0) {
  629. dprintf ("Error reading HalpMpInfoTable.IOApicBase[%d]\n", count + 1);
  630. EXIT_API();
  631. return E_INVALIDARG;
  632. }
  633. dprintf ("\n");
  634. }
  635. EXIT_API();
  636. return S_OK;
  637. }
  638. DECLARE_API( sendnmi )
  639. /*++
  640. Routine Description:
  641. Send an IPI to the processors in the argument bitmask (affinity).
  642. (Used for debugging when a processor is spinning with interrupts
  643. disabled).
  644. Arguments:
  645. KAFFINITY BitMask Supplied a mask of processors to send the
  646. IPI to.
  647. Return Value:
  648. Success.
  649. --*/
  650. {
  651. ULONG64 Address;
  652. ULONG64 ApicAddress;
  653. UCHAR MaxProcsPerCluster;
  654. ULONG i;
  655. ULONG64 TargetSet;
  656. ULONG64 ActiveProcessors;
  657. ULONG Length;
  658. ULONG ApicDWord;
  659. ULONG junk;
  660. //
  661. // APIC/XAPIC machines only.
  662. // This should be doable on IA64 and AMD64 as well but I don't know
  663. // how at time of writing. PeterJ.
  664. //
  665. if (TargetMachine != IMAGE_FILE_MACHINE_I386) {
  666. dprintf("Sorry, only know how to send NMI on an APIC machine.\n");
  667. return E_INVALIDARG;
  668. }
  669. if (strstr(args, "?") ||
  670. ((TargetSet = GetExpression(args)) == 0)) {
  671. dprintf("usage: sendnmi bitmask\n"
  672. " where bitmask is the set of processors an NMI\n"
  673. " is to be sent to.\n");
  674. return E_INVALIDARG;
  675. }
  676. //
  677. // See if we can get the cluster mode from the HAL.
  678. // (On AMD64 and IA64, this information would be in the kernel).
  679. //
  680. Address = GetExpression("hal!HalpMaxProcsPerCluster");
  681. if (!Address) {
  682. dprintf("Unable to get APIC configuration information from the HAL\n");
  683. dprintf("Cannot continue.\n");
  684. return E_INVALIDARG;
  685. }
  686. if (!ReadMemoryUncached(Address,
  687. &MaxProcsPerCluster,
  688. sizeof(MaxProcsPerCluster),
  689. &i) || (i != sizeof(MaxProcsPerCluster))) {
  690. dprintf("Unable to read system memory, quitting.\n");
  691. return E_INVALIDARG;
  692. }
  693. Address = GetExpression("nt!KeActiveProcessors");
  694. Length = GetTypeSize("nt!KeActiveProcessors");
  695. if ((!Address) || (!((Length == 4) || (Length == 8)))) {
  696. dprintf("Unable to get processor configuration from kernel\n");
  697. dprintf("Cannot continue.\n");
  698. return E_INVALIDARG;
  699. }
  700. ActiveProcessors = 0;
  701. if (!ReadMemoryUncached(Address,
  702. &ActiveProcessors,
  703. Length,
  704. &i) || (i != Length) || (ActiveProcessors == 0)) {
  705. dprintf("Unable to read processor configuration from kernel.\n");
  706. dprintf("Cannot continue.\n");
  707. return E_INVALIDARG;
  708. }
  709. if ((TargetSet & ActiveProcessors) != TargetSet) {
  710. dprintf("Target processor set (%I64x) contains processors not in\n"
  711. "system processor set (%I64x).\n",
  712. TargetSet,
  713. ActiveProcessors);
  714. dprintf("Cannot continue.\n");
  715. return E_INVALIDARG;
  716. }
  717. ApicAddress = 0xfffe0000;
  718. ApicAddress = (ULONG64) (LONG64) (LONG) ApicAddress;
  719. if ((!ReadMemoryUncached(ApicAddress,
  720. &junk,
  721. 1,
  722. &i)) ||
  723. (!ReadMemoryUncached(ApicAddress + LU_SIZE - 1,
  724. &junk,
  725. 1,
  726. &i)) ||
  727. (!ReadMemoryUncached(ApicAddress + LU_INT_CMD_LOW,
  728. &ApicDWord,
  729. sizeof(ApicDWord),
  730. &i)) ||
  731. (i != sizeof(ApicDWord))) {
  732. dprintf("Unable to read lapic\n");
  733. dprintf("Cannot continue.\n");
  734. return E_INVALIDARG;
  735. }
  736. if ((ApicDWord & DELIVERY_PENDING) != 0) {
  737. dprintf("Local APIC is busy, can't use it right now.\n");
  738. dprintf("This is probably indicative of an APIC error.\n");
  739. return E_INVALIDARG;
  740. }
  741. if (MaxProcsPerCluster == 0) {
  742. //
  743. // APIC is not in cluster mode. This makes life easy.
  744. // Sanity: This means there's 8 or less processors.
  745. //
  746. if (TargetSet > 0xff) {
  747. dprintf("APIC is in non-cluster mode thus it cannot support\n"
  748. "more than 8 processors yet the target mask includes\n"
  749. "processors outside that range. Something is not right.\n"
  750. "quitting.\n");
  751. return E_INVALIDARG;
  752. }
  753. dprintf("Sending NMI to processors in set %I64x\n", TargetSet);
  754. ApicDWord = ((ULONG)TargetSet) << DESTINATION_SHIFT;
  755. WriteMemory(ApicAddress + LU_INT_CMD_HIGH,
  756. &ApicDWord,
  757. sizeof(ApicDWord),
  758. &i);
  759. ApicDWord = DELIVER_NMI |
  760. LOGICAL_DESTINATION |
  761. ICR_USE_DEST_FIELD |
  762. NMI_VECTOR;
  763. WriteMemory(ApicAddress + LU_INT_CMD_LOW,
  764. &ApicDWord,
  765. sizeof(ApicDWord),
  766. &i);
  767. dprintf("Sent.\n");
  768. } else {
  769. dprintf("APIC is in cluster mode, don't know how to do this yet.\n");
  770. }
  771. return S_OK;
  772. }
  773. //
  774. // This is the definition of an APIC error log entry.
  775. // The OS does not have a defined structure. We just
  776. // use one for simplicity.
  777. //
  778. typedef struct _APIC_ERROR_LOG_ENTRY
  779. {
  780. UCHAR ErrorBits;
  781. UCHAR ProcessorNumber;
  782. } APIC_ERROR_LOG_ENTRY, *PAPIC_ERROR_LOG_ENTRY;
  783. //
  784. // This is an array of strings that corrispond to
  785. // each type of error.
  786. //
  787. #define MAX_ERROR_STRING_LENGTH 25
  788. CHAR ErrorStrings[][MAX_ERROR_STRING_LENGTH] = { "<Invalid Log Entry>",
  789. "Send Check Sum Error",
  790. "Receive Check Sum Error",
  791. "Send Accept Error",
  792. "Receive Accept Error",
  793. "<Reserved>",
  794. "Send Illegal Vector",
  795. "Receive Illegal Vector",
  796. "Illegal Register Address" };
  797. //
  798. // Currently, the hal logs 0x80 error entries and then wraps.
  799. //
  800. #define MAX_APIC_ERROR_ENTRIES 0x80
  801. DECLARE_API( apicerr )
  802. /*++
  803. Routine Description:
  804. Dumps local apic error log.
  805. Arguments:
  806. args - Supplies the format code in hex.
  807. Return Value:
  808. None.
  809. --*/
  810. {
  811. ULONG64 Address;
  812. ULONG ErrorCount;
  813. ULONG i;
  814. ULONG Format;
  815. ULONG ProcCount;
  816. ULONG CurrentProc;
  817. ULONG StringNumber;
  818. ULONG LogStart;
  819. ULONG LogEnd;
  820. BOOL bStatus;
  821. ULONG64 LogPointer;
  822. APIC_ERROR_LOG_ENTRY LogEntry;
  823. UCHAR Bit;
  824. BOOLEAN GroupByProc;
  825. BOOLEAN PrintedSomething;
  826. if (TargetMachine != IMAGE_FILE_MACHINE_I386)
  827. {
  828. dprintf("!apicerr only works for X86 targets\n");
  829. return E_FAIL;
  830. }
  831. //
  832. // Get the format, if specifed. The default is to
  833. // dump the log in order. Specifying one (1) will dump
  834. // the log grouped by processor.
  835. //
  836. Format = (ULONG) GetExpression( args );
  837. if (Format & 0x1) {
  838. //
  839. // We are going to group by processor, so get the number
  840. // of processors in the system. This is how many times
  841. // we need to run the loop.
  842. //
  843. Address = GetExpression( "NT!KeNumberProcessors" );
  844. if (Address == 0) {
  845. dprintf( "Error getting address of KeNumberProcessors.\n\n" );
  846. return E_FAIL;
  847. }
  848. bStatus = ReadMemory( Address,
  849. &ProcCount,
  850. sizeof(ULONG),
  851. NULL );
  852. if (!bStatus) {
  853. dprintf( "Error reading KeNumberProcessors.\n\n" );
  854. return E_FAIL;
  855. }
  856. GroupByProc = TRUE;
  857. } else {
  858. //
  859. // We are not grouping by processor.
  860. //
  861. GroupByProc = FALSE;
  862. }
  863. //
  864. // Display a header.
  865. //
  866. dprintf( "\nAPIC Error Log" );
  867. if (GroupByProc) {
  868. dprintf( " (grouped by processor)" );
  869. }
  870. dprintf( "\n-----------------------------------------------------------\n" );
  871. //
  872. // Get the error count.
  873. //
  874. Address = GetExpression( "hal!HalpLocalApicErrorCount" );
  875. if (Address == 0) {
  876. dprintf( "Error getting address of HalpLocalApicErrorCount.\n\n" );
  877. return E_FAIL;
  878. }
  879. bStatus = ReadMemory( Address,
  880. &ErrorCount,
  881. sizeof(ULONG),
  882. NULL );
  883. if (!bStatus) {
  884. dprintf( "Error reading HalpLocalApicErrorCount.\n\n" );
  885. return E_FAIL;
  886. }
  887. //
  888. // See if there are any errors.
  889. //
  890. if (ErrorCount == 0) {
  891. //
  892. // The error log is empty. Let the user know this
  893. // and we are done.
  894. //
  895. dprintf( "<Error Log Empty>\n\n" );
  896. return E_FAIL;
  897. }
  898. //
  899. // Find the error log.
  900. //
  901. LogPointer = GetExpression( "hal!HalpApicErrorLog" );
  902. if (LogPointer == 0) {
  903. dprintf( "Error getting address of HalpApicErrorLog.\n\n" );
  904. return E_FAIL;
  905. }
  906. //
  907. // Figure out the start of the log.
  908. //
  909. if (ErrorCount > MAX_APIC_ERROR_ENTRIES) {
  910. //
  911. // The log wrapped. It starts right after the last used entry.
  912. //
  913. ErrorCount %= MAX_APIC_ERROR_ENTRIES;
  914. LogStart = ErrorCount;
  915. } else {
  916. //
  917. // The log has not wrapped. It starts at the beginning.
  918. //
  919. LogStart = 0;
  920. }
  921. //
  922. // The log always end at the last used entry.
  923. //
  924. LogEnd = ErrorCount - 1;
  925. //
  926. // Loop for every processor. If we are not grouping by processor,
  927. // we only run the loop once.
  928. //
  929. CurrentProc = 0;
  930. do {
  931. if (CheckControlC())
  932. {
  933. return E_FAIL;
  934. }
  935. //
  936. // Keep track of of whether we printed anything.
  937. //
  938. PrintedSomething = FALSE;
  939. //
  940. // Walk the error log.
  941. //
  942. i = LogStart;
  943. while (TRUE) {
  944. //
  945. // Read in the log entry.
  946. //
  947. bStatus = ReadMemory( LogPointer + i* sizeof(APIC_ERROR_LOG_ENTRY),
  948. &LogEntry,
  949. sizeof(APIC_ERROR_LOG_ENTRY),
  950. NULL );
  951. if (!bStatus) {
  952. dprintf( "Error reading HalpApicErrorLog entry number 0x%08x.\n\n", i );
  953. return E_FAIL;
  954. }
  955. //
  956. // If we are grouping by processor, and this is not the current processor,
  957. // just move to the next entry;
  958. //
  959. if (GroupByProc && LogEntry.ProcessorNumber != (UCHAR)CurrentProc) {
  960. goto NextEntry;
  961. }
  962. //
  963. // Display the error log entry.
  964. //
  965. for (Bit = 1, StringNumber = 1; Bit != 0; Bit <<= 1, StringNumber++) {
  966. //
  967. // Error 0x10 is reserved, so we skip it.
  968. //
  969. if (Bit == 0x10) {
  970. continue;
  971. }
  972. //
  973. // If no bits are set, this is an invalid log entry.
  974. //
  975. if (LogEntry.ErrorBits == 0) {
  976. //
  977. // The first string in the array is the error message.
  978. //
  979. StringNumber = 0;
  980. //
  981. // Setting 'Bit' to zero will make us break out of the loop
  982. // and will get us into the printing code below.
  983. //
  984. Bit = 0;
  985. }
  986. if (((LogEntry.ErrorBits & Bit) != 0) || (Bit == 0)) {
  987. dprintf( "[%02x] - %s\n",
  988. (ULONG)LogEntry.ProcessorNumber,
  989. ErrorStrings[StringNumber] );
  990. PrintedSomething = TRUE;
  991. }
  992. }
  993. NextEntry:
  994. //
  995. // See if we are done.
  996. //
  997. if (i == LogEnd) {
  998. break;
  999. }
  1000. //
  1001. // Move to the next entry.
  1002. //
  1003. i++;
  1004. if (i == MAX_APIC_ERROR_ENTRIES) {
  1005. i = 0;
  1006. }
  1007. }
  1008. //
  1009. // If we printed an error, add a blank line.
  1010. //
  1011. if (PrintedSomething) {
  1012. dprintf( "\n" );
  1013. }
  1014. //
  1015. // Keep looping as long as we are grouping by processor and
  1016. // there are still processors left.
  1017. //
  1018. CurrentProc++;
  1019. } while (GroupByProc && CurrentProc < ProcCount);
  1020. return S_OK;
  1021. }