Переглянути джерело

[pcbios] Prepare for multiple splits of hidden e820 memory regions

Define a list of N allowed memory regions, and split each underlying
e820 region into up to N subregions.  Strip resulting empty regions
out of the map, avoiding using the "return with CF set to strip last
empty region" trick, because it seems that bootmgr.exe in Win2k8 gets
upset if the memory map is terminated with CF set.

This is an intermediate checkin that defines a single allowed memory
region covering the entire 64-bit address space, and uses the existing
map-mangling code on top of the new region-splitting code.  This
sanitises the memory map to the point that Win2k8 is able to boot even
on a system that defines a final zero-length region at the 4GB mark.

I'm checking this in because it may be useful for future debugging
efforts to be able to run with the existing and known-working map
mangling code together with the map sanitisation capabilities of the
new map mangling code.
tags/v0.9.4
Michael Brown 16 роки тому
джерело
коміт
9737095d49

+ 327
- 2
src/arch/i386/firmware/pcbios/e820mangler.S Переглянути файл

@@ -267,6 +267,322 @@ patch_1m_16m:
267 267
 	ret
268 268
 	.size patch_1m_16m, . - patch_1m_16m
269 269
 
270
+/****************************************************************************
271
+ * Get underlying e820 memory region to underlying_e820 buffer
272
+ *
273
+ * Parameters:
274
+ *   As for INT 15,e820
275
+ * Returns:
276
+ *   As for INT 15,e820
277
+ *
278
+ * Wraps the underlying INT 15,e820 call so that the continuation
279
+ * value (%ebx) is a 16-bit simple sequence counter (with the high 16
280
+ * bits ignored), and termination is always via CF=1 rather than
281
+ * %ebx=0.
282
+ *
283
+ ****************************************************************************
284
+ */
285
+	.section ".text16"
286
+get_underlying_e820:
287
+
288
+	/* If the requested region is in the cache, return it */
289
+	cmpw	%bx, underlying_e820_index
290
+	jne	1f
291
+	pushw	%di
292
+	pushw	%si
293
+	movw	$underlying_e820_cache, %si
294
+	movw	$20, %cx
295
+	rep movsb
296
+	popw	%si
297
+	popw	%di
298
+	movw	$20, %cx
299
+	incw	%bx
300
+	movl	%edx, %eax
301
+	ret
302
+1:	
303
+	/* If the requested region is earlier than the cached region,
304
+	 * invalidate the cache.
305
+	 */
306
+	cmpw	%bx, underlying_e820_index
307
+	jbe	1f
308
+	movw	$0xffff, underlying_e820_index
309
+1:
310
+	/* If the cache is invalid, reset the underlying %ebx */
311
+	cmpw	$0xffff, underlying_e820_index
312
+	jne	1f
313
+	andl	$0, underlying_e820_ebx
314
+1:	
315
+	/* If the cache is valid but the continuation value is zero,
316
+	 * this means that the previous underlying call returned with
317
+	 * %ebx=0.  Return with CF=1 in this case.
318
+	 */
319
+	cmpw	$0xffff, underlying_e820_index
320
+	je	1f
321
+	cmpl	$0, underlying_e820_ebx
322
+	jne	1f
323
+	stc
324
+	ret
325
+1:	
326
+	/* Get the next region into the cache */
327
+	pushl	%eax
328
+	pushl	%ebx
329
+	pushl	%ecx
330
+	pushl	%edx
331
+	movl	underlying_e820_ebx, %ebx
332
+	stc
333
+	pushfw
334
+	lcall	*%cs:int15_vector
335
+	jc	1f /* CF set: error */
336
+	cmpl	$SMAP, %eax
337
+	je	2f /* 'SMAP' missing: error */
338
+1:	/* An error occurred: return values returned by underlying e820 call */
339
+	stc	/* Force CF set if SMAP was missing */
340
+	leal	16(%esp), %esp /* avoid changing other flags */
341
+	ret
342
+2:	/* No error occurred */
343
+	movl	%ebx, underlying_e820_ebx
344
+	popl	%edx
345
+	popl	%ecx
346
+	popl	%ebx
347
+	popl	%eax
348
+	/* Copy result to cache */
349
+	pushw	%es
350
+	pushw	%fs
351
+	pushw	%si
352
+	pushw	%di
353
+	pushw	%cx
354
+	pushw	%es
355
+	popw	%fs
356
+	movw	%di, %si
357
+	pushw	%ds
358
+	popw	%es
359
+	movw	$underlying_e820_cache, %di
360
+	movw	$20, %cx
361
+	fs rep movsb
362
+	popw	%cx
363
+	popw	%di
364
+	popw	%si
365
+	popw	%fs
366
+	popw	%es
367
+	/* Mark cache as containing this result */
368
+	incw	underlying_e820_index
369
+
370
+	/* Loop until found */
371
+	jmp	get_underlying_e820
372
+	.size	get_underlying_e820, . - get_underlying_e820
373
+
374
+	.section ".data16"
375
+underlying_e820_index:
376
+	.word	0xffff /* Initialise to an invalid value */
377
+	.size underlying_e820_index, . - underlying_e820_index
378
+
379
+	.section ".bss16"
380
+underlying_e820_ebx:
381
+	.long	0
382
+	.size underlying_e820_ebx, . - underlying_e820_ebx
383
+
384
+	.section ".bss16"
385
+underlying_e820_cache:
386
+	.space	20
387
+	.size underlying_e820_cache, . - underlying_e820_cache
388
+
389
+/****************************************************************************
390
+ * Get windowed e820 region, without empty region stripping
391
+ *
392
+ * Parameters:
393
+ *   As for INT 15,e820
394
+ * Returns:
395
+ *   As for INT 15,e820
396
+ *
397
+ * Wraps the underlying INT 15,e820 call so that each underlying
398
+ * region is returned N times, windowed to fit within N visible-memory
399
+ * windows.  Termination is always via CF=1.
400
+ *
401
+ ****************************************************************************
402
+ */
403
+
404
+	.section ".tbl.data16.memory_windows.00"
405
+	.align 16
406
+memory_windows:
407
+
408
+	// Dummy memory window encompassing entire 64-bit address space
409
+	.long 0, 0, 0xffffffff, 0xffffffff
410
+
411
+	.section ".tbl.data16.memory_windows.99"
412
+	.align 16
413
+memory_windows_end:
414
+	
415
+	.section ".text16"
416
+get_windowed_e820:
417
+
418
+	/* Preserve registers */
419
+	pushl	%esi
420
+	pushw	%bp
421
+
422
+	/* Split %ebx into %si:%bx, store original %bx in %bp */
423
+	pushl	%ebx
424
+	xorl	%esi, %esi
425
+	popw	%bp
426
+	popw	%si
427
+
428
+	/* %si == 0 => start of memory_windows list */
429
+	testw	%si, %si
430
+	jne	1f
431
+	movw	$memory_windows, %si
432
+1:	
433
+	/* Get (cached) underlying e820 region to buffer */
434
+	call	get_underlying_e820
435
+	jc	99f /* Abort on error */
436
+
437
+	/* Preserve registers */
438
+	pushal
439
+	/* start => %edx:%eax, len => %ecx:%ebx */
440
+	movl	%es:0(%di), %eax
441
+	movl	%es:4(%di), %edx
442
+	movl	%es:8(%di), %ebx
443
+	movl	%es:12(%di), %ecx
444
+	/* Convert (start,len) to (start, end) */
445
+	addl	%eax, %ebx
446
+	adcl	%edx, %ecx
447
+	/* Truncate to window start */
448
+	cmpl	4(%esi), %edx
449
+	jne	1f
450
+	cmpl	0(%esi), %eax
451
+1:	jae	2f
452
+	movl	4(%esi), %edx
453
+	movl	0(%esi), %eax
454
+2:	/* Truncate to window end */
455
+	cmpl	12(%esi), %ecx
456
+	jne	1f
457
+	cmpl	8(%esi), %ebx
458
+1:	jbe	2f
459
+	movl	12(%esi), %ecx
460
+	movl	8(%esi), %ebx
461
+2:	/* Convert (start, end) back to (start, len) */
462
+	subl	%eax, %ebx
463
+	sbbl	%edx, %ecx
464
+	/* If length is <0, set length to 0 */
465
+	jae	1f
466
+	xorl	%ebx, %ebx
467
+	xorl	%ecx, %ecx
468
+1:	/* Store modified values in e820 map entry */
469
+	movl	%eax, %es:0(%di)
470
+	movl	%edx, %es:4(%di)
471
+	movl	%ebx, %es:8(%di)
472
+	movl	%ecx, %es:12(%di)
473
+	/* Restore registers */
474
+	popal
475
+
476
+	/* Derive continuation value for next call */
477
+	addw	$16, %si
478
+	cmpw	$memory_windows_end, %si
479
+	jne	1f
480
+	/* End of memory windows: reset %si and allow %bx to continue */
481
+	xorw	%si, %si
482
+	jmp	2f
483
+1:	/* More memory windows to go: restore original %bx */
484
+	movw	%bp, %bx
485
+2:	/* Construct %ebx from %si:%bx */
486
+	pushw	%si
487
+	pushw	%bx
488
+	popl	%ebx
489
+
490
+98:	/* Clear CF */
491
+	clc
492
+99:	/* Restore registers and return */
493
+	popw	%bp
494
+	popl	%esi
495
+	ret
496
+	.size get_windowed_e820, . - get_windowed_e820
497
+
498
+/****************************************************************************
499
+ * Get windowed e820 region, with empty region stripping
500
+ *
501
+ * Parameters:
502
+ *   As for INT 15,e820
503
+ * Returns:
504
+ *   As for INT 15,e820
505
+ *
506
+ * Wraps the underlying INT 15,e820 call so that each underlying
507
+ * region is returned up to N times, windowed to fit within N
508
+ * visible-memory windows.  Empty windows are never returned.
509
+ * Termination is always via CF=1.
510
+ *
511
+ ****************************************************************************
512
+ */
513
+	.section ".text16"
514
+get_nonempty_e820:
515
+
516
+	/* Record entry parameters */
517
+	pushl	%eax
518
+	pushl	%ecx
519
+	pushl	%edx
520
+
521
+	/* Get next windowed region */
522
+	call	get_windowed_e820
523
+	jc	99f /* abort on error */
524
+
525
+	/* If region is non-empty, finish here */
526
+	cmpl	$0, %es:8(%di)
527
+	jne	98f
528
+	cmpl	$0, %es:12(%di)
529
+	jne	98f
530
+
531
+	/* Region was empty: restore entry parameters and go to next region */
532
+	popl	%edx
533
+	popl	%ecx
534
+	popl	%eax
535
+	jmp	get_nonempty_e820
536
+
537
+98:	/* Clear CF */
538
+	clc
539
+99:	/* Return values from underlying call */
540
+	leal	12(%esp), %esp /* avoid changing flags */
541
+	ret
542
+	.size get_nonempty_e820, . - get_nonempty_e820
543
+
544
+/****************************************************************************
545
+ * Get mangled e820 region, with empty region stripping
546
+ *
547
+ * Parameters:
548
+ *   As for INT 15,e820
549
+ * Returns:
550
+ *   As for INT 15,e820
551
+ *
552
+ * Wraps the underlying INT 15,e820 call so that underlying regions
553
+ * are windowed to the allowed memory regions.  Empty regions are
554
+ * stripped from the map.  Termination is always via %ebx=0.
555
+ *
556
+ ****************************************************************************
557
+ */
558
+	.section ".text16"
559
+get_mangled_e820:
560
+
561
+	/* Get a nonempty region */
562
+	call	get_nonempty_e820
563
+	jc	99f /* Abort on error */
564
+
565
+	/* Peek ahead to see if there are any further nonempty regions */
566
+	pushal
567
+	subw	$20, %sp
568
+	movl	$0xe820, %eax
569
+	movl	$SMAP, %edx
570
+	movl	$20, %ecx
571
+	pushw	%ss
572
+	popw	%es
573
+	movw	%sp, %di
574
+	call	get_nonempty_e820
575
+	leal	20(%esp), %esp /* avoid changing flags */
576
+	popal
577
+	jnc	99f /* There are further nonempty regions */
578
+
579
+	/* No futher nonempty regions: zero %ebx and clear CF */
580
+	xorl	%ebx, %ebx
581
+	
582
+99:	/* Return */
583
+	ret
584
+	.size get_mangled_e820, . - get_mangled_e820
585
+
270 586
 /****************************************************************************
271 587
  * Patch E820 memory map entry
272 588
  *
@@ -298,7 +614,7 @@ patch_e820:
298 614
 /****************************************************************************
299 615
  * Split E820 memory map entry if necessary
300 616
  *
301
- * Parameters:
617
+ * Parameters: 
302 618
  *   As for INT 15,e820
303 619
  * Returns:
304 620
  *   As for INT 15,e820
@@ -318,7 +634,16 @@ split_e820:
318 634
 	jnz	1f
319 635
 	movl	%ebx, %cs:real_ebx
320 636
 1:	movl	%cs:real_ebx, %ebx
321
-	lcall	*%cs:int15_vector
637
+
638
+//	lcall	*%cs:int15_vector
639
+	/* Hacked in call to get_mangled_e820 in place of underlying INT15 */
640
+	popfw
641
+	pushw	%ds
642
+	pushw	%cs:rm_ds
643
+	popw	%ds
644
+	call	get_mangled_e820
645
+	popw	%ds
646
+
322 647
 	pushfw
323 648
 	/* Edit result */
324 649
 	pushw	%ds

+ 1
- 0
src/arch/i386/scripts/i386.lds Переглянути файл

@@ -82,6 +82,7 @@ SECTIONS {
82 82
 	__data16 = .;
83 83
 	*(.data16)
84 84
 	*(.data16.*)
85
+	*(SORT(.tbl.data16.*))	/* Various tables.  See include/tables.h */
85 86
 	_edata16_progbits = .;
86 87
     }
87 88
     .bss16 : AT ( _data16_load_offset + __bss16 ) {

Завантаження…
Відмінити
Зберегти