diff --git a/apps/installer.cpp b/apps/installer.cpp index 9392c3d..4c1fbee 100644 --- a/apps/installer.cpp +++ b/apps/installer.cpp @@ -1,3 +1,5 @@ +// TODO Report errors. +// TODO GPT support. // TODO Handle crashing? // TODO Write any modified settings during installation. @@ -84,6 +86,9 @@ bool onWaitScreen, startedInstallation; EsBlockDeviceInformation blockDeviceInformation; EsHandle driveHandle; EsFileOffset partitionOffset; +EsUniqueIdentifier installationIdentifier; +EsMountPoint newFileSystemMountPoint; +EsHandle mountNewFileSystemEvent; ///////////////////////////////////////////// @@ -479,8 +484,6 @@ EsError Install() { m.user.context1.u = 6; EsMessagePost(nullptr, &m); - EsUniqueIdentifier installationIdentifier; - for (int i = 0; i < 16; i++) { installationIdentifier.d[i] = EsRandomU8(); } @@ -488,22 +491,31 @@ EsError Install() { Format(partitionBytes, interfaceString_InstallerVolumeLabel, installationIdentifier, kernel, kernelBytes); FlushWriteBuffer(); - m.user.context1.u = 10; + m.user.context1.u = 8; EsMessagePost(nullptr, &m); - // TODO Mount the new partition. + // Mount the new partition and extract the archive to it. - // Extract the archive. - // TODO Extract to the new partition. + EsDeviceControl(drive.handle, ES_DEVICE_CONTROL_BLOCK_DETECT_FS, nullptr, nullptr); - error = Extract(EsLiteral("0:/installer_archive.dat"), EsLiteral("0:/test")); + m.user.context1.u = 9; + EsMessagePost(nullptr, &m); + + if (ES_ERROR_TIMEOUT_REACHED == (EsError) EsWait(&mountNewFileSystemEvent, 1, 10000)) { + return ES_ERROR_TIMEOUT_REACHED; + } + + error = Extract(EsLiteral("0:/installer_archive.dat"), newFileSystemMountPoint.prefix, newFileSystemMountPoint.prefixBytes); if (error != ES_SUCCESS) return error; return ES_SUCCESS; } void InstallThread(EsGeneric) { - Install(); + EsPerformanceTimerPush(); + EsError error = Install(); + EsAssert(error == ES_SUCCESS); // TODO Reporting errors. + EsPrint("Installation finished in %Fs. Extracted %D from the archive.\n", EsPerformanceTimerPop(), metadata->totalUncompressedBytes); EsMessage m = { MSG_SET_PROGRESS }; m.user.context1.u = 100; @@ -592,6 +604,8 @@ void _start() { metadata = (InstallerMetadata *) EsFileReadAll(EsLiteral("0:/installer_metadata.dat"), nullptr); EsAssert(metadata); + mountNewFileSystemEvent = EsEventCreate(true); + EsWindow *window = EsWindowCreate(_EsInstanceCreate(sizeof(EsInstance), nullptr), ES_WINDOW_PLAIN); EsHandle handle = _EsWindowGetHandle(window); window->instance->window = window; @@ -718,6 +732,24 @@ void _start() { if (!startedInstallation) { ConnectedDriveRemove(message->device); } + } else if (message->type == ES_MSG_REGISTER_FILE_SYSTEM) { + EsVolumeInformation information; + + if (EsMountPointGetVolumeInformation(message->registerFileSystem.mountPoint->prefix, message->registerFileSystem.mountPoint->prefixBytes, &information)) { + bool isBootable = false; + + for (uintptr_t i = 0; i < sizeof(EsUniqueIdentifier); i++) { + if (information.installationIdentifier.d[i]) { + isBootable = true; + break; + } + } + + if (isBootable && 0 == EsMemoryCompare(&information.installationIdentifier, &installationIdentifier, sizeof(EsUniqueIdentifier))) { + newFileSystemMountPoint = *message->registerFileSystem.mountPoint; + EsEventSet(mountNewFileSystemEvent); + } + } } else if (message->type == MSG_SET_PROGRESS) { if (progress != message->user.context1.u) { char buffer[128]; diff --git a/desktop/os.header b/desktop/os.header index fbe4cdf..8c451f5 100644 --- a/desktop/os.header +++ b/desktop/os.header @@ -1134,6 +1134,7 @@ enum EsDeviceControlType { ES_DEVICE_CONTROL_BLOCK_GET_INFORMATION = 0x1001 ES_DEVICE_CONTROL_BLOCK_READ = 0x1002 ES_DEVICE_CONTROL_BLOCK_WRITE = 0x1003 + ES_DEVICE_CONTROL_BLOCK_DETECT_FS = 0x1004 // Detect file systems. All existing file systems must have been unmounted. } function_pointer int EsUICallback(struct EsElement *element, struct EsMessage *message); @@ -1508,6 +1509,7 @@ struct EsVolumeInformation { EsObjectID id; EsFileOffset spaceTotal; EsFileOffset spaceUsed; + EsUniqueIdentifier installationIdentifier; // Currently only supported by EsFS. }; // User interface messages. diff --git a/kernel/files.cpp b/kernel/files.cpp index bedbd85..d733d90 100644 --- a/kernel/files.cpp +++ b/kernel/files.cpp @@ -68,6 +68,7 @@ EsError FSFileControl(KNode *node, uint32_t flags); bool FSTrimCachedNode(MMObjectCache *); bool FSTrimCachedDirectoryEntry(MMObjectCache *); EsError FSBlockDeviceAccess(KBlockDeviceAccessRequest request); +void FSDetectFileSystem(KBlockDevice *device); struct { KWriterLock fileSystemsLock; @@ -1771,6 +1772,14 @@ bool FSFileSystemInitialise(KFileSystem *fileSystem) { } void FSDetectFileSystem(KBlockDevice *device) { + KMutexAcquire(&device->detectFileSystemMutex); + EsDefer(KMutexRelease(&device->detectFileSystemMutex)); + + if (device->children.Length()) { + // The file system or partitions on the device have already been detected and mounted. + return; + } + KernelLog(LOG_INFO, "FS", "detect file system", "Detecting file system on block device '%s'.\n", device->information.modelBytes, device->information.model); if (device->information.nestLevel > 4) { @@ -1786,31 +1795,30 @@ void FSDetectFileSystem(KBlockDevice *device) { uint8_t *signatureBlock = (uint8_t *) EsHeapAllocate(sectorsToRead * device->information.sectorSize, false, K_FIXED); - if (!signatureBlock) { - return; - } + if (signatureBlock) { + device->signatureBlock = signatureBlock; - device->signatureBlock = signatureBlock; + KDMABuffer dmaBuffer = { (uintptr_t) signatureBlock }; + KBlockDeviceAccessRequest request = {}; + request.device = device; + request.count = sectorsToRead * device->information.sectorSize; + request.operation = K_ACCESS_READ; + request.buffer = &dmaBuffer; - KDMABuffer dmaBuffer = { (uintptr_t) signatureBlock }; - KBlockDeviceAccessRequest request = {}; - request.device = device; - request.count = sectorsToRead * device->information.sectorSize; - request.operation = K_ACCESS_READ; - request.buffer = &dmaBuffer; - - if (ES_SUCCESS != FSBlockDeviceAccess(request)) { - // We could not access the block device. - KernelLog(LOG_ERROR, "FS", "detect fileSystem read failure", "The signature block could not be read on block device %x.\n", device); - } else { - if (!device->information.noMBR && FSCheckMBR(device)) { - // Found an MBR. + if (ES_SUCCESS != FSBlockDeviceAccess(request)) { + // We could not access the block device. + KernelLog(LOG_ERROR, "FS", "detect fileSystem read failure", "The signature block could not be read on block device %x.\n", device); } else { - KDeviceAttach(device, "Files", FSSignatureCheck); + if (!device->information.noMBR && FSCheckMBR(device)) { + // Found an MBR. + } else { + KDeviceAttach(device, "Files", FSSignatureCheck); + } } + + EsHeapFree(signatureBlock, sectorsToRead * device->information.sectorSize, K_FIXED); } - EsHeapFree(signatureBlock, sectorsToRead * device->information.sectorSize, K_FIXED); KDeviceCloseHandle(device); } @@ -1819,6 +1827,8 @@ void FSDetectFileSystem(KBlockDevice *device) { ////////////////////////////////////////// void FSRegisterBootFileSystem(KFileSystem *fileSystem, EsUniqueIdentifier identifier) { + fileSystem->installationIdentifier = identifier; + if (!EsMemoryCompare(&identifier, &installationID, sizeof(EsUniqueIdentifier))) { KWriterLockTake(&fs.fileSystemsLock, K_LOCK_EXCLUSIVE); diff --git a/kernel/memory.cpp b/kernel/memory.cpp index 7c60239..163849e 100644 --- a/kernel/memory.cpp +++ b/kernel/memory.cpp @@ -2110,6 +2110,19 @@ MMSpace *MMGetCurrentProcessSpace() { return GetCurrentThread()->process->vmm; } +bool MMFaultRange(uintptr_t address, uintptr_t byteCount) { + uintptr_t start = address & ~(K_PAGE_SIZE - 1); + uintptr_t end = (address + byteCount - 1) & ~(K_PAGE_SIZE - 1); + + for (uintptr_t page = start; page <= end; page += K_PAGE_SIZE) { + if (!MMArchHandlePageFault(page, ES_FLAGS_DEFAULT)) { + return false; + } + } + + return true; +} + void MMArchRemap(MMSpace *space, const void *virtualAddress, uintptr_t newPhysicalAddress) { if (ProcessorAreInterruptsEnabled()) { KernelPanic("MMArchRemap - Cannot remap address with interrupts enabled (does not invalidate the page on other processors).\n"); diff --git a/kernel/module.h b/kernel/module.h index f7c4e6a..9042599 100644 --- a/kernel/module.h +++ b/kernel/module.h @@ -635,6 +635,7 @@ struct KBlockDevice : KDevice { K_PRIVATE uint8_t *signatureBlock; // Signature block. Only valid during fileSystem detection. + KMutex detectFileSystemMutex; }; #define FS_PARTITION_DEVICE_NO_MBR (1 << 0) @@ -881,6 +882,7 @@ struct KFileSystem : KDevice { KMutex moveMutex; bool isBootFileSystem, unmounting; + EsUniqueIdentifier installationIdentifier; volatile uint64_t totalHandleCount; CCSpace cacheSpace; diff --git a/kernel/syscall.cpp b/kernel/syscall.cpp index 752731a..d41d422 100644 --- a/kernel/syscall.cpp +++ b/kernel/syscall.cpp @@ -213,16 +213,8 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_MEMORY_COMMIT) { } SYSCALL_IMPLEMENT(ES_SYSCALL_MEMORY_FAULT_RANGE) { - uintptr_t start = argument0 & ~(K_PAGE_SIZE - 1); - uintptr_t end = (argument0 + argument1 - 1) & ~(K_PAGE_SIZE - 1); - - for (uintptr_t page = start; page <= end; page += K_PAGE_SIZE) { - if (!MMArchHandlePageFault(page, ES_FLAGS_DEFAULT)) { - SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true); - } - } - - SYSCALL_RETURN(ES_SUCCESS, false); + bool success = MMFaultRange(argument0, argument1); + SYSCALL_RETURN(success ? ES_SUCCESS : ES_FATAL_ERROR_INVALID_BUFFER, !success); } SYSCALL_IMPLEMENT(ES_SYSCALL_PROCESS_CREATE) { @@ -758,6 +750,7 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_VOLUME_GET_INFORMATION) { information.spaceTotal = fileSystem->spaceTotal; information.id = fileSystem->objectID; information.flags = fileSystem->write ? ES_FLAGS_DEFAULT : ES_VOLUME_READ_ONLY; + information.installationIdentifier = fileSystem->installationIdentifier; SYSCALL_WRITE(argument1, &information, sizeof(EsVolumeInformation)); SYSCALL_RETURN(ES_SUCCESS, false); @@ -1837,6 +1830,13 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_DEVICE_CONTROL) { EsFileOffset parameters[2]; SYSCALL_READ(parameters, dq, sizeof(EsFileOffset) * 2); SYSCALL_BUFFER(dp, parameters[1], 1, !write /* whether the buffer will be written to */); + + // Since the request is not done via the cache, we need to fault the pages in. + // TODO Formalize this notion in the memory manager with page locking. + if (!MMFaultRange(dp, parameters[1])) { + SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true); + } + KBlockDeviceAccessRequest request = {}; request.device = block; request.offset = parameters[0]; @@ -1845,6 +1845,9 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_DEVICE_CONTROL) { request.buffer = &dmaBuffer; request.flags = FS_BLOCK_ACCESS_SOFT_ERRORS; SYSCALL_RETURN(FSBlockDeviceAccess(request), false); + } else if (type == ES_DEVICE_CONTROL_BLOCK_DETECT_FS) { + KDeviceOpenHandle(block); + FSDetectFileSystem(block); // Closes handle. } else { SYSCALL_RETURN(ES_FATAL_ERROR_UNKNOWN_SYSCALL, true); } diff --git a/shared/strings.cpp b/shared/strings.cpp index 141d746..5062064 100644 --- a/shared/strings.cpp +++ b/shared/strings.cpp @@ -286,7 +286,7 @@ DEFINE_INTERFACE_STRING(InstallerDriveRemoved, "The drive was disconnected."); DEFINE_INTERFACE_STRING(InstallerDriveReadOnly, "This drive is read-only. You cannot install " SYSTEM_BRAND_SHORT " on this drive."); DEFINE_INTERFACE_STRING(InstallerDriveNotEnoughSpace, "This drive does not have enough space to install " SYSTEM_BRAND_SHORT "."); DEFINE_INTERFACE_STRING(InstallerDriveCouldNotRead, "The drive could not be accessed. It may not be working correctly."); -DEFINE_INTERFACE_STRING(InstallerDriveAlreadyHasPartitions, "The drive already has data on it. To prevent data loss, you cannot install " SYSTEM_BRAND_SHORT " on this drive."); +DEFINE_INTERFACE_STRING(InstallerDriveAlreadyHasPartitions, "The drive already has data on it. You cannot install " SYSTEM_BRAND_SHORT " on this drive."); DEFINE_INTERFACE_STRING(InstallerDriveUnsupported, "This drive uses unsupported features. You cannot install " SYSTEM_BRAND_SHORT " on this drive."); DEFINE_INTERFACE_STRING(InstallerDriveOkay, SYSTEM_BRAND_SHORT " can be installed on this drive."); DEFINE_INTERFACE_STRING(InstallerInstall, "Install"); diff --git a/util/build.c b/util/build.c index 0c2a060..08fd308 100644 --- a/util/build.c +++ b/util/build.c @@ -447,7 +447,7 @@ void Run(int emulator, int log, int debug) { const char *secondaryDriveMB = GetOptionString("Emulator.SecondaryDriveMB"); char secondaryDriveFlags[256]; - if (secondaryDriveMB) { + if (secondaryDriveMB && atoi(secondaryDriveMB)) { CallSystemF("dd if=/dev/zero of=bin/drive2 bs=1048576 count=%d", atoi(secondaryDriveMB)); snprintf(secondaryDriveFlags, sizeof(secondaryDriveFlags), "-drive file=bin/drive2,if=none,id=mydisk2,format=raw "