现在的位置: 首页 > 综合 > 正文

sec_log学习

2013年08月14日 ⁄ 综合 ⁄ 共 3168字 ⁄ 字号 评论关闭

学习了下 n7100代码中对kernel log保存代码:

kernel log保存:

1. init.setup 段初始化:

sec_log有如下实现

__setup("sec_log=", sec_log_setup);

说明如下
/*
 * Example usage: sec_log=256K@0x45000000
 * In above case, log_buf size is 256KB and its base address is
 * 0x45000000 physically. Actually, *(int *)(base - 8) is log_magic and
 * *(int *)(base - 4) is log_ptr. So we reserve (size + 8) bytes from
 * (base - 8).
 */

#define __setup(str, fn)                    \
    __setup_param(str, fn, fn, 0)
在内核booting过程中如果对比发现str=a的cmd会调用对应的fn(a)

具体实现如下

vmlinux.lds.h
#define INIT_SETUP(initsetup_align)                    \
        . = ALIGN(initsetup_align);                \
        VMLINUX_SYMBOL(__setup_start) = .;            \
        *(.init.setup)                        \
        VMLINUX_SYMBOL(__setup_end) = .;
#define INIT_CALLS                            \
        VMLINUX_SYMBOL(__initcall_start) = .;            \
        INITCALLS                        \
        VMLINUX_SYMBOL(__initcall_end) = .;

#define INIT_DATA_SECTION(initsetup_align)                \
    .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) {        \
        INIT_DATA                        \
        INIT_SETUP(initsetup_align)                \
        INIT_CALLS                        \
        CON_INITCALL                        \
        SECURITY_INITCALL                    \
        INIT_RAM_FS                        \
    }

对于__setup()定义的:
start_kernel()-->     setup_arch(&command_line);-->parse_early_param();
对于moudle_init定义的:
start_kernel() --> rest_init(); --> kernel_init() --> do_basic_setup() --> do_init_calls()
其中kenrel_init中:
static int __init kernel_init(void * unused)
{
    /*
     * Wait until kthreadd is all set-up.
     */
    wait_for_completion(&kthreadd_done);
    /*
     * init can allocate pages on any node
     */
    set_mems_allowed(node_states[N_HIGH_MEMORY]);
    /*
     * init can run on any cpu.
     */
    set_cpus_allowed_ptr(current, cpu_all_mask);

    cad_pid = task_pid(current);

    smp_prepare_cpus(setup_max_cpus);

    do_pre_smp_initcalls();
    lockup_detector_init();

    smp_init(); // enable multi-core
    sched_init_smp();

    do_basic_setup(); //init_machine也在这里调用
    ......
    init_post();//这里调用free_initmem将initmem释放回收:

        totalram_pages += free_area(__phys_to_pfn(__pa(__init_begin)),
                        __phys_to_pfn(__pa(__init_end)),
                        "init");
}

2. 对于ringbuffer 循环写的实现:
static inline void emit_sec_log_char(char c)
{
    if (sec_log_buf && sec_log_ptr) {
        sec_log_buf[*sec_log_ptr & (sec_log_size - 1)] = c;
        (*sec_log_ptr)++;
    }
}
这里& (sec_log_size - 1)  保证了在sec_log_size范围内 循环写(这要保证sec_log_size为1左移整数位的大小)

3.对上一次kmsg的保存:
static void __init sec_log_save_old(void)
{
    /* provide previous log as last_kmsg */
    last_kmsg_size =
        min((unsigned)(1 << CONFIG_LOG_BUF_SHIFT), *sec_log_ptr);
    last_kmsg_buffer = (char *)alloc_bootmem(last_kmsg_size);

    if (last_kmsg_size && last_kmsg_buffer) {
        unsigned i;
        for (i = 0; i < last_kmsg_size; i++)
            last_kmsg_buffer[i] =
                sec_log_buf[(*sec_log_ptr - last_kmsg_size +
                     i) & (sec_log_size - 1)];

        pr_info("%s: saved old log at %d@%p\n",
            __func__, last_kmsg_size, last_kmsg_buffer);
    } else
        pr_err("%s: failed saving old log %d@%p\n",
               __func__, last_kmsg_size, last_kmsg_buffer);
}
这里CONFIG_LOG_BUF_SHIFT是系统默认的比如 17 那么系统kmsg buffer默认为128K
不管sec_log_size多大,我们可以只保存lastmsg最大128K,其余的丢弃。
last_kmsg_size =
        min((unsigned)(1 << CONFIG_LOG_BUF_SHIFT), *sec_log_ptr);
这样如果sec_log_ptr跑的长度大于128K 我们只要128K 如果有效长度小于128K 我们取有效长度。

抱歉!评论已关闭.