Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / arch / sparc64 / ofmem_sparc64.c
diff --git a/qemu/roms/openbios/arch/sparc64/ofmem_sparc64.c b/qemu/roms/openbios/arch/sparc64/ofmem_sparc64.c
new file mode 100644 (file)
index 0000000..bdfaf56
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+ *     <ofmem_sparc64.c>
+ *
+ *     OF Memory manager
+ *
+ *   Copyright (C) 1999-2004 Samuel Rydh (samuel@ibrium.se)
+ *   Copyright (C) 2004 Stefan Reinauer
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation
+ *
+ */
+
+#include "config.h"
+#include "libopenbios/bindings.h"
+#include "libc/string.h"
+#include "arch/sparc64/ofmem_sparc64.h"
+#include "spitfire.h"
+
+#define OF_MALLOC_BASE         ((char*)OFMEM + ALIGN_SIZE(sizeof(ofmem_t), 8))
+
+#define MEMSIZE (128 * 1024)
+static union {
+       char memory[MEMSIZE];
+       ofmem_t ofmem;
+} s_ofmem_data;
+
+#define OFMEM          (&s_ofmem_data.ofmem)
+#define TOP_OF_RAM     (s_ofmem_data.memory + MEMSIZE)
+
+static retain_t s_retained;
+translation_t **g_ofmem_translations = &s_ofmem_data.ofmem.trans;
+
+ucell *va2ttedata = 0;
+extern uint64_t qemu_mem_size;
+
+static inline size_t ALIGN_SIZE(size_t x, size_t a)
+{
+    return (x + a - 1) & ~(a-1);
+}
+
+static ucell get_heap_top( void )
+{
+       return (ucell)TOP_OF_RAM;
+}
+
+ofmem_t* ofmem_arch_get_private(void)
+{
+       return OFMEM;
+}
+
+void* ofmem_arch_get_malloc_base(void)
+{
+       return OF_MALLOC_BASE;
+}
+
+ucell ofmem_arch_get_heap_top(void)
+{
+       return get_heap_top();
+}
+
+ucell ofmem_arch_get_virt_top(void)
+{
+       return (ucell)TOP_OF_RAM;
+}
+
+ucell ofmem_arch_get_iomem_base(void)
+{
+       /* Currently unused */
+       return 0;
+}
+
+ucell ofmem_arch_get_iomem_top(void)
+{
+       /* Currently unused */
+       return 0;
+}
+
+retain_t *ofmem_arch_get_retained(void)
+{
+       return (&s_retained);
+}
+
+int ofmem_arch_get_translation_entry_size(void)
+{
+       /* Return size of a single MMU package translation property entry in cells */
+       return 3;
+}
+
+void ofmem_arch_create_translation_entry(ucell *transentry, translation_t *t)
+{
+       /* Generate translation property entry for SPARC. While there is no
+       formal documentation for this, both Linux kernel and OpenSolaris sources
+       expect a translation property entry to have the following layout:
+
+               virtual address
+               length
+               mode (valid TTE for start of translation region)
+       */
+
+       transentry[0] = t->virt;
+       transentry[1] = t->size;
+       transentry[2] = t->phys | t->mode | SPITFIRE_TTE_VALID;
+}
+
+/* Return the size of a memory available entry given the phandle in cells */
+int ofmem_arch_get_available_entry_size(phandle_t ph)
+{
+       if (ph == s_phandle_memory) {
+               return 1 + ofmem_arch_get_physaddr_cellsize();
+       } else {
+               return 1 + 1;
+       }
+}
+
+/* Generate memory available property entry for Sparc64 */
+void ofmem_arch_create_available_entry(phandle_t ph, ucell *availentry, phys_addr_t start, ucell size)
+{
+       int i = 0;
+
+       if (ph == s_phandle_memory) {
+               i += ofmem_arch_encode_physaddr(availentry, start);
+       } else {
+               availentry[i++] = start;
+       }
+    
+       availentry[i] = size;
+}
+
+/* Unmap a set of pages */
+void ofmem_arch_unmap_pages(ucell virt, ucell size)
+{
+    ucell va;
+
+    /* align address to 8k */
+    virt &= ~PAGE_MASK_8K;
+
+    /* align size to 8k */
+    size = (size + PAGE_MASK_8K) & ~PAGE_MASK_8K;
+
+    for (va = virt; va < virt + size; va += PAGE_SIZE_8K) {
+        itlb_demap(va);
+        dtlb_demap(va);
+    }  
+}
+
+/* Map a set of pages */
+void ofmem_arch_map_pages(phys_addr_t phys, ucell virt, ucell size, ucell mode)
+{
+    unsigned long tte_data, currsize;
+
+    /* Install locked tlb entries now */
+    if (mode & SPITFIRE_TTE_LOCKED) {
+
+        /* aligned to 8k page */
+        size = (size + PAGE_MASK_8K) & ~PAGE_MASK_8K;
+
+        while (size > 0) {
+            currsize = size;
+            if (currsize >= PAGE_SIZE_4M &&
+                (virt & PAGE_MASK_4M) == 0 &&
+                (phys & PAGE_MASK_4M) == 0) {
+                currsize = PAGE_SIZE_4M;
+                tte_data = 6ULL << 60;
+            } else if (currsize >= PAGE_SIZE_512K &&
+                   (virt & PAGE_MASK_512K) == 0 &&
+                   (phys & PAGE_MASK_512K) == 0) {
+                currsize = PAGE_SIZE_512K;
+                tte_data = 4ULL << 60;
+            } else if (currsize >= PAGE_SIZE_64K &&
+                   (virt & PAGE_MASK_64K) == 0 &&
+                   (phys & PAGE_MASK_64K) == 0) {
+                currsize = PAGE_SIZE_64K;
+                tte_data = 2ULL << 60;
+            } else {
+                currsize = PAGE_SIZE_8K;
+                tte_data = 0;
+            }
+
+            tte_data |= phys | mode | SPITFIRE_TTE_VALID;
+
+            itlb_load2(virt, tte_data);
+            dtlb_load2(virt, tte_data);
+    
+            size -= currsize;
+            phys += currsize;
+            virt += currsize;
+        }
+    }
+}
+
+/************************************************************************/
+/* misc                                                                 */
+/************************************************************************/
+
+int ofmem_arch_get_physaddr_cellsize(void)
+{
+    return 1;
+}
+
+int ofmem_arch_encode_physaddr(ucell *p, phys_addr_t value)
+{
+    p[0] = value;
+    return 1;
+}
+
+ucell ofmem_arch_default_translation_mode( phys_addr_t phys )
+{
+       /* Writable, cacheable */
+       /* Privileged and not locked */
+       return SPITFIRE_TTE_CP | SPITFIRE_TTE_CV | SPITFIRE_TTE_WRITABLE | SPITFIRE_TTE_PRIVILEGED;
+}
+
+ucell ofmem_arch_io_translation_mode( phys_addr_t phys )
+{
+       /* Writable, privileged and not locked */
+       return SPITFIRE_TTE_CV | SPITFIRE_TTE_WRITABLE | SPITFIRE_TTE_PRIVILEGED;
+}
+
+/* Architecture-specific OFMEM helpers */
+unsigned long
+find_tte(unsigned long va)
+{
+       translation_t *t = *g_ofmem_translations;
+       unsigned long tte_data;
+       
+       /* Search the ofmem linked list for this virtual address */
+       while (t != NULL) {
+               /* Find the correct range */
+               if (va >= t->virt && va < (t->virt + t->size)) {
+
+                       /* valid tte, 8k size */
+                       tte_data = SPITFIRE_TTE_VALID;
+
+                       /* mix in phys address mode */
+                       tte_data |= t->mode;
+
+                       /* mix in page physical address = t->phys + offset */
+                       tte_data |= t->phys + (va - t->virt);
+
+                       /* return tte_data */
+                       return tte_data;
+               }
+               t = t->next;
+       }
+
+       /* Couldn't find tte */
+       return -1;
+}
+
+/* ITLB handlers */
+void
+itlb_load2(unsigned long vaddr, unsigned long tte_data)
+{
+    asm("stxa %0, [%1] %2\n"
+        "stxa %3, [%%g0] %4\n"
+        : : "r" (vaddr), "r" (48), "i" (ASI_IMMU),
+          "r" (tte_data), "i" (ASI_ITLB_DATA_IN));
+}
+
+void
+itlb_load3(unsigned long vaddr, unsigned long tte_data,
+           unsigned long tte_index)
+{
+    asm("stxa %0, [%1] %2\n"
+        "stxa %3, [%4] %5\n"
+        : : "r" (vaddr), "r" (48), "i" (ASI_IMMU),
+          "r" (tte_data), "r" (tte_index << 3), "i" (ASI_ITLB_DATA_ACCESS));
+}
+
+unsigned long
+itlb_faultva(void)
+{
+    unsigned long faultva;
+
+    asm("ldxa [%1] %2, %0\n"
+        : "=r" (faultva)
+        : "r" (48), "i" (ASI_IMMU));
+
+    return faultva;
+}
+
+void
+itlb_demap(unsigned long vaddr)
+{
+    asm("stxa %0, [%0] %1\n"
+        : : "r" (vaddr), "i" (ASI_IMMU_DEMAP));
+}
+
+/* DTLB handlers */
+void
+dtlb_load2(unsigned long vaddr, unsigned long tte_data)
+{
+    asm("stxa %0, [%1] %2\n"
+        "stxa %3, [%%g0] %4\n"
+        : : "r" (vaddr), "r" (48), "i" (ASI_DMMU),
+          "r" (tte_data), "i" (ASI_DTLB_DATA_IN));
+}
+
+void
+dtlb_load3(unsigned long vaddr, unsigned long tte_data,
+           unsigned long tte_index)
+{
+    asm("stxa %0, [%1] %2\n"
+        "stxa %3, [%4] %5\n"
+        : : "r" (vaddr), "r" (48), "i" (ASI_DMMU),
+          "r" (tte_data), "r" (tte_index << 3), "i" (ASI_DTLB_DATA_ACCESS));
+}
+
+unsigned long
+dtlb_faultva(void)
+{
+    unsigned long faultva;
+
+    asm("ldxa [%1] %2, %0\n"
+        : "=r" (faultva)
+        : "r" (48), "i" (ASI_DMMU));
+
+    return faultva;
+}
+
+void
+dtlb_demap(unsigned long vaddr)
+{
+    asm("stxa %0, [%0] %1\n"
+        : : "r" (vaddr), "i" (ASI_DMMU_DEMAP));
+}
+
+/************************************************************************/
+/* init / cleanup                                                       */
+/************************************************************************/
+
+static int remap_page_range( phys_addr_t phys, ucell virt, ucell size, ucell mode )
+{
+       ofmem_claim_phys(phys, size, 0);
+       ofmem_claim_virt(virt, size, 0);
+       ofmem_map_page_range(phys, virt, size, mode);
+       if (!(mode & SPITFIRE_TTE_LOCKED)) {
+               OFMEM_TRACE("remap_page_range clearing translation " FMT_ucellx
+                               " -> " FMT_ucellx " " FMT_ucellx " mode " FMT_ucellx "\n",
+                               virt, phys, size, mode );
+               ofmem_arch_unmap_pages(virt, size);
+       }
+       return 0;
+}
+
+#define RETAIN_MAGIC   0x1100220033004400
+
+void ofmem_init( void )
+{
+       retain_t *retained = ofmem_arch_get_retained();
+       int i;
+
+       memset(&s_ofmem_data, 0, sizeof(s_ofmem_data));
+       s_ofmem_data.ofmem.ramsize = qemu_mem_size;
+
+       /* inherit translations set up by entry.S */
+       ofmem_walk_boot_map(remap_page_range);
+
+        /* Map the memory */
+        ofmem_map_page_range(PAGE_SIZE, PAGE_SIZE, 0x800000, 0x36);
+
+       if (!(retained->magic == RETAIN_MAGIC)) {
+               OFMEM_TRACE("ofmem_init: no retained magic found, creating\n");
+               retained->magic = RETAIN_MAGIC;
+               retained->numentries = 0;
+       } else {
+               OFMEM_TRACE("ofmem_init: retained magic found, total %lld mappings\n", retained->numentries);   
+
+               /* Mark physical addresses as used so they are not reallocated */
+               for (i = 0; i < retained->numentries; i++) {
+                       ofmem_claim_phys(retained->retain_phys_range[i].start, 
+                               retained->retain_phys_range[i].size, 0);
+               }
+
+               /* Reset retained area for next reset */
+               retained->magic = RETAIN_MAGIC;
+               retained->numentries = 0;
+       }
+}