9
include/allocator.h
Normal file
9
include/allocator.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
void initialize_allocator(void *bottom, void *top);
|
||||
|
||||
void *allocate_from_bottom(size_t size);
|
||||
|
||||
void *allocate_from_top(size_t size);
|
||||
8
include/context.h
Normal file
8
include/context.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "pageallocator.h"
|
||||
#include "process.h"
|
||||
|
||||
void *initialize_context(void *task_entry, struct page_stack_t *page_stack);
|
||||
|
||||
void load_context(struct process_state_t *context) __attribute__((noreturn));
|
||||
@@ -1,10 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "pageallocator.h"
|
||||
#include "types/physaddr.h"
|
||||
#include <stdint.h>
|
||||
|
||||
const uint32_t elf_magic_number = 0x464c457f;
|
||||
|
||||
enum elf_endianness_t
|
||||
{
|
||||
ELF_LITTLE_ENDIAN = 1,
|
||||
@@ -107,11 +106,13 @@ struct elf_section_header_t
|
||||
};
|
||||
|
||||
#if defined __i386__
|
||||
static const elf_isa_t HOST_ISA = ELF_ISA_x86;
|
||||
static const enum elf_isa_t HOST_ISA = ELF_ISA_x86;
|
||||
#elif defined __x86_64__
|
||||
static const elf_isa_t HOST_ISA = ELF_ISA_x86_64;
|
||||
static const enum elf_isa_t HOST_ISA = ELF_ISA_x86_64;
|
||||
#elif defined __arm__
|
||||
static const elf_isa_t HOST_ISA = ELF_ISA_ARM;
|
||||
static const enum elf_isa_t HOST_ISA = ELF_ISA_ARM;
|
||||
#elif defined __aarch64__
|
||||
static const elf_isa_t HOST_ISA = ELF_ISA_AARCH64;
|
||||
static const enum elf_isa_t HOST_ISA = ELF_ISA_AARCH64;
|
||||
#endif
|
||||
|
||||
int load_program(struct elf_file_header_t *elf, struct page_stack_t *page_stack);
|
||||
|
||||
@@ -1,18 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include "pageallocator.h"
|
||||
#include "priorityqueue.h"
|
||||
#include "resource.h"
|
||||
#include "module.h"
|
||||
#include "process.h"
|
||||
#include <stddef.h>
|
||||
|
||||
enum syscall_id_t
|
||||
{
|
||||
SYSCALL_YIELD = 1
|
||||
};
|
||||
|
||||
struct kernel_t
|
||||
{
|
||||
struct page_stack_t *page_stack;
|
||||
struct priority_queue_t *priority_queue;
|
||||
struct process_t *active_process;
|
||||
struct resource_table_t *resource_table;
|
||||
};
|
||||
|
||||
extern struct kernel_t kernel;
|
||||
extern struct kernel_t kernel_state;
|
||||
|
||||
int do_syscall(struct kernel_t *kernel, size_t id, size_t arg1, size_t arg2, size_t arg3);
|
||||
size_t do_syscall(struct kernel_t *kernel, enum syscall_id_t id, size_t arg1, size_t arg2, size_t arg3);
|
||||
|
||||
int load_module(struct kernel_t *kernel, struct module_t *module);
|
||||
|
||||
struct process_state_t *next_process(struct kernel_t *kernel, struct process_state_t *prev_state) __attribute__((noreturn));
|
||||
|
||||
void panic(const char *message) __attribute__ ((noreturn));
|
||||
|
||||
@@ -3,6 +3,15 @@
|
||||
#include "pageallocator.h"
|
||||
#include "types/physaddr.h"
|
||||
|
||||
enum page_flag_t
|
||||
{
|
||||
PAGE_RW = 1,
|
||||
PAGE_EXECUTABLE = 1 << 1,
|
||||
PAGE_USERMODE = 1 << 2
|
||||
};
|
||||
|
||||
extern const size_t page_size;
|
||||
|
||||
/**
|
||||
* @brief Create a new top-level page table and map the kernel in it.
|
||||
*
|
||||
@@ -19,6 +28,15 @@ physaddr_t create_address_space(struct page_stack_t *page_stack);
|
||||
*/
|
||||
void load_address_space(physaddr_t table);
|
||||
|
||||
/**
|
||||
* @brief Returns the physical address of the top-level page table currently in
|
||||
* use.
|
||||
*
|
||||
* @param table
|
||||
* @return physaddr_t
|
||||
*/
|
||||
physaddr_t current_address_space();
|
||||
|
||||
/**
|
||||
* @brief Maps a single page with the specified flags.
|
||||
*
|
||||
@@ -36,4 +54,4 @@ int map_page(struct page_stack_t *page_stack, void *page, physaddr_t frame, int
|
||||
* @param page
|
||||
* @return physaddr_t
|
||||
*/
|
||||
physaddr_t unmap_page(void *page);
|
||||
physaddr_t unmap_page(void *page);
|
||||
|
||||
@@ -72,4 +72,4 @@ size_t free_page_count(struct page_stack_t *stack);
|
||||
* @param stack
|
||||
* @param map
|
||||
*/
|
||||
int initialize_page_stack(struct page_stack_t *stack, struct memory_map_t *map, size_t page_size);
|
||||
int initialize_page_stack(struct page_stack_t *stack, struct memory_map_t *map);
|
||||
|
||||
@@ -43,7 +43,7 @@ struct process_t *extract_min(struct priority_queue_t *queue);
|
||||
* @param process
|
||||
* @return int
|
||||
*/
|
||||
int insert(struct priority_queue_t *queue, struct process_t *process);
|
||||
int queue_insert(struct priority_queue_t *queue, struct process_t *process);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
@@ -52,4 +52,4 @@ int insert(struct priority_queue_t *queue, struct process_t *process);
|
||||
* @param process
|
||||
* @return int
|
||||
*/
|
||||
int remove(struct priority_queue_t *queue, struct process_t *process);
|
||||
int queue_remove(struct priority_queue_t *queue, struct process_t *process);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "types/physaddr.h"
|
||||
#include <stddef.h>
|
||||
|
||||
struct process_state_t;
|
||||
@@ -7,6 +8,6 @@ struct process_state_t;
|
||||
struct process_t
|
||||
{
|
||||
size_t priority;
|
||||
|
||||
struct process_state_t *state;
|
||||
physaddr_t page_table;
|
||||
};
|
||||
27
include/resource.h
Normal file
27
include/resource.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "process.h"
|
||||
#include <stddef.h>
|
||||
|
||||
enum resource_type_t
|
||||
{
|
||||
RESOURCE_UNAVAILABLE = 0,
|
||||
RESOURCE_PROCESS
|
||||
};
|
||||
|
||||
struct resource_t
|
||||
{
|
||||
size_t type;
|
||||
union
|
||||
{
|
||||
struct process_t process;
|
||||
};
|
||||
};
|
||||
|
||||
struct resource_table_t
|
||||
{
|
||||
struct resource_t *array;
|
||||
size_t capacity;
|
||||
};
|
||||
|
||||
int find_resource_slot(struct resource_table_t *table);
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
int initialize_screen();
|
||||
|
||||
int putchar(int c);
|
||||
|
||||
int puts(const char *str);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
noinst_PROGRAMS = quark-kernel
|
||||
quark_kernel_SOURCES = kernel.c memorymap.c pageallocator.c priorityqueue.c stdio.c string.c
|
||||
quark_kernel_SOURCES = kernel.c memorymap.c pageallocator.c priorityqueue.c stdio.c string.c elf.c resource.c allocator.c
|
||||
quark_kernel_LDADD = -lgcc
|
||||
quark_kernel_CFLAGS = -I$(top_srcdir)/include -ffreestanding -mgeneral-regs-only -O0 -Wall -ggdb
|
||||
quark_kernel_LDFLAGS = -nostdlib
|
||||
@@ -12,6 +12,7 @@ quark_kernel_SOURCES += x86/mmgr.c \
|
||||
x86/apic.c \
|
||||
x86/isr.c \
|
||||
x86/msr.c \
|
||||
x86/context.c \
|
||||
x86/quark_x86.c \
|
||||
x86/entry.S
|
||||
quark_kernel_LDFLAGS += -T x86/linker.ld
|
||||
|
||||
34
src/allocator.c
Normal file
34
src/allocator.c
Normal file
@@ -0,0 +1,34 @@
|
||||
#include "allocator.h"
|
||||
|
||||
struct linear_allocator_t
|
||||
{
|
||||
void *bottom;
|
||||
void *top;
|
||||
} allocator;
|
||||
|
||||
void initialize_allocator(void *bottom, void *top)
|
||||
{
|
||||
allocator.bottom = bottom;
|
||||
allocator.top = top;
|
||||
}
|
||||
|
||||
void *allocate_from_bottom(size_t size)
|
||||
{
|
||||
if((size_t)allocator.bottom + size <= (size_t)allocator.top)
|
||||
{
|
||||
void *ptr = allocator.bottom;
|
||||
allocator.bottom += size;
|
||||
return ptr;
|
||||
}
|
||||
return (void*)NULL;
|
||||
}
|
||||
|
||||
void *allocate_from_top(size_t size)
|
||||
{
|
||||
if((size_t)allocator.top - size >= (size_t)allocator.bottom)
|
||||
{
|
||||
allocator.top -= size;
|
||||
return allocator.top;
|
||||
}
|
||||
return (void*)NULL;
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
#include "allocator.hpp"
|
||||
|
||||
#define AVAIL 0
|
||||
#define UNAVAIL -1
|
||||
|
||||
inline size_t ilog2(size_t n)
|
||||
{
|
||||
size_t m = n;
|
||||
size_t count = 0;
|
||||
bool isPowerOfTwo = true;
|
||||
while(m)
|
||||
{
|
||||
if((m & 1) == 1 && m > 1)
|
||||
{
|
||||
isPowerOfTwo = false;
|
||||
}
|
||||
count++;
|
||||
m >>= 1;
|
||||
}
|
||||
return count - (isPowerOfTwo ? 1 : 0);
|
||||
}
|
||||
|
||||
kernelns::Allocator::Allocator()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
kernelns::Allocator::Allocator(void* base, size_t heapSize, size_t blockSize)
|
||||
{
|
||||
this->base = (char*) base;
|
||||
this->heapSize = heapSize;
|
||||
this->blockSize = blockSize;
|
||||
this->treeHeight = ilog2(heapSize / blockSize);
|
||||
size_t headerSize = (heapSize / blockSize) << 1;
|
||||
for(size_t i = 1; i < (heapSize / blockSize) * 2; i++)
|
||||
this->base[i] = UNAVAIL;
|
||||
for(size_t i = 0; i < heapSize / blockSize; i++)
|
||||
{
|
||||
if(blockSize * i >= headerSize)
|
||||
{
|
||||
size_t index = i + (1 << treeHeight);
|
||||
this->base[index] = AVAIL;
|
||||
for(; index > 1 && this->base[index ^ 1] == 0; index >>= 1)
|
||||
{
|
||||
this->base[index] = UNAVAIL;
|
||||
this->base[index ^ 1] = UNAVAIL;
|
||||
this->base[index >> 1] = AVAIL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->base[i + (1 << treeHeight)] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* kernelns::Allocator::allocate(size_t size)
|
||||
{
|
||||
size += blockSize - 1;
|
||||
size -= size % blockSize;
|
||||
size_t height = ilog2(size / blockSize);
|
||||
size_t index = findFreeBlock(height);
|
||||
if(index)
|
||||
{
|
||||
base[index] = height + 1;
|
||||
return (void*) ((size_t) base + (blockSize << height) * (index - (1 << (treeHeight - height))));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void kernelns::Allocator::free(void* location)
|
||||
{
|
||||
size_t offset = (size_t) location - (size_t) base;
|
||||
size_t index = (offset / blockSize) + (1 << treeHeight);
|
||||
for(; index > 0 && base[index] == UNAVAIL; index >>= 1);
|
||||
base[index] = AVAIL;
|
||||
for(; index > 1 && base[index ^ 1] == AVAIL; index >>= 1)
|
||||
{
|
||||
base[index] = UNAVAIL;
|
||||
base[index ^ 1] = UNAVAIL;
|
||||
base[index >> 1] = AVAIL;
|
||||
}
|
||||
}
|
||||
|
||||
size_t kernelns::Allocator::findFreeBlock(size_t height)
|
||||
{
|
||||
if(height > treeHeight)
|
||||
return 0;
|
||||
for(size_t index = 1 << (treeHeight - height); index < 1 << (treeHeight - height + 1); index++)
|
||||
{
|
||||
if(base[index] == AVAIL)
|
||||
return index;
|
||||
}
|
||||
size_t index = findFreeBlock(height + 1);
|
||||
if(index)
|
||||
{
|
||||
base[index] = UNAVAIL;
|
||||
base[index << 1] = AVAIL;
|
||||
base[(index << 1) ^ 1] = AVAIL;
|
||||
}
|
||||
return index << 1;
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
#ifndef ALLOCATOR_H
|
||||
#define ALLOCATOR_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace kernelns
|
||||
{
|
||||
|
||||
class Allocator
|
||||
{
|
||||
public:
|
||||
|
||||
Allocator();
|
||||
|
||||
/**
|
||||
* @param base A pointer to the start of the heap.
|
||||
* @param heapSize The size of the heap, in bytes. Must be a power of two.
|
||||
* @param blockSize The smallest unit of allocation, in bytes. Must be a power of two less than or equal to heapSize.
|
||||
*/
|
||||
Allocator(void* base, size_t heapSize, size_t blockSize);
|
||||
|
||||
void* allocate(size_t size);
|
||||
|
||||
void free(void* location);
|
||||
|
||||
private:
|
||||
|
||||
size_t findFreeBlock(size_t height);
|
||||
|
||||
char* base;
|
||||
|
||||
size_t heapSize;
|
||||
|
||||
size_t blockSize;
|
||||
|
||||
size_t treeHeight;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
40
src/elf.c
Normal file
40
src/elf.c
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "elf.h"
|
||||
#include "pageallocator.h"
|
||||
#include "mmgr.h"
|
||||
#include "string.h"
|
||||
#include "types/status.h"
|
||||
|
||||
const uint32_t elf_magic_number = 0x464c457f;
|
||||
|
||||
int load_program(struct elf_file_header_t *elf, struct page_stack_t *page_stack)
|
||||
{
|
||||
struct elf_program_header_t *program_header = (struct elf_program_header_t*)((void*)elf + elf->phoffset);
|
||||
unsigned int count = elf->phcount;
|
||||
while(count > 0)
|
||||
{
|
||||
if(program_header->type == ELF_LOAD)
|
||||
{
|
||||
void *d = program_header->vaddr, *s = (void*)elf + program_header->offset;
|
||||
for(size_t n = 0; n < program_header->memsize; n += page_size)
|
||||
{
|
||||
physaddr_t page = reserve_page(page_stack);
|
||||
if(page == S_OUT_OF_MEMORY)
|
||||
{
|
||||
return S_OUT_OF_MEMORY;
|
||||
}
|
||||
int status = map_page(page_stack, d, page, PAGE_RW | PAGE_USERMODE | PAGE_EXECUTABLE);
|
||||
switch(status)
|
||||
{
|
||||
case S_OUT_OF_MEMORY:
|
||||
return status;
|
||||
case S_OUT_OF_BOUNDS:
|
||||
return status;
|
||||
case S_OK:
|
||||
memcpy(d, s, page_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
count--;
|
||||
program_header = (struct elf_program_header_t*)((void*)program_header + elf->phsize);
|
||||
}
|
||||
}
|
||||
77
src/kernel.c
77
src/kernel.c
@@ -1,11 +1,84 @@
|
||||
#include "kernel.h"
|
||||
#include "mmgr.h"
|
||||
#include "stdio.h"
|
||||
#include "elf.h"
|
||||
#include "context.h"
|
||||
#include "types/status.h"
|
||||
|
||||
int do_syscall(struct kernel_t *kernel, size_t id, size_t arg1, size_t arg2, size_t arg3)
|
||||
size_t do_syscall(struct kernel_t *kernel, enum syscall_id_t id, size_t arg1, size_t arg2, size_t arg3)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int load_module(struct kernel_t *kernel, struct module_t *module)
|
||||
{
|
||||
physaddr_t module_address_space = create_address_space(kernel->page_stack);
|
||||
load_address_space(module_address_space);
|
||||
void *const load_base = (void*)0x80000000;
|
||||
size_t load_offset = 0;
|
||||
for(physaddr_t p = module->start & ~(page_size - 1); p < module->end; p += page_size)
|
||||
{
|
||||
int status = map_page(kernel->page_stack, load_base + load_offset, p, PAGE_RW);
|
||||
switch(status)
|
||||
{
|
||||
case S_OUT_OF_MEMORY:
|
||||
panic("ran out of memory while mapping module");
|
||||
case S_OUT_OF_BOUNDS:
|
||||
panic("got out-of-bounds error while mapping module");
|
||||
}
|
||||
load_offset += page_size;
|
||||
}
|
||||
int status = load_program(load_base, kernel->page_stack);
|
||||
switch(status)
|
||||
{
|
||||
case S_OUT_OF_MEMORY:
|
||||
panic("ran out of memory while reading ELF file");
|
||||
case S_OUT_OF_BOUNDS:
|
||||
panic("got out-of-bounds error while reading ELF file");
|
||||
}
|
||||
void *module_entry = ((struct elf_file_header_t*)load_base)->entry;
|
||||
void *module_context = initialize_context(module_entry, kernel->page_stack);
|
||||
printf("loaded module with entry point %08x\n", (unsigned int)module_entry);
|
||||
load_offset = 0;
|
||||
for(physaddr_t p = module->start & ~(page_size - 1); p < module->end; p += page_size)
|
||||
{
|
||||
int status = unmap_page(load_base + load_offset);
|
||||
switch(status)
|
||||
{
|
||||
case S_OUT_OF_MEMORY:
|
||||
panic("ran out of memory while unmapping module");
|
||||
case S_OUT_OF_BOUNDS:
|
||||
panic("got out-of-bounds error while unmapping module");
|
||||
}
|
||||
load_offset += page_size;
|
||||
}
|
||||
int index = find_resource_slot(kernel);
|
||||
if(index < 0)
|
||||
{
|
||||
panic("no space left in resource table for module");
|
||||
}
|
||||
kernel->resource_table->array[index].type = RESOURCE_PROCESS;
|
||||
kernel->resource_table->array[index].process.priority = 1;
|
||||
kernel->resource_table->array[index].process.state = module_context;
|
||||
kernel->resource_table->array[index].process.page_table = current_address_space();
|
||||
queue_insert(kernel->priority_queue, &kernel->resource_table->array[index].process);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}
|
||||
struct process_state_t *next_process(struct kernel_t *kernel, struct process_state_t *prev_state)
|
||||
{
|
||||
if(prev_state != NULL)
|
||||
{
|
||||
kernel->active_process->state = prev_state;
|
||||
queue_insert(kernel->priority_queue, kernel->active_process);
|
||||
}
|
||||
kernel->active_process = extract_min(kernel->priority_queue);
|
||||
load_context(kernel->active_process->state);
|
||||
}
|
||||
|
||||
void panic(const char *message)
|
||||
{
|
||||
printf("panic: %s", message);
|
||||
asm("cli");
|
||||
while(1) asm("hlt");
|
||||
}
|
||||
|
||||
@@ -66,36 +66,36 @@ int trim_map(struct memory_map_t *map, int index)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
struct memory_region_t left = map->array[index];
|
||||
struct memory_region_t right = map->array[index + 1];
|
||||
if(region_overlaps(&left, &right))
|
||||
struct memory_region_t *left = &map->array[index];
|
||||
struct memory_region_t *right = &map->array[index + 1];
|
||||
if(region_overlaps(left, right))
|
||||
{
|
||||
if(left.type == right.type)
|
||||
if(left->type == right->type)
|
||||
{
|
||||
left.size = (right.location + right.size > left.location + left.size ? right.location + right.size : left.location + left.size) - left.location;
|
||||
left->size = (right->location + right->size > left->location + left->size ? right->location + right->size : left->location + left->size) - left->location;
|
||||
remove_map_entry(map, index + 1);
|
||||
return index;
|
||||
}
|
||||
else if(left.type < right.type)
|
||||
else if(left->type < right->type)
|
||||
{
|
||||
if(region_contains(&right, &left))
|
||||
if(region_contains(right, left))
|
||||
{
|
||||
remove_map_entry(map, index);
|
||||
return index;
|
||||
}
|
||||
else if(left.location + left.size <= right.location + right.size)
|
||||
else if(left->location + left->size <= right->location + right->size)
|
||||
{
|
||||
left.size = (right.location > left.location) ? right.location - left.location : 0;
|
||||
left->size = (right->location > left->location) ? right->location - left->location : 0;
|
||||
return index + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct memory_region_t new_right = {
|
||||
.location = right.location + right.size,
|
||||
.size = (left.location + left.size) - (right.location + right.size),
|
||||
.type = left.type};
|
||||
left.size = (right.location > left.location) ? right.location - left.location : 0;
|
||||
if(left.size == 0)
|
||||
.location = right->location + right->size,
|
||||
.size = (left->location + left->size) - (right->location + right->size),
|
||||
.type = left->type};
|
||||
left->size = (right->location > left->location) ? right->location - left->location : 0;
|
||||
if(left->size == 0)
|
||||
remove_map_entry(map, index);
|
||||
insert_map_entry(map, new_right.location, new_right.size, new_right.type);
|
||||
return index + 2;
|
||||
@@ -103,22 +103,22 @@ int trim_map(struct memory_map_t *map, int index)
|
||||
}
|
||||
else
|
||||
{
|
||||
if(region_contains(&left, &right))
|
||||
if(region_contains(left, right))
|
||||
{
|
||||
remove_map_entry(map, index + 1);
|
||||
return index;
|
||||
}
|
||||
else
|
||||
{
|
||||
right.size = (right.location + right.size) - (left.location + left.size);
|
||||
right.location = left.location + left.size;
|
||||
right->size = (right->location + right->size) - (left->location + left->size);
|
||||
right->location = left->location + left->size;
|
||||
return index + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if((left.location + left.size == right.location) && left.type == right.type)
|
||||
else if((left->location + left->size == right->location) && left->type == right->type)
|
||||
{
|
||||
left.size = right.location + right.size - left.location;
|
||||
left->size = right->location + right->size - left->location;
|
||||
remove_map_entry(map, index + 1);
|
||||
return index;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#include "pageallocator.h"
|
||||
#include "mmgr.h"
|
||||
#include "allocator.h"
|
||||
#include "types/status.h"
|
||||
|
||||
physaddr_t reserve_page(struct page_stack_t *stack)
|
||||
@@ -15,12 +17,25 @@ physaddr_t reserve_page(struct page_stack_t *stack)
|
||||
|
||||
int free_page(struct page_stack_t *stack, physaddr_t location)
|
||||
{
|
||||
void *new_limit;
|
||||
if(stack->stack_pointer > stack->limit_pointer)
|
||||
{
|
||||
stack->stack_pointer--;
|
||||
*stack->stack_pointer = location;
|
||||
return S_OK;
|
||||
}
|
||||
else if((new_limit = allocate_from_top(page_size)) != NULL)
|
||||
{
|
||||
switch(map_page(stack, new_limit, location, PAGE_RW))
|
||||
{
|
||||
case S_OUT_OF_MEMORY:
|
||||
return S_OUT_OF_MEMORY;
|
||||
case S_OUT_OF_BOUNDS:
|
||||
return S_OUT_OF_BOUNDS;
|
||||
case S_OK:
|
||||
stack->limit_pointer = new_limit;
|
||||
}
|
||||
}
|
||||
return S_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
@@ -29,7 +44,7 @@ size_t free_page_count(struct page_stack_t *stack)
|
||||
return stack->base_pointer - stack->stack_pointer;
|
||||
}
|
||||
|
||||
int initialize_page_stack(struct page_stack_t *stack, struct memory_map_t *map, size_t page_size)
|
||||
int initialize_page_stack(struct page_stack_t *stack, struct memory_map_t *map)
|
||||
{
|
||||
stack->total_pages = 0;
|
||||
for(int i = 0; i < map->size; i++)
|
||||
|
||||
@@ -36,7 +36,7 @@ struct process_t *extract_min(struct priority_queue_t *queue)
|
||||
return p;
|
||||
}
|
||||
|
||||
int insert(struct priority_queue_t *queue, struct process_t *process)
|
||||
int queue_insert(struct priority_queue_t *queue, struct process_t *process)
|
||||
{
|
||||
if(queue->size == queue->capacity)
|
||||
return S_OUT_OF_MEMORY;
|
||||
@@ -51,7 +51,7 @@ int insert(struct priority_queue_t *queue, struct process_t *process)
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
int remove(struct priority_queue_t *queue, struct process_t *process)
|
||||
int queue_remove(struct priority_queue_t *queue, struct process_t *process)
|
||||
{
|
||||
for(size_t i = 0; i < queue->size; i++)
|
||||
{
|
||||
|
||||
13
src/resource.c
Normal file
13
src/resource.c
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "resource.h"
|
||||
|
||||
int find_resource_slot(struct resource_table_t *table)
|
||||
{
|
||||
for(int i = 0; i < table->capacity; i++)
|
||||
{
|
||||
if(table->array[i].type == RESOURCE_UNAVAILABLE)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -1,8 +1,43 @@
|
||||
#include "mmgr.h"
|
||||
#include "allocator.h"
|
||||
#include "apic.h"
|
||||
#include "msr.h"
|
||||
#include "stdio.h"
|
||||
#include <stddef.h>
|
||||
|
||||
void apic_enable()
|
||||
extern int _kernel_end;
|
||||
|
||||
struct apic_registers_t volatile *apic_registers;
|
||||
|
||||
void apic_enable(struct page_stact_t *page_stack)
|
||||
{
|
||||
|
||||
// Remap and mask 8259 PIC
|
||||
asm volatile(
|
||||
"mov $0x11, %%al;"
|
||||
"outb %%al, $0x20;"
|
||||
"outb %%al, $0xA0;"
|
||||
"mov $0x20, %%al;"
|
||||
"outb %%al, $0x21;"
|
||||
"mov $0x28, %%al;"
|
||||
"outb %%al, $0xA1;"
|
||||
"mov $4, %%al;"
|
||||
"outb %%al, $0x21;"
|
||||
"mov $2, %%al;"
|
||||
"outb %%al, $0xA1;"
|
||||
"mov $0x01, %%al;"
|
||||
"outb %%al, $0x21;"
|
||||
"outb %%al, $0xA1;"
|
||||
"mov $0xFF, %%al;"
|
||||
"outb %%al, $0xA1;"
|
||||
"outb %%al, $0x21;"
|
||||
::: "al"
|
||||
);
|
||||
struct msr_apic_base_t msr;
|
||||
read_msr(MSR_APIC_BASE, (uint64_t*)&msr);
|
||||
apic_registers = (struct apic_registers_t*)allocate_from_bottom(page_size);
|
||||
map_page(page_stack, apic_registers, msr.apic_base << 12, PAGE_RW);
|
||||
printf("MSR_APIC_BASE: %016x\n", *((uint32_t*)&msr));
|
||||
apic_registers->spurious_iv.value = apic_registers->spurious_iv.value | 0x100;
|
||||
}
|
||||
|
||||
void apic_eoi()
|
||||
@@ -32,4 +67,4 @@ void apic_send_ipi(
|
||||
uint32_t *icr_addr = (uint32_t*)&apic_registers->interrput_command;
|
||||
icr_addr[4] = value_addr[4];
|
||||
icr_addr[0] = value_addr[0];
|
||||
}
|
||||
}
|
||||
|
||||
32
src/x86/context.c
Normal file
32
src/x86/context.c
Normal file
@@ -0,0 +1,32 @@
|
||||
#include "context.h"
|
||||
#include "pageallocator.h"
|
||||
#include "mmgr.h"
|
||||
|
||||
void *initialize_context(void *task_entry, struct page_stack_t *page_stack)
|
||||
{
|
||||
physaddr_t stack0 = reserve_page(page_stack);
|
||||
map_page(page_stack, (void*)0xFF7FF000, stack0, PAGE_RW);
|
||||
map_page(page_stack, (void*)0xFF7FD000, stack0, PAGE_RW | PAGE_USERMODE);
|
||||
unmap_page((void*)0xFF7FE000);
|
||||
unmap_page((void*)0xFF7FC000);
|
||||
uint32_t flags;
|
||||
uint32_t *stack = (uint32_t*)((void*)stack0 - 20);
|
||||
asm("pushf; "
|
||||
"mov (%%esp), %0; "
|
||||
"popf; "
|
||||
: "=r"(flags));
|
||||
stack[0] = (uint32_t)task_entry;
|
||||
stack[1] = 27;
|
||||
stack[2] = flags;
|
||||
stack[3] = 0xFF7FE000;
|
||||
stack[4] = 35;
|
||||
return (void*)stack;
|
||||
}
|
||||
|
||||
void load_context(struct process_state_t *context)
|
||||
{
|
||||
asm("mov %0, %%esp; "
|
||||
"popal; "
|
||||
"iret; "
|
||||
:: "r"(context));
|
||||
}
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
.set tagEntryType, 3
|
||||
.set tagEntrySize, 12
|
||||
.set tagEntryAddress, _start - (0xFF900000 - 0x100000)
|
||||
.set tagEntryAddress, _start - (0xFF800000 - 0x100000)
|
||||
|
||||
.set tagModuleAlignType, 6
|
||||
.set tagModuleAlignSize, 8
|
||||
@@ -93,23 +93,6 @@ _multibootInfoTagEnd:
|
||||
.long 8
|
||||
|
||||
_multibootHeaderEnd:
|
||||
|
||||
.section .rodata
|
||||
|
||||
gdt:
|
||||
.long 0, 0
|
||||
.short 0xFFFF
|
||||
.short 0x0000
|
||||
.short 0x9A00
|
||||
.short 0x00CF
|
||||
.short 0xFFFF
|
||||
.short 0x0000
|
||||
.short 0x9200
|
||||
.short 0x00CF
|
||||
|
||||
gdt_info:
|
||||
.short 23
|
||||
.long gdt
|
||||
|
||||
.section .bss
|
||||
|
||||
@@ -125,19 +108,6 @@ _tempIdentityMap:
|
||||
.skip 4096
|
||||
_tempPgTable:
|
||||
.skip 4096
|
||||
|
||||
_bootCmdLine:
|
||||
.skip 64
|
||||
|
||||
.align 64
|
||||
.global system_info
|
||||
system_info:
|
||||
.skip 16
|
||||
|
||||
.align 64
|
||||
.global memory_map
|
||||
memory_map:
|
||||
.skip 16 * 16
|
||||
|
||||
.section .text
|
||||
.global _start
|
||||
@@ -169,19 +139,26 @@ _start:
|
||||
sub $BASE_DIFF, %eax
|
||||
push %eax
|
||||
|
||||
# Push ending physical address to map
|
||||
mov (%ebx), %eax
|
||||
add %ebx, %eax
|
||||
push %eax
|
||||
|
||||
# Push starting physical address to map
|
||||
mov $PHYSICAL_BASE, %eax
|
||||
push %eax
|
||||
|
||||
# Load physical address of startPaging()
|
||||
mov $startPaging, %eax
|
||||
mov $start_paging, %eax
|
||||
sub $BASE_DIFF, %eax
|
||||
|
||||
# Initialize paging
|
||||
call *%eax
|
||||
|
||||
|
||||
# Jump into mapped kernel binary
|
||||
lea 1f, %eax
|
||||
jmp *%eax
|
||||
1:
|
||||
# Delete PDE corresponding to identity map. We shouldn't need it anymore.
|
||||
movl $0, (_tempIdentityMap)
|
||||
|
||||
# Flush TLB
|
||||
mov %cr3, %eax
|
||||
@@ -190,22 +167,9 @@ _start:
|
||||
# Initialize stack in virtual memory
|
||||
mov $stackTop, %esp
|
||||
|
||||
# Load GPT
|
||||
lgdt gdt_info
|
||||
|
||||
# Load segment registers
|
||||
jmp $8, $.ldcs
|
||||
.ldcs:
|
||||
mov $16, %ax
|
||||
mov %ax, %ds
|
||||
mov %ax, %es
|
||||
mov %ax, %gs
|
||||
mov %ax, %fs
|
||||
mov %ax, %ss
|
||||
|
||||
# Change EBX to point to the virtual address of the multiboot info
|
||||
# If the new pointer is out-of-bounds, error
|
||||
add $0xFF800000, %ebx
|
||||
add $0xFF700000, %ebx
|
||||
cmp $0xFF800000, %ebx
|
||||
jl .err
|
||||
cmp $0xFFC00000, %ebx
|
||||
|
||||
@@ -1,14 +1,85 @@
|
||||
#include "interrupts.h"
|
||||
#include "isr.h"
|
||||
#include "string.h"
|
||||
#include <stddef.h>
|
||||
|
||||
struct idt_info_t
|
||||
#define idt_size 256
|
||||
#define gdt_size 6
|
||||
|
||||
enum segment_type_t
|
||||
{
|
||||
SEGMENT_KERNEL_CODE,
|
||||
SEGMENT_KERNEL_DATA,
|
||||
SEGMENT_USER_CODE,
|
||||
SEGMENT_USER_DATA,
|
||||
SEGMENT_TSS
|
||||
};
|
||||
|
||||
struct gdt_entry_t
|
||||
{
|
||||
unsigned int limit_low : 16;
|
||||
unsigned int base_low : 24;
|
||||
unsigned int accessed : 1;
|
||||
unsigned int read_write : 1;
|
||||
unsigned int conforming_expand_down : 1;
|
||||
unsigned int code : 1;
|
||||
unsigned int code_data_segment : 1;
|
||||
unsigned int dpl : 2;
|
||||
unsigned int present : 1;
|
||||
unsigned int limit_high : 4;
|
||||
unsigned int available : 1;
|
||||
unsigned int long_mode : 1;
|
||||
unsigned int big : 1;
|
||||
unsigned int gran : 1;
|
||||
unsigned int base_high : 8;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct tss_t
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
struct interrupt_descriptor_t
|
||||
{
|
||||
uint16_t offset_1;
|
||||
uint16_t selector;
|
||||
uint16_t zero : 8;
|
||||
uint16_t type : 4;
|
||||
uint16_t storage : 1;
|
||||
uint16_t dpl : 2;
|
||||
uint16_t present : 1;
|
||||
uint16_t offset_2;
|
||||
};
|
||||
|
||||
struct descriptor_table_info_t
|
||||
{
|
||||
uint16_t size;
|
||||
void *location;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
void lidt(struct interrupt_descriptor_t *idt)
|
||||
struct tss_t tss;
|
||||
|
||||
void load_gdt(struct gdt_entry_t *gdt)
|
||||
{
|
||||
struct idt_info_t idt_info;
|
||||
struct descriptor_table_info_t gdt_info;
|
||||
gdt_info.size = sizeof(struct gdt_entry_t) * 6 - 1;
|
||||
gdt_info.location = (void *)gdt;
|
||||
asm("lgdt (%0);"
|
||||
"jmp $8, $.ldcs;"
|
||||
".ldcs:;"
|
||||
"mov $16, %%ax;"
|
||||
"mov %%ax, %%ds;"
|
||||
"mov %%ax, %%es;"
|
||||
"mov %%ax, %%gs;"
|
||||
"mov %%ax, %%fs;"
|
||||
"mov %%ax, %%ss;"
|
||||
:
|
||||
: "r"(&gdt_info));
|
||||
}
|
||||
|
||||
void load_idt(struct interrupt_descriptor_t *idt)
|
||||
{
|
||||
struct descriptor_table_info_t idt_info;
|
||||
idt_info.size = sizeof(struct interrupt_descriptor_t) * 256 - 1;
|
||||
idt_info.location = (void *)idt;
|
||||
asm("lidt (%0)"
|
||||
@@ -27,3 +98,104 @@ void create_interrupt_descriptor(struct interrupt_descriptor_t *descriptor, void
|
||||
descriptor->dpl = privilage;
|
||||
descriptor->present = 1;
|
||||
}
|
||||
|
||||
void create_segment_descriptor(struct gdt_entry_t *descriptor, size_t base, size_t limit, enum segment_type_t type)
|
||||
{
|
||||
descriptor->limit_low = limit;
|
||||
descriptor->limit_high = (limit & (0xf << 16)) >> 16;
|
||||
descriptor->base_low = base;
|
||||
descriptor->base_high = (base & (0xff << 24)) >> 24;
|
||||
descriptor->present = 1;
|
||||
switch(type)
|
||||
{
|
||||
case SEGMENT_KERNEL_CODE:
|
||||
descriptor->accessed = 0;
|
||||
descriptor->read_write = 1;
|
||||
descriptor->conforming_expand_down = 0;
|
||||
descriptor->code = 1;
|
||||
descriptor->code_data_segment = 1;
|
||||
descriptor->dpl = 0;
|
||||
descriptor->available = 0;
|
||||
descriptor->long_mode = 0;
|
||||
descriptor->big = 1;
|
||||
descriptor->gran = 1;
|
||||
break;
|
||||
case SEGMENT_KERNEL_DATA:
|
||||
descriptor->accessed = 0;
|
||||
descriptor->read_write = 1;
|
||||
descriptor->conforming_expand_down = 0;
|
||||
descriptor->code = 0;
|
||||
descriptor->code_data_segment = 1;
|
||||
descriptor->dpl = 0;
|
||||
descriptor->available = 0;
|
||||
descriptor->long_mode = 0;
|
||||
descriptor->big = 1;
|
||||
descriptor->gran = 1;
|
||||
break;
|
||||
case SEGMENT_USER_CODE:
|
||||
descriptor->accessed = 0;
|
||||
descriptor->read_write = 1;
|
||||
descriptor->conforming_expand_down = 0;
|
||||
descriptor->code = 1;
|
||||
descriptor->code_data_segment = 1;
|
||||
descriptor->dpl = 3;
|
||||
descriptor->available = 0;
|
||||
descriptor->long_mode = 0;
|
||||
descriptor->big = 1;
|
||||
descriptor->gran = 1;
|
||||
break;
|
||||
case SEGMENT_USER_DATA:
|
||||
descriptor->accessed = 0;
|
||||
descriptor->read_write = 1;
|
||||
descriptor->conforming_expand_down = 0;
|
||||
descriptor->code = 0;
|
||||
descriptor->code_data_segment = 1;
|
||||
descriptor->dpl = 3;
|
||||
descriptor->available = 0;
|
||||
descriptor->long_mode = 0;
|
||||
descriptor->big = 1;
|
||||
descriptor->gran = 1;
|
||||
break;
|
||||
case SEGMENT_TSS:
|
||||
descriptor->accessed = 1;
|
||||
descriptor->read_write = 0;
|
||||
descriptor->conforming_expand_down = 0;
|
||||
descriptor->code = 1;
|
||||
descriptor->code_data_segment = 0;
|
||||
descriptor->dpl = 3;
|
||||
descriptor->available = 0;
|
||||
descriptor->long_mode = 0;
|
||||
descriptor->big = 0;
|
||||
descriptor->gran = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void initialize_gdt()
|
||||
{
|
||||
static struct gdt_entry_t gdt[gdt_size];
|
||||
memset(gdt, 0, sizeof(struct gdt_entry_t) * gdt_size);
|
||||
create_segment_descriptor(&gdt[1], 0, 0xFFFFF, SEGMENT_KERNEL_CODE);
|
||||
create_segment_descriptor(&gdt[2], 0, 0xFFFFF, SEGMENT_KERNEL_DATA);
|
||||
create_segment_descriptor(&gdt[3], 0, 0xFFFFF, SEGMENT_USER_CODE);
|
||||
create_segment_descriptor(&gdt[4], 0, 0xFFFFF, SEGMENT_USER_DATA);
|
||||
//create_segment_descriptor(&gdt[5], (size_t)&tss, sizeof(struct tss_t), SEGMENT_TSS);
|
||||
load_gdt(gdt);
|
||||
}
|
||||
|
||||
void initialize_idt()
|
||||
{
|
||||
static struct interrupt_descriptor_t idt[idt_size];
|
||||
memset(idt, 0, sizeof(struct interrupt_descriptor_t) * idt_size);
|
||||
for(int i = 0; i < idt_size; i++)
|
||||
{
|
||||
create_interrupt_descriptor(&idt[i], (void*)isr_generic, INTERRPUT_INT32, 0);
|
||||
}
|
||||
create_interrupt_descriptor(&idt[EXCEPTION_DIV_BY_0], (void*)isr_division_by_zero, INTERRPUT_INT32, 0);
|
||||
create_interrupt_descriptor(&idt[EXCEPTION_GPF], (void*)isr_gp_fault, INTERRPUT_INT32, 0);
|
||||
create_interrupt_descriptor(&idt[EXCEPTION_PAGE_FAULT], (void*)isr_page_fault, INTERRPUT_INT32, 0);
|
||||
create_interrupt_descriptor(&idt[EXCEPTION_DOUBLE_FAULT], (void*)isr_double_fault, INTERRPUT_INT32, 0);
|
||||
create_interrupt_descriptor(&idt[ISR_APIC_TIMER], (void*)isr_timer, INTERRPUT_INT32, 0);
|
||||
create_interrupt_descriptor(&idt[ISR_AP_START], (void*)isr_ap_start, INTERRPUT_INT32, 0);
|
||||
create_interrupt_descriptor(&idt[ISR_SYSCALL], (void*)isr_syscall, INTERRPUT_INT32, 0);
|
||||
load_idt(idt);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ enum interrupt_code_t
|
||||
EXCEPTION_SIMD_FLOATING_POINT = 19,
|
||||
EXCEPTION_VIRTUALIZATION = 20,
|
||||
EXCEPTION_SECURITY = 30,
|
||||
ISR_APIC_TIMER = 64,
|
||||
ISR_AP_START = 127,
|
||||
ISR_SYSCALL = 128
|
||||
};
|
||||
@@ -37,18 +38,6 @@ enum isr_type_t
|
||||
INTERRPUT_INT16 = 6
|
||||
};
|
||||
|
||||
struct interrupt_descriptor_t
|
||||
{
|
||||
uint16_t offset_1;
|
||||
uint16_t selector;
|
||||
uint16_t zero : 8;
|
||||
uint16_t type : 4;
|
||||
uint16_t storage : 1;
|
||||
uint16_t dpl : 2;
|
||||
uint16_t present : 1;
|
||||
uint16_t offset_2;
|
||||
};
|
||||
void initialize_gdt();
|
||||
|
||||
void lidt(struct interrupt_descriptor_t *idt);
|
||||
|
||||
void create_interrupt_descriptor(struct interrupt_descriptor_t *descriptor, void *isr, enum isr_type_t type, uint32_t privilage);
|
||||
void initialize_idt();
|
||||
|
||||
@@ -1,31 +1,58 @@
|
||||
#include "kernel.h"
|
||||
#include "isr.h"
|
||||
#include "stdio.h"
|
||||
#include "apic.h"
|
||||
|
||||
void isr_generic(void* frame)
|
||||
{
|
||||
printf("Generic interrupt.\n");
|
||||
}
|
||||
|
||||
__attribute__ ((interrupt))
|
||||
void isr_division_by_zero(void* frame)
|
||||
{
|
||||
printf("Exception: Division by zero\n");
|
||||
}
|
||||
|
||||
__attribute__ ((interrupt))
|
||||
void isr_gp_fault(void* frame, unsigned int error)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
__attribute__ ((interrupt))
|
||||
void isr_page_fault(void* frame, unsigned int error)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
__attribute__ ((interrupt))
|
||||
void isr_double_fault(void* frame, unsigned int error)
|
||||
{
|
||||
asm("cli");
|
||||
printf("Exception: GP fault, code %08x\n", error);
|
||||
asm("hlt");
|
||||
}
|
||||
|
||||
__attribute__ ((naked))
|
||||
void isr_page_fault(void* frame, unsigned int error)
|
||||
{
|
||||
size_t addr;
|
||||
asm("mov %%cr2, %0"
|
||||
: "=r"(addr));
|
||||
printf("Exception: Page fault, code %08x, linear address %08x\n", error, addr);
|
||||
asm("hlt");
|
||||
}
|
||||
|
||||
void isr_double_fault(void* frame, unsigned int error)
|
||||
{
|
||||
asm("cli");
|
||||
|
||||
printf("Exception: Double fault (!!), code %08x\n", error);
|
||||
asm("hlt");
|
||||
}
|
||||
|
||||
void isr_timer(void* frame)
|
||||
{
|
||||
printf("Timer tick.\n");
|
||||
apic_eoi();
|
||||
}
|
||||
|
||||
void isr_preempt(void* frame)
|
||||
{
|
||||
asm("pushal;"
|
||||
"mov %esp, %ebp");
|
||||
struct process_state_t *process_state;
|
||||
asm("mov %%ebp, %0"
|
||||
: "=r"(process_state));
|
||||
next_process(&kernel_state, process_state);
|
||||
}
|
||||
|
||||
void isr_ap_start(void* frame)
|
||||
{
|
||||
asm(".code16");
|
||||
@@ -34,7 +61,6 @@ void isr_ap_start(void* frame)
|
||||
// do something useful
|
||||
}
|
||||
|
||||
__attribute__ ((interrupt))
|
||||
void isr_syscall(void* frame)
|
||||
{
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
__attribute__ ((interrupt))
|
||||
void isr_generic(void* frame);
|
||||
|
||||
__attribute__ ((interrupt))
|
||||
void isr_division_by_zero(void* frame);
|
||||
|
||||
@@ -12,6 +15,12 @@ void isr_page_fault(void* frame, unsigned int error);
|
||||
__attribute__ ((interrupt))
|
||||
void isr_double_fault(void* frame, unsigned int error);
|
||||
|
||||
__attribute__ ((interrupt))
|
||||
void isr_timer(void* frame);
|
||||
|
||||
__attribute__ ((naked))
|
||||
void isr_preempt(void* frame);
|
||||
|
||||
__attribute__ ((naked))
|
||||
void isr_ap_start(void* frame);
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0xFF900000;
|
||||
. = 0xFF800000;
|
||||
VIRTUAL_BASE = .;
|
||||
PHYSICAL_BASE = 0x100000;
|
||||
BASE_DIFF = VIRTUAL_BASE - PHYSICAL_BASE;
|
||||
@@ -34,9 +34,8 @@ SECTIONS
|
||||
BSS_END = ADDR(.bss) + SIZEOF(.bss) - (VIRTUAL_BASE - PHYSICAL_BASE);
|
||||
IMAGE_SIZE = ((BSS_END - LOAD_START) + (4096 - ((BSS_END - LOAD_START) % 4096))) / 4096;
|
||||
|
||||
_pageMapLocation = 0xFF800000;
|
||||
_heapLocation = 0xFFB00000;
|
||||
_heapSize = 0x100000;
|
||||
_kernelStart = VIRTUAL_BASE;
|
||||
_kernel_pstart = PHYSICAL_BASE;
|
||||
_kernel_pend = PHYSICAL_BASE + (4096 * IMAGE_SIZE);
|
||||
_kernel_start = VIRTUAL_BASE;
|
||||
_kernel_end = VIRTUAL_BASE + (4096 * IMAGE_SIZE);
|
||||
}
|
||||
|
||||
@@ -11,34 +11,51 @@ const size_t page_bits = 12;
|
||||
struct page_table_entry_t
|
||||
{
|
||||
uint32_t present : 1;
|
||||
|
||||
uint32_t rw : 1;
|
||||
|
||||
uint32_t usermode : 1;
|
||||
|
||||
uint32_t writeThrough : 1;
|
||||
|
||||
uint32_t cacheDisable : 1;
|
||||
|
||||
uint32_t write_through : 1;
|
||||
uint32_t cache_disable : 1;
|
||||
uint32_t accessed : 1;
|
||||
|
||||
uint32_t dirty : 1;
|
||||
|
||||
uint32_t pat : 1;
|
||||
|
||||
uint32_t global : 1;
|
||||
|
||||
uint32_t shared : 1;
|
||||
|
||||
uint32_t ignored : 2;
|
||||
|
||||
uint32_t physicalAddress : 20;
|
||||
uint32_t physical_address : 20;
|
||||
};
|
||||
|
||||
struct page_table_entry_t *page_tables = (struct page_table_entry_t *)0xFFC00000;
|
||||
|
||||
struct page_table_entry_t *page_directory = (struct page_table_entry_t *)0xFFFFF000;
|
||||
|
||||
int start_paging(physaddr_t start, physaddr_t end, uint32_t *directory, uint32_t *table, uint32_t *identity_table)
|
||||
{
|
||||
physaddr_t p = start;
|
||||
size_t count = 0;
|
||||
while(p < end)
|
||||
{
|
||||
uint32_t table_entry = p + 3;
|
||||
int index = p / page_size;
|
||||
table[index - start / page_size] = table_entry;
|
||||
identity_table[index] = table_entry;
|
||||
p += page_size;
|
||||
count++;
|
||||
}
|
||||
directory[0] = ((uint32_t)identity_table) + 3;
|
||||
directory[1022] = ((uint32_t)table) + 3;
|
||||
directory[1023] = ((uint32_t)directory) + 3;
|
||||
asm("mov %0, %%cr3"
|
||||
:
|
||||
: "r"(directory));
|
||||
asm("mov %%cr0, %%eax \n"
|
||||
"or $0x80010000, %%eax \n"
|
||||
"mov %%eax, %%cr0"
|
||||
:
|
||||
:
|
||||
: "eax");
|
||||
return count;
|
||||
}
|
||||
|
||||
physaddr_t create_address_space(struct page_stack_t *page_stack)
|
||||
{
|
||||
physaddr_t table = reserve_page(page_stack);
|
||||
@@ -47,12 +64,14 @@ physaddr_t create_address_space(struct page_stack_t *page_stack)
|
||||
return S_OUT_OF_MEMORY;
|
||||
}
|
||||
struct page_table_entry_t buffer = page_directory[0];
|
||||
page_directory[0].physicalAddress = table >> page_bits;
|
||||
page_directory[0].physical_address = table >> page_bits;
|
||||
asm volatile("invlpg 0xFFC00000" ::
|
||||
: "memory");
|
||||
memset((void *)page_tables, 0, 1022 * 4);
|
||||
page_tables[1022] = page_directory[1022];
|
||||
page_tables[1023] = page_directory[1023];
|
||||
page_tables[1023].physical_address = table >> page_bits;
|
||||
page_tables[1023].present = 1;
|
||||
page_tables[1023].rw = 1;
|
||||
page_directory[0] = buffer;
|
||||
asm volatile("invlpg 0xFFC00000" ::
|
||||
: "memory");
|
||||
@@ -67,6 +86,11 @@ void load_address_space(physaddr_t table)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
physaddr_t current_address_space()
|
||||
{
|
||||
return page_directory[1023].physical_address << 12;
|
||||
}
|
||||
|
||||
int map_page(struct page_stack_t *page_stack, void *page, physaddr_t frame, int flags)
|
||||
{
|
||||
if ((size_t)page % page_size != 0 || frame % page_size != 0)
|
||||
@@ -82,15 +106,15 @@ int map_page(struct page_stack_t *page_stack, void *page, physaddr_t frame, int
|
||||
{
|
||||
return S_OUT_OF_MEMORY;
|
||||
}
|
||||
page_directory[directory_index].physicalAddress = new_table >> page_bits;
|
||||
page_directory[directory_index].physical_address = new_table >> page_bits;
|
||||
page_directory[directory_index].present = 1;
|
||||
page_directory[directory_index].usermode = 0;
|
||||
page_directory[directory_index].usermode = (directory_index < 1022) ? 1 : 0;
|
||||
page_directory[directory_index].rw = 1;
|
||||
}
|
||||
page_tables[table_index].physicalAddress = frame >> 12;
|
||||
page_tables[table_index].physical_address = frame >> 12;
|
||||
page_tables[table_index].present = 1;
|
||||
page_tables[table_index].usermode = 1;
|
||||
page_tables[table_index].rw = 1;
|
||||
page_tables[table_index].usermode = (flags & PAGE_USERMODE) ? 1 : 0;
|
||||
page_tables[table_index].rw = (flags & PAGE_RW) ? 1 : 0;
|
||||
asm volatile("invlpg (%0)"
|
||||
:
|
||||
: "r"(page)
|
||||
@@ -112,7 +136,7 @@ physaddr_t unmap_page(void *page)
|
||||
}
|
||||
else
|
||||
{
|
||||
physaddr_t frame = page_tables[table_index].physicalAddress << page_bits;
|
||||
physaddr_t frame = page_tables[table_index].physical_address << page_bits;
|
||||
memset(&page_tables[table_index], 0, sizeof(struct page_table_entry_t));
|
||||
asm volatile("invlpg (%0)"
|
||||
:
|
||||
|
||||
@@ -36,10 +36,6 @@ void *read_multiboot_table(struct boot_info_t *boot_info, void *table)
|
||||
M_UNAVAILABLE);
|
||||
boot_info->module_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("WARNING: Too many modules, must skip one.\n");
|
||||
}
|
||||
break;
|
||||
case MB_BOOT_COMMAND:
|
||||
strcpy(boot_info->parameters, &((struct multiboot2_string_t*) table)->str);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#include "stdio.h"
|
||||
#include "mmgr.h"
|
||||
#include "allocator.h"
|
||||
#include <stddef.h>
|
||||
|
||||
enum vga_color_t {
|
||||
@@ -28,12 +30,18 @@ struct cell_t
|
||||
char bg : 4;
|
||||
};
|
||||
|
||||
struct cell_t *screen = (struct cell_t*)0xFF8B8000;
|
||||
struct cell_t *screen = (struct cell_t*)NULL;
|
||||
size_t cursor = 0;
|
||||
|
||||
const size_t tab_width = 4;
|
||||
const size_t line_width = 80;
|
||||
|
||||
int initialize_screen()
|
||||
{
|
||||
screen = allocate_from_bottom(page_size);
|
||||
map_page(NULL, screen, 0x000B8000, PAGE_RW);
|
||||
}
|
||||
|
||||
int putchar(int c)
|
||||
{
|
||||
switch(c)
|
||||
|
||||
@@ -1,49 +1,31 @@
|
||||
#include "kernel.h"
|
||||
#include "pageallocator.h"
|
||||
#include "allocator.h"
|
||||
#include "mmgr.h"
|
||||
#include "multiboot2.h"
|
||||
#include "memorymap.h"
|
||||
#include "apic.h"
|
||||
#include "interrupts.h"
|
||||
#include "msr.h"
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
#include "module.h"
|
||||
#include "isr.h"
|
||||
#include "config.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
extern int _kernel_pstart;
|
||||
extern int _kernel_pend;
|
||||
extern int _kernel_start;
|
||||
extern int _kernel_end;
|
||||
|
||||
struct apic_registers_t volatile *apic_registers;
|
||||
|
||||
int startPaging(uint32_t *directory, uint32_t *table, uint32_t *identityTable)
|
||||
{
|
||||
for (int i = 0; i < 1024; i++)
|
||||
{
|
||||
uint32_t pte = i * 4096 + 3;
|
||||
table[i] = pte;
|
||||
identityTable[i] = pte;
|
||||
}
|
||||
directory[0] = ((uint32_t)identityTable) + 3;
|
||||
directory[1022] = ((uint32_t)table) + 3;
|
||||
directory[1023] = ((uint32_t)directory) + 3;
|
||||
asm("mov %0, %%cr3"
|
||||
:
|
||||
: "r"(directory));
|
||||
asm("mov %%cr0, %%eax \n"
|
||||
"or $0x80010000, %%eax \n"
|
||||
"mov %%eax, %%cr0"
|
||||
:
|
||||
:
|
||||
: "eax");
|
||||
return 0;
|
||||
}
|
||||
struct kernel_t kernel_state;
|
||||
|
||||
int initialize(void *multiboot_info)
|
||||
{
|
||||
static struct interrupt_descriptor_t idt[256];
|
||||
initialize_gdt();
|
||||
initialize_idt();
|
||||
initialize_allocator(&_kernel_end, (void*)0xFFC00000);
|
||||
static struct page_stack_t page_stack;
|
||||
static struct kernel_t kernel;
|
||||
struct memory_region_t map_array[16];
|
||||
char bootloader_name[64];
|
||||
char kernel_parameters[64];
|
||||
@@ -55,12 +37,19 @@ int initialize(void *multiboot_info)
|
||||
.array = map_array,
|
||||
.size = 0,
|
||||
.capacity = 16}};
|
||||
void *multiboot_end = multiboot_info + *(uint32_t*)multiboot_info;
|
||||
multiboot_info += 8;
|
||||
while (multiboot_info != NULL)
|
||||
{
|
||||
multiboot_info = read_multiboot_table(&boot_info, multiboot_info);
|
||||
}
|
||||
insert_region(&boot_info.map, 0, 1 << 22, M_UNAVAILABLE);
|
||||
insert_region(&boot_info.map, (physaddr_t)&_kernel_pstart, (physaddr_t)&_kernel_pend, M_UNAVAILABLE);
|
||||
for(void *p = (void*)&_kernel_end; p < multiboot_end; p += page_size)
|
||||
{
|
||||
unmap_page(p);
|
||||
}
|
||||
initialize_screen();
|
||||
printf("***%s***\n", PACKAGE_STRING);
|
||||
printf("Type\t\tLocation\t\tSize\n");
|
||||
for (size_t i = 0; i < boot_info.map.size && boot_info.map.array[i].size > 0; i++)
|
||||
{
|
||||
@@ -68,35 +57,25 @@ int initialize(void *multiboot_info)
|
||||
}
|
||||
page_stack.base_pointer = (physaddr_t*)0xFFC00000;
|
||||
page_stack.stack_pointer = (physaddr_t*)0xFFC00000;
|
||||
page_stack.limit_pointer = (physaddr_t*)0xFF900000;
|
||||
initialize_page_stack(&page_stack, &boot_info.map, 4096);
|
||||
page_stack.limit_pointer = (physaddr_t*)0xFFC00000;
|
||||
initialize_page_stack(&page_stack, &boot_info.map);
|
||||
apic_enable(page_stack);
|
||||
apic_registers->divide_config.value = APIC_DIVIDE_128;
|
||||
apic_registers->lvt_timer.vector = ISR_APIC_TIMER;
|
||||
apic_registers->lvt_timer.timer_mode = APIC_TIMER_PERIODIC;
|
||||
apic_registers->initial_count.value = 1024*1024*1024;
|
||||
apic_registers->lvt_timer.mask = 0;
|
||||
|
||||
kernel_state.page_stack = &page_stack;
|
||||
for(int i = 0; i < boot_info.module_count; i++)
|
||||
{
|
||||
load_module(&kernel, &boot_info.modules[i]);
|
||||
load_module(&kernel_state, &boot_info.modules[i]);
|
||||
}
|
||||
// TODO: setup IDT
|
||||
memset(idt, 0, sizeof(struct interrupt_descriptor_t) * 256);
|
||||
create_interrupt_descriptor(&idt[EXCEPTION_DIV_BY_0], (void*)isr_division_by_zero, INTERRPUT_INT32, 0);
|
||||
create_interrupt_descriptor(&idt[EXCEPTION_GPF], (void*)isr_gp_fault, INTERRPUT_INT32, 0);
|
||||
create_interrupt_descriptor(&idt[EXCEPTION_PAGE_FAULT], (void*)isr_page_fault, INTERRPUT_INT32, 0);
|
||||
create_interrupt_descriptor(&idt[EXCEPTION_DOUBLE_FAULT], (void*)isr_double_fault, INTERRPUT_INT32, 0);
|
||||
create_interrupt_descriptor(&idt[ISR_AP_START], (void*)isr_ap_start, INTERRPUT_INT32, 0);
|
||||
create_interrupt_descriptor(&idt[ISR_SYSCALL], (void*)isr_syscall, INTERRPUT_INT32, 0);
|
||||
lidt(idt);
|
||||
|
||||
// TODO: setup APIC
|
||||
asm volatile(
|
||||
"mov $0xFF, %%al;"
|
||||
"outb %%al, $0xA1;"
|
||||
"outb %%al, $0x21;"
|
||||
::: "al"
|
||||
);
|
||||
apic_enable();
|
||||
struct msr_apic_base_t msr;
|
||||
read_msr(MSR_APIC_BASE, (uint64_t*)&msr);
|
||||
msr.apic_base = (size_t) &_kernel_end >> 12;
|
||||
write_msr(MSR_APIC_BASE, (uint64_t*)&msr);
|
||||
printf("MSR_APIC_BASE: %016x\n", *((uint32_t*)&msr));
|
||||
apic_registers = (struct apic_registers_t*) (msr.apic_base << 12);
|
||||
// TODO: enter first process
|
||||
asm("sti");
|
||||
while(1)
|
||||
{
|
||||
asm("hlt");
|
||||
}
|
||||
// next_process(&kernel_state, NULL);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user