6 * Copyright (C) 1999-2004 Samuel Rydh (samuel@ibrium.se)
7 * Copyright (C) 2004 Stefan Reinauer
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
16 #include "libopenbios/bindings.h"
17 #include "libc/string.h"
18 #include "arch/sparc64/ofmem_sparc64.h"
21 #define OF_MALLOC_BASE ((char*)OFMEM + ALIGN_SIZE(sizeof(ofmem_t), 8))
23 #define MEMSIZE (128 * 1024)
29 #define OFMEM (&s_ofmem_data.ofmem)
30 #define TOP_OF_RAM (s_ofmem_data.memory + MEMSIZE)
32 static retain_t s_retained;
33 translation_t **g_ofmem_translations = &s_ofmem_data.ofmem.trans;
35 ucell *va2ttedata = 0;
36 extern uint64_t qemu_mem_size;
38 static inline size_t ALIGN_SIZE(size_t x, size_t a)
40 return (x + a - 1) & ~(a-1);
43 static ucell get_heap_top( void )
45 return (ucell)TOP_OF_RAM;
48 ofmem_t* ofmem_arch_get_private(void)
53 void* ofmem_arch_get_malloc_base(void)
55 return OF_MALLOC_BASE;
58 ucell ofmem_arch_get_heap_top(void)
60 return get_heap_top();
63 ucell ofmem_arch_get_virt_top(void)
65 return (ucell)TOP_OF_RAM;
68 ucell ofmem_arch_get_iomem_base(void)
70 /* Currently unused */
74 ucell ofmem_arch_get_iomem_top(void)
76 /* Currently unused */
80 retain_t *ofmem_arch_get_retained(void)
85 int ofmem_arch_get_translation_entry_size(void)
87 /* Return size of a single MMU package translation property entry in cells */
91 void ofmem_arch_create_translation_entry(ucell *transentry, translation_t *t)
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:
99 mode (valid TTE for start of translation region)
102 transentry[0] = t->virt;
103 transentry[1] = t->size;
104 transentry[2] = t->phys | t->mode | SPITFIRE_TTE_VALID;
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)
110 if (ph == s_phandle_memory) {
111 return 1 + ofmem_arch_get_physaddr_cellsize();
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)
122 if (ph == s_phandle_memory) {
123 i += ofmem_arch_encode_physaddr(availentry, start);
125 availentry[i++] = start;
128 availentry[i] = size;
131 /* Unmap a set of pages */
132 void ofmem_arch_unmap_pages(ucell virt, ucell size)
136 /* align address to 8k */
137 virt &= ~PAGE_MASK_8K;
139 /* align size to 8k */
140 size = (size + PAGE_MASK_8K) & ~PAGE_MASK_8K;
142 for (va = virt; va < virt + size; va += PAGE_SIZE_8K) {
148 /* Map a set of pages */
149 void ofmem_arch_map_pages(phys_addr_t phys, ucell virt, ucell size, ucell mode)
151 unsigned long tte_data, currsize;
153 /* Install locked tlb entries now */
154 if (mode & SPITFIRE_TTE_LOCKED) {
156 /* aligned to 8k page */
157 size = (size + PAGE_MASK_8K) & ~PAGE_MASK_8K;
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;
177 currsize = PAGE_SIZE_8K;
181 tte_data |= phys | mode | SPITFIRE_TTE_VALID;
183 itlb_load2(virt, tte_data);
184 dtlb_load2(virt, tte_data);
193 /************************************************************************/
195 /************************************************************************/
197 int ofmem_arch_get_physaddr_cellsize(void)
202 int ofmem_arch_encode_physaddr(ucell *p, phys_addr_t value)
208 ucell ofmem_arch_default_translation_mode( phys_addr_t phys )
210 /* Writable, cacheable */
211 /* Privileged and not locked */
212 return SPITFIRE_TTE_CP | SPITFIRE_TTE_CV | SPITFIRE_TTE_WRITABLE | SPITFIRE_TTE_PRIVILEGED;
215 ucell ofmem_arch_io_translation_mode( phys_addr_t phys )
217 /* Writable, privileged and not locked */
218 return SPITFIRE_TTE_CV | SPITFIRE_TTE_WRITABLE | SPITFIRE_TTE_PRIVILEGED;
221 /* Architecture-specific OFMEM helpers */
223 find_tte(unsigned long va)
225 translation_t *t = *g_ofmem_translations;
226 unsigned long tte_data;
228 /* Search the ofmem linked list for this virtual address */
230 /* Find the correct range */
231 if (va >= t->virt && va < (t->virt + t->size)) {
233 /* valid tte, 8k size */
234 tte_data = SPITFIRE_TTE_VALID;
236 /* mix in phys address mode */
239 /* mix in page physical address = t->phys + offset */
240 tte_data |= t->phys + (va - t->virt);
242 /* return tte_data */
248 /* Couldn't find tte */
254 itlb_load2(unsigned long vaddr, unsigned long tte_data)
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));
263 itlb_load3(unsigned long vaddr, unsigned long tte_data,
264 unsigned long tte_index)
266 asm("stxa %0, [%1] %2\n"
268 : : "r" (vaddr), "r" (48), "i" (ASI_IMMU),
269 "r" (tte_data), "r" (tte_index << 3), "i" (ASI_ITLB_DATA_ACCESS));
275 unsigned long faultva;
277 asm("ldxa [%1] %2, %0\n"
279 : "r" (48), "i" (ASI_IMMU));
285 itlb_demap(unsigned long vaddr)
287 asm("stxa %0, [%0] %1\n"
288 : : "r" (vaddr), "i" (ASI_IMMU_DEMAP));
293 dtlb_load2(unsigned long vaddr, unsigned long tte_data)
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));
302 dtlb_load3(unsigned long vaddr, unsigned long tte_data,
303 unsigned long tte_index)
305 asm("stxa %0, [%1] %2\n"
307 : : "r" (vaddr), "r" (48), "i" (ASI_DMMU),
308 "r" (tte_data), "r" (tte_index << 3), "i" (ASI_DTLB_DATA_ACCESS));
314 unsigned long faultva;
316 asm("ldxa [%1] %2, %0\n"
318 : "r" (48), "i" (ASI_DMMU));
324 dtlb_demap(unsigned long vaddr)
326 asm("stxa %0, [%0] %1\n"
327 : : "r" (vaddr), "i" (ASI_DMMU_DEMAP));
330 /************************************************************************/
332 /************************************************************************/
334 static int remap_page_range( phys_addr_t phys, ucell virt, ucell size, ucell mode )
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);
348 #define RETAIN_MAGIC 0x1100220033004400
350 void ofmem_init( void )
352 retain_t *retained = ofmem_arch_get_retained();
355 memset(&s_ofmem_data, 0, sizeof(s_ofmem_data));
356 s_ofmem_data.ofmem.ramsize = qemu_mem_size;
358 /* inherit translations set up by entry.S */
359 ofmem_walk_boot_map(remap_page_range);
362 ofmem_map_page_range(PAGE_SIZE, PAGE_SIZE, 0x800000, 0x36);
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;
369 OFMEM_TRACE("ofmem_init: retained magic found, total %lld mappings\n", retained->numentries);
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);
377 /* Reset retained area for next reset */
378 retained->magic = RETAIN_MAGIC;
379 retained->numentries = 0;