1 /*
2  *   Creation Date: <1999/11/07 19:02:11 samuel>
3  *   Time-stamp: <2004/01/07 19:42:36 samuel>
4  *
5  *	<ofmem.c>
6  *
7  *	OF Memory manager
8  *
9  *   Copyright (C) 1999-2004 Samuel Rydh (samuel@ibrium.se)
10  *   Copyright (C) 2004 Stefan Reinauer
11  *
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
15  *
16  */
17 
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"
25 
26 #define BIT(n)		(1U << (31 - (n)))
27 
28 #define SLB_VSID_SHIFT 12
29 
30 /* called from assembly */
31 extern void dsi_exception(void);
32 extern void isi_exception(void);
33 extern void setup_mmu(unsigned long code_base);
34 
35 /*
36  * From Apple's BootX source comments:
37  *
38  *  96 MB map (currently unused - 4363357 tracks re-adoption)
39  * 00000000 - 00003FFF  : Exception Vectors
40  * 00004000 - 03FFFFFF  : Kernel Image, Boot Struct and Drivers (~64 MB)
41  * 04000000 - 04FFFFFF  : File Load Area (16 MB)   [80 MB]
42  * 05000000 - 053FFFFF  : FS Cache    (4 MB)       [84 MB]
43  * 05400000 - 055FFFFF  : Malloc Zone (2 MB)       [86 MB]
44  * 05600000 - 057FFFFF  : BootX Image (2 MB)       [88 MB]
45  * 05800000 - 05FFFFFF  : Unused/OF   (8 MB)       [96 MB]
46  *
47  */
48 
49 #define OF_CODE_START	0xfff00000UL
50 #define OF_CODE_SIZE    0x00100000
51 #define IO_BASE			0x80000000UL
52 
53 #ifdef __powerpc64__
54 #define HASH_BITS		18
55 #else
56 #define HASH_BITS		15
57 #endif
58 #define HASH_SIZE		(2 << HASH_BITS)
59 #define OFMEM_SIZE		(1 * 1024 * 1024 + 512 * 1024)
60 
61 #define	SEGR_USER		BIT(2)
62 #define SEGR_BASE		0x0400
63 
64 static inline unsigned long
get_hash_base(void)65 get_hash_base(void)
66 {
67     return (mfsdr1() & SDR1_HTABORG_MASK);
68 }
69 
70 static inline unsigned long
get_rom_base(void)71 get_rom_base(void)
72 {
73     ofmem_t *ofmem = ofmem_arch_get_private();
74     return ofmem->ramsize - OF_CODE_SIZE;
75 }
76 
77 static unsigned long
get_ram_top(void)78 get_ram_top(void)
79 {
80     return get_hash_base() - (32 + 64 + 64) * 1024 - OFMEM_SIZE;
81 }
82 
get_heap_top(void)83 static unsigned long get_heap_top(void)
84 {
85     return get_hash_base() - (32 + 64 + 64) * 1024;
86 }
87 
ALIGN_SIZE(size_t x,size_t a)88 static inline size_t ALIGN_SIZE(size_t x, size_t a)
89 {
90     return (x + a - 1) & ~(a - 1);
91 }
92 
ofmem_arch_get_private(void)93 ofmem_t* ofmem_arch_get_private(void)
94 {
95     return (ofmem_t*)cell2pointer(get_heap_top() - OFMEM_SIZE);
96 }
97 
ofmem_arch_get_malloc_base(void)98 void* ofmem_arch_get_malloc_base(void)
99 {
100     return (char*)ofmem_arch_get_private() + ALIGN_SIZE(sizeof(ofmem_t), 4);
101 }
102 
ofmem_arch_get_heap_top(void)103 ucell ofmem_arch_get_heap_top(void)
104 {
105     return get_heap_top();
106 }
107 
ofmem_arch_get_virt_top(void)108 ucell ofmem_arch_get_virt_top(void)
109 {
110     return IO_BASE;
111 }
112 
ofmem_arch_unmap_pages(ucell virt,ucell size)113 void ofmem_arch_unmap_pages(ucell virt, ucell size)
114 {
115     /* kill page mappings in provided range */
116 }
117 
ofmem_arch_map_pages(phys_addr_t phys,ucell virt,ucell size,ucell mode)118 void ofmem_arch_map_pages(phys_addr_t phys, ucell virt, ucell size, ucell mode)
119 {
120     /* none yet */
121 }
122 
ofmem_arch_get_iomem_base(void)123 ucell ofmem_arch_get_iomem_base(void)
124 {
125     /* Currently unused */
126     return 0;
127 }
128 
ofmem_arch_get_iomem_top(void)129 ucell ofmem_arch_get_iomem_top(void)
130 {
131     /* Currently unused */
132     return 0;
133 }
134 
ofmem_arch_get_retained(void)135 retain_t *ofmem_arch_get_retained(void)
136 {
137     /* not implemented */
138     return NULL;
139 }
140 
ofmem_arch_get_physaddr_cellsize(void)141 int ofmem_arch_get_physaddr_cellsize(void)
142 {
143 #ifdef CONFIG_PPC64
144     return 2;
145 #else
146     return 1;
147 #endif
148 }
149 
ofmem_arch_encode_physaddr(ucell * p,phys_addr_t value)150 int ofmem_arch_encode_physaddr(ucell *p, phys_addr_t value)
151 {
152     int n = 0;
153 #ifdef CONFIG_PPC64
154     p[n++] = value >> 32;
155 #endif
156     p[n++] = value;
157     return n;
158 }
159 
160 /* Return size of a single MMU package translation property entry in cells */
ofmem_arch_get_translation_entry_size(void)161 int ofmem_arch_get_translation_entry_size(void)
162 {
163     return 3 + ofmem_arch_get_physaddr_cellsize();
164 }
165 
166 /* Generate translation property entry for PPC.
167  * According to the platform bindings for PPC
168  * (http://www.openfirmware.org/1275/bindings/ppc/release/ppc-2_1.html#REF34579)
169  * a translation property entry has the following layout:
170  *
171  *      virtual address
172  *      length
173  *      physical address
174  *      mode
175  */
ofmem_arch_create_translation_entry(ucell * transentry,translation_t * t)176 void ofmem_arch_create_translation_entry(ucell *transentry, translation_t *t)
177 {
178     int i = 0;
179 
180     transentry[i++] = t->virt;
181     transentry[i++] = t->size;
182     i += ofmem_arch_encode_physaddr(&transentry[i], t->phys);
183     transentry[i++] = t->mode;
184 }
185 
186 /* Return the size of a memory available entry given the phandle in cells */
ofmem_arch_get_available_entry_size(phandle_t ph)187 int ofmem_arch_get_available_entry_size(phandle_t ph)
188 {
189     if (ph == s_phandle_memory) {
190         return 1 + ofmem_arch_get_physaddr_cellsize();
191     } else {
192         return 1 + 1;
193     }
194 }
195 
196 /* Generate memory available property entry for PPC */
ofmem_arch_create_available_entry(phandle_t ph,ucell * availentry,phys_addr_t start,ucell size)197 void ofmem_arch_create_available_entry(phandle_t ph, ucell *availentry, phys_addr_t start, ucell size)
198 {
199     int i = 0;
200 
201     if (ph == s_phandle_memory) {
202         i += ofmem_arch_encode_physaddr(availentry, start);
203     } else {
204 	availentry[i++] = start;
205     }
206 
207     availentry[i] = size;
208 }
209 
210 /************************************************************************/
211 /*	OF private allocations						*/
212 /************************************************************************/
213 
214 /* Private functions for mapping between physical/virtual addresses */
215 phys_addr_t
va2pa(unsigned long va)216 va2pa(unsigned long va)
217 {
218     if (va >= OF_CODE_START && va < OF_CODE_START + OF_CODE_SIZE) {
219         return (phys_addr_t)get_rom_base() - OF_CODE_START + va;
220     } else {
221         return (phys_addr_t)va;
222     }
223 }
224 
225 unsigned long
pa2va(phys_addr_t pa)226 pa2va(phys_addr_t pa)
227 {
228     if ((pa - get_rom_base() + OF_CODE_START >= OF_CODE_START) &&
229         (pa - get_rom_base() + OF_CODE_START < OF_CODE_START + OF_CODE_SIZE))
230         return (unsigned long)pa - get_rom_base() + OF_CODE_START;
231     else
232         return (unsigned long)pa;
233 }
234 
235 void *
malloc(int size)236 malloc(int size)
237 {
238     return ofmem_malloc(size);
239 }
240 
241 void
free(void * ptr)242 free(void *ptr)
243 {
244     ofmem_free(ptr);
245 }
246 
247 void *
realloc(void * ptr,size_t size)248 realloc(void *ptr, size_t size)
249 {
250     return ofmem_realloc(ptr, size);
251 }
252 
253 
254 /************************************************************************/
255 /*	misc								*/
256 /************************************************************************/
257 
ofmem_arch_default_translation_mode(phys_addr_t phys)258 ucell ofmem_arch_default_translation_mode(phys_addr_t phys)
259 {
260     /* XXX: Guard bit not set as it should! */
261     if (phys < IO_BASE)
262         return 0x02;	/*0xa*/	/* wim GxPp */
263     return 0x6a;		/* WIm GxPp, I/O */
264 }
265 
ofmem_arch_io_translation_mode(phys_addr_t phys)266 ucell ofmem_arch_io_translation_mode(phys_addr_t phys)
267 {
268     return 0x6a;		/* WIm GxPp, I/O */
269 }
270 
271 /************************************************************************/
272 /*	page fault handler						*/
273 /************************************************************************/
274 
275 static phys_addr_t
ea_to_phys(unsigned long ea,ucell * mode)276 ea_to_phys(unsigned long ea, ucell *mode)
277 {
278     phys_addr_t phys;
279 
280     if (ea >= OF_CODE_START && ea <= 0xffffffffUL) {
281         /* ROM into RAM */
282         ea -= OF_CODE_START;
283         phys = get_rom_base() + ea;
284         *mode = 0x02;
285 		return phys;
286     }
287 
288     phys = ofmem_translate(ea, mode);
289     if (phys == -1) {
290         phys = ea;
291         *mode = ofmem_arch_default_translation_mode(phys);
292 
293         /* print_virt_range(); */
294         /* print_phys_range(); */
295         /* print_trans(); */
296     }
297     return phys;
298 }
299 
300 /* Converts a global variable (from .data or .bss) into a pointer that
301    can be accessed from real mode */
302 static void *
global_ptr_real(void * p)303 global_ptr_real(void *p)
304 {
305     return (void*)((uintptr_t)p - OF_CODE_START + get_rom_base());
306 }
307 
308 /* Return the next slot to evict, in the range of [0..7] */
309 static int
next_evicted_slot(void)310 next_evicted_slot(void)
311 {
312     static int next_grab_slot;
313     int *next_grab_slot_va;
314     int r;
315 
316     next_grab_slot_va = global_ptr_real(&next_grab_slot);
317     r = *next_grab_slot_va;
318     *next_grab_slot_va = (r + 1) % 8;
319 
320     return r;
321 }
322 
323 static void
hash_page_64(unsigned long ea,phys_addr_t phys,ucell mode)324 hash_page_64(unsigned long ea, phys_addr_t phys, ucell mode)
325 {
326     uint64_t vsid_mask, page_mask, pgidx, hash;
327     uint64_t htab_mask, mask, avpn;
328     unsigned long pgaddr;
329     int i, found;
330     unsigned int vsid, vsid_sh, sdr, sdr_sh, sdr_mask;
331     mPTE_64_t *pp;
332 
333     vsid = (ea >> 28) + SEGR_BASE;
334     vsid_sh = 7;
335     vsid_mask = 0x00003FFFFFFFFF80ULL;
336     sdr = mfsdr1();
337     sdr_sh = 18;
338     sdr_mask = 0x3FF80;
339     page_mask = 0x0FFFFFFF; // XXX correct?
340     pgidx = (ea & page_mask) >> PAGE_SHIFT;
341     avpn = (vsid << 12) | ((pgidx >> 4) & 0x0F80);;
342 
343     hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask;
344     htab_mask = 0x0FFFFFFF >> (28 - (sdr & 0x1F));
345     mask = (htab_mask << sdr_sh) | sdr_mask;
346     pgaddr = sdr | (hash & mask);
347     pp = (mPTE_64_t *)pgaddr;
348 
349     /* replace old translation */
350     for (found = 0, i = 0; !found && i < 8; i++)
351         if (pp[i].avpn == avpn)
352             found = 1;
353 
354     /* otherwise use a free slot */
355     if (!found) {
356         for (i = 0; !found && i < 8; i++)
357             if (!pp[i].v)
358                 found = 1;
359     }
360 
361     /* out of slots, just evict one */
362     if (!found)
363         i = next_evicted_slot() + 1;
364     i--;
365     {
366     mPTE_64_t p = {
367         // .avpn_low = avpn,
368         .avpn = avpn >> 7,
369         .h = 0,
370         .v = 1,
371 
372         .rpn = (phys & ~0xfffUL) >> 12,
373         .r = mode & (1 << 8) ? 1 : 0,
374         .c = mode & (1 << 7) ? 1 : 0,
375         .w = mode & (1 << 6) ? 1 : 0,
376         .i = mode & (1 << 5) ? 1 : 0,
377         .m = mode & (1 << 4) ? 1 : 0,
378         .g = mode & (1 << 3) ? 1 : 0,
379         .n = mode & (1 << 2) ? 1 : 0,
380         .pp = mode & 3,
381     };
382     pp[i] = p;
383     }
384 
385     asm volatile("tlbie %0" :: "r"(ea));
386 }
387 
388 static void
hash_page_32(unsigned long ea,phys_addr_t phys,ucell mode)389 hash_page_32(unsigned long ea, phys_addr_t phys, ucell mode)
390 {
391 #ifndef __powerpc64__
392     unsigned long *upte, cmp, hash1;
393     int i, vsid, found;
394     mPTE_t *pp;
395 
396     vsid = (ea >> 28) + SEGR_BASE;
397     cmp = BIT(0) | (vsid << 7) | ((ea & 0x0fffffff) >> 22);
398 
399     hash1 = vsid;
400     hash1 ^= (ea >> 12) & 0xffff;
401     hash1 &= (((mfsdr1() & 0x1ff) << 16) | 0xffff) >> 6;
402 
403     pp = (mPTE_t*)(get_hash_base() + (hash1 << 6));
404     upte = (unsigned long*)pp;
405 
406     /* replace old translation */
407     for (found = 0, i = 0; !found && i < 8; i++)
408         if (cmp == upte[i*2])
409             found = 1;
410 
411     /* otherwise use a free slot */
412     if (!found) {
413         for (i = 0; !found && i < 8; i++)
414             if (!pp[i].v)
415                 found = 1;
416     }
417 
418     /* out of slots, just evict one */
419     if (!found)
420         i = next_evicted_slot() + 1;
421     i--;
422     upte[i * 2] = cmp;
423     upte[i * 2 + 1] = (phys & ~0xfff) | mode;
424 
425     asm volatile("tlbie %0" :: "r"(ea));
426 #endif
427 }
428 
is_ppc64(void)429 static int is_ppc64(void)
430 {
431 #ifdef __powerpc64__
432     return 1;
433 #elif defined(CONFIG_PPC_64BITSUPPORT)
434     unsigned int pvr = mfpvr();
435     return ((pvr >= 0x330000) && (pvr < 0x70330000));
436 #else
437     return 0;
438 #endif
439 }
440 
441 /* XXX Remove these ugly constructs when legacy 64-bit support is dropped. */
hash_page(unsigned long ea,phys_addr_t phys,ucell mode)442 static void hash_page(unsigned long ea, phys_addr_t phys, ucell mode)
443 {
444     if (is_ppc64())
445         hash_page_64(ea, phys, mode);
446     else
447         hash_page_32(ea, phys, mode);
448 }
449 
450 void
dsi_exception(void)451 dsi_exception(void)
452 {
453     unsigned long dar, dsisr;
454     ucell mode;
455     phys_addr_t phys;
456 
457     asm volatile("mfdar %0" : "=r" (dar) : );
458     asm volatile("mfdsisr %0" : "=r" (dsisr) : );
459 
460     phys = ea_to_phys(dar, &mode);
461     hash_page(dar, phys, mode);
462 }
463 
464 void
isi_exception(void)465 isi_exception(void)
466 {
467     unsigned long nip, srr1;
468     ucell mode;
469     phys_addr_t phys;
470 
471     asm volatile("mfsrr0 %0" : "=r" (nip) : );
472     asm volatile("mfsrr1 %0" : "=r" (srr1) : );
473 
474     phys = ea_to_phys(nip, &mode);
475     hash_page(nip, phys, mode);
476 }
477 
478 /*
479  * Power ISA 2.x has deleted the rfi instruction and rfid shoud be
480  * used instead on cpus following this instruction set or later.
481  *
482  * OpenBIOS 32bits is compiled to use rfi. But, when it runs on a
483  * Power ISA 2.x cpu (a 970 for instance), we need to replace the rfi
484  * instructions with rfid in the vectors' memory section. Else we
485  * won't go any futher than the first exception ...
486  */
487 #define RFI     0x4c000064
488 #define RFID    0x4c000024
489 
490 extern char __vectors[];
491 extern char __vectors_end[];
492 
patch_rfi(void)493 static void patch_rfi(void)
494 {
495     uint32_t* ptr;
496     uint32_t* vec_start = (uint32_t*) 0x100UL;
497     uint32_t* vec_end = (uint32_t*) (__vectors_end - __vectors);
498 
499     if (!is_ppc64())
500         return;
501 
502     for (ptr = vec_start; ptr != vec_end; ptr++)  {
503         if (*ptr == RFI)
504             *ptr = RFID;
505     }
506     flush_icache_range((char*) vec_start , (char*) vec_end);
507 }
508 
509 /************************************************************************/
510 /*	init / cleanup							*/
511 /************************************************************************/
512 
513 void
setup_mmu(unsigned long ramsize)514 setup_mmu(unsigned long ramsize)
515 {
516     ofmem_t *ofmem;
517 #ifndef __powerpc64__
518     unsigned long sr_base;
519 #endif
520     unsigned long hash_base;
521     unsigned long hash_mask = ~0x000fffffUL; /* alignment for ppc64 */
522     int i;
523 
524     /* SDR1: Storage Description Register 1 */
525 
526     hash_base = (ramsize - OF_CODE_SIZE - HASH_SIZE) & hash_mask;
527     memset((void *)hash_base, 0, HASH_SIZE);
528     if (is_ppc64())
529         mtsdr1(hash_base | MAX(HASH_BITS - 18, 0));
530     else
531         mtsdr1(hash_base | ((HASH_SIZE - 1) >> 16));
532 
533 #ifdef __powerpc64__
534 
535     /* Segment Lookaside Buffer */
536 
537     slbia(); /* Invalidate all SLBs except SLB 0 */
538     for (i = 0; i < 16; i++) {
539         unsigned long rs = (0x400 + i) << SLB_VSID_SHIFT;
540         unsigned long rb = ((unsigned long)i << 28) | (1 << 27) | i;
541         slbmte(rs, rb);
542     }
543 
544 #else
545 
546     /* Segment Register */
547 
548     sr_base = SEGR_USER | SEGR_BASE ;
549     for (i = 0; i < 16; i++) {
550         int j = i << 28;
551         asm volatile("mtsrin %0,%1" :: "r" (sr_base + i), "r" (j));
552     }
553 
554 #endif
555 
556     ofmem = ofmem_arch_get_private();
557     memset(ofmem, 0, sizeof(ofmem_t));
558     ofmem->ramsize = ramsize;
559 
560     memcpy((void *)get_rom_base(), (void *)OF_CODE_START, OF_CODE_SIZE);
561 
562     patch_rfi();
563 
564     /* Enable MMU */
565 
566     mtmsr(mfmsr() | MSR_IR | MSR_DR);
567 }
568 
569 void
ofmem_init(void)570 ofmem_init(void)
571 {
572     ofmem_t *ofmem = ofmem_arch_get_private();
573 
574     /* Mark the first page as non-free */
575     ofmem_claim_phys(0, PAGE_SIZE, 0);
576     ofmem_claim_virt(0, PAGE_SIZE, 0);
577 
578     /* Map everything at the top of physical RAM 1:1, minus the OpenBIOS ROM in RAM copy */
579     ofmem_claim_phys(get_ram_top(), get_hash_base() + HASH_SIZE - get_ram_top(), 0);
580     ofmem_claim_virt(get_ram_top(), get_hash_base() + HASH_SIZE - get_ram_top(), 0);
581     ofmem_map(get_ram_top(), get_ram_top(), get_hash_base() + HASH_SIZE - get_ram_top(), 0);
582 
583     /* Map the OpenBIOS ROM in RAM copy */
584     ofmem_claim_phys(ofmem->ramsize - OF_CODE_SIZE, OF_CODE_SIZE, 0);
585     ofmem_claim_virt(OF_CODE_START, OF_CODE_SIZE, 0);
586     ofmem_map(ofmem->ramsize - OF_CODE_SIZE, OF_CODE_START, OF_CODE_SIZE, 0);
587 }
588