Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / arch / sparc64 / lib.c
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  */
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
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
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
58 void *malloc(int size)
59 {
60         return ofmem_malloc(size);
61 }
62
63 void* realloc( void *ptr, size_t size )
64 {
65         return ofmem_realloc(ptr, size);
66 }
67
68 void free(void *ptr)
69 {
70         ofmem_free(ptr);
71 }
72
73 static void
74 mmu_open(void)
75 {
76     RET(-1);
77 }
78
79 static void
80 mmu_close(void)
81 {
82 }
83
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
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
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
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
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
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
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 /*
286   3.6.5 map
287   ( phys.lo ... phys.hi virt size mode -- )
288 */
289 static void
290 mmu_map(void)
291 {
292     ucell virt, size, mode;
293     phys_addr_t phys;
294
295     mode = POP();
296     size = POP();
297     virt = POP();
298     phys = POP();
299     phys <<= 32;
300     phys |= POP();
301
302     ofmem_map(phys, virt, size, mode);
303 }
304
305 /*
306   3.6.5 unmap
307   ( virt size -- )
308 */
309 static void
310 mmu_unmap(void)
311 {
312     ucell virt, size;
313
314     size = POP();
315     virt = POP();
316     ofmem_unmap(virt, size);
317 }
318
319 /*
320   3.6.5 claim
321   ( virt size align -- base )
322 */
323 static void
324 mmu_claim(void)
325 {
326     ucell virt=-1UL, size, align;
327
328     align = POP();
329     size = POP();
330     if (!align) {
331         virt = POP();
332     }
333
334     virt = ofmem_claim_virt(virt, size, align);
335
336     PUSH(virt);
337 }
338
339 /*
340   3.6.5 release
341   ( virt size -- )
342 */
343 static void
344 mmu_release(void)
345 {
346     ucell virt, size;
347
348     size = POP();
349     virt = POP();
350
351     ofmem_release_virt(virt, size);
352 }
353
354 /* ( phys size align --- base ) */
355 static void
356 mem_claim( void )
357 {
358     ucell size, align;
359     phys_addr_t phys=-1UL;
360
361     align = POP();
362     size = POP();
363     if (!align) {
364         phys = POP();
365         phys <<= 32;
366         phys |= POP();
367     }
368
369     phys = ofmem_claim_phys(phys, size, align);
370
371     PUSH(phys & 0xffffffffUL);
372     PUSH(phys >> 32);
373 }
374
375 /* ( phys size --- ) */
376 static void
377 mem_release( void )
378 {
379     phys_addr_t phys;
380     ucell size;
381
382     size = POP();
383     phys = POP();
384     phys <<= 32;
385     phys |= POP();
386
387     ofmem_release_phys(phys, size);
388 }
389
390 /* ( name-cstr phys size align --- phys ) */
391 static void
392 mem_retain ( void )
393 {
394     ucell size, align;
395     phys_addr_t phys=-1UL;
396
397     align = POP();
398     size = POP();
399     if (!align) {
400         phys = POP();
401         phys <<= 32;
402         phys |= POP();
403     }
404
405     /* Currently do nothing with the name */
406     POP();
407
408     phys = ofmem_retain(phys, size, align);
409
410     PUSH(phys & 0xffffffffUL);
411     PUSH(phys >> 32);
412 }
413
414 /* ( virt size align -- baseaddr|-1 ) */
415 static void
416 ciface_claim( void )
417 {
418         ucell align = POP();
419         ucell size = POP();
420         ucell virt = POP();
421         ucell ret = ofmem_claim( virt, size, align );
422
423         /* printk("ciface_claim: %08x %08x %x\n", virt, size, align ); */
424         PUSH( ret );
425 }
426
427 /* ( virt size -- ) */
428 static void
429 ciface_release( void )
430 {
431         ucell size = POP();
432         ucell virt = POP();
433         ofmem_release(virt, size);
434 }
435
436 DECLARE_NODE(memory, INSTALL_OPEN, 0, "/memory");
437
438 NODE_METHODS( memory ) = {
439     { "claim",              mem_claim       },
440     { "release",            mem_release     },
441     { "SUNW,retain",        mem_retain      },
442 };
443
444 DECLARE_NODE(mmu, INSTALL_OPEN, 0, "/virtual-memory");
445
446 NODE_METHODS(mmu) = {
447     { "open",               mmu_open              },
448     { "close",              mmu_close             },
449     { "translate",          mmu_translate         },
450     { "SUNW,dtlb-load",     dtlb_load             },
451     { "SUNW,itlb-load",     itlb_load             },
452     { "map",                mmu_map               },
453     { "unmap",              mmu_unmap             },
454     { "claim",              mmu_claim             },
455     { "release",            mmu_release           },
456 };
457
458 void ob_mmu_init(const char *cpuname, uint64_t ram_size)
459 {
460     /* memory node */
461     REGISTER_NODE_METHODS(memory, "/memory");
462
463     /* MMU node */
464     REGISTER_NODE_METHODS(mmu, "/virtual-memory");
465
466     ofmem_register(find_dev("/memory"), find_dev("/virtual-memory"));
467
468     push_str("/chosen");
469     fword("find-device");
470
471     push_str("/virtual-memory");
472     fword("open-dev");
473     fword("encode-int");
474     push_str("mmu");
475     fword("property");
476
477     push_str("/memory");
478     fword("find-device");
479
480     /* All memory: 0 to RAM_size */
481     PUSH(0);
482     fword("encode-int");
483     PUSH(0);
484     fword("encode-int");
485     fword("encode+");
486     PUSH((int)(ram_size >> 32));
487     fword("encode-int");
488     fword("encode+");
489     PUSH((int)(ram_size & 0xffffffff));
490     fword("encode-int");
491     fword("encode+");
492     push_str("reg");
493     fword("property");
494
495     push_str("/openprom/client-services");
496     fword("find-device");
497     bind_func("cif-claim", ciface_claim);
498     bind_func("cif-release", ciface_release);
499
500     /* Other MMU functions */
501     PUSH(0);
502     fword("active-package!");
503     bind_func("pgmap@", pgmap_fetch);
504
505     /* Find address of va2ttedata defer word contents for MMU miss handlers */
506     va2ttedata = (ucell *)findword("va>tte-data");
507     va2ttedata++;
508 }