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, 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 *) {
|
||||
EsRectangle bounds = EsElementGetWindowBounds(element);
|
||||
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 {
|
||||
// Must be the first fields; used in __cyg_profile_func_enter.
|
||||
uintptr_t kernelFunctionCallCount;
|
||||
|
||||
struct Thread *currentThread,
|
||||
*idleThread,
|
||||
*asyncTaskThread;
|
||||
|
|
|
@ -255,6 +255,8 @@ void MMArchInitialiseVAS();
|
|||
bool MMArchInitialiseUserSpace(MMSpace *space);
|
||||
bool MMArchCommitPageTables(MMSpace *space, MMRegion *region);
|
||||
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 MMFinalizeVAS(MMSpace *space);
|
||||
|
||||
|
|
|
@ -227,6 +227,7 @@ enum KernelObjectType : uint32_t {
|
|||
KERNEL_OBJECT_CONNECTION = 0x00004000, // A network connection.
|
||||
};
|
||||
|
||||
// TODO Rename to KObjectReference and KObjectDereference?
|
||||
void CloseHandleToObject(void *object, KernelObjectType type, uint32_t flags = 0);
|
||||
bool OpenHandleToObject(void *object, KernelObjectType type, uint32_t flags = 0, bool maybeHasNoHandles = false);
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ struct POSIXThread {
|
|||
Process *forkProcess;
|
||||
};
|
||||
|
||||
// TODO Use SYSCALL_READ and SYSCALL_WRITE.
|
||||
#define SYSCALL_BUFFER_POSIX(address, length, index, write) \
|
||||
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; } \
|
||||
|
|
|
@ -43,6 +43,9 @@ struct Thread {
|
|||
// Used by the asynchronous task threads,
|
||||
// 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> allItem; // Entry in the allThreads list.
|
||||
LinkedItem<Thread> processItem; // Entry in the process's list of threads.
|
||||
|
|
|
@ -128,32 +128,19 @@ bool MessageQueue::GetMessage(_EsMessageWithObject *_message) {
|
|||
CHECK_OBJECT(_object ## index); \
|
||||
*((void **) &__object) = (_object ## index).object;
|
||||
#define SYSCALL_READ(destination, source, length) \
|
||||
do { if ((length) > 0) { \
|
||||
SYSCALL_BUFFER((uintptr_t) (source), (length), 0, false); \
|
||||
EsMemoryCopy((void *) (destination), (const void *) (source), (length)); \
|
||||
__sync_synchronize(); \
|
||||
}} while (0)
|
||||
if (!MMArchIsBufferInUserRange(source, length) || !MMArchSafeCopy((uintptr_t) (destination), source, length)) \
|
||||
SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true);
|
||||
#define SYSCALL_READ_HEAP(destination, source, length) \
|
||||
if ((length) > 0) { \
|
||||
void *x = EsHeapAllocate((length), false, K_FIXED); \
|
||||
if (!x) SYSCALL_RETURN(ES_ERROR_INSUFFICIENT_RESOURCES, false); \
|
||||
bool success = false; \
|
||||
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))
|
||||
*(void **) &(destination) = EsHeapAllocate((length), false, K_FIXED); \
|
||||
if ((length) != 0 && !(destination)) SYSCALL_RETURN(ES_ERROR_INSUFFICIENT_RESOURCES, false); \
|
||||
EsDefer(EsHeapFree((destination), (length), K_FIXED)); \
|
||||
SYSCALL_READ(destination, source, length);
|
||||
#define SYSCALL_WRITE(destination, source, length) \
|
||||
do { \
|
||||
__sync_synchronize(); \
|
||||
SYSCALL_BUFFER((uintptr_t) (destination), (length), 0, true); \
|
||||
EsMemoryCopy((void *) (destination), (const void *) (source), (length)); \
|
||||
} while (0)
|
||||
if (!MMArchIsBufferInUserRange(destination, length) || !MMArchSafeCopy(destination, (uintptr_t) (source), length)) \
|
||||
SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true);
|
||||
#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
|
||||
#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_PERMISSION(x) do { if ((x) != (currentProcess->permissions & (x))) { *fatalError = true; return ES_FATAL_ERROR_INSUFFICIENT_PERMISSIONS; } } while (0)
|
||||
typedef uintptr_t (*SyscallFunction)(SYSCALL_ARGUMENTS);
|
||||
|
@ -1414,8 +1401,8 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_YIELD_SCHEDULER) {
|
|||
}
|
||||
|
||||
SYSCALL_IMPLEMENT(ES_SYSCALL_SYSTEM_GET_CONSTANTS) {
|
||||
SYSCALL_BUFFER(argument0, sizeof(uint64_t) * ES_SYSTEM_CONSTANT_COUNT, 1, true /* write */);
|
||||
uint64_t *systemConstants = (uint64_t *) argument0;
|
||||
uint64_t systemConstants[ES_SYSTEM_CONSTANT_COUNT];
|
||||
EsMemoryZero(systemConstants, sizeof(systemConstants));
|
||||
systemConstants[ES_SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND] = timeStampTicksPerMs / 1000;
|
||||
systemConstants[ES_SYSTEM_CONSTANT_WINDOW_INSET] = WINDOW_INSET;
|
||||
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_BORDER_THICKNESS] = BORDER_THICKNESS;
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -282,6 +282,13 @@ void MMArchMapPage(MMSpace *space, uintptr_t physicalAddress, uintptr_t virtualA
|
|||
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) {
|
||||
// EsPrint("Fault %x\n", address);
|
||||
address &= ~(K_PAGE_SIZE - 1);
|
||||
|
@ -883,7 +890,7 @@ extern "C" void InterruptHandler(InterruptContext *context) {
|
|||
if (interrupt < 0x20) {
|
||||
// If we received a non-maskable interrupt, halt execution.
|
||||
if (interrupt == 2) {
|
||||
GetLocalStorage()->panicContext = context;
|
||||
local->panicContext = context;
|
||||
ProcessorHalt();
|
||||
}
|
||||
|
||||
|
@ -992,20 +999,19 @@ extern "C" void InterruptHandler(InterruptContext *context) {
|
|||
ProcessorEnableInterrupts();
|
||||
}
|
||||
|
||||
{
|
||||
CPULocalStorage *storage = GetLocalStorage();
|
||||
|
||||
if (storage && storage->spinlockCount && ((context->cr2 >= 0xFFFF900000000000 && context->cr2 < 0xFFFFF00000000000)
|
||||
|| 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 (local && local->spinlockCount && ((context->cr2 >= 0xFFFF900000000000 && context->cr2 < 0xFFFFF00000000000)
|
||||
|| 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, local->currentThread->lastKnownExecutionAddress, context->cr2);
|
||||
}
|
||||
|
||||
|
||||
if (!MMArchHandlePageFault(context->cr2, MM_HANDLE_PAGE_FAULT_FOR_SUPERVISOR
|
||||
| ((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();
|
||||
|
|
|
@ -336,7 +336,7 @@ EnableCPUFeatures:
|
|||
wrmsr
|
||||
.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
|
||||
or rax,1 << 16
|
||||
mov cr0,rax
|
||||
|
@ -909,6 +909,21 @@ ProcessorInstallTSS:
|
|||
pop rbx
|
||||
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]
|
||||
ArchResetCPU:
|
||||
in al,0x64
|
||||
|
|
Loading…
Reference in New Issue