From ed4192548143468362124ee7ee6105c001fe29c0 Mon Sep 17 00:00:00 2001 From: Hanjie Wu Date: Fri, 21 Apr 2023 01:09:03 -0400 Subject: WP --- .clang-format | 148 ++++++++++++++++++++++++++++++++++++++++ config.mk | 4 +- kern/inc/pv.h | 63 +++++++++++++++++ kern/inc/sched.h | 35 +++++++++- kern/interrupt.c | 51 +++++++++----- kern/interrupt_asm.S | 4 +- kern/kernel.c | 7 +- kern/mm.c | 1 - kern/paging.c | 5 +- kern/pv.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++ kern/sched.c | 150 +++++++++++++++++++++++------------------ kern/syscall_asm.S | 26 +++++++- kern/syscall_hvcall.c | 66 ++++++++++++++++++ kern/timer.c | 2 +- kern/usermem.c | 18 ----- kern/usermem_asm.S | 4 +- 16 files changed, 649 insertions(+), 117 deletions(-) create mode 100644 .clang-format create mode 100644 kern/inc/pv.h create mode 100644 kern/pv.c create mode 100644 kern/syscall_hvcall.c diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..6ba7994 --- /dev/null +++ b/.clang-format @@ -0,0 +1,148 @@ +--- +Language: Cpp +# BasedOnStyle: Chromium +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Left +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: true +BinPackParameters: false +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^' + Priority: 2 + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 4 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Never +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +RawStringFormats: + - Language: Cpp + Delimiters: + - cc + - CC + - cpp + - Cpp + - CPP + - 'c++' + - 'C++' + CanonicalDelimiter: '' + BasedOnStyle: google + - Language: TextProto + Delimiters: + - pb + - PB + - proto + - PROTO + EnclosingFunctions: + - EqualsProto + - EquivToProto + - PARSE_PARTIAL_TEXT_PROTO + - PARSE_TEST_PROTO + - PARSE_TEXT_PROTO + - ParseTextOrDie + - ParseTextProtoOrDie + CanonicalDelimiter: '' + BasedOnStyle: google +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +TabWidth: 8 +UseTab: Never +... + diff --git a/config.mk b/config.mk index 067d33f..e497169 100644 --- a/config.mk +++ b/config.mk @@ -165,7 +165,7 @@ KERNEL_OBJS = console.o kernel.o loader.o malloc_wrappers.o sync_asm.o \ mm.o asm_instr.o sched.o sched_asm.o syscall_asm.o interrupt.o \ paging.o timer.o interrupt_asm.o usermem.o syscall_process.o \ syscall_memory.o syscall_thread.o common.o sync.o syscall_io.o \ - usermem_asm.o syscall_misc.o kbd.o + usermem_asm.o syscall_misc.o kbd.o pv.o syscall_hvcall.o ########################################################################### # WARNING: Do not put **test** programs into the REQPROGS variables. Your @@ -216,3 +216,5 @@ KERNEL_OBJS = console.o kernel.o loader.o malloc_wrappers.o sync_asm.o \ # won't. # STUDENTREQPROGS = + +410GUESTBINS = hello magic diff --git a/kern/inc/pv.h b/kern/inc/pv.h new file mode 100644 index 0000000..7cd8c50 --- /dev/null +++ b/kern/inc/pv.h @@ -0,0 +1,63 @@ +#ifndef _PV_H_ +#define _PV_H_ + +#include +#include +#include +#include + +#include +#include +#include + +#define SEGSEL_RPL3 3 + +#define SEGSEL_PV_CS (SEGSEL_SPARE0 | SEGSEL_RPL3) +#define SEGSEL_PV_CS_IDX SEGSEL_SPARE0_IDX +#define SEGSEL_PV_DS (SEGSEL_SPARE1 | SEGSEL_RPL3) +#define SEGSEL_PV_DS_IDX SEGSEL_SPARE1_IDX +#define SEGSEL_PV_FS (SEGSEL_SPARE3 | SEGSEL_RPL3) +#define SEGSEL_PV_FS_IDX SEGSEL_SPARE3_IDX + +#define PV_VM_LIMIT (~(USER_MEM_START - 1)) + +#define PV_DEFAULT_SIZE 24 +#define PV_MINIMUM_SIZE 20 + +typedef struct pv_pd_s { + int refcount; + queue_t pv_link; + pa_t cr3; + pa_t user_cr3; +} pv_pd_t; + +typedef struct pv_idt_entry_s { + va_t eip; + int dpl; +} pv_idt_entry_t; + +typedef pv_idt_entry_t pv_idt_t[IDT_ENTS]; + +typedef struct pv_s { + int vif; + pv_pd_t* active_shadow_pd; + queue_t* shadow_pds; + pv_idt_t vidt; + va_t vesp0; +} pv_t; + +void pv_init(); + +struct process_s; +typedef struct process_s process_t; +struct thread_s; +typedef struct thread_s thread_t; + +thread_t* create_pv_process(thread_t* t, + simple_elf_t* elf, + char* exe, + va_size_t mem_size); + +void destroy_pv(pv_t* pv); + +#endif diff --git a/kern/inc/sched.h b/kern/inc/sched.h index 335f648..8fc0108 100644 --- a/kern/inc/sched.h +++ b/kern/inc/sched.h @@ -17,6 +17,7 @@ #include #include +#include #include /** name of idle process */ @@ -24,10 +25,34 @@ /** name of init process */ #define INIT_NAME "init" +#define IDLE_PID 2 +#define INIT_PID 1 + /** we use fs to find percpu area */ -#define SEGSEL_KERNEL_FS SEGSEL_SPARE0 +#define SEGSEL_KERNEL_FS SEGSEL_SPARE2 /** index of fs in gdt */ -#define SEGSEL_KERNEL_FS_IDX SEGSEL_SPARE0_IDX +#define SEGSEL_KERNEL_FS_IDX SEGSEL_SPARE2_IDX + +/* G means global segment */ +#define GDT_G_BIT 0x0080000000000000ull +/* FLAG is control flags for segment */ +#define GDT_FLAG_MASK 0x00f0ff0000000000ull +/* high part of base address */ +#define GDT_BASE_MASK_HI 0xff000000ull +/* low part of base address */ +#define GDT_BASE_MASK_LO 0x00ffffffull +/* position of high part of base address */ +#define GDT_BASE_SHIFT_HI (64 - 32) +/* position of low part of base address */ +#define GDT_BASE_SHIFT_LO (40 - 24) +/* high part of limit */ +#define GDT_LIMIT_MASK_HI 0xf0000ull +/* low part of limit */ +#define GDT_LIMIT_MASK_LO 0x0ffffull +/* position of high part of limit */ +#define GDT_LIMIT_SHIFT_HI (52 - 20) +/* position of low part of limit */ +#define GDT_LIMIT_SHIFT_LO (16 - 16) /** an allocated memory of a process */ typedef struct region_s { @@ -98,6 +123,8 @@ typedef struct process_s { pa_t cr3; vector_t regions; /* record the vitural memories the user has mapped */ mutex_t mm_lock; /* lock when operating VM */ + + pv_t* pv; } process_t; /** status of the thread, must lock ready_lock to change it, otherwise may be @@ -159,6 +186,8 @@ int alloc_tid(); * and stack_lo */ #define MAX_TOTAL_ARG_LEN (DEFAULT_STACK_SIZE - PAGE_SIZE) +uint64_t create_segsel(va_t base, va_size_t limit, uint64_t flags); + /** * @brief create an empty process with one thread and no user memory * @return the thread created or NULL on failure @@ -181,6 +210,8 @@ thread_t* create_process(int tid, char* exe, int argc, const char** argv); */ void destroy_thread(thread_t* t); +void destroy_pd(pa_t pd_pa); + /** * @brief add a memory region to a process * @param p the process diff --git a/kern/interrupt.c b/kern/interrupt.c index ad48e5f..e3c2c64 100644 --- a/kern/interrupt.c +++ b/kern/interrupt.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -274,6 +275,8 @@ void sys_swexn(); */ void sys_enosys(); +void sys_hvcall(); + /** index of first syscall */ #define IDT_SYSCALL_START (X86_PIC_MASTER_IRQ_BASE + 16) @@ -282,7 +285,7 @@ void idt_init() { int i; for (i = 0; i < IDT_SYSCALL_START; i++) { - idt[i] = make_idt((va_t)default_handler, IDT_TYPE_I32, IDT_DPL_KERNEL); + idt[i] = make_idt((va_t)default_handler, IDT_TYPE_T32, IDT_DPL_KERNEL); } idt[IDT_DE] = make_idt((va_t)de_handler, IDT_TYPE_I32, IDT_DPL_KERNEL); @@ -353,6 +356,8 @@ void idt_init() { idt[READFILE_INT] = make_idt((va_t)sys_readfile, IDT_TYPE_T32, IDT_DPL_USER); idt[SWEXN_INT] = make_idt((va_t)sys_swexn, IDT_TYPE_T32, IDT_DPL_USER); + + idt[HV_INT] = make_idt((va_t)sys_hvcall, IDT_TYPE_T32, IDT_DPL_USER); } /** string explanation of fault */ @@ -395,6 +400,8 @@ const static char* reasons[] = {"Division Error", */ static void dump_fault(ureg_t* frame); +static int handle_zfod(ureg_t* frame, thread_t* t); + /** * @brief handle a fault * @param frame ureg registers @@ -403,24 +410,9 @@ void handle_fault(ureg_t* frame) { thread_t* current = get_current(); if (frame->cause == SWEXN_CAUSE_PAGEFAULT && frame->cr2 >= USER_MEM_START) { /* check ZFOD */ - pa_t old_pa; - page_directory_t* pd = - (page_directory_t*)map_phys_page(current->process->cr3, &old_pa); - pde_t* pde = &(*pd)[get_pd_index(frame->cr2)]; - if (*pde != BAD_PDE) { - pa_t pt_pa = get_page_table(*pde); - page_table_t* pt = (page_table_t*)map_phys_page(pt_pa, NULL); - pte_t* pte = &(*pt)[get_pt_index(frame->cr2)]; - if (*pte != BAD_PTE && - ((*pte & (PTE_PRESENT << PTE_P_SHIFT)) == 0)) { - *pte = (*pte | (PTE_PRESENT << PTE_P_SHIFT)); - invlpg(frame->cr2); - memset((void*)(frame->cr2 & PAGE_BASE_MASK), 0, PAGE_SIZE); - map_phys_page(old_pa, NULL); - return; - } + if (handle_zfod(frame, current) == 0) { + return; } - map_phys_page(old_pa, NULL); } if (frame->cs == SEGSEL_KERNEL_CS) { /* recover from accessing user memory */ @@ -481,6 +473,29 @@ kill_thread: kill_current(); } +static int handle_zfod(ureg_t* frame, thread_t* t) { + int result = -1; + process_t* p = t->process; + int old_if = save_clear_if(); + pa_t old_pa; + page_directory_t* pd = (page_directory_t*)map_phys_page(p->cr3, &old_pa); + pde_t* pde = &(*pd)[get_pd_index(frame->cr2)]; + if (*pde != BAD_PDE) { + pa_t pt_pa = get_page_table(*pde); + page_table_t* pt = (page_table_t*)map_phys_page(pt_pa, NULL); + pte_t* pte = &(*pt)[get_pt_index(frame->cr2)]; + if (*pte != BAD_PTE && ((*pte & (PTE_PRESENT << PTE_P_SHIFT)) == 0)) { + *pte = (*pte | (PTE_PRESENT << PTE_P_SHIFT)); + invlpg(frame->cr2); + memset((void*)(frame->cr2 & PAGE_BASE_MASK), 0, PAGE_SIZE); + result = 0; + } + } + map_phys_page(old_pa, NULL); + restore_if(old_if); + return result; +} + static void dump_fault(ureg_t* frame) { sim_printf("Fault: %s Error Code: %08x", reasons[frame->cause], frame->error_code); diff --git a/kern/interrupt_asm.S b/kern/interrupt_asm.S index 99176e4..3941d16 100644 --- a/kern/interrupt_asm.S +++ b/kern/interrupt_asm.S @@ -9,7 +9,7 @@ #include #include -#define SEGSEL_KERNEL_FS SEGSEL_SPARE0 +#define SEGSEL_KERNEL_FS SEGSEL_SPARE2 .global default_handler default_handler: @@ -96,8 +96,6 @@ FAULT_HANDLER_ERR ac 0x11 FAULT_HANDLER_NOERR mc 0x12 FAULT_HANDLER_NOERR xf 0x13 -#define SEGSEL_KERNEL_FS SEGSEL_SPARE0 - .global timer_handler .type timer_handler, %function timer_handler: diff --git a/kern/kernel.c b/kern/kernel.c index e473022..33a7c09 100644 --- a/kern/kernel.c +++ b/kern/kernel.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -62,10 +63,11 @@ int kernel_main(mbinfo_t* mbinfo, int argc, char** argv, char** envp) { idt_init(); mm_init(); timer_init(); + pv_init(); clear_console(); const char* init_args[] = {INIT_NAME}; - thread_t* init = create_process(0, INIT_NAME, 1, init_args); + thread_t* init = create_process(INIT_PID, INIT_NAME, 1, init_args); init_process = init->process; add_thread(init); insert_ready_tail(init); @@ -93,8 +95,7 @@ static void kernel_smp_entry(int cpuid) { static void kernel_smp_main() { const char* idle_args[] = {IDLE_NAME}; - thread_t* idle = create_process(0, IDLE_NAME, 1, idle_args); - add_thread(idle); + thread_t* idle = create_process(IDLE_PID, IDLE_NAME, 1, idle_args); set_idle(idle); while (1) { diff --git a/kern/mm.c b/kern/mm.c index 2c40af8..b553018 100644 --- a/kern/mm.c +++ b/kern/mm.c @@ -6,7 +6,6 @@ * @bug No functional bugs */ - #include #include #include diff --git a/kern/paging.c b/kern/paging.c index 568db84..eb81dd9 100644 --- a/kern/paging.c +++ b/kern/paging.c @@ -62,15 +62,14 @@ void paging_init() { *lapic_pte = (make_pte(lapic_pa, PTE_G, PTE_SUPERVISOR, PTE_RW, PTE_PRESENT) | (PTE_PCD << PTE_PCD_SHIFT)); - invlpg(LAPIC_VIRT_BASE); set_cr4(get_cr4() | CR4_PSE | CR4_PGE); set_cr3((uint32_t)kernel_pd); - set_cr0(get_cr0() | CR0_PE | CR0_PG); + set_cr0(get_cr0() | CR0_PE | CR0_PG | CR0_WP); } void paging_enable() { set_cr4(get_cr4() | CR4_PSE | CR4_PGE); set_cr3((uint32_t)kernel_pd); - set_cr0(get_cr0() | CR0_PE | CR0_PG); + set_cr0(get_cr0() | CR0_PE | CR0_PG | CR0_WP); } diff --git a/kern/pv.c b/kern/pv.c new file mode 100644 index 0000000..77e6920 --- /dev/null +++ b/kern/pv.c @@ -0,0 +1,182 @@ +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static int create_boot_pd(process_t* p, pa_t bootmem, int n_pages); + +void pv_init() { + uint64_t* gdt = (uint64_t*)gdt_base(); + /* copy cs's flags so we do not need to create one */ + uint64_t cs_flags = (gdt[SEGSEL_USER_CS_IDX] & GDT_FLAG_MASK); + /* copy ds's flags so we do not need to create one */ + uint64_t ds_flags = (gdt[SEGSEL_USER_DS_IDX] & GDT_FLAG_MASK); + uint64_t fs_flags = (ds_flags & (~GDT_G_BIT)); + uint64_t base = USER_MEM_START; + uint64_t limit = (PV_VM_LIMIT / PAGE_SIZE) - 1; + gdt[SEGSEL_PV_CS_IDX] = create_segsel(base, limit, cs_flags); + gdt[SEGSEL_PV_DS_IDX] = create_segsel(base, limit, ds_flags); + gdt[SEGSEL_PV_FS_IDX] = create_segsel(base, limit, fs_flags); +} + +static int create_boot_pd(process_t* p, pa_t bootmem, int n_pages) { + pv_pd_t* pv_pd = smalloc(sizeof(pv_pd_t)); + if (pv_pd == NULL) { + goto alloc_pv_pd_fail; + } + pv_pd->refcount = 1; + pv_pd->cr3 = p->cr3; + pv_pd->user_cr3 = p->cr3; + queue_insert_head(&p->pv->shadow_pds, &pv_pd->pv_link); + p->pv->active_shadow_pd = pv_pd; + + int i = 0; + int offset = 0; + va_t m_start = USER_MEM_START; + pa_t pt_pa = find_or_create_pt(p, m_start); + if (pt_pa == BAD_PA) { + goto add_pt_fail; + } + do { + offset = i * PAGE_SIZE; + int pt_index = get_pt_index(m_start + offset); + if (pt_index == 0) { + /* step to next page table */ + pt_pa = find_or_create_pt(p, m_start + offset); + if (pt_pa == BAD_PA) { + goto add_pt_fail; + } + } + int old_if = save_clear_if(); + page_table_t* pt = (page_table_t*)map_phys_page(pt_pa, NULL); + /* do not set P bit for ZFOD */ + (*pt)[pt_index] = make_pte(bootmem + offset, 0, PTE_USER, PTE_RW, 0); + restore_if(old_if); + invlpg(m_start + offset); + } while (++i < n_pages); + return 0; + +add_pt_fail: +alloc_pv_pd_fail: + return -1; +} + +thread_t* create_pv_process(thread_t* t, + simple_elf_t* elf, + char* exe, + va_size_t mem_size) { + process_t* p = t->process; + pv_t* pv = (pv_t*)smalloc(sizeof(pv_t)); + if (pv == NULL) { + goto alloc_pv_fail; + } + pv->shadow_pds = NULL; + pv->vif = 0; + memset(&pv->vidt, 0, sizeof(pv_idt_t)); + p->pv = pv; + + int n_bootmem_pages = mem_size / PAGE_SIZE; + pa_t bootmem = alloc_user_pages(n_bootmem_pages); + if (bootmem == BAD_PA) { + goto alloc_bootmem_fail; + } + if (add_region(p, USER_MEM_START, n_bootmem_pages, bootmem, 1) != 0) { + goto alloc_region_fail; + } + if (create_boot_pd(p, bootmem, n_bootmem_pages) != 0) { + goto create_boot_pd_fail; + } + /* temporarily use new process's cr3 to load elf */ + pa_t old_cr3 = get_current()->process->cr3; + get_current()->process->cr3 = p->cr3; + set_cr3(p->cr3); + + file_t* f = find_file(exe); + + if (elf->e_txtlen != 0) { + if (elf->e_txtstart >= mem_size) { + goto load_elf_fail; + } + read_file(f, elf->e_txtoff, elf->e_txtlen, + (char*)(USER_MEM_START + elf->e_txtstart)); + } + if (elf->e_rodatlen != 0) { + if (elf->e_rodatstart >= mem_size) { + goto load_elf_fail; + } + read_file(f, elf->e_rodatoff, elf->e_rodatlen, + (char*)(USER_MEM_START + elf->e_rodatstart)); + } + if (elf->e_datlen != 0) { + if (elf->e_datstart >= mem_size) { + goto load_elf_fail; + } + read_file(f, elf->e_datoff, elf->e_datlen, + (char*)(USER_MEM_START + elf->e_datstart)); + } + + get_current()->process->cr3 = old_cr3; + set_cr3(old_cr3); + + t->kernel_esp -= sizeof(stack_frame_t); + stack_frame_t* frame = (stack_frame_t*)t->kernel_esp; + frame->eip = (reg_t)elf->e_entry; + frame->cs = SEGSEL_PV_CS; + frame->eflags = DEFAULT_EFLAGS; + frame->esp = 0; + frame->ss = SEGSEL_PV_DS; + frame->eax = GUEST_LAUNCH_EAX; + frame->ecx = PV_VM_LIMIT - 1; + frame->edx = 0; + frame->ebx = n_bootmem_pages - 1; + frame->ebp = 0; + frame->esi = 0; + frame->edi = 0; + frame->ds = SEGSEL_PV_DS; + frame->es = SEGSEL_PV_DS; + frame->fs = SEGSEL_PV_FS; + frame->gs = SEGSEL_PV_DS; + + t->kernel_esp -= sizeof(yield_frame_t); + yield_frame_t* yf = (yield_frame_t*)t->kernel_esp; + yf->eflags = DEFAULT_EFLAGS; + yf->raddr = (reg_t)return_to_user; + return t; + +load_elf_fail: + get_current()->process->cr3 = old_cr3; + set_cr3(old_cr3); +create_boot_pd_fail: + vector_pop(&p->regions); +alloc_region_fail: + free_user_pages(bootmem, n_bootmem_pages); +alloc_bootmem_fail: +alloc_pv_fail: + destroy_thread(t); + return NULL; +} + +void destroy_pv(pv_t* pv) { + if (pv->shadow_pds != NULL) { + queue_t* node = pv->shadow_pds; + queue_t* end = node; + do { + pv_pd_t* shadow_pd = queue_data(node, pv_pd_t, pv_link); + destroy_pd(shadow_pd->cr3); + if (shadow_pd->user_cr3 != shadow_pd->cr3) { + destroy_pd(shadow_pd->user_cr3); + } + node = node->next; + sfree(shadow_pd, sizeof(pv_pd_t)); + } while (node != end); + } + sfree(pv, sizeof(pv_t)); +} diff --git a/kern/sched.c b/kern/sched.c index eb8d334..7f7dc75 100644 --- a/kern/sched.c +++ b/kern/sched.c @@ -6,6 +6,7 @@ * @bug No functional bugs */ +#include #include #include #include @@ -59,26 +60,15 @@ queue_t* ready = NULL; rb_t* threads = &rb_nil; mutex_t threads_lock = MUTEX_INIT; -/* G means global segment */ -#define GDT_G_BIT 0x0080000000000000ull -/* FLAG is control flags for segment */ -#define GDT_FLAG_MASK 0x00f0ff0000000000ull -/* high part of base address */ -#define GDT_BASE_MASK_HI 0xff000000ull -/* low part of base address */ -#define GDT_BASE_MASK_LO 0x00ffffffull -/* position of high part of base address */ -#define GDT_BASE_SHIFT_HI (64 - 32) -/* position of low part of base address */ -#define GDT_BASE_SHIFT_LO (40 - 24) -/* high part of limit */ -#define GDT_LIMIT_MASK_HI 0xf0000ull -/* low part of limit */ -#define GDT_LIMIT_MASK_LO 0x0ffffull -/* position of high part of limit */ -#define GDT_LIMIT_SHIFT_HI (52 - 20) -/* position of low part of limit */ -#define GDT_LIMIT_SHIFT_LO (16 - 16) +uint64_t create_segsel(va_t base, va_size_t limit, uint64_t flags) { + uint64_t b = (uint64_t)base; + uint64_t l = (uint64_t)limit; + uint64_t ss = (((b & GDT_BASE_MASK_HI) << GDT_BASE_SHIFT_HI) | + ((b & GDT_BASE_MASK_LO) << GDT_BASE_SHIFT_LO) | + ((l & GDT_LIMIT_MASK_HI) << GDT_LIMIT_SHIFT_HI) | + ((l & GDT_LIMIT_MASK_LO) << GDT_LIMIT_SHIFT_LO) | flags); + return ss; +} /** * @brief set fs @@ -90,16 +80,9 @@ void setup_percpu(percpu_t* percpu) { uint64_t* gdt = (uint64_t*)gdt_base(); uint64_t ds = gdt[SEGSEL_KERNEL_DS_IDX]; /* copy ds's flags so we do not need to create one */ - uint64_t ds_flags = (ds & GDT_FLAG_MASK); - uint64_t base = (uint64_t)(uint32_t)percpu; - uint64_t limit = base + sizeof(percpu_t) - 1; - uint64_t fs = (((base & GDT_BASE_MASK_HI) << GDT_BASE_SHIFT_HI) | - ((base & GDT_BASE_MASK_LO) << GDT_BASE_SHIFT_LO) | - ((limit & GDT_LIMIT_MASK_HI) << GDT_LIMIT_SHIFT_HI) | - ((limit & GDT_LIMIT_MASK_LO) << GDT_LIMIT_SHIFT_LO) | - (ds_flags & (~GDT_G_BIT))); - gdt[SEGSEL_KERNEL_FS_IDX] = fs; - lgdt(gdt, GDT_SEGS * sizeof(uint64_t) - 1); + uint64_t ds_flags = (ds & GDT_FLAG_MASK & (~GDT_G_BIT)); + gdt[SEGSEL_KERNEL_FS_IDX] = + create_segsel((va_t)percpu, sizeof(percpu_t) - 1, ds_flags); set_fs(SEGSEL_KERNEL_FS); } @@ -160,6 +143,7 @@ thread_t* create_empty_process() { } restore_if(old_if); p->mm_lock = MUTEX_INIT; + p->pv = NULL; t->status = THREAD_DEAD; t->status_lock = SPL_INIT; @@ -247,14 +231,32 @@ thread_t* create_process(int tid, char* exe, int argc, const char** argv) { } t->process->pid = t->rb_node.key = ((tid == 0) ? alloc_tid() : tid); + simple_elf_t elf; + if (elf_load_helper(&elf, exe) != ELF_SUCCESS) { + goto open_elf_fail; + } + + if (elf.e_entry < USER_MEM_START) { + va_size_t mem_size = PV_DEFAULT_SIZE; + if (argc > 2) { + goto too_many_args_for_pv; + } + if (argc > 1) { + mem_size = (va_size_t)strtoul(argv[1], NULL, 10); + if (mem_size < PV_MINIMUM_SIZE || mem_size == ULONG_MAX) { + goto bad_mem_size_for_pv; + } + } + mem_size <<= 20; + return create_pv_process(t, &elf, exe, mem_size); + } + /* temporarily use new process's cr3 to load elf */ - reg_t old_cr3 = get_current()->process->cr3; + pa_t old_cr3 = get_current()->process->cr3; get_current()->process->cr3 = t->process->cr3; set_cr3(t->process->cr3); - simple_elf_t elf; - if (elf_load_helper(&elf, exe) != ELF_SUCCESS || - process_load_elf(t->process, &elf, exe) != 0) { + if (process_load_elf(t->process, &elf, exe) != 0) { goto load_elf_fail; } @@ -323,6 +325,9 @@ alloc_argc_addr_fail: load_elf_fail: get_current()->process->cr3 = old_cr3; set_cr3(old_cr3); +bad_mem_size_for_pv: +too_many_args_for_pv: +open_elf_fail: destroy_thread(t); alloc_tcb_fail: return NULL; @@ -346,22 +351,30 @@ void destroy_thread(thread_t* t) { free_user_pages(r->paddr, r->size / PAGE_SIZE); } vector_free(&p->regions); + if (p->pv == NULL) { + destroy_pd(p->cr3); + } else { + destroy_pv(p->pv); + } + sfree(p, sizeof(process_t)); +} +void destroy_pd(pa_t pd_pa) { + int i; int old_if = save_clear_if(); for (i = USER_PD_START; i < NUM_PAGE_ENTRY; i++) { - page_directory_t* pd = (page_directory_t*)map_phys_page(p->cr3, NULL); + page_directory_t* pd = (page_directory_t*)map_phys_page(pd_pa, NULL); if ((*pd)[i] != BAD_PDE) { pa_t pt = get_page_table((*pd)[i]); free_user_pages(pt, 1); } } restore_if(old_if); - free_user_pages(p->cr3, 1); - sfree(p, sizeof(process_t)); + free_user_pages(pd_pa, 1); } int alloc_tid() { - static int tid = 1; + static int tid = IDLE_PID + 1; static int next_check = (1 << 31); if (tid == next_check) { /* allocated all pids */ @@ -370,7 +383,7 @@ int alloc_tid() { p = rb_min(threads); if (p == &rb_nil) { /* no pid inuse */ - tid = 1; + tid = IDLE_PID + 1; next_check = (1 << 31); } else { while (1) { @@ -419,7 +432,6 @@ static int load_segment(process_t* p, goto add_region_fail; } - int rw = (is_rw ? PTE_RW : PTE_RO); int i = 0; int offset = 0; /* file page table one entry per loop */ @@ -441,7 +453,7 @@ static int load_segment(process_t* p, int old_if = save_clear_if(); page_table_t* pt = (page_table_t*)map_phys_page(pt_pa, NULL); /* do not set P bit for ZFOD */ - (*pt)[pt_index] = make_pte(paddr + offset, 0, PTE_USER, rw, 0); + (*pt)[pt_index] = make_pte(paddr + offset, 0, PTE_USER, PTE_RW, 0); restore_if(old_if); invlpg(m_start + offset); } while (++i < n_pages); @@ -449,6 +461,31 @@ static int load_segment(process_t* p, if (f != NULL) { read_file(f, f_off, f_len, (char*)m_off); } + if (is_rw == 0) { + i = 0; + pa_t pt_pa = find_or_create_pt(p, m_start); + if (pt_pa == BAD_PA) { + goto add_pt_fail; + } + do { + offset = i * PAGE_SIZE; + int pt_index = get_pt_index(m_start + offset); + if (pt_index == 0) { + /* step to next page table */ + pt_pa = find_or_create_pt(p, m_start + offset); + if (pt_pa == BAD_PA) { + goto add_pt_fail; + } + } + + int old_if = save_clear_if(); + page_table_t* pt = (page_table_t*)map_phys_page(pt_pa, NULL); + pte_t* pte = &(*pt)[pt_index]; + *pte = ((*pte) & (~(PTE_RW << PTE_RW_SHIFT))); + restore_if(old_if); + invlpg(m_start + offset); + } while (++i < n_pages); + } return 0; add_pt_fail: @@ -556,12 +593,15 @@ void swap_process_inplace(thread_t* newt) { pa_t cr3 = oldp->cr3; vector_t regions = oldp->regions; queue_t* p_threads = oldp->threads; + pv_t* pv = oldp->pv; oldp->cr3 = newp->cr3; oldp->regions = newp->regions; oldp->threads = newp->threads; + oldp->pv = newp->pv; newp->cr3 = cr3; newp->regions = regions; newp->threads = p_threads; + newp->pv = pv; newt->process = oldp; oldt->process = newp; set_cr3(newp->cr3); @@ -593,18 +633,7 @@ void kill_current() { thread_t* current = get_current(); process_t* p = current->process; /* respawn important process */ - if (current == get_idle()) { - if (p->refcount == 1) { - const char* idle_args[] = {IDLE_NAME}; - thread_t* new_idle = - create_process(current->rb_node.key, IDLE_NAME, 1, idle_args); - if (new_idle == NULL) { - panic("no space to allocate idle process"); - } - swap_process_inplace(new_idle); - set_idle(new_idle); - } - } else if (p == init_process) { + if (p == init_process) { if (p->refcount == 1) { mutex_lock(&p->wait_lock); /* reclaim dead childs */ @@ -674,18 +703,11 @@ void kill_current() { free_user_pages(r->paddr, r->size / PAGE_SIZE); } vector_free(&p->regions); - - int old_if = save_clear_if(); - for (i = USER_PD_START; i < NUM_PAGE_ENTRY; i++) { - page_directory_t* pd = - (page_directory_t*)map_phys_page(old_cr3, NULL); - if ((*pd)[i] != BAD_PDE) { - pa_t pt = get_page_table((*pd)[i]); - free_user_pages(pt, 1); - } + if (p->pv == NULL) { + destroy_pd(old_cr3); + } else { + destroy_pv(p->pv); } - restore_if(old_if); - free_user_pages(old_cr3, 1); } /* make sure we do not get swapped out before borrowing kthread's stack */ diff --git a/kern/syscall_asm.S b/kern/syscall_asm.S index 050788a..6bb2b8d 100644 --- a/kern/syscall_asm.S +++ b/kern/syscall_asm.S @@ -9,7 +9,7 @@ #include #include -#define SEGSEL_KERNEL_FS SEGSEL_SPARE0 +#define SEGSEL_KERNEL_FS SEGSEL_SPARE2 .macro SYSCALL name .global sys_\name @@ -27,6 +27,11 @@ sys_\name: mov %ax, %fs cld push %esp + call handle_pv_syscall + add $0x4, %esp + test %eax, %eax + jne return_to_user + push %esp call sys_\name\()_real add $0x4, %esp jmp return_to_user /* check pending exit before iret */ @@ -59,3 +64,22 @@ SYSCALL readfile SYSCALL swexn SYSCALL enosys + +.global sys_hvcall +.type sys_hvcall, %function +sys_hvcall: + pusha /* save a stack_frame_t structure */ + push %ds + push %es + push %fs + push %gs + mov $SEGSEL_KERNEL_DS, %eax + mov %ax, %ds + mov %ax, %es + mov $SEGSEL_KERNEL_FS, %eax + mov %ax, %fs + cld + push %esp + call sys_hvcall_real + add $0x4, %esp + jmp return_to_user /* check pending exit before iret */ diff --git a/kern/syscall_hvcall.c b/kern/syscall_hvcall.c new file mode 100644 index 0000000..18ef741 --- /dev/null +++ b/kern/syscall_hvcall.c @@ -0,0 +1,66 @@ +/** @file syscall_hvcall.c + * + * @brief miscellaneous syscalls. + * + * @author Hanjie Wu (hanjiew) + * @bug No functional bugs + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 0: not pv, 1: processed +int handle_pv_syscall(stack_frame_t* f) { + if (get_current()->process->pv == NULL) { + return 0; + } + if (f->eip >= USER_MEM_START) { + // inject interrupt + return 1; + } + // kernel called syscall + return 1; +} + +void sys_hvcall_real(stack_frame_t* f) { + if (get_current()->process->pv == NULL) { + f->eax = (reg_t)-1; + return; + } + if (f->eip >= USER_MEM_START) { + // inject interrupt + return; + } + switch (f->eax) { + case HV_MAGIC_OP: + f->eax = (reg_t)HV_MAGIC; + break; + default: + f->eax = (reg_t)-1; + break; + } +} diff --git a/kern/timer.c b/kern/timer.c index 7f39f06..e857b51 100644 --- a/kern/timer.c +++ b/kern/timer.c @@ -29,7 +29,7 @@ heap_t timers; /* we want a 2ms thread switch but since sometimes interrupts are disabled, we * set a higher rate to compensate this */ -#define TIMER_FREQ 1000 +#define TIMER_FREQ 1 void timer_init() { int counter = TIMER_RATE / TIMER_FREQ; diff --git a/kern/usermem.c b/kern/usermem.c index 717cdbe..ae48833 100644 --- a/kern/usermem.c +++ b/kern/usermem.c @@ -58,10 +58,6 @@ static void usermem_finish(reg_t old_eip0) { } int copy_from_user(va_t addr, int size, void* buf) { - va_t end = addr + size; - if (addr < USER_MEM_START || end < addr || end >= DEFAULT_STACK_END) { - return -1; - } reg_t old_eip0 = usermem_setup(); int i, result = 0; for (i = 0; i < size; i++) { @@ -75,10 +71,6 @@ int copy_from_user(va_t addr, int size, void* buf) { } int copy_to_user(va_t addr, int size, void* buf) { - va_t end = addr + size; - if (addr < USER_MEM_START || end < addr || end >= DEFAULT_STACK_END) { - return -1; - } reg_t old_eip0 = usermem_setup(); int i, result = 0; for (i = 0; i < size; i++) { @@ -92,12 +84,6 @@ int copy_to_user(va_t addr, int size, void* buf) { } char* copy_string_from_user(va_t addr, int maxlen) { - if (addr < USER_MEM_START || addr >= DEFAULT_STACK_END) { - return NULL; - } - if (DEFAULT_STACK_END - addr < maxlen) { - maxlen = DEFAULT_STACK_END - addr; - } reg_t old_eip0 = usermem_setup(); int len = 0, buflen = 3 * sizeof(int); char* buf = malloc(buflen); @@ -134,10 +120,6 @@ read_string_finished: } int print_buf_from_user(va_t addr, int len) { - va_t end = addr + len; - if (addr < USER_MEM_START || end < addr || end >= DEFAULT_STACK_END) { - return -1; - } reg_t old_eip0 = usermem_setup(); int i, result = 0; char c; diff --git a/kern/usermem_asm.S b/kern/usermem_asm.S index 0eee6f8..5a5483b 100644 --- a/kern/usermem_asm.S +++ b/kern/usermem_asm.S @@ -13,7 +13,7 @@ try_read: mov 0x4(%esp), %eax mov 0x8(%esp), %esi - mov (%eax), %al + mov %gs:(%eax), %al mov %al, (%esi) xor %eax, %eax ret @@ -23,7 +23,7 @@ try_read: try_write: mov 0x4(%esp), %eax mov 0x8(%esp), %edx - mov %dl, (%eax) + mov %dl, %gs:(%eax) xor %eax, %eax ret -- cgit