#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);
}
/**
- * \fn int Proc_Execve(char *File, char **ArgV, char **EnvP)
+ * \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 = malloc( 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);
+ // Frees cachebuf
+ 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 ArgV Arguments to pass to user
* \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;
- 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++ )
+ // --- Save File, ArgV and EnvP
+ if( DataSize == 0 )
{
- argvSaved[i] = strBuf;
- strcpy(argvSaved[i], ArgV[i]);
- strBuf += strlen(ArgV[i])+1;
+ DataSize = Binary_int_CacheArgs( &File, &ArgV, &EnvP, NULL );
+ cachebuf = malloc( DataSize );
+ Binary_int_CacheArgs( &File, &ArgV, &EnvP, cachebuf );
}
- argvSaved[i] = NULL;
- envpSaved = &argvSaved[i+1];
- for( i = 0; i < envc; i++ )
- {
- envpSaved[i] = strBuf;
- strcpy(envpSaved[i], EnvP[i]);
- strBuf += strlen(EnvP[i])+1;
- }
- 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);
// --- Clear User Address space
- MM_ClearUser();
+ // NOTE: This is a little roundabout, maybe telling ClearUser to not touch the
+ // PPD area would be a better idea.
+ {
+ int nfd = *Threads_GetMaxFD();
+ void *handles;
+ handles = VFS_SaveHandles(nfd, NULL);
+ VFS_CloseAllUserHandles();
+ MM_ClearUser();
+ VFS_RestoreHandles(nfd, handles);
+ VFS_FreeSavedHandles(nfd, handles);
+ }
// --- 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
}
/**
* \brief Finds a matching binary entry
- * \param TruePath File Identifier (True path name)
+ * \param MountID Mountpoint ID of binary file
+ * \param InodeID Inode ID of the file
+ * \return Pointer to the binary definition (if already loaded)
*/
tBinary *Binary_GetInfo(tMount MountID, tInode InodeID)
{
tBinary *pBinary;
- pBinary = glLoadedBinaries;
- while(pBinary)
+ for(pBinary = glLoadedBinaries; pBinary; pBinary = pBinary->Next)
{
if(pBinary->MountID == MountID && pBinary->Inode == InodeID)
return pBinary;
- pBinary = pBinary->Next;
}
return NULL;
}
/**
- \fn Uint Binary_MapIn(tBinary *binary)
- \brief Maps an already-loaded binary into an address space.
- \param binary Pointer to globally stored data.
-*/
+ * \brief Maps an already-loaded binary into an address space.
+ * \param Binary Pointer to globally stored binary definition
+ * \param Path Path to the binary's file (for debug)
+ * \param LoadMin Lowest location to map to
+ * \param LoadMax Highest location to map to
+ * \return Base load address
+ */
tVAddr Binary_MapIn(tBinary *Binary, const char *Path, tVAddr LoadMin, tVAddr LoadMax)
{
tVAddr base;
if(base != 0)
{
LOG("Checking base %p", base);
- for(i=0;i<Binary->NumSections;i++)
+ for( i = 0; i < Binary->NumSections; i ++ )
{
if( Binary_int_CheckMemFree( Binary->LoadSections[i].Virtual, Binary->LoadSections[i].MemSize ) )
{
if( sect->Flags & BIN_SECTFLAG_EXEC )
protflags |= MMAP_PROT_EXEC;
+ // Read only pages are COW
if( sect->Flags & BIN_SECTFLAG_RO ) {
VFS_MMap( (void*)addr, sect->FileSize, protflags, MMAP_MAP_SHARED|mapflags, fd, sect->Offset );
}
protflags |= MMAP_PROT_WRITE;
VFS_MMap( (void*)addr, sect->FileSize, protflags, MMAP_MAP_PRIVATE|mapflags, fd, sect->Offset );
}
+
+ // Apply anonymous memory for BSS
if( sect->FileSize < sect->MemSize ) {
mapflags |= MMAP_MAP_ANONYMOUS;
VFS_MMap(
protflags, MMAP_MAP_PRIVATE|mapflags,
0, 0
);
-// memset((void*)(addr + sect->FileSize), 0, sect->MemSize - sect->FileSize);
}
}
- Log_Debug("Binary", "PID %i - Mapped '%s' to 0x%x", Threads_GetPID(), Path, base);
+ Log_Debug("Binary", "PID %i - Mapped '%s' to %p", Threads_GetPID(), Path, base);
VFS_Close(fd);
- //LOG("*0x%x = 0x%x\n", binary->Pages[0].Virtual, *(Uint*)binary->Pages[0].Virtual);
-
LEAVE('p', base);
return base;
}
break;
}
- LOG("pBinary = %p", pBinary);
-
// Close File
VFS_Close(fp);
return NULL;
}
+ LOG("pBinary = %p", pBinary);
+
// Error Check
if(pBinary == NULL) {
LEAVE('n');