1. Task Switching 과 TSS
Intel 80286 이상의 CPU는 Protected Mode에서 CPU 레벨에서 태스크 스위칭을 지원합니다.
태스크 스위칭이 일어나는 동안 각 프로그램에서 사용하는 레지스터의 값을 저장하고, 복원 시키기 위해서 레지스터를 보관하는 장소가 필요합니다. 이러한 영역을 TSS(Task State Segment)라고 합니다. GDT 처럼 TSS를 지정하는 TSS 디스크립터가 GDT에 지정되어야 합니다.
31 |
15 |
|
I/O 맵의 Base Address |
사용안함 |
T |
사용안함 |
LDT 세그먼트 셀렉터 |
|
사용안함 |
GS |
|
사용안함 |
FS |
|
사용안함 |
DS |
|
사용안함 |
SS |
|
사용안함 |
CS |
|
사용안함 |
ES |
|
EDI |
||
ESI |
||
EBP |
||
ESP |
||
EBX |
||
EDX |
||
ECX |
||
EAX |
||
EFLAGS |
||
EIP |
||
CR3(PDBR) |
||
사용안함 |
SS2 |
|
ESP2 |
||
사용안함 |
SS1 |
|
ESP1 |
||
사용안함 |
SS0 |
|
ESP0 |
||
사용안함 |
이전 태스크로의 링크 |
GDTR, IDTR, CR0, CR1레지스터와 같은 모든 태스크가 공유하는 레지스터를 제외하고 모든 레지스터가 포함되어 있습니다.
다음 코드는 tss를 지정하는 코드입니다.
위 그림은 아래부터 위로 증가하며, 아래 코드는 위에서 아래로 증가합니다.
tss1: dw 0, 0 ; 이전 태스크로의 back link dd 0 ; ESP0 dw 0, 0 ; SS0, 사용 안함 dd 0 ; ESP1 dw 0, 0 ; SS1, 사용 안함 dd 0 ; ESP2 dw 0, 0 ; SS2, 사용 안함 dd 0, 0, 0 ; CR3, EIP, EFLAGS dd 0, 0, 0, 0 ; EAX, ECX, EDX, EBX dd 0, 0, 0, 0 ; ESP, EBP, ESI, EDI dw 0, 0 ; ES, 사용 안함 dw 0, 0 ; CS, 사용 안함 dw 0, 0 ; SS, 사용 안함 dw 0, 0 ; DS, 사용 안함 dw 0, 0 ; FS, 사용 안함 dw 0, 0 ; GS, 사용 안함 dw 0, 0 ; LDT, 사용 안함 dw 0, 0 ; 디버그용 T 비트, IO 허가 비트맵 |
각 항목에 대해서 자세히 알아봅시다.
(1) 이전 태스크로의 back link
이전에 동작하던 프로그램의 TSS 영역의 세그먼트 셀렉터 값이 들어갑니다. 이 세그먼트 셀렉터를 이용하여 JMP, CALL 명령을 실행하여 태스크 스위칭을 하게 됩니다. CALL 명령어로 태스크 스위칭을 하게 되면, 다음 태스크는 자신의 TSS영역에 이전 태스크 TSS 디스크립터의 셀렉터 값을 저장 해 두었다가 IRET 명령어 후, 이전 태스크로 스위칭을 합니다.
(2) ESP0, SS0
시스템이 사용하는 권한 레벨별로 사용할 스택이 따로 존재합니다. ESP3, SS3은 없고, 유저 레벨 스택은 TTS의 ESP와 SS에 저장 됩니다.
(3) CR3
페이지 구현과 관련이 있는 레지스터 입니다.
(4) 디버그용 T비트
유저 레벨 태스크를 디버깅 할 때 , 태스크 스위칭이 일어나면 디버깅 주잉었다는 것을 표시하기 위해 T 비트에 설정을 합니다.
(5) I/O 허가 비트맵
유저레벨태스크는 주변 장치를 제멋대로 사용할 수 없어, I/O 허가 비트맵을 사용하여 사용할 수 있는 장비와, 사용할 수 없는 장비를 구분지어 줍니다. RAM의 한 영역에 표시하는데, 이 영역의 시작주소를 TSS의 I/O 허가 비트맵 칸에 넣어둡니다.
TSS 세그먼트 디스크립터
TSS 세그먼트 디스크립터도 GDT에 들어가므로 형태가 비슷합니다.
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
Lmit의 15 - 0비트 |
|||||||||||||||
Base Address의 15 - 0비트 |
|||||||||||||||
P |
DPL |
0 |
Type |
Base Address의 23 – 16 비트 |
|||||||||||
Base Address의 31 – 24 비트 |
G |
0 |
0 |
AVL |
Lmit의 19 - 16비트 |
||||||||||
63 |
62 |
61 |
60 |
59 |
58 |
57 |
56 |
55 |
54 |
53 |
52 |
51 |
50 |
49 |
48 |
다음 코드는 TSS 디스크립터를 기술 한 것이고, 아래 그림은 표로 나타낸 것 입니다.
descriptor4: dw 104 dw 0 db 0 db 0x89 db 0 db 0 |
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
(1) 0x68 |
|||||||||||||||
(3) 0 |
|||||||||||||||
1 |
00 |
0 |
(2) 1001 |
(3) 0 |
|||||||||||
0 |
0 |
0 |
0 |
0 |
0 |
||||||||||
63 |
62 |
61 |
60 |
59 |
58 |
57 |
56 |
55 |
54 |
53 |
52 |
51 |
50 |
49 |
48 |
(1) TSS 디스크립터에서는 항상 limit 값이 0x68 이상이어야 하며, 그렇지 않으면 TSS 예외(#TS)가 발생합니다.
(2) Type 부분은 다음과 같습니다.
1 |
0 |
B |
1 |
1과 0 부분은 고정된 부분이며, B비트는 현재 이 태스크의 상태, 실행/대기를 나타냅니다. 처음에는 0으로 클리어 합니다.
(3) Base address에는 TSS 영역의 시작 주소를 넣습니다.
위의 코드에는TSS 세그먼트 디스크립터에 base address에 0을 기술하였습니다. 이 부분에는 원래 TSS영역의 시작 주소를 넣어 주어야 됩니다. 따라서 실행 코드에서는 Base Address를 넣도록 합니다.
다음 코드가 TSS 세그먼트 디스크립터에 Base address를 채워주는 코드 입니다.
tss1의 주소(offset)+0x10000 한 뒤 값을 16비트와 8비트와 8비트로 나눠 각각 저장합니다. 3단계로 나눠서 살펴보겠습니다.
xor ebx, ebx lea eax, [tss1] ; 1) tss1의 주소를 구함 add eax, 0x10000 ; 2) base address 0x10000 를 더함 mov [descriptor4+2], ax ; 3) 디스크립터에 알맞게 채워 넣음 shr eax, 16 ; mov [descriptor4+4], al ; mov [descriptor4+7], ah ; |
1) tss의 주소 구하기
18 00000009 6631DB xor ebx, ebx 19 0000000C 668D06[3A01] lea eax, [tss1] 20 00000011 660500000100 add eax, 0x10000 21 00000017 A3[2C01] mov [descriptor4+2], ax 22 0000001A 66C1E810 shr eax, 16 23 0000001E A2[2E01] mov [descriptor4+4], al 24 00000021 8826[3101] mov [descriptor4+7], ah |
소스 코드를 기계어 코드로 바꿔본 결과, tss1의 주소는 0x013A 인 것을 알아 내었습니다.
2) 0x10000를 더함
구한 tss의 주소에 base address인 0x10000을 더해줍니다.
(tss1 주소) + (base address) = 0x013A + 0x10000 = 0x1013A
3) 디스크립터에 알맞게 채워 넣음
Eax 레지스터에는 다음과 같이 저장이 되어 있습니다.
|
------- ax --------- |
||
|
---ah--- |
---al---- |
|
0x00 |
0x01 |
0x01 |
0x3A |
Descriptor4+2 주소에 ax, 즉 0x013A를 넣어줍니다.
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
0x68 |
|||||||||||||||
0x013A |
|||||||||||||||
1 |
00 |
0 |
1001 |
0 |
|||||||||||
0 |
0 |
0 |
0 |
0 |
0 |
||||||||||
63 |
62 |
61 |
60 |
59 |
58 |
57 |
56 |
55 |
54 |
53 |
52 |
51 |
50 |
49 |
48 |
그 다음 명령어는 Shr eax, 16으로 2바이트(16비트) 만큼 eax 레지스터의 값을 오른쪽으로 당겨줍니다 .
그 결과 eax 레지스터의 내용이 다음과 같이 변했습니다.
|
------- ax --------- |
||
→→ |
---ah--- |
---al---- |
|
|
|
0x00 |
0x01 |
al의 값을 Descriptor4+4, 즉 Base Address의 23 – 16 비트 영역에 넣어줍니다.
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
0x68 |
|||||||||||||||
0x013A |
|||||||||||||||
1 |
00 |
0 |
1001 |
0x01 |
|||||||||||
0 |
0 |
0 |
0 |
0 |
0 |
||||||||||
63 |
62 |
61 |
60 |
59 |
58 |
57 |
56 |
55 |
54 |
53 |
52 |
51 |
50 |
49 |
48 |
마지막으로 ah 의 내용을 Descriptor4+7, 즉 Base Address의 31-24비트 영역에 넣어 줍니다.
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
0x68 |
|||||||||||||||
0x013A |
|||||||||||||||
1 |
00 |
0 |
1001 |
0x01 |
|||||||||||
0x00 |
0 |
0 |
0 |
0 |
0 |
||||||||||
63 |
62 |
61 |
60 |
59 |
58 |
57 |
56 |
55 |
54 |
53 |
52 |
51 |
50 |
49 |
48 |
결과 Base address 영역에 값이 알맞게 나누어져 들어갔습니다.
Tss2도 마찬가지로 base address 영역을 채워줄 수 있습니다.
(4) CPU에 Tss 세그먼트의 위치를 알립니다.
Tss 세그먼트 디스크립터의 위치를 CPU에 알려야 사용할 수 있습니다. 그렇게 하기 위해 TR 레지스터에 TSS 디스크립터의 셀렉터를 넣어줍니다.
mov ax, TSS1Selector ltr ax |
Ltr 명령은 CPU의 TR 레지스터에 TSS 디스크립터 셀렉터 값을 넣는 명령입니다.
이로서 TSS 디스크립터의 설정이 끝났습니다.
'Operating Systems > OS 커널 제작' 카테고리의 다른 글
6. 보호 (1) - cpu (0) | 2015.01.28 |
---|---|
5. Task Switching (2) – 태스크 스위칭 (0) | 2015.01.26 |
4. Interrupt 와 Exception (4) - 예외 (0) | 2015.01.20 |
4. Interrupt 와 Exception (3) – 인터럽트 핸들러 (0) | 2015.01.19 |
4. Interrupt 와 Exception (2) - PIC (0) | 2015.01.18 |