merge mainline

This commit is contained in:
Colin Watson 2010-07-17 11:17:49 +01:00
commit 41f435b1b4
657 changed files with 94764 additions and 29525 deletions

View file

@ -26,6 +26,7 @@
#include <grub/file.h>
#include <grub/device.h>
#include <grub/command.h>
#include <grub/i18n.h>
/* set ENVVAR=VALUE */
static grub_err_t
@ -73,18 +74,6 @@ grub_core_cmd_unset (struct grub_command *cmd __attribute__ ((unused)),
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)),
@ -133,7 +122,7 @@ grub_core_cmd_ls (struct grub_command *cmd __attribute__ ((unused)),
if (argc < 1)
{
grub_device_iterate (grub_mini_print_devices);
grub_putchar ('\n');
grub_xputs ("\n");
grub_refresh ();
}
else
@ -172,7 +161,7 @@ grub_core_cmd_ls (struct grub_command *cmd __attribute__ ((unused)),
else if (fs)
{
(fs->dir) (dev, path, grub_mini_print_files);
grub_putchar ('\n');
grub_xputs ("\n");
grub_refresh ();
}
@ -190,13 +179,13 @@ void
grub_register_core_commands (void)
{
grub_register_command ("set", grub_core_cmd_set,
"[ENVVAR=VALUE]", "Set an environment variable.");
N_("[ENVVAR=VALUE]"),
N_("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.");
N_("ENVVAR"),
N_("Remove an environment variable."));
grub_register_command ("ls", grub_core_cmd_ls,
"[ARG]", "List devices or files.");
N_("[ARG]"), N_("List devices or files."));
grub_register_command ("insmod", grub_core_cmd_insmod,
"MODULE", "Insert a module.");
N_("MODULE"), N_("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
@ -86,7 +86,7 @@ grub_device_iterate (int (*hook) (const char *name))
struct part_ent
{
struct part_ent *next;
char name[0];
char *name;
} *ents;
int iterate_disk (const char *disk_name)
@ -98,7 +98,10 @@ grub_device_iterate (int (*hook) (const char *name))
dev = grub_device_open (disk_name);
if (! dev)
return 0;
{
grub_errno = GRUB_ERR_NONE;
return 0;
}
if (dev->disk && dev->disk->has_partitions)
{
@ -118,6 +121,7 @@ grub_device_iterate (int (*hook) (const char *name))
if (!ret)
ret = hook (p->name);
grub_free (p->name);
grub_free (p);
p = next;
}
@ -138,15 +142,20 @@ grub_device_iterate (int (*hook) (const char *name))
if (! partition_name)
return 1;
p = grub_malloc (sizeof (p->next) + grub_strlen (disk->name) + 1 +
grub_strlen (partition_name) + 1);
p = grub_malloc (sizeof (*p));
if (!p)
{
grub_free (partition_name);
return 1;
}
grub_sprintf (p->name, "%s,%s", disk->name, partition_name);
p->name = grub_xasprintf ("%s,%s", disk->name, partition_name);
if (!p->name)
{
grub_free (partition_name);
grub_free (p);
return 1;
}
grub_free (partition_name);
p->next = ents;

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
@ -330,6 +330,7 @@ grub_disk_open (const char *name)
void
grub_disk_close (grub_disk_t disk)
{
grub_partition_t part;
grub_dprintf ("disk", "Closing `%s'.\n", disk->name);
if (disk->dev && disk->dev->close)
@ -338,7 +339,12 @@ grub_disk_close (grub_disk_t disk)
/* Reset the timer. */
grub_last_time = grub_get_time_ms ();
grub_free (disk->partition);
while (disk->partition)
{
part = disk->partition->parent;
grub_free (disk->partition);
disk->partition = part;
}
grub_free ((void *) disk->name);
grub_free (disk);
}
@ -349,18 +355,19 @@ grub_disk_close (grub_disk_t disk)
- Verify that the range is inside the partition. */
static grub_err_t
grub_disk_adjust_range (grub_disk_t disk, grub_disk_addr_t *sector,
grub_off_t *offset, grub_size_t size)
grub_off_t *offset, grub_size_t size)
{
grub_partition_t part;
*sector += *offset >> GRUB_DISK_SECTOR_BITS;
*offset &= GRUB_DISK_SECTOR_SIZE - 1;
if (disk->partition)
for (part = disk->partition; part; part = part->parent)
{
grub_disk_addr_t start;
grub_uint64_t len;
start = grub_partition_get_start (disk->partition);
len = grub_partition_get_len (disk->partition);
start = part->start;
len = part->len;
if (*sector >= len
|| len - *sector < ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1)
@ -386,8 +393,6 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
char *tmp_buf;
unsigned real_offset;
grub_dprintf ("disk", "Reading `%s'...\n", disk->name);
/* First of all, check if the region is within the disk. */
if (grub_disk_adjust_range (disk, &sector, &offset, size) != GRUB_ERR_NONE)
{
@ -432,8 +437,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. */
@ -442,7 +448,7 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
grub_errno = GRUB_ERR_NONE;
num = ((size + GRUB_DISK_SECTOR_SIZE - 1)
num = ((size + real_offset + GRUB_DISK_SECTOR_SIZE - 1)
>> GRUB_DISK_SECTOR_BITS);
p = grub_realloc (tmp_buf, num << GRUB_DISK_SECTOR_BITS);
@ -465,12 +471,14 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
if (disk->read_hook)
while (size)
{
grub_size_t to_read = (size > GRUB_DISK_SECTOR_SIZE) ? GRUB_DISK_SECTOR_SIZE : size;
(disk->read_hook) (sector, real_offset,
((size > GRUB_DISK_SECTOR_SIZE)
? GRUB_DISK_SECTOR_SIZE
: size));
to_read);
if (grub_errno != GRUB_ERR_NONE)
goto finish;
sector++;
size -= GRUB_DISK_SECTOR_SIZE - real_offset;
size -= to_read - real_offset;
real_offset = 0;
}

View file

@ -39,31 +39,17 @@
struct grub_dl_list
{
struct grub_dl_list *next;
grub_dl_t mod;
};
typedef struct grub_dl_list *grub_dl_list_t;
static grub_dl_list_t grub_dl_head;
grub_dl_t grub_dl_head = 0;
static grub_err_t
grub_dl_add (grub_dl_t mod)
{
grub_dl_list_t l;
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;
l->mod = mod;
l->next = grub_dl_head;
grub_dl_head = l;
mod->next = grub_dl_head;
grub_dl_head = mod;
return GRUB_ERR_NONE;
}
@ -71,13 +57,12 @@ grub_dl_add (grub_dl_t mod)
static void
grub_dl_remove (grub_dl_t mod)
{
grub_dl_list_t *p, q;
grub_dl_t *p, q;
for (p = &grub_dl_head, q = *p; q; p = &q->next, q = *p)
if (q->mod == mod)
if (q == mod)
{
*p = q->next;
grub_free (q);
return;
}
}
@ -85,25 +70,15 @@ grub_dl_remove (grub_dl_t mod)
grub_dl_t
grub_dl_get (const char *name)
{
grub_dl_list_t l;
grub_dl_t l;
for (l = grub_dl_head; l; l = l->next)
if (grub_strcmp (name, l->mod->name) == 0)
return l->mod;
if (grub_strcmp (name, l->name) == 0)
return l;
return 0;
}
void
grub_dl_iterate (int (*hook) (grub_dl_t mod))
{
grub_dl_list_t l;
for (l = grub_dl_head; l; l = l->next)
if (hook (l->mod))
break;
}
struct grub_symbol
@ -341,24 +316,23 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
switch (type)
{
case STT_NOTYPE:
case STT_OBJECT:
/* Resolve a global symbol. */
if (sym->st_name != 0 && sym->st_shndx == 0)
{
sym->st_value = (Elf_Addr) grub_dl_resolve_symbol (name);
if (! sym->st_value)
return grub_error (GRUB_ERR_BAD_MODULE,
"the symbol `%s' not found", name);
"symbol not found: `%s'", name);
}
else
sym->st_value = 0;
break;
case STT_OBJECT:
sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod,
sym->st_shndx);
if (bind != STB_LOCAL)
if (grub_dl_register_symbol (name, (void *) sym->st_value, mod))
return grub_errno;
{
sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod,
sym->st_shndx);
if (bind != STB_LOCAL)
if (grub_dl_register_symbol (name, (void *) sym->st_value, mod))
return grub_errno;
}
break;
case STT_FUNC:
@ -470,12 +444,14 @@ 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)
{
grub_dl_dep_t dep;
if (!mod)
return 0;
for (dep = mod->dep; dep; dep = dep->next)
grub_dl_ref (dep->mod);
@ -487,12 +463,14 @@ grub_dl_unref (grub_dl_t mod)
{
grub_dl_dep_t dep;
if (!mod)
return 0;
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)
@ -628,12 +606,10 @@ grub_dl_load (const char *name)
return 0;
}
filename = (char *) grub_malloc (grub_strlen (grub_dl_dir) + 1
+ grub_strlen (name) + 4 + 1);
filename = grub_xasprintf ("%s/%s.mod", grub_dl_dir, name);
if (! filename)
return 0;
grub_sprintf (filename, "%s/%s.mod", grub_dl_dir, name);
mod = grub_dl_load_file (filename);
grub_free (filename);
@ -693,11 +669,11 @@ 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;
grub_dl_t p = grub_dl_head;
while (p)
{
if (grub_dl_unload (p->mod))
if (grub_dl_unload (p))
{
p = grub_dl_head;
continue;
@ -713,13 +689,13 @@ grub_dl_unload_all (void)
{
while (grub_dl_head)
{
grub_dl_list_t p;
grub_dl_t p;
grub_dl_unload_unneeded ();
/* Force to decrement the ref count. This will purge pre-loaded
modules and manually inserted modules. */
for (p = grub_dl_head; p; p = p->next)
p->mod->ref_count--;
p->ref_count--;
}
}

View file

@ -1,7 +1,7 @@
/* efi.c - generic EFI support */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2006,2007,2008 Free Software Foundation, Inc.
* Copyright (C) 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
@ -162,13 +162,17 @@ grub_exit (void)
for (;;) ;
}
/* On i386, a firmware-independant grub_reboot() is provided by realmode.S. */
#ifndef __i386__
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);
for (;;) ;
}
#endif
void
grub_halt (void)
@ -176,6 +180,7 @@ 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);
for (;;) ;
}
int

View file

