mirror of https://gitlab.com/nakst/essence
remove KObject
This commit is contained in:
parent
c09eb6c78e
commit
1ad024a542
kernel
|
@ -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.
|
||||
|
|
|
@ -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(¤tProcess->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) {
|
||||
|
|
Loading…
Reference in New Issue