diff --git a/reactos/ntoskrnl/include/internal/io.h b/reactos/ntoskrnl/include/internal/io.h index 1f096b4682c..235ab7ffda1 100644 --- a/reactos/ntoskrnl/include/internal/io.h +++ b/reactos/ntoskrnl/include/internal/io.h @@ -56,6 +56,30 @@ // #define IO_METHOD_FROM_CTL_CODE(c) (c & 0x00000003) +// +// Bugcheck codes for RAM disk booting +// +// +// No LoaderXIPRom descriptor was found in the loader memory list +// +#define RD_NO_XIPROM_DESCRIPTOR 1 +// +// Unable to open the RAM disk driver (ramdisk.sys or \Device\Ramdisk) +// +#define RD_NO_RAMDISK_DRIVER 2 +// +// FSCTL_CREATE_RAM_DISK failed +// +#define RD_FSCTL_FAILED 3 +// +// Unable to create GUID string from binary GUID +// +#define RD_GUID_CONVERT_FAILED 4 +// +// Unable to create symbolic link pointing to the RAM disk device +// +#define RD_SYMLINK_CREATE_FAILED 5 + // // Packet Types when piggybacking on the IRP Overlay // @@ -986,6 +1010,15 @@ IopDeleteIoCompletion( PVOID ObjectBody ); +// +// Ramdisk Routines +// +NTSTATUS +NTAPI +IopStartRamdisk( + IN PLOADER_PARAMETER_BLOCK LoaderBlock +); + // // Global I/O Data // diff --git a/reactos/ntoskrnl/io/iomgr/ramdisk.c b/reactos/ntoskrnl/io/iomgr/ramdisk.c new file mode 100644 index 00000000000..ffcdbee1b12 --- /dev/null +++ b/reactos/ntoskrnl/io/iomgr/ramdisk.c @@ -0,0 +1,255 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: ntoskrnl/io/iomgr/ramdisk.c + * PURPOSE: Allows booting from RAM disk + * PROGRAMMERS: ReactOS Portable Systems Group + */ + +/* INCLUDES *******************************************************************/ + +#include +#include +#include +#define NDEBUG +#include + +/* DATA ***********************************************************************/ + +#if defined (ALLOC_PRAGMA) +#pragma alloc_text(INIT, IopStartRamdisk) +#endif + +/* FUNCTIONS ******************************************************************/ + +NTSTATUS +NTAPI +IopStartRamdisk(IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor; + NTSTATUS Status; + PCHAR CommandLine, Offset, OffsetValue, Length, LengthValue; + HANDLE DriverHandle; + RAMDISK_CREATE_INPUT RamdiskCreate; + IO_STATUS_BLOCK IoStatusBlock; + UNICODE_STRING GuidString, SymbolicLinkName, ObjectName, DeviceString; + PLIST_ENTRY ListHead, NextEntry; + OBJECT_ATTRIBUTES ObjectAttributes; + WCHAR SourceString[54]; + + // + // Scan memory descriptors + // + MemoryDescriptor = NULL; + ListHead = &LoaderBlock->MemoryDescriptorListHead; + NextEntry = ListHead->Flink; + while (NextEntry != ListHead) + { + // + // Get the descriptor + // + MemoryDescriptor = CONTAINING_RECORD(NextEntry, + MEMORY_ALLOCATION_DESCRIPTOR, + ListEntry); + + // + // Needs to be a ROM/RAM descriptor + // + if (MemoryDescriptor->MemoryType == LoaderXIPRom) break; + + // + // Keep trying + // + NextEntry = NextEntry->Flink; + } + + // + // Nothing found? + // + if (NextEntry == ListHead) + { + // + // Bugcheck -- no data + // + KeBugCheckEx(RAMDISK_BOOT_INITIALIZATION_FAILED, + RD_NO_XIPROM_DESCRIPTOR, + STATUS_INVALID_PARAMETER, + 0, + 0); + } + + // + // Setup the input buffer + // + RtlZeroMemory(&RamdiskCreate, sizeof(RamdiskCreate)); + RamdiskCreate.Version = sizeof(RamdiskCreate); + RamdiskCreate.DiskType = FILE_DEVICE_CD_ROM_FILE_SYSTEM; + RamdiskCreate.BasePage = MemoryDescriptor->BasePage; + RamdiskCreate.DiskOffset = 0; + RamdiskCreate.DiskLength = MemoryDescriptor->PageCount << PAGE_SHIFT; + RamdiskCreate.DiskGuid = RAMDISK_BOOTDISK_GUID; + RamdiskCreate.DriveLetter = L'C'; + RamdiskCreate.Options.Fixed = TRUE; + + // + // Check for commandline parameters + // + CommandLine = LoaderBlock->LoadOptions; + if (CommandLine) + { + // + // Make everything upper case + // + _strupr(CommandLine); + + // + // Check for offset parameter + // + Offset = strstr(CommandLine, "RDIMAGEOFFSET"); + if (Offset) + { + // + // Get to the actual value + // + OffsetValue = strstr(Offset, "="); + if (OffsetValue) + { + // + // Set the offset + // + RamdiskCreate.DiskOffset = atol(OffsetValue + 1); + } + } + + // + // Reduce the disk length + // + RamdiskCreate.DiskLength -= RamdiskCreate.DiskOffset; + + // + // Check for length parameter + // + Length = strstr(CommandLine, "RDIMAGELENGTH"); + if (Length) + { + // + // Get to the actual value + // + LengthValue = strstr(Length, "="); + if (LengthValue) + { + // + // Set the offset + // + RamdiskCreate.DiskLength = _atoi64(LengthValue + 1); + } + } + } + + // + // Setup object attributes + // + RtlInitUnicodeString(&ObjectName, L"\\Device\\Ramdisk"); + InitializeObjectAttributes(&ObjectAttributes, + &ObjectName, + OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + // + // Open a handle to the driver + // + Status = ZwOpenFile(&DriverHandle, + GENERIC_ALL, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_NONALERT); + if (!(NT_SUCCESS(Status)) || !(NT_SUCCESS(IoStatusBlock.Status))) + { + // + // Bugcheck -- no driver + // + KeBugCheckEx(RAMDISK_BOOT_INITIALIZATION_FAILED, + RD_NO_RAMDISK_DRIVER, + IoStatusBlock.Status, + 0, + 0); + } + + // + // Send create command + // + Status = ZwDeviceIoControlFile(DriverHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + FSCTL_CREATE_RAM_DISK, + &RamdiskCreate, + sizeof(RamdiskCreate), + NULL, + 0); + ZwClose(DriverHandle); + if (!(NT_SUCCESS(Status)) || !(NT_SUCCESS(IoStatusBlock.Status))) + { + // + // Bugcheck -- driver failed + // + KeBugCheckEx(RAMDISK_BOOT_INITIALIZATION_FAILED, + RD_FSCTL_FAILED, + IoStatusBlock.Status, + 0, + 0); + } + + // + // Convert the GUID + // + Status = RtlStringFromGUID(&RamdiskCreate.DiskGuid, &GuidString); + if (!NT_SUCCESS(Status)) + { + // + // Bugcheck -- GUID convert failed + // + KeBugCheckEx(RAMDISK_BOOT_INITIALIZATION_FAILED, + RD_GUID_CONVERT_FAILED, + Status, + 0, + 0); + } + + // + // Build the symbolic link name and target + // + _snwprintf(SourceString, + sizeof(SourceString), + L"\\Device\\Ramdisk%wZ", + &GuidString); + SymbolicLinkName.Length = 38; + SymbolicLinkName.MaximumLength = 38 + sizeof(UNICODE_NULL); + SymbolicLinkName.Buffer = L"\\ArcName\\ramdisk(0)"; + + // + // Create the symbolic link + // + RtlInitUnicodeString(&DeviceString, SourceString); + Status = IoCreateSymbolicLink(&SymbolicLinkName, &DeviceString); + RtlFreeUnicodeString(&GuidString); + if (!NT_SUCCESS(Status)) + { + // + // Bugcheck -- symlink create failed + // + KeBugCheckEx(RAMDISK_BOOT_INITIALIZATION_FAILED, + RD_SYMLINK_CREATE_FAILED, + Status, + 0, + 0); + } + + // + // We made it + // + return STATUS_SUCCESS; +} diff --git a/reactos/ntoskrnl/ntoskrnl-generic.rbuild b/reactos/ntoskrnl/ntoskrnl-generic.rbuild index cb7c7aad932..eba1feaf9ea 100644 --- a/reactos/ntoskrnl/ntoskrnl-generic.rbuild +++ b/reactos/ntoskrnl/ntoskrnl-generic.rbuild @@ -256,6 +256,7 @@ iowork.c irp.c irq.c + ramdisk.c rawfs.c remlock.c util.c