Browse Source

[prefix] Use 16-bit protected mode for access to high memory

Flat real mode works perfectly on real hardware, but seems to cause
problems for some hypervisors.  Revert to using 16-bit protected mode
(and returning to real mode with 4GB limits, so as not to break PMM
BIOSes).

Allow the code specific to the .mrom format to continue to assume that
flat real mode works, since this format is specific to real hardware.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 13 years ago
parent
commit
a84e15234a
2 changed files with 195 additions and 42 deletions
  1. 189
    41
      src/arch/i386/prefix/libprefix.S
  2. 6
    1
      src/arch/i386/prefix/mromprefix.S

+ 189
- 41
src/arch/i386/prefix/libprefix.S View File

@@ -24,6 +24,9 @@ FILE_LICENCE ( GPL2_OR_LATER )
24 24
 /* Image compression enabled */
25 25
 #define COMPRESS 1
26 26
 
27
+/* Protected mode flag */
28
+#define CR0_PE 1
29
+
27 30
 /*****************************************************************************
28 31
  * Utility function: print character (with LF -> LF,CR translation)
29 32
  *
@@ -229,41 +232,153 @@ print_kill_line:
229 232
  *   None
230 233
  ****************************************************************************
231 234
  */
232
-#if ! COMPRESS
233 235
 	.section ".prefix.lib", "awx", @progbits
234 236
 	.code16
235 237
 copy_bytes:
236
-	pushl %ecx
238
+	pushl	%ecx
237 239
 	rep addr32 movsb
238
-	popl %ecx
240
+	popl	%ecx
239 241
 	ret
240
-	.size copy_bytes, . - copy_bytes
241
-#endif /* COMPRESS */
242
+	.size	copy_bytes, . - copy_bytes
242 243
 
243 244
 /****************************************************************************
244
- * install_block
245
+ * zero_bytes
245 246
  *
246
- * Install block to specified address
247
+ * Zero bytes
247 248
  *
248 249
  * Parameters:
249
- *   %esi : source physical address (must be a multiple of 16)
250
- *   %edi : destination physical address (must be a multiple of 16)
251
- *   %ecx : length of (decompressed) data
252
- *   %edx : total length of block (including any uninitialised data portion)
250
+ *   %ds:esi : source address
251
+ *   %es:edi : destination address
252
+ *   %ecx : length
253 253
  * Returns:
254
- *   %esi : next source physical address (will be a multiple of 16)
255
- *   %edi : next destination physical address (will be a multiple of 16)
254
+ *   %ds:esi : next source address
255
+ *   %es:edi : next destination address
256 256
  * Corrupts:
257
- *   none
257
+ *   None
258 258
  ****************************************************************************
259 259
  */
260 260
 	.section ".prefix.lib", "awx", @progbits
261 261
 	.code16
262
-install_block:
262
+zero_bytes:
263
+	pushl	%ecx
264
+	pushw	%ax
265
+	xorw	%ax, %ax
266
+	rep addr32 stosb
267
+	popw	%ax
268
+	popl	%ecx
269
+	ret
270
+	.size	zero_bytes, . - zero_bytes
271
+
272
+/****************************************************************************
273
+ * process_bytes
274
+ *
275
+ * Call memcpy()-like function
276
+ *
277
+ * Parameters:
278
+ *   %esi : source physical address
279
+ *   %edi : destination physical address
280
+ *   %ecx : length
281
+ *   %bx : memcpy()-like function to call, passing parameters:
282
+ *	     %ds:esi : source address
283
+ *	     %es:edi : destination address
284
+ *	     %ecx : length
285
+ *         and returning:
286
+ *	     %ds:esi : next source address
287
+ *	     %es:edi : next destination address
288
+ * Returns:
289
+ *   %esi : next source physical address
290
+ *   %edi : next destination physical address
291
+ * Corrupts:
292
+ *   None
293
+ ****************************************************************************
294
+ */
295
+	.section ".prefix.lib", "awx", @progbits
296
+	.code16
297
+process_bytes:
298
+
299
+#ifndef KEEP_IT_REAL
300
+
263 301
 	/* Preserve registers */
