|
|
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 "config.h"
11: #include "libc/vsprintf.h"
12: #include "libopenbios/bindings.h"
13: #include "spitfire.h"
14: #include "libopenbios/sys_info.h"
15: #include "boot.h"
16:
17: #include "ofmem_sparc64.h"
18:
19: static ucell *va2ttedata = 0;
20:
21: /* Format a string and print it on the screen, just like the libc
22: * function printf.
23: */
24: int printk( const char *fmt, ... )
25: {
26: char *p, buf[512];
27: va_list args;
28: int i;
29:
30: va_start(args, fmt);
31: i = vsnprintf(buf, sizeof(buf), fmt, args);
32: va_end(args);
33:
34: for( p=buf; *p; p++ )
35: putchar(*p);
36: return i;
37: }
38:
39: /* Private functions for mapping between physical/virtual addresses */
40: phys_addr_t
41: va2pa(unsigned long va)
42: {
43: if ((va >= (unsigned long)&_start) &&
44: (va < (unsigned long)&_end))
45: return va - va_shift;
46: else
47: return va;
48: }
49:
50: unsigned long
51: pa2va(phys_addr_t pa)
52: {
53: if ((pa + va_shift >= (unsigned long)&_start) &&
54: (pa + va_shift < (unsigned long)&_end))
55: return pa + va_shift;
56: else
57: return pa;
58: }
59:
60: void *malloc(int size)
61: {
62: return ofmem_malloc(size);
63: }
64:
65: void* realloc( void *ptr, size_t size )
66: {
67: return ofmem_realloc(ptr, size);
68: }
69:
70: void free(void *ptr)
71: {
72: ofmem_free(ptr);
73: }
74:
75: #define PAGE_SIZE_4M (4 * 1024 * 1024)
76: #define PAGE_SIZE_512K (512 * 1024)
77: #define PAGE_SIZE_64K (64 * 1024)
78: #define PAGE_SIZE_8K (8 * 1024)
79: #define PAGE_MASK_4M (4 * 1024 * 1024 - 1)
80: #define PAGE_MASK_512K (512 * 1024 - 1)
81: #define PAGE_MASK_64K (64 * 1024 - 1)
82: #define PAGE_MASK_8K (8 * 1024 - 1)
83:
84: static void
85: mmu_open(void)
86: {
87: RET(-1);
88: }
89:
90: static void
91: mmu_close(void)
92: {
93: }
94:
95: void ofmem_walk_boot_map(translation_entry_cb cb)
96: {
97: unsigned long phys, virt, size, mode, data, mask;
98: unsigned int i;
99:
100: for (i = 0; i < 64; i++) {
101: data = spitfire_get_dtlb_data(i);
102: if (data & SPITFIRE_TTE_VALID) {
103: switch ((data >> 61) & 3) {
104: default:
105: case 0x0: /* 8k */
106: mask = 0xffffffffffffe000ULL;
107: size = PAGE_SIZE_8K;
108: break;
109: case 0x1: /* 64k */
110: mask = 0xffffffffffff0000ULL;
111: size = PAGE_SIZE_64K;
112: break;
113: case 0x2: /* 512k */
114: mask = 0xfffffffffff80000ULL;
115: size = PAGE_SIZE_512K;
116: break;
117: case 0x3: /* 4M */
118: mask = 0xffffffffffc00000ULL;
119: size = PAGE_SIZE_4M;
120: break;
121: }
122:
123: virt = spitfire_get_dtlb_tag(i);
124: virt &= mask;
125:
126: /* extract 41bit physical address */
127: phys = data & 0x000001fffffff000ULL;
128: phys &= mask;
129:
130: mode = data & 0xfff;
131:
132: cb(phys, virt, size, mode);
133: }
134: }
135: }
136:
137: /*
138: 3.6.5 translate
139: ( virt -- false | phys.lo ... phys.hi mode true )
140: */
141: static void
142: mmu_translate(void)
143: {
144: ucell virt, mode;
145: phys_addr_t phys;
146:
147: virt = POP();
148:
149: phys = ofmem_translate(virt, &mode);
150:
151: if (phys != -1UL) {
152: PUSH(phys & 0xffffffff);
153: PUSH(phys >> 32);
154: PUSH(mode);
155: PUSH(-1);
156: }
157: else {
158: PUSH(0);
159: }
160: }
161:
162: /*
163: * D5.3 pgmap@ ( va -- tte )
164: */
165: static void
166: pgmap_fetch(void)
167: {
168: translation_t *t = *g_ofmem_translations;
169: unsigned long va, tte_data;
170:
171: va = POP();
172:
173: /* Search the ofmem linked list for this virtual address */
174: while (t != NULL) {
175: /* Find the correct range */
176: if (va >= t->virt && va < (t->virt + t->size)) {
177:
178: /* valid tte, 8k size */
179: tte_data = SPITFIRE_TTE_VALID;
180:
181: /* mix in phys address mode */
182: tte_data |= t->mode;
183:
184: /* mix in page physical address = t->phys + offset */
185: tte_data |= t->phys + (va - t->virt);
186:
187: /* return tte_data */
188: PUSH(tte_data);
189:
190: return;
191: }
192: t = t->next;
193: }
194:
195: /* If we get here, there was no entry */
196: PUSH(0);
197: }
198:
199: static void
200: dtlb_load2(unsigned long vaddr, unsigned long tte_data)
201: {
202: asm("stxa %0, [%1] %2\n"
203: "stxa %3, [%%g0] %4\n"
204: : : "r" (vaddr), "r" (48), "i" (ASI_DMMU),
205: "r" (tte_data), "i" (ASI_DTLB_DATA_IN));
206: }
207:
208: static void
209: dtlb_load3(unsigned long vaddr, unsigned long tte_data,
210: unsigned long tte_index)
211: {
212: asm("stxa %0, [%1] %2\n"
213: "stxa %3, [%4] %5\n"
214: : : "r" (vaddr), "r" (48), "i" (ASI_DMMU),
215: "r" (tte_data), "r" (tte_index << 3), "i" (ASI_DTLB_DATA_ACCESS));
216: }
217:
218: static unsigned long
219: dtlb_faultva(void)
220: {
221: unsigned long faultva;
222:
223: asm("ldxa [%1] %2, %0\n"
224: : "=r" (faultva)
225: : "r" (48), "i" (ASI_DMMU));
226:
227: return faultva;
228: }
229:
230: /*
231: ( index tte_data vaddr -- ? )
232: */
233: static void
234: dtlb_load(void)
235: {
236: unsigned long vaddr, tte_data, idx;
237:
238: vaddr = POP();
239: tte_data = POP();
240: idx = POP();
241: dtlb_load3(vaddr, tte_data, idx);
242: }
243:
244: /* MMU D-TLB miss handler */
245: void
246: dtlb_miss_handler(void)
247: {
248: unsigned long faultva, tte_data = 0;
249:
250: /* Grab fault address from MMU and round to nearest 8k page */
251: faultva = dtlb_faultva();
252: faultva >>= 13;
253: faultva <<= 13;
254:
255: /* If a valid va>tte-data routine has been set, invoke that Forth xt instead */
256: if (va2ttedata && *va2ttedata != 0) {
257:
258: /* va>tte-data ( addr cnum -- false | tte-data true ) */
259: PUSH(faultva);
260: PUSH(0);
261: enterforth(*va2ttedata);
262:
263: /* Check the result first... */
264: tte_data = POP();
265: if (!tte_data) {
266: bug();
267: } else {
268: /* Grab the real data */
269: tte_data = POP();
270: }
271: } else {
272: /* Search the ofmem linked list for this virtual address */
273: PUSH(faultva);
274: pgmap_fetch();
275: tte_data = POP();
276: }
277:
278: if (tte_data) {
279: /* Update MMU */
280: dtlb_load2(faultva, tte_data);
281: } else {
282: /* If we got here, there was no translation so fail */
283: bug();
284: }
285:
286: }
287:
288: static void
289: itlb_load2(unsigned long vaddr, unsigned long tte_data)
290: {
291: asm("stxa %0, [%1] %2\n"
292: "stxa %3, [%%g0] %4\n"
293: : : "r" (vaddr), "r" (48), "i" (ASI_IMMU),
294: "r" (tte_data), "i" (ASI_ITLB_DATA_IN));
295: }
296:
297: static void
298: itlb_load3(unsigned long vaddr, unsigned long tte_data,
299: unsigned long tte_index)
300: {
301: asm("stxa %0, [%1] %2\n"
302: "stxa %3, [%4] %5\n"
303: : : "r" (vaddr), "r" (48), "i" (ASI_IMMU),
304: "r" (tte_data), "r" (tte_index << 3), "i" (ASI_ITLB_DATA_ACCESS));
305: }
306:
307: /*
308: ( index tte_data vaddr -- ? )
309: */
310: static void
311: itlb_load(void)
312: {
313: unsigned long vaddr, tte_data, idx;
314:
315: vaddr = POP();
316: tte_data = POP();
317: idx = POP();
318: itlb_load3(vaddr, tte_data, idx);
319: }
320:
321: static unsigned long
322: itlb_faultva(void)
323: {
324: unsigned long faultva;
325:
326: asm("ldxa [%1] %2, %0\n"
327: : "=r" (faultva)
328: : "r" (48), "i" (ASI_IMMU));
329:
330: return faultva;
331: }
332:
333: /* MMU I-TLB miss handler */
334: void
335: itlb_miss_handler(void)
336: {
337: unsigned long faultva, tte_data = 0;
338:
339: /* Grab fault address from MMU and round to nearest 8k page */
340: faultva = itlb_faultva();
341: faultva >>= 13;
342: faultva <<= 13;
343:
344: /* If a valid va>tte-data routine has been set, invoke that Forth xt instead */
345: if (va2ttedata && *va2ttedata != 0) {
346:
347: /* va>tte-data ( addr cnum -- false | tte-data true ) */
348: PUSH(faultva);
349: PUSH(0);
350: enterforth(*va2ttedata);
351:
352: /* Check the result first... */
353: tte_data = POP();
354: if (!tte_data) {
355: bug();
356: } else {
357: /* Grab the real data */
358: tte_data = POP();
359: }
360: } else {
361: /* Search the ofmem linked list for this virtual address */
362: PUSH(faultva);
363: pgmap_fetch();
364: tte_data = POP();
365: }
366:
367: if (tte_data) {
368: /* Update MMU */
369: itlb_load2(faultva, tte_data);
370: } else {
371: /* If we got here, there was no translation so fail */
372: bug();
373: }
374: }
375:
376: static void
377: map_pages(phys_addr_t phys, unsigned long virt,
378: unsigned long size, unsigned long mode)
379: {
380: unsigned long tte_data, currsize;
381:
382: /* aligned to 8k page */
383: size = (size + PAGE_MASK_8K) & ~PAGE_MASK_8K;
384:
385: while (size > 0) {
386: currsize = size;
387: if (currsize >= PAGE_SIZE_4M &&
388: (virt & PAGE_MASK_4M) == 0 &&
389: (phys & PAGE_MASK_4M) == 0) {
390: currsize = PAGE_SIZE_4M;
391: tte_data = 6ULL << 60;
392: } else if (currsize >= PAGE_SIZE_512K &&
393: (virt & PAGE_MASK_512K) == 0 &&
394: (phys & PAGE_MASK_512K) == 0) {
395: currsize = PAGE_SIZE_512K;
396: tte_data = 4ULL << 60;
397: } else if (currsize >= PAGE_SIZE_64K &&
398: (virt & PAGE_MASK_64K) == 0 &&
399: (phys & PAGE_MASK_64K) == 0) {
400: currsize = PAGE_SIZE_64K;
401: tte_data = 2ULL << 60;
402: } else {
403: currsize = PAGE_SIZE_8K;
404: tte_data = 0;
405: }
406:
407: tte_data |= phys | mode | SPITFIRE_TTE_VALID;
408:
409: itlb_load2(virt, tte_data);
410: dtlb_load2(virt, tte_data);
411:
412: size -= currsize;
413: phys += currsize;
414: virt += currsize;
415: }
416: }
417:
418: void ofmem_map_pages(phys_addr_t phys, ucell virt, ucell size, ucell mode)
419: {
420: return map_pages(phys, virt, size, mode);
421: }
422:
423: /*
424: 3.6.5 map
425: ( phys.lo ... phys.hi virt size mode -- )
426: */
427: static void
428: mmu_map(void)
429: {
430: ucell virt, size, mode;
431: phys_addr_t phys;
432:
433: mode = POP();
434: size = POP();
435: virt = POP();
436: phys = POP();
437: phys <<= 32;
438: phys |= POP();
439:
440: ofmem_map(phys, virt, size, mode);
441: }
442:
443: static void
444: itlb_demap(unsigned long vaddr)
445: {
446: asm("stxa %0, [%0] %1\n"
447: : : "r" (vaddr), "i" (ASI_IMMU_DEMAP));
448: }
449:
450: static void
451: dtlb_demap(unsigned long vaddr)
452: {
453: asm("stxa %0, [%0] %1\n"
454: : : "r" (vaddr), "i" (ASI_DMMU_DEMAP));
455: }
456:
457: static void
458: unmap_pages(ucell virt, ucell size)
459: {
460: ucell va;
461:
462: /* align address to 8k */
463: virt &= ~PAGE_MASK_8K;
464:
465: /* align size to 8k */
466: size = (size + PAGE_MASK_8K) & ~PAGE_MASK_8K;
467:
468: for (va = virt; va < virt + size; va += PAGE_SIZE_8K) {
469: itlb_demap(va);
470: dtlb_demap(va);
471: }
472: }
473:
474: void ofmem_arch_unmap_pages(ucell virt, ucell size)
475: {
476: unmap_pages(virt, size);
477: }
478:
479: void ofmem_arch_early_map_pages(phys_addr_t phys, ucell virt, ucell size, ucell mode)
480: {
481: if (mode & SPITFIRE_TTE_LOCKED) {
482: // install locked tlb entries now
483: ofmem_map_pages(phys, virt, size, mode);
484: }
485: }
486:
487: /*
488: 3.6.5 unmap
489: ( virt size -- )
490: */
491: static void
492: mmu_unmap(void)
493: {
494: ucell virt, size;
495:
496: size = POP();
497: virt = POP();
498: ofmem_unmap(virt, size);
499: }
500:
501: /*
502: 3.6.5 claim
503: ( virt size align -- base )
504: */
505: static void
506: mmu_claim(void)
507: {
508: ucell virt=-1UL, size, align;
509:
510: align = POP();
511: size = POP();
512: if (!align) {
513: virt = POP();
514: }
515:
516: virt = ofmem_claim_virt(virt, size, align);
517:
518: PUSH(virt);
519: }
520:
521: /*
522: 3.6.5 release
523: ( virt size -- )
524: */
525: static void
526: mmu_release(void)
527: {
528: ucell virt, size;
529:
530: size = POP();
531: virt = POP();
532:
533: ofmem_release_virt(virt, size);
534: }
535:
536: /* ( phys size align --- base ) */
537: static void
538: mem_claim( void )
539: {
540: ucell size, align;
541: phys_addr_t phys=-1UL;
542:
543: align = POP();
544: size = POP();
545: if (!align) {
546: phys = POP();
547: phys <<= 32;
548: phys |= POP();
549: }
550:
551: phys = ofmem_claim_phys(phys, size, align);
552:
553: PUSH(phys & 0xffffffffUL);
554: PUSH(phys >> 32);
555: }
556:
557: /* ( phys size --- ) */
558: static void
559: mem_release( void )
560: {
561: phys_addr_t phys;
562: ucell size;
563:
564: size = POP();
565: phys = POP();
566: phys <<= 32;
567: phys |= POP();
568:
569: ofmem_release_phys(phys, size);
570: }
571:
572: /* ( name-cstr phys size align --- phys ) */
573: static void
574: mem_retain ( void )
575: {
576: ucell size, align;
577: phys_addr_t phys=-1UL;
578:
579: align = POP();
580: size = POP();
581: if (!align) {
582: phys = POP();
583: phys <<= 32;
584: phys |= POP();
585: }
586:
587: /* Currently do nothing with the name */
588: POP();
589:
590: phys = ofmem_retain(phys, size, align);
591:
592: PUSH(phys & 0xffffffffUL);
593: PUSH(phys >> 32);
594: }
595:
596: /* ( virt size align -- baseaddr|-1 ) */
597: static void
598: ciface_claim( void )
599: {
600: ucell align = POP();
601: ucell size = POP();
602: ucell virt = POP();
603: ucell ret = ofmem_claim( virt, size, align );
604:
605: /* printk("ciface_claim: %08x %08x %x\n", virt, size, align ); */
606: PUSH( ret );
607: }
608:
609: /* ( virt size -- ) */
610: static void
611: ciface_release( void )
612: {
613: ucell size = POP();
614: ucell virt = POP();
615: ofmem_release(virt, size);
616: }
617:
618: DECLARE_NODE(memory, INSTALL_OPEN, 0, "/memory");
619:
620: NODE_METHODS( memory ) = {
621: { "claim", mem_claim },
622: { "release", mem_release },
623: { "SUNW,retain", mem_retain },
624: };
625:
626: DECLARE_NODE(mmu, INSTALL_OPEN, 0, "/virtual-memory");
627:
628: NODE_METHODS(mmu) = {
629: { "open", mmu_open },
630: { "close", mmu_close },
631: { "translate", mmu_translate },
632: { "SUNW,dtlb-load", dtlb_load },
633: { "SUNW,itlb-load", itlb_load },
634: { "map", mmu_map },
635: { "unmap", mmu_unmap },
636: { "claim", mmu_claim },
637: { "release", mmu_release },
638: };
639:
640: void ob_mmu_init(const char *cpuname, uint64_t ram_size)
641: {
642: /* memory node */
643: REGISTER_NODE_METHODS(memory, "/memory");
644:
645: /* MMU node */
646: REGISTER_NODE_METHODS(mmu, "/virtual-memory");
647:
648: ofmem_register(find_dev("/memory"), find_dev("/virtual-memory"));
649:
650: push_str("/chosen");
651: fword("find-device");
652:
653: push_str("/virtual-memory");
654: fword("open-dev");
655: fword("encode-int");
656: push_str("mmu");
657: fword("property");
658:
659: push_str("/memory");
660: fword("find-device");
661:
662: /* All memory: 0 to RAM_size */
663: PUSH(0);
664: fword("encode-int");
665: PUSH(0);
666: fword("encode-int");
667: fword("encode+");
668: PUSH((int)(ram_size >> 32));
669: fword("encode-int");
670: fword("encode+");
671: PUSH((int)(ram_size & 0xffffffff));
672: fword("encode-int");
673: fword("encode+");
674: push_str("reg");
675: fword("property");
676:
677: push_str("/openprom/client-services");
678: fword("find-device");
679: bind_func("cif-claim", ciface_claim);
680: bind_func("cif-release", ciface_release);
681:
682: /* Other MMU functions */
683: PUSH(0);
684: fword("active-package!");
685: bind_func("pgmap@", pgmap_fetch);
686:
687: /* Find address of va2ttedata defer word contents for MMU miss handlers */
688: va2ttedata = (ucell *)findword("va>tte-data");
689: va2ttedata++;
690: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.