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.
11 #include "libc/vsprintf.h"
12 #include "libopenbios/bindings.h"
14 #include "libopenbios/sys_info.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
24 int printk( const char *fmt
, ... )
31 i
= vsnprintf(buf
, sizeof(buf
), fmt
, args
);
39 /* Private functions for mapping between physical/virtual addresses */
41 va2pa(unsigned long va
)
43 if ((va
>= (unsigned long)&_start
) &&
44 (va
< (unsigned long)&_end
))
53 if ((pa
+ va_shift
>= (unsigned long)&_start
) &&
54 (pa
+ va_shift
< (unsigned long)&_end
))
60 void *malloc(int size
)
62 return ofmem_malloc(size
);
65 void* realloc( void *ptr
, size_t size
)
67 return ofmem_realloc(ptr
, size
);
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)
95 void ofmem_walk_boot_map(translation_entry_cb cb
)
97 unsigned long phys
, virt
, size
, mode
, data
, mask
;
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) {
106 mask
= 0xffffffffffffe000ULL
;
110 mask
= 0xffffffffffff0000ULL
;
111 size
= PAGE_SIZE_64K
;
114 mask
= 0xfffffffffff80000ULL
;
115 size
= PAGE_SIZE_512K
;
118 mask
= 0xffffffffffc00000ULL
;
123 virt
= spitfire_get_dtlb_tag(i
);
126 /* extract 41bit physical address */
127 phys
= data
& 0x000001fffffff000ULL
;
132 cb(phys
, virt
, size
, mode
);
139 ( virt -- false | phys.lo ... phys.hi mode true )
149 phys
= ofmem_translate(virt
, &mode
);
152 PUSH(phys
& 0xffffffff);
163 * D5.3 pgmap@ ( va -- tte )
168 translation_t
*t
= *g_ofmem_translations
;
169 unsigned long va
, tte_data
;
173 /* Search the ofmem linked list for this virtual address */
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 */
184 /* mix in page physical address = t->phys + offset */
185 tte_data
|= t
->phys
+ (va
- t
->virt
);
187 /* return tte_data */
195 /* If we get here, there was no entry */
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
));
209 dtlb_load3(unsigned long vaddr
, unsigned long tte_data
,
210 unsigned long tte_index
)
212 asm("stxa %0, [%1] %2\n"
214 : : "r" (vaddr
), "r" (48), "i" (ASI_DMMU
),
215 "r" (tte_data
), "r" (tte_index
<< 3), "i" (ASI_DTLB_DATA_ACCESS
));
221 unsigned long faultva
;
223 asm("ldxa [%1] %2, %0\n"
225 : "r" (48), "i" (ASI_DMMU
));
231 ( index tte_data vaddr -- ? )
236 unsigned long vaddr
, tte_data
, idx
;
241 dtlb_load3(vaddr
, tte_data
, idx
);
244 /* MMU D-TLB miss handler */
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();
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 ) */
261 enterforth(*va2ttedata
);
263 /* Check the result first... */
268 /* Grab the real data */
272 /* Search the ofmem linked list for this virtual address */
280 dtlb_load2(faultva
, tte_data
);
282 /* If we got here, there was no translation so fail */
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
));
298 itlb_load3(unsigned long vaddr
, unsigned long tte_data
,
299 unsigned long tte_index
)
301 asm("stxa %0, [%1] %2\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 -- ? )
313 unsigned long vaddr
, tte_data
, idx
;
318 itlb_load3(vaddr
, tte_data
, idx
);
324 unsigned long faultva
;
326 asm("ldxa [%1] %2, %0\n"
328 : "r" (48), "i" (ASI_IMMU
));
333 /* MMU I-TLB miss handler */
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();
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 ) */
350 enterforth(*va2ttedata
);
352 /* Check the result first... */
357 /* Grab the real data */
361 /* Search the ofmem linked list for this virtual address */
369 itlb_load2(faultva
, tte_data
);
371 /* If we got here, there was no translation so fail */
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
;
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;
403 currsize
= PAGE_SIZE_8K
;
407 tte_data
|= phys
| mode
| SPITFIRE_TTE_VALID
;
409 itlb_load2(virt
, tte_data
);
410 dtlb_load2(virt
, tte_data
);
418 void ofmem_map_pages(phys_addr_t phys
, ucell virt
, ucell size
, ucell mode
)
420 return map_pages(phys
, virt
, size
, mode
);
425 ( phys.lo ... phys.hi virt size mode -- )
430 ucell virt
, size
, mode
;
440 ofmem_map(phys
, virt
, size
, mode
);
444 itlb_demap(unsigned long vaddr
)
446 asm("stxa %0, [%0] %1\n"
447 : : "r" (vaddr
), "i" (ASI_IMMU_DEMAP
));
451 dtlb_demap(unsigned long vaddr
)
453 asm("stxa %0, [%0] %1\n"
454 : : "r" (vaddr
), "i" (ASI_DMMU_DEMAP
));
458 unmap_pages(ucell virt
, ucell size
)
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
) {
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
);
498 ofmem_unmap(virt
, size
);
503 ( virt size align -- base )
508 ucell virt
=-1UL, size
, align
;
516 virt
= ofmem_claim_virt(virt
, size
, align
);
533 ofmem_release_virt(virt
, size
);
536 /* ( phys size align --- base ) */
541 phys_addr_t phys
=-1UL;
551 phys
= ofmem_claim_phys(phys
, size
, align
);
553 PUSH(phys
& 0xffffffffUL
);
557 /* ( phys size --- ) */
569 ofmem_release_phys(phys
, size
);
572 /* ( name-cstr phys size align --- phys ) */
577 phys_addr_t phys
=-1UL;
587 /* Currently do nothing with the name */
590 phys
= ofmem_retain(phys
, size
, align
);
592 PUSH(phys
& 0xffffffffUL
);
596 /* ( virt size align -- baseaddr|-1 ) */
603 ucell ret
= ofmem_claim( virt
, size
, align
);
605 /* printk("ciface_claim: %08x %08x %x\n", virt, size, align ); */
609 /* ( virt size -- ) */
611 ciface_release( void )
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
},
635 { "unmap", mmu_unmap
},
636 { "claim", mmu_claim
},
637 { "release", mmu_release
},
640 void ob_mmu_init(const char *cpuname
, uint64_t ram_size
)
643 REGISTER_NODE_METHODS(memory
, "/memory");
646 REGISTER_NODE_METHODS(mmu
, "/virtual-memory");
648 ofmem_register(find_dev("/memory"), find_dev("/virtual-memory"));
651 fword("find-device");
653 push_str("/virtual-memory");
660 fword("find-device");
662 /* All memory: 0 to RAM_size */
668 PUSH((int)(ram_size
>> 32));
671 PUSH((int)(ram_size
& 0xffffffff));
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 */
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");