ARM Cortex-M7マイコンでキャッシュを使えるようにするためにいろいろ頑張っています。
現在のLinux Kernelでは、アーキテクチャとしてARMv7Mが選択されると同時にCPU_CACHE_NOPが選択*1され、キャッシュを制御するコードとしてarch/arm/mm/cache-nop.S内のコードが利用されるようになっています*2。 このcache-nop.Sにはキャッシュを持たないマイコンのため、キャッシュを操作するための処理として「何もしない(NOP)」というコードが書かれています。 一方、今回対象としているARM Cortex-M7はキャッシュを持つため、このキャッシュを利用するためにはきちんとキャッシュの処理をするコードを書いてあげなければいけません。
さて、このcache-nop.S内の関数はどこでキャッシュを操作する関数として登録されているか調べてみると、proc-v7m.Sにproc_info_list構造体というものがあり、ここのcacheというメンバにセットするとキャッシュを操作する関数として登録されるようです。 以下、proc-v7m.Sの該当部分を引用します。
/* * Match any ARMv7-M processor core. */ .type __v7m_proc_info, #object __v7m_proc_info: .long 0x000f0000 @ Required ID value .long 0x000f0000 @ Mask for ID .long 0 @ proc_info_list.__cpu_mm_mmu_flags .long 0 @ proc_info_list.__cpu_io_mmu_flags initfn __v7m_setup, __v7m_proc_info @ proc_info_list.__cpu_flush .long cpu_arch_name .long cpu_elf_name .long HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT .long cpu_v7m_name .long v7m_processor_functions @ proc_info_list.proc .long 0 @ proc_info_list.tlb .long 0 @ proc_info_list.user .long nop_cache_fns @ proc_info_list.cache .size __v7m_proc_info, . - __v7m_proc_info
ここでproc_info_list.cacheに定義されているnop_cache_fnsシンボルの中身はどこにあるか調べるためgrepをかけてみると、以下のようにproc-v7m.SとSystem.mapにシンボル名は見つかりますが、中身は見つかりません。
$ grep -R "nop_cache_fns" ./ ./arch/arm/mm/proc-v7m.S: .long nop_cache_fns @ proc_info_list.cache Binary file ./arch/arm/mm/cache-nop.o matches Binary file ./arch/arm/mm/proc-v7m.o matches Binary file ./arch/arm/mm/built-in.o matches Binary file ./vmlinux.o matches Binary file ./.tmp_vmlinux1 matches Binary file ./.tmp_vmlinux2 matches Binary file ./vmlinux matches ./System.map:c0128ea0 T nop_cache_fns ./.tmp_System.map:c0128ea0 T nop_cache_f
さっぱりわからないのでcache-nop.Sをじっくり眺めていたところ、以下のような記述を発見しました。
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions nop
define_cache_functionsはマクロっぽいので、コメントに従ってarch/arm/mm/proc-macros.Sを開いてみると、ビンゴでした。 マクロの定義は以下のようになっており、name部分に設定した名前と_cache_fnsを連結した名前の構造体を作るようになっているようです。 上記の例ではnopがセットされているので、nop_cache_fnsという名前の構造体がこのマクロによって作られることなります。
.macro define_cache_functions name:req .align 2 .type \name\()_cache_fns, #object ENTRY(\name\()_cache_fns) .long \name\()_flush_icache_all .long \name\()_flush_kern_cache_all .long \name\()_flush_kern_cache_louis .long \name\()_flush_user_cache_all .long \name\()_flush_user_cache_range .long \name\()_coherent_kern_range .long \name\()_coherent_user_range .long \name\()_flush_kern_dcache_area .long \name\()_dma_map_area .long \name\()_dma_unmap_area .long \name\()_dma_flush_range .size \name\()_cache_fns, . - \name\()_cache_fns .endm
ちなみにnop_cache_fnsの型はcpu_cache_fnsであり、arch/arm/include/asm/cacheflush.hに定義されています。
とりあえず、以上です。