[OS 개발 15] 무한 재부팅에 대한 개인적 견해


무한 재부팅에 대하여


 

 

어느덧 OS 개발에 대한 15번째 포스트 입니다.

IDT에 대한 포스팅까지 마친 시점에서 이번 포스팅에서는 잠시 무한 재부팅 문제에 대해 좀 살펴보기로 하겠습니다.

 

그 동안 OS를 만들고자 했던 많은 분들이 겪어왔던 고충 중 하나가 바로 무한 재부팅 문제입니다. 이전 포스팅에서도 무한 재부팅에 대해 한번 언급한 걸로 기억하는데, 사실 저 역시 OS 개발진행 과정에서 무한 재부팅 현상을 빈번하게 겪었습니다. 이를 해결하기 위해 수 없이 구글링 해 보았지만 무한 재부팅 문제에 대해 깊이 있게 설명하거나 다루는 글이 생각보다 많지 않습니다. 대부분 글을 보시면 아시겠지만 명확한 결론이 없습니다.

 

물론 저도 분명한 해결책을 제시하기 위해 이 글을 쓰는 것은 아닙니다(워낙 그 경우가 다양하기 때문에). 다만 제가 겪은 경험에 근거하여 발생 가능한 몇 가지 가능성을 공유하기 위해 OS 개발 도중 별도의 포스팅을 하게 되었습니다.

 

제가 지금까지 파악한 무한 재부팅의 원인은 다음과 같이 크게 2가지로 구분할 수 있을 것 같습니다. (물론 이건 제 개인적인 의견이 반영된 것입니다). 

 

1. 실수에 의한 무한 재부팅

2. 시스템 문제에 따른 무한 재부팅

 

어찌보면 당연한 얘기겠지만 무한 재부팅 문제는 개발 과정에서 자신의 실수에 의해 발생한 것일 가능성이 가장 큽니다.

아직 포스팅은 안했으나, 저의 경우 태스크 스위칭을 구현하는 과정에서 발생한 무한 재부팅 문제를 해결하느라 하루를 완전히 날린 날이 있었습니다. 그 날은 결국 해결을 못했고, 다음날 다시 코드를 처음부터 꼼꼼히 살펴보았습니다





그 결과, dw로 입력해야할 것이 dd로 입력되어 있는 문제를 발견했고 단 한글자 차이로 완전히 잘못된 결과를 보였음을 확인할 수 있었습니다. 혹시 이 글을 참고하시는 분들도 같은 현상을 겪고 계신다면 다시한번 자신의 코드를 처음부터 끝까지 꼼꼼히 살펴보시기 바랍니다. 어셈블러인 NASM은 이러한 오류를 에러로 처리하지 못하기 때문에 꼼꼼하게 코드를 살펴보지 않으면 오타를 발견할 별다른 방법이 없습니다.

 

두 번째는 '시스템 문제에 따른 무한 재부팅' 문제인데요,.

지금 본인이 사용중인 CPU와 NASM 어셈블러를 통해 제작한 OS의 호환문제(?)로 인해 발생하는 현상일 수 있습니다. 대표적으로 CR0 레지스터 문제로 발생하는 현상을 들 수 있습니다. 이는 무한 재부팅을 겪은 분들이라면 한 번쯤 검색을 통해 접해봤을 법한 문제인데요, CR0는 CPU에게 '앞으로 32비트 보호모드를 사용하겠다'라는 것을 알려주기 위해 사용 되는 레지스터 입니다. 이 레지스터를 통해 무한 재부팅이 발생한다고 호소하는 분들을 여럿 봤습니다. 특히, 김범준님의 저서, '만들면서 배우는 OS 커널의 구조와 원리'의 책의 코드에서 그 에러가 발생하기로 유명합니다. 챕터까지 언급한다면, chap3에서 보호모드로 넘어가는 부분을 구현하는 예제가 있는데, 여기에서 많은 분들이 무한 재부팅 현상을 겪고 있다는 글을 많이 보았습니다. 물론 저 역시 이 부분에서 같은 현상을 겪었습니다.

 

이에 대한 해결책에 대해 많은 분들이 제시하고 있는데, 대충 정리해보면 다음과 같습니다.

 

1. Nasm을 2.05 버전 이하를 써볼 것. 이도 안되면 가장 초기버전인 0.99버전을 써볼 것.

2. 가상머신을 사용할 때 VMware를 최대한 이전 버전을 사용해보거나, Bochs를 써볼것(VirtualBox는 구동시 에러 발생시킴)

3. 가상머신이 아닌 물리 PC에서 플로피 디스크로 구동해 볼 것(환경상 시도하기 어려움)

4. jmp $+2

   nop

   nop

   이 구문을 제거해 볼 것

5. jmp 0x1000:0000 대신 jmp dword SysCodeSelector:0x10000 으로 바꿔볼 것

 

지금까지 파악한 건 이 정도인데, 모두 명확한 해결방법은 아니었습니다. 저도 이 chap3 예제를 구현해 보았지만 아직도 왜 이 예제에서 무한 재부팅이 일어나는지 파악하지 못하고 있습니다.

 

결론적으로 우선 자신의 코드를 천천히 다시 한번 살펴보고, 다음 진행 사항으로 넘어갈 수 있으면 일단 넘어가라고 말씀드리고 싶습니다. 참고로 저는 이 예제에서 gdtr 영역을 부트로더로 옮기고 여기에서 gdt+0x10000을 gdt+0x07C0으로 변경함으로써 해결할 수 있었습니다.

 



TAGS.

Comments