@ -24,7 +24,7 @@
#include <grub/misc.h>
#include <grub/env.h>
#include <grub/mm.h>
#include <grub/machine/kernel.h>
#include <grub/kernel.h>
void
grub_efi_init (void)
@ -36,52 +36,72 @@ grub_efi_init (void)
/* Initialize the memory management system. */
grub_efi_mm_init ();
efi_call_4 (grub_efi_system_table->boot_services->set_watchdog_timer,
0, 0, 0, NULL);
grub_efidisk_init ();
}
void
grub_efi_set_prefix (void)
{
grub_efi_loaded_image_t *image;
grub_efi_loaded_image_t *image = NULL;
char *device = NULL;
char *path = NULL;
image = grub_efi_get_loaded_image (grub_efi_image_handle);
if (image)
{
char *pptr = NULL;
if (grub_prefix[0] == '(')
{
pptr = grub_strrchr (grub_prefix, ')');
if (pptr)
{
device = grub_strndup (grub_prefix + 1, pptr - grub_prefix - 1);
pptr++;
}
}
if (!pptr)
pptr = grub_prefix;
if (pptr[0])
path = grub_strdup (pptr);
}
if (!device || !path)
image = grub_efi_get_loaded_image (grub_efi_image_handle);
if (image && !device)
device = grub_efidisk_get_device_name (image->device_handle);
if (image && !path)
{
char *device;
char *file;
char *p;
device = grub_efidisk_get_device_name (image->device_handle);
file = grub_efi_get_filename (image->file_path);
path = grub_efi_get_filename (image->file_path);
if (device && file)
{
char *p;
char *prefix;
/* Get the directory. */
p = grub_strrchr (file, '/');
if (p)
*p = '\0';
prefix = grub_malloc (1 + grub_strlen (device) + 1
+ grub_strlen (file) + 1);
if (prefix)
{
grub_sprintf (prefix, "(%s)%s", device, file);
grub_env_set ("prefix", prefix);
grub_free (prefix);
}
}
grub_free (device);
grub_free (file);
/* Get the directory. */
p = grub_strrchr (path, '/');
if (p)
*p = '\0';
}
if (device && path)
{
char *prefix;
prefix = grub_xasprintf ("(%s)%s", device, path);
if (prefix)
{
grub_env_set ("prefix", prefix);
grub_free (prefix);
}
}
grub_free (device);
grub_free (path);
}
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,2008 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
@ -346,6 +346,7 @@ grub_efi_mm_init (void)
grub_efi_uintn_t desc_size;
grub_efi_uint64_t total_pages;
grub_efi_uint64_t required_pages;
int mm_status;
/* First of all, allocate pages to maintain allocations. */
allocated_pages
@ -361,16 +362,32 @@ grub_efi_mm_init (void)
if (! memory_map)
grub_fatal ("cannot allocate memory");
filtered_memory_map = NEXT_MEMORY_DESCRIPTOR (memory_map, MEMORY_MAP_SIZE);
/* Obtain descriptors for available memory. */
map_size = MEMORY_MAP_SIZE;
if (grub_efi_get_memory_map (&map_size, memory_map, 0, &desc_size, 0) < 0)
mm_status = grub_efi_get_memory_map (&map_size, memory_map, 0, &desc_size, 0);
if (mm_status == 0)
{
grub_efi_free_pages
((grub_efi_physical_address_t) ((grub_addr_t) memory_map),
2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
memory_map = grub_efi_allocate_pages (0, 2 * BYTES_TO_PAGES (map_size));
if (! memory_map)
grub_fatal ("cannot allocate memory");
mm_status = grub_efi_get_memory_map (&map_size, memory_map, 0,
&desc_size, 0);
}
if (mm_status < 0)
grub_fatal ("cannot get memory map");
memory_map_end = NEXT_MEMORY_DESCRIPTOR (memory_map, map_size);
filtered_memory_map = memory_map_end;
filtered_memory_map_end = filter_memory_map (memory_map, filtered_memory_map,
desc_size, memory_map_end);

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
@ -172,7 +172,7 @@ grub_elf32_phdr_iterate (grub_elf_t elf,
/* Calculate the amount of memory spanned by the segments. */
grub_size_t
grub_elf32_size (grub_elf_t elf)
grub_elf32_size (grub_elf_t elf, Elf32_Addr *base)
{
Elf32_Addr segments_start = (Elf32_Addr) -1;
Elf32_Addr segments_end = 0;
@ -198,6 +198,9 @@ grub_elf32_size (grub_elf_t elf)
grub_elf32_phdr_iterate (elf, calcsize, 0);
if (base)
*base = 0;
if (nr_phdrs == 0)
{
grub_error (GRUB_ERR_BAD_OS, "no program headers present");
@ -211,10 +214,12 @@ grub_elf32_size (grub_elf_t elf)
return 0;
}
if (base)
*base = segments_start;
return segments_end - segments_start;
}
/* Load every loadable segment into memory specified by `_load_hook'. */
grub_err_t
grub_elf32_load (grub_elf_t _elf, grub_elf32_load_hook_t _load_hook,
@ -353,7 +358,7 @@ grub_elf64_phdr_iterate (grub_elf_t elf,
/* Calculate the amount of memory spanned by the segments. */
grub_size_t
grub_elf64_size (grub_elf_t elf)
grub_elf64_size (grub_elf_t elf, Elf64_Addr *base)
{
Elf64_Addr segments_start = (Elf64_Addr) -1;
Elf64_Addr segments_end = 0;
@ -379,6 +384,9 @@ grub_elf64_size (grub_elf_t elf)
grub_elf64_phdr_iterate (elf, calcsize, 0);
if (base)
*base = 0;
if (nr_phdrs == 0)
{
grub_error (GRUB_ERR_BAD_OS, "no program headers present");
@ -392,6 +400,9 @@ grub_elf64_size (grub_elf_t elf)
return 0;
}
if (base)
*base = segments_start;
return segments_end - segments_start;
}

322
kern/emu/console.c Normal file
View file

@ -0,0 +1,322 @@
/* console.c -- Ncurses console for GRUB. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2003,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 <config.h>
/* For compatibility. */
#ifndef A_NORMAL
# define A_NORMAL 0
#endif /* ! A_NORMAL */
#ifndef A_STANDOUT
# define A_STANDOUT 0
#endif /* ! A_STANDOUT */
#include <grub/emu/console.h>
#include <grub/term.h>
#include <grub/types.h>
#if defined(HAVE_NCURSES_CURSES_H)
# include <ncurses/curses.h>
#elif defined(HAVE_NCURSES_H)
# include <ncurses.h>
#elif defined(HAVE_CURSES_H)
# include <curses.h>
#endif
static int grub_console_attr = A_NORMAL;
grub_uint8_t grub_console_cur_color = 7;
static const grub_uint8_t grub_console_standard_color = 0x7;
#define NUM_COLORS 8
static grub_uint8_t color_map[NUM_COLORS] =
{
COLOR_BLACK,
COLOR_BLUE,
COLOR_GREEN,
COLOR_CYAN,
COLOR_RED,
COLOR_MAGENTA,
COLOR_YELLOW,
COLOR_WHITE
};
static int use_color;
static void
grub_ncurses_putchar (struct grub_term_output *term __attribute__ ((unused)),
const struct grub_unicode_glyph *c)
{
addch (c->base | grub_console_attr);
}
static void
grub_ncurses_setcolorstate (struct grub_term_output *term,
grub_term_color_state state)
{
switch (state)
{
case GRUB_TERM_COLOR_STANDARD:
grub_console_cur_color = grub_console_standard_color;
grub_console_attr = A_NORMAL;
break;
case GRUB_TERM_COLOR_NORMAL:
grub_console_cur_color = term->normal_color;
grub_console_attr = A_NORMAL;
break;
case GRUB_TERM_COLOR_HIGHLIGHT:
grub_console_cur_color = term->highlight_color;
grub_console_attr = A_STANDOUT;
break;
default:
break;
}
if (use_color)
{
grub_uint8_t fg, bg;
fg = (grub_console_cur_color & 7);
bg = (grub_console_cur_color >> 4) & 7;
grub_console_attr = (grub_console_cur_color & 8) ? A_BOLD : A_NORMAL;
color_set ((bg << 3) + fg, 0);
}
}
static int saved_char = ERR;
static int
grub_ncurses_checkkey (struct grub_term_input *term __attribute__ ((unused)))
{
int c;
/* Check for SAVED_CHAR. This should not be true, because this
means checkkey is called twice continuously. */
if (saved_char != ERR)
return saved_char;
wtimeout (stdscr, 100);
c = getch ();
/* If C is not ERR, then put it back in the input queue. */
if (c != ERR)
{
saved_char = c;
return c;
}
return -1;
}
static int
grub_ncurses_getkey (struct grub_term_input *term __attribute__ ((unused)))
{
int c;
/* If checkkey has already got a character, then return it. */
if (saved_char != ERR)
{
c = saved_char;
saved_char = ERR;
}
else
{
wtimeout (stdscr, -1);
c = getch ();
}
switch (c)
{
case KEY_LEFT:
c = GRUB_TERM_LEFT;
break;
case KEY_RIGHT:
c = GRUB_TERM_RIGHT;
break;
case KEY_UP:
c = GRUB_TERM_UP;
break;
case KEY_DOWN:
c = GRUB_TERM_DOWN;
break;
case KEY_IC:
c = 24;
break;
case KEY_DC:
c = GRUB_TERM_DC;
break;
case KEY_BACKSPACE:
/* XXX: For some reason ncurses on xterm does not return
KEY_BACKSPACE. */
case 127:
c = GRUB_TERM_BACKSPACE;
break;
case KEY_HOME:
c = GRUB_TERM_HOME;
break;
case KEY_END:
c = GRUB_TERM_END;
break;
case KEY_NPAGE:
c = GRUB_TERM_NPAGE;
break;
case KEY_PPAGE:
c = GRUB_TERM_PPAGE;
break;
}
return c;
}
static grub_uint16_t
grub_ncurses_getxy (struct grub_term_output *term __attribute__ ((unused)))
{
int x;
int y;
getyx (stdscr, y, x);
return (x << 8) | y;
}
static grub_uint16_t
grub_ncurses_getwh (struct grub_term_output *term __attribute__ ((unused)))
{
int x;
int y;
getmaxyx (stdscr, y, x);
return (x << 8) | y;
}
static void
grub_ncurses_gotoxy (struct grub_term_output *term __attribute__ ((unused)),
grub_uint8_t x, grub_uint8_t y)
{
move (y, x);
}
static void
grub_ncurses_cls (struct grub_term_output *term __attribute__ ((unused)))
{
clear ();
refresh ();
}
static void
grub_ncurses_setcursor (struct grub_term_output *term __attribute__ ((unused)),
int on)
{
curs_set (on ? 1 : 0);
}
static void
grub_ncurses_refresh (struct grub_term_output *term __attribute__ ((unused)))
{
refresh ();
}
static grub_err_t
grub_ncurses_init (struct grub_term_output *term __attribute__ ((unused)))
{
initscr ();
raw ();
noecho ();
scrollok (stdscr, TRUE);
nonl ();
intrflush (stdscr, FALSE);
keypad (stdscr, TRUE);
if (has_colors ())
{
start_color ();
if ((COLORS >= NUM_COLORS) && (COLOR_PAIRS >= NUM_COLORS * NUM_COLORS))
{
int i, j, n;
n = 0;
for (i = 0; i < NUM_COLORS; i++)
for (j = 0; j < NUM_COLORS; j++)
init_pair(n++, color_map[j], color_map[i]);
use_color = 1;
}
}
return 0;
}
static grub_err_t
grub_ncurses_fini (struct grub_term_output *term __attribute__ ((unused)))
{
endwin ();
return 0;
}
static struct grub_term_input grub_ncurses_term_input =
{
.name = "console",
.checkkey = grub_ncurses_checkkey,
.getkey = grub_ncurses_getkey,
};
static struct grub_term_output grub_ncurses_term_output =
{
.name = "console",
.init = grub_ncurses_init,
.fini = grub_ncurses_fini,
.putchar = grub_ncurses_putchar,
.getxy = grub_ncurses_getxy,
.getwh = grub_ncurses_getwh,
.gotoxy = grub_ncurses_gotoxy,
.cls = grub_ncurses_cls,
.setcolorstate = grub_ncurses_setcolorstate,
.setcursor = grub_ncurses_setcursor,
.refresh = grub_ncurses_refresh,
.flags = GRUB_TERM_CODE_TYPE_ASCII
};
void
grub_console_init (void)
{
grub_term_register_output ("console", &grub_ncurses_term_output);
grub_term_register_input ("console", &grub_ncurses_term_input);
}
void
grub_console_fini (void)
{
grub_ncurses_fini (&grub_ncurses_term_output);
}

655
kern/emu/getroot.c Normal file
View file

@ -0,0 +1,655 @@
/* getroot.c - Get root device */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,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 <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#ifdef __GNU__
#include <hurd.h>
#include <hurd/lookup.h>
#include <hurd/fs.h>
#include <sys/mman.h>
#endif
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/emu/misc.h>
#include <grub/emu/hostdisk.h>
#include <grub/emu/getroot.h>
static void
strip_extra_slashes (char *dir)
{
char *p = dir;
while ((p = strchr (p, '/')) != 0)
{
if (p[1] == '/')
{
memmove (p, p + 1, strlen (p));
continue;
}
else if (p[1] == '\0')
{
if (p > dir)
p[0] = '\0';
break;
}
p++;
}
}
static char *
xgetcwd (void)
{
size_t size = 10;
char *path;
path = xmalloc (size);
while (! getcwd (path, size))
{
size <<= 1;
path = xrealloc (path, size);
}
return path;
}
#ifdef __linux__
/* Statting something on a btrfs filesystem always returns a virtual device
major/minor pair rather than the real underlying device, because btrfs
can span multiple underlying devices (and even if it's currently only
using a single device it can be dynamically extended onto another). We
can't deal with the multiple-device case yet, but in the meantime, we can
at least cope with the single-device case by scanning
/proc/self/mountinfo. */
static char *
find_root_device_from_mountinfo (const char *dir)
{
FILE *fp;
char *buf = NULL;
size_t len = 0;
char *ret = NULL;
fp = fopen ("/proc/self/mountinfo", "r");
if (! fp)
return NULL; /* fall through to other methods */
while (getline (&buf, &len, fp) > 0)
{
int mnt_id, parent_mnt_id;
unsigned int major, minor;
char enc_root[PATH_MAX], enc_path[PATH_MAX];
int count;
size_t enc_path_len;
const char *sep;
char fstype[PATH_MAX], device[PATH_MAX];
struct stat st;
if (sscanf (buf, "%d %d %u:%u %s %s%n",
&mnt_id, &parent_mnt_id, &major, &minor, enc_root, enc_path,
&count) < 6)
continue;
if (strcmp (enc_root, "/") != 0)
continue; /* only a subtree is mounted */
enc_path_len = strlen (enc_path);
if (strncmp (dir, enc_path, enc_path_len) != 0 ||
(dir[enc_path_len] && dir[enc_path_len] != '/'))
continue;
/* This is a parent of the requested directory. /proc/self/mountinfo
is in mount order, so it must be the closest parent we've
encountered so far. If it's virtual, return its device node;
otherwise, carry on to try to find something closer. */
free (ret);
ret = NULL;
if (major != 0)
continue; /* not a virtual device */
sep = strstr (buf + count, " - ");
if (!sep)
continue;
sep += sizeof (" - ") - 1;
if (sscanf (sep, "%s %s", fstype, device) != 2)
continue;
if (stat (device, &st) < 0)
continue;
if (!S_ISBLK (st.st_mode))
continue; /* not a block device */
ret = strdup (device);
}
free (buf);
fclose (fp);
return ret;
}
#endif /* __linux__ */
#ifdef __MINGW32__
static char *
find_root_device (const char *dir __attribute__ ((unused)),
dev_t dev __attribute__ ((unused)))
{
return 0;
}
#elif ! defined(__CYGWIN__)
static char *
find_root_device (const char *dir, dev_t dev)
{
DIR *dp;
char *saved_cwd;
struct dirent *ent;
dp = opendir (dir);
if (! dp)
return 0;
saved_cwd = xgetcwd ();
grub_util_info ("changing current directory to %s", dir);
if (chdir (dir) < 0)
{
free (saved_cwd);
closedir (dp);
return 0;
}
while ((ent = readdir (dp)) != 0)
{
struct stat st;
/* Avoid:
- dotfiles (like "/dev/.tmp.md0") since they could be duplicates.
- dotdirs (like "/dev/.static") since they could contain duplicates. */
if (ent->d_name[0] == '.')
continue;
if (lstat (ent->d_name, &st) < 0)
/* Ignore any error. */
continue;
if (S_ISLNK (st.st_mode)) {
#ifdef __linux__
if (strcmp (dir, "mapper") == 0) {
/* Follow symbolic links under /dev/mapper/; the canonical name
may be something like /dev/dm-0, but the names under
/dev/mapper/ are more human-readable and so we prefer them if
we can get them. */
if (stat (ent->d_name, &st) < 0)
continue;
} else
#endif /* __linux__ */
/* Don't follow other symbolic links. */
continue;
}
if (S_ISDIR (st.st_mode))
{
/* Find it recursively. */
char *res;
res = find_root_device (ent->d_name, dev);
if (res)
{
if (chdir (saved_cwd) < 0)
grub_util_error ("cannot restore the original directory");
free (saved_cwd);
closedir (dp);
return res;
}
}
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
if (S_ISCHR (st.st_mode) && st.st_rdev == dev)
#else
if (S_ISBLK (st.st_mode) && st.st_rdev == dev)
#endif
{
#ifdef __linux__
/* Skip device names like /dev/dm-0, which are short-hand aliases
to more descriptive device names, e.g. those under /dev/mapper */
if (ent->d_name[0] == 'd' &&
ent->d_name[1] == 'm' &&
ent->d_name[2] == '-' &&
ent->d_name[3] >= '0' &&
ent->d_name[3] <= '9')
continue;
#endif
/* Found! */
char *res;
char *cwd;
#if defined(__NetBSD__)
/* Convert this block device to its character (raw) device. */
const char *template = "%s/r%s";
#else
/* Keep the device name as it is. */
const char *template = "%s/%s";
#endif
cwd = xgetcwd ();
res = xmalloc (strlen (cwd) + strlen (ent->d_name) + 3);
sprintf (res, template, cwd, ent->d_name);
strip_extra_slashes (res);
free (cwd);
/* /dev/root is not a real block device keep looking, takes care
of situation where root filesystem is on the same partition as
grub files */
if (strcmp(res, "/dev/root") == 0)
continue;
if (chdir (saved_cwd) < 0)
grub_util_error ("cannot restore the original directory");
free (saved_cwd);
closedir (dp);
return res;
}
}
if (chdir (saved_cwd) < 0)
grub_util_error ("cannot restore the original directory");
free (saved_cwd);
closedir (dp);
return 0;
}
#else /* __CYGWIN__ */
/* Read drive/partition serial number from mbr/boot sector,
return 0 on read error, ~0 on unknown serial. */
static unsigned
get_bootsec_serial (const char *os_dev, int mbr)
{
/* Read boot sector. */
int fd = open (os_dev, O_RDONLY);
if (fd < 0)
return 0;
unsigned char buf[0x200];
int n = read (fd, buf, sizeof (buf));
close (fd);
if (n != sizeof(buf))
return 0;
/* Check signature. */
if (!(buf[0x1fe] == 0x55 && buf[0x1ff] == 0xaa))
return ~0;
/* Serial number offset depends on boot sector type. */
if (mbr)
n = 0x1b8;
else if (memcmp (buf + 0x03, "NTFS", 4) == 0)
n = 0x048;
else if (memcmp (buf + 0x52, "FAT32", 5) == 0)
n = 0x043;
else if (memcmp (buf + 0x36, "FAT", 3) == 0)
n = 0x027;
else
return ~0;
unsigned serial = *(unsigned *)(buf + n);
if (serial == 0)
return ~0;
return serial;
}
static char *
find_cygwin_root_device (const char *path, dev_t dev)
{
/* No root device for /cygdrive. */
if (dev == (DEV_CYGDRIVE_MAJOR << 16))
return 0;
/* Convert to full POSIX and Win32 path. */
char fullpath[PATH_MAX], winpath[PATH_MAX];
cygwin_conv_to_full_posix_path (path, fullpath);
cygwin_conv_to_full_win32_path (fullpath, winpath);
/* If identical, this is no real filesystem path. */
if (strcmp (fullpath, winpath) == 0)
return 0;
/* Check for floppy drive letter. */
if (winpath[0] && winpath[1] == ':' && strchr ("AaBb", winpath[0]))
return xstrdup (strchr ("Aa", winpath[0]) ? "/dev/fd0" : "/dev/fd1");
/* Cygwin returns the partition serial number in stat.st_dev.
This is never identical to the device number of the emulated
/dev/sdXN device, so above find_root_device () does not work.
Search the partition with the same serial in boot sector instead. */
char devpath[sizeof ("/dev/sda15") + 13]; /* Size + Paranoia. */
int d;
for (d = 'a'; d <= 'z'; d++)
{
sprintf (devpath, "/dev/sd%c", d);
if (get_bootsec_serial (devpath, 1) == 0)
continue;
int p;
for (p = 1; p <= 15; p++)
{
sprintf (devpath, "/dev/sd%c%d", d, p);
unsigned ser = get_bootsec_serial (devpath, 0);
if (ser == 0)
break;
if (ser != (unsigned)~0 && dev == (dev_t)ser)
return xstrdup (devpath);
}
}
return 0;
}
#endif /* __CYGWIN__ */
char *
grub_guess_root_device (const char *dir)
{
char *os_dev;
#ifdef __GNU__
file_t file;
mach_port_t *ports;
int *ints;
loff_t *offsets;
char *data;
error_t err;
mach_msg_type_number_t num_ports = 0, num_ints = 0, num_offsets = 0, data_len = 0;
size_t name_len;
file = file_name_lookup (dir, 0, 0);
if (file == MACH_PORT_NULL)
return 0;
err = file_get_storage_info (file,
&ports, &num_ports,
&ints, &num_ints,
&offsets, &num_offsets,
&data, &data_len);
if (num_ints < 1)
grub_util_error ("Storage info for `%s' does not include type", dir);
if (ints[0] != STORAGE_DEVICE)
grub_util_error ("Filesystem of `%s' is not stored on local disk", dir);
if (num_ints < 5)
grub_util_error ("Storage info for `%s' does not include name", dir);
name_len = ints[4];
if (name_len < data_len)
grub_util_error ("Bogus name length for storage info for `%s'", dir);
if (data[name_len - 1] != '\0')
grub_util_error ("Storage name for `%s' not NUL-terminated", dir);
os_dev = xmalloc (strlen ("/dev/") + data_len);
memcpy (os_dev, "/dev/", strlen ("/dev/"));
memcpy (os_dev + strlen ("/dev/"), data, data_len);
if (ports && num_ports > 0)
{
mach_msg_type_number_t i;
for (i = 0; i < num_ports; i++)
{
mach_port_t port = ports[i];
if (port != MACH_PORT_NULL)
mach_port_deallocate (mach_task_self(), port);
}
munmap ((caddr_t) ports, num_ports * sizeof (*ports));
}
if (ints && num_ints > 0)
munmap ((caddr_t) ints, num_ints * sizeof (*ints));
if (offsets && num_offsets > 0)
munmap ((caddr_t) offsets, num_offsets * sizeof (*offsets));
if (data && data_len > 0)
munmap (data, data_len);
mach_port_deallocate (mach_task_self (), file);
#else /* !__GNU__ */
struct stat st;
#ifdef __linux__
os_dev = find_root_device_from_mountinfo (dir);
if (os_dev)
return os_dev;
#endif /* __linux__ */
if (stat (dir, &st) < 0)
grub_util_error ("cannot stat `%s'", dir);
#ifdef __CYGWIN__
/* Cygwin specific function. */
os_dev = find_cygwin_root_device (dir, st.st_dev);
#else
/* This might be truly slow, but is there any better way? */
os_dev = find_root_device ("/dev", st.st_dev);
#endif
#endif /* !__GNU__ */
return os_dev;
}
static int
grub_util_is_dmraid (const char *os_dev)
{
if (! strncmp (os_dev, "/dev/mapper/nvidia_", 19))
return 1;
else if (! strncmp (os_dev, "/dev/mapper/isw_", 16))
return 1;
else if (! strncmp (os_dev, "/dev/mapper/hpt37x_", 19))
return 1;
else if (! strncmp (os_dev, "/dev/mapper/hpt45x_", 19))
return 1;
else if (! strncmp (os_dev, "/dev/mapper/via_", 16))
return 1;
else if (! strncmp (os_dev, "/dev/mapper/lsi_", 16))
return 1;
else if (! strncmp (os_dev, "/dev/mapper/pdc_", 16))
return 1;
else if (! strncmp (os_dev, "/dev/mapper/jmicron_", 20))
return 1;
else if (! strncmp (os_dev, "/dev/mapper/asr_", 16))
return 1;
else if (! strncmp (os_dev, "/dev/mapper/sil_", 16))
return 1;
return 0;
}
int
grub_util_get_dev_abstraction (const char *os_dev __attribute__((unused)))
{
#ifdef __linux__
/* Check for LVM. */
if (!strncmp (os_dev, "/dev/mapper/", 12)
&& ! grub_util_is_dmraid (os_dev)
&& strncmp (os_dev, "/dev/mapper/mpath", 17) != 0)
return GRUB_DEV_ABSTRACTION_LVM;
/* Check for RAID. */
if (!strncmp (os_dev, "/dev/md", 7))
return GRUB_DEV_ABSTRACTION_RAID;
#endif
/* No abstraction found. */
return GRUB_DEV_ABSTRACTION_NONE;
}
char *
grub_util_get_grub_dev (const char *os_dev)
{
char *grub_dev;
switch (grub_util_get_dev_abstraction (os_dev))
{
case GRUB_DEV_ABSTRACTION_LVM:
{
unsigned short i, len;
grub_size_t offset = sizeof ("/dev/mapper/") - 1;
len = strlen (os_dev) - offset + 1;
grub_dev = xmalloc (len);
for (i = 0; i < len; i++, offset++)
{
grub_dev[i] = os_dev[offset];
if (os_dev[offset] == '-' && os_dev[offset + 1] == '-')
offset++;
}
}
break;
case GRUB_DEV_ABSTRACTION_RAID:
if (os_dev[7] == '_' && os_dev[8] == 'd')
{
/* This a partitionable RAID device of the form /dev/md_dNNpMM. */
char *p, *q;
p = strdup (os_dev + sizeof ("/dev/md_d") - 1);
q = strchr (p, 'p');
if (q)
*q = ',';
grub_dev = xasprintf ("md%s", p);
free (p);
}
else if (os_dev[7] == '/' && os_dev[8] == 'd')
{
/* This a partitionable RAID device of the form /dev/md/dNNpMM. */
char *p, *q;
p = strdup (os_dev + sizeof ("/dev/md/d") - 1);
q = strchr (p, 'p');
if (q)
*q = ',';
grub_dev = xasprintf ("md%s", p);
free (p);
}
else if (os_dev[7] >= '0' && os_dev[7] <= '9')
{
char *p , *q;
p = strdup (os_dev + sizeof ("/dev/md") - 1);
q = strchr (p, 'p');
if (q)
*q = ',';
grub_dev = xasprintf ("md%s", p);
free (p);
}
else if (os_dev[7] == '/' && os_dev[8] >= '0' && os_dev[8] <= '9')
{
char *p , *q;
p = strdup (os_dev + sizeof ("/dev/md/") - 1);
q = strchr (p, 'p');
if (q)
*q = ',';
grub_dev = xasprintf ("md%s", p);
free (p);
}
else if (os_dev[7] == '/')
{
/* mdraid 1.x with a free name. */
char *p , *q;
p = strdup (os_dev + sizeof ("/dev/md/") - 1);
q = strchr (p, 'p');
if (q)
*q = ',';
asprintf (&grub_dev, "%s", p);
free (p);
}
else
grub_util_error ("unknown kind of RAID device `%s'", os_dev);
break;
default: /* GRUB_DEV_ABSTRACTION_NONE */
grub_dev = grub_util_biosdisk_get_grub_dev (os_dev);
}
return grub_dev;
}
const char *
grub_util_check_block_device (const char *blk_dev)
{
struct stat st;
if (stat (blk_dev, &st) < 0)
grub_util_error ("cannot stat `%s'", blk_dev);
if (S_ISBLK (st.st_mode))
return (blk_dev);
else
return 0;
}
const char *
grub_util_check_char_device (const char *blk_dev)
{
struct stat st;
if (stat (blk_dev, &st) < 0)
grub_util_error ("cannot stat `%s'", blk_dev);
if (S_ISCHR (st.st_mode))
return (blk_dev);
else
return 0;
}

1554
kern/emu/hostdisk.c Normal file

File diff suppressed because it is too large Load diff

175
kern/emu/hostfs.c Normal file
View file

@ -0,0 +1,175 @@
/* hostfs.c - Dummy filesystem to provide access to the hosts filesystem */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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
* 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 _BSD_SOURCE
#include <grub/fs.h>
#include <grub/file.h>
#include <grub/disk.h>
#include <grub/misc.h>
#include <grub/dl.h>
#include <grub/util/misc.h>
#include <dirent.h>
#include <stdio.h>
#include <errno.h>
/* dirent.d_type is a BSD extension, not part of POSIX */
#include <sys/stat.h>
#include <string.h>
static int
is_dir (const char *path, const char *name)
{
int len1 = strlen(path);
int len2 = strlen(name);
char pathname[len1 + 1 + len2 + 1 + 13];
strcpy (pathname, path);
/* Avoid UNC-path "//name" on Cygwin. */
if (len1 > 0 && pathname[len1 - 1] != '/')
strcat (pathname, "/");
strcat (pathname, name);
struct stat st;
if (stat (pathname, &st))
return 0;
return S_ISDIR (st.st_mode);
}
static grub_err_t
grub_hostfs_dir (grub_device_t device, const char *path,
int (*hook) (const char *filename,
const struct grub_dirhook_info *info))
{
DIR *dir;
/* Check if the disk is our dummy disk. */
if (grub_strcmp (device->disk->name, "host"))
return grub_error (GRUB_ERR_BAD_FS, "not a hostfs");
dir = opendir (path);
if (! dir)
return grub_error (GRUB_ERR_BAD_FILENAME,
"can't open the hostfs directory `%s'", path);
while (1)
{
struct dirent *de;
struct grub_dirhook_info info;
grub_memset (&info, 0, sizeof (info));
de = readdir (dir);
if (! de)
break;
info.dir = !! is_dir (path, de->d_name);
hook (de->d_name, &info);
}
closedir (dir);
return GRUB_ERR_NONE;
}
/* Open a file named NAME and initialize FILE. */
static grub_err_t
grub_hostfs_open (struct grub_file *file, const char *name)
{
FILE *f;
f = fopen (name, "rb");
if (! f)
return grub_error (GRUB_ERR_BAD_FILENAME,
"can't open `%s'", name);
file->data = f;
#ifdef __MINGW32__
file->size = grub_util_get_disk_size (name);
#else
fseeko (f, 0, SEEK_END);
file->size = ftello (f);
fseeko (f, 0, SEEK_SET);
#endif
return GRUB_ERR_NONE;
}
static grub_ssize_t
grub_hostfs_read (grub_file_t file, char *buf, grub_size_t len)
{
FILE *f;
f = (FILE *) file->data;
if (fseeko (f, file->offset, SEEK_SET) != 0)
{
grub_error (GRUB_ERR_OUT_OF_RANGE, "fseeko: %s", strerror (errno));
return -1;
}
unsigned int s = fread (buf, 1, len, f);
if (s != len)
grub_error (GRUB_ERR_FILE_READ_ERROR, "fread: %s", strerror (errno));
return (signed) s;
}
static grub_err_t
grub_hostfs_close (grub_file_t file)
{
FILE *f;
f = (FILE *) file->data;
fclose (f);
return GRUB_ERR_NONE;
}
static grub_err_t
grub_hostfs_label (grub_device_t device __attribute ((unused)),
char **label __attribute ((unused)))
{
*label = 0;
return GRUB_ERR_NONE;
}
static struct grub_fs grub_hostfs_fs =
{
.name = "hostfs",
.dir = grub_hostfs_dir,
.open = grub_hostfs_open,
.read = grub_hostfs_read,
.close = grub_hostfs_close,
.label = grub_hostfs_label,
.next = 0
};
GRUB_MOD_INIT(hostfs)
{
grub_fs_register (&grub_hostfs_fs);
}
GRUB_MOD_FINI(hostfs)
{
grub_fs_unregister (&grub_hostfs_fs);
}

296
kern/emu/main.c Normal file
View file

@ -0,0 +1,296 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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
* 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 <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <sys/stat.h>
#include <getopt.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <grub/dl.h>
#include <grub/mm.h>
#include <grub/setjmp.h>
#include <grub/fs.h>
#include <grub/emu/hostdisk.h>
#include <grub/time.h>
#include <grub/emu/console.h>
#include <grub/emu/misc.h>
#include <grub/kernel.h>
#include <grub/normal.h>
#include <grub/emu/getroot.h>
#include <grub/env.h>
#include <grub/partition.h>
#include <grub/i18n.h>
#define ENABLE_RELOCATABLE 0
#include "progname.h"
/* Used for going back to the main function. */
static jmp_buf main_env;
/* Store the prefix specified by an argument. */
static char *prefix = NULL;
grub_addr_t
grub_arch_modules_addr (void)
{
return 0;
}
#if GRUB_NO_MODULES
grub_err_t
grub_arch_dl_check_header (void *ehdr)
{
(void) ehdr;
return GRUB_ERR_BAD_MODULE;
}
grub_err_t
grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
{
(void) mod;
(void) ehdr;
return GRUB_ERR_BAD_MODULE;
}
#endif
void
grub_reboot (void)
{
longjmp (main_env, 1);
}
void
grub_halt (
#ifdef GRUB_MACHINE_PCBIOS
int no_apm __attribute__ ((unused))
#endif
)
{
grub_reboot ();
}
void
grub_machine_init (void)
{
}
void
grub_machine_set_prefix (void)
{
grub_env_set ("prefix", prefix);
free (prefix);
prefix = 0;
}
void
grub_machine_fini (void)
{
grub_console_fini ();
}
static struct option options[] =
{
{"root-device", required_argument, 0, 'r'},
{"device-map", required_argument, 0, 'm'},
{"directory", required_argument, 0, 'd'},
{"hold", optional_argument, 0, 'H'},
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
{"verbose", no_argument, 0, 'v'},
{ 0, 0, 0, 0 }
};
static int
usage (int status)
{
if (status)
fprintf (stderr,
"Try `%s --help' for more information.\n", program_name);
else
printf (
"Usage: %s [OPTION]...\n"
"\n"
"GRUB emulator.\n"
"\n"
" -r, --root-device=DEV use DEV as the root device [default=guessed]\n"
" -m, --device-map=FILE use FILE as the device map [default=%s]\n"
" -d, --directory=DIR use GRUB files in the directory DIR [default=%s]\n"
" -v, --verbose print verbose messages\n"
" -H, --hold[=SECONDS] wait until a debugger will attach\n"
" -h, --help display this message and exit\n"
" -V, --version print version information and exit\n"
"\n"
"Report bugs to <%s>.\n", program_name, DEFAULT_DEVICE_MAP, DEFAULT_DIRECTORY, PACKAGE_BUGREPORT);
return status;
}
void grub_hostfs_init (void);
void grub_hostfs_fini (void);
void grub_host_init (void);
void grub_host_fini (void);
#if GRUB_NO_MODULES
void grub_init_all (void);
void grub_fini_all (void);
#endif
int
main (int argc, char *argv[])
{
char *root_dev = 0;
char *dir = DEFAULT_DIRECTORY;
char *dev_map = DEFAULT_DEVICE_MAP;
volatile int hold = 0;
int opt;
set_program_name (argv[0]);
while ((opt = getopt_long (argc, argv, "r:d:m:vH:hV", options, 0)) != -1)
switch (opt)
{
case 'r':
root_dev = optarg;
break;
case 'd':
dir = optarg;
break;
case 'm':
dev_map = optarg;
break;
case 'v':
verbosity++;
break;
case 'H':
hold = (optarg ? atoi (optarg) : -1);
break;
case 'h':
return usage (0);
case 'V':
printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION);
return 0;
default:
return usage (1);
}
if (optind < argc)
{
fprintf (stderr, "Unknown extra argument `%s'.\n", argv[optind]);
return usage (1);
}
/* Wait until the ARGS.HOLD variable is cleared by an attached debugger. */
if (hold && verbosity > 0)
printf ("Run \"gdb %s %d\", and set ARGS.HOLD to zero.\n",
program_name, (int) getpid ());
while (hold)
{
if (hold > 0)
hold--;
sleep (1);
}
signal (SIGINT, SIG_IGN);
grub_console_init ();
grub_host_init ();
grub_hostfs_init ();
/* XXX: This is a bit unportable. */
grub_util_biosdisk_init (dev_map);
#if GRUB_NO_MODULES
grub_init_all ();
#endif
/* Make sure that there is a root device. */
if (! root_dev)
{
char *device_name = grub_guess_root_device (dir);
if (! device_name)
grub_util_error ("cannot find a device for %s", dir);
root_dev = grub_util_get_grub_dev (device_name);
if (! root_dev)
{
grub_util_info ("guessing the root device failed, because of `%s'",
grub_errmsg);
grub_util_error ("cannot guess the root device. Specify the option `--root-device'");
}
}
if (strcmp (root_dev, "host") == 0)
dir = xstrdup (dir);
else
dir = grub_make_system_path_relative_to_its_root (dir);
prefix = xmalloc (strlen (root_dev) + 2 + strlen (dir) + 1);
sprintf (prefix, "(%s)%s", root_dev, dir);
free (dir);
/* Start GRUB! */
if (setjmp (main_env) == 0)
grub_main ();
#if GRUB_NO_MODULES
grub_fini_all ();
#endif
grub_hostfs_fini ();
grub_host_fini ();
grub_machine_fini ();
return 0;
}
#ifdef __MINGW32__
void
grub_millisleep (grub_uint32_t ms)
{
Sleep (ms);
}
#else
void
grub_millisleep (grub_uint32_t ms)
{
struct timespec ts;
ts.tv_sec = ms / 1000;
ts.tv_nsec = (ms % 1000) * 1000000;
nanosleep (&ts, NULL);
}
#endif
#if GRUB_NO_MODULES
void
grub_register_exported_symbols (void)
{
}
#endif

352
kern/emu/misc.c Normal file
View file

@ -0,0 +1,352 @@
#include <config.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/env.h>
#include <grub/types.h>
#include <grub/misc.h>
#include <grub/i18n.h>
#include <grub/time.h>
#include <grub/emu/misc.h>
#ifdef HAVE_DEVICE_MAPPER
# include <libdevmapper.h>
#endif
int verbosity;
void
grub_util_warn (const char *fmt, ...)
{
va_list ap;
fprintf (stderr, _("%s: warn:"), program_name);
fprintf (stderr, " ");
va_start (ap, fmt);
vfprintf (stderr, fmt, ap);
va_end (ap);
fprintf (stderr, ".\n");
fflush (stderr);
}
void
grub_util_info (const char *fmt, ...)
{
if (verbosity > 0)
{
va_list ap;
fprintf (stderr, _("%s: info:"), program_name);
fprintf (stderr, " ");
va_start (ap, fmt);
vfprintf (stderr, fmt, ap);
va_end (ap);
fprintf (stderr, ".\n");
fflush (stderr);
}
}
void
grub_util_error (const char *fmt, ...)
{
va_list ap;
fprintf (stderr, _("%s: error:"), program_name);
fprintf (stderr, " ");
va_start (ap, fmt);
vfprintf (stderr, fmt, ap);
va_end (ap);
fprintf (stderr, ".\n");
exit (1);
}
void *
xmalloc (grub_size_t size)
{
void *p;
p = malloc (size);
if (! p)
grub_util_error ("out of memory");
return p;
}
void *
xrealloc (void *ptr, grub_size_t size)
{
ptr = realloc (ptr, size);
if (! ptr)
grub_util_error ("out of memory");
return ptr;
}
char *
xstrdup (const char *str)
{
size_t len;
char *newstr;
len = strlen (str);
newstr = (char *) xmalloc (len + 1);
memcpy (newstr, str, len + 1);
return newstr;
}
#ifndef HAVE_VASPRINTF
int
vasprintf (char **buf, const char *fmt, va_list ap)
{
/* Should be large enough. */
*buf = xmalloc (512);
return vsprintf (*buf, fmt, ap);
}
#endif
#ifndef HAVE_ASPRINTF
int
asprintf (char **buf, const char *fmt, ...)
{
int status;
va_list ap;
va_start (ap, fmt);
status = vasprintf (*buf, fmt, ap);
va_end (ap);
return status;
}
#endif
char *
xasprintf (const char *fmt, ...)
{
va_list ap;
char *result;
va_start (ap, fmt);
if (vasprintf (&result, fmt, ap) < 0)
{
if (errno == ENOMEM)
grub_util_error ("out of memory");
return NULL;
}
return result;
}
void
grub_exit (void)
{
exit (1);
}
grub_uint64_t
grub_get_time_ms (void)
{
struct timeval tv;
gettimeofday (&tv, 0);
return (tv.tv_sec * 1000 + tv.tv_usec / 1000);
}
grub_uint32_t
grub_get_rtc (void)
{
struct timeval tv;
gettimeofday (&tv, 0);
return (tv.tv_sec * GRUB_TICKS_PER_SECOND
+ (((tv.tv_sec % GRUB_TICKS_PER_SECOND) * 1000000 + tv.tv_usec)
* GRUB_TICKS_PER_SECOND / 1000000));
}
char *
canonicalize_file_name (const char *path)
{
char *ret;
#ifdef PATH_MAX
ret = xmalloc (PATH_MAX);
if (!realpath (path, ret))
return NULL;
#else
ret = realpath (path, NULL);
#endif
return ret;
}
#ifdef __CYGWIN__
/* Convert POSIX path to Win32 path,
remove drive letter, replace backslashes. */
static char *
get_win32_path (const char *path)
{
char winpath[PATH_MAX];
if (cygwin_conv_path (CCP_POSIX_TO_WIN_A, path, winpath, sizeof(winpath)))
grub_util_error ("cygwin_conv_path() failed");
int len = strlen (winpath);
int offs = (len > 2 && winpath[1] == ':' ? 2 : 0);
int i;
for (i = offs; i < len; i++)
if (winpath[i] == '\\')
winpath[i] = '/';
return xstrdup (winpath + offs);
}
#endif
/* This function never prints trailing slashes (so that its output
can be appended a slash unconditionally). */
char *
grub_make_system_path_relative_to_its_root (const char *path)
{
struct stat st;
char *p, *buf, *buf2, *buf3;
uintptr_t offset = 0;
dev_t num;
size_t len;
/* canonicalize. */
p = canonicalize_file_name (path);
if (p == NULL)
grub_util_error ("failed to get canonical path of %s", path);
len = strlen (p) + 1;
buf = xstrdup (p);
free (p);
if (stat (buf, &st) < 0)
grub_util_error ("cannot stat %s: %s", buf, strerror (errno));
buf2 = xstrdup (buf);
num = st.st_dev;
/* This loop sets offset to the number of chars of the root
directory we're inspecting. */
while (1)
{
p = strrchr (buf, '/');
if (p == NULL)
/* This should never happen. */
grub_util_error ("FIXME: no / in buf. (make_system_path_relative_to_its_root)");
if (p != buf)
*p = 0;
else
*++p = 0;
if (stat (buf, &st) < 0)
grub_util_error ("cannot stat %s: %s", buf, strerror (errno));
/* buf is another filesystem; we found it. */
if (st.st_dev != num)
{
/* offset == 0 means path given is the mount point.
This works around special-casing of "/" in Un*x. This function never
prints trailing slashes (so that its output can be appended a slash
unconditionally). Each slash in is considered a preceding slash, and
therefore the root directory is an empty string. */
if (offset == 0)
{
free (buf);
free (buf2);
return xstrdup ("");
}
else
break;
}
offset = p - buf;
/* offset == 1 means root directory. */
if (offset == 1)
{
/* Include leading slash. */
offset = 0;
break;
}
}
free (buf);
buf3 = xstrdup (buf2 + offset);
free (buf2);
#ifdef __CYGWIN__
if (st.st_dev != (DEV_CYGDRIVE_MAJOR << 16))
{
/* Reached some mount point not below /cygdrive.
GRUB does not know Cygwin's emulated mounts,
convert to Win32 path. */
grub_util_info ("Cygwin path = %s\n", buf3);
char * temp = get_win32_path (buf3);
free (buf3);
buf3 = temp;
}
#endif
/* Remove trailing slashes, return empty string if root directory. */
len = strlen (buf3);
while (len > 0 && buf3[len - 1] == '/')
{
buf3[len - 1] = '\0';
len--;
}
return buf3;
}
#ifdef HAVE_DEVICE_MAPPER
static void device_mapper_null_log (int level __attribute__ ((unused)),
const char *file __attribute__ ((unused)),
int line __attribute__ ((unused)),
int dm_errno __attribute__ ((unused)),
const char *f __attribute__ ((unused)),
...)
{
}
int
grub_device_mapper_supported (void)
{
static int supported = -1;
if (supported == -1)
{
struct dm_task *dmt;
/* Suppress annoying log messages. */
dm_log_with_errno_init (&device_mapper_null_log);
dmt = dm_task_create (DM_DEVICE_VERSION);
supported = (dmt != NULL);
if (dmt)
dm_task_destroy (dmt);
/* Restore the original logger. */
dm_log_with_errno_init (NULL);
}
return supported;
}
#endif /* HAVE_DEVICE_MAPPER */

85
kern/emu/mm.c Normal file
View file

@ -0,0 +1,85 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2003,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
* 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/err.h>
#include <grub/mm.h>
#include <stdlib.h>
#include <string.h>
void *
grub_malloc (grub_size_t size)
{
void *ret;
ret = malloc (size);
if (!ret)
grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
return ret;
}
void *
grub_zalloc (grub_size_t size)
{
void *ret;
ret = grub_malloc (size);
if (!ret)
return NULL;
memset (ret, 0, size);
return ret;
}
void
grub_free (void *ptr)
{
free (ptr);
}
void *
grub_realloc (void *ptr, grub_size_t size)
{
void *ret;
ret = realloc (ptr, size);
if (!ret)
grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
return ret;
}
void *
grub_memalign (grub_size_t align, grub_size_t size)
{
void *p;
#if defined(HAVE_POSIX_MEMALIGN)
if (align < sizeof (void *))
align = sizeof (void *);
if (posix_memalign (&p, align, size) != 0)
p = 0;
#elif defined(HAVE_MEMALIGN)
p = memalign (align, size);
#else
(void) align;
(void) size;
grub_util_error ("grub_memalign is not supported");
#endif
if (!p)
grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
return p;
}

46
kern/emu/time.c Normal file
View file

@ -0,0 +1,46 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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/datetime.h>
#include <time.h>
grub_err_t
grub_get_datetime (struct grub_datetime *datetime)
{
struct tm *mytm;
time_t mytime;
mytime = time (&mytime);
mytm = gmtime (&mytime);
datetime->year = mytm->tm_year + 1900;
datetime->month = mytm->tm_mon + 1;
datetime->day = mytm->tm_mday;
datetime->hour = mytm->tm_hour;
datetime->minute = mytm->tm_min;
datetime->second = mytm->tm_sec;
return GRUB_ERR_NONE;
}
grub_err_t
grub_set_datetime (struct grub_datetime *datetime __attribute__ ((unused)))
{
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"no clock setting routine available");
}

View file

@ -18,34 +18,15 @@
*/
#include <grub/env.h>
#include <grub/env_private.h>
#include <grub/misc.h>
#include <grub/mm.h>
/* The size of the hash table. */
#define HASHSZ 13
/* A hashtable for quick lookup of variables. */
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;
};
/* This is used for sorting only. */
struct grub_env_sorted_var
{
struct grub_env_var *var;
struct grub_env_sorted_var *next;
};
/* The initial context. */
static struct grub_env_context initial_context;
/* The current context. */
static struct grub_env_context *current_context = &initial_context;
struct grub_env_context *grub_current_context = &initial_context;
/* Return the hash representation of the string S. */
static unsigned int
@ -60,88 +41,20 @@ grub_env_hashval (const char *s)
return i % HASHSZ;
}
static struct grub_env_var *
struct grub_env_var *
grub_env_find (const char *name)
{
struct grub_env_var *var;
int idx = grub_env_hashval (name);
/* Look for the variable in the current context. */
for (var = current_context->vars[idx]; var; var = var->next)
for (var = grub_current_context->vars[idx]; var; var = var->next)
if (grub_strcmp (var->name, name) == 0)
return var;
return 0;
}
grub_err_t
grub_env_context_open (int export)
{
struct grub_env_context *context;
int i;
context = grub_zalloc (sizeof (*context));
if (! context)
return grub_errno;
context->prev = current_context;
current_context = context;
/* Copy exported variables. */
for (i = 0; i < HASHSZ; i++)
{
struct grub_env_var *var;
for (var = context->prev->vars[i]; var; var = var->next)
{
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;
}
grub_err_t
grub_env_context_close (void)
{
struct grub_env_context *context;
int i;
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->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);
}
}
/* Restore the previous context. */
context = current_context->prev;
grub_free (current_context);
current_context = context;
return GRUB_ERR_NONE;
}
static void
grub_env_insert (struct grub_env_context *context,
struct grub_env_var *var)
@ -165,26 +78,6 @@ grub_env_remove (struct grub_env_var *var)
var->next->prevp = var->prevp;
}
grub_err_t
grub_env_export (const char *name)
{
struct grub_env_var *var;
var = grub_env_find (name);
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;
}
grub_err_t
grub_env_set (const char *name, const char *val)
{
@ -216,9 +109,8 @@ grub_env_set (const char *name, const char *val)
if (! var)
return grub_errno;
/* This is not necessary, because GRUB_ENV_VAR_LOCAL == 0. But leave
this for readability. */
var->type = GRUB_ENV_VAR_LOCAL;
/* This is not necessary. But leave this for readability. */
var->global = 0;
var->name = grub_strdup (name);
if (! var->name)
@ -228,7 +120,7 @@ grub_env_set (const char *name, const char *val)
if (! var->value)
goto fail;
grub_env_insert (current_context, var);
grub_env_insert (grub_current_context, var);
return GRUB_ERR_NONE;
@ -264,16 +156,16 @@ grub_env_unset (const char *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);
grub_free (var->name);
if (var->type != GRUB_ENV_VAR_DATA)
grub_free (var->value);
grub_free (var->value);
grub_free (var);
}
@ -289,14 +181,10 @@ grub_env_iterate (int (*func) (struct grub_env_var *var))
{
struct grub_env_var *var;
for (var = current_context->vars[i]; var; var = var->next)
for (var = grub_current_context->vars[i]; var; var = var->next)
{
struct grub_env_sorted_var *p, **q;
/* Ignore data slots. */
if (var->type == GRUB_ENV_VAR_DATA)
continue;
sorted_var = grub_malloc (sizeof (*sorted_var));
if (! sorted_var)
goto fail;
@ -352,84 +240,3 @@ grub_register_variable_hook (const char *name,
return GRUB_ERR_NONE;
}
static char *
mangle_data_slot_name (const char *name)
{
char *mangled_name;
mangled_name = grub_malloc (grub_strlen (name) + 2);
if (! mangled_name)
return 0;
grub_sprintf (mangled_name, "\e%s", name);
return mangled_name;
}
grub_err_t
grub_env_set_data_slot (const char *name, const void *ptr)
{
char *mangled_name;
struct grub_env_var *var;
mangled_name = mangle_data_slot_name (name);
if (! mangled_name)
goto fail;
/* If the variable does already exist, just update the variable. */
var = grub_env_find (mangled_name);
if (var)
{
var->value = (char *) ptr;
return GRUB_ERR_NONE;
}
/* The variable does not exist, so create a new one. */
var = grub_zalloc (sizeof (*var));
if (! var)
goto fail;
var->type = GRUB_ENV_VAR_DATA;
var->name = mangled_name;
var->value = (char *) ptr;
grub_env_insert (current_context, var);
return GRUB_ERR_NONE;
fail:
grub_free (mangled_name);
return grub_errno;
}
void *
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;
ptr = grub_env_get (mangled_name);
grub_free (mangled_name);
fail:
return ptr;
}
void
grub_env_unset_data_slot (const char *name)
{
char *mangled_name;
mangled_name = mangle_data_slot_name (name);
if (! mangled_name)
return;
grub_env_unset (mangled_name);
grub_free (mangled_name);
}

View file

@ -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
@ -44,7 +45,7 @@ grub_error (grub_err_t n, const char *fmt, ...)
grub_errno = n;
va_start (ap, fmt);
grub_vsprintf (grub_errmsg, fmt, ap);
grub_vsnprintf (grub_errmsg, sizeof (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 ();
@ -121,7 +122,7 @@ grub_print_error (void)
do
{
if (grub_errno != GRUB_ERR_NONE)
grub_err_printf ("error: %s\n", grub_errmsg);
grub_err_printf (_("error: %s.\n"), grub_errmsg);
}
while (grub_error_pop ());

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

View file

@ -27,40 +27,10 @@
#include <grub/mm.h>
#include <grub/term.h>
static grub_fs_t grub_fs_list;
grub_fs_t grub_fs_list = 0;
grub_fs_autoload_hook_t grub_fs_autoload_hook = 0;
void
grub_fs_register (grub_fs_t fs)
{
fs->next = grub_fs_list;
grub_fs_list = fs;
}
void
grub_fs_unregister (grub_fs_t fs)
{
grub_fs_t *p, q;
for (p = &grub_fs_list, q = *p; q; p = &(q->next), q = q->next)
if (q == fs)
{
*p = q->next;
break;
}
}
void
grub_fs_iterate (int (*hook) (const grub_fs_t fs))
{
grub_fs_t p;
for (p = grub_fs_list; p; p = p->next)
if (hook (p))
break;
}
grub_fs_t
grub_fs_probe (grub_device_t device)
{

View file

@ -1,64 +0,0 @@
/* 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

@ -22,7 +22,6 @@
#include <grub/machine/init.h>
#include <grub/machine/memory.h>
#include <grub/machine/console.h>
#include <grub/machine/kernel.h>
#include <grub/types.h>
#include <grub/err.h>
#include <grub/dl.h>
@ -33,8 +32,10 @@
#include <grub/time.h>
#include <grub/symbol.h>
#include <grub/cpu/io.h>
#include <grub/cpu/kernel.h>
#include <grub/cpu/tsc.h>
#ifdef GRUB_MACHINE_QEMU
#include <grub/machine/kernel.h>
#endif
#define GRUB_FLOPPY_REG_DIGITAL_OUTPUT 0x3f2
@ -67,15 +68,12 @@ grub_exit (void)
grub_cpu_idle ();
}
void
grub_arch_sync_caches (void *address __attribute__ ((unused)),
grub_size_t len __attribute__ ((unused)))
{
}
void
grub_machine_init (void)
{
#ifdef GRUB_MACHINE_QEMU
grub_qemu_init_cirrus ();
#endif
/* Initialize the console as early as possible. */
grub_vga_text_init ();
@ -123,7 +121,9 @@ grub_machine_init (void)
return 0;
}
#if defined (GRUB_MACHINE_MULTIBOOT) || defined (GRUB_MACHINE_QEMU)
grub_machine_mmap_init ();
#endif
grub_machine_mmap_iterate (heap_init);
grub_tsc_init ();
@ -150,6 +150,6 @@ grub_arch_modules_addr (void)
#ifdef GRUB_MACHINE_QEMU
return grub_core_entry_addr + grub_kernel_image_size;
#else
return ALIGN_UP((grub_addr_t) _end, GRUB_MOD_ALIGN);
return ALIGN_UP((grub_addr_t) _end, GRUB_KERNEL_MACHINE_MOD_ALIGN);
#endif
}

View file

@ -57,13 +57,23 @@ signature_found:
(long) table_header->size);
for (; table_item->size;
table_item = (grub_linuxbios_table_item_t) ((long) table_item + (long) table_item->size))
if (hook (table_item))
return 1;
{
if (table_item->tag == GRUB_LINUXBIOS_MEMBER_LINK
&& check_signature ((grub_linuxbios_table_header_t) (grub_addr_t)
*(grub_uint64_t *) (table_item + 1)))
{
table_header = (grub_linuxbios_table_header_t) (grub_addr_t)
*(grub_uint64_t *) (table_item + 1);
goto signature_found;
}
if (hook (table_item))
return 1;
}
return 0;
}
void
grub_err_t
grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t))
{
mem_region_t mem_region;

View file

@ -19,7 +19,7 @@
#include <grub/symbol.h>
#include <grub/machine/memory.h>
#include <grub/cpu/linux.h>
#include <grub/cpu/kernel.h>
#include <grub/offsets.h>
#include <multiboot.h>
#include <multiboot2.h>
@ -42,7 +42,7 @@ _start:
* This is a special data area at a fixed offset from the beginning.
*/
. = _start + GRUB_KERNEL_CPU_PREFIX
. = _start + GRUB_KERNEL_MACHINE_PREFIX
VARIABLE(grub_prefix)
/* to be filled by grub-mkimage */
@ -51,7 +51,7 @@ VARIABLE(grub_prefix)
* Leave some breathing room for the prefix.
*/
. = _start + GRUB_KERNEL_CPU_DATA_END
. = _start + GRUB_KERNEL_MACHINE_DATA_END
/*
* Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself).
@ -66,10 +66,12 @@ multiboot_header:
.long -0x1BADB002 - MULTIBOOT_MEMORY_INFO
codestart:
#ifdef GRUB_MACHINE_MULTIBOOT
cmpl $MULTIBOOT_BOOTLOADER_MAGIC, %eax
jne 0f
movl %ebx, EXT_C(startup_multiboot_info)
0:
#endif
/* initialize the stack */
movl $GRUB_MEMORY_MACHINE_PROT_STACK, %esp

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

View file

@ -45,9 +45,3 @@ grub_machine_set_prefix (void)
{
grub_efi_set_prefix ();
}
void
grub_arch_sync_caches (void *address __attribute__ ((unused)),
grub_size_t len __attribute__ ((unused)))
{
}

View file

@ -1,7 +1,7 @@
/* startup.S - bootstrap GRUB itself */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2006,2007 Free Software Foundation, Inc.
* Copyright (C) 2006,2007,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
@ -62,3 +62,5 @@ codestart:
movl %eax, EXT_C(grub_efi_system_table)
call EXT_C(grub_main)
ret
#include "../realmode.S"

View file

@ -26,9 +26,3 @@ void
grub_stop_floppy (void)
{
}
void
grub_arch_sync_caches (void *address __attribute__ ((unused)),
grub_size_t len __attribute__ ((unused)))
{
}

View file

@ -19,7 +19,6 @@
#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>
@ -43,7 +42,7 @@ _start:
* This is a special data area at a fixed offset from the beginning.
*/
. = _start + GRUB_KERNEL_CPU_PREFIX
. = _start + GRUB_KERNEL_MACHINE_PREFIX
VARIABLE(grub_prefix)
/* to be filled by grub-mkimage */
@ -52,7 +51,7 @@ VARIABLE(grub_prefix)
* Leave some breathing room for the prefix.
*/
. = _start + GRUB_KERNEL_CPU_DATA_END
. = _start + GRUB_KERNEL_MACHINE_DATA_END
codestart:
movl %eax, EXT_C(grub_ieee1275_entry_fn)

View file

@ -59,7 +59,7 @@ VARIABLE(grub_linux_real_addr)
VARIABLE(grub_linux_is_bzimage)
.long 0
FUNCTION(grub_linux16_boot)
FUNCTION(grub_linux16_real_boot)
/* Must be done before zImage copy. */
call EXT_C(grub_dl_unload_all)

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,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
@ -18,6 +18,7 @@
#include <grub/kernel.h>
#include <grub/mm.h>
#include <grub/machine/boot.h>
#include <grub/machine/init.h>
#include <grub/machine/memory.h>
#include <grub/machine/console.h>
@ -46,32 +47,48 @@ static int num_regions;
grub_addr_t grub_os_area_addr;
grub_size_t grub_os_area_size;
void
grub_arch_sync_caches (void *address __attribute__ ((unused)),
grub_size_t len __attribute__ ((unused)))
{
}
static char *
make_install_device (void)
{
/* XXX: This should be enough. */
char dev[100];
char dev[100], *ptr = dev;
if (grub_prefix[0] != '(')
{
/* 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_boot_drive == GRUB_BOOT_MACHINE_PXE_DL)
{
grub_strcpy (dev, "(pxe");
ptr += sizeof ("(pxe") - 1;
}
else
{
grub_snprintf (dev, sizeof (dev),
"(%cd%u", (grub_boot_drive & 0x80) ? 'h' : 'f',
grub_boot_drive & 0x7f);
ptr += grub_strlen (ptr);
if (grub_install_dos_part >= 0)
grub_sprintf (dev + grub_strlen (dev), ",%u", grub_install_dos_part + 1);
if (grub_install_dos_part >= 0)
grub_snprintf (ptr, sizeof (dev) - (ptr - dev),
",%u", grub_install_dos_part + 1);
ptr += grub_strlen (ptr);
if (grub_install_bsd_part >= 0)
grub_sprintf (dev + grub_strlen (dev), ",%c", grub_install_bsd_part + 'a');
if (grub_install_bsd_part >= 0)
grub_snprintf (ptr, sizeof (dev) - (ptr - dev), ",%u",
grub_install_bsd_part + 1);
ptr += grub_strlen (ptr);
}
grub_sprintf (dev + grub_strlen (dev), ")%s", grub_prefix);
grub_snprintf (ptr, sizeof (dev) - (ptr - dev), ")%s", grub_prefix);
grub_strcpy (grub_prefix, dev);
}
else if (grub_prefix[1] == ',' || grub_prefix[1] == ')')
{
/* We have a prefix, but still need to fill in the boot drive. */
grub_snprintf (dev, sizeof (dev),
"(%cd%u%s", (grub_boot_drive & 0x80) ? 'h' : 'f',
grub_boot_drive & 0x7f, grub_prefix + 1);
grub_strcpy (grub_prefix, dev);
}

View file

@ -20,6 +20,7 @@
#include <grub/machine/memory.h>
#include <grub/err.h>
#include <grub/types.h>
#include <grub/misc.h>
grub_err_t
grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t))
@ -28,6 +29,8 @@ grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uin
struct grub_machine_mmap_entry *entry
= (struct grub_machine_mmap_entry *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
grub_memset (entry, 0, sizeof (entry));
/* Check if grub_get_mmap_entry works. */
cont = grub_get_mmap_entry (entry, 0);
@ -43,6 +46,8 @@ grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uin
if (! cont)
break;
grub_memset (entry, 0, sizeof (entry));
cont = grub_get_mmap_entry (entry, cont);
}
while (entry->size);

