컴퓨터 시스템의 일반적인 구조
좌측은 CPU와 메모리로 이루어져 있는 우리가 일반적으로 이야기하는 컴퓨터이고, 우측은 I/O device. 호스트 컴퓨터에 붙어서 데이터를 컴퓨터 안에 집어넣는 Input이나 결과를 내보이는 Output을 하는 Device이다.
각각의 Device에는 디바이스를 전담하기 위한 Device Controller들이 있고, 이 Device Controller는 I/O Device를 통해서 데이터를 주고받기 위해 Local buffer에다가 저장하며 CPU한테 뭔가를 알려주고 싶을 때에는 Device Controller가 인터럽트를 걸어 알려준다.
- Local Buffer : i/O Device 작업 데이터를 저장
- Device Controller : 각 디바이스마다 전담하기 위한 작은 하드웨어 장치 (CPU한테 인터럽트 걸 수 있음)
- Device Driver : 각 디바이스를 처리하기 위한 Software
![](https://blog.kakaocdn.net/dn/cDmNoK/btrTQBevE6W/8oWgVs70IPM6W82wUKDGFk/img.jpg)
CPU는 매 순간 메모리 어딘가에 올라와있는 기계어(instruction)를 처리한다. 그렇다면 메모리 어디에 있는 기계어를 읽어올까?
CPU Register 중에서메모리를 가리키고 있는 Program Counter Register가 존재한다. Program Counter가 가리키고 있는 메모리 위치에서 Instruction을 하나 읽어와서 실행하고 나면 pc레지스터는 다음 주소를 가리키고 읽어와서 실행하고 다음 주소를 가리킨다.
CPU는 특별한 일이 없으면 항상 메모리의 다음에 있는 Instruction을 순차적으로 실행하는데, Instruction을 실행하기 전에 CPU는 Interrupt가 들어온 게 있는지 체크를 한다. 인터럽트가 들어왔을 경우, 지금 하고 있는작업을 잠시 멈추고 CPU 제어권을 OS 커널에게 넘겨준다. (함수 호출이나 if문 조건을 만족하지 않을 경우에는 다른 메모리 주소로 점프해서 Instruction 실행)
운영체제에는 인터럽트마다 인터럽트의 상황에 맞게 처리해야 하는 일들이 커널 함수로 정의가 되어있다. 인터럽트 벡터에는 각 인터럽트 종류별로 몇 번 라인의 인터럽트가 들어왔는지를 나타내는 엔트리가 하나 있고 그 인터럽트가 들어왔을 때, 운영체제 메모리 주소 어디에 접근해야 하는지에 대한 정보가 있다. 그러니까, 한마디로 인터럽트 벡터는 인터럽트 번호와 주소를 쌍으로 갖고 있다.
예를 들어, 하드 디스크 컨트롤러가 인터럽트를 걸었을 때, 그 인터럽트 번호가 3번이면 해당 인터럽트 벡터에 가면 3번에 해당하는 주소(함수의 위치)가 있다. 해당하는 함수에 가면 하드 디스크 컨트롤러가 발생시킨 인터럽트에 대해 CPU가 실행해야 될 커널 함수가 정의되어 있다. 이 과정을 인터럽트 처리 루틴(ISR)이라고 부른다.
- 인터럽트 벡터 : 해당 인터럽트의 처리 루틴 주소를 가지고 있음
- 인터럽트 처리 루틴 (인터럽트 핸들러) : 해당 인터럽트를 처리하는 커널 함수
● Mode Bit
CPU안에 mode bit라는 게 있다. CPU제어권이 운영체제에 있으면 mode bit이 0이며, 사용자 프로그램에 있을 경우 mode bit은 1이 된다. 즉, mode bit가 0이면 CPU는 모든 Instruction을 사용할 수 있으며 mode bit이 1이면 사용자 프로그램의 Instruction만 사용할 수 있다. 모든 Instruction을 사용할 수 있다는 뜻은 다른 사용자 프로그램의 메모리 영역을 볼 수도 있고 I/O 디바이스에 접근도 할 수 있다는 것이다.
사용자 프로그램 실행 시, mode bit을 이용하여 메모리 접근을 제한적으로 두는 이유는 해당 사용자 프로그램을 100% 믿을 수 없기 때문이다. A라는 사용자 프로그램이 B라는 프로그램의 메모리 주소를 본다거나 운영체제 커널의 메모리 주소에 가서 이상한 걸 써놓아서 시스템을 망가뜨릴 수 있다. 그래서 자기 자신의 메모리 주소 영역만 볼 수 있게 되어 있다.
I/O Device는 사용자 프로그램은 접근하지 못하고 운영체제만 접근을 할 수 있다.(Mode bit 0) 그래서 사용자 프로그램이 I/O 작업을 하고 싶을 때에는 System Call로 운영체제에 요청을 해야 한다. (운영체제의 커널 함수를 호출하는 것으로 일반 함수 호출과는 다르다.) System Call을 하면 인터럽트 라인을 세팅한 후, CPU는 인터럽트 라인이 생성되었으니 하던 일을 멈추고 CPU 제어권을 운영체제에게 넘겨준다.
● Interrupt (인터럽트)
· 인터럽트 : 인터럽트 당한 시점의 레지스터와 Program Counter를 저장한 후 CPU 제어를 인터럽트 처리 루틴에 넘긴다.
인터럽트는 하드웨어 인터럽트와 소프트웨어 인터럽트로 분류가 되는데, 일반적으로 부르는 인터럽트는 하드웨어 인터럽트이다.
- 하드웨어 인터럽트 : Device Controller같은 하드웨어가 발생시키는 인터럽트
- 소프트웨어 인터럽트 (Trap) : 프로그램이 직접 필요에 따라 인터럽트 라인을 생성해서 OS를 부르는 인터럽트
소프트웨어 인터럽트(Trap)에는 Exception과 system call 두 가지 종류가 있다.
- Exception : 프로그램이 오류를 범한 경우 (0으로 나누는 연산 또는 운영체제 메모리에 접근하려 할 때)
- system call : 프로그램이 커널 함수를 호출하는 경우
I/O Controller가 인터럽트를 걸 수도 있지만 Timer가 인터럽트를 걸 수도 있다. 운영체제가 CPU를 갖고 있다가 사용자 프로그램으로 넘겨줄 때 mode bit을 1로 바꾸고 넘겨주기 때문에 보안에 관련된 것들은 잘 막아놨는데, 사용자 프로그램이 CPU를 계속 잡고 있고 운영체제로 넘겨주지 않을 경우 제어권을 다시 뺏어올 방법이 없다. 이런 일이 발생하는 것을 막기 위해 Timer라는 하드웨어를 두는 것이다. 운영체제가 사용자 프로그램에게 CPU 제어권을 넘겨줄 때, Timer에 정해진 시간(수십ms) 세팅을 한 후 CPU 제어권을 넘겨주는 것이다. 할당된 시간이 끝나면 Timer는 CPU에 인터럽트를 걸어주고 CPU 제어권을 다시 운영체제로 넘긴다.