Operating System: ch2. Review of Computer Hardware

운영체제는 하드웨어와 제일 먼저 interaction하는 소프트웨어이다. 그래서 하드웨어에 대한 기본지식이 필요하다. 프로그램 관점에서의 하드웨어 지식을 살펴보고자 한다.

image 이미지 출처

Computer Systems Architecture

image 이미지 출처

Computer Hardware

컴퓨터의 3대 구성요소는 Processor(프로세서), Memory(기억장치), 그리고 I/O device(주변장치)이다. 이 구성요소들을 연결시켜주는게 system bus이다. 이때, system bus와 I/O device 사이에는 Controller라는 일종의 미니 CPU가 존재한다. 이 컨트롤러가 processor 대신 각 I/O device마다 그 device에 일어나는 업무를 관리하고 연산(operation)한다. 컴퓨터에서 연산을 한다는 것은 이 processor가 무언가 일을 한다는 뜻이다.

Processor

image 최초의 상용 마이크로프로세서 이미지 출처

프로세서(processor) (a.k.a. 중앙처리장치, CPU, Central Processing Unit)
컴퓨터 하드웨어에 부착한 모든 장치의 동작을 제어하고 명령을 실행한다.

image

프로세서는 위 그림과 같이 (1)연산장치, (2)제어장치, (3)레지스터로 구성되고, 이들은 내부 bus로 연결한다.

  • 레지스터의 종류
    • 용도에 따른 구분
      • 전용 레지스터
      • 범용 레지스터
    • 사용자가 정보를 변경할 수 있는지에 따른 구분
      • 사용자 가시 (user-visible) 레지스터
        • 데이터 레지스터 (DR, Data Register): 함수 연산에 필요한 데이터 저장
        • 주소 레지스터 (AR, Address Register): 주소나 유효주소를 계산하는 데 필요한 주소의 일부분 저장
      • 사용자 불가시 (user-invisible) 레지스터
        • 프로그램 카운터 (PC, Program Counter): 다음에 실행할 명령어의 주소를 보관
        • 명령어 레지스터 (IR, Instruction Register): 현재 실행하는 명령어를 보관
        • 누산기 (ACC, ACCumulator): 데이터를 일시적으로 저장
        • 메모리 주소 레지스터 (MAR, Memory Address Register): 프로세서가 참조하려는 데이터의 주소를 명시하여 메모리에 접근하는 버퍼 레지스터
        • 메모리 버퍼 레지스터 (MBR, Memory Buffer Register): 프로세서가 메모리에서 읽거나 메모리에 저장할 데이터 자체를 보관하는 버퍼 레지스터. (a.k.a. 메모리 데이터 레지스터, MDR; Memory Data Register)
    • 저장하는 정보의 종류에 따른 구분
      • 데이터 레지스터
      • 주소 레지스터
      • 상태 레지스터

Memory

image Random-Access Memory의 여러 종류 이미지 출처

레지스터
프로세서 내부에 있으며, 프로세서가 사용할 데이터를 보관하는 가장 빠른 메모리
메인 메모리 (a.k.a. 주기억장치, 1차 기억장치)
프로세서 외부에 있으며, 프로세서에서 즉각적으로 수행할 프로그램과 데이터를 저장하거나 프로세서에서 처리한 결과를 메인 메모리에 저장한다. 저장밀도가 높고 가격이 싼 DRAM(Dynamic RAM)을 많이 사용한다.
메인 메모리는 다수의 cell로 구성되며, 각 cell은 bit로 구성된다. cell이 K비트이면 cell에 $2^K$값을 저장할 수 있다. 메인메모리에 데이터를 저장할 때는 cell 한 개나 여러 개에 나눠서 저장한다. cell에 있는 값에 접근(참조)하려면 주소를 사용해서 한다.
  • 논리주소(logical address)(a.k.a. 가상 주소, 프로그램 주소): 컴파일러가 프로그램을 기계어로 변환할 때 변수와 명령어에 할당하는 주소. 프로그래머는 물리적 주소 대신 논리적 주소 사용. 논리적 주소는 별도의 주소 공간에 나타나며 컴파일로 논리적 주소를 물리적 주소로 변환하는데 이 과정을 mapping(a.k.a. memory map)이라고 한다.
  • 물리주소(physical address): 일련의 변환을 거친 최종 메인 메모리 주소. 컴퓨터에 주어진 주소.
