리눅스 커널 부트스트랩: 초기화 과정 분석

개요

부트로더 → 커널 초기화 → 사용자 공간 init 프로세스

커널 버전: 6.1.x

진입점

현대 운영체제는 더 이상 어셈블리 코드로만 시작되지 않습니다.

  • 레거시 BIOS: x86 기반, arch/x86/boot/bootsect.S 어셈블리에서 main 진입
  • GRUB:
    grub> set root=(hd0,1)
    grub> linux /boot/vmlinuz-3.13.0-29-generic root=/dev/sda1
    grub> initrd /boot/initrd.img-3.13.0-29-generic
    grub> boot
  • UEFI: boot.efi
  • U-Boot: ARM 기반 주 사용, Image_header 구조체 + bl 어셈블리 jump 명령으로 kernel_start 함수 호출

built-in.a: 커널 정적 라이브러리

defconfig/Makefile/Kbuild의 선택적 플래그:

  • -obj-y: 커널 내장 대상
  • -obj-m: 로드 가능한 커널 모듈
  • -lib-y: 라이브러리 대상

Y로 선택 시 컴파일 후 built-in.a로 병합됩니다. M 선택 시 .ko 파일로 생성됩니다. 내장 대상은 module_init/initcall 심볼을 통해 커널 프로세스에서 호출됩니다.

ELF vmlinux

vmlinux는 디버깅 심볼을 포함한 ELF 형식의 커널 이미지입니다. built-in.a와 가상 메모리 정보를 포함합니다. ELF는 유닉스 실행 파일 형식이며, vmlinuz는 압축된 vmlinux를 의미합니다.

zImage/bzImage

자체 압축 해제 기능을 갖춘 부팅 가능한 바이너리입니다. OBJCOPY, AS, CC, LD 등을 사용하여 vmlinux 압축 패키지와 압축 해제 프로그램 및 라이브러리를 결합합니다. ELF와 심볼 정보를 제거하고 BIOS/UEFI/로더가 실행 가능한 코드만 포함합니다.

구성 요소:

  • head.o: 아키텍처 초기화 코드
  • head-<cpu>.o: 프로세서 초기화 코드
  • decompress.o, misc.o: 압축 해제 코드
  • *.gz: 심볼이 제거된 vmlinux 커널 ELF 압축 패키지

최종 결과물: zImage, Image.lz4 + resource.img → boot.img

루트 파일 시스템 rootfs

두 가지 옵션:

  • initrd/initramfs: 읽기 전용 가상 최소 파일 시스템, RAM 디스크 이미지 마운트 (Android 방식)
  • 저장 장치 파티션 직접 마운트 /

커널은 rootfs의 사용자 공간 첫 번째 프로세스 init을 시작합니다.

CPU 모드 전환

CPU/SOC는 일반적으로 높은 권한에서 낮은 권한으로 전환됩니다. 커널 부팅, 사용자와 커널 공간 전환, 호환성 또는 보안 상태 변경 시 CPU 모드 전환이 발생합니다.

  • x86: 리얼 모드 → 보호 모드
  • x86_64: 보호 모드의 Long Mode (64/32비트 호환)
  • ARM: SVC (EL0)

리눅스 커널 단계

init/main.c

모든 부팅 방식은 결국 start_kernel(void) 함수를 호출합니다.

1. 스택 오버플로우 감지

set_task_stack_end_magic(&init_task) - init_task의 스택 하단에 매직 넘버 할당

2. 멀티코어 프로세서 친화성 처리

smp_setup_processor_id(void) - MPIDR 레지스터에서 멀티코어 친화성 정보 획득

3. 초기 부팅 준비

debug_objects_early_init(void) - 객체 추적을 위한 해시 버킷 및 obj_pool 초기화

4. vmlinux 빌드 ID 기록

init_vmlinux_build_id(void) - ELF 헤더에서 빌드 ID 추출

5. 초기 cgroup 초기화

cgroup_init_early(void) - 루트 cgroup 초기화

6. IRQ 인터럽트 비활성화

local_irq_disable();
early_boot_irqs_disabled = true;

7. 각 구성 요소 초기화

boot_cpu_init();
page_address_init();
pr_notice("%s", linux_banner);
early_security_init();
setup_arch(&command_line);
setup_boot_config();
setup_command_line(command_line);
setup_nr_cpu_ids();
setup_per_cpu_areas();
smp_prepare_boot_cpu();
boot_cpu_hotplug_init();
build_all_zonelists(NULL);
page_alloc_init();
// ...

최종 단계: kernel_init(void *unused)

kthreadd 프로세스 완료 후 init 프로세스 환경 초기화, initcall 관련 메모리 해제, 사용자-커널 페이지 테이블 업데이트, NUMA 설정, 저장 장치의 init 프로그램 실행

pid = user_mode_thread(kernel_init, NULL, CLONE_FS);

메모리 해제: free_initmem(void)

__init 섹션의 메모리를 메모리 파트너로 해제합니다. __init 섹션의 코드와 데이터가 더 이상 필요하지 않기 때문입니다.

NUMA 정책 설정: numa_default_policy();

NUMA 정책을 initcal 설정에서 기본값으로 되돌립니다.

첫 번째 init 프로세스 시작: run_init_process(execute_command)

return kernel_execve(init_filename, argv_init, envp_init); - pid 1 제어권을 사용자 모드로 이전

이후 필요할 때만 시스템 호출, 인터럽트, 스케줄링 등을 통해 커널 모드로 전환됩니다.

kthreadd 커널 스레드 생성: kernel_clone

태그: 리눅스커널 부트스트랩 커널초기화 vmlinux zImage

7월 22일 06:40에 게시됨