IT, 소프트웨어

8장. 입출력(Input/Output)

꿈있는 내일 2011. 2. 18. 15:24

 

Chapter 8   입출력(Input/Output)

 

이번 장은 다음과 같은 관점에서 80386의 I/O 특성을 설명한다.

 

l        I/O 포트 주소화 기법l        I/O 연산을 수행하는 인스트럭션들l        I/O 인스트럭션과 I/O 포트를 사용할 때 적용되는 보호(protection)

 

8.1 I/O 주소화(Addressing)

 

80386에서는 입출력이 다음과 같은 두 방식으로 수행된다.

 

l        독립적인 I/O 주소 공간 (특정 I/O 인스트럭션을 사용해서)을 이용하는 방법l        매모리 매핑된(memory-mapped) I/O (일반적인 용도의 피연산자 조작 인스트럭션을 사용해서)를 이용하는 방법

 

 

8.1.1. I/O 주소 공간(Address Space)

 

80386에는 독립적이고, 물리 메모리와는 구별되는 I/O 주소 공간이 있는데, 외부 16개 장치들에 사용되는 입력/출력 포트를 주소화 하는 데 사용된다. I/O 주소 공간은 각각이 8비트 포트로 주소화될 수 있는 2^16 (64K)로 구성된다; 임의의 두 개의 연속된 8-비트 포트는 16-비트 포트로 다룰 수 있다; 그리고 네 개의 연속된 8-비트 포트도 32-비트 포트로 다룰 수 있다; 그래서 I/O 주소 공간은 8-비트 포트로는 64K 포트까지, 16-비트 포트로는 32K까지, 32-비트 포트로는 16K까지 수용할 수 있다.

 

프로그램에서는 두 방식으로 포트 주소를 명시한다. 즉시(immediate) 바이트 상수를 사용했을 때, 프로그램에서 명시할 수 있는 것은 다음과 같다:

 

l        0에서 255까지 번호가 매겨진 256 8비트 포트l        0, 2, 4, …., 252, 254 로 번호가 매겨진 128 16비트 포트l        0, 4, 8, …, 248, 252 로 번호가 매겨진 64 32비트 포트

 

DX에 있는 값을 사용해서, 프로그램에서 명시할 수 있는 것은 다음과 같다.

 

l        0에서 65535까지 번호가 매겨진 8비트 포트l        0, 2, 4, …, 65532, 65534 로 번호가 매겨진 16비트 포트l        0, 4, 8, …, 65528, 65532 로 번호가 매겨진 32비트 포트

 

80386에서는 한 번에 32, 16, 8 비트를 I/O 공간에 있는 장치로 전송할 수 있다. 메모리에 있는 더블워드처럼, 32비트 포트는 32비트를 한 번만 버스를 접근해서 전송할 수 있도록 4의 짝수배로 나누어지도록 정렬되어야 한다. 메모리의 워드처럼, 16비트 포트는 16 비트가 한 번만 버스를 접근해서 전송되도록 짝수로 주소로 정렬되어야 한다. 8비트 포트는 짝수 혹은 홀수 주소에 위치할 수 있다.

 

IN과 OUT 인스트럭션으로 레지스터와 I/O 주소 공간에 있는 포트들 간에 데이터를 이동할 수 있다. INS와 OUTS 인스트럭션으로 메모리 주소 공간과 I/O 주소 공간의 포트들간에 데이터 문자열을 이동할 수 있다.

 

 

8.1.2 메모리 매핑된(Memory-Mapped) I/O

 

I/O 장치들은 80386 메모리 공간에 있을 수도 있다. 장치가 메모리 구성 요소처럼 반응을 하는 한, 프로세서에서 특별하게 처리되지 않는다.

 

메모리-매핑 I/O는 부가적으로 프로그래밍적 유연성을 제공한다. 메모리를 참조하는 어떤 인스트럭션도 메모리 공간에 있는 I/O를 접근하는 데 사용될 수 있다. 예를 들면 MOV 인트럭션은 레지스터와 포트간 데이터 전송에 사용될 수 있다; AND, OR 그리고 TEST 인스트럭션은 장치의 내부 레지스터에 있는 비트를 조작하는 데 사용될 수 있다(그림 8-1 참조). 전체 인스트럭션 셋을 통해 수행되는 메모리-맵 I/O는 원하는 I/O 장치(예를 들면, 직접적 주소, 간접 주소, 기본 레지스터, 인덱스 레지스터, 스케일링)를 선택하는 데 있어서 주소 모드들을 완전히 보완한다.

 

