Qemu を使いこなすために
組み込みを仕事にしているため、よく機材不足や新規基盤の開発遅れなどのトラブルが起きます。
そこで、Qemu を活用できればと思っていたところに良い記事が見つかったので写経してみました。
ところが、ドライバの作成でコンパイルエラーが発生!!
ハードとして x86_64 環境、カーネルは 4.2 を選んだけど、組み合わせの問題はありがちなので解決していく。
> make make -C path/to/linux-4.2/ M=/path/to/custom_d evices/test_pci modules make[1]: Entering directory `/path/to/linux- 4.2' CC [M] /path/to/custom_devices/test_pci/test_pci_driver.o In file included from ./arch/x86/include/asm/bitops.h:16:0, from include/linux/bitops.h:36, from include/linux/kernel.h:10, from include/linux/list.h:8, from include/linux/module.h:9, from /path/to/custom_devices/test_pci/test_pci_driver.c:7: ./arch/x86/include/asm/arch_hweight.h: In function ‘__arch_hweight64’: ./arch/x86/include/asm/arch_hweight.h:53:42: error: expected ‘:’ or ‘)’ before ‘POPCNT64’ asm (ALTERNATIVE("call __sw_hweight64", POPCNT64, X86_FEATURE_POPCNT) ^ MENT’ b_replacement(num)":\n\t" newinstr "\n" e_replacement(num) ":\n\t" ^ ./arch/x86/include/asm/arch_hweight.h:53:7: note: in expansion of macro ‘ALTERNATIVE’ asm (ALTERNATIVE("call __sw_hweight64", POPCNT64, X86_FEATURE_POPCNT) ^ In file included from ./arch/x86/include/asm/pgtable_types.h:250:0, from ./arch/x86/include/asm/processor.h:18, from ./arch/x86/include/asm/thread_info.h:49, from include/linux/thread_info.h:54, from ./arch/x86/include/asm/preempt.h:6, from include/linux/preempt.h:64, from include/linux/spinlock.h:50, from include/linux/seqlock.h:35, from include/linux/time.h:5, from include/linux/stat.h:18, from include/linux/module.h:10, from /path/to/custom_devices/test_pci/test_pci_dri ver.c:7: ... 省略 ...
どうやら、標準ヘッダの 64bit 依存部分に問題があるらしい。
と思ったら、 ARCH
と CROSS_COMPILE
を指定し忘れているだけだった。
obj-m += test_pci_driver.o export ARCH = arm export CROSS_COMPILE = /path/to/buildroot/output/host/usr/bin/arm-buildroot-linux-uclibcgnueabi- KERNELDIR = /path/to/buildroot/output/build/linux-4.2/ all: make -C $(KERNELDIR) M=$(PWD) modules clean: make -C $(KERNELDIR) M=$(PWD) clean
すぐに気づいたけど、ダサすぎる。
ドライバ作成とか慣れていないのがバレバレである。
ビルドができたところで、問題が発生した。
ビルド環境は docker のコンテナ内に作成しているのだが、コンテナにはループバックデバイスがないため、 Qemu のルートファイルシステムがマウントできないのである!
> sudo mount -t ext2 -o loop,rw ../../buildroot/output/images/rootfs.ext2 /mnt/ mount: Could not find any loop device. Maybe this kernel does not know about the loop device? (If so, recompile or `modprobe loop'.)
いろいろ調べたけど、今のコンテナの状態ではできないっぽい。( rootfs をホストから隔離しなければできたり、 loop デバイスをコンテナにも見せたりできるらしいけど、本筋からずれるから今はやらない。でも、開発環境として本格的に利用するのであれば後者を試してみないと)
rootfs は buildroot で作成しているので(カーネルもだけど)、直接組み込むことで解決した。
$ qemu-system-arm -m versatilepb -kernel output/images/zImage -drive file=output/images/rootfs.ext2,if=scsi -append "root=/dev/sda console=ttyAMA0,115200" -nograpic -device test_pci
insmod
してみたけど、 Oops になってしまった。。。
今後は、問題を解決してアプリを作成→業務で使っているデバイスに近づくように拡張。と進めていこう。
# insmod test_pci_driver.ko test_pci 0000:00:0d.0: enabling device (0100 -> 0103) *** /home/embryo/workspa(321) test_pci_probe: PCI enabled for test_pci *** /home/embryo/workspa(327) test_pci_probe: mmio_base: 50002000, mmio_length: 50002000, m mio_flags: 1000 *** /home/embryo/workspa(346) test_pci_probe: pio_base: 1400, pio_length: 100, pio_flags: 4 0101 ------------[ cut here ]------------ kernel BUG at arch/arm/mach-versatile/pci.c:87! Internal error: Oops - BUG: 0 [#1] ARM Modules linked in: test_pci_driver(O+) CPU: 0 PID: 71 Comm: insmod Tainted: G O 4.2.0 #1 Hardware name: ARM-Versatile PB task: c79d6380 ti: c79e8000 task.ti: c79e8000 PC is at __pci_addr.isra.1+0x24/0x2c LR is at versatile_read_config+0x1c/0xb8 pc : [<c00148d8>] lr : [<c001498c>] psr: 20000093 sp : c79e9d20 ip : c0014970 fp : 38623d9c r10: 00000001 r9 : bf001798 r8 : 00000000 r7 : bf001960 r6 : 0000fefe r5 : 00000002 r4 : 00000068 r3 : 00000002 r2 : 0000fefc r1 : 00000068 r0 : 00000000 Flags: nzCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user Control: 00093177 Table: 07b14000 DAC: 00000015 Process insmod (pid: 71, stack limit = 0xc79e8190) Stack: (0xc79e9d20 to 0xc79ea000) 9d20: c79e9d64 60000013 bf0012f0 c017efb0 c79e9d3c c79e9d44 c7870800 00000000 9d40: bf0012f0 c7870800 bf001960 bf000c08 00001400 00000100 00040101 20000013 9d60: bf001750 00000000 c7870800 c7870868 bf001750 00000000 c7870800 bf00171c 9d80: bf001798 c01883a4 c0188330 c7870868 c042bfe0 bf001750 c03f0b40 00000003 9da0: c79dc280 c01cbd48 c7870868 bf001750 c787089c c03f0b40 00000000 c01cbf70 9dc0: 00000000 bf001750 c01cbee4 c01ca470 c7823d0c c7861d50 bf001750 c7b181e0 9de0: 00000000 c01cb5b4 bf0012f0 c79dc288 bf001750 bf001750 c03ddf20 c79d8760 9e00: bf003000 c01cc730 bf001790 c03ddf20 c03ddf20 c0009604 c03f0920 c0036a38 9e20: 00000000 00000000 00000000 c0025f98 000080d0 00000000 c79e9e38 c79e9e38 9e40: bf001828 c7b08000 c03dde00 c7fec9c0 c7ef9000 00000000 00000000 00000000 9e60: c79dc280 00000001 bf0017e0 c79dc288 c79d8720 bf0017e0 bf001828 00000001 9e80: 38623d9c c02cf920 c79e9f48 c79dc288 c79e9f48 c79dc288 00000001 c0056768 9ea0: bf0017ec 00007fff 00000000 c0054238 00000000 00000000 00000000 00000124 9ec0: c898b170 bf00193c bf0017ec 00000000 00000000 c0085004 00000004 c0085cd8 9ee0: ff000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 9f00: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 9f20: c0056bc8 00003545 00000000 000bb55d c898c545 000b8008 c79e8000 00000000 9f40: 00000000 c0056c38 c8989000 00003545 c898ac98 c898ab49 c898c018 00001970 9f60: 00001b60 00000000 00000000 00000000 0000001f 00000020 00000017 00000000 9f80: 00000011 00000000 00000000 beb60f45 000b8008 000b8018 00000080 c000a444 9fa0: c79e8000 c000a2c0 beb60f45 000b8008 000b8018 00003545 000b8008 00000000 9fc0: beb60f45 000b8008 000b8018 00000080 000b669c 00000000 b6fa0f70 00000000 9fe0: b6f4c3c8 beb60c94 0001c994 b6f4c3d8 a0000010 000b8018 00000000 00000000 [<c00148d8>] (__pci_addr.isra.1) from [<c001498c>] (versatile_read_config+0x1c/0xb8) [<c001498c>] (versatile_read_config) from [<c017efb0>] (pci_bus_read_config_word+0x4c/0x60) [<c017efb0>] (pci_bus_read_config_word) from [<bf000c08>] (test_pci_probe+0x1d8/0x558 [test _pci_driver]) [<bf000c08>] (test_pci_probe [test_pci_driver]) from [<c01883a4>] (pci_device_probe+0x74/0x c8) [<c01883a4>] (pci_device_probe) from [<c01cbd48>] (driver_probe_device+0x124/0x2c0) [<c01cbd48>] (driver_probe_device) from [<c01cbf70>] (__driver_attach+0x8c/0x90) [<c01cbf70>] (__driver_attach) from [<c01ca470>] (bus_for_each_dev+0x70/0xa0) [<c01ca470>] (bus_for_each_dev) from [<c01cb5b4>] (bus_add_driver+0x188/0x210) [<c01cb5b4>] (bus_add_driver) from [<c01cc730>] (driver_register+0x78/0xf8) [<c01cc730>] (driver_register) from [<c0009604>] (do_one_initcall+0x80/0x1e0) [<c0009604>] (do_one_initcall) from [<c02cf920>] (do_init_module+0x58/0x1b4) [<c02cf920>] (do_init_module) from [<c0056768>] (load_module+0x18f0/0x1cf4) [<c0056768>] (load_module) from [<c0056c38>] (SyS_init_module+0xcc/0x124) [<c0056c38>] (SyS_init_module) from [<c000a2c0>] (ret_fast_syscall+0x0/0x38) Code: e1801401 e1810002 e28004e9 e12fff1e (e7f001f2) ---[ end trace d58ace19ffed3147 ]--- Segmentation fault # main-loop: WARNING: I/O thread spun for 1000 iterations
、、、
ケアレスミスがいくつか合ったけど、無事ロードができた。
# insmod test_pci_driver.ko test_pci 0000:00:0d.0: enabling device (0100 -> 0103) *** /home/embryo/workspa(321) test_pci_probe: PCI enabled for test_pci *** /home/embryo/workspa(327) test_pci_probe: mmio_base: 50002000, mmio_length: 1000, mmio_flags: 40200 *** /home/embryo/workspa(346) test_pci_probe: pio_base: 1400, pio_length: 100, pio_flags: 40101 *** /home/embryo/workspa(361) test_pci_probe: PCI Vendor ID: fefe, Device ID: 1 *** /home/embryo/workspa(366) test_pci_probe: success allocate I/O region *** /home/embryo/workspa(369) test_pci_probe: device irq: 94 *** /home/embryo/workspa(400) test_pci_probe: test_pci driver(major 253) installed. *** /home/embryo/workspa(420) test_pci_probe: cdma_addr: 7886000
後は、アプリを作ってアクセスしてみよう!