[Prev][Next][Index][Thread]

Re: An example of scheduler...



Hi,
	are you sure that your call-gates is true? i think one of
	your asm() instruction is incorrect, because when i try
	to compile your code i got an error in:
/tmp/cca00673.s: Assembler messages:
/tmp/cca00673.s:553: Error: base/index register must be 32 bit register

	anyway, in addition to this error, I read your code and
	i think your call-gate in incorrect. because you use
	push %ss and pop %ss that it seems incorrect.

	when we have privilege change in call gate, SS, ESP, EFLAG, CS,
	EIP are save automatically in stack and in iret they poped.
	so you should not push then manually in stack.
	attached to this mail two program,

	Guest.c ' it use a scheduler and run your thread in user mode
		  I didn't use TSS here.
		'

	Guest5.c
		'It use a scheduler and run some codes in user mode
		by means of TSS'
	

With Regards, 
--taghi

/*
*	Thread.c , it has a scheduling (an interrupt gate). also
*	^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*	It's thread run in user-mode. (I did not use TSS)	
*	^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*	Written By Mahmoud Taghizadeh.
*	I used ThreadKit source code. I didn't find any copyright 
*	message for it. I apologoize from its authour.
*/

#include <stdio.h>
#include <oskit/machine/base_cpu.h>
#include <oskit/x86/pmode.h>
#include <oskit/x86/base_gdt.h>
#include <oskit/machine/base_vm.h>
#include <oskit/x86/tss.h>
#include <oskit/x86/base_tss.h>
#include <oskit/dev/dev.h>
#include <oskit/x86/proc_reg.h>
#include <oskit/x86/base_idt.h>
#include <oskit/debug.h>
#include <oskit/x86/pio.h>
#include <oskit/x86/pc/pit.h>
#include <oskit/x86/eflags.h>
#include <oskit/x86/pc/base_irq.h>
#include <oskit/x86/base_trap.h>
#include <oskit/x86/trap.h>
#include <oskit/x86/base_paging.h>
#include <oskit/c/malloc.h>
#include <oskit/clientos.h>
#include <oskit/x86/pc/direct_cons.h>
#include "List.h"
#include "Thread.h"

	
CODE32

struct List	*ReadyQueue=0;
struct Thread	*Running=0;
void ThreadLaunch();
int count = 0;
struct Thread *next;

void delay(void) {
	unsigned int i,j, k;
	for (i = 0; i < 30000; ++i)
		for (j = 0; j < 500; ++j)
			k = k +1;
}


void timer(void)
{
	if (++count < 50) {
		asm ("movl %ebp, %esp");
//dont froget pop stack frame.
		asm ("popl %ebp");
		asm ("pusha");
		outb(0x20, 0x20);
		asm ("popa");
		asm ("iret");
	}	
	count = 0;
	asm("pushl %ebp");
	asm("pusha");
	asm("pushl %ds");
	asm("pushl %es");
	asm("pushl %fs");
	asm("pushl %gs");
	asm("movl %%esp, %0" : "=g" (Running->Stack):);
	++count;

//	Its very  important, when you call a function 
//	you have to pop its results mannually.

//	printf("Hello \n");
//	asm("popl %eax");

	next = ThreadYield();
// save current esp0, the next time we have to use it.
	base_tss.esp0 = (unsigned )Running->Stack;
	base_tss_load();
	asm("movl %0, %%esp"::"g"(Running->Stack));

	asm("popl %gs");
	asm("popl %fs");
	asm("popl %es");
	asm("popl %ds");
	asm("popa");
	asm("popl %esp");
	asm("popl %ebp");
	outb(0x20, 0x20);
	asm("iret");
}


void CountOne(void *Data)
{
	printf("One MY DATA IS %d\n",(int)Data);

	while (1) {
		delay();
		printf("One %d: \n",(int)Data);
	}
}

void CountTwo( void *Data )
{
	printf("Two MY DATA IS %d\n",(int)Data);
	while (1) {
		printf("Two %d: \n",(int)Data);
		delay();
	}
}


