Explorar el Código

Make prot_call() able to transparently return via the newly installed copy

of librm.
tags/v0.9.3
Michael Brown hace 19 años
padre
commit
04a99841e6
Se han modificado 2 ficheros con 73 adiciones y 33 borrados
  1. 54
    16
      src/arch/i386/transitions/librm.S
  2. 19
    17
      src/arch/i386/transitions/librm_mgmt.c

+ 54
- 16
src/arch/i386/transitions/librm.S Ver fichero

144
  ****************************************************************************
144
  ****************************************************************************
145
  */
145
  */
146
 	.fill FREE_BASEMEM_HEADER_SIZE, 1, 0
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
  * GDT for initial transition to protected mode
159
  * GDT for initial transition to protected mode
150
  *
160
  *
266
 	xorl	%ebx, %ebx
276
 	xorl	%ebx, %ebx
267
 	movw	%cs, %bx
277
 	movw	%cs, %bx
268
 	shll	$4, %ebx
278
 	shll	$4, %ebx
279
+
280
+	/* Record physical base address of librm */
281
+	movl	%ebx, %ds:OFFSET(librm_base)
269
 		
282
 		
270
 	/* Check base address of stored protected-mode GDT.  If it's
283
 	/* Check base address of stored protected-mode GDT.  If it's
271
 	 * zero, set it up to use our internal GDT (with physical
284
 	 * zero, set it up to use our internal GDT (with physical
360
 	popl	OFFSET(save_ebx)(%ebx)
373
 	popl	OFFSET(save_ebx)(%ebx)
361
 	movl	%eax, OFFSET(save_eax)(%ebx)
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
 	/* Extract return address from the stack, convert to offset
379
 	/* Extract return address from the stack, convert to offset
364
 	 * within librm and save in save_retaddr
380
 	 * within librm and save in save_retaddr
365
 	 */
381
 	 */
445
  *
461
  *
446
  * Call a specific C function in the protected-mode code.  The
462
  * Call a specific C function in the protected-mode code.  The
447
  * prototype of the C function must be
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
  * rm_regs will point to a struct containing the real-mode registers
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
  * All registers will be preserved across prot_call(), unless the C
468
  * All registers will be preserved across prot_call(), unless the C
461
  * function explicitly overwrites values in rm_regs.  Interrupt status
469
  * function explicitly overwrites values in rm_regs.  Interrupt status
462
  * will also be preserved.  Gate A20 will be enabled.
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
  * Parameters:
490
  * Parameters:
465
  *   function : virtual address of protected-mode function to call
491
  *   function : virtual address of protected-mode function to call
466
  *
492
  *
529
 	popl	%eax	/* discard */
555
 	popl	%eax	/* discard */
530
 	popal
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
 	pushl	%esp
559
 	pushl	%esp
535
-	subl	$12, 0(%esp)
536
-	pushl	%ebp
537
 	call	*%ebx
560
 	call	*%ebx
538
 	popl	%eax /* discard */
561
 	popl	%eax /* discard */
539
-	popl	%eax /* discard */
540
 
562
 
541
 	/* Switch to physical addresses, discard PM register store */
563
 	/* Switch to physical addresses, discard PM register store */
542
 	lcall	$VIRTUAL_CS, $_virt_to_phys
564
 	lcall	$VIRTUAL_CS, $_virt_to_phys
553
 	rep movsb
575
 	rep movsb
554
 	movl	%esi, %esp	/* remove rm_regs from PM stack */
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
 	/* Switch to real mode */
594
 	/* Switch to real mode */
557
 	call	prot_to_real
595
 	call	prot_to_real
558
 	.code16
596
 	.code16

+ 19
- 17
src/arch/i386/transitions/librm_mgmt.c Ver fichero

23
 
23
 
24
 /* Current location of librm in base memory */
24
 /* Current location of librm in base memory */
25
 char *installed_librm = librm;
25
 char *installed_librm = librm;
26
-static uint32_t installed_librm_phys;
27
 
26
 
28
 /* Whether or not we have base memory currently allocated for librm.
27
 /* Whether or not we have base memory currently allocated for librm.
29
  * Note that we *can* have a working librm present in unallocated base
28
  * Note that we *can* have a working librm present in unallocated base
67
  * Install librm to base memory
66
  * Install librm to base memory
68
  *
67
  *
69
  */
68
  */
70
-static inline void install_librm ( char *addr ) {
69
+static void install_librm ( char *addr ) {
70
+	librm_base = virt_to_phys ( addr );
71
 	memcpy ( addr, librm, librm_size );
71
 	memcpy ( addr, librm, librm_size );
72
 	installed_librm = addr;
72
 	installed_librm = addr;
73
 }
73
 }
79
  * copy.
79
  * copy.
80
  *
80
  *
81
  */
81
  */
82
-static inline void uninstall_librm ( void ) {
82
+static void uninstall_librm ( void ) {
83
 	memcpy ( librm, installed_librm, librm_size );
83
 	memcpy ( librm, installed_librm, librm_size );
84
+	librm_base = 0;
84
 }
85
 }
85
 
86
 
86
 /*
87
 /*
87
- * On entry, record the physical location of librm.  Do this so that
88
- * we can update installed_librm after relocation.
89
- *
90
- * Doing this is probably more efficient than making installed_librm
91
- * be a physical address, because of the number of times that
92
- * installed_librm gets referenced in the remainder of the code.
88
+ * If librm isn't installed (i.e. if we have librm, but weren't
89
+ * entered via it), then install librm and a real-mode stack to a
90
+ * fixed temporary location, just so that we can e.g. issue printf()
93
  *
91
  *
92
+ * [ If we were entered via librm, then the real_to_prot call will
93
+ * have filled in librm_base. ]
94
  */
94
  */
95
 static void librm_init ( void ) {
95
 static void librm_init ( void ) {
96
-	installed_librm_phys = virt_to_phys ( installed_librm );
96
+	if ( ! librm_base ) {
97
+		install_librm ( phys_to_virt ( 0x7c00 ) );
98
+		inst_rm_stack.segment = 0x7c0;
99
+		inst_rm_stack.offset = 0x1000;
100
+	}
97
 }
101
 }
98
 
102
 
99
 /*
103
 /*
112
 }
116
 }
113
 
117
 
114
 /*
118
 /*
115
- * On reset, we want to free up our old installed copy of librm, if
116
- * any, then allocate a new base memory block and install there.
119
+ * Reset gets called immediately after relocation.
117
  *
120
  *
118
  */
121
  */
119
 
122
 
120
 static void librm_reset ( void ) {
123
 static void librm_reset ( void ) {
121
 	char *new_librm;
124
 	char *new_librm;
122
 
125
 
123
-	/* Point installed_librm back at last known physical location */
124
-	installed_librm = phys_to_virt ( installed_librm_phys );
125
-
126
-	/* Uninstall old librm */
127
-	uninstall_librm();
126
+	/* Point installed_librm back at last known physical location.
127
+	 * Do this in case we have just relocated and the virtual
128
+	 * address has therefore changed. */
129
+	installed_librm = phys_to_virt ( librm_base );
128
 
130
 
129
 	/* Free allocated base memory, if applicable */
131
 	/* Free allocated base memory, if applicable */
130
 	librm_exit();
132
 	librm_exit();

Loading…
Cancelar
Guardar