Date: Tue, 3 Mar 2009 17:16:26 +0000 (UTC) From: John Baldwin <jhb@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-other@freebsd.org Subject: svn commit: r189312 - stable/4/sys/boot/i386/btx/btx Message-ID: <200903031716.n23HGQfD016733@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200903031716.n23HGQfD016733>