From 189c9077a1a6399c6bb6b694ab77f4abc2712cd1 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 27 Feb 2009 22:13:34 +0000 Subject: [PATCH] This patch enables OpenBIOS to initialize on PPC64, enabling support for -cpu 970fx. It gets up to the boot prompt and works rather good so far, though I haven't been able to run a kernel yet. For more recent PowerPC CPUs the PTE layout has changed, so we need to take that into account and create PTEs according to the new layout and at the new physical positions. Signed-off-by: Alexander Graf Signed-off-by: Laurent Vivier git-svn-id: svn://coreboot.org/openbios/openbios-devel@461 f158a5a8-5612-0410-a976-696ce0be7e32 --- arch/ppc/qemu/init.c | 25 +++++++++++ arch/ppc/qemu/mmutypes.h | 21 ++++++++++ arch/ppc/qemu/ofmem.c | 90 +++++++++++++++++++++++++++++++++++++++- include/ofmem.h | 11 +++-- 4 files changed, 142 insertions(+), 5 deletions(-) diff --git a/arch/ppc/qemu/init.c b/arch/ppc/qemu/init.c index 35583b0..b733737 100644 --- a/arch/ppc/qemu/init.c +++ b/arch/ppc/qemu/init.c @@ -238,6 +238,19 @@ cpu_g4_init(const struct cpudef *cpu) fword("finish-device"); } +static void +cpu_970_init(const struct cpudef *cpu) +{ + cpu_generic_init(cpu); + + PUSH(0); + fword("encode-int"); + push_str("reg"); + fword("property"); + + fword("finish-device"); +} + static const struct cpudef ppc_defs[] = { { .iu_version = 0x00040000, @@ -359,6 +372,18 @@ static const struct cpudef ppc_defs[] = { .clock_frequency = 0x1dcd6500, .initfn = cpu_g4_init, }, + { // XXX find out real values + .iu_version = 0x003C0000, + .name = "PowerPC,970FX", + .icache_size = 0x8000, + .dcache_size = 0x8000, + .icache_sets = 0x80, + .dcache_sets = 0x80, + .icache_block_size = 0x80, + .dcache_block_size = 0x80, + .clock_frequency = 0x1dcd6500, + .initfn = cpu_970_init, + }, }; static const struct cpudef * diff --git a/arch/ppc/qemu/mmutypes.h b/arch/ppc/qemu/mmutypes.h index 441d7f8..512c23d 100644 --- a/arch/ppc/qemu/mmutypes.h +++ b/arch/ppc/qemu/mmutypes.h @@ -38,6 +38,27 @@ typedef struct mPTE { unsigned long pp:2; /* Page protection */ } mPTE_t; +typedef struct mPTE_64 { + uint32_t avpn_low; /* Abbreviated Virtual Page Number (unused) */ + uint32_t avpn:25; /* Abbreviated Virtual Page Number */ + uint32_t sw:4; /* Software Use */ + uint32_t :1; /* Reserved */ + uint32_t h:1; /* Hash algorithm indicator */ + uint32_t v:1; /* Entry is valid */ + + uint32_t rpn_low; /* Real (physical) page number (unused) */ + uint32_t rpn:20; /* Real (physical) page number */ + uint32_t :2; /* Reserved */ + uint32_t ac:1; /* Address Compare*/ + uint32_t r:1; /* Referenced */ + uint32_t c:1; /* Changed */ + uint32_t w:1; /* Write-thru cache mode */ + uint32_t i:1; /* Cache inhibited */ + uint32_t m:1; /* Memory coherence */ + uint32_t g:1; /* Guarded */ + uint32_t n:1; /* No-Execute */ + uint32_t pp:2; /* Page protection */ +} mPTE_64_t; typedef struct _mBATU { /* Upper part of BAT (all except 601) */ unsigned long bepi:15; /* Effective page index (virtual address) */ diff --git a/arch/ppc/qemu/ofmem.c b/arch/ppc/qemu/ofmem.c index db57869..5191dd6 100644 --- a/arch/ppc/qemu/ofmem.c +++ b/arch/ppc/qemu/ofmem.c @@ -621,7 +621,73 @@ ea_to_phys( ulong ea, int *mode ) } static void -hash_page( ulong ea, ulong phys, int mode ) +hash_page_64( ulong ea, ulong phys, int mode ) +{ + static int next_grab_slot=0; + uint64_t vsid_mask, page_mask, pgidx, hash; + uint64_t htab_mask, mask, avpn; + ulong pgaddr; + int i, found; + unsigned int vsid, vsid_sh, sdr, sdr_sh, sdr_mask; + mPTE_64_t *pp; + + vsid = (ea >> 28) + SEGR_BASE; + vsid_sh = 7; + vsid_mask = 0x00003FFFFFFFFF80ULL; + asm ( "mfsdr1 %0" : "=r" (sdr) ); + sdr_sh = 18; + sdr_mask = 0x3FF80; + page_mask = 0x0FFFFFFF; // XXX correct? + pgidx = (ea & page_mask) >> PAGE_SHIFT; + avpn = (vsid << 12) | ((pgidx >> 4) & 0x0F80);; + + hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask; + htab_mask = 0x0FFFFFFF >> (28 - (sdr & 0x1F)); + mask = (htab_mask << sdr_sh) | sdr_mask; + pgaddr = sdr | (hash & mask); + pp = (mPTE_64_t *)pgaddr; + + /* replace old translation */ + for( found=0, i=0; !found && i<8; i++ ) + if( pp[i].avpn == avpn ) + found=1; + + /* otherwise use a free slot */ + for( i=0; !found && i<8; i++ ) + if( !pp[i].v ) + found=1; + + /* out of slots, just evict one */ + if( !found ) { + i = next_grab_slot + 1; + next_grab_slot = (next_grab_slot + 1) % 8; + } + i--; + { + mPTE_64_t p = { + // .avpn_low = avpn, + .avpn = avpn >> 7, + .h = 0, + .v = 1, + + .rpn = (phys & ~0xfff) >> 12, + .r = mode & (1 << 8) ? 1 : 0, + .c = mode & (1 << 7) ? 1 : 0, + .w = mode & (1 << 6) ? 1 : 0, + .i = mode & (1 << 5) ? 1 : 0, + .m = mode & (1 << 4) ? 1 : 0, + .g = mode & (1 << 3) ? 1 : 0, + .n = mode & (1 << 2) ? 1 : 0, + .pp = mode & 3, + }; + pp[i] = p; + } + + asm volatile( "tlbie %0" :: "r"(ea) ); +} + +static void +hash_page_32( ulong ea, ulong phys, int mode ) { static int next_grab_slot=0; ulong *upte, cmp, hash1; @@ -660,6 +726,22 @@ hash_page( ulong ea, ulong phys, int mode ) asm volatile( "tlbie %0" :: "r"(ea) ); } +static int is_ppc64(void) +{ + unsigned int pvr; + asm volatile("mfspr %0, 0x11f" : "=r" (pvr) ); + + return ((pvr >= 0x330000) && (pvr < 0x70330000)); +} + +static void hash_page( ulong ea, ulong phys, int mode ) +{ + if ( is_ppc64() ) + hash_page_64(ea, phys, mode); + else + hash_page_32(ea, phys, mode); +} + void dsi_exception( void ) { @@ -699,6 +781,7 @@ setup_mmu( ulong ramsize ) ofmem_t *ofmem = OFMEM; ulong sdr1, sr_base, msr; ulong hash_base; + ulong hash_mask = 0xffff0000; int i; memset(ofmem, 0, sizeof(ofmem_t)); @@ -706,7 +789,10 @@ setup_mmu( ulong ramsize ) /* SDR1: Storage Description Register 1 */ - hash_base = (ramsize - 0x00100000 - HASH_SIZE) & 0xffff0000; + if(is_ppc64()) + hash_mask = 0xfff00000; + + hash_base = (ramsize - 0x00100000 - HASH_SIZE) & hash_mask; memset((void *)hash_base, 0, HASH_SIZE); sdr1 = hash_base | ((HASH_SIZE-1) >> 16); asm volatile("mtsdr1 %0" :: "r" (sdr1) ); diff --git a/include/ofmem.h b/include/ofmem.h index 48ab632..7dfa7e0 100644 --- a/include/ofmem.h +++ b/include/ofmem.h @@ -30,6 +30,8 @@ extern void ofmem_release( ulong virt, ulong size ); extern ulong ofmem_translate( ulong virt, int *ret_mode ); #ifdef CONFIG_PPC +#define PAGE_SHIFT 12 + ulong get_ram_size( void ); ulong get_ram_top( void ); ulong get_ram_bottom( void ); @@ -39,9 +41,6 @@ void setup_mmu( ulong ramsize ); void ofmem_register( phandle_t ph ); #elif defined(CONFIG_SPARC32) #define PAGE_SHIFT 12 -#define PAGE_SIZE (1 << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE - 1)) -#define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK) /* arch/sparc32/lib.c */ struct mem; @@ -53,4 +52,10 @@ int map_page(unsigned long va, uint64_t epa, int type); void *map_io(uint64_t pa, int size); #endif +#ifdef PAGE_SHIFT +#define PAGE_SIZE (1 << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE - 1)) +#define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK) +#endif + #endif /* _H_OFMEM */