MMArchSafeCopy

This commit is contained in:
nakst 2021-08-15 05:54:05 +01:00
parent ad96f4ee85
commit 7e65dafaa9
9 changed files with 68 additions and 39 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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; } \

View File

@ -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.

View File

@ -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);
}

View File

@ -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();

View File

@ -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