mirror of
https://github.com/ipxe/ipxe
synced 2025-12-13 23:41:45 +03:00
[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:
@@ -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 */
|
/* PHYS_CODE: declare a fragment of code that executes in flat physical mode */
|
||||||
#define PHYS_CODE( asm_code_str ) \
|
#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" \
|
".code32\n\t" \
|
||||||
|
"\n1:\n\t" \
|
||||||
asm_code_str \
|
asm_code_str \
|
||||||
"call _phys_to_virt\n\t" \
|
"\n\t" \
|
||||||
CODE_DEFAULT "\n\t"
|
"ret\n\t" \
|
||||||
|
CODE_DEFAULT "\n\t" \
|
||||||
|
".previous\n\t"
|
||||||
|
|
||||||
/** Number of interrupts */
|
/** Number of interrupts */
|
||||||
#define NUM_INT 256
|
#define NUM_INT 256
|
||||||
|
|||||||
@@ -501,6 +501,150 @@ rm_gdtr:
|
|||||||
.word 0 /* Limit */
|
.word 0 /* Limit */
|
||||||
.long 0 /* Base */
|
.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)
|
* 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_IX86: .space SIZEOF_I386_ALL_REGS
|
||||||
PC_OFFSET_PADDING: .space 2 /* for alignment */
|
PC_OFFSET_PADDING: .space 2 /* for alignment */
|
||||||
PC_OFFSET_RETADDR: .space 2
|
PC_OFFSET_RETADDR: .space 2
|
||||||
|
PC_OFFSET_PARAMS:
|
||||||
PC_OFFSET_FUNCTION: .space 4
|
PC_OFFSET_FUNCTION: .space 4
|
||||||
PC_OFFSET_END:
|
PC_OFFSET_END:
|
||||||
.previous
|
.previous
|
||||||
@@ -601,7 +746,9 @@ pc_rmode:
|
|||||||
addr32 movl -20(%esp), %esp
|
addr32 movl -20(%esp), %esp
|
||||||
popfl
|
popfl
|
||||||
popfw /* padding */
|
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)
|
* 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.
|
* See librm.h and realmode.h for details and examples.
|
||||||
*
|
*
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* (32-bit) near pointer to real-mode function to call
|
* function : offset within .text16 of real-mode function to call
|
||||||
*
|
*
|
||||||
* Returns: none
|
* Returns: none
|
||||||
****************************************************************************
|
****************************************************************************
|
||||||
@@ -629,6 +776,7 @@ pc_rmode:
|
|||||||
RC_OFFSET_REGS: .space SIZEOF_I386_REGS
|
RC_OFFSET_REGS: .space SIZEOF_I386_REGS
|
||||||
RC_OFFSET_REGS_END:
|
RC_OFFSET_REGS_END:
|
||||||
RC_OFFSET_RETADDR: .space 4
|
RC_OFFSET_RETADDR: .space 4
|
||||||
|
RC_OFFSET_PARAMS:
|
||||||
RC_OFFSET_FUNCTION: .space 4
|
RC_OFFSET_FUNCTION: .space 4
|
||||||
RC_OFFSET_END:
|
RC_OFFSET_END:
|
||||||
.previous
|
.previous
|
||||||
@@ -665,9 +813,11 @@ rc_rmode:
|
|||||||
.section ".text.real_call", "ax", @progbits
|
.section ".text.real_call", "ax", @progbits
|
||||||
.code32
|
.code32
|
||||||
rc_pmode:
|
rc_pmode:
|
||||||
/* Restore registers and return */
|
/* Restore registers */
|
||||||
popal
|
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
|
/* 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 */
|
.word 0x03ff /* Interrupt descriptor table limit */
|
||||||
.long 0 /* Interrupt descriptor table base */
|
.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)
|
* flatten_real_mode (real-mode near call)
|
||||||
*
|
*
|
||||||
@@ -733,7 +932,7 @@ interrupt_wrapper:
|
|||||||
pushl %esp
|
pushl %esp
|
||||||
|
|
||||||
/* Switch to virtual addressing */
|
/* Switch to virtual addressing */
|
||||||
call _intr_to_virt
|
call intr_to_prot
|
||||||
|
|
||||||
/* Expand IRQ number to whole %eax register */
|
/* Expand IRQ number to whole %eax register */
|
||||||
movzbl %al, %eax
|
movzbl %al, %eax
|
||||||
|
|||||||
Reference in New Issue
Block a user