http://blog.naver.com/doulfguy?Redirect=Log&logNo=80014209279


hardware task switching과 software task switching | OS 개발  2005/06/19 14:10  


http://blog.naver.com/doulfguy/80014150015


먼저 현재 구현중인 software task switching에 관한 조그만 기록을 남기겠다.

내가 잡고 있는 개념대로 적어 갈것이기 때문에 표현이 잘못된 부분도 혹은 잘못알고 있는 부분이

있을 수도 있으니 혹 이 글이 절대적이라고는 생각치 말기 바란다.(아직 공부중인 학생이므로)

일반적으로 사용되는 인텔 CPU는 task switching을 위한 하드웨어적인 메커니즘을 제공하고 있다.

그것이 TSS 인데, 이 TSS에는 CPU의 문맥전환을 위해 존재하고 LTR 명령에 의해 TR 레지스터에

현재 수행할 문맥이 저장되어 있는 TSS의 TSS 셀렉터를 지정하고 CPU는 GDTR과 TR레지스터를

참조하여 GDT내에 존재하는 TSS디스크립터를 이용 실제 TSS영역을 참조한다. 이 TSS 영역은 인텔 메뉴얼을 보면 알 수 있듯이 CPU 수행에 필요한 모든 레지스터들을 기록할 수 있는 구조로 되어있고, 이 구조에 이전 문맥정보를 저장하고 다시 빼오는 식으로 문맥전환을 수월히 수행할 수 있는 것이다. 이는 단순 JMP 명령을 통해 TSS 셀렉터를 지정함으로써 자동으로 문맥전환이 수행되는데 벨로나 OS의 저자는 이를 놀라움 그자체라고 표현하기도 하였다. 가만히 생각해보면 정말 편리하고 잘 만들어진 방법인데, 현재 내가 구현하려고 하는 것은 이러한 하드웨어적 태스크 스위칭이 아닌 소프트웨어적인 태스크 스위칭이다.

그렇다면 왜 소프트웨어적으로 구현해야 하는지에 대해 알아보자..

1. 왜 소프트웨어 스위칭인가? (소프트웨어 스위칭의 장점) : 여러 이유들을 많은 사람들이 이야기 한다. 하지만 내가 생각했을때는 아래의 2가지가 가장 그럴싸한듯 싶다.

  - portable (타 CPU로의 이식이 간편하다 : 하지만 부분적으로 공감할수 없는 부분이 있다. 아래

     에서 알아보겠지만 software task switching 역시 TSS 를 사용하지 않을수 없다. 이러한 측면

     에서 본다면 스위칭 자체를 CPU에 맡기지 않고 소프트웨어적으로 구현한다는 것일뿐 완전 CP

     U 비 의존적이라고 보기는 힘들듯 싶다.)

  -  빠르다. (하드웨어적은 스위칭은 TSS 내의 모든 레지스터를 전환한다. 이는 부분적으로 변경할

     필요가 없는 레지스터까지도 변경한다는 의미가 되고 이러한 점이 문맥 전환시 CPU 클럭을 낭

     비할수 있다. 반면 소프트웨어적으로 구현한다면 필요한 레지스터만을 부분적으로 변경하면 되

     므로 처리속도가 빠르다. : 하지만 이 부분도 부분적으로는 의아한 부분이 있다. 처음 생각했을

     때는 하드웨어 스위칭이 당연히 속도가 빠를것이라 생각했었다. 그 이유는 소프트웨어에 비해

     하드웨어는 회로로 구성되어 있을 것이므로 당연 소프트웨어 처리보다 빠를 것이라는 생각이었

     는데 외국 사이트를 돌아다니다 보니 소프트웨어적 처리가 더 빠르다고 말하는 곳이 많다..)

     (필수 교환 문맥으로는 ESP, EBP, EDI, ESI이다) = 소프트웨어적 스위칭은 이 것만 교환해주면

     된다.

2. 왜 아직 TSS 가 필요한가? (처음생각은 CPU 비 의존적으로 제작하기 위해 TSS를 배제하고 제

   작할 예정이었다. 하지만 여러 자료를 첨부한 결과 TSS는 보호모드 상에서 동작하는 운영체제에

   서는 필수적인듯 싶다.)

  - TSS내의 I/O access Bit는 I/O장치의 접근 허가 권한을 의미하는데 이를 저장할 필요가 있다.

  - 커널 스택 포인터를 TSS 내에 저장할 필요가 있다.

: TSS를 사용치 않는다는 말을 하면 나오는 대답은 그렇다면 유저레벨(3)에서 시스템 레벨(0)으로의 권한 전환이 필요할시는 어떻게 하겠냐는 대답들을 한다. 이 이유를 생각해보면 유저레벨에서 Task Gate를 사용하여 커널레벨로 진입하면 CPU는 TSS내의 SS0, ESP0을 참조하여 커널 스택에 유저레벨에서 수행되던 프로그램의 문맥을 스택에 저장하기 때문이다. SS0과 ESP0을 알수 없다면 커널 스택은 어떻게 사용할 것인가?



3.그렇다면 어떻게 소프트 태스크 스위칭을 구현해야 할 것인가?