void main (void) {
	unsigned eflag;
	if (i16_get_msw() & CR0_PE)
		printf("The processor is in protected mode environment.\n");
	
	oskit_clientos_init();
	base_gdt_init();
	base_gdt_load();
	base_tss_init();
	base_tss_load();
	
	base_tss.ss1 = KERNEL_DS;
	base_tss.ss2 = KERNEL_DS;
	fill_descriptor(&base_gdt[USER_CS / 8],
			0x00000000, 0xffffffff,
			ACC_PL_U | ACC_CODE_R, SZ_32);

	fill_descriptor(&base_gdt[USER_DS / 8],
			0x00000000, 0xffffffff,
			ACC_PL_U | ACC_DATA_W, SZ_32);

	fill_gate(&base_idt[32+ 0], (unsigned)timer, KERNEL_CS, 
		ACC_INTR_GATE | ACC_PL_K, 0);

// let user process use IO.(for using printf)
	eflag = get_eflags();
	eflag |= EFL_IOPL_USER;
	set_eflags(eflag);

/*============================= ThreadKit ============= */
	ThreadSystemInit();
	ThreadCreate(CountOne,(void *)5,1);
	ThreadCreate(CountTwo,(void*)10,1);
	
	eflag &= ~EFL_IOPL_USER;
	set_eflags(eflag);

	osenv_intr_disable();
	pit_init(100);
	osenv_irq_enable(0);
	osenv_intr_enable();   
	while (1) {
		delay();	
		printf("Main program %d \n", count);
	}
	return;
}
	
void ThreadSystemInit() {

	ReadyQueue = ListCreate();
	if( ReadyQueue==0 ) 
		return;

	Running = malloc( sizeof(struct Thread) );
	if(Running==0) {
		ListDelete(ReadyQueue);
		return;
	}

	Running->Node.Priority = 1;
	Running->State = THREAD_STATE_READY;
	Running->StackSize = 0;
	Running->StackBase = 0;
	Running->Stack = 0;

}

void ThreadCreate( void (*Code)(), void *Data, int Priority )
{
	struct Thread *S;
	long *Savestack, eax;

	S = malloc(sizeof(struct Thread));
	if( S==0 ) 
		return;
	S->StackBase = malloc(sizeof(native)*THREAD_STACK_SIZE);
	if( S->StackBase==0 ) {
		free(S);
		return;
	}
	S->StackSize = THREAD_STACK_SIZE;
	S->Node.Priority = Priority;

	/* Reset the stack pointer */
	S->Stack = S->StackBase+(S->StackSize-1)/sizeof(native);

	/* Ready to run! */
	S->State = THREAD_STATE_READY;

	S->StartCode = Code;	/* Function to begin at */
	S->StartData = Data;	/* Argument to pass */

//make a stack fram for this thread, we push necessay argument

//SS
//ESP
//EFLAGS
//CS
//EIP
//EBP --------> stack frame.
//ESP --------> I use it for cleaning stack frame changes that
//		gcc generate it.
//pusha !-:)
//push ds, es, fs, gs
//<----------------------- S->Stack point to here.

	asm("pusha");

	asm("movl %%esp, %0" : "=g" (Savestack):);
	asm("movl %0, %%esp"::"g"(S->Stack));
//user stack segment
	asm("pushl $(0x4b)");
	asm("pushl %esp");
	asm("pushfl");
//user code segment. 0x43 is USER_CS
	asm("pushl $(0x43)");
	asm("movl %%eax, %0": "=g" (eax));
	asm("movl %0, %%eax"::"g"(ThreadLaunch));
	asm("pushl %eax");

	asm("pushl %ebp");
	asm("mov %esp, %ebp");
	asm("pushl %ebp");
	asm("pusha");
//0x4b is USER_DS
	asm("pushl $(0x4b)");
	asm("pushl $(0x4b)");
	asm("pushl $(0x4b)");
	asm("pushl $(0x4b)");

	asm("movl %0, %%eax"::"g"(eax));
	asm("movl %%esp, %0" : "=g" (S->Stack):);
	asm("movl %0, %%esp"::"g"(Savestack));

	asm("popa");

	/* Finally, put the Thread on the ready list */
	ListInsert( ReadyQueue, (struct ListNode *)S );
}


struct Thread * ThreadYield()
{
	if( Running!=0 ) {
		if( Running->State==THREAD_STATE_READY ) {
			ListInsert( ReadyQueue, (struct ListNode *) Running);
		}
	}

	Running = (struct Thread *) ListRemove( ReadyQueue );
	return Running;
}
void ThreadLaunch()
{
	Running->StartCode(Running->StartData);
	ThreadExit();
}

void ThreadExit()
{
	Running = 0;
	ThreadYield();
}

