[OS 개발 17] 태스크 스위칭과 보호 (2) - CALL 스위칭


1. CALL 스위칭으로 변경하기


 

앞서 포스팅에서 현재 태스크에서 다음 태스크로 넘어갈 때, jmp나 Call을 사용한다고 했습니다. 이번에는 앞에서 봤던 코드를 활용하여 CALL 방식으로 프로세스를 불러들이도록 하겠습니다. 따라서 코드를 변경해야 하는데, 지난 코드에서 일부만 수정해 보았습니다.

 

jmp TSS2Selector:0    -->    CALL TSSSelector:0    ; CALL 명령으로 태스크 스위칭 한다.

 

jmp $                        -->    iret                            ; 이전 태스크로 다시 돌아간다.

 

 


2. CALL 스위칭


 

CALL과 jmp의 가장 큰 차이는 jmp는 다음 태스크를 실행 후, 다시 돌아올 때에도 jmp를 통해 돌아오는 반면, CALL 명령은 iret 명령을 통해 돌아온다는 점입니다.

 

그리고 CALL 명령은 EFLAGS의 NT 비트와 TSS 세그먼트 디스크립터 Type 필드의 B 비트를 검사함으로써 작동됩니다.

 

1. NT비트

 먼저 EFLAGS는 아래와 같이 구성되어 있는데, NT비트는 14번째 비트에 위치해 있습니다. (여기서 NT는 Nested의 약자로 중첩되다라는 의미를 지닌다. 즉, NT 비트는 IRET과 CALL을 구별해주기 위해 사용된다) 

 

 

CALL 을 통한 태스크 스위칭을 할 때, CALL과 IRET 모두 CALL 스위칭의 개념입니다. 즉, Iret을 통해 다시 이전 태스크로 돌아가는 것도 CALL 명령과 같은 것입니다. 따라서 스위칭될 때 CALL로 다음 태스크로 넘어가는지, 아니면 Iret으로 이전 태스크로 돌아가는건지 구분해야 할 필요가 있는데, 이 때 NT 비트를 사용합니다.


 

 

NT 비트는 다음과 같이 사용됩니다:

 

태스크 1 ----------------CALL 스위칭----------------> 태스크 2     : NT 비트 = 1

 ↓

 

태스크 1 <---------------IRET 스위칭------------------ 태스크 2     : NT 비트 = 0

 

 

2. B비트

 B비트는 세그먼트 디스크립터의 TYPE 필드에서 (왼쪽에서)2번째 비트에 자리하고 있습니다.

 

1) 태스크1에서 태스크2로 CALL할 때 태스크1이 0인지 검사합니다.

2) 태스크1이 0이면 1로 변환하고 스위칭한 후 태스크 2도 1로 변환합니다.

3) 태스크 2에서 태스크 1로 IRET할 때 태스크1이 1인지 검사합니다.

4) 태스크 1이 1이면 태스크2를 0으로 변환하고 스위칭한 후 태스크 1도 0으로 변환합니다.

이 후 이러한 작업을 반복합니다.

 

 

3. Previous Task Link 16비트

 

이전 태스크로 되돌아가기 위해 저장되어 있던 16비트를 사용하여 이전 태스크를 찾습니다.

 


 

그리고 이러한 과정 중 만약 태스크 2에서 인터럽트가 걸린다면?

 

1. 그 순간 CS, EIP, EFLAGS를 모두 메모리 스택으로 PUSH하여 저장합니다.

2. CPU에서는 이들 레지스터를 모두0으로 초기화 합니다.

3. 인터럽트 핸들러를 실행합니다.

4. 인터럽트 핸들러가 끝나고 IRET해서 다시 돌아오면 메모리에 있던 레지스터를 모두 POP 합니다.

5. 이후 위의 B비트와 NT비트에 대해 소개했던 과정들을 진행합니다.

 


 


TAGS.

Comments