singrdk/base/Kernel/Singularity/Isal/Isa.cs

852 lines
31 KiB
C#
Raw Normal View History

2008-11-17 18:29:00 -05:00
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Isa specifies a standard architecture-neutral interface to the target execution
// environment required by Singularity. Unlike the HAL there is only a single
// Isa available at a time (although the Isa implementation changes on different ISA's.)
//
// Isa defines a basic framework for interrupt handling and dispatching, which is uniform
// across HALs.
//
// The Isa model is:
//
// Each processor has 2 processor-specific records avaiable to it.
// - The CpuRecord is effectively constant for the processor
// - The ThreadRecord will be changed by the OS as context switches occur on the processor
//
// Pointers to these structures are stored in an architecture-specific, yet well-known,
// atomic instruction sequence. (Specifically, atomic with respect to processor migration
// occuring during the sequence.)
//
// This sequence is allowed to be parameterized by a runtime constant parameter
// "offset" (one for each processor and thread.) Values of each offset are
// provided at init time and may not change. (E.g. on x86 this is an offset from fs:[0].)
//
// The target also abstracts ISA-specific interrupt handling and dispatch logic. Each architecture
// identifies interrupts into one of 3 categories (based on static partitioning of dispatch ids):
// - Exceptions. These cause the current context to be saved in the CpuRecord, and
// are dispatched to the debugger infrastructure. (Eventually they will be further
// handled by additional logic, but this is not in place yet.) Note that exceptions
// are not currently reentrant.
// - "Quick" interrupts. These interrupts are intended to be handled by lightweight kernel
// logic. They cannot trigger context switches and thus do not require full context saves.
// - Normal interrupts. These cause a context save into the per-thread spill area. The
// presumption is that execution may resume on a different thread.
//
// There needs to be some discipline enforced in terms of priority of these interrupts, but
// currently there is none. (The current assumption is that normal/quick interrupts
// are non-reentrant, and exceptions may occur at any time but may not be interrupted. However
// note that nothing is preventing quick interrupts from interrupting anything but debugging.)
//
// The interrupt dispatching logic also manages stack switches. The basic model is that only
// normal thread execution occurs on growable stacks. Therefore we maintain only a single
// interrupt stack for all interrupt and exception dispatch - reentrant interrupts simply
// grow that stack. Note that if we ever overflow the interrupt stack it is a panic situation,
// but this is the case anyway since we cannot allocate during interrupt processing. Also note
// that this stack is also suitable for executing application-level stack growth code, since
// such code cannot run during interrupt time.
using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Diagnostics;
#if SINGULARITY_KERNEL
using Microsoft.Singularity.Hal;
using HalPlatform = Microsoft.Singularity.Hal.Platform;
#endif
#if ISA_IX
using Microsoft.Singularity.Isal.IX;
#elif ISA_ARM
using Microsoft.Singularity.Isal.Arm;
#endif
namespace Microsoft.Singularity.Isal
{
[NoCCtor]
[AccessedByRuntime("referenced in c++")]
[CLSCompliant(false)]
public class Isa
{
[AccessedByRuntime("foo", AllFields=true)]
public enum Type
{
X86,
X64,
Arm
};
#if ISA_IX86
public const Type Target = Type.X86;
#elif ISA_IX64
public const Type Target = Type.X64;
#elif ISA_ARM
public const Type Target = Type.Arm;
#endif
////////////////////////////////////////////////////////////////////////
// Thread-local and cpu-local storage
//
// Each ISA sets up an architecure-specific way to access a processor- and thread-specific
// data segment. To allow flexibility in the implementation of this, the HAL
// is allowed to parameterize the location where this data is stored (although this
// offset is interpreted in an ISA-specific way: fs offset on x86, gs offset on
// x64, etc.) This parameter is generically referred to as the "offset".
//
// Note that for each ISA there is a specific well-known assembly sequence, using
// this offset, to access the thread and processor records. (Architecture-neutral code
// should use the function call interfaces.)
////////////////////////////////////////////////////////////////////////
[AccessedByRuntime("referenced in c++")]
public static int currentThreadOffset;
[AccessedByRuntime("referenced in c++")]
public static int currentCpuOffset;
[AccessedByRuntime("referenced in c++")]
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(32)]
[NoHeapAllocation]
public static unsafe extern ThreadRecord *GetCurrentThread();
[AccessedByRuntime("referenced in c++")]
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(32)]
[NoHeapAllocation]
public static unsafe extern CpuRecord *GetCurrentCpu();
#if SINGULARITY_KERNEL
[AccessedByRuntime("referenced in c++")]
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(32)]
[NoHeapAllocation]
public static unsafe extern void SetCurrentThread(ref ThreadRecord record);
#endif
////////////////////////////////////////////////////////////////////////
// Interrupt stack access
//
// This routine allows managed code to be executed on the interrupt stack.
//
// This can only be safely accomplished with interrupt disabled.
// There are two reasons interrupts are required to be disabled here:
//
// 1. We must disable interrupts around the narrow window where we are flipping the stack
// back and forth from the interrupt stack (essentially this must be atomic or the
// interrupt dispatcher could get confused.)
//
// 2. We cannot tolerate a context switch when we are on the interrupt stack.
//
// If we ever support leveled interrupts, we may want to disable interrupts for a very
// narrow window, and separately disable scheduling operations for the longer window.
////////////////////////////////////////////////////////////////////////
[AccessedByRuntime("referenced by asm")]
public abstract class ICallback
{
[NoStackLinkCheckTrans]
internal abstract UIntPtr Callback(UIntPtr param);
[AccessedByRuntime("referenced by asm")]
[NoStackLinkCheckTrans]
private static UIntPtr DoCallback(ICallback pThis, UIntPtr param)
{
VTable.Assert(Isa.IsRunningOnInterruptStack);
return pThis.Callback(param);
}
}
#if SINGULARITY_KERNEL
[NoStackLinkCheckTrans]
[NoHeapAllocation]
public static UIntPtr CallbackOnInterruptStack(ICallback callback, UIntPtr param)
{
VTable.Assert(HalPlatform.ThePlatform.AreInterruptsDisabled());
// Here we assert that we aren't reentering the interrupt stack. This would technically
// be just fine (we'd just call back immediately), but the check is here because:
// (a) existing clients currently don't expect this to happen, so it's a sanity check
// (b) we are participating in an annoying hack where we "discard" the NoHeapAllocation
// attribute on our callback path through unmanaged code, since stack allocation
// calls through here and is not annotated properly. Thus we can't directly call
// the callback here. (@todo: This needs to be fixed.)
VTable.Assert(!IsRunningOnInterruptStack);
return SwitchToInterruptStackAndCallback(callback, param);
}
[AccessedByRuntime("defined in interrupt.asm")]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(16)]
[NoHeapAllocation]
public extern static UIntPtr SwitchToInterruptStackAndCallback(ICallback callback,
UIntPtr param);
#endif // SINGULARITY_KERNEL
public static bool IsRunningOnInterruptStack
{
[NoHeapAllocation]
get {
unsafe {
return StackLimit == GetCurrentCpu()->interruptStackLimit;
}
}
}
////////////////////////////////////////////////////////////////////////
// Direct register access
////////////////////////////////////////////////////////////////////////
public static UIntPtr StackLimit
{
[NoHeapAllocation]
get {
unsafe {
return GetCurrentThread()->activeStackLimit;
}
}
[NoHeapAllocation]
set {
unsafe {
GetCurrentThread()->activeStackLimit = value;
}
}
}
#if ISA_ARM
[AccessedByRuntime("defined in isa.asm")]
[MethodImpl(MethodImplOptions.InternalCall)]
[NoHeapAllocation]
[StackBound(32)]
public static extern uint GetCpsr();
#endif // ISA_ARM
#if ISA_IX
[AccessedByRuntime("defined in isa.asm")]
[MethodImpl(MethodImplOptions.InternalCall)]
[NoHeapAllocation]
[StackBound(32)]
public static extern UIntPtr GetCs();
#endif // ISA_IX
[AccessedByRuntime("defined in isa.asm")]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(16)]
[NoHeapAllocation]
public static extern void WriteMsr(uint offset,ulong value);
[AccessedByRuntime("defined in isa.asm")]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(16)]
[NoHeapAllocation]
public static extern ulong ReadMsr(uint offset);
////////////////////////////////////////////////////////////////////////
// Specialized instruction support
////////////////////////////////////////////////////////////////////////
#if SINGULARITY_KERNEL
[AccessedByRuntime("foo")]
[MethodImpl(MethodImplOptions.InternalCall)]
[NoHeapAllocation]
[StackBound(32)]
public static extern void Halt();
#endif // SINGULARITY_KERNEL
#if ISA_ARM
[AccessedByRuntime("foo")]
[MethodImpl(MethodImplOptions.InternalCall)]
[StackBound(32)]
[NoHeapAllocation]
internal static extern void EnableCycleCounter();
#else
[NoHeapAllocation]
internal static void EnableCycleCounter()
{
}
#endif
[AccessedByRuntime("foo")]
[MethodImpl(MethodImplOptions.InternalCall)]
[StackBound(32)]
[NoHeapAllocation]
internal static extern ulong GetCycleCount();
[AccessedByRuntime("foo")]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(16)]
[NoHeapAllocation]
public static extern ulong ReadPmc(uint offset);
[AccessedByRuntime("foo")]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(64)]
[NoHeapAllocation]
public static extern void ReadCpuid(uint feature,
out uint v0, out uint v1, out uint v2, out uint v3);
////////////////////////////////////////////////////////////////////////
// Basic FPU support
////////////////////////////////////////////////////////////////////////
[AccessedByRuntime("foo")]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(64)]
[NoHeapAllocation]
public static extern void InitFpu();
[AccessedByRuntime("foo")]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(16)]
[NoHeapAllocation]
private static extern uint ReadFpuStatus();
[AccessedByRuntime("foo")]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(16)]
[NoHeapAllocation]
private static extern void ClearFpuStatus();
////////////////////////////////////////////////////////////////////////
// IO space support
////////////////////////////////////////////////////////////////////////
#if ISA_IX
[AccessedByRuntime("defined in isa.asm")]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(64)]
[NoHeapAllocation]
public static extern int In(ushort port);
[AccessedByRuntime("defined in isa.asm")]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(64)]
[NoHeapAllocation]
public static extern void Out(ushort port, int value);
[AccessedByRuntime("defined in isa.asm")]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(64)]
[NoHeapAllocation]
public static extern unsafe void RepInS(uint count, ushort port, byte *buffer);
[AccessedByRuntime("defined in isa.asm")]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(64)]
[NoHeapAllocation]
public static extern unsafe void RepOutS(uint count, ushort port, byte *buffer);
#endif // ISA_IX
////////////////////////////////////////////////////////////////////////
// Chip-level interrupt enable flag
////////////////////////////////////////////////////////////////////////
#if SINGULARITY_KERNEL
[AccessedByRuntime("defined in isa.asm")]
[MethodImpl(MethodImplOptions.InternalCall)]
[NoHeapAllocation]
[StackBound(32)]
public static extern bool AreInterruptsDisabled();
[AccessedByRuntime("defined in isa.asm")]
[MethodImpl(MethodImplOptions.InternalCall)]
[NoHeapAllocation]
[StackBound(32)]
internal static extern bool DisableInterrupts();
[AccessedByRuntime("defined in isa.asm")]
[MethodImpl(MethodImplOptions.InternalCall)]
[NoHeapAllocation]
[StackBound(32)]
internal static extern void EnableInterrupts();
#endif // SINGULARITY_KERNEL
////////////////////////////////////////////////////////////////////////
// Call frame support
////////////////////////////////////////////////////////////////////////
[AccessedByRuntime("foo")]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(32)]
[NoHeapAllocation]
internal static unsafe extern UIntPtr GetFrameReturnAddress(UIntPtr framePointer);
[AccessedByRuntime("foo")]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(32)]
[NoHeapAllocation]
internal static unsafe extern UIntPtr GetFrameCallerFrame(UIntPtr framePointer);
[AccessedByRuntime("foo")]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(32)]
[NoHeapAllocation]
internal static extern UIntPtr GetStackPointer();
[AccessedByRuntime("foo")]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(32)]
[NoHeapAllocation]
internal static extern UIntPtr GetFramePointer();
// These methods are public and safe to use from any where provided
// there's at least 2 call frames on the stack.
[NoHeapAllocation]
public static UIntPtr GetCallerReturnAddress()
{
UIntPtr currentFrame = GetFramePointer();
UIntPtr callerFrame = GetFrameCallerFrame(currentFrame);
if (callerFrame == UIntPtr.Zero) {
return UIntPtr.Zero;
}
UIntPtr callersCaller = GetFrameReturnAddress(callerFrame);
return callersCaller;
}
/// <summary>
/// Provides a mini stack trace starting from the caller of the caller
/// of this method.
/// </summary>
[NoHeapAllocation]
public static void GetStackReturnAddresses(out UIntPtr pc1, out UIntPtr pc2, out UIntPtr pc3)
{
pc1 = UIntPtr.Zero;
pc2 = UIntPtr.Zero;
pc3 = UIntPtr.Zero;
UIntPtr currentFrame = GetFramePointer();
UIntPtr callerFrame = GetFrameCallerFrame(currentFrame);
if (callerFrame == UIntPtr.Zero) {
return;
}
pc1 = GetFrameReturnAddress(callerFrame);
callerFrame = GetFrameCallerFrame(callerFrame);
if (callerFrame == UIntPtr.Zero) {
return;
}
pc2 = GetFrameReturnAddress(callerFrame);
callerFrame = GetFrameCallerFrame(callerFrame);
if (callerFrame == UIntPtr.Zero) {
return;
}
pc3 = GetFrameReturnAddress(callerFrame);
}
/// <summary>
/// Provides the full stack trace starting from the caller of the caller
/// of this method.
/// </summary>
/// <returns>Return address values in stack array from top to bottom</returns>
[NoHeapAllocation]
public static uint GetStackReturnAddresses(UIntPtr[] stack)
{
uint index;
if (stack == null) {
return 0;
}
UIntPtr currentFrame = GetFramePointer();
UIntPtr callerFrame = GetFrameCallerFrame(currentFrame);
for (index = 0; callerFrame != UIntPtr.Zero && index < stack.Length; index++) {
stack[index] = GetFrameReturnAddress(callerFrame);
callerFrame = GetFrameCallerFrame(callerFrame);
}
return index;
}
////////////////////////////////////////////////////////////////////////
// Execution mode
////////////////////////////////////////////////////////////////////////
[NoHeapAllocation]
[AccessedByRuntime("foo")]
internal static bool IsInUserMode()
{
#if ISA_IX
// The bottom two bits of the CS selector are the RPL
// (requested privilege level) of the selector. If
// this is 3, we're running in ring3. Otherwise,
// we're more privileged.
return (GetCs() & 0x3) == 3;
#else
// We don't currently support non-priveleged mode on other archs.
return false;
#endif
}
#if SINGULARITY_KERNEL
[AccessedByRuntime("foo")]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(32)]
[NoHeapAllocation]
internal static extern void EnterUserMode();
#endif // SINGULARITY_KERNEL
////////////////////////////////////////////////////////////////////////
// Chip-level paging support
////////////////////////////////////////////////////////////////////////
#if SINGULARITY_KERNEL
[AccessedByRuntime("foo")]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(16)]
[NoHeapAllocation]
public static extern void EnablePaging(uint pdpt);
[AccessedByRuntime("foo")]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(16)]
[NoHeapAllocation]
public static extern void DisablePaging();
[AccessedByRuntime("foo")]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(16)]
[NoHeapAllocation]
public static extern void ChangePageTableRoot(uint pdpt);
[AccessedByRuntime("foo")]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(16)]
[NoHeapAllocation]
public static extern UIntPtr GetPageTableRoot();
[AccessedByRuntime("foo")]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(16)]
[NoHeapAllocation]
public static extern void InvalidateTLBEntry(UIntPtr pageAddr);
#endif // SINGULARITY_KERNEL
////////////////////////////////////////////////////////////////////////
// Interrupt dispatch logic
////////////////////////////////////////////////////////////////////////
public static bool InInterruptContext
{
[NoHeapAllocation]
get {
unsafe {
// Note that there is a small window where we haven't switched stacks where this
// will return false. However this is balanced against the complexity of
// maintaining a specific flag, especially across context restores operations.
// Also note that during normal thread execution there is a small possibility of
// getting another CPU's interruptStackLimit due to processor migration, but it
// should not affect the result.
return StackLimit == GetCurrentCpu()->interruptStackLimit;
}
}
}
#if SINGULARITY_KERNEL
// This call signature is a lie - in fact this routine has asm-level
// calling conventions and will never be called by managed code.
[AccessedByRuntime("defined in interrupt.asm")]
public extern static void DispatchVector();
// This type is a lie - in fact this is a code fragment. However
// C# won't let us take the address of code, so we declare it as a byte.
[AccessedByRuntime("output to header : defined in context.asm")]
[ExternalStaticData]
public unsafe static byte DefaultReturnFromInterrupt;
// The HAL is also allowed to customize the behavior of the final sequence of resuming
// a context, since it includes enabling interrupts which is abstracted by the hal.
// Currently this is specified by an unmanaged code snipped pointer. This code
// should have identical semantics to [iretd on x86,x64; tbd otherwise.]
[AccessedByRuntime("referenced in c++")]
private unsafe static void *returnFromInterrupt;
[NoHeapAllocation]
[AccessedByRuntime("referenced in c++")]
public static unsafe void SetReturnFromInterruptRoutine(UIntPtr code)
{
returnFromInterrupt = (void *) code;
}
// DebuggerDispatch dispatches exceptions to the debugger infrastructure.
// Eventually this should move to the HAL, as different platforms will
// have different debugging requiremnts
[NoHeapAllocation]
private static void DispatchDebugger(ref SpillContext context, int exception)
{
#if ISA_IX
// TBD: factor this special case into debugger abstraction
if (exception == EVectors.Nmi) {
if (Microsoft.Singularity.MpExecution.FreezeRequested) {
Singularity.MpExecution.FreezeProcessor(ref context);
} else {
DebugStub.WriteLine("******************* NMI Interrupt **********************\n");
Singularity.DebugStub.Trap(ref context, exception);
}
}
else {
// TBD: we should factor the debugger support into the HAL.
Singularity.DebugStub.Trap(ref context, exception);
}
#elif ISA_ARM
// Fix up pc for some software exceptions, regardless of debugger attachment.
if (exception == ExceptionVector.SoftwareInterrupt) {
// Move pc forward to resume after interrupting instruction.
if (context.instruction != 0x0efffff01) {
// Don't move pc forward for debugger-inserted breakpoints.
context.pc += 4;
}
}
else if (exception == ExceptionVector.UndefinedInstruction) {
// Move pc forward to resume after interrupting instruction.
context.pc += 4;
}
// TBD: we should factor the debugger support into the HAL.
Singularity.DebugStub.Trap(ref context, exception);
#endif
context.Resume();
}
// InterruptDispatch is called by the asm code after saving the context
// and switching stacks. This routine may return, in which case execution
// is resumed, or it may call RestoreContext on a new thread.
[AccessedByRuntime("referenced in asm")]
[NoHeapAllocation]
public static unsafe void DispatchInterrupt(InterruptContext *context)
{
#if false
DebugStub.WriteLine("---------------------------------------------------------------\n");
DebugStub.WriteLine("DispatchInterrupt (vector={0:x2})", __arglist(context->vector));
context->Display();
DebugStub.WriteLine("---------------------------------------------------------------\n");
#endif
// This count is stored in the Singularity Processor object, since that is where singx86
// looks for it. Need to move at some point.
Singularity.Processor p = Singularity.Processor.CurrentProcessor;
if (p != null) {
p.IncrementInterruptCounts(context->ExceptionId);
}
if (context->IsException()) {
// All exceptions get reported to the debugger (as first chance.)
DispatchDebugger(ref GetCurrentCpu()->spill, context->ExceptionId);
// TBD: eventually we want to actually have OS logic to do something with
// hardware exceptions...
}
else {
// Reset context for interrupt code (this affects the fpu)
// @todo: investigate details here; this seems wrong -SET
SpillContext.ResetCurrent();
HalPlatform.CurrentCpu.DispatchInterrupt(context);
}
}
#endif // SINGULARITY_KERNEL
////////////////////////////////////////////////////////////////////////
// Initialization
////////////////////////////////////////////////////////////////////////
#if SINGULARITY_KERNEL
[NoHeapAllocation]
[NoStackOverflowCheck]
[AccessedByRuntime("referenced in c++")]
public static void Initialize(int cpuRecordOffset, int threadRecordOffset)
{
// Fetch the offsets from the HAL
currentCpuOffset = cpuRecordOffset;
currentThreadOffset = threadRecordOffset;
// Set default return from interrupt routine
unsafe {
fixed (byte *p = &DefaultReturnFromInterrupt) {
returnFromInterrupt = p;
}
}
}
[NoHeapAllocation]
[NoStackOverflowCheck]
[AccessedByRuntime("referenced in c++")]
[NoStackLinkCheckTrans]
public static unsafe void InitializeCpu(CpuRecord *cpu,
int cpuid,
UIntPtr stackLimit)
{
unsafe {
cpu->id = cpuid;
// Set up active stack limit before we may incurr
// a linked stack check.
cpu->bootThread.activeStackLimit = stackLimit;
// Initially we just use the current stack for interrupts.
cpu->interruptStackBegin = 0;
cpu->interruptStackLimit = stackLimit;
InitializeCurrentCpu(ref *cpu);
InitializeCurrentThread(ref cpu->bootThread);
}
}
[AccessedByRuntime("referenced in c++")]
[NoHeapAllocation]
public static void InitializeDispatchTable()
{
#if ISA_IX
InitializeIdt();
#elif ISA_ARM
// Nothing to do as there is no table, just code.
#endif
}
[AccessedByRuntime("referenced in c++")]
[NoHeapAllocation]
public static void InitializeCpuDispatchTable()
{
#if ISA_IX
LoadIdt();
#elif ISA_ARM
unsafe {
UIntPtr sp = GetCurrentCpu()->dispatchStack.StackBegin;
// Initialize the sp pointers in the various exception modes
SetModeSp(ProcessorMode.Fiq, sp);
SetModeSp(ProcessorMode.Irq, sp);
SetModeSp(ProcessorMode.Supervisor, sp);
SetModeSp(ProcessorMode.Abort, sp);
SetModeSp(ProcessorMode.Undefined, sp);
}
LoadResetVector();
#endif
}
[AccessedByRuntime("referenced in c++")]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(32)]
[NoHeapAllocation]
private static unsafe extern void InitializeCurrentThread(ref ThreadRecord record);
[AccessedByRuntime("referenced in c++")]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.NOGC)]
[StackBound(32)]
[NoHeapAllocation]
private static unsafe extern void InitializeCurrentCpu(ref CpuRecord record);
#endif // SINGULARITY_KERNEL
////////////////////////////////////////////////////////////////////////
// Interrupt table
////////////////////////////////////////////////////////////////////////
#if SINGULARITY_KERNEL
#if ISA_IX
[AccessedByRuntime("accessed from asm")]
// BUG: declare this ExternalStaticData since it is not properly aligned by bartok
[ExternalStaticData]
public static InterruptTable idt;
[AccessedByRuntime("called from C++")]
[NoHeapAllocation]
public static void InitializeIdt()
{
idt.Initialize();
}
[AccessedByRuntime("defined in interrupt.asm")]
[MethodImpl(MethodImplOptions.InternalCall)]
[NoHeapAllocation]
[StackBound(32)]
public static extern void LoadIdt();
#endif
#if ISA_ARM
[AccessedByRuntime("defined in isa.asm")]
[MethodImpl(MethodImplOptions.InternalCall)]
[NoHeapAllocation]
[StackBound(32)]
public static extern void SetModeSp(int mode, UIntPtr sp);
[AccessedByRuntime("defined in interrupt.asm")]
[MethodImpl(MethodImplOptions.InternalCall)]
[NoHeapAllocation]
[StackBound(32)]
public static extern void LoadResetVector();
#endif // ISARM
#endif // SINGULARITY_KERNEL
}
}