COBE 0.1 ALPHA
|
00001 #include <multitasking.h> 00002 #include <stdio.h> 00003 #include <pmm.h> 00004 #include <pgng.h> 00005 #include <sysfunc.h> 00006 00007 #ifndef NULL 00008 #define NULL (void *)0 00009 #endif 00010 00011 extern struct paging_directory* kernel_map; //----------Die Kernel-Map wird auch hier deklariert---------- 00012 00013 new_task_t* first_task = NULL; //----------Zwei Listenelemente für die Tasks, den Startpunkt und den immer derzeitigen Task---------- 00014 new_task_t* current_task = NULL; 00015 phy_alloc_list_t* current_list = NULL; //----------Ein Listenelemente für die allokierten Teile eines Modules, die derzeitige Liste---------- 00016 00017 new_tss_t tss; //----------Die TSS wird erzeugt---------- 00018 00020 00021 void init_mm(multiboot_info_t* mbinfo) { 00022 load_grub_module(0, mbinfo); //----------Das erste GRUB-Modul wird geladen---------- 00023 return; 00024 } 00025 00027 00028 uint32_t getnew_pid() { 00029 static uint32_t pid_counter = 0; 00030 return pid_counter++; 00031 } 00032 00034 00035 new_task_t* init_task(void* entry_point, char* name, phy_alloc_list_t* alloc_list) { 00036 00037 uint8_t* stack = pmm_alloc(); //----------4Kbyte jeweils für den Kernel-Stack und den User-Stack des neuen Tasks werden reserviert und erzeugt---------- 00038 uint8_t* usr_stack = pmm_alloc(); 00039 new_task_t* task = pmm_alloc(); //----------Für das Task-Element wird eine 4Kbyte Seite wird reserviert---------- 00040 struct paging_directory* new_pd = paging_map(); //----------Ein neues PageDirectory(Addressraum) für den neuen Task wird angelegt und initialisiert---------- 00041 00042 00043 //----------Vorläufig wird der Addressraum gleichgesetzt, phys. Addresse = virtuelle Addresse, alle Pages werden mit dem Usermode belegt---------- 00044 for(int i = 0; i < 1024 * 4096; i += 0x1000) identity_mapping(new_pd, i, i, ACCS_BIT | WRITE_BIT | ALL_ACCS_BIT); 00045 00046 //----------Die verteilten physischen Speicherblöcke in denen das Programm liegt werden in virtuelle Reihenfolge gelegt---------- 00047 new_map_addresses(alloc_list, new_pd, 0x200000); 00048 00049 kernel_mapping(new_pd); //----------Der Kernel wird auf RING0 belegt---------- 00050 task->task_pd = new_pd; //----------Die Adresse des PageDirectory wird in das Task-Element geschrieben, da es beim Scheduling gewechselt wird---------- 00051 00052 //----------Der CPU-Zustand wird erzeugt, eip zeigt auf den Einsprungspunkt, esp zeigt auf den User-Stack, die Segmente enthalten die RING3-Werte, bei eflags werden Interrupts freigeschaltet---------- 00053 cpu_regs new_cpu = { 00054 .eax = 0, 00055 .ebx = 0, 00056 .ecx = 0, 00057 .edx = 0, 00058 .esi = 0, 00059 .edi = 0, 00060 .ebp = 0, 00061 .eip = (uint32_t) entry_point, 00062 .esp = (uint32_t) usr_stack + 4096, 00063 .ss = 0x23, 00064 .cs = 0x1B, 00065 .ds = 0x23, 00066 .es = 0x23, 00067 .eflags = 0x200, 00068 }; 00069 00070 cpu_regs* state = (void*) (stack + 4096 - sizeof(new_cpu)); //----------Der CPU-Zustand wird auf den Kernel-Stack des Tasks geschrieben---------- 00071 *state = new_cpu; 00072 00073 task->cpu_state = state; //----------Der CPU-Zustand wird in das Task-Element geschrieben---------- 00074 task->kernel_stack = (uint32_t) stack; //----------Die Addresse des Kernel-Stack wird in das Task-Element geschrieben---------- 00075 task->usr_stack = (uint32_t) usr_stack; 00076 task->next_task = first_task; //----------Als nachfolgenden Task wird der erste Task gesetzt---------- 00077 task->memory_list = alloc_list; 00078 kstrcpy(task->name,name); 00079 task->pid = getnew_pid(); 00080 first_task = task; //----------Der erste Task ist nun dieser Task---------- 00081 00082 return task; 00083 } 00084 00086 00087 uint32_t kill_task(uint32_t pid) { 00088 new_task_t* prev_task = first_task; 00089 new_task_t* current_t = first_task; 00090 do { 00091 if(current_t->pid == pid) { 00092 prev_task->next_task = current_t->next_task; 00093 delete_map_addresses(current_t->memory_list,current_t->task_pd); 00094 pmm_free((void*)current_t->kernel_stack); 00095 pmm_free((void*)current_t->usr_stack); 00096 pmm_free((void*)current_t); 00097 return 0; 00098 } 00099 prev_task = current_t; 00100 current_t = current_t->next_task; 00101 } while(current_t->next_task != first_task); 00102 return 1; 00103 } 00105 00106 void set_tss_stack(uint32_t stack) { 00107 tss.esp0 = stack; //----------Der Kernel-Stack des neuen Tasks wird in die TSS geschrieben---------- 00108 return; 00109 } 00110 00112 00113 cpu_regs* schedule(cpu_regs* cpu) { 00114 if(current_task != NULL) current_task->cpu_state = cpu; //----------Sichere den alten CPU-Zustand im alten Task---------- 00115 if(current_task == NULL) current_task = first_task; //----------Möglicherweise war noch kein Task an der Reihe, der erste Task der Liste wird der neue Task---------- 00116 00117 else { //----------Wenn doch schon ein Task dran war, dann...---------- 00118 current_task = current_task->next_task; //----------...setze den nächsten Task als aktuellen Task---------- 00119 if(current_task == NULL) current_task = first_task; //----------Falls es nun der letzte Task ist, setze den ersten Task als aktuellen Task---------- 00120 } 00121 cpu = current_task->cpu_state; //----------Der CPU-Zustand des neuen Tasks ist der Rückgabewert---------- 00122 act_dir(current_task->task_pd); //----------Der Addressraum des neuen Tasks wird aktiviert---------- 00123 return cpu; //----------Der neue CPU-Zustand wird zurückgegeben---------- 00124 00125 } 00126 00128 00129 void load_grub_module(int num, multiboot_info_t* mbinfo) { 00130 00131 uint32_t address = 0x1000; //----------Der Zwischenwert für die neu zu kopierende Addresse---------- 00132 uint32_t list_address; //----------Die aktuelle Addresse der Liste wird deklariert---------- 00133 00134 module_t* grub_module = (void*)mbinfo->mods_addr; //----------Alle Grub-Module werden deklariert---------- 00135 uint32_t module_size = grub_module[num].mod_end - grub_module[num].mod_start; //----------Die Differenz aus End- und Startaddresse des aktuellen Moduls, ist die Größe des Moduls---------- 00136 uint32_t rest_of_module = module_size % 0x1000; //----------Der Rest der letzten geraden 0x1000-Größe---------- 00137 module_size = module_size - rest_of_module; //----------Der überstehende Rest wird von der Modul-Größe abgeschnitten---------- 00138 00139 list_address = (uint32_t) pmm_alloc(); //----------Ein Speicherbereich für die gesamte Liste wird reserviert---------- 00140 00141 phy_alloc_list_t* new_list = (void*)list_address; //----------Das erste Element wird an den Anfang des Speicherblocks geladen---------- 00142 list_address += sizeof(phy_alloc_list_t); //----------Die Addresse wird um ein Listen-Element hochgesetzt---------- 00143 00144 new_list->addr = pmm_alloc(); //----------Die Addresse zeigt auf einen leeren Speicherblock---------- 00145 current_list = new_list; //----------Die erste Liste, ist die aktuelle Liste---------- 00146 kmemcpy(new_list->addr, (void*) grub_module[num].mod_start, 0x1000); //----------Die ersten 4096Byte des Moduls werden an den ersten Speicherblock geschrieben---------- 00147 00148 //----------Wenn das Modul mehr als 4096Byte hat, müssen die restlichen Blöcke auch einen Platz finden---------- 00149 if(module_size > 0x1000) 00150 { 00151 //----------Das ganze wird so oft durchlaufen, bis alle Blöcke kopiert wurden---------- 00152 for(int i = module_size; i > address; address += 0x1000) 00153 { 00154 //----------Debug-Ausgaben---------- 00155 phy_alloc_list_t* new_phy_list = (void*)list_address; //----------Eine neue Liste wird an der aktuellen Adresse des Speicherblocks für die Listen angelegt, die Addresse wird wieder hochgesetzt---------- 00156 list_address += sizeof(phy_alloc_list_t); 00157 new_phy_list->addr = pmm_alloc(); //----------Die Addresse zeigt auf einen leeren Speicherblock---------- 00158 current_list->next = new_phy_list; //----------Die nächste Liste ist die neue Liste---------- 00159 current_list = new_phy_list; //----------Die neue Liste ist nun die aktuelle Liste---------- 00160 kmemcpy(new_phy_list->addr, (void*) (grub_module[num].mod_start + address), 0x1000); //----------Die nächsten 4096Byte des Moduls werden an den nächsten Speicherblock geschrieben---------- 00161 } 00162 } 00163 //----------Das gleiche nochmal für den letzten Rest, wobei der Rest auch einen ganzen Speicherblock bekommt, anders geht es nicht!---------- 00164 phy_alloc_list_t* new_list_end = (void*)list_address; 00165 list_address += sizeof(phy_alloc_list_t); 00166 new_list_end->addr = pmm_alloc(); 00167 current_list->next = new_list_end; 00168 new_list_end->next = NULL; //----------Eine nächste Liste gibt es nicht, die Liste muss abgebrochen werden---------- 00169 00170 kmemcpy(new_list_end->addr, (void*) (grub_module[num].mod_start + address), rest_of_module); 00171 00172 //----------Das Modul wird als Task gestart, der erste Speicherblock ist der Einsprungspunkt, der Name liegt im Modul, die Liste mit den physischen Addressen wird übergeben---------- 00173 init_task(new_list->addr, (char*)grub_module[num].string, new_list); 00174 00175 return; 00176 } 00177 00179 00180 void new_map_addresses(phy_alloc_list_t* alloc_list, struct paging_directory* pd, uint32_t adr) { 00181 00182 if(alloc_list == 0) return; 00183 uint32_t address = adr; 00184 phy_alloc_list_t* current_list = alloc_list; //----------Die erste Liste ist die aktuelle Liste---------- 00185 while(current_list->next != NULL) //----------Solange die nächste Liste nicht NULL ist, verfolge die Liste---------- 00186 { 00187 identity_mapping(pd, address, (uint32_t)current_list->addr, ACCS_BIT | WRITE_BIT | ALL_ACCS_BIT); //----------Mappe die virtuelle Addresse in einer Reihenfolge, mit den verteilten physischen Addressen---------- 00188 address += 0x1000; 00189 current_list = current_list->next; 00190 } 00191 identity_mapping(pd, address, (uint32_t)current_list->addr, ACCS_BIT | WRITE_BIT | ALL_ACCS_BIT); //----------Den Rest auch noch mappen!---------- 00192 00193 return; 00194 } 00195 00197 00198 void delete_map_addresses(phy_alloc_list_t* alloc_list, struct paging_directory* pd) { 00199 00200 if(alloc_list == 0) return; 00201 phy_alloc_list_t* current_list = alloc_list; //----------Die erste Liste ist die aktuelle Liste---------- 00202 pmm_free((void*)pd); 00203 pmm_free((void*)pd->page_directory); 00204 while(current_list->next != NULL) //----------Solange die nächste Liste nicht NULL ist, verfolge die Liste---------- 00205 { 00206 pmm_free((void*)current_list->addr); 00207 current_list = current_list->next; 00208 } 00209 pmm_free((void*)current_list->addr); //----------Den Rest auch noch löschen!---------- 00210 00211 return; 00212 }