#include "ThreadMan.h"
#include "debug.h"
#include "typedefs.h"
#include "ProcessMan.h"
#include "naskfunc.h"
#include <stdlib.h>
#include <string.h>

BYTE ThreadMan::buf[sizeof(ThreadMan)];


Thread::Thread(Process *p, DWORD tid, DWORD eip)
:p(p),tid(tid)
{
	DWORD gdtsize = 0x400, idtsize = 0x800;
	dtbuf.reset((BYTE *)MemMan::Inst().malloc(true, false, p->getpid()));

	DWORD dtva = p->VirtualAlloc(0xc0000000, true, (DWORD)dtbuf.get());

	dt.init((DWORD)dtbuf.get(), ((DWORD)dtbuf.get()) + gdtsize
		, gdtsize - 1, idtsize - 1);

	TSS32 *tsslist = (TSS32 *)(((DWORD)dtbuf.get()) + gdtsize + idtsize);
	tss.reset(&tsslist[0], placementdeleter());
	systss.reset(&tsslist[1], placementdeleter());
	memset(tss.get(), 0, sizeof(TSS32));
	memset(systss.get(), 0, sizeof(TSS32));

	debugprint("systss:%p\n", systss.get());

	dt.init_app_gdtidt(tss.get(), systss.get());


	//スタック領域として1MBリザーブ
	DWORD esp = p->VirtualAlloc(0xf00000, false, 0, false, 0x100);
	p->VirtualAlloc(esp, false, 0, false, 2, false, true);
	
	tss->ldtr = 0;
	tss->iomap = 0x40000000;
	tss->fs = tss->ds = tss->es = tss->gs = tss->ss = 1 << 3;
	tss->cs = 2 << 3;
	tss->esp = esp;
	//tss->cr3 = p->getcr3();
	tss->cr3 = SYSTEM_PAGE_DIRECTORY_PHY;
	tss->eflags = 0x00000202;
	tss->eax = tss->ecx = tss->edx = tss->edi = tss->esi = tss->ebp = tss->ebx = 0;
	tss->eip = eip;
	tss->eax = dtva;
	tss->ecx = p->getcr3();

	systss->ldtr = 0;
	systss->iomap = 0x40000000;
	systss->cr3 = SYSTEM_PAGE_DIRECTORY_PHY;
}

Thread::~Thread(){
}


void Thread::seteip(DWORD eip){
	tss->eip = eip;
}

void Thread::SwitchThread(){
	store_cr3(p->getcr3());
	dt.load();
	dt.load_systr();
	dt.jump_to_task();
}

void ThreadMan::Init(void)
{
	new ((void *)buf) ThreadMan();
}

ThreadMan::ThreadMan(void)
:thlist(0)
{
	curtid = 1;
	curthread = 0;
}


ThreadMan::~ThreadMan(void)
{
}

Thread *ThreadMan::CreateThread(Process *p, DWORD eip){
	Thread t(p, curtid++, eip);
	thlist.Add(t);
	return thlist[thlist.GetCount() - 1];
}

void ThreadMan::SwitchThread(){
	if(curthread == 0){
		if(thlist.GetCount() < 1){
			return;
		}
		Thread *t = thlist[0];
		t->SwitchThread();
	}

}
