Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

블로그

__inval_dcache_area 본문

linux_kernel/head.S

__inval_dcache_area

ledel 2019. 8. 25. 11:31

kernel v5.1 (arch/arm64/mm/cache.S)

 

__inval_dcache_area는 특정 메모리 영역에 해당하는 cache line을 무효화 하는 프로시저이다.

__inval_dcache_area는 입력된 주소가 캐시라인에 대하여 정렬되어있지 않더라도 모든 주소에 해당하는 캐시라인을

무효화 한다.

/*
 *	__inval_dcache_area(kaddr, size)
 *
 * 	Ensure that any D-cache lines for the interval [kaddr, kaddr+size)
 * 	are invalidated. Any partial lines at the ends of the interval are
 *	also cleaned to PoC to prevent data loss.
 *
 *	- kaddr   - kernel address
 *	- size    - size in question
 */
ENTRY(__inval_dcache_area)
	/* FALLTHROUGH */

/*
 *	__dma_inv_area(start, size)
 *	- start   - virtual start address of region
 *	- size    - size in question
 */
__dma_inv_area:
	add	x1, x1, x0
	dcache_line_size x2, x3
	sub	x3, x2, #1
	tst	x1, x3				// end cache line aligned?
	bic	x1, x1, x3
	b.eq	1f
	dc	civac, x1			// clean & invalidate D / U line
1:	tst	x0, x3				// start cache line aligned?
	bic	x0, x0, x3
	b.eq	2f
	dc	civac, x0			// clean & invalidate D / U line
	b	3f
2:	dc	ivac, x0			// invalidate D / U line
3:	add	x0, x0, x2
	cmp	x0, x1
	b.lo	2b
	dsb	sy
	ret
ENDPIPROC(__inval_dcache_area)
ENDPROC(__dma_inv_area)

__inval_dcache_area는 X0레지스터를 통하여 무효화 할 시작 주소값을, X1레지스터를 통하여 시작 주소로 부터 무효화 할 크기를 인자로 받는다.

 

add	x1, x1, x0

크기와 시작 주소를 더하여 X1레지스터가 무효화 할 영역의 끝 주소를 가지도록 한다.

dcache_line_size x2, x3

다음은 D-cache의 cache line 크기를 가져오는 매크로이다. x2에 캐시 라인 크기가 저장이 되며, x3은 임시 레지스터로 쓰인다.

cache line size가 64바이트라고 가정을 하고 설명을 하도록 하겠다.

64는 이진법으로 나타내면 1000000 이다.

sub	x3, x2, #1

X2레지스터의 값에서 1을 뺀 값을 X3레지스터에 저장을 한다. X2레지스터가 64인 경우, X3레지스터는 이진법으로 111111, 십진법으로는 63이다.

X3는 입력된 주소 값이 cache line 크기에 대해서 정렬이 되어 있는지를 판단하기 위해서 사용된다

tst	x1, x3  

X1레지스터(끝 주소 값)과 X3레지스터(111111)를 AND연산을 한 후 결과는 버리며, 결과에 따라 N(Negative)과 Z(Zero)플래그를 업데이트 한다.(참고: PSTATE)

만약 정렬 할 주소의 시작 주소가 cache line에 정렬이 되어 있다면, tst를 하였을 때 Z플래그가 1일 것이고

정렬이 되어 있지 않다면, Z플래그가 0일 것이다.

두 가지 상황을 그림으로 나타내면 다음과 같다

cache line에 대해서 정렬되어 있지 않은 경우
cache line에 대해서 정렬이 된 경우

bic	x1, x1, x3

X1레지스터에서(끝 주소) X3레지스터에 세팅된 비트( 글에서는 ..... 0011 1111 :1인 부분)를 0으로 만든다.

만약 끝 주소가 정렬이 되어 있다면(위 tst명령에서 Z플래그가 1인 경우) 값에 변화가 없을 것이다.

만약 끝 주소가 정렬이 되어 있지 않다면 아래쪽으로 가장 가까운 정렬된 주소로 만든다.

cache line에 대해서 정렬이 되지 않은 경우 bic연산을 하면 다음과 같이 값이 변경된다.

 

b.eq	1f

b.eq는 Z플래그가 1인 경우 branch를 한다. 즉 끝 주소가 정렬이 된 경우는 아래쪽의 라벨 1로 jump를 한다.

dc	civac, x1

x1이 캐시 라인에 걸쳐있는 경우, dc civac, x1 명령어로 x1이 포함되는 cache line을 clean하고 invalidate한다.

1:	tst	x0, x3	
bic	x0, x0, x3
b.eq	2f
dc	civac, x0			// clean & invalidate D / U line
b	3f

끝 주소에 대해서 계산을 한 것과 마찬가지로 시작 주소에 대해서도 캐시 라인에 대해서 정렬이 되어 있는지 확인을 한 후, 정렬이 되어 있지 않는 경우에는

시작 주소가 포함된 cache라인을 clean & invalidate하고 정렬이 되어 있는 경우에는 건너뛴다.

1:	tst	x0, x3	
bic	x0, x0, x3
b.eq	2f
dc	civac, x0			// clean & invalidate D / U line
b	3f
2:	dc	ivac, x0			// invalidate D / U line
3:	add	x0, x0, x2
cmp	x0, x1
b.lo	2b

X0 레지스터가 시작 주소인 경우 시작 주소가 정렬이 되어 있어서 건너 뛰었다면, 시작 주소의 cache line을 invalidate한다.

그리고 시작 주소에서 cache line 크기 만큼을 더한다.

X0 레지스터가 시작 주소이며, 정렬이 되어 있지 않았다면, 시작 주소에 해당하는 부분의 cache line을 clean & invalidate하였으므로,

바로 시작 주소에 cache line 크기 만큼을 더한다.

2:	dc	ivac, x0			// invalidate D / U line
3:	add	x0, x0, x2
cmp	x0, x1
b.lo	2b
dsb	sy
ret

시작 주소로 부터 cache line 크기 만큼씩 증가를 하면서 invalidate할 끝 주소까지 계속 cache line을 invalidate한다

그리고 나서 barrier를 통하여 위의 모든 작업이 완료 되고 나서 다음 명령이 실행되도록 한다.

 

아래의 더보기를 누르면 문c블로그의 barrier명령어에 대한 설명을 확인할 수 있다.

...더보기

DSB(Data Synchronization Barrier, called DWB)

  • 아래의 항목들(DMB 명령이 하는일 포함)이 완료될 때까지 추가 명령이 실행되는 것을 멈추고 기다리므로 DMB보다 훨씬 느리다. 인수의 사용은 DMB와 동일하다.
    • Instruction 캐시 및 Data 캐시 조작
    • Branch predictor 캐시 flush
    • 지연된 load/store 명령의 처리 <- DMB 명령이 하는 일
    • TLB 캐시 조작 완료

출처: http://jake.dothome.co.kr/barriers/     

         (문c 블로그)

'linux_kernel > head.S' 카테고리의 다른 글

preserve_boot_args  (0) 2019.08.11
Comments