운영체제 강의 노트 - System Structure & Program Execution 1

조해빈·2023년 5월 10일
0

OS

목록 보기
1/9
post-thumbnail

LECTURE is here

KOCW 온라인에서 제공되는 이화여대 반효경 교수님의 OS 강의에 대한 정리 요약

  • 노션에 기록했듯 CSAPP과 함께 천천히 병행
  • 연관 게시글은 강의 진행 순서대로 정렬되어 있지 않고, 내 필요에 따라 강의의 주제를 선택해 듣는다.
  • 온라인 상의 타인들이 올려놓은 연관 자료 역시 함께 참고한다.

컴퓨터 시스템의 구조

하드 디스크는 input device/output device 둘 다의 역할을 한다. CPU 안에는 memory보다 빠른 저장 공간이 있다. 이를 register라고 한다.

Interrupt line은 항상 프로그램이 memory 영역만을 사용해서 작동하기는 어렵기 때문에, I/O device 접근을 위해 프로그램 실행 중 interrupt를 걸어 해당 device에서 데이터를 읽거나 쓴다.

✅ input? output? 컴퓨터 내부를 기준으로 인풋과 아웃풋이 구분된다. CPU 쪽으로 데이터가 들어오는 것이 input, 반대가 output이다. 디스크 입장에서 데이터가 나가는 것이라도, input이다.

cpu의 문제점과 운영체제의 필요성

CPU는 연산속도가 가장 빠르며, 매 클럭마다 메모리에서 무언가를 읽는다. registers중에 프로그램 카운터(pc)가 다음번에 실행할 주소를 가지고 있고, CPU는 그것을 기준으로 매번 실행하는 것이다 하지만 CPU는 하드웨어라 생각을 못한다. 즉, 메모리에서 명령(Instruction)을 읽고, 실행하고, 읽고, 실행하고를 반복한다. 그저 읽고 실행만 하기 때문에 운영체제의 기계어로 인한 관리가 개입된다.

그렇기 때문에 사실상 CPU를 메모리에 있는 특정 프로그램에 넘겨주고 나면, 운영체제가 CPU를 통제할 방법이 없다. CPU는 그저 실행될 뿐이기 때문이다. CPU의 통제를 위해 운영체제는 하드웨어 장치와 협조하고, 인터럽트를 사용한다.

인터럽트 (Interrupt)

📍 Interrupt(넓은 의미)
	- interrupt (하드웨어 인터럽트) : 하드웨어가 발생시킨 인터럽트. 일반적인 의미의 interrupt.
    - trap (소프트웨어 인터럽트)
      - Exception : 프로그램이 오류를 범한 경우
      - System Call : 프로그램이 커널 함수를 호출하는 경우

CPU가 메모리에서 읽던 명령어에서 I/O 장치를 호출하는 내용이 있었고, I/O 디바이스 컨트롤러에 일을 시켰다. 해당 명령어는 I/O 작업이 끝나서 받아온 값을 사용해야 수행할 수 있다고 가정해보자.

설명했듯이, CPU의 연산은 다른 장치들보다 훨씬 빠르기 때문에 I/O장치가 일 하는 것을 기다리는 동안 다른 일을 할 시간이 남는다. CPU가 상대적으로 빠른 만큼, 만약 I/O 장치가 일을 하는 것을 기다리면서 아무것도 하지 않으면 엄청난 낭비인 것이다. 그래서 I/O 작업을 필요로 하는 해당 명령의 실행을 보류하고, CPU는 I/O장치를 안쓰는 다른 프로그램으로 넘어가서 일을 한다. (물론 뭐가 더 빠르다 느리다 비교하지만 우리 눈에는 구분이 가지 않는 작은 시간단위이다. 예시로 키보드로 입력하면 우리 눈에는 자판을 누르자마자 입력되는 것처럼 보인다.)

문제는 CPU는 스스로 움직이지 못한다. 메모리에 명령어를 순차적으로 읽을 뿐이다. CPU는 I/O장치가 일을 끝냈다는 것을 알 방법이 없다. 그런 cpu에게 I/O장치에 맡긴 일을 완료했다는 말해주는 것이 인터럽트이다.

인터럽트가 발생하면, CPU의 통제권이 운영체제에게 넘어가고, I/O 장치의 처리 내용을 받아온다. 인터럽트 당한 시점의 레지스터와 program counter를 save 한 후 CPU의 제어를 인터럽트 처리 루틴에 넘긴다.

그런데 CPU는 명령어를 읽기만 하는데 인터럽트가 들어온 것을 어떻게 알 수 있을까?

인터럽트를 확인하기 위해 CPU는 매 명령어 수행마다 interrupt line을 체크한다 I/O장치를 호출했던(I/O 장치가 필요한) 명령을 실행할 준비가 된 것을 알 수 있게 되는 것이다.

인터럽트 백터

해당 인터럽트의 처리 루틴 주소를 가지고 있다.
인터럽트 번호와 주소의 쌍을 가지고 있다.

인터럽트 처리 루틴

