Blame src/process/ntapi_tt_fork_v1.c

dd89bb
/********************************************************/
dd89bb
/*  ntapi: Native API core library                      */
dd89bb
/*  Copyright (C) 2013,2014,2015  Z. Gilboa             */
dd89bb
/*  Released under GPLv2 and GPLv3; see COPYING.NTAPI.  */
dd89bb
/********************************************************/
dd89bb
dd89bb
#include <psxtypes/psxtypes.h>
dd89bb
#include <ntapi/nt_atomic.h>
dd89bb
#include <ntapi/nt_status.h>
dd89bb
#include <ntapi/nt_object.h>
dd89bb
#include <ntapi/nt_memory.h>
dd89bb
#include <ntapi/nt_thread.h>
dd89bb
#include <ntapi/nt_process.h>
dd89bb
#include <ntapi/nt_string.h>
dd89bb
#include <ntapi/ntapi.h>
dd89bb
#include "ntapi_impl.h"
dd89bb
dd89bb
intptr_t __cdecl	__attr_hidden__ __tt_fork_v1(void);
dd89bb
uint32_t __fastcall	__attr_hidden__ __tt_fork_child_entry_point(uintptr_t saved_regs_stack_pointer);
dd89bb
uint32_t __fastcall	__attr_hidden__ __tt_fork_child_entry_point_adj(uintptr_t saved_regs_stack_pointer);
dd89bb
dd89bb
/** legacy fork chronology:
dd89bb
 *
dd89bb
 *  parent:
dd89bb
 *	__ntapi_tt_fork ->
dd89bb
 *		__tt_fork ->
dd89bb
 *			__tt_fork_impl ->
dd89bb
 *		return to __tt_fork -->
dd89bb
 *	__ntapi_tt_fork
dd89bb
 *	-> return to caller
dd89bb
 *
dd89bb
 *  child:
dd89bb
 *		__tt_fork_child_entry_point[_adj] ->
dd89bb
 *	__ntapi_tt_fork (internal return) ->
dd89bb
 *	-> return to caller
dd89bb
**/
dd89bb
dd89bb
dd89bb
static intptr_t __tt_fork_cancel(void * hprocess,int32_t status)
dd89bb
{
dd89bb
	__ntapi->zw_terminate_process(hprocess, status);
dd89bb
	__ntapi->zw_close(hprocess);
dd89bb
	return (intptr_t)(-1);
dd89bb
}
dd89bb
dd89bb
intptr_t __fastcall __tt_fork_impl_v1(
dd89bb
	uintptr_t	saved_regs_stack_pointer,
dd89bb
	uintptr_t	stack_adjustment)
dd89bb
{
dd89bb
	int32_t			status;
dd89bb
	void *			hprocess;
dd89bb
	void *			hthread;
dd89bb
	void **			hport_session;
dd89bb
	ntapi_internals *	__internals;
dd89bb
dd89bb
	nt_object_attributes		oa;
dd89bb
	nt_process_basic_information	pbi;
dd89bb
	nt_thread_context		context;
dd89bb
	nt_user_stack			stack;
dd89bb
	nt_memory_basic_information	mbi;
dd89bb
	nt_client_id			cid;
dd89bb
	nt_large_integer		timeout;
dd89bb
dd89bb
	hprocess = hthread = (void *)0;
dd89bb
dd89bb
	oa.len		= sizeof(nt_object_attributes);
dd89bb
	oa.root_dir	= 0;
dd89bb
	oa.obj_name	= 0;
dd89bb
	oa.obj_attr	= 0;
dd89bb
	oa.sec_desc	= 0;
dd89bb
	oa.sec_qos	= 0;
dd89bb
dd89bb
	if ((status = __ntapi->zw_create_process(
dd89bb
			&hprocess,
dd89bb
			NT_PROCESS_ALL_ACCESS,
dd89bb
			&oa,
dd89bb
			NT_CURRENT_PROCESS_HANDLE,
dd89bb
			1,0,0,0)))
dd89bb
		return (intptr_t)(-1);
dd89bb
dd89bb
	if ((status = __ntapi->zw_query_information_process(
dd89bb
			hprocess,
dd89bb
			NT_PROCESS_BASIC_INFORMATION,
dd89bb
			(void *)&pbi,
dd89bb
			sizeof(nt_process_basic_information),
dd89bb
			0)))
dd89bb
		return __tt_fork_cancel(hprocess,status);
dd89bb
dd89bb
dd89bb
dd89bb
	__ntapi->tt_aligned_block_memset(
dd89bb
		&context,0,sizeof(nt_thread_context));
dd89bb
dd89bb
	__INIT_CONTEXT(context);
dd89bb
	context.STACK_POINTER_REGISTER = saved_regs_stack_pointer;
dd89bb
	context.FAST_CALL_ARG0 = saved_regs_stack_pointer;
dd89bb
dd89bb
	context.INSTRUCTION_POINTER_REGISTER = stack_adjustment
dd89bb
		? (uintptr_t)__tt_fork_child_entry_point_adj
dd89bb
		: (uintptr_t)__tt_fork_child_entry_point;
dd89bb
dd89bb
dd89bb
dd89bb
	if ((status = __ntapi->zw_query_virtual_memory(
dd89bb
			NT_CURRENT_PROCESS_HANDLE,
dd89bb
			(void *)context.STACK_POINTER_REGISTER,
dd89bb
			NT_MEMORY_BASIC_INFORMATION,
dd89bb
			&mbi,sizeof(nt_memory_basic_information),0)))
dd89bb
		return __tt_fork_cancel(hprocess,status);
dd89bb
dd89bb
	stack.fixed_stack_base		= (void *)0;
dd89bb
	stack.fixed_stack_limit		= (void *)0;
dd89bb
	stack.expandable_stack_base	= (void *)((uintptr_t)mbi.base_address + mbi.region_size);
dd89bb
	stack.expandable_stack_limit	= (void *)mbi.base_address;
dd89bb
	stack.expandable_stack_bottom	= (void *)mbi.allocation_base;
dd89bb
dd89bb
dd89bb
dd89bb
	__internals	= __ntapi_internals();
dd89bb
	hport_session	= &__internals->hport_tty_session;
dd89bb
	timeout.quad	= (-1) * 10 * 1000 * __NT_FORK_CHILD_WAIT_MILLISEC;
dd89bb
dd89bb
	if (hport_session && *hport_session)
dd89bb
		if ((status = __ntapi->tty_client_process_register(
dd89bb
				*hport_session,
dd89bb
				pbi.unique_process_id,
dd89bb
				0, 0, &timeout)))
dd89bb
			return __tt_fork_cancel(hprocess,status);
dd89bb
dd89bb
dd89bb
	if ((status = __ntapi->zw_create_thread(
dd89bb
			&hthread,
dd89bb
			NT_THREAD_ALL_ACCESS,
dd89bb
			&oa,hprocess,&cid,
dd89bb
			&context,&stack,0)))
dd89bb
		return __tt_fork_cancel(hprocess,status);
dd89bb
dd89bb
dd89bb
	if (cid.process_id > 0) {
dd89bb
		__internals->hany[0] = hprocess;
dd89bb
		__internals->hany[1] = hthread;
dd89bb
	} else {
dd89bb
		__internals->hany[0] = 0;
dd89bb
		__internals->hany[1] = 0;
dd89bb
	}
dd89bb
dd89bb
	/* hoppla */
dd89bb
	return (int32_t)cid.process_id;
dd89bb
}
dd89bb
dd89bb
intptr_t __fastcall __ntapi_tt_fork_v1(
dd89bb
	__out	void **		hprocess,
dd89bb
	__out	void **		hthread)
