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.

692 lines
16 KiB

  1. /*++
  2. Module Name:
  3. mpsyssup.c
  4. Abstract:
  5. This file contains APIC-related funtions that are
  6. specific to halmps. The functions that can be
  7. shared with the APIC version of the ACPI HAL are
  8. still in mpsys.c.
  9. Author:
  10. Ron Mosgrove (Intel)
  11. Environment:
  12. Kernel mode only.
  13. Revision History:
  14. Jake Oshins - 10-20-97 - split off from mpsys.c
  15. */
  16. #include "halp.h"
  17. #include "apic.inc"
  18. #include "acpi_mp.inc"
  19. #include "acpitabl.h"
  20. #include "ntacpi.h"
  21. extern ULONG HalpPicVectorRedirect[];
  22. extern ULONG HalpPicVectorFlags[];
  23. extern FADT HalpFixedAcpiDescTable;
  24. extern PVOID *HalpLocalNmiSources;
  25. extern UCHAR HalpMaxProcs;
  26. #define ISA_PIC_VECTORS 16
  27. UCHAR HalpIoApicId[MAX_IOAPICS];
  28. #ifdef ALLOC_PRAGMA
  29. #pragma alloc_text(INIT, HalpInitIntiInfo)
  30. #pragma alloc_text(PAGELK, HalpGetApicInterruptDesc)
  31. #pragma alloc_text(PAGELK, HalpEnableLocalNmiSources)
  32. #pragma alloc_text(PAGE, HaliSetVectorState)
  33. #pragma alloc_text(PAGE, HaliIsVectorValid)
  34. #endif
  35. VOID
  36. HalpInitIntiInfo (
  37. VOID
  38. )
  39. /*++
  40. Routine Description:
  41. This function is called at initialization time before any interrupts
  42. are connected. It reads the PC+MP Inti table and builds internal
  43. information needed to route each Inti.
  44. Return Value:
  45. The following structures are filled in:
  46. HalpIntiInfo
  47. HalpSourceIrqIds
  48. HalpSourceIrqMapping
  49. HalpISAIqpToVector
  50. --*/
  51. {
  52. ULONG ApicNo, BusNo, InterruptInput, IdIndex, ProcNo;
  53. ULONG i, id;
  54. USHORT rtcInti, sciInti;
  55. UCHAR Level, Polarity;
  56. BOOLEAN found;
  57. //
  58. // Clear IntiInfo table. Assume to begin with that
  59. // all interrupts are active-low, level-triggered.
  60. //
  61. for (i=0; i < MAX_INTI; i++) {
  62. HalpIntiInfo[i].Type = INT_TYPE_INTR;
  63. HalpIntiInfo[i].Level = CFG_LEVEL;
  64. HalpIntiInfo[i].Polarity = POLARITY_LOW;
  65. }
  66. //
  67. // Set up the RTC inti with the right flags from
  68. // the redirection table.
  69. //
  70. found = HalpGetApicInterruptDesc( DEFAULT_PC_BUS,
  71. 0,
  72. HalpPicVectorRedirect[RTC_IRQ],
  73. &rtcInti
  74. );
  75. if (!found) {
  76. KeBugCheckEx(HAL_INITIALIZATION_FAILED,
  77. 0x3000,
  78. 1,
  79. HalpPicVectorRedirect[RTC_IRQ],
  80. 0);
  81. }
  82. if ((HalpPicVectorFlags[RTC_IRQ] & PO_BITS) == POLARITY_CONFORMS_WITH_BUS) {
  83. //
  84. // The flags indicated "conforms to bus,"
  85. // so this should be active high.
  86. //
  87. HalpIntiInfo[rtcInti].Polarity = POLARITY_HIGH;
  88. } else {
  89. //
  90. // The polarity flags are overriden.
  91. //
  92. HalpIntiInfo[rtcInti].Polarity =
  93. (UCHAR)HalpPicVectorFlags[RTC_IRQ] & PO_BITS;
  94. }
  95. if ((HalpPicVectorFlags[RTC_IRQ] & EL_BITS) == EL_CONFORMS_WITH_BUS) {
  96. //
  97. // The flags indicated "conforms to bus,"
  98. // so this should be edge triggered.
  99. //
  100. HalpIntiInfo[rtcInti].Level = CFG_EDGE;
  101. } else {
  102. //
  103. // The mode flags are overriden.
  104. //
  105. HalpIntiInfo[rtcInti].Level =
  106. ((UCHAR)(HalpPicVectorFlags[RTC_IRQ] & EL_BITS) == EL_EDGE_TRIGGERED ?
  107. CFG_EDGE : CFG_LEVEL);
  108. }
  109. //
  110. //
  111. // Set up the SCI inti with the right flags from
  112. // the redirection table.
  113. //
  114. found = HalpGetApicInterruptDesc( DEFAULT_PC_BUS,
  115. 0,
  116. HalpPicVectorRedirect[HalpFixedAcpiDescTable.sci_int_vector],
  117. &sciInti
  118. );
  119. if (!found) {
  120. KeBugCheckEx(HAL_INITIALIZATION_FAILED,
  121. 0x3000,
  122. 2,
  123. HalpPicVectorRedirect[HalpFixedAcpiDescTable.sci_int_vector],
  124. 0);
  125. }
  126. if ((HalpPicVectorFlags[HalpFixedAcpiDescTable.sci_int_vector]
  127. & PO_BITS) == POLARITY_CONFORMS_WITH_BUS) {
  128. //
  129. // The flags indicated "conforms to bus,"
  130. // so this should default to the ACPI spec (active low.)
  131. //
  132. HalpIntiInfo[sciInti].Polarity = POLARITY_LOW;
  133. } else {
  134. //
  135. // The polarity flags are overriden.
  136. //
  137. HalpIntiInfo[sciInti].Polarity =
  138. (UCHAR)HalpPicVectorFlags[HalpFixedAcpiDescTable.sci_int_vector] & PO_BITS;
  139. }
  140. if (((HalpPicVectorFlags[HalpFixedAcpiDescTable.sci_int_vector] & EL_BITS) ==
  141. EL_CONFORMS_WITH_BUS) ||
  142. ((HalpPicVectorFlags[HalpFixedAcpiDescTable.sci_int_vector] & EL_BITS) ==
  143. EL_LEVEL_TRIGGERED)) {
  144. //
  145. // The flags indicated "conforms to bus,"
  146. // so this should be level-triggered.
  147. //
  148. HalpIntiInfo[sciInti].Level = CFG_LEVEL;
  149. } else {
  150. //
  151. // The SCI cannot be edge-triggered.
  152. //
  153. KeBugCheckEx(ACPI_BIOS_ERROR,
  154. 0x10008,
  155. HalpFixedAcpiDescTable.sci_int_vector,
  156. 0,
  157. 0);
  158. }
  159. // Make sure there aren't more Inti lines than we can support
  160. //
  161. InterruptInput = 0;
  162. for (i=0; i < MAX_IOAPICS; i++) {
  163. InterruptInput += HalpMaxApicInti[i];
  164. }
  165. ASSERT (InterruptInput < MAX_INTI);
  166. //
  167. // Fill in the boot processors Apic ID.
  168. //
  169. ApicNo = *(PVULONG)(LOCALAPIC + LU_ID_REGISTER);
  170. ApicNo &= APIC_ID_MASK;
  171. ApicNo >>= APIC_ID_SHIFT;
  172. ((PHALPRCB)KeGetCurrentPrcb()->HalReserved)->PCMPApicID = (UCHAR)ApicNo;
  173. //
  174. // Mark the boot processor as started.
  175. //
  176. for (ProcNo = 0; ProcNo < HalpMpInfoTable.ProcessorCount; ProcNo++) {
  177. if (HalpProcLocalApicTable[ProcNo].ApicID == (UCHAR)ApicNo) {
  178. HalpProcLocalApicTable[ProcNo].Started = TRUE;
  179. HalpProcLocalApicTable[ProcNo].Enumerated = TRUE;
  180. break;
  181. }
  182. }
  183. if (ProcNo == HalpMpInfoTable.ProcessorCount) {
  184. KeBugCheckEx(HAL_INITIALIZATION_FAILED, 0xdead000a, ApicNo, (ULONG_PTR)&HalpProcLocalApicTable, 0);
  185. }
  186. //
  187. // If this is an EISA machine check the ELCR
  188. //
  189. //
  190. // if (HalpBusType == MACHINE_TYPE_EISA) {
  191. // HalpCheckELCR ();
  192. // }
  193. }
  194. BOOLEAN
  195. HalpGetApicInterruptDesc (
  196. IN INTERFACE_TYPE BusType,
  197. IN ULONG BusNumber,
  198. IN ULONG BusInterruptLevel,
  199. OUT PUSHORT PcMpInti
  200. )
  201. /*++
  202. Routine Description:
  203. This procedure gets a "Inti" describing the requested interrupt
  204. Arguments:
  205. BusType - The Bus type as known to the IO subsystem
  206. BusNumber - The number of the Bus we care for
  207. BusInterruptLevel - IRQ on the Bus
  208. Return Value:
  209. TRUE if PcMpInti found; otherwise FALSE.
  210. PcMpInti - A number that describes the interrupt to the HAL.
  211. --*/
  212. {
  213. ULONG i;
  214. ULONG index = 0;
  215. UNREFERENCED_PARAMETER(BusType);
  216. UNREFERENCED_PARAMETER(BusNumber);
  217. for (i = 0; i < HalpMpInfoTable.IOApicCount; i++) {
  218. if ((BusInterruptLevel >=
  219. HalpMpInfoTable.IoApicIntiBase[i]) &&
  220. (BusInterruptLevel <
  221. HalpMpInfoTable.IoApicIntiBase[i] +
  222. HalpMaxApicInti[i])) {
  223. //
  224. // Return value is an offset into the INTI_INFO array. So
  225. // calculate which one it is.
  226. //
  227. *PcMpInti = (USHORT)(index + BusInterruptLevel -
  228. HalpMpInfoTable.IoApicIntiBase[i]);
  229. return TRUE;
  230. }
  231. index += HalpMaxApicInti[i];
  232. }
  233. //
  234. // Not found or search out of range
  235. //
  236. return FALSE;
  237. }
  238. ULONG
  239. HalpGetIoApicId(
  240. ULONG ApicNo
  241. )
  242. {
  243. return (ULONG) HalpIoApicId[ApicNo];
  244. }
  245. ULONG
  246. HalpInti2BusInterruptLevel(
  247. ULONG Inti
  248. )
  249. {
  250. return Inti;
  251. }
  252. VOID
  253. HalpMarkProcessorStarted(
  254. ULONG ApicID,
  255. ULONG NtNumber
  256. )
  257. {
  258. ULONG ProcNo;
  259. for (ProcNo = 0; ProcNo < HalpMpInfoTable.ProcessorCount; ProcNo++) {
  260. if (HalpProcLocalApicTable[ProcNo].ApicID == (UCHAR)ApicID) {
  261. HalpProcLocalApicTable[ProcNo].Started = TRUE;
  262. HalpProcLocalApicTable[ProcNo].NtNumber = (UCHAR) NtNumber;
  263. break;
  264. }
  265. }
  266. }
  267. NTSTATUS
  268. HalpGetNextProcessorApicId(
  269. IN ULONG ProcessorNumber,
  270. IN OUT UCHAR *ApicId
  271. )
  272. /*++
  273. Routine Description:
  274. This function returns an APIC ID of a non-started processor,
  275. which will be started by HalpStartProcessor.
  276. Arguments:
  277. ProcessorNumber - The logical processor number that will
  278. be associated with this APIC ID.
  279. ApicId - pointer to a value to fill in with the APIC ID.
  280. Return Value:
  281. status
  282. --*/
  283. {
  284. UCHAR Proc;
  285. //
  286. // Find a processor that hasn't been enumerated.
  287. //
  288. for (Proc = 0; Proc < HalpMpInfoTable.ProcessorCount; Proc++) {
  289. if (!HalpProcLocalApicTable[Proc].Enumerated) {
  290. break;
  291. }
  292. }
  293. if (Proc == HalpMpInfoTable.ProcessorCount) {
  294. //
  295. // Couldn't find a processor to start.
  296. //
  297. return STATUS_NOT_FOUND;
  298. }
  299. //
  300. // Keep track of this processor.
  301. //
  302. HalpProcLocalApicTable[Proc].Enumerated = TRUE;
  303. *ApicId = HalpProcLocalApicTable[Proc].ApicID;
  304. return STATUS_SUCCESS;
  305. }
  306. NTSTATUS
  307. HalpGetApicIdByProcessorNumber(
  308. IN UCHAR Processor,
  309. IN OUT USHORT *ApicId
  310. )
  311. /*++
  312. Routine Description:
  313. This function returns an APIC ID for a given processor.
  314. It is intended this routine be able to produce the same
  315. APIC ID order as HalpGetNextProcessorApicId.
  316. NOTES: This code is used only by the NUMA code to look up an
  317. ApicID by processor number so that this ApicId can then be looked
  318. up in the SRAT table. A better design would be for the kernel to
  319. ask for this information via ApicID or a opaqued hardware
  320. description provided by the HAL that can be associated with an
  321. ApicID.
  322. Arguments:
  323. Processor - The logical processor number that is
  324. associated with this APIC ID.
  325. ApicId - pointer to a value to fill in with the APIC ID.
  326. Return Value:
  327. status
  328. --*/
  329. {
  330. UCHAR Proc;
  331. LONG Skip;
  332. //
  333. // Run thru the processors that have already been started
  334. // to see if this is on of them.
  335. //
  336. Skip = Processor;
  337. for (Proc = 0; Proc < HalpMpInfoTable.ProcessorCount; Proc++) {
  338. if (HalpProcLocalApicTable[Proc].Started) {
  339. Skip--;
  340. if (HalpProcLocalApicTable[Proc].NtNumber == (UCHAR)Processor) {
  341. *ApicId = (USHORT)HalpProcLocalApicTable[Proc].ApicID;
  342. return STATUS_SUCCESS;
  343. }
  344. }
  345. }
  346. //
  347. // Not amongst the started, rely on the order that processors
  348. // will be started (see HalpGetNextProcessorApicId) to get the
  349. // number.
  350. //
  351. ASSERT(Skip >= 0);
  352. for (Proc = 0; Proc < HalpMpInfoTable.ProcessorCount; Proc++) {
  353. //
  354. // If we've started this processor or if it was enumerated and
  355. // not licensed by the OS, then it isn't a candidate.
  356. //
  357. if (HalpProcLocalApicTable[Proc].Started || HalpProcLocalApicTable[Proc].Enumerated) {
  358. continue;
  359. }
  360. if (Skip == 0) {
  361. //
  362. // Return this processor.
  363. //
  364. *ApicId = (USHORT)HalpProcLocalApicTable[Proc].ApicID;
  365. return STATUS_SUCCESS;
  366. }
  367. Skip--;
  368. }
  369. //
  370. // Couldn't find a processor to start.
  371. //
  372. return STATUS_NOT_FOUND;
  373. }
  374. VOID
  375. HaliSetVectorState(
  376. IN ULONG Vector,
  377. IN ULONG Flags
  378. )
  379. {
  380. BOOLEAN found;
  381. USHORT inti;
  382. ULONG picVector;
  383. UCHAR i;
  384. PAGED_CODE();
  385. found = HalpGetApicInterruptDesc(0, 0, Vector, &inti);
  386. if (!found) {
  387. KeBugCheckEx(ACPI_BIOS_ERROR,
  388. 0x10007,
  389. Vector,
  390. 0,
  391. 0);
  392. }
  393. ASSERT(HalpIntiInfo[inti].Type == INT_TYPE_INTR);
  394. //
  395. // Vector is already translated through
  396. // the PIC vector redirection table. We need
  397. // to make sure that we are honoring the flags
  398. // in the redirection table. So look in the
  399. // table here.
  400. //
  401. for (i = 0; i < PIC_VECTORS; i++) {
  402. if (HalpPicVectorRedirect[i] == Vector) {
  403. picVector = i;
  404. break;
  405. }
  406. }
  407. if (i != PIC_VECTORS) {
  408. //
  409. // Found this vector in the redirection table.
  410. //
  411. if (HalpPicVectorFlags[picVector] != 0) {
  412. //
  413. // And the flags say something other than "conforms
  414. // to bus." So we honor the flags from the table.
  415. //
  416. HalpIntiInfo[inti].Level =
  417. (((HalpPicVectorFlags[picVector] & EL_BITS) == EL_LEVEL_TRIGGERED) ?
  418. CFG_LEVEL : CFG_EDGE);
  419. HalpIntiInfo[inti].Polarity = (UCHAR)(HalpPicVectorFlags[picVector] & PO_BITS);
  420. return;
  421. }
  422. }
  423. //
  424. // This vector is not covered in the table, or it "conforms to bus."
  425. // So we honor the flags passed into this function.
  426. //
  427. if (IS_LEVEL_TRIGGERED(Flags)) {
  428. HalpIntiInfo[inti].Level = CFG_LEVEL;
  429. } else {
  430. HalpIntiInfo[inti].Level = CFG_EDGE;
  431. }
  432. if (IS_ACTIVE_LOW(Flags)) {
  433. HalpIntiInfo[inti].Polarity = POLARITY_LOW;
  434. } else {
  435. HalpIntiInfo[inti].Polarity = POLARITY_HIGH;
  436. }
  437. }
  438. VOID
  439. HalpEnableLocalNmiSources(
  440. VOID
  441. )
  442. /*++
  443. Routine Description:
  444. This routine parses the information from the MAPIC table and
  445. enables any NMI sources in the local APIC of the processor
  446. that it is running on.
  447. Callers of this function must be holding HalpAccountingLock.
  448. Arguments:
  449. Return Value:
  450. --*/
  451. {
  452. PLOCAL_NMISOURCE localSource;
  453. PKPCR pPCR;
  454. UCHAR ThisCpu;
  455. ULONG i;
  456. ULONG modeBits = 0;
  457. pPCR = KeGetPcr();
  458. ThisCpu = CurrentPrcb(pPCR)->Number;
  459. //
  460. // Enable local processor NMI source
  461. //
  462. if (!HalpLocalNmiSources) {
  463. //
  464. // Nobody has cataloged any local NMI sources.
  465. //
  466. return;
  467. }
  468. for (i = 0; i < (ULONG)HalpMaxProcs * 2; i++) {
  469. if (!HalpLocalNmiSources[i]) {
  470. //
  471. // Out of entries.
  472. //
  473. return;
  474. }
  475. localSource = (PLOCAL_NMISOURCE)(HalpLocalNmiSources[i]);
  476. if (((HalpProcLocalApicTable[ThisCpu].NamespaceProcID == localSource->ProcessorID) ||
  477. (localSource->ProcessorID == 0xff) &&
  478. HalpProcLocalApicTable[ThisCpu].Started)) {
  479. //
  480. // This entry corresponds to this processor.
  481. //
  482. modeBits |= ((localSource->Flags & PO_BITS) == POLARITY_LOW) ?
  483. ACTIVE_LOW : ACTIVE_HIGH;
  484. modeBits |= ((localSource->Flags & EL_BITS) == EL_LEVEL_TRIGGERED) ?
  485. LEVEL_TRIGGERED : EDGE_TRIGGERED;
  486. if (localSource->LINTIN == 0) {
  487. pLocalApic[LU_INT_VECTOR_0/4] =
  488. modeBits | DELIVER_NMI | NMI_VECTOR;
  489. } else {
  490. pLocalApic[LU_INT_VECTOR_1/4] =
  491. modeBits | DELIVER_NMI | NMI_VECTOR;
  492. }
  493. }
  494. }
  495. }
  496. BOOLEAN
  497. HaliIsVectorValid(
  498. IN ULONG Vector
  499. )
  500. {
  501. BOOLEAN found;
  502. USHORT inti;
  503. PAGED_CODE();
  504. return HalpGetApicInterruptDesc(0, 0, Vector, &inti);
  505. }