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.
25 #define LINUX_READ_CHUNK_SIZE 0x20000 // Read 128k at a time
28 PLINUX_BOOTSECTOR LinuxBootSector
= NULL
;
29 PLINUX_SETUPSECTOR LinuxSetupSector
= NULL
;
30 ULONG SetupSectorSize
= 0;
31 BOOLEAN NewStyleLinuxKernel
= FALSE
;
32 ULONG LinuxKernelSize
= 0;
33 ULONG LinuxInitrdSize
= 0;
34 CHAR LinuxKernelName
[260];
35 CHAR LinuxInitrdName
[260];
36 BOOLEAN LinuxHasInitrd
= FALSE
;
37 CHAR LinuxCommandLine
[260] = "";
38 ULONG LinuxCommandLineSize
= 0;
39 PVOID LinuxKernelLoadAddress
= NULL
;
40 PVOID LinuxInitrdLoadAddress
= NULL
;
41 CHAR LinuxBootDescription
[80];
42 CHAR LinuxBootPath
[260] = "";
44 BOOLEAN
RemoveQuotes(PCHAR QuotedString
)
51 // Skip spaces up to "
54 while (*p
== ' ' || *p
== '"')
61 while (*p
!= '"' && *p
!= ANSI_NULL
)
68 strcpy(TempString
, Start
);
69 strcpy(QuotedString
, TempString
);
74 VOID
LoadAndBootLinux(PCSTR OperatingSystemName
, PCSTR Description
)
76 PFILE LinuxKernel
= 0;
77 PFILE LinuxInitrdFile
= 0;
84 sprintf(LinuxBootDescription
, "Loading %s...", Description
);
88 strcpy(LinuxBootDescription
, "Loading Linux...");
91 UiDrawStatusText(LinuxBootDescription
);
92 UiDrawProgressBarCenter(0, 100, LinuxBootDescription
);
94 // Parse the .ini file section
95 if (!LinuxParseIniSection(OperatingSystemName
))
100 // Open the boot volume
101 if (!MachDiskNormalizeSystemPath(LinuxBootPath
, sizeof(LinuxBootPath
)))
103 UiMessageBox("Invalid boot path");
104 goto LinuxBootFailed
;
108 LinuxKernel
= FsOpenFile(LinuxKernelName
);
111 sprintf(TempString
, "Linux kernel \'%s\' not found.", LinuxKernelName
);
112 UiMessageBox(TempString
);
113 goto LinuxBootFailed
;
116 // Open the initrd file image (if necessary)
119 LinuxInitrdFile
= FsOpenFile(LinuxInitrdName
);
120 if (!LinuxInitrdFile
)
122 sprintf(TempString
, "Linux initrd image \'%s\' not found.", LinuxInitrdName
);
123 UiMessageBox(TempString
);
124 goto LinuxBootFailed
;
128 // Read the boot sector
129 if (!LinuxReadBootSector(LinuxKernel
))
131 goto LinuxBootFailed
;
134 // Read the setup sector
135 if (!LinuxReadSetupSector(LinuxKernel
))
137 goto LinuxBootFailed
;
141 LinuxKernelSize
= FsGetFileSize(LinuxKernel
) - (512 + SetupSectorSize
);
144 LinuxInitrdSize
= FsGetFileSize(LinuxInitrdFile
);
147 if (!LinuxReadKernel(LinuxKernel
))
149 goto LinuxBootFailed
;
152 // Read the initrd (if necessary)
155 if (!LinuxReadInitrd(LinuxInitrdFile
))
157 goto LinuxBootFailed
;
161 // If the default root device is set to FLOPPY (0000h), change to /dev/fd0 (0200h)
162 if (LinuxBootSector
->RootDevice
== 0x0000)
164 LinuxBootSector
->RootDevice
= 0x0200;
167 if (LinuxSetupSector
->Version
>= 0x0202)
169 LinuxSetupSector
->CommandLinePointer
= 0x99000;
173 LinuxBootSector
->CommandLineMagic
= LINUX_COMMAND_LINE_MAGIC
;
174 LinuxBootSector
->CommandLineOffset
= 0x9000;
177 if (NewStyleLinuxKernel
)
179 LinuxSetupSector
->TypeOfLoader
= LINUX_LOADER_TYPE_FREELOADER
;
183 LinuxSetupSector
->LoadFlags
= 0;
186 RtlCopyMemory((PVOID
)0x90000, LinuxBootSector
, 512);
187 RtlCopyMemory((PVOID
)0x90200, LinuxSetupSector
, SetupSectorSize
);
188 RtlCopyMemory((PVOID
)0x99000, LinuxCommandLine
, LinuxCommandLineSize
);
190 UiUnInitialize("Booting Linux...");
192 DiskStopFloppyMotor();
194 if (LinuxSetupSector
->LoadFlags
& LINUX_FLAG_LOAD_HIGH
)
196 BootNewLinuxKernel();
200 BootOldLinuxKernel(LinuxKernelSize
);
208 FsCloseFile(LinuxKernel
);
212 FsCloseFile(LinuxInitrdFile
);
215 if (LinuxBootSector
!= NULL
)
217 MmFreeMemory(LinuxBootSector
);
219 if (LinuxSetupSector
!= NULL
)
221 MmFreeMemory(LinuxSetupSector
);
223 if (LinuxKernelLoadAddress
!= NULL
)
225 MmFreeMemory(LinuxKernelLoadAddress
);
227 if (LinuxInitrdLoadAddress
!= NULL
)
229 MmFreeMemory(LinuxInitrdLoadAddress
);
232 LinuxBootSector
= NULL
;
233 LinuxSetupSector
= NULL
;
234 LinuxKernelLoadAddress
= NULL
;
235 LinuxInitrdLoadAddress
= NULL
;
237 NewStyleLinuxKernel
= FALSE
;
239 LinuxHasInitrd
= FALSE
;
240 strcpy(LinuxCommandLine
, "");
241 LinuxCommandLineSize
= 0;
244 BOOLEAN
LinuxParseIniSection(PCSTR OperatingSystemName
)
246 CHAR SettingName
[260];
249 // Find all the message box settings and run them
250 UiShowMessageBoxesInSection(OperatingSystemName
);
252 // Try to open the operating system section in the .ini file
253 if (!IniOpenSection(OperatingSystemName
, &SectionId
))
255 sprintf(SettingName
, "Section [%s] not found in freeldr.ini.\n", OperatingSystemName
);
256 UiMessageBox(SettingName
);
260 if (!IniReadSettingByName(SectionId
, "BootPath", LinuxBootPath
, sizeof(LinuxBootPath
)))
262 UiMessageBox("Boot path not specified for selected OS!");
266 // Get the kernel name
267 if (!IniReadSettingByName(SectionId
, "Kernel", LinuxKernelName
, sizeof(LinuxKernelName
)))
269 UiMessageBox("Linux kernel filename not specified for selected OS!");
273 // Get the initrd name
274 if (IniReadSettingByName(SectionId
, "Initrd", LinuxInitrdName
, sizeof(LinuxInitrdName
)))
276 LinuxHasInitrd
= TRUE
;
279 // Get the command line
280 if (IniReadSettingByName(SectionId
, "CommandLine", LinuxCommandLine
, sizeof(LinuxCommandLine
)))
282 RemoveQuotes(LinuxCommandLine
);
283 LinuxCommandLineSize
= strlen(LinuxCommandLine
) + 1;
289 BOOLEAN
LinuxReadBootSector(PFILE LinuxKernelFile
)
291 // Allocate memory for boot sector
292 LinuxBootSector
= (PLINUX_BOOTSECTOR
)MmAllocateMemory(512);
293 if (LinuxBootSector
== NULL
)
298 // Read linux boot sector
299 FsSetFilePointer(LinuxKernelFile
, 0);
300 if (!FsReadFile(LinuxKernelFile
, 512, NULL
, LinuxBootSector
))
305 // Check for validity
306 if (LinuxBootSector
->BootFlag
!= LINUX_BOOT_SECTOR_MAGIC
)
308 UiMessageBox("Invalid boot sector magic (0xaa55)");
312 DbgDumpBuffer(DPRINT_LINUX
, LinuxBootSector
, 512);
314 DPRINTM(DPRINT_LINUX
, "SetupSectors: %d\n", LinuxBootSector
->SetupSectors
);
315 DPRINTM(DPRINT_LINUX
, "RootFlags: 0x%x\n", LinuxBootSector
->RootFlags
);
316 DPRINTM(DPRINT_LINUX
, "SystemSize: 0x%x\n", LinuxBootSector
->SystemSize
);
317 DPRINTM(DPRINT_LINUX
, "SwapDevice: 0x%x\n", LinuxBootSector
->SwapDevice
);
318 DPRINTM(DPRINT_LINUX
, "RamSize: 0x%x\n", LinuxBootSector
->RamSize
);
319 DPRINTM(DPRINT_LINUX
, "VideoMode: 0x%x\n", LinuxBootSector
->VideoMode
);
320 DPRINTM(DPRINT_LINUX
, "RootDevice: 0x%x\n", LinuxBootSector
->RootDevice
);
321 DPRINTM(DPRINT_LINUX
, "BootFlag: 0x%x\n", LinuxBootSector
->BootFlag
);
326 BOOLEAN
LinuxReadSetupSector(PFILE LinuxKernelFile
)
328 UCHAR TempLinuxSetupSector
[512];
330 LinuxSetupSector
= (PLINUX_SETUPSECTOR
)TempLinuxSetupSector
;
332 // Read first linux setup sector
333 FsSetFilePointer(LinuxKernelFile
, 512);
334 if (!FsReadFile(LinuxKernelFile
, 512, NULL
, TempLinuxSetupSector
))
339 // Check the kernel version
340 if (!LinuxCheckKernelVersion())
345 if (NewStyleLinuxKernel
)
347 SetupSectorSize
= 512 * LinuxBootSector
->SetupSectors
;
351 SetupSectorSize
= 4 * 512; // Always 4 setup sectors
354 // Allocate memory for setup sectors
355 LinuxSetupSector
= (PLINUX_SETUPSECTOR
)MmAllocateMemory(SetupSectorSize
);
356 if (LinuxSetupSector
== NULL
)
361 // Copy over first setup sector
362 RtlCopyMemory(LinuxSetupSector
, TempLinuxSetupSector
, 512);
364 // Read in the rest of the linux setup sectors
365 FsSetFilePointer(LinuxKernelFile
, 1024);
366 if (!FsReadFile(LinuxKernelFile
, SetupSectorSize
- 512, NULL
, (PVOID
)((ULONG_PTR
)LinuxSetupSector
+ 512)))
371 DbgDumpBuffer(DPRINT_LINUX
, LinuxSetupSector
, SetupSectorSize
);
373 DPRINTM(DPRINT_LINUX
, "SetupHeaderSignature: 0x%x (HdrS)\n", LinuxSetupSector
->SetupHeaderSignature
);
374 DPRINTM(DPRINT_LINUX
, "Version: 0x%x\n", LinuxSetupSector
->Version
);
375 DPRINTM(DPRINT_LINUX
, "RealModeSwitch: 0x%x\n", LinuxSetupSector
->RealModeSwitch
);
376 DPRINTM(DPRINT_LINUX
, "SetupSeg: 0x%x\n", LinuxSetupSector
->SetupSeg
);
377 DPRINTM(DPRINT_LINUX
, "StartSystemSeg: 0x%x\n", LinuxSetupSector
->StartSystemSeg
);
378 DPRINTM(DPRINT_LINUX
, "KernelVersion: 0x%x\n", LinuxSetupSector
->KernelVersion
);
379 DPRINTM(DPRINT_LINUX
, "TypeOfLoader: 0x%x\n", LinuxSetupSector
->TypeOfLoader
);
380 DPRINTM(DPRINT_LINUX
, "LoadFlags: 0x%x\n", LinuxSetupSector
->LoadFlags
);
381 DPRINTM(DPRINT_LINUX
, "SetupMoveSize: 0x%x\n", LinuxSetupSector
->SetupMoveSize
);
382 DPRINTM(DPRINT_LINUX
, "Code32Start: 0x%x\n", LinuxSetupSector
->Code32Start
);
383 DPRINTM(DPRINT_LINUX
, "RamdiskAddress: 0x%x\n", LinuxSetupSector
->RamdiskAddress
);
384 DPRINTM(DPRINT_LINUX
, "RamdiskSize: 0x%x\n", LinuxSetupSector
->RamdiskSize
);
385 DPRINTM(DPRINT_LINUX
, "BootSectKludgeOffset: 0x%x\n", LinuxSetupSector
->BootSectKludgeOffset
);
386 DPRINTM(DPRINT_LINUX
, "BootSectKludgeSegment: 0x%x\n", LinuxSetupSector
->BootSectKludgeSegment
);
387 DPRINTM(DPRINT_LINUX
, "HeapEnd: 0x%x\n", LinuxSetupSector
->HeapEnd
);
392 BOOLEAN
LinuxReadKernel(PFILE LinuxKernelFile
)
395 CHAR StatusText
[260];
398 sprintf(StatusText
, "Loading %s", LinuxKernelName
);
399 UiDrawStatusText(StatusText
);
401 // Allocate memory for Linux kernel
402 LinuxKernelLoadAddress
= MmAllocateMemoryAtAddress(LinuxKernelSize
, (PVOID
)LINUX_KERNEL_LOAD_ADDRESS
, LoaderSystemCode
);
403 if (LinuxKernelLoadAddress
!= (PVOID
)LINUX_KERNEL_LOAD_ADDRESS
)
408 LoadAddress
= LinuxKernelLoadAddress
;
410 // Read linux kernel to 0x100000 (1mb)
411 FsSetFilePointer(LinuxKernelFile
, 512 + SetupSectorSize
);
412 for (BytesLoaded
=0; BytesLoaded
<LinuxKernelSize
; )
414 if (!FsReadFile(LinuxKernelFile
, LINUX_READ_CHUNK_SIZE
, NULL
, LoadAddress
))
419 BytesLoaded
+= LINUX_READ_CHUNK_SIZE
;
420 LoadAddress
= (PVOID
)((ULONG_PTR
)LoadAddress
+ LINUX_READ_CHUNK_SIZE
);
422 UiDrawProgressBarCenter(BytesLoaded
, LinuxKernelSize
+ LinuxInitrdSize
, LinuxBootDescription
);
428 BOOLEAN
LinuxCheckKernelVersion(VOID
)
430 // Just assume old kernel until we find otherwise
431 NewStyleLinuxKernel
= FALSE
;
433 // Check for new style setup header
434 if (LinuxSetupSector
->SetupHeaderSignature
!= LINUX_SETUP_HEADER_ID
)
436 NewStyleLinuxKernel
= FALSE
;
438 // Check for version below 2.0
439 else if (LinuxSetupSector
->Version
< 0x0200)
441 NewStyleLinuxKernel
= FALSE
;
443 // Check for version 2.0
444 else if (LinuxSetupSector
->Version
== 0x0200)
446 NewStyleLinuxKernel
= TRUE
;
448 // Check for version 2.01+
449 else if (LinuxSetupSector
->Version
>= 0x0201)
451 NewStyleLinuxKernel
= TRUE
;
452 LinuxSetupSector
->HeapEnd
= 0x9000;
453 LinuxSetupSector
->LoadFlags
|= LINUX_FLAG_CAN_USE_HEAP
;
456 if ((NewStyleLinuxKernel
== FALSE
) && (LinuxHasInitrd
== TRUE
))
458 UiMessageBox("Error: Cannot load a ramdisk (initrd) with an old kernel image.");
465 BOOLEAN
LinuxReadInitrd(PFILE LinuxInitrdFile
)
468 CHAR StatusText
[260];
470 sprintf(StatusText
, "Loading %s", LinuxInitrdName
);
471 UiDrawStatusText(StatusText
);
473 // Allocate memory for the ramdisk
474 //LinuxInitrdLoadAddress = MmAllocateMemory(LinuxInitrdSize);
475 // Try to align it at the next MB boundary after the kernel
476 //LinuxInitrdLoadAddress = MmAllocateMemoryAtAddress(LinuxInitrdSize, (PVOID)ROUND_UP((LINUX_KERNEL_LOAD_ADDRESS + LinuxKernelSize), 0x100000));
477 if (LinuxSetupSector
->Version
<= 0x0202)
479 LinuxInitrdLoadAddress
= MmAllocateHighestMemoryBelowAddress(LinuxInitrdSize
, (PVOID
)LINUX_MAX_INITRD_ADDRESS
, LoaderSystemCode
);
483 LinuxInitrdLoadAddress
= MmAllocateHighestMemoryBelowAddress(LinuxInitrdSize
, (PVOID
)LinuxSetupSector
->InitrdAddressMax
, LoaderSystemCode
);
485 if (LinuxInitrdLoadAddress
== NULL
)
490 // Set the information in the setup struct
491 LinuxSetupSector
->RamdiskAddress
= (ULONG
)LinuxInitrdLoadAddress
;
492 LinuxSetupSector
->RamdiskSize
= LinuxInitrdSize
;
494 DPRINTM(DPRINT_LINUX
, "RamdiskAddress: 0x%x\n", LinuxSetupSector
->RamdiskAddress
);
495 DPRINTM(DPRINT_LINUX
, "RamdiskSize: 0x%x\n", LinuxSetupSector
->RamdiskSize
);
497 if (LinuxSetupSector
->Version
>= 0x0203)
499 DPRINTM(DPRINT_LINUX
, "InitrdAddressMax: 0x%x\n", LinuxSetupSector
->InitrdAddressMax
);
502 // Read in the ramdisk
503 for (BytesLoaded
=0; BytesLoaded
<LinuxInitrdSize
; )
505 if (!FsReadFile(LinuxInitrdFile
, LINUX_READ_CHUNK_SIZE
, NULL
, (PVOID
)LinuxInitrdLoadAddress
))
510 BytesLoaded
+= LINUX_READ_CHUNK_SIZE
;
511 LinuxInitrdLoadAddress
= (PVOID
)((ULONG_PTR
)LinuxInitrdLoadAddress
+ LINUX_READ_CHUNK_SIZE
);
513 UiDrawProgressBarCenter(BytesLoaded
+ LinuxKernelSize
, LinuxInitrdSize
+ LinuxKernelSize
, LinuxBootDescription
);
518 #endif /* __i386__ */