summaryrefslogblamecommitdiff
path: root/Source/Kernel/TaskManager/Task.ns.cpp
blob: aef07f321b641939717f16f44fd7b59a85a8a737 (plain) (tree)
1
2
3
4
5
6
7
8
9
                    


                                     
                                                                                                                  


                             
                                   


                
                                     
                                  
 





                                        
                                                                                           
 












                                         

                                                      

                      
                                                            







                                                                                   
                             

 
                                   
                          


                                                                                                                           
                                                  
                   


                                                                             
                                    
                 
                                                 













                                                                    
                             
                       
         
 

                                                                                                     

                                     

                                         
 


                          

                                                         



                            
                                         









                                                            
                                







                           

                                                                                   




                                                                             

                                                            
                                                     


                                                                                      


         






                                                                                                                     
                            







                                                                                                     





                                                                                          

 

                                       
                                   


                                  
                                                                     
                                         



                                       
                                       


                                    
                                                                 
                                             



 
#include "Task.ns.h"
#include <MemoryManager/PhysMem.ns.h>

#define INVALID_TASK_MAGIC 0xBEEFFEED
#define TEMP_STACK_SIZE 256 //This must be big enough so that we can call all we need to call when a task finishes

//From Task.wtf.asm
extern "C" u32int read_eip();
extern "C" u32int idle_task(void*);

namespace Task {

SimpleList <Process*> *processes = 0;
SimpleList <Thread*> *threads = 0;

SimpleList <Thread*> *currentThread = 0;
Process* currentProcess = 0;
SimpleList<Thread*> *idleThread = 0;

u32int nextpid = 1;

u32int temp_stack[TEMP_STACK_SIZE];	//Temporary stack used for finishing current thread

Thread* currThread() {
	return currentThread->v();
}

Process* currProcess() {
	return currentProcess;
}

Process* getKernelProcess() {
	if (processes == 0) PANIC("kko");
	return processes->last()->v();
}

void initialize(String cmdline, VirtualTerminal *vt) {
	asm volatile ("cli");
	threads = 0;
	processes = 0;
	currentProcess = Process::createKernel(cmdline, vt);
	currentThread = threads;
	Thread* idle = new Thread(idle_task, 0, true);
	for (SimpleList<Thread*> *iter = threads; iter != 0; iter = iter->next()) {
		if (iter->v() == idle) {
			idleThread = iter;
			break;
		}
	}
	asm volatile ("sti");
}

SimpleList<Thread*> *nextThread() {
	//Find next thread
	if ((u32int)currentThread == INVALID_TASK_MAGIC) {
		currentThread = threads;	//This will happen when we come here just after current thread has finished
	}
	SimpleList<Thread*> *iter = currentThread;
	while (1) {
		iter = iter->next();
		if (iter == 0) iter = threads;
		if (iter->v()->runnable() and iter->v() != idleThread->v()) {
			return iter;
		}
		if (iter == currentThread) break;
	}
	return idleThread;
}

void doSwitch() {
	if (currentThread == NULL or currentProcess == NULL) return;

	u32int esp, ebp, eip, cr3;

	asm volatile("mov %%esp, %0" : "=r"(esp));
	asm volatile("mov %%ebp, %0" : "=r"(ebp));

	eip = read_eip();

	if (eip == 0x12345) {
		return;
	}

	//This will happen when we come here just after current thread has finished
	if ((u32int)currentThread != INVALID_TASK_MAGIC) currentThread->v()->setState(esp, ebp, eip);

	currentThread = nextThread();
	Thread* t = currentThread->v();
	currentProcess = t->getProcess();

	esp = t->getEsp();
	ebp = t->getEbp();
	eip = t->getEip();
	cr3 = currentProcess->getPagedir()->physicalAddr;

	asm volatile("cli");

	t->setKernelStack();

	asm volatile("			\
			mov %0, %%ebp;	\
			mov %1, %%esp;	\
			mov %2, %%ecx;	\
			mov %3, %%cr3;	\
			mov $0x12345, %%eax;	\
			jmp *%%ecx;"
		: : "r"(ebp), "r"(esp), "r"(eip), "r"(cr3));
}

void triggerSwitch() {
	asm volatile("int $65");
}

u32int nextPid() {
	return nextpid++;
}

bool IRQwakeup(u8int irq) {
	bool r = false;
	for (SimpleList<Thread*> *iter = threads; iter != 0; iter = iter->next()) {
		r = r or iter->v()->irqHappens(irq);
	}
	return r;
}

void allocKernelPageTable(u32int id, page_table_t *table, u32int tablePhys) {
	kernelPageDirectory->tables[id] = table;
	kernelPageDirectory->tablesPhysical[id] = tablePhys;
	if (id < 768) return;	//this would be a BUG
	for (SimpleList<Process*> *iter = processes; iter != 0; iter = iter->next()) {
		iter->v()->getPagedir()->tables[id] = table;
		iter->v()->getPagedir()->tablesPhysical[id] = tablePhys;
	}
}

void currThreadExitProceed(u32int errcode) {
	currentThread->v()->finish(errcode);
	currentThread = (SimpleList<Thread*>*)INVALID_TASK_MAGIC;
	doSwitch();  //Normally never come back from here
}

void currentThreadExits(u32int errcode) {	//Call currThreadExitProceed with a working stack (we use temp_stack)
	asm volatile("cli");
	u32int* stack = &temp_stack[TEMP_STACK_SIZE];
	stack--;
	*stack = errcode;
	stack--;
	*stack = 0;
	u32int esp = (u32int)(stack), ebp = (u32int)(stack + 1), eip = (u32int)currThreadExitProceed;

	asm volatile("			\
			mov %0, %%ebp;	\
			mov %1, %%esp;	\
			mov %2, %%ecx;	\
			mov %3, %%cr3;	\
			jmp *%%ecx;"
		: : "r"(ebp), "r"(esp), "r"(eip), "r"(kernelPageDirectory->physicalAddr));
}

void registerThread(Thread* t) {
	unregisterThread(t);	//...//
	threads = threads->cons(t);
}

void unregisterThread(Thread* t) {
	if (threads == 0) return;	//Tasking not yet initialized
	threads = threads->removeOnce(t);
}

void registerProcess(Process* p) {
	unregisterProcess(p);	//...//
	processes = processes->cons(p);
}

void unregisterProcess(Process* p) {
	if (processes == 0) return; //Tasking not yet initialized
	processes = processes->removeOnce(p);
}

}