Main Page   Modules   Alphabetical List   Data Structures   File List   Data Fields   Globals   Related Pages  

Generic Routines
[Multitasking]


Functions

task_tcreate_kthread (void *address, char *pname)
 Create a new kernel thread.
Parameters:
address  The address of the starting point for the thread.
pname  The name of the new thread.
Returns:
A pointer to the new-created task structure.
Exceptions:
NULL  If an error occurs (in particular out-of-memory).


task_tcreate_process (void *address, void *buffer, size_t size, char *pname, int privilege)
 Create a new process.
Parameters:
address  The address of the starting point for the thread.
buffer  An address to a buffer where is placed the executable code.
size  The size of the executable code buffer.
pname  The name of the new task.
privilege  The privilege level of the new task:
Returns:
A pointer to the new-created task structure.
Exceptions:
NULL  If an error occurs (in particular out-of-memory).


size_t new_vspace ()
 Create a new virtual space.
Returns:
The physical address of the page directory for the new virtual space.
Exceptions:
NULL  If an error occurs (in particular out-of-memory).


uint32_ttask_setup_stack (int argc, char **argv, addr_t stack_start, size_t stack_size, int privilege)
 Initialize the stack for a new process.
Parameters:
argc  The number of arguments passed to the new process.
argv  A pointer to the argument strings. NOTE: The content of argv may be changed!!!
stack_start  Where the stack is placed in memory.
stack_size  The size of the stack in bytes.
privilege  The privilege of the task.
Returns:
The starting stack pointer after initialization.


task_tnew_task (char *filename, int argc, char **argv, int privilege)
 Execute a file creating a new task.
Parameters:
filename  The name of the file to execute.
argc  The number of arguments passed to the new process.
argv  The arguments passed to the new process.
argv  A pointer to the argument strings.
privilege  The privilege level of the new task:
Returns:
A pointer to the new-created task structure.
Exceptions:
NULL  If an error occurs (in particular out-of-memory).


bool kill (pid_t pid)
 Kill a task by the pid.
Parameters:
pid  The process id.
Returns:
  • TRUE if the task has been successfully killed
  • FALSE if the task cannot be killed.


void auto_kill (int n)
 Kill the current running task.
Parameters:
n  The return code.


pid_t waitpid (pid_t pid, int *status, int options)
 Wait for the exit of a child.
Parameters:
pid 
  • The child process id
  • -1 to wait for the exit of a generic child.
status  Reports the status of the child.
options  Options flags.
Returns:
The pid of the child or -1 if the process has not been found.


void sleep_task (task_t *p)
 Sleep a process if it is awake.
Parameters:
p  The structure of the task to sleep.


void wakeup_task (task_t *p)
 Wakeup a process if it is sleeping.
Parameters:
p  The structure of the task to wakeup.



Detailed Description

The generic routines for task management.

Function Documentation

void auto_kill int    n
 

Kill the current running task.

Parameters:
n  The return code.

This routine move the current task from the ready queue to the zombie queue. Then the kpager() daemon should provide to free the memory and resources owned by this task.

Definition at line 949 of file task.c.

00950 {
00951         kill( curr_task->pid );
00952 }

task_t* create_kthread void *    address,
char *    pname
 

Create a new kernel thread.

Parameters:
address  The address of the starting point for the thread.
pname  The name of the new thread.
Returns:
A pointer to the new-created task structure.
Exceptions:
NULL  If an error occurs (in particular out-of-memory).

This routine initialize a new kernel thread structure and add this thread to the ready queue.

Definition at line 234 of file task.c.

