Linux : PSCI

Post on 12-Apr-2017

737 Views

Category:

Software

1 Downloads

Preview:

Click to see full reader

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.

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

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 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

おしまい

top related