Author: jhb
Date: Tue Mar  3 17:16:26 2009
New Revision: 189312
URL: http://svn.freebsd.org/changeset/base/189312

Log:
  MFC: Use a clean slate of register state when executing hardware interrupt
  handlers to avoid leaking values into the upper 16-bits of general purpose
  registers when executing these routines.

Modified:
  stable/4/sys/boot/i386/btx/btx/btx.s

Modified: stable/4/sys/boot/i386/btx/btx/btx.s
==============================================================================
--- stable/4/sys/boot/i386/btx/btx/btx.s        Tue Mar  3 17:15:05 2009        
(r189311)
+++ stable/4/sys/boot/i386/btx/btx/btx.s        Tue Mar  3 17:16:26 2009        
(r189312)
@@ -36,6 +36,7 @@
 #
 # Fields in %eflags.
 #
+               .set PSL_RESERVED_DEFAULT,0x00000002
                .set PSL_T,0x00000100           # Trap flag
                .set PSL_I,0x00000200           # Interrupt enable flag
                .set PSL_VM,0x00020000          # Virtual 8086 mode flag
@@ -452,6 +453,18 @@ intx31:    pushl $-1                       # Dummy int no 
for 
 # -0x3c %fs
 # -0x40 %ds
 # -0x44 %es
+# -0x48 zero %eax (hardware int only)  
+# -0x4c zero %ecx (hardware int only)
+# -0x50 zero %edx (hardware int only)
+# -0x54 zero %ebx (hardware int only)
+# -0x58 zero %esp (hardware int only)
+# -0x5c zero %ebp (hardware int only)
+# -0x60 zero %esi (hardware int only)
+# -0x64 zero %edi (hardware int only)
+# -0x68 zero %gs (hardware int only)
+# -0x6c zero %fs (hardware int only)
+# -0x70 zero %ds (hardware int only)
+# -0x74 zero %es (hardware int only)
 #
 int_hw:        cld                             # String ops inc
                pusha                           # Save gp regs
@@ -464,12 +477,15 @@ int_hw:   cld                             # String ops inc
                pushl %ds                       #  address
                popl %es                        #  data
                leal 0x44(%esp,1),%esi          # Base of frame
+               movl %esp,MEM_ESPR-0x04         # Save kernel stack pointer
                movl -0x14(%esi),%eax           # Get Int no
                cmpl $-1,%eax                   # Hardware interrupt?
-               jne intusr.2                    # Yes
+               jne intusr.1                    # Yes
 #
-# v86 calls save the btx_v86 pointer on the real mode stack and read the
-# address and flags from the btx_v86 structure.
+# v86 calls save the btx_v86 pointer on the real mode stack and read
+# the address and flags from the btx_v86 structure.  For interrupt
+# handler invocations (VM86 INTx requests), disable interrupts,
+# tracing, and alignment checking while the handler runs.
 #
                movl $MEM_USR,%ebx              # User base
                movl %ebx,%edx                  #  address
@@ -479,35 +495,36 @@ int_hw:   cld                             # String ops inc
                movl %edx,MEM_ESPR-0x08         # Save btx_v86 ptr
                movl V86_ADDR(%edx),%eax        # Get int no/address
                movl V86_CTL(%edx),%edx         # Get control flags
+               movl -0x08(%esi),%ebx           # Save user flags in %ebx
+               testl $V86F_ADDR,%edx           # Segment:offset?
+               jnz intusr.4                    # Yes
+               andl $~(PSL_I|PSL_T|PSL_AC),%ebx # Disable interrupts, tracing,
+                                               #  and alignment checking for
+                                               #  interrupt handler
                jmp intusr.3                    # Skip hardware interrupt
 #
-# Hardware interrupts store a NULL btx_v86 pointer and use the address
-# (interrupt number) from the stack with empty flags.  Also, we clear
-# the segment registers for the interrupt handler.
+# Hardware interrupts store a NULL btx_v86 pointer and use the
+# address (interrupt number) from the stack with empty flags.  Also,
+# push a dummy frame of zeros onto the stack for all the general
+# purpose and segment registers and clear %eflags.  This gives the
+# hardware interrupt handler a clean slate.
 #
-intusr.2:      xorl %edx,%edx                  # Control flags
+intusr.1:      xorl %edx,%edx                  # Control flags
                movl %edx,MEM_ESPR-0x08         # NULL btx_v86 ptr
-               movl %edx,-0x38(%esi)           # Real mode %gs of 0
-               movl %edx,-0x3c(%esi)           # Real mode %fs of 0
-               movl %edx,-0x40(%esi)           # Real mode %ds of 0
-               movl %edx,-0x44(%esi)           # Real mode %es of 0
+               movl $12,%ecx                   # Frame is 12 dwords
+intusr.2:      pushl $0x0                      # Fill frame
+               loop intusr.2                   #  with zeros
+               movl $PSL_RESERVED_DEFAULT,%ebx # Set clean %eflags
 #