캐시
프로세서 내부나 외부에 있으며, 처리 속도가 빠른 프로세서와 상대적으로 느린 메인 메모리의 속도차이를 보완하는 고속 버퍼. 메인메모리와 크기가 동일한 Block 여러개로 구성되는데, 보통 8~64 Byte 정도 크기의 Block으로 구성된다.
보조기억장치(a.k.a. 2차 기억장치, 외부기억장치)
주변장치 중 프로그램과 데이터를 저장하는 하드웨어. 예를들어, 자기디스크, 광디스크, 자기테이프 등

프로그램이 수행되려면 그 프로그램이 메인 메모리에 올라와있어야 한다. 운영체제는 컴퓨터가 부팅되었을 때부터 항상 수행되면서 각종 자원들을 관리해야 하므로 항상 메모리에 올라가 있다. 하지만, 운영체제의 모든 코드를 다 메모리에 상주시키면 메모리 낭비가 발생하게 된다. 따라서 운영체제 중 항상 메모리에 올라가 있는 부분은 전체 운영체제 중 핵심적인 부분에 한정되며, 이 부분을 커널(kernel)이라고 한다.

System bus

image PCI Express 버스 카드 슬롯 이미지 출처

시스템 버스
하드웨어를 물리적으로 연결하여 서로 데이터를 주고받을 수 있게 하는 통로
컴퓨터 내부의 다양한 신호(데이터 입출력 신호, 프로세서 상태 신호, 인터럽트 요구와 허가 신호, clock 신호 등)를 시스템 버스를 통해 전달한다.

I/O Devices

주변장치
processor와 memory를 제외한 나머지 하드웨어 구성 요소. 단순히 입출력장치(I/O devices)라고도 하나, 크게 입력장치, 출력장치, 저장장치로 구분하기도 한다.

Instruction

  • 명령어(instruction): 프로세서가 실행할 연산인 연산부호와 명령어가 처리할 데이터, 데이터를 저장한 레지스터나 메모리 주소인 피연산자로 구성된다.
    • 연산부호(OPcode, OPeration code): 프로세서가 실행할 동작인 연산을 지정
      • 산술연산 (+, -, *, /)
      • 논리연산 (AND, OR, NOT)
      • shift
      • 보수
    • 피연산자(operand): 연산할 데이터 정보를 저장.
      • 데이터는 레지스터, 메인메모리, 가상기억장치, 입출력장치 등에 위치하고 있다.
      • 데이터 자체보다는 데이터의 위치를 저장
      • 피연산자의 위치를 명시하는 방법 (mode bit 활용)
        • 직접 주소(direct address): 피연산자에 데이터가 있는 레지스터나 메모리 주소 지정
        • 간접 주소(indirect address): 데이터가 있는 레지스터나 메모리 주소 정보를 지정
  • 명령어의 형태: 피연산자 수에 따라 형태가 달라진다
    • 0-주소 명령어 (피연산자)
    • 1-주소 명령어 (연산부호 + 피연산자)
    • 2-주소 명령어 (연산 부호 + 피연산자 + 피연산자)
    • 3-주소 명령어
  • 명령어의 실행과정
    1. 명령어 인출(fetch): 명령어 레지스터에 저장된 다음 명령어를 인출한다.
    2. 명령어 해석(decode), 프로그램 카운터 변경: 인출한 명령어를 해석하고 다음 명령어를 지정하려고 프로그램 카운터를 변경한다.
    3. 피연산자 인출: 명령어가 메모리에 있는 워드를 한 개 사용하려면 사용 장소를 결정하여 피연산자를 인출하고, 필요하면 프로세서 레지스터로 보낸다.
    4. 명령어 실행(excute)
    5. 결과 저장

