현재 저수준 운영 체제 조직을 연구 중입니다. 리눅스 커널이 어떻게 로딩되는지 이해하려고 노력하고있다.Linux 커널에서 실제 모드에서 보호 모드로 전환
내가 이해할 수없는 것은 16 비트 (리얼 모드)에서 32 비트 (보호 모드) 로의 전환입니다. this file에서 발생합니다.
protected_mode_jump
함수는 다음 CR0
reguster
movl %cr0, %edx
orb $X86_CR0_PE, %dl # Protected mode
movl %edx, %cr0
에 PE
비트 수, 나중에 실행되는 32 비트 코드의 다양한 보조 계산을 행하고, 그 32 비트 코드로 긴 점프를 수행 한 후 다음
# Transition to 32-bit mode
.byte 0x66, 0xea # ljmpl opcode
2: .long in_pm32 # offset
.word __BOOT_CS # segment
지금까지 내가 in_pm32
이해 오른쪽 protected_mode_jump
아래에 선언 된 32 비트 함수의 주소는 다음과 같습니다
in_pm32
기능의 기본적 절대 주소 여야되도록 617,451,515,
.code32
.section ".text32","ax"
GLOBAL(in_pm32)
# some code
# ...
# some code
ENDPROC(in_pm32)
__BOOT_CS
섹터 기지국이 0이합니다 (GDT here는 미리 설정되어)있다.
그게 문제입니다. 머신 코드를 생성하는 동안 어셈블러/링커는 in_pm32
함수의 절대 주소를 알지 못합니다. 실제 모드에서 메모리에로드 될 위치를 알 수 없기 때문입니다 (다양한 부트 로더가 다양한 공간을 차지할 수 있으며 리얼 모드 커널은 부트 로더 직후에로드됩니다).
또한 동일한 폴더에있는 setup.ld
은 코드의 원점을 0으로 설정하므로 in_pm32
주소는 리얼 모드 커널의 시작 부분에서 오프셋이됩니다. CS
레지스터가 올바르게 설정 되었기 때문에 16 비트 코드로 정상적으로 작동하지만 긴 점프가 발생하면 CPU가 이미 보호 모드에 있으므로 상대 오프셋이 작동하지 않아야합니다.
내 질문 : 오프셋 (.long in_pm32
)이 상대적이면 보호 모드 (.byte 0x66, 0xea
)의 긴 점프가 적절한 코드 위치를 설정하는 이유는 무엇입니까?
정말 중요한 것을 놓치고있는 것 같습니다.
2: .long in_pm32 # offset
그것은이다
오전 3시 30 분이므로 잠자리에 들려고합니다. JMP에 관한 부분 만 보았습니다. 점프는 _CS_ 선택기를 설정하는 32 비트 FAR JMP입니다. CR0에 보호 모드 비트를 설정하면 실제로 준 16 비트 보호 모드가됩니다. 32 비트 보호 모드로 전환하려면 선택기 (__BOOT_CS)와 오프셋을 사용하여 점프하는 FAR JMP를 수행해야합니다. __BOOT_CS는 GDT의 32 비트 코드 세그먼트 설명자 (0의 기저 및 0xffffffff의 제한이 있음)를 가리키는 선택자 여야합니다. FAR JMP가 완료되면 32 비트 보호 모드가됩니다. –
본질적으로 FAR JMP는 준 16 비트 보호 모드에서 32 비트 보호 모드로 전환해야합니다. –
사실,'__BOOT_CS' 선택기베이스는 0입니다. 나는 FAR JUMP가 원하는 함수/레이블의 절대 주소를 취해야한다고 생각합니다. 왜냐하면'0 + offset'은 단지'offset' 일 것이기 때문입니다. 하지만 여기서 FAR JUMP는 상대적 오프셋 (relative offset)으로 호출됩니다. ('.long in_pm32'는 리얼 모드 커널 바이너리의 처음부터'in_mp32' 함수의 주소입니다.) - 그리고 왜 결국'in_pm32' 함수가 끝내야하는지 이해하지 못합니다 실행됩니다. 원거리 점프는 0x7C00 + bootloader_size 바이트에서 일치하지 않아야합니다. – Alexander