[운영체제] 인터럽트/시스템 콜

VSFe·2022년 2월 11일
0

CS

목록 보기
3/5
post-custom-banner

프로세스는 항상 돌아가진 않는다. (싱글 코어 CPU에선) 한 번에 하나의 프로세스만 동작하는데, 이 과정에서 I/O가 발생하거나, 프로그램에 문제가 생기면 프로세스는 잠시 동작을 멈춰야 하는데, 이것을 누가 처리 해야 할까?

또한, 위에서 언급한 I/O는 실제로는 일반 프로그램이 하는 것이 아니라, 운영체제 측에서 담당해야 하는 것이다. 그런데 왜 우리는 지금까지 그런 것을 모르고 프로그래밍을 했던 것 일까?

이 질문들에 대답을 하기 위해선, 우리는 인터럽트시스템 콜에 대해 알아야 한다.

운영체제의 동작 과정 - Dual Mode

현대 운영체제의 대부분은 Dual Mode로 작동한다. 이는 운영체제가 서로 다른 두 개의 모드로 돌아가는 것을 의미한다.

  • 사용자 모드 (User Mode) : 일반적인 응용프로그램이 구동되는 환경이다.
  • 커널 모드 (Kernel Mode) : 커널이 구동되는 환경이며, 이 모드에서는 OS 시스템에 영향을 주는 명령어를 실행할 수 있다.

처음 운영체제가 구동되면 초기화 작업 및 부팅 과정에서 필요한 과정들을 수행하기 위해 커널 모드로 시작되지만, 곧 사용자 모드로 전환된다.

프로그램을 사용하면서 인터럽트 (Interrupt, H/W가 요청)나 트랩 (Trap, S/W가 요청하거나 오류로 인해 발생)이 발생되면 모드 비트를 0으로 전환하고, 운영체제의 모드 또한 커널 모드로 변경된다.

그렇다면, 왜 이렇게 두 모드를 분리하는 것일까? 만약 사용자 모드와 커널 모드의 구분이 없다면, 응용 프로그램이 시스템에 접근할 수 있는 길이 열리기 때문이다!

운영체제의 경우, 시스템에 영향을 끼칠 수 있는 몇몇 명령어를 특권 명령 (Privileged Instruction) 으로 지정함으로써 운영체제 자신을 보호한다. 만약 응용 소프트웨어가 해당 명령을 시행하려고 접근하게 된다면, OS 측에서 잘못된 접근으로 인식하여 트랩을 걸어 프로그램을 중단 시켜버릴 수 있다.

인터럽트

위에서 인터럽트라는 것이 있다. 정도만 이야기 했는데, 그래서 인터럽트가 뭘까?

CPU가 프로그램을 실행하고 있을 때, 입출력 하드웨어 등의 장치나 예외상황이 발생하여 처리가 필요할 경우에 잠시 프로그램을 중단하고 발생한 일을 처리한 후, 다시 실행중인 작업으로 돌아오는 것을 말한다.

마치, 라면을 끓이면서 컴퓨터를 하고 있는데 물이 넘칠 것 같아 하던 일을 중단하고 불을 끄러 뛰어 나가는 것과 비슷하다.

인터럽트의 종류

인터럽트는 다양한 요인에 의해 발생할 수 있는데, 이를 크게 외부 인터럽트내부 인터럽트라고 볼 수 있다.

사실... 내부 인터럽트를 다른 말로 트랩이라고 부른다. 즉, 엄밀히 말하면 내부 인터럽트는 인터럽트라고 볼 수 없다. 하지만, 이해의 용이함을 위해 여기서는 묶어서 보도록 하자.

외부 인터럽트

  • 전원 이상 인터럽트(Power fail interrupt) : 정전이 발생하거나, 파워에 이상이 발생했을 때 동작한다.
  • 기계 착오 인터럽트(Machine check interrupt) : CPU에 문제가 발생할 때 동작한다.
  • 외부 신호 인터럽트(External interrupt)
    • 타이머에 의한 인터럽트 : 여러 프로세스가 하나의 CPU를 공유하기 때문에, 다양한 방법으로 CPU는 어떤 프로세스를 다룰지 선택할 수 있다. (우리는 이것을 CPU 스케쥴링이라고 부르는데, 다음에 더 자세히 작성 할 예정이다.) 여기서, Time Sharing 방식의 Preemptive 스케쥴링을 선택할 수 있는데, 여기서 자원이 할당된 시간이 다 끝난 경우 해당 프로세스를 중단해야 한다. (Context Switching)
    • 키보드로 인터럽트 키를 누른 경우 : ex. Control + Alt + Delete
    • 외부장치로부터 인터럽트 요청이 있는 경우
  • 입출력 인터럽트(I/O Interrupt)
    • 입출력장치가 데이터 전송을 요구하거나 전송이 끝나 다음 동작이 수행되어야 할 경우
    • 입출력 데이터에 이상이 있는 경우

