컴퓨터 시스템의 동작 원리
컴퓨터 시스템의 동작 원리
컴퓨터 내부 장치 : CPU, 메모리
컴퓨터 외부 장치 : 키보드, 모니터, 마우스 등등
컴퓨터 내의 각 하드웨어 장치에는 컨트롤러가 존재한다. 컨트롤러는 일종의 작은 CPU로서, 컴퓨터 전체에 CPU라는 중앙 처리 장치가 있듯이 컨트롤러는 각 하드웨어 장치마다 존재하면서 이들을 제어하는 작은 CPU라 할 수 있다.
CPU와 I/O 연산
입출력 장치들의 I/O 연산은 I/O 컨트롤러가 담당하고, 컴퓨터 내에서 수행되는 연산은 Main CPU가 담당한다. 이때 입출력 장치와 CPU는 동시 수행이 가능하다. 또한, 각 장치에는 이를 제어하기 위해 설치된 장치 컨트롤러에는 장치로부터 들어오고 나가는 데이터를 임시로 저장하기 위한 작은 메모리인 로컬 버퍼(Local buffer)를 가지고 있다.
과정
- 프로세스에서 외부 입출력에 대한 요청 발생.
- 컨트롤러에 의해서 외부 장치로의 입출력을 제어.
- 외부 장치와 입출력 발생.
- 로컬 버퍼에 데이터를 임시로 저장.
- 컨트롤러에 의해 인터럽트 발생.
- CPU는 컨트롤러로부터 발생한 인터럽트에 대해 인터럽트 라인을 통해 확인
- 로컬 버퍼의 데이터는 메모리에 상주한 프로세스의 영역에 이동 후 저장
- 인터럽트 : 컨트롤러들이 CPU의 서비스가 필요할 때, 이를 통보하는 방법
- 인터럽트는 키보드 입력 혹은 디스크에서 데이터를 다 읽어왔다는 등의 이벤트를 CPU에게 알려줄 필요가 있을 경우, 컨트롤러가 발생시키는 것.
인터럽트의 일반적 기능
- 인터럽트 처리 루틴 : 운영 체제 커널 내에 존재하는 인터럽트 처리 루틴은 다양한 인터럽트에 대해 각각 처리해야 할 업무들을 정의하고 있다.
- 인터럽트 : 하드웨어 인터럽트, 소프트웨어 인터럽트
- CPU의 서비스가 필요한 경우, CPU 옆에 있는 인터럽트 라인에 신호를 보내어 인터럽트가 발생했음을 알리는 것은 동일하다.
- 하드웨어 인터럽트 : 컨트롤러 등 하드웨어 장치가 CPU의 인터럽트 라인을 세팅
- 소프트웨어 인터럽트 : 소프트웨어가 그 일을 수행.
- 인터럽트 처리 루틴은 인터럽트 벡터(interrupt vector)와 인터럽트 서비스 루틴(interrupt service routine)을 담고 있다.
- 인터럽트 벡터 : 인터럽트 종류마다 번호를 부여해서 번호에 따라 처리해야 할 코드가 위치한 부분을 포인터로 가리키고 있는 자료구조.
- 인터럽트 서비스 루틴 : 인터럽트 벡터를 통해 확인한 실제로 작동해야 하는 코드 내용
위의 6번 컨트롤러에 의한 인터럽트 발생시 CPU는 인터럽트 라인의 확인을 통해 인터럽트를 확인하고 OS 영역내의 커널에 있는 인터럽트 처리 루틴을 통해 그에 알맞는 대응을 한다.
인터럽트 핸들링
인터럽트가 발생한 경우에 처리해야 할 일의 절차를 의미한다.
프로그램 A 수행 -> 인터럽트 발생 -> A의 현재 상태 저장 -> 인터럽트 처리
- 현재 상태란 현재 CPU가 수행 중이던 메모리 주소를 포함해 몇 가지 부가적인 정보들을 의미한다.
운영체제 커널 영역에는 현재 시스템 내에서 수행되는 프로그램들을 관리하기 위한 자료 구조인 프로세스 제어 블록(PCB : Process Control Block)을 두고 있다. 인터럽트가 발생했을 때, 프로그램의 어느 부분이 수행되던 중이었는지를 저장하기 위한 자료구조로 사용된다. 저장되는내용으로는 현재 수행중이던 메모리 주소, 레지스터 값, 하드웨어 상태 등이 있다. 인터럽트 수행이 끝나면 저장된 값을 다시 CPU 상에 복원해 진행 중이던 명령을 계속 수행할 수 있다.
프로그램 내부의 함수 호출시 그 복원 지점에 대한 정보는 각 프로그램의 주소 공간 중 스택 부분에 저장된다.
프로그램 A가 수행중에 인터럽트가 발생하면 현재까지 수행된 지점을 프로세스 제어 블록(PCB)에 저장하고, 인터럽트 처리 루틴으로 와서 커널 코드를 수행하게 되며, 이때 이루어지는 함수 호출은 프로세스 A의 커널 스택을 사용하게 된다. 인터럽트 처리가 끝마쳐진 후에는 PCB에 저장된 주소로 되돌아가서 중지된 작업의 나머지 부분을 수행하게 된다.
인터럽트 처리 중에는 다른 인터럽트의 발생을 허용하지 않는다. 이유는 인터럽트 처리 중에 다른 입터러트를 처리하게 되면 데이터의 일관성이 유지되지 않는 경우가 발생하기 때문이다. 인터럽트를 처리하는 중 운영 체제 커널에 정의된 데이터를 변경하고 있는데 다른 인터럽트가 발생해 앞선 인터럽트에서 변경중이던 데이터를 또다시 변경하게 되면 두 인터럽트에 의해 데이터가 원래 의도하지 않았던 결과 값으로 변경될 수 있기 때문이다.
Ex)
A라는 프로그램이 수행되다가 인터럽트가 발생하면 인터럽트 처리 루틴 내에서의 함수 호출 및 리턴 정보는 A의 커널 스택에 저장하게 된다. 요청된 인터럽트에 대한 처리를 수행하던 중에 또 다른 인터럽트가 발생하면, 이 인터럽트 처리 중 발생하는 함수 호출 및 리턴과 관련된 정보를 A의 커널 스택에 또 다시 저장하게 된다. 스택에서 함수를 호출한 후 호출된 함수가 또 다른 함수를 호출할 때와 마찬가지로 중요도가 높은 인터럽트를 먼저 처리하고 난후 CPU를 점령당한 이전의 인터럽트로 돌아가서 하던 작업을 처리하게 된다.
[소프트웨어 인터럽트]
통상적으로 인터럽트는 하드웨어 인터럽트를 의미하며, 소프트웨어 인터럽트는 트랩(trap)이라는 용어로 주로 불린다.
- Ex) 예외 상황(exception), 시스템 콜(System Call)
- 예외 상황이란 프로세스가 0으로 나누는 연산 등 불가능한 작업을 시도하거나 자신의 메모리 영역 바깥을 접근하려는 시도를 할 때 이에 대한 처리를 위해 발생시키는 인터럽트.
- 시스템 콜이란 프로그램이 자신이 작성하지 않은 코드를 운영 체제로부터 서비스 받기 위해 발생시키는 것.
일반적인 함수 호출 vs 시스템 콜
- 일반적인 함수 호출 : 자신이 작성한 함수 또는 라이브러리에 정의된 함수를 호출하는 것.
- 시스템 콜 : 운영체제에 정의된 함수를 호출하는 것. 이는 일종의 인터럽트 매커니즘으로 동작한다.
- printf() 함수를 호출하면 라이브러리 함수인 printf()는 일종의 인터럽트 매커니즘인 write() 시스템 콜을 통해 커널에 입출력 명령을 대신 수행하도록 요청한다. 그러면 운영체제는 해당하는 인터럽트를 처리하기 위한 루틴을 찾고 화면에 출력하라는 요청에 따라 정보를 화면에 출력한다.
입출력 구조
입출력(I/O)란 컴퓨터 시스템이 컴퓨터 외부의 주변 장치들과 데이터를 주고 받는 것을 의미한다.
- 동기식 입출력(synchronous I/O) : 입출력 요청 후 입출력 작업이 완료된 후에야 CPU의 제어권이 그 프로그램에게 다시 넘어갈 수 있는 방식.
- 동기식 입출력에서는 입출력 연산이 끝날 때까지 CPU는 아무 일을 수행할 수 없다.
동기식 입출력에서는 입출력 연산을 수행하는 동안 CPU가 아무 일도 하지 못하기 때문에 자원의 낭비가 초래된다. 따라서 일반적으로 프로그램이 입출력을 수행중인 경우 CPU를 다른 프로그램에게 이양해 CPU가 계속 쉬지 않고 일할 수 있도록 관리한다.
Ex) 프로그램 A가 CPU를 할당받고 명령을 수행하는 도중 입출력 요청을 하게 되면 입출력 작업이 완료될 때까지 CPU를 프로그램 A에게서 선점해 다른 프로그램 B에게 할당한다. 프로그램 B는 CPU를 할당받아 명령을 수행하고 프로그램 A의 입출력이 완료될 때까지 A에게는 CPU를 다시 할당하지 않는다.
이는 입출력이 완료될 때까지는 그 프로그램이 CPU를 할당하더라도 명령을 수행하지 못하기 때문이다. 이것을 프로그램을 봉쇄 상태(blocked state)로 전환시킨다고 말한다.
봉쇄 상태의 프로그램에게는 CPU를 할당하지 않고 CPU를 할당하면 곧바로 작업을 수행할 수 있는 프로그램들에게만 CPU를 할당한다.
동기식 입출력이 발생한 경우에 다수의 프로세스가 하나의 자원을 이용하는 경우, 데이터 동기화에 문제가 발생할 수 있다. 이러한 문제를 방지하기 위해 장치별로 큐(Queue)를 두어 요청한 순서대로 처리할 수 있도록 한다.
- 비동기식 입출력(Aynchronous I/O) : 입출력 연산을 요청한 후에 연산이 끝나기를 기다리는 것이 아니라 CPU의 제어권을 입출력 연산을 호출한 그 프로그램에게 곧바로 다시 부여하는 방식.
DMA(Direct Memory Access)
원칙적으로 메모리는 CPU에 의해서만 접근이 가능한 장치이다. 주변 장치들이 메모리에 접근하기 위해서는 CPU에 인터럽트를 발생시켜 CPU가 일을 대행하는 방식으로 진행된다. 인터럽트 발생시 컨트롤러의 로컬 버퍼에 저장되어 있던 데이터는 CPU에 의해 메모리로 옮겨지게 되는데, 이를 CPU에서 전부 담당하게 되면 CPU의 효율이 떨어진다. 이러한 비효율성을 극복하기 위해 CPU 이외에 메모리 접근이 가능한 장치를 하나 더 두게 되는데 이를 DMA(Direct Memory Access)라고 한다.
DMA는 일종의 컨트롤러로서 CPU가 주변 장치들의 메모리 접근 요청에 의해 자주 인터럽트 당하는 것을 막아준다.
또한, DMA는 블록이라는 큰 단위로 정보를 메모리로 읽어온 후에 CPU에게 인터럽트를 발생시켜 해당 작업의 완료를 알려준다. 이러한 방식으로 CPU에 발생하는 인터럽트의 빈도를 줄여 CPU를 좀더 유용하게 사용하고 입출력 연산을 더욱 빠르게 수행할 수 있다.
저장 장치의 구조
주기억 장치
- 전원이 나가면 저장되었던 내용이 모두 사라져 버리는 휘발성의 RAM을 매체로 사용하는 경우가 대부분이다.
보조기억 장치
- 전원이 나가다 저장된 내용을 기억할 수 있는 비휘발성의 마그네틱 디스크를 흔히 사용한다.
- Ex) 플래시 메모리, CD, 마그네틱 테이프 등
- 용도
- 파일 시스템용 : 전원이 나가도 유지해야 할 정보가 있으면 그것을 파일 형태로 보조 기억 장치에 저장하게 된다.
- 메모리의 연장 공간인 스왑 영역 : 운영체제는 프로그램 수행에 당장 필요한 부분만 메모리에 올려놓고 그렇지 않은 부분은 디스크의 스왑 영역에 내려놓게 된다. (하드디스크가 가장 널리 사용된다.)
이유는 메모리의 크기는 한정적이고 비싼 데다가 용량이 작기 때문이다. 그러므로 다수의 프로그램이 메모리에 올라가 동시에 수행되는 환경에서는 메모리 공간이 부족하다. 그래서 스왑 영역을 사용하는 것이다.
디스크에 내려놓는 일을 스왑 아웃시킨다고 하며, 스왑 아웃된 부분이 필요할 때는 다시 메모리 영역으로 올리게 된다.
캐슁 기법
- 적은 용량의 캐쉬 메모리를 사용해 메인 메모리와 같이 큰 용량을 가진 것처럼 효율적으로 동작할 수 있도록 관리하는 기법이다.
- 즉, 상대적으로 용량이 적은 빠른 저장 장치의 성능 향상을 위한 총체적 기법.
- 상대적으로 느린 저장 장치에 있는 내용 중 당장 사용되거나 빈번히 사용될 정보를 빠른 저장 장치에 선별적으로 저장해 두 저장 장치 사이의 속도를 완충시키는 기법으로 사용된다.
하드웨어의 보안
다중 프로그래밍 환경에서 각각의 프로그램들이 다른 프로그램의 실행을 방해하거나 프로그램 간에 서로 충돌을 일으키는 문제를 막기 위해 하드웨어에 대한 각종 보안 기법이 필요하다. 하드웨어적인 보안을 유지하기 위해 두 가지 모드의 오퍼레이션을 지원한다.
- 커널 모드(kernel mode, system mode)
- 운영 체제가 CPU의 제어권을 가지고 운영 체제 코드를 실행하는 모드로서, 중요한 정보에 접근해 위험한 상황을 초래할 수 있는 연산을 수행한다.
- 시스템에 중요한 영향을 미치는 연산은 커널 모드에서만 실행 가능하다.
- 이 모드에서는 모든 종류의 명령을 다 실행할 수 있다.
- 사용자 모드(user mode)
- 일반 사용자 프로그램이 실행되며 제한적인 명령만을 수행할 수 있다.
CPU 내부에는 모드 비트(Mode bit)를 두어 사용자 프로그램이 수행되는 동안 실행될 수 있는 권한을 제한한다.
모드 비트가 0으로 세팅되어 있으면 커널 모드로서 모든 명령을 수행할 수 있고, 1로 세팅되어 있으면 사용자 모드로서 제한된 명령만을 수행할 수 있다.
사용자 모드의 상태에서 사용자 프로그램이 수행되다가 하드웨어 접근 등 보안이 필요한 중요한 명령을 수행해야 할 경우에는 시스템 콜을 통해 운영체제에게 요청하고 운영체제가 CPU의 권한을 획득한다. 그리고 프로그램으로부터 요청받은 명령을 대신 수행해준다. 요청된 작업이 모두 끝난 후에는 모드 비트를 다시 1로 만들어 사용자 프로그램에게 CPU를 넘겨 주게 된다.
이와 같이 시스템의 보안과 관련된 명령들을 특권 명령이라고 말하며, 특권 명령은 모드 비트가 0일 때에만 수행할 수 있게 된다. 즉, 특권 명령은 커널 모드에서 운영체제에 의해서만 수행이 가능하다.
메모리 보안
메모리에는 여러 프로그램이 동시에 올라가서 실행되기 때문에 하나의 사용자 프로그램이 다른 사용자 프로그램이나 운영체제가 위치한 메모리 영역을 침범할 수 있기 때문에 각각의 영역에 대한 보안이 필요하다.
메모리는 기준 레지스터와 한계 레지스터를 사용해 각 프로그램이 접근하려는 메모리 부분이 합법적인지를 체크함으로써 메모리 보안이 이루어진다.
- 기준 레지스터(base register) : 프로그램이 합법적으로 접근할 수 있는 메모리 상의 가작 작은 주소 즉, 시작 주소를 가지고 있다.
- 한계 레지스터(limit register) : 프로그램이 기준 레지스터 값부터 접근할 수 있는 메모리의 범위를 보관한다.
따라서, 프로그램 A가 접근할 수 있는 메모리의 범위는 기준 레지스터에 있는 주소부터 “기준 레지스터 + 한계 레지스터 값” 사이의 주소 영역만 접근이 가능하며, 접근하려는 주소가 이 범위 안에 없으면 불법적인 메모리 접근이므로 예외 상황이라는 소프트웨어적인 인터럽트가 발생하게 된다.
위의 경우는 한 프로그램이 메모리의 한 영역에 연속적으로 위치하는 경우에만 해당된다.
사용자 모드인 경우에 기준 레지스터와 한계 레지스터를 사용해서 메모리를 보호한다. 커널 모드에서는 메모리에 무제한으로 접근이 가능하다. 메모리 접근 명령은 특권 명령이 아니지만, 올바르지 않은 접근 시도로부터 메모리를 보호하기 위해서는 기준 레지스터와 한계 레지스터의 값을 세팅하는 연산은 특권 명령으로 규정해야 한다. 그렇지 않으면 프로그램이 레지스터의 값을 직접 변경해 메모리에 무제한 접근하는 것이 가능하기 때문이다.
그러므로 운영체제가 두 개의 레지스터 값을 직접 세팅해주고 사용자 프로그램은 값을 변경할 수 없게 한다.
CPU 보호
CPU가 하나의 프로그램에 의해 독점되는 것을 막기 위해 운영 체제는 타이머(timer)라는 하드웨어를 사용한다.
타이머: 정해진 시간이 지나면 인터럽트를 발생시켜 운영체제에게 CPU의 제어권을 이양시키는 역할을 수행한다.- 타이머에 의해 발생하는 인터럽트 처리 루틴은 지금 CPU를 할당받고 수행 중인 프로그램에게서 CPU를 선점해 다른 프로그램에게 CPU를 이양하는 내용이다.
- 타이머는 시분할 시스템에서 현재 시간을 계산하기 위한 용도로 사용된다. 타이머의 값을 세팅하는 명령을 로드 타이머라 하며, 이는 특권 명령으로 분류된다.
시스템 콜을 이용한 입출력 수행
입출력 명령은 특권 명령에 해당 한다. 따라서 사용자 프로그램이 직접 수행할 수 없다.
사용자 프로그램은 직접 입출력을 수행하는 대신 운영 체제에게 시스템 콜이라는 서비스 대행 요청을 하여 입출력을 수행하게 된다. 시스템 콜은 일종의 소프트웨어적인 인터럽트로서 사용자 프로그램이 시스템 콜을 할 경우, 트랩이 발생해 CPU에 대한 제어권이 운영체제로 넘어간다.
그러면 운영 체제는 해당 시스템 콜을 처리하기 위한 루틴으로 가서 정의된 명령을 수행하게 된다. 시스템 콜이 디스크에 대한 입출력 요청이었으면 디스크 컨트롤러에게 입출력 요청을 수행하도록 명령하고, 추후에 디스크 컨트롤러가 입출력 수행을 마치면 CPU에게 인터럽트를 발생시켜 입출력이 완료되었음을 알려주어 해당 프로그램이 다시 CPU를 할당 받을 수 있도록 한다.