struct List *ListCreate()
{
	struct List *L;

	L = malloc(sizeof(struct List));
	if( L==0 ) return 0;

	L->Head=0;

	return L;
}

void ListDelete( struct List *L )
{
	free(L);
}

struct ListNode *ListRemove( struct List *L )
{
	struct ListNode *N;

	N = L->Head;
	if( N==0 ) return 0;

	L->Head = N->Next;

	return N;
}

void ListInsert( struct List *L, struct ListNode *N )
{
	struct ListNode *Test=0,*Prev=0;

	if( L->Head==0 ) {
		L->Head = N;
		N->Next = 0;
	} else {
		for( Test=L->Head; Test!=0; Test=Test->Next ) {
			if( Test->Priority<N->Priority ) break;
			Prev = Test;
		}

		/* Did we fall off the end? */
		if( Test==0 ) {
			Prev->Next = N;
			N->Next = 0;
		
		/* Are we first priority? */
		} else if(Test==L->Head) {
			N->Next = L->Head;
			L->Head = N;

		/* Or did we find a priority spot? */
		} else {
			N->Next = Test->Next;
			Test->Next = N;
		}
	}
}

struct ListNode * ListPeek( struct List *L )
{
	return L->Head;
}





/*
*	User Task & Multi tasking system. also it get GPF traps
*	^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*/

#include <stdio.h>
#include <oskit/machine/base_cpu.h>
#include <oskit/x86/pmode.h>
#include <oskit/x86/base_gdt.h>
#include <oskit/machine/base_vm.h>
#include <oskit/x86/tss.h>
#include <oskit/x86/base_tss.h>
#include <oskit/dev/dev.h>
#include <oskit/x86/proc_reg.h>
#include <oskit/x86/base_idt.h>
#include <oskit/debug.h>
#include <oskit/x86/pio.h>
#include <oskit/x86/pc/pit.h>
#include <oskit/x86/eflags.h>
#include <oskit/x86/pc/base_irq.h>
#include <oskit/x86/base_trap.h>
#include <oskit/x86/trap.h>
#include <oskit/x86/pc/direct_cons.h>

#define SHARIF_TSS_2 0x58
	
	
	
CODE32
extern  oskit_addr_t sharif_pdir_pa;	
struct x86_tss scheduler_tss1;
struct x86_tss my_tss;

long dataseg[100];

long mydataseg[100];

int base_trap_protec_handler(struct trap_state *ts)
{
	if (ts->eflags & EFL_VM) 
		return 0;
	/* 
	 * HACK HACK HACK  :)  Fixing the segment invalid on syscall return
	 * barfage for 2.0 has been put into the too-hard basket but having
	 * a user producing endless GPFs is unacceptable as well. - Paul G.
	 */

	if ((ts->cs & 3) != 3) {
			printf("Ignoring GPF attempt from program \n");
			return 1;
	}

	trap_dump((const struct trap_state *) ts);
	return 0;
}

void delay(void) {
	unsigned int i,j, k;
	for (i = 0; i < 30000; ++i)
		for (j = 0; j < 500; ++j)
			k = k +1;
}

int sv = 0;
unsigned long count = 0;
extern int (*base_trap_handlers[BASE_TRAP_COUNT])(struct trap_state *ts); 

void user_code(void) {
	while (1) {
		delay()	;
		printf("User Code \n");
	}
}

void scheduler(void) 
{
	while (1) {
		if (++count  > 50) {
			count = 0;
			sv++;
			if (sv % 2 ) {
				CurCol = 0x0C;
				base_gdt[SHARIF_TSS / 8].access |= 
					ACC_TSS_BUSY;
				scheduler_tss1.back_link = SHARIF_TSS;
			} else {
				CurCol = 0x0F;
				scheduler_tss1.back_link = BASE_TSS;
				base_gdt[BASE_TSS / 8].access |= 
					ACC_TSS_BUSY;
			}
		}
		outb(0x20, 0x20);
		asm ("iret");
	}
}
	
