Page MenuHomePhabricator

Libxlat Tables V2xlat Tables Utilscvslibxlat Mpuxlat Mpu Utilsc
Updated 1,237 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 <stdio.h>                                            #include <stdio.h>

#include <platform_def.h>                                     #include <platform_def.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"

#if LOG_LEVEL < LOG_LEVEL_VERBOSE                             #if LOG_LEVEL < LOG_LEVEL_VERBOSE

void xlat_mmap_print(__unused const mmap_region_t *mmap)      void xlat_mmap_print(__unused const mmap_region_t *mmap)
{                                                             {
        /* Empty */                                                   /* Empty */
}                                                             }

void xlat_tables_print(__unused xlat_ctx_t *ctx)              void xlat_tables_print(__unused xlat_ctx_t *ctx)
{                                                             {
        /* Empty */                                                   /* Empty */
}                                                             }

#else /* if LOG_LEVEL >= LOG_LEVEL_VERBOSE */                 #else /* if LOG_LEVEL >= LOG_LEVEL_VERBOSE */

void xlat_mmap_print(const mmap_region_t *mmap)               void xlat_mmap_print(const mmap_region_t *mmap)
{                                                             {
        printf("mmap:\n");                                            printf("mmap:\n");
        const mmap_region_t *mm = mmap;                               const mmap_region_t *mm = mmap;

        while (mm->size != 0U) {                                      while (mm->size != 0U) {
                printf(" VA:0x%lx  PA:0x%llx  size:0x%zx                      printf(" VA:0x%lx  PA:0x%llx  size:0x%zx  
                       mm->base_va, mm->base_pa, mm->size,                           mm->base_va, mm->base_pa, mm->size,
                       mm->granularity);                                             mm->granularity);
                ++mm;                                                         ++mm;
        };                                                            };
        printf("\n");                                                 printf("\n");
}                                                             }

/* Print the attributes of the specified block descriptor.    /* Print the attributes of the specified block descriptor.
static void xlat_desc_print(const xlat_ctx_t *ctx, uint64_    static void xlat_desc_print(const xlat_ctx_t *ctx, uint64_
{                                                             {
        uint64_t mem_type_index = ATTR_INDEX_GET(desc);               uint64_t mem_type_index = ATTR_INDEX_GET(desc);
        int xlat_regime = ctx->xlat_regime;                           int xlat_regime = ctx->xlat_regime;

        if (mem_type_index == ATTR_IWBWA_OWBWA_NTR_INDEX)             if (mem_type_index == ATTR_IWBWA_OWBWA_NTR_INDEX) 
                printf("MEM");                                                printf("MEM");
        } else if (mem_type_index == ATTR_NON_CACHEABLE_IN            } else if (mem_type_index == ATTR_NON_CACHEABLE_IN
                printf("NC");                                                 printf("NC");
        } else {                                                      } else {
                assert(mem_type_index == ATTR_DEVICE_INDEX                    assert(mem_type_index == ATTR_DEVICE_INDEX
                printf("DEV");                                                printf("DEV");
        }                                                             }

                                                           >  #ifdef NO_EL3
                                                           >          if (xlat_regime == EL2_REGIME) {
                                                           >  #else
        if ((xlat_regime == EL3_REGIME) || (xlat_regime ==            if ((xlat_regime == EL3_REGIME) || (xlat_regime ==
                                                           >  #endif
                /* For EL3 and EL2 only check the AP[2] an                    /* For EL3 and EL2 only check the AP[2] an
                printf(((desc & LOWER_ATTRS(AP_RO)) != 0UL                    printf(((desc & LOWER_ATTRS(AP_RO)) != 0UL
                printf(((desc & UPPER_ATTRS(XN)) != 0ULL)                     printf(((desc & UPPER_ATTRS(XN)) != 0ULL) 
        } else {                                                      } else {
                assert(xlat_regime == EL1_EL0_REGIME);                        assert(xlat_regime == EL1_EL0_REGIME);
                /*                                                            /*
                 * For EL0 and EL1:                                            * For EL0 and EL1:
                 * - In AArch64 PXN and UXN can be set ind |                   * - In AArch64 PXN and UXN can be set ind
                 *   AArch32 there is no UXN (XN affects b |                   *   both privilege levels).  For consiste
                 *   For consistency, we set them simultan |                   *   simultaneously in both cases.
                 * - RO and RW permissions must be the sam                     * - RO and RW permissions must be the sam
                 *   EL0 can access that memory region, so                     *   EL0 can access that memory region, so
                 *   same permissions.                                         *   same permissions.
                 */                                                            */
