Page MenuHomePhabricator

Libxlat Tables V2xlat Tables Corecvslibxlat Mpuxlat Mpu Corec
Updated 82 Days AgoPublic

/*                                                            /*
 * Copyright (c) 2017-2020, ARM Limited and Contributors.  |   * Copyright (c) 2017-2021, ARM Limited and Contributors. 
 *                                                             *
 * SPDX-License-Identifier: BSD-3-Clause                       * SPDX-License-Identifier: BSD-3-Clause
 */                                                            */

#include <assert.h>                                           #include <assert.h>
#include <errno.h>                                            #include <errno.h>
#include <stdbool.h>                                          #include <stdbool.h>
#include <stdint.h>                                           #include <stdint.h>
#include <string.h>                                           #include <string.h>

#include <platform_def.h>                                     #include <platform_def.h>

#include <arch_features.h>                                    #include <arch_features.h>
#include <arch_helpers.h>                                  |  #include <fvp_r_arch_helpers.h>
#include <common/debug.h>                                     #include <common/debug.h>
#include <lib/utils_def.h>                                    #include <lib/utils_def.h>
#include <lib/xlat_tables/xlat_tables_defs.h>                 #include <lib/xlat_tables/xlat_tables_defs.h>
#include <lib/xlat_tables/xlat_tables_v2.h>                   #include <lib/xlat_tables/xlat_tables_v2.h>

#include "xlat_tables_private.h"                           |  #include "xlat_mpu_private.h"
                                                           >

/* Helper function that cleans the data cache only if it i    /* Helper function that cleans the data cache only if it i
static inline __attribute__((unused)) void xlat_clean_dcac    static inline __attribute__((unused)) void xlat_clean_dcac
{                                                             {
        if (is_dcache_enabled())                                      if (is_dcache_enabled())
                clean_dcache_range(addr, size);                               clean_dcache_range(addr, size);
}                                                             }

#if PLAT_XLAT_TABLES_DYNAMIC                               <
                                                           <
/*                                                         <
 * The following functions assume that they will be called <
 * The base table can't be unmapped, so it is not needed t <
 * handling for it.                                        <
 */                                                        <
                                                           <
/*                                                         <
 * Returns the index of the array corresponding to the spe <
 * table.                                                  <
 */                                                        <
