MFi386: Use real mode instead of v86 mode.
MFC after: 1 week
This commit is contained in:
parent
1c9f1ea6d3
commit
8deeaefd93
@ -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
|
||||
/*
|
||||
@ -33,6 +33,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.
|
||||
*/
|
||||
@ -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_FLG,0x208eff # V86 flag mask
|
||||
.set V86_STK,0x400 # V86 stack allowance
|
||||
.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 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.
|
||||
@ -284,10 +309,6 @@ setpic: in $0x02,%al # Save master
|
||||
outb %al,$0x02 # IMR
|
||||
retw # To caller
|
||||
.code32
|
||||
/*
|
||||
* Initiate return from V86 mode to user mode.
|
||||
*/
|
||||
inthlt: hlt # To supervisor mode
|
||||
/*
|
||||
* Exception jump table.
|
||||
*/
|
||||
@ -314,17 +335,11 @@ 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.
|
||||
*/
|
||||
@ -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
|
||||
|
||||
/*
|
||||
* Reflect hardware interrupts.
|
||||
* Invoke real mode interrupt/function call from user mode with arguments.
|
||||
*/
|
||||
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
|
||||
intx31: pushl $-1 # Dummy int no for btx_v86
|
||||
/*
|
||||
* Invoke V86 interrupt from user mode, with arguments.
|
||||
* 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)
|
||||
*/
|
||||
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
|
||||
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.
|
||||
@ -1139,6 +1085,11 @@ dmpfmt: .byte '\n' # "\n"
|
||||
.ascii "ss:esp" # "ss:esp="
|
||||
.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.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user