H8マイコンでLinux 2回目
- 2011/08/28
- カテゴリー:電子工作
- タグ:H8マイコンでLinux
前回で開発環境が一応整ったみたいなので、Linuxカーネルのビルドを試してみました。
Linuxといっても、改めて言う必要はないかもしれませんが、組み込み向けの「uClinux」を使うことになります。
早速uClinuxのサイトから最新のソースパッケージを取得。
TOPページのhttp://www.uclinux.org/はなぜか頻繁に見れなくなるようなので、ファイルの置いてあるこのページに直接行ったほうがよいかもしれません。
現状では、uClinux-dist-20110810.tar.bz2 が最新のようです。
この記事では1つ前、"20110603"の日付のものを使用していますが、これから行う内容におそらく相違はないと思います。
ソースパッケージには、2.0.x、2.4,x、2.6.xのカーネルソースがそれぞれ入っています。今回はとりあえず2.4.xでビルドします。H8マイコンのメモリ増設はまだしていませんし、メモリ使用量が2.6.xよりも少なくなるようですので。
パッケージを展開して、make menuconfig、make dep、make、めんどいので詳細は略。
make CROSS_COMPILE=h8300-elf- menuconfig
make CROSS_COMPILE=h8300-elf- dep 2>&1 | tee make_dep_log
make CROSS_COMPILE=h8300-elf- 2>&1 | tee make_log
実はツールチェイン構築時の"--target=h8300-elf"は不要でした。このオプションを付けてしまったせいで、make時にもわざわざ"CROSS_COMPILE=h8300-elf-"をつけなくてはなりませんでした。
(何もつけない場合は"h8300-linux-elf"になります)
とりあえず今はこのまま進めます。
makeするとエラーて怒られてしまいました。滞りなく完了すると思っていたのに…
結論から言えば、ソースコードがGCC3以下でコンパイルされることを前提として書かれているのに対し、GCC4でコンパイルしたことが原因でした。GCC4から構文チェックが厳密になって、一部でこれまでの警告がエラーとして出てしまうようです。
いっそのことGCC3でやり直すか、いや待てそれは敗北宣言っぽい気がするな・・・、てなわけで、仕方ないので見ていくことにしましょう。
エラーその1
make CFLAGS="-fno-builtin -DNO_CACHE -D__KERNEL__ -I/usr/local/src/uClinux-dist/linux-2.4.x/include -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fno-strict-aliasing -fno-common -fno-builtin-sprin
tf -fomit-frame-pointer -Wno-pointer-sign -pipe -DNO_MM -DNO_FPU -DNO_CACHE -mh -mint32 -D__ELF__ -DNO_FORGET -DUTS_SYSNAME=\"uClinux\" -D__linux__ -DTARGET=aki3068net -Os " -C drivers
h8300-elf-ld -mh8300helf -r -o aki3068net.o timer.o
ptrace_h8300h.c: In function 'getnextpc':
ptrace_h8300h.c:249:7: error: lvalue required as left operand of assignment
ptrace_h8300h.c:253:7: error: lvalue required as left operand of assignment
linux-2.4.x/arch/h8300/platform/h8300h/ptrace_h8300h.c
202 static unsigned short *getnextpc(struct task_struct *child, unsigned short *pc)
203 {
204 const struct optable *op;
205 unsigned char *fetch_p;
206 unsigned char inst;
207 unsigned long addr;
208 unsigned long *sp;
209 int op_len,regno;
210 op = optables[0].ptr;
211 op_len = optables[0].size;
212 fetch_p = (unsigned char *)pc;
213 inst = *fetch_p++;
214 do {
・・・
247 case relb:
248 if ((inst = 0x55) || isbranch(child,inst & 0x0f))
249 (unsigned char *)pc += (signed char)(*fetch_p);
250 return pc+1; /* skip myself */
251 case relw:
252 if ((inst = 0x5c) || isbranch(child,(*fetch_p & 0xf0) >> 4))
253 (unsigned char *)pc += (signed short)(*(pc+1));
254 return pc+2; /* skip myself */
257 }
エラーが出ている箇所は249行目です。
ググればすぐに出てきますが、左辺がキャストされていることでエラーとなります。やりたいことはわからなくはないですが、この書き方は確かにあいまいです。
修正方法は、2.6.xのソースから引っこ抜いてこればOKです。
247 case relb:
248 if (inst == 0x55 || isbranch(child,inst & 0x0f))
249 pc = (unsigned short *)((unsigned long)pc +
250 ((signed char)(*fetch_p)));
251 return pc+1; /* skip myself */
252 case relw:
253 if (inst == 0x5c || isbranch(child,(*fetch_p & 0xf0) >> 4))
254 pc = (unsigned short *)((unsigned long)pc +
255 ((signed short)(*(pc+1))));
256 return pc+2; /* skip myself */
257 }
エラーその2
h8300-elf-gcc -fno-builtin -DNO_CACHE -D__KERNEL__ -I/usr/local/src/uClinux-dist/linux-2.4.x/include -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fno-strict-aliasing -fno-common -fno-builtin-spri
ntf -fomit-frame-pointer -Wno-pointer-sign -pipe -DNO_MM -DNO_FPU -DNO_CACHE -mh -mint32 -D__ELF__ -DNO_FORGET -DUTS_SYSNAME="uClinux" -D__linux__ -DTARGET=aki3068net -Os -nostdinc -iwithprefix
include -DKBUILD_BASENAME=ints -c -o ints.o ints.c
make[3]: ディレクトリ `/usr/local/src/uClinux-dist/linux-2.4.x/drivers/media' に入ります
make -C radio
make[5]: ディレクトリ `/usr/local/src/uClinux-dist/linux-2.4.x/drivers/ide/arm' に入ります
rm -f idedriver-arm.o
h8300-elf-ar rcs idedriver-arm.o
make[4]: ディレクトリ `/usr/local/src/uClinux-dist/linux-2.4.x/drivers/media/radio' に入ります
make all_targets
n_tty.c: In function 'write_chan':
n_tty.c:1406:5: error: assignment of read-only variable '__gu_val'
n_tty.c:1406:5: warning: passing argument 1 of 'memcpy' discards qualifiers from pointer target type
rm -f mm.o
__gu_val が read-only ということで怒られています。 __gu_val を探してみると下記の場所にありました。
linux-2.4.x/include/asm-h8300/uaccess.h
85 #define get_user(x, ptr) \
86 ({ \
87 int __gu_err = 0; \
88 typeof(*(ptr)) __gu_val = 0; \
89 switch (sizeof(*(ptr))) { \
90 case 1: \
91 case 2: \
92 case 4: \
93 __gu_val = *(ptr); \
94 break; \
95 case 8: \
96 memcpy(&__gu_val, ptr, sizeof (*(ptr))); \
97 break; \
98 default: \
99 __gu_val = 0; \
100 __gu_err = __get_user_bad(); \
101 break; \
102 } \
103 (x) = __gu_val; \
104 __gu_err; \
105 })
ふむふむなるほど。
typeof(*(ptr)) としているんだけど、上記エラー箇所の場合、ptr が const unsigned char* なので、__gu_val が const になってしまい値が代入できない、というオチのようです。
get_userの詳細はさておき、結局やっていることは *ptr → __gu_val → x と値をコピーしていっているだけです。ということはつまり、暗黙的に x と *ptr は同じ(もしくは x が *ptr を内包する)型になっていると考えてもよく、下記でも問題ないはずです。
88 typeof(x) __gu_val = 0; \
もちろん x が const となることはありません。
というわけで、これら2つのエラーを修正することで、カーネル自体のコンパイルはうまくいったようです。
しかしこの後、uClibやユーザランドのコンパイルでエラーがたくさん出てしまうことに…
それはまた次回・・・(って、あるのかわかりませんが^^)