APC8750にNetBSD/evbarmを移植するための記録 9/22
ということで、落ち着いてLinuxのソースをあさる。シリアルのソースはarch/armの下ではなくdrivers/serialの下にあった。
なんてこった。一か所においてほしいもんだ。
https://github.com/apc-io/apc-8750/blob/master/kernel/drivers/serial/serial_wmt.c
非常に長い。
が、初期化しているところできっと割り込みをONにしているのだろうから、それっぽいところを探す。
IERにビットを立てるのでierをORしている奴を探せばよい。
いかにも初期化している関数を発見。
static int wmt_startup(struct uart_port *port)の1601行目から。
デバッグルーチンにちゃんと入ってくれる。が、割り込みコントローラからはUARTのどの割り込みが入ったかわからない。
いよいよ、割り込みコントローラからcomドライバに制御を移す時が来たといえる。
irq_handlerに入ったら嬉しそうにデバッグ文を出していたが、それ以降を見なければならない。
RPIのsys/arch/arm/broadcom/bcm2835_intr.c#bcm2835_irq_handlerを見ると構造としては、自身(MD)のbcm2835_pic_find_pending_irqsを呼び、そのあとにpic_do_pending_intsを読んでいる。
おなじみgeminiのsys/arch/arm/gemini/gemini_icu.c#find_pending_irqsを見てみる。
なので、この関数は、未処理の割り込みをレジスタから読み込み、picに印をつけておく。と想像できる。
sys/arch/arm/pic/pic.c#pic_mark_pending_sourcesを見てみよう。
そのあと、なにやらループを回している。
ん?ffs()とはなんだろう。と調べると、おどろきの common/lib/libc/arch/arm/string/ffs.Sである。Find First Set bitのことであろう。
つまり、pendingに立っているビットの数ぶんループ処理をしているようだ。
ちょっとまてよ、pendingでループを回したということは、pendingには複数のビットが立っていることが前提なんだな。そういえば、さっきMDのblockを呼んでいたけれども、それは、現時点で未処理の割り込みは「すべて」ブロックせよということか。
ははぁ、block, unblockの引数が、IRQの数字ではなくビットで渡っていた理由はそれか。複数ある未処理の割り込みをblock/unblockに渡すためにビットを使っていたのだな。irq_baseの存在理由もわかった気がする。割込みの数を32個単位で管理するためのベース、というわけだな。
そう考えると、以下の5ビットシフトも納得がいく。
で、最初にirq_baseをもとに割込みの配列をipendingとして取り出して、引き数のpendingとorをとって保存。この保存行為が関数名のmarkってことなんだろうかね。
そのあと、さっきのループを回してipl_maskを作って、picの構造体にorで保存(mark)しているってことなんだろうね。
適当に実装したblock/unblockは、ビットが一つしかたっていない前提で作っていたから、一つの割り込みしかOn/Offできないので、ちゃんと複数ビットをみてすべてのOn/Offをしないとダメですね。
ふーむ。つーことで、find_pending_irqsはipl_maskを返せばよいってことか。
で、さっきほったらかしていた、
そういえば、以前icuを全部ダンプしたときに、eth0とpmc_wakeupの二つの割り込みが同時に上がってきていた際に、そういうレジスタがあった。こいつがそのまま使えるってことだな。
まてよ、APCはgeminiと違って、割り込みが64個あるので、二つのレジスタを両方調べにゃいかんはずだな。
似たようなicuのソースないかなということで、find_pending_irqsを検索してみると、sys/arch/arm/omap/omap2_icu.c#omap_irq_handlerで
ふーむ。orで重ねりゃいいのかな。
sys/arch/arm/marvell/kirkwood.c#kirkwood_find_pending_irqsがかなり似ている。
二つのレジスタからpendingを読んできて、それのORをとっている。
irq_handlerはRPIほぼそのままでよかった。
よくかんがえたら、RPIは複雑なことやっているなぁ。最初に参考にするには難しすぎる。geminiわかりやすいわ。
ということで、動かしてみる。
ちゃんと、pic.cのpic_do_pending_ints(I32_bit, oldipl, frame);に入って、pic_dispatchでis->is_funcの関数ポインタを呼び出してくれればオッケー。
なのだが、wmt_tmrのattachメッセージを出したところで止まる。
デバッグメッセージをあちこちに埋め込んで、block/unblockが期待通りに動いているかを見たりする。
unblockの前にblockが呼ばれていたりして不可解な現象に遭遇する。
それはそうか、unblockのレジスタ操作をした瞬間に割り込み処理に飛べばblock処理が動き、blockのログを出した後unblockに復帰してunblockのログを出すのだから。unblockに入った瞬間にログを出せば、それなりの順序性でログを出す。割り込み処理は脳みそ使うなぁ。
動かしていると、すかっとrootデバイスを聞くところまで進んだり、wmt_tmrのattachで止まったりする。
もしかして、キーをバシバシ叩いていれば割り込みが入ってattachで止まっているんじゃないかなと思い、何度か試行してみる。
確かにそれっぽいぞ。
もしやと思って、pic_dispatchの手前にログを埋め込んで、バシバシしながら起動。おぉ、pic_dicpatchまで動いているではないか。
ということは、
comintr()にログを仕込む。確かに実行されている!
が、だんまりである。
comintrは長いので、ばらばらとログを埋めて再実行。なんかしらんが、無限ループにはまっている。
今さらだが、よくよく考えてみると、comドライバのレジスタとwmt_uartのレジスタは全然違っているような気がする。
たしかに、IERなどの名前は同じものがあるのだが、レジスタの並びであるとか、comにはないIrDAのレジスタがあったりと。
そもそも16550Aコンパチだというのは、誰が言ったのだ? たしかにcomドライバで文字は出たけれど、たまたまシリアル出力のためのTXレジスタがどちらも先頭アドレスにあって、たまたま出ているだけなのではないのか?
というか、16550Aコンパチと思い込んだのは自分の早とちりではないか。
そう思って、Linuxのコードとcomドライバのコードを見比べると、レジスタの使いっぷりが全然違う。別物だろうこれは。
おいちょっとまて、これってシリアルコンソールドライバを全部自分で作らないとダメなのか? matchとattachぐらい書けば、あとはcomドライバで面倒見てくれると思っていたから、ここまで頑張れたのに。
シリアルコンソールドライバを自前実装している奴らは、1,000行とか2,000行とかあるんだけど。
自前シリアルコンソールドライバを見つけては絶望していたのだが、sys/arch/arm/s3c2xx0/sscom.c#1850を眺めていて気になるコメントが。
なんか、cngetc, cnputc, cnpollcとattach/detachだけでよさそう。んー、つまりこれは割り込みベースじゃなくって、ポーリングベースで動かすためのミニマムセットなのか?
まてよ、この名前ってどっかでみたぞ。これってcomドライバにもあった。というか、出力ルーチンでタイムアウトを削ったのってcnputcじゃなかったっけ?
もしかすると、割り込みベースでコンソールを動かすことをあきらめたら、俺でも実装できるんじゃ? cnputcはもうあるようなもの(レジスタに値書き込むだけ)だし、ビジーループで待てば、文字も詰まらないはず?
ふーむ。方針を変更して、FIFOだのDMAだの難しいことはやらず、ポーリングベースで動かせるんだろうか?
じゃぁ、sys/dev/cons.c#cngetcを読んでいるところを調べてみるか。
なんだ、実態は同じところにあるsys/dev/cons.c#cngetsnじゃないか。これは、複数文字をgetcするってことだよな。じゃぁ、cngetsnはどこから呼ばれているのかな。
init_mainで/sbin/initって入力するところとroot device, dump device, file systemきいてくるところだけだ。そこだけポーリングモードで入力できても、だめじゃん。
やっぱり、ぜんぶシリアルコンソールドライバを作らないといけないのか。
まぁ、でもすこしでも入力が動くと楽しそうだから、まずはcnシリーズを作ってみましょうか。
なんてこった。一か所においてほしいもんだ。
https://github.com/apc-io/apc-8750/blob/master/kernel/drivers/serial/serial_wmt.c
非常に長い。
が、初期化しているところできっと割り込みをONにしているのだろうから、それっぽいところを探す。
IERにビットを立てるのでierをORしている奴を探せばよい。
いかにも初期化している関数を発見。
static int wmt_startup(struct uart_port *port)の1601行目から。
/* * Enable RX FIFO almost full, timeout, and overrun interrupts. */ uart->urier = URIER_ERXFAF | URIER_ERXFF | URIER_ERXTOUT | URIER_EPER | URIER_EFER | URIER_ERXDOVR;きっとここだろう。URIERシリーズはarch/arm/mach-wmt/include/mach/wmt_uart.hにある。
/* * UART Interrupt Enable Register Bit Definitions */ #define URIER_ETXDE BIT0 /* Enable for TX data register empty */ #define URIER_ERXDF BIT1 /* Enable for RX data register full */ #define URIER_ETXFAE BIT2 /* Enable for TX FIFO almost full */ #define URIER_ETXFE BIT3 /* Enable for TX FIFO full */ #define URIER_ERXFAF BIT4 /* Enable for RX FIFO almost full */ #define URIER_ERXFF BIT5 /* Enable for RX FIFO full */ #define URIER_ETXDUDR BIT6 /* Enable for TX underrun */ #define URIER_ERXDOVR BIT7 /* Enable for RX overrun */ #define URIER_EPER BIT8 /* Enable for parity error */ #define URIER_EFER BIT9 /* Enable for frame error */ #define URIER_EMODM BIT10 /* Enable for modem control signal */ #define URIER_ERXTOUT BIT11 /* Enable for receive time out */ #define URIER_EBK BIT12 /* Enable for break signal done */ /* Bit[13:31] are reserved. */これで、Linuxで立てているbitがわかったので、これを真似することに。
デバッグルーチンにちゃんと入ってくれる。が、割り込みコントローラからはUARTのどの割り込みが入ったかわからない。
いよいよ、割り込みコントローラからcomドライバに制御を移す時が来たといえる。
irq_handlerに入ったら嬉しそうにデバッグ文を出していたが、それ以降を見なければならない。
RPIのsys/arch/arm/broadcom/bcm2835_intr.c#bcm2835_irq_handlerを見ると構造としては、自身(MD)のbcm2835_pic_find_pending_irqsを呼び、そのあとにpic_do_pending_intsを読んでいる。
155 void 156 bcm2835_irq_handler(void *frame) 157 { 158 struct cpu_info * const ci = curcpu(); 159 const int oldipl = ci->ci_cpl; 160 const uint32_t oldipl_mask = __BIT(oldipl); 161 int ipl_mask = 0; 162 163 ci->ci_data.cpu_nintr++; 164 165 bcm2835_barrier(); 166 ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic); 167 168 /* 169 * Record the pending_ipls and deliver them if we can. 170 */ 171 if ((ipl_mask & ~oldipl_mask) > oldipl_mask) 172 pic_do_pending_ints(I32_bit, oldipl, frame); 173 }pic_do_pending_intsはsys/arch/arm/pic/pic.c#pic_do_pending_intsにあるので、まずはbrm2835_pic_find_pending_irqは何をするのか読み解かねばならない。が、さっぱりわからない。
194 /* 195 * Called with interrupts disabled 196 */ 197 static int 198 bcm2835_pic_find_pending_irqs(struct pic_softc *pic) 199 { 200 int ipl = 0; 201 uint32_t bpending, gpu0irq, gpu1irq, armirq; 202 203 bcm2835_barrier(); 204 bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING); 205 if (bpending == 0) 206 return 0; 207 208 armirq = bpending & BCM2835_INTBIT_ARM; 209 gpu0irq = bpending & BCM2835_INTBIT_GPU0; 210 gpu1irq = bpending & BCM2835_INTBIT_GPU1; 211 212 if (armirq) { 213 ipl |= pic_mark_pending_sources(pic, BCM2835_INT_BASICBASE, 214 armirq); 215 216 } 217 218 if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) { 219 uint32_t pending1; 220 221 pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING); 222 ipl |= pic_mark_pending_sources(pic, BCM2835_INT_GPU0BASE, 223 pending1); 224 } 225 if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) { 226 uint32_t pending2; 227 228 pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING); 229 ipl |= pic_mark_pending_sources(pic, BCM2835_INT_GPU1BASE, 230 pending2); 231 } 232 233 return ipl; 234 }ということで、ほかのpicを使っている実装を見てみることにした。
おなじみgeminiのsys/arch/arm/gemini/gemini_icu.c#find_pending_irqsを見てみる。
154 /* 155 * Called with interrupts disabled 156 */ 157 static int 158 find_pending_irqs(struct geminiicu_softc *sc) 159 { 160 uint32_t pending = INTC_READ(sc, GEMINI_ICU_IRQ_STATUS); 161 162 KASSERT((sc->sc_enabled_mask & pending) == pending); 163 164 if (pending == 0) 165 return 0; 166 167 return pic_mark_pending_sources(&sc->sc_pic, 0, pending); 168 }おぉ、なんかあっさりしているぞ。
- なんかレジスタを読む。結果が0なら0を返す。
- pic_mark_pending_sourceを返す
なので、この関数は、未処理の割り込みをレジスタから読み込み、picに印をつけておく。と想像できる。
sys/arch/arm/pic/pic.c#pic_mark_pending_sourcesを見てみよう。
191 uint32_t 192 pic_mark_pending_sources(struct pic_softc *pic, size_t irq_base, 193 uint32_t pending) 194 { 195 struct intrsource ** const isbase = &pic->pic_sources[irq_base]; 196 struct intrsource *is; 197 volatile uint32_t *ipending = &pic->pic_pending_irqs[irq_base >> 5]; 198 uint32_t ipl_mask = 0; 199 200 if (pending == 0) 201 return ipl_mask; 202 203 KASSERT((irq_base & 31) == 0); 204 205 (*pic->pic_ops->pic_block_irqs)(pic, irq_base, pending); 206 207 atomic_or_32(ipending, pending); 208 while (pending != 0) { 209 int n = ffs(pending); 210 if (n-- == 0) 211 break; 212 is = isbase[n]; 213 KASSERT(is != NULL); 214 KASSERT(irq_base <= is->is_irq && is->is_irq < irq_base + 32); 215 pending &= ~__BIT(n); 216 ipl_mask |= __BIT(is->is_ipl); 217 } 218 219 atomic_or_32(&pic->pic_pending_ipls, ipl_mask); 220 atomic_or_32(&pic_pending_ipls, ipl_mask); 221 atomic_or_32(&pic_pending_pics, __BIT(pic->pic_id)); 222 223 return ipl_mask; 224 }これも難しいな。なんか、
205 (*pic->pic_ops->pic_block_irqs)(pic, irq_base, pending);でMDのblockルーチンを読んでいる。これはきっと当該割り込みをOFF(ブロック)するということだろう。
そのあと、なにやらループを回している。
ん?ffs()とはなんだろう。と調べると、おどろきの common/lib/libc/arch/arm/string/ffs.Sである。Find First Set bitのことであろう。
つまり、pendingに立っているビットの数ぶんループ処理をしているようだ。
- pendingに立っているビットを見つける(nとする)
- 割込みnの割り込みソース(is)を取得
- pendingに立っているビットをクリア
- ipl_maskにis->is_iplを立てる
43 /* Interrupt priority "levels". */ 44 #define IPL_NONE 0 /* nothing */ 45 #define IPL_SOFTCLOCK 1 /* clock */ 46 #define IPL_SOFTBIO 2 /* block I/O */ 47 #define IPL_SOFTNET 3 /* software network interrupt */ 48 #define IPL_SOFTSERIAL 4 /* software serial interrupt */ 49 #define IPL_VM 5 /* memory allocation */ 50 #define IPL_SCHED 6 /* clock interrupt */ 51 #define IPL_HIGH 7 /* everything */ 52 53 #define NIPL 8なので、ipl_maskにはそれぞれのIPLに応じたビットを立てるのがこの関数の役目である。
ちょっとまてよ、pendingでループを回したということは、pendingには複数のビットが立っていることが前提なんだな。そういえば、さっきMDのblockを呼んでいたけれども、それは、現時点で未処理の割り込みは「すべて」ブロックせよということか。
ははぁ、block, unblockの引数が、IRQの数字ではなくビットで渡っていた理由はそれか。複数ある未処理の割り込みをblock/unblockに渡すためにビットを使っていたのだな。irq_baseの存在理由もわかった気がする。割込みの数を32個単位で管理するためのベース、というわけだな。
そう考えると、以下の5ビットシフトも納得がいく。
197 volatile uint32_t *ipending = &pic->pic_pending_irqs[irq_base >> 5];pic->pic_pending_irqsは32個単位で管理されている割り込みの配列(ビットだけど)というわけね。
で、最初にirq_baseをもとに割込みの配列をipendingとして取り出して、引き数のpendingとorをとって保存。この保存行為が関数名のmarkってことなんだろうかね。
そのあと、さっきのループを回してipl_maskを作って、picの構造体にorで保存(mark)しているってことなんだろうね。
適当に実装したblock/unblockは、ビットが一つしかたっていない前提で作っていたから、一つの割り込みしかOn/Offできないので、ちゃんと複数ビットをみてすべてのOn/Offをしないとダメですね。
ふーむ。つーことで、find_pending_irqsはipl_maskを返せばよいってことか。
で、さっきほったらかしていた、
- なんかレジスタから読む
そういえば、以前icuを全部ダンプしたときに、eth0とpmc_wakeupの二つの割り込みが同時に上がってきていた際に、そういうレジスタがあった。こいつがそのまま使えるってことだな。
まてよ、APCはgeminiと違って、割り込みが64個あるので、二つのレジスタを両方調べにゃいかんはずだな。
似たようなicuのソースないかなということで、find_pending_irqsを検索してみると、sys/arch/arm/omap/omap2_icu.c#omap_irq_handlerで
145 ipl_mask |= find_pending_irqs(sc, 0); ... 147 ipl_mask |= find_pending_irqs(sc, 1); ... 149 ipl_mask |= find_pending_irqs(sc, 2);みたいにorで重ねていたりする。
ふーむ。orで重ねりゃいいのかな。
sys/arch/arm/marvell/kirkwood.c#kirkwood_find_pending_irqsがかなり似ている。
二つのレジスタからpendingを読んできて、それのORをとっている。
181 kirkwood_find_pending_irqs(void) 182 { 183 int ipl = 0; 184 185 uint32_t causelow = read_mlmbreg(KIRKWOOD_MLMB_MICLR); 186 uint32_t pendinglow = read_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR); 187 188 pendinglow &= causelow; 189 if (pendinglow != 0) 190 ipl |= pic_mark_pending_sources(&kirkwood_pic, 0, pendinglow); 191 192 if ((causelow & (1 << KIRKWOOD_IRQ_HIGH)) == (1 << KIRKWOOD_IRQ_HIGH)) { 193 uint32_t causehigh = read_mlmbreg(KIRKWOOD_MLMB_MICHR); 194 uint32_t pendinghigh = read_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR); 195 pendinghigh &= causehigh; 196 ipl |= pic_mark_pending_sources(&kirkwood_pic, 32, pendinghigh); 197 } 198 199 return ipl; 200 }APCだと、causeとか関係なくとれちゃいそう。こんなのでどうだろう。
/* * Called with interrupts disabled */ static int wm8750_pic_find_pending_irqs(struct pic_softc *pic) { int ipl = 0; uint32_t pending_l = read_icureg(ICIS_L); uint32_t pending_h = read_icureg(ICIS_H); ipl |= pic_mark_pending_sources(pic, 0, pending_l); ipl |= pic_mark_pending_sources(pic, 32, pending_h); return ipl; }block/unblockの複数ビット対応も、すごいすなおにループを回す実装をしてみた。
static void wm8750_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase, uint32_t irq_mask) { uint32_t reg = 0xFFFFFFFF; uint32_t irq_num = 9999; int i; for (i = 0; i < 32; i++) { if (irq_mask & (1<<i)) { irq_num = irqbase + i; reg = read_ic0((irq_num/4)*4); reg |= ((INTC_ENABLE) << ((irq_num % 4) * 8)); write_ic0((irqbase/4)*4, reg); } } aprint_normal("icu: unblock: irqbase=0x%08x, irqmask=0x%08x, irq_num=%d, reg=0x%08x\n", (int)irqbase, irq_mask, irq_num, reg); } static void wm8750_pic_block_irqs(struct pic_softc *pic, size_t irqbase, uint32_t irq_mask) { uint32_t reg=9999, irq_num=0xFFFFFFFF; int i; /* print_regs(); */ for (i = 0; i < 32; i++) { if (irq_mask == (1<<i)) { irq_num = irqbase + i; reg = read_ic0((irq_num/4)*4); reg &= ~((INTC_ENABLE) << ((irq_num % 4)*8)); write_ic0((irqbase/4)*4, reg); } } aprint_normal("icu: block: irqbase=0x%08x, irqmask=0x%08x, irq_num=%d, reg=0x%08x\n", (int)irqbase, irq_mask, irq_num, reg); }よくかんがえたら、ffs()をつかったり、read_4/write_4ではなくread_1/write_1を使ったほうが素直な気がしてきた。後から直そうか。
irq_handlerはRPIほぼそのままでよかった。
よくかんがえたら、RPIは複雑なことやっているなぁ。最初に参考にするには難しすぎる。geminiわかりやすいわ。
ということで、動かしてみる。
ちゃんと、pic.cのpic_do_pending_ints(I32_bit, oldipl, frame);に入って、pic_dispatchでis->is_funcの関数ポインタを呼び出してくれればオッケー。
なのだが、wmt_tmrのattachメッセージを出したところで止まる。
デバッグメッセージをあちこちに埋め込んで、block/unblockが期待通りに動いているかを見たりする。
unblockの前にblockが呼ばれていたりして不可解な現象に遭遇する。
それはそうか、unblockのレジスタ操作をした瞬間に割り込み処理に飛べばblock処理が動き、blockのログを出した後unblockに復帰してunblockのログを出すのだから。unblockに入った瞬間にログを出せば、それなりの順序性でログを出す。割り込み処理は脳みそ使うなぁ。
動かしていると、すかっとrootデバイスを聞くところまで進んだり、wmt_tmrのattachで止まったりする。
もしかして、キーをバシバシ叩いていれば割り込みが入ってattachで止まっているんじゃないかなと思い、何度か試行してみる。
確かにそれっぽいぞ。
もしやと思って、pic_dispatchの手前にログを埋め込んで、バシバシしながら起動。おぉ、pic_dicpatchまで動いているではないか。
ということは、
264 rv = (*is->is_func)(is->is_arg);の部分が実行され、関数ポインタis->is_funcであるcomintr、つまりcomドライバの割り込みルーチンに飛んでいるということでは!
comintr()にログを仕込む。確かに実行されている!
が、だんまりである。
comintrは長いので、ばらばらとログを埋めて再実行。なんかしらんが、無限ループにはまっている。
今さらだが、よくよく考えてみると、comドライバのレジスタとwmt_uartのレジスタは全然違っているような気がする。
たしかに、IERなどの名前は同じものがあるのだが、レジスタの並びであるとか、comにはないIrDAのレジスタがあったりと。
そもそも16550Aコンパチだというのは、誰が言ったのだ? たしかにcomドライバで文字は出たけれど、たまたまシリアル出力のためのTXレジスタがどちらも先頭アドレスにあって、たまたま出ているだけなのではないのか?
というか、16550Aコンパチと思い込んだのは自分の早とちりではないか。
そう思って、Linuxのコードとcomドライバのコードを見比べると、レジスタの使いっぷりが全然違う。別物だろうこれは。
おいちょっとまて、これってシリアルコンソールドライバを全部自分で作らないとダメなのか? matchとattachぐらい書けば、あとはcomドライバで面倒見てくれると思っていたから、ここまで頑張れたのに。
シリアルコンソールドライバを自前実装している奴らは、1,000行とか2,000行とかあるんだけど。
自前シリアルコンソールドライバを見つけては絶望していたのだが、sys/arch/arm/s3c2xx0/sscom.c#1850を眺めていて気になるコメントが。
1850 /* 1851 * Following are all routines needed for SSCOM to act as console 1852 */ん? 以下はコンソールとして動かすのに必要なすべてのルーチンである、と言っている?
なんか、cngetc, cnputc, cnpollcとattach/detachだけでよさそう。んー、つまりこれは割り込みベースじゃなくって、ポーリングベースで動かすためのミニマムセットなのか?
まてよ、この名前ってどっかでみたぞ。これってcomドライバにもあった。というか、出力ルーチンでタイムアウトを削ったのってcnputcじゃなかったっけ?
もしかすると、割り込みベースでコンソールを動かすことをあきらめたら、俺でも実装できるんじゃ? cnputcはもうあるようなもの(レジスタに値書き込むだけ)だし、ビジーループで待てば、文字も詰まらないはず?
ふーむ。方針を変更して、FIFOだのDMAだの難しいことはやらず、ポーリングベースで動かせるんだろうか?
じゃぁ、sys/dev/cons.c#cngetcを読んでいるところを調べてみるか。
なんだ、実態は同じところにあるsys/dev/cons.c#cngetsnじゃないか。これは、複数文字をgetcするってことだよな。じゃぁ、cngetsnはどこから呼ばれているのかな。
init_mainで/sbin/initって入力するところとroot device, dump device, file systemきいてくるところだけだ。そこだけポーリングモードで入力できても、だめじゃん。
やっぱり、ぜんぶシリアルコンソールドライバを作らないといけないのか。
まぁ、でもすこしでも入力が動くと楽しそうだから、まずはcnシリーズを作ってみましょうか。
コメント(0件)
- TB-URL http://www.tokuda.net/diary/adiary.cgi/0834/tb/
APC8750にNetBSD/evbarmを移植するための記録 9/17
もしかしたら、UARTの初期化が足らないのかもしれない。
U-bootでシリアル付近をダンプ
ひとまず、IC Highest-priority Status registerのやつ、本当かどうか試してみる。
任意のIRQをON/OFFできる配列を作り、attachで書き込み、自在に割り込みをコントロールしようとしたのだが、うまくいかない。
気づいたのだが、割り込みは、ビット的に右から割り振られるようだ。
つまり、IRQ0からIRQ3を32bitで表現すると0x[IRQ3][IRQ2][IRQ1][IRQ0]という並び順になるようだ。どうりでOn/Offがうまくいかないわけだ。左からだとてっきり思っていた。ということで、このルールにしたがうと、ちゃんと割り込みを制御できることがわかった。
ついでに気づいたのだが、IC Interrupt Status registerをみてみると、当該IRQ番目のビットに1が立っている。
たとえば、IRQ22であれば左から0から始めて22番目にビットが立った0x00400000になっている。
調子に乗って、eth0のIRQ10も同時に発生させると、22番目と10番目の両方にビットが立った0x00400400が得られるようだ。
同時に複数の割り込みが入った時には、ここを見ればよいことがわかった。で、複数入ったうちの優先度の高いものが、その名のとおりIC Highest-priority Status registerに数字として格納されるということのようだ。
さて、ここまできたが、一向にUARTの割り込みが入らない。
良く考えてみたら、u-bootは割り込みで動いていないのではないか?
そういえば、割り込みの64個あるディスクリプタは全部ゼロだったではないか。割り込みが上がるはずはない。しかしながら、入力はできている。もしかして、ポーリングモードなのかもしれない。
そういえば、wmt_uart.hにはFIFO full/emptyだのregister full/emptyだのとあった。そもそも16550AはFIFOを持っていて割り込みで動くとWikipediaにも書いてあって、割り込みじゃなきゃいけないと思い込んでいたのか?だんだん混乱してきたぞ。
UART register fifoでググると素晴らしいページが見つかった。
beagleboard を触ろう - 割り込み [組み込みソフト]
ここにかいてあるところによると、割り込みモードというのがあるらしい。
IER Interrupt Enable RegisterとFCR FIFO Control Registerやらに設定を行えば、割り込みが入ると書いてある。割り込みがアサートされる、というのが言い回しのようで勉強になる。
とりあえず、いっぱいビットを立てて動かしてみたれ、IERとFCRの両方に大量にビットを立ててみた。
なんと、割り込みが入った。ちゃんとInterrput status registerの32番目に1が立っているし、IC Highest-priority Status registerにも0x20が表示されている。よしよし。やっぱりUARTの初期化が足らなかったのだな。
とにかく、いっぱいビットを立てすぎてしまったので、割り込みが入りまくって、当初の狙いであるシリアル入力の割り込みだけを捕捉したい。
おそらく、IERとFCRのビットをそれぞれうまくセットすればよいのだろう。
ということで、TXっぽいビットをかたっぱしから落としたが、こんどはシリアル出力ができなくなった。
そもそもIERのまえにFCRを設定しなければ、意味がないのでは、などと順番を入れ替えたり、あれこれ試したが、どうにも入力だけに反応するような状態にはならない。
場当たり的な試行錯誤で頑張るのはやめて、すこしほかの実装を見るほうが今は近道かな。
とりえず、UARTからの割り込みの上げ方は(制御はできないけれども)わかったのでよしとしよう。
動作確認するために無理やりコードをいじっていて、収拾がつかなくなっていたりするし、unblock・blockのルーチンも間違ったままなので、すこし割り込みコントローラ周りを本来の動作にしてあげなければならないと思う。
irq_handlerが本来何をすべきなのか、そこから呼ばれるルーチンからcomドライバの割り込み処理まで繋いでであげないといけないし。複数の同時割込みも、レジスタを見たらわかる、ということが判明したし。
そういえば、UARTの表示が遅くて手を入れた件は、もしかしたらレジスタはポーリングモードだがcomドライバは割り込み前提で作られていたりするからタイムアウトに時間がかかっているのかもしれないな。ということは、手を入れたところをもどして、割り込みのOn/Offで挙動が変わるか調べてみればよいかもしれない。いらないかと思っていたTXの割り込みも実際には必要なのかも?
今日はここまでにしよう。
U-bootでシリアル付近をダンプ
WMT # md.l d8200000 64 d8200000: 0000003a 0000000d 00010007 00000007 :............... d8200010: 00000000 00000000 00000081 00000003 ................ d8200020: 00000000 00000000 000001d8 0000000a ................bus spaceで読んでみる。
0000: 0000000d 0004: 0000000d 0008: 00010007 000c: 00000007 0010: 00000000 0014: 00000000 0018: 00000041 001c: 00000003 0020: 00000000 0024: 00000000 0028: 000001d8わかりやすく並べる。
d8200000: 0000003a 0000000d 00010007 00000007 :............... d8200000: 0000000d 0000000d 00010007 00000007 d8200010: 00000000 00000000 00000081 00000003 ................ d8200010: 00000000 00000000 00000041 00000003 d8200020: 00000000 00000000 000001d8 0000000a ................ d8200020: 00000000 00000000 000001d8ほとんど変わらない。00000081と00000041ぐらいか。無理やり上書きしてもダメであった。
ひとまず、IC Highest-priority Status registerのやつ、本当かどうか試してみる。
任意のIRQをON/OFFできる配列を作り、attachで書き込み、自在に割り込みをコントロールしようとしたのだが、うまくいかない。
気づいたのだが、割り込みは、ビット的に右から割り振られるようだ。
つまり、IRQ0からIRQ3を32bitで表現すると0x[IRQ3][IRQ2][IRQ1][IRQ0]という並び順になるようだ。どうりでOn/Offがうまくいかないわけだ。左からだとてっきり思っていた。ということで、このルールにしたがうと、ちゃんと割り込みを制御できることがわかった。
ついでに気づいたのだが、IC Interrupt Status registerをみてみると、当該IRQ番目のビットに1が立っている。
たとえば、IRQ22であれば左から0から始めて22番目にビットが立った0x00400000になっている。
調子に乗って、eth0のIRQ10も同時に発生させると、22番目と10番目の両方にビットが立った0x00400400が得られるようだ。
同時に複数の割り込みが入った時には、ここを見ればよいことがわかった。で、複数入ったうちの優先度の高いものが、その名のとおりIC Highest-priority Status registerに数字として格納されるということのようだ。
さて、ここまできたが、一向にUARTの割り込みが入らない。
良く考えてみたら、u-bootは割り込みで動いていないのではないか?
そういえば、割り込みの64個あるディスクリプタは全部ゼロだったではないか。割り込みが上がるはずはない。しかしながら、入力はできている。もしかして、ポーリングモードなのかもしれない。
そういえば、wmt_uart.hにはFIFO full/emptyだのregister full/emptyだのとあった。そもそも16550AはFIFOを持っていて割り込みで動くとWikipediaにも書いてあって、割り込みじゃなきゃいけないと思い込んでいたのか?だんだん混乱してきたぞ。
UART register fifoでググると素晴らしいページが見つかった。
beagleboard を触ろう - 割り込み [組み込みソフト]
ここにかいてあるところによると、割り込みモードというのがあるらしい。
IER Interrupt Enable RegisterとFCR FIFO Control Registerやらに設定を行えば、割り込みが入ると書いてある。割り込みがアサートされる、というのが言い回しのようで勉強になる。
とりあえず、いっぱいビットを立てて動かしてみたれ、IERとFCRの両方に大量にビットを立ててみた。
なんと、割り込みが入った。ちゃんとInterrput status registerの32番目に1が立っているし、IC Highest-priority Status registerにも0x20が表示されている。よしよし。やっぱりUARTの初期化が足らなかったのだな。
とにかく、いっぱいビットを立てすぎてしまったので、割り込みが入りまくって、当初の狙いであるシリアル入力の割り込みだけを捕捉したい。
おそらく、IERとFCRのビットをそれぞれうまくセットすればよいのだろう。
ということで、TXっぽいビットをかたっぱしから落としたが、こんどはシリアル出力ができなくなった。
そもそもIERのまえにFCRを設定しなければ、意味がないのでは、などと順番を入れ替えたり、あれこれ試したが、どうにも入力だけに反応するような状態にはならない。
場当たり的な試行錯誤で頑張るのはやめて、すこしほかの実装を見るほうが今は近道かな。
とりえず、UARTからの割り込みの上げ方は(制御はできないけれども)わかったのでよしとしよう。
動作確認するために無理やりコードをいじっていて、収拾がつかなくなっていたりするし、unblock・blockのルーチンも間違ったままなので、すこし割り込みコントローラ周りを本来の動作にしてあげなければならないと思う。
irq_handlerが本来何をすべきなのか、そこから呼ばれるルーチンからcomドライバの割り込み処理まで繋いでであげないといけないし。複数の同時割込みも、レジスタを見たらわかる、ということが判明したし。
そういえば、UARTの表示が遅くて手を入れた件は、もしかしたらレジスタはポーリングモードだがcomドライバは割り込み前提で作られていたりするからタイムアウトに時間がかかっているのかもしれないな。ということは、手を入れたところをもどして、割り込みのOn/Offで挙動が変わるか調べてみればよいかもしれない。いらないかと思っていたTXの割り込みも実際には必要なのかも?
今日はここまでにしよう。
- TB-URL http://www.tokuda.net/diary/adiary.cgi/0833/tb/
APC8750にNetBSD/evbarmを移植するための記録 9/7 その2
割り込み処理がどう呼ばれるのかを追っかけてみる。
comの場合、comintrという関数が割り込み処理で呼ばれる。
それを登録するのは、シリアルドライバのattach処理で呼ばれているintr_establishである。
intr_establishはsys/arch/arm/pic/pic.c#699にあり、同ファイル内のpic_establish_intrを呼ぶ。
is->is_funcを呼び出しているところは、sys/arch/arm/pic/pic.c#pic_dispatchである。
gemini_irq_handlerを呼び出しているのは、検索すると出てこないと思いきや、ヘッダファイルに手掛かりがあった。
geminiであればsys/arch/arm/gemini/gemini_intr.h#6にある。
sys/arch/arm/arm32/irq_dispatch.S#87をみると、ARM_IRQ_HANDLERにジャンプしている。
page0relはどこだろうか。
sys/arch/arm/arm32/arm32_machdep.c#arm32_vector_initで使われている。
VERBOSE_INIT_ARMして、該当箇所を見てみよう。
あれ? vbarっていうのが表示されていないな。ブロックごと飛ばされているって感じに見えるな。ARM_HAS_VBARっていうのが関係している?
ARM_HAS_VBARがRPIはあるけどAPCにはつけてないな。
あらためて、RPIと比べるとstd.rpi, std.apcは違いがある。
__HAVE_CPU_COUNTERとか。これは誰をベースにしたんだっけ?
ARM_HAS_VBARを有効にしたら以下のようになった。
しかし、割り込みハンドラは呼ばれない。さて、なぜでしょうか?
ARMjp-vH.pdfのA2-16、A2.6 例外によるとIRQ(割り込み)は0x00000018, 0xffff001cのアドレスだと書かれている。
本当にそうなのか試してみよう。
ubootのプロンプトを使って割り込みベクタを表示。リセット割込みのアドレスに書かれているea00002cにジャンプしてみる。
VBARが有効ならば、先のc01411c0に飛べばリセットされるはずである。
じゃぁ、リセット割込み以外e59ff2d4が実行されるみたいだ。
ところでnetbsdをobjdump -dしてみると
あれ?変わらない。
obj全部消してやり直そう。-uついてなかったので作り直しているはずなんだけどな。
とおもっていたら、std.rpiを消してた!
うーん、やっぱりだめですね。ffff0000に配置されていません。
と思ったら、違うんですな。よく読むと、ARM_VECTORS_LOWじゃないから以下のルートに入るのですね。
デバッグ文を入れてみると以下のように。
これで、割り込みが来たらジャンプしてくれるはずです。
が、割込みが来ない。なぜだ。割り込み禁止になっていたりするんですかね?
逆に、どこで割り込みを有効にするんでしょうか?
思い起こせば、start.Sを読んだのがいつだったか。
確か、割り込みを禁止していたような。と思いつつrpiのstartを眺めるも、アセンブラは忘却の彼方。
こういう時には別所さん由来の橋本さんソースを読もう。ということでnetwalkerである。
もう。いい感じでコメントが入っているではないか。
同様にrpiでも同じ処理をしておる。むしろ、冒頭である。
さて、割り込みを禁止しているのだから、どこかでそれを解いているはず。
ここまで読んでくると、cpsrがキーワードだとわかる。
cpsrでnxr検索すればヒントが。
enable_interrputしてるやん。
しかし、すべてがそうではない。
src/sys/arch/armだとat91, ep93xx, footbridge, imx, iomd, ixp12x0, mpcore, ofw, omap, s3c2xx0, xscaleの一派がenable_interruptしている。
おっと、レファレンスモデルのrpiがないじゃん。
なんなの。
ははぁ、initarm_commonしてる人は、共通関数でenableしてるんでしょ、と思って、arm32_bootを読むが、それっぽいところなさそうだなー。
それどころか、initarm_common族のomap2がicuのattachでenable_interruptしてるぞ。
もうよくわからん。initarm_common族と、enable_interrupt族を比較するとomap2だけが特殊?
enable_interruptもほとんどintr_initメソッドで呼ばれてるけどね。initarm_common族のomap2は自前initarmで呼べないもんだから、attachで読んでるってわけか。
つまり、あんまりタイミング関係ないってこと?initarmでもデバイスのattachでもいいってことかな?
しっかし、arm splx 割り込み、でgoogleしたら、もしかして: arm cpsr 割り込み、と言われるのはすごいな。
attachでenable_interruptしたら割り込みルーチンが呼ばれた!
割込みレジスタ周りを全部表示するデバッグルーチンを書く。
IC Highest-priority Status registerをみると0x0000000aというのがある。もしかしたら割り込み番号?
調べるとeth0であった。死ぬほど呼ばれるので0x0aあたりを32ビットごと00000000で初期化する。これでeth0の割り込みは来ないはず。
しかし、まだ割り込みルーチン呼ばれる。eth0以外からも割り込みが上がってきているということか。
調べると、どうやら0x00000016つまり22である。pmc_wakeupのようだ。これも0x00000000で周辺ごと初期化する。
これでシリアルの割り込みが来たら、すぐにわかるはず。
しかし、割り込みは来ない。むー。何がいかんのだろうか。
comの場合、comintrという関数が割り込み処理で呼ばれる。
それを登録するのは、シリアルドライバのattach処理で呼ばれているintr_establishである。
intr_establishはsys/arch/arm/pic/pic.c#699にあり、同ファイル内のpic_establish_intrを呼ぶ。
699 intr_establish(int irq, int ipl, int type, int (*func)(void *), void *arg) 700 { 701 KASSERT(!cpu_intr_p()); 702 KASSERT(!cpu_softintr_p()); 703 704 for (size_t slot = 0; slot < PIC_MAXPICS; slot++) { 705 struct pic_softc * const pic = pic_list[slot]; 706 if (pic == NULL || pic->pic_irqbase < 0) 707 continue; 708 if (pic->pic_irqbase <= irq 709 && irq < pic->pic_irqbase + pic->pic_maxsources) { 710 return pic_establish_intr(pic, irq - pic->pic_irqbase, 711 ipl, type, func, arg); 712 } 713 } 714 715 return NULL; 716 }sys/arch/arm/pic/pic.c#pic_establish_intrでは様々な前処理を行った後、関数ポインタをつかって、機種依存の割り込みドライバに書かれたestablish処理とunblock処理を呼んでいる。
660 (*pic->pic_ops->pic_establish_irq)(pic, is); 661 662 (*pic->pic_ops->pic_unblock_irqs)(pic, is->is_irq & ~0x1f, 663 __BIT(is->is_irq & 0x1f));機種依存側の処理を見てみると、RPIなどは何もしていない。結局のところ、pic.cに渡されたfuncがpic_sources[]に格納されて、随時呼び出されているということなのだろうか。
is->is_funcを呼び出しているところは、sys/arch/arm/pic/pic.c#pic_dispatchである。
255 void 256 pic_dispatch(struct intrsource *is, void *frame) 257 { 258 int rv; 259 260 if (__predict_false(is->is_arg == NULL) 261 && __predict_true(frame != NULL)) { 262 rv = (*is->is_func)(frame); 263 } else if (__predict_true(is->is_arg != NULL)) { 264 rv = (*is->is_func)(is->is_arg);それを呼び出しているのはsys/arch/arm/pic/pic.c#pic_deliver_irqsである。
277 pic_deliver_irqs(struct pic_softc *pic, int ipl, void *frame) 278 { 279 const uint32_t ipl_mask = __BIT(ipl); ... 335 is = pic->pic_sources[irq_base + irq]; 336 if (is != NULL) { 337 cpsie(I32_bit); 338 pic_dispatch(is, frame); 339 cpsid(I32_bit);さらに、sys/arch/arm/pic/pic.c#pic_list_deliver_irqsに呼ばれており、
430 pic_list_deliver_irqs(register_t psw, int ipl, void *frame) 431 { 432 const uint32_t ipl_mask = __BIT(ipl); 433 struct pic_softc *pic; 434 435 while ((pic = pic_list_find_pic_by_pending_ipl(ipl_mask)) != NULL) { 436 pic_deliver_irqs(pic, ipl, frame); 437 KASSERT((pic->pic_pending_ipls & ipl_mask) == 0);さらにsys/arch/arm/pic/pic.c#pic_do_pending_intsから呼ばれ、
443 pic_do_pending_ints(register_t psw, int newipl, void *frame) 444 { 445 struct cpu_info * const ci = curcpu(); …. 458 pic_set_priority(ci, ipl); 459 pic_list_deliver_irqs(psw, ipl, frame); 460 pic_list_unblock_irqs();これを呼び出しているのが機種依存割り込みドライバのirq_handerになる。たとえば、geminiであればgemini_irq_handlerである。
gemini_irq_handlerを呼び出しているのは、検索すると出てこないと思いきや、ヘッダファイルに手掛かりがあった。
geminiであればsys/arch/arm/gemini/gemini_intr.h#6にある。
6 #define ARM_IRQ_HANDLER _C_LABEL(gemini_irq_handler)ARM_IRQ_HANDLERというのが怪しい。
sys/arch/arm/arm32/irq_dispatch.S#87をみると、ARM_IRQ_HANDLERにジャンプしている。
87 /* 88 * irq_entry: 89 * Main entry point for the IRQ vector. This is a generic version 90 * which can be used by different platforms. 91 */ 92 .text 93 .p2align 5 94 ARM_ASENTRY_NP(irq_entry) 95 sub lr, lr, #0x00000004 /* Adjust the lr */ 96 97 PUSHFRAMEINSVC /* Push an interrupt frame */ 98 ENABLE_ALIGNMENT_FAULTS /* finishes with curcpu() in r4 */ 99 100 /* 101 * Increment the interrupt nesting depth and call the interrupt 102 * dispatch routine. We've pushed a frame, so we can safely use 103 * callee-saved regs here. We use the following registers, which 104 * we expect to persist: 105 * 106 * r4 address of current cpu_info 107 * r6 old value of `ci_intr_depth' 108 */ 109 ldr r6, [r4, #CI_INTR_DEPTH] 110 add r1, r6, #1 111 str r1, [r4, #CI_INTR_DEPTH] 112 113 mov r0, sp /* arg for dispatcher */ 114 bl ARM_IRQ_HANDLERirq_entryで追っかけると、sys/arch/arm/arm/vectors.S#59に記載がある。
59 _C_LABEL(page0rel): 60 b reset_entry 61 b undefined_entry 62 b swi_entry 63 b prefetch_abort_entry 64 b data_abort_entry 65 b address_exception_entry 66 b irq_entryなんとなく、page0relは色々なエントリポイントにジャンプするテーブルのようである。
page0relはどこだろうか。
sys/arch/arm/arm32/arm32_machdep.c#arm32_vector_initで使われている。
134 arm32_vector_init(vaddr_t va, int which) 135 { 136 #if defined(CPU_ARMV7) || defined(CPU_ARM11) || defined(ARM_HAS_VBAR) 137 /* 138 * If this processor has the security extension, don't bother 139 * to move/map the vector page. Simply point VBAR to the copy 140 * that exists in the .text segment. 141 */ 142 #ifndef ARM_HAS_VBAR 143 if (va == ARM_VECTORS_LOW 144 && (armreg_pfr1_read() & ARM_PFR1_SEC_MASK) != 0) { 145 #endif 146 extern const uint32_t page0rel[]; 147 vector_page = (vaddr_t)page0rel;machdepなのできっと機種依存のmachdepから呼ばれているのだろう、と思いつつ、案の定である。initarmの共通関数であるsys/arch/arm/arm32/arm32_boot.c#initarm_commonを代表例として挙げておく。
152 initarm_common(vaddr_t kvm_base, vsize_t kvm_size, 153 const struct boot_physmem *bp, size_t nbp) 154 { … 173 #ifdef VERBOSE_INIT_ARM 174 printf("vectors"); 175 #endif 176 arm32_vector_init(systempage.pv_va, ARM_VEC_ALL); 177 #ifdef VERBOSE_INIT_ARM 178 printf(" %#"PRIxVADDR"\n", vector_page); 179 #endifということは、VERVOSE_INIT_ARMされていれば、
147 vector_page = (vaddr_t)page0rel;なのでpage0relが表示されているはずである。
VERBOSE_INIT_ARMして、該当箇所を見てみよう。
vectors 0xffff0000どうやら0xFFFF0000というのがpage0relなのですな。
あれ? vbarっていうのが表示されていないな。ブロックごと飛ばされているって感じに見えるな。ARM_HAS_VBARっていうのが関係している?
ARM_HAS_VBARがRPIはあるけどAPCにはつけてないな。
あらためて、RPIと比べるとstd.rpi, std.apcは違いがある。
__HAVE_CPU_COUNTERとか。これは誰をベースにしたんだっけ?
ARM_HAS_VBARを有効にしたら以下のようになった。
vectors vbar=0xc01411c0 0xc01411c0むむむ。さっきと全然違うな。
しかし、割り込みハンドラは呼ばれない。さて、なぜでしょうか?
- 割込みが発生していない
- 割込みを許可していない(だから割り込みハンドラが呼ばれない)
- 割込み処理にバグがある
- その他の初期化が足りていない(だから割り込みハンドラが呼ばれない)
ARMjp-vH.pdfのA2-16、A2.6 例外によるとIRQ(割り込み)は0x00000018, 0xffff001cのアドレスだと書かれている。
本当にそうなのか試してみよう。
ubootのプロンプトを使って割り込みベクタを表示。リセット割込みのアドレスに書かれているea00002cにジャンプしてみる。
WMT # md.l ffff0000 8 ffff0000: ea00002c e59ff2d4 e59ff2d4 e59ff2d4 ,............... ffff0010: e59ff2d4 e59ff2d4 e59ff2d4 e59ff2d4 ................ WMT # go ea00002c ## Starting application at 0xEA00002C ...リセットされている感じがない。ちがうちがう。ffff0000から実行するのだ。
WMT # go ffff0000 ## Starting application at 0xFFFF0000 ... WonderMedia Technologies, Inc. W-Load Version : 0.23.00.00 uboot set plla cmd ..found wmt.plla.param=1:800:1,2:5,2:3 device clock is disabledethaddr............found 以下、起動メッセージが続くおぉ、リセットされた。
VBARが有効ならば、先のc01411c0に飛べばリセットされるはずである。
WMT # go c01411c0 ## Starting application at 0xC01411C0 ...何も起こらない。つまり、VBARは有効にしてはいけないのではないか?
じゃぁ、リセット割込み以外e59ff2d4が実行されるみたいだ。
WMT # go ffff0004 ## Starting application at 0xFFFF0004 ...何も起こらない。
WMT # md.l ffff0000 ffff0000: ea00002c e59ff2d4 e59ff2d4 e59ff2d4 ,............... WMT # md.l e59ff2d4 128 e59ff2d4:アドレスを読ませてもくれない。
ところでnetbsdをobjdump -dしてみると
c01411c0 <page0rel>: c01411c0: eafb7bea b c0020170 <reset_entry> c01411c4: eafb7c83 b c00203d8 <undefined_entry> c01411c8: eafb7bf4 b c00201a0 <swi_entry> c01411cc: eafb7c18 b c0020234 <prefetch_abort_entry> c01411d0: eafb7c35 b c00202ac <data_abort_entry> c01411d4: eafb7c51 b c0020320 <address_exception_entry> c01411d8: eafc2b30 b c004bea0 <irq_entry> c01411dc: e25ef004 subs pc, lr, #4てな感じである。これはVBARを外してみるとどうなるか。
あれ?変わらない。
obj全部消してやり直そう。-uついてなかったので作り直しているはずなんだけどな。
とおもっていたら、std.rpiを消してた!
うーん、やっぱりだめですね。ffff0000に配置されていません。
と思ったら、違うんですな。よく読むと、ARM_VECTORS_LOWじゃないから以下のルートに入るのですね。
159 #ifndef ARM_HAS_VBAR 160 if (CPU_IS_PRIMARY(curcpu())) { 161 extern unsigned int page0[], page0_data[]; 162 unsigned int *vectors = (int *) va; 163 unsigned int *vectors_data = vectors + (page0_data - page0); 164 int vec; 165 166 /* 167 * Loop through the vectors we're taking over, and copy the 168 * vector's insn and data word. 169 */ 170 for (vec = 0; vec < ARM_NVEC; vec++) { 171 if ((which & (1 << vec)) == 0) { 172 /* Don't want to take over this vector. */ 173 continue; 174 } 175 vectors[vec] = page0[vec]; 176 vectors_data[vec] = page0_data[vec]; 177 } 178 179 /* Now sync the vectors. */ 180 cpu_icache_sync_range(va, (ARM_NVEC * 2) * sizeof(u_int)); 181 182 vector_page = va; 183 }ということでpage0, page0_dataが大事と。
デバッグ文を入れてみると以下のように。
Message Buffer: 0x002a7000 0x002aafff 0xc02a7000 0xc02aafff 4 Exception Vectors: 0x002ab000 0x002abfff 0xffff0000 0xffff0fff 1 Free Memory: 0x002ac000 0x1fffffff 130388 Free Memory: 0x00000000 0x00007fff 8 switching to new L1 page table @0x294000...TTBR0=0x294000 OK done. nfreeblocks = 2, free_pages = 130396 (0x1fd5c) bootstrap done. vectorsvectors = ffff0000, vectors_data = ffff011c vectors[0] = e59ff114, vectors_data[0] = c00203d0 vectors[1] = e59ff114, vectors_data[1] = c0020638 vectors[2] = e59ff114, vectors_data[2] = c0020400 vectors[3] = e59ff114, vectors_data[3] = c0020494 vectors[4] = e59ff114, vectors_data[4] = c002050c vectors[5] = e59ff114, vectors_data[5] = c0020580 vectors[6] = e59ff114, vectors_data[6] = c004c320 vectors[7] = e25ef004, vectors_data[7] = 00000000 0xffff0000ちゃんと、ffff000からe59ff114つまり
c0141a20 <page0>: c0141a20: e59ff114 ldr pc, [pc, #276] ; c0141b3c <_KERNEL_OPT_ARM_INTR_IMPL+0xc230bbcc> c0141a24: e59ff114 ldr pc, [pc, #276] ; c0141b40 <_KERNEL_OPT_ARM_INTR_IMPL+0xc230bbd0> c0141a28: e59ff114 ldr pc, [pc, #276] ; c0141b44 <_KERNEL_OPT_ARM_INTR_IMPL+0xc230bbd4> c0141a2c: e59ff114 ldr pc, [pc, #276] ; c0141b48 <_KERNEL_OPT_ARM_INTR_IMPL+0xc230bbd8> c0141a30: e59ff114 ldr pc, [pc, #276] ; c0141b4c <_KERNEL_OPT_ARM_INTR_IMPL+0xc230bbdc> c0141a34: e59ff114 ldr pc, [pc, #276] ; c0141b50 <_KERNEL_OPT_ARM_INTR_IMPL+0xc230bbe0> c0141a38: e59ff114 ldr pc, [pc, #276] ; c0141b54 <_KERNEL_OPT_ARM_INTR_IMPL+0xc230bbe4> c0141a3c: e25ef004 subs pc, lr, #4 ... c0141b3c <page0_data>: c0141b3c: c0020390 mulgt r2, r0, r3 c0141b40: c00205f8 strdgt r0, [r2], -r8 c0141b44: c00203c0 andgt r0, r2, r0, asr #7 c0141b48: c0020454 andgt r0, r2, r4, asr r4 c0141b4c: c00204cc andgt r0, r2, ip, asr #9 c0141b50: c0020540 andgt r0, r2, r0, asr #10 c0141b54: c004c2e0 andgt ip, r4, r0, ror #5 c0141b58: 00000000 andeq r0, r0, r0ということですね。
これで、割り込みが来たらジャンプしてくれるはずです。
が、割込みが来ない。なぜだ。割り込み禁止になっていたりするんですかね?
逆に、どこで割り込みを有効にするんでしょうか?
思い起こせば、start.Sを読んだのがいつだったか。
確か、割り込みを禁止していたような。と思いつつrpiのstartを眺めるも、アセンブラは忘却の彼方。
こういう時には別所さん由来の橋本さんソースを読もう。ということでnetwalkerである。
もう。いい感じでコメントが入っているではないか。
同様にrpiでも同じ処理をしておる。むしろ、冒頭である。
さて、割り込みを禁止しているのだから、どこかでそれを解いているはず。
ここまで読んでくると、cpsrがキーワードだとわかる。
cpsrでnxr検索すればヒントが。
enable_interrputしてるやん。
しかし、すべてがそうではない。
src/sys/arch/armだとat91, ep93xx, footbridge, imx, iomd, ixp12x0, mpcore, ofw, omap, s3c2xx0, xscaleの一派がenable_interruptしている。
おっと、レファレンスモデルのrpiがないじゃん。
なんなの。
ははぁ、initarm_commonしてる人は、共通関数でenableしてるんでしょ、と思って、arm32_bootを読むが、それっぽいところなさそうだなー。
それどころか、initarm_common族のomap2がicuのattachでenable_interruptしてるぞ。
もうよくわからん。initarm_common族と、enable_interrupt族を比較するとomap2だけが特殊?
enable_interruptもほとんどintr_initメソッドで呼ばれてるけどね。initarm_common族のomap2は自前initarmで呼べないもんだから、attachで読んでるってわけか。
つまり、あんまりタイミング関係ないってこと?initarmでもデバイスのattachでもいいってことかな?
しっかし、arm splx 割り込み、でgoogleしたら、もしかして: arm cpsr 割り込み、と言われるのはすごいな。
attachでenable_interruptしたら割り込みルーチンが呼ばれた!
割込みレジスタ周りを全部表示するデバッグルーチンを書く。
IC Highest-priority Status registerをみると0x0000000aというのがある。もしかしたら割り込み番号?
調べるとeth0であった。死ぬほど呼ばれるので0x0aあたりを32ビットごと00000000で初期化する。これでeth0の割り込みは来ないはず。
しかし、まだ割り込みルーチン呼ばれる。eth0以外からも割り込みが上がってきているということか。
調べると、どうやら0x00000016つまり22である。pmc_wakeupのようだ。これも0x00000000で周辺ごと初期化する。
これでシリアルの割り込みが来たら、すぐにわかるはず。
しかし、割り込みは来ない。むー。何がいかんのだろうか。
- TB-URL http://www.tokuda.net/diary/adiary.cgi/0832/tb/
APC8750にNetBSD/evbarmを移植するための記録 9/7 その1
ずいぶん時間が過ぎ去った。割り込みコントローラの続き。
割り込みコントローラのアドレスをダンプしてみる
u-bootも見たほうがいいか?
うーん、探せない...
まぁ、触ってみるか。
bus_space_read_4の引き数の最後は割り込みコントローラの先頭アドレス(0xd8140000)からの相対位置でよい。最初は絶対アドレスで書いていたら
もちろん、先のコードでも
ということで、読むのができたら書けるはず。
unblock, blockで読み書きをしてみたが、値が書けるところと書けないところがある。irq=32だとかけて、irq=0だと書けない。
そもそもirq=0って使っていないはず。
establish_irqでis->is_irqで表示させたらirq=3である。なんだこれ。
とにかく、何で書けないのか。
頭にきて、attachで0xd8140000から0xFFFFFFFFを128個ほど書いて直後に読んで書き込めているかどうか表示させてみた。
すると、0xd8140040からは0x7F7F7F7Fが16個(8ビットで64個)と書けている。
そういえば、Linuxでは
つぎは、irq=3がirq=0になっているところ。
これは、block, unblockに渡されてくるirqbase, irq_maskの二つの合わせ技で考えなければならなかった。
これはsys/arch/arm/pic/pic.c#660を読むとわかる。
0から31を表現する下位5ビット分(0x1f)を数字として、32ビットのビット位置で表現されている。
たとえば、irq=3であれば、0x1fでビットをクリアすると0x0なのでirqbaseはゼロ。下位5ビット分は3なので3ビット目が立っている0x8となる。3ビット目といっても0ビット目があるので1<<4になる。1を4ビットシフトさせて0x8である。
ということで、IRQ番号を求めるには、irqbase + (irq_maskの何ビット目が立っているか)を計算する必要がある。
geminiのようにIRQのmaskをビットでやるようなタイプだとこちらのほうが便利ということですね。
さて、IRQは3だということがわかったのですが、このIRQは使われていない(unusedで定義されている)はずなので、やっぱり何かが変です。
また、このestablishを読んでいるのはおそらくタイマードライバです。タイマードライバはirq=48でconfigに書いてあるのですが。
謎だ。
と思ったら、intrが3になる件、当たり前だった。
ところでIPL_CLOCKのIPLとはなにか、Interreput Priority Levelとのこと。
sys/arch/evbarm/include/intr.h#44によると次のとおり。
wm8750tmr_softcにint sc_intrというメンバを加え、attach時にobioから
IRQ = iobase + log(irqmask, 2) という数式で表せばいいかな。
ここまでのログを張っておこう。
割り込みコントローラのアドレスをダンプしてみる
WMT # md.l d8140000 d8140000: 0000003f 0000003f 0000003f 00000000 ?...?...?....... d8140010: 00000000 00000000 00000000 00000000 ................ d8140020: 00000000 00000000 00000000 00000000 ................ d8140030: 00000000 00000000 00000000 00000000 ................ d8140040: 00000000 00000000 00000000 00000000 ................ d8140050: 00000000 00000000 00000000 00000000 ................ d8140060: 00000000 00000000 00000000 00000000 ................ d8140070: 00000000 00000000 00000000 00000000 ................ d8140080: 00000000 00000000 00000000 00000000 ................ d8140090: 00000000 00000000 00000000 00000000 ................ d81400a0: 00000000 00000000 00000000 00000000 ................ d81400b0: 00000000 00000000 00000000 00000000 ................ d81400c0: 00000000 00000000 00000000 00000000 ................ d81400d0: 00000000 00000000 00000000 00000000 ................ d81400e0: 00000000 00000000 00000000 00000000 ................ d81400f0: 00000000 00000000 00000000 00000000 ................最初の三つが気になる。
u-bootも見たほうがいいか?
うーん、探せない...
まぁ、触ってみるか。
/* debug */ for (i = 0; i < 10; i++) { aprint_normal("icu-debug: "); debug = bus_space_read_4(sc->sc_iot, sc->sc_ioh, i); aprint_normal("%08x %08x\n", (int)WM8750_IC0_BASE + i * 4, debug); }とかattachルーチンにいれてみた。
bus_space_read_4の引き数の最後は割り込みコントローラの先頭アドレス(0xd8140000)からの相対位置でよい。最初は絶対アドレスで書いていたら
wmicu0 at obio0 addr 0xd8140000-0xd814ffff icu-debug: uvm_fault(0xc027dfb4, d6280000, 1) -> e Fatal kernel mode data abort: 'Translation Fault (S)' trapframe: 0xc0296d80 FSR=00000005, FAR=d6280000, spsr=200001d3 r0 =00000000, r1 =fe140000, r2 =d8140000, r3 =c000e840 r4 =c1a2a668, r5 =d8140000, r6 =d8140028, r7 =c01b16dc r8 =c018c0a8, r9 =c0180744, r10=00000000, r11=c0296dec r12=c0296da8, ssp=c0296dd0, slr=c01659dc, pc =c000e844 Stopped in pid 0.1 (system) at netbsd:generic_bs_r_4+0x4: ldr r0, [r1, r2] 0xc0296dec: netbsd:wm8750_icu_attach+0xc 0xc0296e18: netbsd:config_attach_loc+0x190 0xc0296e30: netbsd:config_found+0x2c 0xc0296e58: netbsd:obio_attach_critical+0x40 0xc0296e70: netbsd:obio_attach+0x38 0xc0296e9c: netbsd:config_attach_loc+0x190 0xc0296eb0: netbsd:config_attach+0x24 0xc0296eec: netbsd:mainbussearch+0x8c 0xc0296f30: netbsd:config_search_loc+0x134 0xc0296f44: netbsd:config_search_ia+0x1c 0xc0296f70: netbsd:config_attach_loc+0x190 0xc0296f84: netbsd:config_attach+0x24 0xc0296f9c: netbsd:cpu_configure+0x30 0xc0296fec: netbsd:main+0x1fc 0xc0296ffc: netbsd:kernel_text+0x50 db>などと言って落ちた。
もちろん、先のコードでも
icu-debug: d8140000 0000003f icu-debug: data_abort_handler: data_aborts fsr=0x1 far=0xfe140001 Fatal kernel mode data abort: 'Alignment Fault 1' trapframe: 0xc0296d78 FSR=00000001, FAR=fe140001, spsr=200001d3 r0 =00000000, r1 =fe140000, r2 =00000001, r3 =c000e840 r4 =c1a2a668, r5 =00000001, r6 =d8140004, r7 =00000000 r8 =c018c0a8, r9 =c0180744, r10=00000000, r11=c0296dec r12=c0296da4, ssp=c0296dcc, slr=c01659e0, pc =c000e844 Stopped in pid 0.1 (system) at netbsd:generic_bs_r_4+0x4: ldr r0, [r1, r2] 0xc0296dec: netbsd:wm8750_icu_attach+0xc 0xc0296e18: netbsd:config_attach_loc+0x190 0xc0296e30: netbsd:config_found+0x2c 0xc0296e58: netbsd:obio_attach_critical+0x40 0xc0296e70: netbsd:obio_attach+0x38 0xc0296e9c: netbsd:config_attach_loc+0x190 0xc0296eb0: netbsd:config_attach+0x24 0xc0296eec: netbsd:mainbussearch+0x8c 0xc0296f30: netbsd:config_search_loc+0x134 0xc0296f44: netbsd:config_search_ia+0x1c 0xc0296f70: netbsd:config_attach_loc+0x190 0xc0296f84: netbsd:config_attach+0x24 0xc0296f9c: netbsd:cpu_configure+0x30 0xc0296fec: netbsd:main+0x1fc 0xc0296ffc: netbsd:kernel_text+0x50 db>と言って落ちる。一刻みのアドレスでアクセスできるわけないのでアラインメントがおかしいといって。おちる。
comprobe1 0 </wm8750_uart_match rv=0> wmicu0 at obio0 addr 0xd8140000-0xd814ffff icu-debug: d8140000 0000003f icu-debug: d8140004 0000003f icu-debug: d8140008 0000003f icu-debug: d814000c 00000000 icu-debug: d8140010 00000000 icu-debug: d8140014 00000000 中略 icu-debug: d81400f8 00000000 icu-debug: d81400fc 00000000 <wm8750_uart_match> com0 at obio0 addr 0xd8200000-0xd820ffff intr 32 : ns16650, no ERS, working fifo com0: console establish_irq debug: unblock wmtmr0 at obio0 addr 0xd8100000-0xd810ffff intr 48 : VC System Timer establish_irq debug: unblock rn_init: radix functions require max_keylen be set boot device: <unknown> root device:debugいれてみた。icuのモジュールが呼ばれている。
ということで、読むのができたら書けるはず。
unblock, blockで読み書きをしてみたが、値が書けるところと書けないところがある。irq=32だとかけて、irq=0だと書けない。
そもそもirq=0って使っていないはず。
establish_irqでis->is_irqで表示させたらirq=3である。なんだこれ。
とにかく、何で書けないのか。
頭にきて、attachで0xd8140000から0xFFFFFFFFを128個ほど書いて直後に読んで書き込めているかどうか表示させてみた。
すると、0xd8140040からは0x7F7F7F7Fが16個(8ビットで64個)と書けている。
そういえば、Linuxでは
#define ICDC0_ADDR (__IC_BASE + 0x40) /* dest_ctl_addr[0] */と書いてあったのを忘れていた。0xd8140040から8ビット刻みで64個なので辻褄もあっている。ご丁寧に0で初期化されている。
つぎは、irq=3がirq=0になっているところ。
これは、block, unblockに渡されてくるirqbase, irq_maskの二つの合わせ技で考えなければならなかった。
これはsys/arch/arm/pic/pic.c#660を読むとわかる。
660 (*pic->pic_ops->pic_establish_irq)(pic, is); 661 662 (*pic->pic_ops->pic_unblock_irqs)(pic, is->is_irq & ~0x1f, 663 __BIT(is->is_irq & 0x1f));establish_irqにはすなおにisが渡されているが、unblockには0x1fでビットがクリアされたものがirqbaseに渡されている。
0から31を表現する下位5ビット分(0x1f)を数字として、32ビットのビット位置で表現されている。
たとえば、irq=3であれば、0x1fでビットをクリアすると0x0なのでirqbaseはゼロ。下位5ビット分は3なので3ビット目が立っている0x8となる。3ビット目といっても0ビット目があるので1<<4になる。1を4ビットシフトさせて0x8である。
ということで、IRQ番号を求めるには、irqbase + (irq_maskの何ビット目が立っているか)を計算する必要がある。
geminiのようにIRQのmaskをビットでやるようなタイプだとこちらのほうが便利ということですね。
さて、IRQは3だということがわかったのですが、このIRQは使われていない(unusedで定義されている)はずなので、やっぱり何かが変です。
また、このestablishを読んでいるのはおそらくタイマードライバです。タイマードライバはirq=48でconfigに書いてあるのですが。
謎だ。
と思ったら、intrが3になる件、当たり前だった。
clock_ih = wm8750_intr_establish(WM8750_INT_TIMER3, IPL_CLOCK,などとRPIのそのまま(RPIからWM8750に単純置換したまま)になっていたからだ。ばかすぎる。
ところでIPL_CLOCKのIPLとはなにか、Interreput Priority Levelとのこと。
sys/arch/evbarm/include/intr.h#44によると次のとおり。
43 /* Interrupt priority "levels". */ 44 #define IPL_NONE 0 /* nothing */ 45 #define IPL_SOFTCLOCK 1 /* clock */ 46 #define IPL_SOFTBIO 2 /* block I/O */ 47 #define IPL_SOFTNET 3 /* software network interrupt */ 48 #define IPL_SOFTSERIAL 4 /* software serial interrupt */ 49 #define IPL_VM 5 /* memory allocation */ 50 #define IPL_SCHED 6 /* clock interrupt */ 51 #define IPL_HIGH 7 /* everything */ 52 53 #define NIPL 8こういうレベルに基づいて割り込みを格付けしているのですね。
wm8750tmr_softcにint sc_intrというメンバを加え、attach時にobioから
sc->sc_intr = obio->obio_intr;てな感じでsoftcに保存。establish時にsc->sc_intrを使うようにすると、
com0 at obio0 addr 0xd8200000-0xd820ffff intr 32 : ns16650, no ERS, working fifo com0: console icu: establish_irq: is->is_irq=0x20 icu: unblock: irqbase=0x00000020, irqmask=0x00000001, 0x00000000 -> 0x00000008 wmtmr0 at obio0 addr 0xd8100000-0xd810ffff intr 48 : VC System Timer icu: establish_irq: is->is_irq=0x30 icu: unblock: irqbase=0x00000020, irqmask=0x00010000, 0x00000008 -> 0x00000008 rn_init: radix functions require max_keylen be set boot device: <unknown> root device:てな具合。irqmaskも0x10000なので、右から数えて17番目、0から始めて16を表現しているから、0x20+0x10=0x30であってますね。
IRQ = iobase + log(irqmask, 2) という数式で表せばいいかな。
ここまでのログを張っておこう。
WMT # go 8000 ## Starting application at 0x00008000 ... 00008328 NetBSD 00000000 00000000 0049096b 00000412 00000000 00000412 00000004 00000412 c0000000 00000000 0049096b 0000041e 00003000 0000041e 00000004 0000041e fe000000 d8000000 010fffff 00000412 00003f80 d8000412 00000010 00000412 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 NetBSD/evbarm (APC) booting ... initarm: Configuring system ... arm32_bootmem_init: memstart=0, memsize=0x20000000, kernelstart=0x8000 arm32_bootmem_init: kernelend=0x291000 arm32_bootmem_init: adding 130415 free pages: [0x291000..0x1fffffff] (VA 0xc0291000) arm32_bootmem_init: adding 8 free pages: [0..0x7fff] (VA 0xc0000000) arm32_kernel_vm_init: 1 L2 pages are needed to map 0x2bc000 kernel bytes arm32_kernel_vm_init: allocating page tables for vectoradd_pages: adding pv 0xc027fbe8 (pa 0x291000, va 0xc0291000, 1 pages) at tail kerneladd_pages: appending pv 0xc027fe70 (0x292000..0x292fff) to 0x291000..0x291fff vmadd_pages: appending pv 0xc027fe84 (0x293000..0x293fff) to 0x291000..0x292fff add_pages: appending pv 0xc028892c (0x294000..0x297fff) to 0x291000..0x293fff add_pages: appending pv 0xc027fe98 (0x298000..0x298fff) to 0x291000..0x297fff add_pages: appending pv 0xc027feac (0x299000..0x299fff) to 0x291000..0x298fff add_pages: appending pv 0xc027fec0 (0x29a000..0x29afff) to 0x291000..0x299fff add_pages: appending pv 0xc027fed4 (0x29b000..0x29bfff) to 0x291000..0x29afff add_pages: appending pv 0xc027fee8 (0x29c000..0x29cfff) to 0x291000..0x29bfff add_pages: appending pv 0xc027fefc (0x29d000..0x29dfff) to 0x291000..0x29cfff add_pages: appending pv 0xc027ff10 (0x29e000..0x29efff) to 0x291000..0x29dfff add_pages: appending pv 0xc028016c (0x29f000..0x29ffff) to 0x291000..0x29efff add_pages: appending pv 0xc0280180 (0x2a0000..0x2a0fff) to 0x291000..0x29ffff add_pages: appending pv 0xc0280194 (0x2a1000..0x2a1fff) to 0x291000..0x2a0fff add_pages: appending pv 0xc02801a8 (0x2a2000..0x2a2fff) to 0x291000..0x2a1fff add_pages: appending pv 0xc02801bc (0x2a3000..0x2a4fff) to 0x291000..0x2a2fff add_pages: appending pv 0xc0280158 (0x2a5000..0x2a6fff) to 0x291000..0x2a4fff add_pages: appending pv 0xc027fc64 (0x2a7000..0x2aafff) to 0x291000..0x2a6fff Creating L1 page table at 0x00294000 arm32_kernel_vm_init: adding L2 pt (VA 0xc0291000, PA 0x291000) for VA 0xffff0000 (vectors)arm32_kernel_vm_init: adding L2 pt (VA 0xc0292000, PA 0x292000) for VA 0xc0000000 (kernel) arm32_kernel_vm_init: adding L2 pt (VA 0xc0293000, PA 0x293000) for VA 0xc1000000 (vm) arm32_kernel_vm_init: adding L2 pt (VA 0xc0298000, PA 0x298000) for VA 0xc1400000 (vm) arm32_kernel_vm_init: adding L2 pt (VA 0xc0299000, PA 0x299000) for VA 0xc1800000 (vm) arm32_kernel_vm_init: adding L2 pt (VA 0xc029a000, PA 0x29a000) for VA 0xc1c00000 (vm) arm32_kernel_vm_init: adding L2 pt (VA 0xc029b000, PA 0x29b000) for VA 0xc2000000 (vm) arm32_kernel_vm_init: adding L2 pt (VA 0xc029c000, PA 0x29c000) for VA 0xc2400000 (vm) arm32_kernel_vm_init: adding L2 pt (VA 0xc029d000, PA 0x29d000) for VA 0xc2800000 (vm) arm32_kernel_vm_init: adding L2 pt (VA 0xc029e000, PA 0x29e000) for VA 0xc2c00000 (vm) Mapping kernel arm32_kernel_vm_init: adding chunk for kernel text 0x8000..0x1affff (VA 0xc0008000) add_pages: adding pv 0xc027fbd4 (pa 0x8000, va 0xc0008000, 424 pages) before pa 0x291000 arm32_kernel_vm_init: adding chunk for kernel data/bss 0x1b0000..0x290fff (VA 0xc01b0000) add_pages: appending pv 0xc027fc3c (0x1b0000..0x290fff) to 0x8000..0x1affff add_pages: merging pv 0xc027fbe8 (0x291000..0x2aafff) to 0x8000..0x290fff Listing Chunks arm32_kernel_vm_init: pv 0xc027fbd4: chunk VA 0xc0008000..0xc02aafff (PA 0x8000, prot 3, cache 1) Mapping Chunks arm32_kernel_vm_init: mapping last chunk VA 0xc0008000..0xc02aafff (PA 0x8000, prot 3, cache 1) pmap_map_chunk: pa=0x8000 va=0xc0008000 size=0x2a3000 resid=0x2a3000 prot=0x3 cache=1 PPPPPPPPLLLLLLLLLLLLLLLSLLLLLLLLLLPPPPPPPPPPP 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 0x001affff 0xc0008000 0xc01affff 424 data section: 0x001c0000 0x0027f4c0 0xc01c0000 0xc027f4c0 192 bss section: 0x0027f4c0 0x0029096c 0xc027f4c0 0xc029096c 18 L1 page directory: 0x00294000 0x00297fff 0xc0294000 0xc0297fff 4 ABT stack (CPU 0): 0x0029f000 0x0029ffff 0xc029f000 0xc029ffff 1 FIQ stack (CPU 0): 0x002a0000 0x002a0fff 0xc02a0000 0xc02a0fff 1 IRQ stack (CPU 0): 0x002a1000 0x002a1fff 0xc02a1000 0xc02a1fff 1 UND stack (CPU 0): 0x002a2000 0x002a2fff 0xc02a2000 0xc02a2fff 1 IDLE stack (CPU 0): 0x002a3000 0x002a4fff 0xc02a3000 0xc02a4fff 2 SVC stack: 0x002a5000 0x002a6fff 0xc02a5000 0xc02a6fff 2 Message Buffer: 0x002a7000 0x002aafff 0xc02a7000 0xc02aafff 4 Exception Vectors: 0x002ab000 0x002abfff 0xffff0000 0xffff0fff 1 Free Memory: 0x002ac000 0x1fffffff 130388 Free Memory: 0x00000000 0x00007fff 8 switching to new L1 page table @0x294000...TTBR0=0x294000 OK done. nfreeblocks = 2, free_pages = 130396 (0x1fd5c) bootstrap done. vectors 0xffff0000 init subsystems: stacks vectors undefined page pmap_physload pmap [ Kernel symbol table missing! ] done. Loaded initial symtab at 0xc01c4364, strtab at 0xc01e34d4, # entries 7944 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) #55: Mon Sep 9 22:46:37 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 <wm8750_uart_match> comprobe1 0 </wm8750_uart_match rv=0> wmicu0 at obio0 addr 0xd8140000-0xd814ffff icu-debug: d8140040: 00000000 icu-debug: d8140044: 00000000 icu-debug: d8140048: 00000000 icu-debug: d814004c: 00000000 icu-debug: d8140050: 00000000 icu-debug: d8140054: 00000000 icu-debug: d8140058: 00000000 icu-debug: d814005c: 00000000 icu-debug: d8140060: 00000000 icu-debug: d8140064: 00000000 icu-debug: d8140068: 00000000 icu-debug: d814006c: 00000000 icu-debug: d8140070: 00000000 icu-debug: d8140074: 00000000 icu-debug: d8140078: 00000000 icu-debug: d814007c: 00000000 <wm8750_uart_match> com0 at obio0 addr 0xd8200000-0xd820ffff intr 32 : ns16650, no ERS, working fifo com0: console icu: establish_irq: is->is_irq=0x20 icu: unblock: irqbase=0x00000020, irqmask=0x00000001, 0x00000000 -> 0x00000008 wmtmr0 at obio0 addr 0xd8100000-0xd810ffff intr 48 : VC System Timer icu: establish_irq: is->is_irq=0x30 icu: unblock: irqbase=0x00000020, irqmask=0x00010000, 0x00000008 -> 0x00000008 rn_init: radix functions require max_keylen be set boot device: <unknown> root device:
- TB-URL http://www.tokuda.net/diary/adiary.cgi/0831/tb/
APC8750にNetBSD/evbarmを移植するための記録 8/26
今日はgitを入れてリモートからリポジトリを使えるようにする。
が、pkgsrcからscmgitを入れているだけで終わってしまった。
が、pkgsrcからscmgitを入れているだけで終わってしまった。
- TB-URL http://www.tokuda.net/diary/adiary.cgi/0830/tb/
APC8750にNetBSD/evbarmを移植するための記録 8/25
割り込みコントローラをちゃんとしないといけないらしいが、まるで分らない。
ARMのドキュメントをあたると、Cortexなどは標準の割り込みコントローラが内蔵されているようにみえるが、ARM11は英語しかないのでわからん。が、Chapter 12. Vectored Interrupt Controller Portとかいうのがある。こいつはPL192とかいうやつらしいのでその仕様書を読めと書いてある。
Linuxのソースをあたっても、PL192とかいうのはWM8750では使ってなさそうな気がする。
そういえば、http://www.spinics.net/lists/arm-kernel/msg240125.htmlとかいうページを見つけた。vt8500-intcとか読めるので、VT8500というCPU(おそらく昔のVIAのARMで、それがWonderMediaに子会社化されたとかそういうの?)とcompatibleといっておる。VT8500のirc.cとWM8750のirc.cを比較すると、似ているといえば似ているけれど、だいぶ違うような。
http://lxr.free-electrons.com/source/drivers/irqchip/irq-vt8500.c
https://github.com/apc-io/apc-8750/blob/master/kernel/arch/arm/mach-wmt/irq.c
そもそもソースツリーの構造が違うのを比較しても意味ないかもしれんな。
NetBSDの割り込み処理を読んでも、よくわからん。もしかしたら、LinuxとNetBSDの両方にある評価ボードの割り込み処理を比較して、Linuxでこう書くところをNetBSDでこう書けばよい、とわかれば、それをWM8750のirq.cからNetBSDに変換することができるかもしれん。
例によってLinux側のgeminiを見てみるか。ソースはapc-8750/kernel/arch/arm/mach-gemini/irq.cだな。
まずは、レジスタは4刻みで定義されている。
関数の直後にdevice_initcall(wmt_irq_init_devicefs);という文があるのは初期化の際に呼ばれるもののよう。
関数の中身はデバイスクラスを登録する関数を読んでいるようだ。こいつもその直前の構造体を読むとsuspend,resumeはこの関数名ですよと言っているので、まぁ、最初は気にしなくてよいことにしよう。
ack_irqは先ほどのマクロIRQ_CLEARに1<< irqをraw_write1しているだけ。
mask_irqはIRQ_MASKを読んで~(1<<irq)のANDをとって再びIRQ_MASKに書いているだけ。
unmask_irqは|=(1<<irq)しているだけ。maskってintだから32bitとして、32個しか割り込みないのかな?
init_irqが初期化処理みたい。なんか、forループでNR_IRQSの数だけ回している。
geminiのヘッダを見ると
GPIOだけマクロが
ループの中では、set_irq_chip, set_irq_handler, set_irq_flagsを割り込みそれぞれに対して呼び出している模様。
handle_edge_irqの時だけはmode, levelのビットを立てている。
ループの後、すべての割り込みを禁止して、割り込みモードとして先のmode, levelをraw_writelで書き込んでいる。
geminiは割り込み32個をビットにして管理しているってことかな?
NetBSDのgemini_icu.cをみると、確かに割り込み32個あるようだ。sources[32]がそれだろう。
関数として、block, unblockというのがLinuxのmask, unmaskっぽいな。
Linuxのack_irqに相当するものはなさそう。
NetBSDの場合、find_pending_irqs, irq_handler,establish_irqがある。
find_pending_irqs, irq_handlerそれぞれ、最後はpic_から始まる関数を呼んでいる。attachでもadd_picなどとしている。こいつが共通的な何かをしてくれるものなのだろうか。
しかし、irq_handlerは何をしているのだろう、というか、pending処理以外、何もしていないような。ハンドリングしてくれるのかと思ったが...
establish_irqは、IRQの確立、つまり初期化処理なのだろう。UARTのattachで似たような関数を呼んでいた。つまり、何らかのデバイスドライバがこいつを呼ぶということであろうか。
Linuxは最初にループでIRQの初期化を回す。NetBSDはデバイスドライバが初期化されるごとに個々のIRQの初期化処理が走るということなのかもしれない。
WMTのLinuxコードを見ると、割り込みコントローラICDC0は次のようになっている。
ちなみにmmap.cでは
それはともかく、irq.cではICDC0_VAL(irq) = val;という値の代入しかやっていない。
初期化(wmt_init_irq)では0を入れており、mask, unmaskではICDC_ENABLEを立てたり・クリアしたりしている。
ICDC_ENABLEは
ICDC0_VAL(irq)を追っかけてみる。まずは、元の定義は
まず、ICDC_OFFSET_WMT(irq)は次のように定義されている。
初期化ルーチンを読んでみる。
まず、ICDC0_ADDRを先頭とした8ビット単位で64個のテーブルを作り、0で初期化しているというわけか。
次に、おのおののIRQで使うルーチンをset_irq_chipで指定。すべて、
次に、set_irq_handlerでデフォルトのハンドラhandle_level_irq(kernel/irq/chip.c)をセット。set_irq_flagにデフォルトのフラグをセットしている。
デフォルトのフラグは
つうことで、結局、gemini, wmtともにirq.cにはMDの部分だけが書かれていたということですね。
geminiは32ビットのうち、IRQビット目を立てる、という方式だし、WMTは8ビットつまり1バイトを64個ならべて、IRQ個目の1バイトの3ビット目を立てたり、クリアしたり、という部分だけでした。
そこをNetBSDで実装してあげればいいんですね、たぶん。
ARMのドキュメントをあたると、Cortexなどは標準の割り込みコントローラが内蔵されているようにみえるが、ARM11は英語しかないのでわからん。が、Chapter 12. Vectored Interrupt Controller Portとかいうのがある。こいつはPL192とかいうやつらしいのでその仕様書を読めと書いてある。
Linuxのソースをあたっても、PL192とかいうのはWM8750では使ってなさそうな気がする。
そういえば、http://www.spinics.net/lists/arm-kernel/msg240125.htmlとかいうページを見つけた。vt8500-intcとか読めるので、VT8500というCPU(おそらく昔のVIAのARMで、それがWonderMediaに子会社化されたとかそういうの?)とcompatibleといっておる。VT8500のirc.cとWM8750のirc.cを比較すると、似ているといえば似ているけれど、だいぶ違うような。
http://lxr.free-electrons.com/source/drivers/irqchip/irq-vt8500.c
https://github.com/apc-io/apc-8750/blob/master/kernel/arch/arm/mach-wmt/irq.c
そもそもソースツリーの構造が違うのを比較しても意味ないかもしれんな。
NetBSDの割り込み処理を読んでも、よくわからん。もしかしたら、LinuxとNetBSDの両方にある評価ボードの割り込み処理を比較して、Linuxでこう書くところをNetBSDでこう書けばよい、とわかれば、それをWM8750のirq.cからNetBSDに変換することができるかもしれん。
例によってLinux側のgeminiを見てみるか。ソースはapc-8750/kernel/arch/arm/mach-gemini/irq.cだな。
まずは、レジスタは4刻みで定義されている。
#define IRQ_SOURCE(base_addr) (base_addr + 0x00) #define IRQ_MASK(base_addr) (base_addr + 0x04) #define IRQ_CLEAR(base_addr) (base_addr + 0x08) #define IRQ_TMODE(base_addr) (base_addr + 0x0C) #define IRQ_TLEVEL(base_addr) (base_addr + 0x10) #define IRQ_STATUS(base_addr) (base_addr + 0x14) #define FIQ_SOURCE(base_addr) (base_addr + 0x20) #define FIQ_MASK(base_addr) (base_addr + 0x24) #define FIQ_CLEAR(base_addr) (base_addr + 0x28) #define FIQ_TMODE(base_addr) (base_addr + 0x2C) #define FIQ_LEVEL(base_addr) (base_addr + 0x30) #define FIQ_STATUS(base_addr) (base_addr + 0x34)geminiとwmtで関数を比較する。
- gemini_ack_irq
- gemini_mask_irq
- gemini_unmask_irq
- gemini_init_irq
- wmt_ack_irq
- wmt_mask_irq
- wmt_unmask_irq
- wmt_init_irq
- wmt_irq_suspend
- wmt_irq_resume
- wmt_irq_init_devicefs
関数の直後にdevice_initcall(wmt_irq_init_devicefs);という文があるのは初期化の際に呼ばれるもののよう。
関数の中身はデバイスクラスを登録する関数を読んでいるようだ。こいつもその直前の構造体を読むとsuspend,resumeはこの関数名ですよと言っているので、まぁ、最初は気にしなくてよいことにしよう。
ack_irqは先ほどのマクロIRQ_CLEARに1<< irqをraw_write1しているだけ。
mask_irqはIRQ_MASKを読んで~(1<<irq)のANDをとって再びIRQ_MASKに書いているだけ。
unmask_irqは|=(1<<irq)しているだけ。maskってintだから32bitとして、32個しか割り込みないのかな?
init_irqが初期化処理みたい。なんか、forループでNR_IRQSの数だけ回している。
geminiのヘッダを見ると
#define NORMAL_IRQ_NUM 32 #define GPIO_IRQ_BASE NORMAL_IRQ_NUM #define GPIO_IRQ_NUM (3 * 32) #define NR_IRQS (NORMAL_IRQ_NUM + GPIO_IRQ_NUM)つうことは、割り込みの数は32じゃなくて32 + 32 * 3 で128あるってことか。
GPIOだけマクロが
#define IRQ_GPIO(x) (22 + (x))ってなっているのがポイント? GPIOだけ特別扱いされているっぽい、って思っていればいいか。
ループの中では、set_irq_chip, set_irq_handler, set_irq_flagsを割り込みそれぞれに対して呼び出している模様。
handle_edge_irqの時だけはmode, levelのビットを立てている。
ループの後、すべての割り込みを禁止して、割り込みモードとして先のmode, levelをraw_writelで書き込んでいる。
geminiは割り込み32個をビットにして管理しているってことかな?
NetBSDのgemini_icu.cをみると、確かに割り込み32個あるようだ。sources[32]がそれだろう。
関数として、block, unblockというのがLinuxのmask, unmaskっぽいな。
Linuxのack_irqに相当するものはなさそう。
NetBSDの場合、find_pending_irqs, irq_handler,establish_irqがある。
find_pending_irqs, irq_handlerそれぞれ、最後はpic_から始まる関数を呼んでいる。attachでもadd_picなどとしている。こいつが共通的な何かをしてくれるものなのだろうか。
しかし、irq_handlerは何をしているのだろう、というか、pending処理以外、何もしていないような。ハンドリングしてくれるのかと思ったが...
establish_irqは、IRQの確立、つまり初期化処理なのだろう。UARTのattachで似たような関数を呼んでいた。つまり、何らかのデバイスドライバがこいつを呼ぶということであろうか。
Linuxは最初にループでIRQの初期化を回す。NetBSDはデバイスドライバが初期化されるごとに個々のIRQの初期化処理が走るということなのかもしれない。
WMTのLinuxコードを見ると、割り込みコントローラICDC0は次のようになっている。
#define ICDC0_ADDR (__IC_BASE + 0x40) /* dest_ctl_addr[0] */__IC_BASEは
#ifdef __IC_BASE #error "__IC_BASE has already been defined in another file." #endif #ifdef INTERRUPT_CTRL_BASE_ADDR /* From wmt_mmap.h */ #define __IC_BASE INTERRUPT0_CTRL_BASE_ADDR #else #define __IC_BASE 0xFE140000 /* 64K */ #endifてなぐあい。割り込みコントローラのVAであろう。
ちなみにmmap.cでは
#define INTERRUPT0_CTRL_BASE_ADDR (0xD8140000 + WMT_MMAP_OFFSET) /* 64K */なのだ。いずれにせよVAのアドレスになっている。bus_space_mapはPAばかりだったけど...
それはともかく、irq.cではICDC0_VAL(irq) = val;という値の代入しかやっていない。
初期化(wmt_init_irq)では0を入れており、mask, unmaskではICDC_ENABLEを立てたり・クリアしたりしている。
ICDC_ENABLEは
#define ICDC_ENABLE BIT3 /* Interrupt enable bit.*/なのでBIT3を立てている・クリアしているだけである。
ICDC0_VAL(irq)を追っかけてみる。まずは、元の定義は
#define ICDC0_VAL(x) (REG8_VAL(ICDC0_ADDR + ICDC_OFFSET_WMT(x)))となり、マクロが絡み合っているので読み解こう。
まず、ICDC_OFFSET_WMT(irq)は次のように定義されている。
#define ICDC_OFFSET_WMT(x) ((x) & ICDC_NUMMASK_WMT)NUMMASKなどと言っているが、
#define ICDC_NUMMASK_WMT 0x7F /* mask to avoid overflow */ということでほぼxと思えばよい。つまり、ICDC0_VALマクロは
#define ICDC0_VAL(x) (REG8_VAL(ICDC0_ADDR + x))である。で、残ったREG8_VALは最終的にこうなる。hardware.hに定義がある。
# define __REG8P(x) (((__regbase8 *)((x)&~4095))->offset[((x)&4095)>>0]) typedef struct { volatile u8 offset[4096]; /* 4K * 1 = SZ_4K */ } __regbase8;つまり、ICDC0_ADDRを先頭に、割り込み番号ごとに8ビット割り当てられて64個ならんでいると。で、ENABLEのやつにはその8ビットの3ビット目に1が立っていると。
初期化ルーチンを読んでみる。
まず、ICDC0_ADDRを先頭とした8ビット単位で64個のテーブルを作り、0で初期化しているというわけか。
次に、おのおののIRQで使うルーチンをset_irq_chipで指定。すべて、
static struct irq_chip wmt_normal_chip = { .name = "normal", .ack = wmt_ack_irq, .mask = wmt_mask_irq, .unmask = wmt_unmask_irq, };なので、自ファイル(irq.c)にある関数を呼び出すと。
次に、set_irq_handlerでデフォルトのハンドラhandle_level_irq(kernel/irq/chip.c)をセット。set_irq_flagにデフォルトのフラグをセットしている。
デフォルトのフラグは
#define IRQF_VALID (1 << 0)なので0x01ということか。
つうことで、結局、gemini, wmtともにirq.cにはMDの部分だけが書かれていたということですね。
geminiは32ビットのうち、IRQビット目を立てる、という方式だし、WMTは8ビットつまり1バイトを64個ならべて、IRQ個目の1バイトの3ビット目を立てたり、クリアしたり、という部分だけでした。
そこをNetBSDで実装してあげればいいんですね、たぶん。
- TB-URL http://www.tokuda.net/diary/adiary.cgi/0829/tb/
APC8750にNetBSD/evbarmを移植するための記録 8/24
8/24からは書き溜めたメモから順次投下していく。敬体から常体に書きぶりも変わってマス。
二台目は普通に動いてうれしい。
u-bootに毎回同じコマンドを入れるのが面倒くさい。ということで対策。
tftpbootはデフォルトファイル名をC0A80002.imgが設定されているので、netbsd.binにシンボリックリンクを張れば少しだけサボれる。
結局、ほかのドライバと比較するときわかりにくいのでobioをgeminiのobioっぽく書き換え。oba -> obioに変更するなど。ドライバ全体に波及。
シリアルドライバ、matchが1を返すという実装から、geminiのような初期化を加える。
さらに、attachはsc->sc_typeをCOM_TYPE_16650_NOERSに変更。当たり前だが、起動時のメッセージが変わった。で、attachの前後にデバッグ文を入れてみたら、uartのattachはなぜか二回呼ばれている。
ねんがんのシリアル「入力」はできない。
良く考えたら、割り込みコントローラって、コンパイルを通るようにしただけなので、動いているわけがない。
シリアルの入力は、割り込みによって入力処理に飛ばされるはずだから、割り込みコントローラの実装をやらないとダメって気が。当たり前か。consinitで表示ができるのも、わりと謎だが...
で、comprobe1でへくっとる。
根本的におかしいんじゃないのかなと思ってしまう。
geminiとか、consinitでbus_space_mapしてるんだよな。
やったほうがいいのかな。comcnattachだけでええんやろか?
よく考えたら、ここでもCOM_TYPE_NORMALってやってるけど、変えたほうがいいのか?
調べてみたら、COM_TYPE_NORMALじゃないやつって、COM_TYPE_PXA2x0を除けばgeminiのCOM_TYPE_16550_NOERSぐらいか。むしろgeminiが異端に見えるので真似しないほうがよいのかも...
やっぱり、シリアルコンソールの出力はマグレで表示されていると思ったほうがよさそうな気がしてきた。
二台目は普通に動いてうれしい。
u-bootに毎回同じコマンドを入れるのが面倒くさい。ということで対策。
tftpbootはデフォルトファイル名をC0A80002.imgが設定されているので、netbsd.binにシンボリックリンクを張れば少しだけサボれる。
結局、ほかのドライバと比較するときわかりにくいのでobioをgeminiのobioっぽく書き換え。oba -> obioに変更するなど。ドライバ全体に波及。
シリアルドライバ、matchが1を返すという実装から、geminiのような初期化を加える。
さらに、attachはsc->sc_typeをCOM_TYPE_16650_NOERSに変更。当たり前だが、起動時のメッセージが変わった。で、attachの前後にデバッグ文を入れてみたら、uartのattachはなぜか二回呼ばれている。
ねんがんのシリアル「入力」はできない。
良く考えたら、割り込みコントローラって、コンパイルを通るようにしただけなので、動いているわけがない。
シリアルの入力は、割り込みによって入力処理に飛ばされるはずだから、割り込みコントローラの実装をやらないとダメって気が。当たり前か。consinitで表示ができるのも、わりと謎だが...
WMT # set serverip 192.168.0.10 WMT # tftpboot 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 ########################### ################################################################# ################################################################# ################################################################# ################################################################# ###################################### done Bytes transferred = 2520256 (2674c0 hex) WMT # go 8000 ## Starting application at 0x00008000 ... 00008328 NetBSD 00000000 00000000 0048096b 00000412 00000000 00000412 00000004 00000412 c0000000 00000000 0048096b 0000041e 00003000 0000041e 00000004 0000041e fe000000 d8000000 010fffff 00000412 00003f80 d8000412 00000010 00000412 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 NetBSD/evbarm (APC) booting ... [ Kernel symbol table missing! ] Loaded initial symtab at 0xc01b4364, strtab at 0xc01d3494, # entries 7940 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) #28: Sat Aug 24 13:53:26 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 <wm8750_uart_match> comprobe1 0 </wm8750_uart_match rv=0> wmicu0 at obio0 addr 0xd8140000-0xd814ffff <wm8750_uart_match> com0 at obio0 addr 0xd8200000-0xd820ffff intr 32 : ns16650, no ERS, working fifo com0: console wmtmr0 at obio0 addr 0xd8100000-0xd810ffff intr 48 : VC System Timer rn_init: radix functions require max_keylen be set boot device: <unknown> root device:<wm8750_uart_match>はデバッグ文である。むかしむかしJavaでこういう書き方したのでやってみたが、イマイチカッコ悪いな。
で、comprobe1でへくっとる。
根本的におかしいんじゃないのかなと思ってしまう。
geminiとか、consinitでbus_space_mapしてるんだよな。
やったほうがいいのかな。comcnattachだけでええんやろか?
よく考えたら、ここでもCOM_TYPE_NORMALってやってるけど、変えたほうがいいのか?
調べてみたら、COM_TYPE_NORMALじゃないやつって、COM_TYPE_PXA2x0を除けばgeminiのCOM_TYPE_16550_NOERSぐらいか。むしろgeminiが異端に見えるので真似しないほうがよいのかも...
やっぱり、シリアルコンソールの出力はマグレで表示されていると思ったほうがよさそうな気がしてきた。
- TB-URL http://www.tokuda.net/diary/adiary.cgi/0828/tb/