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