blob: 25a498a06081a6eec10cd6532aa52f38d717166e [file] [log] [blame] [raw]
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1996 Erich Boleyn <erich@uruk.org>
*
* 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.
*/
#define _COMMON_C
#include "shared.h"
/*
* Shared BIOS/boot data.
*/
struct multiboot_info mbi;
unsigned long saved_drive;
unsigned long saved_partition;
unsigned long saved_mem_upper;
/*
* Error code stuff.
*/
int errnum = 0;
#ifndef NO_FANCY_STUFF
char *err_list[] =
{
0,
"Selected item won\'t fit into memory",
"Selected disk doesn\'t exist",
"Disk read error",
"Disk write error",
"Disk geometry error",
"Attempt to access block outside partition",
"Partition table invalid or corrupt",
"No such partition",
"Bad filename (must be absolute pathname or blocklist)",
"Bad file or directory type",
"File not found",
"Cannot mount selected partition",
"Inconsistent filesystem structure",
"Filesystem compatibility error, can\'t read whole file",
"Error while parsing number",
"Device string unrecognizable",
"Invalid device requested",
"Invalid or unsupported executable format",
"Loading below 1MB is not supported",
"Unsupported Multiboot features requested",
"Unknown boot failure",
"Must load Multiboot kernel before modules",
"Must load Linux kernel before initrd",
"Cannot boot without kernel loaded",
"Unrecognized command",
"Bad or incompatible header on compressed file",
"Bad or corrupt data while decompressing file",
"Bad or corrupt version of stage1/stage2",
0
};
/* static for BIOS memory map fakery */
static struct AddrRangeDesc fakemap[3] =
{
{ 20, 0, 0, 0, 0, MB_ARD_MEMORY },
{ 20, 0x100000, 0, 0, 0, MB_ARD_MEMORY },
{ 20, 0x1000000, 0, 0, 0, MB_ARD_MEMORY }
};
#endif /* NO_FANCY_STUFF */
/*
* This queries for BIOS information.
*/
void
init_bios_info(void)
{
int cont, memtmp, addr;
/*
* Get information from BIOS on installed RAM.
*/
mbi.mem_lower = get_memsize(0);
mbi.mem_upper = get_memsize(1);
#ifndef NO_FANCY_STUFF
/*
* We need to call this somewhere before trying to put data
* above 1 MB, since without calling it, address line 20 will be wired
* to 0. Not too desirable.
*/
gateA20(1);
/*
* The "mbi.mem_upper" variable only recognizes upper memory in the
* first memory region. If there are multiple memory regions,
* the rest are reported to a Multiboot-compliant OS, but otherwise
* unused by GRUB.
*/
mbi.mmap_addr = (addr = (((int) end) & ~3) + 4);
mbi.mmap_length = 0;
cont = 0;
do
{
cont = get_mem_map(addr, cont);
if ( ! *((int *)addr) )
break;
mbi.mmap_length += *((int *)addr) + 4;
addr += *((int *)addr) + 4;
}
while (cont);
if (mbi.mmap_length)
{
/*
* This is to get the upper memory up to the first memory
* hole into the "mbi.mem_upper" element, for OS's that
* don't care about the memory map, but might care about
* RAM above 64MB.
*
* A big problem is that the memory areas aren't guaranteed
* to be: (1) contiguous, (2) sorted in ascending order, or
* (3) non-overlapping.
*/
memtmp = 0x100000;
do
{
for (cont = 0, addr = mbi.mmap_addr;
addr < mbi.mmap_addr + mbi.mmap_length;
addr += *((int *) addr) + 4)
{
if (((struct AddrRangeDesc *)addr)->BaseAddrHigh == 0
&& ((struct AddrRangeDesc *)addr)->Type == MB_ARD_MEMORY
&& ((struct AddrRangeDesc *)addr)->BaseAddrLow <= memtmp
&& (((struct AddrRangeDesc *)addr)->BaseAddrLow
+ ((struct AddrRangeDesc *)addr)->LengthLow) > memtmp)
{
memtmp = (((struct AddrRangeDesc *)addr)->BaseAddrLow
+ ((struct AddrRangeDesc *)addr)->LengthLow);
cont++;
}
}
}
while (cont);
mbi.mem_upper = (memtmp - 0x100000) >> 10;
}
else if ((memtmp = get_eisamemsize()) != -1)
{
cont = memtmp & ~0xFFFF;
memtmp = memtmp & 0xFFFF;
if (!cont || (memtmp == 0x3c00))
memtmp += (cont >> 10);
else
{
/* XXX should I do this at all ??? */
mbi.mmap_addr = (int)fakemap;
mbi.mmap_length = sizeof(fakemap);
fakemap[0].LengthLow = (mbi.mem_lower << 10);
fakemap[1].LengthLow = (memtmp << 10);
fakemap[2].LengthLow = cont;
}
mbi.mem_upper = memtmp;
}
saved_mem_upper = mbi.mem_upper;
/*
* Initialize other Multiboot Info flags.
*/
mbi.flags = MB_INFO_MEMORY | MB_INFO_CMDLINE | MB_INFO_BOOTDEV;
#endif /* NO_FANCY_STUFF */
/*
* Set boot drive and partition.
*/
saved_drive = boot_drive;
saved_partition = install_partition;
/*
* Start main routine here.
*/
cmain();
}