목차
컴퓨터 시스템 구조
➳ CPU와 device controller는 기계어를 연산하는 기능을 가지고 있다.
➳ Memory는 CPU의 작업 공간이고, local buffer는 device controller의 작업 공간이다.
Interrupt line
Interrupt line에서는 다음 기계어를 실행하기 전, Interrupt가 들어와 있는지 확인한다.
Interrupt는 I/O 장치가 발생시킬 수 있다. 예를 들어, 사용자 프로그램 A가 디스크에서 어떤 파일을 읽어와야 한다면 CPU는 디스크 컨트롤러에게 파일을 읽어달라고 부탁한다. 파일을 읽는 동안 CPU는 운영체제로 갔다가 다른 프로그램으로 넘어간다. 디스크 컨트롤러는 파일 읽는 작업이 끝나면 CPU에게 알려주어야 하기 때문에 Interrupt를 건다. 따라서 CPU는 다음 기계어를 실행하기 전 Interrupt가 들어와 있는지 확인하고, 만약 Interrupt가 들어왔다면 CPU는 자동적으로 운영체제로 넘어간다. 즉, Mode bit이 0이 되고, 읽어온 파일을 사용자에게 넘겨주는 것과 같이 해당 Interrupt에 대응하는 일을 해준다.
Registers
CPU는 기계어를 연산하는데, Registers는 이 연산의 Input과 Output을 저장한다. 아주 빠르고 크기가 작다.
Registers 중 하나인 Program Counter (PC)는 다음 번에 실행할 기계어 메모리의 주소를 가리킨다.
Device Controller
➳ I/O device controller
• 해당 I/O 장치유형을 관리하는 일종의 작은 CPU이다.
• 제어 정보를 위해 control register, status register를 가진다.
• local buffer를 가진다. (일종의 data register)
➳ I/O는 실제 device와 local buffer 사이에서 일어난다.
➳ Device controller는 I/O가 끝났을 경우 interrupt로 CPU에 그 사실을 알린다.
• device driver (장치 구동기) : OS 코드 중 각 장치별 처리루틴 (CPU가 실행하는 코드) : software
• device controller (장치제어기) : 각 장치를 통제하는 일종의 작은 CPU : hardware
Mode bit
운영체제는 믿고 CPU를 맡길 수 있지만, 사용자 프로그램은 무조건 믿고 맡길 수는 없다. 악의적일 수도 있다는 문제점이 있기 때문이다. 하지만 일단 CPU가 사용자 프로그램으로 넘어가면 운영체제는 제어할 길이 없다. 따라서 CPU를 운영체제가 실행하는지, 사용자 프로그램이 실행하는지를 구분할 필요가 있다. 즉, 사용자 프로그램의 잘못된 수행으로 다른 프로그램 및 운영체제에 피해가 가지 않도록 하기 위한 보호 장치가 필요하다.
이는 Mode bit이 도와준다. Mode bit을 통해 하드웨어적으로 두 가지 모드의 operation을 지원한다.
1 사용자 모드 : 사용자 프로그램 수행
0 모니터 모드 : OS 코드 수행
➳ 보안을 해칠 수 있는 중요한 명령어는 모니터 모드에서만 수행 가능한 특권명령으로 규정한다.
• 만약 위험한 기계어인데, Mode bit이 0이 아니라면 자동적으로 CPU가 운영체제로 넘어간다.
• CPU가 기계어를 실행할 때 안전한 명령어만 실행하도록 보호해준다.
➳ Interrupt나 Exception 발생 시 하드웨어가 mode bit을 0으로 바꾼다.
➳ 사용자 프로그램에게 CPU를 넘기기 전에 mode bit을 1로 세팅한다.
🔅 모니터 모드 = 커널 모드, 시스템 모드
Timer
운영체제는 CPU를 넘겨주는 것은 할 수 있지만, 일단 CPU가 다른 프로그램에게 넘어가면 혼자서 다시 뺏어올 수는 없다. CPU의 독점을 막기 위해서는 부가적인 하드웨어가 필요하다. 즉, Timer가 필요하다. Timer는 일정 시간 간격으로 Interrupt를 발생시킨다. (= Timer Interrupt) 운영체제가 사용자 프로그램에게 CPU를 넘길 때에는 Timer에 시간을 세팅한 후 넘겨준다. 따라서 사용자 프로그램이 악의적으로 무한루프를 돌며 혼자 CPU를 독점하려고 해도 CPU의 제어권이 자동적으로 운영체제로 다시 넘어온다. 현대 운영체제가 CPU 스케줄링을 할 때에는 Timer의 도움을 받는다.
➳ 정해진 시간이 흐른 뒤 운영체제에게 제어권이 넘어가도록 Interrupt를 발생시킨다.
➳ Timer는 매 클럭 틱 때마다 1씩 감소한다.
➳ Timer 값이 0이 되면 Timer Interrupt가 발생한다.
➳ CPU를 특정 프로그램이 독점하는 것으로부터 보호한다.
🔅 time sharing을 구현하기 위해 널리 이용된다.
🔅 현재 시간을 계산하기 위해서도 사용한다.
Interrupt
현대 운영체제는 Interrupt에 의해 구동된다. Interrupt 당한 시점의 레지스터와 program counter를 save 한 후, CPU의 제어를 Interrupt 처리 루틴에 넘긴다. 넓은 의미의 인터럽트는 소프트웨어 인터럽트도 포함하지만, 특별히 소프트웨어 인터럽트는 Trap이라고 부른다.
🔅 Interrupt (하드웨어 인터럽트) : 하드웨어가 발생시킨 인터럽트
🔅 Trap (소프트웨어 인터럽트)
➳ Exception : 프로그램이 오류를 범한 경우
➳ System Call : 프로그램이 커널 함수를 호출하는 경우
System Call
I/O 장치에 접근하는 기계어는 전부 특권명령으로 규정된 기계어이다. 따라서 사용자 프로그램에게는 권한이 없고, 운영체제에게 요청을 해야만 한다. 이 역할은 시스템콜 (System Call)이 담당한다. System Call은 사용자 프로그램이 운영체제의 서비스를 받기 위해 커널 함수를 호출하는 것이다.
💡 인터럽트 관련 용어를 알아보자 !
✔ 인터럽트 벡터
해당 인터럽트의 처리 루틴 주소를 가지고 있다.
✔ 인터럽트 처리 루틴 (= Interrupt Service Routine, 인터럽트 핸들러)
해당 인터럽트를 처리하는 커널 함수이다.
동기식 입출력과 비동기식 입출력
두 경우 모두 I/O의 완료는 인터럽트로 알려준다.
동기식 입출력 (synchronous I/O)
➳ I/O 요청 후 입출력 작업이 완료된 후에야 제어가 사용자 프로그램에 넘어간다.
➳ 구현 방법 1
• I/O가 끝날 때까지 CPU를 낭비시킨다.
• 매시점 하나의 I/O만 일어날 수 있다.
➳ 구현 방법 2
• I/O가 완료될 때까지 해당 프로그램에게서 CPU를 빼앗는다.
• I/O 처리를 기다리는 줄에 그 프로그램을 줄 세운다.
• 다른 프로그램에게 CPU를 준다.
비동기식 입출력 (asynchronous I/O)
➳ I/O가 시작된 후 입출력 작업이 끝나기를 기다리지 않고 제어가 사용자 프로그램에 즉시 넘어간다.
DMA (Direct Memory Access)
➳ 빠른 입출력 장치를 메모리에 가까운 속도로 처리하기 위해 사용한다.
➳ CPU의 중재 없이 device controller가 buffer storage의 내용을 메모리에 block 단위로 직접 전송한다.
➳ 바이트 단위가 아니라 block단위로 Interrupt를 발생시킨다.
DMA controller
너무 빈번한 Interrupt는 CPU가 비효율적으로 사용된다.
따라서 메모리에 접근할 수 있는 장치인 DMA를 하나 더 둔 것이다.
저장장치 계층 구조
➳ Primary : CPU에서 직접 접근 가능 / 빠름 / 높은 비용 / 휘발성
➳ Secondary : I/O를 통해서 접근 가능 / 느림 / 낮은 비용 / 비휘발성
➳ Cashing : 더 빠른 스토리지 시스템에 정보를 복수해두고 쓴다. (재사용성)
프로그램의 실행 (메모리 load)
프로그램은 실행 파일 형태로 저장되어있다. 마우스를 클릭해 실행하면 해당 프로그램이 메모리에 올라가서 프로세스가 된다. 운영체제 kernel은 기본적으로 메모리에 올라가 있다.
각각의 프로그램들은 자신만의 메모리 주소 공간이 존재한다. 당장 필요한 부분은 물리적인 메모리에 올라가지만, 그렇지 않은 부분은 디스크의 Swap area에 있다. 코드와 같은 일부는 파일 시스템의 실행파일 형태로 존재하기도 한다.
Virtual memory와 Physical memory에서의 주소는 다르므로 주소 변환 (Address translation)이 필요하다.
Virtual memory에서 각 프로세스의 주소 공간에는 code, data, stack이 있다.
code : 실행파일의 코드가 올라온다. 실제 CPU에서 실행할 기계어라고 할 수 있다.
data : 전역 변수나 프로그램 시작부터 종료까지 남아있는 데이터를 보관하는 영역이다.
stack : 함수 안에 있는 지역변수와 같은 데이터를 보관하는 영역이다. 함수의 호출과 리턴에 관련된 정보를 쌓아 둔다.
운영체제 커널도 하나의 프로그램이기 때문에 함수의 구조로 되어있고, 커널 주소 공간 역시 code, data, stack으로 이루어져 있다.
커널 주소 공간의 내용
시스템 안에서 돌아가는 프로세스를 관리하려면 자료 구조가 필요하다. 이를 PCB (Process Controll Block)라고 부른다.
운영체제 stack은 조금 특이한 구조를 가지고 있다. 커널의 stack은 각 프로세스마다 별도로 두고 있다.
사용자 프로그램이 사용하는 함수
🔅 함수
➳ 사용자 정의 함수
• 자신의 프로그램에서 정의한 함수
➳ 라이브러리 함수
• 자신의 프로그램에서 정의하지 않고 갖다 쓴 함수
• 자신의 프로그램의 실행 파일에 포함되어 있다.
➳ 커널 함수
• 운영체제 프로그램의 함수
• 커널 함수의 호출 = System Call
프로그램의 실행
프로그램을 만드는 사람은 여러 함수를 가져와 쓴다. 프로그램이 진행되면서 'CPU의 제어권이 어떻게 바뀌는가?'를 보면 내가 만든 함수나 라이브러리 함수가 실행될 때에는 내 주소 공간에 있는 코드가 user mode에서 실행된다. 반면 System Call을 부르게 되면 CPU 제어권이 운영체제에게 넘어가 kernel mode에서 운영체제 주소 공간에 있는 코드가 실행된다. user mode는 Mode bit이 1, kernel mode는 Mode bit이 0인 상태이다.
Reference
'CS > OS' 카테고리의 다른 글
프로세스 동기화 (Process Synchronization) (0) | 2022.12.28 |
---|---|
CPU 스케줄링 (2) | 2022.12.26 |
프로세스의 생성과 종료 with System Call (0) | 2022.12.19 |
프로세스 (Process)와 스레드 (Thread) (2) | 2022.12.14 |
운영체제란 무엇인가 ? (0) | 2022.12.09 |