Tegra: memctrl_v2: zero out NS Video memory carveout region
authorVarun Wadekar <vwadekar@nvidia.com>
Wed, 21 Dec 2016 22:50:18 +0000 (14:50 -0800)
committerVarun Wadekar <vwadekar@nvidia.com>
Mon, 1 May 2017 22:33:31 +0000 (15:33 -0700)
The video memory carveout has to be re-sized depending on the Video
content. This requires the NS world to send us new base/size values.
Before setting up the new region, we must zero out the previous memory
region, so that the video frames are not leaked to the outside world.

This patch adds the logic to zero out the previous memory carveout
region.

Change-Id: I471167ef7747154440df5c1a5e015fbeb69d9043
Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
plat/nvidia/tegra/common/drivers/memctrl/memctrl_v2.c
plat/nvidia/tegra/include/t186/tegra_def.h

index 41a4ede80a1e600c9f631895860f42274970513d..87c7ed03df3cae7855f4fd1600221caf740bc627 100644 (file)
@@ -40,7 +40,8 @@
 #include <string.h>
 #include <tegra_def.h>
 #include <tegra_platform.h>
-#include <xlat_tables.h>
+#include <utils.h>
+#include <xlat_tables_v2.h>
 
 #define TEGRA_GPU_RESET_REG_OFFSET     0x30
 #define  GPU_RESET_BIT                 (1 << 0)
@@ -450,7 +451,7 @@ void tegra_memctrl_restore_settings(void)
                tegra_mc_write_32(MC_VIDEO_PROTECT_SIZE_MB, video_mem_size_mb);
 
                /*
-                * MCE propogates the VideoMem configuration values across the
+                * MCE propagates the VideoMem configuration values across the
                 * CCPLEX.
                 */
                mce_update_gsc_videomem();
@@ -490,7 +491,7 @@ void tegra_memctrl_tzdram_setup(uint64_t phys_base, uint32_t size_in_bytes)
                                        tegra_mc_read_32(MC_SECURITY_CFG1_0));
 
        /*
-        * MCE propogates the security configuration values across the
+        * MCE propagates the security configuration values across the
         * CCPLEX.
         */
        mce_update_gsc_tzdram();
@@ -506,25 +507,28 @@ void tegra_memctrl_tzram_setup(uint64_t phys_base, uint32_t size_in_bytes)
 {
        uint32_t index;
        uint32_t total_128kb_blocks = size_in_bytes >> 17;
-       uint32_t residual_4kb_blocks = (size_in_bytes & 0x1FFFF) >> 12;
+       uint32_t residual_4kb_blocks = (size_in_bytes & (uint32_t)0x1FFFF) >> 12;
        uint32_t val;
 
+       INFO("Configuring TrustZone SRAM Memory Carveout\n");
+
        /*
         * Reset the access configuration registers to restrict access
         * to the TZRAM aperture
         */
-       for (index = MC_TZRAM_CARVEOUT_CLIENT_ACCESS_CFG0;
-            index <= MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS5;
-            index += 4)
+       for (index = MC_TZRAM_CLIENT_ACCESS_CFG0;
+            index < ((uint32_t)MC_TZRAM_CARVEOUT_CFG + (uint32_t)MC_GSC_CONFIG_REGS_SIZE);
+            index += 4U) {
                tegra_mc_write_32(index, 0);
+       }
 
        /*
         * Set the TZRAM base. TZRAM base must be 4k aligned, at least.
         */
-       assert(!(phys_base & 0xFFF));
+       assert((phys_base & (uint64_t)0xFFF) == 0U);
        tegra_mc_write_32(MC_TZRAM_BASE_LO, (uint32_t)phys_base);
        tegra_mc_write_32(MC_TZRAM_BASE_HI,
-               (uint32_t)(phys_base >> 32) & TZRAM_BASE_HI_MASK);
+               (uint32_t)(phys_base >> 32) & MC_GSC_BASE_HI_MASK);
 
        /*
         * Set the TZRAM size
@@ -533,7 +537,7 @@ void tegra_memctrl_tzram_setup(uint64_t phys_base, uint32_t size_in_bytes)
         * blocks)
         *
         */