00235 {
00236         task_t *new_task;
00237         byte *pl0_stack;
00238 
00239         sched_enter_critical_region();
00240 
00241         // --- Create the task structure -------------------------------//
00242         //!
00243         //! IA-32 Intel(R) Architecture Software Developer's Manual
00244         //! Volume 3: System Programming Guide - Chapter 6 - reports:
00245         //!
00246         //! "If paging is used, care should be taken to avoid placing a
00247         //! page boundary within the part of the TSS that the processor
00248         //! reads during a task switch (the first 104 bytes). If a page
00249         //! boundary is placed within this part of the TSS, the pages on
00250         //! either side of the boundary must be present at the same time
00251         //! and contiguous in physical memory.
00252         //!
00253         //! The reason for this restriction is that when accessing a TSS
00254         //! during a task switch, the processor reads and writes into
00255         //! the first 104 bytes of each TSS from contiguous physical
00256         //! addresses beginning with the physical address of the first
00257         //! byte of the TSS. It may not perform address translation at a
00258         //! page boundary if one occurs within this area. So, after the
00259         //! TSS access begins, if a part of the 104 bytes is not both
00260         //! present and physically contiguous, the processor will access
00261         //! incorrect TSS information, without generating a page-fault
00262         //! exception. The reading of this incorrect information will
00263         //! generally lead to an unrecoverable exception later in the
00264         //! task switch process..."
00265         new_task = kmemalign(PAGE_SIZE, sizeof(task_t));
00266         if (new_task == NULL)
00267         {
00268                 // Out of virtual memory!!! //
00269                 set_color(LIGHT_RED);
00270                 kprintf("\n\rOut of virtual memory!!! Cannot create task [%s]\n\r", pname);
00271                 set_color(DEFAULT_COLOR);
00272 
00273                 sched_leave_critical_region();
00274                 return(NULL);
00275         }
00276         memset(new_task, 0, sizeof(task_t));
00277 
00278         // --- Create the pl0-stack --- //
00279         pl0_stack = kmalloc(STACK_SIZE);
00280         if (pl0_stack == NULL)
00281         {
00282                 // Out of virtual memory!!! //
00283                 set_color(LIGHT_RED);
00284                 kprintf("\n\rOut of virtual memory!!! Cannot create task [%s]\n\r", pname);
00285                 set_color(DEFAULT_COLOR);
00286                 // Free the previous allocated space //
00287                 kfree((void *)new_task);
00288 
00289                 sched_leave_critical_region();
00290                 return(NULL);
00291         }
00292         // Null the stack to enforce the page mapping //
00293         memset(pl0_stack, 0, STACK_SIZE);
00294         // Setup the pl0-stack //
00295         new_task->tss.ss0 = new_task->tss.ss = KERNEL_STACK;
00296         new_task->tss.esp0 = new_task->tss.esp = new_task->pl0_stack = (dword)(pl0_stack+STACK_SIZE-sizeof(uint32_t));
00297 
00298         // --- Setup the TSS --- //
00299         new_task->tss_sel = setup_GDT_entry(sizeof(tss_IO_t), (dword)&(new_task->tss), TSS_SEG, 0);
00300 
00301         // Setup the task PDBR => get the kernel PDBR //
00302         new_task->tss.cr3 = GET_PDBR();
00303 
00304         // Setup the IO port mapping //
00305         new_task->tss.io_map_addr = sizeof(tss_t);
00306 
00307         // Setup general registers //
00308         new_task->tss.ds = new_task->tss.es = KERNEL_DATA;
00309         new_task->tss.fs = new_task->tss.gs = KERNEL_DATA;
00310         new_task->tss.eflags = EFLAGS_IF | 0x02;
00311 
00312         // Initialize general purpose registers //
00313         new_task->tss.eax = new_task->tss.ebx =
00314         new_task->tss.ecx = new_task->tss.edx =
00315         new_task->tss.esi = new_task->tss.edi = 0;
00316 
00317         // Initialize LDTR (Local Descriptor Table Register) //
00318         // No LDTs for now...
00319         new_task->tss.ldtr = 0;
00320 
00321         // Initialize debug trap //
00322         // If set to 1 the processor generate a debug exception when a task switch to this task occurs...
00323         new_task->tss.trace = 0;
00324 
00325         // Setup starting address //
00326         new_task->tss.cs = KERNEL_CODE;
00327         new_task->tss.eip = (dword)address;
00328 
00329         // --- Get a pid --- //
00330         new_task->pid = new_pid();
00331 
00332         // --- Store the name --- //
00333         // The last character must be ever '\0' (end of string) //
00334         strncpy(new_task->name, pname, sizeof(new_task->name)-2);
00335 
00336         // --- Set the type --- //
00337         new_task->type = KTHREAD_T;
00338 
00339         // --- Set the parent process --- //
00340         new_task->father = curr_task;
00341 
00342         // --- Set the console --- //
00343         new_task->console = curr_task->console;
00344 
00345         // --- Insert the task into the ready queue --- //
00346         new_task->state = READY;
00347         add_queue(&ready_queue, new_task);
00348 
00349         sched_leave_critical_region();
00350 
00351         return (new_task);
00352 }

