mirror of
https://github.com/tailix/kernel.git
synced 2025-04-14 17:33:13 -04:00
Paging shit
This commit is contained in:
parent
ef1012f3b7
commit
3db7363998
8 changed files with 256 additions and 6 deletions
|
@ -7,9 +7,13 @@ OBJS = start.s.o
|
|||
OBJS += init.c.o
|
||||
OBJS += main.c.o
|
||||
|
||||
OBJS += logger.c.o console.c.o kprintf.c.o
|
||||
OBJS += logger.c.o
|
||||
OBJS += console.c.o
|
||||
OBJS += kprintf.c.o
|
||||
|
||||
OBJS += multiboot.c.o
|
||||
OBJS += memory.c.o
|
||||
OBJS += kmalloc.c.o
|
||||
OBJS += paging.c.o
|
||||
|
||||
OBJS += protected.c.o protected.asm.cpp.o
|
||||
|
|
43
arch/kmalloc.c
Normal file
43
arch/kmalloc.c
Normal file
|
@ -0,0 +1,43 @@
|
|||
#include "kmalloc.h"
|
||||
|
||||
unsigned int kmalloc_placement_addr;
|
||||
|
||||
static unsigned int kmalloc_internal(unsigned int size, unsigned char align, unsigned int *phys);
|
||||
|
||||
unsigned int kmalloc(unsigned int size)
|
||||
{
|
||||
return kmalloc_internal(size, 0, 0);
|
||||
}
|
||||
|
||||
unsigned int kmalloc_a(unsigned int size)
|
||||
{
|
||||
return kmalloc_internal(size, 1, 0);
|
||||
}
|
||||
|
||||
unsigned int kmalloc_p(unsigned int size, unsigned int *phys)
|
||||
{
|
||||
return kmalloc_internal(size, 0, phys);
|
||||
}
|
||||
|
||||
unsigned int kmalloc_ap(unsigned int size, unsigned int *phys)
|
||||
{
|
||||
return kmalloc_internal(size, 1, phys);
|
||||
}
|
||||
|
||||
unsigned int kmalloc_internal(unsigned int size, unsigned char align, unsigned int *phys)
|
||||
{
|
||||
if (align && (kmalloc_placement_addr & 0xFFFFF000)) {
|
||||
kmalloc_placement_addr &= 0xFFFFF000;
|
||||
kmalloc_placement_addr += 0x1000;
|
||||
}
|
||||
|
||||
const unsigned int result = kmalloc_placement_addr;
|
||||
|
||||
if (phys) {
|
||||
*phys = result;
|
||||
}
|
||||
|
||||
kmalloc_placement_addr += size;
|
||||
|
||||
return result;
|
||||
}
|
11
arch/kmalloc.h
Normal file
11
arch/kmalloc.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef KERNELMQ_INCLUDED_KMALLOC
|
||||
#define KERNELMQ_INCLUDED_KMALLOC 1
|
||||
|
||||
extern unsigned int kmalloc_placement_addr;
|
||||
|
||||
unsigned int kmalloc(unsigned int size);
|
||||
unsigned int kmalloc_a(unsigned int size);
|
||||
unsigned int kmalloc_p(unsigned int size, unsigned int *phys);
|
||||
unsigned int kmalloc_ap(unsigned int size, unsigned int *phys);
|
||||
|
||||
#endif
|
|
@ -1,15 +1,16 @@
|
|||
#include "logger.h"
|
||||
#include "protected.h"
|
||||
#include "paging.h"
|
||||
#include "timer.h"
|
||||
|
||||
static void on_timer();
|
||||
|
||||
void main()
|
||||
{
|
||||
logger_info("Kernel initialization started.");
|
||||
|
||||
protected_initialize();
|
||||
|
||||
// paging_initialize();
|
||||
|
||||
timer_register_handler(on_timer);
|
||||
timer_initialize(50);
|
||||
|
||||
|
|
176
arch/paging.c
176
arch/paging.c
|
@ -1,6 +1,15 @@
|
|||
#include "paging.h"
|
||||
|
||||
#include "logger.h"
|
||||
#include "kmalloc.h"
|
||||
#include "util.h"
|
||||
|
||||
#define PAGES_PER_TABLE 1024
|
||||
#define TABLES_PER_DIR 1024
|
||||
|
||||
#define INDEX_FROM_BIT(a) ((a) / (8 * 4))
|
||||
#define OFFSET_FROM_BIT(a) ((a) % (8 * 4))
|
||||
|
||||
struct page {
|
||||
unsigned int present : 1;
|
||||
unsigned int rw : 1;
|
||||
|
@ -20,3 +29,170 @@ struct page_dir {
|
|||
unsigned int tables_phys[TABLES_PER_DIR];
|
||||
unsigned int phys;
|
||||
};
|
||||
|
||||
static struct page_dir *kernel_dir = 0;
|
||||
static struct page_dir *current_dir = 0;
|
||||
|
||||
static unsigned int *frames;
|
||||
static unsigned int nframes;
|
||||
|
||||
static void switch_page_dir(struct page_dir *dir);
|
||||
static struct page *get_page(unsigned int address, unsigned char make, struct page_dir *dir);
|
||||
|
||||
static void alloc_frame(struct page *page, unsigned char is_kernel, unsigned char is_writable);
|
||||
static void free_frame(struct page *page);
|
||||
|
||||
// Set a bit in the frames bitset
|
||||
static void set_frame(unsigned int frame_addr);
|
||||
|
||||
// Clear a bit in the frames bitset
|
||||
static void clear_frame(unsigned int frame_addr);
|
||||
|
||||
// Test if a bit is set.
|
||||
static unsigned int test_frame(unsigned int frame_addr);
|
||||
|
||||
// Find the first free frame.
|
||||
static unsigned int first_frame();
|
||||
|
||||
void paging_initialize()
|
||||
{
|
||||
logger_info("Initialize paging.");
|
||||
|
||||
// The size of physical memory. For the moment we
|
||||
// assume it is 16MB big.
|
||||
unsigned int mem_end_page = 0x1000000;
|
||||
|
||||
nframes = mem_end_page / 0x1000;
|
||||
frames = (unsigned int*)kmalloc(INDEX_FROM_BIT(nframes));
|
||||
memset(frames, 0, INDEX_FROM_BIT(nframes));
|
||||
|
||||
// Let's make a page directory.
|
||||
kernel_dir = (struct page_dir*)kmalloc_a(sizeof(struct page_dir));
|
||||
memset(kernel_dir, 0, sizeof(struct page_dir));
|
||||
current_dir = kernel_dir;
|
||||
|
||||
// We need to identity map (phys addr = virt addr) from
|
||||
// 0x0 to the end of used memory, so we can access this
|
||||
// transparently, as if paging wasn't enabled.
|
||||
// NOTE that we use a while loop here deliberately.
|
||||
// inside the loop body we actually change placement_address
|
||||
// by calling kmalloc(). A while loop causes this to be
|
||||
// computed on-the-fly rather than once at the start.
|
||||
int i = 0;
|
||||
while (i < kmalloc_placement_addr) {
|
||||
// Kernel code is readable but not writeable from userspace.
|
||||
alloc_frame(get_page(i, 1, kernel_dir), 0, 0);
|
||||
i += 0x1000;
|
||||
}
|
||||
|
||||
// Now, enable paging!
|
||||
switch_page_dir(kernel_dir);
|
||||
}
|
||||
|
||||
void switch_page_dir(struct page_dir *dir)
|
||||
{
|
||||
current_dir = dir;
|
||||
asm volatile("mov %0, %%cr3":: "r"(&dir->phys));
|
||||
unsigned int cr0;
|
||||
asm volatile("mov %%cr0, %0": "=r"(cr0));
|
||||
cr0 |= 0x80000000; // Enable paging!
|
||||
asm volatile("mov %0, %%cr0":: "r"(cr0));
|
||||
}
|
||||
|
||||
struct page *get_page(unsigned int address, unsigned char make, struct page_dir *dir)
|
||||
{
|
||||
// Turn the address into an index.
|
||||
address /= 0x1000;
|
||||
|
||||
// Find the page table containing this address.
|
||||
unsigned int table_idx = address / 1024;
|
||||
|
||||
// If this table is already assigned
|
||||
if (dir->tables[table_idx]) {
|
||||
return &dir->tables[table_idx]->pages[address%1024];
|
||||
}
|
||||
|
||||
if (make) {
|
||||
unsigned int tmp;
|
||||
dir->tables[table_idx] = (struct page_table*)kmalloc_ap(sizeof(struct page_table), &tmp);
|
||||
memset(dir->tables[table_idx], 0, 0x1000);
|
||||
dir->tables_phys[table_idx] = tmp | 0x7; // PRESENT, RW, US.
|
||||
return &dir->tables[table_idx]->pages[address%1024];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void alloc_frame(struct page *page, unsigned char is_kernel, unsigned char is_writable)
|
||||
{
|
||||
if (page->frame != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int frame = first_frame();
|
||||
|
||||
if (frame == (unsigned int)-1) {
|
||||
return; // TODO: panic
|
||||
}
|
||||
|
||||
set_frame(frame * 0x1000);
|
||||
|
||||
page->present = 1;
|
||||
page->rw = !!is_writable;
|
||||
page->user = !is_kernel;
|
||||
page->frame = frame;
|
||||
}
|
||||
|
||||
void free_frame(struct page *page)
|
||||
{
|
||||
const unsigned int frame = page->frame;
|
||||
|
||||
if (!frame) {
|
||||
return;
|
||||
}
|
||||
|
||||
page->frame = 0;
|
||||
clear_frame(frame);
|
||||
}
|
||||
|
||||
void set_frame(unsigned int frame_addr)
|
||||
{
|
||||
unsigned int frame = frame_addr / 0x1000;
|
||||
unsigned int idx = INDEX_FROM_BIT(frame);
|
||||
unsigned int off = OFFSET_FROM_BIT(frame);
|
||||
frames[idx] |= 0x1 << off;
|
||||
}
|
||||
|
||||
void clear_frame(unsigned int frame_addr)
|
||||
{
|
||||
unsigned int frame = frame_addr / 0x1000;
|
||||
unsigned int idx = INDEX_FROM_BIT(frame);
|
||||
unsigned int off = OFFSET_FROM_BIT(frame);
|
||||
frames[idx] &= ~(0x1 << off);
|
||||
}
|
||||
|
||||
unsigned int test_frame(unsigned int frame_addr)
|
||||
{
|
||||
unsigned int frame = frame_addr / 0x1000;
|
||||
unsigned int idx = INDEX_FROM_BIT(frame);
|
||||
unsigned int off = OFFSET_FROM_BIT(frame);
|
||||
return frames[idx] & (0x1 << off);
|
||||
}
|
||||
|
||||
unsigned int first_frame()
|
||||
{
|
||||
for (unsigned int i = 0; i < INDEX_FROM_BIT(nframes); ++i) {
|
||||
// nothing free, exit early.
|
||||
if (frames[i] != 0xFFFFFFFF) {
|
||||
// at least one bit is free here.
|
||||
for (unsigned int j = 0; j < 32; ++j) {
|
||||
unsigned int to_test = 0x1 << j;
|
||||
if (!(frames[i] & to_test)) {
|
||||
return i * 4 * 8 + j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
|
6
arch/paging.h
Normal file
6
arch/paging.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef KERNELMQ_INCLUDED_PAGING
|
||||
#define KERNELMQ_INCLUDED_PAGING 1
|
||||
|
||||
void paging_initialize();
|
||||
|
||||
#endif
|
|
@ -5,6 +5,7 @@
|
|||
#include "asm.h"
|
||||
#include "exception.h"
|
||||
#include "hwint.h"
|
||||
#include "util.h"
|
||||
|
||||
struct GdtPointer {
|
||||
unsigned short limit;
|
||||
|
@ -75,9 +76,7 @@ void protected_initialize()
|
|||
|
||||
logger_info("Setup IDT.");
|
||||
|
||||
for (unsigned char *p = (unsigned char*)idt_entries; p < (unsigned char*)&idt_entries[IDT_SIZE]; ++p) {
|
||||
*p = 0;
|
||||
}
|
||||
memset(idt_entries, 0, sizeof(idt_entries));
|
||||
|
||||
idt_set_gate(0, (unsigned int)exception_0, 0x08, 0x8E);
|
||||
idt_set_gate(1, (unsigned int)exception_1, 0x08, 0x8E);
|
||||
|
|
10
arch/util.h
10
arch/util.h
|
@ -1,9 +1,19 @@
|
|||
#ifndef KERNELMQ_INCLUDED_UTIL
|
||||
#define KERNELMQ_INCLUDED_UTIL 1
|
||||
|
||||
static inline void memset(void *buffer, unsigned char value, unsigned int size);
|
||||
static inline unsigned int strlen(const char *s);
|
||||
static inline void itoa(char *buf, int base, int d);
|
||||
|
||||
void memset(void *buffer, unsigned char value, unsigned int size)
|
||||
{
|
||||
const unsigned char *end = buffer + size;
|
||||
|
||||
for (unsigned char *p = buffer; p < end; ++p) {
|
||||
*p = value;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int strlen(const char *const s)
|
||||
{
|
||||
unsigned int result = 0;
|
||||
|
|
Loading…
Add table
Reference in a new issue