Browse Source

[librm] Transition to protected mode within init_librm()

Long-mode operation will require page tables, which are too large to
sensibly fit in our .data16 segment in base memory.

Add a portion of init_librm() running in 32-bit protected mode to
provide access to high memory.  Use this portion of init_librm() to
initialise the .textdata variables "virt_offset", "text16", and
"data16", eliminating the redundant (re)initialisation currently
performed on every mode transition as part of real_to_prot().

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 9 years ago
parent
commit
6eb1c927a3
2 changed files with 127 additions and 107 deletions
  1. 1
    4
      src/arch/x86/include/librm.h
  2. 126
    103
      src/arch/x86/transitions/librm.S

+ 1
- 4
src/arch/x86/include/librm.h View File

@@ -14,10 +14,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
14 14
 #define PHYSICAL_DS 0x20
15 15
 #define REAL_CS 0x28
16 16
 #define REAL_DS 0x30
17
-#if 0
18
-#define LONG_CS 0x38
19
-#define LONG_DS 0x40
20
-#endif
17
+#define P2R_DS 0x38
21 18
 
22 19
 #ifdef ASSEMBLY
23 20
 

+ 126
- 103
src/arch/x86/transitions/librm.S View File

@@ -70,14 +70,96 @@ real_cs: 	/* 16 bit real mode code segment */
70 70
 	.word	0xffff, 0
71 71
 	.byte	0, 0x9b, 0x00, 0
72 72
 
73
-	.org	gdt + REAL_DS	
73
+	.org	gdt + REAL_DS, 0
74 74
 real_ds:	/* 16 bit real mode data segment */
75
-	.word	0xffff, ( REAL_DS << 4 )
75
+	.word	0xffff, 0
76
+	.byte	0, 0x93, 0x00, 0
77
+
78
+	.org	gdt + P2R_DS, 0
79
+p2r_ds:		/* 16 bit real mode data segment for prot_to_real transition */
80
+	.word	0xffff, ( P2R_DS << 4 )
76 81
 	.byte	0, 0x93, 0x00, 0
77 82
 
78 83
 gdt_end:
79 84
 	.equ	gdt_length, gdt_end - gdt
80 85
 
86
+/****************************************************************************
87
+ * Stored real-mode and protected-mode stack pointers
88
+ *
89
+ * The real-mode stack pointer is stored here whenever real_to_prot
90
+ * is called and restored whenever prot_to_real is called.  The
91
+ * converse happens for the protected-mode stack pointer.
92
+ *
93
+ * Despite initial appearances this scheme is, in fact re-entrant,
94
+ * because program flow dictates that we always return via the point
95
+ * we left by.  For example:
96
+ *    PXE API call entry
97
+ *  1   real => prot
98
+ *        ...
99
+ *        Print a text string
100
+ *	    ...
101
+ *  2       prot => real
102
+ *            INT 10
103
+ *  3       real => prot
104
+ *	    ...
105
+ *        ...
106
+ *  4   prot => real
107
+ *    PXE API call exit
108
+ *
109
+ * At point 1, the RM mode stack value, say RPXE, is stored in
110
+ * rm_ss,sp.  We want this value to still be present in rm_ss,sp when
111
+ * we reach point 4.
112
+ *
113
+ * At point 2, the RM stack value is restored from RPXE.  At point 3,
114
+ * the RM stack value is again stored in rm_ss,sp.  This *does*
115
+ * overwrite the RPXE that we have stored there, but it's the same
116
+ * value, since the code between points 2 and 3 has managed to return
117
+ * to us.
118
+ ****************************************************************************
119
+ */
120
+	.section ".bss.rm_sp", "aw", @nobits
121
+	.globl rm_sp
122
+rm_sp:	.word 0
123
+
124
+	.section ".bss.rm_ss", "aw", @nobits
125
+	.globl rm_ss
126
+rm_ss:	.word 0
127
+
128
+	.section ".data.pm_esp", "aw", @progbits
129
+pm_esp:	.long _estack
130
+
131
+/****************************************************************************
132
+ * Virtual address offsets
133
+ *
134
+ * These are used by the protected-mode code to map between virtual
135
+ * and physical addresses, and to access variables in the .text16 or
136
+ * .data16 segments.
137
+ ****************************************************************************
138
+ */
139
+	.struct 0
140
+VA_VIRT_OFFSET:	.space	4
141
+VA_TEXT16:	.space	4
142
+VA_DATA16:	.space	4
143
+VA_SIZE:
144
+	.previous
145
+
146
+	/* Internal copies, used only by librm itself */
147
+	.section ".bss16.rm_virt_addrs", "aw", @nobits
148
+rm_virt_addrs:	.space	VA_SIZE
149
+	.equ	rm_virt_offset, ( rm_virt_addrs + VA_VIRT_OFFSET )
150
+	.equ	rm_text16, ( rm_virt_addrs + VA_TEXT16 )
151
+	.equ	rm_data16, ( rm_virt_addrs + VA_DATA16 )
152
+
153
+	/* Externally visible variables, used by C code */
154
+	.section ".bss.virt_addrs", "aw", @nobits
155
+virt_addrs:	.space	VA_SIZE
156
+	.globl	virt_offset
157
+	.equ	virt_offset, ( virt_addrs + VA_VIRT_OFFSET )
158
+	.globl	text16
159
+	.equ	text16, ( virt_addrs + VA_TEXT16 )
160
+	.globl	data16
161
+	.equ	data16, ( virt_addrs + VA_DATA16 )
162
+
81 163
 /****************************************************************************
82 164
  * init_librm (real-mode far call, 16-bit real-mode far return address)
83 165
  *
@@ -96,45 +178,65 @@ init_librm:
96 178
 	/* Preserve registers */
