* to us.
****************************************************************************
*/
- .section ".bss.rm_sp", "aw", @nobits
+ .section ".bss.rm_ss_sp", "aw", @nobits
.globl rm_sp
rm_sp: .word 0
-
- .section ".bss.rm_ss", "aw", @nobits
.globl rm_ss
rm_ss: .word 0
.section ".data.pm_esp", "aw", @progbits
pm_esp: .long VIRTUAL(_estack)
+/****************************************************************************
+ * Temporary static data buffer
+ *
+ * This is used to reduce the amount of real-mode stack space consumed
+ * during mode transitions, since we are sometimes called with very
+ * little real-mode stack space available.
+ ****************************************************************************
+ */
+ /* Temporary static buffer usage by virt_call */
+ .struct 0
+VC_TMP_GDT: .space 6
+VC_TMP_IDT: .space 6
+VC_TMP_PAD: .space 4 /* for alignment */
+.if64
+VC_TMP_CR3: .space 4
+VC_TMP_CR4: .space 4
+VC_TMP_EMER: .space 8
+.endif
+VC_TMP_END:
+ .previous
+
+ /* Temporary static buffer usage by real_call */
+ .struct 0
+RC_TMP_FUNCTION: .space 4
+RC_TMP_END:
+ .previous
+
+ /* Shared temporary static buffer */
+ .section ".bss16.rm_tmpbuf", "aw", @nobits
+ .align 16
+rm_tmpbuf:
+ .space VC_TMP_END
+ .size rm_tmpbuf, . - rm_tmpbuf
+
/****************************************************************************
* Virtual address offsets
*
*
* Parameters:
* %ecx : number of bytes to move from RM stack to PM stack
+ * %edx : number of bytes to copy from RM temporary buffer to PM stack
*
****************************************************************************
*/
/* Add protected-mode return address to length of data to be copied */
addw $4, %cx /* %ecx must be less than 64kB anyway */
- /* Real-mode %ss:%sp => %ebp:%edx and virtual address => %esi */
- xorl %ebp, %ebp
- movw %ss, %bp
- movzwl %sp, %edx
- movl %ebp, %eax
+ /* Real-mode %ss:%sp => %ebp and virtual address => %esi */
+ xorl %eax, %eax
+ movw %ss, %ax
shll $4, %eax
- addr32 leal (%eax,%edx), %esi
+ movzwl %sp, %ebp
+ addr32 leal (%eax,%ebp), %esi
subl rm_virt_offset, %esi
+ shll $12, %eax
+ orl %eax, %ebp
+
+ /* Real-mode data segment virtual address => %ebx */
+ movl rm_data16, %ebx
+.if64 ; subl rm_virt_offset, %ebx ; .endif
/* Load protected-mode global descriptor table */
data32 lgdt gdtr
lidt VIRTUAL(idtr32)
/* Record real-mode %ss:sp (after removal of data) */
- movw %bp, VIRTUAL(rm_ss)
- addl %ecx, %edx
- movw %dx, VIRTUAL(rm_sp)
+ addl %ecx, %ebp
+ movl %ebp, VIRTUAL(rm_sp)
/* Move data from RM stack to PM stack */
+ subl %edx, %esp
subl %ecx, %esp
movl %esp, %edi
rep movsb
+ /* Copy data from RM temporary buffer to PM stack */
+ leal rm_tmpbuf(%ebx), %esi
+ movl %edx, %ecx
+ rep movsb
+
/* Return to virtual address */
ret
*
* Parameters:
* %ecx : number of bytes to move from PM stack to RM stack
+ * %edx : number of bytes to move from PM stack to RM temporary buffer
* %esi : real-mode global and interrupt descriptor table registers
*
****************************************************************************
/* Add return address to data to be moved to RM stack */
addl $4, %ecx
- /* Real-mode %ss:sp => %ebp:edx and virtual address => %edi */
- movzwl VIRTUAL(rm_ss), %ebp
- movzwl VIRTUAL(rm_sp), %edx
- subl %ecx, %edx
- movl %ebp, %eax
+ /* Real-mode %ss:sp => %ebp and virtual address => %edi */
+ movl VIRTUAL(rm_sp), %ebp
+ subl %ecx, %ebp
+ movzwl VIRTUAL(rm_ss), %eax
shll $4, %eax
- leal (%eax,%edx), %edi
+ movzwl %bp, %edi
+ addl %eax, %edi
subl VIRTUAL(virt_offset), %edi
/* Move data from PM stack to RM stack */
movl %esp, %esi
rep movsb
+ /* Move data from PM stack to RM temporary buffer */
+ movl VIRTUAL(data16), %edi
+.if64 ; subl VIRTUAL(virt_offset), %edi ; .endif
+ addl $rm_tmpbuf, %edi
+ movl %edx, %ecx
+ rep movsb
+
/* Record protected-mode %esp (after removal of data) */
movl %esi, VIRTUAL(pm_esp)
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
- movw %bp, %ss
- movl %edx, %esp
+ movl %ebp, %eax
+ shrl $16, %eax
+ movw %ax, %ss
+ movzwl %bp, %esp
/* Return to real-mode address */
data32 ret
****************************************************************************
*/
.struct 0
-VC_OFFSET_GDT: .space 6
-VC_OFFSET_IDT: .space 6
-.if64
-VC_OFFSET_PADDING64: .space 4 /* for alignment */
-VC_OFFSET_CR3: .space 4
-VC_OFFSET_CR4: .space 4
-VC_OFFSET_EMER: .space 8
-.endif
VC_OFFSET_IX86: .space SIZEOF_I386_ALL_REGS
VC_OFFSET_PADDING: .space 2 /* for alignment */
VC_OFFSET_RETADDR: .space 2
.code16
.globl virt_call
virt_call:
- /* Preserve registers, flags and GDT on external RM stack */
+ /* Preserve registers and flags on external RM stack */
pushw %ss /* padding */
pushfl
pushal
pushw %ds
pushw %ss
pushw %cs
- subw $VC_OFFSET_IX86, %sp
- movw %sp, %bp
- sidt VC_OFFSET_IDT(%bp)
- sgdt VC_OFFSET_GDT(%bp)
+
+ /* Claim ownership of temporary static buffer */
+ cli
+
+ /* Preserve GDT and IDT in temporary static buffer */
+ movw %cs:rm_ds, %ds
+ sidt ( rm_tmpbuf + VC_TMP_IDT )
+ sgdt ( rm_tmpbuf + VC_TMP_GDT )
.if64 ; /* Preserve control registers, if applicable */
movl $MSR_EFER, %ecx
rdmsr
- movl %eax, (VC_OFFSET_EMER+0)(%bp)
- movl %edx, (VC_OFFSET_EMER+4)(%bp)
+ movl %eax, ( rm_tmpbuf + VC_TMP_EMER + 0 )
+ movl %edx, ( rm_tmpbuf + VC_TMP_EMER + 4 )
movl %cr4, %eax
- movl %eax, VC_OFFSET_CR4(%bp)
+ movl %eax, ( rm_tmpbuf + VC_TMP_CR4 )
movl %cr3, %eax
- movl %eax, VC_OFFSET_CR3(%bp)
+ movl %eax, ( rm_tmpbuf + VC_TMP_CR3 )
.endif
/* For sanity's sake, clear the direction flag as soon as possible */
cld
/* Switch to protected mode and move register dump to PM stack */
movl $VC_OFFSET_END, %ecx
+ movl $VC_TMP_END, %edx
pushl $VIRTUAL(vc_pmode)
vc_jmp: jmp real_to_prot
.section ".text.virt_call", "ax", @progbits
.code32
vc_pmode:
/* Call function (in protected mode) */
- leal VC_OFFSET_IX86(%esp), %eax
- pushl %eax
+ pushl %esp
call *(VC_OFFSET_FUNCTION+4)(%esp)
popl %eax /* discard */
.code64
/* Call function (in long mode) */
- leaq VC_OFFSET_IX86(%rsp), %rdi
- pushq %rdi
- movslq (VC_OFFSET_FUNCTION+8)(%rsp), %rax
+ movq %rsp, %rdi
+ movslq VC_OFFSET_FUNCTION(%rsp), %rax
callq *%rax
- popq %rdi /* discard */
/* Switch to protected mode */
call long_to_prot
.endif
/* Switch to real mode and move register dump back to RM stack */
movl $VC_OFFSET_END, %ecx
- movl %esp, %esi
+ movl $VC_TMP_END, %edx
+ leal VC_TMP_GDT(%esp, %ecx), %esi
pushl $vc_rmode
jmp prot_to_real
.section ".text16.virt_call", "ax", @progbits
vc_rmode:
.if64 ; /* Restore control registers, if applicable */
movw %sp, %bp
- movl VC_OFFSET_CR3(%bp), %eax
+ movl ( rm_tmpbuf + VC_TMP_CR3 ), %eax
movl %eax, %cr3
- movl VC_OFFSET_CR4(%bp), %eax
+ movl ( rm_tmpbuf + VC_TMP_CR4 ), %eax
movl %eax, %cr4
- movl (VC_OFFSET_EMER+0)(%bp), %eax
- movl (VC_OFFSET_EMER+4)(%bp), %edx
+ movl ( rm_tmpbuf + VC_TMP_EMER + 0 ), %eax
+ movl ( rm_tmpbuf + VC_TMP_EMER + 4 ), %edx
movl $MSR_EFER, %ecx
wrmsr
.endif
/* Restore registers and flags and return */
- addw $( VC_OFFSET_IX86 + 4 /* also skip %cs and %ss */ ), %sp
+ popl %eax /* skip %cs and %ss */
popw %ds
popw %es
popw %fs
.struct 0
RC_OFFSET_REGS: .space SIZEOF_I386_REGS
RC_OFFSET_REGS_END:
+RC_OFFSET_FUNCTION_COPY:.space 4
.if64
RC_OFFSET_LREGS: .space SIZEOF_X86_64_REGS
RC_OFFSET_LREG_RETADDR: .space SIZEOF_ADDR
.code32
.endif
/* Create register dump and function pointer copy on PM stack */
+ pushl ( RC_OFFSET_FUNCTION - RC_OFFSET_FUNCTION_COPY - 4 )(%esp)
pushal
- pushl RC_OFFSET_FUNCTION(%esp)
/* Switch to real mode and move register dump to RM stack */
- movl $( RC_OFFSET_REGS_END + 4 /* function pointer copy */ ), %ecx
+ movl $RC_OFFSET_REGS_END, %ecx
+ movl $RC_TMP_END, %edx
pushl $rc_rmode
movl $VIRTUAL(rm_default_gdtr_idtr), %esi
jmp prot_to_real
.code16
rc_rmode:
/* Call real-mode function */
- popl rc_function
popal
- call *rc_function
+ call *( rm_tmpbuf + RC_TMP_FUNCTION )
pushal
/* For sanity's sake, clear the direction flag as soon as possible */
/* Switch to protected mode and move register dump back to PM stack */
movl $RC_OFFSET_REGS_END, %ecx
+ xorl %edx, %edx
pushl $VIRTUAL(rc_pmode)
jmp real_to_prot
.section ".text.real_call", "ax", @progbits
ret $( RC_OFFSET_END - RC_OFFSET_PARAMS )
- /* Function vector, used because "call xx(%sp)" is not a valid
- * 16-bit expression.
- */
- .section ".bss16.rc_function", "aw", @nobits
-rc_function: .word 0, 0
-
/* Default real-mode global and interrupt descriptor table registers */
.section ".data.rm_default_gdtr_idtr", "aw", @progbits
rm_default_gdtr_idtr: