1. 유저 모드 세그먼트
다음 코드는 유저 모드 세그먼트영역을 지정하는 디스크립터입니다.
dd 0x0000FFFF, 0x00FCFA00 dd 0x0000FFFF, 0x00FCF200 |
유저 모드의 코드 세그먼트
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
0xFFFF |
|||||||||||||||
0x0000 |
|||||||||||||||
1 |
11 |
1 |
1010 |
0x00 |
|||||||||||
0x00 |
1 |
1 |
1 |
1 |
0xC |
||||||||||
63 |
62 |
61 |
60 |
59 |
58 |
57 |
56 |
55 |
54 |
53 |
52 |
51 |
50 |
49 |
48 |
유저모드의 데이터 세그먼트
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
0xFFFF |
|||||||||||||||
0x0000 |
|||||||||||||||
1 |
11 |
1 |
0010 |
0x00 |
|||||||||||
0x00 |
1 |
1 |
1 |
1 |
0xC |
||||||||||
63 |
62 |
61 |
60 |
59 |
58 |
57 |
56 |
55 |
54 |
53 |
52 |
51 |
50 |
49 |
48 |
이 디스크립터의 셀렉터 번호는 다음과 같이 나타냅니다.
UserCodeSelector equ 0x28+3 UserDataSelector equ 0x30+3 |
3을 더하는 것은 세그먼트 셀렉터의 RPL 부분에 유저 모드를 뜻하는 권한 레벨 3을 넣어주겠다는 의미입니다.
15 |
|
|
|
|
|
|
|
|
|
|
|
3 |
2 |
1 |
0 |
|
|
|
|
|
|
|
|
|
|
1 |
0 |
1 |
0 |
1 |
1 |
15 |
|
|
|
|
|
|
|
|
|
|
|
3 |
2 |
1 |
0 |
|
|
|
|
|
|
|
|
|
|
1 |
1 |
0 |
0 |
1 |
1 |
세그먼트 디스크립터는5번, 6번째 위치에 있고, TI가 모두 0이므로 GDT에 존재함을 알 수 있습니다.
2. 콜게이트 설정
GDT에 콜 게이트 디스크립터를 만들었습니다.
descriptor7: dw 0 dw SysCodeSelector db 0x02 db 0xEC db 0 db 0 |
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
0x00 |
|||||||||||||||
SysCodeSelector (ox08) |
|||||||||||||||
1 |
11 |
0 |
1 |
1 |
0 |
0 |
|
사용안함 |
0x2 |
||||||
0x00 |
|||||||||||||||
63 |
62 |
61 |
60 |
59 |
58 |
57 |
56 |
55 |
54 |
53 |
52 |
51 |
50 |
49 |
48 |
커널 루틴의 오프셋 부분이 0으로 설정되어 있고, 이 부분은 Protected Mode로 들어오기 전에 다시 채워 넣을 것입니다. 미리 인수의 개수를 2로 지정하여 인수를 2개 사용합니다.
Printf의 오프셋은 0x00AD 입니다. (채워질 주소 값은 0x10000+0x00AD = 0x100AD)
xor eax, eax lea eax, [printf] add eax, 0x10000 mov [descriptor7], ax shr eax, 16 mov [descriptor7+6], al mov [descriptor7+7], ah |
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
0x00AD |
|||||||||||||||
SysCodeSelector (ox08) |
|||||||||||||||
1 |
11 |
0 |
1 |
1 |
0 |
0 |
|
사용 안함 |
0x2 |
||||||
0x0001 |
|||||||||||||||
63 |
62 |
61 |
60 |
59 |
58 |
57 |
56 |
55 |
54 |
53 |
52 |
51 |
50 |
49 |
48 |
Protected 모드로 들어온 후, 임의의 값을 tts_esp0에 넣어, 커널이 사용할 스택으로 지정합니다. 여기서는 일단 PM_Start의 주소를 지정 합니다. 스택은 거꾸로 자람으로 메모리의 주소 마이너스 방향으로 자라납니다 . PM_Start 위에는 더 이상 사용하지 않는 루틴이 존재하므로 사용해도 좋습니다.
lea esp, [PM_Start]
mov ax, TSSSelector ltr ax
mov [tss_esp0], esp lea eax, [PM_Start-256] mov [tss_esp], eax |
3. 유저 모드로의 태스크 스위칭
유저 모드의 태스크를 실행시키겠습니다. Protected Mode로 들어와 TR 레지스터, TSS영역을 세팅 후, 유저모드 인 것 처럼 설정하여 IRET 명령을 통해 유저 모드의 태스크를 실행시킵니다.
(1) 세그먼트 셋팅 – 유저 데이터 영역 세그먼트로
mov ax, UserDataSelector mov ds, ax mov es, ax mov fs, ax mov gs, ax |
데이터 관련 세그먼트에 UserDataSelector 값을 넣어줍니다.
현재 ESP 레지스터에는 커널 모드의 스택의 시작 주소를 지정하는 PM_Start가 저장되어 있으므로 유저 모드 스택으로 바꾸어 주기 위해 PM_Start-256 값을 지정합니다.
Lea esp, [PM_Start-256] |
(2) 인터럽트에 걸린 것 처럼 스택을 채우기
인터럽트 루틴에서 유저 모드의 레지스터를 스택에 저장해놓았다가 수행을 마치고, 유저 모드로 돌아갈 때 다시 복귀 시킵니다. 인터럽트 루틴을 수행한 것은 아니지만, 그런 상황을 다음과 같이 재현하여, 유저 태스크를 실행시킬 것입니다.
UserDataSelector(SS) |
Esp(ESP) |
0x200(EPLAGS) |
UserCodeSelector(CS) |
User_process(EIP) |
|
Push 명령어로 다음과 같이 스택을 꾸며줍니다.
push dword UserDataSelector push esp push dword 0x200 push dword UserCodeSelector lea eax, [user_process] push eax iretd |
IRET으로 돌아갈 때 유저 모드에서 사용하는 SS 는 복구되지만 DS, ES, Fs, GS 셀렉터들은 값이 복구 되지 않아 미리 값을 채웠습니다.
EIP가 user_process 함수의 주소(오프셋)로 지정되어 있기 때문에 user_process를 실행합니다.
4. 콜게이트를 사용한 시스템 콜
커널 모드의 함수인 printf를 실행하기 위해 콜 게이트를 이용하여 시스템 콜을 합니다. 다음과 같이 스택이 만들어 집니다.
(1) 특권 레벨 3의 스택 : 인자2개
80*2*7 |
|
Parameter1 |
←ESP |
|
(2) 특권 레벨1 의 스택 :
|
SS |
|
ESP |
|
|
80*2*7 |
←EBP+8 |
|
Parameter1 |
||
|
Cs |
←EBP |
EIP |
||
|
ES |
←ESP |
EAX |
printf: mov ebp, esp push es push eax mov ax, VideoSelector mov es, ax mov esi, [ebp+8] mov edi, [ebp+12] |
Printf 함수에서는 먼저 esp(tss의 esp0)의 값을 ebp에 지정을 합니다. 프로그램 진행 중에 바뀔 esp 값을 복원하기 위해 백업해 둔 것입니다.
EBP+8을 하여 첫번째 인수인 문자열을 접근 할 수 있고, 두번째 인수는 EBP+12를 사용해 접근 할 수 있습니다.
'Operating Systems > OS 커널 제작' 카테고리의 다른 글
8. 페이징 (1) – A20 게이트 (0) | 2015.02.03 |
---|---|
7. 유저 모드 Task Switching (2) – 여러 개의 유저 모드 태스크 (0) | 2015.02.02 |
6. 보호 (2) – 특권 레벨 (0) | 2015.01.29 |
6. 보호 (1) - cpu (0) | 2015.01.28 |
5. Task Switching (2) – 태스크 스위칭 (0) | 2015.01.26 |