image

  1. fetch Cycle 인출 사이클
  2. execution Cycle 실행 사이클
  3. indirect Cycle 간접 사이클
  4. interrupt Cycle 인터럽트 사이클

System Interconnect

System bus는 (1)Address bus, (2)Data bus, (3)Control bus 세 가지로 나뉜다.

Address bus
CPU가 시스템의 구성 요소를 식별하는 주소 정보를 전송한다. 주소 버스를 구성하는 배선의 개수가 CPU와 접속할 수 있는 메인메모리의 최대 용량을 결정한다. 데이터가 이동하려면 데이터의 source와 destination을 지정해야하는데, 이 정보를 address라고 한다. address 정보는 address bus를 통해서 이동한다.
Data bus
CPU, Memory, I/O devices 사이에서 데이터를 전송한다. 데이터 버스를 구성하는 배선의 개수는 CPU가 한 번에 전송할 수 있는 비트 수를 결정하는데, 이를 워드(word)라고 한다.
Control bus
CPU가 시스템의 구성 요소를 제어하는 데 사용한다. 제어 신호로 연산장치의 연산 종류와 메인 메모리의 읽기/쓰기 동작을 결정한다.

시스템 버스가 있으면 버스에 대해서 할 수 있는 operation은 크게 두 가지로 나뉜다.

  1. 읽기 read (cpu관점에서 메모리 load)
  2. 쓰기 write (cpu관점에서 메모리 store)

Bus Master

bus transaction을 하려면 처음에 시작하는 요소가 있어야 한다. 이게 바로 bus master이다. bus master가 bus request signal을 보냄으로써 bus transaction이 이루어진다.

read/write transaction을 하려면 제일 먼저 bus를 장악해야한다. 왜냐하면 컴퓨터 시스템 안에는 bus transaction을 시작할 수 있는 bus master가 여러 개 있기 때문이다. 여러 bus master가 서로 bus를 장악하려고 할 때, 특정 bus master에게만 bus를 제공해줘야 한다. 이게 바로 bus arbiter이다.

bus arbiter는 bus master들한테 bus request signal을 받는다. 이 중 우선순위나 어떤 policy에 의해서 하나의 bus master를 선택한다. 그리고 이 bus master에게 bus를 제공한다. 즉, grant signal을 준다.

주로 bus master 역할하는 하드웨어 구성요소로는 3가지 정도 있다.

  1. CPU
  2. I/O Controller: I/O controller가 CPU에게 interrupt를 보낼 때
  3. DMA Controller: DMA controller가 CPU에게 interrupt를 보낼 때

Bus Slave

대표적인 bus slave는 main memory이다. 또한 I/O operation할때 iterrupt-driven I/O를 해서 bus controller가 주동적으로 할 수도 있지만, CPU가 이걸 할때도 있다. 후자의 경우엔 I/O controller도 bus slave가 될 수 있다.

주로 bus slave 역할하는 하드웨어 구성요소로는 2가지 정도 있다.

  1. memory controller (memory)
  2. I/O Controller: CPU가 I/O Controller에게 I/O operation을 요청할 때

2가지를 기억하자.

  1. bus slave는 데이터를 담고 있는 장치다.
  2. 데이터를 여러개 담고 있으니까 address를 가지고 있어야 한다.

메모리에 있는 address와 I/O에 있는 address는 형태가 같게 구현할 수도 있고 다르게 구현할 수도 있다.

I/O Operation

I/O device controller

I/O controller는 해당 장치에 대한 업무를 처리하고, 이를 메인 CPU에 interrupt를 발생시켜 보고하는 역할을 한다. interrupt가 발생하고 나타나는 메커니즘을 interrupt mechanism이라고 하며 밑에서 다룬다.

