[Kernel] System Call에 대하여

두비니

·

2021. 4. 2. 17:04

 

 

 

 


System Call


 

 

 

 

오늘은 System Call에 대해서 정리해볼겁니다.

포너블하면서 겉핥기한정도가 끝인데, 제대로 배워보니 생각보다 복잡하네요.

각설하고, 바로 설명 시작해봅시다.

 

 

0. 인터럽트(Interrupt)란?

결론만 이야기하면, System Call도 결국 소프트웨어 인터럽트의 일종이라, 인터럽트에 대해서 알고 갈 필요가 있을 것 같습니다.

우선 OS는 기본적으로 User 모드와 Kernel 모드로 나뉘어져 있습니다. 안전을 위해서 각 모드에서 할 수 있는 일이 다릅니다.

  • User Mode : I/O나 Protected Instruction을 포함해서 사용시 문제가 될 수 있는 주소 영역에 대해 접근 불가능
  • Kernel Mode : I/O devices를 포함해서 모든 주소 영역이 접근 가능

아무튼 안전상의 문제로 인해 User Mode에서는 제한적인 활동들만 가능합니다.

그러나 그렇다는건 User Mode에서는 프로세스 실행, 종료나 I/O작업마저 불가능하다는 것입니다.

쉽게 말해서 간단한 프로그램을 작성해도, User Mode만 가지고는 실행이 불가능하다는 것이죠.

 

그래서 항상 User Mode는 Kernel Mode에게 대신 해달라고 부탁해야합니다.

안타깝게도 Kernel Mode는 OS를 굴리느라 바쁩니다. 따라서 User Mode를 위해서 기다리는게 아니라, User Mode가 직접 Kernel Mode에게 "이거 좀 해줘"라고 부탁해야합니다.

 

대충 이런느낌?

 

그 과정을 인터럽트(Interrupt)라고 합니다.

그래서 인터럽트의 종류, 과정 등등 할 얘기는 훨씬 더 많지만 오늘은 시스템 콜에 대한 이야기를 하니 여기서 마무리하도록 하겠습니다.

아무튼 "이 인터럽트의 한 종류가 시스템 콜이다!" 라는것만 알고 있으면 될 것 같네요.

 

 

1. 시스템 콜의 정의

시스템 호출 또는 시스템 콜(system call), 간단히 시스콜(syscall)은 운영 체제의 커널이 제공하는 서비스에 대해, 응용 프로그램의 요청에 따라 커널에 접근하기 위한 인터페이스이다. 보통 C나 C++과 같은 고급 언어로 작성된 프로그램들은 직접 시스템 호출을 사용할 수 없기 때문에 고급 API를 통해 시스템 호출에 접근하게 하는 방법이다.

-Wikipedia-

 

그렇다고 하네요.

사실 인터럽트에 대한 정의를 잘 알고 있으면, 그냥 사용자 프로세스가 보내는 인터럽트라고 알고 있어도 충분합니다.

조금 더 설명하자면, 사용자 프로세스가 소프트웨어 인터럽트를 통해 커널의 기능을 이용하기 위한 서비스를 요청하는 하나의 방법입니다. 굳이 이렇게 하는 이유는 위의 Interrupt에 대해서 보면 될 것 같습니다.

 

아래에서 더 자세히 알아볼 것이지만, 간단한 처리방식을 알아봅시다.

  1. 사용자 프로세스가 시스템 콜을요청하면 제어가 커널로 넘어옴 (User Mode➡Kernel Mode)
  2. Kernel이 내부적으로 할당되어있는 고유번호를 통해 원하는 서비스의 기능번호 확인
  3. Kernel이 그 번호에 해당하는 서비스 루틴을 호출
  4. 서비스 루틴을 모두 처리한 뒤, Kernel Mode에서 다시 사용자 모드로 전환

 

2. 시스템 콜의 종류

이제 알아볼 것은 위에서 얘기했던 처리방식 중 서비스 루틴들에 해당하는 종류들을 볼 것입니다.

종류는 다음과 같습니다.

 

  • 프로세스 제어
  • 파일 조작
  • I/O장치 관리
  • 시스템 정보 및 자원 관리
  • 통신 관련

 

3. 시스템 콜의 과정 - fork()를 예시로

 

가장 대표적인 예시인 사용자 프로그램에서 fork()함수를 사용한다고 가정합시다.

다음 그림은 함수가 실행되기까지의 과정을 나타낸 것입니다. 화살표 따라가면서 밑에 설명 읽으시면 됩니다.

1. User Process가 fork() 시스템콜을 호출함

2. CNU C Library(libc.a)에서 fork의 시스템 콜의 고유번호인 '2'를 레지스터에 저장하고 0x80 인터럽트를 발생시킴

    2.1 (참고) int 0x80에서 int는 interrupt를 뜻하는 명령어이므로 128번 인터럽트를 실행시키라는 뜻임

    2.2 Interrupt가 발생했기 때문에 User Mode 에서 Kernel Mode로 전환

3. 이후 Kernel은 IDT(Interrupt Descriptor Table)에서 0x80주소에 있는 system_call을 호출

    3.1 system_call()함수에서는 호출된 시스템 콜 번호와 레지스터들을 스택에 저장한 뒤 검증한다

4. 3.1에서 스택에 옮겨놓은 값을 기반으로 sys_call_table에서 sys_fork함수 탐색 및 호출

5. 함수 종료 뒤에는 사용자 프로세스로 리턴 및 Kernel Mode에서 User Mode로 전환