From b55887a95d71fcb62992d21edd19c871dd00403c Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Mon, 30 Jun 2014 00:05:56 +0200 Subject: [PATCH 01/21] added bitmap allocator --- include/eduos/memory.h | 48 ++++++++++++++++++++ mm/memory.c | 101 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+) create mode 100644 include/eduos/memory.h diff --git a/include/eduos/memory.h b/include/eduos/memory.h new file mode 100644 index 0000000..9a5766a --- /dev/null +++ b/include/eduos/memory.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2010, Stefan Lankes, RWTH Aachen University + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @author Steffen Vogel + * @file include/memory.h + * @brief Memory related functions + * + * This file contains platform independent memory functions + */ + +#ifndef __MEMORY_H__ +#define __MEMORY_H__ + +/** @brief Initialize the memory subsystem */ +int memory_init(); + +/** @brief Request physical page frames */ +size_t get_pages(size_t npages); + +/** @brief release physical page frames */ +int put_pages(size_t phyaddr, size_t npages); + +#endif diff --git a/mm/memory.c b/mm/memory.c index 9b32356..6c40471 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -27,8 +27,21 @@ #include #include +#include + +#include +#include +#include + static char stack[MAX_TASKS-1][KERNEL_STACK_SIZE]; +static char bitmap[BITMAP_SIZE]; + +static spinlock_t bitmap_lock = SPINLOCK_INIT; + +atomic_int32_t total_pages = ATOMIC_INIT(0); +atomic_int32_t total_allocated_pages = ATOMIC_INIT(0); +atomic_int32_t total_available_pages = ATOMIC_INIT(0); void* create_stack(tid_t id) { @@ -41,3 +54,91 @@ void* create_stack(tid_t id) return (void*) stack[id-1]; } + +inline static int page_marked(size_t i) +{ + size_t index = i >> 3; + size_t mod = i & 0x7; + + return (bitmap[index] & (1 << mod)); +} + +inline static void page_set_mark(size_t i) +{ + size_t index = i >> 3; + size_t mod = i & 0x7; + + bitmap[index] = bitmap[index] | (1 << mod); +} + +inline static void page_clear_mark(size_t i) +{ + size_t index = i / 8; + size_t mod = i % 8; + + bitmap[index] = bitmap[index] & ~(1 << mod); +} + +size_t get_pages(size_t npages) +{ + size_t cnt, off; + + if (BUILTIN_EXPECT(!npages, 0)) + return 0; + if (BUILTIN_EXPECT(npages > atomic_int32_read(&total_available_pages), 0)) + return 0; + + spinlock_lock(&bitmap_lock); + + off = 1; + while (off <= BITMAP_SIZE*8 - npages) { + for (cnt=0; cnt> PAGE_BITS; + + if (BUILTIN_EXPECT(!phyaddr, 0)) + return -EINVAL; + if (BUILTIN_EXPECT(!npages, 0)) + return -EINVAL; + + spinlock_lock(&bitmap_lock); + + for (i=0; i Date: Mon, 30 Jun 2014 00:10:04 +0200 Subject: [PATCH 02/21] added bitmap initialization based on Multiboot infos --- arch/x86/include/asm/multiboot.h | 7 +++ kernel/main.c | 24 ++++++-- mm/memory.c | 95 ++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 6 deletions(-) diff --git a/arch/x86/include/asm/multiboot.h b/arch/x86/include/asm/multiboot.h index 4756db5..a4d5c23 100644 --- a/arch/x86/include/asm/multiboot.h +++ b/arch/x86/include/asm/multiboot.h @@ -41,6 +41,13 @@ #include +/// Does the bootloader provide mem_* fields? +#define MULTIBOOT_INFO_MEM (1 << 0) +/// Does the bootloader provide a list of modules? +#define MULTIBOOT_INFO_MODS (1 << 3) +/// Does the bootloader provide a full memory map? +#define MULTIBOOT_INFO_MEM_MAP (1 << 6) + typedef uint16_t multiboot_uint16_t; typedef uint32_t multiboot_uint32_t; typedef uint64_t multiboot_uint64_t; diff --git a/kernel/main.c b/kernel/main.c index 34b8642..dd84a8c 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -33,10 +33,14 @@ #include #include #include +#include + #include #include +#include +#include -/* +/* * Note that linker symbols are not variables, they have no memory allocated for * maintaining a value, rather their address is their value. */ @@ -47,6 +51,11 @@ extern const void bss_end; extern char __BUILD_DATE; extern char __BUILD_TIME; +/* Page frame counters */ +atomic_int32_t total_pages; +atomic_int32_t total_allocated_pages; +atomic_int32_t total_available_pages; + static void userfoo(void* arg) { char str[256]; @@ -91,6 +100,7 @@ static int eduos_init(void) // initialize .bss section memset((void*)&bss_start, 0x00, ((size_t) &bss_end - (size_t) &bss_start)); + memory_init(); system_init(); irq_init(); timer_init(); @@ -104,16 +114,18 @@ int main(void) { tid_t id1; tid_t id2; + eduos_init(); - - kprintf("This is eduOS %s Build %u, %u\n", EDUOS_VERSION, &__BUILD_DATE, &__BUILD_TIME); - kprintf("Kernel starts at %p and ends at %p\n", &kernel_start, &kernel_end); - irq_enable(); system_calibration(); + kprintf("This is eduOS %s Build %u, %u\n", EDUOS_VERSION, &__BUILD_DATE, &__BUILD_TIME); + kprintf("Kernel starts at %p and ends at %p\n", &kernel_start, &kernel_end); kprintf("Processor frequency: %u MHz\n", get_cpu_frequency()); - + kprintf("Total memory: %lu KiB\n", atomic_int32_read(&total_pages) * PAGE_SIZE / 1024); + kprintf("Total memory available: %lu KiB\n", atomic_int32_read(&total_available_pages) * PAGE_SIZE / 1024); + + create_kernel_task(&id1, foo, "foo1", NORMAL_PRIO); create_kernel_task(&id2, wrapper, "userfoo", NORMAL_PRIO); diff --git a/mm/memory.c b/mm/memory.c index 6c40471..072ba63 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -27,12 +27,20 @@ #include #include +#include +#include #include #include #include #include +/* + * Note that linker symbols are not variables, they have no memory allocated for + * maintaining a value, rather their address is their value. + */ +extern const void kernel_start; +extern const void kernel_end; static char stack[MAX_TASKS-1][KERNEL_STACK_SIZE]; static char bitmap[BITMAP_SIZE]; @@ -142,3 +150,90 @@ int put_pages(size_t phyaddr, size_t npages) return ret; } + +int memory_init(void) +{ + unsigned int i; + size_t addr; + int ret = 0; + + // mark all memory as used + memset(bitmap, 0xff, BITMAP_SIZE); + + if (mb_info) { + if (mb_info->flags & MULTIBOOT_INFO_MEM_MAP) { + multiboot_memory_map_t* mmap = (multiboot_memory_map_t*) ((size_t) mb_info->mmap_addr); + multiboot_memory_map_t* mmap_end = (void*) ((size_t) mb_info->mmap_addr + mb_info->mmap_length); + + // mark available memory as free + while (mmap < mmap_end) { + if (mmap->type == MULTIBOOT_MEMORY_AVAILABLE) { + for (addr=mmap->addr; addr < mmap->addr + mmap->len; addr += PAGE_SIZE) { + page_clear_mark(addr >> PAGE_BITS); + atomic_int32_inc(&total_pages); + atomic_int32_inc(&total_available_pages); + } + } + mmap++; + } + } + else if (mb_info->flags & MULTIBOOT_INFO_MEM) { + size_t page; + size_t pages_lower = mb_info->mem_lower >> 2; + size_t pages_upper = mb_info->mem_upper >> 2; + + for (page=0; page> PAGE_BITS); + atomic_int32_inc(&total_allocated_pages); + atomic_int32_dec(&total_available_pages); + + + if (mb_info->flags & MULTIBOOT_INFO_MODS) { + // mark modules list as used + for(addr=mb_info->mods_addr; addrmods_addr+mb_info->mods_count*sizeof(multiboot_module_t); addr+=PAGE_SIZE) { + page_set_mark(addr >> PAGE_BITS); + atomic_int32_inc(&total_allocated_pages); + atomic_int32_dec(&total_available_pages); + } + + // mark modules as used + multiboot_module_t* mmodule = (multiboot_module_t*) ((size_t) mb_info->mods_addr); + for(i=0; imods_count; i++) { + for(addr=mmodule[i].mod_start; addr> PAGE_BITS); + atomic_int32_inc(&total_allocated_pages); + atomic_int32_dec(&total_available_pages); + } + } + } + } + + // mark kernel as used + for(addr=(size_t) &kernel_start; addr<(size_t) &kernel_end; addr+=PAGE_SIZE) { + page_set_mark(addr >> PAGE_BITS); + atomic_int32_inc(&total_allocated_pages); + atomic_int32_dec(&total_available_pages); + } + + // enable paging and map SMP, VGA, Multiboot modules etc. + /*ret = page_init(); + if (BUILTIN_EXPECT(ret, 0)) + return ret; + */ + + return ret; +} From 153447482ab53947b1b0ead2640816804d94c0ec Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Mon, 30 Jun 2014 00:14:22 +0200 Subject: [PATCH 03/21] added headers for paging code --- arch/x86/include/asm/page.h | 154 +++++++++++++++++++++++++++++++ arch/x86/include/asm/processor.h | 29 ++++++ arch/x86/kernel/gdt.c | 1 + include/eduos/config.h.example | 1 - include/eduos/stddef.h | 4 - 5 files changed, 184 insertions(+), 5 deletions(-) create mode 100644 arch/x86/include/asm/page.h diff --git a/arch/x86/include/asm/page.h b/arch/x86/include/asm/page.h new file mode 100644 index 0000000..95a1701 --- /dev/null +++ b/arch/x86/include/asm/page.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2010, Stefan Lankes, RWTH Aachen University + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @author Steffen Vogel + * @file arch/x86/include/asm/page.h + * @brief Paging related functions + * + * This file contains the several functions to manage the page tables + */ + +#ifndef __PAGE_H__ +#define __PAGE_H__ + +/// Page offset bits +#define PAGE_BITS 12 +/// The size of a single page in bytes +#define PAGE_SIZE (1L << PAGE_BITS) + +/// Total operand width in bits +#define BITS 32 +/// Linear/virtual address width +#define VIRT_BITS BITS +/// Physical address width (we dont support PAE) +#define PHYS_BITS BITS +/// Page map bits +#define PAGE_MAP_BITS 10 +/// Number of page map indirections +#define PAGE_MAP_LEVELS 2 +/// Mask the page address without page map flags +#define PAGE_MASK 0xFFFFF000 + +/// The number of entries in a page map table +#define PAGE_MAP_ENTRIES (1L << PAGE_MAP_BITS) + +// Base addresses of the self-mapped pagetables +#define PAGE_MAP_PGD 0xFFFFF000 +#define PAGE_MAP_PGT 0xFFC00000 + +/// Page is present +#define PG_PRESENT (1 << 0) +/// Page is read- and writable +#define PG_RW (1 << 1) +/// Page is addressable from userspace +#define PG_USER (1 << 2) +/// Page write through is activated +#define PG_PWT (1 << 3) +/// Page cache is disabled +#define PG_PCD (1 << 4) +/// Page was recently accessed (set by CPU) +#define PG_ACCESSED (1 << 5) +/// Page is dirty due to recent write-access (set by CPU) +#define PG_DIRTY (1 << 6) +/// Huge page: 4MB (or 2MB, 1GB) +#define PG_PSE (1 << 7) +/// Page attribute table +#define PG_PAT PG_PSE +/// Global TLB entry (Pentium Pro and later) +#define PG_GLOBAL (1 << 8) +/// This page or table is used during the boot process +#define PG_BOOT (1 << 9) + +/// This is a whole set of flags (PRESENT,RW,ACCESSED,DIRTY) for kernelspace tables +#define PG_TABLE (PG_PRESENT|PG_RW) +/// This is a whole set of flags (PRESENT,RW,GLOBAL) for kernelspace pages +#define PG_PAGE (PG_PRESENT|PG_RW|PG_GLOBAL) + +/** @brief A single entry in a page map + * + * Usually used as a pointer to a mapped page map entry. + */ +typedef size_t page_entry_t; + +/** @brief Initialize paging subsystem + * + * This function uses the existing bootstrap page tables (boot_{pgd, pgt}) + * to map required regions (video memory, kernel, etc..). + * Before calling page_init(), the bootstrap tables contain a simple identity + * paging. Which is replaced by more specific mappings. + */ +int page_init(); + +/** @brief Map a continious region of pages + * + * @param viraddr + * @param phyaddr + * @param pages + * @param flags + * @return + */ +int page_map(size_t viraddr, size_t phyaddr, size_t pages, size_t flags); + +/** @brief Unmap a continious region of pages + * + * @param viraddr + * @param pages + * @return + */ +int page_unmap(size_t viraddr, size_t pages); + +/** @brief Copy a single page frame + * + * @param dest + * @param src + * @return + */ +int page_copy(size_t dest, size_t src); + +/** @brief Copy a whole page map tree + * + * @param dest + * @param src + * @return + */ +int page_map_copy(page_entry_t *dest, page_entry_t *src); + +/** @brief Free a whole page map tree + * + * @param map + */ +int page_map_drop(page_entry_t *map); + +/** @brief Converts a virtual address to a physical + * + * @param viraddr Virtual address to convert + * @return Physical address + */ +size_t virt_to_phys(size_t viraddr); + +#endif diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 76e5c78..e814be5 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -57,6 +57,23 @@ inline static uint64_t rdtsc(void) return x; } +/** @brief Read cr3 register + * @return cr3's value + */ +static inline size_t read_cr3(void) { + size_t val; + asm volatile("mov %%cr3, %0" : "=r"(val)); + return val; +} + +/** @brief Write a value into cr3 register + * @param val The value you want to write into cr3 + */ +static inline void write_cr3(size_t val) { + asm volatile("mov %0, %%cr3" : : "r"(val)); +} + + /** @brief Flush cache * * The wbinvd asm instruction which stands for "Write back and invalidate" @@ -66,6 +83,18 @@ inline static void flush_cache(void) { asm volatile ("wbinvd" : : : "memory"); } +/** @brief Flush Translation Lookaside Buffer + * + * Just reads cr3 and writes the same value back into it. + */ +static inline void flush_tlb(void) +{ + size_t val = read_cr3(); + + if (val) + write_cr3(val); +} + /** @brief Invalidate cache * * The invd asm instruction which invalidates cache without writing back diff --git a/arch/x86/kernel/gdt.c b/arch/x86/kernel/gdt.c index 43190af..7bf336f 100644 --- a/arch/x86/kernel/gdt.c +++ b/arch/x86/kernel/gdt.c @@ -34,6 +34,7 @@ #include #include #include +#include gdt_ptr_t gp; static tss_t task_state_segment __attribute__ ((aligned (PAGE_SIZE))); diff --git a/include/eduos/config.h.example b/include/eduos/config.h.example index 7bf80e7..df5b6f2 100644 --- a/include/eduos/config.h.example +++ b/include/eduos/config.h.example @@ -39,7 +39,6 @@ extern "C" { #define VIDEO_MEM_ADDR 0xB8000 // the video memora address #define CACHE_LINE 64 #define KERNEL_STACK_SIZE (8*1024) -#define PAGE_SHIFT 12 #define INT_SYSCALL 0x80 #define BYTE_ORDER LITTLE_ENDIAN diff --git a/include/eduos/stddef.h b/include/eduos/stddef.h index ca3fa70..e488668 100644 --- a/include/eduos/stddef.h +++ b/include/eduos/stddef.h @@ -46,10 +46,6 @@ extern "C" { /// represents a task identifier typedef unsigned int tid_t; -#define PAGE_SIZE (1 << PAGE_SHIFT) -#define PAGE_MASK ~(PAGE_SIZE - 1) -#define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK) - struct task; /// pointer to the current (running) task extern struct task* current_task; From 141e72035602cfe634fdae88fccb7c9c3da04ece Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Mon, 30 Jun 2014 00:18:31 +0200 Subject: [PATCH 04/21] added missing #define --- include/eduos/config.h.example | 1 + 1 file changed, 1 insertion(+) diff --git a/include/eduos/config.h.example b/include/eduos/config.h.example index df5b6f2..6ea0090 100644 --- a/include/eduos/config.h.example +++ b/include/eduos/config.h.example @@ -39,6 +39,7 @@ extern "C" { #define VIDEO_MEM_ADDR 0xB8000 // the video memora address #define CACHE_LINE 64 #define KERNEL_STACK_SIZE (8*1024) +#define BITMAP_SIZE (128<<5) /* for 128 MiB of RAM */ #define INT_SYSCALL 0x80 #define BYTE_ORDER LITTLE_ENDIAN From 2621c0b26188e03fab7de58dd8d993250a2a5552 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Mon, 30 Jun 2014 01:46:59 +0200 Subject: [PATCH 05/21] fixed comment capitalization, style and indentions --- arch/x86/kernel/entry.asm | 90 +++++++++++++++++++--------------- include/eduos/config.h.example | 10 ++-- mm/memory.c | 4 +- 3 files changed, 57 insertions(+), 47 deletions(-) diff --git a/arch/x86/kernel/entry.asm b/arch/x86/kernel/entry.asm index 19df613..f664e55 100644 --- a/arch/x86/kernel/entry.asm +++ b/arch/x86/kernel/entry.asm @@ -32,19 +32,20 @@ %include "config.inc" [BITS 32] + ; We use a special name to map this section at the begin of our kernel -; => Multiboot needs its magic number at the begin of the kernel +; => Multiboot expects its magic number at the beginning of the kernel. SECTION .mboot global start start: jmp stublet -; This part MUST be 4byte aligned, so we solve that issue using 'ALIGN 4' +; This part MUST be 4 byte aligned, so we solve that issue using 'ALIGN 4'. ALIGN 4 mboot: ; Multiboot macros to make a few lines more readable later - MULTIBOOT_PAGE_ALIGN equ 1<<0 - MULTIBOOT_MEMORY_INFO equ 1<<1 + MULTIBOOT_PAGE_ALIGN equ (1 << 0) + MULTIBOOT_MEMORY_INFO equ (1 << 1) MULTIBOOT_HEADER_MAGIC equ 0x1BADB002 MULTIBOOT_HEADER_FLAGS equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO MULTIBOOT_CHECKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) @@ -57,37 +58,44 @@ mboot: SECTION .text ALIGN 4 stublet: -; initialize stack pointer +; Initialize stack pointer mov esp, boot_stack add esp, KERNEL_STACK_SIZE-16 -; initialize cpu features +; Initialize CPU features call cpu_init -; interpret multiboot information +; Interpret multiboot information extern multiboot_init push ebx call multiboot_init add esp, 4 -; jump to the boot processors's C code +; Jump to the boot processors's C code extern main call main jmp $ +; This will set up the x86 control registers: +; Caching and the floating point unit are enabled global cpu_init cpu_init: - mov eax, cr0 -; enable caching, disable paging and fpu emulation - and eax, 0x1ffffffb -; ...and turn on FPU exceptions - or eax, 0x22 - mov cr0, eax ; clears the current pgd entry xor eax, eax mov cr3, eax -; at this stage, we disable the SSE support - mov eax, cr4 - and eax, 0xfffbf9ff + +; Set CR4 mov cr4, eax + and eax, ~(1 << 9) ; disable SSE + or eax, (1 << 4) ; enable PSE + mov cr4, eax + +; Set CR0 + mov eax, cr0 + and eax, ~(1 << 2) ; disable FPU emulation + and eax, ~(1 << 30) ; enable caching + or eax, (1 << 31) ; enable paging + or eax, (1 << 5) ; enable FPU exceptions + mov cr0, eax + ret ; This will set up our new segment registers. We need to do @@ -108,12 +116,12 @@ gdt_flush: flush2: ret -; The first 32 interrupt service routines (isr) entries correspond to exceptions. -; Some exceptions will push an error code onto the stack which is specific to +; The first 32 interrupt service routines (ISR) entries correspond to exceptions. +; Some exceptions will push an error code onto the stack which is specific to ; the exception caused. To decrease the complexity, we handle this by pushing a -; dummy error code of 0 onto the stack for any ISR that doesn't push an error -; code already. -; +; Dummy error code of 0 onto the stack for any ISR that doesn't push an error +; code already. +; ; ISRs are registered as "Interrupt Gate". ; Therefore, the interrupt flag (IF) is already cleared. @@ -136,8 +144,8 @@ flush2: jmp common_stub %endmacro -; create isr entries, where the number after the -; pseudo error code represents following interrupts +; Create isr entries, where the number after the +; pseudo error code represents following interrupts: ; 0: Divide By Zero Exception ; 1: Debug Exception ; 2: Non Maskable Interrupt Exception @@ -189,18 +197,16 @@ isrstub_pseudo_error 9 jmp common_stub %endmacro -; create entries for the interrupts 0 to 23 +; Create entries for the interrupts 0 to 23 %assign i 0 %rep 24 irqstub i %assign i i+1 %endrep -extern syscall_handler +; Used to realize system calls. +; By entering the handler, the interrupt flag is not cleared. global isrsyscall - -; used to realize system calls -; by entering the handler, the interrupt flag is not cleared isrsyscall: cli push es @@ -213,13 +219,14 @@ isrsyscall: push ebx push eax - ; set kernel data segmenets +; Set kernel data segmenets mov ax, 0x10 mov ds, ax mov es, ax mov eax, [esp] sti + extern syscall_handler call syscall_handler cli @@ -241,12 +248,12 @@ extern irq_handler extern get_current_stack extern finish_task_switch +; Create a pseudo interrupt on top of the stack. +; Afterwards, we switch to the task with iret. +; We already are in kernel space => no pushing of SS required. global switch_context ALIGN 4 switch_context: - ; create on the stack a pseudo interrupt - ; afterwards, we switch to the task with iret - ; we already in kernel space => no pushing of SS required mov eax, [esp+4] ; on the stack is already the address to store the old esp pushf ; push controll register push DWORD 0x8 ; CS @@ -263,8 +270,6 @@ ALIGN 4 rollback: ret -extern set_kernel_stack - ALIGN 4 common_stub: pusha @@ -274,8 +279,10 @@ common_stub: mov es, ax mov ds, ax - ; use the same handler for interrupts and exceptions +; Use the same handler for interrupts and exceptions push esp + + extern set_kernel_stack call irq_handler add esp, 4 @@ -287,15 +294,15 @@ common_switch: call get_current_stack ; get new esp xchg eax, esp - ; set task switched flag +; Set task switched flag mov eax, cr0 or eax, 8 mov cr0, eax - ; set esp0 in the task state segment +; Set esp0 in the task state segment call set_kernel_stack - ; call cleanup code +; Call cleanup code call finish_task_switch no_context_switch: @@ -305,9 +312,12 @@ no_context_switch: add esp, 8 iret +SECTION .data + global boot_stack ALIGN 4096 boot_stack: -TIMES (KERNEL_STACK_SIZE) DB 0xcd + TIMES (KERNEL_STACK_SIZE) DB 0xcd +; add some hints to the ELF file SECTION .note.GNU-stack noalloc noexec nowrite progbits diff --git a/include/eduos/config.h.example b/include/eduos/config.h.example index 6ea0090..1959693 100644 --- a/include/eduos/config.h.example +++ b/include/eduos/config.h.example @@ -34,15 +34,15 @@ extern "C" { #define EDUOS_VERSION "0.1" #define MAX_TASKS 16 -#define TIMER_FREQ 100 /* in HZ */ -#define CLOCK_TICK_RATE 1193182 /* 8254 chip's internal oscillator frequency */ -#define VIDEO_MEM_ADDR 0xB8000 // the video memora address +#define TIMER_FREQ 100 /* in HZ */ +#define CLOCK_TICK_RATE 1193182 /* 8254 chip's internal oscillator frequency */ +#define VIDEO_MEM_ADDR 0xB8000 /* the video memory address */ #define CACHE_LINE 64 -#define KERNEL_STACK_SIZE (8*1024) +#define KERNEL_STACK_SIZE (8<<10) /* 8 KiB */ #define BITMAP_SIZE (128<<5) /* for 128 MiB of RAM */ #define INT_SYSCALL 0x80 -#define BYTE_ORDER LITTLE_ENDIAN +#define BYTE_ORDER LITTLE_ENDIAN #define CONFIG_VGA diff --git a/mm/memory.c b/mm/memory.c index 072ba63..37489b9 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -179,14 +179,14 @@ int memory_init(void) } else if (mb_info->flags & MULTIBOOT_INFO_MEM) { size_t page; - size_t pages_lower = mb_info->mem_lower >> 2; + size_t pages_lower = mb_info->mem_lower >> 2; /* KiB to page number */ size_t pages_upper = mb_info->mem_upper >> 2; for (page=0; page Date: Mon, 30 Jun 2014 01:47:33 +0200 Subject: [PATCH 06/21] enabled paging by using a transparent idendity paging during boot --- arch/x86/kernel/entry.asm | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/entry.asm b/arch/x86/kernel/entry.asm index f664e55..7765620 100644 --- a/arch/x86/kernel/entry.asm +++ b/arch/x86/kernel/entry.asm @@ -76,10 +76,12 @@ stublet: ; This will set up the x86 control registers: ; Caching and the floating point unit are enabled +; Bootstrap page tables are loaded and page size +; extensions (huge pages) enabled. global cpu_init cpu_init: -; clears the current pgd entry - xor eax, eax +; Set CR3 + mov eax, boot_pgd mov cr3, eax ; Set CR4 @@ -319,5 +321,18 @@ ALIGN 4096 boot_stack: TIMES (KERNEL_STACK_SIZE) DB 0xcd +; Bootstrap page tables are used during the initialization. +; These tables do a simple identity paging and will +; be replaced in page_init() by more fine-granular mappings. +global boot_map +ALIGN 4096 +boot_map: +boot_pgd: + %assign i 0 + %rep 1024 + DD (i << 12) | 0x083 + %assign i i+1 + %endrep + ; add some hints to the ELF file SECTION .note.GNU-stack noalloc noexec nowrite progbits From 838ad909c69f634a4e92acc277fd17e16662fe2b Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Mon, 30 Jun 2014 12:15:52 +0200 Subject: [PATCH 07/21] replaced multiboot_init() by global pointer in entry.asm --- arch/x86/include/asm/multiboot.h | 4 +++- arch/x86/kernel/Makefile | 2 +- arch/x86/kernel/entry.asm | 10 ++++---- arch/x86/kernel/multiboot.c | 41 -------------------------------- 4 files changed, 10 insertions(+), 47 deletions(-) delete mode 100644 arch/x86/kernel/multiboot.c diff --git a/arch/x86/include/asm/multiboot.h b/arch/x86/include/asm/multiboot.h index a4d5c23..e5d2c19 100644 --- a/arch/x86/include/asm/multiboot.h +++ b/arch/x86/include/asm/multiboot.h @@ -150,6 +150,8 @@ struct multiboot_mod_list }; typedef struct multiboot_mod_list multiboot_module_t; -extern multiboot_info_t* mb_info; +/// Pointer to multiboot structure +/// This pointer is declared at set by entry.asm +extern multiboot_info_t* mb_info; #endif diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index b0c0676..2f4b45c 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -1,4 +1,4 @@ -C_source := tasks.c multiboot.c vga.c gdt.c irq.c idt.c isrs.c timer.c processor.c +C_source := tasks.c vga.c gdt.c irq.c idt.c isrs.c timer.c processor.c ASM_source := entry.asm string32.asm MODULE := arch_x86_kernel diff --git a/arch/x86/kernel/entry.asm b/arch/x86/kernel/entry.asm index 7765620..084f410 100644 --- a/arch/x86/kernel/entry.asm +++ b/arch/x86/kernel/entry.asm @@ -64,10 +64,7 @@ stublet: ; Initialize CPU features call cpu_init ; Interpret multiboot information - extern multiboot_init - push ebx - call multiboot_init - add esp, 4 + mov DWORD [mb_info], ebx ; Jump to the boot processors's C code extern main @@ -316,6 +313,11 @@ no_context_switch: SECTION .data +global mb_info: +ALIGN 4 +mb_info: + DD 0 + global boot_stack ALIGN 4096 boot_stack: diff --git a/arch/x86/kernel/multiboot.c b/arch/x86/kernel/multiboot.c deleted file mode 100644 index f6bd932..0000000 --- a/arch/x86/kernel/multiboot.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2010, Stefan Lankes, RWTH Aachen University - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include - -/* - * eduOS is able to use Multiboot (http://www.gnu.org/software/grub/manual/multiboot/), - * which specifies an interface between a boot loader and a operating system - */ - -multiboot_info_t* mb_info __attribute__ ((section (".data"))) = NULL; - -void multiboot_init(void* mb) -{ - mb_info = (multiboot_info_t*) mb; -} From e514ae24f8e1d4d369fb6be0117a00f2b264e63c Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Thu, 21 Aug 2014 20:13:55 +0200 Subject: [PATCH 08/21] added some preprocessor macros for upcoming paging code --- arch/x86/include/asm/page.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/x86/include/asm/page.h b/arch/x86/include/asm/page.h index 95a1701..5da3983 100644 --- a/arch/x86/include/asm/page.h +++ b/arch/x86/include/asm/page.h @@ -54,6 +54,9 @@ /// Mask the page address without page map flags #define PAGE_MASK 0xFFFFF000 +/// Make address canonical +#define CANONICAL(addr) (addr) // only for 32 bit paging + /// The number of entries in a page map table #define PAGE_MAP_ENTRIES (1L << PAGE_MAP_BITS) @@ -61,6 +64,11 @@ #define PAGE_MAP_PGD 0xFFFFF000 #define PAGE_MAP_PGT 0xFFC00000 +/// Align to next page +#define PAGE_FLOOR(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK) +/// Align to page +#define PAGE_CEIL(addr) ( (addr) & PAGE_MASK) + /// Page is present #define PG_PRESENT (1 << 0) /// Page is read- and writable @@ -84,10 +92,6 @@ /// This page or table is used during the boot process #define PG_BOOT (1 << 9) -/// This is a whole set of flags (PRESENT,RW,ACCESSED,DIRTY) for kernelspace tables -#define PG_TABLE (PG_PRESENT|PG_RW) -/// This is a whole set of flags (PRESENT,RW,GLOBAL) for kernelspace pages -#define PG_PAGE (PG_PRESENT|PG_RW|PG_GLOBAL) /** @brief A single entry in a page map * From 9b4714113a2b0783dd4850114e1d57cc851e6f85 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Thu, 21 Aug 2014 20:14:59 +0200 Subject: [PATCH 09/21] added functions to handle TLB invalidation and control register access --- arch/x86/include/asm/processor.h | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index e814be5..6b9db1d 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -66,6 +66,22 @@ static inline size_t read_cr3(void) { return val; } +/** @brief Read cr2 register + * @return cr2's value + */ +static inline size_t read_cr2(void) { + size_t val; + asm volatile("mov %%cr2, %0" : "=r"(val)); + return val; +} + +/** @brief Write a value into cr2 register + * @param val The value you want to write into cr2 + */ +static inline void write_cr2(size_t val) { + asm volatile("mov %0, %%cr2" : : "r"(val)); +} + /** @brief Write a value into cr3 register * @param val The value you want to write into cr3 */ @@ -73,7 +89,6 @@ static inline void write_cr3(size_t val) { asm volatile("mov %0, %%cr3" : : "r"(val)); } - /** @brief Flush cache * * The wbinvd asm instruction which stands for "Write back and invalidate" @@ -95,6 +110,14 @@ static inline void flush_tlb(void) write_cr3(val); } +/** @brief Flush a specific page entry in TLB + * @param addr The (virtual) address of the page to flush + */ +static inline void tlb_flush_one_page(size_t addr) +{ + asm volatile("invlpg (%0)" : : "r"(addr) : "memory"); +} + /** @brief Invalidate cache * * The invd asm instruction which invalidates cache without writing back From fbf55178c107bdb94d9f95cbd707421755b961f3 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Thu, 21 Aug 2014 20:17:02 +0200 Subject: [PATCH 10/21] added first version of paging code (only page_map() works for now) --- arch/x86/include/asm/page.h | 40 +++--- arch/x86/kernel/entry.asm | 15 ++- arch/x86/mm/Makefile | 4 + arch/x86/mm/page.c | 238 ++++++++++++++++++++++++++++++++++++ kernel/main.c | 2 +- mm/memory.c | 7 +- 6 files changed, 270 insertions(+), 36 deletions(-) create mode 100644 arch/x86/mm/Makefile create mode 100644 arch/x86/mm/page.c diff --git a/arch/x86/include/asm/page.h b/arch/x86/include/asm/page.h index 5da3983..eeb9a9a 100644 --- a/arch/x86/include/asm/page.h +++ b/arch/x86/include/asm/page.h @@ -50,7 +50,7 @@ /// Page map bits #define PAGE_MAP_BITS 10 /// Number of page map indirections -#define PAGE_MAP_LEVELS 2 +#define PAGE_LEVELS 2 /// Mask the page address without page map flags #define PAGE_MASK 0xFFFFF000 @@ -93,11 +93,14 @@ #define PG_BOOT (1 << 9) -/** @brief A single entry in a page map +/** @brief Converts a virtual address to a physical * - * Usually used as a pointer to a mapped page map entry. + * A non mapped virtual address causes a pagefault! + * + * @param addr Virtual address to convert + * @return physical address */ -typedef size_t page_entry_t; +size_t page_virt_to_phys(size_t vir); /** @brief Initialize paging subsystem * @@ -112,27 +115,19 @@ int page_init(); * * @param viraddr * @param phyaddr - * @param pages - * @param flags + * @param npages + * @param bits * @return */ -int page_map(size_t viraddr, size_t phyaddr, size_t pages, size_t flags); +int page_map(size_t viraddr, size_t phyaddr, size_t npages, size_t bits); /** @brief Unmap a continious region of pages * * @param viraddr - * @param pages + * @param npages * @return */ -int page_unmap(size_t viraddr, size_t pages); - -/** @brief Copy a single page frame - * - * @param dest - * @param src - * @return - */ -int page_copy(size_t dest, size_t src); +int page_unmap(size_t viraddr, size_t npages); /** @brief Copy a whole page map tree * @@ -140,19 +135,12 @@ int page_copy(size_t dest, size_t src); * @param src * @return */ -int page_map_copy(page_entry_t *dest, page_entry_t *src); +int page_map_copy(size_t *dest, size_t *src); /** @brief Free a whole page map tree * * @param map */ -int page_map_drop(page_entry_t *map); - -/** @brief Converts a virtual address to a physical - * - * @param viraddr Virtual address to convert - * @return Physical address - */ -size_t virt_to_phys(size_t viraddr); +int page_map_drop(size_t *map); #endif diff --git a/arch/x86/kernel/entry.asm b/arch/x86/kernel/entry.asm index 084f410..bcf7b8d 100644 --- a/arch/x86/kernel/entry.asm +++ b/arch/x86/kernel/entry.asm @@ -1,4 +1,4 @@ -; + ; Copyright (c) 2010, Stefan Lankes, RWTH Aachen University ; All rights reserved. ; @@ -318,22 +318,25 @@ ALIGN 4 mb_info: DD 0 -global boot_stack ALIGN 4096 +global boot_stack boot_stack: TIMES (KERNEL_STACK_SIZE) DB 0xcd ; Bootstrap page tables are used during the initialization. ; These tables do a simple identity paging and will ; be replaced in page_init() by more fine-granular mappings. -global boot_map ALIGN 4096 +global boot_map boot_map: boot_pgd: + DD boot_pgt + 0x103 ; PG_GLOBAL | PG_RW | PG_PRESENT + times 1023 DD 0 ; PAGE_MAP_ENTRIES - 1 +boot_pgt: %assign i 0 - %rep 1024 - DD (i << 12) | 0x083 - %assign i i+1 + %rep 1024 ; PAGE_MAP_ENTRIES + DD i | 0x203 ; PG_BOOT | PG_RW | PG_PRESENT + %assign i i + 4096 ; PAGE_SIZE %endrep ; add some hints to the ELF file diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile new file mode 100644 index 0000000..2f9b183 --- /dev/null +++ b/arch/x86/mm/Makefile @@ -0,0 +1,4 @@ +C_source := page.c +MODULE := arch_x86_mm + +include $(TOPDIR)/Makefile.inc diff --git a/arch/x86/mm/page.c b/arch/x86/mm/page.c new file mode 100644 index 0000000..201afaf --- /dev/null +++ b/arch/x86/mm/page.c @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2010, Stefan Lankes, RWTH Aachen University + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include +#include +#include + +/* Note that linker symbols are not variables, they have no memory + * allocated for maintaining a value, rather their address is their value. */ +extern const void kernel_start; +extern const void kernel_end; + +/** This PGD table is initialized in entry.asm */ +extern size_t boot_map[PAGE_MAP_ENTRIES]; + +/** A self-reference enables direct access to all page tables */ +static size_t* self[PAGE_LEVELS] = { + (size_t *) PAGE_MAP_PGT, (size_t *) PAGE_MAP_PGD +}; + +#define self_child(lvl, vpn) &self[lvl-1][vpn<>PAGE_MAP_BITS] + +/** @todo Does't handle huge pages for now + * @todo This will cause a pagefaut if addr isn't mapped! */ +size_t page_virt_to_phys(size_t addr) +{ + size_t vpn = addr >> PAGE_BITS; // virtual page number + size_t entry = self[0][vpn]; // page table entry + size_t off = addr & ~PAGE_MASK; // offset within page + size_t phy = entry & PAGE_MASK; // physical page frame number + + return phy | off; +} + +int page_map(size_t viraddr, size_t phyaddr, size_t npages, size_t bits) +{ + int lvl; + long vpn = viraddr >> PAGE_BITS; + long first[PAGE_LEVELS], last[PAGE_LEVELS]; // index boundaries for self-mapping + + for (lvl=0; lvl> (lvl * PAGE_MAP_BITS); + last[lvl] = (vpn + npages) >> (lvl * PAGE_MAP_BITS); + } + + /* We start now iterating through the entries + * beginning at the root table (PGD) */ + for (lvl=PAGE_LEVELS-1; lvl>=0; lvl--) { + for (vpn=first[lvl]; vpn<=last[lvl]; vpn++) { + if (lvl) { /* PML4, PDPT, PGD */ + if (self[lvl][vpn] & PG_PRESENT) { + /* There already an existing table which only allows + * kernel accesses. We need to copy the table to create + * private copy for the user space process */ + if (!(self[lvl][vpn] & PG_USER) && (bits & PG_USER)) { + size_t phyaddr = get_pages(1); + if (BUILTIN_EXPECT(!phyaddr, 0)) + return -ENOMEM; + + /* Copy old table contents to new one. + * We temporarily use page zero for this + * by mapping the new table to this address. */ + page_map(0, phyaddr, 1, PG_RW | PG_PRESENT); + memcpy(0, self_child(lvl, vpn), PAGE_SIZE); + + /* Update table by replacing address and altering flags */ + self[lvl][vpn] &= ~(PAGE_MASK | PG_GLOBAL); + self[lvl][vpn] |= phyaddr | PG_USER; + + /* We only need to flush the self-mapped table. + * TLB entries mapped by this table remain valid + * because we only made an identical copy. */ + tlb_flush_one_page((size_t) self_child(lvl, vpn)); + } + } + else { + /* There's no table available which covers the region. + * Therefore we need to create a new empty table. */ + size_t phyaddr = get_pages(1); + if (BUILTIN_EXPECT(!phyaddr, 0)) + return -ENOMEM; + + /* Reference the new table in the parent */ + self[lvl][vpn] = phyaddr | bits; + + /* Fill new table with zeros */ + memset(self_child(lvl, vpn), 0, PAGE_SIZE); + } + } + else { /* PGT */ + if (self[lvl][vpn] & PG_PRESENT) + tlb_flush_one_page(vpn << PAGE_BITS); + + self[lvl][vpn] = phyaddr | bits; + phyaddr += PAGE_SIZE; + } + } + } + + return 0; +} + +int page_unmap(size_t viraddr, size_t npages) +{ + int lvl; + long vpn = viraddr >> PAGE_BITS; + long first[PAGE_LEVELS], last[PAGE_LEVELS]; // index boundaries for self-mapping + + for (lvl=0; lvl> (lvl * PAGE_MAP_BITS); + last[lvl] = (vpn + npages) >> (lvl * PAGE_MAP_BITS); + } + + /* We start now iterating through the entries + * beginning at the root table (PGD) */ + for (lvl=PAGE_LEVELS-1; lvl>=0; lvl--) { + for (vpn=first[lvl]; vpn<=last[lvl]; vpn++) { + if (lvl) { /* PML4, PDPT, PGD */ + + } + else { /* PGT */ + + } + } + } + + return 0; +} + +int page_map_drop(size_t *map) +{ + int lvl; + long vpn; + + /* We start now iterating through the entries + * beginning at the root table (PGD) */ + for (lvl=PAGE_LEVELS-1; lvl>=0; lvl--) { + for (vpn=0; vpn=0; lvl--) { + for (vpn=0; vpnint_no, s->cs, s->eip, viraddr); + + outportb(0x20, 0x20); + + while(1) HALT; +} + +int page_init() +{ + size_t npages; + + // replace default pagefault handler + irq_uninstall_handler(14); + irq_install_handler(14, page_fault_handler); + + // create self-reference + boot_map[PAGE_MAP_ENTRIES-1] = (size_t) &boot_map | PG_PRESENT | PG_RW; + + // map kernel + npages = PAGE_FLOOR((size_t) &kernel_end - (size_t) &kernel_start) >> PAGE_BITS; + page_map((size_t) &kernel_start, (size_t) &kernel_start, npages, PG_PRESENT | PG_RW | PG_GLOBAL); + +#ifdef CONFIG_VGA + // map video memory + page_map(VIDEO_MEM_ADDR, VIDEO_MEM_ADDR, 1, PG_PCD | PG_PRESENT | PG_RW); +#endif + + // flush TLB to apply new mappings + flush_tlb(); + + return 0; +} diff --git a/kernel/main.c b/kernel/main.c index dd84a8c..617bd81 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -100,12 +100,12 @@ static int eduos_init(void) // initialize .bss section memset((void*)&bss_start, 0x00, ((size_t) &bss_end - (size_t) &bss_start)); - memory_init(); system_init(); irq_init(); timer_init(); koutput_init(); multitasking_init(); + memory_init(); return 0; } diff --git a/mm/memory.c b/mm/memory.c index 37489b9..c467a59 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -230,10 +230,11 @@ int memory_init(void) } // enable paging and map SMP, VGA, Multiboot modules etc. - /*ret = page_init(); - if (BUILTIN_EXPECT(ret, 0)) + ret = page_init(); + if (BUILTIN_EXPECT(ret, 0)) { + kputs("Failed to initialize paging!\n"); return ret; - */ + } return ret; } From d190d4c46c49018d7345b0959a864be43c3acfa3 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Thu, 21 Aug 2014 22:25:45 +0200 Subject: [PATCH 11/21] create self-reference directly in assembler .data section --- arch/x86/kernel/entry.asm | 3 ++- arch/x86/mm/page.c | 3 --- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/entry.asm b/arch/x86/kernel/entry.asm index bcf7b8d..3241974 100644 --- a/arch/x86/kernel/entry.asm +++ b/arch/x86/kernel/entry.asm @@ -331,7 +331,8 @@ global boot_map boot_map: boot_pgd: DD boot_pgt + 0x103 ; PG_GLOBAL | PG_RW | PG_PRESENT - times 1023 DD 0 ; PAGE_MAP_ENTRIES - 1 + times 1022 DD 0 ; PAGE_MAP_ENTRIES - 2 + DD boot_pgd + 0x103 ; PG_GLOBAL | PG_RW | PG_PRESENT (self-reference) boot_pgt: %assign i 0 %rep 1024 ; PAGE_MAP_ENTRIES diff --git a/arch/x86/mm/page.c b/arch/x86/mm/page.c index 201afaf..0797336 100644 --- a/arch/x86/mm/page.c +++ b/arch/x86/mm/page.c @@ -219,9 +219,6 @@ int page_init() irq_uninstall_handler(14); irq_install_handler(14, page_fault_handler); - // create self-reference - boot_map[PAGE_MAP_ENTRIES-1] = (size_t) &boot_map | PG_PRESENT | PG_RW; - // map kernel npages = PAGE_FLOOR((size_t) &kernel_end - (size_t) &kernel_start) >> PAGE_BITS; page_map((size_t) &kernel_start, (size_t) &kernel_start, npages, PG_PRESENT | PG_RW | PG_GLOBAL); From 84fb7123089e6ef1cab0b9f7c2465c05262a9cb0 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Thu, 21 Aug 2014 22:26:19 +0200 Subject: [PATCH 12/21] removed unnecessary TLB flush --- arch/x86/mm/page.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/x86/mm/page.c b/arch/x86/mm/page.c index 0797336..f7d64c0 100644 --- a/arch/x86/mm/page.c +++ b/arch/x86/mm/page.c @@ -228,8 +228,5 @@ int page_init() page_map(VIDEO_MEM_ADDR, VIDEO_MEM_ADDR, 1, PG_PCD | PG_PRESENT | PG_RW); #endif - // flush TLB to apply new mappings - flush_tlb(); - return 0; } From 7ec90d2532020b662e7e0af7541ea010ffbc3540 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 28 Nov 2014 01:34:26 +0100 Subject: [PATCH 13/21] added missing targets to Makefile --- Makefile.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.example b/Makefile.example index dd4ead8..c2ff065 100644 --- a/Makefile.example +++ b/Makefile.example @@ -1,7 +1,7 @@ TOPDIR = $(shell pwd) ARCH = x86 NAME = eduos -KERNDIRS = libkern kernel mm arch/$(ARCH)/kernel +KERNDIRS = libkern kernel mm arch/$(ARCH)/kernel arch/$(ARCH)/mm SUBDIRS = $(KERNDIRS) # Set your own cross compiler tool chain prefix here From 58876ffe0576420ded655318a485a0b8ecdd5592 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 28 Nov 2014 01:39:56 +0100 Subject: [PATCH 14/21] simplified code, fixed smaller bugs --- arch/x86/include/asm/page.h | 29 ++---- arch/x86/mm/page.c | 199 +++++++++++++++++++++++++----------- mm/memory.c | 1 + 3 files changed, 151 insertions(+), 78 deletions(-) diff --git a/arch/x86/include/asm/page.h b/arch/x86/include/asm/page.h index eeb9a9a..b91a80a 100644 --- a/arch/x86/include/asm/page.h +++ b/arch/x86/include/asm/page.h @@ -39,7 +39,9 @@ /// Page offset bits #define PAGE_BITS 12 /// The size of a single page in bytes -#define PAGE_SIZE (1L << PAGE_BITS) +#define PAGE_SIZE ( 1L << PAGE_BITS) +/// Mask the page address without page map flags +#define PAGE_MASK (-1L << PAGE_BITS) /// Total operand width in bits #define BITS 32 @@ -50,19 +52,13 @@ /// Page map bits #define PAGE_MAP_BITS 10 /// Number of page map indirections -#define PAGE_LEVELS 2 -/// Mask the page address without page map flags -#define PAGE_MASK 0xFFFFF000 +#define PAGE_LEVELS 2 /// Make address canonical #define CANONICAL(addr) (addr) // only for 32 bit paging /// The number of entries in a page map table -#define PAGE_MAP_ENTRIES (1L << PAGE_MAP_BITS) - -// Base addresses of the self-mapped pagetables -#define PAGE_MAP_PGD 0xFFFFF000 -#define PAGE_MAP_PGT 0xFFC00000 +#define PAGE_MAP_ENTRIES (1L << PAGE_MAP_BITS) /// Align to next page #define PAGE_FLOOR(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK) @@ -131,16 +127,13 @@ int page_unmap(size_t viraddr, size_t npages); /** @brief Copy a whole page map tree * - * @param dest - * @param src - * @return + * @param dest Physical address of new page map + * @retval 0 Success. Everything went fine. + * @retval <0 Error. Something went wrong. */ -int page_map_copy(size_t *dest, size_t *src); +int page_map_copy(size_t dest); -/** @brief Free a whole page map tree - * - * @param map - */ -int page_map_drop(size_t *map); +/** @brief Free a whole page map tree */ +int page_map_drop(); #endif diff --git a/arch/x86/mm/page.c b/arch/x86/mm/page.c index f7d64c0..a090d96 100644 --- a/arch/x86/mm/page.c +++ b/arch/x86/mm/page.c @@ -29,33 +29,49 @@ #include #include #include +#include #include #include #include +#include /* Note that linker symbols are not variables, they have no memory * allocated for maintaining a value, rather their address is their value. */ extern const void kernel_start; extern const void kernel_end; +/** Lock for kernel space page tables */ +static spinlock_t kslock = SPINLOCK_INIT; + /** This PGD table is initialized in entry.asm */ extern size_t boot_map[PAGE_MAP_ENTRIES]; /** A self-reference enables direct access to all page tables */ static size_t* self[PAGE_LEVELS] = { - (size_t *) PAGE_MAP_PGT, (size_t *) PAGE_MAP_PGD + (size_t *) 0xFFC00000, + (size_t *) 0xFFFFF000 }; -#define self_child(lvl, vpn) &self[lvl-1][vpn<>PAGE_MAP_BITS] +/** @todo: replace these offset by something meaningful */ +static size_t * other[PAGE_LEVELS] = { + (size_t *) 0xFF800000, + (size_t *) 0xFFFFE000 +}; -/** @todo Does't handle huge pages for now +/** Addresses of child/parent tables */ +#define CHILD(map, lvl, vpn) &map[lvl-1][vpn<>PAGE_MAP_BITS] + +/** This page is reserved for copying */ +#define PAGE_TMP (PAGE_FLOOR((size_t) &kernel_start) - PAGE_SIZE) + +/** @todo Does't handle huge pages for now * @todo This will cause a pagefaut if addr isn't mapped! */ size_t page_virt_to_phys(size_t addr) { size_t vpn = addr >> PAGE_BITS; // virtual page number - size_t entry = self[0][vpn]; // page table entry + size_t entry = self[0][vpn]; // page table entry size_t off = addr & ~PAGE_MASK; // offset within page size_t phy = entry & PAGE_MASK; // physical page frame number @@ -66,59 +82,70 @@ int page_map(size_t viraddr, size_t phyaddr, size_t npages, size_t bits) { int lvl; long vpn = viraddr >> PAGE_BITS; - long first[PAGE_LEVELS], last[PAGE_LEVELS]; // index boundaries for self-mapping + long first[PAGE_LEVELS], last[PAGE_LEVELS]; + // calculate index boundaries for page map traversal for (lvl=0; lvl> (lvl * PAGE_MAP_BITS); - last[lvl] = (vpn + npages) >> (lvl * PAGE_MAP_BITS); + last[lvl] = (vpn+npages-1) >> (lvl * PAGE_MAP_BITS); } + spinlock_lock(&kslock); + /* We start now iterating through the entries * beginning at the root table (PGD) */ for (lvl=PAGE_LEVELS-1; lvl>=0; lvl--) { for (vpn=first[lvl]; vpn<=last[lvl]; vpn++) { - if (lvl) { /* PML4, PDPT, PGD */ + if (lvl) { /* PML4, PDPT, PGD */ if (self[lvl][vpn] & PG_PRESENT) { /* There already an existing table which only allows * kernel accesses. We need to copy the table to create * private copy for the user space process */ if (!(self[lvl][vpn] & PG_USER) && (bits & PG_USER)) { size_t phyaddr = get_pages(1); - if (BUILTIN_EXPECT(!phyaddr, 0)) + if (BUILTIN_EXPECT(!phyaddr, 0)) { + spinlock_unlock(&kslock); return -ENOMEM; + } + + atomic_int32_inc(¤t_task->user_usage); /* Copy old table contents to new one. - * We temporarily use page zero for this + * We temporarily use page zero (PAGE_TMP) for this * by mapping the new table to this address. */ - page_map(0, phyaddr, 1, PG_RW | PG_PRESENT); - memcpy(0, self_child(lvl, vpn), PAGE_SIZE); + page_map(PAGE_TMP, phyaddr, 1, PG_RW | PG_PRESENT); + memcpy((void *) PAGE_TMP, CHILD(self, lvl, vpn), PAGE_SIZE); /* Update table by replacing address and altering flags */ self[lvl][vpn] &= ~(PAGE_MASK | PG_GLOBAL); - self[lvl][vpn] |= phyaddr | PG_USER; + self[lvl][vpn] |= phyaddr | PG_USER; /* We only need to flush the self-mapped table. * TLB entries mapped by this table remain valid * because we only made an identical copy. */ - tlb_flush_one_page((size_t) self_child(lvl, vpn)); + tlb_flush_one_page((size_t) CHILD(self, lvl, vpn)); } } else { /* There's no table available which covers the region. * Therefore we need to create a new empty table. */ size_t phyaddr = get_pages(1); - if (BUILTIN_EXPECT(!phyaddr, 0)) + if (BUILTIN_EXPECT(!phyaddr, 0)) { + spinlock_unlock(&kslock); return -ENOMEM; + } - /* Reference the new table in the parent */ + /* Reference the new table within its parent */ self[lvl][vpn] = phyaddr | bits; /* Fill new table with zeros */ - memset(self_child(lvl, vpn), 0, PAGE_SIZE); + memset(CHILD(self, lvl, vpn), 0, PAGE_SIZE); } } else { /* PGT */ if (self[lvl][vpn] & PG_PRESENT) + /* There's already a page mapped at this address. + * We have to flush a single TLB entry. */ tlb_flush_one_page(vpn << PAGE_BITS); self[lvl][vpn] = phyaddr | bits; @@ -127,77 +154,99 @@ int page_map(size_t viraddr, size_t phyaddr, size_t npages, size_t bits) } } + spinlock_unlock(&kslock); + return 0; } +/** Tables are freed by page_map_drop() */ int page_unmap(size_t viraddr, size_t npages) { - int lvl; - long vpn = viraddr >> PAGE_BITS; - long first[PAGE_LEVELS], last[PAGE_LEVELS]; // index boundaries for self-mapping + long vpn, start = viraddr >> PAGE_BITS; + long end = start + npages; - for (lvl=0; lvl> (lvl * PAGE_MAP_BITS); - last[lvl] = (vpn + npages) >> (lvl * PAGE_MAP_BITS); - } + spinlock_lock(&kslock); - /* We start now iterating through the entries - * beginning at the root table (PGD) */ - for (lvl=PAGE_LEVELS-1; lvl>=0; lvl--) { - for (vpn=first[lvl]; vpn<=last[lvl]; vpn++) { - if (lvl) { /* PML4, PDPT, PGD */ + for (vpn=start; vpn=0; lvl--) { - for (vpn=0; vpn 1) + traverse(lvl-1, vpn<user_usage); } } } + spinlock_irqsave_lock(¤t_task->page_lock); + + traverse(PAGE_LEVELS-1, 0); + + spinlock_irqsave_unlock(¤t_task->page_lock); + return 0; } -int page_map_copy(size_t *dest, size_t *src) +int page_map_copy(size_t dest) { - int lvl; - long vpn; + int traverse(int lvl, long vpn) { + long stop; + for (stop=vpn+PAGE_MAP_ENTRIES; vpn=0; lvl--) { - for (vpn=0; vpnint_no, s->cs, s->eip, viraddr); - outportb(0x20, 0x20); + outportb(0x20, 0x20); /** @todo: do we need this? */ while(1) HALT; } int page_init() { - size_t npages; + size_t addr, npages; + int i; // replace default pagefault handler irq_uninstall_handler(14); irq_install_handler(14, page_fault_handler); // map kernel + addr = (size_t) &kernel_start; npages = PAGE_FLOOR((size_t) &kernel_end - (size_t) &kernel_start) >> PAGE_BITS; - page_map((size_t) &kernel_start, (size_t) &kernel_start, npages, PG_PRESENT | PG_RW | PG_GLOBAL); + page_map(addr, addr, npages, PG_PRESENT | PG_RW | PG_GLOBAL); #ifdef CONFIG_VGA // map video memory - page_map(VIDEO_MEM_ADDR, VIDEO_MEM_ADDR, 1, PG_PCD | PG_PRESENT | PG_RW); + page_map(VIDEO_MEM_ADDR, VIDEO_MEM_ADDR, 1, PG_PRESENT | PG_RW | PG_PCD); #endif + // map multiboot information and modules + if (mb_info) { + addr = (size_t) mb_info & PAGE_MASK; + npages = PAGE_FLOOR(sizeof(*mb_info)) >> PAGE_BITS; + page_map(addr, addr, npages, PG_PRESENT | PG_GLOBAL); + + if (mb_info->flags & MULTIBOOT_INFO_MODS) { + addr = mb_info->mods_addr; + npages = PAGE_FLOOR(mb_info->mods_count*sizeof(multiboot_module_t)) >> PAGE_BITS; + page_map(addr, addr, npages, PG_PRESENT | PG_GLOBAL); + + multiboot_module_t* mmodule = (multiboot_module_t*) ((size_t) mb_info->mods_addr); + for(i=0; imods_count; i++) { + addr = mmodule[i].mod_start; + npages = PAGE_FLOOR(mmodule[i].mod_end - mmodule[i].mod_start) >> PAGE_BITS; + page_map(addr, addr, npages, PG_PRESENT | PG_USER | PG_GLOBAL); + } + } + } + + // unmap all (identity mapped) pages with PG_BOOT flag in first PGT (boot_pgt) + for (i=0; iflags & MULTIBOOT_INFO_MEM_MAP) { multiboot_memory_map_t* mmap = (multiboot_memory_map_t*) ((size_t) mb_info->mmap_addr); From c96973cf0372ba9cba46f9c1a924f026be76db81 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 28 Nov 2014 01:49:03 +0100 Subject: [PATCH 15/21] improved some targets of the Makefiles used for debugging and testing --- Makefile.example | 20 +++++++++++++++----- debug.gdb | 7 +++++++ 2 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 debug.gdb diff --git a/Makefile.example b/Makefile.example index dd4ead8..cddd314 100644 --- a/Makefile.example +++ b/Makefile.example @@ -20,9 +20,18 @@ OBJCOPY_FOR_TARGET = $(CROSSCOMPREFIX)objcopy RANLIB_FOR_TARGET = $(CROSSCOMPREFIX)ranlib STRIP_FOR_TARGET = $(CROSSCOMPREFIX)strip READELF_FOR_TARGET = $(CROSSCOMPREFIX)readelf + NASM = nasm +GDB = gdb +QEMU = qemu-system-i386 NASMFLAGS = -felf32 -g -i$(TOPDIR)/include/eduos/ +GDBFLAGS = -x debug.gdb +QEMUFLAGS = -smp 2 -monitor stdio \ + -net nic,model=rtl8139 \ + -net user,hostfwd=tcp::12345-:7 \ + -serial tcp::12346,server,nowait + INCLUDE = -I$(TOPDIR)/include -I$(TOPDIR)/arch/$(ARCH)/include # Compiler options for final code CFLAGS = -g -m32 -march=i586 -Wall -O2 -fno-builtin -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc $(INCLUDE) -fno-stack-protector @@ -62,14 +71,15 @@ veryclean: clean @echo Very cleaned qemu: $(NAME).elf - qemu-system-i386 -monitor stdio -smp 2 -net nic,model=rtl8139 -net user,hostfwd=tcp::12345-:7 -net dump -kernel $(NAME).elf + $(QEMU) $(QEMUFLAGS) -kernel $(NAME).elf -qemu-dbg: $(NAME).elf - qemu-system-i386 -monitor stdio -s -S -smp 2 -net nic,model=rtl8139 -net user,hostfwd=tcp::12345-:7 -net dump -kernel $(NAME).elf +debug: $(NAME).elf + $(TERM) -e $(GDB) $(GDBFLAGS) & + $(QEMU) $(QEMUFLAGS) -s -S -kernel $(NAME).elf doc: - @doxygen @echo Create documentation... + @doxygen %.o : %.c @echo [CC] $@ @@ -91,5 +101,5 @@ include/eduos/config.inc: include/eduos/config.h $Q$(CC_FOR_TARGET) $(CFLAGS) -c -o $@ $< .PHONY: default all clean emu gdb newlib tools - + include $(addsuffix /Makefile,$(SUBDIRS)) diff --git a/debug.gdb b/debug.gdb new file mode 100644 index 0000000..f1c08c0 --- /dev/null +++ b/debug.gdb @@ -0,0 +1,7 @@ +# Constant part of the script +symbol-file eduos.sym +target remote localhost:1234 + +set architecture i386 +break main +continue From b86e9d9a7d7956c1cf72aa26180b53531e39b627 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 28 Nov 2014 01:53:32 +0100 Subject: [PATCH 16/21] fixed external declarations --- kernel/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/main.c b/kernel/main.c index 617bd81..88798aa 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -52,9 +52,9 @@ extern char __BUILD_DATE; extern char __BUILD_TIME; /* Page frame counters */ -atomic_int32_t total_pages; -atomic_int32_t total_allocated_pages; -atomic_int32_t total_available_pages; +extern atomic_int32_t total_pages; +extern atomic_int32_t total_allocated_pages; +extern atomic_int32_t total_available_pages; static void userfoo(void* arg) { From b33107eef7a06faa65abce6a72ddd13d45d17a0c Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 28 Nov 2014 02:00:35 +0100 Subject: [PATCH 17/21] removed userspace fork/kill support to separate branch --- arch/x86/mm/page.c | 104 +-------------------------------------------- 1 file changed, 1 insertion(+), 103 deletions(-) diff --git a/arch/x86/mm/page.c b/arch/x86/mm/page.c index a090d96..f8b11c8 100644 --- a/arch/x86/mm/page.c +++ b/arch/x86/mm/page.c @@ -97,36 +97,7 @@ int page_map(size_t viraddr, size_t phyaddr, size_t npages, size_t bits) for (lvl=PAGE_LEVELS-1; lvl>=0; lvl--) { for (vpn=first[lvl]; vpn<=last[lvl]; vpn++) { if (lvl) { /* PML4, PDPT, PGD */ - if (self[lvl][vpn] & PG_PRESENT) { - /* There already an existing table which only allows - * kernel accesses. We need to copy the table to create - * private copy for the user space process */ - if (!(self[lvl][vpn] & PG_USER) && (bits & PG_USER)) { - size_t phyaddr = get_pages(1); - if (BUILTIN_EXPECT(!phyaddr, 0)) { - spinlock_unlock(&kslock); - return -ENOMEM; - } - - atomic_int32_inc(¤t_task->user_usage); - - /* Copy old table contents to new one. - * We temporarily use page zero (PAGE_TMP) for this - * by mapping the new table to this address. */ - page_map(PAGE_TMP, phyaddr, 1, PG_RW | PG_PRESENT); - memcpy((void *) PAGE_TMP, CHILD(self, lvl, vpn), PAGE_SIZE); - - /* Update table by replacing address and altering flags */ - self[lvl][vpn] &= ~(PAGE_MASK | PG_GLOBAL); - self[lvl][vpn] |= phyaddr | PG_USER; - - /* We only need to flush the self-mapped table. - * TLB entries mapped by this table remain valid - * because we only made an identical copy. */ - tlb_flush_one_page((size_t) CHILD(self, lvl, vpn)); - } - } - else { + if (!(self[lvl][vpn] & PG_PRESENT)) { /* There's no table available which covers the region. * Therefore we need to create a new empty table. */ size_t phyaddr = get_pages(1); @@ -175,79 +146,6 @@ int page_unmap(size_t viraddr, size_t npages) return 0; } -/* @todo: complete -int page_map_drop() -{ - void traverse(int lvl, long vpn) { - kprintf("traverse(lvl=%d, vpn=%#lx)\n", lvl, vpn); - - long stop; - for (stop=vpn+PAGE_MAP_ENTRIES; vpn 1) - traverse(lvl-1, vpn<user_usage); - } - } - } - - spinlock_irqsave_lock(¤t_task->page_lock); - - traverse(PAGE_LEVELS-1, 0); - - spinlock_irqsave_unlock(¤t_task->page_lock); - - return 0; -} - -int page_map_copy(size_t dest) -{ - int traverse(int lvl, long vpn) { - long stop; - for (stop=vpn+PAGE_MAP_ENTRIES; vpn Date: Fri, 28 Nov 2014 02:15:15 +0100 Subject: [PATCH 18/21] smaller cleanups --- arch/x86/include/asm/page.h | 2 ++ arch/x86/mm/page.c | 5 +---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/x86/include/asm/page.h b/arch/x86/include/asm/page.h index b91a80a..089c732 100644 --- a/arch/x86/include/asm/page.h +++ b/arch/x86/include/asm/page.h @@ -88,6 +88,8 @@ /// This page or table is used during the boot process #define PG_BOOT (1 << 9) +/// This page is reserved for copying +#define PAGE_TMP (PAGE_FLOOR((size_t) &kernel_start) - PAGE_SIZE) /** @brief Converts a virtual address to a physical * diff --git a/arch/x86/mm/page.c b/arch/x86/mm/page.c index f8b11c8..c3f70e1 100644 --- a/arch/x86/mm/page.c +++ b/arch/x86/mm/page.c @@ -63,9 +63,6 @@ static size_t * other[PAGE_LEVELS] = { #define CHILD(map, lvl, vpn) &map[lvl-1][vpn<>PAGE_MAP_BITS] -/** This page is reserved for copying */ -#define PAGE_TMP (PAGE_FLOOR((size_t) &kernel_start) - PAGE_SIZE) - /** @todo Does't handle huge pages for now * @todo This will cause a pagefaut if addr isn't mapped! */ size_t page_virt_to_phys(size_t addr) @@ -139,7 +136,7 @@ int page_unmap(size_t viraddr, size_t npages) spinlock_lock(&kslock); for (vpn=start; vpn Date: Fri, 28 Nov 2014 02:15:49 +0100 Subject: [PATCH 19/21] made pagefault handler more verbose --- arch/x86/mm/page.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/x86/mm/page.c b/arch/x86/mm/page.c index c3f70e1..f2de90f 100644 --- a/arch/x86/mm/page.c +++ b/arch/x86/mm/page.c @@ -147,10 +147,13 @@ void page_fault_handler(struct state *s) { size_t viraddr = read_cr2(); - kprintf("Page Fault Exception (%d) at cs:ip = %#x:%#lx, address = %#lx\n", - s->int_no, s->cs, s->eip, viraddr); - - outportb(0x20, 0x20); /** @todo: do we need this? */ + kprintf("Page Fault Exception (%d) at cs:ip = %#x:%#lx, task = %u, addr = %#lx, error = %#x [ %s %s %s %s %s ]\n", + s->int_no, s->cs, s->eip, current_task->id, viraddr, s->error, + (s->error & 0x4) ? "user" : "supervisor", + (s->error & 0x10) ? "instruction" : "data", + (s->error & 0x2) ? "write" : ((s->error & 0x10) ? "fetch" : "read"), + (s->error & 0x1) ? "protection" : "not present", + (s->error & 0x8) ? "reserved bit" : "\b"); while(1) HALT; } From 883756d0b4177e951808340a000e56251acb26f1 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 28 Nov 2014 02:26:40 +0100 Subject: [PATCH 20/21] improved documentation --- arch/x86/mm/page.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/arch/x86/mm/page.c b/arch/x86/mm/page.c index f2de90f..5e9f373 100644 --- a/arch/x86/mm/page.c +++ b/arch/x86/mm/page.c @@ -24,6 +24,11 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** + * This is a 32/64 bit portable paging implementation for the x86 architecture + * using self-referenced page tables. + * See http://www.noteblok.net/2014/06/14/bachelor/ for a detailed description. + */ #include #include @@ -59,12 +64,10 @@ static size_t * other[PAGE_LEVELS] = { (size_t *) 0xFFFFE000 }; -/** Addresses of child/parent tables */ +/* Addresses of child/parent tables */ #define CHILD(map, lvl, vpn) &map[lvl-1][vpn<>PAGE_MAP_BITS] -/** @todo Does't handle huge pages for now - * @todo This will cause a pagefaut if addr isn't mapped! */ size_t page_virt_to_phys(size_t addr) { size_t vpn = addr >> PAGE_BITS; // virtual page number @@ -81,7 +84,7 @@ int page_map(size_t viraddr, size_t phyaddr, size_t npages, size_t bits) long vpn = viraddr >> PAGE_BITS; long first[PAGE_LEVELS], last[PAGE_LEVELS]; - // calculate index boundaries for page map traversal + /* Calculate index boundaries for page map traversal */ for (lvl=0; lvl> (lvl * PAGE_MAP_BITS); last[lvl] = (vpn+npages-1) >> (lvl * PAGE_MAP_BITS); @@ -89,8 +92,8 @@ int page_map(size_t viraddr, size_t phyaddr, size_t npages, size_t bits) spinlock_lock(&kslock); - /* We start now iterating through the entries - * beginning at the root table (PGD) */ + /* Start iterating through the entries + * beginning at the root table (PGD or PML4) */ for (lvl=PAGE_LEVELS-1; lvl>=0; lvl--) { for (vpn=first[lvl]; vpn<=last[lvl]; vpn++) { if (lvl) { /* PML4, PDPT, PGD */ @@ -135,6 +138,8 @@ int page_unmap(size_t viraddr, size_t npages) spinlock_lock(&kslock); + /* Start iterating through the entries. + * Only the PGT entries are removed. Tables remain allocated. */ for (vpn=start; vpn> PAGE_BITS; page_map(addr, addr, npages, PG_PRESENT | PG_RW | PG_GLOBAL); #ifdef CONFIG_VGA - // map video memory + /* Map video memory */ page_map(VIDEO_MEM_ADDR, VIDEO_MEM_ADDR, 1, PG_PRESENT | PG_RW | PG_PCD); #endif - // map multiboot information and modules + /* Map multiboot information and modules */ if (mb_info) { addr = (size_t) mb_info & PAGE_MASK; npages = PAGE_FLOOR(sizeof(*mb_info)) >> PAGE_BITS; @@ -197,7 +202,7 @@ int page_init() } } - // unmap all (identity mapped) pages with PG_BOOT flag in first PGT (boot_pgt) + /* Unmap bootstrap identity paging (see entry.asm, PG_BOOT) */ for (i=0; i Date: Fri, 28 Nov 2014 02:28:33 +0100 Subject: [PATCH 21/21] removed obsolescent variable --- arch/x86/mm/page.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/x86/mm/page.c b/arch/x86/mm/page.c index 5e9f373..a0e6d4b 100644 --- a/arch/x86/mm/page.c +++ b/arch/x86/mm/page.c @@ -58,12 +58,6 @@ static size_t* self[PAGE_LEVELS] = { (size_t *) 0xFFFFF000 }; -/** @todo: replace these offset by something meaningful */ -static size_t * other[PAGE_LEVELS] = { - (size_t *) 0xFF800000, - (size_t *) 0xFFFFE000 -}; - /* Addresses of child/parent tables */ #define CHILD(map, lvl, vpn) &map[lvl-1][vpn<>PAGE_MAP_BITS]