230 lines
8.2 KiB
C#
230 lines
8.2 KiB
C#
|
// ----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
using System;
|
||
|
using System.Runtime.InteropServices;
|
||
|
using System.Runtime.CompilerServices;
|
||
|
using System.Threading;
|
||
|
using Microsoft.Singularity.Isal;
|
||
|
using Microsoft.Singularity.Hal;
|
||
|
using Microsoft.Singularity.Io;
|
||
|
|
||
|
#if ISA_IX
|
||
|
using Microsoft.Singularity.Isal.IX;
|
||
|
#endif
|
||
|
|
||
|
namespace Microsoft.Singularity.Hal
|
||
|
{
|
||
|
//
|
||
|
// Cpu contains per-CPU data structures that HAL sets up.
|
||
|
//
|
||
|
|
||
|
[AccessedByRuntime("referenced in c++")]
|
||
|
[CLSCompliant(false)]
|
||
|
[StructLayout(LayoutKind.Sequential, Pack=4)]
|
||
|
public class Cpu
|
||
|
{
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
// Boot configuration information: this is all filled out by the loader or another CPU
|
||
|
//////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
public Cpu()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
protected Cpu(int id, UIntPtr stackLimit, UIntPtr stackBegin)
|
||
|
{
|
||
|
Size = 0;
|
||
|
Id = id;
|
||
|
KernelStackLimit = stackLimit;
|
||
|
KernelStackBegin = stackBegin;
|
||
|
}
|
||
|
|
||
|
// Size of instance; this is a versioning/consistency check
|
||
|
[AccessedByRuntime("referenced in c++")]
|
||
|
public readonly int Size;
|
||
|
|
||
|
// Cpu index
|
||
|
[AccessedByRuntime("referenced in c++")]
|
||
|
public readonly int Id;
|
||
|
|
||
|
// The HAL is responsible for allocating a page for processor-specific
|
||
|
// data structures. This is the address of that page. (Note it must be paragraph aligned.)
|
||
|
[AccessedByRuntime("referenced in c++")]
|
||
|
public readonly UIntPtr CpuRecordPage;
|
||
|
|
||
|
// The HAL is responsible for allocating the kernel stack. The boundaries
|
||
|
// are reported here.
|
||
|
[AccessedByRuntime("referenced in c++")]
|
||
|
public readonly UIntPtr KernelStackLimit; // lower bounds of stack
|
||
|
[AccessedByRuntime("referenced in c++")]
|
||
|
public readonly UIntPtr KernelStackBegin; // upper bounds of stack
|
||
|
|
||
|
//Is 0 or 1...
|
||
|
[AccessedByRuntime("referenced in c++")]
|
||
|
public readonly int DomainBsp;
|
||
|
|
||
|
///// NaticeCpu
|
||
|
#if ISA_IX
|
||
|
// This is our segment table.
|
||
|
[AccessedByRuntime("referenced in c++")]
|
||
|
DescriptorTable segments;
|
||
|
#endif
|
||
|
|
||
|
internal bool halted;
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////
|
||
|
// Kernel information: initialized by kernel during early boot
|
||
|
///////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
// Low level initialization (no allocation allowed)
|
||
|
[NoHeapAllocation]
|
||
|
[AccessedByRuntime("referenced in c++")]
|
||
|
public unsafe void Initialize()
|
||
|
{
|
||
|
if (DomainBsp == 0) {
|
||
|
Platform.ThePlatform.RegisterCpu(this);
|
||
|
}
|
||
|
|
||
|
halted = false;
|
||
|
}
|
||
|
|
||
|
// High level intialization (requires object allocation)
|
||
|
public void InitializeServices()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
// Called from the ISA Target upon interrupt dispatch.
|
||
|
[NoHeapAllocation]
|
||
|
public unsafe void DispatchInterrupt(InterruptContext *context)
|
||
|
{
|
||
|
Processor p = Processor.CurrentProcessor;
|
||
|
int interrupt = context->ExceptionId;
|
||
|
|
||
|
// Indicate that we are in an interrupt context.
|
||
|
Thread target = null;
|
||
|
Thread current = Processor.GetCurrentThread();
|
||
|
|
||
|
Kernel.Waypoint(801);
|
||
|
|
||
|
// Don't generate loads of output for debugger-related interrupts
|
||
|
#if DEBUG_INTERRUPTS
|
||
|
DebugStub.WriteLine("Int{0:x2}", __arglist(interrupt));
|
||
|
context->Display();
|
||
|
#endif
|
||
|
|
||
|
if (Processor.IsSamplingEnabled) {
|
||
|
if (p.nextSampleIdle == false) {
|
||
|
p.Profiler.LogStackTrace(context->InstructionPointer,
|
||
|
context->StackPointer);
|
||
|
}
|
||
|
p.nextSampleIdle = false;
|
||
|
}
|
||
|
|
||
|
if (halted) {
|
||
|
p.clock.CpuResumeFromHaltEvent();
|
||
|
halted = false;
|
||
|
}
|
||
|
|
||
|
unchecked {
|
||
|
if (interrupt != p.clockInterrupt &&
|
||
|
interrupt != p.timerInterrupt) {
|
||
|
// We don't log the clockInterrupt because of all the spew.
|
||
|
Tracing.Log(Tracing.Debug, "Interrupt 0x{0:x}, count={1:x}, eip={2:x} [CC={3:x8}]",
|
||
|
(UIntPtr)(uint)interrupt,
|
||
|
(UIntPtr)p.interruptCounts[interrupt],
|
||
|
(UIntPtr)context->InstructionPointer,
|
||
|
(UIntPtr)(uint)Processor.CycleCount);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Monitoring.Log(Monitoring.Provider.Processor,
|
||
|
(ushort)ProcessorEvent.Interrupt, 0,
|
||
|
(uint)interrupt, 0, 0, 0, 0);
|
||
|
|
||
|
if (interrupt == Kernel.HalIpiInterrupt) {
|
||
|
#if DEBUG_IPI
|
||
|
DebugStub.WriteLine("IPI received 0x{0:x2} on processor {1}",
|
||
|
__arglist(interrupt, p.Id));
|
||
|
#endif // DEBUG_DISPATCH_TIMER
|
||
|
Platform.ClearFixedIPI(interrupt);
|
||
|
//p.dispatcher.HandlePreemptionReschedule();
|
||
|
|
||
|
}
|
||
|
else if (interrupt == p.timerInterrupt) {
|
||
|
// Polling on every timer interrupt is EXCEEDINGLY costly
|
||
|
p.timer.ClearInterrupt();
|
||
|
p.dispatcher.HandlePreemptionReschedule(p.timer);
|
||
|
}
|
||
|
else if (interrupt == p.clockInterrupt) {
|
||
|
|
||
|
p.clock.ClearInterrupt();
|
||
|
#if DEBUG
|
||
|
// Check for a debug break.
|
||
|
if (DebugStub.PollForBreak()) {
|
||
|
DebugStub.WriteLine("Debugger ctrl-break after interrupt 0x{0:x2}",
|
||
|
__arglist(interrupt));
|
||
|
DebugStub.Break();
|
||
|
}
|
||
|
#endif // DEBUG
|
||
|
}
|
||
|
#if ISA_IX
|
||
|
else if (interrupt == EVectors.GCSynchronization) {
|
||
|
|
||
|
Platform.ClearFixedIPI(interrupt);
|
||
|
|
||
|
MpExecution.GCSynchronizationInterrupt();
|
||
|
}
|
||
|
else if (interrupt == EVectors.SpuriousInterrupt) {
|
||
|
|
||
|
// FIXME: identify the source of these isolated interrupts after the
|
||
|
// warmboot. Ignore them for now.
|
||
|
DebugStub.WriteLine("Spurious interrupt");
|
||
|
}
|
||
|
#endif // ISA_IX
|
||
|
else {
|
||
|
if (!Platform.InternalInterrupt((byte)interrupt)) {
|
||
|
HalPic pic = p.GetPic();
|
||
|
|
||
|
DebugStub.Assert(pic != null);
|
||
|
|
||
|
pic.ClearInterrupt((byte)interrupt);
|
||
|
IoIrq.SignalInterrupt(pic.InterruptToIrq((byte)interrupt));
|
||
|
|
||
|
#if DEBUG_DISPATCH_IO
|
||
|
DebugStub.WriteLine("++DispatchInterruptEvent Irq={0:x2}, Thread={1:x8}",
|
||
|
__arglist(pic.InterruptToIrq((byte)interrupt),
|
||
|
Kernel.AddressOf(target)));
|
||
|
#endif // DEBUG_DISPATCH_IO
|
||
|
|
||
|
p.dispatcher.HandleIOReschedule();
|
||
|
}
|
||
|
else {
|
||
|
// Potentially missed interrupt
|
||
|
DebugStub.Break();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if DEBUG_INTERRUPTS
|
||
|
DebugStub.WriteLine("(2nd)Int{0:x2}", __arglist(interrupt));
|
||
|
context->Display();
|
||
|
if (!Processor.InterruptsDisabled()) {
|
||
|
DebugStub.WriteLine(" interrupts enabled!!!!!!!");
|
||
|
DebugStub.Break();
|
||
|
}
|
||
|
#if DEBUG_DEEPER
|
||
|
DebugStub.WriteLine("Int{0:x2}", __arglist(interrupt));
|
||
|
Thread.DisplayAbbrev(ref context, " int end");
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
// Now swap in the resulting current thread. (Note that this call will not return.)
|
||
|
Isa.GetCurrentThread()->spill.Resume();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|