]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[librm] Add phys_call() wrapper for calling code with physical addressing
authorMichael Brown <mcb30@ipxe.org>
Fri, 19 Feb 2016 19:43:04 +0000 (19:43 +0000)
committerMichael Brown <mcb30@ipxe.org>
Sat, 20 Feb 2016 23:09:36 +0000 (23:09 +0000)
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>
src/arch/x86/core/virtaddr.S [deleted file]
src/arch/x86/include/librm.h
src/arch/x86/transitions/librm.S

diff --git a/src/arch/x86/core/virtaddr.S b/src/arch/x86/core/virtaddr.S
deleted file mode 100644 (file)
index 45beb16..0000000
+++ /dev/null
@@ -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
index fc31c5036d0a60586827ae61a4899dfb6c0cb683..bc925a2db5f540c444050fa7d49448ce53508122 100644 (file)
@@ -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
index f3854dfe8ca11019914a4090135c4af39d2815fa..ab4994fb6e6be5d103e42a0ddc2d022cc5a89030 100644 (file)
@@ -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