/******************************************************************************

	COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011.

	This file is part of Sortix.

	Sortix is free software: you can redistribute it and/or modify it under the
	terms of the GNU General Public License as published by the Free Software
	Foundation, either version 3 of the License, or (at your option) any later
	version.

	Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
	WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
	FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
	details.

	You should have received a copy of the GNU General Public License along
	with Sortix. If not, see <http://www.gnu.org/licenses/>.

	idt.cpp
	Sets up and handles the Interrupt Descriptor Table.

******************************************************************************/

#include "types.h"
#include "memory.h"
#include "idt.h"
//#include "isr.h"
//#include "irq.h"
#include "panic.h"
#include "kernel.h"

extern "C" void IDT__Flush(void* IDT);
extern "C" void IDT__Uninitialized();
extern "C" void EnableInterrupts();

void IDT::Init()
{
	// Sets the special IDT pointer up.
	Pointer.Limit = (sizeof(Entries)) - 1;
	Pointer.Base = &Entries;

	// Clear out the entire IDT, initializing it to zeros.
	MemorySet(&Entries, 0, sizeof(Entries));
	
	// Remap the IRQ table.
	WriteByteToPort(0x20, 0x11);
	WriteByteToPort(0xA0, 0x11);
	WriteByteToPort(0x21, 0x20);
	WriteByteToPort(0xA1, 0x28);
	WriteByteToPort(0x21, 0x04);
	WriteByteToPort(0xA1, 0x02);
	WriteByteToPort(0x21, 0x01);
	WriteByteToPort(0xA1, 0x01);
	WriteByteToPort(0x21, 0x0);
	WriteByteToPort(0xA1, 0x0);

	// Panic on all unknown exceptions!
	for ( size_t I = 0; I < 255; I++ ) { SetGate(I, (void*) IDT__Uninitialized, 0x08, 0x80 | 0xD | 0x1); }
	
	GISR->Init(); // Initialize the Interrupt Service Routines (ISR).
	GIRQ->Init(); // Initialize the Interrupt Requests (IRQ).

	// Points the processor's internal register to the new IDT.
	IDT__Flush(&Pointer);

	// Alright, everything is set up. Enable interrupts!
	EnableInterrupts();
}

void IDT::SetGate(size_t Num, void* BaseP, uint16_t Sel, uint16_t Flags)
{
	uintptr_t Base = (uintptr_t) BaseP;

	Entries[Num].BaseLow = Base & 0xFFFF;
	Entries[Num].BaseHigh = (Base >> 16) & 0xFFFF;
	Entries[Num].Sel = Sel;
	Entries[Num].Always0 = 0; // Surprise.
	Entries[Num].Flags = Flags;
}

extern "C" void IDT__FaultHandler(ISR__Regs Regs)
{
	Panic("An exception occured that the IDT hadn't mapped", &Regs);
}

