/* * Copyright (C) 2016 The Android Open Source Project * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include /* 48-bit physical address bits 47:12 */ #define NS_PTE_PHYSADDR_SHIFT 12 #define NS_PTE_PHYSADDR(pte) ((pte) & 0xFFFFFFFFF000ULL) /* Access permissions bits 7:6 * EL0 EL1 * 00 None RW * 01 RW RW * 10 None RO * 11 RO RO */ #define NS_PTE_AP_SHIFT 6 #define NS_PTE_AP_MASK (0x3 << NS_PTE_AP_SHIFT) /* Memory type and cache attributes bits 55:48 */ #define NS_PTE_MAIR_SHIFT 48 #define NS_PTE_MAIR_MASK (0x00FFULL << NS_PTE_MAIR_SHIFT) #define NS_PTE_MAIR_INNER_SHIFT 48 #define NS_PTE_MAIR_INNER_MASK (0x000FULL << NS_PTE_MAIR_INNER_SHIFT) #define NS_PTE_MAIR_OUTER_SHIFT 52 #define NS_PTE_MAIR_OUTER_MASK (0x000FULL << NS_PTE_MAIR_OUTER_SHIFT) /* Normal memory */ #define NS_MAIR_NORMAL_CACHED_WB_RWA 0xFF /* inner and outer write back read/write allocate */ #define NS_MAIR_NORMAL_CACHED_WT_RA 0xAA /* inner and outer write through read allocate */ #define NS_MAIR_NORMAL_CACHED_WB_RA 0xEE /* inner and outer write back, read allocate */ #define NS_MAIR_NORMAL_UNCACHED 0x44 /* uncached */ /* Device memory */ #define NS_MAIR_DEVICE_STRONGLY_ORDERED 0x00 /* nGnRnE (strongly ordered) */ #define NS_MAIR_DEVICE 0x04 /* nGnRE (device) */ #define NS_MAIR_DEVICE_GRE 0x0C /* GRE */ /* shareable attributes bits 9:8 */ #define NS_PTE_SHAREABLE_SHIFT 8 #define NS_NON_SHAREABLE 0x0 #define NS_OUTER_SHAREABLE 0x2 #define NS_INNER_SHAREABLE 0x3 typedef uintptr_t addr_t; typedef uintptr_t vaddr_t; typedef uintptr_t paddr_t; #if NS_ARCH_ARM64 #define PAR_F (0x1 << 0) /* * ARM64 */ /* Note: this will crash if called from user space */ static void arm64_write_ATS1ExW(uint64_t vaddr) { uint64_t _current_el; __asm__ volatile("mrs %0, CurrentEL" : "=r" (_current_el)); _current_el = (_current_el >> 2) & 0x3; switch (_current_el) { case 0x1: __asm__ volatile("at S1E1W, %0" :: "r" (vaddr)); break; case 0x2: __asm__ volatile("at S1E2W, %0" :: "r" (vaddr)); break; case 0x3: default: trusty_fatal("Unsupported execution state: EL%u\n", _current_el ); break; } __asm__ volatile("isb" ::: "memory"); } static uint64_t arm64_read_par64(void) { uint64_t _val; __asm__ volatile("mrs %0, par_el1" : "=r" (_val)); return _val; } static uint64_t va2par(vaddr_t va) { uint64_t par; unsigned long irq_state; trusty_local_irq_disable(&irq_state); arm64_write_ATS1ExW(va); par = arm64_read_par64(); trusty_local_irq_restore(&irq_state); return par; } static uint64_t par2attr(uint64_t par) { uint64_t attr; /* set phys address */ attr = NS_PTE_PHYSADDR(par); /* cache attributes */ attr |= ((par >> 56) & 0xFF) << NS_PTE_MAIR_SHIFT; /* shareable attributes */ attr |= ((par >> 7) & 0x03) << NS_PTE_SHAREABLE_SHIFT; /* the memory is writable and accessible so leave AP field 0 */ attr |= 0x0 << NS_PTE_AP_SHIFT; return attr; } #else #define PAR_F (0x1 << 0) #define PAR_SS (0x1 << 1) #define PAR_SH (0x1 << 7) #define PAR_NOS (0x1 << 10) #define PAR_LPAE (0x1 << 11) /* * ARM32 */ /* Note: this will crash if called from user space */ static void arm_write_ATS1xW(uint64_t vaddr) { uint32_t _cpsr; __asm__ volatile("mrs %0, cpsr" : "=r"(_cpsr)); if ((_cpsr & 0xF) == 0xa) __asm__ volatile("mcr p15, 4, %0, c7, c8, 1" : : "r"(vaddr)); else __asm__ volatile("mcr p15, 0, %0, c7, c8, 1" : : "r"(vaddr)); } static uint64_t arm_read_par64(void) { uint32_t lower, higher; __asm__ volatile( "mrc p15, 0, %0, c7, c4, 0 \n" "tst %0, #(1 << 11) @ LPAE / long desc format\n" "moveq %1, #0 \n" "mrrcne p15, 0, %0, %1, c7 \n" :"=r"(lower), "=r"(higher) : : ); return ((uint64_t)higher << 32) | lower; } static uint8_t ish_to_mair[8] = { 0x04, /* 0b000 Non cacheble */ 0x00, /* 0b001 Strongly ordered */ 0xF0, /* 0b010 reserved */ 0x04, /* 0b011 device */ 0xF0, /* 0b100 reserved */ 0x0F, /* 0b101 write back - write allocate */ 0x0A, /* 0b110 write through */ 0x0E, /* 0b111 write back - no write allocate */ }; static uint8_t osh_to_mair[4] = { 0x00, /* 0b00 Non-cacheable */ 0x0F, /* 0b01 Write-back, Write-allocate */ 0x0A, /* 0b10 Write-through, no Write-allocate */ 0x0E, /* 0b11 Write-back, no Write-allocate */ }; static uint64_t par2attr(uint64_t par) { uint64_t attr; if (par & PAR_LPAE) { /* set phys address */ attr = NS_PTE_PHYSADDR(par); /* cache attributes */ attr |= ((par >> 56) & 0xFF) << NS_PTE_MAIR_SHIFT; /* shareable attributes */ attr |= ((par >> 7) & 0x03) << NS_PTE_SHAREABLE_SHIFT; } else { /* set phys address */ trusty_assert((par & PAR_SS) == 0); /* super section not supported */ attr = NS_PTE_PHYSADDR(par); /* cache attributes */ uint64_t inner = ((uint64_t)ish_to_mair[(par >> 4) & 0x7]) << NS_PTE_MAIR_INNER_SHIFT; uint64_t outer = ((uint64_t)osh_to_mair[(par >> 2) & 0x3]) << NS_PTE_MAIR_OUTER_SHIFT; uint64_t cache_attributes = (outer << 4) | inner; /* Trusty does not support any kind of device memory, so we will force * cache attributes to be NORMAL UNCACHED on the Trusty side. */ if (cache_attributes == NS_MAIR_DEVICE_STRONGLY_ORDERED) { attr |= ((uint64_t)NS_MAIR_NORMAL_UNCACHED << NS_PTE_MAIR_SHIFT); } else { attr |= inner; attr |= outer; } /* shareable attributes */ if (par & PAR_SH) { /* how to handle NOS bit ? */ attr |= ((uint64_t)NS_INNER_SHAREABLE) << NS_PTE_SHAREABLE_SHIFT; } else { attr |= ((uint64_t)NS_NON_SHAREABLE) << NS_PTE_SHAREABLE_SHIFT; } } /* the memory is writable and accessible so leave AP field 0 */ attr |= 0x0 << NS_PTE_AP_SHIFT; return attr; } static uint64_t va2par(vaddr_t va) { uint64_t par; unsigned long irq_state; trusty_local_irq_disable(&irq_state); arm_write_ATS1xW(va); par = arm_read_par64(); trusty_local_irq_restore(&irq_state); return par; } #endif /* ARM64 */ int trusty_encode_page_info(struct ns_mem_page_info *inf, void *va) { uint64_t par = va2par((vaddr_t)va); if (par & PAR_F) { return -1; } inf->attr = par2attr(par); return 0; }