728x90
반응형

필요한 이유 : 운영체제라는 것이 하드웨어와 매우 밀접하게 연관되어 있기 때문

 

커널과 시스템 호출

커널 vs 시스템 프로그램

커널

- cf> (상주) 모니터의 등장 : 다중 프로그래밍 기법을 고안하다 보니 작업관리 프로그램을 메모리에 상주시켜야 했고 입력장치와 비동기적 교신을 위해서 interrupt 처리를 위한 ISR도 메모리에 상주시켜야 했는데 이런 것들이 모여서 상주 모니터가 되었다. => 커널은 상주 모니터의 연장선

- 운영체제의 핵심 부분으로서 부팅 이후 메모리에 상주하는 부분 (부팅자체가 커널을 메모리에 탑재하는 과정)

   - 상주모니터보다 발전해서 시분할 시스템을 제대로 지원하고 메모리와 CPU, 입출력 장치들을 관리하게 된다. 

- 즉, 주로 자원 관리 및 자원 사용에 관한 서비스를 제공함

- 응용 프로그램과 커널은 하드웨어 지원을 받아 원천적으로 분리되게 되어있다. 즉, 응용프로그램하고 커널은 공간이 분리되어있다.

- 커널은 응용프로그램에게 시스템 호출이라는 것을 제공한다. 즉, 운영프로그램으로 하여금 입출력 등 커널 기능이 필요할 경우 이 시스템 호출을 호출하도록 한다. 그렇게 함으로써 커널은 스스로의 코드를 보호하고 응용프로그램은 시스템 호출을 통해서 커널 기능을 사용할 수 있게 된다.

 

시스템 프로그램 (커널과 혼동가능)

- 커널 이외의 프로그램으로써 운영체제 개발자가 기본적으로 제공하는 라이브러리나 운영체제 사용 도구 

- ex> 편집기(vi 등), 컴파일러(gcc 등), 디버거(gdb), 쉘(ssh 등), 쉘 명령어(ls, cd, ps, grep 등)

- 쉘은 윈도우의 명령 프롬프트 또는 dos창, 우분투의 터미널 창 -> 명령어를 통해 사용자와 대화를 나누는 프로그램

- 쉘은 윈도우 형태의 유저인터페이스(GUI)가 보편화되면서 윈도우매니저가 그 역할을 대신한다. 윈도우 매니저의 전신이 쉘이다. 

cf > 윈도우 매니저 : GUI 환경에서 각 프로그램들이 뜨는 창을 다루는 프로그램. MS 윈도나 애플 Mac에는 기본 시스템에 포함되어 있음. 

 

커널의 구성요소

- 기능적 측면 의 구성요소

  • 부팅 단계의 기능
    • 하드웨어 진단 및 초기화 기능 - 커널 수행 이전에 하드웨어들을 진단하고 초기화하는 기능(커널이 수행되기에 적합하도록 하드웨어가 오류 없이 잘 준비되었는지를 진단하고 필요에 맞춰서 설정하는 기능)
    • 디스크 상의 커널 프로그램을 메모리에 적재하는 기능 ( 커널 프로그램을 탑재할 때는 한꺼번에 탑재하지 않고 하드디스크 상의 마스터 부트 레코드로부터 순차적으로 chain식으로 탑재하게 된다)
  • 부팅 후 기능 -> 각종 경영 기능
    • 자원 경영(프로세스 경영, 중앙처리장치 경영, 주기억 장치 경영, 파일 시스템과 보조 기억장치 경영, 시스템 클럭 경영, 네트워크 경영, 입출력 장치 경영)
    • 보안 및 정보보호 기능

