Я создаю своего рода игрушечную ОС, и я пытаюсь настроить пейджинг. Сначала загрузчик сначала отображает ядро в верхнюю половину, а затем я пытаюсь настроить новый каталог страниц.
У меня есть некоторые структуры, определенные следующим образом:
typedef struct pd_entry pd_entry_t;
struct pd_entry
{
uint32_t present : 1;
uint32_t writable : 1;
uint32_t user : 1;
uint32_t writethru : 1;
uint32_t nocache : 1;
uint32_t accessed : 1;
uint32_t _reserved : 1;
uint32_t size_4mb : 1;
uint32_t global : 1;
uint32_t available : 3;
uint32_t frame : 20;
}__attribute__((packed));
typedef struct pt_entry pt_entry_t;
struct pt_entry
{
uint32_t present : 1;
uint32_t writable : 1;
uint32_t user : 1;
uint32_t writethru : 1;
uint32_t nocache : 1;
uint32_t accessed : 1;
uint32_t dirty : 1;
uint32_t attr_index : 1;
uint32_t global : 1;
uint32_t available : 3;
uint32_t frame : 20;
} __attribute__((packed));
typedef struct page_dir page_dir_t;
struct page_dir
{
pd_entry_t entries[TABLES_PER_DIR];
};
typedef struct page_table page_table_t;
struct page_table
{
pt_entry_t entries[PAGES_PER_TABLE];
};
И я использую этот код для установки записей:
// I store the page directory pointer in the last directory entry
uint32_t map_quick(uint32_t addr)
{
GET_PTE(QUICKMAP_ADDR)->frame = PAGE_ALIGN(addr) >> 12; // QUICKMAP_ADDR is 0xC0000000
paging_flush_tlb_entry(QUICKMAP_ADDR); // asm volatile ("invlpg (%0)" :: "r"(addr));
return QUICKMAP_ADDR;
}
pd_entry_t* get_dir_entry(page_dir_t *dir, uint32_t virt)
{
dir = (page_dir_t *)map_quick((uint32_t)dir);
return &dir->entries[PAGE_DIR_INDEX(virt)];
}
void set_dir_entry(page_dir_t *dir, uint32_t virt, page_table_t *pt)
{
pd_entry_t *pde = get_dir_entry(dir, virt);
pde->present = 1;
pde->writable = 1;
pde->user = 0;
pde->writethru = 0;
pde->nocache = 0;
pde->accessed = 0;
pde->size_4mb = 0;
pde->global = 0;
pde->frame = (uint32_t)pt >> 12;
kprintf("0x%x:0x%x ", (uint32_t)pt >> 12, pde->frame); // Just a 'printf' clone
}
Однако, когда вызывается set_dir_entry
, kprintf
печатает 0xA0:0x0
. Я не могу понять, почему pde->frame
не устанавливается? Я не получаю никаких ошибок или исключений страниц, запись в каталоге всегда равна 0
независимо от того, к чему я ее установил.
EDIT: здесь код для kprintf
:
size_t kprintf(const char *str, ...)
{
if (!str) return 0;
va_list args;
va_start(args, str);
unsigned int i;
for (i = 0; i < strlen(str); i++)
{
if (str[i] == '%')
{
switch (str[i+1])
{
case 'c':
{
char c = va_arg(args, char);
kputc(c);
i++;
break;
}
case 's':
{
char *s = va_arg(args, char*);
kputs(s);
i++;
break;
}
case 'd':
case 'i':
{
int c = va_arg(args, int);
char s[32] = {0};
itoa_s(c, s, 10);
kputs(s);
i++;
break;
}
case 'X':
case 'x':
{
int c = va_arg(args, int);
char s[32] = {0};
itoa_s(c, s, 16);
kputs(s);
i++;
break;
}
}
}
else
{
kputc(str[i]);
}
}
va_end(args);
return (size_t)i;
}
void kputc(unsigned char c)
{
uint16_t attr = color << 8;
if (c == 0x8 && posx)
posx--;
else if (c == 0x9)
posx = (posx + 8) & ~(8-1);
else if (c == '\r')
posx = 0;
else if (c == '\n')
{
posx = 0;
posy++;
}
else if (c >= ' ')
{
uint16_t *loc = videomem + (posy*80 + posx);
*loc = c | attr;
posx++;
}
if (posx >= 80)
{
posx = 0;
posy++;
}
if (posy >= 25)
kscroll();
}
void kputs(const char *str)
{
if (!str) return;
unsigned int i;
for (i = 0; i < strlen(str); i++)
kputc(str[i]);
}
EDIT 2: я не знаю, полезно ли это, и мне не очень нравится просто сбрасывать огромное количество кода для людей, чтобы читать, но это весь код персонального вызова. Все вызовы функций, которые не являются частью этого кода, работают независимо друг от друга.
virtual.h
#ifndef _VIRTUAL_H_
#define _VIRTUAL_H_
#include <x86/paging.h>
#include <stdbool.h>
#define VIRTUAL_TO_PHYSICAL(x) ((uint32_t)(x) - 0xC0001000 + 0x00101000)
#define PHYSICAL_TO_VIRTUAL(x) ((uint32_t)(x) + 0xC0001000 - 0x00101000)
#define KERNEL_CODE_VADDRESS 0xC0001000
#define KERNEL_HEAP_VADDRESS 0xD0000000
void virtual_init();
void virtual_create_dir(page_dir_t **dir);
void virtual_destroy_dir(page_dir_t *dir);
void virtual_set_dir(page_dir_t *dir);
void virtual_map_page(page_dir_t *dir, uint32_t phys, uint32_t virt, bool present);
void virtual_map_kernel(page_dir_t *dir);
#endif
virtual.c
#include <system/memory/physical.h>
#include <x86/idt.h>
#include <utils/kernio.h>
#include <utils/kernpanic.h>
#include <string.h>
#include "virtual.h"
#define QUICKMAP_ADDR 0xC0000000
#define GET_PDE(x) ((pd_entry_t *)(0xFFFFF000 + ((x) >> 22) * 4))
#define GET_PTE(x) ((pt_entry_t *)(0xFFC00000 + ((x) >> 12) * 4))
extern uint32_t __kernel_start, __kernel_end;
page_dir_t *kern_dir;
pd_entry_t* get_dir_entry(page_dir_t *dir, uint32_t virt);
void set_dir_entry(page_dir_t *dir, uint32_t virt, page_table_t *pt);
pt_entry_t* get_table_entry(page_dir_t *dir, uint32_t virt);
void set_table_entry(page_dir_t *dir, uint32_t phys, uint32_t virt, bool present);
uint32_t map_quick(uint32_t addr);
void interrupt page_fault(registers_t *regs);
void virtual_init()
{
int_enable(14, page_fault);
virtual_create_dir(&kern_dir);
uint32_t phys, virt;
for (phys = 0; phys < 0x400000; phys += PAGE_SIZE)
virtual_map_page(kern_dir, phys, phys, true);
phys = VIRTUAL_TO_PHYSICAL(&__kernel_start);
virt = (uint32_t)&__kernel_start;
uint32_t end = VIRTUAL_TO_PHYSICAL(&__kernel_end) + physical_get_bitmap_size();
for (; phys < end; phys += PAGE_SIZE, virt += PAGE_SIZE)
virtual_map_page(kern_dir, phys, virt, true);
virtual_map_page(kern_dir, 0x0, QUICKMAP_ADDR, true);
virtual_set_dir(kern_dir);
}
void virtual_create_dir(page_dir_t **dir)
{
*dir = (page_dir_t *)physical_alloc_block();
page_dir_t *virt_dir = (page_dir_t *)map_quick((uint32_t)*dir);
memset(virt_dir, 0, sizeof(page_dir_t));
pd_entry_t *last_pde = &virt_dir->entries[TABLES_PER_DIR - 1];
last_pde->present = 1;
last_pde->writable = 1;
last_pde->frame = (uint32_t)*dir >> 12;
}
void virtual_destroy_dir(page_dir_t *dir)
{
page_dir_t *virt_dir = (page_dir_t *)map_quick((uint32_t)dir);
unsigned int i, j;
for (i = 1; i < KERNEL_CODE_VADDRESS / (PAGE_SIZE * TABLES_PER_DIR); i++)
{
pd_entry_t *pde = &virt_dir->entries[i];
page_table_t *table = (page_table_t *)(pde->frame << 12);
if (table != NULL && pde->present)
{
page_table_t *virt_table = (page_table_t *)map_quick((uint32_t)table);
for (j = 0; j < PAGES_PER_TABLE; j++)
{
pt_entry_t *pte = &virt_table->entries[j];
uint32_t phys = pte->frame << 12;
if (phys != NULL && pte->present)
physical_free_block((void *)phys);
}
physical_free_block(table);
}
}
physical_free_block(dir);
}
void virtual_set_dir(page_dir_t *dir)
{
paging_load_pdbr((uint32_t)dir);
paging_enable(true);
}
void virtual_map_page(page_dir_t *dir, uint32_t phys, uint32_t virt, bool present)
{
set_table_entry(dir, phys, virt, present);
}
void virtual_map_kernel(page_dir_t *dir)
{
pd_entry_t *pde;
pde = get_dir_entry(kern_dir, 0x0);
set_dir_entry(dir, 0x0, (page_table_t *)(pde->frame << 12));
pde = get_dir_entry(kern_dir, KERNEL_CODE_VADDRESS);
set_dir_entry(dir, KERNEL_CODE_VADDRESS, (page_table_t *)(pde->frame << 12));
}
pd_entry_t* get_dir_entry(page_dir_t *dir, uint32_t virt)
{
dir = (page_dir_t *)map_quick((uint32_t)dir);
pd_entry_t *e = &dir->entries[PAGE_DIR_INDEX(virt)];
return &dir->entries[PAGE_DIR_INDEX(virt)];
}
void set_dir_entry(page_dir_t *dir, uint32_t virt, page_table_t *pt)
{
pd_entry_t *pde = get_dir_entry(dir, virt);
pde->present = 1;
pde->writable = 1;
pde->user = 0;
pde->writethru = 0;
pde->nocache = 0;
pde->accessed = 0;
pde->size_4mb = 0;
pde->global = 0;
pde->frame = (uint32_t)pt >> 12;
}
pt_entry_t* get_table_entry(page_dir_t *dir, uint32_t virt)
{
pd_entry_t *pde = get_dir_entry(dir, virt);
page_table_t *table = (page_table_t *)(pde->frame << 12);
if (table == NULL)
{
table = (page_table_t *)physical_alloc_block();
set_dir_entry(dir, virt, table);
unsigned int i;
for (i = 0; i < PAGES_PER_TABLE; i++)
set_table_entry(dir, 0x0, virt + (i * PAGE_SIZE), false);
}
table = (page_table_t *)map_quick((uint32_t)table);
return (pt_entry_t *)&table->entries[PAGE_TABLE_INDEX(virt)];
}
void set_table_entry(page_dir_t *dir, uint32_t phys, uint32_t virt, bool present)
{
pt_entry_t *pte = get_table_entry(dir, PAGE_ALIGN(virt));
pte->present = present;
pte->writable = 1;
pte->user = 0;
pte->writethru = 0;
pte->nocache = 0;
pte->dirty = 0;
pte->attr_index = 0;
pte->global = 0;
pte->frame = PAGE_ALIGN(phys) >> 12;
}
uint32_t map_quick(uint32_t addr)
{
GET_PTE(QUICKMAP_ADDR)->frame = PAGE_ALIGN(addr) >> 12;
paging_flush_tlb_entry(QUICKMAP_ADDR);
return QUICKMAP_ADDR;
}
void interrupt page_fault(registers_t *regs)
{
uint32_t virt;
asm volatile ("movl %%cr2, %0" : "=r" (virt));
kprintf("\nError accessing address 0x%x", virt);
kpanic("Page Fault");
}