"1. Introduction (based on S3C2440 Linux)
In the kernel debugging technology, the simplest is the use of printk. Its usage is similar to that of printf in C language applications. The application relies on the library in stdio. H, but there is no such library in the Linux kernel. Therefore, in the Linux kernel, using this printk requires a certain understanding of the implementation of the kernel.
The difference between printf and printk: printk will add a "" character at the beginning. The range of n is 0 ~ 7, indicating the level of this information.
When printk ("" ""...); N < console in_ Log level, this information can be printed out.
Initialize the console in printk. C (kernel) in the kernel file_ The level of loglevel is 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. View the level configuration through the command cat / proc / sys / kernel / printk:
# cat /proc/sys/kernel/printk
7 4 1 7
Among them, 7, 4, 1 and 7 correspond to console respectively_ loglevel、default_ message_ loglevel、minimum_ console_ loglevel、default_ console_ loglevel
3. Modify level configuration:
#Echo "" 1 4 1 7 "" > / proc / sys / kernel / printk change these four values when it is controlled by console_ When loglevel is set to 1, all debugging information will be printed.
4. Name and usage of printk function record
In the kernel file: kernel. H (include \ Linux), the names of the eight levels 0 ~ 7 are defined
#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])
Using printk:
① printk(KERN_ WARNING""there is a warning here!\ n"");// Note that there is no comma interval in the middle. ② printk(KERN_ DEBUG""%s %s %d\n"", __ FILE__, __ FUNCTION__, __ LINE__);
In ① and ②, we need to check the buffer log_ The data in buf can be used to see the printed information. Command #dmesg is required
one
two
three
four
five
six
seven
eight
nine
ten
eleven
twelve
#
# 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)
................................
You can also use Cat / proc / kmsg & run in the background and print out debugging information in real time. In ②__ FILE__, __ FUNCTION__, __ LINE__ Corresponding to the file, the function and the line. Very practical.
one
two
three
four
five
six
seven
eight
nine
# 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. Relationship between serial port and printk function:
Printk vprintk vscnprintf / / put the output information into the temporary buffer / / copy the output into log_ BUF. / / slightly process the data in the temporary buffer, and then write it to the log_ BUF / / for example, printk ("ABC") will get "" < 4 > ABC "", and then write to the log_ BUF / / you can use the dmesg command to log_ Print the data in buf to reproduce the kernel output. / / call the write function of the hardware to output release_ console_ sem call_ console_ Drivers / / from log_ BUF gets the data and calculates the print level_ call_ console_ drivers if ((msg_ log_ level < console_ Loglevel) / / print if the level is sufficient__ call_ console_ Drivers con - > write / / con is the console_ For the items in the drivers linked list, use the specific output function to view in drives / serial / S3C2410. C, and register a console structure in this function
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);}
The serial port output function will call S3C24XX_ serial_ console_ Putchar function
static int s3c24xx_ serial_ initconsole(void){ ........................... register_ console(&s3c24xx_ serial_ console); return 0;} static struct console s3c24xx_ serial_ console ={.name= S3C24XX_ SERIAL_ Name, / / this macro is defined as: ttysac. Device = UART_ console_ Device, / / init process. When the user program opens / dev / console, it will call. Flags = con_ Printbuffer, / / print and save in log before initializing the console_ Data in buf. Index = - 1, / / select the serial port, which is determined by the command in uboot. Write = S3C24XX_ serial_ console_ Write, / / console output function. Setup = S3C24XX_ serial_ console_ Setup / / serial port setting function};
This function is related to the hardware. Read the register to see whether the data is sent. Finally, write the data byte by byte into the register. The serial port controller of S3C2440 will automatically send the data
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);}
If uboot's console = ttysac0 is recognized as serial port 0 in Linux, there is the following code in / kernel / printk. C,
__ setup(""console="", console_ setup); static int __ init console_ setup(char *str){........ add_ preferred_ console(name, idx, options);}
When the kernel starts to execute, it will be called when it finds the command line parameter of "console =..."
Our other product: