다음 이전 차례

1. C 프로그램에서 I/O 포트, 일반적인 방법

I/O를 읽고 쓰기 위한 루틴은 /usr/include/asm/io.h에 있다. (또는 커널 소스 배 포본의 linux/include/asm-i386/io.h) 이 루틴은 인라인 매크로이기 때문에, #include <asm/io.h> 만으로도 충분하다; 다른 라이브러리를 추가할 필요는 없 다.

gcc(현재 최소한 2.7.2.1또는 그 아래 버전)의 제한 때문에, 여러분은 소스 코드 를 컴파일해야 한다. 최적화 옵션을 사용하여 (gcc -O1 or 더 높게), 또는 다른 방법으로 #including <asm/io.h> 앞의 #define extern을 비워 두어야 한다. 디버깅을 위해서, 여러분은 "gcc -g -O"를 사용할 수 있다. (최소한 요즘 나오 는 버전의 gcc에서는), 최적화 때문에 때때로 디버거가 조금 이상하게 동작할 수 도 있지만. 그것이 방해된다면, 다른 소스 파일에 나누어서 I/O 포트를 읽고 쓰 기 위한 루틴을 넣는다. 그리고 그 소스만 최적화 옵션을 주고 컴파일한다.

어떤 포트를 읽고 쓰기 전에, 반드시 프로그램에 해당하는 권한을 주어야 한다. 이는 여러분 프로그램의 시작 지점에서 가까운 어딘가 에서 (여러분이 어떤 I/O 포트를 읽고 쓰기 전에) ioperm(2) 함수를 호출함으로써 이루어진다. (unistd.h에 선언되어 있고, 커널에서 정의되어 있다). 문법은 ioperm(from,num,turn_on) 이 다, 여기에서 from은 읽고 쓰려는 첫 번째 포트 번호이다. 예를 들어 ioperm(0x300,5,1); 은 포트 0x300에서 0x304 (모두 5개의 포트)에 엑세스할 권한 을 줄 것이다. 마지막 인자는 Boolean 값으로 프로그램에서 포트를 엑세스할 권 한을 줄 것인지(true (1)) 아니면 제거할 것인지 (false (0))를 정의한다. 떨어져 있는 포트 여러 개를 사용하기 위하여 ioperm을 여러 번 호출할 수 있다. 문법 에 대하여 자세한 사항은 ioperm(2) 매뉴얼 페이지를 참조하기 바란다.

ioperm() 호출은 여러분의 프로그램이 루트 권한을 가지고 있기를 요구한다; 따 라서 여러분은 프로그램을 루트 사용자로써 실행하던지 setuid 루트로 해결할 수도 있다. 여러분은 포트를 사용 가능하도록 ioperm()을 호출한 후에 루트 권한 을 버릴 수 있다. 여러분은 ioperm(...,0)로 포트 엑세스 권한을 반드시 버려야 할 필요가 있는 것은 아니다. 이는 프로그램이 끝나면, 자동적으로 이루어진다. setuid()가 루트가 아닌 사용자에게 ioperm()에서 주어지는 포트 엑세스 금지하 는 것이 아니고, fork()가 그러한 일을 한다.

Ioperm()은 0x000에서 0x3ff까지의 포트의 엑세스만 허용한다; 더 상위 번지에 있는 포트는, iopl(2) (이는 한번에 모든 포트에 대해 엑세스 할 수 있도록 한다) 을 사용할 필요가 있다. 프로그램에 모든 I/O 포트를 읽고 쓰는 기능을 제공하 기 위하여 레벨 인자 3(예를 들어 "iopl(3);")을 사용한다 (잘못된 포트를 읽고 쓰 는 것은 컴퓨터에 심한 문제를 일으킬 수 있으므로 주의한다). 다시, 여러분은 iopl()을 호출하려면 루트 권한이 필요하다.

다음으로, 모든 포트를 실제로 읽고 쓰는데, 포트에서 한 바이트를 입력받기 위 해서는, inb(port);를 호출하면 되는데, 이는 받은 바이트를 리턴한다. 포트에 한 바이트를 출력하기 위해서는, outb(value, port);를 호출한다. (매개변수의 순서에 주의한다). 포트 x와 x+1(각각의 한 바이트에서 워드를 형성한다, 어셈블러 명령 의 INW와 같이) 에서 한 개의 워드(16비트)를 입력받기 위해서는, inw(x);를 호 출한다. 두 포트에 한 개의 워드를 출력하기 위해서는, outw(value,x)를 호출한 다. 여러분이 어떤 포트 명령(바이트/워드)을 사용해야 하는지 분명하지 않다면, 여러분은 아마도 inb() 와 outb()를 필요로 할 것이다. - 대부분의 장치들은 바 이트 순서로 포트를 읽고 쓰도록 설계되어 있다. 모든 포트 명령은 최소한 실행 하는데 1 마이크로 초가 걸린다는 것을 기억한다.

inb_p(), outb_p(), inw_p(), and outw_p() 매크로는 위에서 본 것들과 동일하게 수행되지만, 이들은 포트를 읽고 쓴 후에 짧은 (1 마이크로초 정도 되는) 지연 시간을 갖는다; 여러분은 <asm/io.h>를 #include하기 전에 REALLY_SLOW_IO 를 #define으로 정의함으로써 4 마이크로초 동안 지연하도록 할 수 있다. 이들 매크로는 일반적으로 (#define SLOW_IO_BY_JUMPING 하지 않는 한, 이것은 그렇게 정확하지 않다) 0x80번 포트에서의 출력을 사용하므로, 여러분은 0x80번 포트를 읽고 쓸 수 있도록 할 필요가 있다. ioperm() 먼저 (0x80 포트의 출력은 시스템의 다른 부분에 영향을 미치지 않아야 한다). 지연할 수 있는 다른 다양한 방법은 뒤에서 볼 수 있다.

최근에 발표된 리눅스 맨페이지 배포본에는 ioperm(), iopl()와 위의 매크로에 대 한 매뉴얼 페이지가 있다.


다음 이전 차례