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