View file

@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008 Free Software Foundation, Inc.
* 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
@ -53,7 +53,7 @@
#include <multiboot.h>
#include <multiboot2.h>
#define ABS(x) ((x) - _start + GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200)
#define ABS(x) ((x) - LOCAL (base) + GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200)
.file "startup.S"
@ -66,16 +66,15 @@
.globl start, _start
start:
_start:
LOCAL (base):
/*
* Guarantee that "main" is loaded at 0x0:0x8200.
*/
#ifdef APPLE_CC
codestart_abs = ABS(codestart) - 0x10000
ljmp $0, $(codestart_abs)
#ifdef __APPLE__
ljmp $0, $(ABS(LOCAL (codestart)) - 0x10000)
#else
ljmp $0, $ABS(codestart)
ljmp $0, $ABS(LOCAL (codestart))
#endif
/*
* Compatibility version number
*
@ -183,7 +182,7 @@ multiboot_trampoline:
.code16
/* the real mode code continues... */
codestart:
LOCAL (codestart):
cli /* we're not safe here! */
/* set up %ds, %ss, and %es */
@ -1064,7 +1063,7 @@ xsmap:
/*
* void grub_console_real_putchar (int c)
* void grub_console_putchar (const struct grub_unicode_glyph *c)
*
* Put the character C on the console. Because GRUB wants to write a
* character with an attribute, this implementation is a bit tricky.
@ -1077,8 +1076,9 @@ xsmap:
* get the height of the screen, and the TELETYPE OUTPUT BIOS call doesn't
* support setting a background attribute.
*/
FUNCTION(grub_console_real_putchar)
movl %eax, %edx
FUNCTION(grub_console_putchar)
/* Retrieve the base character. */
movl 0(%edx), %edx
pusha
movb EXT_C(grub_console_cur_color), %bl
@ -1156,7 +1156,7 @@ FUNCTION(grub_console_real_putchar)
*/
/* this table is used in translate_keycode below */
translation_table:
LOCAL (translation_table):
.word GRUB_CONSOLE_KEY_LEFT, GRUB_TERM_LEFT
.word GRUB_CONSOLE_KEY_RIGHT, GRUB_TERM_RIGHT
.word GRUB_CONSOLE_KEY_UP, GRUB_TERM_UP
@ -1178,11 +1178,10 @@ translate_keycode:
pushw %bx
pushw %si
#ifdef APPLE_CC
translation_table_abs = ABS (translation_table) - 0x10000
movw $(translation_table_abs), %si
#ifdef __APPLE__
movw $(ABS(LOCAL (translation_table)) - 0x10000), %si
#else
movw $ABS(translation_table), %si
movw $ABS(LOCAL (translation_table)), %si
#endif
1: lodsw
@ -1330,8 +1329,8 @@ FUNCTION(grub_console_gotoxy)
pushl %ebp
pushl %ebx /* save EBX */
movb %dl, %dh /* %dh = y */
movb %al, %dl /* %dl = x */
movb %cl, %dh /* %dh = y */
/* %dl = x */
call prot_to_real
.code16
@ -1407,7 +1406,7 @@ FUNCTION(grub_console_setcursor)
pushl %ebx
/* push ON */
pushl %eax
pushl %edx
/* check if the standard cursor shape has already been saved */
movw console_cursor_shape, %ax
@ -1446,47 +1445,6 @@ FUNCTION(grub_console_setcursor)
popl %ebp
ret
/*
* grub_getrtsecs()
* if a seconds value can be read, read it and return it (BCD),
* otherwise return 0xFF
* BIOS call "INT 1AH Function 02H" to check whether a character is pending
* Call with %ah = 0x2
* Return:
* If RT Clock can give correct values
* %ch = hour (BCD)
* %cl = minutes (BCD)
* %dh = seconds (BCD)
* %dl = daylight savings time (00h std, 01h daylight)
* Carry flag = clear
* else
* Carry flag = set
* (this indicates that the clock is updating, or
* that it isn't running)
*/
FUNCTION(grub_getrtsecs)
pushl %ebp
call prot_to_real /* enter real mode */
.code16
clc
movb $0x2, %ah
int $0x1a
DATA32 jnc gottime
movb $0xff, %dh
gottime:
DATA32 call real_to_prot
.code32
movb %dh, %al
popl %ebp
ret
/*
* grub_get_rtc()
* return the real time in ticks, of which there are about
@ -1541,33 +1499,6 @@ FUNCTION(grub_vga_set_mode)
popl %ebp
ret
/*
* unsigned char *grub_vga_get_font (void)
*/
FUNCTION(grub_vga_get_font)
pushl %ebp
pushl %ebx
call prot_to_real
.code16
movw $0x1130, %ax
movb $0x06, %bh
int $0x10
movw %es, %bx
movw %bp, %dx
DATA32 call real_to_prot
.code32
movzwl %bx, %ecx
shll $4, %ecx
movw %dx, %ax
addl %ecx, %eax
popl %ebx
popl %ebp
ret
/*
* grub_vbe_bios_status_t grub_vbe_get_controller_info (struct grub_vbe_info_block *controller_info)
*

152
kern/i386/qemu/init.c Normal file
View file

@ -0,0 +1,152 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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/pci.h>
#include <grub/machine/kernel.h>
#include <grub/misc.h>
#include <grub/vga.h>
static struct {grub_uint8_t r, g, b, a; } colors[] =
{
// {R, G, B, A}
{0x00, 0x00, 0x00, 0xFF}, // 0 = black
{0x00, 0x00, 0xA8, 0xFF}, // 1 = blue
{0x00, 0xA8, 0x00, 0xFF}, // 2 = green
{0x00, 0xA8, 0xA8, 0xFF}, // 3 = cyan
{0xA8, 0x00, 0x00, 0xFF}, // 4 = red
{0xA8, 0x00, 0xA8, 0xFF}, // 5 = magenta
{0xA8, 0x54, 0x00, 0xFF}, // 6 = brown
{0xA8, 0xA8, 0xA8, 0xFF}, // 7 = light gray
{0x54, 0x54, 0x54, 0xFF}, // 8 = dark gray
{0x54, 0x54, 0xFE, 0xFF}, // 9 = bright blue
{0x54, 0xFE, 0x54, 0xFF}, // 10 = bright green
{0x54, 0xFE, 0xFE, 0xFF}, // 11 = bright cyan
{0xFE, 0x54, 0x54, 0xFF}, // 12 = bright red
{0xFE, 0x54, 0xFE, 0xFF}, // 13 = bright magenta
{0xFE, 0xFE, 0x54, 0xFF}, // 14 = yellow
{0xFE, 0xFE, 0xFE, 0xFF} // 15 = white
};
#include <ascii.h>
static void
load_font (void)
{
unsigned i;
grub_vga_gr_write (0 << 2, GRUB_VGA_GR_GR6);
grub_vga_sr_write (GRUB_VGA_SR_MEMORY_MODE_NORMAL, GRUB_VGA_SR_MEMORY_MODE);
grub_vga_sr_write (1 << GRUB_VGA_TEXT_FONT_PLANE,
GRUB_VGA_SR_MAP_MASK_REGISTER);
grub_vga_gr_write (0, GRUB_VGA_GR_DATA_ROTATE);
grub_vga_gr_write (0, GRUB_VGA_GR_MODE);
grub_vga_gr_write (0xff, GRUB_VGA_GR_BITMASK);
for (i = 0; i < 128; i++)
grub_memcpy ((void *) (0xa0000 + 32 * i), ascii_bitmaps + 16 * i, 16);
}
static void
load_palette (void)
{
unsigned i;
for (i = 0; i < 16; i++)
{
grub_outb (i, GRUB_VGA_IO_ARX);
grub_outb (i, GRUB_VGA_IO_ARX);
}
for (i = 0; i < ARRAY_SIZE (colors); i++)
grub_vga_palette_write (i, colors[i].r, colors[i].g, colors[i].b);
}
void
grub_qemu_init_cirrus (void)
{
auto int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev, grub_pci_id_t pciid);
int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev, grub_pci_id_t pciid __attribute__ ((unused)))
{
grub_pci_address_t addr;
grub_uint32_t class;
addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS);
class = grub_pci_read (addr);
if (((class >> 16) & 0xffff) != 0x0300)
return 0;
/* FIXME: chooose addresses dynamically. */
addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0);
grub_pci_write (addr, 0xf0000000 | GRUB_PCI_ADDR_MEM_PREFETCH
| GRUB_PCI_ADDR_SPACE_MEMORY | GRUB_PCI_ADDR_MEM_TYPE_32);
addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG1);
grub_pci_write (addr, 0xf2000000
| GRUB_PCI_ADDR_SPACE_MEMORY | GRUB_PCI_ADDR_MEM_TYPE_32);
addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND);
grub_pci_write (addr, GRUB_PCI_COMMAND_MEM_ENABLED
| GRUB_PCI_COMMAND_IO_ENABLED);
return 1;
}
grub_pci_iterate (find_card);
grub_outb (1, 0x3c2);
load_font ();
grub_vga_gr_write (GRUB_VGA_GR_GR6_MMAP_CGA, GRUB_VGA_GR_GR6);
grub_vga_gr_write (GRUB_VGA_GR_MODE_ODD_EVEN, GRUB_VGA_GR_MODE);
grub_vga_sr_write (GRUB_VGA_SR_MEMORY_MODE_NORMAL, GRUB_VGA_SR_MEMORY_MODE);
grub_vga_sr_write ((1 << GRUB_VGA_TEXT_TEXT_PLANE)
| (1 << GRUB_VGA_TEXT_ATTR_PLANE),
GRUB_VGA_SR_MAP_MASK_REGISTER);
grub_vga_cr_write (15, GRUB_VGA_CR_CELL_HEIGHT);
grub_vga_cr_write (79, GRUB_VGA_CR_WIDTH);
grub_vga_cr_write (40, GRUB_VGA_CR_PITCH);
int vert = 25 * 16;
grub_vga_cr_write (vert & 0xff, GRUB_VGA_CR_HEIGHT);
grub_vga_cr_write (((vert >> GRUB_VGA_CR_OVERFLOW_HEIGHT1_SHIFT)
& GRUB_VGA_CR_OVERFLOW_HEIGHT1_MASK)
| ((vert >> GRUB_VGA_CR_OVERFLOW_HEIGHT2_SHIFT)
& GRUB_VGA_CR_OVERFLOW_HEIGHT2_MASK),
GRUB_VGA_CR_OVERFLOW);
load_palette ();
grub_outb (0x10, 0x3c0);
grub_outb (0, 0x3c1);
grub_outb (0x14, 0x3c0);
grub_outb (0, 0x3c1);
grub_vga_sr_write (GRUB_VGA_SR_CLOCKING_MODE_8_DOT_CLOCK,
GRUB_VGA_SR_CLOCKING_MODE);
grub_vga_cr_write (14, GRUB_VGA_CR_CURSOR_START);
grub_vga_cr_write (15, GRUB_VGA_CR_CURSOR_END);
grub_outb (0x20, 0x3c0);
}

