본 정리는 운영체제(Operating System: Concepts) 9th edition과 22학년도 1학기 건국대학교 운영체제 수업을 바탕으로 하고 있습니다.
운영체제를 살펴보는 관점에는 3가지가 있다.
1. 운영체제가 제공하는 서비스
2. 운영체제가 사용자 및 프로그래머에게 제공하는 인터페이스
3. 시스템의 구성 요소와 그들의 상호 연결
지난번 포스팅에 운영체제가 사용자 및 프로그래머에게 제공하는 인터페이스인 시스템 콜에 대하여 알아보았다.
참고: https://developbear.tistory.com/95
더욱 자세히 들어가 커널이 하드웨어에게 명령을 내리기 위해 존재하는 인터페이스인 커널-드라이버 인터페이스, HW 인터페이스에 대하여 알아보도록 하자.
입출력 시스템
사용자가 시스템 콜을 통해 커널에서 어떤 함수를 동작하면, 그에 알맞은 동작(파일 읽기, 사용자의 입력받기 등)을 위하여 하드웨어를 통한 입출력을 할 필요가 있다.
이때 사용되는 것이 바로 입출력 시스템이다.
디바이스 컨트롤러에는 3가지 레지스터가 있다.
- 명령 레지스터 : 장치가동을 위한 명령 코드 적재
- 상태 레지스터: busy/done 플래그, 오류코드 표현
- 자료 레지스터: 장치 내의 하드웨어 버퍼
하드웨어 입출력은 3가지 인터페이스를 거쳐서 진행된다.
- 응용 프로그램과 커널 사이 : 시스템 콜
- 커널과 장치제어기 사이 : HW 인터페이스
- 커널과 디바이스 드라이버 사이 : 커널-드라이버 인터페이스
커널은 커널-드라이버 인터페이스를 통해 디바이스 드라이버에 하드웨어가 알맞은 동작을 하기 위한 명령을 내리고,
디바이스 드라이버는 시스템 콜을 하드웨어 기능으로 번역하여 HW 인터페이스를 통해 장치 제어기에 전달한다.
이제 명령을 받은 디바이스 컨트롤러는 하드웨어에 레지스터를 통해 명령을 내린다.
이렇게 인터페이스로 구성한 이유는 대부분의 인터페이스가 그렇듯 갈아 끼우기 쉽게 하기 위함이다.
하드웨어가 바뀐다고 운영체제가 바뀌어야하는가? 전혀 아니다.
인터페이스를 통하여 커널 드라이버만 바뀌어도 운영체제는 바뀔 필요가 없는 plug&play 기능을 가능하게 했다.
HW(HardWare) 인터페이스
하드웨어 인터페이스의 하드웨어 경영 방식들을 알아보자.
- 접근 방식에 의한 분류
- 격리형(isolated I/O)
메모리와는 별도의 주소공간 사용, 디바이스 컨트롤러의 레지스터 접근을 위하여 특수한 입출력 명령어를 사용한다. 입출력이 메모리 주소 공간의 할당에 영향을 주진 않지만 특수 명령어가 추가되어 프로그래밍의 일관성이나
이식성이 떨어진다. - 메모리 사상형(Memory-Mapped IO)
별도의 주소공간을 사용하지 않고 메모리의 논리적 주소 공간에 디바이스 컨트롤러의 레지스터를 사상한다. 기존의 메모리 접근 명령어(load store)를 사용하여 접근할 수 있다. 이로 인해 프로그래밍이 용이해지지만, 메모리 영역을 일부 사용하여야 한다.
- 격리형(isolated I/O)
- 자료 이동 방식에 의한 분류
- 직접 입출력
CPU가 메모리와 제어기의 자료 레지스터 사이의 자료 이동을 직접 관장한다. CPU가 입출력을 동시에 처리할 수 있지만 매 입출력을 위하여 인터럽트를 처리하여야만 한다.
문자 장치는 한 바이트 씩만 인터럽트를 걸면 되기 때문에 문제가 되지 않지만, 디스크와 같이 블록 장치의 경우에
는 문제가 된다. (1블록이 8바이트라면 8번의 인터럽트를 걸어야만 한다. → 성능의 저하)
- DMA(Direct Memory Access)
디바이스 컨트롤러가 CPU 도움 없이 독자적으로 메모리(시스템 버퍼)에 접근하여 한 입출력 명령으로 많은 자료(블록)을 입출력/전송한다. 한 블록의 입출력 완료 시 한 번만 인터럽트를 발생시키면 되기 때문에 인터럽트 빈도수가 줄어든다.
CPU는 계속 자기의 일을 하고 있기 때문에 입출력이 끝나 데이터가 들어왔다는 인터럽트만 주면 된다.
Cycle Stealing - CPU와 DMA가 동시에 메모리 접근을 요구하면 DMA에 우선권으로 주고, CPU는 한 사이클을 쉬게 됨
- 직접 입출력
- 제어 방법에 의한 분류(제어기 상태 변화 전달 방식)
- 폴링(polling) 방식
1. 응용 프로세스로부터 입력이 요청됨
2. 장치 구동기가 장치 제어기의 명령 레지스터에 명령어 적재 → 장치 가동
3. 상태 레지스터가 busy 상태에서 done으로 바뀔 때까지 대기
4. done이 되면 제어기의 자료 레지스터 내용을 응용 프로세스 공간으로 복제
루프를 사용하여 하드웨어가 사용 중인지 주기적으로 계속 확인하므로 CPU가 낭비된다. - 인터럽트 방식
1. (중단) 현재 진행 중인 프로세스 또는 하위의 ISR (Interrupt Service Routine) 수행을 즉시 중단
2. (문맥 보존) 프로그램 카운터 (PC) 및 CPU 레지스터 값들을 보존
3. (마스크 설정) 현재의 인터럽트에 해당하는 마스크를 설정하여 자신보다 하위 인터럽트가 먼저 처리되지 않도록 함
4. (ISR진입) 현재의 인터럽트에 해당하는 ISR으로 제어를 넘김(즉, 프로그램 카운터를 해당 ISR의 첫 주소로 세팅)
인터럽트 백터 테이블(IDT)에 장치 번호 순서대로 ISR의 시작 주소가 기록되어 있다.
인터럽트가 종료되면 보존된 문맥 정보에 따라 원래 실행되던 프로세스 또는 하위 ISR을 실행한다.
인터럽트에 우선순위를 부여할 수 있고, CPU의 낭비가 없어진다.
- 폴링(polling) 방식
시스템 콜이 처리되는 과정 총 정리
read(buf) 함수가 불리는 과정을 커널과 응용 프로그램의 관점에서만 봤었는데, 이번엔 하드웨어까지 포함하여서 정리해보자.
1. user process에서 read함수(API 함수) 호출
2. API(라이브러리) 함수 실행 system call 과정을 거쳐서 디바이스 드라이버의 sys_read() 함수가 실행된다.
2번의 자세한 과정 참고: https://developbear.tistory.com/95
3. 디바이스 드라이버의 sys_read() 함수에서 디바이스 컨트롤러의 명령 레지스터에 read 명령을 적재한다.
4. 이제 입출력이 완료되는 동안 sys_read()는 계속 실행될 필요가 없으니 CPU를 점유하지 않고 sleep() 함수가 실행되고 다른 프로세스로 스케줄링된다.
5. 장치 제어기는 DMA를 통해 메모리로부터 데이터를 가져와 버퍼에 저장한다.
6. 해당 작업이 모두 끝나면 CPU로 인터럽트를 보내고, IDT를 통해 인터럽트에 알맞은 ISR을 실행한다.
7. 완료 시에 다시 sys_read() 함수가 깨어나서 재실행되고, 버퍼에 저장된 값을 buf에 copy 하고 read(buf)에 알맞은 값을 반환해준다.
세세하게 또 어렵게 정리했지만 요점은
응용프로그램(read)→ 시스템 콜 → 커널(IDT, ISR) → 커널-드라이버 인터페이스 → 디바이스 드라이버(sys_read) → HW인터페이스 → 디바이스컨트롤러(명령 레지스터에 알맞게 DMA, 종료 후 CPU로 인터럽트) → 커널(IDT, ISR) → 커널-드라이버 인터페이스 → 디바이스 드라이버(sys_read) -> 반환
이렇게 인터페이스를 통하여 가장 하단인 하드웨어까지 명령이 전달되었다가 다시 반환된다는 것과 각각의 곳에서 어떤 처리를 하는지 이해만 하면 되겠다.
'CS > 운영체제' 카테고리의 다른 글
[OS] Call Stack Frame (0) | 2022.08.16 |
---|---|
[Chapter 3. 프로세스] 프로세스와 문맥 (0) | 2022.08.16 |
[Chapter 2. 시스템 구조] 이중 연산 모드와 모드 비트 (0) | 2022.08.14 |
[Chapter 2. 시스템 구조] 시스템 호출 (System Call) (0) | 2022.08.13 |
[Chapter 2. 시스템 구조] 운영체제가 제공하는 서비스 (0) | 2022.08.11 |