- 1. 컴퓨터 시스템의 구조
- 2. CPU와 I/O 연산
- 3 인터럽트의 일반적 기능
- 4. 인터럽트 핸들링
- 5. 입출력 구조
- 6. DMA(Direct Memory Access)
- 7. 저장 장치의 구조
- 8. 저장 장치의 계층 구조
- 9. 하드웨어의 보안
- 10. 메모리 보안
- 11. CPU 보호
- 12. 시스템 콜을 이용한 입출력 수행
1. 컴퓨터 시스템의 구조
- OS 중 항상 메모리에 올라가 있는 부분은 전체 OS 중 일부분에 해당되는데, 이 부분을 커널이라 한다.
2. CPU와 I/O 연산
-
컴퓨터에서 연산을 한다는 것은 CPU가 무언가 일을 한다는 뜻이다.
-
각 장치마다 이를 제어하기 위해 설치된 장치 러에는
장치로부터 들어오고 나가는 데이터를 임시로 저장하기 위한 작은 메모리를 갖고 있다.
이를 로컬 버퍼라고 부른다. -
이 때 장치에서 로컬 버퍼로 읽어오는 일은 컨트롤러가 담당한다.
-
데이터를 모두 가지고 왔는지 확인하는 작업은 메인 CPU가 일일이 체크하는 것이 아니라
장치에 있는 컨트롤러가 인터럽트를 발생시켜 CPU에게 보고한다. -
이 때 인터럽트란 컨트롤러들이 CPU의 서비스가 필요할 때 이를 통보하는 방법을 말한다.
-
기본적으로 CPU는 매 시점 메모리에서 명령을 하나씩 읽어와서 수행한다.
-
이 때 CPU 옆에는 인터럽트 라인이 있어서, CPU가 자신의 작업을 하던 중간에 인터럽트 라인에 신호가 들어오면 하던 일을 멈추고, 인터럽트와 관련된 일을 처리한다.
즉, CPU는 명령 하나를 수행할 때마다 인터럽트가 발생했는지를 체크한다.
3 인터럽트의 일반적 기능
-
OS 커널에는 인터럽트가 들어왔을 때 해야 할 일을 미리 다 프로그래밍해서 보관하고 있다.
그 중 한가지가 인터럽트 처리 루틴이다. -
먼저 로컬 버퍼에 있는 내용을 프로그램 B가 사용할 수 있도록 메모리에 전달하고,
이제 B가 CPU를 할당받을 경우 다음 명령(instruction)을 수행할 수 있음을 표시한다. -
인터럽트가 발생하면 CPU는 하던 일을 멈추고 인터럽트를 처리하기 위한 루틴(OS 커널 내부 코드)에 들어가서 정의된 일을 찾게 된다.
-
OS는 할 일을 쉽게 찾아가기 위해 인터럽트 벡터를 갖고 있다.
인터럽트 벡터란 인터럽트 종류마다 번호를 정해서, 번호에 따라 처리해야 할 코드가 위치한 부분을 포인터로 가리키고 있는 자료 구조이다. -
실제 처리해야 할 내용은 인터럽트 서비스 루틴이라는 다른 곳에 정의된다.
4. 인터럽트 핸들링
-
CPU에서 명령이 수행될 때에는 CPU 내부에 있는 임시 기억 장치인 레지스터에 데이터를 R/W 작업을 수행하게 되는데,
인터럽트가 발생해 새로운 명령을 수행하면 기존의 레지스터 값들이 지워지게 되므로 레지스터 값 등 CPU 내의 하드웨어 상태를 저장해 두어야 한다. -
OS 커널 영역에는 현재 시스템 내에서 수행되는 프로그램들을 관리하기 위한 자료 구조인 프로세스 제어 블록(PCB)을 두고 있다.
- PCB 중 일부분은 인터럽트 발생 시 프로그램의 어느 부분이 수행되던 중이었는지를 저장하기위해 사용된다.
- 저장되는 내용으로는 현재 수행중이던 메모리 주소와 레지스터 값, HW 상태 등이 있다.
- 인터럽트 수행이 끝나면 저장된 값을 CPU 상에 다시 복원해 직전의 명령을 계속 수행할 수 있다.
- 현재 수행중인 프로그램의 수가 n개라고 할 때, 커널 스택은 n만큼 독립적인 공간을 둔다.
- 즉, 인터럽트 처리 루틴으로 넘어와서 함수 호출이 이루어질 경우에는 각 프로세스별로 독자적인 커널 스택을 사용하게 된다.
- 프로그램 A가 수행중에 인터럽트가 발생하면 현재까지 수행된 지점을 프로세스 제어 블록에 저장하고,
인터럽트 처리 루틴으로 와서 커널 코드를 수행하게 되며, 이 때 이루어지는 함수 호출은 프로세스 A의 커널 스택을 사용하게 된다.
- 통상적으로 인터럽트라 하면 HW 인터럽트를 의미하고, SW는 트랩(trap)이라는 용어를 사용한다.
- SW 인터럽트의 예로는 예외 상황(Exception), 시스템 콜(System Call) 등이 있다.
- SW 인터럽트는 HW 인터럽트처럼 컨트롤러가 발생시키는 인터럽트가 아니라
프로그램 수행 도중 직접 CPU에 인터럽트 라인을 세팅하여 발생시킨다.
5. 입출력 구조
동기식 입출력
- 입출력 요청 후 입출력 작업이 완료된 후에야 CPU의 제어권이 그 프로그램에게 다시 넘어갈 수 있는 방식을 말한다.
// 호출한 프로그램에게 다시 넘어간다 !!!
Ex)
프로그램 A가 CPU를 할당받고 명령을 수행하다가 입출력 요청을 하게 되면
입출력 작업이 완료될 때까지 CPU의 낭비가 초래되므로
CPU를 프로그램 A에게서 선점해 다른 프로그램 B에게 할당하게 된다.
그러면 프로그램 B가 CPU를 할당받아 명령을 수행하고, 프로그램 A의 입출력이 완료될 때까지 A에게는 CPU를 다시 할당하지 않는다.
이는 입출력이 완료될 때까지 그 프로그램에 CPU를 할당하더라도 명령을 수행하지 못하기 때문이다.
- 이것을 프로그램을 봉쇄 상태(Blocked state)로 전환시킨다고 말한다.
선점 시 다음과 같은 문제 발생이 가능하다.
프로그램 A가 파일의 내용을 1->3으로 바꾸는 입출력 요청
그러면 A로부터 CPU를 선점해서 프로그램 B에게 할당
프로그램 B는 파일의 내용 값을 1 증가시키는 연산 실행
결과적으로
1->3->4가 아닌 1->2->3이 된다.
- 따라서 동기식 입출력에서는 입출력 요청의 동기화를 위해 장치별로 큐(queue)를 두어 요청 순서대로 처리하여 동기화 문제를 해결한다.
동기식 입출력 요약
- 동기식 입출력을 요청한 프로그램은 입출력이 완료될 때까지 다음 명령을 수행할 수 없기에 CPU가 낭비된다.
- CPU의 효율적인 사용을 위해 입출력이 수행되는 동안 다른 프로그램에게 CPU를 양도하여
동시에 다수의 입출력 연산이 가능해 진다. - 다수의 프로그램이 동시에 입출력 연산을 요청하는 경우 동기성을 보장하기 위해 장치마다 큐를 두어 해결한다.
동기식 입출력 과정 (1)
사용자가 I/O 요청을 하면 먼저 OS의 커널로 CPU의 제어권이 넘어와서
입출력 처리와 관련된 커널의 코드가 수행된다.
이 때, 입출력을 호출한 프로세스의 상태를 봉쇄 상태로 바꾸고
입출력이 완료될 때까지 CPU를 할당받지 못하도록 한다.
입출력이 완료되면 I/O 컨트롤러가 CPU에게 인터럽트를 발생시켜 입출력이 완료되었음을 알려준다.
그러면 이 프로세스의 봉쇄 상태를 해제시켜 CPU를 할당받을 수 있는 권한이 다시 생긴다.
동기식 입출력 과정 (2)
프로그램 A가 실행중에 디스크에서 어떤 데이터를 읽어오는 명령을 만나면
프로그램 A는 시스템 콜을 통해 CPU에게 S/W 인터럽트를 발생시킨다.
그러면 CPU는 지금까지 프로그램 A의 작업을 멈추고 현재 상태를 저장 후
인터럽트에 의해 처리해야 할 커널의 루틴으로 이동한다.
처리 루틴으로 이동하면 CPU는 컨트롤러에게 입출력 연산을 요청한다.
그러면 컨트롤러는 A가 요청한 데이터를 디스크로부터 자신의 로컬 버퍼로 읽어온다.
읽어오는 동안 프로그램 A는 봉쇄 상태가 되고 CPU를 선점당하게 되며,
CPU는 다른 프로세스에게 할당해 계속 CPU가 일을 할 수 있도록 한다.
원하는 정보가 로컬 버퍼로 다 들어오면 컨트롤러는 CPU에게 인터럽트를 발생시킨다.
이 때 발생하는 인터럽트는 H/W 인터럽트에 해당한다.
프로그램 B를 수행중이던 CPU는 작업을 멈추고 현재 상태를 저장 후 인터럽트를 처리하게 된다.
인터럽트 처리 루틴은 로컬 버퍼에 있는 A가 요청한 데이터를 A의 메모리 영역으로 읽어오고,
A의 봉쇄 상태를 해제시킨다. 그러면 A는 다시 CPU를 기다리는 줄에 대기하게 된다.
그 후 CPU는 원래 수행하던 프로그램 B의 지점으로 돌아가서 하던 업무를 계속 수행한다.
프로그램 A는 CPU를 기다리는 줄에서 기다리다
자신의 차례가 되면 CPU를 할당받고 입출력연산 이후의 작업을 수행하게 된다.
- 일반적으로 입출력 요청을 OS에게 하게 되면 동기식 입출력을 사용한다.
비동기식 입출력
- 입출력 연산 요청 후 연산 결과를 기다리는게 아니라 CPU의 제어권을 다시 프로그램에게 곧바로 부여하는 방식이다.
6. DMA(Direct Memory Access)
-
원칙적으로는 메모리는 CPU는 의해서만 접근 가능한 장치이다.
따라서, 주변 장치들이 메모리에 접근하기 위해서는 CPU에게 인터럽트를 발생시켜 CPU가 일을 대행하는 식으로만 가능하다.
즉, 컨트롤러가 CPU에게 인터럽트를 발생시키면 CPU는 컨트롤러의 로컬 버퍼와 메모리 사잉에서 데이터를 옮겨 주는 일을 하게 된다. -
모든 메모리 접근 연산이 CPU에 의해서만 이뤄질 경우 CPU의 업무가 방해 받아 효율성이 떨어지는 문제점이 발생한다.
-
이러한 비효율성을 극복하기 위해 CPU 이외에 메모리 접근이 가능한 장치를 하나 더 두는 경우가 많은데
이와 같은 장치를 DMA라고 부른다. -
DMA는 로컬 버퍼에서 메모리로 읽어오는 작업을 진행 후 CPU에게 인터럽트를 발생시켜 해당 작업의 완료를 알려준다.
-
DMA는 바이트 단위가 아니라 블록이라는 큰 단위로 정보를 메모리로 읽어 온다.
-
이런 방식으로 CPU에 발생하는 인터럽트의 빈도를 줄여 CPU의 효율성을 높일 수 있게 된다.
7. 저장 장치의 구조
- 컴퓨터 시스템을 구성하는 저장 장치는 주 기억 장치와 보조 기억 장치로 나눌 수 있다.
주 기억 장치
- 보통 메모리라 부르며 휘발성이다.
Ex) RAM
보조 기억 장치
-
비휘발성이다.
Ex) 마그네틱 디스크 -
보조 기억 장치의 용도는 크게 2가지로 구분된다.
- 파일 시스템용
- 전원 Off 시 유지해야할 정보가 있으면 그것을 파일 형태로 보조 기억 장치에 저장한다.
- 메모리는 휘발성이므로 비휘발성 매체인 디스크를 파일 시스템용으로 흔히 사용한다.
- 메모리의 연장공간인 스왑 영역용
- OS는 프로그램 수행에 당장 필요한 부분만 메모리에 올려 놓고 나머지는 디스크의 스왑 영역에 내려놓게 된다.
- 디스크에 내려놓는 일을 스왑 아웃이라 말한다.
- 스왑 아웃된 부분이 필요 시 다시 메모리 영역에 올린다.
- 스왑 영역은 프로그램이 실행 시 내용을 저장했다가 프로그램이 종료될 때 삭제하는 메모리의 연장 공간으로서의 역할을 담당한다.
- 파일 시스템처럼 비휘발성 용도로 사용되는 것과는 역할이 구분된다.
8. 저장 장치의 계층 구조
-
주 기억 장치 / 보조 기억 장치로 나눌 수 있다.
-
주 기억 장치 : 비쌈 / 빠름 / 용량 적음 / 휘발성
-
보조 기억 장치 : 저렴 / 느림 / 용량 많음 / 비휘발성
9. 하드웨어의 보안
-
우리가 사용하는 OS는 여러 프로그램이 동시에 실행될 수 있는 다중 프로그래밍 환경에서 동작한다.
그러므로 각 프로그램들이 다른 프로그램의 실행을 방해하거나 서로 충돌을 일으키는 문제를 막기 위해 HW에 대한 각종 보안 기법이 필요하다. -
HW 보안을 유지하기 위해 OS는 기본적으로 두 가지 모드의 오퍼레이션을 지원한다.
커널 모드(Kernel Mode)
-
CPU 내부의 모드 비트가 0인 상태이다.
OS가 CPU의 제어권을 갖고 OS 코드를 실행하는 모드로서, 모든 종류의 명령을 다 실행할 수 있다. -
중요한 정보에 접근해 위험한 상황을 초래할 수 있는 연산은 커널 모드에서만 실행되도록 하여 보안성을 확보한다.
-
시스템의 보안과 관련된 명령들을 특권 명령이라하며, 모드 비트가 0일 때에만 수행가능하다.
즉, 특권 명령은 커널 모드에서 OS에 의해서만 수행이 가능하다.
사용자 모드(User Mode)
- CPU 내부의 모드 비트가 1인 상태이다.
일반 사용자 프로그램이 실행되며 제어한적인 명령만을 수행할 수 있다.
# 모드 비트 사용 이유
사용자 프로그램이 프로그램 내에서 시스템에 영향을 끼치는 연산을 수행할 수 가 있다.
이 때 사용자 프로그램이 CPU를 가지고 있는 동안에는 OS가 CPU를 선점할 수 없으므로 사용자 프로그램을 감시할 수 있는 방법이 없다.
그렇기 때문에 CPU 내부에 모드 비트를 두어 사용자 프로그램을 감시할 수 있게 된다.
# 모드 비트 세팅 과정
OS가 CPU를 점유해 자신의 코드를 수행하다 사용자 프로그램에게 CPU의 제어권을 넘길 때
모드 비트를 1로 세팅해 넘긴다.
사용자 프로그램이 수행되다 HW 접근 등 보안이 필요한 중요한 명령을 수행해야 할 경우에는
시스템 콜을 통해 OS에게 서비스를 대신해 줄 것을 요청하게 된다.
인터럽트가 발생할 때에는 모드 비트가 0으로 세팅되어 OS는 서비스에 필요한 모든 종류의 명령을 수행할 수 있다.
10. 메모리 보안
-
여러 프로그램이 동시에 메모리에 올라가서 실행되기 때문에 하나의 사용자 프로그램이 다른 사용자 프로그램이나 OS가 위치한 메모리 영역을 침범할 수 있기 때문에 메모리 보안이 필요하다.
-
2개의 레지스터(기준 레지스터, 한계 레지스터)를 사용해서 프로그램이 접근하려는 메모리 부분이 합법적인지 체크하여 메모리 보호가 이뤄진다.
-
기준 레지스터는 어떤 프로그램이 수행되는 동안 합법적으로 접근할 수 있는 메모리 상의 가장 작은 주소를 보관한다.
-
한계 레지스터는 그 프로그램이 기준 레지스터 값부터 접근할 수 있는 메모리의 범위를 보관한다.
-
즉 어떤 프로그램이 실제 메모리에 올라가 있는 부분의 시작 주소와 그 프로그램의 길이를 보관해 메모리 접근 연산이 있을 때마다 하드웨어적으로 현재 접근하려는 위치가 합법적인 범위인지를 체크한다.
-
사용자 프로그램은 기준 레지스터 + 한계 레지스터 값 사이 주소 영역만 접근이 가능하며, 이 범위 안에 없으면 불법적인 메모리 접근이므로 예외 상황이라는 SW 인터럽트를 발생하게 된다.
예외 상황은 OS에게 SW 인터럽트를 발생시켜 CPU의 제어권을 이양시키고 OS는 그 프로그램을 강제 종료시킨다. -
단 여기에서 기준 + 한계 레지스터를 통한 메모리 보호 기법은 하나의 프로그램이 메모리의 한영역에 연속적으로 위치하는 경우에 대한 설명이다.
그 밖의 하나의 프로그램이 메모리 여러 영역에 나뉘어 위치하는 페이징기법도 존재한다. -
메모리 접근 연산은 사용자 프로그램이 CPU를 가지고 있는 동안에 수행할 수 있는 연산이므로 특권 명령은 아니다.
다만 사용자 프로그램이 메모리를 접근하기 전에 하드웨어적으로 그 접근이 합법적인지를 체크하여 메모리를 보호한다.
이것이 OS만 수행할 수 있는 입출력 연산과 메모리 접근 연산과의 차이점이라 할 수 있다. -
사용자 모드인 경우에는 기준 + 한계 레지스터를 사용해 메모리를 보호하고
커널 모드에서는 메모리에 무제한으로 접근이 가능하다.
11. CPU 보호
-
일반적으로 CPU는 컴퓨터 내에 하나밖에 존재하지 않기 때문에 특정 프로그램이 CPU를 독점해 무한 반복문을 수행하는 등 부적절한 방법으로 독점한다면 다른 프로그램 및 OS가 CPU의 제어권을 획득할 수 있는 방법이 없게 된다.
-
OS는 CPU가 하나의 프로그램에 의해 독점되는 것을 막기 위해 타이머라는 HW를 사용한다.
-
타이머는 정해진 시간이 지나면 인터럽트를 발생시켜 OS에게 CPU릐 제어권을 이양시키는 역할을 수행한다.
-
타이머는 시분할 시스템에서 현재 시간을 계산하기 위해서도 널리 사용된다.
시분할 시스템이란 여러 프로그램이 CPU의 시간을 조금씩 나누어 사용하는 시스템을 의미한다.
12. 시스템 콜을 이용한 입출력 수행
-
시스템 콜은 일종의 SW 인터럽트로 사용자 프로그램이 시스템 콜을 요청할 경우 트랩이 발생해 CPU에 대한 제어권이 OS로 넘어가게 된다.
-
그러면 OS는 해당 시스템 콜을 처리하기 위한 루틴으로 가서 정의된 명령을 수행하게 된다.