-       val = (residual_4kb_blocks << TZRAM_SIZE_RANGE_4KB_SHIFT) |
+       val = (residual_4kb_blocks << MC_GSC_SIZE_RANGE_4KB_SHIFT) |
              total_128kb_blocks;
        tegra_mc_write_32(MC_TZRAM_SIZE, val);
 
@@ -543,17 +547,96 @@ void tegra_memctrl_tzram_setup(uint64_t phys_base, uint32_t size_in_bytes)
         * at all.
         */
        val = tegra_mc_read_32(MC_TZRAM_CARVEOUT_CFG);
-       val &= ~TZRAM_ENABLE_TZ_LOCK_BIT;
-       val |= TZRAM_LOCK_CFG_SETTINGS_BIT;
+       val &= ~MC_GSC_ENABLE_TZ_LOCK_BIT;
+       val |= MC_GSC_LOCK_CFG_SETTINGS_BIT;
        tegra_mc_write_32(MC_TZRAM_CARVEOUT_CFG, val);
 
        /*
-        * MCE propogates the security configuration values across the
+        * MCE propagates the security configuration values across the
         * CCPLEX.
         */
        mce_update_gsc_tzram();
 }
 
+static void tegra_lock_videomem_nonoverlap(uint64_t phys_base,
+                                          uint64_t size_in_bytes)
+{
+       uint32_t index;
+       uint64_t total_128kb_blocks = size_in_bytes >> 17;
+       uint64_t residual_4kb_blocks = (size_in_bytes & (uint32_t)0x1FFFF) >> 12;
+       uint64_t val;
+
+       /*
+        * Reset the access configuration registers to restrict access to
+        * old Videomem aperture
+        */
+       for (index = MC_VIDEO_PROTECT_CLEAR_ACCESS_CFG0;
+            index < ((uint32_t)MC_VIDEO_PROTECT_CLEAR_ACCESS_CFG0 + (uint32_t)MC_GSC_CONFIG_REGS_SIZE);
+            index += 4U) {
+               tegra_mc_write_32(index, 0);
+       }
+
+       /*
+        * Set the base. It must be 4k aligned, at least.
+        */
+       assert((phys_base & (uint64_t)0xFFF) == 0U);
+       tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_BASE_LO, (uint32_t)phys_base);
+       tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_BASE_HI,
+               (uint32_t)(phys_base >> 32) & (uint32_t)MC_GSC_BASE_HI_MASK);
+
+       /*
+        * Set the aperture size
+        *
+        * total size = (number of 128KB blocks) + (number of remaining 4KB
+        * blocks)
+        *
+        */
+       val = (uint32_t)((residual_4kb_blocks << MC_GSC_SIZE_RANGE_4KB_SHIFT) |
+                        total_128kb_blocks);
+       tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_SIZE, (uint32_t)val);
+
+       /*
+        * Lock the configuration settings by enabling TZ-only lock and
+        * locking the configuration against any future changes from NS
+        * world.
+        */
+       tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_CFG,
+                         (uint32_t)MC_GSC_ENABLE_TZ_LOCK_BIT);
+
+       /*
+        * MCE propagates the GSC configuration values across the
+        * CCPLEX.
+        */
+}
+
+static void tegra_unlock_videomem_nonoverlap(void)
+{
+       /* Clear the base */
+       tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_BASE_LO, 0);
+       tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_BASE_HI, 0);
+
+       /* Clear the size */
+       tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_SIZE, 0);
+}
+
+static void tegra_clear_videomem(uintptr_t non_overlap_area_start,
+                                unsigned long long non_overlap_area_size)
+{
+       /*
+        * Map the NS memory first, clean it and then unmap it.
+        */
+       mmap_add_dynamic_region(non_overlap_area_start, /* PA */
+                               non_overlap_area_start, /* VA */
+                               non_overlap_area_size, /* size */
+                               MT_NS | MT_RW | MT_EXECUTE_NEVER); /* attrs */
+
+       zero_normalmem((void *)non_overlap_area_start, non_overlap_area_size);
+       flush_dcache_range(non_overlap_area_start, non_overlap_area_size);
+
+       mmap_remove_dynamic_region(non_overlap_area_start,
+               non_overlap_area_size);
+}
+
 /*
  * Program the Video Memory carveout region
  *
@@ -562,7 +645,10 @@ void tegra_memctrl_tzram_setup(uint64_t phys_base, uint32_t size_in_bytes)
  */
 void tegra_memctrl_videomem_setup(uint64_t phys_base, uint32_t size_in_bytes)
 {
+       uintptr_t vmem_end_old = video_mem_base + (video_mem_size_mb << 20);
+       uintptr_t vmem_end_new = phys_base + size_in_bytes;
        uint32_t regval;
+       unsigned long long non_overlap_area_size;
 
        /*
         * The GPU is the user of the Video Memory region. In order to
@@ -570,7 +656,7 @@ void tegra_memctrl_videomem_setup(uint64_t phys_base, uint32_t size_in_bytes)
         * new base/size ONLY if the GPU is in reset mode.
         */
        regval = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_GPU_RESET_REG_OFFSET);