각 device마다 이를 control하기 위해 설치된 I/O device controller는 device로부터 들어오고 나가는 데이터를 임시로 저장하기 위한 작은 메모리를 가지고 있다. 이를 local buffer라고 부른다.

I/O device controller는 bus master와 bus slave 둘다 될 수 있다.

I/O device controller도 2가지 register를 갖는다.

  1. data register
  2. control register

CPU에 의해 I/O operation이 시작되는 상황이라고 해보자 (bus slave)

  • interrupt-driven I/O: write operation이라고 하면, CPU가 출력되야할 data를 i/O controller에 있는 data register로 전송한다. 그러고나서 I/O controller에게 output명령을 내보낸다. 그러면 그걸 받은 I/O controller는 I/O device가 가용한 상태인가를 확인한 다음 가용한 상태면 output한다. 이런과정에서 CPU는 다른 job을 수행 하고 있는다. 그 다음 성공적으로 write되면 I/O controller가 CPU에게 비동기적으로 성공 status를 줄 수 있어야 한다. 이걸 주는게 바로 interrupt-driven I/O이다.
  • polling I/O: 이와 반대로 CPU가 출력될 데이터를 I/O controller에 있는 output register로 보낸다. 그 다음 실제로 output에 관여한다. output operation이 제대로 끝났는지까지도 CPU가 관여한다. 무한 루프를 돌면서 I/O 동작이 완료될때까지 CPU가 반복해서 I/O controller의 register 상태를 계속 확인한다. 이게 바로 polling I/O이다. 이건 I/O동작과 CPU동작이 동시에 overlap(동시수행)될 수 없다.

I/O addressing

CPU가 I/O Controller에게 I/O operation을 요청하는 데 이것은 I/O controller의 memory에 값을 쓴다는 것을 의미한다. 즉, I/O controller 내부에 있는 버퍼 메모리 혹은 레지스터에 값을 쓴다. 이때 I/O controller 메모리 주소를 표현하는 방식이 두 가지로 나뉜다.

  • port-mapped I/O: I/O controller에 있는 resgister를 다른 말로 port register라고도 부른다. 이건 device register를 위해서 별도의 주소 공간을 할애한다. memory address space와는 별도의 port address space를 갖게 된다. input, ouput을 하기 위해서 별도의 instruction을 필요로 하게 된다. 이때 instruction의 타겟 주소가 port register가 된다. 인텔 프로세서가 이 방식을 사용한다.
  • memory-mapped I/O: 이건 메인메모리 주소 공간의 일부를 할애해서 거기에 I/O register를 매핑하는 방법이다. port mapped I/O처럼 별도의 주소공간을 할애하지 않는다. 별도의 Instruction이 필요하지 않다. memory의 load, store 명령어가지고 구현가능. 모토로라계열의 마이크로 프로세서 이 방식을 사용하는데 요즘은 잘 사용 안되는 추세이다.

Direct Memory Acess (DMA)

원칙적으로 메모리는 CPU에 의해서만 접근할 수 있는 장치이다. 따라서 CPU 외의 장치가 메모리의 데이터에 접근하기 위해서는 CPU에게 interrupt를 발생시켜 CPU가 이를 대행하는 식으로만 가능하다. I/O controller가 CPU에게 interrupt를 발생시키면 CPU는 controller의 local buffer와 메인 메모리 사이에서 데이터를 옮기는 일을 하게 된다.

DMA 등장 배경

  • 모든 메모리 접근 연산이 CPU에 의해서만 이루어질 경우 I/O device가 메모리 접근을 원할 때마다 interrupt에 의해 CPU의 업무가 방해를 받게 되어 CPU 사용의 효율성이 떨어지는 문제가 있다.
  • 여태까지 I/O operation(interrupt-driven I/O & polling I/O)는 주로 char I/O operation을 의미했다. 즉, Byte단위의 작은 데이터 전송이었다. 근데 Block이라는 큰 단위의 데이터를 전송할 필요가 많아졌다.

