mirror of
https://github.com/xcat2/xNBA.git
synced 2024-12-14 23:31:39 +00:00
Make prot_call() able to transparently return via the newly installed copy
of librm.
This commit is contained in:
parent
44eee81d11
commit
04a99841e6
@ -144,7 +144,17 @@ _librm_start:
|
||||
****************************************************************************
|
||||
*/
|
||||
.fill FREE_BASEMEM_HEADER_SIZE, 1, 0
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Record of the current physical location of the installed copy.
|
||||
* Used by prot_call in order to return via the current installed copy
|
||||
* even if Etherboot has been relocated during the protected-mode
|
||||
* call.
|
||||
****************************************************************************
|
||||
*/
|
||||
EXPORT(librm_base):
|
||||
librm_base: .long 0
|
||||
|
||||
/****************************************************************************
|
||||
* GDT for initial transition to protected mode
|
||||
*
|
||||
@ -266,6 +276,9 @@ EXPORT(real_to_prot):
|
||||
xorl %ebx, %ebx
|
||||
movw %cs, %bx
|
||||
shll $4, %ebx
|
||||
|
||||
/* Record physical base address of librm */
|
||||
movl %ebx, %ds:OFFSET(librm_base)
|
||||
|
||||
/* Check base address of stored protected-mode GDT. If it's
|
||||
* zero, set it up to use our internal GDT (with physical
|
||||
@ -360,6 +373,9 @@ EXPORT(prot_to_real):
|
||||
popl OFFSET(save_ebx)(%ebx)
|
||||
movl %eax, OFFSET(save_eax)(%ebx)
|
||||
|
||||
/* Record physical base address of librm */
|
||||
movl %ebx, OFFSET(librm_base)(%ebx)
|
||||
|
||||
/* Extract return address from the stack, convert to offset
|
||||
* within librm and save in save_retaddr
|
||||
*/
|
||||
@ -445,22 +461,32 @@ p2r_ljmp:
|
||||
*
|
||||
* Call a specific C function in the protected-mode code. The
|
||||
* prototype of the C function must be
|
||||
* void function ( struct real_mode_regs *rm_regs,
|
||||
* void (*retaddr) (void) );
|
||||
* void function ( struct real_mode_regs *rm_regs );
|
||||
* rm_regs will point to a struct containing the real-mode registers
|
||||
* at entry to prot_call. retaddr will point to the (virtual) return
|
||||
* address from "function". This return address will point into
|
||||
* librm. It is included so that "function" may, if desired, relocate
|
||||
* librm and return via the new copy. It must not be directly called
|
||||
* as a function, i.e. you may not do "*retaddr()"; you must instead
|
||||
* do something like:
|
||||
* *retaddr += ( new_librm_location - old_librm_location );
|
||||
* return;
|
||||
* at entry to prot_call.
|
||||
*
|
||||
* All registers will be preserved across prot_call(), unless the C
|
||||
* function explicitly overwrites values in rm_regs. Interrupt status
|
||||
* will also be preserved. Gate A20 will be enabled.
|
||||
*
|
||||
* The protected-mode code may install librm to a new location. If it
|
||||
* does so, it must update librm_base in *this* copy of librm to point
|
||||
* to the new physical location. prot_call will then return via the
|
||||
* newly installed copy.
|
||||
*
|
||||
* Note that when Etherboot performs its initial relocation, "*this*"
|
||||
* copy in the above paragraph will refer to the "master" copy, since
|
||||
* that is the initial installed copy. Etherboot will return to
|
||||
* prot_call using a virtual address, so will return to the master
|
||||
* copy in high memory (rather than the original copy in base memory).
|
||||
* The master copy in high memory will have the physical address of
|
||||
* the newly installed copy in librm_base, since install_librm()
|
||||
* writes it there. Thus, Etherboot's initialise() function will
|
||||
* return to the master copy of prot_call(), which will then jump to
|
||||
* the installed copy.
|
||||
*
|
||||
* It works, trust me.
|
||||
*
|
||||
* Parameters:
|
||||
* function : virtual address of protected-mode function to call
|
||||
*
|
||||
@ -529,14 +555,10 @@ EXPORT(prot_call):
|
||||
popl %eax /* discard */
|
||||
popal
|
||||
|
||||
/* Push &rm_regs and &retaddr on the stack, and call function */
|
||||
movl %esp, %ebp
|
||||
/* Push &rm_regs on the stack, and call function */
|
||||
pushl %esp
|
||||
subl $12, 0(%esp)
|
||||
pushl %ebp
|
||||
call *%ebx
|
||||
popl %eax /* discard */
|
||||
popl %eax /* discard */
|
||||
|
||||
/* Switch to physical addresses, discard PM register store */
|
||||
lcall $VIRTUAL_CS, $_virt_to_phys
|
||||
@ -553,6 +575,22 @@ EXPORT(prot_call):
|
||||
rep movsb
|
||||
movl %esi, %esp /* remove rm_regs from PM stack */
|
||||
|
||||
/* Obtain physical base address of installed copy of librm in
|
||||
* %ebx. (It's possible that this *isn't* the physical base
|
||||
* address of the copy we're currently executing in, because
|
||||
* the protected-mode call could have moved librm. If it does
|
||||
* so, it must update librm_base in our copy to reflect the
|
||||
* new location.
|
||||
*/
|
||||
call 1f
|
||||
1: popl %ebp
|
||||
movl OFFSET(librm_base-1b)(%ebp), %ebx
|
||||
|
||||
/* Jump to running in installed copy of librm */
|
||||
addl $OFFSET(1f), %ebx
|
||||
jmp *%ebx
|
||||
1:
|
||||
|
||||
/* Switch to real mode */
|
||||
call prot_to_real
|
||||
.code16
|
||||
|
@ -23,7 +23,6 @@
|
||||
|
||||
/* Current location of librm in base memory */
|
||||
char *installed_librm = librm;
|
||||
static uint32_t installed_librm_phys;
|
||||
|
||||
/* Whether or not we have base memory currently allocated for librm.
|
||||
* Note that we *can* have a working librm present in unallocated base
|
||||
@ -67,7 +66,8 @@ void remove_from_rm_stack ( void *data, size_t size ) {
|
||||
* Install librm to base memory
|
||||
*
|
||||
*/
|
||||
static inline void install_librm ( char *addr ) {
|
||||
static void install_librm ( char *addr ) {
|
||||
librm_base = virt_to_phys ( addr );
|
||||
memcpy ( addr, librm, librm_size );
|
||||
installed_librm = addr;
|
||||
}
|
||||
@ -79,21 +79,25 @@ static inline void install_librm ( char *addr ) {
|
||||
* copy.
|
||||
*
|
||||
*/
|
||||
static inline void uninstall_librm ( void ) {
|
||||
static void uninstall_librm ( void ) {
|
||||
memcpy ( librm, installed_librm, librm_size );
|
||||
librm_base = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* On entry, record the physical location of librm. Do this so that
|
||||
* we can update installed_librm after relocation.
|
||||
*
|
||||
* Doing this is probably more efficient than making installed_librm
|
||||
* be a physical address, because of the number of times that
|
||||
* installed_librm gets referenced in the remainder of the code.
|
||||
* If librm isn't installed (i.e. if we have librm, but weren't
|
||||
* entered via it), then install librm and a real-mode stack to a
|
||||
* fixed temporary location, just so that we can e.g. issue printf()
|
||||
*
|
||||
* [ If we were entered via librm, then the real_to_prot call will
|
||||
* have filled in librm_base. ]
|
||||
*/
|
||||
static void librm_init ( void ) {
|
||||
installed_librm_phys = virt_to_phys ( installed_librm );
|
||||
if ( ! librm_base ) {
|
||||
install_librm ( phys_to_virt ( 0x7c00 ) );
|
||||
inst_rm_stack.segment = 0x7c0;
|
||||
inst_rm_stack.offset = 0x1000;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -112,19 +116,17 @@ static void librm_exit ( void ) {
|
||||
}
|
||||
|
||||
/*
|
||||
* On reset, we want to free up our old installed copy of librm, if
|
||||
* any, then allocate a new base memory block and install there.
|
||||
* Reset gets called immediately after relocation.
|
||||
*
|
||||
*/
|
||||
|
||||
static void librm_reset ( void ) {
|
||||
char *new_librm;
|
||||
|
||||
/* Point installed_librm back at last known physical location */
|
||||
installed_librm = phys_to_virt ( installed_librm_phys );
|
||||
|
||||
/* Uninstall old librm */
|
||||
uninstall_librm();
|
||||
/* Point installed_librm back at last known physical location.
|
||||
* Do this in case we have just relocated and the virtual
|
||||
* address has therefore changed. */
|
||||
installed_librm = phys_to_virt ( librm_base );
|
||||
|
||||
/* Free allocated base memory, if applicable */
|
||||
librm_exit();
|
||||
|
Loading…
Reference in New Issue
Block a user