어제 급히 Application Level, 즉 User Level을 추가했다가 낭패를 크게 봤습니다. ㅡ_ㅡa...  첫번째는 아무 생각없이 Supervisor Mode로 맵핑되어있는 Paging 때문에... 두번째는 요상하게 설정된 User Level Descriptor 때문에... 세번째는 Segment Selector에서 잘못된 RPL Field 때문에... 네번째는 RFLAGS에 있는 IOPL 때문에... 다섯번째는 Interrupt 발생 시, User Level에서 Kernel Level로 변경되어 자동으로 발생하는 Stack Switching 때문이었습니다. 헥헥... 나열하니 이거 끝이 없군요. ;)

 원래의 목적은 Application Level에서 커널 함수를 사용할 때 Interrupt를 사용해서 Kernel 레벨로 바꾸고, Interrupt를 활성화 한 상태에서 커널 코드를 실행하는 것이었습니다. 이렇게 하면 인터럽트 불가로 동작하는 시간이 줄어들기 때문에 인터럽트에 좀 더 기민하게 반응할 수 있습니다. 만약 윈도우 전체를 다시 그리는 커널 코드를 실행한다고 가정하면 그 시간이 얼마나 걸릴지... 그리고 그동안 인터럽트 처리가 안되면 어떻게 될지는 금방 상상이 되실겁니다. ^^;;;;;

 그런데 이게 Stack Switching이 발생하다보니, Kernel Level Stack을 Application들 끼리 공유하게 되더군요. 32bit 같은 경우는 Task 별로 TSS 영역이 존재해서 별도의 Kernel Stack을 할당해 줄 수 있었지만, 64Bit에서는 TSS가 Task에 종속적으로 존재하는 것이 아닙니다. 거의 Global하게 공통적으로 사용한다고 해도 될만큼 말입니다. ㅠㅠ

 하지만 커널 코드 수행 시, 인터럽트를 활성화하려면 태스크 별로 커널 스택을 별도로 가져야 하는데... 어떻게 할까 고민하다가 결국 Interrupt Service Routine에서 System Call용은 Kernel Stack에서 Application Stack으로 돌아가도록 했습니다. Stack Switching을 한번 더 한다는 이야기지요. 이렇게 하면 System Call 호출로 인해 Kernel Mode에 진입해 있지만 Stack은 Application의 Stack을 사용하기 때문에 커널 함수를 수행하는 도중 Task Switching이 발생해서 다른 Application이 Kernel로 진입해도 문제 없습니다.

 일단 대충 코드를 구현했는데... 오늘은 일찍 자는 날이라서 내일 테스트 해야겠군요. 별것 아닌 것 같은데... 해보니 별거(?)였다는... ㅠㅠ

 아직 내공이 많이 부족한가 봅니다. 크윽... 저의 애마(?) 마제스터치 키보드와 함께 계속 달려야겠군요.
 다들 그럼 좋은 밤 되세요. ;)


+ Recent posts