kernel misc

kernel misc

. include/linux/string.h

在kernel里使用string类的函数,比如strstr()等,这些函数声明在include/linux/string.h,include <linux/string.h>即可

. /dev/tty, tty driver blog

http://www.mysixue.com/?p=127#devconsole_devtty0_devtty1

. log ratelimit

ratelimit_state_init()

例如如下ratelimit_state_init()是设置5s内打印10条msg:

#define DEFAULT_RATELIMIT_INTERVAL (5 * HZ)
#define DEFAULT_RATELIMIT_BURST 10
static inline void ratelimit_default_init(struct ratelimit_state *rs)
{
return ratelimit_state_init(rs, DEFAULT_RATELIMIT_INTERVAL,
DEFAULT_RATELIMIT_BURST);
}

. kernel makefile desc

https://blog.51cto.com/weiguozhihui/1591397

. set_task_comm(tsk, "kthreadd");

. android在init.rc里将panic_on_oops默认设置为了1

write /proc/sys/kernel/panic_on_oops 1

. __ffs/fls

获取二进制形式数值第一个非0bit,从低位往高位检查,index从0开始:

	unsigned long bitmap = 0x90911010;
	/* first bit */
	printk("Bitmap: %#lx __ffs(): %ld\n", bitmap, __ffs(bitmap));
执行结果:
Bitmap: 0x90911010 __ffs(): 4

如果是ffs(),它和__ffs功能一样,结果只差1,比如上述__ffs结果为4,则ffs结果是5.
与ffs功能相对,fls是找到最后一个bit被设置为1的bit
fls(0)返回的结果是0

size_t/ssize_t type definition

4.19\include\linux\types.h
#ifndef _SIZE_T
#define _SIZE_T
typedef __kernel_size_t        size_t;
#endif

#ifndef _SSIZE_T
#define _SSIZE_T
typedef __kernel_ssize_t    ssize_t;
#endif
4.19\include\uapi\asm-generic\posix_types.h
#ifndef __kernel_size_t
#if __BITS_PER_LONG != 64
typedef unsigned int    __kernel_size_t;
typedef int        __kernel_ssize_t;
typedef int        __kernel_ptrdiff_t;
#else
typedef __kernel_ulong_t __kernel_size_t;
typedef __kernel_long_t    __kernel_ssize_t;
typedef __kernel_long_t    __kernel_ptrdiff_t;
#endif
#endif

 CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT

CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT: Temporary per-CPU printk log buffer size (12 => 4KB, 13 => 8KB)

The Linux kernel configuration item CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT:

  • prompt: Temporary per-CPU printk log buffer size (12 => 4KB, 13 => 8KB)
  • type: int
  • depends on: CONFIG_PRINTK
  • defined in init/Kconfig
  • found in Linux kernels: 4.11–4.20, 5.0–5.13, 5.13+HEAD

Help text

Select the size of an alternate printk per-CPU buffer where messages printed from usafe contexts are temporary stored. One example would be NMI messages, another one - printk recursion. The messages are copied to the main log buffer in a safe context to avoid a deadlock. The value defines the size as a power of 2.

Those messages are rare and limited. The largest one is when a backtrace is printed. It usually fits into 4KB. Select 8KB if you want to be on the safe side.

Examples: 17 => 128 KB for each CPU 16 => 64 KB for each CPU 15 => 32 KB for each CPU 14 => 16 KB for each CPU 13 => 8 KB for each CPU 12 => 4 KB for each CPU

from: https://cateee.net/lkddb/web-lkddb/PRINTK_SAFE_LOG_BUF_SHIFT.html

 

Linux kernel中的IS_ENABLED

首先在Kconfig中选中某个选项为y或m时, 在.config文件中就会由一个CONFIG_XXXXX=y或CONFIG_XXXXX=m, 并且会自动生成一个头文件autoconfig.h. 当选中为y时, 头文件中包含#define CONFIG_XXXXX 1, 当选中为m时, 头文件中包含#define CONFIG_XXXXX_MODULE 1, 当不选中是, 头文件中不包含相关语句.

from: https://blog.csdn.net/gngshn/article/details/69790798

在kernel里读一个文件(比如一个ko)

使用kernel_read_file_from_fd(),根据fd来read:

SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags)
{
    struct load_info info = { };
    void *hdr = NULL;
    int err;

    err = may_init_module();
    if (err)
        return err;

    pr_debug("finit_module: fd=%d, uargs=%p, flags=%i\n", fd, uargs, flags);

    if (flags & ~(MODULE_INIT_IGNORE_MODVERSIONS
              |MODULE_INIT_IGNORE_VERMAGIC))
        return -EINVAL;

    err = kernel_read_file_from_fd(fd, 0, &hdr, INT_MAX, NULL,
                       READING_MODULE);
    if (err < 0)
        return err;
    info.hdr = hdr;
    info.len = err;

    return load_module(&info, uargs, flags);
}

kernel延时函数

mdelay()

这个属于忙等待,不会让出CPU

msleep()

这个调用了后会让出CPU,不会忙等待

usleep_range(min, max)

这个调用了后会让出CPU,不会忙等待

/proc/kallsyms

如果只开了CONFIG_KALLSYMS,CONFIG_KALLSYMS_ALL没开,则/proc/kallsyms里将只会有函数symbol,全局变量symbol将没有。

 

