rewrite ES_SYSCALL_PROCESS_CREATE

This commit is contained in:
nakst 2021-09-11 18:14:47 +01:00
parent 243166f370
commit f140770dac
5 changed files with 126 additions and 80 deletions

View File

@ -1233,6 +1233,8 @@ bool ApplicationInstanceStart(int64_t applicationID, EsApplicationStartupInforma
arguments.permissions = ES_PERMISSION_WINDOW_MANAGER; arguments.permissions = ES_PERMISSION_WINDOW_MANAGER;
Array<EsMountPoint> initialMountPoints = {}; Array<EsMountPoint> initialMountPoints = {};
Array<EsHandle> handleDuplicateList = {};
Array<uint32_t> handleModeDuplicateList = {};
_EsNodeInformation settingsNode = {}; _EsNodeInformation settingsNode = {};
if (application->permissions & APPLICATION_PERMISSION_MANAGE_PROCESSES) { if (application->permissions & APPLICATION_PERMISSION_MANAGE_PROCESSES) {
@ -1246,20 +1248,26 @@ bool ApplicationInstanceStart(int64_t applicationID, EsApplicationStartupInforma
arguments.permissions |= ES_PERMISSION_POSIX_SUBSYSTEM; arguments.permissions |= ES_PERMISSION_POSIX_SUBSYSTEM;
MountPoint root = *NodeFindMountPoint(EsLiteral("0:")); MountPoint root = *NodeFindMountPoint(EsLiteral("0:"));
root.write = true;
root.prefixBytes = EsStringFormat(root.prefix, sizeof(root.prefix), "|POSIX:"); root.prefixBytes = EsStringFormat(root.prefix, sizeof(root.prefix), "|POSIX:");
initialMountPoints.Add(root); initialMountPoints.Add(root);
handleDuplicateList.Add(root.base);
handleModeDuplicateList.Add(0);
} }
if (application->permissions & APPLICATION_PERMISSION_ALL_FILES) { if (application->permissions & APPLICATION_PERMISSION_ALL_FILES) {
for (uintptr_t i = 0; i < api.mountPoints.Length(); i++) { for (uintptr_t i = 0; i < api.mountPoints.Length(); i++) {
initialMountPoints.Add(api.mountPoints[i]); initialMountPoints.Add(api.mountPoints[i]);
initialMountPoints[i].write = true; handleDuplicateList.Add(api.mountPoints[i].base);
handleModeDuplicateList.Add(0);
} }
arguments.permissions |= ES_PERMISSION_GET_VOLUME_INFORMATION; arguments.permissions |= ES_PERMISSION_GET_VOLUME_INFORMATION;
} else { } else {
initialMountPoints.Add(*NodeFindMountPoint(EsLiteral("|Fonts:"))); MountPoint fonts = *NodeFindMountPoint(EsLiteral("|Fonts:"));
initialMountPoints.Add(fonts);
handleDuplicateList.Add(fonts.base);
handleModeDuplicateList.Add(2 /* prevent write */);
} }
{ {
@ -1270,25 +1278,34 @@ bool ApplicationInstanceStart(int64_t applicationID, EsApplicationStartupInforma
EsMountPoint settings = {}; EsMountPoint settings = {};
settings.prefixBytes = EsStringFormat(settings.prefix, sizeof(settings.prefix), "|Settings:"); settings.prefixBytes = EsStringFormat(settings.prefix, sizeof(settings.prefix), "|Settings:");
settings.base = settingsNode.handle; settings.base = settingsNode.handle;
settings.write = true;
initialMountPoints.Add(settings); initialMountPoints.Add(settings);
handleDuplicateList.Add(settings.base);
handleModeDuplicateList.Add(0);
} else { } else {
settingsNode.handle = ES_INVALID_HANDLE; settingsNode.handle = ES_INVALID_HANDLE;
} }
} }
#if 0 arguments.data.initialMountPoints = EsConstantBufferCreate(initialMountPoints.array, initialMountPoints.Length() * sizeof(EsMountPoint), ES_CURRENT_PROCESS);
arguments.initialMountPoints = initialMountPoints.array; handleDuplicateList.Add(arguments.data.initialMountPoints);
arguments.initialMountPointCount = initialMountPoints.Length(); handleModeDuplicateList.Add(0);
#endif
// TODO Update this. arguments.handles = handleDuplicateList.array;
arguments.handleModes = handleModeDuplicateList.array;
arguments.handleCount = handleDuplicateList.Length();
EsAssert(handleDuplicateList.Length() == handleModeDuplicateList.Length());
error = EsProcessCreate(&arguments, &information); error = EsProcessCreate(&arguments, &information);
EsHandleClose(arguments.executable); EsHandleClose(arguments.executable);
initialMountPoints.Free(); initialMountPoints.Free();
if (settingsNode.handle) EsHandleClose(settingsNode.handle); handleDuplicateList.Free();
handleModeDuplicateList.Free();
if (settingsNode.handle) {
EsHandleClose(settingsNode.handle);
}
if (!ES_CHECK_ERROR(error)) { if (!ES_CHECK_ERROR(error)) {
process = information.handle; process = information.handle;

View File

@ -1248,7 +1248,6 @@ struct EsMountPoint {
char prefix[16]; char prefix[16];
size_t prefixBytes; size_t prefixBytes;
EsHandle base; EsHandle base;
bool write;
}; };
struct EsProcessCreateData { struct EsProcessCreateData {
@ -1269,6 +1268,7 @@ struct EsProcessStartupInformation {
struct EsProcessCreationArguments { struct EsProcessCreationArguments {
EsHandle executable; EsHandle executable;
EsHandle *handles; // Duplicated. EsHandle *handles; // Duplicated.
uint32_t *handleModes; // The share arguments.
size_t handleCount; size_t handleCount;
EsProcessCreateData data; EsProcessCreateData data;
uint32_t flags; uint32_t flags;

View File

@ -386,6 +386,33 @@ void CloseHandleToObject(void *object, KernelObjectType type, uint32_t flags) {
} }
} }
uintptr_t HandleShare(Handle share, Process *process, uint32_t mode, EsHandle at = ES_INVALID_HANDLE) {
#define HANDLE_SHARE_TYPE_MASK (KERNEL_OBJECT_SHMEM | KERNEL_OBJECT_CONSTANT_BUFFER | KERNEL_OBJECT_PROCESS \
| KERNEL_OBJECT_DEVICE | KERNEL_OBJECT_NODE | KERNEL_OBJECT_EVENT | KERNEL_OBJECT_PIPE)
if ((share.type & HANDLE_SHARE_TYPE_MASK) == 0) {
KernelPanic("HandleShare - Invalid object type %x; allowed types are %x.\n", share.type, HANDLE_SHARE_TYPE_MASK);
}
uint32_t sharedFlags = share.flags;
// TODO Sort out flag modes.
if (share.type == KERNEL_OBJECT_SHMEM) {
sharedFlags = mode;
} else if (share.type == KERNEL_OBJECT_NODE) {
sharedFlags = (mode & 1) && (share.flags & (ES_FILE_WRITE_SHARED | ES_FILE_WRITE)) ? ES_FILE_READ_SHARED : share.flags;
if (mode & 2) sharedFlags &= ~_ES_NODE_DIRECTORY_WRITE;
} else if (share.type == KERNEL_OBJECT_PIPE) {
}
if (!OpenHandleToObject(share.object, share.type, sharedFlags)) {
return ES_ERROR_PERMISSION_NOT_GRANTED;
} else {
return process->handleTable.OpenHandle(share.object, sharedFlags, share.type, at);
}
}
bool HandleTable::CloseHandle(EsHandle handle) { bool HandleTable::CloseHandle(EsHandle handle) {
if (handle > HANDLE_TABLE_L1_ENTRIES * HANDLE_TABLE_L2_ENTRIES) { if (handle > HANDLE_TABLE_L1_ENTRIES * HANDLE_TABLE_L2_ENTRIES) {
return false; return false;

View File

@ -128,7 +128,7 @@ struct Process {
char cExecutableName[ES_SNAPSHOT_MAX_PROCESS_NAME_LENGTH + 1]; char cExecutableName[ES_SNAPSHOT_MAX_PROCESS_NAME_LENGTH + 1];
EsProcessCreateData data; EsProcessCreateData data;
uint64_t permissions; uint64_t permissions;
uint64_t creationFlags; uint32_t creationFlags;
ProcessType type; ProcessType type;
// Object management: // Object management:
@ -144,7 +144,7 @@ struct Process {
// Termination: // Termination:
bool allThreadsTerminated; bool allThreadsTerminated;
bool terminating; bool terminating;
int exitStatus; int exitStatus; // TODO Remove this.
KEvent killedEvent; KEvent killedEvent;
// Executable state: // Executable state:
@ -156,6 +156,7 @@ struct Process {
// Statistics: // Statistics:
uintptr_t cpuTimeSlices, idleTimeSlices; uintptr_t cpuTimeSlices, idleTimeSlices;
// POSIX:
#ifdef ENABLE_POSIX_SUBSYSTEM #ifdef ENABLE_POSIX_SUBSYSTEM
bool posixForking; bool posixForking;
int pgid; int pgid;

View File

@ -229,13 +229,6 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_PROCESS_CREATE) {
EsProcessCreationArguments arguments; EsProcessCreationArguments arguments;
SYSCALL_READ(&arguments, argument0, sizeof(EsProcessCreationArguments)); SYSCALL_READ(&arguments, argument0, sizeof(EsProcessCreationArguments));
EsProcessInformation processInformation;
EsMemoryZero(&processInformation, sizeof(EsProcessInformation));
if (arguments.handleCount > 65536) {
SYSCALL_RETURN(ES_ERROR_INSUFFICIENT_RESOURCES, false);
}
// Check the permissions. // Check the permissions.
SYSCALL_PERMISSION(ES_PERMISSION_PROCESS_CREATE); SYSCALL_PERMISSION(ES_PERMISSION_PROCESS_CREATE);
@ -256,63 +249,86 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_PROCESS_CREATE) {
SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_NODE_TYPE, true); SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_NODE_TYPE, true);
} }
// TODO. // Check the handle list.
#if 0
Process *process = scheduler.SpawnProcess();
if (!process) { if (arguments.handleCount > SYSCALL_BUFFER_LIMIT / sizeof(Handle)) {
SYSCALL_RETURN(ES_ERROR_INSUFFICIENT_RESOURCES, false); SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true);
} }
process->creationFlags = arguments.flags; EsHandle *inHandles;
process->creationArguments[CREATION_ARGUMENT_MAIN] = arguments.creationArgument.u; SYSCALL_READ_HEAP(inHandles, (uintptr_t) arguments.handles, arguments.handleCount * sizeof(EsHandle));
process->permissions = arguments.permissions; uint32_t *inHandleModes;
SYSCALL_READ_HEAP(inHandleModes, (uintptr_t) arguments.handleModes, arguments.handleCount * sizeof(uint32_t));
// TODO Free the process object if something fails here. Handle *handles = (Handle *) EsHeapAllocate(sizeof(Handle) * arguments.handleCount, false, K_PAGED);
if (arguments.environmentBlockBytes) { if (!handles && arguments.handleCount) {
if (arguments.environmentBlockBytes > SYSCALL_BUFFER_LIMIT) SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true); SYSCALL_RETURN(ES_ERROR_INSUFFICIENT_RESOURCES, K_PAGED);
SYSCALL_BUFFER((uintptr_t) arguments.environmentBlock, arguments.environmentBlockBytes, 1, false); }
process->creationArguments[CREATION_ARGUMENT_ENVIRONMENT] = MakeConstantBuffer(arguments.environmentBlock, arguments.environmentBlockBytes, process);
}
if (arguments.initialMountPointCount) {
if (arguments.initialMountPointCount > ES_MOUNT_POINT_MAX_COUNT) SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true);
EsMountPoint *mountPoints = (EsMountPoint *) EsHeapAllocate(arguments.initialMountPointCount * sizeof(EsMountPoint), false, K_FIXED); EsDefer(EsHeapFree(handles, sizeof(Handle) * arguments.handleCount, K_PAGED));
EsDefer(EsHeapFree(mountPoints, arguments.initialMountPointCount * sizeof(EsMountPoint), K_FIXED));
SYSCALL_READ(mountPoints, (uintptr_t) arguments.initialMountPoints, arguments.initialMountPointCount * sizeof(EsMountPoint));
for (uintptr_t i = 0; i < arguments.initialMountPointCount; i++) { EsError error = ES_SUCCESS;
// Open handles to the mount points for the new process.
// TODO Handling errors when opening handles. for (uintptr_t i = 0; i < arguments.handleCount; i++) {
KObject object(currentProcess, mountPoints[i].base, KERNEL_OBJECT_NODE); if (RESOLVE_HANDLE_NORMAL != currentProcess->handleTable.ResolveHandle(&handles[i], inHandles[i], HANDLE_SHARE_TYPE_MASK)) {
CHECK_OBJECT(object); handles[i].object = nullptr;
if (!mountPoints[i].write) object.flags &= ~_ES_NODE_DIRECTORY_WRITE; error = ES_FATAL_ERROR_INVALID_HANDLE;
OpenHandleToObject(object.object, object.type, object.flags);
mountPoints[i].base = process->handleTable.OpenHandle(object.object, object.flags, object.type);
} }
process->creationArguments[CREATION_ARGUMENT_INITIAL_MOUNT_POINTS]
= MakeConstantBuffer(mountPoints, arguments.initialMountPointCount * sizeof(EsMountPoint), process);
} }
if (!process->StartWithNode((KNode *) executableObject.object)) { // Create the process.
CloseHandleToObject(process, KERNEL_OBJECT_PROCESS);
SYSCALL_RETURN(ES_ERROR_UNKNOWN, false); if (error == ES_SUCCESS) {
Process *process = scheduler.SpawnProcess();
if (!process) {
error = ES_ERROR_INSUFFICIENT_RESOURCES;
} else {
process->creationFlags = arguments.flags;
process->data = arguments.data;
process->permissions = arguments.permissions;
// Duplicate handles.
for (uintptr_t i = 0; i < arguments.handleCount; i++) {
EsError error2 = HandleShare(handles[i], process, inHandleModes[i], inHandles[i]);
if (ES_CHECK_ERROR(error2)) {
error = error2;
break;
}
}
// Start the process.
if (error != ES_SUCCESS || !process->StartWithNode(executableObject)) {
// TODO Confirm that this frees the handle table.
error = ES_ERROR_UNKNOWN; // TODO.
CloseHandleToObject(process, KERNEL_OBJECT_PROCESS);
} else {
// Write the process information out.
EsProcessInformation processInformation;
EsMemoryZero(&processInformation, sizeof(EsProcessInformation));
processInformation.pid = process->id;
processInformation.mainThread.tid = process->executableMainThread->id;
processInformation.mainThread.handle = currentProcess->handleTable.OpenHandle(process->executableMainThread, 0, KERNEL_OBJECT_THREAD);
processInformation.handle = currentProcess->handleTable.OpenHandle(process, 0, KERNEL_OBJECT_PROCESS);
SYSCALL_WRITE(argument2, &processInformation, sizeof(EsProcessInformation));
}
}
} }
processInformation.pid = process->id; // Close handles.
processInformation.mainThread.tid = process->executableMainThread->id;
processInformation.mainThread.handle = currentProcess->handleTable.OpenHandle(process->executableMainThread, 0, KERNEL_OBJECT_THREAD); for (uintptr_t i = 0; i < arguments.handleCount; i++) {
processInformation.handle = currentProcess->handleTable.OpenHandle(process, 0, KERNEL_OBJECT_PROCESS); if (handles[i].object) {
CloseHandleToObject(handles[i].object, handles[i].type, handles[i].flags);
}
}
SYSCALL_WRITE(argument2, &processInformation, sizeof(EsProcessInformation)); SYSCALL_RETURN(error, error >= 0);
SYSCALL_RETURN(ES_SUCCESS, false);
#endif
SYSCALL_RETURN(ES_FATAL_ERROR_UNKNOWN_SYSCALL, true);
} }
SYSCALL_IMPLEMENT(ES_SYSCALL_SCREEN_FORCE_UPDATE) { SYSCALL_IMPLEMENT(ES_SYSCALL_SCREEN_FORCE_UPDATE) {
@ -716,24 +732,9 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_CONSTANT_BUFFER_CREATE) {
} }
SYSCALL_IMPLEMENT(ES_SYSCALL_HANDLE_SHARE) { SYSCALL_IMPLEMENT(ES_SYSCALL_HANDLE_SHARE) {
SYSCALL_HANDLE_2(argument0, KERNEL_OBJECT_SHMEM | KERNEL_OBJECT_CONSTANT_BUFFER | KERNEL_OBJECT_PROCESS SYSCALL_HANDLE_2(argument0, HANDLE_SHARE_TYPE_MASK, share);
| KERNEL_OBJECT_DEVICE | KERNEL_OBJECT_NODE | KERNEL_OBJECT_EVENT | KERNEL_OBJECT_PIPE, share);
SYSCALL_HANDLE(argument1, KERNEL_OBJECT_PROCESS, process, Process); SYSCALL_HANDLE(argument1, KERNEL_OBJECT_PROCESS, process, Process);
uint32_t sharedFlags = share.flags; SYSCALL_RETURN(HandleShare(share, process, argument2), false);
if (share.type == KERNEL_OBJECT_SHMEM) {
sharedFlags = argument2; // TODO Sort out flags.
} else if (share.type == KERNEL_OBJECT_NODE) {
sharedFlags = (argument2 & 1) && (share.flags & (ES_FILE_WRITE_SHARED | ES_FILE_WRITE)) ? ES_FILE_READ_SHARED : share.flags;
} else if (share.type == KERNEL_OBJECT_PIPE) {
// TODO Sort out flags.
}
if (!OpenHandleToObject(share.object, share.type, sharedFlags)) {
SYSCALL_RETURN(ES_ERROR_PERMISSION_NOT_GRANTED, false);
} else {
SYSCALL_RETURN(process->handleTable.OpenHandle(share.object, sharedFlags, share.type), false);
}
} }
SYSCALL_IMPLEMENT(ES_SYSCALL_VOLUME_GET_INFORMATION) { SYSCALL_IMPLEMENT(ES_SYSCALL_VOLUME_GET_INFORMATION) {