티스토리 뷰

개발/arm64 linux 6 분석

start_kernel 1

clucle 2025. 5. 24. 15:20

kernel 을 초기화하는 start_kernel 는 여러 함수로 이루어져있다.

우선은 하나씩 분석을 해보자

    // stack 의 끝에 overflow detection 을 위해 magic 값을 설정
    set_task_stack_end_magic(&init_task);
    // 시작 cpu 의 (0번) id 를 지정
    smp_setup_processor_id();
    // 디버그를 위한 lock 과 리스트 초기화 (간단해서 분석 x)
    debug_objects_early_init();
    // notes 영역에서 빌드 id 를 획득해서 변수에 저장
    init_vmlinux_build_id();

    // cgroup subsystem 초기화
    cgroup_init_early();

    local_irq_disable();
    early_boot_irqs_disabled = true;

    /*
     * Interrupts are still disabled. Do necessary setups, then
     * enable them.
     */
     // 초기 cpu 활성화 (간단해서 분석 x)
    boot_cpu_init(); 
    // highmem 을 사용하는 경우 테이블 초기화 (간단해서 분석 x)
    page_address_init();

1. set_task_stack_end_magic

void set_task_stack_end_magic(struct task_struct *tsk)
{
    unsigned long *stackend;

    stackend = end_of_stack(tsk);
    *stackend = STACK_END_MAGIC;    /* for overflow detection */
}

end_of_stack

CONFIG_STACK_GROWSUP: 스택이 아래에서 위로 자라기 때문에 stack 의 사이즈만큼 더해줌

static __always_inline unsigned long *end_of_stack(const struct task_struct *task)
{
#ifdef CONFIG_STACK_GROWSUP
    return (unsigned long *)((unsigned long)task->stack + THREAD_SIZE) - 1;
#else
    return task->stack;
#endif
}

stack 정보가 config 에 따라 task 의 thread_info 에 정의되기도 함. 지금은 가장 쉬운 버전인 task->stack 으로 보자

2. smp_setup_processor_id

MPIDR: Multiprocessor Affinity Register

arch/arm64/kernel/setup.c

void __init smp_setup_processor_id(void)
{
    u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
    set_cpu_logical_map(0, mpidr);

    pr_info("Booting Linux on physical CPU 0x%010lx [0x%08x]\n",
        (unsigned long)mpidr, read_cpuid_id());
}

// Booting Linux on physical CPU 0x0000000000 [0x411fd070]

mpidr

cpu 별로 mpidr 레지스터를 가지고 있음

static inline u64 __attribute_const__ read_cpuid_mpidr(void)
{
    return read_cpuid(MPIDR_EL1);
}

#define read_cpuid(reg)            read_sysreg_s(SYS_ ## reg)

3. init_vmlinux_build_id

kernel 에 .text 처럼 .notes 라는 section 이 존재한다. 여기에 어떤 정보들이 들어가있는 것 같고, build id 도 여기에 존재한다.

// /sys/kernel/notes give the raw contents of our kernel .notes section.

#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID) || IS_ENABLED(CONFIG_VMCORE_INFO)
unsigned char vmlinux_build_id[BUILD_ID_SIZE_MAX] __ro_after_init;

/**
 * init_vmlinux_build_id - Compute and stash the running kernel's build ID
 */
void __init init_vmlinux_build_id(void)
{
    extern const void __start_notes;
    extern const void __stop_notes;
    unsigned int size = &__stop_notes - &__start_notes;

    build_id_parse_buf(&__start_notes, vmlinux_build_id, size);
}
#endif

nhdr->n_type == BUILD_ID

kernel notes

$ readelf -S vmlinux | grep -i notes
  [11] .notes            NOTE             ffff800081cc2d48  01cd2d48

$ objdump -s -j .notes vmlinux

vmlinux:     file format elf64-little

Contents of section .notes:
 ffff800081cc2d48 04000000 14000000 03000000 474e5500  ............GNU.
 ffff800081cc2d58 ab0efc65 008ba569 b4d05afc b7d9e249  ...e...i..Z....I
 ffff800081cc2d68 e56162c9 06000000 04000000 01010000  .ab.............
 ffff800081cc2d78 4c696e75 78000000 00000000 06000000  Linux...........
 ffff800081cc2d88 01000000 00010000 4c696e75 78000000  ........Linux...
 ffff800081cc2d98 00000000                             ....

4. cgroup_init_early

이거 보고 공부가 더 필요함

