driver_init()

 

리눅스 디바이스 드라이버 모델의 초기화

 

리눅스 디바이스 드라이버 모델을 표현하기위해 kobjectkset등이 사용된다.

  • sysfs는 kobject 및 kset 등으로 이루어진 하이라키 관계를 sysfs 가상 파일 시스템을 통해 표현되고 관리된다.

 

다음 그림은 디바이스 드라이버 모델의 초기화 호출 과정을 보여준다.

 

driver_init()

drivers/base/init.c

/**                                                                             
 * driver_init - initialize driver model.                                       
 *                                                                              
 * Call the driver model init functions to initialize their                     
 * subsystems. Called early from init/main.c.                                   
 */                                                                             
void __init driver_init(void)                                                   
{                                                                               
    /* These are the core pieces */                                             
    devtmpfs_init();                                                            
    devices_init();                                                             
    buses_init();                                                               
    classes_init();                                                             
    firmware_init();                                                            
    hypervisor_init();                                                          
                                                                                
    /* These are also core pieces, but must come after the                      
     * core core pieces.                                                        
     */                                                                         
    platform_bus_init();                                                        
    cpu_dev_init();                                                             
    memory_dev_init();                                                          
    container_dev_init();                                                       
    of_core_init();                                                             
}

리눅스 커널이 사용하는 드라이버 모델의 초기화를 수행한다.

  • 코드 라인 10에서 devtmpfs 파일 시스템을 마운트하고 kdevtmpfs 스레드를 생성하고 동작시킨다.
  • 코드 라인 11에서 디바이스를 표현 및 관리할 “/sys/devices” 및 “/sys/dev” 디렉토리를 생성한다. 또한 캐릭터 디바이스를 표현 및 관리할 “/sys/dev/block” 디렉토리와 블럭 디바이스를 표현 및 관리할 “/sys/dev/char” 디렉토리를 생성한다.
  • 코드 라인 12에서 버스 디바이스를 표현 및 관리할 “/sys/bus” 디렉토리를 생성한다. 또한 서브 시스템들이 등록될 “/sys/devices/system” 디렉토리도 생성한다.
  • 코드 라인 13에서 클래스 디바이스를 표현 및 관리할 “/sys/class” 디렉토리를 생성한다.
  • 코드 라인 14에서 펌웨어를 표현 및 관리할 “/sys/firmware” 디렉토리를 생성한다.
  • 코드 라인 15에서 하이퍼바이저를 표현 및 관리할 “/sys/hypervisor” 디렉토리를 생성한다.
  • 코드 라인 20에서 플랫폼 디바이스를 표현 및 관리할 “/sys/devices/platform” 디렉토리와 “/sys/bus/platform” 디렉토리를 생성한다.
  • 코드 라인 21에서 cpu 서브시스템의 cpu들을 표현 및 관리할  “/sys/devices/system/cpu” 디렉토리와 그 아래에 속성 파일들을 생성한다.
  • 코드 라인 22에서 hotplug 허용된 시스템에서 memory 서브시스템의 memory 블럭들을 표현 및 관리할  “/sys/devices/system/memory” 디렉토리와 그 아래에 속성 파일들을 생성한다.
  • 코드 라인 23에서 컨테이너 서브시스템의 컨테이너들을 표현 및 관리할 “/sys/devices/system/container” 디렉토리를 생성한다.
  • 코드 라인 24에서 디바이스 트리를 표현 및 관리할 “/sys/firmware/devicetree” 디렉토리를 생성하고, 그 이하에 모든 노드에 대한 디렉토리를 만든다. 그리고 각 노드의 속성들도 해당 노드 디렉토리에 각각 파일로 추가한다.

 

devices_init()

drivers/base/core.c

int __init devices_init(void)                                                   
{                                                                               
    devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);    
    if (!devices_kset)                                                          
        return -ENOMEM;                                                         
    dev_kobj = kobject_create_and_add("dev", NULL);                             
    if (!dev_kobj)                                                              
        goto dev_kobj_err;                                                      
    sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);           
    if (!sysfs_dev_block_kobj)                                                  
        goto block_kobj_err;                                                    
    sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);             
    if (!sysfs_dev_char_kobj)                                                   
        goto char_kobj_err;                                                     
                                                                                
    return 0;                                                                   
                                                                                
 char_kobj_err:                                                                 
    kobject_put(sysfs_dev_block_kobj);                                          
 block_kobj_err:                                                                
    kobject_put(dev_kobj);                                                      
 dev_kobj_err:                                                                  
    kset_unregister(devices_kset);                                              
    return -ENOMEM;                                                             
}