- 형태적 측면 의 구성요소 -> 커널을 각종 기능을 수행하는 함수들이 어떻게 모아져 있느냐를 뜻한다

  • 그림 : 커널 중심으로 맨 위에 응용 프로그램이 있고 맨 아래에 입출력 장치가 있다. 응용 프로그램은 위에서 커널이 제공하는 시스템 호출을 통해 커널 내의 함수 서비스를 받게 되어있다.
    반면, 입출력 장치는 인터럽트를 통해서 커널의 ISR, 디바이스 내의 ISR을 작동시켜서 커널의 서비스를 받게 되어있다. 
  • 이렇게 시스템 호출, ISR 둘밖에 없는 것은 아니고 둘 사이에는 커널 내부의 작동을 담당하는 많은 함수들, 커널 내부 함수가 존재한다. 
  • 경우에 따라서는 시스템 호출 함수와 디바이스 드라이브 내의 함수들이 커널 내부의 함수들과 연결이 되게 되어있다. 
  • 인터럽트 처리기의 집합 - 시스템 클럭 및 대부분의 입출력 장치와 관계된 장치 드라이브의 핵심들이 된다. 
  • 커널 내부 함수의 예로는 [스케쥴러]가 있다. 스케쥴러는 중요한 기능이지만 형태적으로는 시스템 호출 함수나 인터럽트 처리기에 의하여 필요에 따라 호출되는 커널 내부 함수이다. 스케쥴링이 필요할 때 내부적으로 호출된다. 

시스템 호출(system call)

- 응용 프로그램과 커널이 만나는 곳에 시스템 호출이 있다. 

- 응용 프로그램 개발자에게는 함수 호출하는 것과 큰 차이가 없다. 예를 들어 printf, open, read, write -> 이런 것들이 라이브러리 내의 함수를 호출하듯이 사용하지만 알고 보면 시스템 호출이 이루어져서 커널의 함수가 내부적으로 작동하는 것들이 된다. 

- 사용자 모드로 돌아가는 응용 프로그램이 open() 함수를 호출하게 된 것이고, 이것이 시스템 호출로 전환되어서 커널 내의 시스템 콜 테이블에서 해당 함수가 i번 함수인 것을 알아내서 처리가 이루어지고 처리가 끝나면 다시 사용자 모드로 가서 open() 함수의 다음 부분을 실행하는 그림. 

 

시스템 호출이 이루어지는 과정

- 두 가지를 통해서 이루어진다

1. 파라미터 전달 방법(시스템 호출도 함수 호출과 비슷하기 때문에 파라미터를 전달함)

- Linux나 Solaris 같은 경우 : 파라미터를 레지스터를 통해 주소를 전달하는 방식

   - X라는 곳에 전달하고자 하는 파라미터를 기록한 다음에 X의 주소를 특정 레지스터에 로드를 해놓는다. 즉, 메모리 상의 블록이나 테이블에 파라미터 값을 기록하고 시작 주소(X)를 레지스터에 기록하면 커널에서 레지스터 상의 주소를 얻어 파라미터 값들을 접근

- 다른 방식 : 레지스터가 아니라 스택을 사용

  - 스택에 파라미터 값을 Push 하면 커널에서 pop해가는 방식

- 커널에 시스템 호출 사실은 어떻게 알릴까? : CPU의 명령을 실행

 

2. 특정 CPU 명령 실행

커널상에서 어떻게 대응되는지 정해져 있음

 - open을 예시로 들면 open의 system call 고유번호가 13(시스템 호출 번호)이라는 숫자라고 볼 때, X를 담았던 레지스터와는 다른 CPU 내의 또 다른 레지스터에 담아서 interrupt를 거는(소프트웨어적인 인터럽트인 트랩) CPU 명령어를 실행하는 것이다. 즉 13을 다른 레지스터에 담고 interrupt명령어를 수행시켜 준다. 

 - interrupt를 거는 CPU 명령어 -> 소프트웨어 interrupt명령어(트랩 명령어)

 - 트랩 명령어 : X86 계열의 경우 int라는 명령어, ARM 계열의 CPU인 경우 swi

 - 이러한 interrupt는 하드웨어 interrupt와는 다르고, 단지 시스템 호출을 위해서 소프트웨어적으로 거는 것이라서 trap이라고 부른다. 

 - 리눅스의 경우의 예(리눅스 커널 2.4)