task_t* create_process void *    address,
void *    buffer,
size_t    size,
char *    pname,
int    privilege
 

Create a new process.

Parameters:
address  The address of the starting point for the thread.
buffer  An address to a buffer where is placed the executable code.
size  The size of the executable code buffer.
pname  The name of the new task.
privilege  The privilege level of the new task:
Returns:
A pointer to the new-created task structure.
Exceptions:
NULL  If an error occurs (in particular out-of-memory).

This routine initializes the new task structure, copies the content of the buffer to the entry point address and then add the new task to the ready queue.

Definition at line 374 of file task.c.

00375 {
00376         task_t *new_task;
00377         byte *pl0_stack;
00378         dword *PDBR;
00379         dword PDBR_frame, i;
00380         register dword cr3;
00381 
00382         sched_enter_critical_region();
00383 
00384         // --- Create the task structure -------------------------------//
00385         //!
00386         //! IA-32 Intel(R) Architecture Software Developer's Manual
00387         //! Volume 3: System Programming Guide - Chapter 6 - reports:
00388         //!
00389         //! "If paging is used, care should be taken to avoid placing a
00390         //! page boundary within the part of the TSS that the processor
00391         //! reads during a task switch (the first 104 bytes). If a page
00392         //! boundary is placed within this part of the TSS, the pages on
00393         //! either side of the boundary must be present at the same time
00394         //! and contiguous in physical memory.
00395         //!
00396         //! The reason for this restriction is that when accessing a TSS
00397         //! during a task switch, the processor reads and writes into
00398         //! the first 104 bytes of each TSS from contiguous physical
00399         //! addresses beginning with the physical address of the first
00400         //! byte of the TSS. It may not perform address translation at a
00401         //! page boundary if one occurs within this area. So, after the
00402         //! TSS access begins, if a part of the 104 bytes is not both
00403         //! present and physically contiguous, the processor will access
00404         //! incorrect TSS information, without generating a page-fault
00405         //! exception. The reading of this incorrect information will
00406         //! generally lead to an unrecoverable exception later in the
00407         //! task switch process..."
00408         new_task = kmemalign(PAGE_SIZE, sizeof(task_t));
00409         if (new_task == NULL)
00410         {
00411                 // Out of virtual memory!!! //
00412                 set_color(LIGHT_RED);
00413                 kprintf("\n\rOut of virtual memory!!! Cannot create task [%s]\n\r", pname);
00414                 set_color(DEFAULT_COLOR);
00415 
00416                 sched_leave_critical_region();
00417                 return(NULL);
00418         }
00419         memset(new_task, 0, sizeof(task_t));
00420 
00421         // --- Create the pl0-stack --- //
00422         pl0_stack = kmalloc(STACK_SIZE);
00423         if (pl0_stack == NULL)
00424         {
00425                 // Out of virtual memory!!! //
00426                 set_color(LIGHT_RED);
00427                 kprintf("\n\rOut of virtual memory!!! Cannot create task [%s]\n\r", pname);
00428                 set_color(DEFAULT_COLOR);
00429                 // Free the previous allocated space //
00430                 kfree((void *)new_task);
00431 
00432                 sched_leave_critical_region();
00433                 return(NULL);
00434         }
00435         // Null the stack to enforce the page mapping //
00436         memset(pl0_stack, 0, STACK_SIZE);
00437         // Setup the pl0-stack //
00438         new_task->tss.ss0 = KERNEL_STACK;
00439         new_task->tss.esp0 = new_task->pl0_stack = (dword)(pl0_stack+STACK_SIZE-sizeof(uint32_t));
00440 
00441         // --- Setup the TSS --- //
00442         new_task->tss_sel = setup_GDT_entry(sizeof(tss_IO_t), (dword)&(new_task->tss), TSS_SEG, 0);
00443 
00444         // --- Create the virtual space of the task ------------------- //
00445         PDBR = (dword *)get_temp_page();
00446         if ( PDBR == NULL )
00447         {
00448                 // Out of memory!!! Free the previous allocated memory. //
00449                 set_color(LIGHT_RED);
00450                 kprintf("\n\rOut memory!!! Cannot create task [%s]\n\r", pname);
00451                 set_color(DEFAULT_COLOR);
00452                 // Free the previous allocated space //
00453                 kfree((void *)(pl0_stack));
00454                 kfree((void *)new_task);
00455                 // Destroy the TSS //
00456                 remove_GDT_entry(new_task->tss_sel);
00457                 // Free the
00458 
00459                 sched_leave_critical_region();
00460                 return(NULL);
00461         }
00462         PDBR_frame = vir_to_phys( (dword)PDBR );
00463 
00464         // Initialize PDBR //
00465         memset(PDBR, 0, PAGE_SIZE);
00466         for (i=K_VIR_START/(PAGE_SIZE*1024); i<1024; i++)
00467                 PDBR[i] = K_PDBR[i];
00468 
00469         // Map page directory into itself //
00470         PDBR[1023] = PDBR_frame | P_PRESENT | P_WRITE;
00471 
00472         // Unmap the temporary page, without free the physical frame    //
00473         free_temp_page(PDBR, FALSE);
00474 
00475         // Temporary switch to the new address space                    //
00476         //                                                              //
00477         // QUESTION: cr3 is in the stack... if I switch into the new    //
00478         // address space can I ever see the old cr3 value???            //
00479         //                                                              //
00480         // RE: Yes, but only if cr3 is stored into a register...        //
00481         // And if the value should be stored into the stack, here we    //
00482         // are at CPL0, so we're using the 0-privileged stack, so,      //
00483         // since the 0-privileged stack space is shared between every   //
00484         // task and also the kernel, we're ever able to see the stored  //
00485         // cr3 value...                                                 //
00486         __asm__ __volatile__ ("movl %%cr3, %0" : "=r"(cr3) : );
00487         __asm__ __volatile__ ("movl %0, %%cr3" : : "r"(PDBR_frame));
00488 
00489         // --- Create the user space --- //
00490 
00491         // Create the task stack //
00492         new_task->tss.ss = (privilege == KERNEL_PRIVILEGE) ? KERNEL_STACK : USER_STACK | 3;
00493         if ( privilege == KERNEL_PRIVILEGE )
00494                 new_task->tss.esp = new_task->pl0_stack;
00495         else
00496                 new_task->tss.esp = (dword)(TASK_STACK_START-sizeof(size_t));
00497 
00498         // Map the user code and data space.                            //
00499         // ("address" is the virtual task space, "buffer" is the        //
00500         // kernel space where the task-code is located).                //
00501         if (address != buffer)
00502         {
00503                 memcpy(address, buffer, size);
00504         }
00505 
00506         // Restore the old address space //
00507         __asm__ __volatile__ ("movl %0, %%cr3" : : "r"(cr3));
00508 
00509         // Setup the task PDBR //
00510         new_task->tss.cr3 = PDBR_frame;
00511 
00512         // Setup the IO port mapping //
00513         new_task->tss.io_map_addr = sizeof(tss_t);
00514 
00515         // Setup general registers //
00516         if ( privilege == KERNEL_PRIVILEGE )
00517                 new_task->tss.ds = new_task->tss.es =
00518                 new_task->tss.fs = new_task->tss.gs = KERNEL_DATA;
00519         else
00520                 new_task->tss.ds = new_task->tss.es =
00521                 new_task->tss.fs = new_task->tss.gs = USER_DATA | 3;
00522 
00523         new_task->tss.eflags = EFLAGS_IF | 0x02;
00524         if ( privilege == USER_PRIVILEGE )
00525                 // User tasks must have the I/O privilege level         //
00526                 // at the lower level                                   //
00527                 new_task->tss.eflags |= EFLAGS_IOPL3;
00528 
00529         // Initialize general purpose registers //
00530         new_task->tss.eax = new_task->tss.ebx =
00531         new_task->tss.ecx = new_task->tss.edx =
00532         new_task->tss.esi = new_task->tss.edi = 0;
00533 
00534         // Initialize LDTR (Local Descriptor Table Register) //
00535         // No LDTs for now...
00536         new_task->tss.ldtr = 0;
00537 
00538         // Initialize debug trap //
00539         // If set to 1 the processor generates a debug exception when a //
00540         // task switch to this task occurs...                           //
00541         new_task->tss.trace = 0;
00542 
00543         // Setup starting address //
00544         new_task->tss.cs = (privilege == KERNEL_PRIVILEGE) ? KERNEL_CODE : USER_CODE | 3;
00545         new_task->tss.eip = (dword)address;
00546 
00547         // --- Get a pid --- //
00548         new_task->pid = new_pid();
00549 
00550         // --- Store the name --- //
00551         // The last character must be ever '\0' (end of string) //
00552         strncpy(new_task->name, pname, sizeof(new_task->name)-2);
00553 
00554         // --- Set the type --- //
00555         new_task->type = PROCESS_T;
00556 
00557         // --- Set the parent process --- //
00558         new_task->father = curr_task;
00559 
00560         // --- Set the console --- //
00561         if( curr_task )
00562                 new_task->console = curr_task->console;
00563 
00564         // --- Insert the task into the ready queue --- //
00565         new_task->state = READY;
00566         add_queue(&ready_queue, new_task);
00567 
00568         sched_leave_critical_region();
00569         return (new_task);
00570 }

