From 8f6f6cf471d47b04fb9bc9365ab4138e9b29dcd8 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Sun, 17 Oct 2021 15:37:20 +0200 Subject: [PATCH 01/40] WIP: add TSS management --- arch/x86/cpu_context.c | 198 +++++++++++++++++++++++++++++++++- arch/x86/cpu_context_switch.S | 20 ++++ arch/x86/gdt.c | 34 +++++- arch/x86/gdt.h | 6 +- core/cpu_context.h | 19 +++- core/main.c | 4 +- core/segment.h | 3 + 7 files changed, 274 insertions(+), 10 deletions(-) diff --git a/arch/x86/cpu_context.c b/arch/x86/cpu_context.c index ea5d673..c3e69d7 100644 --- a/arch/x86/cpu_context.c +++ b/arch/x86/cpu_context.c @@ -1,15 +1,16 @@ -/* Copyright (C) 2005 David Decotigny +/* Copyright (C) 2021 Mathieu Maret + Copyright (C) 2005 David Decotigny Copyright (C) 2000-2004, The KOS team Initially taken from SOS */ +#include "cpu_context.h" #include "assert.h" +#include "gdt.h" #include "klibc.h" #include "segment.h" -#include "cpu_context.h" - /** * Here is the definition of a CPU context for IA32 processors. This * is a Matos/SOS convention, not a specification given by the IA32 @@ -76,6 +77,22 @@ struct cpu_kstate { struct cpu_state regs; } __attribute__((packed)); +/** + * Structure of an interrupted User thread's context. This is almost + * the same as a kernel context, except that 2 additional values are + * pushed on the stack before the eflags/cs/eip of the interrupted + * context: the stack configuration of the interrupted user context. + * + * @see Section 6.4.1 of Intel x86 vol 1 + */ +struct cpu_ustate { + struct cpu_state regs; + struct { + uint32_t cpl3_esp; + uint16_t cpl3_ss; + }; +} __attribute__((packed)); + /** * THE main operation of a kernel thread. This routine calls the * kernel thread function start_func and calls exit_func when @@ -96,6 +113,123 @@ static void core_routine(cpu_kstate_function_arg1_t *start_func, void *start_arg ; } +/* + * Structure of a Task State Segment on the x86 Architecture. + * + * @see Intel x86 spec vol 3, figure 6-2 + * + * @note Such a data structure should not cross any page boundary (see + * end of section 6.2.1 of Intel spec vol 3). This is the reason why + * we tell gcc to align it on a 128B boundary (its size is 104B, which + * is <= 128). + */ +struct x86_tss { + + /** + * Intel provides a way for a task to switch to another in an + * automatic way (call gates). In this case, the back_link field + * stores the source TSS of the context switch. This allows to + * easily implement coroutines, task backtracking, ... In Matos/SOS we + * don't use TSS for the context switch purpouse, so we always + * ignore this field. + * (+0) + */ + uint16_t back_link; + + uint16_t reserved1; + + /* CPL0 saved context. (+4) */ + vaddr_t esp0; + uint16_t ss0; + + uint16_t reserved2; + + /* CPL1 saved context. (+12) */ + vaddr_t esp1; + uint16_t ss1; + + uint16_t reserved3; + + /* CPL2 saved context. (+20) */ + vaddr_t esp2; + uint16_t ss2; + + uint16_t reserved4; + + /* Interrupted context's saved registers. (+28) */ + vaddr_t cr3; + vaddr_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; + + /* +72 */ + uint16_t es; + uint16_t reserved5; + + /* +76 */ + uint16_t cs; + uint16_t reserved6; + + /* +80 */ + uint16_t ss; + uint16_t reserved7; + + /* +84 */ + uint16_t ds; + uint16_t reserved8; + + /* +88 */ + uint16_t fs; + uint16_t reserved9; + + /* +92 */ + uint16_t gs; + uint16_t reserved10; + + /* +96 */ + uint16_t ldtr; + uint16_t reserved11; + + /* +100 */ + uint16_t debug_trap_flag : 1; + uint16_t reserved12 : 15; + uint16_t iomap_base_addr; + + /* 104 */ +} __attribute__((packed, aligned(128))); + +static struct x86_tss kernel_tss; + +int cpu_context_subsystem_setup() +{ + /* Reset the kernel TSS */ + memset(&kernel_tss, 0x0, sizeof(kernel_tss)); + + /** + * Now setup the kernel TSS. + * + * Considering the privilege change method we choose (cpl3 -> cpl0 + * through a software interrupt), we don't need to initialize a + * full-fledged TSS. See section 6.4.1 of Intel x86 vol 1. Actually, + * only a correct value for the kernel esp and ss are required (aka + * "ss0" and "esp0" fields). Since the esp0 will have to be updated + * at privilege change time, we don't have to set it up now. + */ + kernel_tss.ss0 = BUILD_SEGMENT_REG_VALUE(0, FALSE, SEG_KDATA); + + /* Register this TSS into the gdt */ + gdtRegisterTSS((vaddr_t)&kernel_tss); + + return 0; +} + int cpu_kstate_init(struct cpu_state **ctxt, cpu_kstate_function_arg1_t *start_func, vaddr_t start_arg, vaddr_t stack_bottom, size_t stack_size, cpu_kstate_function_arg1_t *exit_func, vaddr_t exit_arg) @@ -213,6 +347,30 @@ void cpu_state_detect_kernel_stack_overflow(const struct cpu_state *ctxt, vaddr_ /* ======================================================================= * Public Accessor functions */ +int cpu_context_is_in_user_mode(const struct cpu_state *ctxt) +{ + /* An interrupted user thread has its CS register set to that of the + User code segment */ + switch (GET_CPU_CS_REGISTER_VALUE(ctxt->cs)) { + case BUILD_SEGMENT_REG_VALUE(3, FALSE, SEG_UCODE): + return TRUE; + break; + + case BUILD_SEGMENT_REG_VALUE(0, FALSE, SEG_KCODE): + return FALSE; + break; + + default: + pr_err("Invalid saved context Code segment register: 0x%x (k=%x, u=%x) !", + (unsigned)GET_CPU_CS_REGISTER_VALUE(ctxt->cs), + BUILD_SEGMENT_REG_VALUE(0, FALSE, SEG_KCODE), + BUILD_SEGMENT_REG_VALUE(3, FALSE, SEG_UCODE)); + break; + } + + /* Should never get here */ + return -1; +} vaddr_t cpu_context_get_PC(const struct cpu_state *ctxt) { @@ -240,3 +398,37 @@ void cpu_context_dump(const struct cpu_state *ctxt) (unsigned)GET_CPU_CS_REGISTER_VALUE(ctxt->cs), (unsigned)ctxt->ds, (unsigned)ctxt->cpl0_ss, (unsigned)ctxt->error_code); } + +/* ************************************************************* + * Function to manage the TSS. This function is not really "public": + * it is reserved to the assembler routines defined in + * cpu_context_switch.S + * + * Update the kernel stack address so that the IRQ, syscalls and + * exception return in a correct stack location when coming back into + * kernel mode. + */ +void cpu_context_update_kernel_tss(struct cpu_state *next_ctxt) +{ + /* next_ctxt corresponds to an interrupted user thread ? */ + if (cpu_context_is_in_user_mode(next_ctxt)) { + /* + * Yes: "next_ctxt" is an interrupted user thread => we are + * going to switch to user mode ! Setup the stack address so + * that the user thread "next_ctxt" can come back to the correct + * stack location when returning in kernel mode. + * + * This stack location corresponds to the SP of the next user + * thread once its context has been transferred on the CPU, ie + * once the CPU has executed all the pop/iret instruction of the + * context switch with privilege change. + */ + kernel_tss.esp0 = ((vaddr_t)next_ctxt) + sizeof(struct cpu_ustate); + /* Note: no need to protect this agains IRQ because IRQs are not + allowed to update it by themselves, and they are not allowed + to block */ + } else { + /* No: No need to update kernel TSS when we stay in kernel + mode */ + } +} diff --git a/arch/x86/cpu_context_switch.S b/arch/x86/cpu_context_switch.S index f26c376..064cc68 100644 --- a/arch/x86/cpu_context_switch.S +++ b/arch/x86/cpu_context_switch.S @@ -2,6 +2,17 @@ .text +/** + * C Function called by the routines below in order to tell the CPU + * where will be the kernel stack (needed by the interrupt handlers) + * when next_ctxt will come back into kernel mode. + * + * void cpu_context_update_kernel_tss(struct cpu_state *next_ctxt) + * + * @see end of cpu_context.c + */ +.extern cpu_context_update_kernel_tss + .globl cpu_context_switch .type cpu_context_switch, @function @@ -32,6 +43,15 @@ cpu_context_switch: /* This is the proper context switch ! We change the stack here */ movl 68(%esp), %esp + /* Prepare kernel TSS in case we are switching to a user thread: we + make sure that we will come back into the kernel at a correct + stack location */ + pushl %esp /* Pass the location of the context we are + restoring to the function */ + call cpu_context_update_kernel_tss + + + addl $4, %esp /* Restore the CPU context */ popw %gs popw %fs diff --git a/arch/x86/gdt.c b/arch/x86/gdt.c index 7737611..769eae1 100644 --- a/arch/x86/gdt.c +++ b/arch/x86/gdt.c @@ -1,4 +1,5 @@ -/* Copyright (C) 2004 David Decotigny +/* Copyright (C) 2021 Mathieu Maret + Copyright (C) 2004 David Decotigny Copyright (C) 1999 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or @@ -17,7 +18,6 @@ USA. */ #include "segment.h" - #include "gdt.h" /** @@ -111,6 +111,10 @@ static struct x86_segment_descriptor gdt[] = { }, [SEG_KCODE] = BUILD_GDTE(0, 1), [SEG_KDATA] = BUILD_GDTE(0, 0), + [SEG_UCODE] = BUILD_GDTE(3, 1), + [SEG_UDATA] = BUILD_GDTE(3, 0), + [SEG_K_TSS] = {0,}, // Used by syscall, IRQ while in user space + // initialized by gdtRegisterTSS }; int gdtSetup(void) @@ -144,3 +148,29 @@ int gdtSetup(void) return 0; } + +int gdtRegisterTSS(vaddr_t tss_vaddr) +{ + uint16_t regval_tss; + + /* Initialize the GDT entry */ + gdt[SEG_K_TSS] = (struct x86_segment_descriptor){ + .limit_15_0 = 0x67, /* See Intel x86 vol 3 section 6.2.2 */ + .base_paged_addr_15_0 = (tss_vaddr)&0xffff, + .base_paged_addr_23_16 = (tss_vaddr >> 16) & 0xff, + .segment_type = 0x9, /* See Intel x86 vol 3 figure 6-3 */ + .descriptor_type = 0, /* (idem) */ + .dpl = 3, /* Allowed for CPL3 tasks */ + .present = 1, + .limit_19_16 = 0, /* Size of a TSS is < 2^16 ! */ + .custom = 0, /* Unused */ + .op_size = 0, /* See Intel x86 vol 3 figure 6-3 */ + .granularity = 1, /* limit is in Bytes */ + .base_paged_addr_31_24 = (tss_vaddr >> 24) & 0xff}; + + /* Load the TSS register into the processor */ + regval_tss = BUILD_SEGMENT_REG_VALUE(0, FALSE, SEG_K_TSS); + asm("ltr %0" : : "r"(regval_tss)); + + return 0; +} diff --git a/arch/x86/gdt.h b/arch/x86/gdt.h index d61885a..2e7792f 100644 --- a/arch/x86/gdt.h +++ b/arch/x86/gdt.h @@ -1,4 +1,5 @@ -/* Copyright (C) 2004 David Decotigny +/* Copyright (C) 2021 Mathieu Maret + Copyright (C) 2004 David Decotigny Copyright (C) 1999 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or @@ -17,7 +18,7 @@ USA. */ #pragma once - +#include "types.h" /** * @file gdt.h * @@ -34,3 +35,4 @@ * address space (ie "flat" virtual space). */ int gdtSetup(void); +int gdtRegisterTSS(vaddr_t tss_vaddr); diff --git a/core/cpu_context.h b/core/cpu_context.h index d719a1d..9d141cc 100644 --- a/core/cpu_context.h +++ b/core/cpu_context.h @@ -1,4 +1,5 @@ -/* Copyright (C) 2005 David Decotigny +/* Copyright (C) 2021 Mathieu Maret + Copyright (C) 2005 David Decotigny Copyright (C) 2000-2004, The KOS team This program is free software; you can redistribute it and/or @@ -84,6 +85,11 @@ int cpu_kstate_init(struct cpu_state **kctxt, cpu_kstate_function_arg1_t *start_ vaddr_t start_arg, vaddr_t stack_bottom, size_t stack_size, cpu_kstate_function_arg1_t *exit_func, vaddr_t exit_arg); +/** + * Prepare the system to deal with multiple CPU execution contexts + */ +int cpu_context_subsystem_setup(); + /** * Function that performs an immediate context-switch from one * kernel/user thread to another one. It stores the current executing @@ -119,6 +125,14 @@ void cpu_context_exit_to(struct cpu_state *switch_to_ctxt, * Public Accessor functions */ +/** + * Return whether the saved context was in kernel or user context + * + * @return TRUE when context was interrupted when in user mode, FALSE + * when in kernel mode, < 0 on error. + */ +int cpu_context_is_in_user_mode(const struct cpu_state *ctxt); + /** * Return Program Counter stored in the saved kernel/user context */ @@ -181,7 +195,8 @@ void cpu_state_detect_kernel_stack_overflow(const struct cpu_state *ctxt, vaddr_t kernel_stack_bottom, size_t kernel_stack_size); #else -#define cpu_state_prepare_detect_kernel_stack_overflow(ctxt, stkbottom, stksize) ({/* nop \ +#define cpu_state_prepare_detect_kernel_stack_overflow(ctxt, stkbottom, stksize) \ + ({/* nop \ */}) #define cpu_state_detect_kernel_stack_overflow(ctxt, stkbottom, stksize) ({/* nop */}) #endif diff --git a/core/main.c b/core/main.c index 0aa58c7..cda08ef 100644 --- a/core/main.c +++ b/core/main.c @@ -129,6 +129,7 @@ void kmain(unsigned long magic, unsigned long addr) // Turns out linux and windows do the same ! // https://lore.kernel.org/lkml/MWHPR21MB159330952629D36EEDE706B3D7379@MWHPR21MB1593.namprd21.prod.outlook.com/ if (mmap[i].addr < 0x100000) { + printf(" -> skipping\n"); continue; } memAddBank(max(mmap[i].addr, (multiboot_uint64_t)lastUsedByMem), @@ -161,7 +162,8 @@ void kmain(unsigned long magic, unsigned long addr) printf("[Setup] allocation system\n"); areaInit(firstUsedByMem, lastUsedByMem); - //allocSetup(); + + cpu_context_subsystem_setup(); printf("[Setup] thread system\n"); kthreadSetup(_stack_bottom, (_stack_top - _stack_bottom + 1)); diff --git a/core/segment.h b/core/segment.h index a548b1c..bc6d609 100644 --- a/core/segment.h +++ b/core/segment.h @@ -39,6 +39,9 @@ #define SEG_NULL 0 /* NULL segment, unused by the procesor */ #define SEG_KCODE 1 /* Kernel code segment */ #define SEG_KDATA 2 /* Kernel data segment */ +#define SEG_UCODE 3 /* User code segment */ +#define SEG_UDATA 4 /* User data segment */ +#define SEG_K_TSS 5 /* Kernel TSS for priviledge change (user to kernel) */ /** * Helper macro that builds a segment register's value -- 2.47.0 From 75dbbdb53b77a68ed06445dfc3a6113847241509 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Mon, 25 Oct 2021 23:25:31 +0200 Subject: [PATCH 02/40] Wrap IRQ, Exception, cpu_context to be ready for user Fix ASM where ebp was push 2 times. One by pushw ebp One by pushal later --- Makefile | 7 +-- arch/x86/cpu_context.c | 3 +- arch/x86/cpu_context_switch.S | 39 ++++++++++++--- arch/x86/exception_wrappers.S | 54 ++++++++++++++++----- arch/x86/gdt.h | 1 + arch/x86/irq_wrappers.S | 54 ++++++++++++++++----- arch/x86/syscall_wrappers.S | 91 +++++++++++++++++++++++++++++++++++ core/kthread.c | 13 +++++ core/segment.h | 14 ++++-- core/syscall.c | 21 ++++++++ core/syscall.h | 5 ++ 11 files changed, 260 insertions(+), 42 deletions(-) create mode 100644 arch/x86/syscall_wrappers.S create mode 100644 core/syscall.c create mode 100644 core/syscall.h diff --git a/Makefile b/Makefile index 6865285..e02517b 100644 --- a/Makefile +++ b/Makefile @@ -12,12 +12,13 @@ QEMU_OPT += -hda disk.img ARCH?=x86 SUBDIRS := core drivers tests arch/$(ARCH) -CPPFLAGS += $(foreach dir, $(SUBDIRS), -I$(dir)) +INCDIRS += $(foreach dir, $(SUBDIRS), -I$(dir)) +CPPFLAGS += $(INCDIRS) asmsrc=$(wildcard arch/$(ARCH)/boot/*.asm) asmobj=$(asmsrc:%.asm=%.o) csrc=$(shell find $(SUBDIRS) -type f -name "*.c")# $(wildcard *.c) -cobj=$(csrc:%.c=%.o) arch/$(ARCH)/cpu_context_switch.o arch/$(ARCH)/irq_pit.o arch/$(ARCH)/irq_wrappers.o arch/$(ARCH)/exception_wrappers.o +cobj=$(csrc:%.c=%.o) arch/$(ARCH)/cpu_context_switch.o arch/$(ARCH)/irq_pit.o arch/$(ARCH)/irq_wrappers.o arch/$(ARCH)/exception_wrappers.o arch/$(ARCH)/syscall_wrappers.o deps = $(csrc:%.c=%.d) kernel kernel.sym &: $(asmobj) $(cobj) linker.ld @@ -38,7 +39,7 @@ disk.img: $(AS) $(ASFLAGS) -o $@ $< %.o: %.S - $(CC) "-I$(PWD)" -c "$<" $(CFLAGS) -o "$@" + $(CC) $(INCDIRS) -c "$<" $(CFLAGS) -o "$@" test: CFLAGS += -DRUN_TEST diff --git a/arch/x86/cpu_context.c b/arch/x86/cpu_context.c index c3e69d7..40f77bf 100644 --- a/arch/x86/cpu_context.c +++ b/arch/x86/cpu_context.c @@ -38,12 +38,11 @@ struct cpu_state { uint16_t alignment_padding; /* unused */ uint32_t edi; uint32_t esi; - uint32_t esp; - uint32_t ebp; uint32_t ebx; uint32_t edx; uint32_t ecx; uint32_t eax; + uint32_t ebp; /* MUST NEVER CHANGE (dependent on the IA32 iret instruction) */ uint32_t error_code; diff --git a/arch/x86/cpu_context_switch.S b/arch/x86/cpu_context_switch.S index 064cc68..c043510 100644 --- a/arch/x86/cpu_context_switch.S +++ b/arch/x86/cpu_context_switch.S @@ -24,7 +24,13 @@ cpu_context_switch: pushl %cs // (cs) esp+52 pushl $resume_pc // (ip) esp+48 pushl $0 // (error code) esp+12+8x4 - pushal // (general reg) esp+12 + pushl %ebp + pushl %eax + pushl %ecx + pushl %edx + pushl %ebx + pushl %esi + pushl %edi subl $2, %esp // (alignment) esp+10 pushw %ss // esp+8 pushw %ds // esp+6 @@ -37,11 +43,11 @@ cpu_context_switch: */ /* Store the address of the saved context */ - movl 64(%esp), %ebx + movl 60(%esp), %ebx movl %esp, (%ebx) /* This is the proper context switch ! We change the stack here */ - movl 68(%esp), %esp + movl 64(%esp), %esp /* Prepare kernel TSS in case we are switching to a user thread: we make sure that we will come back into the kernel at a correct @@ -49,9 +55,8 @@ cpu_context_switch: pushl %esp /* Pass the location of the context we are restoring to the function */ call cpu_context_update_kernel_tss - - addl $4, %esp + /* Restore the CPU context */ popw %gs popw %fs @@ -59,7 +64,13 @@ cpu_context_switch: popw %ds popw %ss addl $2,%esp - popal + popl %edi + popl %esi + popl %ebx + popl %edx + popl %ecx + popl %eax + popl %ebp addl $4, %esp /* Ignore "error code" */ /* This restores the eflags, the cs and the eip registers */ @@ -95,6 +106,14 @@ cpu_context_exit_to: call *8(%eax) addl $4, %esp + /* Prepare kernel TSS in case we are switching to a user thread: we + make sure that we will come back into the kernel at a correct + stack location */ + pushl %esp /* Pass the location of the context we are + restoring to the function */ + call cpu_context_update_kernel_tss + addl $4, %esp + /* Restore the CPU context */ popw %gs popw %fs @@ -102,7 +121,13 @@ cpu_context_exit_to: popw %ds popw %ss addl $2,%esp - popal + popl %edi + popl %esi + popl %ebx + popl %edx + popl %ecx + popl %eax + popl %ebp addl $4, %esp /* Ignore "error code" */ /* This restores the eflags, the cs and the eip registers */ diff --git a/arch/x86/exception_wrappers.S b/arch/x86/exception_wrappers.S index 23f16ac..34dd39e 100644 --- a/arch/x86/exception_wrappers.S +++ b/arch/x86/exception_wrappers.S @@ -1,10 +1,19 @@ #define ASM_SOURCE 1 +#include "segment.h" .file "irq_wrappers.S" .text .extern exception_handler_wrap .globl exception_handler_wrapper_array +/** Update the kernel TSS in case we are switching to a thread in user + mode in order to come back into the correct kernel stack */ +.extern cpu_context_update_kernel_tss + +/* The address of the function to call to set back the user thread's + MMU configuration upon return to user context */ +.extern thread_prepare_exception_switch_back + .altmacro @@ -24,12 +33,12 @@ pushl %ebp movl %esp, %ebp - pushl %edi - pushl %esi - pushl %edx - pushl %ecx - pushl %ebx pushl %eax + pushl %ecx + pushl %edx + pushl %ebx + pushl %esi + pushl %edi subl $2,%esp pushw %ss pushw %ds @@ -37,11 +46,31 @@ pushw %fs pushw %gs + /* Set correct kernel segment descriptors' value */ + movw $BUILD_SEGMENT_REG_VALUE(0, 0, SEG_KDATA), %di + pushw %di ; popw %ds + pushw %di ; popw %es + pushw %di ; popw %fs + pushw %di ; popw %gs + push %esp pushl $\id call exception_handler_wrap addl $8, %esp + /* Reconfigure the MMU if needed */ + pushl %esp /* cpu_ctxt */ + call thread_prepare_exception_switch_back + addl $4, %esp /* Unallocate the stack */ + + /* Prepare kernel TSS in case we are switching to a + user thread: we make sure that we will come back + into the kernel at a correct stack location */ + pushl %esp /* Pass the location of the context we are + restoring to the function */ + call cpu_context_update_kernel_tss + addl $4, %esp + /* Restore the context */ popw %gs popw %fs @@ -49,14 +78,13 @@ popw %ds popw %ss addl $2,%esp - popl %eax - popl %ebx - popl %ecx - popl %edx - popl %esi - popl %edi - popl %ebp - + popl %edi + popl %esi + popl %ebx + popl %edx + popl %ecx + popl %eax + popl %ebp /* Remove fake error code */ addl $4, %esp diff --git a/arch/x86/gdt.h b/arch/x86/gdt.h index 2e7792f..aa5f50a 100644 --- a/arch/x86/gdt.h +++ b/arch/x86/gdt.h @@ -19,6 +19,7 @@ */ #pragma once #include "types.h" +#include "stdarg.h" /** * @file gdt.h * diff --git a/arch/x86/irq_wrappers.S b/arch/x86/irq_wrappers.S index a9bce0b..cb5b0e4 100644 --- a/arch/x86/irq_wrappers.S +++ b/arch/x86/irq_wrappers.S @@ -1,9 +1,17 @@ #define ASM_SOURCE 1 +#include "segment.h" .file "irq_wrappers.S" .text .extern interrupt_handler_pic .globl irq_handler_wrapper_array +/** Update the kernel TSS in case we are switching to a thread in user + mode in order to come back into the correct kernel stack */ +.extern cpu_context_update_kernel_tss + +/* The address of the function to call to set back the user thread's + MMU configuration upon return to user context */ +.extern thread_prepare_irq_switch_back .altmacro @@ -24,12 +32,12 @@ pushl %ebp movl %esp, %ebp - pushl %edi - pushl %esi - pushl %edx - pushl %ecx - pushl %ebx pushl %eax + pushl %ecx + pushl %edx + pushl %ebx + pushl %esi + pushl %edi subl $2,%esp pushw %ss pushw %ds @@ -37,25 +45,45 @@ pushw %fs pushw %gs + /* Set correct kernel segment descriptors' value */ + movw $BUILD_SEGMENT_REG_VALUE(0, 0, SEG_KDATA), %di + pushw %di ; popw %ds + pushw %di ; popw %es + pushw %di ; popw %fs + pushw %di ; popw %gs + push %esp pushl $\irq call interrupt_handler_pic addl $8, %esp + /* Reconfigure the MMU if needed */ + pushl %esp /* cpu_ctxt */ + call thread_prepare_irq_switch_back + addl $4, %esp /* Unallocate the stack */ + + /* Prepare kernel TSS in case we are switching to a + user thread: we make sure that we will come back + into the kernel at a correct stack location */ + pushl %esp /* Pass the location of the context we are + restoring to the function */ + call cpu_context_update_kernel_tss + addl $4, %esp + /* Restore the context */ popw %gs popw %fs popw %es - popw %ds + popw %ds popw %ss addl $2,%esp - popl %eax - popl %ebx - popl %ecx - popl %edx - popl %esi - popl %edi - popl %ebp + popl %edi + popl %esi + popl %ebx + popl %edx + popl %ecx + popl %eax + popl %ebp /* Remove fake error code */ addl $4, %esp diff --git a/arch/x86/syscall_wrappers.S b/arch/x86/syscall_wrappers.S new file mode 100644 index 0000000..7d8f568 --- /dev/null +++ b/arch/x86/syscall_wrappers.S @@ -0,0 +1,91 @@ +#define ASM_SOURCE +#include "segment.h" + +.file "syscall_wrappers.S" + +.text + +/* The address of the real "C" syscall function */ +.extern syscall_execute + +/** Update the kernel TSS in case we are switching to a thread in user + mode in order to come back into the correct kernel stack */ +.extern cpu_context_update_kernel_tss + +/* The address of the function to call to set back the user thread's + MMU configuration upon return to user context */ +.extern thread_prepare_syscall_switch_back + +.p2align 2, 0x90 +.globl syscallHandler +syscallHandler: +.type syscallHandler,@function + + /* Fake error code */ + pushl $0 + /* Backup the context */ + pushl %ebp + movl %esp, %ebp + + pushl %eax + pushl %ecx + pushl %edx + pushl %ebx + pushl %esi + pushl %edi + subl $2,%esp + pushw %ss + pushw %ds + pushw %es + pushw %fs + pushw %gs + + /* Set correct kernel segment descriptors' value */ + movw $BUILD_SEGMENT_REG_VALUE(0, 0, SEG_KDATA), %di + pushw %di ; popw %ds + pushw %di ; popw %es + pushw %di ; popw %fs + pushw %di ; popw %gs + + /* Prepare the call to do_syscall */ + pushl %esp /* user_ctxt */ + pushl %eax /* syscall ID */ + + call syscall_execute + /* Unallocate the stack used by the + do_syscall arguments */ + addl $8, %esp + + /* store the do_syscall return value into interrupted context */ + movl %eax, 12(%esp) + + /* Set the MMU configuration to that of the user thread's process */ + pushl %esp /* user_ctxt */ + call thread_prepare_syscall_switch_back + addl $4, %esp /* Unallocate the stack */ + + /* Prepare kernel TSS because we are switching back to a user + thread: we make sure that we will come back into the kernel at a + correct stack location */ + pushl %esp /* Pass the location of the context we are + restoring to the function */ + call cpu_context_update_kernel_tss + addl $4, %esp + + /* Restore the user context */ + popw %gs + popw %fs + popw %es + popw %ds + popw %ss + addl $2,%esp + popl %edi + popl %esi + popl %ebx + popl %edx + popl %ecx + popl %eax + popl %ebp + /* Remove fake error code */ + addl $4, %esp + iret diff --git a/core/kthread.c b/core/kthread.c index 78e115a..8fc1f55 100644 --- a/core/kthread.c +++ b/core/kthread.c @@ -258,3 +258,16 @@ int kthreadAddThread(struct kthread *th) return 0; } +void thread_prepare_syscall_switch_back(struct cpu_state *cpu_state){ + (void)cpu_state; + return; +} + +void thread_prepare_exception_switch_back(struct cpu_state *cpu_state){ + (void)cpu_state; + return; +} +void thread_prepare_irq_switch_back(struct cpu_state *cpu_state){ + (void)cpu_state; + return; +} diff --git a/core/segment.h b/core/segment.h index bc6d609..c3bf208 100644 --- a/core/segment.h +++ b/core/segment.h @@ -1,4 +1,5 @@ -/* Copyright (C) 2004 The SOS Team +/* Copyright (C) 2021 Mathieu Maret + Copyright (C) 2004 The SOS Team Copyright (C) 1999 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or @@ -29,8 +30,6 @@ * @see Intel x86 doc, vol 3 chapter 3. */ -#include "stdarg.h" - /* * Global segment selectors (GDT) for SOS/x86. * @@ -46,9 +45,16 @@ /** * Helper macro that builds a segment register's value */ +#ifdef ASM_SOURCE +#define BUILD_SEGMENT_REG_VALUE(desc_privilege,in_ldt,seg_index) \ + ( (((desc_privilege) & 0x3) << 0) \ + | ((in_ldt & 1) << 2) \ + | ((seg_index) << 3) ) + +#else #define BUILD_SEGMENT_REG_VALUE(desc_privilege, in_ldt, seg_index) \ ((((desc_privilege)&0x3) << 0) | (((in_ldt) ? 1 : 0) << 2) | ((seg_index) << 3)) - +#endif /* * Local segment selectors (LDT) for SOS/x86 */ diff --git a/core/syscall.c b/core/syscall.c new file mode 100644 index 0000000..87976a0 --- /dev/null +++ b/core/syscall.c @@ -0,0 +1,21 @@ +#include "syscall.h" +#include "irq.h" +#include "idt.h" + +extern void syscallHandler(); + +int syscallSetup(){ + uint32_t flags, ret; + + disable_IRQs(flags); + ret = idt_set_handler(SYSCALL_INTR_NB, (vaddr_t)syscallHandler, 3); + restore_IRQs(flags); + + return ret; +} + +int syscall_execute(int syscallId, const struct cpu_state *user_ctx){ + (void)syscallId; + (void)user_ctx; + return 0; +} diff --git a/core/syscall.h b/core/syscall.h new file mode 100644 index 0000000..2b4a2be --- /dev/null +++ b/core/syscall.h @@ -0,0 +1,5 @@ +#pragma once + +#define SYSCALL_INTR_NB 0x42 + +int syscallSetup(); -- 2.47.0 From 3fb667d62ee5e69a079cd5dce66f3c0f84ba11f4 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Tue, 26 Oct 2021 20:22:10 +0200 Subject: [PATCH 03/40] Core exception handling w or wo err code --- arch/x86/exception_wrappers.S | 160 +++++++++++++++++++++++++--------- debug.gdb | 2 + 2 files changed, 119 insertions(+), 43 deletions(-) diff --git a/arch/x86/exception_wrappers.S b/arch/x86/exception_wrappers.S index 34dd39e..4ba8b55 100644 --- a/arch/x86/exception_wrappers.S +++ b/arch/x86/exception_wrappers.S @@ -22,36 +22,108 @@ .type exception_wrapper_\id,@function /* INTERRUPT FRAME START */ /* ALREADY PUSHED TO US BY THE PROCESSOR UPON ENTRY TO THIS INTERRUPT */ - /* uint32_t ip */ - /* uint32_t cs; */ /* uint32_t flags */ + /* uint32_t cs; */ + /* uint32_t ip */ /* Pushes the other reg to save same and look like a struct cpu_state*/ /* Fake error code */ - pushl $0 + pushl $0 - /* Backup the actual context */ - pushl %ebp - movl %esp, %ebp + /* Backup the actual context */ + pushl %ebp + movl %esp, %ebp - pushl %eax - pushl %ecx - pushl %edx - pushl %ebx - pushl %esi - pushl %edi - subl $2,%esp - pushw %ss - pushw %ds - pushw %es - pushw %fs - pushw %gs + pushl %eax + pushl %ecx + pushl %edx + pushl %ebx + pushl %esi + pushl %edi + subl $2,%esp + pushw %ss + pushw %ds + pushw %es + pushw %fs + pushw %gs - /* Set correct kernel segment descriptors' value */ - movw $BUILD_SEGMENT_REG_VALUE(0, 0, SEG_KDATA), %di - pushw %di ; popw %ds - pushw %di ; popw %es - pushw %di ; popw %fs - pushw %di ; popw %gs + /* Set correct kernel segment descriptors' value */ + movw $BUILD_SEGMENT_REG_VALUE(0, 0, SEG_KDATA), %di + pushw %di ; popw %ds + pushw %di ; popw %es + pushw %di ; popw %fs + pushw %di ; popw %gs + + push %esp + pushl $\id + call exception_handler_wrap + addl $8, %esp + + /* Reconfigure the MMU if needed */ + pushl %esp /* cpu_ctxt */ + call thread_prepare_exception_switch_back + addl $4, %esp /* Unallocate the stack */ + + /* Prepare kernel TSS in case we are switching to a + user thread: we make sure that we will come back + into the kernel at a correct stack location */ + pushl %esp /* Pass the location of the context we are + restoring to the function */ + call cpu_context_update_kernel_tss + addl $4, %esp + + /* Restore the context */ + popw %gs + popw %fs + popw %es + popw %ds + popw %ss + addl $2,%esp + popl %edi + popl %esi + popl %ebx + popl %edx + popl %ecx + popl %eax + popl %ebp + /* Remove fake error code */ + addl $4, %esp + + iret +.endm + +.macro exception_mac_with_errcode id + exception_wrapper_\id: + .type exception_wrapper_\id,@function + /* INTERRUPT FRAME START */ + /* ALREADY PUSHED TO US BY THE PROCESSOR UPON ENTRY TO THIS INTERRUPT */ + /* uint32_t flags */ + /* uint32_t cs; */ + /* uint32_t ip */ + /* Pushes the other reg to save same and look like a struct cpu_state*/ + + /* Backup the actual context */ + pushl %ebp + movl %esp, %ebp + + pushl %eax + pushl %ecx + pushl %edx + pushl %ebx + pushl %esi + pushl %edi + subl $2,%esp + pushw %ss + pushw %ds + pushw %es + pushw %fs + pushw %gs + + /* Set correct kernel segment descriptors' value */ + movw $BUILD_SEGMENT_REG_VALUE(0, 0, SEG_KDATA), %di + pushw %di ; popw %ds + pushw %di ; popw %es + pushw %di ; popw %fs + pushw %di ; popw %gs push %esp pushl $\id @@ -72,30 +144,32 @@ addl $4, %esp /* Restore the context */ - popw %gs - popw %fs - popw %es - popw %ds - popw %ss - addl $2,%esp - popl %edi - popl %esi - popl %ebx - popl %edx - popl %ecx - popl %eax - popl %ebp - /* Remove fake error code */ - addl $4, %esp + popw %gs + popw %fs + popw %es + popw %ds + popw %ss + addl $2,%esp + popl %edi + popl %esi + popl %ebx + popl %edx + popl %ecx + popl %eax + popl %ebp + /* Remove fake error code */ + addl $4, %esp iret .endm +/*List of exception w or w/o err codehttps://wiki.osdev.org/Exceptions*/ +.irp exception_id, 8, 10, 11, 12, 13, 14, 17, 30 + exception_mac_with_errcode exception_id +.endr -.set i, 0 -.rept 0x20 - exception_mac %i - .set i, i+1 +.irp exception_id, 0, 1, 2, 3, 4, 5, 6, 7, 9, 15, 16, 18, 19, 20 21, 22, 23, 24, 25, 26, 27, 28, 29, 31 + exception_mac exception_id .endr .macro ref_exception_wrapper id diff --git a/debug.gdb b/debug.gdb index a78e6cd..6828808 100644 --- a/debug.gdb +++ b/debug.gdb @@ -1,3 +1,5 @@ add-symbol-file kernel.sym source custom_gdb_extension.py +#For ASM sources +directory arch/x86/:core target remote | qemu-system-i386 -S -gdb stdio -kernel kernel -m 16M -- 2.47.0 From 1e7f99a3e209e9c33f66a5655cfc5deab28b5602 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Tue, 26 Oct 2021 20:55:15 +0200 Subject: [PATCH 04/40] Correct irq asm handling --- arch/x86/irq_pit.S | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/arch/x86/irq_pit.S b/arch/x86/irq_pit.S index 039cb7a..4305875 100644 --- a/arch/x86/irq_pit.S +++ b/arch/x86/irq_pit.S @@ -7,8 +7,14 @@ .globl pit_handler .type pit_handler, @function pit_handler: // already got eflags, cs and eip on stack thanks to CPU - pushl $0 // err_code esp+12+8*4=44 - pushal // (general reg) esp+12 + pushl $0 // err_code esp+12+7*4=40 + pushl %ebp + pushl %eax + pushl %ecx + pushl %edx + pushl %ebx + pushl %esi + pushl %edi subl $2, %esp // (alignment) esp+10 pushw %ss // esp+8 pushw %ds // esp+6 @@ -31,7 +37,13 @@ pit_handler: // already got eflags, cs and eip on stack thanks to CPU popw %ds popw %ss addl $2,%esp - popal + popl %edi + popl %esi + popl %ebx + popl %edx + popl %ecx + popl %eax + popl %ebp addl $4, %esp /* Ignore "error code" */ /* This restores the eflags, the cs and the eip registers */ -- 2.47.0 From fbb51dff0f88b31985ef29a09cc361961aa34864 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Tue, 26 Oct 2021 21:42:57 +0200 Subject: [PATCH 05/40] Fix Area research and init size --- core/allocArea.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/core/allocArea.c b/core/allocArea.c index 5c999ed..4e47264 100644 --- a/core/allocArea.c +++ b/core/allocArea.c @@ -19,14 +19,15 @@ void areaInit(vaddr_t firstMemUsed, vaddr_t lastUsed) vaddr_t areaAddr, descAddr, entryAddr; allocSetup(sizeof(struct memArea), &areaAddr, &descAddr, &entryAddr); - areaAdd(descAddr, PAGE_SIZE, FALSE); + areaAdd(descAddr, 1, FALSE); if (entryAddr != descAddr) - areaAdd(entryAddr, PAGE_SIZE, FALSE); + areaAdd(entryAddr, 1, FALSE); if (areaAddr != descAddr && areaAddr != entryAddr) - areaAdd(areaAddr, PAGE_SIZE, FALSE); + areaAdd(areaAddr, 1, FALSE); int nbPages = DIV_ROUND_UP((lastUsed - firstMemUsed), PAGE_SIZE); areaAdd(ALIGN_DOWN(firstMemUsed, PAGE_SIZE), nbPages, FALSE); + //TODO: fix the 300 areaAdd(ALIGN_DOWN(areaAddr + PAGE_SIZE, PAGE_SIZE), 300 , TRUE); allocPopulate(); } @@ -158,7 +159,7 @@ static struct memArea *areaFindMemArea(struct memArea *list, vaddr_t addr) int count; list_foreach(list, area, count) { - if (area->startAddr <= addr && addr <= area->startAddr + area->nbPages * PAGE_SIZE) + if (area->startAddr <= addr && addr < area->startAddr + area->nbPages * PAGE_SIZE) return area; } -- 2.47.0 From 4aa093034bf8cd439db835515f7e909f2e47492f Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Tue, 26 Oct 2021 21:57:45 +0200 Subject: [PATCH 06/40] Page fault: more information --- arch/x86/cpu_context.c | 21 +++++++++++++++++++++ arch/x86/cpu_context_switch.S | 14 +++++++------- arch/x86/exception.c | 8 ++------ core/cpu_context.h | 2 +- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/arch/x86/cpu_context.c b/arch/x86/cpu_context.c index 40f77bf..3c8a2ca 100644 --- a/arch/x86/cpu_context.c +++ b/arch/x86/cpu_context.c @@ -390,6 +390,27 @@ vaddr_t cpu_context_get_SP(const struct cpu_state *ctxt) return (vaddr_t)ctxt; } +uint32_t cpu_context_get_EX_err(const struct cpu_state *ctxt) +{ + assert(NULL != ctxt); + + /* This is the Err_code of the interrupted context (ie kernel or user + context). */ + return ctxt->error_code; +} + +vaddr_t cpu_context_get_EX_faulting_vaddr(const struct cpu_state *ctxt) +{ + assert(NULL != ctxt); + + // A page fault has occurred. + // The faulting address is stored in the CR2 register. + vaddr_t faulting_address; + asm volatile("mov %%cr2, %0" : "=r"(faulting_address)); + + return faulting_address; +} + void cpu_context_dump(const struct cpu_state *ctxt) { printf("CPU: eip=%x esp=%x eflags=%x cs=%x ds=%x ss=%x err=%x", (unsigned)ctxt->eip, diff --git a/arch/x86/cpu_context_switch.S b/arch/x86/cpu_context_switch.S index c043510..7e661f6 100644 --- a/arch/x86/cpu_context_switch.S +++ b/arch/x86/cpu_context_switch.S @@ -17,13 +17,13 @@ .globl cpu_context_switch .type cpu_context_switch, @function cpu_context_switch: - // arg2= to_context -- esp+68 - // arg1= from_context -- esp+64 - // caller ip -- esp+60 - pushf // (eflags) esp+56 - pushl %cs // (cs) esp+52 - pushl $resume_pc // (ip) esp+48 - pushl $0 // (error code) esp+12+8x4 + // arg2= to_context -- esp+64 + // arg1= from_context -- esp+60 + // caller ip -- esp+56 + pushf // (eflags) esp+52 + pushl %cs // (cs) esp+48 + pushl $resume_pc // (ip) esp+44 + pushl $0 // (error code) esp+12+7x4 pushl %ebp pushl %eax pushl %ecx diff --git a/arch/x86/exception.c b/arch/x86/exception.c index 5b3d9a8..4aac3df 100644 --- a/arch/x86/exception.c +++ b/arch/x86/exception.c @@ -51,14 +51,10 @@ void print_handler(struct cpu_state *frame, ulong intr) void pagefault_handler(struct cpu_state *frame, ulong intr) { - // A page fault has occurred. - // The faulting address is stored in the CR2 register. - uint32_t faulting_address; - asm volatile("mov %%cr2, %0" : "=r"(faulting_address)); struct kthread *current = getCurrentThread(); - printf("page fault while in thread %s at 0x%x 0x%x\n", current->name, faulting_address, - cpu_context_get_PC(frame)); + printf("page fault while in thread %s code at 0x%x when trying to access 0x%x err_code 0x%x\n", current->name, + cpu_context_get_PC(frame), cpu_context_get_EX_faulting_vaddr(frame), cpu_context_get_EX_err(frame)); VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "PAGE FAULT %d", intr); (void)intr; for (;;) diff --git a/core/cpu_context.h b/core/cpu_context.h index 9d141cc..e17c31b 100644 --- a/core/cpu_context.h +++ b/core/cpu_context.h @@ -156,7 +156,7 @@ void cpu_context_dump(const struct cpu_state *ctxt); * Return the argument passed by the CPU upon exception, as stored in the * saved context */ -uint32_t cpu_context_get_EX_info(const struct cpu_state *ctxt); +uint32_t cpu_context_get_EX_err(const struct cpu_state *ctxt); /** * Return the faulting address of the exception -- 2.47.0 From 2c6ffe34a171c79ad25bbe0ef1f4e641a20bf3a3 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Tue, 26 Oct 2021 22:08:36 +0200 Subject: [PATCH 07/40] Allow to unref unrefered page --- core/mem.c | 8 +++++--- core/mem.h | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/core/mem.c b/core/mem.c index d74b31f..de471b0 100644 --- a/core/mem.c +++ b/core/mem.c @@ -1,8 +1,9 @@ -#include "mem.h" #include "assert.h" +#include "errno.h" #include "kernel.h" #include "klibc.h" #include "list.h" +#include "mem.h" #include "types.h" static struct phyMemDesc *pageDesc = (struct phyMemDesc *)&__ld_kernel_end; @@ -139,9 +140,10 @@ int unrefPhyPage(paddr_t addr) { struct phyMemDesc *mem = addr2memDesc(addr); if (!mem) { - return -1; + return -EINVAL; } - assert(mem->ref > 0); + if(mem->ref <= 0) + return -EINVAL; mem->ref--; if (mem->ref == 0) { allocatedPage--; diff --git a/core/mem.h b/core/mem.h index b16fdb6..278c930 100644 --- a/core/mem.h +++ b/core/mem.h @@ -7,6 +7,8 @@ #define PAGE_SHIFT 12U #define PAGE_SIZE (1U << PAGE_SHIFT) +#define PAGE_MASK (PAGE_SIZE - 1) + // Defined in linker.ld script extern uint32_t __ld_kernel_begin; -- 2.47.0 From 46e1bb064287ea23f3fef13cf937b9e3db89b89e Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Tue, 26 Oct 2021 22:29:51 +0200 Subject: [PATCH 08/40] area alloc: mapping optionnal --- arch/x86/paging.h | 2 +- core/alloc.c | 6 ++--- core/allocArea.c | 57 ++++++++++++++++++++++++++--------------------- core/allocArea.h | 7 +++++- 4 files changed, 41 insertions(+), 31 deletions(-) diff --git a/arch/x86/paging.h b/arch/x86/paging.h index 11490de..d43e0a3 100644 --- a/arch/x86/paging.h +++ b/arch/x86/paging.h @@ -1,7 +1,7 @@ #pragma once #include "types.h" -#define PAGING_MEM_USER 1 +#define PAGING_MEM_USER (1U << 0) #define PAGING_MEM_READ (1U << 1) #define PAGING_MEM_WRITE (1U << 2) diff --git a/core/alloc.c b/core/alloc.c index 491ac24..e9058c5 100644 --- a/core/alloc.c +++ b/core/alloc.c @@ -127,7 +127,7 @@ static int allocSlab(struct slabDesc **desc, size_t size, size_t sizeSlab, int s nbPage = DIV_ROUND_UP(sizeSlab, PAGE_SIZE); if (allocInitialized) { - alloc = areaAlloc(nbPage); + alloc = areaAlloc(nbPage, AREA_PHY_MAP); if (alloc == (paddr_t)NULL) return -ENOMEM; } else { @@ -182,7 +182,7 @@ static int allocSlabEntry(struct slabEntry **desc, size_t size, size_t sizeSlab, } nbPage = DIV_ROUND_UP(sizeSlab, PAGE_SIZE); - vaddr_t alloc = areaAlloc(nbPage); + vaddr_t alloc = areaAlloc(nbPage, AREA_PHY_MAP); if (alloc == (paddr_t)NULL) return -ENOMEM; @@ -262,7 +262,7 @@ void *malloc(size_t size) disable_IRQs(flags); if (size >= PAGE_SIZE){ - vaddr_t area = areaAlloc(DIV_ROUND_UP(size, PAGE_SIZE)); + vaddr_t area = areaAlloc(DIV_ROUND_UP(size, PAGE_SIZE), AREA_PHY_MAP); return (void *)area; } diff --git a/core/allocArea.c b/core/allocArea.c index 4e47264..6294df7 100644 --- a/core/allocArea.c +++ b/core/allocArea.c @@ -63,7 +63,7 @@ static void insertSorted(struct memArea **list, struct memArea *item) list_add_tail(*list, item); } -vaddr_t areaAlloc(unsigned int nbPages) +vaddr_t areaAlloc(unsigned int nbPages, uint32_t flags) { struct memArea *area, *allocated; @@ -75,33 +75,35 @@ vaddr_t areaAlloc(unsigned int nbPages) list_delete(freeArea, area); insertSorted(&usedArea, area); allocated = area; + } else { + struct memArea *newArea = (struct memArea *)malloc(sizeof(struct memArea)); + if (!newArea) { + pr_devel("Failed to allocated area of %d pages\n", nbPages); + return (vaddr_t)NULL; + } + + // Avoid insertSorted(freeArea, newArea) call by modifying area + + newArea->nbPages = nbPages; + newArea->startAddr = area->startAddr; + + area->nbPages -= nbPages; + area->startAddr += nbPages * PAGE_SIZE; + + insertSorted(&usedArea, newArea); + + allocated = newArea; } - struct memArea *newArea = (struct memArea *)malloc(sizeof(struct memArea)); - if (!newArea){ - pr_devel("Failed to allocated area of %d pages\n", nbPages); - return (vaddr_t)NULL; - } - - // Avoid insertSorted(freeArea, newArea) call by modifying area - - newArea->nbPages = nbPages; - newArea->startAddr = area->startAddr; - - area->nbPages -= nbPages; - area->startAddr += nbPages * PAGE_SIZE; - - insertSorted(&usedArea, newArea); - - allocated = newArea; - - for (uint i = 0; i < nbPages; i++) { - paddr_t page = allocPhyPage(1); - if (page) { - pageMap(newArea->startAddr + i * PAGE_SIZE, page, PAGING_MEM_WRITE); - } else { - // TODO - assert(1); + if (flags & AREA_PHY_MAP) { + for (uint i = 0; i < nbPages; i++) { + paddr_t page = allocPhyPage(1); + if (page) { + pageMap(allocated->startAddr + i * PAGE_SIZE, page, PAGING_MEM_WRITE); + } else { + // TODO + assert(1); + } } } @@ -175,6 +177,9 @@ int areaFree(vaddr_t addr) pr_info("Cannot find memArea associated to %p\n", addr); return -1; } + for(uint i = 0; i < area->nbPages; i++){ + pageUnmap( area->startAddr + i * PAGE_SIZE); + } list_delete(usedArea, area); insertSorted(&freeArea, area); diff --git a/core/allocArea.h b/core/allocArea.h index 292190b..a2030c0 100644 --- a/core/allocArea.h +++ b/core/allocArea.h @@ -2,6 +2,11 @@ #include "paging.h" #include "stdarg.h" +/* Pure Virtual Memory Allocation */ + +// areaAlloc map vmem to phy pages +#define AREA_PHY_MAP (1<<0) + struct memArea { vaddr_t startAddr; uint nbPages; @@ -11,6 +16,6 @@ struct memArea { }; void areaInit(vaddr_t firstMemUsed, vaddr_t lastUsed); -vaddr_t areaAlloc(unsigned int nbPages); +vaddr_t areaAlloc(unsigned int nbPages, uint32_t flags); int areaFree(vaddr_t addr); int areaAdd(vaddr_t addr, uint nbPages, int isFree); -- 2.47.0 From 7f6bb8eef309a4e7bb3f576611d7b94774499f1f Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Tue, 26 Oct 2021 22:52:24 +0200 Subject: [PATCH 09/40] add mmu context --- arch/x86/mmuContext.c | 79 +++++++++++++++++++++++++++++++++++++++++++ arch/x86/paging.c | 31 +++++++++++++++++ arch/x86/paging.h | 3 ++ core/mmuContext.h | 5 +++ 4 files changed, 118 insertions(+) create mode 100644 arch/x86/mmuContext.c create mode 100644 core/mmuContext.h diff --git a/arch/x86/mmuContext.c b/arch/x86/mmuContext.c new file mode 100644 index 0000000..d69c574 --- /dev/null +++ b/arch/x86/mmuContext.c @@ -0,0 +1,79 @@ +#include "mmuContext.h" +#include "alloc.h" +#include "allocArea.h" +#include "errno.h" +#include "klibc.h" +#include "irq.h" +#include "list.h" +#include "paging.h" +#include "stdarg.h" +#include "types.h" + +struct mmu_context { + paddr_t paddr_PD; + vaddr_t vaddr_PD; + uint32_t ref; + + struct mmu_context *next, *prev; +}; + +static struct mmu_context *listContext = NULL; +static struct mmu_context *currentContext = NULL; + +int mmuContextSetup() +{ + struct mmu_context *initialCtx; + int ret = 0; + + initialCtx = malloc(sizeof(struct mmu_context)); + + if (initialCtx == NULL) + return -ENOMEM; + + initialCtx->paddr_PD = pagingGetCurrentPDPaddr(); + initialCtx->vaddr_PD = areaAlloc(1, 0); + + ret = pageMap(initialCtx->vaddr_PD, initialCtx->paddr_PD, + PAGING_MEM_WRITE | PAGING_MEM_READ); + + if (ret) + return ret; + + list_singleton(listContext, initialCtx); + currentContext = initialCtx; + + // We create the context and we are using it + initialCtx->ref = 2; + return 0; +} + +struct mmu_context *mmuContextCreate() +{ + struct mmu_context *ctx; + uint32_t flags; + + ctx = malloc(sizeof(struct mmu_context)); + + if (ctx == NULL) + return NULL; + + ctx->vaddr_PD = areaAlloc(1, AREA_PHY_MAP); + + if (ctx->vaddr_PD == (vaddr_t)NULL) { + pr_info("Fail to allocate MMU Context\n"); + free(ctx); + + return NULL; + } + + ctx->paddr_PD = pagingGetPaddr(ctx->vaddr_PD); + + ctx->ref = 1; + + //TODO copy kernel space + disable_IRQs(flags); + list_add_tail(listContext, ctx); + restore_IRQs(flags); + + return ctx; +} diff --git a/arch/x86/paging.c b/arch/x86/paging.c index 8020a21..b8e8804 100644 --- a/arch/x86/paging.c +++ b/arch/x86/paging.c @@ -198,7 +198,38 @@ int pageUnmap(vaddr_t vaddr) return 0; } +paddr_t pagingGetPaddr(vaddr_t vaddr) +{ + /* Get the page directory entry and table entry index for this + address */ + unsigned pdEntry = vaddr >> PD_SHIFT; + unsigned ptEntry = vaddr >> PT_SHIFT; + unsigned pageOffset = vaddr & PAGE_MASK; + + /* Get the PD of the current context */ + struct pde *pd = + (struct pde *)((PD_MIRROR_PAGE_IDX << PD_SHIFT) + (PD_MIRROR_PAGE_IDX << PT_SHIFT)); + + /* Address of the PT in the mirroring */ + struct pte *pt = (struct pte *)((PD_MIRROR_PAGE_IDX << PD_SHIFT) + (pdEntry << PT_SHIFT)); + + /* No page mapped at this address ? */ + if (!pd[pdEntry].present) + return (paddr_t)NULL; + if (!pt[ptEntry].present) + return (paddr_t)NULL; + + return (pt[ptEntry].paddr << PT_SHIFT) + pageOffset; +} + unsigned long getNbMappedPage(void) { return mappedPage; } + +paddr_t pagingGetCurrentPDPaddr() +{ + struct pdbr pdbr; + asm volatile("movl %%cr3, %0\n": "=r"(pdbr)); + return (pdbr.pd_paddr << 12); +} diff --git a/arch/x86/paging.h b/arch/x86/paging.h index d43e0a3..1c7702f 100644 --- a/arch/x86/paging.h +++ b/arch/x86/paging.h @@ -10,3 +10,6 @@ int pagingSetup(paddr_t lowerKernelAddr, paddr_t upperKernelAddr); int pageMap(vaddr_t vaddr, paddr_t paddr, int flags); int pageUnmap(vaddr_t vaddr); unsigned long getNbMappedPage(void); + +paddr_t pagingGetPaddr(vaddr_t vaddr); +paddr_t pagingGetCurrentPDPaddr(); diff --git a/core/mmuContext.h b/core/mmuContext.h new file mode 100644 index 0000000..32e581a --- /dev/null +++ b/core/mmuContext.h @@ -0,0 +1,5 @@ +#pragma once + +struct mmu_context; +int mmuContextSetup(); +struct mmu_context *mmuContextCreate(); -- 2.47.0 From 9ae500f06ee33710fa1c8bcdd647e4b00eba6467 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Tue, 26 Oct 2021 23:26:42 +0200 Subject: [PATCH 10/40] Add more test --- tests/test.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/tests/test.c b/tests/test.c index 4c0af66..477c381 100644 --- a/tests/test.c +++ b/tests/test.c @@ -1,4 +1,5 @@ #include "alloc.h" +#include "allocArea.h" #include "ata.h" #include "assert.h" #include "cpu_context.h" @@ -84,14 +85,22 @@ static void *testAllocNSet(size_t size) return allocated; } -static void testAlloc(void) +void testAllocArea(){ + vaddr_t area = areaAlloc(1, 0); + vaddr_t area2 = areaAlloc(1, AREA_PHY_MAP); + assert(area != area2); + areaFree(area); + areaFree(area2); +} + +void testAlloc(void) { assert(malloc(1410065407) == NULL); for (uint i = 0; i < PAGE_SIZE / (sizeof(struct slabEntry)); i++) { - malloc(sizeof(struct slabEntry)); + assert(malloc(sizeof(struct slabEntry)) != NULL); } for (uint i = 0; i < PAGE_SIZE / (sizeof(struct slabDesc)); i++) { - malloc(sizeof(struct slabDesc)); + assert(malloc(sizeof(struct slabDesc)) != NULL); } assert(malloc(1)); assert(malloc(2)); @@ -103,6 +112,8 @@ static void testAlloc(void) free(malloc2); void *malloc3 = malloc(sizeof(void *)); assertmsg((char *)malloc2 == (char *)malloc3, " %d %d\n", malloc2, malloc3); + free(malloc1); + free(malloc3); void *alloc1 = testAllocNSet(1024); void *alloc2 = testAllocNSet(1024); void *alloc3 = testAllocNSet(1024); @@ -388,6 +399,7 @@ void run_test(void) serialPutc('l'); serialPutc('o'); testAlloc(); + testAllocArea(); printf("Testing backtrace\n"); test_backtrace(); testCoroutine(); -- 2.47.0 From 7b9ceba6b25893e453d8a31d846cdafd21bf3e45 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Thu, 28 Oct 2021 00:32:35 +0200 Subject: [PATCH 11/40] Give stack information to area --- core/allocArea.c | 12 +++++++++--- core/allocArea.h | 2 +- core/main.c | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/core/allocArea.c b/core/allocArea.c index 6294df7..a30b60c 100644 --- a/core/allocArea.c +++ b/core/allocArea.c @@ -12,7 +12,9 @@ static struct memArea *usedArea; static int areaMergeFreeArea(struct memArea *prev, struct memArea *next); -void areaInit(vaddr_t firstMemUsed, vaddr_t lastUsed) + +//Kernel stack is inside firstMemUsed-lastUsed +void areaInit(vaddr_t firstMemUsed, vaddr_t lastUsed, vaddr_t stackBottom, vaddr_t stackTop) { list_init(freeArea); list_init(usedArea); @@ -25,8 +27,12 @@ void areaInit(vaddr_t firstMemUsed, vaddr_t lastUsed) if (areaAddr != descAddr && areaAddr != entryAddr) areaAdd(areaAddr, 1, FALSE); - int nbPages = DIV_ROUND_UP((lastUsed - firstMemUsed), PAGE_SIZE); - areaAdd(ALIGN_DOWN(firstMemUsed, PAGE_SIZE), nbPages, FALSE); + int nbPagesKernel = DIV_ROUND_UP((lastUsed - firstMemUsed), PAGE_SIZE); + areaAdd(ALIGN_DOWN(firstMemUsed, PAGE_SIZE), nbPagesKernel, FALSE); + if(stackBottom > lastUsed){ + int nbPagesStack = DIV_ROUND_UP((stackTop - stackBottom), PAGE_SIZE); + areaAdd(ALIGN_DOWN(stackBottom, PAGE_SIZE), nbPagesStack, FALSE); + } //TODO: fix the 300 areaAdd(ALIGN_DOWN(areaAddr + PAGE_SIZE, PAGE_SIZE), 300 , TRUE); allocPopulate(); diff --git a/core/allocArea.h b/core/allocArea.h index a2030c0..5a7618a 100644 --- a/core/allocArea.h +++ b/core/allocArea.h @@ -15,7 +15,7 @@ struct memArea { struct memArea *prev; }; -void areaInit(vaddr_t firstMemUsed, vaddr_t lastUsed); +void areaInit(vaddr_t firstMemUsed, vaddr_t lastUsed, vaddr_t stack_bottom, vaddr_t stack_top); vaddr_t areaAlloc(unsigned int nbPages, uint32_t flags); int areaFree(vaddr_t addr); int areaAdd(vaddr_t addr, uint nbPages, int isFree); diff --git a/core/main.c b/core/main.c index cda08ef..4a5c249 100644 --- a/core/main.c +++ b/core/main.c @@ -161,7 +161,7 @@ void kmain(unsigned long magic, unsigned long addr) serialSetup(115200); printf("[Setup] allocation system\n"); - areaInit(firstUsedByMem, lastUsedByMem); + areaInit(firstUsedByMem, lastUsedByMem, _stack_bottom, _stack_top); cpu_context_subsystem_setup(); -- 2.47.0 From 07d173a9c1efa1ddcb3eece8be2ef1ea99a4f992 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Thu, 28 Oct 2021 00:41:02 +0200 Subject: [PATCH 12/40] Sync PDs on modifications --- arch/x86/mmuContext.c | 21 ++++++++++++ arch/x86/paging.c | 77 ++++++++++++++++++++++++++++++++++++------- arch/x86/paging.h | 1 + core/mmuContext.h | 3 ++ 4 files changed, 90 insertions(+), 12 deletions(-) diff --git a/arch/x86/mmuContext.c b/arch/x86/mmuContext.c index d69c574..278bfb9 100644 --- a/arch/x86/mmuContext.c +++ b/arch/x86/mmuContext.c @@ -77,3 +77,24 @@ struct mmu_context *mmuContextCreate() return ctx; } + +int mmuContextSyncKernelPDE(int pdEntry, void * pde, size_t pdeSize) +{ + uint32_t flags; + struct mmu_context *destContext; + int nbContexts; + + disable_IRQs(flags); + list_foreach_forward(listContext, destContext, nbContexts) + { + void *dest_pd; + + assert(destContext->ref > 0); + + dest_pd = (void *)destContext->vaddr_PD; + memcpy(dest_pd + pdEntry *pdeSize, pde, pdeSize); + } + restore_IRQs(flags); + + return 0; +} diff --git a/arch/x86/paging.c b/arch/x86/paging.c index b8e8804..8b4ef08 100644 --- a/arch/x86/paging.c +++ b/arch/x86/paging.c @@ -1,7 +1,9 @@ #include "paging.h" #include "errno.h" +#include "kernel.h" #include "klibc.h" #include "mem.h" +#include "mmuContext.h" #include "stdarg.h" // In a Vaddr, 10 first bit (MSB) are the index in the Page Directory. A Page Directory Entry @@ -23,6 +25,20 @@ #define PD_SHIFT 22 #define PD_MIRROR_PAGE_IDX 1023U +/** Frontier between kernel and user space virtual addresses */ +#define PAGING_BASE_USER_ADDRESS (0x40000000) /* 1GB (must be 4MB-aligned) */ +#define PAGING_TOP_USER_ADDRESS (0xFFFFFFFF) /* 4GB - 1B */ +#define PAGING_USER_SPACE_SIZE (0xc0000000) /* 3GB */ + +/** Length of the space reserved for the mirroring in the kernel + virtual space */ +#define PAGING_MIRROR_SIZE (PAGE_SIZE << 10) /* 1 PD = 1024 Page Tables = 4MB */ + +/** Virtual address where the mirroring takes place */ +#define PAGING_MIRROR_VADDR \ + (PAGING_BASE_USER_ADDRESS - PAGING_MIRROR_SIZE) + + static unsigned long mappedPage = 0; struct pde { @@ -107,9 +123,10 @@ int pagingSetup(paddr_t lowerKernelAddr, paddr_t upperKernelAddr) } // Setup mirroring - pd[PD_MIRROR_PAGE_IDX].present = 1; - pd[PD_MIRROR_PAGE_IDX].write = 1; - pd[PD_MIRROR_PAGE_IDX].pt_addr = ((paddr_t)pd >> PT_SHIFT); + pd[PAGING_MIRROR_VADDR >> PD_SHIFT].present = 1; + pd[PAGING_MIRROR_VADDR >> PD_SHIFT].write = 1; + pd[PAGING_MIRROR_VADDR >> PD_SHIFT].pt_addr = ((paddr_t)pd >> PT_SHIFT); + pd[PAGING_MIRROR_VADDR >> PD_SHIFT].user = 0; // Loading of the PDBR in the MMU: asm volatile("movl %0,%%cr3\n\t" @@ -130,22 +147,34 @@ int pageMap(vaddr_t vaddr, paddr_t paddr, int flags) uint pdEntry = vaddr >> (PD_SHIFT); uint ptEntry = (vaddr >> PT_SHIFT) & PTE_MASK; + if ((vaddr >= PAGING_MIRROR_VADDR) && + (vaddr < PAGING_MIRROR_VADDR + PAGING_MIRROR_SIZE)) + return -EINVAL; + // Thank to mirroring, we can access the PD struct pde *pd = - (struct pde *)((PD_MIRROR_PAGE_IDX << PD_SHIFT) + (PD_MIRROR_PAGE_IDX << PT_SHIFT)); + (struct pde *)(PAGING_MIRROR_VADDR + PAGE_SIZE*(PAGING_MIRROR_VADDR>>PD_SHIFT)); + + struct pte *pt = (struct pte *)((PAGING_MIRROR_VADDR) + (pdEntry * PAGE_SIZE)); - struct pte *pt = (struct pte *)((PD_MIRROR_PAGE_IDX << PD_SHIFT) + (pdEntry << PT_SHIFT)); if (!pd[pdEntry].present) { paddr_t ptPhy = allocPhyPage(1); if (ptPhy == (vaddr_t)NULL) return -ENOMEM; - pd[pdEntry].user = (flags & PAGING_MEM_USER) ? 1 : 0; pd[pdEntry].present = 1; pd[pdEntry].write = 1; pd[pdEntry].pt_addr = (ptPhy >> PT_SHIFT); + if(vaddr < PAGING_BASE_USER_ADDRESS){ + pd[pdEntry].user = 0; + mmuContextSyncKernelPDE(pdEntry, &pd[pdEntry], sizeof(struct pde)); + }else{ + assert(flags & PAGING_MEM_USER); + pd[pdEntry].user = 1; + } + __native_flush_tlb_single((vaddr_t)pt); memset((void *)pt, 0, PAGE_SIZE); } else { @@ -175,11 +204,15 @@ int pageUnmap(vaddr_t vaddr) uint pdEntry = vaddr >> (PD_SHIFT); uint ptEntry = (vaddr >> PT_SHIFT) & PTE_MASK; + if ((vaddr >= PAGING_MIRROR_VADDR) && + (vaddr < PAGING_MIRROR_VADDR + PAGING_MIRROR_SIZE)) + return -EINVAL; + // Thank to mirroring, we can access the PD struct pde *pd = - (struct pde *)((PD_MIRROR_PAGE_IDX << PD_SHIFT) + (PD_MIRROR_PAGE_IDX << PT_SHIFT)); + (struct pde *)(PAGING_MIRROR_VADDR + PAGE_SIZE*(PAGING_MIRROR_VADDR>>PD_SHIFT)); - struct pte *pt = (struct pte *)((PD_MIRROR_PAGE_IDX << PD_SHIFT) + (pdEntry << PT_SHIFT)); + struct pte *pt = (struct pte *)((PAGING_MIRROR_VADDR) + (pdEntry * PAGE_SIZE)); if (!pd[pdEntry].present) return -EINVAL; if (!pt[ptEntry].present) @@ -191,6 +224,9 @@ int pageUnmap(vaddr_t vaddr) // PTE not used. Decrease refcount on it. Is PT not used anymore ? if (unrefPhyPage(pd[pdEntry].pt_addr << PT_SHIFT) == 0) { pd[pdEntry].present = 0; + if (vaddr < PAGING_BASE_USER_ADDRESS) { + mmuContextSyncKernelPDE(pdEntry, &pd[pdEntry], sizeof(struct pde)); + } __native_flush_tlb_single((vaddr_t)pt); } __native_flush_tlb_single(vaddr); @@ -206,12 +242,11 @@ paddr_t pagingGetPaddr(vaddr_t vaddr) unsigned ptEntry = vaddr >> PT_SHIFT; unsigned pageOffset = vaddr & PAGE_MASK; - /* Get the PD of the current context */ + // Thank to mirroring, we can access the PD struct pde *pd = - (struct pde *)((PD_MIRROR_PAGE_IDX << PD_SHIFT) + (PD_MIRROR_PAGE_IDX << PT_SHIFT)); + (struct pde *)(PAGING_MIRROR_VADDR + PAGE_SIZE*(PAGING_MIRROR_VADDR>>PD_SHIFT)); - /* Address of the PT in the mirroring */ - struct pte *pt = (struct pte *)((PD_MIRROR_PAGE_IDX << PD_SHIFT) + (pdEntry << PT_SHIFT)); + struct pte *pt = (struct pte *)((PAGING_MIRROR_VADDR) + (pdEntry * PAGE_SIZE)); /* No page mapped at this address ? */ if (!pd[pdEntry].present) @@ -233,3 +268,21 @@ paddr_t pagingGetCurrentPDPaddr() asm volatile("movl %%cr3, %0\n": "=r"(pdbr)); return (pdbr.pd_paddr << 12); } + +int pagingSetCurrentPDPaddr(paddr_t paddrPD) +{ + struct pdbr pdbr; + + assert(paddrPD != 0); + assert(IS_ALIGNED(paddrPD, PAGE_SIZE)); + + /* Setup the value of the PDBR */ + memset(& pdbr, 0x0, sizeof(struct pdbr)); /* Reset the PDBR */ + pdbr.pd_paddr = (paddrPD >> 12); + + /* Configure the MMU according to the PDBR */ + asm volatile ("movl %0,%%cr3\n" ::"r"(pdbr)); + + return 0; +} + diff --git a/arch/x86/paging.h b/arch/x86/paging.h index 1c7702f..a862432 100644 --- a/arch/x86/paging.h +++ b/arch/x86/paging.h @@ -11,5 +11,6 @@ int pageMap(vaddr_t vaddr, paddr_t paddr, int flags); int pageUnmap(vaddr_t vaddr); unsigned long getNbMappedPage(void); +int pagingSetCurrentPDPaddr(paddr_t paddrPD); paddr_t pagingGetPaddr(vaddr_t vaddr); paddr_t pagingGetCurrentPDPaddr(); diff --git a/core/mmuContext.h b/core/mmuContext.h index 32e581a..ca5feea 100644 --- a/core/mmuContext.h +++ b/core/mmuContext.h @@ -1,5 +1,8 @@ #pragma once +#include "stdarg.h" struct mmu_context; + int mmuContextSetup(); struct mmu_context *mmuContextCreate(); +int mmuContextSyncKernelPDE(int pdEntry, void *pde, size_t pdeSize); -- 2.47.0 From e658ea6e48be535956b366aeba6a8314bbcb9c7a Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Thu, 28 Oct 2021 00:58:24 +0200 Subject: [PATCH 13/40] Fix upper area limit --- arch/x86/paging.c | 14 -------------- arch/x86/paging.h | 13 +++++++++++++ core/allocArea.c | 4 ++-- core/allocArea.h | 1 + 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/arch/x86/paging.c b/arch/x86/paging.c index 8b4ef08..666e0c3 100644 --- a/arch/x86/paging.c +++ b/arch/x86/paging.c @@ -25,20 +25,6 @@ #define PD_SHIFT 22 #define PD_MIRROR_PAGE_IDX 1023U -/** Frontier between kernel and user space virtual addresses */ -#define PAGING_BASE_USER_ADDRESS (0x40000000) /* 1GB (must be 4MB-aligned) */ -#define PAGING_TOP_USER_ADDRESS (0xFFFFFFFF) /* 4GB - 1B */ -#define PAGING_USER_SPACE_SIZE (0xc0000000) /* 3GB */ - -/** Length of the space reserved for the mirroring in the kernel - virtual space */ -#define PAGING_MIRROR_SIZE (PAGE_SIZE << 10) /* 1 PD = 1024 Page Tables = 4MB */ - -/** Virtual address where the mirroring takes place */ -#define PAGING_MIRROR_VADDR \ - (PAGING_BASE_USER_ADDRESS - PAGING_MIRROR_SIZE) - - static unsigned long mappedPage = 0; struct pde { diff --git a/arch/x86/paging.h b/arch/x86/paging.h index a862432..717a046 100644 --- a/arch/x86/paging.h +++ b/arch/x86/paging.h @@ -1,6 +1,19 @@ #pragma once #include "types.h" +/** Frontier between kernel and user space virtual addresses */ +#define PAGING_BASE_USER_ADDRESS (0x40000000) /* 1GB (must be 4MB-aligned) */ +#define PAGING_TOP_USER_ADDRESS (0xFFFFFFFF) /* 4GB - 1B */ +#define PAGING_USER_SPACE_SIZE (0xc0000000) /* 3GB */ + +/** Length of the space reserved for the mirroring in the kernel + virtual space */ +#define PAGING_MIRROR_SIZE (PAGE_SIZE << 10) /* 1 PD = 1024 Page Tables = 4MB */ + +/** Virtual address where the mirroring takes place */ +#define PAGING_MIRROR_VADDR \ + (PAGING_BASE_USER_ADDRESS - PAGING_MIRROR_SIZE) + #define PAGING_MEM_USER (1U << 0) #define PAGING_MEM_READ (1U << 1) #define PAGING_MEM_WRITE (1U << 2) diff --git a/core/allocArea.c b/core/allocArea.c index a30b60c..4c5bb20 100644 --- a/core/allocArea.c +++ b/core/allocArea.c @@ -33,8 +33,8 @@ void areaInit(vaddr_t firstMemUsed, vaddr_t lastUsed, vaddr_t stackBottom, vaddr int nbPagesStack = DIV_ROUND_UP((stackTop - stackBottom), PAGE_SIZE); areaAdd(ALIGN_DOWN(stackBottom, PAGE_SIZE), nbPagesStack, FALSE); } - //TODO: fix the 300 - areaAdd(ALIGN_DOWN(areaAddr + PAGE_SIZE, PAGE_SIZE), 300 , TRUE); + int nbFreePages = DIV_ROUND_UP((AREA_MEM_TOP - areaAddr), PAGE_SIZE); + areaAdd(ALIGN_DOWN(areaAddr + PAGE_SIZE, PAGE_SIZE), nbFreePages , TRUE); allocPopulate(); } diff --git a/core/allocArea.h b/core/allocArea.h index 5a7618a..afa8674 100644 --- a/core/allocArea.h +++ b/core/allocArea.h @@ -6,6 +6,7 @@ // areaAlloc map vmem to phy pages #define AREA_PHY_MAP (1<<0) +#define AREA_MEM_TOP PAGING_MIRROR_VADDR struct memArea { vaddr_t startAddr; -- 2.47.0 From be080af906d104a6fd0a40038d465491775a3393 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Thu, 28 Oct 2021 18:19:35 +0200 Subject: [PATCH 14/40] Fix initial area setup The inital kernel stack was not page aligned and thus was found in 2 area --- arch/x86/boot/boot.asm | 2 +- core/allocArea.c | 30 +++++++++++++++++++----------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/arch/x86/boot/boot.asm b/arch/x86/boot/boot.asm index 5f9b676..7588d78 100644 --- a/arch/x86/boot/boot.asm +++ b/arch/x86/boot/boot.asm @@ -28,7 +28,7 @@ align 4 ; stack is properly aligned and failure to align the stack will result in ; undefined behavior. section .bss -align 16 +align 4096 stack_bottom: resb 16384 ; 16 KiB stack_top: diff --git a/core/allocArea.c b/core/allocArea.c index 4c5bb20..73df03a 100644 --- a/core/allocArea.c +++ b/core/allocArea.c @@ -6,14 +6,11 @@ #include "mem.h" #include "stdarg.h" - static struct memArea *freeArea; static struct memArea *usedArea; static int areaMergeFreeArea(struct memArea *prev, struct memArea *next); - -//Kernel stack is inside firstMemUsed-lastUsed void areaInit(vaddr_t firstMemUsed, vaddr_t lastUsed, vaddr_t stackBottom, vaddr_t stackTop) { list_init(freeArea); @@ -27,14 +24,23 @@ void areaInit(vaddr_t firstMemUsed, vaddr_t lastUsed, vaddr_t stackBottom, vaddr if (areaAddr != descAddr && areaAddr != entryAddr) areaAdd(areaAddr, 1, FALSE); - int nbPagesKernel = DIV_ROUND_UP((lastUsed - firstMemUsed), PAGE_SIZE); + //kernel bootstrap part + int nbPagesKernel = DIV_ROUND_UP((stackBottom - firstMemUsed), PAGE_SIZE); areaAdd(ALIGN_DOWN(firstMemUsed, PAGE_SIZE), nbPagesKernel, FALSE); - if(stackBottom > lastUsed){ - int nbPagesStack = DIV_ROUND_UP((stackTop - stackBottom), PAGE_SIZE); - areaAdd(ALIGN_DOWN(stackBottom, PAGE_SIZE), nbPagesStack, FALSE); - } + + //Initial kernel stack + int nbPagesStack = DIV_ROUND_UP((stackTop - stackBottom), PAGE_SIZE); + areaAdd(ALIGN_DOWN(stackBottom, PAGE_SIZE), nbPagesStack, FALSE); + + // Rest of kernel code + int nbPagesKernelCode = DIV_ROUND_UP((lastUsed - stackTop), PAGE_SIZE); + areaAdd(ALIGN_DOWN(stackTop, PAGE_SIZE), nbPagesKernelCode, FALSE); + + // Rest of virtual mem is free int nbFreePages = DIV_ROUND_UP((AREA_MEM_TOP - areaAddr), PAGE_SIZE); - areaAdd(ALIGN_DOWN(areaAddr + PAGE_SIZE, PAGE_SIZE), nbFreePages , TRUE); + areaAdd(ALIGN_DOWN(areaAddr + PAGE_SIZE, PAGE_SIZE), nbFreePages, TRUE); + + // Create allocBank for the rest of the system allocPopulate(); } @@ -183,9 +189,11 @@ int areaFree(vaddr_t addr) pr_info("Cannot find memArea associated to %p\n", addr); return -1; } - for(uint i = 0; i < area->nbPages; i++){ - pageUnmap( area->startAddr + i * PAGE_SIZE); + + for (uint i = 0; i < area->nbPages; i++) { + pageUnmap(area->startAddr + i * PAGE_SIZE); } + list_delete(usedArea, area); insertSorted(&freeArea, area); -- 2.47.0 From ca399ee782349ce099ed6ac6660860dac888a45c Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Thu, 28 Oct 2021 18:33:02 +0200 Subject: [PATCH 15/40] Modify areaAdd api to be able to do more check --- core/allocArea.c | 28 +++++++++++++++------------- core/allocArea.h | 2 +- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/core/allocArea.c b/core/allocArea.c index 73df03a..e18a0e5 100644 --- a/core/allocArea.c +++ b/core/allocArea.c @@ -18,27 +18,23 @@ void areaInit(vaddr_t firstMemUsed, vaddr_t lastUsed, vaddr_t stackBottom, vaddr vaddr_t areaAddr, descAddr, entryAddr; allocSetup(sizeof(struct memArea), &areaAddr, &descAddr, &entryAddr); - areaAdd(descAddr, 1, FALSE); + areaAdd(descAddr, descAddr + PAGE_SIZE, FALSE); if (entryAddr != descAddr) - areaAdd(entryAddr, 1, FALSE); + areaAdd(entryAddr, entryAddr + PAGE_SIZE, FALSE); if (areaAddr != descAddr && areaAddr != entryAddr) - areaAdd(areaAddr, 1, FALSE); + areaAdd(areaAddr, areaAddr + PAGE_SIZE, FALSE); //kernel bootstrap part - int nbPagesKernel = DIV_ROUND_UP((stackBottom - firstMemUsed), PAGE_SIZE); - areaAdd(ALIGN_DOWN(firstMemUsed, PAGE_SIZE), nbPagesKernel, FALSE); + areaAdd(ALIGN_DOWN(firstMemUsed, PAGE_SIZE), stackBottom, FALSE); //Initial kernel stack - int nbPagesStack = DIV_ROUND_UP((stackTop - stackBottom), PAGE_SIZE); - areaAdd(ALIGN_DOWN(stackBottom, PAGE_SIZE), nbPagesStack, FALSE); + areaAdd(stackBottom, stackTop, FALSE); // Rest of kernel code - int nbPagesKernelCode = DIV_ROUND_UP((lastUsed - stackTop), PAGE_SIZE); - areaAdd(ALIGN_DOWN(stackTop, PAGE_SIZE), nbPagesKernelCode, FALSE); + areaAdd(stackTop, lastUsed, FALSE); // Rest of virtual mem is free - int nbFreePages = DIV_ROUND_UP((AREA_MEM_TOP - areaAddr), PAGE_SIZE); - areaAdd(ALIGN_DOWN(areaAddr + PAGE_SIZE, PAGE_SIZE), nbFreePages, TRUE); + areaAdd(areaAddr + PAGE_SIZE, AREA_MEM_TOP, TRUE); // Create allocBank for the rest of the system allocPopulate(); @@ -122,16 +118,22 @@ vaddr_t areaAlloc(unsigned int nbPages, uint32_t flags) return allocated->startAddr; } -int areaAdd(vaddr_t addr, uint nbPages, int isFree) +int areaAdd(vaddr_t start, vaddr_t end, int isFree) { struct memArea **area; + int nbPages = (end-start)/PAGE_SIZE; + + assert(nbPages >0); + assert(IS_ALIGNED(start, PAGE_SIZE)); + assert(IS_ALIGNED(end, PAGE_SIZE)); + struct memArea *newArea = (struct memArea *)malloc(sizeof(struct memArea)); if (!newArea) return (vaddr_t)NULL; newArea->nbPages = nbPages; - newArea->startAddr = addr; + newArea->startAddr = start; if (isFree) { area = &freeArea; diff --git a/core/allocArea.h b/core/allocArea.h index afa8674..948e527 100644 --- a/core/allocArea.h +++ b/core/allocArea.h @@ -19,4 +19,4 @@ struct memArea { void areaInit(vaddr_t firstMemUsed, vaddr_t lastUsed, vaddr_t stack_bottom, vaddr_t stack_top); vaddr_t areaAlloc(unsigned int nbPages, uint32_t flags); int areaFree(vaddr_t addr); -int areaAdd(vaddr_t addr, uint nbPages, int isFree); +int areaAdd(vaddr_t begin, vaddr_t end, int isFree); -- 2.47.0 From f1039b7fe4fe3a8f1a22597c3af794b1aa0272e3 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Thu, 28 Oct 2021 19:18:03 +0200 Subject: [PATCH 16/40] context: add copy kernel context fix also some indentation --- arch/x86/mmuContext.c | 16 ++++++--- arch/x86/paging.c | 84 ++++++++++++++++++++++++++++++------------- arch/x86/paging.h | 1 + 3 files changed, 72 insertions(+), 29 deletions(-) diff --git a/arch/x86/mmuContext.c b/arch/x86/mmuContext.c index 278bfb9..ae778d2 100644 --- a/arch/x86/mmuContext.c +++ b/arch/x86/mmuContext.c @@ -2,8 +2,8 @@ #include "alloc.h" #include "allocArea.h" #include "errno.h" -#include "klibc.h" #include "irq.h" +#include "klibc.h" #include "list.h" #include "paging.h" #include "stdarg.h" @@ -70,7 +70,13 @@ struct mmu_context *mmuContextCreate() ctx->ref = 1; - //TODO copy kernel space + if (pagingCopyKernelSpace(ctx->vaddr_PD, ctx->paddr_PD, currentContext->vaddr_PD)) { + pr_err("Fail to copy Kernel space\n"); + free(ctx); + + return NULL; + } + disable_IRQs(flags); list_add_tail(listContext, ctx); restore_IRQs(flags); @@ -78,7 +84,7 @@ struct mmu_context *mmuContextCreate() return ctx; } -int mmuContextSyncKernelPDE(int pdEntry, void * pde, size_t pdeSize) +int mmuContextSyncKernelPDE(int pdEntry, void *pde, size_t pdeSize) { uint32_t flags; struct mmu_context *destContext; @@ -91,8 +97,8 @@ int mmuContextSyncKernelPDE(int pdEntry, void * pde, size_t pdeSize) assert(destContext->ref > 0); - dest_pd = (void *)destContext->vaddr_PD; - memcpy(dest_pd + pdEntry *pdeSize, pde, pdeSize); + dest_pd = (void *)destContext->vaddr_PD; + memcpy(dest_pd + pdEntry * pdeSize, pde, pdeSize); } restore_IRQs(flags); diff --git a/arch/x86/paging.c b/arch/x86/paging.c index 666e0c3..19bc60b 100644 --- a/arch/x86/paging.c +++ b/arch/x86/paging.c @@ -133,17 +133,15 @@ int pageMap(vaddr_t vaddr, paddr_t paddr, int flags) uint pdEntry = vaddr >> (PD_SHIFT); uint ptEntry = (vaddr >> PT_SHIFT) & PTE_MASK; - if ((vaddr >= PAGING_MIRROR_VADDR) && - (vaddr < PAGING_MIRROR_VADDR + PAGING_MIRROR_SIZE)) + if ((vaddr >= PAGING_MIRROR_VADDR) && (vaddr < PAGING_MIRROR_VADDR + PAGING_MIRROR_SIZE)) return -EINVAL; // Thank to mirroring, we can access the PD struct pde *pd = - (struct pde *)(PAGING_MIRROR_VADDR + PAGE_SIZE*(PAGING_MIRROR_VADDR>>PD_SHIFT)); + (struct pde *)(PAGING_MIRROR_VADDR + PAGE_SIZE * (PAGING_MIRROR_VADDR >> PD_SHIFT)); struct pte *pt = (struct pte *)((PAGING_MIRROR_VADDR) + (pdEntry * PAGE_SIZE)); - if (!pd[pdEntry].present) { paddr_t ptPhy = allocPhyPage(1); if (ptPhy == (vaddr_t)NULL) @@ -153,12 +151,12 @@ int pageMap(vaddr_t vaddr, paddr_t paddr, int flags) pd[pdEntry].write = 1; pd[pdEntry].pt_addr = (ptPhy >> PT_SHIFT); - if(vaddr < PAGING_BASE_USER_ADDRESS){ - pd[pdEntry].user = 0; + if (vaddr < PAGING_BASE_USER_ADDRESS) { + pd[pdEntry].user = 0; mmuContextSyncKernelPDE(pdEntry, &pd[pdEntry], sizeof(struct pde)); - }else{ + } else { assert(flags & PAGING_MEM_USER); - pd[pdEntry].user = 1; + pd[pdEntry].user = 1; } __native_flush_tlb_single((vaddr_t)pt); @@ -190,13 +188,12 @@ int pageUnmap(vaddr_t vaddr) uint pdEntry = vaddr >> (PD_SHIFT); uint ptEntry = (vaddr >> PT_SHIFT) & PTE_MASK; - if ((vaddr >= PAGING_MIRROR_VADDR) && - (vaddr < PAGING_MIRROR_VADDR + PAGING_MIRROR_SIZE)) + if ((vaddr >= PAGING_MIRROR_VADDR) && (vaddr < PAGING_MIRROR_VADDR + PAGING_MIRROR_SIZE)) return -EINVAL; // Thank to mirroring, we can access the PD struct pde *pd = - (struct pde *)(PAGING_MIRROR_VADDR + PAGE_SIZE*(PAGING_MIRROR_VADDR>>PD_SHIFT)); + (struct pde *)(PAGING_MIRROR_VADDR + PAGE_SIZE * (PAGING_MIRROR_VADDR >> PD_SHIFT)); struct pte *pt = (struct pte *)((PAGING_MIRROR_VADDR) + (pdEntry * PAGE_SIZE)); if (!pd[pdEntry].present) @@ -230,7 +227,7 @@ paddr_t pagingGetPaddr(vaddr_t vaddr) // Thank to mirroring, we can access the PD struct pde *pd = - (struct pde *)(PAGING_MIRROR_VADDR + PAGE_SIZE*(PAGING_MIRROR_VADDR>>PD_SHIFT)); + (struct pde *)(PAGING_MIRROR_VADDR + PAGE_SIZE * (PAGING_MIRROR_VADDR >> PD_SHIFT)); struct pte *pt = (struct pte *)((PAGING_MIRROR_VADDR) + (pdEntry * PAGE_SIZE)); @@ -250,25 +247,64 @@ unsigned long getNbMappedPage(void) paddr_t pagingGetCurrentPDPaddr() { - struct pdbr pdbr; - asm volatile("movl %%cr3, %0\n": "=r"(pdbr)); - return (pdbr.pd_paddr << 12); + struct pdbr pdbr; + asm volatile("movl %%cr3, %0\n" : "=r"(pdbr)); + return (pdbr.pd_paddr << 12); } int pagingSetCurrentPDPaddr(paddr_t paddrPD) { - struct pdbr pdbr; + struct pdbr pdbr; - assert(paddrPD != 0); - assert(IS_ALIGNED(paddrPD, PAGE_SIZE)); + assert(paddrPD != 0); + assert(IS_ALIGNED(paddrPD, PAGE_SIZE)); - /* Setup the value of the PDBR */ - memset(& pdbr, 0x0, sizeof(struct pdbr)); /* Reset the PDBR */ - pdbr.pd_paddr = (paddrPD >> 12); + /* Setup the value of the PDBR */ + memset(&pdbr, 0x0, sizeof(struct pdbr)); /* Reset the PDBR */ + pdbr.pd_paddr = (paddrPD >> 12); - /* Configure the MMU according to the PDBR */ - asm volatile ("movl %0,%%cr3\n" ::"r"(pdbr)); + /* Configure the MMU according to the PDBR */ + asm volatile("movl %0,%%cr3\n" ::"r"(pdbr)); - return 0; + return 0; +} + +int pagingCopyKernelSpace(vaddr_t destVaddrPD, paddr_t destPaddrPD, vaddr_t srcVaddrPD) +{ + struct pde *src_pd = (struct pde *)srcVaddrPD; + struct pde *dest_pd = (struct pde *)destVaddrPD; + struct pde mirror_pde; + uint index_in_pd; + + /* Fill destination PD with zeros */ + memset((void *)destVaddrPD, 0x0, PAGE_SIZE); + + /* Synchronize it with the master Kernel MMU context. Stop just + before the mirroring ! */ + for (index_in_pd = 0; index_in_pd < (PAGING_MIRROR_VADDR >> 22); /* 1 PDE = 1 PT + = 1024 Pages + = 4MB */ + index_in_pd++) { + /* Copy the master's configuration */ + dest_pd[index_in_pd] = src_pd[index_in_pd]; + + /* We DON'T mark the underlying PT and pages as referenced + because all the PD are equivalent in the kernel space: as + soon as a page is mapped in the kernel, it is mapped by X + address spaces, and as soon as it is unmapped by 1 address + space, it is unmapped in all the others. So that for X + address spaces, the reference counter will be either 0 or X, + and not something else: using the reference counter correctly + won't be of any use and would consume some time in updating it. */ + } + + /* Setup the mirroring for the new address space */ + mirror_pde.present = TRUE; + mirror_pde.write = 1; + mirror_pde.user = 0; /* This is a KERNEL PDE */ + mirror_pde.pt_addr = (destPaddrPD >> 12); + dest_pd[PAGING_MIRROR_VADDR >> 22] = mirror_pde; + + return 0; } diff --git a/arch/x86/paging.h b/arch/x86/paging.h index 717a046..b676b39 100644 --- a/arch/x86/paging.h +++ b/arch/x86/paging.h @@ -27,3 +27,4 @@ unsigned long getNbMappedPage(void); int pagingSetCurrentPDPaddr(paddr_t paddrPD); paddr_t pagingGetPaddr(vaddr_t vaddr); paddr_t pagingGetCurrentPDPaddr(); +int pagingCopyKernelSpace(vaddr_t destVaddrPD, paddr_t destPaddrPD, vaddr_t srcVaddrPD); -- 2.47.0 From 186192023de01f93e24d2176203d5257bc424507 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Thu, 28 Oct 2021 19:24:31 +0200 Subject: [PATCH 17/40] Exception: fix stack for ex withour err code --- arch/x86/exception_wrappers.S | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/x86/exception_wrappers.S b/arch/x86/exception_wrappers.S index 4ba8b55..122bcd0 100644 --- a/arch/x86/exception_wrappers.S +++ b/arch/x86/exception_wrappers.S @@ -157,8 +157,6 @@ popl %ecx popl %eax popl %ebp - /* Remove fake error code */ - addl $4, %esp iret .endm -- 2.47.0 From d702c7b60e85339a37f0c7ee6246caca6c1af8cb Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Thu, 28 Oct 2021 23:18:05 +0200 Subject: [PATCH 18/40] malloc: fix recursivity with areaAlloc --- core/alloc.c | 95 +++++++++++++++++++++++++++++++----------------- core/alloc.h | 7 ++-- core/allocArea.c | 59 +++++++++++++++++++++++++++++- core/allocArea.h | 4 ++ core/mem.c | 1 + 5 files changed, 127 insertions(+), 39 deletions(-) diff --git a/core/alloc.c b/core/alloc.c index e9058c5..05a086d 100644 --- a/core/alloc.c +++ b/core/alloc.c @@ -17,7 +17,7 @@ static struct slabDesc *slub; static int allocInitialized = FALSE; static int allocSlab(struct slabDesc **desc, size_t sizeEl, size_t sizeSlab, - int self_containing); + int self_containing, int neverEmpty); static int allocSlabEntry(struct slabEntry **desc, size_t sizeEl, size_t sizeSlab, int selfContained); static int formatPage(struct slabEntry *desc, size_t size, size_t sizeSlab, int selfContained); @@ -28,27 +28,29 @@ static struct { size_t elementSize; size_t slabSize; unsigned char isSelf; -} initSlab[] = {{4, PAGE_SIZE, 0}, - {8, PAGE_SIZE, 0}, - {16, PAGE_SIZE, 0}, - {32, PAGE_SIZE, 0}, - {64, PAGE_SIZE, 0}, - {128, PAGE_SIZE, 0}, - {256, 2 * PAGE_SIZE, 0}, - {1024, 2 * PAGE_SIZE, 0}, - {2048, 3 * PAGE_SIZE, 0}, - {4096, 4 * PAGE_SIZE, 0}, - {0, 0, 0}}; + unsigned char neverEmpty; +} initSlab[] = {{4, PAGE_SIZE, 0, 0}, + {8, PAGE_SIZE, 0, 0}, + {16, PAGE_SIZE, 0, 0}, + {32, PAGE_SIZE, 0, 0}, + {64, PAGE_SIZE, 0, 0}, + {128, PAGE_SIZE, 0, 0}, + {256, 2 * PAGE_SIZE, 0, 0}, + {1024, 2 * PAGE_SIZE, 0, 0}, + {2048, 3 * PAGE_SIZE, 0, 0}, + {4096, 4 * PAGE_SIZE, 0, 0}, + {0, 0, 0, 0}}; int allocSetup(size_t sizeOfArea, vaddr_t *areaAddr, vaddr_t *descAddr, vaddr_t *entryAddr) { list_init(slub); - assert(allocBookSlab(sizeof(struct slabDesc), PAGE_SIZE, TRUE) == 0); + assert(allocBookSlab(sizeof(struct slabDesc), PAGE_SIZE, TRUE, FALSE) == 0); *descAddr = (vaddr_t)allocGetSlab(sizeof(struct slabDesc)); - assert(allocBookSlab(sizeof(struct slabEntry), PAGE_SIZE, TRUE) == 0); + assert(allocBookSlab(sizeof(struct slabEntry), PAGE_SIZE, TRUE, FALSE) == 0); *entryAddr = (vaddr_t)allocGetSlab(sizeof(struct slabEntry)); - assert(allocBookSlab(sizeOfArea, PAGE_SIZE, TRUE) == 0); + printf("allocSetup for sizeOfArea %d\n", sizeOfArea); + assert(allocBookSlab(sizeOfArea, PAGE_SIZE, TRUE, TRUE) == 0); *areaAddr = (vaddr_t)allocGetSlab(sizeOfArea); allocInitialized = TRUE; @@ -61,7 +63,7 @@ int allocPopulate() int ret; if ((ret = allocBookSlab(initSlab[i].elementSize, initSlab[i].slabSize, - initSlab[i].isSelf))) { + initSlab[i].isSelf, initSlab[i].neverEmpty))) { if (ret == -EEXIST) continue; pr_err("Fail to allocBookSlab %d for %d \n", ret, (1U << i)); @@ -73,7 +75,7 @@ int allocPopulate() return 0; } -int allocBookSlab(size_t sizeEl, size_t sizeSlab, int selfContained) +int allocBookSlab(size_t sizeEl, size_t sizeSlab, int selfContained, int neverEmpty) { struct slabDesc *slab = NULL; struct slabDesc *newSlab = NULL; @@ -95,7 +97,7 @@ int allocBookSlab(size_t sizeEl, size_t sizeSlab, int selfContained) } } - if ((ret = allocSlab(&newSlab, sizeEl, sizeSlab, selfContained))) { + if ((ret = allocSlab(&newSlab, sizeEl, sizeSlab, selfContained, neverEmpty))) { pr_devel("Failed to alloc Slab\n"); restore_IRQs(flags); return ret; @@ -112,7 +114,8 @@ int allocBookSlab(size_t sizeEl, size_t sizeSlab, int selfContained) return 0; } -static int allocSlab(struct slabDesc **desc, size_t size, size_t sizeSlab, int selfContained) +static int allocSlab(struct slabDesc **desc, size_t size, size_t sizeSlab, int selfContained, + int neverEmpty) { uint nbPage, i; vaddr_t alloc; @@ -153,10 +156,11 @@ static int allocSlab(struct slabDesc **desc, size_t size, size_t sizeSlab, int s struct slabEntry *slab = &(*desc)->slab; list_singleton(slab, slab); - slab->page = (vaddr_t)alloc; - slab->full = 0; - slab->size = sizeSlab; - (*desc)->size = size; + slab->page = (vaddr_t)alloc; + slab->full = 0; + slab->size = sizeSlab; + (*desc)->neverEmpty = neverEmpty; + (*desc)->size = size; return formatPage(&(*desc)->slab, size, sizeSlab, selfContained); @@ -202,8 +206,6 @@ static int allocSlabEntry(struct slabEntry **desc, size_t size, size_t sizeSlab, (*desc)->size = sizeSlab; return formatPage((*desc), size, sizeSlab, selfContained); - - return -ENOMEM; } static int formatPage(struct slabEntry *desc, size_t size, size_t sizeSlab, int selfContained) @@ -261,7 +263,7 @@ void *malloc(size_t size) disable_IRQs(flags); - if (size >= PAGE_SIZE){ + if (size >= PAGE_SIZE) { vaddr_t area = areaAlloc(DIV_ROUND_UP(size, PAGE_SIZE), AREA_PHY_MAP); return (void *)area; @@ -271,12 +273,36 @@ void *malloc(size_t size) return NULL; } + struct slabEntry *slabList = &slab->slab; list_foreach(&slab->slab, slabEntry, slabIdx) { if (!slabEntry->full) { - // pr_devel("found place in slub %d at idx %d for size %d\n", slubIdx, - // slabIdx, size); + // pr_devel("found place in slab idx %d for size %d\n", slabIdx, slab->size); ret = allocFromSlab(slabEntry); + if (slabEntry->full && slab->neverEmpty) { + + pr_devel("Prealloc place for slab for object size %d\n", slab->size); + assert(IS_SELF_CONTAINED(slabEntry)); + size_t slabSize = slabEntry->size; + int nbPages = DIV_ROUND_UP(slabSize, PAGE_SIZE); + struct slabEntry *entry = (struct slabEntry *)areaBook(nbPages, AREA_PHY_MAP); + if (entry == NULL) { + restore_IRQs(flags); + + return NULL; + } + + (entry)->freeEl = (char *)(entry) + sizeof(struct slabEntry); + list_singleton(entry, entry); + entry->page = (vaddr_t)entry; + entry->full = 0; + entry->size = slabSize; + + formatPage(entry, slab->size, slabSize, 1); + list_add_tail(slabList, entry); + areaAdd((vaddr_t)entry, (vaddr_t)entry + nbPages * PAGE_SIZE, FALSE); + } + restore_IRQs(flags); return ret; } @@ -284,8 +310,7 @@ void *malloc(size_t size) // No room found struct slabEntry *newSlabEntry; - struct slabEntry *slabList = &slab->slab; - size_t slabSize = MAX(PAGE_SIZE, size); + size_t slabSize = MAX(PAGE_SIZE, size); int retSlab; if ((retSlab = allocSlabEntry(&newSlabEntry, slab->size, slabSize, @@ -304,7 +329,8 @@ void *malloc(size_t size) return ret; } -void *zalloc(size_t size){ +void *zalloc(size_t size) +{ void *alloc = malloc(size); if (alloc != NULL) @@ -333,7 +359,8 @@ static int freeFromSlab(void *ptr, struct slabEntry *slab) return 0; } -int freeSlabAllocated(void *ptr){ +int freeSlabAllocated(void *ptr) +{ struct slabDesc *slab; int slabIdx; int flags; @@ -361,8 +388,8 @@ void free(void *ptr) { if (!ptr) return; - if(!freeSlabAllocated(ptr)) + if (!freeSlabAllocated(ptr)) return; - if(areaFree((vaddr_t)ptr)) + if (areaFree((vaddr_t)ptr)) pr_err("free: cannot found origin\n"); } diff --git a/core/alloc.h b/core/alloc.h index 944bf7c..df6171f 100644 --- a/core/alloc.h +++ b/core/alloc.h @@ -12,7 +12,7 @@ int allocPopulate(); * Allow malloc to allocate elements of this precise size. * Otherwise the allocation will be in the closest biggest pool. * */ -int allocBookSlab(size_t size, size_t sizeSlab, int selfContained); +int allocBookSlab(size_t size, size_t sizeSlab, int selfContained, int neverEmpty); void *malloc(size_t size); void *zalloc(size_t size); @@ -22,9 +22,9 @@ void free(void *ptr); */ struct slabEntry { vaddr_t page; - size_t size; void *freeEl; - char full; + size_t size; + bool_t full;//TODO replace by freeEl == NULL struct slabEntry *next; struct slabEntry *prev; }; @@ -32,6 +32,7 @@ struct slabEntry { struct slabDesc { struct slabEntry slab; size_t size; + bool_t neverEmpty; struct slabDesc *next; struct slabDesc *prev; }; diff --git a/core/allocArea.c b/core/allocArea.c index e18a0e5..a733811 100644 --- a/core/allocArea.c +++ b/core/allocArea.c @@ -2,6 +2,7 @@ #include "alloc.h" #include "assert.h" #include "kernel.h" +#include "irq.h" #include "list.h" #include "mem.h" #include "stdarg.h" @@ -71,13 +72,64 @@ static void insertSorted(struct memArea **list, struct memArea *item) list_add_tail(*list, item); } +vaddr_t areaBook(unsigned int nbPages, uint32_t flags){ + + struct memArea *area; + vaddr_t allocated; + uint32_t irqFlags; + + disable_IRQs(irqFlags); + + area = areaFindFit(nbPages); + if (!area){ + printf("NULL<\n"); + restore_IRQs(irqFlags); + + return (vaddr_t)NULL; + } + + if (area->nbPages == nbPages) { + list_delete(freeArea, area); + allocated = area->startAddr; + } else { + + allocated = area->startAddr; + + area->nbPages -= nbPages; + area->startAddr += nbPages * PAGE_SIZE; + + } + + if (flags & AREA_PHY_MAP) { + for (uint i = 0; i < nbPages; i++) { + paddr_t page = allocPhyPage(1); + if (page) { + pageMap(allocated + i * PAGE_SIZE, page, PAGING_MEM_WRITE); + } else { + printf("Ooops\n"); + // TODO + assert(0); + } + } + } + + restore_IRQs(irqFlags); + return allocated; +} + vaddr_t areaAlloc(unsigned int nbPages, uint32_t flags) { struct memArea *area, *allocated; + uint32_t irqFlags; + + disable_IRQs(irqFlags); area = areaFindFit(nbPages); - if (!area) + if (!area){ + restore_IRQs(irqFlags); + return (vaddr_t)NULL; + } if (area->nbPages == nbPages) { list_delete(freeArea, area); @@ -87,6 +139,7 @@ vaddr_t areaAlloc(unsigned int nbPages, uint32_t flags) struct memArea *newArea = (struct memArea *)malloc(sizeof(struct memArea)); if (!newArea) { pr_devel("Failed to allocated area of %d pages\n", nbPages); + restore_IRQs(irqFlags); return (vaddr_t)NULL; } @@ -109,12 +162,14 @@ vaddr_t areaAlloc(unsigned int nbPages, uint32_t flags) if (page) { pageMap(allocated->startAddr + i * PAGE_SIZE, page, PAGING_MEM_WRITE); } else { + printf("Ooops\n"); // TODO - assert(1); + assert(0); } } } + restore_IRQs(irqFlags); return allocated->startAddr; } diff --git a/core/allocArea.h b/core/allocArea.h index 948e527..1b21709 100644 --- a/core/allocArea.h +++ b/core/allocArea.h @@ -18,5 +18,9 @@ struct memArea { void areaInit(vaddr_t firstMemUsed, vaddr_t lastUsed, vaddr_t stack_bottom, vaddr_t stack_top); vaddr_t areaAlloc(unsigned int nbPages, uint32_t flags); +// Remove an area from the free ones but do not add it into used ones. +// This area should be latter added woth areaAdd. +// Used by malloc to avoid recursivity issue +vaddr_t areaBook(unsigned int nbPages, uint32_t flags); int areaFree(vaddr_t addr); int areaAdd(vaddr_t begin, vaddr_t end, int isFree); diff --git a/core/mem.c b/core/mem.c index de471b0..4fa25ce 100644 --- a/core/mem.c +++ b/core/mem.c @@ -133,6 +133,7 @@ paddr_t allocPhyPage(uint nbPage) next = mem->next; } allocatedPage += nbPage; + return head->phy_addr; } -- 2.47.0 From 7081fea36d0768fb52b006186b3bb09cc4b14d95 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Thu, 28 Oct 2021 23:49:58 +0200 Subject: [PATCH 19/40] Fix areaAlloc map failing and tests --- core/allocArea.c | 46 +++++++++++++++++++++++++++++++--------------- core/kthread.c | 2 ++ tests/test.c | 8 +++----- 3 files changed, 36 insertions(+), 20 deletions(-) diff --git a/core/allocArea.c b/core/allocArea.c index a733811..b8ccf94 100644 --- a/core/allocArea.c +++ b/core/allocArea.c @@ -1,8 +1,8 @@ #include "allocArea.h" #include "alloc.h" #include "assert.h" -#include "kernel.h" #include "irq.h" +#include "kernel.h" #include "list.h" #include "mem.h" #include "stdarg.h" @@ -25,10 +25,10 @@ void areaInit(vaddr_t firstMemUsed, vaddr_t lastUsed, vaddr_t stackBottom, vaddr if (areaAddr != descAddr && areaAddr != entryAddr) areaAdd(areaAddr, areaAddr + PAGE_SIZE, FALSE); - //kernel bootstrap part + // kernel bootstrap part areaAdd(ALIGN_DOWN(firstMemUsed, PAGE_SIZE), stackBottom, FALSE); - //Initial kernel stack + // Initial kernel stack areaAdd(stackBottom, stackTop, FALSE); // Rest of kernel code @@ -72,7 +72,8 @@ static void insertSorted(struct memArea **list, struct memArea *item) list_add_tail(*list, item); } -vaddr_t areaBook(unsigned int nbPages, uint32_t flags){ +vaddr_t areaBook(unsigned int nbPages, uint32_t flags) +{ struct memArea *area; vaddr_t allocated; @@ -81,7 +82,7 @@ vaddr_t areaBook(unsigned int nbPages, uint32_t flags){ disable_IRQs(irqFlags); area = areaFindFit(nbPages); - if (!area){ + if (!area) { printf("NULL<\n"); restore_IRQs(irqFlags); @@ -97,18 +98,25 @@ vaddr_t areaBook(unsigned int nbPages, uint32_t flags){ area->nbPages -= nbPages; area->startAddr += nbPages * PAGE_SIZE; - } if (flags & AREA_PHY_MAP) { for (uint i = 0; i < nbPages; i++) { paddr_t page = allocPhyPage(1); if (page) { - pageMap(allocated + i * PAGE_SIZE, page, PAGING_MEM_WRITE); - } else { + if (pageMap(allocated + i * PAGE_SIZE, page, PAGING_MEM_WRITE)) { + unrefPhyPage(page); + page = (paddr_t)NULL; + } else { + unrefPhyPage(page); + } + } + if (page == (paddr_t)NULL) { printf("Ooops\n"); // TODO - assert(0); + // assert(0); + restore_IRQs(irqFlags); + return (vaddr_t)NULL; } } } @@ -125,7 +133,7 @@ vaddr_t areaAlloc(unsigned int nbPages, uint32_t flags) disable_IRQs(irqFlags); area = areaFindFit(nbPages); - if (!area){ + if (!area) { restore_IRQs(irqFlags); return (vaddr_t)NULL; @@ -160,11 +168,18 @@ vaddr_t areaAlloc(unsigned int nbPages, uint32_t flags) for (uint i = 0; i < nbPages; i++) { paddr_t page = allocPhyPage(1); if (page) { - pageMap(allocated->startAddr + i * PAGE_SIZE, page, PAGING_MEM_WRITE); - } else { + if (pageMap(allocated->startAddr + i * PAGE_SIZE, page, PAGING_MEM_WRITE)) { + page = (paddr_t)NULL; + } else { + unrefPhyPage(page); + } + } + if (page == (paddr_t)NULL) { printf("Ooops\n"); // TODO - assert(0); + // assert(0); + restore_IRQs(irqFlags); + return (vaddr_t)NULL; } } } @@ -177,9 +192,10 @@ int areaAdd(vaddr_t start, vaddr_t end, int isFree) { struct memArea **area; - int nbPages = (end-start)/PAGE_SIZE; + int nbPages = (end - start) / PAGE_SIZE; + pr_devel("Add %s area 0x%x->0x%x (%d)\n", isFree ? "free" : "used", start, end, nbPages); - assert(nbPages >0); + assert(nbPages > 0); assert(IS_ALIGNED(start, PAGE_SIZE)); assert(IS_ALIGNED(end, PAGE_SIZE)); diff --git a/core/kthread.c b/core/kthread.c index 8fc1f55..9076793 100644 --- a/core/kthread.c +++ b/core/kthread.c @@ -55,6 +55,8 @@ struct kthread *kthreadCreate(const char *name, cpu_kstate_function_arg1_t func, return NULL; thread->stackAddr = (vaddr_t)malloc(KTHREAD_DEFAULT_STACK_SIZE); + if(!thread->stackAddr) + return NULL; #ifdef DEBUG printf("Alloc stack at 0x%x struct at 0x%x\n", thread->stackAddr, thread); #endif diff --git a/tests/test.c b/tests/test.c index 477c381..aa9cb60 100644 --- a/tests/test.c +++ b/tests/test.c @@ -154,9 +154,7 @@ static void testPaging(void) int allocCount = 0; int freeCount = 0; - while ((page = (struct phyMemDesc *)allocPhyPage(1)) != NULL) { - assertmsg(pageMap((vaddr_t)page, (paddr_t)page, PAGING_MEM_WRITE) == 0, - "Fail to map page %d\n", allocCount); + while ((page = (struct phyMemDesc *)areaAlloc(1, AREA_PHY_MAP)) != NULL) { memset(page, allocCount, PAGE_SIZE); allocCount++; list_add_tail(allocated_page_list, page); @@ -167,12 +165,12 @@ static void testPaging(void) (page = list_pop_head(allocated_page_list)) != NULL) { assertmsg((char)page->phy_addr == (char)freeCount, "page modified %d but is %d\n", freeCount, page->phy_addr); - assertmsg(unrefPhyPage((ulong)page) >= 0, "Failed to free page %d\n", (ulong)page); - pageUnmap((vaddr_t)page); + areaFree((vaddr_t)page); freeCount++; } printf("%d pages freed\n", freeCount); + assert(freeCount == allocCount); assertmsg((page = (struct phyMemDesc *)allocPhyPage(1)) != NULL, "Cannot allocate memory\n"); unrefPhyPage((ulong)page); -- 2.47.0 From 55e709adb54c1ca80d4aa148cef0946f4dfc5d2d Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Fri, 29 Oct 2021 23:06:03 +0200 Subject: [PATCH 20/40] allocArea: implement allocPhy failure case --- core/alloc.c | 1 - core/allocArea.c | 10 ++++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/core/alloc.c b/core/alloc.c index 05a086d..b2554a4 100644 --- a/core/alloc.c +++ b/core/alloc.c @@ -49,7 +49,6 @@ int allocSetup(size_t sizeOfArea, vaddr_t *areaAddr, vaddr_t *descAddr, vaddr_t *descAddr = (vaddr_t)allocGetSlab(sizeof(struct slabDesc)); assert(allocBookSlab(sizeof(struct slabEntry), PAGE_SIZE, TRUE, FALSE) == 0); *entryAddr = (vaddr_t)allocGetSlab(sizeof(struct slabEntry)); - printf("allocSetup for sizeOfArea %d\n", sizeOfArea); assert(allocBookSlab(sizeOfArea, PAGE_SIZE, TRUE, TRUE) == 0); *areaAddr = (vaddr_t)allocGetSlab(sizeOfArea); allocInitialized = TRUE; diff --git a/core/allocArea.c b/core/allocArea.c index b8ccf94..67945d0 100644 --- a/core/allocArea.c +++ b/core/allocArea.c @@ -112,10 +112,9 @@ vaddr_t areaBook(unsigned int nbPages, uint32_t flags) } } if (page == (paddr_t)NULL) { - printf("Ooops\n"); - // TODO - // assert(0); + areaFree(allocated); restore_IRQs(irqFlags); + return (vaddr_t)NULL; } } @@ -175,10 +174,9 @@ vaddr_t areaAlloc(unsigned int nbPages, uint32_t flags) } } if (page == (paddr_t)NULL) { - printf("Ooops\n"); - // TODO - // assert(0); + areaFree(allocated->startAddr); restore_IRQs(irqFlags); + return (vaddr_t)NULL; } } -- 2.47.0 From 79a2bc58aeced2f8d66c7de4cb21addd22cc247f Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Sat, 30 Oct 2021 00:28:31 +0200 Subject: [PATCH 21/40] Integrate MMU context --- arch/x86/mmuContext.c | 61 +++++++++++++++++++++++++++++++++++++++++++ arch/x86/paging.c | 40 ++++++++++++++++++++++++++++ arch/x86/paging.h | 1 + core/main.c | 2 ++ core/mmuContext.h | 4 +++ tests/test.c | 16 +++++++++++- 6 files changed, 123 insertions(+), 1 deletion(-) diff --git a/arch/x86/mmuContext.c b/arch/x86/mmuContext.c index ae778d2..164bb71 100644 --- a/arch/x86/mmuContext.c +++ b/arch/x86/mmuContext.c @@ -20,6 +20,10 @@ struct mmu_context { static struct mmu_context *listContext = NULL; static struct mmu_context *currentContext = NULL; +struct mmu_context * mmuContextGetCurrent(){ + return currentContext; +} + int mmuContextSetup() { struct mmu_context *initialCtx; @@ -84,6 +88,63 @@ struct mmu_context *mmuContextCreate() return ctx; } +int mmuContextRef(struct mmu_context *ctx) +{ + uint32_t flags; + + disable_IRQs(flags); + + // ref == 0 => suppression + assert(ctx->ref > 0); + ctx->ref++; + + restore_IRQs(flags); + + return 0; +} + +int mmuContextUnref(struct mmu_context *ctx) +{ + uint32_t flags; + + disable_IRQs(flags); + + assert(ctx->ref > 0); + ctx->ref--; + + if (ctx->ref == 0) { + list_delete(listContext, ctx); + pagingClearUserContext(ctx->vaddr_PD); + areaFree(ctx->vaddr_PD); + free(ctx); + } + + restore_IRQs(flags); + + return 0; +} + +int mmuContextSwitch(struct mmu_context *ctx) +{ + uint32_t flags; + + disable_IRQs(flags); + assert(ctx->ref > 0); + assert(currentContext->ref > 0); + + if (ctx != currentContext) { + struct mmu_context *prev = currentContext; + + ctx->ref++; + currentContext = ctx; + pagingSetCurrentPDPaddr(ctx->paddr_PD); + mmuContextUnref(prev); + } + + restore_IRQs(flags); + return 0; +} + int mmuContextSyncKernelPDE(int pdEntry, void *pde, size_t pdeSize) { uint32_t flags; diff --git a/arch/x86/paging.c b/arch/x86/paging.c index 19bc60b..b7759f0 100644 --- a/arch/x86/paging.c +++ b/arch/x86/paging.c @@ -1,3 +1,4 @@ +#include "allocArea.h" #include "paging.h" #include "errno.h" #include "kernel.h" @@ -269,6 +270,45 @@ int pagingSetCurrentPDPaddr(paddr_t paddrPD) return 0; } +// unmap page inside this MMU context +int pagingClearUserContext(vaddr_t vaddr_PD) +{ + struct pde *pd = (struct pde *)vaddr_PD; + //Tmp pt to unref page they reference + struct pte *pt = (struct pte *)areaAlloc(1, 0); + + if(pt == NULL) + return -ENOMEM; + + for (int pdIdx = PAGING_BASE_USER_ADDRESS >> PD_SHIFT; pdIdx < 1024; pdIdx++) { + + if(!pd[pdIdx].present){ + memset(&pd[pdIdx], 0, sizeof(struct pde)); + + continue; + } + paddr_t ptAddr = pd[pdIdx].pt_addr << PT_SHIFT; + assert(!pageMap(ptAddr, (vaddr_t)pt, PAGING_MEM_USER | PAGING_MEM_WRITE)); + for(int ptIdx = 0; ptIdx < 1024; ptIdx ++){ + if(!pt[ptIdx].present){ + memset(&pt[ptIdx], 0, sizeof(struct pte)); + + continue; + } + unrefPhyPage(pt[ptIdx].paddr); + memset(&pt[ptIdx], 0, sizeof(struct pte)); + } + assert(!pageUnmap((vaddr_t)pt)); + memset(&pd[pdIdx], 0, sizeof(struct pde)); + + unrefPhyPage(ptAddr); + } + + areaFree((vaddr_t)pt); + + return 0; +} + int pagingCopyKernelSpace(vaddr_t destVaddrPD, paddr_t destPaddrPD, vaddr_t srcVaddrPD) { struct pde *src_pd = (struct pde *)srcVaddrPD; diff --git a/arch/x86/paging.h b/arch/x86/paging.h index b676b39..360d052 100644 --- a/arch/x86/paging.h +++ b/arch/x86/paging.h @@ -28,3 +28,4 @@ int pagingSetCurrentPDPaddr(paddr_t paddrPD); paddr_t pagingGetPaddr(vaddr_t vaddr); paddr_t pagingGetCurrentPDPaddr(); int pagingCopyKernelSpace(vaddr_t destVaddrPD, paddr_t destPaddrPD, vaddr_t srcVaddrPD); +int pagingClearUserContext(vaddr_t vaddr_PD); diff --git a/core/main.c b/core/main.c index 4a5c249..cf0a74f 100644 --- a/core/main.c +++ b/core/main.c @@ -11,6 +11,7 @@ #include "klibc.h" #include "kthread.h" #include "mem.h" +#include "mmuContext.h" #include "multiboot.h" #include "paging.h" #include "pit.h" @@ -163,6 +164,7 @@ void kmain(unsigned long magic, unsigned long addr) printf("[Setup] allocation system\n"); areaInit(firstUsedByMem, lastUsedByMem, _stack_bottom, _stack_top); + mmuContextSetup(); cpu_context_subsystem_setup(); printf("[Setup] thread system\n"); diff --git a/core/mmuContext.h b/core/mmuContext.h index ca5feea..8bb73a0 100644 --- a/core/mmuContext.h +++ b/core/mmuContext.h @@ -6,3 +6,7 @@ struct mmu_context; int mmuContextSetup(); struct mmu_context *mmuContextCreate(); int mmuContextSyncKernelPDE(int pdEntry, void *pde, size_t pdeSize); +int mmuContextSwitch(struct mmu_context *ctx); +struct mmu_context *mmuContextGetCurrent(); +int mmuContextRef(struct mmu_context *ctx); +int mmuContextUnref(struct mmu_context *ctx); diff --git a/tests/test.c b/tests/test.c index aa9cb60..68e8d43 100644 --- a/tests/test.c +++ b/tests/test.c @@ -7,6 +7,7 @@ #include "kthread.h" #include "list.h" #include "mem.h" +#include "mmuContext.h" #include "paging.h" #include "serial.h" #include "stack.h" @@ -363,11 +364,23 @@ void testATAThread(){ } } -void testATA(){ +static void testATA(){ kthreadCreate("ATA_TEST", testATAThread, NULL); //testATAThread(); } +static void testMMUContext() +{ + printf("Testing mmu\n"); + struct mmu_context *current = mmuContextGetCurrent(); + assert(current != NULL); + struct mmu_context *new = mmuContextCreate(); + assert(new != NULL); + mmuContextSwitch(new); + mmuContextSwitch(current); + mmuContextUnref(new); +} + void run_test(void) { testATA(); @@ -402,4 +415,5 @@ void run_test(void) test_backtrace(); testCoroutine(); testKthread(); + testMMUContext(); } -- 2.47.0 From 2c4ade0fcac5b4d38d1dc038569aba9c989d8179 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Sat, 30 Oct 2021 00:37:26 +0200 Subject: [PATCH 22/40] test show free mem before/after --- tests/test.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/test.c b/tests/test.c index 68e8d43..7d36840 100644 --- a/tests/test.c +++ b/tests/test.c @@ -145,7 +145,7 @@ void testAlloc(void) free(alloc16); } -static void testPaging(void) +void testPaging(void) { printf("Testing paging\n"); struct phyMemDesc *allocated_page_list; @@ -383,6 +383,10 @@ static void testMMUContext() void run_test(void) { + + uint freemem, usedmem; + uint afterFreemem, afterUsedmem; + memGetStat(&freemem, &usedmem); testATA(); testMemcpyPerf(); { @@ -416,4 +420,6 @@ void run_test(void) testCoroutine(); testKthread(); testMMUContext(); + memGetStat(&afterFreemem, &afterUsedmem); + printf("free %d -> %d\n", freemem, afterFreemem); } -- 2.47.0 From e6524c7d483bdfffaf8feff7467436ea01664ba2 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Sat, 30 Oct 2021 13:58:12 +0200 Subject: [PATCH 23/40] Naming fix --- arch/x86/exception_wrappers.S | 10 +++++++--- arch/x86/irq_wrappers.S | 4 ++-- arch/x86/syscall_wrappers.S | 4 ++-- core/kthread.c | 8 +++++--- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/arch/x86/exception_wrappers.S b/arch/x86/exception_wrappers.S index 122bcd0..52f6a09 100644 --- a/arch/x86/exception_wrappers.S +++ b/arch/x86/exception_wrappers.S @@ -12,7 +12,7 @@ /* The address of the function to call to set back the user thread's MMU configuration upon return to user context */ -.extern thread_prepare_exception_switch_back +.extern threadPrepareExceptionSwitchBack .altmacro @@ -60,7 +60,7 @@ /* Reconfigure the MMU if needed */ pushl %esp /* cpu_ctxt */ - call thread_prepare_exception_switch_back + call threadPrepareExceptionSwitchBack addl $4, %esp /* Unallocate the stack */ /* Prepare kernel TSS in case we are switching to a @@ -99,6 +99,7 @@ /* uint32_t flags */ /* uint32_t cs; */ /* uint32_t ip */ + /* uint32_t errcode */ /* Pushes the other reg to save same and look like a struct cpu_state*/ /* Backup the actual context */ @@ -132,7 +133,7 @@ /* Reconfigure the MMU if needed */ pushl %esp /* cpu_ctxt */ - call thread_prepare_exception_switch_back + call threadPrepareExceptionSwitchBack addl $4, %esp /* Unallocate the stack */ /* Prepare kernel TSS in case we are switching to a @@ -158,6 +159,9 @@ popl %eax popl %ebp + /* Error code isn't compatible with iretd */ + addl $4, %esp + iret .endm diff --git a/arch/x86/irq_wrappers.S b/arch/x86/irq_wrappers.S index cb5b0e4..b989a96 100644 --- a/arch/x86/irq_wrappers.S +++ b/arch/x86/irq_wrappers.S @@ -11,7 +11,7 @@ /* The address of the function to call to set back the user thread's MMU configuration upon return to user context */ -.extern thread_prepare_irq_switch_back +.extern threadPrepareIrqSwitchBack .altmacro @@ -59,7 +59,7 @@ /* Reconfigure the MMU if needed */ pushl %esp /* cpu_ctxt */ - call thread_prepare_irq_switch_back + call threadPrepareIrqSwitchBack addl $4, %esp /* Unallocate the stack */ /* Prepare kernel TSS in case we are switching to a diff --git a/arch/x86/syscall_wrappers.S b/arch/x86/syscall_wrappers.S index 7d8f568..06d2a9f 100644 --- a/arch/x86/syscall_wrappers.S +++ b/arch/x86/syscall_wrappers.S @@ -14,7 +14,7 @@ /* The address of the function to call to set back the user thread's MMU configuration upon return to user context */ -.extern thread_prepare_syscall_switch_back +.extern threadPrepareSyscallSwitchBack .p2align 2, 0x90 .globl syscallHandler @@ -61,7 +61,7 @@ syscallHandler: /* Set the MMU configuration to that of the user thread's process */ pushl %esp /* user_ctxt */ - call thread_prepare_syscall_switch_back + call threadPrepareSyscallSwitchBack addl $4, %esp /* Unallocate the stack */ /* Prepare kernel TSS because we are switching back to a user diff --git a/core/kthread.c b/core/kthread.c index 9076793..7ef7e13 100644 --- a/core/kthread.c +++ b/core/kthread.c @@ -260,16 +260,18 @@ int kthreadAddThread(struct kthread *th) return 0; } -void thread_prepare_syscall_switch_back(struct cpu_state *cpu_state){ + +void threadPrepareSyscallSwitchBack(struct cpu_state *cpu_state){ (void)cpu_state; return; } -void thread_prepare_exception_switch_back(struct cpu_state *cpu_state){ +void threadPrepareExceptionSwitchBack(struct cpu_state *cpu_state){ (void)cpu_state; return; } -void thread_prepare_irq_switch_back(struct cpu_state *cpu_state){ + +void threadPrepareIrqSwitchBack(struct cpu_state *cpu_state){ (void)cpu_state; return; } -- 2.47.0 From ca4b318df63e024192ff242f69eae99b7a7fd8dd Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Sat, 30 Oct 2021 14:08:12 +0200 Subject: [PATCH 24/40] rename struct kthread in thread --- arch/x86/exception.c | 2 +- core/kthread.c | 38 +++++++++++++++++++------------------- core/kthread.h | 24 ++++++++++++------------ core/synchro.c | 2 +- core/wait.c | 4 ++-- core/wait.h | 4 ++-- 6 files changed, 37 insertions(+), 37 deletions(-) diff --git a/arch/x86/exception.c b/arch/x86/exception.c index 4aac3df..6a39f00 100644 --- a/arch/x86/exception.c +++ b/arch/x86/exception.c @@ -52,7 +52,7 @@ void print_handler(struct cpu_state *frame, ulong intr) void pagefault_handler(struct cpu_state *frame, ulong intr) { - struct kthread *current = getCurrentThread(); + struct thread *current = getCurrentThread(); printf("page fault while in thread %s code at 0x%x when trying to access 0x%x err_code 0x%x\n", current->name, cpu_context_get_PC(frame), cpu_context_get_EX_faulting_vaddr(frame), cpu_context_get_EX_err(frame)); VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "PAGE FAULT %d", intr); diff --git a/core/kthread.c b/core/kthread.c index 7ef7e13..1235103 100644 --- a/core/kthread.c +++ b/core/kthread.c @@ -7,8 +7,8 @@ #include "time.h" #include "vga.h" -static struct kthread *currentThread; -static struct kthread *threadWithTimeout; +static struct thread *currentThread; +static struct thread *threadWithTimeout; void kthreadExit() { @@ -16,8 +16,8 @@ void kthreadExit() disable_IRQs(flags); - struct kthread *current = currentThread; - struct kthread *next = kthreadSelectNext(); + struct thread *current = currentThread; + struct thread *next = kthreadSelectNext(); if (next == current) assert("cannot exit thread"); @@ -35,7 +35,7 @@ void kthreadExit() int kthreadSetup(vaddr_t mainStack, size_t mainStackSize) { - struct kthread *current = (struct kthread *)malloc(sizeof(struct kthread)); + struct thread *current = (struct thread *)malloc(sizeof(struct thread)); strzcpy(current->name, "[KINIT]", KTHREAD_NAME_MAX_LENGTH); current->stackAddr = mainStack; current->stackSize = mainStackSize; @@ -48,9 +48,9 @@ int kthreadSetup(vaddr_t mainStack, size_t mainStackSize) return 0; } -struct kthread *kthreadCreate(const char *name, cpu_kstate_function_arg1_t func, void *args) +struct thread *kthreadCreate(const char *name, cpu_kstate_function_arg1_t func, void *args) { - struct kthread *thread = (struct kthread *)malloc(sizeof(struct kthread)); + struct thread *thread = (struct thread *)malloc(sizeof(struct thread)); if (!thread) return NULL; @@ -87,7 +87,7 @@ free_mem: return NULL; } -void kthreadDelete(struct kthread *thread) +void kthreadDelete(struct thread *thread) { uint32_t flags; disable_IRQs(flags); @@ -101,9 +101,9 @@ void kthreadDelete(struct kthread *thread) restore_IRQs(flags); } -struct kthread *kthreadSelectNext() +struct thread *kthreadSelectNext() { - struct kthread *nextThread; + struct thread *nextThread; int idx; list_foreach(currentThread->next, nextThread, idx) { @@ -117,7 +117,7 @@ struct kthread *kthreadSelectNext() struct cpu_state *kthreadSwitch(struct cpu_state *prevCpu) { uint32_t flags; - struct kthread *nextThread; + struct thread *nextThread; disable_IRQs(flags); @@ -134,7 +134,7 @@ struct cpu_state *kthreadSwitch(struct cpu_state *prevCpu) int kthreadOnJieffiesTick() { - struct kthread *nextThread; + struct thread *nextThread; int idx; uint32_t flags; disable_IRQs(flags); @@ -162,7 +162,7 @@ int kthreadOnJieffiesTick() return 0; } -int kthreadUnsched(struct kthread *th) +int kthreadUnsched(struct thread *th) { list_delete(currentThread, th); @@ -170,7 +170,7 @@ int kthreadUnsched(struct kthread *th) } // Must be called with IRQ disabled -int kthreadWait(struct kthread *current, struct kthread *next, unsigned long msec) +int kthreadWait(struct thread *current, struct thread *next, unsigned long msec) { if (current == next) { assertmsg(0, "Cannot yield from %s to %s\n", current->name, next->name); @@ -197,8 +197,8 @@ int kthreadYield() uint32_t flags; disable_IRQs(flags); - struct kthread *next = kthreadSelectNext(); - struct kthread *current = currentThread; + struct thread *next = kthreadSelectNext(); + struct thread *current = currentThread; if (current == next) { restore_IRQs(flags); @@ -222,7 +222,7 @@ int kthreadYield() int kthreadMsleep(unsigned long msec) { uint32_t flags; - struct kthread *next, *current; + struct thread *next, *current; disable_IRQs(flags); @@ -245,12 +245,12 @@ int kthreadMsleep(unsigned long msec) return current->sleepHaveTimeouted == 1; } -struct kthread *getCurrentThread() +struct thread *getCurrentThread() { return currentThread; } -int kthreadAddThread(struct kthread *th) +int kthreadAddThread(struct thread *th) { if (th->state == READY) return 0; diff --git a/core/kthread.h b/core/kthread.h index dc50b45..ded9b07 100644 --- a/core/kthread.h +++ b/core/kthread.h @@ -15,7 +15,7 @@ typedef enum { EXITING } kthread_state; -struct kthread { +struct thread { char name[KTHREAD_NAME_MAX_LENGTH]; struct cpu_state *cpuState; kthread_state state; @@ -23,25 +23,25 @@ struct kthread { size_t stackSize; unsigned long jiffiesSleeping; int sleepHaveTimeouted; - struct kthread *next; - struct kthread *prev; - struct kthread *timeNext; - struct kthread *timePrev; + struct thread *next; + struct thread *prev; + struct thread*timeNext; + struct thread *timePrev; }; int kthreadSetup(vaddr_t mainStack, size_t mainStackSize); void kthreadExit(); -struct kthread *kthreadCreate(const char *name, cpu_kstate_function_arg1_t func, void *args); -void kthreadDelete(struct kthread *thread); +struct thread *kthreadCreate(const char *name, cpu_kstate_function_arg1_t func, void *args); +void kthreadDelete(struct thread *thread); -struct kthread *kthreadSelectNext(); +struct thread *kthreadSelectNext(); struct cpu_state *kthreadSwitch(struct cpu_state *prevCpu); int kthreadYield(); -int kthreadWait(struct kthread *current, struct kthread *next, unsigned long msec); -int kthreadUnsched(struct kthread *th); +int kthreadWait(struct thread *current, struct thread *next, unsigned long msec); +int kthreadUnsched(struct thread *th); int kthreadMsleep(unsigned long msec); int kthreadOnJieffiesTick(); -struct kthread *getCurrentThread(); -int kthreadAddThread(struct kthread *th); +struct thread *getCurrentThread(); +int kthreadAddThread(struct thread *th); diff --git a/core/synchro.c b/core/synchro.c index d485f32..ce2f5cd 100644 --- a/core/synchro.c +++ b/core/synchro.c @@ -51,7 +51,7 @@ int mutexFree(struct mutex *m) int mutexLock(struct mutex *m) { uint32_t flags; - struct kthread *current; + struct thread *current; disable_IRQs(flags); current = getCurrentThread(); diff --git a/core/wait.c b/core/wait.c index 3a44ed1..73aa705 100644 --- a/core/wait.c +++ b/core/wait.c @@ -25,7 +25,7 @@ int waitQueueFree(struct wait_queue *wq) int wakeUp(struct wait_queue *wq) { - struct kthread *th; + struct thread *th; uint32_t flags; disable_IRQs(flags); @@ -46,7 +46,7 @@ int wait(struct wait_queue *wq) int waitTimeout(struct wait_queue *wq, unsigned long msec) { - struct kthread *current, *next; + struct thread *current, *next; uint32_t flags; int ret; diff --git a/core/wait.h b/core/wait.h index bc2b4a8..1d2f90e 100644 --- a/core/wait.h +++ b/core/wait.h @@ -3,7 +3,7 @@ #include "kthread.h" struct wait_queue { - struct kthread *thread; + struct thread *thread; struct wait_queue *next; struct wait_queue *prev; }; @@ -35,6 +35,6 @@ struct semaphore { }; struct mutex { - struct kthread *owner; + struct thread *owner; struct wait_queue *wait; }; -- 2.47.0 From e65a57d55d0b83dd002ba6e337ac94d2a45d19a4 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Sat, 30 Oct 2021 14:18:21 +0200 Subject: [PATCH 25/40] Rename kthread to thread --- arch/x86/exception.c | 2 +- core/kthread.h | 47 --------------------------------- core/main.c | 10 ++++---- core/{kthread.c => thread.c} | 50 ++++++++++++++++++------------------ core/thread.h | 47 +++++++++++++++++++++++++++++++++ core/wait.c | 10 ++++---- core/wait.h | 2 +- custom_gdb_extension.py | 46 +++++++++++++++++---------------- drivers/ata.c | 2 +- drivers/pit.c | 6 ++--- tests/test.c | 34 ++++++++++++------------ 11 files changed, 129 insertions(+), 127 deletions(-) delete mode 100644 core/kthread.h rename core/{kthread.c => thread.c} (82%) create mode 100644 core/thread.h diff --git a/arch/x86/exception.c b/arch/x86/exception.c index 6a39f00..57de266 100644 --- a/arch/x86/exception.c +++ b/arch/x86/exception.c @@ -4,7 +4,7 @@ #include "interrupt.h" #include "irq.h" #include "klibc.h" -#include "kthread.h" +#include "thread.h" #include "vga.h" exception_handler exception_handler_array[EXCEPTION_NUM] = { diff --git a/core/kthread.h b/core/kthread.h deleted file mode 100644 index ded9b07..0000000 --- a/core/kthread.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include "cpu_context.h" -#include "mem.h" - -#define KTHREAD_NAME_MAX_LENGTH 32 -#define KTHREAD_DEFAULT_STACK_SIZE PAGE_SIZE - - -typedef enum { - RUNNING, - READY, - SLEEPING, - WAITING, - EXITING -} kthread_state; - -struct thread { - char name[KTHREAD_NAME_MAX_LENGTH]; - struct cpu_state *cpuState; - kthread_state state; - vaddr_t stackAddr; - size_t stackSize; - unsigned long jiffiesSleeping; - int sleepHaveTimeouted; - struct thread *next; - struct thread *prev; - struct thread*timeNext; - struct thread *timePrev; -}; - -int kthreadSetup(vaddr_t mainStack, size_t mainStackSize); -void kthreadExit(); - -struct thread *kthreadCreate(const char *name, cpu_kstate_function_arg1_t func, void *args); -void kthreadDelete(struct thread *thread); - -struct thread *kthreadSelectNext(); -struct cpu_state *kthreadSwitch(struct cpu_state *prevCpu); - -int kthreadYield(); -int kthreadWait(struct thread *current, struct thread *next, unsigned long msec); -int kthreadUnsched(struct thread *th); -int kthreadMsleep(unsigned long msec); -int kthreadOnJieffiesTick(); -struct thread *getCurrentThread(); -int kthreadAddThread(struct thread *th); diff --git a/core/main.c b/core/main.c index cf0a74f..e3d074e 100644 --- a/core/main.c +++ b/core/main.c @@ -9,7 +9,7 @@ #include "irq.h" #include "keyboard.h" #include "klibc.h" -#include "kthread.h" +#include "thread.h" #include "mem.h" #include "mmuContext.h" #include "multiboot.h" @@ -32,7 +32,7 @@ void idleThread(void *arg) (void)arg; while (1) { VGAPrintf(GREEN, BLACK, 0, VGA_HEIGHT - 1, "%d", (jiffies / HZ)); - kthreadYield(); + threadYield(); } } @@ -168,8 +168,8 @@ void kmain(unsigned long magic, unsigned long addr) cpu_context_subsystem_setup(); printf("[Setup] thread system\n"); - kthreadSetup(_stack_bottom, (_stack_top - _stack_bottom + 1)); - kthreadCreate("idle ", idleThread, NULL); + threadSetup(_stack_bottom, (_stack_top - _stack_bottom + 1)); + threadCreate("idle ", idleThread, NULL); irqSetRoutine(IRQ_TIMER, pit_handler); @@ -187,5 +187,5 @@ void kmain(unsigned long magic, unsigned long addr) // There is no real caller behind this point // So finish this by ourself - kthreadExit(); + threadExit(); } diff --git a/core/kthread.c b/core/thread.c similarity index 82% rename from core/kthread.c rename to core/thread.c index 1235103..2ac49ad 100644 --- a/core/kthread.c +++ b/core/thread.c @@ -1,4 +1,4 @@ -#include "kthread.h" +#include "thread.h" #include "alloc.h" #include "assert.h" #include "irq.h" @@ -10,14 +10,14 @@ static struct thread *currentThread; static struct thread *threadWithTimeout; -void kthreadExit() +void threadExit() { uint32_t flags; disable_IRQs(flags); struct thread *current = currentThread; - struct thread *next = kthreadSelectNext(); + struct thread *next = threadSelectNext(); if (next == current) assert("cannot exit thread"); @@ -25,7 +25,7 @@ void kthreadExit() currentThread->state = EXITING; currentThread = next; currentThread->state = RUNNING; - cpu_context_exit_to(next->cpuState, (cpu_kstate_function_arg1_t *)kthreadDelete, + cpu_context_exit_to(next->cpuState, (cpu_kstate_function_arg1_t *)threadDelete, (uint32_t)current); restore_IRQs(flags); @@ -33,10 +33,10 @@ void kthreadExit() return; } -int kthreadSetup(vaddr_t mainStack, size_t mainStackSize) +int threadSetup(vaddr_t mainStack, size_t mainStackSize) { struct thread *current = (struct thread *)malloc(sizeof(struct thread)); - strzcpy(current->name, "[KINIT]", KTHREAD_NAME_MAX_LENGTH); + strzcpy(current->name, "[KINIT]", THREAD_NAME_MAX_LENGTH); current->stackAddr = mainStack; current->stackSize = mainStackSize; @@ -48,31 +48,31 @@ int kthreadSetup(vaddr_t mainStack, size_t mainStackSize) return 0; } -struct thread *kthreadCreate(const char *name, cpu_kstate_function_arg1_t func, void *args) +struct thread *threadCreate(const char *name, cpu_kstate_function_arg1_t func, void *args) { struct thread *thread = (struct thread *)malloc(sizeof(struct thread)); if (!thread) return NULL; - thread->stackAddr = (vaddr_t)malloc(KTHREAD_DEFAULT_STACK_SIZE); + thread->stackAddr = (vaddr_t)malloc(THREAD_DEFAULT_STACK_SIZE); if(!thread->stackAddr) return NULL; #ifdef DEBUG printf("Alloc stack at 0x%x struct at 0x%x\n", thread->stackAddr, thread); #endif - thread->stackSize = KTHREAD_DEFAULT_STACK_SIZE; + thread->stackSize = THREAD_DEFAULT_STACK_SIZE; if (!thread->stackAddr) goto free_mem; if (name) - strzcpy(thread->name, name, KTHREAD_NAME_MAX_LENGTH); + strzcpy(thread->name, name, THREAD_NAME_MAX_LENGTH); else - strzcpy(thread->name, "[UNKNOW]", KTHREAD_NAME_MAX_LENGTH); + strzcpy(thread->name, "[UNKNOW]", THREAD_NAME_MAX_LENGTH); if (cpu_kstate_init(&thread->cpuState, (cpu_kstate_function_arg1_t *)func, (vaddr_t)args, thread->stackAddr, thread->stackSize, - (cpu_kstate_function_arg1_t *)kthreadExit, 0)) + (cpu_kstate_function_arg1_t *)threadExit, 0)) goto free_mem; thread->state = READY; @@ -87,7 +87,7 @@ free_mem: return NULL; } -void kthreadDelete(struct thread *thread) +void threadDelete(struct thread *thread) { uint32_t flags; disable_IRQs(flags); @@ -101,7 +101,7 @@ void kthreadDelete(struct thread *thread) restore_IRQs(flags); } -struct thread *kthreadSelectNext() +struct thread *threadSelectNext() { struct thread *nextThread; int idx; @@ -114,14 +114,14 @@ struct thread *kthreadSelectNext() return currentThread; } -struct cpu_state *kthreadSwitch(struct cpu_state *prevCpu) +struct cpu_state *threadSwitch(struct cpu_state *prevCpu) { uint32_t flags; struct thread *nextThread; disable_IRQs(flags); - nextThread = kthreadSelectNext(); + nextThread = threadSelectNext(); currentThread->cpuState = prevCpu; currentThread->state = READY; currentThread = nextThread; @@ -132,7 +132,7 @@ struct cpu_state *kthreadSwitch(struct cpu_state *prevCpu) return nextThread->cpuState; } -int kthreadOnJieffiesTick() +int threadOnJieffiesTick() { struct thread *nextThread; int idx; @@ -154,7 +154,7 @@ int kthreadOnJieffiesTick() if (!nextThread->jiffiesSleeping) { nextThread->sleepHaveTimeouted = 1; list_delete_named(threadWithTimeout, nextThread, timePrev, timeNext); - kthreadAddThread(nextThread); + threadAddThread(nextThread); } } } @@ -162,7 +162,7 @@ int kthreadOnJieffiesTick() return 0; } -int kthreadUnsched(struct thread *th) +int threadUnsched(struct thread *th) { list_delete(currentThread, th); @@ -170,7 +170,7 @@ int kthreadUnsched(struct thread *th) } // Must be called with IRQ disabled -int kthreadWait(struct thread *current, struct thread *next, unsigned long msec) +int threadWait(struct thread *current, struct thread *next, unsigned long msec) { if (current == next) { assertmsg(0, "Cannot yield from %s to %s\n", current->name, next->name); @@ -192,12 +192,12 @@ int kthreadWait(struct thread *current, struct thread *next, unsigned long msec) return current->sleepHaveTimeouted; } -int kthreadYield() +int threadYield() { uint32_t flags; disable_IRQs(flags); - struct thread *next = kthreadSelectNext(); + struct thread *next = threadSelectNext(); struct thread *current = currentThread; if (current == next) { @@ -219,7 +219,7 @@ int kthreadYield() return 0; } -int kthreadMsleep(unsigned long msec) +int threadMsleep(unsigned long msec) { uint32_t flags; struct thread *next, *current; @@ -233,7 +233,7 @@ int kthreadMsleep(unsigned long msec) current->state = SLEEPING; current->sleepHaveTimeouted = 0; current->jiffiesSleeping = msecs_to_jiffies(msec); - next = kthreadSelectNext(); + next = threadSelectNext(); assert(next != current); assert(next->state == READY); @@ -250,7 +250,7 @@ struct thread *getCurrentThread() return currentThread; } -int kthreadAddThread(struct thread *th) +int threadAddThread(struct thread *th) { if (th->state == READY) return 0; diff --git a/core/thread.h b/core/thread.h new file mode 100644 index 0000000..2bbb065 --- /dev/null +++ b/core/thread.h @@ -0,0 +1,47 @@ +#pragma once + +#include "cpu_context.h" +#include "mem.h" + +#define THREAD_NAME_MAX_LENGTH 32 +#define THREAD_DEFAULT_STACK_SIZE PAGE_SIZE + + +typedef enum { + RUNNING, + READY, + SLEEPING, + WAITING, + EXITING +} thread_state; + +struct thread { + char name[THREAD_NAME_MAX_LENGTH]; + struct cpu_state *cpuState; + thread_state state; + vaddr_t stackAddr; + size_t stackSize; + unsigned long jiffiesSleeping; + int sleepHaveTimeouted; + struct thread *next; + struct thread *prev; + struct thread*timeNext; + struct thread *timePrev; +}; + +int threadSetup(vaddr_t mainStack, size_t mainStackSize); +void threadExit(); + +struct thread *threadCreate(const char *name, cpu_kstate_function_arg1_t func, void *args); +void threadDelete(struct thread *thread); + +struct thread *threadSelectNext(); +struct cpu_state *threadSwitch(struct cpu_state *prevCpu); + +int threadYield(); +int threadWait(struct thread *current, struct thread *next, unsigned long msec); +int threadUnsched(struct thread *th); +int threadMsleep(unsigned long msec); +int threadOnJieffiesTick(); +struct thread *getCurrentThread(); +int threadAddThread(struct thread *th); diff --git a/core/wait.c b/core/wait.c index 73aa705..c6281d1 100644 --- a/core/wait.c +++ b/core/wait.c @@ -1,5 +1,5 @@ #include "irq.h" -#include "kthread.h" +#include "thread.h" #include "list.h" #include "wait.h" @@ -31,7 +31,7 @@ int wakeUp(struct wait_queue *wq) disable_IRQs(flags); list_collapse(wq->thread, th) { - kthreadAddThread(th); + threadAddThread(th); } restore_IRQs(flags); @@ -54,11 +54,11 @@ int waitTimeout(struct wait_queue *wq, unsigned long msec) current = getCurrentThread(); current->state = WAITING; - next = kthreadSelectNext(); - kthreadUnsched(current); + next = threadSelectNext(); + threadUnsched(current); list_add_tail(wq->thread, current); - ret = kthreadWait(current, next, msec); + ret = threadWait(current, next, msec); restore_IRQs(flags); return ret; diff --git a/core/wait.h b/core/wait.h index 1d2f90e..f0d0212 100644 --- a/core/wait.h +++ b/core/wait.h @@ -1,6 +1,6 @@ #pragma once -#include "kthread.h" +#include "thread.h" struct wait_queue { struct thread *thread; diff --git a/custom_gdb_extension.py b/custom_gdb_extension.py index 5ce128e..0479f02 100644 --- a/custom_gdb_extension.py +++ b/custom_gdb_extension.py @@ -39,32 +39,32 @@ class CustomPrettyPrinterLocator(PrettyPrinter): if typename is None: typename = val.type.name - if typename == "kthread": + if typename == "thread": return KthreadPrettyPrinter(val) -class KthreadListDumpCmd(gdb.Command): - """Prints the kthread list""" +class threadListDumpCmd(gdb.Command): + """Prints the thread list""" def __init__(self): - super(KthreadListDumpCmd, self).__init__( - "kthread_list_dump", gdb.COMMAND_USER + super(threadListDumpCmd, self).__init__( + "thread_list_dump", gdb.COMMAND_USER ) - def _kthread_list_to_str(self, val): + def _thread_list_to_str(self, val): """Walk through the Kthread list. We will simply follow the 'next' pointers until we encounter the HEAD again """ idx = 0 head = val - kthread_ptr = val + thread_ptr = val result = "" - while kthread_ptr != 0 and (idx == 0 or kthread_ptr != head): - result += "\n%d: %s" % (idx, KthreadPrettyPrinter(kthread_ptr).to_string()) - kthread_ptr = kthread_ptr["next"] + while thread_ptr != 0 and (idx == 0 or thread_ptr != head): + result += "\n%d: %s" % (idx, KthreadPrettyPrinter(thread_ptr).to_string()) + thread_ptr = thread_ptr["next"] idx += 1 - result = ("Found a Linked List with %d kthread:" % idx) + result + result = ("Found a Linked List with %d thread:" % idx) + result return result def complete(self, text, word): @@ -77,14 +77,14 @@ class KthreadListDumpCmd(gdb.Command): # to do argument parsing print("Args Passed: %s" % args) if args: - kthread_ptr_val = gdb.parse_and_eval(args) + thread_ptr_val = gdb.parse_and_eval(args) else: - kthread_ptr_val = gdb.parse_and_eval("currentThread") - if str(kthread_ptr_val.type) != "struct kthread *": - print("Expected pointer argument of type (struct kthread *)") + thread_ptr_val = gdb.parse_and_eval("currentThread") + if str(thread_ptr_val.type) != "struct thread *": + print("Expected pointer argument of type (struct thread *)") return - print(self._kthread_list_to_str(kthread_ptr_val)) + print(self._thread_list_to_str(thread_ptr_val)) class PhyMemDescListDumpCmd(gdb.Command): @@ -175,6 +175,7 @@ class PrintStructC99Cmd(gdb.Command): rr_rval = rr_s[1].strip() print(' ' * hs + '.' + rr_s[0] + '= ' + rr_rval) + class ListDumpCmd(gdb.Command): """Prints a linked list""" @@ -190,13 +191,13 @@ class ListDumpCmd(gdb.Command): """ idx = 0 head = val - kthread_ptr = val + thread_ptr = val result = "" - while kthread_ptr != 0 and (idx == 0 or kthread_ptr != head): - result += gdb.execute('p *({}){}'.format(str(kthread_ptr.type),kthread_ptr), to_string=True) - kthread_ptr = kthread_ptr["next"] + while thread_ptr != 0 and (idx == 0 or thread_ptr != head): + result += gdb.execute('p *({}){}'.format(str(thread_ptr.type),thread_ptr), to_string=True) + thread_ptr = thread_ptr["next"] idx += 1 - result = ("Found a Linked List with %d items:" % idx) + "\n"+ result + result = ("Found a Linked List with %d items:" % idx) + "\n" + result return result def complete(self, text, word): @@ -220,8 +221,9 @@ class ListDumpCmd(gdb.Command): print(self._print_list(ptr_val)) + register_pretty_printer(None, CustomPrettyPrinterLocator(), replace=True) -KthreadListDumpCmd() +threadListDumpCmd() PhyMemDescListDumpCmd() PrintStructC99Cmd() ListDumpCmd() diff --git a/drivers/ata.c b/drivers/ata.c index ca9ad20..eaa5eec 100644 --- a/drivers/ata.c +++ b/drivers/ata.c @@ -2,7 +2,7 @@ #include "io.h" #include "kernel.h" #include "klibc.h" -#include "kthread.h" +#include "thread.h" // from // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ata/ns-ata-_identify_device_data diff --git a/drivers/pit.c b/drivers/pit.c index ba95765..31aa199 100644 --- a/drivers/pit.c +++ b/drivers/pit.c @@ -2,7 +2,7 @@ #include "io.h" #include "irq.h" #include "klibc.h" -#include "kthread.h" +#include "thread.h" #include "time.h" int pitSetup(unsigned int freq) @@ -20,8 +20,8 @@ int pitSetup(unsigned int freq) struct cpu_state *pitIrqHandler(struct cpu_state *prevCpu) { __atomic_add_fetch(&jiffies, 1, __ATOMIC_RELAXED); - kthreadOnJieffiesTick(); + threadOnJieffiesTick(); // Uncomment for non-preemptible kernel // return prevCpu; - return kthreadSwitch(prevCpu); + return threadSwitch(prevCpu); } diff --git a/tests/test.c b/tests/test.c index 7d36840..368d30b 100644 --- a/tests/test.c +++ b/tests/test.c @@ -4,7 +4,7 @@ #include "assert.h" #include "cpu_context.h" #include "klibc.h" -#include "kthread.h" +#include "thread.h" #include "list.h" #include "mem.h" #include "mmuContext.h" @@ -274,7 +274,7 @@ static void kthread1(void *strIn) char *str = (char *)strIn; for (; *str != '\n'; str++) { printf("kth1: %c\n", *str); - kthreadYield(); + threadYield(); } } @@ -283,7 +283,7 @@ static void kthread2(void *strIn) char *str = (char *)strIn; for (; *str != '\n'; str++) { printf("kth2: %c\n", *str); - kthreadYield(); + threadYield(); } } @@ -296,11 +296,11 @@ void sleepThread(void *arg) while (secSleep < 5) { // printf("Sleeping loop %d\n", secSleep); secSleep++; - kthreadMsleep(1000); + threadMsleep(1000); } unsigned long ellapsedTime = jiffies_to_msecs(jiffies - initialJiffies); assertmsg(ellapsedTime >= 5000 && ellapsedTime < 5100, "ellapsedTime %d\n", ellapsedTime); - kthreadMsleep(0); + threadMsleep(0); printf("I should never be showed\n"); assert(1); } @@ -315,7 +315,7 @@ void mutThread(void *arg) while (test > 0) { mutexLock(&mutexTest); printf("%s sleep\n", (char *)arg); - kthreadMsleep(1000); + threadMsleep(1000); printf("%s up\n", (char *)arg); mutexUnlock(&mutexTest); test--; @@ -336,17 +336,17 @@ void testKthread() { mutexInit(&mutexTest); // It is not expected to have necessarily "Hello world\n" properly written - kthreadCreate("Test2", (cpu_kstate_function_arg1_t *)kthread2, (void *)"el ol\n"); - kthreadCreate("Test1", (cpu_kstate_function_arg1_t *)kthread1, (void *)"Hlowrd\n"); - kthreadMsleep(1000); - kthreadCreate("wq timeout", wqThread, NULL); - kthreadMsleep(2000); + threadCreate("Test2", (cpu_kstate_function_arg1_t *)kthread2, (void *)"el ol\n"); + threadCreate("Test1", (cpu_kstate_function_arg1_t *)kthread1, (void *)"Hlowrd\n"); + threadMsleep(1000); + threadCreate("wq timeout", wqThread, NULL); + threadMsleep(2000); assert(haveTimeout); - kthreadCreate("sleep", sleepThread, NULL); - kthreadMsleep(5000); - kthreadCreate("mtest1", mutThread, "mut1"); - kthreadCreate("mtest2", mutThread, "mut2"); - kthreadCreate("mtest3", mutThread, "mut3"); + threadCreate("sleep", sleepThread, NULL); + threadMsleep(5000); + threadCreate("mtest1", mutThread, "mut1"); + threadCreate("mtest2", mutThread, "mut2"); + threadCreate("mtest3", mutThread, "mut3"); } void testATAThread(){ @@ -365,7 +365,7 @@ void testATAThread(){ } static void testATA(){ - kthreadCreate("ATA_TEST", testATAThread, NULL); + threadCreate("ATA_TEST", testATAThread, NULL); //testATAThread(); } -- 2.47.0 From 5230b971b21804d410bba958c3980e465fad2911 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Sat, 30 Oct 2021 15:30:19 +0200 Subject: [PATCH 26/40] Add process subsystem --- arch/x86/mmuContext.c | 5 +- core/process.c | 163 ++++++++++++++++++++++++++++++++++++++++++ core/process.h | 15 ++++ core/thread.h | 13 ++-- 4 files changed, 191 insertions(+), 5 deletions(-) create mode 100644 core/process.c create mode 100644 core/process.h diff --git a/arch/x86/mmuContext.c b/arch/x86/mmuContext.c index 164bb71..9a8438f 100644 --- a/arch/x86/mmuContext.c +++ b/arch/x86/mmuContext.c @@ -1,10 +1,11 @@ -#include "mmuContext.h" #include "alloc.h" #include "allocArea.h" #include "errno.h" #include "irq.h" #include "klibc.h" #include "list.h" +#include "mem.h" +#include "mmuContext.h" #include "paging.h" #include "stdarg.h" #include "types.h" @@ -29,6 +30,8 @@ int mmuContextSetup() struct mmu_context *initialCtx; int ret = 0; + allocBookSlab(sizeof(struct mmu_context), PAGE_SIZE * 3, 0, 0); + initialCtx = malloc(sizeof(struct mmu_context)); if (initialCtx == NULL) diff --git a/core/process.c b/core/process.c new file mode 100644 index 0000000..182c33b --- /dev/null +++ b/core/process.c @@ -0,0 +1,163 @@ +#include "process.h" +#include "alloc.h" +#include "irq.h" +#include "klibc.h" +#include "list.h" +#include "mmuContext.h" + +struct process { + char name[PROCESS_NAME_MAX_LENGTH]; + int ref; + int pid; + struct mmu_context *context; + struct thread *thList; + + struct process *prev, *next; +}; + +static struct process *processList; +static int nextPid; + +int processSetup() +{ + list_init(processList); + allocBookSlab(sizeof(struct process), PAGE_SIZE * 3, 0, 0); + nextPid = 0; + + return 0; +} + +struct process *processCreate(char *name) +{ + uint32_t flags; + + struct process *new = (struct process *)malloc(sizeof(struct process)); + if (new == NULL) + return NULL; + + new->context = mmuContextCreate(); + if (new->context == NULL) { + free(new); + + return NULL; + } + + strzcpy(new->name, name, PROCESS_NAME_MAX_LENGTH); + new->ref = 1; + + disable_IRQs(flags); + new->pid = nextPid++; + list_add_tail(processList, new); + restore_IRQs(flags); + + return new; +} + +void processListPrint() +{ + struct process *proc; + int nbProcs; + struct thread *cur = getCurrentThread(); + + printf("PID NAME NBTHREAD REF\n"); + list_foreach(processList, proc, nbProcs) + { + struct thread *th; + int nbTh; + + printf("%d %s %d %d\n", proc->pid, proc->name, processCountThread(proc), proc->ref); + list_foreach_named(proc->thList, th, nbTh, prevInProcess, nextInProcess) + { + if (th == cur) { + printf(" th: 0x%x Current\n", th); + } else { + printf(" th: 0x%x in 0x%x\n", th, cpu_context_get_PC(th->cpuState)); + } + } + } +} + +int processCountThread(struct process *proc) +{ + int count; + struct thread *th; + + list_foreach_named(proc->thList, th, count, prevInProcess, nextInProcess) {} + + return count; +} + +int processRef(struct process *proc) +{ + uint32_t flags; + // ref == 0 -> delete + assert(proc->ref > 0); + + disable_IRQs(flags); + proc->ref++; + restore_IRQs(flags); + + return 0; +} + +int processUnref(struct process *proc) +{ + uint32_t flags; + + assert(proc->ref > 0); + + disable_IRQs(flags); + + proc->ref--; + if (proc->ref > 0) { + restore_IRQs(flags); + return -EBUSY; + } + list_delete(processList, proc); + restore_IRQs(flags); + + mmuContextUnref(proc->context); + free(proc); + + return 0; +} + +int processAddThread(struct process *proc, struct thread *th) +{ + uint32_t flags; + + assert(proc->ref > 0); + + th->process = proc; + + disable_IRQs(flags); + processRef(proc); + list_add_tail_named(proc->thList, th, prevInProcess, nextInProcess); + + restore_IRQs(flags); + + return 0; +} + +int processRemoveThread(struct thread *th) +{ + uint32_t flags; + struct process *proc; + + disable_IRQs(flags); + proc = th->process; + + list_delete_named(proc->thList, th, prevInProcess, nextInProcess); + restore_IRQs(flags); + processUnref(proc); + + return 0; +} + +int processSetName(struct process *proc, char *name) +{ + assert(name != NULL); + strzcpy(proc->name, name, PROCESS_NAME_MAX_LENGTH); + + return 0; +} diff --git a/core/process.h b/core/process.h new file mode 100644 index 0000000..4c6c9d2 --- /dev/null +++ b/core/process.h @@ -0,0 +1,15 @@ +#pragma once +#include "thread.h" + +#define PROCESS_NAME_MAX_LENGTH 32 + +struct process; + +int processSetup(); +struct process *processCreate(char *name); +int processCountThread(struct process *proc); +void processListPrint(); +int processRef(struct process *proc); +int processUnref(struct process *proc); +int processSetName(struct process *proc, char *name); +int processAddThread(struct process *proc, struct thread *th); diff --git a/core/thread.h b/core/thread.h index 2bbb065..a8d6cbd 100644 --- a/core/thread.h +++ b/core/thread.h @@ -1,7 +1,9 @@ #pragma once +struct thread; #include "cpu_context.h" #include "mem.h" +#include "process.h" #define THREAD_NAME_MAX_LENGTH 32 #define THREAD_DEFAULT_STACK_SIZE PAGE_SIZE @@ -21,12 +23,15 @@ struct thread { thread_state state; vaddr_t stackAddr; size_t stackSize; + unsigned long jiffiesSleeping; int sleepHaveTimeouted; - struct thread *next; - struct thread *prev; - struct thread*timeNext; - struct thread *timePrev; + + struct thread *next, *prev; + struct thread *timeNext, *timePrev; + // For User thread only + struct thread *nextInProcess, *prevInProcess; + struct process *process; }; int threadSetup(vaddr_t mainStack, size_t mainStackSize); -- 2.47.0 From ec65623da46beb2c04948d6e0ae7762146af343a Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Sat, 30 Oct 2021 15:34:13 +0200 Subject: [PATCH 27/40] Reduce kthead execution time --- tests/test.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/test.c b/tests/test.c index 368d30b..7bc66a3 100644 --- a/tests/test.c +++ b/tests/test.c @@ -296,10 +296,10 @@ void sleepThread(void *arg) while (secSleep < 5) { // printf("Sleeping loop %d\n", secSleep); secSleep++; - threadMsleep(1000); + threadMsleep(100); } unsigned long ellapsedTime = jiffies_to_msecs(jiffies - initialJiffies); - assertmsg(ellapsedTime >= 5000 && ellapsedTime < 5100, "ellapsedTime %d\n", ellapsedTime); + assertmsg(ellapsedTime >= 500 && ellapsedTime < 510, "ellapsedTime %d\n", ellapsedTime); threadMsleep(0); printf("I should never be showed\n"); assert(1); @@ -315,7 +315,7 @@ void mutThread(void *arg) while (test > 0) { mutexLock(&mutexTest); printf("%s sleep\n", (char *)arg); - threadMsleep(1000); + threadMsleep(100); printf("%s up\n", (char *)arg); mutexUnlock(&mutexTest); test--; @@ -327,7 +327,7 @@ void wqThread(void *arg) (void)arg; DECLARE_WAITQUEUE(test); waitQueueInit(&test); - assert(waitTimeout(&test, 1000) == 1); + assert(waitTimeout(&test, 100) == 1); waitQueueFree(&test); haveTimeout = 1; } @@ -338,12 +338,12 @@ void testKthread() // It is not expected to have necessarily "Hello world\n" properly written threadCreate("Test2", (cpu_kstate_function_arg1_t *)kthread2, (void *)"el ol\n"); threadCreate("Test1", (cpu_kstate_function_arg1_t *)kthread1, (void *)"Hlowrd\n"); - threadMsleep(1000); + threadMsleep(100); threadCreate("wq timeout", wqThread, NULL); - threadMsleep(2000); + threadMsleep(200); assert(haveTimeout); threadCreate("sleep", sleepThread, NULL); - threadMsleep(5000); + threadMsleep(500); threadCreate("mtest1", mutThread, "mut1"); threadCreate("mtest2", mutThread, "mut2"); threadCreate("mtest3", mutThread, "mut3"); -- 2.47.0 From 0040fb1cda318dab665d64f653e3f4056e36a800 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Sat, 30 Oct 2021 15:43:40 +0200 Subject: [PATCH 28/40] Add basic test for process --- core/main.c | 2 ++ core/process.h | 1 + tests/test.c | 19 +++++++++++++++++++ 3 files changed, 22 insertions(+) diff --git a/core/main.c b/core/main.c index e3d074e..f261810 100644 --- a/core/main.c +++ b/core/main.c @@ -15,6 +15,7 @@ #include "multiboot.h" #include "paging.h" #include "pit.h" +#include "process.h" #include "serial.h" #include "stack.h" #include "stdarg.h" @@ -170,6 +171,7 @@ void kmain(unsigned long magic, unsigned long addr) printf("[Setup] thread system\n"); threadSetup(_stack_bottom, (_stack_top - _stack_bottom + 1)); threadCreate("idle ", idleThread, NULL); + processSetup(); irqSetRoutine(IRQ_TIMER, pit_handler); diff --git a/core/process.h b/core/process.h index 4c6c9d2..61350bc 100644 --- a/core/process.h +++ b/core/process.h @@ -13,3 +13,4 @@ int processRef(struct process *proc); int processUnref(struct process *proc); int processSetName(struct process *proc, char *name); int processAddThread(struct process *proc, struct thread *th); +int processRemoveThread(struct thread *th); diff --git a/tests/test.c b/tests/test.c index 7bc66a3..4544a77 100644 --- a/tests/test.c +++ b/tests/test.c @@ -9,6 +9,7 @@ #include "mem.h" #include "mmuContext.h" #include "paging.h" +#include "process.h" #include "serial.h" #include "stack.h" #include "synchro.h" @@ -381,6 +382,23 @@ static void testMMUContext() mmuContextUnref(new); } + +static void testProcess(){ + struct process *proc= processCreate("TESTPROCESS"); + struct thread *th1 = threadCreate("th1", sleepThread, NULL); + struct thread *th2 = threadCreate("th2", sleepThread, NULL); + processAddThread(proc, th1); + processAddThread(proc, th2); + processListPrint(); + threadMsleep(600); + + processRemoveThread(th1); + processRemoveThread(th2); + processUnref(proc); + printf("Next process list should be empty\n"); + processListPrint(); +} + void run_test(void) { @@ -420,6 +438,7 @@ void run_test(void) testCoroutine(); testKthread(); testMMUContext(); + testProcess(); memGetStat(&afterFreemem, &afterUsedmem); printf("free %d -> %d\n", freemem, afterFreemem); } -- 2.47.0 From 814d38bc9750ea33842f1fbb6153da439d187288 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Sun, 31 Oct 2021 00:04:01 +0200 Subject: [PATCH 29/40] Makefile: all asm in Gnu AS --- Makefile | 16 +++++++++------- arch/x86/boot/{boot.s => boot.S} | 6 +++++- 2 files changed, 14 insertions(+), 8 deletions(-) rename arch/x86/boot/{boot.s => boot.S} (97%) diff --git a/Makefile b/Makefile index e02517b..4e37392 100644 --- a/Makefile +++ b/Makefile @@ -15,14 +15,16 @@ SUBDIRS := core drivers tests arch/$(ARCH) INCDIRS += $(foreach dir, $(SUBDIRS), -I$(dir)) CPPFLAGS += $(INCDIRS) -asmsrc=$(wildcard arch/$(ARCH)/boot/*.asm) +asmsrc= asmobj=$(asmsrc:%.asm=%.o) +gasmsrc=$(wildcard arch/$(ARCH)/*.S arch/$(ARCH)/boot/*.S) +gasmobj=$(gasmsrc:%.S=%.o) csrc=$(shell find $(SUBDIRS) -type f -name "*.c")# $(wildcard *.c) -cobj=$(csrc:%.c=%.o) arch/$(ARCH)/cpu_context_switch.o arch/$(ARCH)/irq_pit.o arch/$(ARCH)/irq_wrappers.o arch/$(ARCH)/exception_wrappers.o arch/$(ARCH)/syscall_wrappers.o -deps = $(csrc:%.c=%.d) +cobj=$(csrc:%.c=%.o) +deps=$(csrc:%.c=%.d) $(gasmsrc:%.S=%.d) -kernel kernel.sym &: $(asmobj) $(cobj) linker.ld - $(CC) -m32 -ffreestanding -nostdlib $(cobj) $(asmobj) -o kernel -T linker.ld -lgcc +kernel kernel.sym &: $(asmobj) $(gasmobj) $(cobj) linker.ld + $(CC) -m32 -ffreestanding -nostdlib $(cobj) $(gasmobj) $(asmobj) -o kernel -T linker.ld -lgcc objcopy --only-keep-debug kernel kernel.sym objcopy --strip-debug kernel @@ -39,7 +41,7 @@ disk.img: $(AS) $(ASFLAGS) -o $@ $< %.o: %.S - $(CC) $(INCDIRS) -c "$<" $(CFLAGS) -o "$@" + $(CC) $(CFLAGS) $(CPPFLAGS) -c "$<" -o "$@" test: CFLAGS += -DRUN_TEST @@ -61,7 +63,7 @@ debug_test: CFLAGS += $(DEBUG_FLAGS) -DRUN_TEST debug_test: debug clean: - $(RM) kernel $(asmobj) $(cobj) $(deps) fd.iso kernel.sym + $(RM) kernel $(asmobj) $(gasmobj) $(cobj) $(deps) fd.iso kernel.sym $(RM) -r isodir ifneq ($(MAKECMDGOALS),clean) diff --git a/arch/x86/boot/boot.s b/arch/x86/boot/boot.S similarity index 97% rename from arch/x86/boot/boot.s rename to arch/x86/boot/boot.S index 27f32f6..4a50200 100644 --- a/arch/x86/boot/boot.s +++ b/arch/x86/boot/boot.S @@ -31,7 +31,7 @@ stack is properly aligned and failure to align the stack will result in undefined behavior. */ .section .bss -.align 16 +.align 4096 stack_bottom: .skip 16384 # 16 KiB stack_top: @@ -117,3 +117,7 @@ Set the size of the _start symbol to the current location '.' minus its start. This is useful when debugging or when you implement call tracing. */ .size _start, . - _start +.global _stack_bottom +_stack_bottom: stack_bottom +.global _stack_stop +_stack_stop: stack_top -- 2.47.0 From 98db8b89628f1f0872979edfb6a2cf10c468530f Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Tue, 2 Nov 2021 21:24:12 +0100 Subject: [PATCH 30/40] add context switch in thread --- arch/x86/cpu_context.c | 37 ++++++++++++++++++++ arch/x86/irq_pit.S | 9 +++++ core/process.c | 5 +++ core/process.h | 1 + core/thread.c | 78 ++++++++++++++++++++++++++++++++++++------ core/thread.h | 35 +++++++++++++++++++ core/types.h | 3 ++ 7 files changed, 157 insertions(+), 11 deletions(-) diff --git a/arch/x86/cpu_context.c b/arch/x86/cpu_context.c index 3c8a2ca..48697f9 100644 --- a/arch/x86/cpu_context.c +++ b/arch/x86/cpu_context.c @@ -310,6 +310,43 @@ int cpu_kstate_init(struct cpu_state **ctxt, cpu_kstate_function_arg1_t *start_f return 0; } +int cpu_ustate_init(struct cpu_state **ctx, uaddr_t startPC, uint32_t arg1, uint32_t arg2, + uaddr_t startSP, vaddr_t kernelStackBottom, size_t kernelStackSize) +{ + + // The user context is stacked above the usual cpu state by the CPU on context switch. + // So store it when the cpu expect it (See cpu_kstate_init for more details) + struct cpu_ustate *uctx = + (struct cpu_ustate *)(kernelStackBottom + kernelStackSize - sizeof(struct cpu_ustate)); + + /* If needed, poison the stack */ +#ifdef CPU_STATE_DETECT_UNINIT_KERNEL_VARS + memset((void *)kernelStackBottom, CPU_STATE_STACK_POISON, kernelStackSize); +#elif defined(CPU_STATE_DETECT_KERNEL_STACK_OVERFLOW) + cpu_state_prepare_detect_kernel_stack_overflow(stack_bottom, stack_size); +#endif + + memset(uctx, 0, sizeof(struct cpu_ustate)); + + uctx->regs.eip = startPC; + uctx->regs.eax = arg1; + uctx->regs.ebx = arg2; + + uctx->regs.cs = BUILD_SEGMENT_REG_VALUE(3, FALSE, SEG_UCODE); // Code + uctx->regs.ds = BUILD_SEGMENT_REG_VALUE(3, FALSE, SEG_UDATA); // Data + uctx->regs.es = BUILD_SEGMENT_REG_VALUE(3, FALSE, SEG_UDATA); // Data + uctx->regs.cpl0_ss = BUILD_SEGMENT_REG_VALUE(3, FALSE, SEG_UDATA); // Kernel Stack + uctx->cpl3_ss = BUILD_SEGMENT_REG_VALUE(3, FALSE, SEG_UDATA); // User Stack + + uctx->cpl3_esp = startSP; + + /* The newly created context is initially interruptible */ + uctx->regs.eflags = (1 << 9); /* set IF bit */ + + *ctx = (struct cpu_state *)uctx; + return 0; +} + #if defined(CPU_STATE_DETECT_KERNEL_STACK_OVERFLOW) void cpu_state_prepare_detect_kernel_stack_overflow(const struct cpu_state *ctxt, vaddr_t stack_bottom, size_t stack_size) diff --git a/arch/x86/irq_pit.S b/arch/x86/irq_pit.S index 4305875..cc5f0f0 100644 --- a/arch/x86/irq_pit.S +++ b/arch/x86/irq_pit.S @@ -1,3 +1,5 @@ +#define ASM_SOURCE 1 +#include "segment.h" .file "irq_pit.S" .text @@ -22,6 +24,13 @@ pit_handler: // already got eflags, cs and eip on stack thanks to CPU pushw %fs // esp+2 pushw %gs // esp + /* Set correct kernel segment descriptors' value */ + movw $BUILD_SEGMENT_REG_VALUE(0, 0, SEG_KDATA), %di + pushw %di ; popw %ds + pushw %di ; popw %es + pushw %di ; popw %fs + pushw %di ; popw %gs + /* Send EOI to PIC */ movb $0x20, %al outb %al, $0x20 diff --git a/core/process.c b/core/process.c index 182c33b..90acb13 100644 --- a/core/process.c +++ b/core/process.c @@ -161,3 +161,8 @@ int processSetName(struct process *proc, char *name) return 0; } + +struct mmu_context *processGetMMUContext(struct process *proc) +{ + return proc->context; +} diff --git a/core/process.h b/core/process.h index 61350bc..b6e11b9 100644 --- a/core/process.h +++ b/core/process.h @@ -14,3 +14,4 @@ int processUnref(struct process *proc); int processSetName(struct process *proc, char *name); int processAddThread(struct process *proc, struct thread *th); int processRemoveThread(struct thread *th); +struct mmu_context *processGetMMUContext(struct process *th); diff --git a/core/thread.c b/core/thread.c index 2ac49ad..9fe7b24 100644 --- a/core/thread.c +++ b/core/thread.c @@ -4,12 +4,15 @@ #include "irq.h" #include "klibc.h" #include "list.h" +#include "mmuContext.h" #include "time.h" #include "vga.h" static struct thread *currentThread; static struct thread *threadWithTimeout; +static void threadPrepareContext(struct thread *th); + void threadExit() { uint32_t flags; @@ -55,7 +58,7 @@ struct thread *threadCreate(const char *name, cpu_kstate_function_arg1_t func, v return NULL; thread->stackAddr = (vaddr_t)malloc(THREAD_DEFAULT_STACK_SIZE); - if(!thread->stackAddr) + if (!thread->stackAddr) return NULL; #ifdef DEBUG printf("Alloc stack at 0x%x struct at 0x%x\n", thread->stackAddr, thread); @@ -92,13 +95,19 @@ void threadDelete(struct thread *thread) uint32_t flags; disable_IRQs(flags); list_delete(currentThread, thread); + restore_IRQs(flags); + + if (thread->squattedContext) { + threadChangeCurrentContext(NULL); + } + if (thread->process) + processRemoveThread(thread); #ifdef DEBUG printf("Free stack at 0x%x struct at 0x%x\n", thread->stackAddr, thread); #endif free((void *)thread->stackAddr); free((void *)thread); - restore_IRQs(flags); } struct thread *threadSelectNext() @@ -187,6 +196,7 @@ int threadWait(struct thread *current, struct thread *next, unsigned long msec) currentThread = next; currentThread->state = RUNNING; + threadPrepareContext(next); cpu_context_switch(¤t->cpuState, next->cpuState); return current->sleepHaveTimeouted; @@ -213,6 +223,7 @@ int threadYield() currentThread = next; currentThread->state = RUNNING; + threadPrepareContext(next); cpu_context_switch(¤t->cpuState, next->cpuState); restore_IRQs(flags); @@ -240,6 +251,7 @@ int threadMsleep(unsigned long msec) currentThread = next; currentThread->state = RUNNING; + threadPrepareContext(next); cpu_context_switch(¤t->cpuState, next->cpuState); restore_IRQs(flags); return current->sleepHaveTimeouted == 1; @@ -261,17 +273,61 @@ int threadAddThread(struct thread *th) return 0; } -void threadPrepareSyscallSwitchBack(struct cpu_state *cpu_state){ - (void)cpu_state; - return; +static void threadPrepareContext(struct thread *th) +{ + if (cpu_context_is_in_user_mode(th->cpuState)) { + assert(th->process != NULL); + assert(th->squattedContext == NULL); + mmuContextSwitch(processGetMMUContext(th->process)); + } else if (th->squattedContext) { + mmuContextSwitch(th->squattedContext); + } } -void threadPrepareExceptionSwitchBack(struct cpu_state *cpu_state){ - (void)cpu_state; - return; +int threadChangeCurrentContext(struct mmu_context *ctx) +{ + uint32_t flags; + struct mmu_context *prev = currentThread->squattedContext; + + if (ctx != NULL) { + assert(prev == NULL); + } else { + assert(prev != NULL); + } + + disable_IRQs(flags); + currentThread->squattedContext = ctx; + + if (ctx != NULL) { + mmuContextRef(ctx); + mmuContextSwitch(ctx); + } else { + mmuContextUnref(prev); + } + restore_IRQs(flags); + + return 0; } -void threadPrepareIrqSwitchBack(struct cpu_state *cpu_state){ - (void)cpu_state; - return; +void threadPrepareSyscallSwitchBack(struct cpu_state *cpuState) +{ + currentThread->cpuState = cpuState; + threadPrepareContext(currentThread); +} + +void threadPrepareExceptionSwitchBack(struct cpu_state *cpuState) +{ + currentThread->cpuState = cpuState; + threadPrepareContext(currentThread); +} + +void threadPrepareIrqServicing(struct cpu_state *cpuState) +{ + currentThread->cpuState = cpuState; +} + +void threadPrepareIrqSwitchBack(struct cpu_state *cpuState) +{ + currentThread->cpuState = cpuState; + threadPrepareContext(currentThread); } diff --git a/core/thread.h b/core/thread.h index a8d6cbd..ce76c2b 100644 --- a/core/thread.h +++ b/core/thread.h @@ -32,6 +32,40 @@ struct thread { // For User thread only struct thread *nextInProcess, *prevInProcess; struct process *process; + + /** + * Address space currently "squatted" by the thread, or used to be + * active when the thread was interrupted/preempted. This is the MMU + * configuration expected before the cpu_state of the thread is + * restored on CPU. + * - For kernel threads: should normally be NULL, meaning that the + * thread will squat the current mm_context currently set in the + * MMU. Might be NON NULL when a kernel thread squats a given + * process to manipulate its address space. + * - For user threads: should normally be NULL. More precisely: + * - in user mode: the thread->process.mm_context is ALWAYS + * set on MMU. squatted_mm_context is ALWAYS NULL in this + * situation, meaning that the thread in user mode uses its + * process-space as expected + * - in kernel mode: NULL means that we keep on using the + * mm_context currently set on MMU, which might be the + * mm_context of another process. This is natural since a + * thread in kernel mode normally only uses data in kernel + * space. BTW, this limits the number of TLB flushes. However, + * there are exceptions where this squatted_mm_context will + * NOT be NULL. One is the copy_from/to_user API, which can + * force the effective mm_context so that the MMU will be + * (re)configured upon every context to the thread to match + * the squatted_mm_context. Another exception is when a parent + * thread creates the address space of a child process, in + * which case the parent thread might temporarilly decide to + * switch to the child's process space. + * + * This is the SOS/matos implementation of the Linux "Lazy TLB" and + * address-space loaning. + */ + struct mmu_context *squattedContext; + }; int threadSetup(vaddr_t mainStack, size_t mainStackSize); @@ -50,3 +84,4 @@ int threadMsleep(unsigned long msec); int threadOnJieffiesTick(); struct thread *getCurrentThread(); int threadAddThread(struct thread *th); +int threadChangeCurrentContext(struct mmu_context *ctx); diff --git a/core/types.h b/core/types.h index 5fcfbf3..45f0fd0 100644 --- a/core/types.h +++ b/core/types.h @@ -33,3 +33,6 @@ typedef unsigned long vaddr_t; // Physical address typedef unsigned long paddr_t; + +// Userspace vaddr +typedef unsigned long uaddr_t; -- 2.47.0 From 84e104d83ef7a9c2929cab98b2658eb9860883cf Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Tue, 2 Nov 2021 21:47:05 +0100 Subject: [PATCH 31/40] Implement some basic syscall --- arch/x86/cpu_context.c | 31 +++++++++++++++++++++++++++++ core/syscall.c => arch/x86/swintr.c | 7 +------ core/syscall.h => arch/x86/swintr.h | 1 + arch/x86/syscall_wrappers.S | 4 ++-- core/cpu_context.h | 12 +++++++++++ core/thread.c | 1 + 6 files changed, 48 insertions(+), 8 deletions(-) rename core/syscall.c => arch/x86/swintr.c (63%) rename core/syscall.h => arch/x86/swintr.h (98%) diff --git a/arch/x86/cpu_context.c b/arch/x86/cpu_context.c index 48697f9..b7a6fd6 100644 --- a/arch/x86/cpu_context.c +++ b/arch/x86/cpu_context.c @@ -489,3 +489,34 @@ void cpu_context_update_kernel_tss(struct cpu_state *next_ctxt) mode */ } } + + +inline +int syscallGet3args(const struct cpu_state *user_ctxt, + /* out */unsigned int *arg1, + /* out */unsigned int *arg2, + /* out */unsigned int *arg3) +{ + *arg1 = user_ctxt->ebx; + *arg2 = user_ctxt->ecx; + *arg3 = user_ctxt->edx; + return 0; +} + + +int syscallGet1arg(const struct cpu_state *user_ctxt, + /* out */unsigned int *arg1) +{ + unsigned int unused; + return syscallGet3args(user_ctxt, arg1, & unused, & unused); +} + + +int _syscallGet2args(const struct cpu_state *user_ctxt, + /* out */unsigned int *arg1, + /* out */unsigned int *arg2) +{ + unsigned int unused; + return syscallGet3args(user_ctxt, arg1, arg2, & unused); +} + diff --git a/core/syscall.c b/arch/x86/swintr.c similarity index 63% rename from core/syscall.c rename to arch/x86/swintr.c index 87976a0..d16d3e8 100644 --- a/core/syscall.c +++ b/arch/x86/swintr.c @@ -1,4 +1,4 @@ -#include "syscall.h" +#include "swintr.h" #include "irq.h" #include "idt.h" @@ -14,8 +14,3 @@ int syscallSetup(){ return ret; } -int syscall_execute(int syscallId, const struct cpu_state *user_ctx){ - (void)syscallId; - (void)user_ctx; - return 0; -} diff --git a/core/syscall.h b/arch/x86/swintr.h similarity index 98% rename from core/syscall.h rename to arch/x86/swintr.h index 2b4a2be..2da6c00 100644 --- a/core/syscall.h +++ b/arch/x86/swintr.h @@ -2,4 +2,5 @@ #define SYSCALL_INTR_NB 0x42 + int syscallSetup(); diff --git a/arch/x86/syscall_wrappers.S b/arch/x86/syscall_wrappers.S index 06d2a9f..53e58cb 100644 --- a/arch/x86/syscall_wrappers.S +++ b/arch/x86/syscall_wrappers.S @@ -6,7 +6,7 @@ .text /* The address of the real "C" syscall function */ -.extern syscall_execute +.extern syscallExecute /** Update the kernel TSS in case we are switching to a thread in user mode in order to come back into the correct kernel stack */ @@ -51,7 +51,7 @@ syscallHandler: pushl %esp /* user_ctxt */ pushl %eax /* syscall ID */ - call syscall_execute + call syscallExecute /* Unallocate the stack used by the do_syscall arguments */ addl $8, %esp diff --git a/core/cpu_context.h b/core/cpu_context.h index e17c31b..840179f 100644 --- a/core/cpu_context.h +++ b/core/cpu_context.h @@ -200,3 +200,15 @@ void cpu_state_detect_kernel_stack_overflow(const struct cpu_state *ctxt, */}) #define cpu_state_detect_kernel_stack_overflow(ctxt, stkbottom, stksize) ({/* nop */}) #endif + +int syscallGet3args(const struct cpu_state *user_ctxt, + /* out */ unsigned int *arg1, + /* out */ unsigned int *arg2, + /* out */ unsigned int *arg3); + +int syscallGet1arg(const struct cpu_state *user_ctxt, + /* out */ unsigned int *arg1); + +int syscallGet2args(const struct cpu_state *user_ctxt, + /* out */ unsigned int *arg1, + /* out */ unsigned int *arg2); diff --git a/core/thread.c b/core/thread.c index 9fe7b24..fa31335 100644 --- a/core/thread.c +++ b/core/thread.c @@ -28,6 +28,7 @@ void threadExit() currentThread->state = EXITING; currentThread = next; currentThread->state = RUNNING; + threadPrepareContext(next); cpu_context_exit_to(next->cpuState, (cpu_kstate_function_arg1_t *)threadDelete, (uint32_t)current); -- 2.47.0 From 7b60e1bdaca89c6d2e38b98b29a1f036e4627953 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Tue, 2 Nov 2021 21:57:57 +0100 Subject: [PATCH 32/40] Fix threadSwitch context --- core/syscall.c | 27 +++++++++++++++++++++++++++ core/syscall.h | 9 +++++++++ core/thread.c | 11 +++++++---- 3 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 core/syscall.c create mode 100644 core/syscall.h diff --git a/core/syscall.c b/core/syscall.c new file mode 100644 index 0000000..9d99a61 --- /dev/null +++ b/core/syscall.c @@ -0,0 +1,27 @@ +#include "klibc.h" +#include "stdarg.h" +#include "syscall.h" +#include "thread.h" + +int syscallExecute(int syscallId, const struct cpu_state *user_ctx){ + + int ret; + + switch (syscallId) { + case SYSCALL_ID_EXIT: + uint status; + ret = syscallGet1arg(user_ctx, &status); + if(ret != 0) + break; + threadExit(); + assert(0); + break; + case SYSCALL_ID_WRITE: + ret = printf("YOLO FROM USERSPACE\n"); + break; + default: + printf("Unknon syscall id %d\n", syscallId); + ret = -ENOENT; + } + return ret; +} diff --git a/core/syscall.h b/core/syscall.h new file mode 100644 index 0000000..d73e10e --- /dev/null +++ b/core/syscall.h @@ -0,0 +1,9 @@ +#pragma once + +#include "cpu_context.h" + + +#define SYSCALL_ID_EXIT 1 +#define SYSCALL_ID_WRITE 2 + +int syscallExecute(int syscallId, const struct cpu_state *user_ctx); diff --git a/core/thread.c b/core/thread.c index fa31335..42ab230 100644 --- a/core/thread.c +++ b/core/thread.c @@ -132,10 +132,13 @@ struct cpu_state *threadSwitch(struct cpu_state *prevCpu) disable_IRQs(flags); nextThread = threadSelectNext(); - currentThread->cpuState = prevCpu; - currentThread->state = READY; - currentThread = nextThread; - currentThread->state = RUNNING; + if (nextThread != currentThread) { + currentThread->cpuState = prevCpu; + currentThread->state = READY; + currentThread = nextThread; + currentThread->state = RUNNING; + threadPrepareContext(nextThread); + } restore_IRQs(flags); -- 2.47.0 From ebc90d3f06f08637315998e8df8ee759ea42f9fe Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Tue, 2 Nov 2021 22:33:04 +0100 Subject: [PATCH 33/40] Fix mapping issue --- arch/x86/paging.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/x86/paging.c b/arch/x86/paging.c index b7759f0..1e618a8 100644 --- a/arch/x86/paging.c +++ b/arch/x86/paging.c @@ -162,7 +162,8 @@ int pageMap(vaddr_t vaddr, paddr_t paddr, int flags) __native_flush_tlb_single((vaddr_t)pt); memset((void *)pt, 0, PAGE_SIZE); - } else { + } + { // Already mapped ? Remove old mapping if (pt[ptEntry].present) { @@ -223,7 +224,7 @@ paddr_t pagingGetPaddr(vaddr_t vaddr) /* Get the page directory entry and table entry index for this address */ unsigned pdEntry = vaddr >> PD_SHIFT; - unsigned ptEntry = vaddr >> PT_SHIFT; + unsigned ptEntry = vaddr >> PT_SHIFT & PTE_MASK; unsigned pageOffset = vaddr & PAGE_MASK; // Thank to mirroring, we can access the PD -- 2.47.0 From 97d1e9ba2a06e0276c0cbe2e1ba1931a95cff091 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Tue, 2 Nov 2021 23:05:56 +0100 Subject: [PATCH 34/40] Pit handler save ebp --- arch/x86/irq_pit.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/irq_pit.S b/arch/x86/irq_pit.S index cc5f0f0..e0e596b 100644 --- a/arch/x86/irq_pit.S +++ b/arch/x86/irq_pit.S @@ -11,6 +11,8 @@ pit_handler: // already got eflags, cs and eip on stack thanks to CPU pushl $0 // err_code esp+12+7*4=40 pushl %ebp + movl %esp, %ebp + pushl %eax pushl %ecx pushl %edx -- 2.47.0 From 959bc56bc7ceb0cf6d3d045b168377ff99fbdf69 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Tue, 2 Nov 2021 23:22:24 +0100 Subject: [PATCH 35/40] pit_handler: fix stack growing --- arch/x86/irq_pit.S | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/irq_pit.S b/arch/x86/irq_pit.S index e0e596b..f5e8517 100644 --- a/arch/x86/irq_pit.S +++ b/arch/x86/irq_pit.S @@ -39,6 +39,7 @@ pit_handler: // already got eflags, cs and eip on stack thanks to CPU pushl %esp call pitIrqHandler + addl $4, %esp movl %eax,%esp /* Restore the CPU context */ -- 2.47.0 From e94f87b7985baa1075f43faa995a43ab2ded1c1d Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Tue, 2 Nov 2021 23:56:47 +0100 Subject: [PATCH 36/40] Fix threadSwitch --- core/thread.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/thread.c b/core/thread.c index 42ab230..0aa406d 100644 --- a/core/thread.c +++ b/core/thread.c @@ -132,11 +132,11 @@ struct cpu_state *threadSwitch(struct cpu_state *prevCpu) disable_IRQs(flags); nextThread = threadSelectNext(); + currentThread->cpuState = prevCpu; if (nextThread != currentThread) { - currentThread->cpuState = prevCpu; - currentThread->state = READY; - currentThread = nextThread; - currentThread->state = RUNNING; + currentThread->state = READY; + currentThread = nextThread; + currentThread->state = RUNNING; threadPrepareContext(nextThread); } -- 2.47.0 From afb622e17a051471bc025de933ec5ae11930881f Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Wed, 3 Nov 2021 23:00:20 +0100 Subject: [PATCH 37/40] ATA: write do not block forever --- drivers/ata.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/ata.c b/drivers/ata.c index eaa5eec..5bc8b1b 100644 --- a/drivers/ata.c +++ b/drivers/ata.c @@ -536,6 +536,7 @@ int ATAReadSector(struct ata_device *dev, int lba, uint nb_sector, void *buf) int ATAWriteSector(struct ata_device *dev, int lba, uint nb_sector, void *buf) { struct ata_controller *ctl = dev->ctl; + int ret = 0; mutexLock(&ctl->mutex); @@ -561,7 +562,8 @@ int ATAWriteSector(struct ata_device *dev, int lba, uint nb_sector, void *buf) printf("ATA write error\n"); return -1; } - while (1) { + int retry = 100; + while (retry) { int status = inb(ctl->base + ATA_PIO_STATUS); if (status & ATA_PIO_STATUS_REG_ERR) { mutexUnlock(&ctl->mutex); @@ -571,12 +573,19 @@ int ATAWriteSector(struct ata_device *dev, int lba, uint nb_sector, void *buf) if ((status & ATA_PIO_STATUS_DRQ) && !(status & ATA_PIO_STATUS_DRIVE_BUSY)) break; + retry--; + } + if(retry == 0){ + printf("ATA write timeout error\n"); + ret=-1; + break; } for (uint i = 0; i < (DISK_SECTOR_SIZE / sizeof(uint16_t)); i++) { outw(ctl->base + ATA_PIO_DATA, *ptr++); } + retry = 1000; // Wait for the device to receive the data - while (1) { + while (retry) { int status = inb(ctl->base + ATA_PIO_STATUS); if (status & ATA_PIO_STATUS_REG_ERR) { mutexUnlock(&ctl->mutex); @@ -586,12 +595,18 @@ int ATAWriteSector(struct ata_device *dev, int lba, uint nb_sector, void *buf) if (!(status & ATA_PIO_STATUS_DRQ) && !(status & ATA_PIO_STATUS_DRIVE_BUSY)) break; + retry --; + } + if(retry == 0){ + printf("ATA write data timeout error\n"); + ret=-1; + break; } } mutexUnlock(&ctl->mutex); - return 0; + return ret; } struct ata_device *ATAGetDevice(int ctlId, int devId) -- 2.47.0 From 7c227a730c8e1f326627f1085b8d97a0a0f46744 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Wed, 3 Nov 2021 23:36:48 +0100 Subject: [PATCH 38/40] debug output serial into a file --- debug.gdb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug.gdb b/debug.gdb index 6828808..cc6c6d8 100644 --- a/debug.gdb +++ b/debug.gdb @@ -2,4 +2,4 @@ add-symbol-file kernel.sym source custom_gdb_extension.py #For ASM sources directory arch/x86/:core -target remote | qemu-system-i386 -S -gdb stdio -kernel kernel -m 16M +target remote | qemu-system-i386 -S -gdb stdio -kernel kernel -m 16M -serial file:serialOut -- 2.47.0 From a02167ad88956653dcc1c53abea3a090190b3d6f Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Wed, 3 Nov 2021 23:37:44 +0100 Subject: [PATCH 39/40] Reduce assert stack depth This may cause page fault in test --- core/assert.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/assert.h b/core/assert.h index a48a58e..5bafdd8 100644 --- a/core/assert.h +++ b/core/assert.h @@ -6,7 +6,7 @@ do { \ if (!(p)) { \ printf("BUG at %s:%d assert(%s)\n", __FILE__, __LINE__, #p); \ - printStackTrace(5); \ + printStackTrace(3); \ while (1) { \ } \ } \ @@ -17,7 +17,7 @@ if (!(p)) { \ printf("BUG at %s:%d assert(%s)\n", __FILE__, __LINE__, #p); \ printf(__VA_ARGS__); \ - printStackTrace(5); \ + printStackTrace(3); \ while (1) { \ } \ } \ -- 2.47.0 From 4ad5b58787a31f2cde834b106b6a0a3af4aa6d2b Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Wed, 3 Nov 2021 23:54:36 +0100 Subject: [PATCH 40/40] Userspace with a syscall --- arch/x86/cpu_context.c | 2 +- arch/x86/swintr.c | 4 ++- core/cpu_context.h | 3 ++ core/main.c | 2 ++ core/thread.c | 62 +++++++++++++++++++++++++++++++++++++++--- core/thread.h | 3 ++ tests/test.c | 53 ++++++++++++++++++++++++++++++++++++ 7 files changed, 123 insertions(+), 6 deletions(-) diff --git a/arch/x86/cpu_context.c b/arch/x86/cpu_context.c index b7a6fd6..eedd0f4 100644 --- a/arch/x86/cpu_context.c +++ b/arch/x86/cpu_context.c @@ -335,7 +335,7 @@ int cpu_ustate_init(struct cpu_state **ctx, uaddr_t startPC, uint32_t arg1, uint uctx->regs.cs = BUILD_SEGMENT_REG_VALUE(3, FALSE, SEG_UCODE); // Code uctx->regs.ds = BUILD_SEGMENT_REG_VALUE(3, FALSE, SEG_UDATA); // Data uctx->regs.es = BUILD_SEGMENT_REG_VALUE(3, FALSE, SEG_UDATA); // Data - uctx->regs.cpl0_ss = BUILD_SEGMENT_REG_VALUE(3, FALSE, SEG_UDATA); // Kernel Stack + uctx->regs.cpl0_ss = BUILD_SEGMENT_REG_VALUE(0, FALSE, SEG_KDATA); // Kernel Stack uctx->cpl3_ss = BUILD_SEGMENT_REG_VALUE(3, FALSE, SEG_UDATA); // User Stack uctx->cpl3_esp = startSP; diff --git a/arch/x86/swintr.c b/arch/x86/swintr.c index d16d3e8..44d28fc 100644 --- a/arch/x86/swintr.c +++ b/arch/x86/swintr.c @@ -1,3 +1,4 @@ +#include "assert.h" #include "swintr.h" #include "irq.h" #include "idt.h" @@ -8,9 +9,10 @@ int syscallSetup(){ uint32_t flags, ret; disable_IRQs(flags); - ret = idt_set_handler(SYSCALL_INTR_NB, (vaddr_t)syscallHandler, 3); + ret = idt_set_handler(SYSCALL_INTR_NB, (vaddr_t)syscallHandler, 3); restore_IRQs(flags); + assert(ret == 0); return ret; } diff --git a/core/cpu_context.h b/core/cpu_context.h index 840179f..724b067 100644 --- a/core/cpu_context.h +++ b/core/cpu_context.h @@ -201,6 +201,9 @@ void cpu_state_detect_kernel_stack_overflow(const struct cpu_state *ctxt, #define cpu_state_detect_kernel_stack_overflow(ctxt, stkbottom, stksize) ({/* nop */}) #endif +int cpu_ustate_init(struct cpu_state **ctx, uaddr_t startPC, uint32_t arg1, uint32_t arg2, + uaddr_t startSP, vaddr_t kernelStackBottom, size_t kernelStackSize); + int syscallGet3args(const struct cpu_state *user_ctxt, /* out */ unsigned int *arg1, /* out */ unsigned int *arg2, diff --git a/core/main.c b/core/main.c index f261810..62f4f19 100644 --- a/core/main.c +++ b/core/main.c @@ -19,6 +19,7 @@ #include "serial.h" #include "stack.h" #include "stdarg.h" +#include "swintr.h" #ifdef RUN_TEST #include "test.h" #endif @@ -172,6 +173,7 @@ void kmain(unsigned long magic, unsigned long addr) threadSetup(_stack_bottom, (_stack_top - _stack_bottom + 1)); threadCreate("idle ", idleThread, NULL); processSetup(); + syscallSetup(); irqSetRoutine(IRQ_TIMER, pit_handler); diff --git a/core/thread.c b/core/thread.c index 0aa406d..4bd8f6d 100644 --- a/core/thread.c +++ b/core/thread.c @@ -6,6 +6,7 @@ #include "list.h" #include "mmuContext.h" #include "time.h" +#include "types.h" #include "vga.h" static struct thread *currentThread; @@ -59,15 +60,15 @@ struct thread *threadCreate(const char *name, cpu_kstate_function_arg1_t func, v return NULL; thread->stackAddr = (vaddr_t)malloc(THREAD_DEFAULT_STACK_SIZE); - if (!thread->stackAddr) + if (!thread->stackAddr){ + free(thread); return NULL; + } #ifdef DEBUG printf("Alloc stack at 0x%x struct at 0x%x\n", thread->stackAddr, thread); #endif thread->stackSize = THREAD_DEFAULT_STACK_SIZE; - if (!thread->stackAddr) - goto free_mem; if (name) strzcpy(thread->name, name, THREAD_NAME_MAX_LENGTH); @@ -91,12 +92,53 @@ free_mem: return NULL; } +struct thread *threadCreateUser(const char *name, struct process *proc, uaddr_t startPc, + uint32_t arg1, uint32_t arg2, uaddr_t startSP) +{ + struct thread *thread = malloc(sizeof(struct thread)); + + if (thread == NULL) + return NULL; + + thread->stackAddr = (vaddr_t)malloc(THREAD_DEFAULT_STACK_SIZE); + if (!thread->stackAddr) { + free(thread); + return NULL; + } + thread->stackSize = THREAD_DEFAULT_STACK_SIZE; + + if (name) + strzcpy(thread->name, name, THREAD_NAME_MAX_LENGTH); + else + strzcpy(thread->name, "[UNKNOW]", THREAD_NAME_MAX_LENGTH); + + if (cpu_ustate_init(&thread->cpuState, startPc, arg1, arg2, startSP, thread->stackAddr, + thread->stackSize)) { + goto free_mem; + } + + if(processAddThread(proc, thread)) + goto free_mem; + + thread->state = READY; + uint32_t flags; + disable_IRQs(flags); + list_add_tail(currentThread, thread); + restore_IRQs(flags); + return thread; +free_mem: + free((void *)thread->stackAddr); + free((void *)thread); + return NULL; +} + void threadDelete(struct thread *thread) { uint32_t flags; disable_IRQs(flags); list_delete(currentThread, thread); restore_IRQs(flags); + assert(thread->state == EXITING); if (thread->squattedContext) { threadChangeCurrentContext(NULL); @@ -135,6 +177,7 @@ struct cpu_state *threadSwitch(struct cpu_state *prevCpu) currentThread->cpuState = prevCpu; if (nextThread != currentThread) { currentThread->state = READY; +// printf(" Switch from %s to %s\n", currentThread->name, nextThread->name); currentThread = nextThread; currentThread->state = RUNNING; threadPrepareContext(nextThread); @@ -145,6 +188,17 @@ struct cpu_state *threadSwitch(struct cpu_state *prevCpu) return nextThread->cpuState; } +int threadCount() +{ + struct thread *nextThread; + int idx; + uint32_t flags; + disable_IRQs(flags); + list_foreach(currentThread, nextThread, idx){ + } + return idx; +} + int threadOnJieffiesTick() { struct thread *nextThread; @@ -224,7 +278,7 @@ int threadYield() if (current->state == RUNNING) current->state = READY; - +// printf(" Yield from %s to %s\n", currentThread->name, next->name); currentThread = next; currentThread->state = RUNNING; threadPrepareContext(next); diff --git a/core/thread.h b/core/thread.h index ce76c2b..0997676 100644 --- a/core/thread.h +++ b/core/thread.h @@ -72,6 +72,8 @@ int threadSetup(vaddr_t mainStack, size_t mainStackSize); void threadExit(); struct thread *threadCreate(const char *name, cpu_kstate_function_arg1_t func, void *args); +struct thread *threadCreateUser(const char *name, struct process *proc, uaddr_t startPc, + uint32_t arg1, uint32_t arg2, uaddr_t startSP); void threadDelete(struct thread *thread); struct thread *threadSelectNext(); @@ -85,3 +87,4 @@ int threadOnJieffiesTick(); struct thread *getCurrentThread(); int threadAddThread(struct thread *th); int threadChangeCurrentContext(struct mmu_context *ctx); +int threadCount(); diff --git a/tests/test.c b/tests/test.c index 4544a77..a1117f8 100644 --- a/tests/test.c +++ b/tests/test.c @@ -3,6 +3,7 @@ #include "ata.h" #include "assert.h" #include "cpu_context.h" +#include "kernel.h" #include "klibc.h" #include "thread.h" #include "list.h" @@ -13,6 +14,8 @@ #include "serial.h" #include "stack.h" #include "synchro.h" +#include "syscall.h" +#include "swintr.h" #include "time.h" void testMemcpyPerf() @@ -213,6 +216,7 @@ static void reclaim_stack(void *stack_vaddr) static void exit_hello12(void *stack_vaddr) { + printf("Stopping hello\n"); cpu_context_exit_to(ctxt_main, (cpu_kstate_function_arg1_t *)reclaim_stack, (vaddr_t)stack_vaddr); } @@ -348,6 +352,7 @@ void testKthread() threadCreate("mtest1", mutThread, "mut1"); threadCreate("mtest2", mutThread, "mut2"); threadCreate("mtest3", mutThread, "mut3"); + threadMsleep(2000); } void testATAThread(){ @@ -382,6 +387,29 @@ static void testMMUContext() mmuContextUnref(new); } +static void userProgramm() +{ + int ret; + + asm volatile("movl %1,%%eax \n" + "movl %2,%%ebx \n" + "movl %3,%%ecx \n" + "movl %4,%%edx \n" + "int %5\n" + "movl %%eax, %0" + : "=g"(ret) + : "g"(SYSCALL_ID_WRITE), "g"(0), "g"(0), "g"(0), "i"(SYSCALL_INTR_NB) + : "eax", "ebx", "ecx", "edx"); + asm volatile("movl %1,%%eax \n" + "movl %2,%%ebx \n" + "movl %3,%%ecx \n" + "movl %4,%%edx \n" + "int %5\n" + "movl %%eax, %0" + : "=g"(ret) + : "g"(SYSCALL_ID_EXIT), "g"(0), "g"(0), "g"(0), "i"(SYSCALL_INTR_NB) + : "eax", "ebx", "ecx", "edx"); +} static void testProcess(){ struct process *proc= processCreate("TESTPROCESS"); @@ -397,6 +425,29 @@ static void testProcess(){ processUnref(proc); printf("Next process list should be empty\n"); processListPrint(); + printf("Running user space app\n"); + struct process *proc2= processCreate("TESTPROCESS2"); + + threadChangeCurrentContext(processGetMMUContext(proc2)); + uaddr_t stackTop = 0xfffffffc; + uaddr_t stackBottom = ALIGN_DOWN(stackTop, PAGE_SIZE); + paddr_t stackPhy = allocPhyPage(1); + assert(pageMap(stackBottom, stackPhy, PAGING_MEM_USER | PAGING_MEM_WRITE | PAGING_MEM_READ) == 0); + unrefPhyPage(stackPhy); + + uaddr_t mem = PAGING_BASE_USER_ADDRESS; + paddr_t memPhy = allocPhyPage(1); + assert(pageMap(mem, memPhy, PAGING_MEM_USER | PAGING_MEM_WRITE | PAGING_MEM_READ) == 0); + unrefPhyPage(memPhy); + + memcpy((void *)mem, userProgramm, PAGE_SIZE); + + threadCreateUser("UserProg", proc2, mem, 0, 0, stackTop); + threadYield(); + processUnref(proc2); + threadChangeCurrentContext(NULL); + + printf("Running user space app DONE\n"); } void run_test(void) @@ -436,7 +487,9 @@ void run_test(void) printf("Testing backtrace\n"); test_backtrace(); testCoroutine(); + int nbThread = threadCount(); testKthread(); + assert(nbThread + 1 == threadCount());//For sleep Thread testMMUContext(); testProcess(); memGetStat(&afterFreemem, &afterUsedmem); -- 2.47.0