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