티스토리 뷰

CS/OS

3. 들어가기 전에 ③

Sueaty 2020. 1. 9. 05:15

이 글은 본격적으로 운영체제에 대해 다루기 이전에 미리 상식적으로 알면 좋을 것 같은 내용들을 다루겠습니다. OS? Oh Yes! 서적 기반, 숙명여대 김주균 교수님 강의, 위키피디아 등을 정리했습니다. 공부한 것을 정리하는 형식으로 작성되었으므로 오류가 있을 수 있습니다. 오류 발견시 댓글로 꼭 말씀해주세요! 시작해볼까요?

시작 전 (잡)여담

마지막 '들어가기 전에'입니다. 이번에 다룰 내용들은 컴퓨터 구조 수업을 들어봤다면 한 번씩은 더 심도있게 다뤄봤을 내용입니다. 저는 컴퓨터 구조를 수강할 당시 너무너무너무너무 이 수업이 싫어 정말 재수강만 면하자... 라는 생각으로 공부했던 과목입니다. 그런데 운영체제를 공부하다보니 컴퓨터 구조와 너무 밀접한 관계를 가지고 있었고, 운영체제를 너무 재미있게 공부(...?)하고 있어서 만약 다시 컴퓨터구조 수업을 듣게 된다면 A+을 목표로 할 수 있지 않을까...(라는 말도 안되는 소리를 하고 있죠?)

Booting (부팅)

역대 Windows 부팅 화면이랑 소리라는데 정말 소리들이 화려해요ㅋㅋ

부팅은 비전공자도(컴퓨터랑 안친한 제 엄마도 아세요) 무엇인지 알겠지만, 컴퓨터 내부에서는 어떻게 돌아가는지는 모르시는 분들이 많을 것 같습니다. 전원이 꺼져 있을 때 운영체제는 전부 디스크에 저장이 되어 있다가 전원 버튼을 누르면 커널이 메모리에 올라가 실행하면서 장치들을 준비시키고 각종 레지스터 값을 초기화하는데 이것을 부팅이라고 합니다. 그런데 커널이 디스크에 어디에 있는지 어떻게 알까요? ROM에 위치한 부트 프로그램 또는 부츠트랩로더가 도움을 줍니다. 우리가 쓰는 PC의 경우 ROM에 있는 부츠트랩 로더가 디스크에 있는 부트 프로그램을 메모리에 올려 실행시키면 이 부트 프로그램이 커널을 메모리로 올려 실행을 시켜 줍니다. 그러나 일반적인 경우 부츠트랩 로더와 부트 프로그램이 하나로 합쳐져 ROM에 구성되어 같은 역할을 하게 됩니다.

Register (레지스터)

CPU는 다양한 종류의 레지스터를 가지고 있는데 메모리 보다 빠른 기억 장치입니다. 레지스터 종류를 좀 나열해보면 프로그램에서 사용하는 데이터 레지스터, 주소 레지스터, 조건 코드 레지스터 등이 있고, CPU의 연산을 제어하기 위해 사용되는 MBR, MAR, IR, PC 등이 있습니다. 각 레지스터 어떤 역할을 하는지는 컴퓨터 구조 책을 참고하시면 좋을 것 같습니다. 추가로  PSW(Program Status Word, 프로그램 상태 워드)는 인터럽트 가능/불가능 표시 비트, 현재 실행 모드를 나타내는 비트 등을 포함합니다.

Instruction Cycle (명령어 주기)

명령어가 처리 되는 과정을 나타내는 instruction cycle이 위 그림에 나타나있습니다. 명령어의 처리는 크게 Fetch와 Execute가 반복되는 과정이라서 fetch-execute cycle이라고 부르기도 합니다. Fetch는 메모리에 있는 명령어를 읽고 레지스터로 가져오는 과정이고, Execute는 실제 실행시키는 과정인데 이 때 위에서 언급한 다양한 레지스터들이 동원됩니다.

Interrupt (인터럽트)

