diff options
-rw-r--r-- | sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S | 33 |
1 files changed, 30 insertions, 3 deletions
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S b/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S index fc496fa671..247e0de68c 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S @@ -38,9 +38,11 @@ ENTRY (__clone) beq- cr0,L(badargs) /* Save some regs in the "red zone". */ + std r28,-32(r1) std r29,-24(r1) std r30,-16(r1) std r31,-8(r1) + cfi_offset(r28,-32) cfi_offset(r29,-24) cfi_offset(r30,-16) cfi_offset(r31,-8) @@ -69,11 +71,26 @@ ENTRY (__clone) /* Do the call. */ li r0,SYS_ify(clone) - DO_CALL_SC + CHECK_SCV_SUPPORT r28 0f + /* This is equivalent to DO_CALL_SCV, but we cannot use the macro here + because it uses CFI directives and we just called cfi_endproc. */ + mflr r9 + std r9,FRAME_LR_SAVE(r1) + scv 0 + ld r9,FRAME_LR_SAVE(r1) + mtlr r9 + + /* Check for child process. */ + /* When using scv, error is indicated by negative r3. */ + cmpdi cr1,r3,0 + b 1f +0: DO_CALL_SC /* Check for child process. */ + /* With sc, error is indicated by cr0.SO. */ cmpdi cr1,r3,0 crandc cr1*4+eq,cr1*4+eq,cr0*4+so +1: bne- cr1,L(parent) /* The '-' is to minimise the race. */ std r2,FRAME_TOC_SAVE(r1) @@ -95,19 +112,29 @@ L(badargs): TAIL_CALL_SYSCALL_ERROR L(parent): + /* Check if scv is available. */ + cmpdi cr1,r28,0 + /* Parent. Restore registers & return. */ + cfi_offset(r28,-32) cfi_offset(r29,-24) cfi_offset(r30,-16) cfi_offset(r31,-8) + ld r28,-32(r1) ld r29,-24(r1) ld r30,-16(r1) ld r31,-8(r1) + cfi_restore(r28) cfi_restore(r29) cfi_restore(r30) cfi_restore(r31) - RET_SC - TAIL_CALL_SYSCALL_ERROR + beq cr1,0f + RET_SCV + b 1f +0: RET_SC +1: TAIL_CALL_SYSCALL_ERROR + END (__clone) |