디바이스를 표현 및 관리할 “/sys/devices” 및 “/sys/dev” 디렉토리를 생성한다. 또한 캐릭터 디바이스를 표현 및 관리할 “/sys/dev/block” 디렉토리와 블럭 디바이스를 표현 및 관리할 “/sys/dev/char” 디렉토리를 생성한다.

  • 코드 라인 1~3에서 “devices” 이름을 갖는 kset를 생성하고 sysfs 루트에 추가한다.
  • 코드 라인 4~6에서 “dev” 이름을 갖는 kobject를 생성하고 sysfs 루트에 생성한다.
  • 코드 라인 7~9에서 “block” 이름을 갖는 kobject를 생성하고 “/sys/dev” 뒤에 추가한다.
  • 코드 라인 10~12에서 “char” 이름을 갖는 kobject를 생성하고 “/sys/dev” 뒤에 추가한다.

 

buses_init()

drivers/base/bus.c

int __init buses_init(void)                                                     
{                                                                               
    bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);               
    if (!bus_kset)                                                              
        return -ENOMEM;                                                         
                                                                                
    system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj);     
    if (!system_kset)                                                           
        return -ENOMEM;                                                         
                                                                                
    return 0;                                                                   
}

버스 디바이스를 표현 및 관리할 “/sys/bus” 디렉토리를 생성한다. 또한 서브 시스템들이 등록될 “/sys/devices/system” 디렉토리도 생성한다.

  • 코드 라인 3~5에서 “bus” 이름을 갖는 kset를 생성하고 sysfs 루트에 추가한다.
  • 코드 라인 7~9에서 “system” 이름을 갖는 kset를 생성하고 “/sys/devices” 뒤에 추가한다.

 

classes_init()

drivers/base/class.c

int __init classes_init(void)                                                   
{                                                                               
    class_kset = kset_create_and_add("class", NULL, NULL);                      
    if (!class_kset)                                                            
        return -ENOMEM;                                                         
    return 0;                                                                   
}

클래스 디바이스를 표현 및 관리할 “/sys/class” 디렉토리를 생성한다.

  • 코드 라인 3~5에서 “class” 이름을 갖는 kset를 생성하고 sysfs 루트에 추가한다.

 

firmware_init()

drivers/base/firmware.c

int __init firmware_init(void)                                                  
{                                                                               
    firmware_kobj = kobject_create_and_add("firmware", NULL);                   
    if (!firmware_kobj)                                                         
        return -ENOMEM;                                                         
    return 0;                                                                   
}

펌웨어를 표현 및 관리할 “/sys/firmware” 디렉토리를 생성한다.

  • 코드 라인 3~5에서 “firmware” 이름을 갖는 kobject를 생성하고 sysfs 루트에 추가한다.

 

 

hypervisor_init()

drivers/base/hypervisor.c

int __init hypervisor_init(void)                                                
{                                                                               
    hypervisor_kobj = kobject_create_and_add("hypervisor", NULL);               
    if (!hypervisor_kobj)                                                       
        return -ENOMEM;                                                         
    return 0;                                                                   
}

하이퍼바이저를 표현 및 관리할 “/sys/hypervisor” 디렉토리를 생성한다.

  • 코드 라인 3~5에서 “hypervisor” 이름을 갖는 kobject를 생성하고 sysfs 루트에 추가한다.

 

platform_bus_init()

drivers/base/platform.c

int __init platform_bus_init(void)                                              
{                                                                               
    int error;                                                                  
                                                                                
    early_platform_cleanup();                                                   
                                                                                
    error = device_register(&platform_bus);                                     
    if (error)                                                                  
        return error;                                                           
    error =  bus_register(&platform_bus_type);                                  
    if (error)                                                                  
        device_unregister(&platform_bus);                                       
    of_platform_register_reconfig_notifier();                                   
    return error;                                                               
}

