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
27 DBG_DEFAULT_CHANNEL(LINUX
);
29 PLINUX_BOOTSECTOR LinuxBootSector
= NULL
;
30 PLINUX_SETUPSECTOR LinuxSetupSector
= NULL
;
31 ULONG SetupSectorSize
= 0;
32 BOOLEAN NewStyleLinuxKernel
= FALSE
;
33 ULONG LinuxKernelSize
= 0;
34 ULONG LinuxInitrdSize
= 0;
35 CHAR LinuxKernelName
[260];
36 CHAR LinuxInitrdName
[260];
37 BOOLEAN LinuxHasInitrd
= FALSE
;
38 CHAR LinuxCommandLine
[260] = "";
39 ULONG LinuxCommandLineSize
= 0;
40 PVOID LinuxKernelLoadAddress
= NULL
;
41 PVOID LinuxInitrdLoadAddress
= NULL
;
42 CHAR LinuxBootDescription
[80];
43 CHAR LinuxBootPath
[260] = "";
45 BOOLEAN
RemoveQuotes(PCHAR QuotedString
)
52 // Skip spaces up to "
55 while (*p
== ' ' || *p
== '"')
62 while (*p
!= '"' && *p
!= ANSI_NULL
)
69 strcpy(TempString
, Start
);
70 strcpy(QuotedString
, TempString
);
76 LoadAndBootLinux(IN OperatingSystemItem
* OperatingSystem
,
77 IN USHORT OperatingSystemVersion
)
79 PCSTR SectionName
= OperatingSystem
->SystemPartition
;
80 PCSTR Description
= OperatingSystem
->LoadIdentifier
;
81 PFILE LinuxKernel
= 0;
82 PFILE LinuxInitrdFile
= 0;
89 sprintf(LinuxBootDescription
, "Loading %s...", Description
);
93 strcpy(LinuxBootDescription
, "Loading Linux...");
96 UiDrawStatusText(LinuxBootDescription
);
97 UiDrawProgressBarCenter(0, 100, LinuxBootDescription
);
99 // Parse the .ini file section
100 if (!LinuxParseIniSection(SectionName
))
102 goto LinuxBootFailed
;
106 LinuxKernel
= FsOpenFile(LinuxKernelName
);
109 sprintf(TempString
, "Linux kernel \'%s\' not found.", LinuxKernelName
);
110 UiMessageBox(TempString
);
111 goto LinuxBootFailed
;
114 // Open the initrd file image (if necessary)
117 LinuxInitrdFile
= FsOpenFile(LinuxInitrdName
);
118 if (!LinuxInitrdFile
)
120 sprintf(TempString
, "Linux initrd image \'%s\' not found.", LinuxInitrdName
);
121 UiMessageBox(TempString
);
122 goto LinuxBootFailed
;
126 // Read the boot sector
127 if (!LinuxReadBootSector(LinuxKernel
))
129 goto LinuxBootFailed
;
132 // Read the setup sector
133 if (!LinuxReadSetupSector(LinuxKernel
))
135 goto LinuxBootFailed
;
139 LinuxKernelSize
= FsGetFileSize(LinuxKernel
) - (512 + SetupSectorSize
);
142 LinuxInitrdSize
= FsGetFileSize(LinuxInitrdFile
);
145 if (!LinuxReadKernel(LinuxKernel
))
147 goto LinuxBootFailed
;
150 // Read the initrd (if necessary)
153 if (!LinuxReadInitrd(LinuxInitrdFile
))
155 goto LinuxBootFailed
;
159 // If the default root device is set to FLOPPY (0000h), change to /dev/fd0 (0200h)
160 if (LinuxBootSector
->RootDevice
== 0x0000)
162 LinuxBootSector
->RootDevice
= 0x0200;
165 if (LinuxSetupSector
->Version
>= 0x0202)
167 LinuxSetupSector
->CommandLinePointer
= 0x99000;
171 LinuxBootSector
->CommandLineMagic
= LINUX_COMMAND_LINE_MAGIC
;
172 LinuxBootSector
->CommandLineOffset
= 0x9000;
175 if (NewStyleLinuxKernel
)
177 LinuxSetupSector
->TypeOfLoader
= LINUX_LOADER_TYPE_FREELOADER
;
181 LinuxSetupSector
->LoadFlags
= 0;
184 RtlCopyMemory((PVOID
)0x90000, LinuxBootSector
, 512);
185 RtlCopyMemory((PVOID
)0x90200, LinuxSetupSector
, SetupSectorSize
);
186 RtlCopyMemory((PVOID
)0x99000, LinuxCommandLine
, LinuxCommandLineSize
);
188 UiUnInitialize("Booting Linux...");
190 DiskStopFloppyMotor();
192 if (LinuxSetupSector
->LoadFlags
& LINUX_FLAG_LOAD_HIGH
)
194 BootNewLinuxKernel();
198 BootOldLinuxKernel(LinuxKernelSize
);
206 FsCloseFile(LinuxKernel
);
210 FsCloseFile(LinuxInitrdFile
);
213 if (LinuxBootSector
!= NULL
)
215 MmFreeMemory(LinuxBootSector
);
217 if (LinuxSetupSector
!= NULL
)
219 MmFreeMemory(LinuxSetupSector
);
221 if (LinuxKernelLoadAddress
!= NULL
)
223 MmFreeMemory(LinuxKernelLoadAddress
);
225 if (LinuxInitrdLoadAddress
!= NULL
)
227 MmFreeMemory(LinuxInitrdLoadAddress
);
230 LinuxBootSector
= NULL
;
231 LinuxSetupSector
= NULL
;
232 LinuxKernelLoadAddress
= NULL
;
233 LinuxInitrdLoadAddress
= NULL
;
235 NewStyleLinuxKernel
= FALSE
;
237 LinuxHasInitrd
= FALSE
;
238 strcpy(LinuxCommandLine
, "");
239 LinuxCommandLineSize
= 0;
242 BOOLEAN
LinuxParseIniSection(PCSTR SectionName
)
245 CHAR SettingName
[260];
247 // Find all the message box settings and run them
248 UiShowMessageBoxesInSection(SectionName
);
250 // Try to open the operating system section in the .ini file
251 if (!IniOpenSection(SectionName
, &SectionId
))
253 sprintf(SettingName
, "Section [%s] not found in freeldr.ini.\n", SectionName
);
254 UiMessageBox(SettingName
);
258 if (!IniReadSettingByName(SectionId
, "BootPath", LinuxBootPath
, sizeof(LinuxBootPath
)))
260 UiMessageBox("Boot path not specified for selected OS!");
264 // Get the kernel name
265 if (!IniReadSettingByName(SectionId
, "Kernel", LinuxKernelName
, sizeof(LinuxKernelName
)))
267 UiMessageBox("Linux kernel filename not specified for selected OS!");
271 // Get the initrd name
272 if (IniReadSettingByName(SectionId
, "Initrd", LinuxInitrdName
, sizeof(LinuxInitrdName
)))
274 LinuxHasInitrd
= TRUE
;
277 // Get the command line
278 if (IniReadSettingByName(SectionId
, "CommandLine", LinuxCommandLine
, sizeof(LinuxCommandLine
)))
280 RemoveQuotes(LinuxCommandLine
);
281 LinuxCommandLineSize
= strlen(LinuxCommandLine
) + 1;
287 BOOLEAN
LinuxReadBootSector(PFILE LinuxKernelFile
)
289 // Allocate memory for boot sector
290 LinuxBootSector
= MmAllocateMemoryWithType(512, LoaderSystemCode
);
291 if (LinuxBootSector
== NULL
)
296 // Read linux boot sector
297 FsSetFilePointer(LinuxKernelFile
, 0);
298 if (!FsReadFile(LinuxKernelFile
, 512, NULL
, LinuxBootSector
))
303 // Check for validity
304 if (LinuxBootSector
->BootFlag
!= LINUX_BOOT_SECTOR_MAGIC
)
306 UiMessageBox("Invalid boot sector magic (0xaa55)");
310 DbgDumpBuffer(DPRINT_LINUX
, LinuxBootSector
, 512);
312 TRACE("SetupSectors: %d\n", LinuxBootSector
->SetupSectors
);
313 TRACE("RootFlags: 0x%x\n", LinuxBootSector
->RootFlags
);
314 TRACE("SystemSize: 0x%x\n", LinuxBootSector
->SystemSize
);
315 TRACE("SwapDevice: 0x%x\n", LinuxBootSector
->SwapDevice
);
316 TRACE("RamSize: 0x%x\n", LinuxBootSector
->RamSize
);
317 TRACE("VideoMode: 0x%x\n", LinuxBootSector
->VideoMode
);
318 TRACE("RootDevice: 0x%x\n", LinuxBootSector
->RootDevice
);
319 TRACE("BootFlag: 0x%x\n", LinuxBootSector
->BootFlag
);
324 BOOLEAN
LinuxReadSetupSector(PFILE LinuxKernelFile
)
326 UCHAR TempLinuxSetupSector
[512];
328 LinuxSetupSector
= (PLINUX_SETUPSECTOR
)TempLinuxSetupSector
;
330 // Read first linux setup sector
331 FsSetFilePointer(LinuxKernelFile
, 512);
332 if (!FsReadFile(LinuxKernelFile
, 512, NULL
, TempLinuxSetupSector
))
337 // Check the kernel version
338 if (!LinuxCheckKernelVersion())
343 if (NewStyleLinuxKernel
)
345 SetupSectorSize
= 512 * LinuxBootSector
->SetupSectors
;
349 SetupSectorSize
= 4 * 512; // Always 4 setup sectors
352 // Allocate memory for setup sectors
353 LinuxSetupSector
= MmAllocateMemoryWithType(SetupSectorSize
, LoaderSystemCode
);
354 if (LinuxSetupSector
== NULL
)
359 // Copy over first setup sector
360 RtlCopyMemory(LinuxSetupSector
, TempLinuxSetupSector
, 512);
362 // Read in the rest of the linux setup sectors
363 FsSetFilePointer(LinuxKernelFile
, 1024);
364 if (!FsReadFile(LinuxKernelFile
, SetupSectorSize
- 512, NULL
, (PVOID
)((ULONG_PTR
)LinuxSetupSector
+ 512)))
369 DbgDumpBuffer(DPRINT_LINUX
, LinuxSetupSector
, SetupSectorSize
);
371 TRACE("SetupHeaderSignature: 0x%x (HdrS)\n", LinuxSetupSector
->SetupHeaderSignature
);
372 TRACE("Version: 0x%x\n", LinuxSetupSector
->Version
);
373 TRACE("RealModeSwitch: 0x%x\n", LinuxSetupSector
->RealModeSwitch
);
374 TRACE("SetupSeg: 0x%x\n", LinuxSetupSector
->SetupSeg
);
375 TRACE("StartSystemSeg: 0x%x\n", LinuxSetupSector
->StartSystemSeg
);
376 TRACE("KernelVersion: 0x%x\n", LinuxSetupSector
->KernelVersion
);
377 TRACE("TypeOfLoader: 0x%x\n", LinuxSetupSector
->TypeOfLoader
);
378 TRACE("LoadFlags: 0x%x\n", LinuxSetupSector
->LoadFlags
);
379 TRACE("SetupMoveSize: 0x%x\n", LinuxSetupSector
->SetupMoveSize
);
380 TRACE("Code32Start: 0x%x\n", LinuxSetupSector
->Code32Start
);
381 TRACE("RamdiskAddress: 0x%x\n", LinuxSetupSector
->RamdiskAddress
);
382 TRACE("RamdiskSize: 0x%x\n", LinuxSetupSector
->RamdiskSize
);
383 TRACE("BootSectKludgeOffset: 0x%x\n", LinuxSetupSector
->BootSectKludgeOffset
);
384 TRACE("BootSectKludgeSegment: 0x%x\n", LinuxSetupSector
->BootSectKludgeSegment
);
385 TRACE("HeapEnd: 0x%x\n", LinuxSetupSector
->HeapEnd
);
390 BOOLEAN
LinuxReadKernel(PFILE LinuxKernelFile
)
393 CHAR StatusText
[260];
396 sprintf(StatusText
, "Loading %s", LinuxKernelName
);
397 UiDrawStatusText(StatusText
);
399 // Allocate memory for Linux kernel
400 LinuxKernelLoadAddress
= MmAllocateMemoryAtAddress(LinuxKernelSize
, (PVOID
)LINUX_KERNEL_LOAD_ADDRESS
, LoaderSystemCode
);
401 if (LinuxKernelLoadAddress
!= (PVOID
)LINUX_KERNEL_LOAD_ADDRESS
)
406 LoadAddress
= LinuxKernelLoadAddress
;
408 // Read linux kernel to 0x100000 (1mb)
409 FsSetFilePointer(LinuxKernelFile
, 512 + SetupSectorSize
);
410 for (BytesLoaded
=0; BytesLoaded
<LinuxKernelSize
; )
412 if (!FsReadFile(LinuxKernelFile
, LINUX_READ_CHUNK_SIZE
, NULL
, LoadAddress
))
417 BytesLoaded
+= LINUX_READ_CHUNK_SIZE
;
418 LoadAddress
= (PVOID
)((ULONG_PTR
)LoadAddress
+ LINUX_READ_CHUNK_SIZE
);
420 UiDrawProgressBarCenter(BytesLoaded
, LinuxKernelSize
+ LinuxInitrdSize
, LinuxBootDescription
);
426 BOOLEAN
LinuxCheckKernelVersion(VOID
)
428 // Just assume old kernel until we find otherwise
429 NewStyleLinuxKernel
= FALSE
;
431 // Check for new style setup header
432 if (LinuxSetupSector
->SetupHeaderSignature
!= LINUX_SETUP_HEADER_ID
)
434 NewStyleLinuxKernel
= FALSE
;
436 // Check for version below 2.0
437 else if (LinuxSetupSector
->Version
< 0x0200)
439 NewStyleLinuxKernel
= FALSE
;
441 // Check for version 2.0
442 else if (LinuxSetupSector
->Version
== 0x0200)
444 NewStyleLinuxKernel
= TRUE
;
446 // Check for version 2.01+
447 else if (LinuxSetupSector
->Version
>= 0x0201)
449 NewStyleLinuxKernel
= TRUE
;
450 LinuxSetupSector
->HeapEnd
= 0x9000;
451 LinuxSetupSector
->LoadFlags
|= LINUX_FLAG_CAN_USE_HEAP
;
454 if ((NewStyleLinuxKernel
== FALSE
) && (LinuxHasInitrd
== TRUE
))
456 UiMessageBox("Error: Cannot load a ramdisk (initrd) with an old kernel image.");
463 BOOLEAN
LinuxReadInitrd(PFILE LinuxInitrdFile
)
466 CHAR StatusText
[260];
468 sprintf(StatusText
, "Loading %s", LinuxInitrdName
);
469 UiDrawStatusText(StatusText
);
471 // Allocate memory for the ramdisk
472 //LinuxInitrdLoadAddress = MmAllocateMemory(LinuxInitrdSize);
473 // Try to align it at the next MB boundary after the kernel
474 //LinuxInitrdLoadAddress = MmAllocateMemoryAtAddress(LinuxInitrdSize, (PVOID)ROUND_UP((LINUX_KERNEL_LOAD_ADDRESS + LinuxKernelSize), 0x100000));
475 if (LinuxSetupSector
->Version
<= 0x0202)
477 LinuxInitrdLoadAddress
= MmAllocateHighestMemoryBelowAddress(LinuxInitrdSize
, (PVOID
)LINUX_MAX_INITRD_ADDRESS
, LoaderSystemCode
);
481 LinuxInitrdLoadAddress
= MmAllocateHighestMemoryBelowAddress(LinuxInitrdSize
, (PVOID
)LinuxSetupSector
->InitrdAddressMax
, LoaderSystemCode
);
483 if (LinuxInitrdLoadAddress
== NULL
)
488 // Set the information in the setup struct
489 LinuxSetupSector
->RamdiskAddress
= (ULONG
)LinuxInitrdLoadAddress
;
490 LinuxSetupSector
->RamdiskSize
= LinuxInitrdSize
;
492 TRACE("RamdiskAddress: 0x%x\n", LinuxSetupSector
->RamdiskAddress
);
493 TRACE("RamdiskSize: 0x%x\n", LinuxSetupSector
->RamdiskSize
);
495 if (LinuxSetupSector
->Version
>= 0x0203)
497 TRACE("InitrdAddressMax: 0x%x\n", LinuxSetupSector
->InitrdAddressMax
);
500 // Read in the ramdisk
501 for (BytesLoaded
=0; BytesLoaded
<LinuxInitrdSize
; )
503 if (!FsReadFile(LinuxInitrdFile
, LINUX_READ_CHUNK_SIZE
, NULL
, (PVOID
)LinuxInitrdLoadAddress
))
508 BytesLoaded
+= LINUX_READ_CHUNK_SIZE
;
509 LinuxInitrdLoadAddress
= (PVOID
)((ULONG_PTR
)LinuxInitrdLoadAddress
+ LINUX_READ_CHUNK_SIZE
);
511 UiDrawProgressBarCenter(BytesLoaded
+ LinuxKernelSize
, LinuxInitrdSize
+ LinuxKernelSize
, LinuxBootDescription
);
516 #endif /* __i386__ */