summaryrefslogtreecommitdiff
path: root/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta_mmu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta_mmu.c')
-rw-r--r--drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta_mmu.c586
1 files changed, 586 insertions, 0 deletions
diff --git a/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta_mmu.c b/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta_mmu.c
new file mode 100644
index 000000000000..fda0493e14c5
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta_mmu.c
@@ -0,0 +1,586 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_types.h"
+#include "gc_hal_base.h"
+#include "gc_hal_security_interface.h"
+#include "gc_hal_ta.h"
+#include "gc_hal.h"
+
+#define _GC_OBJ_ZONE 2
+/*******************************************************************************
+************************************ Define ************************************
+********************************************************************************/
+
+#define gcdMMU_MTLB_SHIFT 22
+#define gcdMMU_STLB_4K_SHIFT 12
+#define gcdMMU_STLB_64K_SHIFT 16
+
+#define gcdMMU_MTLB_BITS (32 - gcdMMU_MTLB_SHIFT)
+#define gcdMMU_PAGE_4K_BITS gcdMMU_STLB_4K_SHIFT
+#define gcdMMU_STLB_4K_BITS (32 - gcdMMU_MTLB_BITS - gcdMMU_PAGE_4K_BITS)
+#define gcdMMU_PAGE_64K_BITS gcdMMU_STLB_64K_SHIFT
+#define gcdMMU_STLB_64K_BITS (32 - gcdMMU_MTLB_BITS - gcdMMU_PAGE_64K_BITS)
+
+#define gcdMMU_MTLB_ENTRY_NUM (1 << gcdMMU_MTLB_BITS)
+#define gcdMMU_MTLB_SIZE (gcdMMU_MTLB_ENTRY_NUM << 2)
+#define gcdMMU_STLB_4K_ENTRY_NUM (1 << gcdMMU_STLB_4K_BITS)
+#define gcdMMU_STLB_4K_SIZE (gcdMMU_STLB_4K_ENTRY_NUM << 2)
+#define gcdMMU_PAGE_4K_SIZE (1 << gcdMMU_STLB_4K_SHIFT)
+#define gcdMMU_STLB_64K_ENTRY_NUM (1 << gcdMMU_STLB_64K_BITS)
+#define gcdMMU_STLB_64K_SIZE (gcdMMU_STLB_64K_ENTRY_NUM << 2)
+#define gcdMMU_PAGE_64K_SIZE (1 << gcdMMU_STLB_64K_SHIFT)
+
+#define gcdMMU_MTLB_MASK (~((1U << gcdMMU_MTLB_SHIFT)-1))
+#define gcdMMU_STLB_4K_MASK ((~0U << gcdMMU_STLB_4K_SHIFT) ^ gcdMMU_MTLB_MASK)
+#define gcdMMU_PAGE_4K_MASK (gcdMMU_PAGE_4K_SIZE - 1)
+#define gcdMMU_STLB_64K_MASK ((~((1U << gcdMMU_STLB_64K_SHIFT)-1)) ^ gcdMMU_MTLB_MASK)
+#define gcdMMU_PAGE_64K_MASK (gcdMMU_PAGE_64K_SIZE - 1)
+
+/* Page offset definitions. */
+#define gcdMMU_OFFSET_4K_BITS (32 - gcdMMU_MTLB_BITS - gcdMMU_STLB_4K_BITS)
+#define gcdMMU_OFFSET_4K_MASK ((1U << gcdMMU_OFFSET_4K_BITS) - 1)
+#define gcdMMU_OFFSET_16K_BITS (32 - gcdMMU_MTLB_BITS - gcdMMU_STLB_16K_BITS)
+#define gcdMMU_OFFSET_16K_MASK ((1U << gcdMMU_OFFSET_16K_BITS) - 1)
+
+#define gcdMMU_MTLB_PRESENT 0x00000001
+#define gcdMMU_MTLB_EXCEPTION 0x00000002
+#define gcdMMU_MTLB_4K_PAGE 0x00000000
+
+#define gcdMMU_STLB_PRESENT 0x00000001
+#define gcdMMU_STLB_EXCEPTION 0x00000002
+#define gcdMMU_STLB_SECURITY (1 << 4)
+#define gcdMMU_STLB_4K_PAGE 0x00000000
+
+#define gcdUSE_MMU_EXCEPTION 1
+
+#define gcdMMU_SECURE_AREA_START ((gcdMMU_MTLB_ENTRY_NUM - gcdMMU_SECURE_AREA_SIZE) << gcdMMU_MTLB_SHIFT)
+
+typedef enum _gceMMU_TYPE
+{
+ gcvMMU_USED = (0 << 4),
+ gcvMMU_SINGLE = (1 << 4),
+ gcvMMU_FREE = (2 << 4),
+}
+gceMMU_TYPE;
+
+typedef struct _gcsMMU_STLB *gcsMMU_STLB_PTR;
+typedef struct _gcsMMU_STLB
+{
+ gctPHYS_ADDR physical;
+ gctUINT32_PTR logical;
+ gctSIZE_T size;
+ gctPHYS_ADDR_T physBase;
+ gctSIZE_T pageCount;
+ gctUINT32 mtlbIndex;
+ gctUINT32 mtlbEntryNum;
+ gcsMMU_STLB_PTR next;
+} gcsMMU_STLB;
+
+
+#define gcmENTRY_TYPE(x) (x & 0xF0)
+/*
+* We need flat mapping ta command buffer.
+
+*/
+
+/*
+* Helper
+*/
+gctUINT32
+_MtlbOffset(
+ gctUINT32 Address
+ )
+{
+ return (Address & gcdMMU_MTLB_MASK) >> gcdMMU_MTLB_SHIFT;
+}
+
+gctUINT32
+_StlbOffset(
+ gctUINT32 Address
+ )
+{
+ return (Address & gcdMMU_STLB_4K_MASK) >> gcdMMU_STLB_4K_SHIFT;
+}
+
+static gctUINT32
+_SetPage(gctUINT32 PageAddress)
+{
+ return PageAddress
+ /* writable */
+ | (1 << 2)
+ /* Ignore exception */
+ | (0 << 1)
+ /* Present */
+ | (1 << 0);
+}
+
+static void
+_WritePageEntry(
+ IN gctUINT32_PTR PageEntry,
+ IN gctUINT32 EntryValue
+ )
+{
+ *PageEntry = EntryValue;
+
+ gctaOS_CacheClean((gctUINT8_PTR)PageEntry, gcmSIZEOF(gctUINT32));
+}
+
+static gceSTATUS
+_FillPageTable(
+ IN gctUINT32_PTR PageTable,
+ IN gctUINT32 PageCount,
+ IN gctUINT32 EntryValue
+)
+{
+ gctUINT i;
+
+ for (i = 0; i < PageCount; i++)
+ {
+ _WritePageEntry(PageTable + i, EntryValue);
+ }
+
+ return gcvSTATUS_OK;
+}
+
+
+static gceSTATUS
+_AllocateStlb(
+ IN gctaOS Os,
+ OUT gcsMMU_STLB_PTR *Stlb
+ )
+{
+ gceSTATUS status;
+ gcsMMU_STLB_PTR stlb;
+ gctPOINTER pointer = gcvNULL;
+
+ /* Allocate slave TLB record. */
+ gcmkONERROR(gctaOS_Allocate(gcmSIZEOF(gcsMMU_STLB), &pointer));
+ stlb = pointer;
+
+ stlb->size = gcdMMU_STLB_4K_SIZE;
+
+ /* Allocate slave TLB entries. */
+ gcmkONERROR(gctaOS_AllocateSecurityMemory(
+ Os,
+ &stlb->size,
+ (gctPOINTER *)&stlb->logical,
+ &stlb->physical
+ ));
+
+ gcmkONERROR(gctaOS_GetPhysicalAddress(Os, stlb->logical, &stlb->physBase));
+
+#if gcdUSE_MMU_EXCEPTION
+ _FillPageTable(stlb->logical, stlb->size / 4, gcdMMU_STLB_EXCEPTION);
+#else
+ gctaOS_ZeroMemory(stlb->logical, stlb->size);
+#endif
+
+ *Stlb = stlb;
+
+ return gcvSTATUS_OK;
+
+OnError:
+ if(pointer != gcvNULL)
+ gcmkVERIFY_OK(gctaOS_Free(pointer));
+ return status;
+}
+
+gceSTATUS
+gctaMMU_Construct(
+ IN gcTA TA,
+ OUT gcTA_MMU *Mmu
+ )
+{
+ gceSTATUS status;
+ gctSIZE_T bytes = 4096;
+
+ gcTA_MMU mmu = gcvNULL;
+
+ gcmkONERROR(gctaOS_Allocate(
+ gcmSIZEOF(gcsTA_MMU),
+ (gctPOINTER *)&mmu
+ ));
+
+ mmu->mtlbLogical = gcvNULL;
+ mmu->stlbs = gcvNULL;
+ mmu->safePageLogical = gcvNULL;
+ mmu->nonSecureSafePageLogical = gcvNULL;
+
+ mmu->os = TA->os;
+
+ /* MTLB bytes. */
+ mmu->mtlbBytes = gcdMMU_MTLB_SIZE;
+
+ /* Allocate MTLB. */
+ gcmkONERROR(gctaOS_AllocateSecurityMemory(
+ TA->os,
+ &mmu->mtlbBytes,
+ &mmu->mtlbLogical,
+ &mmu->mtlbPhysical
+ ));
+
+#if gcdUSE_MMU_EXCEPTION
+ _FillPageTable(mmu->mtlbLogical, mmu->mtlbBytes / 4, gcdMMU_STLB_EXCEPTION);
+#else
+ gctaOS_ZeroMemory(mmu->mtlbLogical, mmu->mtlbBytes);
+#endif
+
+ /* Allocate a array to store stlbs. */
+ gcmkONERROR(gctaOS_Allocate(mmu->mtlbBytes, &mmu->stlbs));
+
+ gctaOS_ZeroMemory((gctUINT8_PTR)mmu->stlbs, mmu->mtlbBytes);
+
+ /* Allocate security safe page. */
+ gcmkONERROR(gctaOS_AllocateSecurityMemory(
+ TA->os,
+ &bytes,
+ &mmu->safePageLogical,
+ &mmu->safePagePhysical
+ ));
+
+ gctaOS_ZeroMemory((gctUINT8_PTR)mmu->safePageLogical, bytes);
+
+ /* Allocate non security safe page. */
+ gcmkONERROR(gctaOS_AllocateSecurityMemory(
+ TA->os,
+ &bytes,
+ &mmu->nonSecureSafePageLogical,
+ &mmu->nonSecureSafePagePhysical
+ ));
+
+ gctaOS_ZeroMemory((gctUINT8_PTR)mmu->nonSecureSafePageLogical, bytes);
+
+ /* gcmkONERROR(gctaOS_CreateMutex(TA->os, &mmu->mutex)); */
+
+ *Mmu = mmu;
+
+ return gcvSTATUS_OK;
+
+OnError:
+ if (mmu)
+ {
+ if (mmu->safePageLogical)
+ {
+ gcmkVERIFY_OK(gctaOS_FreeSecurityMemory(
+ TA->os,
+ 4096,
+ mmu->safePageLogical,
+ mmu->safePagePhysical
+ ));
+ }
+
+ if (mmu->nonSecureSafePageLogical)
+ {
+ gcmkVERIFY_OK(gctaOS_FreeSecurityMemory(
+ TA->os,
+ 4096,
+ mmu->nonSecureSafePageLogical,
+ mmu->nonSecureSafePagePhysical
+ ));
+ }
+
+ if (mmu->mtlbLogical)
+ {
+ gcmkVERIFY_OK(gctaOS_FreeSecurityMemory(
+ TA->os,
+ 4096,
+ mmu->mtlbLogical,
+ mmu->mtlbPhysical
+ ));
+ }
+
+ if (mmu->stlbs)
+ {
+ gcmkVERIFY_OK(gctaOS_Free((gctPOINTER)mmu->stlbs));
+ }
+
+ gcmkVERIFY_OK(gctaOS_Free((gctPOINTER)mmu));
+ }
+ return status;
+}
+
+gceSTATUS
+gctaMMU_Destory(
+ IN gcTA_MMU Mmu
+ )
+{
+ gctaOS os = Mmu->os;
+
+ if (Mmu->safePageLogical)
+ {
+ gcmkVERIFY_OK(gctaOS_FreeSecurityMemory(
+ os,
+ 4096,
+ Mmu->safePageLogical,
+ Mmu->safePagePhysical
+ ));
+ }
+
+ if (Mmu->nonSecureSafePageLogical)
+ {
+ gcmkVERIFY_OK(gctaOS_FreeSecurityMemory(
+ os,
+ 4096,
+ Mmu->nonSecureSafePageLogical,
+ Mmu->nonSecureSafePagePhysical
+ ));
+ }
+
+ if (Mmu->mtlbLogical)
+ {
+ gcmkVERIFY_OK(gctaOS_FreeSecurityMemory(
+ os,
+ 4096,
+ Mmu->mtlbLogical,
+ Mmu->mtlbPhysical
+ ));
+ }
+
+ if (Mmu->stlbs)
+ {
+ gcmkVERIFY_OK(gctaOS_Free((gctPOINTER)Mmu->stlbs));
+ }
+
+ gcmkVERIFY_OK(gctaOS_Free(Mmu));
+
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gctaMMU_GetPageEntry(
+ IN gcTA_MMU Mmu,
+ IN gctUINT32 Address,
+ OUT gctUINT32_PTR MtlbEntry,
+ OUT gctUINT32_PTR *PageTable,
+ OUT gctBOOL * Secure
+ )
+{
+ gceSTATUS status;
+ struct _gcsMMU_STLB *stlb;
+ struct _gcsMMU_STLB **stlbs = (struct _gcsMMU_STLB **)Mmu->stlbs;
+ gctUINT32 offset = _MtlbOffset(Address);
+ gctUINT32 mtlbEntry;
+ gctBOOL secure = Address > gcdMMU_SECURE_AREA_START;
+
+ gcmkHEADER_ARG("Mmu=0x%x", Mmu);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_ARGUMENT((Address & 0xFFF) == 0);
+
+ stlb = stlbs[offset];
+
+ if (stlb == gcvNULL)
+ {
+ gcmkONERROR(_AllocateStlb(Mmu->os, &stlb));
+
+ mtlbEntry = (gctUINT32)(stlb->physBase & 0xFFFFFFFF)
+ | gcdMMU_MTLB_4K_PAGE
+ | gcdMMU_MTLB_PRESENT
+ ;
+
+ if (secure)
+ {
+ /* Secure MTLB. */
+ mtlbEntry |= (1 << 4);
+ }
+
+ /* Insert Slave TLB address to Master TLB entry.*/
+ _WritePageEntry((gctUINT32_PTR)Mmu->mtlbLogical + offset, mtlbEntry);
+
+ /* Record stlb. */
+ stlbs[offset] = stlb;
+
+ if (MtlbEntry)
+ {
+ /* Return entry value of new mtlb entry. */
+ *MtlbEntry = mtlbEntry;
+ }
+ }
+
+ *PageTable = &stlb->logical[_StlbOffset(Address)];
+
+ if (Secure)
+ {
+ *Secure = secure;
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gctaMMU_SetPage(
+ IN gcTA_MMU Mmu,
+ IN gctUINT32 PageAddress,
+ IN gctUINT32 *PageEntry
+ )
+{
+ /* gctBOOL secure; */
+
+ gcmkHEADER_ARG("Mmu=0x%x", Mmu);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_ARGUMENT(PageEntry != gcvNULL);
+ gcmkVERIFY_ARGUMENT(!(PageAddress & 0xFFF));
+
+ _WritePageEntry(PageEntry, _SetPage(PageAddress));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gctaMMU_FreePages(
+ IN gcTA_MMU Mmu,
+ IN gctUINT32 Address,
+ IN gctUINT32 PageCount
+ )
+{
+ gceSTATUS status;
+ gctUINT32 i;
+ gctUINT32_PTR entry;
+ gcmkHEADER_ARG("Mmu=0x%x", Mmu);
+
+ /* Fill in page table. */
+ for (i = 0; i < PageCount; i++)
+ {
+ gcmkONERROR(gctaMMU_GetPageEntry(Mmu, Address, gcvNULL, &entry, gcvNULL));
+
+#if gcdUSE_MMU_EXCEPTION
+ *entry = gcdMMU_STLB_EXCEPTION;
+#else
+ *entry = 0;
+#endif
+
+ Address += 4096;
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gctaMMU_Enable(
+ IN gcTA_MMU Mmu,
+ IN gcTA TA
+ )
+{
+ gceSTATUS status;
+ gctPHYS_ADDR_T address;
+ gctPHYS_ADDR_T safeAddress;
+
+ gcmkONERROR(gctaOS_GetPhysicalAddress(Mmu->os, Mmu->mtlbLogical, &address));
+
+ gctaOS_GetPhysicalAddress(Mmu->os, Mmu->safePageLogical, &safeAddress);
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+void
+gctaMMU_DumpPagetableEntry(
+ IN gcTA_MMU Mmu,
+ IN gctUINT32 Address
+ )
+{
+ gctUINT32 entry;
+ gctUINT32 mtlb = _MtlbOffset(Address);
+ gctUINT32_PTR mtlbLogical = Mmu->mtlbLogical;
+ gctUINT32_PTR stlbLogical;
+ gcsMMU_STLB_PTR stlb;
+ struct _gcsMMU_STLB **stlbs = (struct _gcsMMU_STLB **)Mmu->stlbs;
+
+ gctUINT32 stlbOffset = (Address & gcdMMU_STLB_4K_MASK) >> gcdMMU_STLB_4K_SHIFT;
+ gctUINT32 offsetInPage = Address & gcdMMU_OFFSET_4K_MASK;
+
+ stlb = stlbs[mtlb];
+
+ gcmkPRINT(" MTLB entry = %d\n", mtlb);
+
+ gcmkPRINT(" STLB entry = %d\n", stlbOffset);
+
+ gcmkPRINT(" Offset = 0x%08X (%d)\n", offsetInPage, offsetInPage);
+
+
+ if (stlb == gcvNULL)
+ {
+ /* Dmp mtlb entry. */
+ entry = mtlbLogical[mtlb];
+
+ gcmkPRINT(" mtlb entry [%d] = %x", mtlb, entry);
+ }
+ else
+ {
+ stlbLogical = stlb->logical;
+
+ gcmkPRINT(" stlb entry = 0x%08X", stlbLogical[stlbOffset]);
+ }
+}
+
+