Browse Source

[PXE] Add PMM support to romprefix.S (untested)

ROM initialisation vector now attempts to allocate a 2MB block using
PMM.  If successful, it copies the ROM image to this block, then
shrinks the ROM image to allow for more option ROMs.  If unsuccessful,
it leaves the ROM as-is.

ROM BEV now attempts to return to the BIOS, resorting to INT 18 only
if the BIOS stack has been corrupted.
tags/v0.9.4
Michael Brown 17 years ago
parent
commit
12f203c606
3 changed files with 243 additions and 73 deletions
  1. 58
    30
      src/arch/i386/prefix/libprefix.S
  2. 183
    43
      src/arch/i386/prefix/romprefix.S
  3. 2
    0
      src/arch/i386/scripts/i386.lds

+ 58
- 30
src/arch/i386/prefix/libprefix.S View File

@@ -17,6 +17,10 @@
17 17
  *
18 18
  */
19 19
 
20
+	.arch i386
21
+	.section ".prefix.lib", "awx", @progbits
22
+	.section ".data16", "aw", @progbits
23
+
20 24
 /**
21 25
  * High memory temporary load address
22 26
  *
@@ -27,25 +31,18 @@
27 31
  * We use the start of an even megabyte so that we don't have to worry
28 32
  * about the current state of the A20 line.
29 33
  *
30
- * We use 4MB rather than 2MB because there is at least one commercial
31
- * PXE ROM ("Broadcom UNDI, PXE-2.1 (build 082) v2.0.4") which stores
32
- * data required by the UNDI ROM loader (yes, the ROM loader; that's
33
- * the component which should be impossible to damage short of
34
- * screwing with the MMU) around the 2MB mark.  Sadly, this is not a
35
- * joke.
36
- *
34
+ * We use 4MB rather than 2MB because some PXE stack / PMM BIOS
35
+ * combinations are known to place data required by other UNDI ROMs
36
+ * loader around the 2MB mark.
37 37
  */
38
-#define HIGHMEM_LOADPOINT ( 4 << 20 )
38
+	.globl	HIGHMEM_LOADPOINT
39
+	.equ	HIGHMEM_LOADPOINT, ( 4 << 20 )
39 40
 
40 41
 /* Image compression enabled */
41 42
 #define COMPRESS 1
42 43
 
43 44
 #define CR0_PE 1
44 45
 
45
-	.arch i386
46
-	.section ".prefix.lib", "awx", @progbits
47
-	.section ".data16", "aw", @progbits
48
-
49 46
 /****************************************************************************
50 47
  * pm_call (real-mode near call)
51 48
  *
@@ -223,12 +220,15 @@ copy_bytes:
223 220
  * Returns:
224 221
  *   %ds:esi : next source address (will be a multiple of 16)
225 222
  * Corrupts:
226
- *   %edi, %ecx, %edx
223
+ *   %ecx, %edx
227 224
  ****************************************************************************
228 225
  */
229 226
 	.section ".prefix.lib"
230 227
 	.code16
231 228
 install_block:
229
+	/* Preserve registers */
230
+	pushl	%edi
231
+	
232 232
 #if COMPRESS
233 233
 	/* Decompress source to destination */
234 234
 	call	decompress16
@@ -249,6 +249,8 @@ install_block:
249 249
 	addl	$0xf, %esi
250 250
 	andl	$~0xf, %esi
251 251
 
252
+	/* Restore registers and return */
253
+	popl	%edi
252 254
 	ret
253 255
 	.size install_block, . - install_block
254 256
 	
@@ -270,6 +272,7 @@ install_block:
270 272
  */
271 273
 	.section ".prefix.lib"
272 274
 	.code16
275
+	.globl	alloc_basemem
273 276
 alloc_basemem:
274 277
 	/* FBMS => %ax as segment address */
275 278
 	movw	$0x40, %ax
@@ -308,13 +311,14 @@ alloc_basemem:
308 311
  * Returns:
309 312
  *   %esi : next source physical address (will be a multiple of 16)
310 313
  * Corrupts:
311
- *   %edi, %ecx, %edx
314
+ *   %ecx, %edx
312 315
  ****************************************************************************
313 316
  */
314 317
 	.section ".prefix.lib"
315 318
 	.code16
316 319
 install_basemem:
317 320
 	/* Preserve registers */
321
+	pushl	%edi
318 322
 	pushw	%ds
