summaryrefslogtreecommitdiffstats
path: root/sys/boot/pc98/btx
diff options
context:
space:
mode:
authornyan <nyan@FreeBSD.org>2009-12-08 13:04:26 +0000
committernyan <nyan@FreeBSD.org>2009-12-08 13:04:26 +0000
commit8deeaefd93eaf35d983592e19be360bad03660d4 (patch)
treea3a68e970deba518db281b5c1273037979d851cd /sys/boot/pc98/btx
parent1c9f1ea6d355743e879a297091891c764b4da6ef (diff)
downloadFreeBSD-src-8deeaefd93eaf35d983592e19be360bad03660d4.zip
FreeBSD-src-8deeaefd93eaf35d983592e19be360bad03660d4.tar.gz
MFi386: Use real mode instead of v86 mode.
MFC after: 1 week
Diffstat (limited to 'sys/boot/pc98/btx')
-rw-r--r--sys/boot/pc98/btx/btx/btx.S771
1 files changed, 361 insertions, 410 deletions
diff --git a/sys/boot/pc98/btx/btx/btx.S b/sys/boot/pc98/btx/btx/btx.S
index 7d22b27..95788d4 100644
--- a/sys/boot/pc98/btx/btx/btx.S
+++ b/sys/boot/pc98/btx/btx/btx.S
@@ -21,11 +21,11 @@
.set MEM_BTX,0x1000 # Start of BTX memory
.set MEM_ESP0,0x1800 # Supervisor stack
.set MEM_BUF,0x1800 # Scratch buffer
- .set MEM_ESP1,0x1e00 # Link stack
- .set MEM_IDT,0x1e00 # IDT
- .set MEM_TSS,0x1f98 # TSS
- .set MEM_MAP,0x2000 # I/O bit map
- .set MEM_TSS_END,0x3fff # Page directory
+ .set MEM_ESPR,0x5e00 # Real mode stack
+ .set MEM_IDT,0x5e00 # IDT
+ .set MEM_TSS,0x5f98 # TSS
+ .set MEM_MAP,0x6000 # I/O bit map
+ .set MEM_TSS_END,0x7fff # End of TSS
.set MEM_ORG,0x9000 # BTX code
.set MEM_USR,0xa000 # Start of user memory
/*
@@ -34,6 +34,14 @@
.set PAG_SIZ,0x1000 # Page size
.set PAG_CNT,0x1000 # Pages to map
/*
+ * 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
+ .set PSL_AC,0x00040000 # Alignment check flag
+/*
* Segment selectors.
*/
.set SEL_SCODE,0x8 # Supervisor code
@@ -48,7 +56,6 @@
*/
.set TSS_ESP0,0x4 # PL 0 ESP
.set TSS_SS0,0x8 # PL 0 SS
- .set TSS_ESP1,0xc # PL 1 ESP
.set TSS_MAP,0x66 # I/O bit map base
/*
* System calls.
@@ -56,10 +63,20 @@
.set SYS_EXIT,0x0 # Exit
.set SYS_EXEC,0x1 # Exec
/*
- * V86 constants.
+ * Fields in V86 interface structure.
+ */
+ .set V86_CTL,0x0 # Control flags
+ .set V86_ADDR,0x4 # Int number/address
+ .set V86_ES,0x8 # V86 ES
+ .set V86_DS,0xc # V86 DS
+ .set V86_FS,0x10 # V86 FS
+ .set V86_GS,0x14 # V86 GS
+/*
+ * V86 control flags.
*/
- .set V86_FLG,0x208eff # V86 flag mask
- .set V86_STK,0x400 # V86 stack allowance
+ .set V86F_ADDR,0x10000 # Segment:offset address
+ .set V86F_CALLF,0x20000 # Emulate far call
+ .set V86F_FLAGS,0x40000 # Return flags
/*
* Dump format control bytes.
*/
@@ -77,13 +94,11 @@
* BIOS Data Area locations.
*/
.set BDA_MEM,0x501 # Free memory
- .set BDA_KEYFLAGS,0x53a # Keyboard shift-state flags
.set BDA_POS,0x53e # Cursor position
/*
* Derivations, for brevity.
*/
.set _ESP0H,MEM_ESP0>>0x8 # Byte 1 of ESP0
- .set _ESP1H,MEM_ESP1>>0x8 # Byte 1 of ESP1
.set _TSSIO,MEM_MAP-MEM_TSS # TSS I/O base
.set _TSSLM,MEM_TSS_END-MEM_TSS # TSS limit
.set _IDTLM,MEM_TSS-MEM_IDT-1 # IDT limit
@@ -100,7 +115,7 @@ btx_hdr: .byte 0xeb # Machine ID
.byte 0xe # Header size
.ascii "BTX" # Magic
.byte 0x1 # Major version
- .byte 0x1 # Minor version
+ .byte 0x2 # Minor version
.byte BTX_FLAGS # Flags
.word PAG_CNT-MEM_ORG>>0xc # Paging control
.word break-start # Text size
@@ -121,13 +136,24 @@ init: cli # Disable interrupts
*/
mov $MEM_IDT,%di # Memory to initialize
mov $(MEM_ORG-MEM_IDT)/2,%cx # Words to zero
- push %di # Save
rep # Zero-fill
stosw # memory
- pop %di # Restore
+/*
+ * Update real mode IDT for reflecting hardware interrupts.
+ */
+ mov $intr20,%bx # Address first handler
+ mov $0x10,%cx # Number of handlers
+ mov $0x20*4,%di # First real mode IDT entry
+init.0: mov %bx,(%di) # Store IP
+ inc %di # Address next
+ inc %di # entry
+ stosw # Store CS
+ add $4,%bx # Next handler
+ loop init.0 # Next IRQ
/*
* Create IDT.
*/
+ mov $MEM_IDT,%di
mov $idtctl,%si # Control string
init.1: lodsb # Get entry
cbw # count
@@ -153,7 +179,6 @@ init.3: lea 0x8(%di),%di # Next entry
*/
init.4: movb $_ESP0H,TSS_ESP0+1(%di) # Set ESP0
movb $SEL_SDATA,TSS_SS0(%di) # Set SS0
- movb $_ESP1H,TSS_ESP1+1(%di) # Set ESP1
movb $_TSSIO,TSS_MAP(%di) # Set I/O bit map base
/*
* Bring up the system.
@@ -253,8 +278,8 @@ exit.2: xor %ax,%ax # Real mode segment
exit.3: jz exit.3 # No
movb $0xa0,%al
outb %al,$0x35
- movb 0,%al
- outb %al,$0xf0
+ movb $0x00,%al
+ outb %al,$0xf0 # reboot the machine
exit.4: jmp exit.4
/*
* Set IRQ offsets by reprogramming 8259A PICs.
@@ -285,10 +310,6 @@ setpic: in $0x02,%al # Save master
retw # To caller
.code32
/*
- * Initiate return from V86 mode to user mode.
- */
-inthlt: hlt # To supervisor mode
-/*
* Exception jump table.
*/
intx00: push $0x0 # Int 0x0: #DE
@@ -314,18 +335,12 @@ intx00: push $0x0 # Int 0x0: #DE
push $0xc # Int 0xc: #SS
jmp except # Stack segment fault
push $0xd # Int 0xd: #GP
- jmp ex_v86 # General protection
+ jmp except # General protection
push $0xe # Int 0xe: #PF
jmp except # Page fault
intx10: push $0x10 # Int 0x10: #MF
jmp ex_noc # Floating-point error
/*
- * Handle #GP exception.
- */
-ex_v86: testb $0x2,0x12(%esp,1) # V86 mode?
- jz except # No
- jmp v86mon # To monitor
-/*
* Save a zero error code.
*/
ex_noc: pushl (%esp,1) # Duplicate int no
@@ -337,24 +352,17 @@ except: cld # String ops inc
pushl %ds # Save
pushl %es # most
pusha # registers
- movb $0x6,%al # Push loop count
- testb $0x2,0x3a(%esp,1) # V86 mode?
- jnz except.1 # Yes
pushl %gs # Set GS
pushl %fs # Set FS
pushl %ds # Set DS
pushl %es # Set ES
- movb $0x2,%al # Push loop count
cmpw $SEL_SCODE,0x44(%esp,1) # Supervisor mode?
jne except.1 # No
pushl %ss # Set SS
- leal 0x50(%esp,1),%eax # Set
- pushl %eax # ESP
jmp except.2 # Join common code
-except.1: pushl 0x50(%esp,1) # Set GS, FS, DS, ES
- decb %al # (if V86 mode), and
- jne except.1 # SS, ESP
-except.2: push $SEL_SDATA # Set up
+except.1: pushl 0x50(%esp,1) # Set SS
+except.2: pushl 0x50(%esp,1) # Set ESP
+ push $SEL_SDATA # Set up
popl %ds # to
pushl %ds # address
popl %es # data
@@ -363,14 +371,12 @@ except.2: push $SEL_SDATA # Set up
movl $MEM_BUF,%edi # Buffer
pushl %eax
pushl %edx
-wait.1:
- inb $0x60,%al
+wait.1: inb $0x60,%al
testb $0x04,%al
jz wait.1
movb $0xe0,%al
outb %al,$0x62
-wait.2:
- inb $0x60,%al
+wait.2: inb $0x60,%al
testb $0x01,%al
jz wait.2
xorl %edx,%edx
@@ -399,237 +405,11 @@ wait.2:
je except.3 # Yes
cmpb $0x1,(%esp,1) # Debug?
jne except.2a # No
- testl $0x100,0x10(%esp,1) # Trap flag set?
+ testl $PSL_T,0x10(%esp,1) # Trap flag set?
jnz except.3 # Yes
except.2a: jmp exit # Exit
except.3: leal 0x8(%esp,1),%esp # Discard err, int no
iret # From interrupt
-/*
- * Return to user mode from V86 mode.
- */
-intrtn: cld # String ops inc
- pushl %ds # Address
- popl %es # data
- leal 0x3c(%ebp),%edx # V86 Segment registers
- movl MEM_TSS+TSS_ESP1,%esi # Link stack pointer
- lodsl # INT_V86 args pointer
- movl %esi,%ebx # Saved exception frame
- testl %eax,%eax # INT_V86 args?
- jz intrtn.2 # No
- movl $MEM_USR,%edi # User base
- movl 0x1c(%esi),%ebx # User ESP
- movl %eax,(%edi,%ebx,1) # Restore to user stack
- leal 0x8(%edi,%eax,1),%edi # Arg segment registers
- testb $0x4,-0x6(%edi) # Return flags?
- jz intrtn.1 # No
- movl 0x30(%ebp),%eax # Get V86 flags
- movw %ax,0x18(%esi) # Set user flags
-intrtn.1: leal 0x10(%esi),%ebx # Saved exception frame
- xchgl %edx,%esi # Segment registers
- movb $0x4,%cl # Update seg regs
- rep # in INT_V86
- movsl # args
-intrtn.2: xchgl %edx,%esi # Segment registers
- leal 0x28(%ebp),%edi # Set up seg
- movb $0x4,%cl # regs for
- rep # later
- movsl # pop
- xchgl %ebx,%esi # Restore exception
- movb $0x5,%cl # frame to
- rep # supervisor
- movsl # stack
- movl %esi,MEM_TSS+TSS_ESP1 # Link stack pointer
- popa # Restore
- leal 0x8(%esp,1),%esp # Discard err, int no
- popl %es # Restore
- popl %ds # user
- popl %fs # segment
- popl %gs # registers
- iret # To user mode
-/*
- * V86 monitor.
- */
-v86mon: cld # String ops inc
- pushl $SEL_SDATA # Set up for
- popl %ds # flat addressing
- pusha # Save registers
- movl %esp,%ebp # Address stack frame
- movzwl 0x2c(%ebp),%edi # Load V86 CS
- shll $0x4,%edi # To linear
- movl 0x28(%ebp),%esi # Load V86 IP
- addl %edi,%esi # Code pointer
- xorl %ecx,%ecx # Zero
- movb $0x2,%cl # 16-bit operands
- xorl %eax,%eax # Zero
-v86mon.1: lodsb # Get opcode
- cmpb $0x66,%al # Operand size prefix?
- jne v86mon.2 # No
- movb $0x4,%cl # 32-bit operands
- jmp v86mon.1 # Continue
-v86mon.2: cmpb $0xf4,%al # HLT?
- jne v86mon.3 # No
- cmpl $inthlt+0x1,%esi # Is inthlt?
- jne v86mon.7 # No (ignore)
- jmp intrtn # Return to user mode
-v86mon.3: cmpb $0xf,%al # Prefixed instruction?
- jne v86mon.4 # No
- cmpb $0x09,(%esi) # Is it a WBINVD?
- je v86wbinvd # Yes
- cmpb $0x30,(%esi) # Is it a WRMSR?
- je v86wrmsr # Yes
- cmpb $0x32,(%esi) # Is it a RDMSR?
- je v86rdmsr # Yes
- cmpb $0x20,(%esi) # Is this a MOV reg,CRx?
- je v86mov # Yes
-v86mon.4: cmpb $0xfa,%al # CLI?
- je v86cli # Yes
- cmpb $0xfb,%al # STI?
- je v86sti # Yes
- movzwl 0x38(%ebp),%ebx # Load V86 SS
- shll $0x4,%ebx # To offset
- pushl %ebx # Save
- addl 0x34(%ebp),%ebx # Add V86 SP
- movl 0x30(%ebp),%edx # Load V86 flags
- cmpb $0x9c,%al # PUSHF/PUSHFD?
- je v86pushf # Yes
- cmpb $0x9d,%al # POPF/POPFD?
- je v86popf # Yes
- cmpb $0xcd,%al # INT imm8?
- je v86intn # Yes
- cmpb $0xcf,%al # IRET/IRETD?
- je v86iret # Yes
- popl %ebx # Restore
- popa # Restore
- jmp except # Handle exception
-v86mon.5: movl %edx,0x30(%ebp) # Save V86 flags
-v86mon.6: popl %edx # V86 SS adjustment
- subl %edx,%ebx # Save V86
- movl %ebx,0x34(%ebp) # SP
-v86mon.7: subl %edi,%esi # From linear
- movl %esi,0x28(%ebp) # Save V86 IP
- popa # Restore
- leal 0x8(%esp,1),%esp # Discard int no, error
- iret # To V86 mode
-/*
- * Emulate MOV reg,CRx.
- */
-v86mov: movb 0x1(%esi),%bl # Fetch Mod R/M byte
- testb $0x10,%bl # Read CR2 or CR3?
- jnz v86mov.1 # Yes
- movl %cr0,%eax # Read CR0
- testb $0x20,%bl # Read CR4 instead?
- jz v86mov.2 # No
- movl %cr4,%eax # Read CR4
- jmp v86mov.2
-v86mov.1: movl %cr2,%eax # Read CR2
- testb $0x08,%bl # Read CR3 instead?
- jz v86mov.2 # No
- movl %cr3,%eax # Read CR3
-v86mov.2: andl $0x7,%ebx # Compute offset in
- shl $2,%ebx # frame of destination
- neg %ebx # register
- movl %eax,0x1c(%ebp,%ebx,1) # Store CR to reg
- incl %esi # Adjust IP
-/*
- * Return from emulating a 0x0f prefixed instruction
- */
-v86preret: incl %esi # Adjust IP
- jmp v86mon.7 # Finish up
-/*
- * Emulate WBINVD
- */
-v86wbinvd: wbinvd # Write back and invalidate
- # cache
- jmp v86preret # Finish up
-/*
- * Emulate WRMSR
- */
-v86wrmsr: movl 0x18(%ebp),%ecx # Get user's %ecx (MSR to write)
- movl 0x14(%ebp),%edx # Load the value
- movl 0x1c(%ebp),%eax # to write
- wrmsr # Write MSR
- jmp v86preret # Finish up
-/*
- * Emulate RDMSR
- */
-v86rdmsr: movl 0x18(%ebp),%ecx # MSR to read
- rdmsr # Read the MSR
- movl %eax,0x1c(%ebp) # Return the value of
- movl %edx,0x14(%ebp) # the MSR to the user
- jmp v86preret # Finish up
-/*
- * Emulate CLI.
- */
-v86cli: andb $~0x2,0x31(%ebp) # Clear IF
- jmp v86mon.7 # Finish up
-/*
- * Emulate STI.
- */
-v86sti: orb $0x2,0x31(%ebp) # Set IF
- jmp v86mon.7 # Finish up
-/*
- * Emulate PUSHF/PUSHFD.
- */
-v86pushf: subl %ecx,%ebx # Adjust SP
- cmpb $0x4,%cl # 32-bit
- je v86pushf.1 # Yes
- data16 # 16-bit
-v86pushf.1: movl %edx,(%ebx) # Save flags
- jmp v86mon.6 # Finish up
-/*
- * Emulate IRET/IRETD.
- */
-v86iret: movzwl (%ebx),%esi # Load V86 IP
- movzwl 0x2(%ebx),%edi # Load V86 CS
- leal 0x4(%ebx),%ebx # Adjust SP
- movl %edi,0x2c(%ebp) # Save V86 CS
- xorl %edi,%edi # No ESI adjustment
-/*
- * Emulate POPF/POPFD (and remainder of IRET/IRETD).
- */
-v86popf: cmpb $0x4,%cl # 32-bit?
- je v86popf.1 # Yes
- movl %edx,%eax # Initialize
- data16 # 16-bit
-v86popf.1: movl (%ebx),%eax # Load flags
- addl %ecx,%ebx # Adjust SP
- andl $V86_FLG,%eax # Merge
- andl $~V86_FLG,%edx # the
- orl %eax,%edx # flags
- jmp v86mon.5 # Finish up
-/*
- * trap int 15, function 87
- * reads %es:%si from saved registers on stack to find a GDT containing
- * source and destination locations
- * reads count of words from saved %cx
- * returns success by setting %ah to 0
- */
-int15_87: pushl %esi # Save
- pushl %edi # registers
- movl 0x3C(%ebp),%edi # Load ES
- movzwl 0x4(%ebp),%eax # Load user's SI
- shll $0x4,%edi # EDI = (ES << 4) +
- addl %eax,%edi # SI
- movl 0x11(%edi),%eax # Read base of
- movb 0x17(%edi),%al # GDT entry
- ror $8,%eax # for source
- xchgl %eax,%esi # into %esi
- movl 0x19(%edi),%eax # Read base of
- movb 0x1f(%edi),%al # GDT entry for
- ror $8,%eax # destination
- xchgl %eax,%edi # into %edi
- pushl %ds # Make:
- popl %es # es = ds
- movzwl 0x18(%ebp),%ecx # Get user's CX
- shll $0x1,%ecx # Convert count from words
- rep # repeat...
- movsb # perform copy.
- popl %edi # Restore
- popl %esi # registers
- movb $0x0,0x1d(%ebp) # set ah = 0 to indicate
- # success
- andb $0xfe,%dl # clear CF
- jmp v86mon.5 # Finish up
/*
* Reboot the machine by setting the reboot flag and exiting
@@ -638,36 +418,7 @@ reboot: orb $0x1,btx_hdr+0x7 # Set the reboot flag
jmp exit # Terminate BTX and reboot
/*
- * Emulate INT imm8... also make sure to check if it's int 15/87
- */
-v86intn: lodsb # Get int no
- cmpb $0x19,%al # is it int 19?
- je reboot # yes, reboot the machine
- cmpb $0x15,%al # is it int 15?
- jne v86intn.1 # no, skip parse
- cmpb $0x87,0x1d(%ebp) # is it the memcpy subfunction?
- je int15_87 # yes
- cmpw $0x4f53,0x1c(%ebp) # is it the delete key callout?
- jne v86intn.1 # no, handle the int normally
- movb BDA_KEYFLAGS,%ch # get the shift key state
- andb $0x18,%ch # mask off just Ctrl and Alt
- cmpb $0x18,%ch # are both Ctrl and Alt down?
- je reboot # yes, reboot the machine
-v86intn.1: subl %edi,%esi # From
- shrl $0x4,%edi # linear
- movw %dx,-0x2(%ebx) # Save flags
- movw %di,-0x4(%ebx) # Save CS
- leal -0x6(%ebx),%ebx # Adjust SP
- movw %si,(%ebx) # Save IP
- shll $0x2,%eax # Scale
- movzwl (%eax),%esi # Load IP
- movzwl 0x2(%eax),%edi # Load CS
- movl %edi,0x2c(%ebp) # Save CS
- xorl %edi,%edi # No ESI adjustment
- andb $~0x1,%dh # Clear TF
- jmp v86mon.5 # Finish up
-/*
- * Hardware interrupt jump table.
+ * Protected Mode Hardware interrupt jump table.
*/
intx20: push $0x8 # Int 0x20: IRQ0
jmp int_hw # V86 int 0x8
@@ -701,127 +452,267 @@ intx20: push $0x8 # Int 0x20: IRQ0
jmp int_hw # V86 int 0x16
push $0x17 # Int 0x2f: IRQ15
jmp int_hw # V86 int 0x17
+
+/*
+ * Invoke real mode interrupt/function call from user mode with arguments.
+ */
+intx31: pushl $-1 # Dummy int no for btx_v86
/*
- * Reflect hardware interrupts.
- */
-int_hw: testb $0x2,0xe(%esp,1) # V86 mode?
- jz intusr # No
- pushl $SEL_SDATA # Address
- popl %ds # data
- xchgl %eax,(%esp,1) # Swap EAX, int no
- pushl %ebp # Address
- movl %esp,%ebp # stack frame
- pushl %ebx # Save
- shll $0x2,%eax # Get int
- movl (%eax),%eax # vector
- subl $0x6,0x14(%ebp) # Adjust V86 ESP
- movzwl 0x18(%ebp),%ebx # V86 SS
- shll $0x4,%ebx # * 0x10
- addl 0x14(%ebp),%ebx # + V86 ESP
- xchgw %ax,0x8(%ebp) # Swap V86 IP
- rorl $0x10,%eax # Swap words
- xchgw %ax,0xc(%ebp) # Swap V86 CS
- roll $0x10,%eax # Swap words
- movl %eax,(%ebx) # CS:IP for IRET
- movl 0x10(%ebp),%eax # V86 flags
- movw %ax,0x4(%ebx) # Flags for IRET
- andb $~0x3,0x11(%ebp) # Clear IF, TF
- popl %ebx # Restore
- popl %ebp # saved
- popl %eax # registers
- iret # To V86 mode
-/*
- * Invoke V86 interrupt from user mode, with arguments.
- */
-intx31: stc # Have btx_v86
- pushl %eax # Missing int no
-/*
- * Invoke V86 interrupt from user mode.
- */
-intusr: std # String ops dec
- pushl %eax # Expand
- pushl %eax # stack
- pushl %eax # frame
- pusha # Save
+ * Invoke real mode interrupt/function call from protected mode.
+ *
+ * We place a trampoline on the user stack that will return to rret_tramp
+ * which will reenter protected mode and then finally return to the user
+ * client.
+ *
+ * Kernel frame %esi points to: Real mode stack frame at MEM_ESPR:
+ *
+ * -0x00 user %ss -0x04 kernel %esp (with full frame)
+ * -0x04 user %esp -0x08 btx_v86 pointer
+ * -0x08 user %eflags -0x0c flags (only used if interrupt)
+ * -0x0c user %cs -0x10 real mode CS:IP return trampoline
+ * -0x10 user %eip -0x12 real mode flags
+ * -0x14 int no -0x16 real mode CS:IP (target)
+ * -0x18 %eax
+ * -0x1c %ecx
+ * -0x20 %edx
+ * -0x24 %ebx
+ * -0x28 %esp
+ * -0x2c %ebp
+ * -0x30 %esi
+ * -0x34 %edi
+ * -0x38 %gs
+ * -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
pushl %gs # Save
- movl %esp,%eax # seg regs
- pushl %fs # and
- pushl %ds # point
- pushl %es # to them
+ pushl %fs # seg
+ pushl %ds # regs
+ pushl %es
push $SEL_SDATA # Set up
popl %ds # to
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.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. 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
- jc intusr.1 # If btx_v86
- xorl %edx,%edx # Control flags
- xorl %ebp,%ebp # btx_v86 pointer
-intusr.1: leal 0x50(%esp,1),%esi # Base of frame
- pushl %esi # Save
addl -0x4(%esi),%ebx # User ESP
- movl MEM_TSS+TSS_ESP1,%edi # Link stack pointer
- leal -0x4(%edi),%edi # Adjust for push
- xorl %ecx,%ecx # Zero
- movb $0x5,%cl # Push exception
- rep # frame on
- movsl # link stack
- xchgl %eax,%esi # Saved seg regs
- movl 0x40(%esp,1),%eax # Get int no
- testl %edx,%edx # Have btx_v86?
- jz intusr.2 # No
movl (%ebx),%ebp # btx_v86 pointer
- movb $0x4,%cl # Count
- addl %ecx,%ebx # Adjust for pop
- rep # Push saved seg regs
- movsl # on link stack
addl %ebp,%edx # Flatten btx_v86 ptr
- leal 0x14(%edx),%esi # Seg regs pointer
- movl 0x4(%edx),%eax # Get int no/address
- movzwl 0x2(%edx),%edx # Get control flags
-intusr.2: movl %ebp,(%edi) # Push btx_v86 and
- movl %edi,MEM_TSS+TSS_ESP1 # save link stack ptr
- popl %edi # Base of frame
- xchgl %eax,%ebp # Save intno/address
- movl 0x48(%esp,1),%eax # Get flags
- testb $0x2,%dl # Simulate CALLF?
- jnz intusr.3 # Yes
- decl %ebx # Push flags
- decl %ebx # on V86
- movw %ax,(%ebx) # stack
-intusr.3: movb $0x4,%cl # Count
- subl %ecx,%ebx # Push return address
- movl $inthlt,(%ebx) # on V86 stack
- rep # Copy seg regs to
- movsl # exception frame
- xchgl %eax,%ecx # Save flags
- movl %ebx,%eax # User ESP
- subl $V86_STK,%eax # Less bytes
- ja intusr.4 # to
- xorl %eax,%eax # keep
-intusr.4: shrl $0x4,%eax # Gives segment
- stosl # Set SS
- shll $0x4,%eax # To bytes
- xchgl %eax,%ebx # Swap
- subl %ebx,%eax # Gives offset
- stosl # Set ESP
- xchgl %eax,%ecx # Get flags
- btsl $0x11,%eax # Set VM
- andb $~0x1,%ah # Clear TF
- stosl # Set EFL
- xchgl %eax,%ebp # Get int no/address
- testb $0x1,%dl # Address?
- jnz intusr.5 # Yes
- shll $0x2,%eax # Scale
+ 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,
+ * 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.1: xorl %edx,%edx # Control flags
+ movl %edx,MEM_ESPR-0x08 # NULL btx_v86 ptr
+ 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
+/*
+ * Look up real mode IDT entry for hardware interrupts and VM86 INTx
+ * requests.
+ */
+intusr.3: shll $0x2,%eax # Scale
movl (%eax),%eax # Load int vector
-intusr.5: movl %eax,%ecx # Save
- shrl $0x10,%eax # Gives segment
- stosl # Set CS
- movw %cx,%ax # Restore
- stosl # Set EIP
- leal 0x10(%esp,1),%esp # Discard seg regs
- popa # Restore
- iret # To V86 mode
+ 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
+ movl $badvm86,%esi # Display bad
+ call putstr # VM86 call
+ popl %es # Restore
+ popl %ds # seg
+ popl %fs # regs
+ 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
+/*
+ * If this is a v86 call, copy the seg regs out of the btx_v86 structure.
+ */
+ movl MEM_ESPR-0x08,%ecx # Get btx_v86 ptr
+ jecxz intusr.6 # Skip for hardware ints
+ leal -0x44(%esi),%edi # %edi => kernel stack seg regs
+ pushl %esi # Save
+ leal V86_ES(%ecx),%esi # %esi => btx_v86 seg regs
+ movl $4,%ecx # Copy seg regs
+ rep # from btx_v86
+ movsl # to kernel stack
+ popl %esi # Restore
+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
+ movl %eax,MEM_ESPR-0x16 # Real mode target CS:IP
+ ljmpw $SEL_RCODE,$intusr.7 # Change to 16-bit segment
+ .code16
+intusr.7: movl %cr0,%eax # Leave
+ dec %al # protected
+ movl %eax,%cr0 # mode
+ ljmpw $0x0,$intusr.8
+intusr.8: xorw %ax,%ax # Reset %ds
+ movw %ax,%ds # and
+ movw %ax,%ss # %ss
+ lidt ivtdesc # Set IVT
+ popl %es # Restore
+ popl %ds # seg
+ popl %fs # regs
+ popl %gs
+ popal # Restore gp regs
+ movw $MEM_ESPR-0x16,%sp # Switch to real mode stack
+ iret # Call target routine
+/*
+ * For the return to real mode we setup a stack frame like this on the real
+ * mode stack. Note that callf calls won't pop off the flags, but we just
+ * ignore that by repositioning %sp to be just above the btx_v86 pointer
+ * so it is aligned. The stack is relative to MEM_ESPR.
+ *
+ * -0x04 kernel %esp
+ * -0x08 btx_v86
+ * -0x0c %eax
+ * -0x10 %ecx
+ * -0x14 %edx
+ * -0x18 %ebx
+ * -0x1c %esp
+ * -0x20 %ebp
+ * -0x24 %esi
+ * -0x28 %edi
+ * -0x2c %gs
+ * -0x30 %fs
+ * -0x34 %ds
+ * -0x38 %es
+ * -0x3c %eflags
+ */
+rret_tramp: movw $MEM_ESPR-0x08,%sp # Reset stack pointer
+ pushal # Save gp regs
+ pushl %gs # Save
+ pushl %fs # seg
+ pushl %ds # regs
+ pushl %es
+ pushfl # Save %eflags
+ cli # Disable interrupts
+ std # String ops dec
+ xorw %ax,%ax # Reset seg
+ movw %ax,%ds # regs
+ movw %ax,%es # (%ss is already 0)
+ lidt idtdesc # Set IDT
+ lgdt gdtdesc # Set GDT
+ mov %cr0,%eax # Switch to protected
+ inc %ax # mode
+ mov %eax,%cr0 #
+ ljmp $SEL_SCODE,$rret_tramp.1 # To 32-bit code
+ .code32
+rret_tramp.1: xorl %ecx,%ecx # Zero
+ movb $SEL_SDATA,%cl # Setup
+ movw %cx,%ss # 32-bit
+ movw %cx,%ds # seg
+ movw %cx,%es # regs
+ movl MEM_ESPR-0x04,%esp # Switch to kernel stack
+ leal 0x44(%esp,1),%esi # Base of frame
+ andb $~0x2,tss_desc+0x5 # Clear TSS busy
+ movb $SEL_TSS,%cl # Set task
+ ltr %cx # register
+/*
+ * 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.
+ */
+ leal -0x18(%esi),%edi # Kernel stack GP regs
+ pushl %esi # Save
+ movl $MEM_ESPR-0x0c,%esi # Real mode stack GP regs
+ movl $8,%ecx # Copy GP regs from
+ rep # real mode stack
+ movsl # to kernel stack
+ movl $SEL_UDATA,%eax # Selector for data seg regs
+ movl $4,%ecx # Initialize %ds,
+ rep # %es, %fs, and
+ stosl # %gs
+/*
+ * 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
+ leal V86_GS(%ecx),%edi # %edi => btx_v86 seg regs
+ leal MEM_ESPR-0x2c,%esi # %esi => real mode seg regs
+ xchgl %ecx,%edx # Save btx_v86 ptr
+ movl $4,%ecx # Copy seg regs
+ rep # from real mode stack
+ movsl # to btx_v86
+ popl %esi # Restore
+ movl V86_CTL(%edx),%edx # Read V86 control flags
+ testl $V86F_FLAGS,%edx # User wants flags?
+ jz rret_tramp.3 # No
+ movl MEM_ESPR-0x3c,%eax # Read real mode flags
+ movw %ax,-0x08(%esi) # Update user flags (low 16)
+/*
+ * Return to the user task
+ */
+rret_tramp.3: popl %es # Restore
+ popl %ds # seg
+ popl %fs # regs
+ popl %gs
+ popal # Restore gp regs
+ addl $4,%esp # Discard int no
+ iret # Return to user mode
+
/*
* System Call.
*/
@@ -869,7 +760,7 @@ dump.1: testb $DMP_X32,%ch # Dump long?
dump.2: testb $DMP_MEM,%ch # Dump memory?
jz dump.8 # No
pushl %ds # Save
- testb $0x2,0x52(%ebx) # V86 mode?
+ testl $PSL_VM,0x50(%ebx) # V86 mode?
jnz dump.3 # Yes
verr 0x4(%esi) # Readable selector?
jnz dump.3 # No
@@ -1060,6 +951,61 @@ putchr.4: movw %dx,(%ebx) # Update position
ret # To caller
#endif
+ .code16
+/*
+ * Real Mode Hardware interrupt jump table.
+ */
+intr20: push $0x8 # Int 0x20: IRQ0
+ jmp int_hwr # V86 int 0x8
+ push $0x9 # Int 0x21: IRQ1
+ jmp int_hwr # V86 int 0x9
+ push $0xa # Int 0x22: IRQ2
+ jmp int_hwr # V86 int 0xa
+ push $0xb # Int 0x23: IRQ3
+ jmp int_hwr # V86 int 0xb
+ push $0xc # Int 0x24: IRQ4
+ jmp int_hwr # V86 int 0xc
+ push $0xd # Int 0x25: IRQ5
+ jmp int_hwr # V86 int 0xd
+ push $0xe # Int 0x26: IRQ6
+ jmp int_hwr # V86 int 0xe
+ push $0xf # Int 0x27: IRQ7
+ jmp int_hwr # V86 int 0xf
+ push $0x10 # Int 0x28: IRQ8
+ jmp int_hwr # V86 int 0x10
+ push $0x11 # Int 0x29: IRQ9
+ jmp int_hwr # V86 int 0x11
+ push $0x12 # Int 0x2a: IRQ10
+ jmp int_hwr # V86 int 0x12
+ push $0x13 # Int 0x2b: IRQ11
+ jmp int_hwr # V86 int 0x13
+ push $0x14 # Int 0x2c: IRQ12
+ jmp int_hwr # V86 int 0x14
+ push $0x15 # Int 0x2d: IRQ13
+ jmp int_hwr # V86 int 0x15
+ push $0x16 # Int 0x2e: IRQ14
+ jmp int_hwr # V86 int 0x16
+ push $0x17 # Int 0x2f: IRQ15
+ jmp int_hwr # V86 int 0x17
+/*
+ * Reflect hardware interrupts in real mode.
+ */
+int_hwr: push %ax # Save
+ push %ds # Save
+ push %bp # Save
+ mov %sp,%bp # Address stack frame
+ xchg %bx,6(%bp) # Swap BX, int no
+ xor %ax,%ax # Set %ds:%bx to
+ shl $2,%bx # point to
+ mov %ax,%ds # IDT entry
+ mov (%bx),%ax # Load IP
+ mov 2(%bx),%bx # Load CS
+ xchg %ax,4(%bp) # Swap saved %ax,%bx with
+ xchg %bx,6(%bp) # CS:IP of handler
+ pop %bp # Restore
+ pop %ds # Restore
+ lret # Jump to handler
+
.p2align 4
/*
* Global descriptor table.
@@ -1071,7 +1017,7 @@ gdt: .word 0x0,0x0,0x0,0x0 # Null entry
.word 0xffff,0x0,0x9200,0x0 # SEL_RDATA
.word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE
.word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA
- .word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS
+tss_desc: .word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS
gdt.1:
/*
* Pseudo-descriptors.
@@ -1140,6 +1086,11 @@ dmpfmt: .byte '\n' # "\n"
.byte 0x80|DMP_MEM|DMP_EOL,0x0 # "00 00 ... 00 00\n"
.asciz "BTX halted\n" # End
/*
+ * Bad VM86 call panic
+ */
+badvm86: .asciz "Invalid VM86 Request\n"
+
+/*
* End of BTX memory.
*/
.p2align 4
OpenPOWER on IntegriCloud