메모리-맵 I/O는 다른 메모리 참조처럼 보호 모드에서 실행할 때, 보호와 제어 접근에 종속적이다. 메모리 보호에 관한 것은 6장을 참조하라.

 

 

8.2 I/O 인스트럭션

 

80386 I/O 인스트럭션으로 주변 장치에서 오가는 데이터 전송을 위해 프로세서의 I/O 포트를 접근할 수 있다. 이러한 인스트럭션은 하나의 피연산자로 I/O 주소 공간에 있는 포트 주소를 갖는다. I/O 인스트럭션에는 두 부류가 있다.

 

1.       레지스터에 있는 단일 항목 전송 (바이트, 워드, 혹은 더블워드)2.       메모리에 있는 일련의 항목(바이트, 워드, 더블워드 열) 전송. 이러한 것들은 “스트링(string) I/O 인스트럭션” 혹은 “블록 I/O 인스트럭션”이라 한다.

 

 

8.2.1 레지스터 I/O 인스트럭션

 

I/O 인스트럭션인 IN 과 OUT은 I/O 포트와 EAX(32-비트 I/O), AX(16-비트 I/O) 혹은 AL(8-비트 I/O) 범용 레지스터간 데이터 이동을 위해 사용된다. IN과 OUT 인스트럭션은 인스트럭션에 코딩된 256 포트까지 있는 것 중에 하나의 주소로 직접 주소화하거나 64K 포트 주소까지 DX 레지스터를 사용해서 간접적으로 주소화 한다.

 

IN (Input from Port) 는 바이트, 워드, 또는 더블워드를 입력 포트에서 AL, AX, 혹은 EAX에 전송한다. 프로그램에서 IN 인스트럭션을 사용해서 AL을 명시한다면, 프로세서는 8비트를 선택한 포트에서 AL로 전송한다. 프로그램에서 IN인스트럭션으로 AX를 명시했다면, 프로세서는 16비트를 포트에서 AX로 전송한다. 프로그램에서 IN인스트럭션으로 EAX를 명시했다면, 프로세서는 32비트를 포트에서 EAX로 전송한다.

 

OUT (Output to Port) 는 바이트, 워드, 더블워드를 AL, AX, EAX에서 출력 포트로 전송한다. 프로그램은 IN인스트럭션과 동일한 방법으로 포트 수를 명시할 수 있다.

 

그림 8-1 메모리 맵(Memory-Mapped) I/O

 

 

 

 

8.2.2 블록(Block) I/O 인스트럭션

 

블록(혹은 스트링) I/O 인스트럭션인 INS와 OUTS는 I/O 포트들과 메모리 공간간에 데이터 블록을 이동한다. 블록 I/O 인스트럭션은 I/O 주소 공간에 포트 주소를 명시하기 위해 DX레지스터를 사용한다. INS와 OUTS는 다음을 명시하기 위해 DX를 사용한다:

 

l        0에서 65535까지의 8-비트 포트l        0, 2, 4, …, 65532, 65534 까지의 16비트 포트l        0, 4, 8, …, 65528, 65532까지의 32비트 포트

 

블록 I/O 인스트럭션은 원본이나 수신지 메모리 주소를 표시하기 위해 SI나 DI를 사용한다. 각 전송에 대해 SI나 DI는 자동적으로 플래그 레지스터에 있는 방향 비트에 명시된 것처럼 증가하거나 감소시킨다.

 

INS 와 OUTS는, 반복 접두사와 사용될 때, 블록 입력이나 출력 연산을 유발한다. REP, 반복 접두사는 INS와 OUTS를 변경해서 I/O 포트와 메모리 간 블록 데이터 전송을 가능하게 한다. 이러한 블록 I/O 인스트럭션들은 문자열에 원형들이다 (문자열 원형에 관한 보다 많은 것은 3장을 참조하라). 이것들은 프로그래밍을 단순화하고 별도의 LOOP 인스트럭션이나 데이터를 저장하기 위해 즉시 레지스터를 사용할 필요가 없기 때문에 데이터 전송 속도를 증가시킨다.

 