View file

@ -22,26 +22,42 @@
#include <grub/types.h>
#include <grub/err.h>
#include <grub/misc.h>
#include <grub/i386/cmos.h>
#include <grub/cmos.h>
#define QEMU_CMOS_MEMSIZE_HIGH 0x35
#define QEMU_CMOS_MEMSIZE_LOW 0x34
#define QEMU_CMOS_MEMSIZE2_HIGH 0x31
#define QEMU_CMOS_MEMSIZE2_LOW 0x30
#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;
static grub_uint64_t mem_size, above_4g;
void
grub_machine_mmap_init ()
{
mem_size = grub_cmos_read (QEMU_CMOS_MEMSIZE_HIGH) << 24 | grub_cmos_read (QEMU_CMOS_MEMSIZE_LOW) << 16;
mem_size = ((grub_uint64_t) grub_cmos_read (QEMU_CMOS_MEMSIZE_HIGH)) << 24
| ((grub_uint64_t) grub_cmos_read (QEMU_CMOS_MEMSIZE_LOW)) << 16;
if (mem_size > 0)
{
/* Don't ask... */
mem_size += (16 * 1024 * 1024);
}
else
{
mem_size
= ((((grub_uint64_t) grub_cmos_read (QEMU_CMOS_MEMSIZE2_HIGH)) << 18)
| ((grub_uint64_t) (grub_cmos_read (QEMU_CMOS_MEMSIZE2_LOW)) << 10))
+ 1024 * 1024;
}
/* Don't ask... */
mem_size += (16 * 1024 * 1024);
above_4g = (((grub_uint64_t) grub_cmos_read (0x5b)) << 16)
| (((grub_uint64_t) grub_cmos_read (0x5c)) << 24)
| (((grub_uint64_t) grub_cmos_read (0x5d)) << 32);
}
grub_err_t
@ -57,6 +73,12 @@ grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uin
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;
/* 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,
@ -64,10 +86,8 @@ grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uin
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))
if (above_4g != 0 && hook (0x100000000ULL, above_4g,
GRUB_MACHINE_MEMORY_AVAILABLE))
return 1;
return 0;

View file

@ -27,7 +27,7 @@
_start:
jmp codestart
. = _start + GRUB_KERNEL_MACHINE_CORE_ENTRY_ADDR
. = _start + GRUB_KERNEL_I386_QEMU_CORE_ENTRY_ADDR
VARIABLE(grub_core_entry_addr)
.long 0
VARIABLE(grub_kernel_image_size)

View file

@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2009 Free Software Foundation, Inc.
* Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,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
@ -16,6 +16,7 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/i386/pc/memory.h>
/*
* Note: These functions defined in this file may be called from C.

View file

@ -20,7 +20,6 @@
#include <grub/kernel.h>
#include <grub/misc.h>
#include <grub/types.h>
#include <grub/machine/kernel.h>
#include <grub/ieee1275/ieee1275.h>
int (*grub_ieee1275_entry_fn) (void *);
@ -59,6 +58,7 @@ grub_ieee1275_find_options (void)
char tmp[32];
int is_smartfirmware = 0;
int is_olpc = 0;
int is_qemu = 0;
grub_ieee1275_finddevice ("/", &root);
grub_ieee1275_finddevice ("/options", &options);
@ -79,6 +79,11 @@ grub_ieee1275_find_options (void)
if (rc >= 0 && !grub_strcmp (tmp, "OLPC"))
is_olpc = 1;
rc = grub_ieee1275_get_property (root, "model",
tmp, sizeof (tmp), 0);
if (rc >= 0 && !grub_strcmp (tmp, "Emulated PC"))
is_qemu = 1;
if (is_smartfirmware)
{
/* Broken in all versions */
@ -135,6 +140,10 @@ grub_ieee1275_find_options (void)
grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_OFDISK_SDCARD_ONLY);
}
if (is_qemu)
/* OpenFirmware hangs on qemu if one requests any memory below 1.5 MiB. */
grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_PRE1_5M_CLAIM);
if (! grub_ieee1275_finddevice ("/rom/boot-rom", &bootrom))
{
rc = grub_ieee1275_get_property (bootrom, "model", tmp, sizeof (tmp), 0);

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
@ -284,8 +284,8 @@ grub_ieee1275_read (grub_ieee1275_ihandle_t ihandle, void *buffer,
}
int
grub_ieee1275_seek (grub_ieee1275_ihandle_t ihandle, int pos_hi,
int pos_lo, grub_ssize_t *result)
grub_ieee1275_seek (grub_ieee1275_ihandle_t ihandle, grub_disk_addr_t pos,
grub_ssize_t *result)
{
struct write_args
{
@ -299,8 +299,15 @@ grub_ieee1275_seek (grub_ieee1275_ihandle_t ihandle, int pos_hi,
INIT_IEEE1275_COMMON (&args.common, "seek", 3, 1);
args.ihandle = ihandle;
args.pos_hi = (grub_ieee1275_cell_t) pos_hi;
args.pos_lo = (grub_ieee1275_cell_t) pos_lo;
/* To prevent stupid gcc warning. */
#if GRUB_IEEE1275_CELL_SIZEOF >= 8
args.pos_hi = 0;
args.pos_lo = pos;
#else
args.pos_hi = (grub_ieee1275_cell_t) (pos >> (8 * GRUB_IEEE1275_CELL_SIZEOF));
args.pos_lo = (grub_ieee1275_cell_t)
(pos & ((1ULL << (8 * GRUB_IEEE1275_CELL_SIZEOF)) - 1));
#endif
if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
return -1;

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
@ -28,21 +28,20 @@
#include <grub/env.h>
#include <grub/misc.h>
#include <grub/time.h>
#include <grub/machine/console.h>
#include <grub/machine/kernel.h>
#include <grub/cpu/kernel.h>
#include <grub/ieee1275/console.h>
#include <grub/ieee1275/ofdisk.h>
#include <grub/ieee1275/ieee1275.h>
#include <grub/offsets.h>
/* The minimal heap size we can live with. */
#define HEAP_MIN_SIZE (unsigned long) (2 * 1024 * 1024)
/* The maximum heap size we're going to claim */
#define HEAP_MAX_SIZE (unsigned long) (4 * 1024 * 1024)
#define HEAP_MAX_SIZE (unsigned long) (32 * 1024 * 1024)
/* If possible, we will avoid claiming heap above this address, because it
seems to cause relocation problems with OSes that link at 4 MiB */
#define HEAP_MAX_ADDR (unsigned long) (4 * 1024 * 1024)
#define HEAP_MAX_ADDR (unsigned long) (32 * 1024 * 1024)
extern char _start[];
extern char _end[];
@ -75,10 +74,6 @@ grub_machine_set_prefix (void)
char *filename;
char *prefix;
if (grub_env_get ("prefix"))
/* We already set prefix in grub_machine_init(). */
return;
if (grub_prefix[0])
{
grub_env_set ("prefix", grub_prefix);
@ -111,11 +106,12 @@ grub_machine_set_prefix (void)
*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;
newprefix = grub_xasprintf ("%s%s", prefix, filename);
if (newprefix)
{
grub_free (prefix);
prefix = newprefix;
}
}
}
@ -136,6 +132,17 @@ static void grub_claim_heap (void)
if (type != 1)
return 0;
if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_PRE1_5M_CLAIM))
{
if (addr + len <= 0x180000)
return 0;
if (addr < 0x180000)
{
len = addr + len - 0x180000;
addr = 0x180000;
}
}
len -= 1; /* Required for some firmware. */
/* Never exceed HEAP_MAX_SIZE */
@ -217,11 +224,12 @@ grub_machine_init (void)
grub_ieee1275_init ();
grub_console_init ();
grub_console_init_early ();
#ifdef __i386__
grub_get_extended_memory ();
#endif
grub_claim_heap ();
grub_console_init_lately ();
grub_ofdisk_init ();
/* Process commandline. */
@ -287,5 +295,5 @@ grub_get_rtc (void)
grub_addr_t
grub_arch_modules_addr (void)
{
return ALIGN_UP((grub_addr_t) _end + GRUB_MOD_GAP, GRUB_MOD_ALIGN);
return ALIGN_UP((grub_addr_t) _end + GRUB_KERNEL_MACHINE_MOD_GAP, GRUB_KERNEL_MACHINE_MOD_ALIGN);
}

View file

@ -21,7 +21,6 @@
#include <grub/err.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/machine/kernel.h>
#include <grub/ieee1275/ieee1275.h>
enum grub_ieee1275_parse_type
@ -38,7 +37,7 @@ grub_children_iterate (char *devpath,
grub_ieee1275_phandle_t dev;
grub_ieee1275_phandle_t child;
char *childtype, *childpath;
char *childname, *fullname;
char *childname;
int ret = 0;
if (grub_ieee1275_finddevice (devpath, &dev))
@ -63,14 +62,6 @@ grub_children_iterate (char *devpath,
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
{
@ -79,28 +70,31 @@ grub_children_iterate (char *devpath,
if (grub_ieee1275_get_property (child, "device_type", childtype,
IEEE1275_MAX_PROP_LEN, &actual))
childtype[0] = 0;
if (dev == child)
continue;
if (grub_ieee1275_package_to_path (child, childpath,
IEEE1275_MAX_PATH_LEN, &actual))
continue;
if (grub_strcmp (devpath, childpath) == 0)
continue;
if (grub_ieee1275_get_property (child, "name", childname,
IEEE1275_MAX_PROP_LEN, &actual))
continue;
grub_sprintf (fullname, "%s/%s", devpath, childname);
alias.type = childtype;
alias.path = childpath;
alias.name = fullname;
alias.name = childname;
ret = hook (&alias);
if (ret)
break;
}
while (grub_ieee1275_peer (child, &child));
while (grub_ieee1275_peer (child, &child) != -1);
grub_free (fullname);
grub_free (childname);
grub_free (childpath);
grub_free (childtype);
@ -108,6 +102,20 @@ grub_children_iterate (char *devpath,
return ret;
}
int
grub_ieee1275_devices_iterate (int (*hook) (struct grub_ieee1275_devalias *alias))
{
auto int it_through (struct grub_ieee1275_devalias *alias);
int it_through (struct grub_ieee1275_devalias *alias)
{
if (hook (alias))
return 1;
return grub_children_iterate (alias->path, it_through);
}
return grub_children_iterate ("/", it_through);
}
/* Iterate through all device aliases. This function can be used to
find a device of a specific type. */
int
@ -135,7 +143,7 @@ grub_devalias_iterate (int (*hook) (struct grub_ieee1275_devalias *alias))
/* Find the first property. */
aliasname[0] = '\0';
while (grub_ieee1275_next_property (aliases, aliasname, aliasname))
while (grub_ieee1275_next_property (aliases, aliasname, aliasname) > 0)
{
grub_ieee1275_phandle_t dev;
grub_ssize_t pathlen;
@ -199,9 +207,9 @@ nextprop:
}
/* 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)
int
grub_ieee1275_map (grub_addr_t phys, grub_addr_t virt, grub_size_t size,
grub_uint32_t mode)
{
struct map_args {
struct grub_ieee1275_common_hdr common;
@ -210,17 +218,30 @@ grub_map (grub_addr_t phys, grub_addr_t virt, grub_uint32_t size,
grub_ieee1275_cell_t mode;
grub_ieee1275_cell_t size;
grub_ieee1275_cell_t virt;
grub_ieee1275_cell_t phys;
#ifdef GRUB_MACHINE_SPARC64
grub_ieee1275_cell_t phys_high;
#endif
grub_ieee1275_cell_t phys_low;
grub_ieee1275_cell_t catch_result;
} args;
INIT_IEEE1275_COMMON (&args.common, "call-method", 6, 1);
INIT_IEEE1275_COMMON (&args.common, "call-method",
#ifdef GRUB_MACHINE_SPARC64
7,
#else
6,
#endif
1);
args.method = (grub_ieee1275_cell_t) "map";
args.ihandle = grub_ieee1275_mmu;
args.phys = phys;
#ifdef GRUB_MACHINE_SPARC64
args.phys_high = 0;
#endif
args.phys_low = phys;
args.virt = virt;
args.size = size;
args.mode = mode; /* Format is WIMG0PP. */
args.catch_result = (grub_ieee1275_cell_t) -1;
if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
return -1;
@ -235,7 +256,7 @@ grub_claimmap (grub_addr_t addr, grub_size_t size)
return -1;
if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_REAL_MODE)
&& grub_map (addr, addr, size, 0x00))
&& grub_ieee1275_map (addr, addr, size, 0x00))
{
grub_printf ("map failed: address 0x%llx, size 0x%llx\n",
(long long) addr, (long long) size);
@ -330,12 +351,11 @@ grub_ieee1275_parse_args (const char *path, enum grub_ieee1275_parse_type ptype)
{
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);
ret = grub_xasprintf ("\\%s", filepath);
else
grub_strcpy (ret, filepath);
ret = grub_strdup (filepath);
}
}
else if (ptype == GRUB_PARSE_PARTITION)
@ -375,7 +395,7 @@ grub_ieee1275_encode_devname (const char *path)
char *partition = grub_ieee1275_parse_args (path, GRUB_PARSE_PARTITION);
char *encoding;
if (partition)
if (partition && partition[0])
{
unsigned int partno = grub_strtoul (partition, 0, 0);
@ -383,15 +403,10 @@ grub_ieee1275_encode_devname (const char *path)
/* GRUB partition 1 is OF partition 0. */
partno++;
/* 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);
encoding = grub_xasprintf ("(%s,%d)", device, partno);
}
else
{
encoding = grub_malloc (grub_strlen (device) + 2);
grub_sprintf (encoding, "(%s)", device);
}
encoding = grub_xasprintf ("(%s)", device);
grub_free (partition);
grub_free (device);
@ -405,14 +420,17 @@ void
grub_reboot (void)
{
grub_ieee1275_interpret ("reset-all", 0);
for (;;) ;
}
#endif
void
grub_halt (void)
{
/* Not standardized. We try both known commands. */
/* Not standardized. We try three known commands. */
grub_ieee1275_interpret ("shut-down", 0);
grub_ieee1275_interpret ("power-off", 0);
grub_ieee1275_interpret ("poweroff", 0);
for (;;) ;
}