-       if ((regval & GPU_RESET_BIT) == 0) {
+       if ((regval & GPU_RESET_BIT) == 0U) {
                ERROR("GPU not in reset! Video Memory setup failed\n");
                return;
        }
@@ -581,17 +667,61 @@ void tegra_memctrl_videomem_setup(uint64_t phys_base, uint32_t size_in_bytes)
         */
        INFO("Configuring Video Memory Carveout\n");
 
+       /*
+        * Configure Memory Controller directly for the first time.
+        */
+       if (video_mem_base == 0U)
+               goto done;
+
+       /*
+        * Lock the non overlapping memory being cleared so that other masters
+        * do not accidently write to it. The memory would be unlocked once
+        * the non overlapping region is cleared and the new memory
+        * settings take effect.
+        */
+       tegra_lock_videomem_nonoverlap(video_mem_base,
+                                      video_mem_size_mb << 20);
+
+       /*
+        * Clear the old regions now being exposed. The following cases
+        * can occur -
+        *
+        * 1. clear whole old region (no overlap with new region)
+        * 2. clear old sub-region below new base
+        * 3. clear old sub-region above new end
+        */
+       INFO("Cleaning previous Video Memory Carveout\n");
+
+       if (phys_base > vmem_end_old || video_mem_base > vmem_end_new) {
+               tegra_clear_videomem(video_mem_base,
+                                    (uint64_t)video_mem_size_mb << 20);
+       } else {
+               if (video_mem_base < phys_base) {
+                       non_overlap_area_size = phys_base - video_mem_base;
+                       tegra_clear_videomem(video_mem_base, non_overlap_area_size);
+               }
+               if (vmem_end_old > vmem_end_new) {
+                       non_overlap_area_size = vmem_end_old - vmem_end_new;
+                       tegra_clear_videomem(vmem_end_new, non_overlap_area_size);
+               }
+       }
+
+done:
+       /* program the Videomem aperture */
        tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_LO, (uint32_t)phys_base);
        tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_HI,
                          (uint32_t)(phys_base >> 32));
        tegra_mc_write_32(MC_VIDEO_PROTECT_SIZE_MB, size_in_bytes >> 20);
 
+       /* unlock the previous locked nonoverlapping aperture */
+       tegra_unlock_videomem_nonoverlap();
+
        /* store new values */
        video_mem_base = phys_base;
        video_mem_size_mb = size_in_bytes >> 20;
 
        /*
-        * MCE propogates the VideoMem configuration values across the
+        * MCE propagates the VideoMem configuration values across the
         * CCPLEX.
         */
        mce_update_gsc_videomem();
