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, STMicroelectronics International N.V.
 * 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>

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

static struct memaccess_area ddr[] = {
	MEMACCESS_AREA(DRAM0_BASE, DRAM0_SIZE),
#ifdef DRAM1_BASE
	MEMACCESS_AREA(DRAM1_BASE, DRAM1_SIZE),
#endif
};

static struct memaccess_area secure_only[] = {
#ifdef TZSRAM_BASE
	MEMACCESS_AREA(TZSRAM_BASE, TZSRAM_SIZE),
#endif
	MEMACCESS_AREA(TZDRAM_BASE, TZDRAM_SIZE),
};

static struct memaccess_area nsec_shared[] = {
	MEMACCESS_AREA(CFG_SHMEM_START, CFG_SHMEM_SIZE),
};

static bool _pbuf_intersects(struct memaccess_area *a, size_t alen,
			     paddr_t pa, size_t size)
{
	size_t n;

	for (n = 0; n < alen; n++)
		if (core_is_buffer_intersect(pa, size, a[n].paddr, a[n].size))
			return true;
	return false;
}
#define pbuf_intersects(a, pa, size) \
	_pbuf_intersects((a), ARRAY_SIZE(a), (pa), (size))

static bool _pbuf_is_inside(struct memaccess_area *a, size_t alen,
			    paddr_t pa, size_t size)
{
	size_t n;

	for (n = 0; n < alen; n++)
		if (core_is_buffer_inside(pa, size, a[n].paddr, a[n].size))
			return true;
	return false;
}
#define pbuf_is_inside(a, pa, size) \
	_pbuf_is_inside((a), ARRAY_SIZE(a), (pa), (size))

static bool pbuf_is_multipurpose(paddr_t paddr, size_t size)
{
	if (pbuf_intersects(secure_only, paddr, size))
		return false;
	if (pbuf_intersects(nsec_shared, paddr, size))
		return false;

	return pbuf_is_inside(ddr, paddr, size);
}

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

	case CORE_MEM_NON_SEC:
		return pbuf_is_inside(nsec_shared, paddr, size);

	case CORE_MEM_MULTPURPOSE:
		return pbuf_is_multipurpose(paddr, size);

	case CORE_MEM_EXTRAM:
		return pbuf_is_inside(ddr, paddr, size);

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

/* platform specific memory layout provided to teecore */
static struct map_area bootcfg_memory_map[] = {
#ifdef ROM_BASE
	{
	 .type = MEM_AREA_IO_SEC,
	 .pa = ROM_BASE, .size = ROM_SIZE,
	 .cached = true, .secure = true, .rw = false, .exec = false,
	 },
#endif

	{	/* teecore execution RAM */
	 .type = MEM_AREA_TEE_RAM,
	 .pa = CFG_TEE_RAM_START, .size = CFG_TEE_RAM_PH_SIZE,
#ifdef CFG_WITH_PAGER
	 .region_size = SMALL_PAGE_SIZE,
#endif
	 .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_SHMEM_START, .size = CFG_SHMEM_SIZE,
	 .cached = true, .secure = false, .rw = true, .exec = false,
	 },

	{	/* UART */
	 .type = MEM_AREA_IO_NSEC,
	 .pa = CONSOLE_UART_BASE & ~SECTION_MASK, .size = SECTION_SIZE,
	 .device = true, .secure = true, .rw = true,
	 },

	{	/* GIC */
	 .type = MEM_AREA_IO_SEC,
	 .pa = GIC_BASE & ~SECTION_MASK, .size = SECTION_SIZE,
	 .device = true, .secure = true, .rw = true,
	 },

#if PLATFORM_FLAVOR_IS(fvp)
	{	/*
		 * FVP's GIC Distributor is beyond SECTION_SIZE,
		 * and need to be mapped seperately.
		 */
	 .type = MEM_AREA_IO_SEC,
	 .pa = (GIC_BASE + GICD_OFFSET) & ~SECTION_MASK, .size = SECTION_SIZE,
	 .device = true, .secure = true, .rw = true,
	 },
#endif

#ifdef CFG_PCSC_PASSTHRU_READER_DRV
	{	/* PCSC passthru reader */
	 .type = MEM_AREA_IO_SEC,
	 .pa = PCSC_BASE & ~SECTION_MASK, .size = SECTION_SIZE,
	 .device = true, .secure = true, .rw = true,
	 },
#endif

	{.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;
	size_t n;

	/* check defined memory access layout */
	for (n = 0; n < ARRAY_SIZE(secure_only); n++) {
		if (pbuf_intersects(nsec_shared, secure_only[n].paddr,
				    secure_only[n].size)) {
			EMSG("invalid memory access configuration: sec/nsec");
			return NULL;
		}
	}

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

	return bootcfg_memory_map;
}