하드웨어가 어떻게 돌아가는지, 프로그램이 이 하드웨어 위에서 어떻게 돌아가는지 설명하는 챕터.
하드웨어에 중점을 두고 설명하는 것이다
컴퓨터의 구조
전문적인 입장에서 컴퓨터를 말하면 cpu, memory.
외부 I/O 디바이스
CPU
- cpu가 하는 일 : 기계어를 실행시키는 것
- cpu는 매 클럭마다, 메모리에서 기계어를 읽어들여서(fetch) 실행한다(execute). 평생 하는 일이 이것 하나 뿐이다.
- cpu가 접근 가능한 메모리
- 메인 메모리
- 하드웨어에 붙어있는 로컬 버퍼
- 레지스터 존재
- 메모리보다 더 빠르면서, 정보를 저장할 수 있는 작은 공간들
- mode bit 존재
- 현재 사용자모드인지, 커널모드인지 알려줌
- 커널모드 (mode bit == 0)
- 운영체제가 cpu를 가지고 있는 것
- 사용자모드( mode bit == 1)
- 사용자 프로그램이 cpu를 가지고 있는 것
- 운영체제가 cpu를 사용자 프로그램에게 넘겨줄 때, 모드비트를 1로 바꾸어서 넘겨준다.
- memory 관련 instruction만 수행 가능하고, i/o 관련 instruction은 수행 불가능
- Interrupt line 존재(붙어있음)
- cpu는 memory하고만 일을 한다(무조건). (하나 추가적인 작업은, 인터럽트 라인을 확인해서 인터럽트를 받아들인다)
- 그럼 다음과 같은 예시를 생각해보자
- c언어로 작성한 프로그램이 메모리에 올라와있고, 해당 프로그램을 실행시키는 중이다. cpu는 해당 프로그램의 명령어를 가져오고, 해석하고, 실행한다. 계속 그 작업만 반복하는 것이다
- 내가 작성한 프로그램에서 printf나, scanf와 같은 명령어가 있었다. 그럼 cpu는 이런 명령은 어떻게 처리하는 것인가??
- 이럴 땐, 디바이스 컨트롤러한테 특정 어딘가에서 값을 읽어오라고 일을 시킨다
- 그리고, 디바이스 컨트롤러가 디바이스에게 값을 읽어오라고 일을 시킨다.
- 디바이스는 , 수행한 결과를 로컬 버퍼에 담아둔다
- cpu가 디스크 컨트롤러에게 일을 시키고, 자신은 다시 memory에서 명령어를 가져와 실행하는 작업을 계속 진행한다!(cpu가 쉬는 것은 낭비이므로)
- 이때, I/O 작업을 요청한 사용자 프로그램에게 cpu를 주는 것이 아니다. I/O 작업으로부터의 결과가 안들어왔으니, 더 이상 작업 불가이기 때문이다.
- 다른 사용자 프로그램 중, cpu만 있으면 실행될 수 있는 사용자 프로그램에게 cpu를 주게 된다.
- 그런데 i/o 디바이스가 인터럽트를 보냈을 때 어떻게 알 수 있느냐. 바로 Interrupt line을 통해 아는 것이다
타이머
- 특정 프로그램이 cpu를 독점하는 것을 막도록 하기 위함
- 정해진 시간이 흐른 뒤, cpu가 사용자 프로그램에서 운영체제로 넘어가게 하는 것
- 예시)
- 사용자 프로그램의 코드가, 무한 루프를 도는 코드라면? -> cpu를 계속 사용하게 된다
- 타이머가 인터럽트 라인에 인터럽트를 걸어주면, cpu는 인터럽트를 받아들이게 된다
메모리
- cpu의 작업공간
I/O 디바이스
- 디바이스 컨트롤러가 존재
- 각 디바이스마다, 작은 cpu와 같은 것이 달려있다.
- 헤드를 어떻게 움직일지와 같은 디바이스를 조작하는 것은 이 부분이 담당한다
- 로컬 버퍼 존재 (= 디바이스 컨트롤러의 작업 공간이 존재 - cpu가 작업공간으로 memory를 갖고 있듯이)
운영체제 (메모리에 항상 상주하는 프로그램)
- 인터럽트가 들어오면, 기본적으로 cpu 제어권이 운영체제에게 넘어간다.
- 인터럽트의 종류
- 하드웨어가 어떤 작업을 완료하고 그 결과를 로컬 버퍼에 담았다. 그리고, 디바이스 컨트롤러가 해당 작업이 끝났음을 cpu에게 알려주는 것
- 인터럽트의 종류
DMA controller
- 원칙적으로는, CPU만 메모리에 접근 가능하다.
- 하지만, 효율을 위해 추가된 DMA 또한 메모리(와 로컬 버퍼)에 접근 가능하도록 하였다!!
- 역할
- I/O의 결과가 끝나서 인터럽트를 걸면, cpu가 로컬 버퍼에서 값을 읽어서 메모리에 존재하는 사용자 프로그램에 값을 복사하는 과정을 거친다.
- 이 과정의 단점이, 하드웨어로부터의 인터럽트가 많아지면 cpu가 너무 방해를 받게된다..
- 그래서 하드웨어로부터의 인터럽트를 DMA가 받아서, 로컬 버퍼에서 값을 읽어서 메모리에 존재하는 사용자 프로그램에 값을 복사하는 과정을 대신 진행하는 것이다!
- 그 과정이 끝나면 DMA가 CPU에게 인터럽트를 한번만 걸어서 "저 로컬 버퍼에서 읽어서 메모리로 복붙까지 다 했어요" 라는 사실만 알려주면 된다.
Device Controller
- I/O 장치를 관리하는 일종의 작은 cpu
- device driver란?
- os코드 중, 각 장치별 처리 루틴을 정해놓은 소프트웨어
- I/O에 접근하기 위해 cpu가 실행하는 어떤 코드부분이다.
I/O의 수행
- 모든 입출력 명령은 특권명령어
- 그럼, 사용자 프로그램이 I/O를 하고 싶을 땐, 어떻게 하는가???
- 시스템 콜 사용
- 운영체제의 함수(코드)를 호출하는 것
- 근데, 운영체제의 함수를 호출하는 것은 직접 해당 함수의 주소로 넘어가는 것이 불가능하다
- 왜냐하면, 모드비트가 1인 상태에서는 운영체제의 코드로 넘어갈 수가 없기 때문이다!!
- 그래서, 프로그램이 직접 인터럽트를 걸 수 있는 방법(소프트웨어적으로)을 고안해냈다. = 소프트웨어 인터럽트 = 트랩
- 인터럽트를 걸면, 모드비트가 0으로 바뀌고, cpu제어권이 os로 넘어가게 된다!
- 시스템 콜 사용
- I/O가 다 끝났을 때는?
- 디스크 컨트롤러가 cpu에게 작업이 끝났다고 하드웨어 인터럽트를 걸어준다
- 그럼 여기서 문제. I/O 과정에서 일어나는 인터럽트는 무슨 인터럽트인가?
- 소프트웨어 인터럽트, 하드웨어 인터럽트 둘 다 일어난다.
인터럽트
- 좁은 의미 : 하드웨어 인터럽트
- 넓은 의미 : 소프트웨어 인터럽트(=트랩)까지 포함
- "현대의 운영체제는 인터럽트에 의해 구동된다"
- 사용자 프로그램이 cpu를 사용하고 있고, 인터럽트가 걸릴 때만 운영체제가 cpu를 사용하게 된다는 말이다!
- 인터럽트 처리 루틴, 인터럽트 벡터
- 인터럽트의 종류가 여러가지가 있고(키보드 인터럽트, 타이머 인터럽트 등), 각 종류마다 해야할 일이 다르다.
- 즉, 각 인터럽트마다 처리해야 할 코드가 정의되어있다. 이 코드가 인터럽트 처리 루틴이다.
- 인터럽트가 발생할 때마다, 각 인터럽트마다 어디에 있는 함수를 호출해야 하는지, 해당 함수들의 주소를 정의해놓은 테이블 같은 것을 인터럽트 벡터라고 한다.