kernel里读memory,比如dump一个寄存器指向的memory前后的数据

如下是一个示例,一次读16byte:

    unsigned char buf[16] = {0};
    if(!probe_kernel_read(buf,(const void *)task_struct_addr,sizeof(buf)))

 

list_for_each_entry()相关的操作都需要放在这个循环体里,如果是遍历了一遍,它会返回head,此时如果指向回了head,此循环将会结束,此时如果在循环体外有对p的相关操作,会导致debug异常call到brk_handler:

        list_for_each_entry(p, &mali_cmar_files_list, node) {
            if(p->pid == tsk->pid)
            {
                if(once)
                {
                    once = 0;
                    pr_info("unregister 0x%px files_struct ptr.\n", &tsk->files);
                    unregister_wp_bp((unsigned long)&tsk->files);
                }
                
                list_del_init(&p->node);
                kfree(p);
                p = NULL;
                
                break;
            }
        }

 

打印调用者

    printk("caller is %pS\n", __builtin_return_address(0));

 

打印结果:

[ 102.549872] caller is exit_files+0x150/0x310


module_param_named

#include <linux/moduleparam.h>
#include <linux/module.h>

bool inode_debug_ctrl = 0;

module_param_named(inode_debug_ctrl, dcache_debug_ctrl,
        bool, S_IRUGO | S_IWUSR);

 

比如我在4.19/fs/inode.c里加上上述这段后,开机后在如下路径下就有了dcache_debug_ctrl文件了:

console:/sys/module # find -name dcache_debug_ctrl

./inode/parameters/dcache_debug_ctrl

module_param

module_param(ignore_loglevel, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(ignore_loglevel,
         "ignore loglevel setting (prints all kernel messages to the console)");

 

根据pid获取对应的task_struct

系统中所有线程pid是唯一的,可以用如下API来获取对应线程的task_struct

find_task_by_pid_ns() 

get caller in kernel

__builtin_return_address(0)

 

GENMASK_ULL(h,l)

这个macro的功能是产生一个bits mask,比如GENMASK_ULL(43,0),将产生一个bit43-bit0均为1其它bit63-bit44为0的bits mask,BITS_PER_LONG_LONG的值定义为64:

#define GENMASK_ULL(h, l) \
    (((~0ULL) - (1ULL << (l)) + 1) & \
     (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h))))

 

在一个函数里加控制打印次数的log

如下示例,这部分控制打印这句log3秒内打印一次

    static DEFINE_RATELIMIT_STATE(ratelimit_state, 3 * HZ, 1);

    if (__ratelimit(&ratelimit_state))
        pr_info("in cpufreq_update_util: curr cpu is %d, cpu_of(rq) is %d.\n", raw_smp_processor_id(), cpu_of(rq));

 

%pS/%pS/%pF等指针格式打印符解析code位置

lib/vsprintf.c

int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
        case FORMAT_TYPE_PTR:
            str = pointer(fmt, str, end, va_arg(args, void *),
                      spec);

 

 

static noinline_for_stack
char *pointer(const char *fmt, char *buf, char *end, void *ptr,
          struct printf_spec spec)
{
    switch (*fmt) {
    case 'F':
    case 'f':
    case 'S':
    case 's':
        ptr = dereference_symbol_descriptor(ptr);
        /* Fallthrough */
    case 'B':
        return symbol_string(buf, end, ptr, spec, fmt);

 

KBUILD_EXTMOD

如果是源码内编译模块,KBUILD_EXTMOD变量为空。模块在编译过程中,如果依赖一个外部模块,需要使用KBUILD_EXTMOD来指定外部模块的符号文件Module.symvers,否则也会产生编译错误

from: https://zhuanlan.zhihu.com/p/409648724

添加一个新的kernel module Kconfig步骤

1.添加Kconfig文件,比如下面这样

config SYS_MISC
        tristate "SYS MISC"
        help
        sys misc.

 

2.如果是创建了新目录,在其父目录的Kconfig里添加source此Kconfig,这里的路径要从kernel根目录开始

3.在kernel config file里添加一个config,比如在arch/arm64/configs/里的一个config文件里添加CONFIG_SYS_MISC=m

printk()默认等级

printk()没有指定loglevel,则将使用默认loglevel,默认loglevel是KERN_WARNING(4)

打印一块buffer数据函数print_hex_dump()

void print_hex_dump(const char *level, const char *prefix_str, int prefix_type,
            int rowsize, int groupsize,
            const void *buf, size_t len, bool ascii)

level: kernel打印level

prefix_str: 自定义标识字串

prefix_type: 有如下几种,PREFIX_ADDRESS将打印地址

enum {
    DUMP_PREFIX_NONE,
    DUMP_PREFIX_ADDRESS,
    DUMP_PREFIX_OFFSET
};

rowsize: 一行打印多少字节,比如一行打印16 byte

groupsize: 表示一组几个自己,比如8,表示打印一个数值会有8byte

buf: 需要dump的buffer地址

ascii: 表示是否要将打印的数据的ascii码打印出来,1将打印,0则不打印

xchg()

xchg(*ptr, x){
    ret = *ptr;
    *ptr = x;
    return ret;}

它干了两件事,一是给一个指针赋值,二是获取了这个指针在赋值前的值。

 

 

 

 

 

 

 

posted @ 2021-08-05 16:25  aspirs  阅读(372)  评论(0编辑  收藏  举报