플랫폼 디바이스를 표현 및 관리할 “/sys/devices/platform” 디렉토리와 “/sys/bus/platform” 디렉토리를 생성한다.

  • 코드 라인 5에서 early 플랫폼 디바이스를 리스트에서 제거한다.
  • 코드 라인 7~9에서 플랫폼 버스 디바이스를 등록한다.
    • 플랫폼 버스 디바이스를 표현하고 관리할 “/sys/devices/platform” 디렉토리를 생성한다.
  • 코드 라인 10~12에서 플랫폼 버스를 등록한다.
    • 플랫폼 버스를 표현하고 관리할 “/sys/bus/platform” 디렉토리를 생성한다.
  • 코드 라인 13에서 디바이스 트리를 통해 플랫폼 디바이스가 추가/삭제될 때 마다 호출되도록 notifier block에 of_platform_notify() 함수를 등록한다.

 

등록될 디바이스

struct device platform_bus = {                                                  
    .init_name  = "platform",                                                   
};                                                                              
EXPORT_SYMBOL_GPL(platform_bus);

 

등록될 버스

struct bus_type platform_bus_type = {                                           
    .name       = "platform",                                                   
    .dev_groups = platform_dev_groups,                                          
    .match      = platform_match,                                               
    .uevent     = platform_uevent,                                              
    .pm     = &platform_dev_pm_ops,                                             
};                                                                              
EXPORT_SYMBOL_GPL(platform_bus_type);

 

예) 다음은 platform 버스 디바이스 아래에 등록된 플랫폼 디바이스들이다.

$ ls /sys/devices/platform -la
drwxr-xr-x    3 root     root             0 May 16 15:00 20020000.pcie
drwxr-xr-x    3 root     root             0 Mar 15 09:55 50020000.pcie
drwxr-xr-x    3 root     root             0 May 16 15:00 60c00000.pcie
drwxr-xr-x    3 root     root             0 May 28 16:17 Fixed MDIO bus.0
drwxr-xr-x    2 root     root             0 May 28 16:17 alarmtimer
drwxr-xr-x    2 root     root             0 May 28 16:17 pmu
drwxr-xr-x    2 root     root             0 May 28 16:17 psci
drwxr-xr-x    2 root     root             0 May 28 16:17 secure_rtc
drwxr-xr-x    2 root     root             0 May 28 16:17 serial8250
drwxr-xr-x   70 root     root             0 Mar 30 15:41 soc
drwxr-xr-x    2 root     root             0 May 28 16:17 timer
-rw-r--r--    1 root     root          4096 May 28 16:17 uevent

 

early_platform_cleanup()

drivers/base/platform.c

/**                                                                             
 * early_platform_cleanup - clean up early platform code                        
 */                                                                             
void __init early_platform_cleanup(void)                                        
{                                                                               
    struct platform_device *pd, *pd2;                                           
                                                                                
    /* clean up the devres list used to chain devices */                        
    list_for_each_entry_safe(pd, pd2, &early_platform_device_list,              
                 dev.devres_head) {                                             
        list_del(&pd->dev.devres_head);                                         
        memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head));           
    }                                                                           
}

등록된 early 플랫폼 디바이스들을 리스트에서 제거한다.

  • early_platform_add_devices() 함수로 추가한 플랫폼 디바이스이다.
  • arm64에서는 early 플랫폼 디바이스를 등록하지 않는다.
  • 디바이스 트리를 통해 플랫폼 디바이스가 추가/삭제될 때 마다 of_platform_notify() 후크 함수가 호출되도록 등록한다.

 

of_platform_register_reconfig_notifier()

drivers/of/platform.c

void of_platform_register_reconfig_notifier(void)                               
{                                                                               
    WARN_ON(of_reconfig_notifier_register(&platform_of_notifier));              
}

디바이스 트리를 통해 플랫폼 디바이스가 추가/삭제될 때 마다 호출되도록 notifier block에 of_platform_notify() 함수를 등록한다.

  • CONFIG_OF_DYNAMIC 및 CONFIG_OF_ADDRESS 두 커널 옵션이 사용되어야 동작한다.
  • 참고: Platform Device | 문c

 

cpu_dev_init()

drivers/base/cpu.c