319 323
 
320 324
 	/* Preserve original %esi */
@@ -335,6 +339,7 @@ install_basemem:
335 339
 
336 340
 	/* Restore registers */
337 341
 	popw	%ds
342
+	popl	%edi
338 343
 	ret
339 344
 	.size install_basemem, . - install_basemem
340 345
 
@@ -351,7 +356,7 @@ install_basemem:
351 356
  * Returns:
352 357
  *   %esi : next source physical address (will be a multiple of 16)
353 358
  * Corrupts:
354
- *   %edi, %ecx, %edx
359
+ *   %ecx, %edx
355 360
  ****************************************************************************
356 361
  */
357 362
 
@@ -376,17 +381,14 @@ install_highmem:
376 381
 	
377 382
 /****************************************************************************
378 383
  * install (real-mode near call)
379
- * install_prealloc (real-mode near call)
380 384
  *
381 385
  * Install all text and data segments.
382 386
  *
383 387
  * Parameters:
384
- *   %ax : .text16 segment address (install_prealloc only)
385
- *   %bx : .data16 segment address (install_prealloc only)
388
+ *   none
386 389
  * Returns:
387
- *   %ax : .text16 segment address
388
- *   %bx : .data16 segment address
389
- *   %edi : .text physical address (if applicable)
390
+ *   %ax  : .text16 segment address
391
+ *   %bx  : .data16 segment address
390 392
  * Corrupts:
391 393
  *   none
392 394
  ****************************************************************************
@@ -395,26 +397,55 @@ install_highmem:
395 397
 	.code16
396 398
 	.globl install
397 399
 install:
400
+	/* Preserve registers */
401
+	pushl	%esi
402
+	pushl	%edi
398 403
 	/* Allocate space for .text16 and .data16 */
399 404
 	call	alloc_basemem
405
+	/* Image source = %cs:0000 */
406
+	xorl	%esi, %esi
407
+	/* Image destination = HIGHMEM_LOADPOINT */
408
+	movl	$HIGHMEM_LOADPOINT, %edi
409
+	/* Install text and data segments */
410
+	call	install_prealloc
411
+	/* Restore registers and return */
412
+	popl	%edi
413
+	popl	%esi
414
+	ret
400 415
 	.size install, . - install
416
+
417
+/****************************************************************************
418
+ * install_prealloc (real-mode near call)
419
+ *
420
+ * Install all text and data segments.
421
+ *
422
+ * Parameters:
423
+ *   %ax  : .text16 segment address
424
+ *   %bx  : .data16 segment address
425
+ *   %esi : Image source physical address (or zero for %cs:0000)
426
+ *   %edi : Decompression temporary area physical address
427
+ * Corrupts:
428
+ *   none
429
+ ****************************************************************************
430
+ */
431
+	.section ".prefix.lib"
432
+	.code16
401 433
 	.globl install_prealloc
402 434
 install_prealloc:
403 435
 	/* Save registers */
436
+	pushal
404 437
 	pushw	%ds
405 438
 	pushw	%es
406
-	pushl	%esi
407
-	pushl	%ecx
408
-	pushl	%edx
409 439
 
410 440
 	/* Sanity: clear the direction flag asap */
411 441
 	cld
412 442
 
413 443
 	/* Calculate physical address of payload (i.e. first source) */
414
-	xorl	%esi, %esi
444
+	testl	%esi, %esi
445
+	jnz	1f
415 446
 	movw	%cs, %si
416 447
 	shll	$4, %esi
417
-	addl	$_payload_offset, %esi
448
+1:	addl	$_payload_offset, %esi
418 449
 
419 450
 	/* Install .text16 */
420 451
 	movw	%ax, %es
@@ -440,7 +471,6 @@ install_prealloc:
440 471
 	 * prior to reading the E820 memory map and relocating
441 472
 	 * properly.
442 473
 	 */
443
-	movl	$HIGHMEM_LOADPOINT, %edi
444 474
 	movl	$_textdata_progbits_size, %ecx
445 475
 	movl	$_textdata_size, %edx
446 476
 	pushl	%edi
@@ -473,11 +503,9 @@ install_prealloc:
473 503
 
474 504
 #endif
475 505
 	/* Restore registers */
476
-	popl	%edx
477
-	popl	%ecx
478
-	popl	%esi
479 506
 	popw	%es