https://junsoolee.gitbook.io/linux-insides-ko/summary/cgroups/linux-cgroups-1

cgroup 이란?: cgroups is a Linux kernel feature that limits, accounts for, and isolates the resource usage of a collection of processes. 프로세스의 자원을 격리하고 제한하는 기능

kernel/cgroup/cgroup.c

/**
 * cgroup_init_early - cgroup initialization at system boot
 *
 * Initialize cgroups at system boot, and initialize any
 * subsystems that request early init.
 */
int __init cgroup_init_early(void)
{
    // __initdata: 초기화시에만 사용
    static struct cgroup_fs_context __initdata ctx;
    struct cgroup_subsys *ss;
    int i;

    // context 의 root 를 cgrp_dfl_root 로 설정
    // cgrp: cgroup
    // dfl: default
    // root: root
    ctx.root = &cgrp_dfl_root;
    init_cgroup_root(&ctx);
    cgrp_dfl_root.cgrp.self.flags |= CSS_NO_REF;

    RCU_INIT_POINTER(init_task.cgroups, &init_css_set);

    for_each_subsys(ss, i) {
        ...

        if (ss->early_init)
            cgroup_init_subsys(ss, true);
    }
    return 0;
}

cgroup subsystem

subsystem: 한종류의 리소스를 나타냄

cpuset : 프로세서를 그룹의 작업에 할당
cpu : ...
memory : 메모리 사용 제한

그래서 예를들어 device 안에 디렉토리를 만들고, device 에 접근을 못하게하고 task 에 pid 를 넣으면 print 를 못하게 할 수도 있음.

하나의 task(프로세스)는 여러 subsys(자원 종류) 별로 각각 하나씩의 cgroup에 속한다.

Subsystem (subsys) Task가 속한 cgroup
cpu cgroup A
memory cgroup B
blkio cgroup C
... ...
$ cat /proc/cgroups
#subsys_name    hierarchy       num_cgroups     enabled
cpuset  1       1       1
cpu     2       1       1
cpuacct 3       1       1
blkio   4       1       1
memory  5       1       1
devices 6       1       1
freezer 7       1       1
net_cls 8       1       1
perf_event      9       1       1
net_prio        10      1       1
hugetlb 11      1       1
pids    12      1       1
rdma    13      1       1

clucle@DESKTOP-N5AJSPQ:~/repo/wsl-qemu-arm64-gdb$ ls /sys/fs/cgroup/cpu/
cgroup.clone_children  cpu.cfs_burst_us   cpu.idle    cpu.stat.local     tasks
cgroup.procs           cpu.cfs_period_us  cpu.shares  notify_on_release
cgroup.sane_behavior   cpu.cfs_quota_us   cpu.stat    release_agent
clucle@DESKTOP-N5AJSPQ:~/repo/wsl-qemu-arm64-gdb$ ls /sys/fs/cgroup
blkio  cpuacct  devices  hugetlb  net_cls   perf_event  rdma
cpu    cpuset   freezer  memory   net_prio  pids        unified

// 각 pid 가 tasks 에 정의됨
$ cat /sys/fs/cgroup/cpu/tasks
1
6
7
8
13
14
// subsys 는 define 으로 등록해둠
include/linux/cgroup_subsys.h
#if IS_ENABLED(CONFIG_CPUSETS)
SUBSYS(cpuset)
#endif

#if IS_ENABLED(CONFIG_CGROUP_SCHED)
SUBSYS(cpu)
#endif

// kernel/group/cgroup.c
/* generate an array of cgroup subsystem pointers */
#define SUBSYS(_x) [_x ## _cgrp_id] = &_x ## _cgrp_subsys,
struct cgroup_subsys *cgroup_subsys[] = {
#include <linux/cgroup_subsys.h>
};
#undef SUBSYS
// include/linux/cgroup_defs.h
struct cgroup_subsys {
    struct cgroup_subsys_state *(*css_alloc)(struct cgroup_subsys_state *parent_css);
    int (*css_online)(struct cgroup_subsys_state *css);
    void (*css_offline)(struct cgroup_subsys_state *css);
    void (*css_released)(struct cgroup_subsys_state *css
    ...
}

'개발 > arm64 linux 6 분석' 카테고리의 다른 글

start_kernel 2 setup_arch  (0) 2025.05.24
proc.S __primary_switch  (0) 2025.05.17
proc.S __cpu_setup  (0) 2025.05.10
250503 head.S  (2) 2025.05.03
댓글