void __init cpu_dev_init(void)                                                  
{                                                                               
    if (subsys_system_register(&cpu_subsys, cpu_root_attr_groups))              
        panic("Failed to register CPU subsystem");                              
                                                                                
    cpu_dev_register_generic();                                                 
    cpu_register_vulnerabilities();                                             
}

cpu 서브시스템의 cpu들을 표현 및 관리할  “/sys/devices/system/cpu” 디렉토리와 그 아래에 속성 파일들을 생성한다.

  • 코드 라인 3~4에서 cpu 서브 시스템을 등록하고 그 밑에 속성들을 추가한다.
    • “/sys/devices/system/cpu” 디렉토리를 만들고 그 밑에 다음 속성들을 추가한다.
      • probe, release, online, possible, present, offline, isolated, nohz_full, modalias
  • 코드 라인 6~7에서 CONFIG_GENERIC_CPU_DEVICES 커널 옵션을 사용하는 경우 호출되지만 arm64 아키텍처는 관련 없다.

 

다음은 cpu 서브 시스템에 해당하는 버스 타입이다.

struct bus_type cpu_subsys = {                                                  
    .name = "cpu",                                                              
    .dev_name = "cpu",                                                          
    .match = cpu_subsys_match,                                                  
#ifdef CONFIG_HOTPLUG_CPU                                                       
    .online = cpu_subsys_online,                                                
    .offline = cpu_subsys_offline,                                              
#endif                                                                          
};                                                                              
EXPORT_SYMBOL_GPL(cpu_subsys);

 

다음은 cpu 서브 시스템에 추가될 속성들이다.

static struct attribute *cpu_root_attrs[] = {                                   
#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE                                            
    &dev_attr_probe.attr,                                                       
    &dev_attr_release.attr,                                                     
#endif                                                                          
    &cpu_attrs[0].attr.attr,                                                    
    &cpu_attrs[1].attr.attr,                                                    
    &cpu_attrs[2].attr.attr,                                                    
    &dev_attr_kernel_max.attr,                                                  
    &dev_attr_offline.attr,                                                     
    &dev_attr_isolated.attr,                                                    
#ifdef CONFIG_NO_HZ_FULL                                                        
    &dev_attr_nohz_full.attr,                                                   
#endif                                                                          
#ifdef CONFIG_GENERIC_CPU_AUTOPROBE                                             
    &dev_attr_modalias.attr,                                                    
#endif                                                                          
    NULL                                                                        
};

 

cpu 서브 시스템에 등록된 속성들을 간단히 알아본다.

  • probe
    • CONFIG_ARCH_CPU_PROBE_RELEASE 커널 옵션이 필요하다.
  • release
    • CONFIG_ARCH_CPU_PROBE_RELEASE 커널 옵션이 필요하다.
  • online
    • 현재 online 된 cpu를 보여준다. (장착되고 online된 상태의 cpu)
    • 예) 0-1
  • possible
    • possible cpu를 보여준다. (장착 되었거나 추가 장착 가능한 상태의 cpu)
    • 예) 0~3
  • present
    • preseent cpu를 보여준다. (장착된 상태의 cpu)
    • 예) 0~1
  • kernel_max
    • 현재 부팅된 커널이 지원하는 최고 cpu 번호 (NR_CPUS -1)
      • 예) 3
  • offline
    • offline된 cpu를 보여준다.
      • 예) 2~3
  • isolated
    • isolate된 cpu를 보여준다. (스케줄링에서 제외된 cpu)
      • 예) 기본적으로는 없으므로 아무것도 보여주지 않는다.
  • nohz_full
    • nohz full된 상태의 cpu를 보여준다.
    • CONFIG_NO_HZ_FULL 커널 옵션이 필요하다.
  • modalias
    • cpu 타입과 feature들을 보여준다.
    • 예) cpu:type:aarch64_be:feature:,0000,0001,0003,0004,0005,0006,0007
    • CONFIG_GENERIC_CPU_AUTOPROBE 커널 옵션이 필요하다.
    • arm, arm64, mips, s390, x86 등 많은 아키텍처들이 이 커널 옵션을 사용한다.

 

