summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/boot/i386/btx/btx/btx.S95
1 files changed, 60 insertions, 35 deletions
diff --git a/sys/boot/i386/btx/btx/btx.S b/sys/boot/i386/btx/btx/btx.S
index 2f917e0..e762e4b 100644
--- a/sys/boot/i386/btx/btx/btx.S
+++ b/sys/boot/i386/btx/btx/btx.S
@@ -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
@@ -455,6 +456,18 @@ intx31: pushl $-1 # Dummy int no for btx_v86
* -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
@@ -467,12 +480,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
@@ -482,35 +498,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
@@ -522,6 +539,11 @@ intusr.4: testl $V86F_CALLF,%edx # Far call?
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
/*
@@ -536,8 +558,7 @@ intusr.5: movw %bx,MEM_ESPR-0x12 # Pass user flags to real mode
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
@@ -611,9 +632,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.
@@ -624,20 +652,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
OpenPOWER on IntegriCloud