bool kill pid_t    pid
 

Kill a task by the pid.

Parameters:
pid  The process id.
Returns:
  • TRUE if the task has been successfully killed
  • FALSE if the task cannot be killed.

This routine move the task having the pid from the ready queue to the zombie queue. Then the kpager() daemon should provide to free the memory and resources owned by this task.

Definition at line 881 of file task.c.

00882 {
00883         // Queues where to search the processes                         //
00884         static queue_t **q[] = { &ready_queue, &wait_queue };
00885         task_t *p = curr_task;
00886         bool retval = FALSE;
00887         register int i, j, n;
00888 
00889         // No running processes(???) => quit!                           //
00890         if ( p==NULL )
00891                 return(FALSE);
00892 
00893         sched_enter_critical_region();
00894 
00895         // Explore every task queue                                     //
00896         for ( i=0; i<_countof(q); i++)
00897                 for ( j=0, n=count_queue(q[i]); j<n; j++ )
00898                 {
00899                         // Get the next task in the queue               //
00900                         p = pick_queue( q[i] );
00901 
00902                         if ( p->pid == pid )
00903                         {
00904                                 // Move the task from the queue to the  //
00905                                 // zombie queue                         //
00906                                 if ( rem_queue(q[i], p) )
00907                                 {
00908                                         add_queue(&zombie_queue, p);
00909                                         p->state = ZOMBIE;
00910                                         // Wake-up the kpager daemon    //
00911                                         wakeup_task( kpagd );
00912                                         // Wake-up the father           //
00913                                         if ( p->father != NULL )
00914                                                 wakeup_task( p->father );
00915                                         // Task killed!                 //
00916                                         retval = TRUE;
00917                                 }
00918                         }
00919                         else
00920                         {
00921                                 // If the process p is a child of the   //
00922                                 // process to kill we have to set its   //
00923                                 // father to NULL                       //
00924                                 if ( p->father != NULL )
00925                                         if ( (p->father)->pid == pid )
00926                                                 p->father = NULL;
00927                         }
00928                 }
00929 
00930         // Check if the task has killed itself                          //
00931         if (curr_task->pid == pid)
00932         {
00933                 sched_leave_critical_region();
00934                 // Wait for the dispatcher                              //
00935                 do_idle();
00936         }
00937 
00938         sched_leave_critical_region();
00939         return( retval );
00940 }