이러한 배경으로 인하여 CPU 이외에 메모리 접근이 가능한 장치를 하나 더 두는 경우가 많은데 이 장치가 DMA(Direct Memory Acess)이다. DMA는 일종의 controller로서, 이 controller가 메모리에 direct로 access하기 때문에 붙혀진 이름이다. CPU가 I/O devices의 메모리 접근 요청에 의해 자주 interrupt 당하는 것을 막아주는 역할을 한다. CPU의 개입 없이 I/O controller가 메모리에 직접 접근하여 Data를 읽거나 쓸 수 있도록 한다. Block data를 옮길 때 CPU intervention을 최소한으로 줄이기 위해 사용한다.

  1. 처음에 CPU가 DMA controller에게 DMA operation initiation한다.
  2. DMA operation initiation하려면 CPU가 DMA controller에게 여러 data와 command를 제공해야한다.
    • data: 전송되야할 block의 메모리상 시작주소, 얼마나 많은 데이터를 포함하는지(block size)
    • command: read 또는 write
  3. DMA controller가 CPU에게 data와 command를 제공받고 나면 이제 실제로 block에 있는 데이터를 옮기는 작업을 한다. 이 과정에서 CPU intervention은 전혀 없다.
  4. DMA controller는 bus master로서 매번 data bus에서 한 word씩 가져올 때마다 bus를 장악해야한다. bus arbituration과정을 통해 버스를 장악한 다음 메인메모리에서 한 워드씩 직접 읽어온다. 읽은 후에 자신의 buffer에 잠시 보관하고 I/O 디바이스로 전송한다.

DMA가 block데이터를 옮기는 2가지 방식

  • Cycle Stealing: CPU가 메모리 access하는걸 간섭 하지 않기 위해서 CPU가 메모리 access하고 instruction을 수행시키고 있을때(bus가 idle할때), bus cycle을 훔쳐서 데이터를 한 워드 단위로 옮겨가는거다. CPU 성능에는 영향을 미치지 않지만, DMA하는데 시간이 오래걸린다.
  • Block Transfer: CPU와 DMA controller가 대등하게 경쟁하여 Bus를 사용하는 방식

Interrupt Mechanism

지금까지 컴퓨터 시스템에 대해서 공부하며 CPU, 메모리, I/O와 같은 entity 위주로 생각했었다.

반면, OS에서는 bus 중심의 사고방식이 필요하다. bus master, bus slave, interrupt operation 등을 항상 생각해야 한다.

interrupt mechanism은 OS가 존재하기 위해서 컴퓨터 하드웨어가 제공해야하는 가장 중요한 메커니즘이다.

CPU는 instruction 하나를 수행할 때마다 interrupt가 발생했는지 확인한다. interrupt가 발생했으면 다음 instruction을 수행하기 전에 interrupt 처리를 하게 되고, 그렇지 않으면 다음 instruction을 계속 수행하는 것이다.

Interrupt Mechanism 개념

interrupt에는 H/W interrupt와 S/W interupt가 있다. 공통점은 둘 다 어떤 프로세스가 CPU 연산이 필요할 경우 CPU 옆에 있는 interrupt line에 signal을 보내서 interrupt가 발생했음을 알려주는 방식이라는 점이다.

  • H/W interrupt
    • I/O controller와 같은 하드웨어가 CPU의 interrupt line을 세팅한다.
    • 비동기적이다.
  • S/W interrupt (a.k.a. Trap)
    • 하드웨어가 아니라 소프트웨어가 CPU의 interrupt line을 세팅한다.
    • 소프트웨어의 예로는 excpetion(예외)와 system call이 있다.
      • exception: 사용자 프로그램이 0으로 나누는 연산 등 비정상적인 작업을 시도하거나, 자신의 메모리 영역 바깥에 접근하려는 시도 등 권한이 없는 작업을 시도할 때 이에 대한 처리를 위해 발생시키는 interrupt
      • system call: 사용자 프로그램이 운영체제 내부에 정의된 커널 코드를 실행하고 싶을 때 운영체제에 서비스를 요청하는 방법
    • 동기적이다.