Interrupt Service Routine, 인터럽트 핸들러
인터럽트 요청이 오면 해당 인터럽트를 처리하는 커널 함수를 거친다.

Mode Bit

초기의 단순한 컴퓨터 구조에서는 사용자 프로그램의 잘못된 수행, 예를 들어 OS의 데이터를 건드릴 수 있는 기계어의 실행이 들어오는 경우 등 다른 프로그램 및 운영체제에 피해가 가지 않도록 할 방지턱이 없었고, 이에 대한 보호 체계가 필요했다. -> Mode bit라는 하드웨어를 통해 두 가지 모드의 operation 지원한다.

Mode bit는 사용자 프로그램의 잘못된 수행으로 다른 프로그램 및 운영체제에 피해가 가지 않도록 하기 위한 보호 장치이다. CPU는 항상 interrupt line을 체크해 프로그램 실행 중 interrupt가 발생했는지를 확인하는데, Mode bit을 통해 하드웨어적으로 두 가지 모드의 operation 지원한다.

1 - (User mode) : 사용자 프로그램 수행

운영체제가 CPU에서 실행중. 모든지 실행을 할 수 있음.

0 - (Monitor mode, kernel mode, system mode) : OS Code 수행

사용자 프로그램이 CPU를 제어하고 있을때는, 제한된 instruction만 CPU에서 실행 가능함.
Interrupt가 들어오면 자동으로 다시 CPU가 Os로 넘어오기 때문에 mode bit이 0으로 변경됨.

보안을 해칠 수 있는 중요한 명령어는 모니터 모드에서만 수행 가능한 특권 명령으로 규정하고, 이를 "특권 명령"이라 명명한다.

interrupt나 exception 발생 시 하드웨어가 mode bit을 0으로 바꾸고, 사용자 프로그램에게 CPU를 넘기기 전에 mode bit을 1로 세팅하는 방식이다.

Interrupt line은 항상 프로그램이 memory 영역만을 사용해서 작동하기는 어렵기 때문에, I/O device 접근을 위해 프로그램 실행 중 interrupt를 걸어 해당 device에서 데이터를 읽거나 쓴다.

CPU는 메모리에서 기계어를 읽어 한 줄 실행한 다음 다음 기계어 실행에 앞서 매번 interrupt line에 시그널이 들어온 게 있는지 체크한다고 했다. 이 interrupt line에 시그널이 들어오는 것이 곧 인터럽트의 개념이다.

interrupt line을 누가 셋팅하느냐에 따라 interrupt는 다시 둘로 나뉠 수 있다. 하드웨어 장치들이 인터럽트를 걸어서 CPU가 넘어가는 경우, 프로그램 소프트웨어가 직접 interrupt line을 셋팅하여 CPU가 넘어가게 요청하는 경우이다. 후자가 시스템 콜이다.

매번 interrupt line을 체크한다. CPU는 다음 명령어 대신 mode bit을 바꾸면서 운영체제로 넘어가는 것이다. 이렇게 사용자 프로그램이 운영체제에게 I/O요청을 하는 것을 시스템콜(system call)이라고 한다.

✅ system call (시스템 콜)

- trap을 사용하여 인터럽트 벡터의 특정 위치로 이동
- 제어권이 인터럽트 벡터가 가리키는 인터럽트 서비스 루틴으로 이동
- 올바른 I/O 요청인지 확인 후 I/O 수행
- I/O 완료 시 제어권을 시스템 콜 다음 명령으로 옮김

I/O Device Controller

해당 I/O 장치 유형을 관리하고 제어하는, 일종의 작은 CPU – cpu보다 device가 처리 속도가 느리기 때문에 이러한 처리를 관리해주는 역할을 device controller가 수행한다.

제어 정보를 위해 control register, status register를 가진다. (CPU의 지시를 위한 register) – cpu안에는 memory보다 빠른 저장 공간이 있다. 아까 말했듯 이를 register라고 한다.

I/O Device들은 반면 local buffer를 가진다. 일종의 data register라고 보면 되고, local buffer는 일종의 각 디바이스 별 작업 공간이다.

I/O는 실제 Device와 Local Buffer 사이에서 일어나는 것이다.

  • Device Controller는 I/O 가 끝났을 경우 interrupt로 CPU에 그 사실을 알림
  • device driver (장치 구동기) : OS Code 중 각 장치별 처리 루틴을 의미함 -> Software 영역
  • device Controller (장치 제어기) : 각 장치를 통제하는 일종의 작은 CPU -> Hardware

I/O Device controller

    해당 I/O 장치유형을 관리하는 작은 CPU의 일종
    제어 정보를 위해 control register, status register를 가짐
    local buffer 가짐 (일종의 data register)

device controller는 각각 디바이스를 전담한다. 예시로 디스크 내부를 통제하는 것은 CPU가 아닌 device controller의 몫이다. 각 장치들을 제어하는 작은 CPU로 생각하면 된다.