task_t* new_task char *    filename,
int    argc,
char **    argv,
int    privilege
 

Execute a file creating a new task.

Parameters:
filename  The name of the file to execute.
argc  The number of arguments passed to the new process.
argv  The arguments passed to the new process.
argv  A pointer to the argument strings.
privilege  The privilege level of the new task:
Returns:
A pointer to the new-created task structure.
Exceptions:
NULL  If an error occurs (in particular out-of-memory).

This routine can execute only ELF32 files. The file is loaded in a temporary buffer, then the sections are copied into memory and the task structure is initialized. At the end of this the new task is putted into the ready queue.

Definition at line 697 of file task.c.

00698 {
00699         uint32_t temp_PDBR;
00700         task_t  *task;
00701         byte    *pl0_stack;
00702         size_t  PDBR, entry;
00703         void    *filebuffer;
00704         int     filesize = get_file_size(filename);
00705 
00706         if ( filesize < 0 )
00707                 return(NULL);
00708 
00709         // Load the ELF32 file into the buffer //
00710         filebuffer = kmalloc(filesize);
00711         if ( elf32_load_file(filename, filebuffer)<0 )
00712         {
00713                 kfree(filebuffer);
00714                 return(NULL);
00715         }
00716 
00717         sched_enter_critical_region();
00718 
00719         // Create the task structure //
00720         task = kmemalign(PAGE_SIZE, sizeof(task_t));
00721         if ( task == NULL )
00722         {
00723                 sched_leave_critical_region();
00724                 kfree(filebuffer);
00725                 return(NULL);
00726         }
00727         memset(task, 0, sizeof(task_t));
00728 
00729         // Create the PL0-stack //
00730         pl0_stack = kmalloc(STACK_SIZE);
00731         if (pl0_stack == NULL)
00732         {
00733                 // Out of virtual memory!!! //
00734                 // Free the previous allocated space //
00735                 kfree((void *)task);
00736                 kfree(filebuffer);
00737 
00738                 sched_leave_critical_region();
00739                 return(NULL);
00740         }
00741         // Null the stack to enforce the page mapping //
00742         memset(pl0_stack, 0, STACK_SIZE);
00743 
00744         // Setup the PL0-stack //
00745         task->tss.ss0 = KERNEL_STACK;
00746         task->tss.esp0 = task->pl0_stack = (dword)(pl0_stack+STACK_SIZE-sizeof(uint32_t));
00747 
00748         // Setup the TSS //
00749         task->tss_sel = setup_GDT_entry(sizeof(tss_IO_t), (dword)&(task->tss), TSS_SEG, 0);
00750 
00751         // Create the new virtual space //
00752         PDBR = new_vspace();
00753         if ( PDBR == NULL )
00754         {
00755                 // Out of memory !!! //
00756 
00757                 // Destroy the TSS //
00758                 remove_GDT_entry(task->tss_sel);
00759                 // Free the previous allocated space //
00760                 kfree((void *)(pl0_stack));
00761                 kfree((void *)task);
00762                 kfree(filebuffer);
00763 
00764                 sched_leave_critical_region();
00765                 return(NULL);
00766         }
00767 
00768         // Temporary switch to the new address space //
00769         __asm__ __volatile__ ("movl %%cr3, %0" : "=r"(temp_PDBR) : );
00770         __asm__ __volatile__ ("movl %0, %%cr3" : : "r"(PDBR));
00771 
00772         // Copy the file sections into memory //
00773         entry = elf32_copy_sections(filebuffer);
00774         if ( entry == NULL )
00775         {
00776                 // Restore the old address space //
00777                 __asm__ __volatile__ ("movl %0, %%cr3" : : "r"(temp_PDBR));
00778 
00779                 // Free the PDBR frame //
00780                 push_frame(PDBR/PAGE_SIZE);
00781                 // Destroy the TSS //
00782                 remove_GDT_entry(task->tss_sel);
00783                 // Free the previous allocated space //
00784                 kfree((void *)(pl0_stack));
00785                 kfree((void *)task);
00786                 kfree(filebuffer);
00787 
00788                 sched_leave_critical_region();
00789                 return(NULL);
00790         }
00791 
00792         // Create the task stack.
00793         task->tss.ss = (privilege == KERNEL_PRIVILEGE) ? KERNEL_STACK : USER_STACK | 3;
00794         if ( privilege == KERNEL_PRIVILEGE )
00795                 task->tss.esp = (uint32_t)task_setup_stack(argc, argv, task->pl0_stack, STACK_SIZE, privilege);
00796         else
00797                 task->tss.esp = (uint32_t)task_setup_stack(argc, argv, TASK_STACK_START, STACK_SIZE, privilege);
00798 
00799         // Initialize the user heap.
00800         umalloc_init( TASK_HEAP_START, TASK_HEAP_DEFAULT_SIZE );
00801 
00802         // Restore the old address space //
00803         __asm__ __volatile__ ("movl %0, %%cr3" : : "r"(temp_PDBR));
00804 
00805         // Setup the task PDBR //
00806         task->tss.cr3 = PDBR;
00807 
00808         // Setup the IO port mapping //
00809         task->tss.io_map_addr = sizeof(tss_t);
00810 
00811         // Setup general registers //
00812         if ( privilege == KERNEL_PRIVILEGE )
00813                 task->tss.ds = task->tss.es =
00814                 task->tss.fs = task->tss.gs = KERNEL_DATA;
00815         else
00816                 task->tss.ds = task->tss.es =
00817                 task->tss.fs = task->tss.gs = USER_DATA | 3;
00818 
00819         task->tss.eflags = EFLAGS_IF | 0x02;
00820         if ( privilege == USER_PRIVILEGE )
00821                 // User privilege must be the I/O privilege set to the  //
00822                 // lower level                                          //
00823                 task->tss.eflags |= EFLAGS_IOPL3;
00824 
00825         // Initialize general purpose registers //
00826         task->tss.eax = task->tss.ebx =
00827         task->tss.ecx = task->tss.edx =
00828         task->tss.esi = task->tss.edi = 0;
00829 
00830         // Initialize LDTR (Local Descriptor Table Register) //
00831         // No LDTs for now...
00832         task->tss.ldtr = 0;
00833 
00834         // Initialize debug trap //
00835         // If set to 1 the processor generate a debug exception when a task switch to this task occurs...
00836         task->tss.trace = 0;
00837 
00838         // Setup starting address //
00839         task->tss.cs = (privilege == KERNEL_PRIVILEGE) ? KERNEL_CODE : USER_CODE | 3;
00840         task->tss.eip = entry;
00841 
00842         // Get a pid //
00843         task->pid = new_pid();
00844 
00845         // Store the name //
00846         // The last character must be ever '\0' (end of string) //
00847         strncpy(task->name, filename, sizeof(task->name)-2);
00848 
00849         // Set the type //
00850         task->type = PROCESS_T;
00851 
00852         // Set the parent process //
00853         task->father = curr_task;
00854 
00855         // Set the console //
00856         task->console = curr_task->console;
00857 
00858         // Insert the task into the ready queue //
00859         task->state = READY;
00860         add_queue(&ready_queue, task);
00861 
00862         // Well done! //
00863         kfree(filebuffer);
00864         sched_leave_critical_region();
00865 
00866         return( task );
00867 }

