diff --git a/arch/x86/Makefile.target b/arch/x86/Makefile.target index 9de5dc64af..a872c8ab62 100644 --- a/arch/x86/Makefile.target +++ b/arch/x86/Makefile.target @@ -2,6 +2,7 @@ ## This file is part of the LinuxBIOS project. ## ## Copyright (C) 2006 coresystems GmbH +## Copyright (C) 2007 Ron G. Minnich ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by @@ -26,13 +27,13 @@ CFLAGS := -linuxbios.jump: FORCE - $(Q)echo "Building jump vector" - $(Q)$(CC) -E $(srctree)/arch/x86/reset.S -o $(objtree)/reset.s -DBOOTBLK=0x1f00 -DRESRVED=0xf0 -DDATE=\"`date +%Y/%m/%d`\" - $(Q)$(AS) $(objtree)/reset.s -o $(objtree)/reset.o - $(Q)$(LD) -Ttext 0xfffffff0 -s --oformat binary $(objtree)/reset.o -o $(objtree)/linuxbios.jump - $(Q)chmod 644 $(objtree)/linuxbios.jump - $(Q)echo "Len: `wc -c < linuxbios.jump`" +#linuxbios.jump: FORCE +# $(Q)echo "Building jump vector" +# $(Q)$(CC) -E $(srctree)/arch/x86/reset.S -o $(objtree)/reset.s -DBOOTBLK=0x1f00 -DRESRVED=0xf0 -DDATE=\"`date +%Y/%m/%d`\" +# $(Q)$(AS) $(objtree)/reset.s -o $(objtree)/reset.o +# $(Q)$(LD) -Ttext 0xfffffff0 -s --oformat binary $(objtree)/reset.o -o $(objtree)/linuxbios.jump +# $(Q)chmod 644 $(objtree)/linuxbios.jump +# $(Q)echo "Len: `wc -c < linuxbios.jump`" # # This part takes care of compression. It should build the compression modules @@ -92,12 +93,19 @@ linuxbios.lar: $(objtree)/lar lzma linuxbios.initram linuxbios_ram payload INITCFLAGS=-I$(srctree)/include/cpu/generic/x86 -I$(srctree)/include -fno-builtin -Os -linuxbios.init: +# Note: we could cat .o files together, but one important goal is to leave us with a complete gdb-debuggable +# .o for use with popular ICE and other tools. We go to some effort here to end up with a +# stage0.o that has debug symbols. This stage0 will actually load the first LAR file and execute it. +stage0.init: + echo "You will need to create variables for arch/$(CONFIG_ARCH)" + echo "and CC flags for architecture, and to select the stage0_$(CONFIG_STAGE0_1)" + echo "these will be set in mainboard Kconfig. Also, you need to define the .c files for " + echo "stage0 in that file as well. " $(Q)echo Building linuxbios.init # # asm stub - $(Q)$(CC) -E $(srctree)/arch/x86/init.S -o $(objtree)/init.s - $(Q)$(AS) $(objtree)/init.s -o $(objtree)/init.o + $(Q)$(CC) -E $(LINUXBIOSINCLUDE) $(srctree)/arch/x86/stage0_i586.S -o $(objtree)/stage0_i586.s -DBOOTBLK=0x1f00 -DRESRVED=0xf0 -DDATE=\"`date +%Y/%m/%d`\" + $(Q)$(AS) $(objtree)/stage0_i586.s -o $(objtree)/stage0_i586.o # # main $(Q)$(CC) $(INITCFLAGS) -c $(srctree)/arch/x86/cachemain.c -o cachemain.o @@ -110,23 +118,28 @@ linuxbios.init: $(Q)$(CC) $(INITCFLAGS) -c $(srctree)/console/vtxprintf.c -o vtxprintf.o $(Q)$(CC) $(INITCFLAGS) -c $(srctree)/lib/uart8250.c -o uart8250.o - # TODO: dynamic start address 4G - 0x2000 (bootblock size) - $(Q)$(LD) -Ttext 0xffffe000 -s --oformat binary init.o cachemain.o console.o uart8250.o \ - serial.o vtxprintf.o lar.o -o linuxbios.init.pre + # leave a .o around for debugging etc. + # we did not want to use a ldscript. But the outstanding bugs in gld make it impossible to do + # anything else. + # Google Not enough room for program headers (allocated 3, need 4) + $(Q)$(CC) -m32 -nostdlib -static -T $(srctree)/arch/x86/ldscript.ld cachemain.o console.o uart8250.o \ + serial.o vtxprintf.o lar.o stage0_i586.o -o stage0.o + $(Q)objcopy -O binary stage0.o stage0.init.pre # Pad boot block to 0x2000 - 0x100 - $(Q)dd if=linuxbios.init.pre of=linuxbios.init bs=7936 conv=sync - $(Q)echo "Len: `wc -c < linuxbios.init.pre`" + # we will probably remove this step -- not needed if we continue with ldscript.ld + $(Q)dd if=stage0.init.pre of=stage0.init bs=7936 conv=sync + $(Q)echo "Len: `wc -c < stage0.init.pre`" # - $(Q)test `wc -c < linuxbios.init.pre` -gt 7936 && echo "Error. Bootblock got too big" || true + $(Q)test `wc -c < stage0.init.pre` -gt 7936 && echo "Error. Bootblock got too big" || true # # Compose the image: # -linuxbios.rom: linuxbios.lar linuxbios.init linuxbios.vpd linuxbios.jump - $(Q)cat $(objtree)/linuxbios.lar $(objtree)/linuxbios.init \ - $(objtree)/linuxbios.vpd $(objtree)/linuxbios.jump > \ +linuxbios.rom: linuxbios.lar stage0.init linuxbios.vpd + $(Q)cat $(objtree)/linuxbios.lar \ + $(objtree)/linuxbios.vpd $(objtree)/stage0.init> \ $(objtree)/linuxbios.rom $(objtree)/lar: diff --git a/arch/x86/ldscript.ld b/arch/x86/ldscript.ld new file mode 100644 index 0000000000..84d282c456 --- /dev/null +++ b/arch/x86/ldscript.ld @@ -0,0 +1,61 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2007 Ron G. Minnich + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) + +/* +ENTRY(_start) +*/ + +TARGET(binary) +SECTIONS +{ + . = 0xffffe000 + 256; /* leave space for vpd */ + + .stage0_1 . : { + _stage0_1 = .; + *(.text); + *(.data); + *(.bss); + *(.rodata.*) + *(.rodata) + _estage0_1 = .; + } + /DISCARD/ : { + *(.comment) + *(.note) + } +} + +SECTIONS { + _ROMTOP = 0xfffffff0; + . = _ROMTOP; + .resetvector . : { + *(.reset) +/* + . = 15 ; + BYTE(0x00); + */ + } +} + +/* +*/ diff --git a/arch/x86/stage0_i586.S b/arch/x86/stage0_i586.S new file mode 100644 index 0000000000..fd72912b28 --- /dev/null +++ b/arch/x86/stage0_i586.S @@ -0,0 +1,528 @@ +## Note: this file contains _multiple_ copyright/license headers, see below. + +## +## This file is part of the LinuxBIOS project. +## +## Copyright (C) 2000,2007 Ronald G. Minnich +## +## Copyright (C) 2007 coresystems GmbH +## Written by Stefan Reinauer for coresystems GmbH +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; version 2 of the License. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +## + +# init code - switch cpu to pmode and enable cache as ram. + +#include "macros.h" + +#define ROM_CODE_SEG 0x08 +#define ROM_DATA_SEG 0x10 + +#define CACHE_RAM_CODE_SEG 0x18 +#define CACHE_RAM_DATA_SEG 0x20 +# .section ".rom.text" + + .code16 +#.=0 + .globl _stage0 +# .section ".rom.text" +_stage0: + cli + + /* save the BIST result */ + movl %eax, %ebp; + + /* thanks to kmliu@sis.tw.com for this TBL fix */ + /* IMMEDIATELY invalidate the translation lookaside buffer 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. + */ + + xorl %eax, %eax + movl %eax, %cr3 /* Invalidate TLB */ + + /* switch to protected mode */ + /* NOTE: WIth GNU assembler version 2.15.94.0.2.2 (i386-redhat-linux) using BFD version 2.15.94.0.2.2 20041220 + * this works fine without all the ld hackery and other things. So leave it as is with this comment. + */ + +# movw %cs, %ax +# shlw $4, %ax +# movl $0xffffe000, %ebx +# movw $gdt16 + 0xe000, %bx + #subw %ax, %bx + #data32 lgdt %cs:(%bx) + data32 lgdt %cs:gdtptr + + 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 result */ + movl %ebp, %eax + + + // port80_post (0x23) /* post 0x01 */ + /* Now we are in protected mode. Jump to a 32 bit code segment. */ + data32 ljmp $ROM_CODE_SEG, $protected_stage0 + /* I am leaving this weird jump in here in the event that future gas bugs force it to be used. */ + #.byte 0x66 + .code32 + #ljmp $ROM_CODE_SEG, $protected_stage0 + + #.code16 + .align 4 + .globl gdt16 +gdt16 = . - _stage0 +gdt16x: + .word gdt16xend - gdt16x -1 /* compute the table limit */ + .long gdt16x + .word 0 + + /* selgdt 0x08, flat code segment */ + .word 0xffff, 0x0000 + .byte 0x00, 0x9b, 0xcf, 0x00 + + /* selgdt 0x10,flat data segment */ + .word 0xffff, 0x0000 + .byte 0x00, 0x93, 0xcf, 0x00 +gdt16xend: + + /* From now on we are 32bit */ + + .code32 + +/* We have two gdts where we could have one. That is ok. + * Let's not worry about this -- optimizing gdt is pointless since we're only in it for a little bit. + * BTW note the trick below: the gdt points to ITSELF, and the first good descriptor is at offset 8. + * so you word-align the table, and then because you chose 8, + * you get a nice 64-bit aligned gdt endtry, which is + * good as this is the size of the entry. Just in case you ever wonder why people do this. + */ + .align 4 + .globl gdtptr +gdt: +gdtptr: + .word gdt_end - gdt -1 /* compute the table limit */ + .long gdt /* we know the offset */ + .word 0 + + /* selgdt 0x08, flat code segment */ + .word 0xffff, 0x0000 + .byte 0x00, 0x9b, 0xcf, 0x00 + + /* selgdt 0x10,flat data segment */ + .word 0xffff, 0x0000 + .byte 0x00, 0x93, 0xcf, 0x00 + + /* selgdt 0x18, flat code segment for CAR */ + .word 0xffff, 0x0000 + .byte 0x00, 0x9b, 0xcf, 0x00 + + /* selgdt 0x20,flat data segment for CAR */ + .word 0xffff, 0x0000 + .byte 0x00, 0x93, 0xcf, 0x00 +gdt_end: + +/* + * When we come here we are in protected mode. We expand + * the stack and copies the data segment from ROM to the + * memory. + * + * After that, we call the chipset bootstrap routine that + * does what is left of the chipset initialization. + * + * NOTE aligned to 4 so that we are sure that the prefetch + * cache will be reloaded. + */ + + .align 4 + .globl protected_stage0 +protected_stage0: + //This code was used by v2. TODO + lgdt %cs:gdtptr + ljmp $ROM_CODE_SEG, $__protected_stage0 + +.globl __protected_stage0 +__protected_stage0: + /* Save the BIST value */ + movl %eax, %ebp + + port80_post (0x01) /* post 0x01 */ + + movw $ROM_DATA_SEG, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + movw %ax, %fs + movw %ax, %gs + + /* Restore the BIST value to %eax */ + movl %ebp, %eax + +.align 4 + +## +## This file is part of the LinuxBIOS project. +## +## Copyright (C) 2005 Eswar Nallusamy, LANL +## +## Copyright (C) 2005 Tyan +## Written by Yinghai Lu for Tyan. +## +## Copyright (C) 2007 coresystems GmbH +## Written by Stefan Reinauer for coresystems GmbH +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +## + +/* We will use 4Kbytes only for cache as ram. This is + * enough to fit in our stack. + * + * disable HyperThreading is done by eswar + * the other is very similar to the AMD CAR, except remove amd specific msr + */ + +#ifndef CONFIG_CARSIZE +#define CacheSize 4096 +#else +#define CacheSize CONFIG_CARSIZE +#endif + +#ifndef CONFIG_CARBASE +#define CacheBase (0xd0000 - CacheSize) +#else +#define CacheBase CONFIG_CARBASE +#endif + +#define ASSEMBLY +#include "mtrr.h" + + /* Save the BIST result */ + movl %eax, %ebp + +CacheAsRam: + /* Check whether the processor has HT capability */ + movl $01, %eax + cpuid + btl $28, %edx + jnc NotHtProcessor + bswapl %ebx + cmpb $01, %bh + jbe NotHtProcessor + + /* It is a HT processor; Send SIPI to the other logical processor + * within this processor so that the CAR related common system + * registers are programmed accordingly + */ + + /* Use some register that is common to both logical processors + * as semaphore. Refer Appendix B, Vol.3 + */ + + xorl %eax, %eax + xorl %edx, %edx + movl $0x250, %ecx + wrmsr + + /* Figure out the logical AP's APIC ID; the following logic will work + * only for processors with 2 threads. + * + * Refer to Vol 3. Table 7-1 for details about this logic + */ + movl $0xFEE00020, %esi + movl (%esi), %ebx + andl $0xFF000000, %ebx + bswapl %ebx + btl $0, %ebx + jnc LogicalAP0 + andb $0xFE, %bl + jmp SendSIPI +LogicalAP0: + orb $0x01, %bl +SendSIPI: + bswapl %ebx /* ebx - logical AP's APIC ID */ + + /* Fill up the IPI command registers in the Local APIC mapped to + * default address and issue SIPI to the other logical processor + * within this processor die. + */ + +RetrySIPI: + movl %ebx, %eax + movl $0xFEE00310, %esi + movl %eax, (%esi) + + /* SIPI vector - F900:0000 */ + movl $0x000006F9, %eax + movl $0xFEE00300, %esi + movl %eax, (%esi) + + movl $0x30, %ecx +SIPIDelay: + pause + decl %ecx + jnz SIPIDelay + + movl (%esi), %eax + andl $0x00001000, %eax + jnz RetrySIPI + + /* Wait for the Logical AP to complete initialization */ +LogicalAPSIPINotdone: + movl $0x250, %ecx + rdmsr + orl %eax, %eax + jz LogicalAPSIPINotdone + + + +NotHtProcessor: + /* Set the default memory type and enable fixed and variable MTRRs */ + movl $MTRRdefType_MSR, %ecx + xorl %edx, %edx + /* Enable Variable and Fixed MTRRs */ + movl $0x00000c00, %eax + wrmsr + + /*Clear all MTRRs */ + xorl %edx, %edx + movl $fixed_mtrr_msr, %esi +clear_fixed_var_mtrr: + lodsl (%esi), %eax + testl %eax, %eax + jz clear_fixed_var_mtrr_out + + movl %eax, %ecx + xorl %eax, %eax + wrmsr + + jmp clear_fixed_var_mtrr +clear_fixed_var_mtrr_out: + +#if CacheSize == 0x10000 + /* enable caching for 64K using fixed mtrr */ + movl $0x268, %ecx /* fix4k_c0000*/ + movl $0x06060606, %eax /* WB IO type */ + movl %eax, %edx + wrmsr + movl $0x269, %ecx + wrmsr +#endif + +#if CacheSize == 0x8000 + /* enable caching for 32K using fixed mtrr */ + movl $0x269, %ecx /* fix4k_c8000*/ + movl $0x06060606, %eax /* WB IO type */ + movl %eax, %edx + wrmsr +#endif + + /* enable caching for 16K/8K/4K using fixed mtrr */ + movl $0x269, %ecx /* fix4k_cc000*/ +#if CacheSize == 0x4000 + movl $0x06060606, %edx /* WB IO type */ +#endif +#if CacheSize == 0x2000 + movl $0x06060000, %edx /* WB IO type */ +#endif +#if CacheSize == 0x1000 + movl $0x06000000, %edx /* WB IO type */ +#endif + xorl %eax, %eax + wrmsr + +#if defined(CONFIG_XIP_ROM_SIZE) && defined(CONFIG_XIP_ROM_BASE) + /* enable write base caching so we can do execute in place + * on the flash rom. + */ + movl $0x202, %ecx + xorl %edx, %edx + movl $(XIP_ROM_BASE | MTRR_TYPE_WRBACK), %eax + wrmsr + + movl $0x203, %ecx + movl $0x0000000f, %edx + movl $(~(XIP_ROM_SIZE - 1) | 0x800), %eax + wrmsr +#endif /* XIP_ROM_SIZE && XIP_ROM_BASE */ + + /* enable cache */ + movl %cr0, %eax + andl $0x9fffffff,%eax + movl %eax, %cr0 + + /* Read the range with lodsl*/ + movl $CacheBase, %esi + cld + movl $(CacheSize>>2), %ecx + rep lodsl + + /* Clear the range */ + movl $CacheBase, %edi + movl $(CacheSize>>2), %ecx + xorl %eax, %eax + rep stosl + + + /* TODO: make this a config variable */ +#if CONFIG_CARTEST + /* check the cache as ram */ + movl $CacheBase, %esi + movl $(CacheSize>>2), %ecx +.xin1: + movl %esi, %eax + movl %eax, (%esi) + decl %ecx + je .xout1 + add $4, %esi + jmp .xin1 +.xout1: + + movl $CacheBase, %esi +// movl $(CacheSize>>2), %ecx + movl $4, %ecx +.xin1x: + movl %esi, %eax + + movl $0x4000, %edx + movb %ah, %al +.testx1: + outb %al, $0x80 + decl %edx + jnz .testx1 + + movl (%esi), %eax + cmpb 0xff, %al + je .xin2 /* dont show */ + + movl $0x4000, %edx +.testx2: + outb %al, $0x80 + decl %edx + jnz .testx2 + +.xin2: decl %ecx + je .xout1x + add $4, %esi + jmp .xin1x +.xout1x: + +#endif + + movl $(CacheBase+CacheSize-4), %eax + movl %eax, %esp + + /* Load a different set of data segments */ + movw $CACHE_RAM_DATA_SEG, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + +lout: + + /* Restore the BIST result */ + movl %ebp, %eax + /* We need to set ebp ? No need */ + movl %esp, %ebp + pushl %eax /* bist */ + call stage1_main + /* We will not go back */ +fixed_mtrr_msr: + .long 0x250, 0x258, 0x259 + .long 0x268, 0x269, 0x26A + .long 0x26B, 0x26C, 0x26D + .long 0x26E, 0x26F +var_mtrr_msr: + .long 0x200, 0x201, 0x202, 0x203 + .long 0x204, 0x205, 0x206, 0x207 + .long 0x208, 0x209, 0x20A, 0x20B + .long 0x20C, 0x20D, 0x20E, 0x20F + .long 0x000 /* NULL, end of table */ + + + + +## +## This file is part of the LinuxBIOS project. +## +## Copyright (C) 2007 coresystems GmbH +## Written by Stefan Reinauer for coresystems GmbH +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +## + +# reset vector + +# RVECTOR: size of reset vector, default is 0x10 +# RESRVED: size of vpd code, default is 0xf0 +# +# BOOTBLK: size of bootblock code, default is 0x1f00 (8k-256b) +# + +SEGMENT_SIZE = 0x10000 +RVECTOR = 0x00010 +#.=0x1ff0 +#.=0xfffffff0 +#.=_stage0 + 0x1ff0 +# due to YET ANOTHER BUG in GNU bintools, you can NOT have a code16 here. +# I think we should leave it this way forever, as the bugs come and go -- and come again +# .code16 +# .section ".rom.text" +.section ".reset", "ax" + .globl _resetjump +_resetjump: + /* gnu bintools win again. this jumps to stage0 - 2. Sigh. */ +# jmp _stage0 + .byte 0xe9 + .int _stage0 - ( . + 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. + */ +.byte 0 + +# date? idstring? we might want to put something else in here. +.ascii DATE + +# checksum +#.word 0