- compressed/head.S 에서 사용하였던 __armv7_mmu_cache_flush: 루틴과 거의 동일하다.
- 데이터 캐시를 지우라고 요청하면 SoC 정보를 확인하여 지원하는 최종 캐시레벨을 확인한 후 L1 부터 해당 캐시 레벨까지 flush한다.
- 해당 캐시 레벨에서는 index와 way를 사용하여 하나씩 삭제한다.
hierarchical cache
- ARMv6 아키텍처까지는 ARM 아키텍처에서 L1 캐시만 지원하였었다.
- ARMv7 아키텍처부터 다단계의 캐시를 지원하게되었다.
- 다단계 캐시, ARM에서는 hierarchical cache 구조 라고 한다.
v7_flush_dcache_louis()
arch/arm/mm/cache-v7.S
01 | /* |
02 | * v7_flush_dcache_louis() |
03 | * |
04 | * Flush the D-cache up to the Level of Unification Inner Shareable |
05 | * |
06 | * Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode) |
07 | */ |
08 |
09 | ENTRY(v7_flush_dcache_louis) |
10 | dmb @ ensure ordering with previous memory accesses |
11 | mrc p15, 1, r0, c0, c0, 1 @ read clidr, r0 = clidr |
12 | ALT_SMP(ands r3, r0, #(7 << 21)) @ extract LoUIS from clidr |
13 | ALT_UP(ands r3, r0, #(7 << 27)) @ extract LoUU from clidr |
14 | #ifdef CONFIG_ARM_ERRATA_643719 |
15 | ALT_SMP(mrceq p15, 0, r2, c0, c0, 0) @ read main ID register |
16 | ALT_UP(reteq lr) @ LoUU is zero, so nothing to do |
17 | ldreq r1, =0x410fc090 @ ID of ARM Cortex A9 r0p? |
18 | biceq r2, r2, #0x0000000f @ clear minor revision number |
19 | teqeq r2, r1 @ test for errata affected core and if so... |
20 | orreqs r3, #(1 << 21) @ fix LoUIS value (and set flags state to 'ne' ) |
21 | #endif |
22 | ALT_SMP(mov r3, r3, lsr #20) @ r3 = LoUIS * 2 |
23 | ALT_UP(mov r3, r3, lsr #26) @ r3 = LoUU * 2 |
24 | reteq lr @ return if level == 0 |
25 | mov r10, #0 @ r10 (starting level) = 0 |
26 | b flush_levels @ start flushing cache levels |
27 | ENDPROC(v7_flush_dcache_louis) |
- mrc p15, 1, r0, c0, c0, 1
- LoUU/LoUIS를 추출하기 위해 CLIDR을 읽어온다.
- ALT_SMP(ands r3, r0, #(7 << 21))
- SMP 시스템에서 CLIDR의 LoUIS 필드를 추출해온다.
- ERRATA_643719
- 특정 프로세서의 CLIDR.LOUIS가 잘못 기록이 되어 있어서 이를 보정해주는 코드
- Cortex-A9 r1p0 이전 버전에서 LoUIS 값이 1이 아닌 0으로 기록된 것을 잡아준다.
- ALT_SMP(mov r3, r3, lsr #20)
- r3: 읽어온 값을 우측으로 쉬프트하여 LoUIS x 2와 같은 값으로 만든다.
- d-cache를 어느 캐시 레벨까지 flush할지 결정하기 위함.
- r3: 읽어온 값을 우측으로 쉬프트하여 LoUIS x 2와 같은 값으로 만든다.
- reteq lr
- 읽어온 LoUIS가 0이면 d-cache의 flush를 포기하고 루틴을 빠져나간다.
- mov r10, #0
- 시작 캐시 레벨을 0(L1)부터 준비한다.
- b flush_levels
- v7_flush_dcache_all() 루틴 중간에 있는 flush_levels 레이블을 같이 사용한다.
v7_flush_dcache_all()
01 | /* |
02 | * v7_flush_dcache_all() |
03 | * |
04 | * Flush the whole D-cache. |
05 | * |
06 | * Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode) |
07 | * |
08 | * - mm - mm_struct describing address space |
09 | */ |
10 | ENTRY(v7_flush_dcache_all) |
11 | dmb @ ensure ordering with previous memory accesses |
12 | mrc p15, 1, r0, c0, c0, 1 @ read clidr |
13 | ands r3, r0, #0x7000000 @ extract loc from clidr |
14 | mov r3, r3, lsr #23 @ left align loc bit field |
15 | beq finished @ if loc is 0, then no need to clean |
16 | mov r10, #0 @ start clean at cache level 0 |
01 | flush_levels: |
02 | add r2, r10, r10, lsr #1 @ work out 3x current cache level |
03 | mov r1, r0, lsr r2 @ extract cache type bits from clidr |
04 | and r1, r1, #7 @ mask of the bits for current cache only |
05 | cmp r1, #2 @ see what cache we have at this level |
06 | blt skip @ skip if no cache, or just i-cache |
07 | #ifdef CONFIG_PREEMPT |
08 | save_and_disable_irqs_notrace r9 @ make cssr&csidr read atomic |
09 | #endif |
10 | mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr |
11 | isb @ isb to sych the new cssr&csidr |
12 | mrc p15, 1, r1, c0, c0, 0 @ read the new csidr |
13 | #ifdef CONFIG_PREEMPT |
14 | restore_irqs_notrace r9 |
15 | #endif |
16 | and r2, r1, #7 @ extract the length of the cache lines |
17 | add r2, r2, #4 @ add 4 (line length offset) |
18 | ldr r4, =0x3ff |
19 | ands r4, r4, r1, lsr #3 @ find maximum number on the way size |
20 | clz r5, r4 @ find bit position of way size increment |
21 | ldr r7, =0x7fff |
22 | ands r7, r7, r1, lsr #13 @ extract max number of the index size |
23 | loop1: |
24 | mov r9, r7 @ create working copy of max index |
25 | loop2: |
26 | ARM( orr r11, r10, r4, lsl r5 ) @ factor way and cache number into r11 |
27 | THUMB( lsl r6, r4, r5 ) |
28 | THUMB( orr r11, r10, r6 ) @ factor way and cache number into r11 |
29 | ARM( orr r11, r11, r9, lsl r2 ) @ factor index number into r11 |
30 | THUMB( lsl r6, r9, r2 ) |
31 | THUMB( orr r11, r11, r6 ) @ factor index number into r11 |
32 | mcr p15, 0, r11, c7, c14, 2 @ clean & invalidate by set/way |
33 | subs r9, r9, #1 @ decrement the index |
34 | bge loop2 |
35 | subs r4, r4, #1 @ decrement the way |
36 | bge loop1 |
37 | skip: |
38 | add r10, r10, #2 @ increment cache number |
39 | cmp r3, r10 |
40 | bgt flush_levels |
41 | finished: |
42 | mov r10, #0 @ swith back to cache level 0 |
43 | mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr |
44 | dsb st |
45 | isb |
46 | ret lr |
47 | ENDPROC(v7_flush_dcache_all) |
- decompressed/head.S에서 d-cache를 flush한 로직과 거의 흡사하다.
- way와 index 루프 순서만 기존과 바뀌었다.