[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:
Michael Brown
2016-02-19 19:43:04 +00:00
parent a4923354e3
commit ea203e4fe1
3 changed files with 212 additions and 153 deletions

View File

@@ -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