| /* SPDX-License-Identifier: Apache-2.0 |
| * |
| * Copyright (c) 2019 Lexmark International, Inc. |
| */ |
| |
| #include <zephyr/sys/math_extras.h> |
| |
| /** |
| * Get the number of supported MPU regions. |
| */ |
| static inline uint8_t get_num_regions(void) |
| { |
| #if defined(NUM_MPU_REGIONS) |
| /* Retrieve the number of regions from DTS configuration. */ |
| return NUM_MPU_REGIONS; |
| #else |
| uint32_t type; |
| |
| __asm__ volatile("mrc p15, 0, %0, c0, c0, 4" : "=r" (type) ::); |
| |
| type = (type & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos; |
| |
| return (uint8_t)type; |
| #endif /* NUM_MPU_REGIONS */ |
| } |
| |
| static inline uint32_t get_region_attributes(void) |
| { |
| uint32_t attr; |
| |
| __asm__ volatile("mrc p15, 0, %0, c6, c1, 4" : "=r" (attr) ::); |
| return attr; |
| } |
| |
| static inline uint32_t get_region_base_address(void) |
| { |
| uint32_t addr; |
| |
| __asm__ volatile("mrc p15, 0, %0, c6, c1, 0" : "=r" (addr) ::); |
| return addr; |
| } |
| |
| static inline uint32_t get_region_size(void) |
| { |
| uint32_t size; |
| |
| __asm__ volatile("mrc p15, 0, %0, c6, c1, 2" : "=r" (size) ::); |
| return size; |
| } |
| |
| static inline void set_region_attributes(uint32_t attr) |
| { |
| __asm__ volatile("mcr p15, 0, %0, c6, c1, 4" :: "r" (attr) :); |
| } |
| |
| static inline void set_region_base_address(uint32_t addr) |
| { |
| __asm__ volatile("mcr p15, 0, %0, c6, c1, 0" :: "r" (addr) :); |
| } |
| |
| static inline void set_region_number(uint32_t index) |
| { |
| __asm__ volatile("mcr p15, 0, %0, c6, c2, 0" :: "r" (index) :); |
| } |
| |
| static inline uint32_t mpu_region_get_base(uint32_t index) |
| { |
| set_region_number(index); |
| |
| return get_region_base_address() & MPU_RBAR_ADDR_Msk; |
| } |
| |
| /** |
| * This internal function converts the SIZE field value of MPU_RASR |
| * to the region size (in bytes). |
| */ |
| static inline uint32_t mpu_rasr_size_to_size(uint32_t rasr_size) |
| { |
| return 1 << (rasr_size + 1U); |
| } |
| |
| static inline void set_region_size(uint32_t size) |
| { |
| __asm__ volatile("mcr p15, 0, %0, c6, c1, 2" :: "r" (size) :); |
| } |
| |
| static inline void ARM_MPU_ClrRegion(uint32_t rnr) |
| { |
| set_region_number(rnr); |
| /* clear size field, which contains enable bit */ |
| set_region_size(0); |
| } |
| |
| /** |
| * This internal function checks if region is enabled or not. |
| * |
| * Note: |
| * The caller must provide a valid region number. |
| */ |
| static inline int is_enabled_region(uint32_t index) |
| { |
| set_region_number(index); |
| |
| return (get_region_size() & MPU_RASR_ENABLE_Msk) ? 1 : 0; |
| } |
| |
| /** |
| * This internal function returns the access permissions of an MPU region |
| * specified by its region index. |
| * |
| * Note: |
| * The caller must provide a valid region number. |
| */ |
| static inline uint32_t get_region_ap(uint32_t r_index) |
| { |
| set_region_number(r_index); |
| |
| return (get_region_attributes() & MPU_RASR_AP_Msk) >> MPU_RASR_AP_Pos; |
| } |
| |
| /** |
| * This internal function checks if the given buffer is in the region. |
| * |
| * Note: |
| * The caller must provide a valid region number. |
| */ |
| static inline int is_in_region(uint32_t r_index, uint32_t start, uint32_t size) |
| { |
| uint32_t r_addr_start; |
| uint32_t r_size_lshift; |
| uint32_t r_addr_end; |
| uint32_t end; |
| |
| set_region_number(r_index); |
| |
| r_addr_start = get_region_base_address() & MPU_RBAR_ADDR_Msk; |
| |
| r_size_lshift = ((get_region_size() & MPU_RASR_SIZE_Msk) >> |
| MPU_RASR_SIZE_Pos) + 1; |
| |
| r_addr_end = r_addr_start + (1UL << r_size_lshift) - 1; |
| |
| size = size == 0 ? 0 : size - 1; |
| if (u32_add_overflow(start, size, &end)) { |
| return 0; |
| } |
| |
| if ((start >= r_addr_start) && (end <= r_addr_end)) { |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| static inline uint32_t mpu_region_get_size(uint32_t index) |
| { |
| set_region_number(index); |
| |
| uint32_t rasr_size = |
| (get_region_size() & MPU_RASR_SIZE_Msk) >> MPU_RASR_SIZE_Pos; |
| |
| return mpu_rasr_size_to_size(rasr_size); |
| } |