운영체제 기본/Linux/x86-64/BIOS 부팅/GRUB의 커널 적재와 제어권 전달: 두 판 사이의 차이

변경된 절 제목으로 내부 역링크 갱신
역링크 갱신 완료 후 불필요한 호환 span id 제거
33번째 줄: 33번째 줄:
이 그림의 <code>startup_32</code>와 <code>startup_64</code>는 '''<code>arch/x86/boot/compressed/head_64.S</code> 안의 기호'''이다. 압축이 풀린 커널 쪽 <code>arch/x86/kernel/head_64.S</code>에도 <code>startup_64</code>가 있으므로, 함수 이름만으로 부팅 위치를 판단하면 안 된다.<ref name="compressed-head">[https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/boot/compressed/head_64.S?h=v6.12 Linux v6.12, arch/x86/boot/compressed/head_64.S]. <code>startup_32</code>의 진입 조건과 초기 GDT 교체를 확인할 수 있다.</ref>
이 그림의 <code>startup_32</code>와 <code>startup_64</code>는 '''<code>arch/x86/boot/compressed/head_64.S</code> 안의 기호'''이다. 압축이 풀린 커널 쪽 <code>arch/x86/kernel/head_64.S</code>에도 <code>startup_64</code>가 있으므로, 함수 이름만으로 부팅 위치를 판단하면 안 된다.<ref name="compressed-head">[https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/boot/compressed/head_64.S?h=v6.12 Linux v6.12, arch/x86/boot/compressed/head_64.S]. <code>startup_32</code>의 진입 조건과 초기 GDT 교체를 확인할 수 있다.</ref>


