PageRenderTime 57ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/base/Kernel/Singularity/Processor.cs

#
C# | 949 lines | 621 code | 155 blank | 173 comment | 49 complexity | 8d63fa178089da49ccbe7874537108f0 MD5 | raw file
  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Microsoft Research Singularity
  4. //
  5. // Copyright (c) Microsoft Corporation. All rights reserved.
  6. //
  7. // File: Processor.cs
  8. //
  9. // Note:
  10. //
  11. //#define DEBUG_EXCEPTIONS
  12. //#define DEBUG_INTERRUPTS
  13. //#define DEBUG_DISPATCH_TIMER
  14. //#define DEBUG_DISPATCH_IO
  15. //#define CHECK_DISABLE_INTERRUPTS
  16. // #define SINGULARITY_ASMP
  17. using System;
  18. using System.Runtime.InteropServices;
  19. using System.Runtime.CompilerServices;
  20. using System.Threading;
  21. using Microsoft.Singularity.Eventing;
  22. using Microsoft.Singularity.Hal;
  23. using Microsoft.Singularity.Io;
  24. using Microsoft.Singularity.Isal;
  25. using Microsoft.Singularity.Memory;
  26. using Microsoft.Singularity.Scheduling;
  27. using Microsoft.Singularity.V1.Threads;
  28. // For Abi Call
  29. // using Microsoft.Singularity.V1.Services;
  30. namespace Microsoft.Singularity
  31. {
  32. [CLSCompliant(false)]
  33. public enum ProcessorEvent : ushort
  34. {
  35. Exception = 0,
  36. Resume = 1,
  37. Interrupt = 2
  38. }
  39. [CLSCompliant(false)]
  40. [CCtorIsRunDuringStartup]
  41. [AccessedByRuntime("referenced in hal.cpp/processor.cpp")]
  42. public class Processor
  43. {
  44. // Callback object for context switching
  45. static ResumeThreadCallback resumeThreadCallback;
  46. private ProcessorLogger ProcessorLog = null;
  47. private ProcessorCounter processorCounter = null;
  48. internal SamplingProfiler Profiler = null;
  49. internal bool nextSampleIdle = false;
  50. internal static bool IsSamplingEnabled = false;
  51. //
  52. // This is called by HalDevicesApic.StartApProcessors() when
  53. // initializing additional physical AP processors to set its
  54. // hardware state when its started.
  55. //
  56. public void InitializeKernelThreadState(Thread thread,
  57. UIntPtr kernelStackBegin,
  58. UIntPtr kernelStackLimit)
  59. {
  60. kernelThread = thread;
  61. kernelStackBegin = kernelStackBegin;
  62. kernelStackLimit = kernelStackLimit;
  63. }
  64. public HalTimer Timer
  65. {
  66. [NoHeapAllocation]
  67. get { return timer; }
  68. }
  69. public HalClock Clock
  70. {
  71. [NoHeapAllocation]
  72. get { return clock; }
  73. }
  74. internal static void InitializeProcessorTable(int cpus)
  75. {
  76. // use the full value initially
  77. ExpectedProcessors = cpus;
  78. processorTable = new Processor[cpus];
  79. for (int i = 0; i < processorTable.Length; i++) {
  80. processorTable[i] = new Processor(i);
  81. }
  82. DebugStub.WriteLine("Processors: {0} of {1}",
  83. __arglist(processorTable.Length, cpus));
  84. }
  85. internal static void AllocateStack(UIntPtr size, out UIntPtr begin, out UIntPtr limit)
  86. {
  87. Kernel.Waypoint(818);
  88. size = MemoryManager.PagePad(size);
  89. limit = MemoryManager.KernelAllocate(
  90. MemoryManager.PagesFromBytes(size), null, 0, System.GCs.PageType.Stack);
  91. begin = limit + size;
  92. Kernel.Waypoint(819);
  93. }
  94. private Processor(int index)
  95. {
  96. processorIndex = index;
  97. if (interruptCounts == null) {
  98. interruptCounts = new int [256];
  99. }
  100. ProcessorLog = ProcessorLogger.Create("ProcessorLogger:"+index.ToString());
  101. processorCounter = ProcessorCounter.Create("ProcessorCounters:"+index.ToString(), 256);
  102. DebugStub.WriteLine("Processor: {0}", __arglist(index));
  103. }
  104. public void EnableProfiling()
  105. {
  106. if (SamplingEnabled()) {
  107. Profiler = SamplingProfiler.Create("SampleProfiler:" + Id.ToString(),
  108. 32, // maximum stack depth
  109. Kernel.ProfilerBufferSize); // sampling buffer size
  110. DebugStub.WriteLine("Sampling profiler enabled");
  111. }
  112. }
  113. public static Processor EnableProcessor(int processorId)
  114. {
  115. Processor p = processorTable[processorId];
  116. p.Initialize(processorId);
  117. return p;
  118. }
  119. private unsafe void Initialize(int processorId)
  120. {
  121. uint DefaultStackSize = 0xA000;
  122. processorTable[processorId] = this;
  123. context = (ProcessorContext*) Isa.GetCurrentCpu();
  124. DebugStub.WriteLine("Processor context: {0} {1:x8}",
  125. __arglist(processorId, Kernel.AddressOf(context)));
  126. context->UpdateAfterGC(this);
  127. if (0 != processorId) {
  128. Thread.BindKernelThread(kernelThread,
  129. kernelStackBegin,
  130. kernelStackLimit);
  131. }
  132. AllocateStack(DefaultStackSize,
  133. out context->cpuRecord.interruptStackBegin,
  134. out context->cpuRecord.interruptStackLimit);
  135. Tracing.Log(Tracing.Debug, "Initialized Processor {0}",
  136. (UIntPtr)processorId);
  137. Tracing.Log(Tracing.Debug, "asmInterruptStack={0:x}..{1:x}",
  138. context->cpuRecord.interruptStackBegin,
  139. context->cpuRecord.interruptStackLimit);
  140. #if false
  141. DebugStub.WriteLine("proc{0}: InterruptStack={1:x}..{2:x}",
  142. __arglist(
  143. processorId,
  144. context->cpuRecord.interruptStackBegin,
  145. context->cpuRecord.interruptStackLimit
  146. ));
  147. #endif
  148. Interlocked.Increment(ref runningCpus);
  149. MpExecution.AddProcessorContext(context);
  150. // Need to allocate this callback object outside of NoThreadAllocation region
  151. if (processorId == 0) {
  152. resumeThreadCallback = new ResumeThreadCallback();
  153. }
  154. Isa.EnableCycleCounter();
  155. }
  156. ///
  157. /// <summary>
  158. /// Initialize dispatcher
  159. /// </summary>
  160. ///
  161. /// <param name="processorId">Id of the processor dispatcher belongs to</param>
  162. ///
  163. public static void InitializeDispatcher(int processorId)
  164. {
  165. // Create a processor dispatcher
  166. processorTable[processorId].dispatcher = new ProcessorDispatcher();
  167. // Initialize dispatcher
  168. processorTable[processorId].dispatcher.Initialize(processorTable[processorId]);
  169. }
  170. ///
  171. /// <summary>
  172. /// Activate Timer
  173. /// </summary>
  174. ///
  175. ///
  176. public static void ActivateTimer(int processorId)
  177. {
  178. processorTable[processorId].timer.SetNextInterrupt(TimeSpan.FromMilliseconds(5));
  179. }
  180. [NoHeapAllocation]
  181. public void Uninitialize(int processorId)
  182. {
  183. Tracing.Log(Tracing.Debug, "UnInitializing Processor {0}",
  184. (UIntPtr)processorId);
  185. Interlocked.Decrement(ref runningCpus);
  186. // #if DEBUG
  187. // Interrupts should be off now
  188. if (!InterruptsDisabled()) {
  189. DebugStub.WriteLine("Processor::Uninitialize AP Processor does not have interrupts disabled\n");
  190. DebugStub.Break();
  191. }
  192. // #endif // DBG
  193. // Processor is out of commission
  194. HaltUntilInterrupt();
  195. // #if DEBUG
  196. DebugStub.WriteLine("Processor::Uninitialize: AP processor woke up on shutdown!\n");
  197. DebugStub.Break();
  198. // #endif // DBG
  199. }
  200. public void AddPic(HalPic pic)
  201. {
  202. Tracing.Log(Tracing.Audit, "AddPic({0})\n",
  203. Kernel.TypeName(pic));
  204. this.pic = pic;
  205. }
  206. [NoHeapAllocation]
  207. public HalPic GetPic()
  208. {
  209. return this.pic;
  210. }
  211. [NoHeapAllocation]
  212. public void AddTimer(byte interrupt, HalTimer timer)
  213. {
  214. Tracing.Log(Tracing.Audit, "AddTimer({0}) on {1}\n",
  215. Kernel.TypeName(timer), interrupt);
  216. this.timer = timer;
  217. this.timerInterrupt = interrupt;
  218. }
  219. [NoHeapAllocation]
  220. public void AddClock(byte interrupt, HalClock clock)
  221. {
  222. Tracing.Log(Tracing.Audit, "AddClock({0}) on {1}\n",
  223. Kernel.TypeName(clock), interrupt);
  224. this.clock = clock;
  225. this.clockInterrupt = interrupt;
  226. }
  227. [NoHeapAllocation]
  228. public static void AddMemory(HalMemory aHalMemory)
  229. {
  230. Tracing.Log(Tracing.Audit, "AddHalMemory({0})\n",
  231. Kernel.TypeName(aHalMemory));
  232. halMemory = aHalMemory;
  233. }
  234. [NoHeapAllocation]
  235. internal unsafe void Display()
  236. {
  237. int stackVariable;
  238. UIntPtr currentStack = new UIntPtr(&stackVariable);
  239. unchecked {
  240. Tracing.Log(Tracing.Debug, "Interrupt stack: {0:x} {1:x}..{2:x} uses",
  241. currentStack,
  242. context->cpuRecord.interruptStackBegin,
  243. context->cpuRecord.interruptStackLimit);
  244. }
  245. }
  246. // Returns the processor that the calling thread is running on.
  247. // TODO:Needs to be fixed. (Added for consistency)
  248. public static Processor CurrentProcessor
  249. {
  250. [NoHeapAllocation]
  251. get { return GetCurrentProcessor(); }
  252. }
  253. ///
  254. /// <summary>
  255. /// Retrieve current dispatcher
  256. /// </summary>
  257. public ProcessorDispatcher Dispatcher
  258. {
  259. [NoHeapAllocation]
  260. get { return dispatcher; }
  261. }
  262. [NoHeapAllocation]
  263. public static int GetCurrentProcessorId()
  264. {
  265. return GetCurrentProcessor().Id;
  266. }
  267. public unsafe int Id
  268. {
  269. [NoHeapAllocation]
  270. get {
  271. return context->cpuRecord.id;
  272. }
  273. }
  274. [NoHeapAllocation]
  275. public static Processor GetProcessor(int i)
  276. {
  277. if (null == processorTable && i == 0) {
  278. return CurrentProcessor;
  279. }
  280. else {
  281. return processorTable[i];
  282. }
  283. }
  284. public static int CpuCount
  285. {
  286. [NoHeapAllocation]
  287. get { return null == processorTable ? 1 : processorTable.Length; }
  288. }
  289. [NoHeapAllocation]
  290. public static void HaltUntilInterrupt()
  291. {
  292. Platform.ThePlatform.Halt();
  293. }
  294. [NoHeapAllocation]
  295. public int GetInterruptCount(byte interrupt)
  296. {
  297. return interruptCounts[interrupt];
  298. }
  299. public int GetIrqCount(byte irq)
  300. {
  301. HalPic pic = CurrentProcessor.pic;
  302. // Only set on native hal
  303. if (pic == null) {
  304. return 0;
  305. }
  306. return interruptCounts[pic.IrqToInterrupt(irq)];
  307. }
  308. public static byte GetMaxIrq()
  309. {
  310. HalPic pic = CurrentProcessor.pic;
  311. // This is not set on halhyper or halwin32
  312. if (pic == null) {
  313. return 0;
  314. }
  315. return CurrentProcessor.pic.MaximumIrq;
  316. }
  317. public static ulong CyclesPerSecond
  318. {
  319. [NoHeapAllocation]
  320. get { return GetCurrentProcessor().cyclesPerSecond; }
  321. [NoHeapAllocation]
  322. set { GetCurrentProcessor().cyclesPerSecond = value; }
  323. }
  324. public static ulong CycleCount
  325. {
  326. [NoHeapAllocation]
  327. get { return Isa.GetCycleCount(); }
  328. }
  329. //////////////////////////////////////////////////////////////////////
  330. //
  331. //
  332. [NoHeapAllocation]
  333. public static bool SamplingEnabled()
  334. {
  335. return (Kernel.ProfilerBufferSize != 0);
  336. }
  337. internal static void StartSampling()
  338. {
  339. if (SamplingEnabled()) {
  340. IsSamplingEnabled = true;
  341. }
  342. }
  343. [NoHeapAllocation]
  344. internal void NextSampleIsIdle()
  345. {
  346. nextSampleIdle = true;
  347. }
  348. //////////////////////////////////////////////////// External Methods.
  349. //
  350. [NoHeapAllocation]
  351. internal static Processor GetCurrentProcessor()
  352. {
  353. unsafe {
  354. return GetCurrentProcessorContext()->processor;
  355. }
  356. }
  357. [NoHeapAllocation]
  358. [AccessedByRuntime("output to header : called by c code")]
  359. internal static unsafe ThreadContext * GetCurrentThreadContext()
  360. {
  361. unsafe {
  362. return (ThreadContext *) Isa.GetCurrentThread();
  363. }
  364. }
  365. [NoHeapAllocation]
  366. [AccessedByRuntime("output to header : called by c code")]
  367. internal static unsafe ProcessorContext * GetCurrentProcessorContext()
  368. {
  369. unsafe {
  370. return (ProcessorContext *) Isa.GetCurrentCpu();
  371. }
  372. }
  373. [NoHeapAllocation]
  374. internal static Thread GetCurrentThread()
  375. {
  376. unsafe {
  377. return GetCurrentThreadContext()->thread;
  378. }
  379. }
  380. [NoHeapAllocation]
  381. internal static void SetCurrentThreadContext(ref ThreadContext context)
  382. {
  383. unsafe {
  384. fixed (ThreadContext *c = &context) {
  385. Isa.SetCurrentThread(ref c->threadRecord);
  386. }
  387. }
  388. }
  389. ///
  390. /// <summary>
  391. /// Verify if thread currently is running on interrupt stack
  392. /// </summary>
  393. ///
  394. [NoHeapAllocation]
  395. [Inline]
  396. internal bool IsOnInterruptStack(Thread currentThread)
  397. {
  398. return Isa.IsRunningOnInterruptStack;
  399. }
  400. internal bool InInterruptContext
  401. {
  402. [NoHeapAllocation]
  403. get {
  404. return Isa.InInterruptContext;
  405. }
  406. }
  407. [AccessedByRuntime("defined in halforgc.asm")]
  408. [MethodImpl(MethodImplOptions.InternalCall)]
  409. [GCAnnotation(GCOption.GCFRIEND)]
  410. [StackBound(32)]
  411. [NoHeapAllocation]
  412. internal static extern void SwitchToThreadContext(ref ThreadContext oldContext, ref ThreadContext newContext);
  413. private class ResumeThreadCallback : Isa.ICallback
  414. {
  415. internal override UIntPtr Callback(UIntPtr param)
  416. {
  417. unsafe {
  418. ThreadContext* newContext = (ThreadContext *) param;
  419. // Switch our thread context, synchronizing with the dispatcher as necessary.
  420. ProcessorDispatcher.TransferToThreadContext(ref *GetCurrentThreadContext(),
  421. ref *newContext);
  422. // Resume in the new context. Note that this call does not return.
  423. newContext->threadRecord.spill.Resume();
  424. return 0;
  425. }
  426. }
  427. }
  428. [AccessedByRuntime("referenced by halforgc.asm")]
  429. [NoHeapAllocation]
  430. [GCAnnotation(GCOption.NOGC)]
  431. internal static unsafe void SwitchToThreadContextNoGC(ref ThreadContext newContext)
  432. {
  433. // Interrupts should be disabled at this point
  434. VTable.Assert(Processor.InterruptsDisabled());
  435. // Save appears to returns twice: once with true on this thread after
  436. // the save, and once with false when the context is restored.
  437. if (GetCurrentThreadContext()->threadRecord.spill.Save()) {
  438. // Initial return from save; time to swap in the new context.
  439. // Must do this on the interrupt stack, since once we release the
  440. // dispatch lock the saved context is free to run (and we would
  441. // be on the same stack.)
  442. fixed (ThreadContext *c = &newContext) {
  443. // Note that this does not return.
  444. Isa.CallbackOnInterruptStack(resumeThreadCallback, (UIntPtr) c);
  445. }
  446. }
  447. // Saved context will resume here
  448. }
  449. [MethodImpl(MethodImplOptions.InternalCall)]
  450. [GCAnnotation(GCOption.NOGC)]
  451. [StackBound(32)]
  452. [NoHeapAllocation]
  453. internal static extern void TestSaveLoad(ref ThreadContext newContext);
  454. [MethodImpl(MethodImplOptions.InternalCall)]
  455. [GCAnnotation(GCOption.NOGC)]
  456. [StackBound(32)]
  457. [NoHeapAllocation]
  458. internal static extern void TestSave(ref ThreadContext newContext);
  459. //////////////////////////////////////////////////////////////////////
  460. //
  461. // These methods are currently marked external because they are used
  462. // by device drivers. We need a tool to verify that device drivers
  463. // are in fact using them correctly!
  464. //
  465. [AccessedByRuntime("accessed by C++")]
  466. [NoHeapAllocation]
  467. [GCAnnotation(GCOption.NOGC)]
  468. public static bool DisableLocalPreemption()
  469. {
  470. return DisableInterrupts();
  471. }
  472. [AccessedByRuntime("accessed by C++")]
  473. [NoHeapAllocation]
  474. [GCAnnotation(GCOption.NOGC)]
  475. public static void RestoreLocalPreemption(bool enabled)
  476. {
  477. RestoreInterrupts(enabled);
  478. }
  479. [AccessedByRuntime("accessed by C++")]
  480. [NoHeapAllocation]
  481. [GCAnnotation(GCOption.NOGC)]
  482. public static bool DisableInterrupts()
  483. {
  484. #if CHECK_DISABLE_INTERRUPTS
  485. bool wasDisabled = InterruptsDisabled();
  486. #endif
  487. bool result = Isa.DisableInterrupts();
  488. #if CHECK_DISABLE_INTERRUPTS
  489. if (result && wasDisabled) {
  490. DebugStub.Break();
  491. }
  492. #endif
  493. return result;
  494. }
  495. [AccessedByRuntime("accessed by C++")]
  496. [NoHeapAllocation]
  497. [GCAnnotation(GCOption.NOGC)]
  498. public static void RestoreInterrupts(bool enabled)
  499. {
  500. int i = 0;
  501. try {
  502. #if CHECK_DISABLE_INTERRUPTS
  503. if (!InterruptsDisabled()) {
  504. DebugStub.Break();
  505. }
  506. #endif
  507. i = 1;
  508. if (enabled) {
  509. i = 2;
  510. // Processor flag should be turned off before this call
  511. if (GetCurrentProcessor().InInterruptContext) {
  512. DebugStub.Break();
  513. }
  514. i = 3;
  515. Isa.EnableInterrupts();
  516. }
  517. i = 5;
  518. #if CHECK_DISABLE_INTERRUPTS
  519. if (enabled && InterruptsDisabled()) {
  520. DebugStub.Break();
  521. }
  522. #endif
  523. }
  524. catch(Exception e) {
  525. DebugStub.Break();
  526. }
  527. }
  528. // Use this method for assertions only!
  529. [AccessedByRuntime("accessed by C++")]
  530. [NoHeapAllocation]
  531. [GCAnnotation(GCOption.NOGC)]
  532. public static bool InterruptsDisabled()
  533. {
  534. return Platform.ThePlatform.AreInterruptsDisabled();
  535. }
  536. [NoHeapAllocation]
  537. public unsafe void IncrementInterruptCounts(int interrupt)
  538. {
  539. NumInterrupts++;
  540. NumExceptions++;
  541. interruptCounts[interrupt]++;
  542. if (ProcessorLog != null) {
  543. // ProcessorLog.Log(interrupt);
  544. processorCounter.Buffer[interrupt].Hits += 1;
  545. }
  546. }
  547. [NoHeapAllocation]
  548. internal static unsafe void UpdateAfterGC(Thread currentThread)
  549. {
  550. // Update the processor pointers in processor contexts
  551. for (int i = 0; i < Processor.processorTable.Length; i++) {
  552. Processor p = Processor.processorTable[i];
  553. if (p != null) {
  554. p.context->UpdateAfterGC(p);
  555. }
  556. }
  557. // Ensure that Thread.CurrentThread returns new thread object
  558. SetCurrentThreadContext(ref currentThread.context);
  559. }
  560. [NoHeapAllocation]
  561. internal void ActivateDispatcher()
  562. {
  563. if (Platform.Cpu(processorIndex) != null){
  564. // Wake processor
  565. Platform.ThePlatform.WakeNow(processorIndex);
  566. }
  567. }
  568. ///
  569. /// <summary>
  570. /// Set next alarm: timer that we are interested in
  571. /// </summary>
  572. ///
  573. /// <param name="delta">Time until the next time we would like to be awaken</param>
  574. ///
  575. [NoHeapAllocation]
  576. public void SetNextTimerInterrupt(TimeSpan delta)
  577. {
  578. // Make sure that interrupts are disabled
  579. bool iflag = Processor.DisableInterrupts();
  580. TimeSpan start = delta;
  581. if (delta < timer.MinInterruptInterval) {
  582. delta = timer.MinInterruptInterval;
  583. }
  584. if (delta > timer.MaxInterruptInterval) {
  585. delta = timer.MaxInterruptInterval;
  586. }
  587. #if false
  588. DebugStub.WriteLine("-- SetNextTimerInterrupt(delta={0}, start={1} [min={2},max={3})",
  589. __arglist(delta.Ticks,
  590. start.Ticks,
  591. timer.MinInterruptInterval.Ticks,
  592. timer.MaxInterruptInterval.Ticks));
  593. #endif
  594. timer.SetNextInterrupt(delta);
  595. // Restore interrupts if necessary
  596. Processor.RestoreInterrupts(iflag);
  597. }
  598. //////////////////////////////////////////////////////////////////////
  599. //
  600. // These (native) methods manipulate the local processor's paging
  601. // hardware. They can be used even before Processor.Initialize()
  602. // has been called.
  603. //
  604. internal static void EnablePaging(AddressSpace bootstrapSpace)
  605. {
  606. Isa.EnablePaging((uint)bootstrapSpace.PdptPage.Value);
  607. }
  608. internal static void ChangeAddressSpace(AddressSpace space)
  609. {
  610. Isa.ChangePageTableRoot((uint)space.PdptPage.Value);
  611. }
  612. internal static void InvalidateTLBEntry(UIntPtr pageAddr)
  613. {
  614. DebugStub.Assert(MemoryManager.IsPageAligned(pageAddr));
  615. Isa.InvalidateTLBEntry(pageAddr);
  616. }
  617. internal static AddressSpace GetCurrentAddressSpace()
  618. {
  619. return new AddressSpace(new PhysicalAddress(Isa.GetPageTableRoot()));
  620. }
  621. //
  622. public static HalMemory.ProcessorAffinity[] GetProcessorAffinity()
  623. {
  624. HalMemory.ProcessorAffinity[] processors =
  625. halMemory.GetProcessorAffinity();
  626. return processors;
  627. }
  628. public static HalMemory.MemoryAffinity[] GetMemoryAffinity()
  629. {
  630. HalMemory.MemoryAffinity[] memories =
  631. halMemory.GetMemoryAffinity();
  632. return memories;
  633. }
  634. public static unsafe void EnableMoreProcessors(int cpus)
  635. {
  636. ExpectedProcessors = cpus;
  637. Platform.ThePlatform.EnableMoreCpus(cpus);
  638. StartApProcessors(cpus);
  639. }
  640. /// <summary> Start application processors. </summary>
  641. [System.Diagnostics.Conditional("SINGULARITY_MP")]
  642. public static void StartApProcessors(int cpuCount)
  643. {
  644. // At this point only the BSP is running.
  645. Tracing.Log(Tracing.Debug, "Processor.StartApProcessors()");
  646. Platform.StartApProcessors(cpuCount);
  647. // At this point the BSP and APs are running.
  648. }
  649. /// <summary> Stop application processors. </summary>
  650. [NoHeapAllocation]
  651. [System.Diagnostics.Conditional("SINGULARITY_MP")]
  652. public static void StopApProcessors()
  653. {
  654. //
  655. // Note: This should go into a HAL interface and this
  656. // code confined to Platform.cs
  657. //
  658. // At this point the BSP and APs are running.
  659. Tracing.Log(Tracing.Debug, "Processor.StopApProcessors()");
  660. if (Processor.GetRunningProcessorCount() > 1) {
  661. //
  662. // This stops them in MpExecution in a halt state with
  663. // interrupts off.
  664. //
  665. Platform.BroadcastFixedIPI((byte)Isal.IX.EVectors.HaltApProcessors, true);
  666. }
  667. while (GetRunningProcessorCount() != 1) {
  668. // Thread.Sleep(100); Thread.Sleep needs NoHeapAllocation annotation
  669. Thread.Yield();
  670. }
  671. //
  672. // We must reset the AP Processors since a debug entry
  673. // will generated a NMI which will wake them up from HALT,
  674. // and they may start executing code again while the kernel
  675. // is still shutting down.
  676. //
  677. Platform.ResetApProcessors();
  678. DebugStub.RevertToUniprocessor();
  679. // At this point only the BSP is running.
  680. }
  681. /// <summary> Gets the number of processors in use by
  682. /// the system. </summary>
  683. [NoHeapAllocation]
  684. public static int GetRunningProcessorCount()
  685. {
  686. return runningCpus;
  687. }
  688. /// <summary> Gets the total number of processors known
  689. /// to the system. This includes processors not
  690. /// currently in use by the system. </summary>
  691. [NoHeapAllocation]
  692. public static int GetProcessorCount()
  693. {
  694. return Platform.GetProcessorCount();
  695. }
  696. //
  697. //public static int GetDomainCount()
  698. //{
  699. // HalMemory.ProcessorAffinity[] processors =
  700. // halMemory.GetProcessorAffinity();
  701. // uint domain = 0;
  702. // for (int i = 0; i < processors.Length; i++) {
  703. // if (processors[i].domain > domain) {
  704. // domain = processors[i].domain;
  705. // }
  706. // }
  707. // domain++; // domain number starts from 0
  708. // return (int)domain;
  709. //}
  710. //
  711. public static bool PerProcessorAddressSpaceDisabled()
  712. {
  713. return halMemory.PerProcessorAddressSpaceDisabled();
  714. }
  715. public static bool HasAffinityInfo()
  716. {
  717. HalMemory.ProcessorAffinity[] processors = halMemory.GetProcessorAffinity();
  718. HalMemory.MemoryAffinity[] memories = halMemory.GetMemoryAffinity();
  719. if (processors == null || memories == null) {
  720. return false;
  721. }
  722. return true;
  723. }
  724. // return cpuId if context is not null
  725. [NoHeapAllocation]
  726. public unsafe int ValidProcessorId(int i)
  727. {
  728. if (context != null) {
  729. return context->cpuRecord.id;
  730. }
  731. else {
  732. return -1;
  733. }
  734. }
  735. ///
  736. /// <summary>
  737. /// Is system MP or UP
  738. /// </summary>
  739. ///
  740. public static bool IsUP
  741. {
  742. [NoHeapAllocation]
  743. get
  744. {
  745. return CpuCount == 1;
  746. }
  747. }
  748. ///<summary> Count of the number of processors expected to be running </summary>
  749. public static int ExpectedProcessors;
  750. ///<summary> Global processor table </summary>
  751. public static Processor[] processorTable;
  752. /// <summary> Processor contexts </summary>
  753. internal unsafe ProcessorContext* context;
  754. ///<summary> Processor dispatcher </summary>
  755. [AccessedByRuntime("referenced from c++")]
  756. internal ProcessorDispatcher dispatcher;
  757. //<summary> Hardware pic, or its emulation </summary>
  758. private HalPic pic;
  759. /// <summary> Per processor HalTimer </summary>
  760. internal HalTimer timer = null;
  761. /// <summary> Per processor HalClock </summary>
  762. internal HalClock clock = null;
  763. /// <summary> Hal memory interface </summary>
  764. private static HalMemory halMemory;
  765. /// <summary> Id of a timer interrupt </summary>
  766. internal byte timerInterrupt;
  767. /// <summary> Id of a clock interrupt</summary>
  768. internal byte clockInterrupt;
  769. /// <summary> Shows if a processor currently in a context of interrupt </summary>
  770. private bool inInterruptContext = false;
  771. /// <summary> Shows if a processor currently in halt state </summary>
  772. private bool halted = false;
  773. ///<summary> Processor Index </summary>
  774. private int processorIndex;
  775. /// <summary> A number of exception occured on this processor </summary>
  776. public uint NumExceptions = 0;
  777. /// <summary> A number of interrupts occrued on this processor </summary>
  778. public uint NumInterrupts = 0;
  779. /// <summary> A number of context switches </summary>
  780. public uint NumContextSwitches = 0;
  781. /// <summary> A interrupt statistics per processor </summary>
  782. internal int[] interruptCounts;
  783. /// <summary> A number of cycles per second on a given processor </summary>
  784. private ulong cyclesPerSecond;
  785. /// <summary> A number of active Processors </summary>
  786. private static int runningCpus = 0;
  787. /// <summary> An initial per processor kernel thread </summary>
  788. private Thread kernelThread;
  789. /// <summary>Beginning of kernel thread stack </summary>
  790. private UIntPtr kernelStackBegin = 0;
  791. /// <summary> Limit of kernel thread stack </summary>
  792. private UIntPtr kernelStackLimit = 0;
  793. }
  794. }