-# %eax now holds either the interrupt number or segment:offset of function.
-# %edx now holds the V86F_* flags.
-#
-# For interrupt handler invocations (either hardware interrupts or VM86
-# INTx requests) we also disable interrupts, tracing, and alignment checking
-# while the handler runs.
+# Look up real mode IDT entry for hardware interrupts and VM86 INTx
+# requests.
 #
-intusr.3:      movl -0x08(%esi),%ebx           # Save user flags in %ebx
-               testl $V86F_ADDR,%edx           # Segment:offset?
-               jnz intusr.4                    # Yes
-               shll $0x2,%eax                  # Scale
+intusr.3:      shll $0x2,%eax                  # Scale
                movl (%eax),%eax                # Load int vector
-               andl $~(PSL_I|PSL_T|PSL_AC),%ebx # Disable interrupts, tracing,
-                                               #  and alignment checking for
-                                               #  interrupt handler
                jmp intusr.5                    # Skip CALLF test
+#
+# Panic if V86F_CALLF isn't set with V86F_ADDR.
+#
 intusr.4:      testl $V86F_CALLF,%edx          # Far call?
                jnz intusr.5                    # Ok
                movl %edx,0x30(%esp,1)          # Place VM86 flags in int no
@@ -519,6 +536,11 @@ intusr.4:  testl $V86F_CALLF,%edx          # Far 
                popl %gs
                popal                           # Restore gp regs
                jmp ex_noc                      # Panic
+#
+# %eax now holds the segment:offset of the function.
+# %ebx now holds the %eflags to pass to real mode.
+# %edx now holds the V86F_* flags.
+#
 intusr.5:      movw %bx,MEM_ESPR-0x12          # Pass user flags to real mode
                                                #  target
 #
@@ -533,8 +555,7 @@ intusr.5:   movw %bx,MEM_ESPR-0x12          # Pass
                rep                             #  from btx_v86
                movsl                           #  to kernel stack
                popl %esi                       # Restore
-intusr.6:      movl %esp,MEM_ESPR-0x04         # Save kernel stack pointer
-               movl -0x08(%esi),%ebx           # Copy user flags to real
+intusr.6:      movl -0x08(%esi),%ebx           # Copy user flags to real
                movl %ebx,MEM_ESPR-0x0c         #  mode return trampoline
                movl $rret_tramp,%ebx           # Set return trampoline
                movl %ebx,MEM_ESPR-0x10         #  CS:IP
@@ -608,9 +629,16 @@ rret_tramp.1:      xorl %ecx,%ecx                  # Zero
                movb $SEL_TSS,%cl               # Set task
                ltr %cx                         #  register
 #
-# Now we are back in protected mode.  Copy the registers off of the real
-# mode stack onto the kernel stack.  Also, initialize all the seg regs on
-# the kernel stack.
+# Now we are back in protected mode.  The kernel stack frame set up
+# before entering real mode is still intact. For hardware interrupts,
+# leave the frame unchanged.
+#
+               cmpl $0,MEM_ESPR-0x08           # Leave saved regs unchanged
+               jz rret_tramp.3                 #  for hardware ints
+#
+# For V86 calls, copy the registers off of the real mode stack onto
+# the kernel stack as we want their updated values.  Also, initialize
+# the segment registers on the kernel stack.
 #
 # Note that the %esp in the kernel stack after this is garbage, but popa
 # ignores it, so we don't have to fix it up.
@@ -621,20 +649,17 @@ rret_tramp.1:     xorl %ecx,%ecx                  # Zero
                movl $8,%ecx                    # Copy GP regs from
                rep                             #  real mode stack
                movsl                           #  to kernel stack
-               popl %esi                       # Restore
                movl $SEL_UDATA,%eax            # Selector for data seg regs
                movl $4,%ecx                    # Initialize %ds,
                rep                             #  %es, %fs, and
                stosl                           #  %gs
 #
-# If this was a V86 call, copy the saved seg regs on the real mode stack
-# back over to the btx_v86 structure.  Also, conditionally update the saved
-# eflags on the kernel stack based on the flags from the user.
+# For V86 calls, copy the saved seg regs on the real mode stack back
+# over to the btx_v86 structure.  Also, conditionally update the
+# saved eflags on the kernel stack based on the flags from the user.
 #
                movl MEM_ESPR-0x08,%ecx         # Get btx_v86 ptr
-               jecxz rret_tramp.3              # Skip for hardware ints
                leal V86_GS(%ecx),%edi          # %edi => btx_v86 seg regs
-               pushl %esi                      # Save
                leal MEM_ESPR-0x2c,%esi         # %esi => real mode seg regs
                xchgl %ecx,%edx                 # Save btx_v86 ptr
                movl $4,%ecx                    # Copy seg regs
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to