static int xlat_table_get_index(const xlat_ctx_t *ctx, con <
{                                                          <
        for (int i = 0; i < ctx->tables_num; i++)          <
                if (ctx->tables[i] == table)               <
                        return i;                          <
                                                           <
        /*                                                 <
         * Maybe we were asked to get the index of the bas <
         * should never happen.                            <
         */                                                <
        assert(false);                                     <
                                                           <
        return -1;                                         <
}                                                          <
                                                           <
/* Returns a pointer to an empty translation table. */     <
static uint64_t *xlat_table_get_empty(const xlat_ctx_t *ct <
{                                                          <
        for (int i = 0; i < ctx->tables_num; i++)          <
                if (ctx->tables_mapped_regions[i] == 0)    <
                        return ctx->tables[i];             <
                                                           <
        return NULL;                                       <
}                                                          <
                                                           <
/* Increments region count for a given table. */           <
static void xlat_table_inc_regions_count(const xlat_ctx_t  <
                                         const uint64_t *t <
{                                                          <
        int idx = xlat_table_get_index(ctx, table);        <
                                                           <
        ctx->tables_mapped_regions[idx]++;                 <
}                                                          <
                                                           <
/* Decrements region count for a given table. */           <
static void xlat_table_dec_regions_count(const xlat_ctx_t  <
                                         const uint64_t *t <
{                                                          <
        int idx = xlat_table_get_index(ctx, table);        <
                                                           <
        ctx->tables_mapped_regions[idx]--;                 <
}                                                          <
                                                           <
/* Returns 0 if the specified table isn't empty, otherwise <
static bool xlat_table_is_empty(const xlat_ctx_t *ctx, con <
{                                                          <
        return ctx->tables_mapped_regions[xlat_table_get_i <
}                                                          <
                                                           <
#else /* PLAT_XLAT_TABLES_DYNAMIC */                       <
                                                           <
/* Returns a pointer to the first empty translation table. <
static uint64_t *xlat_table_get_empty(xlat_ctx_t *ctx)     <
{                                                          <
        assert(ctx->next_table < ctx->tables_num);         <
                                                           <
        return ctx->tables[ctx->next_table++];             <
}                                                          <

#endif /* PLAT_XLAT_TABLES_DYNAMIC */                      <

/*                                                         |  /* Calculate region-attributes byte for PRBAR part of MPU-
 * Returns a block/page table descriptor for the given lev |  uint64_t prbar_attr_value (uint32_t attr)
 */                                                        <
uint64_t xlat_desc(const xlat_ctx_t *ctx, uint32_t attr,   <
                   unsigned long long addr_pa, unsigned in <
{                                                             {
        uint64_t desc;                                     |          uint64_t retValue = UL(0);
        uint32_t mem_type;                                 |          uint64_t extract;  /* temp var holding bit extract
        uint32_t shareability_type;                        <
                                                           <
        /* Make sure that the granularity is fine enough t <
        assert((addr_pa & XLAT_BLOCK_MASK(level)) == 0U);  <
                                                           <
        desc = addr_pa;                                    <
        /*                                                 <
         * There are different translation table descripto <
         * rest.                                           <
         */                                                <
        desc |= (level == XLAT_TABLE_LEVEL_MAX) ? PAGE_DES <
        /*                                                 <
         * Always set the access flag, as this library ass <
         * faults aren't managed.                          <
         */                                                <
        desc |= LOWER_ATTRS(ACCESS_FLAG);                  <
        /*                                                 <
         * Deduce other fields of the descriptor based on  <
         * memory region attributes.                       <
         */                                                <
        desc |= ((attr & MT_NS) != 0U) ? LOWER_ATTRS(NS) : <
        desc |= ((attr & MT_RW) != 0U) ? LOWER_ATTRS(AP_RW <
                                                           <
        /*                                                 <
         * Do not allow unprivileged access when the mappi <
         * EL. For translation regimes that do not have ma <
         * lower exception levels, set AP[2] to AP_NO_ACCE <
         */                                                <
        if (ctx->xlat_regime == EL1_EL0_REGIME) {          <
                if ((attr & MT_USER) != 0U) {              <
                        /* EL0 mapping requested, so we gi <
                        desc |= LOWER_ATTRS(AP_ACCESS_UNPR <
                } else {                                   <
                        /* EL1 mapping requested, no User  <
                        desc |= LOWER_ATTRS(AP_NO_ACCESS_U <
                }                                          <
        } else {                                           <
                assert((ctx->xlat_regime == EL2_REGIME) || <
                       (ctx->xlat_regime == EL3_REGIME));  <
                desc |= LOWER_ATTRS(AP_ONE_VA_RANGE_RES1); <
        }                                                  <
                                                           <
        /*                                                 <
         * Deduce shareability domain and executability of <
         * from the memory type of the attributes (MT_TYPE <
         *                                                 <
         * Data accesses to device memory and non-cacheabl <
         * coherent for all observers in the system, and c <
         * always treated as being Outer Shareable. Theref <
         * of memory, it is not strictly needed to set the <
         * in the translation tables.                      <
         */                                                <
        mem_type = MT_TYPE(attr);                          <
        if (mem_type == MT_DEVICE) {                       <
                desc |= LOWER_ATTRS(ATTR_DEVICE_INDEX | OS <
                /*                                         <
                 * Always map device memory as execute-nev <
                 * This is to avoid the possibility of a s <
                 * fetch, which could be an issue if this  <
                 * corresponds to a read-sensitive periphe <
                 */                                        <
                desc |= xlat_arch_regime_get_xn_desc(ctx-> <

        } else { /* Normal memory */                       |          /* Extract and stuff SH: */
                /*                                         |          extract = (uint64_t) (  (attr >> MT_SHAREABILITY_S
                 * Always map read-write normal memory as  |                                & MT_SHAREABILITY_MASK);
                 * This library assumes that it is used by |          retValue |= (extract << PRBAR_SH_SHIFT);
                 * not self-modify its code, therefore R/W <
                 * for data storage, which must not be exe <
                 *                                         <
                 * Note that setting the XN bit here is fo <
                 * The function that enables the MMU sets  <
                 * which makes any writable memory region  <
                 * execute-never, regardless of the value  <
                 * translation table.                      <
                 *                                         <
                 * For read-only memory, rely on the MT_EX <
                 * attribute to figure out the value of th <
                 * XN bit(s) to set in the descriptor depe <
                 * translation regime and the policy appli <
                 * xlat_arch_regime_get_xn_desc().         <
                 */                                        <
                if (((attr & MT_RW) != 0U) || ((attr & MT_ <
                        desc |= xlat_arch_regime_get_xn_de <
                }                                          <

                shareability_type = MT_SHAREABILITY(attr); |          /* Extract and stuff AP: */
                if (mem_type == MT_MEMORY) {               |          extract = (uint64_t) (  (attr >> MT_PERM_SHIFT)
                        desc |= LOWER_ATTRS(ATTR_IWBWA_OWB |                                & MT_PERM_MASK);
                        if (shareability_type == MT_SHAREA |          if (extract == 0) {
                                desc |= LOWER_ATTRS(NSH);  |                  retValue |= (UL(2) << PRBAR_AP_SHIFT);
                        } else if (shareability_type == MT |          } else /* extract == 1 */ {
                                desc |= LOWER_ATTRS(OSH);  |                  retValue |= (UL(0) << PRBAR_AP_SHIFT);
                        } else {                           <
                                desc |= LOWER_ATTRS(ISH);  <
                        }                                  <
                                                           <
                        /* Check if Branch Target Identifi <
#if ENABLE_BTI                                             <
                        /* Set GP bit for block and page c <
                         * if BTI mechanism is implemented <
                         */                                <
                        if (is_armv8_5_bti_present() &&    <
                           ((attr & (MT_TYPE_MASK | MT_RW  <
                                MT_EXECUTE_NEVER)) == MT_C <
                                desc |= GP;                <
                        }                                  <
#endif                                                     <
                } else {                                   <
                        assert(mem_type == MT_NON_CACHEABL <
                        desc |= LOWER_ATTRS(ATTR_NON_CACHE <
                }                                          <
        }                                                             }

        return desc;                                       |          /* Extract and stuff XN: */
}                                                          |          extract = (uint64_t) (  (attr >> MT_EXECUTE_SHIFT)
                                                           |                                & MT_EXECUTE_MASK);
/*                                                         |          retValue |= (extract << PRBAR_XN_SHIFT);
 * Enumeration of actions that can be made when mapping ta |          /* However, also don't execute in peripheral space
 * on the previous value in that entry and information abo |          extract = (uint64_t) (  (attr >> MT_TYPE_SHIFT)
 * mapped.                                                 |                                & MT_TYPE_MASK);
 */                                                        |          if (extract == 0) {
typedef enum {                                             |                  retValue |= (UL(1) << PRBAR_XN_SHIFT);
                                                           <
        /* Do nothing */                                   <
        ACTION_NONE,                                       <
                                                           <
        /* Write a block (or page, if in level 3) entry. * <
        ACTION_WRITE_BLOCK_ENTRY,                          <
                                                           <
        /*                                                 <
         * Create a new table and write a table entry poin <
         * into it for further processing.                 <
         */                                                <
        ACTION_CREATE_NEW_TABLE,                           <
                                                           <
        /*                                                 <
         * There is a table descriptor in this entry, read <
         * that table for further processing.              <
         */                                                <
        ACTION_RECURSE_INTO_TABLE,                         <
                                                           <
} action_t;                                                <
                                                           <
/*                                                         <
 * Function that returns the first VA of the table affecte <
 * mmap region.                                            <
 */                                                        <
static uintptr_t xlat_tables_find_start_va(mmap_region_t * <
                                   const uintptr_t table_b <
                                   const unsigned int leve <
{                                                          <
        uintptr_t table_idx_va;                            <
                                                           <
        if (mm->base_va > table_base_va) {                 <
                /* Find the first index of the table affec <
                table_idx_va = mm->base_va & ~XLAT_BLOCK_M <
        } else {                                           <
                /* Start from the beginning of the table.  <
                table_idx_va = table_base_va;              <
        }                                                             }
                                                           |          return retValue;
        return table_idx_va;                               <
}                                                             }

/*                                                         |  /* Calculate region-attributes byte for PRLAR part of MPU-
 * Function that returns table index for the given VA and  |  uint64_t prlar_attr_value (uint32_t attr)
 */                                                        <
static inline unsigned int  xlat_tables_va_to_index(const  <
                                                const uint <
                                                const unsi <
{                                                          <
        return (unsigned int)((va - table_base_va) >> XLAT <
}                                                          <
                                                           <
#if PLAT_XLAT_TABLES_DYNAMIC                               <
                                                           <
/*                                                         <
 * From the given arguments, it decides which action to ta <
 * specified region.                                       <
 */                                                        <
static action_t xlat_tables_unmap_region_action(const mmap <
                const uintptr_t table_idx_va, const uintpt <
                const unsigned int level, const uint64_t d <
{                                                             {
        action_t action;                                   |          uint64_t retValue = UL(0);
        uintptr_t region_end_va = mm->base_va + mm->size - |          uint64_t extract;  /* temp var holding bit extract
                                                           <
        if ((mm->base_va <= table_idx_va) &&               <
            (region_end_va >= table_idx_end_va)) {         <
                /* Region covers all block */              <
                                                           <
                if (level == 3U) {                         <
                        /*                                 <
                         * Last level, only page descripto <
                         * erase it.                       <
                         */                                <
                        assert(desc_type == PAGE_DESC);    <
                                                           <
                        action = ACTION_WRITE_BLOCK_ENTRY; <
                } else {                                   <
                        /*                                 <
                         * Other levels can have table des <
                         * so, recurse into it and erase d <
                         * inside it as needed. If there i <
                         * descriptor, just erase it. If a <
                         * descriptor is found, this table <
                         * actually mapped, which shouldn' <
                         */                                <
                        if (desc_type == TABLE_DESC) {     <
                                action = ACTION_RECURSE_IN <
                        } else {                           <
                                assert(desc_type == BLOCK_ <
                                action = ACTION_WRITE_BLOC <
                        }                                  <
                }                                          <
                                                           <
        } else if ((mm->base_va <= table_idx_end_va) ||    <
                   (region_end_va >= table_idx_va)) {      <
                /*                                         <
                 * Region partially covers block.          <
                 *                                         <
                 * It can't happen in level 3.             <
                 *                                         <
                 * There must be a table descriptor here,  <
                 * was a problem when mapping the region.  <
                 */                                        <
                assert(level < 3U);                        <
                assert(desc_type == TABLE_DESC);           <

                action = ACTION_RECURSE_INTO_TABLE;        |          /* Extract and stuff AttrIndx: */
        } else {                                           |          extract = (uint64_t) (  (attr >> MT_TYPE_SHIFT)
                /* The region doesn't cover the block at a |                                & MT_TYPE_MASK);
                action = ACTION_NONE;                      |          switch (extract) {
                                                           >          case UL(0):
                                                           >                  retValue |= (UL(1) << PRLAR_ATTR_SHIFT);
                                                           >                  break;
                                                           >          case UL(2):
                                                           >                  /* 0, so OR in nothing */
                                                           >                  break;
                                                           >          case UL(3):
                                                           >                  retValue |= (UL(2) << PRLAR_ATTR_SHIFT);
                                                           >                  break;
                                                           >          default:
                                                           >                  retValue |= (extract << PRLAR_ATTR_SHIFT);
                                                           >                  break;
        }                                                             }

        return action;                                     |          /* Stuff EN: */
}                                                          |          retValue |= (UL(1) << PRLAR_EN_SHIFT);
/*                                                         <
 * Recursive function that writes to the translation table <
 * specified region.                                       <
 */                                                        <
static void xlat_tables_unmap_region(xlat_ctx_t *ctx, mmap <
                                     const uintptr_t table <
                                     uint64_t *const table <
                                     const unsigned int ta <
                                     const unsigned int le <
{                                                          <
        assert((level >= ctx->base_level) && (level <= XLA <
                                                           <
        uint64_t *subtable;                                <
        uint64_t desc;                                     <
                                                           <
        uintptr_t table_idx_va;                            <
        uintptr_t table_idx_end_va; /* End VA of this entr <
                                                           <
        uintptr_t region_end_va = mm->base_va + mm->size - <

        unsigned int table_idx;                            |          /* Force NS to 0 (Secure);  v8-R64 only supports S
                                                           >          extract = ~(1 << PRLAR_NS_SHIFT);
                                                           >          retValue &= extract;

        table_idx_va = xlat_tables_find_start_va(mm, table |          return retValue;
        table_idx = xlat_tables_va_to_index(table_base_va, <
                                                           <
        while (table_idx < table_entries) {                <
                                                           <
                table_idx_end_va = table_idx_va + XLAT_BLO <
                                                           <
                desc = table_base[table_idx];              <
                uint64_t desc_type = desc & DESC_MASK;     <
                                                           <
                action_t action = xlat_tables_unmap_region <
                                table_idx_va, table_idx_en <
                                desc_type);                <
                                                           <
                if (action == ACTION_WRITE_BLOCK_ENTRY) {  <
                                                           <
                        table_base[table_idx] = INVALID_DE <
                        xlat_arch_tlbi_va(table_idx_va, ct <
                                                           <
                } else if (action == ACTION_RECURSE_INTO_T <
                                                           <
                        subtable = (uint64_t *)(uintptr_t) <
                                                           <
                        /* Recurse to write into subtable  <
                        xlat_tables_unmap_region(ctx, mm,  <
                                                 subtable, <
                                                 level + 1 <
#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARL <
                        xlat_clean_dcache_range((uintptr_t <
                                XLAT_TABLE_ENTRIES * sizeo <
#endif                                                     <
                        /*                                 <
                         * If the subtable is now empty, r <
                         */                                <
                        if (xlat_table_is_empty(ctx, subta <
                                table_base[table_idx] = IN <
                                xlat_arch_tlbi_va(table_id <
                                                  ctx->xla <
                        }                                  <
                                                           <
                } else {                                   <
                        assert(action == ACTION_NONE);     <
                }                                          <
                                                           <
                table_idx++;                               <
                table_idx_va += XLAT_BLOCK_SIZE(level);    <
                                                           <
                /* If reached the end of the region, exit  <
                if (region_end_va <= table_idx_va)         <
                        break;                             <
        }                                                  <
                                                           <
        if (level > ctx->base_level)                       <
                xlat_table_dec_regions_count(ctx, table_ba <
}                                                             }

#endif /* PLAT_XLAT_TABLES_DYNAMIC */                      <
                                                           <
/*                                                            /*
 * From the given arguments, it decides which action to ta |   * region_attr() performs the reverse of prbar_attr_value(
 * specified region.                                       |   * prlar_attr_value() above, combined.  That is, it recons
                                                           >   * from the attributes in PRBAR and PRLAR for the MPU regi
 */                                                            */
static action_t xlat_tables_map_region_action(const mmap_r |  uint32_t region_attr (uint64_t prbar_attr, uint64_t prlar_
                unsigned int desc_type, unsigned long long <
                uintptr_t table_entry_base_va, unsigned in <
{                                                             {
        uintptr_t mm_end_va = mm->base_va + mm->size - 1U; |          /* TODO:  Remove this comment when these API calls
        uintptr_t table_entry_end_va =                     |             implemented and tested! */
                        table_entry_base_va + XLAT_BLOCK_S |          ERROR("region_attr() is not yet implemented for xl
                                                           |          panic();
        /*                                                 <
         * The descriptor types allowed depend on the curr <
         */                                                <
                                                           <
        if ((mm->base_va <= table_entry_base_va) &&        <
            (mm_end_va >= table_entry_end_va)) {           <
                                                           <
                /*                                         <
                 * Table entry is covered by region        <
                 * --------------------------------        <
                 *                                         <
                 * This means that this table entry can de <
                 * translation with this granularity in pr <
                 */                                        <
                                                           <
                if (level == 3U) {                         <
                        /*                                 <
                         * Last level, only page descripto <
                         */                                <
                        if (desc_type == PAGE_DESC) {      <
                                /*                         <
                                 * There's another region  <
                                 * overwrite.              <
                                 */                        <
                                return ACTION_NONE;        <
                        } else {                           <
                                assert(desc_type == INVALI <
                                return ACTION_WRITE_BLOCK_ <
                        }                                  <
                                                           <
                } else {                                   <
                                                           <
                        /*                                 <
                         * Other levels. Table descriptors <
                         * descriptors too, but they have  <
                         */                                <
                                                           <
                        if (desc_type == TABLE_DESC) {     <
                                /* There's already a table <
                                return ACTION_RECURSE_INTO <
                                                           <
                        } else if (desc_type == INVALID_DE <
                                /*                         <
                                 * There's nothing mapped  <
                                 * entry.                  <
                                 *                         <
                                 * Check if the destinatio <
                                 * us to use a block descr <
                                 * finer table for it.     <
                                 *                         <
                                 * Also, check if the curr <
                                 * descriptors. If not, cr <
                                 */                        <
                                if (((dest_pa & XLAT_BLOCK <
                                    || (level < MIN_LVL_BL <
                                    (mm->granularity < XLA <
                                        return ACTION_CREA <
                                else                       <
                                        return ACTION_WRIT <
                                                           <
                        } else {                           <
                                /*                         <
                                 * There's another region  <
                                 * overwrite.              <
                                 */                        <
                                assert(desc_type == BLOCK_ <
                                                           <
                                return ACTION_NONE;        <
                        }                                  <
                }                                          <
                                                           <
        } else if ((mm->base_va <= table_entry_end_va) ||  <
                   (mm_end_va >= table_entry_base_va)) {   <
                                                           <
                /*                                         <
                 * Region partially covers table entry     <
                 * -----------------------------------     <
                 *                                         <
                 * This means that this table entry can't  <
                 * translation, a finer table is needed.   <
                                                           <
                 * There cannot be partial block overlaps  <
                 * happens, some of the preliminary checks <
                 * mmap region failed to detect that PA an <
                 * aligned to PAGE_SIZE.                   <
                 */                                        <
                assert(level < 3U);                        <
                                                           <
                if (desc_type == INVALID_DESC) {           <
                        /*                                 <
                         * The block is not fully covered  <
                         * a new table, recurse into it an <
                         * region with finer granularity.  <
                         */                                <
                        return ACTION_CREATE_NEW_TABLE;    <
                                                           <
                } else {                                   <
                        assert(desc_type == TABLE_DESC);   <
                        /*                                 <
                         * The block is not fully covered  <
                         * there is already a table here.  <
                         * try to map with finer granulari <
                         *                                 <
                         * PAGE_DESC for level 3 has the s <
                         * TABLE_DESC, but this code can't <
                         * table because there can't be ov <
                         */                                <
                        return ACTION_RECURSE_INTO_TABLE;  <
                }                                          <
        } else {                                           <
                                                           <
                /*                                         <
                 * This table entry is outside of the regi <
                 * arguments, don't write anything to it.  <
                 */                                        <
                return ACTION_NONE;                        <
        }                                                  <
}                                                             }

/*                                                            /*
 * Recursive function that writes to the translation table |   * Function that writes an MPU "translation" into the MPU 
 * specified region. On success, it returns the VA of the  |   * possible (e.g., if no more MPU regions available) boot 
 * successfully mapped. On error, it returns the VA of the <
 * should have been mapped.                                <
 */                                                            */
static uintptr_t xlat_tables_map_region(xlat_ctx_t *ctx, m |  static void mpu_map_region(mmap_region_t *mm)
                                   uintptr_t table_base_va <
                                   uint64_t *const table_b <
                                   unsigned int table_entr <
                                   unsigned int level)     <
{                                                             {
        assert((level >= ctx->base_level) && (level <= XLA |          uint64_t prenr_el2_value = 0;
                                                           |          uint64_t prbar_attrs = 0;
        uintptr_t mm_end_va = mm->base_va + mm->size - 1U; |          uint64_t prlar_attrs = 0;
                                                           |          int region_to_use = 0;
        uintptr_t table_idx_va;                            <
        unsigned long long table_idx_pa;                   <
                                                           <
        uint64_t *subtable;                                <
        uint64_t desc;                                     <
                                                           <
        unsigned int table_idx;                            <
                                                           <
        table_idx_va = xlat_tables_find_start_va(mm, table <
        table_idx = xlat_tables_va_to_index(table_base_va, <
                                                           <
#if PLAT_XLAT_TABLES_DYNAMIC                               <
        if (level > ctx->base_level)                       <
                xlat_table_inc_regions_count(ctx, table_ba <
#endif                                                     <
                                                           <
        while (table_idx < table_entries) {                <

                desc = table_base[table_idx];              |          /* If all MPU regions in use, then abort boot: */
                                                           >          prenr_el2_value = read_prenr_el2();
                                                           >          assert(prenr_el2_value != 0xffffffff);

                table_idx_pa = mm->base_pa + table_idx_va  |          /* Find and select first-available MPU region: */
                                                           |          for (region_to_use = 0;  region_to_use < N_MPU_REG
                action_t action = xlat_tables_map_region_a |               region_to_use++) {
                        (uint32_t)(desc & DESC_MASK), tabl |                  if (((prenr_el2_value >> region_to_use) & 
                        table_idx_va, level);              <
                                                           <
                if (action == ACTION_WRITE_BLOCK_ENTRY) {  <
                                                           <
                        table_base[table_idx] =            <
                                xlat_desc(ctx, (uint32_t)m <
                                          level);          <
                                                           <
                } else if (action == ACTION_CREATE_NEW_TAB <
                        uintptr_t end_va;                  <
                                                           <
                        subtable = xlat_table_get_empty(ct <
                        if (subtable == NULL) {            <
                                /* Not enough free tables  <
                                return table_idx_va;       <
                        }                                  <
                                                           <
                        /* Point to new subtable from this <
                        table_base[table_idx] =            <
                                TABLE_DESC | (uintptr_t)su <
                                                           <
                        /* Recurse to write into subtable  <
                        end_va = xlat_tables_map_region(ct <
                                               subtable, X <
                                               level + 1U) <
#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARL <
                        xlat_clean_dcache_range((uintptr_t <
                                XLAT_TABLE_ENTRIES * sizeo <
#endif                                                     <
                        if (end_va !=                      <
                                (table_idx_va + XLAT_BLOCK <
                                return end_va;             <
                                                           <
                } else if (action == ACTION_RECURSE_INTO_T <
                        uintptr_t end_va;                  <
                                                           <
                        subtable = (uint64_t *)(uintptr_t) <
                        /* Recurse to write into subtable  <
                        end_va = xlat_tables_map_region(ct <
                                               subtable, X <
                                               level + 1U) <
#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARL <
                        xlat_clean_dcache_range((uintptr_t <
                                XLAT_TABLE_ENTRIES * sizeo <
#endif                                                     <
                        if (end_va !=                      <
                                (table_idx_va + XLAT_BLOCK <
                                return end_va;             <
                                                           <
                } else {                                   <
                                                           <
                        assert(action == ACTION_NONE);     <
                                                           <
                }                                          <
                                                           <
                table_idx++;                               <
                table_idx_va += XLAT_BLOCK_SIZE(level);    <
                                                           <
                /* If reached the end of the region, exit  <
                if (mm_end_va <= table_idx_va)             <
                        break;                                                        break;
                                                           >                  }
        }                                                             }
                                                           >          write_prselr_el2 ((uint64_t) (region_to_use));

        return table_idx_va - 1U;                          |          /* Set base and limit addresses: */
                                                           >          write_prbar_el2(mm->base_pa & PRBAR_PRLAR_ADDR_MAS
                                                           >          write_prlar_el2(  (mm->base_pa + mm->size - 1UL)
                                                           >                          & PRBAR_PRLAR_ADDR_MASK);
                                                           >
                                                           >          /* Set attributes: */
                                                           >          prbar_attrs = prbar_attr_value (mm->attr);
                                                           >          write_prbar_el2(read_prbar_el2() | prbar_attrs);
                                                           >          prlar_attrs = prlar_attr_value (mm->attr);
                                                           >          write_prlar_el2(read_prlar_el2() | prlar_attrs);
                                                           >
                                                           >          /* Mark this MPU region as used: */
                                                           >          prenr_el2_value |= (1 << region_to_use);
                                                           >          write_prenr_el2 (prenr_el2_value);
}                                                             }

/*                                                            /*
 * Function that verifies that a region can be mapped.         * Function that verifies that a region can be mapped.
 * Returns:                                                    * Returns:
 *        0: Success, the mapping is allowed.                  *        0: Success, the mapping is allowed.
 *   EINVAL: Invalid values were used as arguments.            *   EINVAL: Invalid values were used as arguments.
 *   ERANGE: The memory limits were surpassed.                 *   ERANGE: The memory limits were surpassed.
 *   ENOMEM: There is not enough memory in the mmap array.     *   ENOMEM: There is not enough memory in the mmap array.
 *    EPERM: Region overlaps another one in an invalid way     *    EPERM: Region overlaps another one in an invalid way
 */                                                            */
static int mmap_add_region_check(const xlat_ctx_t *ctx, co    static int mmap_add_region_check(const xlat_ctx_t *ctx, co
{                                                             {
        unsigned long long base_pa = mm->base_pa;                     unsigned long long base_pa = mm->base_pa;
        uintptr_t base_va = mm->base_va;                              uintptr_t base_va = mm->base_va;
        size_t size = mm->size;                                       size_t size = mm->size;
        size_t granularity = mm->granularity;              <

        unsigned long long end_pa = base_pa + size - 1U;              unsigned long long end_pa = base_pa + size - 1U;
        uintptr_t end_va = base_va + size - 1U;                       uintptr_t end_va = base_va + size - 1U;

        if (!IS_PAGE_ALIGNED(base_pa) || !IS_PAGE_ALIGNED( |          if (base_pa != base_va)
                        !IS_PAGE_ALIGNED(size))            |                  return -EINVAL;  /* MPU does not perform a
                return -EINVAL;                            |
                                                           |          if ((base_pa % 64) != 0)
        if ((granularity != XLAT_BLOCK_SIZE(1U)) &&        |                  return -EINVAL;  /* MPU requires 64-byte a
                (granularity != XLAT_BLOCK_SIZE(2U)) &&    <
                (granularity != XLAT_BLOCK_SIZE(3U))) {    <
                return -EINVAL;                            <
        }                                                  <

        /* Check for overflows */                                     /* Check for overflows */
        if ((base_pa > end_pa) || (base_va > end_va))                 if ((base_pa > end_pa) || (base_va > end_va))
                return -ERANGE;                                               return -ERANGE;

        if (end_va > ctx->va_max_address)                  <
                return -ERANGE;                            <
                                                           <
        if (end_pa > ctx->pa_max_address)                             if (end_pa > ctx->pa_max_address)
                return -ERANGE;                                               return -ERANGE;

        /* Check that there is space in the ctx->mmap arra            /* Check that there is space in the ctx->mmap arra
        if (ctx->mmap[ctx->mmap_num - 1].size != 0U)                  if (ctx->mmap[ctx->mmap_num - 1].size != 0U)
                return -ENOMEM;                                               return -ENOMEM;

        /* Check for PAs and VAs overlaps with all other r            /* Check for PAs and VAs overlaps with all other r
        for (const mmap_region_t *mm_cursor = ctx->mmap;              for (const mmap_region_t *mm_cursor = ctx->mmap;
             mm_cursor->size != 0U; ++mm_cursor) {                         mm_cursor->size != 0U; ++mm_cursor) {

                uintptr_t mm_cursor_end_va = mm_cursor->ba |                  uintptr_t mm_cursor_end_va =
                                                        +  |                          mm_cursor->base_va + mm_cursor->si

                /*                                                            /*
                 * Check if one of the regions is complete                     * Check if one of the regions is complete
                 * one.                                                        * one.
                 */                                                            */
                bool fully_overlapped_va =                                    bool fully_overlapped_va =
                        ((base_va >= mm_cursor->base_va) &                            ((base_va >= mm_cursor->base_va) &
                                        (end_va <= mm_curs                                            (end_va <= mm_curs
                        ((mm_cursor->base_va >= base_va) &                            ((mm_cursor->base_va >= base_va) &
                                                (mm_cursor                                                    (mm_cursor

                /*                                                            /*
                 * Full VA overlaps are only allowed if bo                     * Full VA overlaps are only allowed if bo
                 * identity mapped (zero offset) or have t                     * identity mapped (zero offset) or have t
                 * offset. Also, make sure that it's not t                     * offset. Also, make sure that it's not t
                 * This can only be done with static regio                     * This can only be done with static regio
                 */                                                            */
                if (fully_overlapped_va) {                                    if (fully_overlapped_va) {

#if PLAT_XLAT_TABLES_DYNAMIC                                  #if PLAT_XLAT_TABLES_DYNAMIC
                        if (((mm->attr & MT_DYNAMIC) != 0U                            if (((mm->attr & MT_DYNAMIC) != 0U
                            ((mm_cursor->attr & MT_DYNAMIC                                ((mm_cursor->attr & MT_DYNAMIC
                                return -EPERM;                                                return -EPERM;
#endif /* PLAT_XLAT_TABLES_DYNAMIC */                         #endif /* PLAT_XLAT_TABLES_DYNAMIC */
                        if ((mm_cursor->base_va - mm_curso                            if ((mm_cursor->base_va - mm_curso
                                                        (b                                                            (b
                                return -EPERM;                                                return -EPERM;

                        if ((base_va == mm_cursor->base_va                            if ((base_va == mm_cursor->base_va
                                                (size == m                                                    (size == m
                                return -EPERM;                                                return -EPERM;

                } else {                                                      } else {
                        /*                                                            /*
                         * If the regions do not have full                             * If the regions do not have full
                         * then they must have fully separ                             * then they must have fully separ
                         * Partial overlaps are not allowe                             * Partial overlaps are not allowe
                         */                                                            */

                        unsigned long long mm_cursor_end_p                            unsigned long long mm_cursor_end_p
                                     mm_cursor->base_pa +                                          mm_cursor->base_pa + 

                        bool separated_pa = (end_pa < mm_c                            bool separated_pa = (end_pa < mm_c
                                (base_pa > mm_cursor_end_p                                    (base_pa > mm_cursor_end_p
                        bool separated_va = (end_va < mm_c                            bool separated_va = (end_va < mm_c
                                (base_va > mm_cursor_end_v                                    (base_va > mm_cursor_end_v

                        if (!separated_va || !separated_pa                            if (!separated_va || !separated_pa
                                return -EPERM;                                                return -EPERM;
                }                                                             }
        }                                                             }

        return 0;                                                     return 0;
}                                                             }

void mmap_add_region_ctx(xlat_ctx_t *ctx, const mmap_regio    void mmap_add_region_ctx(xlat_ctx_t *ctx, const mmap_regio
{                                                             {
        mmap_region_t *mm_cursor = ctx->mmap, *mm_destinat            mmap_region_t *mm_cursor = ctx->mmap, *mm_destinat
        const mmap_region_t *mm_end = ctx->mmap + ctx->mma            const mmap_region_t *mm_end = ctx->mmap + ctx->mma
        const mmap_region_t *mm_last;                                 const mmap_region_t *mm_last;
        unsigned long long end_pa = mm->base_pa + mm->size            unsigned long long end_pa = mm->base_pa + mm->size
        uintptr_t end_va = mm->base_va + mm->size - 1U;               uintptr_t end_va = mm->base_va + mm->size - 1U;
        int ret;                                                      int ret;

        /* Ignore empty regions */                                    /* Ignore empty regions */
        if (mm->size == 0U)                                           if (mm->size == 0U)
                return;                                                       return;

        /* Static regions must be added before initializin            /* Static regions must be added before initializin
        assert(!ctx->initialized);                                    assert(!ctx->initialized);

        ret = mmap_add_region_check(ctx, mm);                         ret = mmap_add_region_check(ctx, mm);
        if (ret != 0) {                                               if (ret != 0) {
                ERROR("mmap_add_region_check() failed. err                    ERROR("mmap_add_region_check() failed. err
                assert(false);                                                assert(false);
                return;                                                       return;
        }                                                             }

        /*                                                            /*
         * Find correct place in mmap to insert new region <
         *                                                 <
         * 1 - Lower region VA end first.                  <
         * 2 - Smaller region size first.                  <
         *                                                 <
         * VA  0                                   0xFF    <
         *                                                 <
         * 1st |------|                                    <
         * 2nd |------------|                              <
         * 3rd                 |------|                    <
         * 4th                            |---|            <
         * 5th                                   |---|     <
         * 6th                            |----------|     <
         * 7th |-------------------------------------|     <
         *                                                 <
         * This is required for overlapping regions only.  <
         * regions with the loop in xlat_tables_init_inter <
         * ones won't overwrite block or page descriptors  <
         * previously.                                     <
         *                                                 <
         * Overlapping is only allowed for static regions. <
         */                                                <
                                                           <
        while (((mm_cursor->base_va + mm_cursor->size - 1U <
               && (mm_cursor->size != 0U)) {               <
                ++mm_cursor;                               <
        }                                                  <
                                                           <
        while (((mm_cursor->base_va + mm_cursor->size - 1U <
               (mm_cursor->size != 0U) && (mm_cursor->size <
                ++mm_cursor;                               <
        }                                                  <
                                                           <
        /*                                                 <
         * Find the last entry marker in the mmap                      * Find the last entry marker in the mmap
         */                                                            */
        mm_last = ctx->mmap;                                          mm_last = ctx->mmap;
        while ((mm_last->size != 0U) && (mm_last < mm_end)            while ((mm_last->size != 0U) && (mm_last < mm_end)
                ++mm_last;                                                    ++mm_last;
        }                                                             }

        /*                                                            /*
         * Check if we have enough space in the memory map             * Check if we have enough space in the memory map
         * This shouldn't happen as we have checked in mma             * This shouldn't happen as we have checked in mma
         * that there is free space.                                   * that there is free space.
         */                                                            */
        assert(mm_last->size == 0U);                                  assert(mm_last->size == 0U);

        /* Make room for new region by moving other region            /* Make room for new region by moving other region
        mm_destination = mm_cursor + 1;                               mm_destination = mm_cursor + 1;
        (void)memmove(mm_destination, mm_cursor,                      (void)memmove(mm_destination, mm_cursor,
                (uintptr_t)mm_last - (uintptr_t)mm_cursor)                    (uintptr_t)mm_last - (uintptr_t)mm_cursor)

        /*                                                            /*
         * Check we haven't lost the empty sentinel from t             * Check we haven't lost the empty sentinel from t
         * This shouldn't happen as we have checked in mma             * This shouldn't happen as we have checked in mma
         * that there is free space.                                   * that there is free space.
         */                                                            */
        assert(mm_end->size == 0U);                                   assert(mm_end->size == 0U);

        *mm_cursor = *mm;                                             *mm_cursor = *mm;

        if (end_pa > ctx->max_pa)                                     if (end_pa > ctx->max_pa)
                ctx->max_pa = end_pa;                                         ctx->max_pa = end_pa;
        if (end_va > ctx->max_va)                                     if (end_va > ctx->max_va)
                ctx->max_va = end_va;                                         ctx->max_va = end_va;
}                                                             }

/*                                                         <
 * Determine the table level closest to the initial lookup <
 * can describe this translation. Then, align base VA to t <
 * at the determined level.                                <
 */                                                        <
static void mmap_alloc_va_align_ctx(xlat_ctx_t *ctx, mmap_ <
{                                                          <
        /*                                                 <
         * By or'ing the size and base PA the alignment wi <
         * corresponding to the smallest boundary of the t <
         *                                                 <
         * There are three different cases. For example (f <
         *                                                 <
         * +--------------+------------------++----------- <
         * | PA alignment | Size multiple of || VA alignme <
         * +--------------+------------------++----------- <
         * |     2 MiB    |       2 MiB      ||     2 MiB  <
         * |     2 MiB    |       4 KiB      ||     4 KiB  <
         * |     4 KiB    |       2 MiB      ||     4 KiB  <
         * +--------------+------------------++----------- <
         *                                                 <
         * - In (1), it is possible to take advantage of t <
         *   and the size of the region to use a level 2 t <
         *   instead of a level 3 one.                     <
         *                                                 <
         * - In (2), the size is smaller than a block entr <
         *   needed to use a level 3 table to describe the <
         *   will map more memory than the desired one.    <
         *                                                 <
         * - In (3), even though the region has the size o <
         *   entry, it isn't possible to describe the tran <
         *   block entry because of the alignment of the b <
         *                                                 <
         *   Only bits 47:21 of a level 2 block descriptor <
         *   bits 20:0 of the resulting address are 0 in t <
         *   this, the PA generated as result of this tran <
         *   2 MiB. The PA that was requested to be mapped <
         *   though, which means that the resulting transl <
         *   The only way to prevent this is by using a fi <
         */                                                <
        unsigned long long align_check;                    <
                                                           <
        align_check = mm->base_pa | (unsigned long long)mm <
                                                           <
        /*                                                 <
         * Assume it is always aligned to level 3. There's <
         * level because its block size is PAGE_SIZE. The  <
         * the addresses and size are aligned to PAGE_SIZE <
         * mmap_add_region.                                <
         */                                                <
        for (unsigned int level = ctx->base_level; level < <
                                                           <
                if ((align_check & XLAT_BLOCK_MASK(level)) <
                        continue;                          <
                                                           <
                mm->base_va = round_up(mm->base_va, XLAT_B <
                return;                                    <
        }                                                  <
}                                                          <
                                                           <
void mmap_add_region_alloc_va_ctx(xlat_ctx_t *ctx, mmap_re <
{                                                          <
        mm->base_va = ctx->max_va + 1UL;                   <
                                                           <
        assert(mm->size > 0U);                             <
                                                           <
        mmap_alloc_va_align_ctx(ctx, mm);                  <
                                                           <
        /* Detect overflows. More checks are done in mmap_ <
        assert(mm->base_va > ctx->max_va);                 <
                                                           <
        mmap_add_region_ctx(ctx, mm);                      <
}                                                          <
                                                           <
void mmap_add_ctx(xlat_ctx_t *ctx, const mmap_region_t *mm    void mmap_add_ctx(xlat_ctx_t *ctx, const mmap_region_t *mm
{                                                             {
        const mmap_region_t *mm_cursor = mm;                          const mmap_region_t *mm_cursor = mm;

        while (mm_cursor->granularity != 0U) {                        while (mm_cursor->granularity != 0U) {
                mmap_add_region_ctx(ctx, mm_cursor);                          mmap_add_region_ctx(ctx, mm_cursor);
                mm_cursor++;                                                  mm_cursor++;
        }                                                             }
}                                                             }

#if PLAT_XLAT_TABLES_DYNAMIC                               <
                                                           <
int mmap_add_dynamic_region_ctx(xlat_ctx_t *ctx, mmap_regi <
{                                                          <
        mmap_region_t *mm_cursor = ctx->mmap;              <
        const mmap_region_t *mm_last = mm_cursor + ctx->mm <
        unsigned long long end_pa = mm->base_pa + mm->size <
        uintptr_t end_va = mm->base_va + mm->size - 1U;    <
        int ret;                                           <
                                                           <
        /* Nothing to do */                                <
        if (mm->size == 0U)                                <
                return 0;                                  <
                                                           <
        /* Now this region is a dynamic one */             <
        mm->attr |= MT_DYNAMIC;                            <
                                                           <
        ret = mmap_add_region_check(ctx, mm);              <
        if (ret != 0)                                      <
                return ret;                                <
                                                           <
        /*                                                 <
         * Find the adequate entry in the mmap array in th <
         * static regions in mmap_add_region_ctx().        <
         */                                                <
                                                           <
        while (((mm_cursor->base_va + mm_cursor->size - 1U <
               && (mm_cursor->size != 0U)) {               <
                ++mm_cursor;                               <
        }                                                  <
                                                           <
        while (((mm_cursor->base_va + mm_cursor->size - 1U <
               (mm_cursor->size != 0U) && (mm_cursor->size <
                ++mm_cursor;                               <
        }                                                  <
                                                           <
        /* Make room for new region by moving other region <
        (void)memmove(mm_cursor + 1U, mm_cursor,           <
                     (uintptr_t)mm_last - (uintptr_t)mm_cu <
                                                           <
        /*                                                 <
         * Check we haven't lost the empty sentinal from t <
         * This shouldn't happen as we have checked in mma <
         * that there is free space.                       <
         */                                                <
        assert(mm_last->size == 0U);                       <
                                                           <
        *mm_cursor = *mm;                                  <
                                                           <
        /*                                                 <
         * Update the translation tables if the xlat table <
         * not, this region will be mapped when they are i <
         */                                                <
        if (ctx->initialized) {                            <
                end_va = xlat_tables_map_region(ctx, mm_cu <
                                0U, ctx->base_table, ctx-> <
                                ctx->base_level);          <
#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARL <
                xlat_clean_dcache_range((uintptr_t)ctx->ba <
                                   ctx->base_table_entries <
#endif                                                     <
                /* Failed to map, remove mmap entry, unmap <
                if (end_va != (mm_cursor->base_va + mm_cur <
                        (void)memmove(mm_cursor, mm_cursor <
                                (uintptr_t)mm_last - (uint <
                                                           <
                        /*                                 <
                         * Check if the mapping function a <
                         * anything. If not, just return n <
                         */                                <
                        if (mm->base_va >= end_va)         <
                                return -ENOMEM;            <
                                                           <
                        /*                                 <
                         * Something went wrong after mapp <
                         * entries, undo every change done <
                         */                                <
                        mmap_region_t unmap_mm = {         <
                                        .base_pa = 0U,     <
                                        .base_va = mm->bas <
                                        .size = end_va - m <
                                        .attr = 0U         <
                        };                                 <
                        xlat_tables_unmap_region(ctx, &unm <
                                ctx->base_table, ctx->base <
                                ctx->base_level);          <
#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARL <
                        xlat_clean_dcache_range((uintptr_t <
                                ctx->base_table_entries *  <
#endif                                                     <
                        return -ENOMEM;                    <
                }                                          <
                                                           <
                /*                                         <
                 * Make sure that all entries are written  <
                 * is no need to invalidate entries when m <
                 * because new table/block/page descriptor <
                 * invalid descriptors, that aren't TLB ca <
                 */                                        <
                dsbishst();                                <
        }                                                  <
                                                           <
        if (end_pa > ctx->max_pa)                          <
                ctx->max_pa = end_pa;                      <
        if (end_va > ctx->max_va)                          <
                ctx->max_va = end_va;                      <
                                                           <
        return 0;                                          <
}                                                          <
                                                           <
int mmap_add_dynamic_region_alloc_va_ctx(xlat_ctx_t *ctx,  <
{                                                          <
        mm->base_va = ctx->max_va + 1UL;                   <
                                                           <
        if (mm->size == 0U)                                <
                return 0;                                  <
                                                           <
        mmap_alloc_va_align_ctx(ctx, mm);                  <
                                                           <
        /* Detect overflows. More checks are done in mmap_ <
        if (mm->base_va < ctx->max_va) {                   <
                return -ENOMEM;                            <
        }                                                  <
                                                           <
        return mmap_add_dynamic_region_ctx(ctx, mm);       <
}                                                          <
                                                           <
/*                                                         <
 * Removes the region with given base Virtual Address and  <
 * context.                                                <
 *                                                         <
 * Returns:                                                <
 *        0: Success.                                      <
 *   EINVAL: Invalid values were used as arguments (region <
 *    EPERM: Tried to remove a static region.              <
 */                                                        <
int mmap_remove_dynamic_region_ctx(xlat_ctx_t *ctx, uintpt <
                                   size_t size)            <
{                                                          <
        mmap_region_t *mm = ctx->mmap;                     <
        const mmap_region_t *mm_last = mm + ctx->mmap_num; <
        int update_max_va_needed = 0;                      <
        int update_max_pa_needed = 0;                      <
                                                           <
        /* Check sanity of mmap array. */                  <
        assert(mm[ctx->mmap_num].size == 0U);              <
                                                           <
        while (mm->size != 0U) {                           <
                if ((mm->base_va == base_va) && (mm->size  <
                        break;                             <
                ++mm;                                      <
        }                                                  <
                                                           <
        /* Check that the region was found */              <
        if (mm->size == 0U)                                <
                return -EINVAL;                            <
                                                           <
        /* If the region is static it can't be removed */  <
        if ((mm->attr & MT_DYNAMIC) == 0U)                 <
                return -EPERM;                             <
                                                           <
        /* Check if this region is using the top VAs or PA <
        if ((mm->base_va + mm->size - 1U) == ctx->max_va)  <
                update_max_va_needed = 1;                  <
        if ((mm->base_pa + mm->size - 1U) == ctx->max_pa)  <
                update_max_pa_needed = 1;                  <
                                                           <
        /* Update the translation tables if needed */      <
        if (ctx->initialized) {                            <
                xlat_tables_unmap_region(ctx, mm, 0U, ctx- <
                                         ctx->base_table_e <
                                         ctx->base_level); <
#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARL <
                xlat_clean_dcache_range((uintptr_t)ctx->ba <
                        ctx->base_table_entries * sizeof(u <
#endif                                                     <
                xlat_arch_tlbi_va_sync();                  <
        }                                                  <
                                                           <
        /* Remove this region by moving the rest down by o <
        (void)memmove(mm, mm + 1U, (uintptr_t)mm_last - (u <
                                                           <
        /* Check if we need to update the max VAs and PAs  <
        if (update_max_va_needed == 1) {                   <
                ctx->max_va = 0U;                          <
                mm = ctx->mmap;                            <
                while (mm->size != 0U) {                   <
                        if ((mm->base_va + mm->size - 1U)  <
                                ctx->max_va = mm->base_va  <
                        ++mm;                              <
                }                                          <
        }                                                  <
                                                           <
        if (update_max_pa_needed == 1) {                   <
                ctx->max_pa = 0U;                          <
                mm = ctx->mmap;                            <
                while (mm->size != 0U) {                   <
                        if ((mm->base_pa + mm->size - 1U)  <
                                ctx->max_pa = mm->base_pa  <
                        ++mm;                              <
                }                                          <
        }                                                  <
                                                           <
        return 0;                                          <
}                                                          <
                                                           <
void xlat_setup_dynamic_ctx(xlat_ctx_t *ctx, unsigned long <
                            uintptr_t va_max, struct mmap_ <
                            unsigned int mmap_num, uint64_ <
                            unsigned int tables_num, uint6 <
                            int xlat_regime, int *mapped_r <
{                                                          <
        ctx->xlat_regime = xlat_regime;                    <
                                                           <
        ctx->pa_max_address = pa_max;                      <
        ctx->va_max_address = va_max;                      <
                                                           <
        ctx->mmap = mmap;                                  <
        ctx->mmap_num = mmap_num;                          <
        memset(ctx->mmap, 0, sizeof(struct mmap_region) *  <
                                                           <
        ctx->tables = (void *) tables;                     <
        ctx->tables_num = tables_num;                      <
                                                           <
        uintptr_t va_space_size = va_max + 1;              <
        ctx->base_level = GET_XLAT_TABLE_LEVEL_BASE(va_spa <
        ctx->base_table = base_table;                      <
        ctx->base_table_entries = GET_NUM_BASE_LEVEL_ENTRI <
                                                           <
        ctx->tables_mapped_regions = mapped_regions;       <
                                                           <
        ctx->max_pa = 0;                                   <
        ctx->max_va = 0;                                   <
        ctx->initialized = 0;                              <
}                                                          <
                                                           <
#endif /* PLAT_XLAT_TABLES_DYNAMIC */                      <
                                                           <
void __init init_xlat_tables_ctx(xlat_ctx_t *ctx)             void __init init_xlat_tables_ctx(xlat_ctx_t *ctx)
{                                                             {
                                                           >          uint64_t mair = UL(0);
                                                           >
        assert(ctx != NULL);                                          assert(ctx != NULL);
        assert(!ctx->initialized);                                    assert(!ctx->initialized);
                                                           >  #ifdef NO_EL3
                                                           >          assert((ctx->xlat_regime == EL2_REGIME) ||
                                                           >                 (ctx->xlat_regime == EL1_EL0_REGIME));
                                                           >  #else
        assert((ctx->xlat_regime == EL3_REGIME) ||                    assert((ctx->xlat_regime == EL3_REGIME) ||
               (ctx->xlat_regime == EL2_REGIME) ||                           (ctx->xlat_regime == EL2_REGIME) ||
               (ctx->xlat_regime == EL1_EL0_REGIME));                        (ctx->xlat_regime == EL1_EL0_REGIME));
        assert(!is_mmu_enabled_ctx(ctx));                  |  #endif
                                                           >          assert(!is_mpu_enabled_ctx(ctx));

        mmap_region_t *mm = ctx->mmap;                                mmap_region_t *mm = ctx->mmap;

        assert(ctx->va_max_address >=                                 assert(ctx->va_max_address >=
                (xlat_get_min_virt_addr_space_size() - 1U)                    (xlat_get_min_virt_addr_space_size() - 1U)
        assert(ctx->va_max_address <= (MAX_VIRT_ADDR_SPACE            assert(ctx->va_max_address <= (MAX_VIRT_ADDR_SPACE
        assert(IS_POWER_OF_TWO(ctx->va_max_address + 1U));            assert(IS_POWER_OF_TWO(ctx->va_max_address + 1U));

        xlat_mmap_print(mm);                                          xlat_mmap_print(mm);

        /* All tables must be zeroed before mapping any re            /* All tables must be zeroed before mapping any re

        for (unsigned int i = 0U; i < ctx->base_table_entr            for (unsigned int i = 0U; i < ctx->base_table_entr
                ctx->base_table[i] = INVALID_DESC;                            ctx->base_table[i] = INVALID_DESC;

        for (int j = 0; j < ctx->tables_num; j++) {        |          /* Also mark all MPU regions as invalid in the MPU
#if PLAT_XLAT_TABLES_DYNAMIC                               |          write_prenr_el2 (0);
                ctx->tables_mapped_regions[j] = 0;         |                  /* Sufficient for current, max-32-region i
#endif                                                     <
                for (unsigned int i = 0U; i < XLAT_TABLE_E <
                        ctx->tables[j][i] = INVALID_DESC;  <
        }                                                  <
                                                           <
        while (mm->size != 0U) {                                      while (mm->size != 0U) {
                uintptr_t end_va = xlat_tables_map_region( |                  if (read_prenr_el2() == ALL_MPU_EL2_REGION
                                ctx->base_table, ctx->base |                          ERROR("Not enough MPU regions to m
                                ctx->base_level);          <
#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARL <
                xlat_clean_dcache_range((uintptr_t)ctx->ba <
                                   ctx->base_table_entries <
#endif                                                     <
                if (end_va != (mm->base_va + mm->size - 1U <
                        ERROR("Not enough memory to map re <
                              " VA:0x%lx  PA:0x%llx  size:                                  " VA:0x%lx  PA:0x%llx  size:
                              mm->base_va, mm->base_pa, mm                                  mm->base_va, mm->base_pa, mm
                        panic();                                                      panic();
                                                           >                  } else {
                                                           >  #if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARL
                                                           >                          xlat_clean_dcache_range((uintptr_t
                                                           >                                     mm->size);
                                                           >  #endif
                                                           >                          mpu_map_region(mm);
                }                                                             }
                                                           <
                mm++;                                                         mm++;
        }                                                             }

        assert(ctx->pa_max_address <= xlat_arch_get_max_su <
        assert(ctx->max_va <= ctx->va_max_address);        <
        assert(ctx->max_pa <= ctx->pa_max_address);        <
                                                           <
        ctx->initialized = true;                                      ctx->initialized = true;

        xlat_tables_print(ctx);                                       xlat_tables_print(ctx);
                                                           >
                                                           >          /* Set attributes in the right indices of the MAIR
                                                           >          mair = MAIR_ATTR_SET(ATTR_DEVICE, ATTR_DEVICE_INDE
                                                           >          mair |= MAIR_ATTR_SET(ATTR_IWBWA_OWBWA_NTR,
                                                           >                          ATTR_IWBWA_OWBWA_NTR_INDEX);
                                                           >          mair |= MAIR_ATTR_SET(ATTR_NON_CACHEABLE,
                                                           >                          ATTR_NON_CACHEABLE_INDEX);
                                                           >          write_mair_el2(mair);
                                                           >  }
                                                           >
                                                           >  /*
                                                           >   * Function to wipe clean and disable all MPU regions.  Th
                                                           >   * that the MPU has already been turned off, and caching c
                                                           >   * but it nevertheless also explicitly turns off the MPU.
                                                           >   */
                                                           >  void clear_all_mpu_regions(void)
                                                           >  {
                                                           >          uint64_t sctlr_el2_value = 0UL;
                                                           >          uint64_t region_n = 0;
                                                           >
                                                           >          /* MPU should already be disabled, but explicitly 
                                                           >             nevertheless: */
                                                           >          sctlr_el2_value = read_sctlr_el2() & ~((uint64_t) 
                                                           >          write_sctlr_el2(sctlr_el2_value);
                                                           >
                                                           >          /* Disable all regions: */
                                                           >          write_prenr_el2 ((uint64_t) 0UL);
                                                           >
                                                           >          /* Sequence through all regions, zeroing them out 
                                                           >          for (region_n = 0UL;  region_n < N_MPU_REGIONS;  r
                                                           >                  write_prselr_el2 (region_n);
                                                           >                  write_prbar_el2((uint64_t) 0UL);
                                                           >                  write_prlar_el2((uint64_t) 0UL);
                                                           >          }
}                                                             }
Last Author
garymorrison-arm
Last Edited
Jul 2 2021, 10:52 PM