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.

928 lines
22 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 PhysAddress,
  67. ULONG Offset
  68. )
  69. {
  70. ULONG Data = 0, result;
  71. PhysAddress += IO_REGISTER_SELECT;
  72. WritePhysical(PhysAddress, &Offset, sizeof(ULONG), &result);
  73. PhysAddress += IO_REGISTER_WINDOW - IO_REGISTER_SELECT;
  74. ReadPhysical(PhysAddress, &Data, sizeof (ULONG), &result);
  75. return Data;
  76. }
  77. ULONG
  78. IoSApicRead (
  79. ULONG64 VirtualAddress,
  80. ULONG Offset
  81. )
  82. {
  83. ULONG Data = 0, result;
  84. WriteMemoryUncached(VirtualAddress + IO_REGISTER_SELECT, &Offset, sizeof(ULONG), &result);
  85. ReadMemoryUncached(VirtualAddress + IO_REGISTER_WINDOW, &Data, sizeof(Data), &result);
  86. return Data;
  87. }
  88. ULONG
  89. ApicDumpSetBits (
  90. PUCHAR Desc,
  91. PULONG Bits
  92. )
  93. {
  94. PULONG p;
  95. ULONG i;
  96. BOOLEAN FoundOne;
  97. BOOLEAN InSetRange;
  98. BOOLEAN MultipleBitsInRange;
  99. BOOLEAN status;
  100. dprintf(Desc);
  101. i = 0;
  102. p = Bits;
  103. FoundOne = FALSE;
  104. InSetRange = FALSE;
  105. for (i = 0; i < 0x100; i++) {
  106. if (*p & (1 << (i & 0x1F))) {
  107. if (!InSetRange) {
  108. InSetRange = TRUE;
  109. MultipleBitsInRange = FALSE;
  110. if (FoundOne) {
  111. dprintf(", ");
  112. }
  113. dprintf("%.2X", i);
  114. FoundOne = TRUE;
  115. } else if (!MultipleBitsInRange) {
  116. MultipleBitsInRange = TRUE;
  117. dprintf("-");
  118. }
  119. } else {
  120. if (InSetRange) {
  121. if (MultipleBitsInRange == TRUE) {
  122. dprintf("%x",i-1);
  123. }
  124. InSetRange = FALSE;
  125. }
  126. }
  127. if ((i & 0x1F) == 0x1F) {
  128. p++;
  129. }
  130. }
  131. if (InSetRange && MultipleBitsInRange) {
  132. if (MultipleBitsInRange == TRUE) {
  133. dprintf("%x", i - 1);
  134. }
  135. }
  136. dprintf ("\n");
  137. return 0;
  138. }
  139. ULONG
  140. ApicReadAndDumpBits (
  141. PUCHAR Desc,
  142. ULONG64 Address,
  143. ULONG Offset
  144. )
  145. {
  146. #define SETREGISTERS (256 / 32)
  147. ULONG Bits [SETREGISTERS];
  148. PULONG p;
  149. ULONG i, result;
  150. ULONG64 MemAddr;
  151. BOOLEAN status;
  152. //
  153. // Read the bytes
  154. //
  155. MemAddr = Address + Offset;
  156. for (i = 0; i < SETREGISTERS; i++) {
  157. status = ReadMemoryUncached(MemAddr, &Bits[i], sizeof(DWORD), &result);
  158. if (status == FALSE) {
  159. dprintf("Unable to read 4 bytes at offset %UI64\n",
  160. MemAddr);
  161. return E_INVALIDARG;
  162. }
  163. MemAddr += 0x10;
  164. }
  165. ApicDumpSetBits(Desc, Bits);
  166. return 0;
  167. }
  168. ULONG
  169. ApicDumpRedir (
  170. PUCHAR Desc,
  171. BOOLEAN CommandReg,
  172. BOOLEAN DestSelf,
  173. ULONG lh,
  174. ULONG ll
  175. )
  176. {
  177. static PUCHAR DelMode[] = {
  178. "FixedDel",
  179. "LowestDl",
  180. "res010 ",
  181. "remoterd",
  182. "NMI ",
  183. "RESET ",
  184. "res110 ",
  185. "ExtINTA "
  186. };
  187. static PUCHAR DesShDesc[] = { "",
  188. " Dest=Self",
  189. " Dest=ALL",
  190. " Dest=Othrs"
  191. };
  192. ULONG del, dest, delstat, rirr, trig, masked, destsh, pol;
  193. del = (ll >> 8) & 0x7;
  194. dest = (ll >> 11) & 0x1;
  195. delstat = (ll >> 12) & 0x1;
  196. pol = (ll >> 13) & 0x1;
  197. rirr = (ll >> 14) & 0x1;
  198. trig = (ll >> 15) & 0x1;
  199. masked = (ll >> 16) & 0x1;
  200. destsh = (ll >> 18) & 0x3;
  201. if (CommandReg) {
  202. // command reg's don't have a mask
  203. masked = 0;
  204. }
  205. dprintf ("%s: %08x Vec:%02X %s ",
  206. Desc,
  207. ll,
  208. ll & 0xff,
  209. DelMode [ del ]
  210. );
  211. if (DestSelf) {
  212. dprintf (DesShDesc[1]);
  213. } else if (CommandReg && destsh) {
  214. dprintf (DesShDesc[destsh]);
  215. } else {
  216. if (dest) {
  217. dprintf ("Lg:%08x", lh);
  218. } else {
  219. dprintf ("PhysDest:%02X", (lh >> 56) & 0xFF);
  220. }
  221. }
  222. dprintf ("%s %s %s %s %s\n",
  223. delstat ? "-Pend" : " ",
  224. trig ? "lvl" : "edg",
  225. pol ? "low " : "high",
  226. rirr ? "rirr" : " ",
  227. masked ? "masked" : " "
  228. );
  229. return 0;
  230. }
  231. #define IA64_DEBUG_CONTROL_SPACE_KSPECIAL 3
  232. typedef struct _REGISTER_LOOKUP_TABLE
  233. {
  234. LPSTR FieldName;
  235. PULONGLONG Variable;
  236. } REGISTER_LOOKUP_TABLE, *PREGISTER_LOOKUP_TABLE;
  237. BOOL
  238. ReadKSpecialRegisters(DWORD Cpu, PREGISTER_LOOKUP_TABLE Table, ULONG TableSize)
  239. {
  240. PUCHAR buffer;
  241. ULONG size;
  242. ULONG offset;
  243. ULONG i;
  244. size = GetTypeSize("nt!KSPECIAL_REGISTERS");
  245. if (size == 0) {
  246. dprintf("Can't find the size of KSPECIAL_REGISTERS\n");
  247. return FALSE;
  248. }
  249. if ((buffer = LocalAlloc(LPTR, size)) == NULL) {
  250. dprintf("Can't allocate memory for KSPECIAL_REGISTERS\n");
  251. return FALSE;
  252. }
  253. ReadControlSpace64((USHORT)Cpu, IA64_DEBUG_CONTROL_SPACE_KSPECIAL, buffer, size);
  254. for (i = 0; i < TableSize; i++) {
  255. if (GetFieldOffsetEx("KSPECIAL_REGISTERS", Table[i].FieldName, &offset, &size) != S_OK) {
  256. dprintf("Can't get offset of %s\n", Table[i].FieldName);
  257. return FALSE;
  258. }
  259. if (size != sizeof(ULONGLONG)) {
  260. dprintf("Sizeof %s (%d) is not sizeof(ULONGLONG)\n", Table[i].FieldName, size);
  261. return FALSE;
  262. }
  263. *Table[i].Variable = *(PULONGLONG)&buffer[offset];
  264. }
  265. LocalFree(buffer);
  266. return TRUE;
  267. }
  268. PUCHAR DeliveryModes[8] = {
  269. "INT", "INT w/Hint", "PMI", "RSV3", "NMI", "INIT", "RSV6", "ExtINT"
  270. };
  271. void
  272. DumpSApicRedir(
  273. PUCHAR Description,
  274. ULONG HighHalf,
  275. ULONG LowHalf
  276. )
  277. {
  278. dprintf("%s: %.8X Vec:%.2X %-10s %.2X%.2X%s %s %s %s\n",
  279. Description,
  280. LowHalf,
  281. (ULONG)(LowHalf & 0xFF),
  282. DeliveryModes[(ULONG)(LowHalf >> 8) & 0x7],
  283. (HighHalf >> 24) & 0xFF,
  284. (HighHalf >> 16) & 0xFF,
  285. (LowHalf & (1 << 12)) ? "-Pend" : " ",
  286. (LowHalf & (1 << 15)) ? "lvl" : "edg",
  287. (LowHalf & (1 << 13)) ? "low" : "high",
  288. (LowHalf & (1 << 16)) ? "masked" : " "
  289. );
  290. }
  291. void
  292. DumpLocalSapic(ULONG Processor, LPCSTR Args)
  293. {
  294. DWORD cpu;
  295. ULONGLONG SaLID;
  296. ULONGLONG SaTPR;
  297. ULONGLONG SaIRR[4];
  298. ULONGLONG SaITV;
  299. ULONGLONG SaPMV;
  300. ULONGLONG SaCMCV;
  301. ULONGLONG SaLRR[2];
  302. REGISTER_LOOKUP_TABLE registerTable[] = {
  303. { "SaLID", &SaLID },
  304. { "SaTPR", &SaTPR },
  305. { "SaIRR0", &SaIRR[0] },
  306. { "SaIRR1", &SaIRR[1] },
  307. { "SaIRR2", &SaIRR[2] },
  308. { "SaIRR3", &SaIRR[3] },
  309. { "SaITV", &SaITV },
  310. { "SaPMV", &SaPMV },
  311. { "SaCMCV", &SaCMCV },
  312. { "SaLRR0", &SaLRR[0] },
  313. { "SaLRR1", &SaLRR[1] }
  314. };
  315. if (Args[0] == '\0') {
  316. cpu = Processor;
  317. }
  318. else {
  319. cpu = atoi(Args);
  320. }
  321. if (!ReadKSpecialRegisters(cpu, registerTable, sizeof(registerTable) / sizeof(registerTable[0]))) {
  322. return;
  323. }
  324. dprintf("Local Sapic for processor %d\n", cpu);
  325. dprintf("LID: EID = %d, ID = %d\n", (ULONG)((SaLID >> 16) & 0xFF), (ULONG)((SaLID >> 24) & 0xFF));
  326. dprintf("TPR: Mask Interrupt Class = %d, Mask Maskable Interrupts = %s\n", (ULONG)(SaTPR >> 4) & 0xF, (SaTPR & (1 << 16)) ? "TRUE" : "FALSE");
  327. ApicDumpSetBits("IRR: ", (PULONG)&SaIRR[0]);
  328. dprintf("ITV: Vector = 0x%.2X, Masked = %s\n", (ULONG)(SaITV & 0xFF), (SaITV & (1 << 16)) ? "TRUE" : "FALSE");
  329. dprintf("PMV: Vector = 0x%.2X, Masked = %s\n", (ULONG)(SaPMV & 0xFF), (SaPMV & (1 << 16)) ? "TRUE" : "FALSE");
  330. dprintf("CMCV: Vector = 0x%.2X, Masked = %s\n", (ULONG)(SaCMCV & 0xFF), (SaCMCV & (1 << 16)) ? "TRUE" : "FALSE");
  331. DumpSApicRedir("LRR0", (ULONG)(SaLRR[0] >> 32), (ULONG)SaLRR[0]);
  332. DumpSApicRedir("LRR1", (ULONG)(SaLRR[1] >> 32), (ULONG)SaLRR[1]);
  333. }
  334. DECLARE_API( apic )
  335. /*++
  336. Routine Description:
  337. Dumps local apic
  338. Arguments:
  339. args - Supplies the address in hex.
  340. Return Value:
  341. None
  342. --*/
  343. {
  344. static PUCHAR divbase[] = { "2", "4", "8", "f" };
  345. static PUCHAR clktype[] = { "clk", "tmbase", "%s/%s", "??%s/%s" };
  346. ULONG64 Address;
  347. ULONG result, junk, l, ll, lh, clkvec;
  348. UCHAR s[40];
  349. INIT_API();
  350. if (TargetMachine == IMAGE_FILE_MACHINE_IA64) {
  351. ULONG processor;
  352. GetCurrentProcessor(Client, &processor, NULL);
  353. DumpLocalSapic(processor, args);
  354. EXIT_API();
  355. return S_OK;
  356. }
  357. if (TargetMachine != IMAGE_FILE_MACHINE_I386 &&
  358. TargetMachine != IMAGE_FILE_MACHINE_AMD64) {
  359. dprintf("X86 and AMD64 only API.\n");
  360. EXIT_API();
  361. return E_INVALIDARG;
  362. }
  363. if ((Address = GetExpression(args)) == 0) {
  364. //
  365. // Default Apic address
  366. //
  367. Address = 0xfffe0000;
  368. }
  369. if (Address == 0) {
  370. //
  371. // Use default for MPS systems.
  372. //
  373. Address = 0xfffe0000;
  374. }
  375. Address = (ULONG64) (LONG64) (LONG) Address;
  376. if ( !ReadMemoryUncached(
  377. Address + LU_ID_REGISTER,
  378. (PVOID)&junk,
  379. 4,
  380. &result
  381. ) ) {
  382. dprintf("Unable to read lapic\n");
  383. EXIT_API();
  384. return E_INVALIDARG;
  385. }
  386. if ( !ReadMemoryUncached(
  387. Address + LU_DIVIDER_CONFIG,
  388. (PVOID)&junk,
  389. 4,
  390. &result
  391. ) ) {
  392. dprintf("Unable to read lapic\n");
  393. EXIT_API();
  394. return E_INVALIDARG;
  395. }
  396. dprintf ("Apic @ %08x ID:%x (%x) LogDesc:%08x DestFmt:%08x TPR %02X\n",
  397. (ULONG)Address,
  398. ApicRead (Address, LU_ID_REGISTER) >> 24,
  399. ApicRead (Address, LU_VERS_REGISTER),
  400. ApicRead (Address, LU_DEST),
  401. ApicRead (Address, LU_DEST_FORMAT),
  402. ApicRead (Address, LU_TPR)
  403. );
  404. l = ApicRead (Address, LU_SPURIOUS_VECTOR);
  405. ll = ApicRead (Address, LU_DIVIDER_CONFIG);
  406. clkvec = ApicRead (Address, LU_TIMER_VECTOR);
  407. sprintf (s, clktype[ (clkvec >> 18) & 0x3 ],
  408. clktype [ (ll >> 2) & 0x1 ],
  409. divbase [ ll & 0x3]
  410. );
  411. dprintf ("TimeCnt: %08x%s%s SpurVec:%02x FaultVec:%02x error:%x%s\n",
  412. ApicRead (Address, LU_INITIAL_COUNT),
  413. s,
  414. ((clkvec >> 17) & 1) ? "" : "-oneshot",
  415. l & 0xff,
  416. ApicRead (Address, LU_FAULT_VECTOR),
  417. ApicRead (Address, LU_ERROR_STATUS),
  418. l & 0x100 ? "" : " DISABLED"
  419. );
  420. ll = ApicRead (Address, LU_INT_CMD_LOW);
  421. lh = ApicRead (Address, LU_INT_CMD_HIGH);
  422. ApicDumpRedir ("Ipi Cmd", TRUE, FALSE, lh, ll);
  423. ApicDumpRedir ("Timer..", FALSE, TRUE, 0, clkvec);
  424. ApicDumpRedir ("Linti0.", FALSE, TRUE, 0, ApicRead (Address, LU_INT_VECTOR_0));
  425. ApicDumpRedir ("Linti1.", FALSE, TRUE, 0, ApicRead (Address, LU_INT_VECTOR_1));
  426. ApicReadAndDumpBits ("TMR: ", Address, LU_TMR_0);
  427. ApicReadAndDumpBits ("IRR: ", Address, LU_IRR_0);
  428. ApicReadAndDumpBits ("ISR: ", Address, LU_ISR_0);
  429. EXIT_API();
  430. return S_OK;
  431. }
  432. void
  433. DumpIoSApic(
  434. IN LPCSTR Args
  435. )
  436. {
  437. ULONG64 address;
  438. ULONG ioSapicCount;
  439. ULONG index;
  440. ULONG64 apicDebugAddresses;
  441. ULONG apicDebugSize;
  442. ULONG64 apicVirtualAddress;
  443. ULONG64 apicPhysicalAddress;
  444. ULONG ll, lh;
  445. ULONG i, max;
  446. UCHAR s[40];
  447. address = GetExpression("hal!HalpMpInfo");
  448. if (address == 0) {
  449. dprintf("Can't find hal!HalpMpInfo\n");
  450. return;
  451. }
  452. if (GetFieldValue(address, "hal!_MPINFO", "IoSapicCount", ioSapicCount) != 0) {
  453. dprintf("Error reading IoSapicCount\n");
  454. return;
  455. }
  456. address = GetExpression("Hal!HalpApicDebugAddresses");
  457. if (address == 0) {
  458. dprintf("Can't find Hal!HalpApicDebugAddresses\n");
  459. return;
  460. }
  461. if (ReadPtr(address, &apicDebugAddresses) != 0) {
  462. dprintf("Error reading Hal!HalpApicDebugAddresses\n");
  463. return;
  464. }
  465. apicDebugSize = GetTypeSize("hal!_IOAPIC_DEBUG_TABLE");
  466. if (apicDebugSize == 0) {
  467. dprintf("Can't find hal!_IOAPIC_DEBUG_TABLE\n");
  468. return;
  469. }
  470. for (index = 0; index < ioSapicCount; index++) {
  471. GetFieldValue(apicDebugAddresses + (index * apicDebugSize),
  472. "hal!_IOAPIC_DEBUG_TABLE", "IoSapicRegs",
  473. apicVirtualAddress);
  474. apicPhysicalAddress = 0;
  475. GetPhysicalAddress(apicVirtualAddress, &apicPhysicalAddress);
  476. ll = IoSApicRead(apicVirtualAddress, IO_VERS_REGISTER);
  477. dprintf("I/O SAPIC @ %.8X, Version = %.2X (0x%.8X)\n", (ULONG)apicPhysicalAddress, (ll & 0xFF), ll);
  478. max = (ll >> 16) & 0xff;
  479. //
  480. // Dump inti table
  481. //
  482. max *= 2;
  483. for (i = 0; i <= max; i += 2) {
  484. ll = IoSApicRead(apicVirtualAddress, IO_REDIR_BASE + i + 0);
  485. lh = IoSApicRead(apicVirtualAddress, IO_REDIR_BASE + i + 1);
  486. sprintf(s, "Inti%02X", i / 2);
  487. DumpSApicRedir(s, lh, ll);
  488. }
  489. }
  490. }
  491. DECLARE_API( ioapic )
  492. /*++
  493. Routine Description:
  494. Dumps io apic
  495. Arguments:
  496. args - Supplies the address in hex, if no address is specified, all IOApics will be dumped.
  497. Return Value:
  498. None
  499. --*/
  500. {
  501. ULONG64 PhysAddress;
  502. ULONG64 Address;
  503. ULONG i, ll, lh, max, IOApicCount;
  504. UCHAR s[40];
  505. BOOLEAN Converted;
  506. ULONG64 addr;
  507. UCHAR count;
  508. INIT_API();
  509. if (TargetMachine == IMAGE_FILE_MACHINE_IA64) {
  510. DumpIoSApic(args);
  511. EXIT_API();
  512. return S_OK;
  513. }
  514. if (TargetMachine != IMAGE_FILE_MACHINE_I386 &&
  515. TargetMachine != IMAGE_FILE_MACHINE_AMD64) {
  516. dprintf("X86 or AMD64 only API.\n");
  517. EXIT_API();
  518. return E_INVALIDARG;
  519. }
  520. Address = GetExpression(args);
  521. Converted = GetPhysicalAddress (Address, &PhysAddress);
  522. if (Converted) {
  523. IOApicCount = 1;
  524. } else {
  525. //
  526. // Get a copy of the global data structure Hal!HalpMpInfoTable.
  527. //
  528. addr = GetExpression("Hal!HalpMpInfoTable");
  529. if (addr == 0) {
  530. dprintf ("Error retrieving address of HalpMpInfoTable\n");
  531. EXIT_API();
  532. return E_INVALIDARG;
  533. }
  534. if (InitTypeRead(addr, Hal!HalpMpInfo)) {
  535. dprintf ("Error reading HalpMpInfoTable\n");
  536. EXIT_API();
  537. return E_INVALIDARG;
  538. }
  539. IOApicCount = (ULONG) ReadField(IOApicCount);
  540. Address = ReadField(IoApicBase[0]);
  541. Converted = GetPhysicalAddress ( Address, &PhysAddress);
  542. }
  543. for (count = 0; count < IOApicCount; count++) {
  544. ll = IoApicRead (PhysAddress, IO_VERS_REGISTER),
  545. max = (ll >> 16) & 0xff;
  546. dprintf ("IoApic @ %08x ID:%x (%x) Arb:%x\n",
  547. (ULONG)Address,
  548. IoApicRead (PhysAddress, IO_ID_REGISTER) >> 24,
  549. ll & 0xFF,
  550. IoApicRead (PhysAddress, IO_ARB_ID_REGISTER)
  551. );
  552. //
  553. // Dump inti table
  554. //
  555. max *= 2;
  556. for (i=0; i <= max; i += 2) {
  557. ll = IoApicRead (PhysAddress, IO_REDIR_BASE+i+0);
  558. lh = IoApicRead (PhysAddress, IO_REDIR_BASE+i+1);
  559. sprintf (s, "Inti%02X.", i/2);
  560. ApicDumpRedir (s, FALSE, FALSE, lh, ll);
  561. }
  562. //
  563. // Get the next IoApic Virtual Address, convert it to Physical
  564. // and break if this conversion fails.
  565. //
  566. Address = ReadField(IoApicBase[count+1]);
  567. Converted = GetPhysicalAddress ( Address, &PhysAddress);
  568. if (!Converted) {
  569. break;
  570. }
  571. dprintf ("\n");
  572. }
  573. EXIT_API();
  574. return S_OK;
  575. }
  576. DECLARE_API( sendnmi )
  577. /*++
  578. Routine Description:
  579. Send an IPI to the processors in the argument bitmask (affinity).
  580. (Used for debugging when a processor is spinning with interrupts
  581. disabled).
  582. Arguments:
  583. KAFFINITY BitMask Supplied a mask of processors to send the
  584. IPI to.
  585. Return Value:
  586. Success.
  587. --*/
  588. {
  589. ULONG64 Address;
  590. ULONG64 ApicAddress;
  591. UCHAR MaxProcsPerCluster;
  592. ULONG i;
  593. ULONG64 TargetSet;
  594. ULONG64 ActiveProcessors;
  595. ULONG Length;
  596. ULONG ApicDWord;
  597. ULONG junk;
  598. //
  599. // APIC/XAPIC machines only.
  600. // This should be doable on IA64 and AMD64 as well but I don't know
  601. // how at time of writing. PeterJ.
  602. //
  603. if (TargetMachine != IMAGE_FILE_MACHINE_I386) {
  604. dprintf("Sorry, only know how to send NMI on an APIC machine.\n");
  605. return E_INVALIDARG;
  606. }
  607. if (strstr(args, "?") ||
  608. ((TargetSet = GetExpression(args)) == 0)) {
  609. dprintf("usage: sendnmi bitmask\n"
  610. " where bitmask is the set of processors an NMI\n"
  611. " is to be sent to.\n");
  612. return E_INVALIDARG;
  613. }
  614. //
  615. // See if we can get the cluster mode from the HAL.
  616. // (On AMD64 and IA64, this information would be in the kernel).
  617. //
  618. Address = GetExpression("hal!HalpMaxProcsPerCluster");
  619. if (!Address) {
  620. dprintf("Unable to get APIC configuration information from the HAL\n");
  621. dprintf("Cannot continue.\n");
  622. return E_INVALIDARG;
  623. }
  624. if (!ReadMemoryUncached(Address,
  625. &MaxProcsPerCluster,
  626. sizeof(MaxProcsPerCluster),
  627. &i) || (i != sizeof(MaxProcsPerCluster))) {
  628. dprintf("Unable to read system memory, quitting.\n");
  629. return E_INVALIDARG;
  630. }
  631. Address = GetExpression("nt!KeActiveProcessors");
  632. Length = GetTypeSize("nt!KeActiveProcessors");
  633. if ((!Address) || (!((Length == 4) || (Length == 8)))) {
  634. dprintf("Unable to get processor configuration from kernel\n");
  635. dprintf("Cannot continue.\n");
  636. return E_INVALIDARG;
  637. }
  638. ActiveProcessors = 0;
  639. if (!ReadMemoryUncached(Address,
  640. &ActiveProcessors,
  641. Length,
  642. &i) || (i != Length) || (ActiveProcessors == 0)) {
  643. dprintf("Unable to read processor configuration from kernel.\n");
  644. dprintf("Cannot continue.\n");
  645. return E_INVALIDARG;
  646. }
  647. if ((TargetSet & ActiveProcessors) != TargetSet) {
  648. dprintf("Target processor set (%I64x) contains processors not in\n"
  649. "system processor set (%I64x).\n",
  650. TargetSet,
  651. ActiveProcessors);
  652. dprintf("Cannot continue.\n");
  653. return E_INVALIDARG;
  654. }
  655. ApicAddress = 0xfffe0000;
  656. ApicAddress = (ULONG64) (LONG64) (LONG) ApicAddress;
  657. if ((!ReadMemoryUncached(ApicAddress,
  658. &junk,
  659. 1,
  660. &i)) ||
  661. (!ReadMemoryUncached(ApicAddress + LU_SIZE - 1,
  662. &junk,
  663. 1,
  664. &i)) ||
  665. (!ReadMemoryUncached(ApicAddress + LU_INT_CMD_LOW,
  666. &ApicDWord,
  667. sizeof(ApicDWord),
  668. &i)) ||
  669. (i != sizeof(ApicDWord))) {
  670. dprintf("Unable to read lapic\n");
  671. dprintf("Cannot continue.\n");
  672. return E_INVALIDARG;
  673. }
  674. if ((ApicDWord & DELIVERY_PENDING) != 0) {
  675. dprintf("Local APIC is busy, can't use it right now.\n");
  676. dprintf("This is probably indicative of an APIC error.\n");
  677. return E_INVALIDARG;
  678. }
  679. if (MaxProcsPerCluster == 0) {
  680. //
  681. // APIC is not in cluster mode. This makes life easy.
  682. // Sanity: This means there's 8 or less processors.
  683. //
  684. if (TargetSet > 0xff) {
  685. dprintf("APIC is in non-cluster mode thus it cannot support\n"
  686. "more than 8 processors yet the target mask includes\n"
  687. "processors outside that range. Something is not right.\n"
  688. "quitting.\n");
  689. return E_INVALIDARG;
  690. }
  691. dprintf("Sending NMI to processors in set %I64x\n", TargetSet);
  692. ApicDWord = ((ULONG)TargetSet) << DESTINATION_SHIFT;
  693. WriteMemory(ApicAddress + LU_INT_CMD_HIGH,
  694. &ApicDWord,
  695. sizeof(ApicDWord),
  696. &i);
  697. ApicDWord = DELIVER_NMI |
  698. LOGICAL_DESTINATION |
  699. ICR_USE_DEST_FIELD |
  700. NMI_VECTOR;
  701. WriteMemory(ApicAddress + LU_INT_CMD_LOW,
  702. &ApicDWord,
  703. sizeof(ApicDWord),
  704. &i);
  705. dprintf("Sent.\n");
  706. } else {
  707. dprintf("APIC is in cluster mode, don't know how to do this yet.\n");
  708. }
  709. return S_OK;
  710. }