Multitasking works!
This commit is contained in:
parent
58b706d40f
commit
98d524bc8a
7 changed files with 121 additions and 72 deletions
|
@ -9,14 +9,26 @@ extern void interrupt_enable();
|
|||
|
||||
void utask(){
|
||||
char *msg=(char*)4206592+10;
|
||||
msg[0]='T';
|
||||
msg[1]='a';
|
||||
msg[2]='s';
|
||||
msg[3]='k';
|
||||
msg[4]='1';
|
||||
msg[5]='\0';
|
||||
asm("mov $0x1, %%eax;int $0x30"::"b"(msg));
|
||||
while(1);
|
||||
msg[0]='A';
|
||||
msg[1]='\0';
|
||||
while(1){
|
||||
asm("mov $0x1, %%eax;int $0x30"::"b"(msg));
|
||||
for(int i=0;i<10000;i++){
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void utask2(){
|
||||
char *msg=(char*)4206592+10;
|
||||
msg[0]='B';
|
||||
msg[1]='\0';
|
||||
while(1){
|
||||
asm("mov $0x1, %%eax;int $0x30"::"b"(msg));
|
||||
for(int i=0;i<10000;i++){
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bringelle(){
|
||||
|
@ -34,10 +46,15 @@ void bringelle(){
|
|||
show_tics=1;
|
||||
|
||||
// Utask
|
||||
print("Launch user task \n");
|
||||
int* page_dir=paging_allocate(2);
|
||||
run_task(page_dir, utask,100);
|
||||
print("Launch user tasks \n");
|
||||
|
||||
int* page_dir=paging_allocate(2);
|
||||
task_create(page_dir, utask,100);
|
||||
|
||||
int* page_dir2=paging_allocate(2);
|
||||
task_create(page_dir2, utask2,100);
|
||||
|
||||
scheduler_start();
|
||||
|
||||
while(1);
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ void idt_init(){
|
|||
if(i==33)
|
||||
idt_write_entry((IDT_ENTRY){0x08,(u32)&INT_KEYPRESS,IDT_INT_GATE},i);
|
||||
if(i==48)
|
||||
idt_write_entry((IDT_ENTRY){0x08,(u32)&INT_SYSCALL,IDT_TRAP_GATE},i);
|
||||
idt_write_entry((IDT_ENTRY){0x08,(u32)&INT_SYSCALL,IDT_INT_GATE|0x6000},i);
|
||||
}
|
||||
// Load IDT
|
||||
asm("lidtl (IDTR)");
|
||||
|
|
|
@ -110,7 +110,7 @@ int *paging_allocate(int p){
|
|||
u_page_table[1]=(int)k_page_table|7;
|
||||
u_page_table[2]=(int)u_page_table|7;
|
||||
u_page_table[3]=(int)paging_allocate_next_page()|7;
|
||||
|
||||
|
||||
return page_dir;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,13 @@
|
|||
#else
|
||||
#define PAGING_MAX_DIR_ENTRY PAGING_MAX_PAGES/1024
|
||||
#endif
|
||||
#define PADDR(entry) (((u32)entry)&0xFFFFF000)
|
||||
#define PAGING_PADDR(entry) ((int*)(((u32)entry)&0xFFFFF000))
|
||||
#define PAGING_ENTRY_POINT_VIRT (1024*PAGING_PAGE_SIZE+3*PAGING_PAGE_SIZE)
|
||||
#define PAGING_ENTRY_POINT_PHY(page_dir) ((int*)(((int*)((((int*)page_dir)[1])&0xFFFFF000))[3]&0xFFFFF000))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Configure and enable paging
|
||||
|
|
|
@ -9,16 +9,14 @@ PROC procs[MAX_PROC];
|
|||
u16 current_id;
|
||||
u16 nproc;
|
||||
|
||||
void schedule(){
|
||||
void schedule(u32 *stack){
|
||||
// Note that this function is called by clock
|
||||
// clock is called by INT_CLOCK (core/int.S)
|
||||
// which store all the process information on
|
||||
// the stack. Thus, knowing the C calling conventions
|
||||
// and that schedule() is call by two functions with no parameters,
|
||||
// the first process register can be accessed by ebp+2
|
||||
u32 *stack;
|
||||
asm("mov %%ebp, %0":"=r" (stack));
|
||||
|
||||
|
||||
// No proc to schedule
|
||||
if(nproc<2)
|
||||
return;
|
||||
|
@ -47,7 +45,8 @@ void schedule(){
|
|||
current_id++;
|
||||
if(current_id>=nproc)
|
||||
current_id=0;
|
||||
|
||||
p=&procs[current_id];
|
||||
|
||||
// Have a clean stack on next interrupt
|
||||
TSS.esp0=(u32)stack+19;
|
||||
asm("mov %%ss, %0": "=m" (TSS.ss0));
|
||||
|
@ -58,13 +57,16 @@ void schedule(){
|
|||
|
||||
// Perform task switch
|
||||
asm(
|
||||
"mov %0, %%esi \n\t"
|
||||
"push %0 \n\t"
|
||||
"jmp task_switch \n\t"
|
||||
:: "a" (p)
|
||||
);
|
||||
}
|
||||
|
||||
void clock(){
|
||||
u32* stack;
|
||||
asm("mov %%ebp, %0":"=r" (stack));
|
||||
|
||||
static int tic=0;
|
||||
static int sec=0;
|
||||
tic++;
|
||||
|
@ -75,46 +77,69 @@ void clock(){
|
|||
putchar('.');
|
||||
}
|
||||
if(scheduler_on==1)
|
||||
schedule();
|
||||
schedule(stack);
|
||||
}
|
||||
|
||||
void run_task(int *page_dir, void *task, int task_size){
|
||||
void task_create(int *page_dir, void *task, int task_size){
|
||||
if(nproc<=MAX_PROC){
|
||||
// Compute various addresses
|
||||
int*pt_addr=(int*)PADDR(page_dir[1]);
|
||||
void *entry_point=(void*)(PADDR(pt_addr[3]));
|
||||
void *ustack=(void*)((int)entry_point+0xFF);
|
||||
void *entry_point=PAGING_ENTRY_POINT_VIRT;
|
||||
void *ustack=(void*)(PAGING_ENTRY_POINT_VIRT+0xFF);
|
||||
|
||||
// Load the task into memory
|
||||
memcpy(task,entry_point, task_size);
|
||||
|
||||
// Load page directory
|
||||
asm(
|
||||
"mov %0, %%eax \n\t"
|
||||
"mov %%eax,%%cr3 \n\t"
|
||||
:: "b"(page_dir)
|
||||
);
|
||||
memcpy(task,PAGING_ENTRY_POINT_PHY(page_dir), task_size);
|
||||
|
||||
// Setup users adresses
|
||||
|
||||
// Switch to user task
|
||||
// Setup process registers
|
||||
PROC *p=&procs[nproc];
|
||||
p->regs.cs=0x23; // Task cs which is 0x30 along with prlv which is 0x3
|
||||
p->regs.eip=entry_point;
|
||||
p->regs.ss=0x33; // Task ss which is 0x20 along with prlv which is 0x3
|
||||
p->regs.esp=ustack; // Stack is here for now...
|
||||
p->regs.ds=0x2B; // GDT entry 0x28 along with prlv which is 0x3
|
||||
p->regs.eax=0;
|
||||
p->regs.ebx=0;
|
||||
p->regs.ecx=0;
|
||||
p->regs.edx=0;
|
||||
|
||||
// Manage eflags
|
||||
u32 eflags;
|
||||
asm (
|
||||
"cli \n\t" // Ensure we do not get interrupted
|
||||
"movl %%ss, %%eax \n\t"
|
||||
"movl %%eax, %0 \n\t" // Save kernel ss segment into the TSS
|
||||
"movl %%esp, %1 \n\t" // Save kernel esp into the TSS BEFORE setting up the stack
|
||||
"pushl $0x33 \n\t" // Push task ss which is 0x30 along with prlv which is 0x3
|
||||
"pushl %2 \n\t" // Push task esp
|
||||
"pushfl \n\t" // Retrieve flags
|
||||
"popl %%eax \n\t"
|
||||
"orl $0x200, %%eax \n\t" // Enable interrupt for the user task
|
||||
"and $0xffffbfff, %%eax \n\t" // Clear the NT flags
|
||||
"push %%eax \n\t" // Push task flags
|
||||
"push $0x23 \n\t" // Push task cs which is 0x20 along with prlv which is 0x3
|
||||
"push %3 \n\t" // Push task entry point
|
||||
"mov $0x2B, %%eax \n\t" // GDT entry 0x28 along with prlv which is 0x3
|
||||
"mov %%eax, %%ds \n\t" // Setting up user data segment
|
||||
"iret \n\t" // Launch user task
|
||||
: "=m" (TSS.ss0), "=m" (TSS.esp0)
|
||||
: "b" (ustack), "c" (entry_point)
|
||||
);
|
||||
"mov %%eax, %0 \n\t" // Get flags into eflag
|
||||
: "=m" (eflags)
|
||||
);
|
||||
p->regs.eflags=eflags;
|
||||
|
||||
// Setup other attributes
|
||||
p->id=nproc;
|
||||
p->pid=nproc;
|
||||
p->page_dir=page_dir;
|
||||
nproc++;
|
||||
}
|
||||
}
|
||||
|
||||
void scheduler_start(){
|
||||
if(nproc>0){
|
||||
asm("cli");
|
||||
scheduler_on=1; // Enable scheduling
|
||||
u32 *stack;
|
||||
asm("mov %%ebp, %0":"=r" (stack));
|
||||
TSS.esp0=(u32)stack+1; // Remove ebp (c call convention)
|
||||
asm("mov %%ss, %0": "=m" (TSS.ss0));
|
||||
|
||||
current_id=1;
|
||||
PROC *p=&procs[current_id];
|
||||
|
||||
// Ensure interrupts are activated and NT flag is clear
|
||||
p->regs.eflags|=0x200;
|
||||
p->regs.eflags&=0xffffbfff;
|
||||
asm(
|
||||
"push %0 \n\t"
|
||||
"jmp task_switch"
|
||||
:: "a" (p)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -34,6 +34,6 @@ extern u16 nproc;
|
|||
|
||||
void clock();
|
||||
void schedule();
|
||||
void run_task(int *page_dir, void *task, int task_size);
|
||||
|
||||
void task_create(int *page_dir, void *task, int task_size);
|
||||
void scheduler_start();
|
||||
#endif
|
|
@ -4,24 +4,24 @@
|
|||
// to a PROC structure and jump
|
||||
// to this process
|
||||
task_switch:
|
||||
push 12(%esi) # eax (cf PROC struct)
|
||||
push 16(%esi) # ebx
|
||||
push 20(%esi) # ecx
|
||||
push 24(%esi) # edx
|
||||
push 44(%esi) # ebp
|
||||
push 48(%esi) # esi
|
||||
push 52(%esi) # edi
|
||||
push 56(%esi) # ds
|
||||
push 60(%esi) # es
|
||||
push 64(%esi) # fs
|
||||
push 68(%esi) # gs
|
||||
pop %esi
|
||||
push 8(%esi) # eax (cf PROC struct)
|
||||
push 12(%esi) # ebx
|
||||
push 16(%esi) # ecx
|
||||
push 20(%esi) # edx
|
||||
push 40(%esi) # ebp
|
||||
push 48(%esi) # edi
|
||||
push 52(%esi) # ds
|
||||
push 56(%esi) # es
|
||||
push 60(%esi) # fs
|
||||
push 64(%esi) # gs
|
||||
|
||||
// Don't forget to clear the interrupt
|
||||
movb $0x20, %al
|
||||
outb %al, $0x20
|
||||
|
||||
// Setup process page directory
|
||||
mov 8(%esi), %eax
|
||||
mov 4(%esi), %eax
|
||||
mov %eax, %cr3
|
||||
|
||||
// Setup registers
|
||||
|
@ -30,7 +30,6 @@ task_switch:
|
|||
pop %es
|
||||
pop %ds
|
||||
pop %edi
|
||||
pop %esi
|
||||
pop %ebp
|
||||
pop %edx
|
||||
pop %ecx
|
||||
|
@ -38,9 +37,11 @@ task_switch:
|
|||
pop %eax
|
||||
|
||||
// Perform the task switch
|
||||
push 36(%esi) # ss
|
||||
push 40(%esi) # esp
|
||||
push 72(%esi) # eflags
|
||||
push 28(%esi) # cs
|
||||
push 32(%esi) # eip
|
||||
iret
|
||||
push 32(%esi) # ss
|
||||
push 36(%esi) # esp
|
||||
push 68(%esi) # eflags
|
||||
push 24(%esi) # cs
|
||||
push 28(%esi) # eip
|
||||
mov 52(%esi), %ds # Choose the right data segment
|
||||
mov 44(%esi), %esi # Now restore task esi
|
||||
iret # Launch task
|
||||
|
|
Loading…
Add table
Reference in a new issue