: 왼쪽에서는 응용프로그램이 사용자 공간에서 현재 수행 중에 있다. main을 수행하다가 read()를 만났을 경우이다. read함수 호출이 일어났다고 실질적인 내용이 막바로 실행되는 것이 아니다. 시스템 라이브러리인 libc 안에 있는 read함수가 호출된다. 이 응용프로그램이 컴파일되고 나서 링크될 때 read함수가 바로 libc함수로 링크되었기 때문에 libc내의 read함수가 호출되게 되는 것이다.

 libc내의 read함수는 read라는 함수 번호가 3번으로 약속되어있다는 것을 커널 프로그래머가 지정해서 알고 있고 3번을 범용 레지스터인 eax 레지스터(명령어 주소를 담았던 레지스터와는 다른 레지스터)에 기록하고 (movl 3, % eax) trap명령어인 int를 수행하게 되는 것이다. 시스템 내에는 수없이 많은 interrupt가 존재하기 때문에 커널에게 trap임을 인지시키기 위해서 trap의 고유번호인 0x80을 int instruction의 operand에 담아서 실행시킨다(결국 int $0x80이 하나의 명령어로 실행되는 것)

 이렇게 되면 커널로 0x80번의 interrupt가 걸리게 되는 것이다. 이에 따라서 IDT(Interrupt Descriptor Table)에서 0x80 interrupt의 ISR의 주소를 알아내서 노란색 저기로 점프를 하게 된다. ISR에서는 eax 레지스터의 4byte 값, int 수행 전인 3번을 읽어내서                      call ~~~ (% eax,4)) -> 3

 sys_call_table이라는 곳으로 가게 된다. sys_call_table은 system call table이다. sys_call_table에서 3번째 항으로 간다.
3번 항에 기록된 주소로 다시 한번 jump를 하게 된다. 이런 과정을 거쳐서 드디어 응용 프로그램이 read함수를 호출한 종착점인 sys_read() 함수로 도달하게 된다. (이 부분은 디바이스 드라이브 내부에 있을 공산이 크다..?)
-> a와 b는 이후에 나올 내용과 연관. a는 커널 쪽을 얘기하고 b는 디바이스 드라이브 쪽. 

- 시스템 콜의 실질적인 mechanism은 trap mechanism이다. 

- 시스템이 다르면 맞지 않는 경우가 생긴다(ex. 파라미터의 순서, 시스템 콜의 번호) -> 호환성에 치명적인 문제
-> POSIX사용 (일관성)

- 국제 표준 - POSIX(시스템 콜의 표준)

- POSIX에서는 시스템 호출을 6개의 경우로 나누고 있다. 

1. 프로세스 제어 ex. kill

2. 파일 조작       ex. open, close, read, write

3. 주변장치 조작

4. 정보관리

5. 통신             ex. send, receive(TCP socket)

6. 프로텍션(보호)

 

시스템 콜을 응용프로그램 개발자가 이용할 때 알아두어야 할 것

- 시스템 호출에는 2가지 유형이 있다. 

1. 동기식(blocking call) : 입출력을 시작시키고 끝날 때까지 대기

- read() 같은 시스템 콜을 하고 결괏값이 넘어오기를 기다린다. 넘어오기까지 기다린 후에 넘어오면 read 다음 라인으로 계속해서 수행해가는 것. 그것이 blocking call이다. read가 실행되는 동안에는 진행을 멈추고 있다. 대부분의 시스템 콜은 이런 방식으로 지원된다. 기다리는 동안 CPU는 아무 일도 하지 않을까? ㄴㄴ -> 시분할 시스템에서는 그사이 다른 프로세스를 실행시키게 되어있다. 대기하는 동안 CPU를 다른 프로세스가 사용

2. 비동기식(non-blocking call) : 입출력을 시작시키고 바로 다음 연산을 수행, 입출력이 이루어지는 동안 자식도 CPU를 사용할 수 있음

- 시스템 콜이 이루어지면 커널에 요청만 해놓고 바로 리턴 그러고 나서 다음 라인을 바로 진행. 요청한 시스템 콜이 종료가 될 때 event가 전달된다. event가 처리할 함수를 인자로 알려주게 되어있다. --> callback함수. 이벤트가 온다는 것은 callback함수가 불린다는 것이다. callback함수는 전달되어온 데이터를 응용프로그램에 일종 자료구조에 저장하거나 직접 처리를 하게 되는 것이다.
이런 비동기식 시스템 콜은 사용하는 장치가 그러한 기능을 제공할 뿐만 아니라 디바이스 드라이브에서 비동기식에 필요한 기능을 잘 구현해놓은 경우에만 가능하다.

 

