//////////////////////////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//


using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;

namespace Microsoft.Singularity.Isal.IX
{
    [NoCCtor]
    [AccessedByRuntime("referenced in c++")]
    [CLSCompliant(false)]
    [StructAlign(16)]
    [StructLayout(LayoutKind.Sequential, Pack=1, 
#if ISA_IX86
                  Size=256*8 // sizeof(Idte)
#else
                  Size=256*16 // sizeof(Idte)
#endif
                  )] 
    public struct InterruptTable
    {
        // Dispatcher is an opaque declaration of a code fragment which normalizes 
        // the stack with the interrupt id, then dispatches to the centralized dispatch routine.
        [AccessedByRuntime("referenced in asm")]
        [StructLayout(LayoutKind.Sequential, Pack=1, Size=16)]
        private struct Dispatcher
        {
            byte first;
        }

        // There are a total of 256 entries; this is controled by the StructLayout attribute above.
        Idte  entry0;

        unsafe Idte *GetStart() 
        {
            fixed (Idte *p = &entry0)
                return p;
        }

        unsafe Idte *GetEnd() 
        {
            fixed (Idte *p = &entry0)
                return p+256;
        }

        [AccessedByRuntime("defined in idt.asm")]
        [MethodImpl(MethodImplOptions.InternalCall)]
        [GCAnnotation(GCOption.NOGC)]
        [StackBound(16)]
        [NoHeapAllocation]
        private extern unsafe static Dispatcher *GetDispatchers();

        [NoHeapAllocation]
        public void Initialize()
        {
            unsafe {
                Dispatcher *d = GetDispatchers();

                fixed (Idte *first = &entry0) {
                    Idte *p = first;
                    Idte *pEnd = p + 256;

                    while (p < pEnd) {
                        InitializeEntry(ref *p, (UIntPtr) d);
                        p++;
                        d++;
                    }
                }
            }
        }

        [NoHeapAllocation]
        public static void InitializeEntry(ref Idte entry, UIntPtr address)
        {
            entry.offset_0_15 = (ushort) address;
            entry.offset_16_31 = (ushort) (((uint) address) >> 16);
#if ISA_IX64
            entry.offset_32_63 = (uint) (((ulong)address) >> 32);
#endif

            entry.selector = (ushort) Isa.GetCs();
            entry.flags = 0;
            entry.access = (byte) (Idte.PRESENT | Idte.DPL_RING0 | Idte.INT_GATE);
        } 
    }
}