480 507
 	popw	%ds
508
+	popal
481 509
 	ret
482 510
 	.size install_prealloc, . - install_prealloc
483 511
 

+ 183
- 43
src/arch/i386/prefix/romprefix.S View File

@@ -6,6 +6,10 @@
6 6
  * table so using a noticeable amount of stack space is a no-no.
7 7
  */
8 8
 
9
+#define PNP_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) )
10
+#define PMM_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'M' << 16 ) + ( 'M' << 24 ) )
11
+#define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
12
+
9 13
 	.text
10 14
 	.code16
11 15
 	.arch i386
@@ -15,7 +19,9 @@
15 19
 romheader:
16 20
 	.word	0xAA55			/* BIOS extension signature */
17 21
 romheader_size:	.byte _load_size_sect	/* Size in 512-byte blocks */
18
-	jmp	init_vector		/* Initialisation vector */
22
+	jmp	init			/* Initialisation vector */
23
+checksum:
24
+	.byte	0
19 25
 	.org	0x16
20 26
 	.word	undiheader
21 27
 	.org	0x18
@@ -72,7 +78,7 @@ pnpheader:
72 78
 	.byte	0x54			/* Device indicator */
73 79
 	.word	0x0000			/* Boot connection vector */
74 80
 	.word	0x0000			/* Disconnect vector */
75
-	.word	exec_vector		/* Boot execution vector */
81
+	.word	bev_entry		/* Boot execution vector */
76 82
 	.word	0x0000			/* Reserved */
77 83
 	.word	0x0000			/* Static resource information vector*/
78 84
 	.equ pnpheader_len, . - pnpheader
@@ -98,60 +104,180 @@ undiheader:
98 104
 	.equ undiheader_len, . - undiheader
99 105
 	.size undiheader, . - undiheader
100 106
 
101
-/* Initialisation vector
107
+/* Initialisation (called once during POST)
102 108
  *
103 109
  * Determine whether or not this is a PnP system via a signature
104 110
  * check.  If it is PnP, return to the PnP BIOS indicating that we are
105 111
  * a boot-capable device; the BIOS will call our boot execution vector
106 112
  * if it wants to boot us.  If it is not PnP, hook INT 19.
107 113
  */
108
-init_vector:
109
-	pushw	%si
110
-	cmpw	$'$'+'P'*256, %es:0(%di)
111
-	jne	notpnp
112
-	cmpw	$'n'+'P'*256, %es:2(%di)
113
-	jne	notpnp
114
-ispnp:
115
-	movw	$ispnp_message, %si
116
-	jmp	99f
117
-notpnp:
114
+init:
115
+	/* Preserve registers, clear direction flag, set %ds=%cs */
116
+	pushaw
118 117
 	pushw	%ds
119
-	pushw	$0
120
-	popw	%ds
118
+	pushw	%es
119
+	cld
121 120
 	pushw	%cs
122
-	pushw	$exec_vector
123
-	popl	( 0x19 * 4 )
124 121
 	popw	%ds