문자열 I/O 원형은 바이트 문자열, 워드 문자열, 혹은 더블워드 문자열에 동작할 수 있다. 각 전송 후에, ESI나 EDI의 메모리 주소는 바이트에 피연산자에 대해서는 1, 워드 피연산자에 대해서는 2, 혹은 더블 워드 피연산자에 대해서는 4만큼 갱신된다. 방향 플래그(DF) 값은 프로세서가 자동으로 ESI 혹은 EDI(DF=0)를 증가시킬 것인지 혹은 이 레지스터를 감소시킬 것인지(DF=1)를 결정한다.

 

INS (Input String from Port)는 바이트나 워드 문자열 요소를 입력 포트에서 메모리로 전송한다. INSB, INSW, INSD들은 명시적으로 피연산자의 크기를 지정하는 변형된 형태이다. 프로그램에서 INSB를 명시한다면, 프로세서는 8비트 데이터들을 선택한 포트에서 ES:EDI가 가리키는 메모리 위치로 이동시킨다. 프로그램에서 INSW를 명시한다면, 프로세서는 16 비트 데이터들을 포트에서 ES:EDI가 가리키는 메모리로 이동시킨다. 프로그램에서 INSD를 지정한다면, 프로세서는 32비트 데이터를 ES:EDI가 가리키는 메모리 위치로 이동시킨다. 수신지 세그먼트 레지스터 선택(ES)은 INS 인스트럭션에서는 변경될 수 없다. REP 접두사와 함께, INS는 입력 포트의 인련의 정보 블록을 연속적인 메모리 위치로 이동시킨다.

 

OUTS (Output String to Port) 는 바이트, 워드, 더블워드 문자열 요소를 메모리에서 출력 포트로 전송한다. OUTSB, OUTSW, 그리고 OUTSD들은 명시적으로 피연산자의 크기를 지정하는 변형된 형태들이다. 프로그램에서 OUTSB를 명시한다면, 프로세서는 ES:EDI가 가리키는 8비트 메모리 데이터를 선택한 포트에 전송한다. 프로그램에서 OUTSW를 사용하면, 프로세서는 ES:EDI가 가리키는 메모리에서 16비트 데이터를 선택한 포트로 전송한다. 프로그램에서 OUTSD를 사용하면, 프로세서는 ES:EDI가 가리키는 메모리에서 32비트 데이터를 선택한 포트로 전송한다. REP 접두사와 같이 사용해서 OUTS는 일련의 정보블록을 ES:EDI가 가리키는 연속된 메모리 위치에서 출력 포트로 전송한다.

 

 

8.3.1 I/O 특권 레벨

 

I/O를 조작하는 인스트럭션은 제약될 필요가 있고 또한 0이 아닌 특권 레벨에서 실행되는 프로시져에 의해서 실행될 필요가 있다. 이러한 이유로 프로세서는 I/O 특권 레벨(IOPL)을 저장하기 위해 플래그 레지스터의 두 비트를 사용한다. IOPL은 I/O 관련 인스트럭션을 실행하기 위해 필요한 특권 레벨을 정의한다.

 

다음 인스트럭션은 오직 CPL ≤ IOPL 일 경우에만 실행될 수 있다:

 

IN           -            Input

INS         -            Input String

OUT       -            Output

OUTS     -            Output String

CLI         -            Clear Interrupt-Enable Flag

STI         -            Set Interrupt-Enable

 

이러한 인스트럭션들은 “민감한(sensitive)” 인스트럭션이라 한다, 왜냐하면 이들은 IOPL에 민감하기 때문이다.

 

민감한 인스트럭션을 사용하려면, 프로시져는 최소한 IOPL이 지정한 특권 레벨(CPL ≤ IOPL)에서 실행되어야 한다. 덜 특권화된 프로시져에서 민감한 인스트럭션을 사용하려는 어떤 시도도 일반 보호 예외의 결과를 낳는다.

 

각 태스크는 자신의 고유한 플래그 레지스터 복사본이 있기 때문에, 각 태스크는 다른 IOPL을 가질 수 있다. 주 기능이 I/O를 수행하는 태스크(디바이스 드라이버)는 세 IOPL에서 잇점을 얻을 수 있어서 모든 태스크의 프로시져로 하여금 I/O를 수행할 수 있도록 한다. 다른 태스크는 특별히 IOPL을 0이나 1로 셋팅해서 가장 특권화된 프로시져로 하여금 I/O를 수행할 수 있도록 권한을 유지한다.

 

