3 * Copyright (C) 1998-2002 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.
31 #include <oslist.h> // For RemoveQuotes()
34 PLINUX_BOOTSECTOR LinuxBootSector
= NULL
;
35 PLINUX_SETUPSECTOR LinuxSetupSector
= NULL
;
36 U32 SetupSectorSize
= 0;
37 BOOL NewStyleLinuxKernel
= FALSE
;
38 U32 LinuxKernelSize
= 0;
39 UCHAR LinuxKernelName
[260];
40 UCHAR LinuxInitrdName
[260];
41 BOOL LinuxHasInitrd
= FALSE
;
42 UCHAR LinuxCommandLine
[260] = "";
43 U32 LinuxCommandLineSize
= 0;
44 PVOID LinuxKernelLoadAddress
= NULL
;
45 PVOID LinuxInitrdLoadAddress
= NULL
;
47 VOID
LoadAndBootLinux(PUCHAR OperatingSystemName
)
49 PFILE LinuxKernel
= NULL
;
50 UCHAR TempString
[260];
54 // Parse the .ini file section
55 if (!LinuxParseIniSection(OperatingSystemName
))
60 // Open the boot volume
61 if (!OpenDiskDrive(BootDrive
, BootPartition
))
63 UiMessageBox("Failed to open boot drive.");
68 LinuxKernel
= OpenFile(LinuxKernelName
);
69 if (LinuxKernel
== NULL
)
71 sprintf(TempString
, "Linux kernel \'%s\' not found.", LinuxKernelName
);
72 UiMessageBox(TempString
);
76 // Read the boot sector
77 if (!LinuxReadBootSector(LinuxKernel
))
82 // Read the setup sector
83 if (!LinuxReadSetupSector(LinuxKernel
))
89 if (!LinuxReadKernel(LinuxKernel
))
94 // Read the initrd (if necessary)
97 if (!LinuxReadInitrd())
103 // If the default root device is set to FLOPPY (0000h), change to /dev/fd0 (0200h)
104 if (LinuxBootSector
->RootDevice
== 0x0000)
106 LinuxBootSector
->RootDevice
= 0x0200;
109 LinuxBootSector
->CommandLineMagic
= LINUX_COMMAND_LINE_MAGIC
;
110 LinuxBootSector
->CommandLineOffset
= 0x9000;
112 if (NewStyleLinuxKernel
)
114 LinuxSetupSector
->TypeOfLoader
= LINUX_LOADER_TYPE_FREELOADER
;
118 LinuxSetupSector
->LoadFlags
= 0;
121 RtlCopyMemory((PVOID
)0x90000, LinuxBootSector
, 512);
122 RtlCopyMemory((PVOID
)0x90200, LinuxSetupSector
, SetupSectorSize
);
123 RtlCopyMemory((PVOID
)0x99000, LinuxCommandLine
, LinuxCommandLineSize
);
125 VideoShowTextCursor();
130 if (LinuxSetupSector
->LoadFlags
& LINUX_FLAG_LOAD_HIGH
)
132 BootNewLinuxKernel();
136 BootOldLinuxKernel(LinuxKernelSize
);
142 if (LinuxKernel
!= NULL
)
144 CloseFile(LinuxKernel
);
147 if (LinuxBootSector
!= NULL
)
149 MmFreeMemory(LinuxBootSector
);
151 if (LinuxSetupSector
!= NULL
)
153 MmFreeMemory(LinuxSetupSector
);
155 if (LinuxKernelLoadAddress
!= NULL
)
157 MmFreeMemory(LinuxKernelLoadAddress
);
159 if (LinuxInitrdLoadAddress
!= NULL
)
161 MmFreeMemory(LinuxInitrdLoadAddress
);
164 LinuxBootSector
= NULL
;
165 LinuxSetupSector
= NULL
;
166 LinuxKernelLoadAddress
= NULL
;
167 LinuxInitrdLoadAddress
= NULL
;
169 NewStyleLinuxKernel
= FALSE
;
171 LinuxHasInitrd
= FALSE
;
172 strcpy(LinuxCommandLine
, "");
173 LinuxCommandLineSize
= 0;
176 BOOL
LinuxParseIniSection(PUCHAR OperatingSystemName
)
178 UCHAR SettingName
[260];
179 UCHAR SettingValue
[260];
182 // Find all the message box settings and run them
183 UiShowMessageBoxesInSection(OperatingSystemName
);
185 // Try to open the operating system section in the .ini file
186 if (!IniOpenSection(OperatingSystemName
, &SectionId
))
188 sprintf(SettingName
, "Section [%s] not found in freeldr.ini.\n", OperatingSystemName
);
189 UiMessageBox(SettingName
);
193 if (!IniReadSettingByName(SectionId
, "BootDrive", SettingValue
, 260))
195 UiMessageBox("Boot drive not specified for selected OS!");
199 BootDrive
= atoi(SettingValue
);
202 if (IniReadSettingByName(SectionId
, "BootPartition", SettingValue
, 260))
204 BootPartition
= atoi(SettingValue
);
207 // Get the kernel name
208 if (!IniReadSettingByName(SectionId
, "Kernel", LinuxKernelName
, 260))
210 UiMessageBox("Linux kernel filename not specified for selected OS!");
214 // Get the initrd name
215 if (IniReadSettingByName(SectionId
, "Initrd", LinuxInitrdName
, 260))
217 LinuxHasInitrd
= TRUE
;
220 // Get the command line
221 if (IniReadSettingByName(SectionId
, "CommandLine", LinuxCommandLine
, 260))
223 RemoveQuotes(LinuxCommandLine
);
224 LinuxCommandLineSize
= strlen(LinuxCommandLine
) + 1;
230 BOOL
LinuxReadBootSector(PFILE LinuxKernelFile
)
232 // Allocate memory for boot sector
233 LinuxBootSector
= (PLINUX_BOOTSECTOR
)MmAllocateMemory(512);
234 if (LinuxBootSector
== NULL
)
239 // Read linux boot sector
240 SetFilePointer(LinuxKernelFile
, 0);
241 if (!ReadFile(LinuxKernelFile
, 512, NULL
, LinuxBootSector
))
246 // Check for validity
247 if (LinuxBootSector
->BootFlag
!= LINUX_BOOT_SECTOR_MAGIC
)
249 UiMessageBox("Invalid boot sector magic (0xaa55)");
253 DbgDumpBuffer(DPRINT_LINUX
, LinuxBootSector
, 512);
255 DbgPrint((DPRINT_LINUX
, "SetupSectors: %d\n", LinuxBootSector
->SetupSectors
));
256 DbgPrint((DPRINT_LINUX
, "RootFlags: 0x%x\n", LinuxBootSector
->RootFlags
));
257 DbgPrint((DPRINT_LINUX
, "SystemSize: 0x%x\n", LinuxBootSector
->SystemSize
));
258 DbgPrint((DPRINT_LINUX
, "SwapDevice: 0x%x\n", LinuxBootSector
->SwapDevice
));
259 DbgPrint((DPRINT_LINUX
, "RamSize: 0x%x\n", LinuxBootSector
->RamSize
));
260 DbgPrint((DPRINT_LINUX
, "VideoMode: 0x%x\n", LinuxBootSector
->VideoMode
));
261 DbgPrint((DPRINT_LINUX
, "RootDevice: 0x%x\n", LinuxBootSector
->RootDevice
));
262 DbgPrint((DPRINT_LINUX
, "BootFlag: 0x%x\n", LinuxBootSector
->BootFlag
));
267 BOOL
LinuxReadSetupSector(PFILE LinuxKernelFile
)
269 U8 TempLinuxSetupSector
[512];
271 LinuxSetupSector
= (PLINUX_SETUPSECTOR
)TempLinuxSetupSector
;
273 // Read first linux setup sector
274 SetFilePointer(LinuxKernelFile
, 512);
275 if (!ReadFile(LinuxKernelFile
, 512, NULL
, TempLinuxSetupSector
))
280 // Check the kernel version
281 if (!LinuxCheckKernelVersion())
286 if (NewStyleLinuxKernel
)
288 SetupSectorSize
= 512 * LinuxBootSector
->SetupSectors
;
292 SetupSectorSize
= 4 * 512; // Always 4 setup sectors
295 // Allocate memory for setup sectors
296 LinuxSetupSector
= (PLINUX_SETUPSECTOR
)MmAllocateMemory(SetupSectorSize
);
297 if (LinuxSetupSector
== NULL
)
302 // Copy over first setup sector
303 RtlCopyMemory(LinuxSetupSector
, TempLinuxSetupSector
, 512);
305 // Read in the rest of the linux setup sectors
306 SetFilePointer(LinuxKernelFile
, 1024);
307 if (!ReadFile(LinuxKernelFile
, SetupSectorSize
- 512, NULL
, ((PVOID
)LinuxSetupSector
) + 512))
312 DbgDumpBuffer(DPRINT_LINUX
, LinuxSetupSector
, SetupSectorSize
);
314 DbgPrint((DPRINT_LINUX
, "SetupHeaderSignature: 0x%x (HdrS)\n", LinuxSetupSector
->SetupHeaderSignature
));
315 DbgPrint((DPRINT_LINUX
, "Version: 0x%x\n", LinuxSetupSector
->Version
));
316 DbgPrint((DPRINT_LINUX
, "RealModeSwitch: 0x%x\n", LinuxSetupSector
->RealModeSwitch
));
317 DbgPrint((DPRINT_LINUX
, "SetupSeg: 0x%x\n", LinuxSetupSector
->SetupSeg
));
318 DbgPrint((DPRINT_LINUX
, "StartSystemSeg: 0x%x\n", LinuxSetupSector
->StartSystemSeg
));
319 DbgPrint((DPRINT_LINUX
, "KernelVersion: 0x%x\n", LinuxSetupSector
->KernelVersion
));
320 DbgPrint((DPRINT_LINUX
, "TypeOfLoader: 0x%x\n", LinuxSetupSector
->TypeOfLoader
));
321 DbgPrint((DPRINT_LINUX
, "LoadFlags: 0x%x\n", LinuxSetupSector
->LoadFlags
));
322 DbgPrint((DPRINT_LINUX
, "SetupMoveSize: 0x%x\n", LinuxSetupSector
->SetupMoveSize
));
323 DbgPrint((DPRINT_LINUX
, "Code32Start: 0x%x\n", LinuxSetupSector
->Code32Start
));
324 DbgPrint((DPRINT_LINUX
, "RamdiskAddress: 0x%x\n", LinuxSetupSector
->RamdiskAddress
));
325 DbgPrint((DPRINT_LINUX
, "RamdiskSize: 0x%x\n", LinuxSetupSector
->RamdiskSize
));
326 DbgPrint((DPRINT_LINUX
, "BootSectKludgeOffset: 0x%x\n", LinuxSetupSector
->BootSectKludgeOffset
));
327 DbgPrint((DPRINT_LINUX
, "BootSectKludgeSegment: 0x%x\n", LinuxSetupSector
->BootSectKludgeSegment
));
328 DbgPrint((DPRINT_LINUX
, "HeapEnd: 0x%x\n", LinuxSetupSector
->HeapEnd
));
333 BOOL
LinuxReadKernel(PFILE LinuxKernelFile
)
336 UCHAR StatusText
[260];
339 sprintf(StatusText
, "Loading %s", LinuxKernelName
);
340 UiDrawStatusText(StatusText
);
341 UiDrawProgressBarCenter(0, 100);
344 LinuxKernelSize
= GetFileSize(LinuxKernelFile
) - (512 + SetupSectorSize
);
346 // Allocate memory for Linux kernel
347 LinuxKernelLoadAddress
= MmAllocateMemoryAtAddress(LinuxKernelSize
, (PVOID
)LINUX_KERNEL_LOAD_ADDRESS
);
348 if (LinuxKernelLoadAddress
!= (PVOID
)LINUX_KERNEL_LOAD_ADDRESS
)
353 LoadAddress
= LinuxKernelLoadAddress
;
355 // Read linux kernel to 0x100000 (1mb)
356 SetFilePointer(LinuxKernelFile
, 512 + SetupSectorSize
);
357 for (BytesLoaded
=0; BytesLoaded
<LinuxKernelSize
; )
359 if (!ReadFile(LinuxKernelFile
, 0x4000, NULL
, LoadAddress
))
364 BytesLoaded
+= 0x4000;
365 LoadAddress
+= 0x4000;
367 UiDrawProgressBarCenter(BytesLoaded
, LinuxKernelSize
);
373 BOOL
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
== TRUE
))
403 UiMessageBox("Error: Cannot load a ramdisk (initrd) with an old kernel image.");
410 BOOL
LinuxReadInitrd(VOID
)
412 PFILE LinuxInitrdFile
;
413 UCHAR TempString
[260];
416 UCHAR StatusText
[260];
418 sprintf(StatusText
, "Loading %s", LinuxInitrdName
);
419 UiDrawStatusText(StatusText
);
420 UiDrawProgressBarCenter(0, 100);
422 // Open the initrd file image
423 LinuxInitrdFile
= OpenFile(LinuxInitrdName
);
424 if (LinuxInitrdFile
== NULL
)
426 sprintf(TempString
, "Linux initrd image \'%s\' not found.", LinuxInitrdName
);
427 UiMessageBox(TempString
);
432 LinuxInitrdSize
= GetFileSize(LinuxInitrdFile
);
434 // Allocate memory for the ramdisk
435 LinuxInitrdLoadAddress
= MmAllocateMemory(LinuxInitrdSize
);
436 if (LinuxInitrdLoadAddress
== NULL
)
441 // Set the information in the setup struct
442 LinuxSetupSector
->RamdiskAddress
= (U32
)LinuxInitrdLoadAddress
;
443 LinuxSetupSector
->RamdiskSize
= LinuxInitrdSize
;
445 // Read in the ramdisk
446 for (BytesLoaded
=0; BytesLoaded
<LinuxInitrdSize
; )
448 if (!ReadFile(LinuxInitrdFile
, 0x4000, NULL
, (PVOID
)LinuxInitrdLoadAddress
))
453 BytesLoaded
+= 0x4000;
454 LinuxInitrdLoadAddress
+= 0x4000;
456 UiDrawProgressBarCenter(BytesLoaded
, LinuxInitrdSize
);