예) 다음은 cpu 서브 시스템에 등록된 cpu들과 속성들이다.

  • cpu0 ~ cpu3과 같은 cpu 디렉토리들은 cpu가 online/offline될 때마다 추가/제거된다.
$ ls /sys/devices/system/cpu -la
drwxr-xr-x    4 root     root             0 May 28 16:50 cpu0
drwxr-xr-x    4 root     root             0 May 28 16:50 cpu1
drwxr-xr-x    2 root     root             0 May 28 16:50 cpu2
drwxr-xr-x    2 root     root             0 May 28 16:50 cpu3
drwxr-xr-x    2 root     root             0 May 28 16:50 cpufreq
drwxr-xr-x    2 root     root             0 May 28 16:50 cpuidle
-r--r--r--    1 root     root          4096 May 28 16:50 isolated
-r--r--r--    1 root     root          4096 May 28 16:50 kernel_max
-r--r--r--    1 root     root          4096 May 28 16:50 modalias
-r--r--r--    1 root     root          4096 May 28 16:50 offline
-r--r--r--    1 root     root          4096 Mar 15 09:55 online
-r--r--r--    1 root     root          4096 May 28 16:50 possible
-r--r--r--    1 root     root          4096 May 28 16:50 present
-rw-r--r--    1 root     root          4096 May 28 16:50 uevent

 

예) 다음은 cpu0에 대한 속성들이다.

<pre “>$ ls /sys/devices/system/cpu/cpu0 -la drwxr-xr-x 5 root root 0 May 28 17:12 cache -r——– 1 root root 4096 May 28 17:12 frequency lrwxrwxrwx 1 root root 0 May 28 17:12 of_node -> ../../../../firmware/devicetree/base/cpus/cpu@0 -rw-r–r– 1 root root 4096 May 28 17:12 online lrwxrwxrwx 1 root root 0 May 28 17:12 subsystem -> ../../../../bus/cpu drwxr-xr-x 2 root root 0 May 28 17:12 topology -rw-r–r– 1 root root 4096 May 28 17:12 uevent

 

memory_dev_init()

drivers/base/memory.c

/*                                                                              
 * Initialize the sysfs support for memory devices...                           
 */                                                                             
int __init memory_dev_init(void)                                                
{                                                                               
    unsigned int i;                                                             
    int ret;                                                                    
    int err;                                                                    
    unsigned long block_sz;                                                     
                                                                                
    ret = subsys_system_register(&memory_subsys, memory_root_attr_groups);      
    if (ret)                                                                    
        goto out;                                                               
                                                                                
    block_sz = get_memory_block_size();                                         
    sections_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE;                      
                                                                                
    /*                                                                          
     * Create entries for memory sections that were found                       
     * during boot and have been initialized                                    
     */                                                                         
    mutex_lock(&mem_sysfs_mutex);                                               
    for (i = 0; i < NR_MEM_SECTIONS; i += sections_per_block) {                 
        /* Don't iterate over sections we know are !present: */                 
        if (i > __highest_present_section_nr)                                   
            break;                                                              
                                                                                
        err = add_memory_block(i);                                              
        if (!ret)                                                               
            ret = err;                                                          
    }                                                                           
    mutex_unlock(&mem_sysfs_mutex);                                             
                                                                                
out:                                                                            
    if (ret)                                                                    
        printk(KERN_ERR "%s() failed: %d\n", __func__, ret);                    
    return ret;                                                                 
}

hotplug 허용된 시스템(CONFIG_MEMORY_HOTPLUG_SPARSE 커널 옵션)에서 memory 서브시스템의 memory 블럭들을 표현 및 관리할  “/sys/devices/system/memory” 디렉토리와 그 아래에 속성 파일들을 생성한다.

  • 코드 라인 11~13에서 memory 서브시스템을 등록하고 관련 속성을 추가한다.
    • “/sys/devices/system/memory” 디렉토리를 만들고 그 밑에 다음 속성들을 추가한다.
      • probe, soft_offline_page, block_size_bytes, auto_online_blocks
  • 코드 라인에서 15~16에서 블럭당 섹션 수를 산출한다.
    • arm64는 블럭과 섹션 크기가 같으므로 항상 1이다.
  • 코드 라인 22~32에서 전체 섹션에 대해서 블럭 크기만큼 증가시키며 memory 서브시스템 밑에 메모리 블럭(디렉토리 및 파일들)을 추가한다.

 

