#pragma once
#include "typedefs.h"
#include "naskfunc.h"

#pragma pack(push, 1)
struct SEGMENT_DESCRIPTOR {
	WORD limit_low, base_low;
	BYTE base_mid, access_right;
	BYTE limit_high, base_high;
};
struct GATE_DESCRIPTOR {
	WORD offset_low, selector;
	BYTE dw_count, access_right;
	WORD offset_high;
};

struct TSS32 {
	DWORD backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3;
	DWORD eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi;
	DWORD es, cs, ss, ds, fs, gs;
	DWORD ldtr, iomap;
};
#pragma pack(pop)



class GDT_IDT{
	SEGMENT_DESCRIPTOR *gdt;
	GATE_DESCRIPTOR    *idt;
	DWORD gdtlimit;
	DWORD idtlimit;
	bool ismine;

	DWORD tasktr;
	DWORD systr;
public:
	GDT_IDT(DWORD gdtaddr, DWORD idtaddr, DWORD gdtlimit, DWORD idtlimit);
	GDT_IDT();
	~GDT_IDT();

	void init(DWORD gdtaddr, DWORD idtaddr, DWORD gdtlimit, DWORD idtlimit);

	void set_segmdesc(DWORD i, DWORD limit, DWORD base, DWORD ar);
	void set_gatedesc(DWORD i, DWORD offset, DWORD selector, DWORD ar);
	DWORD getgdtcount();
	DWORD getidtcount();
	void load();

	void init_app_gdtidt(TSS32 *tss, TSS32 *systss);

	void load_systr(){
		load_tr(systr << 3);
	}
	void load_tasktr(){
		load_tr(tasktr << 3);
	}
	void jump_to_task(){
		farjmp(0, tasktr << 3);
	}
};


void init_gdtidt(void);

const DWORD ADR_GDT = 0x00270000;
const DWORD LIMIT_GDT = 0x000007ff;
const DWORD ADR_IDT = 0x00270800;
const DWORD LIMIT_IDT = 0x000007ff;

const DWORD AR_DPL_0 = 0 << 5;
const DWORD AR_DPL_1 = 1 << 5;
const DWORD AR_DPL_2 = 2 << 5;
const DWORD AR_DPL_3 = 3 << 5;

#define AR_DATA32_RW	0x4092
#define AR_CODE32_ER	0x409a
#define AR_LDT			0x0082
#define AR_TSS32		0x0089
#define AR_INTGATE32	0x008e

const DWORD SYSTEM_PAGE_DIRECTORY_PHY = 0x00100000;
const DWORD SYSTEM_PAGE_FOR_DT     = 0xC0000000;
const DWORD NEW_GDT     = SYSTEM_PAGE_FOR_DT + ADR_GDT;
const DWORD NEW_IDT     = SYSTEM_PAGE_FOR_DT + ADR_GDT + 0x800;
