c1836fff223fd19f20a7803f15aa1dd82f565b90
[reactos.git] / boot / freeldr / freeldr / ntldr / setupldr.c
1 /*
2 * PROJECT: FreeLoader
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Windows-compatible NT OS Setup Loader.
5 * COPYRIGHT: Copyright 2009-2019 Aleksey Bragin <aleksey@reactos.org>
6 */
7
8 #include <freeldr.h>
9 #include <ndk/ldrtypes.h>
10 #include <arc/setupblk.h>
11 #include "winldr.h"
12 #include "inffile.h"
13
14 #include <debug.h>
15 DBG_DEFAULT_CHANNEL(WINDOWS);
16
17 #define TAG_BOOT_OPTIONS 'pOtB'
18
19 // TODO: Move to .h
20 VOID AllocateAndInitLPB(PLOADER_PARAMETER_BLOCK *OutLoaderBlock);
21
22 static VOID
23 SetupLdrLoadNlsData(PLOADER_PARAMETER_BLOCK LoaderBlock, HINF InfHandle, PCSTR SearchPath)
24 {
25 INFCONTEXT InfContext;
26 PCSTR AnsiName, OemName, LangName;
27
28 /* Get ANSI codepage file */
29 if (!InfFindFirstLine(InfHandle, "NLS", "AnsiCodepage", &InfContext))
30 {
31 ERR("Failed to find 'NLS/AnsiCodepage'\n");
32 return;
33 }
34 if (!InfGetDataField(&InfContext, 1, &AnsiName))
35 {
36 ERR("Failed to get load options\n");
37 return;
38 }
39
40 /* Get OEM codepage file */
41 if (!InfFindFirstLine(InfHandle, "NLS", "OemCodepage", &InfContext))
42 {
43 ERR("Failed to find 'NLS/AnsiCodepage'\n");
44 return;
45 }
46 if (!InfGetDataField(&InfContext, 1, &OemName))
47 {
48 ERR("Failed to get load options\n");
49 return;
50 }
51
52 if (!InfFindFirstLine(InfHandle, "NLS", "UnicodeCasetable", &InfContext))
53 {
54 ERR("Failed to find 'NLS/AnsiCodepage'\n");
55 return;
56 }
57 if (!InfGetDataField(&InfContext, 1, &LangName))
58 {
59 ERR("Failed to get load options\n");
60 return;
61 }
62
63 TRACE("NLS data '%s' '%s' '%s'\n", AnsiName, OemName, LangName);
64
65 #if DBG
66 {
67 BOOLEAN Success = WinLdrLoadNLSData(LoaderBlock, SearchPath, AnsiName, OemName, LangName);
68 TRACE("NLS data loading %s\n", Success ? "successful" : "failed");
69 }
70 #else
71 WinLdrLoadNLSData(LoaderBlock, SearchPath, AnsiName, OemName, LangName);
72 #endif
73
74 /* TODO: Load OEM HAL font */
75 // Value "OemHalFont"
76 }
77
78 static VOID
79 SetupLdrScanBootDrivers(PLIST_ENTRY BootDriverListHead, HINF InfHandle, PCSTR SearchPath)
80 {
81 INFCONTEXT InfContext, dirContext;
82 BOOLEAN Success;
83 PCSTR Media, DriverName, dirIndex, ImagePath;
84 WCHAR ServiceName[256];
85 WCHAR ImagePathW[256];
86
87 /* Open inf section */
88 if (!InfFindFirstLine(InfHandle, "SourceDisksFiles", NULL, &InfContext))
89 return;
90
91 /* Load all listed boot drivers */
92 do
93 {
94 if (InfGetDataField(&InfContext, 7, &Media) &&
95 InfGetDataField(&InfContext, 0, &DriverName) &&
96 InfGetDataField(&InfContext, 13, &dirIndex))
97 {
98 if ((strcmp(Media, "x") == 0) &&
99 InfFindFirstLine(InfHandle, "Directories", dirIndex, &dirContext) &&
100 InfGetDataField(&dirContext, 1, &ImagePath))
101 {
102 /* Convert name to widechar */
103 swprintf(ServiceName, L"%S", DriverName);
104
105 /* Prepare image path */
106 swprintf(ImagePathW, L"%S", ImagePath);
107 wcscat(ImagePathW, L"\\");
108 wcscat(ImagePathW, ServiceName);
109
110 /* Remove .sys extension */
111 ServiceName[wcslen(ServiceName) - 4] = 0;
112
113 /* Add it to the list */
114 Success = WinLdrAddDriverToList(BootDriverListHead,
115 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\",
116 ImagePathW,
117 ServiceName);
118 if (!Success)
119 {
120 ERR("Could not add boot driver '%s', '%s'\n", SearchPath, DriverName);
121 return;
122 }
123 }
124 }
125 } while (InfFindNextLine(&InfContext, &InfContext));
126 }
127
128
129 /* SETUP STARTER **************************************************************/
130
131 ARC_STATUS
132 LoadReactOSSetup(
133 IN ULONG Argc,
134 IN PCHAR Argv[],
135 IN PCHAR Envp[])
136 {
137 PCSTR ArgValue;
138 PCHAR File;
139 CHAR FileName[512];
140 CHAR BootPath[512];
141 CHAR BootOptions2[256];
142 PCSTR LoadOptions;
143 PSTR BootOptions;
144 BOOLEAN BootFromFloppy;
145 BOOLEAN Success;
146 ULONG i, ErrorLine;
147 HINF InfHandle;
148 INFCONTEXT InfContext;
149 PLOADER_PARAMETER_BLOCK LoaderBlock;
150 PSETUP_LOADER_BLOCK SetupBlock;
151 PCSTR SystemPath;
152
153 static PCSTR SourcePaths[] =
154 {
155 "", /* Only for floppy boot */
156 #if defined(_M_IX86)
157 "I386\\",
158 #elif defined(_M_MPPC)
159 "PPC\\",
160 #elif defined(_M_MRX000)
161 "MIPS\\",
162 #endif
163 "reactos\\",
164 NULL
165 };
166
167 UiDrawStatusText("Setup is loading...");
168
169 UiDrawBackdrop();
170 UiDrawProgressBarCenter(1, 100, "Loading ReactOS Setup...");
171
172 /* Retrieve the system path */
173 *BootPath = ANSI_NULL;
174 ArgValue = GetArgumentValue(Argc, Argv, "SystemPath");
175 if (ArgValue)
176 {
177 RtlStringCbCopyA(BootPath, sizeof(BootPath), ArgValue);
178 }
179 else
180 {
181 /*
182 * IMPROVE: I don't want to call MachDiskGetBootPath here as a
183 * default choice because I can call it after (see few lines below).
184 * Instead I reset BootPath here so that we can build the full path
185 * using the general code from below.
186 */
187 // MachDiskGetBootPath(BootPath, sizeof(BootPath));
188 // RtlStringCbCopyA(BootPath, sizeof(BootPath), ArgValue);
189 *BootPath = ANSI_NULL;
190 }
191
192 /*
193 * Check whether BootPath is a full path
194 * and if not, create a full boot path.
195 *
196 * See FsOpenFile for the technique used.
197 */
198 if (strrchr(BootPath, ')') == NULL)
199 {
200 /* Temporarily save the boot path */
201 RtlStringCbCopyA(FileName, sizeof(FileName), BootPath);
202
203 /* This is not a full path. Use the current (i.e. boot) device. */
204 MachDiskGetBootPath(BootPath, sizeof(BootPath));
205
206 /* Append a path separator if needed */
207 if (*FileName != '\\' && *FileName != '/')
208 RtlStringCbCatA(BootPath, sizeof(BootPath), "\\");
209
210 /* Append the remaining path */
211 RtlStringCbCatA(BootPath, sizeof(BootPath), FileName);
212 }
213
214 /* Append a backslash if needed */
215 if (!*BootPath || BootPath[strlen(BootPath) - 1] != '\\')
216 RtlStringCbCatA(BootPath, sizeof(BootPath), "\\");
217
218 TRACE("BootPath: '%s'\n", BootPath);
219
220 /* Retrieve the boot options */
221 *BootOptions2 = ANSI_NULL;
222 ArgValue = GetArgumentValue(Argc, Argv, "Options");
223 if (ArgValue)
224 RtlStringCbCopyA(BootOptions2, sizeof(BootOptions2), ArgValue);
225
226 TRACE("BootOptions: '%s'\n", BootOptions2);
227
228 /* Check if a ramdisk file was given */
229 File = strstr(BootOptions2, "/RDPATH=");
230 if (File)
231 {
232 /* Copy the file name and everything else after it */
233 RtlStringCbCopyA(FileName, sizeof(FileName), File + 8);
234
235 /* Null-terminate */
236 *strstr(FileName, " ") = ANSI_NULL;
237
238 /* Load the ramdisk */
239 if (!RamDiskLoadVirtualFile(FileName))
240 {
241 UiMessageBox("Failed to load RAM disk file %s", FileName);
242 return ENOENT;
243 }
244 }
245
246 /* Check if we booted from floppy */
247 BootFromFloppy = strstr(BootPath, "fdisk") != NULL;
248
249 /* Open 'txtsetup.sif' from any of source paths */
250 File = BootPath + strlen(BootPath);
251 for (i = BootFromFloppy ? 0 : 1; ; i++)
252 {
253 SystemPath = SourcePaths[i];
254 if (!SystemPath)
255 {
256 UiMessageBox("Failed to open txtsetup.sif");
257 return ENOENT;
258 }
259 RtlStringCbCopyA(File, sizeof(BootPath) - (File - BootPath)*sizeof(CHAR), SystemPath);
260 RtlStringCbCopyA(FileName, sizeof(FileName), BootPath);
261 RtlStringCbCatA(FileName, sizeof(FileName), "txtsetup.sif");
262 if (InfOpenFile(&InfHandle, FileName, &ErrorLine))
263 {
264 break;
265 }
266 }
267
268 TRACE("BootPath: '%s', SystemPath: '%s'\n", BootPath, SystemPath);
269
270 /* Get Load options - debug and non-debug */
271 if (!InfFindFirstLine(InfHandle, "SetupData", "OsLoadOptions", &InfContext))
272 {
273 ERR("Failed to find 'SetupData/OsLoadOptions'\n");
274 return EINVAL;
275 }
276
277 if (!InfGetDataField(&InfContext, 1, &LoadOptions))
278 {
279 ERR("Failed to get load options\n");
280 return EINVAL;
281 }
282
283 #if DBG
284 /* Get debug load options and use them */
285 if (InfFindFirstLine(InfHandle, "SetupData", "DbgOsLoadOptions", &InfContext))
286 {
287 PCSTR DbgLoadOptions;
288
289 if (InfGetDataField(&InfContext, 1, &DbgLoadOptions))
290 LoadOptions = DbgLoadOptions;
291 }
292 #endif
293
294 /* Copy loadoptions (original string will be freed) */
295 BootOptions = FrLdrTempAlloc(strlen(LoadOptions) + 1, TAG_BOOT_OPTIONS);
296 ASSERT(BootOptions);
297 strcpy(BootOptions, LoadOptions);
298
299 TRACE("BootOptions: '%s'\n", BootOptions);
300
301 /* Allocate and minimalist-initialize LPB */
302 AllocateAndInitLPB(&LoaderBlock);
303
304 /* Allocate and initialize setup loader block */
305 SetupBlock = &WinLdrSystemBlock->SetupBlock;
306 LoaderBlock->SetupLdrBlock = SetupBlock;
307
308 /* Set textmode setup flag */
309 SetupBlock->Flags = SETUPLDR_TEXT_MODE;
310
311 /* Load the system hive "setupreg.hiv" for setup */
312 UiDrawBackdrop();
313 UiDrawProgressBarCenter(15, 100, "Loading setup system hive...");
314 Success = WinLdrInitSystemHive(LoaderBlock, BootPath, TRUE);
315 TRACE("Setup SYSTEM hive %s\n", (Success ? "loaded" : "not loaded"));
316 /* Bail out if failure */
317 if (!Success)
318 return ENOEXEC;
319
320 /* Load NLS data, they are in the System32 directory of the installation medium */
321 RtlStringCbCopyA(FileName, sizeof(FileName), BootPath);
322 RtlStringCbCatA(FileName, sizeof(FileName), "system32\\");
323 SetupLdrLoadNlsData(LoaderBlock, InfHandle, FileName);
324
325 // UiDrawStatusText("Press F6 if you need to install a 3rd-party SCSI or RAID driver...");
326
327 /* Get a list of boot drivers */
328 SetupLdrScanBootDrivers(&LoaderBlock->BootDriverListHead, InfHandle, BootPath);
329
330 /* Close the inf file */
331 InfCloseFile(InfHandle);
332
333 UiDrawStatusText("The Setup program is starting...");
334
335 /* Load ReactOS Setup */
336 return LoadAndBootWindowsCommon(_WIN32_WINNT_WS03,
337 LoaderBlock,
338 BootOptions,
339 BootPath,
340 TRUE);
341 }