/* Copyright (C) 2014 OSCAR lab, Stony Brook University
This file is part of Graphene Library OS.
Graphene Library OS is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
Graphene Library OS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see . */
/*
* clone-x86_64.S
*
* This file contains architecture-specific implementation of clone
* method.
* The source code is imported and modified from the GNU C Library.
*/
/* clone() is even more special than fork() as it mucks with stacks
and invokes a function in the right context after its all over. */
#include
#include
#include "sysdep-x86_64.h"
#define CLONE_VM 0x00000100
#define CLONE_THREAD 0x00010000
/* The userland implementation is:
int clone (int (*fn)(void *arg), void *child_stack, int flags, void *arg),
the kernel entry is:
int clone (long flags, void *child_stack).
The parameters are passed in register and on the stack from userland:
rdi: fn
rsi: child_stack
rdx: flags
rcx: arg
r8: TID field in parent
r9: thread pointer
esp+8: TID field in child
The kernel expects:
rax: system call number
rdi: flags
rsi: child_stack
rdx: TID field in parent
r10: TID field in child
r8: thread pointer */
.text
ENTRY (clone)
/* Sanity check arguments. */
movq $-EINVAL, %rax
testq %rdi, %rdi /* no NULL function pointers */
/* jz SYSCALL_ERROR_LABEL */
testq %rsi, %rsi /* no NULL stack pointers */
/* jz SYSCALL_ERROR_LABEL */
/* Insert the argument onto the new stack. */
subq $16, %rsi
movq %rcx, 8(%rsi)
/* Save the function pointer. It will be popped off in the
child in the ebx frobbing below. */
movq %rdi, 0(%rsi)
/* Do the system call. */
movq %rdx, %rdi
movq %r8, %rdx
movq %r9, %r8
movq 8(%rsp), %r10
movl $SYS_ify(clone), %eax
/* End FDE now, because in the child the unwind info will be
wrong. */
cfi_endproc
syscall
testq %rax, %rax
/* jl SYSCALL_ERROR_LABEL */
jz thread_start
ret
ENTRY (thread_start)
thread_start:
cfi_startproc
/* Clearing frame pointer is insufficient, use CFI. */
cfi_undefined (rip)
/* Clear the frame pointer. The ABI suggests this be done, to mark
the outermost frame obviously. */
xorl %ebp, %ebp
/* Set up arguments for the function call. */
popq %rax /* Function to call. */
popq %rdi /* Argument. */
call *%rax
/* Call exit with return value from function call. */
/* movq %rax, %rdi */
/* movl $SYS_ify(exit), %eax */
/* syscall */
/* Instead of syscall exit, let's call _DkThreadExit */
call *_DkThreadExit(%rip)
cfi_endproc
cfi_startproc
END (clone)