From: Ben Pfaff Date: Fri, 27 Aug 2004 07:18:38 +0000 (+0000) Subject: Make userspace actually work. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?p=pintos-anon;a=commitdiff_plain;h=44d0fa6a2b24a84e5eb0d54959ed91c1d4f15343 Make userspace actually work. --- diff --git a/src/devices/kbd.c b/src/devices/kbd.c index e5d3d82..ed52cfa 100644 --- a/src/devices/kbd.c +++ b/src/devices/kbd.c @@ -14,5 +14,5 @@ irq21_keyboard (struct intr_frame *args UNUSED) void kbd_init (void) { - intr_register (0x21, 0, IF_OFF, irq21_keyboard); + intr_register (0x21, 0, IF_OFF, irq21_keyboard, "8042 Keyboard"); } diff --git a/src/devices/timer.c b/src/devices/timer.c index 4adca89..4b8dd2a 100644 --- a/src/devices/timer.c +++ b/src/devices/timer.c @@ -3,6 +3,10 @@ #include "interrupt.h" #include "io.h" +#if TIMER_FREQ < 19 +#error 8254 timer requires TIMER_FREQ >= 19 +#endif + static volatile uint64_t ticks; static void @@ -26,7 +30,7 @@ timer_init (void) outb (0x40, count & 0xff); outb (0x40, count >> 8); - intr_register (0x20, 0, IF_OFF, irq20_timer); + intr_register (0x20, 0, IF_OFF, irq20_timer, "8254 Timer"); } uint64_t diff --git a/src/threads/init.c b/src/threads/init.c index 234c41e..f247612 100644 --- a/src/threads/init.c +++ b/src/threads/init.c @@ -32,7 +32,7 @@ void power_off (void); static void main_thread (void *aux UNUSED) { - printk ("execute=%d\n", (int) thread_execute ("a.out")); + thread_execute ("a.out"); } int @@ -71,7 +71,6 @@ main (void) #ifdef FILESYS filesys_init (false); - filesys_self_test (); #endif thread_init (); diff --git a/src/threads/init.h b/src/threads/init.h index b482079..2c73fd9 100644 --- a/src/threads/init.h +++ b/src/threads/init.h @@ -3,6 +3,8 @@ #include +struct tss *tss; + extern size_t kernel_pages; extern size_t ram_pages; diff --git a/src/threads/interrupt.c b/src/threads/interrupt.c index 6250f81..9058775 100644 --- a/src/threads/interrupt.c +++ b/src/threads/interrupt.c @@ -1,4 +1,5 @@ #include "interrupt.h" +#include #include #include "intr-stubs.h" #include "debug.h" @@ -93,15 +94,26 @@ pic_eoi (void) outb (0x20, 0x20); } -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) { @@ -128,10 +140,7 @@ intr_handler (struct intr_frame *args) } if (yield_on_return) - { - printk ("."); - thread_yield (); - } + thread_yield (); } bool @@ -146,29 +155,8 @@ intr_yield_on_return (void) 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), @@ -200,13 +188,15 @@ make_trap_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 @@ -219,46 +209,81 @@ intr_init (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); + } +} + + diff --git a/src/threads/interrupt.h b/src/threads/interrupt.h index a40276a..5fa67b2 100644 --- a/src/threads/interrupt.h +++ b/src/threads/interrupt.h @@ -44,8 +44,11 @@ struct intr_frame typedef void intr_handler_func (struct intr_frame *); void intr_init (void); -void intr_register (uint8_t vec, int dpl, enum if_level, intr_handler_func *); +void intr_register (uint8_t vec, int dpl, enum if_level, intr_handler_func *, + const char *name); bool intr_context (void); void intr_yield_on_return (void); +const char *intr_name (int vec); + #endif /* interrupt.h */ diff --git a/src/threads/loader.S b/src/threads/loader.S index 18086ed..c60e8dd 100644 --- a/src/threads/loader.S +++ b/src/threads/loader.S @@ -153,6 +153,13 @@ read_sector: movl %eax, %cr0 jmp 1f 1: + +##### Turn on EM bit in CR0, forcing most floating-point instructions +##### to trap. We don't support floating-point or MMX. + + movl %cr0, %eax + orl $CR0_EM, %eax + movl %eax, %cr0 ##### Jump to kernel entry point. diff --git a/src/threads/paging.c b/src/threads/paging.c index 2fa549c..d54fef8 100644 --- a/src/threads/paging.c +++ b/src/threads/paging.c @@ -8,29 +8,22 @@ 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); @@ -74,7 +67,7 @@ paging_init (void) pd[pde_idx] = make_pde (pt); } - pt[pte_idx] = make_pte (vaddr, true); + pt[pte_idx] = make_kernel_pte (vaddr, true); } pagedir_activate (pd); @@ -100,49 +93,49 @@ pagedir_destroy (uint32_t *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 @@ -150,16 +143,16 @@ pagedir_set_page (uint32_t *pagedir, void *upage, void *kpage, } 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; } @@ -194,7 +187,7 @@ scan_pd (uint32_t *pd, unsigned pde_idx, void **upage) 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; } @@ -204,9 +197,9 @@ scan_pd (uint32_t *pd, unsigned pde_idx, void **upage) } 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 * @@ -217,7 +210,7 @@ pagedir_next (uint32_t *pd, void **upage) 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); @@ -225,7 +218,7 @@ pagedir_next (uint32_t *pd, void **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))); } diff --git a/src/threads/switch.S b/src/threads/switch.S index b00823a..fddd821 100644 --- a/src/threads/switch.S +++ b/src/threads/switch.S @@ -32,7 +32,16 @@ switch_threads: popl %ebx ret - .globl switch_thunk -switch_thunk: + .globl switch_entry +switch_entry: + # Discard thread_switch() arguments. addl $8, %esp + + # Call schedule_tail(prev). + pushl %eax + .globl schedule_tail + call schedule_tail + addl $4, %esp + + # Start thread proper. ret diff --git a/src/threads/switch.h b/src/threads/switch.h index c9ae4ab..8a2974f 100644 --- a/src/threads/switch.h +++ b/src/threads/switch.h @@ -3,7 +3,7 @@ #ifndef __ASSEMBLER__ /* switch_thread()'s stack frame. */ -struct switch_frame +struct switch_threads_frame { uint32_t ebx; /* 0: Saved %ebx. */ uint32_t ebp; /* 4: Saved %ebp. */ @@ -19,11 +19,13 @@ struct switch_frame NEXT's context. */ struct thread *switch_threads (struct thread *cur, struct thread *next); -struct switch_thunk_frame +struct switch_entry_frame { void (*eip) (void); }; +void switch_entry (void); + /* Pops the CUR and NEXT arguments off the stack, for use in initializing threads. */ void switch_thunk (void); diff --git a/src/threads/thread.c b/src/threads/thread.c index 82858df..dd98be0 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -67,8 +67,8 @@ thread_create (const char *name, void (*function) (void *aux), void *aux) { 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); @@ -80,13 +80,13 @@ thread_create (const char *name, void (*function) (void *aux), void *aux) 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); @@ -108,8 +108,8 @@ thread_execute (const char *filename) { 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); @@ -130,14 +130,14 @@ thread_execute (const char *filename) 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); @@ -182,6 +182,23 @@ thread_destroy (struct thread *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) { @@ -196,20 +213,16 @@ 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 @@ -241,6 +254,7 @@ thread_exit (void) intr_disable (); thread_current ()->status = THREAD_DYING; thread_schedule (); + NOT_REACHED (); } void diff --git a/src/threads/thread.h b/src/threads/thread.h index 8a0df6e..9251ad8 100644 --- a/src/threads/thread.h +++ b/src/threads/thread.h @@ -2,6 +2,7 @@ #define HEADER_THREAD_H 1 #include +#include "debug.h" #include "list.h" #ifdef USERPROG @@ -40,7 +41,7 @@ bool thread_execute (const char *filename); void thread_start (struct thread *); void thread_ready (struct thread *); -void thread_exit (void); +void thread_exit (void) NO_RETURN; void thread_yield (void); void thread_sleep (void); diff --git a/src/userprog/addrspace.c b/src/userprog/addrspace.c index eb0de49..c136ae5 100644 --- a/src/userprog/addrspace.c +++ b/src/userprog/addrspace.c @@ -3,6 +3,7 @@ #include "debug.h" #include "file.h" #include "filesys.h" +#include "init.h" #include "lib.h" #include "mmu.h" #include "malloc.h" @@ -209,11 +210,6 @@ addrspace_load (struct addrspace *as, const char *filename, file_seek (file, file_ofs); if (file_read (file, &phdr, sizeof phdr) != sizeof phdr) LOAD_ERROR (("error reading program header")); - printk ("%x: %08x, %08x %08x %08x %05x %05x\n", - file_tell (file), - phdr.p_type, - phdr.p_offset, phdr.p_vaddr, phdr.p_paddr, - phdr.p_filesz, phdr.p_memsz); file_ofs += sizeof phdr; switch (phdr.p_type) { @@ -270,4 +266,5 @@ addrspace_activate (struct addrspace *as) if (as->pagedir != NULL) pagedir_activate (as->pagedir); + tss->esp0 = (uint32_t) pg_round_down (as) + PGSIZE; }