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.
27 #define LINUX_READ_CHUNK_SIZE 0x20000 // Read 128k at a time
30 PLINUX_BOOTSECTOR LinuxBootSector
= NULL
;
31 PLINUX_SETUPSECTOR LinuxSetupSector
= NULL
;
32 ULONG SetupSectorSize
= 0;
33 BOOLEAN NewStyleLinuxKernel
= FALSE
;
34 ULONG LinuxKernelSize
= 0;
35 ULONG LinuxInitrdSize
= 0;
36 CHAR LinuxKernelName
[260];
37 CHAR LinuxInitrdName
[260];
38 BOOLEAN LinuxHasInitrd
= FALSE
;
39 CHAR LinuxCommandLine
[260] = "";
40 ULONG LinuxCommandLineSize
= 0;
41 PVOID LinuxKernelLoadAddress
= NULL
;
42 PVOID LinuxInitrdLoadAddress
= NULL
;
43 CHAR LinuxBootDescription
[80];
44 CHAR LinuxBootPath
[260] = "";
46 VOID
LoadAndBootLinux(PCSTR OperatingSystemName
, PCSTR Description
)
48 PFILE LinuxKernel
= NULL
;
49 PFILE LinuxInitrdFile
= NULL
;
56 sprintf(LinuxBootDescription
, "Loading %s...", Description
);
60 strcpy(LinuxBootDescription
, "Loading Linux...");
63 UiDrawStatusText(LinuxBootDescription
);
64 UiDrawProgressBarCenter(0, 100, LinuxBootDescription
);
66 // Parse the .ini file section
67 if (!LinuxParseIniSection(OperatingSystemName
))
72 // Open the boot volume
73 if (!MachDiskNormalizeSystemPath(LinuxBootPath
, sizeof(LinuxBootPath
)))
75 UiMessageBox("Invalid boot path");
78 if (!FsOpenSystemVolume(LinuxBootPath
, NULL
, NULL
))
80 UiMessageBox("Failed to open boot drive.");
85 LinuxKernel
= FsOpenFile(LinuxKernelName
);
86 if (LinuxKernel
== NULL
)
88 sprintf(TempString
, "Linux kernel \'%s\' not found.", LinuxKernelName
);
89 UiMessageBox(TempString
);
93 // Open the initrd file image (if necessary)
96 LinuxInitrdFile
= FsOpenFile(LinuxInitrdName
);
97 if (LinuxInitrdFile
== NULL
)
99 sprintf(TempString
, "Linux initrd image \'%s\' not found.", LinuxInitrdName
);
100 UiMessageBox(TempString
);
101 goto LinuxBootFailed
;
105 // Read the boot sector
106 if (!LinuxReadBootSector(LinuxKernel
))
108 goto LinuxBootFailed
;
111 // Read the setup sector
112 if (!LinuxReadSetupSector(LinuxKernel
))
114 goto LinuxBootFailed
;
118 LinuxKernelSize
= FsGetFileSize(LinuxKernel
) - (512 + SetupSectorSize
);
121 LinuxInitrdSize
= FsGetFileSize(LinuxInitrdFile
);
124 if (!LinuxReadKernel(LinuxKernel
))
126 goto LinuxBootFailed
;
129 // Read the initrd (if necessary)
132 if (!LinuxReadInitrd(LinuxInitrdFile
))
134 goto LinuxBootFailed
;
138 // If the default root device is set to FLOPPY (0000h), change to /dev/fd0 (0200h)
139 if (LinuxBootSector
->RootDevice
== 0x0000)
141 LinuxBootSector
->RootDevice
= 0x0200;
144 if (LinuxSetupSector
->Version
>= 0x0202)
146 LinuxSetupSector
->CommandLinePointer
= 0x99000;
150 LinuxBootSector
->CommandLineMagic
= LINUX_COMMAND_LINE_MAGIC
;
151 LinuxBootSector
->CommandLineOffset
= 0x9000;
154 if (NewStyleLinuxKernel
)
156 LinuxSetupSector
->TypeOfLoader
= LINUX_LOADER_TYPE_FREELOADER
;
160 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
)
173 BootNewLinuxKernel();
177 BootOldLinuxKernel(LinuxKernelSize
);
183 if (LinuxKernel
!= NULL
)
185 FsCloseFile(LinuxKernel
);
187 if (LinuxInitrdFile
!= NULL
)
189 FsCloseFile(LinuxInitrdFile
);
192 if (LinuxBootSector
!= NULL
)
194 MmFreeMemory(LinuxBootSector
);
196 if (LinuxSetupSector
!= NULL
)
198 MmFreeMemory(LinuxSetupSector
);
200 if (LinuxKernelLoadAddress
!= NULL
)
202 MmFreeMemory(LinuxKernelLoadAddress
);
204 if (LinuxInitrdLoadAddress
!= NULL
)
206 MmFreeMemory(LinuxInitrdLoadAddress
);
209 LinuxBootSector
= NULL
;
210 LinuxSetupSector
= NULL
;
211 LinuxKernelLoadAddress
= NULL
;
212 LinuxInitrdLoadAddress
= NULL
;
214 NewStyleLinuxKernel
= FALSE
;
216 LinuxHasInitrd
= FALSE
;
217 strcpy(LinuxCommandLine
, "");
218 LinuxCommandLineSize
= 0;
221 BOOLEAN
LinuxParseIniSection(PCSTR OperatingSystemName
)
223 CHAR SettingName
[260];
226 // Find all the message box settings and run them
227 UiShowMessageBoxesInSection(OperatingSystemName
);
229 // Try to open the operating system section in the .ini file
230 if (!IniOpenSection(OperatingSystemName
, &SectionId
))
232 sprintf(SettingName
, "Section [%s] not found in freeldr.ini.\n", OperatingSystemName
);
233 UiMessageBox(SettingName
);
237 if (!IniReadSettingByName(SectionId
, "BootPath", LinuxBootPath
, sizeof(LinuxBootPath
)))
239 UiMessageBox("Boot path not specified for selected OS!");
243 // Get the kernel name
244 if (!IniReadSettingByName(SectionId
, "Kernel", LinuxKernelName
, sizeof(LinuxKernelName
)))
246 UiMessageBox("Linux kernel filename not specified for selected OS!");
250 // Get the initrd name
251 if (IniReadSettingByName(SectionId
, "Initrd", LinuxInitrdName
, sizeof(LinuxInitrdName
)))
253 LinuxHasInitrd
= TRUE
;
256 // Get the command line
257 if (IniReadSettingByName(SectionId
, "CommandLine", LinuxCommandLine
, sizeof(LinuxCommandLine
)))
259 RemoveQuotes(LinuxCommandLine
);
260 LinuxCommandLineSize
= strlen(LinuxCommandLine
) + 1;
266 BOOLEAN
LinuxReadBootSector(PFILE LinuxKernelFile
)
268 // Allocate memory for boot sector
269 LinuxBootSector
= (PLINUX_BOOTSECTOR
)MmAllocateMemory(512);
270 if (LinuxBootSector
== NULL
)
275 // Read linux boot sector
276 FsSetFilePointer(LinuxKernelFile
, 0);
277 if (!FsReadFile(LinuxKernelFile
, 512, NULL
, LinuxBootSector
))
282 // Check for validity
283 if (LinuxBootSector
->BootFlag
!= LINUX_BOOT_SECTOR_MAGIC
)
285 UiMessageBox("Invalid boot sector magic (0xaa55)");
289 DbgDumpBuffer(DPRINT_LINUX
, LinuxBootSector
, 512);
291 DbgPrint((DPRINT_LINUX
, "SetupSectors: %d\n", LinuxBootSector
->SetupSectors
));
292 DbgPrint((DPRINT_LINUX
, "RootFlags: 0x%x\n", LinuxBootSector
->RootFlags
));
293 DbgPrint((DPRINT_LINUX
, "SystemSize: 0x%x\n", LinuxBootSector
->SystemSize
));
294 DbgPrint((DPRINT_LINUX
, "SwapDevice: 0x%x\n", LinuxBootSector
->SwapDevice
));
295 DbgPrint((DPRINT_LINUX
, "RamSize: 0x%x\n", LinuxBootSector
->RamSize
));
296 DbgPrint((DPRINT_LINUX
, "VideoMode: 0x%x\n", LinuxBootSector
->VideoMode
));
297 DbgPrint((DPRINT_LINUX
, "RootDevice: 0x%x\n", LinuxBootSector
->RootDevice
));
298 DbgPrint((DPRINT_LINUX
, "BootFlag: 0x%x\n", LinuxBootSector
->BootFlag
));
303 BOOLEAN
LinuxReadSetupSector(PFILE LinuxKernelFile
)
305 UCHAR TempLinuxSetupSector
[512];
307 LinuxSetupSector
= (PLINUX_SETUPSECTOR
)TempLinuxSetupSector
;
309 // Read first linux setup sector
310 FsSetFilePointer(LinuxKernelFile
, 512);
311 if (!FsReadFile(LinuxKernelFile
, 512, NULL
, TempLinuxSetupSector
))
316 // Check the kernel version
317 if (!LinuxCheckKernelVersion())
322 if (NewStyleLinuxKernel
)
324 SetupSectorSize
= 512 * LinuxBootSector
->SetupSectors
;
328 SetupSectorSize
= 4 * 512; // Always 4 setup sectors
331 // Allocate memory for setup sectors
332 LinuxSetupSector
= (PLINUX_SETUPSECTOR
)MmAllocateMemory(SetupSectorSize
);
333 if (LinuxSetupSector
== NULL
)
338 // Copy over first setup sector
339 RtlCopyMemory(LinuxSetupSector
, TempLinuxSetupSector
, 512);
341 // Read in the rest of the linux setup sectors
342 FsSetFilePointer(LinuxKernelFile
, 1024);
343 if (!FsReadFile(LinuxKernelFile
, SetupSectorSize
- 512, NULL
, (PVOID
)((ULONG_PTR
)LinuxSetupSector
+ 512)))
348 DbgDumpBuffer(DPRINT_LINUX
, LinuxSetupSector
, SetupSectorSize
);
350 DbgPrint((DPRINT_LINUX
, "SetupHeaderSignature: 0x%x (HdrS)\n", LinuxSetupSector
->SetupHeaderSignature
));
351 DbgPrint((DPRINT_LINUX
, "Version: 0x%x\n", LinuxSetupSector
->Version
));
352 DbgPrint((DPRINT_LINUX
, "RealModeSwitch: 0x%x\n", LinuxSetupSector
->RealModeSwitch
));
353 DbgPrint((DPRINT_LINUX
, "SetupSeg: 0x%x\n", LinuxSetupSector
->SetupSeg
));
354 DbgPrint((DPRINT_LINUX
, "StartSystemSeg: 0x%x\n", LinuxSetupSector
->StartSystemSeg
));
355 DbgPrint((DPRINT_LINUX
, "KernelVersion: 0x%x\n", LinuxSetupSector
->KernelVersion
));
356 DbgPrint((DPRINT_LINUX
, "TypeOfLoader: 0x%x\n", LinuxSetupSector
->TypeOfLoader
));
357 DbgPrint((DPRINT_LINUX
, "LoadFlags: 0x%x\n", LinuxSetupSector
->LoadFlags
));
358 DbgPrint((DPRINT_LINUX
, "SetupMoveSize: 0x%x\n", LinuxSetupSector
->SetupMoveSize
));
359 DbgPrint((DPRINT_LINUX
, "Code32Start: 0x%x\n", LinuxSetupSector
->Code32Start
));
360 DbgPrint((DPRINT_LINUX
, "RamdiskAddress: 0x%x\n", LinuxSetupSector
->RamdiskAddress
));
361 DbgPrint((DPRINT_LINUX
, "RamdiskSize: 0x%x\n", LinuxSetupSector
->RamdiskSize
));
362 DbgPrint((DPRINT_LINUX
, "BootSectKludgeOffset: 0x%x\n", LinuxSetupSector
->BootSectKludgeOffset
));
363 DbgPrint((DPRINT_LINUX
, "BootSectKludgeSegment: 0x%x\n", LinuxSetupSector
->BootSectKludgeSegment
));
364 DbgPrint((DPRINT_LINUX
, "HeapEnd: 0x%x\n", LinuxSetupSector
->HeapEnd
));
369 BOOLEAN
LinuxReadKernel(PFILE LinuxKernelFile
)
372 CHAR StatusText
[260];
375 sprintf(StatusText
, "Loading %s", LinuxKernelName
);
376 UiDrawStatusText(StatusText
);
378 // Allocate memory for Linux kernel
379 LinuxKernelLoadAddress
= MmAllocateMemoryAtAddress(LinuxKernelSize
, (PVOID
)LINUX_KERNEL_LOAD_ADDRESS
);
380 if (LinuxKernelLoadAddress
!= (PVOID
)LINUX_KERNEL_LOAD_ADDRESS
)
385 LoadAddress
= LinuxKernelLoadAddress
;
387 // Read linux kernel to 0x100000 (1mb)
388 FsSetFilePointer(LinuxKernelFile
, 512 + SetupSectorSize
);
389 for (BytesLoaded
=0; BytesLoaded
<LinuxKernelSize
; )
391 if (!FsReadFile(LinuxKernelFile
, LINUX_READ_CHUNK_SIZE
, NULL
, LoadAddress
))
396 BytesLoaded
+= LINUX_READ_CHUNK_SIZE
;
397 LoadAddress
= (PVOID
)((ULONG_PTR
)LoadAddress
+ LINUX_READ_CHUNK_SIZE
);
399 UiDrawProgressBarCenter(BytesLoaded
, LinuxKernelSize
+ LinuxInitrdSize
, LinuxBootDescription
);
405 BOOLEAN
LinuxCheckKernelVersion(VOID
)
407 // Just assume old kernel until we find otherwise
408 NewStyleLinuxKernel
= FALSE
;
410 // Check for new style setup header
411 if (LinuxSetupSector
->SetupHeaderSignature
!= LINUX_SETUP_HEADER_ID
)
413 NewStyleLinuxKernel
= FALSE
;
415 // Check for version below 2.0
416 else if (LinuxSetupSector
->Version
< 0x0200)
418 NewStyleLinuxKernel
= FALSE
;
420 // Check for version 2.0
421 else if (LinuxSetupSector
->Version
== 0x0200)
423 NewStyleLinuxKernel
= TRUE
;
425 // Check for version 2.01+
426 else if (LinuxSetupSector
->Version
>= 0x0201)
428 NewStyleLinuxKernel
= TRUE
;
429 LinuxSetupSector
->HeapEnd
= 0x9000;
430 LinuxSetupSector
->LoadFlags
|= LINUX_FLAG_CAN_USE_HEAP
;
433 if ((NewStyleLinuxKernel
== FALSE
) && (LinuxHasInitrd
== TRUE
))
435 UiMessageBox("Error: Cannot load a ramdisk (initrd) with an old kernel image.");
442 BOOLEAN
LinuxReadInitrd(PFILE LinuxInitrdFile
)
445 CHAR StatusText
[260];
447 sprintf(StatusText
, "Loading %s", LinuxInitrdName
);
448 UiDrawStatusText(StatusText
);
450 // Allocate memory for the ramdisk
451 //LinuxInitrdLoadAddress = MmAllocateMemory(LinuxInitrdSize);
452 // Try to align it at the next MB boundary after the kernel
453 //LinuxInitrdLoadAddress = MmAllocateMemoryAtAddress(LinuxInitrdSize, (PVOID)ROUND_UP((LINUX_KERNEL_LOAD_ADDRESS + LinuxKernelSize), 0x100000));
454 if (LinuxSetupSector
->Version
<= 0x0202)
456 LinuxInitrdLoadAddress
= MmAllocateHighestMemoryBelowAddress(LinuxInitrdSize
, (PVOID
)LINUX_MAX_INITRD_ADDRESS
);
460 LinuxInitrdLoadAddress
= MmAllocateHighestMemoryBelowAddress(LinuxInitrdSize
, (PVOID
)LinuxSetupSector
->InitrdAddressMax
);
462 if (LinuxInitrdLoadAddress
== NULL
)
467 // Set the information in the setup struct
468 LinuxSetupSector
->RamdiskAddress
= (ULONG
)LinuxInitrdLoadAddress
;
469 LinuxSetupSector
->RamdiskSize
= LinuxInitrdSize
;
471 DbgPrint((DPRINT_LINUX
, "RamdiskAddress: 0x%x\n", LinuxSetupSector
->RamdiskAddress
));
472 DbgPrint((DPRINT_LINUX
, "RamdiskSize: 0x%x\n", LinuxSetupSector
->RamdiskSize
));
474 if (LinuxSetupSector
->Version
>= 0x0203)
476 DbgPrint((DPRINT_LINUX
, "InitrdAddressMax: 0x%x\n", LinuxSetupSector
->InitrdAddressMax
));
479 // Read in the ramdisk
480 for (BytesLoaded
=0; BytesLoaded
<LinuxInitrdSize
; )
482 if (!FsReadFile(LinuxInitrdFile
, LINUX_READ_CHUNK_SIZE
, NULL
, (PVOID
)LinuxInitrdLoadAddress
))
487 BytesLoaded
+= LINUX_READ_CHUNK_SIZE
;
488 LinuxInitrdLoadAddress
= (PVOID
)((ULONG_PTR
)LinuxInitrdLoadAddress
+ LINUX_READ_CHUNK_SIZE
);
490 UiDrawProgressBarCenter(BytesLoaded
+ LinuxKernelSize
, LinuxInitrdSize
+ LinuxKernelSize
, LinuxBootDescription
);
495 #endif /* __i386__ */