Add ability to be loaded as "multiboot kernel" from other multiboot loaders

svn path=/trunk/; revision=11524
This commit is contained in:
Gé van Geldorp 2004-11-01 20:49:32 +00:00
parent 3ec6acd622
commit a10211cdc2
8 changed files with 361 additions and 41 deletions

View file

@ -269,17 +269,18 @@ VIDEO_OBJS = video.o \
MATH_OBJS = libgcc2.o
BASE_OBJS = freeldr.o \
debug.o \
multiboot.o \
version.o
debug.o \
multiboot.o \
version.o \
cmdline.o
FREELDR_OBJS= bootmgr.o \
drivemap.o \
miscboot.o \
options.o \
linuxboot.o \
oslist.o \
custom.o
drivemap.o \
miscboot.o \
options.o \
linuxboot.o \
oslist.o \
custom.o
ROSLDR_OBJS = reactos.o

View file

@ -22,6 +22,7 @@
#define ASM
#include <arch.h>
#include <multiboot.h>
EXTERN(RealEntryPoint)
@ -52,16 +53,18 @@ EXTERN(RealEntryPoint)
movb %dh,(_BootPartition)
/* GO! */
xorl %eax,%eax
pushl %eax
call _BootMain
call switch_to_real
.code16
int $0x19
int $0x19
/* We should never get here */
stop:
jmp stop
jmp stop
nop
nop
@ -100,9 +103,9 @@ EXTERN(switch_to_prot)
lidt i386idtptr
/* Enable Protected Mode */
mov %cr0,%eax
orl $CR0_PE_SET,%eax
mov %eax,%cr0
mov %cr0,%eax
orl $CR0_PE_SET,%eax
mov %eax,%cr0
/* Clear prefetch queue & correct CS */
ljmp $PMODE_CS, $inpmode
@ -168,9 +171,9 @@ switch_to_real16:
movw %ax,%ss
/* Disable Protected Mode */
mov %cr0,%eax
mov %cr0,%eax
andl $CR0_PE_CLR,%eax
mov %eax,%cr0
mov %eax,%cr0
/* Clear prefetch queue & correct CS */
ljmp $0, $inrmode
@ -211,9 +214,9 @@ inrmode:
.code16
empty_8042:
.word 0x00eb,0x00eb // jmp $+2, jmp $+2
inb $0x64,%al
testb $0x02,%al
jnz empty_8042
inb $0x64,%al
testb $0x02,%al
jnz empty_8042
ret
/*
@ -228,11 +231,11 @@ EXTERN(_EnableA20)
.code16
call empty_8042
movb $0xD1,%al // command write
outb %al,$0x64
movb $0xD1,%al // command write
outb %al,$0x64
call empty_8042
mov $0xDF,%al // A20 on
out %al,$0x60
mov $0xDF,%al // A20 on
out %al,$0x60
call empty_8042
call switch_to_prot
.code32
@ -253,11 +256,11 @@ EXTERN(_DisableA20)
.code16
call empty_8042
movb $0xD1,%al // command write
outb %al,$0x64
movb $0xD1,%al // command write
outb %al,$0x64
call empty_8042
mov $0xDD,%al // A20 off
out %al,$0x60
mov $0xDD,%al // A20 off
out %al,$0x60
call empty_8042
call switch_to_prot
.code32
@ -266,8 +269,134 @@ EXTERN(_DisableA20)
ret
/* Multiboot support
*
* Allows freeldr to be loaded as a "multiboot kernel" by
* other boot loaders like Grub
*/
#define MB_INFO_FLAGS_OFFSET 0
#define MB_INFO_BOOT_DEVICE_OFFSET 12
#define MB_INFO_COMMAND_LINE_OFFSET 16
/*
* We want to execute at 0x8000 (to be compatible with bootsector
* loading), but Grub only allows loading of multiboot kernels
* above 1MB. So we let Grub load us there and then relocate
* ourself to 0x8000
*/
#define CMDLINE_BASE 0x7000
#define FREELDR_BASE 0x8000
#define INITIAL_BASE 0x200000
/* Align 32 bits boundary */
.align 4
/* Multiboot header */
MultibootHeader:
/* magic */
.long MULTIBOOT_HEADER_MAGIC
/* flags */
.long MULTIBOOT_HEADER_FLAGS
/* checksum */
.long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
/* header_addr */
.long INITIAL_BASE + MultibootHeader - FREELDR_BASE
/* load_addr */
.long INITIAL_BASE
/* load_end_addr */
.long INITIAL_BASE + __bss_start__ - FREELDR_BASE
/* bss_end_addr */
.long INITIAL_BASE + __bss_end__ - FREELDR_BASE
/* entry_addr */
.long INITIAL_BASE + MultibootEntry - FREELDR_BASE
MultibootEntry:
cli /* Even after setting up the our IDT below we are
* not ready to handle hardware interrupts (no entries
* in IDT), so there's no sti here. Interrupts will be
* enabled in due time */
/* Although the multiboot spec says we should be called with the
* segment registers set to 4GB flat mode, let's be sure and set up
* our own */
lgdt gdtptrhigh + INITIAL_BASE - FREELDR_BASE
/* Reload segment selectors */
ljmp $PMODE_CS, $(mb1 + INITIAL_BASE - FREELDR_BASE)
mb1:
movw $PMODE_DS,%dx
movw %dx,%ds
movw %dx,%es
/* Copy to low mem */
movl $INITIAL_BASE,%esi
movl $FREELDR_BASE,%edi
movl $(__bss_end__ - FREELDR_BASE),%ecx
addl $3,%ecx
shrl $2,%ecx
rep movsl
/* Load the GDT and IDT */
lgdt gdtptr
lidt i386idtptr
/* Clear prefetch queue & correct CS,
* jump to low mem */
ljmp $PMODE_CS, $mb2
mb2:
/* Reload segment selectors */
movw $PMODE_DS,%dx
movw %dx,%ds
movw %dx,%es
movw %dx,%fs
movw %dx,%gs
movw %dx,%ss
movl $STACK32ADDR,%esp
/* Check for valid multiboot signature */
cmpl $MULTIBOOT_BOOTLOADER_MAGIC,%eax
jne mbfail
/* See if the boot device was passed in */
movl MB_INFO_FLAGS_OFFSET(%ebx),%edx
testl $MB_INFO_FLAG_BOOT_DEVICE,%edx
jz mb3
/* Retrieve boot device info */
movl MB_INFO_BOOT_DEVICE_OFFSET(%ebx),%eax
shrl $16,%eax
incb %al
movb %al,_BootPartition
movb %ah,_BootDrive
jmp mb4
mb3: /* No boot device known, assume first partition of first harddisk */
movb $0x80,_BootDrive
movb $1,_BootPartition
mb4:
/* Check for a command line */
xorl %eax,%eax
testl $MB_INFO_FLAG_COMMAND_LINE,%edx
jz mb6
/* Copy command line to low mem*/
movl MB_INFO_COMMAND_LINE_OFFSET(%ebx),%esi
movl $CMDLINE_BASE,%edi
mb5: lodsb
stosb
testb %al,%al
jnz mb5
movl $CMDLINE_BASE,%eax
mb6:
/* GO! */
pushl %eax
call _BootMain
mbfail: call switch_to_real
.code16
int $0x19
mbstop: jmp mbstop /* We should never get here */
.code32
/* 16-bit stack pointer */
stack16:
@ -323,6 +452,11 @@ gdtptr:
.word 0x27 /* Limit */
.long gdt /* Base Address */
/* Initial GDT table pointer for multiboot */
gdtptrhigh:
.word 0x27 /* Limit */
.long gdt + INITIAL_BASE - FREELDR_BASE /* Base Address */
/* Real-mode IDT pointer */
rmode_idtptr:
.word 0x3ff /* Limit */

