linux : psci
TRANSCRIPT
Linux : PSCI
2016/5/7(土)、作成2016/11/19 (土)、追記
@Vengineer
PSCIとは
PSCIは、POWER STATE COORDINATION INTERFACE の略
ARMv8(ARM64)では、多くのSoCがPSCIをサポートしている
参考資料"Power State Coordination Interface System Software on ARM processors"http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/
LinuxのDevice Tree Bindinghttps://www.kernel.org/doc/Documentation/devicetree/bindings/arm/psci.txt
cpuノードのenable-methodプロパティ
http://lxr.free-electrons.com/source/Documentation/devicetree/bindings/arm/cpus.txt
- enable-method Value type: <stringlist> Usage and definition depend on ARM architecture version. # On ARM v8 64-bit this property is required and must be one of:
"psci" "spin-table" - cpu-release-addr Usage: required for systems that have an "enable-method" property value of "spin-table". Value type: <prop-encoded-array> Definition: # On ARM v8 64-bit systems must be a two cell property identifying a 64-bit zero-initialised memory location.
psciの例 : Hisilicon 6220 (HiKey)http://lxr.free-electrons.com/source/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
cpu0: cpu@0 { compatible = "arm,cortex-a53", "arm,armv8"; device_type = "cpu"; reg = <0x0 0x0>;
enable-method = "psci"; };
追記)、2016.11.19 DragonBoard 410cでも、Linaro Debian 16.09からPSCIをサポート
spin-tableの例 : APM X-Gene SoChttp://lxr.free-electrons.com/source/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi
cpu0: cpu@0 { compatible = apm,strega", "arm,armv8"; device_type = "cpu"; reg = <0x0 0x000>;
enable-method = "spin-table"; cpu-release-addr = <0x1 0x0000fff8>; ext-level-cache = <&xgene_L2_0>; };
spin-tableの例 : Raspberry Pi3
h追記)、2016.11.19 Raspberry Pi3は、Linux 4.8でサポートされたが ”spin-table”
arch/arm64/boot/dts/broadcom/bcm2837.dtsi
参考資料)、 2016年11月号、第2章
なるほどそうやって動くのか!リセット直後から丸はだか!
完全理解! ラズベリー・パイの32/64ビットLinux起動シーケンス
原山 みや
http://www.kumikomi.net/interface/sample/201611/if11_037.pdf
enable-methodプロパティのチェック
http://lxr.free-electrons.com/source/arch/arm64/kernel/cpu_ops.c
static const char *__init cpu_read_enable_method(int cpu) { struct device_node *dn = of_get_cpu_node(cpu, NULL);
enable_method = of_get_property(dn, "enable-method", NULL); if (!enable_method) { /* The boot CPU may not have an enable method (e.g. * when spin-table is used for secondaries). * Don't warn spuriously. */ if (cpu != 0) pr_err("%s: missing enable-method property\n", dn->full_name); }}
pscihttp://lxr.free-electrons.com/source/arch/arm64/kernel/psci.c
const struct cpu_operations cpu_psci_ops = { .name = "psci",#ifdef CONFIG_CPU_IDLE .cpu_init_idle = cpu_psci_cpu_init_idle, .cpu_suspend = cpu_psci_cpu_suspend,#endif .cpu_init = cpu_psci_cpu_init, .cpu_prepare = cpu_psci_cpu_prepare, .cpu_boot = cpu_psci_cpu_boot,#ifdef CONFIG_HOTPLUG_CPU .cpu_disable = cpu_psci_cpu_disable, .cpu_die = cpu_psci_cpu_die, .cpu_kill = cpu_psci_cpu_kill,#endif};
サスペンドをサポート
ホットプラグをサポート
spin_tablehttp://lxr.free-electrons.com/source/arch/arm64/kernel/smp_spin_table.c
const strucsmp_spin_table.ct cpu_operations smp_spin_table_ops = { .name = "spin-table", .cpu_init = smp_spin_table_cpu_init, .cpu_prepare = smp_spin_table_cpu_prepare, .cpu_boot = smp_spin_table_cpu_boot,};
サスペンドにも、ホットプラグもサポートしていない。
.cpu_init_idle = NULL, .cpu_suspend = NULL, .cpu_disable = NULL, .cpu_die = NULL, .cpu_kill = NULL,
drivers/firmware/psci.c (Linux 4.3〜
static u32 psci_get_version(void){
return invoke_psci_fn(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0);}
drivers/firmware/psci.c (Linux 4.3〜
static int psci_cpu_suspend(u32 state, unsigned long entry_point){ int err; u32 fn;
fn = psci_function_id[PSCI_FN_CPU_SUSPEND];
err = invoke_psci_fn(fn, state, entry_point, 0); return psci_to_linux_errno(err);}
drivers/firmware/psci.c (Linux 4.3〜
static void psci_sys_reset(enum reboot_mode reboot_mode, const char *cmd){
invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0);}
static void psci_sys_poweroff(void)1{
invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);}
drivers/firmware/psci.c (Linux 4.3〜static int psci_system_suspend(unsigned long unused){
return invoke_psci_fn( PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND), virt_to_phys(cpu_resume), 0, 0);}
static int psci_system_suspend_enter(suspend_state_t state){ return cpu_suspend(0, psci_system_suspend);}
drivers/firmware/psci.c (Linux 4.3〜static int get_set_conduit_method(struct device_node *np){ if (of_property_read_string(np, "method", &method)) { pr_warn("missing \"method\" property\n"); return -ENXIO; }
if (!strcmp("hvc", method)) {
invoke_psci_fn = __invoke_psci_fn_hvc; } else if (!strcmp("smc", method)) {
invoke_psci_fn = __invoke_psci_fn_smc; }
drivers/firmware/psci.c (Linux 4.3〜
static unsigned long __invoke_psci_fn_smc( unsigned long function_id, unsigned long arg0, unsigned long arg1, unsigned long arg2){ struct arm_smccc_res res;
arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); return res.a0;}
arch/arm64/kernel/smccc-call.S
/* * void arm_smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5, unsigned long a6, unsigned long a7, struct arm_smccc_res *res)*/
ENTRY(arm_smccc_smc) SMCCC smcENDPROC(arm_smccc_smc)
arch/arm64/kernel/smccc-call.S
.macro SMCCC instr .cfi_startproc \instr #0 ldr x4, [sp] stp x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS] stp x2, x3, [x4, #ARM_SMCCC_RES_X2_OFFS] ret .cfi_endproc
.endm
LinuxからATFへはどのように伝える?
http://lxr.free-electrons.com/source/arch/arm64/kernel/smccc-call.S
・SMC (Secure Monitor Call) を使う http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0204ij/Cjaeeged.html
/* * void arm_smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2, * unsigned long a3, unsigned long a4, unsigned long a5, * unsigned long a6, unsigned long a7, struct arm_smccc_res *res) */ENTRY(arm_smccc_smc) SMCCC smc /* SMCCC は、このファイル(smccc-call.S内でマクロ定義されてい
る)*/ENDPROC(arm_smccc_smc)
EL3 Runtime Service
https://github.com/ARM-software/arm-trusted-firmware/blob/master/docs/rt-svc-writers-guide.md
Software executing in the normal world and in the trusted world at exception levels lower than EL3 will request runtime services using the Secure Monitor Call (SMC) instruction. These requests will follow the convention described in the SMC Calling Convention PDD (SMCCC). The SMCCC assigns function identifiers to each SMC request and describes how arguments are passed and results are returned.
・Standard Service calls => 標準サービスの提供 ( PSCI )
・SiP Service calls => 各社独自サービス用
Standard Service calls
https://github.com/ARM-software/arm-trusted-firmware/blob/master/services/std_svc/std_svc_setup.c
/* Register Standard Service Calls as runtime service */DECLARE_RT_SVC(
std_svc,
OEN_STD_START,OEN_STD_END,SMC_TYPE_FAST,
std_svc_setup,std_svc_smc_handler
);
std_svc_smc_handler
https://github.com/ARM-software/arm-trusted-firmware/blob/master/services/std_svc/std_svc_setup.c
/* Top-level Standard Service SMC handler. This handler will in turn dispatch calls to PSCI SMC handler */
uint64_t std_svc_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4,
void *cookie, void *handle, uint64_t flags){
/* Dispatch PSCI calls to PSCI SMC handler and return its return value */if (is_psci_fid(smc_fid)) {
return psci_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);}
psci_smc_handler
https://github.com/ARM-software/arm-trusted-firmware/blob/master/services/std_svc/psci/psci_main.c
uint64_t psci_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4,
void *cookie, void *handle, uint64_t flags)
switch (smc_fid) {case PSCI_CPU_SUSPEND_AARCH64: SMC_RET1(handle, psci_cpu_suspend(x1, x2, x3));case PSCI_CPU_ON_AARCH64: SMC_RET1(handle, psci_cpu_on(x1, x2, x3));case PSCI_AFFINITY_INFO_AARCH64: SMC_RET1(handle, psci_affinity_info(x1, x2));case PSCI_MIG_AARCH64: SMC_RET1(handle, psci_migrate(x1));case PSCI_MIG_INFO_UP_CPU_AARCH64:SMC_RET1(handle, psci_migrate_info_up_cpu());case PSCI_SYSTEM_SUSPEND_AARCH64: SMC_RET1(handle, psci_system_suspend(x1, x2));default:break;
}
Power Off / Reboot / System Suspend
User Landから
・Power Off ・Reboot ・System Suspend
を実行した場合、どのような関数を経由して、PSCIにアクセスするのか?
System Halt (Power Off)
SYSCALL_DEFINE4(reboot, kernel/reboot.ckernel_restart kernel/reboot.cmachine_restart arch/arm64/kernel/process.carm_pm_restart arch/arm64/kernel/process.cpsci_sys_reset drivers/firmware/psci.cinvoke_psci_fn drivers/firmware/psci.c__invoke_psci_fn_smc drivers/firmware/psci.carm_smccc_smc include/linux/arm-smccc.h
System Reboot (System Reset)
SYSCALL_DEFINE4(reboot, kernel/reboot.ckernel_power_off kernel/reboot.cmachine_power_off arch/arm64/kernel/process.cpm_power_off arch/arm64/kernel/process.cpsci_sys_poweroff drivers/firmware/psci.cinvoke_psci_fn drivers/firmware/psci.c__invoke_psci_fn_smc drivers/firmware/psci.carm_smccc_smc include/linux/arm-smccc.h
System Suspend
pm_suspend kernel/power/suspend.center_state kernel/power/suspend.csuspend_devices_and_enter kernel/power/suspend.csuspend_enter kernel/power/suspend.cpsci_system_suspend_enter drivers/firmware/psci.cpsci_system_suspend drivers/firmware/psci.cinvoke_psci_fn drivers/firmware/psci.c__invoke_psci_fn_smc drivers/firmware/psci.carm_smccc_smc include/linux/arm-smccc.h
おしまい