OS Concepts
CPU는 Application의 System에 대한 잘못된 접근을 막기 위해 두 가지 이상의 모드로 동작하도록 구현되어 있습니다. 기본적으로 kernel mode (=0
)와 user mode (=1
)가 있습니다. 그밖에도 가상 머신에서 guest VM이 사용 가능한 VMM mode가 있습니다. Kernel mode는 OS(kernel)에 의해 실행되며 권한이 높기 때문에 하드웨어에도 직접적으로 접근할 수 있고, 유저 프로세스를 포함한 모든 프로세스의 영역에 자유롭게 접근할 수 있습니다. 예를 들어 프로세서 동작을 멈추는 HLT
instruction은 kernel mode에서만 실행할 수 있습니다.
Exception vs Interrupt
Exception은 Software interrupt라고도 하며 특정 조건을 만족할 때 발동되거나(fault, 예: user mode에서 privileged instruction 실행을 시도할 때) 발동시킬 수(trap, 예: OS에 서비스를 요청할 때) 있죠. 한편 Interrupt는 Hardware interrupt라고도 하며 외부 장치(hardware devices)로부터 발생하는 신호에 의해 비동기적으로 발생합니다.
대부분의 OS는 interrupt-driven(Exception 포함)이며 특히 user mode에서 kernel mode로의 전환이 interrupt로 이루어집니다.
User mode -> Kernel mode Transition
예를 들어, Timer가 있습니다. Process scheduling에 사용되며, user-mode에서 프로세스가 실행 중이다가, Timer가 만료되면 Timer interrupt가 발생합니다. 이때 CPU는 현재 실행 중인 프로세스의 상태를 저장하고, Timer interrupt handler를 실행합니다. Timer interrupt handler는 현재 실행 중인 프로세스를 중단하고, 다음 프로세스를 실행하기 위해 context switch를 수행할지 결정합니다.
System call을 통해 synchronous하게 수행되는 경우도 있습니다. 프로세스가 실행 중이다가 Privileged instruction이 필요해지는 순간이 오면 System call API를 호출하는 것이져.
System Calls & API
대부분의 system call은 직접적으로 호출되기보단 OS에 의해 제공되는 High-level language로 작성된 system call을 호출하는 API를 통해 이뤄집니다. 예를 들어 Windows의 Win32 API, POSIX API 등이 있죠. Rust standard library도 이에 포함됩니다(예: write()
system call을 호출하는 println!()
).
System call은 file handling, device handling, communication 등 다양한 기능을 제공합니다.
일반적으로, 각 system call은 unique한 number를 가지고 있습니다. System-call interface가 이 숫자에 따라 system call을 인덱싱하는 테이블을 관리하고 있습니다. System call interface는 user와 kernel 사이에서 OS kernel에 의도된 system call을 호출하고 리턴 상태와 리턴값을 user application에 반환하는 역할을 합니다.
System Call Parameter Passing
System call을 호출할 때, parameter를 전달해야 할 때가 있습니다. 일반적으로 세 가지 전달 빙식이 있는데, 가장 단순한 방법은 register를 사용하는 것입니다.
그러나 register의 개수가 제한되어 있기 때문에, parameter가 많은 경우에는 stack을 사용합니다. 또는 parameter를 저장하는 메모리 영역을 사용하기도 합니다(Linux, Solaris). 이때는 해당 메모리 영역의 주소가 register에 전달되죠.
참고 문헌
-
고려대학교 컴퓨터학과 오상은 교수님의 시스템 프로그래밍(COSE322) 과목 강의자료
Rust 맛보기