3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 /* INCLUDES *******************************************************************/
29 DBG_DEFAULT_CHANNEL(LINUX
);
31 /* GLOBALS ********************************************************************/
33 #define LINUX_READ_CHUNK_SIZE 0x20000 // Read 128k at a time
35 PLINUX_BOOTSECTOR LinuxBootSector
= NULL
;
36 PLINUX_SETUPSECTOR LinuxSetupSector
= NULL
;
37 ULONG SetupSectorSize
= 0;
38 BOOLEAN NewStyleLinuxKernel
= FALSE
;
39 ULONG LinuxKernelSize
= 0;
40 ULONG LinuxInitrdSize
= 0;
41 PCSTR LinuxKernelName
= NULL
;
42 PCSTR LinuxInitrdName
= NULL
;
43 PSTR LinuxCommandLine
= NULL
;
44 ULONG LinuxCommandLineSize
= 0;
45 PVOID LinuxKernelLoadAddress
= NULL
;
46 PVOID LinuxInitrdLoadAddress
= NULL
;
47 CHAR LinuxBootDescription
[80];
48 PCSTR LinuxBootPath
= NULL
;
50 /* FUNCTIONS ******************************************************************/
54 IN OUT PSTR QuotedString
)
60 /* Skip spaces up to " */
62 while (*p
== ' ' || *p
== '\t' || *p
== '"')
67 while (*p
!= ANSI_NULL
&& *p
!= '"')
72 /* Move the NULL-terminated string back into 'QuotedString' in place */
73 Size
= (strlen(Start
) + 1) * sizeof(CHAR
);
74 memmove(QuotedString
, Start
, Size
);
84 PFILE LinuxKernel
= 0;
85 PFILE LinuxInitrdFile
= 0;
87 Description
= GetArgumentValue(Argc
, Argv
, "LoadIdentifier");
89 RtlStringCbPrintfA(LinuxBootDescription
, sizeof(LinuxBootDescription
), "Loading %s...", Description
);
91 strcpy(LinuxBootDescription
, "Loading Linux...");
94 UiDrawStatusText(LinuxBootDescription
);
95 UiDrawProgressBarCenter(0, 100, LinuxBootDescription
);
97 /* Find all the message box settings and run them */
98 UiShowMessageBoxesInArgv(Argc
, Argv
);
100 /* Parse the .ini file section */
101 if (!LinuxParseIniSection(Argc
, Argv
))
102 goto LinuxBootFailed
;
104 /* Open the kernel */
105 LinuxKernel
= FsOpenFile(LinuxKernelName
);
108 UiMessageBox("Linux kernel \'%s\' not found.", LinuxKernelName
);
109 goto LinuxBootFailed
;
112 /* Open the initrd file image (if necessary) */
115 LinuxInitrdFile
= FsOpenFile(LinuxInitrdName
);
116 if (!LinuxInitrdFile
)
118 UiMessageBox("Linux initrd image \'%s\' not found.", LinuxInitrdName
);
119 goto LinuxBootFailed
;
123 /* Read the boot sector */
124 if (!LinuxReadBootSector(LinuxKernel
))
125 goto LinuxBootFailed
;
127 /* Read the setup sector */
128 if (!LinuxReadSetupSector(LinuxKernel
))
129 goto LinuxBootFailed
;
131 /* Calc kernel size */
132 LinuxKernelSize
= FsGetFileSize(LinuxKernel
) - (512 + SetupSectorSize
);
134 /* Get the file size */
135 LinuxInitrdSize
= FsGetFileSize(LinuxInitrdFile
);
137 /* Read the kernel */
138 if (!LinuxReadKernel(LinuxKernel
))
139 goto LinuxBootFailed
;
141 /* Read the initrd (if necessary) */
144 if (!LinuxReadInitrd(LinuxInitrdFile
))
145 goto LinuxBootFailed
;
148 // If the default root device is set to FLOPPY (0000h), change to /dev/fd0 (0200h)
149 if (LinuxBootSector
->RootDevice
== 0x0000)
150 LinuxBootSector
->RootDevice
= 0x0200;
152 if (LinuxSetupSector
->Version
>= 0x0202)
154 LinuxSetupSector
->CommandLinePointer
= 0x99000;
158 LinuxBootSector
->CommandLineMagic
= LINUX_COMMAND_LINE_MAGIC
;
159 LinuxBootSector
->CommandLineOffset
= 0x9000;
162 if (NewStyleLinuxKernel
)
163 LinuxSetupSector
->TypeOfLoader
= LINUX_LOADER_TYPE_FREELOADER
;
165 LinuxSetupSector
->LoadFlags
= 0;
167 RtlCopyMemory((PVOID
)0x90000, LinuxBootSector
, 512);
168 RtlCopyMemory((PVOID
)0x90200, LinuxSetupSector
, SetupSectorSize
);
169 RtlCopyMemory((PVOID
)0x99000,
170 LinuxCommandLine
? LinuxCommandLine
: "",
171 LinuxCommandLine
? LinuxCommandLineSize
: sizeof(ANSI_NULL
));
173 UiUnInitialize("Booting Linux...");
176 DiskStopFloppyMotor();
178 if (LinuxSetupSector
->LoadFlags
& LINUX_FLAG_LOAD_HIGH
)
179 BootNewLinuxKernel();
181 BootOldLinuxKernel(LinuxKernelSize
);
187 FsCloseFile(LinuxKernel
);
190 FsCloseFile(LinuxInitrdFile
);
192 if (LinuxBootSector
!= NULL
)
193 MmFreeMemory(LinuxBootSector
);
195 if (LinuxSetupSector
!= NULL
)
196 MmFreeMemory(LinuxSetupSector
);
198 if (LinuxKernelLoadAddress
!= NULL
)
199 MmFreeMemory(LinuxKernelLoadAddress
);
201 if (LinuxInitrdLoadAddress
!= NULL
)
202 MmFreeMemory(LinuxInitrdLoadAddress
);
204 LinuxBootSector
= NULL
;
205 LinuxSetupSector
= NULL
;
207 NewStyleLinuxKernel
= FALSE
;
210 LinuxKernelName
= NULL
;
211 LinuxInitrdName
= NULL
;
212 LinuxCommandLine
= NULL
;
213 LinuxCommandLineSize
= 0;
214 LinuxKernelLoadAddress
= NULL
;
215 LinuxInitrdLoadAddress
= NULL
;
216 *LinuxBootDescription
= ANSI_NULL
;
217 LinuxBootPath
= NULL
;
223 LinuxParseIniSection(
227 LinuxBootPath
= GetArgumentValue(Argc
, Argv
, "BootPath");
230 UiMessageBox("Boot path not specified for selected OS!");
234 /* Get the kernel name */
235 LinuxKernelName
= GetArgumentValue(Argc
, Argv
, "Kernel");
236 if (!LinuxKernelName
)
238 UiMessageBox("Linux kernel filename not specified for selected OS!");
242 /* Get the initrd name (optional) */
243 LinuxInitrdName
= GetArgumentValue(Argc
, Argv
, "Initrd");
245 /* Get the command line (optional) */
246 LinuxCommandLineSize
= 0;
247 LinuxCommandLine
= GetArgumentValue(Argc
, Argv
, "CommandLine");
248 if (LinuxCommandLine
)
250 RemoveQuotes(LinuxCommandLine
);
251 LinuxCommandLineSize
= min(strlen(LinuxCommandLine
) + 1, 260);
257 BOOLEAN
LinuxReadBootSector(PFILE LinuxKernelFile
)
259 /* Allocate memory for boot sector */
260 LinuxBootSector
= MmAllocateMemoryWithType(512, LoaderSystemCode
);
261 if (LinuxBootSector
== NULL
)
264 /* Read linux boot sector */
265 FsSetFilePointer(LinuxKernelFile
, 0);
266 if (!FsReadFile(LinuxKernelFile
, 512, NULL
, LinuxBootSector
))
269 /* Check for validity */
270 if (LinuxBootSector
->BootFlag
!= LINUX_BOOT_SECTOR_MAGIC
)
272 UiMessageBox("Invalid boot sector magic (0xaa55)");
276 // DbgDumpBuffer(DPRINT_LINUX, LinuxBootSector, 512);
278 TRACE("SetupSectors: %d\n" , LinuxBootSector
->SetupSectors
);
279 TRACE("RootFlags: 0x%x\n", LinuxBootSector
->RootFlags
);
280 TRACE("SystemSize: 0x%x\n", LinuxBootSector
->SystemSize
);
281 TRACE("SwapDevice: 0x%x\n", LinuxBootSector
->SwapDevice
);
282 TRACE("RamSize: 0x%x\n", LinuxBootSector
->RamSize
);
283 TRACE("VideoMode: 0x%x\n", LinuxBootSector
->VideoMode
);
284 TRACE("RootDevice: 0x%x\n", LinuxBootSector
->RootDevice
);
285 TRACE("BootFlag: 0x%x\n", LinuxBootSector
->BootFlag
);
290 BOOLEAN
LinuxReadSetupSector(PFILE LinuxKernelFile
)
292 UCHAR TempLinuxSetupSector
[512];
294 /* Read first linux setup sector */
295 FsSetFilePointer(LinuxKernelFile
, 512);
296 if (!FsReadFile(LinuxKernelFile
, 512, NULL
, TempLinuxSetupSector
))
299 /* Check the kernel version */
300 LinuxSetupSector
= (PLINUX_SETUPSECTOR
)TempLinuxSetupSector
;
301 if (!LinuxCheckKernelVersion())
304 if (NewStyleLinuxKernel
)
305 SetupSectorSize
= 512 * LinuxBootSector
->SetupSectors
;
307 SetupSectorSize
= 512 * 4; // Always 4 setup sectors
309 /* Allocate memory for setup sectors */
310 LinuxSetupSector
= MmAllocateMemoryWithType(SetupSectorSize
, LoaderSystemCode
);
311 if (LinuxSetupSector
== NULL
)
314 /* Copy over first setup sector */
315 RtlCopyMemory(LinuxSetupSector
, TempLinuxSetupSector
, 512);
317 /* Read in the rest of the linux setup sectors */
318 FsSetFilePointer(LinuxKernelFile
, 1024);
319 if (!FsReadFile(LinuxKernelFile
, SetupSectorSize
- 512, NULL
, (PVOID
)((ULONG_PTR
)LinuxSetupSector
+ 512)))
322 // DbgDumpBuffer(DPRINT_LINUX, LinuxSetupSector, SetupSectorSize);
324 TRACE("SetupHeaderSignature: 0x%x (HdrS)\n", LinuxSetupSector
->SetupHeaderSignature
);
325 TRACE("Version: 0x%x\n", LinuxSetupSector
->Version
);
326 TRACE("RealModeSwitch: 0x%x\n", LinuxSetupSector
->RealModeSwitch
);
327 TRACE("SetupSeg: 0x%x\n", LinuxSetupSector
->SetupSeg
);
328 TRACE("StartSystemSeg: 0x%x\n", LinuxSetupSector
->StartSystemSeg
);
329 TRACE("KernelVersion: 0x%x\n", LinuxSetupSector
->KernelVersion
);
330 TRACE("TypeOfLoader: 0x%x\n", LinuxSetupSector
->TypeOfLoader
);
331 TRACE("LoadFlags: 0x%x\n", LinuxSetupSector
->LoadFlags
);
332 TRACE("SetupMoveSize: 0x%x\n", LinuxSetupSector
->SetupMoveSize
);
333 TRACE("Code32Start: 0x%x\n", LinuxSetupSector
->Code32Start
);
334 TRACE("RamdiskAddress: 0x%x\n", LinuxSetupSector
->RamdiskAddress
);
335 TRACE("RamdiskSize: 0x%x\n", LinuxSetupSector
->RamdiskSize
);
336 TRACE("BootSectKludgeOffset: 0x%x\n", LinuxSetupSector
->BootSectKludgeOffset
);
337 TRACE("BootSectKludgeSegment: 0x%x\n", LinuxSetupSector
->BootSectKludgeSegment
);
338 TRACE("HeapEnd: 0x%x\n", LinuxSetupSector
->HeapEnd
);
343 BOOLEAN
LinuxReadKernel(PFILE LinuxKernelFile
)
346 CHAR StatusText
[260];
349 RtlStringCbPrintfA(StatusText
, sizeof(StatusText
), "Loading %s", LinuxKernelName
);
350 UiDrawStatusText(StatusText
);
352 /* Allocate memory for Linux kernel */
353 LinuxKernelLoadAddress
= MmAllocateMemoryAtAddress(LinuxKernelSize
, (PVOID
)LINUX_KERNEL_LOAD_ADDRESS
, LoaderSystemCode
);
354 if (LinuxKernelLoadAddress
!= (PVOID
)LINUX_KERNEL_LOAD_ADDRESS
)
359 LoadAddress
= LinuxKernelLoadAddress
;
361 /* Read linux kernel to 0x100000 (1mb) */
362 FsSetFilePointer(LinuxKernelFile
, 512 + SetupSectorSize
);
363 for (BytesLoaded
=0; BytesLoaded
<LinuxKernelSize
; )
365 if (!FsReadFile(LinuxKernelFile
, LINUX_READ_CHUNK_SIZE
, NULL
, LoadAddress
))
368 BytesLoaded
+= LINUX_READ_CHUNK_SIZE
;
369 LoadAddress
= (PVOID
)((ULONG_PTR
)LoadAddress
+ LINUX_READ_CHUNK_SIZE
);
371 UiDrawProgressBarCenter(BytesLoaded
, LinuxKernelSize
+ LinuxInitrdSize
, LinuxBootDescription
);
377 BOOLEAN
LinuxCheckKernelVersion(VOID
)
379 /* Just assume old kernel until we find otherwise */
380 NewStyleLinuxKernel
= FALSE
;
382 /* Check for new style setup header */
383 if (LinuxSetupSector
->SetupHeaderSignature
!= LINUX_SETUP_HEADER_ID
)
385 NewStyleLinuxKernel
= FALSE
;
387 /* Check for version below 2.0 */
388 else if (LinuxSetupSector
->Version
< 0x0200)
390 NewStyleLinuxKernel
= FALSE
;
392 /* Check for version 2.0 */
393 else if (LinuxSetupSector
->Version
== 0x0200)
395 NewStyleLinuxKernel
= TRUE
;
397 /* Check for version 2.01+ */
398 else if (LinuxSetupSector
->Version
>= 0x0201)
400 NewStyleLinuxKernel
= TRUE
;
401 LinuxSetupSector
->HeapEnd
= 0x9000;
402 LinuxSetupSector
->LoadFlags
|= LINUX_FLAG_CAN_USE_HEAP
;
405 if ((NewStyleLinuxKernel
== FALSE
) && (LinuxInitrdName
))
407 UiMessageBox("Error: Cannot load a ramdisk (initrd) with an old kernel image.");
414 BOOLEAN
LinuxReadInitrd(PFILE LinuxInitrdFile
)
417 CHAR StatusText
[260];
419 RtlStringCbPrintfA(StatusText
, sizeof(StatusText
), "Loading %s", LinuxInitrdName
);
420 UiDrawStatusText(StatusText
);
422 // Allocate memory for the ramdisk
423 //LinuxInitrdLoadAddress = MmAllocateMemory(LinuxInitrdSize);
424 // Try to align it at the next MB boundary after the kernel
425 //LinuxInitrdLoadAddress = MmAllocateMemoryAtAddress(LinuxInitrdSize, (PVOID)ROUND_UP((LINUX_KERNEL_LOAD_ADDRESS + LinuxKernelSize), 0x100000));
426 if (LinuxSetupSector
->Version
<= 0x0202)
428 LinuxInitrdLoadAddress
= MmAllocateHighestMemoryBelowAddress(LinuxInitrdSize
, (PVOID
)LINUX_MAX_INITRD_ADDRESS
, LoaderSystemCode
);
432 LinuxInitrdLoadAddress
= MmAllocateHighestMemoryBelowAddress(LinuxInitrdSize
, (PVOID
)LinuxSetupSector
->InitrdAddressMax
, LoaderSystemCode
);
434 if (LinuxInitrdLoadAddress
== NULL
)
439 /* Set the information in the setup struct */
440 LinuxSetupSector
->RamdiskAddress
= (ULONG
)LinuxInitrdLoadAddress
;
441 LinuxSetupSector
->RamdiskSize
= LinuxInitrdSize
;
443 TRACE("RamdiskAddress: 0x%x\n", LinuxSetupSector
->RamdiskAddress
);
444 TRACE("RamdiskSize: 0x%x\n", LinuxSetupSector
->RamdiskSize
);
446 if (LinuxSetupSector
->Version
>= 0x0203)
448 TRACE("InitrdAddressMax: 0x%x\n", LinuxSetupSector
->InitrdAddressMax
);
451 /* Read in the ramdisk */
452 for (BytesLoaded
=0; BytesLoaded
<LinuxInitrdSize
; )
454 if (!FsReadFile(LinuxInitrdFile
, LINUX_READ_CHUNK_SIZE
, NULL
, (PVOID
)LinuxInitrdLoadAddress
))
457 BytesLoaded
+= LINUX_READ_CHUNK_SIZE
;
458 LinuxInitrdLoadAddress
= (PVOID
)((ULONG_PTR
)LinuxInitrdLoadAddress
+ LINUX_READ_CHUNK_SIZE
);
460 UiDrawProgressBarCenter(BytesLoaded
+ LinuxKernelSize
, LinuxInitrdSize
+ LinuxKernelSize
, LinuxBootDescription
);