メッセージ欄

分類 【NetBSD】 で検索

一覧で表示する

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

APC8750にNetBSD/evbarmを移植するための記録 10/7
2014/01/26(日) 25:04 NetBSD はてブ情報 はてブに登録 はてブ数

つまらんミスで動いてなかった。
if(hoge)
    return 0;
というのをprintf debugした際に
if(hoge)
    printf(piyo);
    return 0;
としていた。中かっこが足らないのだ。初心者かよ!

いざ、実行。
sys_execve
sys_execve: eror = -2
cnopen: minor
cnopen: cn_tab == NULL?
cnopen: cndev=000fff00
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
cnopen: VOP_UNLOCK error=6
openが6を返している。エラーコードが6というとENXIOとのこと。
#define    ENXIO        6        /* Device not configured */
じゃぁ、cndevvp[0]=c1bf2a50のc1bf2a50ってなんだよ、とnetbsd.mapを見てみると
.text          0x00000000c0184c64      0x4e0 wmt_com.o
                0x00000000c0184c64                wmtcomcnpollc
                0x00000000c0184c6c                wmtcomstop
                0x00000000c0184c78                wmtcomioctl
                0x00000000c0184c98                wmtcompoll
                0x00000000c0184cb8                wmtcomwrite
                0x00000000c0184cd8                wmtcomread
                0x00000000c0184cf8                wmtcomclose
                0x00000000c0184d18                wmtcomopen

ということでハズしている。後で確認したが、objdump -dでみたら、netbsd.mapとも違う数字になっていた。なんだこりゃ。


VOP_OPENをもう少し表示させてみる。
sys_execve: eror = -2
VOP_OPEN: vp=c1bf2c60, VOFFSET(vop_open)=00000005
cnopen: minor
cnopen: cn_tab == NULL?
cnopen: cndev=000fff00
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, VOFFSET(vop_open)=00000005
cnopen: VOP_UNLOCK error=6
わかんないな。ん? なんだ、c1bf2c60というのがcnopenの前に出てるぞ?
VOP_OPENがcnopen経由以外で呼ばれているってことか。それっぽいのは以下あたり?
  • vfs_mount.cのvfs_mountroot(void)
  • tty_tty.cのcttyopen(dev_t dev, int flag, int mode, struct lwp *l)
ちがうかな?init.cのopenlogかもしれん。

と思ったが、ramdisk.fsだとインストーラように小さくするため、きっと#ifndef LETS_GET_SMALLのはずだから違うか。

とりあえず、本当は誰が呼んでるかわからんからpanicさせてみるかなぁ。
rn_init: radix functions require max_keylen be set
start_init
module_init_class
boot device: <unknown>
root on md0a dumps on md0b
VOP_OPEN: vp=c1bf2f20, VOFFSET(vop_open)=00000005
VOP_OPEN: error=0
panic: VOP_OPEN
Stopped in pid 0.1 (system) at  netbsd:cpu_Debugger+0x4:        bx      r14
0xc06b1f24: netbsd:vpanic+0xc
0xc06b1f3c: netbsd:printf_nolog
0xc06b1f70: netbsd:VOP_OPEN+0x70
0xc06b1f9c: netbsd:vfs_mountroot+0x280
0xc06b1fec: netbsd:main+0x350
0xc06b1ffc: netbsd:kernel_text+0x50
db>
ふむ。やはりvfs_mountroot。

じゃぁ、cnopenは?
root on md0a dumps on md0b
VOP_OPEN: vp=c1bf2f20, VOFFSET(vop_open)=00000005
VOP_OPEN: error=0
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
VOP_OPEN: vp=c1bf2dc0, VOFFSET(vop_open)=00000005
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, VOFFSET(vop_open)=00000005
VOP_OPEN: error=0
sys_execve: eror = -2
VOP_OPEN: vp=c1bf2c60, VOFFSET(vop_open)=00000005
cnopen: minor
cnopen: cn_tab == NULL?
cnopen: cndev=000fff00
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, VOFFSET(vop_open)=00000005
VOP_OPEN: error=6
cnopen: VOP_UNLOCK error=6
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+0x68
0xca86cd4c: netbsd:spec_open+0x198
0xca86cd70: netbsd:VOP_OPEN+0x98
0xca86ce24: netbsd:vn_open+0x1dc
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>
うん。swi_handlerでした。

読めば読むほどinit.cのprint_consoleどうにもできる気がしない。

ということで、このpanicさせるopenシステムコールを少しずつ動かして、どこまで進んでいるかを見れば、どこで止まっているかはわかる。

どうやら、sbin/init/init.c#771の場所。single_user()の中で使われているwaitpid()が帰ってきていないようだ。
    771 	requested_transition = 0;
    772 	do {
    773 		if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)
    774 			collect_child(wpid, status);
というか、そのまえのfork()が失敗しているということである。
kernelのfork1は成功して/sbin/initが実行されているのだけれど、forkはうまく動いていないようだ。
とにかく、いろいろおかしいことがわかってきた。こういう時、どうデバックしたらいいのか。
まずは、forkが失敗しようがしまいが、進めてしまうとどうなるのだろうか。
sys_execve
VOP_OPEN: vp=c1bf2b00, VOFFSET(vop_open)=00000005
VOP_OPEN: error=0
sys_execve: error = -2
proc: table is full - increase kern.maxproc or NPROC
しばらくして上のproc: table is full - ... が出た。なんか、ループして食いつぶしたような感じである。

とにかくだ、シリアル動かないとにっちもさっちも。やっぱりprint_console動かす方向に戻す。

