Massive backlog of changes
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -27,3 +27,5 @@ stamp-h1
|
||||
rootfs/apps
|
||||
test/
|
||||
doc/
|
||||
bochsrc
|
||||
bx_enh_dbg.ini
|
||||
@@ -1,9 +0,0 @@
|
||||
#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);
|
||||
41
include/avltree.h
Normal file
41
include/avltree.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* @brief An AVL tree.
|
||||
*
|
||||
*/
|
||||
struct avltree_t {
|
||||
int height;
|
||||
int key;
|
||||
void *value;
|
||||
struct avltree_t *left, *right;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Inserts a new node into an AVL tree.
|
||||
*
|
||||
* A new node will be allocated and assigned the provided key and value.
|
||||
*
|
||||
* @param tree A pointer to the tree to insert into.
|
||||
* @param key The key to associate the new node with.
|
||||
* @param value A pointer to store into the new node.
|
||||
*/
|
||||
struct avltree_t *avl_insert(struct avltree_t *tree, int key, void *value);
|
||||
|
||||
/**
|
||||
* @brief Removes the node associated with `key` from `tree`.
|
||||
*
|
||||
* @param tree A pointer to the tree to remove from.
|
||||
* @param key The key of the node to remove.
|
||||
* @return struct avltree_t* The pointer stored in the node that was just removed.
|
||||
*/
|
||||
struct avltree_t *avl_remove(struct avltree_t *tree, int key);
|
||||
|
||||
/**
|
||||
* @brief Searches for a node in `tree` with a matching key, and returns the
|
||||
*
|
||||
* @param tree
|
||||
* @param key
|
||||
* @return void*
|
||||
*/
|
||||
void *avl_get(struct avltree_t *tree, int key);
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "pageallocator.h"
|
||||
#include "mmgr.h"
|
||||
#include "types/physaddr.h"
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -115,4 +115,4 @@ struct elf_section_header_t
|
||||
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);
|
||||
int load_program(struct elf_file_header_t *elf);
|
||||
|
||||
33
include/heap.h
Normal file
33
include/heap.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include "mmgr.h"
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
* @brief Initializes the system's heap.
|
||||
*
|
||||
* This function contructs the heap's internal tables, allocating pages as needed
|
||||
* to do so.
|
||||
*
|
||||
* @param page_stack Pointer to the page stack descriptor
|
||||
* @param base Base location of the heap to contruct
|
||||
* @param heap_size Total size in bytes of the heap
|
||||
* @param block_size Size in bytes of a single unit of allocation
|
||||
* @return a status code
|
||||
*/
|
||||
int kminit(void *base, size_t heap_size, size_t block_size);
|
||||
|
||||
/**
|
||||
* @brief Allocates a block of memory containing at least `size` bytes.
|
||||
*
|
||||
* @param size The size of the block to allocate
|
||||
* @return void* A pointer to the allocated block, or NULL upon failure.
|
||||
*/
|
||||
void *kmalloc(size_t size);
|
||||
|
||||
/**
|
||||
* @brief Frees a block of memory previously allocated by `kmalloc`.
|
||||
*
|
||||
* @param ptr Pointer to the block to free
|
||||
*/
|
||||
void kfree(void *ptr);
|
||||
@@ -1,14 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "pageallocator.h"
|
||||
#include "avltree.h"
|
||||
#include "memmap.h"
|
||||
#include "priorityqueue.h"
|
||||
#include "resource.h"
|
||||
#include "module.h"
|
||||
#include "memorymap.h"
|
||||
#include "syscallid.h"
|
||||
#include "mmgr.h"
|
||||
#include "syscalls.h"
|
||||
#include <stddef.h>
|
||||
|
||||
typedef size_t (*syscall_t)(struct kernel_t*, size_t, size_t, size_t);
|
||||
#define MAX_SYSCALL_ID 256
|
||||
#define module_limit 8
|
||||
|
||||
enum process_state_t
|
||||
{
|
||||
@@ -18,6 +18,22 @@ enum process_state_t
|
||||
|
||||
struct process_context_t;
|
||||
|
||||
struct module_t
|
||||
{
|
||||
physaddr_t start;
|
||||
physaddr_t end;
|
||||
char str[64 - 2 * sizeof(physaddr_t)];
|
||||
};
|
||||
|
||||
struct boot_info_t
|
||||
{
|
||||
char *bootloader;
|
||||
char *parameters;
|
||||
size_t module_count;
|
||||
struct memory_map_t map;
|
||||
struct module_t modules[module_limit];
|
||||
};
|
||||
|
||||
struct message_t
|
||||
{
|
||||
uint16_t sender, type;
|
||||
@@ -35,30 +51,33 @@ struct process_t
|
||||
|
||||
struct kernel_t
|
||||
{
|
||||
struct page_stack_t *page_stack;
|
||||
struct priority_queue_t *priority_queue;
|
||||
struct resource_table_t *resource_table;
|
||||
struct syscall_t syscall_table[MAX_SYSCALL_ID];
|
||||
struct priority_queue_t priority_queue;
|
||||
struct avltree_t *process_table;
|
||||
struct process_t *active_process;
|
||||
int next_pid;
|
||||
};
|
||||
|
||||
extern syscall_t syscall_table[32];
|
||||
void kernel_initialize(struct boot_info_t *boot_info);
|
||||
|
||||
extern struct kernel_t kernel_state;
|
||||
int set_syscall(int id, int arg_count, int pid, void *func_ptr);
|
||||
|
||||
void construct_kernel_state(struct kernel_t *kernel, struct page_stack_t *page_stack,
|
||||
struct priority_queue_t *priority_queue, struct resource_table_t *resource_table,
|
||||
size_t module_count, struct module_t *module_list);
|
||||
size_t do_syscall(enum syscall_id_t id, syscall_arg_t arg1, syscall_arg_t arg2, syscall_arg_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 module_t *module);
|
||||
|
||||
int load_module(struct kernel_t *kernel, struct module_t *module);
|
||||
int active_process();
|
||||
|
||||
struct process_context_t *next_process(struct kernel_t *kernel, struct process_context_t *prev_state);
|
||||
int add_process(void *program_entry, int priority, physaddr_t address_space);
|
||||
|
||||
int terminate_process(struct kernel_t *kernel, size_t process_id);
|
||||
struct process_context_t *next_process(struct process_context_t *prev_state);
|
||||
|
||||
int accept_message(struct kernel_t *kernel, size_t process_id, struct message_t *message);
|
||||
int terminate_process(size_t process_id);
|
||||
|
||||
int send_message(struct kernel_t *kernel, size_t process_id, const struct message_t *message);
|
||||
/*
|
||||
int accept_message(size_t process_id, struct message_t *message);
|
||||
|
||||
int send_message(size_t process_id, const struct message_t *message);
|
||||
*/
|
||||
|
||||
void panic(const char *message) __attribute__ ((noreturn));
|
||||
|
||||
@@ -1,24 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include "pageallocator.h"
|
||||
#include "memmap.h"
|
||||
#include "platform/paging.h"
|
||||
#include "types/physaddr.h"
|
||||
|
||||
enum page_flag_t
|
||||
{
|
||||
PAGE_RW = 1,
|
||||
PAGE_EXECUTABLE = 1 << 1,
|
||||
PAGE_USERMODE = 1 << 2
|
||||
};
|
||||
|
||||
enum page_type_t
|
||||
{
|
||||
PAGE_NOT_PRESENT = 0,
|
||||
PAGE_ANON = 1,
|
||||
PAGE_COPY_ON_WRITE = 2
|
||||
};
|
||||
#include <stddef.h>
|
||||
|
||||
extern const size_t page_size;
|
||||
|
||||
/**
|
||||
* @brief Pop the topmost address from the stack and returns that value.
|
||||
*
|
||||
* If the stack is empty, this function will instead return a status code. This
|
||||
* can be identified by testing the least signifigant bits of the return value.
|
||||
*
|
||||
* @param stack
|
||||
* @return physaddr_t
|
||||
*/
|
||||
physaddr_t reserve_page();
|
||||
|
||||
/**
|
||||
* @brief Pushes `location` onto the stack.
|
||||
*
|
||||
* If there is no room on the stack, the stack will be unaffected.
|
||||
*
|
||||
* @param stack
|
||||
* @param location
|
||||
*/
|
||||
int free_page(physaddr_t location);
|
||||
|
||||
/**
|
||||
* @brief Computes the number of available pages.
|
||||
*
|
||||
* @param stack
|
||||
* @return size_t
|
||||
*/
|
||||
size_t free_page_count();
|
||||
|
||||
/**
|
||||
* @brief Get the location of the bottom of the page stack.
|
||||
*
|
||||
* @return void*
|
||||
*/
|
||||
void *page_stack_bottom();
|
||||
|
||||
/**
|
||||
* @brief Get the location of the top of the page stack.
|
||||
*
|
||||
* @return void*
|
||||
*/
|
||||
void *page_stack_top();
|
||||
|
||||
/**
|
||||
* @brief Push all available pages in `map` onto the stack
|
||||
*
|
||||
* @param stack
|
||||
* @param map
|
||||
*/
|
||||
int initialize_page_stack(struct memory_map_t *map, physaddr_t *stack_base);
|
||||
|
||||
/**
|
||||
* @brief Create a new top-level page table and map the kernel in it.
|
||||
*
|
||||
@@ -26,14 +65,7 @@ extern const size_t page_size;
|
||||
*
|
||||
* @return physaddr_t
|
||||
*/
|
||||
physaddr_t create_address_space(struct page_stack_t *page_stack);
|
||||
|
||||
/**
|
||||
* @brief Load an existing top-level page table
|
||||
*
|
||||
* @param table
|
||||
*/
|
||||
void load_address_space(physaddr_t table);
|
||||
physaddr_t create_address_space();
|
||||
|
||||
/**
|
||||
* @brief Returns the physical address of the top-level page table currently in
|
||||
@@ -52,7 +84,7 @@ physaddr_t current_address_space();
|
||||
* @param flags
|
||||
* @return int
|
||||
*/
|
||||
int map_page(struct page_stack_t *page_stack, void *page, physaddr_t frame, int flags);
|
||||
int map_page(void *page, physaddr_t frame, int flags);
|
||||
|
||||
/**
|
||||
* @brief Unmaps a single page, returning the physical address of the frame it
|
||||
@@ -69,7 +101,7 @@ physaddr_t unmap_page(void *page);
|
||||
* @param page
|
||||
* @return enum page_type_t
|
||||
*/
|
||||
enum page_type_t page_type(void *page);
|
||||
int page_type(void *page);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "types/physaddr.h"
|
||||
|
||||
struct module_t
|
||||
{
|
||||
physaddr_t start;
|
||||
physaddr_t end;
|
||||
char str[64 - 2 * sizeof(physaddr_t)];
|
||||
};
|
||||
@@ -1,75 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "memorymap.h"
|
||||
#include "types/physaddr.h"
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
* @brief Describes a stack containing the physical addresses of available page
|
||||
* frames.
|
||||
*
|
||||
*/
|
||||
struct page_stack_t
|
||||
{
|
||||
/**
|
||||
* @brief The total number of physical pages managed by the system.
|
||||
*
|
||||
*/
|
||||
size_t total_pages;
|
||||
|
||||
/**
|
||||
* @brief Points to the topmost physical address on the stack.
|
||||
*
|
||||
*/
|
||||
physaddr_t *stack_pointer;
|
||||
|
||||
/**
|
||||
* @brief Points to the bottom of the stack.
|
||||
*
|
||||
*/
|
||||
physaddr_t *base_pointer;
|
||||
|
||||
/**
|
||||
* @brief Points to the limit of the stack. The stack cannot grow beyond
|
||||
* this point.
|
||||
*
|
||||
*/
|
||||
physaddr_t *limit_pointer;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Pop the topmost address from the stack and returns that value.
|
||||
*
|
||||
* If the stack is empty, this function will instead return a status code. This
|
||||
* can be identified by testing the least signifigant bits of the return value.
|
||||
*
|
||||
* @param stack
|
||||
* @return physaddr_t
|
||||
*/
|
||||
physaddr_t reserve_page(struct page_stack_t *stack);
|
||||
|
||||
/**
|
||||
* @brief Pushes `location` onto the stack.
|
||||
*
|
||||
* If there is no room on the stack, the stack will be unaffected.
|
||||
*
|
||||
* @param stack
|
||||
* @param location
|
||||
*/
|
||||
int free_page(struct page_stack_t *stack, physaddr_t location);
|
||||
|
||||
/**
|
||||
* @brief Computes the number of available pages.
|
||||
*
|
||||
* @param stack
|
||||
* @return size_t
|
||||
*/
|
||||
size_t free_page_count(struct page_stack_t *stack);
|
||||
|
||||
/**
|
||||
* @brief Push all available pages in `map` onto the stack
|
||||
*
|
||||
* @param stack
|
||||
* @param map
|
||||
*/
|
||||
int initialize_page_stack(struct page_stack_t *stack, struct memory_map_t *map, physaddr_t *stack_base);
|
||||
@@ -1,9 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "pageallocator.h"
|
||||
#include "kernel.h"
|
||||
void *initialize_context(void *task_entry);
|
||||
|
||||
void *initialize_context(void *task_entry, struct page_stack_t *page_stack);
|
||||
void destroy_context(void *ctx);
|
||||
|
||||
void save_context(struct process_context_t *context, void *ptr);
|
||||
|
||||
20
include/platform/interrupts.h
Normal file
20
include/platform/interrupts.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int initialize_interrupts();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
void irq_enable();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
void irq_disable();
|
||||
96
include/platform/paging.h
Normal file
96
include/platform/paging.h
Normal file
@@ -0,0 +1,96 @@
|
||||
#pragma once
|
||||
|
||||
#include "types/physaddr.h"
|
||||
#include <stddef.h>
|
||||
|
||||
enum page_flag_t
|
||||
{
|
||||
PAGE_RW = 1,
|
||||
PAGE_EXECUTABLE = 1 << 1,
|
||||
PAGE_USERMODE = 1 << 2,
|
||||
PAGE_PRESENT = 1 << 16,
|
||||
PAGE_ANON = 1 << 17,
|
||||
PAGE_COPY_ON_WRITE = 1 << 18
|
||||
};
|
||||
|
||||
const size_t page_table_levels;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param table
|
||||
* @return int
|
||||
*/
|
||||
int paging_init_top_table(physaddr_t table);
|
||||
|
||||
/**
|
||||
* @brief Returns the physical address of the top-level page table currently in
|
||||
* use.
|
||||
*
|
||||
* @return physaddr_t
|
||||
*/
|
||||
physaddr_t paging_current_address_space();
|
||||
|
||||
/**
|
||||
* @brief Load an existing top-level page table
|
||||
*
|
||||
* @param table
|
||||
*/
|
||||
void paging_load_address_space(physaddr_t table);
|
||||
|
||||
/**
|
||||
* @brief Get the pte type object
|
||||
*
|
||||
* @param page
|
||||
* @param level
|
||||
* @return int
|
||||
*/
|
||||
int get_pte_type(void *page, int level);
|
||||
|
||||
/**
|
||||
* @brief Set the pte type object
|
||||
*
|
||||
* @param page
|
||||
* @param level
|
||||
* @param flags
|
||||
* @return int
|
||||
*/
|
||||
int set_pte_type(void *page, int level, int flags);
|
||||
|
||||
/**
|
||||
* @brief Get the pte address object
|
||||
*
|
||||
* @param page
|
||||
* @param level
|
||||
* @return physaddr_t
|
||||
*/
|
||||
physaddr_t get_pte_address(void *page, int level);
|
||||
|
||||
/**
|
||||
* @brief Set the pte address object
|
||||
*
|
||||
* @param page
|
||||
* @param level
|
||||
* @param addr
|
||||
* @return int
|
||||
*/
|
||||
int set_pte_address(void *page, int level, physaddr_t addr);
|
||||
|
||||
/**
|
||||
* @brief Set the pte object
|
||||
*
|
||||
* @param page
|
||||
* @param level
|
||||
* @param flags
|
||||
* @param addr
|
||||
* @return int
|
||||
*/
|
||||
int set_pte(void *page, int level, int flags, physaddr_t addr);
|
||||
|
||||
/**
|
||||
* @brief Resets all entries in the same table as the specified entry
|
||||
*
|
||||
* @param page
|
||||
* @param level
|
||||
*/
|
||||
void wipe_page_table(void *page, int level);
|
||||
24
include/platform/putc.h
Normal file
24
include/platform/putc.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* @brief Prepare to output characters to the screen.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int initialize_screen();
|
||||
|
||||
/**
|
||||
* @brief Write a single character to the screen.
|
||||
*
|
||||
* @param c
|
||||
* @return int
|
||||
*/
|
||||
int putchar(int c);
|
||||
|
||||
/**
|
||||
* @brief Write a string to the screen.
|
||||
*
|
||||
* @param str
|
||||
* @return int
|
||||
*/
|
||||
int puts(const char *str);
|
||||
@@ -1,11 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include "pageallocator.h"
|
||||
#include "kernel.h"
|
||||
#include <stddef.h>
|
||||
/**
|
||||
* @brief An pair consisting of a priority and a pointer to be stored in
|
||||
* a priority queue.
|
||||
*
|
||||
*/
|
||||
struct priority_queue_node_t
|
||||
{
|
||||
/**
|
||||
* @brief A pointer to some user-defined object.
|
||||
*
|
||||
*/
|
||||
void *value;
|
||||
|
||||
/**
|
||||
* @brief The priority of the associated object. Only the object with the
|
||||
* lowest priority is directly accessible from a priority queue.
|
||||
*
|
||||
*/
|
||||
int priority;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief A priority queue. Each object in the queue contains a priority and
|
||||
* a pointer to some user-defined value, and a priority. Operations on the
|
||||
* queue consist of insertion and deletion of objects, and extraction of the
|
||||
* object with the lowest priority.
|
||||
*
|
||||
*/
|
||||
struct priority_queue_t
|
||||
@@ -14,45 +34,59 @@ struct priority_queue_t
|
||||
* @brief A pointer to the heap described by this structure.
|
||||
*
|
||||
*/
|
||||
struct process_t **heap;
|
||||
struct priority_queue_node_t *heap;
|
||||
|
||||
/**
|
||||
* @brief The current number of elements stored in the heap.
|
||||
*
|
||||
*/
|
||||
size_t size;
|
||||
int size;
|
||||
|
||||
/**
|
||||
* @brief The maximum number of elements that the heap can currently hold.
|
||||
*
|
||||
*/
|
||||
size_t capacity;
|
||||
int capacity;
|
||||
};
|
||||
|
||||
int construct_priority_queue(struct priority_queue_t *queue, struct page_stack_t *page_stack);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Initializes the given queue struct.
|
||||
*
|
||||
* The queue's underlying heap is allocated
|
||||
*
|
||||
* @param queue
|
||||
* @return struct process_t*
|
||||
*/
|
||||
struct process_t *extract_min(struct priority_queue_t *queue);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param queue
|
||||
* @param process
|
||||
* @return int
|
||||
*/
|
||||
int queue_insert(struct priority_queue_t *queue, struct process_t *process);
|
||||
int construct_priority_queue(struct priority_queue_t *queue, int capacity);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief Extracts the object with the lowest priority off the given queue.
|
||||
*
|
||||
* The object is removed from the queue, and a pointer to its userdata is
|
||||
* returned. If the queue is empty, this function returns NULL and the queue
|
||||
* is unaffected. If multiple objects with the same priority are stored on the
|
||||
* queue, this function will extract the object lest-recently inserted.
|
||||
*
|
||||
* @param queue
|
||||
* @param process
|
||||
* @return void*
|
||||
*/
|
||||
void *extract_min(struct priority_queue_t *queue);
|
||||
|
||||
/**
|
||||
* @brief Inserts a new object onto the queue.
|
||||
*
|
||||
* @param queue
|
||||
* @param value
|
||||
* @param priority
|
||||
* @return int
|
||||
*/
|
||||
int queue_remove(struct priority_queue_t *queue, struct process_t *process);
|
||||
int queue_insert(struct priority_queue_t *queue, void *value, int priority);
|
||||
|
||||
/**
|
||||
* @brief Removes the object with a matching value from the queue.
|
||||
*
|
||||
* @param queue
|
||||
* @param value
|
||||
* @return int
|
||||
*/
|
||||
int queue_remove(struct priority_queue_t *queue, void *value);
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pageallocator.h"
|
||||
#include "kernel.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;
|
||||
struct resource_t *limit;
|
||||
};
|
||||
|
||||
int construct_resource_table(struct resource_table_t *table, struct page_stack_t *page_stack);
|
||||
|
||||
int get_free_resource_slot(struct resource_table_t *table, struct page_stack_t *page_stack);
|
||||
@@ -2,12 +2,6 @@
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
int initialize_screen();
|
||||
|
||||
int putchar(int c);
|
||||
|
||||
int puts(const char *str);
|
||||
|
||||
int printf(const char *format, ...);
|
||||
|
||||
int sprintf(char *str, const char *format, ...);
|
||||
@@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
enum syscall_id_t
|
||||
{
|
||||
SYSCALL_TEST = 1,
|
||||
SYSCALL_YIELD,
|
||||
SYSCALL_MMAP,
|
||||
SYSCALL_MUNMAP,
|
||||
SYSCALL_TERMINATE_SELF
|
||||
};
|
||||
@@ -1,11 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include "kernel.h"
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
size_t test_syscall(struct kernel_t *kernel, size_t arg1, size_t arg2, size_t arg3);
|
||||
enum syscall_id_t
|
||||
{
|
||||
SYSCALL_TEST = 1,
|
||||
SYSCALL_YIELD,
|
||||
SYSCALL_MMAP,
|
||||
SYSCALL_MUNMAP,
|
||||
SYSCALL_TERMINATE_SELF
|
||||
};
|
||||
|
||||
size_t mmap(struct kernel_t *kernel, size_t location, size_t length, size_t flags);
|
||||
typedef union
|
||||
{
|
||||
long signed_int;
|
||||
unsigned long unsigned_int;
|
||||
void *ptr;
|
||||
} syscall_arg_t;
|
||||
|
||||
size_t munmap(struct kernel_t *kernel, size_t location, size_t length, size_t arg3);
|
||||
typedef size_t (*syscall_ptr_0_t)();
|
||||
|
||||
size_t terminate_self(struct kernel_t *kernel, size_t arg1, size_t arg2, size_t arg3)
|
||||
typedef size_t (*syscall_ptr_1_t)(syscall_arg_t);
|
||||
|
||||
typedef size_t (*syscall_ptr_2_t)(syscall_arg_t, syscall_arg_t);
|
||||
|
||||
typedef size_t (*syscall_ptr_3_t)(syscall_arg_t, syscall_arg_t, syscall_arg_t);
|
||||
|
||||
struct syscall_t
|
||||
{
|
||||
bool defined;
|
||||
int arg_count;
|
||||
int process_id;
|
||||
union
|
||||
{
|
||||
syscall_ptr_0_t func_ptr_0;
|
||||
syscall_ptr_1_t func_ptr_1;
|
||||
syscall_ptr_2_t func_ptr_2;
|
||||
syscall_ptr_3_t func_ptr_3;
|
||||
};
|
||||
};
|
||||
|
||||
size_t test_syscall(syscall_arg_t str);
|
||||
|
||||
size_t mmap(syscall_arg_t location, syscall_arg_t length, syscall_arg_t flags);
|
||||
|
||||
size_t munmap(syscall_arg_t location, syscall_arg_t length);
|
||||
|
||||
size_t terminate_self();
|
||||
|
||||
@@ -61,7 +61,7 @@ struct apic_register_t
|
||||
{
|
||||
uint32_t value;
|
||||
uint32_t padding[3];
|
||||
};
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct apic_lapic_version_t
|
||||
{
|
||||
@@ -71,7 +71,7 @@ struct apic_lapic_version_t
|
||||
uint32_t suppress_eoi_broadcast : 1;
|
||||
uint32_t reserved_2 : 7;
|
||||
uint32_t padding[3];
|
||||
};
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct apic_lvt_t
|
||||
{
|
||||
@@ -86,7 +86,7 @@ struct apic_lvt_t
|
||||
uint32_t timer_mode : 2;
|
||||
uint32_t reserved_2 : 13;
|
||||
uint32_t padding[3];
|
||||
};
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct apic_icr_t
|
||||
{
|
||||
@@ -104,7 +104,7 @@ struct apic_icr_t
|
||||
uint32_t reserved : 24;
|
||||
uint32_t destination : 8;
|
||||
uint32_t padding_2[3];
|
||||
};
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct apic_registers_t
|
||||
{
|
||||
@@ -138,9 +138,10 @@ struct apic_registers_t
|
||||
struct apic_register_t reserved_4[4];
|
||||
struct apic_register_t divide_config;
|
||||
struct apic_register_t reserved_5;
|
||||
};
|
||||
struct apic_register_t reserved_76[16 * 12];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
extern struct apic_registers_t volatile *apic_registers;
|
||||
extern struct apic_registers_t volatile apic_registers;
|
||||
|
||||
void apic_enable();
|
||||
|
||||
|
||||
@@ -8,6 +8,9 @@ void isr_generic(struct interrupt_frame_t *frame);
|
||||
__attribute__ ((interrupt))
|
||||
void isr_division_by_zero(struct interrupt_frame_t *frame);
|
||||
|
||||
__attribute__ ((interrupt))
|
||||
void isr_segment_not_present(struct interrupt_frame_t *frame, unsigned int error);
|
||||
|
||||
__attribute__ ((interrupt))
|
||||
void isr_gp_fault(struct interrupt_frame_t *frame, unsigned int error);
|
||||
|
||||
|
||||
@@ -1,84 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "memorymap.h"
|
||||
#include "module.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define module_limit 8
|
||||
|
||||
enum multiboot2_tag_types
|
||||
{
|
||||
MB_END_TAG = 0,
|
||||
MB_BOOT_COMMAND = 1,
|
||||
MB_BOOTLOADER = 2,
|
||||
MB_MODULE = 3,
|
||||
MB_MEMORY_INFO = 4,
|
||||
MB_BIOS_BOOT_DEVICE = 5,
|
||||
MB_MEMORY_MAP = 6,
|
||||
MB_VBE = 7,
|
||||
MB_FRAMEBUFFER = 8,
|
||||
MB_ELF_SYMBOLS = 9,
|
||||
MB_APM = 10,
|
||||
MB_EFI32_SYSTEM_TABLE = 11,
|
||||
MB_EFI64_SYSTEM_TABLE = 12,
|
||||
MB_SMBIOS = 13,
|
||||
MB_ACPI10_RSDP = 14,
|
||||
MB_ACPT20_RSDP = 15,
|
||||
MB_NETOWRK = 16,
|
||||
MB_EFI_MEMORY_MAP = 17,
|
||||
MB_EFI_BOOT_SERVICES = 18,
|
||||
MB_EFI32_IMAGE = 19,
|
||||
MB_EFI64_IMAGE = 20,
|
||||
MB_LOAD_ADDRESS = 21
|
||||
};
|
||||
|
||||
enum multiboot2_memory_types
|
||||
{
|
||||
MB_AVAILABLE = 1,
|
||||
MB_ACPI = 3,
|
||||
MB_DEFECTIVE = 5
|
||||
};
|
||||
|
||||
struct multiboot2_string_t
|
||||
{
|
||||
uint32_t type;
|
||||
uint32_t size;
|
||||
char str;
|
||||
};
|
||||
|
||||
struct multiboot2_module_t
|
||||
{
|
||||
uint32_t type;
|
||||
uint32_t size;
|
||||
uint32_t start;
|
||||
uint32_t end;
|
||||
char str;
|
||||
};
|
||||
|
||||
struct multiboot2_map_entry_t
|
||||
{
|
||||
uint64_t base;
|
||||
uint64_t length;
|
||||
uint32_t type;
|
||||
};
|
||||
|
||||
struct multiboot2_memory_map_t
|
||||
{
|
||||
uint32_t type;
|
||||
uint32_t size;
|
||||
uint32_t entry_size;
|
||||
uint32_t entry_version;
|
||||
struct multiboot2_map_entry_t entries;
|
||||
};
|
||||
|
||||
struct boot_info_t
|
||||
{
|
||||
char *bootloader;
|
||||
char *parameters;
|
||||
size_t module_count;
|
||||
struct memory_map_t map;
|
||||
struct module_t modules[module_limit];
|
||||
};
|
||||
#include "kernel.h"
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param boot_info
|
||||
* @param table
|
||||
* @return void*
|
||||
*/
|
||||
void *read_multiboot_table(struct boot_info_t *boot_info, void *table);
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
noinst_PROGRAMS = quark-kernel
|
||||
quark_kernel_SOURCES = kernel.c memorymap.c pageallocator.c priorityqueue.c stdio.c string.c elf.c resource.c allocator.c syscalls.c
|
||||
quark_kernel_SOURCES = kernel.c mmgr.c priorityqueue.c stdio.c string.c elf.c syscalls.c heap.c memmap.c avltree.c
|
||||
quark_kernel_LDADD = -lgcc
|
||||
quark_kernel_CFLAGS = -I$(top_srcdir)/include -ffreestanding -mgeneral-regs-only -O0 -Wall -ggdb
|
||||
quark_kernel_LDFLAGS = -nostdlib
|
||||
|
||||
if x86
|
||||
quark_kernel_SOURCES += x86/mmgr.c \
|
||||
quark_kernel_SOURCES += x86/paging.c \
|
||||
x86/putc.c \
|
||||
x86/multiboot2.c \
|
||||
x86/idt.c \
|
||||
x86/interrupts.c \
|
||||
x86/apic.c \
|
||||
x86/isr.c \
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
198
src/avltree.c
Normal file
198
src/avltree.c
Normal file
@@ -0,0 +1,198 @@
|
||||
#include "avltree.h"
|
||||
#include "heap.h"
|
||||
#include "stddef.h"
|
||||
|
||||
struct avltree_t *avl_new(int key, void *value)
|
||||
{
|
||||
struct avltree_t *new_tree = kmalloc(sizeof(struct avltree_t));
|
||||
new_tree->height = 1;
|
||||
new_tree->left = new_tree->right = NULL;
|
||||
new_tree->key = key;
|
||||
new_tree->value = value;
|
||||
return new_tree;
|
||||
}
|
||||
|
||||
int avl_height(struct avltree_t *tree)
|
||||
{
|
||||
if(tree == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return tree->height;
|
||||
}
|
||||
}
|
||||
|
||||
int avl_balance(struct avltree_t *tree)
|
||||
{
|
||||
if(tree == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return avl_height(tree->left) - avl_height(tree->right);
|
||||
}
|
||||
}
|
||||
|
||||
void avl_update_height(struct avltree_t *tree)
|
||||
{
|
||||
if(tree != NULL)
|
||||
{
|
||||
tree->height = 1 + (avl_height(tree->left) > avl_height(tree->right) ? avl_height(tree->left) : avl_height(tree->right));
|
||||
}
|
||||
}
|
||||
|
||||
struct avltree_t *avl_right_rotate(struct avltree_t *y)
|
||||
{
|
||||
struct avltree_t *x = y->left;
|
||||
struct avltree_t *z = x->right;
|
||||
x->right = y;
|
||||
y->left = z;
|
||||
avl_update_height(x);
|
||||
avl_update_height(y);
|
||||
return x;
|
||||
}
|
||||
|
||||
struct avltree_t *avl_left_rotate(struct avltree_t *x)
|
||||
{
|
||||
struct avltree_t *y = x->right;
|
||||
struct avltree_t *z = y->left;
|
||||
y->left = x;
|
||||
x->right = z;
|
||||
avl_update_height(x);
|
||||
avl_update_height(y);
|
||||
return y;
|
||||
}
|
||||
|
||||
struct avltree_t *avl_insert(struct avltree_t *tree, int key, void *value)
|
||||
{
|
||||
if(tree == NULL)
|
||||
{
|
||||
return avl_new(key, value);
|
||||
}
|
||||
else if(key < tree->key)
|
||||
{
|
||||
tree->left = avl_insert(tree->left, key, value);
|
||||
}
|
||||
else if(key > tree->key)
|
||||
{
|
||||
tree->right = avl_insert(tree->right, key, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
return tree;
|
||||
}
|
||||
|
||||
avl_update_height(tree);
|
||||
int balance = avl_balance(tree);
|
||||
if(balance > 1 && key < tree->left->key)
|
||||
{
|
||||
return avl_right_rotate(tree);
|
||||
}
|
||||
else if(balance < -1 && key > tree->right->key)
|
||||
{
|
||||
return avl_left_rotate(tree);
|
||||
}
|
||||
else if(balance > 1 && key > tree->left->key)
|
||||
{
|
||||
tree->left = avl_left_rotate(tree->left);
|
||||
return avl_right_rotate(tree);
|
||||
}
|
||||
else if(balance < -1 && key < tree->right->key)
|
||||
{
|
||||
tree->right = avl_right_rotate(tree->right);
|
||||
return avl_left_rotate(tree);
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
struct avltree_t *avl_remove(struct avltree_t *tree, int key)
|
||||
{
|
||||
if(tree == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else if(key < tree->key)
|
||||
{
|
||||
tree->left = avl_remove(tree->left, key);
|
||||
}
|
||||
else if(key > tree->key)
|
||||
{
|
||||
tree->right = avl_remove(tree->right, key);
|
||||
}
|
||||
else if(tree->left == NULL || tree->right == NULL)
|
||||
{
|
||||
struct avltree_t *child = tree->left == NULL ? tree->right : tree->left;
|
||||
if(child == NULL)
|
||||
{
|
||||
child = tree;
|
||||
tree = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
*tree = *child;
|
||||
}
|
||||
kfree(child);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct avltree_t *min = tree->right;
|
||||
while(min->left != NULL)
|
||||
{
|
||||
min = min->left;
|
||||
}
|
||||
tree->key = min->key;
|
||||
tree->value = min->value;
|
||||
tree->right = avl_remove(tree->right, min->key);
|
||||
}
|
||||
|
||||
if(tree == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
avl_update_height(tree);
|
||||
int balance = avl_balance(tree);
|
||||
if(balance > 1 && avl_balance(tree->left) >= 0)
|
||||
{
|
||||
return avl_right_rotate(tree);
|
||||
}
|
||||
else if(balance > 1 && avl_balance(tree->left) < 0)
|
||||
{
|
||||
tree->left = avl_left_rotate(tree->left);
|
||||
return avl_right_rotate(tree);
|
||||
}
|
||||
else if(balance < -1 && avl_balance(tree->right) <= 0)
|
||||
{
|
||||
return avl_left_rotate(tree);
|
||||
}
|
||||
else if(balance < -1 && avl_balance(tree->right) > 0)
|
||||
{
|
||||
tree->right = avl_right_rotate(tree->right);
|
||||
return avl_left_rotate(tree);
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
void *avl_get(struct avltree_t *tree, int key)
|
||||
{
|
||||
if(tree == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else if(key < tree->key)
|
||||
{
|
||||
return avl_get(tree->left, key);
|
||||
}
|
||||
else if(key > tree->key)
|
||||
{
|
||||
return avl_get(tree->right, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
return tree->value;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,11 @@
|
||||
#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)
|
||||
int load_program(struct elf_file_header_t *elf)
|
||||
{
|
||||
struct elf_program_header_t *program_header = (struct elf_program_header_t*)((void*)elf + elf->phoffset);
|
||||
unsigned int count = elf->phcount;
|
||||
@@ -17,12 +16,12 @@ int load_program(struct elf_file_header_t *elf, struct page_stack_t *page_stack)
|
||||
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);
|
||||
physaddr_t page = reserve_page();
|
||||
if(page == S_OUT_OF_MEMORY)
|
||||
{
|
||||
return S_OUT_OF_MEMORY;
|
||||
}
|
||||
int status = map_page(page_stack, d + n, page, PAGE_RW | PAGE_USERMODE | PAGE_EXECUTABLE);
|
||||
int status = map_page(d + n, page, PAGE_RW | PAGE_USERMODE | PAGE_EXECUTABLE);
|
||||
switch(status)
|
||||
{
|
||||
case S_OUT_OF_MEMORY:
|
||||
@@ -37,4 +36,5 @@ int load_program(struct elf_file_header_t *elf, struct page_stack_t *page_stack)
|
||||
count--;
|
||||
program_header = (struct elf_program_header_t*)((void*)program_header + elf->phsize);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
176
src/heap.c
Normal file
176
src/heap.c
Normal file
@@ -0,0 +1,176 @@
|
||||
#include <stdbool.h>
|
||||
#include "heap.h"
|
||||
#include "mmgr.h"
|
||||
#include "types/status.h"
|
||||
|
||||
#define AVAIL 0
|
||||
#define UNAVAIL 1
|
||||
#define ALLOCATED 2
|
||||
|
||||
struct heap_t
|
||||
{
|
||||
struct heap_node_t *base;
|
||||
size_t heap_size;
|
||||
size_t block_size;
|
||||
size_t tree_height;
|
||||
} system_heap;
|
||||
|
||||
struct heap_node_t
|
||||
{
|
||||
size_t height : 5;
|
||||
size_t mapped : 1;
|
||||
size_t state : 2;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
size_t find_free_block(struct heap_t *heap, size_t height)
|
||||
{
|
||||
if(height > heap->tree_height)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
for(size_t index = 1 << (heap->tree_height - height); index < 1 << (heap->tree_height - height + 1); index++)
|
||||
{
|
||||
if(heap->base[index].state == AVAIL)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
}
|
||||
size_t index = find_free_block(heap, height + 1);
|
||||
if(index)
|
||||
{
|
||||
heap->base[index].state = UNAVAIL;
|
||||
heap->base[index << 1].state = AVAIL;
|
||||
heap->base[(index << 1) ^ 1].state = AVAIL;
|
||||
}
|
||||
return index << 1;
|
||||
}
|
||||
|
||||
int map_region(struct heap_t *heap, size_t height, size_t index)
|
||||
{
|
||||
int status = 0;
|
||||
if(heap->base[index].mapped == 0)
|
||||
{
|
||||
if(height > 0)
|
||||
{
|
||||
status = map_region(heap, height - 1, index << 1);
|
||||
if(status == 0)
|
||||
{
|
||||
status = map_region(heap, height - 1, (index << 1) ^ 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
void *ptr = (void*) ((size_t) heap->base + (heap->block_size << height) * (index - (1 << (heap->tree_height - height))));
|
||||
if((page_type(ptr) & PAGE_PRESENT) == 0)
|
||||
{
|
||||
status = map_page(ptr, reserve_page(), PAGE_RW);
|
||||
}
|
||||
}
|
||||
heap->base[index].mapped = 1;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int heap_contruct(struct heap_t *heap, void *base, size_t heap_size, size_t block_size)
|
||||
{
|
||||
heap->base = (struct heap_node_t*) base;
|
||||
heap->heap_size = heap_size;
|
||||
heap->block_size = block_size;
|
||||
heap->tree_height = ilog2(heap_size / block_size);
|
||||
size_t header_size = (heap_size / block_size) << 1;
|
||||
for(size_t i = 1; i < (heap_size / block_size) * 2; i++)
|
||||
{
|
||||
int flags = page_type((void*) heap->base + i);
|
||||
if((flags & PAGE_PRESENT) == 0)
|
||||
{
|
||||
int status = map_page((void*)heap->base + i, reserve_page(), PAGE_RW);
|
||||
if(status != S_OK)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
}
|
||||
heap->base[i].state = UNAVAIL;
|
||||
heap->base[i].mapped = 0;
|
||||
}
|
||||
for(size_t i = 0; i < heap_size / block_size; i++)
|
||||
{
|
||||
if(block_size * i >= header_size)
|
||||
{
|
||||
size_t index = i + (1 << heap->tree_height);
|
||||
heap->base[index].state = AVAIL;
|
||||
for(; index > 1 && heap->base[index ^ 1].state == 0; index >>= 1)
|
||||
{
|
||||
heap->base[index].state = UNAVAIL;
|
||||
heap->base[index ^ 1].state = UNAVAIL;
|
||||
heap->base[index >> 1].state = AVAIL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
heap->base[i + (1 << heap->tree_height)].state = UNAVAIL;
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void *heap_allocate(struct heap_t *heap, size_t size)
|
||||
{
|
||||
size += heap->block_size - 1;
|
||||
size -= size % heap->block_size;
|
||||
size_t height = ilog2(size / heap->block_size);
|
||||
size_t index = find_free_block(heap, height);
|
||||
if(index)
|
||||
{
|
||||
heap->base[index].state = ALLOCATED;
|
||||
void *ptr = (void*) ((size_t) heap->base + (heap->block_size << height) * (index - (1 << (heap->tree_height - height))));
|
||||
map_region(heap, height, index);
|
||||
return ptr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void heap_free(struct heap_t *heap, void *ptr)
|
||||
{
|
||||
size_t offset = (size_t) ptr - (size_t) heap->base;
|
||||
size_t index = (offset / heap->block_size) + (1 << heap->tree_height);
|
||||
for(; index > 0 && heap->base[index].state == UNAVAIL; index >>= 1);
|
||||
heap->base[index].state = AVAIL;
|
||||
for(; index > 1 && heap->base[index ^ 1].state == AVAIL; index >>= 1)
|
||||
{
|
||||
heap->base[index].state = UNAVAIL;
|
||||
heap->base[index ^ 1].state = UNAVAIL;
|
||||
heap->base[index >> 1].state = AVAIL;
|
||||
}
|
||||
}
|
||||
|
||||
int kminit(void *base, size_t heap_size, size_t block_size)
|
||||
{
|
||||
return heap_contruct(&system_heap, base, heap_size, block_size);
|
||||
}
|
||||
|
||||
void *kmalloc(size_t size)
|
||||
{
|
||||
return heap_allocate(&system_heap, size);
|
||||
}
|
||||
|
||||
void kfree(void *ptr)
|
||||
{
|
||||
heap_free(&system_heap, ptr);
|
||||
}
|
||||
242
src/kernel.c
242
src/kernel.c
@@ -1,45 +1,151 @@
|
||||
#include "kernel.h"
|
||||
#include "mmgr.h"
|
||||
#include "heap.h"
|
||||
#include "stdio.h"
|
||||
#include "elf.h"
|
||||
#include "context.h"
|
||||
#include "syscalls.h"
|
||||
#include "string.h"
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "platform/interrupts.h"
|
||||
#include "platform/context.h"
|
||||
#include "platform/putc.h"
|
||||
#include "types/status.h"
|
||||
|
||||
syscall_t syscall_table[32];
|
||||
struct kernel_t kernel;
|
||||
|
||||
void construct_kernel_state(struct kernel_t *kernel, struct page_stack_t *page_stack,
|
||||
struct priority_queue_t *priority_queue, struct resource_table_t *resource_table,
|
||||
size_t module_count, struct module_t *module_list)
|
||||
void kernel_initialize(struct boot_info_t *boot_info)
|
||||
{
|
||||
kernel->page_stack = page_stack;
|
||||
kernel->resource_table = resource_table;
|
||||
kernel->priority_queue = priority_queue;
|
||||
kernel->active_process = NULL;
|
||||
for(int i = 0; i < module_count; i++)
|
||||
insert_region(&boot_info->map, (physaddr_t)&_kernel_pstart, (physaddr_t)&_kernel_pend - (physaddr_t)&_kernel_pstart, M_UNAVAILABLE);
|
||||
initialize_page_stack(&boot_info->map, (physaddr_t*)&_kernel_end);
|
||||
kminit(page_stack_top(), 0xFFC00000 - (size_t)page_stack_top(), page_size);
|
||||
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++)
|
||||
{
|
||||
load_module(&kernel_state, &module_list[i]);
|
||||
printf("%i\t\t\t%08x\t\t%u\n", boot_info->map.array[i].type, boot_info->map.array[i].location, boot_info->map.array[i].size);
|
||||
}
|
||||
|
||||
kernel.active_process = NULL;
|
||||
kernel.next_pid = 1;
|
||||
kernel.process_table = NULL;
|
||||
if(construct_priority_queue(&kernel.priority_queue, 512) != S_OK)
|
||||
{
|
||||
panic("Failed to construct priority queue.");
|
||||
}
|
||||
memset(kernel.syscall_table, 0, sizeof(struct syscall_t) * MAX_SYSCALL_ID);
|
||||
set_syscall(SYSCALL_TEST, 1, 0, test_syscall);
|
||||
set_syscall(SYSCALL_MMAP, 3, 0, mmap);
|
||||
set_syscall(SYSCALL_MUNMAP, 2, 0, munmap);
|
||||
for(int i = 0; i < boot_info->module_count; i++)
|
||||
{
|
||||
if(load_module(&boot_info->modules[i]) != S_OK)
|
||||
{
|
||||
panic("Failed to load modules.");
|
||||
}
|
||||
}
|
||||
|
||||
if(initialize_interrupts() != S_OK)
|
||||
{
|
||||
panic("Failed to initialize interrupts.");
|
||||
}
|
||||
|
||||
/*asm("mov $281, %ax;"
|
||||
"mov %ax, %ds");
|
||||
|
||||
asm("hlt");*/
|
||||
|
||||
irq_enable();
|
||||
load_context(next_process(NULL));
|
||||
}
|
||||
|
||||
size_t do_syscall(struct kernel_t *kernel, enum syscall_id_t id, size_t arg1, size_t arg2, size_t arg3)
|
||||
int set_syscall(int id, int arg_count, int pid, void *func_ptr)
|
||||
{
|
||||
if(syscall_table[id] == NULL)
|
||||
if(id < 0 || id > MAX_SYSCALL_ID)
|
||||
{
|
||||
return S_OUT_OF_BOUNDS;
|
||||
}
|
||||
else if(kernel.syscall_table[id].defined)
|
||||
{
|
||||
return S_INVALID_ARGUMENT;
|
||||
}
|
||||
else if(arg_count < 0 || arg_count > 3)
|
||||
{
|
||||
return S_INVALID_ARGUMENT;
|
||||
}
|
||||
else if(pid != 0 && avl_get(kernel.process_table, pid) == NULL)
|
||||
{
|
||||
return S_DOESNT_EXIST;
|
||||
}
|
||||
else if(func_ptr == NULL)
|
||||
{
|
||||
return S_NULL_POINTER;
|
||||
}
|
||||
kernel.syscall_table[id].defined = true;
|
||||
kernel.syscall_table[id].arg_count = arg_count;
|
||||
kernel.syscall_table[id].process_id = pid;
|
||||
kernel.syscall_table[id].func_ptr_0 = func_ptr;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
size_t do_syscall(enum syscall_id_t id, syscall_arg_t arg1, syscall_arg_t arg2, syscall_arg_t arg3)
|
||||
{
|
||||
if(id < 0 || id > MAX_SYSCALL_ID)
|
||||
{
|
||||
return S_BAD_SYSCALL;
|
||||
}
|
||||
return syscall_table[id](kernel, arg1, arg2, arg3);
|
||||
else if(!kernel.syscall_table[id].defined)
|
||||
{
|
||||
return S_BAD_SYSCALL;
|
||||
}
|
||||
bool switched_address_space = false;
|
||||
if(kernel.syscall_table[id].process_id > 0)
|
||||
{
|
||||
struct process_t *callee = avl_get(kernel.process_table, kernel.syscall_table[id].process_id);
|
||||
if(callee == NULL)
|
||||
{
|
||||
kernel.syscall_table[id].defined = false;
|
||||
return S_BAD_SYSCALL;
|
||||
}
|
||||
paging_load_address_space(callee->page_table);
|
||||
switched_address_space = true;
|
||||
}
|
||||
size_t result;
|
||||
switch(kernel.syscall_table[id].arg_count)
|
||||
{
|
||||
case 0:
|
||||
result = kernel.syscall_table[id].func_ptr_0();
|
||||
break;
|
||||
case 1:
|
||||
result = kernel.syscall_table[id].func_ptr_1(arg1);
|
||||
break;
|
||||
case 2:
|
||||
result = kernel.syscall_table[id].func_ptr_2(arg1, arg2);
|
||||
break;
|
||||
case 3:
|
||||
result = kernel.syscall_table[id].func_ptr_3(arg1, arg2, arg3);
|
||||
break;
|
||||
}
|
||||
if(switched_address_space)
|
||||
{
|
||||
paging_load_address_space(kernel.active_process->page_table);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int load_module(struct kernel_t *kernel, struct module_t *module)
|
||||
int load_module(struct module_t *module)
|
||||
{
|
||||
physaddr_t module_address_space = create_address_space(kernel->page_stack);
|
||||
load_address_space(module_address_space);
|
||||
physaddr_t module_address_space = create_address_space();
|
||||
if(module_address_space == S_OUT_OF_MEMORY) {
|
||||
panic("failed to create address space for module: out of memory");
|
||||
}
|
||||
paging_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);
|
||||
int status = map_page(load_base + load_offset, p, PAGE_RW);
|
||||
switch(status)
|
||||
{
|
||||
case S_OUT_OF_MEMORY:
|
||||
@@ -48,8 +154,9 @@ int load_module(struct kernel_t *kernel, struct module_t *module)
|
||||
panic("got out-of-bounds error while mapping module");
|
||||
}
|
||||
load_offset += page_size;
|
||||
|
||||
}
|
||||
int status = load_program(load_base, kernel->page_stack);
|
||||
int status = load_program(load_base);
|
||||
switch(status)
|
||||
{
|
||||
case S_OUT_OF_MEMORY:
|
||||
@@ -58,7 +165,6 @@ int load_module(struct kernel_t *kernel, struct module_t *module)
|
||||
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)
|
||||
@@ -73,64 +179,85 @@ int load_module(struct kernel_t *kernel, struct module_t *module)
|
||||
}
|
||||
load_offset += page_size;
|
||||
}
|
||||
int index = get_free_resource_slot(kernel->resource_table, kernel->page_stack);
|
||||
if(index < 0)
|
||||
if(add_process(module_entry, 1, current_address_space()) > 0)
|
||||
{
|
||||
panic("no space left in resource table for module");
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
kernel->resource_table->array[index].type = RESOURCE_PROCESS;
|
||||
kernel->resource_table->array[index].process.priority = 1;
|
||||
kernel->resource_table->array[index].process.resource_id = index;
|
||||
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_context_t *next_process(struct kernel_t *kernel, struct process_context_t *prev_state)
|
||||
int active_process()
|
||||
{
|
||||
if(kernel.active_process == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return kernel.active_process->resource_id;
|
||||
}
|
||||
}
|
||||
|
||||
int add_process(void *program_entry, int priority, physaddr_t address_space)
|
||||
{
|
||||
struct process_t *new_process = (struct process_t*) kmalloc(sizeof(struct process_t));
|
||||
if(new_process == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
struct process_context_t *initial_context = initialize_context(program_entry);
|
||||
new_process->priority = priority;
|
||||
new_process->resource_id = kernel.next_pid;
|
||||
new_process->page_table = address_space;
|
||||
new_process->state = initial_context;
|
||||
kernel.process_table = avl_insert(kernel.process_table, new_process->resource_id, new_process);
|
||||
queue_insert(&kernel.priority_queue, new_process, new_process->priority);
|
||||
kernel.next_pid++;
|
||||
return new_process->resource_id;
|
||||
}
|
||||
|
||||
struct process_context_t *next_process(struct process_context_t *prev_state)
|
||||
{
|
||||
if(prev_state != NULL)
|
||||
{
|
||||
kernel->active_process->state = prev_state;
|
||||
queue_insert(kernel->priority_queue, kernel->active_process);
|
||||
kernel.active_process->state = prev_state;
|
||||
queue_insert(&kernel.priority_queue, kernel.active_process, kernel.active_process->priority);
|
||||
}
|
||||
kernel->active_process = extract_min(kernel->priority_queue);
|
||||
if(kernel->active_process != NULL)
|
||||
kernel.active_process = extract_min(&kernel.priority_queue);
|
||||
if(kernel.active_process != NULL)
|
||||
{
|
||||
load_address_space(kernel->active_process->page_table);
|
||||
printf("entering process %08x cr3=%08x state=%08x.\n", kernel->active_process, kernel->active_process->page_table, kernel->active_process->state);
|
||||
return kernel->active_process->state;
|
||||
paging_load_address_space(kernel.active_process->page_table);
|
||||
printf("entering process %08x cr3=%08x state=%08x.\n", kernel.active_process, kernel.active_process->page_table, kernel.active_process->state);
|
||||
return kernel.active_process->state;
|
||||
}
|
||||
panic("no processes available to enter!");
|
||||
}
|
||||
|
||||
int terminate_process(struct kernel_t *kernel, size_t process_id)
|
||||
int terminate_process(size_t process_id)
|
||||
{
|
||||
if(kernel == NULL)
|
||||
struct process_t *process = avl_get(kernel.process_table, process_id);
|
||||
if(process == NULL)
|
||||
{
|
||||
return S_NULL_POINTER;
|
||||
return S_DOESNT_EXIST;
|
||||
}
|
||||
else if(kernel->resource_table->limit >= process_id)
|
||||
if(kernel.active_process == process)
|
||||
{
|
||||
return S_OUT_OF_BOUNDS;
|
||||
kernel.active_process = NULL;
|
||||
}
|
||||
else if(kernel->resource_table->array[process_id].type != RESOURCE_PROCESS)
|
||||
{
|
||||
return S_INVALID_ARGUMENT;
|
||||
}
|
||||
struct process_t *process = &kernel->resource_table->array[process_id].process;
|
||||
kernel->resource_table->array[process_id].type = RESOURCE_UNAVAILABLE;
|
||||
if(kernel->active_process == process)
|
||||
{
|
||||
kernel->active_process = NULL;
|
||||
}
|
||||
queue_remove(kernel->priority_queue, process);
|
||||
kernel.process_table = avl_remove(kernel.process_table, process_id);
|
||||
queue_remove(&kernel.priority_queue, process);
|
||||
destroy_context(process->state);
|
||||
kfree(process);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
int accept_message(struct kernel_t *kernel, size_t process_id, struct message_t *message)
|
||||
/*
|
||||
int accept_message(size_t process_id, struct message_t *message)
|
||||
{
|
||||
if(kernel == NULL || message == NULL)
|
||||
if(message == NULL)
|
||||
{
|
||||
return S_NULL_POINTER;
|
||||
}
|
||||
@@ -153,7 +280,7 @@ int accept_message(struct kernel_t *kernel, size_t process_id, struct message_t
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
int send_message(struct kernel_t *kernel, size_t process_id, const struct message_t *message)
|
||||
int send_message(size_t process_id, const struct message_t *message)
|
||||
{
|
||||
if(kernel == NULL || message == NULL)
|
||||
{
|
||||
@@ -176,6 +303,7 @@ int send_message(struct kernel_t *kernel, size_t process_id, const struct messag
|
||||
struct message_t buffer = *message;
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
void panic(const char *message)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "memorymap.h"
|
||||
#include "memmap.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
int compare_regions(struct memory_region_t *lhs, struct memory_region_t *rhs)
|
||||
192
src/mmgr.c
Normal file
192
src/mmgr.c
Normal file
@@ -0,0 +1,192 @@
|
||||
#include "mmgr.h"
|
||||
#include "string.h"
|
||||
#include "platform/paging.h"
|
||||
#include "types/status.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* @brief Describes a stack containing the physical addresses of available page
|
||||
* frames.
|
||||
*
|
||||
*/
|
||||
struct page_stack_t
|
||||
{
|
||||
/**
|
||||
* @brief The total number of physical pages managed by the system.
|
||||
*
|
||||
*/
|
||||
size_t total_pages;
|
||||
|
||||
/**
|
||||
* @brief Points to the topmost physical address on the stack.
|
||||
*
|
||||
*/
|
||||
physaddr_t *stack_pointer;
|
||||
|
||||
/**
|
||||
* @brief Points to the bottom of the stack.
|
||||
*
|
||||
*/
|
||||
physaddr_t *base_pointer;
|
||||
|
||||
/**
|
||||
* @brief Points to the limit of the stack. The stack cannot grow beyond
|
||||
* this point.
|
||||
*
|
||||
*/
|
||||
physaddr_t *limit_pointer;
|
||||
|
||||
} page_stack;
|
||||
|
||||
int initialize_page_stack(struct memory_map_t *map, physaddr_t *stack_base)
|
||||
{
|
||||
page_stack.base_pointer = stack_base;
|
||||
page_stack.limit_pointer = stack_base;
|
||||
page_stack.stack_pointer = stack_base;
|
||||
page_stack.total_pages = 0;
|
||||
for(int i = 0; i < map->size; i++)
|
||||
{
|
||||
if(map->array[i].type != M_AVAILABLE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
size_t location = (map->array[i].location + page_size - 1) & ~(page_size - 1);
|
||||
while(location + page_size <= map->array[i].location + map->array[i].size)
|
||||
{
|
||||
if(free_page(location) != S_OK)
|
||||
{
|
||||
return S_OUT_OF_MEMORY;
|
||||
}
|
||||
page_stack.total_pages++;
|
||||
location += page_size;
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
physaddr_t reserve_page()
|
||||
{
|
||||
if(page_stack.stack_pointer > page_stack.base_pointer)
|
||||
{
|
||||
page_stack.stack_pointer--;
|
||||
physaddr_t frame = *page_stack.stack_pointer;
|
||||
*page_stack.stack_pointer = (physaddr_t) 0;
|
||||
return frame;
|
||||
}
|
||||
return S_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
int free_page(physaddr_t location)
|
||||
{
|
||||
if(page_stack.stack_pointer < page_stack.limit_pointer)
|
||||
{
|
||||
*page_stack.stack_pointer = location;
|
||||
page_stack.stack_pointer++;
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(map_page(page_stack.limit_pointer, 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:
|
||||
page_stack.limit_pointer += page_size / sizeof(*page_stack.limit_pointer);
|
||||
return S_OK;
|
||||
}
|
||||
return S_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
size_t free_page_count()
|
||||
{
|
||||
return page_stack.base_pointer - page_stack.stack_pointer;
|
||||
}
|
||||
|
||||
void *page_stack_bottom()
|
||||
{
|
||||
return (void*)page_stack.base_pointer;
|
||||
}
|
||||
|
||||
void *page_stack_top()
|
||||
{
|
||||
return (void*)page_stack.limit_pointer;
|
||||
}
|
||||
|
||||
physaddr_t create_address_space()
|
||||
{
|
||||
physaddr_t table = reserve_page();
|
||||
int result;
|
||||
if (table == S_OUT_OF_MEMORY)
|
||||
{
|
||||
return S_OUT_OF_MEMORY;
|
||||
}
|
||||
else if((result = paging_init_top_table(table)))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return table;
|
||||
}
|
||||
}
|
||||
|
||||
physaddr_t current_address_space()
|
||||
{
|
||||
return paging_current_address_space();
|
||||
}
|
||||
|
||||
int map_page(void *page, physaddr_t frame, int flags)
|
||||
{
|
||||
if (frame % page_size != 0)
|
||||
{
|
||||
return S_INVALID_ARGUMENT;
|
||||
}
|
||||
for(int level = 0; level < page_table_levels - 1; level++)
|
||||
{
|
||||
int present = get_pte_type(page, level) & PAGE_PRESENT;
|
||||
if(present == 0)
|
||||
{
|
||||
physaddr_t new_table = reserve_page();
|
||||
if(new_table == S_OUT_OF_MEMORY)
|
||||
{
|
||||
return S_OUT_OF_MEMORY;
|
||||
}
|
||||
set_pte(page, level, PAGE_PRESENT | PAGE_USERMODE | PAGE_RW, new_table);
|
||||
wipe_page_table(page, level + 1);
|
||||
}
|
||||
}
|
||||
set_pte(page, page_table_levels - 1, PAGE_PRESENT | flags, frame);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
physaddr_t unmap_page(void *page)
|
||||
{
|
||||
for(int level = 0; level < page_table_levels; level++)
|
||||
{
|
||||
if((get_pte_type(page, level) & PAGE_PRESENT) == 0)
|
||||
return S_OUT_OF_BOUNDS;
|
||||
}
|
||||
physaddr_t frame = get_pte_address(page, page_table_levels - 1);
|
||||
set_pte(page, page_table_levels - 1, 0, 0);
|
||||
return frame;
|
||||
}
|
||||
|
||||
int page_type(void *page)
|
||||
{
|
||||
for(int level = 0; level < page_table_levels - 1; level++)
|
||||
{
|
||||
int flags = get_pte_type(page, level);
|
||||
if((flags & PAGE_PRESENT) == 0)
|
||||
return flags;
|
||||
}
|
||||
return get_pte_type(page, page_table_levels - 1);
|
||||
}
|
||||
|
||||
physaddr_t physical_address(void *linear_address)
|
||||
{
|
||||
return get_pte_address(linear_address, page_table_levels - 1);
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
#include "pageallocator.h"
|
||||
#include "mmgr.h"
|
||||
#include "allocator.h"
|
||||
#include "types/status.h"
|
||||
|
||||
physaddr_t reserve_page(struct page_stack_t *stack)
|
||||
{
|
||||
if(stack->stack_pointer < stack->base_pointer)
|
||||
{
|
||||
physaddr_t frame = *stack->stack_pointer;
|
||||
*stack->stack_pointer = (physaddr_t) 0;
|
||||
stack->stack_pointer++;
|
||||
return frame;
|
||||
}
|
||||
return S_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
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_OK;
|
||||
}
|
||||
}
|
||||
return S_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
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, physaddr_t *stack_base)
|
||||
{
|
||||
stack->base_pointer = stack_base;
|
||||
stack->limit_pointer = stack_base;
|
||||
stack->stack_pointer = stack_base;
|
||||
stack->total_pages = 0;
|
||||
for(int i = 0; i < map->size; i++)
|
||||
{
|
||||
if(map->array[i].type != M_AVAILABLE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
size_t location = (map->array[i].location + page_size - 1) & ~(page_size - 1);
|
||||
while(location + page_size <= map->array[i].location + map->array[i].size)
|
||||
{
|
||||
if(free_page(stack, location) != S_OK)
|
||||
{
|
||||
return S_OUT_OF_MEMORY;
|
||||
}
|
||||
stack->total_pages++;
|
||||
location += page_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "priorityqueue.h"
|
||||
#include "allocator.h"
|
||||
#include "mmgr.h"
|
||||
#include "heap.h"
|
||||
#include "types/status.h"
|
||||
|
||||
void heapify(struct priority_queue_t *queue, size_t i)
|
||||
@@ -9,71 +8,68 @@ void heapify(struct priority_queue_t *queue, size_t i)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if(queue->heap[i * 2 + 1]->priority <= queue->heap[i]->priority
|
||||
&& queue->heap[i * 2 + 1]->priority <= queue->heap[i * 2 + 2]->priority)
|
||||
else if(queue->heap[i * 2 + 1].priority <= queue->heap[i].priority
|
||||
&& queue->heap[i * 2 + 1].priority <= queue->heap[i * 2 + 2].priority)
|
||||
{
|
||||
struct process_t *buffer = queue->heap[i];
|
||||
struct priority_queue_node_t buffer = queue->heap[i];
|
||||
queue->heap[i] = queue->heap[i * 2 + 1];
|
||||
queue->heap[i * 2 + 1] = buffer;
|
||||
heapify(queue, i * 2 + 1);
|
||||
}
|
||||
else if(queue->heap[i * 2 + 2]->priority <= queue->heap[i]->priority
|
||||
&& queue->heap[i * 2 + 2]->priority <= queue->heap[i * 2 + 1]->priority)
|
||||
else if(queue->heap[i * 2 + 2].priority <= queue->heap[i].priority
|
||||
&& queue->heap[i * 2 + 2].priority <= queue->heap[i * 2 + 1].priority)
|
||||
{
|
||||
struct process_t *buffer = queue->heap[i];
|
||||
struct priority_queue_node_t buffer = queue->heap[i];
|
||||
queue->heap[i] = queue->heap[i * 2 + 2];
|
||||
queue->heap[i * 2 + 2] = buffer;
|
||||
heapify(queue, i * 2 + 2);
|
||||
}
|
||||
}
|
||||
|
||||
int construct_priority_queue(struct priority_queue_t *queue, struct page_stack_t *page_stack)
|
||||
int construct_priority_queue(struct priority_queue_t *queue, int capacity)
|
||||
{
|
||||
queue->heap = allocate_from_bottom(page_size);
|
||||
queue->heap = kmalloc(sizeof(struct priority_queue_node_t) * capacity);
|
||||
if(queue->heap == NULL)
|
||||
{
|
||||
return S_OUT_OF_MEMORY;
|
||||
}
|
||||
int status = map_page(page_stack, queue->heap, reserve_page(page_stack), PAGE_RW);
|
||||
if(status == S_OK)
|
||||
{
|
||||
queue->capacity = page_size / sizeof(struct process_t*);
|
||||
queue->size = 0;
|
||||
}
|
||||
return status;
|
||||
queue->capacity = capacity;
|
||||
queue->size = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
struct process_t *extract_min(struct priority_queue_t *queue)
|
||||
void *extract_min(struct priority_queue_t *queue)
|
||||
{
|
||||
if(queue->size == 0)
|
||||
return NULL;
|
||||
queue->size--;
|
||||
struct process_t *p = queue->heap[0];
|
||||
void *value = queue->heap[0].value;
|
||||
queue->heap[0] = queue->heap[queue->size];
|
||||
heapify(queue, 0);
|
||||
return p;
|
||||
return value;
|
||||
}
|
||||
|
||||
int queue_insert(struct priority_queue_t *queue, struct process_t *process)
|
||||
int queue_insert(struct priority_queue_t *queue, void *value, int priority)
|
||||
{
|
||||
if(queue->size == queue->capacity)
|
||||
return S_OUT_OF_MEMORY;
|
||||
size_t i = queue->size;
|
||||
queue->size++;
|
||||
while(i > 0 && queue->heap[(i - 1) / 2]->priority > process->priority)
|
||||
while(i > 0 && queue->heap[(i - 1) / 2].priority > priority)
|
||||
{
|
||||
queue->heap[i] = queue->heap[(i - 1) / 2];
|
||||
i = (i - 1) / 2;
|
||||
}
|
||||
queue->heap[i] = process;
|
||||
queue->heap[i].priority = priority;
|
||||
queue->heap[i].value = value;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
int queue_remove(struct priority_queue_t *queue, struct process_t *process)
|
||||
int queue_remove(struct priority_queue_t *queue, void *value)
|
||||
{
|
||||
for(size_t i = 0; i < queue->size; i++)
|
||||
{
|
||||
if(queue->heap[i] == process)
|
||||
if(queue->heap[i].value == value)
|
||||
{
|
||||
queue->size--;
|
||||
queue->heap[i] = queue->heap[queue->size];
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
#include "resource.h"
|
||||
#include "mmgr.h"
|
||||
#include "allocator.h"
|
||||
#include "types/status.h"
|
||||
|
||||
int construct_resource_table(struct resource_table_t *table, struct page_stack_t *page_stack)
|
||||
{
|
||||
if(table == NULL)
|
||||
{
|
||||
return S_NULL_POINTER;
|
||||
}
|
||||
void *table_ptr = allocate_from_bottom(page_size);
|
||||
if(table_ptr == NULL)
|
||||
{
|
||||
return S_OUT_OF_MEMORY;
|
||||
}
|
||||
int status = map_page(page_stack, table_ptr, reserve_page(page_stack), PAGE_RW);
|
||||
if(status == S_OK)
|
||||
{
|
||||
table->array = (struct resource_t*)table_ptr;
|
||||
table->limit = (struct resource_t*)(table_ptr + page_size);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int get_free_resource_slot(struct resource_table_t *table, struct page_stack_t *page_stack)
|
||||
{
|
||||
if(table == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
size_t capacity = table->limit - table->array;
|
||||
for(int i = 0; i < capacity; i++)
|
||||
{
|
||||
if(table->array[i].type == RESOURCE_UNAVAILABLE)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
void *new_limit = allocate_from_bottom(page_size);
|
||||
if(new_limit != NULL)
|
||||
{
|
||||
if(map_page(page_stack, new_limit, reserve_page(page_stack), PAGE_RW) != S_OK)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
table->limit = (struct resource_t*)(new_limit + page_size);
|
||||
return get_free_resource_slot(table, page_stack);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "stdio.h"
|
||||
#include "platform/putc.h"
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
@@ -4,14 +4,17 @@
|
||||
#include "stdio.h"
|
||||
#include "types/status.h"
|
||||
|
||||
size_t test_syscall(struct kernel_t *kernel, size_t arg1, size_t arg2, size_t arg3)
|
||||
size_t test_syscall(syscall_arg_t str)
|
||||
{
|
||||
printf("%s", (char*)arg1);
|
||||
printf("%s", (char*)str.ptr);
|
||||
return 17;
|
||||
}
|
||||
|
||||
size_t mmap(struct kernel_t *kernel, size_t location, size_t length, size_t flags)
|
||||
size_t mmap(syscall_arg_t arg_location, syscall_arg_t arg_length, syscall_arg_t arg_flags)
|
||||
{
|
||||
unsigned long location = arg_location.unsigned_int;
|
||||
unsigned long length = arg_length.unsigned_int;
|
||||
unsigned long flags = arg_flags.unsigned_int;
|
||||
if(location % page_size != 0 || length % page_size != 0)
|
||||
{
|
||||
return S_INVALID_ARGUMENT;
|
||||
@@ -22,7 +25,7 @@ size_t mmap(struct kernel_t *kernel, size_t location, size_t length, size_t flag
|
||||
}
|
||||
for(size_t i = 0; i < length; i += page_size)
|
||||
{
|
||||
if(page_type((void*)(location + i)) != PAGE_NOT_PRESENT)
|
||||
if(page_type((void*)(location + i)) & PAGE_PRESENT)
|
||||
{
|
||||
return S_EXISTS;
|
||||
}
|
||||
@@ -31,12 +34,12 @@ size_t mmap(struct kernel_t *kernel, size_t location, size_t length, size_t flag
|
||||
int status = S_OK;
|
||||
while(n < length && status == S_OK)
|
||||
{
|
||||
physaddr_t frame = reserve_page(kernel->page_stack);
|
||||
physaddr_t frame = reserve_page();
|
||||
status = frame % page_size;
|
||||
if(status == S_OK)
|
||||
{
|
||||
status = map_page(kernel->page_stack, (void*)(location + n), frame, PAGE_USERMODE | PAGE_RW);
|
||||
if(status != S_OK && free_page(kernel->page_stack, frame) != S_OK)
|
||||
status = map_page((void*)(location + n), frame, PAGE_USERMODE | PAGE_RW);
|
||||
if(status != S_OK && free_page(frame) != S_OK)
|
||||
{
|
||||
panic("critical error reached during mmap.");
|
||||
}
|
||||
@@ -47,15 +50,17 @@ size_t mmap(struct kernel_t *kernel, size_t location, size_t length, size_t flag
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(status != S_OK && munmap(kernel, location, page_size, NULL) != S_OK)
|
||||
if(status != S_OK && munmap(arg_location, arg_length) != S_OK)
|
||||
{
|
||||
panic("critical error reached during mmap.");
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
size_t munmap(struct kernel_t *kernel, size_t location, size_t length, size_t arg3)
|
||||
size_t munmap(syscall_arg_t arg_location, syscall_arg_t arg_length)
|
||||
{
|
||||
unsigned long location = arg_location.unsigned_int;
|
||||
unsigned long length = arg_length.unsigned_int;
|
||||
if(location % page_size != 0 || length % page_size != 0)
|
||||
{
|
||||
return S_INVALID_ARGUMENT;
|
||||
@@ -68,21 +73,21 @@ size_t munmap(struct kernel_t *kernel, size_t location, size_t length, size_t ar
|
||||
int status = S_OK;
|
||||
while(n < length && status == S_OK)
|
||||
{
|
||||
enum page_type_t type = page_type((void*)(location + n));
|
||||
int type = page_type((void*)(location + n));
|
||||
physaddr_t frame;
|
||||
if(type != PAGE_NOT_PRESENT)
|
||||
if(type & PAGE_PRESENT)
|
||||
{
|
||||
frame = unmap_page((void*)(location + n));
|
||||
}
|
||||
if(type == PAGE_ANON)
|
||||
{
|
||||
status = free_page(kernel->page_stack, frame);
|
||||
if(type & PAGE_ANON)
|
||||
{
|
||||
status = free_page(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
size_t terminate_self(struct kernel_t *kernel, size_t arg1, size_t arg2, size_t arg3)
|
||||
size_t terminate_self()
|
||||
{
|
||||
return terminate_process(kernel, kernel->active_process->resource_id);
|
||||
return terminate_process(active_process());
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "mmgr.h"
|
||||
#include "allocator.h"
|
||||
#include "x86/apic.h"
|
||||
#include "x86/msr.h"
|
||||
#include "stdio.h"
|
||||
@@ -7,9 +6,9 @@
|
||||
|
||||
extern int _kernel_end;
|
||||
|
||||
struct apic_registers_t volatile *apic_registers;
|
||||
struct apic_registers_t volatile apic_registers __attribute__ ((aligned (4096)));
|
||||
|
||||
void apic_enable(struct page_stact_t *page_stack)
|
||||
void apic_enable()
|
||||
{
|
||||
// Remap and mask 8259 PIC
|
||||
asm volatile(
|
||||
@@ -32,18 +31,19 @@ void apic_enable(struct page_stact_t *page_stack)
|
||||
"outb %%al, $0x21;"
|
||||
::: "al"
|
||||
);
|
||||
printf("APIC register size: %04x\n", sizeof(struct apic_register_t));
|
||||
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);
|
||||
map_page(&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 | 0x1FF;
|
||||
apic_registers->destination_format.value = 0xFFFFFFFF;
|
||||
apic_registers.spurious_iv.value = apic_registers.spurious_iv.value | 0x1FF;
|
||||
apic_registers.destination_format.value = 0xFFFFFFFF;
|
||||
printf("Finished enabling APIC.\n");
|
||||
}
|
||||
|
||||
void apic_eoi()
|
||||
{
|
||||
apic_registers->eoi.value = 0;
|
||||
apic_registers.eoi.value = 0;
|
||||
}
|
||||
|
||||
void apic_send_ipi(
|
||||
@@ -65,7 +65,7 @@ void apic_send_ipi(
|
||||
.destination = destination
|
||||
};
|
||||
uint32_t *value_addr = (uint32_t*) &value;
|
||||
uint32_t *icr_addr = (uint32_t*)&apic_registers->interrput_command;
|
||||
uint32_t *icr_addr = (uint32_t*)&apic_registers.interrput_command;
|
||||
icr_addr[4] = value_addr[4];
|
||||
icr_addr[0] = value_addr[0];
|
||||
}
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
#include "context.h"
|
||||
#include "pageallocator.h"
|
||||
#include "platform/context.h"
|
||||
#include "mmgr.h"
|
||||
#include "string.h"
|
||||
#include "x86/processstate.h"
|
||||
|
||||
void *initialize_context(void *task_entry, struct page_stack_t *page_stack)
|
||||
void *initialize_context(void *task_entry)
|
||||
{
|
||||
map_page(page_stack, (void*)NULL, reserve_page(page_stack), PAGE_RW);
|
||||
map_page(page_stack, (void*)0xFF7FF000, reserve_page(page_stack), PAGE_RW | PAGE_USERMODE);
|
||||
unmap_page((void*)0xFF7FE000);
|
||||
/*
|
||||
* TODO: this implementation is a goddamn mess.
|
||||
* Stack pointer is hardcoded, and the stack isn't resizable.
|
||||
* PCB pointer is just a constant.
|
||||
*/
|
||||
map_page(NULL, reserve_page(), PAGE_RW);
|
||||
map_page((void*)0xFF3FF000, reserve_page(), PAGE_RW | PAGE_USERMODE);
|
||||
unmap_page((void*)0xFF3FE000);
|
||||
uint32_t flags;
|
||||
asm("pushf; "
|
||||
"mov (%%esp), %0; "
|
||||
@@ -20,7 +24,12 @@ void *initialize_context(void *task_entry, struct page_stack_t *page_stack)
|
||||
state->eip = (uint32_t)task_entry;
|
||||
state->flags = (flags & ~0xFD) | 0x200;
|
||||
state->ss = 0x23;
|
||||
state->esp = 0xFF800000;
|
||||
state->ebp = 0xFF800000;
|
||||
state->esp = 0xFF400000;
|
||||
state->ebp = 0xFF400000;
|
||||
return (void*)state;
|
||||
}
|
||||
|
||||
void destroy_context(void *ctx)
|
||||
{
|
||||
// Nothing to do...
|
||||
}
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
.set tagEntryType, 3
|
||||
.set tagEntrySize, 12
|
||||
.set tagEntryAddress, _start - (0xFF800000 - 0x100000)
|
||||
.set tagEntryAddress, _entry_paddr
|
||||
|
||||
.set tagModuleAlignType, 6
|
||||
.set tagModuleAlignSize, 8
|
||||
@@ -150,6 +150,10 @@ _start:
|
||||
mov $PHYSICAL_BASE, %eax
|
||||
push %eax
|
||||
|
||||
# Push kernel's starting linear address
|
||||
mov $VIRTUAL_BASE, %eax
|
||||
push %eax
|
||||
|
||||
# Load physical address of startPaging()
|
||||
mov $start_paging, %eax
|
||||
sub $BASE_DIFF, %eax
|
||||
@@ -171,15 +175,15 @@ _start:
|
||||
|
||||
# Change EBX to point to the virtual address of the multiboot info
|
||||
# If the new pointer is out-of-bounds, error
|
||||
add $0xFF700000, %ebx
|
||||
cmp $0xFF800000, %ebx
|
||||
add $BASE_DIFF, %ebx
|
||||
cmp $VIRTUAL_BASE, %ebx
|
||||
jl .err
|
||||
cmp $0xFFC00000, %ebx
|
||||
jge .err
|
||||
|
||||
# Call initialize(void* multibootInfo)
|
||||
# Call x86_startup(void* multibootInfo)
|
||||
push %ebx
|
||||
call initialize
|
||||
call x86_startup
|
||||
|
||||
.err:
|
||||
cli
|
||||
|
||||
259
src/x86/idt.c
Normal file
259
src/x86/idt.c
Normal file
@@ -0,0 +1,259 @@
|
||||
#include "x86/idt.h"
|
||||
#include "x86/isr.h"
|
||||
#include "string.h"
|
||||
#include "system.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#define idt_size 256
|
||||
#define gdt_size 7
|
||||
|
||||
extern int default_page_dir;
|
||||
|
||||
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 granularity : 1;
|
||||
unsigned int base_high : 8;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct tss_entry_t
|
||||
{
|
||||
uint32_t prev_tss;
|
||||
uint32_t esp0;
|
||||
uint32_t ss0;
|
||||
uint32_t esp1;
|
||||
uint32_t ss1;
|
||||
uint32_t esp2;
|
||||
uint32_t ss2;
|
||||
uint32_t cr3;
|
||||
uint32_t eip;
|
||||
uint32_t eflags;
|
||||
uint32_t eax;
|
||||
uint32_t ecx;
|
||||
uint32_t edx;
|
||||
uint32_t ebx;
|
||||
uint32_t esp;
|
||||
uint32_t ebp;
|
||||
uint32_t esi;
|
||||
uint32_t edi;
|
||||
uint32_t es;
|
||||
uint32_t cs;
|
||||
uint32_t ss;
|
||||
uint32_t ds;
|
||||
uint32_t fs;
|
||||
uint32_t gs;
|
||||
uint32_t ldt;
|
||||
uint16_t trap;
|
||||
uint16_t iomap_base;
|
||||
};
|
||||
|
||||
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;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct descriptor_table_info_t
|
||||
{
|
||||
uint16_t size;
|
||||
void *location;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
void load_gdt(struct gdt_entry_t *gdt)
|
||||
{
|
||||
struct descriptor_table_info_t gdt_info;
|
||||
gdt_info.size = sizeof(struct gdt_entry_t) * 7 - 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)"
|
||||
:
|
||||
: "r"(&idt_info));
|
||||
}
|
||||
|
||||
void load_tr(uint16_t gdt_offset)
|
||||
{
|
||||
gdt_offset |= 3;
|
||||
asm("mov %0, %%ax; "
|
||||
"ltr %%ax; "
|
||||
:
|
||||
: "r"(gdt_offset));
|
||||
}
|
||||
|
||||
void create_interrupt_descriptor(struct interrupt_descriptor_t *descriptor, void *isr, enum isr_type_t type, uint32_t privilage, uint32_t selector)
|
||||
{
|
||||
if(type != INTERRPUT_TASK32)
|
||||
{
|
||||
descriptor->offset_1 = (uint32_t) isr & 0xFFFF;
|
||||
descriptor->offset_2 = (uint32_t) isr >> 16;
|
||||
}
|
||||
descriptor->selector = selector;
|
||||
descriptor->zero = 0;
|
||||
descriptor->type = type;
|
||||
descriptor->storage = 0;
|
||||
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->granularity = 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->granularity = 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->granularity = 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->granularity = 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->granularity = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void initialize_gdt()
|
||||
{
|
||||
static struct gdt_entry_t gdt[gdt_size];
|
||||
static struct tss_entry_t tss;
|
||||
static struct tss_entry_t double_fault_tss;
|
||||
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_entry_t) - 1, SEGMENT_TSS);
|
||||
create_segment_descriptor(&gdt[6], (size_t)&double_fault_tss, sizeof(struct tss_entry_t) - 1, SEGMENT_TSS);
|
||||
memset(&tss, 0, sizeof(tss));
|
||||
memset(&double_fault_tss, 0, sizeof(tss));
|
||||
tss.esp0 = (uint32_t)&stack_top;
|
||||
tss.ss0 = 0x10;
|
||||
double_fault_tss.esp0 = (uint32_t)&stack_top;
|
||||
double_fault_tss.ss0 = 0x10;
|
||||
double_fault_tss.esp = (uint32_t)&stack_top;
|
||||
double_fault_tss.cs = 0x08;
|
||||
double_fault_tss.ds = 0x10;
|
||||
double_fault_tss.ss = 0x10;
|
||||
double_fault_tss.fs = 0x10;
|
||||
double_fault_tss.gs = 0x10;
|
||||
double_fault_tss.cr3 = (uint32_t)&default_page_dir - (uint32_t)&_kernel_start + (uint32_t)&_kernel_pstart;
|
||||
double_fault_tss.eip = (uint32_t)isr_double_fault;
|
||||
load_gdt(gdt);
|
||||
load_tr(5 * sizeof(struct gdt_entry_t));
|
||||
}
|
||||
|
||||
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, 8);
|
||||
}
|
||||
create_interrupt_descriptor(&idt[EXCEPTION_DIV_BY_0], (void*)isr_division_by_zero, INTERRPUT_INT32, 0, 8);
|
||||
create_interrupt_descriptor(&idt[EXCEPTION_SEGMENT_NOT_PRESENT], (void*)isr_segment_not_present, INTERRPUT_TRAP32, 0, 8);
|
||||
create_interrupt_descriptor(&idt[EXCEPTION_GPF], (void*)isr_gp_fault, INTERRPUT_TRAP32, 0, 8);
|
||||
create_interrupt_descriptor(&idt[EXCEPTION_PAGE_FAULT], (void*)isr_page_fault, INTERRPUT_TRAP32, 0, 8);
|
||||
create_interrupt_descriptor(&idt[EXCEPTION_DOUBLE_FAULT], /*(void*)isr_double_fault*/NULL, INTERRPUT_TASK32, 0, 8 * 6);
|
||||
create_interrupt_descriptor(&idt[ISR_PREEMPT], (void*)isr_preempt, INTERRPUT_INT32, 3, 8);
|
||||
create_interrupt_descriptor(&idt[ISR_APIC_TIMER], (void*)isr_timer, INTERRPUT_INT32, 0, 8);
|
||||
create_interrupt_descriptor(&idt[ISR_SYSCALL], (void*)isr_syscall, INTERRPUT_INT32, 3, 8);
|
||||
load_idt(idt);
|
||||
}
|
||||
@@ -1,256 +1,18 @@
|
||||
#include "x86/interrupts.h"
|
||||
#include "x86/isr.h"
|
||||
#include "string.h"
|
||||
#include "system.h"
|
||||
#include <stddef.h>
|
||||
#include "platform/interrupts.h"
|
||||
#include "x86/apic.h"
|
||||
|
||||
#define idt_size 256
|
||||
#define gdt_size 6
|
||||
|
||||
extern int default_page_dir;
|
||||
|
||||
enum segment_type_t
|
||||
int initialize_interrupts()
|
||||
{
|
||||
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 granularity : 1;
|
||||
unsigned int base_high : 8;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct tss_entry_t
|
||||
{
|
||||
uint32_t prev_tss;
|
||||
uint32_t esp0;
|
||||
uint32_t ss0;
|
||||
uint32_t esp1;
|
||||
uint32_t ss1;
|
||||
uint32_t esp2;
|
||||
uint32_t ss2;
|
||||
uint32_t cr3;
|
||||
uint32_t eip;
|
||||
uint32_t eflags;
|
||||
uint32_t eax;
|
||||
uint32_t ecx;
|
||||
uint32_t edx;
|
||||
uint32_t ebx;
|
||||
uint32_t esp;
|
||||
uint32_t ebp;
|
||||
uint32_t esi;
|
||||
uint32_t edi;
|
||||
uint32_t es;
|
||||
uint32_t cs;
|
||||
uint32_t ss;
|
||||
uint32_t ds;
|
||||
uint32_t fs;
|
||||
uint32_t gs;
|
||||
uint32_t ldt;
|
||||
uint16_t trap;
|
||||
uint16_t iomap_base;
|
||||
};
|
||||
|
||||
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;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct descriptor_table_info_t
|
||||
{
|
||||
uint16_t size;
|
||||
void *location;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
void load_gdt(struct gdt_entry_t *gdt)
|
||||
{
|
||||
struct descriptor_table_info_t gdt_info;
|
||||
gdt_info.size = sizeof(struct gdt_entry_t) * 7 - 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));
|
||||
apic_enable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void load_idt(struct interrupt_descriptor_t *idt)
|
||||
void irq_enable()
|
||||
{
|
||||
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)"
|
||||
:
|
||||
: "r"(&idt_info));
|
||||
asm("sti");
|
||||
}
|
||||
|
||||
void load_tr(uint16_t gdt_offset)
|
||||
void irq_disable()
|
||||
{
|
||||
gdt_offset |= 3;
|
||||
asm("mov %0, %%ax; "
|
||||
"ltr %%ax; "
|
||||
:
|
||||
: "r"(gdt_offset));
|
||||
}
|
||||
|
||||
void create_interrupt_descriptor(struct interrupt_descriptor_t *descriptor, void *isr, enum isr_type_t type, uint32_t privilage, uint32_t selector)
|
||||
{
|
||||
if(type != INTERRPUT_TASK32)
|
||||
{
|
||||
descriptor->offset_1 = (uint32_t) isr & 0xFFFF;
|
||||
descriptor->offset_2 = (uint32_t) isr >> 16;
|
||||
}
|
||||
descriptor->selector = selector;
|
||||
descriptor->zero = 0;
|
||||
descriptor->type = type;
|
||||
descriptor->storage = 0;
|
||||
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->granularity = 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->granularity = 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->granularity = 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->granularity = 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->granularity = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void initialize_gdt()
|
||||
{
|
||||
static struct gdt_entry_t gdt[gdt_size];
|
||||
static struct tss_entry_t tss;
|
||||
static struct tss_entry_t double_fault_tss;
|
||||
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_entry_t) - 1, SEGMENT_TSS);
|
||||
create_segment_descriptor(&gdt[6], (size_t)&double_fault_tss, sizeof(struct tss_entry_t) - 1, SEGMENT_TSS);
|
||||
memset(&tss, 0, sizeof(tss));
|
||||
memset(&double_fault_tss, 0, sizeof(tss));
|
||||
tss.esp0 = &stack_top;
|
||||
tss.ss0 = 0x10;
|
||||
double_fault_tss.esp0 = &stack_top;
|
||||
double_fault_tss.ss0 = 0x10;
|
||||
double_fault_tss.esp = &stack_top;
|
||||
double_fault_tss.cs = 0x08;
|
||||
double_fault_tss.ds = 0x10;
|
||||
double_fault_tss.ss = 0x10;
|
||||
double_fault_tss.cr3 = &default_page_dir;
|
||||
double_fault_tss.eip = (void*)isr_double_fault;
|
||||
load_gdt(gdt);
|
||||
load_tr(5 * sizeof(struct gdt_entry_t));
|
||||
}
|
||||
|
||||
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, 8);
|
||||
}
|
||||
create_interrupt_descriptor(&idt[EXCEPTION_DIV_BY_0], (void*)isr_division_by_zero, INTERRPUT_INT32, 0, 8);
|
||||
create_interrupt_descriptor(&idt[EXCEPTION_GPF], (void*)isr_gp_fault, INTERRPUT_TRAP32, 0, 8);
|
||||
create_interrupt_descriptor(&idt[EXCEPTION_PAGE_FAULT], (void*)isr_page_fault, INTERRPUT_TRAP32, 0, 8);
|
||||
create_interrupt_descriptor(&idt[EXCEPTION_DOUBLE_FAULT], (void*)isr_double_fault, INTERRPUT_TASK32, 0, 8 * 6);
|
||||
create_interrupt_descriptor(&idt[ISR_PREEMPT], (void*)isr_preempt, INTERRPUT_INT32, 3, 8);
|
||||
create_interrupt_descriptor(&idt[ISR_APIC_TIMER], (void*)isr_timer, INTERRPUT_INT32, 0, 8);
|
||||
create_interrupt_descriptor(&idt[ISR_SYSCALL], (void*)isr_syscall, INTERRPUT_INT32, 3, 8);
|
||||
load_idt(idt);
|
||||
asm("cli");
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
#include "kernel.h"
|
||||
#include "x86/isr.h"
|
||||
#include "stdio.h"
|
||||
#include "x86/apic.h"
|
||||
#include "x86/processstate.h"
|
||||
#include "context.h"
|
||||
#include "platform/interrupts.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct interrupt_frame_t
|
||||
{
|
||||
size_t eip;
|
||||
size_t cs;
|
||||
size_t eflags;
|
||||
size_t esp;
|
||||
size_t ss;
|
||||
uint32_t eip;
|
||||
uint32_t cs;
|
||||
uint32_t eflags;
|
||||
uint32_t esp;
|
||||
uint32_t ss;
|
||||
};
|
||||
|
||||
void isr_generic(struct interrupt_frame_t *frame)
|
||||
@@ -24,9 +24,16 @@ void isr_division_by_zero(struct interrupt_frame_t *frame)
|
||||
printf("Exception: Division by zero\n");
|
||||
}
|
||||
|
||||
void isr_segment_not_present(struct interrupt_frame_t *frame, unsigned int error)
|
||||
{
|
||||
irq_disable();
|
||||
printf("Exception: NP fault, code %08x\n", error);
|
||||
asm("hlt");
|
||||
}
|
||||
|
||||
void isr_gp_fault(struct interrupt_frame_t *frame, unsigned int error)
|
||||
{
|
||||
asm("cli");
|
||||
irq_disable();
|
||||
asm("mov $0x10, %%ax; "
|
||||
"mov %%ax, %%ds; "
|
||||
"mov %%ax, %%es; "
|
||||
@@ -39,7 +46,7 @@ void isr_gp_fault(struct interrupt_frame_t *frame, unsigned int error)
|
||||
|
||||
void isr_page_fault(struct interrupt_frame_t *frame, unsigned int error)
|
||||
{
|
||||
size_t addr;
|
||||
uint32_t addr;
|
||||
asm("mov %%cr2, %0"
|
||||
: "=r"(addr));
|
||||
asm("mov $0x10, %%ax; "
|
||||
@@ -54,8 +61,7 @@ void isr_page_fault(struct interrupt_frame_t *frame, unsigned int error)
|
||||
|
||||
void isr_double_fault(struct interrupt_frame_t *frame, unsigned int error)
|
||||
{
|
||||
asm("cli");
|
||||
|
||||
irq_disable();
|
||||
printf("Exception: Double fault (!!), code %08x\n", error);
|
||||
asm("hlt");
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0xFF800000;
|
||||
. = 0xFF400000;
|
||||
VIRTUAL_BASE = .;
|
||||
PHYSICAL_BASE = 0x100000;
|
||||
BASE_DIFF = VIRTUAL_BASE - PHYSICAL_BASE;
|
||||
@@ -38,4 +38,5 @@ SECTIONS
|
||||
_kernel_pend = PHYSICAL_BASE + (4096 * IMAGE_SIZE);
|
||||
_kernel_start = VIRTUAL_BASE;
|
||||
_kernel_end = VIRTUAL_BASE + (4096 * IMAGE_SIZE);
|
||||
_entry_paddr = _start - _kernel_start + _kernel_pstart;
|
||||
}
|
||||
|
||||
162
src/x86/mmgr.c
162
src/x86/mmgr.c
@@ -1,162 +0,0 @@
|
||||
#include "mmgr.h"
|
||||
#include "pageallocator.h"
|
||||
#include "string.h"
|
||||
#include "types/status.h"
|
||||
#include <stdint.h>
|
||||
|
||||
const size_t page_size = 4096;
|
||||
|
||||
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 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 type : 2;
|
||||
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 + 1024;
|
||||
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);
|
||||
if (table == S_OUT_OF_MEMORY)
|
||||
{
|
||||
return S_OUT_OF_MEMORY;
|
||||
}
|
||||
struct page_table_entry_t buffer = page_directory[0];
|
||||
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].physical_address = table >> page_bits;
|
||||
page_tables[1023].present = 1;
|
||||
page_tables[1023].rw = 1;
|
||||
page_directory[0] = buffer;
|
||||
asm volatile("invlpg 0xFFC00000" ::
|
||||
: "memory");
|
||||
return table;
|
||||
}
|
||||
|
||||
void load_address_space(physaddr_t table)
|
||||
{
|
||||
asm volatile("mov %0, %%cr3"
|
||||
:
|
||||
: "r"(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)
|
||||
{
|
||||
return S_OUT_OF_BOUNDS;
|
||||
}
|
||||
size_t table_index = (size_t)page / page_size;
|
||||
size_t directory_index = table_index / (page_size / sizeof(struct page_table_entry_t));
|
||||
if (!page_directory[directory_index].present)
|
||||
{
|
||||
physaddr_t new_table = reserve_page(page_stack);
|
||||
if (new_table == S_OUT_OF_MEMORY)
|
||||
{
|
||||
return S_OUT_OF_MEMORY;
|
||||
}
|
||||
page_directory[directory_index].physical_address = new_table >> page_bits;
|
||||
page_directory[directory_index].present = 1;
|
||||
page_directory[directory_index].usermode = (directory_index < 1022) ? 1 : 0;
|
||||
page_directory[directory_index].rw = 1;
|
||||
}
|
||||
page_tables[table_index].physical_address = frame >> 12;
|
||||
page_tables[table_index].present = 1;
|
||||
page_tables[table_index].usermode = (flags & PAGE_USERMODE) ? 1 : 0;
|
||||
page_tables[table_index].rw = (flags & PAGE_RW) ? 1 : 0;
|
||||
page_tables[table_index].type = PAGE_ANON;
|
||||
asm volatile("invlpg (%0)"
|
||||
:
|
||||
: "r"(page)
|
||||
: "memory");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
physaddr_t unmap_page(void *page)
|
||||
{
|
||||
if ((size_t)page % page_size != 0)
|
||||
{
|
||||
return S_INVALID_ARGUMENT;
|
||||
}
|
||||
size_t table_index = (size_t)page / page_size;
|
||||
size_t directory_index = table_index / (page_size / sizeof(struct page_table_entry_t));
|
||||
if (!page_directory[directory_index].present || !page_tables[table_index].present)
|
||||
{
|
||||
return S_OUT_OF_BOUNDS;
|
||||
}
|
||||
else
|
||||
{
|
||||
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)"
|
||||
:
|
||||
: "r"(page)
|
||||
: "memory");
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
|
||||
enum page_type_t page_type(void *page)
|
||||
{
|
||||
size_t table_index = (size_t)page / page_size;
|
||||
size_t directory_index = table_index / (page_size / sizeof(struct page_table_entry_t));
|
||||
if (!page_directory[directory_index].present || !page_tables[table_index].present)
|
||||
{
|
||||
return PAGE_NOT_PRESENT;
|
||||
}
|
||||
else
|
||||
{
|
||||
return page_tables[table_index].type;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,74 @@
|
||||
#include "x86/multiboot2.h"
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void *read_multiboot_table(struct boot_info_t *boot_info, void *table)
|
||||
enum multiboot2_tag_types
|
||||
{
|
||||
MB_END_TAG = 0,
|
||||
MB_BOOT_COMMAND = 1,
|
||||
MB_BOOTLOADER = 2,
|
||||
MB_MODULE = 3,
|
||||
MB_MEMORY_INFO = 4,
|
||||
MB_BIOS_BOOT_DEVICE = 5,
|
||||
MB_MEMORY_MAP = 6,
|
||||
MB_VBE = 7,
|
||||
MB_FRAMEBUFFER = 8,
|
||||
MB_ELF_SYMBOLS = 9,
|
||||
MB_APM = 10,
|
||||
MB_EFI32_SYSTEM_TABLE = 11,
|
||||
MB_EFI64_SYSTEM_TABLE = 12,
|
||||
MB_SMBIOS = 13,
|
||||
MB_ACPI10_RSDP = 14,
|
||||
MB_ACPT20_RSDP = 15,
|
||||
MB_NETOWRK = 16,
|
||||
MB_EFI_MEMORY_MAP = 17,
|
||||
MB_EFI_BOOT_SERVICES = 18,
|
||||
MB_EFI32_IMAGE = 19,
|
||||
MB_EFI64_IMAGE = 20,
|
||||
MB_LOAD_ADDRESS = 21
|
||||
};
|
||||
|
||||
enum multiboot2_memory_types
|
||||
{
|
||||
MB_AVAILABLE = 1,
|
||||
MB_ACPI = 3,
|
||||
MB_DEFECTIVE = 5
|
||||
};
|
||||
|
||||
struct multiboot2_string_t
|
||||
{
|
||||
uint32_t type;
|
||||
uint32_t size;
|
||||
char str;
|
||||
};
|
||||
|
||||
struct multiboot2_module_t
|
||||
{
|
||||
uint32_t type;
|
||||
uint32_t size;
|
||||
uint32_t start;
|
||||
uint32_t end;
|
||||
char str;
|
||||
};
|
||||
|
||||
struct multiboot2_map_entry_t
|
||||
{
|
||||
uint64_t base;
|
||||
uint64_t length;
|
||||
uint32_t type;
|
||||
};
|
||||
|
||||
struct multiboot2_memory_map_t
|
||||
{
|
||||
uint32_t type;
|
||||
uint32_t size;
|
||||
uint32_t entry_size;
|
||||
uint32_t entry_version;
|
||||
struct multiboot2_map_entry_t entries;
|
||||
};
|
||||
|
||||
void *read_multiboot_table_entry(struct boot_info_t *boot_info, void *table)
|
||||
{
|
||||
uint32_t *int_table = (uint32_t *)table;
|
||||
switch (*int_table)
|
||||
@@ -49,3 +115,14 @@ void *read_multiboot_table(struct boot_info_t *boot_info, void *table)
|
||||
size_t size = (int_table[1] + 7) - ((int_table[1] + 7) % 8);
|
||||
return table + size;
|
||||
}
|
||||
|
||||
void *read_multiboot_table(struct boot_info_t *boot_info, void *table)
|
||||
{
|
||||
void *multiboot_end = table + *(uint32_t*)table;
|
||||
table += 8;
|
||||
while (table != NULL)
|
||||
{
|
||||
table = read_multiboot_table_entry(boot_info, table);
|
||||
}
|
||||
return multiboot_end;
|
||||
}
|
||||
|
||||
196
src/x86/paging.c
Normal file
196
src/x86/paging.c
Normal file
@@ -0,0 +1,196 @@
|
||||
#include "platform/paging.h"
|
||||
#include "string.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
struct page_table_entry_t
|
||||
{
|
||||
uint32_t present : 1;
|
||||
uint32_t rw : 1;
|
||||
uint32_t usermode : 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 type : 2;
|
||||
uint32_t physical_address : 20;
|
||||
};
|
||||
|
||||
extern int _kernel_start;
|
||||
|
||||
const size_t page_size = 4096;
|
||||
|
||||
const size_t page_bits = 12;
|
||||
|
||||
const size_t page_table_levels = 2;
|
||||
|
||||
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;
|
||||
|
||||
struct page_table_entry_t *get_pte_pointer(void *page, int level)
|
||||
{
|
||||
unsigned int directory_index = (unsigned int)page >> 22;
|
||||
struct page_table_entry_t *entry = NULL;
|
||||
if(level == 0)
|
||||
{
|
||||
entry = &page_directory[directory_index];
|
||||
}
|
||||
else if(level == 1 && page_directory[directory_index].present)
|
||||
{
|
||||
unsigned int page_index = (unsigned int)page >> page_bits;
|
||||
entry = &page_tables[page_index];
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
int start_paging(void *linear_addr, physaddr_t start, physaddr_t end, uint32_t *directory, uint32_t *table, uint32_t *identity_table)
|
||||
{
|
||||
unsigned int directory_index = (unsigned int) linear_addr >> 22;
|
||||
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[directory_index] = ((uint32_t)table) + 3 + 1024;
|
||||
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;
|
||||
}
|
||||
|
||||
int paging_init_top_table(physaddr_t table)
|
||||
{
|
||||
struct page_table_entry_t buffer = page_directory[0];
|
||||
page_directory[0].physical_address = table >> page_bits;
|
||||
asm volatile("invlpg 0xFFC00000" ::
|
||||
: "memory");
|
||||
memset((void *)page_tables, 0, page_size);
|
||||
int last_index = (page_size / sizeof(struct page_table_entry_t)) - 1;
|
||||
int kernel_index = (size_t)&_kernel_start >> 22;
|
||||
for(int i = kernel_index; i < last_index; i++)
|
||||
{
|
||||
page_tables[i] = page_directory[i];
|
||||
}
|
||||
page_tables[last_index].physical_address = table >> page_bits;
|
||||
page_tables[last_index].present = 1;
|
||||
page_tables[last_index].rw = 1;
|
||||
page_directory[0] = buffer;
|
||||
asm volatile("invlpg 0xFFC00000" ::
|
||||
: "memory");
|
||||
return 0;
|
||||
}
|
||||
|
||||
physaddr_t paging_current_address_space()
|
||||
{
|
||||
return page_directory[1023].physical_address << page_bits;
|
||||
}
|
||||
|
||||
void paging_load_address_space(physaddr_t table)
|
||||
{
|
||||
asm volatile("mov %0, %%cr3"
|
||||
:
|
||||
: "r"(table)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
int get_pte_type(void *page, int level)
|
||||
{
|
||||
struct page_table_entry_t *entry = get_pte_pointer(page, level);
|
||||
if(entry != NULL)
|
||||
{
|
||||
int flags = (entry->present ? PAGE_PRESENT | PAGE_EXECUTABLE : 0)
|
||||
| (entry->rw ? PAGE_RW : 0)
|
||||
| (entry->usermode ? PAGE_USERMODE : 0);
|
||||
return flags;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int set_pte_type(void *page, int level, int flags)
|
||||
{
|
||||
struct page_table_entry_t *entry = get_pte_pointer(page, level);
|
||||
if(entry != NULL)
|
||||
{
|
||||
entry->present = PAGE_PRESENT ? 1 : 0;
|
||||
entry->rw = PAGE_RW ? 1 : 0;
|
||||
entry->usermode = PAGE_USERMODE ? 1 : 0;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
physaddr_t get_pte_address(void *page, int level)
|
||||
{
|
||||
struct page_table_entry_t *entry = get_pte_pointer(page, level);
|
||||
if(entry != NULL)
|
||||
{
|
||||
return entry->physical_address << page_bits | ((size_t)page & 0xFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int set_pte_address(void *page, int level, physaddr_t addr)
|
||||
{
|
||||
struct page_table_entry_t *entry = get_pte_pointer(page, level);
|
||||
if(entry != NULL)
|
||||
{
|
||||
entry->physical_address = addr >> page_bits;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int set_pte(void *page, int level, int flags, physaddr_t addr)
|
||||
{
|
||||
if(set_pte_address(page, level, addr) == 0)
|
||||
{
|
||||
return set_pte_type(page, level, flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void wipe_page_table(void *page, int level)
|
||||
{
|
||||
if(level == 1 && (get_pte_type(page, 0) & PAGE_PRESENT) != 0)
|
||||
{
|
||||
unsigned int table_index = ((unsigned int)page >> page_bits) & ~0x3FF;
|
||||
for(int i = 0; i < 1024; i++)
|
||||
{
|
||||
page_tables[table_index + i].present = 0;
|
||||
page_tables[table_index + i].physical_address = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,14 +8,13 @@ isr_syscall:
|
||||
push %ecx
|
||||
push %ebx
|
||||
push %eax
|
||||
push $kernel_state
|
||||
mov $0x10, %ax
|
||||
mov %ax, %ds
|
||||
mov %ax, %es
|
||||
mov %ax, %fs
|
||||
mov %ax, %gs
|
||||
call do_syscall
|
||||
add $0x14, %esp
|
||||
add $0x10, %esp
|
||||
mov $0x23, %cx
|
||||
mov %cx, %ds
|
||||
mov %cx, %es
|
||||
@@ -32,7 +31,6 @@ isr_preempt:
|
||||
call save_context
|
||||
add $8, %esp
|
||||
push $0x800
|
||||
push $kernel_state
|
||||
call next_process
|
||||
add $8, %esp
|
||||
push %eax
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#include "stdio.h"
|
||||
#include "platform/putc.h"
|
||||
#include "mmgr.h"
|
||||
#include "allocator.h"
|
||||
#include <stddef.h>
|
||||
|
||||
enum vga_color_t {
|
||||
VGA_COLOR_BLACK = 0,
|
||||
@@ -30,17 +28,17 @@ struct cell_t
|
||||
char bg : 4;
|
||||
};
|
||||
|
||||
struct cell_t *screen = (struct cell_t*)NULL;
|
||||
size_t cursor = 0;
|
||||
unsigned int cursor = 0;
|
||||
|
||||
const size_t tab_width = 4;
|
||||
const size_t line_width = 80;
|
||||
const size_t line_count = 25;
|
||||
const unsigned int tab_width = 4;
|
||||
const unsigned int line_width = 80;
|
||||
const unsigned int line_count = 25;
|
||||
|
||||
struct cell_t screen[4096 / sizeof(struct cell_t)] __attribute__ ((aligned (4096)));
|
||||
|
||||
int initialize_screen()
|
||||
{
|
||||
screen = allocate_from_bottom(page_size);
|
||||
map_page(NULL, screen, 0x000B8000, PAGE_RW);
|
||||
return map_page(screen, 0x000B8000, PAGE_RW);
|
||||
}
|
||||
|
||||
int putchar(int c)
|
||||
|
||||
@@ -1,29 +1,11 @@
|
||||
#include "kernel.h"
|
||||
#include "pageallocator.h"
|
||||
#include "allocator.h"
|
||||
#include "mmgr.h"
|
||||
#include "priorityqueue.h"
|
||||
#include "x86/multiboot2.h"
|
||||
#include "memorymap.h"
|
||||
#include "x86/apic.h"
|
||||
#include "x86/interrupts.h"
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
#include "module.h"
|
||||
#include "x86/idt.h"
|
||||
#include "system.h"
|
||||
#include "syscalls.h"
|
||||
#include "config.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
struct kernel_t kernel_state;
|
||||
|
||||
int initialize(void *multiboot_info)
|
||||
void x86_startup(void *multiboot_info)
|
||||
{
|
||||
initialize_gdt();
|
||||
initialize_idt();
|
||||
initialize_allocator(&_kernel_end, (void*)0xFFC00000);
|
||||
static struct page_stack_t page_stack;
|
||||
struct memory_region_t map_array[24];
|
||||
char bootloader_name[64];
|
||||
char kernel_parameters[64];
|
||||
@@ -35,42 +17,12 @@ int initialize(void *multiboot_info)
|
||||
.array = map_array,
|
||||
.size = 0,
|
||||
.capacity = 24}};
|
||||
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, (physaddr_t)&_kernel_pstart, (physaddr_t)&_kernel_pend - (physaddr_t)&_kernel_pstart, M_UNAVAILABLE);
|
||||
initialize_gdt();
|
||||
initialize_idt();
|
||||
void *multiboot_end = read_multiboot_table(&boot_info, multiboot_info);
|
||||
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++)
|
||||
{
|
||||
printf("%i\t\t\t%08x\t\t%u\n", boot_info.map.array[i].type, boot_info.map.array[i].location, boot_info.map.array[i].size);
|
||||
}*/
|
||||
initialize_page_stack(&page_stack, &boot_info.map, (physaddr_t*)0xFFC00000);
|
||||
static struct priority_queue_t priority_queue;
|
||||
construct_priority_queue(&priority_queue, &page_stack);
|
||||
static struct resource_table_t resource_table;
|
||||
construct_resource_table(&resource_table, &page_stack);
|
||||
construct_kernel_state(&kernel_state, &page_stack, &priority_queue, &resource_table, boot_info.module_count, boot_info.modules);
|
||||
memset(syscall_table, 0, sizeof(syscall_t)*32);
|
||||
syscall_table[SYSCALL_TEST] = test_syscall;
|
||||
syscall_table[SYSCALL_MMAP] = mmap;
|
||||
syscall_table[SYSCALL_MUNMAP] = munmap;
|
||||
apic_enable(page_stack);
|
||||
/*apic_registers->divide_config.value = APIC_DIVIDE_1;
|
||||
apic_registers->lvt_timer.timer_mode = APIC_TIMER_PERIODIC;
|
||||
apic_registers->lvt_timer.vector = ISR_PREEMPT;
|
||||
apic_registers->lvt_timer.mask = 0;
|
||||
apic_registers->initial_count.value = 1024*1024;*/
|
||||
asm("sti");
|
||||
load_context(next_process(&kernel_state, NULL));
|
||||
while(1) asm("hlt");
|
||||
|
||||
kernel_initialize(&boot_info);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user