|
@@ -144,7 +144,17 @@ _librm_start:
|
144
|
144
|
****************************************************************************
|
145
|
145
|
*/
|
146
|
146
|
.fill FREE_BASEMEM_HEADER_SIZE, 1, 0
|
147
|
|
-
|
|
147
|
+
|
|
148
|
+/****************************************************************************
|
|
149
|
+ * Record of the current physical location of the installed copy.
|
|
150
|
+ * Used by prot_call in order to return via the current installed copy
|
|
151
|
+ * even if Etherboot has been relocated during the protected-mode
|
|
152
|
+ * call.
|
|
153
|
+ ****************************************************************************
|
|
154
|
+ */
|
|
155
|
+EXPORT(librm_base):
|
|
156
|
+librm_base: .long 0
|
|
157
|
+
|
148
|
158
|
/****************************************************************************
|
149
|
159
|
* GDT for initial transition to protected mode
|
150
|
160
|
*
|
|
@@ -266,6 +276,9 @@ EXPORT(real_to_prot):
|
266
|
276
|
xorl %ebx, %ebx
|
267
|
277
|
movw %cs, %bx
|
268
|
278
|
shll $4, %ebx
|
|
279
|
+
|
|
280
|
+ /* Record physical base address of librm */
|
|
281
|
+ movl %ebx, %ds:OFFSET(librm_base)
|
269
|
282
|
|
270
|
283
|
/* Check base address of stored protected-mode GDT. If it's
|
271
|
284
|
* zero, set it up to use our internal GDT (with physical
|
|
@@ -360,6 +373,9 @@ EXPORT(prot_to_real):
|
360
|
373
|
popl OFFSET(save_ebx)(%ebx)
|
361
|
374
|
movl %eax, OFFSET(save_eax)(%ebx)
|
362
|
375
|
|
|
376
|
+ /* Record physical base address of librm */
|
|
377
|
+ movl %ebx, OFFSET(librm_base)(%ebx)
|
|
378
|
+
|
363
|
379
|
/* Extract return address from the stack, convert to offset
|
364
|
380
|
* within librm and save in save_retaddr
|
365
|
381
|
*/
|
|
@@ -445,22 +461,32 @@ p2r_ljmp:
|
445
|
461
|
*
|
446
|
462
|
* Call a specific C function in the protected-mode code. The
|
447
|
463
|
* prototype of the C function must be
|
448
|
|
- * void function ( struct real_mode_regs *rm_regs,
|
449
|
|
- * void (*retaddr) (void) );
|
|
464
|
+ * void function ( struct real_mode_regs *rm_regs );
|
450
|
465
|
* rm_regs will point to a struct containing the real-mode registers
|
451
|
|
- * at entry to prot_call. retaddr will point to the (virtual) return
|
452
|
|
- * address from "function". This return address will point into
|
453
|
|
- * librm. It is included so that "function" may, if desired, relocate
|
454
|
|
- * librm and return via the new copy. It must not be directly called
|
455
|
|
- * as a function, i.e. you may not do "*retaddr()"; you must instead
|
456
|
|
- * do something like:
|
457
|
|
- * *retaddr += ( new_librm_location - old_librm_location );
|
458
|
|
- * return;
|
|
466
|
+ * at entry to prot_call.
|
459
|
467
|
*
|
460
|
468
|
* All registers will be preserved across prot_call(), unless the C
|
461
|
469
|
* function explicitly overwrites values in rm_regs. Interrupt status
|
462
|
470
|
* will also be preserved. Gate A20 will be enabled.
|
463
|
471
|
*
|
|
472
|
+ * The protected-mode code may install librm to a new location. If it
|
|
473
|
+ * does so, it must update librm_base in *this* copy of librm to point
|
|
474
|
+ * to the new physical location. prot_call will then return via the
|
|
475
|
+ * newly installed copy.
|
|
476
|
+ *
|
|
477
|
+ * Note that when Etherboot performs its initial relocation, "*this*"
|
|
478
|
+ * copy in the above paragraph will refer to the "master" copy, since
|
|
479
|
+ * that is the initial installed copy. Etherboot will return to
|
|
480
|
+ * prot_call using a virtual address, so will return to the master
|
|
481
|
+ * copy in high memory (rather than the original copy in base memory).
|
|
482
|
+ * The master copy in high memory will have the physical address of
|
|
483
|
+ * the newly installed copy in librm_base, since install_librm()
|
|
484
|
+ * writes it there. Thus, Etherboot's initialise() function will
|
|
485
|
+ * return to the master copy of prot_call(), which will then jump to
|
|
486
|
+ * the installed copy.
|
|
487
|
+ *
|
|
488
|
+ * It works, trust me.
|
|
489
|
+ *
|
464
|
490
|
* Parameters:
|
465
|
491
|
* function : virtual address of protected-mode function to call
|
466
|
492
|
*
|
|
@@ -529,14 +555,10 @@ EXPORT(prot_call):
|
529
|
555
|
popl %eax /* discard */
|
530
|
556
|
popal
|
531
|
557
|
|
532
|
|
- /* Push &rm_regs and &retaddr on the stack, and call function */
|
533
|
|
- movl %esp, %ebp
|
|
558
|
+ /* Push &rm_regs on the stack, and call function */
|
534
|
559
|
pushl %esp
|
535
|
|
- subl $12, 0(%esp)
|
536
|
|
- pushl %ebp
|
537
|
560
|
call *%ebx
|
538
|
561
|
popl %eax /* discard */
|
539
|
|
- popl %eax /* discard */
|
540
|
562
|
|
541
|
563
|
/* Switch to physical addresses, discard PM register store */
|
542
|
564
|
lcall $VIRTUAL_CS, $_virt_to_phys
|
|
@@ -553,6 +575,22 @@ EXPORT(prot_call):
|
553
|
575
|
rep movsb
|
554
|
576
|
movl %esi, %esp /* remove rm_regs from PM stack */
|
555
|
577
|
|
|
578
|
+ /* Obtain physical base address of installed copy of librm in
|
|
579
|
+ * %ebx. (It's possible that this *isn't* the physical base
|
|
580
|
+ * address of the copy we're currently executing in, because
|
|
581
|
+ * the protected-mode call could have moved librm. If it does
|
|
582
|
+ * so, it must update librm_base in our copy to reflect the
|
|
583
|
+ * new location.
|
|
584
|
+ */
|
|
585
|
+ call 1f
|
|
586
|
+1: popl %ebp
|
|
587
|
+ movl OFFSET(librm_base-1b)(%ebp), %ebx
|
|
588
|
+
|
|
589
|
+ /* Jump to running in installed copy of librm */
|
|
590
|
+ addl $OFFSET(1f), %ebx
|
|
591
|
+ jmp *%ebx
|
|
592
|
+1:
|
|
593
|
+
|
556
|
594
|
/* Switch to real mode */
|
557
|
595
|
call prot_to_real
|
558
|
596
|
.code16
|