ppc: Set up SLBs for ppc64
[openbios/afaerber.git] / arch / ppc / qemu / ofmem.c
blobe87162310c6d33634d6864b7186ef3422bc9a411
1 /*
2 * Creation Date: <1999/11/07 19:02:11 samuel>
3 * Time-stamp: <2004/01/07 19:42:36 samuel>
5 * <ofmem.c>
7 * OF Memory manager
9 * Copyright (C) 1999-2004 Samuel Rydh (samuel@ibrium.se)
10 * Copyright (C) 2004 Stefan Reinauer
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation
18 #include "config.h"
19 #include "libopenbios/bindings.h"
20 #include "libc/string.h"
21 #include "libopenbios/ofmem.h"
22 #include "kernel.h"
23 #include "mmutypes.h"
24 #include "asm/processor.h"
26 #define BIT(n) (1U<<(31-(n)))
28 /* called from assembly */
29 extern void dsi_exception( void );
30 extern void isi_exception( void );
31 extern void setup_mmu( unsigned long code_base );
34 * From Apple's BootX source comments:
36 * 96 MB map (currently unused - 4363357 tracks re-adoption)
37 * 00000000 - 00003FFF : Exception Vectors
38 * 00004000 - 03FFFFFF : Kernel Image, Boot Struct and Drivers (~64 MB)
39 * 04000000 - 04FFFFFF : File Load Area (16 MB) [80 MB]
40 * 05000000 - 053FFFFF : FS Cache (4 MB) [84 MB]
41 * 05400000 - 055FFFFF : Malloc Zone (2 MB) [86 MB]
42 * 05600000 - 057FFFFF : BootX Image (2 MB) [88 MB]
43 * 05800000 - 05FFFFFF : Unused/OF (8 MB) [96 MB]
47 #define FREE_BASE 0x00004000
48 #define OF_CODE_START 0xfff00000UL
49 #define IO_BASE 0x80000000
51 #define HASH_SIZE (2 << 15)
52 #define OFMEM_SIZE (2 * 1024 * 1024)
54 #define SEGR_USER BIT(2)
55 #define SEGR_BASE 0x0400
57 static inline unsigned long
58 get_hash_base( void )
60 unsigned long sdr1;
62 asm volatile("mfsdr1 %0" : "=r" (sdr1) );
64 return (sdr1 & 0xffff0000);
67 static inline unsigned long
68 get_hash_size( void )
70 unsigned long sdr1;
72 asm volatile("mfsdr1 %0" : "=r" (sdr1) );
74 return ((sdr1 << 16) | 0x0000ffff) + 1;
77 static inline unsigned long
78 get_rom_base( void )
80 ofmem_t *ofmem = ofmem_arch_get_private();
81 return ofmem->ramsize - 0x00100000;
84 unsigned long
85 get_ram_top( void )
87 return get_hash_base() - (32 + 64 + 64) * 1024 - OFMEM_SIZE;
90 unsigned long
91 get_ram_bottom( void )
93 return (unsigned long)FREE_BASE;
96 static ucell get_heap_top( void )
98 return get_hash_base() - (32 + 64 + 64) * 1024;
101 static inline size_t ALIGN_SIZE(size_t x, size_t a)
103 return (x + a - 1) & ~(a-1);
106 ofmem_t* ofmem_arch_get_private(void)
108 return (ofmem_t*)cell2pointer(get_heap_top() - OFMEM_SIZE);
111 void* ofmem_arch_get_malloc_base(void)
113 return (char*)ofmem_arch_get_private() + ALIGN_SIZE(sizeof(ofmem_t), 4);
116 ucell ofmem_arch_get_heap_top(void)
118 return get_heap_top();
121 ucell ofmem_arch_get_virt_top(void)
123 return IO_BASE;
126 void ofmem_arch_unmap_pages(ucell virt, ucell size)
128 /* kill page mappings in provided range */
131 void ofmem_arch_early_map_pages(ucell phys, ucell virt, ucell size, ucell mode)
133 /* none yet */
136 retain_t *ofmem_arch_get_retained(void)
138 /* not implemented */
139 return NULL;
142 int ofmem_arch_get_translation_entry_size(void)
144 /* Return size of a single MMU package translation property entry in cells */
145 return 4;
148 void ofmem_arch_create_translation_entry(ucell *transentry, translation_t *t)
150 /* Generate translation property entry for PPC. According to the
151 platform bindings for PPC (http://playground.sun.com/1275/bindings/ppc/release/ppc-2_1.html#REF34579)
152 a translation property entry has the following layout:
154 virtual address
155 length
156 physical address
157 mode
160 transentry[0] = t->virt;
161 transentry[1] = t->size;
162 transentry[2] = t->phys;
163 transentry[3] = t->mode;
166 /************************************************************************/
167 /* OF private allocations */
168 /************************************************************************/
170 void *
171 malloc( int size )
173 return ofmem_malloc(size);
176 void
177 free( void *ptr )
179 ofmem_free(ptr);
182 void *
183 realloc( void *ptr, size_t size )
185 return ofmem_realloc(ptr, size);
189 /************************************************************************/
190 /* misc */
191 /************************************************************************/
193 ucell ofmem_arch_default_translation_mode( ucell phys )
195 /* XXX: Guard bit not set as it should! */
196 if( phys < IO_BASE )
197 return 0x02; /*0xa*/ /* wim GxPp */
198 return 0x6a; /* WIm GxPp, I/O */
202 /************************************************************************/
203 /* page fault handler */
204 /************************************************************************/
206 static ucell
207 ea_to_phys( ucell ea, ucell *mode )
209 ucell phys;
211 if (ea >= OF_CODE_START) {
212 /* ROM into RAM */
213 ea -= OF_CODE_START;
214 phys = get_rom_base() + ea;
215 *mode = 0x02;
216 return phys;
219 phys = ofmem_translate(ea, mode);
220 if( phys == -1 ) {
221 phys = ea;
222 *mode = ofmem_arch_default_translation_mode( phys );
224 /* print_virt_range(); */
225 /* print_phys_range(); */
226 /* print_trans(); */
228 return phys;
231 static void
232 hash_page_64( ucell ea, ucell phys, ucell mode )
234 static int next_grab_slot=0;
235 uint64_t vsid_mask, page_mask, pgidx, hash;
236 uint64_t htab_mask, mask, avpn;
237 unsigned long pgaddr;
238 int i, found;
239 unsigned int vsid, vsid_sh, sdr, sdr_sh, sdr_mask;
240 mPTE_64_t *pp;
242 vsid = (ea >> 28) + SEGR_BASE;
243 vsid_sh = 7;
244 vsid_mask = 0x00003FFFFFFFFF80ULL;
245 asm ( "mfsdr1 %0" : "=r" (sdr) );
246 sdr_sh = 18;
247 sdr_mask = 0x3FF80;
248 page_mask = 0x0FFFFFFF; // XXX correct?
249 pgidx = (ea & page_mask) >> PAGE_SHIFT;
250 avpn = (vsid << 12) | ((pgidx >> 4) & 0x0F80);;
252 hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask;
253 htab_mask = 0x0FFFFFFF >> (28 - (sdr & 0x1F));
254 mask = (htab_mask << sdr_sh) | sdr_mask;
255 pgaddr = sdr | (hash & mask);
256 pp = (mPTE_64_t *)pgaddr;
258 /* replace old translation */
259 for( found=0, i=0; !found && i<8; i++ )
260 if( pp[i].avpn == avpn )
261 found=1;
263 /* otherwise use a free slot */
264 for( i=0; !found && i<8; i++ )
265 if( !pp[i].v )
266 found=1;
268 /* out of slots, just evict one */
269 if( !found ) {
270 i = next_grab_slot + 1;
271 next_grab_slot = (next_grab_slot + 1) % 8;
273 i--;
275 mPTE_64_t p = {
276 // .avpn_low = avpn,
277 .avpn = avpn >> 7,
278 .h = 0,
279 .v = 1,
281 .rpn = (phys & ~0xfff) >> 12,
282 .r = mode & (1 << 8) ? 1 : 0,
283 .c = mode & (1 << 7) ? 1 : 0,
284 .w = mode & (1 << 6) ? 1 : 0,
285 .i = mode & (1 << 5) ? 1 : 0,
286 .m = mode & (1 << 4) ? 1 : 0,
287 .g = mode & (1 << 3) ? 1 : 0,
288 .n = mode & (1 << 2) ? 1 : 0,
289 .pp = mode & 3,
291 pp[i] = p;
294 asm volatile( "tlbie %0" :: "r"(ea) );
297 static void
298 hash_page_32( ucell ea, ucell phys, ucell mode )
300 static int next_grab_slot=0;
301 unsigned long *upte, cmp, hash1;
302 int i, vsid, found;
303 mPTE_t *pp;
305 vsid = (ea>>28) + SEGR_BASE;
306 cmp = BIT(0) | (vsid << 7) | ((ea & 0x0fffffff) >> 22);
308 hash1 = vsid;
309 hash1 ^= (ea >> 12) & 0xffff;
310 hash1 &= (get_hash_size() - 1) >> 6;
312 pp = (mPTE_t*)(get_hash_base() + (hash1 << 6));
313 upte = (unsigned long*)pp;
315 /* replace old translation */
316 for( found=0, i=0; !found && i<8; i++ )
317 if( cmp == upte[i*2] )
318 found=1;
320 /* otherwise use a free slot */
321 for( i=0; !found && i<8; i++ )
322 if( !pp[i].v )
323 found=1;
325 /* out of slots, just evict one */
326 if( !found ) {
327 i = next_grab_slot + 1;
328 next_grab_slot = (next_grab_slot + 1) % 8;
330 i--;
331 upte[i*2] = cmp;
332 upte[i*2+1] = (phys & ~0xfff) | mode;
334 asm volatile( "tlbie %0" :: "r"(ea) );
337 static int is_ppc64(void)
339 unsigned int pvr = mfpvr();
340 return ((pvr >= 0x330000) && (pvr < 0x70330000));
343 static void hash_page( unsigned long ea, unsigned long phys, ucell mode )
345 if ( is_ppc64() )
346 hash_page_64(ea, phys, mode);
347 else
348 hash_page_32(ea, phys, mode);
351 void
352 dsi_exception( void )
354 unsigned long dar, dsisr;
355 ucell mode;
356 ucell phys;
358 asm volatile("mfdar %0" : "=r" (dar) : );
359 asm volatile("mfdsisr %0" : "=r" (dsisr) : );
361 phys = ea_to_phys(dar, &mode);
362 hash_page( dar, phys, mode );
365 void
366 isi_exception( void )
368 unsigned long nip, srr1;
369 ucell mode;
370 ucell phys;
372 asm volatile("mfsrr0 %0" : "=r" (nip) : );
373 asm volatile("mfsrr1 %0" : "=r" (srr1) : );
375 phys = ea_to_phys(nip, &mode);
376 hash_page( nip, phys, mode );
380 /************************************************************************/
381 /* init / cleanup */
382 /************************************************************************/
384 void
385 setup_mmu( unsigned long ramsize )
387 ofmem_t *ofmem;
388 unsigned long sdr1;
389 #ifndef __powerpc64__
390 unsigned long sr_base;
391 #endif
392 unsigned long hash_base;
393 unsigned long hash_mask = 0xfff00000; /* alignment for ppc64 */
394 int i;
396 /* SDR1: Storage Description Register 1 */
398 hash_base = (ramsize - 0x00100000 - HASH_SIZE) & hash_mask;
399 memset((void *)hash_base, 0, HASH_SIZE);
400 sdr1 = hash_base | ((HASH_SIZE-1) >> 16);
401 asm volatile("mtsdr1 %0" :: "r" (sdr1) );
403 #ifdef __powerpc64__
405 /* Segment Lookaside Buffer */
407 slbia(); /* Invalidate all SLBs except SLB 0 */
408 for (i = 0; i < 16; i++) {
409 unsigned long rs = ((0x400 + i) << 12) | (0x10 << 7);
410 unsigned long rb = ((unsigned long)i << 28) | (1 << 27) | i;
411 slbmte(rs, rb);
414 #else
416 /* Segment Register */
418 sr_base = SEGR_USER | SEGR_BASE ;
419 for( i=0; i<16; i++ ) {
420 int j = i << 28;
421 asm volatile("mtsrin %0,%1" :: "r" (sr_base + i), "r" (j) );
424 #endif
426 ofmem = ofmem_arch_get_private();
427 memset(ofmem, 0, sizeof(ofmem_t));
428 ofmem->ramsize = ramsize;
430 memcpy((void *)get_rom_base(), (void *)OF_CODE_START, 0x00100000);
432 /* Enable MMU */
434 mtmsr(mfmsr() | MSR_IR | MSR_DR);
437 void
438 ofmem_init( void )
440 ofmem_t *ofmem = ofmem_arch_get_private();
442 ofmem_claim_phys(0, get_ram_bottom(), 0);
443 ofmem_claim_virt(0, get_ram_bottom(), 0);
444 ofmem_map( 0, 0, get_ram_bottom(), 0 );
446 ofmem_claim_phys(get_ram_top(), ofmem->ramsize - get_ram_top(), 0);
447 ofmem_claim_virt(get_ram_top(), ofmem->ramsize - get_ram_top(), 0);
448 ofmem_map( get_ram_top(), get_ram_top(), ofmem->ramsize - get_ram_top(), 0);