컴퓨터 시스템의 구조는 컴퓨터 내부 장치인 CPU, 메모리와 컴퓨터 외부 장치(입출력 장치)인 디스크, 키보드, 마우스, 모니터, 네트워크 장치 등으로 구분된다. 컴퓨터는 외부 장치에서 내부 장치로 데이터를 읽어와 (input) 각종 연산을 수행한 후, 그 결과를 외부 장치로 내보내는(output) 방식으로 업무를 처리한다.
CPU(Central Processing Unit)
저장장치에 있는 코드를 불러와서 수행하거나 외부 장치로부터 입력을 받거나 출력하는 기능을 한다. 인간의 신체 기관으로 비유하면 뇌에 해당한다.
컴퓨터 시스템을 통제하고 프로그램의 연산을 실행하고 처리하는 가장 핵심적인 컴퓨터의 제어 장치, 혹은 그 기능을 내장한 칩을 말한다. 컴퓨터 안의 중앙 처리 장치(CPU)는 외부에서 정보를 입력 받고, 기억하고, 컴퓨터 프로그램의 명령어를 해석하여 연산하고, 외부로 출력하는 역할을 한다.[wikipedia]
CPU의 역할은 매 클럭 사이클마다 메모리(Memory, 주기억장치)의 인스트럭션(Instruction, 기계어)을 읽어서 수행하는 것이다. CPU 내에는 메모리보다 속도는 빠르면서 용량은 작은 레지스터(Registers)가 있는데 이 중 PC(Program Counter)가 가리키고 있는 메모리의 주소에서 인스트럭션을 순차적으로 불러와서 수행한다.
PC(Program Counter) : 프로그램을 실행할 메모리의 다음 주소를 가리키고 있으며 보통 4 Byte.
보통 PC의 메모리 주소를 순차적으로 가지고 오지만 항상 그런 것은 아니고 함수 호출(Function call)이나 조건문(If Statement) 불일치 등 주소(번지)를 점프해야 하는 상황이 생기면 메모리 주소를 점프한다.
또한 인스트럭션을 종료할 때마다 인터럽트 라인(Interrupt line)을 체크하는데 만약 인터럽트가 들어오면 CPU를 누가 쓰고 있었던 간에 제어권이 OS(Operating System, 운영체제)에게 넘어간다.
접근 범위
CPU는 메인 메모리와 Local Buffer에 접근이 가능하다.
인터럽트(Interrupt)
인터럽트(Interrupt)는 소프웨어적 인터럽트와 하드웨어적 인터럽트로 나뉘는데 보통 하드웨어적인 것을 부를 때 사용한다. 참고로 소프트웨어적 인터럽트는 보통 트랩(Trap)이라고 호칭하며 종류로는 시스템 콜(System call)과 예외처리(Exception) 등이 있다. 시스템 콜에 대한 내용은 후술하겠다.
현대의 운영체제는 인터럽트에 의해 구동된다. 인터럽트가 들어오면 인터럽트 당한 시점의 레지스터와 Program counter를 저장한 뒤 CPU의 제어권을 인터럽트 처리 루틴(Interrupt Service Routine)에 넘긴다. 이 때 어떤 인터럽트가 들어왔는지에 따라 어떤 함수(주소)로 보내야 하는지 정의해 놓은 것을 인터럽트 벡터(Interrupt Vector)라고 한다.
하드웨어 인터럽트 vs 소프트웨어 인터럽트
CPU 인터럽트 라인에 신호를 보내서 인터럽트를 알려주는 방식은 똑같다. 다만 하드웨어 인터럽트는 컨트롤러 등 하드웨어 장치가 CPU의 인터럽트 라인을 세팅하는 반면, 소프트웨어 인터럽트는 소프트웨어가 CPU의 인터럽트 라인을 세팅한다.
인터럽트 라인 (Interrupt Line)
CPU가 자신의 작업을 하던 중간에 인터럽트 라인에 신호가 들어오면 하던 일을 멈추고 인터럽트와 관련된 일을 먼저 처리한다.
인터럽트 벡터
운영 체제는 할 일을 쉽게 찾아가기 위해 인터럽트 벡터를 가지고 있는데, 인터럽트 벡터란 인터럽트 종류마다 번호를 정해서 번호에 따라 처리해야 할 코드가 위치한 부분을 가리키고 있는 자료 구조를 말한다.
인터럽트 처리 루틴 (인터럽트 핸들러)
인터럽트 벡터에서 실제 처리해야 할 코드를 인터럽트 처리 루틴 혹은 인터럽트 핸들러라고 부른다.
인터럽트 처리 루틴을 통해 해당하는 인터럽트 처리를 완료하고 나면 원래 수행하던 작업으로 돌아갈 위치를 알아야 하므로 인터럽트 처리 전에 수행 중이던 작업이 무엇이었는지 반드시 저장해야 하는데, 이러한 정보를 저장히기 위해 운영 체제는 PCB라는 공간을 별도로 가지고 있다.
모드 비트(Mode bit)
CPU 제어권을 운영체제가 갖고 있는지, 사용자 프로그램이 갖고 있는지 구분한다.
악의적인 사용자 프로그램이나 코드, 또는 사용자 프로그램의 잘못된 수행으로 다른 프로그램이나 운영체제에 피해갈 수 있기 때문에 이를 방지하기 위해 존재한다.
모드 비트 ‘1’은 사용자 모드를 의미한다. 한정된 인스트력션만 수행 가능하고 주소 이동도 자신의 메모리 주소 영역에서만 이동이 가능하다. 사용자 프로그램에게 CPU를 넘기기 전에는 항상 모드 비트를 ‘1’로 세팅한다.
모드 비트(Mode bit) ‘0’은 커널 모드(Kernel mode)를 의미한다. 실행 가능한 모든 기계어를 수행 가능하며 입・출력도 이때만 가능하다. 사용자 프로그램 실행 중 인터럽트가 들어오거나 예외가 발생하면 모드 비트가 ‘0’으로 바뀐다.
메모리(Memory)
CPU의 작업공간을 말한다. OS(Kernel)가 상주하고 있으며 프로그램이 실행되면 프로세스가 이곳에 적재(Load)되어 필요하지 않을 때 까지 상주한다.
디바이스 컨트롤러(Device controller)
각 입・출력 디바이스(Input/Output Device) 장치를 제어 및 관리하는 일종의 작은 CPU이다. (디바이스 드라이버 와는 다르다.)
Device Driver : 운영체제 코드 중 장치별 처리루틴. 디바이스가 어떤 일을 할 수 있는지 알려주는 코드이다.
즉, CPU가 실행하는 각 디바이스에 접근하기 위한 소프트웨어를 뜻한다.
외부 장치(I/O Device)의 입・출력 속도는 CPU의 처리 속도에 비해 매우 느리기 때문에 CPU와 동기적으로(Synchronous) 동작하면 입력 또는 출력이 완료되기 까지 CPU가 디바이스를 기다려야 하므로 CPU의 효율이 많이 떨어질 수 있다. 디바이스 컨트롤러는 이를 극복하기 위해 존재한다.
디바이스 컨트롤러에는 제어 정보를 담기 위한 레지스터(Registers)와 입・출력 데이터를 담기 위한 로컬 버퍼(Local buffer)가 있다. 각 디바이스의 입・출력이 종료되면 디바이스 컨트롤러는 CPU에게 인터럽트로 그 사실을 알린다. 인터럽트가 들어오기 전까지 CPU는 다른 인스트럭션을 처리하면 되기 때문에 컴퓨팅 자원 이용의 효율성이 좋아진다.
Local Buffer
메인 CPU의 작업 공간인 메인 메모리가 있듯이 디바이스 컨트롤러도 데이터를 임시로 저장하기 위한 작업 공간이 필요한데, 이를 Local Buffer가 그 역할을 한다.
그런데 만약 키보드 입력 한 글자(Byte 단위) 마다 인터럽트가 보낸다면 어떻게 될까? 처리속도가 높은 CPU는 잦은 방해(인터럽트)를 받을 것이고 시간 대비 수행 효율이 떨어질 것이다.
이를 방지하기 위하여 DMA 컨트롤러(Direct Memory Access Controller)를 둔다. DMA 컨트롤러가 있으면 매 입력 또는 출력마다 인터럽트를 넣지 않고 입・출력 데이터를 DMA 컨트롤러가 직접 메모리에 저장한다. 그리고 일정량의 정보(Block 단위)가 채워지면 인터럽트를 발생시킨다. 이는 CPU 자원의 오버헤드를 낮춘다.
입・출력(I/O, Input/Output)의 수행
모든 입출력 명령은 운영 체제만 사용할 수 있는 특권 명령으로만 가능하다. 그렇다면 사용자 프로그램은 어떻게 I/O를 할 수 있을까? 바로, 시스템 콜을 활용한다.
시스템 콜은 운영 체제에게 I/O를 요청하는 것을 말한다. 운영 체제의 서비스를 받기 위해 커널 함수를 호출하는 것이라고 생각하면 된다.
동작
mode bit가 1인 상태로 사용자 프로그램이 실행되고 있다가 I/O를 해야 하는 상황이 오면 바로 OS의 주소로 점프를 할 수가 없다. 그래서 프로그램이 직접 인터럽트 라인을 세팅 한 후, CPU에게 인터럽트를 보내면, CPU는 다음 인스트럭션을 수행하는 대신 mode bit를 0으로 바꾸고 CPU 제어권을 OS로 넘기게 된다. 이러한 방식으로 사용자 프로그램이 OS에게 I/O 요청을 보낼 수 있다.
시스템 콜(System call)
사용자 프로그램은 악의적인 프로그램이나 코드가 있을 수 있다. 따라서 보안상 직접 디바이스에 접근할 수 없도록 되어 있으며 입・출력이 필요하면 운영체제에게 요청하여 도움을 받아야 한다.
시스템 콜(System call)은 사용자 프로그램이 입・출력이 필요할 때 운영체제의 함수를 호출하는 것을 의미한다. 어렵게 생각할 필요없이 말 그대로 시스템을 콜하는 것이다.
사용자 프로그램이 입・출력이 필요하면 자발적으로 소프트웨어적인 인터럽트를 발생시켜 OS에게 CPU 제어권을 넘기는데 이를 트랩(Trap)이라고 한다. 운영체제는 트랩이 들어오면 해당 요청이 올바른 요청인지 확인한 뒤 입・출력을 수행하고 입・출력 완료 시 제어권을 시스템 콜의 다음 명령으로 옮긴다.
타이머(Timer)
무한 루프가 동작하면 CPU 제어권이 무한 루프를 실행시킨 프로그램에게 고정된다. 이와 같이 특정 프로그램이 CPU를 독점하는 것을 막기위해 부착된 하드웨어이다.
특정 프로그램에 CPU를 넘길 때 타이머를 세팅(예: 100 ms)하고 넘기고 세팅 시간을 초과하게 되면 CPU에 인터럽트를 걸어서 사용자 프로그램으로부터 OS로 제어권을 뺏어온다. 이러한 특징을 이용하면 운영체제가 컴퓨터 시스템의 자원을 효율적으로 분배할 수 있다. 운영체제의 타임 쉐어링(Time sharing)을 구현할 때 이용한다.
부가적인 기능으로 현재 시간을 계산할 때 사용되기도 한다.
DMA (Direct Memory Access) Controller
원칙적으로 메모리는 CPU에 의해서만 접근할 수 있는 장치이다. CPU 외의 장치가 메모리의 데이터에 접근하기 위해서는 CPU에게 인터럽트 발생시켜 CPU가 대신 컨트롤러의 로컬 버퍼와 메모리 사이에서 데이터를 옮겨 준다. 하지만, 작업 처리 속도가 매우 빠른 CPU가 인터럽트를 많이 당하면 비효율적이다. 그래서 CPU 이외에 메모리 접근이 가능한 DMA 컨트롤러를 둔다.
DMA를 사용하게 되면 로컬 버퍼에서 메모리로 읽어오는 작업을 CPU 대신 수행해 줄 수 있다. 이때, DMA는 바이트 단위가 아니라 블록이라는 큰 단위로 정보를 메모리로 읽어온 후에 인터럽트를 발생시켜서 작업 완료 신호를 CPU에게 보낸다. 이러한 방식으로 CPU에 발생하는 인터럽트의 빈도를 줄여 CPU를 효울적으로 이용할 수 있다.
다만, CPU와 DMA가 동시에 메인 메모리에 접근할 수 있다는 문제점이 있어서 누가 메모리에 먼저 접근하게 만들지 Memory Controller가 교통 정리하는 역할을 한다.
참고