VOP_OPENを追っかけると、vpではなくvp->v_opが大事そうである。
つまり、vp->v_op[offset]が関数ポインタとして実行されるのである。
ということで、vp->v_opを表示させるようにしてみる。
VOP_OPEN: vp=c1bf2a50, vp->v_op=c1a35d28, VOFFSET(vop_open)=00000005
VOP_OPEN: error=6
cnopen: VOP_UNLOCK error=6
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+0x68
0xca86cd4c: netbsd:spec_open+0x198
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>
とはいうものの、c1a35d28はobjdumpしても見つからない。
よく考えたら、アドレスがわかっても意味なくって、アドレスに格納されている値が大事なのでは?

まてよ、そういえばコンソールから入力できるようになっているので、ddbが使えるということでは?!

man ddbしてみると、いくつかのコマンドが打てる。
psとかやってみる。
db> ps
PID    LID S CPU     FLAGS       STRUCT LWP *               NAME WAIT
2        1 2   0         0           c1a3b540               init
1    >   1 7   0         0           c1be8aa0               init
0       30 3   0       200           c1a3b2a0           aiodoned aiodoned
0       29 3   0       200           c1be8d40            ioflush syncer
0       28 3   0       200           c1a3b000           pgdaemon pgdaemon
0       25 3   0       200           c1be8800              unpgc unpgc
0       24 3   0       200           c1be8560        vmem_rehash vmem_rehash
0       15 3   0       200           c1a3ba80         pmfsuspend pmfsuspend
0       14 3   0       200           c1a3bd20           pmfevent pmfevent
0       13 3   0       200           c1a34020         sopendfree sopendfr
0       12 3   0       200           c1a342c0           nfssilly nfssilly
0       11 3   0       200           c1a34560            cachegc cachegc
0       10 3   0       200           c1a34800              vrele vrele
0        9 3   0       200           c1a34aa0             vdrain vdrain
0        8 3   0       200           c1a34d40          modunload mod_unld
0        7 3   0       200           c1a2b000            xcall/0 xcall
0        6 1   0       200           c1a2b2a0          softser/0
0        5 1   0       200           c1a2b540          softclk/0
0        4 1   0       200           c1a2b7e0          softbio/0
0        3 1   0       200           c1a2ba80          softnet/0
0        2 1   0       201           c1a2bd20             idle/0
0        1 3   0       200           c029b120            swapper uvm
db>
おぉー、プロセスがけっこう動いているみたいじゃないか。

アドレスの中身を除くのはexamineのようだ。

