--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Samsung TN debugging code
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/sec_debug.h>
+
+static char *last_kmsg_buffer;
+static size_t last_kmsg_size;
+
+void sec_debug_save_last_kmsg(unsigned char *head_ptr, unsigned char *curr_ptr, size_t buf_size)
+{
+ size_t size;
+ unsigned char *magickey_addr;
+
+ if (!head_ptr || !curr_ptr || head_ptr == curr_ptr) {
+ pr_err("%s: no data\n", __func__);
+ return;
+ }
+
+ if ((curr_ptr - head_ptr) <= 0) {
+ pr_err("%s: invalid args\n", __func__);
+ return;
+ }
+ size = (size_t)(curr_ptr - head_ptr);
+
+ magickey_addr = head_ptr + buf_size - (size_t)0x08;
+
+ /* provide previous log as last_kmsg */
+ if (*((unsigned long long *)magickey_addr) == SEC_LKMSG_MAGICKEY) {
+ pr_info("%s: sec_log buffer is full\n", __func__);
+ last_kmsg_size = (size_t)SZ_2M;
+ last_kmsg_buffer = kzalloc(last_kmsg_size, GFP_NOWAIT);
+ if (last_kmsg_size && last_kmsg_buffer) {
+ memcpy(last_kmsg_buffer, curr_ptr, last_kmsg_size - size);
+ memcpy(last_kmsg_buffer + (last_kmsg_size - size), head_ptr, size);
+ pr_info("%s: succeeded\n", __func__);
+ } else {
+ pr_err("%s: failed\n", __func__);
+ }
+ } else {
+ pr_info("%s: sec_log buffer is not full\n", __func__);
+ last_kmsg_size = size;
+ last_kmsg_buffer = kzalloc(last_kmsg_size, GFP_NOWAIT);
+ if (last_kmsg_size && last_kmsg_buffer) {
+ memcpy(last_kmsg_buffer, head_ptr, last_kmsg_size);
+ pr_info("%s: succeeded\n", __func__);
+ } else {
+ pr_err("%s: failed\n", __func__);
+ }
+ }
+}
+
+static ssize_t sec_last_kmsg_read(struct file *file, char __user *buf,
+ size_t len, loff_t *offset)
+{
+ loff_t pos = *offset;
+ ssize_t count;
+
+ if (pos >= last_kmsg_size)
+ return 0;
+
+ count = min(len, (size_t)(last_kmsg_size - pos));
+ if (copy_to_user(buf, last_kmsg_buffer + pos, count))
+ return -EFAULT;
+
+ *offset += count;
+ return count;
+}
+
+static const struct file_operations last_kmsg_file_ops = {
+ .owner = THIS_MODULE,
+ .read = sec_last_kmsg_read,
+};
+
+static int __init sec_last_kmsg_late_init(void)
+{
+ struct proc_dir_entry *entry;
+
+ if (!last_kmsg_buffer)
+ return 0;
+
+ entry = proc_create("last_kmsg", S_IFREG | 0444,
+ NULL, &last_kmsg_file_ops);
+ if (!entry) {
+ pr_err("%s: failed to create proc entry\n", __func__);
+ return 0;
+ }
+
+ proc_set_size(entry, last_kmsg_size);
+ return 0;
+}
+
+late_initcall(sec_last_kmsg_late_init);
--- /dev/null
+/*
+* Samsung debugging features for Samsung's SoC's.
+*
+* Copyright (c) 2014-2017 Samsung Electronics Co., Ltd.
+* http://www.samsung.com
+*
+* 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.
+*/
+
+#ifndef SEC_DEBUG_H
+#define SEC_DEBUG_H
+
+#ifdef CONFIG_SEC_DEBUG_LAST_KMSG
+#define SEC_LKMSG_MAGICKEY 0x0000000a6c6c7546
+extern void sec_debug_save_last_kmsg(unsigned char *head_ptr,
+ unsigned char *curr_ptr, size_t buf_size);
+#endif
+
+#endif /* SEC_DEBUG_H */
+
#include <soc/samsung/cal-if.h>
#endif
+#ifdef CONFIG_SEC_DEBUG_LAST_KMSG
+#include <linux/sec_debug.h>
+#endif
+
extern void register_hook_logbuf(void (*)(const char *, size_t));
extern void register_hook_logger(void (*)(const char *, const char *, size_t));
if (likely(dss_base.enabled && item->entry.enabled)) {
size_t last_buf;
- if (dbg_snapshot_check_eob(item, size))
+ if (dbg_snapshot_check_eob(item, size)) {
item->curr_ptr = item->head_ptr;
+#ifdef CONFIG_SEC_DEBUG_LAST_KMSG
+ *((unsigned long long *)(item->head_ptr + item->entry.size - (size_t)0x08)) = SEC_LKMSG_MAGICKEY;
+#endif
+ }
memcpy(item->curr_ptr, buf, size);
item->curr_ptr += size;
/* output the information of debug-snapshot */
dbg_snapshot_output();
+
+#ifdef CONFIG_SEC_DEBUG_LAST_KMSG
+ sec_debug_save_last_kmsg(dss_items[dss_desc.log_kernel_num].head_ptr,
+ dss_items[dss_desc.log_kernel_num].curr_ptr,
+ dss_items[dss_desc.log_kernel_num].entry.size);
+#endif
}
static int dbg_snapshot_init_dt_parse(struct device_node *np)