내부 인터럽트 (트랩)

잘못된 명령이나 잘못된 데이터를 사용할때 발생한다. 다른 말로 프로그램 검사 인터럽트 (Program check interrupt) 라고 부르는데, 크게 다음과 같은 것들이 있다.

  • Division by zero
  • Overflow/Underflow
  • 기타 프로그램 Exception

인터럽트의 동작 과정

  • 프로그램 실행 중단 : 현재 실행중이던 명령어까지 수행한다.
  • 현재의 프로그램 상태 보존 : PC (Program Counter)의 값을 스택에 저장한다. (인터럽트 종료 후 복귀를 위해)
  • 인터럽트 처리루틴 실행 : 인터럽트를 요청한 장치를 식별한다.
  • 인터럽트 서비스 루틴 (ISR) 실행 : 인터럽트 원인을 파악하고 실질적인 작업을 수행한다. 처리기 레지스터 상태를 보존한다. 서비스 루틴 수행 중 우선 순위가 더 높은 인터럽트가 발생하면 또 재귀적으로 1~5를 수행한다.
  • 상태복구 : 인터럽트 발생 시 저장해둔 PC(Program counter)를 다시 복구한다.
  • 중단된 프로그램 실행 재개 : PC의 값을 이용하여 이전에 수행중이던 프로그램을 재개한다.

ISR을 처리하기 전, 현재 수행하던 작업을 스택에 저장하는 과정을 거치는 것을 볼 수 있는데, 우리는 다른 말로 Context를 저장한다고 한다. (여기서 Context는 프로세스의 상태와 관련된 레지스터의 집합을 의미한다.)

시스템 콜

앞에서 말했듯이, 응용 소프트웨어는 커널 모드에 접근할 수 없다. 그렇다면 정말 아무것도 할 수 없는 것일까? 그건 아니다. 프로세스가 시스템의 자원이나, 서비스를 필요로 할 경우 운영체제에게 요청 할 수 있다. 우리는 이 것을 시스템 콜이라고 부른다.

정확히 말하면 시스템 콜 또한 인터럽트의 일종이다.

그렇다면 다음과 같은 의문이 들 수도 있지 않을까?

자원도 요청하고, 서비스도 요청하고... 그러면 요청할 수 있는 종류가 많지 않나요? 이걸 어떻게 구분할 수 있나요?

시스템 콜의 동작 과정을 잠시 살펴보자.

  • 응용 프로그램에서 시스템 콜을 호출하면, (일반적으로는 API 형태로 Wrapped 되어 있기 때문에 우리는 의식하지 않고 사용함.) 0x80 인터럽트가 발생한다.
  • IDT (Interrupt Descripter Table; 인터럽트의 종류를 판단하기 위해 사용함.)에서 0x80은 system_call() 이기 때문에, 커널이 시스템 콜과 관련된 동작을 수행함.

하지만 그림에서도 보면 알 수 있지만, 시스템 콜의 종류는 정말 다양하기 때문에, 우리가 어떤 시스템 콜을 수행해야 하지? 라는 질문에 답하기 위해선 추가적인 매개변수가 필요할 것이다.

그렇다면 매개변수를 어떤 식으로 전달해야 할까?

  • 매개변수를 레지스터에 담는다.
    • 하지만, 매개변수가 레지스터의 수 보다 많은 경우가 존재하므로 적합하지 않은 방법이다.
  • 매개변수를 연속적 (블록) 또는 불연속적 (테이블 사용)으로 메모리에 담은 뒤, 주소를 레지스터에 담는다.
    • 크기에 제한이 없으므로 많이 사용된다.
  • 스택에 매개변수를 담는다.
    • 이 경우, 스택에 담긴 모든 데이터를 레지스터에 옮기고 스택에 원소를 담아야 하기 때문에, 결과적으로 첫 번째 방법과 큰 차이가 없다!
profile
아직 많이 공부 중...
post-custom-banner

0개의 댓글