mirror of https://gitlab.com/nakst/essence
MMArchSafeCopy
This commit is contained in:
parent
ad96f4ee85
commit
7e65dafaa9
|
@ -151,6 +151,22 @@ void InitialiseInstance(EsInstance *instance) {
|
||||||
EsButtonOnCommand(EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Wait"), [] (EsInstance *, EsElement *, EsCommand *) { EsSleep(8000); });
|
EsButtonOnCommand(EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Wait"), [] (EsInstance *, EsElement *, EsCommand *) { EsSleep(8000); });
|
||||||
EsButtonOnCommand(EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Wait, then crash"), [] (EsInstance *, EsElement *, EsCommand *) { EsSleep(8000); EsAssert(false); });
|
EsButtonOnCommand(EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Wait, then crash"), [] (EsInstance *, EsElement *, EsCommand *) { EsSleep(8000); EsAssert(false); });
|
||||||
|
|
||||||
|
EsButtonOnCommand(EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Crash 2"), [] (EsInstance *, EsElement *, EsCommand *) {
|
||||||
|
EsSyscall(ES_SYSCALL_WAIT, 0x8000000000000000, 1, 0, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
EsButtonOnCommand(EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Crash 3"), [] (EsInstance *, EsElement *, EsCommand *) {
|
||||||
|
EsSyscall(ES_SYSCALL_PRINT, 0, 16, 0, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
EsButtonOnCommand(EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Crash 4"), [] (EsInstance *, EsElement *, EsCommand *) {
|
||||||
|
EsSyscall(ES_SYSCALL_WAIT, 0x0000FFFFFFFFFFFF, 1, 0, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
EsButtonOnCommand(EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Crash 5"), [] (EsInstance *, EsElement *, EsCommand *) {
|
||||||
|
EsSyscall(ES_SYSCALL_WAIT, 0x00000FFFFFFFFFFF, 1, 0, 0);
|
||||||
|
});
|
||||||
|
|
||||||
EsButtonOnCommand(EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Announcement 1"), [] (EsInstance *, EsElement *element, EsCommand *) {
|
EsButtonOnCommand(EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Announcement 1"), [] (EsInstance *, EsElement *element, EsCommand *) {
|
||||||
EsRectangle bounds = EsElementGetWindowBounds(element);
|
EsRectangle bounds = EsElementGetWindowBounds(element);
|
||||||
EsAnnouncementShow(element->window, ES_FLAGS_DEFAULT, (bounds.l + bounds.r) / 2, (bounds.t + bounds.b) / 2, "Hello, world!", -1);
|
EsAnnouncementShow(element->window, ES_FLAGS_DEFAULT, (bounds.l + bounds.r) / 2, (bounds.t + bounds.b) / 2, "Hello, world!", -1);
|
||||||
|
|
|
@ -70,9 +70,6 @@ struct AsyncTask {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CPULocalStorage {
|
struct CPULocalStorage {
|
||||||
// Must be the first fields; used in __cyg_profile_func_enter.
|
|
||||||
uintptr_t kernelFunctionCallCount;
|
|
||||||
|
|
||||||
struct Thread *currentThread,
|
struct Thread *currentThread,
|
||||||
*idleThread,
|
*idleThread,
|
||||||
*asyncTaskThread;
|
*asyncTaskThread;
|
||||||
|
|
|
@ -255,6 +255,8 @@ void MMArchInitialiseVAS();
|
||||||
bool MMArchInitialiseUserSpace(MMSpace *space);
|
bool MMArchInitialiseUserSpace(MMSpace *space);
|
||||||
bool MMArchCommitPageTables(MMSpace *space, MMRegion *region);
|
bool MMArchCommitPageTables(MMSpace *space, MMRegion *region);
|
||||||
bool MMArchMakePageWritable(MMSpace *space, uintptr_t virtualAddress);
|
bool MMArchMakePageWritable(MMSpace *space, uintptr_t virtualAddress);
|
||||||
|
bool MMArchIsBufferInUserRange(uintptr_t baseAddress, size_t byteCount);
|
||||||
|
extern "C" bool MMArchSafeCopy(uintptr_t destinationAddress, uintptr_t sourceAddress, size_t byteCount); // Returns false if a page fault occured during the copy.
|
||||||
void MMFreeVAS(MMSpace *space);
|
void MMFreeVAS(MMSpace *space);
|
||||||
void MMFinalizeVAS(MMSpace *space);
|
void MMFinalizeVAS(MMSpace *space);
|
||||||
|
|
||||||
|
|
|
@ -227,6 +227,7 @@ enum KernelObjectType : uint32_t {
|
||||||
KERNEL_OBJECT_CONNECTION = 0x00004000, // A network connection.
|
KERNEL_OBJECT_CONNECTION = 0x00004000, // A network connection.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO Rename to KObjectReference and KObjectDereference?
|
||||||
void CloseHandleToObject(void *object, KernelObjectType type, uint32_t flags = 0);
|
void CloseHandleToObject(void *object, KernelObjectType type, uint32_t flags = 0);
|
||||||
bool OpenHandleToObject(void *object, KernelObjectType type, uint32_t flags = 0, bool maybeHasNoHandles = false);
|
bool OpenHandleToObject(void *object, KernelObjectType type, uint32_t flags = 0, bool maybeHasNoHandles = false);
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ struct POSIXThread {
|
||||||
Process *forkProcess;
|
Process *forkProcess;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO Use SYSCALL_READ and SYSCALL_WRITE.
|
||||||
#define SYSCALL_BUFFER_POSIX(address, length, index, write) \
|
#define SYSCALL_BUFFER_POSIX(address, length, index, write) \
|
||||||
MMRegion *_region ## index = MMFindAndPinRegion(currentVMM, (address), (length)); \
|
MMRegion *_region ## index = MMFindAndPinRegion(currentVMM, (address), (length)); \
|
||||||
if (!_region ## index && !fromKernel) { KernelLog(LOG_ERROR, "POSIX", "EFAULT", "POSIX application EFAULT at %x.\n", address); return -EFAULT; } \
|
if (!_region ## index && !fromKernel) { KernelLog(LOG_ERROR, "POSIX", "EFAULT", "POSIX application EFAULT at %x.\n", address); return -EFAULT; } \
|
||||||
|
|
|
@ -43,6 +43,9 @@ struct Thread {
|
||||||
// Used by the asynchronous task threads,
|
// Used by the asynchronous task threads,
|
||||||
// and the memory manager's balancer.
|
// and the memory manager's balancer.
|
||||||
|
|
||||||
|
// ** Must be the first item in the structure; see MMArchSafeCopy. **
|
||||||
|
bool inSafeCopy;
|
||||||
|
|
||||||
LinkedItem<Thread> item; // Entry in relevent thread queue or blockedThreads list for mutexes/writer locks.
|
LinkedItem<Thread> item; // Entry in relevent thread queue or blockedThreads list for mutexes/writer locks.
|
||||||
LinkedItem<Thread> allItem; // Entry in the allThreads list.
|
LinkedItem<Thread> allItem; // Entry in the allThreads list.
|
||||||
LinkedItem<Thread> processItem; // Entry in the process's list of threads.
|
LinkedItem<Thread> processItem; // Entry in the process's list of threads.
|
||||||
|
|
|
@ -128,32 +128,19 @@ bool MessageQueue::GetMessage(_EsMessageWithObject *_message) {
|
||||||
CHECK_OBJECT(_object ## index); \
|
CHECK_OBJECT(_object ## index); \
|
||||||
*((void **) &__object) = (_object ## index).object;
|
*((void **) &__object) = (_object ## index).object;
|
||||||
#define SYSCALL_READ(destination, source, length) \
|
#define SYSCALL_READ(destination, source, length) \
|
||||||
do { if ((length) > 0) { \
|
if (!MMArchIsBufferInUserRange(source, length) || !MMArchSafeCopy((uintptr_t) (destination), source, length)) \
|
||||||
SYSCALL_BUFFER((uintptr_t) (source), (length), 0, false); \
|
SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true);
|
||||||
EsMemoryCopy((void *) (destination), (const void *) (source), (length)); \
|
|
||||||
__sync_synchronize(); \
|
|
||||||
}} while (0)
|
|
||||||
#define SYSCALL_READ_HEAP(destination, source, length) \
|
#define SYSCALL_READ_HEAP(destination, source, length) \
|
||||||
if ((length) > 0) { \
|
*(void **) &(destination) = EsHeapAllocate((length), false, K_FIXED); \
|
||||||
void *x = EsHeapAllocate((length), false, K_FIXED); \
|
if ((length) != 0 && !(destination)) SYSCALL_RETURN(ES_ERROR_INSUFFICIENT_RESOURCES, false); \
|
||||||
if (!x) SYSCALL_RETURN(ES_ERROR_INSUFFICIENT_RESOURCES, false); \
|
EsDefer(EsHeapFree((destination), (length), K_FIXED)); \
|
||||||
bool success = false; \
|
SYSCALL_READ(destination, source, length);
|
||||||
EsDefer(if (!success) EsHeapFree(x, 0, K_FIXED);); \
|
|
||||||
SYSCALL_BUFFER((uintptr_t) (source), (length), 0, false); \
|
|
||||||
*((void **) &(destination)) = x; \
|
|
||||||
EsMemoryCopy((void *) (destination), (const void *) (source), (length)); \
|
|
||||||
success = true; \
|
|
||||||
__sync_synchronize(); \
|
|
||||||
} else destination = nullptr; EsDefer(EsHeapFree(destination, 0, K_FIXED))
|
|
||||||
#define SYSCALL_WRITE(destination, source, length) \
|
#define SYSCALL_WRITE(destination, source, length) \
|
||||||
do { \
|
if (!MMArchIsBufferInUserRange(destination, length) || !MMArchSafeCopy(destination, (uintptr_t) (source), length)) \
|
||||||
__sync_synchronize(); \
|
SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true);
|
||||||
SYSCALL_BUFFER((uintptr_t) (destination), (length), 0, true); \
|
|
||||||
EsMemoryCopy((void *) (destination), (const void *) (source), (length)); \
|
|
||||||
} while (0)
|
|
||||||
#define SYSCALL_ARGUMENTS uintptr_t argument0, uintptr_t argument1, uintptr_t argument2, uintptr_t argument3, \
|
#define SYSCALL_ARGUMENTS uintptr_t argument0, uintptr_t argument1, uintptr_t argument2, uintptr_t argument3, \
|
||||||
Thread *currentThread, Process *currentProcess, MMSpace *currentVMM, uintptr_t *userStackPointer, bool *fatalError
|
Thread *currentThread, Process *currentProcess, MMSpace *currentVMM, uintptr_t *userStackPointer, bool *fatalError
|
||||||
#define SYSCALL_IMPLEMENT(_type) uintptr_t Do ## _type ( SYSCALL_ARGUMENTS )
|
#define SYSCALL_IMPLEMENT(_type) uintptr_t Do ## _type (SYSCALL_ARGUMENTS)
|
||||||
#define SYSCALL_RETURN(value, fatal) do { *fatalError = fatal; return (value); } while (0)
|
#define SYSCALL_RETURN(value, fatal) do { *fatalError = fatal; return (value); } while (0)
|
||||||
#define SYSCALL_PERMISSION(x) do { if ((x) != (currentProcess->permissions & (x))) { *fatalError = true; return ES_FATAL_ERROR_INSUFFICIENT_PERMISSIONS; } } while (0)
|
#define SYSCALL_PERMISSION(x) do { if ((x) != (currentProcess->permissions & (x))) { *fatalError = true; return ES_FATAL_ERROR_INSUFFICIENT_PERMISSIONS; } } while (0)
|
||||||
typedef uintptr_t (*SyscallFunction)(SYSCALL_ARGUMENTS);
|
typedef uintptr_t (*SyscallFunction)(SYSCALL_ARGUMENTS);
|
||||||
|
@ -1414,8 +1401,8 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_YIELD_SCHEDULER) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SYSCALL_IMPLEMENT(ES_SYSCALL_SYSTEM_GET_CONSTANTS) {
|
SYSCALL_IMPLEMENT(ES_SYSCALL_SYSTEM_GET_CONSTANTS) {
|
||||||
SYSCALL_BUFFER(argument0, sizeof(uint64_t) * ES_SYSTEM_CONSTANT_COUNT, 1, true /* write */);
|
uint64_t systemConstants[ES_SYSTEM_CONSTANT_COUNT];
|
||||||
uint64_t *systemConstants = (uint64_t *) argument0;
|
EsMemoryZero(systemConstants, sizeof(systemConstants));
|
||||||
systemConstants[ES_SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND] = timeStampTicksPerMs / 1000;
|
systemConstants[ES_SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND] = timeStampTicksPerMs / 1000;
|
||||||
systemConstants[ES_SYSTEM_CONSTANT_WINDOW_INSET] = WINDOW_INSET;
|
systemConstants[ES_SYSTEM_CONSTANT_WINDOW_INSET] = WINDOW_INSET;
|
||||||
systemConstants[ES_SYSTEM_CONSTANT_CONTAINER_TAB_BAND_HEIGHT] = CONTAINER_TAB_BAND_HEIGHT;
|
systemConstants[ES_SYSTEM_CONSTANT_CONTAINER_TAB_BAND_HEIGHT] = CONTAINER_TAB_BAND_HEIGHT;
|
||||||
|
@ -1423,6 +1410,7 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_SYSTEM_GET_CONSTANTS) {
|
||||||
systemConstants[ES_SYSTEM_CONSTANT_UI_SCALE] = UI_SCALE;
|
systemConstants[ES_SYSTEM_CONSTANT_UI_SCALE] = UI_SCALE;
|
||||||
systemConstants[ES_SYSTEM_CONSTANT_BORDER_THICKNESS] = BORDER_THICKNESS;
|
systemConstants[ES_SYSTEM_CONSTANT_BORDER_THICKNESS] = BORDER_THICKNESS;
|
||||||
systemConstants[ES_SYSTEM_CONSTANT_OPTIMAL_WORK_QUEUE_THREAD_COUNT] = scheduler.currentProcessorID; // TODO Update this as processors are added/removed.
|
systemConstants[ES_SYSTEM_CONSTANT_OPTIMAL_WORK_QUEUE_THREAD_COUNT] = scheduler.currentProcessorID; // TODO Update this as processors are added/removed.
|
||||||
|
SYSCALL_WRITE(argument0, systemConstants, sizeof(systemConstants));
|
||||||
SYSCALL_RETURN(ES_SUCCESS, false);
|
SYSCALL_RETURN(ES_SUCCESS, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -282,6 +282,13 @@ void MMArchMapPage(MMSpace *space, uintptr_t physicalAddress, uintptr_t virtualA
|
||||||
ProcessorInvalidatePage(oldVirtualAddress);
|
ProcessorInvalidatePage(oldVirtualAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MMArchIsBufferInUserRange(uintptr_t baseAddress, size_t byteCount) {
|
||||||
|
if (baseAddress & 0xFFFF800000000000) return false;
|
||||||
|
if (byteCount & 0xFFFF800000000000) return false;
|
||||||
|
if ((baseAddress + byteCount) & 0xFFFF800000000000) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool MMArchHandlePageFault(uintptr_t address, uint32_t flags) {
|
bool MMArchHandlePageFault(uintptr_t address, uint32_t flags) {
|
||||||
// EsPrint("Fault %x\n", address);
|
// EsPrint("Fault %x\n", address);
|
||||||
address &= ~(K_PAGE_SIZE - 1);
|
address &= ~(K_PAGE_SIZE - 1);
|
||||||
|
@ -883,7 +890,7 @@ extern "C" void InterruptHandler(InterruptContext *context) {
|
||||||
if (interrupt < 0x20) {
|
if (interrupt < 0x20) {
|
||||||
// If we received a non-maskable interrupt, halt execution.
|
// If we received a non-maskable interrupt, halt execution.
|
||||||
if (interrupt == 2) {
|
if (interrupt == 2) {
|
||||||
GetLocalStorage()->panicContext = context;
|
local->panicContext = context;
|
||||||
ProcessorHalt();
|
ProcessorHalt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -992,20 +999,19 @@ extern "C" void InterruptHandler(InterruptContext *context) {
|
||||||
ProcessorEnableInterrupts();
|
ProcessorEnableInterrupts();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
if (local && local->spinlockCount && ((context->cr2 >= 0xFFFF900000000000 && context->cr2 < 0xFFFFF00000000000)
|
||||||
CPULocalStorage *storage = GetLocalStorage();
|
|| context->cr2 < 0x8000000000000000)) {
|
||||||
|
KernelPanic("HandlePageFault - Page fault occurred in critical section at %x (S = %x, B = %x, LG = %x) (CR2 = %x).\n",
|
||||||
if (storage && storage->spinlockCount && ((context->cr2 >= 0xFFFF900000000000 && context->cr2 < 0xFFFFF00000000000)
|
context->rip, context->rsp, context->rbp, local->currentThread->lastKnownExecutionAddress, context->cr2);
|
||||||
|| context->cr2 < 0x8000000000000000)) {
|
|
||||||
KernelPanic("HandlePageFault - Page fault occurred in critical section at %x (S = %x, B = %x, LG = %x) (CR2 = %x).\n",
|
|
||||||
context->rip, context->rsp, context->rbp, storage->currentThread->lastKnownExecutionAddress, context->cr2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!MMArchHandlePageFault(context->cr2, MM_HANDLE_PAGE_FAULT_FOR_SUPERVISOR
|
if (!MMArchHandlePageFault(context->cr2, MM_HANDLE_PAGE_FAULT_FOR_SUPERVISOR
|
||||||
| ((context->errorCode & 2) ? MM_HANDLE_PAGE_FAULT_WRITE : 0))) {
|
| ((context->errorCode & 2) ? MM_HANDLE_PAGE_FAULT_WRITE : 0))) {
|
||||||
goto fault;
|
if (local->currentThread->inSafeCopy && context->cr2 < 0x8000000000000000) {
|
||||||
|
context->rip = context->r8; // See definition of MMArchSafeCopy.
|
||||||
|
} else {
|
||||||
|
goto fault;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessorDisableInterrupts();
|
ProcessorDisableInterrupts();
|
||||||
|
|
|
@ -336,7 +336,7 @@ EnableCPUFeatures:
|
||||||
wrmsr
|
wrmsr
|
||||||
.no_tce_support:
|
.no_tce_support:
|
||||||
|
|
||||||
; Enable write protect, so copy-on-write works in the kernel.
|
; Enable write protect, so copy-on-write works in the kernel, and MMArchSafeCopy will page fault in read-only regions.
|
||||||
mov rax,cr0
|
mov rax,cr0
|
||||||
or rax,1 << 16
|
or rax,1 << 16
|
||||||
mov cr0,rax
|
mov cr0,rax
|
||||||
|
@ -909,6 +909,21 @@ ProcessorInstallTSS:
|
||||||
pop rbx
|
pop rbx
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
[global MMArchSafeCopy]
|
||||||
|
MMArchSafeCopy:
|
||||||
|
call GetCurrentThread
|
||||||
|
mov byte [rax + 0],1 ; see definition of Thread
|
||||||
|
mov rcx,rdx
|
||||||
|
mov r8,.error ; where to jump to if we get a page fault
|
||||||
|
rep movsb
|
||||||
|
mov byte [rax + 0],0
|
||||||
|
mov al,1
|
||||||
|
ret
|
||||||
|
.error: ; we got a page fault in a user address, return false
|
||||||
|
mov byte [rax + 0],0
|
||||||
|
mov al,0
|
||||||
|
ret
|
||||||
|
|
||||||
[global ArchResetCPU]
|
[global ArchResetCPU]
|
||||||
ArchResetCPU:
|
ArchResetCPU:
|
||||||
in al,0x64
|
in al,0x64
|
||||||
|
|
Loading…
Reference in New Issue