#include "../bootpack.h"

namespace system {
	//const dword ADR_IDT			= 0x0026f800;
	const dword ADR_IDT			= 0x00000000;
	//const dword LIMIT_IDT		= 0x000007ff;
	const dword LIMIT_IDT		= 0x000003ff;
	const dword ADR_GDT			= 0x00270000;
	const dword LIMIT_GDT		= 0x0000ffff;
	const dword ADR_BOTPAK		= 0x00280000;
	const dword LIMIT_BOTPAK	= 0x0007ffff;
	const dword AR_DATA32_RW	= 0x4092;
	const dword AR_CODE32_ER	= 0x409a;
	const dword AR_TSS32		= 0x0089;
	const dword AR_INTGATE32	= 0x008e;
}


void GDT::SetSegmDesc(SegmentDescriptor *sd, unsigned int limit, unsigned int base, unsigned int ar)
{
	if (limit > 0xfffff) {
		ar |= 0x8000; // G_bit = 1
		limit /= 0x1000; // G_bitを1にすると、リミットが4096倍される。
	}
	sd->limitLow    = limit & 0xffff;
	sd->baseLow     = base & 0xffff;
	sd->baseMid     = (base >> 16) & 0xff;
	sd->accessRight = ar & 0xff;
	sd->limitHigh   = ((limit >> 16) & 0x0f) | ((ar >> 8) & 0xf0);
	sd->baseHigh    = (base >> 24) & 0xff;
}

SegmentDescriptor *GDT::gdt = (SegmentDescriptor *)ADR_GDT;
void GDT::init()
{
	int i;
	for (i = 0; i < 8192; i++) {
		GDT::SetSegmDesc(gdt + i, 0, 0, 0);
	}
	GDT::SetSegmDesc(gdt + 1, 0xffffffff, 0x00000000, AR_DATA32_RW);
	GDT::SetSegmDesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER);
	//load_gdtr(LIMIT_GDT, ADR_GDT);
	gdtr.load(LIMIT_GDT, ADR_GDT);
}

void IDT::SetGateDesc(GateDescriptor *gd, unsigned int offset, unsigned int selector, unsigned int ar)
{
	gd->offsetLow = offset & 0xffff;
	gd->selector = selector;
	gd->dwCount = (ar >> 8) & 0xff;
	gd->accessRight = ar & 0xff;
	gd->offsetHigh = (offset >> 16) & 0xffff;
}

GateDescriptor *IDT::idt = (GateDescriptor *)ADR_IDT;
void IDT::init()
{
	int i;
	//for (i = 0; i < 256; i++) {
	for (i = 0; i < 128; i++) {
		IDT::SetGateDesc(idt + i, 0, 0, 0);
	}
	//load_idtr(LIMIT_IDT, ADR_IDT);
	idtr.load(LIMIT_IDT, ADR_IDT);
//	IDT::SetGateDesc(idt + 0x0c, (int) asm_inthandler0c, 2 * 8, AR_INTGATE32);
//	IDT::SetGateDesc(idt + 0x0d, (int) asm_inthandler0d, 2 * 8, AR_INTGATE32);
	IDT::SetGateDesc(idt + 0x20, (int) asm_inthandler20, 2 * 8, AR_INTGATE32);
	IDT::SetGateDesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32);
	IDT::SetGateDesc(idt + 0x27, (int) asm_inthandler27, 2 * 8, AR_INTGATE32);
	IDT::SetGateDesc(idt + 0x2c, (int) asm_inthandler2c, 2 * 8, AR_INTGATE32);
//	IDT::SetGateDesc(idt + 0x40, (int) asm_nos_api     , 2 * 8, AR_INTGATE32 + 0x60);
}