다음은 memory 서브 시스템에 해당하는 버스 타입이다.

static struct bus_type memory_subsys = {                                        
    .name = MEMORY_CLASS_NAME,                                                  
    .dev_name = MEMORY_CLASS_NAME,                                              
    .online = memory_subsys_online,                                             
    .offline = memory_subsys_offline,                                           
};

 

다음은 memory 서브 시스템에 추가될 속성들이다.

static struct attribute *memory_root_attrs[] = {                                
#ifdef CONFIG_ARCH_MEMORY_PROBE                                                 
    &dev_attr_probe.attr,                                                       
#endif                                                                          
                                                                                
#ifdef CONFIG_MEMORY_FAILURE                                                    
    &dev_attr_soft_offline_page.attr,                                           
    &dev_attr_hard_offline_page.attr,                                           
#endif                                                                          
                                                                                
    &dev_attr_block_size_bytes.attr,                                            
    &dev_attr_auto_online_blocks.attr,                                          
    NULL                                                                        
};                                                                              
                                                                                
static struct attribute_group memory_root_attr_group = {                        
    .attrs = memory_root_attrs,                                                 
};                                                                              
                                                                                
static const struct attribute_group *memory_root_attr_groups[] = {              
    &memory_root_attr_group,                                                    
    NULL,                                                                       
};

 

예) 다음은 memory 서브 시스템에 등록된 메모리 블럭들과 속성들이다.

  • memory0 ~ memory27과 같은 memory 블럭 디렉토리들은 memory가 online/offline될 때마다 추가/제거된다.
$ ls -la
-r--r--r--  1 root root 4096  5월 29 14:14 block_size_bytes
--w-------  1 root root 4096  5월 29 14:14 hard_offline_page
drwxr-xr-x  3 root root    0  5월 29 14:18 memory0
drwxr-xr-x  3 root root    0  5월 29 13:36 memory1
...
drwxr-xr-x  3 root root    0  5월 29 13:36 memory27
drwxr-xr-x  2 root root    0  5월 29 14:14 power
--w-------  1 root root 4096  5월 29 14:14 probe
--w-------  1 root root 4096  5월 29 14:14 soft_offline_page
-rw-r--r--  1 root root 4096  5월 29 13:36 uevent

 

예) 다음은 memory0 블럭에 대한 속성들이다.

$ ls /sys/devices/system/memory/memory0 -la
lrwxrwxrwx 1 root root 0 5월 29 14:18 node0 -> ../../node/node0
-rw-r--r-- 1 root root 4096 5월 29 14:18 online
-r--r--r-- 1 root root 4096 5월 29 14:18 phys_device
-r--r--r-- 1 root root 4096 5월 29 14:18 phys_index
drwxr-xr-x 2 root root 0 5월 29 14:18 power
-r--r--r-- 1 root root 4096 5월 29 14:18 removable
-rw-r--r-- 1 root root 4096 5월 29 14:18 state
lrwxrwxrwx 1 root root 0 5월 29 14:18 subsystem -> ../../../../bus/memory
-rw-r--r-- 1 root root 4096 5월 29 14:18 uevent
-r--r--r-- 1 root root 4096 5월 29 14:18 valid_zones

 

get_memory_block_size()

drivers/base/memory.c

static unsigned long get_memory_block_size(void)                                
{                                                                               
    unsigned long block_sz;                                                     
                                                                                
    block_sz = memory_block_size_bytes();                                       
                                                                                
    /* Validate blk_sz is a power of 2 and not less than section size */        
    if ((block_sz & (block_sz - 1)) || (block_sz < MIN_MEMORY_BLOCK_SIZE)) {    
        WARN_ON(1);                                                             
        block_sz = MIN_MEMORY_BLOCK_SIZE;                                       
    }                                                                           
                                                                                
    return block_sz;                                                            
}

메모리 블럭 사이즈를 반환한다.

  • 아키텍처에 별도의 구현이 없는 디폴트: 섹션 사이즈(arm64)

 

container_dev_init()

drivers/base/container.c

