고급 개발자로 가는 길

Embedded/Linux Kernel

[Linux Kernel] 커널 디버깅용 Debugfs 드라이버 코드

다크엔지니어 2022. 2. 6. 13:51
반응형

우선 해당 드라이버 코드는 [LG전자 김동현님]의 코드를 참조한 것이다.

 

커널 소스를 수정하여 빌드 할 경우, 잘못 오류를 범하게 되면 커널 패닉이나,

시스템 락이 발생하여, 다시 이미지를 라이팅하는 상황이 발생할 수 있다.

 

그러한 경우를 방지하기 위해 Debugfs 드라이브 코드를 작성하여, 필요시에만 

수정된 소스를 커널에 반영하는 방식을 알아 보도록 할 것이다.

 

먼저 아래 소스를 참고하면 된다.

내용은 간단하다. get, set 을 통해 raspbian_debug_state 전역변수에 값을 쓰고 읽는다.

눈치를 채신분도 계실텐데, 우리는 저 전역변수를 통해 if 문으로 제어 할 것이다.

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
//#include <linux/reboot.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/memblock.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/cpu.h>
#include <linux/delay.h>
#include <asm/setup.h>
#include <linux/input.h>
#include <linux/debugfs.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
#include <linux/slub_def.h>
#include <linux/uaccess.h>
#include <asm/memory.h>

uint32_t raspbian_debug_state = 0x1000;
static struct dentry *rpi_kernel_debug_debugfs_root;

static int rpi_kernel_debug_stat_get(void *data, u64 *val)
{
    printk("===[%s][L:%d][val:%d]===\n", __func__, __LINE__, raspbian_debug_state);
    *val = raspbian_debug_state;

    return 0;
}

static int rpi_kernel_debug_stat_set(void *data, u64 val)
{
    raspbian_debug_state = (uint32_t)val;

    printk("[raspbian] [%s][L:%d], raspbian_debug_state[%lu],value[%lu]===\n", 
   __func__, __LINE__, (long unsigned int)raspbian_debug_state, (long unsigned int)val);

    return 0;
}


DEFINE_SIMPLE_ATTRIBUTE(rpi_kernel_debug_stat_fops, rpi_kernel_debug_stat_get, rpi_kernel_debug_stat_set, "%llu\n");

static int rpi_kernel_debug_debugfs_driver_probe(struct platform_device *pdev)
{
    printk("===[%s][L:%d]===\n", __func__, __LINE__);
    return 0;
}

static struct platform_driver rpi_kernel_debug_debugfs_driver = {
    .probe      = rpi_kernel_debug_debugfs_driver_probe,
    .driver     = {
        .owner  = THIS_MODULE,
        .name   = "rpi_debug",
    },
};

static int __init rpi_kernel_debug_debugfs_init(void)
{
    printk("===[%s][L:%d]===\n", __func__, __LINE__);

    rpi_kernel_debug_debugfs_root = debugfs_create_dir("rpi_debug", NULL);
    debugfs_create_file("val", S_IRUGO, rpi_kernel_debug_debugfs_root,
    NULL, &rpi_kernel_debug_stat_fops);

    return platform_driver_register(&rpi_kernel_debug_debugfs_driver);
}

late_initcall(rpi_kernel_debug_debugfs_init);

MODULE_DESCRIPTION("raspberrypi debug interface driver");
MODULE_AUTHOR("Austin Kim <austindh.kim@gmail.com>");
MODULE_LICENSE("GPL");

 

위 소스를 rpi_debugfs.c 로 저장하고 아래와 같이 Makefile 에 추가하여 빌드를 진행 할 것이다.

// 새로 추가
obj-y += rpi_debugfs.o
// 기존 코드
obj-$(CONFIG_BCM2835_POWER)     += bcm2835-power.o
obj-$(CONFIG_RASPBERRYPI_POWER) += raspberrypi-power.o
obj-$(CONFIG_SOC_BCM63XX)       += bcm63xx/
obj-$(CONFIG_SOC_BRCMSTB)       += brcmstb/

 

빌드 환경인 drivers/soc/bcm 에서

아래와 같이 .c 파일 추가 후 Makefile 에도 반영 된 모습이다.

 

추가 후 커널 빌드 후 이미지 설치가 완료되어 reboot 후

실행 시 실제 커널에 반영이 되었으므로,

/sys/kernel/debug/rpi_debug 가 추가 된 것을 확인 할 수 있다.

 

.c 소스코드에서 val 로 이름을 정했기에 val 을 읽으면 default 값 0x1000 을 확인 할 수 있다.

 

그렇다면, 1224 로 원하는 특정 값을 리다이렉션 하여 set 을 진행한다.

여기서 가장 중요한건, 1224는 필자 생일이다.

 

그렇다면, 실제 커널소스에 새로운 내용 추가 시 아래 if 문을 통해 set 으로 부담없이 반영 할 수 있다.

반응형