125
-	movw	$notpnp_message, %si
122
+	/* Print message as early as possible */
123
+	movw	$init_message, %si
124
+	call	print_message
125
+	/* Check for PnP BIOS */
126
+	cmpl	$PNP_SIGNATURE, %es:0(%di)
127
+	je	ispnp
128
+notpnp:	/* Not PnP: hook INT19 */
129
+	xorw	%ax, %ax
130
+	movw	%ax, %es
131
+	pushw	%cs
132
+	pushw	$int19_entry
133
+	popl	%es:( 0x19 * 4 )
134
+	jmp	99f
135
+ispnp:	/* Is PnP: print PnP message */
136
+	movw	$init_message_pnp, %si
137
+	call	print_message
138
+	/* Check for PMM */
139
+	movw	$( 0xe000 - 1 ), %di
140
+pmm_scan:
141
+	incw	%di
142
+	jz	99f
143
+	movw	%di, %es
144
+	cmpl	$PMM_SIGNATURE, %es:0
145
+	jne	pmm_scan
146
+	xorw	%bx, %bx
147
+	xorw	%si, %si
148
+	movzbw	%es:5, %cx
149
+1:	es lodsb
150
+	addb	%al, %bl
151
+	loop	1b
152
+	jnz	pmm_scan
153
+	/* PMM found: print PMM message */
154
+	movw	$init_message_pmm, %si
155
+	call	print_message
156
+	/* Try to allocate 2MB block via PMM */
157
+	pushw	$0x0006		/* Aligned, extended memory */
158
+	pushl	$0xffffffff	/* No handle */
159
+	pushl	$( 0x00200000 / 16 ) /* 2MB in paragraphs */
160
+	pushw	$0x0000		/* pmmAllocate */
161
+	lcall	%es:*(7)
162
+	addw	$12, %sp
163
+	testw	%dx, %dx	/* %ax==0 even on success, since align=2MB */
164
+	jnz	gotpmm
165
+	movw	$init_message_pmm_failed, %si
166
+	call	print_message
167
+	jmp	99f
168
+gotpmm:	/* PMM allocation succeeded: copy ROM to PMM block */
169
+	pushal			/* PMM presence implies 1kB stack */
170
+	movw	%ax, %es	/* %ax=0 already - see above */
171
+	pushw	%dx
172
+	pushw	%ax
173
+	popl	%edi
174
+	movl	%edi, image_source
175
+	xorl	%esi, %esi
176
+	movzbl	romheader_size, %ecx
177
+	shll	$9, %ecx
178
+	addr32 rep movsb	/* PMM presence implies flat real mode */
179
+	movl	%edi, decompress_to
180
+	/* Shrink ROM and update checksum */
181
+	xorw	%bx, %bx
182
+	xorw	%si, %si
183
+	movb	$_prefix_size_sect, romheader_size
184
+	shlw	$9, %cx
185
+1:	lodsb
186
+	addb	%al, %bl
187
+	loop	1b
188
+	subb	%bl, checksum
189
+	popal
126 190
 99:
191
+	/* Print CRLF to terminate messages */
192
+	movw	$init_message_crlf, %si
127 193
 	call	print_message
194
+	/* Restore registers */
195
+	popw	%es
196
+	popw	%ds
197
+	popaw
198
+	/* Indicate boot capability to PnP BIOS, if present */
128 199
 	movw	$0x20, %ax
129
-	popw	%si
130 200
 	lret
131
-	.size init_vector, . - init_vector
132
-
133
-ispnp_message:
134
-	.asciz	"gPXE detected PnP BIOS\r\n"
135
-	.size ispnp_message, . - ispnp_message
136
-notpnp_message:
137
-	.asciz	"gPXE detected non-PnP BIOS\r\n"
138
-	.size notpnp_message, . - notpnp_message
139
-
140
-/* Boot execution vector
141
- *pciheader_size
142
- * Called by the PnP BIOS when it wants to boot us, or via the hooked
143
- * INT 19 if we detected a non-PnP BIOS.
144
- */	
145
-exec_vector:
146
-	/* Obtain a reasonably-sized stack */
201
+	.size init, . - init
202
+
203
+init_message:
204
+	.asciz	"gPXE (http://etherboot.org)"
205
+	.size	init_message, . - init_message
206
+init_message_pnp:
207
+	.asciz	" - PnP BIOS detected"
208
+	.size init_message_pnp, . - init_message_pnp
209
+init_message_pmm:
210
+	.asciz	", using PMM"
211
+	.size init_message_pmm, . - init_message_pmm
212
+init_message_pmm_failed:
213
+	.asciz	" (failed)"
214
+	.size init_message_pmm_failed, . - init_message_pmm_failed
215
+init_message_crlf:
216
+	.asciz	"\r\n"
217
+	.size	init_message_crlf, . - init_message_crlf
218
+
219
+/* ROM image location
220
+ *
221
+ * May be either within option ROM space, or within PMM-allocated block.
222
+ */
223
+image_source:
224
+	.long	0
225
+	.size	image_source, . - image_source
226
+/* Temporary decompression area
227
+ *
228
+ * May be either at HIGHMEM_LOADPOINT, or within PMM-allocated block.
229
+ */
230
+decompress_to:
231
+	.long	HIGHMEM_LOADPOINT
232
+	.size	decompress_to, . - decompress_to
233
+
234
+/* Boot Execution Vector entry point
235
+ *
236
+ * Called by the PnP BIOS when it wants to boot us.
237
+ */
238
+bev_entry:
239
+	pushw	%cs
240
+	call	exec
241
+	lret
242
+	.size	bev_entry, . - bev_entry
243
+
244
+/* INT19 entry point
245
+ *
246
+ * Called via the hooked INT 19 if we detected a non-PnP BIOS.
247
+ */
248
+int19_entry:
249
+	pushw	%cs
250
+	call	exec
251
+	/* No real way to return from INT19 */
252
+	int	$0x18
253
+	.size	int19_entry, . - int19_entry
254
+
255
+/* Execute as a boot device
256
+ *
257
+ */
258
+exec:	/* Set %ds = %cs */
259
+	pushw	%cs
260
+	popw	%ds
261
+
262
+	/* Print message as soon as possible */
263
+	movw	$exec_message, %si
264
+	call	print_message
265
+
266
+	/* Store magic word on BIOS stack and remember BIOS %ss:sp */
267
+	pushl	$STACK_MAGIC
268
+	movw	%ss, %dx
269
+	movw	%sp, %bp
270
+
271
+	/* Obtain a reasonably-sized temporary stack */
147 272
 	xorw	%ax, %ax
