Syscall work, interrupt enabling, sysenter tweaks
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 30 Jun 2009 17:42:51 +0000 (10:42 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 1 Jul 2009 18:23:23 +0000 (11:23 -0700)
Interrupts are enabled for all syscalls (whether trap or sysenter),
env_run can handle returning from something other than sysenter (will
happen when we handle traps better), EFLAGS are saved and restored, can
fully inline sysenters if desired, and a couple other tweaks.

include/arch/mmu.h
include/ros/env.h
include/syscall.h
kern/src/env.c
kern/src/syscall.c
kern/src/trap.c
kern/src/trapentry.S
user/roslib/src/syscall.c

index b7f3c54..b2fe3c7 100644 (file)
@@ -293,6 +293,7 @@ typedef struct Gatedesc {
 
 // Set up a normal interrupt/trap gate descriptor.
 // - istrap: 1 for a trap (= exception) gate, 0 for an interrupt gate.
+//   - interrupt gates automatically disable interrupts (cli)
 // - sel: Code segment selector for interrupt/trap handler
 // - off: Offset in code segment for interrupt/trap handler
 // - dpl: Descriptor Privilege Level -
index 03f38e5..b218708 100644 (file)
@@ -50,6 +50,7 @@ struct Env {
        unsigned env_status;            // Status of the environment
        uint32_t env_runs;                      // Number of times environment has run
        uint32_t env_refcnt;            // Reference count of kernel contexts using this
+       uint32_t env_flags;
        // Note this is the actual backring, not a pointer to it somewhere else
        syscall_back_ring_t env_sysbackring;    // BackRing for generic syscalls
 
@@ -64,4 +65,7 @@ struct Env {
        uint64_t env_tscfreq;           // Frequency of the TSC for measurements
 };
 
+/* Process Flags */
+// None yet
+
 #endif // !ROS_INC_ENV_H
index 3497a34..3b8240b 100644 (file)
@@ -11,5 +11,4 @@ int32_t (SYNCHRONOUS syscall)(env_t* e, uint32_t num, uint32_t a1, uint32_t a2,
                               uint32_t a3, uint32_t a4, uint32_t a5);
 int32_t syscall_async(env_t* e, syscall_req_t *syscall);
 int32_t process_generic_syscalls(env_t* e, uint32_t max);
-void syscall_wrapper(struct Trapframe *tf);
 #endif /* !ROS_KERN_SYSCALL_H */
index 5a694da..1260481 100644 (file)
@@ -245,6 +245,7 @@ env_alloc(env_t **newenv_store, envid_t parent_id)
        e->env_status = ENV_RUNNABLE;
        e->env_runs = 0;
        e->env_refcnt = 1;
+       e->env_flags = 0;
 
        // Clear out all the saved register state,
        // to prevent the register values
@@ -590,28 +591,29 @@ void schedule(void)
 //
 void env_pop_tf(trapframe_t *tf)
 {
-       __asm __volatile(
-           "movl %0,%%esp\n"
-           "\tpopal\n"
-           "\tpopl %%es\n"
-           "\tpopl %%ds\n"
-           "\taddl $0x8,%%esp\n" /* skip tf_trapno and tf_errcode */
-           "\tiret"
-           : : "g" (tf) : "memory");
+       asm volatile ("movl %0,%%esp;           "
+                     "popal;                   "
+                     "popl %%es;               "
+                     "popl %%ds;               "
+                     "addl $0x8,%%esp;         "
+                     "iret                     "
+                     : : "g" (tf) : "memory");
        panic("iret failed");  /* mostly to placate the compiler */
 }
 
+/* Return path of sysexit.  See sysenter_handler's asm for details. */
 void env_pop_tf_sysexit(trapframe_t *tf)
 {
-       __asm __volatile(
-           "movl %0,%%esp\n"
-           "\tpopal\n"
-           "\tpopl %%es\n"
-           "\tpopl %%ds\n"
-           "\tmovl %%ebp, %%ecx\n"
-           "\tmovl %%esi, %%edx\n"
-           "\tsysexit"
-           : : "g" (tf) : "memory");
+       asm volatile ("movl %0,%%esp;           "
+                     "popal;                   "
+                     "popl %%es;               "
+                     "popl %%ds;               "
+                     "addl $0x10, %%esp;       "
+                     "popfl;                   "
+                     "movl %%ebp, %%ecx;       "
+                     "movl %%esi, %%edx;       "
+                     "sysexit                  "
+                     : : "g" (tf) : "memory");
        panic("sysexit failed");  /* mostly to placate the compiler */
 }
 
@@ -643,26 +645,15 @@ env_run(env_t *e)
                curenvs[lapic_get_id()] = e;
                e->env_runs++;
                lcr3(e->env_cr3);
-               
-               #ifndef SYSCALL_TRAP
-                       // The first time through we need to set up 
-                       // ebp and esi because there is no corresponding 
-                       // sysenter call and we have not set them up yet
-                       // for use by the env_pop_tf_sysexit() call that 
-                       // follows
-                       if(e->env_runs == 1) {
-                               e->env_tf.tf_regs.reg_ebp = e->env_tf.tf_esp;
-                               e->env_tf.tf_regs.reg_esi = e->env_tf.tf_eip;
-                       }
-               #endif
-
        }
-       
-       #ifndef SYSCALL_TRAP
-               env_pop_tf_sysexit(&e->env_tf);
-       #else
+       /* If the process entered the kernel via sysenter, we need to leave via
+        * sysexit.  sysenter trapframes have 0 for a CS, which is pushed in
+        * sysenter_handler.
+        */
+       if (e->env_tf.tf_cs)
                env_pop_tf(&e->env_tf);
-       #endif
+       else
+               env_pop_tf_sysexit(&e->env_tf);
 }
 
 /* This is the top-half of an interrupt handler, where the bottom half is
index 7ff66cb..068a94e 100644 (file)
 #include <trap.h>
 #include <syscall.h>
 
-/* This is called from sysenter's asm, with the tf on the kernel stack */
-void syscall_wrapper(struct Trapframe *tf)
+/* This is called from sysenter's asm, with the tf on the kernel stack. */
+void sysenter_callwrapper(struct Trapframe *tf)
 {
        env_t* curenv = curenvs[lapic_get_id()];
-    curenv->env_tf = *tf;
-       // TODO: sort this interrupts shit better
-       //Re enable interrupts. sysenter disables them.
-       enable_irq();
+       curenv->env_tf = *tf;
        
        // The trapframe on the stack should be ignored from here on.
        tf = &curenv->env_tf;
-    tf->tf_regs.reg_eax = (intreg_t) syscall(curenv,
+       tf->tf_regs.reg_eax = (intreg_t) syscall(curenv,
                                                 tf->tf_regs.reg_eax,
                                                 tf->tf_regs.reg_edx,
                                                 tf->tf_regs.reg_ecx,
@@ -243,7 +240,7 @@ intreg_t syscall(env_t* e, uint32_t syscallno, uint32_t a1, uint32_t a2,
        //printk("Running syscall: %d\n", syscallno);
        if (INVALID_SYSCALL(syscallno))
                return -E_INVAL;
-
+       
        switch (syscallno) {
                case SYS_null:
                        sys_null();
index b89c32f..924ccd3 100644 (file)
@@ -95,7 +95,9 @@ idt_init(void)
 
        // turn on syscall handling and other user-accessible ints
        // DPL 3 means this can be triggered by the int instruction
+       // STS_TG32 sets the IDT type to a Trap Gate (interrupts enabled)
        idt[T_SYSCALL].gd_dpl = 3;
+       idt[T_SYSCALL].gd_type = STS_TG32;
        idt[T_BRKPT].gd_dpl = 3;
 
        // Setup a TSS so that we get the right stack
index 8834166..016b947 100644 (file)
@@ -137,6 +137,9 @@ TRAPHANDLER_NOEC(ISR_default, T_DEFAULT)
 .globl trap_tbl_end
 trap_tbl_end:
 
+/* Keep the exit paths of _alltraps, _allirqs, and sysenter_handler in sync
+ * with the corresponding pop_tf's.
+ */
 .text
 _alltraps:
        cld
@@ -180,20 +183,28 @@ _allirqs:
 .globl sysenter_handler;
 .type sysenter_handler, @function;
 sysenter_handler:
-    cld
+       sti                                             # enable interrupts (things are sane here)
+       cld
+       pushfl                                  # save the eflags
+       pushl $0                                # these zeros keep the trapframe looking the same 
+       pushl $0                                # as when we receive a trap or interrupt
+       pushl $0                                # and CS == 0 lets the kernel know it was a sysenter
+       pushl $T_SYSCALL                # helps with print_trapframe
        pushl %ds
-    pushl %es
-    pushal
-    movw $GD_KD, %ax
-    movw %ax, %ds
-    movw %ax, %es
-    pushl %esp
+       pushl %es
+       pushal
+       movw $GD_KD, %ax
+       movw %ax, %ds
+       movw %ax, %es
+       pushl %esp
        movl $0, %ebp                   # so we can backtrace to this point
-    call syscall_wrapper
-    popl %esp
-    popal
-    popl %es
-    popl %ds
-    movl %ebp, %ecx
-    movl %esi, %edx
-    sysexit
+       call sysenter_callwrapper
+       popl %esp
+       popal
+       popl %es
+       popl %ds
+       addl $0x10, %esp                # pop T_SYSCALL and the three zeros
+       popfl                                   # restore EFLAGS
+       movl %ebp, %ecx
+       movl %esi, %edx
+       sysexit
index 37a800c..7a60785 100644 (file)
@@ -14,26 +14,21 @@ static intreg_t syscall_sysenter(uint16_t num, intreg_t a1,
                                  intreg_t a4, intreg_t a5)
 {
        intreg_t ret;
-    asm volatile(
-            //"pushl %%ecx\n\t"
-            //"pushl %%edx\n\t"
-            "pushl %%ebp\n\t"
-                       "pushl %%esi\n\t"
-            "movl %%esp, %%ebp\n\t"
-            "leal after_sysenter, %%esi\n\t"
-            "sysenter\n\t"
-            "after_sysenter:\n\t"
-                       "popl %%esi\n\t"
-            "popl %%ebp\n\t"
-            //"popl %%edx\n\t"
-            //"popl %%ecx"
-            :"=a" (ret)
-            : "a" (num),
-                "d" (a1),
-                "c" (a2),
-                "b" (a3),
-                "D" (a4)
-        : "cc", "memory", "%esp");
+       asm volatile ("  pushl %%ebp;        "
+                     "  pushl %%esi;        "
+                     "  movl %%esp, %%ebp;  "
+                     "  leal 1f, %%esi;     "
+                     "  sysenter;           "
+                     "1:                    "
+                     "  popl %%esi;         "
+                     "  popl %%ebp;         "
+                     : "=a" (ret)
+                     : "a" (num),
+                       "d" (a1),
+                       "c" (a2),
+                       "b" (a3),
+                       "D" (a4)
+                     : "cc", "memory");
        return ret;
 }
 
@@ -55,23 +50,22 @@ static intreg_t syscall_trap(uint16_t num, intreg_t a1,
        // potentially change the condition codes and arbitrary
        // memory locations.
 
-       asm volatile("int %1\n"
-               : "=a" (ret)
-               : "i" (T_SYSCALL),
-                 "a" (num),
-                 "d" (a1),
-                 "c" (a2),
-                 "b" (a3),
-                 "D" (a4),
-                 "S" (a5)
-               : "cc", "memory");
-
+       asm volatile("int %1"
+                    : "=a" (ret)
+                    : "i" (T_SYSCALL),
+                      "a" (num),
+                      "d" (a1),
+                      "c" (a2),
+                      "b" (a3),
+                      "D" (a4),
+                      "S" (a5)
+                    : "cc", "memory");
        return ret;
 }
 
-static intreg_t syscall(uint16_t num, intreg_t a1,
-                        intreg_t a2, intreg_t a3,
-                        intreg_t a4, intreg_t a5)
+static inline intreg_t syscall(uint16_t num, intreg_t a1,
+                               intreg_t a2, intreg_t a3,
+                               intreg_t a4, intreg_t a5)
 {
        #ifndef SYSCALL_TRAP
                return syscall_sysenter(num, a1, a2, a3, a4, a5);