本題に戻ってc1a35d28つまりvp->v_opから先頭を10こ表示させてみる。
db> examine /x c1a35d28,10
c1a35d28:       c0167b48    c01640b8    c00d77c8    c00402ec    c00402ec    c00d
85f8    c00d7944    c004047c    c004047c    c004047c    c00d82dc    c00d7f74
c1a35d58:       c00d7e40    c00402d8    c00d7da4    c00d7d78
db>
ほうほう。VOFFSET(vop_open)=00000005だった。配列は0から始まるので6個目がそれにあたる。
つまり、改行しているところにある値がそれで、c00d85f8である。
これをobjdumpの結果にgrepしてみる。
c00d85f8 <spec_open>:
c00d85f8:       e1a0c00d        mov     ip, sp
c00d85fc:       e92ddff0        push    {r4, r5, r6, r7, r8, r9, sl, fp, ip, lr, pc}
c00d8600:       e24cb004        sub     fp, ip, #4
c00d8604:       e24dd024        sub     sp, sp, #36     ; 0x24
c00d8608:       e1a06000        mov     r6, r0
c00d860c:       ee1d3f90        mrc     15, 0, r3, cr13, cr0, {4}
c00d8610:       e5904004        ldr     r4, [r0, #4]
c00d8614:       e5933178        ldr     r3, [r3, #376]  ; 0x178
c00d8618:       e5945098        ldr     r5, [r4, #152]  ; 0x98
c00d861c:       e50b3034        str     r3, [fp, #-52]  ; 0x34
c00d8620:       e5943064        ldr     r3, [r4, #100]  ; 0x64
c00d8624:       e595800c        ldr     r8, [r5, #12]
c00d8628:       e3530000        cmp     r3, #0
c00d862c:       e595a010        ldr     sl, [r5, #16]
c00d8630:       e5959004        ldr     r9, [r5, #4]
おぉ、関数名にopenがついてそれっぽいぞ!

spec_openは[sys/miscfs/specfs/spec_vnops.c#spec_open]にある。

sys/kern/vfs_subr.c#cdevvpにあったgetdevvpにVCHRが与えられていたことから、
    352 int
    353 cdevvp(dev_t dev, vnode_t **vpp)
    354 {
    355 
    356     return (getdevvp(dev, vpp, VCHR));
    357 }
このブロックがひじょーに怪しいな。device not configuredのENXIOという記述もあるし。
    531     switch (vp->v_type) {
    532     case VCHR:
    533         error = kauth_authorize_device_spec(ap->a_cred, req, vp);
    534         if (error != 0)
    535             return (error);
    536 
    537         /*
    538          * Character devices can accept opens from multiple
    539          * vnodes.
    540          */
    541         mutex_enter(&device_lock);
    542         if (sn->sn_gone) {
    543             mutex_exit(&device_lock);
    544             return (EBADF);
    545         }
    546         sd->sd_opencnt++;
    547         sn->sn_opencnt++;
    548         mutex_exit(&device_lock);
    549         if (cdev_type(dev) == D_TTY)
    550             vp->v_vflag |= VV_ISTTY;
    551         VOP_UNLOCK(vp);
    552         do {
    553             const struct cdevsw *cdev;
    554 
    555             gen = module_gen;
    556             error = cdev_open(dev, ap->a_mode, S_IFCHR, l);
    557             if (error != ENXIO)
    558                 break;
    559 
    560             /* Check if we already have a valid driver */
    561             mutex_enter(&device_lock);
    562             cdev = cdevsw_lookup(dev);
    563             mutex_exit(&device_lock);
    564             if (cdev != NULL)
    565                 break;
    566 
    567             /* Get device name from devsw_conv array */
    568             if ((name = cdevsw_getname(major(dev))) == NULL)
    569                 break;
    570 
    571             /* Try to autoload device module */
    572             (void) module_autoload(name, MODULE_CLASS_DRIVER);
    573         } while (gen != module_gen);
    574 
    575         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
    576         break;
ここがprintfで反応したらビンゴかもしれん。

ビンゴであった。
結局subr_devsw.cのcdevsw_lookup, cdev_openあたりにprintfを入れまくり。

ひさびさにバナーからログを残しておこう。 
init subsystems: stacks vectors undefined page pmap_physload pmap [ Kernel symbol table missing! ]
done.
Loaded initial symtab at 0xc01e431c, strtab at 0xc020453c, # entries 8211
pmap_postinit: Allocated 35 static L1 descriptor tables
Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
    2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
    The NetBSD Foundation, Inc.  All rights reserved.
Copyright (c) 1982, 1986, 1989, 1991, 1993
    The Regents of the University of California.  All rights reserved.

NetBSD 6.99.23 (APC) #50: Mon Oct  7 17:28:43 UTC 2013
        root@builder.localdomain:/usr/obj/sys/arch/evbarm/compile/APC
total memory = 512 MB
avail memory = 495 MB
mainbus0 (root)
cpu0 at mainbus0 core 0: ARM1176JZ-S r0p7 (ARM11J V6ZK core)
cpu0: DC enabled IC enabled WB enabled LABT
cpu0: 16KB/32B 4-way L1 Instruction cache
cpu0: 16KB/32B 4-way write-back-locking-C L1 Data cache
vfp0 at cpu0: VFP11
obio0 at mainbus0
wmicu0 at obio0 addr 0xd8140000-0xd814ffff
icu-debug:
d8140040: 00000000 -> 00000000
d8140044: 00000000 -> 00000000
d8140048: 00000000 -> 00000000
d814004c: 00000000 -> 00000000
d8140050: 00000000 -> 00000000
d8140054: 00000000 -> 00000000
d8140058: 00000000 -> 00000000
d814005c: 00000000 -> 00000000
d8140060: 00000000 -> 00000000
d8140064: 00000000 -> 00000000
d8140068: 00000000 -> 00000000
d814006c: 00000000 -> 00000000
d8140070: 00000000 -> 00000000
d8140074: 00000000 -> 00000000
d8140078: 00000000 -> 00000000
d814007c: 00000000 -> 00000000
wmtmr0 at obio0 addr 0xd8100000-0xd810ffff intr 48 : WMT System Timer
wmtcom0 at obio0 addr 0xd8200000-0xd820ffff intr 32 : WMT UART
wmtcom:wmtcom_attach_subr
wmtcom:wmtcom_attach_subr 1
wmtcom:wmtcom_attach_subr 1-1
wmtcom:wmtcom_attach_subr 1-2
wmtcom:wmtcom_attach_subr 1-3
wmtcom:wmtcom_attach_subr 2
wmtcom:wmtcom_attach_subr 3
wmtcom:wmtcom_attach_subr 3-1
wmtcom0: console cn_tab->cn_dev=000fff00
icu: establish_irq: is->is_irq=0x20
icu: unblock: irqbase=0x00000020, irqmask=0x00000001, irq_num=32, reg=0x00000008
icu: establish_irq: is->is_irq=0x30
icu: unblock: irqbase=0x00000020, irqmask=0x00010000, irq_num=48, reg=0x00000008
rn_init: radix functions require max_keylen be set
start_init
module_init_class
boot device: <unknown>
root on md0a dumps on md0b
VOP_OPEN: vp=c1bf2f20, vp->v_op=c1a35d28, VOFFSET(vop_open)=00000005
spec_open: start
cdevsw_lookup: dev=00001200, cmajor = 18, cdevsw = c01e0350
spec_open: cdev_ioctl error=0
VOP_OPEN: error=0
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
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=000fff00
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=000fff00, cmajor = 4095, cdevsw = c01e0350
cdevsw_lookup: dev=000fff00, cmajor = 4095, cdevsw = c01e0350
cdevsw_lookup: dev=000fff00, cmajor = 4095, cdevsw = c01e0350
cdev_open: cdevsw_lookup() == NULL, dev=000fff00
spec_open: cdev_open error=6
cdevsw_lookup: dev=000fff00, cmajor = 4095, cdevsw = c01e0350
cdevsw_lookup: dev=000fff00, cmajor = 4095, cdevsw = c01e0350
spec_open: cdev_type(dev) != D_DISK error=6
VOP_OPEN: error=6
cnopen: VOP_UNLOCK error=6
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>
結論から言えば、cdevsw[]に所望のデバイスが見つからない(lookupできない)のでエラーになっていた。
うまくlookupできているものとそうでないものを比較していてぴんときた。
cdevsw_lookup: dev=00000200, cmajor = 2, cdevsw = c01e0350
cdevsw_lookup: dev=000fff00, cmajor = 4095, cdevsw = c01e0350
そういえば、dev=000fff00って変だなと思っていて、wmt_com.cのattachでそれを作っていたのだった。
                /* locate the major number */
                maj = cdevsw_lookup_major(&wmtcom_cdevsw);

                cn_tab->cn_dev = makedev(maj, device_unit(sc->sc_dev));
makedevはビットシフトしてintを作るだけなんだけど、majが怪しいってことですな。
で、それの元ネタになるのが&wmtcom_cdevswなわけで、デバイスのメジャー番号ってどこで定義するんだっけ? 自動的に決まるというはずはなくってどこかに書いたはずだけど、ということでgrep -i major しまくるとarch/arm/conf/majors.arm32にたどり着いた。
ここにはepcomなどのCPU固有のデバイスを含めて記述されている。wmtcomはここに書いていないからうまくlookupできないのに違いない。
evbarm/conf/APCに一行加えてやってみる。
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
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 = c0184f7c, dev=00007000
panic: wmtcom: open

Stopped in pid 1.1 (init) at    netbsd:cpu_Debugger+0x4:        bx      r14
0xca86cbd4: netbsd:vpanic+0xc
0xca86cbec: netbsd:printf_nolog
0xca86cc0c: netbsd:wmtcomopen+0x14
0xca86cc34: netbsd:cdev_open+0x78
0xca86cc84: netbsd:spec_open+0x1b0
0xca86cca8: netbsd:VOP_OPEN+0xa0
0xca86ccd4: netbsd:cnopen+0x150
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>
よし! wmt_com.cのwmtcomopenが呼ばれた!

ついに/sbin/initのシステムコールopenからソフトウェア割込み経由でカーネルに入り、vn_open -> spec_open -> cdev_open -> cn_open -> spec_open -> cdev_open -> wmtcomopenというopenの流れをつなぐことができた。

vnode(vn)からキャラクタデバイス(cdev)にいき、コンソール(cn)に行き、デバイスドライバに行き着くということなんだろうか。

gitリポジトリに久しぶりにcommit & push。ファイルをリネームして億劫になっていた。

結局、git mv oldfile newfileとやらねばならないらしく、ファイル名をいったん戻してからcommitし直して面倒だった。うかつに通常のmvを使ってはいけないね。

さて、ここまで来たら、またixp12x0_comを手本にしてシリアルコンソールドライバを作りこむことになりそうだ。

ハードウェア割込みとソフトウェア割り込みの合わせ技でread/writeするというのを実現しつつ、今のところ用途がわからない関数をうめていくのかなぁ。まずは、ユーザランドから一文字でもいいから出力してみたい。うん。

APC8750にNetBSD/evbarmを移植するための記録 10/3
2014/01/26(日) 22:07 NetBSD はてブ情報 はてブに登録 はてブ数

一日releaseさせて、いざ。

ramdisk.fsがインストールカーネルのfsなので、それをmdsetimageしてブートしてみたが、症状は同じであった。つまり、何にも変わらない。

ということで、mdsetimageやらramdisk.fsを疑うよりも、/sbin/initが動いているのか追っかけてみるのがよさそうである。

/sbin/initはユーザ空間では動いていないので、コンソール出力といってもcnputcは使えないよなぁ、と思いながらinit.cを読む。

するとsbin/init/init.c#393にはprint_consoleという関数が用意されている。少し手前の#if 0で潰されているけれど、なんだこれは。
    392 static void
    393 print_console(int level, const char *message, va_list ap)
    394 {
    395 	/*
    396 	 * XXX: syslog seems to just plain not work in console-only
    397 	 * XXX: situation... that should be fixed.  Let's leave this
    398 	 * XXX: note + code here in case someone gets in trouble and
    399 	 * XXX: wants to debug. -- Jachym Holecek <freza (at) liberouter.org>
    400 	 */
    401 	char errbuf[1024];
    402 	int fd, len;
    403 
    404 	/* We can't do anything on errors, anyway... */
    405 	fd = open(_PATH_CONSOLE, O_WRONLY);
    406 	if (fd == -1)
    407 		return ;
    408 
    409 	/* %m will get lost... */
    410 	len = vsnprintf(errbuf, sizeof(errbuf), message, ap);
    411 	(void)write(fd, (void *)errbuf, len);
    412 	(void)close(fd);
    413 }
いかにもopen, write, closeてな調子でシステムコールを呼んでくれそうだ。ひいては、それがwmtcomopenやwmtcomwriteを読んでくれるのではないか。まぁ、open, writeは実装されていないから、シリアルドライバをちゃんと動くようにしなきゃダメだろうけど。ひとまず、手掛かりを追ってみよう。 

さて、init.cをいじってramdisk.fsを作るのは面倒くさそうである。build.sh releaseを毎回やるのは時間がかかりすぎる。もっと良い手があるはず。

build中のログを見ると、
===> Updated makewrapper: /usr/src/obj/tooldir.NetBSD-6.99.23-amd64/bin/nbmake-evbarm
なる行がある。これを使えば、とても楽ちんである。
builder# cd /usr/src/distrib/evbarm/instkernel/ramdisk/
builder# vi /usr/src/sbin/init/init.c
builder# /usr/src/obj/tooldir.NetBSD-6.99.23-amd64/bin/nbmake-evbarm  > make.log
builder# cp obj/ramdisk.fs /root/md
これでinit.cを修正した版のramdisk.fsができるのである。

ということで、main関数の最初のほうでprint_consoleを仕込んでみた。
wmtmr0 at obio0 addr 0xd8100000-0xd810ffff intr 48 : WMT System Timer
wmtcom0 at obio0 addr 0xd8200000-0xd820ffff intr 32 : WMT UART
wmtcom:wmtcom_attach_subr
icu: establish_irq: is->is_irq=0x20
icu: unblock: irqbase=0x00000020, irqmask=0x00000001, irq_num=32, reg=0x00000008
icu: establish_irq: is->is_irq=0x30
icu: unblock: irqbase=0x00000020, irqmask=0x00010000, irq_num=48, reg=0x00000008
rn_init: radix functions require max_keylen be set
start_init
module_init_class
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: eror = -2
panic: cnopen: no console device
Stopped in pid 1.1 (init) at    netbsd:cpu_Debugger+0x4:        bx      r14
0xca86cc94: netbsd:vpanic+0xc
0xca86ccac: netbsd:printf_nolog
0xca86ccd8: netbsd:cnopen+0xf0
0xca86cd00: netbsd:cdev_open+0x68
0xca86cd50: netbsd:spec_open+0x198
0xca86cd70: netbsd:VOP_OPEN+0x60
0xca86ce24: netbsd:vn_open+0x1dc
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>
よっしゃpanicしてくれた。

トレースからなんとなく、openがソフトウェア割込み(swi)を発生させて、その割込みをswi_handlerが拾って割込み処理をしているように見える。

panicとともに表示されているno console deviceと出力しているのは//nxr.netbsd.org/xref/src/sys/dev/cons.c#cnopen関数である。
     96     cndev = cn_tab->cn_dev;
     97     if (cndev == NODEV) {
     98         /*
     99          * This is most likely an error in the console attach
    100          * code. Panicking looks better than jumping into nowhere
    101          * through cdevsw below....
    102          */
    103         panic("cnopen: no console device");
    104     }
ということで、cn_tab->cn_devがないのである。

なんとなくcn_tabに見覚えがあったので、sys/arch/arm/ixp12x0/ixp12x0_com.c#ixpcom_attach_subrをみてみると、
    183 void
    184 ixpcom_attach_subr(struct ixpcom_softc *sc)
    185 {
... 
    223 
    224 	tty_attach(tp);
    225 
    226 	if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
    227 		int maj;
    228 
    229 		/* locate the major number */
    230 		maj = cdevsw_lookup_major(&ixpcom_cdevsw);
    231 
    232 		cn_tab->cn_dev = makedev(maj, device_unit(sc->sc_dev));
    233 
    234 		aprint_normal("%s: console\n", device_xname(sc->sc_dev));
    235 	}
ここで定義している。つまり、wmtcom_attach_subrで同じようにしてやればよいのであろう。コピーして、すこし手直しすればよさそうである。

動かしてみると、wmtcom_attach_subrで止まる。printf debugしてみるとdelay(10000)で止まっている。
    196 		/* Make sure the console is always "hardwired". */
    197 		/* XXX IXPCOM_SR should be checked  */
    198 		delay(10000);	/* wait for output to finish */
これは、やっぱしdelayを適当に作ったのがイカンかったようですな。wmt_tmr.cもやっぱりちゃんとやらないとダメなんですね。うーん。
とはいえ、delayを#ifdef hogeで飛ばすと、ひとまず先に進んで、やっぱりとまる。
d814007c: 00000000 -> 00000000
wmtmr0 at obio0 addr 0xd8100000-0xd810ffff intr 48 : WMT System Timer
wmtcom0 at obio0 addr 0xd8200000-0xd820ffff intr 32 : WMT UART
wmtcom:wmtcom_attach_subr
wmtcom:wmtcom_attach_subr 1
wmtcom:wmtcom_attach_subr 1-1
wmtcom:wmtcom_attach_subr 1-2
wmtcom:wmtcom_attach_subr 1-3
wmtcom:wmtcom_attach_subr 2
wmtcom:wmtcom_attach_subr 3
wmtcom:wmtcom_attach_subr 3-1
wmtcom0: console
icu: establish_irq: is->is_irq=0x20
icu: unblock: irqbase=0x00000020, irqmask=0x00000001, irq_num=32, reg=0x00000008
icu: establish_irq: is->is_irq=0x30
icu: unblock: irqbase=0x00000020, irqmask=0x00010000, irq_num=48, reg=0x00000008
rn_init: radix functions require max_keylen be set
start_init
module_init_class
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: eror = -2
cons.cは通っているんだろうか?
wmtcomxxxxのaprintf_normalが動く保証がどこにもないな。
うーん、かたっぱしからpanicするようにしたらいいんだろうか。

まず、//nxr.netbsd.org/xref/src/sys/dev/cons.c#cnopenをprintf debug
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: eror = -2
cnopen: minor
cnopen: cn_tab == NULL?
cnopen: cndev == NODEV?
cnopen: dev == cndev?
cnopen: cn_devvp == NULLVP?
Process (pid 1) got sig 11
Process (pid 1) got sig 11
Process (pid 1) got sig 11
Process (pid 1) got sig 11
Process (pid 1) got sig 11
以降sig 11が続く
二回やっても同じ。signal 11はsys/signal.hより、
     63 #define    SIGSEGV        11    /* segmentation violation */
らしい。うーん、変なところを指しているのかな。というか、NULLVPということは、
    114     if (cn_devvp[unit] != NULLVP)
    115         return 0;
ということだから、unitがめちゃくちゃなのかな?
sys_execve: eror = -2
cnopen: minor
cnopen: cn_tab == NULL?
cnopen: cndev == NODEV?
cnopen: dev == cndev?
cnopen: cn_devvp == NULLVP? unit=0
Process (pid 1) got sig 11
Process (pid 1) got sig 11
Process (pid 1) got sig 11
Process (pid 1) got sig 11
unit=0である。cn_devvp触ったら死んでいるということか。
sys/dev/cons.c#cnopenの手前にある定義ではこうなっている。
struct  tty *constty = NULL;    /* virtual console output device */
struct  consdev *cn_tab;        /* physical console device info */
struct  vnode *cn_devvp[2];     /* vnode for underlying device. */

int
cnopen(dev_t dev, int flag, int mode, struct lwp *l)
うーん。なにがいかんのか。わからんので寝る!

あらためて考えたら、ちゃんとsbin/init/init.cの中が実行されているということだよな。

APC8750にNetBSD/evbarmを移植するための記録 9/30
2014/01/26(日) 16:13 NetBSD はてブ情報 はてブに登録 はてブ数

さて、シリアルコンソールが動いてroot deviceを指定できるようになったので、/sbin/initを動かしてみたい。とはいえ、etherドライバもないし、SDのドライバもないのでmdデバイスを使ってメモリ上で動かしてみようと思う。512MBもメモリあるし。

conf/APCにoptions MEMORY_DISKシリーズをINSTALLからパクってくる。

ルートファイルシステムイメージのファイルを作る。
dd if=/dev/zero of=rootfs.img bs=12m count=1
vnconfig vnd0 rootfs.img
newfs /dev/rvnd0a
mount /dev/rvnd0a /mnt
イメージファイルの中身はevbarmのbase.tgz, etc.tgzを拾ってきて、sbin/init, bin/sh, dev/MAKEDEVあたりをコピー。
MAKEDEV allしないとpanicするので注意だな。
mdsetimage netbsd rootfs.img
でメモリディスクつきのkernelになる。簡単だね。
ただ、rescue/init, shで動かしてみると、initを実行するところで止まってしまう。
icu: establish_irq: is->is_irq=0x30
icu: unblock: irqbase=0x00000020, irqmask=0x00010000, irq_num=48, reg=0x00000008
rn_init: radix functions require max_keylen be set
boot device: <unknown>
root on md0a dumps on md0b
mountroot: trying nfs...
mountroot: trying msdos...
mountroot: trying ffs...
root file system type: ffs
WARNING: no TOD clock present
WARNING: using filesystem time
WARNING: CHECK AND RESET THE DATE!
init: copying out flags `-s' 3
init: copying out path `/sbin/init' 11
exec /sbin/init: error 2
init: copying out flags `-s' 3
init: copying out path `/sbin/oinit' 12
exec /sbin/oinit: error 2
init: copying out flags `-s' 3
init: copying out path `/sbin/init.bak' 15
exec /sbin/init.bak: error 2
init path (default /sbin/init): /rescue/init
init: copying out flags `-s' 3
init: copying out path `/rescue/init' 13
うーん、どこが変なのかな。資材が足りてないのか、mdsetimageがうまく動いてくれていないのか。initはバイナリをとってきたやつなのでデバッグ文も入れられらないし。

ディスクイメージの作り方ミスだと悲しすぎるのと改造版/sbin/initを作れるようにするためにbuild.sh releaseしよう。ちゃんとしたやり方でINSTALLカーネルが作られるはずだし。

そういや、initはconsoleをopenするのだろうか。まぁ、インストーラは絶対openするだろうからとにかくやってみるかな。

APC8750にNetBSD/evbarmを移植するための記録 9/28
2014/01/25(土) 14:33 NetBSD はてブ情報 はてブに登録 はてブ数

ひとまずコンパイルを通す作業を始めたが、wm8750と打つのが面倒なのでwmtに全部変えることに。なんとなくuartもcomに名前を変更。

evbarm側にwmtcom_apc.cなるcom用のエントリを作成。
conf/APCもそれに合わせて修正。コンパイルが通るまで一苦労。結局、ixp12x0ベースに直しまくることに。

wmtcomcnputcさえ動いてくれれば、もとのレベルに戻せるということで、ぽつぽ
つと実装を始める。

しかし、文字は出ない。
困ったので、apc_machdep.cにあった文字出力ルーチンを復活させる。

consinitは通っているけど、putcが動いていない模様。無限ループでTX busyを見ているのがいけないのかと思い、comドライバにならってタイムアウト用timo変数を追加してループを抜けるようにしてみたら、ちょろっと文字が出た。

やはりputcが正しく動いていないようだ。状況としては、文字が抜けたりしながら表示を続け、root deviceを聞くところまで進んでいるみたい。表示はぐちゃぐちゃだけど。

u-bootのメモリダンプを眺めつつ、TXONというのもチェックしたほうがいいかなー、ってことでTX BusyとTX Onの両方がOKならループを抜けるというロジックに変更したところ、これがビンゴだったらしく、ちゃんと表示されるようになった。

むしろ、以前よりも高速な気がするぐらいだ。ここまでくれば、入力も動かしたい。

getcのロジックは、実はいいところまで行っていたのだけど、戻り値をもどさず、スケルトンで書いていたreturn 0;をreturn c;にしてやると動くことがわかった。

ということで、めでたく入力と出力ができるようになりました。
WMT # set serverip 192.168.0.10
WMT # tftpboot 8000; go 8000
EEP-less strapping = TRUE
*** Warning: no boot file name; using 'C0A80002.img'
TFTP from server 192.168.0.10; our IP address is 192.168.0.2
Filename 'C0A80002.img'.
Load address: 0x8000
Loading: #################################################################
         ###############################T ##################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         ####################T ##################
done
Bytes transferred = 2520192 (267480 hex)
## Starting application at 0x00008000 ...
00008328
NetBSD
00000000 00000000 004808cb 00000412
00000000 00000412 00000004 00000412
c0000000 00000000 004808cb 0000041e
00003000 0000041e 00000004 0000041e
fe000000 d8000000 010fffff 00000412
00003f80 d8000412 00000010 00000412
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
NS
NetBSD/evbarm (APC) booting ...
initarm: Configuring system ...
arm32_bootmem_init: memstart=0, memsize=0x20000000, kernelstart=0x8000
arm32_bootmem_init: kernelend=0x281000
arm32_bootmem_init: adding 130431 free pages: [0x281000..0x1fffffff] (VA 0xc0281000)
arm32_bootmem_init: adding 8 free pages: [0..0x7fff] (VA 0xc0000000)
arm32_kernel_vm_init: 1 L2 pages are needed to map 0x2ac000 kernel bytes
arm32_kernel_vm_init: allocating page tables for vectoradd_pages: adding pv 0xc026fba8 (pa 0x281000, va 0xc0281000, 1 pages) at tail
 kerneladd_pages: appending pv 0xc026fe30 (0x282000..0x282fff) to 0x281000..0x281fff
 vmadd_pages: appending pv 0xc026fe44 (0x283000..0x283fff) to 0x281000..0x282fff
add_pages: appending pv 0xc027886c (0x284000..0x287fff) to 0x281000..0x283fff
add_pages: appending pv 0xc026fe58 (0x288000..0x288fff) to 0x281000..0x287fff
add_pages: appending pv 0xc026fe6c (0x289000..0x289fff) to 0x281000..0x288fff
add_pages: appending pv 0xc026fe80 (0x28a000..0x28afff) to 0x281000..0x289fff
add_pages: appending pv 0xc026fe94 (0x28b000..0x28bfff) to 0x281000..0x28afff
add_pages: appending pv 0xc026fea8 (0x28c000..0x28cfff) to 0x281000..0x28bfff
add_pages: appending pv 0xc026febc (0x28d000..0x28dfff) to 0x281000..0x28cfff
add_pages: appending pv 0xc026fed0 (0x28e000..0x28efff) to 0x281000..0x28dfff
add_pages: appending pv 0xc027012c (0x28f000..0x28ffff) to 0x281000..0x28efff
add_pages: appending pv 0xc0270140 (0x290000..0x290fff) to 0x281000..0x28ffff
add_pages: appending pv 0xc0270154 (0x291000..0x291fff) to 0x281000..0x290fff
add_pages: appending pv 0xc0270168 (0x292000..0x292fff) to 0x281000..0x291fff
add_pages: appending pv 0xc027017c (0x293000..0x294fff) to 0x281000..0x292fff
add_pages: appending pv 0xc0270118 (0x295000..0x296fff) to 0x281000..0x294fff
add_pages: appending pv 0xc026fc24 (0x297000..0x29afff) to 0x281000..0x296fff
Creating L1 page table at 0x00284000
arm32_kernel_vm_init: adding L2 pt (VA 0xc0281000, PA 0x281000) for VA 0xffff0000
 (vectors)arm32_kernel_vm_init: adding L2 pt (VA 0xc0282000, PA 0x282000) for VA 0xc0000000 (kernel)
arm32_kernel_vm_init: adding L2 pt (VA 0xc0283000, PA 0x283000) for VA 0xc1000000 (vm)
arm32_kernel_vm_init: adding L2 pt (VA 0xc0288000, PA 0x288000) for VA 0xc1400000 (vm)
arm32_kernel_vm_init: adding L2 pt (VA 0xc0289000, PA 0x289000) for VA 0xc1800000 (vm)
arm32_kernel_vm_init: adding L2 pt (VA 0xc028a000, PA 0x28a000) for VA 0xc1c00000 (vm)
arm32_kernel_vm_init: adding L2 pt (VA 0xc028b000, PA 0x28b000) for VA 0xc2000000 (vm)
arm32_kernel_vm_init: adding L2 pt (VA 0xc028c000, PA 0x28c000) for VA 0xc2400000 (vm)
arm32_kernel_vm_init: adding L2 pt (VA 0xc028d000, PA 0x28d000) for VA 0xc2800000 (vm)
arm32_kernel_vm_init: adding L2 pt (VA 0xc028e000, PA 0x28e000) for VA 0xc2c00000 (vm)
Mapping kernel
arm32_kernel_vm_init: adding chunk for kernel text 0x8000..0x1adfff (VA 0xc0008000)
add_pages: adding pv 0xc026fb94 (pa 0x8000, va 0xc0008000, 422 pages) before pa 0x281000
arm32_kernel_vm_init: adding chunk for kernel data/bss 0x1ae000..0x280fff (VA 0xc01ae000)
add_pages: appending pv 0xc026fbfc (0x1ae000..0x280fff) to 0x8000..0x1adfff
add_pages: merging pv 0xc026fba8 (0x281000..0x29afff) to 0x8000..0x280fff
Listing Chunks
arm32_kernel_vm_init: pv 0xc026fb94: chunk VA 0xc0008000..0xc029afff (PA 0x8000, prot 3, cache 1)

Mapping Chunks
arm32_kernel_vm_init: mapping last chunk VA 0xc0008000..0xc029afff (PA 0x8000, prot 3, cache 1)
pmap_map_chunk: pa=0x8000 va=0xc0008000 size=0x293000 resid=0x293000 prot=0x3 cache=1
PPPPPPPPLLLLLLLLLLLLLLLSLLLLLLLLLPPPPPPPPPPP
devmap: d8000000 -> d8ffffff @ fe000000
pmap_map_chunk: pa=0xd8000000 va=0xfe000000 size=0x1000000 resid=0x1000000 prot=0x3 cache=0
SSSSSSSSSSSSSSSS
                             Physical              Virtual        Num
                       Starting    Ending    Starting    Ending   Pages
               SDRAM: 0x00000000 0x1fffffff 0xc0000000 0xdfffffff 131072
        text section: 0x00008000 0x001adfff 0xc0008000 0xc01adfff 422
        data section: 0x001b0000 0x0026f480 0xc01b0000 0xc026f480 192
         bss section: 0x0026f480 0x002808cc 0xc026f480 0xc02808cc 18
   L1 page directory: 0x00284000 0x00287fff 0xc0284000 0xc0287fff 4
   ABT stack (CPU 0): 0x0028f000 0x0028ffff 0xc028f000 0xc028ffff 1
   FIQ stack (CPU 0): 0x00290000 0x00290fff 0xc0290000 0xc0290fff 1
   IRQ stack (CPU 0): 0x00291000 0x00291fff 0xc0291000 0xc0291fff 1
   UND stack (CPU 0): 0x00292000 0x00292fff 0xc0292000 0xc0292fff 1
  IDLE stack (CPU 0): 0x00293000 0x00294fff 0xc0293000 0xc0294fff 2
           SVC stack: 0x00295000 0x00296fff 0xc0295000 0xc0296fff 2
      Message Buffer: 0x00297000 0x0029afff 0xc0297000 0xc029afff 4
   Exception Vectors: 0x0029b000 0x0029bfff 0xffff0000 0xffff0fff 1
         Free Memory: 0x0029c000 0x1fffffff                       130404
         Free Memory: 0x00000000 0x00007fff                       8
switching to new L1 page table @0x284000...TTBR0=0x284000 OK
done.
nfreeblocks = 2, free_pages = 130412 (0x1fd6c)
bootstrap done.
vectorsvectors = ffff0000, vectors_data = ffff011c
vectors[0] = e59ff114, vectors_data[0] = c001d610
vectors[1] = e59ff114, vectors_data[1] = c001d878
vectors[2] = e59ff114, vectors_data[2] = c001d640
vectors[3] = e59ff114, vectors_data[3] = c001d6d4
vectors[4] = e59ff114, vectors_data[4] = c001d74c
vectors[5] = e59ff114, vectors_data[5] = c001d7c0
vectors[6] = e59ff114, vectors_data[6] = c0049560
vectors[7] = e25ef004, vectors_data[7] = 00000000
 0xffff0000
init subsystems: stacks vectors undefined page pmap_physload pmap [ Kernel symbol table missing! ]
done.
Loaded initial symtab at 0xc01b431c, strtab at 0xc01d319c, # entries 7897
pmap_postinit: Allocated 35 static L1 descriptor tables
Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
    2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
    The NetBSD Foundation, Inc.  All rights reserved.
Copyright (c) 1982, 1986, 1989, 1991, 1993
    The Regents of the University of California.  All rights reserved.

NetBSD 6.99.23 (APC) #17: Sat Sep 28 14:46:19 UTC 2013
        root@builder.localdomain:/usr/obj/sys/arch/evbarm/compile/APC
total memory = 512 MB
avail memory = 499 MB
mainbus0 (root)
cpu0 at mainbus0 core 0: ARM1176JZ-S r0p7 (ARM11J V6ZK core)
cpu0: DC enabled IC enabled WB enabled LABT
cpu0: 16KB/32B 4-way L1 Instruction cache
cpu0: 16KB/32B 4-way write-back-locking-C L1 Data cache
vfp0 at cpu0: VFP11
obio0 at mainbus0
wmicu0 at obio0 addr 0xd8140000-0xd814ffff
icu-debug:
d8140040: 00000000 -> 00000000
d8140044: 00000000 -> 00000000
d8140048: 00000000 -> 00000000
d814004c: 00000000 -> 00000000
d8140050: 00000000 -> 00000000
d8140054: 00000000 -> 00000000
d8140058: 00000000 -> 00000000
d814005c: 00000000 -> 00000000
d8140060: 00000000 -> 00000000
d8140064: 00000000 -> 00000000
d8140068: 00000000 -> 00000000
d814006c: 00000000 -> 00000000
d8140070: 00000000 -> 00000000
d8140074: 00000000 -> 00000000
d8140078: 00000000 -> 00000000
d814007c: 00000000 -> 00000000
wmtmr0 at obio0 addr 0xd8100000-0xd810ffff intr 48 : WMT System Timer
wmtcom0 at obio0 addr 0xd8200000-0xd820ffff intr 32 : WMT UART
icu: establish_irq: is->is_irq=0x20
icu: unblock: irqbase=0x00000020, irqmask=0x00000001, irq_num=32, reg=0x00000008
icu: establish_irq: is->is_irq=0x30
icu: unblock: irqbase=0x00000020, irqmask=0x00010000, irq_num=48, reg=0x00000008
rn_init: radix functions require max_keylen be set
boot device: <unknown>
root device:
use one of: ddb halt reboot
root device: reboot
syncing disks... done
unmounting file systems...
unmounting done
rebooting...
ただし、まだ割り込みモードでは動いていないので、それはゆくゆく動かせばいいかと。

ということで、ixp12x0_com.cで割り込みがどのように制御されているかを調べた。

CR_RIE, CR_XIEが割り込みのビットなので、これをON/OFFしているところを探した。関数ごとにOn/Offを見てみると次のような関係になっている。
open : RX On
comintr : TX Off, RX Off
rxsoft RX on
start TX on
comintrでなんらか割り込みが上がってきたら、割り込みをOffにして、ソフトウェア割込みに処理を委譲。

ソフトウェア割込みは処理を終わらせたら割り込みをOn、ということのようだ。txsoftがOnにするのではなく、startでOnにしているのは、txsoftで*tp->linesw->l_start)(tp);という行があるので、間接的ではあるがstartが呼ばれるのではないかなぁと思っている。

しかし謎なのは、openでRXだけOnにしているところだ。もしかしたら、ほかの場所でもstartが呼ばれるということなのかもしれない。
ixpcomparamからもstartが呼ばれているし、きっとそのあたりが割り込みをOnにしてくれているのですかね。

ということで、割込みの有効化はmatchやattachなどでやるのではなく、openされた時にやるものだ、ということがわかった。/dev/consoleがopenされるのはいつなのだろう。