View file

@ -28,18 +28,6 @@ grub_list_push (grub_list_t *head, grub_list_t item)
*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)
{
@ -53,51 +41,16 @@ grub_list_remove (grub_list_t *head, grub_list_t item)
}
}
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;
grub_named_list_t item;
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;
}
FOR_LIST_ELEMENTS (item, head)
if (grub_strcmp (item->name, name) == 0)
return item;
return 0;
}
grub_list_iterate (GRUB_AS_LIST (head), (grub_list_hook_t) list_find);
return result;
return NULL;
}
void
@ -105,27 +58,30 @@ 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)
grub_prio_list_t *p, q;
for (p = head, q = *p; q; p = &(q->next), q = q->next)
{
int r;
r = grub_strcmp (new_item->name, item->name);
if (r)
return (r < 0);
r = grub_strcmp (nitem->name, q->name);
if (r < 0)
break;
if (r > 0)
continue;
if (new_item->prio >= (item->prio & GRUB_PRIO_LIST_PRIO_MASK))
if (nitem->prio >= (q->prio & GRUB_PRIO_LIST_PRIO_MASK))
{
item->prio &= ~GRUB_PRIO_LIST_FLAG_ACTIVE;
return 1;
q->prio &= ~GRUB_PRIO_LIST_FLAG_ACTIVE;
break;
}
inactive = 1;
return 0;
}
grub_list_insert (GRUB_AS_LIST_P (head), GRUB_AS_LIST (nitem),
(grub_list_test_t) test);
*p = nitem;
nitem->next = q;
if (! inactive)
nitem->prio |= GRUB_PRIO_LIST_FLAG_ACTIVE;
}

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
@ -53,6 +53,25 @@ grub_module_iterate (int (*hook) (struct grub_module_header *header))
}
}
/* This is actualy platform-independant but used only on yeeloong and sparc. */
#if defined (GRUB_MACHINE_MIPS_YEELOONG) || defined (GRUB_MACHINE_SPARC64)
grub_addr_t
grub_modules_get_end (void)
{
struct grub_module_info *modinfo;
grub_addr_t modbase;
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 modbase;
return modbase + modinfo->size;
}
#endif
/* Load all modules in core. */
static void
grub_load_modules (void)
@ -68,6 +87,9 @@ grub_load_modules (void)
(header->size - sizeof (struct grub_module_header))))
grub_fatal ("%s", grub_errmsg);
if (grub_errno)
grub_print_error ();
return 0;
}
@ -80,7 +102,7 @@ grub_load_config (void)
auto int hook (struct grub_module_header *);
int hook (struct grub_module_header *header)
{
/* Not an ELF module, skip. */
/* Not an embedded config, skip. */
if (header->type != OBJ_TYPE_CONFIG)
return 0;
@ -114,7 +136,6 @@ grub_set_root_dev (void)
const char *prefix;
grub_register_variable_hook ("root", 0, grub_env_write_root);
grub_env_export ("root");
prefix = grub_env_get ("prefix");
@ -159,19 +180,19 @@ grub_main (void)
/* Load pre-loaded modules and free the space. */
grub_register_exported_symbols ();
#ifdef GRUB_LINKER_HAVE_INIT
grub_arch_dl_init_linker ();
#endif
grub_load_modules ();
/* 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 ();
grub_register_core_commands ();
grub_register_rescue_parser ();
grub_register_rescue_reader ();
grub_load_config ();
grub_load_normal_mode ();
grub_reader_loop (0);
grub_rescue_run ();
}

7
kern/mips/cache.S Normal file
View file

@ -0,0 +1,7 @@
#include <grub/symbol.h>
FUNCTION (grub_cpu_flush_cache)
FUNCTION (grub_arch_sync_caches)
#include "cache_flush.S"
j $ra

23
kern/mips/cache_flush.S Normal file
View file

@ -0,0 +1,23 @@
move $t2, $a0
addu $t3, $a0, $a1
srl $t2, $t2, 5
sll $t2, $t2, 5
addu $t3, $t3, 0x1f
srl $t3, $t3, 5
sll $t3, $t3, 5
move $t0, $t2
subu $t1, $t3, $t2
1:
cache 1, 0($t0)
addiu $t0, $t0, 0x1
addiu $t1, $t1, 0xffff
bne $t1, $zero, 1b
sync
move $t0, $t2
subu $t1, $t3, $t2
2:
cache 0, 0($t0)
addiu $t0, $t0, 0x1
addiu $t1, $t1, 0xffff
bne $t1, $zero, 2b
sync

237
kern/mips/dl.c Normal file
View file

@ -0,0 +1,237 @@
/* dl-386.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>
#include <grub/cpu/types.h>
#include <grub/mm.h>
/* Dummy __gnu_local_gp. Resolved by linker. */
static char __gnu_local_gp_dummy;
/* Check if EHDR is a valid ELF header. */
grub_err_t
grub_arch_dl_check_header (void *ehdr)
{
Elf_Ehdr *e = ehdr;
/* Check the magic numbers. */
#ifdef WORDS_BIGENDIAN
if (e->e_ident[EI_CLASS] != ELFCLASS32
|| e->e_ident[EI_DATA] != ELFDATA2MSB
|| e->e_machine != EM_MIPS)
#else
if (e->e_ident[EI_CLASS] != ELFCLASS32
|| e->e_ident[EI_DATA] != ELFDATA2LSB
|| e->e_machine != EM_MIPS)
#endif
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)
{
Elf_Ehdr *e = ehdr;
Elf_Shdr *s;
Elf_Word entsize;
unsigned i;
grub_size_t gp_size = 0;
/* FIXME: suboptimal. */
grub_uint32_t *gp, *gpptr;
grub_uint32_t gp0;
/* Find a symbol table. */
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
i < e->e_shnum;
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");
entsize = s->sh_entsize;
/* Find reginfo. */
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
if (s->sh_type == SHT_MIPS_REGINFO)
break;
if (i == e->e_shnum)
return grub_error (GRUB_ERR_BAD_MODULE, "no reginfo found");
gp0 = ((grub_uint32_t *)((char *) e + s->sh_offset))[5];
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
if (s->sh_type == SHT_REL)
{
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)
{
Elf_Rel *rel, *max;
for (rel = (Elf_Rel *) ((char *) e + s->sh_offset),
max = rel + s->sh_size / s->sh_entsize;
rel < max;
rel++)
switch (ELF_R_TYPE (rel->r_info))
{
case R_MIPS_GOT16:
case R_MIPS_CALL16:
case R_MIPS_GPREL32:
gp_size += 4;
break;
}
}
}
if (gp_size > 0x08000)
return grub_error (GRUB_ERR_OUT_OF_RANGE, "__gnu_local_gp is too big\n");
gpptr = gp = grub_malloc (gp_size);
if (!gp)
return grub_errno;
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
if (s->sh_type == SHT_REL)
{
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)
{
Elf_Rel *rel, *max;
for (rel = (Elf_Rel *) ((char *) e + s->sh_offset),
max = rel + s->sh_size / s->sh_entsize;
rel < max;
rel++)
{
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 = (Elf_Word *) ((char *) seg->addr + rel->r_offset);
sym = (Elf_Sym *) ((char *) mod->symtab
+ entsize * ELF_R_SYM (rel->r_info));
if (sym->st_value == (grub_addr_t) &__gnu_local_gp_dummy)
sym->st_value = (grub_addr_t) gp;
switch (ELF_R_TYPE (rel->r_info))
{
case R_MIPS_HI16:
{
grub_uint32_t value;
Elf_Rel *rel2;
/* Handle partner lo16 relocation. Lower part is
treated as signed. Hence add 0x8000 to compensate.
*/
value = (*(grub_uint16_t *) addr << 16)
+ sym->st_value + 0x8000;
for (rel2 = rel + 1; rel2 < max; rel2++)
if (ELF_R_SYM (rel2->r_info)
== ELF_R_SYM (rel->r_info)
&& ELF_R_TYPE (rel2->r_info) == R_MIPS_LO16)
{
value += *(grub_int16_t *)
((char *) seg->addr + rel2->r_offset);
break;
}
*(grub_uint16_t *) addr = (value >> 16) & 0xffff;
}
break;
case R_MIPS_LO16:
*(grub_uint16_t *) addr += (sym->st_value) & 0xffff;
break;
case R_MIPS_32:
*(grub_uint32_t *) addr += sym->st_value;
break;
case R_MIPS_GPREL32:
*(grub_uint32_t *) addr = sym->st_value
+ *(grub_uint32_t *) addr + gp0 - (grub_uint32_t)gp;
break;
case R_MIPS_26:
{
grub_uint32_t value;
grub_uint32_t raw;
raw = (*(grub_uint32_t *) addr) & 0x3ffffff;
value = raw << 2;
value += sym->st_value;
raw = (value >> 2) & 0x3ffffff;
*(grub_uint32_t *) addr =
raw | ((*(grub_uint32_t *) addr) & 0xfc000000);
}
break;
case R_MIPS_GOT16:
case R_MIPS_CALL16:
/* FIXME: reuse*/
*gpptr = sym->st_value + *(grub_uint16_t *) addr;
*(grub_uint16_t *) addr
= sizeof (grub_uint32_t) * (gpptr - gp);
gpptr++;
break;
default:
{
grub_free (gp);
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"Unknown relocation type %d\n",
ELF_R_TYPE (rel->r_info));
}
break;
}
}
}
}
return GRUB_ERR_NONE;
}
void
grub_arch_dl_init_linker (void)
{
grub_dl_register_symbol ("__gnu_local_gp", &__gnu_local_gp_dummy, 0);
}

