singrdk/base/Kernel/Singularity/Hal/Platform.cs

697 lines
24 KiB
C#
Raw Permalink Normal View History

2008-11-17 18:29:00 -05:00
// ----------------------------------------------------------------------------
//
// 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;
namespace Microsoft.Singularity.Hal
{
//
// Platform is the basic abstraction of the HAL execution platform
//
// Part of the platform consts
//
[CLSCompliant(false)]
[AccessedByRuntime("referenced in c++", AllFields = true)]
[StructLayout(LayoutKind.Sequential, Pack=4)]
public class Platform
{
///////////////////////////////////////////////////////////////////////
// Constants: these remain the same on all platforms.
///////////////////////////////////////////////////////////////////////
// TODO: Fix case of constants to camel case
[AccessedByRuntime("referenced in c++")]
// 4KB is currently the only supported size
internal const uint PAGE_SIZE = 0x00001000; // 4KB
// This is the ABI Stub (MpSyscalls.x86)
[AccessedByRuntime("referenced in c++")]
internal const uint MP_ABI_BASE = 0x00600000;
//
// These constants control the gross layout of *virtual*
// memory
//
// The physical address and extent of the high-memory
// range to map into the Kernel space, and mark
// "uncached". This window is for communicating with
// hardware.
[AccessedByRuntime("referenced in c++")]
public const uint UNCACHED_PHYSICAL = 0xFE000000;
[AccessedByRuntime("referenced in c++")]
public const uint UNCACHED_MAPPED = 0x02000000;
// This is the amount of *contiguous, physical* memory
// to reserve at boot for use as I/O memory
public const uint IO_MEMORY_SIZE = 0x00800000; // 8MB
// This determines where the kernel/user boundary is.
// Currently, it needs to be multiple of 1GB.
[AccessedByRuntime("referenced in c++")]
internal const uint KERNEL_BOUNDARY = 0x40000000; // 1GB
// This determines the maximum virtual address
// we will use. Setting this to less than the
// machine's maximum pointer size can reduce the
// overhead of paging structures.
//
// NOTE: we are not currently safe to use the top
// bit of addresses (because of the "mark" bit in the
// multi-use word header), so restrict ourselves to the
// bottom 2GB.
[AccessedByRuntime("referenced in c++")]
public const uint MAX_VIRTUAL_ADDR = 0x80000000; // 2GB
// Exit Codes:
[AccessedByRuntime("referenced in c++")]
internal const int EXIT_AND_RESTART = 0x1fff;
[AccessedByRuntime("referenced in c++")]
internal const int EXIT_AND_SHUTDOWN = 0x1ffe;
[AccessedByRuntime("referenced in c++")]
internal const int EXIT_AND_WARMBOOT = 0x1ffd;
[AccessedByRuntime("referenced in c++")]
internal const int EXIT_AND_HALT = 0x1ffc;
///////////////////////////////////////////////////////////////////////
// Boot configuration information: this is all filled out by the loader
///////////////////////////////////////////////////////////////////////
// Size of instance; this is a versioning/consistency check
[AccessedByRuntime("referenced in c++")]
public readonly int Size;
#if ISA_IX64
[AccessedByRuntime("referenced in c++")]
public readonly UIntPtr Dummy;
#endif
[AccessedByRuntime("referenced in c++")]
public readonly uint BootYear;
[AccessedByRuntime("referenced in c++")]
public readonly uint BootMonth;
[AccessedByRuntime("referenced in c++")]
public readonly uint BootDay;
[AccessedByRuntime("referenced in c++")]
public readonly uint BootHour;
[AccessedByRuntime("referenced in c++")]
public readonly uint BootMinute;
[AccessedByRuntime("referenced in c++")]
public readonly uint BootSecond;
// Max # of CPUs allowed. !!! is this a long term thing? Should it be a constant?
[AccessedByRuntime("referenced in c++")]
public readonly int CpuMaxCount;
[AccessedByRuntime("referenced in c++")]
public readonly int CpuRealCount;
// Warm boot count (0 = cold boot, 1 = first warm boot, etc.)
[AccessedByRuntime("referenced in c++")]
public readonly int BootCount;
// Description of memory
// @todo: this is a simple description of devices in the physical address space.
// Eventually we want a richer way for HAL to communicate the memory layout to
// S, rather than having S make assumptions about where HAL is and isn't using memory.
[AccessedByRuntime("referenced in c++")]
// Field must be integral for 16-bit boot code
public readonly UIntPtr Smap32;
public unsafe Microsoft.Singularity.SMAPINFO *Smap {
[NoHeapAllocation]
get {
return (Microsoft.Singularity.SMAPINFO *) Smap32;
}
}
[AccessedByRuntime("referenced in c++")]
public readonly int SmapCount;
// Lowest address which should be accessed as physical memory
[AccessedByRuntime("referenced in c++")]
public readonly UIntPtr PhysicalBase;
//For now I'm just doing a single communication channel from subservient kernel
//to the BSP kernel.
[AccessedByRuntime("referenced in c++")]
unsafe public readonly uint*OutgoingMessage;
[AccessedByRuntime("referenced in c++")]
unsafe public readonly int* OutgoingCount;
[AccessedByRuntime("referenced in c++")]
unsafe public readonly uint*IncomingFree; //previously sent messages that cane be safely freed
[AccessedByRuntime("referenced in c++")]
unsafe public readonly int* IncomingFreeCount;
[AccessedByRuntime("referenced in c++")]
unsafe public readonly uint*IncomingMessage; //messages bound for this kernel
[AccessedByRuntime("referenced in c++")]
unsafe public readonly int* IncomingCount;
[AccessedByRuntime("referenced in c++")]
unsafe public readonly uint*OutgoingFree; // messages that this kernel has processed
[AccessedByRuntime("referenced in c++")]
unsafe public readonly int* OutgoingFreeCount;
[AccessedByRuntime("referenced in c++")]
public readonly uint MaxBufferLength;
[AccessedByRuntime("referenced in c++")]
public readonly uint thisDestinationId;
[AccessedByRuntime("referenced in c++")]
public readonly uint hasApic;
public int ApicId {
[NoHeapAllocation]
get {
#if ISA_IX
if(hasApic == 1) {
// THIS SHOULD GO AWAY. WE SHOULD:
// - 1. CHECK HEAP ALLOCATOR INITIALIZED AND PROCESSOR TABLE
// - YES, return info from processor
// - NO, return 0
uint p0, p1, p2, p3;
Isa.ReadCpuid((uint)1, out p0, out p1, out p2, out p3);
return (int)((p1 & 0xFF000000) >> 24);
}
return 0;
#elif ISA_ARM
return 0;
#else
#error "E_UNSUPPORTED_PLATFORM"
#endif
}
}
//
// This represents "boot memory" in which
// managed structures are allocated before the
// GC and memory manager is initialized. These
// pages must be marked early in MM initialization
// so that they are known as nonGC pages.
//
// It is OK for this to be null if a given platform
// allocates these classes in memory that is otherwise
// accounted for.
//
// Examples are the Platform class, and each
// processor class.
//
[AccessedByRuntime("referenced in c++")]
public readonly UIntPtr BootAllocatedMemory;
[AccessedByRuntime("referenced in c++")]
public readonly UIntPtr BootAllocatedMemorySize;
// Command line (if any) given to HAL launcher.
// !!! either generalize this or distill it to specific options.
[AccessedByRuntime("referenced in c++")]
// Field must be integral for 16-bit boot code
public readonly UIntPtr CommandLine32;
public unsafe char * CommandLine {
[NoHeapAllocation]
get {
return (char *) CommandLine32;
}
}
[AccessedByRuntime("referenced in c++")]
public readonly int CommandLineCount;
// CpuContext record is stored off of FS at the value stored at the following offset
// of fs. A platform is guaranteed to have 2 pointers available at this offset.
[AccessedByRuntime("referenced in c++")]
public readonly unsafe int CpuRecordPointerOffset;
[AccessedByRuntime("referenced in c++")]
public readonly unsafe int ThreadRecordPointerOffset;
// Various logging buffers
// !!! Move these out of HAL
[AccessedByRuntime("referenced in c++")]
public readonly UIntPtr LogRecordBuffer;
[AccessedByRuntime("referenced in c++")]
public readonly UIntPtr LogRecordSize;
[AccessedByRuntime("referenced in c++")]
public readonly UIntPtr LogTextBuffer;
[AccessedByRuntime("referenced in c++")]
public readonly UIntPtr LogTextSize;
// Kernel Dll (kernel.x86) where S execution will begin;
// this is reported to S for use in debugging infrastructure
[AccessedByRuntime("referenced in c++")]
public readonly UIntPtr KernelDllBase;
[AccessedByRuntime("referenced in c++")]
public readonly UIntPtr KernelDllSize;
[AccessedByRuntime("referenced in c++")]
public readonly UIntPtr KernelDllFirstPage; // first page may be disjoint on CE
// Initial minidump file address (if any)
[AccessedByRuntime("referenced in c++")]
public readonly UIntPtr MiniDumpBase;
[AccessedByRuntime("referenced in c++")]
public readonly UIntPtr MiniDumpLimit;
// TODO: Remove DebuggerType; replace with BOOL and always go through HAL
// Debugger type to attach to
[AccessedByRuntime("referenced in c++")]
public readonly int DebuggerType;
// Debugger type enumeration
[AccessedByRuntime("referenced in c++")]
public const int DEBUGGER_NONE = 0;
[AccessedByRuntime("referenced in c++")]
public const int DEBUGGER_SERIAL = 1;
[AccessedByRuntime("referenced in c++")]
public const int DEBUGGER_1394 = 2;
// EntryPoint return values
[AccessedByRuntime("referenced in c++")]
public const int SUCCESS = 0;
[AccessedByRuntime("referenced in c++")]
public const int ERROR_BAD_SIZE = 1;
[AccessedByRuntime("referenced in c++")]
public const int ERROR_BAD_PLATFORM = 2;
///////////////////////////////////////////////////////////////////////
// Platform abstractions - these are filled in by the HAL during kernel
// initialization
///////////////////////////////////////////////////////////////////////
[AccessedByRuntime("referenced in c++")]
public static Platform thePlatform;
[AccessedByRuntime("referenced in c++")]
protected Cpu bootCpu;
public static Platform ThePlatform
{
[Inline]
[NoHeapAllocation]
get {
return thePlatform;
}
}
public static Cpu BootCpu
{
[Inline]
[NoHeapAllocation]
get {
return thePlatform.bootCpu;
}
}
public static Cpu CurrentCpu
{
[Inline]
[NoHeapAllocation]
get {
return GetCurrentCpu();
}
}
[AccessedByRuntime("accessed by C++")]
[Inline]
[NoHeapAllocation]
public static Cpu Cpu(int id)
{
return thePlatform.GetCpu(id);
}
// Returns the current processor. Note that in general you need to
// have preemption disabled for this to return a meaningful value.
[AccessedByRuntime("defined in hal.cpp")]
[MethodImpl(MethodImplOptions.InternalCall)]
[NoHeapAllocation]
[StackBound(32)]
public static extern Cpu GetCurrentCpu();
// Platform is initially configured before Kernel.Main. At this point
// it is a minimal shell containing the boot records and the boot processor
// information. Services are not available until InitializeServices is
// called later (which requires the object heap to be set up.)
// called before boot; cannot allocate memory
[NoHeapAllocation]
[AccessedByRuntime("referenced in c++")]
public unsafe void Initialize(Cpu bootCpu)
{
this.bootCpu = bootCpu;
thePlatform = this;
}
/// Platform
#region BootInformation
// Sanity Check
public uint RecSize;
// Debug Stub Information
#if ISA_IX
public ushort DebugBasePort;
#elif ISA_ARM
public uint DebugBasePort;
#endif
public ushort DebugSpinBase;
public uint TwiddleSpinBase;
// Self-descriptive information
public ulong Info32;
public ulong Kill32;
public uint KillAction;
// Location (in high memory) of the executable images
public ulong DumpAddr32;
// File image table ???
public ulong FileImageTableBase32;
public uint FileImageTableEntries;
// Extent of that data
public uint DumpSize32;
public ulong DumpRemainder;
// Marks the highest address used by the kernel image (undumped from high memory)
public ulong DumpLimit;
public ulong NativeContext;
public ulong Cpus;
#if ISA_IX64
public ulong Ppml432; // pointer to Page Map Level-4
public ulong AddrTss; // pointer to the 64-bit TSS containing the IST stack table
#endif
// IDT and PIC
public ushort BiosPicMask;
public byte BiosWarmResetCmos;
public uint BiosWarmResetVector;
public uint Info16;
// Temporary IDT
public ulong IdtEnter0;
public ulong IdtEnter1;
public ulong IdtEnterN;
public ulong IdtTarget;
public ulong Pdpt32;
//
// This is the kernel's operating map that secondary processors
// must use. It may be updated by the kernel during the CPU 0
// initialization process.
//
// Initially set to the same value as Pdpt32 by singboot when
// CPU 0 is initialized.
//
public ulong KernelPdpt64;
public ulong Undump;
// PCI Information (V2.0+)
public uint PciBiosAX;
public uint PciBiosBX;
public uint PciBiosCX;
public uint PciBiosEDX;
// BIOS Information
public ulong AcpiRoot32;
public ulong PnpNodesAddr32;
public uint PnpNodesSize32;
public ulong SmbiosRoot32;
public ulong DmiRoot32;
public uint IsaCsns;
public ushort IsaReadPort;
public uint Ebda32;
public uint MpFloat32;
// 1394 Information
public ulong Ohci1394Base;
public ulong Ohci1394BufferAddr32;
public uint Ohci1394BufferSize32;
// VESA Information
public ulong VesaBuffer;
// MP specific variables
public ulong MpEnter32; // Entry point
public uint MpCpuCount; // No of AP's booted
public uint MpStatus32; // Error indicator
public ulong MpStartupLock32; // Pointer to MP init lock var
public Microsoft.Singularity.MpBootInfo MpBootInfo;
#endregion // BootInformation
//////////////////////////////////////////////////////////////////////
// Kernel fields initialized by early kernel code
//////////////////////////////////////////////////////////////////////
private Cpu[] processors;
private HalDevices devices;
[NoHeapAllocation]
public void RegisterCpu(Cpu p)
{
DebugStub.Assert(processors != null);
DebugStub.Assert(p.Id >= 0);
DebugStub.Assert(p.Id < processors.Length);
DebugStub.Assert((processors[p.Id] == null) || (processors[p.Id] == p));
processors[p.Id] = p;
}
// This routine is used to report GC objects which are manufactured by the
// HAL, in order to trace their reference fields. (Note that such objects
// must also end up on pages labelled NonGC for tracing, etc to work correctly.)
internal void VisitSpecialData(System.GCs.ReferenceVisitor visitor)
{
// The Platform object and the processor objects are all allocated
// on fixed pages, so must be explicitly traced.
visitor.VisitReferenceFields(thePlatform);
foreach (Cpu p in processors) {
if (p != null) {
visitor.VisitReferenceFields(p);
}
}
}
[NoHeapAllocation]
public bool DisableInterrupts()
{
return Isa.DisableInterrupts();
}
[NoHeapAllocation]
public void EnableInterrupts()
{
Isa.EnableInterrupts();
}
[NoHeapAllocation]
public bool AreInterruptsDisabled()
{
return Isa.AreInterruptsDisabled();
}
// Halt causes the current CPU to cease execution until an interrupt occurs.
[NoHeapAllocation]
public void Halt()
{
// @BUG this is broken - we can migrate to another CPU
CurrentCpu.halted = true;
Isa.Halt();
}
// RendezvousCpus sends a rendezvous to the other processors.
[NoHeapAllocation]
public void RendezvousCpus()
{
// Not implemented
}
// Kill exits the platform environment.
[AccessedByRuntime("referenced in c++")]
[MethodImpl(MethodImplOptions.InternalCall)]
[StackBound(64)]
[NoHeapAllocation]
private static extern void NativeKill(int exitCode);
[NoHeapAllocation]
public void Kill(int exitCode)
{
NativeKill(exitCode);
}
// TBD: there is currently no standard processor array, it is maintained by the HAL.
// (Not sure if this is valuable.)
[NoHeapAllocation]
public Cpu GetCpu(int i)
{
return processors[i];
}
// This will cause the CPUs to get enabled; each will have EntryPoint called
public void EnableMoreCpus(int cpus)
{
//
// Currently a separate code path in kernel.cs calls the HalDevices.StartApProcessors()
// due to layering issues with the HalPic's in the kernel, and the HAL being below
// the kernel not allowed to call up into the kernel. Eventually when these
// devices move into the HAL (and PNP resource assignment issues are resolved) this
// code will call StartAppProcessors(cpus).
//
}
#region Debugging
[NoHeapAllocation]
public void FreezeAllCpus()
{
devices.FreezeProcessors();
}
#endregion // debugging
#region Timer
// Request that an interrupt fire immediately on the given processor.
// Note that this may be called on other CPUs to facilitate IPC.
[NoHeapAllocation]
public void WakeNow(int cpu)
{
int fromCpu = Microsoft.Singularity.Processor.GetCurrentProcessorId();
devices.SendFixedIPI((byte)Kernel.HalIpiInterrupt, fromCpu, cpu);
}
#endregion // Timer
// This is called to fully initialize the platform
public void InitializeServices()
{
processors = new Cpu[CpuMaxCount];
processors[0] = bootCpu;
bootCpu.InitializeServices();
// TBD
}
#region HAL
// Get our HalDevices interface from the externally implemented HAL
public static void InitializeHal(Processor processor)
{
thePlatform.devices = (HalDevices)HalDevicesFactory.Initialize(processor);
}
public static void ReleaseResources()
{
thePlatform.devices.ReleaseResources();
}
//
// Adding and removing interrupts from the Pic.
//
[NoHeapAllocation]
public static void EnableIoInterrupt(byte irq)
{
thePlatform.devices.EnableIoInterrupt(irq);
}
[NoHeapAllocation]
public static void DisableIoInterrupt(byte irq)
{
thePlatform.devices.DisableIoInterrupt(irq);
}
[NoHeapAllocation]
public static bool InternalInterrupt(byte interrupt)
{
return thePlatform.devices.InternalInterrupt(interrupt);
}
[NoHeapAllocation]
public static byte GetMaximumIrq()
{
return thePlatform.devices.GetMaximumIrq();
}
[NoHeapAllocation]
public static int GetProcessorCount()
{
return thePlatform.devices.GetProcessorCount();
}
public static void StartApProcessors(int cpus)
{
thePlatform.devices.StartApProcessors(cpus);
}
[NoHeapAllocation]
public static void ResetApProcessors()
{
thePlatform.devices.ResetApProcessors();
}
[NoHeapAllocation]
public static void FreezeProcessors()
{
thePlatform.devices.FreezeProcessors();
}
// send fixed interrupt
[NoHeapAllocation]
public static void SendFixedIPI(byte vector, int from, int to)
{
thePlatform.devices.SendFixedIPI(vector, from, to);
}
[NoHeapAllocation]
public static void BroadcastFixedIPI(byte vector, bool includeSelf)
{
thePlatform.devices.BroadcastFixedIPI(vector, includeSelf);
}
[NoHeapAllocation]
public static void ClearFixedIPI(int interrupt)
{
thePlatform.devices.ClearFixedIPI(interrupt);
}
public static byte TranslatePciInterrupt(byte currentInterruptLine,
byte pciInterruptPin,
PciPort pciPort)
{
return thePlatform.devices.TranslatePciInterrupt(currentInterruptLine,
pciInterruptPin,
pciPort);
}
#endregion // HAL
}
}