singrdk/base/Kernel/Singularity/Kernel.cs

632 lines
22 KiB
C#

///////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: Kernel.cs
//
// Note:
//
using System;
using System.Collections;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.Bartok.Runtime;
using Microsoft.SingSharp;
using Microsoft.Singularity.Channels;
using Microsoft.Singularity.Drivers;
using Microsoft.Singularity.Hal;
using Microsoft.Singularity.Io;
using Microsoft.Singularity.Loader;
using Microsoft.Singularity.Memory;
using Microsoft.Singularity.Scheduling;
using Microsoft.Singularity.Directory;
using Microsoft.Singularity.Security;
using Microsoft.Singularity.Xml;
using Microsoft.Singularity.V1.Services;
[assembly: AssemblyTitle("Microsoft.Singularity")]
[assembly: AssemblyProduct("Microsoft Research Singularity Operating System")]
[assembly: AssemblyCompany("Microsoft Corporation")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyKeyFile("public.snk")]
[assembly: AssemblyDelaySign(true)]
namespace Microsoft.Singularity
{
[NoCCtor]
[CLSCompliant(false)]
public class Kernel
{
private static string[] args;
private static ManualResetEvent mpEndEvent;
private static int bootReturnCode;
#region Waypoints
public static long[] Waypoints;
public static int[] WaypointSeq;
public static int[] WaypointThd;
public static int WaypointNumber;// = 0;
public static long WaypointSamples;// = 0;
public static bool WaypointSuspicious;
public static uint WaypointInterrupt;
public const int NWP = 2048; // XXX if this is readonly then it seems to read as 0!
[Conditional("WAYPOINTS")]
[NoHeapAllocation]
public static void Waypoint0()
{
WaypointSamples++;
Waypoints[0] = (long)Processor.CycleCount;
WaypointNumber = 1;
WaypointSuspicious = false;
WaypointInterrupt = Processor.CurrentProcessor.NumInterrupts;
}
[Conditional("WAYPOINTS")]
[NoHeapAllocation]
public static void Waypoint(int num)
{
if (Waypoints == null || Waypoints[0] == 0 || WaypointNumber > NWP-1) {
return;
}
long delta = (long)Processor.CycleCount - Waypoints[0];
if (delta > 7000000) {
WaypointSuspicious = true;
}
WaypointSeq[WaypointNumber] = num;
WaypointThd[WaypointNumber] = Thread.GetCurrentThreadIndex();
Waypoints[WaypointNumber++] = delta;
}
[Conditional("WAYPOINTS")]
[NoHeapAllocation]
public static void WaypointDone()
{
Waypoints[0] = 0;
}
#if false
[Conditional("WAYPOINTS")]
[NoHeapAllocation]
public static void WaypointDump()
{
WaypointDump(NWP);
}
#endif
[Conditional("WAYPOINTS")]
public static void WaypointDump()
{
bool iflag = Processor.DisableInterrupts();
DebugStub.WriteLine("Interrupts: {0}",
__arglist(Processor.CurrentProcessor.NumInterrupts
- WaypointInterrupt));
DebugStub.WriteLine("WPT Waypoint Sequence THD Diff");
for (int i = 1; i < WaypointNumber; i++) {
DebugStub.WriteLine("{0,3:d} {1,10:d} {2,10:d} {3,3:d} {4,10:d}",
__arglist(
i,
Waypoints[i],
WaypointSeq[i],
WaypointThd[i].GetHashCode(),
Waypoints[i] - Kernel.Waypoints[i-1]));
}
Processor.RestoreInterrupts(iflag);
}
[Conditional("WAYPOINTS")]
[NoHeapAllocation]
public static void WaypointReset()
{
for (int i = 0; i < NWP; i++) {
Waypoints[i] = 0;
}
WaypointSamples = 0;
}
#endregion // Waypoints
// Note: This function is called by Hal.cpp.
[AccessedByRuntime("referenced from hal.cpp")]
internal static int Main()
{
bootReturnCode = BootInfo.EXIT_AND_RESTART;
DebugStub.WriteLine("Kernel.Main()");
// Initialize the memory subsystem. This turns on paging!
MemoryManager.Initialize();
// Note for Monitoring early boot process:
// if you ever want to monitor stuff before this point, you should
// allocate a static memory area in BootInit.cs, init the
// monitoring system earlier, hold the system at this point here,
// copy over all the collected data up to now to the new
// dynamically created buffer and continue
Monitoring.Initialize(); // uses page memory
HandleTable.Initialize();
Stacks.Initialize();
try {
// Initialize the rest of the primitive runtime.
VTable.Initialize((RuntimeType)typeof(Kernel));
#if PAGING
// Must occur before MemoryManager.PostGCInitialize()
ProtectionDomain.Initialize();
#endif
// Must occur before SharedHeap.Initialize()
MemoryManager.PostGCInitialize();
SharedHeap.Initialize();
#if PAGING
// Must occur after SharedHeap.Initialize();
ProtectionDomain.DefaultDomain.InitHook();
#endif
args = GetCommandLine();
VTable.ParseArgs(args);
// Initialize the processor table.
InitType(typeof(Processor));
InitType(typeof(Scheduler));
InitType(typeof(MinScheduler));
Processor.InitializeProcessorTable();
Tracing.Log(Tracing.Audit, "processor");
Processor processor = Processor.processorTable[0];
processor.Initialize(0);
PEImage.Initialize();
// initialize endpoints
InitType(typeof(Microsoft.Singularity.Channels.EndpointCore));
// get the system manifest
XmlReader xmlReader = new XmlReader(Binder.GetSystemManifest());
XmlNode xmlData = xmlReader.Parse();
XmlNode manifestRoot = xmlData.GetChild("system");
XmlNode initConfig = manifestRoot.GetChild("initConfig");
PerfCounters.Initialize();
// need to have processed the manifest before we can call Process initialize
PrincipalImpl.Initialize(initConfig);
Process.Initialize(manifestRoot.GetChild("processConfig"));
// obtain the configuration for the namespace service
// and initialize the namespace service
DirectoryService.Initialize(initConfig);
Tracing.Log(Tracing.Audit, "IoSystem");
IoSystem.Initialize(
manifestRoot.GetChild("drivers"));
Tracing.Log(Tracing.Audit, "Registering HAL Drivers.");
Devices.RegisterPnpResources(); // add the root device
HalDevices.Initialize(processor); //
#if SINGULARITY_MP
// haryadi -- at this point we have the SRAT table,
// Create per-processor address space now
MemoryManager.InitializeProcessorAddressSpace();
#endif
// From here on, we want lazy type initialization to worry about
// competing threads.
VTable.InitializeForMultipleThread();
Console.WriteLine("Running C# Kernel of {0}", GetLinkDate());
Console.WriteLine();
Console.WriteLine("Initializing Scheduler");
MinScheduler.Initialize(Process.idleProcess);
DirectoryService.StartNotificationThread();
Console.WriteLine("Initializing Shared Heap Walker");
Process.InitializeSharedHeapWalker();
Console.WriteLine("Initializing Service Thread");
ServiceThread.Initialize();
#if GENERATE_ABI_SHIM
// haryadi: add Ap service thread
Console.WriteLine("Initializing AP Service Thread");
ApServiceThread.Initialize();
#endif
Tracing.Log(Tracing.Audit, "Enabling GC Heap");
GC.EnableHeap();
Tracing.Log(Tracing.Audit, "Waypoints init");
Waypoints = new long[2048];
WaypointSeq = new int[2048];
WaypointThd = new int[2048];
Tracing.Log(Tracing.Audit, "Interrupts ON.");
Processor.RestoreInterrupts(true);
Tracing.Log(Tracing.Audit, "Starting Security Service channels");
PrincipalImpl.Export();
Tracing.Log(Tracing.Audit, "Creating Root Directory.");
IoSystem.InitializeDirectoryService();
// [TODO]turn off kernel interfaces to namespace here
Tracing.Log(Tracing.Audit, "Binder");
Binder.Initialize(
manifestRoot.GetChild("namingConventions"));
Tracing.Log(Tracing.Audit, "Creating console.");
ConsoleOutput.Initialize();
// Initialize MP after Binder and ConsoleOutput
// are initialized so there are no
// initialization races if the additional
// threads try to use them.
Tracing.Log(Tracing.Audit, "Starting additional processors");
MpExecution.Initialize();
mpEndEvent = new ManualResetEvent(false);
Processor.StartApProcessors();
Tracing.Log(Tracing.Audit, "Initializing Volume Manager.");
IoSystem.InitializeVolumeManager();
// Register drivers who depend on scheduling and resource
// management.
DebugStub.WriteLine("--- Registering Drivers ---------------------------");
Console.WriteLine("Registering Non-HAL Drivers.");
// register the metadata-based drivers
IoSystem.RegisterDrivers();
// register the internal kernel drivers
Devices.RegisterInternalDrivers();
NvPciLpcBridge.Register();
#if DEBUG
// and output the results
IoSystem.Dump(false);
#endif
DebugStub.WriteLine("--- Activating Devices ----------------------------");
// now do device initialization
IoSystem.ActivateDrivers();
#if DEBUG
// and output the results
IoSystem.Dump(true);
#endif
Tracing.Log(Tracing.Audit, "Initializing Service Manager.");
IoSystem.InitializeServiceManager(manifestRoot.GetChild("serviceConfig"));
// Start up the kernel's diagnostics module
Console.WriteLine("Starting diagnostics module...");
Diagnostics.DiagnosticsModule.Initialize();
// Start up the kernel's stress test module
Console.WriteLine("Initializing stress module...");
Stress.StressService.Initialize();
Processor.StartSampling();
// Consider boot successful at this stage.
bootReturnCode = BootInfo.EXIT_AND_SHUTDOWN;
DebugStub.WriteLine("----------------------------------------------------------");
DebugStub.WriteLine("RdTsc, Halt, RdTsc");
ulong beg;
ulong end;
beg = Processor.CycleCount;
Processor.HaltUntilInterrupt();
end = Processor.CycleCount;
DebugStub.WriteLine(" Begin: {0,16:d}", __arglist(beg));
DebugStub.WriteLine(" End: {0,16:d}", __arglist(end));
DebugStub.WriteLine(" Diff: {0,16:d}", __arglist(end - beg));
DebugStub.WriteLine("----------------------------------------------------------");
Tracing.Log(Tracing.Audit, "Creating Shell Process");
int exit = -10000;
Process process = null;
IoMemory memory;
Manifest manifest;
#if KERNEL_USE_LOGIN
if (args[0] == "bvt") {
memory = Binder.LoadImage(Thread.CurrentProcess, "tty.x86", out manifest);
}
else{
// TODO: The login app needs to be fixed to setup stdin and stdout pipes for
// the shell and pump the data back and forth.
memory = Binder.LoadImage(Thread.CurrentProcess, "login.x86", out manifest);
}
#else
memory = Binder.LoadImage(Thread.CurrentProcess, "tty.x86", out manifest);
#endif
if (memory != null && memory.Length > 0) {
String[] shellArgs = new String[args.Length + 2];
shellArgs[0] = "tty.x86";
shellArgs[1] = "shell.x86";
for (int i = 0; i < args.Length; i++) {
shellArgs[i + 2] = args[i];
}
process = new Process(Thread.CurrentProcess, memory, null, shellArgs, manifest);
if (process != null) {
process.Start();
process.Join();
exit = process.ExitCode;
}
}
switch (exit) {
case -10000:
Tracing.Log(Tracing.Audit, "Failed to start shell process.");
bootReturnCode = BootInfo.EXIT_AND_RESTART;
break;
case BootInfo.EXIT_AND_WARMBOOT:
bootReturnCode = BootInfo.EXIT_AND_WARMBOOT;
break;
case BootInfo.EXIT_AND_RESTART:
bootReturnCode = BootInfo.EXIT_AND_RESTART;
break;
case BootInfo.EXIT_AND_SHUTDOWN:
bootReturnCode = BootInfo.EXIT_AND_SHUTDOWN;
break;
}
Tracing.Log(Tracing.Audit, "Shutting down AP processors");
Processor.StopApProcessors();
Tracing.Log(Tracing.Audit, "Shutting down I/O system");
Console.WriteLine("Shutting down I/O system");
IoSystem.Finalize();
Tracing.Log(Tracing.Audit, "Interrupts OFF.");
Processor.DisableInterrupts();
Tracing.Log(Tracing.Audit, "Shutting down scheduler");
Console.WriteLine("Shutting down scheduler");
MinScheduler.Finalize();
// We should turn off interrupts here!
HalDevices.Finalize();
PEImage.Finalize();
DebugStub.WriteLine("Kernel Exiting [{0}]",
__arglist(bootReturnCode));
}
catch (Exception e) {
Tracing.Log(Tracing.Fatal, "Caught exception {0}", e.Message);
DebugStub.WriteLine("Caught {0}", __arglist(e.Message));
bootReturnCode = -1;
DebugStub.Break();
}
DebugStub.WriteLine("Kernel exiting with 0x{0:x4}",
__arglist(bootReturnCode));
Stacks.Finalize();
HandleTable.Finalize();
#if !PAGING
SharedHeap.Finalize();
#endif //PAGING
MemoryManager.Finalize();
if (bootReturnCode != BootInfo.EXIT_AND_WARMBOOT) {
Kill(bootReturnCode);
}
return bootReturnCode;
}
// Note: This function is entry point to the managed
// kernel for CPU's other than the bootstrap processor.
// It is called by Hal.cpp.
[AccessedByRuntime("referenced from hal.cpp")]
internal static int MpMain(int cpu)
{
Tracing.Log(Tracing.Audit, "processor");
Processor processor = Processor.processorTable[cpu];
processor.Initialize(cpu);
HalDevices.Initialize(processor);
Processor.CurrentProcessor.SetNextTimerInterrupt(TimeSpan.Zero);
Processor.RestoreInterrupts(true);
Tracing.Log(Tracing.Audit,
"Halting processor until first interrupt.");
Processor.HaltUntilInterrupt();
Tracing.Log(Tracing.Audit, "Resumed from halt.");
// This probably won't be the
// ultimate way of dissociating kernel entry threads
// from the kernel.
mpEndEvent.WaitOne();
return 0;
}
// This function is called by the GC to locate all non-static object
// references allocated somewhere other than the stack.
internal static
void VisitSpecialData(System.GCs.NonNullReferenceVisitor visitor)
{
Process.VisitSpecialData(visitor);
visitor.VisitReferenceFields(Processor.processorTable);
}
// This function is called by GCs that move object to update all
// object references contained in non-objects (i.e. unsafe structs).
internal static void UpdateAfterGC(Thread currentThread)
{
Processor.UpdateAfterGC(currentThread);
}
[MethodImpl(MethodImplOptions.InternalCall)]
[StackBound(8)]
[NoHeapAllocation]
private static unsafe extern char * HalGetLinkDate();
internal static unsafe string GetLinkDate()
{
return new String(HalGetLinkDate());
}
internal static unsafe string[] GetCommandLine()
{
String[] args =
(new String((char *)(BootInfo.HalGetBootInfo()->CmdLine32))).Split(null);
int dst = 0;
for (int src = 0; src < args.Length; src++) {
if (args[src] != null && args[src].Length > 0) {
args[dst++] = args[src];
}
}
if (dst < args.Length) {
String[] list = new String[dst];
for (int i = 0; i < dst; i++) {
list[i] = args[i];
}
return list;
}
return args;
}
[NoHeapAllocation]
public static void RequestWarmBoot()
{
bootReturnCode = BootInfo.EXIT_AND_WARMBOOT;
}
[NoHeapAllocation]
public static void RequestRestart()
{
bootReturnCode = BootInfo.EXIT_AND_RESTART;
}
[NoHeapAllocation]
public static void RequestShutdown()
{
bootReturnCode = BootInfo.EXIT_AND_SHUTDOWN;
}
[MethodImpl(MethodImplOptions.InternalCall)]
[StackBound(1024)]
[NoHeapAllocation]
private static extern void Kill(int exitCode);
internal static void Shutdown(int exitCode)
{
unchecked {
Tracing.Log(Tracing.Audit, "Kernel.Shutdown({0})", (UIntPtr)(uint)exitCode);
}
DebugStub.WriteLine("Kernel.Shutdown(0x{0:x4})",
__arglist(exitCode));
DebugStub.Break();
VTable.Shutdown(exitCode);
}
internal static void Panic(string why)
{
DebugStub.WriteLine("KERNEL PANIC: {0}", __arglist(why));
Shutdown(BootInfo.EXIT_AND_HALT);
}
//////////////////////////////////////////////////////////////////////
//
[NoHeapAllocation]
public static UIntPtr AddressOf(Object o)
{
return Magic.addressOf(o);
}
[NoHeapAllocation]
public static UIntPtr SizeOf(Object o)
{
return System.GCs.ObjectLayout.Sizeof(o);
}
[NoHeapAllocation]
public static UIntPtr AddressOf(ITracked tracked)
{
return Magic.addressOf(tracked);
}
[NoHeapAllocation]
unsafe public static UIntPtr AddressOf(void * ptr)
{
return (UIntPtr)ptr;
}
public static void InitType(Type ty)
{
VTable.initType((RuntimeType) ty);
}
[NoHeapAllocation]
public static string TypeName(Object o)
{
if (o == null) {
return "null";
}
else {
Type t = o.GetType();
RuntimeType r = (RuntimeType)t;
return r.Name;
}
}
[NoHeapAllocation]
public static string TypeNameSpace(Object o)
{
if (o == null) {
return "null";
}
else {
Type t = o.GetType();
RuntimeType r = (RuntimeType)t;
return r.Namespace;
}
}
public static string FullTypeName(Object o)
{
if (o == null) {
return "null";
}
else {
Type t = o.GetType();
RuntimeType r = (RuntimeType)t;
return r.Namespace + "." + r.Name;
}
}
public static void DumpPageTable()
{
System.GCs.PageTable.Dump("PageTable");
}
}
}