View file

@ -1,4 +1,3 @@
/* reader.c - reader support */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
@ -17,33 +16,19 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/types.h>
#include <grub/mm.h>
#include <grub/reader.h>
#include <grub/parser.h>
#include <grub/kernel.h>
#include <grub/env.h>
struct grub_handler_class grub_reader_class =
{
.name = "reader"
};
grub_err_t
grub_reader_loop (grub_reader_getline_t getline)
void
grub_machine_set_prefix (void)
{
while (1)
{
char *line;
grub_reader_getline_t func;
/* Print an error, if any. */
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
func = (getline) ? : grub_reader_get_current ()->read_line;
if ((func (&line, 0)) || (! line))
return grub_errno;
grub_parser_get_current ()->parse_line (line, func);
grub_free (line);
}
grub_env_set ("prefix", grub_prefix);
}
extern char _end[];
grub_addr_t
grub_arch_modules_addr (void)
{
return (grub_addr_t) _end;
}

View file

@ -0,0 +1,61 @@
#include <grub/kernel.h>
#include <grub/misc.h>
#include <grub/env.h>
#include <grub/time.h>
#include <grub/types.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/time.h>
#include <grub/machine/kernel.h>
#include <grub/machine/memory.h>
#include <grub/cpu/kernel.h>
#define RAMSIZE (*(grub_uint32_t *) ((16 << 20) - 264))
grub_uint32_t
grub_get_rtc (void)
{
static int calln = 0;
return calln++;
}
void
grub_machine_init (void)
{
grub_mm_init_region ((void *) GRUB_MACHINE_MEMORY_USABLE,
RAMSIZE - (GRUB_MACHINE_MEMORY_USABLE & 0x7fffffff));
grub_install_get_time_ms (grub_rtc_get_time_ms);
}
void
grub_machine_fini (void)
{
}
void
grub_exit (void)
{
while (1);
}
void
grub_halt (void)
{
while (1);
}
void
grub_reboot (void)
{
while (1);
}
grub_err_t
grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t,
grub_uint64_t,
grub_uint32_t))
{
hook (0, RAMSIZE,
GRUB_MACHINE_MEMORY_AVAILABLE);
return GRUB_ERR_NONE;
}

226
kern/mips/startup.S Normal file
View file

@ -0,0 +1,226 @@
/* startup.S - Startup code for the MIPS. */
/*
* 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/offsets.h>
#include <grub/machine/memory.h>
#include <grub/offsets.h>
#define BASE_ADDR 8
.extern __bss_start
.extern _end
.globl __start, _start, start
__start:
_start:
start:
bal codestart
base:
. = _start + GRUB_KERNEL_MACHINE_COMPRESSED_SIZE
compressed_size:
.long 0
. = _start + GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE
total_module_size:
.long 0
. = _start + GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE
kernel_image_size:
.long 0
codestart:
/* Save our base. */
move $s0, $ra
/* Parse arguments. Has to be done before relocation.
So need to do it in asm. */
#ifdef GRUB_MACHINE_MIPS_YEELOONG
move $s2, $zero
move $s3, $zero
move $s4, $zero
move $s5, $zero
/* $a2 has the environment. */
addiu $t0, $a2, 1
beq $t0, $zero, argdone
move $t0, $a2
argcont:
lw $t1, 0($t0)
beq $t1, $zero, argdone
#define DO_PARSE(str, reg) \
addiu $t2, $s0, (str-base);\
bal parsestr;\
beq $v0, $zero, 1f;\
move reg, $v0;\
b 2f;\
1:
DO_PARSE (busclockstr, $s2)
DO_PARSE (cpuclockstr, $s3)
DO_PARSE (memsizestr, $s4)
DO_PARSE (highmemsizestr, $s5)
2:
addiu $t0, $t0, 4
b argcont
parsestr:
move $v0, $zero
move $t3, $t1
3:
lb $t4, 0($t2)
lb $t5, 0($t3)
addiu $t2, $t2, 1
addiu $t3, $t3, 1
beq $t5, $zero, 1f
beq $t5, $t4, 3b
bne $t4, $zero, 1f
addiu $t3, $t3, 0xffff
digcont:
lb $t5, 0($t3)
/* Substract '0' from digit. */
addiu $t5, $t5, 0xffd0
bltz $t5, 1f
addiu $t4, $t5, 0xfff7
bgtz $t4, 1f
/* Multiply $v0 by 10 with bitshifts. */
sll $v0, $v0, 1
sll $t4, $v0, 2
addu $v0, $v0, $t4
addu $v0, $v0, $t5
addiu $t3, $t3, 1
b digcont
1:
jr $ra
busclockstr: .asciiz "busclock="
cpuclockstr: .asciiz "cpuclock="
memsizestr: .asciiz "memsize="
highmemsizestr: .asciiz "highmemsize="
.p2align 2
argdone:
#endif
/* Decompress the payload. */
addiu $a0, $s0, GRUB_KERNEL_MACHINE_RAW_SIZE - BASE_ADDR
lui $a1, %hi(compressed)
addiu $a1, %lo(compressed)
lw $a2, (GRUB_KERNEL_MACHINE_COMPRESSED_SIZE - BASE_ADDR)($s0)
move $s1, $a1
/* $a0 contains source compressed address, $a1 is destination,
$a2 is compressed size. FIXME: put LZMA here. Don't clober $s0,
$s1, $s2, $s3, $s4 and $s5.
On return $v0 contains uncompressed size.
*/
move $v0, $a2
reloccont:
lb $t4, 0($a0)
sb $t4, 0($a1)
addiu $a1,$a1,1
addiu $a0,$a0,1
addiu $a2, 0xffff
bne $a2, $0, reloccont
move $a0, $s1
move $a1, $v0
#include "cache_flush.S"
lui $t1, %hi(cont)
addiu $t1, %lo(cont)
jr $t1
. = _start + GRUB_KERNEL_MACHINE_RAW_SIZE
compressed:
. = _start + GRUB_KERNEL_MACHINE_PREFIX
VARIABLE(grub_prefix)
/* to be filled by grub-mkelfimage */
/*
* Leave some breathing room for the prefix.
*/
. = _start + GRUB_KERNEL_MACHINE_DATA_END
#ifdef GRUB_MACHINE_MIPS_YEELOONG
VARIABLE (grub_arch_busclock)
.long 0
VARIABLE (grub_arch_cpuclock)
.long 0
VARIABLE (grub_arch_memsize)
.long 0
VARIABLE (grub_arch_highmemsize)
.long 0
#endif
cont:
#ifdef GRUB_MACHINE_MIPS_YEELOONG
lui $t1, %hi(grub_arch_busclock)
addiu $t1, %lo(grub_arch_busclock)
sw $s2, 0($t1)
sw $s3, 4($t1)
sw $s4, 8($t1)
sw $s5, 12($t1)
#endif
/* Move the modules out of BSS. */
lui $t1, %hi(_start)
addiu $t1, %lo(_start)
lw $t2, (GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE - BASE_ADDR)($s0)
addu $t2, $t1, $t2
lui $t1, %hi(_end)
addiu $t1, %lo(_end)
addiu $t1, (GRUB_KERNEL_MACHINE_MOD_ALIGN-1)
li $t3, (GRUB_KERNEL_MACHINE_MOD_ALIGN-1)
nor $t3, $t3, $0
and $t1, $t1, $t3
lw $t3, (GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE - BASE_ADDR)($s0)
/* Backward copy. */
add $t1, $t1, $t3
add $t2, $t2, $t3
addiu $t1, $t1, 0xffff
addiu $t2, $t2, 0xffff
/* $t2 is source. $t1 is destination. $t3 is size. */
modulesmovcont:
lb $t4, 0($t2)
sb $t4, 0($t1)
addiu $t1,$t1,0xffff
addiu $t2,$t2,0xffff
addiu $t3, 0xffff
bne $t3, $0, modulesmovcont
/* Clean BSS. */
lui $t1, %hi(__bss_start)
addiu $t1, %lo(__bss_start)
lui $t2, %hi(_end)
addiu $t2, %lo(_end)
bsscont:
sb $0,0($t1)
addiu $t1,$t1,1
sltu $t3,$t1,$t2
bne $t3, $0, bsscont
li $sp, GRUB_MACHINE_MEMORY_STACK_HIGH
lui $t1, %hi(grub_main)
addiu $t1, %lo(grub_main)
jr $t1

245
kern/mips/yeeloong/init.c Normal file
View file

