Включение подкачки вызывает PAGE_FAULT сразу после установки флага на cr0 - PullRequest
1 голос
/ 17 января 2020

Я работаю над собственной ОС, это очень весело, но я застрял с пейджингом, я написал простой (очень простой) код нумерации страниц, но когда я включаю нумерацию страниц, возникает ошибка страницы. Некоторые подробности: я использую 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

...