Fix the Forth boot word if the current package is not /chosen under SPARC32.
[openbios/afaerber.git] / arch / ppc / qemu / ofmem.c
blob297e6857d4afbcd4e83c80c0795755ecad90898c
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 0x00004000UL
48 #define OF_CODE_START 0xfff00000UL
49 #define OF_CODE_SIZE 0x00100000
50 #define IO_BASE 0x80000000UL
52 #ifdef __powerpc64__
53 #define HASH_BITS 18
54 #else
55 #define HASH_BITS 15
56 #endif
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
64 get_hash_base(void)
66 return (mfsdr1() & SDR1_HTABORG_MASK);
69 static inline unsigned long
70 get_rom_base(void)
72 ofmem_t *ofmem = ofmem_arch_get_private();
73 return ofmem->ramsize - OF_CODE_SIZE;
76 unsigned long
77 get_ram_top(void)
79 return get_hash_base() - (32 + 64 + 64) * 1024 - OFMEM_SIZE;
82 unsigned long
83 get_ram_bottom(void)
85 return FREE_BASE;
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)
115 return IO_BASE;
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)
132 /* none yet */
135 ucell ofmem_arch_get_iomem_base(void)
137 /* Currently unused */
138 return 0;
141 ucell ofmem_arch_get_iomem_top(void)
143 /* Currently unused */
144 return 0;
147 retain_t *ofmem_arch_get_retained(void)
149 /* not implemented */
150 return NULL;
153 int ofmem_arch_get_physaddr_cellsize(void)
155 #ifdef CONFIG_PPC64
156 return 2;
157 #else
158 return 1;
159 #endif
162 int ofmem_arch_encode_physaddr(ucell *p, phys_addr_t value)
164 int n = 0;
165 #ifdef CONFIG_PPC64
166 p[n++] = value >> 32;
167 #endif
168 p[n++] = value;
169 return n;
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:
183 * virtual address
184 * length
185 * physical address
186 * mode
188 void ofmem_arch_create_translation_entry(ucell *transentry, translation_t *t)
190 int i = 0;
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();
203 } else {
204 return 1 + 1;
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)
211 int i = 0;
213 if (ph == s_phandle_memory) {
214 i += ofmem_arch_encode_physaddr(availentry, start);
215 } else {
216 availentry[i++] = start;
219 availentry[i] = size;
222 /************************************************************************/
223 /* OF private allocations */
224 /************************************************************************/
226 /* Private functions for mapping between physical/virtual addresses */
227 phys_addr_t
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;
232 } else {
233 return (phys_addr_t)va;
237 unsigned long
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;
243 else
244 return (unsigned long)pa;
247 void *
248 malloc(int size)
250 return ofmem_malloc(size);
253 void
254 free(void *ptr)
256 ofmem_free(ptr);
259 void *
260 realloc(void *ptr, size_t size)
262 return ofmem_realloc(ptr, size);
266 /************************************************************************/
267 /* misc */
268 /************************************************************************/
270 ucell ofmem_arch_default_translation_mode(phys_addr_t phys)
272 /* XXX: Guard bit not set as it should! */
273 if (phys < IO_BASE)
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 /************************************************************************/
287 static phys_addr_t
288 ea_to_phys(unsigned long ea, ucell *mode)
290 phys_addr_t phys;
292 if (ea >= OF_CODE_START && ea <= 0xffffffffUL) {
293 /* ROM into RAM */
294 ea -= OF_CODE_START;
295 phys = get_rom_base() + ea;
296 *mode = 0x02;
297 return phys;
300 phys = ofmem_translate(ea, mode);
301 if (phys == -1) {
302 phys = ea;
303 *mode = ofmem_arch_default_translation_mode(phys);
305 /* print_virt_range(); */
306 /* print_phys_range(); */
307 /* print_trans(); */
309 return phys;
312 static void
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;
319 int i, found;
320 unsigned int vsid, vsid_sh, sdr, sdr_sh, sdr_mask;
321 mPTE_64_t *pp;
323 vsid = (ea >> 28) + SEGR_BASE;
324 vsid_sh = 7;
325 vsid_mask = 0x00003FFFFFFFFF80ULL;
326 sdr = mfsdr1();
327 sdr_sh = 18;
328 sdr_mask = 0x3FF80;
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)
342 found = 1;
344 /* otherwise use a free slot */
345 for (i = 0; !found && i < 8; i++)
346 if (!pp[i].v)
347 found = 1;
349 /* out of slots, just evict one */
350 if (!found) {
351 i = next_grab_slot + 1;
352 next_grab_slot = (next_grab_slot + 1) % 8;
354 i--;
356 mPTE_64_t p = {
357 // .avpn_low = avpn,
358 .avpn = avpn >> 7,
359 .h = 0,
360 .v = 1,
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,
370 .pp = mode & 3,
372 pp[i] = p;
375 asm volatile("tlbie %0" :: "r"(ea));
378 static void
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;
384 int i, vsid, found;
385 mPTE_t *pp;
387 vsid = (ea >> 28) + SEGR_BASE;
388 cmp = BIT(0) | (vsid << 7) | ((ea & 0x0fffffff) >> 22);
390 hash1 = vsid;
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])
400 found = 1;
402 /* otherwise use a free slot */
403 for (i = 0; !found && i < 8; i++)
404 if (!pp[i].v)
405 found = 1;
407 /* out of slots, just evict one */
408 if (!found) {
409 i = next_grab_slot + 1;
410 next_grab_slot = (next_grab_slot + 1) % 8;
412 i--;
413 upte[i * 2] = cmp;
414 upte[i * 2 + 1] = (phys & ~0xfff) | mode;
416 asm volatile("tlbie %0" :: "r"(ea));
417 #endif
420 static int is_ppc64(void)
422 #ifdef __powerpc64__
423 return 1;
424 #elif defined(CONFIG_PPC_64BITSUPPORT)
425 unsigned int pvr = mfpvr();
426 return ((pvr >= 0x330000) && (pvr < 0x70330000));
427 #else
428 return 0;
429 #endif
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)
435 if (is_ppc64())
436 hash_page_64(ea, phys, mode);
437 else
438 hash_page_32(ea, phys, mode);
441 void
442 dsi_exception(void)
444 unsigned long dar, dsisr;
445 ucell mode;
446 phys_addr_t phys;
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);
455 void
456 isi_exception(void)
458 unsigned long nip, srr1;
459 ucell mode;
460 phys_addr_t phys;
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 /************************************************************************/
471 /* init / cleanup */
472 /************************************************************************/
474 void
475 setup_mmu(unsigned long ramsize)
477 ofmem_t *ofmem;
478 #ifndef __powerpc64__
479 unsigned long sr_base;
480 #endif
481 unsigned long hash_base;
482 unsigned long hash_mask = ~0x000fffffUL; /* alignment for ppc64 */
483 int i;
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);
489 if (is_ppc64())
490 mtsdr1(hash_base | MAX(HASH_BITS - 18, 0));
491 else
492 mtsdr1(hash_base | ((HASH_SIZE - 1) >> 16));
494 #ifdef __powerpc64__
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;
502 slbmte(rs, rb);
505 #else
507 /* Segment Register */
509 sr_base = SEGR_USER | SEGR_BASE ;
510 for (i = 0; i < 16; i++) {
511 int j = i << 28;
512 asm volatile("mtsrin %0,%1" :: "r" (sr_base + i), "r" (j));
515 #endif
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);
523 /* Enable MMU */
525 mtmsr(mfmsr() | MSR_IR | MSR_DR);
528 void
529 ofmem_init(void)
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);