입출력 시스템 : 커널과 입출력 장치와의 인터페이스

 물리적인 입출력 장치가 바로 시스템 버스에 접촉되어있는게 아니라 장치 제어기를 통해 연결되어 있다. 굳이 비유하자면 지상의 2층, 지하의 1층 건물과 같다. 2층은 응용프로그램, 1층은 커널이다. 지하 1층에는 하드웨어가 있다.

 하드웨어는 제어장치와 장치로 이루어진다. 제어하기 위해 커널에는 Device driver가 있다. 층과 층 사이에는 인터페이스가 있다. 2층과 1층 사이에의 인터페이스는 시스템 콜이 되고, 1층과 지하 1층 사이의 인터페이스는 버스가 된다. (ex> PCI 버스)

Device driver는 하드웨어인 장치 제어기와 약속된 바에 따라서 명령과 정보를 주고 받는다. 그것의 실체가 무엇일까?

그것은 장치제어기 내에 있는 레지스터에(명령, 상태, 자료 레지스터들) 정해진 값을 쓰거나 읽어오는것이 된다. 장치 제어기의 레지스터들은 메인메모리 상의 주소에 mapping되어 있다. 따라서 Device driver는 이 주소에 값을 쓰거나 읽으면 바로 해당 레지스터의 값을 쓰고 읽게 되는 것이다. 그렇게 하드웨어가 만들어져 있다. 

- 레지스터

  • 명령 레지스터 : 장치가동을 위한 명령 코드 적재
  • 상태 레지스터 : busy/done플래그, 오류코드 표현
  • 자료 레지스터 : 장치 내의 하드웨어 버퍼

Device Controller(장치 제어기) 내에는 어떤 레지스터들이 있을까? 적어도 3종류의 레지스터들이 있다. 즉, 명령, 상태, 자료 레지스터. 명령 레지스터는 장치의 쓰기나 읽기 동작을 명령하기 위해서 명령 코드를 적재하기 위한 레지스터. 상태 레지스터는 현재 해당 장치에 오류가 있는지 또는 작업이 진행중에 있는지 작업을 끝내고 쉬고 있는지 등의 장치의 상태를 체크해보는 용도로 사용된다. 자료 레지스터는 명령 레지스터의 명령 오고갈 데이터를 읽고 쓰기위한 버퍼같은 용도로 사용된다. 

 

층과 층사이의 인터페이스를 자세히 설명하자면 3가지로 봐야 한다. 두가지는 시스템 콜, HW인터페이스(버스). 

장치들을 커널의 코드들을 바꾸지 않고 플러그 앤 플레이 식으로 install할 수 있도록 해야한다. 이 경우 커널과 디바이스 간의 인터페이스를 매우 잘 디자인해서 공개해주어야 한다. 그렇게 공개된 커널(1층)과 디바이스 간의 인터페이스가 3번째 인터페이스이다. 

- 커널과 디바이스 간의 인터페이스(장치구동기- 커널 인터페이스)

: 왼편이 커널, 오른편이 디바이스 드라이브이다. 그 사이에 커널과 디바이스 간의 인터페이스(Driver-Kernel Interface)가 있다. 커널안에는 디바이스 드라이브가 등록되면 디바이스 드라이브의 번호가 생김, 여기서는 번호가 i 이다.

 그 디바이스 드라이브가 제공하는 함수들이 등록되는 table같은 구조가 있다. 앞서 설명한 시스템 콜 테이블이 일례이다. 이후, 응용 프로그램에서 장치 i를 사용하고자 open이라는 시스템콜을 호출하면 트랩을 통해 진입. 그런 후 i를 위한 커널 내의 테이블에서 open함수의 실제 구현함수인 디바이스 드라이브 내의 sys_open이라는 함수 포인터를 얻어서 그 함수로 점프를 하게 된다.

 이러한 과정을 통해서 커널과 디바이스 드라이브 간의 인터페이스가 동작하게 되는 것이다. 디바이스 드라이브는 커널 모드에서 커널과 함께 동작하기 때문에 디바이스 드라이브가 커널 내의 커널 함수를 직접 호출하거나 커널 내의 변수를 직접 접근할수도 있다. 커널의 기능을 효과적으로 이용하는 디바이스를 만들 수 있을것이다.

 하지만 커널 내의 함수와 커널 내의 전역변수들을 바로 접근할 수 있기 때문에 디바이스 드라이브를 만들때 상당히 조심해서 만들어야한다. 

 

