You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1226 lines
33 KiB
1226 lines
33 KiB
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* drivers/samsung/debug/sec_debug.c
|
|
*
|
|
* COPYRIGHT(C) 2006-2019 Samsung Electronics Co., Ltd. All Right Reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 and
|
|
* only version 2 as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that 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.
|
|
*/
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ":%s() " fmt, __func__
|
|
|
|
#include <linux/version.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/init.h>
|
|
#include <linux/input/qpnp-power-on.h>
|
|
#include <linux/kernel_stat.h>
|
|
#include <linux/module.h>
|
|
#include <linux/nmi.h>
|
|
#include <linux/notifier.h>
|
|
#include <linux/of_address.h>
|
|
#include <linux/oom.h>
|
|
#include <linux/reboot.h>
|
|
#include <linux/regulator/consumer.h>
|
|
#include <linux/seq_file.h>
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,4,0)
|
|
#include <linux/memblock.h>
|
|
#include <soc/qcom/qseecom_scm.h>
|
|
#include <linux/qcom_scm.h>
|
|
#else
|
|
#include <linux/bootmem.h>
|
|
#include <asm/compiler.h>
|
|
#endif
|
|
#include <linux/soc/qcom/smem.h>
|
|
#include <soc/qcom/restart.h>
|
|
|
|
#include <asm/cacheflush.h>
|
|
#include <asm/stacktrace.h>
|
|
#include <asm/system_misc.h>
|
|
|
|
#include <linux/sec_debug.h>
|
|
#include <linux/sec_param.h>
|
|
|
|
#define CREATE_TRACE_POINTS
|
|
#include <trace/events/sec_debug.h>
|
|
|
|
#include "sec_debug_internal.h"
|
|
|
|
#ifdef CONFIG_ARM64
|
|
static inline void outer_flush_all(void) { }
|
|
#endif
|
|
|
|
#ifndef CONFIG_SAMSUNG_PRODUCT_SHIP
|
|
unsigned long sec_delay_check __read_mostly = 1;
|
|
EXPORT_SYMBOL(sec_delay_check);
|
|
#endif
|
|
|
|
/* enable sec_debug feature */
|
|
static unsigned int sec_dbg_level;
|
|
static int force_upload;
|
|
|
|
static unsigned int enable = 1;
|
|
module_param_named(enable, enable, uint, 0644);
|
|
|
|
#ifdef CONFIG_SEC_SSR_DEBUG_LEVEL_CHK
|
|
static unsigned int enable_cp_debug = 1;
|
|
module_param_named(enable_cp_debug, enable_cp_debug, uint, 0644);
|
|
#endif
|
|
|
|
static unsigned int dump_sink;
|
|
module_param_named(dump_sink, dump_sink, uint, 0644);
|
|
|
|
static unsigned int reboot_multicmd;
|
|
module_param_named(reboot_multicmd, reboot_multicmd, uint, 0644);
|
|
|
|
uint64_t get_pa_dump_sink(void)
|
|
{
|
|
return virt_to_phys(&dump_sink);
|
|
}
|
|
|
|
/* This is shared with msm-power off module. */
|
|
void __iomem *restart_reason;
|
|
static void __iomem *upload_cause;
|
|
#if IS_ENABLED(CONFIG_POWER_RESET_QCOM_DOWNLOAD_MODE)
|
|
static void __iomem *watchdog_base;
|
|
#define WDT0_RST 0x04
|
|
#define WDT0_EN 0x08
|
|
#define WDT0_BITE_TIME 0x14
|
|
#endif
|
|
|
|
void (*sec_nvmem_pon_write)(u8 pon_rr) = NULL;
|
|
|
|
DEFINE_PER_CPU(struct sec_debug_core_t, sec_debug_core_reg);
|
|
DEFINE_PER_CPU(struct sec_debug_mmu_reg_t, sec_debug_mmu_reg);
|
|
DEFINE_PER_CPU(enum sec_debug_upload_cause_t, sec_debug_upload_cause);
|
|
|
|
static void sec_debug_set_qc_dload_magic(int on)
|
|
{
|
|
pr_info("on=%d\n", on);
|
|
set_dload_mode(on);
|
|
}
|
|
|
|
#define PON_RESTART_REASON_NOT_HANDLE PON_RESTART_REASON_MAX
|
|
#define RESTART_REASON_NOT_HANDLE RESTART_REASON_END
|
|
|
|
/* This is shared with 'msm-poweroff.c' module. */
|
|
static enum sec_restart_reason_t __iomem *qcom_restart_reason;
|
|
|
|
static void sec_debug_set_upload_magic(unsigned int magic)
|
|
{
|
|
__pr_err("(%s) %x\n", __func__, magic);
|
|
|
|
if (magic != RESTART_REASON_NORMAL)
|
|
sec_debug_set_qc_dload_magic(1);
|
|
else
|
|
sec_debug_set_qc_dload_magic(0);
|
|
|
|
__raw_writel(magic, qcom_restart_reason);
|
|
|
|
flush_cache_all();
|
|
outer_flush_all();
|
|
}
|
|
|
|
static int sec_debug_normal_reboot_handler(struct notifier_block *nb,
|
|
unsigned long action, void *data)
|
|
{
|
|
char recovery_cause[256] = { '\0', };
|
|
char *ptr1, *ptr2;
|
|
char index_char[3];
|
|
unsigned int index;
|
|
|
|
set_dload_mode(0); /* set defalut (not upload mode) */
|
|
|
|
sec_debug_set_upload_magic(RESTART_REASON_NORMAL);
|
|
|
|
if (unlikely(!data))
|
|
return 0;
|
|
|
|
if ((action == SYS_RESTART) &&
|
|
!strncmp((char *)data, "recovery", 8)) {
|
|
sec_get_param(param_index_reboot_recovery_cause,
|
|
recovery_cause);
|
|
if (!recovery_cause[0] || !strlen(recovery_cause)) {
|
|
snprintf(recovery_cause, sizeof(recovery_cause),
|
|
"%s:%d ", current->comm, task_pid_nr(current));
|
|
sec_set_param(param_index_reboot_recovery_cause,
|
|
recovery_cause);
|
|
}
|
|
}
|
|
|
|
if ((action == SYS_RESTART) &&
|
|
!strncmp((char *)data, "param", 5)) {
|
|
ptr1 = strchr((char *)data, '_');
|
|
ptr1 = ptr1 + 1;
|
|
ptr2 = strchr((char *)ptr1, '_');
|
|
memcpy(&index_char, ptr1 , ptr2-ptr1);
|
|
index_char[ptr2-ptr1] = '\0';
|
|
|
|
if(!kstrtouint(index_char, 0, &index)) {
|
|
ptr2 = ptr2 + 1;
|
|
if (*ptr2 == '0') {
|
|
unsigned long value_number;
|
|
if (!kstrtoul(ptr2 + 1, 0, &value_number))
|
|
sec_set_param(index, &value_number);
|
|
} else if (*ptr2 == '1') {
|
|
char value_char[256] = {0,};
|
|
ptr2 = ptr2 + 1;
|
|
memcpy(value_char, ptr2, strlen ((char *)ptr2));
|
|
sec_set_param(index, value_char);
|
|
} else
|
|
pr_info("invalid param index of reboot cmd.\n");
|
|
} else
|
|
pr_info("invalid param value of reboot cmd.\n");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void sec_debug_update_dload_mode(const int restart_mode, const int in_panic)
|
|
{
|
|
if (!in_panic && restart_mode != RESTART_DLOAD)
|
|
sec_debug_set_upload_magic(RESTART_REASON_NORMAL);
|
|
}
|
|
|
|
static inline void __sec_debug_set_restart_reason(
|
|
enum sec_restart_reason_t __r)
|
|
{
|
|
__raw_writel((u32)__r, qcom_restart_reason);
|
|
}
|
|
|
|
static enum pon_restart_reason __pon_restart_rory_start(
|
|
unsigned long opt_code)
|
|
{
|
|
return (PON_RESTART_REASON_RORY_START | opt_code);
|
|
}
|
|
|
|
static enum pon_restart_reason __pon_restart_set_debug_level(
|
|
unsigned long opt_code)
|
|
{
|
|
switch (opt_code) {
|
|
case ANDROID_DEBUG_LEVEL_LOW:
|
|
return PON_RESTART_REASON_DBG_LOW;
|
|
case ANDROID_DEBUG_LEVEL_MID:
|
|
return PON_RESTART_REASON_DBG_MID;
|
|
case ANDROID_DEBUG_LEVEL_HIGH:
|
|
return PON_RESTART_REASON_DBG_HIGH;
|
|
}
|
|
|
|
return PON_RESTART_REASON_UNKNOWN;
|
|
}
|
|
|
|
static enum pon_restart_reason __pon_restart_set_cpdebug(
|
|
unsigned long opt_code)
|
|
{
|
|
if (opt_code == ANDROID_CP_DEBUG_ON)
|
|
return PON_RESTART_REASON_CP_DBG_ON;
|
|
else if (opt_code == ANDROID_CP_DEBUG_OFF)
|
|
return PON_RESTART_REASON_CP_DBG_OFF;
|
|
|
|
return PON_RESTART_REASON_UNKNOWN;
|
|
}
|
|
|
|
static enum pon_restart_reason __pon_restart_force_upload(
|
|
unsigned long opt_code)
|
|
{
|
|
return (opt_code) ?
|
|
PON_RESTART_REASON_FORCE_UPLOAD_ON :
|
|
PON_RESTART_REASON_FORCE_UPLOAD_OFF;
|
|
}
|
|
|
|
static enum pon_restart_reason __pon_restart_dump_sink(
|
|
unsigned long opt_code)
|
|
{
|
|
switch (opt_code) {
|
|
case DUMP_SINK_TO_BOOTDEV:
|
|
return PON_RESTART_REASON_DUMP_SINK_BOOTDEV;
|
|
case DUMP_SINK_TO_SDCARD:
|
|
return PON_RESTART_REASON_DUMP_SINK_SDCARD;
|
|
default:
|
|
return PON_RESTART_REASON_DUMP_SINK_USB;
|
|
}
|
|
|
|
return PON_RESTART_REASON_UNKNOWN;
|
|
}
|
|
|
|
static enum pon_restart_reason __pon_restart_cdsp_signoff(
|
|
unsigned long opt_code)
|
|
{
|
|
switch (opt_code) {
|
|
case CDSP_SIGNOFF_ON:
|
|
return PON_RESTART_REASON_CDSP_ON;
|
|
case CDSP_SIGNOFF_BLOCK:
|
|
return PON_RESTART_REASON_CDSP_BLOCK;
|
|
}
|
|
|
|
return PON_RESTART_REASON_UNKNOWN;
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_MUIC_SUPPORT_RUSTPROOF
|
|
static enum pon_restart_reason __pon_restart_swsel(
|
|
unsigned long opt_code)
|
|
{
|
|
unsigned long value =
|
|
(((opt_code & 0x8) >> 1) | opt_code) & 0x7;
|
|
|
|
return (PON_RESTART_REASON_SWITCHSEL | value);
|
|
}
|
|
#endif
|
|
|
|
/* FIXME: QC's linux-5.4.y does not have 'arm_pm_restart' call back in
|
|
* arch/arm64/kernel/process.c file.
|
|
* This is an weak symbol having a same name and this will be eliminated
|
|
* while linking if the kernel has a 'arm_pm_restart' and if it does't
|
|
* this variable has a 'NULL' value by default.
|
|
*/
|
|
void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd) __weak;
|
|
|
|
static inline void sec_debug_pm_restart(char *cmd)
|
|
{
|
|
__pr_err("(%s) %s %s\n", __func__,
|
|
init_uts_ns.name.release, init_uts_ns.name.version);
|
|
__pr_err("(%s) rebooting...\n", __func__);
|
|
flush_cache_all();
|
|
outer_flush_all();
|
|
|
|
#if IS_ENABLED(CONFIG_POWER_RESET_QCOM_DOWNLOAD_MODE)
|
|
if (!sec_nvmem_pon_write && watchdog_base) {
|
|
pr_emerg("Causing a watchdog bite!\n");
|
|
__raw_writel(1, watchdog_base + WDT0_EN);
|
|
mb();
|
|
__raw_writel(1, watchdog_base + WDT0_BITE_TIME);
|
|
/* Mke sure bite time is written before we reset */
|
|
mb();
|
|
__raw_writel(1, watchdog_base + WDT0_RST);
|
|
/* Make sure we wait only after reset */
|
|
mb();
|
|
|
|
/* while (1) ; */
|
|
asm volatile ("b .");
|
|
}
|
|
#endif
|
|
if (arm_pm_restart)
|
|
arm_pm_restart(REBOOT_COLD, cmd);
|
|
else
|
|
do_kernel_restart(cmd);
|
|
|
|
/* while (1) ; */
|
|
asm volatile ("b .");
|
|
}
|
|
|
|
static void __sec_debug_hw_reset(void)
|
|
{
|
|
sec_debug_pm_restart("sec_debug_hw_reset");
|
|
}
|
|
|
|
#ifndef CONFIG_SEC_LOG_STORE_LAST_KMSG
|
|
static bool sec_check_leave_reboot_reason(enum pon_restart_reason pon_rr)
|
|
{
|
|
bool result = false;
|
|
|
|
result = (pon_rr == PON_RESTART_REASON_MULTICMD) || result;
|
|
result = (pon_rr == PON_RESTART_REASON_LIMITED_DRAM_SETTING) || result;
|
|
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
void sec_debug_update_restart_reason(const char *cmd, const int in_panic,
|
|
const int restart_mode)
|
|
{
|
|
struct __magic {
|
|
const char *cmd;
|
|
enum pon_restart_reason pon_rr;
|
|
enum sec_restart_reason_t sec_rr;
|
|
enum pon_restart_reason (*func)(unsigned long opt_code);
|
|
} magic[] = {
|
|
{ "sec_debug_hw_reset",
|
|
PON_RESTART_REASON_NOT_HANDLE,
|
|
RESTART_REASON_SEC_DEBUG_MODE, NULL},
|
|
{ "download",
|
|
PON_RESTART_REASON_DOWNLOAD,
|
|
RESTART_REASON_NOT_HANDLE, NULL},
|
|
{ "nvbackup",
|
|
PON_RESTART_REASON_NVBACKUP,
|
|
RESTART_REASON_NOT_HANDLE, NULL},
|
|
{ "nvrestore",
|
|
PON_RESTART_REASON_NVRESTORE,
|
|
RESTART_REASON_NOT_HANDLE, NULL},
|
|
{ "nverase",
|
|
PON_RESTART_REASON_NVERASE,
|
|
RESTART_REASON_NOT_HANDLE, NULL},
|
|
{ "nvrecovery",
|
|
PON_RESTART_REASON_NVRECOVERY,
|
|
RESTART_REASON_NOT_HANDLE, NULL},
|
|
{ "cpmem_on",
|
|
PON_RESTART_REASON_CP_MEM_RESERVE_ON,
|
|
RESTART_REASON_NOT_HANDLE, NULL},
|
|
{ "cpmem_off",
|
|
PON_RESTART_REASON_CP_MEM_RESERVE_OFF,
|
|
RESTART_REASON_NOT_HANDLE, NULL},
|
|
{ "mbsmem_on",
|
|
PON_RESTART_REASON_MBS_MEM_RESERVE_ON,
|
|
RESTART_REASON_NOT_HANDLE, NULL},
|
|
{ "mbsmem_off",
|
|
PON_RESTART_REASON_MBS_MEM_RESERVE_OFF,
|
|
RESTART_REASON_NOT_HANDLE, NULL},
|
|
{ "GlobalActions restart",
|
|
PON_RESTART_REASON_NORMALBOOT,
|
|
RESTART_REASON_NOT_HANDLE, NULL},
|
|
{ "userrequested",
|
|
PON_RESTART_REASON_NORMALBOOT,
|
|
RESTART_REASON_NOT_HANDLE, NULL},
|
|
{ "silent.sec",
|
|
PON_RESTART_REASON_NORMALBOOT,
|
|
RESTART_REASON_NOT_HANDLE, NULL },
|
|
{ "oem-",
|
|
PON_RESTART_REASON_UNKNOWN,
|
|
RESTART_REASON_NORMAL, NULL},
|
|
{ "sud",
|
|
PON_RESTART_REASON_UNKNOWN,
|
|
RESTART_REASON_NORMAL, __pon_restart_rory_start},
|
|
{ "debug",
|
|
PON_RESTART_REASON_UNKNOWN,
|
|
RESTART_REASON_NORMAL, __pon_restart_set_debug_level},
|
|
{ "cpdebug",
|
|
PON_RESTART_REASON_UNKNOWN,
|
|
RESTART_REASON_NORMAL, __pon_restart_set_cpdebug},
|
|
{ "forceupload",
|
|
PON_RESTART_REASON_UNKNOWN,
|
|
RESTART_REASON_NORMAL, __pon_restart_force_upload},
|
|
{ "dump_sink",
|
|
PON_RESTART_REASON_UNKNOWN,
|
|
RESTART_REASON_NORMAL, __pon_restart_dump_sink},
|
|
{ "signoff",
|
|
PON_RESTART_REASON_UNKNOWN,
|
|
RESTART_REASON_NORMAL, __pon_restart_cdsp_signoff},
|
|
{ "cross_fail",
|
|
PON_RESTART_REASON_CROSS_FAIL,
|
|
RESTART_REASON_NORMAL, NULL},
|
|
{ "from_fastboot",
|
|
PON_RESTART_REASON_NORMALBOOT,
|
|
RESTART_REASON_NOT_HANDLE, NULL},
|
|
{ "disallow,fastboot",
|
|
PON_RESTART_REASON_NORMALBOOT,
|
|
RESTART_REASON_NOT_HANDLE, NULL},
|
|
#ifdef CONFIG_MUIC_SUPPORT_RUSTPROOF
|
|
{ "swsel",
|
|
PON_RESTART_REASON_UNKNOWN,
|
|
RESTART_REASON_NORMAL, __pon_restart_swsel},
|
|
#endif
|
|
#ifdef CONFIG_SEC_PERIPHERAL_SECURE_CHK
|
|
{ "peripheral_hw_reset",
|
|
PON_RESTART_REASON_SECURE_CHECK_FAIL,
|
|
RESTART_REASON_NORMAL, NULL},
|
|
#endif
|
|
#ifdef CONFIG_SEC_QUEST_UEFI_USER
|
|
{ "user_quefi_quest",
|
|
PON_RESTART_REASON_QUEST_QUEFI_USER_START,
|
|
RESTART_REASON_NORMAL, NULL},
|
|
{ "user_suefi_quest",
|
|
PON_RESTART_REASON_QUEST_SUEFI_USER_START,
|
|
RESTART_REASON_NORMAL, NULL},
|
|
#endif
|
|
#ifdef CONFIG_SEC_QUEST_DDR_SCAN_USER
|
|
{ "user_dram_test",
|
|
PON_RESTART_REASON_USER_DRAM_TEST,
|
|
RESTART_REASON_NORMAL, NULL},
|
|
#endif
|
|
{ "multicmd",
|
|
PON_RESTART_REASON_MULTICMD,
|
|
RESTART_REASON_NORMAL, NULL},
|
|
{ "dram",
|
|
PON_RESTART_REASON_LIMITED_DRAM_SETTING,
|
|
RESTART_REASON_NORMAL, NULL}
|
|
};
|
|
enum pon_restart_reason pon_rr = PON_RESTART_REASON_UNKNOWN;
|
|
enum sec_restart_reason_t sec_rr = RESTART_REASON_NORMAL;
|
|
char cmd_buf[256];
|
|
size_t i;
|
|
|
|
if (!in_panic && restart_mode != RESTART_DLOAD)
|
|
pon_rr = PON_RESTART_REASON_NORMALBOOT;
|
|
|
|
#ifndef CONFIG_SEC_LOG_STORE_LAST_KMSG
|
|
__next_cmd:
|
|
#endif
|
|
if (!cmd)
|
|
__pr_err("(%s) reboot cmd : NULL\n", __func__);
|
|
else if (!strlen(cmd))
|
|
__pr_err("(%s) reboot cmd : Zero Length\n", __func__);
|
|
else {
|
|
strlcpy(cmd_buf, cmd, ARRAY_SIZE(cmd_buf));
|
|
__pr_err("(%s) reboot cmd : %s\n", __func__, cmd_buf);
|
|
}
|
|
|
|
if (!cmd || !strlen(cmd) || !strncmp(cmd, "adb", 3))
|
|
goto __done;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(magic); i++) {
|
|
size_t len = strlen(magic[i].cmd);
|
|
|
|
if (strncmp(cmd, magic[i].cmd, len))
|
|
continue;
|
|
|
|
#ifndef CONFIG_SEC_LOG_STORE_LAST_KMSG
|
|
if (sec_check_leave_reboot_reason(magic[i].pon_rr)) {
|
|
cmd = cmd + len + 1;
|
|
goto __next_cmd;
|
|
}
|
|
#endif
|
|
pon_rr = magic[i].pon_rr;
|
|
sec_rr = magic[i].sec_rr;
|
|
|
|
if (magic[i].func != NULL) {
|
|
unsigned long opt_code;
|
|
char *ptr = strstr(cmd_buf, ":");
|
|
|
|
if (ptr != NULL)
|
|
*ptr = '\0';
|
|
|
|
if (!kstrtoul(cmd_buf + len, 0, &opt_code))
|
|
pon_rr = magic[i].func(opt_code);
|
|
}
|
|
|
|
goto __done;
|
|
}
|
|
|
|
__sec_debug_set_restart_reason(RESTART_REASON_REBOOT);
|
|
|
|
return;
|
|
|
|
__done:
|
|
if (pon_rr != PON_RESTART_REASON_NOT_HANDLE) {
|
|
if (sec_nvmem_pon_write)
|
|
sec_nvmem_pon_write(pon_rr);
|
|
else
|
|
qpnp_pon_set_restart_reason(pon_rr);
|
|
}
|
|
if (sec_rr != RESTART_REASON_NOT_HANDLE)
|
|
__sec_debug_set_restart_reason(sec_rr);
|
|
__pr_err("(%s) restart_reason = 0x%x(0x%x)\n",
|
|
__func__, sec_rr, pon_rr);
|
|
}
|
|
|
|
void sec_debug_set_upload_cause(enum sec_debug_upload_cause_t type)
|
|
{
|
|
if (unlikely(!upload_cause)) {
|
|
pr_err("upload cause address unmapped.\n");
|
|
} else {
|
|
int cpu = get_cpu();
|
|
per_cpu(sec_debug_upload_cause, cpu) = type;
|
|
__raw_writel(type, upload_cause);
|
|
put_cpu();
|
|
|
|
pr_emerg("%x\n", type);
|
|
}
|
|
}
|
|
|
|
enum sec_debug_upload_cause_t sec_debug_get_upload_cause(void)
|
|
{
|
|
if (unlikely(!upload_cause)) {
|
|
pr_err("upload cause address unmapped.\n");
|
|
return UPLOAD_CAUSE_INIT;
|
|
}
|
|
|
|
return readl(upload_cause);
|
|
}
|
|
|
|
#ifdef CONFIG_SEC_PERIPHERAL_SECURE_CHK
|
|
void sec_peripheral_secure_check_fail(void)
|
|
{
|
|
if (!sec_debug_is_enabled()) {
|
|
sec_debug_set_qc_dload_magic(0);
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,4,0)
|
|
sec_debug_update_restart_reason("peripheral_hw_reset", 0, RESTART_NORMAL);
|
|
#endif
|
|
sec_debug_pm_restart("peripheral_hw_reset");
|
|
/* never reach here */
|
|
}
|
|
|
|
panic("subsys - modem secure check fail");
|
|
}
|
|
|
|
void sec_modem_loading_fail_to_bootloader(void)
|
|
{
|
|
if (!sec_debug_is_enabled()) {
|
|
sec_debug_set_qc_dload_magic(0);
|
|
sec_debug_pm_restart("peripheral_hw_reset");
|
|
/* never reach here */
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_SEC_USER_RESET_DEBUG
|
|
static inline void sec_debug_store_backtrace(void)
|
|
{
|
|
unsigned long flags;
|
|
|
|
local_irq_save(flags);
|
|
sec_debug_backtrace();
|
|
local_irq_restore(flags);
|
|
}
|
|
#endif /* CONFIG_SEC_USER_RESET_DEBUG */
|
|
|
|
enum sec_debug_strncmp_func {
|
|
SEC_STRNCMP = 0,
|
|
SEC_STRNSTR,
|
|
SEC_STRNCASECMP,
|
|
};
|
|
|
|
static inline bool __sec_debug_strncmp(const char *s1, const char *s2,
|
|
size_t len, enum sec_debug_strncmp_func func)
|
|
{
|
|
switch (func) {
|
|
case SEC_STRNCMP:
|
|
return !strncmp(s1, s2, len);
|
|
case SEC_STRNSTR:
|
|
return !!strnstr(s1, s2, len);
|
|
case SEC_STRNCASECMP:
|
|
return !strncasecmp(s1, s2, len);
|
|
}
|
|
|
|
pr_warn("%d is not a valid strncmp function!\n", (int)func);
|
|
|
|
return false;
|
|
}
|
|
|
|
struct __upload_cause {
|
|
const char *msg;
|
|
enum sec_debug_upload_cause_t type;
|
|
enum sec_debug_strncmp_func func;
|
|
};
|
|
|
|
struct __upload_cause upload_cause_st[] = {
|
|
{ UPLOAD_MSG_USER_FAULT, UPLOAD_CAUSE_USER_FAULT, SEC_STRNCMP },
|
|
{ UPLOAD_MSG_CRASH_KEY, UPLOAD_CAUSE_FORCED_UPLOAD, SEC_STRNCMP },
|
|
{ UPLOAD_MSG_USER_CRASH_KEY, UPLOAD_CAUSE_USER_FORCED_UPLOAD, SEC_STRNCMP },
|
|
{ UPLOAD_MSG_LONG_KEY_PRESS, UPLOAD_CAUSE_POWER_LONG_PRESS, SEC_STRNCMP },
|
|
{ UPLOAD_MSG_PF_WD_BITE, UPLOAD_CAUSE_PF_WD_BITE, SEC_STRNSTR },
|
|
{ UPLOAD_MSG_PF_WD_INIT_FAIL, UPLOAD_CAUSE_PF_WD_INIT_FAIL, SEC_STRNCMP },
|
|
{ UPLOAD_MSG_PF_WD_RESTART_FAIL, UPLOAD_CAUSE_PF_WD_RESTART_FAIL, SEC_STRNCMP },
|
|
{ UPLOAD_MSG_PF_WD_KICK_FAIL, UPLOAD_CAUSE_PF_WD_KICK_FAIL, SEC_STRNCMP },
|
|
{ "taking too long", UPLOAD_CAUSE_SUBSYS_IF_TIMEOUT, SEC_STRNSTR },
|
|
{ "CP Crash", UPLOAD_CAUSE_CP_ERROR_FATAL, SEC_STRNCMP },
|
|
{ "adsp", UPLOAD_CAUSE_ADSP_ERROR_FATAL, SEC_STRNSTR },
|
|
{ "slpi", UPLOAD_CAUSE_SLPI_ERROR_FATAL, SEC_STRNSTR },
|
|
{ "spss", UPLOAD_CAUSE_SPSS_ERROR_FATAL, SEC_STRNSTR },
|
|
{ "npu", UPLOAD_CAUSE_NPU_ERROR_FATAL, SEC_STRNSTR },
|
|
{ "cdsp", UPLOAD_CAUSE_CDSP_ERROR_FATAL, SEC_STRNSTR },
|
|
{ "MDM Crash", UPLOAD_CAUSE_MDM_ERROR_FATAL, SEC_STRNCMP },
|
|
{ "unrecoverable external_modem", UPLOAD_CAUSE_MDM_CRITICAL_FATAL, SEC_STRNSTR },
|
|
{ "external_modem", UPLOAD_CAUSE_MDM_ERROR_FATAL, SEC_STRNSTR },
|
|
{ "esoc0 crashed", UPLOAD_CAUSE_MDM_ERROR_FATAL, SEC_STRNSTR },
|
|
{ "modem", UPLOAD_CAUSE_MODEM_RST_ERR, SEC_STRNSTR },
|
|
{ "riva", UPLOAD_CAUSE_RIVA_RST_ERR, SEC_STRNSTR },
|
|
{ "lpass", UPLOAD_CAUSE_LPASS_RST_ERR, SEC_STRNSTR },
|
|
{ "dsps", UPLOAD_CAUSE_DSPS_RST_ERR, SEC_STRNSTR },
|
|
{ "subsys", UPLOAD_CAUSE_PERIPHERAL_ERR, SEC_STRNCASECMP },
|
|
{ "SMPL", UPLOAD_CAUSE_SMPL, SEC_STRNSTR },
|
|
#if defined(CONFIG_SEC_QUEST)
|
|
{ "crypto_test", UPLOAD_CAUSE_QUEST_CRYPTO, SEC_STRNCMP },
|
|
{ "icache_test", UPLOAD_CAUSE_QUEST_ICACHE, SEC_STRNCMP },
|
|
{ "ccoherency_test", UPLOAD_CAUSE_QUEST_CACHECOHERENCY, SEC_STRNCMP },
|
|
{ "suspend_test", UPLOAD_CAUSE_QUEST_SUSPEND, SEC_STRNCMP },
|
|
{ "vddmin_test", UPLOAD_CAUSE_QUEST_VDDMIN, SEC_STRNCMP },
|
|
{ "qmesa_ddr_test", UPLOAD_CAUSE_QUEST_QMESADDR, SEC_STRNCMP },
|
|
{ "qmesa_cache_test", UPLOAD_CAUSE_QUEST_QMESACACHE, SEC_STRNCMP },
|
|
{ "pmic_test", UPLOAD_CAUSE_QUEST_PMIC, SEC_STRNCMP },
|
|
{ "ufs_test", UPLOAD_CAUSE_QUEST_UFS, SEC_STRNCMP },
|
|
{ "sdcard_test", UPLOAD_CAUSE_QUEST_SDCARD, SEC_STRNCMP },
|
|
{ "sensor_test", UPLOAD_CAUSE_QUEST_SENSOR, SEC_STRNCMP },
|
|
{ "sensorprobe_test", UPLOAD_CAUSE_QUEST_SENSORPROBE, SEC_STRNCMP },
|
|
{ "naturescene_test", UPLOAD_CAUSE_QUEST_NATURESCENE, SEC_STRNCMP },
|
|
{ "a75g_test", UPLOAD_CAUSE_QUEST_A75G, SEC_STRNCMP },
|
|
{ "q65g_test", UPLOAD_CAUSE_QUEST_Q65G, SEC_STRNCMP },
|
|
{ "thermal_test", UPLOAD_CAUSE_QUEST_THERMAL, SEC_STRNCMP },
|
|
{ "qdaf_fail", UPLOAD_CAUSE_QUEST_QDAF_FAIL, SEC_STRNCMP },
|
|
{ "zip_unzip_test", UPLOAD_CAUSE_QUEST_ZIP_UNZIP, SEC_STRNCMP },
|
|
{ "quest_fail", UPLOAD_CAUSE_QUEST_FAIL, SEC_STRNCMP },
|
|
{ "aoss_thermal_diff", UPLOAD_CAUSE_QUEST_AOSSTHERMALDIFF, SEC_STRNCMP },
|
|
{ "stressapptest_test", UPLOAD_CAUSE_QUEST_STRESSAPPTEST, SEC_STRNCMP },
|
|
#endif
|
|
};
|
|
|
|
void sec_debug_upload_cause_str(enum sec_debug_upload_cause_t type,
|
|
char *str, size_t len)
|
|
{
|
|
size_t i;
|
|
|
|
if (type == UPLOAD_CAUSE_KERNEL_PANIC)
|
|
strlcpy(str, "kernel_panic", len);
|
|
else if (type == UPLOAD_CAUSE_INIT)
|
|
strlcpy(str, "unknown_error", len);
|
|
else if (type == UPLOAD_CAUSE_NON_SECURE_WDOG_BARK)
|
|
strlcpy(str, "watchdog_bark", len);
|
|
else {
|
|
for (i = 0; i < ARRAY_SIZE(upload_cause_st); i++) {
|
|
if (type == upload_cause_st[i].type) {
|
|
snprintf(str, len, "%s", upload_cause_st[i].msg);
|
|
return;
|
|
}
|
|
}
|
|
strlcpy(str, "unknown_reset", len);
|
|
}
|
|
}
|
|
|
|
static bool sec_debug_platform_lockup_suspected(char *panic_msg)
|
|
{
|
|
if (!strcmp(panic_msg, UPLOAD_MSG_CRASH_KEY) ||
|
|
!strcmp(panic_msg, UPLOAD_MSG_USER_CRASH_KEY) ||
|
|
!strcmp(panic_msg, UPLOAD_MSG_LONG_KEY_PRESS) ||
|
|
!strncmp(panic_msg, UPLOAD_MSG_PF_WD_BITE, strlen(UPLOAD_MSG_PF_WD_BITE)) ||
|
|
!strcmp(panic_msg, UPLOAD_MSG_PF_WD_INIT_FAIL) ||
|
|
!strcmp(panic_msg, UPLOAD_MSG_PF_WD_RESTART_FAIL) ||
|
|
!strcmp(panic_msg, UPLOAD_MSG_PF_WD_KICK_FAIL))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
static int sec_debug_panic_handler(struct notifier_block *nb,
|
|
unsigned long l, void *buf)
|
|
{
|
|
#define MAX_STR_LEN 80
|
|
size_t len, i;
|
|
|
|
emerg_pet_watchdog(); /* CTC-should be modify */
|
|
#ifdef CONFIG_SEC_USER_RESET_DEBUG
|
|
sec_debug_store_backtrace();
|
|
#endif
|
|
sec_debug_set_upload_magic(RESTART_REASON_SEC_DEBUG_MODE);
|
|
|
|
__pr_err("%s :%s\n", __func__, (char *)buf);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(upload_cause_st); i++) {
|
|
len = strnlen(buf, MAX_STR_LEN);
|
|
if (__sec_debug_strncmp(buf, upload_cause_st[i].msg, len,
|
|
upload_cause_st[i].func)) {
|
|
sec_debug_set_upload_cause(upload_cause_st[i].type);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == ARRAY_SIZE(upload_cause_st))
|
|
sec_debug_set_upload_cause(UPLOAD_CAUSE_KERNEL_PANIC);
|
|
|
|
if (!sec_debug_is_enabled()) {
|
|
#ifdef CONFIG_SEC_DEBUG_LOW_LOG
|
|
__sec_debug_hw_reset();
|
|
#endif
|
|
/* SEC will get reset_summary.html in debug low.
|
|
* reset_summary.html need more information about abnormal reset
|
|
* or kernel panic.
|
|
* So we skip as below
|
|
*/
|
|
/* return -EPERM; */
|
|
}
|
|
|
|
/* enable after SSR feature */
|
|
/* ssr_panic_handler_for_sec_dbg(); */
|
|
|
|
/* platform lockup suspected, it needs more info */
|
|
if (sec_debug_platform_lockup_suspected((char *)buf)) {
|
|
show_state_filter(TASK_UNINTERRUPTIBLE);
|
|
dump_memory_info();
|
|
dump_cpu_stat();
|
|
}
|
|
|
|
/* save context here so that function call after this point doesn't
|
|
* corrupt stacks below the saved sp
|
|
*/
|
|
sec_debug_save_context();
|
|
__sec_debug_hw_reset();
|
|
|
|
return 0;
|
|
}
|
|
|
|
void sec_debug_prepare_for_wdog_bark_reset(void)
|
|
{
|
|
#ifndef CONFIG_SAMSUNG_PRODUCT_SHIP
|
|
sec_delay_check = 0;
|
|
#endif
|
|
sec_debug_set_upload_magic(RESTART_REASON_SEC_DEBUG_MODE);
|
|
sec_debug_set_upload_cause(UPLOAD_CAUSE_NON_SECURE_WDOG_BARK);
|
|
}
|
|
|
|
static struct notifier_block nb_reboot_block = {
|
|
.notifier_call = sec_debug_normal_reboot_handler,
|
|
};
|
|
|
|
static struct notifier_block nb_panic_block = {
|
|
.notifier_call = sec_debug_panic_handler,
|
|
.priority = -1,
|
|
};
|
|
|
|
#ifdef CONFIG_OF
|
|
static int __init __sec_debug_dt_addr_init(void)
|
|
{
|
|
struct device_node *np;
|
|
|
|
/* Using bottom of sec_dbg DDR address range
|
|
* for writing restart reason
|
|
*/
|
|
np = of_find_compatible_node(NULL, NULL,
|
|
"qcom,msm-imem-restart_reason");
|
|
if (unlikely(!np)) {
|
|
pr_err("unable to find DT imem restart reason node\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
qcom_restart_reason = of_iomap(np, 0);
|
|
if (unlikely(!qcom_restart_reason)) {
|
|
pr_err("unable to map imem restart reason offset\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
/* check restart_reason address here */
|
|
pr_emerg("restart_reason addr : 0x%p(0x%llx)\n",
|
|
qcom_restart_reason,
|
|
(unsigned long long)virt_to_phys(qcom_restart_reason));
|
|
|
|
/* Using bottom of sec_dbg DDR address range for writing upload_cause */
|
|
np = of_find_compatible_node(NULL, NULL, "qcom,msm-imem-upload_cause");
|
|
if (unlikely(!np)) {
|
|
pr_err("unable to find DT imem upload cause node\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
upload_cause = of_iomap(np, 0);
|
|
if (unlikely(!upload_cause)) {
|
|
pr_err("unable to map imem upload_cause offset\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
/* check upload_cause here */
|
|
pr_emerg("upload_cause addr : 0x%p(0x%llx)\n", upload_cause,
|
|
(unsigned long long)virt_to_phys(upload_cause));
|
|
|
|
#if IS_ENABLED(CONFIG_POWER_RESET_QCOM_DOWNLOAD_MODE)
|
|
np = of_find_compatible_node(NULL, NULL, "qcom,msm-watchdog");
|
|
if (unlikely(!np)) {
|
|
pr_err("unable to find DT qcom,msm-watchdog node\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
if (of_device_is_available(np)) {
|
|
watchdog_base = of_iomap(np, 0);
|
|
if (unlikely(!watchdog_base)) {
|
|
pr_err("unable to map watchdog_base offset\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
/* check upload_cause here */
|
|
pr_emerg("watchdog_base addr : 0x%p(0x%llx)\n", watchdog_base,
|
|
(unsigned long long)virt_to_phys(watchdog_base));
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
#else /* CONFIG_OF */
|
|
static int __init __sec_debug_dt_addr_init(void) { return 0; }
|
|
#endif /* CONFIG_OF */
|
|
|
|
static int __init force_upload_setup(char *en)
|
|
{
|
|
get_option(&en, &force_upload);
|
|
return 0;
|
|
}
|
|
early_param("androidboot.force_upload", force_upload_setup);
|
|
|
|
/* for sec debug level */
|
|
static int __init sec_debug_level_setup(char *str)
|
|
{
|
|
get_option(&str, &sec_dbg_level);
|
|
return 0;
|
|
}
|
|
early_param("androidboot.debug_level", sec_debug_level_setup);
|
|
|
|
static int __init sec_debug_init(void)
|
|
{
|
|
int ret;
|
|
|
|
ret = __sec_debug_dt_addr_init();
|
|
if (unlikely(ret < 0))
|
|
return ret;
|
|
|
|
register_reboot_notifier(&nb_reboot_block);
|
|
atomic_notifier_chain_register(&panic_notifier_list, &nb_panic_block);
|
|
|
|
sec_debug_set_upload_magic(RESTART_REASON_SEC_DEBUG_MODE);
|
|
sec_debug_set_upload_cause(UPLOAD_CAUSE_INIT);
|
|
|
|
/* TODO: below code caused reboot fail when debug level LOW */
|
|
switch (sec_dbg_level) {
|
|
case ANDROID_DEBUG_LEVEL_LOW:
|
|
#ifdef CONFIG_SEC_FACTORY
|
|
case ANDROID_DEBUG_LEVEL_MID:
|
|
#endif
|
|
|
|
#if defined(CONFIG_ARCH_ATOLL) || defined(CONFIG_ARCH_SEC_SM7150)
|
|
if (!force_upload)
|
|
qcom_scm_disable_sdi();
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
#ifdef CONFIG_SEC_LOG_STORE_LAST_KMSG
|
|
if (reboot_multicmd)
|
|
reboot_multicmd = 1;
|
|
else
|
|
reboot_multicmd = 0;
|
|
#else
|
|
reboot_multicmd = 0;
|
|
#endif
|
|
return 0;
|
|
}
|
|
arch_initcall_sync(sec_debug_init);
|
|
|
|
bool sec_debug_is_enabled(void)
|
|
{
|
|
switch (sec_dbg_level) {
|
|
case ANDROID_DEBUG_LEVEL_LOW:
|
|
#ifdef CONFIG_SEC_FACTORY
|
|
case ANDROID_DEBUG_LEVEL_MID:
|
|
#endif
|
|
return !!(force_upload);
|
|
}
|
|
|
|
return !!(enable);
|
|
}
|
|
|
|
unsigned int sec_debug_level(void)
|
|
{
|
|
return sec_dbg_level;
|
|
}
|
|
|
|
#ifdef CONFIG_SEC_SSR_DEBUG_LEVEL_CHK
|
|
int sec_debug_is_enabled_for_ssr(void)
|
|
{
|
|
return enable_cp_debug;
|
|
}
|
|
#endif
|
|
|
|
static inline void __dump_one_task_info(struct task_struct *tsk,
|
|
bool is_process)
|
|
{
|
|
char stat_array[] = { 'R', 'S', 'D' };
|
|
char stat_ch;
|
|
|
|
stat_ch = tsk->state <= TASK_UNINTERRUPTIBLE ?
|
|
stat_array[tsk->state] : '?';
|
|
__pr_info("%8d %8llu %8llu %16llu %c (%ld) %px %c %s\n",
|
|
tsk->pid, (unsigned long long)tsk->utime,
|
|
(unsigned long long)tsk->stime,
|
|
tsk->se.exec_start, stat_ch, tsk->state,
|
|
tsk, is_process ? '*' : ' ', tsk->comm);
|
|
|
|
if (tsk->state == TASK_RUNNING || tsk->state == TASK_UNINTERRUPTIBLE)
|
|
show_stack(tsk, NULL);
|
|
}
|
|
|
|
#define __HLINE_LEFT " -------------------------------------------"
|
|
#define __HLINE_RIGHT "--------------------------------------------\n"
|
|
|
|
void dump_memory_info(void)
|
|
{
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)
|
|
show_mem(0, NULL);
|
|
#else
|
|
show_mem(0);
|
|
#endif
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0)
|
|
dump_tasks(NULL, NULL);
|
|
#endif
|
|
}
|
|
|
|
void dump_all_task_info(void)
|
|
{
|
|
struct task_struct *p;
|
|
struct task_struct *t;
|
|
|
|
__pr_info("\n");
|
|
__pr_info(" current proc : %d %s\n",
|
|
current->pid, current->comm);
|
|
__pr_info(__HLINE_LEFT __HLINE_RIGHT);
|
|
__pr_info("%8s %8s %8s %16s %5s %s\n",
|
|
"pid", "uTime", "sTime", "exec(ns)",
|
|
"stat", "task_struct");
|
|
__pr_info(__HLINE_LEFT __HLINE_RIGHT);
|
|
|
|
for_each_process_thread(p, t) {
|
|
__dump_one_task_info(t, p == t);
|
|
}
|
|
|
|
__pr_info(__HLINE_LEFT __HLINE_RIGHT);
|
|
}
|
|
|
|
/* TODO: this is a modified version of 'show_stat' in 'fs/proc/stat.c'
|
|
* this function should be adapted for each kernel version
|
|
*/
|
|
#ifndef arch_irq_stat_cpu
|
|
#define arch_irq_stat_cpu(cpu) 0
|
|
#endif
|
|
#ifndef arch_irq_stat
|
|
#define arch_irq_stat() 0
|
|
#endif
|
|
|
|
void dump_cpu_stat(void)
|
|
{
|
|
int i, j;
|
|
u64 user, nice, system, idle, iowait, irq, softirq, steal;
|
|
u64 guest, guest_nice;
|
|
u64 sum = 0;
|
|
u64 sum_softirq = 0;
|
|
unsigned int per_softirq_sums[NR_SOFTIRQS] = {0};
|
|
struct timespec64 boottime;
|
|
|
|
user = nice = system = idle = iowait =
|
|
irq = softirq = steal = 0;
|
|
guest = guest_nice = 0;
|
|
getboottime64(&boottime);
|
|
|
|
for_each_present_cpu(i) {
|
|
BUG_ON(i >= NR_CPUS);
|
|
|
|
user += kcpustat_cpu(i).cpustat[CPUTIME_USER];
|
|
nice += kcpustat_cpu(i).cpustat[CPUTIME_NICE];
|
|
system += kcpustat_cpu(i).cpustat[CPUTIME_SYSTEM];
|
|
idle += kcpustat_cpu(i).cpustat[CPUTIME_IDLE];
|
|
iowait += kcpustat_cpu(i).cpustat[CPUTIME_IOWAIT];
|
|
irq += kcpustat_cpu(i).cpustat[CPUTIME_IRQ];
|
|
softirq += kcpustat_cpu(i).cpustat[CPUTIME_SOFTIRQ];
|
|
steal += kcpustat_cpu(i).cpustat[CPUTIME_STEAL];
|
|
guest += kcpustat_cpu(i).cpustat[CPUTIME_GUEST];
|
|
guest_nice += kcpustat_cpu(i).cpustat[CPUTIME_GUEST_NICE];
|
|
sum += kstat_cpu_irqs_sum(i);
|
|
sum += arch_irq_stat_cpu(i);
|
|
|
|
for (j = 0; j < NR_SOFTIRQS; j++) {
|
|
unsigned int softirq_stat = kstat_softirqs_cpu(j, i);
|
|
|
|
per_softirq_sums[j] += softirq_stat;
|
|
sum_softirq += softirq_stat;
|
|
}
|
|
}
|
|
sum += arch_irq_stat();
|
|
|
|
__pr_info("\n");
|
|
__pr_info(__HLINE_LEFT __HLINE_RIGHT);
|
|
__pr_info(" %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s\n",
|
|
"user", "nice", "system", "idle", "iowait", "irq",
|
|
"softirq", "steal", "guest", "guest_nice");
|
|
__pr_info("cpu %8llu %8llu %8llu %8llu %8llu %8llu %8llu %8llu %8llu %8llu\n",
|
|
nsec_to_clock_t(user),
|
|
nsec_to_clock_t(nice),
|
|
nsec_to_clock_t(system),
|
|
nsec_to_clock_t(idle),
|
|
nsec_to_clock_t(iowait),
|
|
nsec_to_clock_t(irq),
|
|
nsec_to_clock_t(softirq),
|
|
nsec_to_clock_t(steal),
|
|
nsec_to_clock_t(guest),
|
|
nsec_to_clock_t(guest_nice));
|
|
|
|
for_each_online_cpu(i) {
|
|
/* Copy values here to work around gcc-2.95.3, gcc-2.96 */
|
|
user = kcpustat_cpu(i).cpustat[CPUTIME_USER];
|
|
nice = kcpustat_cpu(i).cpustat[CPUTIME_NICE];
|
|
system = kcpustat_cpu(i).cpustat[CPUTIME_SYSTEM];
|
|
idle = kcpustat_cpu(i).cpustat[CPUTIME_IDLE];
|
|
iowait = kcpustat_cpu(i).cpustat[CPUTIME_IOWAIT];
|
|
irq = kcpustat_cpu(i).cpustat[CPUTIME_IRQ];
|
|
softirq = kcpustat_cpu(i).cpustat[CPUTIME_SOFTIRQ];
|
|
steal = kcpustat_cpu(i).cpustat[CPUTIME_STEAL];
|
|
guest = kcpustat_cpu(i).cpustat[CPUTIME_GUEST];
|
|
guest_nice = kcpustat_cpu(i).cpustat[CPUTIME_GUEST_NICE];
|
|
__pr_info("cpu%-2d %8llu %8llu %8llu %8llu %8llu %8llu %8llu %8llu %8llu %8llu\n",
|
|
i,
|
|
nsec_to_clock_t(user),
|
|
nsec_to_clock_t(nice),
|
|
nsec_to_clock_t(system),
|
|
nsec_to_clock_t(idle),
|
|
nsec_to_clock_t(iowait),
|
|
nsec_to_clock_t(irq),
|
|
nsec_to_clock_t(softirq),
|
|
nsec_to_clock_t(steal),
|
|
nsec_to_clock_t(guest),
|
|
nsec_to_clock_t(guest_nice));
|
|
}
|
|
|
|
__pr_info(__HLINE_LEFT __HLINE_RIGHT);
|
|
__pr_info("intr %llu\n", (unsigned long long)sum);
|
|
|
|
/* sum again ? it could be updated? */
|
|
for_each_irq_nr(j)
|
|
if (kstat_irqs(j))
|
|
__pr_info(" irq-%d : %u\n", j, kstat_irqs(j));
|
|
|
|
__pr_info(__HLINE_LEFT __HLINE_RIGHT);
|
|
__pr_info("\nctxt %llu\n"
|
|
"btime %llu\n"
|
|
"processes %lu\n"
|
|
"procs_running %lu\n"
|
|
"procs_blocked %lu\n",
|
|
nr_context_switches(),
|
|
(unsigned long long)boottime.tv_sec,
|
|
total_forks,
|
|
nr_running(),
|
|
nr_iowait());
|
|
|
|
__pr_info(__HLINE_LEFT __HLINE_RIGHT);
|
|
__pr_info("softirq %llu\n", (unsigned long long)sum_softirq);
|
|
|
|
for (i = 0; i < NR_SOFTIRQS; i++)
|
|
__pr_info(" softirq-%d : %u\n", i, per_softirq_sums[i]);
|
|
__pr_info("\n");
|
|
|
|
__pr_info(__HLINE_LEFT __HLINE_RIGHT);
|
|
}
|
|
|
|
char *erased_command_line;
|
|
|
|
char *__init sec_debug_get_erased_command_line(void)
|
|
{
|
|
size_t cmdline_len;
|
|
size_t len;
|
|
char *token_begin, *token_end, *to_be_zero;
|
|
const char *to_be_deleted[] = {
|
|
"ap_serial=0x",
|
|
"serialno=",
|
|
"em.did=",
|
|
"androidboot.un=W",
|
|
"androidboot.un=H",
|
|
};
|
|
size_t i;
|
|
|
|
if (erased_command_line)
|
|
return erased_command_line;
|
|
|
|
cmdline_len = strlen(boot_command_line) + 1;
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,4,0)
|
|
erased_command_line = memblock_alloc(cmdline_len, SMP_CACHE_BYTES);
|
|
#else
|
|
erased_command_line = memblock_virt_alloc(cmdline_len, 0);
|
|
#endif
|
|
strlcpy(erased_command_line, saved_command_line, cmdline_len);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(to_be_deleted); i++) {
|
|
len = strlen(to_be_deleted[i]);
|
|
token_begin = strstr(erased_command_line,
|
|
to_be_deleted[i]);
|
|
if (!token_begin)
|
|
continue;
|
|
|
|
token_end = strstr(token_begin, " ");
|
|
if (!token_end) /* last command line option */
|
|
token_end = &(erased_command_line[cmdline_len - 1]);
|
|
to_be_zero = &(token_begin[len]);
|
|
while (to_be_zero < token_end)
|
|
*to_be_zero++ = '0';
|
|
}
|
|
|
|
return erased_command_line;
|
|
}
|
|
|
|
/* FIXME: this variable is not referenced anywhere */
|
|
static unsigned int runtime_debug_val;
|
|
module_param_named(runtime_debug_val, runtime_debug_val, uint, 0644);
|
|
|
|
#ifdef CONFIG_SEC_FILE_LEAK_DEBUG
|
|
static inline int __sec_debug_print_file_list(void)
|
|
{
|
|
size_t i;
|
|
unsigned int nCnt;
|
|
struct file *file;
|
|
struct files_struct *files = current->files;
|
|
const char *pRootName;
|
|
const char *pFileName;
|
|
int ret = 0;
|
|
|
|
nCnt = files->fdt->max_fds;
|
|
|
|
pr_err(" [Opened file list of process %s(PID:%d, TGID:%d) :: %d]\n",
|
|
current->group_leader->comm, current->pid, current->tgid, nCnt);
|
|
|
|
for (i = 0; i < nCnt; i++) {
|
|
rcu_read_lock();
|
|
file = fcheck_files(files, i);
|
|
|
|
pRootName = NULL;
|
|
pFileName = NULL;
|
|
|
|
if (file) {
|
|
if (file->f_path.mnt &&
|
|
file->f_path.mnt->mnt_root &&
|
|
file->f_path.mnt->mnt_root->d_name.name)
|
|
pRootName =
|
|
file->f_path.mnt->mnt_root->d_name.name;
|
|
|
|
if (file->f_path.dentry &&
|
|
file->f_path.dentry->d_name.name)
|
|
pFileName = file->f_path.dentry->d_name.name;
|
|
|
|
pr_err("[%04zd]%s%s\n", i,
|
|
pRootName ? pRootName : "null",
|
|
pFileName ? pFileName : "null");
|
|
ret++;
|
|
}
|
|
rcu_read_unlock();
|
|
}
|
|
|
|
return (ret == nCnt) ? 1 : 0;
|
|
}
|
|
|
|
/* FIXME: this function is not referenced anywhere */
|
|
void __deprecated sec_debug_EMFILE_error_proc(void)
|
|
{
|
|
pr_err("Too many open files(%d:%s)\n",
|
|
current->tgid, current->group_leader->comm);
|
|
|
|
if (!sec_debug_is_enabled())
|
|
return;
|
|
|
|
/* We check EMFILE error in only "system_server",
|
|
* "mediaserver" and "surfaceflinger" process.
|
|
*/
|
|
if (!strncmp(current->group_leader->comm,
|
|
"system_server", ARRAY_SIZE("system_server")) ||
|
|
!strncmp(current->group_leader->comm,
|
|
"mediaserver", ARRAY_SIZE("mediaserver")) ||
|
|
!strncmp(current->group_leader->comm,
|
|
"surfaceflinger", ARRAY_SIZE("surfaceflinger"))) {
|
|
if (__sec_debug_print_file_list() == 1)
|
|
panic("Too many open files");
|
|
}
|
|
}
|
|
#endif /* CONFIG_SEC_FILE_LEAK_DEBUG */
|
|
|
|
/* FIXME: this function is not referenced anywhere */
|
|
void __deprecated sec_debug_print_model(struct seq_file *m,
|
|
const char *cpu_name)
|
|
{
|
|
u32 cpuid = read_cpuid_id();
|
|
|
|
seq_printf(m, "model name\t: %s rev %d (%s)\n",
|
|
cpu_name, cpuid & 15, ELF_PLATFORM);
|
|
}
|
|
|
|
/* FIXME: this function is not referenced anywhere */
|
|
void __deprecated sec_debug_set_thermal_upload(void)
|
|
{
|
|
pr_emerg("set thermal upload cause\n");
|
|
sec_debug_set_upload_magic(0x776655ee);
|
|
sec_debug_set_upload_cause(UPLOAD_CAUSE_POWER_THERMAL_RESET);
|
|
}
|
|
|