return gpCurrentThread;
}
-void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, char **ArgV, int DataSize)
+void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize)
{
Uint32 *usr_sp;
int i;
- char **envp;
+ const char **envp;
tVAddr delta;
// Log_Debug("Proc", "Proc_StartUser: (Entrypoint=%p, Base=%p, ArgC=%i, ArgV=%p, DataSize=0x%x)",
// === FUNCTIONS ===
extern void MM_FinishVirtualInit(void);
extern void MM_SetCR3(Uint CR3);
-extern tPAddr MM_Clone(void);
+extern tPAddr MM_Clone(int bCloneUser);
extern tVAddr MM_NewKStack(void);
extern tVAddr MM_NewWorkerStack(Uint *InitialStack, size_t StackSize);
* \fn tPAddr MM_Clone(void)
* \brief Clone the current address space
*/
-tPAddr MM_Clone(void)
+tPAddr MM_Clone(int bNoUserCopy)
{
Uint i, j;
tPAddr ret;
INVLPG( gaTmpDir );
memsetd( gaTmpDir, 0, 1024 );
- if( Threads_GetPID() != 0 )
+ if( Threads_GetPID() != 0 && !bNoUserCopy )
{
// Copy Tables
for( i = 0; i < 768; i ++)
; Save RSP
mov eax, [esp+0x20+4]
mov [eax], esp
+ push DWORD [esp+0x20+12]
call MM_Clone
+ add esp, 4
; Save CR3
mov esi, [esp+0x20+8]
mov [esi], eax
extern Uint GetEIP(void); // start.asm
extern Uint GetEIP_Sched(void); // proc.asm
extern void NewTaskHeader(tThread *Thread, void *Fcn, int nArgs, ...); // Actually takes cdecl args
-extern Uint Proc_CloneInt(Uint *ESP, Uint32 *CR3);
+extern Uint Proc_CloneInt(Uint *ESP, Uint32 *CR3, int bNoUserClone);
extern Uint32 gaInitPageDir[1024]; // start.asm
extern char Kernel_Stack_Top[];
extern int giNumCPUs;
newThread->KernelStack = cur->KernelStack;
// Clone state
- eip = Proc_CloneInt(&newThread->SavedState.ESP, &newThread->Process->MemState.CR3);
+ eip = Proc_CloneInt(&newThread->SavedState.ESP, &newThread->Process->MemState.CR3, Flags & CLONE_NOUSER);
if( eip == 0 ) {
return 0;
}
return base + USER_STACK_SZ;
}
-void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, char **ArgV, int DataSize)
+void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize)
{
Uint *stack;
int i;
- char **envp = NULL;
+ const char **envp = NULL;
Uint16 ss, cs;
// Copy data to the user stack and free original buffer
stack = (void*)Proc_MakeUserStack();
- stack -= DataSize/sizeof(*stack);
+ stack -= (DataSize+sizeof(*stack)-1)/sizeof(*stack);
memcpy( stack, ArgV, DataSize );
free(ArgV);
if( DataSize )
{
Uint delta = (Uint)stack - (Uint)ArgV;
- ArgV = (char**)stack;
+ ArgV = (const char**)stack;
for( i = 0; ArgV[i]; i++ ) ArgV[i] += delta;
envp = &ArgV[i+1];
for( i = 0; envp[i]; i++ ) envp[i] += delta;
MM_RefPhys( TMPMAPLVL4(i) & PADDR_MASK );
}
}
+ else
+ {
+ for( i = 0; i < 256; i ++ )
+ {
+ TMPMAPLVL4(i) = 0;
+ }
+ }
// #4 Map in kernel pages
for( i = 256; i < 512; i ++ )
if(i != -1) return 0;
// Allocate Stack - Allocate incrementally to clean up MM_Dump output
+ // - Most of the user stack is the zero page
for( i = 0; i < (USER_STACK_SZ-USER_STACK_PREALLOC)/0x1000; i++ )
{
MM_AllocateZero( base + (i<<12) );
}
+ // - but the top USER_STACK_PREALLOC pages are actually allocated
for( ; i < USER_STACK_SZ/0x1000; i++ )
{
tPAddr alloc = MM_Allocate( base + (i<<12) );
return base + USER_STACK_SZ;
}
-void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, char **ArgV, int DataSize)
+void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize)
{
Uint *stack;
int i;
- char **envp = NULL;
+ const char **envp = NULL;
Uint16 ss, cs;
if(DataSize)
{
Uint delta = (Uint)stack - (Uint)ArgV;
- ArgV = (char**)stack;
+ ArgV = (const char**)stack;
for( i = 0; ArgV[i]; i++ ) ArgV[i] += delta;
envp = &ArgV[i+1];
for( i = 0; envp[i]; i++ ) envp[i] += delta;
#include <binary.h>
#include <mm_virt.h>
#include <hal_proc.h>
+#include <vfs_threads.h>
// === CONSTANTS ===
#define BIN_LOWEST MM_USER_MIN // 1MiB
extern tBinaryType gELF_Info;
// === PROTOTYPES ===
- int Proc_Execve(const char *File, const char **ArgV, const char **EnvP);
+ int Binary_int_CacheArgs(const char **Path, const char ***ArgV, const char ***EnvP, void *DestBuffer);
tVAddr Binary_Load(const char *Path, tVAddr *EntryPoint);
tBinary *Binary_GetInfo(tMount MountID, tInode InodeID);
tVAddr Binary_MapIn(tBinary *Binary, const char *Path, tVAddr LoadMin, tVAddr LoadMax);
LOG("stackPath = '%s'", stackPath);
- if(Proc_Clone(CLONE_VM) == 0)
+ if(Proc_Clone(CLONE_VM|CLONE_NOUSER) == 0)
{
// CHILD
const char *args[2] = {stackPath, NULL};
LOG("stackPath = '%s'", stackPath);
- Proc_Execve(stackPath, args, &args[1]);
+ Proc_Execve(stackPath, args, &args[1], 0);
for(;;);
}
LEAVE('i', 0);
return 0;
}
+/**
+ * \todo Document
+ */
+int Binary_int_CacheArgs(const char **Path, const char ***ArgV, const char ***EnvP, void *DestBuffer)
+{
+ int size, argc=0, envc=0;
+ int i;
+ char *strbuf;
+ const char **arrays;
+
+ // Calculate size
+ size = 0;
+ if( ArgV && *ArgV )
+ {
+ const char **argv = *ArgV;
+ for( argc = 0; argv[argc]; argc ++ )
+ size += strlen( argv[argc] ) + 1;
+ }
+ if( EnvP && *EnvP )
+ {
+ const char **envp = *EnvP;
+ for( envc = 0; envp[envc]; envc ++ )
+ size += strlen( envp[envc] ) + 1;
+ }
+ size = (size + sizeof(void*)-1) & ~(sizeof(void*)-1); // Word align
+ size += (argc+1+envc+1)*sizeof(void*); // Arrays
+ if( Path )
+ {
+ size += strlen( *Path ) + 1;
+ }
+
+ if( DestBuffer )
+ {
+ arrays = DestBuffer;
+ strbuf = (void*)&arrays[argc+1+envc+1];
+
+ // Fill ArgV
+ if( ArgV && *ArgV )
+ {
+ const char **argv = *ArgV;
+ for( i = 0; argv[i]; i ++ )
+ {
+ arrays[i] = strbuf;
+ strcpy(strbuf, argv[i]);
+ strbuf += strlen( argv[i] ) + 1;
+ }
+ *ArgV = arrays;
+ arrays += i;
+ }
+ *arrays++ = NULL;
+ // Fill EnvP
+ if( EnvP && *EnvP )
+ {
+ const char **envp = *EnvP;
+ for( i = 0; envp[i]; i ++ )
+ {
+ arrays[i] = strbuf;
+ strcpy(strbuf, envp[i]);
+ strbuf += strlen( envp[i] ) + 1;
+ }
+ *EnvP = arrays;
+ arrays += i;
+ }
+ *arrays++ = NULL;
+ // Fill path
+ if( Path )
+ {
+ strcpy(strbuf, *Path);
+ *Path = strbuf;
+ }
+ }
+
+ return size;
+}
+
+/**
+ * \brief Create a new process with the specified set of file descriptors
+ */
+int Proc_SysSpawn(const char *Binary, const char **ArgV, const char **EnvP, int nFD, int *FDs)
+{
+ void *handles;
+ void *cachebuf;
+ int size;
+ tPID ret;
+
+ // --- Save File, ArgV and EnvP
+ size = Binary_int_CacheArgs( &Binary, &ArgV, &EnvP, NULL );
+ cachebuf = alloca( size );
+ Binary_int_CacheArgs( &Binary, &ArgV, &EnvP, cachebuf );
+
+ // Cache the VFS handles
+ handles = VFS_SaveHandles(nFD, FDs);
+
+ // Create new process
+ ret = Proc_Clone(CLONE_VM|CLONE_NOUSER);
+ if( ret == 0 )
+ {
+ VFS_RestoreHandles(nFD, handles);
+ VFS_FreeSavedHandles(nFD, handles);
+ Proc_Execve(Binary, ArgV, EnvP, size);
+ for(;;);
+ }
+ if( ret < 0 )
+ {
+ VFS_FreeSavedHandles(nFD, handles);
+ }
+
+ return ret;
+}
+
/**
* \brief Replace the current user image with another
* \param File File to load as the next image
* \param EnvP User's environment
* \note Called Proc_ for historical reasons
*/
-int Proc_Execve(const char *File, const char **ArgV, const char **EnvP)
+int Proc_Execve(const char *File, const char **ArgV, const char **EnvP, int DataSize)
{
- int argc, envc, i;
- int argenvBytes;
- char **argenvBuf, *strBuf;
- char **argvSaved, **envpSaved;
- char *savedFile;
+ void *cachebuf;
tVAddr entry;
Uint base; // Uint because Proc_StartUser wants it
+ int argc;
ENTER("sFile pArgV pEnvP", File, ArgV, EnvP);
- // --- Save File, ArgV and EnvP (also get argc)
-
- // Count Arguments, Environment Variables and total string sizes
- argenvBytes = 0;
- for( argc = 0; ArgV && ArgV[argc]; argc++ )
- argenvBytes += strlen(ArgV[argc])+1;
- for( envc = 0; EnvP && EnvP[envc]; envc++ )
- argenvBytes += strlen(EnvP[envc])+1;
- LOG("argc = %i, envc = %i", envc);
- argenvBytes = (argenvBytes + sizeof(void*)-1) & ~(sizeof(void*)-1);
- argenvBytes += (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*);
-
- // Allocate
- argenvBuf = malloc(argenvBytes);
- if(argenvBuf == NULL) {
- Log_Error("Binary", "Proc_Execve - What the hell? The kernel is out of heap space");
- LEAVE('i', 0);
- return 0;
- }
- strBuf = (char*)argenvBuf + (argc+1)*sizeof(void*) + (envc+1)*sizeof(void*);
-
- // Populate
- argvSaved = argenvBuf;
- for( i = 0; i < argc; i++ )
- {
- argvSaved[i] = strBuf;
- strcpy(argvSaved[i], ArgV[i]);
- LOG("argv[%i] = '%s'", i, strBuf);
- strBuf += strlen(ArgV[i])+1;
- }
- argvSaved[i] = NULL;
- envpSaved = &argvSaved[i+1];
- for( i = 0; i < envc; i++ )
+ // --- Save File, ArgV and EnvP
+ if( DataSize == 0 )
{
- envpSaved[i] = strBuf;
- LOG("envp[%i] = '%s'", i, strBuf);
- strcpy(envpSaved[i], EnvP[i]);
- strBuf += strlen(EnvP[i])+1;
+ DataSize = Binary_int_CacheArgs( &File, &ArgV, &EnvP, NULL );
+ cachebuf = malloc( DataSize );
+ Binary_int_CacheArgs( &File, &ArgV, &EnvP, cachebuf );
}
- envpSaved[i] = NULL;
-
- savedFile = malloc(strlen(File)+1);
- strcpy(savedFile, File);
+
+ // --- Get argc
+ for( argc = 0; ArgV && ArgV[argc]; argc ++ );
// --- Set Process Name
Threads_SetName(File);
MM_ClearUser();
// --- Load new binary
- base = Binary_Load(savedFile, &entry);
- free(savedFile);
+ base = Binary_Load(File, &entry);
if(base == 0)
{
- free(argvSaved);
- Log_Warning("Binary", "Proc_Execve - Unable to load '%s'", Threads_GetName(-1));
+ Log_Warning("Binary", "Proc_Execve - Unable to load '%s'", File);
LEAVE('-');
Threads_Exit(0, -10);
for(;;);
}
LOG("entry = 0x%x, base = 0x%x", entry, base);
-
-// MM_DumpTables(0, KERNEL_BASE);
-
LEAVE('-');
// --- And... Jump to it
- Proc_StartUser(entry, base, argc, argvSaved, argenvBytes);
+ Proc_StartUser(entry, base, argc, ArgV, DataSize);
for(;;); // Tell GCC that we never return
}
*/
//! Clone the entire process
#define CLONE_VM 0x10
+//! Don't copy user pages
+#define CLONE_NOUSER 0x20
/**
* \}
*/
// --- Heap ---
#include <heap.h>
+/**
+ * \brief Magic heap allocation function
+ */
+extern void *alloca(size_t Size);
// --- Modules ---
/**
*/
extern int Proc_SpawnWorker(void (*Fcn)(void*), void *Data);
extern int Proc_Spawn(const char *Path);
+extern int Proc_SysSpawn(const char *Binary, const char **ArgV, const char **EnvP, int nFD, int *FDs);
+extern int Proc_Execve(const char *File, const char **ArgV, const char **EnvP, int DataSize);
extern void Threads_Exit(int TID, int Status);
extern void Threads_Yield(void);
extern void Threads_Sleep(void);
* \param DataSize Size of the \a ArgV buffer in bytes
* \note This function should free \a ArgV
*/
-extern void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, char **ArgV, int DataSize) NORETURN;
+extern void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize) NORETURN;
/**
* \brief Call the fault handler for a thread
* \param Thread Thread that is at fault :)
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * include/vfs_threads.h
+ * - Handle maintainance functions for the VFS used by threading code
+ */
+#ifndef _VFS_THREADS_H_
+#define _VFS_THREADS_H_
+
+// === FUNCTIONS ===
+extern void VFS_ReferenceUserHandles(void);
+extern void VFS_CloseAllUserHandles(void);
+
+extern void *VFS_SaveHandles(int NumFDs, int *FDs);
+extern void VFS_RestoreHandles(int NumFDs, void *Handles);
+extern void VFS_FreeSavedHandles(int NumFDs, void *Handles);
+
+#endif
if(!(v)||!Syscall_ValidString((v))){ret=-1;err=-EINVAL;break;}
// === IMPORTS ===
-extern int Proc_Execve(char *File, char **ArgV, char **EnvP);
extern Uint Binary_Load(const char *file, Uint *entryPoint);
// === PROTOTYPES ===
}
}
LEAVE('s', "Assuming 0");
- // Path, **Argv, **Envp
- ret = Proc_Execve( (char*)Regs->Arg1, (char**)Regs->Arg2, (char**)Regs->Arg3 );
+ // Path, **Argv, **Envp, DataSize (=0 to tell it to create a copy)
+ ret = Proc_Execve( (const char*)Regs->Arg1, (const char**)Regs->Arg2, (const char**)Regs->Arg3, 0 );
break;
// -- Load a binary into the current process
case SYS_LOADBIN:
#include "vfs_int.h"
#include "vfs_ext.h"
#include <threads.h> // GetMaxFD
+#include <vfs_threads.h> // Handle maintainance
// === CONSTANTS ===
#define MAX_KERNEL_FILES 128
return -1;
}
+
+void VFS_ReferenceUserHandles(void)
+{
+ int i;
+ int max_handles = *Threads_GetMaxFD();
+
+ for( i = 0; i < max_handles; i ++ )
+ {
+ tVFS_Handle *h;
+ h = &gaUserHandles[i];
+ if( h->Node->Type && h->Node->Type->Reference )
+ h->Node->Type->Reference( h->Node );
+ }
+}
+
+void VFS_CloseAllUserHandles(void)
+{
+ int i;
+ int max_handles = *Threads_GetMaxFD();
+
+ for( i = 0; i < max_handles; i ++ )
+ {
+ tVFS_Handle *h;
+ h = &gaUserHandles[i];
+ if( h->Node->Type && h->Node->Type->Close )
+ h->Node->Type->Close( h->Node );
+ }
+}
+
+/**
+ * \brief Take a backup of a set of file descriptors
+ */
+void *VFS_SaveHandles(int NumFDs, int *FDs)
+{
+ tVFS_Handle *ret;
+ int i;
+
+ // Check if this process has any handles
+ if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) == 0 )
+ return NULL;
+
+ // Allocate
+ ret = malloc( NumFDs * sizeof(tVFS_Handle) );
+ if( !ret )
+ return NULL;
+
+ // Take copies of the handles
+ for( i = 0; i < NumFDs; i ++ )
+ {
+ tVFS_Handle *h;
+ h = VFS_GetHandle(FDs[i] & (VFS_KERNEL_FLAG - 1));
+ if(!h) {
+ Log_Warning("VFS", "VFS_SaveHandles - Invalid FD %i",
+ FDs[i] & (VFS_KERNEL_FLAG - 1) );
+ free(ret);
+ return NULL;
+ }
+ memcpy( &ret[i], h, sizeof(tVFS_Handle) );
+
+ // Reference node
+ if( h->Node->Type && h->Node->Type->Reference )
+ h->Node->Type->Reference( h->Node );
+ }
+
+ return ret;
+}
+
+void VFS_RestoreHandles(int NumFDs, void *Handles)
+{
+ tVFS_Handle *handles = Handles;
+ int i;
+
+ // NULL = nothing to do
+ if( !Handles )
+ return ;
+
+ // Check if there is already a set of handles
+ if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) != 0 )
+ return ;
+
+
+ // Allocate user handle area
+ {
+ Uint addr, size;
+ int max_handles = *Threads_GetMaxFD();
+ size = max_handles * sizeof(tVFS_Handle);
+ for(addr = 0; addr < size; addr += 0x1000)
+ {
+ if( !MM_Allocate( (tVAddr)gaUserHandles + addr ) )
+ {
+ Warning("OOM - VFS_AllocHandle");
+ Threads_Exit(0, 0xFF); // Terminate user
+ }
+ }
+ memset( gaUserHandles, 0, size );
+ }
+
+ // Restore handles
+ memcpy( gaUserHandles, handles, NumFDs * sizeof(tVFS_Handle) );
+ // Reference when copied
+ for( i = 0; i < NumFDs; i ++ )
+ {
+ tVFS_Handle *h = &handles[i];
+
+ if( h->Node->Type && h->Node->Type->Reference )
+ h->Node->Type->Reference( h->Node );
+ }
+}
+
+void VFS_FreeSavedHandles(int NumFDs, void *Handles)
+{
+ tVFS_Handle *handles = Handles;
+ int i;
+
+ // Dereference all saved nodes
+ for( i = 0; i < NumFDs; i ++ )
+ {
+ tVFS_Handle *h = &handles[i];
+
+ if( h->Node->Type && h->Node->Type->Close )
+ h->Node->Type->Close( h->Node );
+ }
+ free( Handles );
+}