initial commit
[pfinal.git] / Routix / src / mm / paging.c
blobc8b58e7e5b9302c76024f8e760d2f74a7e3f72a3
1 /*! \addtogroup MemoryManager
2 \page paging.c
3 Administración de la memoria paginada. Esta compuesto por funciones dedicadas a la traducción de direcciones físicas
4 a lineales y viceversa. Prepara los directorios y tablas de páginas, para accesos lógicos.
5 */
7 #include "routix/system.h"
8 #include "routix/paging.h"
9 #include "routix/debug.h"
10 #include <routix/kstdio.h>
11 #include "routix/kalloc.h"
15 //! Devuelve en la estructura la posicion dentro del DIR de paginas, y dentro de la Tabla
16 page_index_t get_page_index (addr_t p)
18 page_index_t indice;
20 indice.dir_index = p / ( PAGINA_SIZE * TABLAS_POR_DIR);
21 indice.tabla_index = (p % ( PAGINA_SIZE * TABLAS_POR_DIR)) / PAGINA_SIZE;
22 return indice;
26 //! Convierte una direccion logica respecto a cierto CR3 a una direccion de memoria fisica
27 void *convertir_direccion ( void *dir_logica, addr_t cr3 )
29 void *dir_fisica;
31 page_index_t indice;
33 // Obtener los indices del directorio y de la tabla de paginas para la direccion logica
34 indice = get_page_index ( (addr_t) dir_logica );
36 pd_t *dir= (pd_t *) cr3;
37 // Obtener la direccion de la tabla correspondiente y enmascarar los 12 bits de atributos
38 pt_t *tabla = (pt_t *) (dir->entry[indice.dir_index] & 0xfffff000);
39 // Obtener la direccion fisica y enmascarar los 12 bits de atributos
40 dir_fisica = (void *) (tabla->entry[indice.tabla_index] & 0xfffff000);
42 // Sumarle a la pagina obtenida de la tabla el offset de la direccion logica
43 dir_fisica = dir_fisica + ((dword) dir_logica & 0xfff);
45 return dir_fisica;
49 //! Crea una entrada de directorio (tanto para directorio como para tabla, ya que son iguales en IA32)
50 pde_t make_pde (addr_t direccion, word atributos)
52 pde_t entrada;
53 entrada= atributos & 0xfff;
54 entrada= entrada | direccion;
56 return entrada;
59 //! Crea una entrada de Pagina (tanto para directorio como para tabla, ya que son iguales en IA32)
60 pte_t make_pte (addr_t direccion, word atributos)
62 pte_t entrada;
63 entrada= atributos & 0xfff;
64 entrada= entrada | direccion;
66 return entrada;
71 /*! Mapea una dirección física en una logica */
72 /* ej.:
73 * mem = kmalloc_page();
74 * if ( ! kmapmem( fisica, mem, 0xe0000000, PAGE_PRES ) )
75 * kfree_page(mem);
77 #define ERR_DIR_BUSY -1
78 #define ERR_NO_ALIGN -2
80 #define ERR_DIR_EMPTY -5
82 /*! \brief Mapea una dirección física en una lógica
83 * \param fisica dirección de la pagina física (debe estar alineada a 4KB)
84 * \param logica dirección lógica donde quiero tener la página anteriormente citada
85 * \param directorio directorio de páginas en el cuál se desea mapear la dirección
86 * \param atributo atributos de página
87 * \return 0 en caso de exito y -1 en caso contrario
89 int kmapmem ( addr_t fisica, addr_t logica, addr_t directorio, word atributo)
91 page_index_t indice;
92 indice = get_page_index ( logica );
93 pd_t *dir;
94 pt_t *tabla;
95 word i;
97 atributo = atributo & 0xfff;
99 if ( (fisica & 0xfff) || (logica & 0xfff) ) {
100 if ( getvar("pagedebug")==1 )
101 kprintf("Debug Mode - Fis2log: las direcciones deben estar alineadas a 4KB\n");
102 return ERR_NO_ALIGN;
105 if ( getvar("pagedebug")==1 ) {
106 kprintf("Kmapmem: Mapeando 0x%x en 0x%x\n", fisica, logica);
107 kprintf("Kmapmem: Indice DIR: %d Indice Tabla: %d\n", indice.dir_index, indice.tabla_index);
110 dir= (pd_t *) directorio;
112 if (dir->entry[indice.dir_index] == 0 ) {
113 if ( getvar("pagedebug")==1 )
114 kprintf("Kmapmem: Debe alocarse una nueva tabla de paginas\n");
116 dir->entry[indice.dir_index]= (pde_t) make_pde ( kmalloc_page(), PAGE_PRES | PAGE_SUPER | PAGE_RW);
117 tabla = (pt_t *) (dir->entry[indice.dir_index] & 0xfffff000);
118 /* Poner todas las pte en 0 */
119 for (i=0; i < PAGINAS_POR_TABLA ; i++)
120 tabla->entry[i]=(pte_t) make_pte (0, 0);
123 else { // Si la entrada existe, esa pagina puede ya estar asignada
125 tabla = (pt_t *) (dir->entry[indice.dir_index] & 0xfffff000);
126 if (tabla->entry[indice.tabla_index]) {
127 if ( getvar("pagedebug")==1 )
128 kprintf("Kmapmem: Pagina ya en uso\n");
129 return ERR_DIR_BUSY;
133 tabla->entry[indice.tabla_index]= (pte_t) make_pte ( fisica , atributo);
135 return OK;
138 /*! \brief "Desmapea" una dirección lógica
139 * Esta función se encarga de liberar la tabla de página si no posee entradas
140 * \param logica dirección lógica de la página
141 * \param directorio directorio de páginas donde se encuentra mapeada
142 * \return 0 en caso de éxito, -1 en caso contrario
144 int kunmapmem (addr_t logica, addr_t directorio)
146 if ( logica & 0xfff) {
147 if ( getvar("pagedebug")==1 )
148 kprintf("KunmapMem: la direccion debe estar alineada a 4KB\n");
149 return ERR_NO_ALIGN;
153 page_index_t indice;
154 indice = get_page_index ( logica );
156 pd_t *dir = (pd_t *) directorio;
158 pt_t *tabla = (pt_t *) (dir->entry[indice.dir_index] & 0xfffff000);
161 if ( !tabla ) { //Si la entrada correspondiente a "logica" esta vacia
162 if ( getvar("pagedebug")==1 )
163 kprintf("Debug Mode - KunmapMem: la tabla esta vacia\n");
164 return ERR_DIR_EMPTY;
167 //Liberar la entrada correspondiente
168 tabla->entry[indice.tabla_index] = 0;
171 //Ahora verifico si todas las entradas de la tabla estan vacias. Si es asi la libero. Con que haya una
172 //ocupada, no puedo hacerlo
173 word i;
174 for ( i=0 ; i < PAGINAS_POR_TABLA ; i++)
175 if ( tabla->entry[i] )
176 return OK;
178 if (getvar("pagedebug")==1)
179 kprintf("Kunmapmem: liberando tabla en: 0x%x\n", dir->entry[indice.dir_index] & 0xfffff000);
180 kfree_page( (addr_t) (dir->entry[indice.dir_index] & 0xfffff000) );
181 dir->entry[indice.dir_index] = 0;
182 return OK;
186 //! Crea un nuevo directorio de páginas para una aplicación
187 void *make_pdt (void)
189 addr_t nuevo_directorio = kmalloc_page();
190 if ( nuevo_directorio == 0) {
191 return NULL;
194 copy_page( (void *) nuevo_directorio, (void *) USER_PDT);
195 return (void *) nuevo_directorio;
198 //! Copia una pagina completa, moviendo de a 4 bytes (movsl) una cantidad de PAGINA_SIZE / sizeof(dword) (1024 veces
199 //! si PAGINA_SIZE=4096 y el dword es de 4 bytes
200 void *copy_page( void *dest, const void *src)
202 __asm__("push %%ecx; push %%edi ; push %%esi ;cld ; rep ; movsl ; pop %%esi ; pop %%edi ; pop %%ecx" \
203 : : "c" ((word) (PAGINA_SIZE / (sizeof(dword)))), "S" (src), "D" (dest));
205 return dest;