302
+	pushfw
303
+	pushl	%eax
304
+	pushl	%ebp
305
+
306
+	/* Construct GDT on stack (since .prefix may not be writable) */
307
+	.equ	PM_DS, 0x18	/* Flat data segment */
308
+	pushl	$0x008f9300
309
+	pushl	$0x0000ffff
310
+	.equ	PM_SS, 0x10	/* Stack segment based at %ss:0000 */
311
+	pushl	$0x008f0930
312
+	pushw	%ss
313
+	pushw	$0xffff
314
+	.equ	PM_CS, 0x08	/* Code segment based at %cs:0000 */
315
+	pushl	$0x008f09b0
316
+	pushw	%cs
317
+	pushw	$0xffff
318
+	pushl	$0		/* Base and length */
319
+	pushw	%ss
320
+	pushw	$0x1f
321
+	movzwl	%sp, %ebp
322
+	shll	$4, 0x02(%bp)
323
+	addl	%ebp, 0x02(%bp)
324
+	shll	$4, 0x0a(%bp)
325
+	shll	$4, 0x12(%bp)
326
+	subw	$8, %sp
327
+	sgdt	-8(%bp)
328
+
329
+	/* Switch to protected mode */
330
+	pushw	%gs
331
+	pushw	%fs
332
+	pushw	%es
333
+	pushw	%ds
334
+	pushw	%ss
335
+	pushw	%cs
336
+	pushw	$2f
337
+	cli
338
+	data32 lgdt (%bp)
339
+	movl	%cr0, %eax
340
+	orb	$CR0_PE, %al
341
+	movl	%eax, %cr0
342
+	ljmp	$PM_CS, $1f
343
+1:	movw	$PM_SS, %ax
344
+	movw	%ax, %ss
345
+	movw	$PM_DS, %ax
346
+	movw	%ax, %ds
347
+	movw	%ax, %es
348
+	movw	%ax, %fs
349
+	movw	%ax, %gs
350
+
351
+	/* Call memcpy()-like function */
352
+	call	*%bx
353
+
354
+	/* Return to (flat) real mode */
355
+	movl	%cr0, %eax
356
+	andb	$0!CR0_PE, %al
357
+	movl	%eax, %cr0
358
+	lret
359
+2:	/* lret will ljmp to here */
360
+	popw	%ss
361
+	popw	%ds
362
+	popw	%es
363
+	popw	%fs
364
+	popw	%gs
365
+
366
+	/* Restore GDT */
367
+	data32 lgdt -8(%bp)
368
+	addw	$( 8 /* saved GDT */ + ( PM_DS + 8 ) /* GDT on stack */ ), %sp
369
+
370
+	/* Restore registers and return */
371
+	popl	%ebp
372
+	popl	%eax
373
+	popfw
374
+	ret
375
+
376
+#else /* KEEP_IT_REAL */
377
+
378
+	/* Preserve registers */
379
+	pushl	%eax
264 380
 	pushw	%ds
265 381
 	pushw	%es
266
-	pushl	%ecx
267 382
 	
268 383
 	/* Convert %esi and %edi to %ds:esi and %es:edi */
269 384
 	shrl	$4, %esi
@@ -275,21 +390,66 @@ install_block:
275 390
 	xorw	%di, %di
276 391
 	shll	$4, %edi
277 392
 
