void cpu_reset(void) { disable_intr(); /* * The keyboard controller has 4 random output pins, one of which is * connected to the RESET pin on the CPU in many PCs. We tell the * keyboard controller to pulse this line a couple of times. */ outb(IO_KBD + KBCMDP, KBC_PULSE0); delay(100000); outb(IO_KBD + KBCMDP, KBC_PULSE0); delay(100000); /* * Try to cause a triple fault and watchdog reset by making the IDT * invalid and causing a fault. */ memset((caddr_t)idt, 0, NIDT * sizeof(idt[0])); __asm __volatile("divl %0,%1" : : "q" (0), "a" (0)); #if 0 /* * Try to cause a triple fault and watchdog reset by unmapping the * entire address space and doing a TLB flush. */ memset((caddr_t)PTD, 0, PAGE_SIZE); tlbflush(); #endif for (;;); }
/* * Move pages from one kernel virtual address to another. * Both addresses are assumed to reside in the Sysmap. */ void pagemove(caddr_t from, caddr_t to, size_t size) { pt_entry_t *fpte, *tpte, *mafpte, *matpte; pt_entry_t ofpte, otpte; #ifdef MULTIPROCESSOR u_int32_t cpumask = 0; #endif #ifdef DIAGNOSTIC if ((size & PAGE_MASK) != 0) panic("pagemove"); #endif fpte = kvtopte((vaddr_t)from); tpte = kvtopte((vaddr_t)to); while (size > 0) { mafpte = (pt_entry_t *)vtomach((vaddr_t)fpte); matpte = (pt_entry_t *)vtomach((vaddr_t)tpte); otpte = pte_atomic_update(tpte, matpte, *fpte); ofpte = pte_atomic_update(fpte, mafpte, 0); tpte++; fpte++; #if defined(I386_CPU) && !defined(MULTIPROCESSOR) if (cpu_class != CPUCLASS_386) #endif { if (otpte & PG_V) #ifdef MULTIPROCESSOR pmap_tlb_shootdown(pmap_kernel(), (vaddr_t)to, otpte, &cpumask); #else pmap_update_pg((vaddr_t)to); #endif if (ofpte & PG_V) #ifdef MULTIPROCESSOR pmap_tlb_shootdown(pmap_kernel(), (vaddr_t)from, ofpte, &cpumask); #else pmap_update_pg((vaddr_t)from); #endif } from += PAGE_SIZE; to += PAGE_SIZE; size -= PAGE_SIZE; } #ifdef MULTIPROCESSOR pmap_tlb_shootnow(cpumask); #else #if defined(I386_CPU) if (cpu_class == CPUCLASS_386) tlbflush(); #endif #endif }
//cambia el contexto del directorio de paginas, invalida la cache de direcciones y retorna el contenido viejo de CR3 unsigned int changePaginationContext(pagedir_entry* newDirContext){ //usando estos "getters" y "setters" del registro del cpu CR3 voy a cambiar el contexto de memoria virtual //void lcr3(unsigned int val); => escribe a CR3 //unsigned int rcr3(void); => lee el contenido de CR3 unsigned int oldCR3 = rcr3(); lcr3((unsigned int) newDirContext); //invalido la cache de traduccion de direcciones tlbflush(); return oldCR3; }
/* * Write bytes to kernel address space for debugger. */ void db_write_bytes(vaddr_t addr, size_t size, char *data) { char *dst; pt_entry_t *ptep0 = 0; pt_entry_t oldmap0 = { 0 }; vaddr_t addr1; pt_entry_t *ptep1 = 0; pt_entry_t oldmap1 = { 0 }; extern char etext; if (addr >= VM_MIN_KERNEL_ADDRESS && addr < (vaddr_t)&etext) { ptep0 = kvtopte(addr); oldmap0 = *ptep0; *(int *)ptep0 |= /* INTEL_PTE_WRITE */ PG_RW; addr1 = trunc_page(addr + size - 1); if (trunc_page(addr) != addr1) { /* data crosses a page boundary */ ptep1 = kvtopte(addr1); oldmap1 = *ptep1; *(int *)ptep1 |= /* INTEL_PTE_WRITE */ PG_RW; } tlbflush(); } dst = (char *)addr; while (size-- > 0) *dst++ = *data++; if (ptep0) { *ptep0 = oldmap0; if (ptep1) *ptep1 = oldmap1; tlbflush(); } }
//Pre: existe la pagina a desmapear //Post: se desmapea la pagina, queda no presente en la tabla de paginas correspondiente. void mmu_unmapear_pagina(unsigned int virtual, pagedir_entry* pageDirBase){ //obtengo los indices del dir de paginas y las tablas unsigned int pdIndex = (unsigned int)(virtual >> 22);//me quedo con los bits 31 a 22 unsigned int ptIndex = (unsigned int)((virtual >> 12) & 0x03FF);//con la mascara me quedo unicamente con 10 bits de los bits 21 a 12 //obtengo la tabla de paginas desde el directorio de paginas //shifteo 12 bits la direccion para completar el puntero de 32 bits a la tabla de paginas apuntada por la entrada del directorio pagetable_entry* pageTable = (pagetable_entry*) (pageDirBase[pdIndex].pageBase << 12); //indexo la pagina en cuestion de la tabla y la seteo como no presente pageTable[ptIndex].present=0;//la marco como no presente //si no quedaron mas paginas presentes en toda la tabla, seteo como no presente la entrada del directorio? tlbflush(); }
//esta funcion inicializa el directorio de paginas y las 2 tablas de paginas necesarias que se piden por enunciado en el ej 3b. //para el ejercicio 3b del tp me piden mapear los primeros 7.5mb entre 0x00000000 y 0x0077FFFF, necesito 2 entradas en el directorio de paginas, //la primera de 1024 entradas de 4k => 4mb y la segunda con 896 entradas de 4k => 3584 = 3.5mb //las primeras 1024 paginas las puedo clavar en la tabla de paginas del kernel en 0x28000 segun el mapa de memoria //las proximas 896 las voy a poner momentaneamente a partir de KERNEL_SECOND_PAGETABLE_POINTER por lo consultado a los ayudantes que realizaron el mapa de memoria void mmu_inicializar_dir_kernel() { //marco todas como no presentes en el directorio de paginas, son 1024 entradas pageDirectoryInitialize(krnPageDir, 0, 0, 1023); //inicializo 1024 paginas con direcciones entre 0 y 1023*4096 marcandolas como presentes pageTableInitialize(krnFirstPageTable, 1, 0, 1023, 0); //marco las 1024 paginas como no presentes en la segunda tabla de paginas pageTableInitialize(krnSecondPageTable, 0, 0, 1023, 1024/*comenzar a mapear desde aqui*/); //inicializo las primeras 896 paginas para llenar 3.5mb como presentes pageTableInitialize(krnSecondPageTable, 1, 0, 895, 1024/*comenzar a mapear desde 1024 inclusive*/); //activo las primeras 2 paginas del directorio y les seteo las direcciones de las 2 tablas de paginas PAGEDIR_ENTRY(krnPageDir, 0/*index*/, 1/*present*/, 1/*read+write*/, 0/*supervisor*/, 0, 0, 0, 0, 0, 0, 0, (((unsigned int)(krnFirstPageTable)) >> 12) ); PAGEDIR_ENTRY(krnPageDir, 1/*index*/, 1/*present*/, 1/*read+write*/, 0/*supervisor*/, 0, 0, 0, 0, 0, 0, 0, (((unsigned int)(krnSecondPageTable)) >> 12) ); //invalido la cache de traduccion de direcciones tlbflush(); }
//Pre: todas las entradas del dir de paginas y de todas las tablas de paginas que se acceden estan previamente inicializadas //es decir, cuando accedo a las pageBase los punteros son validos y los bits tienen algun valor inicializado a conciencia //&& dir fisica esta alineada a 4k //Post: pisa la pagina si existia anteriormente con el mapeo void mmu_mapear_pagina(unsigned int virtual, pagedir_entry* pageDirBase, unsigned int fisica, unsigned char readWriteb, unsigned char userSupervisorb){ //obtengo los indices del dir de paginas y las tablas unsigned int pdIndex = (unsigned int)(virtual >> 22);//me quedo con los bits 31 a 22 unsigned int ptIndex = (unsigned int)((virtual >> 12) & 0x03FF);//con la mascara me quedo unicamente con 10 bits de los bits 21 a 12 //obtengo el offset de la pagina unsigned int pageOffset = (unsigned int)(virtual & 0x0FFF);//me quedo con los primeros 12 bits //obtengo la tabla de paginas desde el directorio de paginas //shifteo 12 bits la direccion para completar el puntero de 32 bits a la tabla de paginas apuntada por la entrada del directorio //esto es un acceso valido por precondicion! pagetable_entry* pageTable = (pagetable_entry*) (pageDirBase[pdIndex].pageBase << 12); //PARAMETROS MACRO: pageTableTarget, index, userSupervisorb, pageLevelWriteThroughb, pageLevelCacheDisableb, accesedb, dirtyBitb, disponibleb, pageBased PAGETABLE_ENTRY(pageTable, ptIndex, 1/*present*/, readWriteb/*read+write*/, userSupervisorb/*supervisor*/, 0/*pageLevelWriteThroughb*/, 0/*pageLevelCacheDisableb*/, 0/*accesedb*/, 0/*dirtyBitb*/, 0/*disponibleb*/, ((fisica + pageOffset) >> 12)/*direccion >> 12 pues es multiplo de 4k*/); //seteo como presente la entrada en el directorio de paginas(podria pasar que no hubiera ninguna pagina todavia y ahora la hay) pageDirBase[pdIndex].present = 1; tlbflush(); }
/* Frees (decrefs) all memory mapped in the given range */ void env_user_mem_free(env_t* e, void* start, size_t len) { assert((uintptr_t)start + len <= UVPT); //since this keeps f*****g happening int user_page_free(env_t* e, pte_t pte, void* va, void* arg) { if (!pte_is_mapped(pte)) return 0; page_t *page = pa2page(pte_get_paddr(pte)); pte_clear(pte); page_decref(page); /* TODO: consider other states here (like !P, yet still tracking a page, * for VM tricks, page map stuff, etc. Should be okay: once we're * freeing, everything else about this proc is dead. */ return 0; } env_user_mem_walk(e,start,len,&user_page_free,NULL); tlbflush(); }
void mmu_unmapear_pagina(unsigned int virtual, unsigned int cr3){ int *page_directory = (int*) (ALIGN(cr3)); int *page_table = (int*) (page_directory[PDE_INDEX(virtual)] & 0xFFFFF000); int presente = (page_directory[PDE_INDEX(virtual)] & 0x01); int tablaVacia = 1; if(presente){ page_table[PTE_INDEX(virtual)] = 0; int i = 0; while(tablaVacia && i < 1024){ int entradaNoPresente = (page_table[i] & 0x01); // Aca usamos and logico. La tabla esta vacia // si ya estaba vacia y la i-esima entrada no esta presente tablaVacia = tablaVacia && entradaNoPresente; i++; } if(tablaVacia){ page_directory[PDE_INDEX(virtual)] = 0; } } tlbflush(); }
static inline void pmap_tlb_invalidate(const pmap_tlb_packet_t *tp) { int i; /* Find out what we need to invalidate. */ if (tp->tp_count == (uint16_t)-1) { u_int egen = uvm_emap_gen_return(); if (tp->tp_pte & PG_G) { /* Invalidating user and kernel TLB entries. */ tlbflushg(); } else { /* Invalidating user TLB entries only. */ tlbflush(); } uvm_emap_update(egen); } else { /* Invalidating a single page or a range of pages. */ for (i = tp->tp_count - 1; i >= 0; i--) { pmap_update_pg(tp->tp_va[i]); } } }
void mmu_mapear_pagina( unsigned int virtual, unsigned int cr3, unsigned int fisica, short attr){ unsigned int pageDirIndex = PDE_INDEX(virtual); //ebp-12 unsigned int pageDirTableIndex = PTE_INDEX(virtual); //ebp-16 unsigned int page_table_entry = fisica | attr; //ebp-20 int* page_directory = (int*) (ALIGN(cr3)); int* page_table = 0; int presente = (page_directory[pageDirIndex] & 0x01); if(!presente){ // chequeo presente! page_table = mmu_proxima_pagina_fisica_libre(); page_directory[pageDirIndex] = ( (unsigned int) page_table ) | attr; int i = 0; while(i < 1024) {// Limpiamos la tabla nueva page_table[i] = 0; i++; } }else{ page_table = ((int*) (page_directory[pageDirIndex] & 0xFFFFF000)); } page_table[pageDirTableIndex] = page_table_entry; tlbflush(); }
// Free the EPT table entries and the EPT tables. // NOTE: Does not deallocate EPT PML4 page. void free_guest_mem(epte_t* eptrt) { free_ept_level(eptrt, EPT_LEVELS - 1); tlbflush(); }
pid loader_load(pso_file* f, int pl) { //me guardo el cr3 viejo. uint_32 old_cr3 = rcr3(); //pido un directorio para la nueva tarea void* task_dir = mm_dir_new(); printf(" >loader_load: task_dir = %x", task_dir); //TODO VER CUANTA MEMORIA NECESITA REALMENTE void* puntero_page_tarea = mm_mem_alloc(); printf(" >loader_load: puntero page tarea : %x", (uint_32) puntero_page_tarea); //stacks de anillo 3 y 0 para la tarea void* task_stack3 = mm_mem_alloc(); void* task_stack0 = mm_mem_alloc(); printf(" >loader_load: pfi after allocs: kernel = %x | usr = %x", *kernel_pf_info, *usr_pf_info); //ver esto donde van mapeados los stacks mm_page_map(STACK_3_VIRTUAL, task_dir, (uint_32) task_stack3, 0, USR_STD_ATTR); mm_page_map(STACK_0_VIRTUAL, task_dir, (uint_32) task_stack0, 0, MM_ATTR_RW | MM_ATTR_US_S); //TODO ver estas direcciones temporales donde ponerlas mm_page_map(KERNEL_TEMP_PAGE,(mm_page *) old_cr3, (uint_32) task_stack0, 0, MM_ATTR_RW | MM_ATTR_US_S); //inicializamos la pila de nivel 0 para que tenga el contexto para //poder volver del switchto uint_32* stack0 = (uint_32*) (KERNEL_TEMP_PAGE + 0xffC); *stack0-- = 0x23; *stack0-- = STACK_3_VIRTUAL + 0x1000; *stack0-- = 0x202; *stack0-- = (pl)? 0x1B : 0x08; //Elijo el selector de segmento según el privilegio de la tarea *stack0-- = (uint_32) f->_main; *stack0-- = (uint_32) &task_ret; *stack0-- = resp(); *stack0-- = 0x0; *stack0-- = 0x0; *stack0-- = 0x0; mm_page_map((uint_32) f->mem_start, task_dir, (uint_32) puntero_page_tarea, 0, USR_STD_ATTR); //mapeo la direccion virtual temporal para copiar en la pagina que recien se me asigno. mm_page_map((uint_32) KERNEL_TEMP_PAGE,(mm_page *) old_cr3, (uint_32) puntero_page_tarea, 0, USR_STD_ATTR); tlbflush(); //copio la tarea desde donde esta a la pagina que acabo de mapear. uint_8* addr_to_copy = (uint_8*) KERNEL_TEMP_PAGE; uint_8* task_to_copy = (uint_8*) f; uint_32 cant_to_copy = f->mem_end_disk - f->mem_start; int i; printf(" >loader_load: task_to_copy = %x", task_to_copy); for (i = 0; i < cant_to_copy; i++) { *addr_to_copy++ = *task_to_copy++; } //tengo que armar la estreuctura uint_32 requested_pid = get_new_pid(); task_table[requested_pid].cr3 = (uint_32) task_dir; task_table[requested_pid].esp0 = STACK_0_VIRTUAL + 0xFD8; mm_page_free(KERNEL_TEMP_PAGE, (mm_page *) old_cr3); tlbflush(); sched_load(requested_pid); tasks_running++; printf(" >loader_load: finished loading to new pid %d", requested_pid); return requested_pid; }
uint_32 sys_fork(uint_32 org_eip, uint_32 org_esp) { //me guardo el cr3 viejo. uint_32 old_cr3 = rcr3(); printf(" >sys_fork: org_eip (%x), org_esp (%x)", org_eip, org_esp); //pido un directorio para la nueva tarea void* new_cr3 = mm_dir_fork((mm_page*) old_cr3); if (new_cr3 == NULL) { //No pudo hacerse fork de la estrucutra de paginación printf("! >sys_fork: no se pudo crear el directorio de la nueva tarea"); return -1; } printf(" >sys_fork: new_cr3 = %x", new_cr3); //stacks de anillo 3 y 0 para la tarea void* task_stack3 = mm_mem_alloc(); void* task_stack0 = mm_mem_alloc(); printf(" >sys_fork: paginas stack_ kernel %x | usr %x", task_stack0, task_stack3); //ver esto donde van mapeados los stacks mm_page_map(STACK_3_VIRTUAL, new_cr3, (uint_32) task_stack3, 0, USR_STD_ATTR); mm_page_map(STACK_0_VIRTUAL, new_cr3, (uint_32) task_stack0, 0, MM_ATTR_RW | MM_ATTR_US_S); //TODO ver estas direcciones temporales donde ponerlas mm_page_map(KERNEL_TEMP_PAGE,(mm_page *) old_cr3, (uint_32) task_stack0, 0, MM_ATTR_RW | MM_ATTR_US_S); //inicializamos la pila de nivel 0 para que tenga el contexto para //poder volver del switchto uint_32* stack0 = (uint_32*) (KERNEL_TEMP_PAGE + 0xffC); *stack0-- = 0x23; *stack0-- = org_esp; *stack0-- = 0x202; *stack0-- = 0x1B; *stack0-- = org_eip; *stack0-- = (uint_32) &fork_ret; *stack0-- = resp(); *stack0-- = 0x0; *stack0-- = 0x0; *stack0-- = 0x0; //Copio la pila de usuario como está //Innecesario, ya lo hace el fork mm_copy_vf((uint_32*)STACK_3_VIRTUAL, (uint_32)task_stack3, PAGE_SIZE); mm_page_free(KERNEL_TEMP_PAGE, (mm_page*) old_cr3); tlbflush(); //tengo que armar la estructura de proceso uint_32 requested_pid = get_new_pid(); task_table[requested_pid].cr3 = (uint_32) new_cr3; task_table[requested_pid].esp0 = STACK_0_VIRTUAL + 0xFD8; //Duplico los file descriptor actualizando referencias device_fork_descriptors(cur_pid, requested_pid); // esto esta mal.. tiene q decidir q numero devolver creo q necesitamos un semaforo! sched_load(requested_pid); tasks_running++; printf(" >sys_fork: forkeo finalizado en pid %d", requested_pid); mm_dump(); return requested_pid; }