개요
부트로더 → 커널 초기화 → 사용자 공간 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