#if ENABLE_ASSERTIONS                                         #if ENABLE_ASSERTIONS
                uint64_t xn_mask = xlat_arch_regime_get_xn                    uint64_t xn_mask = xlat_arch_regime_get_xn
                uint64_t xn_perm = desc & xn_mask;                            uint64_t xn_perm = desc & xn_mask;

                assert((xn_perm == xn_mask) || (xn_perm ==                    assert((xn_perm == xn_mask) || (xn_perm ==
#endif                                                        #endif
                printf(((desc & LOWER_ATTRS(AP_RO)) != 0UL                    printf(((desc & LOWER_ATTRS(AP_RO)) != 0UL
                /* Only check one of PXN and UXN, the othe                    /* Only check one of PXN and UXN, the othe
                printf(((desc & UPPER_ATTRS(PXN)) != 0ULL)                    printf(((desc & UPPER_ATTRS(PXN)) != 0ULL)
                /*                                                            /*
                 * Privileged regions can only be accessed                     * Privileged regions can only be accessed
                 * regions can be accessed from EL1 and EL                     * regions can be accessed from EL1 and EL
                 */                                                            */
                printf(((desc & LOWER_ATTRS(AP_ACCESS_UNPR                    printf(((desc & LOWER_ATTRS(AP_ACCESS_UNPR
                          ? "-USER" : "-PRIV");                                         ? "-USER" : "-PRIV");
        }                                                             }

        printf(((LOWER_ATTRS(NS) & desc) != 0ULL) ? "-NS"             printf(((LOWER_ATTRS(NS) & desc) != 0ULL) ? "-NS" 

#ifdef __aarch64__                                         <
        /* Check Guarded Page bit */                                  /* Check Guarded Page bit */
        if ((desc & GP) != 0ULL) {                                    if ((desc & GP) != 0ULL) {
                printf("-GP");                                                printf("-GP");
        }                                                             }
#endif                                                     <
}                                                             }

static const char * const level_spacers[] = {              <
        "[LV0] ",                                          <
        "  [LV1] ",                                        <
        "    [LV2] ",                                      <
        "      [LV3] "                                     <
};                                                         <
                                                           <
static const char *invalid_descriptors_ommited =              static const char *invalid_descriptors_ommited =
                "%s(%d invalid descriptors omitted)\n";                       "%s(%d invalid descriptors omitted)\n";

/*                                                            /*
 * Recursive function that reads the translation tables pa     * Recursive function that reads the translation tables pa
 * and prints their status.                                    * and prints their status.
 */                                                            */
static void xlat_tables_print_internal(xlat_ctx_t *ctx, ui    static void xlat_tables_print_internal(xlat_ctx_t *ctx, ui
                const uint64_t *table_base, unsigned int t                    const uint64_t *table_base, unsigned int t
                unsigned int level)                                           unsigned int level)
{                                                             {
        assert(level <= XLAT_TABLE_LEVEL_MAX);                        assert(level <= XLAT_TABLE_LEVEL_MAX);

        uint64_t desc;                                     |          int region_to_use = 0;
        uintptr_t table_idx_va = table_base_va;            |          uint64_t address = ((uint64_t) region_base);
        unsigned int table_idx = 0U;                       |          uint64_t address = ((uint64_t) region_size);
        size_t level_size = XLAT_BLOCK_SIZE(level);        |          uint64_t prenr_el2_value = 0;

        /*                                                            /*
         * Keep track of how many invalid descriptors are              * Keep track of how many invalid descriptors are 
         * Whenever multiple invalid descriptors are found             * Whenever multiple invalid descriptors are found
         * is printed, and a line is added to inform about             * is printed, and a line is added to inform about
         * have been omitted.                                          * have been omitted.
         */                                                            */
        int invalid_row_count = 0;                                    int invalid_row_count = 0;

        while (table_idx < table_entries) {                |          /* TODO:  Remove this comment when these API calls
                                                           |             implemented and tested! */
                desc = table_base[table_idx];              |          WARN("xlat_tables_print_internal() in this early v
                                                           |
                if ((desc & DESC_MASK) == INVALID_DESC) {  |          /* Sequence through all regions and print those in
                                                           |          prenr_el2_value = read_prenr_el2();
                        if (invalid_row_count == 0) {      |          for (region_to_use = 0;  region_to_use < N_MPU_REG
                                printf("%sVA:0x%lx size:0x |               region_to_use++) {
                                       level_spacers[level |                  if (((prenr_el2_value >> region_to_use) & 
                                       table_idx_va, level |                          continue;
                        }                                  <
                        invalid_row_count++;               <
                                                           <
                } else {                                   <
                                                           <
                        if (invalid_row_count > 1) {       <
                                printf(invalid_descriptors <
                                       level_spacers[level <
                                       invalid_row_count - <
                        }                                  <
                        invalid_row_count = 0;             <
                                                           <
                        /*                                 <
                         * Check if this is a table or a b <
                         * allowed in levels other than 3, <
                         * same value as DESC_TABLE, so we <
                         */                                <
                        if (((desc & DESC_MASK) == TABLE_D <
                                        (level < XLAT_TABL <
                                /*                         <
                                 * Do not print any PA for <
                                 * as it doesn't directly  <
                                 * but instead points to t <
                                 * table in the translatio <
                                 */                        <
                                printf("%sVA:0x%lx size:0x <
                                       level_spacers[level <
                                       table_idx_va, level <
                                                           <
                                uintptr_t addr_inner = des <
                                                           <
                                xlat_tables_print_internal <
                                        (uint64_t *)addr_i <
                                        XLAT_TABLE_ENTRIES <
                        } else {                           <
                                printf("%sVA:0x%lx PA:0x%l <
                                       level_spacers[level <
                                       (uint64_t)(desc & T <
                                       level_size);        <
                                xlat_desc_print(ctx, desc) <
                                printf("\n");              <
                        }                                  <
                }                                                             }
                                                           >                  region_base = read_prbar_el2() & PRBAR_PRL
                                                           >                  region_size = read_prlar_el2() & PRBAR_PRL
                                                           >                  printf("VA:0x%lx PA:0x%llx size:0x%llx ",
                                                           >                          region_base region_size);

                table_idx++;                               |                  }
                table_idx_va += level_size;                <
        }                                                  <
                                                           <
        if (invalid_row_count > 1) {                       <
                printf(invalid_descriptors_ommited,        <
                       level_spacers[level], invalid_row_c <
        }                                                             }
}                                                             }

void xlat_tables_print(xlat_ctx_t *ctx)                       void xlat_tables_print(xlat_ctx_t *ctx)
{                                                             {
        const char *xlat_regime_str;                                  const char *xlat_regime_str;
        int used_page_tables;                                         int used_page_tables;

        if (ctx->xlat_regime == EL1_EL0_REGIME) {                     if (ctx->xlat_regime == EL1_EL0_REGIME) {
                xlat_regime_str = "1&0";                                      xlat_regime_str = "1&0";
        } else if (ctx->xlat_regime == EL2_REGIME) {                  } else if (ctx->xlat_regime == EL2_REGIME) {
                xlat_regime_str = "2";                                        xlat_regime_str = "2";
        } else {                                                      } else {
                assert(ctx->xlat_regime == EL3_REGIME);                       assert(ctx->xlat_regime == EL3_REGIME);
                xlat_regime_str = "3";                                        xlat_regime_str = "3";
                                                           >                  /* If NO_EL3 and EL3 tables generated, the
        }                                                             }
        VERBOSE("Translation tables state:\n");                       VERBOSE("Translation tables state:\n");
        VERBOSE("  Xlat regime:     EL%s\n", xlat_regime_s            VERBOSE("  Xlat regime:     EL%s\n", xlat_regime_s
        VERBOSE("  Max allowed PA:  0x%llx\n", ctx->pa_max            VERBOSE("  Max allowed PA:  0x%llx\n", ctx->pa_max
        VERBOSE("  Max allowed VA:  0x%lx\n", ctx->va_max_            VERBOSE("  Max allowed VA:  0x%lx\n", ctx->va_max_
        VERBOSE("  Max mapped PA:   0x%llx\n", ctx->max_pa            VERBOSE("  Max mapped PA:   0x%llx\n", ctx->max_pa
        VERBOSE("  Max mapped VA:   0x%lx\n", ctx->max_va)            VERBOSE("  Max mapped VA:   0x%lx\n", ctx->max_va)

        VERBOSE("  Initial lookup level: %u\n", ctx->base_            VERBOSE("  Initial lookup level: %u\n", ctx->base_
        VERBOSE("  Entries @initial lookup level: %u\n",              VERBOSE("  Entries @initial lookup level: %u\n",
                ctx->base_table_entries);                                     ctx->base_table_entries);

                                                           >  #if 0  /* TODO:  Figure out whether this is relevant to MP
#if PLAT_XLAT_TABLES_DYNAMIC                                  #if PLAT_XLAT_TABLES_DYNAMIC
        used_page_tables = 0;                                         used_page_tables = 0;
        for (int i = 0; i < ctx->tables_num; ++i) {                   for (int i = 0; i < ctx->tables_num; ++i) {
                if (ctx->tables_mapped_regions[i] != 0)                       if (ctx->tables_mapped_regions[i] != 0)
                        ++used_page_tables;                                           ++used_page_tables;
        }                                                             }
#else                                                         #else
        used_page_tables = ctx->next_table;                           used_page_tables = ctx->next_table;
#endif                                                        #endif
        VERBOSE("  Used %d sub-tables out of %d (spare: %d            VERBOSE("  Used %d sub-tables out of %d (spare: %d
                used_page_tables, ctx->tables_num,                            used_page_tables, ctx->tables_num,
                ctx->tables_num - used_page_tables);                          ctx->tables_num - used_page_tables);
                                                           >  #endif  /* if 0 */

        xlat_tables_print_internal(ctx, 0U, ctx->base_tabl            xlat_tables_print_internal(ctx, 0U, ctx->base_tabl
                                   ctx->base_table_entries                                       ctx->base_table_entries
}                                                             }

#endif /* LOG_LEVEL >= LOG_LEVEL_VERBOSE */                   #endif /* LOG_LEVEL >= LOG_LEVEL_VERBOSE */

/*                                                         <
 * Do a translation table walk to find the block or page d <
 * virtual_addr.                                           <
 *                                                         <
 * On success, return the address of the descriptor within <
 * table. Its lookup level is stored in '*out_level'.      <
 * On error, return NULL.                                  <
 *                                                         <
 * xlat_table_base                                         <
 *   Base address for the initial lookup level.            <
 * xlat_table_base_entries                                 <
 *   Number of entries in the translation table for the in <
 * virt_addr_space_size                                    <
 *   Size in bytes of the virtual address space.           <
 */                                                        <
static uint64_t *find_xlat_table_entry(uintptr_t virtual_a <
                                       void *xlat_table_ba <
                                       unsigned int xlat_t <
                                       unsigned long long  <
                                       unsigned int *out_l <
{                                                          <
        unsigned int start_level;                          <
        uint64_t *table;                                   <
        unsigned int entries;                              <
                                                           <
        start_level = GET_XLAT_TABLE_LEVEL_BASE(virt_addr_ <
                                                           <
        table = xlat_table_base;                           <
        entries = xlat_table_base_entries;                 <
                                                           <
        for (unsigned int level = start_level;             <
             level <= XLAT_TABLE_LEVEL_MAX;                <
             ++level) {                                    <
                uint64_t idx, desc, desc_type;             <
                                                           <
                idx = XLAT_TABLE_IDX(virtual_addr, level); <
                if (idx >= entries) {                      <
                        WARN("Missing xlat table entry at  <
                             virtual_addr);                <
                        return NULL;                       <
                }                                          <
                                                           <
                desc = table[idx];                         <
                desc_type = desc & DESC_MASK;              <
                                                           <
                if (desc_type == INVALID_DESC) {           <
                        VERBOSE("Invalid entry (memory not <
                        return NULL;                       <
                }                                          <
                                                           <
                if (level == XLAT_TABLE_LEVEL_MAX) {       <
                        /*                                 <
                         * Only page descriptors allowed a <
                         * level.                          <
                         */                                <
                        assert(desc_type == PAGE_DESC);    <
                        *out_level = level;                <
                        return &table[idx];                <
                }                                          <
                                                           <
                if (desc_type == BLOCK_DESC) {             <
                        *out_level = level;                <
                        return &table[idx];                <
                }                                          <
                                                           <
                assert(desc_type == TABLE_DESC);           <
                table = (uint64_t *)(uintptr_t)(desc & TAB <
                entries = XLAT_TABLE_ENTRIES;              <
        }                                                  <
                                                           <
        /*                                                 <
         * This shouldn't be reached, the translation tabl <
         * most at level XLAT_TABLE_LEVEL_MAX and return f <
         */                                                <
        assert(false);                                     <
                                                           <
        return NULL;                                       <
}                                                          <
                                                           <
                                                           <
static int xlat_get_mem_attributes_internal(const xlat_ctx    static int xlat_get_mem_attributes_internal(const xlat_ctx
                uintptr_t base_va, uint32_t *attributes, u                    uintptr_t base_va, uint32_t *attributes, u
                unsigned long long *addr_pa, unsigned int                     unsigned long long *addr_pa, unsigned int 
{                                                             {
        uint64_t *entry;                                   |          int region_to_use = 0;
        uint64_t desc;                                     |          uint64_t prenr_el2_value = 0;
        unsigned int level;                                |          uint64_t region_base;
        unsigned long long virt_addr_space_size;           |          uint64_t region_extent;
                                                           >          uint64_t prbar_attrs = 0;
                                                           >          uint64_t prlar_attrs = 0;
                                                           >
                                                           >          /* TODO:  Remove this comment when these API calls
                                                           >             implemented and tested! */
                                                           >          WARN("xlat_get_mem_attributes_internal() in this e

        /*                                                            /*
         * Sanity-check arguments.                                     * Sanity-check arguments.
         */                                                            */
        assert(ctx != NULL);                                          assert(ctx != NULL);
        assert(ctx->initialized);                                     assert(ctx->initialized);
                                                           >  #ifdef NO_EL3
                                                           >          assert((ctx->xlat_regime == EL1_EL0_REGIME) ||
                                                           >                 (ctx->xlat_regime == EL2_REGIME));
                                                           >  #else
        assert((ctx->xlat_regime == EL1_EL0_REGIME) ||                assert((ctx->xlat_regime == EL1_EL0_REGIME) ||
               (ctx->xlat_regime == EL2_REGIME) ||                           (ctx->xlat_regime == EL2_REGIME) ||
               (ctx->xlat_regime == EL3_REGIME));                            (ctx->xlat_regime == EL3_REGIME));
                                                           >  #endif

        virt_addr_space_size = (unsigned long long)ctx->va |          /* Find the MPU region descriptor and extract base
        assert(virt_addr_space_size > 0U);                 |          prenr_el2_value = read_prenr_el2();
                                                           |          for (region_to_use = 0;  region_to_use < N_MPU_REG
        entry = find_xlat_table_entry(base_va,             |               region_to_use++) {
                                ctx->base_table,           |                  if (((prenr_el2_value >> region_to_use) & 
                                ctx->base_table_entries,   |                          continue;
                                virt_addr_space_size,      |                  }
                                &level);                   |                  region_base = read_prbar_el2() & PRBAR_PRL
        if (entry == NULL) {                               |                  region_extent = read_prlar_el2() & PRBAR_P
                WARN("Address 0x%lx is not mapped.\n", bas |                  region_extent += region_base;
                return -EINVAL;                            |                  prbar_attrs =   (read_prbar_el2() >> PRBAR
        }                                                  |                                & PRBAR_ATTR_MASK;
                                                           |                  prlar_attrs =   (read_prlar_el2() >> PRLAR
        if (addr_pa != NULL) {                             |                                & PRLAR_ATTR_MASK;
                *addr_pa = *entry & TABLE_ADDR_MASK;       |                  if (base_va >= region_base && base_va <= r
        }                                                  |                          break;
                                                           |                  }
        if (table_entry != NULL) {                         <
                *table_entry = entry;                      <
        }                                                             }
                                                           |          if (region_to_use > N_MPU_REGIONS) {
        if (table_level != NULL) {                         |                  WARN("%s: Changing region attributes did n
                *table_level = level;                      |                       __func__);
                                                           >                  return -EINVAL;
        }                                                             }

        desc = *entry;                                     <
                                                           <
#if LOG_LEVEL >= LOG_LEVEL_VERBOSE                            #if LOG_LEVEL >= LOG_LEVEL_VERBOSE
        VERBOSE("Attributes: ");                                      VERBOSE("Attributes: ");
        xlat_desc_print(ctx, desc);                                   xlat_desc_print(ctx, desc);
        printf("\n");                                                 printf("\n");
#endif /* LOG_LEVEL >= LOG_LEVEL_VERBOSE */                   #endif /* LOG_LEVEL >= LOG_LEVEL_VERBOSE */

        assert(attributes != NULL);                        |          *attributes = region_attr (prbar_attrs, prlar_attr
        *attributes = 0U;                                  |          *addr_pa = base_va;
                                                           |          *table_entry = (uint64_t *) NULL;
        uint64_t attr_index = (desc >> ATTR_INDEX_SHIFT) & |          *table_level = 0;  /* no levels on an MPU */
                                                           <
        if (attr_index == ATTR_IWBWA_OWBWA_NTR_INDEX) {    <
                *attributes |= MT_MEMORY;                  <
        } else if (attr_index == ATTR_NON_CACHEABLE_INDEX) <
                *attributes |= MT_NON_CACHEABLE;           <
        } else {                                           <
                assert(attr_index == ATTR_DEVICE_INDEX);   <
                *attributes |= MT_DEVICE;                  <
        }                                                  <
                                                           <
        uint64_t ap2_bit = (desc >> AP2_SHIFT) & 1U;       <
                                                           <
        if (ap2_bit == AP2_RW)                             <
                *attributes |= MT_RW;                      <
                                                           <
        if (ctx->xlat_regime == EL1_EL0_REGIME) {          <
                uint64_t ap1_bit = (desc >> AP1_SHIFT) & 1 <
                                                           <
                if (ap1_bit == AP1_ACCESS_UNPRIVILEGED)    <
                        *attributes |= MT_USER;            <
        }                                                  <
                                                           <
        uint64_t ns_bit = (desc >> NS_SHIFT) & 1U;         <
                                                           <
        if (ns_bit == 1U)                                  <
                *attributes |= MT_NS;                      <
                                                           <
        uint64_t xn_mask = xlat_arch_regime_get_xn_desc(ct <
                                                           <
        if ((desc & xn_mask) == xn_mask) {                 <
                *attributes |= MT_EXECUTE_NEVER;           <
        } else {                                           <
                assert((desc & xn_mask) == 0U);            <
        }                                                  <
                                                           <
        return 0;                                                     return 0;
}                                                             }


int xlat_get_mem_attributes_ctx(const xlat_ctx_t *ctx, uin    int xlat_get_mem_attributes_ctx(const xlat_ctx_t *ctx, uin
                                uint32_t *attr)                                               uint32_t *attr)
{                                                             {
        return xlat_get_mem_attributes_internal(ctx, base_            return xlat_get_mem_attributes_internal(ctx, base_
                                NULL, NULL, NULL);                                            NULL, NULL, NULL);
}                                                             }


int xlat_change_mem_attributes_ctx(const xlat_ctx_t *ctx,     int xlat_change_mem_attributes_ctx(const xlat_ctx_t *ctx, 
                                   size_t size, uint32_t a                                       size_t size, uint32_t a
{                                                             {
        /* Note: This implementation isn't optimized. */   |          int region_to_use = 0;
                                                           >          uint64_t address = ((uint64_t) base_va);
                                                           >          uint64_t region_base;
                                                           >          uint64_t region_extent;
                                                           >          uint64_t prenr_el2_value = 0;
                                                           >          uint64_t prbar_attrs = 0;
                                                           >          uint64_t prlar_attrs = 0;

        assert(ctx != NULL);                                          assert(ctx != NULL);
        assert(ctx->initialized);                                     assert(ctx->initialized);

        unsigned long long virt_addr_space_size =                     unsigned long long virt_addr_space_size =
                (unsigned long long)ctx->va_max_address +                     (unsigned long long)ctx->va_max_address + 
        assert(virt_addr_space_size > 0U);                            assert(virt_addr_space_size > 0U);

                                                           >          /* TODO:  Remove this comment when these API calls
                                                           >             implemented and tested! */
                                                           >          WARN("xlat_change_mem_attributes_ctx() in this ear
                                                           >
        if (!IS_PAGE_ALIGNED(base_va)) {                              if (!IS_PAGE_ALIGNED(base_va)) {
                WARN("%s: Address 0x%lx is not aligned on                     WARN("%s: Address 0x%lx is not aligned on 
                     __func__, base_va);                                           __func__, base_va);
                return -EINVAL;                                               return -EINVAL;
        }                                                             }

        if (size == 0U) {                                             if (size == 0U) {
                WARN("%s: Size is 0.\n", __func__);                           WARN("%s: Size is 0.\n", __func__);
                return -EINVAL;                                               return -EINVAL;
        }                                                             }

        if ((size % PAGE_SIZE) != 0U) {                    <
                WARN("%s: Size 0x%zx is not a multiple of  <
                     __func__, size);                      <
                return -EINVAL;                            <
        }                                                  <
                                                           <
        if (((attr & MT_EXECUTE_NEVER) == 0U) && ((attr &             if (((attr & MT_EXECUTE_NEVER) == 0U) && ((attr & 
                WARN("%s: Mapping memory as read-write and                    WARN("%s: Mapping memory as read-write and
                     __func__);                                                    __func__);
                return -EINVAL;                                               return -EINVAL;
        }                                                             }

        size_t pages_count = size / PAGE_SIZE;                        size_t pages_count = size / PAGE_SIZE;

        VERBOSE("Changing memory attributes of %zu pages s |          VERBOSE("Changing memory attributes of %zu regions
                pages_count, base_va);                                        pages_count, base_va);

        uintptr_t base_va_original = base_va;              |          /* Find and select MPU region containing base_va: 
                                                           |          prenr_el2_value = read_prenr_el2();
        /*                                                 |          for (region_to_use = 0;  region_to_use < N_MPU_REG
         * Sanity checks.                                  |               region_to_use++) {
         */                                                |                  if (((prenr_el2_value >> region_to_use) & 
        for (unsigned int i = 0U; i < pages_count; ++i) {  |                          continue;
                const uint64_t *entry;                     <
                uint64_t desc, attr_index;                 <
                unsigned int level;                        <
                                                           <
                entry = find_xlat_table_entry(base_va,     <
                                              ctx->base_ta <
                                              ctx->base_ta <
                                              virt_addr_sp <
                                              &level);     <
                if (entry == NULL) {                       <
                        WARN("Address 0x%lx is not mapped. <
                        return -EINVAL;                    <
                }                                                             }
                                                           |                  region_base = read_prbar_el2() & PRBAR_PRL
                desc = *entry;                             |                  region_extent = read_prlar_el2() & PRBAR_P
                                                           |                  region_extent += region_base;
                /*                                         |                  if (address >= region_base && address <= r
                 * Check that all the required pages are m |                          break;
                 * granularity.                            <
                 */                                        <
                if (((desc & DESC_MASK) != PAGE_DESC) ||   <
                        (level != XLAT_TABLE_LEVEL_MAX)) { <
                        WARN("Address 0x%lx is not mapped  <
                             base_va);                     <
                        WARN("Granularity is 0x%lx, should <
                             XLAT_BLOCK_SIZE(level), PAGE_ <
                        return -EINVAL;                    <
                }                                                             }
                                                           <
                /*                                         <
                 * If the region type is device, it should <
                 */                                        <
                attr_index = (desc >> ATTR_INDEX_SHIFT) &  <
                if (attr_index == ATTR_DEVICE_INDEX) {     <
                        if ((attr & MT_EXECUTE_NEVER) == 0 <
                                WARN("Setting device memor <
                                     base_va);             <
                                return -EINVAL;            <
                        }                                  <
                }                                          <
                                                           <
                base_va += PAGE_SIZE;                      <
        }                                                             }
                                                           |          if (region_to_use > N_MPU_REGIONS) {
        /* Restore original value. */                      |                  WARN("%s: Changing region attributes did n
        base_va = base_va_original;                        |                       __func__);
                                                           |                  return -EINVAL;
        for (unsigned int i = 0U; i < pages_count; ++i) {  <
                                                           <
                uint32_t old_attr = 0U, new_attr;          <
                uint64_t *entry = NULL;                    <
                unsigned int level = 0U;                   <
                unsigned long long addr_pa = 0ULL;         <
                                                           <
                (void) xlat_get_mem_attributes_internal(ct <
                                            &entry, &addr_ <
                                                           <
                /*                                         <
                 * From attr, only MT_RO/MT_RW, MT_EXECUTE <
                 * MT_USER/MT_PRIVILEGED are taken into ac <
                 * information is ignored.                 <
                 */                                        <
                                                           <
                /* Clean the old attributes so that they c <
                new_attr = old_attr & ~(MT_RW | MT_EXECUTE <
                                                           <
                /*                                         <
                 * Update attributes, but filter out the o <
                 * isn't allowed to change.                <
                 */                                        <
                new_attr |= attr & (MT_RW | MT_EXECUTE_NEV <
                                                           <
                /*                                         <
                 * The break-before-make sequence requires <
                 * descriptor and making sure that the sys <
                 * before writing the new descriptor.      <
                 */                                        <
                *entry = INVALID_DESC;                     <
#if !HW_ASSISTED_COHERENCY                                 <
                dccvac((uintptr_t)entry);                  <
#endif                                                     <
                /* Invalidate any cached copy of this mapp <
                xlat_arch_tlbi_va(base_va, ctx->xlat_regim <
                                                           <
                /* Ensure completion of the invalidation.  <
                xlat_arch_tlbi_va_sync();                  <
                                                           <
                /* Write new descriptor */                 <
                *entry = xlat_desc(ctx, new_attr, addr_pa, <
#if !HW_ASSISTED_COHERENCY                                 <
                dccvac((uintptr_t)entry);                  <
#endif                                                     <
                base_va += PAGE_SIZE;                      <
        }                                                             }
                                                           >          write_prselr_el2 ((uint64_t) (region_to_use));
                                                           >
                                                           >          /* Change attributes: */
                                                           >          prbar_attrs = prbar_attr_value (attr);
                                                           >          write_prbar_el2(read_prbar_el2() | prbar_attrs);
                                                           >          prlar_attrs = prlar_attr_value (attr);
                                                           >          write_prlar_el2(read_prlar_el2() | prlar_attrs);

        /* Ensure that the last descriptor writen is seen             /* Ensure that the last descriptor writen is seen 
        dsbish();                                                     dsbish();

        return 0;                                                     return 0;
}                                                             }
Last Author
garymorrison-arm
Last Edited
Jul 2 2021, 10:48 PM