03. syscall

  • Haram Lee
  • 2026-04-14
  • studies / 26-1 / operating-systems

Interrupt, System Call, Upcall

  • trap: software exception
  • Privileged instruction
    • 어플리케이션이 중요한 지시를 수행하지 않도록 보호한다.
  • Memory protection
    • 어플리케이션이 다른 어플리케이션이나 커널의 메모리에 접근하는 것을 막는다.
  • (Timer) interrupt
    • 운영체제가 어플리케이션으로부터 통제권을 다시 얻도록 한다.

Mode switch: User → Kernel

  1. Interrupts
    • 바깥에서 들어온 사건 때문에 커널이 개입하는 경우, 외부 하드웨어가 발생시키는 사건.
    • e.g., timer and I/O
  2. exceptions
    • 현재 실행 중인 프로그램의 동작 때문에 발생하는 사건
    • e.g., 잘못된 메모리 접근, 0으로 나누기, 보호 규칙 위반
  3. system calls (implemented using the exception mechanism)
    • 프로세스가 커널에게 정식으로 일을 부탁하는 경우
    • exception mechanism 위에 구현
    • 즉 하드웨어 입장에서는 시스템 콜도 일종의 trap/exception처럼 처리되지만, 운영체제 설계 관점에서는 제한된 수의 carefully coded entry points, 즉 아주 엄격하게 준비된 공식 입구를 통해 커널 서비스를 요청하는 방식이라고 본다.

Mode switch: Kernel → User

  1. 새로운 process나 thread가 시작될 때
    • 이때 커널은 해당 프로그램의 실행 환경을 다 준비한 뒤, 프로그램의 첫 번째 instruction 부터 실행되도록 넘겨준다.
  2. interrupt, exception, system call 처리 후 원래 실행 흐름으로 돌아갈 때
    • 사용자 프로그램이 실행 중이었는데 interrupt가 들어오면 잠깐 커널이 처리하고, 끝나면 다시 그 프로그램의 중단된 지점부터 실행을 이어간다.
  3. context switch
    • 커널이 꼭 원래 실행 중이던 프로세스로 되돌아가야 하는 것은 아니다.
    • 인터럽트를 처리하고 나서 스케줄러가 판단했을 때, 지금은 다른 프로세스를 돌리는 것이 더 적절하다면 커널은 다른 process/thread의 문맥을 복원해서 user mode로 내려보낼 수 있다.
  4. user-level upcall (UNIX signal)
    • 커널이 사용자 프로그램에게 비동기적으로 사건을 알려 주는 방식이다.
    • 어떤 signal이 도착하면, 커널은 원래 user code로 그냥 돌아가는 대신 사용자 공간 안에 준비된 signal handler 쪽으로 제어를 넘길 수 있다.
    • 즉 kernel → user 이동 중에서도 “원래 코드로 복귀"와 “사용자 handler로 진입"이 구분된다고 보면 된다.

Handling interrupts (or exceptions)

  • 현재 실행 중이던 사용자 프로그램의 상태((IP, SP)를 interrupt stack에 저장한다.
  • 상태 저장이 끝나면 CPU의 제어는 interrupt handler, ISR로 넘어간다.

Interrupt stack

  • CPU 코어마다 하나씩(per-core) 존재하고, kernel memory 안에 위치한다. 인터럽트나 예외가 발생했을 때 커널은 사용자 stack을 그대로 쓰지 않기 때문이다.
  • 보통의 프로세스/스레드는 user stack과 kernel stack을 둘 다 가지며, interrupt stack은 kernel stack의 일부이다.
  • 사용자 stack은 user space에 있으므로 신뢰할 수 없고, 커널은 자기 보호된 메모리 안에서 안전하게 상태를 저장하고 handler를 실행해야 한다. 그래서 평소에는 user stack 위에서 실행되던 프로그램이, 사건이 발생하는 순간 kernel stack 쪽으로 내려와서 그 위에 사용자 CPU 상태를 저장하고, 그다음 커널 함수 호출 프레임들을 쌓으며 처리를 진행하게 된다.

Interrupt Masking

  • interrupt handler는 interrupts off 상태에서 실행됨 / 그리고 처리가 끝나면 다시 enable된다.
  • 왜 이럴까? 이유는 간단하다. 커널이 어떤 민감한 상태를 업데이트하는 중에 또 다른 인터럽트가 들어오면 자료구조가 꼬이거나 race condition이 생길 수 있기 때문이다. 그래서 보통 인터럽트 핸들러가 실행되는 동안은 새로운 인터럽트를 잠시 막아 두고, 처리가 끝난 뒤 다시 허용한다.
  • OS kernel도 필요에 따라 직접 interrupts를 껐다 켤 수 있다.
  • CLI 는 disable interrupts, STI 는 enable interrupts다.
  • 다만 이 효과는 현재 CPU에만 적용된다는 점도 같이 강조한다. 멀티코어 환경에서 한 CPU에서 인터럽트를 끈다고 해서 시스템 전체 인터럽트가 모두 꺼지는 것은 아니다.
    • 물론 CLI/STI는 privileged instruction이다…
    • IP: 다음에 실행할 명령어 위치 / SP: 원래 유저 스택 위치
    • jmp아니고 iret: 복귀
  • 유저 코드 실행 중
    • → 인터럽트 발생
    • → CPU가 커널 모드로 들어감
    • → 유저 상태를 interrupt stack에 저장
    • → 커널이 interrupt handler 실행
    • → 저장된 상태 복원
    • iret로 user mode 복귀
    • → 유저 프로그램이 원래 하던 일 계속 수행

System call: OS trap

  • kernel handler를 일으키는 exception
  • parameter를 넘김
  • caller의 상태를 저장함
  • e.g.,
    • INT instruction (IA-32)
    • SYSCALL instruction (x86_64)
    • ECALL instruction (RISC-V)
  • count = read (fd, buffer, nbytes);

Upcall: User-level event delivery

  • 커널이 사용자 프로그램 쪽으로 이벤트를 전달하는 것.
    • system call: user → kernel
      • read(), fork()
    • interrupt: hardware → kernel
      • 타이머, 디스크 I/O 완료
    • upcall: kernel → user
      • signal 전달

Upcalls vs. Interrupts

  • signal handler = interrupt vector
  • signal stack = interrupt stack
  • signal masking = interrupt masking
Discussion