Linux debugging

Check our new training course

Linux debugging, tracing, profiling & perf. analysis

Check our new training course
with Creative Commons CC-BY-SA
lecture and lab materials

Bootlin logo

Elixir Cross Referencer

/*
 * Copyright (c) 2014, Allwinner Technology Co., Ltd.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
#include <platform_config.h>

#include <mm/core_mmu.h>
#include <mm/core_memprot.h>
#include <util.h>
#include <kernel/tee_misc.h>
#include <trace.h>

#ifndef CFG_DDR_TEETZ_RESERVED_START
#error "TEETZ reserved DDR start address undef: CFG_DDR_TEETZ_RESERVED_START"
#endif
#ifndef CFG_DDR_TEETZ_RESERVED_SIZE
#error "TEETZ reserved DDR siez undefined: CFG_DDR_TEETZ_RESERVED_SIZE"
#endif

/*
 * TEE/TZ RAM layout:
 *
 *  +-----------------------------------------+  <- CFG_DDR_TEETZ_RESERVED_START
 *  | TEETZ private RAM  |  TEE_RAM           |   ^
 *  |                    +--------------------+   |
 *  |                    |  TA_RAM            |   |
 *  +-----------------------------------------+   | CFG_DDR_TEETZ_RESERVED_SIZE
 *  |                    |      teecore alloc |   |
 *  |  TEE/TZ and NSec   |  PUB_RAM   --------|   |
 *  |   shared memory    |         NSec alloc |   |
 *  +-----------------------------------------+   v
 *
 *  TEE_RAM : 1MByte
 *  PUB_RAM : 1MByte
 *  TA_RAM  : all what is left (at least 2MByte !)
 */

/* define the several memory area sizes */
#if (CFG_DDR_TEETZ_RESERVED_SIZE < (4 * 1024 * 1024))
#error "Invalid CFG_DDR_TEETZ_RESERVED_SIZE: at least 4MB expected"
#endif

#define CFG_PUB_RAM_SIZE		(1 * 1024 * 1024)
#define CFG_TEE_RAM_SIZE		(1 * 1024 * 1024)
#define CFG_TA_RAM_SIZE			(CFG_DDR_TEETZ_RESERVED_SIZE - \
					CFG_TEE_RAM_SIZE - CFG_PUB_RAM_SIZE)

/* define the secure/unsecure memory areas */
#define CFG_DDR_ARMTZ_ONLY_START	(CFG_DDR_TEETZ_RESERVED_START)
#define CFG_DDR_ARMTZ_ONLY_SIZE		(CFG_TEE_RAM_SIZE + CFG_TA_RAM_SIZE)

#define CFG_DDR_ARM_ARMTZ_START		\
			(CFG_DDR_ARMTZ_ONLY_START + CFG_DDR_ARMTZ_ONLY_SIZE)
#define CFG_DDR_ARM_ARMTZ_SIZE		(CFG_PUB_RAM_SIZE)

/* define the memory areas (TEE_RAM must start at reserved DDR start addr */
#define CFG_TEE_RAM_START		(CFG_DDR_ARMTZ_ONLY_START)
#define CFG_TA_RAM_START		(CFG_TEE_RAM_START + CFG_TEE_RAM_SIZE)
#define CFG_PUB_RAM_START		(CFG_TA_RAM_START + CFG_TA_RAM_SIZE)


/*
 * define the platform memory Secure layout
 */
struct memaccess_area {
	unsigned long paddr;
	size_t size;
};
#define MEMACCESS_AREA(a, s) { .paddr = a, .size = s }

static struct memaccess_area ddr[] = {
	MEMACCESS_AREA(CFG_DDR_START, CFG_DDR_SIZE),
};

static struct memaccess_area secure_only =
MEMACCESS_AREA(CFG_DDR_ARMTZ_ONLY_START, CFG_DDR_ARMTZ_ONLY_SIZE);

static struct memaccess_area nsec_shared =
MEMACCESS_AREA(CFG_DDR_ARM_ARMTZ_START, CFG_DDR_ARM_ARMTZ_SIZE);

/* pbuf_is_ddr - return true is buffer is inside the DDR */
static bool pbuf_is_ddr(unsigned long paddr, size_t size)
{
	int i = sizeof(ddr) / sizeof(*ddr);

	while (i--) {
		if (core_is_buffer_inside(paddr, size,
					ddr[i].paddr, ddr[i].size))
			return true;
	}
	return false;
}

/*
 * pbuf_is_multipurpose - return true is buffer is inside unsafe DDR
 *
 * Unsafe DDR (or multipurpose DDR) is DDR that is under a firewalling
 * reconfigured at run-time: there is no static information that can
 * tell wether this RAM is tagged secured or not.
 */
static bool pbuf_is_multipurpose(unsigned long paddr, size_t size)
{
	if (core_is_buffer_intersect(paddr, size,
				     secure_only.paddr, secure_only.size))
		return false;
	if (core_is_buffer_intersect(paddr, size,
				     nsec_shared.paddr, nsec_shared.size))
		return false;

	return pbuf_is_ddr(paddr, size);
}