148 273
 	movw	%ax, %ss
149 274
 	movw	$0x7c00, %sp
150
-	
151
-	movw	$exec_message, %si
152
-	call	print_message
153 275
 
154
-	call	install
276
+	/* Install gPXE */
277
+	movl	image_source, %esi
278
+	movl	decompress_to, %edi
279
+	call	alloc_basemem
280
+	call	install_prealloc
155 281
 
156 282
 	/* Set up real-mode stack */
157 283
 	movw	%bx, %ss
@@ -162,13 +288,23 @@ exec_vector:
162 288
 	pushw	$1f
163 289
 	lret
164 290
 	.section ".text16", "awx", @progbits
165
-1:
291
+1:	/* Call main() */
166 292
 	pushl	$main
167 293
 	pushw	%cs
168 294
 	call	prot_call
169
-	popl	%eax /* discard */
295
+	/* No need to clean up stack; we are about to reload %ss:sp */
296
+	
297
+	/* Restore BIOS stack */
298
+	movw	%dx, %ss
299
+	movw	%bp, %sp
170 300
 
171
-	/* Boot next device */
301
+	/* Check magic word on BIOS stack */
302
+	popl	%eax
303
+	cmpl	$STACK_MAGIC, %eax
304
+	jne	1f
305
+	/* BIOS stack OK: return to caller */
306
+	lret
307
+1:	/* BIOS stack corrupt: use INT 18 */
172 308
 	int	$0x18
173 309
 	.previous
174 310
 
@@ -182,6 +318,7 @@ exec_message:
182 318
  */
183 319
 undiloader:
184 320
 	/* Save registers */
321
+	pushl	%esi
185 322
 	pushl	%edi
186 323
 	pushw	%es
187 324
 	pushw	%bx
@@ -193,6 +330,8 @@ undiloader:
193 330
 	pushw	%di
194 331
 	movw	%es:12(%di), %bx
195 332
 	movw	%es:14(%di), %ax
333
+	movl	%cs:image_source, %esi
334
+	movl	%cs:decompress_to, %edi
196 335
 	call	install_prealloc
197 336
 	popw	%di
198 337
 	/* Call UNDI loader C code */
@@ -208,6 +347,7 @@ undiloader:
208 347
 	popw	%bx
209 348
 	popw	%es
210 349
 	popl	%edi
350
+	popl	%esi
211 351
 	lret
212 352
 	.size undiloader, . - undiloader
213 353
 				
@@ -218,7 +358,7 @@ print_message:
218 358
 	pushw	%bx
219 359
 	pushw	%bp
220 360
 	movw    $0x0007, %bx
221
-1:	cs lodsb
361
+1:	lodsb
222 362
 	testb	%al, %al
223 363
 	je	2f
224 364
 	movb    $0x0e, %ah              /* write char, tty mode */

+ 2
- 0
src/arch/i386/scripts/i386.lds View File

@@ -257,6 +257,8 @@ SECTIONS {
257 257
     /*
258 258
      * Values calculated to save code from doing it
259 259
      */
260
+    _prefix_size_pgh	= ( ( _prefix_size + 15 ) / 16 );
261
+    _prefix_size_sect	= ( ( _prefix_size + 511 ) / 512 );
260 262
     _text16_size_pgh	= ( ( _text16_size + 15 ) / 16 );
261 263
     _data16_size_pgh	= ( ( _data16_size + 15 ) / 16 );
262 264
 

Loading…
Cancel
Save