android_kernel_modules_leno.../intel_media/video/common/tng_securefw.c

332 lines
10 KiB
C

/**************************************************************************
* Copyright (c) 2014, Intel Corporation.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
*
**************************************************************************/
#include <linux/firmware.h>
#include <drm/drmP.h>
#include <drm/drm.h>
#include "psb_drv.h"
#include "vsp.h"
#ifdef CONFIG_DX_SEP54
extern int sepapp_image_verify(u8 *addr, ssize_t size, u32 key_index, u32 magic_num);
extern int sepapp_key_validity_check(u8 *addr, ssize_t size, u32 flag);
#endif
/*
* FW load flow:
* 1. check if verifcation FW is valid for this platform
* 2. check if product FW is valid
*
* To your own FW with non-INTEL key signed, releace verfication FW.
*/
#define FW_NAME_LEN 64
#define IMR_REG_NUMBER(imrl_reg) ((imrl_reg - TNG_IMR_MSG_REGBASE) >> 2)
#define ISLAND_MAGIC_NUMBER(island_str) ((island_str[2] << 24) | (island_str[1] << 16) | (island_str[0] << 8) | '$')
#define VRL_SZ 728
#define prod_suffix "prod"
#define verf_suffix "verf"
static int tng_checkfw(struct drm_device *dev, char *fw_name,
unsigned char *imr_ptr, int key, uint64_t imr_addr)
{
const struct firmware *raw = NULL;
const int vrl_header_size = VRL_SZ;
int ret = -1;
/* upload fw VRL header */
ret = request_firmware(&raw, fw_name, &dev->pdev->dev);
if (raw == NULL || ret < 0) {
DRM_ERROR("Failed to request firmware %s, ret = %d\n", fw_name, ret);
goto out;
}
if (vrl_header_size > raw->size) {
DRM_ERROR("invalid FW: FW size (%d) < VRL header size(%d)\n",
raw->size, vrl_header_size);
ret = -1;
goto out;
}
PSB_DEBUG_INIT("Try to copy VRL header into IMR region\n");
memcpy(imr_ptr, raw->data, vrl_header_size);
/* validate VRL header */
#ifdef CONFIG_DX_SEP54
PSB_DEBUG_INIT("Try to validate VRL header for %s\n", fw_name);
ret = sepapp_key_validity_check((u8 *)imr_addr, vrl_header_size, 0);
if (ret) {
DRM_ERROR("firmware %s is invalid, ret %x\n", fw_name, ret);
goto out;
}
PSB_DEBUG_INIT("FW %s is valid\n", fw_name);
#else
DRM_ERROR("sep module is not compiled in");
#endif
out:
if (raw)
release_firmware(raw);
return ret;
}
static int tng_get_fwinfo(struct drm_device *dev, char *fw_name,
char *fw_basename, int *sep_key, unsigned char *imr_ptr, uint64_t imr_addr)
{
int i, ret;
const int key = 15;
/* set key */
if (drm_video_sepkey == -1)
*sep_key = key;
else
*sep_key = drm_video_sepkey;
PSB_DEBUG_INIT("sep key is %d\n", *sep_key);
/* check if verification FW is valid */
snprintf(fw_name, FW_NAME_LEN, "%s.bin.%s", fw_basename, verf_suffix);
ret = tng_checkfw(dev, fw_name, imr_ptr, *sep_key, imr_addr);
if (ret == 0)
return ret;
/* verfication FW is invalid, check if production FW is valid */
snprintf(fw_name, FW_NAME_LEN, "%s.bin.%s", fw_basename, prod_suffix);
ret = tng_checkfw(dev, fw_name, imr_ptr, *sep_key, imr_addr);
if (ret == 0)
return ret;
return -1;
}
static void tng_print_imrinfo(int imrl_reg, uint64_t imr_base, uint64_t imr_end)
{
unsigned int imr_regnum = IMR_REG_NUMBER(imrl_reg);
if (imr_base != 0)
PSB_DEBUG_INIT("IMR%d ranges 0x%12llx - 0x%12llx\n",
imr_regnum, imr_base, imr_end);
PSB_DEBUG_INIT("IMR%d L 0x%2x = 0x%032x\n",
imr_regnum, imrl_reg,
intel_mid_msgbus_read32(PNW_IMR_MSG_PORT, imrl_reg));
PSB_DEBUG_INIT("IMR%d H 0x%2x = 0x%032x\n",
imr_regnum, imrl_reg + 1,
intel_mid_msgbus_read32(PNW_IMR_MSG_PORT, imrl_reg+1));
PSB_DEBUG_INIT("IMR%d RAC 0x%2x = 0x%032x\n",
imr_regnum, imrl_reg + 2,
intel_mid_msgbus_read32(PNW_IMR_MSG_PORT, imrl_reg+2));
PSB_DEBUG_INIT("IMR%d WAC 0x%2x = 0x%032x\n",
imr_regnum, imrl_reg + 3,
intel_mid_msgbus_read32(PNW_IMR_MSG_PORT, imrl_reg+3));
}
static void tng_get_imrinfo(int imrl_reg, uint64_t *imr_addr)
{
uint32_t imrl, imrh;
uint64_t imr_base, imr_end;
imrl = intel_mid_msgbus_read32(TNG_IMR_MSG_PORT, imrl_reg);
imrh = intel_mid_msgbus_read32(TNG_IMR_MSG_PORT, imrl_reg+1);
imr_base = (imrl & TNG_IMR_ADDRESS_MASK) << TNG_IMR_ADDRESS_SHIFT;
imr_end = (imrh & TNG_IMR_ADDRESS_MASK) << TNG_IMR_ADDRESS_SHIFT;
*imr_addr = imr_base;
tng_print_imrinfo(imrl_reg, imr_base, imr_end);
}
static int tng_securefw_prevsp(struct drm_device *dev, const struct firmware *raw)
{
struct drm_psb_private *dev_priv = dev->dev_private;
struct vsp_private *vsp_priv = dev_priv->vsp_private;
struct vsp_secure_boot_header *boot_header;
struct vsp_multi_app_blob_data *ma_header;
unsigned int vrl_header_size = 736;
unsigned char *ptr, *ma_ptr;
if (raw->size < sizeof(struct vsp_secure_boot_header)) {
DRM_ERROR("VSP:firmware is not a correct firmware (size %d)\n", (int)raw->size);
return 1;
}
ptr = (void *)raw->data;
ma_ptr = (void *) raw->data + vrl_header_size;
boot_header = (struct vsp_secure_boot_header *)(ptr + vrl_header_size);
ma_header = (struct vsp_multi_app_blob_data *)(ma_ptr + boot_header->ma_header_offset);
/* get firmware header */
memcpy(&vsp_priv->boot_header, boot_header, sizeof(vsp_priv->boot_header));
if (vsp_priv->boot_header.magic_number != VSP_SECURE_BOOT_MAGIC_NR) {
DRM_ERROR("VSP: failed to load correct vsp firmware\n"
"FW magic number is wrong %x (should be %x)\n",
vsp_priv->boot_header.magic_number,
VSP_SECURE_BOOT_MAGIC_NR);
return 1;
}
/* read application firmware image data (for state-buffer size, etc) */
/* load the multi-app blob header */
memcpy(&vsp_priv->ma_header, ma_header, sizeof(vsp_priv->ma_header));
if (vsp_priv->ma_header.magic_number != VSP_MULTI_APP_MAGIC_NR) {
DRM_ERROR("VSP: failed to load correct vsp firmware\n"
"FW magic number is wrong %x (should be %x)\n",
vsp_priv->ma_header.magic_number,
VSP_MULTI_APP_MAGIC_NR);
return 1;
}
VSP_DEBUG("firmware secure header:\n");
VSP_DEBUG("boot_header magic number %x\n", boot_header->magic_number);
VSP_DEBUG("boot_text_offset %x\n", boot_header->boot_text_offset);
VSP_DEBUG("boot_text_reg %x\n", boot_header->boot_text_reg);
VSP_DEBUG("boot_icache_value %x\n", boot_header->boot_icache_value);
VSP_DEBUG("boot_icache_reg %x\n", boot_header->boot_icache_reg);
VSP_DEBUG("boot_pc_value %x\n", boot_header->boot_pc_value);
VSP_DEBUG("boot_pc_reg %x\n", boot_header->boot_pc_reg);
VSP_DEBUG("ma_header_offset %x\n", boot_header->ma_header_offset);
VSP_DEBUG("ma_header_reg %x\n", boot_header->ma_header_reg);
VSP_DEBUG("boot_start_value %x\n", boot_header->boot_start_value);
VSP_DEBUG("boot_start_reg %x\n", boot_header->boot_start_reg);
VSP_DEBUG("firmware ma_blob header:\n");
VSP_DEBUG("ma_header magic number %x\n", ma_header->magic_number);
VSP_DEBUG("offset_from_start %x\n", ma_header->offset_from_start);
VSP_DEBUG("imr_state_buffer_addr %x\n", ma_header->imr_state_buffer_addr);
VSP_DEBUG("imr_state_buffer_size %x\n", ma_header->imr_state_buffer_size);
VSP_DEBUG("apps_default_context_buffer_size %x\n",
ma_header->apps_default_context_buffer_size);
return 0;
}
static void tng_securefw_postvsp(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
struct vsp_private *vsp_priv = dev_priv->vsp_private;
vsp_priv->ctrl = (struct vsp_ctrl_reg *) (dev_priv->vsp_reg +
VSP_CONFIG_REG_SDRAM_BASE +
VSP_CONFIG_REG_START);
vsp_priv->fw_loaded = VSP_FW_LOADED;
vsp_priv->vsp_state = VSP_STATE_DOWN;
}
int tng_securefw(struct drm_device *dev, char *fw_basename, char *island_name, int imrl_reg)
{
const struct firmware *raw = NULL;
char fw_name[FW_NAME_LEN];
unsigned char *imr_ptr;
uint64_t imr_addr;
int ret = 0, sep_key, fw_size;
const int vrl_header_size = VRL_SZ;
PSB_DEBUG_INIT("Try to get IMR region information\n");
tng_get_imrinfo(imrl_reg, &imr_addr);
PSB_DEBUG_INIT("Try to map IMR region\n");
imr_ptr = ioremap(imr_addr, VRL_SZ);
if (!imr_ptr) {
DRM_ERROR("Failed to map IMR region\n");
return 1;
}
ret = tng_get_fwinfo(dev, fw_name, fw_basename, &sep_key, imr_ptr, imr_addr);
if (ret) {
DRM_ERROR("failed to get fwinfo for %s\n", fw_basename);
goto out;
}
PSB_DEBUG_INIT("Use firmware %s for %s, SEP key %d\n", fw_name, sep_key);
PSB_DEBUG_INIT("Try to unmap IMR region\n");
if (imr_ptr) {
iounmap(imr_ptr);
imr_ptr = NULL;
}
/* try to load firmware from storage */
PSB_DEBUG_INIT("Try to request firmware %s\n", fw_name);
ret = request_firmware(&raw, fw_name, &dev->pdev->dev);
if (raw == NULL || ret < 0) {
DRM_ERROR("Failed to request firmware %s, ret = %d\n", fw_name, ret);
goto out;
}
PSB_DEBUG_INIT("Try to map IMR region\n");
imr_ptr = ioremap(imr_addr, raw->size);
if (!imr_ptr) {
DRM_ERROR("Failed to map IMR region\n");
ret = -1;
goto out;
}
if (!strncmp(island_name, "VSP", 3)) {
ret = tng_securefw_prevsp(dev, raw);
if (ret) {
DRM_ERROR("VSP sanity check failed\n");
goto out;
}
}
fw_size = raw->size;
PSB_DEBUG_INIT("Try to copy firmware into IMR region\n");
memcpy(imr_ptr, raw->data, fw_size);
#ifdef CONFIG_DX_SEP54
PSB_DEBUG_INIT("Try to verify firmware\n");
ret = sepapp_image_verify((u8 *)imr_addr, fw_size, sep_key,
ISLAND_MAGIC_NUMBER(island_name));
if (ret) {
DRM_ERROR("Failed to verify firmware %x\n", ret);
goto out;
}
PSB_DEBUG_INIT("After verification, IMR region information\n");
tng_print_imrinfo(imrl_reg, 0, 0);
#endif
if (!strncmp(island_name, "VSP", 3))
tng_securefw_postvsp(dev);
out:
PSB_DEBUG_INIT("Try to release firmware\n");
if (raw)
release_firmware(raw);
PSB_DEBUG_INIT("Try to unmap IMR region\n");
if (imr_ptr)
iounmap(imr_ptr);
return ret;
}
int tng_rawfw(struct drm_device *dev, uint8_t *fw_basename)
{
DRM_ERROR("Non secure mode never be ran\n");
return 1;
}