97 179
 	pushl	%eax
98 180
 	pushl	%ebx
181
+	pushl	%edi
99 182
 
100
-	/* Store virt_offset and set up virtual_cs and virtual_ds segments */
183
+	/* Store rm_virt_offset and set up virtual_cs and virtual_ds segments */
184
+	movl	%edi, rm_virt_offset
101 185
 	movl	%edi, %eax
102 186
 	movw	$virtual_cs, %bx
103 187
 	call	set_seg_base
104 188
 	movw	$virtual_ds, %bx
105
-	call	set_seg_base	
106
-	movl	%edi, rm_virt_offset
189
+	call	set_seg_base
107 190
 
108
-	/* Negate virt_offset */
109
-	negl	%edi
110
-		
111
-	/* Store rm_cs and text16, set up real_cs segment */
191
+	/* Store rm_cs and rm_text16, set up real_cs segment */
112 192
 	xorl	%eax, %eax
113 193
 	movw	%cs, %ax
114 194
 	movw	%ax, %cs:rm_cs
115 195
 	shll	$4, %eax
116 196
 	movw	$real_cs, %bx
117 197
 	call	set_seg_base
118
-	addr32 leal	(%eax, %edi), %ebx
119
-	movl	%ebx, rm_text16
198
+	subl	%edi, %eax
199
+	movl	%eax, rm_text16
120 200
 
121
-	/* Store rm_ds and data16 */
201
+	/* Store rm_ds and rm_data16, set up real_ds segment and GDT base */
122 202
 	xorl	%eax, %eax
123 203
 	movw	%ds, %ax
124 204
 	movw	%ax, %cs:rm_ds
125 205
 	shll	$4, %eax
126
-	addr32 leal	(%eax, %edi), %ebx
127
-	movl	%ebx, rm_data16
128
-
129
-	/* Set GDT base */
206
+	movw	$real_ds, %bx
207
+	call	set_seg_base
130 208
 	movl	%eax, gdt_base
131 209
 	addl	$gdt, gdt_base
210
+	subl	%edi, %eax
211
+	movl	%eax, rm_data16
212
+
213
+	/* Switch to protected mode */
214
+	virtcall init_librm_pmode
215
+	.section ".text.init_librm", "ax", @progbits
216
+	.code32
217
+init_librm_pmode:
218
+
219
+	/* Store virt_offset, text16, and data16 */
220
+	pushw	%ds
221
+	movw	$REAL_DS, %ax
222
+	movw	%ax, %ds
223
+	movl	$rm_virt_addrs, %esi
224
+	movl	$virt_addrs, %edi
225
+	movl	$( VA_SIZE / 4 ), %ecx
226
+	rep movsl
227
+	popw	%ds
228
+
229
+	/* Return to real mode */
230
+	ret
231
+	.section ".text16.init_librm", "ax", @progbits
232
+	.code16
233
+init_librm_rmode:
132 234
 
133 235
 	/* Initialise IDT */
134 236
 	virtcall init_idt
135 237
 
136 238
 	/* Restore registers */
137
-	negl	%edi
239
+	popl	%edi
138 240
 	popl	%ebx
139 241
 	popl	%eax
140 242
 	lret
@@ -177,16 +279,10 @@ real_to_prot:
177 279
 1:	jc	1b
178 280
 
179 281
 	/* Make sure we have our data segment available */
180
-	movw	%cs:rm_ds, %ax
181
-	movw	%ax, %ds
282
+	movw	%cs:rm_ds, %ds
182 283
 
183
-	/* Add virt_offset, text16 and data16 to stack to be
184
-	 * copied, and also copy the return address.
185
-	 */
186
-	pushl	rm_virt_offset
187
-	pushl	rm_text16
188
-	pushl	rm_data16
189
-	addw	$16, %cx /* %ecx must be less than 64kB anyway */
284
+	/* Add protected-mode return address to length of data to be copied */
285
+	addw	$4, %cx /* %ecx must be less than 64kB anyway */
190 286
 
