[OS] Chapter 3, 4. 컴퓨터 시스템의 동작 원리
Table of Contents
운영체제와 정보기술의 원리 강의를 듣고 공부한 노트입니다.
컴퓨터 시스템의 구조 #
컴퓨터 내 연산과 I/O 연산 #
- 컴퓨터 내에서 수행되는 연산 : CPU 담당
- CPU는 매 시점에 메모리에서 명령(instruction) 하나를 읽어서 수행한다.
- CPU가 어떤 명령을 수행할 지에 대한 주소는 프로그램 카운터(program counter) 라는 레지스터가 알고 있다.
- CPU는 명령을 수행할 때마다 옆에 있는 인터럽트 라인(interrupt line)에 신호가 들어왔는지를 확인한다. 그리고 신호가 들어오면 하던 일을 멈추고 인터럽트 관련된 일을 먼저 처리한다.
- 입출력 장치들의 I/O 연산 : 장치 컨트롤러 담당
- 장치 컨트롤러는 들어오고 나가는 데이터를 임시로 저장하기 위해 로컬버퍼(local buffer) 라는 작은 메모리를 가지고 있다.
- 예를 들어, 프로그램 A가 디스크에서 데이터를 읽어오라는 명령을 내리면, 장치 컨트롤러가 디스크에서 내용을 읽어서 로컬버퍼에 저장한다. 그리고 장치 컨트롤러는 인터럽트를 발생시켜서 다 했다고 보고한다.
인터럽트 #
인터럽트의 종류 #
- 하드웨어 장치나 소프트웨어는 CPU의 서비스가 필요한 경우 CPU 옆에 있는 인터럽트 라인에 신호를 보내서 인터럽트를 발생시킨다.
- 인터럽트가 발생하면, CPU는 하던 일을 멈추고 해당 인터럽트 발생 시 해야하는 코드를 찾아서 수행한다.
- (1) 하드웨어 인터럽트
- 장치 컨트롤러와 같은 하드웨어 장치가 CPU의 인터럽트 라인을 설정한다.
- (2) 소프트웨어 인터럽트
- 트랩(trap) 이라고 주로 불린다.
- 소프트웨어가 CPU의 인터럽트 라인을 설정한다.
- CPU의 제어권이 사용자 프로세스로부터 운영체제로 이양된다.
- 예를 들어, 프로그램이 키보드 입력 등의 입출력 작업이 필요할 때는 인터럽트 라인을 설정해서 CPU 제어권을 운영체제로 넘겨서 수행한다.
- 예시 1. 예외 상황(exception)
- 비정상적인 작업을 시도(0으로 나누기)하거나 권한이 없는 작업(자신의 메모리 영역을 벗어난 접근)을 시도할 때 이에 대한 처리를 하기 위해 발생시키는 인터럽트이다.
- 예시 2. 시스템 콜(system call)
- 사용자 프로그램이 운영체제 내부에 정의된 코드를 실행하고 싶을 때 운영체제에 서비스를 요청하기 위해 발생시키는 인터럽트이다.
운영체제는 인터럽트가 발생했을 때만 CPU의 제어권을 점유한다. 그 외에는 사용자 프로그램이 항상 CPU를 사용한다.
운영체제의 커널이 인터럽트 처리를 위해 갖고 있는 것들 #
- 인터럽트 처리루틴(interrupt service routine) 혹은 인터럽트 핸들러(interrupt handler)
- 인터럽트가 들어왔을 때 해야 할 일을 프로그래밍 해 놓은 코드이다.
- 인터럽트 벡터(interrupt vector)
- 인터럽트는 종류마다 번호가 정해져 있고, 인터럽트 발생 시 각각 처리해야 할 코드가 다르다.
- 인터럽트 벡터는 인터럽트 번호마다 처리할 코드를 가리키고 있는 자료구조이다.
- 각 인터럽트 종류마다 번호를 정해 놓았다.
- 프로세스 제어블록(Process Control Block: PCB)
- 운영체제가 프로세스들을 관리하기 위해 프로세스의 정보를 담는 커널 내의 자료구조이다.
- CPU는 새로운 명령을 실행하면 레지스터에 데이터를 읽고 쓰면서 작업을 한다. 인터럽트가 발생하면 현재 실행되던 기존 레지스터 값들이 모두 날아가기 때문에, 현재 실행되던 프로세스의 상태를 저장해두어야 한다. 그래서 프로세스마다 PCB를 갖고 있고, 여기에는 실행 중이던 코드의 메모리 주소와 레지스터 값 등이 담긴다.
- 예를 들어, 프로그램 실행 중에 인터럽트가 발생하면 상태를 PCB에 저장하고 CPU의 제어권이 인터럽트 처리루틴으로 넘어간다. 그리고 처리가 끝나면 저장된 상태를 PCB에서 CPU로 복원해서 해당 위치부터 다시 작업을 이어나간다.
- PCB 구성 요소
인터럽트의 우선순위 #
- 더 높은 우선순위의 인터럽트가 발생하면 현재 처리 중이던 인터럽트 코드의 수행 지점을 저장하고 우선순위가 높은 인터럽트를 처리히게 된다.
입출력 구조 #
- (1) 동기식 입출력(synchronous I/O)
- 어떤 프로그램이 입출력 요청을 하면, 그 입출력 작업이 완료된 다음에야 다음 후속 작업을 할 수 있는 것이다.
- 이렇게 되면 한 입출력 작업이 끝날 때까지 CPU가 아무일도 하지 않아서 자원이 낭비된다. 그래서 일반적으로는 프로그램이 입출력을 수행 중인 경우, CPU를 다른 프로그램에게 이양해서 CPU가 쉬지 않고 일하도록 한다.
- 관리방법
- 운영체제는 프로그램을 몇 가지 상태로 나누고, 입출력 중인 프로그램를 봉쇄 상태(blocked state) 로 전환시킨다.
- 그리고 봉쇄 상태인 프로그램에게는 CPU를 할당하지 않고, 다른 프로그램에게 할당해준다.
- 만약에 여러 프로그램의 입출력 요청이 여러번 있다면, 그 순서는 어떻게 지킬 것인가?
- 장치별로 큐(queue)를 두어서 요청한 순서대로 처리할 수 있도록한다.
- (2) 비동기식 입출력(asynchronous I/O)
- 입출력 연산이 끝나기를 기다리지 않고, CPU 제어권을 입출력 연산을 호출한 그 프로그램에게 곧바로 다시 부여하는 것이다.
- 그래서 입출력 연산과 무관하게 처리 가능한 작업들을 처리할 수 있다.
- 디스크나 키보드에서 데이터를 읽어오는 경우의 동기식 입출력 예시…
- 프로그램 A를 실행하던 중에, 디스크에서 데이터를 읽어오는 명령을 만나게 되면, 그 프로그램은 시스템 콜(소프트웨어 인터럽트) 을 통해 CPU에게 인터럽트를 발생시킨다.
- CPU는 인터럽트가 발생하면, 하던 일을 멈추고 현재 실행 중이던 프로그램의 상태를 PCB에 저장한다. 그리고 CPU의 제어권이 운영체제로 이양된다.
- 운영체제 커널에서 인터럽트 처리루틴을 찾아서 장치 컨트롤러에게 입출력 연산을 요청한다.
- 장치 컨트롤러가 물리적인 장치에서 로컬버퍼로 데이터를 읽어온다.
- (읽어오는 동안 해당 프로그램은 운영체제에 의해 봉쇄 상태로 설정되었으므로 CPU를 할당 받지 못한다.)
- (그동안 CPU는 다른 프로그램 B에게 할당된다.)
- 그러고 나서, 다 읽었다고 인터럽트를 발생시킨다. (하드웨어 인터럽트)
- 인터럽트 처리루틴에 의해서 요청한 데이터를 해당 메모리 영역으로 읽어오고, 봉쇄 상태를 해제한다. 그리고 다음 차례를 기다린다.
- PCB에 담긴 저장 상태를 레지스터로 복원해서 작업을 이어나간다.
CPU 대신 메모리에 접근하는 DMA #
- DMA(Direct Memory Access)
- CPU만이 메모리에 접근해서 연산을 처리할 수 있다. 하지만 이렇게 되면 입출력 장치가 메모리 접근을 원할 때마다 인터럽트에 의해 CPU 업무가 방해를 받게된다.
- 따라서 DMA라는 장치를 두어 로컬버퍼에서 메모리로 읽어오는 작업을 대행할 수 있게 했다.
- DMA는 바이트(byte) 단위가 아니라 블록(block) 이라는 큰 단위로 데이터를 로컬버퍼에서 읽어온다. 그리고 나서 CPU에게 인터럽트를 발생시켜서 작업이 완료되었음을 알린다.
저장장치의 구조 #
- 주기억장치
- 휘발성(volatile)
- 보조기억장치
- 비휘발성(nonvolatile)
- 보조기억장치의 용도
- (1) 파일 시스템(file system) 용
- 주기억장치의 내용은 전원이 꺼지면 모두 날아가므로, 전원이 나가도 유지할 정보를 저장하기 위해 사용한다.
- (2) 스왑 영역(swap area) 용
- 주기억장치의 크기가 한정적이기 떄문에, 주기억장치에는 당장 필요한 부분만 올려놓고 나머지는 디스크의 스왑영역에 내려놓는다. 이렇게 메모리의 연장 공간인 스왑 영역으로 사용할 수 있다.
- 당장 필요한 게 아닌 부분은 디스크의 스왑 영역에 내려 놓는데, 이것을 스왑 아웃(swap out) 이라고 한다.
- (1) 파일 시스템(file system) 용
- 저장장치 빠른 순서
- 레지스터 → 캐시 메모리 → 메인 메모리 → 마그네틱 디스크 → 광디스크 → 마그네틱 테이프
- 캐싱 기법
- 느린 저장장치에 있는 내용 중 당장 사용되거나 빈번히 사용될 정보를 빠른 저장장치에 선별적으로 저장해서, 두 저장장치 사이의 속도를 완충하는 것이다.
하드웨어 보안 #
CPU가 수행하는 명령의 종류 #
- (1) 일반 명령
- 메모리에서 자료를 읽어와 CPU에서 계산하고 결과를 메모리에 쓰는 명령들.
- (2) 특권 명령
- 보안이 필요한 명령들.
- 입출력 장치, 타이머 장치 등 각종 장치에 접근하는 명령.
하드웨어 보안을 위한 운영체제의 모드 #
- (1) 사용자 모드(user mode)
- 일반 명령만 수행할 수 있다.
- (2) 커널 모드(kernel mode)
- 운영체제가 CPU의 제어권을 가지고 운영체제의 코드를 실행하는 모드이다. 이 모드에서는 모든 명령을 다 실행할 수 있다.
- 사용자 프로그램이 이상한 명령으로 다른 프로그램의 메모리 영역이나 파일 시스템에 접근하면 위험한 상황이 발생할 수 있다.
- 따라서 중요한 정보에 접근해 위험한 상황을 초래할 수 있는 연산은 커널모드에서만 실행되도록 했다.
- 만약에 사용자 프로그램이 CPU의 제어권을 갖고 있을 때 중요한 연산을 실행시켜버리면 어떡할까?
- CPU 내부에 모드 비트(mode bit) 를 두어서 사용자 프로그램을 감시하도록 했다.
- 모드 비트가 1이면 사용자 모드이고, 0이면 커널 모드이다.
- 그래서 CPU는 보안과 관련된 명령을 수행하기 전에 모드 비트를 살펴보고 커널 모드일 때만 그 명령을 수행한다.
사용자 프로그램이 CPU를 빼앗기는 경우는 (1)입출력 요청을 위해 시스템 콜을 하는 경우와 (2)타이머에 의해 인터럽트가 발생한 경우이다.
메모리 보안 #
메모리 보안을 위한 2개의 레지스터 #
- (1) 기준 레지스터(base register)
- 해당 프로그램이 합법적으로 접근할 수 있는 메모리 상의 가장 작은 주소를 보관한다.
- (2) 한계 레지스터(limit register)
- 해당 프로그램이 합법적으로 접근할 수 있는 메모리의 범위를 보관한다.
- 따라서 메모리 접근 연산이 있을 때마다,
기준 레지스터 ~ 기준 레지스터 + 한계 레지스터
의 범위에 있는지를 체크해서 보안을 한다.- 이것은 프로그램이 연속적으로 메모리에 위치한다는 것을 가정한 것이다. 페이징과 같이 여러영역에 나뉘어 위치할 경우에는 다른 메모리 관리 기법이 필요하다. 이것은 다음에 살펴본다.
CPU 보호 #
타이머 #
- CPU가 하나의 프로그램에 의해서 독점되는 것을 막기 위해, 운영체제는 타이머(timer)라는 하드웨어를 사용한다.
- 타이머는 정해진 시간이 지나면 인터럽트를 발생시켜서 운영체제가 CPU의 제어권을 획득할 수 있도록 한다.
- 시분할 시스템에서 현재 시간을 계산하기 위해서도 사용한다.
- 타이머의 값을 일정 시간 단위로 세팅하는 명령을 로드 타이머(load timer) 라고 한다. 이것은 특권명령이다.
프로그램의 주소 영역 #
- 프로그램이 실행되었을 때, 프로그램의 주소 영역 중에서 당장 실행에 필요한 부분만 메모리에 올려놓고, 나머지 부분은 메모리의 연장 공간으로 사용되는 스왑 영역에 내려놓는다.
- 프로그램이 각각 독자적으로 가지는 주소 공간을, 가상 메모리(virtual memory) 혹은 논리적 메모리(logical memory) 라고 한다.
주소영역 | 설명 |
---|---|
코드(code) | CPU에서 수행할 수 있는 기계어 명령(machine instruction)을 저장하는 부분. |
데이터(data) | 전역 변수(global variable) 등, 프로그램이 사용할 데이터를 저장하는 부분. |
스택(stack) | 호출된 함수의 수행을 마치고 복귀할 주소 및 데이터를 임시로 저장하는 부분. |
커널의 주소 영역 #
- 커널도 주소 공간을 가지고 있다.
주소영역 | 설명 |
---|---|
코드(code) | CPU, 메모리 등 자원을 관리하기 위한 코드. 사용자에게 편리한 서비스를 제공하기 위한 코드. 시스템 콜, 인터럽트를 처리하기 위한 코드. |
데이터(data) | 각종 자원을 관리하기 위한 자료구조가 저장된다. CPU나 메모리같은 하드웨어 자원을 관리하기 위한 자료구조(큐 등), PCB. |
스택(stack) | 호출된 함수의 수행을 마치고 복귀할 주소 및 데이터를 임시로 저장하는 부분. 각 프로세스 마다 별도의 스택을 두어서 관리한다. |
- 상황에 따라 복귀 정보가 담기는 곳이 달라진다.
- 프로그램 수행중에 다른 함수 호출이 이루어졌다 → 복귀 정보는 프로그램의 스택에 담긴다.
- 인터럽트로 CPU의 수행 주체가 운영체제로 바뀌었다. → 복귀 정보는 PCB에 담긴다.
- 커널의 코드가 수행되던 중간에 다른 함수호출이 이루어졌다. → 복귀 정보는 커널의 스택에 담긴다.