diff --git a/kernel/common/console.h b/kernel/common/console.h index 87209f9a965d3065dbf7605f4248d81760c7808f..f7c4dd89f313e178f2c54e63d67d9d8b7b5e0d5a 100644 --- a/kernel/common/console.h +++ b/kernel/common/console.h @@ -54,7 +54,7 @@ extern "C" { /* Define two fixed console id for Console ID. */ #define CONSOLE_SERIAL 1 //串行方式 #define CONSOLE_TELNET 2 //远程登录 - +//POSIX 定义了 STDIN_FILENO、STDOUT_FILENO 和 STDERR_FILENO 来代替 0、1、2 #define LOSCFG_PLATFORM_CONSOLE #define STDIN 0 //标准输入 #define STDOUT 1 //标准输出 diff --git a/kernel/common/los_printf.c b/kernel/common/los_printf.c index ed4b0114c0db1dd8e34b64f1914b53d23a8f4ec5..51969968ede72cc9aaecbcfcbc3c7af0e56d3912 100644 --- a/kernel/common/los_printf.c +++ b/kernel/common/los_printf.c @@ -76,37 +76,37 @@ STATIC VOID ErrorMsg(VOID) const CHAR *p = "Output illegal string! vsnprintf_s failed!\n"; UartPuts(p, (UINT32)strlen(p), UART_WITH_LOCK); } -//串口输出,打印消息的本质就是从串口输出buf +//串口输出,打印消息的本质就是向串口输出buf STATIC VOID UartOutput(const CHAR *str, UINT32 len, BOOL isLock) { -#ifdef LOSCFG_SHELL_DMESG - if (!OsCheckUartLock()) { - UartPuts(str, len, isLock); +#ifdef LOSCFG_SHELL_DMESG //是否打开了 dmesg开关,打开了会写到文件中 var/log/dmesg 文件中 + if (!OsCheckUartLock()) {//是否被锁 + UartPuts(str, len, isLock);//直接写串口 } if (isLock != UART_WITHOUT_LOCK) { - (VOID)OsLogMemcpyRecord(str, len); + (VOID)OsLogMemcpyRecord(str, len);//写入dmesg缓存区 } #else - UartPuts(str, len, isLock); + UartPuts(str, len, isLock);//没有打开dmesg开关时,直接写串口 #endif } -//输出日志 +//输出控制处理 VOID OutputControl(const CHAR *str, UINT32 len, OutputType type) { switch (type) { case CONSOLE_OUTPUT: #ifdef LOSCFG_PLATFORM_CONSOLE - if (ConsoleEnable() == TRUE) { - (VOID)write(STDOUT_FILENO, str, (size_t)len); - break; + if (ConsoleEnable() == TRUE) {//POSIX 定义了 STDIN_FILENO、STDOUT_FILENO 和 STDERR_FILENO 来代替 0、1、2 + (VOID)write(STDOUT_FILENO, str, (size_t)len);//向控制台写日志, STDOUT_FILENO可理解为 fd = 1 的一个文件 + break;//在三个文件会在 VFS中默认创建 } #endif - /* fall-through */ + /* fall-through */ //落空的情况下,会接着向串口打印数据 case UART_OUTPUT: - UartOutput(str, len, UART_WITH_LOCK); + UartOutput(str, len, UART_WITH_LOCK);//向串口发送数据 break; case EXC_OUTPUT: - UartOutput(str, len, UART_WITHOUT_LOCK); + UartOutput(str, len, UART_WITHOUT_LOCK);//以串口不加锁的方式发送数据 break; default: break; @@ -120,41 +120,42 @@ STATIC VOID OsVprintfFree(CHAR *buf, UINT32 bufLen) (VOID)LOS_MemFree(m_aucSysMem0, buf); } } -// +//printf由 print 和 format 两个单词构成,格式化输出函数, 一般用于向标准输出设备按规定格式输出信息 +//鸿蒙由OsVprintf 来实现可变参数日志格式的输入 VOID OsVprintf(const CHAR *fmt, va_list ap, OutputType type) { INT32 len; - const CHAR *errMsgMalloc = "OsVprintf, malloc failed!\n"; - const CHAR *errMsgLen = "OsVprintf, length overflow!\n"; + const CHAR *errMsgMalloc = "OsVprintf, malloc failed!\n";//内存分配失败的错误日志,注意这是在打印函数里分配内存失败的情况 + const CHAR *errMsgLen = "OsVprintf, length overflow!\n";//所以要直接向串口发送字符串,不能再调用 printK(...)打印日志了. CHAR aBuf[SIZEBUF] = {0}; CHAR *bBuf = NULL; UINT32 bufLen = SIZEBUF; UINT32 systemStatus; bBuf = aBuf; - len = vsnprintf_s(bBuf, bufLen, bufLen - 1, fmt, ap); - if ((len == -1) && (*bBuf == '\0')) { - /* parameter is illegal or some features in fmt dont support */ + len = vsnprintf_s(bBuf, bufLen, bufLen - 1, fmt, ap);//C语言库函数之一,属于可变参数。用于向字符串中打印数据、数据格式用户自定义。 + if ((len == -1) && (*bBuf == '\0')) {//直接碰到字符串结束符或长度异常 + /* parameter is illegal or some features in fmt dont support */ //参数非法或fmt中的某些功能不支持 ErrorMsg(); return; } - while (len == -1) { + while (len == -1) {//处理((len == -1) && (*bBuf != '\0'))的情况 /* bBuf is not enough */ OsVprintfFree(bBuf, bufLen); bufLen = bufLen << 1; - if ((INT32)bufLen <= 0) { + if ((INT32)bufLen <= 0) {//异常情况下 向串口发送 UartPuts(errMsgLen, (UINT32)strlen(errMsgLen), UART_WITH_LOCK); return; } bBuf = (CHAR *)LOS_MemAlloc(m_aucSysMem0, bufLen); - if (bBuf == NULL) { + if (bBuf == NULL) {//分配内存失败,直接向串口发送错误信息 UartPuts(errMsgMalloc, (UINT32)strlen(errMsgMalloc), UART_WITH_LOCK); return; } - len = vsnprintf_s(bBuf, bufLen, bufLen - 1, fmt, ap); - if (*bBuf == '\0') { + len = vsnprintf_s(bBuf, bufLen, bufLen - 1, fmt, ap);//将ap按格式输出到buf中 + if (*bBuf == '\0') {//字符串结束符 /* parameter is illegal or some features in fmt dont support */ (VOID)LOS_MemFree(m_aucSysMem0, bBuf); ErrorMsg(); @@ -171,12 +172,12 @@ VOID OsVprintf(const CHAR *fmt, va_list ap, OutputType type) } OsVprintfFree(bBuf, bufLen); } - +//串口方式输入printf内容 VOID UartVprintf(const CHAR *fmt, va_list ap) { OsVprintf(fmt, ap, UART_OUTPUT); } - +//__attribute__((noinline)) 意思是告诉编译器 这是非内联函数 __attribute__((noinline)) VOID UartPrintf(const CHAR *fmt, ...) { va_list ap; @@ -192,7 +193,7 @@ __attribute__ ((noinline)) VOID dprintf(const CHAR *fmt, ...) OsVprintf(fmt, ap, CONSOLE_OUTPUT); va_end(ap); } - +//LK 注者的理解是 log kernel(内核日志) VOID LkDprintf(const CHAR *fmt, va_list ap) { OsVprintf(fmt, ap, CONSOLE_OUTPUT); @@ -246,7 +247,7 @@ VOID PrintExcInfo(const CHAR *fmt, ...) va_end(ap); } -#ifndef LOSCFG_SHELL_LK +#ifndef LOSCFG_SHELL_LK //log kernel 内核日志 VOID LOS_LkPrint(INT32 level, const CHAR *func, INT32 line, const CHAR *fmt, ...) { va_list ap; @@ -256,9 +257,9 @@ VOID LOS_LkPrint(INT32 level, const CHAR *func, INT32 line, const CHAR *fmt, ... } if ((level != LOS_COMMON_LEVEL) && ((level > LOS_EMG_LEVEL) && (level <= LOS_TRACE_LEVEL))) { - dprintf("[%s]", g_logString[level]); + dprintf("[%s]", g_logString[level]);//日志格式,先打印日志头 INFO ..... } - OsVprintf(fmt, ap, CONSOLE_OUTPUT); + OsVprintf(fmt, ap, CONSOLE_OUTPUT);//控制台打印 va_end(ap); } #endif diff --git a/kernel/include/los_printf.h b/kernel/include/los_printf.h index 5e6eebc6e2a7cf69758a2862eb67cea196364460..c81a3753e4dc504ca3031660c2e977f50f71ef86 100644 --- a/kernel/include/los_printf.h +++ b/kernel/include/los_printf.h @@ -49,6 +49,7 @@ extern "C" { #endif /* __cplusplus */ #endif /* __cplusplus */ +//见于\third_party\musl\kernel\include\*.h extern VOID LOS_LkPrint(INT32 level, const CHAR *func, INT32 line, const CHAR *fmt, ...); #define LOS_EMG_LEVEL 0 diff --git a/shell/full/include/dmesg.h b/shell/full/include/dmesg.h index c2a71b1f67877aba964d42719f9bfb14f72f9c4b..ca41342c455036c41a6acaee3b38e1472ed327d2 100644 --- a/shell/full/include/dmesg.h +++ b/shell/full/include/dmesg.h @@ -44,13 +44,13 @@ extern "C" { * @ingroup dmesg * Defalut dmesg buffer size. */ -#define KERNEL_LOG_BUF_SIZE (8 * 1024) +#define KERNEL_LOG_BUF_SIZE (8 * 1024) //默认缓存区大小 /** * @ingroup dmesg * Max dmesg buffer size to set. */ -#define MAX_KERNEL_LOG_BUF_SIZE (8 * 1024 * 10) +#define MAX_KERNEL_LOG_BUF_SIZE (8 * 1024 * 10) //设置缓冲区大小的上限 可以通过shell dmesg -s XX(K) 来改变缓冲区大小 /** * @ingroup dmesg diff --git a/shell/full/src/cmds/dmesg.c b/shell/full/src/cmds/dmesg.c index 65ec375c64181f43bc1738f310853a63492a8e0f..161f9dc196528193b471b954aad8deaa91fa4022 100644 --- a/shell/full/src/cmds/dmesg.c +++ b/shell/full/src/cmds/dmesg.c @@ -72,13 +72,13 @@ extern "C" { LITE_OS_SEC_BSS STATIC SPIN_LOCK_INIT(g_dmesgSpin);//dmesg自旋锁初始化 -STATIC DmesgInfo *g_dmesgInfo = NULL; //日志缓冲区描述符 -STATIC UINT32 g_logBufSize = 0; //日志buf大小,默认8K +STATIC DmesgInfo *g_dmesgInfo = NULL; //缓存区描述符 +STATIC UINT32 g_logBufSize = 0; //缓存buf大小,默认8K STATIC VOID *g_mallocAddr = NULL; //dmesg buf地址 STATIC UINT32 g_dmesgLogLevel = 3; //默认日志等级 LOS_ERR_LEVEL = 3 STATIC UINT32 g_consoleLock = 0; //控制台锁 STATIC UINT32 g_uartLock = 0; //串口锁 -STATIC const CHAR *g_levelString[] = { +STATIC const CHAR *g_levelString[] = {//缓存等级 "EMG", "COMMON", "ERR", @@ -481,7 +481,7 @@ STATIC VOID OsWriteTailToEnd(const CHAR *dst, UINT32 logLen) g_dmesgInfo->logSize += logLen; } } - +//dmesg中记录日志 INT32 OsLogMemcpyRecord(const CHAR *buf, UINT32 logLen) { UINT32 intSave; @@ -491,20 +491,20 @@ INT32 OsLogMemcpyRecord(const CHAR *buf, UINT32 logLen) LOS_SpinUnlockRestore(&g_dmesgSpin, intSave); return -1; } - if (g_dmesgInfo->logSize < g_logBufSize) { - if (g_dmesgInfo->logHead <= g_dmesgInfo->logTail) { - OsWriteTailToEnd(buf, logLen); + if (g_dmesgInfo->logSize < g_logBufSize) {//小于缓冲区大小的情况将怎么写入数据? + if (g_dmesgInfo->logHead <= g_dmesgInfo->logTail) {//说明head位置还有未读取的数据 + OsWriteTailToEnd(buf, logLen);//从写数据的位置开始写入 } else { - OsWriteTailToHead(buf, logLen); + OsWriteTailToHead(buf, logLen);//从读数据的位置开始写入 } - } else { - OsBufFullWrite(buf, logLen); + } else {//超过缓冲区大小的情况 + OsBufFullWrite(buf, logLen);//全覆盖方式写buf } LOS_SpinUnlockRestore(&g_dmesgSpin, intSave); return LOS_OK; } -//显示日志,写串口 +//打印缓存区内容 shell dmesg 命令调用 VOID OsLogShow(VOID) { UINT32 intSave; @@ -533,10 +533,10 @@ VOID OsLogShow(VOID) } } LOS_SpinUnlockRestore(&g_dmesgSpin, intSave); - UartPuts(p, i, UART_WITH_LOCK);//串口写入数据 + UartPuts(p, i, UART_WITH_LOCK);//向串口发送数据 free(p);//释放内存 } - +//设置缓存等级,一共五级,默认第三级 STATIC INT32 OsDmesgLvSet(const CHAR *level) { UINT32 levelNum, ret; @@ -558,18 +558,18 @@ STATIC INT32 OsDmesgLvSet(const CHAR *level) return -1; } } - +//设置缓冲区大小, shell dmesg -s 16K STATIC INT32 OsDmesgMemSizeSet(const CHAR *size) { UINT32 sizeVal; CHAR *p = NULL; - sizeVal = strtoul(size, &p, 0); - if (sizeVal > MAX_KERNEL_LOG_BUF_SIZE) { + sizeVal = strtoul(size, &p, 0);//C库函数将size所指向的字符串根据给定的base转换为一个无符号长整数(类型为 unsigned long int 型) + if (sizeVal > MAX_KERNEL_LOG_BUF_SIZE) {//不能超过缓存区的上限,默认80K goto ERR_OUT; } - if (!(LOS_DmesgMemSet(NULL, sizeVal))) { + if (!(LOS_DmesgMemSet(NULL, sizeVal))) {//调整缓存区大小 PRINTK("Set dmesg buf size %u success\n", sizeVal); return LOS_OK; } else { @@ -619,7 +619,7 @@ UINT32 LOS_DmesgMemSet(VOID *addr, UINT32 size) } return ret; } - +//LOS 开头为外部接口, 封装 OsDmesgRead INT32 LOS_DmesgRead(CHAR *buf, UINT32 len) { INT32 ret; @@ -637,13 +637,13 @@ INT32 LOS_DmesgRead(CHAR *buf, UINT32 len) LOS_SpinUnlockRestore(&g_dmesgSpin, intSave); return ret; } - +//将缓冲区内容写到指定文件 INT32 OsDmesgWrite2File(const CHAR *fullpath, const CHAR *buf, UINT32 logSize) { INT32 ret; - - INT32 fd = open(fullpath, O_CREAT | O_RDWR | O_APPEND, 0644); /* 0644:file right */ - if (fd < 0) { + //见于 third_party\NuttX\fs\vfs\fs_open.c + INT32 fd = open(fullpath, O_CREAT | O_RDWR | O_APPEND, 0644); /* 0644:file right */ //可读可写 ,并以append的方式写文件 + if (fd < 0) { //fd必须大于0 ,并且 0,1,2 被控制台占用 return -1; } ret = write(fd, buf, logSize); @@ -651,7 +651,7 @@ INT32 OsDmesgWrite2File(const CHAR *fullpath, const CHAR *buf, UINT32 logSize) return ret; } -#ifdef LOSCFG_FS_VFS +#ifdef LOSCFG_FS_VFS //是否支持虚拟文件系统 INT32 LOS_DmesgToFile(const CHAR *filename) { CHAR *fullpath = NULL; @@ -706,7 +706,7 @@ ERR_OUT2: free(fullpath); return ret; } -#else +#else //不支持虚拟文件系统直接串口输出 INT32 LOS_DmesgToFile(CHAR *filename) { (VOID)filename; @@ -716,6 +716,11 @@ INT32 LOS_DmesgToFile(CHAR *filename) #endif /**************************************************************** +dmesg是一种程序,用于检测和控制内核环缓冲。程序用来帮助用户了解系统的启动信息。 +Linux dmesg命令用于显示开机信息。鸿蒙沿用了linux dmesg命令 +kernel会将开机信息存储在ring buffer中。您若是开机时来不及查看信息,可利用dmesg来查看。 +开机信息亦保存在/var/log目录中,名称为dmesg的文件里 + 命令功能 dmesg命令用于控制内核dmesg缓存区。 @@ -761,24 +766,24 @@ INT32 OsShellCmdDmesg(INT32 argc, const CHAR **argv) goto ERR_OUT; } - if (!strcmp(argv[1], "-c")) { + if (!strcmp(argv[1], "-c")) {//打印缓存区内容并清空缓存区。 PRINTK("\n"); OsLogShow(); LOS_DmesgClear(); return LOS_OK; - } else if (!strcmp(argv[1], "-C")) { + } else if (!strcmp(argv[1], "-C")) {//清空缓存区 LOS_DmesgClear(); return LOS_OK; - } else if (!strcmp(argv[1], "-D")) { + } else if (!strcmp(argv[1], "-D")) {//关闭控制台打印 OsLockConsole(); return LOS_OK; - } else if (!strcmp(argv[1], "-E")) { + } else if (!strcmp(argv[1], "-E")) {//开启控制台打印 OsUnlockConsole(); return LOS_OK; - } else if (!strcmp(argv[1], "-L")) { + } else if (!strcmp(argv[1], "-L")) {//关闭串口打印 OsLockUart(); return LOS_OK; - } else if (!strcmp(argv[1], "-U")) { + } else if (!strcmp(argv[1], "-U")) {//开启串口打印 OsUnlockUart(); return LOS_OK; } @@ -796,9 +801,9 @@ INT32 OsShellCmdDmesg(INT32 argc, const CHAR **argv) return LOS_OK; } } else if (!strcmp(argv[1], "-l")) { - return OsDmesgLvSet(argv[2]); /* 2:index of parameters */ + return OsDmesgLvSet(argv[2]); /* 2:index of parameters */ //设置缓存等级,一共五级,默认第三级 } else if (!strcmp(argv[1], "-s")) { - return OsDmesgMemSizeSet(argv[2]); /* 2:index of parameters */ + return OsDmesgMemSizeSet(argv[2]); /* 2:index of parameters */ //设置缓冲区大小 } } diff --git a/zzz/git/push.sh b/zzz/git/push.sh index 1223e740033fa677ba2a9a3b9457c0dbe9d20ce1..473d737a03b5bd16b53728791069147500d7a225 100644 --- a/zzz/git/push.sh +++ b/zzz/git/push.sh @@ -1,5 +1,5 @@ git add -A -git commit -m '内核日志缓冲区 Dmesg 实现部分代码注释 +git commit -m 'prinf,可变参数是如何实现的? 用到了musl的哪些标准C库代码 搜索 @note_pic 可以查看全部字符图 搜索 @note_why 是注者尚未看明白的地方,如果您看明白了,请告诉注者完善 搜索 @note_thinking 是注者的思考和吐槽的地方 diff --git a/zzz/test/main.c b/zzz/test/main.c index b6c41eb5b20c72a1d4fc599e710ad82dcd748bed..c692ea5ddf4d9c4714e3b50296a4fa01096c067a 100644 --- a/zzz/test/main.c +++ b/zzz/test/main.c @@ -12,21 +12,19 @@ typedef struct LOS_DL_LIST { struct LOS_DL_LIST *pstNext; /**< Current node's pointer to the next node */ } LOS_DL_LIST; -//鸿蒙内核源码分析系列篇 https://blog.csdn.net/kuangyufei - void b(){ UINT8 w[3]={0}; PTE_T pte1BasePtr = 0x11100000; VADDR_T vaddr = 0x80738903; -#define MMU_DESCRIPTOR_L1_SMALL_SIZE 0x100000 //1M -#define MMU_DESCRIPTOR_L1_SMALL_MASK (MMU_DESCRIPTOR_L1_SMALL_SIZE - 1) -#define MMU_DESCRIPTOR_L1_SMALL_FRAME (~MMU_DESCRIPTOR_L1_SMALL_MASK) -#define MMU_DESCRIPTOR_L1_SMALL_SHIFT 20 -#define MMU_DESCRIPTOR_L1_SECTION_ADDR(x) ((x) & MMU_DESCRIPTOR_L1_SMALL_FRAME) -#define OS_TSK_HIGH_BITS 3U -#define OS_TSK_LOW_BITS (32U - OS_TSK_HIGH_BITS) //29 -#define OS_TSK_SORTLINK_LOGLEN OS_TSK_HIGH_BITS //3U + #define MMU_DESCRIPTOR_L1_SMALL_SIZE 0x100000 //1M + #define MMU_DESCRIPTOR_L1_SMALL_MASK (MMU_DESCRIPTOR_L1_SMALL_SIZE - 1) + #define MMU_DESCRIPTOR_L1_SMALL_FRAME (~MMU_DESCRIPTOR_L1_SMALL_MASK) + #define MMU_DESCRIPTOR_L1_SMALL_SHIFT 20 + #define MMU_DESCRIPTOR_L1_SECTION_ADDR(x) ((x) & MMU_DESCRIPTOR_L1_SMALL_FRAME) + #define OS_TSK_HIGH_BITS 3U + #define OS_TSK_LOW_BITS (32U - OS_TSK_HIGH_BITS) //29 + #define OS_TSK_SORTLINK_LOGLEN OS_TSK_HIGH_BITS //3U PTE_T l1Entry = pte1BasePtr + vaddr >> MMU_DESCRIPTOR_L1_SMALL_SHIFT; printf("pte1BasePtr ad: %x\n",&pte1BasePtr);