통상적으로 interrupt라고 하면 H/W interrupt를 의미하고 S/W interrupt는 Trap으로 많이 불린다.

Interrupt Operation

CPU가 H/W interrupt를 받아들이려면 Micro-processor에 interrupt signal을 받아들이는 pin이 있어야 한다. 이 pin에 signal이 들어오면 interrupt가 발생했다는 걸 알 수 있다. image

물론 이 pin에 interrupt를 발생시키는 source가 물려있어야 한다. source로는 I/O controller, DMA controller가 있다.

Interrupt 처리 과정

  • 처리1: pin에 signal이 오면 현재 수행중인 프로세스을 중단시킨다. 현재 수행중인 instruction을 완료하고 마이크로 프로세서의 프로그램카운터(PC)값을 안전한 곳(레지스터)에 저장한다.
  • 처리2: interrupt source가 무엇인지를 확인한다. interrupt source는 interrupt signal과 함께 IRQ 번호(Interrupt ReQuest Number)를 보냈을 것이다. 그러면 어떤 device인 source에서 interrupt signal을 보냈는지 확인이 가능하다.
  • 처리3: 컴퓨터 시스템의 특정 메모리에는 interrupt가 발생했을 때 어떤 처리해야는지 그 코드가 interrupt handler(a.k.a. ISR; Interrupt Service Routine)라는 곳에 저장되어 있다. 이 곳으로 갈 수 있게 그 interrupt handler의 주소가 저장된 table을 Interrupt Vector Table이라고 한다. IRQ번호가 interrupt vector table의 index 역할을 한다. 마이크로프로세서는 이 IRQ번호로 interrupt vector table의 indexing하고 handler 주소를 얻는다. 그리고 handler로 jump한다.
    • 운영체제가 해야할 일들을 운영체제의 개발자가 미리 코드를 짜서 커널 내에 포함시켜뒀다. 그 중 한 가지가 ISR이다. 운영체제 커널 내에 있는 ISR은 다양한 interrupt에 대해 각각 처리해야할 업무들을 정의하고 있다.
  • 처리4: handler로 점프 후에 그곳에서 service routine을 수행한다.
  • 처리5: 그 다음 기존 프로세스로 복귀한다.

interrupt 발생 -> interrupt vector table 확인 -> ISR로 점프,수행 -> PC 복귀 -> 기존 프로세스로 복귀

예를 들어, 사용자로부터 키보드에 입력이 들어오면 키보드 controller가 interrupt를 발생시켜 CPU에 그 사실을 알려준다. 그러면 CPU는 현재 수행 중이던 작업의 상태를 저장하고, interrupt 요청을 처리하기 위해서 OS내 정의된 키보드 ISR을 찾아간다. ISR은 키보드로부터 입력받은 내용을 메모리의 특정 부분에 저장해 해당 프로그램에 키보드 입력이 들어왔음을 알리면서 interrupt 처리를 완료한다. 이 후 interrupt 처리가 끝나면 interrupt가 발생하기 직전의 상태를 복구시켜 중단되었던 작업을 재개한다. I/O 장치들은 이와 같이 interrupt를 통해서 CPU의 서비스를 받을 수 있다.

하지만, 여기서 문제가 발생한다. 마이크로프로세서는 다양한 시스템에 사용될 수 있다. 어떤 시스템에는 Interrupt source가 4개, 다른 시스템은 30개 … 그럼 이렇게 interrupt source에 맞춰서 pin개수도 늘어나야 될텐데, pin 하나하나가 비싸다. 이런 문제를 scaleability problem이라고 한다(CPU가 source의 확장성을 감당하지 못하는 문제). 그래서 실제로 구현할때는 이렇게 CPU의 pin에 source를 바로 연결(hard-wire)하진 않는다. image

해결방법은 PIC(Programmable Interrupt Controller)이다. pin과 source들 사이에 programmable한 circuit이 존재하는데 이걸 PIC라고 한다. PIC는 CPU의 pin에 인가되는 output line 하나를 갖고 있고 source에 인가되는 input line 여러 개를 가지고 있다.