운영체제가 자원(하드웨어 자원을 뜻함. ex. devices, peripherals)을 효율적으로 관리하기 위해서는 현재 자원들의 상황을 파악해야 합니다. 자원의 현황을 파악하는 방법은 두 가지가 있는데 하나는 Polling(폴링)이고 다른 하나는 Interrupt(인터럽트)입니다. 소제목이 인터럽트인 것을 보니 인터럽트가 더 중요하겠죠? 폴링은 거의 쓰지 않는 방법이니 간단하게만 집고 넘어가도록 하겠습니다.

 

 [ 폴링 ] 

CPU가 일정한 시간 간격을 두고 각 자원들의 상태를 주기적으로 확인하는 방법입니다. 이렇게 보면 될 것 같아요. 학교에서 운체를 수강하는데 전체 학생 수가 10명이고, 이 교수님께서는 소단원이 끝날 때 마다 질문을 받는다고 합시다. 그런데 모든 학생들에게 확인하고 싶으신 나머지 이 10명 모두에게 "질문 있니?"를 물어보시는거죠. 그러면 이때 CPU는 교수님, 10명의 학생들은 자원, 소단원이 끝나는데 걸리는 시간은 주기가 됩니다. 이 때의 문제점은 1) 소단원이 끝날 때마다 질문을 받는게 적절할지 대단원이 끝날 때마다 질문을 받는게 적절할지를 정해야 한다는 것이고 2) 학생이 수업 중간에 질문이 생기면 한 주기(소/대단원)이 끝날 때 까지 기다려야 한다는 것이고 3) 질문이 없는데도 교수님은 질문의 유무 여부를 묻는데 시간을 써야 한다는 것입니다.

 

 [ 인터럽트란 ] 

반면 인터럽트는 각 자원들이 능동적으로 자신의 상태 변화를 CPU에게 알리는 것입니다. 즉, 학생이 질문이 생기면 바로바로 질문을 하는 방식입니다. 인터럽트는 크게 하드웨어 인터럽트Trap(트랩, 소프트웨어 인터럽트)으로 나눌 수 있습니다. 트랩은 CPU가 자신에게 인터럽트를 해야할 때 발생되는 것입니다. 가령 0으로 나누는 오류 또는 다른 사용자 주소를 참조할 때, 그리고 이전에 나온 시스템 콜이 트랩이 발생되는 예시입니다.

 

하드웨어 인터럽트가 발생하면 현재 진행 중인 명령어 실행을 마친 후 처리가 됩니다. 반면 트랩은 종류에 따라 갈리는데, 오류로 인한 트랩은 프로그램의 즉각 종료를 야기하고, 시스템 콜의 경우 입출력 완료를 먼저 시킨 후 실행 중인 명령어가 완료되고 다음 실행문으로 넘어가게 됩니다.

 

 [ 인터럽트 처리 루틴 ] 

현재(인터럽트 발생 전) CPU와 메모리의 내부가 아래 그림 (A)와 같이 생겼다고 합시다. CPU 내부를 먼저 보게 되면 PC값이 N+1이므로 현재 실행되고 있는 명령어의 주소가 N임을 알 수 있습니다.(PC는 다음 실행 될 명령어의 주소값을 가지기 때문.) 범용 레지스터에 있는 값들은 명령어를 처리하면서 발생 된 값들입니다. 인터럽트가 발생하지 않은 현재는 스택 포인터가 빈 값이어야 합니다.

 

이제 인터럽트가 들어오면 현재 실행되던 명령어를 완료시키고 인터럽트 신호를 확인한 후 인터럽트 처리 루틴을 실행시키게 됩니다. 그러나 인터럽트 처리 후 다시 다음 명령어로 넘어가야 하므로 현재 실행중인 정보(PSW, PC 값, 레지스터 값 등)를 시스탬 스택에 저장합니다. 이제 본격적으로 인터럽트를 시작하기 위해 PC에 인터럽트 처리 루틴의 시작주소(그림에서 Y)를 넣습니다. 인터럽트 처리 루틴이 제일 먼저 하는 일은 CPU의 레지스터 값들과 기존에 있던 PC값(인터럽트 처리 이후 실행할 주소)을 저장합니다. 이렇게 저장하는 과정에서 CPU의 스택 포인터는 T, T-1, T-2 ... T-5(그림에서 저장할 정보가 5개이므로)로 바뀌게 됩니다.

