1 /*! \addtogroup MemoryManager
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.
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
)
20 indice
.dir_index
= p
/ ( PAGINA_SIZE
* TABLAS_POR_DIR
);
21 indice
.tabla_index
= (p
% ( PAGINA_SIZE
* TABLAS_POR_DIR
)) / PAGINA_SIZE
;
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
)
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);
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
)
53 entrada
= atributos
& 0xfff;
54 entrada
= entrada
| direccion
;
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
)
63 entrada
= atributos
& 0xfff;
64 entrada
= entrada
| direccion
;
71 /*! Mapea una dirección física en una logica */
73 * mem = kmalloc_page();
74 * if ( ! kmapmem( fisica, mem, 0xe0000000, PAGE_PRES ) )
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
)
92 indice
= get_page_index ( logica
);
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");
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");
133 tabla
->entry
[indice
.tabla_index
]= (pte_t
) make_pte ( fisica
, atributo
);
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");
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
174 for ( i
=0 ; i
< PAGINAS_POR_TABLA
; i
++)
175 if ( tabla
->entry
[i
] )
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;
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) {
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
));