Tidy cell types and format strings
[openbios.git] / arch / sparc64 / lib.c
blob58286bae19cd9094897a447ed96bd7d63ac4b9b6
1 /* lib.c
2 * tag: simple function library
4 * Copyright (C) 2003 Stefan Reinauer
6 * See the file "COPYING" for further information about
7 * the copyright and warranty status of this work.
8 */
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"
17 #include "ofmem_sparc64.h"
19 static ucell *va2ttedata = 0;
21 /* Format a string and print it on the screen, just like the libc
22 * function printf.
24 int printk( const char *fmt, ... )
26 char *p, buf[512];
27 va_list args;
28 int i;
30 va_start(args, fmt);
31 i = vsnprintf(buf, sizeof(buf), fmt, args);
32 va_end(args);
34 for( p=buf; *p; p++ )
35 putchar(*p);
36 return i;
39 /* Private functions for mapping between physical/virtual addresses */
40 phys_addr_t
41 va2pa(unsigned long va)
43 if ((va >= (unsigned long)&_start) &&
44 (va < (unsigned long)&_end))
45 return va - va_shift;
46 else
47 return va;
50 unsigned long
51 pa2va(phys_addr_t pa)
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;
60 void *malloc(int size)
62 return ofmem_malloc(size);
65 void* realloc( void *ptr, size_t size )
67 return ofmem_realloc(ptr, size);
70 void free(void *ptr)
72 ofmem_free(ptr);
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)
84 static void
85 mmu_open(void)
87 RET(-1);
90 static void
91 mmu_close(void)
95 void ofmem_walk_boot_map(translation_entry_cb cb)
97 unsigned long phys, virt, size, mode, data, mask;
98 unsigned int i;
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;
123 virt = spitfire_get_dtlb_tag(i);
124 virt &= mask;
126 /* extract 41bit physical address */
127 phys = data & 0x000001fffffff000ULL;
128 phys &= mask;
130 mode = data & 0xfff;
132 cb(phys, virt, size, mode);
138 3.6.5 translate
139 ( virt -- false | phys.lo ... phys.hi mode true )
141 static void
142 mmu_translate(void)
144 ucell virt, mode;
145 phys_addr_t phys;
147 virt = POP();
149 phys = ofmem_translate(virt, &mode);
151 if (phys != -1UL) {
152 PUSH(phys & 0xffffffff);
153 PUSH(phys >> 32);
154 PUSH(mode);
155 PUSH(-1);
157 else {
158 PUSH(0);
163 * D5.3 pgmap@ ( va -- tte )
165 static void
166 pgmap_fetch(void)
168 translation_t *t = *g_ofmem_translations;
169 unsigned long va, tte_data;
171 va = POP();
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)) {
178 /* valid tte, 8k size */
179 tte_data = SPITFIRE_TTE_VALID;
181 /* mix in phys address mode */
182 tte_data |= t->mode;
184 /* mix in page physical address = t->phys + offset */
185 tte_data |= t->phys + (va - t->virt);
187 /* return tte_data */
188 PUSH(tte_data);
190 return;
192 t = t->next;
195 /* If we get here, there was no entry */
196 PUSH(0);
199 static void
200 dtlb_load2(unsigned long vaddr, unsigned long tte_data)
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));
208 static void
209 dtlb_load3(unsigned long vaddr, unsigned long tte_data,
210 unsigned long tte_index)
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));
218 static unsigned long
219 dtlb_faultva(void)
221 unsigned long faultva;
223 asm("ldxa [%1] %2, %0\n"
224 : "=r" (faultva)
225 : "r" (48), "i" (ASI_DMMU));
227 return faultva;
231 ( index tte_data vaddr -- ? )
233 static void
234 dtlb_load(void)
236 unsigned long vaddr, tte_data, idx;
238 vaddr = POP();
239 tte_data = POP();
240 idx = POP();
241 dtlb_load3(vaddr, tte_data, idx);
244 /* MMU D-TLB miss handler */
245 void
246 dtlb_miss_handler(void)
248 unsigned long faultva, tte_data = 0;
250 /* Grab fault address from MMU and round to nearest 8k page */
251 faultva = dtlb_faultva();
252 faultva >>= 13;
253 faultva <<= 13;
255 /* If a valid va>tte-data routine has been set, invoke that Forth xt instead */
256 if (va2ttedata && *va2ttedata != 0) {
258 /* va>tte-data ( addr cnum -- false | tte-data true ) */
259 PUSH(faultva);
260 PUSH(0);
261 enterforth(*va2ttedata);
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();
271 } else {
272 /* Search the ofmem linked list for this virtual address */
273 PUSH(faultva);
274 pgmap_fetch();
275 tte_data = POP();
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();
288 static void
289 itlb_load2(unsigned long vaddr, unsigned long tte_data)
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));
297 static void
298 itlb_load3(unsigned long vaddr, unsigned long tte_data,
299 unsigned long tte_index)
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));
308 ( index tte_data vaddr -- ? )
310 static void
311 itlb_load(void)
313 unsigned long vaddr, tte_data, idx;
315 vaddr = POP();
316 tte_data = POP();
317 idx = POP();
318 itlb_load3(vaddr, tte_data, idx);
321 static unsigned long
322 itlb_faultva(void)
324 unsigned long faultva;
326 asm("ldxa [%1] %2, %0\n"
327 : "=r" (faultva)
328 : "r" (48), "i" (ASI_IMMU));
330 return faultva;
333 /* MMU I-TLB miss handler */
334 void
335 itlb_miss_handler(void)
337 unsigned long faultva, tte_data = 0;
339 /* Grab fault address from MMU and round to nearest 8k page */
340 faultva = itlb_faultva();
341 faultva >>= 13;
342 faultva <<= 13;
344 /* If a valid va>tte-data routine has been set, invoke that Forth xt instead */
345 if (va2ttedata && *va2ttedata != 0) {
347 /* va>tte-data ( addr cnum -- false | tte-data true ) */
348 PUSH(faultva);
349 PUSH(0);
350 enterforth(*va2ttedata);
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();
360 } else {
361 /* Search the ofmem linked list for this virtual address */
362 PUSH(faultva);
363 pgmap_fetch();
364 tte_data = POP();
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();
376 static void
377 map_pages(phys_addr_t phys, unsigned long virt,
378 unsigned long size, unsigned long mode)
380 unsigned long tte_data, currsize;
382 /* aligned to 8k page */
383 size = (size + PAGE_MASK_8K) & ~PAGE_MASK_8K;
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;
407 tte_data |= phys | mode | SPITFIRE_TTE_VALID;
409 itlb_load2(virt, tte_data);
410 dtlb_load2(virt, tte_data);
412 size -= currsize;
413 phys += currsize;
414 virt += currsize;
418 void ofmem_map_pages(phys_addr_t phys, ucell virt, ucell size, ucell mode)
420 return map_pages(phys, virt, size, mode);
424 3.6.5 map
425 ( phys.lo ... phys.hi virt size mode -- )
427 static void
428 mmu_map(void)
430 ucell virt, size, mode;
431 phys_addr_t phys;
433 mode = POP();
434 size = POP();
435 virt = POP();
436 phys = POP();
437 phys <<= 32;
438 phys |= POP();
440 ofmem_map(phys, virt, size, mode);
443 static void
444 itlb_demap(unsigned long vaddr)
446 asm("stxa %0, [%0] %1\n"
447 : : "r" (vaddr), "i" (ASI_IMMU_DEMAP));
450 static void
451 dtlb_demap(unsigned long vaddr)
453 asm("stxa %0, [%0] %1\n"
454 : : "r" (vaddr), "i" (ASI_DMMU_DEMAP));
457 static void
458 unmap_pages(ucell virt, ucell size)
460 ucell va;
462 /* align address to 8k */
463 virt &= ~PAGE_MASK_8K;
465 /* align size to 8k */
466 size = (size + PAGE_MASK_8K) & ~PAGE_MASK_8K;
468 for (va = virt; va < virt + size; va += PAGE_SIZE_8K) {
469 itlb_demap(va);
470 dtlb_demap(va);
474 void ofmem_arch_unmap_pages(ucell virt, ucell size)
476 unmap_pages(virt, size);
479 void ofmem_arch_early_map_pages(phys_addr_t phys, ucell virt, ucell size, ucell mode)
481 if (mode & SPITFIRE_TTE_LOCKED) {
482 // install locked tlb entries now
483 ofmem_map_pages(phys, virt, size, mode);
488 3.6.5 unmap
489 ( virt size -- )
491 static void
492 mmu_unmap(void)
494 ucell virt, size;
496 size = POP();
497 virt = POP();
498 ofmem_unmap(virt, size);
502 3.6.5 claim
503 ( virt size align -- base )
505 static void
506 mmu_claim(void)
508 ucell virt=-1UL, size, align;
510 align = POP();
511 size = POP();
512 if (!align) {
513 virt = POP();
516 virt = ofmem_claim_virt(virt, size, align);
518 PUSH(virt);
522 3.6.5 release
523 ( virt size -- )
525 static void
526 mmu_release(void)
528 ucell virt, size;
530 size = POP();
531 virt = POP();
533 ofmem_release_virt(virt, size);
536 /* ( phys size align --- base ) */
537 static void
538 mem_claim( void )
540 ucell size, align;
541 phys_addr_t phys=-1UL;
543 align = POP();
544 size = POP();
545 if (!align) {
546 phys = POP();
547 phys <<= 32;
548 phys |= POP();
551 phys = ofmem_claim_phys(phys, size, align);
553 PUSH(phys & 0xffffffffUL);
554 PUSH(phys >> 32);
557 /* ( phys size --- ) */
558 static void
559 mem_release( void )
561 phys_addr_t phys;
562 ucell size;
564 size = POP();
565 phys = POP();
566 phys <<= 32;
567 phys |= POP();
569 ofmem_release_phys(phys, size);
572 /* ( name-cstr phys size align --- phys ) */
573 static void
574 mem_retain ( void )
576 ucell size, align;
577 phys_addr_t phys=-1UL;
579 align = POP();
580 size = POP();
581 if (!align) {
582 phys = POP();
583 phys <<= 32;
584 phys |= POP();
587 /* Currently do nothing with the name */
588 POP();
590 phys = ofmem_retain(phys, size, align);
592 PUSH(phys & 0xffffffffUL);
593 PUSH(phys >> 32);
596 /* ( virt size align -- baseaddr|-1 ) */
597 static void
598 ciface_claim( void )
600 ucell align = POP();
601 ucell size = POP();
602 ucell virt = POP();
603 ucell ret = ofmem_claim( virt, size, align );
605 /* printk("ciface_claim: %08x %08x %x\n", virt, size, align ); */
606 PUSH( ret );
609 /* ( virt size -- ) */
610 static void
611 ciface_release( void )
613 ucell size = POP();
614 ucell virt = POP();
615 ofmem_release(virt, size);
618 DECLARE_NODE(memory, INSTALL_OPEN, 0, "/memory");
620 NODE_METHODS( memory ) = {
621 { "claim", mem_claim },
622 { "release", mem_release },
623 { "SUNW,retain", mem_retain },
626 DECLARE_NODE(mmu, INSTALL_OPEN, 0, "/virtual-memory");
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 },
640 void ob_mmu_init(const char *cpuname, uint64_t ram_size)
642 /* memory node */
643 REGISTER_NODE_METHODS(memory, "/memory");
645 /* MMU node */
646 REGISTER_NODE_METHODS(mmu, "/virtual-memory");
648 ofmem_register(find_dev("/memory"), find_dev("/virtual-memory"));
650 push_str("/chosen");
651 fword("find-device");
653 push_str("/virtual-memory");
654 fword("open-dev");
655 fword("encode-int");
656 push_str("mmu");
657 fword("property");
659 push_str("/memory");
660 fword("find-device");
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");
677 push_str("/openprom/client-services");
678 fword("find-device");
679 bind_func("cif-claim", ciface_claim);
680 bind_func("cif-release", ciface_release);
682 /* Other MMU functions */
683 PUSH(0);
684 fword("active-package!");
685 bind_func("pgmap@", pgmap_fetch);
687 /* Find address of va2ttedata defer word contents for MMU miss handlers */
688 va2ttedata = (ucell *)findword("va>tte-data");
689 va2ttedata++;