APC8750にNetBSD/evbarmを移植するための記録 10/13
2014/02/11(火) 25:30 NetBSD はてブ情報 はてブに登録 はてブ数

ユーザーランドからデバイスを叩くには、何はなくともopenが実装されてなきゃいかんだろ、ということでテキトーにopenを書いて実行。
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: write
wmtcomwriteが呼ばれている。
良くわからんので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           0

ISR=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
というメッセージを残して果てていました。合掌。

名前:  非公開コメント   

  • TB-URL  http://www.tokuda.net/diary/0840/tb/