BareMetal Raspberry Pi
『江戸前魚食大全』(草思社)なんて言う本を読んだ。
江戸前寿司とか言う、江戸前とは? 将軍様がおわすお城の前に広がる海の事。 徳川の家康親父が江戸に移ってきて町が栄えると供に、魚場が活気付いたそうな。 それまでは、ほそぼそとした漁村があっただけとの事。
お城以下、武士の町として江戸は発展。それに群がるように商人達が上方の京都の 方からやって来た。
その中に紀州とか大阪、堺方面の魚師達も、新しい漁法を引っさげて、江戸へと やってきた。にわかに江戸前の海は賑わい始める。
こうした連中は、建前ではお城に納める魚を取るって事だったんだけど、余った 魚を一般に売って儲けようとした、魚河岸の始まりである。日本橋に魚河岸が 有ったらしい。
漁村から魚を仕入れ、市場に下ろす魚問屋が次第に幅を利かせていく。一義は お城からの注文をきちんと履行する事。これを守るため、何軒かの問屋が、 持ち回りで、お城に納める魚の調達に責任を持たされた。
とはいえ、いつもいつも、上魚とされる鯛とかを調達出来る訳ではない。 (自然が相手の漁業ですからね)そこで、魚を生簀に入れて、対応出来るように した。取れすぎた時には、生簀に入れ、不魚の時は、生簀から出荷。
これをまねしたのが、コンピュータの特に通信関係で多用される、バッファリング 技術。これなくしては、インターネットの発展は全く無かっただろう。経路の 遅延とかは、全く予測できませんから。話が逸れた。
上方からやってきた魚師は、野田とか銚子で内職の醤油作りとかを始めた。 濃い口醤油。味噌も参勤交代で、地方の味噌が入ってくるようになった。 伊達藩が江戸の屋敷で作る味噌が仙台味噌として有名になった。 こうして、調味料も揃って、江戸前の味が完成していく。
参勤交代の地方への土産は、浅草のり。浅草で海苔が取れるわけではなく、 浅草に海苔の加工場が有ったので、浅草海苔がブランド名になったとか。 採取は、江戸前海。品川とか大井あたりだったらしい。
面白すぎて、引き写しも出来ないな。一読あれ。1800円也。キンドルで 読み放題に登録されるのかな?
次は何
前回、弦の事を調べるんで、bfdに降りて行った。一番詳しいのは、例によって infoに有るって事が分かった。それとは別に、ぐぐるのアンテナに下記が 引っかかってきた。
jonesforthのgasによるコンパイルと -build-id オプションなど
この記事に出てきてる、jonesforthって何だ? これをぐぐると言う道草が 始まった。
で、行き着いたのが、こちら。
Porting Richard Jones' FORTH to ARM
最後に行き着いたのが、 A bare-metal FORTH operating system for Raspberry Pi
なんか、面白そうジャン。所で、bare-metalって何よ。ハイフォンで結ばれているから 造語だな。最初のbareってのは、裸とか、ありのままとか、最低限とかいう意味 らしい。metalは、金属とか気性って事らしい。
普通、ラズパイと言うとラスビアンとか言う、Debianを移植したOSを入れて、 パソコンの代わりをさせる。
けど、bareって事で、ハードだけ、Linux無しよって言う、シャープ得意の クリーンコンピュータを言うんだな。
そのクリーンコンピュータにforthだけを入れましょっていう潔い人が世の中には いて、それが、上のgitの持ち主。
ハードの中身が見えるんで、ヤリタイ放題なんだろうな。
jonesforth arm port
OpenBSDにqemu-system-armを入れておいたので、やってみる。
makeの前にCROSS変数を設定するの面倒なので、Makefileの冒頭付近に 下記を埋め込んでおく。
CROSS=arm-none-eabi-
そして、試作する。
[ob: pijFORTHos]$ make clean all rm -f *.o *.sym *.bin *.hex *.elf *.list *.img *~ core arm-none-eabi-as start.s -o start.o arm-none-eabi-as jonesforth.s -o jonesforth.o arm-none-eabi-gcc -g -Wall -O2 -nostdlib -nostartfiles -ffreestanding -c raspberry.c arm-none-eabi-gcc -g -Wall -O2 -nostdlib -nostartfiles -ffreestanding -c timer.c arm-none-eabi-gcc -g -Wall -O2 -nostdlib -nostartfiles -ffreestanding -c serial.c arm-none-eabi-gcc -g -Wall -O2 -nostdlib -nostartfiles -ffreestanding -c xmodem.c arm-none-eabi-ld start.o jonesforth.o raspberry.o timer.o serial.o xmodem.o -T loadmap -o pijFORTHos.elf arm-none-eabi-objdump -D pijFORTHos.elf > pijFORTHos.list arm-none-eabi-objcopy pijFORTHos.elf -O ihex pijFORTHos.hex arm-none-eabi-objcopy --only-keep-debug pijFORTHos.elf kernel.sym arm-none-eabi-objcopy pijFORTHos.elf -O binary kernel.img
起動はどうする? gitの説明書では、boot-loaderを入れるようになってるけど、 qemuだと、ブートローダー相当をqemuが受け持ってくれるようなので、elfファイルを 指定すればいいのかな?
qemu-system-arm -M versatilepb -cpu arm1176 -m 128 -nographic \ -singlestep -kernel pijFORTHos.elf
何の応答も無い。はて? minicomで接続するってなってるんで、そうやってみたい。 でも、上の起動方法だと、接続先が出てこないぞ。ぐぐったら、
qemu-system-arm -M versatilepb -cpu arm1176 -m 128 \ -monitor stdio -serial pty \ -singlestep -kernel pijFORTHos.elf
こんな風にシリアルを仮想端末に割り当てられるようだ。
QEMU 2.2.1 monitor - type 'help' for more information (qemu) char device redirected to /dev/ttyp3 (label serial0)
こんなんで、端末が出るんで、それをminicomに接続。でもだんまりだなあ。
しょうがないので、arm-none-eabi-gdb の出番かな。
diff --git a/start.s b/start.s index 5959129..b51ea8a 100644 --- a/start.s +++ b/start.s @@ -20,7 +20,8 @@ _start: ldr lr, =halt @ Halt on "return" ldr r0, =0x8000 @ Absolute address of kernel memory cmp r0, r1 @ Are we loaded where we expect to be? - beq k_start @ Then, jump to kernel entry-point + b k_start +@@ beq k_start @ Then, jump to kernel entry-point mov lr, r0 @ Otherwise, relocate ourselves ldr r2, =0x7F00 @ Copy (32k - 256) bytes 1: ldmia r1!, {r3-r10} @ Read 8 words
こんな風に、start.sをちょっと改変。qemuの起動コードに、-s -S を追加する。 そして、qemuを起動。それから、gdbを起動。
[ob: pijFORTHos]$ arm-none-eabi-gdb -q pijFORTHos.elf Reading symbols from pijFORTHos.elf...done. (gdb) target remote localhost:1234 Remote debugging using localhost:1234 0x00008000 in _start () (gdb) si 0x00008004 in _start () : k_start (sp=0) at raspberry.c:269 269 {
これで、追いかけて行ったら、
k_start(u32 sp) { timer_init(); serial_init(); // wait for initial interaction serial_puts(";-) "); putchar(wait_for_kb());
ニコニコ文字列の表示を通り過ぎるも、表示は全く無し。続けて追うと、キーボード 入力待ちの所でうろうろしてて、らちが明かない。
方針転換しようってんで、ぐぐるを再び漁る。
本当のラズパイを真似る
piでベアメタルプログラミングなんてのが引っかかってきた。去年の今頃も見た気がするけど、一期一会の 可能性が有るので、メモ。
そして、 QEMUで完全にRaspbianをエミュレートする方法なんてのにも出会った。
armの真似をしてくれるqemuが、ラズパイを完全にサポートしないものだから、 色々不都合が有るらしい。我らが百科事典で全体像を掴んでおこう。 Raspberry Pi - Wikipedia
載っているCPUはシングルコアのARM1176JZF-Sから、クワッドコアのARM Cortex-A7、 時代の先端を行く64Bit化を果たした、ARM Cortex-A53 まで、さまざま。
そして、それを中心に、GPUとかペリフェラルを同梱したSocにまとめられて、 BCM2835,6,7シリーズが出てる。それぞれの石が載ったボードを愛称で、 ラズパイ2 モデルB とか称する訳ね。
一般ユーザーには、この愛称が通りやすいんでしょうな。qemuのモデルを見てると、 ラズパイなんてのは、勿論無い。
そこで、今まではは代用の、versatilepb なんてモデルを使ってた訳だ。内部の UARTのアドレス配置とかが違うんで、ソースの書き換えとか面倒が有ったんだ。
$ git clone --depth=1 https://github.com/0xabu/qemu.git $ cd qemu $ ./configure --target-list=arm-softmmu $ make $ sudo make install
とまあ、能書きはいいので、qemuからforkしたというのをfedora23に入れてみた。 これも去年経験ずみ。glib2-develが入っていなくて、頓珍漢なメッセージに 悩まされたり、これが無いから、パッケージで入れるか、私に任せて (configureを擬人化してるな)gitで入れるか、選択せいとか、、、勿論、 お任せコースで、約15分で、出来上がった。
[sakae@fedora ~]$ qemu-system-arm -M help : raspi Raspberry Pi raspi2 Raspberry Pi 2 : versatileab ARM Versatile/AB (ARM926EJ-S)
ちゃんとパイ2まで、サポートされたよ。
さあ、ここまで来れば、動くかな? やっぱりニコニコ文字は拝めずです。 で、ここからまた、放浪の旅へ。。。
Raspberry Pi Bare Bones - OSDev Wiki たまたま、こちらを見てたら、さらっと、下記のような書き込みが!
Note that currently the QEMU "raspi" emulation may incorrectly load the kernel binaries at 0x10000 instead of 0x8000, so if you do not see any output, try adjusting the base address constant in the linker script.
これは重大なノートですよ。ロードアドレスを変更せいとな。
[sakae@fedora pijFORTHos]$ cat loadmap MEMORY { arm : ORIGIN = 0x10000, LENGTH = 0x8000 }
に変更。起動スクリプトは、下記を採用。
/usr/local/bin/qemu-system-arm -M raspi -nographic \ -singlestep -kernel pijFORTHos.elf
これで、動くかな。動いた、顔文字が出たらCRを叩くと、forthが動き出す。
[sakae@fedora pijFORTHos]$ sh z.sh main-loop: WARNING: I/O thread spun for 1000 iterations ;-) pijFORTHos 0.1.8 sp=0x00008000 1 2 3 4 + . 7 QEMU 2.5.50 monitor - type 'help' for more information (qemu) quit
終了は、Ctl-a c で、qemuのモニターに落ちて、強制終了って荒業です。
qemuのラズパイコード
折角、ソースからqemuを入れたので、担当コードとご対面しとく
[sakae@fedora src]$ cd qemu/hw/arm [sakae@fedora arm]$ ls Makefile.objs exynos4_boards.c omap2.c strongarm.h allwinner-a10.c fsl-imx25.c omap_sx1.c sysbus-fdt.c armv7m.c fsl-imx31.c palm.c tosa.c ast2400.c gumstix.c palmetto-bmc.c versatilepb.c bcm2835.c highbank.c pxa2xx.c vexpress.c bcm2835_peripherals.c imx25_pdk.c pxa2xx_gpio.c virt-acpi-build.c bcm2836.c integratorcp.c pxa2xx_pic.c virt.c boot.c kzm.c raspi.c xilinx_zynq.c collie.c mainstone.c realview.c xlnx-ep108.c cubieboard.c musicpal.c spitz.c xlnx-zynqmp.c digic.c netduino2.c stellaris.c z2.c digic_boards.c nseries.c stm32f205_soc.c exynos4210.c omap1.c strongarm.c
担当者は、bcm* と raspi.c だな。
/* * Raspberry Pi emulation (c) 2012 Gregory Estrade * Upstreaming code cleanup [including bcm2835_*] (c) 2013 Jan Petrous * * Rasperry Pi 2 emulation Copyright (c) 2015, Microsoft * Written by Andrew Baumann * * This code is licensed under the GNU GPLv2 and later. */
これ、raspi.cのクレジット。Microsoftの方って、個人参加されてるのかな? だったら、社名を出さないか。仕事としてやってるのかな。だったら、両者 偉いぞ。人類の知恵への貢献だな。
bcm2835.c
/* Peripheral base address seen by the CPU */ #define BCM2835_PERI_BASE 0x20000000
bcm2835_peripherals.c
/* Peripheral base address on the VC (GPU) system bus */ #define BCM2835_VC_PERI_BASE 0x7e000000
bcm2836.c
/* Peripheral base address seen by the CPU */ #define BCM2836_PERI_BASE 0x3F000000
これが際立った違いかな。CPUとGPUとのやりとりは、mailboxってハードで やってるらしい。複数のマシンが内蔵されてるって、とっても大変な事なのね。
raspi_platform.hに面白い冒頭コメントが
/* * bcm2708 aka bcm2835/2836 aka Raspberry Pi/Pi2 SoC platform defines * * These definitions are derived from those in Raspbian Linux at * arch/arm/mach-{bcm2708,bcm2709}/include/mach/platform.h * where they carry the following notice: * * Copyright (C) 2010 Broadcom * * This program is free software; you can redistribute it and/or modify :
Broadcomも太っ腹だなあ。まてよ、ラズパイ財団から石の注文を受けた時の 条件として、うちらこの石でリナちゃんを動かす積もり、それに関わる 資料は、自由になるようにGPL2ライセンスね、って事なんだろうね。
それで、親玉のSoC bcm2708シリーズから、フォークしてbcm2835/36が 生まれたって事なんだろうね。
で、詳細は、マニュアル嫁だな。
再び普通のqemuでやってみる
上記は、よりラズパイに近いqemuを作って動かした結果だけど、色々手を動かして 汗を流した結果、普通のqemuで動かす目処が付いた。
イソップ物語にも、この手の挿話が有ったよね。親父が死んだ。畑の中に宝を 隠してあるから、掘ってみろ。一生懸命に畑を掘り返したけど、何も出ず。 でも、畑を掘り返したおかげで、作物が非常に豊かに実った。
diff --git a/loadmap b/loadmap index 40537fb..5d614f0 100644 --- a/loadmap +++ b/loadmap @@ -1,7 +1,7 @@ MEMORY { - arm : ORIGIN = 0x8000, LENGTH = 0x8000 + arm : ORIGIN = 0x10000, LENGTH = 0x8000 } SECTIONS diff --git a/serial.c b/serial.c index 6259c65..1fe624f 100644 --- a/serial.c +++ b/serial.c @@ -9,7 +9,7 @@ #define USE_SERIAL_UART0 /* select full UART for serial i/o */ //#define USE_SERIAL_UART1 /* select mini UART for serial i/o */ -#define GPIO_BASE 0x20200000 +#define GPIO_BASE 0x101E4000 #define GPFSEL1 (*((volatile u32*)(GPIO_BASE + 0x04))) #define GPSET0 (*((volatile u32*)(GPIO_BASE + 0x1c))) #define GPCLR0 (*((volatile u32*)(GPIO_BASE + 0x28))) @@ -37,7 +37,7 @@ struct uart0 { u32 ICR; //_44; u32 DMACR; //_48; }; -#define UART0 ((volatile struct uart0 *)0x20201000) +#define UART0 ((volatile struct uart0 *)0x101F1000) struct uart1 { u32 _00;
qemu-system-arm -M versatilepb -cpu arm1176 -m 256 -nographic \ -singlestep -kernel pijFORTHos.elf
これで動いた。やってみるものだ。無駄では無かったな。