PIC는 말 그대로 programmable하다, 즉 software적으로 동작을 변형할 수 있다. 예를 들어 synchronization이나 scheduling 때문에 잠시동안 특정 interrupt soruce를 disable시켜야할 때가 있다. 이때 PIC 안에는 1bit 짜리 flag 들이 있다. 이 flag를 0으로 masking해버리면 disable된다. 1로하면 enable된다. 예를 들어 “1110 0001 1111 1101” 처럼 표현한다. 이 flag를 0,1로 전환하는걸 software적으로 할 수 있다. 그래서 programmable interrupt controller라고 한다.

예를 들어 interrupt source가 16개 있다면 16진수짜리 flag register가 PIC에 존재하는 것이다. CPU를 통해서 flag register 값들을 0또는 1로 부분적으로 셋팅할 수 있다.

이 flag를 전문용어로 interrupt mask라고 한다. interrupt mask란 interrupt source가 발생시키는 interrupt를 무시하거나 향후에 처리할 수 있도록 하는 방법이다. I/O operation을 통해서 mask register의 port number (I/O address)를 타겟으로해서 output operation을 하면 된다.

PIC안에 있는 레지스터들은 전부 I/O address range안에 전부 mapping되어 있어야하고, 전부 port address를 부여받고 있다. 그리고 이 port address를 이용해서 특정 mask registor의 비트를 끄거나 킬 수 있다.

CPU는 IRQ넘버를 알야아하는데 이건 PIC 안에 있는 레지스터에서 알 수 있다.

Hardware protection

하드웨어적 관점에의 memory protection을 살펴보자.

Multiprogrammed OS에서 언급했듯이, 메모리 안에는 active job들이 여러개 있다. 근데 어떤 job이 자기한테 할당된 메모리 영역이 아니라 다른 메모리에 access하게되면 문제가 발생한다. 이런 protection 문제를 해결하기 위해서 base register와 bound register를 사용했다. job이 바뀔때마다 OS가 base와 bound를 정확한 값으로 셋팅해줘야한다. 이를 위해 Privilieged instruction(특권명령)라는 개념을 도입했다.

Privilieged instruction
OS만 엑세스하거나 수행할 수 있는 instruction이다.

이 privilieged instruction을 어떻게 구현할지 dual mode operation을 중심으로 살펴보겠다.

Basic Mechanism: Dual mode operation

  • Dual mode operation
    • 말 그대로 수행할때 모드가 두 가지 있다는 것
      • User Mode: 일반 사용자 프로그램이 실행되며 제한적인 명령만 사용할 수 있다.
      • Kernel Mode (a.k.a. privilieged/system/monitor mode): 운영체제가 CPU의 제어권을 가지고 운영체제 코드를 실행하는 모드로서, 이 모드에서는 모든 종류의 명령을 다 실행할 수 있다.
    • 모드는 마이크로프로세서 안에 존재하는 레지스터가 결정한다.
      • process status register: 최근 수행했던 여러가지 상태를 기억하고 있다. 여러가지 상태를 flag형태로 저장하는 것. 이 중 한 bit를 mode bit라고 한다.
      • mode bit
        • 1: user program을 수행하는 모드 (User Mode), Privileged instruction들을 수행시킬 수 없는 모드.
        • 0: OS을 수행하는 모드 (Kernel Mode a.k.a Privilieged Mode, Monitor Mode), Privileged instruction들을 수행시킬 수 있는 모드. Privileged instruction을 실행시킬 수 있는 권한과 모든 메모리 영역에 엑세스 권한을 부여받는다.

Q. Privileged instruction은 어떻게 구현할까?

CPU가 instruction를 실행시키기 위해서 fetch를 했다. 그러면 fetch한 instruction을 decode하는데, 이때 micro-processor의 process status register 중 하나인 mode bit를 체크한다.

