diff --git a/Kconfig b/Kconfig index d9f60a40..1b3a174e 100644 --- a/Kconfig +++ b/Kconfig @@ -63,6 +63,8 @@ source "kernel/common/Kconfig" source "kernel/common/patchfs/Kconfig" ######################### config options of blackbox ##################### source "kernel/common/blackbox/Kconfig" +######################### config options of hidumper ##################### +source "kernel/common/hidumper/Kconfig" config QUICK_START bool "Enable QUICK_START" diff --git a/kernel/common/hidumper/Kconfig b/kernel/common/hidumper/Kconfig new file mode 100644 index 00000000..b15d50a8 --- /dev/null +++ b/kernel/common/hidumper/Kconfig @@ -0,0 +1,5 @@ +config HIDUMPER + bool "Enable hidumper" + default n + help + Answer Y to enable LiteOS support hidumper diff --git a/kernel/common/hidumper/Makefile b/kernel/common/hidumper/Makefile new file mode 100644 index 00000000..230c1d8a --- /dev/null +++ b/kernel/common/hidumper/Makefile @@ -0,0 +1,13 @@ +include $(LITEOSTOPDIR)/config.mk + +MODULE_NAME := $(notdir $(shell pwd)) + +LOCAL_SRCS := $(wildcard *.c) + +LOCAL_INCLUDE := \ + -I $(LITEOSTOPDIR)/kernel/common \ + -I $(LITEOSTOPDIR)/kernel/common/hidumper \ + +LOCAL_FLAGS := $(LOCAL_INCLUDE) $(LITEOS_GCOV_OPTS) + +include $(MODULE) diff --git a/kernel/common/hidumper/los_hidumper.c b/kernel/common/hidumper/los_hidumper.c new file mode 100644 index 00000000..d04647db --- /dev/null +++ b/kernel/common/hidumper/los_hidumper.c @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2021-2021 Huawei Device Co., Ltd. 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. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * 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. + */ + +/* ------------ includes ------------ */ +#include "los_hidumper.h" +#ifdef LOSCFG_BLACKBOX +#include "los_blackbox.h" +#endif +#ifdef LOSCFG_CPUP_INCLUDE_IRQ +#include "los_cpup_pri.h" +#endif +#include "los_hwi_pri.h" +#include "los_init.h" +#include "los_mp.h" +#include "los_mux.h" +#include "los_printf.h" +#include "los_process_pri.h" +#include "los_task_pri.h" +#include "los_vm_dump.h" +#include "los_vm_lock.h" +#include "los_vm_map.h" +#ifdef LOSCFG_FS_VFS +#include "fs/file.h" +#endif +#include "fs/driver.h" +#include "securec.h" +#ifdef LOSCFG_LIB_LIBC +#include "unistd.h" +#endif +#include "user_copy.h" + +/* ------------ local macroes ------------ */ +#define CPUP_TYPE_COUNT 3 +#define HIDUMPER_DEVICE "/dev/hidumper" +#define HIDUMPER_DEVICE_MODE 0666 +#define KERNEL_FAULT_ADDR 0x1 +#define KERNEL_FAULT_VALUE 0x2 +#define READ_BUF_SIZE 128 +#define SYS_INFO_HEADER "************ sys info ***********" +#define CPU_USAGE_HEADER "************ cpu usage ***********" +#define MEM_USAGE_HEADER "************ mem usage ***********" +#define PAGE_USAGE_HEADER "************ physical page usage ***********" +#define TASK_INFO_HEADER "************ task info ***********" +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) +#endif +#define REPLACE_INTERFACE(dst, src, type, func) {\ + if (((type *)src)->func != NULL) {\ + ((type *)dst)->func = ((type *)src)->func;\ + } else {\ + PRINT_ERR("%s->%s is NULL!\n", #src, #func);\ + }\ +} +#define INVOKE_INTERFACE(adapter, type, func) {\ + if (((type *)adapter)->func != NULL) {\ + ((type *)adapter)->func();\ + } else {\ + PRINT_ERR("%s->%s is NULL!\n", #adapter, #func);\ + }\ +} + +/* ------------ local prototypes ------------ */ +/* ------------ local function declarations ------------ */ +STATIC INT32 HiDumperOpen(struct file *filep); +STATIC INT32 HiDumperClose(struct file *filep); +STATIC INT32 HiDumperIoctl(struct file *filep, INT32 cmd, unsigned long arg); + +/* ------------ global function declarations ------------ */ +#ifdef LOSCFG_SHELL +extern VOID OsShellCmdSystemInfoGet(VOID); +extern UINT32 OsShellCmdFree(INT32 argc, const CHAR *argv[]); +extern UINT32 OsShellCmdUname(INT32 argc, const CHAR *argv[]); +extern UINT32 OsShellCmdDumpPmm(VOID); +#endif + +/* ------------ local variables ------------ */ +static struct HiDumperAdapter g_adapter; +STATIC struct file_operations_vfs g_hidumperDevOps = { + HiDumperOpen, /* open */ + HiDumperClose, /* close */ + NULL, /* read */ + NULL, /* write */ + NULL, /* seek */ + HiDumperIoctl, /* ioctl */ + NULL, /* mmap */ +#ifndef CONFIG_DISABLE_POLL + NULL, /* poll */ +#endif + NULL, /* unlink */ +}; + +/* ------------ function definitions ------------ */ +STATIC INT32 HiDumperOpen(struct file *filep) +{ + (VOID)filep; + return 0; +} + +STATIC INT32 HiDumperClose(struct file *filep) +{ + (VOID)filep; + return 0; +} + +static void DumpSysInfo(void) +{ + PRINTK("\n%s\n", SYS_INFO_HEADER); +#ifdef LOSCFG_SHELL + const char *argv[1] = {"-a"}; + (VOID)OsShellCmdUname(ARRAY_SIZE(argv), &argv[0]); + (VOID)OsShellCmdSystemInfoGet(); +#else + PRINTK("\nUnsupported!\n"); +#endif +} + +#ifdef LOSCFG_KERNEL_CPUP +static void DoDumpCpuUsageUnsafe(CPUP_INFO_S *processCpupAll, + CPUP_INFO_S *processCpup10s, + CPUP_INFO_S *processCpup1s) +{ + UINT32 pid; + + PRINTK("%-32s PID CPUUSE CPUUSE10S CPUUSE1S\n", "PName"); + for (pid = 0; pid < g_processMaxNum; pid++) { + LosProcessCB *processCB = g_processCBArray + pid; + if (OsProcessIsUnused(processCB)) { + continue; + } + PRINTK("%-32s %u %5u.%1u%8u.%1u%7u.%-1u\n", + processCB->processName, processCB->processID, + processCpupAll[pid].usage / LOS_CPUP_PRECISION_MULT, + processCpupAll[pid].usage % LOS_CPUP_PRECISION_MULT, + processCpup10s[pid].usage / LOS_CPUP_PRECISION_MULT, + processCpup10s[pid].usage % LOS_CPUP_PRECISION_MULT, + processCpup1s[pid].usage / LOS_CPUP_PRECISION_MULT, + processCpup1s[pid].usage % LOS_CPUP_PRECISION_MULT); + } +} +#endif + +static void DumpCpuUsageUnsafe(void) +{ + PRINTK("\n%s\n", CPU_USAGE_HEADER); +#ifdef LOSCFG_KERNEL_CPUP + UINT32 size; + CPUP_INFO_S *processCpup = NULL; + CPUP_INFO_S *processCpupAll = NULL; + CPUP_INFO_S *processCpup10s = NULL; + CPUP_INFO_S *processCpup1s = NULL; + + size = sizeof(*processCpup) * g_processMaxNum * CPUP_TYPE_COUNT; + processCpup = LOS_MemAlloc(m_aucSysMem1, size); + if (processCpup == NULL) { + PRINT_ERR("func: %s, LOS_MemAlloc failed, Line: %d\n", __func__, __LINE__); + return; + } + processCpupAll = processCpup; + processCpup10s = processCpupAll + g_processMaxNum; + processCpup1s = processCpup10s + g_processMaxNum; + (VOID)memset_s(processCpup, size, 0, size); + LOS_GetAllProcessCpuUsage(CPUP_ALL_TIME, processCpupAll, g_processMaxNum * sizeof(CPUP_INFO_S)); + LOS_GetAllProcessCpuUsage(CPUP_LAST_TEN_SECONDS, processCpup10s, g_processMaxNum * sizeof(CPUP_INFO_S)); + LOS_GetAllProcessCpuUsage(CPUP_LAST_ONE_SECONDS, processCpup1s, g_processMaxNum * sizeof(CPUP_INFO_S)); + DoDumpCpuUsageUnsafe(processCpupAll, processCpup10s, processCpup1s); + (VOID)LOS_MemFree(m_aucSysMem1, processCpup); +#else + PRINTK("\nUnsupported!\n"); +#endif +} + +static void DumpMemUsage(void) +{ + PRINTK("\n%s\n", MEM_USAGE_HEADER); +#ifdef LOSCFG_SHELL + PRINTK("Unit: KB\n"); + const char *argv[1] = {"-k"}; + (VOID)OsShellCmdFree(ARRAY_SIZE(argv), &argv[0]); + PRINTK("%s\n", PAGE_USAGE_HEADER); + (VOID)OsShellCmdDumpPmm(); +#else + PRINTK("\nUnsupported!\n"); +#endif +} + +static void DumpTaskInfo(void) +{ + PRINTK("\n%s\n", TASK_INFO_HEADER); +#ifdef LOSCFG_SHELL + (VOID)OsShellCmdTskInfoGet(OS_ALL_TASK_MASK, NULL, OS_PROCESS_INFO_ALL); +#else + PRINTK("\nUnsupported!\n"); +#endif +} + +#ifdef LOSCFG_BLACKBOX +static void PrintFileData(INT32 fd) +{ +#ifdef LOSCFG_FS_VFS + CHAR buf[READ_BUF_SIZE]; + + if (fd < 0) { + PRINT_ERR("fd: %d!\n", fd); + return; + } + + (void)memset_s(buf, sizeof(buf), 0, sizeof(buf)); + while (read(fd, buf, sizeof(buf) - 1) > 0) { + PRINTK("%s", buf); + (void)memset_s(buf, sizeof(buf), 0, sizeof(buf)); + } +#else + (VOID)fd; + PRINT_ERR("LOSCFG_FS_VFS isn't defined!\n"); +#endif +} + +static void PrintFile(const char *filePath, const char *pHeader) +{ +#ifdef LOSCFG_FS_VFS + int fd; + + if (filePath == NULL || pHeader == NULL) { + PRINT_ERR("filePath: %p, pHeader: %p\n", filePath, pHeader); + return; + } + + fd = open(filePath, O_RDONLY); + if (fd >= 0) { + PRINTK("\n%s\n", pHeader); + PrintFileData(fd); + (void)close(fd); + } else { + PRINT_ERR("Open [%s] failed or there's no fault log!\n", filePath); + } +#else + (VOID)filePath; + (VOID)pHeader; + PRINT_ERR("LOSCFG_FS_VFS isn't defined!\n"); +#endif +} +#endif + +static void DumpFaultLog(void) +{ +#ifdef LOSCFG_BLACKBOX + PrintFile(KERNEL_FAULT_LOG_PATH, "************kernel fault info************"); + PrintFile(USER_FAULT_LOG_PATH, "************user fault info************"); +#endif +} + +static void DumpMemData(struct MemDumpParam *param) +{ + PRINTK("\nDumpType: %d\n", param->type); + PRINTK("Unsupported now!\n"); +} + +static void InjectKernelCrash(void) +{ +#ifdef LOSCFG_DEBUG_VERSION + *((INT32 *)KERNEL_FAULT_ADDR) = KERNEL_FAULT_VALUE; +#else + PRINTK("\nUnsupported!\n"); +#endif +} + +static INT32 HiDumperIoctl(struct file *filep, INT32 cmd, unsigned long arg) +{ + INT32 ret = 0; + + switch (cmd) { + case HIDUMPER_DUMP_ALL: + INVOKE_INTERFACE(&g_adapter, struct HiDumperAdapter, DumpSysInfo); + INVOKE_INTERFACE(&g_adapter, struct HiDumperAdapter, DumpCpuUsage); + INVOKE_INTERFACE(&g_adapter, struct HiDumperAdapter, DumpMemUsage); + INVOKE_INTERFACE(&g_adapter, struct HiDumperAdapter, DumpTaskInfo); + break; + case HIDUMPER_CPU_USAGE: + INVOKE_INTERFACE(&g_adapter, struct HiDumperAdapter, DumpCpuUsage); + break; + case HIDUMPER_MEM_USAGE: + INVOKE_INTERFACE(&g_adapter, struct HiDumperAdapter, DumpMemUsage); + break; + case HIDUMPER_TASK_INFO: + INVOKE_INTERFACE(&g_adapter, struct HiDumperAdapter, DumpTaskInfo); + break; + case HIDUMPER_INJECT_KERNEL_CRASH: + INVOKE_INTERFACE(&g_adapter, struct HiDumperAdapter, InjectKernelCrash); + break; + case HIDUMPER_DUMP_FAULT_LOG: + INVOKE_INTERFACE(&g_adapter, struct HiDumperAdapter, DumpFaultLog); + break; + case HIDUMPER_MEM_DATA: + if (g_adapter.DumpMemData != NULL) { + g_adapter.DumpMemData((struct MemDumpParam *)arg); + } + break; + default: + ret = EPERM; + PRINTK("Invalid CMD: 0x%x\n", (UINT32)cmd); + break; + } + + return ret; +} + +static void RegisterCommonAdapter(void) +{ + struct HiDumperAdapter adapter; + + adapter.DumpSysInfo = DumpSysInfo; + adapter.DumpCpuUsage = DumpCpuUsageUnsafe; + adapter.DumpMemUsage = DumpMemUsage; + adapter.DumpTaskInfo = DumpTaskInfo; + adapter.DumpFaultLog = DumpFaultLog; + adapter.DumpMemData = DumpMemData; + adapter.InjectKernelCrash = InjectKernelCrash; + HiDumperRegisterAdapter(&adapter); +} + +int HiDumperRegisterAdapter(struct HiDumperAdapter *pAdapter) +{ + if (pAdapter == NULL) { + PRINT_ERR("pAdapter: %p\n", pAdapter); + return -1; + } + + REPLACE_INTERFACE(&g_adapter, pAdapter, struct HiDumperAdapter, DumpSysInfo); + REPLACE_INTERFACE(&g_adapter, pAdapter, struct HiDumperAdapter, DumpCpuUsage); + REPLACE_INTERFACE(&g_adapter, pAdapter, struct HiDumperAdapter, DumpMemUsage); + REPLACE_INTERFACE(&g_adapter, pAdapter, struct HiDumperAdapter, DumpTaskInfo); + REPLACE_INTERFACE(&g_adapter, pAdapter, struct HiDumperAdapter, DumpFaultLog); + REPLACE_INTERFACE(&g_adapter, pAdapter, struct HiDumperAdapter, DumpMemData); + REPLACE_INTERFACE(&g_adapter, pAdapter, struct HiDumperAdapter, InjectKernelCrash); + + return 0; +} + +int OsHiDumperDriverInit(void) +{ + INT32 ret; + +#ifdef LOSCFG_DEBUG_VERSION + RegisterCommonAdapter(); + ret = register_driver(HIDUMPER_DEVICE, &g_hidumperDevOps, HIDUMPER_DEVICE_MODE, NULL); + if (ret != 0) { + PRINT_ERR("Hidumper register driver failed!\n"); + return -1; + } +#endif + + return 0; +} +LOS_MODULE_INIT(OsHiDumperDriverInit, LOS_INIT_LEVEL_KMOD_EXTENDED); diff --git a/kernel/common/hidumper/los_hidumper.h b/kernel/common/hidumper/los_hidumper.h new file mode 100644 index 00000000..ab48f302 --- /dev/null +++ b/kernel/common/hidumper/los_hidumper.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2021-2021 Huawei Device Co., Ltd. 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. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * 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. + */ + +#ifndef LOS_HIDUMPER_H +#define LOS_HIDUMPER_H + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#ifndef __user +#define __user +#endif + +#define PATH_MAX_LEN 256 + +enum MemDumpType { + DUMP_TO_STDOUT, + DUMP_REGION_TO_STDOUT, + DUMP_TO_FILE, + DUMP_REGION_TO_FILE +}; + +struct MemDumpParam { + enum MemDumpType type; + unsigned long long start; + unsigned long long size; + char filePath[PATH_MAX_LEN]; +}; + +struct HiDumperAdapter { + void (*DumpSysInfo)(void); + void (*DumpCpuUsage)(void); + void (*DumpMemUsage)(void); + void (*DumpTaskInfo)(void); + void (*DumpFaultLog)(void); + void (*DumpMemData)(struct MemDumpParam *param); + void (*InjectKernelCrash)(void); +}; + +#define HIDUMPER_IOC_BASE 'd' +#define HIDUMPER_DUMP_ALL _IO(HIDUMPER_IOC_BASE, 1) +#define HIDUMPER_CPU_USAGE _IO(HIDUMPER_IOC_BASE, 2) +#define HIDUMPER_MEM_USAGE _IO(HIDUMPER_IOC_BASE, 3) +#define HIDUMPER_TASK_INFO _IO(HIDUMPER_IOC_BASE, 4) +#define HIDUMPER_INJECT_KERNEL_CRASH _IO(HIDUMPER_IOC_BASE, 5) +#define HIDUMPER_DUMP_FAULT_LOG _IO(HIDUMPER_IOC_BASE, 6) +#define HIDUMPER_MEM_DATA _IOW(HIDUMPER_IOC_BASE, 7, struct MemDumpParam) + +int HiDumperRegisterAdapter(struct HiDumperAdapter *pAdapter); +int OsHiDumperDriverInit(void); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif \ No newline at end of file diff --git a/tools/build/mk/liteos_tables_ldflags.mk b/tools/build/mk/liteos_tables_ldflags.mk index db8b93c9..eed3a4b9 100644 --- a/tools/build/mk/liteos_tables_ldflags.mk +++ b/tools/build/mk/liteos_tables_ldflags.mk @@ -137,7 +137,8 @@ LITEOS_TABLES_KERNEL_INIT_LDFLAGS := \ -uOsResourceFreeTaskCreate \ -uOsSystemInit \ -uOsBBoxDriverInit \ - -uOsBBoxSystemAdapterInit + -uOsBBoxSystemAdapterInit \ + -uOsHiDumperDriverInit LITEOS_TABLES_DRIVER_LDFLAGS := \ -ui2c_init \ diff --git a/tools/build/mk/los_config.mk b/tools/build/mk/los_config.mk index 902f770a..b332f723 100644 --- a/tools/build/mk/los_config.mk +++ b/tools/build/mk/los_config.mk @@ -448,6 +448,11 @@ ifeq ($(LOSCFG_BLACKBOX), y) LIB_SUBDIRS += $(LITEOSTOPDIR)/kernel/common/blackbox LITEOS_BLACKBOX_INCLUDE += -I $(LITEOSTOPDIR)/kernel/common/blackbox endif +ifeq ($(LOSCFG_HIDUMPER), y) + LITEOS_BASELIB += -lhidumper + LIB_SUBDIRS += $(LITEOSTOPDIR)/kernel/common/hidumper + LITEOS_HIDUMPER_INCLUDE += -I $(LITEOSTOPDIR)/kernel/common/hidumper +endif ############################## Dfx Option End ####################################### ############################# Tools && Debug Option Begin ############################## @@ -645,7 +650,8 @@ LITEOS_DRIVERS_INCLUDE := $(LITEOS_CELLWISE_INCLUDE) $(LITEOS_GPIO_INCLUDE $(LITEOS_HIEVENT_INCLUDE) $(LITEOS_DEV_MEM_INCLUDE) \ $(LITEOS_DEV_QUICKSTART_INCLUDE) LITEOS_DFX_INCLUDE := $(LITEOS_HILOG_INCLUDE) \ - $(LITEOS_BLACKBOX_INCLUDE) + $(LITEOS_BLACKBOX_INCLUDE) \ + $(LITEOS_HIDUMPER_INCLUDE) LITEOS_SECURITY_INCLUDE := $(LITEOS_SECURITY_CAP_INC) $(LITEOS_SECURITY_VID_INC) LOSCFG_TOOLS_DEBUG_INCLUDE := $(LITEOS_SHELL_INCLUDE) $(LITEOS_UART_INCLUDE) \