디바이스 드라이브와 장치제어기 사이에 명령이나 정보가 오고가는 그것의 실체가 뭐냐라는 것을 얘기할때 레지스터를 접근하는 것이다 이렇게 설명함. --> 파고들어가면 방법이 다양함.

전반적으로 HW 인터페이스와 관련된 것이다. 먼저 HW 인터페이스 운영체제 관점에서 중요한 점들. (디바이스 드라이브를 설계하는데 있어서 결정적인 영향을 미치는 중요한 요소들) (장치와 장치제어기를 만드는 menufactoror들이 커널 안의 디바이스 드라이브를 짜는 software또는 개발자들에게 반드시 정확히 설명해주어야 할 부분이 있는 것이다. 그것을 장치 메뉴얼로 전달한다) 3가지 포인트가 있다.

장치제어기와 장치를 만드는 사람들이 디바이스 드라이브를 짜는 사람들에게 반드시 알려주어야 할 사항들

1. 접근 방식에 의한 분류 (레지스터 접근 방식) 어떤 방식이 있느냐

 - 격리형(isolated I/O)

 - 메모리 사상형(memory-mapped I/O)

2. 자료이동 방식에 따른 분류(디바이스 드라이브가 장치 제어기 내의 준비된 자료를 가져오는 방식)

 - 직접 입출력 방식

 - DMA 방식

3. 제어 방법에 의한 분류(장치 제어기 내에서 벌어진 상태변화를 디바이스 드라이브에게 알리는 방식)

 - 폴링(polling)

 - 인터럽트

아래에서 설명

1. 레지스터 접근 방식

  •  격리형(Isolated I/O 또는 I/O mapped I/O) 입출력 
    • 입출력 장치가 메모리와는 별도의 주소공간 사용(하드웨어 구조상 주변장치를 위하여)
    • 이 방식은 메모리 주소 지정을 위해 사용하는 주소 버스와는 별도로 I/O 장치를 위한 주소 라인을 따로 사용하기 때문에 주소값이 메모리 주소인지 입출력 장치 주소인지 구별하는 제어라인을 따로 사용하는 하드웨어 구조를 전제하는 방식이다. 
    • 결국 이러한 하드웨어적 특성을 이용하기 때문에 특수한 입출력 명령어를 사용해야 한다. (제어기 레지스터 접근을 위하여 하드웨어에 특화된 특수한 입출력 명령어)
    • 장점 : 입출력이 메모리 주소 공간의 크기나 할당에 영향을 주지 않음
    • 단점 : 메모리 접근 명령어와는 별도의 입출력 명령어를 사용하게 되어 프로그래밍의 일관성이나 이식성이 떨어짐
  • 메모리 사상형(Memory-Mapped IO) 입출력
    • 장치를 위한 별도의 주소 공간과 명령어를 정의하지 않고 메모리의 논리적 주소 공간에 제어기의 레지스터를 사상(mapping)
    • 메모리 주소 지정을 위해서 주소 버스와 입출력 제어 라인을 공유를 하고 주소 버스에 실린 값으로 메모리 주소와 입출력 주소를 구분하는 하드웨어 특징을 전제로 한다. 메모리 주소냐 입출력 주소냐를 구분하는 별도의 라인을 두지 않고 주소 자체로 판단한다. 
    • 따라서 메모리에 할당된 주소의 일부를 장치 제어기의 레지스터를 접근하는 주소로 사용할 수 있게 되는 그런 방식이다. 
    • 별도의 주소 공간과 입출력 명령어가 필요 없고 기존의 메모리 접근을 위한 명령어를 사용
      • 예를 들어서 CPU가 제공하는 LOAD명령과 STORE명령으로 수행(모든 입출력에 관한 명령은 해당 메모리에 대한 LOAD와 STORE 명령으로 수행)
    • 장점 : 명령어 개수를 줄일 수 있어 프로그래밍이 용이하고, 일관성과 이식성이 좋다
    • 단점 : 입출력을 위하여 메모리의 일부를 사용하므로 메모리 영역이 감소된다.(최근은 메모리가 커져서 큰 손해는 아님 -> 메모리 사상형 입출력이 보편화되었다)

