blob: d6e66ad82a0ddd2f525dce389f71107e40d1f233 [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Framework for parsing the firmware image configuration.
*
* Copyright (C) 2022 Google LLC
*/
#ifndef __GCIP_IMAGE_CONFIG_H__
#define __GCIP_IMAGE_CONFIG_H__
#include <asm/page.h>
#include <linux/bits.h>
#include <linux/types.h>
#define GCIP_FW_NUM_VERSIONS 4
#define GCIP_IMG_CFG_MAX_IOMMU_MAPPINGS 20
#define GCIP_IMG_CFG_MAX_NS_IOMMU_MAPPINGS 5
#define GCIP_IMG_CFG_MAX_PROTECTED_MEMORY_MAPPINGS 3
#define GCIP_FW_PRIV_LEVEL_GSA 0
#define GCIP_FW_PRIV_LEVEL_TZ 1
#define GCIP_FW_PRIV_LEVEL_NS 2
/*
* The image configuration attached to the signed firmware.
*/
struct gcip_image_config {
__u32 carveout_base;
__u32 firmware_base;
__u32 firmware_size;
__u32 firmware_versions[GCIP_FW_NUM_VERSIONS];
__u32 config_version;
__u32 privilege_level;
__u32 remapped_region_start;
__u32 remapped_region_size;
__u32 num_iommu_mappings;
struct {
/* Device virtual address */
__u32 virt_address;
/*
* Encodes a 12-bit aligned address and the corresponding size
* into a 32-bit value.
* Detailed encoding method is defined in gcip-image-config.c.
*/
__u32 image_config_value;
} iommu_mappings[GCIP_IMG_CFG_MAX_IOMMU_MAPPINGS];
__u32 protected_memory_regions[GCIP_IMG_CFG_MAX_PROTECTED_MEMORY_MAPPINGS];
__u32 secure_telemetry_region_start;
__u32 remapped_data_start;
__u32 remapped_data_size;
__u32 num_ns_iommu_mappings;
__u32 ns_iommu_mappings[GCIP_IMG_CFG_MAX_NS_IOMMU_MAPPINGS];
} __packed;
#define GCIP_IMAGE_CONFIG_FLAGS_SECURE (1u << 0)
struct gcip_image_config_ops {
/*
* Adds an IOMMU mapping from @daddr to @paddr with size @size.
*
* It is ensured that there is no overflow on @paddr + @size before calling this function.
*
* @flags is a bit-field with the following attributes:
* [0:0] - Security. 1 for secure and 0 for non-secure.
* [31:1] - Reserved.
*
* Returns 0 on success. Otherwise a negative errno.
* Mandatory.
*/
int (*map)(void *data, dma_addr_t daddr, phys_addr_t paddr, size_t size,
unsigned int flags);
/*
* Removes the IOMMU mapping previously added by @map.
*
* Mandatory.
*/
void (*unmap)(void *data, dma_addr_t daddr, size_t size, unsigned int flags);
};
struct gcip_image_config_parser {
struct device *dev;
void *data; /* User-specify data, will be passed to ops. */
const struct gcip_image_config_ops *ops;
/* The last image config being successfully parsed. */
struct gcip_image_config last_config;
/* true == last_config is valid, false == never parsed a valid image config or cleared. */
bool last_config_valid;
};
#define GCIP_IMG_CFG_ADDR_SHIFT 12
#define GCIP_IMG_CFG_PAGE_SHIFT 12
#define GCIP_IMG_CFG_MB_SHIFT 20
#define GCIP_IMG_CFG_SIZE_MODE_BIT BIT(GCIP_IMG_CFG_ADDR_SHIFT - 1)
#define GCIP_IMG_CFG_SECURE_SIZE_MASK (GCIP_IMG_CFG_SIZE_MODE_BIT - 1u)
#define GCIP_IMG_CFG_NS_SIZE_MASK (GCIP_IMG_CFG_SIZE_MODE_BIT - 1u)
#define GCIP_IMG_CFG_ADDR_MASK ~(BIT(GCIP_IMG_CFG_ADDR_SHIFT) - 1u)
/* For decoding the size of ns_iommu_mappings. */
static inline u32 gcip_ns_config_to_size(u32 cfg)
{
if (cfg & GCIP_IMG_CFG_SIZE_MODE_BIT)
return (cfg & GCIP_IMG_CFG_NS_SIZE_MASK) << GCIP_IMG_CFG_PAGE_SHIFT;
return (cfg & GCIP_IMG_CFG_NS_SIZE_MASK) << GCIP_IMG_CFG_MB_SHIFT;
}
/* For decoding the size of iommu_mappings. */
static inline u32 gcip_config_to_size(u32 cfg)
{
if (cfg & GCIP_IMG_CFG_SIZE_MODE_BIT)
return (cfg & GCIP_IMG_CFG_SECURE_SIZE_MASK) << GCIP_IMG_CFG_PAGE_SHIFT;
return BIT(cfg & GCIP_IMG_CFG_SECURE_SIZE_MASK) << GCIP_IMG_CFG_PAGE_SHIFT;
}
/*
* Initializes the image configuration parser.
*
* @dev is only used for logging.
* @data will be passed to operations.
*
* Returns 0 on success. Returns -EINVAL when any mandatory operations is NULL.
*/
int gcip_image_config_parser_init(struct gcip_image_config_parser *parser,
const struct gcip_image_config_ops *ops, struct device *dev,
void *data);
/*
* Parses the image configuration and adds specified IOMMU mappings by calling pre-registered
* operations.
*
* Number of mappings to be added might be different according to the value of
* @config->privilege_level:
* - GCIP_FW_PRIV_LEVEL_NS:
* Both @iommu_mappings and @ns_iommu_mappings will be added. Because GCIP_FW_PRIV_LEVEL_NS means
* the firmware will run in non-secure mode and all transactions will go through the non-secure
* IOMMU.
* - Otherwise:
* Only @ns_iommu_mappings are considered. TZ/GSA will be the one who programs secure IOMMU for
* those secure IOMMU mappings.
*
* Before parsing the newly passed @config, the mappings of the last record (stored by @parser
* internally) will be reverted. If there is any mapping in the new config fails to be mapped, the
* reverted last config will be reverted again. i.e. This function will keep the mapping state the
* same as before calling it on any error happens. But if the IOMMU state is somehow corrupted and
* hence fails to roll back the reverted last image config, only an error is logged. See the pseudo
* code below:
*
* gcip_image_config_parse(config):
* unmap(last_image_config)
* if ret = map(config) fails:
* LOG("Failed to map image config, rolling back to the last image config.")
* if map(last_image_config) fails:
* LOG("Failed to roll back the last image config.")
* return ret
* else:
* last_image_config = config
* return SUCCESS
*
* A special case being considered is if the content of @config is identical to the last
* successfully parsed image config, this function will return 0 immediately without removing /
* adding any mapping.
*
* Returns 0 on success. Otherwise an errno, which usually would be the one returned by
* gcip_image_config_ops.map. On error no new mapping specified in @config is added.
*/
int gcip_image_config_parse(struct gcip_image_config_parser *parser,
struct gcip_image_config *config);
/*
* Clears the mappings specified in the last image config.
*
* It's valid to call this function without any image config has been successfully parsed, or when
* the last image config is already cleared. In which case this function works as no-op.
*/
void gcip_image_config_clear(struct gcip_image_config_parser *parser);
/*
* Returns whether the privilege level specified by @config is non-secure.
*/
static inline bool gcip_image_config_is_ns(struct gcip_image_config *config)
{
return config->privilege_level == GCIP_FW_PRIV_LEVEL_NS;
}
#endif /* __GCIP_IMAGE_CONFIG_H__ */