blob: 52a2146f77643d92416126da939ae31b6dc9426c [file] [log] [blame]
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/ioport.h>
#include <linux/poll.h>
#include <linux/delay.h>
#include <linux/wait.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <asm/io.h>
#include <linux/vmalloc.h>
#include <linux/soc/zte/rpmsg.h>
#include "pub_debug_info.h"
#include "ringbuf.h"
#include "ram_config.h"
#include "ZspTrace.h"
#include <linux/proc_fs.h>
#include <asm/barrier.h>
#include <asm/cache.h>
#include <asm/cacheflush.h>
#include <linux/seq_file.h>
#include <linux/ktime.h>
#include <linux/time.h>
#if defined(_USE_ZXIC_DEBUG_INFO)
/*******************************************************************************
* 宏定义 *
*******************************************************************************/
#define DEBUG_INFO_AP_MEM_LEN (0x2000)
#define DEBUG_INFO_READABLE_LEN (0x1400)
#define DEBUG_INFO_READ_TIME_MSECS (10000)
#define DEBUG_INFO_OK (0)
#define DEBUG_INFO_ERROR (-1)
#define DEBUG_READ_NOBLOCK (11)
#define DEBUG_INFO_MAX_ID_LEN (16+3)
#define DEBUG_INFO_MAX_DATA_LEN (128)
#define DEBUG_INFO_MAX_TIME_LEN (0)//(20+3)
#define DEBUG_INFO_MAX_DATE_LEN (19+3)
#define DEBUG_INFO_MAX_TOTAL_LEN (DEBUG_INFO_MAX_ID_LEN + DEBUG_INFO_MAX_DATA_LEN + DEBUG_INFO_MAX_TIME_LEN)
#define DEBUG_INFO_CORE_NUM (2)
/*******************************************************************************
* 结构体定义 *
*******************************************************************************/
typedef unsigned int UINT32;
typedef unsigned short UINT16;
typedef unsigned char UINT8;
typedef unsigned long UINT64;
typedef struct{
unsigned int head; /* 0x010a0a0a */
unsigned int datalen[DEBUG_INFO_CORE_NUM]; /* 数据内容长度 */
} T_SAVE_FILE_DATA;
/*******************************************************************************
* 全局变量 *
*******************************************************************************/
static struct semaphore debug_sem;
static int g_init_flag = 0;
UINT32 *g_ps_debug_write_cnt;
UINT32 *g_ps_debug_full_cnt;
UINT32 g_ps_debug_read_cnt;
UINT32 g_ps_debug_read_full_cnt;
unsigned long g_debug_read_cnt;
unsigned long g_ap_debug_write_cnt;
unsigned long g_ap_debug_read_cnt;
UINT8 *g_ap_debug_buffer_start;
UINT8 *g_ap_debug_buffer_read;
UINT8 *g_ap_debug_buffer_write;
UINT8 *g_ap_debug_buffer_end;
UINT8 *g_ps_debug_buffer_start;
UINT8 *g_ps_debug_buffer_end;
UINT8 *g_ps_debug_buffer_read;
static DEFINE_SPINLOCK(debug_info_lock);
static char g_ap_debug_buffer[DEBUG_INFO_AP_MEM_LEN];
unsigned long g_debug_read_state = 0;
/*******************************************************************************
* 内部函数定义 *
*******************************************************************************/
static int sc_debug_info_read_to_user(char *buf, size_t count);
static int sc_debug_info_record_from_user(const char *info, size_t count);
static void sc_debug_info_from_ps(void *buf, unsigned int len);
static void kernel_timer_timeout(struct timer_list *t);
static ssize_t debug_info_read(struct file *fp, char __user *buf, size_t count, loff_t *pos);
static ssize_t debug_info_write(struct file *fp, const char __user *buf, size_t count, loff_t *pos);
static int debug_info_open(struct inode *ip, struct file *fp);
static long debug_info_ioctl(struct file *fp, unsigned int cmd, unsigned long arg);
static int debug_info_release(struct inode *ip, struct file *fp);
extern u64 cop_time_get_value64(void);
extern int seq_write(struct seq_file *seq, const void *data, size_t len);
static DEFINE_TIMER(timer, kernel_timer_timeout);
static const struct file_operations debug_info_fops = {
.owner = THIS_MODULE,
.read = debug_info_read,
.write = debug_info_write,
.open = debug_info_open,
.unlocked_ioctl = debug_info_ioctl,
.release = debug_info_release,
};
static struct miscdevice debug_info_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "debug_info",
.fops = &debug_info_fops,
};
static void kernel_timer_timeout(struct timer_list *t)
{
if (debug_sem.count == 0)
{
up(&debug_sem);
}
/* Kernel Timer restart */
mod_timer(&timer, jiffies + msecs_to_jiffies(DEBUG_INFO_READ_TIME_MSECS));
}
/* Started by AICoder, pid:y6ffbg9a06ieda114a190b4cb0ff4417bd78c0f4 */
static ssize_t debug_info_read(struct file *fp, char __user *buf, size_t count, loff_t *pos)
{
int ret;
int rd_len;
if (g_debug_read_state != DEBUG_READ_NOBLOCK)
{
ret = down_interruptible(&debug_sem);
if (ret < 0)
{
return ret;
}
}
rd_len = sc_debug_info_read_to_user(buf, count);
return rd_len;
}
/* Ended by AICoder, pid:y6ffbg9a06ieda114a190b4cb0ff4417bd78c0f4 */
static ssize_t debug_info_write(struct file *fp, const char __user *buf, size_t count, loff_t *pos)
{
int wr_len = sc_debug_info_record_from_user(buf, count);
return wr_len;
}
static int debug_info_open(struct inode *ip, struct file *fp)
{
return 0;
}
/* Started by AICoder, pid:u635ed463ce5ab2145a109c3c0f54d149e6386b3 */
static long debug_info_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) {
if (cmd == DEBUG_READ_NOBLOCK) {
g_debug_read_state = DEBUG_READ_NOBLOCK;
} else {
// 如果命令不匹配,返回错误码
return -EINVAL;
}
// 记录调试信息
sc_debug_info_record("debug_info", "read noblock!\n");
return 0;
}
/* Ended by AICoder, pid:u635ed463ce5ab2145a109c3c0f54d149e6386b3 */
static int debug_info_release(struct inode *ip, struct file *fp)
{
return 0;
}
static int ap_log_proc_show(struct seq_file *m, void *v)
{
unsigned long writecnt = g_ap_debug_write_cnt;
if (writecnt > DEBUG_INFO_AP_MEM_LEN)
{
writecnt = DEBUG_INFO_AP_MEM_LEN;
}
seq_write(m, g_ap_debug_buffer_start, writecnt);
return 0;
}
static int ps_log_proc_show(struct seq_file *m, void *v)
{
unsigned long writecnt = 0;
unsigned long fulllcnt = 0;
writecnt = *(UINT32 *)g_ps_debug_write_cnt;
fulllcnt = *(UINT32 *)g_ps_debug_full_cnt;
if (fulllcnt > 0)
{
writecnt = PS_DEBUG_INFO_SIZE;
}
//__inval_dcache_area((void *)g_ps_debug_buffer_start, writecnt);
seq_write(m, g_ps_debug_buffer_start, writecnt);
return 0;
}
UINT32 skip_end_null(char *buf, size_t count)
{
UINT32 len = 0;
char *tmpbuf = buf;
while (count > 0)
{
if (*tmpbuf == '\0')
{
++len;
tmpbuf -= 1;
count -= 1;
}
else
{
break;
}
}
return len;
}
int sc_debug_info_read_ap(char *buf, size_t count)
{
UINT32 readLen = 0;
UINT32 updatelen = 0;
UINT32 readremainLen = 0;
UINT8 *readbuffaddr = 0;
UINT32 nullLen = 0;
char *tmpbuf = buf;
updatelen = g_ap_debug_write_cnt - g_ap_debug_read_cnt;
if (updatelen > DEBUG_INFO_AP_MEM_LEN)
updatelen = DEBUG_INFO_AP_MEM_LEN;
if(g_ap_debug_buffer_end - g_ap_debug_buffer_read >= updatelen)
{
readbuffaddr = g_ap_debug_buffer_read;
readLen = updatelen;
if (copy_to_user(tmpbuf , readbuffaddr, readLen))
{
return -EFAULT;
}
g_ap_debug_buffer_read += readLen;
}
else if(g_ap_debug_buffer_end - g_ap_debug_buffer_read < updatelen)
{
readbuffaddr = g_ap_debug_buffer_read;
readLen = g_ap_debug_buffer_end - readbuffaddr;
readremainLen = updatelen - readLen;
nullLen = skip_end_null(g_ap_debug_buffer_end - 1, readLen);
readLen = readLen - nullLen;
if (copy_to_user(tmpbuf, readbuffaddr, readLen))
{
return -EFAULT;
}
if (copy_to_user(tmpbuf + readLen, g_ap_debug_buffer_start, readremainLen))
{
return -EFAULT;
}
g_ap_debug_buffer_read = g_ap_debug_buffer_start + readremainLen;
}
else
{
panic("gaohf sc_debug_info_read_to_user error");
}
g_ap_debug_read_cnt = g_ap_debug_write_cnt;
return (readLen + readremainLen);
}
int sc_debug_info_read_ps(char *buf, size_t count)
{
UINT32 readLen = 0;
UINT32 readremainLen = 0;
UINT8 *readbuffaddr = 0;
UINT32 fulllcnt = 0;
UINT32 fulllcntdiff = 0;
unsigned long writecnt = 0;
UINT32 nullLen = 0;
char *tmpbuf = buf;
writecnt = *(volatile UINT32 *)g_ps_debug_write_cnt;
fulllcnt = *(volatile UINT32 *)g_ps_debug_full_cnt;
if (fulllcnt >= g_ps_debug_read_full_cnt)
{
fulllcntdiff = fulllcnt - g_ps_debug_read_full_cnt;
}
else
{
fulllcntdiff = 0xFFFFFFFF - g_ps_debug_read_full_cnt + fulllcnt;
}
if(fulllcntdiff >= 2)
{
readbuffaddr = g_ps_debug_buffer_start + writecnt;
readLen = g_ps_debug_buffer_end - readbuffaddr;
readremainLen = writecnt;
nullLen = skip_end_null(g_ps_debug_buffer_end - 1, readLen);
readLen = readLen - nullLen;
if (copy_to_user(tmpbuf, readbuffaddr, readLen))
{
return -EFAULT;
}
if (copy_to_user(tmpbuf + readLen, g_ps_debug_buffer_start, readremainLen))
{
return -EFAULT;
}
g_ps_debug_buffer_read = g_ps_debug_buffer_start + readremainLen;
}
else if(fulllcntdiff == 0)
{
readbuffaddr = g_ps_debug_buffer_read;
readLen = writecnt - g_ps_debug_read_cnt;;
if (copy_to_user(tmpbuf , readbuffaddr, readLen))
{
return -EFAULT;
}
g_ps_debug_buffer_read += readLen;
}
else if(fulllcntdiff == 1)
{
readLen = writecnt >= g_ps_debug_read_cnt ? writecnt : g_ps_debug_read_cnt;
readLen = PS_DEBUG_INFO_SIZE - readLen;
readbuffaddr = g_ps_debug_buffer_read;
nullLen = skip_end_null(g_ps_debug_buffer_end - 1, readLen);
readLen = readLen - nullLen;
if (copy_to_user(tmpbuf, readbuffaddr, readLen))
{
return -EFAULT;
}
readremainLen = writecnt;
if (copy_to_user(tmpbuf + readLen , g_ps_debug_buffer_start, readremainLen))
{
return -EFAULT;
}
g_ps_debug_buffer_read = g_ps_debug_buffer_start + readremainLen;
}
else
{
panic("gaohf sc_debug_info_read_to_user error");
}
g_ps_debug_read_cnt = writecnt;
g_ps_debug_read_full_cnt = fulllcnt;
return (readLen + readremainLen);
}
int sc_debug_info_read_to_user(char *buf, size_t count)
{
char *tmpbuf = 0;
int ret = 0;
int ap_len = 0;
int ps_len = 0;
T_SAVE_FILE_DATA fileDataHead;
if (g_init_flag == 0)
{
printk("debug_info not init.\n");
return DEBUG_INFO_ERROR;
}
if (count == 0 || buf == NULL )
{
printk("sc_debug_info_read_to_user count == 0 || buf == NULL \n");
return DEBUG_INFO_ERROR;
}
tmpbuf = buf + sizeof(T_SAVE_FILE_DATA);
ap_len = sc_debug_info_read_ap(tmpbuf, DEBUG_INFO_AP_MEM_LEN);
tmpbuf += ap_len;
ps_len = sc_debug_info_read_ps(tmpbuf, PS_DEBUG_INFO_SIZE);
fileDataHead.head = 0x010a0a0a;
fileDataHead.datalen[0] = ap_len;
fileDataHead.datalen[1] = ps_len;
if (copy_to_user(buf, &fileDataHead, sizeof(T_SAVE_FILE_DATA)))
{
printk("sc_debug_info_read_to_user copy_to_user error \n");
return -EFAULT;
}
return sizeof(T_SAVE_FILE_DATA) + ap_len + ps_len;
}
static int sc_debug_info_record_from_user(const char *info, size_t count)
{
UINT32 cnt = 0;
int spacelen;
int msg_len = 0;
struct tm tm;
time64_t time;
unsigned long used_space;
char buffer[DEBUG_INFO_MAX_TOTAL_LEN];
unsigned long flags;
UINT8 *tmp_write_addr = buffer;
if (g_init_flag == 0 || info == NULL)
{
printk("debug_info not init or sc_debug_info_record_from_user info is NULL\n");
return DEBUG_INFO_ERROR;
}
if(count > DEBUG_INFO_MAX_DATA_LEN + DEBUG_INFO_MAX_ID_LEN)
{
printk("debug_info data too long\n");
return DEBUG_INFO_ERROR;
}
time = ktime_get_real_seconds();
time64_to_tm(time, 0, &tm);
cnt = snprintf((char *)tmp_write_addr, DEBUG_INFO_MAX_DATE_LEN, "[%ld-%02d-%02d %d:%02d:%02d]", \
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
tmp_write_addr += cnt;
msg_len = cnt;
spin_lock_irqsave(&debug_info_lock, flags);
spacelen = g_ap_debug_buffer_end - g_ap_debug_buffer_write;
if (spacelen < msg_len + count)
{
g_ap_debug_write_cnt += spacelen;
memset(g_ap_debug_buffer_write, '\0', spacelen);
g_ap_debug_buffer_write = g_ap_debug_buffer_start;
}
memcpy(g_ap_debug_buffer_write, buffer, msg_len);
if (copy_from_user(g_ap_debug_buffer_write + msg_len, info, count))
return -EFAULT;
msg_len += count;
g_ap_debug_buffer_write += msg_len;
g_ap_debug_write_cnt += msg_len;
used_space = g_ap_debug_write_cnt - g_ap_debug_read_cnt;
spin_unlock_irqrestore(&debug_info_lock, flags);
if (used_space > DEBUG_INFO_READABLE_LEN)
{
if (debug_sem.count == 0)
{
up(&debug_sem);
}
}
return msg_len;
}
int sc_debug_info_vrecord(char *id, const char *format, va_list args)
{
int spacelen;
int msg_len = 0;
int cnt = 0;
unsigned long used_space;
struct tm tm;
time64_t time;
char buffer[DEBUG_INFO_MAX_TOTAL_LEN];
unsigned long flags;
UINT8 *tmp_write_addr = buffer;
time = ktime_get_real_seconds();
time64_to_tm(time, 0, &tm);
cnt = snprintf((char *)tmp_write_addr, DEBUG_INFO_MAX_DATE_LEN, "[%ld-%02d-%02d %d:%02d:%02d]", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
tmp_write_addr += cnt;
msg_len = cnt;
cnt = snprintf((char *)tmp_write_addr, DEBUG_INFO_MAX_ID_LEN, "[%s]",id);
tmp_write_addr += cnt;
msg_len += cnt;
msg_len += vsnprintf((char *)tmp_write_addr, DEBUG_INFO_MAX_DATA_LEN, format, args);
spin_lock_irqsave(&debug_info_lock, flags);
spacelen = g_ap_debug_buffer_end - g_ap_debug_buffer_write;
if (spacelen < DEBUG_INFO_MAX_TOTAL_LEN)
{
g_ap_debug_write_cnt += spacelen;
memset(g_ap_debug_buffer_write, '\0', spacelen);
g_ap_debug_buffer_write = g_ap_debug_buffer_start;
}
memcpy(g_ap_debug_buffer_write, buffer, msg_len);
g_ap_debug_buffer_write += msg_len;
g_ap_debug_write_cnt += msg_len;
used_space = g_ap_debug_write_cnt - g_ap_debug_read_cnt;
spin_unlock_irqrestore(&debug_info_lock, flags);
if (used_space > DEBUG_INFO_READABLE_LEN)
{
if (debug_sem.count == 0)
{
up(&debug_sem);
}
}
return msg_len;
}
EXPORT_SYMBOL(sc_debug_info_vrecord);
int sc_debug_info_record(char *id, const char *format, ...)
{
va_list args;
int r;
if (g_init_flag == 0)
{
printk("debug_info not init.\n");
return DEBUG_INFO_ERROR;
}
va_start(args, format);
r = sc_debug_info_vrecord(id, format, args);
va_end(args);
return r;
}
EXPORT_SYMBOL(sc_debug_info_record);
void early_debug_info_init(void)
{
g_ap_debug_buffer_start = g_ap_debug_buffer;
g_ap_debug_buffer_write = g_ap_debug_buffer_start;
g_ap_debug_buffer_read = g_ap_debug_buffer_start;
g_ap_debug_buffer_end = g_ap_debug_buffer + DEBUG_INFO_AP_MEM_LEN;
g_ap_debug_read_cnt = 0;
g_ap_debug_write_cnt = 0;
g_init_flag = 1;
printk("cap early_debug_info_init success \n");
}
static int __init debug_info_init(void)
{
int ret;
ret = misc_register(&debug_info_device);
if (ret)
{
printk("debug_info_init init.\n");
return DEBUG_INFO_ERROR;
}
g_ps_debug_write_cnt = (UINT32 *)ioremap(PS_DEBUG_INFO_LEN_ADDR_PA, PS_DEBUG_INFO_LEN_SIZE);
// printf("PS_DEBUG_INFO_LEN_ADDR_PA \n",)
g_ps_debug_full_cnt = (UINT32 *)((char *)g_ps_debug_write_cnt + 4);
g_ps_debug_buffer_start = (unsigned long)ioremap(PS_DEBUG_INFO_ADDR_PA, PS_DEBUG_INFO_SIZE);
g_ps_debug_buffer_read = g_ps_debug_buffer_start;
g_ps_debug_buffer_end = g_ps_debug_buffer_start + PS_DEBUG_INFO_SIZE;
g_ps_debug_read_cnt = 0;
g_ps_debug_read_full_cnt = 0;
sema_init(&debug_sem, 0);
proc_create_single("debug_info_cap", 0, NULL, ap_log_proc_show);
proc_create_single("debug_info_ap", 0, NULL, ps_log_proc_show);
mod_timer(&timer, jiffies + 1);
printk("cap debug_info_init success \n");
// g_init_flag = 1;
return 0;
}
static void __exit debug_info_exit(void)
{
misc_deregister(&debug_info_device);
del_timer(&timer);
}
module_init(debug_info_init);
module_exit(debug_info_exit);
MODULE_DESCRIPTION("debug_info driver");
MODULE_LICENSE("GPL");
#else
int sc_debug_info_record(char *id, const char *format, ...)
{
return 0;
}
#endif /* _USE_ZXIC_DEBUG_INFO */