This patch adds CAR support for LX, as well as the include file. It
builds but is not tested. Signed-off-by: Ronald G. Minnich <rminnich@gmail.com> Acked-by: Stefan Reinauer <stepan@coresystems.de> git-svn-id: svn://coreboot.org/repository/LinuxBIOSv3@323 f3766cd6-281f-0410-b1cd-43a5c92072e9
This commit is contained in:
parent
42b209a0be
commit
5dfd441cdf
2 changed files with 973 additions and 0 deletions
411
arch/x86/stage0_amd_geodelx.S
Normal file
411
arch/x86/stage0_amd_geodelx.S
Normal file
|
|
@ -0,0 +1,411 @@
|
|||
##
|
||||
## This file is part of the LinuxBIOS project.
|
||||
##
|
||||
## Copyright (C) 2000,2007 Ronald G. Minnich <rminnich@gmail.com>
|
||||
##
|
||||
## Copyright (C) 2005 Eswar Nallusamy, LANL
|
||||
##
|
||||
## Copyright (C) 2005 Tyan
|
||||
## Written by Yinghai Lu <yhlu@tyan.com> for Tyan.
|
||||
##
|
||||
## Copyright (C) 2007 coresystems GmbH
|
||||
## Written by Stefan Reinauer <stepan@coresystems.de> for coresystems GmbH.
|
||||
##
|
||||
## Copyright (C) 2007 Advanced Micro Devices
|
||||
##
|
||||
## 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"
|
||||
#include <amd_geodelx.h>
|
||||
|
||||
#define LX_STACK_BASE CONFIG_DCACHE_RAM_BASE /* this is where the DCache will be mapped and be used as stack, It would be cool if it was the same base as LinuxBIOS normal stack */
|
||||
#define LX_STACK_END LX_STACK_BASE+(CONFIG_DCACHE_RAM_SIZE-4)
|
||||
|
||||
#define LX_NUM_CACHELINES 0x080 /* there are 128lines per way */
|
||||
#define LX_CACHELINE_SIZE 0x020 /* there are 32bytes per line */
|
||||
#define LX_CACHEWAY_SIZE (LX_NUM_CACHELINES * LX_CACHELINE_SIZE)
|
||||
#define CR0_CD 0x40000000 /* bit 30 = Cache Disable */
|
||||
#define CR0_NW 0x20000000 /* bit 29 = Not Write Through */
|
||||
|
||||
#define ROM_CODE_SEG 0x08
|
||||
#define ROM_DATA_SEG 0x10
|
||||
|
||||
#define CACHE_RAM_CODE_SEG 0x18
|
||||
#define CACHE_RAM_DATA_SEG 0x20
|
||||
.code16
|
||||
.globl _stage0
|
||||
_stage0:
|
||||
cli
|
||||
|
||||
/* save the BIST result */
|
||||
movl %eax, %ebp;
|
||||
|
||||
/* thanks to kmliu@sis.com.tw for this TLB 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.
|
||||
*/
|
||||
|
||||
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 entry, 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
|
||||
.globl gdt_limit
|
||||
gdt_limit = gdt_end - gdt - 1 /* compute the table limit */
|
||||
|
||||
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
|
||||
/* here begins CAR support */
|
||||
/* this particular code is straight from LinuxBIOS V2 */
|
||||
/***************************************************************************
|
||||
/**
|
||||
/** DCacheSetup
|
||||
/**
|
||||
/** Setup data cache for use as RAM for a stack.
|
||||
/**
|
||||
/***************************************************************************/
|
||||
DCacheSetup:
|
||||
|
||||
invd
|
||||
/* set cache properties */
|
||||
movl $CPU_RCONF_DEFAULT, %ecx
|
||||
rdmsr
|
||||
movl $0x010010000, %eax /*1MB system memory in write back 1|00100|00 */
|
||||
wrmsr
|
||||
|
||||
/* in LX DCDIS is set after POR which disables the cache..., clear this bit */
|
||||
movl CPU_DM_CONFIG0,%ecx
|
||||
rdmsr
|
||||
andl $(~(DM_CONFIG0_LOWER_DCDIS_SET)), %eax /* TODO: make consistent with i$ init, either whole reg = 0, or just this bit... */
|
||||
wrmsr
|
||||
|
||||
/* get cache timing params from BIOS config data locations and apply */
|
||||
/* fix delay controls for DM and IM arrays */
|
||||
/* fix delay controls for DM and IM arrays */
|
||||
movl $CPU_BC_MSS_ARRAY_CTL0, %ecx
|
||||
xorl %edx, %edx
|
||||
movl $0x2814D352, %eax
|
||||
wrmsr
|
||||
|
||||
movl $CPU_BC_MSS_ARRAY_CTL1, %ecx
|
||||
xorl %edx, %edx
|
||||
movl $0x1068334D, %eax
|
||||
wrmsr
|
||||
|
||||
movl $CPU_BC_MSS_ARRAY_CTL2, %ecx
|
||||
movl $0x00000106, %edx
|
||||
movl $0x83104104, %eax
|
||||
wrmsr
|
||||
|
||||
movl $GLCP_FIFOCTL, %ecx
|
||||
rdmsr
|
||||
movl $0x00000005, %edx
|
||||
wrmsr
|
||||
|
||||
/* Enable setting */
|
||||
movl $CPU_BC_MSS_ARRAY_CTL_ENA, %ecx
|
||||
xorl %edx, %edx
|
||||
movl $0x01, %eax
|
||||
wrmsr
|
||||
|
||||
/* Get cleaned up. */
|
||||
xorl %edi, %edi
|
||||
xorl %esi, %esi
|
||||
xorl %ebp, %ebp
|
||||
|
||||
/* DCache Ways0 through Ways7 will be tagged for LX_STACK_BASE + CONFIG_DCACHE_RAM_SIZE for holding stack */
|
||||
/* remember, there is NO stack yet... */
|
||||
|
||||
/* Tell cache we want to fill WAY 0 starting at the top */
|
||||
xorl %edx, %edx
|
||||
xorl %eax, %eax
|
||||
movl $CPU_DC_INDEX, %ecx
|
||||
wrmsr
|
||||
|
||||
/* startaddress for tag of Way0: ebp will hold the incrementing address. dont destroy! */
|
||||
movl $LX_STACK_BASE, %ebp /* init to start address */
|
||||
orl $1, %ebp /* set valid bit and tag for this Way (B[31:12] : Cache tag value for line/way curr. selected by CPU_DC_INDEX */
|
||||
|
||||
/* start tag Ways 0 with 128 lines with 32bytes each: edi will hold the line counter. dont destroy! */
|
||||
movl $LX_NUM_CACHELINES, %edi
|
||||
DCacheSetupFillWay:
|
||||
|
||||
/* fill with dummy data: zero it so we can tell it from PCI memory space (returns FFs). */
|
||||
/* We will now store a line (32 bytes = 4 x 8bytes = 4 quadWords) */
|
||||
movw $0x04, %si
|
||||
xorl %edx, %edx
|
||||
xorl %eax, %eax
|
||||
movl $CPU_DC_DATA, %ecx
|
||||
DCacheSetup_quadWordLoop:
|
||||
wrmsr
|
||||
decw %si
|
||||
jnz DCacheSetup_quadWordLoop
|
||||
|
||||
/* Set the tag for this line, need to do this for every new cache line to validate it! */
|
||||
/* accessing CPU_DC_TAG_I makes the LINE field in CPU_DC_INDEX increment and thus cont. in the next cache line... */
|
||||
xorl %edx, %edx
|
||||
movl %ebp, %eax
|
||||
movl $CPU_DC_TAG, %ecx
|
||||
wrmsr
|
||||
|
||||
/* switch to next line */
|
||||
/* lines are in Bits10:4 */
|
||||
/* when index is crossing 0x7F -> 0x80 writing a RSVD bit as 0x80 is not a valid CL anymore! */
|
||||
movl $CPU_DC_INDEX, %ecx
|
||||
rdmsr
|
||||
addl $0x010, %eax /* TODO: prob. would be more elegant to calc. this from counter var edi... */
|
||||
wrmsr
|
||||
|
||||
decl %edi
|
||||
jnz DCacheSetupFillWay
|
||||
|
||||
/* 1 Way has been filled, forward start address for next Way, terminate if we have reached end of desired address range */
|
||||
addl $LX_CACHEWAY_SIZE, %ebp
|
||||
cmpl $LX_STACK_END, %ebp
|
||||
jge leave_DCacheSetup
|
||||
movl $LX_NUM_CACHELINES, %edi
|
||||
|
||||
/* switch to next way */
|
||||
movl $CPU_DC_INDEX, %ecx
|
||||
rdmsr
|
||||
addl $0x01, %eax
|
||||
andl $0xFFFFF80F, %eax /* lets be sure: reset line index Bits10:4 */
|
||||
wrmsr
|
||||
|
||||
jmp DCacheSetupFillWay
|
||||
|
||||
leave_DCacheSetup:
|
||||
xorl %edi, %edi
|
||||
xorl %esi, %esi
|
||||
xorl %ebp, %ebp
|
||||
|
||||
/* Disable the cache, but ... DO NOT INVALIDATE the tags. */
|
||||
/* Memory reads and writes will all hit in the cache. */
|
||||
/* Cache updates and memory write-backs will not occur ! */
|
||||
movl %cr0, %eax
|
||||
orl $(CR0_CD + CR0_NW), %eax /* set the CD and NW bits */
|
||||
movl %eax, %cr0
|
||||
|
||||
/* Now point sp to the cached stack. */
|
||||
/* The stack will be fully functional at this location. No system memory is required at all ! */
|
||||
/* set up the stack pointer */
|
||||
movl $LX_STACK_END, %eax
|
||||
movl %eax, %esp
|
||||
|
||||
/* test the stack*/
|
||||
movl $0x0F0F05A5A, %edx
|
||||
pushl %edx
|
||||
popl %ecx
|
||||
cmpl %ecx, %edx
|
||||
je DCacheSetupGood
|
||||
movb $0xC5, %al
|
||||
outb %al, $0x80
|
||||
DCacheSetupBad:
|
||||
hlt /* issues */
|
||||
jmp DCacheSetupBad
|
||||
DCacheSetupGood:
|
||||
|
||||
/* If you wanted to maintain the stack in memory you would need to set the tags as dirty
|
||||
so the wbinvd would push out the old stack contents to memory */
|
||||
/* Clear the cache, the following code from crt0.S.lb will setup a new stack*/
|
||||
wbinvd
|
||||
|
||||
/* at this point, CAR should be working */
|
||||
movl $(LX_STACK_END), %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 */
|
||||
|
||||
# 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
|
||||
# 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 bugs 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? ID string? We might want to put something else in here.
|
||||
.ascii DATE
|
||||
|
||||
# Checksum.
|
||||
#.word 0
|
||||
Loading…
Add table
Add a link
Reference in a new issue