index 6693cb3ae6daa9a35aab603bf02f604815129757..8d7ab6eae566d174946bce2c174b1ed1cc53397b 100644 (file)
 #define TEGRA_MC_STREAMID_BASE         0x02C00000
 #define TEGRA_MC_BASE                  0x02C10000
 
+/* General Security Carveout register macros */
+#define MC_GSC_CONFIG_REGS_SIZE                0x40UL
+#define MC_GSC_LOCK_CFG_SETTINGS_BIT   (1UL << 1)
+#define MC_GSC_ENABLE_TZ_LOCK_BIT      (1UL << 0)
+#define MC_GSC_SIZE_RANGE_4KB_SHIFT    27UL
+#define MC_GSC_BASE_LO_SHIFT           12UL
+#define MC_GSC_BASE_LO_MASK            0xFFFFFUL
+#define MC_GSC_BASE_HI_SHIFT           0UL
+#define MC_GSC_BASE_HI_MASK            3UL
+
 /* TZDRAM carveout configuration registers */
 #define MC_SECURITY_CFG0_0             0x70
 #define MC_SECURITY_CFG1_0             0x74
 /* Video Memory carveout configuration registers */
 #define MC_VIDEO_PROTECT_BASE_HI       0x978
 #define MC_VIDEO_PROTECT_BASE_LO       0x648
-#define MC_VIDEO_PROTECT_SIZE_MB       0x64c
+#define MC_VIDEO_PROTECT_SIZE_MB       0x64C
+
+/*
+ * Carveout (MC_SECURITY_CARVEOUT24) registers used to clear the
+ * non-overlapping Video memory region
+ */
+#define MC_VIDEO_PROTECT_CLEAR_CFG     0x25A0
+#define MC_VIDEO_PROTECT_CLEAR_BASE_LO 0x25A4
+#define MC_VIDEO_PROTECT_CLEAR_BASE_HI 0x25A8
+#define MC_VIDEO_PROTECT_CLEAR_SIZE    0x25AC
+#define MC_VIDEO_PROTECT_CLEAR_ACCESS_CFG0     0x25B0
 
 /* TZRAM carveout (MC_SECURITY_CARVEOUT11) configuration registers */
+#define MC_TZRAM_CARVEOUT_CFG          0x2190
 #define MC_TZRAM_BASE_LO               0x2194
-#define  TZRAM_BASE_LO_SHIFT           12
-#define  TZRAM_BASE_LO_MASK            0xFFFFF
 #define MC_TZRAM_BASE_HI               0x2198
-#define  TZRAM_BASE_HI_SHIFT           0
-#define  TZRAM_BASE_HI_MASK            3
 #define MC_TZRAM_SIZE                  0x219C
-#define  TZRAM_SIZE_RANGE_4KB_SHIFT    27
-
-#define MC_TZRAM_CARVEOUT_CFG                  0x2190
-#define  TZRAM_LOCK_CFG_SETTINGS_BIT           (1 << 1)
-#define  TZRAM_ENABLE_TZ_LOCK_BIT              (1 << 0)
-#define MC_TZRAM_CARVEOUT_CLIENT_ACCESS_CFG0   0x21A0
-#define MC_TZRAM_CARVEOUT_CLIENT_ACCESS_CFG1   0x21A4
-#define MC_TZRAM_CARVEOUT_CLIENT_ACCESS_CFG2   0x21A8
-#define MC_TZRAM_CARVEOUT_CLIENT_ACCESS_CFG3   0x21AC
-#define MC_TZRAM_CARVEOUT_CLIENT_ACCESS_CFG4   0x21B0
-#define MC_TZRAM_CARVEOUT_CLIENT_ACCESS_CFG5   0x21B4
-
-#define MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS0       0x21B8
-#define MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS1       0x21BC
-#define MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS2       0x21C0
-#define MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS3       0x21C4
-#define MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS4       0x21C8
-#define MC_TZRAM_CARVEOUT_FORCE_INTERNAL_ACCESS5       0x21CC
+#define MC_TZRAM_CLIENT_ACCESS_CFG0    0x21A0
 
 /*******************************************************************************
  * Tegra UART Controller constants