<span id="GRUB가_파일에서_읽는_것"></span>
== GRUB의 커널 파일 해석 ==
== GRUB의 커널 파일 해석 ==
GRUB 메뉴의 항목은 대략 다음과 같은 명령으로 커널과 초기 RAM 파일 시스템 이미지를 지정한다. 경로와 <code>root=</code> 값은 설치 환경에 따라 다르다.
GRUB 메뉴의 항목은 대략 다음과 같은 명령으로 커널과 초기 RAM 파일 시스템 이미지를 지정한다. 경로와 <code>root=</code> 값은 설치 환경에 따라 다르다.
53번째 줄: 52번째 줄:
<code>initrd</code> 명령은 별도의 이미지를 메모리에 올리고 그 주소와 크기를 기록한다. 이름이 initrd여도 실제 내용은 initramfs일 수 있다. 부트로더 관점에서는 커널에 전달할 바이트 배열이며, 이를 해석하여 초기 루트 파일시스템으로 사용하는 일은 커널 쪽 일이다. 이 데이터가 <code>/init</code> 파일로 이어지는 과정은 [[운영체제 기본/x86-64 Linux의 BIOS 부팅/루트 파일시스템과 init 선택#init 실행을 위한 루트 파일시스템 준비|루트 파일시스템과 init 선택]]에서 다룬다.
<code>initrd</code> 명령은 별도의 이미지를 메모리에 올리고 그 주소와 크기를 기록한다. 이름이 initrd여도 실제 내용은 initramfs일 수 있다. 부트로더 관점에서는 커널에 전달할 바이트 배열이며, 이를 해석하여 초기 루트 파일시스템으로 사용하는 일은 커널 쪽 일이다. 이 데이터가 <code>/init</code> 파일로 이어지는 과정은 [[운영체제 기본/x86-64 Linux의 BIOS 부팅/루트 파일시스템과 init 선택#init 실행을 위한 루트 파일시스템 준비|루트 파일시스템과 init 선택]]에서 다룬다.


<span id="boot_params로_부트_정보를_전달한다"></span>
== boot_params와 부트 정보 전달 ==
== boot_params와 부트 정보 전달 ==
GRUB는 커널에 파일 이름만 전달하지 않는다. 파일은 이미 메모리에 올라와 있어야 하며, 커널이 그 메모리를 찾고 기계를 파악하는 데 필요한 정보도 함께 준비한다.
GRUB는 커널에 파일 이름만 전달하지 않는다. 파일은 이미 메모리에 올라와 있어야 하며, 커널이 그 메모리를 찾고 기계를 파악하는 데 필요한 정보도 함께 준비한다.
83번째 줄: 81번째 줄:
GRUB 소스의 <code>linux_params</code>는 준비 중인 정보이며, <code>grub_linux_boot()</code>는 최종 배치할 공간을 확보하고 이를 복사한다. 같은 단계에서 명령행 주소와 메모리 맵도 마무리한다. 소스에 나오는 <code>real_mode_target</code>이라는 변수명만 보고 16비트 실행 경로라고 판단해서는 안 된다. 여기서는 최종 부팅 정보가 놓일 주소를 가리키며, 마지막 분기는 명백히 <code>grub_relocator32_boot()</code>이다.<ref name="grub-linux" />
GRUB 소스의 <code>linux_params</code>는 준비 중인 정보이며, <code>grub_linux_boot()</code>는 최종 배치할 공간을 확보하고 이를 복사한다. 같은 단계에서 명령행 주소와 메모리 맵도 마무리한다. 소스에 나오는 <code>real_mode_target</code>이라는 변수명만 보고 16비트 실행 경로라고 판단해서는 안 된다. 여기서는 최종 부팅 정보가 놓일 주소를 가리키며, 마지막 분기는 명백히 <code>grub_relocator32_boot()</code>이다.<ref name="grub-linux" />


<span id="마지막_점프_직전의_CPU_상태"></span>
== 커널 인계 직전의 CPU 상태 ==
== 커널 인계 직전의 CPU 상태 ==
GDT의 디스크립터와 세그먼트 선택자가 주소 해석과 권한을 정하는 방식은 [[운영체제 기본/x86-64 Linux의 BIOS 부팅/GDT와 LDT 초기화|GDT와 LDT 초기화]]에서 설명한다.
GDT의 디스크립터와 세그먼트 선택자가 주소 해석과 권한을 정하는 방식은 [[운영체제 기본/x86-64 Linux의 BIOS 부팅/GDT와 LDT 초기화|GDT와 LDT 초기화]]에서 설명한다.
113번째 줄: 110번째 줄:
<code>grub_linux_boot()</code>는 <code>ESI</code>뿐 아니라 <code>ESP</code>에도 부팅 정보의 최종 주소를 넣는다. 그러나 이를 Linux가 계속 사용할 정식 커널 스택이라고 생각해서는 안 된다. Linux의 <code>startup_32</code>는 곧 <code>boot_params</code> 안의 scratch 필드를 이용해 현재 적재 위치를 계산하고, 자신의 초기 부팅 스택을 설정한다.<ref name="grub-linux" /><ref name="compressed-head" />
<code>grub_linux_boot()</code>는 <code>ESI</code>뿐 아니라 <code>ESP</code>에도 부팅 정보의 최종 주소를 넣는다. 그러나 이를 Linux가 계속 사용할 정식 커널 스택이라고 생각해서는 안 된다. Linux의 <code>startup_32</code>는 곧 <code>boot_params</code> 안의 scratch 필드를 이용해 현재 적재 위치를 계산하고, 자신의 초기 부팅 스택을 설정한다.<ref name="grub-linux" /><ref name="compressed-head" />


<span id="인계_이후에는_누가_무엇을_책임지는가"></span>
== GRUB과 커널의 역할 분담 ==
== GRUB과 커널의 역할 분담 ==
GRUB가 진입점으로 점프하면 정상 부팅 흐름에서 제어권은 Linux로 넘어간다. Linux는 GRUB의 함수 호출을 계속 이용하여 운영체제를 실행하지 않는다. 그렇다고 넘어오는 순간 GRUB가 적재한 모든 메모리를 지워도 되는 것은 아니다. 커널 이미지, 부팅 정보, 명령행, initrd는 커널이 읽어야 할 입력으로 남아 있다.
GRUB가 진입점으로 점프하면 정상 부팅 흐름에서 제어권은 Linux로 넘어간다. Linux는 GRUB의 함수 호출을 계속 이용하여 운영체제를 실행하지 않는다. 그렇다고 넘어오는 순간 GRUB가 적재한 모든 메모리를 지워도 되는 것은 아니다. 커널 이미지, 부팅 정보, 명령행, initrd는 커널이 읽어야 할 입력으로 남아 있다.
125번째 줄: 121번째 줄:
# '''압축 해제 코드에서 압축이 풀린 커널로''': 별도의 초기 어셈블리 진입과 C 초기화 준비.
# '''압축 해제 코드에서 압축이 풀린 커널로''': 별도의 초기 어셈블리 진입과 C 초기화 준비.


<span id="linux16과_혼동하지_않기"></span>
== linux와 linux16의 진입 경로 ==
== linux와 linux16의 진입 경로 ==
BIOS용 GRUB에는 <code>linux16</code>과 <code>initrd16</code>도 있다. 이 경로는 Linux의 16비트 setup에 진입하며, setup이 BIOS 기반 초기 작업과 보호 모드 전환을 수행한다. 하지만 그것은 이 문서의 일반 <code>linux</code> 경로와 다른 선택이다. '''BIOS로 시작했다는 이유만으로 Linux의 16비트 setup도 실행되었다고 결론 내릴 수 없다.'''<ref name="grub-manual" />
BIOS용 GRUB에는 <code>linux16</code>과 <code>initrd16</code>도 있다. 이 경로는 Linux의 16비트 setup에 진입하며, setup이 BIOS 기반 초기 작업과 보호 모드 전환을 수행한다. 하지만 그것은 이 문서의 일반 <code>linux</code> 경로와 다른 선택이다. '''BIOS로 시작했다는 이유만으로 Linux의 16비트 setup도 실행되었다고 결론 내릴 수 없다.'''<ref name="grub-manual" />