2. 자료 이동 방식 : 장치제어기 내의 자료 레지스터하고 메인 메모리 사이의 데이터가 어떤 방식으로 이동하는 것인가에 관한 것. 직접 입출력 방식과 DMA 방식이 있다. 

  • 직접 입출력 
    • CPU가 장치 제어기 내의 레지스터하고 메모리 자료 이동을 매번 직접 관장 
    • CPU는 기본적으로 입출력 장치가 입출력을 하는 도중에도 프로세스 수행을 계속 할 수 있도록 되어있다. 하지만 이 방법 사용시 매 입출력 마다 인터럽트가 들어오기 때문에 CPU에게 상당한 부담이 될 수 있다. 
    • 따라서 이 방식은 입출력발생의 시간간격이 비교적 큰 장치들(ex> 문자 장치(chararcter device)) 캐릭터 단위로 입출력(ex> 키보드) Serial 입출력 방식이 여기에 해당한다. 
      • 반면, 대용량의 입출력 장치를 블록 장치라고 하는데(block device) (가장 대표적으로 하드디스크) 이런 장치에 직접 입출력 방식을 사용하는 것은 문제가 크다. 
    • 이걸 극복하는 방식이 DMA 방식이다.
  • DMA(Direct Memory Access)
    • 입출력장치가 CPU 도움 없이 독자적으로 메모리(시스템 버퍼)에 Direct로 접근하여 한 입출력 명령으로 많은 자료(블록)을 입출력/전송
      • 한 가지 문제가 있을 수 있는데 메모리 입장에서 CPU도 독립적으로 접근할 것이고, DMA도 독립적으로 접근을 하게 되어서 서로 간에 충돌이 일어날 수 있다. 
      • 해결 : Cycle Stealing -> CPU와 DMA가 동시에 메모리 접근을 요구한다면 DMA에 우선권을 주고, CPU는 한 사이클을 쉬게 됨. 
      • Cycle : CPU가 instruction을 수행하는데 있어서 한번에 instruction 수행하는 것이 아니라, CPU수행을 위해서는 몇번의 cycle을 돌게 되어 있다. 
      • CPU 입장에서 보면 I/O는 가끔 일어나는 셈이 된다. I/O가 일어나는 interval이 길기 때문에 우선권을 한 사이클정도는 DMA에 줘도 괜찮음
      • DMA의 주체는 하드웨어이다. 
    • 한 블록의 입출력 완료시 한번만 인터럽트 발생시켜 빈도수를 줄인다. 

3. 장치제어기 상태를 CPU로 하여금 알게 하는 방식(CPU가 장치제어기 상태를 알아내는 방식)