View file

@ -34,6 +34,7 @@
#include <bootmgr.h>
#include <drivemap.h>
#include <keycodes.h>
#include <cmdline.h>
VOID RunLoader(VOID)
@ -153,20 +154,30 @@ reboot:
U32 GetDefaultOperatingSystem(PUCHAR OperatingSystemList[], U32 OperatingSystemCount)
{
UCHAR DefaultOSText[80];
U32 SectionId;
U32 DefaultOS = 0;
U32 Idx;
char* DefaultOSName;
U32 SectionId;
U32 DefaultOS = 0;
U32 Idx;
if (!IniOpenSection("FreeLoader", &SectionId))
{
return 0;
}
if (IniReadSettingByName(SectionId, "DefaultOS", DefaultOSText, 80))
DefaultOSName = CmdLineGetDefaultOS();
if (NULL == DefaultOSName)
{
if (IniReadSettingByName(SectionId, "DefaultOS", DefaultOSText, 80))
{
DefaultOSName = DefaultOSText;
}
}
if (NULL != DefaultOSName)
{
for (Idx=0; Idx<OperatingSystemCount; Idx++)
{
if (stricmp(DefaultOSText, OperatingSystemList[Idx]) == 0)
if (stricmp(DefaultOSName, OperatingSystemList[Idx]) == 0)
{
DefaultOS = Idx;
break;
@ -183,6 +194,12 @@ S32 GetTimeOut(VOID)
U32 TimeOut;
U32 SectionId;
TimeOut = CmdLineGetTimeOut();
if (0 <= TimeOut)
{
return TimeOut;
}
if (!IniOpenSection("FreeLoader", &SectionId))
{
return -1;

122
freeldr/freeldr/cmdline.c Normal file
View file

@ -0,0 +1,122 @@
/* $Id: cmdline.c,v 1.1 2004/11/01 20:49:32 gvg Exp $
*
* FreeLoader
* Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <freeldr.h>
#include <cmdline.h>
#include <rtl.h>
static CMDLINEINFO CmdLineInfo;
static char *
SkipWhitespace(char *s)
{
while ('\0' != *s && isspace(*s))
{
s++;
}
return s;
}
void
CmdLineParse(char *CmdLine)
{
char *s;
char *Name;
char *Value;
char *End;
CmdLineInfo.DefaultOperatingSystem = NULL;
CmdLineInfo.TimeOut = -1;
if (NULL == CmdLine)
{
return;
}
/* Skip over "kernel name" */
s = CmdLine;
while ('\0' != *s && ! isspace(*s))
{
s++;
}
s = SkipWhitespace(s);
while ('\0' != *s)
{
Name = s;
while (! isspace(*s) && '=' != *s && '\0' != *s)
{
s++;
}
End = s;
s = SkipWhitespace(s);
if ('=' == *s)
{
s++;
*End = '\0';
s = SkipWhitespace(s);
if ('"' == *s)
{
s++;
Value = s;
while ('"' != *s && '\0' != *s)
{
s++;
}
}
else
{
Value = s;
while (! isspace(*s) && '\0' != *s)
{
s++;
}
}
if ('\0' != *s)
{
*s++ = '\0';
}
if (0 == stricmp(Name, "defaultos"))
{
CmdLineInfo.DefaultOperatingSystem = Value;
}
else if (0 == stricmp(Name, "timeout"))
{
CmdLineInfo.TimeOut = atoi(Value);
}
}
}
}
char *
CmdLineGetDefaultOS(void)
{
return CmdLineInfo.DefaultOperatingSystem;
}
S32
CmdLineGetTimeOut(void)
{
return CmdLineInfo.TimeOut;
}
/* EOF */

View file

@ -24,13 +24,11 @@
#include <debug.h>
#include <bootmgr.h>
#include <fs.h>
#include <cmdline.h>
// Variables BootDrive & BootPartition moved to asmcode.S
//U32 BootDrive = 0; // BIOS boot drive, 0-A:, 1-B:, 0x80-C:, 0x81-D:, etc.
//U32 BootPartition = 0; // Boot Partition, 1-4
VOID BootMain(VOID)
VOID BootMain(char *CmdLine)
{
CmdLineParse(CmdLine);
EnableA20();

View file

@ -0,0 +1,37 @@
/* $Id: cmdline.h,v 1.1 2004/11/01 20:49:32 gvg Exp $
*
* FreeLdr boot loader
* Copyright (C) 2002, 2003 ReactOS Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __CMDLINE_H__
#define __CMDLINE_H__
typedef struct tagCMDLINEINFO
{
char *DefaultOperatingSystem;
S32 TimeOut;
} CMDLINEINFO, *PCMDLINEINFO;
extern void CmdLineParse(char *CmdLine);
extern char *CmdLineGetDefaultOS(void);
extern S32 CmdLineGetTimeOut(void);
#endif /* __CMDLINE_H__ */
/* EOF */

View file

@ -75,7 +75,7 @@ extern U32 BootDrive; // BIOS boot drive, 0-A:, 1-B:, 0x80-C:, 0x81-D:, etc.
extern U32 BootPartition; // Boot Partition, 1-4
extern BOOL UserInterfaceUp; // Tells us if the user interface is displayed
void BootMain(void);
void BootMain(char *CmdLine);
VOID RunLoader(VOID);
#endif // defined __FREELDR_H

View file

@ -4,7 +4,7 @@ Memory layout:
0000:0000 - 0000:0FFF: Interrupt vector table & BIOS data
0000:1000 - 0000:6FFF: Real mode stack area
0000:7000 - 0000:7FFF: Unused
0000:7000 - 0000:7FFF: Cmdline (multiboot)
0000:8000 - xxxx:xxxx: FreeLoader program & data area
xxxx:xxxx - 7000:7FFF: Random memory allocation heap
7000:8000 - 7000:FFFF: Protected mode stack area
@ -34,13 +34,24 @@ ISO-9660 (CD-ROM) Boot Sector
The BIOS loads the boot sector (2048 bytes) at 0000:7C00. First, the
boot sector relocates itself to 0000:7000 (up to 0000:7800). Then it looks
for the I386 directory and makes it the current directory. Next it looks for
for the LOADER directory and makes it the current directory. Next it looks for
FREELDR.SYS and loads it at 0000:8000. Finally it restores the boot drive
number in the DL register and jumps to FreeLoader's entry point at 0000:8000.
Multiboot
Freeldr contains a multiboot signature and can itself be loaded by a
multiboot-compliant loader (like Grub). The multiboot header instructs the
primary loader to load freeldr.sys at 0x200000 (needs to be above 1MB). Control
is then transferred to the multiboot entry point. Since freeldr.sys expects to
be loaded at a base address 0000:8000 it will start by relocating itself there
and then jumping to the relocated copy.
FreeLoader Initialization
When FreeLoader gets control it saves the boot drive, passed to it in
the DL register, and sets up the stack, enables protected mode, and calls
BootMain().
BootMain().