2 * Creation Date: <1999/11/07 19:02:11 samuel>
3 * Time-stamp: <2004/01/07 19:42:36 samuel>
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
19 #include "libopenbios/bindings.h"
20 #include "libc/string.h"
21 #include "libopenbios/ofmem.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
62 asm volatile("mfsdr1 %0" : "=r" (sdr1
) );
64 return (sdr1
& 0xffff0000);
67 static inline unsigned long
72 asm volatile("mfsdr1 %0" : "=r" (sdr1
) );
74 return ((sdr1
<< 16) | 0x0000ffff) + 1;
77 static inline unsigned long
80 ofmem_t
*ofmem
= ofmem_arch_get_private();
81 return ofmem
->ramsize
- 0x00100000;
87 return get_hash_base() - (32 + 64 + 64) * 1024 - OFMEM_SIZE
;
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)
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
)
136 retain_t
*ofmem_arch_get_retained(void)
138 /* not implemented */
142 int ofmem_arch_get_translation_entry_size(void)
144 /* Return size of a single MMU package translation property entry in cells */
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:
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 /************************************************************************/
173 return ofmem_malloc(size
);
183 realloc( void *ptr
, size_t size
)
185 return ofmem_realloc(ptr
, size
);
189 /************************************************************************/
191 /************************************************************************/
193 ucell
ofmem_arch_default_translation_mode( ucell phys
)
195 /* XXX: Guard bit not set as it should! */
197 return 0x02; /*0xa*/ /* wim GxPp */
198 return 0x6a; /* WIm GxPp, I/O */
202 /************************************************************************/
203 /* page fault handler */
204 /************************************************************************/
207 ea_to_phys( ucell ea
, ucell
*mode
)
211 if (ea
>= OF_CODE_START
) {
214 phys
= get_rom_base() + ea
;
219 phys
= ofmem_translate(ea
, mode
);
222 *mode
= ofmem_arch_default_translation_mode( phys
);
224 /* print_virt_range(); */
225 /* print_phys_range(); */
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
;
239 unsigned int vsid
, vsid_sh
, sdr
, sdr_sh
, sdr_mask
;
242 vsid
= (ea
>> 28) + SEGR_BASE
;
244 vsid_mask
= 0x00003FFFFFFFFF80ULL
;
245 asm ( "mfsdr1 %0" : "=r" (sdr
) );
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
)
263 /* otherwise use a free slot */
264 for( i
=0; !found
&& i
<8; i
++ )
268 /* out of slots, just evict one */
270 i
= next_grab_slot
+ 1;
271 next_grab_slot
= (next_grab_slot
+ 1) % 8;
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,
294 asm volatile( "tlbie %0" :: "r"(ea
) );
298 hash_page_32( ucell ea
, ucell phys
, ucell mode
)
300 static int next_grab_slot
=0;
301 unsigned long *upte
, cmp
, hash1
;
305 vsid
= (ea
>>28) + SEGR_BASE
;
306 cmp
= BIT(0) | (vsid
<< 7) | ((ea
& 0x0fffffff) >> 22);
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] )
320 /* otherwise use a free slot */
321 for( i
=0; !found
&& i
<8; i
++ )
325 /* out of slots, just evict one */
327 i
= next_grab_slot
+ 1;
328 next_grab_slot
= (next_grab_slot
+ 1) % 8;
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
)
346 hash_page_64(ea
, phys
, mode
);
348 hash_page_32(ea
, phys
, mode
);
352 dsi_exception( void )
354 unsigned long dar
, dsisr
;
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
);
366 isi_exception( void )
368 unsigned long nip
, srr1
;
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 /************************************************************************/
382 /************************************************************************/
385 setup_mmu( unsigned long ramsize
)
389 #ifndef __powerpc64__
390 unsigned long sr_base
;
392 unsigned long hash_base
;
393 unsigned long hash_mask
= 0xfff00000; /* alignment for ppc64 */
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
) );
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
;
416 /* Segment Register */
418 sr_base
= SEGR_USER
| SEGR_BASE
;
419 for( i
=0; i
<16; i
++ ) {
421 asm volatile("mtsrin %0,%1" :: "r" (sr_base
+ i
), "r" (j
) );
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);
434 mtmsr(mfmsr() | MSR_IR
| MSR_DR
);
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);