Intel Architecture Manual을 보면 아래와 같은 Operating Mode Diagram이 있습니다. 각 Mode에 따라서 어떤 Mode로 전환할 수 있으며 이때 필요한 Register 설정은 무엇인지를 나타내는 그림이지요. ;)
 

이 그림을 자세히보면 리얼 모드에서는  IA-32e 모드로 전환할 수 있는 방법이 없습니다. 전환 하려면 보호 모드를 거쳐서 전환해야 하지요. 실제로 Intel Architecture Manual Volume 3A의 9.8.5를 봐도 "The operating system must be in protected mode with paging enabled before attempting to initialize IA-32e mode"로 보호 모드를 거쳐야 한다고 나와있습니다.

그런데~!!! 지나다가님의 제보로 리얼 모드에서 바로 IA-32e 모드로 전환할 수 있는 방법을 알게되었습니다. 물론 제조사 Manual에 나와있지 않은 내용이라, 팁 정도로 봐야겠지만 상당히 흥미로운 내용이라 한번 올려봅니다.

원본의 내용은 http://forum.osdev.org/viewtopic.php?f=1&t=11093&start=0 에서 보실 수 있으며, IA-32e 모드로 변경하려면 실제로 아래와 같이 7가지의 단계를 거쳐야합니다.

    1) Build paging structures (PML4, PDPT, PD and PTs)
    2) Enable PAE in CR4
    3) Set CR3 so it points to the PML4
    4) Enable long mode in the EFER MSR
    5) Enable paging and protected mode at the same time (activate long mode)
    6) Load a GDT
    7) Do a "far jump" to some 64 bit code 
 

위의 단계 중에서 6번은 리얼 모드에서 보호 모드로 전환하는 단계에서 하고, 나머지 6 가지는 보호 모드에서 수행하여 IA-32e 모드의 64비트 서브 모드로 전환합니다. But~!!! 리얼 모드에서 위의 7단계를 모두 수행해서 한번에 IA-32e 모드로 전환하는게 바로 Magic의 정체입니다. @0@)-b

과연 동작할까 싶지만, 실제로 동작하더군요. ㅎㄷㄷ 실제로 동작하는 코드는 http://bcos.hopto.org/temp/init.html에서 보실 수 있으며, 지나가다님이 작성하신 http://jsandroidapp.cafe24.com/xe/1936 에서도 보실 수 있습니다. ^^

정말 깜짝 놀랄 일이군요. ㅎㅎ 어떻게 이런 방법을 찾았는지... ㅎㅎ 세상에는 별별 사람들이 다 있는 것 같습니다. >ㅁ<)-b

 

<이미지 뷰어와 콘솔 셸이 추가된 MINT64 OS>

 오늘 너무 황당한 일이 있어서 오랜 적막(?)을 깨고 한자 적어 올립니다(사실 다시 삽질 안 하려고 잊기 전에 올리는 것이지만... ㅡ_ㅡ;;;). 요즘 유저 레벨 응용 프로그램을 추가하려고 시스템 콜 부분을 구현하고 있는데, 인터럽트나 콜 게이트 방식 말고 다른 방식이 아닌 새로운 방식을 한번 도입해봤습니다. 이미 이 글의 제목에도 나와있지만 SYSCALL과 SYSRET 명령어를 사용하는 것이지요.;)


SYSCALL과 SYSRET 명령어는 INTEL과 AMD 양쪽에서 모두 사용할 수 있으며, IA-32e 모드에서 Ring 0와 Ring 3을 순식간에 오가는데 아주 유용하....다고 적혀있습니다. ㅡ_ㅡa... 실제로 얼마나 빠른지는 잘 모르겠지만 콜 게이트나 인터럽트처럼 스택에 데이터를 저장하고 특권 레벨을 체크하는 부분이 없으므로, 이전 것들(?)보다는 빠를 듯 합니다. ^^;;;;


뭐, 일단 SYSCALL과 SYSRET 명령어를 사용하려면 어떻게 환경을 설정해야 하는지는 INTEL 문서 Volume 3에 4.8.8 부분에 잘 나와있으니 생략하고... 실제로 SYSCALL과 SYSRET를 NASM으로 사용할 때 주의할 점만 한 줄로 정리해보면 다음과 같습니다.


IA-32e 모드의 64bit 서브 모드를 사용할 경우
SYSRET 명령어 앞에 REX.W 비트를 반드시 명시적으로 켜줘야 한다.


위의 사실을 찾는 데만 무려 3시간이 걸렸습니다. ㅠㅠ INTEL 문서를 보면 SYSRET의 경우 IA-32e 모드의 서브 모드 중에서 호환 모드(Compatibility Mode)와 64 비트 모드 중에서 선택해서 돌아갈 수 있으며, 그 핵심은 REX.W 비트라고 적혀있습니다. MINT64 OS는 64비트 서브 모드를 사용하니 REX.W 비트를 켜줘야 하는데, REX.W 비트가 켜지지 않아서 시스템 콜을 호출하고 돌아올 때 문제가 계속 생겼습니다.


코드를 생성할 때 64bit로 생성했기 때문에 NASM이 알아서 붙여 줄거라 생각했는데... 확인 결과 아무것도 없이 그냥 SYSRET 커맨드만 덩그러니 있었습니다. 그래서 시스템 콜을 호출한 뒤에 돌아오면... 잘못된 명령어라는 예외가 발생하더군요. ㅠㅠ 그래서 REX.W 비트를 키려고 봤더니... 


얼래... NASM에는 SYSRET 명령어 앞에 REX.W 비트를 명시적으로 붙이는 접두사나 키워드가 없었습니다~!!! (여운산님이 o64 키워드가 있다는 사실을 제보해주셨습니다. o64 키워드를 붙이니까 잘 되더군요 >ㅁ<)-b 완전 감사합니다). ㅠㅠ 오퍼랜드가 있는 다른 명령어들은 뒤에 오는 오퍼랜드의 크기에 따라 REX.W 비트를 켜주는 모양이던데, SYSRET는 오퍼랜드가 없으니 그냥 넘어간 모양입니다. ㅠㅠ 그래서 아래처럼 설정해줬습니다.


DB 0x48  <== REX Prefix로 W 비트가 1로 설정된 상태입니다. ^^;;;; (제가 해결한 무식한 방법입니다)
SYSRET

o64  <== REX.W 비트를 1로 설정하는 키워드 입니다. ;) (여운산님이 제보해주신 방법입니다, 아주 깔끔하네요 ;) )
SYSRET


이걸 해놓고 나니까 겨우 정상적으로 동작하네요. 이제야 겨우 유저 레벨 코드를 작업할 수 있게 되었습니다. ㅠㅠ)-b 안 그래도 할 일이 산더미 같은데... 이런 일로 시간 낭비(?)를 하고 나니 머리가 어찔하네요. ㅠㅠ 에휴... 이제 다시 작업하러 가야겠습니다.


ps) 위의 화면은 MINT64 OS에 이미지 뷰어와 콘솔 셸이 추가된 화면입니다. ㅎㅎ 조만간 또 테스트할 수 있는 바이너리... 보다는 동영상으로 한번 올리겠습니다. ;)

+ Recent posts