3 minute read

가상화 구현시 문제점

  1. 성능 저하: 시스템에 과중한 오버헤드를 줄이고 가상화를 구현할 수 있을까?
  2. 제어 문제: CPU에 대한 통제를 유지하면서 프로세스를 효율적으로 실행시킬 수 있는 방법은 무엇인가?
    • 즉, 제어를 유지하면서 효과적으로 CPU를 가상화하기 위해선 하드웨어운영체제의 지원이 필수적이다.

기본 원리: 제한적 직접 실행(Limited Direct Execution)

  • 프로그램을 CPU 상에서 직접 실행시키는 것이다.

문제점 1: 제한된 연산

  • 프로세스는 입출력 연산이나 메모리와 같은 시스템 자원에 대한 추가 할당 요청 등의 제한된 연산을 수행할 수 없다.
    • 사용자 모드(user mode)커널 모드(kernel mode)가 도입되었다.
      • 사용자 모드에서 실행되는 코드는 할 수 있는 일이 제한되고, 커널모드에서는 모든 작업을 할 수 있다.

Screen Shot 2022-12-11 at 5 45 46 PM

시스템 콜(system call)과 트랩(trap)

  • 현대 하드웨어는 사용자 프로세스가 특권 명령을 실행할 수 있게 하기 위해 시스템 콜(system call)을 제공한다.
  • 시스템 콜을 실행하기 위해서는 trap 특수 명령어를 실행해야 한다. 이 명령어는 커널 안으로 분기하는 동시에 특권 수준을 커널 모드로 상향 조정한다.
  • 시스템콜이 완료되면 운영체제는 return-from-trap 특수 명령어를 호출하고, 특권 수준을 사용자 모드로 하향하면서 호출한 사용자 프로그램으로 리턴한다.
  • 운영체제가 return-from-trap 실행 시 사용자 프로세스로 제대로 리턴할 수 있도록 플래그, 레지스터 들을 각 프로세스의 커널 스택(kernel stack)에 저장한다.
    trap이 운영체제 코드의 어디를 실행할 지 어떻게 아는가? 
    호출한 프로세서는 분기할 주소를 명시할 수 없다.
    주소를 명시한다는 것은 커널 내부의 원하는 지점을
    접근할 수 있다는 것이기에 위험하다.
    
  • 커널은 부팅시에 트랩 테이블(trab table)을 만들어 시스템을 통제한다.
  • 운영체제는 하드웨어에게 예외 사건이 일어났을 때 어떤 코드를 실행해야 하는지 알려준다.
    • 운영체제는 특정 명령어를 사용하여 하드웨어에게 트랩 핸들러(trap handler)의 위치를 알려준다.
    • 따라서, 시스템 콜과 같은 예외적인 사건이 발생했을 때 하드웨어는 어느 코드로 분기하여 실행할 지 알 수 있다.
  • 하드웨어에게 트랩 테이블의 위치를 알려주는 것은 매우 강력한 기능이다. 사용자에게 이 명령어를 실행하려고 하면 운영체제는 그 프로세스를 제거한다.

Screen Shot 2022-12-11 at 5 45 35 PM

문제점 2: 프로세스 간 전환

CPU에서 프로세스가 실행 중이라는 것은
운영체제는 실행 중이지 않다는 것을 의미한다.
운영체제가 실행하고 있지 않다면, 프로세스간 전환을 어떻게 하겠는가?

협조 방식: 시스템 콜 기다리기

  • 대부분의 프로세스는 자주 시스템 콜을 호출하여 CPU의 제어권을 운영체제에게 넘겨준다. yield 시스템 콜은 운영체제가 다른 프로세스를 실행할 수 있게 한다.
  • 악의적이든 버그든 무한 루프에 빠져 시스템 콜을 호출할 수 없게 되었을 때 운영체제가 할 수 있는 일은 무엇인가?

비협조 방식: 운영체제가 전권 행사

  • 이러한 문제를 해결하기 위해 타이머 인터럽트(timer interrupt)를 이용한다.
  • 타이머 장치는 수 밀리 초마다 인터럽트를 발생시킨다. 인터럽트가 발생하면 현재 수행 중인 프로세스는 중단되고 미리 구성된 운영체제의 인터럽트 핸들러(interrupt handler)가 실행된다.
    • 인터럽트 발생 시 하드웨어는 실행 중이던 프로세스의 상태를 저장하여 나중에 refurn-from-trap 명령어가 프로그램을 다시 시작할 수 있도록 한다.
    • 프로세스 전환을 위하여 운영체제는 어셈블리 코드를 사용하여 현재 실행 중인 프로세스의 범용 레지스터, PC뿐 아니라 현재 커널 스택 포인터를 저장한다. 그리고 곧 실행될 프로세의 범용 레지스터, PC를 복원하고 커널 스택을 이 프로세스의 커널 스택으로 전환된다.
    • 이 과정에서 두 번의 레지스터의 저장/복원이 일어난다.
      • 첫 번째는 타이머 인터럽트가 발생했을 때 일어난다.
        • 실행 중인 프로세스의 사용자 레지스터가 하드웨어에 의해 암묵적으로 저장되고 저장 장소로 해당 프로세스의 커널 스택이 사용된다.
      • 두 번째는 운영체제가 A에서 B로 전환하기로 결정했을 때 일어난다.
        • 커널 레지스터는 운영체제에 의하여 해당 프로세스의 프로세스 구조체에 저장된다. 이것은 운영체제가 A가 아닌 B로부터 커널로 트랩된 것처럼 만든다.

Screen Shot 2022-12-11 at 5 45 19 PM

시스템 콜을 처리하는 도중 타이머
인터럽트가 발생하면 어떤 일이 발생하는가?

하나의 인터럽트를 처리하고 있을 때
다른 인터럽트가 발생하면 어떤 일이 생기는가?
  • 병행성 문제
    • 운영체제는 인터럽트를 처리하는 동안 인터럽트를 불능화시킨다.

프로세스 전환 어셈블리 코드

.globl switch
switch:
    # Save old register
    movl 4(%esp), %eax     # old포인터를 eax에 넣는다.
    popl 0(%eax)           # old IP를 저장한다.
    movl %esp, 4(%eax)     # 그리고 스택
    movl %ebx, 8(%eax)     # 그리고 다른 레지스터
    movl %ecx, 12(%eax)
    movl %edx, 16(%eax)
    movl %esi, 20(%eax)
    movl %edi, 24(%eax)
    movl %ebp, 28(%eax)
	
    # Load new register
    movl 4(%esp), %eax     # new포인터를 eax에 넣는다.
    movl 28(%eax), %ebp    # 다른 레지스터를 복원한다.
    movl 24(%eax), %edi
    movl 20(%eax), %esi
    movl 16(%eax), %edx
    movl 12(%eax), %ecx
    movl 8(%eax), %ebx
    movl 4(%eax), %esp     # 스택은 이 지점에서 전환된다.
    pushl 0(%eax)          # 리턴 주소를 지정된 장소에 넣는다.
    ret                    # 마지막으로 new문맥으로 리턴한다.

참고 자료

  • 운영체제: 아주 쉬운 세 가지 이야기