Przeglądaj źródła

msm: camera: isp: validation of cmd_buf support

This change validates cmd_buf in IFE/TFE before submitting
BL to CDM when debugfs(enable_invalid_cmd_check) is enabled.

CRs-Fixed: 3616889
Change-Id: I5418661ff092fb15d04ab7dda6f3b59742a232a8
Signed-off-by: Karthik Dillibabu <[email protected]>
(cherry picked from commit 7528980860a33e0d800915c64005965862b80982)
Karthik Dillibabu 1 rok temu
rodzic
commit
97c4721bae

+ 84 - 3
drivers/cam_cdm/cam_cdm_util.c

@@ -18,7 +18,6 @@
 
 #define CAM_CDM_SW_CMD_COUNT    2
 #define CAM_CMD_LENGTH_MASK     0xFFFF
-#define CAM_CDM_COMMAND_OFFSET  24
 #define CAM_CDM_REG_OFFSET_MASK 0x00FFFFFF
 
 #define CAM_CDM_DMI_DATA_HI_OFFSET   8
@@ -873,6 +872,88 @@ static long cam_cdm_util_dump_perf_ctrl_cmd(uint32_t *cmd_buf_addr)
 	return ret;
 }
 
+bool cam_cdm_util_validate_cmd_buf(
+	uint32_t *cmd_buf_start, uint32_t *cmd_buf_end)
+{
+	uint32_t *buf_now = cmd_buf_start;
+	uint32_t *buf_end = cmd_buf_end;
+	uint32_t cmd = 0;
+	int i = 0;
+	struct cdm_regcontinuous_cmd *p_regcont_cmd = NULL;
+	struct cdm_regrandom_cmd *p_regrand_cmd = NULL;
+
+	if (!cmd_buf_start || !cmd_buf_end) {
+		CAM_ERR(CAM_CDM, "Invalid args");
+		return true;
+	}
+
+	do {
+		cmd = *buf_now;
+		cmd = cmd >> CAM_CDM_COMMAND_OFFSET;
+
+		switch (cmd) {
+		case CAM_CDM_CMD_DMI:
+		case CAM_CDM_CMD_DMI_32:
+		case CAM_CDM_CMD_DMI_64:
+			if (buf_now > buf_end)
+				return true;
+
+			buf_now += CDMCmdHeaderSizes[CAM_CDM_CMD_DMI];
+			break;
+		case CAM_CDM_CMD_REG_CONT:
+			p_regcont_cmd = (struct cdm_regcontinuous_cmd *)buf_now;
+			buf_now += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_CONT];
+			for (i = 0; i < p_regcont_cmd->count; i++) {
+				if (buf_now > buf_end)
+					return true;
+
+				buf_now++;
+			}
+			break;
+		case CAM_CDM_CMD_REG_RANDOM:
+			p_regrand_cmd = (struct cdm_regrandom_cmd *)buf_now;
+			buf_now += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_RANDOM];
+			for (i = 0; i < p_regrand_cmd->count; i++) {
+				if (buf_now > buf_end)
+					return true;
+
+				buf_now += 2;
+			}
+			break;
+		case CAM_CDM_CMD_BUFF_INDIRECT:
+			buf_now += CDMCmdHeaderSizes[CAM_CDM_CMD_BUFF_INDIRECT];
+			if (buf_now > buf_end)
+				return true;
+
+			break;
+		case CAM_CDM_CMD_GEN_IRQ:
+			buf_now += CDMCmdHeaderSizes[CAM_CDM_CMD_GEN_IRQ];
+			break;
+		case CAM_CDM_CMD_WAIT_EVENT:
+			buf_now += CDMCmdHeaderSizes[CAM_CDM_CMD_WAIT_EVENT];
+			break;
+		case CAM_CDM_CMD_CHANGE_BASE:
+			if (buf_now > buf_end)
+				return true;
+
+			buf_now += CDMCmdHeaderSizes[CAM_CDM_CMD_CHANGE_BASE];
+			break;
+		case CAM_CDM_CMD_PERF_CTRL:
+			buf_now += CDMCmdHeaderSizes[CAM_CDM_CMD_PERF_CTRL];
+			break;
+		case CAM_CDM_CMD_COMP_WAIT:
+			buf_now += CDMCmdHeaderSizes[CAM_CDM_CMD_COMP_WAIT];
+			break;
+		default:
+			CAM_ERR(CAM_CDM, "Invalid CMD: 0x%x buf 0x%x",
+				cmd, *buf_now);
+			return true;
+		}
+	} while (buf_now < cmd_buf_end);
+
+	return false;
+}
+
 void cam_cdm_util_dump_cmd_buf(
 	uint32_t *cmd_buf_start, uint32_t *cmd_buf_end)
 {
@@ -931,7 +1012,7 @@ void cam_cdm_util_dump_cmd_buf(
 			buf_now++;
 			break;
 		}
-	} while (buf_now <= cmd_buf_end);
+	} while (buf_now < cmd_buf_end);
 }
 
 static uint32_t cam_cdm_util_dump_reg_cont_cmd_v2(
@@ -1102,6 +1183,6 @@ int cam_cdm_util_dump_cmd_bufs_v2(
 			buf_now++;
 			break;
 		}
-	} while (buf_now <= dump_info->src_end);
+	} while (buf_now < dump_info->src_end);
 	return rc;
 }

