본문으로 이동
  • 현재 모든 문서는 작성 중입니다. 보시는 데 불편함이 있더라도 양해 부탁드립니다.

운영체제 기본/Linux/x86-64/BIOS 부팅/진입 규약과 압축 해제

~ldmsys
관리자 (토론 | 기여)님의 2026년 10월 31일 (토) 06:43 판 (부팅 1장 분리·보강: 진입 조건, boot_params, 압축 해제와 본체 진입)
(차이) ← 이전 판 | 최신판 (차이) | 다음 판 → (차이)

운영체제 기본 목차 · 부팅 목차

시작 상태: 로더가 Linux bzImage를 메모리에 적재하고, 64비트 부트 프로토콜의 진입 조건을 마련했다.

끝 상태: 압축 해제기가 커널 본체를 실행 가능한 위치에 배치하고 본체의 startup_64로 분기한다.

기준은 Linux v6.12, x86-64 부트 CPU의 bzImage 64비트 진입 경로다. 이 장의 출발점은 전원 인가나 펌웨어 리셋 벡터가 아니다.

1. 첫 명령어에도 실행 조건이 필요하다

C 함수에 호출 규약이 있듯이 로더와 커널 사이에도 부트 규약이 있다. 로더가 아무 주소에 이미지를 복사한 다음 아무 CPU 상태에서 분기해서는 커널이 실행될 수 없다. 예를 들어 페이징이 활성화되어 있으면 CPU가 명령어를 가져오는 주소도 페이지 테이블로 변환된다. 다음 명령어가 있는 메모리를 매핑하지 않았다면 시작하자마자 문제가 생긴다.

이 경로에서는 CPU가 이미 64비트 모드이며 페이징도 켜져 있다. 로더는 필요한 이미지·부트 정보·명령행 영역을 identity mapping해 둔다. 이는 해당 범위에서 가상 주소와 물리 주소의 수치가 같도록 매핑한다는 뜻이다. 페이징을 끈다는 뜻은 아니다. 아직 커널의 최종 주소 공간을 완성하지 않았어도, 합의한 주소로 초기 코드와 데이터를 사용할 수 있게 하는 조건이다.[1]

로더가 넘기는 또 하나의 핵심은 boot_params다. 커널 이미지의 위치와 명령행 같은 부트 정보를 전달하기 위한 구조체이며, 진입 시 %rsi가 그 주소를 담는다. 커널은 로더의 C 전역변수를 공유하는 것이 아니라, 정해진 형식의 메모리와 레지스터를 통해 정보를 받는다. 인터럽트 비활성화와 GDT·세그먼트 설정도 진입 계약에 포함된다.[1]

2. 지금 들어온 곳은 커널 본체가 아니다

bzImage는 압축된 본체를 포함한다. 압축된 바이트를 CPU가 그대로 명령어로 실행할 수는 없으므로, 먼저 압축을 풀어 줄 코드가 실행되어야 한다. 이 경로의 첫 startup_64는 arch/x86/boot/compressed/head_64.S에 있다. 본체의 동명 심볼인 arch/x86/kernel/head_64.S:startup_64와는 다른 코드다.[2][3]

부트 규약에서 64비트 진입점은 적재된 커널 시작 주소에 0x200을 더한 위치다. 이 값을 디스크상의 bzImage 파일 시작이나 최종 커널 가상 주소에 무조건 더해서는 안 된다. 규약이 지정한 적재 영역을 기준으로 읽어야 한다.[1]

3. 압축 해제 중 자기 자신을 덮어쓰지 않아야 한다

입력은 작지만 출력은 크다. 따라서 출력 버퍼를 잘못 잡으면 아직 읽지 않은 압축 데이터나 현재 실행 중인 해제기를 덮어쓸 수 있다. 해제기 코드는 압축 이미지를 안전한 위치로 복사하고, 옮겨진 코드로 분기한 뒤 작업을 계속한다. “복사한 다음 계속 원래 위치에서 실행한다”가 아니다.[2]

이 경로는 자체 스택과 필요한 매핑도 준비하며 BSS를 비운다. BSS는 초기값이 0인 전역·정적 저장 영역을 위한 구역이다. 실행 환경을 처음 만드는 코드에서는 그 영역이 0이라는 조건도 직접 마련해야 한다. 이는 나중에 본체가 자신의 BSS를 초기화하는 것과 별도의 작업이다.[2]

extract_kernel()은 출력 위치를 선택·검사하고 decompress_kernel()을 호출한다. 뒤의 함수는 압축 해제뿐 아니라 ELF 정보를 해석해 본체를 배치하고 relocation을 처리한다. relocation은 코드나 데이터의 주소 참조를 실제 배치에 맞게 보정하는 작업이다. 파일의 바이트를 풀어 놓았다는 사실만으로, 다른 주소에 놓인 프로그램의 주소 참조까지 맞아지는 것은 아니다.[4]

다음은 중간 준비·조건부 기능·오류 처리를 생략한 흐름이다.

compressed/head_64.S:startup_64
  → 안전한 위치로 옮겨진 해제기
  → extract_kernel()
      → decompress_kernel()
  → 반환된 본체 진입 주소로 jump

반환값은 다음에 실행할 주소다. 어셈블리 코드는 부트 정보 주소를 다시 %rsi에 두고 그 주소로 분기한다. 다음 장은 여기서 시작한다.[2]

다른 부팅 경로와의 경계

32비트 규약으로 진입하면 모드 전환 과정이 앞에 붙는다. EFI stub은 펌웨어가 PE/COFF 실행 파일로 들어오는 별도 입구다. 이미 준비된 비압축 본체로 직접 진입하는 경우도 본체 소스에 명시되어 있다. 이들을 이 장의 앞뒤에 모두 이어 붙여 “반드시 거치는 단계”로 그리면 안 된다.[2][3][5]

소스 탐색: startup_64 · extract_kernel. 동명 심볼의 파일 경로를 확인한다. 검증 근거는 각주의 동일 태그 원문이다.

다음: 커널 초기화

  1. ↑ 1.0 1.1 1.2 v6.12 Documentation/arch/x86/boot.rst, 64-bit Boot Protocol 절.
  2. ↑ 2.0 2.1 2.2 2.3 2.4 v6.12 arch/x86/boot/compressed/head_64.S, startup_64.
  3. ↑ 3.0 3.1 v6.12 arch/x86/kernel/head_64.S, startup_64.
  4. ↑ v6.12 arch/x86/boot/compressed/misc.c, extract_kernel, decompress_kernel, parse_elf, handle_relocations.
  5. ↑ v6.12 Documentation/admin-guide/efi-stub.rst.