size_t new_vspace  
 

Create a new virtual space.

Returns:
The physical address of the page directory for the new virtual space.
Exceptions:
NULL  If an error occurs (in particular out-of-memory).

Definition at line 579 of file task.c.

00580 {
00581         size_t PDBR_frame;
00582         uint32_t *PDBR;
00583         int i;
00584 
00585         // Create the virtual space of the task                         //
00586         PDBR = (uint32_t *)get_temp_page();
00587         if (PDBR == NULL)
00588         {
00589                 // Out of memory!!!                                     //
00590                 return( NULL );
00591         }
00592         PDBR_frame = vir_to_phys( (dword)PDBR );
00593 
00594         // Initialize PDBR                                              //
00595         memset(PDBR, 0, PAGE_SIZE);
00596         for (i=K_VIR_START/(PAGE_SIZE*1024); i<1024; i++)
00597                 PDBR[i] = K_PDBR[i];
00598         // Map page directory into itself                               //
00599         PDBR[1023] = PDBR_frame | P_PRESENT | P_WRITE;
00600 
00601         // Free the page, but doesn't destroy the physical frame        //
00602         free_temp_page( PDBR, FALSE );
00603 
00604         return( PDBR_frame );
00605 }

void sleep_task task_t   p
 

Sleep a process if it is awake.

