Browse Source

[prefix] Add A20-enabling code in libflat

iPXE currently insists on residing in an even megabyte.  This imposes
undesirably severe constraints upon our PMM allocation strategy, and
limits our options for mechanisms to access ROMs greater than 64kB in
size.

Add A20 handling code to libflat so that prefixes are able to access
memory even in odd megabytes.

The algorithms and tuning parameters in the new A20 handling code are
based upon a mixture of the existing iPXE A20 code and the A20 code
from the 2.6.32 Linux kernel.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 14 years ago
parent
commit
24b52ae476
2 changed files with 296 additions and 8 deletions
  1. 16
    5
      src/arch/i386/prefix/libprefix.S
  2. 280
    3
      src/arch/i386/transitions/libflat.S

+ 16
- 5
src/arch/i386/prefix/libprefix.S View File

@@ -512,13 +512,24 @@ install_prealloc:
512 512
 
513 513
 	/* Open up access to payload */
514 514
 #ifndef KEEP_IT_REAL
515
-	/* Flatten real mode */
515
+	/* Access high memory */
516 516
 	pushw	%cs
517 517
 	pushw	$1f
518 518
 	pushw	%ax
519
-	pushw	$flatten_real_mode
519
+	pushw	$access_highmem
520 520
 	lret
521
-1:
521
+1:	/* Die if we could not access high memory */
522
+	jnc	3f
523
+	movw	$a20_death_message, %si
524
+	xorw	%di, %di
525
+	call	print_message
526
+2:	jmp	2b
527
+	.section ".prefix.data", "aw", @progbits
528
+a20_death_message:
529
+	.asciz	"Gate A20 stuck - cannot continue\n"
530
+	.size	a20_death_message, . - a20_death_message
531
+	.previous
532
+3:
522 533
 #endif
523 534
 
524 535
 	/* Calculate physical address of payload (i.e. first source) */
@@ -570,13 +581,13 @@ install_prealloc:
570 581
 	popl	%edx /* discard */
571 582
 
572 583
 	/* Copy code to new location */
584
+	pushl	%edi
573 585
 	xorw	%ax, %ax
574 586
 	movw	%ax, %es
575
-	movl	%ebp, %edi
576 587
 	es rep addr32 movsb
588
+	popl	%edi
577 589
 
578 590
 	/* Initialise librm at new location */
579
-	movl	%ebp, %edi
580 591
 	lcall	*init_librm_vector
581 592
 #endif
582 593
 

+ 280
- 3
src/arch/i386/transitions/libflat.S View File

@@ -24,7 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER )
24 24
 #define CR0_PE 1
25 25
 
26 26
 /****************************************************************************
27
- * flatten_real_mode (real-mode far call)
27
+ * flatten_real_mode
28 28
  *
29 29
  * Set up 4GB segment limits
30 30
  *
@@ -63,7 +63,6 @@ flatten_saved_gdt:
63 63
 
64 64
 	.section ".text16.early", "awx", @progbits
65 65
 	.code16
66
-	.globl	flatten_real_mode
67 66
 flatten_real_mode:
68 67
 	/* Preserve registers and flags */
69 68
 	pushfl
@@ -126,7 +125,7 @@ flatten_real_mode:
126 125
 	popw	%si
127 126
 	popl	%eax
128 127
 	popfl
129
-	lret
128
+	ret
130 129
 	.size flatten_real_mode, . - flatten_real_mode
131 130
 
132 131
 	.section ".text16.early", "awx", @progbits
@@ -139,3 +138,281 @@ set_seg_base:
139 138
 	andb	$0x0f, 4(%si)
140 139
 	ret
141 140
 	.size set_seg_base, . - set_seg_base
