Skip to content
Snippets Groups Projects
Commit d83c305c authored by Naixin Yu's avatar Naixin Yu Committed by Cheng Jian
Browse files

Huawei BMA: Adding Huawei BMA driver: host_kbox_drv

driver inclusion
category: feature
bugzilla: 34535
CVE: NA

The BMA software is a system management software offered by Huawei. It supports
the status monitoring, performance monitoring, and event monitoring of various
components, including server CPUs, memory, hard disks, NICs, IB cards, PCIe
cards, RAID controller cards, and optical modules.

The host_kbox_drv driver serves the function of a black box. When a panic or mce
event happen to the system, it will record the event time, system's status and
system logs and send them to BMC before the OS shutdown. This driver depends on
the host_edms_drv driver.

Link: https://lkml.org/lkml/2020/6/22/752


Signed-off-by: default avatarNaixin Yu <yunaixin@huawei.com>
Reviewed-by: default avatarWang Qindong <wangqindong@huawei.com>
Acked-by: default avatarXie XiuQi <xiexiuqi@huawei.com>
Signed-off-by: default avatarYang Yingliang <yangyingliang@huawei.com>
Signed-off-by: default avatarCheng Jian <cj.chengjian@huawei.com>
parent 751b5850
No related branches found
No related tags found
No related merge requests found
Showing
with 2844 additions and 0 deletions
......@@ -5,4 +5,5 @@
obj-$(CONFIG_BMA) += edma_drv/
obj-$(CONFIG_BMA) += cdev_drv/
obj-$(CONFIG_BMA) += veth_drv/
obj-$(CONFIG_BMA) += kbox_drv/
obj-$(CONFIG_BMA) += cdev_veth_drv/
\ No newline at end of file
obj-$(CONFIG_BMA) += host_kbox_drv.o
host_kbox_drv-y := kbox_main.o kbox_ram_drive.o kbox_ram_image.o kbox_ram_op.o kbox_printk.o kbox_dump.o kbox_hook.o kbox_panic.o
ifdef CONFIG_X86
host_kbox_drv-y += kbox_mce.o
endif
\ No newline at end of file
// SPDX-License-Identifier: GPL-2.0
/* Huawei iBMA driver.
* Copyright (c) 2017, Huawei Technologies Co., Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*/
#include <linux/spinlock.h>
#include <linux/utsname.h> /* system_utsname */
#include <linux/rtc.h> /* struct rtc_time */
#include "kbox_include.h"
#include "kbox_main.h"
#include "kbox_printk.h"
#include "kbox_ram_image.h"
#include "kbox_ram_op.h"
#include "kbox_dump.h"
#include "kbox_panic.h"
#ifdef CONFIG_X86
#include "kbox_mce.h"
#endif
#define THREAD_TMP_BUF_SIZE 256
static DEFINE_SPINLOCK(g_dump_lock);
static const char g_day_in_month[] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
#define LEAP_YEAR(year) \
((!((year) % 4) && ((year) % 100)) || !((year) % 400))
#define MONTH_DAYS(month, year) \
(g_day_in_month[(month)] + (int)(LEAP_YEAR(year) && (month == 1)))
static void kbox_show_kernel_version(void)
{
(void)kbox_dump_painc_info
("\nOS : %s,\nRelease : %s,\nVersion : %s,\n",
init_uts_ns.name.sysname,
init_uts_ns.name.release,
init_uts_ns.name.version);
(void)kbox_dump_painc_info
("Machine : %s,\nNodename : %s\n",
init_uts_ns.name.machine,
init_uts_ns.name.nodename);
}
static void kbox_show_version(void)
{
(void)kbox_dump_painc_info("\nKBOX_VERSION : %s\n",
KBOX_VERSION);
}
static void kbox_show_time_stamps(void)
{
struct rtc_time rtc_time_val = { };
struct timespec64 uptime;
ktime_get_coarse_real_ts64(&uptime);
rtc_time64_to_tm(uptime.tv_sec, &rtc_time_val);
(void)kbox_dump_painc_info
("Current time : %04d-%02d-%02d %02d:%02d:%02d\n",
rtc_time_val.tm_year + 1900, rtc_time_val.tm_mon + 1,
rtc_time_val.tm_mday, rtc_time_val.tm_hour,
rtc_time_val.tm_min, rtc_time_val.tm_sec);
}
void kbox_dump_event(enum kbox_error_type_e type, unsigned long event,
const char *msg)
{
if (!spin_trylock(&g_dump_lock))
return;
(void)kbox_dump_painc_info("\n====kbox begin dumping...====\n");
switch (type) {
#ifdef CONFIG_X86
case KBOX_MCE_EVENT:
kbox_handle_mce_dump(msg);
break;
#endif
case KBOX_OPPS_EVENT:
break;
case KBOX_PANIC_EVENT:
if (kbox_handle_panic_dump(msg) == KBOX_FALSE)
goto end;
break;
default:
break;
}
kbox_show_kernel_version();
kbox_show_version();
kbox_show_time_stamps();
(void)kbox_dump_painc_info("\n====kbox end dump====\n");
kbox_output_syslog_info();
kbox_output_printk_info();
end:
spin_unlock(&g_dump_lock);
}
/* SPDX-License-Identifier: GPL-2.0 */
/* Huawei iBMA driver.
* Copyright (c) 2017, Huawei Technologies Co., Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*/
#ifndef _KBOX_DUMP_H_
#define _KBOX_DUMP_H_
#define DUMPSTATE_MCE_RESET 1
#define DUMPSTATE_OPPS_RESET 2
#define DUMPSTATE_PANIC_RESET 3
enum kbox_error_type_e {
KBOX_MCE_EVENT = 1,
KBOX_OPPS_EVENT,
KBOX_PANIC_EVENT
};
int kbox_dump_thread_info(const char *fmt, ...);
void kbox_dump_event(enum kbox_error_type_e type, unsigned long event,
const char *msg);
#endif
// SPDX-License-Identifier: GPL-2.0
/* Huawei iBMA driver.
* Copyright (c) 2017, Huawei Technologies Co., Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*/
#include <linux/notifier.h>
#include "kbox_include.h"
#include "kbox_dump.h"
#include "kbox_hook.h"
int panic_notify(struct notifier_block *this,
unsigned long event, void *msg);
static int die_notify(struct notifier_block *self,
unsigned long val, void *data);
static struct notifier_block g_panic_nb = {
.notifier_call = panic_notify,
.priority = 100,
};
static struct notifier_block g_die_nb = {
.notifier_call = die_notify,
};
int panic_notify(struct notifier_block *pthis, unsigned long event, void *msg)
{
UNUSED(pthis);
UNUSED(event);
kbox_dump_event(KBOX_PANIC_EVENT, DUMPSTATE_PANIC_RESET,
(const char *)msg);
return NOTIFY_OK;
}
int die_notify(struct notifier_block *self, unsigned long val, void *data)
{
struct kbox_die_args *args = (struct kbox_die_args *)data;
if (!args)
return NOTIFY_OK;
switch (val) {
case 1:
break;
case 5:
if (strcmp(args->str, "nmi") == 0)
return NOTIFY_OK;
#ifdef CONFIG_X86
kbox_dump_event(KBOX_MCE_EVENT, DUMPSTATE_MCE_RESET, args->str);
#endif
break;
default:
break;
}
return NOTIFY_OK;
}
int kbox_register_hook(void)
{
int ret = 0;
ret = atomic_notifier_chain_register(&panic_notifier_list, &g_panic_nb);
if (ret)
KBOX_MSG("atomic_notifier_chain_register g_panic_nb failed!\n");
ret = register_die_notifier(&g_die_nb);
if (ret)
KBOX_MSG("register_die_notifier g_die_nb failed!\n");
return ret;
}
void kbox_unregister_hook(void)
{
int ret = 0;
ret =
atomic_notifier_chain_unregister(&panic_notifier_list, &g_panic_nb);
if (ret < 0) {
KBOX_MSG
("atomic_notifier_chain_unregister g_panic_nb failed!\n");
}
ret = unregister_die_notifier(&g_die_nb);
if (ret < 0)
KBOX_MSG("unregister_die_notifier g_die_nb failed!\n");
}
/* SPDX-License-Identifier: GPL-2.0 */
/* Huawei iBMA driver.
* Copyright (c) 2017, Huawei Technologies Co., Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*/
#ifndef _KBOX_PANIC_HOOK_H_
#define _KBOX_PANIC_HOOK_H_
struct kbox_die_args {
struct pt_regs *regs;
const char *str;
long err;
int trapnr;
int signr;
};
int register_die_notifier(struct notifier_block *nb);
int unregister_die_notifier(struct notifier_block *nb);
int kbox_register_hook(void);
void kbox_unregister_hook(void);
#endif
/* SPDX-License-Identifier: GPL-2.0 */
/* Huawei iBMA driver.
* Copyright (c) 2017, Huawei Technologies Co., Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*/
#ifndef _KBOX_INCLUDE_H_
#define _KBOX_INCLUDE_H_
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/netdevice.h>
#ifdef DRV_VERSION
#define KBOX_VERSION MICRO_TO_STR(DRV_VERSION)
#else
#define KBOX_VERSION "0.3.4"
#endif
#define UNUSED(x) (x = x)
#define KBOX_FALSE (-1)
#define KBOX_TRUE 0
#ifdef KBOX_DEBUG
#define KBOX_MSG(fmt, args...) \
netdev_notice(0, "kbox: %s(), %d, " fmt, __func__, __LINE__, ## args)
#else
#define KBOX_MSG(fmt, args...)
#endif
#endif
// SPDX-License-Identifier: GPL-2.0
/* Huawei iBMA driver.
* Copyright (c) 2017, Huawei Technologies Co., Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*/
#include <linux/module.h>
#include <linux/processor.h> /* for rdmsr and MSR_IA32_MCG_STATUS */
#include <linux/fs.h> /* everything... */
#include <linux/file.h> /* for fput */
#include <linux/proc_fs.h>
#include <linux/uaccess.h> /* copy_*_user */
#include <linux/version.h>
#include "kbox_include.h"
#include "kbox_panic.h"
#include "kbox_main.h"
#include "kbox_printk.h"
#include "kbox_ram_image.h"
#include "kbox_ram_op.h"
#include "kbox_dump.h"
#include "kbox_hook.h"
#include "kbox_ram_drive.h"
#ifdef CONFIG_X86
#include <asm/msr.h>
#include "kbox_mce.h"
#endif
#define KBOX_LOADED_FILE ("/proc/kbox")
#define KBOX_ROOT_ENTRY_NAME ("kbox")
static int kbox_is_loaded(void)
{
struct file *fp = NULL;
mm_segment_t old_fs;
old_fs = get_fs(); /* save old flag */
set_fs(KERNEL_DS); /* mark data from kernel space */
fp = filp_open(KBOX_LOADED_FILE, O_RDONLY, 0);
if (IS_ERR(fp)) {
set_fs(old_fs);
return KBOX_FALSE;
}
(void)filp_close(fp, NULL);
set_fs(old_fs); /* restore old flag */
return KBOX_TRUE;
}
static int kbox_printk_proc_init(void)
{
struct proc_dir_entry *kbox_entry = NULL;
if (kbox_is_loaded() != KBOX_TRUE) {
kbox_entry = proc_mkdir(KBOX_ROOT_ENTRY_NAME, NULL);
if (!kbox_entry) {
KBOX_MSG("can not create %s entry\n",
KBOX_ROOT_ENTRY_NAME);
return -ENOMEM;
}
}
return KBOX_TRUE;
}
int __init kbox_init(void)
{
int ret = KBOX_TRUE;
int kbox_proc_exist = 0;
if (!kbox_get_base_phy_addr())
return -ENXIO;
ret = kbox_super_block_init();
if (ret) {
KBOX_MSG("kbox_super_block_init failed!\n");
return ret;
}
if (kbox_is_loaded() == KBOX_TRUE)
kbox_proc_exist = 1;
ret = kbox_printk_init(kbox_proc_exist);
if (ret)
KBOX_MSG("kbox_printk_init failed!\n");
ret = kbox_panic_init();
if (ret) {
KBOX_MSG("kbox_panic_init failed!\n");
goto fail1;
}
ret = kbox_register_hook();
if (ret) {
KBOX_MSG("kbox_register_hook failed!\n");
goto fail2;
}
#ifdef CONFIG_X86
(void)kbox_mce_init();
#endif
ret = kbox_read_super_block();
if (ret) {
KBOX_MSG("update super block failed!\n");
goto fail3;
}
if (kbox_printk_proc_init() != 0) {
KBOX_MSG("kbox_printk_proc_init failed!\n");
goto fail4;
}
ret = kbox_drive_init();
if (ret) {
KBOX_MSG("kbox_drive_init failed!\n");
goto fail5;
}
return KBOX_TRUE;
fail5:
fail4:
fail3:
#ifdef CONFIG_X86
kbox_mce_exit();
#endif
kbox_unregister_hook();
fail2:
kbox_panic_exit();
fail1:
kbox_printk_exit();
return ret;
}
void __exit kbox_cleanup(void)
{
kbox_drive_cleanup();
#ifdef CONFIG_X86
kbox_mce_exit();
#endif
kbox_unregister_hook();
kbox_panic_exit();
kbox_printk_exit();
}
MODULE_AUTHOR("HUAWEI TECHNOLOGIES CO., LTD.");
MODULE_DESCRIPTION("HUAWEI KBOX DRIVER");
MODULE_LICENSE("GPL");
MODULE_VERSION(KBOX_VERSION);
#ifndef _lint
module_init(kbox_init);
module_exit(kbox_cleanup);
#endif
/* SPDX-License-Identifier: GPL-2.0 */
/* Huawei iBMA driver.
* Copyright (c) 2017, Huawei Technologies Co., Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*/
#ifndef _KBOX_MAIN_H_
#define _KBOX_MAIN_H_
#include "../edma_drv/bma_include.h"
int kbox_init(void);
void kbox_cleanup(void);
#endif
// SPDX-License-Identifier: GPL-2.0
/* Huawei iBMA driver.
* Copyright (c) 2017, Huawei Technologies Co., Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*/
#include <linux/version.h>
#include <linux/types.h>
#include <linux/atomic.h>
#include <linux/smp.h>
#include <linux/notifier.h>
#include <asm/mce.h>
#include <asm/msr.h>
#include "kbox_include.h"
#include "kbox_mce.h"
#include "kbox_dump.h"
#include "kbox_printk.h"
#include "kbox_panic.h"
enum context {
KBOX_IN_KERNEL = 1, KBOX_IN_USER = 2
};
enum ser {
KBOX_SER_REQUIRED = 1, KBOX_NO_SER = 2
};
enum severity_level {
KBOX_MCE_NO_SEVERITY,
KBOX_MCE_KEEP_SEVERITY,
KBOX_MCE_SOME_SEVERITY,
KBOX_MCE_AO_SEVERITY,
KBOX_MCE_UC_SEVERITY,
KBOX_MCE_AR_SEVERITY,
KBOX_MCE_PANIC_SEVERITY,
};
static struct severity {
u64 kbox_mask;
u64 kbox_result;
unsigned char kbox_sev;
unsigned char kbox_mcgmask;
unsigned char kbox_mcgres;
unsigned char kbox_ser;
unsigned char kbox_context;
unsigned char kbox_covered;
char *kbox_msg;
} kbox_severities[] = {
#define KBOX_KERNEL .kbox_context = KBOX_IN_KERNEL
#define KBOX_USER .kbox_context = KBOX_IN_USER
#define KBOX_SER .kbox_ser = KBOX_SER_REQUIRED
#define KBOX_NOSER .kbox_ser = KBOX_NO_SER
#define KBOX_SEV(s) .kbox_sev = KBOX_MCE_ ## s ## _SEVERITY
#define KBOX_BITCLR(x, s, m, r...) \
{ .kbox_mask = x, .kbox_result = 0, KBOX_SEV(s), .kbox_msg = m, ## r }
#define KBOX_BITSET(x, s, m, r...) \
{ .kbox_mask = x, .kbox_result = x, KBOX_SEV(s), .kbox_msg = m, ## r }
#define KBOX_MCGMASK(x, res, s, m, r...) \
{ .kbox_mcgmask = x, .kbox_mcgres = res, KBOX_SEV(s), \
.kbox_msg = m, ## r }
#define KBOX_MASK(x, y, s, m, r...) \
{ .kbox_mask = x, .kbox_result = y, KBOX_SEV(s), .kbox_msg = m, ## r }
#define KBOX_MCI_UC_S (MCI_STATUS_UC | MCI_STATUS_S)
#define KBOX_MCI_UC_SAR (MCI_STATUS_UC | MCI_STATUS_S | MCI_STATUS_AR)
#define KBOX_MCACOD 0xffff
KBOX_BITCLR(MCI_STATUS_VAL, NO, "Invalid"),
KBOX_BITCLR(MCI_STATUS_EN, NO, "Not enabled"),
KBOX_BITSET(MCI_STATUS_PCC, PANIC, "Processor context corrupt"),
KBOX_MCGMASK(MCG_STATUS_MCIP, 0, PANIC, "MCIP not set in MCA handler"),
KBOX_MCGMASK(MCG_STATUS_RIPV | MCG_STATUS_EIPV, 0, PANIC,
"Neither restart nor error IP"),
KBOX_MCGMASK(MCG_STATUS_RIPV, 0, PANIC, "In kernel and no restart IP",
KBOX_KERNEL),
KBOX_BITCLR(MCI_STATUS_UC, KEEP, "Corrected error", KBOX_NOSER),
KBOX_MASK(MCI_STATUS_OVER | MCI_STATUS_UC | MCI_STATUS_EN, MCI_STATUS_UC, SOME,
"Spurious not enabled", KBOX_SER),
KBOX_MASK(KBOX_MCI_UC_SAR, MCI_STATUS_UC, KEEP,
"Uncorrected no action required", KBOX_SER),
KBOX_MASK(MCI_STATUS_OVER | KBOX_MCI_UC_SAR, MCI_STATUS_UC | MCI_STATUS_AR,
PANIC, "Illegal combination (UCNA with AR=1)", KBOX_SER),
KBOX_MASK(MCI_STATUS_S, 0, KEEP, "Non signalled machine check", KBOX_SER),
KBOX_MASK(MCI_STATUS_OVER | KBOX_MCI_UC_SAR, MCI_STATUS_OVER | KBOX_MCI_UC_SAR,
PANIC, "Action required with lost events", KBOX_SER),
KBOX_MASK(MCI_STATUS_OVER | KBOX_MCI_UC_SAR | KBOX_MCACOD, KBOX_MCI_UC_SAR,
PANIC, "Action required; unknown MCACOD", KBOX_SER),
KBOX_MASK(KBOX_MCI_UC_SAR | MCI_STATUS_OVER | 0xfff0, KBOX_MCI_UC_S | 0xc0,
AO, "Action optional: memory scrubbing error", KBOX_SER),
KBOX_MASK(KBOX_MCI_UC_SAR | MCI_STATUS_OVER | KBOX_MCACOD,
KBOX_MCI_UC_S | 0x17a, AO,
"Action optional: last level cache writeback error", KBOX_SER),
KBOX_MASK(MCI_STATUS_OVER | KBOX_MCI_UC_SAR, KBOX_MCI_UC_S, SOME,
"Action optional unknown MCACOD", KBOX_SER),
KBOX_MASK(MCI_STATUS_OVER | KBOX_MCI_UC_SAR, KBOX_MCI_UC_S | MCI_STATUS_OVER,
SOME, "Action optional with lost events", KBOX_SER),
KBOX_BITSET(MCI_STATUS_UC | MCI_STATUS_OVER, PANIC, "Overflowed uncorrected"),
KBOX_BITSET(MCI_STATUS_UC, UC, "Uncorrected"),
KBOX_BITSET(0, SOME, "No match")
};
static unsigned int g_kbox_nr_mce_banks;
static unsigned int g_kbox_mce_ser;
static atomic_t g_mce_dump_state = ATOMIC_INIT(0);
static int kbox_mce_severity(u64 mcgstatus, u64 status)
{
struct severity *s;
for (s = kbox_severities;; s++) {
if ((status & s->kbox_mask) != s->kbox_result)
continue;
if ((mcgstatus & s->kbox_mcgmask) != s->kbox_mcgres)
continue;
if (s->kbox_ser == KBOX_SER_REQUIRED && !g_kbox_mce_ser)
continue;
if (s->kbox_ser == KBOX_NO_SER && g_kbox_mce_ser)
continue;
break;
}
return s->kbox_sev;
}
static u64 kbox_mce_rdmsrl(u32 ulmsr)
{
u64 ullv = 0;
if (rdmsrl_safe(ulmsr, &ullv)) {
(void)kbox_dump_painc_info("mce: Unable to read msr %d!\n",
ulmsr);
ullv = 0;
}
return ullv;
}
static int kbox_intel_machine_check(void)
{
unsigned int idx = 0;
u64 mcgstatus = 0;
int worst = 0;
mcgstatus = kbox_mce_rdmsrl(MSR_IA32_MCG_STATUS);
(void)
kbox_dump_painc_info
("CPU %d: Machine Check Exception MCG STATUS: 0x%016llx\n",
smp_processor_id(), mcgstatus);
if (!(mcgstatus & MCG_STATUS_RIPV))
(void)kbox_dump_painc_info("Unable to continue\n");
for (idx = 0; idx < g_kbox_nr_mce_banks; idx++) {
u64 status = 0;
u64 misc = 0;
u64 addr = 0;
int lseverity = 0;
status = kbox_mce_rdmsrl(MSR_IA32_MCx_STATUS(idx));
(void)kbox_dump_painc_info("Bank %d STATUS: 0x%016llx\n", idx,
status);
if (0 == (status & MCI_STATUS_VAL))
continue;
lseverity = kbox_mce_severity(mcgstatus, status);
if (lseverity == KBOX_MCE_KEEP_SEVERITY ||
lseverity == KBOX_MCE_NO_SEVERITY)
continue;
(void)kbox_dump_painc_info("severity = %d\n", lseverity);
if (status & MCI_STATUS_MISCV) {
misc = kbox_mce_rdmsrl(MSR_IA32_MCx_MISC(idx));
(void)kbox_dump_painc_info("misc = 0x%016llx\n", misc);
}
if (status & MCI_STATUS_ADDRV) {
addr = kbox_mce_rdmsrl(MSR_IA32_MCx_ADDR(idx));
(void)kbox_dump_painc_info("addr = 0x%016llx\n", addr);
}
(void)kbox_dump_painc_info("\n");
if (lseverity > worst)
worst = lseverity;
}
if (worst >= KBOX_MCE_UC_SEVERITY)
return KBOX_FALSE;
(void)kbox_dump_painc_info("Attempting to continue.\n");
return KBOX_TRUE;
}
int kbox_handle_mce_dump(const char *msg)
{
int mce_recoverable = KBOX_FALSE;
atomic_read(&g_mce_dump_state);
mce_recoverable = kbox_intel_machine_check();
if (mce_recoverable != KBOX_TRUE) {
static atomic_t mce_entry_tmp;
int flag = atomic_add_return(1, &mce_entry_tmp);
if (flag != 1)
return KBOX_FALSE;
}
atomic_set(&g_mce_dump_state, DUMPSTATE_MCE_RESET);
if (msg) {
(void)
kbox_dump_painc_info
("-------[ System may reset by %s! ]-------\n\n", msg);
}
return KBOX_TRUE;
}
int kbox_mce_init(void)
{
u64 cap = 0;
cap = kbox_mce_rdmsrl(MSR_IA32_MCG_CAP);
g_kbox_nr_mce_banks = cap & MCG_BANKCNT_MASK;
if (cap & MCG_SER_P)
g_kbox_mce_ser = 1;
KBOX_MSG("get nr_mce_banks:%d, g_kbox_mce_ser = %d, cap = 0x%016llx\n",
g_kbox_nr_mce_banks, g_kbox_mce_ser, cap);
return KBOX_TRUE;
}
void kbox_mce_exit(void)
{
g_kbox_nr_mce_banks = 0;
g_kbox_mce_ser = 0;
}
/* SPDX-License-Identifier: GPL-2.0 */
/* Huawei iBMA driver.
* Copyright (c) 2017, Huawei Technologies Co., Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*/
#ifndef _KBOX_MCE_H_
#define _KBOX_MCE_H_
int kbox_handle_mce_dump(const char *msg);
int kbox_mce_init(void);
void kbox_mce_exit(void);
#endif
// SPDX-License-Identifier: GPL-2.0
/* Huawei iBMA driver.
* Copyright (c) 2017, Huawei Technologies Co., Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*/
#include <asm/types.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/err.h>
#include "kbox_include.h"
#include "kbox_panic.h"
#include "kbox_ram_op.h"
#ifdef CONFIG_X86
#include <asm/msr.h>
#endif
#define PANIC_TMP_BUF_SIZE 256
static int g_panic_init_ok = KBOX_FALSE;
static char *g_panic_info_buf_tmp;
static char *g_panic_info_buf;
static unsigned int g_panic_info_start;
static unsigned int g_panic_info_end;
static unsigned int g_panic_info_len;
static DEFINE_SPINLOCK(g_panic_buf_lock);
static void kbox_emit_syslog_char(const char c)
{
if (unlikely(!g_panic_info_buf))
return;
*(g_panic_info_buf + (g_panic_info_end % SLOT_LENGTH)) = c;
g_panic_info_end++;
if (g_panic_info_end > SLOT_LENGTH)
g_panic_info_start++;
if (g_panic_info_len < SLOT_LENGTH)
g_panic_info_len++;
}
static int kbox_duplicate_syslog_info(const char *syslog_buf,
unsigned int buf_len)
{
unsigned int idx = 0;
unsigned long flags = 0;
if (!syslog_buf)
return 0;
spin_lock_irqsave(&g_panic_buf_lock, flags);
for (idx = 0; idx < buf_len; idx++)
kbox_emit_syslog_char(*syslog_buf++);
spin_unlock_irqrestore(&g_panic_buf_lock, flags);
return buf_len;
}
int kbox_dump_painc_info(const char *fmt, ...)
{
va_list args;
int num = 0;
char tmp_buf[PANIC_TMP_BUF_SIZE] = { };
va_start(args, fmt);
num = vsnprintf(tmp_buf, sizeof(tmp_buf) - 1, fmt, args);
if (num >= 0)
(void)kbox_duplicate_syslog_info(tmp_buf, num);
va_end(args);
return num;
}
void kbox_output_syslog_info(void)
{
unsigned int start_tmp = 0;
unsigned int end_tmp = 0;
unsigned int len_tmp = 0;
unsigned long flags = 0;
if (unlikely
(!g_panic_info_buf || !g_panic_info_buf_tmp))
return;
spin_lock_irqsave(&g_panic_buf_lock, flags);
if (g_panic_info_len == 0) {
spin_unlock_irqrestore(&g_panic_buf_lock, flags);
return;
}
start_tmp = (g_panic_info_start % SLOT_LENGTH);
end_tmp = ((g_panic_info_end - 1) % SLOT_LENGTH);
len_tmp = g_panic_info_len;
if (start_tmp > end_tmp) {
memcpy(g_panic_info_buf_tmp,
(g_panic_info_buf + start_tmp),
len_tmp - start_tmp);
memcpy((g_panic_info_buf_tmp + len_tmp - start_tmp),
g_panic_info_buf,
end_tmp + 1);
} else {
memcpy(g_panic_info_buf_tmp,
(char *)(g_panic_info_buf + start_tmp),
len_tmp);
}
spin_unlock_irqrestore(&g_panic_buf_lock, flags);
(void)kbox_write_panic_info(g_panic_info_buf_tmp, len_tmp);
}
int kbox_panic_init(void)
{
int ret = KBOX_TRUE;
g_panic_info_buf = kmalloc(SLOT_LENGTH, GFP_KERNEL);
if (IS_ERR(g_panic_info_buf) || !g_panic_info_buf) {
KBOX_MSG("kmalloc g_panic_info_buf fail!\n");
ret = -ENOMEM;
goto fail;
}
memset(g_panic_info_buf, 0, SLOT_LENGTH);
g_panic_info_buf_tmp = kmalloc(SLOT_LENGTH, GFP_KERNEL);
if (IS_ERR(g_panic_info_buf_tmp) || !g_panic_info_buf_tmp) {
KBOX_MSG("kmalloc g_panic_info_buf_tmp fail!\n");
ret = -ENOMEM;
goto fail;
}
memset(g_panic_info_buf_tmp, 0, SLOT_LENGTH);
g_panic_init_ok = KBOX_TRUE;
return ret;
fail:
kfree(g_panic_info_buf);
g_panic_info_buf = NULL;
kfree(g_panic_info_buf_tmp);
g_panic_info_buf_tmp = NULL;
return ret;
}
void kbox_panic_exit(void)
{
if (g_panic_init_ok != KBOX_TRUE)
return;
kfree(g_panic_info_buf);
g_panic_info_buf = NULL;
kfree(g_panic_info_buf_tmp);
g_panic_info_buf_tmp = NULL;
}
int kbox_handle_panic_dump(const char *msg)
{
if (msg)
(void)kbox_dump_painc_info("panic string: %s\n", msg);
return KBOX_TRUE;
}
/* SPDX-License-Identifier: GPL-2.0 */
/* Huawei iBMA driver.
* Copyright (c) 2017, Huawei Technologies Co., Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*/
#ifndef _KBOX_PANIC_H_
#define _KBOX_PANIC_H_
int kbox_handle_panic_dump(const char *msg);
void kbox_output_syslog_info(void);
int kbox_dump_painc_info(const char *fmt, ...);
int kbox_panic_init(void);
void kbox_panic_exit(void);
#endif
// SPDX-License-Identifier: GPL-2.0
/* Huawei iBMA driver.
* Copyright (c) 2017, Huawei Technologies Co., Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*/
#include <linux/spinlock.h>
#include <linux/console.h> /* struct console */
#include <linux/slab.h>
#include <linux/err.h>
#include "kbox_include.h"
#include "kbox_main.h"
#include "kbox_printk.h"
#include "kbox_ram_image.h"
#include "kbox_ram_op.h"
#define TMP_BUF_SIZE 256
static int g_printk_init_ok = KBOX_FALSE;
static char *g_printk_info_buf;
static char *g_printk_info_buf_tmp;
static struct printk_ctrl_block_tmp_s g_printk_ctrl_block_tmp = { };
static DEFINE_SPINLOCK(g_printk_buf_lock);
static void kbox_printk_info_write(struct console *console,
const char *printk_buf,
unsigned int buf_len);
static struct console g_printk_console = {
.name = "k_prtk",
.flags = CON_ENABLED | CON_PRINTBUFFER,
.write = kbox_printk_info_write,
};
static int kbox_printk_format_is_order(struct printk_info_ctrl_block_s *
printk_ctrl_blk_first,
struct printk_info_ctrl_block_s *
printk_ctrl_blk_second)
{
if (!printk_ctrl_blk_first || !printk_ctrl_blk_second)
return KBOX_FALSE;
if (!memcmp(printk_ctrl_blk_first->flag, PRINTK_CURR_FLAG,
PRINTK_FLAG_LEN) &&
!memcmp(printk_ctrl_blk_second->flag, PRINTK_LAST_FLAG,
PRINTK_FLAG_LEN)) {
return KBOX_TRUE;
}
return KBOX_FALSE;
}
static void kbox_printk_format(struct printk_info_ctrl_block_s *printk_ctrl_blk,
const unsigned int len, const char *flag)
{
if (!printk_ctrl_blk || !flag)
return;
memset(printk_ctrl_blk, 0, len);
memcpy(printk_ctrl_blk->flag, flag, PRINTK_FLAG_LEN);
}
static void kbox_printk_init_info_first
(struct image_super_block_s *kbox_super_block)
{
KBOX_MSG("\n");
if (kbox_printk_format_is_order(kbox_super_block->printk_ctrl_blk,
kbox_super_block->printk_ctrl_blk +
1) == KBOX_TRUE) {
memcpy(kbox_super_block->printk_ctrl_blk[0].flag,
PRINTK_LAST_FLAG, PRINTK_FLAG_LEN);
memcpy(kbox_super_block->printk_ctrl_blk[1].flag,
PRINTK_CURR_FLAG, PRINTK_FLAG_LEN);
kbox_super_block->printk_ctrl_blk[1].len = 0;
g_printk_ctrl_block_tmp.printk_region = 1;
g_printk_ctrl_block_tmp.section = KBOX_SECTION_PRINTK2;
(void)kbox_clear_region(KBOX_SECTION_PRINTK2);
} else if (kbox_printk_format_is_order
(kbox_super_block->printk_ctrl_blk + 1,
kbox_super_block->printk_ctrl_blk) == KBOX_TRUE) {
memcpy(kbox_super_block->printk_ctrl_blk[1].flag,
PRINTK_LAST_FLAG,
PRINTK_FLAG_LEN);
memcpy(kbox_super_block->printk_ctrl_blk[0].flag,
PRINTK_CURR_FLAG,
PRINTK_FLAG_LEN);
kbox_super_block->printk_ctrl_blk[0].len = 0;
g_printk_ctrl_block_tmp.printk_region = 0;
g_printk_ctrl_block_tmp.section = KBOX_SECTION_PRINTK1;
(void)kbox_clear_region(KBOX_SECTION_PRINTK1);
} else {
kbox_printk_format(kbox_super_block->printk_ctrl_blk,
sizeof(struct printk_info_ctrl_block_s),
PRINTK_CURR_FLAG);
kbox_printk_format(kbox_super_block->printk_ctrl_blk + 1,
sizeof(struct printk_info_ctrl_block_s),
PRINTK_LAST_FLAG);
g_printk_ctrl_block_tmp.printk_region = 0;
g_printk_ctrl_block_tmp.section = KBOX_SECTION_PRINTK1;
(void)kbox_clear_region(KBOX_SECTION_PRINTK1);
(void)kbox_clear_region(KBOX_SECTION_PRINTK2);
}
g_printk_ctrl_block_tmp.start = 0;
g_printk_ctrl_block_tmp.end = 0;
g_printk_ctrl_block_tmp.valid_len = 0;
}
static void kbox_printk_init_info_not_first
(struct image_super_block_s *kbox_super_block)
{
KBOX_MSG("\n");
if (KBOX_TRUE ==
kbox_printk_format_is_order(kbox_super_block->printk_ctrl_blk,
kbox_super_block->printk_ctrl_blk +
1)) {
g_printk_ctrl_block_tmp.printk_region = 0;
g_printk_ctrl_block_tmp.section = KBOX_SECTION_PRINTK1;
} else if (KBOX_TRUE ==
kbox_printk_format_is_order
(kbox_super_block->printk_ctrl_blk + 1,
kbox_super_block->printk_ctrl_blk)) {
g_printk_ctrl_block_tmp.printk_region = 1;
g_printk_ctrl_block_tmp.section = KBOX_SECTION_PRINTK2;
} else {
kbox_printk_format(kbox_super_block->printk_ctrl_blk,
sizeof(struct printk_info_ctrl_block_s),
PRINTK_CURR_FLAG);
kbox_printk_format(kbox_super_block->printk_ctrl_blk + 1,
sizeof(struct printk_info_ctrl_block_s),
PRINTK_LAST_FLAG);
g_printk_ctrl_block_tmp.printk_region = 0;
g_printk_ctrl_block_tmp.section = KBOX_SECTION_PRINTK1;
(void)kbox_clear_region(KBOX_SECTION_PRINTK1);
(void)kbox_clear_region(KBOX_SECTION_PRINTK2);
}
g_printk_ctrl_block_tmp.start = 0;
}
static int kbox_printk_init_info(int kbox_proc_exist)
{
struct image_super_block_s kbox_super_block = { };
unsigned int read_len = 0;
unsigned int write_len = 0;
read_len =
kbox_read_from_ram(SECTION_KERNEL_OFFSET,
(unsigned int)sizeof(struct image_super_block_s),
(char *)&kbox_super_block, KBOX_SECTION_KERNEL);
if (read_len != sizeof(struct image_super_block_s)) {
KBOX_MSG("fail to get superblock data!\n");
return KBOX_FALSE;
}
if (kbox_proc_exist) {
kbox_printk_init_info_not_first(&kbox_super_block);
if (KBOX_TRUE !=
kbox_read_printk_info(g_printk_info_buf,
&g_printk_ctrl_block_tmp)) {
g_printk_ctrl_block_tmp.end = 0;
g_printk_ctrl_block_tmp.valid_len = 0;
}
} else {
kbox_printk_init_info_first(&kbox_super_block);
}
kbox_super_block.checksum = 0;
kbox_super_block.checksum =
~((unsigned char)
kbox_checksum((char *)&kbox_super_block,
(unsigned int)sizeof(kbox_super_block))) + 1;
write_len =
kbox_write_to_ram(SECTION_KERNEL_OFFSET,
(unsigned int)sizeof(struct image_super_block_s),
(char *)&kbox_super_block, KBOX_SECTION_KERNEL);
if (write_len <= 0) {
KBOX_MSG("fail to write superblock data!\n");
return KBOX_FALSE;
}
return KBOX_TRUE;
}
void kbox_output_printk_info(void)
{
unsigned int start_tmp = 0;
unsigned int end_tmp = 0;
unsigned int len_tmp = 0;
unsigned long flags = 0;
if (unlikely(!g_printk_info_buf || !g_printk_info_buf_tmp))
return;
if (g_printk_init_ok != KBOX_TRUE)
return;
spin_lock_irqsave(&g_printk_buf_lock, flags);
if (g_printk_ctrl_block_tmp.valid_len == 0) {
spin_unlock_irqrestore(&g_printk_buf_lock, flags);
return;
}
start_tmp = (g_printk_ctrl_block_tmp.start % SECTION_PRINTK_LEN);
end_tmp = ((g_printk_ctrl_block_tmp.end - 1) % SECTION_PRINTK_LEN);
len_tmp = g_printk_ctrl_block_tmp.valid_len;
if (start_tmp > end_tmp) {
memcpy(g_printk_info_buf_tmp,
g_printk_info_buf + start_tmp,
len_tmp - start_tmp);
memcpy(g_printk_info_buf_tmp + len_tmp - start_tmp,
g_printk_info_buf,
end_tmp + 1);
} else {
memcpy(g_printk_info_buf_tmp,
g_printk_info_buf + start_tmp,
len_tmp);
}
spin_unlock_irqrestore(&g_printk_buf_lock, flags);
(void)kbox_write_printk_info(g_printk_info_buf_tmp,
&g_printk_ctrl_block_tmp);
}
static void kbox_emit_printk_char(const char c)
{
if (unlikely(!g_printk_info_buf))
return;
*(g_printk_info_buf +
(g_printk_ctrl_block_tmp.end % SECTION_PRINTK_LEN)) = c;
g_printk_ctrl_block_tmp.end++;
if (g_printk_ctrl_block_tmp.end > SECTION_PRINTK_LEN)
g_printk_ctrl_block_tmp.start++;
if (g_printk_ctrl_block_tmp.end < SECTION_PRINTK_LEN)
g_printk_ctrl_block_tmp.valid_len++;
}
static int kbox_duplicate_printk_info(const char *printk_buf,
unsigned int buf_len)
{
unsigned int idx = 0;
unsigned long flags = 0;
spin_lock_irqsave(&g_printk_buf_lock, flags);
for (idx = 0; idx < buf_len; idx++)
kbox_emit_printk_char(*printk_buf++);
spin_unlock_irqrestore(&g_printk_buf_lock, flags);
return buf_len;
}
int kbox_dump_printk_info(const char *fmt, ...)
{
va_list args;
int num = 0;
char tmp_buf[TMP_BUF_SIZE] = { };
if (g_printk_init_ok != KBOX_TRUE)
return 0;
va_start(args, fmt);
num = vsnprintf(tmp_buf, sizeof(tmp_buf) - 1, fmt, args);
if (num >= 0)
(void)kbox_duplicate_printk_info(tmp_buf, num);
va_end(args);
return num;
}
static void kbox_printk_info_write(struct console *pconsole,
const char *printk_buf, unsigned int buf_len)
{
UNUSED(pconsole);
if (unlikely(!printk_buf))
return;
(void)kbox_duplicate_printk_info(printk_buf, buf_len);
}
int kbox_printk_init(int kbox_proc_exist)
{
int ret = KBOX_TRUE;
g_printk_info_buf = kmalloc(SECTION_PRINTK_LEN,
GFP_KERNEL);
if (IS_ERR(g_printk_info_buf) || !g_printk_info_buf) {
KBOX_MSG("kmalloc g_printk_info_buf fail!\n");
ret = -ENOMEM;
goto fail;
}
memset(g_printk_info_buf, 0, SECTION_PRINTK_LEN);
g_printk_info_buf_tmp = kmalloc(SECTION_PRINTK_LEN,
GFP_KERNEL);
if (IS_ERR(g_printk_info_buf_tmp) || !g_printk_info_buf_tmp) {
KBOX_MSG("kmalloc g_printk_info_buf_tmp fail!\n");
ret = -ENOMEM;
goto fail;
}
memset(g_printk_info_buf_tmp, 0, SECTION_PRINTK_LEN);
ret = kbox_printk_init_info(kbox_proc_exist);
if (ret != KBOX_TRUE) {
KBOX_MSG("kbox_printk_init_info failed!\n");
goto fail;
}
register_console(&g_printk_console);
g_printk_init_ok = KBOX_TRUE;
return ret;
fail:
kfree(g_printk_info_buf);
g_printk_info_buf = NULL;
kfree(g_printk_info_buf_tmp);
g_printk_info_buf_tmp = NULL;
return ret;
}
void kbox_printk_exit(void)
{
int ret = 0;
if (g_printk_init_ok != KBOX_TRUE)
return;
kfree(g_printk_info_buf);
g_printk_info_buf = NULL;
kfree(g_printk_info_buf_tmp);
g_printk_info_buf_tmp = NULL;
ret = unregister_console(&g_printk_console);
if (ret)
KBOX_MSG("unregister_console failed!\n");
}
/* SPDX-License-Identifier: GPL-2.0 */
/* Huawei iBMA driver.
* Copyright (c) 2017, Huawei Technologies Co., Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*/
#ifndef _KBOX_PRINTK_H_
#define _KBOX_PRINTK_H_
#include "kbox_ram_image.h"
struct printk_ctrl_block_tmp_s {
int printk_region;
enum kbox_section_e section;
unsigned int start;
unsigned int end;
unsigned int valid_len;/* valid length of printk section */
};
int kbox_printk_init(int kbox_proc_exist);
void kbox_output_printk_info(void);
int kbox_dump_printk_info(const char *fmt, ...);
void kbox_printk_exit(void);
#endif
// SPDX-License-Identifier: GPL-2.0
/* Huawei iBMA driver.
* Copyright (c) 2017, Huawei Technologies Co., Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*/
#include <linux/fs.h> /* everything... */
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <asm/ioctls.h>
#include <linux/slab.h>
#include "kbox_include.h"
#include "kbox_ram_drive.h"
#include "kbox_main.h"
#include "kbox_ram_image.h"
#include "kbox_ram_op.h"
#define KBOX_DEVICE_NAME "kbox"
#define KBOX_DEVICE_MINOR 255
static struct kbox_dev_s *g_kbox_dev;
static ssize_t kbox_read(struct file *filp, char __user *data, size_t count,
loff_t *ppos);
static ssize_t kbox_write(struct file *filp, const char __user *data,
size_t count, loff_t *ppos);
static long kbox_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
static int kbox_mmap(struct file *filp, struct vm_area_struct *vma);
static int kbox_open(struct inode *inode, struct file *filp);
static int kbox_release(struct inode *inode, struct file *filp);
const struct file_operations kbox_fops = {
.owner = THIS_MODULE,
.read = kbox_read,
.write = kbox_write,
.unlocked_ioctl = kbox_ioctl,
.mmap = kbox_mmap,
.open = kbox_open,
.release = kbox_release,
};
static struct miscdevice kbox_device = {
KBOX_DEVICE_MINOR,
KBOX_DEVICE_NAME,
&kbox_fops,
};
static ssize_t kbox_read(struct file *filp, char __user *data, size_t count,
loff_t *ppos)
{
int read_len = 0;
if (!filp || !data || !ppos) {
KBOX_MSG("input NULL point!\n");
return -EFAULT;
}
read_len = kbox_read_op((long long)(*ppos),
count,
data,
KBOX_SECTION_USER);
if (read_len < 0)
return -EFAULT;
*ppos += read_len;
return read_len;
}
static ssize_t kbox_write(struct file *filp, const char __user *data,
size_t count, loff_t *ppos)
{
int write_len = 0;
if (!filp || !data || !ppos) {
KBOX_MSG("input NULL point!\n");
return -EFAULT;
}
write_len = kbox_write_op((long long)(*ppos),
count, data, KBOX_SECTION_USER);
if (write_len < 0)
return -EFAULT;
*ppos += write_len;
return write_len;
}
static long kbox_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
UNUSED(filp);
if (kbox_ioctl_detail(cmd, arg) < 0)
return -ENOTTY;
return 0;
}
static int kbox_mmap(struct file *filp, struct vm_area_struct *vma)
{
if (!filp || !vma) {
KBOX_MSG("input NULL point!\n");
return -EFAULT;
}
if (kbox_mmap_ram(filp, vma, KBOX_SECTION_USER) < 0)
return -EFAULT;
return 0;
}
static int kbox_open(struct inode *pinode, struct file *filp)
{
UNUSED(pinode);
if ((g_kbox_dev) && (!atomic_dec_and_test(&g_kbox_dev->au_count))) {
atomic_inc(&g_kbox_dev->au_count);
KBOX_MSG("EBUSY\n");
return -EBUSY;
}
filp->private_data = (void *)g_kbox_dev;
return 0;
}
int kbox_release(struct inode *pinode, struct file *filp)
{
struct kbox_dev_s *kbox_dev = (struct kbox_dev_s *)filp->private_data;
UNUSED(pinode);
KBOX_MSG("\n");
if (kbox_dev)
atomic_inc(&kbox_dev->au_count);
return 0;
}
int kbox_drive_init(void)
{
int ret = 0;
KBOX_MSG("\n");
g_kbox_dev =
kmalloc(sizeof(struct kbox_dev_s), GFP_KERNEL);
if (!g_kbox_dev)
return -ENOMEM;
ret = misc_register(&kbox_device);
if (ret)
goto fail;
atomic_set(&g_kbox_dev->au_count, 1);
KBOX_MSG("ok!\n");
return ret;
fail:
kfree(g_kbox_dev);
g_kbox_dev = NULL;
return ret;
}
void kbox_drive_cleanup(void)
{
if (!g_kbox_dev)
return;
misc_deregister(&kbox_device);
kfree(g_kbox_dev);
g_kbox_dev = NULL;
}
/* SPDX-License-Identifier: GPL-2.0 */
/* Huawei iBMA driver.
* Copyright (c) 2017, Huawei Technologies Co., Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*/
#ifndef _KBOX_RAM_DRIVE_H_
#define _KBOX_RAM_DRIVE_H_
#include <linux/types.h>
#include <linux/atomic.h>
struct kbox_dev_s {
atomic_t au_count;
struct kbox_pci_dev_s *kbox_pci_dev;
};
int kbox_drive_init(void);
void kbox_drive_cleanup(void);
#endif
// SPDX-License-Identifier: GPL-2.0
/* Huawei iBMA driver.
* Copyright (c) 2017, Huawei Technologies Co., Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*/
#include "kbox_include.h"
#include "kbox_main.h"
#include "kbox_ram_image.h"
void __iomem *kbox_get_section_addr(enum kbox_section_e kbox_section)
{
void __iomem *kbox_addr = kbox_get_base_addr();
unsigned long kbox_len = kbox_get_io_len();
if (!kbox_addr || kbox_len == 0) {
KBOX_MSG("get kbox_addr or kbox_len failed!\n");
return NULL;
}
switch (kbox_section) {
case KBOX_SECTION_KERNEL:
return kbox_addr;
case KBOX_SECTION_PANIC:
return kbox_addr + SECTION_KERNEL_LEN;
case KBOX_SECTION_THREAD:
return kbox_addr + SECTION_KERNEL_LEN + SECTION_PANIC_LEN;
case KBOX_SECTION_PRINTK1:
return kbox_addr + (kbox_len - (2 * SECTION_PRINTK_LEN) -
SECTION_USER_LEN);
case KBOX_SECTION_PRINTK2:
return kbox_addr + (kbox_len - SECTION_PRINTK_LEN -
SECTION_USER_LEN);
case KBOX_SECTION_USER:
return kbox_addr + (kbox_len - SECTION_USER_LEN);
case KBOX_SECTION_ALL:
return kbox_addr;
default:
KBOX_MSG("input kbox_section error!\n");
return NULL;
}
}
unsigned long kbox_get_section_len(enum kbox_section_e kbox_section)
{
unsigned long kbox_len = kbox_get_io_len();
if (kbox_len == 0) {
KBOX_MSG("get kbox_len failed!\n");
return 0;
}
switch (kbox_section) {
case KBOX_SECTION_KERNEL:
return SECTION_KERNEL_LEN;
case KBOX_SECTION_PANIC:
return SECTION_PANIC_LEN;
case KBOX_SECTION_THREAD:
return (kbox_len - (2 * SECTION_PRINTK_LEN) -
SECTION_USER_LEN - SECTION_KERNEL_LEN -
SECTION_PANIC_LEN);
case KBOX_SECTION_PRINTK1:
case KBOX_SECTION_PRINTK2:
return SECTION_PRINTK_LEN;
case KBOX_SECTION_USER:
return SECTION_USER_LEN;
case KBOX_SECTION_ALL:
return kbox_len;
default:
KBOX_MSG("input kbox_section error!\n");
return 0;
}
}
unsigned long kbox_get_section_phy_addr(enum kbox_section_e kbox_section)
{
unsigned long kbox_phy_addr = kbox_get_base_phy_addr();
unsigned long kbox_len = kbox_get_io_len();
if (kbox_phy_addr == 0 || kbox_len == 0) {
KBOX_MSG("get kbox_phy_addr or kbox_len failed!\n");
return 0;
}
switch (kbox_section) {
case KBOX_SECTION_KERNEL:
return kbox_phy_addr;
case KBOX_SECTION_PANIC:
return kbox_phy_addr + SECTION_KERNEL_LEN;
case KBOX_SECTION_THREAD:
return kbox_phy_addr + SECTION_KERNEL_LEN + SECTION_PANIC_LEN;
case KBOX_SECTION_PRINTK1:
return kbox_phy_addr + (kbox_len - (2 * SECTION_PRINTK_LEN) -
SECTION_USER_LEN);
case KBOX_SECTION_PRINTK2:
return kbox_phy_addr + (kbox_len - SECTION_PRINTK_LEN -
SECTION_USER_LEN);
case KBOX_SECTION_USER:
return kbox_phy_addr + (kbox_len - SECTION_USER_LEN);
case KBOX_SECTION_ALL:
return kbox_phy_addr;
default:
KBOX_MSG("input kbox_section error!\n");
return 0;
}
}
/* SPDX-License-Identifier: GPL-2.0 */
/* Huawei iBMA driver.
* Copyright (c) 2017, Huawei Technologies Co., Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*/
#ifndef _KBOX_RAM_IMAGE_H_
#define _KBOX_RAM_IMAGE_H_
enum kbox_section_e {
KBOX_SECTION_KERNEL = 1,
KBOX_SECTION_PANIC = 2,
KBOX_SECTION_THREAD = 3,
KBOX_SECTION_PRINTK1 = 4,
KBOX_SECTION_PRINTK2 = 5,
KBOX_SECTION_USER = 6,
KBOX_SECTION_ALL = 7
};
#define KBOX_BIG_ENDIAN (0x2B)
#define KBOX_LITTLE_ENDIAN (0xB2)
#define IMAGE_VER (0x0001)
#define IMAGE_MAGIC (0xB202C086)
#define VALID_IMAGE(x) (IMAGE_MAGIC == (x)->magic_flag)
#define SLOT_NUM (8)
#define SLOT_LENGTH (16 * 1024)
#define MAX_RECORD_NO (0xFF)
#define MAX_USE_NUMS (0xFF)
#define PRINTK_NUM (2)
#define PRINTK_CURR_FLAG ("curr")
#define PRINTK_LAST_FLAG ("last")
#define PRINTK_FLAG_LEN (4)
struct panic_ctrl_block_s {
unsigned char use_nums;
unsigned char number;
unsigned short len;
unsigned int time;
};
struct thread_info_ctrl_block_s {
unsigned int thread_info_len;
};
struct printk_info_ctrl_block_s {
unsigned char flag[PRINTK_FLAG_LEN];
unsigned int len;
};
struct image_super_block_s {
unsigned char byte_order;
unsigned char checksum;
unsigned short version;
unsigned int magic_flag;
unsigned int panic_nums;
struct panic_ctrl_block_s panic_ctrl_blk[SLOT_NUM];
struct printk_info_ctrl_block_s printk_ctrl_blk[PRINTK_NUM];
struct thread_info_ctrl_block_s thread_ctrl_blk;
};
#define SECTION_KERNEL_LEN (sizeof(struct image_super_block_s))
#define SECTION_PANIC_LEN (8 * SLOT_LENGTH)
#define SECTION_PRINTK_LEN (512 * 1024)
#define SECTION_USER_LEN (2 * 1024 * 1024)
#define SECTION_KERNEL_OFFSET (0)
#define SECTION_PANIC_OFFSET SECTION_KERNEL_LEN
#define SECTION_THREAD_OFFSET (SECTION_KERNEL_LEN + SECTION_PANIC_LEN)
void __iomem *kbox_get_section_addr(enum kbox_section_e kbox_section);
unsigned long kbox_get_section_len(enum kbox_section_e kbox_section);
unsigned long kbox_get_section_phy_addr(enum kbox_section_e kbox_section);
#endif
This diff is collapsed.
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment