merge from trunk

This commit is contained in:
Colin Watson 2010-05-18 11:14:13 +01:00
commit e6127bed25
360 changed files with 38433 additions and 8956 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
@ -178,11 +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.");
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

@ -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)
{
@ -152,7 +155,7 @@ grub_device_iterate (int (*hook) (const char *name))
grub_free (partition_name);
grub_free (p);
return 1;
}
}
grub_free (partition_name);
p->next = ents;

View file

@ -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)
@ -441,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);
@ -464,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

@ -348,7 +348,7 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
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
{
@ -469,12 +469,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);
@ -486,12 +488,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)

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

@ -0,0 +1,384 @@
/* 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 grub_uint8_t grub_console_standard_color = 0x7;
static grub_uint8_t grub_console_normal_color = 0x7;
static grub_uint8_t grub_console_highlight_color = 0x70;
#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 (grub_uint32_t c)
{
/* Better than nothing. */
switch (c)
{
case GRUB_TERM_DISP_LEFT:
c = '<';
break;
case GRUB_TERM_DISP_UP:
c = '^';
break;
case GRUB_TERM_DISP_RIGHT:
c = '>';
break;
case GRUB_TERM_DISP_DOWN:
c = 'v';
break;
case GRUB_TERM_DISP_HLINE:
c = '-';
break;
case GRUB_TERM_DISP_VLINE:
c = '|';
break;
case GRUB_TERM_DISP_UL:
case GRUB_TERM_DISP_UR:
case GRUB_TERM_DISP_LL:
case GRUB_TERM_DISP_LR:
c = '+';
break;
default:
/* ncurses does not support Unicode. */
if (c > 0x7f)
c = '?';
break;
}
addch (c | grub_console_attr);
}
static grub_ssize_t
grub_ncurses_getcharwidth (grub_uint32_t code __attribute__ ((unused)))
{
return 1;
}
static void
grub_ncurses_setcolorstate (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 = grub_console_normal_color;
grub_console_attr = A_NORMAL;
break;
case GRUB_TERM_COLOR_HIGHLIGHT:
grub_console_cur_color = grub_console_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);
}
}
/* XXX: This function is never called. */
static void
grub_ncurses_setcolor (grub_uint8_t normal_color, grub_uint8_t highlight_color)
{
grub_console_normal_color = normal_color;
grub_console_highlight_color = highlight_color;
}
static void
grub_ncurses_getcolor (grub_uint8_t *normal_color, grub_uint8_t *highlight_color)
{
*normal_color = grub_console_normal_color;
*highlight_color = grub_console_highlight_color;
}
static int saved_char = ERR;
static int
grub_ncurses_checkkey (void)
{
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 (void)
{
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 = 2;
break;
case KEY_RIGHT:
c = 6;
break;
case KEY_UP:
c = 16;
break;
case KEY_DOWN:
c = 14;
break;
case KEY_IC:
c = 24;
break;
case KEY_DC:
c = 4;
break;
case KEY_BACKSPACE:
/* XXX: For some reason ncurses on xterm does not return
KEY_BACKSPACE. */
case 127:
c = 8;
break;
case KEY_HOME:
c = 1;
break;
case KEY_END:
c = 5;
break;
case KEY_NPAGE:
c = 3;
break;
case KEY_PPAGE:
c = 7;
break;
}
return c;
}
static grub_uint16_t
grub_ncurses_getxy (void)
{
int x;
int y;
getyx (stdscr, y, x);
return (x << 8) | y;
}
static grub_uint16_t
grub_ncurses_getwh (void)
{
int x;
int y;
getmaxyx (stdscr, y, x);
return (x << 8) | y;
}
static void
grub_ncurses_gotoxy (grub_uint8_t x, grub_uint8_t y)
{
move (y, x);
}
static void
grub_ncurses_cls (void)
{
clear ();
refresh ();
}
static void
grub_ncurses_setcursor (int on)
{
curs_set (on ? 1 : 0);
}
static void
grub_ncurses_refresh (void)
{
refresh ();
}
static grub_err_t
grub_ncurses_init (void)
{
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 (void)
{
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,
.getcharwidth = grub_ncurses_getcharwidth,
.getxy = grub_ncurses_getxy,
.getwh = grub_ncurses_getwh,
.gotoxy = grub_ncurses_gotoxy,
.cls = grub_ncurses_cls,
.setcolorstate = grub_ncurses_setcolorstate,
.setcolor = grub_ncurses_setcolor,
.getcolor = grub_ncurses_getcolor,
.setcursor = grub_ncurses_setcursor,
.refresh = grub_ncurses_refresh
};
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 ();
}

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

@ -0,0 +1,543 @@
/* 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>
#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 __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))
/* Don't follow 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;
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
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;
}

1548
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

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

@ -0,0 +1,296 @@
#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>
#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>
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));
}
#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;
}

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

@ -67,12 +67,6 @@ 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)
{
@ -123,7 +117,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 ();

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

@ -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

@ -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

@ -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

@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009 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,12 +47,6 @@ 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)
{
@ -62,22 +57,28 @@ make_install_device (void)
{
/* No hardcoded root partition - make it from the boot drive and the
partition number encoded at the install time. */
grub_snprintf (dev, sizeof (dev),
"(%cd%u", (grub_boot_drive & 0x80) ? 'h' : 'f',
grub_boot_drive & 0x7f);
ptr += grub_strlen (ptr);
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_snprintf (ptr, sizeof (dev) - (ptr - 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);
ptr += grub_strlen (ptr);
if (grub_install_bsd_part >= 0)
grub_snprintf (ptr, sizeof (dev) - (ptr - dev), ",%c",
grub_install_bsd_part + 'a');
ptr += grub_strlen (ptr);
if (grub_install_bsd_part >= 0)
grub_snprintf (ptr, sizeof (dev) - (ptr - dev), ",%c",
grub_install_bsd_part + 'a');
ptr += grub_strlen (ptr);
}
grub_snprintf (ptr, sizeof (dev) - (ptr - dev), ")%s", grub_prefix);
grub_strcpy (grub_prefix, dev);

View file

@ -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 */
@ -1156,7 +1155,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 +1177,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
@ -1446,47 +1444,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 +1498,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)
*

View file

@ -59,6 +59,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 +80,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 +141,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

@ -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

@ -38,11 +38,11 @@
#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[];
@ -133,6 +133,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 */

View file

@ -68,38 +68,33 @@ grub_children_iterate (char *devpath,
{
struct grub_ieee1275_devalias alias;
grub_ssize_t actual;
char *fullname;
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;
fullname = grub_xasprintf ("%s/%s", devpath, childname);
if (!fullname)
{
grub_free (childname);
grub_free (childpath);
grub_free (childtype);
return 0;
}
alias.type = childtype;
alias.path = childpath;
alias.name = fullname;
alias.name = childname;
ret = hook (&alias);
grub_free (fullname);
if (ret)
break;
}
while (grub_ieee1275_peer (child, &child));
while (grub_ieee1275_peer (child, &child) != -1);
grub_free (childname);
grub_free (childpath);
@ -108,6 +103,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 +144,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 +208,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 +219,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 +257,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);
@ -374,7 +396,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);
@ -405,8 +427,9 @@ grub_reboot (void)
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);
}

View file

@ -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;

View file

@ -29,10 +29,10 @@
#include <grub/cpu/kernel.h>
extern void grub_video_sm712_init (void);
extern void grub_video_video_init (void);
extern void grub_video_bitmap_init (void);
extern void grub_font_manager_init (void);
extern void grub_term_gfxterm_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);
/* FIXME: use interrupt to count high. */
@ -63,45 +63,23 @@ grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t,
return GRUB_ERR_NONE;
}
static void *
get_modules_end (void)
{
struct grub_module_info *modinfo;
struct grub_module_header *header;
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 modinfo;
for (header = (struct grub_module_header *) (modbase + modinfo->offset);
header < (struct grub_module_header *) (modbase + modinfo->size);
header = (struct grub_module_header *) ((char *) header + header->size));
return header;
}
void
grub_machine_init (void)
{
void *modend;
modend = get_modules_end ();
grub_mm_init_region (modend, (grub_arch_memsize << 20)
- (((grub_addr_t) modend) - GRUB_ARCH_LOWMEMVSTART));
grub_addr_t modend;
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. */
grub_install_get_time_ms (grub_rtc_get_time_ms);
/* Initialize output terminal (can't be done earlier, as gfxterm
relies on a working heap. */
grub_video_sm712_init ();
grub_video_video_init ();
grub_video_bitmap_init ();
grub_font_manager_init ();
grub_term_gfxterm_init ();
grub_video_init ();
grub_bitmap_init ();
grub_font_init ();
grub_gfxterm_init ();
grub_at_keyboard_init ();
}

View file

@ -35,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;
@ -206,7 +206,6 @@ grub_vprintf (const char *fmt, va_list args)
int ret;
ret = grub_vsnprintf_real (0, 0, fmt, args);
grub_refresh ();
return ret;
}
@ -876,9 +875,6 @@ grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt, va_list ar
if (str)
*str = '\0';
if (count && !str)
grub_refresh ();
return count;
}
@ -975,6 +971,10 @@ grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize,
{
/* invalid */
code = '?';
/* Character c may be valid, don't eat it. */
src--;
if (srcsize != (grub_size_t)-1)
srcsize++;
count = 0;
}
else
@ -1058,7 +1058,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)
/* Some gcc versions generate a call to this function
in trampolines for nested functions. */
void __enable_execute_stack (void *addr __attribute__ ((unused)))
@ -1066,3 +1066,12 @@ 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

@ -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,35 +230,33 @@ grub_parser_split_cmdline (const char *cmdline, grub_reader_getline_t getline,
return 0;
}
struct grub_handler_class grub_parser_class =
{
.name = "parser"
};
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)
{

View file

@ -17,40 +17,44 @@
*/
#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;
grub_partition_map_t grub_partition_map_list;
void
grub_partition_map_register (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)
{
partmap->next = grub_partition_map_list;
grub_partition_map_list = partmap;
}
grub_partition_t p = 0;
void
grub_partition_map_unregister (grub_partition_map_t partmap)
{
grub_partition_map_t *p, q;
auto int find_func (grub_disk_t d, const grub_partition_t partition);
for (p = &grub_partition_map_list, q = *p; q; p = &(q->next), q = q->next)
if (q == partmap)
{
*p = q->next;
break;
}
}
int find_func (grub_disk_t d __attribute__ ((unused)),
const grub_partition_t partition)
{
if (partnum == partition->number)
{
p = (grub_partition_t) grub_malloc (sizeof (*p));
if (! p)
return 1;
int
grub_partition_map_iterate (int (*hook) (const grub_partition_map_t partmap))
{
grub_partition_map_t p;
grub_memcpy (p, partition, sizeof (*p));
return 1;
}
for (p = grub_partition_map_list; p; p = p->next)
if (hook (p))
return 1;
return 0;
}
partmap->iterate (disk, find_func);
if (grub_errno)
goto fail;
return p;
fail:
grub_free (p);
return 0;
}
@ -58,28 +62,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 +130,51 @@ 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;
}
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_errno != GRUB_ERR_NONE)
struct grub_partition p = *partition;
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 +182,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

@ -24,7 +24,7 @@
.globl _start
_start:
ba codestart
nop
mov %o4, %o0
. = EXT_C(_start) + GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE
@ -53,12 +53,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 +83,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/boot.h>
#include <grub/machine/console.h>
#include <grub/machine/kernel.h>
#include <grub/machine/time.h>
#include <grub/ieee1275/ofdisk.h>
#include <grub/ieee1275/ieee1275.h>
grub_addr_t grub_ieee1275_original_stack;
void
grub_exit (void)
{
@ -104,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

View file

@ -57,16 +57,17 @@ grub_putchar (int c)
{
static grub_size_t size = 0;
static grub_uint8_t buf[6];
grub_uint8_t *rest;
grub_uint32_t code;
grub_size_t ret;
buf[size++] = c;
ret = grub_utf8_to_ucs4 (&code, 1, buf, size, 0);
if (ret != 0)
while (grub_utf8_to_ucs4 (&code, 1, buf, size, (const grub_uint8_t **) &rest)
!= 0)
{
struct grub_term_output *term;
size = 0;
size -= rest - buf;
grub_memmove (buf, rest, size);
FOR_ACTIVE_TERM_OUTPUTS(term)
grub_putcode (code, term);
if (code == '\n' && grub_newline_hook)
@ -79,6 +80,8 @@ grub_getkey (void)
{
grub_term_input_t term;
grub_refresh ();
while (1)
{
FOR_ACTIVE_TERM_INPUTS(term)