///////////////////////////////////////////////////////////////////////////////
//
//  Microsoft Research Singularity
//
//  Copyright (c) Microsoft Corporation.  All rights reserved.
//
//  File: HalDevicesFactory.cs
//
//  Constructs the correct HAL implementation based on system configuation.
//

using System;
using System.Collections;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Threading;

using Microsoft.Singularity;
using Microsoft.Singularity.Hal;
using Microsoft.Singularity.Io;
using Microsoft.Singularity.Isal;

namespace Microsoft.Singularity.Hal
{
    [CLSCompliant(false)]
    public sealed class HalDevicesFactory
    {
        public static HalDevices devices = null;

        public static bool apic = false; // True if APIC is present

        public static object Initialize(Processor processor)
        {
            if (processor.Id == 0) {

                 // We have hardware PICS, determine which kind
                 //
                 // Detect if an APIC is present on the CPU
                 //
                 // From 8.4.2 Presence of the Local APIC on page 337 of the
                 // Intel 64 and IA-32 Architectures Software Developers Manual
                 //
                 // function (1) -> eax
                 // cpuid
                 // eax -> p0
                 // ebx -> p1
                 // ecx -> p2
                 // edx -> p3 Bit 9 set if APIC present
                 //
                 //
                 // Note: It has been noted that some older motherboards
                 //       may have an APIC capable processor, but a chipset
                 //       that does not properly support the APIC interrupt
                 //       protocol. These motherboards will remove the APIC
                 //       hardware tables from the ACPI tables as an indication
                 //       that the APIC present on the processor should not
                 //       be used. Of course these are uni-processor only
                 //       motherboards without hyperthreading or multiple-cores.
                 //
                 uint p0, p1, p2, p3;
                 Isa.ReadCpuid((uint)1, out p0, out p1, out p2, out p3);

                 if (((p3 >> 9) & 0x1) != 0) {
                     apic = true;
                     DebugStub.Print("HalDevices: CPUID says APIC present\n");
                 }
                 else {
                     apic = false;
                     DebugStub.Print("HalDevices: CPUID says APIC NOT present\n");
                 }

                 // Dynamically select the proper hardware support drivers
                 if (apic) {
                     devices = HalDevicesApic.Create();
                 }
                 else {
                     devices = HalDevicesLegacyPC.Create();
                 }
            }

            // This happens for all processors
            devices.Initialize(processor);

            return devices;
        }
    }
}

