diff --git a/.gitignore b/.gitignore index 0db5efa..4f70696 100755 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,6 @@ stamp-h1 rootfs/apps test/ -doc/ \ No newline at end of file +doc/ +bochsrc +bx_enh_dbg.ini \ No newline at end of file diff --git a/configure.ac b/configure.ac index 6ed9f7e..4cd90c7 100644 --- a/configure.ac +++ b/configure.ac @@ -5,7 +5,7 @@ AC_PREREQ([2.69]) AC_INIT([quark-kernel], [pre-alpha]) AM_INIT_AUTOMAKE([-Wall foreign subdir-objects]) AC_CONFIG_SRCDIR([src/kernel.c]) -AC_CONFIG_HEADERS([src/config.h]) +AC_CONFIG_HEADERS([include/config.h]) # Checks for programs. AC_PROG_CC diff --git a/include/allocator.h b/include/allocator.h deleted file mode 100644 index ad6172e..0000000 --- a/include/allocator.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include - -void initialize_allocator(void *bottom, void *top); - -void *allocate_from_bottom(size_t size); - -void *allocate_from_top(size_t size); diff --git a/include/avltree.h b/include/avltree.h new file mode 100644 index 0000000..c248241 --- /dev/null +++ b/include/avltree.h @@ -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); \ No newline at end of file diff --git a/include/context.h b/include/context.h deleted file mode 100644 index 8f321d9..0000000 --- a/include/context.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include "pageallocator.h" -#include "process.h" - -void *initialize_context(void *task_entry, struct page_stack_t *page_stack); - -void save_context(struct process_state_t *context, void *ptr); - -void load_context(struct process_state_t *context); diff --git a/include/elf.h b/include/elf.h index 24146ea..14766da 100644 --- a/include/elf.h +++ b/include/elf.h @@ -1,6 +1,6 @@ #pragma once -#include "pageallocator.h" +#include "mmgr.h" #include "types/physaddr.h" #include @@ -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); diff --git a/include/heap.h b/include/heap.h new file mode 100644 index 0000000..43d35b2 --- /dev/null +++ b/include/heap.h @@ -0,0 +1,33 @@ +#pragma once + +#include "mmgr.h" +#include + +/** + * @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); diff --git a/include/kernel.h b/include/kernel.h index 635c5f8..0d1054e 100644 --- a/include/kernel.h +++ b/include/kernel.h @@ -1,31 +1,83 @@ #pragma once -#include "pageallocator.h" +#include "avltree.h" +#include "memmap.h" #include "priorityqueue.h" -#include "resource.h" -#include "module.h" -#include "process.h" +#include "mmgr.h" +#include "syscalls.h" #include -enum syscall_id_t +#define MAX_SYSCALL_ID 256 +#define module_limit 8 + +enum process_state_t { - SYSCALL_YIELD = 1 + PROCESS_ACTIVE, + PROCESS_WAITING +}; + +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; + uint32_t param1, param2, param3; +}; + +struct process_t +{ + size_t priority; + size_t resource_id; + physaddr_t page_table; + struct process_context_t *state; + struct message_t *message; }; struct kernel_t { - struct page_stack_t *page_stack; - struct priority_queue_t *priority_queue; + struct syscall_t syscall_table[MAX_SYSCALL_ID]; + struct priority_queue_t priority_queue; + struct avltree_t *process_table; struct process_t *active_process; - struct resource_table_t *resource_table; + int next_pid; }; -extern struct kernel_t kernel_state; +void kernel_initialize(struct boot_info_t *boot_info); -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); -int load_module(struct kernel_t *kernel, struct module_t *module); +size_t do_syscall(enum syscall_id_t id, syscall_arg_t arg1, syscall_arg_t arg2, syscall_arg_t arg3); -struct process_state_t *next_process(struct kernel_t *kernel, struct process_state_t *prev_state); +int load_module(struct module_t *module); + +int active_process(); + +int add_process(void *program_entry, int priority, physaddr_t address_space); + +struct process_context_t *next_process(struct process_context_t *prev_state); + +int terminate_process(size_t process_id); + +/* +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)); diff --git a/include/memorymap.h b/include/memmap.h similarity index 90% rename from include/memorymap.h rename to include/memmap.h index 933b641..06967ad 100644 --- a/include/memorymap.h +++ b/include/memmap.h @@ -24,4 +24,4 @@ struct memory_map_t size_t capacity; }; -void insert_region(struct memory_map_t *map, physaddr_t location, size_t size, enum memory_type_t type); \ No newline at end of file +void insert_region(struct memory_map_t *map, physaddr_t location, size_t size, enum memory_type_t type); diff --git a/include/mmgr.h b/include/mmgr.h index 12e86c8..7df2fb5 100644 --- a/include/mmgr.h +++ b/include/mmgr.h @@ -1,17 +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 -}; +#include 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. * @@ -19,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 @@ -45,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 @@ -55,3 +94,19 @@ int map_page(struct page_stack_t *page_stack, void *page, physaddr_t frame, int * @return physaddr_t */ physaddr_t unmap_page(void *page); + +/** + * @brief + * + * @param page + * @return enum page_type_t + */ +int page_type(void *page); + +/** + * @brief + * + * @param linear_address + * @return physaddr_t + */ +physaddr_t physical_address(void *linear_address); diff --git a/include/module.h b/include/module.h deleted file mode 100644 index 4e0cc1a..0000000 --- a/include/module.h +++ /dev/null @@ -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)]; -}; \ No newline at end of file diff --git a/include/pageallocator.h b/include/pageallocator.h deleted file mode 100644 index 3bb71d3..0000000 --- a/include/pageallocator.h +++ /dev/null @@ -1,75 +0,0 @@ -#pragma once - -#include "memorymap.h" -#include "types/physaddr.h" -#include - -/** - * @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); diff --git a/include/platform/context.h b/include/platform/context.h new file mode 100644 index 0000000..f3fd65d --- /dev/null +++ b/include/platform/context.h @@ -0,0 +1,9 @@ +#pragma once + +void *initialize_context(void *task_entry); + +void destroy_context(void *ctx); + +void save_context(struct process_context_t *context, void *ptr); + +void load_context(struct process_context_t *context); diff --git a/include/platform/interrupts.h b/include/platform/interrupts.h new file mode 100644 index 0000000..8c76cd7 --- /dev/null +++ b/include/platform/interrupts.h @@ -0,0 +1,20 @@ +#pragma once + +/** + * @brief + * + * @return int + */ +int initialize_interrupts(); + +/** + * @brief + * + */ +void irq_enable(); + +/** + * @brief + * + */ +void irq_disable(); \ No newline at end of file diff --git a/include/platform/paging.h b/include/platform/paging.h new file mode 100644 index 0000000..9a67c26 --- /dev/null +++ b/include/platform/paging.h @@ -0,0 +1,96 @@ +#pragma once + +#include "types/physaddr.h" +#include + +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); \ No newline at end of file diff --git a/include/platform/putc.h b/include/platform/putc.h new file mode 100644 index 0000000..c2fdab9 --- /dev/null +++ b/include/platform/putc.h @@ -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); \ No newline at end of file diff --git a/include/priorityqueue.h b/include/priorityqueue.h index b15b45f..cb49fcb 100644 --- a/include/priorityqueue.h +++ b/include/priorityqueue.h @@ -1,11 +1,31 @@ #pragma once -#include "pageallocator.h" -#include "process.h" -#include +/** + * @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); diff --git a/include/process.h b/include/process.h deleted file mode 100644 index 8f545fb..0000000 --- a/include/process.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "types/physaddr.h" -#include - -struct process_state_t; - -struct process_t -{ - size_t priority; - struct process_state_t *state; - physaddr_t page_table; -}; \ No newline at end of file diff --git a/include/resource.h b/include/resource.h deleted file mode 100644 index dcf041c..0000000 --- a/include/resource.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include "pageallocator.h" -#include "process.h" -#include - -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); diff --git a/include/stdio.h b/include/stdio.h index e669124..bb123d7 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -2,12 +2,6 @@ #include -int initialize_screen(); - -int putchar(int c); - -int puts(const char *str); - int printf(const char *format, ...); int sprintf(char *str, const char *format, ...); \ No newline at end of file diff --git a/include/syscalls.h b/include/syscalls.h new file mode 100644 index 0000000..0a09101 --- /dev/null +++ b/include/syscalls.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include + +enum syscall_id_t +{ + SYSCALL_TEST = 1, + SYSCALL_YIELD, + SYSCALL_MMAP, + SYSCALL_MUNMAP, + SYSCALL_TERMINATE_SELF +}; + +typedef union +{ + long signed_int; + unsigned long unsigned_int; + void *ptr; +} syscall_arg_t; + +typedef size_t (*syscall_ptr_0_t)(); + +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(); diff --git a/include/types/status.h b/include/types/status.h index 4e45672..d80bfef 100644 --- a/include/types/status.h +++ b/include/types/status.h @@ -3,8 +3,12 @@ enum status_t { S_OK = 0, - S_BAD_SYSCALL, - S_OUT_OF_MEMORY, + S_NULL_POINTER, S_OUT_OF_BOUNDS, - S_NULL_POINTER + S_INVALID_ARGUMENT, + S_OUT_OF_MEMORY, + S_DOESNT_EXIST, + S_EXISTS, + S_BAD_SYSCALL, + S_BUSY }; \ No newline at end of file diff --git a/include/x86/apic.h b/include/x86/apic.h index 65e7739..04f2774 100644 --- a/include/x86/apic.h +++ b/include/x86/apic.h @@ -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(); diff --git a/include/x86/interrupts.h b/include/x86/idt.h similarity index 100% rename from include/x86/interrupts.h rename to include/x86/idt.h diff --git a/include/x86/isr.h b/include/x86/isr.h index a2377da..a28379b 100644 --- a/include/x86/isr.h +++ b/include/x86/isr.h @@ -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); diff --git a/include/x86/multiboot2.h b/include/x86/multiboot2.h index ce65ddb..968857e 100644 --- a/include/x86/multiboot2.h +++ b/include/x86/multiboot2.h @@ -1,84 +1,12 @@ #pragma once -#include "memorymap.h" -#include "module.h" -#include -#include - -#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); diff --git a/include/x86/processstate.h b/include/x86/processstate.h index a991ef1..e8c45cf 100644 --- a/include/x86/processstate.h +++ b/include/x86/processstate.h @@ -4,7 +4,7 @@ #define PCB_LOCATION 0x800 -struct process_state_t +struct process_context_t { uint32_t eax; uint32_t ebx; diff --git a/rootfs/boot/grub/grub.cfg b/rootfs/boot/grub/grub.cfg index 49fa9ae..e499f92 100644 --- a/rootfs/boot/grub/grub.cfg +++ b/rootfs/boot/grub/grub.cfg @@ -2,4 +2,6 @@ menuentry "Quark OS" { multiboot2 /apps/quark-kernel module2 /apps/quark-testmod module2 /apps/quark-testmod + module2 /apps/quark-testmod + module2 /apps/quark-testmod } \ No newline at end of file diff --git a/src/Makefile.am b/src/Makefile.am index 8f5c591..bdbd1e8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 +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 \ diff --git a/src/allocator.c b/src/allocator.c deleted file mode 100644 index 574b195..0000000 --- a/src/allocator.c +++ /dev/null @@ -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; -} diff --git a/src/avltree.c b/src/avltree.c new file mode 100644 index 0000000..41ae7c9 --- /dev/null +++ b/src/avltree.c @@ -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; + } +} \ No newline at end of file diff --git a/src/elf.c b/src/elf.c index 586fb21..e04110b 100644 --- a/src/elf.c +++ b/src/elf.c @@ -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, 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: @@ -30,11 +29,12 @@ int load_program(struct elf_file_header_t *elf, struct page_stack_t *page_stack) case S_OUT_OF_BOUNDS: return status; case S_OK: - memcpy(d, s, page_size); + memcpy(d + n, s + n, n + page_size < program_header->memsize ? page_size : program_header->memsize - n); } } } count--; program_header = (struct elf_program_header_t*)((void*)program_header + elf->phsize); } + return S_OK; } \ No newline at end of file diff --git a/src/heap.c b/src/heap.c new file mode 100644 index 0000000..79fde3a --- /dev/null +++ b/src/heap.c @@ -0,0 +1,176 @@ +#include +#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); +} diff --git a/src/kernel.c b/src/kernel.c index 4ca80aa..9c510c2 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -1,24 +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" -size_t do_syscall(struct kernel_t *kernel, enum syscall_id_t id, size_t arg1, size_t arg2, size_t arg3) -{ +struct kernel_t kernel; +void kernel_initialize(struct boot_info_t *boot_info) +{ + 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++) + { + 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)); } -int load_module(struct kernel_t *kernel, struct module_t *module) +int set_syscall(int id, int arg_count, int pid, void *func_ptr) { - physaddr_t module_address_space = create_address_space(kernel->page_stack); - load_address_space(module_address_space); + 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; + } + 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 module_t *module) +{ + 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: @@ -27,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: @@ -37,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) @@ -52,36 +179,132 @@ 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.state = module_context; - kernel->resource_table->array[index].process.page_table = current_address_space(); - queue_insert(kernel->priority_queue, &kernel->resource_table->array[index].process); - return S_OK; } -struct process_state_t *next_process(struct kernel_t *kernel, struct process_state_t *prev_state) +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(size_t process_id) +{ + struct process_t *process = avl_get(kernel.process_table, process_id); + if(process == NULL) + { + return S_DOESNT_EXIST; + } + if(kernel.active_process == process) + { + kernel.active_process = NULL; + } + 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(size_t process_id, struct message_t *message) +{ + if(message == NULL) + { + return S_NULL_POINTER; + } + else if(kernel->resource_table->limit >= process_id) + { + return S_OUT_OF_BOUNDS; + } + 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; + process->state = PROCESS_WAITING; + process->message = message; + if(kernel->active_process == process) + { + kernel->active_process = NULL; + } + queue_remove(kernel->priority_queue, process); + return S_OK; +} + +int send_message(size_t process_id, const struct message_t *message) +{ + if(kernel == NULL || message == NULL) + { + return S_NULL_POINTER; + } + else if(kernel->resource_table->limit >= process_id) + { + return S_OUT_OF_BOUNDS; + } + 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; + if(process->state != PROCESS_WAITING || process->message == NULL) + { + return S_BUSY; + } + queue_insert(kernel->priority_queue, kernel->active_process); + struct message_t buffer = *message; + +} +*/ + void panic(const char *message) { printf("panic: %s", message); diff --git a/src/memorymap.c b/src/memmap.c similarity index 99% rename from src/memorymap.c rename to src/memmap.c index ed32e6c..a1c9263 100644 --- a/src/memorymap.c +++ b/src/memmap.c @@ -1,4 +1,4 @@ -#include "memorymap.h" +#include "memmap.h" #include int compare_regions(struct memory_region_t *lhs, struct memory_region_t *rhs) @@ -133,4 +133,4 @@ void insert_region(struct memory_map_t *map, physaddr_t location, size_t size, u { i = trim_map(map, i); } -} \ No newline at end of file +} diff --git a/src/mmgr.c b/src/mmgr.c new file mode 100644 index 0000000..0525633 --- /dev/null +++ b/src/mmgr.c @@ -0,0 +1,192 @@ +#include "mmgr.h" +#include "string.h" +#include "platform/paging.h" +#include "types/status.h" +#include +#include + +/** + * @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); +} diff --git a/src/pageallocator.c b/src/pageallocator.c deleted file mode 100644 index 775a928..0000000 --- a/src/pageallocator.c +++ /dev/null @@ -1,68 +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) -{ - 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; - } - } -} diff --git a/src/priorityqueue.c b/src/priorityqueue.c index ed57038..5f62875 100644 --- a/src/priorityqueue.c +++ b/src/priorityqueue.c @@ -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]; diff --git a/src/resource.c b/src/resource.c deleted file mode 100644 index dc5b8b3..0000000 --- a/src/resource.c +++ /dev/null @@ -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; -} diff --git a/src/stdio.c b/src/stdio.c index 1e2165d..a487e3a 100644 --- a/src/stdio.c +++ b/src/stdio.c @@ -1,4 +1,5 @@ #include "stdio.h" +#include "platform/putc.h" #include #include diff --git a/src/syscalls.c b/src/syscalls.c new file mode 100644 index 0000000..2ae8a10 --- /dev/null +++ b/src/syscalls.c @@ -0,0 +1,93 @@ +#include "syscalls.h" +#include "kernel.h" +#include "mmgr.h" +#include "stdio.h" +#include "types/status.h" + +size_t test_syscall(syscall_arg_t str) +{ + printf("%s", (char*)str.ptr); + return 17; +} + +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; + } + else if(location == NULL) + { + return S_NULL_POINTER; + } + for(size_t i = 0; i < length; i += page_size) + { + if(page_type((void*)(location + i)) & PAGE_PRESENT) + { + return S_EXISTS; + } + } + size_t n = 0; + int status = S_OK; + while(n < length && status == S_OK) + { + physaddr_t frame = reserve_page(); + status = frame % page_size; + if(status == 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."); + } + n += page_size; + } + else + { + break; + } + } + if(status != S_OK && munmap(arg_location, arg_length) != S_OK) + { + panic("critical error reached during mmap."); + } + return status; +} + +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; + } + else if(location == 0) + { + return S_NULL_POINTER; + } + size_t n = 0; + int status = S_OK; + while(n < length && status == S_OK) + { + int type = page_type((void*)(location + n)); + physaddr_t frame; + if(type & PAGE_PRESENT) + { + frame = unmap_page((void*)(location + n)); + if(type & PAGE_ANON) + { + status = free_page(frame); + } + } + } + return status; +} + +size_t terminate_self() +{ + return terminate_process(active_process()); +} diff --git a/src/x86/apic.c b/src/x86/apic.c index 8eb82da..7944f2d 100644 --- a/src/x86/apic.c +++ b/src/x86/apic.c @@ -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]; } diff --git a/src/x86/context.c b/src/x86/context.c index 36d6ed0..2387392 100644 --- a/src/x86/context.c +++ b/src/x86/context.c @@ -1,26 +1,35 @@ -#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; " "popf; " : "=r"(flags)); - struct process_state_t *state = (struct process_state_t*)PCB_LOCATION; + struct process_context_t *state = (struct process_context_t*)PCB_LOCATION; memset(NULL, 0, page_size); state->cs = 0x1B; 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... +} \ No newline at end of file diff --git a/src/x86/entry.S b/src/x86/entry.S index 4ef8462..7a27a00 100755 --- a/src/x86/entry.S +++ b/src/x86/entry.S @@ -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 diff --git a/src/x86/idt.c b/src/x86/idt.c new file mode 100644 index 0000000..6b9d1be --- /dev/null +++ b/src/x86/idt.c @@ -0,0 +1,259 @@ +#include "x86/idt.h" +#include "x86/isr.h" +#include "string.h" +#include "system.h" +#include + +#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); +} diff --git a/src/x86/interrupts.c b/src/x86/interrupts.c index ff0f9f9..e3cb7c6 100644 --- a/src/x86/interrupts.c +++ b/src/x86/interrupts.c @@ -1,256 +1,18 @@ -#include "x86/interrupts.h" -#include "x86/isr.h" -#include "string.h" -#include "system.h" -#include +#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, 0, 8); - load_idt(idt); -} + asm("cli"); +} \ No newline at end of file diff --git a/src/x86/isr.c b/src/x86/isr.c index 5bff31a..9371383 100644 --- a/src/x86/isr.c +++ b/src/x86/isr.c @@ -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 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"); } @@ -65,7 +71,3 @@ void isr_timer(struct interrupt_frame_t *frame) printf("Timer tick.\n"); apic_eoi(); } - -void isr_syscall(struct interrupt_frame_t *frame) -{ -} \ No newline at end of file diff --git a/src/x86/linker.ld b/src/x86/linker.ld index f13451d..c0c4709 100755 --- a/src/x86/linker.ld +++ b/src/x86/linker.ld @@ -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; } diff --git a/src/x86/mmgr.c b/src/x86/mmgr.c deleted file mode 100644 index 572abc2..0000000 --- a/src/x86/mmgr.c +++ /dev/null @@ -1,147 +0,0 @@ -#include "mmgr.h" -#include "pageallocator.h" -#include "string.h" -#include "types/status.h" -#include - -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 ignored : 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; - 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; - 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_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 || !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; - } -} \ No newline at end of file diff --git a/src/x86/multiboot2.c b/src/x86/multiboot2.c index a41fad5..fe83633 100644 --- a/src/x86/multiboot2.c +++ b/src/x86/multiboot2.c @@ -1,8 +1,74 @@ #include "x86/multiboot2.h" -#include "stdio.h" #include "string.h" +#include +#include -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; +} diff --git a/src/x86/paging.c b/src/x86/paging.c new file mode 100644 index 0000000..4d4cdb5 --- /dev/null +++ b/src/x86/paging.c @@ -0,0 +1,196 @@ +#include "platform/paging.h" +#include "string.h" + +#include + +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; + } + } +} diff --git a/src/x86/preempt.S b/src/x86/preempt.S index 47cc4c2..ededc1c 100644 --- a/src/x86/preempt.S +++ b/src/x86/preempt.S @@ -1,5 +1,27 @@ .section .text +.global isr_syscall +.type isr_syscall, @function +isr_syscall: + cli + push %edx + push %ecx + push %ebx + push %eax + mov $0x10, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + call do_syscall + add $0x10, %esp + mov $0x23, %cx + mov %cx, %ds + mov %cx, %es + mov %cx, %fs + mov %cx, %gs + iret + .global isr_preempt .type isr_preempt, @function isr_preempt: @@ -7,11 +29,10 @@ isr_preempt: push %esp push $0x800 call save_context - sub $8, %esp + add $8, %esp push $0x800 - push $kernel_state call next_process - sub $8, %esp + add $8, %esp push %eax call load_context \ No newline at end of file diff --git a/src/x86/putc.c b/src/x86/putc.c index fad6f72..e6eea77 100644 --- a/src/x86/putc.c +++ b/src/x86/putc.c @@ -1,7 +1,5 @@ -#include "stdio.h" +#include "platform/putc.h" #include "mmgr.h" -#include "allocator.h" -#include enum vga_color_t { VGA_COLOR_BLACK = 0, @@ -30,16 +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 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) @@ -62,6 +61,21 @@ int putchar(int c) screen[cursor].c = (char) c; cursor++; } + if(cursor >= line_count * line_width) + { + for(int i = 0; i < line_count * line_width; i++) + { + if(i < (line_count - 1) * line_width) + { + screen[i] = screen[i + line_width]; + } + else + { + screen[i].c = ' '; + } + } + cursor -= line_width; + } return c; } diff --git a/src/x86/quark_x86.c b/src/x86/quark_x86.c index b03ef31..47367ff 100644 --- a/src/x86/quark_x86.c +++ b/src/x86/quark_x86.c @@ -1,28 +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 "config.h" -#include -#include -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]; @@ -34,48 +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); - }*/ - page_stack.base_pointer = (physaddr_t*)0xFFC00000; - page_stack.stack_pointer = (physaddr_t*)0xFFC00000; - page_stack.limit_pointer = (physaddr_t*)0xFFC00000; - initialize_page_stack(&page_stack, &boot_info.map); - 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); - kernel_state.page_stack = &page_stack; - kernel_state.resource_table = &resource_table; - kernel_state.priority_queue = &priority_queue; - kernel_state.active_process = NULL; - for(int i = 0; i < boot_info.module_count; i++) - { - load_module(&kernel_state, &boot_info.modules[i]); - } - 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); }