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 CHAR LinuxKernelName
[260];
42 CHAR LinuxInitrdName
[260];
43 BOOLEAN LinuxHasInitrd
= FALSE
;
44 CHAR LinuxCommandLine
[260] = "";
45 ULONG LinuxCommandLineSize
= 0;
46 PVOID LinuxKernelLoadAddress
= NULL
;
47 PVOID LinuxInitrdLoadAddress
= NULL
;
48 CHAR LinuxBootDescription
[80];
49 CHAR LinuxBootPath
[260] = "";
51 /* FUNCTIONS ******************************************************************/
53 BOOLEAN
RemoveQuotes(PCHAR QuotedString
)
59 /* Skip spaces up to " */
61 while (*p
== ' ' || *p
== '"')
66 while (*p
!= '"' && *p
!= ANSI_NULL
)
71 strcpy(TempString
, Start
);
72 strcpy(QuotedString
, TempString
);
78 LoadAndBootLinux(IN OperatingSystemItem
* OperatingSystem
,
79 IN USHORT OperatingSystemVersion
)
81 PCSTR SectionName
= OperatingSystem
->SystemPartition
;
82 PCSTR Description
= OperatingSystem
->LoadIdentifier
;
83 PFILE LinuxKernel
= 0;
84 PFILE LinuxInitrdFile
= 0;
89 sprintf(LinuxBootDescription
, "Loading %s...", Description
);
91 strcpy(LinuxBootDescription
, "Loading Linux...");
93 UiDrawStatusText(LinuxBootDescription
);
94 UiDrawProgressBarCenter(0, 100, LinuxBootDescription
);
96 /* Parse the .ini file section */
97 if (!LinuxParseIniSection(SectionName
))
100 /* Open the kernel */
101 LinuxKernel
= FsOpenFile(LinuxKernelName
);
104 UiMessageBox("Linux kernel \'%s\' not found.", LinuxKernelName
);
105 goto LinuxBootFailed
;
108 /* Open the initrd file image (if necessary) */
111 LinuxInitrdFile
= FsOpenFile(LinuxInitrdName
);
112 if (!LinuxInitrdFile
)
114 UiMessageBox("Linux initrd image \'%s\' not found.", LinuxInitrdName
);
115 goto LinuxBootFailed
;
119 /* Read the boot sector */
120 if (!LinuxReadBootSector(LinuxKernel
))
121 goto LinuxBootFailed
;
123 /* Read the setup sector */
124 if (!LinuxReadSetupSector(LinuxKernel
))
125 goto LinuxBootFailed
;
127 /* Calc kernel size */
128 LinuxKernelSize
= FsGetFileSize(LinuxKernel
) - (512 + SetupSectorSize
);
130 /* Get the file size */
131 LinuxInitrdSize
= FsGetFileSize(LinuxInitrdFile
);
133 /* Read the kernel */
134 if (!LinuxReadKernel(LinuxKernel
))
135 goto LinuxBootFailed
;
137 /* Read the initrd (if necessary) */
140 if (!LinuxReadInitrd(LinuxInitrdFile
))
141 goto LinuxBootFailed
;
144 // If the default root device is set to FLOPPY (0000h), change to /dev/fd0 (0200h)
145 if (LinuxBootSector
->RootDevice
== 0x0000)
146 LinuxBootSector
->RootDevice
= 0x0200;
148 if (LinuxSetupSector
->Version
>= 0x0202)
150 LinuxSetupSector
->CommandLinePointer
= 0x99000;
154 LinuxBootSector
->CommandLineMagic
= LINUX_COMMAND_LINE_MAGIC
;
155 LinuxBootSector
->CommandLineOffset
= 0x9000;
158 if (NewStyleLinuxKernel
)
159 LinuxSetupSector
->TypeOfLoader
= LINUX_LOADER_TYPE_FREELOADER
;
161 LinuxSetupSector
->LoadFlags
= 0;
163 RtlCopyMemory((PVOID
)0x90000, LinuxBootSector
, 512);
164 RtlCopyMemory((PVOID
)0x90200, LinuxSetupSector
, SetupSectorSize
);
165 RtlCopyMemory((PVOID
)0x99000, LinuxCommandLine
, LinuxCommandLineSize
);
167 UiUnInitialize("Booting Linux...");
169 DiskStopFloppyMotor();
171 if (LinuxSetupSector
->LoadFlags
& LINUX_FLAG_LOAD_HIGH
)
172 BootNewLinuxKernel();
174 BootOldLinuxKernel(LinuxKernelSize
);
180 FsCloseFile(LinuxKernel
);
183 FsCloseFile(LinuxInitrdFile
);
185 if (LinuxBootSector
!= NULL
)
186 MmFreeMemory(LinuxBootSector
);
188 if (LinuxSetupSector
!= NULL
)
189 MmFreeMemory(LinuxSetupSector
);
191 if (LinuxKernelLoadAddress
!= NULL
)
192 MmFreeMemory(LinuxKernelLoadAddress
);
194 if (LinuxInitrdLoadAddress
!= NULL
)
195 MmFreeMemory(LinuxInitrdLoadAddress
);
197 LinuxBootSector
= NULL
;
198 LinuxSetupSector
= NULL
;
199 LinuxKernelLoadAddress
= NULL
;
200 LinuxInitrdLoadAddress
= NULL
;
202 NewStyleLinuxKernel
= FALSE
;
204 LinuxHasInitrd
= FALSE
;
205 strcpy(LinuxCommandLine
, "");
206 LinuxCommandLineSize
= 0;
209 BOOLEAN
LinuxParseIniSection(PCSTR SectionName
)
213 /* Find all the message box settings and run them */
214 UiShowMessageBoxesInSection(SectionName
);
216 /* Try to open the operating system section in the .ini file */
217 if (!IniOpenSection(SectionName
, &SectionId
))
219 UiMessageBox("Section [%s] not found in freeldr.ini.", SectionName
);
223 if (!IniReadSettingByName(SectionId
, "BootPath", LinuxBootPath
, sizeof(LinuxBootPath
)))
225 UiMessageBox("Boot path not specified for selected OS!");
229 /* Get the kernel name */
230 if (!IniReadSettingByName(SectionId
, "Kernel", LinuxKernelName
, sizeof(LinuxKernelName
)))
232 UiMessageBox("Linux kernel filename not specified for selected OS!");
236 /* Get the initrd name */
237 if (IniReadSettingByName(SectionId
, "Initrd", LinuxInitrdName
, sizeof(LinuxInitrdName
)))
239 LinuxHasInitrd
= TRUE
;
242 /* Get the command line */
243 if (IniReadSettingByName(SectionId
, "CommandLine", LinuxCommandLine
, sizeof(LinuxCommandLine
)))
245 RemoveQuotes(LinuxCommandLine
);
246 LinuxCommandLineSize
= strlen(LinuxCommandLine
) + 1;
252 BOOLEAN
LinuxReadBootSector(PFILE LinuxKernelFile
)
254 /* Allocate memory for boot sector */
255 LinuxBootSector
= MmAllocateMemoryWithType(512, LoaderSystemCode
);
256 if (LinuxBootSector
== NULL
)
259 /* Read linux boot sector */
260 FsSetFilePointer(LinuxKernelFile
, 0);
261 if (!FsReadFile(LinuxKernelFile
, 512, NULL
, LinuxBootSector
))
264 /* Check for validity */
265 if (LinuxBootSector
->BootFlag
!= LINUX_BOOT_SECTOR_MAGIC
)
267 UiMessageBox("Invalid boot sector magic (0xaa55)");
271 // DbgDumpBuffer(DPRINT_LINUX, LinuxBootSector, 512);
273 TRACE("SetupSectors: %d\n", LinuxBootSector
->SetupSectors
);
274 TRACE("RootFlags: 0x%x\n", LinuxBootSector
->RootFlags
);
275 TRACE("SystemSize: 0x%x\n", LinuxBootSector
->SystemSize
);
276 TRACE("SwapDevice: 0x%x\n", LinuxBootSector
->SwapDevice
);
277 TRACE("RamSize: 0x%x\n", LinuxBootSector
->RamSize
);
278 TRACE("VideoMode: 0x%x\n", LinuxBootSector
->VideoMode
);
279 TRACE("RootDevice: 0x%x\n", LinuxBootSector
->RootDevice
);
280 TRACE("BootFlag: 0x%x\n", LinuxBootSector
->BootFlag
);
285 BOOLEAN
LinuxReadSetupSector(PFILE LinuxKernelFile
)
287 UCHAR TempLinuxSetupSector
[512];
289 LinuxSetupSector
= (PLINUX_SETUPSECTOR
)TempLinuxSetupSector
;
291 /* Read first linux setup sector */
292 FsSetFilePointer(LinuxKernelFile
, 512);
293 if (!FsReadFile(LinuxKernelFile
, 512, NULL
, TempLinuxSetupSector
))
296 /* Check the kernel version */
297 if (!LinuxCheckKernelVersion())
300 if (NewStyleLinuxKernel
)
301 SetupSectorSize
= 512 * LinuxBootSector
->SetupSectors
;
303 SetupSectorSize
= 512 * 4; // Always 4 setup sectors
305 /* Allocate memory for setup sectors */
306 LinuxSetupSector
= MmAllocateMemoryWithType(SetupSectorSize
, LoaderSystemCode
);
307 if (LinuxSetupSector
== NULL
)
310 /* Copy over first setup sector */
311 RtlCopyMemory(LinuxSetupSector
, TempLinuxSetupSector
, 512);
313 /* Read in the rest of the linux setup sectors */
314 FsSetFilePointer(LinuxKernelFile
, 1024);
315 if (!FsReadFile(LinuxKernelFile
, SetupSectorSize
- 512, NULL
, (PVOID
)((ULONG_PTR
)LinuxSetupSector
+ 512)))
318 // DbgDumpBuffer(DPRINT_LINUX, LinuxSetupSector, SetupSectorSize);
320 TRACE("SetupHeaderSignature: 0x%x (HdrS)\n", LinuxSetupSector
->SetupHeaderSignature
);
321 TRACE("Version: 0x%x\n", LinuxSetupSector
->Version
);
322 TRACE("RealModeSwitch: 0x%x\n", LinuxSetupSector
->RealModeSwitch
);
323 TRACE("SetupSeg: 0x%x\n", LinuxSetupSector
->SetupSeg
);
324 TRACE("StartSystemSeg: 0x%x\n", LinuxSetupSector
->StartSystemSeg
);
325 TRACE("KernelVersion: 0x%x\n", LinuxSetupSector
->KernelVersion
);
326 TRACE("TypeOfLoader: 0x%x\n", LinuxSetupSector
->TypeOfLoader
);
327 TRACE("LoadFlags: 0x%x\n", LinuxSetupSector
->LoadFlags
);
328 TRACE("SetupMoveSize: 0x%x\n", LinuxSetupSector
->SetupMoveSize
);
329 TRACE("Code32Start: 0x%x\n", LinuxSetupSector
->Code32Start
);
330 TRACE("RamdiskAddress: 0x%x\n", LinuxSetupSector
->RamdiskAddress
);
331 TRACE("RamdiskSize: 0x%x\n", LinuxSetupSector
->RamdiskSize
);
332 TRACE("BootSectKludgeOffset: 0x%x\n", LinuxSetupSector
->BootSectKludgeOffset
);
333 TRACE("BootSectKludgeSegment: 0x%x\n", LinuxSetupSector
->BootSectKludgeSegment
);
334 TRACE("HeapEnd: 0x%x\n", LinuxSetupSector
->HeapEnd
);
339 BOOLEAN
LinuxReadKernel(PFILE LinuxKernelFile
)
342 CHAR StatusText
[260];
345 sprintf(StatusText
, "Loading %s", LinuxKernelName
);
346 UiDrawStatusText(StatusText
);
348 /* Allocate memory for Linux kernel */
349 LinuxKernelLoadAddress
= MmAllocateMemoryAtAddress(LinuxKernelSize
, (PVOID
)LINUX_KERNEL_LOAD_ADDRESS
, LoaderSystemCode
);
350 if (LinuxKernelLoadAddress
!= (PVOID
)LINUX_KERNEL_LOAD_ADDRESS
)
355 LoadAddress
= LinuxKernelLoadAddress
;
357 /* Read linux kernel to 0x100000 (1mb) */
358 FsSetFilePointer(LinuxKernelFile
, 512 + SetupSectorSize
);
359 for (BytesLoaded
=0; BytesLoaded
<LinuxKernelSize
; )
361 if (!FsReadFile(LinuxKernelFile
, LINUX_READ_CHUNK_SIZE
, NULL
, LoadAddress
))
364 BytesLoaded
+= LINUX_READ_CHUNK_SIZE
;
365 LoadAddress
= (PVOID
)((ULONG_PTR
)LoadAddress
+ LINUX_READ_CHUNK_SIZE
);
367 UiDrawProgressBarCenter(BytesLoaded
, LinuxKernelSize
+ LinuxInitrdSize
, LinuxBootDescription
);
373 BOOLEAN
LinuxCheckKernelVersion(VOID
)
375 /* Just assume old kernel until we find otherwise */
376 NewStyleLinuxKernel
= FALSE
;
378 /* Check for new style setup header */
379 if (LinuxSetupSector
->SetupHeaderSignature
!= LINUX_SETUP_HEADER_ID
)
381 NewStyleLinuxKernel
= FALSE
;
383 /* Check for version below 2.0 */
384 else if (LinuxSetupSector
->Version
< 0x0200)
386 NewStyleLinuxKernel
= FALSE
;
388 /* Check for version 2.0 */
389 else if (LinuxSetupSector
->Version
== 0x0200)
391 NewStyleLinuxKernel
= TRUE
;
393 /* Check for version 2.01+ */
394 else if (LinuxSetupSector
->Version
>= 0x0201)
396 NewStyleLinuxKernel
= TRUE
;
397 LinuxSetupSector
->HeapEnd
= 0x9000;
398 LinuxSetupSector
->LoadFlags
|= LINUX_FLAG_CAN_USE_HEAP
;
401 if ((NewStyleLinuxKernel
== FALSE
) && (LinuxHasInitrd
))
403 UiMessageBox("Error: Cannot load a ramdisk (initrd) with an old kernel image.");
410 BOOLEAN
LinuxReadInitrd(PFILE LinuxInitrdFile
)
413 CHAR StatusText
[260];
415 sprintf(StatusText
, "Loading %s", LinuxInitrdName
);
416 UiDrawStatusText(StatusText
);
418 // Allocate memory for the ramdisk
419 //LinuxInitrdLoadAddress = MmAllocateMemory(LinuxInitrdSize);
420 // Try to align it at the next MB boundary after the kernel
421 //LinuxInitrdLoadAddress = MmAllocateMemoryAtAddress(LinuxInitrdSize, (PVOID)ROUND_UP((LINUX_KERNEL_LOAD_ADDRESS + LinuxKernelSize), 0x100000));
422 if (LinuxSetupSector
->Version
<= 0x0202)
424 LinuxInitrdLoadAddress
= MmAllocateHighestMemoryBelowAddress(LinuxInitrdSize
, (PVOID
)LINUX_MAX_INITRD_ADDRESS
, LoaderSystemCode
);
428 LinuxInitrdLoadAddress
= MmAllocateHighestMemoryBelowAddress(LinuxInitrdSize
, (PVOID
)LinuxSetupSector
->InitrdAddressMax
, LoaderSystemCode
);
430 if (LinuxInitrdLoadAddress
== NULL
)
435 /* Set the information in the setup struct */
436 LinuxSetupSector
->RamdiskAddress
= (ULONG
)LinuxInitrdLoadAddress
;
437 LinuxSetupSector
->RamdiskSize
= LinuxInitrdSize
;
439 TRACE("RamdiskAddress: 0x%x\n", LinuxSetupSector
->RamdiskAddress
);
440 TRACE("RamdiskSize: 0x%x\n", LinuxSetupSector
->RamdiskSize
);
442 if (LinuxSetupSector
->Version
>= 0x0203)
444 TRACE("InitrdAddressMax: 0x%x\n", LinuxSetupSector
->InitrdAddressMax
);
447 /* Read in the ramdisk */
448 for (BytesLoaded
=0; BytesLoaded
<LinuxInitrdSize
; )
450 if (!FsReadFile(LinuxInitrdFile
, LINUX_READ_CHUNK_SIZE
, NULL
, (PVOID
)LinuxInitrdLoadAddress
))
453 BytesLoaded
+= LINUX_READ_CHUNK_SIZE
;
454 LinuxInitrdLoadAddress
= (PVOID
)((ULONG_PTR
)LinuxInitrdLoadAddress
+ LINUX_READ_CHUNK_SIZE
);
456 UiDrawProgressBarCenter(BytesLoaded
+ LinuxKernelSize
, LinuxInitrdSize
+ LinuxKernelSize
, LinuxBootDescription
);