Resync with trunk

This commit is contained in:
Robert Millan 2010-01-18 15:02:21 +00:00
commit e68d3b243f
706 changed files with 157184 additions and 45875 deletions

58
kern/command.c Normal file
View file

@ -0,0 +1,58 @@
/* command.c - support basic command */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <grub/mm.h>
#include <grub/command.h>
grub_command_t grub_command_list;
grub_command_t
grub_register_command_prio (const char *name,
grub_command_func_t func,
const char *summary,
const char *description,
int prio)
{
grub_command_t cmd;
cmd = (grub_command_t) grub_zalloc (sizeof (*cmd));
if (! cmd)
return 0;
cmd->name = name;
cmd->func = func;
cmd->summary = (summary) ? summary : "";
cmd->description = description;
cmd->flags = GRUB_COMMAND_FLAG_BOTH;
cmd->prio = prio;
grub_prio_list_insert (GRUB_AS_PRIO_LIST_P (&grub_command_list),
GRUB_AS_PRIO_LIST (cmd));
return cmd;
}
void
grub_unregister_command (grub_command_t cmd)
{
grub_prio_list_remove (GRUB_AS_PRIO_LIST_P (&grub_command_list),
GRUB_AS_PRIO_LIST (cmd));
grub_free (cmd);
}

202
kern/corecmd.c Normal file
View file

@ -0,0 +1,202 @@
/* corecmd.c - critical commands which are registered in kernel */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <grub/mm.h>
#include <grub/dl.h>
#include <grub/err.h>
#include <grub/env.h>
#include <grub/misc.h>
#include <grub/term.h>
#include <grub/file.h>
#include <grub/device.h>
#include <grub/command.h>
/* set ENVVAR=VALUE */
static grub_err_t
grub_core_cmd_set (struct grub_command *cmd __attribute__ ((unused)),
int argc, char *argv[])
{
char *var;
char *val;
auto int print_env (struct grub_env_var *env);
int print_env (struct grub_env_var *env)
{
grub_printf ("%s=%s\n", env->name, env->value);
return 0;
}
if (argc < 1)
{
grub_env_iterate (print_env);
return 0;
}
var = argv[0];
val = grub_strchr (var, '=');
if (! val)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "not an assignment");
val[0] = 0;
grub_env_set (var, val + 1);
val[0] = '=';
return 0;
}
static grub_err_t
grub_core_cmd_unset (struct grub_command *cmd __attribute__ ((unused)),
int argc, char *argv[])
{
if (argc < 1)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
"no environment variable specified");
grub_env_unset (argv[0]);
return 0;
}
static grub_err_t
grub_core_cmd_export (struct grub_command *cmd __attribute__ ((unused)),
int argc, char **args)
{
if (argc < 1)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
"no environment variable specified");
grub_env_export (args[0]);
return 0;
}
/* insmod MODULE */
static grub_err_t
grub_core_cmd_insmod (struct grub_command *cmd __attribute__ ((unused)),
int argc, char *argv[])
{
char *p;
grub_dl_t mod;
if (argc == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified");
p = grub_strchr (argv[0], '/');
if (! p)
mod = grub_dl_load (argv[0]);
else
mod = grub_dl_load_file (argv[0]);
if (mod)
grub_dl_ref (mod);
return 0;
}
static int
grub_mini_print_devices (const char *name)
{
grub_printf ("(%s) ", name);
return 0;
}
static int
grub_mini_print_files (const char *filename,
const struct grub_dirhook_info *info)
{
grub_printf ("%s%s ", filename, info->dir ? "/" : "");
return 0;
}
/* ls [ARG] */
static grub_err_t
grub_core_cmd_ls (struct grub_command *cmd __attribute__ ((unused)),
int argc, char *argv[])
{
if (argc < 1)
{
grub_device_iterate (grub_mini_print_devices);
grub_putchar ('\n');
grub_refresh ();
}
else
{
char *device_name;
grub_device_t dev;
grub_fs_t fs;
char *path;
device_name = grub_file_get_device_name (argv[0]);
dev = grub_device_open (device_name);
if (! dev)
goto fail;
fs = grub_fs_probe (dev);
path = grub_strchr (argv[0], ')');
if (! path)
path = argv[0];
else
path++;
if (! path && ! device_name)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid argument");
goto fail;
}
if (! path)
{
if (grub_errno == GRUB_ERR_UNKNOWN_FS)
grub_errno = GRUB_ERR_NONE;
grub_printf ("(%s): Filesystem is %s.\n",
device_name, fs ? fs->name : "unknown");
}
else if (fs)
{
(fs->dir) (dev, path, grub_mini_print_files);
grub_putchar ('\n');
grub_refresh ();
}
fail:
if (dev)
grub_device_close (dev);
grub_free (device_name);
}
return grub_errno;
}
void
grub_register_core_commands (void)
{
grub_register_command ("set", grub_core_cmd_set,
"[ENVVAR=VALUE]", "Set an environment variable.");
grub_register_command ("unset", grub_core_cmd_unset,
"ENVVAR", "Remove an environment variable.");
grub_register_command ("export", grub_core_cmd_export,
"ENVVAR", "Export a variable.");
grub_register_command ("ls", grub_core_cmd_ls,
"[ARG]", "List devices or files.");
grub_register_command ("insmod", grub_core_cmd_insmod,
"MODULE", "Insert a module.");
}

View file

@ -1,7 +1,7 @@
/* device.c - device manager */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2005,2007,2008 Free Software Foundation, Inc.
* Copyright (C) 2002,2005,2007,2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -41,18 +41,15 @@ grub_device_open (const char *name)
goto fail;
}
}
dev = grub_malloc (sizeof (*dev));
if (! dev)
goto fail;
/* Try to open a disk. */
disk = grub_disk_open (name);
if (! disk)
{
grub_error (GRUB_ERR_BAD_DEVICE, "unknown device");
goto fail;
}
goto fail;
dev->disk = disk;
dev->net = 0; /* FIXME */
@ -62,7 +59,7 @@ grub_device_open (const char *name)
fail:
if (disk)
grub_disk_close (disk);
grub_free (dev);
return 0;
@ -85,53 +82,77 @@ grub_device_iterate (int (*hook) (const char *name))
auto int iterate_disk (const char *disk_name);
auto int iterate_partition (grub_disk_t disk,
const grub_partition_t partition);
struct part_ent
{
struct part_ent *next;
char name[0];
} *ents;
int iterate_disk (const char *disk_name)
{
grub_device_t dev;
if (hook (disk_name))
return 1;
dev = grub_device_open (disk_name);
if (! dev)
return 0;
if (dev->disk && dev->disk->has_partitions)
if (grub_partition_iterate (dev->disk, iterate_partition))
{
grub_device_close (dev);
return 1;
}
{
struct part_ent *p;
int ret = 0;
ents = NULL;
(void) grub_partition_iterate (dev->disk, iterate_partition);
grub_device_close (dev);
grub_errno = GRUB_ERR_NONE;
p = ents;
while (p != NULL)
{
struct part_ent *next = p->next;
if (!ret)
ret = hook (p->name);
grub_free (p);
p = next;
}
return ret;
}
grub_device_close (dev);
return 0;
}
int iterate_partition (grub_disk_t disk, const grub_partition_t partition)
{
char *partition_name;
char *device_name;
int ret;
struct part_ent *p;
partition_name = grub_partition_get_name (partition);
if (! partition_name)
return 1;
device_name = grub_malloc (grub_strlen (disk->name) + 1
+ grub_strlen (partition_name) + 1);
if (! device_name)
p = grub_malloc (sizeof (p->next) + grub_strlen (disk->name) + 1 +
grub_strlen (partition_name) + 1);
if (!p)
{
grub_free (partition_name);
return 1;
}
grub_sprintf (device_name, "%s,%s", disk->name, partition_name);
grub_sprintf (p->name, "%s,%s", disk->name, partition_name);
grub_free (partition_name);
ret = hook (device_name);
grub_free (device_name);
return ret;
p->next = ents;
ents = p;
return 0;
}
/* Only disk devices are supported at the moment. */

View file

