急急急!!这个最简单的linux内核的printk打印不出信息是怎么回事

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了急急急!!这个最简单的linux内核的printk打印不出信息是怎么回事相关的知识,希望对你有一定的参考价值。

#include<linux/init.h>
#include<linux/module.h>
#include<linux/kernel.h>
MODULE_LICENSE("GPL");

static int hello_init(void)

printk(KERN_ALERT "hello,world\n");
return 0;


static void hello_exit(void)

printk(KERN_ALERT "godbye!!!\n");


module_init(hello_init);
module_exit(hello_exit);
注:printk的优先级从最低设置到最高可无论用哪个优先级都不能在执行#iinsmod hello.ko后打印出我要的打印信息,但能正常加载进内核!!求解求解啊!!!急急急!!!!!!!

printk并不默认打印到终端,你加载进内核后,使用指令dmesg试试追问

可我是想把它打印到终端啊,怎么才能让它默认到系统的终端呢?。请求指教啊

参考技术A 用dmesg -c命令查看打印信息。
ctrl+alt+F1 切换到纯终端,可以在终端直接看到打印信息
参考技术B 内核模块需要先注册吧?你试试加上注册的代码并把它编译到内核空间里。你试试。 参考技术C 兄弟, 是printf吧!!追问

这不是C代码

linux内核调试技术之printk

1、简介(基于s3c2440 linux)

在内核调试技术之中,最简单的就是printk的使用了,它的用法和C语言应用程序中的printf使用类似,在应用程序中依靠的是stdio.h中的库,而在linux内核中没有这个库,所以在linux内核中,使用这个printk就要对内核的实现有一定的了解。

printf和printk的区别:printk会在开头处加上"<N>"样式的字符,N的范围是0~7,表示这个信息的级别。

 

当printk("<n>"......);中的n < console_loglevel 时候,这个信息才能被打印出来。 

在内核文件中Printk.c (kernel) 中初始化这个console_loglevel 的级别为7.

技术图片
/* printk‘s without a loglevel use this.. */
#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */

/* We show everything that is MORE important than this.. */
#define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */
#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */int console_printk[4] = {
    DEFAULT_CONSOLE_LOGLEVEL,    /* console_loglevel */
    DEFAULT_MESSAGE_LOGLEVEL,    /* default_message_loglevel */
    MINIMUM_CONSOLE_LOGLEVEL,    /* minimum_console_loglevel */
    DEFAULT_CONSOLE_LOGLEVEL,    /* default_console_loglevel */
};
技术图片

2、通过命令cat /proc/sys/kernel/printk查看等级配置:

# cat /proc/sys/kernel/printk
7 4 1 7

其中的 7 4 1 7,分别对应与:console_loglevel、default_message_loglevel、minimum_console_loglevel、default_console_loglevel 

3、修改等级配置:

#echo "1 4 1 7">/proc/sys/kernel/printk 改变这四个值,当被console_loglevel设置为1的时候,所有的调试信息都会被打印出来。

4、printk函数记录的名称及使用

 在内核文件:Kernel.h (includelinux) 定义了0~7这8个级别的名称

技术图片
#define   KERN_EMERG   "<0>"    /* system is unusable */
#define    KERN_ALERT    "<1>"    /* action must be taken immediately */
#define    KERN_CRIT     "<2>"    /* critical conditions */
#define    KERN_ERR      "<3>"    /* error conditions */
#define    KERN_WARNING  "<4>"    /* warning conditions */
#define    KERN_NOTICE   "<5>"    /* normal but significant condition*/
#define    KERN_INFO     "<6>"    /* informational*/
#define    KERN_DEBUG    "<7>"    /* debug-level messages */
#define console_loglevel      (console_printk[0])
#define default_message_loglevel (console_printk[1])
#define minimum_console_loglevel (console_printk[2])
#define default_console_loglevel (console_printk[3])
技术图片

使用printk:

