summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHanjie Wu <hanjiew@andrew.cmu.edu>2023-04-23 01:51:51 -0400
committerHanjie Wu <hanjiew@andrew.cmu.edu>2023-04-23 01:51:51 -0400
commitaeb97c4547e79f6875eb641d2420b89ade8c5337 (patch)
tree5e5e1cc7a04304638d5fc5ca3eb20aaefec104da
parenta7e1cbd3cb53bd4fb43a52a806fd50ab6fa24a24 (diff)
pending irq
-rw-r--r--kern/hvcall.c40
-rw-r--r--kern/inc/pv.h12
-rw-r--r--kern/kbd.c68
-rw-r--r--kern/pv.c70
-rw-r--r--kern/sched.c7
-rw-r--r--kern/sched_asm.S2
-rw-r--r--kern/timer.c4
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;
diff --git a/kern/kbd.c b/kern/kbd.c
index ab359be..d933293 100644
--- a/kern/kbd.c
+++ b/kern/kbd.c
@@ -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);
}
}
diff --git a/kern/pv.c b/kern/pv.c
index c2c3d23..02b0ae9 100644
--- a/kern/pv.c
+++ b/kern/pv.c
@@ -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()) {