CPU가 갖는 실행 권한 수준. 하드웨어를 직접 다루는 명령은 커널 모드에서만 실행된다.
왜 나누나
-
모든 프로그램이 하드웨어를 직접 만질 수 있다면
- 남의 메모리를 읽고 쓴다
- 디스크를 통째로 지운다
- CPU 를 독점해 다른 프로그램이 못 돈다
-
하드웨어에 직접 닿는 명령을 '특권 명령' 으로 지정하고
- 커널 모드에서만 실행되게 막는다
두 모드가 실제로 다른 것
-
유저 모드 — 일반 연산·자기 주소 공간 접근만 가능
- 특권 명령을 시도하면 예외(trap) 가 발생한다
-
커널 모드 — 전체 메모리 · I/O 포트 · 인터럽트 제어 · 페이지 테이블 조작 가능
x86은 링 0(커널)~링 3(유저)의 4단계를 제공하지만 실제로는 0과 3만 쓴다.
전환 비용
유저 → 커널 전환에 드는 일
-
레지스터 저장
-
스택 전환 (유저 스택 → 커널 스택)
-
권한 검사
-
돌아올 때 복원
-
수십~수백 나노초. 함수 호출보다 훨씬 비싸다
-
시스템 콜을 자주 부르면 이 비용이 쌓인다
- (그래서 버퍼링·배치 I/O 가 성능에 크게 기여한다)
가상화와의 관계
하이퍼바이저는 커널보다 더 높은 권한이 필요하다
- Intel VT-x · AMD-V 가 '링 -1' 에 해당하는 계층을 하드웨어로 제공
- 게스트 커널이 링 0 이라 믿게 두면서도 실제 하드웨어는 못 만지게 한다
시스템 콜은 어떻게 모드를 넘나
- ① 유저 코드가 라이브러리 래퍼(glibc 의 read())를 호출
- ② 시스템 콜 번호를 레지스터에 넣고 syscall 명령 실행
- ③ CPU 가 커널 모드로 전환하고 미리 등록된 진입점으로 점프
- ④ 커널이 번호로 테이블을 조회해 해당 핸들러 실행
- ⑤ 결과를 레지스터에 담고 sysret 으로 유저 모드 복귀
진입점을 하드웨어가 강제한다는 점이 핵심이다 유저가 "커널의 임의 주소로 점프" 를 할 수 없다
왜 CPU 가 직접 지원해야 하나
소프트웨어만으로는 권한 분리를 만들 수 없다. 검사 코드 자체를 우회하면 그만이기 때문이다. 그래서 현재 권한 수준을 CPU 레지스터가 들고 있고, 특권 명령은 그 값을 하드웨어가 확인한 뒤에만 실행된다. 값을 바꾸는 것 역시 특권 연산이므로 유저 코드가 스스로 승격할 방법이 없다.
비용을 줄이는 기법
- vDSO — 시간 조회처럼 읽기만 하는 호출을 커널이 유저 공간에 매핑
- gettimeofday() 가 모드 전환 없이 끝난다
- io_uring — 링 버퍼를 유저·커널이 공유해 시스템 콜 없이 요청을 쌓는다
- 배치 I/O — writev · sendmmsg 로 여러 건을 한 번에 넘긴다
면접 함정
- ❌ "함수 호출과 시스템 콜은 비슷한 비용" → 모드 전환이 있어 훨씬 비싸다.
- ❌ "커널 모드는 커널 코드만" → 유저 프로세스도 시스템 콜 중에는 커널 모드로 실행된다.