Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / arch / sparc32 / ofmem_sparc32.c
diff --git a/qemu/roms/openbios/arch/sparc32/ofmem_sparc32.c b/qemu/roms/openbios/arch/sparc32/ofmem_sparc32.c
new file mode 100644 (file)
index 0000000..f7af753
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ *     <ofmem_sparc32.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/sparc32/ofmem_sparc32.h"
+#include "asm/asi.h"
+#include "pgtsrmmu.h"
+
+#define OF_MALLOC_BASE         ((char*)OFMEM + ALIGN_SIZE(sizeof(ofmem_t), 8))
+
+#define MEMSIZE (256 * 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)
+
+#define OFMEM_PHYS_RESERVED    0x1000000
+
+translation_t **g_ofmem_translations = &s_ofmem_data.ofmem.trans;
+
+extern uint32_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)OFMEM_VIRT_TOP;
+}
+
+ucell ofmem_arch_get_iomem_base(void)
+{
+       return pointer2cell(&_end);
+}
+
+ucell ofmem_arch_get_iomem_top(void)
+{
+       return pointer2cell(&_iomem);
+}
+
+retain_t *ofmem_arch_get_retained(void)
+{
+       /* Not used */
+       return 0;
+}
+
+int ofmem_arch_get_physaddr_cellsize(void)
+{
+       return 2;
+}
+
+int ofmem_arch_encode_physaddr(ucell *p, phys_addr_t value)
+{
+       int n = 0;
+
+       p[n++] = value >> 32;
+       p[n++] = value;
+
+       return n;
+}
+
+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
+       */
+
+       transentry[0] = t->virt;
+       transentry[1] = t->size;
+       transentry[2] = t->mode;
+}
+
+/* Return the size of a memory available entry given the phandle in cells */
+int ofmem_arch_get_available_entry_size(phandle_t ph)
+{
+       return 1 + ofmem_arch_get_physaddr_cellsize();
+}
+
+/* Generate memory available property entry for Sparc32 */
+void ofmem_arch_create_available_entry(phandle_t ph, ucell *availentry, phys_addr_t start, ucell size)
+{
+  int i = 0;
+
+       i += ofmem_arch_encode_physaddr(availentry, start);
+       availentry[i] = size;
+}
+
+/* Unmap a set of pages */
+void ofmem_arch_unmap_pages(ucell virt, ucell size)
+{
+       unsigned long pa;
+       ucell i;
+
+       for (i = 0; i < size; i += PAGE_SIZE) {
+               pa = find_pte(virt, 0);
+               *(uint32_t *)pa = 0;
+               virt += PAGE_SIZE;
+       }
+
+       srmmu_flush_whole_tlb(); 
+}
+
+/* Map a set of pages */
+void ofmem_arch_map_pages(phys_addr_t phys, ucell virt, ucell size, ucell mode)
+{
+       unsigned long npages, off;
+       uint32_t pte;
+       unsigned long pa;
+
+       off = phys & (PAGE_SIZE - 1);
+       npages = (off + (size - 1) + (PAGE_SIZE - 1)) / PAGE_SIZE;
+       phys &= ~(uint64_t)(PAGE_SIZE - 1);
+
+       while (npages-- != 0) {
+               pa = find_pte(virt, 1);
+
+               pte = SRMMU_ET_PTE | ((phys & PAGE_MASK) >> 4);
+               pte |= mode;
+
+               *(uint32_t *)pa = pte;
+
+               virt += PAGE_SIZE;
+               phys += PAGE_SIZE;
+       }
+}
+
+/* Architecture-specific OFMEM helpers */
+unsigned long
+find_pte(unsigned long va, int alloc)
+{
+    uint32_t pte;
+    void *p;
+    unsigned long pa;
+    int ret;
+
+    pte = l1[(va >> SRMMU_PGDIR_SHIFT) & (SRMMU_PTRS_PER_PGD - 1)];
+    if ((pte & SRMMU_ET_MASK) == SRMMU_ET_INVALID) {
+        if (alloc) {
+            ret = ofmem_posix_memalign(&p, SRMMU_PTRS_PER_PMD * sizeof(int),
+                                 SRMMU_PTRS_PER_PMD * sizeof(int));
+            if (ret != 0)
+                return ret;
+            pte = SRMMU_ET_PTD | ((va2pa((unsigned long)p)) >> 4);
+            l1[(va >> SRMMU_PGDIR_SHIFT) & (SRMMU_PTRS_PER_PGD - 1)] = pte;
+            /* barrier() */
+        } else {
+            return -1;
+        }
+    }
+
+    pa = (pte & 0xFFFFFFF0) << 4;
+    pa += ((va >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1)) << 2;
+    pte = *(uint32_t *)pa2va(pa);
+    if ((pte & SRMMU_ET_MASK) == SRMMU_ET_INVALID) {
+        if (alloc) {
+            ret = ofmem_posix_memalign(&p, SRMMU_PTRS_PER_PTE * sizeof(void *),
+                                 SRMMU_PTRS_PER_PTE * sizeof(void *));
+            if (ret != 0)
+                return ret;
+            pte = SRMMU_ET_PTD | ((va2pa((unsigned int)p)) >> 4);
+            *(uint32_t *)pa2va(pa) = pte;
+        } else {
+            return -2;
+        }
+    }
+
+    pa = (pte & 0xFFFFFFF0) << 4;
+    pa += ((va >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1)) << 2;
+
+    return pa2va(pa);
+}
+
+/************************************************************************/
+/* misc                                                                 */
+/************************************************************************/
+
+ucell ofmem_arch_default_translation_mode( phys_addr_t phys )
+{
+       return SRMMU_REF | SRMMU_CACHE | SRMMU_PRIV;
+}
+
+ucell ofmem_arch_io_translation_mode( phys_addr_t phys )
+{
+       return SRMMU_REF | SRMMU_PRIV;
+}
+
+/************************************************************************/
+/* init / cleanup                                                       */
+/************************************************************************/
+
+void ofmem_init( void )
+{
+       memset(&s_ofmem_data, 0, sizeof(s_ofmem_data));
+       s_ofmem_data.ofmem.ramsize = qemu_mem_size;
+       
+       /* Mark the first page as non-free */
+       ofmem_claim_virt(0, PAGE_SIZE, 0);
+       
+       /* Claim reserved physical addresses at top of RAM */
+       ofmem_claim_phys(s_ofmem_data.ofmem.ramsize - OFMEM_PHYS_RESERVED, OFMEM_PHYS_RESERVED, 0);
+       
+       /* Claim OpenBIOS reserved space */
+       ofmem_claim_virt(0xffd00000, 0x200000, 0);
+}