/* linux.c - boot Linux */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2003, 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
*
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
GRUB_MOD_LICENSE ("GPLv3+");
static int loaded;
/* /virtual-memory/translations property layout */
struct grub_ieee1275_translation {
};
static int of_num_trans;
static char *linux_args;
struct linux_bootstr_info {
char buf[];
};
struct linux_hdrs {
/* All HdrS versions support these fields. */
unsigned short hdrs_version;
unsigned short root_flags;
unsigned short root_dev;
unsigned short ram_flags;
unsigned int __deprecated_ramdisk_image;
unsigned int ramdisk_size;
/* HdrS versions 0x0201 and higher only */
char *reboot_command;
/* HdrS versions 0x0202 and higher only */
/* HdrS versions 0x0301 and higher only */
unsigned long ramdisk_image;
};
static grub_err_t
grub_linux_boot (void)
{
/* Any pointer we dereference in the kernel image must be relocated
to where we actually loaded the kernel. */
/* Set the command line arguments, unless the kernel has been
built with a fixed CONFIG_CMDLINE. */
{
}
if (initrd_addr)
{
/* The kernel expects the physical address, adjusted relative
to the lowest address advertised in "/memory"'s available
property.
The history of this is that back when the kernel only supported
specifying a 32-bit ramdisk address, this was the way to still
be able to specify the ramdisk physical address even if memory
started at some place above 4GB.
The magic 0x400000 is KERNBASE, I have no idea why SILO adds
that term into the address, but it does and thus we have to do
it too as this is what the kernel expects. */
}
/* Boot the kernel. */
asm volatile ("sethi %hi(grub_ieee1275_entry_fn), %o1\n"
"ldx [%o1 + %lo(grub_ieee1275_entry_fn)], %o4\n"
"sethi %hi(grub_ieee1275_original_stack), %o1\n"
"ldx [%o1 + %lo(grub_ieee1275_original_stack)], %o6\n"
"sethi %hi(linux_addr), %o1\n"
"ldx [%o1 + %lo(linux_addr)], %o5\n"
"mov %g0, %o0\n"
"mov %g0, %o2\n"
"mov %g0, %o3\n"
"jmp %o5\n"
"mov %g0, %o1\n");
return GRUB_ERR_NONE;
}
static grub_err_t
grub_linux_release_mem (void)
{
linux_args = 0;
linux_addr = 0;
initrd_addr = 0;
return GRUB_ERR_NONE;
}
static grub_err_t
grub_linux_unload (void)
{
err = grub_linux_release_mem ();
loaded = 0;
return err;
}
static grub_addr_t
{
{
if (type != 1)
return 0;
return 0;
{
return 0;
}
{
return 0;
}
if (loaded)
{
{
return 0;
}
{
return 0;
}
}
return 1;
}
return ret;
}
static grub_err_t
{
int ret;
linux_addr = 0x40004000;
off = 0x4000;
if (linux_size == 0)
return grub_errno;
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
"couldn't allocate physical memory");
if (ret)
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
"couldn't map physical memory");
linux_paddr = paddr;
/* Now load the segments into the area we claimed. */
{
{
*do_load = 0;
return 0;
}
*do_load = 1;
/* Adjust the program load address to linux_addr. */
return 0;
}
}
static grub_err_t
{
int size;
if (argc == 0)
{
goto out;
}
if (!file)
goto out;
if (! elf)
goto out;
{
"this ELF file is not of the right type");
goto out;
}
/* Release the previously used memory. */
if (grub_elf_is_elf64 (elf))
else
{
goto out;
}
if (! linux_args)
goto out;
/* Create kernel command line. */
size);
out:
if (elf)
else if (file)
if (grub_errno != GRUB_ERR_NONE)
{
loaded = 0;
}
else
{
initrd_addr = 0;
loaded = 1;
}
return grub_errno;
}
static grub_err_t
{
int ret;
int i;
int nfiles = 0;
if (argc == 0)
{
goto fail;
}
if (!loaded)
{
goto fail;
}
if (!files)
goto fail;
for (i = 0; i < argc; i++)
{
if (! files[i])
goto fail;
nfiles++;
}
addr = 0x60000000;
{
"couldn't allocate physical memory");
goto fail;
}
if (ret)
{
"couldn't map physical memory");
goto fail;
}
for (i = 0; i < nfiles; i++)
{
{
if (!grub_errno)
argv[i]);
goto fail;
}
}
initrd_addr = addr;
initrd_size = size;
fail:
for (i = 0; i < nfiles; i++)
grub_file_close (files[i]);
return grub_errno;
}
static void
determine_phys_base (void)
{
auto int NESTED_FUNC_ATTR get_physbase (grub_uint64_t addr, grub_uint64_t len __attribute__((unused)), grub_uint32_t type);
int NESTED_FUNC_ATTR get_physbase (grub_uint64_t addr, grub_uint64_t len __attribute__((unused)), grub_uint32_t type)
{
if (type != 1)
return 0;
return 0;
}
phys_base = ~(grub_uint64_t) 0;
}
static void
fetch_translations (void)
{
int i;
{
grub_printf ("Cannot find /virtual-memory node.\n");
return;
}
{
grub_printf ("Cannot find /virtual-memory/translations size.\n");
return;
}
if (!of_trans)
{
grub_printf ("Cannot allocate translations buffer.\n");
return;
}
{
grub_printf ("Cannot fetch /virtual-memory/translations property.\n");
return;
}
for (i = 0; i < of_num_trans; i++)
{
struct grub_ieee1275_translation *p = &of_trans[i];
if (p->vaddr == 0x2000)
{
(unsigned long) grub_phys_start,
(unsigned long) grub_phys_end);
break;
}
}
}
{
0, N_("Load Linux."));
0, N_("Load initrd."));
}
{
}