メッセージ欄

2014年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されるのはいつなのだろう。

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

シリアルコンソールのドライバを書くにあたって、まずはRPIをお手本にするということでsys/arch/evbarm/dev/plcom.cだけど、comドライバに似ているつくり、というコメントがある。16550Aを意識しているってことかなぁ。ひとまず避けるか。

シリアルコンソールドライバのサイズを比較してみる。
25,419    arm/clps711x/clpscom.c
26,322    arm/ep93xx/epcom.c
18,175    arm/footbridge/footbridge_com.c
26,658    arm/ixp12x0/ixp12x0_com.c
48,257    arm/s3c2xx0/sscom.c
34,717    arm/sa11x0/sa11x0_com.c
58,808    arm/imx/imxuart.c
一番ちいさいfootbridge_com.cを見てみるか。

短くてわかりやすい。

が、fcomcons_bs_tagの扱いがほかと比べると違う。ほかというのはepcom.c, ixp12x0_com.cなど。

単独でbus_space_tag, handleを定義しているが、そうではなく、softcを定義して構造体でアクセスしている。_io.cというのがついている。なんかこれだけ。ふしぎ。

footbridgeってnetwinderなのか。evbarmかと思ったら、NetBSD/netwinderなのね。だから風情が違うって感じ。
epcom, ixp12x0あたりが似ていて、footbridgeが違うのはそこらへんが由来か。

シンプルなのはいいけど... 参考にするならevbarmあたりのほうがよさげって感じ?

とりあえず、sys/arch/evbarm/ixp12x0/ixp12x0_com.cをベースにスケルトンを作成。

ザックリソースを読んでわかったこと。

dev_type_open(xxx)はシステムコールなのかな。関数ポインタで該当するAPIを呼び出すのが主な仕事。
割り込みルーチンは、下準備をした後ソフトウェア割込みを発生させている模様。
   1173 	/* Wake up the poller. */
   1174 	softint_schedule(sc->sc_si);
ソフトウェア割り込みルーチンは、割り込みの種別(送信・受信)を判断して、それぞれの割り込みルーチンに飛ばしている。
ハードウェア割込みでそれぞれの割り込み処理をやらないのはなぜなんだろう。
ハードウェア割込みからはできるだけ早く復帰しましょう、っていうことなのか?

先ほどのリスト、
25,419    arm/clps711x/clpscom.c
26,322    arm/ep93xx/epcom.c
18,175    arm/footbridge/footbridge_com.c
26,658    arm/ixp12x0/ixp12x0_com.c
48,257    arm/s3c2xx0/sscom.c
34,717    arm/sa11x0/sa11x0_com.c
58,808    arm/imx/imxuart.c
の素性を調べてみる。footbridgeはさっきのとおりnetwinder。
clpsはepoc32だったり。
sscomはevbarm/smdk2xx0, MINI2440、
sacomはhpcarmのJORNADAだったり。
imxはわれらがnetwalkerだったり。

ixp12x0とepcomはそっくりさん。どっちが先に作られたのかを見てみたら、ixp12x0が祖先の模様。
matchとattachはevbarmがわで定義しているみたいですね。
CFATTACH_DECL_NEWがarm/evbarmのどっちに所属するかはそこらへんが違い。

とりあえず、ixp12x0, epcomをベースに進めていくことにしよう。

wm8750というのを頭につけてこれまでやってきたけど、いかにも冗長だなと。
wmtぐらいでよさそうな気がする。どうせwmtなシリアルは似たようなもんだろうし、割り込みあたりは結構違うかもしれないけど、wm8xxxぐらいには同じなんじゃないかな。

そもそもドライバがuart, icu, tmrぐらいしかないので。ていうか、現時点で理解して(したつもりで)作っているのってicuぐらいしかない気がする。

この調子だと、いつになったらインタラクティブな入出力ができるかわからんなぁ。

やっぱり、新しいCPUは無謀だったか。後悔先に立たず。小さな目標を立ててクリアしていこう。

まずはcnシリーズぐらいは動かしたい。すでにputcは動いているのだから、現状ぐらいまでは戻そう。当然TXBUSYはCOMドライバじゃないから面倒見れるわけだし。うむ。

まとめると、
  • evbarmがわにcomドライバを用意する(apccomとか?)
  • dev_type_xxxシリーズは簡単そうなので実装
  • cnシリーズを除くその他の関数は、#ifdefあたりで逃げる
  • cnシリーズを実装
ぐらいはやらないと、コンパイルが通らない&consinitが動作しない。

Linux久々に調べてみるか。UBOOTのコンフィグはここらしいな。

https://github.com/apc-io/apc-8750/blob/master/u-boot/include/configs/wmt.h

なんとここにwmtのソースがいっぱい。

https://github.com/apc-io/apc-8750/tree/master/u-boot/cpu/arm920t/wmt