@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2003,2004,2006,2007,2008 Free Software Foundation, Inc.
* Copyright (C) 2002,2003,2004,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -22,19 +22,19 @@
#include <grub/types.h>
#include <grub/partition.h>
#include <grub/misc.h>
#include <grub/machine/time.h>
#include <grub/time.h>
#include <grub/file.h>
#define GRUB_CACHE_TIMEOUT 2
/* The last time the disk was used. */
static unsigned long grub_last_time = 0;
static grub_uint64_t grub_last_time = 0;
/* Disk cache. */
struct grub_disk_cache
{
unsigned long dev_id;
enum grub_disk_dev_id dev_id;
unsigned long disk_id;
grub_disk_addr_t sector;
char *data;
@ -46,6 +46,10 @@ static struct grub_disk_cache grub_disk_cache_table[GRUB_DISK_CACHE_NUM];
void (*grub_disk_firmware_fini) (void);
int grub_disk_firmware_is_tainted;
grub_err_t (* grub_disk_ata_pass_through) (grub_disk_t,
struct grub_disk_ata_pass_through_parms *);
#if 0
static unsigned long grub_disk_cache_hits;
static unsigned long grub_disk_cache_misses;
@ -128,7 +132,7 @@ grub_disk_cache_fetch (unsigned long dev_id, unsigned long disk_id,
#if 0
grub_disk_cache_misses++;
#endif
return 0;
}
@ -153,16 +157,19 @@ grub_disk_cache_store (unsigned long dev_id, unsigned long disk_id,
{
unsigned index;
struct grub_disk_cache *cache;
grub_disk_cache_invalidate (dev_id, disk_id, sector);
index = grub_disk_cache_get_index (dev_id, disk_id, sector);
cache = grub_disk_cache_table + index;
cache->lock = 1;
grub_free (cache->data);
cache->data = 0;
cache->lock = 0;
cache->data = grub_malloc (GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
if (! cache->data)
return grub_errno;
grub_memcpy (cache->data, data,
GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
cache->dev_id = dev_id;
@ -187,7 +194,7 @@ void
grub_disk_dev_unregister (grub_disk_dev_t dev)
{
grub_disk_dev_t *p, q;
for (p = &grub_disk_dev_list, q = *p; q; p = &(q->next), q = q->next)
if (q == dev)
{
@ -202,40 +209,54 @@ grub_disk_dev_iterate (int (*hook) (const char *name))
grub_disk_dev_t p;
for (p = grub_disk_dev_list; p; p = p->next)
if ((p->iterate) (hook))
if (p->iterate && (p->iterate) (hook))
return 1;
return 0;
}
/* Return the location of the first ',', if any, which is not
escaped by a '\'. */
static const char *
find_part_sep (const char *name)
{
const char *p = name;
char c;
while ((c = *p++) != '\0')
{
if (c == '\\' && *p == ',')
p++;
else if (c == ',')
return p - 1;
}
return NULL;
}
grub_disk_t
grub_disk_open (const char *name)
{
char *p;
const char *p;
grub_disk_t disk;
grub_disk_dev_t dev;
char *raw = (char *) name;
unsigned long current_time;
grub_uint64_t current_time;
grub_dprintf ("disk", "Opening `%s'...\n", name);
disk = (grub_disk_t) grub_malloc (sizeof (*disk));
disk = (grub_disk_t) grub_zalloc (sizeof (*disk));
if (! disk)
return 0;
disk->dev = 0;
disk->read_hook = 0;
disk->partition = 0;
disk->data = 0;
disk->name = grub_strdup (name);
if (! disk->name)
goto fail;
p = grub_strchr (name, ',');
p = find_part_sep (name);
if (p)
{
grub_size_t len = p - name;
raw = grub_malloc (len + 1);
if (! raw)
goto fail;
@ -265,7 +286,7 @@ grub_disk_open (const char *name)
grub_error (GRUB_ERR_BAD_DEVICE, "no partition on this disk");
goto fail;
}
disk->dev = dev;
if (p)
@ -280,16 +301,16 @@ grub_disk_open (const char *name)
/* The cache will be invalidated about 2 seconds after a device was
closed. */
current_time = grub_get_rtc ();
current_time = grub_get_time_ms ();
if (current_time > (grub_last_time
+ GRUB_CACHE_TIMEOUT * GRUB_TICKS_PER_SECOND))
+ GRUB_CACHE_TIMEOUT * 1000))
grub_disk_cache_invalidate_all ();
grub_last_time = current_time;
fail:
if (raw && raw != name)
grub_free (raw);
@ -315,20 +336,24 @@ grub_disk_close (grub_disk_t disk)
(disk->dev->close) (disk);
/* Reset the timer. */
grub_last_time = grub_get_rtc ();
grub_last_time = grub_get_time_ms ();
grub_free (disk->partition);
grub_free ((void *) disk->name);
grub_free (disk);
}
/* This function performs three tasks:
- Make sectors disk relative from partition relative.
- Normalize offset to be less than the sector size.
- Verify that the range is inside the partition. */
static grub_err_t
grub_disk_check_range (grub_disk_t disk, grub_disk_addr_t *sector,
grub_disk_adjust_range (grub_disk_t disk, grub_disk_addr_t *sector,
grub_off_t *offset, grub_size_t size)
{
*sector += *offset >> GRUB_DISK_SECTOR_BITS;
*offset &= GRUB_DISK_SECTOR_SIZE - 1;
if (disk->partition)
{
grub_disk_addr_t start;
@ -356,23 +381,23 @@ grub_disk_check_range (grub_disk_t disk, grub_disk_addr_t *sector,
/* Read data from the disk. */
grub_err_t
grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
grub_off_t offset, grub_size_t size, char *buf)
grub_off_t offset, grub_size_t size, void *buf)
{
char *tmp_buf;
unsigned real_offset;
/* First of all, check if the region is within the disk. */
if (grub_disk_check_range (disk, &sector, &offset, size) != GRUB_ERR_NONE)
if (grub_disk_adjust_range (disk, &sector, &offset, size) != GRUB_ERR_NONE)
{
grub_error_push ();
grub_dprintf ("disk", "Read out of range: sector 0x%llx.\n",
(unsigned long long) sector);
grub_dprintf ("disk", "Read out of range: sector 0x%llx (%s).\n",
(unsigned long long) sector, grub_errmsg);
grub_error_pop ();
return grub_errno;
}
real_offset = offset;
/* Allocate a temporary buffer. */
tmp_buf = grub_malloc (GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
if (! tmp_buf)
@ -405,8 +430,9 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
else
{
/* Otherwise read data from the disk actually. */
if ((disk->dev->read) (disk, start_sector,
GRUB_DISK_CACHE_SIZE, tmp_buf)
if (start_sector + GRUB_DISK_CACHE_SIZE > disk->total_sectors
|| (disk->dev->read) (disk, start_sector,
GRUB_DISK_CACHE_SIZE, tmp_buf)
!= GRUB_ERR_NONE)
{
/* Uggh... Failed. Instead, just read necessary data. */
@ -423,7 +449,7 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
goto finish;
tmp_buf = p;
if ((disk->dev->read) (disk, sector, num, tmp_buf))
{
grub_error_push ();
@ -462,62 +488,71 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
{
grub_disk_addr_t s = sector;
grub_size_t l = len;
while (l)
{
(disk->read_hook) (s, real_offset,
((l > GRUB_DISK_SECTOR_SIZE)
? GRUB_DISK_SECTOR_SIZE
: l));
if (l < GRUB_DISK_SECTOR_SIZE - real_offset)
break;
s++;
l -= GRUB_DISK_SECTOR_SIZE - real_offset;
real_offset = 0;
}
}
sector = start_sector + GRUB_DISK_CACHE_SIZE;
buf += len;
buf = (char *) buf + len;
size -= len;
real_offset = 0;
}
finish:
grub_free (tmp_buf);
return grub_errno;
}
grub_err_t
grub_disk_write (grub_disk_t disk, grub_disk_addr_t sector,
grub_off_t offset, grub_size_t size, const char *buf)
grub_off_t offset, grub_size_t size, const void *buf)
{
unsigned real_offset;
if (grub_disk_check_range (disk, &sector, &offset, size) != GRUB_ERR_NONE)
grub_dprintf ("disk", "Writing `%s'...\n", disk->name);
if (grub_disk_adjust_range (disk, &sector, &offset, size) != GRUB_ERR_NONE)
return -1;
real_offset = offset;
while (size)
{
if (real_offset != 0 || (size < GRUB_DISK_SECTOR_SIZE && size != 0))
{
char tmp_buf[GRUB_DISK_SECTOR_SIZE];
grub_size_t len;
grub_partition_t part;
part = disk->partition;
disk->partition = 0;
if (grub_disk_read (disk, sector, 0, GRUB_DISK_SECTOR_SIZE, tmp_buf)
!= GRUB_ERR_NONE)
goto finish;
{
disk->partition = part;
goto finish;
}
disk->partition = part;
len = GRUB_DISK_SECTOR_SIZE - real_offset;
if (len > size)
len = size;
grub_memcpy (tmp_buf + real_offset, buf, len);
grub_disk_cache_invalidate (disk->dev->id, disk->id, sector);
@ -526,7 +561,7 @@ grub_disk_write (grub_disk_t disk, grub_disk_addr_t sector,
goto finish;
sector++;
buf += len;
buf = (char *) buf + len;
size -= len;
real_offset = 0;
}
@ -537,14 +572,14 @@ grub_disk_write (grub_disk_t disk, grub_disk_addr_t sector,
len = size & ~(GRUB_DISK_SECTOR_SIZE - 1);
n = size >> GRUB_DISK_SECTOR_BITS;
if ((disk->dev->write) (disk, sector, n, buf) != GRUB_ERR_NONE)
goto finish;
while (n--)
grub_disk_cache_invalidate (disk->dev->id, disk->id, sector++);
buf += len;
buf = (char *) buf + len;
size -= len;
}
}
@ -554,7 +589,7 @@ grub_disk_write (grub_disk_t disk, grub_disk_addr_t sector,
return grub_errno;
}
grub_uint64_t
grub_uint64_t
grub_disk_get_size (grub_disk_t disk)
{
if (disk->partition)

153
kern/dl.c
View file

@ -1,7 +1,7 @@
/* dl.c - loadable module support */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2003,2004,2005,2007 Free Software Foundation, Inc.
* Copyright (C) 2002,2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -17,6 +17,9 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
/* Force native word size */
#define GRUB_TARGET_WORDSIZE (8 * GRUB_CPU_SIZEOF_VOID_P)
#include <config.h>
#include <grub/elf.h>
#include <grub/dl.h>
@ -29,28 +32,9 @@
#include <grub/env.h>
#include <grub/cache.h>
#if GRUB_CPU_SIZEOF_VOID_P == 4
typedef Elf32_Word Elf_Word;
typedef Elf32_Addr Elf_Addr;
typedef Elf32_Ehdr Elf_Ehdr;
typedef Elf32_Shdr Elf_Shdr;
typedef Elf32_Sym Elf_Sym;
# define ELF_ST_BIND(val) ELF32_ST_BIND (val)
# define ELF_ST_TYPE(val) ELF32_ST_TYPE (val)
#elif GRUB_CPU_SIZEOF_VOID_P == 8
typedef Elf64_Word Elf_Word;
typedef Elf64_Addr Elf_Addr;
typedef Elf64_Ehdr Elf_Ehdr;
typedef Elf64_Shdr Elf_Shdr;
typedef Elf64_Sym Elf_Sym;
# define ELF_ST_BIND(val) ELF64_ST_BIND (val)
# define ELF_ST_TYPE(val) ELF64_ST_TYPE (val)
/* Platforms where modules are in a readonly area of memory. */
#if defined(GRUB_MACHINE_QEMU)
#define GRUB_MODULES_MACHINE_READONLY
#endif
@ -72,7 +56,7 @@ grub_dl_add (grub_dl_t mod)
if (grub_dl_get (mod->name))
return grub_error (GRUB_ERR_BAD_MODULE,
"`%s' is already loaded", mod->name);
l = (grub_dl_list_t) grub_malloc (sizeof (*l));
if (! l)
return grub_errno;
@ -151,7 +135,7 @@ grub_symbol_hash (const char *s)
/* Resolve the symbol name NAME and return the address.
Return NULL, if not found. */
void *
static void *
grub_dl_resolve_symbol (const char *name)
{
grub_symbol_t sym;
@ -169,7 +153,7 @@ grub_dl_register_symbol (const char *name, void *addr, grub_dl_t mod)
{
grub_symbol_t sym;
unsigned k;
sym = (grub_symbol_t) grub_malloc (sizeof (*sym));
if (! sym)
return grub_errno;
@ -185,10 +169,10 @@ grub_dl_register_symbol (const char *name, void *addr, grub_dl_t mod)
}
else
sym->name = name;
sym->addr = addr;
sym->mod = mod;
k = grub_symbol_hash (name);
sym->next = grub_symtab[k];
grub_symtab[k] = sym;
@ -204,7 +188,7 @@ grub_dl_unregister_symbols (grub_dl_t mod)
if (! mod)
grub_fatal ("core symbols cannot be unregistered");
for (i = 0; i < GRUB_SYMTAB_SIZE; i++)
{
grub_symbol_t sym, *p, q;
@ -238,7 +222,7 @@ grub_dl_get_section_addr (grub_dl_t mod, unsigned n)
}
/* Check if EHDR is a valid ELF header. */
grub_err_t
static grub_err_t
grub_dl_check_header (void *ehdr, grub_size_t size)
{
Elf_Ehdr *e = ehdr;
@ -266,7 +250,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
{
unsigned i;
Elf_Shdr *s;
for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize))
@ -278,7 +262,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
seg = (grub_dl_segment_t) grub_malloc (sizeof (*seg));
if (! seg)
return grub_errno;
if (s->sh_size)
{
void *addr;
@ -323,7 +307,7 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
Elf_Sym *sym;
const char *str;
Elf_Word size, entsize;
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
@ -333,10 +317,16 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
if (i == e->e_shnum)
return grub_error (GRUB_ERR_BAD_MODULE, "no symbol table");
sym = (Elf_Sym *) ((char *) e + s->sh_offset);
#ifdef GRUB_MODULES_MACHINE_READONLY
mod->symtab = grub_malloc (s->sh_size);
memcpy (mod->symtab, (char *) e + s->sh_offset, s->sh_size);
#else
mod->symtab = (Elf_Sym *) ((char *) e + s->sh_offset);
#endif
sym = mod->symtab;
size = s->sh_size;
entsize = s->sh_entsize;
s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shentsize * s->sh_link);
str = (char *) e + s->sh_offset;
@ -347,7 +337,7 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
unsigned char type = ELF_ST_TYPE (sym->st_info);
unsigned char bind = ELF_ST_BIND (sym->st_info);
const char *name = str + sym->st_name;
switch (type)
{
case STT_NOTYPE:
@ -377,7 +367,7 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
if (bind != STB_LOCAL)
if (grub_dl_register_symbol (name, (void *) sym->st_value, mod))
return grub_errno;
if (grub_strcmp (name, "grub_mod_init") == 0)
mod->init = (void (*) (grub_dl_t)) sym->st_value;
else if (grub_strcmp (name, "grub_mod_fini") == 0)
@ -445,7 +435,7 @@ grub_dl_resolve_dependencies (grub_dl_t mod, Elf_Ehdr *e)
s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
str = (char *) e + s->sh_offset;
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
@ -454,25 +444,25 @@ grub_dl_resolve_dependencies (grub_dl_t mod, Elf_Ehdr *e)
const char *name = (char *) e + s->sh_offset;
const char *max = name + s->sh_size;
while (name < max)
while ((name < max) && (*name))
{
grub_dl_t m;
grub_dl_dep_t dep;
m = grub_dl_load (name);
if (! m)
return grub_errno;
grub_dl_ref (m);
dep = (grub_dl_dep_t) grub_malloc (sizeof (*dep));
if (! dep)
return grub_errno;
dep->mod = m;
dep->next = mod->dep;
mod->dep = dep;
name += grub_strlen (name) + 1;
}
}
@ -480,6 +470,7 @@ grub_dl_resolve_dependencies (grub_dl_t mod, Elf_Ehdr *e)
return GRUB_ERR_NONE;
}
#ifndef GRUB_UTIL
int
grub_dl_ref (grub_dl_t mod)
{
@ -487,7 +478,7 @@ grub_dl_ref (grub_dl_t mod)
for (dep = mod->dep; dep; dep = dep->next)
grub_dl_ref (dep->mod);
return ++mod->ref_count;
}
@ -498,9 +489,10 @@ grub_dl_unref (grub_dl_t mod)
for (dep = mod->dep; dep; dep = dep->next)
grub_dl_unref (dep->mod);
return --mod->ref_count;
}
#endif
static void
grub_dl_flush_cache (grub_dl_t mod)
@ -509,8 +501,8 @@ grub_dl_flush_cache (grub_dl_t mod)
for (seg = mod->segment; seg; seg = seg->next) {
if (seg->size) {
grub_dprintf ("modules", "flushing 0x%x bytes at %p\n", seg->size,
seg->addr);
grub_dprintf ("modules", "flushing 0x%lx bytes at %p\n",
(unsigned long) seg->size, seg->addr);
grub_arch_sync_caches (seg->addr, seg->size);
}
}
@ -523,7 +515,8 @@ grub_dl_load_core (void *addr, grub_size_t size)
Elf_Ehdr *e;
grub_dl_t mod;
grub_dprintf ("modules", "module at %p, size 0x%x\n", addr, size);
grub_dprintf ("modules", "module at %p, size 0x%lx\n", addr,
(unsigned long) size);
e = addr;
if (grub_dl_check_header (e, size))
return 0;
@ -541,16 +534,11 @@ grub_dl_load_core (void *addr, grub_size_t size)
return 0;
}
mod = (grub_dl_t) grub_malloc (sizeof (*mod));
mod = (grub_dl_t) grub_zalloc (sizeof (*mod));
if (! mod)
return 0;
mod->name = 0;
mod->ref_count = 1;
mod->dep = 0;
mod->segment = 0;
mod->init = 0;
mod->fini = 0;
grub_dprintf ("modules", "relocating to %p\n", mod);
if (grub_dl_resolve_name (mod, e)
@ -606,11 +594,11 @@ grub_init_module (const char *name,
grub_dl_t
grub_dl_load_file (const char *filename)
{
grub_file_t file;
grub_file_t file = NULL;
grub_ssize_t size;
void *core = 0;
grub_dl_t mod = 0;
file = grub_file_open (filename);
if (! file)
return 0;
@ -618,21 +606,31 @@ grub_dl_load_file (const char *filename)
size = grub_file_size (file);
core = grub_malloc (size);
if (! core)
goto failed;
{
grub_file_close (file);
return 0;
}
if (grub_file_read (file, core, size) != (int) size)
goto failed;
{
grub_file_close (file);
grub_free (core);
return 0;
}
/* We must close this before we try to process dependencies.
Some disk backends do not handle gracefully multiple concurrent
opens of the same device. */
grub_file_close (file);
mod = grub_dl_load_core (core, size);
if (! mod)
goto failed;
{
grub_free (core);
return 0;
}
mod->ref_count = 0;
failed:
grub_file_close (file);
grub_free (core);
return mod;
}
@ -647,7 +645,7 @@ grub_dl_load (const char *name)
mod = grub_dl_get (name);
if (mod)
return mod;
if (! grub_dl_dir) {
grub_error (GRUB_ERR_FILE_NOT_FOUND, "\"prefix\" is not set");
return 0;
@ -657,17 +655,17 @@ grub_dl_load (const char *name)
+ grub_strlen (name) + 4 + 1);
if (! filename)
return 0;
grub_sprintf (filename, "%s/%s.mod", grub_dl_dir, name);
mod = grub_dl_load_file (filename);
grub_free (filename);
if (! mod)
return 0;
if (grub_strcmp (mod->name, name) != 0)
grub_error (GRUB_ERR_BAD_MODULE, "mismatched names");
return mod;
}
@ -683,17 +681,17 @@ grub_dl_unload (grub_dl_t mod)
if (mod->fini)
(mod->fini) ();
grub_dl_remove (mod);
grub_dl_unregister_symbols (mod);
for (dep = mod->dep; dep; dep = depn)
{
depn = dep->next;
if (! grub_dl_unref (dep->mod))
grub_dl_unload (dep->mod);
grub_free (dep);
}
@ -703,8 +701,11 @@ grub_dl_unload (grub_dl_t mod)
grub_free (seg->addr);
grub_free (seg);
}
grub_free (mod->name);
#ifdef GRUB_MODULES_MACHINE_READONLY
grub_free (mod->symtab);
#endif
grub_free (mod);
return 1;
}
@ -716,7 +717,7 @@ grub_dl_unload_unneeded (void)
/* Because grub_dl_remove modifies the list of modules, this
implementation is tricky. */
grub_dl_list_t p = grub_dl_head;
while (p)
{
if (grub_dl_unload (p->mod))
@ -736,7 +737,7 @@ grub_dl_unload_all (void)
while (grub_dl_head)
{
grub_dl_list_t p;
grub_dl_unload_unneeded ();
/* Force to decrement the ref count. This will purge pre-loaded

View file

@ -1,7 +1,7 @@
/* efi.c - generic EFI support */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2006,2007 Free Software Foundation, Inc.
* Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -18,6 +18,7 @@
*/
#include <grub/misc.h>
#include <grub/charset.h>
#include <grub/efi/api.h>
#include <grub/efi/efi.h>
#include <grub/efi/console_control.h>
@ -42,13 +43,12 @@ grub_efi_locate_protocol (grub_efi_guid_t *protocol, void *registration)
{
void *interface;
grub_efi_status_t status;
status = grub_efi_system_table->boot_services->locate_protocol (protocol,
registration,
&interface);
status = efi_call_3 (grub_efi_system_table->boot_services->locate_protocol,
protocol, registration, &interface);
if (status != GRUB_EFI_SUCCESS)
return 0;
return interface;
}
@ -65,13 +65,13 @@ grub_efi_locate_handle (grub_efi_locate_search_type_t search_type,
grub_efi_status_t status;
grub_efi_handle_t *buffer;
grub_efi_uintn_t buffer_size = 8 * sizeof (grub_efi_handle_t);
buffer = grub_malloc (buffer_size);
if (! buffer)
return 0;
b = grub_efi_system_table->boot_services;
status = b->locate_handle (search_type, protocol, search_key,
status = efi_call_5 (b->locate_handle, search_type, protocol, search_key,
&buffer_size, buffer);
if (status == GRUB_EFI_BUFFER_TOO_SMALL)
{
@ -79,8 +79,8 @@ grub_efi_locate_handle (grub_efi_locate_search_type_t search_type,
buffer = grub_malloc (buffer_size);
if (! buffer)
return 0;
status = b->locate_handle (search_type, protocol, search_key,
status = efi_call_5 (b->locate_handle, search_type, protocol, search_key,
&buffer_size, buffer);
}
@ -102,14 +102,14 @@ grub_efi_open_protocol (grub_efi_handle_t handle,
grub_efi_boot_services_t *b;
grub_efi_status_t status;
void *interface;
b = grub_efi_system_table->boot_services;
status = b->open_protocol (handle,
protocol,
&interface,
grub_efi_image_handle,
0,
attributes);
status = efi_call_6 (b->open_protocol, handle,
protocol,
&interface,
grub_efi_image_handle,
0,
attributes);
if (status != GRUB_EFI_SUCCESS)
return 0;
@ -127,13 +127,13 @@ grub_efi_set_text_mode (int on)
/* No console control protocol instance available, assume it is
already in text mode. */
return 1;
if (c->get_mode (c, &mode, 0, 0) != GRUB_EFI_SUCCESS)
if (efi_call_4 (c->get_mode, c, &mode, 0, 0) != GRUB_EFI_SUCCESS)
return 0;
new_mode = on ? GRUB_EFI_SCREEN_TEXT : GRUB_EFI_SCREEN_GRAPHICS;
if (mode != new_mode)
if (c->set_mode (c, new_mode) != GRUB_EFI_SUCCESS)
if (efi_call_2 (c->set_mode, c, new_mode) != GRUB_EFI_SUCCESS)
return 0;
return 1;
@ -142,7 +142,7 @@ grub_efi_set_text_mode (int on)
void
grub_efi_stall (grub_efi_uintn_t microseconds)
{
grub_efi_system_table->boot_services->stall (microseconds);
efi_call_1 (grub_efi_system_table->boot_services->stall, microseconds);
}
grub_efi_loaded_image_t *
@ -157,9 +157,25 @@ void
grub_exit (void)
{
grub_efi_fini ();
grub_efi_system_table->boot_services->exit (grub_efi_image_handle,
GRUB_EFI_SUCCESS,
0, 0);
efi_call_4 (grub_efi_system_table->boot_services->exit,
grub_efi_image_handle, GRUB_EFI_SUCCESS, 0, 0);
for (;;) ;
}
void
grub_reboot (void)
{
grub_efi_fini ();
efi_call_4 (grub_efi_system_table->runtime_services->reset_system,
GRUB_EFI_RESET_COLD, GRUB_EFI_SUCCESS, 0, NULL);
}
void
grub_halt (void)
{
grub_efi_fini ();
efi_call_4 (grub_efi_system_table->runtime_services->reset_system,
GRUB_EFI_RESET_SHUTDOWN, GRUB_EFI_SUCCESS, 0, NULL);
}
int
@ -167,12 +183,31 @@ grub_efi_exit_boot_services (grub_efi_uintn_t map_key)
{
grub_efi_boot_services_t *b;
grub_efi_status_t status;
b = grub_efi_system_table->boot_services;
status = b->exit_boot_services (grub_efi_image_handle, map_key);
status = efi_call_2 (b->exit_boot_services, grub_efi_image_handle, map_key);
return status == GRUB_EFI_SUCCESS;
}
grub_err_t
grub_efi_set_virtual_address_map (grub_efi_uintn_t memory_map_size,
grub_efi_uintn_t descriptor_size,
grub_efi_uint32_t descriptor_version,
grub_efi_memory_descriptor_t *virtual_map)
{
grub_efi_runtime_services_t *r;
grub_efi_status_t status;
r = grub_efi_system_table->runtime_services;
status = efi_call_4 (r->set_virtual_address_map, memory_map_size,
descriptor_size, descriptor_version, virtual_map);
if (status == GRUB_EFI_SUCCESS)
return GRUB_ERR_NONE;
return grub_error (GRUB_ERR_IO, "set_virtual_address_map failed");
}
grub_uint32_t
grub_get_rtc (void)
{
@ -180,7 +215,7 @@ grub_get_rtc (void)
grub_efi_runtime_services_t *r;
r = grub_efi_system_table->runtime_services;
if (r->get_time (&time, 0) != GRUB_EFI_SUCCESS)
if (efi_call_2 (r->get_time, &time, 0) != GRUB_EFI_SUCCESS)
/* What is possible in this case? */
return 0;
@ -201,7 +236,7 @@ grub_arch_modules_addr (void)
struct grub_pe32_section_table *section;
struct grub_module_info *info;
grub_uint16_t i;
image = grub_efi_get_loaded_image (grub_efi_image_handle);
if (! image)
return 0;
@ -236,7 +271,7 @@ char *
grub_efi_get_filename (grub_efi_device_path_t *dp)
{
char *name = 0;
while (1)
{
grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp);
@ -260,7 +295,7 @@ grub_efi_get_filename (grub_efi_device_path_t *dp)
}
else
size = 0;
len = ((GRUB_EFI_DEVICE_PATH_LENGTH (dp) - 4)
/ sizeof (grub_efi_char16_t));
p = grub_realloc (name, size + len * 4 + 1);
@ -353,8 +388,8 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
grub_memcpy (&mmapped, dp, len);
grub_printf ("/MMap(%x,%llx,%llx)",
(unsigned) mmapped.memory_type,
mmapped.start_address,
mmapped.end_address);
(unsigned long long) mmapped.start_address,
(unsigned long long) mmapped.end_address);
}
break;
case GRUB_EFI_VENDOR_DEVICE_PATH_SUBTYPE:
@ -406,17 +441,17 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
grub_efi_expanded_acpi_device_path_t eacpi;
grub_memcpy (&eacpi, dp, sizeof (eacpi));
grub_printf ("/ACPI(");
if (GRUB_EFI_EXPANDED_ACPI_HIDSTR (dp)[0] == '\0')
grub_printf ("%x,", (unsigned) eacpi.hid);
else
grub_printf ("%s,", GRUB_EFI_EXPANDED_ACPI_HIDSTR (dp));
if (GRUB_EFI_EXPANDED_ACPI_UIDSTR (dp)[0] == '\0')
grub_printf ("%x,", (unsigned) eacpi.uid);
else
grub_printf ("%s,", GRUB_EFI_EXPANDED_ACPI_UIDSTR (dp));
if (GRUB_EFI_EXPANDED_ACPI_CIDSTR (dp)[0] == '\0')
grub_printf ("%x)", (unsigned) eacpi.cid);
else
@ -456,14 +491,15 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
grub_efi_fibre_channel_device_path_t fc;
grub_memcpy (&fc, dp, len);
grub_printf ("/FibreChannel(%llx,%llx)",
fc.wwn, fc.lun);
(unsigned long long) fc.wwn,
(unsigned long long) fc.lun);
}
break;
case GRUB_EFI_1394_DEVICE_PATH_SUBTYPE:
{
grub_efi_1394_device_path_t firewire;
grub_memcpy (&firewire, dp, len);
grub_printf ("/1394(%llx)", firewire.guid);
grub_printf ("/1394(%llx)", (unsigned long long) firewire.guid);
}
break;
case GRUB_EFI_USB_DEVICE_PATH_SUBTYPE:
@ -560,9 +596,9 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
grub_memcpy (&ib, dp, len);
grub_printf ("/InfiniBand(%x,%llx,%llx,%llx)",
(unsigned) ib.port_gid[0], /* XXX */
ib.remote_id,
ib.target_port_id,
ib.device_id);
(unsigned long long) ib.remote_id,
(unsigned long long) ib.target_port_id,
(unsigned long long) ib.device_id);
}
break;
case GRUB_EFI_UART_DEVICE_PATH_SUBTYPE:
@ -570,7 +606,7 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
grub_efi_uart_device_path_t uart;
grub_memcpy (&uart, dp, len);
grub_printf ("/UART(%llu,%u,%x,%x)",
uart.baud_rate,
(unsigned long long) uart.baud_rate,
uart.data_bits,
uart.parity,
uart.stop_bits);
@ -609,8 +645,8 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
grub_memcpy (&hd, dp, len);
grub_printf ("/HD(%u,%llx,%llx,%02x%02x%02x%02x%02x%02x%02x%02x,%x,%x)",
hd.partition_number,
hd.partition_start,
hd.partition_size,
(unsigned long long) hd.partition_start,
(unsigned long long) hd.partition_size,
(unsigned) hd.partition_signature[0],
(unsigned) hd.partition_signature[1],
(unsigned) hd.partition_signature[2],
@ -629,8 +665,8 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
grub_memcpy (&cd, dp, len);
grub_printf ("/CD(%u,%llx,%llx)",
cd.boot_entry,
cd.partition_start,
cd.partition_size);
(unsigned long long) cd.partition_start,
(unsigned long long) cd.partition_size);
}
break;
case GRUB_EFI_VENDOR_MEDIA_DEVICE_PATH_SUBTYPE:
@ -712,10 +748,33 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
return;
break;
}
if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
break;
dp = (grub_efi_device_path_t *) ((char *) dp + len);
}
}
int
grub_efi_finish_boot_services (void)
{
grub_efi_uintn_t mmap_size = 0;
grub_efi_uintn_t map_key;
grub_efi_uintn_t desc_size;
grub_efi_uint32_t desc_version;
void *mmap_buf = 0;
if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key,
&desc_size, &desc_version) < 0)
return 0;
mmap_buf = grub_malloc (mmap_size);
if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key,
&desc_size, &desc_version) <= 0)
return 0;
return grub_efi_exit_boot_services (map_key);
}

View file

@ -43,7 +43,7 @@ void
grub_efi_set_prefix (void)
{
grub_efi_loaded_image_t *image;
image = grub_efi_get_loaded_image (grub_efi_image_handle);
if (image)
{
@ -52,12 +52,12 @@ grub_efi_set_prefix (void)
device = grub_efidisk_get_device_name (image->device_handle);
file = grub_efi_get_filename (image->file_path);
if (device && file)
{
char *p;
char *prefix;
/* Get the directory. */
p = grub_strrchr (file, '/');
if (p)
@ -72,7 +72,7 @@ grub_efi_set_prefix (void)
grub_free (prefix);
}
}
grub_free (device);
grub_free (file);
}
@ -82,6 +82,5 @@ void
grub_efi_fini (void)
{
grub_efidisk_fini ();
grub_efi_mm_fini ();
grub_console_fini ();
}

View file

@ -1,7 +1,7 @@
/* mm.c - generic EFI memory management */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2006,2007 Free Software Foundation, Inc.
* Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -22,14 +22,16 @@
#include <grub/efi/api.h>
#include <grub/efi/efi.h>
//#define DEBUG_MM
#define NEXT_MEMORY_DESCRIPTOR(desc, size) \
((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size)))
#define BYTES_TO_PAGES(bytes) ((bytes + 0xfff) >> 12)
#define PAGES_TO_BYTES(pages) ((pages) << 12)
/* The size of a memory map obtained from the firmware. This must be
a multiplier of 4KB. */
#define MEMORY_MAP_SIZE 0x3000
/* Maintain the list of allocated pages. */
struct allocated_page
{
@ -45,7 +47,8 @@ static struct allocated_page *allocated_pages = 0;
/* The minimum and maximum heap size for GRUB itself. */
#define MIN_HEAP_SIZE 0x100000
#define MAX_HEAP_SIZE (16 * 0x100000)
#define MAX_HEAP_SIZE (1600 * 0x100000)
/* Allocate pages. Return the pointer to the first of allocated pages. */
void *
@ -56,11 +59,13 @@ grub_efi_allocate_boot_pages (grub_efi_physical_address_t address,
grub_efi_status_t status;
grub_efi_boot_services_t *b;
#if GRUB_CPU_SIZEOF_VOID_P < 8
#if GRUB_TARGET_SIZEOF_VOID_P < 8
/* Limit the memory access to less than 4GB for 32-bit platforms. */
if (address > 0xffffffff)
return 0;
#endif
#if GRUB_TARGET_SIZEOF_VOID_P < 8 || defined (MCMODEL_SMALL)
if (address == 0)
{
type = GRUB_EFI_ALLOCATE_MAX_ADDRESS;
@ -76,7 +81,7 @@ grub_efi_allocate_boot_pages (grub_efi_physical_address_t address,
#endif
b = grub_efi_system_table->boot_services;
status = b->allocate_pages (type, GRUB_EFI_LOADER_DATA, pages, &address);
status = efi_call_4 (b->allocate_pages, type, GRUB_EFI_LOADER_DATA, pages, &address);
if (status != GRUB_EFI_SUCCESS)
return 0;
@ -84,13 +89,13 @@ grub_efi_allocate_boot_pages (grub_efi_physical_address_t address,
{
/* Uggh, the address 0 was allocated... This is too annoying,
so reallocate another one. */
status = b->allocate_pages (type, GRUB_EFI_LOADER_DATA, pages, &address);
status = efi_call_4 (b->allocate_pages, type, GRUB_EFI_LOADER_DATA, pages, &address);
grub_efi_free_boot_pages (0, pages);
if (status != GRUB_EFI_SUCCESS)
return 0;
}
return (void *)address;
return (void *) address;
}
/* Free pages starting from ADDRESS. */
@ -111,7 +116,7 @@ grub_efi_allocate_pages (grub_efi_physical_address_t address,
{
address = grub_efi_allocate_boot_pages (address, pages);
if (address != 0 && allocated_pages)
if (address && allocated_pages)
{
unsigned i;
@ -126,7 +131,7 @@ grub_efi_allocate_pages (grub_efi_physical_address_t address,
if (i == MAX_ALLOCATED_PAGES)
grub_fatal ("too many page allocations");
}
return (void *) ((grub_addr_t) address);
}
@ -140,7 +145,7 @@ grub_efi_free_pages (grub_efi_physical_address_t address,
!= address))
{
unsigned i;
for (i = 0; i < MAX_ALLOCATED_PAGES; i++)
if (allocated_pages[i].addr == address)
{
@ -171,9 +176,9 @@ grub_efi_get_memory_map (grub_efi_uintn_t *memory_map_size,
map_key = &key;
if (! descriptor_version)
descriptor_version = &version;
b = grub_efi_system_table->boot_services;
status = b->get_memory_map (memory_map_size, memory_map, map_key,
status = efi_call_5 (b->get_memory_map, memory_map_size, memory_map, map_key,
descriptor_size, descriptor_version);
if (status == GRUB_EFI_SUCCESS)
return 1;
@ -191,13 +196,13 @@ sort_memory_map (grub_efi_memory_descriptor_t *memory_map,
{
grub_efi_memory_descriptor_t *d1;
grub_efi_memory_descriptor_t *d2;
for (d1 = memory_map;
d1 < memory_map_end;
d1 = NEXT_MEMORY_DESCRIPTOR (d1, desc_size))
{
grub_efi_memory_descriptor_t *max_desc = d1;
for (d2 = NEXT_MEMORY_DESCRIPTOR (d1, desc_size);
d2 < memory_map_end;
d2 = NEXT_MEMORY_DESCRIPTOR (d2, desc_size))
@ -232,14 +237,14 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map,
desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
{
if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY
#if GRUB_CPU_SIZEOF_VOID_P < 8
#if GRUB_TARGET_SIZEOF_VOID_P < 8 || defined (MCMODEL_SMALL)
&& desc->physical_start <= 0xffffffff
#endif
&& desc->physical_start + PAGES_TO_BYTES (desc->num_pages) > 0x100000
&& desc->num_pages != 0)
{
grub_memcpy (filtered_desc, desc, desc_size);
/* Avoid less than 1MB, because some loaders seem to be confused. */
if (desc->physical_start < 0x100000)
{
@ -247,8 +252,8 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map,
- desc->physical_start);
desc->physical_start = 0x100000;
}
#if GRUB_CPU_SIZEOF_VOID_P < 8
#if GRUB_TARGET_SIZEOF_VOID_P < 8 || defined (MCMODEL_SMALL)
if (BYTES_TO_PAGES (filtered_desc->physical_start)
+ filtered_desc->num_pages
> BYTES_TO_PAGES (0x100000000LL))
@ -256,10 +261,10 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map,
= (BYTES_TO_PAGES (0x100000000LL)
- BYTES_TO_PAGES (filtered_desc->physical_start));
#endif
if (filtered_desc->num_pages == 0)
continue;
filtered_desc = NEXT_MEMORY_DESCRIPTOR (filtered_desc, desc_size);
}
}
@ -275,7 +280,7 @@ get_total_pages (grub_efi_memory_descriptor_t *memory_map,
{
grub_efi_memory_descriptor_t *desc;
grub_efi_uint64_t total = 0;
for (desc = memory_map;
desc < memory_map_end;
desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
@ -343,7 +348,7 @@ print_memory_map (grub_efi_memory_descriptor_t *memory_map,
{
grub_efi_memory_descriptor_t *desc;
int i;
for (desc = memory_map, i = 0;
desc < memory_map_end;
desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size), i++)
@ -401,7 +406,7 @@ grub_efi_mm_init (void)
grub_fatal ("cannot get memory map");
memory_map_end = NEXT_MEMORY_DESCRIPTOR (memory_map, map_size);
filtered_memory_map_end = filter_memory_map (memory_map, filtered_memory_map,
desc_size, memory_map_end);
@ -434,7 +439,7 @@ grub_efi_mm_init (void)
NEXT_MEMORY_DESCRIPTOR (memory_map, map_size));
grub_abort ();
#endif
/* Release the memory maps. */
grub_efi_free_pages ((grub_addr_t) memory_map,
2 * BYTES_TO_PAGES (memory_map_size));

View file

@ -1,7 +1,7 @@
/* elf.c - load ELF files */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2003,2004,2005,2006,2007,2008 Free Software Foundation, Inc.
* Copyright (C) 2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -61,21 +61,20 @@ grub_elf_file (grub_file_t file)
{
grub_elf_t elf;
elf = grub_malloc (sizeof (*elf));
elf = grub_zalloc (sizeof (*elf));
if (! elf)
return 0;
elf->file = file;
elf->phdrs = 0;
if (grub_file_seek (elf->file, 0) == (grub_off_t) -1)
goto fail;
if (grub_file_read (elf->file, (char *) &elf->ehdr, sizeof (elf->ehdr))
if (grub_file_read (elf->file, &elf->ehdr, sizeof (elf->ehdr))
!= sizeof (elf->ehdr))
{
grub_error_push ();
grub_error (GRUB_ERR_READ_ERROR, "Cannot read ELF header.");
grub_error (GRUB_ERR_READ_ERROR, "cannot read ELF header");
goto fail;
}
@ -85,9 +84,8 @@ grub_elf_file (grub_file_t file)
return elf;
fail:
grub_error_push ();
grub_elf_close (elf);
grub_error_pop ();
grub_free (elf->phdrs);
grub_free (elf);
return 0;
}
@ -95,12 +93,17 @@ grub_elf_t
grub_elf_open (const char *name)
{
grub_file_t file;
grub_elf_t elf;
file = grub_gzfile_open (name, 1);
if (! file)
return 0;
return grub_elf_file (file);
elf = grub_elf_file (file);
if (! elf)
grub_file_close (file);
return elf;
}
@ -119,9 +122,9 @@ grub_elf32_load_phdrs (grub_elf_t elf)
phdrs_size = elf->ehdr.ehdr32.e_phnum * elf->ehdr.ehdr32.e_phentsize;
grub_dprintf ("elf", "Loading program headers at 0x%llx, size 0x%x.\n",
grub_dprintf ("elf", "Loading program headers at 0x%llx, size 0x%lx.\n",
(unsigned long long) elf->ehdr.ehdr32.e_phoff,
phdrs_size);
(unsigned long) phdrs_size);
elf->phdrs = grub_malloc (phdrs_size);
if (! elf->phdrs)
@ -131,7 +134,7 @@ grub_elf32_load_phdrs (grub_elf_t elf)
|| (grub_file_read (elf->file, elf->phdrs, phdrs_size) != phdrs_size))
{
grub_error_push ();
return grub_error (GRUB_ERR_READ_ERROR, "Cannot read program headers");
return grub_error (GRUB_ERR_READ_ERROR, "cannot read program headers");
}
return GRUB_ERR_NONE;
@ -177,8 +180,10 @@ grub_elf32_size (grub_elf_t elf)
/* Run through the program headers to calculate the total memory size we
* should claim. */
auto int calcsize (grub_elf_t _elf, Elf32_Phdr *phdr, void *_arg);
int calcsize (grub_elf_t UNUSED _elf, Elf32_Phdr *phdr, void UNUSED *_arg)
auto int NESTED_FUNC_ATTR calcsize (grub_elf_t _elf, Elf32_Phdr *phdr, void *_arg);
int NESTED_FUNC_ATTR calcsize (grub_elf_t _elf __attribute__ ((unused)),
Elf32_Phdr *phdr,
void *_arg __attribute__ ((unused)))
{
/* Only consider loadable segments. */
if (phdr->p_type != PT_LOAD)
@ -195,14 +200,14 @@ grub_elf32_size (grub_elf_t elf)
if (nr_phdrs == 0)
{
grub_error (GRUB_ERR_BAD_OS, "No program headers present");
grub_error (GRUB_ERR_BAD_OS, "no program headers present");
return 0;
}
if (segments_end < segments_start)
{
/* Very bad addresses. */
grub_error (GRUB_ERR_BAD_OS, "Bad program header load addresses");
grub_error (GRUB_ERR_BAD_OS, "bad program header load addresses");
return 0;
}
@ -224,14 +229,15 @@ grub_elf32_load (grub_elf_t _elf, grub_elf32_load_hook_t _load_hook,
{
grub_elf32_load_hook_t load_hook = (grub_elf32_load_hook_t) hook;
grub_addr_t load_addr;
if (phdr->p_type != PT_LOAD)
return 0;
int do_load = 1;
load_addr = phdr->p_paddr;
if (load_hook && load_hook (phdr, &load_addr))
if (load_hook && load_hook (phdr, &load_addr, &do_load))
return 1;
if (! do_load)
return 0;
if (load_addr < load_base)
load_base = load_addr;
@ -243,7 +249,7 @@ grub_elf32_load (grub_elf_t _elf, grub_elf32_load_hook_t _load_hook,
{
grub_error_push ();
return grub_error (GRUB_ERR_BAD_OS,
"Invalid offset in program header.");
"invalid offset in program header");
}
if (phdr->p_filesz)
@ -255,8 +261,8 @@ grub_elf32_load (grub_elf_t _elf, grub_elf32_load_hook_t _load_hook,
/* XXX How can we free memory from `load_hook'? */
grub_error_push ();
return grub_error (GRUB_ERR_BAD_OS,
"Couldn't read segment from file: "
"wanted 0x%lx bytes; read 0x%lx bytes.",
"couldn't read segment from file: "
"wanted 0x%lx bytes; read 0x%lx bytes",
phdr->p_filesz, read);
}
}
@ -297,9 +303,9 @@ grub_elf64_load_phdrs (grub_elf_t elf)
phdrs_size = elf->ehdr.ehdr64.e_phnum * elf->ehdr.ehdr64.e_phentsize;
grub_dprintf ("elf", "Loading program headers at 0x%llx, size 0x%x.\n",
grub_dprintf ("elf", "Loading program headers at 0x%llx, size 0x%lx.\n",
(unsigned long long) elf->ehdr.ehdr64.e_phoff,
phdrs_size);
(unsigned long) phdrs_size);
elf->phdrs = grub_malloc (phdrs_size);
if (! elf->phdrs)
@ -309,7 +315,7 @@ grub_elf64_load_phdrs (grub_elf_t elf)
|| (grub_file_read (elf->file, elf->phdrs, phdrs_size) != phdrs_size))
{
grub_error_push ();
return grub_error (GRUB_ERR_READ_ERROR, "Cannot read program headers");
return grub_error (GRUB_ERR_READ_ERROR, "cannot read program headers");
}
return GRUB_ERR_NONE;
@ -355,8 +361,10 @@ grub_elf64_size (grub_elf_t elf)
/* Run through the program headers to calculate the total memory size we
* should claim. */
auto int calcsize (grub_elf_t _elf, Elf64_Phdr *phdr, void *_arg);
int calcsize (grub_elf_t UNUSED _elf, Elf64_Phdr *phdr, void UNUSED *_arg)
auto int NESTED_FUNC_ATTR calcsize (grub_elf_t _elf, Elf64_Phdr *phdr, void *_arg);
int NESTED_FUNC_ATTR calcsize (grub_elf_t _elf __attribute__ ((unused)),
Elf64_Phdr *phdr,
void *_arg __attribute__ ((unused)))
{
/* Only consider loadable segments. */
if (phdr->p_type != PT_LOAD)
@ -373,14 +381,14 @@ grub_elf64_size (grub_elf_t elf)
if (nr_phdrs == 0)
{
grub_error (GRUB_ERR_BAD_OS, "No program headers present");
grub_error (GRUB_ERR_BAD_OS, "no program headers present");
return 0;
}
if (segments_end < segments_start)
{
/* Very bad addresses. */
grub_error (GRUB_ERR_BAD_OS, "Bad program header load addresses");
grub_error (GRUB_ERR_BAD_OS, "bad program header load addresses");
return 0;
}
@ -403,14 +411,15 @@ grub_elf64_load (grub_elf_t _elf, grub_elf64_load_hook_t _load_hook,
{
grub_elf64_load_hook_t load_hook = (grub_elf64_load_hook_t) hook;
grub_addr_t load_addr;
if (phdr->p_type != PT_LOAD)
return 0;
int do_load = 1;
load_addr = phdr->p_paddr;
if (load_hook && load_hook (phdr, &load_addr))
if (load_hook && load_hook (phdr, &load_addr, &do_load))
return 1;
if (! do_load)
return 0;
if (load_addr < load_base)
load_base = load_addr;
@ -422,7 +431,7 @@ grub_elf64_load (grub_elf_t _elf, grub_elf64_load_hook_t _load_hook,
{
grub_error_push ();
return grub_error (GRUB_ERR_BAD_OS,
"Invalid offset in program header.");
"invalid offset in program header");
}
if (phdr->p_filesz)
@ -434,8 +443,8 @@ grub_elf64_load (grub_elf_t _elf, grub_elf64_load_hook_t _load_hook,
/* XXX How can we free memory from `load_hook'? */
grub_error_push ();
return grub_error (GRUB_ERR_BAD_OS,
"Couldn't read segment from file: "
"wanted 0x%lx bytes; read 0x%lx bytes.",
"couldn't read segment from file: "
"wanted 0x%lx bytes; read 0x%lx bytes",
phdr->p_filesz, read);
}
}

View file

@ -1,7 +1,7 @@
/* env.c - Environment variables */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2003,2005,2006,2007,2008 Free Software Foundation, Inc.
* Copyright (C) 2003,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -29,7 +29,7 @@ struct grub_env_context
{
/* A hash table for variables. */
struct grub_env_var *vars[HASHSZ];
/* One level deeper on the stack. */
struct grub_env_context *prev;
};
@ -75,16 +75,15 @@ grub_env_find (const char *name)
}
grub_err_t
grub_env_context_open (void)
grub_env_context_open (int export)
{
struct grub_env_context *context;
int i;
context = grub_malloc (sizeof (*context));
context = grub_zalloc (sizeof (*context));
if (! context)
return grub_errno;
grub_memset (context, 0, sizeof (*context));
context->prev = current_context;
current_context = context;
@ -92,21 +91,22 @@ grub_env_context_open (void)
for (i = 0; i < HASHSZ; i++)
{
struct grub_env_var *var;
for (var = context->prev->vars[i]; var; var = var->next)
{
if (var->type == GRUB_ENV_VAR_GLOBAL)
if (export && var->type == GRUB_ENV_VAR_GLOBAL)
{
if (grub_env_set (var->name, var->value) != GRUB_ERR_NONE)
{
grub_env_context_close ();
return grub_errno;
}
grub_env_export (var->name);
grub_register_variable_hook (var->name, var->read_hook, var->write_hook);
}
}
}
return GRUB_ERR_NONE;
}
@ -118,15 +118,18 @@ grub_env_context_close (void)
if (! current_context->prev)
grub_fatal ("cannot close the initial context");
/* Free the variables associated with this context. */
for (i = 0; i < HASHSZ; i++)
{
struct grub_env_var *p, *q;
for (p = current_context->prev->vars[i]; p; p = q)
for (p = current_context->vars[i]; p; p = q)
{
q = p->next;
grub_free (p->name);
if (p->type != GRUB_ENV_VAR_DATA)
grub_free (p->value);
grub_free (p);
}
}
@ -146,10 +149,10 @@ grub_env_insert (struct grub_env_context *context,
int idx = grub_env_hashval (var->name);
/* Insert the variable into the hashtable. */
var->prevp = &context->vars[idx];;
var->prevp = &context->vars[idx];
var->next = context->vars[idx];
if (var->next)
var->next->prevp = &var;
var->next->prevp = &(var->next);
context->vars[idx] = var;
}
@ -168,8 +171,16 @@ grub_env_export (const char *name)
struct grub_env_var *var;
var = grub_env_find (name);
if (var)
var->type = GRUB_ENV_VAR_GLOBAL;
if (! var)
{
grub_err_t err;
err = grub_env_set (name, "");
if (err)
return err;
var = grub_env_find (name);
}
var->type = GRUB_ENV_VAR_GLOBAL;
return GRUB_ERR_NONE;
}
@ -189,7 +200,7 @@ grub_env_set (const char *name, const char *val)
var->value = var->write_hook (var, val);
else
var->value = grub_strdup (val);
if (! var->value)
{
var->value = old;
@ -201,20 +212,18 @@ grub_env_set (const char *name, const char *val)
}
/* The variable does not exist, so create a new one. */
var = grub_malloc (sizeof (*var));
var = grub_zalloc (sizeof (*var));
if (! var)
return grub_errno;
grub_memset (var, 0, sizeof (*var));
/* This is not necessary, because GRUB_ENV_VAR_LOCAL == 0. But leave
this for readability. */
var->type = GRUB_ENV_VAR_LOCAL;
var->name = grub_strdup (name);
if (! var->name)
goto fail;
var->value = grub_strdup (val);
if (! var->value)
goto fail;
@ -235,7 +244,7 @@ char *
grub_env_get (const char *name)
{
struct grub_env_var *var;
var = grub_env_find (name);
if (! var)
return 0;
@ -250,15 +259,16 @@ void
grub_env_unset (const char *name)
{
struct grub_env_var *var;
var = grub_env_find (name);
if (! var)
return;
/* XXX: It is not possible to unset variables with a read or write
hook. */
if (var->read_hook || var->write_hook)
return;
{
grub_env_set (name, "");
return;
}
grub_env_remove (var);
@ -274,12 +284,12 @@ grub_env_iterate (int (*func) (struct grub_env_var *var))
struct grub_env_sorted_var *sorted_list = 0;
struct grub_env_sorted_var *sorted_var;
int i;
/* Add variables associated with this context into a sorted list. */
for (i = 0; i < HASHSZ; i++)
{
struct grub_env_var *var;
for (var = current_context->vars[i]; var; var = var->next)
{
struct grub_env_sorted_var *p, **q;
@ -287,7 +297,7 @@ grub_env_iterate (int (*func) (struct grub_env_var *var))
/* Ignore data slots. */
if (var->type == GRUB_ENV_VAR_DATA)
continue;
sorted_var = grub_malloc (sizeof (*sorted_var));
if (! sorted_var)
goto fail;
@ -299,7 +309,7 @@ grub_env_iterate (int (*func) (struct grub_env_var *var))
if (grub_strcmp (p->var->name, var->name) > 0)
break;
}
sorted_var->next = *q;
*q = sorted_var;
}
@ -331,18 +341,13 @@ grub_register_variable_hook (const char *name,
if (! var)
{
char *val = grub_strdup ("");
if (grub_env_set (name, "") != GRUB_ERR_NONE)
return grub_errno;
if (! val)
return grub_errno;
if (grub_env_set (name, val) != GRUB_ERR_NONE)
return grub_errno;
var = grub_env_find (name);
/* XXX Insert an assertion? */
}
var->read_hook = read_hook;
var->write_hook = write_hook;
@ -357,7 +362,7 @@ mangle_data_slot_name (const char *name)
mangled_name = grub_malloc (grub_strlen (name) + 2);
if (! mangled_name)
return 0;
grub_sprintf (mangled_name, "\e%s", name);
return mangled_name;
}
@ -381,11 +386,9 @@ grub_env_set_data_slot (const char *name, const void *ptr)
}
/* The variable does not exist, so create a new one. */
var = grub_malloc (sizeof (*var));
var = grub_zalloc (sizeof (*var));
if (! var)
goto fail;
grub_memset (var, 0, sizeof (*var));
var->type = GRUB_ENV_VAR_DATA;
var->name = mangled_name;
@ -406,7 +409,7 @@ grub_env_get_data_slot (const char *name)
{
char *mangled_name;
void *ptr = 0;
mangled_name = mangle_data_slot_name (name);
if (! mangled_name)
goto fail;
@ -415,7 +418,7 @@ grub_env_get_data_slot (const char *name)
grub_free (mangled_name);
fail:
return ptr;
}
@ -423,7 +426,7 @@ void
grub_env_unset_data_slot (const char *name)
{
char *mangled_name;
mangled_name = mangle_data_slot_name (name);
if (! mangled_name)
return;

View file

@ -1,7 +1,7 @@
/* err.c - error handling routines */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2005,2007 Free Software Foundation, Inc.
* Copyright (C) 2002,2005,2007,2008 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -20,6 +20,7 @@
#include <grub/err.h>
#include <grub/misc.h>
#include <stdarg.h>
#include <grub/i18n.h>
#define GRUB_MAX_ERRMSG 256
#define GRUB_ERROR_STACK_SIZE 10
@ -40,11 +41,11 @@ grub_err_t
grub_error (grub_err_t n, const char *fmt, ...)
{
va_list ap;
grub_errno = n;
va_start (ap, fmt);
grub_vsprintf (grub_errmsg, fmt, ap);
grub_vsprintf (grub_errmsg, _(fmt), ap);
va_end (ap);
return n;
@ -56,7 +57,7 @@ grub_fatal (const char *fmt, ...)
va_list ap;
va_start (ap, fmt);
grub_vprintf (fmt, ap);
grub_vprintf (_(fmt), ap);
va_end (ap);
grub_abort ();
@ -73,7 +74,7 @@ grub_error_push (void)
grub_memcpy (grub_error_stack_items[grub_error_stack_pos].errmsg,
grub_errmsg,
sizeof (grub_errmsg));
/* Advance to next error stack position. */
grub_error_stack_pos++;
}
@ -96,19 +97,19 @@ grub_error_pop (void)
{
/* Pop error message from error stack to current active error. */
grub_error_stack_pos--;
grub_errno = grub_error_stack_items[grub_error_stack_pos].errno;
grub_memcpy (grub_errmsg,
grub_error_stack_items[grub_error_stack_pos].errmsg,
sizeof (grub_errmsg));
return 1;
}
else
{
/* There is no more items on error stack, reset to no error state. */
grub_errno = GRUB_ERR_NONE;
return 0;
}
}
@ -121,14 +122,14 @@ grub_print_error (void)
do
{
if (grub_errno != GRUB_ERR_NONE)
grub_printf ("error: %s\n", grub_errmsg);
}
grub_err_printf (_("error: %s.\n"), grub_errmsg);
}
while (grub_error_pop ());
/* If there was an assert while using error stack, report about it. */
if (grub_error_stack_assert)
{
grub_printf ("assert: error stack overflow detected!\n");
grub_err_printf ("assert: error stack overflow detected!\n");
grub_error_stack_assert = 0;
}
}

View file

@ -1,7 +1,7 @@
/* file.c - file I/O functions */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2006,2007 Free Software Foundation, Inc.
* Copyright (C) 2002,2006,2007,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -32,7 +32,7 @@ grub_file_get_device_name (const char *name)
{
char *p = grub_strchr (name, ')');
char *ret;
if (! p)
{
grub_error (GRUB_ERR_BAD_FILENAME, "missing `)'");
@ -42,7 +42,7 @@ grub_file_get_device_name (const char *name)
ret = (char *) grub_malloc (p - name);
if (! ret)
return 0;
grub_memcpy (ret, name + 1, p - name - 1);
ret[p - name - 1] = '\0';
return ret;
@ -74,16 +74,13 @@ grub_file_open (const char *name)
grub_free (device_name);
if (! device)
goto fail;
file = (grub_file_t) grub_malloc (sizeof (*file));
file = (grub_file_t) grub_zalloc (sizeof (*file));
if (! file)
goto fail;
file->device = device;
file->offset = 0;
file->data = 0;
file->read_hook = 0;
if (device->disk && file_name[0] != '/')
/* This is a block list. */
file->fs = &grub_fs_blocklist;
@ -106,25 +103,32 @@ grub_file_open (const char *name)
/* if (net) grub_net_close (net); */
grub_free (file);
return 0;
}
grub_ssize_t
grub_file_read (grub_file_t file, char *buf, grub_size_t len)
grub_file_read (grub_file_t file, void *buf, grub_size_t len)
{
grub_ssize_t res;
if (file->offset > file->size)
{
grub_error (GRUB_ERR_OUT_OF_RANGE,
"attempt to read past the end of file");
return -1;
}
if (len == 0 || len > file->size - file->offset)
len = file->size - file->offset;
/* Prevent an overflow. */
if ((grub_ssize_t) len < 0)
len >>= 1;
if (len == 0)
return 0;
res = (file->fs->read) (file, buf, len);
if (res > 0)
file->offset += res;
@ -155,7 +159,7 @@ grub_file_seek (grub_file_t file, grub_off_t offset)
"attempt to seek outside of the file");
return -1;
}
old = file->offset;
file->offset = offset;
return old;

View file

@ -65,10 +65,11 @@ grub_fs_t
grub_fs_probe (grub_device_t device)
{
grub_fs_t p;
auto int dummy_func (const char *filename, int dir);
auto int dummy_func (const char *filename,
const struct grub_dirhook_info *info);
int dummy_func (const char *filename __attribute__ ((unused)),
int dir __attribute__ ((unused)))
const struct grub_dirhook_info *info __attribute__ ((unused)))
{
return 1;
}
@ -99,24 +100,24 @@ grub_fs_probe (grub_device_t device)
if (grub_fs_autoload_hook && count == 0)
{
count++;
while (grub_fs_autoload_hook ())
{
p = grub_fs_list;
(p->dir) (device, "/", dummy_func);
if (grub_errno == GRUB_ERR_NONE)
{
count--;
return p;
}
if (grub_errno != GRUB_ERR_BAD_FS)
{
count--;
return 0;
}
grub_errno = GRUB_ERR_NONE;
}
@ -148,7 +149,7 @@ grub_fs_blocklist_open (grub_file_t file, const char *name)
unsigned i;
grub_disk_t disk = file->device->disk;
struct grub_fs_block *blocks;
/* First, count the number of blocks. */
do
{
@ -160,7 +161,7 @@ grub_fs_blocklist_open (grub_file_t file, const char *name)
while (p);
/* Allocate a block list. */
blocks = grub_malloc (sizeof (struct grub_fs_block) * (num + 1));
blocks = grub_zalloc (sizeof (struct grub_fs_block) * (num + 1));
if (! blocks)
return 0;
@ -178,8 +179,6 @@ grub_fs_blocklist_open (grub_file_t file, const char *name)
goto fail;
}
}
else
blocks[i].offset = 0;
p++;
blocks[i].length = grub_strtoul (p, &p, 0);
@ -197,14 +196,13 @@ grub_fs_blocklist_open (grub_file_t file, const char *name)
grub_error (GRUB_ERR_BAD_FILENAME, "beyond the total sectors");
goto fail;
}
file->size += (blocks[i].length << GRUB_DISK_SECTOR_BITS);
p++;
}
blocks[i].length = 0;
file->data = blocks;
return GRUB_ERR_NONE;
fail:
@ -235,11 +233,11 @@ grub_fs_blocklist_read (grub_file_t file, char *buf, grub_size_t len)
if (((size + offset + GRUB_DISK_SECTOR_SIZE - 1)
>> GRUB_DISK_SECTOR_BITS) > p->length - sector)
size = ((p->length - sector) << GRUB_DISK_SECTOR_BITS) - offset;
if (grub_disk_read (file->device->disk, p->offset + sector, offset,
size, buf) != GRUB_ERR_NONE)
return -1;
ret += size;
len -= size;
sector -= ((size + offset) >> GRUB_DISK_SECTOR_BITS);

39
kern/generic/millisleep.c Normal file
View file

@ -0,0 +1,39 @@
/* millisleep.c - generic millisleep function.
* The generic implementation of these functions can be used for architectures
* or platforms that do not have a more specialized implementation. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <grub/misc.h>
#include <grub/time.h>
void
grub_millisleep (grub_uint32_t ms)
{
grub_uint64_t start;
start = grub_get_time_ms ();
/* Instead of setting an end time and looping while the current time is
less than that, comparing the elapsed sleep time with the desired sleep
time handles the (unlikely!) case that the timer would wrap around
during the sleep. */
while (grub_get_time_ms () - start < ms)
grub_cpu_idle ();
}

View file

@ -0,0 +1,37 @@
/* rtc_get_time_ms.c - get_time_ms implementation using platform RTC.
* The generic implementation of these functions can be used for architectures
* or platforms that do not have a more specialized implementation. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2008 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <grub/time.h>
#include <grub/misc.h>
/* Calculate the time in milliseconds since the epoch based on the RTC. */
grub_uint64_t
grub_rtc_get_time_ms (void)
{
/* By dimensional analysis:
1000 ms N rtc ticks 1 s
------- * ----------- * ----------- = 1000*N/T ms
1 s 1 T rtc ticks
*/
grub_uint64_t ticks_ms_per_sec = ((grub_uint64_t) 1000) * grub_get_rtc ();
return grub_divmod64 (ticks_ms_per_sec, GRUB_TICKS_PER_SECOND, 0);
}

64
kern/handler.c Normal file
View file

@ -0,0 +1,64 @@
/* handler.c - grub handler function */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <grub/handler.h>
grub_handler_class_t grub_handler_class_list;
void
grub_handler_register (grub_handler_class_t class, grub_handler_t handler)
{
int first_handler = (class->handler_list == 0);
grub_list_push (GRUB_AS_LIST_P (&class->handler_list),
GRUB_AS_LIST (handler));
if (first_handler)
{
grub_list_push (GRUB_AS_LIST_P (&grub_handler_class_list),
GRUB_AS_LIST (class));
grub_handler_set_current (class, handler);
}
}
void
grub_handler_unregister (grub_handler_class_t class, grub_handler_t handler)
{
grub_list_remove (GRUB_AS_LIST_P (&class->handler_list),
GRUB_AS_LIST (handler));
if (class->handler_list == 0)
grub_list_remove (GRUB_AS_LIST_P (&grub_handler_class_list),
GRUB_AS_LIST (class));
}
grub_err_t
grub_handler_set_current (grub_handler_class_t class, grub_handler_t handler)
{
if (class->cur_handler && class->cur_handler->fini)
if ((class->cur_handler->fini) () != GRUB_ERR_NONE)
return grub_errno;
if (handler->init)
if ((handler->init) () != GRUB_ERR_NONE)
return grub_errno;
class->cur_handler = handler;
return GRUB_ERR_NONE;
}

View file

@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2003,2004,2005,2006,2007 Free Software Foundation, Inc.
* Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -33,6 +33,8 @@
#include <grub/time.h>
#include <grub/symbol.h>
#include <grub/cpu/io.h>
#include <grub/cpu/kernel.h>
#include <grub/cpu/tsc.h>
#define GRUB_FLOPPY_REG_DIGITAL_OUTPUT 0x3f2
@ -41,15 +43,11 @@ extern char _end[];
grub_addr_t grub_os_area_addr;
grub_size_t grub_os_area_size;
grub_size_t grub_lower_mem, grub_upper_mem;
/* FIXME: we need interrupts to do this right */
static grub_uint32_t grub_time_tics = 0;
grub_uint32_t
grub_get_rtc (void)
{
return grub_time_tics;
grub_fatal ("grub_get_rtc() is not implemented.\n");
}
/* Stop the floppy drive from spinning, so that other software is
@ -60,30 +58,13 @@ grub_stop_floppy (void)
grub_outb (0, GRUB_FLOPPY_REG_DIGITAL_OUTPUT);
}
void
grub_millisleep (grub_uint32_t ms __attribute__ ((unused)))
{
}
void
grub_exit (void)
{
grub_printf ("grub_exit() is not implemented.\n");
grub_stop ();
}
void
grub_reboot (void)
{
grub_printf ("grub_reboot() is not implemented.\n");
grub_stop ();
}
void
grub_halt (int no_apm __attribute__ ((unused)))
{
grub_printf ("grub_halt() is not implemented.\n");
grub_stop ();
/* We can't use grub_fatal() in this function. This would create an infinite
loop, since grub_fatal() calls grub_abort() which in turn calls grub_exit(). */
while (1)
grub_cpu_idle ();
}
void
@ -92,41 +73,24 @@ grub_arch_sync_caches (void *address __attribute__ ((unused)),
{
}
static char *
make_install_device (void)
{
return NULL;
}
void
grub_machine_init (void)
{
/* Initialize the console as early as possible. */
grub_console_init ();
grub_vga_text_init ();
grub_lower_mem = GRUB_MEMORY_MACHINE_LOWER_USABLE;
grub_upper_mem = 0;
auto int heap_init (mem_region_t);
int heap_init (mem_region_t mem_region)
auto int NESTED_FUNC_ATTR heap_init (grub_uint64_t, grub_uint64_t, grub_uint32_t);
int NESTED_FUNC_ATTR heap_init (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
{
grub_uint64_t addr = mem_region->addr;
grub_uint64_t size = mem_region->size;
#if GRUB_CPU_SIZEOF_VOID_P == 4
/* Restrict ourselves to 32-bit memory space. */
if (addr > ULONG_MAX)
{
grub_upper_mem = ULONG_MAX;
return 0;
}
if (addr + size > ULONG_MAX)
size = ULONG_MAX - addr;
if (addr > GRUB_ULONG_MAX)
return 0;
if (addr + size > GRUB_ULONG_MAX)
size = GRUB_ULONG_MAX - addr;
#endif
grub_upper_mem = grub_max (grub_upper_mem, addr + size);
if (mem_region->type != GRUB_LINUXBIOS_MEMORY_AVAILABLE)
if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
return 0;
/* Avoid the lower memory. */
@ -154,33 +118,38 @@ grub_machine_init (void)
quarter);
}
else
grub_mm_init_region ((void *) addr, (grub_size_t) size);
grub_mm_init_region ((void *) (grub_addr_t) addr, (grub_size_t) size);
return 0;
}
grub_available_iterate (heap_init);
grub_machine_mmap_init ();
grub_machine_mmap_iterate (heap_init);
/* This variable indicates size, not offset. */
grub_upper_mem -= GRUB_MEMORY_MACHINE_UPPER_START;
grub_tsc_init ();
}
void
grub_machine_set_prefix (void)
{
/* Initialize the prefix. */
grub_env_set ("prefix", make_install_device ());
grub_env_set ("prefix", grub_prefix);
}
void
grub_machine_fini (void)
{
grub_console_fini ();
grub_vga_text_fini ();
grub_stop_floppy ();
}
/* Return the end of the core image. */
grub_addr_t
grub_arch_modules_addr (void)
{
return ALIGN_UP(_end, GRUB_MOD_ALIGN);
#ifdef GRUB_MACHINE_QEMU
return grub_core_entry_addr + grub_kernel_image_size;
#else
return ALIGN_UP((grub_addr_t) _end, GRUB_MOD_ALIGN);
#endif
}

View file

@ -19,6 +19,7 @@
#include <grub/machine/memory.h>
#include <grub/types.h>
#include <grub/err.h>
#include <grub/misc.h>
static grub_err_t
grub_linuxbios_table_iterate (int (*hook) (grub_linuxbios_table_item_t))
@ -27,9 +28,9 @@ grub_linuxbios_table_iterate (int (*hook) (grub_linuxbios_table_item_t))
grub_linuxbios_table_item_t table_item;
auto int check_signature (grub_linuxbios_table_header_t);
int check_signature (grub_linuxbios_table_header_t table_header)
int check_signature (grub_linuxbios_table_header_t tbl_header)
{
if (! grub_memcmp (table_header->signature, "LBIO", 4))
if (! grub_memcmp (tbl_header->signature, "LBIO", 4))
return 1;
return 0;
@ -37,11 +38,13 @@ grub_linuxbios_table_iterate (int (*hook) (grub_linuxbios_table_item_t))
/* Assuming table_header is aligned to its size (8 bytes). */
for (table_header = 0x500; table_header < 0x1000; table_header++)
for (table_header = (grub_linuxbios_table_header_t) 0x500;
table_header < (grub_linuxbios_table_header_t) 0x1000; table_header++)
if (check_signature (table_header))
goto signature_found;
for (table_header = 0xf0000; table_header < 0x100000; table_header++)
for (table_header = (grub_linuxbios_table_header_t) 0xf0000;
table_header < (grub_linuxbios_table_header_t) 0x100000; table_header++)
if (check_signature (table_header))
goto signature_found;
@ -60,8 +63,8 @@ signature_found:
return 0;
}
grub_err_t
grub_available_iterate (int (*hook) (mem_region_t))
void
grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t))
{
mem_region_t mem_region;
@ -74,10 +77,16 @@ grub_available_iterate (int (*hook) (mem_region_t))
mem_region =
(mem_region_t) ((long) table_item +
sizeof (struct grub_linuxbios_table_item));
for (; (long) mem_region < (long) table_item + (long) table_item->size;
mem_region++)
if (hook (mem_region))
return 1;
while ((long) mem_region < (long) table_item + (long) table_item->size)
{
if (hook (mem_region->addr, mem_region->size,
/* Multiboot mmaps match with the coreboot mmap definition.
Therefore, we can just pass type through. */
mem_region->type))
return 1;
mem_region++;
}
return 0;
}

View file

@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007 Free Software Foundation, Inc.
* Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -16,11 +16,10 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#define ASM_FILE 1
#include <grub/symbol.h>
#include <grub/machine/memory.h>
#include <grub/cpu/linux.h>
#include <grub/cpu/kernel.h>
#include <multiboot.h>
#include <multiboot2.h>
@ -35,36 +34,49 @@
.file "startup.S"
.text
.globl start, _start
start:
_start:
jmp codestart
/*
* This is a special data area at a fixed offset from the beginning.
*/
. = _start + GRUB_KERNEL_CPU_PREFIX
VARIABLE(grub_prefix)
/* to be filled by grub-mkimage */
/*
* Leave some breathing room for the prefix.
*/
. = _start + GRUB_KERNEL_CPU_DATA_END
#if 0
/*
* Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself).
*/
.p2align 2 /* force 4-byte alignment */
multiboot_header:
/* magic */
.long 0x1BADB002
/* flags */
.long 0
.long MULTIBOOT_MEMORY_INFO
/* checksum */
.long -0x1BADB002
#endif
.long -0x1BADB002 - MULTIBOOT_MEMORY_INFO
codestart:
cmpl $MULTIBOOT_BOOTLOADER_MAGIC, %eax
jne 0f
movl %ebx, EXT_C(startup_multiboot_info)
0:
start:
_start:
/* initialize the stack */
movl $GRUB_MEMORY_MACHINE_PROT_STACK, %esp
/* jump to the main body of C code */
jmp EXT_C(grub_main)
/*
* This call is special... it never returns... in fact it should simply
* hang at this point!
*/
FUNCTION(grub_stop)
hlt
jmp EXT_C(grub_stop)
/*
* prot_to_real and associated structures (but NOT real_to_prot, that is
* only needed for BIOS gates).

View file

@ -1,7 +1,7 @@
/* dl-386.c - arch-dependent part of loadable module support */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2005,2007 Free Software Foundation, Inc.
* Copyright (C) 2002,2005,2007,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -26,7 +26,7 @@
grub_err_t
grub_arch_dl_check_header (void *ehdr)
{
Elf32_Ehdr *e = ehdr;
Elf_Ehdr *e = ehdr;
/* Check the magic numbers. */
if (e->e_ident[EI_CLASS] != ELFCLASS32
@ -41,28 +41,26 @@ grub_arch_dl_check_header (void *ehdr)
grub_err_t
grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
{
Elf32_Ehdr *e = ehdr;
Elf32_Shdr *s;
Elf32_Sym *symtab;
Elf32_Word entsize;
Elf_Ehdr *e = ehdr;
Elf_Shdr *s;
Elf_Word entsize;
unsigned i;
/* Find a symbol table. */
for (i = 0, s = (Elf32_Shdr *) ((char *) e + e->e_shoff);
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf32_Shdr *) ((char *) s + e->e_shentsize))
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
if (s->sh_type == SHT_SYMTAB)
break;
if (i == e->e_shnum)
return grub_error (GRUB_ERR_BAD_MODULE, "no symtab found");
symtab = (Elf32_Sym *) ((char *) e + s->sh_offset);
entsize = s->sh_entsize;
for (i = 0, s = (Elf32_Shdr *) ((char *) e + e->e_shoff);
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf32_Shdr *) ((char *) s + e->e_shentsize))
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
if (s->sh_type == SHT_REL)
{
grub_dl_segment_t seg;
@ -74,32 +72,32 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
if (seg)
{
Elf32_Rel *rel, *max;
for (rel = (Elf32_Rel *) ((char *) e + s->sh_offset),
Elf_Rel *rel, *max;
for (rel = (Elf_Rel *) ((char *) e + s->sh_offset),
max = rel + s->sh_size / s->sh_entsize;
rel < max;
rel++)
{
Elf32_Word *addr;
Elf32_Sym *sym;
Elf_Word *addr;
Elf_Sym *sym;
if (seg->size < rel->r_offset)
return grub_error (GRUB_ERR_BAD_MODULE,
"reloc offset is out of the segment");
addr = (Elf32_Word *) ((char *) seg->addr + rel->r_offset);
sym = (Elf32_Sym *) ((char *) symtab
+ entsize * ELF32_R_SYM (rel->r_info));
switch (ELF32_R_TYPE (rel->r_info))
addr = (Elf_Word *) ((char *) seg->addr + rel->r_offset);
sym = (Elf_Sym *) ((char *) mod->symtab
+ entsize * ELF_R_SYM (rel->r_info));
switch (ELF_R_TYPE (rel->r_info))
{
case R_386_32:
*addr += sym->st_value;
break;
case R_386_PC32:
*addr += (sym->st_value - (Elf32_Word) seg->addr
*addr += (sym->st_value - (Elf_Word) seg->addr
- rel->r_offset);
break;
}

View file

@ -25,18 +25,13 @@
#include <grub/cache.h>
#include <grub/kernel.h>
#include <grub/efi/efi.h>
#include <grub/time.h>
void
grub_millisleep (grub_uint32_t ms)
{
grub_millisleep_generic (ms);
}
#include <grub/i386/tsc.h>
void
grub_machine_init (void)
{
grub_efi_init ();
grub_tsc_init ();
}
void

View file

@ -34,14 +34,14 @@ _start:
* These MUST be at byte offset 6 and 7 of the executable
* DO NOT MOVE !!!
*/
. = EXT_C(start) + 0x6
. = _start + 0x6
.byte GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR
/*
* This is a special data area 8 bytes from the beginning.
*/
. = EXT_C(start) + 0x8
. = _start + 0x8
VARIABLE(grub_prefix)
/* to be filled by grub-mkimage */
@ -50,7 +50,7 @@ VARIABLE(grub_prefix)
* Leave some breathing room for the prefix.
*/
. = EXT_C(start) + 0x50
. = _start + 0x50
codestart:
/*

42
kern/i386/halt.c Normal file
View file

@ -0,0 +1,42 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2008 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <grub/cpu/io.h>
#include <grub/machine/init.h>
#include <grub/misc.h>
const char bochs_shutdown[] = "Shutdown";
void
grub_halt (void)
{
unsigned int i;
/* Disable interrupts. */
__asm__ __volatile__ ("cli");
/* Bochs, QEMU, etc. */
for (i = 0; i < sizeof (bochs_shutdown) - 1; i++)
grub_outb (bochs_shutdown[i], 0x8900);
grub_printf ("GRUB doesn't know how to halt this machine yet!\n");
/* In order to return we'd have to check what the previous status of IF
flag was. But user most likely doesn't want to return anyway ... */
grub_stop ();
}

View file

@ -18,13 +18,16 @@
*/
#include <grub/types.h>
#include <grub/cache.h>
void grub_stop_floppy (void);
void
grub_stop_floppy (void)
{
}
void
void
grub_arch_sync_caches (void *address __attribute__ ((unused)),
grub_size_t len __attribute__ ((unused)))
{

View file

@ -16,11 +16,10 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#define ASM_FILE 1
#include <grub/symbol.h>
#include <grub/machine/memory.h>
#include <grub/cpu/linux.h>
#include <grub/cpu/kernel.h>
#include <multiboot.h>
#include <multiboot2.h>
@ -38,16 +37,26 @@
start:
_start:
movl %eax, EXT_C(grub_ieee1275_entry_fn)
jmp EXT_C(cmain)
jmp codestart
/*
* This call is special... it never returns... in fact it should simply
* hang at this point!
*/
FUNCTION(grub_stop)
hlt
jmp EXT_C(grub_stop)
/*
* This is a special data area at a fixed offset from the beginning.
*/
. = _start + GRUB_KERNEL_CPU_PREFIX
VARIABLE(grub_prefix)
/* to be filled by grub-mkimage */
/*
* Leave some breathing room for the prefix.
*/
. = _start + GRUB_KERNEL_CPU_DATA_END
codestart:
movl %eax, EXT_C(grub_ieee1275_entry_fn)
jmp EXT_C(grub_main)
/*
* prot_to_real and associated structures (but NOT real_to_prot, that is

View file

@ -21,7 +21,7 @@
* Note: These functions defined in this file may be called from C.
* Be careful of that you must not modify some registers. Quote
* from gcc-2.95.2/gcc/config/i386/i386.h:
1 for registers not available across function calls.
These must include the FIXED_REGISTERS and also any
registers that can be used without being saved.
@ -46,7 +46,7 @@
*/
.p2align 2 /* force 4-byte alignment */
/*
* void grub_linux_boot_zimage (void)
*/
@ -58,8 +58,8 @@ VARIABLE(grub_linux_real_addr)
.long 0
VARIABLE(grub_linux_is_bzimage)
.long 0
FUNCTION(grub_linux_boot)
FUNCTION(grub_linux16_real_boot)
/* Must be done before zImage copy. */
call EXT_C(grub_dl_unload_all)
@ -118,47 +118,3 @@ linux_setup_seg:
.word 0
.code32
/*
* This starts the multiboot kernel.
*/
FUNCTION(grub_multiboot_real_boot)
/* Push the entry address on the stack. */
pushl %eax
/* Move the address of the multiboot information structure to ebx. */
movl %edx,%ebx
/* Unload all modules and stop the floppy driver. */
call EXT_C(grub_dl_unload_all)
call EXT_C(grub_stop_floppy)
/* Interrupts should be disabled. */
cli
/* Move the magic value into eax and jump to the kernel. */
movl $MULTIBOOT_MAGIC2,%eax
popl %ecx
jmp *%ecx
/*
* This starts the multiboot 2 kernel.
*/
FUNCTION(grub_multiboot2_real_boot)
/* Push the entry address on the stack. */
pushl %eax
/* Move the address of the multiboot information structure to ebx. */
movl %edx,%ebx
/* Unload all modules and stop the floppy driver. */
call EXT_C(grub_dl_unload_all)
call EXT_C(grub_stop_floppy)
/* Interrupts should be disabled. */
cli
/* Move the magic value into eax and jump to the kernel. */
movl $MULTIBOOT2_BOOTLOADER_MAGIC,%eax
popl %ecx
jmp *%ecx

29
kern/i386/misc.S Normal file
View file

@ -0,0 +1,29 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <grub/symbol.h>
.text
/*
* This call is special... it never returns... in fact it should simply
* hang at this point!
*/
FUNCTION(grub_stop)
cli
1: hlt
jmp 1b

View file

@ -0,0 +1,87 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <grub/machine/init.h>
#include <grub/machine/memory.h>
#include <grub/types.h>
#include <grub/multiboot.h>
#include <grub/err.h>
#include <grub/misc.h>
grub_size_t grub_lower_mem, grub_upper_mem;
/* A pointer to the MBI in its initial location. */
struct multiboot_info *startup_multiboot_info;
/* The MBI has to be copied to our BSS so that it won't be
overwritten. This is its final location. */
static struct multiboot_info kern_multiboot_info;
/* Unfortunately we can't use heap at this point. But 32 looks like a sane
limit (used by memtest86). */
static grub_uint8_t mmap_entries[sizeof (struct multiboot_mmap_entry) * 32];
void
grub_machine_mmap_init ()
{
if (! startup_multiboot_info)
grub_fatal ("Unable to find Multiboot Information (is CONFIG_MULTIBOOT disabled in coreboot?)");
/* Move MBI to a safe place. */
grub_memmove (&kern_multiboot_info, startup_multiboot_info, sizeof (struct multiboot_info));
if ((kern_multiboot_info.flags & MULTIBOOT_INFO_MEM_MAP) == 0)
grub_fatal ("Missing Multiboot memory information");
/* Move the memory map to a safe place. */
if (kern_multiboot_info.mmap_length > sizeof (mmap_entries))
{
grub_printf ("WARNING: Memory map size exceeds limit (0x%x > 0x%x); it will be truncated\n",
kern_multiboot_info.mmap_length, sizeof (mmap_entries));
kern_multiboot_info.mmap_length = sizeof (mmap_entries);
}
grub_memmove (mmap_entries, (void *) kern_multiboot_info.mmap_addr, kern_multiboot_info.mmap_length);
kern_multiboot_info.mmap_addr = (grub_uint32_t) mmap_entries;
if ((kern_multiboot_info.flags & MULTIBOOT_INFO_MEMORY) == 0)
{
grub_lower_mem = GRUB_MEMORY_MACHINE_LOWER_USABLE;
grub_upper_mem = 0;
}
else
{
grub_lower_mem = kern_multiboot_info.mem_lower * 1024;
grub_upper_mem = kern_multiboot_info.mem_upper * 1024;
}
}
grub_err_t
grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t))
{
struct multiboot_mmap_entry *entry = (void *) kern_multiboot_info.mmap_addr;
while ((unsigned long) entry < kern_multiboot_info.mmap_addr + kern_multiboot_info.mmap_length)
{
if (hook (entry->addr, entry->len, entry->type))
break;
entry = (void *) ((grub_addr_t) entry + entry->size + sizeof (entry->size));
}
return 0;
}

View file

@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2003,2004,2005,2006,2007,2008 Free Software Foundation, Inc.
* Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -30,6 +30,7 @@
#include <grub/env.h>
#include <grub/cache.h>
#include <grub/time.h>
#include <grub/cpu/tsc.h>
struct mem_region
{
@ -44,15 +45,8 @@ static int num_regions;
grub_addr_t grub_os_area_addr;
grub_size_t grub_os_area_size;
grub_size_t grub_lower_mem, grub_upper_mem;
void
grub_millisleep (grub_uint32_t ms)
{
grub_millisleep_generic (ms);
}
void
grub_arch_sync_caches (void *address __attribute__ ((unused)),
grub_size_t len __attribute__ ((unused)))
{
@ -64,27 +58,23 @@ make_install_device (void)
/* XXX: This should be enough. */
char dev[100];
if (grub_memdisk_image_size)
if (grub_prefix[0] != '(')
{
grub_sprintf (dev, "(memdisk)%s", grub_prefix);
grub_strcpy (grub_prefix, dev);
}
else if (grub_install_dos_part != -2)
{
grub_sprintf (dev, "(%cd%u",
(grub_boot_drive & 0x80) ? 'h' : 'f',
/* No hardcoded root partition - make it from the boot drive and the
partition number encoded at the install time. */
grub_sprintf (dev, "(%cd%u", (grub_boot_drive & 0x80) ? 'h' : 'f',
grub_boot_drive & 0x7f);
if (grub_install_dos_part >= 0)
grub_sprintf (dev + grub_strlen (dev), ",%u", grub_install_dos_part + 1);
if (grub_install_bsd_part >= 0)
grub_sprintf (dev + grub_strlen (dev), ",%c", grub_install_bsd_part + 'a');
grub_sprintf (dev + grub_strlen (dev), ")%s", grub_prefix);
grub_strcpy (grub_prefix, dev);
}
return grub_prefix;
}
@ -122,7 +112,7 @@ compact_mem_regions (void)
if (mem_regions[i].addr + mem_regions[i].size >= mem_regions[i + 1].addr)
{
j = i + 1;
if (mem_regions[i].addr + mem_regions[i].size
< mem_regions[j].addr + mem_regions[j].size)
mem_regions[i].size = (mem_regions[j].addr + mem_regions[j].size
@ -138,16 +128,14 @@ compact_mem_regions (void)
void
grub_machine_init (void)
{
grub_uint32_t cont;
struct grub_machine_mmap_entry *entry
= (struct grub_machine_mmap_entry *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
int i;
int grub_lower_mem;
/* Initialize the console as early as possible. */
grub_console_init ();
grub_lower_mem = grub_get_memsize (0) << 10;
/* Sanity check. */
if (grub_lower_mem < GRUB_MEMORY_MACHINE_RESERVED_END)
grub_fatal ("too small memory");
@ -157,60 +145,45 @@ grub_machine_init (void)
grub_gate_a20 (1);
#endif
/* FIXME: This prevents loader/i386/linux.c from using low memory. When our
heap implements support for requesting a chunk in low memory, this should
no longer be a problem. */
#if 0
/* Add the lower memory into free memory. */
if (grub_lower_mem >= GRUB_MEMORY_MACHINE_RESERVED_END)
add_mem_region (GRUB_MEMORY_MACHINE_RESERVED_END,
grub_lower_mem - GRUB_MEMORY_MACHINE_RESERVED_END);
/* Check if grub_get_mmap_entry works. */
cont = grub_get_mmap_entry (entry, 0);
#endif
if (entry->size)
do
{
/* Avoid the lower memory. */
if (entry->addr < 0x100000)
{
if (entry->len <= 0x100000 - entry->addr)
goto next;
entry->len -= 0x100000 - entry->addr;
entry->addr = 0x100000;
}
/* Ignore >4GB. */
if (entry->addr <= 0xFFFFFFFF && entry->type == 1)
{
grub_addr_t addr;
grub_size_t len;
addr = (grub_addr_t) entry->addr;
len = ((addr + entry->len > 0xFFFFFFFF)
? 0xFFFFFFFF - addr
: (grub_size_t) entry->len);
add_mem_region (addr, len);
}
next:
if (! cont)
break;
cont = grub_get_mmap_entry (entry, cont);
}
while (entry->size);
else
auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
{
grub_uint32_t eisa_mmap = grub_get_eisa_mmap ();
if (eisa_mmap)
/* Avoid the lower memory. */
if (addr < 0x100000)
{
add_mem_region (0x100000, (eisa_mmap & 0xFFFF) << 10);
add_mem_region (0x1000000, eisa_mmap & ~0xFFFF);
if (size <= 0x100000 - addr)
return 0;
size -= 0x100000 - addr;
addr = 0x100000;
}
else
add_mem_region (0x100000, grub_get_memsize (1) << 10);
/* Ignore >4GB. */
if (addr <= 0xFFFFFFFF && type == GRUB_MACHINE_MEMORY_AVAILABLE)
{
grub_size_t len;
len = (grub_size_t) ((addr + size > 0xFFFFFFFF)
? 0xFFFFFFFF - addr
: size);
add_mem_region (addr, len);
}
return 0;
}
grub_machine_mmap_iterate (hook);
compact_mem_regions ();
/* Add the memory regions to free memory, except for the region starting
@ -221,7 +194,6 @@ grub_machine_init (void)
{
grub_size_t quarter = mem_regions[i].size >> 2;
grub_upper_mem = mem_regions[i].size;
grub_os_area_addr = mem_regions[i].addr;
grub_os_area_size = mem_regions[i].size - quarter;
grub_mm_init_region ((void *) (grub_os_area_addr + grub_os_area_size),
@ -229,9 +201,11 @@ grub_machine_init (void)
}
else
grub_mm_init_region ((void *) mem_regions[i].addr, mem_regions[i].size);
if (! grub_os_area_addr)
grub_fatal ("no upper memory");
grub_tsc_init ();
}
void
@ -245,27 +219,13 @@ void
grub_machine_fini (void)
{
grub_console_fini ();
grub_stop_floppy ();
}
/* Return the end of the core image. */
grub_addr_t
grub_arch_modules_addr (void)
{
return grub_end_addr;
}
/* Return the start of the memdisk image. */
grub_addr_t
grub_arch_memdisk_addr (void)
{
return GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR
+ (grub_kernel_image_size - GRUB_KERNEL_MACHINE_RAW_SIZE)
+ grub_total_module_size;
}
/* Return the size of the memdisk image. */
grub_off_t
grub_arch_memdisk_size (void)
{
return grub_memdisk_image_size;
+ (grub_kernel_image_size - GRUB_KERNEL_MACHINE_RAW_SIZE);
}

677
kern/i386/pc/lzma_decode.S Normal file
View file

@ -0,0 +1,677 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2008 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#define FIXED_PROPS
#define LZMA_BASE_SIZE 1846
#define LZMA_LIT_SIZE 768
#define LZMA_PROPERTIES_SIZE 5
#define kNumTopBits 24
#define kTopValue (1 << kNumTopBits)
#define kNumBitModelTotalBits 11
#define kBitModelTotal (1 << kNumBitModelTotalBits)
#define kNumMoveBits 5
#define kNumPosBitsMax 4
#define kNumPosStatesMax (1 << kNumPosBitsMax)
#define kLenNumLowBits 3
#define kLenNumLowSymbols (1 << kLenNumLowBits)
#define kLenNumMidBits 3
#define kLenNumMidSymbols (1 << kLenNumMidBits)
#define kLenNumHighBits 8
#define kLenNumHighSymbols (1 << kLenNumHighBits)
#define LenChoice 0
#define LenChoice2 (LenChoice + 1)
#define LenLow (LenChoice2 + 1)
#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
#define kNumStates 12
#define kNumLitStates 7
#define kStartPosModelIndex 4
#define kEndPosModelIndex 14
#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
#define kNumPosSlotBits 6
#define kNumLenToPosStates 4
#define kNumAlignBits 4
#define kAlignTableSize (1 << kNumAlignBits)
#define kMatchMinLen 2
#define IsMatch 0
#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
#define IsRepG0 (IsRep + kNumStates)
#define IsRepG1 (IsRepG0 + kNumStates)
#define IsRepG2 (IsRepG1 + kNumStates)
#define IsRep0Long (IsRepG2 + kNumStates)
#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
#define LenCoder (Align + kAlignTableSize)
#define RepLenCoder (LenCoder + kNumLenProbs)
#define Literal (RepLenCoder + kNumLenProbs)
#if 0
DbgOut:
pushf
pushl %ebp
pushl %edi
pushl %esi
pushl %edx
pushl %ecx
pushl %ebx
pushl %eax
call _DebugPrint
popl %eax
popl %ebx
popl %ecx
popl %edx
popl %esi
popl %edi
popl %ebp
popf
ret
/*
* int LzmaDecodeProperties(CLzmaProperties *propsRes,
* const unsigned char *propsData,
* int size);
*/
_LzmaDecodePropertiesA:
movb (%edx), %dl
xorl %ecx, %ecx
1:
cmpb $45, %dl
jb 2f
incl %ecx
subb $45, %dl
jmp 1b
2:
movl %ecx, 8(%eax) /* pb */
xorl %ecx, %ecx
1:
cmpb $9, %dl
jb 2f
incl %ecx
subb $9, %dl
2:
movl %ecx, 4(%eax) /* lp */
movb %dl, %cl
movl %ecx, (%eax) /* lc */
#endif
#ifndef ASM_FILE
xorl %eax, %eax
#endif
ret
#define out_size 8(%ebp)
#define now_pos -4(%ebp)
#define prev_byte -8(%ebp)
#define range -12(%ebp)
#define code -16(%ebp)
#define state -20(%ebp)
#define rep0 -24(%ebp)
#define rep1 -28(%ebp)
#define rep2 -32(%ebp)
#define rep3 -36(%ebp)
#ifdef FIXED_PROPS
#define FIXED_LC 3
#define FIXED_LP 0
#define FIXED_PB 2
#define POS_STATE_MASK ((1 << (FIXED_PB)) - 1)
#define LIT_POS_MASK ((1 << (FIXED_LP)) - 1)
#define LOCAL_SIZE 36
#else
#define lc (%ebx)
#define lp 4(%ebx)
#define pb 8(%ebx)
#define probs 12(%ebx)
#define pos_state_mask -40(%ebp)
#define lit_pos_mask -44(%ebp)
#define LOCAL_SIZE 44
#endif
RangeDecoderBitDecode:
#ifdef FIXED_PROPS
leal (%ebx, %eax, 4), %eax
#else
shll $2, %eax
addl probs, %eax
#endif
movl %eax, %ecx
movl (%ecx), %eax
movl range, %edx
shrl $kNumBitModelTotalBits, %edx
mull %edx
cmpl code, %eax
jbe 1f
movl %eax, range
movl $kBitModelTotal, %edx
subl (%ecx), %edx
shrl $kNumMoveBits, %edx
addl %edx, (%ecx)
clc
3:
pushf
cmpl $kTopValue, range
jnc 2f
shll $8, code
lodsb
movb %al, code
shll $8, range
2:
popf
ret
1:
subl %eax, range
subl %eax, code
movl (%ecx), %edx
shrl $kNumMoveBits, %edx
subl %edx, (%ecx)
stc
jmp 3b
RangeDecoderBitTreeDecode:
RangeDecoderReverseBitTreeDecode:
movzbl %cl, %ecx
xorl %edx, %edx
pushl %edx
incl %edx
pushl %edx
1:
pushl %eax
pushl %ecx
pushl %edx
addl %edx, %eax
call RangeDecoderBitDecode
popl %edx
popl %ecx
jnc 2f
movl 4(%esp), %eax
orl %eax, 8(%esp)
stc
2:
adcl %edx, %edx
popl %eax
shll $1, (%esp)
loop 1b
popl %ecx
subl %ecx, %edx /* RangeDecoderBitTreeDecode */
popl %ecx /* RangeDecoderReverseBitTreeDecode */
ret
LzmaLenDecode:
pushl %eax
addl $LenChoice, %eax
call RangeDecoderBitDecode
popl %eax
jc 1f
pushl $0
movb $kLenNumLowBits, %cl
addl $LenLow, %eax
2:
movl 12(%esp), %edx
shll %cl, %edx
addl %edx, %eax
3:
call RangeDecoderBitTreeDecode
popl %eax
addl %eax, %edx
ret
1:
pushl %eax
addl $LenChoice2, %eax
call RangeDecoderBitDecode
popl %eax
jc 1f
pushl $kLenNumLowSymbols
movb $kLenNumMidBits, %cl
addl $LenMid, %eax
jmp 2b
1:
pushl $(kLenNumLowSymbols + kLenNumMidSymbols)
addl $LenHigh, %eax
movb $kLenNumHighBits, %cl
jmp 3b
WriteByte:
movb %al, prev_byte
stosb
incl now_pos
ret
/*
* int LzmaDecode(CLzmaDecoderState *vs,
* const unsigned char *inStream,
* unsigned char *outStream,
* SizeT outSize);
*/
_LzmaDecodeA:
pushl %ebp
movl %esp, %ebp
subl $LOCAL_SIZE, %esp
#ifndef ASM_FILE
pushl %esi
pushl %edi
pushl %ebx
movl %eax, %ebx
movl %edx, %esi
pushl %ecx
#else
pushl %edi
#endif
cld
#ifdef FIXED_PROPS
movl %ebx, %edi
movl $(Literal + (LZMA_LIT_SIZE << (FIXED_LC + FIXED_LP))), %ecx
#else
movl $LZMA_LIT_SIZE, %eax
movb lc, %cl
addb lp, %cl
shll %cl, %eax
addl $Literal, %eax
movl %eax, %ecx
movl probs, %edi
#endif
movl $(kBitModelTotal >> 1), %eax
rep
stosl
popl %edi
xorl %eax, %eax
movl %eax, now_pos
movl %eax, prev_byte
movl %eax, state
incl %eax
movl %eax, rep0
movl %eax, rep1
movl %eax, rep2
movl %eax, rep3
#ifndef FIXED_PROPS
movl %eax, %edx
movb pb, %cl
shll %cl, %edx
decl %edx
movl %edx, pos_state_mask
movl %eax, %edx
movb lp, %cl
shll %cl, %edx
decl %edx
movl %edx, lit_pos_mask;
#endif
/* RangeDecoderInit */
negl %eax
movl %eax, range
incl %eax
movb $5, %cl
1:
shll $8, %eax
lodsb
loop 1b
movl %eax, code
lzma_decode_loop:
movl now_pos, %eax
cmpl out_size, %eax
jb 1f
#ifndef ASM_FILE
xorl %eax, %eax
popl %ebx
popl %edi
popl %esi
#endif
movl %ebp, %esp
popl %ebp
ret
1:
#ifdef FIXED_PROPS
andl $POS_STATE_MASK, %eax
#else
andl pos_state_mask, %eax
#endif
pushl %eax /* posState */
movl state, %edx
shll $kNumPosBitsMax, %edx
addl %edx, %eax
pushl %eax /* (state << kNumPosBitsMax) + posState */
call RangeDecoderBitDecode
jc 1f
movl now_pos, %eax
#ifdef FIXED_PROPS
andl $LIT_POS_MASK, %eax
shll $FIXED_LC, %eax
movl prev_byte, %edx
shrl $(8 - FIXED_LC), %edx
#else
andl lit_pos_mask, %eax
movb lc, %cl
shll %cl, %eax
negb %cl
addb $8, %cl
movl prev_byte, %edx
shrl %cl, %edx
#endif
addl %edx, %eax
movl $LZMA_LIT_SIZE, %edx
mull %edx
addl $Literal, %eax
pushl %eax
incl %edx /* edx = 1 */
movl rep0, %eax
negl %eax
pushl (%edi, %eax) /* matchByte */
cmpb $kNumLitStates, state
jb 5f
/* LzmaLiteralDecodeMatch */
3:
cmpl $0x100, %edx
jae 4f
xorl %eax, %eax
shlb $1, (%esp)
adcl %eax, %eax
pushl %eax
pushl %edx
shll $8, %eax
leal 0x100(%edx, %eax), %eax
addl 12(%esp), %eax
call RangeDecoderBitDecode
setc %al
popl %edx
adcl %edx, %edx
popl %ecx
cmpb %cl, %al
jz 3b
5:
/* LzmaLiteralDecode */
cmpl $0x100, %edx
jae 4f
pushl %edx
movl %edx, %eax
addl 8(%esp), %eax
call RangeDecoderBitDecode
popl %edx
adcl %edx, %edx
jmp 5b
4:
addl $16, %esp
movb %dl, %al
call WriteByte
movb state, %al
cmpb $4, %al
jae 2f
xorb %al, %al
jmp 3f
2:
subb $3, %al
cmpb $7, %al
jb 3f
subb $3, %al
3:
movb %al, state
jmp lzma_decode_loop
1:
movl state, %eax
addl $IsRep, %eax
call RangeDecoderBitDecode
jnc 1f
movl state, %eax
addl $IsRepG0, %eax
call RangeDecoderBitDecode
jc 10f
movl (%esp), %eax
addl $IsRep0Long, %eax
call RangeDecoderBitDecode
jc 20f
cmpb $7, state
movb $9, state
jb 100f
addb $2, state
100:
movl $1, %ecx
3:
movl rep0, %edx
negl %edx
4:
movb (%edi, %edx), %al
call WriteByte
loop 4b
popl %eax
popl %eax
jmp lzma_decode_loop
10:
movl state, %eax
addl $IsRepG1, %eax
call RangeDecoderBitDecode
movl rep1, %edx
jnc 100f
movl state, %eax
addl $IsRepG2, %eax
call RangeDecoderBitDecode
movl rep2, %edx
jnc 1000f
movl rep2, %edx
xchgl rep3, %edx
1000:
pushl rep1
popl rep2
100:
xchg rep0, %edx
movl %edx, rep1
20:
movl $RepLenCoder, %eax
call LzmaLenDecode
cmpb $7, state
movb $8, state
jb 100f
addb $3, state
100:
jmp 2f
1:
movl rep0, %eax
xchgl rep1, %eax
xchgl rep2, %eax
movl %eax, rep3
cmpb $7, state
movb $7, state
jb 10f
addb $3, state
10:
movl $LenCoder, %eax
call LzmaLenDecode
pushl %edx
movl $(kNumLenToPosStates - 1), %eax
cmpl %eax, %edx
jbe 100f
movl %eax, %edx
100:
movb $kNumPosSlotBits, %cl
shll %cl, %edx
leal PosSlot(%edx), %eax
call RangeDecoderBitTreeDecode
movl %edx, rep0
cmpl $kStartPosModelIndex, %edx
jb 100f
movl %edx, %ecx
shrl $1, %ecx
decl %ecx
movzbl %dl, %eax
andb $1, %al
orb $2, %al
shll %cl, %eax
movl %eax, rep0
cmpl $kEndPosModelIndex, %edx
jae 200f
movl rep0, %eax
addl $(SpecPos - 1), %eax
subl %edx, %eax
jmp 300f
200:
subb $kNumAlignBits, %cl
/* RangeDecoderDecodeDirectBits */
xorl %edx, %edx
1000:
shrl $1, range
shll $1, %edx
movl range, %eax
cmpl %eax, code
jb 2000f
subl %eax, code
orb $1, %dl
2000:
cmpl $kTopValue, %eax
jae 3000f
shll $8, range
shll $8, code
lodsb
movb %al, code
3000:
loop 1000b
movb $kNumAlignBits, %cl
shll %cl, %edx
addl %edx, rep0
movl $Align, %eax
300:
call RangeDecoderReverseBitTreeDecode
addl %ecx, rep0
100:
incl rep0
popl %edx
2:
addl $kMatchMinLen, %edx
movl %edx, %ecx
jmp 3b

View file

@ -1,322 +0,0 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer
* Copyright (C) 2003,2007 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
/*
* This code was stolen from the files enter.sh, leave.sh, lzo1x_d.sh,
* lzo1x_f.s and lzo_asm.h in LZO version 1.08, and was heavily modified
* to adapt it to GRUB's requirement.
*
* See <http://www.oberhumer.com/opensource/lzo/>, for more information
* about LZO.
*/
#define INP 4+16(%esp)
#define INS 8+16(%esp)
#define OUTP 12+16(%esp)
#define NN 3
#define N_3 %ebp
#define N_255 $255
#define LODSB movb (%esi), %al ; incl %esi
#define NOTL_3(r) xorl N_3, r
#define MOVSL(r1,r2,x) movl (r1), x ; addl $4, r1 ; movl x, (r2) ; addl $4, r2
#define COPYL_C(r1,r2,x,rc) 9: MOVSL(r1,r2,x) ; decl rc ; jnz 9b
#define COPYL(r1,r2,x) COPYL_C(r1,r2,x,%ecx)
lzo1x_decompress:
pushl %ebp
pushl %edi
pushl %esi
pushl %ebx
cld
movl INP, %esi
movl OUTP, %edi
movl $3, %ebp
xorl %eax, %eax
xorl %ebx, %ebx /* high bits 9-32 stay 0 */
lodsb
cmpb $17, %al
jbe .L01
subb $17-NN, %al
jmp .LFLR
/***********************************************************************
// literal run
************************************************************************/
0: addl N_255, %eax
1: movb (%esi), %bl
incl %esi
orb %bl, %bl
jz 0b
leal 18+NN(%eax,%ebx), %eax
jmp 3f
.align 8
.L00:
LODSB
.L01:
cmpb $16, %al
jae .LMATCH
/* a literal run */
orb %al, %al
jz 1b
addl $3+NN, %eax
3:
.LFLR:
movl %eax, %ecx
NOTL_3(%eax)
shrl $2, %ecx
andl N_3, %eax
COPYL(%esi,%edi,%edx)
subl %eax, %esi
subl %eax, %edi
LODSB
cmpb $16, %al
jae .LMATCH
/***********************************************************************
// R1
************************************************************************/
shrl $2, %eax
movb (%esi), %bl
leal -0x801(%edi), %edx
leal (%eax,%ebx,4), %eax
incl %esi
subl %eax, %edx
movl (%edx), %ecx
movl %ecx, (%edi)
addl N_3, %edi
jmp .LMDONE
/***********************************************************************
// M2
************************************************************************/
.align 8
.LMATCH:
cmpb $64, %al
jb .LM3MATCH
/* a M2 match */
movl %eax, %ecx
shrl $2, %eax
leal -1(%edi), %edx
andl $7, %eax
movb (%esi), %bl
shrl $5, %ecx
leal (%eax,%ebx,8), %eax
incl %esi
subl %eax, %edx
addl $1+3, %ecx
cmpl N_3, %eax
jae .LCOPYLONG
jmp .LCOPYBYTE
/***********************************************************************
// M3
************************************************************************/
0: addl N_255, %eax
1: movb (%esi), %bl
incl %esi
orb %bl, %bl
jz 0b
leal 33+NN(%eax,%ebx), %ecx
xorl %eax, %eax
jmp 3f
.align 8
.LM3MATCH:
cmpb $32, %al
jb .LM4MATCH
/* a M3 match */
andl $31, %eax
jz 1b
lea 2+NN(%eax), %ecx
3:
movw (%esi), %ax
leal -1(%edi), %edx
shrl $2, %eax
addl $2, %esi
subl %eax, %edx
cmpl N_3, %eax
jb .LCOPYBYTE
/***********************************************************************
// copy match
************************************************************************/
.align 2
.LCOPYLONG: /* copy match using longwords */
leal -3(%edi,%ecx), %eax
shrl $2, %ecx
COPYL(%edx,%edi,%ebx)
movl %eax, %edi
xorl %ebx, %ebx
.LMDONE:
movb -2(%esi), %al
andl N_3, %eax
jz .L00
.LFLR3:
movl (%esi), %edx
addl %eax, %esi
movl %edx, (%edi)
addl %eax, %edi
LODSB
jmp .LMATCH
.align 8
.LCOPYBYTE: /* copy match using bytes */
xchgl %edx,%esi
subl N_3,%ecx
rep
movsb
movl %edx, %esi
jmp .LMDONE
/***********************************************************************
// M4
************************************************************************/
0: addl N_255, %ecx
1: movb (%esi), %bl
incl %esi
orb %bl, %bl
jz 0b
leal 9+NN(%ebx,%ecx), %ecx
jmp 3f
.align 8
.LM4MATCH:
cmpb $16, %al
jb .LM1MATCH
/* a M4 match */
movl %eax, %ecx
andl $8, %eax
shll $13, %eax /* save in bit 16 */
andl $7, %ecx
jz 1b
addl $2+NN, %ecx
3:
movw (%esi), %ax
addl $2, %esi
leal -0x4000(%edi), %edx
shrl $2, %eax
jz .LEOF
subl %eax, %edx
jmp .LCOPYLONG
/***********************************************************************
// M1
************************************************************************/
.align 8
.LM1MATCH:
/* a M1 match */
shrl $2, %eax
movb (%esi), %bl
leal -1(%edi), %edx
leal (%eax,%ebx,4), %eax
incl %esi
subl %eax, %edx
movb (%edx), %al /* we must use this because edx can be edi-1 */
movb %al, (%edi)
movb 1(%edx), %bl
movb %bl, 1(%edi)
addl $2, %edi
jmp .LMDONE
/***********************************************************************
//
************************************************************************/
.LEOF:
/**** xorl %eax,%eax eax=0 from above */
cmpl $3+NN, %ecx /* ecx must be 3/6 */
setnz %al
/* check compressed size */
movl INP, %edx
addl INS, %edx
cmpl %edx, %esi /* check compressed size */
ja .L_input_overrun
jb .L_input_not_consumed
.L_leave:
negl %eax
jnz 1f
subl OUTP, %edi /* write back the uncompressed size */
movl %edi, %eax
1: popl %ebx
popl %esi
popl %edi
popl %ebp
ret
.L_input_not_consumed:
movl $8, %eax /* LZO_E_INPUT_NOT_CONSUMED */
jmp .L_leave
.L_input_overrun:
movl $4, %eax /* LZO_E_INPUT_OVERRUN */
jmp .L_leave
#undef INP
#undef INS
#undef OUTP
#undef NN
#undef NN
#undef N_3
#undef N_255
#undef LODSB
#undef NOTL_3
#undef MOVSL
#undef COPYL_C
#undef COPYL

63
kern/i386/pc/mmap.c Normal file
View file

@ -0,0 +1,63 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2003,2004,2005,2006,2007,2008 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <grub/machine/init.h>
#include <grub/machine/memory.h>
#include <grub/err.h>
#include <grub/types.h>
grub_err_t
grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t))
{
grub_uint32_t cont;
struct grub_machine_mmap_entry *entry
= (struct grub_machine_mmap_entry *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
/* Check if grub_get_mmap_entry works. */
cont = grub_get_mmap_entry (entry, 0);
if (entry->size)
do
{
if (hook (entry->addr, entry->len,
/* Multiboot mmaps have been defined to match with the E820 definition.
Therefore, we can just pass type through. */
entry->type))
break;
if (! cont)
break;
cont = grub_get_mmap_entry (entry, cont);
}
while (entry->size);
else
{
grub_uint32_t eisa_mmap = grub_get_eisa_mmap ();
if (eisa_mmap)
{
if (hook (0x100000, (eisa_mmap & 0xFFFF) << 10, GRUB_MACHINE_MEMORY_AVAILABLE) == 0)
hook (0x1000000, eisa_mmap & ~0xFFFF, GRUB_MACHINE_MEMORY_AVAILABLE);
}
else
hook (0x100000, grub_get_memsize (1) << 10, GRUB_MACHINE_MEMORY_AVAILABLE);
}
return 0;
}

File diff suppressed because it is too large Load diff

56
kern/i386/pit.c Normal file
View file

@ -0,0 +1,56 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2008 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <grub/types.h>
#include <grub/i386/io.h>
#include <grub/i386/pit.h>
#define TIMER2_REG_CONTROL 0x42
#define TIMER_REG_COMMAND 0x43
#define TIMER2_REG_LATCH 0x61
#define TIMER2_SELECT 0x80
#define TIMER_ENABLE_LSB 0x20
#define TIMER_ENABLE_MSB 0x10
#define TIMER2_LATCH 0x20
#define TIMER2_SPEAKER 0x02
#define TIMER2_GATE 0x01
void
grub_pit_wait (grub_uint16_t tics)
{
/* Disable timer2 gate and speaker. */
grub_outb (grub_inb (TIMER2_REG_LATCH) & ~ (TIMER2_SPEAKER | TIMER2_GATE),
TIMER2_REG_LATCH);
/* Set tics. */
grub_outb (TIMER2_SELECT | TIMER_ENABLE_LSB | TIMER_ENABLE_MSB, TIMER_REG_COMMAND);
grub_outb (tics & 0xff, TIMER2_REG_CONTROL);
grub_outb (tics >> 8, TIMER2_REG_CONTROL);
/* Enable timer2 gate, keep speaker disabled. */
grub_outb ((grub_inb (TIMER2_REG_LATCH) & ~ TIMER2_SPEAKER) | TIMER2_GATE,
TIMER2_REG_LATCH);
/* Wait. */
while ((grub_inb (TIMER2_REG_LATCH) & TIMER2_LATCH) == 0x00);
/* Disable timer2 gate and speaker. */
grub_outb (grub_inb (TIMER2_REG_LATCH) & ~ (TIMER2_SPEAKER | TIMER2_GATE),
TIMER2_REG_LATCH);
}

74
kern/i386/qemu/mmap.c Normal file
View file

@ -0,0 +1,74 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <grub/machine/init.h>
#include <grub/machine/memory.h>
#include <grub/machine/boot.h>
#include <grub/types.h>
#include <grub/err.h>
#include <grub/misc.h>
#include <grub/i386/cmos.h>
#define QEMU_CMOS_MEMSIZE_HIGH 0x35
#define QEMU_CMOS_MEMSIZE_LOW 0x34
#define min(a,b) ((a) > (b) ? (b) : (a))
extern char _start[];
extern char _end[];
grub_size_t grub_lower_mem, grub_upper_mem;
grub_uint64_t mem_size;
void
grub_machine_mmap_init ()
{
mem_size = grub_cmos_read (QEMU_CMOS_MEMSIZE_HIGH) << 24 | grub_cmos_read (QEMU_CMOS_MEMSIZE_LOW) << 16;
/* Don't ask... */
mem_size += (16 * 1024 * 1024);
}
grub_err_t
grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t))
{
if (hook (0x0,
(grub_addr_t) _start,
GRUB_MACHINE_MEMORY_AVAILABLE))
return 1;
if (hook (GRUB_MEMORY_MACHINE_UPPER,
0x100000 - GRUB_MEMORY_MACHINE_UPPER,
GRUB_MACHINE_MEMORY_RESERVED))
return 1;
/* Protect boot.img, which contains the gdt. It is mapped at the top of memory
(it is also mapped below 0x100000, but we already reserved that area). */
if (hook ((grub_uint32_t) -GRUB_BOOT_MACHINE_SIZE,
GRUB_BOOT_MACHINE_SIZE,
GRUB_MACHINE_MEMORY_RESERVED))
return 1;
/* Everything else is free. */
if (hook (0x100000,
min (mem_size, (grub_uint32_t) -GRUB_BOOT_MACHINE_SIZE) - 0x100000,
GRUB_MACHINE_MEMORY_AVAILABLE))
return 1;
return 0;
}

99
kern/i386/qemu/startup.S Normal file
View file

@ -0,0 +1,99 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <config.h>
#include <grub/symbol.h>
#include <grub/machine/memory.h>
#include <grub/machine/kernel.h>
.text
.code32
.globl _start
_start:
jmp codestart
. = _start + GRUB_KERNEL_MACHINE_CORE_ENTRY_ADDR
VARIABLE(grub_core_entry_addr)
.long 0
VARIABLE(grub_kernel_image_size)
.long 0
VARIABLE(grub_prefix)
/* to be filled by grub-mkimage */
/*
* Leave some breathing room for the prefix.
*/
. = _start + GRUB_KERNEL_MACHINE_DATA_END
codestart:
/* Relocate to low memory. First we figure out our location.
We will derive the rom start address from it. */
call 1f
1: popl %esi
/* Rom size is a multiple of 64 kiB. With this we get the
value of `grub_core_entry_addr' in %esi. */
xorw %si, %si
/* ... which allows us to access `grub_kernel_image_size'
before relocation. */
movl (grub_kernel_image_size - _start)(%esi), %ecx
movl $_start, %edi
cld
rep
movsb
ljmp $GRUB_MEMORY_MACHINE_PROT_MODE_CSEG, $1f
1:
#ifdef APPLE_CC
/* clean out the bss */
bss_start_abs = ABS (bss_start)
bss_end_abs = ABS (bss_end)
movl bss_start_abs, %edi
/* compute the bss length */
movl bss_end_abs, %ecx
subl %edi, %ecx
#else
/* clean out the bss */
movl $BSS_START_SYMBOL, %edi
/* compute the bss length */
movl $END_SYMBOL, %ecx
subl %edi, %ecx
#endif
/* clean out */
xorl %eax, %eax
cld
rep
stosb
/*
* Call the start of main body of C code.
*/
call EXT_C(grub_main)
/* This should never happen. */
jmp EXT_C(grub_stop)
#include "../realmode.S"

View file

@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007 Free Software Foundation, Inc.
* Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -21,7 +21,7 @@
* Note: These functions defined in this file may be called from C.
* Be careful of that you must not modify some registers. Quote
* from gcc-2.95.2/gcc/config/i386/i386.h:
1 for registers not available across function calls.
These must include the FIXED_REGISTERS and also any
registers that can be used without being saved.
@ -84,7 +84,7 @@ gdt:
/* -- data segment --
* base = 0x00000000, limit 0xFFFFF (4 KiB Granularity), present
* type = 32 bit data read/write, DPL = 0
* type = 32 bit data read/write, DPL = 0
*/
.word 0xFFFF, 0
.byte 0, 0x92, 0xCF, 0
@ -110,12 +110,58 @@ gdtdesc:
.long gdt /* addr */
/*
* These next routine, "prot_to_real" is structured in a very
* specific way. Be very careful when changing it.
* These next two routines, "real_to_prot" and "prot_to_real" are structured
* in a very specific way. Be very careful when changing them.
*
* NOTE: Use of it messes up %eax and %ebp.
* NOTE: Use of either one messes up %eax and %ebp.
*/
real_to_prot:
.code16
cli
/* load the GDT register */
xorw %ax, %ax
movw %ax, %ds
DATA32 ADDR32 lgdt gdtdesc
/* turn on protected mode */
movl %cr0, %eax
orl $GRUB_MEMORY_CPU_CR0_PE_ON, %eax
movl %eax, %cr0
/* jump to relocation, flush prefetch queue, and reload %cs */
DATA32 ljmp $GRUB_MEMORY_MACHINE_PROT_MODE_CSEG, $protcseg
.code32
protcseg:
/* reload other segment registers */
movw $GRUB_MEMORY_MACHINE_PROT_MODE_DSEG, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss
/* put the return address in a known safe location */
movl (%esp), %eax
movl %eax, GRUB_MEMORY_MACHINE_REAL_STACK
/* get protected mode stack */
movl protstack, %eax
movl %eax, %esp
movl %eax, %ebp
/* get return address onto the right stack */
movl GRUB_MEMORY_MACHINE_REAL_STACK, %eax
movl %eax, (%esp)
/* zero %eax */
xorl %eax, %eax
/* return on the old (or initialized) stack! */
ret
prot_to_real:
/* just in case, set GDT */
lgdt gdtdesc
@ -150,7 +196,7 @@ tmpcseg:
/* clear the PE bit of CR0 */
movl %cr0, %eax
andl $(~GRUB_MEMORY_MACHINE_CR0_PE_ON), %eax
andl $(~GRUB_MEMORY_CPU_CR0_PE_ON), %eax
movl %eax, %cr0
/* flush prefetch queue, reload %cs */
@ -169,10 +215,27 @@ realcseg:
movw %ax, %gs
movw %ax, %ss
#ifdef GRUB_MACHINE_PCBIOS
/* restore interrupts */
sti
#endif
/* return on new stack! */
DATA32 ret
.code32
/*
* grub_reboot()
*
* Reboot the system. At the moment, rely on BIOS.
*/
FUNCTION(grub_reboot)
call prot_to_real
.code16
cold_reboot:
/* set 0x472 to 0x0000 for cold boot (0x1234 for warm boot) */
movw $0x0472, %di
movw %ax, (%di)
ljmp $0xf000, $0xfff0
.code32

74
kern/i386/tsc.c Normal file
View file

@ -0,0 +1,74 @@
/* kern/i386/tsc.c - x86 TSC time source implementation
* Requires Pentium or better x86 CPU that supports the RDTSC instruction.
* This module uses the RTC (via grub_get_rtc()) to calibrate the TSC to
* real time.
*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2008 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <grub/types.h>
#include <grub/time.h>
#include <grub/misc.h>
#include <grub/i386/tsc.h>
#include <grub/i386/pit.h>
/* This defines the value TSC had at the epoch (that is, when we calibrated it). */
static grub_uint64_t tsc_boot_time;
/* Calibrated TSC rate. (In TSC ticks per millisecond.) */
static grub_uint64_t tsc_ticks_per_ms;
grub_uint64_t
grub_tsc_get_time_ms (void)
{
return tsc_boot_time + grub_divmod64 (grub_get_tsc (), tsc_ticks_per_ms, 0);
}
/* How many RTC ticks to use for calibration loop. (>= 1) */
#define CALIBRATION_TICKS 2
/* Calibrate the TSC based on the RTC. */
static void
calibrate_tsc (void)
{
/* First calibrate the TSC rate (relative, not absolute time). */
grub_uint64_t start_tsc;
grub_uint64_t end_tsc;
start_tsc = grub_get_tsc ();
grub_pit_wait (0xffff);
end_tsc = grub_get_tsc ();
tsc_ticks_per_ms = grub_divmod64 (end_tsc - start_tsc, 55, 0);
}
void
grub_tsc_init (void)
{
if (grub_cpu_is_tsc_supported ())
{
tsc_boot_time = grub_get_tsc ();
calibrate_tsc ();
grub_install_get_time_ms (grub_tsc_get_time_ms);
}
else
{
grub_install_get_time_ms (grub_rtc_get_time_ms);
}
}

View file

@ -17,8 +17,6 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <alloca.h>
#include <stdint.h>
#include <grub/kernel.h>
#include <grub/misc.h>
#include <grub/types.h>
@ -57,7 +55,7 @@ grub_ieee1275_find_options (void)
grub_ieee1275_phandle_t openprom;
grub_ieee1275_phandle_t bootrom;
int rc;
int realmode = 0;
grub_uint32_t realmode = 0;
char tmp[32];
int is_smartfirmware = 0;
int is_olpc = 0;
@ -130,7 +128,7 @@ grub_ieee1275_find_options (void)
- SD cards. These work fine.
To avoid brekage, we only need to skip USB probing. However,
To avoid breakage, we only need to skip USB probing. However,
since detecting SD cards is more reliable, we do that instead.
*/
@ -144,6 +142,9 @@ grub_ieee1275_find_options (void)
{
grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_BROKEN_OUTPUT);
grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_CANNOT_SET_COLORS);
grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_CANNOT_INTERPRET);
grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_FORCE_CLAIM);
grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_ANSI);
}
}
}
@ -151,9 +152,8 @@ grub_ieee1275_find_options (void)
#undef SF
#undef OHW
void cmain (void);
void
cmain (void)
grub_ieee1275_init (void)
{
grub_ieee1275_finddevice ("/chosen", &grub_ieee1275_chosen);
@ -162,9 +162,4 @@ cmain (void)
grub_ieee1275_mmu = 0;
grub_ieee1275_find_options ();
/* Now invoke the main function. */
grub_main ();
/* Never reached. */
}

View file

@ -1,7 +1,7 @@
/* of.c - Access the Open Firmware client interface. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2003,2004,2005,2007,2008 Free Software Foundation, Inc.
* Copyright (C) 2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -20,8 +20,8 @@
#include <grub/ieee1275/ieee1275.h>
#include <grub/types.h>
#define IEEE1275_PHANDLE_INVALID ((grub_ieee1275_phandle_t) -1)
#define IEEE1275_IHANDLE_INVALID ((grub_ieee1275_ihandle_t) 0)
#define IEEE1275_PHANDLE_INVALID ((grub_ieee1275_cell_t) -1)
#define IEEE1275_IHANDLE_INVALID ((grub_ieee1275_cell_t) 0)
#define IEEE1275_CELL_INVALID ((grub_ieee1275_cell_t) -1)
@ -33,7 +33,7 @@ grub_ieee1275_finddevice (char *name, grub_ieee1275_phandle_t *phandlep)
{
struct grub_ieee1275_common_hdr common;
grub_ieee1275_cell_t device;
grub_ieee1275_phandle_t phandle;
grub_ieee1275_cell_t phandle;
}
args;
@ -56,7 +56,7 @@ grub_ieee1275_get_property (grub_ieee1275_phandle_t phandle,
struct get_property_args
{
struct grub_ieee1275_common_hdr common;
grub_ieee1275_phandle_t phandle;
grub_ieee1275_cell_t phandle;
grub_ieee1275_cell_t prop;
grub_ieee1275_cell_t buf;
grub_ieee1275_cell_t buflen;
@ -90,7 +90,7 @@ grub_ieee1275_get_integer_property (grub_ieee1275_phandle_t phandle,
/* Integer properties are always in big endian. */
if (ret == 0)
{
int i;
unsigned int i;
size /= sizeof (grub_uint32_t);
for (i = 0; i < size; i++)
buf[i] = grub_be_to_cpu32 (buf[i]);
@ -106,7 +106,7 @@ grub_ieee1275_next_property (grub_ieee1275_phandle_t phandle, char *prev_prop,
struct get_property_args
{
struct grub_ieee1275_common_hdr common;
grub_ieee1275_phandle_t phandle;
grub_ieee1275_cell_t phandle;
grub_ieee1275_cell_t prev_prop;
grub_ieee1275_cell_t next_prop;
grub_ieee1275_cell_t flags;
@ -125,13 +125,13 @@ grub_ieee1275_next_property (grub_ieee1275_phandle_t phandle, char *prev_prop,
}
int
grub_ieee1275_get_property_length (grub_ieee1275_phandle_t phandle,
grub_ieee1275_get_property_length (grub_ieee1275_phandle_t phandle,
const char *prop, grub_ssize_t *length)
{
struct get_property_args
{
struct grub_ieee1275_common_hdr common;
grub_ieee1275_phandle_t phandle;
grub_ieee1275_cell_t phandle;
grub_ieee1275_cell_t prop;
grub_ieee1275_cell_t length;
}
@ -157,14 +157,14 @@ grub_ieee1275_instance_to_package (grub_ieee1275_ihandle_t ihandle,
struct instance_to_package_args
{
struct grub_ieee1275_common_hdr common;
grub_ieee1275_ihandle_t ihandle;
grub_ieee1275_phandle_t phandle;
grub_ieee1275_cell_t ihandle;
grub_ieee1275_cell_t phandle;
}
args;
INIT_IEEE1275_COMMON (&args.common, "instance-to-package", 1, 1);
args.ihandle = ihandle;
if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
return -1;
*phandlep = args.phandle;
@ -181,7 +181,7 @@ grub_ieee1275_package_to_path (grub_ieee1275_phandle_t phandle,
struct instance_to_package_args
{
struct grub_ieee1275_common_hdr common;
grub_ieee1275_phandle_t phandle;
grub_ieee1275_cell_t phandle;
grub_ieee1275_cell_t buf;
grub_ieee1275_cell_t buflen;
grub_ieee1275_cell_t actual;
@ -192,7 +192,7 @@ grub_ieee1275_package_to_path (grub_ieee1275_phandle_t phandle,
args.phandle = phandle;
args.buf = (grub_ieee1275_cell_t) path;
args.buflen = (grub_ieee1275_cell_t) len;
if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
return -1;
if (actual)
@ -210,7 +210,7 @@ grub_ieee1275_instance_to_path (grub_ieee1275_ihandle_t ihandle,
struct instance_to_path_args
{
struct grub_ieee1275_common_hdr common;
grub_ieee1275_ihandle_t ihandle;
grub_ieee1275_cell_t ihandle;
grub_ieee1275_cell_t buf;
grub_ieee1275_cell_t buflen;
grub_ieee1275_cell_t actual;
@ -221,7 +221,7 @@ grub_ieee1275_instance_to_path (grub_ieee1275_ihandle_t ihandle,
args.ihandle = ihandle;
args.buf = (grub_ieee1275_cell_t) path;
args.buflen = (grub_ieee1275_cell_t) len;
if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
return -1;
if (actual)
@ -232,13 +232,13 @@ grub_ieee1275_instance_to_path (grub_ieee1275_ihandle_t ihandle,
}
int
grub_ieee1275_write (grub_ieee1275_ihandle_t ihandle, void *buffer,
grub_ieee1275_write (grub_ieee1275_ihandle_t ihandle, void *buffer,
grub_size_t len, grub_ssize_t *actualp)
{
struct write_args
{
struct grub_ieee1275_common_hdr common;
grub_ieee1275_ihandle_t ihandle;
grub_ieee1275_cell_t ihandle;
grub_ieee1275_cell_t buf;
grub_ieee1275_cell_t len;
grub_ieee1275_cell_t actual;
@ -264,7 +264,7 @@ grub_ieee1275_read (grub_ieee1275_ihandle_t ihandle, void *buffer,
struct write_args
{
struct grub_ieee1275_common_hdr common;
grub_ieee1275_ihandle_t ihandle;
grub_ieee1275_cell_t ihandle;
grub_ieee1275_cell_t buf;
grub_ieee1275_cell_t len;
grub_ieee1275_cell_t actual;
@ -290,7 +290,7 @@ grub_ieee1275_seek (grub_ieee1275_ihandle_t ihandle, int pos_hi,
struct write_args
{
struct grub_ieee1275_common_hdr common;
grub_ieee1275_ihandle_t ihandle;
grub_ieee1275_cell_t ihandle;
grub_ieee1275_cell_t pos_hi;
grub_ieee1275_cell_t pos_lo;
grub_ieee1275_cell_t result;
@ -317,8 +317,8 @@ grub_ieee1275_peer (grub_ieee1275_phandle_t node,
struct peer_args
{
struct grub_ieee1275_common_hdr common;
grub_ieee1275_phandle_t node;
grub_ieee1275_phandle_t result;
grub_ieee1275_cell_t node;
grub_ieee1275_cell_t result;
}
args;
@ -340,8 +340,8 @@ grub_ieee1275_child (grub_ieee1275_phandle_t node,
struct child_args
{
struct grub_ieee1275_common_hdr common;
grub_ieee1275_phandle_t node;
grub_ieee1275_phandle_t result;
grub_ieee1275_cell_t node;
grub_ieee1275_cell_t result;
}
args;
@ -364,8 +364,8 @@ grub_ieee1275_parent (grub_ieee1275_phandle_t node,
struct parent_args
{
struct grub_ieee1275_common_hdr common;
grub_ieee1275_phandle_t node;
grub_ieee1275_phandle_t result;
grub_ieee1275_cell_t node;
grub_ieee1275_cell_t result;
}
args;
@ -390,6 +390,9 @@ grub_ieee1275_interpret (const char *command, grub_ieee1275_cell_t *catch)
}
args;
if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CANNOT_INTERPRET))
return -1;
INIT_IEEE1275_COMMON (&args.common, "interpret", 1, 1);
args.command = (grub_ieee1275_cell_t) command;
@ -438,7 +441,7 @@ grub_ieee1275_open (const char *path, grub_ieee1275_ihandle_t *result)
{
struct grub_ieee1275_common_hdr common;
grub_ieee1275_cell_t path;
grub_ieee1275_ihandle_t result;
grub_ieee1275_cell_t result;
}
args;
@ -459,7 +462,7 @@ grub_ieee1275_close (grub_ieee1275_ihandle_t ihandle)
struct close_args
{
struct grub_ieee1275_common_hdr common;
grub_ieee1275_ihandle_t ihandle;
grub_ieee1275_cell_t ihandle;
}
args;
@ -514,7 +517,7 @@ grub_ieee1275_release (grub_addr_t addr, grub_size_t size)
INIT_IEEE1275_COMMON (&args.common, "release", 2, 0);
args.addr = addr;
args.size = size;
if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
return -1;
return 0;
@ -528,7 +531,7 @@ grub_ieee1275_set_property (grub_ieee1275_phandle_t phandle,
struct set_property_args
{
struct grub_ieee1275_common_hdr common;
grub_ieee1275_phandle_t phandle;
grub_ieee1275_cell_t phandle;
grub_ieee1275_cell_t propname;
grub_ieee1275_cell_t buf;
grub_ieee1275_cell_t size;
@ -557,8 +560,8 @@ grub_ieee1275_set_color (grub_ieee1275_ihandle_t ihandle,
struct set_color_args
{
struct grub_ieee1275_common_hdr common;
char *method;
grub_ieee1275_ihandle_t ihandle;
grub_ieee1275_cell_t method;
grub_ieee1275_cell_t ihandle;
grub_ieee1275_cell_t index;
grub_ieee1275_cell_t b;
grub_ieee1275_cell_t g;
@ -568,7 +571,7 @@ grub_ieee1275_set_color (grub_ieee1275_ihandle_t ihandle,
args;
INIT_IEEE1275_COMMON (&args.common, "call-method", 6, 1);
args.method = "color!";
args.method = (grub_ieee1275_cell_t) "color!";
args.ihandle = ihandle;
args.index = index;
args.r = r;

View file

@ -1,7 +1,7 @@
/* init.c -- Initialize GRUB on the newworld mac (PPC). */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2003,2004,2005,2007,2008 Free Software Foundation, Inc.
* Copyright (C) 2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -30,6 +30,7 @@
#include <grub/time.h>
#include <grub/machine/console.h>
#include <grub/machine/kernel.h>
#include <grub/cpu/kernel.h>
#include <grub/ieee1275/ofdisk.h>
#include <grub/ieee1275/ieee1275.h>
@ -46,12 +47,6 @@
extern char _start[];
extern char _end[];
void
grub_millisleep (grub_uint32_t ms)
{
grub_millisleep_generic (ms);
}
void
grub_exit (void)
{
@ -84,6 +79,13 @@ grub_machine_set_prefix (void)
/* We already set prefix in grub_machine_init(). */
return;
if (grub_prefix[0])
{
grub_env_set ("prefix", grub_prefix);
/* Prefix is hardcoded in the core image. */
return;
}
if (grub_ieee1275_get_property (grub_ieee1275_chosen, "bootpath", &bootpath,
sizeof (bootpath), 0))
{
@ -128,9 +130,12 @@ static void grub_claim_heap (void)
{
unsigned long total = 0;
auto int heap_init (grub_uint64_t addr, grub_uint64_t len);
int heap_init (grub_uint64_t addr, grub_uint64_t len)
auto int NESTED_FUNC_ATTR heap_init (grub_uint64_t addr, grub_uint64_t len, grub_uint32_t type);
int NESTED_FUNC_ATTR heap_init (grub_uint64_t addr, grub_uint64_t len, grub_uint32_t type)
{
if (type != 1)
return 0;
len -= 1; /* Required for some firmware. */
/* Never exceed HEAP_MAX_SIZE */
@ -145,10 +150,10 @@ static void grub_claim_heap (void)
/* In theory, firmware should already prevent this from happening by not
listing our own image in /memory/available. The check below is intended
as a safegard in case that doesn't happen. It does, however, not protect
as a safeguard in case that doesn't happen. However, it doesn't protect
us from corrupting our module area, which extends up to a
yet-undetermined region above _end. */
if ((addr < _end) && ((addr + len) > _start))
if ((addr < (grub_addr_t) _end) && ((addr + len) > (grub_addr_t) _start))
{
grub_printf ("Warning: attempt to claim over our own code!\n");
len = 0;
@ -159,7 +164,7 @@ static void grub_claim_heap (void)
/* Claim and use it. */
if (grub_claimmap (addr, len) < 0)
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
"Failed to claim heap at 0x%llx, len 0x%llx\n",
"failed to claim heap at 0x%llx, len 0x%llx",
addr, len);
grub_mm_init_region ((void *) (grub_addr_t) addr, len);
}
@ -171,18 +176,50 @@ static void grub_claim_heap (void)
return 0;
}
grub_available_iterate (heap_init);
if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CANNOT_INTERPRET))
heap_init (HEAP_MAX_ADDR - HEAP_MIN_SIZE, HEAP_MIN_SIZE, 1);
else
grub_machine_mmap_iterate (heap_init);
}
#ifdef __i386__
grub_uint32_t grub_upper_mem;
/* We need to call this before grub_claim_memory. */
static void
grub_get_extended_memory (void)
{
auto int NESTED_FUNC_ATTR find_ext_mem (grub_uint64_t addr, grub_uint64_t len, grub_uint32_t type);
int NESTED_FUNC_ATTR find_ext_mem (grub_uint64_t addr, grub_uint64_t len, grub_uint32_t type)
{
if (type == 1 && addr == 0x100000)
{
grub_upper_mem = len;
return 1;
}
return 0;
}
grub_machine_mmap_iterate (find_ext_mem);
}
#endif
static grub_uint64_t ieee1275_get_time_ms (void);
void
grub_machine_init (void)
{
char args[256];
int actual;
grub_ssize_t actual;
grub_ieee1275_init ();
grub_console_init ();
#ifdef __i386__
grub_keyboard_controller_init ();
grub_get_extended_memory ();
#endif
grub_claim_heap ();
grub_ofdisk_init ();
@ -220,6 +257,8 @@ grub_machine_init (void)
}
}
}
grub_install_get_time_ms (ieee1275_get_time_ms);
}
void
@ -229,8 +268,8 @@ grub_machine_fini (void)
grub_console_fini ();
}
grub_uint32_t
grub_get_rtc (void)
static grub_uint64_t
ieee1275_get_time_ms (void)
{
grub_uint32_t msecs = 0;
@ -239,8 +278,14 @@ grub_get_rtc (void)
return msecs;
}
grub_uint32_t
grub_get_rtc (void)
{
return ieee1275_get_time_ms ();
}
grub_addr_t
grub_arch_modules_addr (void)
{
return ALIGN_UP(_end + GRUB_MOD_GAP, GRUB_MOD_ALIGN);
return ALIGN_UP((grub_addr_t) _end + GRUB_MOD_GAP, GRUB_MOD_ALIGN);
}

74
kern/ieee1275/mmap.c Normal file
View file

@ -0,0 +1,74 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2003,2004,2005,2007,2008 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <grub/machine/memory.h>
#include <grub/ieee1275/ieee1275.h>
#include <grub/types.h>
grub_err_t
grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t))
{
grub_ieee1275_phandle_t root;
grub_ieee1275_phandle_t memory;
grub_uint32_t available[32];
grub_ssize_t available_size;
grub_uint32_t address_cells = 1;
grub_uint32_t size_cells = 1;
int i;
/* Determine the format of each entry in `available'. */
grub_ieee1275_finddevice ("/", &root);
grub_ieee1275_get_integer_property (root, "#address-cells", &address_cells,
sizeof address_cells, 0);
grub_ieee1275_get_integer_property (root, "#size-cells", &size_cells,
sizeof size_cells, 0);
if (size_cells > address_cells)
address_cells = size_cells;
/* Load `/memory/available'. */
if (grub_ieee1275_finddevice ("/memory", &memory))
return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
"couldn't find /memory node");
if (grub_ieee1275_get_integer_property (memory, "available", available,
sizeof available, &available_size))
return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
"couldn't examine /memory/available property");
/* Decode each entry and call `hook'. */
i = 0;
available_size /= sizeof (grub_uint32_t);
while (i < available_size)
{
grub_uint64_t address;
grub_uint64_t size;
address = available[i++];
if (address_cells == 2)
address = (address << 32) | available[i++];
size = available[i++];
if (size_cells == 2)
size = (size << 32) | available[i++];
if (hook (address, size, GRUB_MACHINE_MEMORY_AVAILABLE))
break;
}
return grub_errno;
}

View file

@ -1,7 +1,7 @@
/* openfw.c -- Open firmware support functions. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2003,2004,2005,2007,2008 Free Software Foundation, Inc.
* Copyright (C) 2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -17,7 +17,6 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <alloca.h>
#include <grub/types.h>
#include <grub/err.h>
#include <grub/misc.h>
@ -32,39 +31,62 @@ enum grub_ieee1275_parse_type
};
/* Walk children of 'devpath', calling hook for each. */
grub_err_t
int
grub_children_iterate (char *devpath,
int (*hook) (struct grub_ieee1275_devalias *alias))
int (*hook) (struct grub_ieee1275_devalias *alias))
{
grub_ieee1275_phandle_t dev;
grub_ieee1275_phandle_t child;
char *childtype, *childpath;
char *childname, *fullname;
int ret = 0;
if (grub_ieee1275_finddevice (devpath, &dev))
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Unknown device");
return 0;
if (grub_ieee1275_child (dev, &child))
return grub_error (GRUB_ERR_BAD_DEVICE, "Device has no children");
return 0;
childtype = grub_malloc (IEEE1275_MAX_PROP_LEN);
if (!childtype)
return 0;
childpath = grub_malloc (IEEE1275_MAX_PATH_LEN);
if (!childpath)
{
grub_free (childtype);
return 0;
}
childname = grub_malloc (IEEE1275_MAX_PROP_LEN);
if (!childname)
{
grub_free (childpath);
grub_free (childtype);
return 0;
}
fullname = grub_malloc (IEEE1275_MAX_PATH_LEN);
if (!fullname)
{
grub_free (childname);
grub_free (childpath);
grub_free (childtype);
return 0;
}
do
{
/* XXX: Don't use hardcoded path lengths. */
char childtype[64];
char childpath[64];
char childname[64];
char fullname[64];
struct grub_ieee1275_devalias alias;
int actual;
grub_ssize_t actual;
if (grub_ieee1275_get_property (child, "device_type", &childtype,
sizeof childtype, &actual))
if (grub_ieee1275_get_property (child, "device_type", childtype,
IEEE1275_MAX_PROP_LEN, &actual))
continue;
if (grub_ieee1275_package_to_path (child, childpath, sizeof childpath,
&actual))
if (grub_ieee1275_package_to_path (child, childpath,
IEEE1275_MAX_PATH_LEN, &actual))
continue;
if (grub_ieee1275_get_property (child, "name", &childname,
sizeof childname, &actual))
if (grub_ieee1275_get_property (child, "name", childname,
IEEE1275_MAX_PROP_LEN, &actual))
continue;
grub_sprintf (fullname, "%s/%s", devpath, childname);
@ -72,25 +94,43 @@ grub_children_iterate (char *devpath,
alias.type = childtype;
alias.path = childpath;
alias.name = fullname;
hook (&alias);
ret = hook (&alias);
if (ret)
break;
}
while (grub_ieee1275_peer (child, &child));
return 0;
grub_free (fullname);
grub_free (childname);
grub_free (childpath);
grub_free (childtype);
return ret;
}
/* Iterate through all device aliases. This function can be used to
find a device of a specific type. */
grub_err_t
int
grub_devalias_iterate (int (*hook) (struct grub_ieee1275_devalias *alias))
{
grub_ieee1275_phandle_t aliases;
char aliasname[32];
int actual;
char *aliasname, *devtype;
grub_ssize_t actual;
struct grub_ieee1275_devalias alias;
int ret = 0;
if (grub_ieee1275_finddevice ("/aliases", &aliases))
return -1;
return 0;
aliasname = grub_malloc (IEEE1275_MAX_PROP_LEN);
if (!aliasname)
return 0;
devtype = grub_malloc (IEEE1275_MAX_PROP_LEN);
if (!devtype)
{
grub_free (aliasname);
return 0;
}
/* Find the first property. */
aliasname[0] = '\0';
@ -100,8 +140,6 @@ grub_devalias_iterate (int (*hook) (struct grub_ieee1275_devalias *alias))
grub_ieee1275_phandle_t dev;
grub_ssize_t pathlen;
char *devpath;
/* XXX: This should be large enough for any possible case. */
char devtype[64];
grub_dprintf ("devalias", "devalias name = %s\n", aliasname);
@ -111,9 +149,17 @@ grub_devalias_iterate (int (*hook) (struct grub_ieee1275_devalias *alias))
if (!grub_strcmp (aliasname, "name"))
continue;
/* Sun's OpenBoot often doesn't zero terminate the device alias
strings, so we will add a NULL byte at the end explicitly. */
pathlen += 1;
devpath = grub_malloc (pathlen);
if (! devpath)
return grub_errno;
{
grub_free (devtype);
grub_free (aliasname);
return 0;
}
if (grub_ieee1275_get_property (aliases, aliasname, devpath, pathlen,
&actual))
@ -121,6 +167,7 @@ grub_devalias_iterate (int (*hook) (struct grub_ieee1275_devalias *alias))
grub_dprintf ("devalias", "get_property (%s) failed\n", aliasname);
goto nextprop;
}
devpath [actual] = '\0';
if (grub_ieee1275_finddevice (devpath, &dev))
{
@ -129,71 +176,26 @@ grub_devalias_iterate (int (*hook) (struct grub_ieee1275_devalias *alias))
}
if (grub_ieee1275_get_property (dev, "device_type", devtype,
sizeof devtype, &actual))
IEEE1275_MAX_PROP_LEN, &actual))
{
grub_dprintf ("devalias", "get device type failed\n");
goto nextprop;
/* NAND device don't have device_type property. */
devtype[0] = 0;
}
alias.name = aliasname;
alias.path = devpath;
alias.type = devtype;
hook (&alias);
ret = hook (&alias);
nextprop:
grub_free (devpath);
}
return 0;
}
grub_err_t grub_available_iterate (int (*hook) (grub_uint64_t, grub_uint64_t))
{
grub_ieee1275_phandle_t root;
grub_ieee1275_phandle_t memory;
grub_uint32_t available[32];
grub_ssize_t available_size;
int address_cells = 1;
int size_cells = 1;
unsigned int i;
/* Determine the format of each entry in `available'. */
grub_ieee1275_finddevice ("/", &root);
grub_ieee1275_get_integer_property (root, "#address-cells", &address_cells,
sizeof address_cells, 0);
grub_ieee1275_get_integer_property (root, "#size-cells", &size_cells,
sizeof size_cells, 0);
/* Load `/memory/available'. */
if (grub_ieee1275_finddevice ("/memory", &memory))
return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
"Couldn't find /memory node");
if (grub_ieee1275_get_integer_property (memory, "available", available,
sizeof available, &available_size))
return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
"Couldn't examine /memory/available property");
/* Decode each entry and call `hook'. */
i = 0;
available_size /= sizeof (grub_uint32_t);
while (i < available_size)
{
grub_uint64_t address;
grub_uint64_t size;
address = available[i++];
if (address_cells == 2)
address = (address << 32) | available[i++];
size = available[i++];
if (size_cells == 2)
size = (size << 32) | available[i++];
if (hook (address, size))
if (ret)
break;
}
return grub_errno;
grub_free (devtype);
grub_free (aliasname);
return ret;
}
/* Call the "map" method of /chosen/mmu. */
@ -203,17 +205,17 @@ grub_map (grub_addr_t phys, grub_addr_t virt, grub_uint32_t size,
{
struct map_args {
struct grub_ieee1275_common_hdr common;
char *method;
grub_ieee1275_ihandle_t ihandle;
grub_uint32_t mode;
grub_uint32_t size;
grub_uint32_t virt;
grub_uint32_t phys;
int catch_result;
grub_ieee1275_cell_t method;
grub_ieee1275_cell_t ihandle;
grub_ieee1275_cell_t mode;
grub_ieee1275_cell_t size;
grub_ieee1275_cell_t virt;
grub_ieee1275_cell_t phys;
grub_ieee1275_cell_t catch_result;
} args;
INIT_IEEE1275_COMMON (&args.common, "call-method", 6, 1);
args.method = "map";
args.method = (grub_ieee1275_cell_t) "map";
args.ihandle = grub_ieee1275_mmu;
args.phys = phys;
args.virt = virt;
@ -235,7 +237,8 @@ grub_claimmap (grub_addr_t addr, grub_size_t size)
if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_REAL_MODE)
&& grub_map (addr, addr, size, 0x00))
{
grub_printf ("map failed: address 0x%x, size 0x%x\n", addr, size);
grub_printf ("map failed: address 0x%llx, size 0x%llx\n",
(long long) addr, (long long) size);
grub_ieee1275_release (addr, size);
return -1;
}
@ -305,13 +308,13 @@ grub_ieee1275_parse_args (const char *path, enum grub_ieee1275_parse_type ptype)
file path properly. */
if (grub_ieee1275_finddevice (device, &dev))
{
grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Device %s not found\n", device);
grub_error (GRUB_ERR_UNKNOWN_DEVICE, "device %s not found", device);
goto fail;
}
if (grub_ieee1275_get_property (dev, "device_type", &type, sizeof type, 0))
{
grub_error (GRUB_ERR_UNKNOWN_DEVICE,
"Device %s lacks a device_type property\n", device);
"device %s lacks a device_type property", device);
goto fail;
}
@ -396,16 +399,19 @@ grub_ieee1275_encode_devname (const char *path)
return encoding;
}
/* On i386, a firmware-independant grub_reboot() is provided by realmode.S. */
#ifndef __i386__
void
grub_reboot (void)
{
grub_ieee1275_interpret ("reset-all", 0);
}
#endif
void
grub_halt (void)
{
/* Not standarized. We try both known commands. */
/* Not standardized. We try both known commands. */
grub_ieee1275_interpret ("shut-down", 0);
grub_ieee1275_interpret ("power-off", 0);

131
kern/list.c Normal file
View file

@ -0,0 +1,131 @@
/* list.c - grub list function */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <grub/list.h>
#include <grub/misc.h>
#include <grub/mm.h>
void
grub_list_push (grub_list_t *head, grub_list_t item)
{
item->next = *head;
*head = item;
}
void *
grub_list_pop (grub_list_t *head)
{
grub_list_t item;
item = *head;
if (item)
*head = item->next;
return item;
}
void
grub_list_remove (grub_list_t *head, grub_list_t item)
{
grub_list_t *p, q;
for (p = head, q = *p; q; p = &(q->next), q = q->next)
if (q == item)
{
*p = q->next;
break;
}
}
int
grub_list_iterate (grub_list_t head, grub_list_hook_t hook)
{
grub_list_t p;
for (p = head; p; p = p->next)
if (hook (p))
return 1;
return 0;
}
void
grub_list_insert (grub_list_t *head, grub_list_t item,
grub_list_test_t test)
{
grub_list_t *p, q;
for (p = head, q = *p; q; p = &(q->next), q = q->next)
if (test (item, q))
break;
*p = item;
item->next = q;
}
void *
grub_named_list_find (grub_named_list_t head, const char *name)
{
grub_named_list_t result = NULL;
auto int list_find (grub_named_list_t item);
int list_find (grub_named_list_t item)
{
if (! grub_strcmp (item->name, name))
{
result = item;
return 1;
}
return 0;
}
grub_list_iterate (GRUB_AS_LIST (head), (grub_list_hook_t) list_find);
return result;
}
void
grub_prio_list_insert (grub_prio_list_t *head, grub_prio_list_t nitem)
{
int inactive = 0;
auto int test (grub_prio_list_t new_item, grub_prio_list_t item);
int test (grub_prio_list_t new_item, grub_prio_list_t item)
{
int r;
r = grub_strcmp (new_item->name, item->name);
if (r)
return (r < 0);
if (new_item->prio >= (item->prio & GRUB_PRIO_LIST_PRIO_MASK))
{
item->prio &= ~GRUB_PRIO_LIST_FLAG_ACTIVE;
return 1;
}
inactive = 1;
return 0;
}
grub_list_insert (GRUB_AS_LIST_P (head), GRUB_AS_LIST (nitem),
(grub_list_test_t) test);
if (! inactive)
nitem->prio |= GRUB_PRIO_LIST_FLAG_ACTIVE;
}

View file

@ -1,75 +0,0 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2003,2004,2006,2007 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <grub/loader.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/kernel.h>
static grub_err_t (*grub_loader_boot_func) (void);
static grub_err_t (*grub_loader_unload_func) (void);
static int grub_loader_noreturn;
static int grub_loader_loaded;
int
grub_loader_is_loaded (void)
{
return grub_loader_loaded;
}
void
grub_loader_set (grub_err_t (*boot) (void),
grub_err_t (*unload) (void),
int noreturn)
{
if (grub_loader_loaded && grub_loader_unload_func)
grub_loader_unload_func ();
grub_loader_boot_func = boot;
grub_loader_unload_func = unload;
grub_loader_noreturn = noreturn;
grub_loader_loaded = 1;
}
void
grub_loader_unset(void)
{
if (grub_loader_loaded && grub_loader_unload_func)
grub_loader_unload_func ();
grub_loader_boot_func = 0;
grub_loader_unload_func = 0;
grub_loader_loaded = 0;
}
grub_err_t
grub_loader_boot (void)
{
if (! grub_loader_loaded)
return grub_error (GRUB_ERR_NO_KERNEL, "no loaded kernel");
if (grub_loader_noreturn)
grub_machine_fini ();
return (grub_loader_boot_func) ();
}

View file

@ -1,7 +1,7 @@
/* main.c - the kernel main routine */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2003,2005,2006,2008 Free Software Foundation, Inc.
* Copyright (C) 2002,2003,2005,2006,2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -19,18 +19,19 @@
#include <grub/kernel.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/symbol.h>
#include <grub/dl.h>
#include <grub/term.h>
#include <grub/rescue.h>
#include <grub/file.h>
#include <grub/device.h>
#include <grub/env.h>
#include <grub/mm.h>
#include <grub/command.h>
#include <grub/reader.h>
#include <grub/parser.h>
/* Load all modules in core. */
static void
grub_load_modules (void)
void
grub_module_iterate (int (*hook) (struct grub_module_header *header))
{
struct grub_module_info *modinfo;
struct grub_module_header *header;
@ -38,7 +39,7 @@ grub_load_modules (void)
modbase = grub_arch_modules_addr ();
modinfo = (struct grub_module_info *) modbase;
/* Check if there are any modules. */
if ((modinfo == 0) || modinfo->magic != GRUB_MODULE_MAGIC)
return;
@ -47,13 +48,48 @@ grub_load_modules (void)
header < (struct grub_module_header *) (modbase + modinfo->size);
header = (struct grub_module_header *) ((char *) header + header->size))
{
if (! grub_dl_load_core ((char *) header + header->offset,
(header->size - header->offset)))
if (hook (header))
break;
}
}
/* Load all modules in core. */
static void
grub_load_modules (void)
{
auto int hook (struct grub_module_header *);
int hook (struct grub_module_header *header)
{
/* Not an ELF module, skip. */
if (header->type != OBJ_TYPE_ELF)
return 0;
if (! grub_dl_load_core ((char *) header + sizeof (struct grub_module_header),
(header->size - sizeof (struct grub_module_header))))
grub_fatal ("%s", grub_errmsg);
return 0;
}
/* Add the region where modules reside into dynamic memory. */
grub_mm_init_region ((void *) modinfo, modinfo->size);
grub_module_iterate (hook);
}
static void
grub_load_config (void)
{
auto int hook (struct grub_module_header *);
int hook (struct grub_module_header *header)
{
/* Not an ELF module, skip. */
if (header->type != OBJ_TYPE_CONFIG)
return 0;
grub_parser_execute ((char *) header +
sizeof (struct grub_module_header));
return 1;
}
grub_module_iterate (hook);
}
/* Write hook for the environment variables of root. Remove surrounding
@ -64,7 +100,7 @@ grub_env_write_root (struct grub_env_var *var __attribute__ ((unused)),
{
/* XXX Is it better to check the existence of the device? */
grub_size_t len = grub_strlen (val);
if (val[0] == '(' && val[len - 1] == ')')
return grub_strndup (val + 1, len - 2);
@ -79,9 +115,9 @@ grub_set_root_dev (void)
grub_register_variable_hook ("root", 0, grub_env_write_root);
grub_env_export ("root");
prefix = grub_env_get ("prefix");
if (prefix)
{
char *dev;
@ -101,9 +137,12 @@ grub_load_normal_mode (void)
{
/* Load the module. */
grub_dl_load ("normal");
/* Ignore any error, because we have the rescue mode anyway. */
grub_errno = GRUB_ERR_NONE;
/* Something went wrong. Print errors here to let user know why we're entering rescue mode. */
grub_print_error ();
grub_errno = 0;
grub_command_execute ("normal", 0, 0);
}
/* The main routine. */
@ -125,11 +164,13 @@ grub_main (void)
/* It is better to set the root device as soon as possible,
for convenience. */
grub_machine_set_prefix ();
grub_env_export ("prefix");
grub_set_root_dev ();
/* Load the normal mode module. */
grub_register_core_commands ();
grub_register_rescue_parser ();
grub_load_config ();
grub_load_normal_mode ();
/* Enter the rescue mode. */
grub_enter_rescue_mode ();
grub_rescue_run ();
}

View file

@ -1,7 +1,7 @@
/* misc.c - definitions of misc functions */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007 Free Software Foundation, Inc.
* Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -23,7 +23,22 @@
#include <stdarg.h>
#include <grub/term.h>
#include <grub/env.h>
#include <grub/time.h>
#include <grub/i18n.h>
static int
grub_iswordseparator (int c)
{
return (grub_isspace (c) || c == ',' || c == ';' || c == '|' || c == '&');
}
/* grub_gettext_dummy is not translating anything. */
const char *
grub_gettext_dummy (const char *s)
{
return s;
}
const char* (*grub_gettext) (const char *s) = grub_gettext_dummy;
void *
grub_memmove (void *dest, const void *src, grub_size_t n)
@ -38,18 +53,30 @@ grub_memmove (void *dest, const void *src, grub_size_t n)
{
d += n;
s += n;
while (n--)
*--d = *--s;
}
return dest;
}
#ifndef APPLE_CC
void *memmove (void *dest, const void *src, grub_size_t n)
__attribute__ ((alias ("grub_memmove")));
/* GCC emits references to memcpy() for struct copies etc. */
void *memcpy (void *dest, const void *src, grub_size_t n)
__attribute__ ((alias ("grub_memmove")));
#else
void *memcpy (void *dest, const void *src, grub_size_t n)
{
return grub_memmove (dest, src, n);
}
void *memmove (void *dest, const void *src, grub_size_t n)
{
return grub_memmove (dest, src, n);
}
#endif
char *
grub_strcpy (char *dest, const char *src)
@ -66,7 +93,7 @@ char *
grub_strncpy (char *dest, const char *src, int c)
{
char *p = dest;
while ((*p++ = *src++) != '\0' && --c)
;
@ -86,47 +113,70 @@ grub_stpcpy (char *dest, const char *src)
return d - 1;
}
char *
grub_strcat (char *dest, const char *src)
{
char *p = dest;
while (*p)
p++;
while ((*p++ = *src++) != '\0')
;
return dest;
}
char *
grub_strncat (char *dest, const char *src, int c)
{
char *p = dest;
while (*p)
p++;
while ((*p++ = *src++) != '\0' && --c)
;
*(--p) = '\0';
return dest;
}
int
grub_printf (const char *fmt, ...)
{
va_list ap;
int ret;
va_start (ap, fmt);
ret = grub_vprintf (fmt, ap);
va_end (ap);
return ret;
}
}
int
grub_printf_ (const char *fmt, ...)
{
va_list ap;
int ret;
va_start (ap, fmt);
ret = grub_vprintf (_(fmt), ap);
va_end (ap);
return ret;
}
int
grub_puts (const char *s)
{
while (*s)
{
grub_putchar (*s);
s++;
}
grub_putchar ('\n');
return 1; /* Cannot fail. */
}
int
grub_puts_ (const char *s)
{
return grub_puts (_(s));
}
#if defined (APPLE_CC) && ! defined (GRUB_UTIL)
int
grub_err_printf (const char *fmt, ...)
{
va_list ap;
int ret;
va_start (ap, fmt);
ret = grub_vprintf (fmt, ap);
va_end (ap);
return ret;
}
#endif
#if ! defined (APPLE_CC) && ! defined (GRUB_UTIL)
int grub_err_printf (const char *fmt, ...)
__attribute__ ((alias("grub_printf")));
#endif
void
grub_real_dprintf (const char *file, const int line, const char *condition,
@ -134,10 +184,10 @@ grub_real_dprintf (const char *file, const int line, const char *condition,
{
va_list args;
const char *debug = grub_env_get ("debug");
if (! debug)
return;
if (grub_strword (debug, "all") || grub_strword (debug, condition))
{
grub_printf ("%s:%d: ", file, line);
@ -162,7 +212,7 @@ grub_memcmp (const void *s1, const void *s2, grub_size_t n)
{
const char *t1 = s1;
const char *t2 = s2;
while (n--)
{
if (*t1 != *t2)
@ -174,8 +224,15 @@ grub_memcmp (const void *s1, const void *s2, grub_size_t n)
return 0;
}
#ifndef APPLE_CC
int memcmp (const void *s1, const void *s2, grub_size_t n)
__attribute__ ((alias ("grub_memcmp")));
#else
int memcmp (const void *s1, const void *s2, grub_size_t n)
{
return grub_memcmp (s1, s2, n);
}
#endif
int
grub_strcmp (const char *s1, const char *s2)
@ -183,8 +240,8 @@ grub_strcmp (const char *s1, const char *s2)
while (*s1 && *s2)
{
if (*s1 != *s2)
return (int) *s1 - (int) *s2;
break;
s1++;
s2++;
}
@ -197,12 +254,12 @@ grub_strncmp (const char *s1, const char *s2, grub_size_t n)
{
if (n == 0)
return 0;
while (*s1 && *s2 && --n)
{
if (*s1 != *s2)
return (int) *s1 - (int) *s2;
break;
s1++;
s2++;
}
@ -210,33 +267,15 @@ grub_strncmp (const char *s1, const char *s2, grub_size_t n)
return (int) *s1 - (int) *s2;
}
int
grub_strncasecmp (const char *s1, const char *s2, int c)
{
int p = 1;
while (grub_tolower (*s1) && grub_tolower (*s2) && p < c)
{
if (grub_tolower (*s1) != grub_tolower (*s2))
return (int) grub_tolower (*s1) - (int) grub_tolower (*s2);
s1++;
s2++;
p++;
}
return (int) *s1 - (int) *s2;
}
char *
grub_strchr (const char *s, int c)
{
while (*s)
do
{
if (*s == c)
return (char *) s;
s++;
}
while (*s++);
return 0;
}
@ -244,14 +283,14 @@ grub_strchr (const char *s, int c)
char *
grub_strrchr (const char *s, int c)
{
char *p = 0;
char *p = NULL;
while (*s)
do
{
if (*s == c)
p = (char *) s;
s++;
}
while (*s++);
return p;
}
@ -271,7 +310,7 @@ grub_strstr (const char *haystack, const char *needle)
/* Speed up the following searches of needle by caching its first
character. */
char b = *needle++;
for (;; haystack++)
{
if (*haystack == '\0')
@ -339,12 +378,6 @@ grub_strword (const char *haystack, const char *needle)
return 0;
}
int
grub_iswordseparator (int c)
{
return (grub_isspace (c) || c == ',' || c == ';' || c == '|' || c == '&');
}
int
grub_isspace (int c)
{
@ -357,33 +390,6 @@ grub_isprint (int c)
return (c >= ' ' && c <= '~');
}
int
grub_isalpha (int c)
{
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
int
grub_isdigit (int c)
{
return (c >= '0' && c <= '9');
}
int
grub_isgraph (int c)
{
return (c >= '!' && c <= '~');
}
int
grub_tolower (int c)
{
if (c >= 'A' && c <= 'Z')
return c - 'A' + 'a';
return c;
}
unsigned long
grub_strtoul (const char *str, char **end, int base)
@ -405,14 +411,14 @@ grub_strtoull (const char *str, char **end, int base)
{
unsigned long long num = 0;
int found = 0;
/* Skip white spaces. */
while (*str && grub_isspace (*str))
str++;
/* Guess the base, if not specified. The prefix `0x' means 16, and
the prefix `0' means 8. */
if (base == 0 && str[0] == '0')
if (str[0] == '0')
{
if (str[1] == 'x')
{
@ -422,10 +428,10 @@ grub_strtoull (const char *str, char **end, int base)
str += 2;
}
}
else if (str[1] >= '0' && str[1] <= '7')
else if (base == 0 && str[1] >= '0' && str[1] <= '7')
base = 8;
}
if (base == 0)
base = 10;
@ -459,7 +465,7 @@ grub_strtoull (const char *str, char **end, int base)
grub_error (GRUB_ERR_BAD_NUMBER, "unrecognized number");
return 0;
}
if (end)
*end = (char *) str;
@ -471,7 +477,7 @@ grub_strdup (const char *s)
{
grub_size_t len;
char *p;
len = grub_strlen (s) + 1;
p = (char *) grub_malloc (len);
if (! p)
@ -485,14 +491,14 @@ grub_strndup (const char *s, grub_size_t n)
{
grub_size_t len;
char *p;
len = grub_strlen (s);
if (len > n)
len = n;
p = (char *) grub_malloc (len + 1);
if (! p)
return 0;
grub_memcpy (p, s, len);
p[len] = '\0';
return p;
@ -508,8 +514,15 @@ grub_memset (void *s, int c, grub_size_t n)
return s;
}
#ifndef APPLE_CC
void *memset (void *s, int c, grub_size_t n)
__attribute__ ((alias ("grub_memset")));
#else
void *memset (void *s, int c, grub_size_t n)
{
return grub_memset (s, c, n);
}
#endif
grub_size_t
grub_strlen (const char *s)
@ -539,31 +552,6 @@ grub_reverse (char *str)
}
}
static char *
grub_itoa (char *str, int c, unsigned n)
{
unsigned base = (c == 'x') ? 16 : 10;
char *p;
if ((int) n < 0 && c == 'd')
{
n = (unsigned) (-((int) n));
*str++ = '-';
}
p = str;
do
{
unsigned d = n % base;
*p++ = (d > 9) ? d + 'a' - 10 : d + '0';
}
while (n /= base);
*p = 0;
grub_reverse (str);
return p;
}
/* Divide N by D, return the quotient, and store the remainder in *R. */
grub_uint64_t
grub_divmod64 (grub_uint64_t n, grub_uint32_t d, grub_uint32_t *r)
@ -584,17 +572,17 @@ grub_divmod64 (grub_uint64_t n, grub_uint32_t d, grub_uint32_t *r)
return ((grub_uint32_t) n) / d;
}
while (bits--)
{
m <<= 1;
if (n & (1ULL << 63))
m |= 1;
q <<= 1;
n <<= 1;
if (m >= d)
{
q |= 1;
@ -604,7 +592,7 @@ grub_divmod64 (grub_uint64_t n, grub_uint32_t d, grub_uint32_t *r)
if (r)
*r = m;
return q;
}
@ -615,7 +603,7 @@ grub_lltoa (char *str, int c, unsigned long long n)
{
unsigned base = (c == 'x') ? 16 : 10;
char *p;
if ((long long) n < 0 && c == 'd')
{
n = (unsigned long long) (-((long long) n));
@ -636,36 +624,18 @@ grub_lltoa (char *str, int c, unsigned long long n)
do
{
unsigned m;
n = grub_divmod64 (n, 10, &m);
*p++ = m + '0';
}
while (n);
*p = 0;
grub_reverse (str);
return p;
}
static char *
grub_ftoa (char *str, double f, int round)
{
unsigned int intp;
unsigned int fractp;
unsigned int power = 1;
int i;
for (i = 0; i < round; i++)
power *= 10;
intp = f;
fractp = (f - (float) intp) * power;
grub_sprintf (str, "%d.%d", intp, fractp);
return str;
}
int
grub_vsprintf (char *str, const char *fmt, va_list args)
{
@ -674,7 +644,7 @@ grub_vsprintf (char *str, const char *fmt, va_list args)
auto void write_char (unsigned char ch);
auto void write_str (const char *s);
auto void write_fill (const char ch, int n);
void write_char (unsigned char ch)
{
if (str)
@ -697,7 +667,7 @@ grub_vsprintf (char *str, const char *fmt, va_list args)
for (i = 0; i < n; i++)
write_char (ch);
}
while ((c = *fmt++) != 0)
{
if (c != '%')
@ -707,12 +677,13 @@ grub_vsprintf (char *str, const char *fmt, va_list args)
char tmp[32];
char *p;
unsigned int format1 = 0;
unsigned int format2 = 3;
unsigned int format2 = ~ 0U;
char zerofill = ' ';
int rightfill = 0;
int n;
int longfmt = 0;
int longlongfmt = 0;
int unsig = 0;
if (*fmt && *fmt =='-')
{
@ -734,20 +705,22 @@ grub_vsprintf (char *str, const char *fmt, va_list args)
zerofill = '0';
format1 = grub_strtoul (s, 0, 10);
fmt = p;
if (*p && *p == '.')
}
if (*p && *p == '.')
{
p++;
fmt++;
while (*p && grub_isdigit (*p))
p++;
if (p > fmt)
{
p++;
fmt++;
while (*p && grub_isdigit (*p))
p++;
if (p > fmt)
{
char fstr[p - fmt];
grub_strncpy (fstr, fmt, p - fmt);
format2 = grub_strtoul (fstr, 0, 10);
fmt = p;
}
char fstr[p - fmt + 1];
grub_strncpy (fstr, fmt, p - fmt);
fstr[p - fmt] = 0;
format2 = grub_strtoul (fstr, 0, 10);
fmt = p;
}
}
@ -769,9 +742,11 @@ grub_vsprintf (char *str, const char *fmt, va_list args)
write_str ("0x");
c = 'x';
longlongfmt |= (sizeof (void *) == sizeof (long long));
/* fall through */
/* Fall through. */
case 'x':
case 'u':
unsig = 1;
/* Fall through. */
case 'd':
if (longlongfmt)
{
@ -780,13 +755,25 @@ grub_vsprintf (char *str, const char *fmt, va_list args)
ll = va_arg (args, long long);
grub_lltoa (tmp, c, ll);
}
else if (longfmt && unsig)
{
unsigned long l = va_arg (args, unsigned long);
grub_lltoa (tmp, c, l);
}
else if (longfmt)
{
long l = va_arg (args, long);
grub_lltoa (tmp, c, l);
}
else if (unsig)
{
unsigned u = va_arg (args, unsigned);
grub_lltoa (tmp, c, u);
}
else
{
if (longfmt)
n = va_arg (args, long);
else
n = va_arg (args, int);
grub_itoa (tmp, c, n);
n = va_arg (args, int);
grub_lltoa (tmp, c, n);
}
if (! rightfill && grub_strlen (tmp) < format1)
write_fill (zerofill, format1 - grub_strlen (tmp));
@ -794,31 +781,18 @@ grub_vsprintf (char *str, const char *fmt, va_list args)
if (rightfill && grub_strlen (tmp) < format1)
write_fill (zerofill, format1 - grub_strlen (tmp));
break;
case 'c':
n = va_arg (args, int);
write_char (n & 0xff);
break;
case 'f':
{
float f;
f = va_arg (args, double);
grub_ftoa (tmp, f, format2);
if (!rightfill && grub_strlen (tmp) < format1)
write_fill (zerofill, format1 - grub_strlen (tmp));
write_str (tmp);
if (rightfill && grub_strlen (tmp) < format1)
write_fill (zerofill, format1 - grub_strlen (tmp));
break;
}
case 'C':
{
grub_uint32_t code = va_arg (args, grub_uint32_t);
int shift;
unsigned mask;
if (code <= 0x7f)
{
shift = 0;
@ -857,7 +831,7 @@ grub_vsprintf (char *str, const char *fmt, va_list args)
}
write_char (mask | (code >> shift));
for (shift -= 6; shift >= 0; shift -= 6)
write_char (0x80 | (0x3f & (code >> shift)));
}
@ -867,17 +841,23 @@ grub_vsprintf (char *str, const char *fmt, va_list args)
p = va_arg (args, char *);
if (p)
{
if (!rightfill && grub_strlen (p) < format1)
write_fill (zerofill, format1 - grub_strlen (p));
write_str (p);
if (rightfill && grub_strlen (p) < format1)
write_fill (zerofill, format1 - grub_strlen (p));
grub_size_t len = 0;
while (len < format2 && p[len])
len++;
if (!rightfill && len < format1)
write_fill (zerofill, format1 - len);
grub_size_t i;
for (i = 0; i < len; i++)
write_char (*p++);
if (rightfill && len < format1)
write_fill (zerofill, format1 - len);
}
else
write_str ("(null)");
break;
default:
@ -892,7 +872,7 @@ grub_vsprintf (char *str, const char *fmt, va_list args)
if (count && !str)
grub_refresh ();
return count;
}
@ -901,7 +881,7 @@ grub_sprintf (char *str, const char *fmt, ...)
{
va_list ap;
int ret;
va_start (ap, fmt);
ret = grub_vsprintf (str, fmt, ap);
va_end (ap);
@ -909,90 +889,36 @@ grub_sprintf (char *str, const char *fmt, ...)
return ret;
}
/* Convert UTF-16 to UTF-8. */
grub_uint8_t *
grub_utf16_to_utf8 (grub_uint8_t *dest, grub_uint16_t *src,
grub_size_t size)
{
grub_uint32_t code_high = 0;
while (size--)
{
grub_uint32_t code = *src++;
if (code_high)
{
if (code >= 0xDC00 && code <= 0xDFFF)
{
/* Surrogate pair. */
code = ((code_high - 0xD800) << 12) + (code - 0xDC00) + 0x10000;
*dest++ = (code >> 18) | 0xF0;
*dest++ = ((code >> 12) & 0x3F) | 0x80;
*dest++ = ((code >> 6) & 0x3F) | 0x80;
*dest++ = (code & 0x3F) | 0x80;
}
else
{
/* Error... */
*dest++ = '?';
}
code_high = 0;
}
else
{
if (code <= 0x007F)
*dest++ = code;
else if (code <= 0x07FF)
{
*dest++ = (code >> 6) | 0xC0;
*dest++ = (code & 0x3F) | 0x80;
}
else if (code >= 0xD800 && code <= 0xDBFF)
{
code_high = code;
continue;
}
else if (code >= 0xDC00 && code <= 0xDFFF)
{
/* Error... */
*dest++ = '?';
}
else
{
*dest++ = (code >> 12) | 0xE0;
*dest++ = ((code >> 6) & 0x3F) | 0x80;
*dest++ = (code & 0x3F) | 0x80;
}
}
}
return dest;
}
/* Convert an UTF-8 string to an UCS-4 string. Return the number of
characters converted. DEST must be able to hold at least SIZE
characters (when the input is unknown). If an invalid sequence is found,
return -1. */
grub_ssize_t
grub_utf8_to_ucs4 (grub_uint32_t *dest, const grub_uint8_t *src,
grub_size_t size)
/* Convert a (possibly null-terminated) UTF-8 string of at most SRCSIZE
bytes (if SRCSIZE is -1, it is ignored) in length to a UCS-4 string.
Return the number of characters converted. DEST must be able to hold
at least DESTSIZE characters.
If SRCEND is not NULL, then *SRCEND is set to the next byte after the
last byte used in SRC. */
grub_size_t
grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize,
const grub_uint8_t *src, grub_size_t srcsize,
const grub_uint8_t **srcend)
{
grub_uint32_t *p = dest;
int count = 0;
grub_uint32_t code = 0;
while (size--)
if (srcend)
*srcend = src;
while (srcsize && destsize)
{
grub_uint32_t c = *src++;
if (srcsize != (grub_size_t)-1)
srcsize--;
if (count)
{
if ((c & 0xc0) != 0x80)
{
/* invalid */
return -1;
code = '?';
count = 0;
}
else
{
@ -1003,6 +929,9 @@ grub_utf8_to_ucs4 (grub_uint32_t *dest, const grub_uint8_t *src,
}
else
{
if (c == 0)
break;
if ((c & 0x80) == 0x00)
code = c;
else if ((c & 0xe0) == 0xc0)
@ -1031,39 +960,52 @@ grub_utf8_to_ucs4 (grub_uint32_t *dest, const grub_uint8_t *src,
code = c & 0x01;
}
else
/* invalid */
return -1;
{
/* invalid */
code = '?';
count = 0;
}
}
if (count == 0)
*p++ = code;
{
*p++ = code;
destsize--;
}
}
if (srcend)
*srcend = src;
return p - dest;
}
void
grub_millisleep_generic (grub_uint32_t ms)
{
grub_uint32_t end_at;
end_at = grub_get_rtc () + grub_div_roundup (ms * GRUB_TICKS_PER_SECOND, 1000);
while (grub_get_rtc () < end_at)
grub_cpu_idle ();
}
/* Abort GRUB. This function does not return. */
void
grub_abort (void)
{
if (grub_term_get_current ())
grub_printf ("\nAborted.");
#ifndef GRUB_UTIL
if (grub_term_inputs)
#endif
{
grub_printf ("\nAborted. Press any key to exit.");
grub_printf (" Press any key to exit.");
grub_getkey ();
}
grub_exit ();
}
#ifndef APPLE_CC
/* GCC emits references to abort(). */
void abort (void) __attribute__ ((alias ("grub_abort")));
#endif
#ifdef NEED_ENABLE_EXECUTE_STACK
/* Some gcc versions generate a call to this function
in trampolines for nested functions. */
void __enable_execute_stack (void *addr __attribute__ ((unused)))
{
}
#endif

132
kern/mm.c
View file

@ -1,7 +1,7 @@
/* mm.c - functions for memory manager */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2005,2007 Free Software Foundation, Inc.
* Copyright (C) 2002,2005,2007,2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -68,6 +68,7 @@
#ifdef MM_DEBUG
# undef grub_malloc
# undef grub_zalloc
# undef grub_realloc
# undef grub_free
# undef grub_memalign
@ -129,7 +130,7 @@ get_header_from_pointer (void *ptr, grub_mm_header_t *p, grub_mm_region_t *r)
if (! *r)
grub_fatal ("out of range pointer %p", ptr);
*p = (grub_mm_header_t) ptr - 1;
if ((*p)->magic != GRUB_MM_ALLOC_MAGIC)
grub_fatal ("alloc magic is broken at %p", *p);
@ -155,7 +156,7 @@ grub_mm_init_region (void *addr, grub_size_t size)
r = (grub_mm_region_t) (((grub_addr_t) addr + GRUB_MM_ALIGN - 1)
& (~(GRUB_MM_ALIGN - 1)));
size -= (char *) r - (char *) addr + sizeof (*r);
h = (grub_mm_header_t) ((char *) r + GRUB_MM_ALIGN);
h->next = h;
h->magic = GRUB_MM_FREE_MAGIC;
@ -170,22 +171,26 @@ grub_mm_init_region (void *addr, grub_size_t size)
for (p = &base, q = *p; q; p = &(q->next), q = *p)
if (q->size > r->size)
break;
*p = r;
r->next = q;
}
/* Allocate the number of units N with the alignment ALIGN from the ring
buffer starting from *FIRST. ALIGN must be a power of two. Return a
non-NULL if successful, otherwise return NULL. */
buffer starting from *FIRST. ALIGN must be a power of two. Both N and
ALIGN are in units of GRUB_MM_ALIGN. Return a non-NULL if successful,
otherwise return NULL. */
static void *
grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
{
grub_mm_header_t p, q;
/* When everything is allocated side effect is that *first will have alloc
magic marked, meaning that there is no room in this region. */
if ((*first)->magic == GRUB_MM_ALLOC_MAGIC)
return 0;
/* Try to search free slot for allocation in this memory region. */
for (q = *first, p = q->next; ; q = p, p = p->next)
{
grub_off_t extra;
@ -204,11 +209,37 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
{
if (extra == 0 && p->size == n)
{
/* There is no special alignment requirement and memory block
is complete match.
1. Just mark memory block as allocated and remove it from
free list.
Result:
+---------------+ previous block's next
| alloc, size=n | |
+---------------+ v
*/
q->next = p->next;
p->magic = GRUB_MM_ALLOC_MAGIC;
}
else if (extra == 0 || p->size == n + extra)
{
/* There might be alignment requirement, when taking it into
account memory block fits in.
1. Allocate new area at end of memory block.
2. Reduce size of available blocks from original node.
3. Mark new area as allocated and "remove" it from free
list.
Result:
+---------------+
| free, size-=n | next --+
+---------------+ |
| alloc, size=n | |
+---------------+ v
*/
p->size -= n;
p += p->size;
p->size = n;
@ -216,13 +247,32 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
}
else
{
/* There is alignment requirement and there is room in memory
block. Split memory block to three pieces.
1. Create new memory block right after section being
allocated. Mark it as free.
2. Add new memory block to free chain.
3. Mark current memory block having only extra blocks.
4. Advance to aligned block and mark that as allocated and
"remove" it from free list.
Result:
+------------------------------+
| free, size=extra | next --+
+------------------------------+ |
| alloc, size=n | |
+------------------------------+ |
| free, size=orig.size-extra-n | <------+, next --+
+------------------------------+ v
*/
grub_mm_header_t r;
r = p + extra + n;
r->magic = GRUB_MM_FREE_MAGIC;
r->size = p->size - extra - n;
r->next = p->next;
p->size = extra;
p->next = r;
p += extra;
@ -230,11 +280,15 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
p->magic = GRUB_MM_ALLOC_MAGIC;
}
/* Mark find as a start marker for next allocation to fasten it.
This will have side effect of fragmenting memory as small
pieces before this will be un-used. */
*first = q;
return p + 1;
}
/* Search was completed without result. */
if (p == *first)
break;
}
@ -249,17 +303,17 @@ grub_memalign (grub_size_t align, grub_size_t size)
grub_mm_region_t r;
grub_size_t n = ((size + GRUB_MM_ALIGN - 1) >> GRUB_MM_ALIGN_LOG2) + 1;
int count = 0;
align = (align >> GRUB_MM_ALIGN_LOG2);
if (align == 0)
align = 1;
again:
for (r = base; r; r = r->next)
{
void *p;
p = grub_real_malloc (&(r->first), n, align);
if (p)
return p;
@ -273,7 +327,7 @@ grub_memalign (grub_size_t align, grub_size_t size)
grub_disk_cache_invalidate_all ();
count++;
goto again;
case 1:
/* Unload unneeded modules. */
grub_dl_unload_unneeded ();
@ -283,7 +337,7 @@ grub_memalign (grub_size_t align, grub_size_t size)
default:
break;
}
grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
return 0;
}
@ -295,6 +349,19 @@ grub_malloc (grub_size_t size)
return grub_memalign (0, size);
}
/* Allocate SIZE bytes, clear them and return the pointer. */
void *
grub_zalloc (grub_size_t size)
{
void *ret;
ret = grub_memalign (0, size);
if (ret)
grub_memset (ret, 0, size);
return ret;
}
/* Deallocate the pointer PTR. */
void
grub_free (void *ptr)
@ -326,12 +393,12 @@ grub_free (void *ptr)
}
while (q != r->first);
#endif
for (q = r->first; q >= p || q->next <= p; q = q->next)
{
if (q->magic != GRUB_MM_FREE_MAGIC)
grub_fatal ("free magic is broken at %p: 0x%x", q, q->magic);
if (q >= q->next && (q < p || q->next > p))
break;
}
@ -339,7 +406,7 @@ grub_free (void *ptr)
p->magic = GRUB_MM_FREE_MAGIC;
p->next = q->next;
q->next = p;
if (p + p->size == p->next)
{
if (p->next == q)
@ -349,7 +416,7 @@ grub_free (void *ptr)
p->size += p->next->size;
p->next = p->next->next;
}
if (q + q->size == p)
{
p->magic = 0;
@ -370,7 +437,7 @@ grub_realloc (void *ptr, grub_size_t size)
grub_mm_region_t r;
void *q;
grub_size_t n;
if (! ptr)
return grub_malloc (size);
@ -383,14 +450,14 @@ grub_realloc (void *ptr, grub_size_t size)
/* FIXME: Not optimal. */
n = ((size + GRUB_MM_ALIGN - 1) >> GRUB_MM_ALIGN_LOG2) + 1;
get_header_from_pointer (ptr, &p, &r);
if (p->size >= n)
return ptr;
q = grub_malloc (size);
if (! q)
return q;
grub_memcpy (q, ptr, size);
grub_free (ptr);
return q;
@ -434,7 +501,7 @@ grub_mm_dump (unsigned lineno)
for (r = base; r; r = r->next)
{
grub_mm_header_t p;
for (p = (grub_mm_header_t) ((r->addr + GRUB_MM_ALIGN - 1)
& (~(GRUB_MM_ALIGN - 1)));
(grub_addr_t) p < r->addr + r->size;
@ -462,13 +529,26 @@ grub_debug_malloc (const char *file, int line, grub_size_t size)
void *ptr;
if (grub_mm_debug)
grub_printf ("%s:%d: malloc (0x%x) = ", file, line, size);
grub_printf ("%s:%d: malloc (0x%zx) = ", file, line, size);
ptr = grub_malloc (size);
if (grub_mm_debug)
grub_printf ("%p\n", ptr);
return ptr;
}
void *
grub_debug_zalloc (const char *file, int line, grub_size_t size)
{
void *ptr;
if (grub_mm_debug)
grub_printf ("%s:%d: zalloc (0x%zx) = ", file, line, size);
ptr = grub_zalloc (size);
if (grub_mm_debug)
grub_printf ("%p\n", ptr);
return ptr;
}
void
grub_debug_free (const char *file, int line, void *ptr)
{
@ -481,7 +561,7 @@ void *
grub_debug_realloc (const char *file, int line, void *ptr, grub_size_t size)
{
if (grub_mm_debug)
grub_printf ("%s:%d: realloc (%p, 0x%x) = ", file, line, ptr, size);
grub_printf ("%s:%d: realloc (%p, 0x%zx) = ", file, line, ptr, size);
ptr = grub_realloc (ptr, size);
if (grub_mm_debug)
grub_printf ("%p\n", ptr);
@ -493,9 +573,9 @@ grub_debug_memalign (const char *file, int line, grub_size_t align,
grub_size_t size)
{
void *ptr;
if (grub_mm_debug)
grub_printf ("%s:%d: memalign (0x%x, 0x%x) = ",
grub_printf ("%s:%d: memalign (0x%zx, 0x%zx) = ",
file, line, align, size);
ptr = grub_memalign (align, size);
if (grub_mm_debug)

View file

@ -1,7 +1,7 @@
/* parser.c - the part of the parser that can return partial tokens */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2005,2007 Free Software Foundation, Inc.
* Copyright (C) 2005,2007,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -47,8 +47,8 @@ static struct grub_parser_state_transition state_transitions[] =
{ GRUB_PARSER_STATE_QVAR, GRUB_PARSER_STATE_QVARNAME2, '{', 0},
{ GRUB_PARSER_STATE_QVAR, GRUB_PARSER_STATE_QVARNAME, 0, 1},
{ GRUB_PARSER_STATE_QVARNAME, GRUB_PARSER_STATE_DQUOTE, ' ', 1},
{ GRUB_PARSER_STATE_QVARNAME, GRUB_PARSER_STATE_TEXT, '\"', 0},
{ GRUB_PARSER_STATE_QVARNAME, GRUB_PARSER_STATE_DQUOTE, ' ', 1},
{ GRUB_PARSER_STATE_QVARNAME2, GRUB_PARSER_STATE_DQUOTE, '}', 0},
{ 0, 0, 0, 0}
@ -60,9 +60,7 @@ grub_parser_state_t
grub_parser_cmdline_state (grub_parser_state_t state, char c, char *result)
{
struct grub_parser_state_transition *transition;
struct grub_parser_state_transition *next_match = 0;
struct grub_parser_state_transition default_transition;
int found = 0;
default_transition.to_state = state;
default_transition.keep_value = 1;
@ -70,26 +68,24 @@ grub_parser_cmdline_state (grub_parser_state_t state, char c, char *result)
/* Look for a good translation. */
for (transition = state_transitions; transition->from_state; transition++)
{
if (transition->from_state != state)
continue;
/* An exact match was found, use it. */
if (transition->from_state == state && transition->input == c)
{
found = 1;
break;
}
if (transition->input == c)
break;
if (transition->input == ' ' && ! grub_isalpha (c)
&& ! grub_isdigit (c) && c != '_')
break;
/* A less perfect match was found, use this one if no exact
match can be found. */
if (transition->from_state == state && transition->input == 0)
next_match = transition;
if (transition->input == 0)
break;
}
if (! found)
{
if (next_match)
transition = next_match;
else
transition = &default_transition;
}
if (! transition->from_state)
transition = &default_transition;
if (transition->keep_value)
*result = c;
@ -100,7 +96,7 @@ grub_parser_cmdline_state (grub_parser_state_t state, char c, char *result)
grub_err_t
grub_parser_split_cmdline (const char *cmdline, grub_err_t (*getline) (char **),
grub_parser_split_cmdline (const char *cmdline, grub_reader_getline_t getline,
int *argc, char ***argv)
{
grub_parser_state_t state = GRUB_PARSER_STATE_TEXT;
@ -140,27 +136,30 @@ grub_parser_split_cmdline (const char *cmdline, grub_err_t (*getline) (char **),
vp = varname;
if (! val)
return;
/* Insert the contents of the variable in the buffer. */
for (; *val; val++)
*(bp++) = *val;
}
*argc = 1;
*argc = 0;
do
{
if (! *rd)
if (! rd || !*rd)
{
if (getline)
getline (&rd);
getline (&rd, 1);
else break;
}
if (!rd)
break;
for (; *rd; rd++)
{
grub_parser_state_t newstate;
char use;
newstate = grub_parser_cmdline_state (state, *rd, &use);
/* If a variable was being processed and this character does
@ -192,19 +191,23 @@ grub_parser_split_cmdline (const char *cmdline, grub_err_t (*getline) (char **),
state = newstate;
}
} while (state != GRUB_PARSER_STATE_TEXT && !check_varstate (state));
*(bp++) = '\0';
/* A special case for when the last character was part of a
variable. */
add_var (GRUB_PARSER_STATE_TEXT);
if (bp != buffer && *(bp - 1))
{
*(bp++) = '\0';
(*argc)++;
}
/* Reserve memory for the return values. */
args = grub_malloc (bp - buffer);
if (! args)
return grub_errno;
grub_memcpy (args, buffer, bp - buffer);
*argv = grub_malloc (sizeof (char *) * (*argc + 1));
if (! *argv)
{
@ -223,7 +226,49 @@ grub_parser_split_cmdline (const char *cmdline, grub_err_t (*getline) (char **),
bp++;
}
(*argc)--;
return 0;
}
struct grub_handler_class grub_parser_class =
{
.name = "parser"
};
grub_err_t
grub_parser_execute (char *source)
{
auto grub_err_t getline (char **line, int cont);
grub_err_t getline (char **line, int cont __attribute__ ((unused)))
{
char *p;
if (! source)
{
*line = 0;
return 0;
}
p = grub_strchr (source, '\n');
if (p)
*p = 0;
*line = grub_strdup (source);
if (p)
*p = '\n';
source = p ? p + 1 : 0;
return 0;
}
while (source)
{
char *line;
grub_parser_t parser;
getline (&line, 0);
parser = grub_parser_get_current ();
parser->parse_line (line, getline);
grub_free (line);
}
return grub_errno;
}

View file

@ -33,7 +33,7 @@ void
grub_partition_map_unregister (grub_partition_map_t partmap)
{
grub_partition_map_t *p, q;
for (p = &grub_partition_map_list, q = *p; q; p = &(q->next), q = q->next)
if (q == partmap)
{
@ -90,7 +90,7 @@ grub_partition_iterate (struct grub_disk *disk,
{
grub_partition_map_t partmap = 0;
int ret = 0;
auto int part_map_iterate (const grub_partition_map_t p);
auto int part_map_iterate_hook (grub_disk_t d,
const grub_partition_t partition);
@ -100,15 +100,13 @@ grub_partition_iterate (struct grub_disk *disk,
{
return 1;
}
int part_map_iterate (const grub_partition_map_t p)
{
grub_err_t err;
grub_dprintf ("partition", "Detecting %s...\n", p->name);
err = p->iterate (disk, part_map_iterate_hook);
p->iterate (disk, part_map_iterate_hook);
if (err != GRUB_ERR_NONE)
if (grub_errno != GRUB_ERR_NONE)
{
/* Continue to next partition map type. */
grub_dprintf ("partition", "%s detection failed.\n", p->name);
@ -124,7 +122,7 @@ grub_partition_iterate (struct grub_disk *disk,
grub_partition_map_iterate (part_map_iterate);
if (partmap)
ret = partmap->iterate (disk, hook);
return ret;
}

View file

@ -1,7 +1,7 @@
/* dl.c - arch-dependent part of loadable module support */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2004,2005,2007 Free Software Foundation, Inc.
* Copyright (C) 2002,2004,2005,2007,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -26,7 +26,7 @@
grub_err_t
grub_arch_dl_check_header (void *ehdr)
{
Elf32_Ehdr *e = ehdr;
Elf_Ehdr *e = ehdr;
/* Check the magic numbers. */
if (e->e_ident[EI_CLASS] != ELFCLASS32
@ -42,28 +42,26 @@ grub_arch_dl_check_header (void *ehdr)
grub_err_t
grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
{
Elf32_Ehdr *e = ehdr;
Elf32_Shdr *s;
Elf32_Sym *symtab;
Elf32_Word entsize;
Elf_Ehdr *e = ehdr;
Elf_Shdr *s;
Elf_Word entsize;
unsigned i;
/* Find a symbol table. */
for (i = 0, s = (Elf32_Shdr *) ((char *) e + e->e_shoff);
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf32_Shdr *) ((char *) s + e->e_shentsize))
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
if (s->sh_type == SHT_SYMTAB)
break;
if (i == e->e_shnum)
return grub_error (GRUB_ERR_BAD_MODULE, "no symtab found");
symtab = (Elf32_Sym *) ((char *) e + s->sh_offset);
entsize = s->sh_entsize;
for (i = 0, s = (Elf32_Shdr *) ((char *) e + e->e_shoff);
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf32_Shdr *) ((char *) s + e->e_shentsize))
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
if (s->sh_type == SHT_RELA)
{
grub_dl_segment_t seg;
@ -75,64 +73,64 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
if (seg)
{
Elf32_Rela *rel, *max;
for (rel = (Elf32_Rela *) ((char *) e + s->sh_offset),
Elf_Rela *rel, *max;
for (rel = (Elf_Rela *) ((char *) e + s->sh_offset),
max = rel + s->sh_size / s->sh_entsize;
rel < max;
rel++)
{
Elf32_Word *addr;
Elf32_Sym *sym;
Elf_Word *addr;
Elf_Sym *sym;
grub_uint32_t value;
if (seg->size < rel->r_offset)
return grub_error (GRUB_ERR_BAD_MODULE,
"reloc offset is out of the segment");
addr = (Elf32_Word *) ((char *) seg->addr + rel->r_offset);
sym = (Elf32_Sym *) ((char *) symtab
+ entsize * ELF32_R_SYM (rel->r_info));
addr = (Elf_Word *) ((char *) seg->addr + rel->r_offset);
sym = (Elf_Sym *) ((char *) mod->symtab
+ entsize * ELF_R_SYM (rel->r_info));
/* On the PPC the value does not have an explicit
addend, add it. */
value = sym->st_value + rel->r_addend;
switch (ELF32_R_TYPE (rel->r_info))
switch (ELF_R_TYPE (rel->r_info))
{
case R_PPC_ADDR16_LO:
*(Elf32_Half *) addr = value;
*(Elf_Half *) addr = value;
break;
case R_PPC_REL24:
{
Elf32_Sword delta = value - (Elf32_Word) addr;
Elf_Sword delta = value - (Elf_Word) addr;
if (delta << 6 >> 6 != delta)
return grub_error (GRUB_ERR_BAD_MODULE, "Relocation overflow");
return grub_error (GRUB_ERR_BAD_MODULE, "relocation overflow");
*addr = (*addr & 0xfc000003) | (delta & 0x3fffffc);
break;
}
case R_PPC_ADDR16_HA:
*(Elf32_Half *) addr = (value + 0x8000) >> 16;
*(Elf_Half *) addr = (value + 0x8000) >> 16;
break;
case R_PPC_ADDR32:
*addr = value;
break;
case R_PPC_REL32:
*addr = value - (Elf32_Word) addr;
*addr = value - (Elf_Word) addr;
break;
default:
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"This relocation (%d) is not implemented yet",
ELF32_R_TYPE (rel->r_info));
"this relocation (%d) is not implemented yet",
ELF_R_TYPE (rel->r_info));
}
}
}
}
return GRUB_ERR_NONE;
}

View file

@ -1,4 +1,4 @@
/* crt0.S - Startup code for the PowerPC. */
/* startup.S - Startup code for the PowerPC. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2003,2004,2005,2007,2008 Free Software Foundation, Inc.
@ -17,13 +17,31 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/symbol.h>
#include <grub/cpu/kernel.h>
.extern __bss_start
.extern _end
.text
.align 2
.globl _start
_start:
.globl start, _start
start:
_start:
b codestart
. = _start + GRUB_KERNEL_CPU_PREFIX
VARIABLE(grub_prefix)
/* to be filled by grub-mkelfimage */
/*
* Leave some breathing room for the prefix.
*/
. = _start + GRUB_KERNEL_CPU_DATA_END
codestart:
li 2, 0
li 13, 0
@ -42,5 +60,5 @@ _start:
lis 9, grub_ieee1275_entry_fn@ha
stw 5, grub_ieee1275_entry_fn@l(9)
bl cmain
bl grub_main
1: b 1b

View file

@ -1,707 +0,0 @@
/* rescue.c - rescue mode */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2003,2005,2007 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <grub/kernel.h>
#include <grub/rescue.h>
#include <grub/term.h>
#include <grub/misc.h>
#include <grub/disk.h>
#include <grub/file.h>
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/loader.h>
#include <grub/dl.h>
#include <grub/partition.h>
#include <grub/env.h>
#include <grub/parser.h>
#define GRUB_RESCUE_BUF_SIZE 256
#define GRUB_RESCUE_MAX_ARGS 20
struct grub_rescue_command
{
const char *name;
void (*func) (int argc, char *argv[]);
const char *message;
struct grub_rescue_command *next;
};
typedef struct grub_rescue_command *grub_rescue_command_t;
static char linebuf[GRUB_RESCUE_BUF_SIZE];
static grub_rescue_command_t grub_rescue_command_list;
void
grub_rescue_register_command (const char *name,
void (*func) (int argc, char *argv[]),
const char *message)
{
grub_rescue_command_t cmd;
cmd = (grub_rescue_command_t) grub_malloc (sizeof (*cmd));
if (! cmd)
return;
cmd->name = name;
cmd->func = func;
cmd->message = message;
cmd->next = grub_rescue_command_list;
grub_rescue_command_list = cmd;
}
void
grub_rescue_unregister_command (const char *name)
{
grub_rescue_command_t *p, q;
for (p = &grub_rescue_command_list, q = *p; q; p = &(q->next), q = q->next)
if (grub_strcmp (name, q->name) == 0)
{
*p = q->next;
grub_free (q);
break;
}
}
/* Prompt to input a command and read the line. */
static void
grub_rescue_get_command_line (const char *prompt)
{
int c;
int pos = 0;
grub_printf (prompt);
grub_memset (linebuf, 0, GRUB_RESCUE_BUF_SIZE);
while ((c = GRUB_TERM_ASCII_CHAR (grub_getkey ())) != '\n' && c != '\r')
{
if (grub_isprint (c))
{
if (pos < GRUB_RESCUE_BUF_SIZE - 1)
{
linebuf[pos++] = c;
grub_putchar (c);
}
}
else if (c == '\b')
{
if (pos > 0)
{
linebuf[--pos] = 0;
grub_putchar (c);
grub_putchar (' ');
grub_putchar (c);
}
}
grub_refresh ();
}
grub_putchar ('\n');
grub_refresh ();
}
/* boot */
static void
grub_rescue_cmd_boot (int argc __attribute__ ((unused)),
char *argv[] __attribute__ ((unused)))
{
grub_loader_boot ();
}
/* cat FILE */
static void
grub_rescue_cmd_cat (int argc, char *argv[])
{
grub_file_t file;
char buf[GRUB_DISK_SECTOR_SIZE];
grub_ssize_t size;
if (argc < 1)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
return;
}
file = grub_file_open (argv[0]);
if (! file)
return;
while ((size = grub_file_read (file, buf, sizeof (buf))) > 0)
{
int i;
for (i = 0; i < size; i++)
{
unsigned char c = buf[i];
if (grub_isprint (c) || grub_isspace (c))
grub_putchar (c);
else
{
grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
grub_printf ("<%x>", (int) c);
grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
}
}
}
grub_putchar ('\n');
grub_refresh ();
grub_file_close (file);
}
static int
grub_rescue_print_devices (const char *name)
{
grub_printf ("(%s) ", name);
return 0;
}
static int
grub_rescue_print_files (const char *filename, int dir)
{
grub_printf ("%s%s ", filename, dir ? "/" : "");
return 0;
}
/* ls [ARG] */
static void
grub_rescue_cmd_ls (int argc, char *argv[])
{
if (argc < 1)
{
grub_device_iterate (grub_rescue_print_devices);
grub_putchar ('\n');
grub_refresh ();
}
else
{
char *device_name;
grub_device_t dev;
grub_fs_t fs;
char *path;
device_name = grub_file_get_device_name (argv[0]);
dev = grub_device_open (device_name);
if (! dev)
goto fail;
fs = grub_fs_probe (dev);
path = grub_strchr (argv[0], ')');
if (! path)
path = argv[0];
else
path++;
if (! path && ! device_name)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid argument");
goto fail;
}
if (! path)
{
if (grub_errno == GRUB_ERR_UNKNOWN_FS)
grub_errno = GRUB_ERR_NONE;
grub_printf ("(%s): Filesystem is %s.\n",
device_name, fs ? fs->name : "unknown");
}
else if (fs)
{
(fs->dir) (dev, path, grub_rescue_print_files);
grub_putchar ('\n');
grub_refresh ();
}
fail:
if (dev)
grub_device_close (dev);
grub_free (device_name);
}
}
/* help */
static void
grub_rescue_cmd_help (int argc __attribute__ ((unused)),
char *argv[] __attribute__ ((unused)))
{
grub_rescue_command_t p, q;
/* Sort the commands. This is not a good algorithm, but this is enough,
because rescue mode has a small number of commands. */
for (p = grub_rescue_command_list; p; p = p->next)
for (q = p->next; q; q = q->next)
if (grub_strcmp (p->name, q->name) > 0)
{
struct grub_rescue_command tmp;
tmp.name = p->name;
tmp.func = p->func;
tmp.message = p->message;
p->name = q->name;
p->func = q->func;
p->message = q->message;
q->name = tmp.name;
q->func = tmp.func;
q->message = tmp.message;
}
/* Print them. */
for (p = grub_rescue_command_list; p; p = p->next)
grub_printf ("%s\t%s\n", p->name, p->message);
}
#if 0
static void
grub_rescue_cmd_info (void)
{
extern void grub_disk_cache_get_performance (unsigned long *,
unsigned long *);
unsigned long hits, misses;
grub_disk_cache_get_performance (&hits, &misses);
grub_printf ("Disk cache: hits = %u, misses = %u ", hits, misses);
if (hits + misses)
{
unsigned long ratio = hits * 10000 / (hits + misses);
grub_printf ("(%u.%u%%)\n", ratio / 100, ratio % 100);
}
else
grub_printf ("(N/A)\n");
}
#endif
/* root [DEVICE] */
static void
grub_rescue_cmd_root (int argc, char *argv[])
{
grub_device_t dev;
grub_fs_t fs;
if (argc > 0)
{
char *device_name = grub_file_get_device_name (argv[0]);
if (! device_name)
return;
grub_env_set ("root", device_name);
grub_free (device_name);
}
dev = grub_device_open (0);
if (! dev)
return;
fs = grub_fs_probe (dev);
if (grub_errno == GRUB_ERR_UNKNOWN_FS)
grub_errno = GRUB_ERR_NONE;
grub_printf ("(%s): Filesystem is %s.\n",
grub_env_get ("root"), fs ? fs->name : "unknown");
grub_device_close (dev);
}
#if 0
static void
grub_rescue_cmd_testload (int argc, char *argv[])
{
grub_file_t file;
char *buf;
grub_ssize_t size;
grub_ssize_t pos;
auto void read_func (unsigned long sector, unsigned offset, unsigned len);
void read_func (unsigned long sector __attribute__ ((unused)),
unsigned offset __attribute__ ((unused)),
unsigned len __attribute__ ((unused)))
{
grub_putchar ('.');
grub_refresh ();
}
if (argc < 1)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
return;
}
file = grub_file_open (argv[0]);
if (! file)
return;
size = grub_file_size (file) & ~(GRUB_DISK_SECTOR_SIZE - 1);
if (size == 0)
{
grub_file_close (file);
return;
}
buf = grub_malloc (size);
if (! buf)
goto fail;
grub_printf ("Reading %s sequentially", argv[0]);
file->read_hook = read_func;
if (grub_file_read (file, buf, size) != size)
goto fail;
grub_printf (" Done.\n");
/* Read sequentially again. */
grub_printf ("Reading %s sequentially again", argv[0]);
if (grub_file_seek (file, 0) < 0)
goto fail;
for (pos = 0; pos < size; pos += GRUB_DISK_SECTOR_SIZE)
{
char sector[GRUB_DISK_SECTOR_SIZE];
if (grub_file_read (file, sector, GRUB_DISK_SECTOR_SIZE)
!= GRUB_DISK_SECTOR_SIZE)
goto fail;
if (grub_memcmp (sector, buf + pos, GRUB_DISK_SECTOR_SIZE) != 0)
{
grub_printf ("\nDiffers in %d\n", pos);
goto fail;
}
}
grub_printf (" Done.\n");
/* Read backwards and compare. */
grub_printf ("Reading %s backwards", argv[0]);
pos = size;
while (pos > 0)
{
char sector[GRUB_DISK_SECTOR_SIZE];
pos -= GRUB_DISK_SECTOR_SIZE;
if (grub_file_seek (file, pos) < 0)
goto fail;
if (grub_file_read (file, sector, GRUB_DISK_SECTOR_SIZE)
!= GRUB_DISK_SECTOR_SIZE)
goto fail;
if (grub_memcmp (sector, buf + pos, GRUB_DISK_SECTOR_SIZE) != 0)
{
int i;
grub_printf ("\nDiffers in %d\n", pos);
for (i = 0; i < GRUB_DISK_SECTOR_SIZE; i++)
grub_putchar (buf[pos + i]);
if (i)
grub_refresh ();
goto fail;
}
}
grub_printf (" Done.\n");
fail:
grub_file_close (file);
grub_free (buf);
}
#endif
/* dump ADDRESS [SIZE] */
static void
grub_rescue_cmd_dump (int argc, char *argv[])
{
grub_uint8_t *addr;
grub_size_t size = 4;
if (argc == 0)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "no address specified");
return;
}
addr = (grub_uint8_t *) grub_strtoul (argv[0], 0, 0);
if (grub_errno)
return;
if (argc > 1)
size = (grub_size_t) grub_strtoul (argv[1], 0, 0);
while (size--)
{
grub_printf ("%x%x ", *addr >> 4, *addr & 0xf);
addr++;
}
}
/* insmod MODULE */
static void
grub_rescue_cmd_insmod (int argc, char *argv[])
{
char *p;
grub_dl_t mod;
if (argc == 0)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified");
return;
}
p = grub_strchr (argv[0], '/');
if (! p)
mod = grub_dl_load (argv[0]);
else
mod = grub_dl_load_file (argv[0]);
if (mod)
grub_dl_ref (mod);
}
/* rmmod MODULE */
static void
grub_rescue_cmd_rmmod (int argc, char *argv[])
{
grub_dl_t mod;
if (argc == 0)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified");
return;
}
mod = grub_dl_get (argv[0]);
if (! mod)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "no such module");
return;
}
if (grub_dl_unref (mod) <= 0)
grub_dl_unload (mod);
}
/* lsmod */
static void
grub_rescue_cmd_lsmod (int argc __attribute__ ((unused)),
char *argv[] __attribute__ ((unused)))
{
auto int print_module (grub_dl_t mod);
int print_module (grub_dl_t mod)
{
grub_dl_dep_t dep;
grub_printf ("%s\t%d\t\t", mod->name, mod->ref_count);
for (dep = mod->dep; dep; dep = dep->next)
{
if (dep != mod->dep)
grub_putchar (',');
grub_printf ("%s", dep->mod->name);
}
grub_putchar ('\n');
grub_refresh ();
return 0;
}
grub_printf ("Name\tRef Count\tDependencies\n");
grub_dl_iterate (print_module);
}
/* set ENVVAR=VALUE */
static void
grub_rescue_cmd_set (int argc, char *argv[])
{
char *var;
char *val;
auto int print_env (struct grub_env_var *env);
int print_env (struct grub_env_var *env)
{
grub_printf ("%s=%s\n", env->name, env->value);
return 0;
}
if (argc < 1)
{
grub_env_iterate (print_env);
return;
}
var = argv[0];
val = grub_strchr (var, '=');
if (! val)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "not an assignment");
return;
}
val[0] = 0;
grub_env_set (var, val + 1);
val[0] = '=';
}
static void
grub_rescue_cmd_unset (int argc, char *argv[])
{
if (argc < 1)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "no environment variable specified");
return;
}
grub_env_unset (argv[0]);
}
/* exit */
static void
grub_rescue_cmd_exit (int argc __attribute__ ((unused)),
char *argv[] __attribute__ ((unused)))
{
grub_exit ();
}
static void
attempt_normal_mode (void)
{
grub_rescue_command_t cmd;
for (cmd = grub_rescue_command_list; cmd; cmd = cmd->next)
{
if (grub_strcmp ("normal", cmd->name) == 0)
{
(cmd->func) (0, 0);
break;
}
}
}
/* Enter the rescue mode. */
void
grub_enter_rescue_mode (void)
{
auto grub_err_t getline (char **line);
grub_err_t getline (char **line)
{
grub_rescue_get_command_line ("> ");
*line = linebuf;
return 0;
}
/* First of all, attempt to execute the normal mode. */
attempt_normal_mode ();
grub_printf ("Entering into rescue mode...\n");
grub_rescue_register_command ("boot", grub_rescue_cmd_boot,
"boot an operating system");
grub_rescue_register_command ("cat", grub_rescue_cmd_cat,
"show the contents of a file");
grub_rescue_register_command ("help", grub_rescue_cmd_help,
"show this message");
grub_rescue_register_command ("ls", grub_rescue_cmd_ls,
"list devices or files");
grub_rescue_register_command ("root", grub_rescue_cmd_root,
"set the root device");
grub_rescue_register_command ("dump", grub_rescue_cmd_dump,
"dump memory");
grub_rescue_register_command ("insmod", grub_rescue_cmd_insmod,
"insert a module");
grub_rescue_register_command ("rmmod", grub_rescue_cmd_rmmod,
"remove a module");
grub_rescue_register_command ("lsmod", grub_rescue_cmd_lsmod,
"show loaded modules");
grub_rescue_register_command ("set", grub_rescue_cmd_set,
"set an environment variable");
grub_rescue_register_command ("unset", grub_rescue_cmd_unset,
"remove an environment variable");
grub_rescue_register_command ("exit", grub_rescue_cmd_exit,
"exit from GRUB");
while (1)
{
char *line = linebuf;
char *name;
int n;
grub_rescue_command_t cmd;
char **args;
/* Print an error, if any. */
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
/* Get a command line. */
grub_rescue_get_command_line ("grub rescue> ");
if (grub_parser_split_cmdline (line, getline, &n, &args) || n < 0)
continue;
/* In case of an assignment set the environment accordingly
instead of calling a function. */
if (n == 0 && grub_strchr (line, '='))
{
char *val = grub_strchr (args[0], '=');
val[0] = 0;
grub_env_set (args[0], val + 1);
val[0] = '=';
grub_free (args[0]);
continue;
}
/* Get the command name. */
name = args[0];
/* If nothing is specified, restart. */
if (*name == '\0')
{
grub_free (args[0]);
continue;
}
/* Find the command and execute it. */
for (cmd = grub_rescue_command_list; cmd; cmd = cmd->next)
{
if (grub_strcmp (name, cmd->name) == 0)
{
(cmd->func) (n, &args[1]);
break;
}
}
/* If not found, print an error message. */
if (! cmd)
{
grub_printf ("Unknown command `%s'\n", name);
grub_printf ("Try `help' for usage\n");
}
grub_free (args[0]);
}
}

88
kern/rescue_parser.c Normal file
View file

@ -0,0 +1,88 @@
/* rescue_parser.c - rescue mode parser */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <grub/types.h>
#include <grub/mm.h>
#include <grub/env.h>
#include <grub/parser.h>
#include <grub/misc.h>
#include <grub/command.h>
static grub_err_t
grub_rescue_parse_line (char *line, grub_reader_getline_t getline)
{
char *name;
int n;
grub_command_t cmd;
char **args;
if (grub_parser_split_cmdline (line, getline, &n, &args) || n < 0)
return grub_errno;
if (n == 0)
return GRUB_ERR_NONE;
/* In case of an assignment set the environment accordingly
instead of calling a function. */
if (n == 1 && grub_strchr (line, '='))
{
char *val = grub_strchr (args[0], '=');
val[0] = 0;
grub_env_set (args[0], val + 1);
val[0] = '=';
goto quit;
}
/* Get the command name. */
name = args[0];
/* If nothing is specified, restart. */
if (*name == '\0')
goto quit;
cmd = grub_command_find (name);
if (cmd)
{
(cmd->func) (cmd, n - 1, &args[1]);
}
else
{
grub_printf ("Unknown command `%s'\n", name);
if (grub_command_find ("help"))
grub_printf ("Try `help' for usage\n");
}
quit:
grub_free (args[0]);
grub_free (args);
return grub_errno;
}
static struct grub_parser grub_rescue_parser =
{
.name = "rescue",
.parse_line = grub_rescue_parse_line
};
void
grub_register_rescue_parser (void)
{
grub_parser_register ("rescue", &grub_rescue_parser);
}

92
kern/rescue_reader.c Normal file
View file

@ -0,0 +1,92 @@
/* rescue_reader.c - rescue mode reader */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009,2010 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <grub/types.h>
#include <grub/reader.h>
#include <grub/parser.h>
#include <grub/misc.h>
#include <grub/term.h>
#include <grub/mm.h>
#define GRUB_RESCUE_BUF_SIZE 256
static char linebuf[GRUB_RESCUE_BUF_SIZE];
/* Prompt to input a command and read the line. */
static grub_err_t
grub_rescue_read_line (char **line, int cont)
{
int c;
int pos = 0;
grub_printf ((cont) ? "> " : "grub rescue> ");
grub_memset (linebuf, 0, GRUB_RESCUE_BUF_SIZE);
while ((c = GRUB_TERM_ASCII_CHAR (grub_getkey ())) != '\n' && c != '\r')
{
if (grub_isprint (c))
{
if (pos < GRUB_RESCUE_BUF_SIZE - 1)
{
linebuf[pos++] = c;
grub_putchar (c);
}
}
else if (c == '\b')
{
if (pos > 0)
{
linebuf[--pos] = 0;
grub_putchar (c);
grub_putchar (' ');
grub_putchar (c);
}
}
grub_refresh ();
}
grub_putchar ('\n');
grub_refresh ();
*line = grub_strdup (linebuf);
return 0;
}
void
grub_rescue_run (void)
{
grub_printf ("Entering rescue mode...\n");
while (1)
{
char *line;
/* Print an error, if any. */
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
grub_rescue_read_line (&line, 0);
if (! line || line[0] == '\0')
continue;
grub_parser_get_current ()->parse_line (line, grub_rescue_read_line);
grub_free (line);
}
}

View file

@ -1,7 +1,7 @@
/* cache.S - Flush the processor cache for a specific region. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2005,2007 Free Software Foundation, Inc.
* Copyright (C) 2005,2007,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -27,17 +27,15 @@
* void grub_arch_sync_caches (void *address, grub_size_t len)
*/
FUNCTION(grub_arch_sync_caches)
save %o6, -0xC, %o6 ! Get a new register window,
! reserve space on stack for
! %i0, %i1, %i2
brz,pn %i0, return ! Return if address == 0.
nop
brz,pn %i1, return ! Return if len == 0.
clr %i2 ! index = 0.
loop: flush %i0 + %i2 ! Flush address + index.
cmp %i1, %i2 ! Compare len & index .
bpos,a,pt %xcc, loop ! If len > index, loop.
add %i2, 8, %i2 ! Go to next doubleword.
return: ret ! Restore caller's register
restore ! window and return.
brz,pn %o1, 2f
add %o0, %o1, %o1
add %o1, 7, %o1
andn %o1, 7, %o1
andn %o0, 7, %o0
sub %o1, %o0, %o1
1: subcc %o1, 8, %o1
bne,pt %icc, 1b
flush %o0 + %o1
2: retl
nop

View file

@ -1,7 +1,7 @@
/* dl.c - arch-dependent part of loadable module support */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2004,2005,2007 Free Software Foundation, Inc.
* Copyright (C) 2002,2004,2005,2007,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -26,7 +26,7 @@
grub_err_t
grub_arch_dl_check_header (void *ehdr)
{
Elf64_Ehdr *e = ehdr;
Elf_Ehdr *e = ehdr;
/* Check the magic numbers. */
if (e->e_ident[EI_CLASS] != ELFCLASS64
@ -42,28 +42,26 @@ grub_arch_dl_check_header (void *ehdr)
grub_err_t
grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
{
Elf64_Ehdr *e = ehdr;
Elf64_Shdr *s;
Elf64_Sym *symtab;
Elf64_Word entsize;
Elf_Ehdr *e = ehdr;
Elf_Shdr *s;
Elf_Word entsize;
unsigned i;
/* Find a symbol table. */
for (i = 0, s = (Elf64_Shdr *) ((char *) e + e->e_shoff);
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf64_Shdr *) ((char *) s + e->e_shentsize))
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
if (s->sh_type == SHT_SYMTAB)
break;
if (i == e->e_shnum)
return grub_error (GRUB_ERR_BAD_MODULE, "no symtab found");
symtab = (Elf64_Sym *) ((char *) e + s->sh_offset);
entsize = s->sh_entsize;
for (i = 0, s = (Elf64_Shdr *) ((char *) e + e->e_shoff);
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf64_Shdr *) ((char *) s + e->e_shentsize))
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
if (s->sh_type == SHT_RELA)
{
grub_dl_segment_t seg;
@ -75,64 +73,70 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
if (seg)
{
Elf64_Rela *rel, *max;
for (rel = (Elf64_Rela *) ((char *) e + s->sh_offset),
Elf_Rela *rel, *max;
for (rel = (Elf_Rela *) ((char *) e + s->sh_offset),
max = rel + s->sh_size / s->sh_entsize;
rel < max;
rel++)
{
Elf64_Word *addr;
Elf64_Sym *sym;
Elf64_Addr value;
Elf_Word *addr;
Elf_Sym *sym;
Elf_Addr value;
if (seg->size < rel->r_offset)
return grub_error (GRUB_ERR_BAD_MODULE,
"reloc offset is out of the segment");
addr = (Elf64_Word *) ((char *) seg->addr + rel->r_offset);
sym = (Elf64_Sym *) ((char *) symtab
+ entsize * ELF64_R_SYM (rel->r_info));
addr = (Elf_Word *) ((char *) seg->addr + rel->r_offset);
sym = (Elf_Sym *) ((char *) mod->symtab
+ entsize * ELF_R_SYM (rel->r_info));
value = sym->st_value + rel->r_addend;
switch (ELF64_R_TYPE (rel->r_info))
switch (ELF_R_TYPE (rel->r_info) & 0xff)
{
case R_SPARC_32: /* 3 V-word32 */
if (value & 0xFFFFFFFF00000000)
return grub_error (GRUB_ERR_BAD_MODULE,
"Address out of 32 bits range");
"address out of 32 bits range");
*addr = value;
break;
case R_SPARC_WDISP30: /* 7 V-disp30 */
if (((value - (Elf64_Addr) addr) & 0xFFFFFFFF00000000) &&
((value - (Elf64_Addr) addr) & 0xFFFFFFFF00000000
!= 0xFFFFFFFF00000000))
if (((value - (Elf_Addr) addr) & 0xFFFFFFFF00000000) &&
(((value - (Elf_Addr) addr) & 0xFFFFFFFF00000000)
!= 0xFFFFFFFF00000000))
return grub_error (GRUB_ERR_BAD_MODULE,
"Displacement out of 30 bits range");
"displacement out of 30 bits range");
*addr = (*addr & 0xC0000000) |
(((grub_int32_t) ((value - (Elf64_Addr) addr) >> 2)) &
(((grub_int32_t) ((value - (Elf_Addr) addr) >> 2)) &
0x3FFFFFFF);
break;
case R_SPARC_HI22: /* 9 V-imm22 */
if (((grub_int32_t) value) & 0xFF00000000)
return grub_error (GRUB_ERR_BAD_MODULE,
"High address out of 22 bits range");
"high address out of 22 bits range");
*addr = (*addr & 0xFFC00000) | ((value >> 10) & 0x3FFFFF);
break;
case R_SPARC_LO10: /* 12 T-simm13 */
*addr = (*addr & 0xFFFFFC00) | (value & 0x3FF);
break;
case R_SPARC_64: /* 32 V-xwords64 */
*(Elf64_Xword *) addr = value;
*(Elf_Xword *) addr = value;
break;
case R_SPARC_OLO10:
*addr = (*addr & ~0x1fff)
| (((value & 0x3ff) +
(ELF_R_TYPE (rel->r_info) >> 8))
& 0x1fff);
break;
default:
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"This relocation (%d) is not implemented yet",
ELF64_R_TYPE (rel->r_info));
"this relocation (%d) is not implemented yet",
ELF_R_TYPE (rel->r_info));
}
}
}
}
return GRUB_ERR_NONE;
}

View file

@ -0,0 +1,77 @@
/* crt0.S - Startup code for the Sparc64. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <grub/symbol.h>
#include <grub/machine/kernel.h>
.text
.align 4
.globl _start
_start:
ba codestart
nop
. = EXT_C(_start) + GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE
VARIABLE(grub_total_module_size)
.word 0
VARIABLE(grub_kernel_image_size)
.word 0
VARIABLE(grub_compressed_size)
.word 0
VARIABLE(grub_prefix)
/* to be filled by grub-mkimage */
/*
* Leave some breathing room for the prefix.
*/
. = EXT_C(_start) + GRUB_KERNEL_MACHINE_DATA_END
codestart:
/* Copy the modules past the end of the kernel image.
* They are currently sitting in the BSS.
*/
sethi %hi(__bss_start), %o2
or %o2, %lo(__bss_start), %o2
sethi %hi(_end), %o3
or %o3, %lo(_end), %o3
sethi %hi(grub_total_module_size), %o4
lduw [%o4 + %lo(grub_total_module_size)], %o4
1: lduw [%o2], %o5
stw %o5, [%o3]
subcc %o4, 4, %o4
add %o2, 4, %o2
bne,pt %icc, 1b
add %o3, 4, %o3
/* Now it's safe to clear out the BSS. */
sethi %hi(__bss_start), %o2
or %o2, %lo(__bss_start), %o2
sethi %hi(_end), %o3
or %o3, %lo(_end), %o3
1: stx %g0, [%o2]
add %o2, 8, %o2
cmp %o2, %o3
blt,pt %xcc, 1b
nop
sethi %hi(grub_ieee1275_entry_fn), %o2
stx %o0, [%o2 + %lo(grub_ieee1275_entry_fn)]
call grub_main
nop
1: ba,a 1b

View file

@ -0,0 +1,124 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <grub/ieee1275/ieee1275.h>
#include <grub/types.h>
/* Sun specific ieee1275 interfaces used by GRUB. */
int
grub_ieee1275_map_physical (grub_addr_t paddr, grub_addr_t vaddr,
grub_size_t size, grub_uint32_t mode)
{
struct map_physical_args
{
struct grub_ieee1275_common_hdr common;
grub_ieee1275_cell_t method;
grub_ieee1275_cell_t ihandle;
grub_ieee1275_cell_t mode;
grub_ieee1275_cell_t size;
grub_ieee1275_cell_t virt;
grub_ieee1275_cell_t phys_high;
grub_ieee1275_cell_t phys_low;
grub_ieee1275_cell_t catch_result;
}
args;
INIT_IEEE1275_COMMON (&args.common, "call-method", 7, 1);
args.method = (grub_ieee1275_cell_t) "map";
args.ihandle = grub_ieee1275_mmu;
args.mode = mode;
args.size = size;
args.virt = vaddr;
args.phys_high = 0;
args.phys_low = paddr;
args.catch_result = (grub_ieee1275_cell_t) -1;
if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
return -1;
return args.catch_result;
}
int
grub_ieee1275_claim_vaddr (grub_addr_t vaddr, grub_size_t size)
{
struct claim_vaddr_args
{
struct grub_ieee1275_common_hdr common;
grub_ieee1275_cell_t method;
grub_ieee1275_cell_t ihandle;
grub_ieee1275_cell_t align;
grub_ieee1275_cell_t size;
grub_ieee1275_cell_t virt;
grub_ieee1275_cell_t catch_result;
}
args;
INIT_IEEE1275_COMMON (&args.common, "call-method", 5, 2);
args.method = (grub_ieee1275_cell_t) "claim";
args.ihandle = grub_ieee1275_mmu;
args.align = 0;
args.size = size;
args.virt = vaddr;
args.catch_result = (grub_ieee1275_cell_t) -1;
if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
return -1;
return args.catch_result;
}
int
grub_ieee1275_alloc_physmem (grub_addr_t *paddr, grub_size_t size,
grub_uint32_t align)
{
grub_uint32_t memory_ihandle;
struct alloc_physmem_args
{
struct grub_ieee1275_common_hdr common;
grub_ieee1275_cell_t method;
grub_ieee1275_cell_t ihandle;
grub_ieee1275_cell_t align;
grub_ieee1275_cell_t size;
grub_ieee1275_cell_t catch_result;
grub_ieee1275_cell_t phys_high;
grub_ieee1275_cell_t phys_low;
}
args;
grub_ssize_t actual = 0;
grub_ieee1275_get_property (grub_ieee1275_chosen, "memory",
&memory_ihandle, sizeof (memory_ihandle),
&actual);
if (actual != sizeof (memory_ihandle))
return -1;
if (!align)
align = 1;
INIT_IEEE1275_COMMON (&args.common, "call-method", 4, 3);
args.method = (grub_ieee1275_cell_t) "claim";
args.ihandle = memory_ihandle;
args.align = (align ? align : 1);
args.size = size;
if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
return -1;
*paddr = args.phys_low;
return args.catch_result;
}

View file

@ -1,7 +1,7 @@
/* init.c -- Initialize GRUB on the Ultra Sprac (sparc64). */
/* init.c -- Initialize GRUB on SPARC64. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2003,2004,2005,2007 Free Software Foundation, Inc.
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -18,163 +18,111 @@
*/
#include <grub/kernel.h>
#include <grub/dl.h>
#include <grub/disk.h>
#include <grub/mm.h>
#include <grub/partition.h>
#include <grub/normal.h>
#include <grub/fs.h>
#include <grub/setjmp.h>
#include <grub/env.h>
#include <grub/err.h>
#include <grub/misc.h>
#include <grub/time.h>
#include <grub/machine/console.h>
#include <grub/machine/kernel.h>
#include <grub/machine/time.h>
#include <grub/ieee1275/ofdisk.h>
#include <grub/ieee1275/ieee1275.h>
/* OpenBoot entry point. */
int (*grub_ieee1275_entry_fn) (void *);
grub_ieee1275_phandle_t grub_ieee1275_chosen;
static grub_uint32_t grub_ieee1275_flags;
/* FIXME (sparc64). */
static const grub_addr_t grub_heap_start = 0x40000;
static grub_addr_t grub_heap_len;
void
_start (uint64_t r0 __attribute__((unused)),
uint64_t r1 __attribute__((unused)),
uint64_t r2 __attribute__((unused)),
uint64_t r3 __attribute__((unused)),
uint64_t r4,
uint64_t r5 __attribute__((unused)));
void
_start (uint64_t r0 __attribute__((unused)),
uint64_t r1 __attribute__((unused)),
uint64_t r2 __attribute__((unused)),
uint64_t r3 __attribute__((unused)),
uint64_t r4,
uint64_t r5 __attribute__((unused)))
grub_exit (void)
{
grub_ieee1275_entry_fn = (int (*)(void *)) r4;
grub_ieee1275_finddevice ("/chosen", &grub_ieee1275_chosen);
/* Now invoke the main function. */
grub_main ();
/* Never reached. */
grub_ieee1275_exit ();
}
void
grub_millisleep (grub_uint32_t ms)
static grub_uint64_t
ieee1275_get_time_ms (void)
{
grub_millisleep_generic (ms);
grub_uint32_t msecs = 0;
grub_ieee1275_milliseconds (&msecs);
return msecs;
}
int
grub_ieee1275_test_flag (enum grub_ieee1275_flag flag)
grub_uint32_t
grub_get_rtc (void)
{
return (grub_ieee1275_flags & (1 << flag));
return ieee1275_get_time_ms ();
}
void
grub_ieee1275_set_flag (enum grub_ieee1275_flag flag)
grub_addr_t
grub_arch_modules_addr (void)
{
grub_ieee1275_flags |= (1 << flag);
}
/* Translate an OF filesystem path (separated by backslashes), into a GRUB
path (separated by forward slashes). */
static void
grub_translate_ieee1275_path (char *filepath)
{
char *backslash;
backslash = grub_strchr (filepath, '\\');
while (backslash != 0)
{
*backslash = '/';
backslash = grub_strchr (filepath, '\\');
}
extern char _end[];
return (grub_addr_t) _end;
}
void
grub_machine_set_prefix (void)
{
char bootpath[64]; /* XXX check length */
char *filename;
char *prefix;
if (grub_ieee1275_get_property (grub_ieee1275_chosen, "bootpath", bootpath,
sizeof (bootpath), 0))
if (grub_prefix[0] != '(')
{
/* Should never happen. */
grub_printf ("/chosen/bootpath property missing!\n");
grub_env_set ("prefix", "");
return;
}
char bootpath[IEEE1275_MAX_PATH_LEN];
char *prefix, *path, *colon;
grub_ssize_t actual;
/* Transform an OF device path to a GRUB path. */
prefix = grub_ieee1275_encode_devname (bootpath);
filename = grub_ieee1275_get_filename (bootpath);
if (filename)
{
char *newprefix;
char *lastslash = grub_strrchr (filename, '\\');
/* Truncate at last directory. */
if (lastslash)
{
*lastslash = '\0';
grub_translate_ieee1275_path (filename);
newprefix = grub_malloc (grub_strlen (prefix)
+ grub_strlen (filename));
grub_sprintf (newprefix, "%s%s", prefix, filename);
grub_free (prefix);
prefix = newprefix;
if (grub_ieee1275_get_property (grub_ieee1275_chosen, "bootpath",
&bootpath, sizeof (bootpath), &actual))
{
/* Should never happen. */
grub_printf ("/chosen/bootpath property missing!\n");
grub_env_set ("prefix", "");
return;
}
/* Transform an OF device path to a GRUB path. */
colon = grub_strchr (bootpath, ':');
if (colon)
{
char *part = colon + 1;
/* Consistently provide numbered partitions to GRUB.
OpenBOOT traditionally uses alphabetical partition
specifiers. */
if (part[0] >= 'a' && part[0] <= 'z')
part[0] = '1' + (part[0] - 'a');
}
prefix = grub_ieee1275_encode_devname (bootpath);
path = grub_malloc (grub_strlen (grub_prefix)
+ grub_strlen (prefix)
+ 2);
grub_sprintf(path, "%s%s", prefix, grub_prefix);
grub_strcpy (grub_prefix, path);
grub_free (path);
grub_free (prefix);
}
grub_env_set ("prefix", prefix);
grub_free (filename);
grub_free (prefix);
grub_env_set ("prefix", grub_prefix);
}
void
grub_machine_init (void)
static void
grub_heap_init (void)
{
char *args;
grub_ssize_t length;
grub_mm_init_region ((void *)(long)0x4000UL, 0x200000 - 0x4000);
}
grub_console_init ();
static void
grub_parse_cmdline (void)
{
grub_ssize_t actual;
char args[256];
/* FIXME (sparc64). */
grub_heap_len = (grub_addr_t) &_start - 0x1000 - grub_heap_start;
if (grub_ieee1275_claim (grub_heap_start, grub_heap_len, 0, 0))
grub_fatal ("Failed to claim heap at %p, len 0x%x\n", grub_heap_start,
grub_heap_len);
grub_mm_init_region ((void *) grub_heap_start, grub_heap_len);
grub_ofdisk_init ();
/* Process commandline. */
if (grub_ieee1275_get_property_length (grub_ieee1275_chosen, "bootargs",
&length) == 0 &&
length > 0)
if (grub_ieee1275_get_property (grub_ieee1275_chosen, "bootargs", &args,
sizeof args, &actual) == 0
&& actual > 1)
{
grub_ssize_t i = 0;
int i = 0;
args = grub_malloc (length);
grub_ieee1275_get_property (grub_ieee1275_chosen, "bootargs", args,
length, 0);
while (i < length)
while (i < actual)
{
char *command = &args[i];
char *end;
@ -182,7 +130,7 @@ grub_machine_init (void)
end = grub_strchr (command, ';');
if (end == 0)
i = length; /* No more commands after this one. */
i = actual; /* No more commands after this one. */
else
{
*end = '\0';
@ -200,7 +148,20 @@ grub_machine_init (void)
}
}
}
}
void
grub_machine_init (void)
{
grub_ieee1275_init ();
grub_console_init ();
grub_heap_init ();
grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_PARTITION_0);
grub_ofdisk_init ();
grub_parse_cmdline ();
grub_install_get_time_ms (ieee1275_get_time_ms);
}
void
@ -209,26 +170,3 @@ grub_machine_fini (void)
grub_ofdisk_fini ();
grub_console_fini ();
}
void
grub_exit (void)
{
grub_ieee1275_enter ();
}
grub_uint32_t
grub_get_rtc (void)
{
grub_uint32_t msecs;
if (grub_ieee1275_milliseconds (&msecs))
return 0;
return msecs;
}
grub_addr_t
grub_arch_modules_addr (void)
{
return GRUB_IEEE1275_MODULE_BASE;
}

View file

@ -1,373 +0,0 @@
/* openfw.c -- Open firmware support functions. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2003,2004,2005,2007 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <grub/err.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/machine/kernel.h> /* Needed ? */
#include <grub/ieee1275/ieee1275.h>
enum grub_ieee1275_parse_type
{
GRUB_PARSE_FILENAME,
GRUB_PARSE_PARTITION,
};
/* Walk children of 'devpath', calling hook for each. */
grub_err_t
grub_children_iterate (char *devpath,
int (*hook) (struct grub_ieee1275_devalias *alias))
{
grub_ieee1275_phandle_t dev;
grub_ieee1275_phandle_t child;
grub_ieee1275_finddevice (devpath, &dev);
if (((signed) dev) == -1)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Unknown device");
grub_ieee1275_child (dev, &child);
if (((signed) child) == -1)
return grub_error (GRUB_ERR_BAD_DEVICE, "Device has no children");
do
{
/* XXX: Don't use hardcoded path lengths. */
char childtype[64];
char childpath[64];
char childname[64];
char fullname[64];
struct grub_ieee1275_devalias alias;
grub_ssize_t actual;
grub_ieee1275_get_property (child, "device_type", childtype,
sizeof childtype, &actual);
if (actual == -1)
continue;
grub_ieee1275_package_to_path (child, childpath, sizeof childpath,
&actual);
if (actual == -1)
continue;
grub_ieee1275_get_property (child, "name", childname,
sizeof childname, &actual);
if (actual == -1)
continue;
grub_sprintf (fullname, "%s/%s", devpath, childname);
alias.type = childtype;
alias.path = childpath;
alias.name = fullname;
hook (&alias);
}
while (grub_ieee1275_peer (child, &child));
return 0;
}
/* Iterate through all device aliases. This function can be used to
find a device of a specific type. */
grub_err_t
grub_devalias_iterate (int (*hook) (struct grub_ieee1275_devalias *alias))
{
grub_ieee1275_phandle_t devalias;
char aliasname[32];
grub_ssize_t actual;
grub_ieee1275_cell_t flags;
struct grub_ieee1275_devalias alias;
if (grub_ieee1275_finddevice ("/aliases", &devalias))
return -1;
aliasname[0] = '\0';
while (grub_ieee1275_next_property (devalias, aliasname, aliasname, &flags) != -1
&& ((signed) flags) != -1 )
{
grub_ieee1275_phandle_t dev;
grub_ssize_t pathlen, typelen;
char *devpath, *devtype;
grub_dprintf ("devalias", "devalias name = %s\n", aliasname);
/* The property `name' is a special case we should skip. */
if (!grub_strcmp (aliasname, "name"))
continue;
grub_ieee1275_get_property_length (devalias, aliasname, &pathlen);
devpath = grub_malloc (pathlen);
if (! devpath)
return grub_errno;
if (grub_ieee1275_get_property (devalias, aliasname, devpath, pathlen,
&actual))
{
grub_dprintf ("devalias", "get_property (%s) failed\n", aliasname);
grub_free (devpath);
continue;
}
if (grub_ieee1275_finddevice (devpath, &dev) || ((signed) dev) == -1)
{
grub_dprintf ("devalias", "finddevice (%s) failed\n", devpath);
grub_free (devpath);
continue;
}
grub_ieee1275_get_property_length (dev, "device_type", &typelen);
devtype = grub_malloc (typelen);
if (! devtype)
{
grub_free (devpath);
return grub_errno;
}
if (grub_ieee1275_get_property (dev, "device_type", devtype, typelen, &actual))
{
grub_dprintf ("devalias", "get device type failed\n");
grub_free (devtype);
grub_free (devpath);
continue;
}
alias.name = aliasname;
alias.path= devpath;
alias.type = devtype;
if((*hook) (&alias))
{
grub_free (devtype);
grub_free (devpath);
break;
}
grub_free (devtype);
grub_free (devpath);
}
return 0;
}
/* FIXME (sparc64) */
#if 0
/* Call the "map" method of /chosen/mmu. */
static int
grub_map (grub_addr_t phys, grub_addr_t virt, grub_uint32_t size,
grub_uint8_t mode)
{
struct map_args {
struct grub_ieee1275_common_hdr common;
char *method;
grub_ieee1275_ihandle_t ihandle;
grub_uint32_t mode;
grub_uint32_t size;
grub_uint32_t virt;
grub_uint32_t phys;
int catch_result;
} args;
grub_ieee1275_ihandle_t mmu;
grub_ssize_t len;
grub_ieee1275_get_integer_property (grub_ieee1275_chosen, "mmu", &mmu, sizeof mmu,
&len);
if (len != sizeof mmu)
return -1;
INIT_IEEE1275_COMMON (&args.common, "call-method", 6, 1);
args.method = "map";
args.ihandle = mmu;
args.phys = phys;
args.virt = virt;
args.size = size;
args.mode = mode; /* Format is WIMG0PP. */
if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
return -1;
return args.catch_result;
}
#endif
int
grub_claimmap (grub_addr_t addr, grub_size_t size)
{
if (grub_ieee1275_claim (addr, size, 0, 0))
return -1;
return 0;
}
/* Get the device arguments of the Open Firmware node name `path'. */
static char *
grub_ieee1275_get_devargs (const char *path)
{
char *colon = grub_strchr (path, ':');
if (! colon)
return 0;
return grub_strdup (colon + 1);
}
/* Get the device path of the Open Firmware node name `path'. */
static char *
grub_ieee1275_get_devname (const char *path)
{
char *colon = grub_strchr (path, ':');
char *newpath = 0;
int pathlen = grub_strlen (path);
auto int match_alias (struct grub_ieee1275_devalias *alias);
int match_alias (struct grub_ieee1275_devalias *curalias)
{
/* briQ firmware can change capitalization in /chosen/bootpath. */
if (! grub_strncasecmp (curalias->path, path, pathlen))
{
newpath = grub_strndup (curalias->name, grub_strlen (curalias->name));
return 1;
}
return 0;
}
if (colon)
pathlen = (int)(colon - path);
/* Try to find an alias for this device. */
grub_devalias_iterate (match_alias);
if (! newpath)
newpath = grub_strdup (path);
return newpath;
}
static char *
grub_ieee1275_parse_args (const char *path, enum grub_ieee1275_parse_type ptype)
{
char type[64]; /* XXX check size. */
char *device = grub_ieee1275_get_devname (path);
char *args = grub_ieee1275_get_devargs (path);
char *ret = 0;
grub_ieee1275_phandle_t dev;
if (!args)
/* Shouldn't happen. */
return 0;
/* We need to know what type of device it is in order to parse the full
file path properly. */
if (grub_ieee1275_finddevice (device, &dev))
{
grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Device %s not found\n", device);
goto fail;
}
if (grub_ieee1275_get_property (dev, "device_type", type, sizeof type, 0))
{
grub_error (GRUB_ERR_UNKNOWN_DEVICE,
"Device %s lacks a device_type property\n", device);
goto fail;
}
if (!grub_strcmp ("block", type))
{
/* The syntax of the device arguments is defined in the CHRP and PReP
IEEE1275 bindings: "[partition][,[filename]]". */
char *comma = grub_strchr (args, ',');
if (ptype == GRUB_PARSE_FILENAME)
{
if (comma)
{
char *filepath = comma + 1;
ret = grub_malloc (grub_strlen (filepath) + 1);
/* Make sure filepath has leading backslash. */
if (filepath[0] != '\\')
grub_sprintf (ret, "\\%s", filepath);
else
grub_strcpy (ret, filepath);
}
}
else if (ptype == GRUB_PARSE_PARTITION)
{
if (!comma)
ret = grub_strdup (args);
else
ret = grub_strndup (args, (grub_size_t)(comma - args));
}
}
else
{
/* XXX Handle net devices by configuring & registering a grub_net_dev
here, then return its name?
Example path: "net:<server ip>,<file name>,<client ip>,<gateway
ip>,<bootp retries>,<tftp retries>". */
grub_printf ("Unsupported type %s for device %s\n", type, device);
}
fail:
grub_free (device);
grub_free (args);
return ret;
}
char *
grub_ieee1275_get_filename (const char *path)
{
return grub_ieee1275_parse_args (path, GRUB_PARSE_FILENAME);
}
/* Convert a device name from IEEE1275 syntax to GRUB syntax. */
char *
grub_ieee1275_encode_devname (const char *path)
{
char *device = grub_ieee1275_get_devname (path);
char *partition = grub_ieee1275_parse_args (path, GRUB_PARSE_PARTITION);
char *encoding;
if (partition)
{
unsigned int partno = grub_strtoul (partition, 0, 0);
/* Assume partno will require less than five bytes to encode. */
encoding = grub_malloc (grub_strlen (device) + 3 + 5);
grub_sprintf (encoding, "(%s,%d)", device, partno);
}
else
{
encoding = grub_malloc (grub_strlen (device) + 2);
grub_sprintf (encoding, "(%s)", device);
}
grub_free (partition);
grub_free (device);
return encoding;
}
void
grub_reboot (void)
{
grub_ieee1275_interpret ("reset-all", 0);
}
void
grub_halt (void)
{
grub_ieee1275_interpret ("power-off", 0);
}

View file

@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2003,2005,2007 Free Software Foundation, Inc.
* Copyright (C) 2002,2003,2005,2007,2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -21,125 +21,33 @@
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/env.h>
#include <grub/time.h>
/* The list of terminals. */
static grub_term_t grub_term_list;
struct grub_term_output *grub_term_outputs_disabled;
struct grub_term_input *grub_term_inputs_disabled;
struct grub_term_output *grub_term_outputs;
struct grub_term_input *grub_term_inputs;
/* The current terminal. */
static grub_term_t grub_cur_term;
/* The amount of lines counted by the pager. */
static int grub_more_lines;
/* If the more pager is active. */
static int grub_more;
/* The current cursor state. */
static int cursor_state = 1;
void
grub_term_register (grub_term_t term)
{
term->next = grub_term_list;
grub_term_list = term;
}
void
grub_term_unregister (grub_term_t term)
{
grub_term_t *p, q;
for (p = &grub_term_list, q = *p; q; p = &(q->next), q = q->next)
if (q == term)
{
*p = q->next;
break;
}
}
void
grub_term_iterate (int (*hook) (grub_term_t term))
{
grub_term_t p;
for (p = grub_term_list; p; p = p->next)
if (hook (p))
break;
}
grub_err_t
grub_term_set_current (grub_term_t term)
{
if (grub_cur_term && grub_cur_term->fini)
if ((grub_cur_term->fini) () != GRUB_ERR_NONE)
return grub_errno;
if (term->init)
if ((term->init) () != GRUB_ERR_NONE)
return grub_errno;
grub_cur_term = term;
grub_cls ();
grub_setcursor (grub_getcursor ());
return GRUB_ERR_NONE;
}
grub_term_t
grub_term_get_current (void)
{
return grub_cur_term;
}
void (*grub_newline_hook) (void) = NULL;
/* Put a Unicode character. */
void
grub_putcode (grub_uint32_t code)
grub_putcode (grub_uint32_t code, struct grub_term_output *term)
{
int height = grub_getwh () & 255;
if (code == '\t' && grub_cur_term->getxy)
if (code == '\t' && term->getxy)
{
int n;
n = 8 - ((grub_getxy () >> 8) & 7);
n = 8 - ((term->getxy () >> 8) & 7);
while (n--)
grub_putcode (' ');
grub_putcode (' ', term);
return;
}
(grub_cur_term->putchar) (code);
(term->putchar) (code);
if (code == '\n')
{
grub_putcode ('\r');
grub_more_lines++;
if (grub_more && grub_more_lines == height - 1)
{
char key;
int pos = grub_getxy ();
/* Show --MORE-- on the lower left side of the screen. */
grub_gotoxy (1, height - 1);
grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
grub_printf ("--MORE--");
grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
key = grub_getkey ();
/* Remove the message. */
grub_gotoxy (1, height - 1);
grub_printf (" ");
grub_gotoxy (pos >> 8, pos & 0xFF);
/* Scroll one lines or an entire page, depending on the key. */
if (key == '\r' || key =='\n')
grub_more_lines--;
else
grub_more_lines = 0;
}
}
(term->putchar) ('\r');
}
/* Put a character. C is one byte of a UTF-8 stream.
@ -150,127 +58,101 @@ grub_putchar (int c)
static grub_size_t size = 0;
static grub_uint8_t buf[6];
grub_uint32_t code;
grub_ssize_t ret;
grub_size_t ret;
buf[size++] = c;
ret = grub_utf8_to_ucs4 (&code, buf, size);
if (ret > 0)
{
size = 0;
grub_putcode (code);
}
else if (ret < 0)
{
size = 0;
grub_putcode ('?');
}
}
ret = grub_utf8_to_ucs4 (&code, 1, buf, size, 0);
/* Return the number of columns occupied by the character code CODE. */
grub_ssize_t
grub_getcharwidth (grub_uint32_t code)
{
return (grub_cur_term->getcharwidth) (code);
if (ret != 0)
{
struct grub_term_output *term;
size = 0;
FOR_ACTIVE_TERM_OUTPUTS(term)
grub_putcode (code, term);
if (code == '\n' && grub_newline_hook)
grub_newline_hook ();
}
}
int
grub_getkey (void)
{
return (grub_cur_term->getkey) ();
grub_term_input_t term;
while (1)
{
FOR_ACTIVE_TERM_INPUTS(term)
{
int key = term->checkkey ();
if (key != -1)
return term->getkey ();
}
grub_cpu_idle ();
}
}
int
grub_checkkey (void)
{
return (grub_cur_term->checkkey) ();
grub_term_input_t term;
FOR_ACTIVE_TERM_INPUTS(term)
{
int key = term->checkkey ();
if (key != -1)
return key;
}
return -1;
}
grub_uint16_t
grub_getxy (void)
int
grub_getkeystatus (void)
{
return (grub_cur_term->getxy) ();
}
int status = 0;
grub_term_input_t term;
grub_uint16_t
grub_getwh (void)
{
return (grub_cur_term->getwh) ();
}
FOR_ACTIVE_TERM_INPUTS(term)
{
if (term->getkeystatus)
status |= term->getkeystatus ();
}
void
grub_gotoxy (grub_uint8_t x, grub_uint8_t y)
{
(grub_cur_term->gotoxy) (x, y);
return status;
}
void
grub_cls (void)
{
if ((grub_cur_term->flags & GRUB_TERM_DUMB) || (grub_env_get ("debug")))
{
grub_putchar ('\n');
grub_refresh ();
}
else
(grub_cur_term->cls) ();
struct grub_term_output *term;
FOR_ACTIVE_TERM_OUTPUTS(term)
{
if ((term->flags & GRUB_TERM_DUMB) || (grub_env_get ("debug")))
{
grub_putcode ('\n', term);
grub_term_refresh (term);
}
else
(term->cls) ();
}
}
void
grub_setcolorstate (grub_term_color_state state)
{
if (grub_cur_term->setcolorstate)
(grub_cur_term->setcolorstate) (state);
}
void
grub_setcolor (grub_uint8_t normal_color, grub_uint8_t highlight_color)
{
if (grub_cur_term->setcolor)
(grub_cur_term->setcolor) (normal_color, highlight_color);
}
void
grub_getcolor (grub_uint8_t *normal_color, grub_uint8_t *highlight_color)
{
if (grub_cur_term->getcolor)
(grub_cur_term->getcolor) (normal_color, highlight_color);
}
int
grub_setcursor (int on)
{
int ret = cursor_state;
if (grub_cur_term->setcursor)
{
(grub_cur_term->setcursor) (on);
cursor_state = on;
}
struct grub_term_output *term;
return ret;
}
int
grub_getcursor (void)
{
return cursor_state;
FOR_ACTIVE_TERM_OUTPUTS(term)
grub_term_setcolorstate (term, state);
}
void
grub_refresh (void)
{
if (grub_cur_term->refresh)
(grub_cur_term->refresh) ();
}
struct grub_term_output *term;
void
grub_set_more (int onoff)
{
if (onoff == 1)
grub_more++;
else
grub_more--;
grub_more_lines = 0;
FOR_ACTIVE_TERM_OUTPUTS(term)
grub_term_refresh (term);
}

37
kern/time.c Normal file
View file

@ -0,0 +1,37 @@
/* time.c - kernel time functions */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2008 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <grub/time.h>
typedef grub_uint64_t (*get_time_ms_func_t) (void);
/* Function pointer to the implementation in use. */
static get_time_ms_func_t get_time_ms_func;
grub_uint64_t
grub_get_time_ms (void)
{
return get_time_ms_func ();
}
void
grub_install_get_time_ms (get_time_ms_func_t func)
{
get_time_ms_func = func;
}

119
kern/x86_64/dl.c Normal file
View file

@ -0,0 +1,119 @@
/* dl-x86_64.c - arch-dependent part of loadable module support */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2005,2007,2009 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <grub/dl.h>
#include <grub/elf.h>
#include <grub/misc.h>
#include <grub/err.h>
/* Check if EHDR is a valid ELF header. */
grub_err_t
grub_arch_dl_check_header (void *ehdr)
{
Elf64_Ehdr *e = ehdr;
/* Check the magic numbers. */
if (e->e_ident[EI_CLASS] != ELFCLASS64
|| e->e_ident[EI_DATA] != ELFDATA2LSB
|| e->e_machine != EM_X86_64)
return grub_error (GRUB_ERR_BAD_OS, "invalid arch specific ELF magic");
return GRUB_ERR_NONE;
}
/* Relocate symbols. */
grub_err_t
grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
{
Elf64_Ehdr *e = ehdr;
Elf64_Shdr *s;
Elf64_Word entsize;
unsigned i;
/* Find a symbol table. */
for (i = 0, s = (Elf64_Shdr *) ((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf64_Shdr *) ((char *) s + e->e_shentsize))
if (s->sh_type == SHT_SYMTAB)
break;
if (i == e->e_shnum)
return grub_error (GRUB_ERR_BAD_MODULE, "no symtab found");
entsize = s->sh_entsize;
for (i = 0, s = (Elf64_Shdr *) ((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf64_Shdr *) ((char *) s + e->e_shentsize))
if (s->sh_type == SHT_RELA)
{
grub_dl_segment_t seg;
/* Find the target segment. */
for (seg = mod->segment; seg; seg = seg->next)
if (seg->section == s->sh_info)
break;
if (seg)
{
Elf64_Rela *rel, *max;
for (rel = (Elf64_Rela *) ((char *) e + s->sh_offset),
max = rel + s->sh_size / s->sh_entsize;
rel < max;
rel++)
{
Elf64_Word *addr32;
Elf64_Xword *addr64;
Elf64_Sym *sym;
if (seg->size < rel->r_offset)
return grub_error (GRUB_ERR_BAD_MODULE,
"reloc offset is out of the segment");
addr32 = (Elf64_Word *) ((char *) seg->addr + rel->r_offset);
addr64 = (Elf64_Xword *) addr32;
sym = (Elf64_Sym *) ((char *) mod->symtab
+ entsize * ELF_R_SYM (rel->r_info));
switch (ELF_R_TYPE (rel->r_info))
{
case R_X86_64_64:
*addr64 += rel->r_addend + sym->st_value;
break;
case R_X86_64_PC32:
*addr32 += rel->r_addend + sym->st_value -
(Elf64_Xword) seg->addr - rel->r_offset;
break;
case R_X86_64_32:
case R_X86_64_32S:
*addr32 += rel->r_addend + sym->st_value;
break;
default:
grub_fatal ("Unrecognized relocation: %d\n", ELF_R_TYPE (rel->r_info));
}
}
}
}
return GRUB_ERR_NONE;
}

116
kern/x86_64/efi/callwrap.S Normal file
View file

@ -0,0 +1,116 @@
/* callwrap.S - wrapper for x86_64 efi calls */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2006,2007,2009 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <config.h>
#include <grub/symbol.h>
#include <grub/boot.h>
/*
* x86_64 uses registry to pass parameters. Unfortunately, gcc and efi use
* different call conversion, so we need to do some conversion.
*
* gcc:
* %rdi, %esi, %rdx, %rcx, %r8, %r9, 8(%rsp), 16(%rsp), ...
*
* efi:
* %rcx, %rdx, %r8, %r9, 32(%rsp), 40(%rsp), 48(%rsp), ...
*
*/
.file "callwrap.S"
.text
FUNCTION(efi_wrap_0)
subq $40, %rsp
call *%rdi
addq $40, %rsp
ret
FUNCTION(efi_wrap_1)
subq $40, %rsp
mov %rsi, %rcx
call *%rdi
addq $40, %rsp
ret
FUNCTION(efi_wrap_2)
subq $40, %rsp
mov %rsi, %rcx
call *%rdi
addq $40, %rsp
ret
FUNCTION(efi_wrap_3)
subq $40, %rsp
mov %rcx, %r8
mov %rsi, %rcx
call *%rdi
addq $40, %rsp
ret
FUNCTION(efi_wrap_4)
subq $40, %rsp
mov %r8, %r9
mov %rcx, %r8
mov %rsi, %rcx
call *%rdi
addq $40, %rsp
ret
FUNCTION(efi_wrap_5)
subq $40, %rsp
mov %r9, 32(%rsp)
mov %r8, %r9
mov %rcx, %r8
mov %rsi, %rcx
call *%rdi
addq $40, %rsp
ret
FUNCTION(efi_wrap_6)
subq $56, %rsp
mov 56+8(%rsp), %rax
mov %rax, 40(%rsp)
mov %r9, 32(%rsp)
mov %r8, %r9
mov %rcx, %r8
mov %rsi, %rcx
call *%rdi
addq $56, %rsp
ret
FUNCTION(efi_wrap_10)
subq $88, %rsp
mov 88+40(%rsp), %rax
mov %rax, 72(%rsp)
mov 88+32(%rsp), %rax
mov %rax, 64(%rsp)
mov 88+24(%rsp), %rax
mov %rax, 56(%rsp)
mov 88+16(%rsp), %rax
mov %rax, 48(%rsp)
mov 88+8(%rsp), %rax
mov %rax, 40(%rsp)
mov %r9, 32(%rsp)
mov %r8, %r9
mov %rcx, %r8
mov %rsi, %rcx
call *%rdi
addq $88, %rsp
ret

63
kern/x86_64/efi/startup.S Normal file
View file

@ -0,0 +1,63 @@
/* startup.S - bootstrap GRUB itself */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2006,2007,2009 Free Software Foundation, Inc.
*
* GRUB 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 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/>.
*/
#include <config.h>
#include <grub/symbol.h>
#include <grub/boot.h>
.file "startup.S"
.text
.globl start, _start
.code64
start:
_start:
jmp codestart
/*
* Compatibility version number
*
* These MUST be at byte offset 6 and 7 of the executable
* DO NOT MOVE !!!
*/
. = _start + 0x6
.byte GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR
/*
* This is a special data area 8 bytes from the beginning.
*/
. = _start + 0x8
VARIABLE(grub_prefix)
/* to be filled by grub-mkimage */
/*
* Leave some breathing room for the prefix.
*/
. = _start + 0x50
codestart:
movq %rcx, EXT_C(grub_efi_image_handle)(%rip)
movq %rdx, EXT_C(grub_efi_system_table)(%rip)
call EXT_C(grub_main)
ret