이번에는 primary_entry함수 안에 있는 set_cpu_boot_mode_flag 함수에 대해서 알아보겠다.

/*
 * Sets the __boot_cpu_mode flag depending on the CPU boot mode passed
 * in w0. See arch/arm64/include/asm/virt.h for more info.
 */
SYM_FUNC_START_LOCAL(set_cpu_boot_mode_flag)
	adr_l	x1, __boot_cpu_mode
	cmp	w0, #BOOT_CPU_MODE_EL2
	b.ne	1f
	add	x1, x1, #4
1:	str	w0, [x1]			// This CPU has booted in EL1
	dmb	sy
	dc	ivac, x1			// Invalidate potentially stale cache line
	ret
SYM_FUNC_END(set_cpu_boot_mode_flag)

일단 이 함수는 w0에 (첫번째 register를 의미하며, 32bit만 읽고 싶을때는 w0, 64bit를 모두 읽고 싶을 때는 x0로 읽어 올 수 있다.) 현재 CPU에서 동작하는 Exception Level이 인자로 전달되었다고 가정한다.

결론 부터 이야기 하면 이 함수의 목적은, 커널이 소유하고있는 CPU들이 같은 Exception Level에서 부팅되었음을 확인하고자 만들어졌으며, 알고리즘은 쓰고 같은지 확인 이다.

 

__boot_cpu_mode 배열은 아래와 같이 선언되었다고 했을 때, 이 함수를 수행하고 있는 CPU가 EL1에서 booting되었다고 한다면, 함수는 아래 배열에서 첫번째 index에 BOOT_CPU_MODE_EL1 값을 쓸 것이며, 결과로는 배열의 element들이 모두 같은 값을 갖게 될 것이다. 반대로 CPU가 EL2에서 booting되었다고 한다면, 함수는 아래 배열에서 두 번째 index에 BOOT_CPU_MODE_EL2 값을 쓸것이고, 배열의 모든 element들이 모두 같은 값을 갖게된다.

/*
 * We need to find out the CPU boot mode long after boot, so we need to
 * store it in a writable variable.
 *
 * This is not in .bss, because we set it sufficiently early that the boot-time
 * zeroing of .bss would clobber it.
 */
SYM_DATA_START(__boot_cpu_mode)
	.long	BOOT_CPU_MODE_EL2
	.long	BOOT_CPU_MODE_EL1
SYM_DATA_END(__boot_cpu_mode)

이는 boot CPU 이후에 secondary CPU들에 대해서도 booting exception level에 따라 배열의 element에 값을 쓰고 배열의 element들이 같은 값을 유지하고 있는지 여부에 따라 모든 CPU들의 booting exception level들이 같은 level에서 부팅되었는지 다른 level을 갖고 부팅 되었는지를 확인할 수 있게 된다.

  • dc ivac, x1:이 함수가 호출 되었을 때는 아직 CPU의 dcache가 활성화 되어있지 않은 상태로써, dcache에 배열의 주소에 해당하는 data가 있다면 나중에 예기치 못한 상황이 생길 수도있어서, 해당 배열에 대해서 dcache invalidation operation을 해주고 있다.

 

+ Recent posts