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 0x00004000UL
48 #define OF_CODE_START 0xfff00000UL
49 #define OF_CODE_SIZE 0x00100000
50 #define IO_BASE 0x80000000UL
57 #define HASH_SIZE (2 << HASH_BITS)
58 #define OFMEM_SIZE (1 * 1024 * 1024 + 512 * 1024)
60 #define SEGR_USER BIT(2)
61 #define SEGR_BASE 0x0400
63 static inline unsigned long
66 return (mfsdr1() & SDR1_HTABORG_MASK
);
69 static inline unsigned long
72 ofmem_t
*ofmem
= ofmem_arch_get_private();
73 return ofmem
->ramsize
- OF_CODE_SIZE
;
79 return get_hash_base() - (32 + 64 + 64) * 1024 - OFMEM_SIZE
;
88 static unsigned long get_heap_top(void)
90 return get_hash_base() - (32 + 64 + 64) * 1024;
93 static inline size_t ALIGN_SIZE(size_t x
, size_t a
)
95 return (x
+ a
- 1) & ~(a
- 1);
98 ofmem_t
* ofmem_arch_get_private(void)
100 return (ofmem_t
*)cell2pointer(get_heap_top() - OFMEM_SIZE
);
103 void* ofmem_arch_get_malloc_base(void)
105 return (char*)ofmem_arch_get_private() + ALIGN_SIZE(sizeof(ofmem_t
), 4);
108 ucell
ofmem_arch_get_heap_top(void)
110 return get_heap_top();
113 ucell
ofmem_arch_get_virt_top(void)
118 phys_addr_t
ofmem_arch_get_phys_top(void)
120 ofmem_t
*ofmem
= ofmem_arch_get_private();
122 return ofmem
->ramsize
;
125 void ofmem_arch_unmap_pages(ucell virt
, ucell size
)
127 /* kill page mappings in provided range */
130 void ofmem_arch_early_map_pages(phys_addr_t phys
, ucell virt
, ucell size
, ucell mode
)
135 ucell
ofmem_arch_get_iomem_base(void)
137 /* Currently unused */
141 ucell
ofmem_arch_get_iomem_top(void)
143 /* Currently unused */
147 retain_t
*ofmem_arch_get_retained(void)
149 /* not implemented */
153 int ofmem_arch_get_physaddr_cellsize(void)
162 int ofmem_arch_encode_physaddr(ucell
*p
, phys_addr_t value
)
166 p
[n
++] = value
>> 32;
172 /* Return size of a single MMU package translation property entry in cells */
173 int ofmem_arch_get_translation_entry_size(void)
175 return 3 + ofmem_arch_get_physaddr_cellsize();
178 /* Generate translation property entry for PPC.
179 * According to the platform bindings for PPC
180 * (http://playground.sun.com/1275/bindings/ppc/release/ppc-2_1.html#REF34579)
181 * a translation property entry has the following layout:
188 void ofmem_arch_create_translation_entry(ucell
*transentry
, translation_t
*t
)
192 transentry
[i
++] = t
->virt
;
193 transentry
[i
++] = t
->size
;
194 i
+= ofmem_arch_encode_physaddr(&transentry
[i
], t
->phys
);
195 transentry
[i
++] = t
->mode
;
198 /* Return the size of a memory available entry given the phandle in cells */
199 int ofmem_arch_get_available_entry_size(phandle_t ph
)
201 if (ph
== s_phandle_memory
) {
202 return 1 + ofmem_arch_get_physaddr_cellsize();
208 /* Generate memory available property entry for PPC */
209 void ofmem_arch_create_available_entry(phandle_t ph
, ucell
*availentry
, phys_addr_t start
, ucell size
)
213 if (ph
== s_phandle_memory
) {
214 i
+= ofmem_arch_encode_physaddr(availentry
, start
);
216 availentry
[i
++] = start
;
219 availentry
[i
] = size
;
222 /************************************************************************/
223 /* OF private allocations */
224 /************************************************************************/
226 /* Private functions for mapping between physical/virtual addresses */
228 va2pa(unsigned long va
)
230 if (va
>= OF_CODE_START
&& va
< OF_CODE_START
+ OF_CODE_SIZE
) {
231 return (phys_addr_t
)get_rom_base() - OF_CODE_START
+ va
;
233 return (phys_addr_t
)va
;
238 pa2va(phys_addr_t pa
)
240 if ((pa
- get_rom_base() + OF_CODE_START
>= OF_CODE_START
) &&
241 (pa
- get_rom_base() + OF_CODE_START
< OF_CODE_START
+ OF_CODE_SIZE
))
242 return (unsigned long)pa
- get_rom_base() + OF_CODE_START
;
244 return (unsigned long)pa
;
250 return ofmem_malloc(size
);
260 realloc(void *ptr
, size_t size
)
262 return ofmem_realloc(ptr
, size
);
266 /************************************************************************/
268 /************************************************************************/
270 ucell
ofmem_arch_default_translation_mode(phys_addr_t phys
)
272 /* XXX: Guard bit not set as it should! */
274 return 0x02; /*0xa*/ /* wim GxPp */
275 return 0x6a; /* WIm GxPp, I/O */
278 ucell
ofmem_arch_io_translation_mode(phys_addr_t phys
)
280 return 0x6a; /* WIm GxPp, I/O */
283 /************************************************************************/
284 /* page fault handler */
285 /************************************************************************/
288 ea_to_phys(unsigned long ea
, ucell
*mode
)
292 if (ea
>= OF_CODE_START
&& ea
<= 0xffffffffUL
) {
295 phys
= get_rom_base() + ea
;
300 phys
= ofmem_translate(ea
, mode
);
303 *mode
= ofmem_arch_default_translation_mode(phys
);
305 /* print_virt_range(); */
306 /* print_phys_range(); */
313 hash_page_64(unsigned long ea
, phys_addr_t phys
, ucell mode
)
315 static int next_grab_slot
= 0;
316 uint64_t vsid_mask
, page_mask
, pgidx
, hash
;
317 uint64_t htab_mask
, mask
, avpn
;
318 unsigned long pgaddr
;
320 unsigned int vsid
, vsid_sh
, sdr
, sdr_sh
, sdr_mask
;
323 vsid
= (ea
>> 28) + SEGR_BASE
;
325 vsid_mask
= 0x00003FFFFFFFFF80ULL
;
329 page_mask
= 0x0FFFFFFF; // XXX correct?
330 pgidx
= (ea
& page_mask
) >> PAGE_SHIFT
;
331 avpn
= (vsid
<< 12) | ((pgidx
>> 4) & 0x0F80);;
333 hash
= ((vsid
^ pgidx
) << vsid_sh
) & vsid_mask
;
334 htab_mask
= 0x0FFFFFFF >> (28 - (sdr
& 0x1F));
335 mask
= (htab_mask
<< sdr_sh
) | sdr_mask
;
336 pgaddr
= sdr
| (hash
& mask
);
337 pp
= (mPTE_64_t
*)pgaddr
;
339 /* replace old translation */
340 for (found
= 0, i
= 0; !found
&& i
< 8; i
++)
341 if (pp
[i
].avpn
== avpn
)
344 /* otherwise use a free slot */
345 for (i
= 0; !found
&& i
< 8; i
++)
349 /* out of slots, just evict one */
351 i
= next_grab_slot
+ 1;
352 next_grab_slot
= (next_grab_slot
+ 1) % 8;
362 .rpn
= (phys
& ~0xfffUL
) >> 12,
363 .r
= mode
& (1 << 8) ? 1 : 0,
364 .c
= mode
& (1 << 7) ? 1 : 0,
365 .w
= mode
& (1 << 6) ? 1 : 0,
366 .i
= mode
& (1 << 5) ? 1 : 0,
367 .m
= mode
& (1 << 4) ? 1 : 0,
368 .g
= mode
& (1 << 3) ? 1 : 0,
369 .n
= mode
& (1 << 2) ? 1 : 0,
375 asm volatile("tlbie %0" :: "r"(ea
));
379 hash_page_32(unsigned long ea
, phys_addr_t phys
, ucell mode
)
381 #ifndef __powerpc64__
382 static int next_grab_slot
= 0;
383 unsigned long *upte
, cmp
, hash1
;
387 vsid
= (ea
>> 28) + SEGR_BASE
;
388 cmp
= BIT(0) | (vsid
<< 7) | ((ea
& 0x0fffffff) >> 22);
391 hash1
^= (ea
>> 12) & 0xffff;
392 hash1
&= (((mfsdr1() & 0x1ff) << 16) | 0xffff) >> 6;
394 pp
= (mPTE_t
*)(get_hash_base() + (hash1
<< 6));
395 upte
= (unsigned long*)pp
;
397 /* replace old translation */
398 for (found
= 0, i
= 0; !found
&& i
< 8; i
++)
399 if (cmp
== upte
[i
*2])
402 /* otherwise use a free slot */
403 for (i
= 0; !found
&& i
< 8; i
++)
407 /* out of slots, just evict one */
409 i
= next_grab_slot
+ 1;
410 next_grab_slot
= (next_grab_slot
+ 1) % 8;
414 upte
[i
* 2 + 1] = (phys
& ~0xfff) | mode
;
416 asm volatile("tlbie %0" :: "r"(ea
));
420 static int is_ppc64(void)
424 #elif defined(CONFIG_PPC_64BITSUPPORT)
425 unsigned int pvr
= mfpvr();
426 return ((pvr
>= 0x330000) && (pvr
< 0x70330000));
432 /* XXX Remove these ugly constructs when legacy 64-bit support is dropped. */
433 static void hash_page(unsigned long ea
, phys_addr_t phys
, ucell mode
)
436 hash_page_64(ea
, phys
, mode
);
438 hash_page_32(ea
, phys
, mode
);
444 unsigned long dar
, dsisr
;
448 asm volatile("mfdar %0" : "=r" (dar
) : );
449 asm volatile("mfdsisr %0" : "=r" (dsisr
) : );
451 phys
= ea_to_phys(dar
, &mode
);
452 hash_page(dar
, phys
, mode
);
458 unsigned long nip
, srr1
;
462 asm volatile("mfsrr0 %0" : "=r" (nip
) : );
463 asm volatile("mfsrr1 %0" : "=r" (srr1
) : );
465 phys
= ea_to_phys(nip
, &mode
);
466 hash_page(nip
, phys
, mode
);
470 /************************************************************************/
472 /************************************************************************/
475 setup_mmu(unsigned long ramsize
)
478 #ifndef __powerpc64__
479 unsigned long sr_base
;
481 unsigned long hash_base
;
482 unsigned long hash_mask
= ~0x000fffffUL
; /* alignment for ppc64 */
485 /* SDR1: Storage Description Register 1 */
487 hash_base
= (ramsize
- OF_CODE_SIZE
- HASH_SIZE
) & hash_mask
;
488 memset((void *)hash_base
, 0, HASH_SIZE
);
490 mtsdr1(hash_base
| MAX(HASH_BITS
- 18, 0));
492 mtsdr1(hash_base
| ((HASH_SIZE
- 1) >> 16));
496 /* Segment Lookaside Buffer */
498 slbia(); /* Invalidate all SLBs except SLB 0 */
499 for (i
= 0; i
< 16; i
++) {
500 unsigned long rs
= ((0x400 + i
) << 12) | (0x10 << 7);
501 unsigned long rb
= ((unsigned long)i
<< 28) | (1 << 27) | i
;
507 /* Segment Register */
509 sr_base
= SEGR_USER
| SEGR_BASE
;
510 for (i
= 0; i
< 16; i
++) {
512 asm volatile("mtsrin %0,%1" :: "r" (sr_base
+ i
), "r" (j
));
517 ofmem
= ofmem_arch_get_private();
518 memset(ofmem
, 0, sizeof(ofmem_t
));
519 ofmem
->ramsize
= ramsize
;
521 memcpy((void *)get_rom_base(), (void *)OF_CODE_START
, OF_CODE_SIZE
);
525 mtmsr(mfmsr() | MSR_IR
| MSR_DR
);
531 ofmem_t
*ofmem
= ofmem_arch_get_private();
533 ofmem_claim_phys(0, get_ram_bottom(), 0);
534 ofmem_claim_virt(0, get_ram_bottom(), 0);
535 ofmem_map(0, 0, get_ram_bottom(), 0);
537 ofmem_claim_phys(get_ram_top(), ofmem
->ramsize
- get_ram_top(), 0);
538 ofmem_claim_virt(get_ram_top(), ofmem
->ramsize
- get_ram_top(), 0);
539 ofmem_map(get_ram_top(), get_ram_top(), ofmem
->ramsize
- get_ram_top(), 0);