CPU는 I/O 작업에 비해 크게 빠르다. 엄청나게 빠른 CPU입장에서 이 시간을 쉬지 않고 일한다면 많은 일을 할 수 있을 것이다. 그래서 device controller에게 I/O작업을 시키고 I/O 작업을 대기하는 동안 다른 작업을 우선적으로 처리하는 것이다.

Device controller(장치제어기) vs Device driver(장치구동기)

device controller

하드웨어
각 장치 통제하는 작은 CPU

device driver

소프트웨어
OS코드 중 각 장치별 처리 루틴
    각 장치에 맞는 인터페이스가 운영체제에 있다. 거기에 접근하게 해준다.
CPU가 장치를 실행하기 위한 코드를 담고 있다.

✅ local buffer란?
I/O 장치들은 컴퓨터의 메모리에 직접 접근하여 읽고 쓸 권한이 없다. 고로 장치에 들어오고 나가는 데이터를 저장하는 임의의 작은 메모리로, 이곳의 데이터를 장치에서 local buffer로 읽어오는 것은 controller가 담당한다. 작업이 완료되면 인터럽트를 발생시키고, 그것을 CPU가 local buffer의 내용을 메모리에 복사해 와 메모리에 담을 수 있다. 고로 local buffer는 실제 데이터를 저장하며 I/O는 실제 device와 local buffer사이에서 일어난다고 할 수 있다.

Timer

정해진 시간이 흐른 뒤(초기에 정해진 시간을 할당함) 운영체제에게 제어권이 넘어가도록 인터럽트를 발생시킨다.

Timer는 특정 프로그램이 cpu를 독점하는 것을 막기 위한 역할을 수행하는 것이다. Timer에 값을 세팅한 후 프로그램을 cpu에 전달한다. 세팅한 시간이 지나면 interrupt를 걸어 프로그램이 멈추도록 한다.

- 타이머는 매 클럭 틱 때마다 1씩 감소
- 타이머 값이 0이 되면 타이머 인터럽트 발생
- CPU를 특정 프로그램이 독점하는 것으로부터 보호
- 타이머는 time sharing을 구현하기 위해 널리 이용됨
- 타이머는 현재 시간을 계산하기 위해서도 사용됨

DMA(Direct Memory Access) Controller

인터럽트는 실로 자주 발생한다. 그때마다 CPU를 활용해 직접 메모리에 내용을 복사하면, CPU 작업에 오버헤드가 너무 많이 발생한다. 따라서 빠른 입출력 장치를 메모리에 가까운 속도로 처리하기 위해 사용하는 것이 DMA(Direct Memory Access) Controller이다. 즉, I/O의 과도한 interrupt를 방지하기 위한 Controller다. 즉, CPU뿐만 아니라 DMA가 메모리에 접근할 수 있는 것이며, DMA는 CPU대신 I/O장치의 내용을 메모리에 복사해준다.

동시에 CPU와 DMA가 메모리에 접근하면 문제가 되기 때문에, memory controller가 교통정리를 해준다.

저장장치 계층 구조

internal 기억장치들은 주로 휘발성 기억장치들, external 기억장치들은 주로 비휘발성 기억장치로 구성된다.

CPU가 직접 접근 가능한 primary 저장장치들은 register, cache memory, main memory가 있다.

용량이 적을수록 속도도 빠르고 가격이 비싸며, 용량이 클수록 속도도 느리고 가격이 저렴하다. register와 main memory간의 속도 차이를 줄이기 위해 cache memory 를 사용한다.

총 I/O 과정

CPU는 register중에 프로그램 카운터가 다음번에 실행할 주소를 가지고 있고, 매번 읽고 실행하면서 interrupt line을 확인한다.
➡️ 실행 도중 I/O 장치에 접근하게 되면 device driver를 통해 명령한다. 만약 I/O 장치가 사용자 프로그램에서 호출되었다면, 시스템콜(trap-> 벡터 -> 루틴)을 통해 인터럽트를 발생시키고, 운영체제에 제어권을 넘기면서 mode bit을 0으로 바꾼다. 운영체제는 device driver를 사용한다.
➡️ 운영체제가 device controller에게 일을 시켜놓고, I/O장치를 기다리는 동안 CPU는 다른 I/O장치가 필요없는 명령들을 실행한다. 사용자 프로그램을 사용할 때는 mode bit을 1로 변경시킨다.
➡️ device controller는 레지스터들을 활용하여 장치를 사용하고, local bufffer에 내용을 전달한다. 완료 시 인터럽트를 발생시킨다.
➡️ CPU는 다른일에 사용되다가 인터럽트가 넘어오면 운영체제로 넘어간다. (mode bit 0)
➡️ DMA는 I/O장치의 내용을 local buffer에서 읽어와 메모리에 복사한다.
➡️ 보통 timer 시간이 남아있다면 인터럽트 당해서 방금 CPU를 빼앗긴 작업에게 CPU를 다시 준다. (mode bit 1)
➡️ 차례가 돌아오면 I/O값을 사용하려던 명령이 CPU를 얻어 실행된다.

profile
UE5 공부하는 블로그로 거처를 옮겼습니다!

0개의 댓글