393
+	/* Call memcpy()-like function */
394
+	call	*%bx
395
+
396
+	/* Convert %ds:esi and %es:edi back to physical addresses */
397
+	xorl	%eax, %eax
398
+	movw	%ds, %cx
399
+	shll	$4, %eax
400
+	addl	%eax, %esi
401
+	xorl	%eax, %eax
402
+	movw	%es, %cx
403
+	shll	$4, %eax
404
+	addl	%eax, %edi
405
+
406
+	/* Restore registers and return */
407
+	popw	%es
408
+	popw	%ds
409
+	popl	%eax
410
+	ret
411
+
412
+#endif /* KEEP_IT_REAL */
413
+
414
+	.size	process_bytes, . - process_bytes
415
+
416
+/****************************************************************************
417
+ * install_block
418
+ *
419
+ * Install block to specified address
420
+ *
421
+ * Parameters:
422
+ *   %esi : source physical address (must be a multiple of 16)
423
+ *   %edi : destination physical address (must be a multiple of 16)
424
+ *   %ecx : length of (decompressed) data
425
+ *   %edx : total length of block (including any uninitialised data portion)
426
+ * Returns:
427
+ *   %esi : next source physical address (will be a multiple of 16)
428
+ *   %edi : next destination physical address (will be a multiple of 16)
429
+ * Corrupts:
430
+ *   none
431
+ ****************************************************************************
432
+ */
433
+	.section ".prefix.lib", "awx", @progbits
434
+	.code16
435
+install_block:
436
+	/* Preserve registers */
437
+	pushl	%ecx
438
+	pushw	%bx
439
+
440
+	/* Decompress (or copy) source to destination */
278 441
 #if COMPRESS
279
-	/* Decompress source to destination */
280
-	call	decompress16
442
+	movw	$decompress16, %bx
281 443
 #else
282
-	/* Copy source to destination */
283
-	call	copy_bytes
444
+	movw	$copy_bytes, %bx
284 445
 #endif
446
+	call	process_bytes
285 447
 
286 448
 	/* Zero .bss portion */
287 449
 	negl	%ecx
288 450
 	addl	%edx, %ecx
289
-	pushw	%ax
290
-	xorw	%ax, %ax
291
-	rep addr32 stosb
292
-	popw	%ax
451
+	movw	$zero_bytes, %bx
452
+	call	process_bytes
293 453
 
294 454
 	/* Round up %esi and %edi to start of next blocks */
295 455
 	addl	$0xf, %esi
@@ -297,20 +457,9 @@ install_block:
297 457
 	addl	$0xf, %edi
298 458
 	andl	$~0xf, %edi
299 459
 
300
-	/* Convert %ds:esi and %es:edi back to physical addresses */
301
-	xorl	%ecx, %ecx
302
-	movw	%ds, %cx
303
-	shll	$4, %ecx
304
-	addl	%ecx, %esi
305
-	xorl	%ecx, %ecx
306
-	movw	%es, %cx
307
-	shll	$4, %ecx
308
-	addl	%ecx, %edi
309
-
310 460
 	/* Restore registers and return */
461
+	popw	%bx
311 462
 	popl	%ecx
312
-	popw	%es
313
-	popw	%ds
314 463
 	ret
315 464
 	.size install_block, . - install_block
316 465
 
@@ -612,11 +761,10 @@ payload_death_message:
612 761
 
613 762
 	/* Copy code to new location */
614 763
 	pushl	%edi
615
-	pushw	%ax
616
-	xorw	%ax, %ax
617
-	movw	%ax, %es
618
-	es rep addr32 movsb
619
-	popw	%ax
764
+	pushw	%bx
765
+	movw	$copy_bytes, %bx
766
+	call	process_bytes
767
+	popw	%bx
620 768
 	popl	%edi
621 769
 
622 770
 	/* Initialise librm at new location */

+ 6
- 1
src/arch/i386/prefix/mromprefix.S View File

@@ -151,7 +151,12 @@ find_mem_bar:
151 151
 	/* Copy payload to buffer, or set buffer address to BAR address */
152 152
 	testl	%esi, %esi
153 153
 	jz	1f
154
-	/* We have a buffer; copy payload to it */
154
+	/* We have a buffer; copy payload to it.  Since .mrom is
155
+	 * designed specifically for real hardware, we assume that
156
+	 * flat real mode is working properly.  (In the unlikely event
157
+	 * that this code is run inside a hypervisor that doesn't
158
+	 * properly support flat real mode, it will die horribly.)
159
+	 */
155 160
 	pushl	%esi
156 161
 	pushw	%es
157 162
 	movl	%esi, %edi

Loading…
Cancel
Save