191 287
 	/* Real-mode %ss:%sp => %ebp:%edx and virtual address => %esi */
192 288
 	xorl	%ebp, %ebp
@@ -242,11 +338,6 @@ r2p_pmode:
242 338
 	movl	%esp, %edi
243 339
 	rep movsb
244 340
 
245
-	/* Publish virt_offset, text16 and data16 for PM code to use */
246
-	popl	data16
247
-	popl	text16
248
-	popl	virt_offset
249
-
250 341
 	/* Return to virtual address */
251 342
 	ret
252 343
 
@@ -284,7 +375,7 @@ prot_to_real:
284 375
 
285 376
 	/* Add return address to data to be moved to RM stack */
286 377
 	addl	$4, %ecx
287
-	
378
+
288 379
 	/* Real-mode %ss:sp => %ebp:edx and virtual address => %edi */
289 380
 	movzwl	rm_ss, %ebp
290 381
 	movzwl	rm_sp, %edx
@@ -293,16 +384,16 @@ prot_to_real:
293 384
 	shll	$4, %eax
294 385
 	leal	(%eax,%edx), %edi
295 386
 	subl	virt_offset, %edi
296
-	
387
+
297 388
 	/* Move data from PM stack to RM stack */
298 389
 	movl	%esp, %esi
299 390
 	rep movsb
300
-	
391
+
301 392
 	/* Record protected-mode %esp (after removal of data) */
302 393
 	movl	%esi, pm_esp
303 394
 
304 395
 	/* Load real-mode segment limits */
305
-	movw	$REAL_DS, %ax
396
+	movw	$P2R_DS, %ax
306 397
 	movw	%ax, %ds
307 398
 	movw	%ax, %es
308 399
 	movw	%ax, %fs
@@ -604,71 +695,3 @@ interrupt_wrapper:
604 695
 	/* Restore registers and return */
605 696
 	popal
606 697
 	iret
607
-
608
-/****************************************************************************
609
- * Stored real-mode and protected-mode stack pointers
610
- *
611
- * The real-mode stack pointer is stored here whenever real_to_prot
612
- * is called and restored whenever prot_to_real is called.  The
613
- * converse happens for the protected-mode stack pointer.
614
- *
615
- * Despite initial appearances this scheme is, in fact re-entrant,
616
- * because program flow dictates that we always return via the point
617
- * we left by.  For example:
618
- *    PXE API call entry
619
- *  1   real => prot
620
- *        ...
621
- *        Print a text string
622
- *	    ...
623
- *  2       prot => real
624
- *            INT 10
625
- *  3       real => prot
626
- *	    ...
627
- *        ...
628
- *  4   prot => real
629
- *    PXE API call exit
630
- *
631
- * At point 1, the RM mode stack value, say RPXE, is stored in
632
- * rm_ss,sp.  We want this value to still be present in rm_ss,sp when
633
- * we reach point 4.
634
- *
635
- * At point 2, the RM stack value is restored from RPXE.  At point 3,
636
- * the RM stack value is again stored in rm_ss,sp.  This *does*
637
- * overwrite the RPXE that we have stored there, but it's the same
638
- * value, since the code between points 2 and 3 has managed to return
639
- * to us.
640
- ****************************************************************************
641
- */
642
-	.section ".bss.rm_sp", "aw", @nobits
643
-	.globl rm_sp
644
-rm_sp:	.word 0
645
-
646
-	.section ".bss.rm_ss", "aw", @nobits
647
-	.globl rm_ss
648
-rm_ss:	.word 0
649
-
650
-	.section ".data.pm_esp", "aw", @progbits
651
-pm_esp:	.long _estack
652
-
653
-/****************************************************************************
654
- * Virtual address offsets
655
- *
656
- * These are used by the protected-mode code to map between virtual
657
- * and physical addresses, and to access variables in the .text16 or
658
- * .data16 segments.
659
- ****************************************************************************
660
- */
661
-	/* Internal copies, created by init_librm (which runs in real mode) */
662
-	.section ".bss16.rm_virt_offset", "aw", @nobits
663
-rm_virt_offset:	.long 0
664
-rm_text16:	.long 0
665
-rm_data16:	.long 0
666
-
667
-	/* Externally-visible copies, created by real_to_prot */
668
-	.section ".bss.virt_offset", "aw", @nobits
669
-	.globl virt_offset
670
-virt_offset:	.long 0	
671
-	.globl text16
672
-text16:		.long 0
673
-	.globl data16
674
-data16:		.long 0

Loading…
Cancel
Save