+ 15 - 0
drivers/cam_cdm/cam_cdm_util.h

@@ -9,6 +9,7 @@
 
 /* Max len for tag name for header while dumping cmd buffer*/
 #define CAM_CDM_CMD_TAG_MAX_LEN 128
+#define CAM_CDM_COMMAND_OFFSET  24
 
 #include <linux/types.h>
 
@@ -227,6 +228,20 @@ struct cam_cdm_cmd_dump_header {
 	uint32_t  word_size;
 };
 
+/**
+ * cam_cdm_util_validate_cmd_buf()
+ *
+ * @brief:            Util function to validate cdm command buffers
+ *
+ * @cmd_buffer_start: Pointer to start of cmd buffer
+ * @cmd_buffer_end:   Pointer to end of cmd buffer
+ *
+ * return true if invalid cmd found, otherwise false
+ *
+ */
+bool cam_cdm_util_validate_cmd_buf(
+	uint32_t *cmd_buffer_start, uint32_t *cmd_buffer_end);
+
 /**
  * cam_cdm_util_log_cmd_bufs()
  *

+ 8 - 1
drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c

@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include "cam_fd_hw_core.h"
@@ -368,6 +368,13 @@ static int cam_fd_hw_util_processcmd_prestart(struct cam_hw_info *fd_hw,
 		((struct cam_fd_soc_private *)soc_info->soc_private)->
 		regbase_index[CAM_FD_REG_CORE]);
 
+	if (mem_base == -1) {
+		CAM_ERR(CAM_FD, "failed to get mem_base, index: %d num_reg_map: %u",
+			((struct cam_fd_soc_private *)soc_info->soc_private)->
+			regbase_index[CAM_FD_REG_CORE], soc_info->num_reg_map);
+		return -EINVAL;
+	}
+
 	ctx_hw_private->cdm_ops->cdm_write_changebase(cmd_buf_addr, mem_base);
 	cmd_buf_addr += size;
 	available_size -= (size * 4);

+ 41 - 0
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c

@@ -22,6 +22,7 @@
 #include "cam_isp_packet_parser.h"
 #include "cam_ife_hw_mgr.h"
 #include "cam_cdm_intf_api.h"
+#include "cam_cdm_util.h"
 #include "cam_packet_util.h"
 #include "cam_debug_util.h"
 #include "cam_mem_mgr.h"
@@ -7103,6 +7104,9 @@ static int cam_ife_mgr_config_hw(
 	struct cam_ife_hw_mgr *ife_hw_mgr;
 	unsigned long rem_jiffies = 0;
 	bool is_cdm_hung = false;
+	size_t len = 0;
+	uint32_t *buf_addr = NULL, *buf_start = NULL, *buf_end = NULL;
+	uint32_t cmd_type = 0;
 
 	if (!hw_mgr_priv || !config_hw_args) {
 		CAM_ERR(CAM_ISP,
@@ -7336,6 +7340,41 @@ skip_bw_clk_update:
 			cdm_cmd->cmd[i - skip].offset = cmd->offset;
 			cdm_cmd->cmd[i - skip].len = cmd->len;
 			cdm_cmd->cmd[i - skip].arbitrate = false;
+
+			if (g_ife_hw_mgr.debug_cfg.enable_cdm_cmd_check) {
+				CAM_INFO_RATE_LIMIT(CAM_ISP, "Enter cdm cmd_buf validation");
+				rc = cam_packet_util_get_cmd_mem_addr(
+					cdm_cmd->cmd[i - skip].bl_addr.mem_handle,
+					&buf_addr, &len);
+				if (rc) {
+					CAM_ERR(CAM_ISP,
+						"Failed to get buf_addr and len for mem_handle: %d ctx id: %u request id: %llu",
+						cdm_cmd->cmd[i - skip].bl_addr.mem_handle,
+						ctx->ctx_index, cfg->request_id);
+					continue;
+				}
+
+				buf_start = (uint32_t *)((uint8_t *) buf_addr +
+					cdm_cmd->cmd[i - skip].offset);
+				buf_end = (uint32_t *)((uint8_t *) buf_start +
+					cdm_cmd->cmd[i - skip].len - 1);
+				cmd_type = ((uint32_t)(*buf_start) >> CAM_CDM_COMMAND_OFFSET);
+				if ((i == 0) && (cmd_type != CAM_CDM_CMD_CHANGE_BASE)) {
+					CAM_ERR(CAM_ISP,
+						"first cmd in cmd_buf is not change_base, cmd_type: %u ctx id: %u request id: %llu",
+						cmd_type, ctx->ctx_index, cfg->request_id);
+					cam_cdm_util_dump_cmd_buf(buf_start, buf_end);
+					return -EINVAL;
+				}
+
+				if (cam_cdm_util_validate_cmd_buf(buf_start, buf_end)) {
+					CAM_ERR(CAM_ISP,
+						"found invalid cmd in cmd_buf, ctx id: %u request id: %llu",
+						ctx->ctx_index, cfg->request_id);
+					cam_cdm_util_dump_cmd_buf(buf_start, buf_end);
+					return -EINVAL;
+				}
+			}
 		}
 		cdm_cmd->cmd_arrary_count = cfg->num_hw_update_entries - skip;
 
@@ -16901,6 +16940,8 @@ static int cam_ife_hw_mgr_debug_register(void)
 		&g_ife_hw_mgr.debug_cfg.enable_presil_reg_dump);
 	debugfs_create_file("isp_irq_inject", 0644,
 		g_ife_hw_mgr.debug_cfg.dentry, NULL, &cam_isp_irq_injection);
+	debugfs_create_bool("enable_cdm_cmd_check", 0644, g_ife_hw_mgr.debug_cfg.dentry,
+		&g_ife_hw_mgr.debug_cfg.enable_cdm_cmd_check);
 end:
 	g_ife_hw_mgr.debug_cfg.enable_csid_recovery = 1;
 	return rc;

+ 2 - 1
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h

@@ -64,7 +64,7 @@ enum cam_ife_ctx_master_type {
  * @rx_capture_debug_set:      If rx capture debug is set by user
  * @disable_isp_drv:           Disable ISP DRV config
  * @enable_presil_reg_dump:    Enable per req regdump in presil
- *
+ * @enable_cdm_cmd_check:      Enable invalid command check in cmd_buf
  */
 struct cam_ife_hw_mgr_debug {
 	struct dentry  *dentry;
@@ -87,6 +87,7 @@ struct cam_ife_hw_mgr_debug {
 	bool           rx_capture_debug_set;
 	bool           disable_isp_drv;
 	bool           enable_presil_reg_dump;
+	bool           enable_cdm_cmd_check;
 };
 
 /**

+ 40 - 0
drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.c

@@ -19,6 +19,7 @@
 #include "cam_isp_packet_parser.h"
 #include "cam_tfe_hw_mgr.h"
 #include "cam_cdm_intf_api.h"
+#include "cam_cdm_util.h"
 #include "cam_packet_util.h"
 #include "cam_debug_util.h"
 #include "cam_cpas_api.h"
@@ -2666,6 +2667,9 @@ static int cam_tfe_mgr_config_hw(void *hw_mgr_priv,
 	struct cam_tfe_hw_mgr_ctx *ctx;
 	struct cam_isp_prepare_hw_update_data *hw_update_data;
 	bool is_cdm_hung = false;
+	size_t len = 0;
+	uint32_t *buf_addr = NULL, *buf_start = NULL, *buf_end = NULL;
+	uint32_t cmd_type = 0;
 
 	if (!hw_mgr_priv || !config_hw_args) {
 		CAM_ERR(CAM_ISP, "Invalid arguments");
@@ -2769,6 +2773,40 @@ static int cam_tfe_mgr_config_hw(void *hw_mgr_priv,
 		cdm_cmd->cmd[i - skip].offset = cmd->offset;
 		cdm_cmd->cmd[i - skip].len = cmd->len;
 		cdm_cmd->cmd[i - skip].arbitrate = false;
+
+		if (g_tfe_hw_mgr.debug_cfg.enable_cdm_cmd_check) {
+			CAM_INFO_RATE_LIMIT(CAM_ISP, "Enter cdm cmd_buf validation");
+			rc = cam_packet_util_get_cmd_mem_addr(
+				cdm_cmd->cmd[i - skip].bl_addr.mem_handle, &buf_addr, &len);
+			if (rc) {
+				CAM_ERR(CAM_ISP,
+					"Failed to get buf_addr and len for mem_handle: %d ctx id: %u request id: %llu",
+					cdm_cmd->cmd[i - skip].bl_addr.mem_handle,
+					ctx->ctx_index, cfg->request_id);
+				continue;
+			}
+
+			buf_start = (uint32_t *)((uint8_t *) buf_addr +
+				cdm_cmd->cmd[i - skip].offset);
+			buf_end = (uint32_t *)((uint8_t *) buf_start +
+				cdm_cmd->cmd[i - skip].len - 1);
+			cmd_type = ((uint32_t)(*buf_start) >> CAM_CDM_COMMAND_OFFSET);
+			if ((i == 0) && (cmd_type != CAM_CDM_CMD_CHANGE_BASE)) {
+				CAM_ERR(CAM_ISP,
+					"first cmd in cmd_buf is not change_base, cmd_type: %u ctx id: %u request id: %llu",
+					cmd_type, ctx->ctx_index, cfg->request_id);
+				cam_cdm_util_dump_cmd_buf(buf_start, buf_end);
+				return -EINVAL;
+			}
+
+			if (cam_cdm_util_validate_cmd_buf(buf_start, buf_end)) {
+				CAM_ERR(CAM_ISP,
+					"found invalid cmd in cmd_buf, ctx id: %u request id: %llu",
+					ctx->ctx_index, cfg->request_id);
+				cam_cdm_util_dump_cmd_buf(buf_start, buf_end);
+				return -EINVAL;
+			}
+		}
 	}
 
 	cdm_cmd->cmd_arrary_count = cfg->num_hw_update_entries - skip;
@@ -5967,6 +6005,8 @@ static int cam_tfe_hw_mgr_debug_register(void)
 	debugfs_create_u32("per_req_reg_dump", 0644,
 		g_tfe_hw_mgr.debug_cfg.dentry,
 		&g_tfe_hw_mgr.debug_cfg.per_req_reg_dump);
+	debugfs_create_bool("enable_cdm_cmd_check", 0644, g_tfe_hw_mgr.debug_cfg.dentry,
+		&g_tfe_hw_mgr.debug_cfg.enable_cdm_cmd_check);
 	if (IS_ERR(dbgfileptr)) {
 		if (PTR_ERR(dbgfileptr) == -ENODEV)
 			CAM_WARN(CAM_ISP, "DebugFS not enabled in kernel!");

+ 2 - 1
drivers/cam_isp/isp_hw_mgr/cam_tfe_hw_mgr.h

@@ -32,7 +32,7 @@
  * @camif_debug:               enable sensor diagnosis status
  * @enable_reg_dump:           enable reg dump on error;
  * @per_req_reg_dump:          Enable per request reg dump
- *
+ * @enable_cdm_cmd_check:      Enable invalid command check in cmd_buf
  */
 struct cam_tfe_hw_mgr_debug {
 	struct dentry  *dentry;
@@ -42,6 +42,7 @@ struct cam_tfe_hw_mgr_debug {
 	uint32_t       camif_debug;
 	uint32_t       enable_reg_dump;
 	uint32_t       per_req_reg_dump;
+	bool           enable_cdm_cmd_check;
 };
 
 /**

+ 6 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_common.c

@@ -684,6 +684,12 @@ int cam_ife_csid_get_base(struct cam_hw_soc_info *soc_info,
 	}
 
 	mem_base = CAM_SOC_GET_REG_MAP_CAM_BASE(soc_info, base_id);
+	if (mem_base == -1) {
+		CAM_ERR(CAM_ISP, "failed to get mem_base, index: %d num_reg_map: %u",
+				base_id, soc_info->num_reg_map);
+		return -EINVAL;
+	}
+
 	if (cdm_args->cdm_id == CAM_CDM_RT) {
 		if (!soc_private->rt_wrapper_base) {
 			CAM_ERR(CAM_ISP, "rt_wrapper_base_addr is null");

+ 5 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_top/cam_sfe_top.c

@@ -780,6 +780,11 @@ static int cam_sfe_top_get_base(
 	mem_base = CAM_SOC_GET_REG_MAP_CAM_BASE(
 		top_priv->common_data.soc_info,
 		SFE_CORE_BASE_IDX);
+	if (mem_base == -1) {
+		CAM_ERR(CAM_SFE, "failed to get mem_base, index: %d num_reg_map: %u",
+				SFE_CORE_BASE_IDX, top_priv->common_data.soc_info->num_reg_map);
+		return -EINVAL;
+	}
 
 	if (cdm_args->cdm_id == CAM_CDM_RT) {
 		if (!soc_private->rt_wrapper_base) {

+ 5 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/tfe_hw/cam_tfe_core.c

@@ -1207,6 +1207,11 @@ static int cam_tfe_top_get_base(struct cam_tfe_top_priv *top_priv,
 
 	mem_base = CAM_SOC_GET_REG_MAP_CAM_BASE(
 		top_priv->common_data.soc_info, TFE_CORE_BASE_IDX);
+	if (mem_base == -1) {
+		CAM_ERR(CAM_ISP, "failed to get mem_base, index: %d num_reg_map: %u",
+			TFE_CORE_BASE_IDX, top_priv->common_data.soc_info->num_reg_map);
+		return -EINVAL;
+	}
 
 	cdm_util_ops->cdm_write_changebase(
 	cdm_args->cmd.cmd_buf_addr, mem_base);

+ 6 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c

@@ -64,6 +64,12 @@ static int cam_vfe_top_mux_get_base(struct cam_vfe_top_ver2_priv *top_priv,
 
 	mem_base = CAM_SOC_GET_REG_MAP_CAM_BASE(
 		top_priv->top_common.soc_info, VFE_CORE_BASE_IDX);
+	if (mem_base == -1) {
+		CAM_ERR(CAM_ISP, "failed to get mem_base, index: %d num_reg_map: %u",
+			VFE_CORE_BASE_IDX, top_priv->top_common.soc_info->num_reg_map);
+		return -EINVAL;
+	}
+
 	CAM_DBG(CAM_ISP, "core %d mem_base 0x%x",
 		top_priv->top_common.soc_info->index, mem_base);
 

+ 5 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c

@@ -83,6 +83,11 @@ static int cam_vfe_top_ver3_mux_get_base(struct cam_vfe_top_ver3_priv *top_priv,
 
 	mem_base = CAM_SOC_GET_REG_MAP_CAM_BASE(
 		top_priv->top_common.soc_info, VFE_CORE_BASE_IDX);
+	if (mem_base == -1) {
+		CAM_ERR(CAM_ISP, "failed to get mem_base, index: %d num_reg_map: %u",
+			VFE_CORE_BASE_IDX, top_priv->top_common.soc_info->num_reg_map);
+		return -EINVAL;
+	}
 	CAM_DBG(CAM_ISP, "core %d mem_base 0x%x",
 		top_priv->top_common.soc_info->index, mem_base);
 

+ 6 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver4.c

@@ -258,6 +258,12 @@ static int cam_vfe_top_ver4_mux_get_base(struct cam_vfe_top_ver4_priv *top_priv,
 
 	mem_base = CAM_SOC_GET_REG_MAP_CAM_BASE(
 		top_priv->top_common.soc_info, VFE_CORE_BASE_IDX);
+	if (mem_base == -1) {
+		CAM_ERR(CAM_ISP, "failed to get mem_base, index: %d num_reg_map: %u",
+			VFE_CORE_BASE_IDX, top_priv->top_common.soc_info->num_reg_map);
+		return -EINVAL;
+	}
+
 	if (cdm_args->cdm_id == CAM_CDM_RT) {
 		if (!soc_private->rt_wrapper_base) {
 			CAM_ERR(CAM_ISP, "VFE:%u rt_wrapper_base_addr is null",

+ 6 - 1
drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c

@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/timer.h>
@@ -408,6 +408,11 @@ static int cam_lrme_hw_util_process_config_hw(struct cam_hw_info *lrme_hw,
 	}
 
 	mem_base = CAM_SOC_GET_REG_MAP_CAM_BASE(soc_info, CAM_LRME_BASE_IDX);
+	if (mem_base == -1) {
+		CAM_ERR(CAM_LRME, "failed to get mem_base, index: %d num_reg_map: %u",
+			CAM_LRME_BASE_IDX, soc_info->num_reg_map);
+		return -EINVAL;
+	}
 
 	hw_cdm_info->cdm_ops->cdm_write_changebase(cmd_buf_addr, mem_base);
 	cmd_buf_addr += size;