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