void main (void) {
	
	if (i16_get_msw() & CR0_PE)
		printf("The processor is in protected mode environment.\n");
	
	base_gdt_init();
	base_gdt_load();
	base_tss_init();
	base_tss_load();
/*TASK descriptor*/	
/*
	We have 3 task.
	main task.
	scheduler
	sharif task.
*/
	base_trap_handlers [T_GENERAL_PROTECTION]= base_trap_protec_handler; 

	fill_descriptor(&base_gdt[SHARIF_TSS_2 / 8], 
		kvtolin(&scheduler_tss1), sizeof(scheduler_tss1) - 1, 
		ACC_PL_U | ACC_TSS | ACC_P, 0);

	fill_descriptor(&base_gdt[SHARIF_TSS / 8], 
		kvtolin(&my_tss), sizeof(my_tss) - 1, 
		ACC_PL_U | ACC_TSS | ACC_P, 0);

/*user-mode descriptor*/
	fill_descriptor(&base_gdt[USER_CS / 8],
			0x00000000, 0xffffffff,
			ACC_PL_U | ACC_CODE_R, SZ_32);
	fill_descriptor(&base_gdt[USER_DS / 8],
			0x00000000, 0xffffffff,
			ACC_PL_U | ACC_DATA_W, SZ_32);

//	set_ss(USER_DS); -------------> generate a GPF
//	set_ss(KERNLE_DS); -------------> no problem



	base_tss.eflags = base_tss.eflags | 0x202 ;
	
	scheduler_tss1.eip = (long)&scheduler;
	scheduler_tss1.cs  = KERNEL_CS;
	scheduler_tss1.es  = KERNEL_DS;
	scheduler_tss1.ds  = KERNEL_DS;
	scheduler_tss1.ss  = KERNEL_DS;
	scheduler_tss1.fs  = KERNEL_DS;
	scheduler_tss1.gs  = KERNEL_DS;
	scheduler_tss1.ss0 = KERNEL_DS;
	scheduler_tss1.ss1 = KERNEL_DS;
	scheduler_tss1.ss2 = KERNEL_DS;
	scheduler_tss1.esp =  sizeof(dataseg) * 100 + (long)dataseg; 
	scheduler_tss1.esp0 = sizeof(dataseg) * 100 + (long)dataseg;
	scheduler_tss1.esp1 = sizeof(dataseg) * 100 + (long)dataseg;
	scheduler_tss1.esp2 = sizeof(dataseg) * 100 + (long)dataseg;
	scheduler_tss1.io_bit_map_offset = sizeof(scheduler_tss1);
	scheduler_tss1.ldt = 0;
	scheduler_tss1.eflags = 0x202;
	base_gdt[SHARIF_TSS_2 / 8].access &= ~ACC_TSS_BUSY;

	my_tss.eip = (long)&user_code;
	my_tss.cs  =  USER_CS;
	my_tss.es  =  USER_DS;
	my_tss.ds  =  USER_DS;
	my_tss.ss  =  USER_DS;
	my_tss.fs  =  USER_DS;
	my_tss.gs  =  USER_DS;
	my_tss.ss0 =  KERNEL_DS;
	my_tss.ss1 =  KERNEL_DS;
	my_tss.ss2 =  KERNEL_DS;
	my_tss.esp =  sizeof(mydataseg) * 100 + (long)mydataseg;   
	my_tss.esp0 = sizeof(mydataseg) * 100 + (long)mydataseg;
	my_tss.esp1 = sizeof(mydataseg) * 100 + (long)mydataseg;      
	my_tss.esp2 = sizeof(mydataseg) * 100 + (long)mydataseg;   
	my_tss.io_bit_map_offset = sizeof(my_tss);
	my_tss.ldt = 0;
/*
	Its for using in/out instruction in user mode program.
*/
	my_tss.eflags = 0x202 | EFL_IOPL_USER; 
	base_gdt[SHARIF_TSS / 8].access &= ~ACC_TSS_BUSY;
/*
	printf("Try to call a user proess \n");
	getchar();
	asm ("ljmp %0, $0"::"g"(SHARIF_TSS));
	printf("ok \n");
*/
	osenv_intr_disable();
//	Its very interesting that this line also work for our purpose.

//	fill_gate(&base_idt[irq_master_base + 0], 0, SHARIF_TSS_2, 
//		ACC_TASK_GATE | ACC_PL_K, 0);

	fill_gate(&base_idt[32+ 0], 0, SHARIF_TSS_2, 
		ACC_TASK_GATE | ACC_PL_K, 0);
	pit_init(100);
	osenv_irq_enable(0);
	osenv_intr_enable();   
	
	while (1) {
		delay();	
		printf("Main program \n");
	}
	
	printf("Just in case...\n");
	
	return;
}