컴퓨터 시스템 구조
🦕 시스템 : 범용 버스를 통해 데이터를 교환하는 여러 장치로 구성된 범용 컴퓨터
목차! 아래 키워드만 보고 차근차근 설명할 수 있으면 이 부분 공부는 성공일듯!!!
- CPU
- register
- mode bit
- interrupt line
- Memory
- Timer
- I/O
- Device Controller
- Local Buffer
- Interrupt / System Call
- DMA Controller
CPU
- 메모리에서 instruction 읽어서 수행하는 일만 한다.
- register : CPU의 연산 결과를 저장하는 작고 빠른 메모리 같은 것.
- Program Counter : 메모리 주소를 가리키는 register
- mode bit : 현재 진행중인 프로그램이 OS 인지 사용자 프로그램인지를 구분하는 보호장치. (OS 면 모든 instruction 을 실행할 수 있게 권한을 더 줄려고)
- interrupt line : interrupt 신호를 처리하기 위한 하드웨어.
- Memory : CPU 의 작업 공간. OS Kernel 이 항상 상주하고 있고, 실행중인 사용자 프로그램이 올라온다.
🦕 메모리 (DRAM)
- CPU 에서 실행할 명령어들을 저장하는 공간.
- 휘발성!
- 명령어
- load : 메모리에서 CPU register 로 실행할 명령어를 이동 (적재)
- store : CPU register 에서 저장할 값을 메모리로 이동 (저장)
- 명시적으로 명령어를 날리지 않아도, 프로그램을 이전 상태부터 시작하기 위해서 프로그램 카운터에 저장된 값을 CPU 가 자동으로 적재하기도 한다.
🦕 EEPROM
- 컴퓨터가 켜졌을 때, 가장 먼저 실행되는 부트스트랩 프로그램을 유지 하기 위해 사용되는 읽기 전용 메모리 (DRAM 은 휘발성이라 유지가 안됨.)
- 펌웨어 같은 쓰기 명령은 많이 안들어가고 읽기 명령만 들어가는 것도 사용한다.
Mode Bit
- 사용자 프로그램의 잘못된 수행으로 인해서 다른 프로그램이나 OS 에 피해가 가지 않도록 하는 보호 장치
- 1 : 사용자 모드 - 일반 명령만 수행한다.
- 0 : 커널 모드 (== 모니터 모드, 시스템 모드) - 모든 명령을 수행할 수 있다. (특권 명령)
- Interrupt / Exception 가 발생하면 0 으로 바꿔서 OS 에 CPU 넘기고,
- Exception : 사용자 프로그램이 권한이 없는 명령을 실행한 것.
- 사용자 프로그램에 넘기기 전에 1로 세팅.
Interrupt Line
I/O 작업은 오래걸리기 때문에 작업에 들어갈 때 CPU 제어권을 다른 프로그램에 넘긴다. 그래서 I/O 작업이 끝나면 Device Controller 가 interrupt 를 건다. (Interrupt Line 을 세팅한다.) 그러면 OS 에 CPU 가 넘어가서 I/O 를 요청했던 프로그램의 메모리 공간에 I/O 작업에서 가져온 값을 복사해준다던가 하는 작업을 하고, 다시 원래 작업하던 프로그램에 CPU 를 넘긴다.
한마디로 I/O 작업이 끝났다는 신호
- CPU 는 instruction 을 한번 수행하고, Interrupt Line 을 확인함.
Timer
- CPU 의 독점을 막기 위해서 일정 간격으로 interrupt 를 발생시키는 하드웨어.
- 사용자 프로그램에 CPU 가 넘어가면 OS 가 CPU 를 뺏을 수가 없다. 무한루프 프로그램 같은 경우 CPU 를 독점할 수 있음.
- 매 클럭마다 1씩 감소해서 0이 되면 인터럽트를 발생시킴.
- Time Sharing 을 구현하기 위해서 널리 사용 됨.
I/O Device
- Input, Ouput 키보드 마우스 스피커 모니터 디스크 ...
- Device Controller : I/O Device 를 제어하는 작은 CPU.
- Local Buffer : I/O Device 를 제어하는 메모리 같은 것!
- I/O 는 실제 Device Controller 와 Local Buffer 사이에서 일어나게 된다.
🦕 Interrupt
Device Controller
- I/O 작업은 매우 오래 걸리기 때문에, CPU 가 제어하지 않음.
CPU 는 정말 메모리에서 기계어 읽어서 수행만 함.
- I/O 작업을 요청받으면 I/O 작업을 Device Controller 가 진행하고,
- 끝나면 Device Controller 가 interrupt 검.
- CPU 가 Local Buffer 에서 데이터 읽어감. -> Interrupt 가 너무 많이 걸림 -> DMA Controller
- control register, status register 를 가진다.
- device driver : CPU 가 실행하는 각 I/O 기기를 다루는 코드를 가지고 있는 SW
- I/O 기기에서 기계어 수행은 펌웨어가 한다.
Local Buffer
- 실제 데이터를 저장하는 곳.
- 메모리에 있는 데이터를 갖고 오기도 하고, 여기 있는 데이터를 메모리에서 가져가기도 함.
DMA Controller
- Direct Memory Access : I/O 장치를 메모리에 가까운 속도로 처리하기 위해서 사용. 메모리에 접근이 가능하다. (원래는 CPU 만 가능)
- Device Controller 가 interrupt 를 걸면 CPU 가 Local Buffer 에서 데이터를 읽어가는데,
- Interrupt 가 너무 많이 걸림. 계속 CPU 가 왔다갔다 해야해서 낭비.
- Local Buffer 에 일정 분량이 쌓이면 DMA Controller 가 🦕 CPU 개입 없이 블럭 단위로 한번에 메모리에 copy 를 하고 interrupt 를 걸어준다.
- Memory Controller 는 DMA 와 CPU 중 어느 것이 먼저 메모리에 접근하게 할지 같은 것을 결정해준다.
I/O 의 수행
- I/O 명령은 특권 명령이라 OS 를 통해서만 접근할 수 있다.
- 그럼 어떻게..? -> 시스템 콜 (trap 을 이용한 interrupt)
- OS 가 확인해보고 올바른 요청인 경우 I/O 요청을 수행한다.
Interrupt ⭐️
- 인터럽트 당한 시점의 레지스터와 Program Counter 를 저장하고, CPU 제어권을 인터럽트 처리 루틴(OS 의 I/O 처리 함수)에 넘긴다.
- HW Interrupt == Interrupt
- Timer
- Device Controller / DMA Controller
- Sw Interrupt == Trap
- Exception : 프로그램이 오류를 범한 경우
- 0으로 나눈다거나 하는 코드를 실행하면 CPU 가 그 코드를 실행할 수가 없기 때문에 interrupt.
- 강제 종료 등의 처리를 하게 됨.
- System Call : 사용자 프로그램이 커널 함수를 호출하는 경우
- 현대의 운영체제는 인터럽트에 의해 구동된다. == I/O 가 들어올 때만 CPU 를 잡음.
- 인트럽트 벡터 : 해당 인터럽트 처리 루틴 주소를 가지고 있음. (테이블 같은 것)
- 인트럽트 처리 루틴 : 해당 인터럽트를 처리하는 커널 함수.
🦕 Interrupt
- 장치 드라이버 : OS 에 있는 여러 장치를 제어하기 위한 부분.
- 장치 드라이버가 장치 컨트롤러(Device Controller) 의 레지스터에 값을 쓴다.
- 장치 드라이버가 레지스터를 읽어서 어떤 작업을 수행할지 결정한다.
- 장치 컨트롤러가 로컬 버퍼로 데이터를 전송한다.
- 전송이 완료되면 장치 컨트롤러가 장치 드라이버에 알려줌. -> 그래서 이 알려주는걸 어떻게?? -> Interrupt
- 장치 드라이버는 요청이 읽기 요청이면 데이터나 데이터에 대한 포인터를 반환하고, 쓰기 요청이면 OS 의 다른 부분에 CPU 제어권을 넘긴다.
- 장치 컨트롤러가 인터럽트 요청 라인에 신호를 보내서 인터럽트를 raise 시키고,
- CPU는 인터럽트를 catch 하고,
- 인터럽트 핸들러로 dispatch 하고,
- 핸들러는 장치를 서비스해서 인터럽트를 지운다. clear
🦕 Interrupt
- 하드웨어가 발생시킨다. (시스템 버스를 통해 CPU에 신호를 보냄)
- 인터럽트 되면, 인터럽트 처리 루틴이 실행된다.
- 그런데, 인터럽트는 아주 빈번하게 일어나기 때문에, 속도를 위해서 인터럽트 처리 루틴의 주소를 가진 테이블을 메모리에 올려놓고 사용한다. 인터럽트 벡터는 그 테이블의 인덱스 같은 것!
🦕 Interrupt 구현
- CPU 는 하나의 명령어를 실행할 때마다 인터럽트 요청 라인을 읽는 것이 기본인데,
현대의 OS 의 경우
1. 중요한 처리 중에 인터럽트를 연기할 수 있어야 함.
2. 장치에 맞는 인터럽트 처리 핸들러를 효율적으로 부를 수 있어야 함.
3. 인터럽트의 우선순위를 구분하고 우선순위가 높은 인터럽트를 먼저 처리할 수 있어야 함.
위의 3가지를 제공하기 위해,
- 마스킹 불가능 인터럽트 라인 / 마스킹 가능 인터럽트 라인 사용.
- 마스킹 불가능 인터럽트 라인 : 복구 불가능한 메모리 오류 같은 중요한 인터럽트를 보냄.
- 마스킹 가능 인터럽트 라인 : 인터럽트 되면 안되는 중요한 작업을 실행하기 전에 꺼버리기 때문에, 중요한 작업 수행 중에는 실행되지 않음.
- Device Controller 가 보내는 인터럽트의 경우 여기에 속함!
- 인터럽트 체인
- 인터럽트 벡터 갯수보다 실제 인터럽트 처리 루틴, 핸들러의 갯수가 더 많기 때문에
- 인터럽트 벡터의 각 요소가 인터럽트 핸들러 리스트의 헤드를 가리키고,
- 인터럽트 벡터에 맞는 리스트를 찾아가서 요청을 처리할 수 있는 핸들러가 발견될 때 까지 알맞는 리스트의 모든 핸들러를 순서대로 호출해보는 형태로 작동한다.
을 사용한다.
System Call ⭐️
- 사용자 프로그램 내에서 메모리 주소를 바꾸는 것은 쉽다.
- 하지만 사용자 프로그램은 I/O 같은 작업이 필요할 때, OS 커널 의 (I/O 작업과 관련된) 메모리 주소에 접근할 수가 없음. (because Mode bit == 1)
- 그런 경우, 사용자 프로그램이 OS 에게 무언가를 요청하기 위해 interrupt 를 걸어서 OS 의 함수를 호출할 수가 있다. -> 이것이 바로 시스템 콜.
-> I/O 요청을 할 때는 System Call (SW Interrupt) 를 하고, 끝나면 HW Interrupt
sync / async I/O
- 동기식 입출력 (일반적)
- I/O 요청 후에 작업이 완료가 되어야 CPU 제어가 사용자 프로그램(다른 일)에 넘어감. (I/O 장치까지 가서 뭘 작업했는지 보고 다음 작업 실행.)
- 그치만 하나의 I/O 가 완료될 때 까지 계속 기다리는건 CPU, I/O 장치 낭비이므로,
- 해당 프로그램에서 CPU 를 빼앗고,
- I/O 처리 큐에 넣은 뒤,
- 다른 프로그램에게 CPU 를 주는 방식으로 구현
- 끝나면 디바이스 컨트롤러가 인터럽트
- 비동기식 입출력
- I/O 요청 후에 작업이 끝나기를 기다리지 않고 CPU 제어가 사용자 프로그램(다른 일)에 넘어감.
- I/O 와 무관한 일을 하거나
- write 작업 : file 을 쓰거나 모니터에 띄운다라면 이렇게 해도 무방한 경우가 있음.
- 둘 다 I/O 가 끝나면 inetrrupt
I/O 명령어 (방법)
- I/O 를 수행하는 Special Instruction (일반적)
- CPU 에 메모리에 접근하는 instruction 과 I/O 를 접근하는 instrution 이 나누어져 있음.
- Memory Mapped I/O
- I/O 디바이스에 메모리 주소를 줘서 메모리로 접근.
실제로 했던 필기
참고 / 출처
반효경 교수님의 2014 운영체제 2. System Structure & Program Execution 강의를 듣고 포스팅하고,
공룡책을 읽고 추가 정리합니다.
사진 출처는 강의 자료.