태스크는 POPF 인스트럭션을 통해서만 IOPL을 변경할 수 있다; 하지만 그러한 변경들은 특권화되어 있다. 어떤 프로시져도 레벨 0에서 실행되고 있지 않다면, IOPL(플래그 레지스터에 있는 특권 레벨)을 변경하지 못할 것이다. 덜 특권화된 프로시져가 IOPL을 변경하려 시도한다면 예외를 발생시킨다; IOPL은 변경되지 않은 채 있을 것이다.

 

POPF 인스트럭션은 CLI와 STI와 더불어 인터럽트-활성화 플래그(IF)를 변경하기 위해 사용된다; 하지만 POPF로 IF를 변경하는 것은 IOPL에 민감하다. 프로시져는 최소한 IOPL과 같은 특권 레벨에서 실행 중일 때 POPF 인스트럭션으로 IF를 변경할 것이다. 덜 특권화된 프로시져에서 이런 방식으로 IF를 변경하려는 시도는 예외를 낳는다; 변경되지 않은 채 남는다.

 

 

8.3.2 I/O 허용 비트 맵(Permission Bit Map)

 

직접적으로 프로세서 I/O 공간에 있는 주소를 참조하는 I/O 인스트럭션은 IN, OUT, INS, OUTS이다. 80386은 선택적으로 특정 I/O 주소 참조를 트랩(trap)할 수 있는 능력이 있다. 선택적인 트래핑을 가능하게 하는 구조는 TSS 세그먼트(그림 8-2 참조) I/O 허용 비트 맵이다. I/O 허용 맵은 비트 벡터이다. TSS 세그먼트에서 맵의 크기와 위치는 가변적이다. 프로세서는 I/O 허용 맵을 TSS의 고정 영역에 있는 I/O 맵 베이트 필드를 사용해서 위치시킨다. I/O 허용 맵의 상한은 TSS 세그먼트의 한계와 동일하다.

 

보호 모드에서, I/O 인스트럭션(IN, INS, OUT, OUTS)을 만났을 때, 프로세서는 첫째로 CPL ≤ IOPL 인가를 체크한다. 만일 이 조건이 참이면 I/O 연산이 수행된다. 만일 참이 아니면 프로세서는 I/O 허용 맵을 체크한다. (가상 8086 모드에서 프로세서는 IOPL에 상관없이 맵을 참조한다. 15장 참조)

 

맵의 각 비트는 I/O 포트의 바이트 주소에 대응한다; 예를 들면, 포트 41의 비트는 I/O 맵 베이트 + 5, 비트 오프셋 1에서 찾을 수 있다. 프로세서는 I/O 연산에서 사용되는 I/O 주소들에 해당하는 모든 비트를 테스트한다; 예를 들면, 더블워느 연산은 네 개의 인접한 주소에 해당하는 네 비트를 테스트한다. 만일 테스트한 어떤 비트가 셋팅되었다면 프로세서는 범용 보호 예외 신호를 보낸다. 테스트된 모든 비트가 0이면 I/O 연산을 계속된다.

 

I/O 허용 맵이 모든 I/O 주소를 나타낼 필요는 없다. 맵에서 나타나지 않는 I/O 주소는 맵에 한 비트를 갖었던 것처럼 다뤄진다. 예를 들면 TSS 한계가 I/O 맵 베이스 + 31와 같다면, 처음 256 I/O 포트는 매핑되었다; 255보다 큰 임의의 포트에서 I/O 연산은 예외를 발생시킨다.

 

I/O 맵 베이스가 TSS 한계와 같거나 크다면, TSS 세그먼트는 I/O 허용 맵을 가지지 않고, 80386 프로그램에서 모든 I/O 인스트럭션은 CPL ≥ IOPL일 때 예외를 발생시킨다.

 

I/O 허용 맵은 TSS 세그먼트에 있기 때문에, 다른 태스크들은 다른 맵을 가진다. 그래서 OS는 태스크의 TSS에 있는 I/O 허용 맵을 바꿔서 포트를 태스크에 할당할 수 있다.

 

그림 8-2.  I/O 주소 비트 맵(I/O Address Bit Map)