이 글은 KOCW에 공개되어있는 '반효경 교수님'의 운영체제 강의 및 강의 교재 Operation System Concepts(a.k.a 공룡책🦕)의 내용을 기반으로 작성했t습니다.
이번 챕터에서는 운영체제의 동작을 이해하기 위한 하드웨어의 동작, 프로그램의 동작을 설명을 할 것이다
오류가 있다면 댓글로 정정 부탁드려요
| 컴퓨터 구조
간략한 컴퓨터 구조는 [CPU +메모리(컴퓨터)] +[ I/O device]를 말한다(modebit, interrupt는 뒤에 설명 나옴)
| CPU 와 CPU의 작업 공간 메모리
- CPU는 매 clock cycle 마다 메모리에서 instruction(기계어)를 읽어서 실행하게 된다
- CPU는 modebit을 통해 지금 실행되는 것이 운영체제인지 사용자 프로그래밍인지 구분하게 된다
- interrupt request line을 통해 interrupt 신호를 감지한다.
| IO Device
- io device 는 controller 가 붙어서 제어를 해준다(마치 작은 CPU)
- io device는 local buffer라는 각각의 작업 공간을 가지게 된다(cf CPU의 작업 공간인 memory)
- cpu에 비해 io device 는 처리 속도가 훨씬 느리다!
ex) 키보드/마우스(input device), 프린터/모니터(output device) 하드 디스크 (input, output device)
| Interrupt
주변 기기가 CPU에게 어떤 사실을 알리는 일
- CPU가 interrupt 를 당하게 된다면, interrupt 당한 시점의 레지스터와 program counter을 저장한다
- 이후 CPU의 제어를 interrupt 처리 루틴에 넘긴다 .
interrupt의 종류에는 1) software interrupt와 2) hardware interrupt(좁은 의미의 interrupt) 두 가지가 있다
| 소프트웨어의 interrupt
소프트웨어 interrupt(trap)은 사용자 프로그램이 운영체제를 호출하는 것으로 1) System call, 2) Exception 이 있다
소프트웨어의 interrupt를 설명하기에 앞서 Mode bit에 대한 이해가 필요하다
Mode bit : 사용자 프로그램의 잘못된 수행으로 다른 프로그램 및 운영체제에 피해가 가지 않도록 하는 보호 장치이다
사용자 모드 (1) : 사용자 프로그램 수행(제한된 instruction만을 수행할 수 있다)
모니터 모드 (0) : OS 코드 수행 (메모리 접근/ io 접근 instruction 등 보안과 관련된 중요한 명령어인 "특권명령" 사용 가능)
`
- 사용자 프로그램에게 CPU를 넘기기 전에 mode bit을 1로 세팅(IO 접근이 가능한 것은 운영체제 뿐)
- 시스템 콜이나 Exception 발생 시 운영체제에게 CPU 제어권을 넘기기 위해 하드웨어가 mode bit을 0으로 바꿈
- 즉 modebit은 cpu를 운영체제가 가지고 있느냐 아니면 사용자 프로그램이 가지고 있느냐를 표현해준다
- 이를 통해 사용자 프로그램이 자신의 메모리 주소 영역만을 보고 일할 수 있도록 하고, 다른 사용자 프로그램의 메모리 주소 영역이나 IO 디바이스에 접근할 수 없도록 한다
1. System Call
사용자 프로그램이 운영체제의 서비스를 받기 위해 커널 함수를 호출하는 것
1) CPU 제어권을 가지고 있던 사용자 프로그램에 IO 작업을 할 일이 생김(modebit 1)
- modebit이 1인 상태이므로 IO접근이 직접적으로 안된다
2) 사용자 프로그램이 Interrupt line 직접 세팅
- interrupt line 이 setting 되면 CPU가 하던 일이 중단되게 되며, 제어권이 운영체제로 넘어감
3) IO 작업을 하기 위해 CPU 제어권이 운영체제로 넘어 감(modebit이 0으로 바뀜), Interrupt line의 종류에 따라 CPU가 OS 커널안의 함수를 실행하게 됨
- 올바른 I/O 요청인지 확인 후 I/O 수행
- 실제로 해야할 일인 interrupt handler(interrupt service routine)을 실행하기 위해 인터럽트 벡터를 이용하여 해당 interrupt의 주솟값으로 이동 후 함수 실행
- 인터럽트 벡터 : 요청된 interrupt의 번호와 해당 interrupt 요청 시 실행해야 하는 instruction의 주솟값을 가진 vector(instruction은 운영체제 안에 함수로 정의되어 있다)
4) CPU가 IO 작업을 Device Controller에 요청하게 된다
- cpu는 IO device에 직접 접근하지 않고 메모리를 실행하는 instruction만 접근하도록 되어있음
- IO 작업은 device controller에 시킨다
- 디스크는 IO 작업의 결과를 local buffer에 집어넣게 된다
5) Controller에 요청을 한 후 CPU의 제어권은 다음 프로그램으로 넘어가게 된다
- CPU는 IO요청을 한 프로그램 다음의 프로그램을 실행하게 된다(CPU가 쉬지 않고 일하기 때문에 사용자는 interactive 하게 느낌)
2. exception(예외)
- 프로그램이 CPU에서 instruction을 실행하다 exception을 발생시킬 때 interrupt 됨
- modebit 1의 상태에서 운영체제 메모리 접근하려는 상황이 발생했을 때 interrupt line이 자동으로 세팅되고 자동적으로 cpu가 운영체제로 넘어간다
| 하드웨어의 interrupt
하드웨어 interrupt는 하드웨어 장치가 interrupt를 거는 것으로
1)IO controller interrupt와 2)timer interrupt가 있다
1) io controller interrupt
- IO controller 가 요청한 작업을 끝내서 값이 IO buffer에 들어오면 IO controller가 CPU에 interrupt 를 걸게 된다
- interrupt line이 세팅되면 CPU 제어권이 현재 실행되고 있던 프로그램에서 운영체제로 넘어오게 된다.
- 입력된 값을 IO 요청을 했던 프로그램의 메모리 영역에 카피를 해준다
- 현재 실행되다 interrupt를 당한 프로그램을 다시 실행해주게 되고, 이후 순차적으로 프로그램을 실행하게 된다
2) Timer interrupt
- 한 프로그램이 CPU를 독점하는 것을 막기 위해 하드웨어(timer)를 이용해 CPU 제어권을 가질 수 있는 시간 제한을 두는 것
- CPU 제어권은 운영체제 -> A프로그램 -> 운영체제 -> B프로그램-> 운영체제->... 형태로 넘어가게 된다
- 운영체제는 cpu를 가지고 있다가 사용자 프로그램에 cpu를 넘겨줄 때 타이머를 같이 달아 전달하며 시간이 다 되면 interrupt를 발생시킨다
- 만약 메모리에서 instruction을 돌다가 프로그램이 수행을 마치고 종료가 되면, CPU를 자동으로 반납하게 되고 interrupt가 일어나지 않기 때문에 운영체제는 CPU를 사용할 일이 없게 된다
| IO Device (입출력 장치) 구조
| Device Controller
Device Controller 은 해당 I/O 장치 유형을 관리하는 일종의 작은 CPU이며,
제어 정보를 위한 1) control register/status register과 2) local buffer(data register)을 가진다
1) 제어정보를 위한 레지스터(control register/ status register)
cpu가 일을 시킬 때 제어정보를 위한 레지스터를 이용해 지시를 내리게 한다
2) local buffer(data register) & device controller
어떤 파일을 저장하고 싶으면 데이터 자체는 local buffer에 저장하고, 명령은 device controller에 시킨다
device controller(장치제어기) : 각 장치를 통제하는 작은 CPU(하드웨어)
device driver(장치구동기) : 운영체제 코드 중 각 디바이스 접근을 위한 인터페이스에 맞게 붙이는 소프트웨어 모듈(소프트웨어)
| DMA(Direct Memory Access) Controller
IO Device 가 처리한 일이 Local Buffer에 쌓이면 Interrupt가 발생하고, CPU가 내용을 읽어 Memory에 복사하게 된다
-> cpu가 너무 많은 interrupt를 당해 비효율적이라 할 수 있다
그래서 메모리에 직접 접근할 수 있는 DMA(direct memory access) Controller를 하나 더 둔다
- CPU 와 DMA가 동시에 메모리 영역에 접근하는 문제가 발생할 수 있다
- 이를 방지하기 위해 Memory Controller은 CPU와 DMA 중 어떤 것이 먼저 접근할 지를 중재해준다
- DMA의 작동 순서는 다음과 같다(다음 작업을 통해 오버헤드를 줄일 수 있다)
1)I/O 작업 후 Local Buffer에 내용 저장
2) DMA가 메모리로 내용 복사
1, 2번 반복
3) 기준치 이상(block 단위)까지의 일을 하게 되면 DMA는 CPU에 Interrupt를 한번 걸어 내용이 메모리에 올라왔다고 보고함
| IO 작동 방식(입출력 방식)
입출력 방식에는 1)동기식 입출력, 2)비동기식 입출력 두가지가 있다
| 동기식 입출력(synchronous I/O)
동기식 입출력은 I/O 요청 후 입출력 작업이 완료된 후에야 제어가 사용자 프로그램에 넘어가는 것을 말한다
동기식 입출력 구현방법 1
I/O 가 끝날 때 까지 해당 프로그램에 cpu를 할당시킨다
-> cpu를 낭비시키며, 매 시점 I/O를 하나만 할 수 있어 I/O를 낭비시킨다
동기식 입출력 구현방법 2
I/O 처리가 끝날 때까지 해당 프로그램에서 CPU를 빼앗고, I/O 처리를 기다리는 줄에 그 프로그램을 줄세운다. 그 때까지 다른 프로그램에 CPU를 할당한다
-> cpu와 I/O 를 낭비하지 않을 수 있다
| 비동기식 입출력(Asynchronous IO)
I/O가 시작된 후 입출력 작업이 끝나기를 기다리지 않고 제어가 사용자 프로그램으로 즉시 넘어가는 것
- asynchronous로 짜여진 시스템 프로그램은 운영체제에 i/o요청만 해놓고 바로 cpu 제어권을 얻어서 다른 작업을 하는 것이다
- io와 관련 없는 작업을 먼저 진행-> io 결과를 안 후에 io 작업을 진행
- 보통 read 는 synchronous, writing 은 asynchronous 하게 한다
- 비동기 & 동기 모두 I/O의 완료는 모두 interrupt가 알려준다
| 서로 다른 입출력 명령어
일반적 IO 방식
- memory instruction(로드 스토어) 와 IO 디바이스의 주소를 따로 사용한다
Memory Mapped 방식
- IO device에 메모리 주소를 매겨서 memory instruction을 통해 IO 디바이스 접근
- IO 장치에도 메모리 주소의 연장 주소를 붙인 후 메모리 접근 가능하게 함(사실 메모리 접근이 아니라 IO 접근인 것)
저장 장치(Storage) 구조
저장장치의 구조는 다음과 같이 1) Primary Storage, 2) Secondary Storage 로 구성되어있다
기본적으로 위로 올라갈 수록 속도가 빠르고 비싸다
1. primary(Executable)
- Primary Storage는 CPU에 직접 접근하기 때문에 "바이트 단위" 로 접근이 가능하다(executable)
- Primary Storage는 대부분 휘발성 매체로 구성되어있다(하지만 최근에는 비휘발성 매체를 사용하기도 한다)
- Secondary Storage에 비해 용량이 작기 때문에 Primary Storage에 모든 것을 올려놓을 수 없다.
- Cache Memory : CPU의 속도(instruction 당 1clock)와 Main Memory DRAM의 속도(instruction당 100clock)의 속도를 완충하기 위해 사용한다. 메인 메모리보다 용량이 작기 때문에 당장 필요한 것만 올려서 사용한다
캐싱 : 당장 필요한 것만 Cache Memory에 올려놓고 사용하는 것으로 빠른 매체로 정보를 읽어들이게 된다. 캐싱은 대부분 재사용을 목적으로 하며, 한번 올려놓으면 두번째 요청할 때 바로 읽어들일 수 있어 속도가 빨라지게 된다
2. Secondary
- Secondary Storage는 setter 단위로 진행이 되는 하드디스크이기 때문에 executable하지 않다.
- secondary Storage는 비 휘발성 매체로 구성이 되어있다.
| 프로그램 실행(Memory Load)
File System에 저장되어있는 실행 파일이 메모리에 적재되면 프로세스가 되어 프로그램이 실행되게 된다. 이 때 물리적인 메모리에 바로 올라가는 것이 아니라 virtual memory 즉 가상 메모리에 적재를 하게 된다
| virtual memory (Address Space)
프로그램을 실행시키게 되면 그 프로그램의 0번지부터 시작하는 독자적인 virtual address space (가상 메모리 주소 공간)가 생기게 되고, 주소 공간은 code, data, stack으로 구성되게 된다
- code : CPU에서 실행할 기계어 code
- data : 전역변수와 프로그램이 실행하는 자료구조
- stack : code에서 호출한 함수가 저장되며 return 할 때 데이터를 꺼내게 된다
- Virtual memory는 물리적 메모리에 올라가게 된다
| Address translation
- virtual memory, physical memory 주소는 모두 0번지부터 시작한다
- 메모리에 적재할 때 virtual memory 의 주소를 물리적 메모리에 맞게 변환해줘야 한다
- 이때 주소 변환을 해주는 하드웨어 장치를 사용하게 된다(논리적 메모리 주소-> 물리적 메모리 주소)
| Physical memory
- 가상 메모리를 물리적 메모리 공간에 올릴 때 필요한 부분만 올려놔 메모리 낭비를 줄이게 된다(virtual memroy 기법)
- 프로그램이 종료되게 되면 물리 메모리에서 쫓아내게 되고, 프로그램이 종료되기 전까지 가지고 있어야 하는 부분을 Swap Area에 저장하게 된다
- OS 커널은 물리적 메모리에 상주한다(OS 커널도 stack/data/code 형태로 이루어져있다)
| Swap Area
- 물리적 메모리의 공간이 한정적이기 때문에 주소 공간에서 당장 필요한 것은 물리적인 공간에 올려놓게 되고 그렇지 않은 경우에는 Disk Swap Area(메모리 연장 공간)에 내려놓게 된다
- 전원이 꺼지면 프로세스가 종료되고, 메모리 영역에 잇는 데이터도 사라지기 때문에 swap area에 있는 데이터도 사라지게 된다(휘발성) cf) File System(비휘발성)
| OS 커널 영역의 내용
커널 주소 공간은 code, data, stack의 구조로 되어있다.
code
- 시스템콜, 인터럽트 처리 코드
- 자원을 효율적으로 관리하기 위한 코드
- 사용자에게 편리를 줄 수 있는 서비스 코드
- 사용자 프로그램이 운영체제 커널의 코드를 요청할 수 있다(시스템 콜)
data
- 하드웨어를 관리하는 자료구조
- PCB(Process Control Block) : 프로세스를 관리하는 OS 자료구조
stack
- 운영체제는 함수 구조로 짜여져있기 때문에 stack 영역을 사용한다
| 프로그램의 실행
- user mode(프로그램이 CPU를 잡은 상태)에서 유저 정의 함수/Library 함수 실행
- 시스템 콜 이후에는 주소공간이 아닌 커널 주소 공간 안(커널 함수)에서 실행되게 된다(커널 모드의 CPU 동작)
- 이후 위 과정 계속 반복