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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32 #include <oslist.h> // For RemoveQuotes()
38 #define LINUX_READ_CHUNK_SIZE 0x20000 // Read 128k at a time
41 PLINUX_BOOTSECTOR LinuxBootSector
= NULL
;
42 PLINUX_SETUPSECTOR LinuxSetupSector
= NULL
;
43 U32 SetupSectorSize
= 0;
44 BOOL NewStyleLinuxKernel
= FALSE
;
45 U32 LinuxKernelSize
= 0;
46 U32 LinuxInitrdSize
= 0;
47 UCHAR LinuxKernelName
[260];
48 UCHAR LinuxInitrdName
[260];
49 BOOL LinuxHasInitrd
= FALSE
;
50 UCHAR LinuxCommandLine
[260] = "";
51 U32 LinuxCommandLineSize
= 0;
52 PVOID LinuxKernelLoadAddress
= NULL
;
53 PVOID LinuxInitrdLoadAddress
= NULL
;
54 UCHAR LinuxBootDescription
[80];
56 VOID
LoadAndBootLinux(PUCHAR OperatingSystemName
, PUCHAR Description
)
58 PFILE LinuxKernel
= NULL
;
59 PFILE LinuxInitrdFile
= NULL
;
60 UCHAR TempString
[260];
66 sprintf(LinuxBootDescription
, "Loading %s...", Description
);
70 strcpy(LinuxBootDescription
, "Loading Linux...");
73 UiDrawStatusText(LinuxBootDescription
);
74 UiDrawProgressBarCenter(0, 100, LinuxBootDescription
);
76 // Parse the .ini file section
77 if (!LinuxParseIniSection(OperatingSystemName
))
82 // Open the boot volume
83 if (!FsOpenVolume(BootDrive
, BootPartition
))
85 UiMessageBox("Failed to open boot drive.");
90 LinuxKernel
= FsOpenFile(LinuxKernelName
);
91 if (LinuxKernel
== NULL
)
93 sprintf(TempString
, "Linux kernel \'%s\' not found.", LinuxKernelName
);
94 UiMessageBox(TempString
);
98 // Open the initrd file image (if necessary)
101 LinuxInitrdFile
= FsOpenFile(LinuxInitrdName
);
102 if (LinuxInitrdFile
== NULL
)
104 sprintf(TempString
, "Linux initrd image \'%s\' not found.", LinuxInitrdName
);
105 UiMessageBox(TempString
);
106 goto LinuxBootFailed
;
110 // Read the boot sector
111 if (!LinuxReadBootSector(LinuxKernel
))
113 goto LinuxBootFailed
;
116 // Read the setup sector
117 if (!LinuxReadSetupSector(LinuxKernel
))
119 goto LinuxBootFailed
;
123 LinuxKernelSize
= FsGetFileSize(LinuxKernel
) - (512 + SetupSectorSize
);
126 LinuxInitrdSize
= FsGetFileSize(LinuxInitrdFile
);
129 if (!LinuxReadKernel(LinuxKernel
))
131 goto LinuxBootFailed
;
134 // Read the initrd (if necessary)
137 if (!LinuxReadInitrd(LinuxInitrdFile
))
139 goto LinuxBootFailed
;
143 // If the default root device is set to FLOPPY (0000h), change to /dev/fd0 (0200h)
144 if (LinuxBootSector
->RootDevice
== 0x0000)
146 LinuxBootSector
->RootDevice
= 0x0200;
149 if (LinuxSetupSector
->Version
>= 0x0202)
151 LinuxSetupSector
->CommandLinePointer
= 0x99000;
155 LinuxBootSector
->CommandLineMagic
= LINUX_COMMAND_LINE_MAGIC
;
156 LinuxBootSector
->CommandLineOffset
= 0x9000;
159 if (NewStyleLinuxKernel
)
161 LinuxSetupSector
->TypeOfLoader
= LINUX_LOADER_TYPE_FREELOADER
;
165 LinuxSetupSector
->LoadFlags
= 0;
168 RtlCopyMemory((PVOID
)0x90000, LinuxBootSector
, 512);
169 RtlCopyMemory((PVOID
)0x90200, LinuxSetupSector
, SetupSectorSize
);
170 RtlCopyMemory((PVOID
)0x99000, LinuxCommandLine
, LinuxCommandLineSize
);
172 UiUnInitialize("Booting Linux...");
174 DiskStopFloppyMotor();
176 if (LinuxSetupSector
->LoadFlags
& LINUX_FLAG_LOAD_HIGH
)
178 BootNewLinuxKernel();
182 BootOldLinuxKernel(LinuxKernelSize
);
188 if (LinuxKernel
!= NULL
)
190 FsCloseFile(LinuxKernel
);
192 if (LinuxInitrdFile
!= NULL
)
194 FsCloseFile(LinuxInitrdFile
);
197 if (LinuxBootSector
!= NULL
)
199 MmFreeMemory(LinuxBootSector
);
201 if (LinuxSetupSector
!= NULL
)
203 MmFreeMemory(LinuxSetupSector
);
205 if (LinuxKernelLoadAddress
!= NULL
)
207 MmFreeMemory(LinuxKernelLoadAddress
);
209 if (LinuxInitrdLoadAddress
!= NULL
)
211 MmFreeMemory(LinuxInitrdLoadAddress
);
214 LinuxBootSector
= NULL
;
215 LinuxSetupSector
= NULL
;
216 LinuxKernelLoadAddress
= NULL
;
217 LinuxInitrdLoadAddress
= NULL
;
219 NewStyleLinuxKernel
= FALSE
;
221 LinuxHasInitrd
= FALSE
;
222 strcpy(LinuxCommandLine
, "");
223 LinuxCommandLineSize
= 0;
226 BOOL
LinuxParseIniSection(PUCHAR OperatingSystemName
)
228 UCHAR SettingName
[260];
229 UCHAR SettingValue
[260];
232 // Find all the message box settings and run them
233 UiShowMessageBoxesInSection(OperatingSystemName
);
235 // Try to open the operating system section in the .ini file
236 if (!IniOpenSection(OperatingSystemName
, &SectionId
))
238 sprintf(SettingName
, "Section [%s] not found in freeldr.ini.\n", OperatingSystemName
);
239 UiMessageBox(SettingName
);
243 if (!IniReadSettingByName(SectionId
, "BootDrive", SettingValue
, 260))
245 UiMessageBox("Boot drive not specified for selected OS!");
249 BootDrive
= DriveMapGetBiosDriveNumber(SettingValue
);
252 if (IniReadSettingByName(SectionId
, "BootPartition", SettingValue
, 260))
254 BootPartition
= atoi(SettingValue
);
257 // Get the kernel name
258 if (!IniReadSettingByName(SectionId
, "Kernel", LinuxKernelName
, 260))
260 UiMessageBox("Linux kernel filename not specified for selected OS!");
264 // Get the initrd name
265 if (IniReadSettingByName(SectionId
, "Initrd", LinuxInitrdName
, 260))
267 LinuxHasInitrd
= TRUE
;
270 // Get the command line
271 if (IniReadSettingByName(SectionId
, "CommandLine", LinuxCommandLine
, 260))
273 RemoveQuotes(LinuxCommandLine
);
274 LinuxCommandLineSize
= strlen(LinuxCommandLine
) + 1;
280 BOOL
LinuxReadBootSector(PFILE LinuxKernelFile
)
282 // Allocate memory for boot sector
283 LinuxBootSector
= (PLINUX_BOOTSECTOR
)MmAllocateMemory(512);
284 if (LinuxBootSector
== NULL
)
289 // Read linux boot sector
290 FsSetFilePointer(LinuxKernelFile
, 0);
291 if (!FsReadFile(LinuxKernelFile
, 512, NULL
, LinuxBootSector
))
296 // Check for validity
297 if (LinuxBootSector
->BootFlag
!= LINUX_BOOT_SECTOR_MAGIC
)
299 UiMessageBox("Invalid boot sector magic (0xaa55)");
303 DbgDumpBuffer(DPRINT_LINUX
, LinuxBootSector
, 512);
305 DbgPrint((DPRINT_LINUX
, "SetupSectors: %d\n", LinuxBootSector
->SetupSectors
));
306 DbgPrint((DPRINT_LINUX
, "RootFlags: 0x%x\n", LinuxBootSector
->RootFlags
));
307 DbgPrint((DPRINT_LINUX
, "SystemSize: 0x%x\n", LinuxBootSector
->SystemSize
));
308 DbgPrint((DPRINT_LINUX
, "SwapDevice: 0x%x\n", LinuxBootSector
->SwapDevice
));
309 DbgPrint((DPRINT_LINUX
, "RamSize: 0x%x\n", LinuxBootSector
->RamSize
));
310 DbgPrint((DPRINT_LINUX
, "VideoMode: 0x%x\n", LinuxBootSector
->VideoMode
));
311 DbgPrint((DPRINT_LINUX
, "RootDevice: 0x%x\n", LinuxBootSector
->RootDevice
));
312 DbgPrint((DPRINT_LINUX
, "BootFlag: 0x%x\n", LinuxBootSector
->BootFlag
));
317 BOOL
LinuxReadSetupSector(PFILE LinuxKernelFile
)
319 U8 TempLinuxSetupSector
[512];
321 LinuxSetupSector
= (PLINUX_SETUPSECTOR
)TempLinuxSetupSector
;
323 // Read first linux setup sector
324 FsSetFilePointer(LinuxKernelFile
, 512);
325 if (!FsReadFile(LinuxKernelFile
, 512, NULL
, TempLinuxSetupSector
))
330 // Check the kernel version
331 if (!LinuxCheckKernelVersion())
336 if (NewStyleLinuxKernel
)
338 SetupSectorSize
= 512 * LinuxBootSector
->SetupSectors
;
342 SetupSectorSize
= 4 * 512; // Always 4 setup sectors
345 // Allocate memory for setup sectors
346 LinuxSetupSector
= (PLINUX_SETUPSECTOR
)MmAllocateMemory(SetupSectorSize
);
347 if (LinuxSetupSector
== NULL
)
352 // Copy over first setup sector
353 RtlCopyMemory(LinuxSetupSector
, TempLinuxSetupSector
, 512);
355 // Read in the rest of the linux setup sectors
356 FsSetFilePointer(LinuxKernelFile
, 1024);
357 if (!FsReadFile(LinuxKernelFile
, SetupSectorSize
- 512, NULL
, ((PVOID
)LinuxSetupSector
) + 512))
362 DbgDumpBuffer(DPRINT_LINUX
, LinuxSetupSector
, SetupSectorSize
);
364 DbgPrint((DPRINT_LINUX
, "SetupHeaderSignature: 0x%x (HdrS)\n", LinuxSetupSector
->SetupHeaderSignature
));
365 DbgPrint((DPRINT_LINUX
, "Version: 0x%x\n", LinuxSetupSector
->Version
));
366 DbgPrint((DPRINT_LINUX
, "RealModeSwitch: 0x%x\n", LinuxSetupSector
->RealModeSwitch
));
367 DbgPrint((DPRINT_LINUX
, "SetupSeg: 0x%x\n", LinuxSetupSector
->SetupSeg
));
368 DbgPrint((DPRINT_LINUX
, "StartSystemSeg: 0x%x\n", LinuxSetupSector
->StartSystemSeg
));
369 DbgPrint((DPRINT_LINUX
, "KernelVersion: 0x%x\n", LinuxSetupSector
->KernelVersion
));
370 DbgPrint((DPRINT_LINUX
, "TypeOfLoader: 0x%x\n", LinuxSetupSector
->TypeOfLoader
));
371 DbgPrint((DPRINT_LINUX
, "LoadFlags: 0x%x\n", LinuxSetupSector
->LoadFlags
));
372 DbgPrint((DPRINT_LINUX
, "SetupMoveSize: 0x%x\n", LinuxSetupSector
->SetupMoveSize
));
373 DbgPrint((DPRINT_LINUX
, "Code32Start: 0x%x\n", LinuxSetupSector
->Code32Start
));
374 DbgPrint((DPRINT_LINUX
, "RamdiskAddress: 0x%x\n", LinuxSetupSector
->RamdiskAddress
));
375 DbgPrint((DPRINT_LINUX
, "RamdiskSize: 0x%x\n", LinuxSetupSector
->RamdiskSize
));
376 DbgPrint((DPRINT_LINUX
, "BootSectKludgeOffset: 0x%x\n", LinuxSetupSector
->BootSectKludgeOffset
));
377 DbgPrint((DPRINT_LINUX
, "BootSectKludgeSegment: 0x%x\n", LinuxSetupSector
->BootSectKludgeSegment
));
378 DbgPrint((DPRINT_LINUX
, "HeapEnd: 0x%x\n", LinuxSetupSector
->HeapEnd
));
383 BOOL
LinuxReadKernel(PFILE LinuxKernelFile
)
386 UCHAR StatusText
[260];
389 sprintf(StatusText
, "Loading %s", LinuxKernelName
);
390 UiDrawStatusText(StatusText
);
392 // Allocate memory for Linux kernel
393 LinuxKernelLoadAddress
= MmAllocateMemoryAtAddress(LinuxKernelSize
, (PVOID
)LINUX_KERNEL_LOAD_ADDRESS
);
394 if (LinuxKernelLoadAddress
!= (PVOID
)LINUX_KERNEL_LOAD_ADDRESS
)
399 LoadAddress
= LinuxKernelLoadAddress
;
401 // Read linux kernel to 0x100000 (1mb)
402 FsSetFilePointer(LinuxKernelFile
, 512 + SetupSectorSize
);
403 for (BytesLoaded
=0; BytesLoaded
<LinuxKernelSize
; )
405 if (!FsReadFile(LinuxKernelFile
, LINUX_READ_CHUNK_SIZE
, NULL
, LoadAddress
))
410 BytesLoaded
+= LINUX_READ_CHUNK_SIZE
;
411 LoadAddress
+= LINUX_READ_CHUNK_SIZE
;
413 UiDrawProgressBarCenter(BytesLoaded
, LinuxKernelSize
+ LinuxInitrdSize
, LinuxBootDescription
);
419 BOOL
LinuxCheckKernelVersion(VOID
)
421 // Just assume old kernel until we find otherwise
422 NewStyleLinuxKernel
= FALSE
;
424 // Check for new style setup header
425 if (LinuxSetupSector
->SetupHeaderSignature
!= LINUX_SETUP_HEADER_ID
)
427 NewStyleLinuxKernel
= FALSE
;
429 // Check for version below 2.0
430 else if (LinuxSetupSector
->Version
< 0x0200)
432 NewStyleLinuxKernel
= FALSE
;
434 // Check for version 2.0
435 else if (LinuxSetupSector
->Version
== 0x0200)
437 NewStyleLinuxKernel
= TRUE
;
439 // Check for version 2.01+
440 else if (LinuxSetupSector
->Version
>= 0x0201)
442 NewStyleLinuxKernel
= TRUE
;
443 LinuxSetupSector
->HeapEnd
= 0x9000;
444 LinuxSetupSector
->LoadFlags
|= LINUX_FLAG_CAN_USE_HEAP
;
447 if ((NewStyleLinuxKernel
== FALSE
) && (LinuxHasInitrd
== TRUE
))
449 UiMessageBox("Error: Cannot load a ramdisk (initrd) with an old kernel image.");
456 BOOL
LinuxReadInitrd(PFILE LinuxInitrdFile
)
459 UCHAR StatusText
[260];
461 sprintf(StatusText
, "Loading %s", LinuxInitrdName
);
462 UiDrawStatusText(StatusText
);
464 // Allocate memory for the ramdisk
465 //LinuxInitrdLoadAddress = MmAllocateMemory(LinuxInitrdSize);
466 // Try to align it at the next MB boundary after the kernel
467 //LinuxInitrdLoadAddress = MmAllocateMemoryAtAddress(LinuxInitrdSize, (PVOID)ROUND_UP((LINUX_KERNEL_LOAD_ADDRESS + LinuxKernelSize), 0x100000));
468 if (LinuxSetupSector
->Version
<= 0x0202)
470 LinuxInitrdLoadAddress
= MmAllocateHighestMemoryBelowAddress(LinuxInitrdSize
, (PVOID
)LINUX_MAX_INITRD_ADDRESS
);
474 LinuxInitrdLoadAddress
= MmAllocateHighestMemoryBelowAddress(LinuxInitrdSize
, (PVOID
)LinuxSetupSector
->InitrdAddressMax
);
476 if (LinuxInitrdLoadAddress
== NULL
)
481 // Set the information in the setup struct
482 LinuxSetupSector
->RamdiskAddress
= (U32
)LinuxInitrdLoadAddress
;
483 LinuxSetupSector
->RamdiskSize
= LinuxInitrdSize
;
485 DbgPrint((DPRINT_LINUX
, "RamdiskAddress: 0x%x\n", LinuxSetupSector
->RamdiskAddress
));
486 DbgPrint((DPRINT_LINUX
, "RamdiskSize: 0x%x\n", LinuxSetupSector
->RamdiskSize
));
488 if (LinuxSetupSector
->Version
>= 0x0203)
490 DbgPrint((DPRINT_LINUX
, "InitrdAddressMax: 0x%x\n", LinuxSetupSector
->InitrdAddressMax
));
493 // Read in the ramdisk
494 for (BytesLoaded
=0; BytesLoaded
<LinuxInitrdSize
; )
496 if (!FsReadFile(LinuxInitrdFile
, LINUX_READ_CHUNK_SIZE
, NULL
, (PVOID
)LinuxInitrdLoadAddress
))
501 BytesLoaded
+= LINUX_READ_CHUNK_SIZE
;
502 LinuxInitrdLoadAddress
+= LINUX_READ_CHUNK_SIZE
;
504 UiDrawProgressBarCenter(BytesLoaded
+ LinuxKernelSize
, LinuxInitrdSize
+ LinuxKernelSize
, LinuxBootDescription
);