installation to MBR

This commit is contained in:
nakst 2021-09-12 21:50:37 +01:00
parent dfd80c3dcd
commit f82e5d9a30
8 changed files with 101 additions and 39 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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