Power Architecture 64 位 Linux 系统调用 ABI¶
系统调用¶
调用¶
系统调用通过 sc 指令发起,并在执行完 sc 指令后的下一条指令处继续返回执行。
如果 AT_HWCAP2 ELF 辅助向量中出现了 PPC_FEATURE2_SCV,则 scv 0 指令是一种可替代的方案,它可能提供更好的性能,但调用序列略有不同。
系统调用序列[1]与 Power Architecture 64 位 ELF ABI 规范的 C 函数调用序列(包括寄存器保护规则)相匹配,但存在以下差异。
参数¶
系统调用号在 r0 中指定。
系统调用最多有 6 个整型参数,通过 r3-r8 传递。
返回值¶
对于 sc 指令,会同时返回一个值和一个错误条件。cr0.SO 是错误条件,r3 是返回值。当 cr0.SO 清除时,系统调用成功且 r3 为返回值。当 cr0.SO 置位时,系统调用失败且 r3 为错误值(通常对应 errno)。
对于 scv 0 指令,如果返回值在 -4095..-1 范围内(即作为无符号数比较时 >= -MAX_ERRNO (-4095)),则表示失败,此时错误值为返回值的相反数。
栈¶
系统调用不会修改调用者的栈帧。例如,不使用调用者栈帧的 LR 和 CR 保存字段。
寄存器保护规则¶
寄存器保护规则与 ELF ABI 调用序列相匹配,但有一些差异。
对于 sc 指令,与 ELF ABI 的差异如下
寄存器 |
保护规则 |
用途 |
|---|---|---|
r0 |
易失的 |
(系统调用号。) |
r3 |
易失的 |
(参数 1 和返回值。) |
r4-r8 |
易失的 |
(参数 2-6。) |
cr0 |
易失的 |
(cr0.SO 是返回错误条件。) |
cr1, cr5-7 |
非易失的 |
|
lr |
非易失的 |
对于 scv 0 指令,与 ELF ABI 的差异如下
寄存器 |
保护规则 |
用途 |
|---|---|---|
r0 |
易失的 |
(系统调用号。) |
r3 |
易失的 |
(参数 1 和返回值。) |
r4-r8 |
易失的 |
(参数 2-6。) |
所有的浮点寄存器、向量数据寄存器以及控制和状态寄存器均是非易失的。
事务内存¶
如果处理器处于事务状态或挂起事务状态,系统调用行为可能会改变,并且系统调用会影响事务的行为。
如果在发起系统调用时处理器处于挂起状态,系统调用将正常执行并正常返回。系统调用将在挂起状态下执行,因此根据通常的事务内存语义,其副作用将是持久的。系统调用可能会也可能不会导致事务被硬件判定为失败。
如果在发起系统调用时处理器处于事务状态,则其行为取决于 AT_HWCAP2 ELF 辅助向量中是否存在 PPC_FEATURE2_HTM_NOSC。
如果存在(较新的内核即是如此),则系统调用将不会执行,且内核会在 TEXASR SPR 中使用失败代码 TM_CAUSE_SYSCALL | TM_CAUSE_PERSISTENT 将事务判定为失败。
如果不存在(较旧的内核),则内核将挂起事务状态,系统调用将像挂起状态系统调用一样进行,并在返回调用者之前恢复事务状态。这种情况未得到明确定义或支持,因此不应依赖此行为。
scv 0 系统调用始终表现得如同存在 PPC_FEATURE2_HTM_NOSC 一样。
ptrace¶
在使用 ptrace 跟踪系统调用(PTRACE_SYSCALL)时,pt_regs.trap 值包含系统调用类型,可用于区分 sc 和 scv 0 系统调用,并据此处理不同的寄存器约定。
如果 (pt_regs.trap & 0xfff0) 的值为 0xc00,则该系统调用是通过 sc 指令执行的;如果为 0x3000,则该系统调用是通过 scv 0 指令执行的。
vsyscall¶
vsyscall 调用序列与系统调用序列相匹配,但有以下差异。某些 vsyscall 可能具有不同的调用序列。
参数和返回值¶
r0 不用作输入。vsyscall 通过其地址来选择。
栈¶
vsyscall 可能会也可能不会使用调用者的栈帧保存区。
寄存器保护规则¶
r0 |
易失的 |
cr1, cr5-7 |
易失的 |
lr |
易失的 |
调用¶
vsyscall 通过一条带链接的分支指令跳转到 vsyscall 函数地址来执行。
事务内存¶
vsyscall 将在与调用者相同的事务状态下运行。vsyscall 可能会也可能不会导致事务被硬件判定为失败。