読者です 読者をやめる 読者になる 読者になる

明日にはでっかい太陽が昇るかもしれません。

「覚悟」とは!! 暗闇の荒野に!!進むべき道を切り開く事だッ!

Qemu を使いこなすために

組み込みを仕事にしているため、よく機材不足や新規基盤の開発遅れなどのトラブルが起きます。

そこで、Qemu を活用できればと思っていたところに良い記事が見つかったので写経してみました。

qiita.com

ところが、ドライバの作成でコンパイルエラーが発生!!

ハードとして 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 依存部分に問題があるらしい。

と思ったら、 ARCHCROSS_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

後は、アプリを作ってアクセスしてみよう!