(A)

인터럽트 처리가 끝난 직후의 상태가 그림(B)에 나타나 있습니다. 주목해야 할 점은 인터럽트 처리 루틴이 끝나고 return을 해주는 곳의 주소가 Y+L인데 CPU의 PC에 Y + L + 1이 들어가 있다는 것입니다. 다음 주소를 저장하는 PC의 입장에서는 당연한 말이지만, Y+L+1은 더 이상 인터럽트와는 상관이 없는 주소라는 것을 알고 제어 스택에 있는 정보를 다시 재저장(restore)한 후 자연스럽게 프로그램의 실행을 이어나갑니다. 물론 스택 포인터 값은 T로 조정이 됩니다.

(B)

 [ 중첩된 인터럽트 처리 ] 

중첩된 인터럽트란 하나의 인터럽트를 처리 하는 도중에 다른 인터럽트가 걸려오는 것을 뜻합니다. 이를 처리하는 방식은 크게 두 가지로 나눠 볼 수 있는데 하나는 순차 처리이고 다른 하나는 중첩 처리입니다. 순차처리는 말 그대로 중간에 들어온 인터럽트는 현재 처리하고 있던 인터럽트 부터 끝내고 이어서 처리 해주는 것을 뜻합니다. 중첩 처리는 현재 처리 중이던 인터럽트를 잠시 접고 다른 인터럽트를 처리할 수 있는 것을 뜻하는데 항상 접는 것이 아니라 후에 들어오는 인터럽트의 우선순위에 따라 접던지, 처리하던 것 부터 끝내고 하던지 달라질 수 있습니다.

 

 [ Context Switching (문맥교환) ] 

여기서 context란 interrupt 발생 시 저장해야할 정보라고 생각하면 쉬울 것 같습니다. 현재까지 하던 일을 멈추고 다른 일을 해야할 때 그 일을 그 상태 그대로 가까운 곳에 두었다가 끝나면 다시 가져오는 것이 문맥 교환입니다. 문맥은 상태 정보를 포함한 처리기 레지스터들의 값이 되겠습니다. 후에 나오는 PCB(Process Control Block)의 전부 또는 일부가 문맥에 해당된다고 보면 됩니다.

 

Storage Hierarchy (기억 장치의 계층적 구조)

컴퓨터 시스템이 사용하는 다양한 저장 장치들은 속도(접근 시간), 용량, 그리고 가격(비트 당 단가)에 따라 분류가 가능합니다. 속도가 빠르면 가격이 비싸고, 용량이 크면 속도는 느리지만 가격이 싸다는 장단점이 있습니다. 마음 같아서는 용량도 크고, 속도도 빠르고, 가격도 쌌으면 좋겠지만 이는 불가능하므로 여러 종류의 기억 장치들을 용도에 맞게 적절히 계층적으로 구성하게 된 것입니다. 아래 그림에도 나와 있듯이 상위계층에 있을 수록 속도가 빠르지만 가격이 비싸고, 하위 계층으로 갈 수록 용량이 커집니다.(제일 끝에 있는 Magnetic tapes(자기테이프)는 요즘 거의 안쓰죠.)

 

컴퓨터 성능이 좋아지려면 CPU가 처리할 명령어 또는 데이터가 상위계층에 있을 수록 좋다는 것입니다. 프로그램이 CPU에 의해 실행되려면 main memory에 적재되어 있어야 하는데 이때 일부분이 캐시로, 또 그 중에서 실행 될 명령어는 register로 적재됩니다. 계층구조의 설계로 인해 데이터나 명령어가 계층을 드나드는데 드는 부담이 분명 있지만 상위 계층로 올라왔을 때 얻는 처리 시간의 단축이 그 부담을 보상하기 때문에 대부분의 시스템은 이렇게 구성되어있습니다.

 

기억 장치의 계층적 구조

I/O  방식

