259 lines
7.7 KiB
C
Executable File
259 lines
7.7 KiB
C
Executable File
/**
|
|
NVT logfile function
|
|
This file will handle NVT logfile function
|
|
@file logfile.c
|
|
@ingroup
|
|
@note
|
|
Copyright Novatek Microelectronics Corp. 2021. All rights 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 as
|
|
published by the Free Software Foundation.
|
|
*/
|
|
#include <linux/kobject.h>
|
|
#include <linux/string.h>
|
|
#include <linux/sysfs.h>
|
|
#include <linux/export.h>
|
|
#include <linux/init.h>
|
|
#include <linux/kexec.h>
|
|
#include <linux/profile.h>
|
|
#include <linux/stat.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/capability.h>
|
|
#include <linux/compiler.h>
|
|
#include <linux/uaccess.h>
|
|
#include <mach/nvt-io.h>
|
|
#include <linux/dma-buf.h>
|
|
#include <linux/sched/clock.h>
|
|
#include <plat/hardware.h>
|
|
#include <linux/module.h>
|
|
|
|
extern struct dma_buf *logfile_dmabuf;
|
|
|
|
#define MAKEFOURCC(ch0, ch1, ch2, ch3) ((u32)(u8)(ch0) | ((u32)(u8)(ch1) << 8) | ((u32)(u8)(ch2) << 16) | ((u32)(u8)(ch3) << 24 ))
|
|
#define LOGFILE_INTERFACE_VER 0x19112808
|
|
#define LOGFILE_SYS_ERROR_KEY MAKEFOURCC('S','Y','S','E')
|
|
#define PRINT_CTRL_CHAR_LEN 7
|
|
#define NVT_TIMER_TM0_CNT 0x108
|
|
|
|
enum log_flags {
|
|
LOG_ROLLBACK = 1, /* log already rollback */
|
|
};
|
|
|
|
typedef struct {
|
|
unsigned int InterfaceVer; ///< the Interface version of logfile ring buffer
|
|
unsigned int BufferStartAddr; ///< the buffer start address for store log msg
|
|
unsigned int BufferSize; ///< the total buffer size for store log msg
|
|
unsigned int DataIn; ///< the log msg input offset
|
|
unsigned int DataOut; ///< the log msg output offset
|
|
unsigned int BufferMapAddr; ///< the ioremap buffer start address for store log msg
|
|
unsigned int SysErr; ///< the kernel panic or some system error
|
|
unsigned int flags; ///< the log flags
|
|
unsigned int reserved[8]; ///< reserved
|
|
} LOGFILE_RINGBUF_HEAD;
|
|
|
|
static LOGFILE_RINGBUF_HEAD *g_logfile_buf = NULL;
|
|
static u64 g_timer0_offset = 0;
|
|
|
|
static int logfile_init(void)
|
|
{
|
|
unsigned long buf_addr, buf_size;
|
|
|
|
if (!logfile_dmabuf)
|
|
return -1;
|
|
|
|
/*
|
|
* Get buffer information from shared buffer object and
|
|
* map a page of the buffer object into kernel address space.
|
|
*/
|
|
buf_size = (unsigned long)logfile_dmabuf->size;
|
|
buf_addr = (unsigned long)dma_buf_kmap(logfile_dmabuf, buf_size/PAGE_SIZE);
|
|
g_logfile_buf = (LOGFILE_RINGBUF_HEAD *)buf_addr;
|
|
g_logfile_buf->BufferMapAddr = (unsigned int)g_logfile_buf + sizeof(LOGFILE_RINGBUF_HEAD);
|
|
|
|
/*
|
|
* Add interface version check and init log msg input/output offset
|
|
* here to store log msg before userspace application ready.
|
|
*/
|
|
g_logfile_buf->InterfaceVer = LOGFILE_INTERFACE_VER;
|
|
g_logfile_buf->BufferSize = buf_size - sizeof(LOGFILE_RINGBUF_HEAD);
|
|
g_logfile_buf->DataIn = 0;
|
|
g_logfile_buf->DataOut = 0;
|
|
|
|
/* Read nvt timer0 for log time string. */
|
|
g_timer0_offset = nvt_readl(NVT_TIMER_BASE_VIRT + NVT_TIMER_TM0_CNT);
|
|
g_timer0_offset *= 1000;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static size_t logfile_print_time(u64 ts, char *buf)
|
|
{
|
|
unsigned long rem_nsec;
|
|
|
|
rem_nsec = do_div(ts, 1000000000);
|
|
return sprintf(buf, "[%5lu.%06lu] ",
|
|
(unsigned long)ts, rem_nsec / 1000);
|
|
}
|
|
|
|
static int logfile_skip_head(const char *s)
|
|
{
|
|
char *in = (char*)s;
|
|
|
|
if (strncmp(s,"\033[0;3",5) == 0 || strncmp(s,"\033[1;3",5) == 0) {
|
|
in+= 6;
|
|
if (*in == 'm')
|
|
return 7;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void logfile_save_str(const char *s, size_t count, int kernel_space)
|
|
{
|
|
const char *instr;
|
|
char timeStr[40];
|
|
unsigned int timeLen = 0, strLen;
|
|
unsigned int DataOut, DataIn;
|
|
unsigned int instrLen, remainLen, DataSize;
|
|
LOGFILE_RINGBUF_HEAD *pbuf;
|
|
u64 ts_nsec;
|
|
int isAddTimeStrNext = 0;
|
|
static int isAddTimeStr = 1;
|
|
char temp_start_str[PRINT_CTRL_CHAR_LEN];
|
|
char temp_end_str[1];
|
|
int skip_len;
|
|
|
|
if (g_logfile_buf == NULL)
|
|
if (logfile_init() < 0)
|
|
return;
|
|
|
|
pbuf = g_logfile_buf;
|
|
|
|
/* Check interface version. */
|
|
if (pbuf->InterfaceVer != LOGFILE_INTERFACE_VER)
|
|
return;
|
|
|
|
ts_nsec = local_clock() + g_timer0_offset;
|
|
|
|
DataOut = pbuf->DataOut;
|
|
DataIn = pbuf->DataIn;
|
|
if (DataIn >= DataOut)
|
|
DataSize = DataIn - DataOut;
|
|
else
|
|
DataSize = pbuf->BufferSize + DataIn - DataOut;
|
|
|
|
instrLen = count;
|
|
instr = s;
|
|
if (count >= PRINT_CTRL_CHAR_LEN) {
|
|
if (kernel_space == 1)
|
|
memcpy((void *)temp_start_str, instr, PRINT_CTRL_CHAR_LEN);
|
|
else
|
|
copy_from_user((void *)temp_start_str, instr, PRINT_CTRL_CHAR_LEN);
|
|
|
|
skip_len = logfile_skip_head(temp_start_str);
|
|
instrLen -= skip_len;
|
|
instr += skip_len;
|
|
}
|
|
|
|
if (instrLen < 1 || instrLen > pbuf->BufferSize)
|
|
return;
|
|
|
|
if (kernel_space == 1)
|
|
memcpy((void *)temp_end_str, instr+instrLen-1, 1);
|
|
else
|
|
copy_from_user((void *)temp_end_str, instr+instrLen-1, 1);
|
|
|
|
/* Check new line and need to add time string at next line. */
|
|
if (temp_end_str[0] == '\n')
|
|
isAddTimeStrNext = 1;
|
|
|
|
/* Add log time string. */
|
|
if (isAddTimeStr) {
|
|
logfile_print_time(ts_nsec, timeStr);
|
|
timeLen = strlen(timeStr);
|
|
}
|
|
|
|
strLen = instrLen + timeLen;
|
|
if (DataIn + strLen < pbuf->BufferSize) {
|
|
if (isAddTimeStr) {
|
|
memcpy((void *)(DataIn + pbuf->BufferMapAddr), timeStr, timeLen);
|
|
if (kernel_space == 1)
|
|
memcpy((void *)(DataIn + pbuf->BufferMapAddr + timeLen), instr, strLen - timeLen);
|
|
else
|
|
copy_from_user((void *)(DataIn + pbuf->BufferMapAddr + timeLen), instr, strLen - timeLen);
|
|
} else {
|
|
if (kernel_space == 1)
|
|
memcpy((void *)(DataIn + pbuf->BufferMapAddr), instr, strLen);
|
|
else
|
|
copy_from_user((void *)(DataIn + pbuf->BufferMapAddr), instr, strLen);
|
|
}
|
|
DataIn += strLen;
|
|
} else {
|
|
remainLen = pbuf->BufferSize - DataIn;
|
|
if (isAddTimeStr) {
|
|
if (remainLen >= timeLen) {
|
|
memcpy((void *)(DataIn + pbuf->BufferMapAddr), timeStr, timeLen);
|
|
DataIn += timeLen;
|
|
remainLen -= timeLen;
|
|
if (kernel_space == 1)
|
|
memcpy((void *)DataIn + pbuf->BufferMapAddr, instr, remainLen);
|
|
else
|
|
copy_from_user((void *)DataIn + pbuf->BufferMapAddr, instr, remainLen);
|
|
/* Rollback log. */
|
|
DataIn = 0;
|
|
if (kernel_space == 1)
|
|
memcpy((void *)DataIn + pbuf->BufferMapAddr, instr+remainLen, instrLen - remainLen);
|
|
else
|
|
copy_from_user((void *)DataIn + pbuf->BufferMapAddr, instr+remainLen, instrLen - remainLen);
|
|
DataIn += (instrLen - remainLen);
|
|
} else {
|
|
memcpy((void *)(DataIn + pbuf->BufferMapAddr), timeStr, remainLen);
|
|
/* Rollback log. */
|
|
DataIn = 0;
|
|
memcpy((void *)DataIn + pbuf->BufferMapAddr, timeStr+remainLen, timeLen - remainLen);
|
|
DataIn += (timeLen - remainLen);
|
|
if (kernel_space == 1)
|
|
memcpy((void *)(DataIn + pbuf->BufferMapAddr + timeLen), instr, strLen - timeLen);
|
|
else
|
|
copy_from_user((void *)(DataIn + pbuf->BufferMapAddr + timeLen), instr, strLen - timeLen);
|
|
DataIn += instrLen;
|
|
}
|
|
} else {
|
|
if (kernel_space == 1)
|
|
memcpy((void *)DataIn + pbuf->BufferMapAddr, instr, remainLen);
|
|
else
|
|
copy_from_user((void *)DataIn + pbuf->BufferMapAddr, instr, remainLen);
|
|
/* Rollback log. */
|
|
DataIn = 0;
|
|
if (kernel_space == 1)
|
|
memcpy((void *)DataIn + pbuf->BufferMapAddr, instr+remainLen, instrLen - remainLen);
|
|
else
|
|
copy_from_user((void *)DataIn + pbuf->BufferMapAddr, instr+remainLen, instrLen - remainLen);
|
|
DataIn += (instrLen - remainLen);
|
|
}
|
|
pbuf->flags |= LOG_ROLLBACK;
|
|
}
|
|
pbuf->DataIn = DataIn;
|
|
|
|
isAddTimeStr = isAddTimeStrNext;
|
|
}
|
|
|
|
|
|
void logfile_save_syserr(void)
|
|
{
|
|
LOGFILE_RINGBUF_HEAD *pbuf;
|
|
|
|
if (g_logfile_buf == NULL)
|
|
if (logfile_init() < 0)
|
|
return;
|
|
|
|
pbuf = g_logfile_buf;
|
|
|
|
/* Add sys error key. */
|
|
pbuf->SysErr = LOGFILE_SYS_ERROR_KEY;
|
|
}
|
|
|
|
MODULE_AUTHOR("Novatek Microelectronics Corp.");
|
|
MODULE_LICENSE("GPL v2");
|
|
MODULE_DESCRIPTION("logfile function for NVT");
|
|
MODULE_VERSION("1.00.000"); |