remove KObject

This commit is contained in:
nakst 2021-09-11 15:50:03 +01:00
parent c09eb6c78e
commit 1ad024a542
2 changed files with 82 additions and 101 deletions

View File

@ -79,63 +79,22 @@ struct HandleTable {
bool CloseHandle(EsHandle handle);
void ModifyFlags(EsHandle handle, uint32_t newFlags);
// Resolve the handle if it is valid and return the type in type.
// Resolve the handle if it is valid.
// The initial value of type is used as a mask of expected object types for the handle.
void ResolveHandle(struct KObject *object, EsHandle handle);
#define RESOLVE_HANDLE_FAILED (0)
#define RESOLVE_HANDLE_NO_CLOSE (1)
#define RESOLVE_HANDLE_NORMAL (2)
uint8_t ResolveHandle(Handle *outHandle, EsHandle inHandle, KernelObjectType typeMask);
void Destroy();
};
struct KObject {
void Initialise(HandleTable *handleTable, EsHandle _handle, KernelObjectType _type);
KObject() { EsMemoryZero(this, sizeof(*this)); }
KObject(Process *process, EsHandle _handle, KernelObjectType _type);
KObject(HandleTable *handleTable, EsHandle _handle, KernelObjectType _type);
~KObject() {
if (!checked && valid) {
KernelPanic("KObject - Object not checked!\n");
}
if (parentObject && close) {
CloseHandleToObject(parentObject, parentType, parentFlags);
}
}
void *object, *parentObject;
uint32_t flags, parentFlags;
KernelObjectType type, parentType;
bool valid, checked, close, softFailure;
};
void InitialiseObjectManager();
#endif
#ifdef IMPLEMENTATION
KObject::KObject(Process *process, EsHandle _handle, KernelObjectType _type) {
EsMemoryZero(this, sizeof(*this));
Initialise(&process->handleTable, _handle, _type);
}
KObject::KObject(HandleTable *handleTable, EsHandle _handle, KernelObjectType _type) {
EsMemoryZero(this, sizeof(*this));
Initialise(handleTable, _handle, _type);
}
void KObject::Initialise(HandleTable *handleTable, EsHandle _handle, KernelObjectType _type) {
type = _type;
handleTable->ResolveHandle(this, _handle);
parentObject = object, parentType = type, parentFlags = flags;
if (!valid) {
KernelLog(LOG_ERROR, "Object Manager", "invalid handle", "KObject::Initialise - Invalid handle %d for type mask %x.\n", _handle, _type);
}
}
// A lock used to change the handle count on several objects.
// TODO Make changing handle count lockless wherever possible?
KMutex objectHandleCountChange;
@ -462,43 +421,48 @@ void HandleTable::ModifyFlags(EsHandle handle, uint32_t newFlags) {
_handle->flags = newFlags;
}
void HandleTable::ResolveHandle(KObject *object, EsHandle handle) {
KernelObjectType requestedType = object->type;
object->type = COULD_NOT_RESOLVE_HANDLE;
uint8_t HandleTable::ResolveHandle(Handle *outHandle, EsHandle inHandle, KernelObjectType typeMask) {
// Special handles.
if (handle == ES_CURRENT_THREAD && (requestedType & KERNEL_OBJECT_THREAD)) {
object->type = KERNEL_OBJECT_THREAD, object->valid = true, object->object = GetCurrentThread();
return;
} else if (handle == ES_CURRENT_PROCESS && (requestedType & KERNEL_OBJECT_PROCESS)) {
object->type = KERNEL_OBJECT_PROCESS, object->valid = true, object->object = GetCurrentThread()->process;
return;
} else if (handle == ES_INVALID_HANDLE && (requestedType & KERNEL_OBJECT_NONE)) {
object->type = KERNEL_OBJECT_NONE, object->valid = true;
return;
if (inHandle == ES_CURRENT_THREAD && (typeMask & KERNEL_OBJECT_THREAD)) {
outHandle->type = KERNEL_OBJECT_THREAD;
outHandle->object = GetCurrentThread();
outHandle->flags = 0;
return RESOLVE_HANDLE_NO_CLOSE;
} else if (inHandle == ES_CURRENT_PROCESS && (typeMask & KERNEL_OBJECT_PROCESS)) {
outHandle->type = KERNEL_OBJECT_PROCESS;
outHandle->object = GetCurrentThread()->process;
outHandle->flags = 0;
return RESOLVE_HANDLE_NO_CLOSE;
} else if (inHandle == ES_INVALID_HANDLE && (typeMask & KERNEL_OBJECT_NONE)) {
outHandle->type = KERNEL_OBJECT_NONE;
outHandle->object = nullptr;
outHandle->flags = 0;
return RESOLVE_HANDLE_NO_CLOSE;
}
// Check that the handle is within the correct bounds.
if ((!handle) || handle >= HANDLE_TABLE_L1_ENTRIES * HANDLE_TABLE_L2_ENTRIES) {
return;
if ((!inHandle) || inHandle >= HANDLE_TABLE_L1_ENTRIES * HANDLE_TABLE_L2_ENTRIES) {
return RESOLVE_HANDLE_FAILED;
}
KMutexAcquire(&lock);
EsDefer(KMutexRelease(&lock));
HandleTableL2 *l2 = l1r.t[handle / HANDLE_TABLE_L2_ENTRIES];
if (!l2) return;
HandleTableL2 *l2 = l1r.t[inHandle / HANDLE_TABLE_L2_ENTRIES];
if (!l2) return RESOLVE_HANDLE_FAILED;
Handle *_handle = l2->t + (handle % HANDLE_TABLE_L2_ENTRIES);
Handle *_handle = l2->t + (inHandle % HANDLE_TABLE_L2_ENTRIES);
if ((_handle->type & requestedType) && (_handle->object)) {
if ((_handle->type & typeMask) && (_handle->object)) {
// Open a handle to the object so that it can't be destroyed while the system call is still using it.
// The handle is closed in the KObject's destructor.
if (OpenHandleToObject(_handle->object, _handle->type, _handle->flags)) {
object->type = _handle->type, object->object = _handle->object, object->flags = _handle->flags;
object->valid = object->close = true;
*outHandle = *_handle;
return RESOLVE_HANDLE_NORMAL;
}
}
return RESOLVE_HANDLE_FAILED;
}
// TODO Switch the order of flags and type, so that the default value of flags can be 0.

View File

@ -115,7 +115,6 @@ bool MessageQueue::GetMessage(_EsMessageWithObject *_message) {
return true;
}
#define CHECK_OBJECT(x) if (!x.valid) SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_HANDLE, !x.softFailure); else x.checked = true
#define SYSCALL_BUFFER_LIMIT (64 * 1024 * 1024) // To prevent overflow and DOS attacks.
#define SYSCALL_BUFFER(address, length, index, write) \
MMRegion *_region ## index = MMFindAndPinRegion(currentVMM, (address), (length)); \
@ -123,18 +122,18 @@ bool MessageQueue::GetMessage(_EsMessageWithObject *_message) {
EsDefer(if (_region ## index) MMUnpinRegion(currentVMM, _region ## index)); \
if (write && (_region ## index->flags & MM_REGION_READ_ONLY) && (~_region ## index->flags & MM_REGION_COPY_ON_WRITE)) \
SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true);
#define SYSCALL_HANDLE(handle, type, __object, variableType) \
KObject ES_C_PREPROCESSOR_JOIN(_object, __LINE__)(currentProcess, handle, type); \
CHECK_OBJECT(ES_C_PREPROCESSOR_JOIN(_object, __LINE__)); \
variableType *const __object = (variableType *) (ES_C_PREPROCESSOR_JOIN(_object, __LINE__)).object
#define SYSCALL_HANDLE_2(handle, _type, out) \
KObject ES_C_PREPROCESSOR_JOIN(_object, __LINE__)(currentProcess, handle, _type); \
CHECK_OBJECT(ES_C_PREPROCESSOR_JOIN(_object, __LINE__)); \
const Handle out = { \
.object = (ES_C_PREPROCESSOR_JOIN(_object, __LINE__)).object, \
.flags = (ES_C_PREPROCESSOR_JOIN(_object, __LINE__)).flags, \
.type = (ES_C_PREPROCESSOR_JOIN(_object, __LINE__)).type, \
}
Handle _ ## out; \
uint8_t status_ ## out = currentProcess->handleTable.ResolveHandle(&_ ## out, handle, _type); \
if (status_ ## out == RESOLVE_HANDLE_FAILED) SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_HANDLE, true); \
EsDefer(if (status_ ## out == RESOLVE_HANDLE_NORMAL) CloseHandleToObject(_ ## out.object, _ ## out.type, _ ## out.flags)); \
const Handle out = _ ## out
#define SYSCALL_HANDLE(handle, _type, out, variableType) \
Handle _ ## out; \
uint8_t status_ ## out = currentProcess->handleTable.ResolveHandle(&_ ## out, handle, _type); \
if (status_ ## out == RESOLVE_HANDLE_FAILED) SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_HANDLE, true); \
EsDefer(if (status_ ## out == RESOLVE_HANDLE_NORMAL) CloseHandleToObject(_ ## out.object, _ ## out.type, _ ## out.flags)); \
variableType *const out = (variableType *) _ ## out.object
#define SYSCALL_READ(destination, source, length) \
if (!MMArchIsBufferInUserRange(source, length) || !MMArchSafeCopy((uintptr_t) (destination), source, length)) \
SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true);
@ -866,15 +865,22 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_WAIT) {
}
EsHandle handles[ES_MAX_WAIT_COUNT];
KEvent *events[ES_MAX_WAIT_COUNT];
Handle _objects[ES_MAX_WAIT_COUNT];
uint8_t status[ES_MAX_WAIT_COUNT];
bool handleErrors = false;
uintptr_t waitReturnValue;
SYSCALL_READ(handles, argument0, argument1 * sizeof(EsHandle));
KEvent *events[ES_MAX_WAIT_COUNT];
KObject _objects[ES_MAX_WAIT_COUNT] = {};
for (uintptr_t i = 0; i < argument1; i++) {
_objects[i].Initialise(&currentProcess->handleTable, handles[i],
KERNEL_OBJECT_PROCESS | KERNEL_OBJECT_THREAD | KERNEL_OBJECT_EVENT | KERNEL_OBJECT_EVENT_SINK);
CHECK_OBJECT(_objects[i]);
KernelObjectType typeMask = KERNEL_OBJECT_PROCESS | KERNEL_OBJECT_THREAD | KERNEL_OBJECT_EVENT | KERNEL_OBJECT_EVENT_SINK;
status[i] = currentProcess->handleTable.ResolveHandle(&_objects[i], handles[i], typeMask);
if (status[i] == RESOLVE_HANDLE_FAILED) {
handleErrors = true;
continue;
}
void *object = _objects[i].object;
@ -901,28 +907,39 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_WAIT) {
}
}
size_t waitObjectCount = argument1;
KTimer timer = {};
if (!handleErrors) {
size_t waitObjectCount = argument1;
KTimer timer = {};
if (argument2 != (uintptr_t) ES_WAIT_NO_TIMEOUT) {
KTimerSet(&timer, argument2);
events[waitObjectCount++] = &timer.event;
if (argument2 != (uintptr_t) ES_WAIT_NO_TIMEOUT) {
KTimerSet(&timer, argument2);
events[waitObjectCount++] = &timer.event;
}
currentThread->terminatableState = THREAD_USER_BLOCK_REQUEST;
waitReturnValue = scheduler.WaitEvents(events, waitObjectCount);
currentThread->terminatableState = THREAD_IN_SYSCALL;
if (waitReturnValue == argument1) {
waitReturnValue = ES_ERROR_TIMEOUT_REACHED;
}
if (argument2 != (uintptr_t) ES_WAIT_NO_TIMEOUT) {
KTimerRemove(&timer);
}
}
uintptr_t waitReturnValue;
currentThread->terminatableState = THREAD_USER_BLOCK_REQUEST;
waitReturnValue = scheduler.WaitEvents(events, waitObjectCount);
currentThread->terminatableState = THREAD_IN_SYSCALL;
if (waitReturnValue == argument1) {
waitReturnValue = ES_ERROR_TIMEOUT_REACHED;
for (uintptr_t i = 0; i < argument1; i++) {
if (status[i] == RESOLVE_HANDLE_NORMAL) {
CloseHandleToObject(_objects[i].object, _objects[i].type, _objects[i].flags);
}
}
if (argument2 != (uintptr_t) ES_WAIT_NO_TIMEOUT) {
KTimerRemove(&timer);
if (handleErrors) {
SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_HANDLE, true);
} else {
SYSCALL_RETURN(waitReturnValue, false);
}
SYSCALL_RETURN(waitReturnValue, false);
}
SYSCALL_IMPLEMENT(ES_SYSCALL_WINDOW_SET_CURSOR) {