/* Copyright (C) 2008 Emmanuel Varoquaux This file is part of XOS. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "proc_struct.h" #include #include #include #include #include #include #include #include #include #include /* table des taches */ static struct task_table_entry { struct task_table_entry *next_free; } task_table[NR_TASKS]; static struct task_table_entry *first_free; /* processus inactif */ static struct proc_struct _idle; struct proc_struct *const idle = &_idle; /* Table des taches */ static void init_task_table() { struct task_table_entry *entry; /* task_table[0] n'est jamais libre : c'est idle. */ entry = first_free = task_table + 1; while (entry != task_table + (NR_TASKS - 1)) { entry->next_free = entry + 1; entry++; } entry->next_free = NULL; } static void print_task_table_info() { printk("Task table size: %d\n", NR_TASKS); } static unsigned int alloc_task_nr() { struct task_table_entry *entry; if (!(entry = first_free)) return 0; first_free = first_free->next_free; return entry - task_table; } static void free_task_nr(unsigned int task_nr) { struct task_table_entry *entry; entry = task_table + task_nr; entry->next_free = first_free; first_free = entry; } /* Taches */ static void init_idle_task() { struct tss_data_struct tss_data; /* Inutile de definir idle->kernel_stack. */ /* table des pages de premier niveau */ get_pdbr(idle->page_directory); /* TSS */ tss_data.pdbr = (unsigned long)idle->page_directory; tss_data.ldt = 0; tss_data.ss0 = 0; /* idle ne fait jamais de changement de privilege donc il est inutile de definir ss0 et esp0. */ tss_data.esp0 = 0; tss_data.ss1 = 0; tss_data.esp1 = 0; tss_data.ss2 = 0; tss_data.esp2 = 0; tss_data.trap = 0; tss_data.iomap_base = 0; /* Inutile de definir les champs dynamiques car idle est en cours d'execution. */ set_tss(&idle->tss, &tss_data); gdt_set_tss_descr(0, &idle->tss); /* selecteur de TSS */ idle->tss_sel = get_tss_sel(0); /* chargement des registres systeme */ lldt(0); ltr(idle->tss_sel); } static int init_task(struct proc_struct *proc, const struct registers_struct *registers, const struct interrupted_instruction_struct *start_instruction) { int retval; unsigned int task_nr; struct tss_data_struct tss_data; /* allocation d'un numero de tache */ if (!(task_nr = alloc_task_nr())) { retval = -EAGAIN; goto error; } /* pile noyau */ if (!(proc->kernel_stack = kmalloc(KERNEL_STACK_SIZE))) { retval = -ENOMEM; goto error_free_task; } /* table des pages de premier niveau */ if (!(proc->page_directory = kmalloc(PAGE_SIZE))) { retval = -ENOMEM; goto error_free_kernel_stack; } /* TSS */ tss_data.pdbr = (unsigned long)proc->page_directory; tss_data.ldt = 0; tss_data.ss0 = KERNEL_DATA_SEL; tss_data.esp0 = (unsigned long)(proc->kernel_stack + KERNEL_STACK_SIZE); tss_data.ss1 = 0; tss_data.esp1 = 0; tss_data.ss2 = 0; tss_data.esp2 = 0; tss_data.trap = 0; tss_data.iomap_base = sizeof (struct tss_struct); /* pas de ports autorises en mode utilisateur */ tss_data.eax = 0; tss_data.ebx = registers->ebx; tss_data.ecx = registers->ecx; tss_data.edx = registers->edx; tss_data.ebp = registers->ebp; tss_data.esp = start_instruction->esp; tss_data.esi = registers->esi; tss_data.edi = registers->edi; tss_data.cs = USER_CODE_SEL; tss_data.ds = USER_DATA_SEL; tss_data.es = USER_DATA_SEL; tss_data.fs = USER_DATA_SEL; tss_data.gs = USER_DATA_SEL; tss_data.ss = USER_DATA_SEL; tss_data.eflags = start_instruction->eflags; tss_data.eip = start_instruction->eip; tss_data.previous = 0; set_tss(&proc->tss, &tss_data); gdt_set_tss_descr(task_nr, &proc->tss); /* selecteur de TSS */ proc->tss_sel = get_tss_sel(task_nr); return 0; error_free_kernel_stack: kfree(proc->kernel_stack, KERNEL_STACK_SIZE); error_free_task: free_task_nr(task_nr); error: return retval; } static void destroy_task(struct proc_struct *proc) { unsigned int task_nr; /* numero de tache */ task_nr = get_task_nr(proc->tss_sel); /* table des pages de premier niveau */ kfree(proc->page_directory, PAGE_SIZE); /* pile noyau */ kfree(proc->kernel_stack, KERNEL_STACK_SIZE); /* liberation du numero de tache */ free_task_nr(task_nr); } /* Interface publique */ void alloc_proc_init() { init_task_table(); init_idle_task(); } void alloc_proc_print_info() { print_task_table_info(); } /* Alloue et initialise une tache. Retourne un bloc de controle de processus * non initialise sur cette tache. */ int alloc_proc(const struct registers_struct *registers, const struct interrupted_instruction_struct *start_instruction, struct proc_struct **proc) { int retval; /* allocation de memoire pour le bloc de controle */ if (!(*proc = kmalloc(sizeof (struct proc_struct)))) { retval = -ENOMEM; goto error; } /* initialisation de la tache */ if ((retval = init_task(*proc, registers, start_instruction)) < 0) goto error_kfree; return 0; error_kfree: kfree(*proc, sizeof (struct proc_struct)); error: return retval; } /* Detruit et libere une tache. */ void free_proc(struct proc_struct *proc) { /* destruction de la tache */ destroy_task(proc); /* liberation de la memoire allouee pour le bloc de controle */ kfree(proc, sizeof (struct proc_struct)); }