diff --git a/apps/installer.cpp b/apps/installer.cpp index eee3502..2c9a05b 100644 --- a/apps/installer.cpp +++ b/apps/installer.cpp @@ -1,12 +1,24 @@ #define INSTALLER + #define ES_CRT_WITHOUT_PREFIX #include -#include + #include +#include + +#include +#define IMPLEMENTATION +#include +#undef IMPLEMENTATION + #define Log(...) #define exit(x) EsThreadTerminate(ES_CURRENT_THREAD) #include +Array connectedDrives; + +///////////////////////////////////////////// + #define BUFFER_SIZE (1048576) #define NAME_MAX (4096) @@ -115,17 +127,55 @@ EsError Extract(const char *pathIn, size_t pathInBytes, const char *pathOut, siz } void ReadBlock(uint64_t, uint64_t, void *) { + // TODO. } void WriteBlock(uint64_t, uint64_t, void *) { + // TODO. } void WriteBytes(uint64_t, uint64_t, void *) { + // TODO. +} + +void ConnectedDriveAdd(EsMessageDevice device) { + if (device.type != ES_DEVICE_BLOCK) { + return; + } + + EsBlockDeviceInformation information; + EsDeviceControl(device.handle, ES_DEVICE_CONTROL_BLOCK_GET_INFORMATION, 0, &information); + + if (information.nestLevel) { + return; + } + + connectedDrives.Add(device); +} + +void ConnectedDriveRemove(EsMessageDevice device) { + for (uintptr_t i = 0; i < connectedDrives.Length(); i++) { + if (connectedDrives[i].id == device.id) { + connectedDrives.Delete(i); + return; + } + } } void _start() { _init(); - EsPerformanceTimerPush(); - EsAssert(ES_SUCCESS == Extract(EsLiteral("0:/installer_archive.dat"), EsLiteral("0:/extracted"))); - EsPrint("time: %Fs\n", EsPerformanceTimerPop()); + + EsDeviceEnumerate([] (EsMessageDevice device, EsGeneric) { + ConnectedDriveAdd(device); + }, 0); + + while (true) { + EsMessage *message = EsMessageReceive(); + + if (message->type == ES_MSG_DEVICE_CONNECTED) { + ConnectedDriveAdd(message->device); + } else if (message->type == ES_MSG_DEVICE_DISCONNECTED) { + ConnectedDriveRemove(message->device); + } + } } diff --git a/desktop/api.cpp b/desktop/api.cpp index 3bb9f6d..7418234 100644 --- a/desktop/api.cpp +++ b/desktop/api.cpp @@ -113,7 +113,9 @@ struct Timer { struct { Array systemConfigurationGroups; EsMutex systemConfigurationMutex; + Array mountPoints; + Array connectedDevices; bool foundBootFileSystem; EsProcessStartupInformation *startupInformation; GlobalData *global; @@ -254,12 +256,22 @@ bool EsMountPointGetVolumeInformation(const char *prefix, size_t prefixBytes, Es } void EsMountPointEnumerate(EsMountPointEnumerationCallback callback, EsGeneric context) { + EsMessageMutexCheck(); + for (uintptr_t i = 0; i < api.mountPoints.Length(); i++) { MountPoint *mountPoint = &api.mountPoints[i]; callback(mountPoint->prefix, mountPoint->prefixBytes, context); } } +void EsDeviceEnumerate(EsDeviceEnumerationCallback callback, EsGeneric context) { + EsMessageMutexCheck(); + + for (uintptr_t i = 0; i < api.connectedDevices.Length(); i++) { + callback(api.connectedDevices[i], context); + } +} + EsError NodeOpen(const char *path, size_t pathBytes, uint32_t flags, _EsNodeInformation *node) { EsMountPoint *mountPoint = NodeFindMountPoint(path, pathBytes); @@ -1060,6 +1072,17 @@ EsMessage *EsMessageReceive() { return &message.message; } } + } else if (type == ES_MSG_DEVICE_CONNECTED) { + api.connectedDevices.Add(message.message.device); + return &message.message; + } else if (type == ES_MSG_DEVICE_DISCONNECTED) { + for (uintptr_t i = 0; i < api.connectedDevices.Length(); i++) { + if (api.connectedDevices[i].id == message.message.device.id) { + EsHandleClose(api.connectedDevices[i].handle); + api.connectedDevices.Delete(i); + return &message.message; + } + } } else if (type == ES_MSG_INSTANCE_DESTROY) { APIInstance *instance = (APIInstance *) message.message.instanceDestroy.instance->_private; @@ -1263,6 +1286,18 @@ extern "C" void _start(EsProcessStartupInformation *_startupInformation) { EsHeapFree(initialMountPoints); EsHandleClose(initialMountPointsBuffer); + EsHandle initialDevicesBuffer = api.startupInformation->data.initialDevices; + size_t initialDevicesCount = EsConstantBufferGetSize(initialDevicesBuffer) / sizeof(EsMessageDevice); + EsMessageDevice *initialDevices = (EsMessageDevice *) EsHeapAllocate(initialDevicesCount * sizeof(EsMessageDevice), false); + EsConstantBufferRead(initialDevicesBuffer, initialDevices); + + for (uintptr_t i = 0; i < initialDevicesCount; i++) { + api.connectedDevices.Add(initialDevices[i]); + } + + EsHeapFree(initialDevices); + EsHandleClose(initialDevicesBuffer); + uint8_t m = DESKTOP_MSG_SYSTEM_CONFIGURATION_GET; EsBuffer responseBuffer = { .canGrow = true }; MessageDesktop(&m, 1, ES_INVALID_HANDLE, &responseBuffer); diff --git a/desktop/desktop.cpp b/desktop/desktop.cpp index 33cc303..899ab23 100644 --- a/desktop/desktop.cpp +++ b/desktop/desktop.cpp @@ -175,7 +175,6 @@ struct { Array installedApplications; Array allApplicationInstances; Array allContainerWindows; - Array connectedDevices; InstalledApplication *fileManager; @@ -1233,6 +1232,7 @@ bool ApplicationInstanceStart(int64_t applicationID, EsApplicationStartupInforma arguments.permissions = ES_PERMISSION_WINDOW_MANAGER; Array initialMountPoints = {}; + Array initialDevices = {}; Array handleDuplicateList = {}; Array handleModeDuplicateList = {}; _EsNodeInformation settingsNode = {}; @@ -1270,6 +1270,14 @@ bool ApplicationInstanceStart(int64_t applicationID, EsApplicationStartupInforma handleModeDuplicateList.Add(2 /* prevent write */); } + if (application->permissions & APPLICATION_PERMISSION_ALL_DEVICES) { + for (uintptr_t i = 0; i < api.connectedDevices.Length(); i++) { + initialDevices.Add(api.connectedDevices[i]); + handleDuplicateList.Add(api.connectedDevices[i].handle); + handleModeDuplicateList.Add(0); + } + } + { error = NodeOpen(application->settingsPath, application->settingsPathBytes, ES_NODE_DIRECTORY | ES_NODE_CREATE_DIRECTORIES | _ES_NODE_DIRECTORY_WRITE, &settingsNode); @@ -1291,6 +1299,10 @@ bool ApplicationInstanceStart(int64_t applicationID, EsApplicationStartupInforma handleDuplicateList.Add(arguments.data.initialMountPoints); handleModeDuplicateList.Add(0); + arguments.data.initialDevices = EsConstantBufferCreate(initialDevices.array, initialDevices.Length() * sizeof(EsMessageDevice), ES_CURRENT_PROCESS); + handleDuplicateList.Add(arguments.data.initialDevices); + handleModeDuplicateList.Add(0); + arguments.handles = handleDuplicateList.array; arguments.handleModes = handleModeDuplicateList.array; arguments.handleCount = handleDuplicateList.Length(); @@ -1300,6 +1312,7 @@ bool ApplicationInstanceStart(int64_t applicationID, EsApplicationStartupInforma EsHandleClose(arguments.executable); initialMountPoints.Free(); + initialDevices.Free(); handleDuplicateList.Free(); handleModeDuplicateList.Free(); @@ -1307,6 +1320,14 @@ bool ApplicationInstanceStart(int64_t applicationID, EsApplicationStartupInforma EsHandleClose(settingsNode.handle); } + if (arguments.data.initialMountPoints) { + EsHandleClose(arguments.data.initialMountPoints); + } + + if (arguments.data.initialDevices) { + EsHandleClose(arguments.data.initialDevices); + } + if (!ES_CHECK_ERROR(error)) { process = information.handle; EsHandleClose(information.mainThread.handle); @@ -2525,12 +2546,15 @@ void DesktopMessage(EsMessage *message) { for (uintptr_t i = 0; i < desktop.installedApplications.Length(); i++) { desktop.installedApplications[i]->notified = false; } - } else if (message->type == ES_MSG_UNREGISTER_FILE_SYSTEM) { + } else if (message->type == ES_MSG_DEVICE_CONNECTED) { + EsHandle handle = message->device.handle; + for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) { ApplicationInstance *instance = desktop.allApplicationInstances[i]; - if (instance->application && (instance->application->permissions & APPLICATION_PERMISSION_ALL_FILES) + if (instance->application && (instance->application->permissions & APPLICATION_PERMISSION_ALL_DEVICES) && instance->processHandle && !instance->application->notified) { + message->device.handle = EsSyscall(ES_SYSCALL_HANDLE_SHARE, handle, instance->processHandle, 0, 0); EsMessagePostRemote(instance->processHandle, message); if (instance->application->useSingleProcess) instance->application->notified = true; } @@ -2539,19 +2563,33 @@ void DesktopMessage(EsMessage *message) { for (uintptr_t i = 0; i < desktop.installedApplications.Length(); i++) { desktop.installedApplications[i]->notified = false; } - } else if (message->type == ES_MSG_DEVICE_CONNECTED) { - desktop.connectedDevices.Add(message->device); - // TODO Propagate message. - } else if (message->type == ES_MSG_DEVICE_DISCONNECTED) { - for (uintptr_t i = 0; i < desktop.connectedDevices.Length(); i++) { - if (desktop.connectedDevices[i].id == message->device.id) { - EsHandleClose(desktop.connectedDevices[i].handle); - desktop.connectedDevices.Delete(i); - break; + } else if (message->type == ES_MSG_UNREGISTER_FILE_SYSTEM || message->type == ES_MSG_DEVICE_DISCONNECTED) { + for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) { + ApplicationInstance *instance = desktop.allApplicationInstances[i]; + + if (!instance->application) { + continue; + } + + if (message->type == ES_MSG_UNREGISTER_FILE_SYSTEM) { + if (~instance->application->permissions & APPLICATION_PERMISSION_ALL_FILES) { + continue; + } + } else if (message->type == ES_MSG_DEVICE_DISCONNECTED) { + if (~instance->application->permissions & APPLICATION_PERMISSION_ALL_DEVICES) { + continue; + } + } + + if (instance->processHandle && !instance->application->notified) { + EsMessagePostRemote(instance->processHandle, message); + if (instance->application->useSingleProcess) instance->application->notified = true; } } - // TODO Propagate message. + for (uintptr_t i = 0; i < desktop.installedApplications.Length(); i++) { + desktop.installedApplications[i]->notified = false; + } } else if (message->type == ES_MSG_SET_SCREEN_RESOLUTION) { if (desktop.setupDesktopUIComplete) { DesktopSetup(); // Refresh desktop UI. diff --git a/desktop/os.header b/desktop/os.header index 0612e88..9b42abf 100644 --- a/desktop/os.header +++ b/desktop/os.header @@ -827,6 +827,7 @@ enum EsSyscallType { ES_SYSCALL_FILE_CONTROL ES_SYSCALL_DIRECTORY_ENUMERATE ES_SYSCALL_VOLUME_GET_INFORMATION + ES_SYSCALL_DEVICE_CONTROL // Networking. @@ -1126,6 +1127,10 @@ enum EsClipboardFormat { ES_CLIPBOARD_FORMAT_PATH_LIST } +enum EsDeviceControlType { + ES_DEVICE_CONTROL_BLOCK_GET_INFORMATION +} + function_pointer int EsUICallback(struct EsElement *element, struct EsMessage *message); struct EsBuffer { @@ -1251,7 +1256,7 @@ struct EsMountPoint { }; struct EsProcessCreateData { - EsHandle environment, initialMountPoints; + EsHandle environment, initialMountPoints, initialDevices; }; struct EsProcessStartupInformation { @@ -1860,6 +1865,17 @@ struct EsFontInformation { uint16_t availableWeightsItalic; }; +struct EsBlockDeviceInformation { + size_t sectorSize; + EsFileOffset sectorCount; + bool noMBR; + bool readOnly; + uint8_t nestLevel; + uint8_t driveType; + uint8_t modelBytes; + char model[64]; +}; + // Function pointer types. function_pointer void EsThreadEntryCallback(EsGeneric argument); @@ -1870,6 +1886,7 @@ function_pointer void EsTimerCallback(EsGeneric argument); function_pointer void EsMenuCallback(EsMenu *menu, EsGeneric context); function_pointer void EsUndoCallback(const void *item, EsUndoManager *manager, EsMessage *message); function_pointer void EsMountPointEnumerationCallback(const char *prefix, size_t prefixBytes, EsGeneric context); +function_pointer void EsDeviceEnumerationCallback(EsMessageDevice device, EsGeneric context); function_pointer void EsListViewEnumerateVisibleItemsCallback(EsListView *view, EsElement *item, uint32_t group, EsGeneric index); function_pointer void EsFontEnumerationCallback(const EsFontInformation *information, EsGeneric context); function_pointer void EsUserTaskCallback(EsUserTask *task, EsGeneric data); @@ -1947,6 +1964,9 @@ function bool EsMountPointGetVolumeInformation(const char *prefix, size_t prefix function void EsMountPointEnumerate(EsMountPointEnumerationCallback callback, EsGeneric context); function void _EsPathAnnouncePathMoved(STRING oldPath, STRING newPath); +function void EsDeviceEnumerate(EsDeviceEnumerationCallback callback, EsGeneric context); +function EsError EsDeviceControl(EsHandle handle, EsDeviceControlType type, int32_t di, void *dp); + // Processes and threads. function EsError EsProcessCreate(EsProcessCreationArguments *arguments, EsProcessInformation *information); @@ -1967,8 +1987,8 @@ function void *EsArenaAllocate(EsArena *arena, bool zero); // Not thread-safe. function void EsArenaFree(EsArena *arena, void *pointer); // Not thread-safe. function void EsArenaInitialise(EsArena *arena, size_t blockSize, size_t itemSize); -function const void *EsBufferRead(struct EsBuffer *buffer, size_t readBytes); -function bool EsBufferReadInto(struct EsBuffer *buffer, void *destination, size_t readBytes); +function const void *EsBufferRead(EsBuffer *buffer, size_t readBytes); +function bool EsBufferReadInto(EsBuffer *buffer, void *destination, size_t readBytes); function const void *EsBufferReadMany(struct EsBuffer *buffer, size_t a, size_t b); function int32_t EsBufferReadInt32Endian(EsBuffer *buffer, int32_t errorValue); function void *EsBufferWrite(EsBuffer *buffer, const void *source, size_t writeBytes); diff --git a/desktop/posix.cpp b/desktop/posix.cpp index 4480cf9..868c95a 100644 --- a/desktop/posix.cpp +++ b/desktop/posix.cpp @@ -534,7 +534,7 @@ long EsPOSIXSystemCall(long n, long a1, long a2, long a3, long a4, long a5, long double timeStampMs = EsTimeStampMs(); uint64_t ns = timeStampMs * 1e6; tp->tv_sec = ns / 1000000000; - tp->tv_nsec = (ns % 1000000000) * 1000; + tp->tv_nsec = ns % 1000000000; } break; case SYS_wait4: { diff --git a/desktop/syscall.cpp b/desktop/syscall.cpp index 582de77..a6549d4 100644 --- a/desktop/syscall.cpp +++ b/desktop/syscall.cpp @@ -903,3 +903,7 @@ size_t EsPipeRead(EsHandle pipe, void *buffer, size_t bytes) { size_t EsPipeWrite(EsHandle pipe, const void *buffer, size_t bytes) { return EsSyscall(ES_SYSCALL_PIPE_WRITE, pipe, (uintptr_t) buffer, bytes, 0); } + +EsError EsDeviceControl(EsHandle handle, EsDeviceControlType type, int32_t di, void *dp) { + return EsSyscall(ES_SYSCALL_DEVICE_CONTROL, handle, type, di, (uintptr_t) dp); +} diff --git a/drivers/ahci.cpp b/drivers/ahci.cpp index 7dfc914..2ecbeb7 100644 --- a/drivers/ahci.cpp +++ b/drivers/ahci.cpp @@ -835,13 +835,15 @@ void AHCIController::Initialise() { device->controller = this; device->port = i; - device->sectorSize = ports[i].sectorBytes; - device->sectorCount = ports[i].sectorCount; - device->maxAccessSectorCount = ports[i].atapi ? (65535 / device->sectorSize) - : ((PRDT_ENTRY_COUNT - 1 /* need one extra if not page aligned */) * K_PAGE_SIZE / device->sectorSize); - device->readOnly = ports[i].atapi; - device->cModel = ports[i].model; - device->driveType = ports[i].atapi ? ES_DRIVE_TYPE_CDROM : ports[i].ssd ? ES_DRIVE_TYPE_SSD : ES_DRIVE_TYPE_HDD; + device->information.sectorSize = ports[i].sectorBytes; + device->information.sectorCount = ports[i].sectorCount; + device->maxAccessSectorCount = ports[i].atapi ? (65535 / device->information.sectorSize) + : ((PRDT_ENTRY_COUNT - 1 /* need one extra if not page aligned */) * K_PAGE_SIZE / device->information.sectorSize); + device->information.readOnly = ports[i].atapi; + EsAssert(sizeof(ports[i].model) <= sizeof(device->information.model)); + EsMemoryCopy(device->information.model, ports[i].model, sizeof(ports[i].model)); + device->information.modelBytes = sizeof(ports[i].model); + device->information.driveType = ports[i].atapi ? ES_DRIVE_TYPE_CDROM : ports[i].ssd ? ES_DRIVE_TYPE_SSD : ES_DRIVE_TYPE_HDD; device->access = [] (KBlockDeviceAccessRequest request) { AHCIDrive *drive = (AHCIDrive *) request.device; diff --git a/drivers/esfs2.cpp b/drivers/esfs2.cpp index 7074338..dd92b9c 100644 --- a/drivers/esfs2.cpp +++ b/drivers/esfs2.cpp @@ -1833,7 +1833,7 @@ static bool Mount(Volume *volume, EsFileOffsetDifference *rootDirectoryChildren) return false; } - if (volume->block->readOnly) { + if (volume->block->information.readOnly) { volume->readOnly = true; } @@ -1846,8 +1846,8 @@ static bool Mount(Volume *volume, EsFileOffsetDifference *rootDirectoryChildren) ESFS_CHECK_FATAL(0 == EsMemoryCompare(volume->superblock.signature, ESFS_SIGNATURE_STRING, 16), "Invalid superblock signature."); ESFS_CHECK_FATAL(volume->superblock.requiredReadVersion <= ESFS_DRIVER_VERSION, "Incompatible file system version."); - ESFS_CHECK_FATAL(superblock->blockSize >= 1024 && superblock->blockSize <= 16384 && (superblock->blockSize % volume->block->sectorSize) == 0, "Invalid block size."); - ESFS_CHECK_FATAL(superblock->blockCount * superblock->blockSize / volume->block->sectorSize <= volume->block->sectorCount, "More blocks than drive."); + ESFS_CHECK_FATAL(superblock->blockSize >= 1024 && superblock->blockSize <= 16384 && (superblock->blockSize % volume->block->information.sectorSize) == 0, "Invalid block size."); + ESFS_CHECK_FATAL(superblock->blockCount * superblock->blockSize / volume->block->information.sectorSize <= volume->block->information.sectorCount, "More blocks than drive."); ESFS_CHECK_FATAL(superblock->blocksUsed <= superblock->blockCount, "More blocks used than exist."); ESFS_CHECK_FATAL(superblock->blocksPerGroup <= 65536 && superblock->blocksPerGroup < superblock->blockCount && superblock->blocksPerGroup >= 1024, "Invalid block group size."); ESFS_CHECK_FATAL((superblock->groupCount - 1) * superblock->blocksPerGroup <= superblock->blockCount, "Invalid number of block groups."); diff --git a/drivers/ext2.cpp b/drivers/ext2.cpp index b5ee69e..3d150a0 100644 --- a/drivers/ext2.cpp +++ b/drivers/ext2.cpp @@ -140,16 +140,16 @@ static bool Mount(Volume *volume) { // Load the superblock. - uint8_t *sectorBuffer = (uint8_t *) EsHeapAllocate(volume->block->sectorSize, false, K_FIXED); + uint8_t *sectorBuffer = (uint8_t *) EsHeapAllocate(volume->block->information.sectorSize, false, K_FIXED); if (!sectorBuffer) { MOUNT_FAILURE("Could not allocate buffer.\n"); } - EsDefer(EsHeapFree(sectorBuffer, volume->block->sectorSize, K_FIXED)); + EsDefer(EsHeapFree(sectorBuffer, volume->block->information.sectorSize, K_FIXED)); { - if (!volume->Access(1024, volume->block->sectorSize, K_ACCESS_READ, sectorBuffer, ES_FLAGS_DEFAULT)) { + if (!volume->Access(1024, volume->block->information.sectorSize, K_ACCESS_READ, sectorBuffer, ES_FLAGS_DEFAULT)) { MOUNT_FAILURE("Could not read boot sector.\n"); } @@ -169,7 +169,7 @@ static bool Mount(Volume *volume) { volume->blockBytes = 1024 << volume->superBlock.blockSizeExponent; - if (volume->blockBytes < volume->block->sectorSize) { + if (volume->blockBytes < volume->block->information.sectorSize) { MOUNT_FAILURE("Block size smaller than drive sector size.\n"); } } @@ -201,14 +201,14 @@ static bool Mount(Volume *volume) { uint32_t blockGroup = (inode - 1) / volume->superBlock.inodesPerBlockGroup; uint32_t indexInInodeTable = (inode - 1) % volume->superBlock.inodesPerBlockGroup; - uint32_t sectorInInodeTable = (indexInInodeTable * volume->superBlock.inodeStructureBytes) / volume->block->sectorSize; - uint32_t offsetInSector = (indexInInodeTable * volume->superBlock.inodeStructureBytes) % volume->block->sectorSize; + uint32_t sectorInInodeTable = (indexInInodeTable * volume->superBlock.inodeStructureBytes) / volume->block->information.sectorSize; + uint32_t offsetInSector = (indexInInodeTable * volume->superBlock.inodeStructureBytes) % volume->block->information.sectorSize; BlockGroupDescriptor *blockGroupDescriptor = volume->blockGroupDescriptorTable + blockGroup; if (!volume->Access(blockGroupDescriptor->inodeTable * volume->blockBytes - + sectorInInodeTable * volume->block->sectorSize, - volume->block->sectorSize, + + sectorInInodeTable * volume->block->information.sectorSize, + volume->block->information.sectorSize, K_ACCESS_READ, sectorBuffer, ES_FLAGS_DEFAULT)) { MOUNT_FAILURE("Could not read the inode table.\n"); } @@ -234,7 +234,7 @@ static bool Mount(Volume *volume) { } static uint32_t GetDataBlock(Volume *volume, Inode *node, uint64_t blockIndex, uint8_t *blockBuffer) { -#define CHECK_BLOCK_INDEX() if (offset == 0 || offset / volume->block->sectorSize > volume->block->sectorCount) { \ +#define CHECK_BLOCK_INDEX() if (offset == 0 || offset / volume->block->information.sectorSize > volume->block->information.sectorCount) { \ KernelLog(LOG_ERROR, "Ext2", "invalid block index", "GetDataBlock - Block out of bounds.\n"); return 0; } #define GET_DATA_BLOCK_ACCESS_FAILURE() do { KernelLog(LOG_ERROR, "Ext2", "block access failure", "GetDataBlock - Could not read block.\n"); return 0; } while (0) @@ -448,14 +448,14 @@ static EsError Load(KNode *_directory, KNode *node, KNodeMetadata *metadata, con uint32_t blockGroup = (inode - 1) / volume->superBlock.inodesPerBlockGroup; uint32_t indexInInodeTable = (inode - 1) % volume->superBlock.inodesPerBlockGroup; - uint32_t sectorInInodeTable = (indexInInodeTable * volume->superBlock.inodeStructureBytes) / volume->block->sectorSize; - uint32_t offsetInSector = (indexInInodeTable * volume->superBlock.inodeStructureBytes) % volume->block->sectorSize; + uint32_t sectorInInodeTable = (indexInInodeTable * volume->superBlock.inodeStructureBytes) / volume->block->information.sectorSize; + uint32_t offsetInSector = (indexInInodeTable * volume->superBlock.inodeStructureBytes) % volume->block->information.sectorSize; BlockGroupDescriptor *blockGroupDescriptor = volume->blockGroupDescriptorTable + blockGroup; if (!volume->Access(blockGroupDescriptor->inodeTable * volume->blockBytes - + sectorInInodeTable * volume->block->sectorSize, - volume->block->sectorSize, + + sectorInInodeTable * volume->block->information.sectorSize, + volume->block->information.sectorSize, K_ACCESS_READ, blockBuffer, ES_FLAGS_DEFAULT)) { return ES_ERROR_DRIVE_CONTROLLER_REPORTED; } @@ -600,9 +600,9 @@ static void DeviceAttach(KDevice *parent) { return; } - if (volume->block->sectorSize & 0x1FF) { + if (volume->block->information.sectorSize & 0x1FF) { KernelLog(LOG_ERROR, "Ext2", "incorrect sector size", "Expected sector size to be a multiple of 512, but drive's sectors are %D.\n", - volume->block->sectorSize); + volume->block->information.sectorSize); KDeviceDestroy(volume); return; } diff --git a/drivers/fat.cpp b/drivers/fat.cpp index 6764b89..00bae4c 100644 --- a/drivers/fat.cpp +++ b/drivers/fat.cpp @@ -404,7 +404,7 @@ static bool Mount(Volume *volume) { sectorsPerFAT * SECTOR_SIZE, K_ACCESS_READ, volume->fat, ES_FLAGS_DEFAULT)) MOUNT_FAILURE("Could not read FAT.\n"); volume->spaceUsed = CountUsedClusters(volume) * superBlock->sectorsPerCluster * superBlock->bytesPerSector; - volume->spaceTotal = volume->block->sectorSize * volume->block->sectorCount; + volume->spaceTotal = volume->block->information.sectorSize * volume->block->information.sectorCount; volume->rootDirectory->driverNode = EsHeapAllocate(sizeof(FSNode), true, K_FIXED); if (!volume->rootDirectory->driverNode) MOUNT_FAILURE("Could not allocate root node.\n"); @@ -461,7 +461,7 @@ static void DeviceAttach(KDevice *parent) { return; } - if (volume->block->sectorSize != SECTOR_SIZE) { + if (volume->block->information.sectorSize != SECTOR_SIZE) { KernelLog(LOG_ERROR, "FAT", "mount failure", "DeviceAttach - Unsupported sector size.\n"); KDeviceDestroy(volume); return; diff --git a/drivers/ide.cpp b/drivers/ide.cpp index 2d34f1e..a441d2b 100644 --- a/drivers/ide.cpp +++ b/drivers/ide.cpp @@ -559,11 +559,11 @@ void ATAController::Initialise() { } device->index = i; - device->sectorSize = isATAPI[i] ? ATAPI_SECTOR_SIZE : ATA_SECTOR_SIZE; - device->sectorCount = sectorCount[i]; + device->information.sectorSize = isATAPI[i] ? ATAPI_SECTOR_SIZE : ATA_SECTOR_SIZE; + device->information.sectorCount = sectorCount[i]; device->maxAccessSectorCount = isATAPI[i] ? 31 : 64; - device->readOnly = isATAPI[i]; - device->driveType = isATAPI[i] ? ES_DRIVE_TYPE_CDROM : ES_DRIVE_TYPE_HDD; + device->information.readOnly = isATAPI[i]; + device->information.driveType = isATAPI[i] ? ES_DRIVE_TYPE_CDROM : ES_DRIVE_TYPE_HDD; device->access = [] (KBlockDeviceAccessRequest request) { request.dispatchGroup->Start(); diff --git a/drivers/iso9660.cpp b/drivers/iso9660.cpp index 422dad1..ef891ab 100644 --- a/drivers/iso9660.cpp +++ b/drivers/iso9660.cpp @@ -172,8 +172,8 @@ static bool Mount(Volume *volume) { ScanInternal(EsLiteral("ESSENCE.DAT;1"), volume->rootDirectory, &record); record.extentSize.x = (record.extentSize.x + SECTOR_SIZE - 1) / SECTOR_SIZE; - if (!record.length || record.extentStart.x >= volume->block->sectorCount - || record.extentSize.x >= volume->block->sectorCount - record.extentStart.x) { + if (!record.length || record.extentStart.x >= volume->block->information.sectorCount + || record.extentSize.x >= volume->block->information.sectorCount - record.extentStart.x) { goto notBoot; } @@ -205,7 +205,7 @@ static bool Mount(Volume *volume) { KernelLog(LOG_INFO, "ISO9660", "found boot disc", "Found boot disc. Image at %d/%d.\n", record.extentStart.x, record.extentSize.x); - FSPartitionDeviceCreate(volume->block, record.extentStart.x, record.extentSize.x, ES_FLAGS_DEFAULT, "CD-ROM boot partition"); + FSPartitionDeviceCreate(volume->block, record.extentStart.x, record.extentSize.x, ES_FLAGS_DEFAULT, EsLiteral("CD-ROM boot partition")); } notBoot:; @@ -495,9 +495,9 @@ static void DeviceAttach(KDevice *parent) { return; } - if (volume->block->sectorSize != SECTOR_SIZE) { + if (volume->block->information.sectorSize != SECTOR_SIZE) { KernelLog(LOG_ERROR, "ISO9660", "incorrect sector size", "DeviceAttach - Expected 2KB sectors, but drive's sectors are %D.\n", - volume->block->sectorSize); + volume->block->information.sectorSize); KDeviceDestroy(volume); return; } diff --git a/drivers/nvme.cpp b/drivers/nvme.cpp index fe067df..d7f022d 100644 --- a/drivers/nvme.cpp +++ b/drivers/nvme.cpp @@ -317,8 +317,8 @@ bool NVMeController::Access(struct NVMeDrive *drive, uint64_t offsetBytes, size_ KernelLog(LOG_VERBOSE, "NVMe", "start access", "Start access of %d, offset %D, count %D, using slot %d.\n", drive->nsid, offsetBytes, countBytes, ioSubmissionQueueTail); - uint64_t offsetSector = offsetBytes / drive->sectorSize; - uint64_t countSectors = countBytes / drive->sectorSize; + uint64_t offsetSector = offsetBytes / drive->information.sectorSize; + uint64_t countSectors = countBytes / drive->information.sectorSize; // Build the PRP list. @@ -801,11 +801,11 @@ void NVMeController::Initialise() { device->controller = this; device->nsid = nsid; - device->sectorSize = sectorBytes; - device->sectorCount = capacity / sectorBytes; + device->information.sectorSize = sectorBytes; + device->information.sectorCount = capacity / sectorBytes; device->maxAccessSectorCount = maximumDataTransferBytes / sectorBytes; - device->readOnly = readOnly; - device->driveType = ES_DRIVE_TYPE_SSD; + device->information.readOnly = readOnly; + device->information.driveType = ES_DRIVE_TYPE_SSD; device->access = [] (KBlockDeviceAccessRequest request) { NVMeDrive *drive = (NVMeDrive *) request.device; diff --git a/drivers/usb_bulk.cpp b/drivers/usb_bulk.cpp index bf24835..7ed1484 100644 --- a/drivers/usb_bulk.cpp +++ b/drivers/usb_bulk.cpp @@ -98,8 +98,8 @@ void DriveAccess(KBlockDeviceAccessRequest request) { Device *device = drive->device; request.dispatchGroup->Start(); - uint32_t offsetSectors = request.offset / drive->sectorSize; - uint32_t countSectors = request.count / drive->sectorSize; + uint32_t offsetSectors = request.offset / drive->information.sectorSize; + uint32_t countSectors = request.count / drive->information.sectorSize; CommandBlock command = { .transferBytes = (uint32_t) request.count, @@ -194,12 +194,12 @@ void Device::Initialise() { drive->device = this; drive->lun = i; - drive->sectorSize = sectorBytes; - drive->sectorCount = sectorCount; + drive->information.sectorSize = sectorBytes; + drive->information.sectorCount = sectorCount; drive->maxAccessSectorCount = 262144 / sectorBytes; // TODO How to determine this? What does the USB layer support? - drive->readOnly = false; // TODO How to detect this? + drive->information.readOnly = false; // TODO How to detect this? drive->access = DriveAccess; - drive->driveType = ES_DRIVE_TYPE_USB_MASS_STORAGE; + drive->information.driveType = ES_DRIVE_TYPE_USB_MASS_STORAGE; FSRegisterBlockDevice(drive); } diff --git a/kernel/drivers.cpp b/kernel/drivers.cpp index 96c255b..1c58080 100644 --- a/kernel/drivers.cpp +++ b/kernel/drivers.cpp @@ -135,6 +135,7 @@ void KDeviceSendConnectedMessage(KDevice *device, EsDeviceType type) { } device->flags |= K_DEVICE_VISIBLE_TO_USER; + device->type = type; KMutexRelease(&deviceTreeMutex); diff --git a/kernel/files.cpp b/kernel/files.cpp index 4b60f77..6ce8b91 100644 --- a/kernel/files.cpp +++ b/kernel/files.cpp @@ -1546,16 +1546,16 @@ bool FSBlockDeviceAccess(KBlockDeviceAccessRequest request) { return true; } - if (device->readOnly && request.operation == K_ACCESS_WRITE) { + if (device->information.readOnly && request.operation == K_ACCESS_WRITE) { KernelPanic("FSBlockDeviceAccess - Drive %x is read-only.\n", device); } - if (request.offset / device->sectorSize > device->sectorCount - || (request.offset + request.count) / device->sectorSize > device->sectorCount) { + if (request.offset / device->information.sectorSize > device->information.sectorCount + || (request.offset + request.count) / device->information.sectorSize > device->information.sectorCount) { KernelPanic("FSBlockDeviceAccess - Access out of bounds on drive %x.\n", device); } - if ((request.offset % device->sectorSize) || (request.count % device->sectorSize)) { + if ((request.offset % device->information.sectorSize) || (request.count % device->information.sectorSize)) { KernelPanic("FSBlockDeviceAccess - Misaligned access.\n"); } @@ -1581,7 +1581,7 @@ bool FSBlockDeviceAccess(KBlockDeviceAccessRequest request) { r.offset = request.offset; while (request.count) { - r.count = device->maxAccessSectorCount * device->sectorSize; + r.count = device->maxAccessSectorCount * device->information.sectorSize; if (r.count > request.count) r.count = request.count; buffer.offsetBytes = 0; buffer.totalByteCount = r.count; @@ -1669,25 +1669,28 @@ struct PartitionDevice : KBlockDevice { void FSPartitionDeviceAccess(KBlockDeviceAccessRequest request) { PartitionDevice *_device = (PartitionDevice *) request.device; request.device = (KBlockDevice *) _device->parent; - request.offset += _device->sectorOffset * _device->sectorSize; + request.offset += _device->sectorOffset * _device->information.sectorSize; FSBlockDeviceAccess(request); } -void FSPartitionDeviceCreate(KBlockDevice *parent, EsFileOffset offset, EsFileOffset sectorCount, unsigned flags, const char *cName) { - PartitionDevice *child = (PartitionDevice *) KDeviceCreate(cName, parent, sizeof(PartitionDevice)); +void FSPartitionDeviceCreate(KBlockDevice *parent, EsFileOffset offset, EsFileOffset sectorCount, unsigned flags, const char *model, size_t modelBytes) { + PartitionDevice *child = (PartitionDevice *) KDeviceCreate("Partition", parent, sizeof(PartitionDevice)); if (!child) return; + if (modelBytes > sizeof(child->information.model)) modelBytes = sizeof(child->information.model); + EsMemoryCopy(child->information.model, model, modelBytes); + child->parent = parent; - child->sectorSize = parent->sectorSize; + child->information.sectorSize = parent->information.sectorSize; child->maxAccessSectorCount = parent->maxAccessSectorCount; child->sectorOffset = offset; - child->sectorCount = sectorCount; - child->noMBR = flags & FS_PARTITION_DEVICE_NO_MBR ? true : false; - child->readOnly = parent->readOnly; + child->information.sectorCount = sectorCount; + child->information.noMBR = flags & FS_PARTITION_DEVICE_NO_MBR ? true : false; + child->information.readOnly = parent->information.readOnly; child->access = FSPartitionDeviceAccess; - child->cModel = cName; - child->nestLevel = parent->nestLevel + 1; - child->driveType = parent->driveType; + child->information.modelBytes = modelBytes; + child->information.nestLevel = parent->information.nestLevel + 1; + child->information.driveType = parent->information.driveType; FSRegisterBlockDevice(child); } @@ -1697,7 +1700,7 @@ void FSPartitionDeviceCreate(KBlockDevice *parent, EsFileOffset offset, EsFileOf ////////////////////////////////////////// bool FSSignatureCheck(KInstalledDriver *driver, KDevice *device) { - uint8_t *block = ((KBlockDevice *) device)->information; + uint8_t *block = ((KBlockDevice *) device)->signatureBlock; EsINIState s = {}; s.buffer = driver->config; @@ -1723,7 +1726,7 @@ bool FSSignatureCheck(KInstalledDriver *driver, KDevice *device) { } bool FSCheckMBR(KBlockDevice *device) { - if (device->information[510] != 0x55 || device->information[511] != 0xAA) { + if (device->signatureBlock[510] != 0x55 || device->signatureBlock[511] != 0xAA) { return false; } @@ -1733,23 +1736,23 @@ bool FSCheckMBR(KBlockDevice *device) { bool present[4] = {}; for (uintptr_t i = 0; i < 4; i++) { - if (!device->information[4 + 0x1BE + i * 0x10]) { + if (!device->signatureBlock[4 + 0x1BE + i * 0x10]) { continue; } offsets[i] = - ((uint32_t) device->information[0x1BE + i * 0x10 + 8 ] << 0 ) - + ((uint32_t) device->information[0x1BE + i * 0x10 + 9 ] << 8 ) - + ((uint32_t) device->information[0x1BE + i * 0x10 + 10] << 16) - + ((uint32_t) device->information[0x1BE + i * 0x10 + 11] << 24); + ((uint32_t) device->signatureBlock[0x1BE + i * 0x10 + 8 ] << 0 ) + + ((uint32_t) device->signatureBlock[0x1BE + i * 0x10 + 9 ] << 8 ) + + ((uint32_t) device->signatureBlock[0x1BE + i * 0x10 + 10] << 16) + + ((uint32_t) device->signatureBlock[0x1BE + i * 0x10 + 11] << 24); counts[i] = - ((uint32_t) device->information[0x1BE + i * 0x10 + 12] << 0 ) - + ((uint32_t) device->information[0x1BE + i * 0x10 + 13] << 8 ) - + ((uint32_t) device->information[0x1BE + i * 0x10 + 14] << 16) - + ((uint32_t) device->information[0x1BE + i * 0x10 + 15] << 24); + ((uint32_t) device->signatureBlock[0x1BE + i * 0x10 + 12] << 0 ) + + ((uint32_t) device->signatureBlock[0x1BE + i * 0x10 + 13] << 8 ) + + ((uint32_t) device->signatureBlock[0x1BE + i * 0x10 + 14] << 16) + + ((uint32_t) device->signatureBlock[0x1BE + i * 0x10 + 15] << 24); present[i] = true; - if (offsets[i] > device->sectorCount || counts[i] > device->sectorCount - offsets[i] || counts[i] < 32) { + if (offsets[i] > device->information.sectorCount || counts[i] > device->information.sectorCount - offsets[i] || counts[i] < 32) { KernelLog(LOG_INFO, "FS", "invalid MBR", "Partition %d has offset %d and count %d, which is invalid. Ignoring the rest of the MBR...\n", i, offsets[i], counts[i]); return false; @@ -1760,7 +1763,7 @@ bool FSCheckMBR(KBlockDevice *device) { if (present[i]) { KernelLog(LOG_INFO, "FS", "MBR partition", "Found MBR partition %d with offset %d and count %d.\n", i, offsets[i], counts[i]); - FSPartitionDeviceCreate(device, offsets[i], counts[i], FS_PARTITION_DEVICE_NO_MBR, "MBR partition"); + FSPartitionDeviceCreate(device, offsets[i], counts[i], FS_PARTITION_DEVICE_NO_MBR, EsLiteral("MBR partition")); } } @@ -1790,31 +1793,31 @@ bool FSFileSystemInitialise(KFileSystem *fileSystem) { } void FSDetectFileSystem(KBlockDevice *device) { - KernelLog(LOG_INFO, "FS", "detect file system", "Detecting file system on block device '%z'.\n", device->cModel); + KernelLog(LOG_INFO, "FS", "detect file system", "Detecting file system on block device '%s'.\n", device->information.modelBytes, device->information.model); - if (device->nestLevel > 4) { + if (device->information.nestLevel > 4) { KernelLog(LOG_ERROR, "FS", "file system nest limit", "Reached file system nest limit (4), ignoring device.\n"); } - uint64_t sectorsToRead = (K_SIGNATURE_BLOCK_SIZE + device->sectorSize - 1) / device->sectorSize; + uint64_t sectorsToRead = (K_SIGNATURE_BLOCK_SIZE + device->information.sectorSize - 1) / device->information.sectorSize; - if (sectorsToRead > device->sectorCount) { + if (sectorsToRead > device->information.sectorCount) { KernelLog(LOG_ERROR, "FS", "drive too small", "The drive must be at least %D (K_SIGNATURE_BLOCK_SIZE).\n", K_SIGNATURE_BLOCK_SIZE); return; } - uint8_t *information = (uint8_t *) EsHeapAllocate(sectorsToRead * device->sectorSize, false, K_FIXED); + uint8_t *signatureBlock = (uint8_t *) EsHeapAllocate(sectorsToRead * device->information.sectorSize, false, K_FIXED); - if (!information) { + if (!signatureBlock) { return; } - device->information = information; + device->signatureBlock = signatureBlock; - KDMABuffer dmaBuffer = { (uintptr_t) information }; + KDMABuffer dmaBuffer = { (uintptr_t) signatureBlock }; KBlockDeviceAccessRequest request = {}; request.device = device; - request.count = sectorsToRead * device->sectorSize; + request.count = sectorsToRead * device->information.sectorSize; request.operation = K_ACCESS_READ; request.buffer = &dmaBuffer; @@ -1822,14 +1825,14 @@ void FSDetectFileSystem(KBlockDevice *device) { // 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->noMBR && FSCheckMBR(device)) { + if (!device->information.noMBR && FSCheckMBR(device)) { // Found an MBR. } else { KDeviceAttach(device, "Files", FSSignatureCheck); } } - EsHeapFree(information, sectorsToRead * device->sectorSize, K_FIXED); + EsHeapFree(signatureBlock, sectorsToRead * device->information.sectorSize, K_FIXED); KDeviceCloseHandle(device); } diff --git a/kernel/module.h b/kernel/module.h index 1c59d30..5b30873 100644 --- a/kernel/module.h +++ b/kernel/module.h @@ -551,6 +551,7 @@ struct KDevice { #define K_DEVICE_VISIBLE_TO_USER (1 << 1) // A ES_MSG_DEVICE_CONNECTED message was sent to Desktop for this device. uint8_t flags; uint32_t handles; + EsDeviceType type; EsObjectID objectID; // These callbacks are called with the deviceTreeMutex locked, and are all optional. @@ -628,21 +629,16 @@ typedef void (*KDeviceAccessCallbackFunction)(KBlockDeviceAccessRequest request) struct KBlockDevice : KDevice { KDeviceAccessCallbackFunction access; // Don't call directly; see KFileSystem::Access. - size_t sectorSize, maxAccessSectorCount; - EsFileOffset sectorCount; - bool noMBR; // Set to `true` if this device cannot contain a MBR. - bool readOnly; - uint8_t nestLevel; - uint8_t driveType; - const char *cModel; + EsBlockDeviceInformation information; + size_t maxAccessSectorCount; K_PRIVATE - uint8_t *information; // Signature block. Only valid during fileSystem detection. + uint8_t *signatureBlock; // Signature block. Only valid during fileSystem detection. }; #define FS_PARTITION_DEVICE_NO_MBR (1 << 0) -void FSPartitionDeviceCreate(KBlockDevice *parent, EsFileOffset offset, EsFileOffset sectorCount, unsigned flags, const char *cName); +void FSPartitionDeviceCreate(KBlockDevice *parent, EsFileOffset offset, EsFileOffset sectorCount, unsigned flags, const char *name, size_t nameBytes); // --------------------------------------------------------------------------------------------------------------- // PCI. diff --git a/kernel/syscall.cpp b/kernel/syscall.cpp index 485cc8c..4263653 100644 --- a/kernel/syscall.cpp +++ b/kernel/syscall.cpp @@ -725,9 +725,14 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_MEMORY_MAP_OBJECT) { SYSCALL_IMPLEMENT(ES_SYSCALL_CONSTANT_BUFFER_CREATE) { if (argument2 > SYSCALL_BUFFER_LIMIT) SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true); - SYSCALL_BUFFER(argument0, argument2, 1, false); SYSCALL_HANDLE(argument1, KERNEL_OBJECT_PROCESS, process, Process); - SYSCALL_RETURN(MakeConstantBuffer((void *) argument0, argument2, process), false); + + if (argument2) { + SYSCALL_BUFFER(argument0, argument2, 1, false); + SYSCALL_RETURN(MakeConstantBuffer((void *) argument0, argument2, process), false); + } else { + SYSCALL_RETURN(MakeConstantBuffer(nullptr, 0, process), false); + } } SYSCALL_IMPLEMENT(ES_SYSCALL_HANDLE_SHARE) { @@ -748,7 +753,7 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_VOLUME_GET_INFORMATION) { EsMemoryZero(&information, sizeof(EsVolumeInformation)); EsMemoryCopy(information.label, fileSystem->name, sizeof(fileSystem->name)); information.labelBytes = fileSystem->nameBytes; - information.driveType = fileSystem->block->driveType; + information.driveType = fileSystem->block->information.driveType; information.spaceUsed = fileSystem->spaceUsed; information.spaceTotal = fileSystem->spaceTotal; information.id = fileSystem->objectID; @@ -1816,6 +1821,24 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_CONNECTION_NOTIFY) { SYSCALL_RETURN(ES_SUCCESS, false); } +SYSCALL_IMPLEMENT(ES_SYSCALL_DEVICE_CONTROL) { + SYSCALL_HANDLE(argument0, KERNEL_OBJECT_DEVICE, device, KDevice); + + if (device->type == ES_DEVICE_BLOCK) { + KBlockDevice *block = (KBlockDevice *) device; + + if (argument1 == ES_DEVICE_CONTROL_BLOCK_GET_INFORMATION) { + SYSCALL_WRITE(argument3, &block->information, sizeof(EsBlockDeviceInformation)); + } else { + SYSCALL_RETURN(ES_FATAL_ERROR_UNKNOWN_SYSCALL, true); + } + } else { + SYSCALL_RETURN(ES_FATAL_ERROR_UNKNOWN_SYSCALL, true); + } + + SYSCALL_RETURN(ES_SUCCESS, false); +} + SYSCALL_IMPLEMENT(ES_SYSCALL_DEBUG_COMMAND) { #ifdef DEBUG_BUILD if (argument0 == 1) { diff --git a/util/api_table.ini b/util/api_table.ini index c40530b..90a1298 100644 --- a/util/api_table.ini +++ b/util/api_table.ini @@ -6,6 +6,7 @@ EsPOSIXInitialise=4 EsFileStoreReadAll=5 EsPOSIXSystemCall=6 EsINIParse=7 +EsDeviceEnumerate=8 EsTakeSystemSnapshot=9 EsListViewFocusItem=10 _EsInstanceCreate=11 @@ -444,3 +445,4 @@ EsColorInterpolate=443 EsBufferReadInt32Endian=444 EsBufferWriteInt32Endian=445 EsSystemGetOptimalWorkQueueThreadCount=446 +EsDeviceControl=447