[운영체제] System Structure & Program Execution(1)
컴퓨터의 하드웨어적인 동작 원리
메모리: CPU의 작업 공간. 기계어를 실행.
CPU: 매 클럭 사이클마다 메모리에서 기계어(Instruction)를 읽어서 실행. 그리고 다음 기계어를 읽어서 처리.
레지스터: CPU 안에 존재하는 작은 저장공간. 메모리보다 속보가 빠름. I/O 디바이스에 직업 접근하지 않음. 오직 메모리와만 일함. 만약 CPU에서 디스크 등등에 접근할 필요가 생기면 device 컨트롤러에게 요청. 그럼 디스크에서 정보를 가져와서 local buffer에 저장. 이 사이에 CPU는 계속 자신의 작업 연산 처리. 하나의 프로그램을 끝내면 다음 프로그램으로 매우 빠르게 전환. 사용자 입장에서는 굉장히 interactive 하게 보임
그런데 for문, while문 등등으로 인해 무한루프에 빠지면 하나의 프로그램에서 CPU가 빠져나오지 못해서 다른 작업을 처리하지 못함. 이걸 방지하기 위한 게 timer. TIMER는 특정 프로그램이 CPU를 독점하는 걸 방지. 타이머를 설정하고 CPU에게 프로그램을 넘겨줌. 때문에 CPU가 작업을 하다가 세팅된 시간이 넘어가면 타이머가 Interrupt를 보내고 CPU는 이걸 확인. 그러면 CPU의 제어권이 프로그램에서 운영체제로 자동으로 넘어감. 운영체제는 다시 타이머를 설정하고 다음 프로그램에게 CPU를 넘겨줌.
메모리에서 프로그램이 동작하다가 I/O가 필요하면 자동으로 운영체제에 CPU를 넘겨줌. 사용자 프로그램은 직접 IO에 접근할 수 없기 때문. 오직 OS를 통해서만 IO에 접근 가능함. 그리고 CPU는 다른 프로그램에 넘어감. 그러다가 L/B에 D/C가 요청한 데이터가 들어오면 D/C가 CPU에 인터럽트를 보냄. 그럼 CPU가 인터럽트를 받고 제어권이 OS로 넘어감. OS는 제어권을 받고 인터럽트를 확인해서 입력된 값을 아까 요청한 프로그램에 카피해줌. 그리고 일단 인터럽트 당한 프로그램에 CPU를 다시 넘겨줌.
mode bit: CPU 제어권을 가지고 있는게 운영체제인지 사용자 프로그램인지 구분.
0이면 -> 모니터 모드, 커널 모드. 운영체제에서 CPU를 수행 중. 메모리 접근, IO 접근 모두 실행 가능
1이면 -> 사용자 프로그램이 CPU를 제어. 제한된 instruction만 가능. for 보안.
mode bit을 보고 인스트럭션 실행 여부 판단.
interrupt line: CPU는 항상 메모리의 인스터럭션만 실행. 하나를 처리하면 다음 기계어의 주소 값이 증가
각각의 I/O 기기마다 device controller 존재. device controller도 작업공간이 필요한데 이게 local buffer
Timer: 정해진 시간이 흐른 뒤 운영체제에게 제어권이 넘어가지 않게 인터럽트 발생
데이터를 저장하는 local buffer를 가짐.
제어 정보를 위한 register -> CPU가 일을 시킬 때 제어 정보를 위한 레지스터를 통해 전달.
ex. 모니터에 출력을 하라는 지시는 제어 레지스터를 통해 Device Controller. 출력할 정보는 local buffer에 저장
ex. 데이터 자체는 로컬 버퍼에, 저장하라는 명령은 제어 정보 레스터를 통해 IO d/c에게 전달
- 메모리 컨트롤러 역시 존재. 원칙적으로 메모리에는 cpu만 접근이 가능. 버퍼에 데이터가 쌓이면 CPU가 이걸 읽어서 자신의 작업 메모리에 복사를 함. CPU는 메모리와 로컬 버퍼 모두 접근 가능. 원칙적으로는 ㅇㅇ. 그런데 이렇게 하니까 CPU가 너무 인터럽트를 많이 받음. 그다지 효율적이지 않게 동작. 이를 해결하기 위해 DMA
- DMA(Direct Memory Access): 메모리는 CPU와 DMA 컨트롤러 모두 접근 가능. IO 디바이스들이 보내는 인터럽트를 DMA가 직접 로컬 버퍼에 저장된 내용을 복사해서 메모리에 전달. 그리고 작업이 끝나면 CPU에 인터럽트를 한 번만 걸어서 작업 완료를 보고. 이렇게 하면 CPU의 인터럽트 빈도가 줄어듬.
- memory controller: CPU와 DMA가 동시에 메모리에 접근하는 걸 조율하는 역할.
- Device Controller: 각 디바이스를 전담하는 작은 하드웨어 장치
- Device Driver: 소프트웨어를 의미. 운영체제에서 각 디바이스에 접근할 수 있게
결국 CPU의 숙명 -> 자신이 처리해야 할 인스트럭션의 메모리 주소를 레지스터 주소에서 가져오고, 그 인스트럭션만 실행. 그 인스트럭션 중 IO장치에 접근해야 하면 디바이스 드라이버를 통해 컨트롤러에 명령. device driver가 실제 어떤 데이터를 읽게 하는 코드는 아님. 그 코드는 device constroller가 받아서 실행. CPU는 메모리의 인스트럭션만 받음. 디바이스의 실행 매뉴얼은 디바이스 안의 펌웨어 저장.
전체적인 CPU 통제는 OS에서 진행.
운영체제를 통해서만 IO장치 접근 가능. mode bit 0. 운영체제에게 부탁하는 걸 시스템콜(System call). 커널 함수 호출이기 때문에 일반 함수 호출과는 다름. 트랩을 이용해서 인터럽트를 걸어서 실행
함수 호출, 예외 처리 등등 -> CPU가 순차적으로 실행되지 않고 인스트럭션의 메모리 주소로 점프를 함. 프로그램 내에서 함수 호출은 그냥 메모리 안에서 주소 이동. 하지만 시스템 콜은 단순히 메모리 주소를 바꾸는 문제에서 그치지 않음. IO를 위해서는 운영체제에 해당되는 주소로 넘어가야 됨. 근데 모드 빗 1에서는 이게 허용이 안 됨. 때문에 프로그램이 직접 인터럽트 라인을 만드는 인스트럭션을 실행. CPU는 메모리에서 인스트럭션을 하나 처리하고 인터럽션이 있는지 체크함. timer 혹은 io가 인터럽트를 거는 게 아니라, 프로그램이 직접 인터럽트를 걸 수 있고 CPU는 이 인터럽트를 받으면 mode bit이 0으로 바뀌고 CPU 운영권이 운영체제에게 넘어감. 그럼 운영체제가 이걸 확인하고 device controller에게 이걸 부탁. 인터럽트는 사용자 프로그램이 운영체제에게 요청하는 상황에서도 인터럽트 라인을 생성해서 사용 가능. 이걸 소프트웨어 인터럽트라고 부름
소프트웨어 인터럽트 = 트랩.
운영체제는 올바른 인터럽트인지 확인. IO가 끝나면 하드웨어 인터럽트가 CPU 혹은 DMA에 도착.
즉, IO를 위해선 두 종류의 인터럽트가 존재.
1) IO 요청을 위한 시스템 콜(소프트웨어 인터럽트) -> 기기에 일을 시킴
2) 일을 다 하면 하드웨어 인터럽트가 걸림(요청한 일이 완료되었다는 걸 전달). IO 컨트롤러가 전달.
* 타이머가 주는 것도 하드웨어 인터럽트.
인터럽트에 종류가 굉장히 많은데, 각각의 종류마다 운영체제가 해야 할 일이 다름. ex) 키보드는 버퍼를 저장하고, 타이머는 CPU를 뺏어서 다른 프로그램에 전달. 이 일들이 운영체제 코드에 저장이 되어 있음. 이렇게 처리하는 코드를 인터럽트 처리 루틴이라고 부름. 이러한 루틴 주소를 벡터가 저장. 어느 주소에 있는 함수를 처리해야 하는지 인터럽트 벡터가 테이블에 저장