시스템콜 - 커널영역의 명령어를 사용하는 Limited Direct Execution

cpu는 물리적으로 1개인데 모드를 유저모드냐 커널모드냐에 따라서 완전히 다르게 동작한다.

우선 커널 모드는 privileged 모드로, cpu가 할 수 있는 모든 일을 처리 할 수 있다.

그러나 유저 모드에서는 민감한 명령어들은 사용할 수 없는데, 인터럽트나 IO 관련한 작업 등은 커널에서만 동작한다.

그 대신 커널의 여러가지 기능을 사용자에게 시스템콜 형식으로 제공함으로써 유저들이 이런 처리를 프로그램에서 할 수 있게 해준다.

이렇게 사용자가 커널 모드의 명령어를 실행시키면서도, cpu를 성능적으로 손실 없게 사용할 수 있도록 하는 방식이 limited direct execution이다.


유저 프로그램을 실행시키면 OS에 의해 로딩돼서 메모리에 탑재되는데, 커널 역시 메모리에 각종 핸들러나 시스템 콜 테이블 등등이 올라가있어야 한다(이는 처음에 부팅할 때 로딩되어 있다).

우선은 프로그램카운터(PC)가 유저 프로그램을 가리킴으로써 cpu가 유저 모드로 처리하는데, 이 때 privileged 명령어들을 처리해야할 경우에는 PC가 커널 영역을 가리킴으로써 커널 모드로 바뀌어야 한다.

이를 위해 Trap 이라는 개념이 등장하는데, 트랩이 걸릴 경우에는 PC가 미리 지정해놓은 곳으로 바뀌게 된다.

트랩을 처리할 핸들러의 위치를 지정해놓음으로써 하드웨어적으로 PC의 값을 변경하는데, 이 때 커널 영역을 가리키게 할 수 있는 것이다.

유저 모드로 유저의 프로그램을 실행하다가 트랩에 걸려 PC가 튀면서 커널 모드로 바뀌는데, 이는 유저 프로그램에서 시스템 콜을 호출함으로써 발생한다.

유저 프로그램에서, 파일이든 표준출력이든 사용자가 뭔가 출력을 하고 싶을 때 write()를 호출할 경우에 해당한다.

write 라는 시스템 콜은, 자신에게 맞는 어떤 값을 레지스터에 세팅해놓은 뒤 INT 등의 명령어를 통해 트랩을 발생시키는 함수이기 때문에, 사용자가 write 를 호출할 경우에 PC가 커널영역에 존재하는 트랩 핸들러로 넘어가는 것이다.

트랩핸들러에서는 cpu가 약속된 레지스터에 있는 값을 확인하도록 구성되어있다.

즉 write가 레지스터에 세팅해놓은 값을 확인한 뒤, 시스템 콜 테이블에서 해당 오프셋을 찾아가 연결되어있는 함수를 실행시킴으로써, 유저 프로그램에서 커널 모드에서만 가능한 함수를 동작시킬 수 있는 것이다.


좀 더 자세히 정리하자면,

  1. 먼저 커널 모드에서 운영체제가 프로세스를 생성한 뒤, 메모리에 코드를 올리고, 스택 힙 데이터 등의 영역을 세팅한다.

  2. 메모리의 커널 스택에 있는 값들을 cpu의 레지스터들에 싹 복사함으로써 해당 프로그램을 위해 레지스터가 준비되며, PC 역시 세팅되기 때문에 자연스럽게 사람 입장에서 볼 때 커널 모드에서 유저 모드로 변경되는 것이다.

  3. 유저 프로그램의 main 함수 실행되고, 프로그래머가 짜놓은 코드대로 순차적으로 실행된다.

  4. 프로그램 안에서 시스템 콜을 호출하는 부분을 만날 경우, 해당 시스템 콜 함수는 미리 약속된 값(시스템콜을 구별할 수 있는)을 약속된 레지스터에 세팅한 뒤 트랩을 발생시키도록 구현되어있기 때문에, 트랩이 발생한다.

  5. 트랩에 걸리면 하드웨어적으로 현재 유저 프로그램에서 사용하던 레지스터값들을 커널 스택에 저장한다(커널 모드에서 레지스터값들을 손상시킬 수 있기 때문에).

  6. 이 때 PC가 약속된 트랩핸들러 위치로 세팅되어, 커널 모드로 넘어오면서 정의된 핸들러대로 cpu가 일을 한다.

  7. 핸들러에는 시스템 콜 테이블이 존재하고, 테이블 안에는 여러 함수들을 정의해놓은 위치가 담겨있기 때문에, 사용자 프로그램에서 약속된 레지스터에 세팅해놓은 값(4번 과정)을 읽어온 뒤 테이블에서 해당 함수를 찾아 실행시킨다.

  8. 처리가 끝나면 다시 유저 모드로 돌아가기 위해, 커널 스택의 레지스터 값들을 복원시킨다.

  9. 유저 프로그램으로 돌아와 나머지 코드들을 마저 실행한다.

  10. exit() 등으로 프로그램을 종료시키는 경우에도, exit 도 시스템콜이기 때문에 똑같이 트랩을 발생시키고, 커널 모드로 바뀐 뒤 메모리 해제하고 프로세스를 종료시키는 등의 행동을 수행한다.