|
|
1.1 root 1: /* lib.c
2: * tag: simple function library
3: *
4: * Copyright (C) 2003 Stefan Reinauer
5: *
6: * See the file "COPYING" for further information about
7: * the copyright and warranty status of this work.
8: */
9:
10: #include "libc/vsprintf.h"
11: #include "libopenbios/bindings.h"
12: #include "libopenbios/ofmem.h"
13: #include "asm/asi.h"
14: #include "pgtsrmmu.h"
15: #include "openprom.h"
16: #include "libopenbios/sys_info.h"
17: #include "boot.h"
18: #include "romvec.h"
19:
20: #define NCTX_SWIFT 0x100
21: #define LOWMEMSZ 32 * 1024 * 1024
22:
23: #ifdef CONFIG_DEBUG_MEM
24: #define DPRINTF(fmt, args...) \
25: do { printk(fmt , ##args); } while (0)
26: #else
27: #define DPRINTF(fmt, args...)
28: #endif
29:
30: /* Format a string and print it on the screen, just like the libc
31: * function printf.
32: */
33: int printk( const char *fmt, ... )
34: {
35: char *p, buf[512];
36: va_list args;
37: int i;
38:
39: va_start(args, fmt);
40: i = vsnprintf(buf, sizeof(buf), fmt, args);
41: va_end(args);
42:
43: for( p=buf; *p; p++ )
44: putchar(*p);
45: return i;
46: }
47:
48: /*
49: * Allocatable memory chunk.
50: */
51: struct mem {
52: char *start, *uplim;
53: char *curp;
54: };
55:
56: struct mem cdvmem; /* Current device virtual memory space */
57:
58: unsigned int va_shift;
59: static unsigned long *context_table;
60: static unsigned long *l1;
61:
62: static ucell *mem_reg = 0;
63: static ucell *mem_avail = 0;
64: static ucell *virt_avail = 0;
65:
66: static struct linux_mlist_v0 totphys[1];
67: static struct linux_mlist_v0 totmap[1];
68: static struct linux_mlist_v0 totavail[1];
69:
70: struct linux_mlist_v0 *ptphys;
71: struct linux_mlist_v0 *ptmap;
72: struct linux_mlist_v0 *ptavail;
73:
74: /* Private functions for mapping between physical/virtual addresses */
75: phys_addr_t
76: va2pa(unsigned long va)
77: {
78: if ((va >= (unsigned long)&_start) &&
79: (va < (unsigned long)&_end))
80: return va - va_shift;
81: else
82: return va;
83: }
84:
85: unsigned long
86: pa2va(phys_addr_t pa)
87: {
88: if ((pa + va_shift >= (unsigned long)&_start) &&
89: (pa + va_shift < (unsigned long)&_end))
90: return pa + va_shift;
91: else
92: return pa;
93: }
94:
95: void *
96: malloc(int size)
97: {
98: return ofmem_malloc(size);
99: }
100:
101: void *
102: realloc( void *ptr, size_t size )
103: {
104: return ofmem_realloc(ptr, size);
105: }
106:
107: void
108: free(void *ptr)
109: {
110: ofmem_free(ptr);
111: }
112:
113: /*
114: * Allocate memory. This is reusable.
115: */
116: void
117: mem_init(struct mem *t, char *begin, char *limit)
118: {
119: t->start = begin;
120: t->uplim = limit;
121: t->curp = begin;
122: }
123:
124: void *
125: mem_alloc(struct mem *t, int size, int align)
126: {
127: char *p;
128: unsigned long pa;
129:
130: // The alignment restrictions refer to physical, not virtual
131: // addresses
132: pa = va2pa((unsigned long)t->curp) + (align - 1);
133: pa &= ~(align - 1);
134: p = (char *)pa2va(pa);
135:
136: if ((unsigned long)p >= (unsigned long)t->uplim ||
137: (unsigned long)p + size > (unsigned long)t->uplim)
138: return NULL;
139: t->curp = p + size;
140:
141: return p;
142: }
143:
144: static unsigned long
145: find_pte(unsigned long va, int alloc)
146: {
147: uint32_t pte;
148: void *p;
149: unsigned long pa;
150: int ret;
151:
152: pte = l1[(va >> SRMMU_PGDIR_SHIFT) & (SRMMU_PTRS_PER_PGD - 1)];
153: if ((pte & SRMMU_ET_MASK) == SRMMU_ET_INVALID) {
154: if (alloc) {
155: ret = ofmem_posix_memalign(&p, SRMMU_PTRS_PER_PMD * sizeof(int),
156: SRMMU_PTRS_PER_PMD * sizeof(int));
157: if (ret != 0)
158: return ret;
159: pte = SRMMU_ET_PTD | ((va2pa((unsigned long)p)) >> 4);
160: l1[(va >> SRMMU_PGDIR_SHIFT) & (SRMMU_PTRS_PER_PGD - 1)] = pte;
161: /* barrier() */
162: } else {
163: return -1;
164: }
165: }
166:
167: pa = (pte & 0xFFFFFFF0) << 4;
168: pa += ((va >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1)) << 2;
169: pte = *(uint32_t *)pa2va(pa);
170: if ((pte & SRMMU_ET_MASK) == SRMMU_ET_INVALID) {
171: if (alloc) {
172: ret = ofmem_posix_memalign(&p, SRMMU_PTRS_PER_PTE * sizeof(void *),
173: SRMMU_PTRS_PER_PTE * sizeof(void *));
174: if (ret != 0)
175: return ret;
176: pte = SRMMU_ET_PTD | ((va2pa((unsigned int)p)) >> 4);
177: *(uint32_t *)pa2va(pa) = pte;
178: } else {
179: return -2;
180: }
181: }
182:
183: pa = (pte & 0xFFFFFFF0) << 4;
184: pa += ((va >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1)) << 2;
185:
186: return pa2va(pa);
187: }
188:
189: static void
190: map_pages(phys_addr_t phys, unsigned long virt,
191: unsigned long size, unsigned long mode)
192: {
193: unsigned long npages, off;
194: uint32_t pte;
195: unsigned long pa;
196:
197: DPRINTF("map_pages: va 0x%lx, pa 0x%llx, size 0x%lx\n", virt, phys, size);
198:
199: off = phys & (PAGE_SIZE - 1);
200: npages = (off + (size - 1) + (PAGE_SIZE - 1)) / PAGE_SIZE;
201: phys &= ~(uint64_t)(PAGE_SIZE - 1);
202:
203: while (npages-- != 0) {
204: pa = find_pte(virt, 1);
205:
206: pte = SRMMU_ET_PTE | ((phys & PAGE_MASK) >> 4);
207: pte |= mode;
208:
209: *(uint32_t *)pa = pte;
210:
211: virt += PAGE_SIZE;
212: phys += PAGE_SIZE;
213: }
214: }
215:
216: /*
217: * D5.3 pgmap@ ( va -- pte )
218: */
219: static void
220: pgmap_fetch(void)
221: {
222: uint32_t pte;
223: unsigned long va, pa;
224:
225: va = POP();
226:
227: pa = find_pte(va, 0);
228: if (pa == 1 || pa == 2)
229: goto error;
230: pte = *(uint32_t *)pa;
231: DPRINTF("pgmap@: va 0x%lx pa 0x%lx pte 0x%x\n", va, pa, pte);
232:
233: PUSH(pte);
234: return;
235: error:
236: PUSH(0);
237: }
238:
239: /*
240: * D5.3 pgmap! ( pte va -- )
241: */
242: static void
243: pgmap_store(void)
244: {
245: uint32_t pte;
246: unsigned long va, pa;
247:
248: va = POP();
249: pte = POP();
250:
251: pa = find_pte(va, 1);
252: *(uint32_t *)pa = pte;
253: DPRINTF("pgmap!: va 0x%lx pa 0x%lx pte 0x%x\n", va, pa, pte);
254: }
255:
256: /*
257: * D5.3 map-pages ( pa space va size -- )
258: */
259: static void
260: ob_map_pages(void)
261: {
262: unsigned long va;
263: int size;
264: uint64_t pa;
265:
266: size = POP();
267: va = POP();
268: pa = POP();
269: pa <<= 32;
270: pa |= POP() & 0xffffffff;
271:
272: map_pages(pa, va, size, ofmem_arch_default_translation_mode(pa));
273: DPRINTF("map-page: va 0x%lx pa 0x%llx size 0x%x\n", va, pa, size);
274: }
275:
276: static void
277: update_memory_properties(void)
278: {
279: /* Update the device tree memory properties from the master
280: totphys, totmap and totavail romvec arrays */
281: mem_reg[0] = 0;
282: mem_reg[1] = pointer2cell(totphys[0].start_adr);
283: mem_reg[2] = totphys[0].num_bytes;
284:
285: virt_avail[0] = 0;
286: virt_avail[1] = 0;
287: virt_avail[2] = pointer2cell(totmap[0].start_adr);
288:
289: mem_avail[0] = 0;
290: mem_avail[1] = pointer2cell(totavail[0].start_adr);
291: mem_avail[2] = totavail[0].num_bytes;
292: }
293:
294: static void
295: init_romvec_mem(void)
296: {
297: ptphys = totphys;
298: ptmap = totmap;
299: ptavail = totavail;
300:
301: /*
302: * Form memory descriptors.
303: */
304: totphys[0].theres_more = NULL;
305: totphys[0].start_adr = (char *) 0;
306: totphys[0].num_bytes = qemu_mem_size;
307:
308: totavail[0].theres_more = NULL;
309: totavail[0].start_adr = (char *) 0;
310: totavail[0].num_bytes = va2pa((int)&_start) - PAGE_SIZE;
311:
312: totmap[0].theres_more = NULL;
313: totmap[0].start_adr = &_start;
314: totmap[0].num_bytes = (unsigned long) &_iomem -
315: (unsigned long) &_start + PAGE_SIZE;
316:
317: /* Pointers to device tree memory properties */
318: mem_reg = malloc(sizeof(ucell) * 3);
319: mem_avail = malloc(sizeof(ucell) * 3);
320: virt_avail = malloc(sizeof(ucell) * 3);
321:
322: update_memory_properties();
323: }
324:
325: char *obp_dumb_mmap(char *va, int which_io, unsigned int pa,
326: unsigned int size)
327: {
328: uint64_t mpa = ((uint64_t)which_io << 32) | (uint64_t)pa;
329:
330: map_pages(mpa, (unsigned long)va, size, ofmem_arch_default_translation_mode(mpa));
331: return va;
332: }
333:
334: void obp_dumb_munmap(__attribute__((unused)) char *va,
335: __attribute__((unused)) unsigned int size)
336: {
337: DPRINTF("obp_dumb_munmap: virta 0x%x, sz %d\n", (unsigned int)va, size);
338: }
339:
340: void ofmem_arch_unmap_pages(ucell virt, ucell size)
341: {
342: /* Currently do nothing */
343: }
344:
345: void ofmem_arch_early_map_pages(phys_addr_t phys, ucell virt, ucell size, ucell mode)
346: {
347: map_pages(phys, virt, size, mode);
348: }
349:
350: char *obp_memalloc(char *va, unsigned int size, unsigned int align)
351: {
352: phys_addr_t phys;
353: ucell virt;
354:
355: /* Claim physical memory */
356: phys = ofmem_claim_phys(-1, size, align);
357:
358: /* Claim virtual memory */
359: virt = ofmem_claim_virt(pointer2cell(va), size, 0);
360:
361: /* Map the memory */
362: ofmem_map(phys, virt, size, ofmem_arch_default_translation_mode(phys));
363:
364: return cell2pointer(virt);
365: }
366:
367: char *obp_dumb_memalloc(char *va, unsigned int size)
368: {
369: unsigned long align;
370: int i;
371:
372: /* Solaris seems to assume that the returned value is physically aligned to size. For
373: example, not having this here causes the Solaris 8 kernel to fault because the
374: IOMMU page table base address is calculated incorrectly. */
375:
376: /* Enforce a minimum alignment of CONFIG_OFMEM_MALLOC_ALIGN, and choose an alignment
377: which is the next power of 2 higher than the specified size */
378: align = size;
379: if (align <= CONFIG_OFMEM_MALLOC_ALIGN) {
380: align = CONFIG_OFMEM_MALLOC_ALIGN;
381: } else {
382: align--;
383: for (i = 1; i < sizeof(unsigned long) * 8; i<<=1) {
384: align |= align >> i;
385: }
386: align++;
387: }
388:
389: return obp_memalloc(va, size, align);
390: }
391:
392: void obp_dumb_memfree(__attribute__((unused))char *va,
393: __attribute__((unused))unsigned sz)
394: {
395: DPRINTF("obp_dumb_memfree 0x%p (size %d)\n", va, sz);
396: }
397:
398: void
399: ob_init_mmu(void)
400: {
401: ucell *memreg;
402: ucell *virtreg;
403: phys_addr_t virtregsize;
404: ofmem_t *ofmem = ofmem_arch_get_private();
405:
406: init_romvec_mem();
407:
408: /* Find the phandles for the /memory and /virtual-memory nodes */
409: push_str("/memory");
410: fword("find-package");
411: POP();
412: s_phandle_memory = POP();
413:
414: push_str("/virtual-memory");
415: fword("find-package");
416: POP();
417: s_phandle_mmu = POP();
418:
419: ofmem_register(s_phandle_memory, s_phandle_mmu);
420:
421: /* Setup /memory:reg (totphys) property */
422: memreg = malloc(3 * sizeof(ucell));
423: ofmem_arch_encode_physaddr(memreg, 0); /* physical base */
424: memreg[2] = (ucell)ofmem->ramsize; /* size */
425:
426: push_str("/memory");
427: fword("find-device");
428: PUSH(pointer2cell(memreg));
429: PUSH(3 * sizeof(ucell));
430: push_str("reg");
431: PUSH_ph(s_phandle_memory);
432: fword("encode-property");
433:
434: /* Setup /virtual-memory:reg property */
435: virtregsize = ((phys_addr_t)((ucell)-1) + 1) / 2;
436:
437: virtreg = malloc(6 * sizeof(ucell));
438: ofmem_arch_encode_physaddr(virtreg, 0);
439: virtreg[2] = virtregsize;
440: ofmem_arch_encode_physaddr(&virtreg[3], virtregsize);
441: virtreg[5] = virtregsize;
442:
443: push_str("/virtual-memory");
444: fword("find-device");
445: PUSH(pointer2cell(virtreg));
446: PUSH(6 * sizeof(ucell));
447: push_str("reg");
448: PUSH_ph(s_phandle_mmu);
449: fword("encode-property");
450:
451: PUSH(0);
452: fword("active-package!");
453: bind_func("pgmap@", pgmap_fetch);
454: bind_func("pgmap!", pgmap_store);
455: bind_func("map-pages", ob_map_pages);
456: }
457:
458: /*
459: * Switch page tables.
460: */
461: void
462: init_mmu_swift(void)
463: {
464: unsigned int addr, i;
465: unsigned long pa, va;
466: int size;
467:
468: ofmem_posix_memalign((void *)&context_table, NCTX_SWIFT * sizeof(int),
469: NCTX_SWIFT * sizeof(int));
470: ofmem_posix_memalign((void *)&l1, 256 * sizeof(int), 256 * sizeof(int));
471:
472: context_table[0] = (((unsigned long)va2pa((unsigned long)l1)) >> 4) |
473: SRMMU_ET_PTD;
474:
475: for (i = 1; i < NCTX_SWIFT; i++) {
476: context_table[i] = SRMMU_ET_INVALID;
477: }
478: for (i = 0; i < 256; i += 4) {
479: l1[i] = SRMMU_ET_INVALID;
480: }
481:
482: // text, rodata, data, and bss mapped to end of RAM
483: va = (unsigned long)&_start;
484: size = (unsigned long)&_end - (unsigned long)&_start;
485: pa = va2pa(va);
486: map_pages(pa, va, size, ofmem_arch_default_translation_mode(pa));
487:
488: // 1:1 mapping for RAM
489: map_pages(0, 0, LOWMEMSZ, ofmem_arch_default_translation_mode(0));
490:
491: /*
492: * Flush cache
493: */
494: for (addr = 0; addr < 0x2000; addr += 0x10) {
495: __asm__ __volatile__ ("sta %%g0, [%0] %1\n\t" : :
496: "r" (addr), "i" (ASI_M_DATAC_TAG));
497: __asm__ __volatile__ ("sta %%g0, [%0] %1\n\t" : :
498: "r" (addr<<1), "i" (ASI_M_TXTC_TAG));
499: }
500: srmmu_set_context(0);
501: srmmu_set_ctable_ptr(va2pa((unsigned long)context_table));
502: srmmu_flush_whole_tlb();
503: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.