다음은 소프트 테스크 스위칭을 하면 흔히 볼 수 있는  Victor의 답변이다.

first, you have to save the other registers by hand.
Second, you have to save the old esp.
Third, you have to load a new esp.
Fourth, you have to restore the other regsters.
Fifth, you have to iretd back to the new task.

Your ring0 stack would look like this after the entry:
  -saved registers (you have to 'push' them) <- esp points here
  -eip
  -cs
  -eflg
  -esp3 => only here if you were at ring3 and used the tss to enter ring0
  -ss3  => -||-

You save the old esp0 (the current esp), and load the new one.
Then you can pop back all the registers, and iretd back to the
new task. (this method doesn't change paged address spaces)

For more info, read the official intel manuals. (volume 3.)

  Viktor

ps:
I would use an array of dwords (unsigned long int-s) for a stack.
Also, it is far simplier to write the task switcher in inline asm,
since you need stack push/pop-s, mov to/from the esp, and ire



현재 실제적인 구현은 구현중에 있으므로 구현이 완료되면 자세한 설명및 코드를 개제하도록 하겠당.. 처음에도 말했다시피 잘못된 부분이 있을수 있으므로 잘못된 부분이 있다면 덧글이나 likegame@hanmail.net으로 메일주세요..^^* 그럼 즐거운 하루...

저번에 hardware task switch와 software task switch에 대해 간략히 적어봤는데 오늘 읽은 책에 이부분에 대한 설명이 나온 부분이 있어서 약간 수정하도록 하겠다.

일단 인텔 아키텍처에서 제공하는 하드웨어 지원을 활용하여, far jmp 명령어를 통해 프로세스를 next 프로세스의 작업 상태 세그먼트 디스크립터의 셀렉터로 전환하는 하드웨어적인 방식은 자동으로 CPU가 이전 하드웨어 컨텍스트를 저장하고 새로운 컨텍스트를 로드하여 제작에 수월함을 줄수있다.(즉, 고민할 필요없이 스팩대로 구현만 하면 된다.)  하지만 다음과 같은 이유로 소프트웨어적인 태스크 스위칭이 필요하다.

1. 일련의 mov 명령어를 이용해 점진적으로 프로세스를 전환하면, 복구하는 데이터가 올바른지 더 확실히 통제할 수 있다. 특히 세그먼트 레지스터 값을 검사할 수 있다. 이런 종류의 검사는 간단히

far jmp 명령어를 사용하는 경우에는 불가능 하다.

2. 이전 접근 방법을 사용할 때 걸리는 시간과 새로운 방법을 사용할 때 걸리는 시간은 거의 같다. 그러나 현재 프로세스 전환 코드는 앞으로 개선할 수 있지만, 하드웨어 컨텍스트를 전환을 최적화 하는 것은 불가능 하다.



그럼, 소프트웨어적으로 구현되어도 TSS가 필요한 이유 부분도 약간 수정하겠다.

1. 80x86 CPU는 사용자 모드에서 커널모드로 전환할 때 TSS에서 커널 모드 스택의 주소를 가져온다.

2. 사용자 모드 프로세스가 in이나 out 명령어를 사용하여 입출력 포트에 접근하면 CPU는 프로세스가 해당 포트에 접근할 수 있는지 확인하려고 ,TSS에 들어 있는 입출력 권한 비트맵(I/O permission bitmap)에 접근할 수도 있다.



다음은 실제 문맥전환에 대해 좀더 깊숙히 들어가 보자.

시스템에 있는 CPU마다 TSS를 하나씩 할당한다.

(현재 CPU가 하나이므로 TSS 하나만 할당하면 됨)
   - 태스크 스위칭을 할때마다 커널은 TSS의 몇몇 필드를 갱신하여 해당 CPU의 제어 유닛이 필요

로 하는 정보를 안전하게 가져갈 수 있게 한다.


TSS에 대해 알아보기
각 TSS에는 GDT내에 존재하는 TSSD(Task State Segment Descriptor)가 있다.
이 디스크립터에는 TSS의 시작위치를 나타내는 32비트 Base field와 20비트 Limit 필드가 있다.
TSSD의 S 플래그는 0으로 설정하여 TSS가 '시스템 세그먼트'임을 나타낸다.
Type 필드는 세그먼트가 실제로 TSS임을 의미하는 9나 11값으로 설정된다.
인텔의 원래 설계에 따르면 시스템에 있는 각 프로세스는 자신만의 TSS를 참조해야 한다.
Type 필드의 하위 두번째 필드를 '사용중인 비트'라고 한다. 프로세스가 CPU에서 실행중이면 이

비트는 1이고, 그렇지 않으면 0이다. 현재 각 CPU마다 TSS가 하나만 있도록 하므로 사용중인 비트

는 항상 1이다. GDT의 시작주소는 gdtr 레지스터에 들어감. 각 CPUdml tr 레지스터는 해당 TSS의 TSSD 셀렉터를 포함한다. 프로세스 전환을 할때마다 교체되어 나가는 태스크의 컨텍스트를 어딘

가에 저장하여야 한다.

+ Recent posts