nuttx/arch/arm/src/armv7-a/arm_mmu.c
2014-04-02 09:03:29 -06:00

206 lines
6.8 KiB
C

/****************************************************************************
* arch/arm/src/armv7-a/arm_mmu.c
*
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include "cache.h"
#include "mmu.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: mmu_l1_setentry
*
* Description:
* Set a one level 1 translation table entry. Only a single L1 page table
* is supported.
*
* Input Paramters:
* paddr - The physical address to be mapped. Must be aligned to a 1MB
* address boundary
* vaddr - The virtual address to be mapped. Must be aligned to a 1MB
* address boundary
* mmuflags - The MMU flags to use in the mapping.
*
****************************************************************************/
#ifndef CONFIG_ARCH_ROMPGTABLE
void mmu_l1_setentry(uint32_t paddr, uint32_t vaddr, uint32_t mmuflags)
{
uint32_t *l1table = (uint32_t*)PGTABLE_BASE_VADDR;
uint32_t index = vaddr >> 20;
/* Save the page table entry */
l1table[index] = (paddr | mmuflags);
/* Flush the data cache entry. Make sure that the modified contents
* of the page table are flushed into physical memory.
*/
cp15_clean_dcache_bymva((uint32_t)&l1table[index]);
/* Invalidate the TLB cache associated with virtual address range */
mmu_invalidate_region(vaddr, 1024*1024);
}
#endif
/****************************************************************************
* Name: mmu_l2_setentry
*
* Description:
* Set one small (4096B) entry in a level2 translation table.
*
* Input Parameters:
* l2vaddr - the virtual address of the beginning of the L2 translation
* table.
* paddr - The physical address to be mapped. Must be aligned to a 4KB
* address boundary
* vaddr - The virtual address to be mapped. Must be aligned to a 4KB
* address boundary
* mmuflags - The MMU flags to use in the mapping.
*
****************************************************************************/
#ifndef CONFIG_ARCH_ROMPGTABLE
void mmu_l2_setentry(uint32_t l2vaddr, uint32_t paddr, uint32_t vaddr,
uint32_t mmuflags)
{
uint32_t *l2table = (uint32_t*)l2vaddr;
uint32_t index;
/* The table divides a 1Mb address space up into 256 entries, each
* corresponding to 4Kb of address space. The page table index is
* related to the offset from the beginning of 1Mb region.
*/
index = (vaddr & 0x000ff000) >> 12;
/* Save the table entry */
l2table[index] = (paddr | mmuflags);
/* Flush the data cache entry. Make sure that the modified contents
* of the page table are flushed into physical memory.
*/
cp15_clean_dcache_bymva((uint32_t)&l2table[index]);
/* Invalidate the TLB cache associated with virtual address range */
cp15_invalidate_tlb_bymva(vaddr);
}
#endif
/****************************************************************************
* Name: mmu_l1_map_region
*
* Description:
* Set multiple level 1 translation table entries in order to map a
* region of memory.
*
* Input Parameters:
* mapping - Describes the mapping to be performed.
*
****************************************************************************/
#ifndef CONFIG_ARCH_ROMPGTABLE
void mmu_l1_map_region(const struct section_mapping_s *mapping)
{
uint32_t paddr = mapping->physbase;
uint32_t vaddr = mapping->virtbase;
uint32_t mmuflags = mapping->mmuflags;
int i;
/* Loop, writing each mapping into the L1 page table */
for (i = 0; i < mapping->nsections; i++)
{
mmu_l1_setentry(paddr, vaddr, mmuflags);
paddr += SECTION_SIZE;
vaddr += SECTION_SIZE;
}
}
#endif
/****************************************************************************
* Name: mmu_invalidate_region
*
* Description:
* Invalidate TLBs for a range of addresses (all 4KB aligned).
*
* Input Parameters:
* vaddr - The beginning of the region to invalidate.
* size - The size of the region in bytes to be invalidated.
*
****************************************************************************/
#ifndef CONFIG_ARCH_ROMPGTABLE
void mmu_invalidate_region(uint32_t vstart, size_t size)
{
uint32_t vaddr = vstart & 0xfffff000;
uint32_t vend = vaddr + size;
/* Loop, invalidating regions */
while (vaddr < vend)
{
cp15_invalidate_tlb_bymva(vaddr);
vaddr += 4096;
}
}
#endif