Я работаю над собственной ОС, это очень весело, но я застрял с пейджингом, я написал простой (очень простой) код нумерации страниц, но когда я включаю нумерацию страниц, возникает ошибка страницы. Некоторые подробности: я использую C для ядра. Я использую qemu в качестве виртуальной машины. У меня был собственный кросс-компилятор. Я не использую внешние библиотеки. После загрузки и перехода в код ядра я устанавливаю прерывания и переназначаю PI C, это работает и я считаю, что это не проблема, после этого я пытаюсь включить подкачку страниц Вот paging.h
#ifndef PAGING_H
#define PAGING_H
#include "../cpu/types.h"
#include "../cpu/isr.h"
#define PAGE_SIZE 4096
typedef struct page{
u32 present :1;
u32 rw :1;
u32 kernel_space :1;
u32 accessed :1;
u32 dirty :1;
u32 unused :7;
u32 frame :20;
} page_t;
typedef struct page_table{
page_t pages[1024];
} page_table_t;
typedef struct page_directory{
u32 page_tables[1024];
} page_dir_t;
typedef struct page_directory_interface{
page_dir_t dir;
page_table_t* page_tables;
u32 page_dir_ph_address;
} page_dir_interface_t;
void init_paging();
void switch_page_dir(page_dir_t* new_dir);
page_t* get_page(u32 addres, page_dir_t* dir, u8 make);
void page_fault(registers_t regs);
#endif
Я использую структуру page_t из какого-то учебника, потому что я считаю, что это довольно удобно, другие части Я дважды писал самостоятельно, в обоих случаях результаты кода с PageFault. Вот подкачка. c:
#include "./paging.h"
#include "../util/panic.h"
#include "./memory.h"
#include "../drivers/screen.h"
page_dir_t* kernel_dir, cur_dir;
//helper function for convinient printing
void pint(u32 a){
char * tmp;
itoa(a, tmp);
kprint(tmp);
kprint("\n");
}
void init_paging(){
kernel_dir = kmalloc(sizeof(page_dir_t));
memset(kernel_dir, 0, 4096);
pint(sizeof(page_dir_t));
pint(&kernel_dir->page_tables[0]);
pint(kernel_dir);
int i;
for(i=0; i<1024; i++){ //setting up page directories for kernel
// read and write and kernel_mode and not present
kernel_dir->page_tables[i] = (u32)kmalloc(sizeof(page_table_t)) | 0x2;
}
map_page_table(kernel_dir->page_tables[0], 1, 1); //map ram to pages;
kernel_dir->page_tables[0] |= 0x3; //set as present
enable_paging();
}
void map_page_table(page_table_t* p_table, int kernel, int rw){
int i;
page_t tmp_page;
tmp_page.present = 1;
tmp_page.rw = (rw) ? 1 : 0;
tmp_page.kernel_space = (kernel) ? 1: 0;
for(i=0; i<1024; i++){
tmp_page.frame |= kmalloc(PAGE_SIZE);
p_table->pages[i] = tmp_page;
}
}
void enable_paging(){
u32 cr0_temp_value;
__asm__ __volatile__("mov %0, %%cr3":: "r"(&kernel_dir->page_tables));
__asm__ ("mov %%cr0, %0": "=r"(cr0_temp_value));
cr0_temp_value |= 0x80000000;
__asm__ __volatile__("mov %0, %%cr0":: "r"(cr0_temp_value));
}
А вот и память. c:
#include "./memory.h"
#include "../cpu/types.h"
#include "../../cathesimc/def.h"
u32 placement_addr = 0x10000;
void memcpy(char* src, char* dst, unsigned int bytes){
int i=0;
for (i=0; i< bytes; i++){
dst[i] = src[i];
}
}
void memset(u8* dest, u8 val, u32 len){
u8* tmp = (u8*)dest;
for(;len != 0; len--) *tmp++ = val;
}
//@TODO poprawic tego biedackiego malloca
u32 kmalloc_intrnl(size_t size, short int align, u32 *phys_addr){
if(align != 0 && (placement_addr & 0xFFFFF000)){
placement_addr &= 0xFFFFF000;
placement_addr += 0x1000;
}
if(phys_addr) *phys_addr = placement_addr;
u32 ret = placement_addr;
placement_addr += size;
return ret;
}
u32 kmalloc(size_t size){
return kmalloc_intrnl(size, 0, NULL);
}
u32 kmalloc_a(size_t size){
return kmalloc_intrnl(size, 1, NULL);
}
u32 kmalloc_p(size_t size, u32* phys_addr){
return kmalloc_intrnl(size, 0, phys_addr);
}
u32 kmalloc_ap(size_t size, u32* phys_addr){
return kmalloc_intrnl(size, 1, phys_addr);
}
Мое ядро меньше 0x10000, оно имеет около 16 КБ, поэтому 0x10000 - безопасный запуск Отображенное пространство и память с этого адреса однозначно не используются, я настраиваю только одну таблицу страниц, потому что хочу сделать миниатюры подкачки, а затем позаботиться о распределении и освобождении, поэтому моя единственная цель на данный момент - выяснить, какая ошибка у меня есть решения.
============ РЕДАКТИРОВАТЬ ==============
Я провел интенсивное расследование и обнаружил, что mallo c имеет странное поведение, ниже приведены фрагменты кода с объяснением
//as we can se from kmalloc() code above, kmalloc starts with
//placement_addr == 0x10000 when kernel starts
void init_paging(){
kernel_dir = kmalloc(sizeof(page_dir_t)); //page_dir_t has size 4096 and that is first malloc in kernel code
memset(kernel_dir, 0, 4096);
pint(sizeof(page_dir_t));
phex(sizeof(page_dir_t));
pint(&kernel_dir->page_tables[0]);
phex(&kernel_dir->page_tables[0]); //prints 0x10000 as expected
int i;
for(i=0; i<1024; i++){ //setting up page directories for kernel
// read and write and kernel_mode and not present
kernel_dir->page_tables[i] = (u32)kmalloc(sizeof(page_table_t)) | 0x2;
}
phex(kernel_dir->page_tables[0]); //0x11002 as expected
phex(kernel_dir->page_tables[1023]); //0x410002 as expected
kprint("pages\n");
map_page_table(kernel_dir->page_tables[0], 1, 1); //map ram to pages;
kernel_dir->page_tables[0] |= 0x3; //set as present
kprint("lol");
enable_paging();
}
void map_page_table(page_table_t* p_table, int kernel, int rw){
int i;
page_t tmp_page;
tmp_page.present = 1;
tmp_page.rw = (rw) ? 1 : 0;
tmp_page.kernel_space = (kernel) ? 1: 0;
//since now troubles starts this forloop below prints adresses:
// iteration0 0x11000
// iteration1 0x12000
// iteration2 0x13000
// iteration3 0x14000
// iteration4 0x15000
// iteration5 0x16000
// iteration6 0x17000
// iteration7 0x18000
for(i=0; i<8; i++){
tmp_page.frame = kmalloc(PAGE_SIZE);
phex(tmp_page.frame);
p_table->pages[i] = tmp_page;
}
}
Я думаю, что это определенно может быть источником проблем, но я понятия не имею, почему location_addr изменяется, когда я вызываю другую функцию, и почему тогда оно меняется на 0x11000