xref: /reactos/ntoskrnl/io/iomgr/ramdisk.c (revision 94a413ae)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         BSD - See COPYING.ARM in the top level directory
4  * FILE:            ntoskrnl/io/iomgr/ramdisk.c
5  * PURPOSE:         Allows booting from RAM disk
6  * PROGRAMMERS:     ReactOS Portable Systems Group
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #include <initguid.h>
13 #include <ntddrdsk.h>
14 #define NDEBUG
15 #include <debug.h>
16 
17 /* GLOBALS *******************************************************************/
18 
19 extern KEVENT PiEnumerationFinished;
20 
21 /* DATA ***********************************************************************/
22 
23 #if defined (ALLOC_PRAGMA)
24 #pragma alloc_text(INIT, IopStartRamdisk)
25 #endif
26 
27 /* FUNCTIONS ******************************************************************/
28 
29 INIT_FUNCTION
30 NTSTATUS
31 NTAPI
32 IopStartRamdisk(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
33 {
34     PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
35     NTSTATUS Status;
36     PCHAR CommandLine, Offset, OffsetValue, Length, LengthValue;
37     HANDLE DriverHandle;
38     RAMDISK_CREATE_INPUT RamdiskCreate;
39     IO_STATUS_BLOCK IoStatusBlock;
40     UNICODE_STRING GuidString, SymbolicLinkName, ObjectName, DeviceString;
41     PLIST_ENTRY ListHead, NextEntry;
42     OBJECT_ATTRIBUTES ObjectAttributes;
43     WCHAR SourceString[54];
44 
45     //
46     // Scan memory descriptors
47     //
48     MemoryDescriptor = NULL;
49     ListHead = &LoaderBlock->MemoryDescriptorListHead;
50     NextEntry = ListHead->Flink;
51     while (NextEntry != ListHead)
52     {
53         //
54         // Get the descriptor
55         //
56         MemoryDescriptor = CONTAINING_RECORD(NextEntry,
57                                              MEMORY_ALLOCATION_DESCRIPTOR,
58                                              ListEntry);
59 
60         //
61         // Needs to be a ROM/RAM descriptor
62         //
63         if (MemoryDescriptor->MemoryType == LoaderXIPRom) break;
64 
65         //
66         // Keep trying
67         //
68         NextEntry = NextEntry->Flink;
69     }
70 
71     //
72     // Nothing found?
73     //
74     if (NextEntry == ListHead)
75     {
76         //
77         // Bugcheck -- no data
78         //
79         KeBugCheckEx(RAMDISK_BOOT_INITIALIZATION_FAILED,
80                      RD_NO_XIPROM_DESCRIPTOR,
81                      STATUS_INVALID_PARAMETER,
82                      0,
83                      0);
84     }
85 
86     //
87     // Setup the input buffer
88     //
89     RtlZeroMemory(&RamdiskCreate, sizeof(RamdiskCreate));
90     RamdiskCreate.Version = sizeof(RamdiskCreate);
91     RamdiskCreate.DiskType = RAMDISK_BOOT_DISK;
92     RamdiskCreate.BasePage = MemoryDescriptor->BasePage;
93     RamdiskCreate.DiskOffset = 0;
94     RamdiskCreate.DiskLength.QuadPart = MemoryDescriptor->PageCount << PAGE_SHIFT;
95     RamdiskCreate.DiskGuid = RAMDISK_BOOTDISK_GUID;
96     RamdiskCreate.DriveLetter = L'C';
97     RamdiskCreate.Options.Fixed = TRUE;
98 
99     //
100     // Check for commandline parameters
101     //
102     CommandLine = LoaderBlock->LoadOptions;
103     if (CommandLine)
104     {
105         //
106         // Make everything upper case
107         //
108         _strupr(CommandLine);
109 
110         //
111         // Check for offset parameter
112         //
113         Offset = strstr(CommandLine, "RDIMAGEOFFSET");
114         if (Offset)
115         {
116             //
117             // Get to the actual value
118             //
119             OffsetValue = strstr(Offset, "=");
120             if (OffsetValue)
121             {
122                 //
123                 // Set the offset
124                 //
125                 RamdiskCreate.DiskOffset = atol(OffsetValue + 1);
126             }
127         }
128 
129         //
130         // Reduce the disk length
131         //
132         RamdiskCreate.DiskLength.QuadPart -= RamdiskCreate.DiskOffset;
133 
134         //
135         // Check for length parameter
136         //
137         Length = strstr(CommandLine, "RDIMAGELENGTH");
138         if (Length)
139         {
140             //
141             // Get to the actual value
142             //
143             LengthValue = strstr(Length, "=");
144             if (LengthValue)
145             {
146                 //
147                 // Set the offset
148                 //
149                 RamdiskCreate.DiskLength.QuadPart = _atoi64(LengthValue + 1);
150             }
151         }
152     }
153 
154     //
155     // Setup object attributes
156     //
157     RtlInitUnicodeString(&ObjectName, L"\\Device\\Ramdisk");
158     InitializeObjectAttributes(&ObjectAttributes,
159                                &ObjectName,
160                                OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
161                                NULL,
162                                NULL);
163 
164     //
165     // Open a handle to the driver
166     //
167     Status = ZwOpenFile(&DriverHandle,
168                         GENERIC_ALL | SYNCHRONIZE,
169                         &ObjectAttributes,
170                         &IoStatusBlock,
171                         FILE_SHARE_READ | FILE_SHARE_WRITE,
172                         FILE_SYNCHRONOUS_IO_NONALERT);
173     if (!(NT_SUCCESS(Status)) || !(NT_SUCCESS(IoStatusBlock.Status)))
174     {
175         //
176         // Bugcheck -- no driver
177         //
178         KeBugCheckEx(RAMDISK_BOOT_INITIALIZATION_FAILED,
179                      RD_NO_RAMDISK_DRIVER,
180                      IoStatusBlock.Status,
181                      0,
182                      0);
183     }
184 
185     //
186     // Send create command
187     //
188     Status = ZwDeviceIoControlFile(DriverHandle,
189                                    NULL,
190                                    NULL,
191                                    NULL,
192                                    &IoStatusBlock,
193                                    FSCTL_CREATE_RAM_DISK,
194                                    &RamdiskCreate,
195                                    sizeof(RamdiskCreate),
196                                    NULL,
197                                    0);
198     ZwClose(DriverHandle);
199     if (!(NT_SUCCESS(Status)) || !(NT_SUCCESS(IoStatusBlock.Status)))
200     {
201         //
202         // Bugcheck -- driver failed
203         //
204         KeBugCheckEx(RAMDISK_BOOT_INITIALIZATION_FAILED,
205                      RD_FSCTL_FAILED,
206                      IoStatusBlock.Status,
207                      0,
208                      0);
209     }
210 
211     //
212     // Convert the GUID
213     //
214     Status = RtlStringFromGUID(&RamdiskCreate.DiskGuid, &GuidString);
215     if (!NT_SUCCESS(Status))
216     {
217         //
218         // Bugcheck -- GUID convert failed
219         //
220         KeBugCheckEx(RAMDISK_BOOT_INITIALIZATION_FAILED,
221                      RD_GUID_CONVERT_FAILED,
222                      Status,
223                      0,
224                      0);
225     }
226 
227     //
228     // Build the symbolic link name and target
229     //
230     _snwprintf(SourceString,
231                sizeof(SourceString)/sizeof(WCHAR),
232                L"\\Device\\Ramdisk%wZ",
233                &GuidString);
234     SymbolicLinkName.Length = 38;
235     SymbolicLinkName.MaximumLength = 38 + sizeof(UNICODE_NULL);
236     SymbolicLinkName.Buffer = L"\\ArcName\\ramdisk(0)";
237 
238     //
239     // Create the symbolic link
240     //
241     RtlInitUnicodeString(&DeviceString, SourceString);
242     Status = IoCreateSymbolicLink(&SymbolicLinkName, &DeviceString);
243     RtlFreeUnicodeString(&GuidString);
244     if (!NT_SUCCESS(Status))
245     {
246         //
247         // Bugcheck -- symlink create failed
248         //
249         KeBugCheckEx(RAMDISK_BOOT_INITIALIZATION_FAILED,
250                      RD_SYMLINK_CREATE_FAILED,
251                      Status,
252                      0,
253                      0);
254     }
255 
256     //
257     // ReactOS hack (drive letter should not be hardcoded, and maybe set by mountmgr.sys)
258     //
259     {
260         ANSI_STRING AnsiPath;
261         CHAR Buffer[256];
262         UNICODE_STRING NtSystemRoot;
263         UNICODE_STRING DriveLetter = RTL_CONSTANT_STRING(L"\\??\\X:");
264 
265         AnsiPath.Length = sprintf(Buffer, "X:%s", LoaderBlock->NtBootPathName);
266         AnsiPath.MaximumLength = AnsiPath.Length + 1;
267         AnsiPath.Buffer = Buffer;
268         RtlInitEmptyUnicodeString(&NtSystemRoot,
269                                   SharedUserData->NtSystemRoot,
270                                   sizeof(SharedUserData->NtSystemRoot));
271         RtlAnsiStringToUnicodeString(&NtSystemRoot, &AnsiPath, FALSE);
272         IoCreateSymbolicLink(&DriveLetter, &DeviceString);
273     }
274 
275     //
276     // Wait for ramdisk relations being initialized
277     //
278 
279     KeWaitForSingleObject(&PiEnumerationFinished, Executive, KernelMode, FALSE, NULL);
280 
281     //
282     // We made it
283     //
284     return STATUS_SUCCESS;
285 }
286