summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHanjie Wu <hanjiew@andrew.cmu.edu>2023-04-24 03:51:54 -0400
committerHanjie Wu <hanjiew@andrew.cmu.edu>2023-04-24 03:55:02 -0400
commit6b13d5d9b1ff1cb38bb50e918e51a241a225f8da (patch)
tree90e8e5da37402975d769184aeb4b51fa13b610f3
parente021b8f12ad129c0bdbda3111bb93a170e21ae41 (diff)
timer
-rw-r--r--config.mk2
-rw-r--r--kern/hvcall.c10
-rw-r--r--kern/inc/interrupt.h54
-rw-r--r--kern/inc/paging.h3
-rw-r--r--kern/inc/timer.h2
-rw-r--r--kern/interrupt.c50
-rw-r--r--kern/kernel.c11
-rw-r--r--kern/paging.c2
-rw-r--r--kern/pts.c1
-rw-r--r--kern/sched.c1
-rw-r--r--kern/timer.c44
-rw-r--r--kern/timer_asm.S18
12 files changed, 133 insertions, 65 deletions
diff --git a/config.mk b/config.mk
index 222453b..a7cf3b7 100644
--- a/config.mk
+++ b/config.mk
@@ -165,7 +165,7 @@ KERNEL_OBJS = pts.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 pv.o hvcall.o toad.o
+ usermem_asm.o syscall_misc.o pv.o hvcall.o toad.o timer_asm.o
###########################################################################
# WARNING: Do not put **test** programs into the REQPROGS variables. Your
diff --git a/kern/hvcall.c b/kern/hvcall.c
index c57b668..d387771 100644
--- a/kern/hvcall.c
+++ b/kern/hvcall.c
@@ -316,6 +316,7 @@ static pv_pd_t* translate_pv_pd(pv_t* pv, pa_t pd, int wp) {
}
pt_pa += pv->mem_base;
page_table_t* pt = (page_table_t*)map_phys_page(pt_pa, NULL);
+ int old_pde_us = (old_pde & (1 << PTE_US_SHIFT));
int j;
for (j = 0; j < NUM_PAGE_ENTRY; j++) {
pte_t old_pte = (*pt)[j];
@@ -340,7 +341,7 @@ static pv_pd_t* translate_pv_pd(pv_t* pv, pa_t pd, int wp) {
new_mask =
((1 << PTE_P_SHIFT) | old_rw | (PTE_USER << PTE_US_SHIFT));
}
- if (old_us != 0) {
+ if ((old_us & old_pde_us) != 0) {
new_user_mask =
((1 << PTE_P_SHIFT) | old_rw | (PTE_USER << PTE_US_SHIFT));
} else {
@@ -543,7 +544,7 @@ static void hvcall_print(stack_frame_t* f) {
if (copy_from_user(esp, sizeof(int), &len) != 0) {
goto read_arg_fail;
}
- if (len < 0) {
+ if (len < 0 || len > HV_PRINT_MAX) {
goto bad_length;
}
if (copy_from_user(esp + sizeof(va_t), sizeof(va_t), &base) != 0) {
@@ -659,6 +660,9 @@ static void hvcall_print_at(stack_frame_t* f) {
if (copy_from_user(esp + 4 * sizeof(va_t), sizeof(int), &color) != 0) {
goto read_arg_fail;
}
+ if (len < 0 || len > HV_PRINT_MAX) {
+ goto bad_length;
+ }
pts_t* pts = get_current()->pts;
mutex_lock(&pts->lock);
int result = pts_print_at(pts, len, base, row, col, color);
@@ -670,6 +674,8 @@ static void hvcall_print_at(stack_frame_t* f) {
print_fail:
pv_die("Bad argument");
+bad_length:
+ pv_die("Bad buffer length");
read_arg_fail:
pv_die("Bad argument address");
}
diff --git a/kern/inc/interrupt.h b/kern/inc/interrupt.h
index 7c15ccd..f90ee04 100644
--- a/kern/inc/interrupt.h
+++ b/kern/inc/interrupt.h
@@ -9,6 +9,10 @@
#ifndef _INTERRUPT_H_
#define _INTERRUPT_H_
+#include <x86/seg.h>
+
+#include <paging.h>
+
/**
* IRQ # of timer
*/
@@ -20,6 +24,56 @@
#define KBD_IRQ 1
/**
+ * @brief an idt entry
+ */
+typedef struct idt_s {
+ unsigned long lo;
+ unsigned long hi;
+} idt_t;
+
+/** means this entry requires ring 0 privilige */
+#define IDT_DPL_KERNEL 0
+/** means this entry requires ring 3 privilige */
+#define IDT_DPL_USER 3
+/** means this entry is valid */
+#define IDT_P 1
+/** means this entry is a 32 bit interrupt */
+#define IDT_TYPE_I32 0xe
+/** means this entry is a 32 bit trap */
+#define IDT_TYPE_T32 0xf
+
+/** P bit's position */
+#define IDT_P_SHIFT (47 - 32)
+/** DPL's position */
+#define IDT_DPL_SHIFT (45 - 32)
+/** TYPE's position */
+#define IDT_TYPE_SHIFT (40 - 32)
+/** CS's position */
+#define IDT_CS_SHIFT 16
+
+/** EIP's high part's bits */
+#define IDT_EIP_HI_MASK 0xffff0000
+/** EIP's low part's bits */
+#define IDT_EIP_LO_MASK 0x0000ffff
+
+#define IDT_FAULT_15 15
+
+/**
+ * @brief create an idt entry
+ * @param eip eip
+ * @param type type
+ * @param dpl dpl
+ * @return the idt entry
+ */
+static inline idt_t make_idt(va_t eip, int type, int dpl) {
+ idt_t idt;
+ idt.hi = ((eip & IDT_EIP_HI_MASK) | (IDT_P << IDT_P_SHIFT) |
+ (dpl << IDT_DPL_SHIFT) | (type << IDT_TYPE_SHIFT));
+ idt.lo = ((SEGSEL_KERNEL_CS << IDT_CS_SHIFT) | (eip & IDT_EIP_LO_MASK));
+ return idt;
+}
+
+/**
* @brief initialize idt
*/
void idt_init();
diff --git a/kern/inc/paging.h b/kern/inc/paging.h
index 182f50f..de00981 100644
--- a/kern/inc/paging.h
+++ b/kern/inc/paging.h
@@ -56,6 +56,7 @@ typedef unsigned int reg_t;
/** means a page can only be accessed in ring 0 */
#define PTE_SUPERVISOR 0
#define PTE_PCD 1
+#define PTE_PWT 1
/** means a page's TLB entry should not be flushed on switching cr3 */
#define PTE_G 1
@@ -65,6 +66,8 @@ typedef unsigned int reg_t;
#define PTE_RW_SHIFT 1
/** USER/SUPERVISOR bit's position */
#define PTE_US_SHIFT 2
+/** PWT bit's position */
+#define PTE_PWT_SHIFT 3
/** PCD bit's position */
#define PTE_PCD_SHIFT 4
/** G bit's position */
diff --git a/kern/inc/timer.h b/kern/inc/timer.h
index 8d6368e..759cf9e 100644
--- a/kern/inc/timer.h
+++ b/kern/inc/timer.h
@@ -21,4 +21,6 @@ extern heap_t timers;
*/
void timer_init();
+void setup_lapic_timer();
+
#endif
diff --git a/kern/interrupt.c b/kern/interrupt.c
index fd6839a..ba08bbd 100644
--- a/kern/interrupt.c
+++ b/kern/interrupt.c
@@ -31,56 +31,6 @@
#include <timer.h>
#include <usermem.h>
-/** means this entry requires ring 0 privilige */
-#define IDT_DPL_KERNEL 0
-/** means this entry requires ring 3 privilige */
-#define IDT_DPL_USER 3
-/** means this entry is valid */
-#define IDT_P 1
-/** means this entry is a 32 bit interrupt */
-#define IDT_TYPE_I32 0xe
-/** means this entry is a 32 bit trap */
-#define IDT_TYPE_T32 0xf
-
-/** P bit's position */
-#define IDT_P_SHIFT (47 - 32)
-/** DPL's position */
-#define IDT_DPL_SHIFT (45 - 32)
-/** TYPE's position */
-#define IDT_TYPE_SHIFT (40 - 32)
-/** CS's position */
-#define IDT_CS_SHIFT 16
-
-/** EIP's high part's bits */
-#define IDT_EIP_HI_MASK 0xffff0000
-/** EIP's low part's bits */
-#define IDT_EIP_LO_MASK 0x0000ffff
-
-#define IDT_FAULT_15 15
-
-/**
- * @brief an idt entry
- */
-typedef struct idt_s {
- unsigned long lo;
- unsigned long hi;
-} idt_t;
-
-/**
- * @brief create an idt entry
- * @param eip eip
- * @param type type
- * @param dpl dpl
- * @return the idt entry
- */
-static inline idt_t make_idt(va_t eip, int type, int dpl) {
- idt_t idt;
- idt.hi = ((eip & IDT_EIP_HI_MASK) | (IDT_P << IDT_P_SHIFT) |
- (dpl << IDT_DPL_SHIFT) | (type << IDT_TYPE_SHIFT));
- idt.lo = ((SEGSEL_KERNEL_CS << IDT_CS_SHIFT) | (eip & IDT_EIP_LO_MASK));
- return idt;
-}
-
/**
* @brief DE handler entry
*/
diff --git a/kern/kernel.c b/kern/kernel.c
index 057b6fe..bd675a5 100644
--- a/kern/kernel.c
+++ b/kern/kernel.c
@@ -55,6 +55,7 @@ static void kernel_smp_main();
int kernel_main(mbinfo_t* mbinfo, int argc, char** argv, char** envp) {
int smp_good = (smp_init(mbinfo) == 0);
paging_init();
+ setup_pts();
percpu_t percpu;
setup_percpu(&percpu);
thread_t kthread;
@@ -62,12 +63,12 @@ int kernel_main(mbinfo_t* mbinfo, int argc, char** argv, char** envp) {
setup_kth(&kthread, &kprocess);
set_mapped_phys_page(mapped_phys_pages);
set_mapped_phys_page_pte(mapped_phys_page_ptes);
- setup_pts();
idt_init();
mm_init();
- timer_init();
pv_init();
+ timer_init();
+
print_toad();
const char* init_args[] = {INIT_NAME};
@@ -76,11 +77,12 @@ int kernel_main(mbinfo_t* mbinfo, int argc, char** argv, char** envp) {
add_thread(init);
insert_ready_tail(init);
- if (smp_good && smp_num_cpus() > 1 && 0) {
- /* SMP not enabled */
+ if (smp_good && smp_num_cpus() > 1) {
+ set_cr3((pa_t)&kernel_pd);
smp_boot(kernel_smp_entry);
}
+ setup_lapic_timer();
kernel_smp_main();
return -1;
}
@@ -94,6 +96,7 @@ static void kernel_smp_entry(int cpuid) {
setup_kth(&kthread, &kprocess);
set_mapped_phys_page(mapped_phys_pages + cpuid * PAGE_SIZE);
set_mapped_phys_page_pte(mapped_phys_page_ptes + cpuid);
+ setup_lapic_timer();
kernel_smp_main();
}
diff --git a/kern/paging.c b/kern/paging.c
index eb81dd9..73c86da 100644
--- a/kern/paging.c
+++ b/kern/paging.c
@@ -61,7 +61,7 @@ void paging_init() {
pte_t* lapic_pte = (pte_t*)kernel_pt + (LAPIC_VIRT_BASE / PAGE_SIZE);
*lapic_pte =
(make_pte(lapic_pa, PTE_G, PTE_SUPERVISOR, PTE_RW, PTE_PRESENT) |
- (PTE_PCD << PTE_PCD_SHIFT));
+ (PTE_PWT << PTE_PWT_SHIFT) | (PTE_PCD << PTE_PCD_SHIFT));
set_cr4(get_cr4() | CR4_PSE | CR4_PGE);
set_cr3((uint32_t)kernel_pd);
diff --git a/kern/pts.c b/kern/pts.c
index 2964a25..9fdabf5 100644
--- a/kern/pts.c
+++ b/kern/pts.c
@@ -44,7 +44,6 @@ pts_t kernel_pts;
void setup_pts() {
pts_init(&kernel_pts);
- get_current()->pts = &kernel_pts;
kernel_pts.refcount++; /* kernel's refcount for all kths */
active_pts = &kernel_pts;
}
diff --git a/kern/sched.c b/kern/sched.c
index fbb5c6c..7764c26 100644
--- a/kern/sched.c
+++ b/kern/sched.c
@@ -88,6 +88,7 @@ void setup_kth(thread_t* kthread, process_t* kprocess) {
kprocess->refcount = 1;
kprocess->cr3 = (pa_t)kernel_pd;
kthread->process = kprocess;
+ kthread->pts = active_pts;
set_current(kthread);
set_kthread(kthread);
}
diff --git a/kern/timer.c b/kern/timer.c
index a202cb5..53fd576 100644
--- a/kern/timer.c
+++ b/kern/timer.c
@@ -10,8 +10,10 @@
#include <stdio.h>
#include <string.h>
+#include <apic.h>
#include <assert.h>
#include <x86/asm.h>
+#include <x86/idt.h>
#include <x86/interrupt_defines.h>
#include <x86/timer_defines.h>
@@ -26,19 +28,49 @@ spl_t timer_lock = SPL_INIT;
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
+static uint32_t lapic_dt;
+
+/* 2ms */
+#define TIMER_FREQ 500
+
+int timer_test_status;
+
+void timer_test_handler();
void timer_init() {
- int counter = TIMER_RATE / TIMER_FREQ;
+ /* use 10x slower frequency for APIC timer testing */
+ int counter = TIMER_RATE / (TIMER_FREQ / 10);
outb(TIMER_MODE_IO_PORT, TIMER_SQUARE_WAVE);
outb(TIMER_PERIOD_IO_PORT, counter & 0xFF);
outb(TIMER_PERIOD_IO_PORT, (counter >> 8) & 0xFF);
if (heap_init(&timers) != 0) {
panic("no space to initialize timer heap");
}
+ idt_t* idt = (idt_t*)idt_base();
+ idt_t old_idt = idt[TIMER_IDT_ENTRY];
+ idt[TIMER_IDT_ENTRY] =
+ make_idt((va_t)timer_test_handler, IDT_TYPE_I32, IDT_DPL_KERNEL);
+
+ lapic_write(LAPIC_LVT_TIMER, (LAPIC_ONESHOT | TIMER_IDT_ENTRY));
+ lapic_write(LAPIC_TIMER_DIV, LAPIC_X1);
+ lapic_write(LAPIC_TIMER_INIT, 0xffffffff);
+
+ timer_test_status = 10;
+ enable_interrupts();
+ while (timer_test_status != 0) {
+ }
+ disable_interrupts();
+
+ lapic_dt = (0xffffffff - lapic_read(LAPIC_TIMER_CUR)) / 100;
+ lapic_write(LAPIC_TIMER_INIT, 0);
+ idt[TIMER_IDT_ENTRY] = old_idt;
+}
+
+void setup_lapic_timer() {
+ lapic_write(LAPIC_LVT_TIMER, (LAPIC_PERIODIC | TIMER_IDT_ENTRY));
+ lapic_write(LAPIC_TIMER_DIV, LAPIC_X1);
+ lapic_write(LAPIC_TIMER_INIT, lapic_dt);
+ outb(TIMER_MODE_IO_PORT, TIMER_ONE_SHOT);
}
/**
@@ -61,7 +93,7 @@ static void check_timers() {
}
void timer_handler_real(stack_frame_t* f) {
- pic_acknowledge(TIMER_IRQ);
+ apic_eoi();
ticks++;
check_timers();
pv_inject_irq(f, TIMER_IDT_ENTRY, 0);
diff --git a/kern/timer_asm.S b/kern/timer_asm.S
new file mode 100644
index 0000000..cf4c76f
--- /dev/null
+++ b/kern/timer_asm.S
@@ -0,0 +1,18 @@
+#include <x86/seg.h>
+#include <x86/interrupt_defines.h>
+#include <x86/timer_defines.h>
+
+.text
+
+.global timer_test_handler
+.type timer_test_handler, %function
+timer_test_handler:
+ push %eax
+ mov timer_test_status, %eax
+ dec %eax
+ mov %eax, timer_test_status
+ mov $INT_ACK_CURRENT, %al
+ mov $INT_CTL_PORT, %dx
+ outb %al, %dx
+ pop %eax
+ iret