APC8750にNetBSD/evbarmを移植するための記録 10/13
ユーザーランドからデバイスを叩くには、何はなくともopenが実装されてなきゃいかんだろ、ということでテキトーにopenを書いて実行。
良くわからんのでpanicさせてみる。
もう少し細かくprintfしてみよう。
ttychars, ttsetwaterあたりが怪しいのかな。
あたりまえだ。
ここまでのルートでいろいろ不足して、変なルートに入っている可能性があるので、見直しに入る。
wmtcomparam()を無視していたのでそこを見直そう。
wmtcomparamでは、ttyのspeedやらflagやらを設定しているようだ。tty側に設定したりsoftc側に設定したりと。
ixpcomやepcomではスピードをBRDでコントロールレジスタに書き込む形式に変換するために、次のようなマクロを使っている。
https://github.com/apc-io/apc-8750/blob/master/kernel/drivers/serial/serial_wmt.c#L173
epcom.cを読み進めていくと、epcomstartを読んでいる。これは、wmtcomstartも書かないとダメか... とりあえず、呼ばれるのか確認してみるか。
wmtcomstart()にpanicを仕込んでwmtcomparamをテキトーにコピペ。
ttyopenからttysleepに道をそれることなくttyopenがerror=0でかえるようになった。
これは、openがうまくいったんだろうか?
システムコールの根っこあたりでログをはいてみる。syscall -> sys_openなのでsys_openにログを仕込む。
そのあとのwriteシステムコールがここまで届いているようだ。wmtcomwriteは、epcomなどからコピペする。
t_lineswはttyXXXXXシリーズを呼び出すものと想像できる。
いよいよ、割り込みをONにする時が来たか...
ということで、そこに至るまでの関数をまじめに作ることになる。
wmtcom_filltxを見てみる。
これは、出力をつかさどるレジスタTDRに文字をどんどん書いていく、というルーチンのようだ。
ただ、TXがビジーになると止めます。ということで、ループは一回だけまわってすぐにビジーになるので、もしかしたらいっぱいレジスタにかけるようなCPUがあるのかもしれないな。
あとは、割り込み用のレジスタに書き込むwmtcom_set_lcrである。
しかしながら、今回のWMTでは割り込みのON・OFFはIERでやるので、ラインコントロールレジスタ(LCR)というのはちょっとミスマッチかもしれないな。
bus_space_readでIERを読んで、bus_space_writeでIERに書き込むという、ベタな実装にした。epcom, ixp12x0_comはwrite一発で済むように工夫しているんだが... まぁ、テクニックの差を素直に受け止めよう。
と、よく考えてみると、wmtcom_set_lcrはwmtcomopenでも呼ばれている。入力の割り込みは、キーボードに触らなければ発動しないので、きっとwriteのときに初めて発動するのだろう。
ほかのcomintrの実装を見ると、大物です。が、writeに必要なTXだけだと、少なそうです。
まずは、ISR, USRあたりを表示させて、どこらへんのビットが立っているのか様子を見てみます。
USR=41、つまり、bit0, bit6が立っている。
うーん、ddb実行時だと状態が変わっているかもしれないな。
ということでTX部分を作ってみました。が、無限ループに入ります。
よく見ると、USRが最初は3ですが、次から41です。下位2ビットを見るとTXONはずっと1でTXDBSYはON->OFFと変化してます。
filltxはビジーになるまで、というループを回していますが、以前の経験からTXDBSYだけでなくTXONも合わせてチェックしていたのが余計なお世話なのかも。
TXDBSYだけにしてみよう。
filltxのところを見てみると変化があります。
pid2といえば、/sbin/initです。
pid2という四文字を表示したあと、softintrが呼ばれ、txsoftが呼ばれているみたいです。文字の表示自体はできているのかもしれませんねぇ。もう一息なのかなぁ。
で、無限ループかと思ったら、どうやら、次々とメッセージを表示しているようです。
空っぽの関数だったwmtcomstop, wmtcomshutdown wmtcom_breakに中身をコピペして、体裁を整えます。
コメントのせいで、initからのメッセージが読めないため、コメントをOFFにしたいところです。
メッセージを延々と出し続け、最後に、
root file system type: ffs configure3 inittodr WARNING: no TOD clock present WARNING: using filesystem time WARNING: CHECK AND RESET THE DATE! uvm_swap_init VOP_OPEN: vp=c1bf2dc0, vp->v_op=c1a35d28, VOFFSET(vop_open)=00000005 spec_open: start cdevsw_lookup: dev=00000100, cmajor = 1, cdevsw = c01e0350 spec_open: cdev_type(dev) != D_DISK error=0 VOP_OPEN: error=0 uvm_scheduler init: copying out flags `-s' 3 init: copying out path `/sbin/init' 11 move out arg pinters sys_execve VOP_OPEN: vp=c1bf2b00, vp->v_op=c1a35b68, VOFFSET(vop_open)=00000005 VOP_OPEN: error=0 sys_execve: error = -2 vn_open: pathstring=/dev/console VOP_OPEN: vp=c1bf2c60, vp->v_op=c1a35a88, VOFFSET(vop_open)=00000005 spec_open: start spec_open: VCHR cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdev_open: d->d_open = c001034c, dev=00000200 cnopen: minor cnopen: cn_tab == NULL? cnopen: cndev=00007000 cnopen: cndev == NODEV? cnopen: dev == cndev? cnopen: cn_devvp == NULLVP? unit=0 cnopen: cdevvp() cnopen: cdevvp() error=0 cnopen: vn_lock() cnopen: vn_lock error=0 cnopen: VOP_OPEN cndevvp[0]=c1bf2a50 VOP_OPEN: vp=c1bf2a50, vp->v_op=c1a35d28, VOFFSET(vop_open)=00000005 spec_open: start spec_open: VCHR cdevsw_lookup: dev=00007000, cmajor = 112, cdevsw = c01e0350 cdevsw_lookup: dev=00007000, cmajor = 112, cdevsw = c01e0350 cdevsw_lookup: dev=00007000, cmajor = 112, cdevsw = c01e0350 cdev_open: d->d_open = c0185010, dev=00007000 wmtcomopen: wmtcomopen: device_is_active wmtcomopen:kauth_authorize_device wmtcomopen:spltty wmtcomopen: TS_ISOPEN wmtcomopen: splserial wmtcomopen: wmtcom_set_lcr wmtcom: param vn_open: pathstring=/dev/console VOP_OPEN: vp=c1bf2c60, vp->v_op=c1a35a88, VOFFSET(vop_open)=00000005 spec_open: start spec_open: VCHR cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdev_open: d->d_open = c001034c, dev=00000200 cnopen: minor cnopen: cn_tab == NULL? cnopen: cndev=00007000 cnopen: cndev == NODEV? cnopen: dev == cndev? cnopen: cn_devvp == NULLVP? unit=0 cnopen: cn_devvp != NULLVP! spec_open: cdev_open error=0 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 spec_open: cdev_type(dev) != D_DISK error=0 VOP_OPEN: error=0 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdevsw_lookup: dev=00007000, cmajor = 112, cdevsw = c01e0350 wmtcom: writewmtcomwriteが呼ばれている。
良くわからんのでpanicさせてみる。
wmtcomopen: wmtcomopen: device_is_active wmtcomopen:kauth_authorize_device wmtcomopen:spltty wmtcomopen: TS_ISOPEN wmtcomopen: splserial wmtcomopen: wmtcom_set_lcr wmtcom: param vn_open: pathstring=/dev/console VOP_OPEN: vp=c1bf2c60, vp->v_op=c1a35a88, VOFFSET(vop_open)=00000005 spec_open: start spec_open: VCHR cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdev_open: d->d_open = c001034c, dev=00000200 cnopen: minor cnopen: cn_tab == NULL? cnopen: cndev=00007000 cnopen: cndev == NODEV? cnopen: dev == cndev? cnopen: cn_devvp == NULLVP? unit=0 cnopen: cn_devvp != NULLVP! spec_open: cdev_open error=0 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 spec_open: cdev_type(dev) != D_DISK error=0 VOP_OPEN: error=0 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdevsw_lookup: dev=00007000, cmajor = 112, cdevsw = c01e0350 wmtcom: write panic: wmtcomwrita Stopped in pid 2.1 (init) at netbsd:cpu_Debugger+0x4: bx r14 0xca864d10: netbsd:vpanic+0xc 0xca864d28: netbsd:printf_nolog 0xca864d48: netbsd:wmtcomwrite+0x1c 0xca864d68: netbsd:cdev_write+0x40 0xca864d90: netbsd:cnwrite+0x50 0xca864db0: netbsd:cdev_write+0x40 0xca864e14: netbsd:spec_write+0x234 0xca864e24: netbsd:ufsspec_write+0x44 0xca864e4c: netbsd:VOP_WRITE+0x64 0xca864e78: netbsd:vn_write+0xd8 0xca864ec8: netbsd:dofilewrite+0x84 0xca864ef0: netbsd:sys_write+0x70 0xca864f84: netbsd:syscall+0x88 0xca864fac: netbsd:swi_handler+0x98 db>うーん、ソフトウェア割込みが起こっている。
もう少し細かくprintfしてみよう。
ttychars, ttsetwaterあたりが怪しいのかな。
wmtcomopen: wmtcom_set_lcr
wmtcom: param
wmtcomopen: ttychars
wmtcomopen: ttsetwater
vn_open: pathstring=/dev/console
VOP_OPEN: vp=c1bf2c60, vp->v_op=c1a35a88, VOFFSET(vop_open)=00000005
spec_open: start
spec_open: VCHR
cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350
cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350
cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350
cdev_open: d->d_open = c001034c, dev=00000200
cnopen: minor
cnopen: cn_tab == NULL?
cnopen: cndev=00007000
cnopen: cndev == NODEV?
cnopen: dev == cndev?
cnopen: cn_devvp == NULLVP? unit=0
cnopen: cn_devvp != NULLVP!
spec_open: cdev_open error=0
cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350
spec_open: cdev_type(dev) != D_DISK error=0
VOP_OPEN: error=0
cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350
cdevsw_lookup: dev=00007000, cmajor = 112, cdevsw = c01e0350
wmtcom: write
panic: wmtcomwrita
Stopped in pid 2.1 (init) at netbsd:cpu_Debugger+0x4: bx r14
0xca864d10: netbsd:vpanic+0xc
0xca864d28: netbsd:printf_nolog
0xca864d48: netbsd:wmtcomwrite+0x1c
0xca864d68: netbsd:cdev_write+0x40
0xca864d90: netbsd:cnwrite+0x50
0xca864db0: netbsd:cdev_write+0x40
0xca864e14: netbsd:spec_write+0x234
0xca864e24: netbsd:ufsspec_write+0x44
0xca864e4c: netbsd:VOP_WRITE+0x64
0xca864e78: netbsd:vn_write+0xd8
0xca864ec8: netbsd:dofilewrite+0x84
0xca864ef0: netbsd:sys_write+0x70
0xca864f84: netbsd:syscall+0x88
0xca864fac: netbsd:swi_handler+0x98
db>
ttsetwaterがあやしすぎる。wmtcom: param wmtcomopen: ttychars wmtcomopen: ttsetwater wmtcomopen: s2 = splserial vn_open: pathstring=/dev/console VOP_OPEN: vp=c1bf2c60, vp->v_op=c1a35a88, VOFFSET(vop_open)=00000005無実だった...
あたりまえだ。
error = ttyopen(tp, COMDIALOUT(dev), ISSET(flag, O_NONBLOCK));これに決まっている。
wmtcomopen: ttyopen vn_open: pathstring=/dev/console VOP_OPEN: vp=c1bf2c60, vp->v_op=c1a35a88, VOFFSET(vop_open)=00000005 spec_open: start spec_open: VCHR cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdev_open: d->d_open = c001034c, dev=00000200 cnopen: minor cnopen: cn_tab == NULL? cnopen: cndev=00007000 cnopen: cndev == NODEV? cnopen: dev == cndev? cnopen: cn_devvp == NULLVP? unit=0 cnopen: cn_devvp != NULLVP! spec_open: cdev_open error=0 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 spec_open: cdev_type(dev) != D_DISK error=0 VOP_OPEN: error=0 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdevsw_lookup: dev=00007000, cmajor = 112, cdevsw = c01e0350 wmtcom: write panic: wmtcomwrita Stopped in pid 2.1 (init) at netbsd:cpu_Debugger+0x4: bx r14 0xca864d10: netbsd:vpanic+0xc 0xca864d28: netbsd:printf_nolog 0xca864d48: netbsd:wmtcomwrite+0x1c 0xca864d68: netbsd:cdev_write+0x40 0xca864d90: netbsd:cnwrite+0x50 0xca864db0: netbsd:cdev_write+0x40 0xca864e14: netbsd:spec_write+0x234 0xca864e24: netbsd:ufsspec_write+0x44 0xca864e4c: netbsd:VOP_WRITE+0x64 0xca864e78: netbsd:vn_write+0xd8 0xca864ec8: netbsd:dofilewrite+0x84 0xca864ef0: netbsd:sys_write+0x70 0xca864f84: netbsd:syscall+0x88 0xca864fac: netbsd:swi_handler+0x98 db>やはり。sys/kern/tty.c#ttyopenの中を追っかける。
wmtcomopen: ttyopen ttyopen: ttyopen: dialout == FALSE ttyopen: !nonblock ttyopen: ttysleep vn_open: pathstring=/dev/console VOP_OPEN: vp=c1bf2c60, vp->v_op=c1a35a88, VOFFSET(vop_open)=00000005 spec_open: start spec_open: VCHR cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdev_open: d->d_open = c001034c, dev=00000200 cnopen: minor cnopen: cn_tab == NULL? cnopen: cndev=00007000 cnopen: cndev == NODEV? cnopen: dev == cndev? cnopen: cn_devvp == NULLVP? unit=0 cnopen: cn_devvp != NULLVP! spec_open: cdev_open error=0 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 spec_open: cdev_type(dev) != D_DISK error=0 VOP_OPEN: error=0 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdevsw_lookup: dev=00007000, cmajor = 112, cdevsw = c01e0350 wmtcom: write panic: wmtcomwrita Stopped in pid 2.1 (init) at netbsd:cpu_Debugger+0x4: bx r14 0xca864d10: netbsd:vpanic+0xc 0xca864d28: netbsd:printf_nolog 0xca864d48: netbsd:wmtcomwrite+0x1c 0xca864d68: netbsd:cdev_write+0x40 0xca864d90: netbsd:cnwrite+0x50 0xca864db0: netbsd:cdev_write+0x40 0xca864e14: netbsd:spec_write+0x234 0xca864e24: netbsd:ufsspec_write+0x44 0xca864e4c: netbsd:VOP_WRITE+0x64 0xca864e78: netbsd:vn_write+0xd8 0xca864ec8: netbsd:dofilewrite+0x84 0xca864ef0: netbsd:sys_write+0x70 0xca864f84: netbsd:syscall+0x88 0xca864fac: netbsd:swi_handler+0x98 db>sys/kern/tty.c#ttyopenのなかのttysleepのあたりか。
372 if (!nonblock) { 373 /* 374 * Wait for carrier. Also wait for any dialout 375 * processes to close the tty first. 376 */ 377 while (ISSET(tp->t_state, TS_DIALOUT) || 378 !CONNECTED(tp)) { 379 tp->t_wopen++; 380 error = ttysleep(tp, &tp->t_rawcv, true, 0); 381 tp->t_wopen--; 382 if (error) 383 goto out;もう少し深く。
ttyopen: dialout=0, nonblock=0 ttyopen: dialout == FALSE ttyopen: !nonblock ttyopen: ttysleep ttysleep: timo=0 ttysleep: catch vn_open: pathstring=/dev/console VOP_OPEN: vp=c1bf2c60, vp->v_op=c1a35a88, VOFFSET(vop_open)=00000005 spec_open: start spec_open: VCHRうーむ。sys/kern/tty.c#ttysleepによると、
2692 2693 } else if (catch) { 2694 printf("ttysleep: catch\n"); 2695 error = cv_timedwait_sig(cv, &tty_lock, timo); 2696 printf("ttysleep: cv_timedwait_sig error=%d\n", error);ということで、sys/kern/kern_condvar.c#cv_timedwait_sigの中を追わねばならない。
277 cv_timedwait_sig(kcondvar_t *cv, kmutex_t *mtx, int timo) 278 { 279 lwp_t *l = curlwp; 280 int error; 281 282 KASSERT(mutex_owned(mtx)); 283 284 cv_enter(cv, mtx, l); 285 error = sleepq_block(timo, true); 286 return cv_exit(cv, mtx, l, error); 287 }あやしいとすればsleepq_blockぐらい? 冷静になって考えて、ファイル名からして、なんだか関係ない気がする。writeだのopenだのからはずいぶん離れてしまった。
ここまでのルートでいろいろ不足して、変なルートに入っている可能性があるので、見直しに入る。
wmtcomparam()を無視していたのでそこを見直そう。
wmtcomparamでは、ttyのspeedやらflagやらを設定しているようだ。tty側に設定したりsoftc側に設定したりと。
ixpcomやepcomではスピードをBRDでコントロールレジスタに書き込む形式に変換するために、次のようなマクロを使っている。
39 #define IXPCOM_FREQ (3686400 / 16) 40 #define IXPCOMSPEED(b) (IXPCOM_FREQ / (b) - 1) 41 #define IXPCOMSPEED2BRD(b) (IXPCOMSPEED(b) << 16) 31 #define EPCOM_FREQ 7372800 32 #define EPCOMSPEED2BRD(b) ((EPCOM_FREQ / (16 * (b))) - 1)wmtでは計算式がわからないため、Linuxのソースにある以下の対応表でやればレジスタに書き込む値がそのままわかるので、これを使うことになるのかな。
https://github.com/apc-io/apc-8750/blob/master/kernel/drivers/serial/serial_wmt.c#L173
static struct baud_info_s baud_table[] = { { 3600, 0x100FF, 15 }, { 7600, 0x1007F, 30 }, { 9600, 0x2003F, 39 }, { 14400, 0x1003F, 59 }, { 19200, 0x2001F, 79 }, { 28800, 0x1001F, 118 }, { 38400, 0x2000F, 157 }, { 57600, 0x1000F, 236 }, { 115200, 0x10007, 472 }, { 230400, 0x10003, 944 }, { 460800, 0x10001, 1920 }, { 921600, 0x10000, 3775 }, };ただ、どうせ変えないので、わざわざレジスタに書き込むこともないかな。関数の中では何もしないことにしよう。(と、あとに負債を残すのであった)
epcom.cを読み進めていくと、epcomstartを読んでいる。これは、wmtcomstartも書かないとダメか... とりあえず、呼ばれるのか確認してみるか。
wmtcomstart()にpanicを仕込んでwmtcomparamをテキトーにコピペ。
ttyopenからttysleepに道をそれることなくttyopenがerror=0でかえるようになった。
wmtcomopen: wmtcomopen: device_is_active wmtcomopen:kauth_authorize_device wmtcomopen:spltty wmtcomopen: TS_ISOPEN wmtcomopen: splserial wmtcomopen: wmtcom_set_lcr wmtcomparam: t->c_ispeed=0, t->c_ospeed=115200 wmtcomparam: t_linesw->l_modem() wmtcomopen: ttychars wmtcomopen: ttsetwater wmtcomopen: s2 = splserial wmtcomopen: splserial done. wmtcomopen: iflash wmtcomopen: CLR RX_ANY_BLOCK wmtcomopen: ttyopen ttyopen: dialout=0, nonblock=0 ttyopen: dialout == FALSE ttyopen: !nonblock wmtcomopen: ttyopen error=0 wmtcomopen: t_linesw->l_open error=0 spec_open: cdev_open error=0 cdevsw_lookup: dev=00007000, cmajor = 112, cdevsw = c01e0350 spec_open: cdev_type(dev) != D_DISK error=0 VOP_OPEN: error=0 cnopen: VOP_UNLOCK error=0 panic: cnopen Stopped in pid 1.1 (init) at netbsd:cpu_Debugger+0x4: bx r14 0xca86cc80: netbsd:vpanic+0xc 0xca86cc98: netbsd:printf_nolog 0xca86ccd4: netbsd:cnopen+0x16c 0xca86ccfc: netbsd:cdev_open+0x78 0xca86cd4c: netbsd:spec_open+0x1b0 0xca86cd70: netbsd:VOP_OPEN+0xa0 0xca86ce24: netbsd:vn_open+0x1e8 0xca86ce9c: netbsd:do_open+0xb0 0xca86cecc: netbsd:do_sys_openat+0x7c 0xca86cef0: netbsd:sys_open+0x34 0xca86cf84: netbsd:syscall+0x88 0xca86cfac: netbsd:swi_handler+0x98 db>done!の後ろに\nを入れ忘れたが以下のようになった。
cnopen: done!spec_open: cdev_open error=0 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 spec_open: cdev_type(dev) != D_DISK error=0 VOP_OPEN: error=0 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdevsw_lookup: dev=00007000, cmajor = 112, cdevsw = c01e0350 wmtcom: write panic: wmtcomwrita Stopped in pid 1.1 (init) at netbsd:cpu_Debugger+0x4: bx r14 0xca86cd10: netbsd:vpanic+0xc 0xca86cd28: netbsd:printf_nolog 0xca86cd48: netbsd:wmtcomwrite+0x1c 0xca86cd68: netbsd:cdev_write+0x40 0xca86cd90: netbsd:cnwrite+0x50 0xca86cdb0: netbsd:cdev_write+0x40 0xca86ce14: netbsd:spec_write+0x234 0xca86ce24: netbsd:ufsspec_write+0x44 0xca86ce4c: netbsd:VOP_WRITE+0x64 0xca86ce78: netbsd:vn_write+0xd8 0xca86cec8: netbsd:dofilewrite+0x84 0xca86cef0: netbsd:sys_write+0x70 0xca86cf84: netbsd:syscall+0x88 0xca86cfac: netbsd:swi_handler+0x98んで、writeが呼ばれている。
これは、openがうまくいったんだろうか?
システムコールの根っこあたりでログをはいてみる。syscall -> sys_openなのでsys_openにログを仕込む。
ttyopen: dialout=0, nonblock=0 ttyopen: dialout == FALSE ttyopen: !nonblock wmtcomopen: ttyopen error=0 wmtcomopen: t_linesw->l_open error=0 spec_open: cdev_open error=0 cdevsw_lookup: dev=00007000, cmajor = 112, cdevsw = c01e0350 spec_open: cdev_type(dev) != D_DISK error=0 VOP_OPEN: error=0 cnopen: VOP_UNLOCK error=0 cnopen: done! spec_open: cdev_open error=0 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 spec_open: cdev_type(dev) != D_DISK error=0 VOP_OPEN: error=0 sysopen: done! error=0 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdevsw_lookup: dev=00007000, cmajor = 112, cdevsw = c01e0350 wmtcom: write panic: wmtcomwrita Stopped in pid 1.1 (init) at netbsd:cpu_Debugger+0x4: bx r14 0xca86cd10: netbsd:vpanic+0xc 0xca86cd28: netbsd:printf_nolog 0xca86cd48: netbsd:wmtcomwrite+0x1c 0xca86cd68: netbsd:cdev_write+0x40 0xca86cd90: netbsd:cnwrite+0x50 0xca86cdb0: netbsd:cdev_write+0x40 0xca86ce14: netbsd:spec_write+0x234 0xca86ce24: netbsd:ufsspec_write+0x44 0xca86ce4c: netbsd:VOP_WRITE+0x64 0xca86ce78: netbsd:vn_write+0xd8 0xca86cec8: netbsd:dofilewrite+0x84 0xca86cef0: netbsd:sys_write+0x70 0xca86cf84: netbsd:syscall+0x88 0xca86cfac: netbsd:swi_handler+0x98 db>よし。sysopen: done!というのがあるな。openシステムコールがやっとこさ成功したようだ。
そのあとのwriteシステムコールがここまで届いているようだ。wmtcomwriteは、epcomなどからコピペする。
int wmtcomwrite(dev_t dev, struct uio *uio, int flag) { struct wmtcom_softc *sc = device_lookup_private(&wmtcom_cd, COMUNIT(dev)); struct tty *tp = sc->sc_tty; if (COM_ISALIVE(sc) == 0) return (EIO); return ((*tp->t_linesw->l_write)(tp, uio, flag)); }するとwmtcomstartがいよいよ呼ばれている。
sysopen: done! error=0 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdevsw_lookup: dev=00007000, cmajor = 112, cdevsw = c01e0350 panic: wmtcom:start Stopped in pid 1.1 (init) at netbsd:cpu_Debugger+0x4: bx r14 0xca86cc54: netbsd:vpanic+0xc 0xca86cc6c: netbsd:printf_nolog 0xca86cc8c: netbsd:wmtcomstart+0x14 0xca86cd2c: netbsd:ttwrite+0x200 0xca86cd48: netbsd:wmtcomwrite+0x68 0xca86cd68: netbsd:cdev_write+0x40 0xca86cd90: netbsd:cnwrite+0x50 0xca86cdb0: netbsd:cdev_write+0x40 0xca86ce14: netbsd:spec_write+0x234 0xca86ce24: netbsd:ufsspec_write+0x44 0xca86ce4c: netbsd:VOP_WRITE+0x64 0xca86ce78: netbsd:vn_write+0xd8 0xca86cec8: netbsd:dofilewrite+0x84 0xca86cef0: netbsd:sys_write+0x70 0xca86cf84: netbsd:syscall+0x88 0xca86cfac: netbsd:swi_handler+0x98 db>どうやら、wmtcomwriteの最後の行が次のように関数ポインタになっているのだが、
return ((*tp->t_linesw->l_write)(tp, uio, flag));これはpanicからするとttywriteが呼ばれているってことだ。
t_lineswはttyXXXXXシリーズを呼び出すものと想像できる。
いよいよ、割り込みをONにする時が来たか...
ということで、そこに至るまでの関数をまじめに作ることになる。
wmtcom_filltxを見てみる。
これは、出力をつかさどるレジスタTDRに文字をどんどん書いていく、というルーチンのようだ。
ただ、TXがビジーになると止めます。ということで、ループは一回だけまわってすぐにビジーになるので、もしかしたらいっぱいレジスタにかけるようなCPUがあるのかもしれないな。
あとは、割り込み用のレジスタに書き込むwmtcom_set_lcrである。
しかしながら、今回のWMTでは割り込みのON・OFFはIERでやるので、ラインコントロールレジスタ(LCR)というのはちょっとミスマッチかもしれないな。
bus_space_readでIERを読んで、bus_space_writeでIERに書き込むという、ベタな実装にした。epcom, ixp12x0_comはwrite一発で済むように工夫しているんだが... まぁ、テクニックの差を素直に受け止めよう。
と、よく考えてみると、wmtcom_set_lcrはwmtcomopenでも呼ばれている。入力の割り込みは、キーボードに触らなければ発動しないので、きっとwriteのときに初めて発動するのだろう。
wmtcomopen: wmtcomopen: device_is_active wmtcomopen:kauth_authorize_device wmtcomopen:spltty wmtcomopen: TS_ISOPEN wmtcomopen: splserial wmtcomopen: wmtcom_set_lcr set_lcr read->lcr=00000000 set_lcr write->lcr=00000002 wmtcomparam: t->c_ispeed=0, t->c_ospeed=115200 set_lcr read->lcr=00000002 set_lcr write->lcr=00000002 wmtcomparam: t_linesw->l_modem() wmtcomopen: ttychars wmtcomopen: ttsetwater wmtcomopen: s2 = splserial wmtcomopen: splserial done. wmtcomopen: iflash wmtcomopen: CLR RX_ANY_BLOCK wmtcomopen: ttyopen ttyopen: dialout=0, nonblock=0 ttyopen: dialout == FALSE ttyopen: !nonblock wmtcomopen: ttyopen error=0 wmtcomopen: t_linesw->l_open error=0 spec_open: cdev_open error=0 cdevsw_lookup: dev=00007000, cmajor = 112, cdevsw = c01e0350 spec_open: cdev_type(dev) != D_DISK error=0 VOP_OPEN: error=0 cnopen: VOP_UNLOCK error=0 cnopen: done! spec_open: cdev_open error=0 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 spec_open: cdev_type(dev) != D_DISK error=0 VOP_OPEN: error=0 sysopen: done! error=0 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdevsw_lookup: dev=00007000, cmajor = 112, cdevsw = c01e0350 wmtcom:filltx set_lcr read->lcr=00000002 set_lcr write->lcr=00000003 icu: block: irqbase=0x00000020, irqmask=0x00000001, irq_num=32, reg=0x00000000 pic: pic_dispatch pic: pic_dispatch irq=32, source=uart0 arg=c1a42b50 panic: wmtcomintr! Stopped in pid 1.1 (init) at netbsd:cpu_Debugger+0x4: bx r14 0xca86cb94: netbsd:vpanic+0xc 0xca86cbac: netbsd:printf_nolog 0xca86cbcc: netbsd:wmtcomintr+0x20 0xca86cbec: netbsd:pic_dispatch+0x48 0xca86cc64: netbsd:pic_do_pending_ints+0x3d4 0xca86cc8c: netbsd:splx+0x60 0xca86cd2c: netbsd:ttwrite+0x200 0xca86cd48: netbsd:wmtcomwrite+0x68 0xca86cd68: netbsd:cdev_write+0x40 0xca86cd90: netbsd:cnwrite+0x50 0xca86cdb0: netbsd:cdev_write+0x40 0xca86ce14: netbsd:spec_write+0x234 0xca86ce24: netbsd:ufsspec_write+0x44 0xca86ce4c: netbsd:VOP_WRITE+0x64 0xca86ce78: netbsd:vn_write+0xd8 0xca86cec8: netbsd:dofilewrite+0x84 0xca86cef0: netbsd:sys_write+0x70 0xca86cf84: netbsd:syscall+0x88 0xca86cfac: netbsd:swi_handler+0x98おぉ、予想が当たりました。
ほかのcomintrの実装を見ると、大物です。が、writeに必要なTXだけだと、少なそうです。
まずは、ISR, USRあたりを表示させて、どこらへんのビットが立っているのか様子を見てみます。
db> examine /x fe200000,20 fe200000: 3a d 10007 7 0 3 fe200018: c1 41 0 0 1d8 a fe200030: 0 0 0 0 30 d fe200048: 10007 7 0 3 c1 41 fe200060: 0 0 1d8 a 0 0 fe200078: 0 0ISR=c1, つまり、bit0, bit6, bit7が立っている。
USR=41、つまり、bit0, bit6が立っている。
うーん、ddb実行時だと状態が変わっているかもしれないな。
icu: block: irqbase=0x00000020, irqmask=0x00000001, irq_num=32, reg=0x00000000 pic: pic_dispatch pic: pic_dispatch irq=32, source=uart0 arg=c1a42b50 isr=000000c1 usr=00000041 panic: wmtcomintr! Stopped in pid 1.1 (init) at netbsd:cpu_Debugger+0x4: bx r14 0xca86cb88: netbsd:vpanic+0xc 0xca86cba0: netbsd:printf_nolog 0xca86cbcc: netbsd:wmtcomintr+0x74 0xca86cbec: netbsd:pic_dispatch+0x48 0xca86cc64: netbsd:pic_do_pending_ints+0x3d4 0xca86cc8c: netbsd:splx+0x60 0xca86cd2c: netbsd:ttwrite+0x200 0xca86cd48: netbsd:wmtcomwrite+0x68 0xca86cd68: netbsd:cdev_write+0x40 0xca86cd90: netbsd:cnwrite+0x50 0xca86cdb0: netbsd:cdev_write+0x40 0xca86ce14: netbsd:spec_write+0x234 0xca86ce24: netbsd:ufsspec_write+0x44 0xca86ce4c: netbsd:VOP_WRITE+0x64 0xca86ce78: netbsd:vn_write+0xd8 0xca86cec8: netbsd:dofilewrite+0x84 0xca86cef0: netbsd:sys_write+0x70 0xca86cf84: netbsd:syscall+0x88 0xca86cfac: netbsd:swi_handler+0x98 db>ありゃ、変わりませんね。
ということでTX部分を作ってみました。が、無限ループに入ります。
sysopen: done! error=0 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdevsw_lookup: dev=00007000, cmajor = 112, cdevsw = c01e0350 wmtcom:filltx wmtcom:filltx n=0 set_lcr read->lcr=00000002 set_lcr write->lcr=00000003 icu: block: irqbase=0x00000020, irqmask=0x00000001, irq_num=32, reg=0x00000000 pic: pic_dispatch pic: pic_dispatch irq=32, source=uart0 arg=c1a42b50 isr=00000041 usr=00000041 wmtcom:filltx wmtcom:filltx n=0 wmtcom: comintr done. pic: pic_dispatch done. icu: unblock: irqbase=0x00000020, irqmask=0x00000001, irq_num=32, reg=0x00000008 icu: block: irqbase=0x00000020, irqmask=0x00000001, irq_num=32, reg=0x00000000 pic: pic_dispatch pic: pic_dispatch irq=32, source=uart0 arg=c1a42b50 isr=00000041 usr=00000003 wmtcom:filltx wmtcom:filltx n=0 wmtcom: comintr done. pic: pic_dispatch done. icu: unblock: irqbase=0x00000020, irqmask=0x00000001, irq_num=32, reg=0x00000008 icu: block: irqbase=0x00000020, irqmask=0x00000001, irq_num=32, reg=0x00000000 pic: pic_dispatch pic: pic_dispatch irq=32, source=uart0 arg=c1a42b50 isr=00000041 usr=00000041 wmtcom:filltx wmtcom:filltx n=0 wmtcom: comintr done. pic: pic_dispatch done. icu: unblock: irqbase=0x00000020, irqmask=0x00000001, irq_num=32, reg=0x00000008 icu: block: irqbase=0x00000020, irqmask=0x00000001, irq_num=32, reg=0x00000000 pic: pic_dispatch pic: pic_dispatch irq=32, source=uart0 arg=c1a42b50 isr=00000041 usr=00000041 wmtcom:filltx wmtcom:filltx n=0 wmtcom: comintr done. pic: pic_dispatch done. icu: unblock: irqbase=0x00000020, irqmask=0x00000001, irq_num=32, reg=0x00000008 icu: block: irqbase=0x00000020, irqmask=0x00000001, irq_num=32, reg=0x00000000 pic: pic_dispatch pic: pic_dispatch irq=32, source=uart0 arg=c1a42b50 isr=00000041 usr=00000041どうやらfilltxが何もせずに抜けて、割り込みが上がり続けているようです。
よく見ると、USRが最初は3ですが、次から41です。下位2ビットを見るとTXONはずっと1でTXDBSYはON->OFFと変化してます。
filltxはビジーになるまで、というループを回していますが、以前の経験からTXDBSYだけでなくTXONも合わせてチェックしていたのが余計なお世話なのかも。
TXDBSYだけにしてみよう。
sysopen: done! error=0 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdevsw_lookup: dev=00007000, cmajor = 112, cdevsw = c01e0350 wmtcom: wmtcomstart tbc 4 wmtcom:filltx wmtcom: filltx tbc 4 wmtcom:filltx write=pid2 pwmtcom:filltx n=1 set_lcr read->lcr=00000002 set_lcr write->lcr=00000003 icu: block: irqbase=0x00000020, irqmask=0x00000001, irq_num=32, reg=0x00000000 pic: pic_dispatch pic: pic_dispatch irq=32, source=uart0 arg=c1a42b50 isr=000000c1 usr=00000041 wmtcom:filltx wmtcom: filltx tbc 3 wmtcom:filltx write=id2 iwmtcom:filltx write=d2 dwmtcom:filltx n=2 wmtcom: comintr done. pic: pic_dispatch done. icu: unblock: irqbase=0x00000020, irqmask=0x00000001, irq_num=32, reg=0x00000008 icu: block: irqbase=0x00000020, irqmask=0x00000001, irq_num=32, reg=0x00000000 pic: pic_dispatch pic: pic_dispatch irq=32, source=uart0 arg=c1a42b50 isr=000000c1 usr=00000041 wmtcom:filltx wmtcom: filltx tbc 1 wmtcom:filltx write=2 2wmtcom:filltx n=1 wmtcom: comintr done. pic: pic_dispatch done. icu: unblock: irqbase=0x00000020, irqmask=0x00000001, irq_num=32, reg=0x00000008 icu: block: irqbase=0x00000020, irqmask=0x00000001, irq_num=32, reg=0x00000000 pic: pic_dispatch pic: pic_dispatch irq=32, source=uart0 arg=c1a42b50 isr=000000c1 usr=00000041 set_lcr read->lcr=00000003 set_lcr write->lcr=00000002 wmtcom: comintr done. pic: pic_dispatch done. icu: unblock: irqbase=0x00000020, irqmask=0x00000001, irq_num=32, reg=0x00000008 panic: txsoft Stopped in pid 0.6 (system) at netbsd:cpu_Debugger+0x4: bx r14 0xc9fccf28: netbsd:vpanic+0xc 0xc9fccf40: netbsd:printf_nolog 0xc9fccf60: netbsd:wmtcomsoft+0x14 0xc9fccfac: netbsd:softint_dispatch+0xfc 0xca86cc64: netbsd:softint_switch+0x50 0xca86cc8c: netbsd:splx+0xc0 0xca86cd2c: netbsd:ttwrite+0x208 0xca86cd48: netbsd:wmtcomwrite+0x68 0xca86cd68: netbsd:cdev_write+0x40 0xca86cd90: netbsd:cnwrite+0x50 0xca86cdb0: netbsd:cdev_write+0x40 0xca86ce14: netbsd:spec_write+0x234 0xca86ce24: netbsd:ufsspec_write+0x44 0xca86ce4c: netbsd:VOP_WRITE+0x64 0xca86ce78: netbsd:vn_write+0xd8 0xca86cec8: netbsd:dofilewrite+0x84 0xca86cef0: netbsd:sys_write+0x70 0xca86cf84: netbsd:syscall+0x88 0xca86cfac: netbsd:swi_handler+0x98 db>おっと、と、txsoftまで進みました。
filltxのところを見てみると変化があります。
wmtcom:filltx wmtcom: filltx tbc 4 wmtcom:filltx write=pid2 pwmtcom:filltx n=1ん? wrilte=pid2というのはpid2という文字列のようですね。pwmtcomというのはpid2という文字列における一文字目のpを表示して、つづいてデバッグ文のwmtcomがつながって表示されている感じですか?
pid2といえば、/sbin/initです。
pid2という四文字を表示したあと、softintrが呼ばれ、txsoftが呼ばれているみたいです。文字の表示自体はできているのかもしれませんねぇ。もう一息なのかなぁ。
wmtcom:filltx wmtcom: filltx tbc 1 wmtcom:filltx write=2 2wmtcom:filltx n=1 wmtcom: comintr done. pic: pic_dispatch done. icu: unblock: irqbase=0x00000020, irqmask=0x00000001, irq_num=32, reg=0x00000008 icu: block: irqbase=0x00000020, irqmask=0x00000001, irq_num=32, reg=0x00000000 pic: pic_dispatch pic: pic_dispatch irq=32, source=uart0 arg=c1a42b50 isr=000000c1 usr=00000003 set_lcr read->lcr=00000003 set_lcr write->lcr=00000002 wmtcom: comintr done. pic: pic_dispatch done. icu: unblock: irqbase=0x00000020, irqmask=0x00000001, irq_num=32, reg=0x00000008 wmtcom: txsoft wmtcom: txsoft call l_start wmtcom: txsoft done cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdevsw_lookup: dev=00007000, cmajor = 112, cdevsw = c01e0350 wmtcom: close cdevsw_lookup: dev=00007000, cmajor = 112, cdevsw = c01e0350 wmtcom: stop wmtcom: shutdown sysopen: start vn_open: pathstring=/dev/console VOP_OPEN: vp=c1bf2c60, vp->v_op=c1a35a88, VOFFSET(vop_open)=00000005 spec_open: start spec_open: VCHR cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350 cdev_open: d->d_open = c001034c, dev=00000200 cnopen: minor cnopen: cn_tab == NULL? cnopen: cndev=00007000 cnopen: cndev == NODEV? cnopen: dev == cndev?ということで、wmtcom stop, shutdownまで呼ばれていることがわかりました。なにもしてませんが。
で、無限ループかと思ったら、どうやら、次々とメッセージを表示しているようです。
wmtcom: filltx tbc 4 wmtcom:filltx write=pid0であるとか、
wmtcom: filltx tbc 48 wmtcom:filltx write=wait for single-user shell failed: m; restartingであるとか。sbin/init/init.c#778を見ると
778 warning("wait for single-user shell failed: %m; " 779 "restarting");おぉ、まさしく、init.cからのメッセージです。
空っぽの関数だったwmtcomstop, wmtcomshutdown wmtcom_breakに中身をコピペして、体裁を整えます。
コメントのせいで、initからのメッセージが読めないため、コメントをOFFにしたいところです。
boot device: <unknown> root on md0a dumps on md0b mountroot: trying nfs... mountroot: trying msdos... mountroot: trying ffs... root file system type: ffs configure3 inittodr WARNING: no TOD clock present WARNING: using filesystem time WARNING: CHECK AND RESET THE DATE! uvm_swap_init uvm_scheduler init: copying out flags `-s' 3 init: copying out path `/sbin/init' 11 move out arg pinters sys_execve sys_execve: error = -2 pid2pid0wait for single-user shell failed: m; restartingpid3pid0wait for single-user shell failed: m; restartingpid4pid0wait for single-user shell failed: m; restartingpid5pid0wait for single-user shell failed: m; restartingpid6pid0wait for single-user shell failed: m; restartingpid7pid0wait for single-user shell failed: m; restartingpid8pid0wait for single-user shell failed: m; restartingpid9pid0wait for single-user shell failed: m; restartingpid10pid0wait for single-user shell failed: m; restartingpid11pid0wait for single-user shell failed: m; restartingpid12pid0wait for single-user shell failed: m; restartingpid13pid0wait for single-user shell failed: m; restartingpid1おぉ、こういうことになっていたのですね。
メッセージを延々と出し続け、最後に、
it for single-user shell failed: m; restartingpid1066pid0wait for single-user shell failed: m; restartingpid1067pid0wait for single-user shell failed: m; restartingpid1068pid0wait for single-user shell failed: m; restartingpid1069pid0wait for single-user shell failed: m; restartingpid1070pid0wait for single-user shell failed: m; restartingpid1071pid0wait for single-user shell failed: m; restartingpid1072pid0wait for single-user shell failed: m; restartingpid1073pid0wait for single-user shell failed: m; restartingproc: table is full - increase kern.maxproc or NPROC pid-1というメッセージを残して果てていました。合掌。
コメント(0件)
- TB-URL http://www.tokuda.net/diary/0840/tb/