singrdk/base/Kernel/Singularity/Kernel.cs

1034 lines
36 KiB
C#

///////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// 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.Directory;
using Microsoft.Singularity.Drivers;
using Microsoft.Singularity.Eventing;
using Microsoft.Singularity.Hal;
using Microsoft.Singularity.Io;
using Microsoft.Singularity.Loader;
using Microsoft.Singularity.Memory;
using Microsoft.Singularity.Scheduling;
using Microsoft.Singularity.Security;
using Microsoft.Singularity.V1.Services;
using Microsoft.Singularity.Xml;
[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)]
[AccessedByRuntime("referenced from hal.cpp/hal.cpp")]
public class Kernel
{
private static string[] args;
private static ManualResetEvent mpEndEvent;
private static int bootReturnCode;
// sample profiler kernel data
public static uint ProfilerBufferSize;
#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 PBAR if this is readonly then it seems to read as 0!
// This is temporary, until we get a HAL-based plug-and-play system going.
public const byte HalIpiInterrupt = 249;
/// <summary> Flag indicating if kernel has succesfully booted </summary>
private static bool hasBooted;
private static Scheduler scheduler;
///
/// <summary>
/// Property to find out if kernel finished booting
/// </summary>
///
public static bool HasBooted
{
[NoHeapAllocation]
get
{
return hasBooted;
}
}
/// <summary>
/// Get a default kernel scheduler
/// </summary>
internal static Scheduler TheScheduler
{
[Inline]
[NoHeapAllocation]
get
{
return scheduler;
}
}
[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
internal static DateTime BootTime;
// [System.Diagnostics.Conditional("ISA_ARM")]
private static void ARM_PROGRESS(string msg)
{
DebugStub.WriteLine(msg);
}
[System.Diagnostics.Conditional("ISA_ARM")]
private static void ARM_SPIN_FOREVER(string msg)
{
DebugStub.Assert(!Processor.InterruptsDisabled());
Processor p = Processor.CurrentProcessor;
DebugStub.WriteLine(msg);
DateTime last = DateTime.Now;
uint n = 0;
while (true) {
Thread.Sleep(1000);
}
}
// Note: This function is called by Hal.cpp.
[AccessedByRuntime("referenced from hal.cpp")]
internal static int Main()
{
bootReturnCode = Platform.EXIT_AND_RESTART;
InitPreMonitoring();
try {
InitServices();
// Consider boot successful at this stage.
bootReturnCode = Platform.EXIT_AND_SHUTDOWN;
ARM_SPIN_FOREVER("kernel.arm Spinning forever");
bootReturnCode = SpawnAndWaitForShell();
// The shell has exited when we get here
FinalizeServices();
}
catch (Exception e) {
System.Console.WriteLine("EXCEPTION:: " + e.Message);
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));
FinalizePreMonitoring();
if (bootReturnCode != Platform.EXIT_AND_WARMBOOT) {
Kill(bootReturnCode);
}
return bootReturnCode;
}
private static void InitPreMonitoring()
{
Tracing.Log(0);
Tracing.Log(1);
Tracing.Log(2);
Tracing.Log(3);
DebugStub.WriteLine("-------------------------------------------------------------------------------");
ARM_PROGRESS("Kernel!001");
// Indicate that we are not booted yet
hasBooted = false;
// Rather than mark all bootstrap code with [NoBarriers], perform a mini-
// initialization that gives us a working WriteBarrier.
System.GCs.Barrier.PreInitialize();
ARM_PROGRESS("Kernel!002");
// Initialize the memory subsystem. If enabled 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
ARM_PROGRESS("Kernel!003");
HandleTable.Initialize();
}
private static void InitGCSupport()
{
ARM_PROGRESS("Kernel!004");
// Initialize the rest of the primitive runtime.
VTable.Initialize((RuntimeType)typeof(Kernel));
ARM_PROGRESS("Kernel!005");
// Must occur before MemoryManager.PostGCInitialize()
ProtectionDomain.Initialize();
ARM_PROGRESS("Kernel!006");
// Must occur before SharedHeap.Initialize()
MemoryManager.PostGCInitialize();
ARM_PROGRESS("Kernel!007");
// Allocates callback objects for stack growth
Stacks.Initialize();
ARM_PROGRESS("Kernel!008");
// Initialize the HAL parts which require GC allocation
Platform.ThePlatform.InitializeServices();
ARM_PROGRESS("Kernel!009");
SharedHeap.Initialize();
ARM_PROGRESS("Kernel!010");
// Must occur after SharedHeap.Initialize();
ProtectionDomain.DefaultDomain.InitHook();
}
private static void InitServices()
{
InitGCSupport();
args = GetCommandLine();
VTable.ParseArgs(args);
ARM_PROGRESS("Kernel!011");
InitSchedulerTypes();
ARM_PROGRESS("Kernel!018");
Controller.InitializeSystem();
Tracing.InitializeSystem();
ARM_PROGRESS("Kernel!019");
// Read the profiler settings. The values are assumed in kbytes
// convert them to bytes for direct consumption
ProfilerBufferSize = (uint)GetIntegerArgument("profiler", 0);
ProfilerBufferSize *= 1024;
ARM_PROGRESS("Kernel!020");
SpinLock.StaticInitialize();
int cpusLength;
int cpuCount = GetCpuCount(out cpusLength);
Processor.InitializeProcessorTable(cpusLength);
ARM_PROGRESS("Kernel!021");
Tracing.Log(Tracing.Audit, "processor");
Processor processor = Processor.EnableProcessor(0);
PEImage.Initialize();
ARM_PROGRESS("Kernel!034");
// Initialize the sample profiling for the processor
// after the initial breakpoint in kd in the call
// PEImage.Initialize(). This will allow enabling profiling
// from kd, by overwriting the ProfilerBufferSize value
processor.EnableProfiling();
ARM_PROGRESS("Kernel!035");
FlatPages.InitializeMemoryMonitoring();
// initialize endpoints
InitType(typeof(Microsoft.Singularity.Channels.EndpointCore));
// TODO Bug 59: Currently broken, need to review paging build.
//#if PAGING
// Microsoft.Singularity.Channels.EndpointTrusted.StaticInitialize();
//#endif
ARM_PROGRESS("Kernel!036");
// get the system manifest
IoMemory systemManifest = GetSystemManifest();
ARM_PROGRESS("Kernel!037");
XmlReader xmlReader = new XmlReader(systemManifest);
XmlNode xmlData = xmlReader.Parse();
XmlNode manifestRoot = xmlData.GetChild("system");
XmlNode initConfig = manifestRoot.GetChild("initConfig");
ARM_PROGRESS("Kernel!038");
PerfCounters.Initialize();
// need to have processed the manifest before we can call Process initialize
ARM_PROGRESS("Kernel!039");
PrincipalImpl.Initialize(initConfig);
ARM_PROGRESS("Kernel!040");
Process.Initialize(manifestRoot.GetChild("processConfig"));
InitIO(processor, initConfig, manifestRoot.GetChild("drivers"));
InitBootTime();
ARM_PROGRESS("Kernel!045");
// From here on, we want lazy type initialization to worry about
// competing threads.
VTable.InitializeForMultipleThread();
ARM_PROGRESS("Kernel!046");
Console.WriteLine("Running C# Kernel of {0}", GetLinkDate());
Console.WriteLine();
// TODO: remove this
Console.WriteLine("Current time: {0}", SystemClock.GetUtcTime().ToString("r"));
ARM_PROGRESS("Kernel!047");
InitScheduling();
DirectoryService.StartNotificationThread();
Console.WriteLine("Initializing Shared Heap Walker");
ProtectionDomain.InitializeSharedHeapWalker();
ARM_PROGRESS("Kernel!050");
Console.WriteLine("Initializing Service Thread");
ServiceThread.Initialize();
ARM_PROGRESS("Kernel!051");
GC.EnableHeap();
GCProfilerLogger.StartProfiling();
ARM_PROGRESS("Kernel!052");
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);
ARM_PROGRESS("Kernel!053");
#if ISA_ARM && TEST_GC
for (int i = 0; i < 1000; i++) {
DebugStub.WriteLine("Iteration {0}", __arglist(i));
ArrayList a = new ArrayList();
for (int j = 0; j < 128; j++) {
int size = 1024 * 1024;
a.Add(new byte [size]);
}
}
#endif // ISA_ARM
ARM_PROGRESS("Kernel!054");
Tracing.Log(Tracing.Audit, "Binder");
Binder.Initialize(manifestRoot.GetChild("namingConventions"));
#if ISA_ARM
DebugStub.WriteLine("Exporting local namespace to BSP\n");
DirectoryService.ExportArmNamespace();
DebugStub.WriteLine("Export complete...redirecting binder\n");
Binder.RedirectRootRef();
DebugStub.WriteLine("Binder redirect complete\n");
#endif
#if false
Tracing.Log(Tracing.Audit, "Starting Security Service channels");
PrincipalImpl.Export();
ARM_PROGRESS("Kernel!055");
#endif
Tracing.Log(Tracing.Audit, "Creating Root Directory.");
//This can be moved below
IoSystem.InitializeDirectoryService();
ARM_PROGRESS("Kernel!055");
#if false
// Start User space namespace manager
Console.WriteLine("Starting Directory Service SIP");
DirectoryService.StartUserSpaceDirectoryService();
#endif
ARM_PROGRESS("Kernel!055.5");
#if !ISA_ARM
Tracing.Log(Tracing.Audit, "Starting Security Service channels");
PrincipalImpl.Export();
#endif
ARM_PROGRESS("Kernel!056");
Console.WriteLine("Initializing system channels");
// starting channels services
DebugStub.Print("Initializing Channel Services\n");
ChannelDeliveryImplService.Initialize();
ARM_PROGRESS("Kernel!057");
ConsoleOutput.Initialize();
ARM_PROGRESS("Kernel!058");
// 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");
// For ABI to ARM support
MpExecution.Initialize();
ARM_PROGRESS("Kernel!059");
mpEndEvent = new ManualResetEvent(false);
Tracing.Log(Tracing.Audit, "Initializing Volume Manager.");
#if !ISA_ARM
IoSystem.InitializeVolumeManager();
#endif // ISA_ARM
ARM_PROGRESS("Kernel!060");
InitDrivers();
if (cpuCount > 1) {
unsafe {
Console.WriteLine("Enabling {0} cpus out of {1} real cpus\n", cpuCount, Platform.ThePlatform.CpuRealCount);
}
Processor.EnableMoreProcessors(cpuCount);
ARM_PROGRESS("Kernel!064");
}
Tracing.Log(Tracing.Audit, "Initializing Service Manager.");
IoSystem.InitializeServiceManager(manifestRoot.GetChild("serviceConfig"));
ARM_PROGRESS("Kernel!065");
InitDiagnostics();
#if !ISA_ARM
// At this point consider kernel finshed booting
hasBooted = true;
#endif // ISA_ARM
Processor.StartSampling();
ARM_PROGRESS("Kernel!069");
Microsoft.Singularity.KernelDebugger.KdFilesNamespace.StartNamespaceThread();
ARM_PROGRESS("Kernel!070");
}
private static void InitSchedulerTypes()
{
InitType(typeof(Processor));
InitType(typeof(Scheduler));
InitType(typeof(ProcessorDispatcher));
// InitType(typeof(AffinityScheduler));
InitType(typeof(MinScheduler));
ARM_PROGRESS("Kernel!013");
// Create scheduler before initializing processes
scheduler = new MinScheduler();
ARM_PROGRESS("Kernel!017");
// Initialize processor dispatcher
ProcessorDispatcher.StaticInitialize(scheduler);
}
private static void InitScheduling()
{
Console.WriteLine("Initializing Scheduler");
ARM_PROGRESS("Kernel!047");
// Finish scheduler initialization:
scheduler.Initialize();
ARM_PROGRESS("Kernel!048");
// Initialize initial dispatcher
Processor.InitializeDispatcher(0);
Processor.ActivateTimer(0);
ARM_PROGRESS("Kernel!049");
}
private static void InitIO(Processor p, XmlNode initConfig, XmlNode driverConfig)
{
// obtain the configuration for the namespace service
// and initialize the namespace service
ARM_PROGRESS("Kernel!041");
DirectoryService.Initialize(initConfig);
Tracing.Log(Tracing.Audit, "IoSystem");
ARM_PROGRESS("Kernel!042");
IoSystem.Initialize(driverConfig);
Tracing.Log(Tracing.Audit, "Registering HAL Drivers.");
ARM_PROGRESS("Kernel!043");
Devices.RegisterPnpResources(); // add the root devices
ARM_PROGRESS("Kernel!044");
Platform.InitializeHal(p);
}
private static int SpawnAndWaitForShell()
{
#if ISA_ARM
// spin here for now
while (true) {
Thread.Yield();
}
#else
Tracing.Log(Tracing.Audit, "Creating Shell Process");
ARM_PROGRESS("Kernel!071");
int exit = -10000;
Manifest manifest;
#if KERNEL_USE_LOGIN
IoMemory memory;
if (args[0] == "bvt") {
memory = Binder.LoadImage(Thread.CurrentProcess, "tty", 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", out manifest);
}
#else
IoMemory memory = Binder.LoadImage(Thread.CurrentProcess, "tty", out manifest);
#endif
ARM_PROGRESS("Kernel!073");
if (memory == null || memory.Length > 0) {
String[] shellArgs = new String[args.Length + 2];
shellArgs[0] = "tty";
shellArgs[1] = "shell";
for (int i = 0; i < args.Length; i++) {
shellArgs[i + 2] = args[i];
}
Process process = new Process(Thread.CurrentProcess, memory, null, shellArgs, manifest);
if (process != null) {
PrintBootTime();
process.Start();
process.Join();
exit = process.ExitCode;
}
ARM_PROGRESS("Kernel!074");
}
return DetermineShutdown(exit);
#endif
}
private static int DetermineShutdown(int exit)
{
switch (exit) {
case -10000:
Tracing.Log(Tracing.Audit, "Failed to start shell process.");
return Platform.EXIT_AND_RESTART;
case Platform.EXIT_AND_WARMBOOT:
case Platform.EXIT_AND_RESTART:
case Platform.EXIT_AND_SHUTDOWN:
return exit;
default:
DebugStub.WriteLine("Shell process terminated improperly (0x{0:x4})",
__arglist(exit));
Tracing.Log(Tracing.Audit, "Shell process terminated improperly");
DebugStub.Break();
return Platform.EXIT_AND_SHUTDOWN;
}
}
private static void InitBootTime()
{
if (Platform.ThePlatform.BootYear != 0) {
BootTime = new DateTime((int)Platform.ThePlatform.BootYear,
(int)Platform.ThePlatform.BootMonth,
(int)Platform.ThePlatform.BootDay,
(int)Platform.ThePlatform.BootHour,
(int)Platform.ThePlatform.BootMinute,
(int)Platform.ThePlatform.BootSecond,
0);
// There is no time zone support in Singularity, the clock assumes GMT
// but the CMOS reports it in local time. Hardcode the correction here for now
BootTime = BootTime.AddHours(8);
}
else {
// Other HALs do not capture the load time. Make the best effort to
// capture now, after the devices are initialized.
BootTime = DateTime.Now;
}
}
private static void InitDrivers()
{
// 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();
ARM_PROGRESS("Kernel!061");
// register the internal kernel drivers
Devices.RegisterInternalDrivers();
ARM_PROGRESS("Kernel!062");
#if DEBUG
// and output the results
IoSystem.Dump(false);
#endif
DebugStub.WriteLine("--- Activating Devices ----------------------------");
// now do device initialization
IoSystem.ActivateDrivers();
ARM_PROGRESS("Kernel!063");
#if DEBUG
// and output the results
// IoSystem.Dump(true);
#endif
}
private static void InitDiagnostics()
{
// Start up the kernel's diagnostics module
Console.WriteLine("Starting diagnostics module...");
Diagnostics.DiagnosticsModule.Initialize();
ARM_PROGRESS("Kernel!066");
// Start up the kernel's stress test module
Console.WriteLine("Initializing stress module...");
Stress.StressService.Initialize();
ARM_PROGRESS("Kernel!067");
}
private static IoMemory GetSystemManifest()
{
IoMemory res = Binder.GetSystemManifest();
if (res == null) {
DebugStub.WriteLine("Failed to load system manifest.");
DebugStub.Break();
throw new Exception("The system manifest could not be loaded.");
}
return res;
}
private static void FinalizeServices()
{
ARM_PROGRESS("Kernel!075");
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");
for (int i = 0; i < Processor.processorTable.Length; i++) {
Processor p = Processor.processorTable[i];
if (p != null) {
Console.WriteLine(" cpu {0}: {1} context switches, {2} interrupts", i, p.NumContextSwitches, p.NumInterrupts);
}
}
// Finalize the scheduler
scheduler.Finalize();
// We should turn off interrupts here!
Platform.ReleaseResources();
PEImage.Finalize();
DebugStub.WriteLine("Kernel Exiting [{0}]",
__arglist(bootReturnCode));
}
private static void FinalizePreMonitoring()
{
Stacks.Finalize();
HandleTable.Finalize();
SharedHeap.Finalize();
MemoryManager.Finalize();
}
private static int GetCpuCount(out int cpusLength)
{
int cpuReal = Platform.ThePlatform.CpuRealCount;
int cpuLimit = Platform.ThePlatform.CpuMaxCount;
DebugStub.Assert(cpuReal <= cpuLimit);
// See if the command line argument limits our processor count
int cpuCount = GetIntegerArgument("mp", cpuReal);
cpusLength = cpuReal;
#if !SINGULARITY_MP
if (cpuCount > 1) {
Console.WriteLine("Limiting processors to 1 due to SP build");
cpuCount = 1;
}
#endif
return cpuCount;
}
// Note: This function is entry point to the managed
// kernel for CPU's other than the bootstrap processor.
// It is called from the Hal or Hal.
[AccessedByRuntime("referenced from hal.cpp")]
internal static int MpMain(int cpu)
{
Tracing.Log(Tracing.Audit, "processor");
Processor processor = Processor.EnableProcessor(cpu);
// Initialize dispatcher
Processor.InitializeDispatcher(cpu);
// Initialize the HAL processor services
// Note that this must occur after EnableProcessor, as the kernel
// thread does not get bound until then. (It gets bound much
// earlier in the boot processor case -- need to decide if this difference is
// really appropriate.)
Platform.Cpu(cpu).InitializeServices();
Platform.InitializeHal(processor);
Thread.CurrentThread.Affinity = cpu;
Processor.ActivateTimer(cpu);
#if DEBUG_SYSTEM_LOCKUP
// Spin one CPU on debugger. For instance with a quad-proc
// box, spin CPU 3.
while (cpu == 3) {
if (DebugStub.PollForBreak() == true) {
DebugStub.Break();
}
}
#endif // DEBUG_SYSTEM_LOCKUP
Processor.RestoreInterrupts(true);
Tracing.Log(Tracing.Audit,
"Looping in processor's kernel thread.");
//while (cpu > 0) {
// Thread.Yield();
//}
// This probably won't be the
// ultimate way of dissociating kernel entry threads
// from the kernel.
DebugStub.Print("AP Processor started, about to wait\n");
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.DirectReferenceVisitor visitor)
{
Platform.ThePlatform.VisitSpecialData(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);
}
[AccessedByRuntime("defined in HAL.cpp")]
[MethodImpl(MethodImplOptions.InternalCall)]
[StackBound(256)]
[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 *)(Platform.ThePlatform.CommandLine),
0, Platform.ThePlatform.CommandLineCount)).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;
}
// kind the argument "key" and extract the string value following a colon.
internal static string
GetStringArgument(string key, string defaultValue)
{
key = key + ":";
for (int i = 0; i < args.Length; i++) {
string arg = args[i];
if ((arg.StartsWith("-") || arg.StartsWith("/")) &&
0 == String.Compare(arg, 1, key, 0, key.Length, true)) {
string result = arg.Substring(key.Length+1);
string[] newargs = new string[args.Length - 1];
Array.Copy(args, 0, newargs, 0, i);
Array.Copy(args, i + 1, newargs, i, args.Length - i - 1);
args = newargs;
return result;
}
}
return defaultValue;
}
internal static int GetIntegerArgument(string key, int defaultValue)
{
key = key + ":";
for (int i = 0; i < args.Length; i++) {
string arg = args[i];
if ((arg.StartsWith("-") || arg.StartsWith("/")) &&
0 == String.Compare(arg, 1, key, 0, key.Length, true)) {
string result = arg.Substring(key.Length+1);
string[] newargs = new string[args.Length - 1];
Array.Copy(args, 0, newargs, 0, i);
Array.Copy(args, i + 1, newargs, i, args.Length - i - 1);
args = newargs;
// TODO this should be try-parse
return Int32.Parse(result);
}
}
return defaultValue;
}
[NoHeapAllocation]
public static void RequestWarmBoot()
{
bootReturnCode = Platform.EXIT_AND_WARMBOOT;
}
[NoHeapAllocation]
public static void RequestRestart()
{
bootReturnCode = Platform.EXIT_AND_RESTART;
}
[NoHeapAllocation]
public static void RequestShutdown()
{
bootReturnCode = Platform.EXIT_AND_SHUTDOWN;
}
private static void Kill(int exitCode)
{
Platform.ThePlatform.Kill(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);
}
// Rationale for cutting the fact that no stack probes are permitted in this
// tree of calls:
//
// * We are already hosed.
// * Without this cut, places that cannot (transitively) tolerate stack link extensions
// * cannot call Panic.
[NoStackLinkCheckTransCut][IgnoreLockRank]
internal static void Panic(string why)
{
DebugStub.WriteLine("KERNEL PANIC: {0}", __arglist(why));
Shutdown(Platform.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");
}
internal static void PrintBootTime()
{
// Console.WriteLine("Current time: {0}", SystemClock.GetUtcTime().ToString("r"));
// Console.WriteLine("Boot time: {0}", BootTime.ToString("r"));
TimeSpan delta = SystemClock.GetUtcTime() - BootTime;
DebugStub.WriteLine("Elapsed boot time = {0} msec.", __arglist(delta.TotalMilliseconds));
}
}
}