제한적 직접 실행 원리
- CPU 시간을 나누어 씀 => 가상화 구현
가상화 기법을 구현하기 ㅇ
- 가상화 기법을 구현하기 위한 몇가지 문제를 해결해야함:
- 성능저하
- 과중한 오버헤드
- 제어 문제
- CPU에 대한 통제를 유지하면서 프로세스를 효율적으로 실행시킬 수 있는 방법?
- 성능저하
기본 원리: 제한적 직접 실행
- Limited Direct Execution
- 프로그램을 CPU상에서 직접 실행
- 시분할을 어떻게 구현?(직접 실행시 아래의 두 문제 발생)
- 어떻게 운영체제가 원치않는 일을 수행함을 방지?
- OS가 어떻게 프로그램을 중단하고 다른 프로세스로 전환?
문제점 1: 제한된 연산
직접 실행의 장점: 빠르게 실행
- 특수한 종류의 연산을 어떻게? (디스트 IO, 시스템 자원 요청 등)
접근 권한을 검사하는 파일 시스템을 구현
- 프로세스가 디스크에 대하여 입출력하는 것을 제한하지 않으면, 프로세스는 전체 디스크를 읽고 쓸 수 있기 때문에 접근 권한을 검사하는 기능이 아무런 의미가 없음
- 이로인해 사용자 모드(user mode) 도입됨
- 사용자 모드에서 실행되는 코드는 하는 일이 제한될 수 있음 (io요청 제한 등)
- 커널 모드(kernel mode)
- os의 중요한 코드들이 실행됨
- 특수한 명령어 + 원하는 작업 모두 수행 가능
사용자 프로세스가 디스크 읽기와 같은 특권 명령어를 실행해야 할 때
- HW는 사용자 프로세스에게 시스템 콜을 제공
- Atlas와 같은 커널
- 시스템 콜을 통하여 자신의 주요 기능을 사용자 프로그램에게 제공
- 파일 시스템 접근, 프로세스 생성 및 제거, 다른 프로세스와의 통신, 메모리 할당 등
팁: 보호된 제어 양도: HW는 두가지 실행모드로 os를 도움 (유저 모드, 커널 모드), os 가 HW에게 트랩 테이블(trap table)의 메모리 주소를 알려주기 위한 명령어도 함께 제공
시스템 콜: trap 명령문
- 커널안으로 분기하는 동시에 특권 수준을 커널 모드로 상향 조정
- 커널 모드로 진입하면 os는 모든 명령어를 실행할 수 있음
- 이를 통하여 프로세스가 요청한 작업을 처리 가능
- 완료되면 return-from-trap 특수 명령어 호출
- 특권수준 유저모드로 하향조정
- 주의 사항
- 호출한 프로세스의 필요한 레지스터들을 저장해야함
- OS 가 return-from-trap 명령어 실행 시 사용자 프로세스로 제대로 리턴할 수 있도록 하기 위함
- x86: PC, 플래그 등 레지스터를 커널 스택에 저장, 스택에서 pop 하여 유저 모드 프로그램의 실행을 다시 시작
- 호출한 프로세스의 필요한 레지스터들을 저장해야함
- trap의 권한
- 호출한 프로세서는 분기할 주소를 명시 불가
- 주소를 명시: 커널 내부의 원하는 지점을 접근할 수 있음 -> 위험
- 커널이 임의 코드를 실행하기 위해서는 접근 권한 검사가 끝난 후 분기해야함
- trap이 어떤 코드를 실행할지를 통제
- 호출한 프로세서는 분기할 주소를 명시 불가
- 컴퓨터 부팅 시 하는 작업
- 트랩 테이블: 커널이 부팅 시 만듦 (부트 시에는 커널 모드임)
- OS가 하는 초기 작업
- 하드웨어에게 예외 사건이 일어났을 때 어떤 코드를 실행해야 하는지 알려주는 것
- OS는 특정 명령어를 사용하여 HW에게 트랩 핸들러의 위치를 알려줌, 이를 통해 시스템 콜과 같은 예외적인 사건이 발생했을 대 하드웨어는 무엇을 해야할지 알 수 있음
시스템 콜과 프로시저 콜: open 과 read 의 시스템 콜은 C 프로그램의 프로시저 호출의 형태와 똑같음. 시스템 콜은 프로시저 호출이지만, trap 명령어가 감추어져 있음 (어셈블리어로 작성됨)
제한적 직접 실행 프로토콜
OS 부트 (커널모드) | 하드웨어 |
---|---|
트랩 테이블을 초기화 | syscall 핸들러의 주소를 기억 |
OS 실행 (커널모드) | 하드웨어 | 프로그램 (사용자모드) |
---|---|---|
프로세스 목록에 항목 추가, 프로그램을 위한 메모리 할당, 프로그램을 메모리에 탑재, argv를 사용자 스택에 저장, 레지스터와 pc를 커널 스택에 저장, return-from-trap | ||
커널 스택으로부터 레지스터를 복원, 사용자 모드로 이동, main으로 분기 | ||
main 실행, 시스템 콜 호출, trap | ||
레지스터를 커널 스택에 저장, 커널 모드로, 트랩 핸들러로 분기 | ||
트랩을 처리, syscall의 임무를 수행, return-from-trap | ||
커널 스택으로부터 레지스터를 복원, 사용자 모드로 이동, 트랩 이후의 PC로 분기 | ||
main에서 리턴, trap(exit()) | ||
프로세스의 메모리 반환, 프로세스 목록에서 제거 |
- LED 프로토콜의 두 단계
- 부팅시
- 커널은 트랩 테이블 초기화
- CPU는 테이블 위치 기억
- 프로세스 실행시
- return-from-trap으로 프로세스를 위한 작업 수행
- 새로운 프로세스를 위한 노드를 할당, 프로세스 리스트에 삽입, 메모리를 할당
- return-from-trap 명령어 -> CPU를 사용자 모드로 전환, 프로세스 실행을 시작
- 프소세스가 시스템 콜을 호출 -> OS로 트랩
- OS는 시스템 콜 처리, return-from-trap -> 제어를 프로세스에 넘김
- 프로세스는 끝에 main()에서 리턴 (스텁 코드로 리턴 -> 스텁 코드가 프로그램 종료 -> exit 시스템 호출 -> OS로 트랩 -> 정리작업)
- 부팅시
문제점2: 프로세스 간 전환
- CPU에서 프로세스가 실행 중 = OS는 실행 중 X
협조 방식: 시스템 콜 기다리기
- 초기방식
- 너무 오랫동안 실행할 가능성이 있는 프로세스는 OS가 다른 작업을 실행할 결정을 할 수 있도록 주기적으로 CPU를 포기
- 프로세스가 호출하는 시스템콜: 파일 처리, 다른 컴퓨터에 메시지 송신, 새 프로세스 생성
- OS는 yield 시스템 콜을 제공
- yield 시스템 콜: OS에게 제어를 넘겨 OS가 다른 프로세스를 실행할 수 있게함
- OS는 yield 시스템 콜을 제공
- APP이 비정상적인 행위를 하면 OS에게 제어가 넘어감
- 트랩이 일어나 OS가 cpu를 다시 획득, 해당 프로세스 종료
- 협조방식의 스케줄링 시스템에서 OS는 시스템 콜이 호출되길 기다림
- 프로세스가 무한 루프에 빠지면?
- 컴퓨터 재부팅이 답
- 프로세스가 무한 루프에 빠지면?
비협조 방식: OS가 전권을 행사
- 프로세스가 시스템 콜을 호출하기를 거부하거나 실수로 호출하지 않아 OS에게 제어를 넘기지 않을 경우
- HW의 추가적인 도움 없이는 OS가 할 수 있는 일은 거의 없음
- 해결책: 타이머 인터럽트(timer interrupt)를 이용하는 것
- 타이머 장치는 수 밀리 초마다 인터럽트를 발생시키도록 프로그램 가능.
- 인터럽트 발생 -> 현재 수행 중인 프로세스는 중단, 인터럽트 핸들러가 실행됨
dto.setIsbn( rs.getString(“isbn”)); dto.setTitle( rs.getString(“title”)); dto.setAuthor( rs.getString(“author”)); dto.setPrice( rs.getInt(“price”)); dto.setDesc( rs.getString(“desc”)); dto.setImg( rs.getString(“img”));
- 타이머 장치는 수 밀리 초마다 인터럽트를 발생시키도록 프로그램 가능.
핵심 질문
제어를 유지하면서 효과적으로 CPU를 가상화 하는 방법?
- OS는 CPU를 가상화 but 시스템에 대한 제어를 잃지 않음
- 하드웨어 + 운영체제의 지원이 필수적
- 제한 연산을 수행하는 방법?
- 프로세스는 시스템 권한이 없기 때문에.. 제한된 연산을 수행 불가
- 이 일을 위해 OS와 HW가 할 일은?
- OS는 CPU를 어떻게 다시 획득, 프로세스 전환?
APP의 오작동 처리: 오작동하는 프로세스: 악의적으로 설계되었거나 버그 때문에 금지행동을 하는 프로세스 OS는 단순히 행위자를 종료시킴
- 협조 없이 제어를 얻는 방법?