Parameters:
p  The structure of the task to sleep.

Definition at line 1024 of file task.c.

01025 {
01026         p->state = WAIT;
01027 }

uint32_t* task_setup_stack int    argc,
char **    argv,
addr_t    stack_start,
size_t    stack_size,
int    privilege
 

Initialize the stack for a new process.

Parameters:
argc  The number of arguments passed to the new process.
argv  A pointer to the argument strings. NOTE: The content of argv may be changed!!!
stack_start  Where the stack is placed in memory.
stack_size  The size of the stack in bytes.
privilege  The privilege of the task.
Returns:
The starting stack pointer after initialization.

Definition at line 620 of file task.c.

00621 {
00622         static uint8_t __i386_quit[] = {
00623                 0xb8, 0x00, 0x00, 0x00, 0x00,   // mov $0x0, %eax
00624                 0x89, 0xe5,                     // mov %esp, %ebp
00625                 0xcd, 0x80,                     // int $0x80
00626         };
00627         size_t *stack = (uint32_t *)( (stack_start - sizeof(size_t)) -
00628                                         ALIGN_UP(sizeof(size_t), sizeof(__i386_quit)) -
00629                                         sizeof(size_t) );
00630         size_t *exit_point = stack;
00631         size_t *user_argv;
00632         int i;
00633 
00634         // We have not to null the stack to enforce page mapping for a  //
00635         // user-mode task, because a stack fault is managed like a      //
00636         // normal page fault.                                           //
00637         // But In kernel mode a stack fault can cause a system reboot   //
00638         // so we must enforce the page mapping in this case.            //
00639         if ( privilege == KERNEL_PRIVILEGE )
00640                 memset((void *)(stack_start-stack_size), 0, stack_size/sizeof(size_t));
00641 
00642         // Copy the exit code into the stack, because if we are in      //
00643         // user-mode we cannot access to the kernel space without       //
00644         // causing a page level protection fault.                       //
00645         memcpy((void *)stack, __i386_quit, sizeof(__i386_quit));
00646 
00647         // Copy external parameters strings                             //
00648         for( i=0; i<argc; i++ )
00649         {
00650                 stack = (size_t *)((size_t)stack - strlen(argv[i]) - 1);
00651                 strcpy((char *)stack, argv[i]);
00652                 argv[i] = (char *)stack;
00653         }
00654 
00655         // Round down the stack pointer to the stack boundaries         //
00656         stack = (size_t *)( TRUNC((size_t)stack, sizeof(size_t)) );
00657 
00658         // Copy parameter string pointers                               //
00659         for( i=0; i<argc; i++ )
00660         {
00661                 *(--stack) = (size_t)(argv[argc-i-1]);
00662         }
00663 
00664         // Set the process argv pointer                                 //
00665         user_argv = stack;
00666         *(--stack) = (size_t)user_argv;
00667         // Copy number of parameters value                              //
00668         *(--stack) = argc;
00669         // Copy the exit point address                                  //
00670         *(--stack) = (size_t)(exit_point);
00671 
00672         // Return the initial stack pointer                             //
00673         return( stack );
00674 }

