|
|
1.1 root 1: /*
2: * <ofmem_sparc64.c>
3: *
4: * OF Memory manager
5: *
6: * Copyright (C) 1999-2004 Samuel Rydh ([email protected])
7: * Copyright (C) 2004 Stefan Reinauer
8: *
9: * This program is free software; you can redistribute it and/or
10: * modify it under the terms of the GNU General Public License
11: * as published by the Free Software Foundation
12: *
13: */
14:
15: #include "config.h"
16: #include "libopenbios/bindings.h"
17: #include "libc/string.h"
1.1.1.2 ! root 18: #include "arch/sparc64/ofmem_sparc64.h"
1.1 root 19: #include "spitfire.h"
20:
21: #define OF_MALLOC_BASE ((char*)OFMEM + ALIGN_SIZE(sizeof(ofmem_t), 8))
22:
1.1.1.2 ! root 23: #define MEMSIZE (128 * 1024)
1.1 root 24: static union {
25: char memory[MEMSIZE];
26: ofmem_t ofmem;
27: } s_ofmem_data;
28:
29: #define OFMEM (&s_ofmem_data.ofmem)
30: #define TOP_OF_RAM (s_ofmem_data.memory + MEMSIZE)
31:
32: translation_t **g_ofmem_translations = &s_ofmem_data.ofmem.trans;
33:
1.1.1.2 ! root 34: ucell *va2ttedata = 0;
1.1 root 35: extern uint64_t qemu_mem_size;
36:
37: static inline size_t ALIGN_SIZE(size_t x, size_t a)
38: {
39: return (x + a - 1) & ~(a-1);
40: }
41:
42: static ucell get_heap_top( void )
43: {
44: return (ucell)(TOP_OF_RAM - ALIGN_SIZE(sizeof(retain_t), 8));
45: }
46:
47: ofmem_t* ofmem_arch_get_private(void)
48: {
49: return OFMEM;
50: }
51:
52: void* ofmem_arch_get_malloc_base(void)
53: {
54: return OF_MALLOC_BASE;
55: }
56:
57: ucell ofmem_arch_get_heap_top(void)
58: {
59: return get_heap_top();
60: }
61:
62: ucell ofmem_arch_get_virt_top(void)
63: {
64: return (ucell)TOP_OF_RAM;
65: }
66:
67: phys_addr_t ofmem_arch_get_phys_top(void)
68: {
69: ofmem_t *ofmem = ofmem_arch_get_private();
70:
71: return ofmem->ramsize;
72: }
73:
74: ucell ofmem_arch_get_iomem_base(void)
75: {
76: /* Currently unused */
77: return 0;
78: }
79:
80: ucell ofmem_arch_get_iomem_top(void)
81: {
82: /* Currently unused */
83: return 0;
84: }
85:
86: retain_t *ofmem_arch_get_retained(void)
87: {
88: /* Retained area is at the top of physical RAM */
89: return (retain_t *)(qemu_mem_size - sizeof(retain_t));
90: }
91:
92: int ofmem_arch_get_translation_entry_size(void)
93: {
94: /* Return size of a single MMU package translation property entry in cells */
95: return 3;
96: }
97:
98: void ofmem_arch_create_translation_entry(ucell *transentry, translation_t *t)
99: {
100: /* Generate translation property entry for SPARC. While there is no
101: formal documentation for this, both Linux kernel and OpenSolaris sources
102: expect a translation property entry to have the following layout:
103:
104: virtual address
105: length
106: mode
107: */
108:
109: transentry[0] = t->virt;
110: transentry[1] = t->size;
111: transentry[2] = t->mode;
112: }
113:
114: /* Return the size of a memory available entry given the phandle in cells */
115: int ofmem_arch_get_available_entry_size(phandle_t ph)
116: {
117: if (ph == s_phandle_memory) {
118: return 1 + ofmem_arch_get_physaddr_cellsize();
119: } else {
120: return 1 + 1;
121: }
122: }
123:
124: /* Generate memory available property entry for Sparc64 */
125: void ofmem_arch_create_available_entry(phandle_t ph, ucell *availentry, phys_addr_t start, ucell size)
126: {
127: int i = 0;
128:
129: if (ph == s_phandle_memory) {
130: i += ofmem_arch_encode_physaddr(availentry, start);
131: } else {
132: availentry[i++] = start;
133: }
134:
135: availentry[i] = size;
136: }
137:
1.1.1.2 ! root 138: /* Unmap a set of pages */
! 139: void ofmem_arch_unmap_pages(ucell virt, ucell size)
! 140: {
! 141: ucell va;
! 142:
! 143: /* align address to 8k */
! 144: virt &= ~PAGE_MASK_8K;
! 145:
! 146: /* align size to 8k */
! 147: size = (size + PAGE_MASK_8K) & ~PAGE_MASK_8K;
! 148:
! 149: for (va = virt; va < virt + size; va += PAGE_SIZE_8K) {
! 150: itlb_demap(va);
! 151: dtlb_demap(va);
! 152: }
! 153: }
! 154:
! 155: /* Map a set of pages */
! 156: void ofmem_arch_map_pages(phys_addr_t phys, ucell virt, ucell size, ucell mode)
! 157: {
! 158: unsigned long tte_data, currsize;
! 159:
! 160: /* Install locked tlb entries now */
! 161: if (mode & SPITFIRE_TTE_LOCKED) {
! 162:
! 163: /* aligned to 8k page */
! 164: size = (size + PAGE_MASK_8K) & ~PAGE_MASK_8K;
! 165:
! 166: while (size > 0) {
! 167: currsize = size;
! 168: if (currsize >= PAGE_SIZE_4M &&
! 169: (virt & PAGE_MASK_4M) == 0 &&
! 170: (phys & PAGE_MASK_4M) == 0) {
! 171: currsize = PAGE_SIZE_4M;
! 172: tte_data = 6ULL << 60;
! 173: } else if (currsize >= PAGE_SIZE_512K &&
! 174: (virt & PAGE_MASK_512K) == 0 &&
! 175: (phys & PAGE_MASK_512K) == 0) {
! 176: currsize = PAGE_SIZE_512K;
! 177: tte_data = 4ULL << 60;
! 178: } else if (currsize >= PAGE_SIZE_64K &&
! 179: (virt & PAGE_MASK_64K) == 0 &&
! 180: (phys & PAGE_MASK_64K) == 0) {
! 181: currsize = PAGE_SIZE_64K;
! 182: tte_data = 2ULL << 60;
! 183: } else {
! 184: currsize = PAGE_SIZE_8K;
! 185: tte_data = 0;
! 186: }
! 187:
! 188: tte_data |= phys | mode | SPITFIRE_TTE_VALID;
! 189:
! 190: itlb_load2(virt, tte_data);
! 191: dtlb_load2(virt, tte_data);
! 192:
! 193: size -= currsize;
! 194: phys += currsize;
! 195: virt += currsize;
! 196: }
! 197: }
! 198: }
! 199:
1.1 root 200: /************************************************************************/
201: /* misc */
202: /************************************************************************/
203:
204: int ofmem_arch_get_physaddr_cellsize(void)
205: {
206: return 1;
207: }
208:
209: int ofmem_arch_encode_physaddr(ucell *p, phys_addr_t value)
210: {
211: p[0] = value;
212: return 1;
213: }
214:
215: ucell ofmem_arch_default_translation_mode( phys_addr_t phys )
216: {
217: /* Writable, cacheable */
218: /* not privileged and not locked */
219: return SPITFIRE_TTE_CP | SPITFIRE_TTE_CV | SPITFIRE_TTE_WRITABLE;
220: }
221:
222: ucell ofmem_arch_io_translation_mode( phys_addr_t phys )
223: {
224: /* Writable, not privileged and not locked */
225: return SPITFIRE_TTE_CV | SPITFIRE_TTE_WRITABLE;
226: }
227:
1.1.1.2 ! root 228: /* Architecture-specific OFMEM helpers */
! 229: unsigned long
! 230: find_tte(unsigned long va)
! 231: {
! 232: translation_t *t = *g_ofmem_translations;
! 233: unsigned long tte_data;
! 234:
! 235: /* Search the ofmem linked list for this virtual address */
! 236: while (t != NULL) {
! 237: /* Find the correct range */
! 238: if (va >= t->virt && va < (t->virt + t->size)) {
! 239:
! 240: /* valid tte, 8k size */
! 241: tte_data = SPITFIRE_TTE_VALID;
! 242:
! 243: /* mix in phys address mode */
! 244: tte_data |= t->mode;
! 245:
! 246: /* mix in page physical address = t->phys + offset */
! 247: tte_data |= t->phys + (va - t->virt);
! 248:
! 249: /* return tte_data */
! 250: return tte_data;
! 251: }
! 252: t = t->next;
! 253: }
! 254:
! 255: /* Couldn't find tte */
! 256: return -1;
! 257: }
! 258:
! 259: /* ITLB handlers */
! 260: void
! 261: itlb_load2(unsigned long vaddr, unsigned long tte_data)
! 262: {
! 263: asm("stxa %0, [%1] %2\n"
! 264: "stxa %3, [%%g0] %4\n"
! 265: : : "r" (vaddr), "r" (48), "i" (ASI_IMMU),
! 266: "r" (tte_data), "i" (ASI_ITLB_DATA_IN));
! 267: }
! 268:
! 269: void
! 270: itlb_load3(unsigned long vaddr, unsigned long tte_data,
! 271: unsigned long tte_index)
! 272: {
! 273: asm("stxa %0, [%1] %2\n"
! 274: "stxa %3, [%4] %5\n"
! 275: : : "r" (vaddr), "r" (48), "i" (ASI_IMMU),
! 276: "r" (tte_data), "r" (tte_index << 3), "i" (ASI_ITLB_DATA_ACCESS));
! 277: }
! 278:
! 279: unsigned long
! 280: itlb_faultva(void)
! 281: {
! 282: unsigned long faultva;
! 283:
! 284: asm("ldxa [%1] %2, %0\n"
! 285: : "=r" (faultva)
! 286: : "r" (48), "i" (ASI_IMMU));
! 287:
! 288: return faultva;
! 289: }
! 290:
! 291: void
! 292: itlb_demap(unsigned long vaddr)
! 293: {
! 294: asm("stxa %0, [%0] %1\n"
! 295: : : "r" (vaddr), "i" (ASI_IMMU_DEMAP));
! 296: }
! 297:
! 298: /* DTLB handlers */
! 299: void
! 300: dtlb_load2(unsigned long vaddr, unsigned long tte_data)
! 301: {
! 302: asm("stxa %0, [%1] %2\n"
! 303: "stxa %3, [%%g0] %4\n"
! 304: : : "r" (vaddr), "r" (48), "i" (ASI_DMMU),
! 305: "r" (tte_data), "i" (ASI_DTLB_DATA_IN));
! 306: }
! 307:
! 308: void
! 309: dtlb_load3(unsigned long vaddr, unsigned long tte_data,
! 310: unsigned long tte_index)
! 311: {
! 312: asm("stxa %0, [%1] %2\n"
! 313: "stxa %3, [%4] %5\n"
! 314: : : "r" (vaddr), "r" (48), "i" (ASI_DMMU),
! 315: "r" (tte_data), "r" (tte_index << 3), "i" (ASI_DTLB_DATA_ACCESS));
! 316: }
! 317:
! 318: unsigned long
! 319: dtlb_faultva(void)
! 320: {
! 321: unsigned long faultva;
! 322:
! 323: asm("ldxa [%1] %2, %0\n"
! 324: : "=r" (faultva)
! 325: : "r" (48), "i" (ASI_DMMU));
! 326:
! 327: return faultva;
! 328: }
! 329:
! 330: void
! 331: dtlb_demap(unsigned long vaddr)
! 332: {
! 333: asm("stxa %0, [%0] %1\n"
! 334: : : "r" (vaddr), "i" (ASI_DMMU_DEMAP));
! 335: }
! 336:
1.1 root 337: /************************************************************************/
338: /* init / cleanup */
339: /************************************************************************/
340:
341: static int remap_page_range( phys_addr_t phys, ucell virt, ucell size, ucell mode )
342: {
343: ofmem_claim_phys(phys, size, 0);
344: ofmem_claim_virt(virt, size, 0);
345: ofmem_map_page_range(phys, virt, size, mode);
346: if (!(mode & SPITFIRE_TTE_LOCKED)) {
347: OFMEM_TRACE("remap_page_range clearing translation " FMT_ucellx
348: " -> " FMT_ucellx " " FMT_ucellx " mode " FMT_ucellx "\n",
349: virt, phys, size, mode );
350: ofmem_arch_unmap_pages(virt, size);
351: }
352: return 0;
353: }
354:
355: #define RETAIN_MAGIC 0x1100220033004400
356:
357: void ofmem_init( void )
358: {
359: retain_t *retained = ofmem_arch_get_retained();
360: int i;
361:
362: memset(&s_ofmem_data, 0, sizeof(s_ofmem_data));
363: s_ofmem_data.ofmem.ramsize = qemu_mem_size;
364:
365: /* inherit translations set up by entry.S */
366: ofmem_walk_boot_map(remap_page_range);
367:
368: /* Map the memory */
369: ofmem_map_page_range(0, 0, qemu_mem_size, 0x36);
370:
371: if (!(retained->magic == RETAIN_MAGIC)) {
372: OFMEM_TRACE("ofmem_init: no retained magic found, creating\n");
373: retained->magic = RETAIN_MAGIC;
374: retained->numentries = 0;
375: } else {
376: OFMEM_TRACE("ofmem_init: retained magic found, total %lld mappings\n", retained->numentries);
377:
378: /* Mark physical addresses as used so they are not reallocated */
379: for (i = 0; i < retained->numentries; i++) {
380: ofmem_claim_phys(retained->retain_phys_range[i].start,
381: retained->retain_phys_range[i].size, 0);
382: }
383:
384: /* Reset retained area for next reset */
385: retained->magic = RETAIN_MAGIC;
386: retained->numentries = 0;
387: }
388: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.