ipi.c 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376
  1. /*++
  2. Copyright (c) 2012 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. ipi.c
  5. Abstract:
  6. This module implements support for Inter-Processor Interrupts (IPIs).
  7. Author:
  8. Evan Green 27-Sep-2012
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/kernel/kernel.h>
  16. #include <minoca/kernel/bootload.h>
  17. #include "intrupt.h"
  18. //
  19. // ---------------------------------------------------------------- Definitions
  20. //
  21. //
  22. // Set this flag if the processor is present and can be started.
  23. //
  24. #define PROCESSOR_ADDRESSING_FLAG_PRESENT 0x00000001
  25. //
  26. // Set this flag if the processor is running.
  27. //
  28. #define PROCESSOR_ADDRESSING_FLAG_STARTED 0x00000002
  29. //
  30. // Define the amount of time to wait for a processor to come online before
  31. // declaring the system toast.
  32. //
  33. #define PROCESSOR_START_GRACE_PERIOD_SECONDS 5
  34. //
  35. // ------------------------------------------------------ Data Type Definitions
  36. //
  37. //
  38. // ----------------------------------------------- Internal Function Prototypes
  39. //
  40. KSTATUS
  41. HlpInterruptSetupIpiLines (
  42. ULONG ProcessorNumber
  43. );
  44. KSTATUS
  45. HlpInterruptFindIpiLine (
  46. PINTERRUPT_CONTROLLER Controller,
  47. PINTERRUPT_LINE Line
  48. );
  49. //
  50. // -------------------------------------------------------------------- Globals
  51. //
  52. //
  53. // Define an override that limits the system to one processor.
  54. //
  55. BOOL HlRunSingleProcessor = FALSE;
  56. //
  57. // Store the maximum number of processors in the system.
  58. //
  59. ULONG HlMaxProcessors = 0;
  60. //
  61. // Store an array defining the addressing mode of each processor, indexed by
  62. // processor number.
  63. //
  64. PPROCESSOR_ADDRESSING HlProcessorTargets = NULL;
  65. //
  66. // Store the array of interrupts for each IPI type.
  67. //
  68. PKINTERRUPT HlIpiKInterrupt[MAX_IPI_LINE_COUNT];
  69. //
  70. // Store the maximum number of processors in the system that can be targeted
  71. // in logical flat mode.
  72. //
  73. ULONG HlLogicalFlatLimit = 8;
  74. //
  75. // Store the number of processors per cluster and the maximum number of
  76. // clusters allowed.
  77. //
  78. ULONG HlMaxClusterSize = 4;
  79. ULONG HlMaxClusters = 0xF;
  80. //
  81. // Store a boolean indicating if any processors have been programmed in logical
  82. // clustered mode.
  83. //
  84. BOOL HlLogicalClusteredMode = FALSE;
  85. //
  86. // ------------------------------------------------------------------ Functions
  87. //
  88. KERNEL_API
  89. KSTATUS
  90. HlGetProcessorIndexFromId (
  91. ULONGLONG PhysicalId,
  92. PULONG ProcessorIndex,
  93. PBOOL Active
  94. )
  95. /*++
  96. Routine Description:
  97. This routine attempts to find the logical processor index of the processor
  98. with the given physical identifier.
  99. Arguments:
  100. PhysicalId - Supplies the processor physical identifier.
  101. ProcessorIndex - Supplies a pointer where the processor index will be
  102. returned on success.
  103. Active - Supplies a pointer where a boolean will be returned indicating if
  104. this processor is present and active within the system.
  105. Return Value:
  106. Status code.
  107. --*/
  108. {
  109. ULONG Count;
  110. ULONG Index;
  111. ULONG Mask;
  112. Count = HlMaxProcessors;
  113. if (HlProcessorTargets == NULL) {
  114. return STATUS_NOT_FOUND;
  115. }
  116. Mask = PROCESSOR_ADDRESSING_FLAG_PRESENT |
  117. PROCESSOR_ADDRESSING_FLAG_STARTED;
  118. for (Index = 0; Index < Count; Index += 1) {
  119. if (HlProcessorTargets[Index].PhysicalId == PhysicalId) {
  120. *ProcessorIndex = Index;
  121. *Active = FALSE;
  122. if ((HlProcessorTargets[Index].Flags & Mask) == Mask) {
  123. *Active = TRUE;
  124. }
  125. return STATUS_SUCCESS;
  126. }
  127. }
  128. return STATUS_NOT_FOUND;
  129. }
  130. KSTATUS
  131. HlSendIpi (
  132. IPI_TYPE IpiType,
  133. PPROCESSOR_SET Processors
  134. )
  135. /*++
  136. Routine Description:
  137. This routine sends an Inter-Processor Interrupt (IPI) to the given set of
  138. processors.
  139. Arguments:
  140. IpiType - Supplies the type of IPI to deliver.
  141. Processors - Supplies the set of processors to deliver the IPI to.
  142. Return Value:
  143. Status code.
  144. --*/
  145. {
  146. PINTERRUPT_CONTROLLER Controller;
  147. BOOL Enabled;
  148. PINTERRUPT_LINE IpiLine;
  149. ULONG IpiLineIndex;
  150. ULONG Processor;
  151. KSTATUS Status;
  152. INTERRUPT_HARDWARE_TARGET Target;
  153. ULONG Vector;
  154. ASSERT((KeGetRunLevel() >= RunLevelDispatch) ||
  155. (ArAreInterruptsEnabled() == FALSE));
  156. Processor = KeGetCurrentProcessorNumber();
  157. Controller = HlProcessorTargets[Processor].Controller;
  158. //
  159. // Compute the interrupt target in terms the hardware can understand.
  160. //
  161. switch (Processors->Target) {
  162. case ProcessorTargetNone:
  163. Status = STATUS_SUCCESS;
  164. goto SendIpiEnd;
  165. case ProcessorTargetAll:
  166. Target.Addressing = InterruptAddressingAll;
  167. break;
  168. case ProcessorTargetAllExcludingSelf:
  169. Target.Addressing = InterruptAddressingAllExcludingSelf;
  170. break;
  171. case ProcessorTargetSelf:
  172. Target.Addressing = InterruptAddressingSelf;
  173. break;
  174. case ProcessorTargetSingleProcessor:
  175. Target = HlProcessorTargets[Processors->U.Number].Target;
  176. break;
  177. case ProcessorTargetAny:
  178. default:
  179. ASSERT(FALSE);
  180. Status = STATUS_INVALID_PARAMETER;
  181. goto SendIpiEnd;
  182. }
  183. Vector = HlpInterruptGetIpiVector(IpiType);
  184. IpiLineIndex = HlpInterruptGetIpiLineIndex(IpiType);
  185. IpiLine = &(HlProcessorTargets[Processor].IpiLine[IpiLineIndex]);
  186. Enabled = ArDisableInterrupts();
  187. Status = Controller->FunctionTable.RequestInterrupt(
  188. Controller->PrivateContext,
  189. IpiLine,
  190. Vector,
  191. &Target);
  192. if (Enabled != FALSE) {
  193. ArEnableInterrupts();
  194. }
  195. if (!KSUCCESS(Status)) {
  196. goto SendIpiEnd;
  197. }
  198. SendIpiEnd:
  199. return Status;
  200. }
  201. ULONG
  202. HlGetMaximumProcessorCount (
  203. VOID
  204. )
  205. /*++
  206. Routine Description:
  207. This routine returns the maximum number of logical processors that this
  208. machine supports.
  209. Arguments:
  210. None.
  211. Return Value:
  212. Returns the maximum number of logical processors that may exist in the
  213. system.
  214. --*/
  215. {
  216. return HlMaxProcessors;
  217. }
  218. KSTATUS
  219. HlStartAllProcessors (
  220. PPROCESSOR_START_ROUTINE StartRoutine,
  221. PULONG ProcessorsStarted
  222. )
  223. /*++
  224. Routine Description:
  225. This routine is called on the BSP, and starts all APs.
  226. Arguments:
  227. StartRoutine - Supplies the routine the processors should jump to.
  228. ProcessorsStarted - Supplies a pointer where the number of processors
  229. started will be returned (the total number of processors in the system,
  230. including the boot processor).
  231. Return Value:
  232. Status code.
  233. --*/
  234. {
  235. PVOID Context;
  236. PINTERRUPT_CONTROLLER Controller;
  237. BOOL Enabled;
  238. ULONGLONG GiveUpTime;
  239. ULONG Identifier;
  240. PHYSICAL_ADDRESS PhysicalJumpAddress;
  241. ULONG Processor;
  242. ULONG ProcessorCount;
  243. ULONG ProcessorsLaunched;
  244. PPROCESSOR_START_BLOCK StartBlock;
  245. KSTATUS Status;
  246. Enabled = FALSE;
  247. ProcessorsLaunched = 1;
  248. StartBlock = NULL;
  249. //
  250. // Fire up the identity stub, which is used not only to initialize other
  251. // processors but also to come out during resume.
  252. //
  253. Status = HlpInterruptPrepareIdentityStub();
  254. if (!KSUCCESS(Status)) {
  255. goto StartAllProcessorsEnd;
  256. }
  257. //
  258. // Set up P0's startup page, needed for resume.
  259. //
  260. Status = HlpInterruptPrepareForProcessorStart(0, NULL, NULL, NULL);
  261. if (!KSUCCESS(Status)) {
  262. goto StartAllProcessorsEnd;
  263. }
  264. //
  265. // Don't start any other cores if the debug flag is set.
  266. //
  267. if (HlRunSingleProcessor != FALSE) {
  268. Status = STATUS_SUCCESS;
  269. goto StartAllProcessorsEnd;
  270. }
  271. //
  272. // Bail now if this machine is not multiprocessor capable.
  273. //
  274. ProcessorCount = HlGetMaximumProcessorCount();
  275. if (ProcessorCount == 1) {
  276. Status = STATUS_SUCCESS;
  277. goto StartAllProcessorsEnd;
  278. }
  279. //
  280. // Loop through each processor and start it.
  281. //
  282. for (Processor = 1; Processor < ProcessorCount; Processor += 1) {
  283. //
  284. // Skip this processor if it's not present.
  285. //
  286. if ((HlProcessorTargets[Processor].Flags &
  287. PROCESSOR_ADDRESSING_FLAG_PRESENT) == 0) {
  288. continue;
  289. }
  290. Controller = HlpInterruptGetProcessorController(Processor);
  291. Context = Controller->PrivateContext;
  292. Identifier = HlProcessorTargets[Processor].PhysicalId;
  293. //
  294. // Prepare the kernel for the new processor coming online.
  295. //
  296. StartBlock = KePrepareForProcessorLaunch();
  297. if (StartBlock == NULL) {
  298. Status = STATUS_INSUFFICIENT_RESOURCES;
  299. goto StartAllProcessorsEnd;
  300. }
  301. //
  302. // Perform any architecture specific steps needed to start this
  303. // proessor.
  304. //
  305. Enabled = ArDisableInterrupts();
  306. Status = HlpInterruptPrepareForProcessorStart(Processor,
  307. StartBlock,
  308. StartRoutine,
  309. &PhysicalJumpAddress);
  310. if (!KSUCCESS(Status)) {
  311. goto StartAllProcessorsEnd;
  312. }
  313. //
  314. // Send the command to start the processor.
  315. //
  316. Status = Controller->FunctionTable.StartProcessor(Context,
  317. Identifier,
  318. PhysicalJumpAddress);
  319. if (Enabled != FALSE) {
  320. ArEnableInterrupts();
  321. Enabled = FALSE;
  322. }
  323. if (!KSUCCESS(Status)) {
  324. goto StartAllProcessorsEnd;
  325. }
  326. //
  327. // Figure out when to give up if the processor doesn't come online.
  328. //
  329. GiveUpTime = HlQueryTimeCounter() +
  330. (HlQueryTimeCounterFrequency() *
  331. PROCESSOR_START_GRACE_PERIOD_SECONDS);
  332. //
  333. // Wait for the processor to start up.
  334. //
  335. while (StartBlock->Started == FALSE) {
  336. ArProcessorYield();
  337. if (HlQueryTimeCounter() >= GiveUpTime) {
  338. break;
  339. }
  340. }
  341. if (StartBlock->Started == FALSE) {
  342. KeCrashSystem(CRASH_HARDWARE_LAYER_FAILURE,
  343. HL_CRASH_PROCESSOR_WONT_START,
  344. Processor,
  345. (UINTN)Controller,
  346. (UINTN)&(HlProcessorTargets[Processor]));
  347. }
  348. ProcessorsLaunched += 1;
  349. }
  350. Status = STATUS_SUCCESS;
  351. StartAllProcessorsEnd:
  352. if (Enabled != FALSE) {
  353. ArEnableInterrupts();
  354. }
  355. if (!KSUCCESS(Status)) {
  356. if (StartBlock != NULL) {
  357. KeFreeProcessorStartBlock(StartBlock, TRUE);
  358. StartBlock = NULL;
  359. }
  360. }
  361. *ProcessorsStarted = ProcessorsLaunched;
  362. return Status;
  363. }
  364. KSTATUS
  365. HlpInitializeIpis (
  366. VOID
  367. )
  368. /*++
  369. Routine Description:
  370. This routine initialize IPI support in the system. It is called once on
  371. boot.
  372. Arguments:
  373. None.
  374. Return Value:
  375. Status code.
  376. --*/
  377. {
  378. ULONG AllocationSize;
  379. PINTERRUPT_CONTROLLER Controller;
  380. ULONG ControllerCount;
  381. ULONG ControllerIndex;
  382. PPROCESSOR_DESCRIPTION Descriptions;
  383. ULONG GlobalProcessorIndex;
  384. PIO_BUFFER IoBuffer;
  385. ULONG IoBufferFlags;
  386. ULONG MaxProcessors;
  387. ULONG MaxProcessorsPerUnit;
  388. ULONG NextProcessorIndex;
  389. ULONG Offset;
  390. ULONG PageSize;
  391. PHYSICAL_ADDRESS ParkedAddress;
  392. PVOID ParkedAddressMapping;
  393. PHYSICAL_ADDRESS ParkedAddressPage;
  394. ULONG ProcessorIndex;
  395. KSTATUS Status;
  396. Descriptions = NULL;
  397. PageSize = MmPageSize();
  398. //
  399. // Loop through all controllers once to figure out how many processors the
  400. // largest interrupt controller owns, and the total number of processors.
  401. //
  402. MaxProcessorsPerUnit = 0;
  403. MaxProcessors = 0;
  404. ControllerCount = HlInterruptControllerCount;
  405. for (ControllerIndex = 0;
  406. ControllerIndex < ControllerCount;
  407. ControllerIndex += 1) {
  408. Controller = HlInterruptControllers[ControllerIndex];
  409. if (Controller == NULL) {
  410. continue;
  411. }
  412. MaxProcessors += Controller->ProcessorCount;
  413. if (Controller->ProcessorCount > MaxProcessorsPerUnit) {
  414. MaxProcessorsPerUnit = Controller->ProcessorCount;
  415. }
  416. }
  417. if (MaxProcessors == 0) {
  418. MaxProcessors = 1;
  419. MaxProcessorsPerUnit = 1;
  420. }
  421. //
  422. // Allocate the total processor array, and the temporary processor
  423. // description structure.
  424. //
  425. AllocationSize = MaxProcessors * sizeof(PROCESSOR_ADDRESSING);
  426. HlProcessorTargets = MmAllocateNonPagedPool(AllocationSize, HL_POOL_TAG);
  427. if (HlProcessorTargets == NULL) {
  428. Status = STATUS_INSUFFICIENT_RESOURCES;
  429. goto InitializeIpisEnd;
  430. }
  431. RtlZeroMemory(HlProcessorTargets, AllocationSize);
  432. AllocationSize = MaxProcessorsPerUnit * sizeof(PROCESSOR_DESCRIPTION);
  433. Descriptions = MmAllocateNonPagedPool(AllocationSize, HL_POOL_TAG);
  434. if (Descriptions == NULL) {
  435. Status = STATUS_INSUFFICIENT_RESOURCES;
  436. goto InitializeIpisEnd;
  437. }
  438. RtlZeroMemory(Descriptions, AllocationSize);
  439. //
  440. // Loop through the controllers again and grab the processor enumeration
  441. // info from them.
  442. //
  443. ControllerCount = HlInterruptControllerCount;
  444. NextProcessorIndex = 0;
  445. for (ControllerIndex = 0;
  446. ControllerIndex < ControllerCount;
  447. ControllerIndex += 1) {
  448. Controller = HlInterruptControllers[ControllerIndex];
  449. if ((Controller == NULL) || (Controller->ProcessorCount == 0)) {
  450. continue;
  451. }
  452. ASSERT(Controller->ProcessorCount <= MaxProcessorsPerUnit);
  453. AllocationSize = Controller->ProcessorCount *
  454. sizeof(PROCESSOR_DESCRIPTION);
  455. Status = Controller->FunctionTable.EnumerateProcessors(
  456. Controller->PrivateContext,
  457. Descriptions,
  458. AllocationSize);
  459. if (!KSUCCESS(Status)) {
  460. goto InitializeIpisEnd;
  461. }
  462. ASSERT(NextProcessorIndex + Controller->ProcessorCount <=
  463. MaxProcessors);
  464. //
  465. // Loop through each processor in the returned array and create its
  466. // corresponding IPI target.
  467. //
  468. for (ProcessorIndex = 0;
  469. ProcessorIndex < Controller->ProcessorCount;
  470. ProcessorIndex += 1) {
  471. GlobalProcessorIndex = ProcessorIndex + NextProcessorIndex;
  472. if (Descriptions[ProcessorIndex].Version <
  473. PROCESSOR_DESCRIPTION_VERSION) {
  474. Status = STATUS_VERSION_MISMATCH;
  475. goto InitializeIpisEnd;
  476. }
  477. HlProcessorTargets[GlobalProcessorIndex].PhysicalId =
  478. Descriptions[ProcessorIndex].PhysicalId;
  479. HlProcessorTargets[GlobalProcessorIndex].LogicalFlatId =
  480. Descriptions[ProcessorIndex].LogicalFlatId;
  481. //
  482. // If any processor reports a logical flat ID of 0, then logical
  483. // flat mode is not supported.
  484. //
  485. if (HlProcessorTargets[GlobalProcessorIndex].LogicalFlatId == 0) {
  486. HlLogicalFlatLimit = 0;
  487. }
  488. if ((Descriptions[ProcessorIndex].Flags &
  489. PROCESSOR_DESCRIPTION_FLAG_PRESENT) != 0) {
  490. HlProcessorTargets[GlobalProcessorIndex].Flags |=
  491. PROCESSOR_ADDRESSING_FLAG_PRESENT;
  492. }
  493. ParkedAddress = Descriptions[ProcessorIndex].ParkedPhysicalAddress;
  494. HlProcessorTargets[GlobalProcessorIndex].ParkedPhysicalAddress =
  495. ParkedAddress;
  496. HlProcessorTargets[GlobalProcessorIndex].Controller = Controller;
  497. //
  498. // If non-null, map the parked physical address to a VA.
  499. //
  500. if (ParkedAddress != INVALID_PHYSICAL_ADDRESS) {
  501. ParkedAddressPage = ALIGN_RANGE_DOWN(ParkedAddress, PageSize);
  502. Offset = ParkedAddress - ParkedAddressPage;
  503. ParkedAddressMapping = MmMapPhysicalAddress(ParkedAddressPage,
  504. PageSize,
  505. TRUE,
  506. FALSE,
  507. TRUE);
  508. HlProcessorTargets[GlobalProcessorIndex].ParkedVirtualAddress =
  509. ParkedAddressMapping + Offset;
  510. if (ParkedAddressMapping == NULL) {
  511. Status = STATUS_INSUFFICIENT_RESOURCES;
  512. goto InitializeIpisEnd;
  513. }
  514. }
  515. }
  516. //
  517. // Up the global index.
  518. //
  519. NextProcessorIndex += Controller->ProcessorCount;
  520. }
  521. //
  522. // Make up a page for P0 on resume if there was none. The I/O buffer
  523. // structure is leaked since the page is permanent.
  524. //
  525. if (HlProcessorTargets[0].ParkedVirtualAddress == NULL) {
  526. IoBufferFlags = IO_BUFFER_FLAG_PHYSICALLY_CONTIGUOUS |
  527. IO_BUFFER_FLAG_MAP_NON_CACHED |
  528. IO_BUFFER_FLAG_KERNEL_MODE_DATA |
  529. IO_BUFFER_FLAG_MEMORY_LOCKED;
  530. IoBuffer = MmAllocateNonPagedIoBuffer(0,
  531. MAX_ULONG,
  532. PageSize,
  533. PageSize,
  534. IoBufferFlags);
  535. if (IoBuffer == NULL) {
  536. Status = STATUS_INSUFFICIENT_RESOURCES;
  537. goto InitializeIpisEnd;
  538. }
  539. HlProcessorTargets[0].Target.Addressing = InterruptAddressingPhysical;
  540. HlProcessorTargets[0].ParkedPhysicalAddress =
  541. IoBuffer->Fragment[0].PhysicalAddress;
  542. HlProcessorTargets[0].ParkedVirtualAddress =
  543. IoBuffer->Fragment[0].VirtualAddress;
  544. }
  545. Status = STATUS_SUCCESS;
  546. InitializeIpisEnd:
  547. if (KSUCCESS(Status)) {
  548. HlMaxProcessors = MaxProcessors;
  549. } else {
  550. if (HlProcessorTargets != NULL) {
  551. MmFreeNonPagedPool(HlProcessorTargets);
  552. }
  553. }
  554. if (Descriptions != NULL) {
  555. MmFreeNonPagedPool(Descriptions);
  556. }
  557. return Status;
  558. }
  559. KSTATUS
  560. HlpSetupProcessorAddressing (
  561. ULONG Identifier
  562. )
  563. /*++
  564. Routine Description:
  565. This routine prepares the system to receive IPIs on the current processor.
  566. Arguments:
  567. Identifier - Supplies the physical identifier of the processor's local unit.
  568. Return Value:
  569. Status code.
  570. --*/
  571. {
  572. PINTERRUPT_CONTROLLER Controller;
  573. PVOID PrivateContext;
  574. ULONG ProcessorIndex;
  575. ULONG SearchIndex;
  576. PINTERRUPT_SET_LOCAL_UNIT_ADDRESSING SetAddressing;
  577. KSTATUS Status;
  578. PROCESSOR_ADDRESSING SwapSpace;
  579. PINTERRUPT_HARDWARE_TARGET Targeting;
  580. //
  581. // Return immediately if there's only one processor in the system
  582. // (or in the special case of P0 the first go-round, that IPIs have not
  583. // been set up).
  584. //
  585. if (HlProcessorTargets == NULL) {
  586. return STATUS_SUCCESS;
  587. }
  588. //
  589. // Make sure that this processor is in the correct index.
  590. //
  591. ProcessorIndex = KeGetCurrentProcessorNumber();
  592. if (HlProcessorTargets[ProcessorIndex].PhysicalId != Identifier) {
  593. //
  594. // Go find this processor.
  595. //
  596. for (SearchIndex = 0; SearchIndex < HlMaxProcessors; SearchIndex += 1) {
  597. if (HlProcessorTargets[SearchIndex].PhysicalId == Identifier) {
  598. //
  599. // Crash if either of these processors are already started.
  600. //
  601. if (((HlProcessorTargets[ProcessorIndex].Flags &
  602. PROCESSOR_ADDRESSING_FLAG_STARTED) != 0) ||
  603. ((HlProcessorTargets[SearchIndex].Flags &
  604. PROCESSOR_ADDRESSING_FLAG_STARTED) != 0)) {
  605. KeCrashSystem(CRASH_HARDWARE_LAYER_FAILURE,
  606. HL_CRASH_PROCESSOR_INDEXING_ERROR,
  607. ProcessorIndex,
  608. HlProcessorTargets[ProcessorIndex].PhysicalId,
  609. Identifier);
  610. }
  611. //
  612. // Swap the two processors.
  613. //
  614. RtlCopyMemory(&SwapSpace,
  615. &(HlProcessorTargets[SearchIndex]),
  616. sizeof(PROCESSOR_ADDRESSING));
  617. RtlCopyMemory(&(HlProcessorTargets[SearchIndex]),
  618. &(HlProcessorTargets[ProcessorIndex]),
  619. sizeof(PROCESSOR_ADDRESSING));
  620. RtlCopyMemory(&(HlProcessorTargets[ProcessorIndex]),
  621. &SwapSpace,
  622. sizeof(PROCESSOR_ADDRESSING));
  623. break;
  624. }
  625. }
  626. //
  627. // Crash if the processor wasn't found.
  628. //
  629. if (SearchIndex == HlMaxProcessors) {
  630. KeCrashSystem(CRASH_HARDWARE_LAYER_FAILURE,
  631. HL_CRASH_PROCESSOR_INDEXING_ERROR,
  632. 0xFFFFFFFF,
  633. ProcessorIndex,
  634. Identifier);
  635. }
  636. }
  637. Controller = HlProcessorTargets[ProcessorIndex].Controller;
  638. SetAddressing = Controller->FunctionTable.SetLocalUnitAddressing;
  639. PrivateContext = Controller->PrivateContext;
  640. Targeting = &(HlProcessorTargets[ProcessorIndex].Target);
  641. //
  642. // If this processor has already been started, then setup the local unit
  643. // addressing (which must succeed) and finish.
  644. //
  645. if ((HlProcessorTargets[ProcessorIndex].Flags &
  646. PROCESSOR_ADDRESSING_FLAG_STARTED) != 0) {
  647. Status = SetAddressing(PrivateContext, Targeting);
  648. goto SetupProcessorAddressingEnd;
  649. }
  650. //
  651. // Attempt to program the system in logical flat mode if the number of
  652. // processors is below the limit.
  653. //
  654. Status = STATUS_NOT_SUPPORTED;
  655. if ((HlMaxProcessors < HlLogicalFlatLimit) &&
  656. (HlLogicalClusteredMode == FALSE)) {
  657. ASSERT(HlLogicalFlatLimit <= 32);
  658. Targeting->Addressing = InterruptAddressingLogicalFlat;
  659. Targeting->U.LogicalFlatId =
  660. HlProcessorTargets[ProcessorIndex].LogicalFlatId;
  661. Status = SetAddressing(PrivateContext, Targeting);
  662. }
  663. //
  664. // If logical flat mode was a no-go, try for logical clustered mode.
  665. //
  666. if ((!KSUCCESS(Status)) &&
  667. (ProcessorIndex < HlMaxClusters * HlMaxClusterSize)) {
  668. Targeting->Addressing = InterruptAddressingLogicalClustered;
  669. Targeting->U.Cluster.Id = Targeting->U.PhysicalId / HlMaxClusterSize;
  670. Targeting->U.Cluster.Mask =
  671. 1 << (Targeting->U.PhysicalId % HlMaxClusterSize);
  672. Status = SetAddressing(PrivateContext, Targeting);
  673. //
  674. // If this worked, remember that a processor somewhere is programmed
  675. // to logical clustered mode (mixing of logical flat and logical
  676. // clustered is illegal).
  677. //
  678. if (KSUCCESS(Status)) {
  679. HlLogicalClusteredMode = TRUE;
  680. }
  681. }
  682. //
  683. // If logical clustered mode was a no-go, target physically. This must
  684. // succeed.
  685. //
  686. if (!KSUCCESS(Status)) {
  687. Targeting->Addressing = InterruptAddressingPhysical;
  688. Targeting->U.PhysicalId = HlProcessorTargets[ProcessorIndex].PhysicalId;
  689. Status = SetAddressing(PrivateContext, Targeting);
  690. if (!KSUCCESS(Status)) {
  691. KeCrashSystem(CRASH_HARDWARE_LAYER_FAILURE,
  692. HL_CRASH_SET_PROCESSOR_ADDRESSING_FAILURE,
  693. ProcessorIndex,
  694. Targeting->U.PhysicalId,
  695. Status);
  696. }
  697. }
  698. //
  699. // Set up the IPI lines on this processor.
  700. //
  701. Status = HlpInterruptSetupIpiLines(ProcessorIndex);
  702. if (!KSUCCESS(Status)) {
  703. goto SetupProcessorAddressingEnd;
  704. }
  705. //
  706. // Mark this processor as started, as it can now be IPIed.
  707. //
  708. HlProcessorTargets[ProcessorIndex].Flags |=
  709. PROCESSOR_ADDRESSING_FLAG_STARTED;
  710. SetupProcessorAddressingEnd:
  711. return Status;
  712. }
  713. PINTERRUPT_CONTROLLER
  714. HlpInterruptGetCurrentProcessorController (
  715. VOID
  716. )
  717. /*++
  718. Routine Description:
  719. This routine returns the interrupt controller that owns the current
  720. processor.
  721. Arguments:
  722. None.
  723. Return Value:
  724. Returns a pointer to the interrupt controller responsible for this
  725. processor.
  726. NULL on a non-multiprocessor capable machine.
  727. --*/
  728. {
  729. return HlpInterruptGetProcessorController(KeGetCurrentProcessorNumber());
  730. }
  731. PINTERRUPT_CONTROLLER
  732. HlpInterruptGetProcessorController (
  733. ULONG ProcessorIndex
  734. )
  735. /*++
  736. Routine Description:
  737. This routine returns the interrupt controller that owns the given processor.
  738. Arguments:
  739. ProcessorIndex - Supplies the zero-based index of the processor whose
  740. interrupt controller is desired.
  741. Return Value:
  742. Returns a pointer to the interrupt controller responsible for the given
  743. processor.
  744. NULL on a non-multiprocessor capable machine.
  745. --*/
  746. {
  747. //
  748. // Bail if this is a uniprocessor machine.
  749. //
  750. if (HlProcessorTargets == NULL) {
  751. return NULL;
  752. }
  753. return HlProcessorTargets[ProcessorIndex].Controller;
  754. }
  755. KSTATUS
  756. HlpInterruptConvertProcessorSetToInterruptTarget (
  757. PPROCESSOR_SET ProcessorSet,
  758. PINTERRUPT_HARDWARE_TARGET Target
  759. )
  760. /*++
  761. Routine Description:
  762. This routine converts a generic processor set into an interrupt target.
  763. It may not be possible to target the interrupt at all processors specified,
  764. this routine will do what it can. On success, at least one processor in
  765. the set will be targeted. This routine will not target interrupts at a
  766. processor not mentioned in the set.
  767. This routine must be run at dispatch level or above.
  768. Arguments:
  769. ProcessorSet - Supplies a pointer to the processor set.
  770. Target - Supplies a pointer where the interrupt hardware target will be
  771. returned.
  772. Return Value:
  773. Status code.
  774. --*/
  775. {
  776. ULONG Processor;
  777. KSTATUS Status;
  778. RtlZeroMemory(Target, sizeof(INTERRUPT_HARDWARE_TARGET));
  779. switch (ProcessorSet->Target) {
  780. case ProcessorTargetAny:
  781. //
  782. // If the processor targets are not even initialized then this is a
  783. // simple uniprocessor machine.
  784. //
  785. if (HlProcessorTargets == NULL) {
  786. Target->Addressing = InterruptAddressingPhysical;
  787. Target->U.PhysicalId = 0;
  788. //
  789. // If the interrupt is targeted at "any" processor, try to set the
  790. // largest set of processors given the mode.
  791. //
  792. } else if (HlLogicalClusteredMode != FALSE) {
  793. Target->Addressing = InterruptAddressingLogicalClustered;
  794. ASSERT(HlProcessorTargets[0].Target.Addressing ==
  795. InterruptAddressingLogicalClustered);
  796. Target->U.Cluster.Id = HlProcessorTargets[0].Target.U.Cluster.Id;
  797. Target->U.Cluster.Mask =
  798. HlProcessorTargets[0].Target.U.Cluster.Mask;
  799. //
  800. // Add every started processor in P0's cluster.
  801. //
  802. Processor = 1;
  803. while ((Processor < HlMaxProcessors) &&
  804. ((HlProcessorTargets[Processor].Flags &
  805. PROCESSOR_ADDRESSING_FLAG_STARTED) != 0) &&
  806. (HlProcessorTargets[Processor].Target.Addressing ==
  807. InterruptAddressingLogicalClustered) &&
  808. (HlProcessorTargets[Processor].Target.U.Cluster.Id ==
  809. Target->U.Cluster.Id)) {
  810. Target->U.Cluster.Mask |=
  811. HlProcessorTargets[Processor].Target.U.Cluster.Mask;
  812. Processor += 1;
  813. }
  814. //
  815. // Use logical flat mode.
  816. //
  817. } else if (HlProcessorTargets[0].Target.Addressing ==
  818. InterruptAddressingLogicalFlat) {
  819. Target->Addressing = InterruptAddressingLogicalFlat;
  820. Target->U.LogicalFlatId =
  821. HlProcessorTargets[0].Target.U.LogicalFlatId;
  822. //
  823. // Add every started processor's logical flat bit into the mix as
  824. // well.
  825. //
  826. Processor = 1;
  827. while ((Processor < HlMaxProcessors) &&
  828. ((HlProcessorTargets[Processor].Flags &
  829. PROCESSOR_ADDRESSING_FLAG_STARTED) != 0) &&
  830. (HlProcessorTargets[Processor].Target.Addressing ==
  831. InterruptAddressingLogicalFlat)) {
  832. Target->U.LogicalFlatId |=
  833. HlProcessorTargets[Processor].Target.U.LogicalFlatId;
  834. Processor += 1;
  835. }
  836. //
  837. // Use physical mode, just aimed at P0.
  838. //
  839. } else {
  840. ASSERT(HlProcessorTargets[0].Target.Addressing ==
  841. InterruptAddressingPhysical);
  842. Target->Addressing = InterruptAddressingPhysical;
  843. Target->U.PhysicalId = HlProcessorTargets[0].Target.U.PhysicalId;
  844. }
  845. break;
  846. case ProcessorTargetAll:
  847. Target->Addressing = InterruptAddressingAll;
  848. break;
  849. case ProcessorTargetAllExcludingSelf:
  850. Target->Addressing = InterruptAddressingAllExcludingSelf;
  851. break;
  852. case ProcessorTargetSelf:
  853. Processor = KeGetCurrentProcessorNumber();
  854. if (HlProcessorTargets == NULL) {
  855. Target->Addressing = InterruptAddressingSelf;
  856. } else {
  857. *Target = HlProcessorTargets[Processor].Target;
  858. }
  859. break;
  860. case ProcessorTargetSingleProcessor:
  861. if (HlProcessorTargets == NULL) {
  862. ASSERT(ProcessorSet->U.Number == KeGetCurrentProcessorNumber());
  863. Target->Addressing = InterruptAddressingSelf;
  864. } else {
  865. *Target = HlProcessorTargets[ProcessorSet->U.Number].Target;
  866. }
  867. break;
  868. case ProcessorTargetNone:
  869. default:
  870. Status = STATUS_INVALID_PARAMETER;
  871. goto InterruptConvertProcessorSetToInterruptTargetEnd;
  872. }
  873. Status = STATUS_SUCCESS;
  874. InterruptConvertProcessorSetToInterruptTargetEnd:
  875. return Status;
  876. }
  877. //
  878. // --------------------------------------------------------- Internal Functions
  879. //
  880. KSTATUS
  881. HlpInterruptSetupIpiLines (
  882. ULONG ProcessorNumber
  883. )
  884. /*++
  885. Routine Description:
  886. This routine attempts to find interrupt lines suitable for sending IPIs.
  887. Arguments:
  888. ProcessorNumber - Supplies a pointer to the processor being set up.
  889. Return Value:
  890. STATUS_SUCCESS on success.
  891. STATUS_NO_ELIGIBLE_DEVICES if no suitable lines could be found.
  892. --*/
  893. {
  894. PINTERRUPT_CONTROLLER Controller;
  895. PINTERRUPT_LINE IpiLines;
  896. ULONG LineCount;
  897. ULONG LineIndex;
  898. INTERRUPT_LINE_STATE State;
  899. KSTATUS Status;
  900. PROCESSOR_SET Target;
  901. Controller = HlProcessorTargets[ProcessorNumber].Controller;
  902. IpiLines = HlProcessorTargets[ProcessorNumber].IpiLine;
  903. //
  904. // If this processor has the same controller as P0 (and isn't NULL), copy
  905. // P0's values.
  906. //
  907. if ((ProcessorNumber != 0) &&
  908. (IpiLines[0].Type == InterruptLineInvalid) &&
  909. (HlProcessorTargets[ProcessorNumber].Controller ==
  910. HlProcessorTargets[0].Controller)) {
  911. RtlCopyMemory(&(HlProcessorTargets[ProcessorNumber].IpiLine),
  912. &(HlProcessorTargets[0].IpiLine),
  913. sizeof(HlProcessorTargets[0].IpiLine));
  914. }
  915. //
  916. // Determine how many lines this architecture needs.
  917. //
  918. LineCount = HlpInterruptGetRequiredIpiLineCount();
  919. //
  920. // Loop through each needed IPI line.
  921. //
  922. for (LineIndex = 0; LineIndex < LineCount; LineIndex += 1) {
  923. //
  924. // Find a line if this processor/controller is just getting set up for
  925. // the first time.
  926. //
  927. if (IpiLines[LineIndex].Type == InterruptLineInvalid) {
  928. Status = HlpInterruptFindIpiLine(Controller,
  929. &(IpiLines[LineIndex]));
  930. if (!KSUCCESS(Status)) {
  931. goto InterruptFindIpiLinesEnd;
  932. }
  933. }
  934. //
  935. // Configure the line for use.
  936. //
  937. Target.Target = ProcessorTargetAll;
  938. State.Mode = InterruptModeUnknown;
  939. State.Polarity = InterruptActiveLevelUnknown;
  940. State.Flags = INTERRUPT_LINE_STATE_FLAG_ENABLED;
  941. HlpInterruptGetStandardCpuLine(&(State.Output));
  942. Status = HlpInterruptSetLineState(&(IpiLines[LineIndex]),
  943. &State,
  944. HlIpiKInterrupt[LineIndex],
  945. &Target,
  946. NULL,
  947. 0);
  948. if (!KSUCCESS(Status)) {
  949. goto InterruptFindIpiLinesEnd;
  950. }
  951. }
  952. Status = STATUS_SUCCESS;
  953. InterruptFindIpiLinesEnd:
  954. return Status;
  955. }
  956. KSTATUS
  957. HlpInterruptFindIpiLine (
  958. PINTERRUPT_CONTROLLER Controller,
  959. PINTERRUPT_LINE Line
  960. )
  961. /*++
  962. Routine Description:
  963. This routine attempts to find an interrupt line suitable for sending IPIs.
  964. Arguments:
  965. Controller - Supplies a pointer to the interrupt controller to search.
  966. Line - Supplies a pointer that receives the line to use for IPIs.
  967. Return Value:
  968. STATUS_SUCCESS on success.
  969. STATUS_NO_ELIGIBLE_DEVICES if no suitable lines could be found.
  970. --*/
  971. {
  972. PLIST_ENTRY CurrentEntry;
  973. ULONG LineCount;
  974. ULONG LineIndex;
  975. PINTERRUPT_LINES Lines;
  976. PINTERRUPT_LINE_INTERNAL_STATE State;
  977. //
  978. // Loop through looking for software-only lines.
  979. //
  980. CurrentEntry = Controller->LinesHead.Next;
  981. while (CurrentEntry != &(Controller->LinesHead)) {
  982. Lines = LIST_VALUE(CurrentEntry, INTERRUPT_LINES, ListEntry);
  983. CurrentEntry = CurrentEntry->Next;
  984. if (Lines->Type == InterruptLinesSoftwareOnly) {
  985. State = Lines->State;
  986. LineCount = Lines->LineEnd - Lines->LineStart;
  987. //
  988. // Loop through looking for a free line in this segment.
  989. //
  990. for (LineIndex = 0; LineIndex < LineCount; LineIndex += 1) {
  991. if ((State[LineIndex].Flags &
  992. INTERRUPT_LINE_INTERNAL_STATE_FLAG_RESERVED) == 0) {
  993. Line->Type = InterruptLineControllerSpecified;
  994. Line->U.Local.Controller = Controller->Identifier;
  995. Line->U.Local.Line = Lines->LineStart + LineIndex;
  996. return STATUS_SUCCESS;
  997. }
  998. }
  999. }
  1000. }
  1001. Line->Type = InterruptLineInvalid;
  1002. return STATUS_NO_ELIGIBLE_DEVICES;
  1003. }