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 "arch/sparc64/ofmem_sparc64.h"
18 
19 /* Format a string and print it on the screen, just like the libc
20  * function printf.
21  */
printk(const char * fmt,...)22 int printk( const char *fmt, ... )
23 {
24         char *p, buf[512];
25 	va_list args;
26 	int i;
27 
28 	va_start(args, fmt);
29         i = vsnprintf(buf, sizeof(buf), fmt, args);
30 	va_end(args);
31 
32 	for( p=buf; *p; p++ )
33 		putchar(*p);
34 	return i;
35 }
36 
37 /* Private functions for mapping between physical/virtual addresses */
38 phys_addr_t
va2pa(unsigned long va)39 va2pa(unsigned long va)
40 {
41     if ((va >= (unsigned long)&_start) &&
42         (va < (unsigned long)&_end))
43         return va - va_shift;
44     else
45         return va;
46 }
47 
48 unsigned long
pa2va(phys_addr_t pa)49 pa2va(phys_addr_t pa)
50 {
51     if ((pa + va_shift >= (unsigned long)&_start) &&
52         (pa + va_shift < (unsigned long)&_end))
53         return pa + va_shift;
54     else
55         return pa;
56 }
57 
malloc(int size)58 void *malloc(int size)
59 {
60 	return ofmem_malloc(size);
61 }
62 
realloc(void * ptr,size_t size)63 void* realloc( void *ptr, size_t size )
64 {
65 	return ofmem_realloc(ptr, size);
66 }
67 
free(void * ptr)68 void free(void *ptr)
69 {
70 	ofmem_free(ptr);
71 }
72 
73 static void
mmu_open(void)74 mmu_open(void)
75 {
76     RET(-1);
77 }
78 
79 static void
mmu_close(void)80 mmu_close(void)
81 {
82 }
83 
ofmem_walk_boot_map(translation_entry_cb cb)84 void ofmem_walk_boot_map(translation_entry_cb cb)
85 {
86     unsigned long phys, virt, size, mode, data, mask;
87     unsigned int i;
88 
89     for (i = 0; i < 64; i++) {
90         data = spitfire_get_dtlb_data(i);
91         if (data & SPITFIRE_TTE_VALID) {
92             switch ((data >> 61) & 3) {
93             default:
94             case 0x0: /* 8k */
95                 mask = 0xffffffffffffe000ULL;
96                 size = PAGE_SIZE_8K;
97                 break;
98             case 0x1: /* 64k */
99                 mask = 0xffffffffffff0000ULL;
100                 size = PAGE_SIZE_64K;
101                 break;
102             case 0x2: /* 512k */
103                 mask = 0xfffffffffff80000ULL;
104                 size = PAGE_SIZE_512K;
105                 break;
106             case 0x3: /* 4M */
107                 mask = 0xffffffffffc00000ULL;
108                 size = PAGE_SIZE_4M;
109                 break;
110             }
111 
112             virt = spitfire_get_dtlb_tag(i);
113             virt &= mask;
114 
115             /* extract 41bit physical address */
116             phys = data & 0x000001fffffff000ULL;
117 			phys &= mask;
118 
119 			mode = data & 0xfff;
120 
121 			cb(phys, virt, size, mode);
122         }
123     }
124 }
125 
126 /*
127   3.6.5 translate
128   ( virt -- false | phys.lo ... phys.hi mode true )
129 */
130 static void
mmu_translate(void)131 mmu_translate(void)
132 {
133     ucell virt, mode;
134     phys_addr_t phys;
135 
136     virt = POP();
137 
138     phys = ofmem_translate(virt, &mode);
139 
140     if (phys != -1UL) {
141 		PUSH(phys & 0xffffffff);
142 		PUSH(phys >> 32);
143 		PUSH(mode);
144 		PUSH(-1);
145     }
146     else {
147     	PUSH(0);
148     }
149 }
150 
151 /*
152  * D5.3 pgmap@ ( va -- tte )
153  */
154 static void
pgmap_fetch(void)155 pgmap_fetch(void)
156 {
157     unsigned long va, tte_data;
158 
159     va = POP();
160 
161     tte_data = find_tte(va);
162     if (tte_data == -1)
163         goto error;
164 
165     /* return tte_data */
166     PUSH(tte_data);
167     return;
168 
169 error:
170     /* If we get here, there was no entry */
171     PUSH(0);
172 }
173 
174 /*
175   ( index tte_data vaddr -- ? )
176 */
177 static void
dtlb_load(void)178 dtlb_load(void)
179 {
180     unsigned long vaddr, tte_data, idx;
181 
182     vaddr = POP();
183     tte_data = POP();
184     idx = POP();
185     dtlb_load3(vaddr, tte_data, idx);
186 }
187 
188 /* MMU D-TLB miss handler */
189 void
dtlb_miss_handler(void)190 dtlb_miss_handler(void)
191 {
192 	unsigned long faultva, tte_data = 0;
193 
194 	/* Grab fault address from MMU and round to nearest 8k page */
195 	faultva = dtlb_faultva();
196 	faultva >>= 13;
197 	faultva <<= 13;
198 
199 	/* If a valid va>tte-data routine has been set, invoke that Forth xt instead */
200 	if (va2ttedata && *va2ttedata != 0) {
201 
202 		/* va>tte-data ( addr cnum -- false | tte-data true ) */
203 		PUSH(faultva);
204 		PUSH(0);
205 		enterforth(*va2ttedata);
206 
207 		/* Check the result first... */
208 		tte_data = POP();
209 		if (!tte_data) {
210 			bug();
211 		} else {
212 			/* Grab the real data */
213 			tte_data = POP();
214 		}
215 	} else {
216 		/* Search the ofmem linked list for this virtual address */
217 		tte_data = find_tte(faultva);
218 	}
219 
220 	if (tte_data) {
221 		/* Update MMU */
222 		dtlb_load2(faultva, tte_data);
223 	} else {
224 		/* If we got here, there was no translation so fail */
225 		bug();
226 	}
227 
228 }
229 
230 /*
231   ( index tte_data vaddr -- ? )
232 */
233 static void
itlb_load(void)234 itlb_load(void)
235 {
236     unsigned long vaddr, tte_data, idx;
237 
238     vaddr = POP();
239     tte_data = POP();
240     idx = POP();
241     itlb_load3(vaddr, tte_data, idx);
242 }
243 
244 /* MMU I-TLB miss handler */
245 void
itlb_miss_handler(void)246 itlb_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 = itlb_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 		tte_data = find_tte(faultva);
274 	}
275 
276 	if (tte_data) {
277 		/* Update MMU */
278 		itlb_load2(faultva, tte_data);
279 	} else {
280 		/* If we got here, there was no translation so fail */
281 		bug();
282 	}
283 }
284 
285 void
prom_debug_handler(void)286 prom_debug_handler(void)
287 {
288 	/* Execute the current debugger-hook */
289 	feval("debugger-hook");
290 }
291 
292 /*
293   3.6.5 map
294   ( phys.lo ... phys.hi virt size mode -- )
295 */
296 static void
mmu_map(void)297 mmu_map(void)
298 {
299     ucell virt, size, mode;
300     phys_addr_t phys;
301 
302     mode = POP();
303     size = POP();
304     virt = POP();
305     phys = POP();
306     phys <<= 32;
307     phys |= POP();
308 
309     ofmem_map(phys, virt, size, mode);
310 }
311 
312 /*
313   3.6.5 unmap
314   ( virt size -- )
315 */
316 static void
mmu_unmap(void)317 mmu_unmap(void)
318 {
319     ucell virt, size;
320 
321     size = POP();
322     virt = POP();
323     ofmem_unmap(virt, size);
324 }
325 
326 /*
327   3.6.5 claim
328   ( virt size align -- base )
329 */
330 static void
mmu_claim(void)331 mmu_claim(void)
332 {
333     ucell virt=-1UL, size, align;
334 
335     align = POP();
336     size = POP();
337     if (!align) {
338     	virt = POP();
339     }
340 
341     virt = ofmem_claim_virt(virt, size, align);
342 
343     PUSH(virt);
344 }
345 
346 /*
347   3.6.5 release
348   ( virt size -- )
349 */
350 static void
mmu_release(void)351 mmu_release(void)
352 {
353     ucell virt, size;
354 
355     size = POP();
356     virt = POP();
357 
358     ofmem_release_virt(virt, size);
359 }
360 
361 /* ( phys size align --- base ) */
362 static void
mem_claim(void)363 mem_claim( void )
364 {
365     ucell size, align;
366     phys_addr_t phys=-1UL;
367 
368     align = POP();
369     size = POP();
370     if (!align) {
371         phys = POP();
372         phys <<= 32;
373         phys |= POP();
374     }
375 
376     phys = ofmem_claim_phys(phys, size, align);
377 
378     PUSH(phys & 0xffffffffUL);
379     PUSH(phys >> 32);
380 }
381 
382 /* ( phys size --- ) */
383 static void
mem_release(void)384 mem_release( void )
385 {
386     phys_addr_t phys;
387     ucell size;
388 
389     size = POP();
390     phys = POP();
391     phys <<= 32;
392     phys |= POP();
393 
394     ofmem_release_phys(phys, size);
395 }
396 
397 /* ( name-cstr phys size align --- phys ) */
398 static void
mem_retain(void)399 mem_retain ( void )
400 {
401     ucell size, align;
402     phys_addr_t phys=-1UL;
403 
404     align = POP();
405     size = POP();
406     if (!align) {
407         phys = POP();
408         phys <<= 32;
409         phys |= POP();
410     }
411 
412     /* Currently do nothing with the name */
413     POP();
414 
415     phys = ofmem_retain(phys, size, align);
416 
417     PUSH(phys & 0xffffffffUL);
418     PUSH(phys >> 32);
419 }
420 
421 /* ( virt size align -- baseaddr|-1 ) */
422 static void
ciface_claim(void)423 ciface_claim( void )
424 {
425 	ucell align = POP();
426 	ucell size = POP();
427 	ucell virt = POP();
428 	ucell ret = ofmem_claim( virt, size, align );
429 
430 	/* printk("ciface_claim: %08x %08x %x\n", virt, size, align ); */
431 	PUSH( ret );
432 }
433 
434 /* ( virt size -- ) */
435 static void
ciface_release(void)436 ciface_release( void )
437 {
438 	ucell size = POP();
439 	ucell virt = POP();
440 	ofmem_release(virt, size);
441 }
442 
443 DECLARE_NODE(memory, INSTALL_OPEN, 0, "/memory");
444 
445 NODE_METHODS( memory ) = {
446     { "claim",              mem_claim       },
447     { "release",            mem_release     },
448     { "SUNW,retain",        mem_retain      },
449 };
450 
451 DECLARE_NODE(mmu, INSTALL_OPEN, 0, "/virtual-memory");
452 
453 NODE_METHODS(mmu) = {
454     { "open",               mmu_open              },
455     { "close",              mmu_close             },
456     { "translate",          mmu_translate         },
457     { "SUNW,dtlb-load",     dtlb_load             },
458     { "SUNW,itlb-load",     itlb_load             },
459     { "map",                mmu_map               },
460     { "unmap",              mmu_unmap             },
461     { "claim",              mmu_claim             },
462     { "release",            mmu_release           },
463 };
464 
ob_mmu_init(const char * cpuname,uint64_t ram_size)465 void ob_mmu_init(const char *cpuname, uint64_t ram_size)
466 {
467     /* memory node */
468     REGISTER_NODE(memory);
469 
470     /* MMU node */
471     REGISTER_NODE(mmu);
472 
473     ofmem_register(find_dev("/memory"), find_dev("/virtual-memory"));
474 
475     push_str("/chosen");
476     fword("find-device");
477 
478     push_str("/virtual-memory");
479     fword("open-dev");
480     fword("encode-int");
481     push_str("mmu");
482     fword("property");
483 
484     push_str("/memory");
485     fword("find-device");
486 
487     /* All memory: 0 to RAM_size */
488     PUSH(0);
489     fword("encode-int");
490     PUSH(0);
491     fword("encode-int");
492     fword("encode+");
493     PUSH((int)(ram_size >> 32));
494     fword("encode-int");
495     fword("encode+");
496     PUSH((int)(ram_size & 0xffffffff));
497     fword("encode-int");
498     fword("encode+");
499     push_str("reg");
500     fword("property");
501 
502     push_str("/openprom/client-services");
503     fword("find-device");
504     bind_func("cif-claim", ciface_claim);
505     bind_func("cif-release", ciface_release);
506 
507     /* Other MMU functions */
508     PUSH(0);
509     fword("active-package!");
510     bind_func("pgmap@", pgmap_fetch);
511 
512     /* Find address of va2ttedata defer word contents for MMU miss handlers */
513     va2ttedata = (ucell *)findword("va>tte-data");
514     va2ttedata++;
515 }
516