diff options
| author | Hanjie Wu <hanjiew@andrew.cmu.edu> | 2023-04-23 01:51:51 -0400 |
|---|---|---|
| committer | Hanjie Wu <hanjiew@andrew.cmu.edu> | 2023-04-23 01:51:51 -0400 |
| commit | aeb97c4547e79f6875eb641d2420b89ade8c5337 (patch) | |
| tree | 5e5e1cc7a04304638d5fc5ca3eb20aaefec104da | |
| parent | a7e1cbd3cb53bd4fb43a52a806fd50ab6fa24a24 (diff) | |
pending irq
| -rw-r--r-- | kern/hvcall.c | 40 | ||||
| -rw-r--r-- | kern/inc/pv.h | 12 | ||||
| -rw-r--r-- | kern/kbd.c | 68 | ||||
| -rw-r--r-- | kern/pv.c | 70 | ||||
| -rw-r--r-- | kern/sched.c | 7 | ||||
| -rw-r--r-- | kern/sched_asm.S | 2 | ||||
| -rw-r--r-- | kern/timer.c | 4 |
7 files changed, 145 insertions, 58 deletions
diff --git a/kern/hvcall.c b/kern/hvcall.c index 1513942..d8dfeed 100644 --- a/kern/hvcall.c +++ b/kern/hvcall.c @@ -36,6 +36,7 @@ #define HV_REFPD_OP HV_RESERVED_0 #define HV_UNREFPD_OP HV_RESERVED_1 +#define HV_LOADPD_OP HV_RESERVED_2 static void hvcall_exit(stack_frame_t* f); static void hvcall_iret(stack_frame_t* f); @@ -49,6 +50,7 @@ static void hvcall_get_cursor(stack_frame_t* f); static void hvcall_print_at(stack_frame_t* f); static void hvcall_refpd(int ref); +static void hvcall_loadpd(stack_frame_t* f); // 0: not pv, 1: processed int handle_pv_syscall(stack_frame_t* f, int index) { @@ -114,6 +116,9 @@ void sys_hvcall_real(stack_frame_t* f) { case HV_UNREFPD_OP: hvcall_refpd(0); break; + case HV_LOADPD_OP: + hvcall_loadpd(f); + break; default: pv_die("Bad hvcall number"); break; @@ -223,7 +228,7 @@ static void hvcall_setpd(stack_frame_t* f) { goto alloc_pd_fail; } queue_insert_head(&pv->shadow_pds, &pv_pd->pv_link); - select_pv_pd(t->process, pv_pd); + pv_select_pd(t->process, pv_pd); return; alloc_pd_fail: @@ -662,13 +667,38 @@ read_arg_fail: } static void hvcall_refpd(int ref) { - pv_t* pv = get_current()->process->pv; + pv_pd_t* pv_pd = get_current()->process->pv->active_shadow_pd; if (ref == 1) { - pv->active_shadow_pd->refcount++; + pv_pd->refcount++; } else { - pv->active_shadow_pd->refcount--; - if (pv->active_shadow_pd->refcount <= 0) { + pv_pd->refcount--; + if (pv_pd->refcount <= 0) { pv_die("Page table destroyed by kerenl"); } } } + +static void hvcall_loadpd(stack_frame_t* f) { + reg_t esp = f->esp; + pa_t pd; + if (copy_from_user(esp, sizeof(pa_t), &pd) != 0) { + goto read_arg_fail; + } + process_t* p = get_current()->process; + pv_t* pv = p->pv; + queue_t* node = pv->shadow_pds; + queue_t* end = node; + do { + pv_pd_t* pv_pd = queue_data(node, pv_pd_t, pv_link); + if (pv_pd->guest_pd == pd + USER_MEM_START) { + pv_select_pd(p, pv_pd); + return; + } + node = node->next; + sfree(pv_pd, sizeof(pv_pd_t)); + } while (node != end); + pv_die("Loading a nonexist page table"); + +read_arg_fail: + pv_die("Bad argument address"); +} diff --git a/kern/inc/pv.h b/kern/inc/pv.h index 550446c..eeecd47 100644 --- a/kern/inc/pv.h +++ b/kern/inc/pv.h @@ -46,6 +46,11 @@ typedef struct pv_idt_entry_s { int desc; } pv_idt_entry_t; +typedef struct pv_irq_s { + int pending; + int arg; +} pv_irq_t; + #define PV_FAULT_START 0 #define PV_FAULT_END 20 #define PV_IRQ_START 32 @@ -58,6 +63,7 @@ typedef struct pv_idt_entry_s { typedef struct pv_idt_s { pv_idt_entry_t fault[PV_FAULT_END - PV_FAULT_START]; pv_idt_entry_t irq[PV_IRQ_END - PV_IRQ_START]; + pv_irq_t pending_irq[PV_IRQ_END - PV_IRQ_START]; pv_idt_entry_t syscall_1[PV_SYSCALL_1_END - PV_SYSCALL_1_START]; pv_idt_entry_t syscall_2[PV_SYSCALL_2_END - PV_SYSCALL_2_START]; } pv_idt_t; @@ -114,13 +120,15 @@ void pv_die(char* reason); void pv_switch_mode(process_t* p, int kernelmode); -void select_pv_pd(process_t* p, pv_pd_t* pv_pd); +void pv_select_pd(process_t* p, pv_pd_t* pv_pd); void pv_handle_fault(ureg_t* frame, thread_t* t); struct stack_frame_s; typedef struct stack_frame_s stack_frame_t; -int pv_inject_interrupt(stack_frame_t* f, int index, int arg); +int pv_inject_irq(stack_frame_t* f, int index, int arg); + +void pv_check_pending_irq(stack_frame_t* f); typedef struct pv_frame_s { reg_t cr2; @@ -19,6 +19,7 @@ #include <interrupt.h> #include <kbd.h> #include <paging.h> +#include <pv.h> #include <sync.h> #include <usermem.h> @@ -30,7 +31,7 @@ typedef struct kbd_request_s { /** size of scancode ring buffer, a big buffer enough for someone pressing * keyboard fast */ -#define SC_RING_SIZE PAGE_SIZE +#define KH_RING_SIZE PAGE_SIZE /** size of character ring buffer, a big buffer enough for someone pressing * keyboard fast */ #define CHR_RING_SIZE PAGE_SIZE @@ -49,15 +50,13 @@ static cv_t kbd_request_cv = CV_INIT; static mutex_t input_lock = MUTEX_INIT; /** signal for new scancode input */ static cv_t input_cv = CV_INIT; -/** need pic acknowlege */ -static int need_ack = 0; -/** scancode ring buffer */ -static unsigned char sc_ring[SC_RING_SIZE]; -/** read pointer of scancode ring buffer */ -static int sc_r_pos = 0; -/** write pointer of scancode ring buffer */ -static int sc_w_pos = 0; +/** augchar buffer */ +static unsigned char kh_ring[KH_RING_SIZE]; +/** read pointer of augchar ring buffer */ +static int kh_r_pos = 0; +/** write pointer of augchar ring buffer */ +static int kh_w_pos = 0; /** character ring buffer */ static char chr_ring[CHR_RING_SIZE]; @@ -71,14 +70,17 @@ static int chr_w_pos = 0; */ void kbd_handler_real(stack_frame_t* f) { unsigned char sc = inb(KEYBOARD_PORT); - int next_w_pos = (sc_w_pos + 1) % SC_RING_SIZE; - if (next_w_pos != sc_r_pos) { - sc_ring[sc_w_pos] = sc; - sc_w_pos = next_w_pos; - pic_acknowledge(KBD_IRQ); - } else { - /* let processing thread ack after processing scancode */ - need_ack = 1; + pic_acknowledge(KBD_IRQ); + kh_type kh = process_scancode(sc); + if (pv_inject_irq(f, KEY_IDT_ENTRY, kh) == 0) { + return; + } + if (KH_HASDATA(kh) && KH_ISMAKE(kh)) { + int next_w_pos = (kh_w_pos + 1) % KH_RING_SIZE; + if (next_w_pos != kh_r_pos) { + kh_ring[kh_w_pos] = kh; + kh_w_pos = next_w_pos; + } } cv_signal(&input_cv); } @@ -185,14 +187,21 @@ static int flush_line(int len, va_t buf) { if (size > len) { size = len; } - for (i = 0; i < size; i++) { - if (copy_to_user(buf + i, 1, - &chr_ring[(chr_r_pos + i) % CHR_RING_SIZE]) != 0) { - /* failed to flush, do not discard anything */ + int end_pos = (chr_r_pos + size) % CHR_RING_SIZE; + if (end_pos > chr_r_pos) { + if (copy_to_user(buf, size, &chr_ring[chr_r_pos]) != 0) { + return -1; + } + } else { + int size_1 = (CHR_RING_SIZE - chr_r_pos); + if (copy_to_user(buf, size_1, &chr_ring[chr_r_pos]) != 0) { + return -1; + } + if (copy_to_user(buf + size_1, end_pos, &chr_ring[0]) != 0) { return -1; } } - chr_r_pos = (chr_r_pos + i) % CHR_RING_SIZE; + chr_r_pos = end_pos; return size; } @@ -200,19 +209,12 @@ static int sc_process() { while (1) { /* wait for more scancode */ mutex_lock(&input_lock); - while (sc_r_pos == sc_w_pos) { + while (kh_r_pos == kh_w_pos) { cv_wait(&input_cv, &input_lock); } - int sc = sc_ring[sc_r_pos]; - sc_r_pos = (sc_r_pos + 1) % SC_RING_SIZE; + kh_type kh = kh_ring[kh_r_pos]; + kh_r_pos = (kh_r_pos + 1) % KH_RING_SIZE; mutex_unlock(&input_lock); - if (need_ack == 1) { - need_ack = 0; - pic_acknowledge(KBD_IRQ); - } - kh_type kh = process_scancode(sc); - if (KH_HASDATA(kh) && KH_ISMAKE(kh)) { - return KH_GETCHAR(kh); - } + return KH_GETCHAR(kh); } } @@ -204,7 +204,7 @@ void pv_switch_mode(process_t* p, int kernelmode) { set_cr3(target_cr3); } -void select_pv_pd(process_t* p, pv_pd_t* pv_pd) { +void pv_select_pd(process_t* p, pv_pd_t* pv_pd) { pv_t* pv = p->pv; pv_pd_t* old_pv_pd = pv->active_shadow_pd; pv->active_shadow_pd = pv_pd; @@ -270,16 +270,11 @@ no_idt_handler: pv_die("No interrupt handler installed"); } -int pv_inject_interrupt(stack_frame_t* f, int index, int arg) { - thread_t* t = get_current(); - pv_t* pv = t->process->pv; - if (pv == NULL || (pv->vif & EFL_IF) == 0 || f->cs != SEGSEL_PV_CS) { - return -1; - } - pv_idt_entry_t* idt = pv_classify_interrupt(pv, index); - if (idt == NULL) { - goto no_idt_handler; - } +static inline void do_inject_irq(thread_t* t, + pv_t* pv, + stack_frame_t* f, + int arg, + va_t eip) { reg_t new_esp; pv_frame_t pv_f; pv_f.cr2 = 0; @@ -309,13 +304,62 @@ int pv_inject_interrupt(stack_frame_t* f, int index, int arg) { goto push_frame_fail; } } - f->eip = idt->eip; + pv_mask_interrupt(pv); + f->eip = eip; f->esp = new_esp; - return 0; + return; push_frame_fail: pv_die("Error when pushing interrupt frame to stack"); +} + +int pv_inject_irq(stack_frame_t* f, int index, int arg) { + thread_t* t = get_current(); + pv_t* pv = t->process->pv; + if (pv == NULL) { + return -1; + } + if (f->cs != SEGSEL_PV_CS || (pv->vif & EFL_IF) == 0) { + pv_irq_t* irq = &pv->vidt.pending_irq[index - PV_IRQ_START]; + irq->pending = 1; + irq->arg = arg; + return 0; + } + pv_idt_entry_t* idt = &pv->vidt.irq[index - PV_IRQ_START]; + if (idt->eip == 0) { + goto no_idt_handler; + } + do_inject_irq(t, pv, f, arg, idt->eip); + return 0; + no_idt_handler: pv_die("No interrupt handler installed"); return -1; } + +void pv_check_pending_irq(stack_frame_t* f) { + thread_t* t = get_current(); + pv_t* pv = t->process->pv; + if (pv == NULL || f->cs != SEGSEL_PV_CS || (pv->vif & EFL_IF) == 0) { + return; + } + pv_idt_t* vidt = &pv->vidt; + int old_if = save_clear_if(); + int i; + for (i = 0; i < (PV_IRQ_END - PV_IRQ_START); i++) { + if (vidt->pending_irq[i].pending != 0) { + if (vidt->irq[i].eip == 0) { + goto no_idt_handler; + } + do_inject_irq(t, pv, f, vidt->pending_irq[i].arg, vidt->irq[i].eip); + vidt->pending_irq[i].pending = 0; + restore_if(old_if); + return; + } + } + restore_if(old_if); + return; + +no_idt_handler: + pv_die("No interrupt handler installed"); +} diff --git a/kern/sched.c b/kern/sched.c index 7882361..b0fd584 100644 --- a/kern/sched.c +++ b/kern/sched.c @@ -19,6 +19,7 @@ #include <malloc.h> #include <mm.h> #include <paging.h> +#include <pv.h> #include <sched.h> #include <sync.h> @@ -748,13 +749,15 @@ void cleanup_dead_thread(thread_t* t) { * @brief check if a task_vanish is pending and if so, do vanish * @param f saved regs */ -void check_pending_exit(stack_frame_t* f) { +void check_pending_signals(stack_frame_t* f) { /* only vanish before returning to userspace, otherwise some kernel * structure may be jammed */ - if (get_current()->pending_exit != 0 && f->cs == SEGSEL_USER_CS) { + thread_t* t = get_current(); + if (t->pending_exit != 0 && f->cs == SEGSEL_USER_CS) { kill_current(); } + pv_check_pending_irq(f); } thread_t* find_thread(int tid) { diff --git a/kern/sched_asm.S b/kern/sched_asm.S index 7bf8e3b..7a994f5 100644 --- a/kern/sched_asm.S +++ b/kern/sched_asm.S @@ -49,7 +49,7 @@ PERCPU_GETSET mapped_phys_page_pte 0x10 .type return_to_user, %function return_to_user: push %esp - call check_pending_exit + call check_pending_signals add $0x4, %esp pop %gs /* restore from stack_frame_t structure */ pop %fs diff --git a/kern/timer.c b/kern/timer.c index b863c75..a202cb5 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 1 +#define TIMER_FREQ 1000 void timer_init() { int counter = TIMER_RATE / TIMER_FREQ; @@ -64,7 +64,7 @@ void timer_handler_real(stack_frame_t* f) { pic_acknowledge(TIMER_IRQ); ticks++; check_timers(); - pv_inject_interrupt(f, TIMER_IDT_ENTRY, 0); + pv_inject_irq(f, TIMER_IDT_ENTRY, 0); int old_if = spl_lock(&ready_lock); thread_t* current = get_current(); if (current != get_idle()) { |
