KiNOKO-DAQ 関連情報 掲示板

このスレッドに記事を投稿する
前のスレッド | 次のスレッド | 掲示版ホーム

vmeslibでのA32D32アクセスについて
2010 年 7 月 12 日 17 時 16 分
投稿者: 細見健二

お世話になっております。東北大学の細見です。
vmeslib内のwme_write()関数を使ってVMEモジュールに
A32D32アクセスする際に、アクセス先アドレスが0x80000000よりも大きくなった場合に、アクセスエラーになります。

lseek()のパラメタoff_t offsetのoff_tがsigned intのため、0x80000000よりも大きなoffset値は負数として認識されてしまうからなのでしょうか?

使用しているドライバのバージョンは
vmedrv-1.1.6 Linux2.6_Bit3_617 です。



2010 年 7 月 13 日 2 時 51 分
投稿者: 榎本三四郎

アドレスが 0x80000000 を越えた場合に lseek() が負の値を返して,それをエラーとしてしまうバグが過去にもあったのですが,修正したつもりでした(そのために一般的な負値ではなく -1 と比較しています).今コードを見直したのですが,明らかな間違いは見つかりませんでした.

手元にすぐに使えるデバイスがないので,調べてみていただきたいのですが,

*) vmeput プログラムを使ってもエラーが出るでしょうか.その場合,どのようなメッセージが出るでしょうか.

*) lseek() を lseek64() に変更してみた場合,動作が変わるでしょうか.

お手数をお掛けしますが,よろしくお願いします.



2010 年 7 月 13 日 2 時 58 分
投稿者: 榎本三四郎

あとついでに llseek() も試してみてください.
lseek64() は環境依存があるようです(llseek() もですが).
よろしくお願いします.



2010 年 7 月 16 日 5 時 47 分
投稿者: 榎本三四郎

問題を再現し,解決しました.
やはり lseek() がだめだったようです.エラー自体は read() が出していたので若干混乱しましたが...

lseek() の代わりに lseek64() を使えば,問題なく動作するはずです.アドレスが 0x80000000 を越えた場合に,lseek() がドライバに渡すアドレスがすでに 64bit で負値になっていました.lseek64() を使った場合は正の値でした.なので,ドライバ自体の変更はありません.

vmeslib およびドライバサンプルを lseek64() を使うように変更し,vmedrv パッケージの新しいバージョンを公開しました.たぶん大丈夫だと思うのですがテストしていただけると助かります.

lseek64() は比較的新しいインターフェースのようなので,今テストできない古いシステムで問題がでるのではないかと心配です..



2010 年 7 月 21 日 13 時 58 分
投稿者: 細見健二

返事が遅くなってすみません。

vmedrv version 1.1.7を使ってみました。
vmeslibからアクセスするアドレスが0x80000000を越えた場合には、やはりアクセスに失敗します。lseek64()は成功しているようですが、read(),write()が errno=22(Invalid argument)を返します。

vmeputプログラムでは、アクセスするアドレスが0x80000000を越えた場合でも正しくアクセスできることは確認しました。



2010 年 7 月 21 日 19 時 55 分
投稿者: 細見健二

問題を解決しました。

vmeslib内のvme_read(),vme_write()関数を呼び出す際に、引数でアドレスがoff_t型で与えられています。
このため、lseek64()関数に渡されるアドレスが0x80000000を越えた場合には負数で与えられていました。

int vme_read(VMEIO* handle, off_t vme_address, void* buffer, size_t count)
{
int read_size;
if (lseek64(handle->fd, vme_address, SEEK_SET) == -1) {
return -1;
}

if ((read_size = read(handle->fd, buffer, count)) == -1) {
return -1;
}

return read_size;
}

解決策として、
lseek64(handle->fd, (unsigned)vme_address, SEEK_SET)
のように符号無しでアドレスを引数にすれば、0x80000000よりもおおきなアドレス領域にアクセスできるようになりました。

vmeput()関数では最初からアドレスがunsigned型になっていたため、うまくいっているようです。



2010 年 7 月 22 日 4 時 33 分
投稿者: 榎本三四郎

修正ありがとうございます.

vmeslib 内で off_t の代わりに unsigned を使うように変更して新しいバージョンを作成しました.int が 32bit よりも小さい古いシステムでは動作しなくなってしまいますが,今の時代なら大丈夫だと思います..


このスレッドに記事を投稿する