|
|
1.1 root 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"
1.1.1.2 ! root 12: #include "arch/sparc32/ofmem_sparc32.h"
1.1 root 13: #include "asm/asi.h"
14: #include "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: */
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;
1.1.1.2 ! root 59: unsigned long *l1;
1.1 root 60: static unsigned long *context_table;
61:
62: static ucell *mem_reg = 0;
63: static ucell *mem_avail = 0;
64: static ucell *virt_avail = 0;
65:
66: static struct linux_mlist_v0 totphys[1];
67: static struct linux_mlist_v0 totmap[1];
68: static struct linux_mlist_v0 totavail[1];
69:
70: struct linux_mlist_v0 *ptphys;
71: struct linux_mlist_v0 *ptmap;
72: struct linux_mlist_v0 *ptavail;
73:
74: /* Private functions for mapping between physical/virtual addresses */
75: phys_addr_t
76: va2pa(unsigned long va)
77: {
78: if ((va >= (unsigned long)&_start) &&
79: (va < (unsigned long)&_end))
80: return va - va_shift;
81: else
82: return va;
83: }
84:
85: unsigned long
86: pa2va(phys_addr_t pa)
87: {
88: if ((pa + va_shift >= (unsigned long)&_start) &&
89: (pa + va_shift < (unsigned long)&_end))
90: return pa + va_shift;
91: else
92: return pa;
93: }
94:
95: void *
96: malloc(int size)
97: {
98: return ofmem_malloc(size);
99: }
100:
101: void *
102: realloc( void *ptr, size_t size )
103: {
104: return ofmem_realloc(ptr, size);
105: }
106:
107: void
108: free(void *ptr)
109: {
110: ofmem_free(ptr);
111: }
112:
113: /*
114: * Allocate memory. This is reusable.
115: */
116: void
117: mem_init(struct mem *t, char *begin, char *limit)
118: {
119: t->start = begin;
120: t->uplim = limit;
121: t->curp = begin;
122: }
123:
124: void *
125: mem_alloc(struct mem *t, int size, int align)
126: {
127: char *p;
128: unsigned long pa;
129:
130: // The alignment restrictions refer to physical, not virtual
131: // addresses
132: pa = va2pa((unsigned long)t->curp) + (align - 1);
133: pa &= ~(align - 1);
134: p = (char *)pa2va(pa);
135:
136: if ((unsigned long)p >= (unsigned long)t->uplim ||
137: (unsigned long)p + size > (unsigned long)t->uplim)
138: return NULL;
139: t->curp = p + size;
140:
141: return p;
142: }
143:
144: /*
145: * D5.3 pgmap@ ( va -- pte )
146: */
147: static void
148: pgmap_fetch(void)
149: {
150: uint32_t pte;
151: unsigned long va, pa;
152:
153: va = POP();
154:
155: pa = find_pte(va, 0);
156: if (pa == 1 || pa == 2)
157: goto error;
158: pte = *(uint32_t *)pa;
159: DPRINTF("pgmap@: va 0x%lx pa 0x%lx pte 0x%x\n", va, pa, pte);
160:
161: PUSH(pte);
162: return;
163: error:
164: PUSH(0);
165: }
166:
167: /*
168: * D5.3 pgmap! ( pte va -- )
169: */
170: static void
171: pgmap_store(void)
172: {
173: uint32_t pte;
174: unsigned long va, pa;
175:
176: va = POP();
177: pte = POP();
178:
179: pa = find_pte(va, 1);
180: *(uint32_t *)pa = pte;
181: DPRINTF("pgmap!: va 0x%lx pa 0x%lx pte 0x%x\n", va, pa, pte);
182: }
183:
184: /*
185: * D5.3 map-pages ( pa space va size -- )
186: */
187: static void
188: ob_map_pages(void)
189: {
190: unsigned long va;
191: int size;
192: uint64_t pa;
193:
194: size = POP();
195: va = POP();
196: pa = POP();
197: pa <<= 32;
198: pa |= POP() & 0xffffffff;
199:
1.1.1.2 ! root 200: ofmem_arch_map_pages(pa, va, size, ofmem_arch_default_translation_mode(pa));
1.1 root 201: }
202:
203: static void
204: update_memory_properties(void)
205: {
206: /* Update the device tree memory properties from the master
207: totphys, totmap and totavail romvec arrays */
208: mem_reg[0] = 0;
209: mem_reg[1] = pointer2cell(totphys[0].start_adr);
210: mem_reg[2] = totphys[0].num_bytes;
211:
212: virt_avail[0] = 0;
213: virt_avail[1] = 0;
214: virt_avail[2] = pointer2cell(totmap[0].start_adr);
215:
216: mem_avail[0] = 0;
217: mem_avail[1] = pointer2cell(totavail[0].start_adr);
218: mem_avail[2] = totavail[0].num_bytes;
219: }
220:
221: static void
222: init_romvec_mem(void)
223: {
224: ptphys = totphys;
225: ptmap = totmap;
226: ptavail = totavail;
227:
228: /*
229: * Form memory descriptors.
230: */
231: totphys[0].theres_more = NULL;
232: totphys[0].start_adr = (char *) 0;
233: totphys[0].num_bytes = qemu_mem_size;
234:
235: totavail[0].theres_more = NULL;
236: totavail[0].start_adr = (char *) 0;
237: totavail[0].num_bytes = va2pa((int)&_start) - PAGE_SIZE;
238:
239: totmap[0].theres_more = NULL;
240: totmap[0].start_adr = &_start;
241: totmap[0].num_bytes = (unsigned long) &_iomem -
242: (unsigned long) &_start + PAGE_SIZE;
243:
244: /* Pointers to device tree memory properties */
245: mem_reg = malloc(sizeof(ucell) * 3);
246: mem_avail = malloc(sizeof(ucell) * 3);
247: virt_avail = malloc(sizeof(ucell) * 3);
248:
249: update_memory_properties();
250: }
251:
252: char *obp_dumb_mmap(char *va, int which_io, unsigned int pa,
253: unsigned int size)
254: {
255: uint64_t mpa = ((uint64_t)which_io << 32) | (uint64_t)pa;
256:
1.1.1.2 ! root 257: ofmem_arch_map_pages(mpa, (unsigned long)va, size, ofmem_arch_default_translation_mode(mpa));
1.1 root 258: return va;
259: }
260:
261: void obp_dumb_munmap(__attribute__((unused)) char *va,
262: __attribute__((unused)) unsigned int size)
263: {
264: DPRINTF("obp_dumb_munmap: virta 0x%x, sz %d\n", (unsigned int)va, size);
265: }
266:
267: char *obp_memalloc(char *va, unsigned int size, unsigned int align)
268: {
269: phys_addr_t phys;
270: ucell virt;
271:
272: /* Claim physical memory */
273: phys = ofmem_claim_phys(-1, size, align);
274:
275: /* Claim virtual memory */
276: virt = ofmem_claim_virt(pointer2cell(va), size, 0);
277:
278: /* Map the memory */
279: ofmem_map(phys, virt, size, ofmem_arch_default_translation_mode(phys));
280:
281: return cell2pointer(virt);
282: }
283:
284: char *obp_dumb_memalloc(char *va, unsigned int size)
285: {
286: unsigned long align;
287: int i;
288:
289: /* Solaris seems to assume that the returned value is physically aligned to size. For
290: example, not having this here causes the Solaris 8 kernel to fault because the
291: IOMMU page table base address is calculated incorrectly. */
292:
293: /* Enforce a minimum alignment of CONFIG_OFMEM_MALLOC_ALIGN, and choose an alignment
294: which is the next power of 2 higher than the specified size */
295: align = size;
296: if (align <= CONFIG_OFMEM_MALLOC_ALIGN) {
297: align = CONFIG_OFMEM_MALLOC_ALIGN;
298: } else {
299: align--;
300: for (i = 1; i < sizeof(unsigned long) * 8; i<<=1) {
301: align |= align >> i;
302: }
303: align++;
304: }
305:
306: return obp_memalloc(va, size, align);
307: }
308:
309: void obp_dumb_memfree(__attribute__((unused))char *va,
310: __attribute__((unused))unsigned sz)
311: {
312: DPRINTF("obp_dumb_memfree 0x%p (size %d)\n", va, sz);
313: }
314:
315: void
316: ob_init_mmu(void)
317: {
318: ucell *memreg;
319: ucell *virtreg;
320: phys_addr_t virtregsize;
321: ofmem_t *ofmem = ofmem_arch_get_private();
322:
323: init_romvec_mem();
324:
325: /* Find the phandles for the /memory and /virtual-memory nodes */
326: push_str("/memory");
327: fword("find-package");
328: POP();
329: s_phandle_memory = POP();
330:
331: push_str("/virtual-memory");
332: fword("find-package");
333: POP();
334: s_phandle_mmu = POP();
335:
336: ofmem_register(s_phandle_memory, s_phandle_mmu);
337:
338: /* Setup /memory:reg (totphys) property */
339: memreg = malloc(3 * sizeof(ucell));
340: ofmem_arch_encode_physaddr(memreg, 0); /* physical base */
341: memreg[2] = (ucell)ofmem->ramsize; /* size */
342:
343: push_str("/memory");
344: fword("find-device");
345: PUSH(pointer2cell(memreg));
346: PUSH(3 * sizeof(ucell));
347: push_str("reg");
348: PUSH_ph(s_phandle_memory);
349: fword("encode-property");
350:
351: /* Setup /virtual-memory:reg property */
352: virtregsize = ((phys_addr_t)((ucell)-1) + 1) / 2;
353:
354: virtreg = malloc(6 * sizeof(ucell));
355: ofmem_arch_encode_physaddr(virtreg, 0);
356: virtreg[2] = virtregsize;
357: ofmem_arch_encode_physaddr(&virtreg[3], virtregsize);
358: virtreg[5] = virtregsize;
359:
360: push_str("/virtual-memory");
361: fword("find-device");
362: PUSH(pointer2cell(virtreg));
363: PUSH(6 * sizeof(ucell));
364: push_str("reg");
365: PUSH_ph(s_phandle_mmu);
366: fword("encode-property");
367:
368: PUSH(0);
369: fword("active-package!");
370: bind_func("pgmap@", pgmap_fetch);
371: bind_func("pgmap!", pgmap_store);
372: bind_func("map-pages", ob_map_pages);
373: }
374:
375: /*
376: * Switch page tables.
377: */
378: void
379: init_mmu_swift(void)
380: {
381: unsigned int addr, i;
382: unsigned long pa, va;
383: int size;
384:
385: ofmem_posix_memalign((void *)&context_table, NCTX_SWIFT * sizeof(int),
386: NCTX_SWIFT * sizeof(int));
387: ofmem_posix_memalign((void *)&l1, 256 * sizeof(int), 256 * sizeof(int));
388:
389: context_table[0] = (((unsigned long)va2pa((unsigned long)l1)) >> 4) |
390: SRMMU_ET_PTD;
391:
392: for (i = 1; i < NCTX_SWIFT; i++) {
393: context_table[i] = SRMMU_ET_INVALID;
394: }
395: for (i = 0; i < 256; i += 4) {
396: l1[i] = SRMMU_ET_INVALID;
397: }
398:
399: // text, rodata, data, and bss mapped to end of RAM
400: va = (unsigned long)&_start;
401: size = (unsigned long)&_end - (unsigned long)&_start;
402: pa = va2pa(va);
1.1.1.2 ! root 403: ofmem_arch_map_pages(pa, va, size, ofmem_arch_default_translation_mode(pa));
1.1 root 404:
405: // 1:1 mapping for RAM
1.1.1.2 ! root 406: ofmem_arch_map_pages(0, 0, LOWMEMSZ, ofmem_arch_default_translation_mode(0));
1.1 root 407:
408: /*
409: * Flush cache
410: */
411: for (addr = 0; addr < 0x2000; addr += 0x10) {
412: __asm__ __volatile__ ("sta %%g0, [%0] %1\n\t" : :
413: "r" (addr), "i" (ASI_M_DATAC_TAG));
414: __asm__ __volatile__ ("sta %%g0, [%0] %1\n\t" : :
415: "r" (addr<<1), "i" (ASI_M_TXTC_TAG));
416: }
417: srmmu_set_context(0);
418: srmmu_set_ctable_ptr(va2pa((unsigned long)context_table));
419: srmmu_flush_whole_tlb();
420: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.