[coreboot-gerrit] Patch set updated for coreboot: WIP: x86/bootblock: Code reset entry and protected mode switch in NASM

Alexandru Gagniuc (mr.nuke.me@gmail.com) gerrit at coreboot.org
Mon Oct 5 02:36:03 CET 2015


Alexandru Gagniuc (mr.nuke.me at gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/11794

-gerrit

commit 71a6497e3174a005cfd2a84dbe74e02c4d4579dd
Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
Date:   Sun Oct 4 18:30:59 2015 -0700

    WIP: x86/bootblock: Code reset entry and protected mode switch in NASM
    
    Now that we can use NASM, demonstrate its power by coding the reset
    vector entry and switch to protected mode in NASM, and removing the
    old implementation with GNU as.
    
    Note that src/cpu/x86/32bit/entry32.inc is kept for now, as it is
    needed by romstage. However, at this point, this patch series is
    concerned with the bootblock. Other stages will be updated later in
    the series.
    
    Change-Id: Iaeb63d015950cc9df265d00805735d3f8d18735e
    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
---
 src/arch/x86/bootblock.S                |   6 +-
 src/arch/x86/bootblock.ld               |   3 +-
 src/cpu/x86/16bit/entry16.inc           | 140 --------------------------------
 src/cpu/x86/16bit/entry16.ld            |   2 -
 src/cpu/x86/16bit/reset16.inc           |  16 ----
 src/cpu/x86/16bit/reset16.ld            |  16 ----
 src/cpu/x86/Makefile.inc                |   2 +
 src/cpu/x86/reset_entry/reset16.ld      |  17 ++++
 src/cpu/x86/reset_entry/reset_entry.asm |  81 ++++++++++++++++++
 9 files changed, 104 insertions(+), 179 deletions(-)

diff --git a/src/arch/x86/bootblock.S b/src/arch/x86/bootblock.S
index 645e491..d575aa4 100644
--- a/src/arch/x86/bootblock.S
+++ b/src/arch/x86/bootblock.S
@@ -22,9 +22,9 @@
  * of the includes. */
 
 #include <arch/x86/prologue.inc>
-#include <cpu/x86/16bit/entry16.inc>
-#include <cpu/x86/16bit/reset16.inc>
-#include <cpu/x86/32bit/entry32.inc>
+
+.global legacy_bootblock_entry
+legacy_bootblock_entry:
 
 #ifdef CONFIG_CHIPSET_BOOTBLOCK_INCLUDE
 #include CONFIG_CHIPSET_BOOTBLOCK_INCLUDE
diff --git a/src/arch/x86/bootblock.ld b/src/arch/x86/bootblock.ld
index 6835430..8499b4d 100644
--- a/src/arch/x86/bootblock.ld
+++ b/src/arch/x86/bootblock.ld
@@ -18,8 +18,7 @@
  */
 
 #include <arch/x86/failover.ld>
-#include <cpu/x86/16bit/entry16.ld>
-#include <cpu/x86/16bit/reset16.ld>
+#include <cpu/x86/reset_entry/reset16.ld>
 #include <arch/x86/id.ld>
 #if IS_ENABLED(CONFIG_CPU_INTEL_FIRMWARE_INTERFACE_TABLE)
 #include <cpu/intel/fit/fit.ld>
diff --git a/src/cpu/x86/16bit/entry16.inc b/src/cpu/x86/16bit/entry16.inc
deleted file mode 100644
index 4dad1e5..0000000
--- a/src/cpu/x86/16bit/entry16.inc
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * This software and ancillary information (herein called SOFTWARE)
- * called LinuxBIOS is made available under the terms described here.
- *
- * The SOFTWARE has been approved for release with associated
- * LA-CC Number 00-34. Unless otherwise indicated, this SOFTWARE has
- * been authored by an employee or employees of the University of
- * California, operator of the Los Alamos National Laboratory under
- * Contract No. W-7405-ENG-36 with the U.S. Department of Energy.
- *
- * The U.S. Government has rights to use, reproduce, and distribute this
- * SOFTWARE. The public may copy, distribute, prepare derivative works
- * and publicly display this SOFTWARE without charge, provided that this
- * Notice and any statement of authorship are reproduced on all copies.
- *
- * Neither the Government nor the University makes any warranty, express
- * or implied, or assumes any liability or responsibility for the use of
- * this SOFTWARE.  If SOFTWARE is modified to produce derivative works,
- * such modified SOFTWARE should be clearly marked, so as not to confuse
- * it with the version available from LANL.
- *
- * Copyright (C) 2000, Ron Minnich rminnich at lanl.gov
- *                     Advanced Computing Lab, LANL
- */
-
-
-/* Start code to put an i386 or later processor into 32-bit protected mode.
- */
-
-#include <arch/rom_segs.h>
-.code16
-.globl _start
-.type _start, @function
-
-_start:
-	cli
-	/* Save the BIST result */
-	movl	%eax, %ebp
-
-	post_code(POST_RESET_VECTOR_CORRECT)
-
-	/* IMMEDIATELY invalidate the translation lookaside buffer (TLB) before
-	 * executing any further code. Even though paging is disabled we
-	 * could still get false address translations due to the TLB if we
-	 * didn't invalidate it. Thanks to kmliu at sis.com.tw for this TLB fix.
-	 */
-
-	xorl	%eax, %eax
-	movl	%eax, %cr3    /* Invalidate TLB*/
-
-	/* Invalidating the cache here seems to be a bad idea on
-	 * modern processors.  Don't.
-	 * If we are hyperthreaded or we have multiple cores it is bad,
-	 * for SMP startup.  On Opterons it causes a 5 second delay.
-	 * Invalidating the cache was pure paranoia in any event.
-	 * If you cpu needs it you can write a cpu dependent version of
-	 * entry16.inc.
-	 */
-
-	/* Note: gas handles memory addresses in 16 bit code very poorly.
-	 * In particular it doesn't appear to have a directive allowing you
-	 * associate a section or even an absolute offset with a segment register.
-	 *
-	 * This means that anything except cs:ip relative offsets are
-	 * a real pain in 16 bit mode.  And explains why it is almost
-	 * impossible to get gas to do lgdt correctly.
-	 *
-	 * One way to work around this is to have the linker do the
-	 * math instead of the assembler.  This solves the very
-	 * pratical problem of being able to write code that can
-	 * be relocated.
-	 *
-	 * An lgdt call before we have memory enabled cannot be
-	 * position independent, as we cannot execute a call
-	 * instruction to get our current instruction pointer.
-	 * So while this code is relocateable it isn't arbitrarily
-	 * relocatable.
-	 *
-	 * The criteria for relocation have been relaxed to their
-	 * utmost, so that we can use the same code for both
-	 * our initial entry point and startup of the second cpu.
-	 * The code assumes when executing at _start that:
-	 * (((cs & 0xfff) == 0) and (ip == _start & 0xffff))
-	 * or
-	 * ((cs == anything) and (ip == 0)).
-	 *
-	 * The restrictions in reset16.inc mean that _start initially
-	 * must be loaded at or above 0xffff0000 or below 0x100000.
-	 *
-	 * The linker scripts computes gdtptr16_offset by simply returning
-	 * the low 16 bits.  This means that the intial segment used
-	 * when start is called must be 64K aligned.  This should not
-	 * restrict the address as the ip address can be anything.
-	 *
-	 * Also load an IDT with NULL limit to prevent the 16bit IDT being used
-	 * in protected mode before c_start.S sets up a 32bit IDT when entering
-	 * ram stage. In practise: CPU will shutdown on any exception.
-	 * See IA32 manual Vol 3A 19.26 Interrupts.
-	 */
-
-	movw	%cs, %ax
-	shlw	$4, %ax
-	movw	$nullidt_offset, %bx
-	subw	%ax, %bx
-	lidt	%cs:(%bx)
-	movw	$gdtptr16_offset, %bx
-	subw	%ax, %bx
-	lgdtl	%cs:(%bx)
-
-	movl	%cr0, %eax
-	andl	$0x7FFAFFD1, %eax /* PG,AM,WP,NE,TS,EM,MP = 0 */
-	orl	$0x60000001, %eax /* CD, NW, PE = 1 */
-	movl	%eax, %cr0
-
-	/* Restore BIST to %eax */
-	movl	%ebp, %eax
-
-	/* Now that we are in protected mode jump to a 32 bit code segment. */
-	ljmpl	$ROM_CODE_SEG, $__protected_start
-
-	/**
-	 * The gdt is defined in entry32.inc, it has a 4 Gb code segment
-	 * at 0x08, and a 4 GB data segment at 0x10;
-	 */
-.align	4
-.globl gdtptr16
-gdtptr16:
-	.word	gdt_end - gdt -1 /* compute the table limit */
-	.long	gdt		 /* we know the offset */
-
-.align	4
-.globl nullidt
-nullidt:
-	.word	0	/* limit */
-	.long	0
-	.word	0
-
-.globl _estart
-_estart:
-	.code32
diff --git a/src/cpu/x86/16bit/entry16.ld b/src/cpu/x86/16bit/entry16.ld
deleted file mode 100644
index 112d429..0000000
--- a/src/cpu/x86/16bit/entry16.ld
+++ /dev/null
@@ -1,2 +0,0 @@
-	gdtptr16_offset = gdtptr16 & 0xffff;
-	nullidt_offset = nullidt & 0xffff;
diff --git a/src/cpu/x86/16bit/reset16.inc b/src/cpu/x86/16bit/reset16.inc
deleted file mode 100644
index 33712d1..0000000
--- a/src/cpu/x86/16bit/reset16.inc
+++ /dev/null
@@ -1,16 +0,0 @@
-	.section ".reset"
-	.code16
-.globl	reset_vector
-reset_vector:
-	.byte  0xe9
-	.int   _start - ( . + 2 )
-	/* Note: The above jump is hand coded to work around bugs in binutils.
-	 * 5 byte are used for a 3 byte instruction.  This works because x86
-	 * is little endian and allows us to use supported 32bit relocations
-	 * instead of the weird 16 bit relocations that binutils does not
-	 * handle consistenly between versions because they are used so rarely.
-	 */
-	.org 0x8;
-	.code32
-	jmp	protected_start
-	.previous
diff --git a/src/cpu/x86/16bit/reset16.ld b/src/cpu/x86/16bit/reset16.ld
deleted file mode 100644
index d0c4096..0000000
--- a/src/cpu/x86/16bit/reset16.ld
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- *      _ROMTOP                 : The top of the rom used where we
- *				  need to put the reset vector.
- */
-
-SECTIONS {
-	/* Trigger an error if I have an unuseable start address */
-	_bogus = ASSERT(_start >= 0xffff0000, "_start too low. Please report.");
-	_ROMTOP = 0xfffffff0;
-	. = _ROMTOP;
-	.reset . : {
-		KEEP(*(.reset));
-		. = 15 ;
-		BYTE(0x00);
-	}
-}
diff --git a/src/cpu/x86/Makefile.inc b/src/cpu/x86/Makefile.inc
index e9394b2..e046607 100644
--- a/src/cpu/x86/Makefile.inc
+++ b/src/cpu/x86/Makefile.inc
@@ -2,6 +2,8 @@ ifeq ($(CONFIG_ARCH_ROMSTAGE_X86_32)$(CONFIG_ARCH_ROMSTAGE_X86_64),y)
 romstage-$(CONFIG_CACHE_AS_RAM) += car.c
 endif
 
+bootblock-y += reset_entry/reset_entry.asm
+
 subdirs-$(CONFIG_PARALLEL_MP) += name
 ramstage-$(CONFIG_PARALLEL_MP) += mp_init.c
 ramstage-$(CONFIG_MIRROR_PAYLOAD_TO_RAM_BEFORE_LOADING) += mirror_payload.c
diff --git a/src/cpu/x86/reset_entry/reset16.ld b/src/cpu/x86/reset_entry/reset16.ld
new file mode 100644
index 0000000..fe3a7dd
--- /dev/null
+++ b/src/cpu/x86/reset_entry/reset16.ld
@@ -0,0 +1,17 @@
+/*
+ *      _ROMTOP                 : The top of the rom used where we
+ *				  need to put the reset vector.
+ */
+
+SECTIONS {
+	/* Trigger an error if I have an unuseable start address */
+	_bogus = ASSERT(realmode_start >= 0xffff0000,
+			"realmode_start too low. Please report.");
+	_ROMTOP = 0xfffffff0;
+	. = _ROMTOP;
+	.reset . : {
+		KEEP(*(.reset));
+		. = 15 ;
+		BYTE(0x00);
+	}
+}
diff --git a/src/cpu/x86/reset_entry/reset_entry.asm b/src/cpu/x86/reset_entry/reset_entry.asm
new file mode 100644
index 0000000..9ec409d
--- /dev/null
+++ b/src/cpu/x86/reset_entry/reset_entry.asm
@@ -0,0 +1,81 @@
+;
+; The x86 journey, from embryo reset vector, to adult protected mode
+;
+; Copyright (C) 2015  Alexandru Gagniuc <mr.nuke.me at gmail.com>
+; Subject to the GNU GPL v2, or (at your option) any later version.
+;
+
+global realmode_start
+extern legacy_bootblock_entry
+
+ROM_CODE_SEG EQU 0x08
+ROM_DATA_SEG EQU 0x10
+POST_RESET_VECTOR_CORRECT EQU 0x01
+
+%define post_code(code) \
+	mov	eax, code
+	out	0x80, eax
+
+section .reset
+
+reset_vector: bits 16
+	jmp	realmode_start
+
+
+section .text
+
+realmode_start: bits 16
+	;
+	; eax has BIST result, so try not to touch it
+	;
+	mov	esp, eax;
+
+	post_code(POST_RESET_VECTOR_CORRECT)
+
+	cli
+
+	lidt	[cs:idt]
+	o32 lgdt [cs:gdtr]	; for some reason, this needs a 32-bit operand size
+
+	mov	ecx, cr0
+	and	ecx, 0x7FFAFFD1	; original bootblock did this
+	or	ecx, 0x60000001 ; and this
+	mov	cr0, ecx
+
+	; long jump to protected mode
+	jmp	long ROM_CODE_SEG: protected_mode_start
+
+protected_mode_start: bits 32
+	;
+	; eax still has BIST result. Don't touch it
+	;
+	mov	cx, ROM_DATA_SEG
+	mov	ds, cx
+	mov	es, cx
+	mov	ss, cx
+	mov	fs, cx
+	mov	gs, cx
+	mov	eax, esp
+	jmp	legacy_bootblock_entry
+
+align 4
+gdtr:
+	dw	gdt_size - 1
+	dd	gdt
+
+align 4
+gdt:
+	; segment 0x00: unused
+	dw	0x0000, 0x0000
+	db	0x00, 0x00, 0x00, 0x00
+	; segment 0x08: ROM_CODE_SEG
+	dw	0xffff, 0x0000
+	db	0x00, 0x9b, 0xcf, 0x00
+	; segment 0x10: ROM_DATA_SEG
+	dw	0xffff, 0x0000
+	db	0x00, 0x93, 0xcf, 0x00
+gdt_size EQU $ - gdt	; GNU as can't do this
+
+align	4
+idt:
+	dd	0x00000000, 0x00000000



More information about the coreboot-gerrit mailing list