OS를 만들면서 아직 메모리 관리도 안되고, 스케쥴러도 되지 않는 OS라고 부르기엔 참 민망한 OS이지만 현재 개발은 계속되고 있는 중입니다. 저번주 토욜날 할머니께서 돌아가시는 바람에 부랴부랴 내려가서 3일장을 치르고 오느라 기능을 많이 추가하지는 못했군요. 그 전에도 면접에 대한 준비도 하고 실제 면접도 치르느라 시간이 훌쩍 지나갔습니다^^.
예전에 올라왔던 스캔코드를 찍었던 스샷과는 다르게 키보드 처리도 어느정도 된 상태의 스크린샷입니다. 모처에 면접을 볼때는 help, mem, size의 단 3개의 명령어만 존재했는데, 현재 메모리관리자를 넣어보려고 하니 제가 생각한 구조에서는 미리 MP Configuration Table을 어느정도 분석하여 코어 개수에 대한 정보가 필요하더군요. 그래서 Process Control Block 도 지정하고 Bootstrap Core 인덱스도 구하고 하는 등의 작업을 추가 했습니다. 대충 생각한 메모리관리자의 구조가 아래와 같습니다.
3. 프로세스에서 메모리 할당 요청이 들어오면 MemoryAllocator에서 남아있는 여유분의 블럭이 있는지 조사하고 서비스가능한 블럭이 있을경우 BuddyBlock 작업을 수행하여 할당을 한다. 만약 블럭이 없을 경우 PageAllocator에 페이지 할당을 요청한다.
4. PageAllocator에서는 각 Page에 대해서 소유 프로세스를 관리하며, 각각의 페이지 사이즈를 관리한다. 페이지의 할당 요청이 들어왔을 때, 서비스 가능한 페이지가 있다면 해당 페이지를 할당해주고, 아닐 경우 NULL을 리턴한다.
5. 페이지가 할당 요청이 되었을 때에는 MemoryAllocator에 요청된 공간만큼 할당을 시켜준 다음 남은 블럭은 MemoryAllocator에서 자체적으로 다시 관리한다.
6. 해제의 경우 MemoryAllocator에서 남은 블록을 해제 하며 Merging을 수행하여 해당 블럭이 PageAllocator에서 할당하는 기본 페이지 사이즈가 되면 해당 PageAllocator에 페이지 소유를 이양하고 빈 페이지로 설정한다.
아직 다른 OS에서의 메모리 관리를 자세하게 살펴보지를 않은 상태라 나름대로 고민을 하여 구성을 해보았는데 스스로는 꽤나 괜찮다고 생각을 하지만 알고보면 평범할것 같기도 하여 열심히 구현만 하고 있습니다. 이제 메모리 관리자가 제대로 구현되고 나면 실제로 이제 구현되어야할 스케쥴러를 구현하여 멀티태스킹이 들어가게 되고 이 부분이 되고 나면 그래도 그럭저럭 OS라고 부를 수 있지 않을까 하는 생각이 조금씩 드네요^^;
다음에도 더 발전된 포스팅 거리를 들고 찾아뵙도록 하겠습니다. 다른 일이 생기지 말아야 빨리 작업이 될텐데 말이죠^^;
마지막 C++ 커널 진입 글을 올리고 난뒤 많은 시간이 흐른것 같습니다. 엄청 -ㅅ- 도중에 해결할 수 없는 삽질이 계속되어 한 동안 지지부진 하고 있었는데요.. 결과는 오늘 해결을 봤습니다. 결과물은 아래와 같이 Keyboard Interrupt 처리가 되는 화면입니다.(하지만 제대로된 키 입력은 아직 처리를 못했다는게.. 가장 큰 문제라면 문제일까요?)
위 화면에서 볼 수 있다 시피 깨진 문자가 입력이 되긴 합니다. Scan Code 를 곧바로 출력하게 하였더니 이런 현상이 발생하네요^^; 곧 piKeyboard 클래스를 제작하여 제대로 된 입력을 처리하려고 합니다. ㅎㅎ 그래도 예전에 진입만 되었던 화면이랑 많이 달라진 듯 하죠? 대충 그 동안 추가된 기능이 아래와 같습니다.
1. Memory Size Detection - Page Map Level 4 Table등의 메모리 테이블을 구성하여 제대로 메모리 접근이 되는지 검사하여 사이즈를 측정을 하게 하였고
2. Global Descriptor Table - KernelLoader 에서 임시로 롱모드 진입을 위한 GDT 데이터를 1MB 영역에 존재하는 커널에서 다시 재구성하여 로딩을 합니다.
3. Task State Segment - Task Segment 를 구성했구요. 이를 위해서. 뒤에 적을 하나의 구현이 필요했습니다.
4. Interrupt Descriptor Table - CPU에 대한 Interrupt 를 처리하기 위한 IDT를 커널영역에서 구성하였습니다. 물론 Master PIC, Slave PIC 또한 IRQ를 리맵핑하여 처리할 수 있도록 하였습니다.
6. new operator 제공 - 아주 단순한 new 이긴 합니다만, 현재 커널 상에서 커널을 실제 운용하기 위하여 사용되는 Memory Allocation Alogorithm을 사용한 것이 아닌 문법상으로 new 를 지원합니다. 이 부분이 되어야 x64 Task State Segment 에서 사용할 스택공간을 손쉽게 마련할 수 있겠더라구요^^.
7.Global / Static Class의 Constructor, Destructor 호출 - 기존엔 Pointer 를 Global 하게 관리하고 Stack 에 커널 오브젝트를 생성한 후, 사용을 하였는데 그 부분을 LD 와 extern "C" 를 이용하여 서로 연결 Constructor, Destructor를 KernelMain 진입 전후에 호출이 되도록 하였습니다. 이 덕분에 커널영역에 데이터가 존재하게 되었구요
뭐 별 기능이 없는 것 같기는 합니다만. 소스 측면에서는 엄청난 변화가 있었습니다. ㅜㅜ Descriptor Table 들을 어떻게 구성할까 구성할까 하다가 Class 와 Inheritance, Union 을 사용하여 데이터에 대하여 공통적으로 접근하기 쉽도록 일단은 구성을 했었고, 최대한 namespace 를 사용하여 소스코드량은 많아질지라도 구분을 하도록 했고, Get, Set 을 통하여 OOP를 그래도 지켜보려고 했습니다. 그래도 RTTI가 안되다보니 Inheritance의 Virtual Function 같은건 사용할 수도 없습니다. 뭐.. Virtual Function 을 사용하려고 해도 Function Table 로 인하여 Class의 크기가 커지는 문제점이 있어서 손쉽게 할 수 있는 것만도 아니지만요^^;
지금도 열나게 코딩중이긴 하지만 언제까지 달릴 수 있을지 잘 모르겠습니다^^. 그럼 다음에는 더 좋은 결과물을 들고 포스팅을 해보도록 하겠습니다.
일단 제가 작업하고 있는 환경은 Ubuntu 9.10 x64 입니다. 사실 Kubuntu를 개인적으로 더 좋아하긴 하지만 사정상 사용할 수 밖에 없었습니다. 그래서 좀 덜 익숙한 환경에서 삽질을 하고 있었답니다. 무참히 컴파일과 코딩, 에뮬레이션을 번갈아가며 말이죠..
이 OS개발이라는 작업이 제가 보기에도 모 횽님께서 하셨던 말씀인 "무한삽질"이라는 단어보다 더 잘표현할 단어는 없는 듯 보입니다. 그래서 오늘도 여러건 해먹었구요. 아우 그냥 Vmware가 픽픽 죽어나자빠지는데 어떻게 표현할 길이 없더군요. 이건 어디서 왜 죽는지도 모르는 상황이라. 그냥 답답하게 이러니 저러니 테스트하면서 개발하고 있었습니다.
위 코드로 Video Buffer에 해당하는 메모리 구역에 문자를 직접 써넣어 주는 상황을 제작했는데, 입력위치가 오른쪽 하단 에 입력하는 것입니다. 그런데 이게 Scroll 기능을 구현하고 테스트를 하는데 마지막 줄이 스크롤 되면 무조건 Vmware 가 이유없이 리붓이 되네요 ㅜㅜ. 그렇게 해서 한 두어시간 삽질을 진행하고 한 줄씩 디버깅을 하는데!! CpiTextBuffer 라는 클래스 내부에서 'x', 'y', 'z' 에 해당하는 문자를 고정된 위치에 한 번씩 뿌리는데 y 라는 얘가 z로 변하는 게 아닙니까? @0@ 그래서.. 이걸 단서로 찾다가 찾다가 보니. 바로 ImageWriter에서 Binary모드로 파일을 오픈한게 아니더라구요 ㅜㅜ 이런.. 제길.. 이라는 말이 절로 나오더군요.
사실은 맨 처음에 문자를 출력했는데도 불구하고 이상한 문자만 나오길래 이거 Vmware의 -ㅅ- 버그가 아닌가 내심생각을 해서 qemu 를 비롯해서 여러가지 에뮬레이터를 다운받아서 진행을 해봤고, Hex Editor 를 통한 직접적인 Kernel Image Writing을 하다보니 문제가 없었습니다. 그래서 설마 하고 Hex Editor 를 통해서 Vmware 데이터에도 써주니 제대로 동작을 하는!! @0@.. 결국 문제는 편의를 위해서 만들었던 OS Image Writer였습니다.ㅜㅜ 그래도 해결이 되어서 다행이네요. 현재 보이는 CpiTextBuffer 라는 클래스는 TextMode VideoBuffer를 제어하기 위해서 대충 구현이 된 클래스입니다. 대략적으로 기능은 아래와 같은 함수들로 구성이 되어있네요.
동방환상마작 포스팅 이후로 오랜 시간이 흐른 뒤의 포스팅입니다. 그 동안 병역특례의 기간도 끝을 보게 되었고, 한 달 여 정도 문서와 구글속에서 파묻혀 살았습니다. 사실 게임도 아주 약간 했다는 것을 숨길 수는 없겠습니다. 전체적으로 구상도가 정리되지 않는 문서를 보고 있으려니 아주 막막하더라구요^^. 그리하여 한 달 정도 여러가지 문서를 보고 다른 할 일도 처리하면서 시간을 보냈습니다. 아래의 것이 그 결과물 입니다(?)
처음에 보이는 깨지는 문자를 C 로 쓴 커널Entry 에서 보이도록 만들었는데 작동합니다. ㅜㅜ 사실 여태까지 한 번도 롱모드 쪽으로는 전환해본적이 없는데 일단은 성공을 했습니다. 그런데 아마.. 이제부터 시작일 것 같군요^^; IDT를 비롯해서 Memory Management 쪽도 만들어야 하고.. 할 일이 많을것 같습니다. 맨 처음에는 BIOS 인터럽트를 이용하여 부트로더에서 커널로더를 올렸고, 커널로더에서는 x64의 롱모드로 진입 후, CHS모드를 이용하여 데이터를 직접 1MB 영역에 올렸습니다. 그런 다음에 바로 점프를 한셈이구요. rep 를 붙여서 명령어를 돌리는데, 왜 계속 리부팅 되지 되지 하다가.. rcx 가 아니라 ecx 로 데이터를 준 것을 발견하고 삽질 중에 고쳐서 겨우 진입 했습니다. 이게 바로 삽질의 매력(?) 인가요 ㅜㅜ 일단 어쨌든.. 앞으로 할 것이 많이 남은 듯 하군요^^;
보호모드 진입을 위해서 IA32&64 문서를 보고 있군요. 그래도 대충 얻은게 여러가지가 있군요. 사실 보호모드 진입을 위해서 너무 많은 것이 필요하리라 생각하였는데, 예상외로 적은게 필요하더군요. 더불어 x64인 롱모드로 진입을 하려면 32비트 보호모드를 진입한 뒤, 페이징을 비활성화한 뒤, PAE를 활성화 하는 등의 작업을 마련하고 다시 페이징을 활성화 하면 되는 것을 알겠더군요. 물론 그게 실제 코드로 진행 되었을 때 쉬우리라는 보장은 없습니다^^; 일단 GDT, LDT, IDT에 대해서는 그래도 어느정도 파악이 된 것 같습니다. 몇 가지 의심되는 것이 확인 된다면 바로 코드를 작성할 수 있겠군요. 그나저나 별도의 컴파일이 아닌 한 번의 컴파일로 코드 및 부트로더의 코드 생성을 원하는 데, nasm에서 masm으로 잠시 코드를 변환하여 링크를 걸어봤는데, 뭔지 모르게 약간 안 맞아들어가는 부분이 있군요. 그래도 어떻게 방법을 찾으면 있을것 같기는 합니다. 개인적으론 VS.net 이 IDE중에선 가장 편하기 때문에 VS.net으로 해보려고 하는데, 쩝쩝 아직 잘 되지 않습니다. 자료를 더 살펴본 뒤, 진행된 결과를 올려보도록 하겠습니다^^.
댓글을 달아 주세요
관리자만 볼 수 있는 댓글입니다.
음.. 한글화 파일 0.5 버젼은 따로 네이버 동방환상마작 까페에 보시면 있을겁니다.
리비젼 2는 되지 있지 않구요.. 1만 된 상태에 그것도 완전하지는 않습니다.