만약에 privileged instruction인데 mode bit가 1로 되어있으면? 즉, user mode이면? privileged instruction 수행을 허용하면 안된다. 누군가가 protection을 침해하려는거기 때문에 trap을 발생시킨다.

결국, MMU(memory management unit)에 있는 레지스터들을 엑세스하는건 전부 Privileged instruction이다.

컴퓨터시스템은 기본적으로 유저 프로그램은 전혀 신뢰하지 않는다. 프로그램을 짜면 반드시 버그가 존재한다. 이 버그로 인해서 컴퓨터시스템에 악영향을 끼칠 수 있다. 반대로 OS는 무조건 신뢰한다. 통제된 환경에서만 실행해야하므로 모드가 2가지 있는거다.

image

Q. mode change는 어떻게 하는가?

A. 하드웨어적인 매커니즘으로 구현한다. interrupt가 발생하면 무조건 모드가 kernel mode로 된다. 그리고 kernel mode로 바뀌는 순간 mode change를 관할하는 ISR이 시스템을 장악한다. Kernel mode에서는 모든 권한이 허용되므로 직접 process status register에 값을 변경하여 user mode로 변경되는 것이 허용된다. OS가 무한신뢰의 대상이라서 Kernel mode의 이러한 임의 변경이 가능하다.

그러나, User mode에서는 process status register 값을 쓸 수 있는 권한이 없기 때문에 불가능하다. User mode에서 I/O operation과 같은 privileged instruction을 수행할 필요가 있는 경우에는 system call을 호출한다. 이 interrupt를 통해, mode bit를 바꾸어 kernel mode로 진입한 뒤 요청된 interrupt에 대한 ISR을 수행한 뒤 그 결과를 반환하며 다시 User mode로 돌아온다.

system call에 대해서는 추후 좀 더 자세히 다룰 예정이다.

I/O protection

Q. I/O protection이 왜 필요한가?

A. I/O도 resource이므로 어떤 job이 I/O register를 맘대로 엑세스해서 I/O를 독점한다면 컴퓨터시스템을 효율적으로 사용하는 측면에서 문제가 된다.

Q. 어떻게 protection하는가?

A. I/O register(port register)들 엑세스하는 모든 instruction를 Privileged instruction으로 만들면 된다. 모든 I/O에 관한 함수들은 커널 내부로 들어간다는 뜻이다.

5개의 OS 구성요소중 I/O subsystem이 왜 OS에 포함되어야하는지 잘 보여주는 내용이다.

Memory protection

Q. Memory protection이 왜 필요한가?

A. 어떤 Job이 다른 Job 혹은 운영체제에 할당된 메모리 공간 range 침범을 막아야지 컴퓨터 시스템이 원활히 작동한다.

Q. 어떻게 protection하는가?

A. MMU(memory protection unit) + Base register, Bound(limit) register을 도입하여 메모리 접근을 중재한다.

CPU protection

Q. CPU protection이 왜 필요한가?

A. CPU는 컴퓨터 시스템에서 resource이므로 운영체제가 각 프로세스들이 CPU를 독점(monopolized)하는 것을 막으며 중재자 역할을 수행해야 한다. 특정 프로그램이 CPU를 독점해 무한반복문을 수행하는 등 부적절한 방법으로 CPU의 사용 권한을 독점하고 있다면 다른 프로그램 및 운영체제가 CPU를 빼앗을 방법이 없게 된다.

Q. 어떻게 protection하는가?

A. 이를 위해 Timer라는 하드웨어를 도입하여 하나의 프로세스가 일정 한계치 이상 CPU를 독점할 수 없게 했다. Timer는 일정 시간 단위로 세팅될 수 있으며 매 Clock tick 때마다 1씩 감소한다. 그리고 일정 시간이 경과해서 Timer가 0이 되는순간 Timer interrupt를 발생시킨다. 여기서 Timer의 값을 세팅하는 instruction를 load timer라고 하며, 이는 Privilieged instruction에 속한다.

업데이트:

댓글남기기