폴링(Polling) 방식 vs 인터럽트 방식

  • 폴링(Polling) 방식 : 상대방의 상태를 내가 주도적으로 체킹한다 -> CPU가 레지스터를 반복적으로 체크하면서 목표한 상태로 바뀌었는지 체크한다. 따라서 상태변화가 있을때까지는 CPU가 계속 대기하면서 체크하고 있다. 폴링을 위해서 디바이스 드라이브가 동작하는 내용을 순서적으로 본다면
    1. 응용 프로세스로부터 입력이 요청됨
    2. 장치구동기가 장치제어기의 명령 레지스터에 명령어 적재(장치제어기는 하드웨어이기 때문에 즉시 장치 가동)
      -> 장치 가동
    3. 상태 레지스터가 busy 상태에서 done으로 바뀔 때까지 대기(그 명령어로 인해 장치가 끝날때까지 기다림)
    4. done이 되면 제어기의 자료레지스터 내용을 응용 프로세스 공간으로 복제

  • 단점 : 루프를 사용하여(busy waiting 방식) 제어기의 상태를 체크하는 것은 CPU를 낭비하게 됨
  • 그러나, 인터럽트가 제공되지 않는 장치의 경우 일정시간 주기적으로 제어기 상태 조사

 

  • 폴링 방식을 사용하면 busy waiting으로 인하여 CPU에 부담이 가중된다. 할 수 없이 폴링 방식을 사용해야 되는 경우도 있지만 좋은 방법은 아니다. 대안은 인터럽트 방식이다.

 

  • 인터럽트 방식 : (폴링이 대기 방식이였다면 인터럽트는 알림 방식이다.)
    • CPU가 디바이스 드라이브의 코드를 실행함으로써 결국 입출력 명령을 장치 제어기에 전송을 한다. 그리고는 CPU는 다른 프로세스를 수행하고 있으면 그 요청에 뜬 입출력 작업이 다 끝났다는 것을 장치제어기가 CPU에게 알리는 것이다. 여기서 알리는 것을 인터럽트라고 부른다. 즉, 인터럽트는 장치제어기가 보내는 것이고 인터럽트는 CPU가 받는 것이다. 그래서 장치제어기가 입출력 작업이 끝나면 다 끝났다고 CPU에게 알리는 것, 그것이 interrupt라는 것이다. 
    • 인터럽트 방식은 하드웨어가 인터럽트 처리 체계를 갖고 있다는 것을 전제로 하고 있는 것이다. 
    • 인터럽트가 발생하면..
      • 1. (중단) 현재 진행중인 프로세스 또는 하위의 ISR(Interrupt Service Routine) 수행을 즉시 중단
      • 2. (문맥보존) 프로그램 카운터 (PC) 및 CPU 레지스터 값들을 보존(문맥에 해당)
      • 3. (마스크설정) 현재의 인터럽트에 해당하는 마스크를 설정하여 자신보다 하위 인터럽트가 먼저 처리되지 않도록 함(상위 하위 이런것들 판단하기 위해 마스크 설정)
      • 4. (ISR 진입) 현재의 인터럽트에 해당하는 ISR으로 제어를 넘김(즉, 프로그램 카운터를 해당 ISR의 첫주소로 셋팅) (ISR 시작주소 알아야함)
        • 인터럽트 백터 테이블에 장치번호 순서대로 ISR의 시작주소가 기록되어 있음.
    • 인터럽트 처리가 끝나면 인터럽트 당한 프로세스 또는 수행중이던 하위 ISR을 계속 실행하기 위해 보존된 레지스터 내용을 복구 <- 운영체제의 결정이 필요
      • 어떤걸 복구하냐 -> 프로세스이면 여러개 중에 운영체제의 결정이 필요하다(스케쥴링에서 필요)
  • 여러 종류의 인터럽트 간의 경쟁 조정을 위해 인터럽트 priority level을 결정할 필요가 있다
  • 다수준 인터럽트와 인터럽트 마스크
    • 시스템의 모든 장치에 대해 비트(또는 비트번호)를 지정 
      • 예를 들어서 시스템에 접속될 수 있는 장치 최대 장치 개수가 16개라 한다면 인터럽트 종류도 16개가 된다. 그렇게 하기 위해서면 2byte면 된다. 2byte라 하고 각 비트마다 하나의 인터럽트를 지정해주는 것이다. 예를 들어 디스크는 5번, 클럭은 2번 이렇게 지정. 8진수면 디스크는 040 클럭은 004
    • 인터럽트 마스크를 통해 수준(Interrupt priority level) 적용
      • 인터럽트 마스크도 2byte를 사용하겠고 그것도 장치마다 지정했던 비트를 사용한다. 인터럽트 마스크는 우선순위 비교용인데 우선순위 비교를 어떻게 하냐. 
      • 예를 들어 방금 전에 interrupt가 들어와서 이에 해당하는 ISR을 처리중인데 그 ISR에 들어가기 전에 interrupt mask를 044로 설정했다고 하자. 

      • 044면 2번이랑 5번 bit에 1이 표시되어있다. 2번이랑 5번이 아까 클럭과 디스크라 함. 무슨 뜻이냐하면 현재 ISR이 뭔가 처리중에 있는데 ISR을 위해 처리하기 바로 전에 뭐라고 마스크를 설정했냐 하면은 2번이랑 5번은 나보다 쎈 놈입니다. 그놈들이 들어오면 나를 잠시 중지시키세요하고 설정을 하고 들어갔다는 의미이다. 그게 바로 클럭하고 디스크이다. 현재 진행하고 있는 인터럽트 처리보다 클럭이나 인스턴스의 우선순위가 높으니 그것들로부터 인터럽트가 들어오면 나를 잠시 중지시켜달라. 그게 인터럽트 마스크를 설정했다는 의미이다. 
      • 그러한 상황에서 새로 인터럽트 들어왔는데 디스크 인터럽트가 떴으면 그러면 그 인터럽트는 어떻게 표현이 되냐하면 5번 비트가 1로 표현이 된다. 그래서 현재 새로 들어온 인터럽트는 00100000으로 표현이 된다. 그럼 새로 들어온 인터럽트가 더 쎈놈이냐 판단을 해야 하는데 그래서 두개사이에 AND operation을 취한다. 이게 결국에 masking을 해보는 것이다. masking을 했더니 한 bit가 맞아서 1이 되었다. 그래서 전체 값이 양수가 나왔다. 양수가 나왔다는 것은 0이 아니라는 것이고 0이 아니면 False가 아니라는 뜻이므로 새로 들어온 인터럽트가 쎄다라는 것을 판단할 수 있다. 그래서 지금 들어온 디스크 인터럽트부터 처리한다. 그게 인터럽트 마스크의 역할이다. 
      • 인터럽트 마스크를 통해 수준(Interrupt priority level) 적용
        • 임의 인터럽트가 들어오면 해당 인터럽트와 현재의 마스크를 비교하여(마스킹) 우선순위 판단 
        • 그래서 인터럽트 마스크를 항상 설정해주어야 한다. 언제 설정하냐 -> 인터럽트의 ISR시작에 앞서서 인터럽트 마스크를 재설정하고, ISR 종료시 원상복구 해준다. -> 디바이스 드라이브 만드는 사람의 책임이다. 

 

 

  • Q> 가장 순위가 낮은 인터럽트(아마도 키보드 인터럽트), 키보드 인터럽트의 ISR을 처리하는 동안에는 인터럽트 마스크는 어떻게 설정되어 있을까? 당연히 모든 비트가 1로 setting된 0177777이 될것이다.
  • 이 말은 어떠한 interrupt가 와도 새로운 인터럽트를 처리해도 된다는 뜻이다. 
  •  

 

  • 만약 키보드 인터럽트를 처리중에 있다가 네트워크 장비로부터 인터럽트가 들어오면 키보드 인터럽트보다는 네트워크 인터럽트가 우선순위가 높으니까 당연히 현재 처리중인 것은 중단이 되고 네트워크 인터럽트를 처리하러 들어간다. 네트워크 장비에 해당하는 마스크를 044로 설정하고 들어갔다 하자. 즉, 2번과 5번, 클럭과 디스크에 해당하는 장치만 나보다 높다라는 뜻. 그렇게 해서 네트워크 인터럽트를 처리하는 도중에 디스크 인터럽트가 떴다. 그럼 다시 마스크를 004로 설정하고 디스크 인터럽트에 들어간다. 그래서 클럭이라는 것은 2번비트에 표현하고 디스크 인터럽트 ISR 처리하기 위해 들어간다. 즉 자신보다 인터럽트 높은건 지금 클럭밖에 없기때문에. 누가 우선순위 높은지는 빠르게 판단하기 위하여 하드웨어 기준으로 이루어져야 한다. 즉, 마스킹 오퍼레이션은 하드웨어적으로 이루어진다. 이를 위해 AND 연산을 한번만 사용하면 masking operation이 되도록. 즉 디스크로부터 인터럽트가 들어왔다는 것은 004, 네트워크장비는 044, 두개를 AND연산하면 0이 아니므로 더 쎈 인터럽트가 들어왔다는 의미가 됨. 그래서 바로 디스크 인터럽트 처리를 위한 ISR이 된다. 
  • Fast interrupt Handler(FIQ) => 지엽적인 내용이긴함
    • Fast Interrupt : 특별히 빠른 처리 혹은 빠른 반응을 위해 ISR에서 다른 인터럽트 처리를 disable 시키고 짧은 시간에 처리를 마무리하는 것을 의미한다. 시스템에서는 clock 같은 것들이 중요한데 clock interrupt같은 것들은 fast interrupt로 처리한다. 
    • 너무 자주하면 시스템적으로 문제 생길 수 있다. 

 

인터럽트

 

하드웨어에 의한 보호

 

캐시와 기억 장치 구조

 

728x90
반응형

'CS > 운영체제' 카테고리의 다른 글

[5] 프로세스  (0) 2022.03.24
[4] 컴퓨터 구조와 OS 연계  (0) 2022.03.21
[2] 시분할 시스템, 실시간 시스템  (0) 2022.03.09
[1] 운영체제의 발전  (0) 2022.03.07
프로세스의 연산  (0) 2020.11.03

+ Recent posts