Ch 6 Mechanism: Limited Direct Execution (syscall, Timer int)

CPU를 가상화 하기 위해선 OS는 물리적인 CPU를 동시에 작동하는 것 처럼 보이는 모든 프로그램에 할당해줘야 한다. 번갈아 가며 실행하는 것으로 동시에 실행되는 것 처럼 보이게 할 수 있는데 이걸 우리는** Time Sharing이라고 부른다. 이를 달성하기 위해선 여러가지 고민이 따르는데 우선 performance에 대한 문제가 야기된다. 어떻게 추가적인 오버헤드를 발생시키지 않고 가상화를 가능하게 할까? 프로세스를 작동시킬때 어떻게 통제를 CPU로 부터 유지할까? 만약 이런 통제가 없다면 하나의 프로그램이 독점할 수 있다. **그래서 최종 목표는 High performance와 통제권 유지가 OS의 핵심이다.

6.1 Basic Technique: Limited Direct Execution

Limited Direct Execution 먼저 Direct Execution의 경우 CPU에서 프로그램을 작동시키는 것을 말한다. 만약 Limit이 없는 상태라면 그냥 프로그램을 실행시키고 싶을때 Process list의 자리를 만들고 그 후 일반적인 과정(4.3에서 설명)을 통해 프로그램을 실행시키면 된다. 이런 사전 과정이 끝난 후 통제권을 CPU에게 넘어가고 main()의 내용을 실행한다. 프로그램이 끝나면 다시 kernel에게 그 권한을 반납하는 형식이다. 이때 두가지 질문이 생기는데

  1. 어떻게 하면 프로그램이 원치않는 것을 하는 걸 막을 수 있을까?
  2. 어떻게 실행중인 프로세스에서 다른 것으로 넘어갈 수 있을까? (Time sharing)

추후에 설명에서 위 질문에 대한 답과 아직 설명되지 않은 “Limited”에 대한 내용을 공유할 수 있을 듯 하다.

6.2 Problem #1: Restricted Operations

Direct Execution은 빠르다는 장점이 있다. 하지만 만약 해당 프로그램이 허용받지 않은 행동을 한다면 어쩌나? 예를 들어 I/O request를 보내거나 자신에게 유리하도록 CPU나 Memory의 할당량을 바꾼다면? 이는 심각한 문제들을 야기할 수 있다. 이에 대한 답변은 User Mode: 유저모드에서 실행되는 코드는 행동에 제약이 따른다. **예를 들어 I/O를 요청할 수 없고 요청시 죽는다. 유저모드에 대한 반대 개념으로 **Kernel Mode가 존재한다. 커널 모드에서 OS가 작동된다. 커널모드는 더 높은 권한을 갖는다. 이렇게 모드를 구분하여 권한을 나누는것은 좋으나 여전히 문제가 남았다. 만약 유저모드에서 권한을 요구하는 일을 수행하고 싶다면? 이를 해결하기 위해 유저모드에서 system call을 사용할 수 있게 했다.

System call을 실행하기 위해선 프로그램은 Trap **을 발생시켜야 한다. Trap이 발생되면 커널모드로 진입하게 되면서 권한 또한 상승하게 된다. system call을 발생시킨 일이 모두 끝나게 되면 다시 유저모드로 돌아오게 된다. 이때 HW는 점프가 발생하는 동안 하고 있던 일을 기억할 수 있도록 해야하며 원하는 곳으로 돌아올 수 있도록 해야한다. x86에서는 **kernel stack **이라는 것을 통해 이를 따로 관리한다. 이 과정을 수행하는 동안 또 하나의 질문이 떠오르는데 그렇다면 OS 내부에서 어떤 코드가 실행되어야 하는지 Trap은 어떻게 아는가? 커널은 이를 위해 **trap table을 부팅시에 생성한다. 부팅시에는 커널모드로 부팅하게 되는데 이때 HW에게 trap 발생시 이것에 맞춰 어떤 코드를 실행할지 정해준다.

>>>>> gd2md-html alert: inline image link here (to images/image11.png). Store image on your image server and adjust path/filename/extension if necessary.
(Back to top)(Next alert)
>>>>>

alt_text

이때 OS는 HW에게 trap handler의 주소를 알려주게 된다. HW에게 trap table의 주소를 알려주는 것은 아주 권한이 있는 행동이다.

System call을 정확히 분류하기 위해 system-call number가 활용된다. 각 syscall 마다 배정이 되며 이를 다룰 때는 trap handler에서 번호를 확인하여 유효한지 확인한 후 맞다면 해당 코드를 실행한다. 이와 같은 과정을 거치는 이유는 보호차원 이기도 하다. 유저코드는 어떤 주소로 점프할지 결정하는 것 보다 해당 서비스를 번호를 통해 요청하기 때문이다.

Limited Direct Execution은 2가지 파트로 나눌 수 있다.

  1. 부팅시에 Trap Table을 생성하고 CPU가 추후 작업을 위해 해당 주소를 기억하는 것
  2. 커널모드에서 유저모드로 돌아가기 전에 커널은 사전작업이 필요하다.

6.3 Problem #2 Switching Between Processes

해당 문제를 다를 말로 풀어쓰면 어떻게 OS는 프로세스의 교체를 위해 CPU로 부터 통제권을 다시 가져올 수 있을까?

  1. A Cooperative Approach: Wait for system calls

    과거에는 모든 프로세스를 믿었기에 syscall이 발생하면 끝 지점 마다 yield를 넣도록 하였다. yield로 인해 syscall이 끝나면 자연스럽게 OS로 권한이 넘어오게 되었다. 또한 불법적인 일을 하면 Trap을 발생시켜 자연스럽게 OS로 권한이 넘어오게 되었다. 하지만 만약 무한루프에 빠져서 yield가 작동하지 못한다면? ReBoot

  2. Non-Cooperative Approach: The OS takes Control

    1번으로 인해 해결되지 못한 것에 대한 답은 오히려 간단히 해결법을 찾았는데 그것은 바로 **Timer Interrupt **이다. 시간제한 발생시 현재 작동중인 Process는 멈추게 되고 OS가 미리 정해놓은 interrupt handler가 작동된다. 이 경우 OS는 다시 권한을 CPU로 부터 얻게 된다. 앞서 언급한대로 부팅시에 OS는 인터럽트 발생시 할 일을 정해뒀고 추가적으로 부팅시에 Timer 또한 작동하게 된다. 추가적으로 이때 HW가 할 일도 정해져 있는데 그것은 바로 현재 프로그램의 상태를 기록하는 일이다. 이와 같은 과정은 System call의 커널 모드와 유사하다.

Saving and Restoring Context

이제 OS가 다시 통제권을 가졌으니 선택의 기로에 섰다. 프로세스를 계속해서 실행 시킬 것인가 아님 다른 프로세스로 넘어 갈 것 인가? 이 것은 OS의 다른 기관인 Scheduler에 의해 결정된다.

  1. 다음 프로세스로 넘어갈 경우

    low - level 코드의 일부인 context switch가 발생한다. 이때 OS가 할 일은 현재 작동중인 프로세스의 register 값을 커널스택에 저장하고, 교체된 프로세스의 register 값을 복원한다.

    여기서 기억해야 할 것은 2 종류의 register save/load가 발생한다는 것이다. \

  2. Timer Interrupt Occurs

The User register of the running process is saved by the HW to Kernel Stack.

  1. OS decides to switch Process

    The kernel register are saved by the SW(the OS) to memory in the process structure of the process

>>>>> gd2md-html alert: inline image link here (to images/image12.png). Store image on your image server and adjust path/filename/extension if necessary.
(Back to top)(Next alert)
>>>>>

alt_text