① printk(KERN_WARNING"there is a warning here!
");//注意,中间没有逗号间隔。

② printk(KERN_DEBUG"%s %s %d ", __FILE__, __FUNCTION__, __LINE__);

在①和②中,我们需要查看缓冲区log_buf中的数据,才能看到打印出来的信息。需要使用命令 #dmesg

1
2
3
4
5
6
7
8
9
10
11
12
#
# dmesg
Linux version 2.6.22.6 (book@book-desktop) (gcc version 3.4.5) #19 Thu Dec 8 14:06:03 CST 2016
CPU: ARM920T [41129200] revision 0 (ARMv4T), cr=c0007177
Machine: SMDK2440
Memory policy: ECC disabled, Data cache writeback
On node 0 totalpages: 16384
  DMA zone: 128 pages used for memmap
  DMA zone: 0 pages reserved
  DMA zone: 16256 pages, LIFO batch:3
  Normal zone: 0 pages used for memmap
CPU S3C2440A (id 0x32440001)<br>................................

还可以使用 cat /proc/kmsg& 后台运行,实时打印出调试信息。在②中,__FILE__, __FUNCTION__, __LINE__分别对应的是那个文件,那个函数,第几行。非常实用。

1
2
3
4
5
6
7
8
9
# cat /proc/kmsg&
# ./firstdrvtest on
<7>/work/LinuxDrives/20.printk_debug/first_drv.c first_drv_open 23
<7>/work/LinuxDrives/20.printk_debug/first_drv.c first_drv_open 25
<7>/work/LinuxDrives/20.printk_debug/first_drv.c first_drv_open 27
# ./firstdrvtest off
<7>/work/LinuxDrives/20.printk_debug/first_drv.c first_drv_open 23
<7>/work/LinuxDrives/20.printk_debug/first_drv.c first_drv_open 25
<7>/work/LinuxDrives/20.printk_debug/first_drv.c first_drv_open 27

  

 

 

5、串口与printk函数的关系:   

技术图片
printk
    vprintk
        vscnprintf //先把输出信息放入临时BUFFER
                // Copy the output into log_buf.
                // 把临时BUFFER里的数据稍作处理,再写入log_buf
                // 比如printk("abc")会得到"<4>abc", 再写入log_buf
                // 可以用dmesg命令把log_buf里的数据打印出来重现内核的输出信息

        // 调用硬件的write函数输出
        release_console_sem    
            call_console_drivers
          //从log_buf得到数据,算出打印级别 _call_console_drivers if ((msg_log_level < console_loglevel)//如果级别足够则打印 __call_console_drivers con->write //con是console_drivers链表中的项,对用具体的输出函数 在drives/serial/s3c2410.c中查看

技术图片

在该函数中注册一个console结构体

static void s3c24xx_serial_console_write(struct console *co, const char *s,
unsigned int count)
{
uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar);
}

串口输出函数,会调用s3c24xx_serial_console_putchar函数

技术图片
static int s3c24xx_serial_initconsole(void)
{
    ...........................
    register_console(&s3c24xx_serial_console);
    return 0;
}
static struct console s3c24xx_serial_console =
{
.name = S3C24XX_SERIAL_NAME,//这个宏被定义为:TTYSAC
.device = uart_console_device, //init进程,用户程序打开/dev/console的时候会调用
.flags = CON_PRINTBUFFER,//打印还没有初始化化console前保存在log_buf里面的数据
.index = -1,//选择那个串口,由uboot中的命令决定
.write = s3c24xx_serial_console_write,//控制台输出函数
.setup = s3c24xx_serial_console_setup //串口设置函数
};
技术图片

 

这个函数和硬件相关,读取寄存器,看数据是否被发送完成,最后将数据一个字节一个字节的写入寄存器,s3c2440的串口控制器会自动把数据发送出去

技术图片
static void s3c24xx_serial_console_putchar(struct uart_port *port, int ch)

{
unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
while (!s3c24xx_serial_console_txrdy(port, ufcon))
barrier();
wr_regb(cons_uart, S3C2410_UTXH, ch);
}
技术图片

uboot的console=ttySAC0如果在linux中被识别出来是串口0的,在/kernel/printk.c中有一下代码,

技术图片
__setup("console=", console_setup);

static int __init console_setup(char *str)
{
........
  add_preferred_console(name, idx, options);
}
技术图片

 

内核开始执行时,会发现“console=...”的命令行参数时候,就会调用console_setup函数进行数据解析,对于命令行参数"console=ttySAC0",会解析出:设备名(name)为ttySAC,索引index为0,这些信息被保存在类型为console_cmdline、名称为console_cmdline的全局数组中(注意:数组名和数组的类型相同)

在后面的register_console(&s3c24xx_serial_console);的时候,会将s3c24xx_serial_console结构和console_cmdline数组中的设备进行比较。

①解析出来的name为S3C24XX_SERIAL_NAME 既“ttySAC”,而console_cmdline中的命令中的name也为“ttySAC”

②s3c24xx_serial_console结构体中的索引index为-1,表示使用命令行参数“console=ttySAC0”中的索引,index =  0

 

如果还想了解uboot的console=ttySAC0如果在linux中被识别出来是串口0的,可以看《嵌入式linux开发完全手册》Page 365

以上是关于急急急!!这个最简单的linux内核的printk打印不出信息是怎么回事的主要内容,如果未能解决你的问题,请参考以下文章

请大神帮我看看为啥我这个简单的小爬虫得不到数据?急急急急急!!!

在Linux中插上U盘,是怎么识别和挂载U盘的,Linux底层里发生了啥变化!急急急!

linux系统怎么在不影响使用的情况下再创建一个分区?急急急!!!

linux下USB识别不了……急急急……

Linux高手请进,急急急!Linux脚本,与二进制程序的异同

在C# WinForm 里WebBrowser这个控件能清楚Cookie和浏览器里的缓存么?要代码 急急急急急