Alexandru Gagniuc (mr.nuke.me@gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/11794
-gerrit
commit 8578e258c4180114e1168214decf94c977cf83de Author: Alexandru Gagniuc mr.nuke.me@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@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@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@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@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