pid_t waitpid pid_t    pid,
int *    status,
int    options
 

Wait for the exit of a child.

Parameters:
pid 
  • The child process id
  • -1 to wait for the exit of a generic child.
status  Reports the status of the child.
options  Options flags.
Returns:
The pid of the child or -1 if the process has not been found.

Todo:
status flags and options flags not yet implemented!

Definition at line 966 of file task.c.

00967 {
00968         // Queues where to search the processes                         //
00969         static queue_t **q[] = { &ready_queue, &wait_queue };
00970         task_t *p;
00971         int i, j, n;
00972         bool found = FALSE;
00973         dword IF = GET_IF();
00974 
00975         // A task can't wait for yourself!                              //
00976         if (curr_task->pid == pid) return(0);
00977 
00978 repeat:
00979         sched_enter_critical_region();
00980         // Search into every task queue                                 //
00981         for( i=0; i<_countof(q); i++ )
00982         {
00983                 for( j=0, n = count_queue( q[i] ); j<n; j++ )
00984                 {
00985                         p = pick_queue( q[i] );
00986                         if ( (p->father == curr_task) && ((pid==-1) || (p->pid==pid)) )
00987                         {
00988                                 // Found!                               //
00989                                 found = TRUE;
00990 
00991                                 // Update the pid of the child that we  //
00992                                 // are waiting (when pid is -1).        //
00993                                 pid = p->pid;
00994 
00995                                 // Move the current task (father) into  //
00996                                 // the wait queue and wait              //
00997                                 if ( rem_queue(&ready_queue, curr_task) )
00998                                 {
00999                                         add_queue(&wait_queue, curr_task);
01000                                         curr_task->state = WAIT;
01001                                 }
01002                                 sched_leave_critical_region();
01003 
01004                                 // Sleeped!                             //
01005                                 // Now wait for the dispatcher          //
01006                                 enable();
01007                                 idle();
01008                                 // Task waked-up! Check if the child    //
01009                                 // that we are waiting is dead          //
01010                                 goto repeat;
01011                         }
01012                 }
01013 
01014         }
01015         sched_leave_critical_region();
01016         SET_IF(IF);
01017 
01018         // Return the child pid or -1 if the process has not been found //
01019         return( (found) ? pid : -1 );
01020 }

void wakeup_task task_t   p
 

Wakeup a process if it is sleeping.

Parameters:
p  The structure of the task to wakeup.

Definition at line 1031 of file task.c.

01032 {
01033         p->state = READY;
01034 }


Generated on Fri Feb 20 15:32:23 2004 for Minirighi by doxygen1.2.18