/*
 * Wrapper for the platform specific pbuf_is() service.
 */
static bool pbuf_is(enum buf_is_attr attr, unsigned long paddr, size_t size)
{
	switch (attr) {
	case CORE_MEM_SEC:
		return core_is_buffer_inside(paddr, size,
					secure_only.paddr, secure_only.size);

	case CORE_MEM_NON_SEC:
		return core_is_buffer_inside(paddr, size,
					nsec_shared.paddr, nsec_shared.size);

	case CORE_MEM_MULTPURPOSE:
		return pbuf_is_multipurpose(paddr, size);

	case CORE_MEM_EXTRAM:
		return pbuf_is_ddr(paddr, size);

	default:
		EMSG("unpexted request: attr=%X", attr);
		return false;
	}
}

static struct map_area bootcfg_memory[] = {
	{ /* teecore execution RAM */
	 .type = MEM_AREA_TEE_RAM,
	 .pa = CFG_TEE_RAM_START, .size = CFG_TEE_RAM_SIZE,
	 .cached = true, .secure = true, .rw = true, .exec = true,
	 },

	{ /* teecore TA load/exec RAM - Secure, exec user only! */
	 .type = MEM_AREA_TA_RAM,
	 .pa = CFG_TA_RAM_START, .size = CFG_TA_RAM_SIZE,
	 .cached = true, .secure = true, .rw = true, .exec = false,
	 },

	{ /* teecore public RAM - NonSecure, non-exec. */
	 .type = MEM_AREA_NSEC_SHM,
	 .pa = CFG_PUB_RAM_START, .size = CFG_PUB_RAM_SIZE,
	 .cached = true, .secure = false, .rw = true, .exec = false,
	 },

	{ /* AHB0 devices */
	 .type = MEM_AREA_IO_NSEC,
	 .pa = 0x01400000 & ~CORE_MMU_DEVICE_MASK,
	 .size = ROUNDUP(0x00900000, CORE_MMU_DEVICE_SIZE),
	 .device = true, .secure = true, .rw = true,
	 },

	{ /* AHB1 devices */
	 .type = MEM_AREA_IO_NSEC,
	 .pa = (0x00800000) & ~CORE_MMU_DEVICE_MASK,
	 .size = ROUNDUP(0x00300000, CORE_MMU_DEVICE_SIZE),
	 .device = true, .secure = true, .rw = true,
	 },
	{ /* AHB2 devices */
	 .type = MEM_AREA_IO_NSEC,
	 .pa = (0x03000000) & ~CORE_MMU_DEVICE_MASK,
	 .size = ROUNDUP(0x01000000, CORE_MMU_DEVICE_SIZE),
	 .device = true, .secure = true, .rw = true,
	 },
	{ /* AHBS devices */
	 .type = MEM_AREA_IO_NSEC,
	 .pa = (0x06000000) & ~CORE_MMU_DEVICE_MASK,
	 .size = ROUNDUP(0x02200000, CORE_MMU_DEVICE_SIZE),
	 .device = true, .secure = true, .rw = true,
	 },

	{.type = MEM_AREA_NOTYPE}
};

/*
 * bootcfg_get_pbuf_is_handler - return the platform specfic pbuf_is
 */
unsigned long bootcfg_get_pbuf_is_handler(void)
{
	return (unsigned long)pbuf_is;
}

/*
 * This routine is called while MMU and core memory management are not init.
 */
struct map_area *bootcfg_get_memory(void)
{
	struct map_area *map;
	struct memaccess_area *a, *a2;
	struct map_area *ret = bootcfg_memory;
	
	/* check defined memory access layout */
	a = (struct memaccess_area *)&secure_only;
	a2 = (struct memaccess_area *)&nsec_shared;
	if (core_is_buffer_intersect(a->paddr, a->size, a2->paddr, a2->size)) {
		EMSG("invalid memory access configuration: sec/nsec");
		return NULL;
	}

	/* check defined mapping (overlapping will be tested later) */
	map = bootcfg_memory;
	while (map->type != MEM_AREA_NOTYPE) {
		switch (map->type) {
		case MEM_AREA_TEE_RAM:
			a = (struct memaccess_area *)&secure_only;
			if (!core_is_buffer_inside(map->pa, map->size,
						a->paddr, a->size)) {
				EMSG("TEE_RAM does not fit in secure_only");
				ret = NULL;
			}
			break;
		case MEM_AREA_TA_RAM:
			a = (struct memaccess_area *)&secure_only;
			if (!core_is_buffer_inside(map->pa, map->size,
						a->paddr, a->size)) {
				EMSG("TA_RAM does not fit in secure_only");
				ret = NULL;
			}
			break;
		case MEM_AREA_NSEC_SHM:
			a = (struct memaccess_area *)&nsec_shared;
			if (!core_is_buffer_inside(map->pa, map->size,
						a->paddr, a->size)) {
				EMSG("NSEC_RAM does not fit in nsec_shared");
				ret = NULL;
			}
			break;
		default:
			/* other mapped areas are not checked */
			break;
		}
		map++;
	}

	return ret;
}