//Salva contexto de la tarea anterior,carga contexto idle y actualiza las estructuras unsigned short saltar_idle(){ tss* tss_gdt_a_liberar; unsigned short res = proximo_indice_gdt(); if (res == 0x80){ tss_gdt_a_liberar = &tss2; } else { tss_gdt_a_liberar = &tss1; } tss* tss_a_salvar = (tarea_anterior == IDLE) ? &tss_idle : &tareas_tss[tarea_anterior]; // Salvo el contexto de la tarea anterior tss_copy(tss_gdt_a_liberar, tss_a_salvar); // Cargo el conexto de la idle. tss_copy(&tss_idle,tss_gdt_a_liberar); tarea_anterior = tarea_actual; tarea_actual = IDLE; if (indice_gdt == 1){ indice_gdt = 2; }else { indice_gdt = 1; } return res; }
void tss_inicializar_tarea_idle () { tss_idle.ptl = 0x0; tss_idle.unused0 = 0x0; tss_idle.esp0 = 0x27000; tss_idle.ss0 = 0b1011000; tss_idle.unused1 = 0x0; tss_idle.esp1 = 0x0; tss_idle.ss1 = 0x0; tss_idle.unused2 = 0x0; tss_idle.esp2 = 0x0; tss_idle.ss2 = 0x0; tss_idle.unused3 = 0x0; tss_idle.cr3 = 0x27000; tss_idle.eip = 0x20000; tss_idle.eflags = 0x00000202; /* INTERRUPCIONES. CHEQUEAR MANUAL. */ tss_idle.eax = 0x0; tss_idle.ecx = 0x0; tss_idle.edx = 0x0; tss_idle.ebx = 0x0; tss_idle.esp = 0x27000; tss_idle.ebp = 0x27000; tss_idle.esi = 0x0; tss_idle.edi = 0x0; tss_idle.es = 0b1011000; tss_idle.unused4 = 0x0; tss_idle.cs = 0b1001000; /* IDLE VIVE EN KERNEL */ tss_idle.unused5 = 0x0; tss_idle.ss = 0b1011000; tss_idle.unused6 = 0x0; tss_idle.ds = 0b1011000; tss_idle.unused7 = 0x0; tss_idle.fs = 0b1011000; tss_idle.unused8 = 0x0; tss_idle.gs = 0b1011000; tss_idle.unused9 = 0x0; tss_idle.ldt = 0x0; tss_idle.unused10 = 0x0; tss_idle.dtrap = 0x0; /* ??? */ tss_idle.iomap = 0xffff; tss_copy(&tss_next_1, &tss_idle); tss_copy(&tss_inicial, &tss_idle); }
unsigned short sched_montar_idle () { unsigned short r; tss *anterior; anterior = guardar_tanquecito ? &tss_tanques[_tarea_actual] : &tss_idle; /* Se entiende leyendo sched_proxima_tarea. */ if (GDT_TSS_1_BUSY()) { tss_copy(anterior, tss_tarea_2); tss_copy(tss_tarea_2, &tss_idle); } else { tss_copy(anterior, tss_tarea_1); tss_copy(tss_tarea_1, &tss_idle); } r = GDT_TSS_1_BUSY() ? GDT_TSS_2 << 3 : GDT_TSS_1 << 3; guardar_tanquecito = 1 - _esta_corriendo_la_idle; _esta_corriendo_la_idle = TRUE; return r; }
// Prepara el salto para una tarea de usuario. unsigned short sched_cambio_task(){ tss* tss_gdt_a_liberar; unsigned short prox_tarea = sched_proximo_indice(); // Si solo hay 1 tarea, no salto. if (tarea_actual == prox_tarea) return 0; unsigned short res = proximo_indice_gdt(); if (res == 0x80){ tss_gdt_a_liberar = &tss2; } else { tss_gdt_a_liberar = &tss1; } // Cuando recien empiezo con las tareas, tarea_anterior vale 88. // Con lo cual, no tengo que salvar el contexto de "tarea_anterior". if (tarea_anterior == IDLE){ // Salvo contexto de la idle. tss_copy(tss_gdt_a_liberar,&tss_idle); } else if (tarea_anterior != 88 ){ // Salvo contexto de la tarea anterior. tss_copy(tss_gdt_a_liberar, &tareas_tss[tarea_anterior]); } // Cargo el contexto de la tarea a ejecutar. tss_copy(&tareas_tss[prox_tarea],tss_gdt_a_liberar); tarea_anterior = tarea_actual; tarea_actual = prox_tarea; if (indice_gdt == 1 ){ indice_gdt = 2; } else { indice_gdt = 1; } return res; }
void sched_inicializar () { unsigned int i; for (i = 0; i < CANT_TANQUES; i++) { tareas_vivas[i] = TRUE; } tss_tarea_1 = &tss_next_1; /* Tienen que apuntar a algo asi no */ tss_tarea_2 = &tss_next_2; /* frutean al ser sobreescritas. */ tss_copy(tss_tarea_1, &tss_idle); _esta_corriendo_la_idle = TRUE; guardar_tanquecito = TRUE; _estan_todas_muertas = TRUE; _tarea_actual = CANT_TANQUES - 1; primera_vez = TRUE; }
unsigned short sched_proxima_tarea () { unsigned short r; static tss *proximo, *anterior; /** * Si hay que guardar el contexto de un tanque, lo hacemos. * Si no, hay que guardar el contexto de la idle. **/ anterior = guardar_tanquecito ? &(tss_tanques[_tarea_actual]) : &tss_idle; proximo = proxima_tarea(); /** * Si proximo devolvio NULL, o estan todas muertas, * no hay que saltar a otra tarea. **/ if (proximo == NULL || _estan_todas_muertas) { return 0; } if (GDT_TSS_1_BUSY()) { if (primera_vez) { /** * Como es la primera vez, no hace falta guardar el contexto * de la tarea anterior. **/ tss_copy(tss_tarea_2, &tss_tanques[0]); primera_vez = FALSE; } else { /** * Se copia en anterior (que apunta a la estructura correcta) * el contexto viejo, y se sobreescribe ese contexto en la gdt * con el contexto de la proxima tarea a ejecutar. **/ tss_copy(anterior, tss_tarea_2); tss_copy(tss_tarea_2, proximo); } } else { /* Comentarios idem. */ if (primera_vez) { tss_copy(tss_tarea_1, &tss_tanques[0]); primera_vez = FALSE; } else { tss_copy(anterior, tss_tarea_1); tss_copy(tss_tarea_1, proximo); } } /** * Si la entrada del selector de la tss 1 en la gdt esta ocupada, * devuelvo el selector de segmento de la entrada del selector de * la tss 2. Si no, devuelvo el de la tss 1. **/ r = GDT_TSS_1_BUSY() ? GDT_TSS_2 << 3 : GDT_TSS_1 << 3; /** * guardar_tanquecito va a valer 1 si no se esta corriendo la idle, * 0 en caso contrario. * Supongamos que viene corriendo la tarea 1 en la tss 1 y hace un syscall. * Se monta la idle [-> _esta_corriendo_la_idle = 1, y su contexto esta en * la tss 2]. Llega la interrupcion del clock, y hay que hacer context * switch. Se hace toda la saraza de arriba, y se llega a este cacho de * codigo. El codigo de la tarea 2 esta montado en la tss 1. En el proximo * clock, voy a tener que guardar el contexto de la idle. Como todavia * _esta_corriendo_la_idle vale 1, guardar_tanquecito va a pasar a valer 0, * y en el proximo clock, efectivamente anterior va a apuntar a la tss de * la tarea idle. **/ guardar_tanquecito = 1 - _esta_corriendo_la_idle; /* Como cambie de tarea, _NO_ esta corriendo la idle. */ _esta_corriendo_la_idle = FALSE; return r; }