CPU에 정해진 기능을 사용하지 않고 Task Switching을 할 수도 있다.
이 방법은 Protected Mode에서 TR 레지스터와 TSS 영역 등을 세팅한 후 유저 모드인 것처럼 가장하여 IRET 명령을 통해 유저 모드의 태스크를 실행시킨다.
mov ax, UserDataSelector ; 데이터 세그먼트를 유저 모드로 지정
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
lea esp, [PM_Start-256] ; PM_Start 이전 부분은 더이상 쓸 일이 없으므로 스택으로 쓴다.
push dword UserDataSelector ; SS
push esp ; ESP
push dword 0x200 ; EFLAGS
push dword UserCodeSelector ; CS
lea eax, [user_process]
push eax ; EIP
iretd ; 유저 모드 태스크로 점프
이 방식은 유저모드에서 인터럽트가 걸려 커널 모드에서 인터럽트 핸들러를 수행하고 다시 유저모드 Task로 돌아가는 것처럼 흉내낸 것이다.
user_process:
mov edi, 80*2*7
push edi
lea eax, [msg_user_parameter1]
push eax
call 0x38:0
jmp $
msg_user_parameter1 db "This is User Parametr1", 0
유저 모드의 Task가 실행되면 여기부터 실행하는데 80*2*7 과 msg_user_parameter1의 주소를 인자로 넣고(스택에 PUSH) 하고 커널 모드의 함수를 호출하기 위해 '콜게이트 디스크립터'의 셀렉터인 0x38 사용하여 call 한다.
이때 콜게이트 디스크립터는 다음과 같이 설정되어있다.
descriptor7:
dw 0
dw SysCodeSelector
db 0x02
db 0xec
db 0
db 0
그리고 디스크립터 설정 하는 부분은 다음과 같다.
xor eax, eax
lea eax, [printf]
add eax, 0x10000
mov [descriptor7], ax
shr eax,16
mov [descriptor7+6], al
mov [descriptor7+7], ah
콜게이트 디스크립터에 printf 함수(메세지를 출력하는 사용자 정의 함수) 에 대한 정보를 기입한다.
그러므로 call 0x38:0은 커널 모드 함수 printf를 호출하게 되는 것이다.
printf:
mov ebp,esp
push es
push eax
mov ax, VideoSelector
mov es, ax
mov esi, [ebp+8] ; 첫번째 인자
mov edi, [ebp+12] ; 두번째 인자
printf_loop:
mov al, byte [esi]
mov byte [es:edi], al
inc edi
mov byte [es:edi], 0x06
inc esi
inc edi
or al, al
jz printf_end
jmp printf_loop
printf_end:
pop eax
pop es
ret ; 복귀
'Study > Kenrel' 카테고리의 다른 글
a20게이트 & 페이징 (0) | 2015.10.06 |
---|---|
여러개의 Task 일때 Task Switching (0) | 2015.10.01 |
Protected Mode에서의 보호 (0) | 2015.09.30 |
Task Switching in Kernel (0) | 2015.09.25 |
PIC 초기화 (0) | 2015.09.24 |