dd89bb
{
dd89bb
	int32_t			status;
dd89bb
	intptr_t		pid;
dd89bb
	nt_large_integer	timeout;
dd89bb
	void **			hport_session;
dd89bb
	void *			hevent_tty_connected;
dd89bb
	ntapi_internals *	__internals;
dd89bb
dd89bb
	__internals	= __ntapi_internals();
dd89bb
	hport_session	= &__internals->hport_tty_session;
dd89bb
	timeout.quad	= (-1) * 10 * 1000 * __NT_FORK_CHILD_WAIT_MILLISEC;
dd89bb
dd89bb
	if (at_locked_cas(&__internals->hlock,0,1))
dd89bb
		return (intptr_t)(-1);
dd89bb
dd89bb
	if (hport_session && *hport_session)
dd89bb
		if (__ntapi_tt_create_inheritable_event(
dd89bb
				&hevent_tty_connected,
dd89bb
				NT_NOTIFICATION_EVENT,
dd89bb
				NT_EVENT_NOT_SIGNALED))
dd89bb
			return (intptr_t)(-1);
dd89bb
dd89bb
	pid = __tt_fork_v1();
dd89bb
dd89bb
	*hprocess = __internals->hany[0];
dd89bb
	*hthread  = __internals->hany[1];
dd89bb
dd89bb
	at_store(&__internals->hlock,0);
dd89bb
dd89bb
	if (hport_session && *hport_session) {
dd89bb
		if (pid == 0) {
dd89bb
			if ((status = __ntapi->tty_connect(
dd89bb
					hport_session,
dd89bb
					__internals->subsystem->base_named_objects,
dd89bb
					NT_SECURITY_IMPERSONATION)))
dd89bb
				return __tt_fork_cancel(NT_CURRENT_PROCESS_HANDLE,status);
dd89bb
dd89bb
			__internals->hdev_mount_point_mgr = 0;
dd89bb
dd89bb
			if (__internals->rtdata)
dd89bb
				__internals->rtdata->hsession = *hport_session;
dd89bb
dd89bb
			__ntapi->zw_set_event(
dd89bb
				hevent_tty_connected,
dd89bb
				0);
dd89bb
dd89bb
		} else if (pid > 0) {
dd89bb
			status = __ntapi->zw_wait_for_single_object(
dd89bb
				hevent_tty_connected,
dd89bb
				NT_SYNC_NON_ALERTABLE,
dd89bb
				&timeout);
dd89bb
dd89bb
			if (status && __PSX_DEBUG)
dd89bb
				if ((status = __ntapi->zw_wait_for_single_object(
dd89bb
						hevent_tty_connected,
dd89bb
						NT_SYNC_NON_ALERTABLE,
dd89bb
						0)))
dd89bb
					pid = __tt_fork_cancel(*hprocess,status);
dd89bb
		}
dd89bb
dd89bb
		__ntapi->zw_close(hevent_tty_connected);
dd89bb
	}
dd89bb
dd89bb
	return pid;
dd89bb
}