#include "interrupt.h"
+#include <inttypes.h>
#include <stdint.h>
#include "intr-stubs.h"
#include "debug.h"
outb (0x20, 0x20);
}
\f
-uint64_t idt[256];
+#define INTR_CNT 256
-intr_handler_func *intr_handlers[256];
+static uint64_t idt[INTR_CNT];
+static intr_handler_func *intr_handlers[INTR_CNT];
+static const char *intr_names[INTR_CNT];
void intr_handler (struct intr_frame *args);
bool intr_in_progress;
bool yield_on_return;
+const char *
+intr_name (int vec)
+{
+ if (vec < 0 || vec >= INTR_CNT || intr_names[vec] == NULL)
+ return "unknown";
+ else
+ return intr_names[vec];
+}
+
void
intr_handler (struct intr_frame *args)
{
}
if (yield_on_return)
- {
- printk (".");
- thread_yield ();
- }
+ thread_yield ();
}
bool
yield_on_return = true;
}
-/* Handles interrupts we don't know about. */
-intr_handler_func intr_unexpected;
-
-/* Handlers for CPU exceptions. */
-intr_handler_func excp00_divide_error;
-intr_handler_func excp01_debug;
-intr_handler_func excp02_nmi;
-intr_handler_func excp03_breakpoint;
-intr_handler_func excp04_overflow;
-intr_handler_func excp05_bound;
-intr_handler_func excp06_invalid_opcode;
-intr_handler_func excp07_device_not_available;
-intr_handler_func excp08_double_fault;
-intr_handler_func excp09_coprocessor_overrun;
-intr_handler_func excp0a_invalid_tss;
-intr_handler_func excp0b_segment_not_present;
-intr_handler_func excp0c_stack_fault;
-intr_handler_func excp0d_general_protection;
-intr_handler_func excp0e_page_fault;
-intr_handler_func excp10_fp_error;
-intr_handler_func excp11_alignment;
-intr_handler_func excp12_machine_check;
-intr_handler_func excp13_simd_error;
+intr_handler_func intr_panic NO_RETURN;
+intr_handler_func intr_kill NO_RETURN;
static uint64_t
make_intr_gate (void (*target) (void),
enabled. */
void
intr_register (uint8_t vec_no, int dpl, enum if_level level,
- intr_handler_func *handler)
+ intr_handler_func *handler,
+ const char *name)
{
if (level == IF_ON)
idt[vec_no] = make_trap_gate (intr_stubs[vec_no], dpl);
else
idt[vec_no] = make_intr_gate (intr_stubs[vec_no], dpl);
intr_handlers[vec_no] = handler;
+ intr_names[vec_no] = name;
}
void
/* Install default handlers. */
for (i = 0; i < 256; i++)
- intr_register (i, 0, IF_OFF, intr_unexpected);
+ intr_register (i, 0, IF_OFF, intr_panic, NULL);
/* Most exceptions require ring 0.
- Exceptions 3, 4, and 5 can be caused by ring 3 directly.
-
- Most exceptions can be handled with interrupts turned on.
+ Exceptions 3, 4, and 5 can be caused by ring 3 directly. */
+ intr_register (0, 0, IF_ON, intr_kill, "#DE Divide Error");
+ intr_register (1, 0, IF_ON, intr_kill, "#DB Debug Exception");
+ intr_register (2, 0, IF_ON, intr_panic, "NMI Interrupt");
+ intr_register (3, 3, IF_ON, intr_kill, "#BP Breakpoint Exception");
+ intr_register (4, 3, IF_ON, intr_kill, "#OF Overflow Exception");
+ intr_register (5, 3, IF_ON, intr_kill, "#BR BOUND Range Exceeded Exception");
+ intr_register (6, 0, IF_ON, intr_kill, "#UD Invalid Opcode Exception");
+ intr_register (7, 0, IF_ON, intr_kill, "#NM Device Not Available Exception");
+ intr_register (8, 0, IF_ON, intr_panic, "#DF Double Fault Exception");
+ intr_register (9, 0, IF_ON, intr_panic, "Coprocessor Segment Overrun");
+ intr_register (10, 0, IF_ON, intr_panic, "#TS Invalid TSS Exception");
+ intr_register (11, 0, IF_ON, intr_kill, "#NP Segment Not Present");
+ intr_register (12, 0, IF_ON, intr_kill, "#SS Stack Fault Exception");
+ intr_register (13, 0, IF_ON, intr_kill, "#GP General Protection Exception");
+ intr_register (16, 0, IF_ON, intr_kill, "#MF x87 FPU Floating-Point Error");
+ intr_register (17, 0, IF_ON, intr_panic, "#AC Alignment Check Exception");
+ intr_register (18, 0, IF_ON, intr_panic, "#MC Machine-Check Exception");
+ intr_register (19, 0, IF_ON, intr_kill, "#XF SIMD Floating-Point Exception");
+
+ /* Most exceptions can be handled with interrupts turned on.
We need to disable interrupts for page faults because the
- fault address is stored in CR2 and needs to be preserved.
- */
-#if 0
- intr_register (0x00, 0, IF_ON, excp00_divide_error);
- intr_register (0x01, 0, IF_ON, excp01_debug);
- intr_register (0x02, 0, IF_ON, excp02_nmi);
- intr_register (0x03, 3, IF_ON, excp03_breakpoint);
- intr_register (0x04, 3, IF_ON, excp04_overflow);
- intr_register (0x05, 3, IF_ON, excp05_bound);
- intr_register (0x06, 0, IF_ON, excp06_invalid_opcode);
- intr_register (0x07, 0, IF_ON, excp07_device_not_available);
- intr_register (0x08, 0, IF_ON, excp08_double_fault);
- intr_register (0x09, 0, IF_ON, excp09_coprocessor_overrun);
- intr_register (0x0a, 0, IF_ON, excp0a_invalid_tss);
- intr_register (0x0b, 0, IF_ON, excp0b_segment_not_present);
- intr_register (0x0c, 0, IF_ON, excp0c_stack_fault);
- intr_register (0x0d, 0, IF_ON, excp0d_general_protection);
- intr_register (0x0e, 0, IF_OFF, excp0e_page_fault);
- intr_register (0x10, 0, IF_ON, excp10_fp_error);
- intr_register (0x11, 0, IF_ON, excp11_alignment);
- intr_register (0x12, 0, IF_ON, excp12_machine_check);
- intr_register (0x13, 0, IF_ON, excp13_simd_error);
-#endif
+ fault address is stored in CR2 and needs to be preserved. */
+ intr_register (14, 0, IF_OFF, intr_kill, "#PF Page-Fault Exception");
idtr_operand = make_dtr_operand (sizeof idt - 1, idt);
asm volatile ("lidt %0" :: "m" (idtr_operand));
}
-void
-intr_unexpected (struct intr_frame *regs)
+static void
+dump_intr_frame (struct intr_frame *f)
{
- uint32_t cr2;
+ uint32_t cr2, ss;
asm ("movl %%cr2, %0" : "=r" (cr2));
- panic ("Unexpected interrupt 0x%02x, error code %08x, cr2=%08x, eip=%p",
- regs->vec_no, regs->error_code, cr2, (void *) regs->eip);
+ asm ("movl %%ss, %0" : "=r" (ss));
+
+ printk ("Interrupt %#04x (%s) at eip=%p\n",
+ f->vec_no, intr_name (f->vec_no), f->eip);
+ printk (" cr2=%08"PRIx32" error=%08"PRIx32"\n", cr2, f->error_code);
+ printk (" eax=%08"PRIx32" ebx=%08"PRIx32" ecx=%08"PRIx32" edx=%08"PRIx32"\n",
+ f->eax, f->ebx, f->ecx, f->edx);
+ printk (" esi=%08"PRIx32" edi=%08"PRIx32" esp=%08"PRIx32" ebp=%08"PRIx32"\n",
+ f->esi, f->edi, (uint32_t) f->esp, f->ebp);
+ printk (" cs=%04"PRIx16" ds=%04"PRIx16" es=%04"PRIx16" ss=%04"PRIx16"\n",
+ f->cs, f->ds, f->es, f->cs != SEL_KCSEG ? f->ss : ss);
}
+
+void
+intr_panic (struct intr_frame *regs)
+{
+ dump_intr_frame (regs);
+ panic ("Panic!");
+}
+
+void
+intr_kill (struct intr_frame *f)
+{
+ switch (f->cs)
+ {
+ case SEL_UCSEG:
+ printk ("[%p] Interrupt %#04x (%s), killing process.\n",
+ thread_current (), f->vec_no, intr_name (f->vec_no));
+ thread_exit ();
+
+ default:
+ panic ("Interrupt %#04x (%s) in unknown segment %04x",
+ f->vec_no, intr_name (f->vec_no), f->cs);
+
+ case SEL_KCSEG:
+ printk ("intr_kill -> panic %d\n", f->vec_no);
+ intr_panic (f);
+ }
+}
+
+
static uint32_t *base_page_dir;
-static uint32_t
-make_pde (uint32_t *pagetab)
-{
- ASSERT (pg_ofs (pagetab) == 0);
-
- return vtop (pagetab) | PG_U | PG_P | PG_W;
+static uint32_t make_pde (uint32_t *pt) {
+ ASSERT (pg_ofs (pt) == 0);
+ return vtop (pt) | PG_U | PG_P | PG_W;
}
-static uint32_t
-make_pte (uint32_t *page, bool writable)
-{
- uint32_t entry;
-
+static uint32_t make_kernel_pte (uint32_t *page, bool writable) {
ASSERT (pg_ofs (page) == 0);
-
- entry = vtop (page) | PG_U | PG_P;
- if (writable)
- entry |= PG_W;
- return entry;
+ return vtop (page) | PG_P | (writable ? PG_W : 0);
+}
+
+static uint32_t make_user_pte (uint32_t *page, bool writable) {
+ return make_kernel_pte (page, writable) | PG_U;
}
static uint32_t *
-pde_get_pagetab (uint32_t pde)
+pde_get_pt (uint32_t pde)
{
ASSERT (pde & PG_P);
pd[pde_idx] = make_pde (pt);
}
- pt[pte_idx] = make_pte (vaddr, true);
+ pt[pte_idx] = make_kernel_pte (vaddr, true);
}
pagedir_activate (pd);
}
static uint32_t *
-lookup_page (uint32_t *pagedir, void *upage, bool create)
+lookup_page (uint32_t *pd, void *upage, bool create)
{
- uint32_t *pagetab;
+ uint32_t *pt;
uint32_t *pde;
- ASSERT (pagedir != NULL);
+ ASSERT (pd != NULL);
ASSERT (pg_ofs (upage) == 0);
ASSERT (upage < PHYS_BASE);
/* Check for a page table for UPAGE.
If one is missing, create one if requested. */
- pde = pagedir + pd_no (upage);
+ pde = pd + pd_no (upage);
if (*pde == 0)
{
if (create)
{
- pagetab = palloc_get (PAL_ZERO);
- if (pagetab == NULL)
+ pt = palloc_get (PAL_ZERO);
+ if (pt == NULL)
return NULL;
- *pde = make_pde (pagetab);
+ *pde = make_pde (pt);
}
else
return NULL;
}
/* Return the page table entry. */
- pagetab = pde_get_pagetab (*pde);
- return &pagetab[pt_no (upage)];
+ pt = pde_get_pt (*pde);
+ return &pt[pt_no (upage)];
}
bool
-pagedir_set_page (uint32_t *pagedir, void *upage, void *kpage,
+pagedir_set_page (uint32_t *pd, void *upage, void *kpage,
bool writable)
{
uint32_t *pte;
ASSERT (pg_ofs (kpage) == 0);
- pte = lookup_page (pagedir, upage, true);
+ pte = lookup_page (pd, upage, true);
if (pte != NULL)
{
- *pte = make_pte (kpage, writable);
+ *pte = make_user_pte (kpage, writable);
return true;
}
else
}
void *
-pagedir_get_page (uint32_t *pagedir, void *upage)
+pagedir_get_page (uint32_t *pd, void *upage)
{
- uint32_t *pte = lookup_page (pagedir, upage, false);
+ uint32_t *pte = lookup_page (pd, upage, false);
return pte != NULL && *pte != 0 ? pte_get_page (*pte) : NULL;
}
void
-pagedir_clear_page (uint32_t *pagedir, void *upage)
+pagedir_clear_page (uint32_t *pd, void *upage)
{
- uint32_t *pte = lookup_page (pagedir, upage, false);
+ uint32_t *pte = lookup_page (pd, upage, false);
if (pte != NULL)
*pte = 0;
}
if (pde != 0)
{
- void *kpage = scan_pt (pde_get_pagetab (pde), pde_idx, 0, upage);
+ void *kpage = scan_pt (pde_get_pt (pde), pde_idx, 0, upage);
if (kpage != NULL)
return kpage;
}
}
void *
-pagedir_first (uint32_t *pagedir, void **upage)
+pagedir_first (uint32_t *pd, void **upage)
{
- return scan_pd (pagedir, 0, upage);
+ return scan_pd (pd, 0, upage);
}
void *
pde_idx = pd_no (*upage);
pte_idx = pt_no (*upage);
- kpage = scan_pt (pde_get_pagetab (pd[pde_idx]),
+ kpage = scan_pt (pde_get_pt (pd[pde_idx]),
pde_idx, pte_idx + 1, upage);
if (kpage == NULL)
kpage = scan_pd (pd, pde_idx + 1, upage);
}
void
-pagedir_activate (uint32_t *pagedir)
+pagedir_activate (uint32_t *pd)
{
- asm volatile ("movl %0,%%cr3" :: "r" (vtop (pagedir)));
+ asm volatile ("movl %0,%%cr3" :: "r" (vtop (pd)));
}
{
struct thread *t;
struct thread_root_frame *rf;
- struct switch_thunk_frame *tf;
- struct switch_frame *sf;
+ struct switch_entry_frame *ef;
+ struct switch_threads_frame *sf;
ASSERT (function != NULL);
rf->function = function;
rf->aux = aux;
- /* Stack frame for switch_thunk(). */
- tf = alloc_frame (t, sizeof *tf);
- tf->eip = (void (*) (void)) thread_root;
+ /* Stack frame for switch_entry(). */
+ ef = alloc_frame (t, sizeof *ef);
+ ef->eip = (void (*) (void)) thread_root;
/* Stack frame for thread_switch(). */
sf = alloc_frame (t, sizeof *sf);
- sf->eip = (void (*) (void)) switch_thunk;
+ sf->eip = switch_entry;
/* Add to run queue. */
thread_ready (t);
{
struct thread *t;
struct intr_frame *if_;
- struct switch_thunk_frame *tf;
- struct switch_frame *sf;
+ struct switch_entry_frame *ef;
+ struct switch_threads_frame *sf;
void (*start) (void);
ASSERT (filename != NULL);
if_->eflags = FLAG_IF | 2;
if_->esp = PHYS_BASE;
if_->ss = SEL_UDSEG;
-
- /* Stack frame for switch_thunk(). */
- tf = alloc_frame (t, sizeof *tf);
- tf->eip = (void (*) (void)) intr_exit;
+
+ /* Stack frame for switch_entry(). */
+ ef = alloc_frame (t, sizeof *ef);
+ ef->eip = intr_exit;
/* Stack frame for thread_switch(). */
sf = alloc_frame (t, sizeof *sf);
- sf->eip = (void (*) (void)) switch_thunk;
+ sf->eip = switch_entry;
/* Add to run queue. */
thread_ready (t);
palloc_free (t);
}
+void schedule_tail (struct thread *prev);
+
+void
+schedule_tail (struct thread *prev)
+{
+ struct thread *cur = thread_current ();
+
+#ifdef USERPROG
+ addrspace_activate (&cur->addrspace);
+#endif
+
+ if (prev != NULL && prev->status == THREAD_DYING)
+ thread_destroy (prev);
+
+ intr_enable ();
+}
+
void
thread_schedule (void)
{
idle ();
next->status = THREAD_RUNNING;
- prev = switch_threads (cur, next);
-
- /* Prevent GCC from reordering anything around the thread
- switch. */
- asm volatile ("" : : : "memory");
-
-#ifdef USERPROG
- addrspace_activate (&cur->addrspace);
-#endif
+ if (cur != next)
+ {
+ prev = switch_threads (cur, next);
- if (prev != NULL && prev->status == THREAD_DYING)
- thread_destroy (prev);
+ /* Prevent GCC from reordering anything around the thread
+ switch. */
+ asm volatile ("" : : : "memory");
- intr_enable ();
+ schedule_tail (prev);
+ }
}
void
intr_disable ();
thread_current ()->status = THREAD_DYING;
thread_schedule ();
+ NOT_REACHED ();
}
void