[BOOTMGFW]
[reactos.git] / reactos / boot / environ / app / bootmgr / bootmgr.c
1 /*
2 * COPYRIGHT: See COPYING.ARM in the top level directory
3 * PROJECT: ReactOS UEFI Boot Manager
4 * FILE: boot/environ/app/bootmgr.c
5 * PURPOSE: Boot Manager Entrypoint
6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "bootmgr.h"
12
13 /* DATA VARIABLES ************************************************************/
14
15 DEFINE_GUID(GUID_WINDOWS_BOOTMGR,
16 0x9DEA862C,
17 0x5CDD,
18 0x4E70,
19 0xAC, 0xC1, 0xF3, 0x2B, 0x34, 0x4D, 0x47, 0x95);
20
21 ULONGLONG ApplicationStartTime;
22 ULONGLONG PostTime;
23 GUID BmApplicationIdentifier;
24 PWCHAR BootDirectory;
25
26 /* FUNCTIONS *****************************************************************/
27
28 NTSTATUS
29 BmpFwGetApplicationDirectoryPath (
30 _In_ PUNICODE_STRING ApplicationDirectoryPath
31 )
32 {
33 NTSTATUS Status;
34 ULONG i, AppPathLength;
35 PWCHAR ApplicationPath, PathCopy;
36
37 /* Clear the incoming string */
38 ApplicationDirectoryPath->Length = 0;
39 ApplicationDirectoryPath->MaximumLength = 0;
40 ApplicationDirectoryPath->Buffer = 0;
41
42 /* Get the boot application path */
43 ApplicationPath = NULL;
44 Status = BlGetBootOptionString(BlpApplicationEntry.BcdData,
45 BcdLibraryString_ApplicationPath,
46 &ApplicationPath);
47 if (NT_SUCCESS(Status))
48 {
49 /* Calculate the length of the application path */
50 for (i = wcslen(ApplicationPath) - 1; i > 0; i--)
51 {
52 /* Keep going until the path separator */
53 if (ApplicationPath[i] == OBJ_NAME_PATH_SEPARATOR)
54 {
55 break;
56 }
57 }
58
59 /* Check if we have space for one more character */
60 AppPathLength = i + 1;
61 if (AppPathLength < i)
62 {
63 /* Nope, we'll overflow */
64 AppPathLength = -1;
65 Status = STATUS_INTEGER_OVERFLOW;
66 }
67 else
68 {
69 /* Go ahead */
70 Status = STATUS_SUCCESS;
71 }
72
73 /* No overflow? */
74 if (NT_SUCCESS(Status))
75 {
76 /* Check if it's safe to multiply by two */
77 if ((AppPathLength * sizeof(WCHAR)) > 0xFFFFFFFF)
78 {
79 /* Nope */
80 AppPathLength = -1;
81 Status = STATUS_INTEGER_OVERFLOW;
82 }
83 else
84 {
85 /* We're good, do the multiplication */
86 Status = STATUS_SUCCESS;
87 AppPathLength *= sizeof(WCHAR);
88 }
89
90 /* Allocate a copy for the string */
91 if (NT_SUCCESS(Status))
92 {
93 PathCopy = BlMmAllocateHeap(AppPathLength);
94 if (PathCopy)
95 {
96 /* NULL-terminate it */
97 RtlCopyMemory(PathCopy,
98 ApplicationPath,
99 AppPathLength - sizeof(UNICODE_NULL));
100 PathCopy[AppPathLength] = UNICODE_NULL;
101
102 /* Finally, initialize the outoing string */
103 RtlInitUnicodeString(ApplicationDirectoryPath, PathCopy);
104 }
105 else
106 {
107 /* No memory, fail */
108 Status = STATUS_NO_MEMORY;
109 }
110 }
111 }
112 }
113
114 /* Check if we had an application path */
115 if (ApplicationPath)
116 {
117 /* No longer need this, free it */
118 BlMmFreeHeap(ApplicationPath);
119 }
120
121 /* All done! */
122 return Status;
123
124 }
125 NTSTATUS
126 BmFwInitializeBootDirectoryPath (
127 VOID
128 )
129 {
130 PWCHAR FinalPath;
131 NTSTATUS Status;
132 PWCHAR BcdDirectory;
133 UNICODE_STRING BcdPath;
134 ULONG FinalSize;
135 ULONG FileHandle, DeviceHandle;
136
137 /* Initialize everything for failure */
138 BcdPath.MaximumLength = 0;
139 BcdPath.Buffer = NULL;
140 BcdDirectory = NULL;
141 FinalPath = NULL;
142 FileHandle = -1;
143 DeviceHandle = -1;
144
145 /* Try to open the boot device */
146 Status = BlpDeviceOpen(BlpBootDevice, 1u, 0, &DeviceHandle);
147 if (!NT_SUCCESS(Status))
148 {
149 EfiPrintf(L"Device open failed: %lx\r\n", Status);
150 goto Quickie;
151 }
152
153 /* Get the directory path */
154 Status = BmpFwGetApplicationDirectoryPath(&BcdPath);
155 BcdDirectory = BcdPath.Buffer;
156 if (!NT_SUCCESS(Status))
157 {
158 EfiPrintf(L"path failed: %lx\n", Status);
159 goto Quickie;
160 }
161
162 /* Add the BCD file name to it */
163 FinalSize = BcdPath.MaximumLength + sizeof(L"\\BCD") - sizeof(UNICODE_NULL);
164 if (FinalSize < BcdPath.MaximumLength)
165 {
166 goto Quickie;
167 }
168
169 /* Allocate space for the final path */
170 FinalPath = BlMmAllocateHeap(FinalSize);
171 if (!FinalPath)
172 {
173 goto Quickie;
174 }
175
176 /* Build it */
177 RtlZeroMemory(FinalPath, FinalSize);
178 RtlCopyMemory(FinalPath, BcdDirectory, BcdPath.MaximumLength);
179 wcsncat(FinalPath, L"\\BCD", FinalSize / sizeof(WCHAR));
180
181 /* Try to open the file */
182 EfiPrintf(L"Opening: %s\r\n", FinalPath);
183 Status = BlFileOpen(DeviceHandle, FinalPath, 1, &FileHandle);
184 if (!NT_SUCCESS(Status))
185 {
186 BootDirectory = BcdDirectory;
187 goto Quickie;
188 }
189
190 BootDirectory = L"\\EFI\\Microsoft\\Boot";
191
192 Quickie:
193 /* Free all the allocations we made */
194 if (BcdDirectory)
195 {
196 Status = BlMmFreeHeap(BcdDirectory);
197 }
198 if (FinalPath)
199 {
200 Status = BlMmFreeHeap(FinalPath);
201 }
202
203 /* Close the BCD file */
204 if (FileHandle != -1)
205 {
206 Status = BlFileClose(FileHandle);
207 }
208
209 /* Close the boot device */
210 if (DeviceHandle != -1)
211 {
212 Status = BlDeviceClose(DeviceHandle);
213 }
214
215 /* Return back to the caller */
216 return Status;
217 }
218
219
220 /*++
221 * @name BmMain
222 *
223 * The BmMain function implements the Windows Boot Application entrypoint for
224 * the Boot Manager.
225 *
226 * @param BootParameters
227 * Pointer to the Boot Application Parameter Block.
228 *
229 * @return NT_SUCCESS if the image was loaded correctly, relevant error code
230 * otherwise.
231 *
232 *--*/
233 NTSTATUS
234 BmMain (
235 _In_ PBOOT_APPLICATION_PARAMETER_BLOCK BootParameters
236 )
237 {
238 NTSTATUS Status;
239 BL_LIBRARY_PARAMETERS LibraryParameters;
240 PBL_RETURN_ARGUMENTS ReturnArguments;
241 BOOLEAN RebootOnError;
242 PGUID AppIdentifier;
243 // HANDLE BcdHandle;
244
245 EfiPrintf(L"ReactOS UEFI Boot Manager Initializing...\n");
246
247 /* Reading the BCD can change this later on */
248 RebootOnError = FALSE;
249
250 /* Save the start/end-of-POST time */
251 ApplicationStartTime = __rdtsc();
252 PostTime = ApplicationStartTime;
253
254 /* Setup the boot library parameters for this application */
255 BlSetupDefaultParameters(&LibraryParameters);
256 LibraryParameters.TranslationType = BlNone;
257 LibraryParameters.LibraryFlags = 0x400 | 0x8;
258 LibraryParameters.MinimumAllocationCount = 16;
259 LibraryParameters.MinimumHeapSize = 512 * 1024;
260
261 /* Initialize the boot library */
262 Status = BlInitializeLibrary(BootParameters, &LibraryParameters);
263 if (!NT_SUCCESS(Status))
264 {
265 /* Check for failure due to invalid application entry */
266 if (Status != STATUS_INVALID_PARAMETER_9)
267 {
268 /* Specifically print out what happened */
269 EfiPrintf(L"BlInitializeLibrary failed 0x%x\r\n", Status);
270 }
271
272 /* Go to exit path */
273 goto Quickie;
274 }
275
276 /* Get the application identifier */
277 AppIdentifier = BlGetApplicationIdentifier();
278 if (!AppIdentifier)
279 {
280 /* None was given, so set our default one */
281 AppIdentifier = (PGUID)&GUID_WINDOWS_BOOTMGR;
282 }
283
284 /* Save our identifier */
285 BmApplicationIdentifier = *AppIdentifier;
286
287 /* Initialize the file system to open a handle to our root boot directory */
288 BmFwInitializeBootDirectoryPath();
289
290 //Status = BmOpenDataStore(&BcdHandle);
291
292 EfiPrintf(L"We are A-OK!\r\n");
293 EfiStall(10000000);
294
295 Quickie:
296 /* Check if we should reboot */
297 if ((RebootOnError) ||
298 (BlpApplicationEntry.Flags & BL_APPLICATION_ENTRY_REBOOT_ON_ERROR))
299 {
300 /* Reboot the box */
301 BlFwReboot();
302 Status = STATUS_SUCCESS;
303 }
304 else
305 {
306 /* Return back to the caller with the error argument encoded */
307 ReturnArguments = (PVOID)((ULONG_PTR)BootParameters + BootParameters->ReturnArgumentsOffset);
308 ReturnArguments->Version = BL_RETURN_ARGUMENTS_VERSION;
309 ReturnArguments->Status = Status;
310
311 /* Tear down the boot library*/
312 BlDestroyLibrary();
313 }
314
315 /* Return back status */
316 return Status;
317 }
318