리눅스가 부팅된 후 커널모드에서 유저모드로 어떻게 넘어가나요?
커널 모드에서 유저 모드 프로세스를 어떻게 실행하는지 알고 싶습니다.
여기서 말하는 모드는 프로세서의 권한이 0에서 3으로 변환되는 과정입니다.
init 프로세스가 처음으로 실행되는 유저 프로세스라고 알고있습니다.
그래서 start_kernel 함수를 보고 있는데요
start_kernel 함수안에서 rest_init 이라는 함수가 실행되고
rest_init 에서 kernel_thread 라는 함수를 호출합니다.
그리고 다음이 kernel_thread 함수의 내용입니다.
fork 시스템 콜을 호출해서 init 프로세스를 만든 다음
그냥 call 명령으로 init 프로세스를 시작하는 방식으로 보입니다.
제가 보기에는 커널 모드에서 그냥 call 명령을 실행하고
그러면 init 프로세스가 커널 모드에서 실행되지 유저 모드가 아닌것 같습니다.
어떻게 커널 모드에서 유저모드로 옮기는지 궁금합니다.
예를 들어 만들면서 배우는 OS 커널의 구조와 원리라는 책에서는
태스크 레지스터를 이용해서 iretd 명령으로 유저 프로세스로 점프를 하는데요
리눅스에서는 어떻게 하는지 알고싶습니다.
497 int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
498 {
499 long retval, d0;
500
501 __asm__ __volatile__(
502 "movl %%esp,%%esi\n\t"
503 "int $0x80\n\t" /* Linux/i386 system call */
504 "cmpl %%esp,%%esi\n\t" /* child or parent? */
505 "je 1f\n\t" /* parent - jump */
506 /* Load the argument into eax, and push it. That way, it does
507 * not matter whether the called function is compiled with
508 * -mregparm or not. */
509 "movl %4,%%eax\n\t"
510 "pushl %%eax\n\t"
511 "call *%5\n\t" /* call fn */
512 "movl %3,%0\n\t" /* exit */
513 "int $0x80\n"
514 "1:\t"
515 :"=&a" (retval), "=&S" (d0)
516 :"" (__NR_clone), "i" (__NR_exit),
517 "r" (arg), "r" (fn),
518 "b" (flags | CLONE_VM)
519 : "memory");
520 return retval;
521 }
init()는 kernel thread가 맞습니다.
init 함수의 내용을 보시면 원하시는 부분을 알 수 있습니다.
즉, 그냥 fork 하는겁니다. (execve가 수행되지만 기본은 fork죠)
프로세스 생성에 대한 체계가 갖춰진 운영체제에서 일일이 iret으로 프로세스를 생성하는 모습을 보여주지는 않습니다. 끝까지 따라가보면 인터럽트에 의한 context switching이 나오겠지만 편리하게 system call을 만들어 둔 상태에서 일일이 수작업으로 context switching할 필요는 없으니까요.
답변이 아니라서 죄송 ㅜㅠ
:예를 들어 만들면서 배우는 OS 커널의 구조와 원리라는 책에서는
:태스크 레지스터를 이용해서 iretd 명령으로 유저 프로세스로 점프를 하는데요
이 부분좀 구체적으로 설명해주실수 없을까요? ㅜㅠ 공부하는데
이해가 잘 안대네요 ㅠㅠ
부탁드립니다.
리눅스 커널의
리눅스 커널의 이해라는 책에서는 tr 레지스터에 tss 세그먼트를 만들어서
커널의 컨텍스트를 저장하고 스위칭을 한다고 나온것 같은데요..
그런데 커널 소스에는 ltr 명령어를 사용하는 부분이 없는것 같구요
제 생각에는 유저 프로세스마다 따로 커널 스택을 하나씩 가지고 있으니까
굳이 ltr 명령어와 tr 레지스터를 사용할 필요없이
iret 명령어로 유저 프로세스로 점프하고
커널로 진입하면 실행되던 유저모드 스택에 포인터 저장하고
유저 프로세스의 커널 스택에 커널 컨텍스트를 저장했다가
다시 유저 모드 스택의 포인터를 꺼내서 복귀하고..
말이 저도 헛갈리네요.
일단 tr 레지스터를 쓰지 않아도 될것 같습니다.
유저 프로세스마다 따로 커널 스택을 가지고 있으니까요.
공통의 커널 스택을 가지려면 tr 이 필요하지만 그게 아니니까요.
좀더 공부해서 제 손으로 만들어봐야 이해가 될것 같습니다.
근데 리눅스 커널의 이해에는 분명이 tr 레지스터를 쓴다고 나오는데 도통 이해가 안되네요.
----
세상을 바꾸는 것은 단 한 사람. 오직 하나님의 사람뿐이다.
댓글 달기