void __init container_dev_init(void)                                            
{                                                                               
    int ret;                                                                    
                                                                                
    ret = subsys_system_register(&container_subsys, NULL);                      
    if (ret)                                                                    
        pr_err("%s() failed: %d\n", __func__, ret);                             
}

컨테이너 서브시스템의 컨테이너들을 표현 및 관리할 “/sys/devices/system/container” 디렉토리를 생성한다.  (추가할 속성들은 없다)

 

다음은 container 서브 시스템에 해당하는 버스 타입이다.

struct bus_type container_subsys = {                                            
    .name = CONTAINER_BUS_NAME,                                                 
    .dev_name = CONTAINER_BUS_NAME,                                             
    .online = trivial_online,                                                   
    .offline = container_offline,                                               
};

 

of_core_init()

drivers/of/base.c

void __init of_core_init(void)                                                  
{                                                                               
    struct device_node *np;                                                     
                                                                                
    /* Create the kset, and register existing nodes */                          
    mutex_lock(&of_mutex);                                                      
    of_kset = kset_create_and_add("devicetree", NULL, firmware_kobj);           
    if (!of_kset) {                                                             
        mutex_unlock(&of_mutex);                                                
        pr_err("failed to register existing nodes\n");                          
        return;                                                                 
    }                                                                           
    for_each_of_allnodes(np)                                                    
        __of_attach_node_sysfs(np);                                             
    mutex_unlock(&of_mutex);                                                    
                                                                                
    /* Symlink in /proc as required by userspace ABI */                         
    if (of_root)                                                                
        proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base");     
}

디바이스 트리를 표현 및 관리할 “/sys/firmware/devicetree” 디렉토리를 생성하고, 그 이하에 모든 노드에 대한 디렉토리를 만든다. 그리고 각 노드의 속성들도 해당 노드 디렉토리에 각각 파일로 추가한다.

  • 코드 라인 8~12에서 “devicetree” kset을 생성하고 “/sys/firmware”에 추가한다.
    • “/sys/firmware/devicetree” 디렉토리를 만든다.
  • 코드 라인 13~14에서 “/sys/firmware/devicetree” 디렉토리 밑에 읽어온 디바이스 트리 노드들과 속성들을 추가한다.
    • 첫 번째 루트 노드는 base 라는 이름의 디렉토리에 존재한다.
  • 코드 라인 18~19에서 “/sys/firmware/devicetree/base”를 가리키는 심볼릭 링크를 proc 루트 디렉토리에 만든다.
    • “/proc/device-tree”  심볼릭 링크 파일을 생성한다.

 

예) 루트 디렉토리인 base 아래에 생긴 노드들과 속성들이다.

$ ls /sys/firmware/devicetree/base -la
-r--r--r--    1 root     root             4 Mar 30 15:45 #address-cells
-r--r--r--    1 root     root             4 Mar 30 15:45 #size-cells
drwxr-xr-x    2 root     root             0 Mar 30 15:45 aliases
drwxr-xr-x    2 root     root             0 Mar 30 15:45 bootst
drwxr-xr-x    2 root     root             0 Mar 30 15:45 chosen
-r--r--r--    1 root     root            22 Mar 30 15:45 compatible
drwxr-xr-x    7 root     root             0 Mar 30 15:45 cpus
-r--r--r--    1 root     root             4 Mar 30 15:45 interrupt-parent
drwxr-xr-x    2 root     root             0 Mar 30 15:45 memory
-r--r--r--    1 root     root            14 Mar 30 15:45 model
-r--r--r--    1 root     root             1 Mar 30 15:45 name
drwxr-xr-x    2 root     root             0 Mar 30 15:45 pcie@20020000
drwxr-xr-x    2 root     root             0 Mar 30 15:45 pcie@50020000
drwxr-xr-x    2 root     root             0 Mar 30 15:45 pcie@60c00000
drwxr-xr-x    2 root     root             0 Mar 30 15:45 pmu
drwxr-xr-x    2 root     root             0 Mar 30 15:45 psci
drwxr-xr-x    2 root     root             0 Mar 30 15:45 secure_rtc
drwxr-xr-x   70 root     root             0 Mar 30 15:45 soc
drwxr-xr-x    2 root     root             0 Mar 30 15:45 timer

 

참고

 

댓글 남기기