[librm] Add phys_call() wrapper for calling code with physical addressing
Add a phys_call() wrapper function (analogous to the existing real_call() wrapper function) for calling code with flat physical addressing, and use this wrapper within the PHYS_CODE() macro. Move the relevant functionality inside librm.S, where it more naturally belongs. The COMBOOT code currently uses explicit calls to _virt_to_phys and _phys_to_virt. These will need to be rewritten if our COMBOOT support is ever generalised to be able to run in a 64-bit build. Specifically: - com32_exec_loop() should be restructured to use PHYS_CODE() - com32_wrapper.S should be restructured to use an equivalent of prot_call(), passing parameters via a struct i386_all_regs - there appears to be no need for com32_wrapper.S to switch between external and internal stacks; this could be omitted to simplify the design. For now, librm.S continues to expose _virt_to_phys and _phys_to_virt for use by com32.c and com32_wrapper.S. Similarly, librm.S continues to expose _intr_to_virt for use by gdbidt.S. Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
parent
a4923354e3
commit
ea203e4fe1
|
@ -1,145 +0,0 @@
|
|||
/*
|
||||
* Functions to support the virtual addressing method of relocation
|
||||
* that Etherboot uses.
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
#include "librm.h"
|
||||
|
||||
.arch i386
|
||||
.text
|
||||
.code32
|
||||
|
||||
/****************************************************************************
|
||||
* _virt_to_phys (virtual addressing)
|
||||
*
|
||||
* Switch from virtual to flat physical addresses. %esp is adjusted
|
||||
* to a physical value. Segment registers are set to flat physical
|
||||
* selectors. All other registers are preserved. Flags are
|
||||
* preserved.
|
||||
*
|
||||
* Parameters: none
|
||||
* Returns: none
|
||||
****************************************************************************
|
||||
*/
|
||||
.globl _virt_to_phys
|
||||
_virt_to_phys:
|
||||
/* Preserve registers and flags */
|
||||
pushfl
|
||||
pushl %eax
|
||||
pushl %ebp
|
||||
|
||||
/* Change return address to a physical address */
|
||||
movl VIRTUAL(virt_offset), %ebp
|
||||
addl %ebp, 12(%esp)
|
||||
|
||||
/* Switch to physical code segment */
|
||||
cli
|
||||
pushl $PHYSICAL_CS
|
||||
leal VIRTUAL(1f)(%ebp), %eax
|
||||
pushl %eax
|
||||
lret
|
||||
1:
|
||||
/* Reload other segment registers and adjust %esp */
|
||||
movl $PHYSICAL_DS, %eax
|
||||
movl %eax, %ds
|
||||
movl %eax, %es
|
||||
movl %eax, %fs
|
||||
movl %eax, %gs
|
||||
movl %eax, %ss
|
||||
addl %ebp, %esp
|
||||
|
||||
/* Restore registers and flags, and return */
|
||||
popl %ebp
|
||||
popl %eax
|
||||
popfl
|
||||
ret
|
||||
|
||||
/****************************************************************************
|
||||
* _phys_to_virt (flat physical addressing)
|
||||
*
|
||||
* Switch from flat physical to virtual addresses. %esp is adjusted
|
||||
* to a virtual value. Segment registers are set to virtual
|
||||
* selectors. All other registers are preserved. Flags are
|
||||
* preserved.
|
||||
*
|
||||
* Parameters: none
|
||||
* Returns: none
|
||||
****************************************************************************
|
||||
*/
|
||||
.globl _phys_to_virt
|
||||
_phys_to_virt:
|
||||
/* Preserve registers and flags */
|
||||
pushfl
|
||||
pushl %eax
|
||||
pushl %ebp
|
||||
|
||||
/* Switch to virtual code segment */
|
||||
cli
|
||||
ljmp $VIRTUAL_CS, $VIRTUAL(1f)
|
||||
1:
|
||||
/* Reload data segment registers */
|
||||
movl $VIRTUAL_DS, %eax
|
||||
movl %eax, %ds
|
||||
movl %eax, %es
|
||||
movl %eax, %fs
|
||||
movl %eax, %gs
|
||||
|
||||
/* Reload stack segment and adjust %esp */
|
||||
movl VIRTUAL(virt_offset), %ebp
|
||||
movl %eax, %ss
|
||||
subl %ebp, %esp
|
||||
|
||||
/* Change the return address to a virtual address */
|
||||
subl %ebp, 12(%esp)
|
||||
|
||||
/* Restore registers and flags, and return */
|
||||
popl %ebp
|
||||
popl %eax
|
||||
popfl
|
||||
ret
|
||||
|
||||
/****************************************************************************
|
||||
* _intr_to_virt (virtual code segment, virtual or physical stack segment)
|
||||
*
|
||||
* Switch from virtual code segment with either a virtual or physical
|
||||
* stack segment to using virtual addressing. %esp is adjusted if
|
||||
* necessary to a virtual value. Segment registers are set to virtual
|
||||
* selectors. All other registers are preserved. Flags are
|
||||
* preserved.
|
||||
*
|
||||
* Parameters: none
|
||||
* Returns: none
|
||||
****************************************************************************
|
||||
*/
|
||||
.globl _intr_to_virt
|
||||
_intr_to_virt:
|
||||
/* Preserve registers and flags */
|
||||
pushfl
|
||||
pushl %eax
|
||||
pushl %ebp
|
||||
|
||||
/* Check whether stack segment is physical or virtual */
|
||||
movl %ss, %eax
|
||||
cmpw $VIRTUAL_DS, %ax
|
||||
movl $VIRTUAL_DS, %eax
|
||||
|
||||
/* Reload data segment registers */
|
||||
movl %eax, %ds
|
||||
movl %eax, %es
|
||||
movl %eax, %fs
|
||||
movl %eax, %gs
|
||||
|
||||
/* Reload stack segment and adjust %esp if necessary */
|
||||
je 1f
|
||||
movl VIRTUAL(virt_offset), %ebp
|
||||
movl %eax, %ss
|
||||
subl %ebp, %esp
|
||||
1:
|
||||
/* Restore registers and flags, and return */
|
||||
popl %ebp
|
||||
popl %eax
|
||||
popfl
|
||||
ret
|
|
@ -250,11 +250,16 @@ extern void remove_user_from_rm_stack ( userptr_t data, size_t size );
|
|||
|
||||
/* PHYS_CODE: declare a fragment of code that executes in flat physical mode */
|
||||
#define PHYS_CODE( asm_code_str ) \
|
||||
"call _virt_to_phys\n\t" \
|
||||
"push $1f\n\t" \
|
||||
"call phys_call\n\t" \
|
||||
".section \".text.phys\", \"ax\", @progbits\n\t"\
|
||||
".code32\n\t" \
|
||||
"\n1:\n\t" \
|
||||
asm_code_str \
|
||||
"call _phys_to_virt\n\t" \
|
||||
CODE_DEFAULT "\n\t"
|
||||
"\n\t" \
|
||||
"ret\n\t" \
|
||||
CODE_DEFAULT "\n\t" \
|
||||
".previous\n\t"
|
||||
|
||||
/** Number of interrupts */
|
||||
#define NUM_INT 256
|
||||
|
|
|
@ -501,6 +501,150 @@ rm_gdtr:
|
|||
.word 0 /* Limit */
|
||||
.long 0 /* Base */
|
||||
|
||||
/****************************************************************************
|
||||
* phys_to_prot (protected-mode near call, 32-bit physical return address)
|
||||
*
|
||||
* Switch from 32-bit protected mode with physical addresses to 32-bit
|
||||
* protected mode with virtual addresses. %esp is adjusted to a
|
||||
* virtual address. All other registers and flags are preserved.
|
||||
*
|
||||
* The return address for this function should be a 32-bit physical
|
||||
* (sic) address.
|
||||
*
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".text.phys_to_prot", "ax", @progbits
|
||||
.code32
|
||||
.globl phys_to_prot
|
||||
phys_to_prot:
|
||||
/* Preserve registers and flags */
|
||||
pushfl
|
||||
pushl %eax
|
||||
pushl %ebp
|
||||
|
||||
/* Switch to virtual code segment */
|
||||
cli
|
||||
ljmp $VIRTUAL_CS, $VIRTUAL(1f)
|
||||
1:
|
||||
/* Switch to virtual data segment and adjust %esp */
|
||||
movw $VIRTUAL_DS, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %es
|
||||
movw %ax, %fs
|
||||
movw %ax, %gs
|
||||
movw %ax, %ss
|
||||
movl VIRTUAL(virt_offset), %ebp
|
||||
subl %ebp, %esp
|
||||
|
||||
/* Adjust return address to a virtual address */
|
||||
subl %ebp, 12(%esp)
|
||||
|
||||
/* Restore registers and flags, and return */
|
||||
popl %ebp
|
||||
popl %eax
|
||||
popfl
|
||||
ret
|
||||
|
||||
/* Expose as _phys_to_virt for use by COMBOOT */
|
||||
.globl _phys_to_virt
|
||||
.equ _phys_to_virt, phys_to_prot
|
||||
|
||||
/****************************************************************************
|
||||
* prot_to_phys (protected-mode near call, 32-bit virtual return address)
|
||||
*
|
||||
* Switch from 32-bit protected mode with virtual addresses to 32-bit
|
||||
* protected mode with physical addresses. %esp is adjusted to a
|
||||
* physical address. All other registers and flags are preserved.
|
||||
*
|
||||
* The return address for this function should be a 32-bit virtual
|
||||
* (sic) address.
|
||||
*
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".text.prot_to_phys", "ax", @progbits
|
||||
.code32
|
||||
prot_to_phys:
|
||||
/* Preserve registers and flags */
|
||||
pushfl
|
||||
pushl %eax
|
||||
pushl %ebp
|
||||
|
||||
/* Adjust return address to a physical address */
|
||||
movl VIRTUAL(virt_offset), %ebp
|
||||
addl %ebp, 12(%esp)
|
||||
|
||||
/* Switch to physical code segment */
|
||||
cli
|
||||
pushl $PHYSICAL_CS
|
||||
leal VIRTUAL(1f)(%ebp), %eax
|
||||
pushl %eax
|
||||
lret
|
||||
1:
|
||||
/* Switch to physical data segment and adjust %esp */
|
||||
movw $PHYSICAL_DS, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %es
|
||||
movw %ax, %fs
|
||||
movw %ax, %gs
|
||||
movw %ax, %ss
|
||||
addl %ebp, %esp
|
||||
|
||||
/* Restore registers and flags, and return */
|
||||
popl %ebp
|
||||
popl %eax
|
||||
popfl
|
||||
ret
|
||||
|
||||
/* Expose as _virt_to_phys for use by COMBOOT */
|
||||
.globl _virt_to_phys
|
||||
.equ _virt_to_phys, prot_to_phys
|
||||
|
||||
/****************************************************************************
|
||||
* intr_to_prot (protected-mode near call, 32-bit virtual return address)
|
||||
*
|
||||
* Switch from 32-bit protected mode with a virtual code segment and
|
||||
* either a physical or virtual stack segment to 32-bit protected mode
|
||||
* with normal virtual addresses. %esp is adjusted if necessary to a
|
||||
* virtual address. All other registers and flags are preserved.
|
||||
*
|
||||
* The return address for this function should be a 32-bit virtual
|
||||
* address.
|
||||
*
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".text.intr_to_prot", "ax", @progbits
|
||||
.code32
|
||||
.globl intr_to_prot
|
||||
intr_to_prot:
|
||||
/* Preserve registers and flags */
|
||||
pushfl
|
||||
pushl %eax
|
||||
|
||||
/* Check whether stack segment is physical or virtual */
|
||||
movw %ss, %ax
|
||||
cmpw $VIRTUAL_DS, %ax
|
||||
movw $VIRTUAL_DS, %ax
|
||||
|
||||
/* Reload data segment registers */
|
||||
movw %ax, %ds
|
||||
movw %ax, %es
|
||||
movw %ax, %fs
|
||||
movw %ax, %gs
|
||||
|
||||
/* Reload stack segment and adjust %esp if necessary */
|
||||
je 1f
|
||||
movw %ax, %ss
|
||||
subl VIRTUAL(virt_offset), %esp
|
||||
1:
|
||||
/* Restore registers and flags, and return */
|
||||
popl %eax
|
||||
popfl
|
||||
ret
|
||||
|
||||
/* Expose as _intr_to_virt for use by GDB */
|
||||
.globl _intr_to_virt
|
||||
.equ _intr_to_virt, intr_to_prot
|
||||
|
||||
/****************************************************************************
|
||||
* prot_call (real-mode near call, 16-bit real-mode near return address)
|
||||
*
|
||||
|
@ -539,6 +683,7 @@ PC_OFFSET_IDT: .space 6
|
|||
PC_OFFSET_IX86: .space SIZEOF_I386_ALL_REGS
|
||||
PC_OFFSET_PADDING: .space 2 /* for alignment */
|
||||
PC_OFFSET_RETADDR: .space 2
|
||||
PC_OFFSET_PARAMS:
|
||||
PC_OFFSET_FUNCTION: .space 4
|
||||
PC_OFFSET_END:
|
||||
.previous
|
||||
|
@ -601,7 +746,9 @@ pc_rmode:
|
|||
addr32 movl -20(%esp), %esp
|
||||
popfl
|
||||
popfw /* padding */
|
||||
ret $4
|
||||
|
||||
/* Return and discard function parameters */
|
||||
ret $( PC_OFFSET_END - PC_OFFSET_PARAMS )
|
||||
|
||||
/****************************************************************************
|
||||
* real_call (protected-mode near call, 32-bit virtual return address)
|
||||
|
@ -620,7 +767,7 @@ pc_rmode:
|
|||
* See librm.h and realmode.h for details and examples.
|
||||
*
|
||||
* Parameters:
|
||||
* (32-bit) near pointer to real-mode function to call
|
||||
* function : offset within .text16 of real-mode function to call
|
||||
*
|
||||
* Returns: none
|
||||
****************************************************************************
|
||||
|
@ -629,6 +776,7 @@ pc_rmode:
|
|||
RC_OFFSET_REGS: .space SIZEOF_I386_REGS
|
||||
RC_OFFSET_REGS_END:
|
||||
RC_OFFSET_RETADDR: .space 4
|
||||
RC_OFFSET_PARAMS:
|
||||
RC_OFFSET_FUNCTION: .space 4
|
||||
RC_OFFSET_END:
|
||||
.previous
|
||||
|
@ -665,9 +813,11 @@ rc_rmode:
|
|||
.section ".text.real_call", "ax", @progbits
|
||||
.code32
|
||||
rc_pmode:
|
||||
/* Restore registers and return */
|
||||
/* Restore registers */
|
||||
popal
|
||||
ret $4
|
||||
|
||||
/* Return and discard function parameters */
|
||||
ret $( RC_OFFSET_END - RC_OFFSET_PARAMS )
|
||||
|
||||
|
||||
/* Function vector, used because "call xx(%sp)" is not a valid
|
||||
|
@ -684,6 +834,55 @@ rm_default_gdtr_idtr:
|
|||
.word 0x03ff /* Interrupt descriptor table limit */
|
||||
.long 0 /* Interrupt descriptor table base */
|
||||
|
||||
/****************************************************************************
|
||||
* phys_call (protected-mode near call, 32-bit virtual return address)
|
||||
*
|
||||
* Call a function with flat 32-bit physical addressing
|
||||
*
|
||||
* The non-segment register values will be passed directly to the
|
||||
* function. The segment registers will be set for flat 32-bit
|
||||
* physical addressing. The non-segment register values set by the
|
||||
* function will be passed back to the caller.
|
||||
*
|
||||
* librm.h defines a convenient macro PHYS_CODE() for using phys_call.
|
||||
*
|
||||
* Parameters:
|
||||
* function : virtual (sic) address of function to call
|
||||
*
|
||||
****************************************************************************
|
||||
*/
|
||||
.struct 0
|
||||
PHC_OFFSET_RETADDR: .space 4
|
||||
PHC_OFFSET_PARAMS:
|
||||
PHC_OFFSET_FUNCTION: .space 4
|
||||
PHC_OFFSET_END:
|
||||
.previous
|
||||
|
||||
.section ".text.phys_call", "ax", @progbits
|
||||
.code32
|
||||
.globl phys_call
|
||||
phys_call:
|
||||
/* Adjust function pointer to a physical address */
|
||||
pushl %ebp
|
||||
movl VIRTUAL(virt_offset), %ebp
|
||||
addl %ebp, ( PHC_OFFSET_FUNCTION + 4 /* saved %ebp */ )(%esp)
|
||||
popl %ebp
|
||||
|
||||
/* Switch to physical addresses */
|
||||
call prot_to_phys
|
||||
|
||||
/* Call function */
|
||||
call *PHC_OFFSET_FUNCTION(%esp)
|
||||
|
||||
/* For sanity's sake, clear the direction flag as soon as possible */
|
||||
cld
|
||||
|
||||
/* Switch to virtual addresses */
|
||||
call phys_to_prot
|
||||
|
||||
/* Return and discard function parameters */
|
||||
ret $( PHC_OFFSET_END - PHC_OFFSET_PARAMS )
|
||||
|
||||
/****************************************************************************
|
||||
* flatten_real_mode (real-mode near call)
|
||||
*
|
||||
|
@ -733,7 +932,7 @@ interrupt_wrapper:
|
|||
pushl %esp
|
||||
|
||||
/* Switch to virtual addressing */
|
||||
call _intr_to_virt
|
||||
call intr_to_prot
|
||||
|
||||
/* Expand IRQ number to whole %eax register */
|
||||
movzbl %al, %eax
|
||||
|
|
Reference in New Issue