@ -0,0 +1,245 @@
/*
* 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/kernel.h>
#include <grub/misc.h>
#include <grub/env.h>
#include <grub/time.h>
#include <grub/types.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/time.h>
#include <grub/machine/kernel.h>
#include <grub/machine/memory.h>
#include <grub/mips/loongson.h>
#include <grub/cs5536.h>
#include <grub/term.h>
#include <grub/machine/ec.h>
extern void grub_video_sm712_init (void);
extern void grub_video_init (void);
extern void grub_bitmap_init (void);
extern void grub_font_init (void);
extern void grub_gfxterm_init (void);
extern void grub_at_keyboard_init (void);
extern void grub_serial_init (void);
extern void grub_terminfo_init (void);
/* FIXME: use interrupt to count high. */
grub_uint64_t
grub_get_rtc (void)
{
static grub_uint32_t high = 0;
static grub_uint32_t last = 0;
grub_uint32_t low;
asm volatile ("mfc0 %0, " GRUB_CPU_LOONGSON_COP0_TIMER_COUNT : "=r" (low));
if (low < last)
high++;
last = low;
return (((grub_uint64_t) high) << 32) | low;
}
grub_err_t
grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t,
grub_uint64_t,
grub_uint32_t))
{
hook (GRUB_ARCH_LOWMEMPSTART, grub_arch_memsize << 20,
GRUB_MACHINE_MEMORY_AVAILABLE);
hook (GRUB_ARCH_HIGHMEMPSTART, grub_arch_highmemsize << 20,
GRUB_MACHINE_MEMORY_AVAILABLE);
return GRUB_ERR_NONE;
}
static void
init_pci (void)
{
auto int NESTED_FUNC_ATTR set_card (grub_pci_device_t dev, grub_pci_id_t pciid);
int NESTED_FUNC_ATTR set_card (grub_pci_device_t dev, grub_pci_id_t pciid)
{
grub_pci_address_t addr;
/* FIXME: autoscan for BARs and devices. */
switch (pciid)
{
case GRUB_YEELOONG_OHCI_PCIID:
addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0);
grub_pci_write (addr, 0x5025000);
addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND);
grub_pci_write_word (addr, GRUB_PCI_COMMAND_SERR_ENABLE
| GRUB_PCI_COMMAND_PARITY_ERROR
| GRUB_PCI_COMMAND_BUS_MASTER
| GRUB_PCI_COMMAND_MEM_ENABLED);
addr = grub_pci_make_address (dev, GRUB_PCI_REG_STATUS);
grub_pci_write_word (addr, 0x0200 | GRUB_PCI_STATUS_CAPABILITIES);
break;
case GRUB_YEELOONG_EHCI_PCIID:
addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0);
grub_pci_write (addr, 0x5026000);
addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND);
grub_pci_write_word (addr, GRUB_PCI_COMMAND_SERR_ENABLE
| GRUB_PCI_COMMAND_PARITY_ERROR
| GRUB_PCI_COMMAND_BUS_MASTER
| GRUB_PCI_COMMAND_MEM_ENABLED);
addr = grub_pci_make_address (dev, GRUB_PCI_REG_STATUS);
grub_pci_write_word (addr, (1 << GRUB_PCI_STATUS_DEVSEL_TIMING_SHIFT)
| GRUB_PCI_STATUS_CAPABILITIES);
break;
}
return 0;
}
*((volatile grub_uint32_t *) GRUB_CPU_LOONGSON_PCI_HIT1_SEL_LO) = 0x8000000c;
*((volatile grub_uint32_t *) GRUB_CPU_LOONGSON_PCI_HIT1_SEL_HI) = 0xffffffff;
/* Setup PCI controller. */
*((volatile grub_uint16_t *) (GRUB_MACHINE_PCI_CONTROLLER_HEADER
+ GRUB_PCI_REG_COMMAND))
= GRUB_PCI_COMMAND_PARITY_ERROR | GRUB_PCI_COMMAND_BUS_MASTER
| GRUB_PCI_COMMAND_MEM_ENABLED;
*((volatile grub_uint16_t *) (GRUB_MACHINE_PCI_CONTROLLER_HEADER
+ GRUB_PCI_REG_STATUS))
= (1 << GRUB_PCI_STATUS_DEVSEL_TIMING_SHIFT)
| GRUB_PCI_STATUS_FAST_B2B_CAPABLE | GRUB_PCI_STATUS_66MHZ_CAPABLE
| GRUB_PCI_STATUS_CAPABILITIES;
*((volatile grub_uint32_t *) (GRUB_MACHINE_PCI_CONTROLLER_HEADER
+ GRUB_PCI_REG_CACHELINE)) = 0xff;
*((volatile grub_uint32_t *) (GRUB_MACHINE_PCI_CONTROLLER_HEADER
+ GRUB_PCI_REG_ADDRESS_REG0))
= 0x80000000 | GRUB_PCI_ADDR_MEM_TYPE_64 | GRUB_PCI_ADDR_MEM_PREFETCH;
*((volatile grub_uint32_t *) (GRUB_MACHINE_PCI_CONTROLLER_HEADER
+ GRUB_PCI_REG_ADDRESS_REG1)) = 0;
grub_pci_iterate (set_card);
}
void
grub_machine_init (void)
{
grub_addr_t modend;
/* FIXME: measure this. */
if (grub_arch_busclock == 0)
{
grub_arch_busclock = 66000000;
grub_arch_cpuclock = 797000000;
}
grub_install_get_time_ms (grub_rtc_get_time_ms);
if (grub_arch_memsize == 0)
{
grub_port_t smbbase;
grub_err_t err;
grub_pci_device_t dev;
struct grub_smbus_spd spd;
unsigned totalmem;
int i;
if (!grub_cs5536_find (&dev))
grub_fatal ("No CS5536 found\n");
err = grub_cs5536_init_smbus (dev, 0x7ff, &smbbase);
if (err)
grub_fatal ("Couldn't init SMBus: %s\n", grub_errmsg);
/* Yeeloong has only one memory slot. */
err = grub_cs5536_read_spd (smbbase, GRUB_SMB_RAM_START_ADDR, &spd);
if (err)
grub_fatal ("Couldn't read SPD: %s\n", grub_errmsg);
for (i = 5; i < 13; i++)
if (spd.ddr2.rank_capacity & (1 << (i & 7)))
break;
/* Something is wrong. */
if (i == 13)
totalmem = 256;
else
totalmem = ((spd.ddr2.num_of_ranks
& GRUB_SMBUS_SPD_MEMORY_NUM_OF_RANKS_MASK) + 1) << (i + 2);
if (totalmem >= 256)
{
grub_arch_memsize = 256;
grub_arch_highmemsize = totalmem - 256;
}
else
{
grub_arch_memsize = (totalmem >> 20);
grub_arch_highmemsize = 0;
}
grub_cs5536_init_geode (dev);
init_pci ();
}
modend = grub_modules_get_end ();
grub_mm_init_region ((void *) modend, (grub_arch_memsize << 20)
- (modend - GRUB_ARCH_LOWMEMVSTART));
/* FIXME: use upper memory as well. */
/* Initialize output terminal (can't be done earlier, as gfxterm
relies on a working heap. */
grub_video_init ();
grub_video_sm712_init ();
grub_bitmap_init ();
grub_font_init ();
grub_gfxterm_init ();
grub_at_keyboard_init ();
grub_terminfo_init ();
grub_serial_init ();
}
void
grub_machine_fini (void)
{
}
void
grub_halt (void)
{
grub_outb (grub_inb (GRUB_CPU_LOONGSON_GPIOCFG)
& ~GRUB_CPU_LOONGSON_SHUTDOWN_GPIO, GRUB_CPU_LOONGSON_GPIOCFG);
grub_printf ("Shutdown failed\n");
grub_refresh ();
while (1);
}
void
grub_exit (void)
{
grub_halt ();
}
void
grub_reboot (void)
{
grub_write_ec (GRUB_MACHINE_EC_COMMAND_REBOOT);
grub_printf ("Reboot failed\n");
grub_refresh ();
while (1);
}

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,2008,2009 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
@ -25,6 +25,9 @@
#include <grub/env.h>
#include <grub/i18n.h>
static int
grub_vsnprintf_real (char *str, grub_size_t n, const char *fmt, va_list args);
static int
grub_iswordseparator (int c)
{
@ -32,7 +35,7 @@ grub_iswordseparator (int c)
}
/* grub_gettext_dummy is not translating anything. */
const char *
static const char *
grub_gettext_dummy (const char *s)
{
return s;
@ -139,19 +142,6 @@ grub_printf_ (const char *fmt, ...)
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)
{
@ -197,14 +187,37 @@ grub_real_dprintf (const char *file, const int line, const char *condition,
}
}
#define PREALLOC_SIZE 255
int
grub_vprintf (const char *fmt, va_list args)
{
int ret;
grub_size_t s;
static char buf[PREALLOC_SIZE + 1];
char *curbuf = buf;
ret = grub_vsprintf (0, fmt, args);
grub_refresh ();
return ret;
s = grub_vsnprintf_real (buf, PREALLOC_SIZE, fmt, args);
if (s > PREALLOC_SIZE)
{
curbuf = grub_malloc (s + 1);
if (!curbuf)
{
grub_errno = GRUB_ERR_NONE;
buf[PREALLOC_SIZE - 3] = '.';
buf[PREALLOC_SIZE - 2] = '.';
buf[PREALLOC_SIZE - 1] = '.';
buf[PREALLOC_SIZE] = 0;
}
else
s = grub_vsnprintf_real (curbuf, s, fmt, args);
}
grub_xputs (curbuf);
if (curbuf != buf)
grub_free (curbuf);
return s;
}
int
@ -227,6 +240,11 @@ grub_memcmp (const void *s1, const void *s2, grub_size_t n)
#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
@ -512,6 +530,11 @@ grub_memset (void *s, int c, grub_size_t n)
#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
@ -626,21 +649,19 @@ grub_lltoa (char *str, int c, unsigned long long n)
return p;
}
int
grub_vsprintf (char *str, const char *fmt, va_list args)
static int
grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt, va_list args)
{
char c;
int count = 0;
grub_size_t count = 0;
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)
if (count < max_len)
*str++ = ch;
else
grub_putchar (ch);
count++;
}
@ -857,126 +878,85 @@ grub_vsprintf (char *str, const char *fmt, va_list args)
}
}
if (str)
*str = '\0';
if (count && !str)
grub_refresh ();
*str = '\0';
return count;
}
int
grub_sprintf (char *str, const char *fmt, ...)
grub_vsnprintf (char *str, grub_size_t n, const char *fmt, va_list ap)
{
grub_size_t ret;
if (!n)
return 0;
n--;
ret = grub_vsnprintf_real (str, n, fmt, ap);
return ret < n ? ret : n;
}
int
grub_snprintf (char *str, grub_size_t n, const char *fmt, ...)
{
va_list ap;
int ret;
va_start (ap, fmt);
ret = grub_vsprintf (str, fmt, ap);
ret = grub_vsnprintf (str, n, fmt, ap);
va_end (ap);
return ret;
}
/* 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 an invalid sequence is found, return -1.
If SRCEND is not NULL, then *SRCEND is set to the next byte after the
last byte used in SRC. */
grub_ssize_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)
char *
grub_xvasprintf (const char *fmt, va_list ap)
{
grub_uint32_t *p = dest;
int count = 0;
grub_uint32_t code = 0;
grub_size_t s, as = PREALLOC_SIZE;
char *ret;
if (srcend)
*srcend = src;
while (srcsize && destsize)
while (1)
{
grub_uint32_t c = *src++;
if (srcsize != (grub_size_t)-1)
srcsize--;
if (count)
{
if ((c & 0xc0) != 0x80)
{
/* invalid */
return -1;
}
else
{
code <<= 6;
code |= (c & 0x3f);
count--;
}
}
else
{
if (c == 0)
break;
ret = grub_malloc (as + 1);
if (!ret)
return NULL;
if ((c & 0x80) == 0x00)
code = c;
else if ((c & 0xe0) == 0xc0)
{
count = 1;
code = c & 0x1f;
}
else if ((c & 0xf0) == 0xe0)
{
count = 2;
code = c & 0x0f;
}
else if ((c & 0xf8) == 0xf0)
{
count = 3;
code = c & 0x07;
}
else if ((c & 0xfc) == 0xf8)
{
count = 4;
code = c & 0x03;
}
else if ((c & 0xfe) == 0xfc)
{
count = 5;
code = c & 0x01;
}
else
return -1;
}
s = grub_vsnprintf_real (ret, as, fmt, ap);
if (s <= as)
return ret;
if (count == 0)
{
*p++ = code;
destsize--;
}
grub_free (ret);
as = s;
}
}
if (srcend)
*srcend = src;
return p - dest;
char *
grub_xasprintf (const char *fmt, ...)
{
va_list ap;
char *ret;
va_start (ap, fmt);
ret = grub_xvasprintf (fmt, ap);
va_end (ap);
return ret;
}
/* Abort GRUB. This function does not return. */
void
grub_abort (void)
{
if (grub_term_get_current_output ())
grub_printf ("\nAborted.");
#ifndef GRUB_UTIL
if (grub_term_inputs)
#endif
{
grub_printf ("\nAborted.");
if (grub_term_get_current_input ())
{
grub_printf (" Press any key to exit.");
grub_getkey ();
}
grub_printf (" Press any key to exit.");
grub_getkey ();
}
grub_exit ();
@ -987,7 +967,7 @@ grub_abort (void)
void abort (void) __attribute__ ((alias ("grub_abort")));
#endif
#ifdef NEED_ENABLE_EXECUTE_STACK
#if defined(NEED_ENABLE_EXECUTE_STACK) && !defined(GRUB_UTIL) && !defined(GRUB_MACHINE_EMU)
/* Some gcc versions generate a call to this function
in trampolines for nested functions. */
void __enable_execute_stack (void *addr __attribute__ ((unused)))
@ -995,3 +975,13 @@ void __enable_execute_stack (void *addr __attribute__ ((unused)))
}
#endif
#if defined (NEED_REGISTER_FRAME_INFO) && !defined(GRUB_UTIL)
void __register_frame_info (void)
{
}
void __deregister_frame_info (void)
{
}
#endif

View file

@ -1,7 +1,7 @@
/* mm.c - functions for memory 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
@ -148,15 +148,14 @@ grub_mm_init_region (void *addr, grub_size_t size)
grub_printf ("Using memory for heap: start=%p, end=%p\n", addr, addr + (unsigned int) size);
#endif
/* If this region is too small, ignore it. */
if (size < GRUB_MM_ALIGN * 2)
return;
/* Allocate a region from the head. */
r = (grub_mm_region_t) (((grub_addr_t) addr + GRUB_MM_ALIGN - 1)
& (~(GRUB_MM_ALIGN - 1)));
r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN);
size -= (char *) r - (char *) addr + sizeof (*r);
/* If this region is too small, ignore it. */
if (size < GRUB_MM_ALIGN)
return;
h = (grub_mm_header_t) ((char *) r + GRUB_MM_ALIGN);
h->next = h;
h->magic = GRUB_MM_FREE_MAGIC;
@ -221,9 +220,8 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
+---------------+ v
*/
q->next = p->next;
p->magic = GRUB_MM_ALLOC_MAGIC;
}
else if (extra == 0 || p->size == n + extra)
else if (align == 1 || p->size == n + extra)
{
/* There might be alignment requirement, when taking it into
account memory block fits in.
@ -240,10 +238,25 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
| alloc, size=n | |
+---------------+ v
*/
p->size -= n;
p += p->size;
p->size = n;
p->magic = GRUB_MM_ALLOC_MAGIC;
}
else if (extra == 0)
{
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;
q->next = r;
if (q == p)
{
q = r;
r->next = r;
}
}
else
{
@ -276,10 +289,11 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
p->size = extra;
p->next = r;
p += extra;
p->size = n;
p->magic = GRUB_MM_ALLOC_MAGIC;
}
p->magic = GRUB_MM_ALLOC_MAGIC;
p->size = n;
/* 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. */
@ -388,7 +402,7 @@ grub_free (void *ptr)
do
{
grub_printf ("%s:%d: q=%p, q->size=0x%x, q->magic=0x%x\n",
__FILE__, __LINE__, q, q->size, q->magic);
GRUB_FILE, __LINE__, q, q->size, q->magic);
q = q->next;
}
while (q != r->first);

View file

