요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
==========================================================================
Interface for registering and calling firmware-specific operations for ARM
==========================================================================
Written by Tomasz Figa <[email protected]>
Some boards are running with secure firmware running in TrustZone secure
world, which changes the way some things have to be initialized. This makes
a need to provide an interface for such platforms to specify available firmware
operations and call them when needed.
Firmware operations can be specified by filling in a struct firmware_ops
with appropriate callbacks and then registering it with register_firmware_ops()
function::
void register_firmware_ops(const struct firmware_ops *ops)
The ops pointer must be non-NULL. More information about struct firmware_ops
and its members can be found in arch/arm/include/asm/firmware.h header.
There is a default, empty set of operations provided, so there is no need to
set anything if platform does not require firmware operations.
To call a firmware operation, a helper macro is provided::
#define call_firmware_op(op, ...) \
((firmware_ops->op) ? firmware_ops->op(__VA_ARGS__) : (-ENOSYS))
the macro checks if the operation is provided and calls it or otherwise returns
-ENOSYS to signal that given operation is not available (for example, to allow
fallback to legacy operation).
Example of registering firmware operations::
/* board file */
static int platformX_do_idle(void)
{
/* tell platformX firmware to enter idle */
return 0;
}
static int platformX_cpu_boot(int i)
{
/* tell platformX firmware to boot CPU i */
return 0;
}
static const struct firmware_ops platformX_firmware_ops = {
.do_idle = exynos_do_idle,
.cpu_boot = exynos_cpu_boot,
/* other operations not available on platformX */
};
/* init_early callback of machine descriptor */
static void __init board_init_early(void)
{
register_firmware_ops(&platformX_firmware_ops);
}
Example of using a firmware operation::
/* some platform code, e.g. SMP initialization */
__raw_writel(__pa_symbol(exynos4_secondary_startup),
CPU1_BOOT_REG);
/* Call Exynos specific smc call */
if (call_firmware_op(cpu_boot, cpu) == -ENOSYS)
cpu_boot_legacy(...); /* Try legacy way */
gic_raise_softirq(cpumask_of(cpu), 1);
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
Interface for registering and calling firmware-specific operations for ARM
1-11Tomasz Figa가 작성했습니다. 일부 board는 TrustZone secure world에서 secure firmware를 실행하며, 이 때문에 몇몇 초기화 방식이 달라집니다. 이런 platform이 사용 가능한 firmware operation을 지정하고 필요할 때 호출할 interface가 필요합니다.
Registering firmware operations
12-23적절한 callback으로 `struct firmware_ops`를 채운 뒤 `register_firmware_ops()`에 전달해 firmware operation을 등록합니다.
void register_firmware_ops(const struct firmware_ops *ops)
`ops` pointer는 non-NULL이어야 합니다. `struct firmware_ops`와 member의 자세한 정의는 `arch/arm/include/asm/firmware.h`에 있습니다.
기본값으로 비어 있는 operation set이 제공되므로 platform에 firmware operation이 필요하지 않다면 아무것도 설정할 필요가 없습니다.
Calling firmware operations
24-32firmware operation 호출에는 helper macro를 사용합니다.
#define call_firmware_op(op, ...) \
((firmware_ops->op) ? firmware_ops->op(__VA_ARGS__) : (-ENOSYS))
`call_firmware_op(op, ...)`는 해당 operation callback이 있는지 검사해 호출합니다. 없다면 `-ENOSYS`를 반환해 operation을 사용할 수 없음을 알리며, 예를 들어 legacy operation으로 fallback할 수 있게 합니다.
Registration and call examples
33-72board file은 idle 진입과 secondary CPU boot callback을 구현하고 `platformX_firmware_ops`에 연결합니다. machine descriptor의 `init_early` callback에서 이 operation set을 등록합니다.
/* board file */
static int platformX_do_idle(void)
{
/* tell platformX firmware to enter idle */
return 0;
}
static int platformX_cpu_boot(int i)
{
/* tell platformX firmware to boot CPU i */
return 0;
}
static const struct firmware_ops platformX_firmware_ops = {
.do_idle = exynos_do_idle,
.cpu_boot = exynos_cpu_boot,
/* other operations not available on platformX */
};
/* init_early callback of machine descriptor */
static void __init board_init_early(void)
{
register_firmware_ops(&platformX_firmware_ops);
}
platform code는 secondary startup address를 `CPU1_BOOT_REG`에 쓰고 `call_firmware_op(cpu_boot, cpu)`를 호출합니다. 결과가 `-ENOSYS`이면 `cpu_boot_legacy(...)`로 fallback한 뒤 `gic_raise_softirq()`로 target CPU에 interrupt를 보냅니다.
/* some platform code, e.g. SMP initialization */
__raw_writel(__pa_symbol(exynos4_secondary_startup),
CPU1_BOOT_REG);
/* Call Exynos specific smc call */
if (call_firmware_op(cpu_boot, cpu) == -ENOSYS)
cpu_boot_legacy(...); /* Try legacy way */
gic_raise_softirq(cpumask_of(cpu), 1);
요약과 해설
firmware.rst:1-72platform-specific secure firmware 차이를 공통 `struct firmware_ops` 뒤로 숨깁니다. 등록하지 않은 callback은 `-ENOSYS`로 명확히 구분되므로 호출자는 firmware 경로와 legacy 경로를 안전하게 함께 지원할 수 있습니다.
등록된 callback 여부가 secure firmware와 legacy 구현 사이의 선택점입니다.