운영체제의 Dual Mode 에 대해 설명해 주세요.
CPU가 명령어를 실행할 때 사용자 모드(User Mode)와 커널 모드(Kernel Mode) 두 가지 권한 수준을 분리하여 시스템을 보호하는 운영체제의 동작 방식입니다.
왜 필요한가?
모든 프로그램이 동일한 권한을 가진다면 악의적이거나 버그 있는 프로그램이 시스템 전체를 손상시킬 수 있습니다.
[Dual Mode가 없다면]
악성 프로그램 → 디스크 포맷 명령어 직접 실행 → 시스템 파괴
버그 프로그램 → 다른 프로세스 메모리 덮어쓰기 → 시스템 불안정
[Dual Mode가 있으면]
악성 프로그램 → 특권 명령어 실행 시도 → CPU가 차단 → 프로세스만 종료
버그 프로그램 → 다른 프로세스 메모리 접근 → MMU가 차단 → 프로세스만 종료
모드 비트 (Mode Bit)
CPU 내부의 1비트 플래그로 현재 실행 모드를 나타냅니다.
| 모드 비트 | 모드 | 실행 주체 | 권한 |
|---|---|---|---|
| 0 | 커널 모드 | OS 커널, 드라이버 | 모든 명령어 실행 가능 |
| 1 | 사용자 모드 | 응용 프로그램 | 제한된 명령어만 실행 가능 |
두 모드의 상세 비교
| 항목 | 사용자 모드 | 커널 모드 |
|---|---|---|
| 모드 비트 | 1 | 0 |
| 실행 주체 | 응용 프로그램, JVM | OS 커널, 디바이스 드라이버 |
| CPU 명령어 | 일반 명령어만 | 특권 명령어 포함 전체 |
| 메모리 접근 | 자신의 가상 주소 공간만 | 전체 물리·가상 메모리 |
| 하드웨어 접근 | 불가 (시스템 콜 필요) | 직접 접근 가능 |
| I/O 장치 제어 | 불가 | 가능 |
| 인터럽트 제어 | 불가 | 가능 (cli, sti) |
| 오류 발생 시 | 해당 프로세스만 종료 | 커널 패닉 (시스템 전체 크래시) |
특권 명령어 (Privileged Instructions)
커널 모드에서만 실행할 수 있는 명령어입니다. 사용자 모드에서 실행 시 예외(Exception)가 발생합니다.
| 특권 명령어 | 설명 |
|---|---|
cli / sti | 인터럽트 비활성화 / 활성화 |
in / out | I/O 포트 직접 제어 |
hlt | CPU 정지 |
lgdt / lidt | GDT / IDT 레지스터 로드 |
mov to CR0~CR4 | 제어 레지스터 변경 |
mov to CR3 | 페이지 테이블 베이스 변경 |
wrmsr | MSR 레지스터 쓰기 |
invlpg | TLB 엔트리 무효화 |
사용자 모드에서 특권 명령어 실행 시도:
프로그램: cli 실행 (인터럽트 비활성화 시도)
│
▼
CPU: 모드 비트 = 1 (사용자 모드) → 특권 명령어 실행 불가!
│
▼
General Protection Fault 예외 발생 (벡터 13)
│
▼
커널: 해당 프로세스에 SIGSEGV 시그널 전송 → 프로세스 강제 종료
모드 전환 (Mode Switching)
사용자 모드 → 커널 모드 (3가지 경로)
| 경로 | 발생 원인 | 예시 |
|---|---|---|
| 시스템 콜 | 프로세스가 커널 기능 명시적 요청 | read(), fork(), write() |
| 인터럽트 | 하드웨어 장치가 이벤트 알림 | 키보드 입력, 타이머, 디스크 I/O 완료 |
| 예외 | 프로그램 실행 중 오류 발생 | 0으로 나누기, 페이지 폴트 |
커널 모드 → 사용자 모드
| 경로 | 설명 |
|---|---|
| sysret / iret | 시스템 콜·인터럽트·예외 처리 완료 후 복귀 |
| 새 프로세스 시작 | fork() 후 자식 프로세스가 사용자 모드로 시작 |
| 컨텍스트 스위칭 | 스케줄러가 다음 프로세스를 사용자 모드로 전환 |
┌──────────────── 사용자 모드 (모드 비트: 1) ────────────────┐
│ │
│ 응용 프로그램 실행 │
│ │ │ │ │
│ 시스템 콜 인터럽트 예외 │
│ (의도적) (비동기) (비의도적) │
│ │ │ │ │
├──────┴──────────────┴──────────────┴──── 모드 전환 ───────┤
│ │
│ 커널 모드 (모드 비트: 0) │
│ │
│ 커널이 요청 처리 │
│ │ │
│ sysret / iret │
│ │ │
├──────┴───────────────────────────────── 모드 복귀 ────────┤
│ │
│ 사용자 모드 (모드 비트: 1) │
│ 프로그램 계속 실행 │
└──────────────────────────────────────────────────────────┘
모드 전환의 비용
모드 전환은 일반 함수 호출보다 비용이 큽니다.
| 항목 | 일반 함수 호출 | 모드 전환 (시스템 콜) |
|---|---|---|
| 레지스터 저장 | 일부 (callee-saved) | 전체 레지스터 + 스택 전환 |
| 주소 공간 | 변경 없음 | 사용자 스택 → 커널 스택 전환 |
| TLB / 캐시 | 영향 없음 | 캐시 미스 증가 가능 |
| 소요 시간 | ~수 ns | ~수백 ns ~ 수 μs |
| 모드 비트 | 변경 없음 | 1 → 0 → 1 |
Dual Mode에서의 시스템 보호 체계
┌──────────────────────────────────────────────────┐
│ Dual Mode 보호 체계 │
├──────────────┬───────────────────────────────────┤
│ │ │
│ CPU 보호 │ 특권 명령어 제한 │
│ │ 사용자 모드에서 실행 시 예외 발생 │
│ │ │
├──────────────┼───────────────────────────────────┤
│ │ │
│ 메모리 보호 │ MMU + 페이지 테이블 │
│ │ 프로세스별 주소 공간 격리 │
│ │ 권한(R/W/X) 검사 │
│ │ │
├──────────────┼───────────────────────────────────┤
│ │ │
│ I/O 보호 │ I/O 명령어를 특권 명령으로 지정 │
│ │ 사용자는 시스템 콜로만 I/O 가능 │
│ │ │
├──────────────┼───────────────────────────────────┤
│ │ │
│ 타이머 보호 │ 타이머 인터럽트로 CPU 독점 방지 │
│ │ 무한루프 프로세스도 강제 선점 가능 │
│ │ │
└──────────────┴───────────────────────────────────┘
x86의 보호 링 (Protection Ring)
x86 아키텍처는 사실 4단계 권한을 지원하지만, 대부분의 OS는 Ring 0과 Ring 3만 사용하여 Dual Mode를 구현합니다.
┌───────────────────┐
│ Ring 3 │ ← 사용자 모드 (응용 프로그램)
│ ┌─────────────┐ │
│ │ Ring 2 │ │ ← 거의 미사용
│ │ ┌─────────┐ │ │
│ │ │ Ring 1 │ │ │ ← 거의 미사용
│ │ │ ┌─────┐ │ │ │
│ │ │ │Ring0│ │ │ │ ← 커널 모드 (OS 커널)
│ │ │ └─────┘ │ │ │
│ │ └─────────┘ │ │
│ └─────────────┘ │
└───────────────────┘
실제 사용:
Ring 0 = 커널 모드 (OS 커널, 드라이버)
Ring 3 = 사용자 모드 (응용 프로그램)
Ring 1, 2 = 대부분 미사용 (일부 가상화에서 활용)
Java에서의 Dual Mode
// ── 사용자 모드에서 실행 (모드 전환 없음) ──
int a = 10 + 20;
String s = "hello".toUpperCase();
List<Integer> list = new ArrayList<>();
list.add(1);
// ── 커널 모드 전환이 발생하는 경우 ──
System.out.println("hello"); // write() → 커널 모드
new FileInputStream("a.txt"); // open() → 커널 모드
new Socket("example.com", 80); // socket()+connect() → 커널 모드
Thread.sleep(1000); // nanosleep() → 커널 모드
new Thread(() -> {}).start(); // clone() → 커널 모드
byte[] big = new byte[100*1024*1024]; // mmap() → 커널 모드
Java 프로그램의 실행 흐름:
사용자 모드 ●━━━●━━━━━━━━●━━━━●━━━━━━━━━━●━━━━●
│ │ │ │
모드전환 모드전환 모드전환 모드전환
│ │ │ │
커널 모드 ●━● ●━● ●━● ●━●
println() 파일I/O 소켓연결 스레드생성