각각의 입출력 장치에는 controller가 있고 여기에는 CPU와 입출력할 데이터를 저장하는 buffer가 존재합니다. 이때 버퍼는, 데이터의 이동 전 데이터를 버퍼의 크기만큼 채우고 CPU에게 인터럽트를 걸면 CPU가 버퍼의 내용을 옮기는 것입니다. 가령 디스크로부터 10개의 워드를 메모리로 읽어와야 하는 상황이 발생했다고 합시다. 만약 이 버퍼의 크기가 1 워드라면  총 10번의 인터럽트가 동원되어야 하나의 입력이 완료가 됩니다. 

 

입출력을 위해 시스템이 사용하는 방식은 CPU의 개입 정도에 따라 3가지 정도로 분류 할 수 있습니다.

 [ Programmed I/O ] (프로그램에 의한 입출력) 

CPU는 입력을 지시한 후 버퍼가 채워졌는지를 계속해서 확인하도록 하는 방식인데 결론부터 말하자면 더 이상 잘 쓰지 않는 방식입니다. 물론 CPU가 계속 확인을 해주니 버퍼가 인터럽트를 하지 않아도 되지만, CPU는 전체 입출력이 완료될 때 까지 다른 작업을 하지 못해 낭비되버리기 때문입니다.

 

 [ Interrupt-driven I/O ] (인터럽트에 의한 입출력) 

CPU는 입력을 지시한 후 다른 작업을 하다가 버퍼가 다 채워져서 인터럽트가 걸려서 입출력을 완료하는 방식입니다. 물론 위의 예시가 이 인터럽트에 의한 입출력 방식을 쓰고 있는 예시인 셈입니다.

 

[ Direct Memory Access ] (DMA, 메모리에 직접 접근하는 입출력) 

만약 버퍼의 크기가 크다면 인터럽트를 거는 횟수도 줄어들 것입니다. 이렇게 인터럽트 횟수를 줄이고자 하는 것이 DMA입니다. DMA는 입출력 작업을 CPU 대신 할 Channel(채널)이라는 위성 프로세서를 사용합니다. CPU는 채널에게 입출력할 데이터의 시작주소와 크기를 알려주면 그 이후로 입출력을 채널이 도맡아서 합니다. 시스템에서 한 번의 입출력 단위를 Block(블록)이라고 부르는데 채널은 CPU에게 블럭 단위로 인터럽트를 보내므로 한 번의 입출력만 필요로 합니다.

 

다른 관점에서 입출력을 위한 하드웨어의 구성에 따라 2가지 정도로 분류할 수 있습니다.

 [ Isolated I/O ] (독립적인 입출력) 

입출력 장치들이 I/O Bus를 통해 CPU와 연결되어 있는 경우로 입출력을 담당하는 명령어에 의해 처리됩니다. 이렇게 입출력을 위한 명령어가 존재하기 때문에 제어 로직이 복잡해지고, 입출력 버스를 장착하는데 추가 비용이 든다는 점이 단점입니다.

 

 [ Memory-mapped I/O] (메모리 주소지정 입출력) 

입출력 장치들은 Memory Bus에 연결되어 있고 각각 메모리의 한 번지를 할당받아 MOVE, LOAD(메모리에 대한 명령어) 작업이 결국 그 번지에 해당하는 장치로의 입출력이 되는 방식입니다. 예를 들어 7번 주소에 I/O 장치 1번을 연결해놓았다고 가정해 봅시다. 이 떄 명령어가 MOVE "1" address 7와 같이 들어왔다면 1을 7번 주소로 옮기려고 하니 입출력 장치 1번과 연결되있으니 해당 장치로 출력을 하게 되는 것입니다. 그래서 memory-mapped I/O는 존재하는 주소공간 만큼 메로리를 활용하지 못하는 것이 단점입니다.

 

영상 출처 : https://youtu.be/ACEkZQyCc4Y

사진 출처 :  ECE Computer Architecture Dr.Wang slide, http://os4cs.blogspot.com/2015/11/introduction-references-abraham.html

'CS > OS' 카테고리의 다른 글

6. CPU 스케줄링  (0) 2020.01.11
5. Thread(스레드)  (0) 2020.01.10
4. Process (프로세스)  (0) 2020.01.10
2. 들어가기 전에②  (0) 2020.01.08
1. 들어가기 전에①  (0) 2020.01.08
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함