2011.12.15
前へ
次へ
目次へ戻る
ホームページトップへ戻る

パソコンをつくろう!(パソコン自作のすすめ)
組み立てキットを使って自作に挑戦!

[第270回]


●ioperm (2)

前回からの続きです。
リナックスのマニュアルを見ますと、iopermの書式
int ioperm(unsigned long from, unsigned long num, int turn_on);
で、「許可ビットをturn_onに設定する」と書いてあります。
そこのところがよくわからなくて、あれこれ探った結果、多分turn_on=0のときアクセス不可でturn_on≠0のときアクセス可になる、ということだろうと見当をつけました。
それでいいのかどうか、実際にプログラムを書いて試してみましょう、というところで前回は終わってしまいました。

これがもとのプログラムです。
turn_on=1にしています。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/io.h>
#define OUT_PORT 0x378
 
int main(void){
  int i;
  ioperm(OUT_PORT, 4, 1);
  for(i = 0; i < 10; i++){
    outb(0xff, OUT_PORT);
    sleep(1);
    outb(0x00, OUT_PORT);
    sleep(1);
  }
  return 0;
}


このプログラムはUbuntu11.10でコンパイルして正しく実行できることを確認済みです([第267回][第268回])。

●turn_on≠0にしてみる

そのturn_on=1のところを下のようにturn_on=0xff00に変更してみました。
なぜ0xff00という値にしたかといいますと、8ビットよりも大きな値でもいいのか、ということと、ひょっとして末尾(ビット0)のみを見ているのではないか、というようなことも含めて確認してみるためです。

/* outtest2.c */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/io.h>
#define OUT_PORT 0x378
 
int main(void){
  int i;
  ioperm(OUT_PORT, 4, 0xff00);
  for(i = 0; i < 10; i++){
    outb(0xff, OUT_PORT);
    sleep(1);
    outb(0x00, OUT_PORT);
    sleep(1);
  }
  return 0;
}


これをコンパイルして実行してみました。

もとのプログラムのときと全く同じように正しく実行され、LEDが10回点滅しました。

これでturn_onが1以外の値でも、アクセスが許可されることが確認できました。

●turn_on=0にしてみる

では、turn_on=0にしたら、果たしてどうなるのでしょうか?
しつこくこだわって確認してみたいと思います。

/* outtest0.c */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/io.h>
#define OUT_PORT 0x378
 
int main(void){
  int i;
  ioperm(OUT_PORT, 4, 0);
  for(i = 0; i < 10; i++){
    outb(0xff, OUT_PORT);
    sleep(1);
    outb(0x00, OUT_PORT);
    sleep(1);
  }
  return 0;
}

これをコンパイルして実行してみました。

さきほどのouttest2.cのコンパイルと実行に続けて、outtest0.cのコンパイルと実行をしています。
結果はSegmentation faultエラーが表示されました。
Segmentationという言葉からは、8086の64KBの壁であるセグメントが想起されます。
推測するに「許可されていない領域へのアクセスが行なわれた」というような意味でありましょう。

ioperm()命令においてturn_on=0にしたために、指定したI/Oアドレス(0x378〜0x37b)へのアクセスが不許可とされ、その結果その後に続いて実行された
outb(0xff, OUT_PORT);
でSegmentation faultエラーが発生したのではないか、と推測されます。

●outbをコメントアウトしてみる

そこで、さらにさらに、以下のようにして、そのことを確認してみました。

/* outtest0_2.c */


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/io.h>
#define OUT_PORT 0x378
 
int main(void){
  int i;
  ioperm(OUT_PORT, 4, 0);
  for(i = 0; i < 10; i++){
/*    outb(0xff, OUT_PORT); */
    sleep(1);
/*    outb(0x00, OUT_PORT); */
    sleep(1);
  }
  return 0;
}


これをコンパイルして実行してみました。

さきほどのouttest0.cのコンパイルと実行に続けて、outtest0_2.cのコンパイルと実行をしています。
今度は実行してもエラーは表示されませんでした。
かなり長い時間(多分20秒ほど)たってから、下の行が表示されてカーソルが点滅しました。

これで、 ioperm()命令においてturn_on=0にすると、指定したI/Oアドレスへのアクセスが不許可にされることが確認できました。

やっと、納得です。

ところで、このところ検証しております、リナックス用パラレルポート出力プログラムにつきまして、ioperm()以外にも、もう少し考えてみたいことが出てきました。
それについては次回に説明をいたします。

パソコンをつくろう![第270回]
2011.12.15upload

前へ
次へ
目次へ戻る
ホームページトップへ戻る