@ -26,32 +26,31 @@
/* All the possible state transitions on the command line. If a
transition can not be found, it is assumed that there is no
transition and keep_value is assumed to be 1. */
static struct grub_parser_state_transition state_transitions[] =
{
{ GRUB_PARSER_STATE_TEXT, GRUB_PARSER_STATE_QUOTE, '\'', 0},
{ GRUB_PARSER_STATE_TEXT, GRUB_PARSER_STATE_DQUOTE, '\"', 0},
{ GRUB_PARSER_STATE_TEXT, GRUB_PARSER_STATE_VAR, '$', 0},
{ GRUB_PARSER_STATE_TEXT, GRUB_PARSER_STATE_ESC, '\\', 0},
static struct grub_parser_state_transition state_transitions[] = {
{GRUB_PARSER_STATE_TEXT, GRUB_PARSER_STATE_QUOTE, '\'', 0},
{GRUB_PARSER_STATE_TEXT, GRUB_PARSER_STATE_DQUOTE, '\"', 0},
{GRUB_PARSER_STATE_TEXT, GRUB_PARSER_STATE_VAR, '$', 0},
{GRUB_PARSER_STATE_TEXT, GRUB_PARSER_STATE_ESC, '\\', 0},
{ GRUB_PARSER_STATE_ESC, GRUB_PARSER_STATE_TEXT, 0, 1},
{GRUB_PARSER_STATE_ESC, GRUB_PARSER_STATE_TEXT, 0, 1},
{ GRUB_PARSER_STATE_QUOTE, GRUB_PARSER_STATE_TEXT, '\'', 0},
{GRUB_PARSER_STATE_QUOTE, GRUB_PARSER_STATE_TEXT, '\'', 0},
{ GRUB_PARSER_STATE_DQUOTE, GRUB_PARSER_STATE_TEXT, '\"', 0},
{ GRUB_PARSER_STATE_DQUOTE, GRUB_PARSER_STATE_QVAR, '$', 0},
{GRUB_PARSER_STATE_DQUOTE, GRUB_PARSER_STATE_TEXT, '\"', 0},
{GRUB_PARSER_STATE_DQUOTE, GRUB_PARSER_STATE_QVAR, '$', 0},
{ GRUB_PARSER_STATE_VAR, GRUB_PARSER_STATE_VARNAME2, '{', 0},
{ GRUB_PARSER_STATE_VAR, GRUB_PARSER_STATE_VARNAME, 0, 1},
{ GRUB_PARSER_STATE_VARNAME, GRUB_PARSER_STATE_TEXT, ' ', 1},
{ GRUB_PARSER_STATE_VARNAME2, GRUB_PARSER_STATE_TEXT, '}', 0},
{GRUB_PARSER_STATE_VAR, GRUB_PARSER_STATE_VARNAME2, '{', 0},
{GRUB_PARSER_STATE_VAR, GRUB_PARSER_STATE_VARNAME, 0, 1},
{GRUB_PARSER_STATE_VARNAME, GRUB_PARSER_STATE_TEXT, ' ', 1},
{GRUB_PARSER_STATE_VARNAME2, GRUB_PARSER_STATE_TEXT, '}', 0},
{ 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_TEXT, '\"', 0},
{ GRUB_PARSER_STATE_QVARNAME, GRUB_PARSER_STATE_DQUOTE, ' ', 1},
{ GRUB_PARSER_STATE_QVARNAME2, GRUB_PARSER_STATE_DQUOTE, '}', 0},
{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_TEXT, '\"', 0},
{GRUB_PARSER_STATE_QVARNAME, GRUB_PARSER_STATE_DQUOTE, ' ', 1},
{GRUB_PARSER_STATE_QVARNAME2, GRUB_PARSER_STATE_DQUOTE, '}', 0},
{ 0, 0, 0, 0}
{0, 0, 0, 0}
};
@ -74,17 +73,17 @@ grub_parser_cmdline_state (grub_parser_state_t state, char c, char *result)
if (transition->input == c)
break;
if (transition->input == ' ' && ! grub_isalpha (c)
&& ! grub_isdigit (c) && c != '_')
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. */
match can be found. */
if (transition->input == 0)
break;
}
if (! transition->from_state)
if (!transition->from_state)
transition = &default_transition;
if (transition->keep_value)
@ -113,43 +112,44 @@ grub_parser_split_cmdline (const char *cmdline, grub_reader_getline_t getline,
auto int check_varstate (grub_parser_state_t s);
int check_varstate (grub_parser_state_t s)
{
return (s == GRUB_PARSER_STATE_VARNAME
|| s == GRUB_PARSER_STATE_VARNAME2
|| s == GRUB_PARSER_STATE_QVARNAME
|| s == GRUB_PARSER_STATE_QVARNAME2);
}
{
return (s == GRUB_PARSER_STATE_VARNAME
|| s == GRUB_PARSER_STATE_VARNAME2
|| s == GRUB_PARSER_STATE_QVARNAME
|| s == GRUB_PARSER_STATE_QVARNAME2);
}
auto void add_var (grub_parser_state_t newstate);
void add_var (grub_parser_state_t newstate)
{
char *val;
{
char *val;
/* Check if a variable was being read in and the end of the name
was reached. */
if (! (check_varstate (state) && !check_varstate (newstate)))
return;
/* Check if a variable was being read in and the end of the name
was reached. */
if (!(check_varstate (state) && !check_varstate (newstate)))
return;
*(vp++) = '\0';
val = grub_env_get (varname);
vp = varname;
if (! val)
return;
*(vp++) = '\0';
val = grub_env_get (varname);
vp = varname;
if (!val)
return;
/* Insert the contents of the variable in the buffer. */
for (; *val; val++)
*(bp++) = *val;
}
/* Insert the contents of the variable in the buffer. */
for (; *val; val++)
*(bp++) = *val;
}
*argc = 0;
do
{
if (! rd || !*rd)
if (!rd || !*rd)
{
if (getline)
getline (&rd, 1);
else break;
else
break;
}
if (!rd)
@ -190,7 +190,8 @@ grub_parser_split_cmdline (const char *cmdline, grub_reader_getline_t getline,
}
state = newstate;
}
} while (state != GRUB_PARSER_STATE_TEXT && !check_varstate (state));
}
while (state != GRUB_PARSER_STATE_TEXT && !check_varstate (state));
/* A special case for when the last character was part of a
variable. */
@ -204,12 +205,12 @@ grub_parser_split_cmdline (const char *cmdline, grub_reader_getline_t getline,
/* Reserve memory for the return values. */
args = grub_malloc (bp - buffer);
if (! args)
if (!args)
return grub_errno;
grub_memcpy (args, buffer, bp - buffer);
*argv = grub_malloc (sizeof (char *) * (*argc + 1));
if (! *argv)
if (!*argv)
{
grub_free (args);
return grub_errno;
@ -229,44 +230,36 @@ grub_parser_split_cmdline (const char *cmdline, grub_reader_getline_t getline,
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;
{
char *p;
if (! source)
{
*line = 0;
return 0;
}
if (!source)
{
*line = 0;
return 0;
}
p = grub_strchr (source, '\n');
if (p)
*p = 0;
p = grub_strchr (source, '\n');
if (p)
*line = grub_strndup (source, p - source);
else
*line = grub_strdup (source);
if (p)
*p = '\n';
source = p ? p + 1 : 0;
return 0;
}
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_rescue_parse_line (line, getline);
grub_free (line);
}

View file

@ -17,40 +17,80 @@
*/
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/partition.h>
#include <grub/disk.h>
static grub_partition_map_t grub_partition_map_list;
#ifdef GRUB_UTIL
#include <grub/util/misc.h>
#endif
void
grub_partition_map_register (grub_partition_map_t partmap)
grub_partition_map_t grub_partition_map_list;
/*
* Checks that disk->partition contains part. This function assumes that the
* start of part is relative to the start of disk->partition. Returns 1 if
* disk->partition is null.
*/
static int
grub_partition_check_containment (const grub_disk_t disk,
const grub_partition_t part)
{
partmap->next = grub_partition_map_list;
grub_partition_map_list = partmap;
if (disk->partition == NULL)
return 1;
if (part->start + part->len > disk->partition->len)
{
char *partname;
partname = grub_partition_get_name (disk->partition);
grub_dprintf ("partition", "sub-partition %s%d of (%s,%s) ends after parent.\n",
part->partmap->name, part->number + 1, disk->name, partname);
#ifdef GRUB_UTIL
grub_util_warn ("Discarding improperly nested partition (%s,%s,%s%d)",
disk->name, partname, part->partmap->name, part->number + 1);
#endif
grub_free (partname);
return 0;
}
return 1;
}
void
grub_partition_map_unregister (grub_partition_map_t partmap)
static grub_partition_t
grub_partition_map_probe (const grub_partition_map_t partmap,
grub_disk_t disk, int partnum)
{
grub_partition_map_t *p, q;
grub_partition_t p = 0;
for (p = &grub_partition_map_list, q = *p; q; p = &(q->next), q = q->next)
if (q == partmap)
{
*p = q->next;
break;
}
}
auto int find_func (grub_disk_t d, const grub_partition_t partition);
int
grub_partition_map_iterate (int (*hook) (const grub_partition_map_t partmap))
{
grub_partition_map_t p;
int find_func (grub_disk_t dsk,
const grub_partition_t partition)
{
if (partnum != partition->number)
return 0;
for (p = grub_partition_map_list; p; p = p->next)
if (hook (p))
if (!(grub_partition_check_containment (dsk, partition)))
return 0;
p = (grub_partition_t) grub_malloc (sizeof (*p));
if (! p)
return 1;
grub_memcpy (p, partition, sizeof (*p));
return 1;
}
partmap->iterate (disk, find_func);
if (grub_errno)
goto fail;
return p;
fail:
grub_free (p);
return 0;
}
@ -58,28 +98,66 @@ grub_partition_t
grub_partition_probe (struct grub_disk *disk, const char *str)
{
grub_partition_t part = 0;
grub_partition_t curpart = 0;
grub_partition_t tail;
const char *ptr;
auto int part_map_probe (const grub_partition_map_t partmap);
part = tail = disk->partition;
int part_map_probe (const grub_partition_map_t partmap)
for (ptr = str; *ptr;)
{
part = partmap->probe (disk, str);
if (part)
return 1;
grub_partition_map_t partmap;
int num;
const char *partname, *partname_end;
if (grub_errno == GRUB_ERR_BAD_PART_TABLE)
partname = ptr;
while (*ptr && grub_isalpha (*ptr))
ptr++;
partname_end = ptr;
num = grub_strtoul (ptr, (char **) &ptr, 0) - 1;
curpart = 0;
/* Use the first partition map type found. */
FOR_PARTITION_MAPS(partmap)
{
if (partname_end != partname &&
(grub_strncmp (partmap->name, partname, partname_end - partname)
!= 0 || partmap->name[partname_end - partname] != 0))
continue;
disk->partition = part;
curpart = grub_partition_map_probe (partmap, disk, num);
disk->partition = tail;
if (curpart)
break;
if (grub_errno == GRUB_ERR_BAD_PART_TABLE)
{
/* Continue to next partition map type. */
grub_errno = GRUB_ERR_NONE;
continue;
}
break;
}
if (! curpart)
{
/* Continue to next partition map type. */
grub_errno = GRUB_ERR_NONE;
while (part)
{
curpart = part->parent;
grub_free (part);
part = curpart;
}
return 0;
}
return 1;
curpart->parent = part;
part = curpart;
if (! ptr || *ptr != ',')
break;
ptr++;
}
/* Use the first partition map type found. */
grub_partition_map_iterate (part_map_probe);
return part;
}
@ -88,40 +166,55 @@ grub_partition_iterate (struct grub_disk *disk,
int (*hook) (grub_disk_t disk,
const grub_partition_t partition))
{
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);
auto int part_iterate (grub_disk_t dsk, const grub_partition_t p);
int part_map_iterate_hook (grub_disk_t d __attribute__ ((unused)),
const grub_partition_t partition __attribute__ ((unused)))
int part_iterate (grub_disk_t dsk,
const grub_partition_t partition)
{
return 1;
}
struct grub_partition p = *partition;
int part_map_iterate (const grub_partition_map_t p)
{
grub_dprintf ("partition", "Detecting %s...\n", p->name);
p->iterate (disk, part_map_iterate_hook);
if (!(grub_partition_check_containment (dsk, partition)))
return 0;
if (grub_errno != GRUB_ERR_NONE)
p.parent = dsk->partition;
dsk->partition = 0;
if (hook (dsk, &p))
{
/* Continue to next partition map type. */
grub_dprintf ("partition", "%s detection failed.\n", p->name);
grub_errno = GRUB_ERR_NONE;
return 0;
ret = 1;
return 1;
}
grub_dprintf ("partition", "%s detection succeeded.\n", p->name);
partmap = p;
return 1;
if (p.start != 0)
{
const struct grub_partition_map *partmap;
dsk->partition = &p;
FOR_PARTITION_MAPS(partmap)
{
grub_err_t err;
err = partmap->iterate (dsk, part_iterate);
if (err)
grub_errno = GRUB_ERR_NONE;
if (ret)
break;
}
}
dsk->partition = p.parent;
return ret;
}
grub_partition_map_iterate (part_map_iterate);
if (partmap)
ret = partmap->iterate (disk, hook);
{
const struct grub_partition_map *partmap;
FOR_PARTITION_MAPS(partmap)
{
grub_err_t err;
err = partmap->iterate (disk, part_iterate);
if (err)
grub_errno = GRUB_ERR_NONE;
if (ret)
break;
}
}
return ret;
}
@ -129,5 +222,32 @@ grub_partition_iterate (struct grub_disk *disk,
char *
grub_partition_get_name (const grub_partition_t partition)
{
return partition->partmap->get_name (partition);
char *out = 0;
int curlen = 0;
grub_partition_t part;
for (part = partition; part; part = part->parent)
{
/* Even on 64-bit machines this buffer is enough to hold
longest number. */
char buf[grub_strlen (part->partmap->name) + 25];
int strl;
grub_snprintf (buf, sizeof (buf), "%s%d", part->partmap->name,
part->number + 1);
strl = grub_strlen (buf);
if (curlen)
{
out = grub_realloc (out, curlen + strl + 2);
grub_memcpy (out + strl + 1, out, curlen);
out[curlen + 1 + strl] = 0;
grub_memcpy (out, buf, strl);
out[strl] = ',';
curlen = curlen + 1 + strl;
}
else
{
curlen = strl;
out = grub_strdup (buf);
}
}
return out;
}

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

View file

@ -18,7 +18,7 @@
*/
#include <grub/symbol.h>
#include <grub/cpu/kernel.h>
#include <grub/offsets.h>
.extern __bss_start
.extern _end
@ -30,7 +30,7 @@ start:
_start:
b codestart
. = _start + GRUB_KERNEL_CPU_PREFIX
. = _start + GRUB_KERNEL_MACHINE_PREFIX
VARIABLE(grub_prefix)
/* to be filled by grub-mkelfimage */
@ -39,7 +39,7 @@ VARIABLE(grub_prefix)
* Leave some breathing room for the prefix.
*/
. = _start + GRUB_KERNEL_CPU_DATA_END
. = _start + GRUB_KERNEL_MACHINE_DATA_END
codestart:
li 2, 0

View file

@ -24,7 +24,7 @@
#include <grub/misc.h>
#include <grub/command.h>
static grub_err_t
grub_err_t
grub_rescue_parse_line (char *line, grub_reader_getline_t getline)
{
char *name;
@ -74,15 +74,3 @@ grub_rescue_parse_line (char *line, grub_reader_getline_t getline)
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);
}

View file

@ -1,7 +1,7 @@
/* rescue_reader.c - rescue mode reader */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
* 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
@ -19,26 +19,22 @@
#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];
static grub_err_t
grub_rescue_init (void)
{
grub_printf ("Entering rescue mode...\n");
return 0;
}
/* 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;
char str[4];
grub_printf ((cont) ? "> " : "grub rescue> ");
grub_memset (linebuf, 0, GRUB_RESCUE_BUF_SIZE);
@ -49,24 +45,28 @@ grub_rescue_read_line (char **line, int cont)
{
if (pos < GRUB_RESCUE_BUF_SIZE - 1)
{
str[0] = c;
str[1] = 0;
linebuf[pos++] = c;
grub_putchar (c);
grub_xputs (str);
}
}
else if (c == '\b')
{
if (pos > 0)
{
str[0] = c;
str[1] = ' ';
str[2] = c;
str[3] = 0;
linebuf[--pos] = 0;
grub_putchar (c);
grub_putchar (' ');
grub_putchar (c);
grub_xputs (str);
}
}
grub_refresh ();
}
grub_putchar ('\n');
grub_xputs ("\n");
grub_refresh ();
*line = grub_strdup (linebuf);
@ -74,15 +74,24 @@ grub_rescue_read_line (char **line, int cont)
return 0;
}
static struct grub_reader grub_rescue_reader =
{
.name = "rescue",
.init = grub_rescue_init,
.read_line = grub_rescue_read_line
};
void
grub_register_rescue_reader (void)
grub_rescue_run (void)
{
grub_reader_register ("rescue", &grub_rescue_reader);
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_rescue_parse_line (line, grub_rescue_read_line);
grub_free (line);
}
}

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

View file

@ -18,13 +18,14 @@
*/
#include <grub/symbol.h>
#include <grub/machine/kernel.h>
#include <grub/offsets.h>
.text
.align 4
.globl _start
_start:
ba codestart
nop
mov %o4, %o0
. = EXT_C(_start) + GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE
@ -53,12 +54,25 @@ codestart:
or %o3, %lo(_end), %o3
sethi %hi(grub_total_module_size), %o4
lduw [%o4 + %lo(grub_total_module_size)], %o4
add %o2, %o4, %o2
add %o3, %o4, %o3
/* Save ieee1275 stack for future use by booter. */
mov %o6, %o1
/* Our future stack. */
sethi %hi(GRUB_KERNEL_MACHINE_STACK_SIZE - 2047), %o5
or %o5, %lo(GRUB_KERNEL_MACHINE_STACK_SIZE - 2047), %o5
add %o3, %o5, %o6
sub %o2, 4, %o2
sub %o3, 4, %o3
1: lduw [%o2], %o5
stw %o5, [%o3]
subcc %o4, 4, %o4
add %o2, 4, %o2
sub %o2, 4, %o2
bne,pt %icc, 1b
add %o3, 4, %o3
sub %o3, 4, %o3
/* Now it's safe to clear out the BSS. */
sethi %hi(__bss_start), %o2
@ -70,8 +84,9 @@ codestart:
cmp %o2, %o3
blt,pt %xcc, 1b
nop
sethi %hi(grub_ieee1275_original_stack), %o2
stx %o1, [%o2 + %lo(grub_ieee1275_original_stack)]
sethi %hi(grub_ieee1275_entry_fn), %o2
stx %o0, [%o2 + %lo(grub_ieee1275_entry_fn)]
call grub_main
nop
stx %o0, [%o2 + %lo(grub_ieee1275_entry_fn)]
1: ba,a 1b

View file

@ -21,39 +21,6 @@
/* 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)
{

View file

@ -23,12 +23,15 @@
#include <grub/err.h>
#include <grub/misc.h>
#include <grub/time.h>
#include <grub/machine/console.h>
#include <grub/machine/boot.h>
#include <grub/ieee1275/console.h>
#include <grub/machine/kernel.h>
#include <grub/machine/time.h>
#include <grub/ieee1275/ofdisk.h>
#include <grub/ieee1275/ieee1275.h>
grub_addr_t grub_ieee1275_original_stack;
void
grub_exit (void)
{
@ -90,10 +93,7 @@ grub_machine_set_prefix (void)
}
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);
path = grub_xasprintf("%s%s", prefix, grub_prefix);
grub_strcpy (grub_prefix, path);
@ -107,7 +107,8 @@ grub_machine_set_prefix (void)
static void
grub_heap_init (void)
{
grub_mm_init_region ((void *)(long)0x4000UL, 0x200000 - 0x4000);
grub_mm_init_region ((void *) (grub_modules_get_end ()
+ GRUB_KERNEL_MACHINE_STACK_SIZE), 0x200000);
}
static void
@ -154,8 +155,9 @@ void
grub_machine_init (void)
{
grub_ieee1275_init ();
grub_console_init ();
grub_console_init_early ();
grub_heap_init ();
grub_console_init_lately ();
grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_PARTITION_0);
grub_ofdisk_init ();

View file

@ -21,219 +21,116 @@
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/env.h>
#include <grub/time.h>
/* 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;
struct grub_handler_class grub_term_input_class =
{
.name = "terminal_input"
};
struct grub_handler_class grub_term_output_class =
{
.name = "terminal_output"
};
#define grub_cur_term_input grub_term_get_current_input ()
#define grub_cur_term_output grub_term_get_current_output ()
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;
/* Put a Unicode character. */
void
grub_putcode (grub_uint32_t code)
static void
grub_putcode_dumb (grub_uint32_t code,
struct grub_term_output *term)
{
int height = grub_getwh () & 255;
struct grub_unicode_glyph c =
{
.base = code,
.variant = 0,
.attributes = 0,
.ncomb = 0,
.combining = 0,
.estimated_width = 1
};
if (code == '\t' && grub_cur_term_output->getxy)
if (code == '\t' && term->getxy)
{
int n;
n = 8 - ((grub_getxy () >> 8) & 7);
n = 8 - ((term->getxy (term) >> 8) & 7);
while (n--)
grub_putcode (' ');
grub_putcode_dumb (' ', term);
return;
}
(grub_cur_term_output->putchar) (code);
(term->putchar) (term, &c);
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;
}
}
grub_putcode_dumb ('\r', term);
}
/* Put a character. C is one byte of a UTF-8 stream.
This function gathers bytes until a valid Unicode character is found. */
void
grub_putchar (int c)
static void
grub_xputs_dumb (const char *str)
{
static grub_size_t size = 0;
static grub_uint8_t buf[6];
grub_uint32_t code;
grub_ssize_t ret;
buf[size++] = c;
ret = grub_utf8_to_ucs4 (&code, 1, buf, size, 0);
if (ret > 0)
for (; *str; str++)
{
size = 0;
grub_putcode (code);
}
else if (ret < 0)
{
size = 0;
grub_putcode ('?');
grub_term_output_t term;
grub_uint32_t code = *str;
if (code > 0x7f)
code = '?';
FOR_ACTIVE_TERM_OUTPUTS(term)
grub_putcode_dumb (code, term);
}
}
/* Return the number of columns occupied by the character code CODE. */
grub_ssize_t
grub_getcharwidth (grub_uint32_t code)
{
return (grub_cur_term_output->getcharwidth) (code);
}
void (*grub_xputs) (const char *str) = grub_xputs_dumb;
int
grub_getkey (void)
{
return (grub_cur_term_input->getkey) ();
grub_term_input_t term;
grub_refresh ();
while (1)
{
FOR_ACTIVE_TERM_INPUTS(term)
{
int key = term->checkkey (term);
if (key != -1)
return term->getkey (term);
}
grub_cpu_idle ();
}
}
int
grub_checkkey (void)
{
return (grub_cur_term_input->checkkey) ();
grub_term_input_t term;
FOR_ACTIVE_TERM_INPUTS(term)
{
int key = term->checkkey (term);
if (key != -1)
return key;
}
return -1;
}
int
grub_getkeystatus (void)
{
if (grub_cur_term_input->getkeystatus)
return (grub_cur_term_input->getkeystatus) ();
else
return 0;
}
int status = 0;
grub_term_input_t term;
grub_uint16_t
grub_getxy (void)
{
return (grub_cur_term_output->getxy) ();
}
FOR_ACTIVE_TERM_INPUTS(term)
{
if (term->getkeystatus)
status |= term->getkeystatus (term);
}
grub_uint16_t
grub_getwh (void)
{
return (grub_cur_term_output->getwh) ();
}
void
grub_gotoxy (grub_uint8_t x, grub_uint8_t y)
{
(grub_cur_term_output->gotoxy) (x, y);
}
void
grub_cls (void)
{
if ((grub_cur_term_output->flags & GRUB_TERM_DUMB) || (grub_env_get ("debug")))
{
grub_putchar ('\n');
grub_refresh ();
}
else
(grub_cur_term_output->cls) ();
}
void
grub_setcolorstate (grub_term_color_state state)
{
if (grub_cur_term_output->setcolorstate)
(grub_cur_term_output->setcolorstate) (state);
}
void
grub_setcolor (grub_uint8_t normal_color, grub_uint8_t highlight_color)
{
if (grub_cur_term_output->setcolor)
(grub_cur_term_output->setcolor) (normal_color, highlight_color);
}
void
grub_getcolor (grub_uint8_t *normal_color, grub_uint8_t *highlight_color)
{
if (grub_cur_term_output->getcolor)
(grub_cur_term_output->getcolor) (normal_color, highlight_color);
}
int
grub_setcursor (int on)
{
int ret = cursor_state;
if (grub_cur_term_output->setcursor)
{
(grub_cur_term_output->setcursor) (on);
cursor_state = on;
}
return ret;
}
int
grub_getcursor (void)
{
return cursor_state;
return status;
}
void
grub_refresh (void)
{
if (grub_cur_term_output->refresh)
(grub_cur_term_output->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);
}

View file

@ -1,7 +1,7 @@
/* dl-x86_64.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