summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHanjie Wu <hanjiew@andrew.cmu.edu>2023-04-21 01:09:03 -0400
committerHanjie Wu <hanjiew@andrew.cmu.edu>2023-04-21 01:09:03 -0400
commited4192548143468362124ee7ee6105c001fe29c0 (patch)
treecb5e3c1e2ad8b47992b399fa9499f514702660b2
parentc71294cdd3581c3738d24ffd65414f8644a1094d (diff)
WP
-rw-r--r--.clang-format148
-rw-r--r--config.mk4
-rw-r--r--kern/inc/pv.h63
-rw-r--r--kern/inc/sched.h35
-rw-r--r--kern/interrupt.c51
-rw-r--r--kern/interrupt_asm.S4
-rw-r--r--kern/kernel.c7
-rw-r--r--kern/mm.c1
-rw-r--r--kern/paging.c5
-rw-r--r--kern/pv.c182
-rw-r--r--kern/sched.c150
-rw-r--r--kern/syscall_asm.S26
-rw-r--r--kern/syscall_hvcall.c66
-rw-r--r--kern/timer.c2
-rw-r--r--kern/usermem.c18
-rw-r--r--kern/usermem_asm.S4
16 files changed, 649 insertions, 117 deletions
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: '^<ext/.*\.h>'
+ 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 <common_kern.h>
+#include <elf/elf_410.h>
+#include <x86/idt.h>
+#include <x86/seg.h>
+
+#include <common.h>
+#include <loader.h>
+#include <paging.h>
+
+#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 <common.h>
#include <paging.h>
+#include <pv.h>
#include <sync.h>
/** 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 <x86/seg.h>
#include <x86/timer_defines.h>
+#include <hvcall_int.h>
#include <keyhelp.h>
#include <simics.h>
#include <stdio.h>
@@ -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 <x86/seg.h>
#include <x86/interrupt_defines.h>
-#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 <interrupt.h>
#include <mm.h>
#include <paging.h>
+#include <pv.h>
#include <sched.h>
#include <timer.h>
@@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
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 <string.h>
+
+#include <hvcall.h>
+#include <x86/asm.h>
+#include <x86/cr.h>
+
+#include <asm_instr.h>
+#include <loader.h>
+#include <mm.h>
+#include <paging.h>
+#include <pv.h>
+#include <sched.h>
+
+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 <limits.h>
#include <malloc_internal.h>
#include <string.h>
#include <x86/asm.h>
@@ -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 <simics.h>
#include <x86/seg.h>
-#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 <simics.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <common_kern.h>
+#include <elf/elf_410.h>
+#include <hvcall.h>
+#include <hvcall_int.h>
+#include <malloc_internal.h>
+#include <ureg.h>
+
+#include <x86/asm.h>
+#include <x86/cr.h>
+#include <x86/eflags.h>
+#include <x86/seg.h>
+
+#include <asm_instr.h>
+#include <assert.h>
+#include <loader.h>
+#include <malloc.h>
+#include <mm.h>
+#include <paging.h>
+#include <sched.h>
+#include <sync.h>
+#include <timer.h>
+#include <usermem.h>
+
+// 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