141
+
142
+/****************************************************************************
143
+ * test_a20_short, test_a20_long
144
+ *
145
+ * Check to see if A20 line is enabled
146
+ *
147
+ * Parameters:
148
+ *   none
149
+ * Returns:
150
+ *   CF set if A20 line is not enabled
151
+ * Corrupts:
152
+ *   none
153
+ ****************************************************************************
154
+ */
155
+#define TEST_A20_SHORT_MAX_RETRIES 0x20
156
+#define TEST_A20_LONG_MAX_RETRIES 0x200000
157
+	.section ".text16.early", "awx", @progbits
158
+	.code16
159
+test_a20_short:
160
+	pushl	%ecx
161
+	movl	$TEST_A20_SHORT_MAX_RETRIES, %ecx
162
+	jmp	1f
163
+	.size	test_a20_short, . - test_a20_short
164
+test_a20_long:
165
+	pushl	%ecx
166
+	movl	$TEST_A20_LONG_MAX_RETRIES, %ecx
167
+1:	pushw	%ax
168
+
169
+	/* Flatten real mode so we can access the test pattern's 1MB offset */
170
+	call	flatten_real_mode
171
+
172
+2:	/* Modify and check test pattern; succeed if we see a difference */
173
+	incw	%cs:test_a20_data
174
+	addr32 movw %cs:(test_a20_data + 0x100000 ), %ax
175
+	cmpw	%cs:test_a20_data, %ax
176
+	clc
177
+	jnz	99f
178
+
179
+	/* Delay and retry */
180
+	outb	%al, $0x80
181
+	addr32 loop 2b
182
+	stc
183
+
184
+99:	/* Restore registers and return */
185
+	popw	%ax
186
+	popl	%ecx
187
+	ret
188
+	.size	test_a20_long, . - test_a20_long
189
+
190
+	.section ".text16.early.data", "aw", @progbits
191
+	.align	2
192
+test_a20_data:
193
+	.word	0xdead
194
+	.size	test_a20_data, . - test_a20_data
195
+
196
+/****************************************************************************
197
+ * enable_a20_bios
198
+ *
199
+ * Try enabling A20 line via BIOS
200
+ *
201
+ * Parameters:
202
+ *   none
203
+ * Returns:
204
+ *   CF set if A20 line is not enabled
205
+ * Corrupts:
206
+ *   none
207
+ ****************************************************************************
208
+ */
209
+	.section ".text16.early", "awx", @progbits
210
+	.code16
211
+enable_a20_bios:
212
+	/* Preserve registers */
213
+	pushw	%ax
214
+
215
+	/* Attempt INT 15,2401 */
216
+	movw	$0x2401, %ax
217
+	int	$0x15
218
+	jc	99f
219
+
220
+	/* Check that success was really successful */
221
+	call	test_a20_short
222
+
223
+99:	/* Restore registers and return */
224
+	popw	%ax
225
+	ret
226
+	.size	enable_a20_bios, . - enable_a20_bios
227
+
228
+/****************************************************************************
229
+ * enable_a20_kbc
230
+ *
231
+ * Try enabling A20 line via keyboard controller
232
+ *
233
+ * Parameters:
234
+ *   none
235
+ * Returns:
236
+ *   CF set if A20 line is not enabled
237
+ * Corrupts:
238
+ *   none
239
+ ****************************************************************************
240
+ */
241
+#define KC_RDWR		0x60
242
+#define KC_RDWR_SET_A20		0xdf
243
+#define	KC_CMD		0x64
244
+#define KC_CMD_WOUT		0xd1
245
+#define KC_CMD_NULL		0xff
246
+#define KC_STATUS	0x64
247
+#define KC_STATUS_OBUF_FULL	0x01
248
+#define KC_STATUS_IBUF_FULL	0x02
249
+#define KC_MAX_RETRIES	100000
250
+	.section ".text16.early", "awx", @progbits
251
+	.code16
252
+enable_a20_kbc:
253
+	/* Preserve registers */
254
+	pushw	%ax
255
+
256
+	/* Try keyboard controller */
257
+	call	empty_kbc
258
+	movb	$KC_CMD_WOUT, %al
259
+	outb	%al, $KC_CMD
260
+	call	empty_kbc
261
+	movb	$KC_RDWR_SET_A20, %al
262
+	outb	%al, $KC_RDWR
263
+	call	empty_kbc
264
+	movb	$KC_CMD_NULL, %al
265
+	outb	%al, $KC_CMD
266
+	call	empty_kbc
267
+
268
+	/* Check to see if it worked */
269
+	call	test_a20_long
270
+
271
+	/* Restore registers and return */
272
+	popw	%ax
273
+	ret
274
+	.size	enable_a20_kbc, . - enable_a20_kbc
275
+
276
+	.section ".text16.early", "awx", @progbits
277
+	.code16
278
+empty_kbc:
279
+	/* Preserve registers */
280
+	pushl	%ecx
281
+	pushw	%ax
282
+
283
+	/* Wait for KBC to become empty */
284
+	movl	$KC_MAX_RETRIES, %ecx
285
+1:	outb	%al, $0x80
286
+	inb	$KC_STATUS, %al
287
+	testb	$( KC_STATUS_OBUF_FULL | KC_STATUS_IBUF_FULL ), %al
288
+	jz	99f
289
+	testb	$KC_STATUS_OBUF_FULL, %al
290
+	jz	2f
291
+	outb	%al, $0x80
292
+	inb	$KC_RDWR, %al
293
+2:	addr32 loop 1b
294
+
295
+99:	/* Restore registers and return */
296
+	popw	%ax
297
+	popl	%ecx
298
+	ret
299
+	.size	empty_kbc, . - empty_kbc
300
+
301
+/****************************************************************************
302
+ * enable_a20_fast
303
+ *
304
+ * Try enabling A20 line via "Fast Gate A20"
305
+ *
306
+ * Parameters:
307
+ *   none
308
+ * Returns:
309
+ *   CF set if A20 line is not enabled
310
+ * Corrupts:
311
+ *   none
312
+ ****************************************************************************
313
+ */
314
+#define SCP_A 0x92
315
+	.section ".text16.early", "awx", @progbits
316
+	.code16
317
+enable_a20_fast:
318
+	/* Preserve registers */
319
+	pushw	%ax
320
+
321
+	/* Try "Fast Gate A20" */
322
+	inb	$SCP_A, %al
323
+	orb	$0x02, %al
324
+	andb	$~0x01, %al
325
+	outb	%al, $SCP_A
326
+
327
+	/* Check to see if it worked */
328
+	call	test_a20_long
329
+
330
+	/* Restore registers and return */
331
+	popw	%ax
332
+	ret
333
+	.size	enable_a20_fast, . - enable_a20_fast
334
+
335
+/****************************************************************************
336
+ * enable_a20
337
+ *
338
+ * Try enabling A20 line via any available method
339
+ *
340
+ * Parameters:
341
+ *   none
342
+ * Returns:
343
+ *   CF set if A20 line is not enabled
344
+ * Corrupts:
345
+ *   none
346
+ ****************************************************************************
347
+ */
348
+#define ENABLE_A20_RETRIES 255
349
+	.section ".text16.early", "awx", @progbits
350
+	.code16
351
+enable_a20:
352
+	/* Preserve registers */
353
+	pushl	%ecx
354
+	pushw	%ax
355
+
356
+	/* Check to see if A20 is already enabled */
357
+	call	test_a20_short
358
+	jnc	99f
359
+
360
+	/* Use known working method, if we have one */
361
+	movw	%cs:enable_a20_method, %ax
362
+	testw	%ax, %ax
363
+	jz	1f
364
+	call	*%ax
365
+	jmp	99f
366
+1:
367
+	/* Try all methods in turn until one works */
368
+	movl	$ENABLE_A20_RETRIES, %ecx
369
+2:	movw	$enable_a20_bios, %ax
370
+	movw	%ax, %cs:enable_a20_method
371
+	call	*%ax
372
+	jnc	99f
373
+	movw	$enable_a20_kbc, %ax
374
+	movw	%ax, %cs:enable_a20_method
375
+	call	*%ax
376
+	jnc	99f
377
+	movw	$enable_a20_fast, %ax
378
+	movw	%ax, %cs:enable_a20_method
379
+	call	*%ax
380
+	jnc	99f
381
+	addr32 loop 2b
382
+	/* Failure; exit with carry set */
383
+	movw	$0, %cs:enable_a20_method
384
+	stc
385
+
386
+99:	/* Restore registers and return */
387
+	popw	%ax
388
+	popl	%ecx
389
+	ret
390
+
391
+	.section ".text16.early.data", "aw", @progbits
392
+	.align	2
393
+enable_a20_method:
394
+	.word	0
395
+	.size	enable_a20_method, . - enable_a20_method
396
+
397
+/****************************************************************************
398
+ * access_highmem (real mode far call)
399
+ *
400
+ * Open up access to high memory in flat real mode with A20 enabled
401
+ *
402
+ * Parameters:
403
+ *   none
404
+ * Returns:
405
+ *   CF set if high memory could not be accessed
406
+ * Corrupts:
407
+ *   none
408
+ ****************************************************************************
409
+ */
410
+	.section ".text16.early", "awx", @progbits
411
+	.code16
412
+	.globl	access_highmem
413
+access_highmem:
414
+	/* Enable A20 line */
415
+	call	enable_a20
416
+	/* CPU will be in flat real mode as a result of this call */
417
+	lret
418
+	.size	access_highmem, . - access_highmem

Loading…
Cancel
Save