253 lines
5.9 KiB
C
253 lines
5.9 KiB
C
/*
|
|
* <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 "arch/sparc32/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);
|
|
}
|