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 "libc/vsprintf.h"
11 #include "libopenbios/bindings.h"
12 #include "arch/sparc32/ofmem_sparc32.h"
13 #include "asm/asi.h"
14 #include "arch/sparc32/pgtsrmmu.h"
15 #include "openprom.h"
16 #include "libopenbios/sys_info.h"
17 #include "boot.h"
18 #include "romvec.h"
19
20 #define NCTX_SWIFT 0x100
21 #define LOWMEMSZ 32 * 1024 * 1024
22
23 #ifdef CONFIG_DEBUG_MEM
24 #define DPRINTF(fmt, args...) \
25 do { printk(fmt , ##args); } while (0)
26 #else
27 #define DPRINTF(fmt, args...)
28 #endif
29
30 /* Format a string and print it on the screen, just like the libc
31 * function printf.
32 */
printk(const char * fmt,...)33 int printk( const char *fmt, ... )
34 {
35 char *p, buf[512];
36 va_list args;
37 int i;
38
39 va_start(args, fmt);
40 i = vsnprintf(buf, sizeof(buf), fmt, args);
41 va_end(args);
42
43 for( p=buf; *p; p++ )
44 putchar(*p);
45 return i;
46 }
47
48 /*
49 * Allocatable memory chunk.
50 */
51 struct mem {
52 char *start, *uplim;
53 char *curp;
54 };
55
56 struct mem cdvmem; /* Current device virtual memory space */
57
58 unsigned int va_shift;
59 unsigned long *l1;
60 static unsigned long *context_table;
61
62 struct linux_mlist_v0 *ptphys;
63 struct linux_mlist_v0 *ptmap;
64 struct linux_mlist_v0 *ptavail;
65
66 /* Private functions for mapping between physical/virtual addresses */
67 phys_addr_t
va2pa(unsigned long va)68 va2pa(unsigned long va)
69 {
70 if ((va >= (unsigned long)&_start) &&
71 (va < (unsigned long)&_end))
72 return va - va_shift;
73 else
74 return va;
75 }
76
77 unsigned long
pa2va(phys_addr_t pa)78 pa2va(phys_addr_t pa)
79 {
80 if ((pa + va_shift >= (unsigned long)&_start) &&
81 (pa + va_shift < (unsigned long)&_end))
82 return pa + va_shift;
83 else
84 return pa;
85 }
86
87 void *
malloc(int size)88 malloc(int size)
89 {
90 return ofmem_malloc(size);
91 }
92
93 void *
realloc(void * ptr,size_t size)94 realloc( void *ptr, size_t size )
95 {
96 return ofmem_realloc(ptr, size);
97 }
98
99 void
free(void * ptr)100 free(void *ptr)
101 {
102 ofmem_free(ptr);
103 }
104
105 /*
106 * Allocate memory. This is reusable.
107 */
108 void
mem_init(struct mem * t,char * begin,char * limit)109 mem_init(struct mem *t, char *begin, char *limit)
110 {
111 t->start = begin;
112 t->uplim = limit;
113 t->curp = begin;
114 }
115
116 void *
mem_alloc(struct mem * t,int size,int align)117 mem_alloc(struct mem *t, int size, int align)
118 {
119 char *p;
120 unsigned long pa;
121
122 // The alignment restrictions refer to physical, not virtual
123 // addresses
124 pa = va2pa((unsigned long)t->curp) + (align - 1);
125 pa &= ~(align - 1);
126 p = (char *)pa2va(pa);
127
128 if ((unsigned long)p >= (unsigned long)t->uplim ||
129 (unsigned long)p + size > (unsigned long)t->uplim)
130 return NULL;
131 t->curp = p + size;
132
133 return p;
134 }
135
136 /*
137 * D5.3 pgmap@ ( va -- pte )
138 */
139 static void
pgmap_fetch(void)140 pgmap_fetch(void)
141 {
142 uint32_t pte;
143 unsigned long va, pa;
144
145 va = POP();
146
147 pa = find_pte(va, 0);
148 if (pa == 1 || pa == 2)
149 goto error;
150 pte = *(uint32_t *)pa;
151 DPRINTF("pgmap@: va 0x%lx pa 0x%lx pte 0x%x\n", va, pa, pte);
152
153 PUSH(pte);
154 return;
155 error:
156 PUSH(0);
157 }
158
159 /*
160 * D5.3 pgmap! ( pte va -- )
161 */
162 static void
pgmap_store(void)163 pgmap_store(void)
164 {
165 uint32_t pte;
166 unsigned long va, pa;
167
168 va = POP();
169 pte = POP();
170
171 pa = find_pte(va, 1);
172 *(uint32_t *)pa = pte;
173 DPRINTF("pgmap!: va 0x%lx pa 0x%lx pte 0x%x\n", va, pa, pte);
174 }
175
176 /*
177 * D5.3 map-pages ( pa space va size -- )
178 */
179 static void
ob_map_pages(void)180 ob_map_pages(void)
181 {
182 unsigned long va;
183 int size;
184 uint64_t pa;
185
186 size = POP();
187 va = POP();
188 pa = POP();
189 pa <<= 32;
190 pa |= POP() & 0xffffffff;
191
192 ofmem_arch_map_pages(pa, va, size, ofmem_arch_default_translation_mode(pa));
193 }
194
obp_dumb_mmap(char * va,int which_io,unsigned int pa,unsigned int size)195 char *obp_dumb_mmap(char *va, int which_io, unsigned int pa,
196 unsigned int size)
197 {
198 uint64_t mpa = ((uint64_t)which_io << 32) | (uint64_t)pa;
199 ucell virt;
200
201 DPRINTF("obp_dumb_mmap: virta 0x%x, phys 0x%x, size %d\n", (unsigned int)va, pa, size);
202
203 /* Claim virtual memory */
204 virt = ofmem_claim_virt(pointer2cell(va), size, 0);
205
206 /* Map memory */
207 ofmem_map(mpa, virt, size, ofmem_arch_default_translation_mode(mpa));
208
209 return cell2pointer(virt);
210 }
211
obp_dumb_munmap(char * va,unsigned int size)212 void obp_dumb_munmap(char *va, unsigned int size)
213 {
214 DPRINTF("obp_dumb_munmap: virta 0x%x, sz %d\n", (unsigned int)va, size);
215
216 ofmem_unmap(pointer2cell(va), size);
217 ofmem_release_virt(pointer2cell(va), size);
218 }
219
obp_memalloc(char * va,unsigned int size,unsigned int align)220 char *obp_memalloc(char *va, unsigned int size, unsigned int align)
221 {
222 phys_addr_t phys;
223 ucell virt;
224
225 DPRINTF("obp_memalloc: virta 0x%x, sz %d, align %d\n", (unsigned int)va, size, align);
226
227 /* Claim physical memory */
228 phys = ofmem_claim_phys(-1, size, align);
229
230 /* Claim virtual memory */
231 virt = ofmem_claim_virt(pointer2cell(va), size, 0);
232
233 /* Map the memory */
234 ofmem_map(phys, virt, size, ofmem_arch_default_translation_mode(phys));
235
236 return cell2pointer(virt);
237 }
238
obp_dumb_memalloc(char * va,unsigned int size)239 char *obp_dumb_memalloc(char *va, unsigned int size)
240 {
241 unsigned long align = size;
242 phys_addr_t phys;
243 ucell virt;
244
245 DPRINTF("obp_dumb_memalloc: virta 0x%x, sz %d\n", (unsigned int)va, size);
246
247 /* Solaris seems to assume that the returned value is physically aligned to size.
248 e.g. it is used for setting up page tables. */
249
250 /* Claim physical memory */
251 phys = ofmem_claim_phys(-1, size, align);
252
253 /* Claim virtual memory - if va == NULL then we choose va address */
254 if (va == NULL) {
255 virt = ofmem_claim_virt((ucell)-1, size, align);
256 } else {
257 virt = ofmem_claim_virt(pointer2cell(va), size, 0);
258 }
259
260 /* Map the memory */
261 ofmem_map(phys, virt, size, ofmem_arch_default_translation_mode(phys));
262
263 return cell2pointer(virt);
264 }
265
obp_dumb_memfree(char * va,unsigned size)266 void obp_dumb_memfree(char *va, unsigned size)
267 {
268 phys_addr_t phys;
269 ucell cellmode;
270
271 DPRINTF("obp_dumb_memfree: virta 0x%x, sz %d\n", (unsigned int)va, size);
272
273 phys = ofmem_translate(pointer2cell(va), &cellmode);
274
275 ofmem_unmap(pointer2cell(va), size);
276 ofmem_release_virt(pointer2cell(va), size);
277 ofmem_release_phys(phys, size);
278 }
279
280 /* Data fault handling routines */
281
282 extern unsigned int ignore_dfault;
283
284 /* ( -- reg ) */
srmmu_get_sfsr(void)285 static void srmmu_get_sfsr(void)
286 {
287 PUSH(srmmu_get_fstatus());
288 }
289
290 /* ( -- addr ) */
ignore_dfault_addr(void)291 static void ignore_dfault_addr(void)
292 {
293 PUSH(pointer2cell(&ignore_dfault));
294 }
295
296 void
ob_init_mmu(uint32_t simm_size)297 ob_init_mmu(uint32_t simm_size)
298 {
299 ucell *memreg;
300 ucell *virtreg;
301 phys_addr_t virtregsize;
302 ofmem_t *ofmem = ofmem_arch_get_private();
303 int i, c;
304
305 /* Find the phandles for the /memory and /virtual-memory nodes */
306 push_str("/memory");
307 fword("find-package");
308 POP();
309 s_phandle_memory = POP();
310
311 push_str("/virtual-memory");
312 fword("find-package");
313 POP();
314 s_phandle_mmu = POP();
315
316 ofmem_register(s_phandle_memory, s_phandle_mmu);
317
318 /* Setup /memory:reg (totphys) property */
319 c = ofmem->ramsize / simm_size;
320 memreg = malloc(3 * c * sizeof(ucell));
321 for (i = 0; i < c; i++) {
322 ofmem_arch_encode_physaddr(&memreg[i * 3], simm_size * i); /* physical base */
323 memreg[i * 3 + 2] = simm_size; /* size */
324 }
325
326 push_str("/memory");
327 fword("find-device");
328 PUSH(pointer2cell(memreg));
329 PUSH(3 * c * sizeof(ucell));
330 push_str("reg");
331 PUSH_ph(s_phandle_memory);
332 fword("encode-property");
333
334 /* Setup /virtual-memory:reg property */
335 virtregsize = ((phys_addr_t)((ucell)-1) + 1) / 2;
336
337 virtreg = malloc(6 * sizeof(ucell));
338 ofmem_arch_encode_physaddr(virtreg, 0);
339 virtreg[2] = virtregsize;
340 ofmem_arch_encode_physaddr(&virtreg[3], virtregsize);
341 virtreg[5] = virtregsize;
342
343 push_str("/virtual-memory");
344 fword("find-device");
345 PUSH(pointer2cell(virtreg));
346 PUSH(6 * sizeof(ucell));
347 push_str("reg");
348 PUSH_ph(s_phandle_mmu);
349 fword("encode-property");
350
351 PUSH(0);
352 fword("active-package!");
353 bind_func("pgmap@", pgmap_fetch);
354 bind_func("pgmap!", pgmap_store);
355 bind_func("map-pages", ob_map_pages);
356
357 /* Install data fault handler words for cpeek etc. */
358 PUSH_xt(bind_noname_func(srmmu_get_sfsr));
359 feval("to sfsr@");
360 PUSH_xt(bind_noname_func(ignore_dfault_addr));
361 feval("to ignore-dfault");
362 }
363
364 /*
365 * Switch page tables.
366 */
367 void
init_mmu_swift(void)368 init_mmu_swift(void)
369 {
370 unsigned int addr, i;
371 unsigned long pa, va;
372 int size;
373
374 ofmem_posix_memalign((void *)&context_table, NCTX_SWIFT * sizeof(int),
375 NCTX_SWIFT * sizeof(int));
376 ofmem_posix_memalign((void *)&l1, 256 * sizeof(int), 256 * sizeof(int));
377
378 context_table[0] = (((unsigned long)va2pa((unsigned long)l1)) >> 4) |
379 SRMMU_ET_PTD;
380
381 for (i = 1; i < NCTX_SWIFT; i++) {
382 context_table[i] = SRMMU_ET_INVALID;
383 }
384 for (i = 0; i < 256; i++) {
385 l1[i] = SRMMU_ET_INVALID;
386 }
387
388 // text, rodata, data, and bss mapped to end of RAM
389 va = (unsigned long)&_start;
390 size = (unsigned long)&_end - (unsigned long)&_start;
391 pa = va2pa(va);
392 ofmem_arch_map_pages(pa, va, size, ofmem_arch_default_translation_mode(pa));
393 ofmem_map_page_range(pa, va, size, ofmem_arch_default_translation_mode(pa));
394
395 // 1:1 mapping for RAM (don't map page 0 to allow catching of NULL dereferences)
396 ofmem_arch_map_pages(PAGE_SIZE, PAGE_SIZE, LOWMEMSZ - PAGE_SIZE, ofmem_arch_default_translation_mode(0));
397 ofmem_map_page_range(PAGE_SIZE, PAGE_SIZE, LOWMEMSZ - PAGE_SIZE, ofmem_arch_default_translation_mode(0));
398
399 /*
400 * Flush cache
401 */
402 for (addr = 0; addr < 0x2000; addr += 0x10) {
403 __asm__ __volatile__ ("sta %%g0, [%0] %1\n\t" : :
404 "r" (addr), "i" (ASI_M_DATAC_TAG));
405 __asm__ __volatile__ ("sta %%g0, [%0] %1\n\t" : :
406 "r" (addr<<1), "i" (ASI_M_TXTC_TAG));
407 }
408 srmmu_set_context(0);
409 srmmu_set_ctable_ptr(va2pa((unsigned long)context_table));
410 srmmu_flush_whole_tlb();
411 }
412