kernel - Misc fixes and debugging
authorMatthew Dillon <dillon@apollo.backplane.com>
Mon, 12 Dec 2011 17:37:20 +0000 (09:37 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Mon, 12 Dec 2011 17:37:20 +0000 (09:37 -0800)
* Add required CLDs in the exception paths.  The interrupt paths already
  CLD in PUSH_FRAME.

* Note that the fast_syscall (SYSENTER) path has an implied CLD due to the
  hardware mask applied to rflags.

* Add the IOPL bits to the set of bits set to 0 during a fast_syscall.

* When creating a dummy interrupt frame we don't have to push the
  actual %cs.  Just push $0 so the frame isn't misinterpreted as coming
  from userland.

* Additional debug verbosity for freeze_on_seg_fault.

* Reserve two void * fields for LWP debugging (for a later commit)

sys/platform/pc32/i386/exception.s
sys/platform/pc64/apic/apic_vector.s
sys/platform/pc64/x86_64/exception.S
sys/platform/pc64/x86_64/ipl.s
sys/platform/pc64/x86_64/machdep.c
sys/platform/pc64/x86_64/mp_machdep.c
sys/platform/pc64/x86_64/swtch.s
sys/platform/pc64/x86_64/trap.c
sys/platform/pc64/x86_64/vm_machdep.c
sys/sys/proc.h

index 987687f..b0039c8 100644 (file)
@@ -769,7 +769,6 @@ alltraps:
        pushl   %es
        pushl   %fs
        pushl   %gs
-       cld
        .globl  alltraps_with_regs_pushed
 alltraps_with_regs_pushed:
        mov     $KDSEL,%ax
@@ -783,6 +782,7 @@ calltrap:
        FAKE_MCOUNT(btrap)              /* init "from" _btrap -> calltrap */
        incl    PCPU(cnt)+V_TRAP
        /* warning, trap frame dummy arg, no extra reg pushes */
+       cld
        pushl   %esp                    /* pass frame by reference */
        call    trap
        addl    $4,%esp
index f9de780..b338bce 100644 (file)
@@ -52,7 +52,8 @@
  * segment register being changed (e.g. by procfs), which is why syscalls
  * have to use doreti.
  */
-#define APIC_POP_FRAME POP_FRAME
+#define APIC_POP_FRAME                                                 \
+       POP_FRAME ;                                                     \
 
 #define IOAPICADDR(irq_num) \
        CNAME(ioapic_irqs) + IOAPIC_IRQI_SIZE * (irq_num) + IOAPIC_IRQI_ADDR
@@ -161,18 +162,24 @@ IDTVEC(ioapic_intr##irq_num) ;                                            \
 
 /*
  * Handle "spurious INTerrupts".
- * Notes:
- *  This is different than the "spurious INTerrupt" generated by an
- *   8259 PIC for missing INTs.  See the APIC documentation for details.
- *  This routine should NOT do an 'EOI' cycle.
+ *
+ * NOTE: This is different than the "spurious INTerrupt" generated by an
+ *      8259 PIC for missing INTs.  See the APIC documentation for details.
+ *      This routine should NOT do an 'EOI' cycle.
+ *
+ * NOTE: Even though we don't do anything here we must still swapgs if
+ *      coming from a user frame in case the iretq faults... just use
+ *      the nominal APIC_PUSH_FRAME sequence to get it done.
  */
        .text
        SUPERALIGN_TEXT
        .globl Xspuriousint
 Xspuriousint:
-
+       APIC_PUSH_FRAME
        /* No EOI cycle used here */
-
+       FAKE_MCOUNT(TF_RIP(%rsp))
+       MEXITCOUNT
+       APIC_POP_FRAME
        jmp     doreti_iret
 
 #ifdef SMP
index 81106ac..52bb3a6 100644 (file)
@@ -183,6 +183,7 @@ alltraps_pushregs_no_rdi:
        .globl  calltrap
        .type   calltrap,@function
 calltrap:
+       cld
        movq    %rsp, %rdi
        call    trap
        MEXITCOUNT
@@ -228,6 +229,7 @@ IDTVEC(dblfault)
        jz      1f
        swapgs
 1:     movq    %rsp, %rdi
+       cld
        call    dblfault_handler
 2:     hlt
        jmp     2b
@@ -409,6 +411,7 @@ nmi_needswapgs:
 /* Note: this label is also used by ddb and gdb: */
 nmi_calltrap:
        FAKE_MCOUNT(TF_RIP(%rsp))
+       cld
        movq    %rsp, %rdi
        call    trap
        MEXITCOUNT
index ff8f428..a16a35c 100644 (file)
@@ -474,7 +474,7 @@ splz_timer:
         */
 #define PUSH_DUMMY                                                     \
        pushfq ;                        /* phys int frame / flags */    \
-       movl    %cs,%eax ;                                              \
+       xorq    %rax,%rax ;             /* something not SEL_UPL */     \
        pushq   %rax ;                  /* phys int frame / cs */       \
        pushq   3*8(%rsp) ;             /* original caller eip */       \
        subq    $TF_RIP,%rsp ;          /* trap frame */                \
index 889a398..bbf3068 100644 (file)
@@ -1916,7 +1916,7 @@ hammer_time(u_int64_t modulep, u_int64_t physfree)
        msr = ((u_int64_t)GSEL(GCODE_SEL, SEL_KPL) << 32) |
              ((u_int64_t)GSEL(GUCODE32_SEL, SEL_UPL) << 48);
        wrmsr(MSR_STAR, msr);
-       wrmsr(MSR_SF_MASK, PSL_NT|PSL_T|PSL_I|PSL_C|PSL_D);
+       wrmsr(MSR_SF_MASK, PSL_NT|PSL_T|PSL_I|PSL_C|PSL_D|PSL_IOPL);
 
        getmemsize(kmdp, physfree);
        init_param2(physmem);
index 8a93861..e36fa99 100644 (file)
@@ -290,7 +290,7 @@ init_secondary(void)
        msr = ((u_int64_t)GSEL(GCODE_SEL, SEL_KPL) << 32) |
              ((u_int64_t)GSEL(GUCODE32_SEL, SEL_UPL) << 48);
        wrmsr(MSR_STAR, msr);
-       wrmsr(MSR_SF_MASK, PSL_NT|PSL_T|PSL_I|PSL_C|PSL_D);
+       wrmsr(MSR_SF_MASK, PSL_NT|PSL_T|PSL_I|PSL_C|PSL_D|PSL_IOPL);
 
        pmap_set_opt();         /* PSE/4MB pages, etc */
 #if JGXXX
index 14b543c..7c0c244 100644 (file)
@@ -163,6 +163,7 @@ ENTRY(cpu_heavy_switch)
         * PCB_RSP.  We push the flags for later restore by cpu_heavy_restore.
         */
        pushfq
+       cli
        movq    $cpu_heavy_restore, %rax
        pushq   %rax
        movq    %rsp,TD_SP(%rbx)
@@ -267,6 +268,7 @@ ENTRY(cpu_exit_switch)
         * thread but %rsp still points to the old thread's stack, but
         * we are protected by a critical section so it is ok.
         */
+       cli
        movq    %rdi,%rax
        movq    %rax,PCPU(curthread)
        movq    TD_SP(%rax),%rsp
@@ -478,6 +480,8 @@ ENTRY(cpu_heavy_restore)
        movq    PCB_R15(%rdx), %r15
        movq    PCB_RIP(%rdx), %rax
        movq    %rax, (%rsp)
+       movw    $KDSEL,%ax
+       movw    %ax,%es
 
 #if JG
        /*
@@ -704,6 +708,7 @@ ENTRY(cpu_lwkt_switch)
        pushq   %r14
        pushq   %r15
        pushfq
+       cli
 
 #if 1
        /*
index 3a936d1..70c48c1 100644 (file)
@@ -937,11 +937,11 @@ nogo:
        if (td->td_lwp->lwp_vkernel == NULL) {
                if (bootverbose || freeze_on_seg_fault || ddb_on_seg_fault) {
                        kprintf("seg-fault ft=%04x ff=%04x addr=%p rip=%p "
-                           "pid=%d p_comm=%s\n",
+                           "pid=%d cpu=%d p_comm=%s\n",
                            ftype, fault_flags,
                            (void *)frame->tf_addr,
                            (void *)frame->tf_rip,
-                           p->p_pid, p->p_comm);
+                           p->p_pid, mycpu->gd_cpuid, p->p_comm);
                }
 #ifdef DDB
                while (freeze_on_seg_fault) {
@@ -1276,6 +1276,9 @@ out:
                 * (which was holding the value of %rcx) is restored for
                 * the next iteration.
                 */
+               if (frame->tf_err != 0 && frame->tf_err != 2)
+                       kprintf("lp %s:%d frame->tf_err is weird %ld\n",
+                               td->td_comm, lp->lwp_proc->p_pid, frame->tf_err);
                frame->tf_rip -= frame->tf_err;
                frame->tf_r10 = frame->tf_rcx;
                break;
index 1e46db3..0a3797d 100644 (file)
@@ -201,7 +201,8 @@ cpu_prepare_lwp(struct lwp *lp, struct lwp_params *params)
        regs->tf_rip = (long)params->func;
        regs->tf_rsp = (long)params->stack;
        /* Set up argument for function call */
-       regs->tf_rdi = (long)params->arg; /* JG Can this be in userspace addresses? */
+       regs->tf_rdi = (long)params->arg;
+
        /*
         * Set up fake return address.  As the lwp function may never return,
         * we simply copy out a NULL pointer and force the lwp to receive
@@ -410,3 +411,68 @@ kvm_access_check(vm_offset_t saddr, vm_offset_t eaddr, int prot)
        return 0;
 }
 
+#if 0
+
+void _test_frame_enter(struct trapframe *frame);
+void _test_frame_exit(struct trapframe *frame);
+
+void
+_test_frame_enter(struct trapframe *frame)
+{
+       thread_t td = curthread;
+
+       if (ISPL(frame->tf_cs) == SEL_UPL) {
+               KKASSERT(td->td_lwp);
+                KASSERT(td->td_lwp->lwp_md.md_regs == frame,
+                        ("_test_frame_exit: Frame mismatch %p %p",
+                       td->td_lwp->lwp_md.md_regs, frame));
+           td->td_lwp->lwp_saveusp = (void *)frame->tf_rsp;
+           td->td_lwp->lwp_saveupc = (void *)frame->tf_rip;
+       }
+       if ((char *)frame < td->td_kstack ||
+           (char *)frame > td->td_kstack + td->td_kstack_size) {
+               panic("_test_frame_exit: frame not on kstack %p kstack=%p\n",
+                       frame, td->td_kstack);
+       }
+}
+
+void
+_test_frame_exit(struct trapframe *frame)
+{
+       thread_t td = curthread;
+
+       if (ISPL(frame->tf_cs) == SEL_UPL) {
+               KKASSERT(td->td_lwp);
+                KASSERT(td->td_lwp->lwp_md.md_regs == frame,
+                        ("_test_frame_exit: Frame mismatch %p %p",
+                       td->td_lwp->lwp_md.md_regs, frame));
+               if (td->td_lwp->lwp_saveusp != (void *)frame->tf_rsp) {
+                       kprintf("_test_frame_exit: %s:%d usp mismatch %p/%p\n",
+                               td->td_comm, td->td_proc->p_pid,
+                               td->td_lwp->lwp_saveusp,
+                               (void *)frame->tf_rsp);
+               }
+               if (td->td_lwp->lwp_saveupc != (void *)frame->tf_rip) {
+                       kprintf("_test_frame_exit: %s:%d upc mismatch %p/%p\n",
+                               td->td_comm, td->td_proc->p_pid,
+                               td->td_lwp->lwp_saveupc,
+                               (void *)frame->tf_rip);
+               }
+
+               /*
+                * adulterate the fields to catch entries that
+                * don't run through test_frame_enter
+                */
+               td->td_lwp->lwp_saveusp =
+                       (void *)~(intptr_t)td->td_lwp->lwp_saveusp;
+               td->td_lwp->lwp_saveupc =
+                       (void *)~(intptr_t)td->td_lwp->lwp_saveupc;
+       }
+       if ((char *)frame < td->td_kstack ||
+           (char *)frame > td->td_kstack + td->td_kstack_size) {
+               panic("_test_frame_exit: frame not on kstack %p kstack=%p\n",
+                       frame, td->td_kstack);
+       }
+}
+
+#endif
index 9ae50ce..ee829b4 100644 (file)
@@ -223,6 +223,8 @@ struct lwp {
        u_int           lwp_kqueue_serial;
        struct lwkt_token lwp_token;    /* per-lwp token for signal/state */
        struct spinlock lwp_spin;       /* spinlock for signal handling */
+       void            *lwp_reserveds1; /* reserved for lwp_saveusp */
+       void            *lwp_reserveds2; /* reserved for lwp_saveupc */
 };
 
 struct proc {