Hi!
This patch series implement OF memory manager.
I used arch/ppc/qemu/ofmem.c as a starting point, future plans in ofmem area would be to migrate common parts from working implementations (ppc and sparc64) into shared module.
Since ofmem declarations are to be used by different architectures it appears that using ucell type in ofmem.h is appropriate. This required changes to ppc/qemu code. Unfortunately mol, briq and pearpc configurations does not build in my setup so I did not touched those parts, and this change may be incomplete.
It seems useful to introduce CONFIG_OFMEM_OPTION to conditionally trace ofmem operations, so this is implemented as well. Also I introduce FMT_cell and other macros to help formatting log messages easily.
Client interface handler now uses ofmem implementation instead of walking hardware translation tables. Since setup code in entry.S does install it's own translations ofmem initialization routine simply copies entries from hardware. Properties "available" and "translations" are then populated as needed.
This implementation passes boot test with no visible changes on screen for HelenOS-0.4.0-sparc64.iso
Linux boot does not improve with this patch due to conflicts with memory mappings in low memory region. Also there is an issue with lazy conditional codes evaluation by qemu. If disrupting trap is taken before conditional branch is executed then upon return from trap conditional codes are not evaluated correctly. Visible effect is that with this patch series silo is no longer gets into second stage, stopping at SIL output. Patch for this issue is already posted to qemu-devel mailing list.
Signed-off-by: igor.v.kovalenko@gmail.com
Index: openbios-devel/include/ofmem.h =================================================================== --- openbios-devel.orig/include/ofmem.h +++ openbios-devel/include/ofmem.h @@ -20,14 +20,14 @@ extern void ofmem_cleanup( void ); extern void ofmem_init( void );
-extern ulong ofmem_claim( ulong addr, ulong size, ulong align ); -extern ulong ofmem_claim_phys( ulong mphys, ulong size, ulong align ); -extern ulong ofmem_claim_virt( ulong mvirt, ulong size, ulong align ); +extern ucell ofmem_claim( ucell addr, ucell size, ucell align ); +extern ucell ofmem_claim_phys( ucell mphys, ucell size, ucell align ); +extern ucell ofmem_claim_virt( ucell mvirt, ucell size, ucell align );
-extern int ofmem_map( ulong phys, ulong virt, ulong size, int mode ); +extern int ofmem_map( ucell phys, ucell virt, ucell size, ucell mode );
-extern void ofmem_release( ulong virt, ulong size ); -extern ulong ofmem_translate( ulong virt, int *ret_mode ); +extern void ofmem_release( ucell virt, ucell size ); +extern ucell ofmem_translate( ucell virt, ucell *ret_mode );
#ifdef CONFIG_PPC #define PAGE_SHIFT 12 Index: openbios-devel/arch/ppc/qemu/ofmem.c =================================================================== --- openbios-devel.orig/arch/ppc/qemu/ofmem.c +++ openbios-devel/arch/ppc/qemu/ofmem.c @@ -37,21 +37,21 @@
typedef struct alloc_desc { struct alloc_desc *next; - int size; /* size (including) this struct */ + ucell size; /* size (including) this struct */ } alloc_desc_t;
typedef struct mem_range { struct mem_range *next; - ulong start; - ulong size; + ucell start; + ucell size; } range_t;
typedef struct trans { struct trans *next; - ulong virt; /* chain is sorted by virt */ - ulong size; - ulong phys; - int mode; + ucell virt; /* chain is sorted by virt */ + ucell size; + ucell phys; + ucell mode; } translation_t;
typedef struct { @@ -236,8 +236,8 @@ realloc( void *ptr, size_t size ) /************************************************************************/
extern char _start[], _end[]; -static inline int -def_memmode( ulong phys ) +static inline ucell +def_memmode( ucell phys ) { /* XXX: Guard bit not set as it should! */ if( phys < IO_BASE ) @@ -251,7 +251,7 @@ def_memmode( ulong phys ) /************************************************************************/
static int -is_free( ulong ea, ulong size, range_t *r ) +is_free( ucell ea, ucell size, range_t *r ) { if( size == 0 ) return 1; @@ -265,7 +265,7 @@ is_free( ulong ea, ulong size, range_t * }
static void -add_entry_( ulong ea, ulong size, range_t **r ) +add_entry_( ucell ea, ucell size, range_t **r ) { range_t *nr;
@@ -279,7 +279,7 @@ add_entry_( ulong ea, ulong size, range_ }
static int -add_entry( ulong ea, ulong size, range_t **r ) +add_entry( ucell ea, ucell size, range_t **r ) { if( !is_free( ea, size, *r ) ) { printk("add_entry: range not free!\n"); @@ -310,20 +310,20 @@ join_ranges( range_t **rr ) }
static void -fill_range( ulong ea, int size, range_t **rr ) +fill_range( ulong ea, ucell size, range_t **rr ) { add_entry_( ea, size, rr ); join_ranges( rr ); }
-static ulong -find_area( ulong align, ulong size, range_t *r, ulong min, ulong max, int reverse ) +static ucell +find_area( ucell align, ucell size, range_t *r, ucell min, ucell max, int reverse ) { - ulong base = min; + ucell base = min; range_t *r2;
if( (align & (align-1)) ) { - printk("bad alignment %ld\n", align); + printk("bad alignment %d\n", align); align = 0x1000; } if( !align ) @@ -362,11 +362,11 @@ find_area( ulong align, ulong size, rang base = r2->start - size; } } - return (ulong)-1; + return (ucell)-1; }
-static ulong -ofmem_claim_phys_( ulong phys, ulong size, ulong align, int min, int max, int reverse ) +static ucell +ofmem_claim_phys_( ucell phys, ucell size, ucell align, ucell min, ucell max, int reverse ) { ofmem_t *ofmem = OFMEM; if( !align ) { @@ -387,15 +387,15 @@ ofmem_claim_phys_( ulong phys, ulong siz }
/* if align != 0, phys is ignored. Returns -1 on error */ -ulong -ofmem_claim_phys( ulong phys, ulong size, ulong align ) +ucell +ofmem_claim_phys( ucell phys, ucell size, ucell align ) { /* printk("+ ofmem_claim phys %08lx %lx %ld\n", phys, size, align ); */ return ofmem_claim_phys_( phys, size, align, 0, get_ram_size(), 0 ); }
-static ulong -ofmem_claim_virt_( ulong virt, ulong size, ulong align, int min, int max, int reverse ) +static ucell +ofmem_claim_virt_( ucell virt, ucell size, ucell align, ucell min, ucell max, int reverse ) { ofmem_t *ofmem = OFMEM; if( !align ) { @@ -416,8 +416,8 @@ ofmem_claim_virt_( ulong virt, ulong siz return virt; }
-ulong -ofmem_claim_virt( ulong virt, ulong size, ulong align ) +ucell +ofmem_claim_virt( ucell virt, ucell size, ucell align ) { /* printk("+ ofmem_claim virt %08lx %lx %ld\n", virt, size, align ); */ return ofmem_claim_virt_( virt, size, align, get_ram_size() , IO_BASE, 0 ); @@ -425,12 +425,12 @@ ofmem_claim_virt( ulong virt, ulong size
/* allocate both physical and virtual space and add a translation */ -ulong -ofmem_claim( ulong addr, ulong size, ulong align ) +ucell +ofmem_claim( ucell addr, ucell size, ucell align ) { ofmem_t *ofmem = OFMEM; - ulong virt, phys; - ulong offs = addr & 0xfff; + ucell virt, phys; + ucell offs = addr & 0xfff;
/* printk("+ ofmem_claim %08lx %lx %ld\n", addr, size, align ); */ virt = phys = 0; @@ -496,7 +496,7 @@ split_trans( ulong virt ) }
static int -map_page_range( ulong virt, ulong phys, ulong size, int mode ) +map_page_range( ucell virt, ucell phys, ucell size, ucell mode ) { ofmem_t *ofmem = OFMEM; translation_t *t, **tt; @@ -508,7 +508,7 @@ map_page_range( ulong virt, ulong phys, for( t=ofmem->trans; t; ) { if( virt == t->virt || (virt < t->virt && virt + size > t->virt )) { if( t->phys + virt - t->virt != phys ) { - printk("mapping altered (ea %08lx)\n", t->virt ); + printk("mapping altered (ea %08x)\n", t->virt ); } else if( t->mode != mode ){ printk("mapping mode altered\n"); } @@ -538,7 +538,7 @@ map_page_range( ulong virt, ulong phys, }
int -ofmem_map( ulong phys, ulong virt, ulong size, int mode ) +ofmem_map( ucell phys, ucell virt, ucell size, ucell mode ) { ofmem_t *ofmem = OFMEM; /* printk("+ofmem_map: %08lX --> %08lX (size %08lX, mode 0x%02X)\n", @@ -563,14 +563,14 @@ ofmem_map( ulong phys, ulong virt, ulong }
/* virtual -> physical. */ -ulong -ofmem_translate( ulong virt, int *mode ) +ucell +ofmem_translate( ucell virt, ucell *mode ) { ofmem_t *ofmem = OFMEM; translation_t *t;
for( t=ofmem->trans; t && t->virt <= virt ; t=t->next ) { - ulong offs; + ucell offs; if( t->virt + t->size - 1 < virt ) continue; offs = virt - t->virt; @@ -585,7 +585,7 @@ ofmem_translate( ulong virt, int *mode )
/* release memory allocated by ofmem_claim */ void -ofmem_release( ulong virt, ulong size ) +ofmem_release( ucell virt, ucell size ) { /* printk("ofmem_release unimplemented (%08lx, %08lx)\n", virt, size ); */ } @@ -595,10 +595,10 @@ ofmem_release( ulong virt, ulong size ) /* page fault handler */ /************************************************************************/
-static ulong -ea_to_phys( ulong ea, int *mode ) +static ucell +ea_to_phys( ucell ea, ucell *mode ) { - ulong phys; + ucell phys;
if (ea >= 0xfff00000UL) { /* ROM into RAM */ @@ -621,7 +621,7 @@ ea_to_phys( ulong ea, int *mode ) }
static void -hash_page_64( ulong ea, ulong phys, int mode ) +hash_page_64( ucell ea, ucell phys, ucell mode ) { static int next_grab_slot=0; uint64_t vsid_mask, page_mask, pgidx, hash; @@ -687,7 +687,7 @@ hash_page_64( ulong ea, ulong phys, int }
static void -hash_page_32( ulong ea, ulong phys, int mode ) +hash_page_32( ucell ea, ucell phys, ucell mode ) { static int next_grab_slot=0; ulong *upte, cmp, hash1; @@ -734,7 +734,7 @@ static int is_ppc64(void) return ((pvr >= 0x330000) && (pvr < 0x70330000)); }
-static void hash_page( ulong ea, ulong phys, int mode ) +static void hash_page( ulong ea, ulong phys, ucell mode ) { if ( is_ppc64() ) hash_page_64(ea, phys, mode); @@ -746,8 +746,8 @@ void dsi_exception( void ) { ulong dar, dsisr; - int mode; - ulong phys; + ucell mode; + ucell phys;
asm volatile("mfdar %0" : "=r" (dar) : ); asm volatile("mfdsisr %0" : "=r" (dsisr) : ); @@ -760,8 +760,8 @@ void isi_exception( void ) { ulong nip, srr1; - int mode; - ulong phys; + ucell mode; + ucell phys;
asm volatile("mfsrr0 %0" : "=r" (nip) : ); asm volatile("mfsrr1 %0" : "=r" (srr1) : ); Index: openbios-devel/arch/ppc/qemu/methods.c =================================================================== --- openbios-devel.orig/arch/ppc/qemu/methods.c +++ openbios-devel/arch/ppc/qemu/methods.c @@ -241,9 +241,9 @@ mmu_unmap( void ) static void mmu_translate( void ) { - int mode; - int virt = POP(); - int phys = ofmem_translate( virt, &mode ); + ucell mode; + ucell virt = POP(); + ucell phys = ofmem_translate( virt, &mode );
if( phys == -1 ) { PUSH( 0 );
Add CONFIG_DEBUG_OFMEM option to configurations which implement OF memory manager. Implement DEBUG_OFMEM macro to be used by debug traces in OF memory manager code.
Index: openbios-devel/include/ofmem.h =================================================================== --- openbios-devel.orig/include/ofmem.h +++ openbios-devel/include/ofmem.h @@ -58,4 +58,10 @@ void *map_io(uint64_t pa, int size); #define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK) #endif
+#if defined(CONFIG_DEBUG_OFMEM) +# define OFMEM_TRACE(fmt, ...) do { printk("OFMEM: " fmt, ## __VA_ARGS__); } while (0) +#else +# define OFMEM_TRACE(fmt, ...) do {} while(0) +#endif + #endif /* _H_OFMEM */ Index: openbios-devel/config/examples/cross-ppc_config.xml =================================================================== --- openbios-devel.orig/config/examples/cross-ppc_config.xml +++ openbios-devel/config/examples/cross-ppc_config.xml @@ -27,6 +27,7 @@ <option name="CONFIG_SERIAL_PORT" type="integer" value="0"/> <option name="CONFIG_SERIAL_SPEED" type="integer" value="115200"/> <option name="CONFIG_DEBUG_CONSOLE_VGA" type="boolean" value="true"/> + <option name="CONFIG_DEBUG_OFMEM" type="boolean" value="false"/>
<!-- Module Configuration --> Index: openbios-devel/config/examples/cross-sparc32_config.xml =================================================================== --- openbios-devel.orig/config/examples/cross-sparc32_config.xml +++ openbios-devel/config/examples/cross-sparc32_config.xml @@ -33,6 +33,7 @@ <option name="CONFIG_DEBUG_IOMMU" type="boolean" value="false"/> <option name="CONFIG_SERIAL_PORT" type="integer" value="0"/> <option name="CONFIG_SERIAL_SPEED" type="integer" value="9600"/> + <option name="CONFIG_DEBUG_OFMEM" type="boolean" value="false"/>
<!-- Module Configuration --> Index: openbios-devel/config/examples/cross-sparc64_config.xml =================================================================== --- openbios-devel.orig/config/examples/cross-sparc64_config.xml +++ openbios-devel/config/examples/cross-sparc64_config.xml @@ -30,6 +30,7 @@ <option name="CONFIG_SERIAL_PORT" type="integer" value="0"/> <option name="CONFIG_SERIAL_SPEED" type="integer" value="115200"/> <option name="CONFIG_DEBUG_CONSOLE_VGA" type="boolean" value="true"/> + <option name="CONFIG_DEBUG_OFMEM" type="boolean" value="false"/>
<!-- Module Configuration --> Index: openbios-devel/config/examples/ppc_config.xml =================================================================== --- openbios-devel.orig/config/examples/ppc_config.xml +++ openbios-devel/config/examples/ppc_config.xml @@ -27,6 +27,7 @@ <option name="CONFIG_SERIAL_PORT" type="integer" value="0"/> <option name="CONFIG_SERIAL_SPEED" type="integer" value="115200"/> <option name="CONFIG_DEBUG_CONSOLE_VGA" type="boolean" value="true"/> + <option name="CONFIG_DEBUG_OFMEM" type="boolean" value="false"/>
<!-- Module Configuration --> Index: openbios-devel/config/examples/sparc32_config.xml =================================================================== --- openbios-devel.orig/config/examples/sparc32_config.xml +++ openbios-devel/config/examples/sparc32_config.xml @@ -33,6 +33,7 @@ <option name="CONFIG_DEBUG_IOMMU" type="boolean" value="false"/> <option name="CONFIG_SERIAL_PORT" type="integer" value="0"/> <option name="CONFIG_SERIAL_SPEED" type="integer" value="9600"/> + <option name="CONFIG_DEBUG_OFMEM" type="boolean" value="false"/>
<!-- Module Configuration --> Index: openbios-devel/config/examples/sparc64_config.xml =================================================================== --- openbios-devel.orig/config/examples/sparc64_config.xml +++ openbios-devel/config/examples/sparc64_config.xml @@ -30,6 +30,7 @@ <option name="CONFIG_SERIAL_PORT" type="integer" value="0"/> <option name="CONFIG_SERIAL_SPEED" type="integer" value="115200"/> <option name="CONFIG_DEBUG_CONSOLE_VGA" type="boolean" value="true"/> + <option name="CONFIG_DEBUG_OFMEM" type="boolean" value="false"/>
<!-- Module Configuration -->
Use int64_t for cell and uint64_t for ucell. Define printf-style format macros to ease writing cell-type-independend log traces.
Index: openbios-devel/include/sparc64/types.h =================================================================== --- openbios-devel.orig/include/sparc64/types.h +++ openbios-devel/include/sparc64/types.h @@ -29,8 +29,12 @@ typedef long long int64_t; #include "autoconf.h"
/* cell based types */ -typedef long long cell; -typedef unsigned long long ucell; +typedef int64_t cell; +typedef uint64_t ucell; + +#define FMT_cell "%lld" +#define FMT_ucell "%llu" +#define FMT_ucellx "%016llx"
#ifdef NEED_FAKE_INT128_T typedef struct {
Add sparc64 ofmem implementation.
Index: openbios-devel/arch/sparc64/build.xml =================================================================== --- openbios-devel.orig/arch/sparc64/build.xml +++ openbios-devel/arch/sparc64/build.xml @@ -19,6 +19,7 @@ <object source="forthload.c"/> <object source="fcodeload.c"/> <object source="loadfs.c"/> + <object source="ofmem_sparc64.c"/> </library>
<executable name="target/arch/sparc64/entry.o" target="target"> Index: openbios-devel/arch/sparc64/ofmem_sparc64.c =================================================================== --- /dev/null +++ openbios-devel/arch/sparc64/ofmem_sparc64.c @@ -0,0 +1,664 @@ +/* + * <ofmem_sparc64.c> + * + * OF Memory manager + * + * Copyright (C) 1999-2004 Samuel Rydh (samuel@ibrium.se) + * Copyright (C) 2004 Stefan Reinauer + * + * 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 + * + */ + +#include "openbios/config.h" +#include "openbios/bindings.h" +#include "libc/string.h" +#include "ofmem_sparc64.h" +#include "spitfire.h" + +static inline uint64_t ALIGN_SIZE(uint64_t x, uint64_t a) +{ + return (x + a - 1) & ~(a-1); +} + +#define OF_MALLOC_BASE ((char*)OFMEM + ALIGN_SIZE(sizeof(ofmem_t), 8)) + +#define MEMSIZE ((128 + 256 + 512) * 1024) +static union { + char memory[MEMSIZE]; + ofmem_t ofmem; +} s_ofmem_data; + +#define OFMEM (&s_ofmem_data.ofmem) +#define TOP_OF_RAM (s_ofmem_data.memory + MEMSIZE) + +translation_t **g_ofmem_translations = &s_ofmem_data.ofmem.trans; + +ulong get_ram_size( void ) +{ + ofmem_t *ofmem = OFMEM; + return ofmem->ramsize; +} + +static phandle_t s_phandle_memory = 0; +static phandle_t s_phandle_mmu = 0; + +static void ofmem_update_mmu_translations( void ) +{ + ofmem_t *ofmem = OFMEM; + translation_t *t; + int ncells; + ucell *props; + + if (s_phandle_mmu == 0) + return; + + for( t = ofmem->trans, ncells = 0; t ; t=t->next, ncells++ ) { + } + + props = malloc(ncells * sizeof(ucell) * 3); + + if (props == NULL) + return; + + for( t = ofmem->trans, ncells = 0 ; t ; t=t->next ) { + props[ncells++] = t->virt; + props[ncells++] = t->size; + props[ncells++] = t->mode; + } + + set_property(s_phandle_mmu, "translations", + (char*)props, ncells * sizeof(props[0])); + + free(props); +} + +static void ofmem_update_memory_available( phandle_t ph, range_t *range, + u64 top_address ) +{ + range_t *r; + int ncells; + ucell *props; + + ucell start, size; + + if (s_phandle_memory == 0) + return; + + /* count phys_range list entries */ + for( r = range, ncells = 0; r ; r=r->next, ncells++ ) { + } + + /* inverse of phys_range list could take 2 more cells for the tail */ + props = malloc((ncells+1) * sizeof(ucell) * 2); + + if (props == NULL) { + /* out of memory! */ + return; + } + + start = 0; + ncells = 0; + + for (r = range; r; r=r->next) { + if (r->start >= top_address) { + break; + } + + size = r->start - start; + if (size) { + props[ncells++] = start; + props[ncells++] = size; + } + start = r->start + r->size; + } + + /* tail */ + if (start < top_address) { + props[ncells++] = start; + props[ncells++] = top_address - start; + } + + set_property(ph, "available", + (char*)props, ncells * sizeof(props[0])); + + free(props); +} + +static void ofmem_update_translations( void ) +{ + ofmem_t *ofmem = OFMEM; + + ofmem_update_memory_available(s_phandle_memory, + ofmem->phys_range, ofmem->ramsize); + ofmem_update_memory_available(s_phandle_mmu, + ofmem->virt_range, -1ULL); + ofmem_update_mmu_translations(); +} + +/************************************************************************/ +/* OF private allocations */ +/************************************************************************/ + +void* ofmem_malloc( size_t size ) +{ + ofmem_t *ofmem = OFMEM; + alloc_desc_t *d, **pp; + char *ret; + + if( !size ) + return NULL; + + if( !ofmem->next_malloc ) + ofmem->next_malloc = (char*)OF_MALLOC_BASE; + + /* assuming sizeof(alloc_desc_t) is multiple of 8 */ + size = ALIGN_SIZE(size + sizeof(alloc_desc_t), 8); + + /* look in the freelist */ + for( pp=&ofmem->mfree; *pp && (**pp).size < size; pp = &(**pp).next ) { + } + + /* waste at most 4K by taking an entry from the freelist */ + if( *pp && (**pp).size < size + 0x1000 ) { + ret = (char*)*pp + sizeof(alloc_desc_t); + memset( ret, 0, (**pp).size - sizeof(alloc_desc_t) ); + *pp = (**pp).next; + return ret; + } + + if( ofmem->next_malloc + size >= TOP_OF_RAM ) { + printk("out of malloc memory (%x)!\n", size ); + return NULL; + } + + d = (alloc_desc_t*) ofmem->next_malloc; + ofmem->next_malloc += size; + + d->next = NULL; + d->size = size; + + ret = (char*)d + sizeof(alloc_desc_t); + memset( ret, 0, size - sizeof(alloc_desc_t) ); + + return ret; +} + +void ofmem_free( void *ptr ) +{ + ofmem_t *ofmem = OFMEM; + alloc_desc_t **pp, *d; + + /* it is legal to free NULL pointers (size zero allocations) */ + if( !ptr ) + return; + + d = (alloc_desc_t*)((char *)ptr - sizeof(alloc_desc_t)); + d->next = ofmem->mfree; + + /* insert in the (sorted) freelist */ + for( pp=&ofmem->mfree; *pp && (**pp).size < d->size ; pp = &(**pp).next ) { + } + + d->next = *pp; + *pp = d; +} + +void* ofmem_realloc( void *ptr, size_t size ) +{ + alloc_desc_t *d = (alloc_desc_t*)((char *)ptr - sizeof(alloc_desc_t)); + char *p; + + if( !ptr ) + return malloc( size ); + if( !size ) { + free( ptr ); + return NULL; + } + p = malloc( size ); + memcpy( p, ptr, MIN(d->size - sizeof(alloc_desc_t),size) ); + free( ptr ); + return p; +} + + +/************************************************************************/ +/* misc */ +/************************************************************************/ + +static inline ucell def_memmode( ucell phys ) +{ + /* Writable, cacheable */ + /* not privileged and not locked */ + return SPITFIRE_TTE_CP | SPITFIRE_TTE_CV | SPITFIRE_TTE_WRITABLE; +} + + +/************************************************************************/ +/* client interface */ +/************************************************************************/ + +static int is_free( ucell ea, ucell size, range_t *r ) +{ + if( size == 0 ) + return 1; + for( ; r ; r=r->next ) { + if( r->start + r->size - 1 >= ea && r->start <= ea ) + return 0; + if( r->start >= ea && r->start <= ea + size - 1 ) + return 0; + } + return 1; +} + +static void add_entry_( ucell ea, ucell size, range_t **r ) +{ + range_t *nr; + + for( ; *r && (**r).start < ea; r=&(**r).next ) { + } + + nr = (range_t*)malloc( sizeof(range_t) ); + nr->next = *r; + nr->start = ea; + nr->size = size; + *r = nr; +} + +static int add_entry( ucell ea, ucell size, range_t **r ) +{ + if( !is_free( ea, size, *r ) ) { + printk("add_entry: range not free!\n"); + return -1; + } + add_entry_( ea, size, r ); + return 0; +} + +static ucell find_area( ucell align, ucell size, range_t *r, + ucell min, ucell max, int reverse ) +{ + ucell base = min; + range_t *r2; + + if( (align & (align-1)) ) { + printk("bad alignment " FMT_ucell "\n", align); + align = 0x1000; + } + if( !align ) + align = 0x1000; + + base = reverse ? max - size : min; + r2 = reverse ? NULL : r; + + for( ;; ) { + if( !reverse ) { + base = (base + align - 1) & ~(align-1); + if( base < min ) + base = min; + if( base + size - 1 >= max -1 ) + break; + } else { + if( base > max - size ) + base = max - size; + base -= base & (align-1); + } + if( is_free( base, size, r ) ) + return base; + + if( !reverse ) { + if( !r2 ) + break; + base = r2->start + r2->size; + r2 = r2->next; + } else { + range_t *rp; + + for( rp=r; rp && rp->next != r2 ; rp=rp->next ) { + } + + r2 = rp; + if( !r2 ) + break; + base = r2->start - size; + } + } + return (ucell)-1; +} + +static ucell ofmem_claim_phys_( ucell phys, ucell size, ucell align, + ucell min, ucell max, int reverse ) +{ + ofmem_t *ofmem = OFMEM; + if( !align ) { + if( !is_free( phys, size, ofmem->phys_range ) ) { + printk("Non-free physical memory claimed!\n"); + return -1; + } + add_entry( phys, size, &ofmem->phys_range ); + return phys; + } + phys = find_area( align, size, ofmem->phys_range, min, max, reverse ); + if( phys == (ucell)-1 ) { + printk("ofmem->claim_phys - out of space\n"); + return -1; + } + add_entry( phys, size, &ofmem->phys_range ); + + ofmem_update_translations(); + + return phys; +} + +/* if align != 0, phys is ignored. Returns -1 on error */ +ucell ofmem_claim_phys( ucell phys, ucell size, ucell align ) +{ + /* printk("+ ofmem_claim phys %08lx %lx %ld\n", phys, size, align ); */ + return ofmem_claim_phys_( phys, size, align, 0, get_ram_size(), 0 ); +} + +static ucell ofmem_claim_virt_( ucell virt, ucell size, ucell align, + ucell min, ucell max, int reverse ) +{ + ofmem_t *ofmem = OFMEM; + if( !align ) { + if( !is_free( virt, size, ofmem->virt_range ) ) { + printk("Non-free physical memory claimed!\n"); + return -1; + } + add_entry( virt, size, &ofmem->virt_range ); + return virt; + } + + virt = find_area( align, size, ofmem->virt_range, min, max, reverse ); + if( virt == -1UL ) { + printk("ofmem_claim_virt - out of space\n"); + return -1UL; + } + add_entry( virt, size, &ofmem->virt_range ); + return virt; +} + +ucell ofmem_claim_virt( ucell virt, ucell size, ucell align ) +{ + /* printk("+ ofmem_claim virt %08lx %lx %ld\n", virt, size, align ); */ + return ofmem_claim_virt_( virt, size, align, get_ram_size(), (ucell)TOP_OF_RAM, 0 ); +} + + +/* allocate both physical and virtual space and add a translation */ +ucell ofmem_claim( ucell addr, ucell size, ucell align ) +{ + ofmem_t *ofmem = OFMEM; + ucell virt, phys; + ucell offs = addr & 0xfff; + + /* printk("+ ofmem_claim %08lx %lx %ld\n", addr, size, align ); */ + virt = phys = 0; + if( !align ) { + if( is_free(addr, size, ofmem->virt_range) && + is_free(addr, size, ofmem->phys_range) ) { + ofmem_claim_phys_( addr, size, 0, 0, 0, 0 ); + ofmem_claim_virt_( addr, size, 0, 0, 0, 0 ); + virt = phys = addr; + } else { + /* printk("**** ofmem_claim failure ***!\n"); */ + return -1; + } + } else { + if( align < 0x1000 ) + align = 0x1000; + phys = ofmem_claim_phys_( addr, size, align, 0, get_ram_size(), 1 /* reverse */ ); + virt = ofmem_claim_virt_( addr, size, align, 0, get_ram_size(), 1 /* reverse */ ); + if( phys == (ucell)-1 || virt == (ucell)-1 ) { + printk("ofmem_claim failed\n"); + return -1; + } + /* printk("...phys = %08lX, virt = %08lX, size = %08lX\n", phys, virt, size ); */ + } + + /* align */ + if( phys & 0xfff ) { + size += (phys & 0xfff); + virt -= (phys & 0xfff); + phys &= ~0xfff; + } + if( size & 0xfff ) + size = (size + 0xfff) & ~0xfff; + + /* printk("...free memory found... phys: %08lX, virt: %08lX, size %lX\n", phys, virt, size ); */ + ofmem_map( phys, virt, size, -1 ); + return virt + offs; +} + + +/************************************************************************/ +/* keep track of ea -> phys translations */ +/************************************************************************/ + +static void split_trans( ucell virt ) +{ + ofmem_t *ofmem = OFMEM; + translation_t *t, *t2; + + for( t=ofmem->trans; t; t=t->next ) { + if( virt > t->virt && virt < t->virt + t->size-1 ) { + t2 = (translation_t*)malloc( sizeof(translation_t) ); + t2->virt = virt; + t2->size = t->size - (virt - t->virt); + t->size = virt - t->virt; + t2->phys = t->phys + t->size; + t2->mode = t->mode; + t2->next = t->next; + t->next = t2; + } + } +} + +static int map_page_range( ucell phys, ucell virt, ucell size, ucell mode ) +{ + ofmem_t *ofmem = OFMEM; + translation_t *t, **tt; + + OFMEM_TRACE("map_page_range " FMT_ucellx + " -> " FMT_ucellx " " FMT_ucellx " mode " FMT_ucellx "\n", + virt, phys, size, mode ); + + split_trans( virt ); + split_trans( virt + size ); + + /* detect remappings */ + for( t=ofmem->trans; t; ) { + if( virt == t->virt || (virt < t->virt && virt + size > t->virt )) { + if( t->phys + virt - t->virt != phys ) { + OFMEM_TRACE("mapping altered virt=" FMT_ucellx ")\n", t->virt ); + } else if( t->mode != mode ){ + OFMEM_TRACE("mapping mode altered virt=" FMT_ucellx + " old mode=" FMT_ucellx " new mode=" FMT_ucellx "\n", + t->virt, t->mode, mode); + } + + for( tt=&ofmem->trans; *tt != t ; tt=&(**tt).next ) { + } + + *tt = t->next; + + /* really unmap these pages */ + ofmem_unmap_pages(t->virt, t->size); + + free((char*)t); + + t=ofmem->trans; + continue; + } + t=t->next; + } + + /* add mapping */ + for( tt=&ofmem->trans; *tt && (**tt).virt < virt ; tt=&(**tt).next ) { + } + + t = (translation_t*)malloc( sizeof(translation_t) ); + t->virt = virt; + t->phys = phys; + t->size = size; + t->mode = mode; + t->next = *tt; + *tt = t; + + ofmem_update_translations(); + + return 0; +} + +static int unmap_page_range( ucell virt, ucell size ) +{ + ofmem_t *ofmem = OFMEM; + translation_t **plink; + + /* make sure there is exactly one matching translation entry */ + + split_trans( virt ); + split_trans( virt + size ); + + /* find and unlink entries in range */ + plink = &ofmem->trans; + + while (*plink && (*plink)->virt < virt+size) { + translation_t **plinkentry = plink; + translation_t *t = *plink; + + /* move ahead */ + plink = &t->next; + + if (t->virt >= virt && t->virt + t->size <= virt+size) { + + /* unlink entry */ + *plinkentry = t->next; + + printk("unmap_page_range found " FMT_ucellx + " -> " FMT_ucellx " " FMT_ucellx " mode " FMT_ucellx "\n", + t->virt, t->phys, t->size, t->mode ); + + // really map these pages + ofmem_unmap_pages(t->virt, t->size); + + free((char*)t); + } + } + + ofmem_update_translations(); + + return 0; +} + +int ofmem_map( ucell phys, ucell virt, ucell size, ucell mode ) +{ + /* printk("+ofmem_map: %08lX --> %08lX (size %08lX, mode 0x%02X)\n", + virt, phys, size, mode ); */ + + if( (phys & 0xfff) || (virt & 0xfff) || (size & 0xfff) ) { + /* printk("ofmem_map: Bad parameters (%08lX %08lX %08lX)\n", + phys, virt, size ); */ + phys &= ~0xfff; + virt &= ~0xfff; + size = (size + 0xfff) & ~0xfff; + } + + if (mode==-1) { + mode = def_memmode(phys); + } + + // install translations + map_page_range(phys, virt, size, mode); + + if (mode & SPITFIRE_TTE_LOCKED) { + // install locked tlb entries now + ofmem_map_pages(phys, virt, size, mode); + } + + return 0; +} + +int ofmem_unmap( ucell virt, ucell size ) +{ + OFMEM_TRACE("ofmem_unmap " FMT_ucellx " " FMT_ucellx "\n", + virt, size ); + + if( (virt & 0xfff) || (size & 0xfff) ) { + /* printk("ofmem_unmap: Bad parameters (%08lX %08lX)\n", + virt, size ); */ + virt &= ~0xfff; + size = (size + 0xfff) & ~0xfff; + } + + /* remove translations and unmap pages */ + unmap_page_range(virt, size); + + return 0; +} + +/* virtual -> physical. */ +ucell ofmem_translate( ucell virt, ucell *mode ) +{ + ofmem_t *ofmem = OFMEM; + translation_t *t; + + for( t=ofmem->trans; t && t->virt <= virt ; t=t->next ) { + ucell offs; + if( t->virt + t->size - 1 < virt ) + continue; + offs = virt - t->virt; + *mode = t->mode; + return t->phys + offs; + } + + /*printk("ofmem_translate: no translation defined (%08lx)\n", virt);*/ + /*print_trans();*/ + return -1UL; +} + +/* release memory allocated by ofmem_claim */ +void ofmem_release( ucell virt, ucell size ) +{ + printk("ofmem_release unimplemented (" FMT_ucellx ", " FMT_ucellx ")\n", + virt, size ); +} + + +/************************************************************************/ +/* init / cleanup */ +/************************************************************************/ + +extern uint64_t qemu_mem_size; + +static int remap_page_range( ucell phys, ucell virt, ucell size, ucell mode ) +{ + map_page_range(phys, virt, size, mode); + if (!(mode & SPITFIRE_TTE_LOCKED)) { + OFMEM_TRACE("remap_page_range clearing translation " FMT_ucellx + " -> " FMT_ucellx " " FMT_ucellx " mode " FMT_ucellx "\n", + virt, phys, size, mode ); + ofmem_unmap_pages(virt, size); + } + return 0; +} + +void ofmem_init( void ) +{ + memset(&s_ofmem_data, 0, sizeof(s_ofmem_data)); + s_ofmem_data.ofmem.ramsize = qemu_mem_size; + + /* inherit translations set up by entry.S */ + ofmem_walk_boot_map(remap_page_range); +} + +void ofmem_register( phandle_t ph_memory, phandle_t ph_mmu ) +{ + s_phandle_memory = ph_memory; + s_phandle_mmu = ph_mmu; + + ofmem_update_translations(); +} Index: openbios-devel/arch/sparc64/ofmem_sparc64.h =================================================================== --- /dev/null +++ openbios-devel/arch/sparc64/ofmem_sparc64.h @@ -0,0 +1,69 @@ +/* + * <ofmem_sparc64.h> + * + * OF Memory manager + * + * Copyright (C) 1999, 2002 Samuel Rydh (samuel@ibrium.se) + * + * 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 + * + */ + +#ifndef _H_OFMEM_SPARC64 +#define _H_OFMEM_SPARC64 + +#include "ofmem.h" + +extern void* ofmem_malloc( size_t size ); +extern void ofmem_free( void *ptr ); +extern void* ofmem_realloc( void *ptr, size_t size ); + +extern int ofmem_unmap(ucell virt, ucell size); + +ulong get_ram_size( void ); +ulong get_ram_top( void ); +ulong get_ram_bottom( void ); +extern void ofmem_register( phandle_t ph_memory, phandle_t ph_mmu ); +extern void ofmem_map_pages(ucell phys, ucell virt, ucell size, ucell mode); +extern void ofmem_unmap_pages(ucell virt, ucell size); + +typedef int (*translation_entry_cb)(ucell phys, ucell virt, + ucell size, ucell mode); + +extern void ofmem_walk_boot_map(translation_entry_cb cb); + +typedef struct alloc_desc { + struct alloc_desc *next; + ucell size; /* size (including) this struct */ +} alloc_desc_t; + +typedef struct mem_range { + struct mem_range *next; + ucell start; + ucell size; +} range_t; + +typedef struct trans { + struct trans *next; + ucell virt; /* chain is sorted by virt */ + ucell size; + ucell phys; + ucell mode; +} translation_t; + +typedef struct { + uint64_t ramsize; + char *next_malloc; + alloc_desc_t *mfree; /* list of free malloc blocks */ + + range_t *phys_range; + range_t *virt_range; + + translation_t *trans; /* this is really a translation_t */ +} ofmem_t; + +extern translation_t **g_ofmem_translations; + +#endif /* _H_OFMEM_SPARC64 */ Index: openbios-devel/arch/sparc64/spitfire.h =================================================================== --- openbios-devel.orig/arch/sparc64/spitfire.h +++ openbios-devel/arch/sparc64/spitfire.h @@ -35,6 +35,14 @@
#define SPITFIRE_HIGHEST_LOCKED_TLBENT (64 - 1)
+/* translation table entry bits */ +#define SPITFIRE_TTE_WRITABLE 0x02 +#define SPITFIRE_TTE_PRIVILEGED 0x04 +#define SPITFIRE_TTE_CV 0x10 +#define SPITFIRE_TTE_CP 0x20 +#define SPITFIRE_TTE_LOCKED 0x40 +#define SPITFIRE_TTE_VALID 0x8000000000000000ULL + #ifndef __ASSEMBLY__
enum ultra_tlb_layout { Index: openbios-devel/arch/sparc64/lib.c =================================================================== --- openbios-devel.orig/arch/sparc64/lib.c +++ openbios-devel/arch/sparc64/lib.c @@ -14,6 +14,8 @@ #include "sys_info.h" #include "boot.h"
+#include "ofmem_sparc64.h" + /* Format a string and print it on the screen, just like the libc * function printf. */ @@ -80,6 +82,10 @@ mmu_close(void) { }
+void ofmem_walk_boot_map(translation_entry_cb cb) +{ +} + static int spitfire_translate(unsigned long virt, unsigned long *p_phys, unsigned long *p_data, unsigned long *p_size) @@ -212,7 +218,8 @@ itlb_load(void) }
static void -map_pages(unsigned long virt, unsigned long size, unsigned long phys) +map_pages(unsigned long virt, unsigned long size, unsigned long phys, + unsigned long mode) { unsigned long tte_data, currsize;
@@ -238,7 +245,9 @@ map_pages(unsigned long virt, unsigned l currsize = PAGE_SIZE_8K; tte_data = 0; } - tte_data |= phys | 0x8000000000000036ULL; + + tte_data |= phys | mode | SPITFIRE_TTE_VALID; + dtlb_load2(virt, tte_data); itlb_load2(virt, tte_data); size -= currsize; @@ -247,6 +256,11 @@ map_pages(unsigned long virt, unsigned l } }
+void ofmem_map_pages(ucell phys, ucell virt, ucell size, ucell mode) +{ + return map_pages(phys, virt, size, mode); +} + /* 3.6.5 map ( phys.lo ... phys.hi virt size mode -- ) @@ -262,7 +276,7 @@ mmu_map(void) phys = POP(); phys <<= 32; phys |= POP(); - map_pages(virt, size, phys); + map_pages(virt, size, phys, mode); }
static void @@ -299,6 +313,11 @@ unmap_pages(unsigned long virt, unsigned } }
+void ofmem_unmap_pages(ucell virt, ucell size) +{ + unmap_pages(virt, size); +} + /* 3.6.5 unmap ( virt size -- )
Initialize ofmem at startup. Switch malloc/realloc/free to use ofmem. Implement runtime migration of startup mappings to ofmem. Implement mmu miss handlers to install tlb entries based on ofmem translations list.
Index: openbios-devel/arch/sparc64/lib.c =================================================================== --- openbios-devel.orig/arch/sparc64/lib.c +++ openbios-devel/arch/sparc64/lib.c @@ -34,32 +34,19 @@ int printk( const char *fmt, ... ) return i; }
-#define MEMSIZE ((128 + 256 + 512) * 1024) -static char memory[MEMSIZE]; -static void *memptr=memory; -static int memsize=MEMSIZE; - - void *malloc(int size) { - void *ret=(void *)0; - - if( !size ) - return NULL; - - size = (size + 7) & ~7; + return ofmem_malloc(size); +}
- if(memsize>=size) { - memsize-=size; - ret=memptr; - memptr = (void *)((unsigned long)memptr + size); - } - return ret; +void* realloc( void *ptr, size_t size ) +{ + return ofmem_realloc(ptr, size); }
void free(void *ptr) { - /* Nothing yet */ + ofmem_free(ptr); }
#define PAGE_SIZE_4M (4 * 1024 * 1024) @@ -84,50 +71,44 @@ mmu_close(void)
void ofmem_walk_boot_map(translation_entry_cb cb) { -} - -static int -spitfire_translate(unsigned long virt, unsigned long *p_phys, - unsigned long *p_data, unsigned long *p_size) -{ - unsigned long phys, tag, data, mask, size; + unsigned long phys, virt, size, mode, data, mask; unsigned int i;
for (i = 0; i < 64; i++) { data = spitfire_get_dtlb_data(i); - if (data & 0x8000000000000000ULL) { // Valid entry? + if (data & SPITFIRE_TTE_VALID) { switch ((data >> 61) & 3) { default: - case 0x0: // 8k + case 0x0: /* 8k */ mask = 0xffffffffffffe000ULL; size = PAGE_SIZE_8K; break; - case 0x1: // 64k + case 0x1: /* 64k */ mask = 0xffffffffffff0000ULL; size = PAGE_SIZE_64K; break; - case 0x2: // 512k + case 0x2: /* 512k */ mask = 0xfffffffffff80000ULL; size = PAGE_SIZE_512K; break; - case 0x3: // 4M + case 0x3: /* 4M */ mask = 0xffffffffffc00000ULL; size = PAGE_SIZE_4M; break; } - tag = spitfire_get_dtlb_tag(i); - if ((virt & mask) == (tag & mask)) { - phys = data & mask & 0x000001fffffff000ULL; - phys |= virt & ~mask; - *p_phys = phys; - *p_data = data & 0xfff; - *p_size = size; - return -1; - } + + virt = spitfire_get_dtlb_tag(i); + virt &= mask; + + /* extract 41bit physical address */ + phys = data & 0x000001fffffff000ULL; + phys &= mask; + + mode = data & 0xfff; + + cb(phys, virt, size, mode); } } - - return 0; }
/* @@ -137,18 +118,21 @@ spitfire_translate(unsigned long virt, u static void mmu_translate(void) { - unsigned long virt, phys, data, size; + ucell virt, phys, mode;
virt = POP();
- if (spitfire_translate(virt, &phys, &data, &size)) { - PUSH(phys & 0xffffffff); - PUSH(phys >> 32); - PUSH(data); - PUSH(-1); - return; + phys = ofmem_translate(virt, &mode); + + if (phys != -1UL) { + PUSH(phys & 0xffffffff); + PUSH(phys >> 32); + PUSH(mode); + PUSH(-1); + } + else { + PUSH(0); } - PUSH(0); }
static void @@ -218,13 +202,15 @@ itlb_load(void) }
static void -map_pages(unsigned long virt, unsigned long size, unsigned long phys, - unsigned long mode) +map_pages(unsigned long phys, unsigned long virt, + unsigned long size, unsigned long mode) { - unsigned long tte_data, currsize; + unsigned long tte_data, currsize;
- size = (size + PAGE_MASK_8K) & ~PAGE_MASK_8K; - while (size >= PAGE_SIZE_8K) { + /* aligned to 8k page */ + size = (size + PAGE_MASK_8K) & ~PAGE_MASK_8K; + + while (size > 0) { currsize = size; if (currsize >= PAGE_SIZE_4M && (virt & PAGE_MASK_4M) == 0 && @@ -248,8 +234,9 @@ map_pages(unsigned long virt, unsigned l
tte_data |= phys | mode | SPITFIRE_TTE_VALID;
- dtlb_load2(virt, tte_data); itlb_load2(virt, tte_data); + dtlb_load2(virt, tte_data); + size -= currsize; phys += currsize; virt += currsize; @@ -268,7 +255,7 @@ void ofmem_map_pages(ucell phys, ucell v static void mmu_map(void) { - unsigned long virt, size, mode, phys; + ucell virt, size, mode, phys;
mode = POP(); size = POP(); @@ -276,7 +263,8 @@ mmu_map(void) phys = POP(); phys <<= 32; phys |= POP(); - map_pages(virt, size, phys, mode); + + ofmem_map(phys, virt, size, mode); }
static void @@ -294,22 +282,19 @@ dtlb_demap(unsigned long vaddr) }
static void -unmap_pages(unsigned long virt, unsigned long size) +unmap_pages(ucell virt, ucell size) { - unsigned long phys, data; + ucell va;
- unsigned long currsize; + /* align address to 8k */ + virt &= ~PAGE_MASK_8K;
- // align size + /* align size to 8k */ size = (size + PAGE_MASK_8K) & ~PAGE_MASK_8K;
- while (spitfire_translate(virt, &phys, &data, &currsize)) { - - itlb_demap(virt & ~0x1fffULL); - dtlb_demap(virt & ~0x1fffULL); - - size -= currsize; - virt += currsize; + for (va = virt; va < virt + size; va += PAGE_SIZE_8K) { + itlb_demap(va); + dtlb_demap(va); } }
@@ -325,11 +310,11 @@ void ofmem_unmap_pages(ucell virt, ucell static void mmu_unmap(void) { - unsigned long virt, size; + ucell virt, size;
size = POP(); virt = POP(); - unmap_pages(virt, size); + ofmem_unmap(virt, size); }
/* @@ -339,13 +324,23 @@ mmu_unmap(void) static void mmu_claim(void) { - unsigned long virt, size, align; + ucell virt=-1UL, size, align;
align = POP(); size = POP(); - virt = POP(); - printk("claim virt = %lx size = %lx align = %lx\n", virt, size, align); - PUSH(virt); // XXX + if (!align) { + virt = POP(); + } + + printk("claim virt=" FMT_ucellx " size=" FMT_ucellx " align=" FMT_ucellx + "\n", + virt, size, align); + + virt = ofmem_claim_virt(virt, size, align); + + printk("claimed virt=" FMT_ucellx "\n", virt); + + PUSH(virt); }
/* @@ -355,14 +350,63 @@ mmu_claim(void) static void mmu_release(void) { - unsigned long virt, size; + ucell virt, size;
size = POP(); virt = POP(); - printk("release virt = %lx size = %lx\n", virt, size); - // XXX + printk("release virt=" FMT_ucellx " size=" FMT_ucellx "\n", virt, size); + + ofmem_release(virt, size); +} + +/* ( phys size align --- base ) */ +static void +mem_claim( void ) +{ + ucell phys=-1UL, size, align; + + align = POP(); + size = POP(); + if (!align) { + phys = POP(); + phys <<= 32; + phys |= POP(); + } + + printk("mem_claim phys=" FMT_ucellx " size=" FMT_ucellx + " align=" FMT_ucellx "\n", + phys, size, align); + + phys = ofmem_claim_phys(phys, size, align); + + printk("ofmem_claim_phys result phys=" FMT_ucellx "\n", phys); + + ofmem_map(phys, phys, size, -1); + + PUSH(phys >> 32); + PUSH(phys & 0xffffffffUL); +} + +/* ( phys size --- ) */ +static void +mem_release( void ) +{ + ucell phys, size; + + size = POP(); + phys = POP(); + printk("release virt=" FMT_ucellx " size=" FMT_ucellx "\n", phys, size); + + ofmem_release(phys, size); }
+DECLARE_NODE(memory, INSTALL_OPEN, 0, "/memory"); + +NODE_METHODS( memory ) = { + { "claim", mem_claim }, + { "release", mem_release }, +}; + DECLARE_UNNAMED_NODE(mmu, INSTALL_OPEN, 0);
NODE_METHODS(mmu) = { @@ -381,7 +425,10 @@ void ob_mmu_init(const char *cpuname, ui { char nodebuff[256];
- // MMU node + /* memory node */ + REGISTER_NODE_METHODS(memory, "/memory"); + + /* MMU node */ snprintf(nodebuff, sizeof(nodebuff), "/%s", cpuname); push_str(nodebuff); fword("find-device"); @@ -397,6 +444,8 @@ void ob_mmu_init(const char *cpuname, ui
REGISTER_NODE_METHODS(mmu, nodebuff);
+ ofmem_register(find_dev("/memory"), find_dev("/virtual-memory")); + push_str("/chosen"); fword("find-device");
@@ -409,7 +458,7 @@ void ob_mmu_init(const char *cpuname, ui push_str("/memory"); fword("find-device");
- // All memory: 0 to RAM_size + /* All memory: 0 to RAM_size */ PUSH(0); fword("encode-int"); PUSH(0); @@ -424,108 +473,6 @@ void ob_mmu_init(const char *cpuname, ui push_str("reg"); fword("property");
- // Available memory: 0 to va2pa(_start) - PUSH(0); - fword("encode-int"); - PUSH(0); - fword("encode-int"); - fword("encode+"); - PUSH((va2pa((unsigned long)&_data) - 8192) >> 32); - fword("encode-int"); - fword("encode+"); - PUSH((va2pa((unsigned long)&_data) - 8192) & 0xffffffff); - fword("encode-int"); - fword("encode+"); - push_str("available"); - fword("property"); - - // XXX - // Translations - push_str("/virtual-memory"); - fword("find-device"); - - // 0 to 16M: 1:1 - PUSH(0); - fword("encode-int"); - PUSH(0); - fword("encode-int"); - fword("encode+"); - PUSH(0); - fword("encode-int"); - fword("encode+"); - PUSH(16 * 1024 * 1024); - fword("encode-int"); - fword("encode+"); - PUSH(0x80000000); - fword("encode-int"); - fword("encode+"); - PUSH(0x00000036); - fword("encode-int"); - fword("encode+"); - - // _start to _data: ROM used - PUSH(0); - fword("encode-int"); - fword("encode+"); - PUSH((unsigned long)&_start); - fword("encode-int"); - fword("encode+"); - PUSH(0); - fword("encode-int"); - fword("encode+"); - PUSH((unsigned long)&_data - (unsigned long)&_start); - fword("encode-int"); - fword("encode+"); - PUSH(0x800001ff); - fword("encode-int"); - fword("encode+"); - PUSH(0xf0000074); - fword("encode-int"); - fword("encode+"); - - // _data to _end: end of RAM - PUSH(0); - fword("encode-int"); - fword("encode+"); - PUSH((unsigned long)&_data); - fword("encode-int"); - fword("encode+"); - PUSH(0); - fword("encode-int"); - fword("encode+"); - PUSH((unsigned long)&_data - (unsigned long)&_start); - fword("encode-int"); - fword("encode+"); - PUSH(((va2pa((unsigned long)&_data) - 8192) >> 32) | 0x80000000); - fword("encode-int"); - fword("encode+"); - PUSH(((va2pa((unsigned long)&_data) - 8192) & 0xffffffff) | 0x36); - fword("encode-int"); - fword("encode+"); - - // VGA buffer (128k): 1:1 - PUSH(0x1ff); - fword("encode-int"); - fword("encode+"); - PUSH(0x004a0000); - fword("encode-int"); - fword("encode+"); - PUSH(0); - fword("encode-int"); - fword("encode+"); - PUSH(128 * 1024); - fword("encode-int"); - fword("encode+"); - PUSH(0x800001ff); - fword("encode-int"); - fword("encode+"); - PUSH(0x004a0076); - fword("encode-int"); - fword("encode+"); - - push_str("translations"); - fword("property"); - push_str("/openprom/client-services"); fword("find-device"); bind_func("claim", mmu_claim); Index: openbios-devel/arch/sparc64/openbios.c =================================================================== --- openbios-devel.orig/arch/sparc64/openbios.c +++ openbios-devel/arch/sparc64/openbios.c @@ -20,6 +20,7 @@ #define NO_QEMU_PROTOS #include "openbios/fw_cfg.h" #include "video_subr.h" +#include "ofmem.h"
#define UUID_FMT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
@@ -495,6 +496,8 @@ int openbios(void) printk("OpenBIOS for Sparc64\n"); #endif
+ ofmem_init(); + collect_sys_info(&sys_info);
dict = malloc(DICTIONARY_SIZE); Index: openbios-devel/arch/sparc64/tree.fs =================================================================== --- openbios-devel.orig/arch/sparc64/tree.fs +++ openbios-devel/arch/sparc64/tree.fs @@ -27,11 +27,12 @@
new-device " memory" device-name + " memory" device-type external : open true ; : close ; \ claim ( phys size align -- base ) - : claim 2drop ; +\ : claim 2drop ; \ release ( phys size -- ) finish-device
@@ -41,7 +42,7 @@ new-device : open true ; : close ; \ claim ( phys size align -- base ) - : claim 2drop ; +\ : claim 2drop ; \ release ( phys size -- ) finish-device
Index: openbios-devel/arch/sparc64/vectors.S =================================================================== --- openbios-devel.orig/arch/sparc64/vectors.S +++ openbios-devel/arch/sparc64/vectors.S @@ -101,6 +101,8 @@ trap_table: ba bug; mov lvl, %g1; nop; nop; nop; nop; nop; nop; #define BTRAPTL1(lvl) BTRAP(lvl) #define BTRAPS(x) BTRAP(x) BTRAP(x+1) BTRAP(x+2) BTRAP(x+3) BTRAP(x+4) BTRAP(x+5) BTRAP(x+6) BTRAP(x+7) +#define BTRAPS4(x) BTRAP(x) BTRAP(x+1) BTRAP(x+2) BTRAP(x+3) +#define TRAP_HANDLER(routine) ba routine; nop; nop; nop; nop; nop; nop; nop;
#define STACK_BIAS 2047 .globl sparc64_ttable_tl0, sparc64_ttable_tl1 @@ -131,7 +133,16 @@ tl0_irq15: TRAP_IRQ(handler_irq, 15) BTRAPS(0x40) BTRAPS(0x48) #endif BTRAPS(0x50) BTRAPS(0x58) - BTRAPS(0x60) BTRAPS(0x68) + BTRAPS4(0x60) + TRAP_HANDLER(reload_IMMU_tlb) ! 0x64 : instruction_access_MMU_miss + TRAP_HANDLER(reload_IMMU_tlb) ! 0x65 : instruction_access_MMU_miss + TRAP_HANDLER(reload_IMMU_tlb) ! 0x66 : instruction_access_MMU_miss + TRAP_HANDLER(reload_IMMU_tlb) ! 0x67 : instruction_access_MMU_miss + TRAP_HANDLER(reload_DMMU_tlb) ! 0x68 : data_access_MMU_miss + TRAP_HANDLER(reload_DMMU_tlb) ! 0x69 : data_access_MMU_miss + TRAP_HANDLER(reload_DMMU_tlb) ! 0x6A : data_access_MMU_miss + TRAP_HANDLER(reload_DMMU_tlb) ! 0x6B : data_access_MMU_miss + BTRAPS4(0x6C) ! data_access_protection BTRAPS(0x70) BTRAPS(0x78) tl0_s0n: SPILL_WINDOW tl0_s1n: SPILL_WINDOW @@ -206,7 +217,16 @@ tl1_irq15: TRAP_IRQ(handler_irq, 15) BTRAPS(0x40) BTRAPS(0x48) #endif BTRAPS(0x50) BTRAPS(0x58) - BTRAPS(0x60) BTRAPS(0x68) + BTRAPS4(0x60) + TRAP_HANDLER(reload_IMMU_tlb) ! 0x64 : instruction_access_MMU_miss + TRAP_HANDLER(reload_IMMU_tlb) ! 0x65 : instruction_access_MMU_miss + TRAP_HANDLER(reload_IMMU_tlb) ! 0x66 : instruction_access_MMU_miss + TRAP_HANDLER(reload_IMMU_tlb) ! 0x67 : instruction_access_MMU_miss + TRAP_HANDLER(reload_DMMU_tlb) ! 0x68 : data_access_MMU_miss + TRAP_HANDLER(reload_DMMU_tlb) ! 0x69 : data_access_MMU_miss + TRAP_HANDLER(reload_DMMU_tlb) ! 0x6A : data_access_MMU_miss + TRAP_HANDLER(reload_DMMU_tlb) ! 0x6B : data_access_MMU_miss + BTRAPS4(0x6C) ! data_access_protection BTRAPS(0x70) BTRAPS(0x78) tl1_s0n: SPILL_WINDOW tl1_s1n: SPILL_WINDOW @@ -300,6 +320,86 @@ fill_32bit: restored retry
+ .globl reload_DMMU_tlb, reload_IMMU_tlb + +reload_DMMU_tlb: + mov 6 << 3, %g2 ! va = fault virtual address + ldxa [%g2] ASI_DMMU, %g1 ! from tag access register + + srlx %g1, 13, %g1 ! %g1 = va rounded to 8k page + sllx %g1, 13, %g1 ! + + setx g_ofmem_translations, %g7, %g3 + ldx [%g3], %g3 ! translation_t* t = *g_ofmem_translations +dmmu_next_trans: + ldx [%g3], %g3 + brz %g3, bug ! NULL pointer + nop + ldx [%g3+0x08], %g4 ! t->virt + sub %g1, %g4, %g7 ! %g7 offset = va - t->virt + brlz %g7, dmmu_next_trans ! va < t->virt ? + nop + ldx [%g3+0x10], %g4 ! t->size + sub %g7, %g4, %g4 ! va >= t->virt - t->size ? + brgez %g4, dmmu_next_trans + nop + + ! install 8k tlb entry + + ldx [%g3+0x18], %g4 ! t->phys + add %g4, %g7, %g4 ! %g4 page physical address = t->phys + offset + ldx [%g3+0x20], %g5 ! t->mode + + set 0x80000000, %g2 ! valid tte, 8k size + sllx %g2, 32, %g2 + or %g2, %g5, %g2 ! mix in translation mode + or %g2, %g4, %g3 ! mix in phys addr mode + + mov 6 << 3, %g2 ! page virtual address + stxa %g1, [%g2] ASI_DMMU ! + stxa %g3, [%g0] ASI_DTLB_DATA_IN + + retry + +reload_IMMU_tlb: + mov 6 << 3, %g2 ! va = fault virtual address + ldxa [%g2] ASI_IMMU, %g1 ! from tag access register + + srlx %g1, 13, %g1 ! %g1 = va rounded to 8k page + sllx %g1, 13, %g1 ! + + setx g_ofmem_translations, %g7, %g3 + ldx [%g3], %g3 ! translation_t* t = *g_ofmem_translations +immu_next_trans: + ldx [%g3], %g3 + brz %g3, bug ! NULL pointer + nop + ldx [%g3+0x08], %g4 ! t->virt + sub %g1, %g4, %g7 ! %g7 offset = va - t->virt + brlz %g7, immu_next_trans ! va < t->virt ? + nop + ldx [%g3+0x10], %g4 ! t->size + sub %g7, %g4, %g4 ! va >= t->virt - t->size ? + brgez %g4, immu_next_trans + nop + + ! install 8k tlb entry + + ldx [%g3+0x18], %g4 ! t->phys + add %g4, %g7, %g4 ! %g4 page physical address = t->phys + offset + ldx [%g3+0x20], %g5 ! t->mode + + set 0x80000000, %g2 ! valid tte, 8k size + sllx %g2, 32, %g2 + or %g2, %g5, %g2 ! mix in translation mode + or %g2, %g4, %g3 ! mix in phys addr mode + + mov 6 << 3, %g2 ! page virtual address + stxa %g1, [%g2] ASI_IMMU ! + stxa %g3, [%g0] ASI_ITLB_DATA_IN + + retry + __divide_error: bug: /* Dump the exception and its context */
Igor Kovalenko wrote:
This patch series implement OF memory manager.
Hi Igor,
This looks like a great patchset - the lack of the OF memory manager for Sparc64 was preventing me from working further on OpenBIOS to get it to try and load a Solaris kernel under Qemu :)
I haven't had as much spare time to work on this as I would have hoped, however I've been working on adding some debug support to OpenBIOS to try and help me trace through various parts of the Fcode (with limited success). Once I get something working, I'll try out your patches and see if I can get the kernel loading from disk...
ATB,
Mark.
On Thu, Jul 30, 2009 at 8:23 PM, Mark Cave-Aylandmark.cave-ayland@siriusit.co.uk wrote:
Igor Kovalenko wrote:
This patch series implement OF memory manager.
Hi Igor,
This looks like a great patchset - the lack of the OF memory manager for Sparc64 was preventing me from working further on OpenBIOS to get it to try and load a Solaris kernel under Qemu :)
Cool :)
If you have good document describing what solaris boot loader expects from open firmware, that would really help. I have of1275.pdf and it's 32bit and 64bit bindings, and these do not seem to cover what "convey other information to client image" really means.
I haven't had as much spare time to work on this as I would have hoped, however I've been working on adding some debug support to OpenBIOS to try and help me trace through various parts of the Fcode (with limited success). Once I get something working, I'll try out your patches and see if I can get the kernel loading from disk...
There are still issues with qemu emulation code, but we are making some progress :) My plan is to first have ultrasparcIIi qemu emulation booting linux to userspace using openbios sparc64 prom.
On Thu, Jul 30, 2009 at 11:09 AM, Igor Kovalenkoigor.v.kovalenko@gmail.com wrote:
Hi!
This patch series implement OF memory manager.
Thanks, applied all.
On Fri, Jul 31, 2009 at 3:17 PM, Blue Swirlblauwirbel@gmail.com wrote:
On Thu, Jul 30, 2009 at 11:09 AM, Igor Kovalenkoigor.v.kovalenko@gmail.com wrote:
Hi!
This patch series implement OF memory manager.
Thanks, applied all.
Thanks! I will try to factor out common part for ppc and sparc64.