merge mainline and various cleanups

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2011-05-17 14:02:18 +02:00
commit 3666d5f636
380 changed files with 14873 additions and 1961 deletions

View file

@ -37,6 +37,10 @@
#define GRUB_MODULES_MACHINE_READONLY
#endif
#ifdef GRUB_MACHINE_EMU
#include <sys/mman.h>
#endif
grub_dl_t grub_dl_head = 0;
@ -86,6 +90,7 @@ struct grub_symbol
struct grub_symbol *next;
const char *name;
void *addr;
int isfunc;
grub_dl_t mod; /* The module to which this symbol belongs. */
};
typedef struct grub_symbol *grub_symbol_t;
@ -110,21 +115,22 @@ grub_symbol_hash (const char *s)
/* Resolve the symbol name NAME and return the address.
Return NULL, if not found. */
static void *
static grub_symbol_t
grub_dl_resolve_symbol (const char *name)
{
grub_symbol_t sym;
for (sym = grub_symtab[grub_symbol_hash (name)]; sym; sym = sym->next)
if (grub_strcmp (sym->name, name) == 0)
return sym->addr;
return sym;
return 0;
}
/* Register a symbol with the name NAME and the address ADDR. */
grub_err_t
grub_dl_register_symbol (const char *name, void *addr, grub_dl_t mod)
grub_dl_register_symbol (const char *name, void *addr, int isfunc,
grub_dl_t mod)
{
grub_symbol_t sym;
unsigned k;
@ -147,6 +153,7 @@ grub_dl_register_symbol (const char *name, void *addr, grub_dl_t mod)
sym->addr = addr;
sym->mod = mod;
sym->isfunc = isfunc;
k = grub_symbol_hash (name);
sym->next = grub_symtab[k];
@ -225,6 +232,48 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
{
unsigned i;
Elf_Shdr *s;
grub_size_t tsize = 0, talign = 1;
#ifdef __ia64__
grub_size_t tramp;
grub_size_t got;
#endif
char *ptr;
for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize))
{
tsize += ALIGN_UP (s->sh_size, s->sh_addralign);
if (talign < s->sh_addralign)
talign = s->sh_addralign;
}
#ifdef __ia64__
grub_arch_dl_get_tramp_got_size (e, &tramp, &got);
tramp *= GRUB_IA64_DL_TRAMP_SIZE;
got *= sizeof (grub_uint64_t);
tsize += ALIGN_UP (tramp, GRUB_ARCH_DL_TRAMP_ALIGN);
if (talign < GRUB_ARCH_DL_TRAMP_ALIGN)
talign = GRUB_ARCH_DL_TRAMP_ALIGN;
tsize += ALIGN_UP (got, GRUB_ARCH_DL_GOT_ALIGN);
if (talign < GRUB_ARCH_DL_GOT_ALIGN)
talign = GRUB_ARCH_DL_GOT_ALIGN;
#endif
#ifdef GRUB_MACHINE_EMU
if (talign < 8192 * 16)
talign = 8192 * 16;
tsize = ALIGN_UP (tsize, 8192 * 16);
#endif
mod->base = grub_memalign (talign, tsize);
if (!mod->base)
return grub_errno;
ptr = mod->base;
#ifdef GRUB_MACHINE_EMU
mprotect (mod->base, tsize, PROT_READ | PROT_WRITE | PROT_EXEC);
#endif
for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff);
i < e->e_shnum;
@ -242,12 +291,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
{
void *addr;
addr = grub_memalign (s->sh_addralign, s->sh_size);
if (! addr)
{
grub_free (seg);
return grub_errno;
}
ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, s->sh_addralign);
addr = ptr;
ptr += s->sh_size;
switch (s->sh_type)
{
@ -270,6 +316,14 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
mod->segment = seg;
}
}
#ifdef __ia64__
ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN);
mod->tramp = ptr;
ptr += tramp;
ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_GOT_ALIGN);
mod->got = ptr;
ptr += got;
#endif
return GRUB_ERR_NONE;
}
@ -320,17 +374,20 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
/* 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)
grub_symbol_t nsym = grub_dl_resolve_symbol (name);
if (! nsym)
return grub_error (GRUB_ERR_BAD_MODULE,
"symbol not found: `%s'", name);
sym->st_value = (Elf_Addr) nsym->addr;
if (nsym->isfunc)
sym->st_info = ELF_ST_INFO (bind, STT_FUNC);
}
else
{
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))
if (grub_dl_register_symbol (name, (void *) sym->st_value, 0, mod))
return grub_errno;
}
break;
@ -338,10 +395,21 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
case STT_FUNC:
sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod,
sym->st_shndx);
#ifdef __ia64__
{
/* FIXME: free descriptor once it's not used anymore. */
char **desc;
desc = grub_malloc (2 * sizeof (char *));
if (!desc)
return grub_errno;
desc[0] = (void *) sym->st_value;
desc[1] = mod->base;
sym->st_value = (grub_addr_t) desc;
}
#endif
if (bind != STB_LOCAL)
if (grub_dl_register_symbol (name, (void *) sym->st_value, mod))
if (grub_dl_register_symbol (name, (void *) sym->st_value, 1, mod))
return grub_errno;
if (grub_strcmp (name, "grub_mod_init") == 0)
mod->init = (void (*) (grub_dl_t)) sym->st_value;
else if (grub_strcmp (name, "grub_mod_fini") == 0)
@ -373,6 +441,38 @@ grub_dl_call_init (grub_dl_t mod)
(mod->init) (mod);
}
/* Me, Vladimir Serbinenko, hereby I add this module check as per new
GNU module policy. Note that this license check is informative only.
Modules have to be licensed under GPLv3 or GPLv3+ (optionally
multi-licensed under other licences as well) independently of the
presence of this check and solely by linking (module loading in GRUB
constitutes linking) and GRUB core being licensed under GPLv3+.
Be sure to understand your license obligations.
*/
static grub_err_t
grub_dl_check_license (Elf_Ehdr *e)
{
Elf_Shdr *s;
const char *str;
unsigned i;
s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
str = (char *) e + s->sh_offset;
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
if (grub_strcmp (str + s->sh_name, ".module_license") == 0)
{
if (grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv3") == 0
|| grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv3+") == 0
|| grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv2+") == 0)
return GRUB_ERR_NONE;
}
return grub_error (GRUB_ERR_BAD_MODULE, "incompatible license");
}
static grub_err_t
grub_dl_resolve_name (grub_dl_t mod, Elf_Ehdr *e)
{
@ -519,7 +619,16 @@ grub_dl_load_core (void *addr, grub_size_t size)
mod->ref_count = 1;
grub_dprintf ("modules", "relocating to %p\n", mod);
if (grub_dl_resolve_name (mod, e)
/* Me, Vladimir Serbinenko, hereby I add this module check as per new
GNU module policy. Note that this license check is informative only.
Modules have to be licensed under GPLv3 or GPLv3+ (optionally
multi-licensed under other licences as well) independently of the
presence of this check and solely by linking (module loading in GRUB
constitutes linking) and GRUB core being licensed under GPLv3+.
Be sure to understand your license obligations.
*/
if (grub_dl_check_license (e)
|| grub_dl_resolve_name (mod, e)
|| grub_dl_resolve_dependencies (mod, e)
|| grub_dl_load_segments (mod, e)
|| grub_dl_resolve_symbols (mod, e)
@ -585,7 +694,7 @@ grub_dl_load_file (const char *filename)
return 0;
}
mod->ref_count = 0;
mod->ref_count--;
return mod;
}
@ -642,8 +751,7 @@ grub_dl_unload (grub_dl_t mod)
{
depn = dep->next;
if (! grub_dl_unref (dep->mod))
grub_dl_unload (dep->mod);
grub_dl_unload (dep->mod);
grub_free (dep);
}

View file

@ -24,6 +24,7 @@
#include <grub/efi/console_control.h>
#include <grub/efi/pe32.h>
#include <grub/machine/time.h>
#include <grub/time.h>
#include <grub/term.h>
#include <grub/kernel.h>
#include <grub/mm.h>
@ -193,8 +194,8 @@ grub_efi_set_virtual_address_map (grub_efi_uintn_t memory_map_size,
return grub_error (GRUB_ERR_IO, "set_virtual_address_map failed");
}
grub_uint32_t
grub_get_rtc (void)
grub_uint64_t
grub_rtc_get_time_ms (void)
{
grub_efi_time_t time;
grub_efi_runtime_services_t *r;
@ -204,9 +205,14 @@ grub_get_rtc (void)
/* What is possible in this case? */
return 0;
return (((time.minute * 60 + time.second) * 1000
+ time.nanosecond / 1000000)
* GRUB_TICKS_PER_SECOND / 1000);
return ((time.minute * 60 + time.second) * 1000
+ time.nanosecond / 1000000);
}
grub_uint32_t
grub_get_rtc (void)
{
return grub_rtc_get_time_ms ();
}
/* Search the mods section from the PE32/PE32+ image. This code uses

View file

@ -23,6 +23,9 @@
#include <grub/file.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/dl.h>
GRUB_MOD_LICENSE ("GPLv3+");
/* Check if EHDR is a valid ELF header. */
static grub_err_t

View file

@ -0,0 +1,13 @@
#if defined(__ia64__)
#include <grub/cache.h>
void __clear_cache (char *beg, char *end);
void
grub_arch_sync_caches (void *address, grub_size_t len)
{
__clear_cache (address, (char *) address + len);
}
#endif

View file

@ -23,6 +23,7 @@ FUNCTION (grub_arch_sync_caches)
.set macro
#elif defined(__powerpc__)
#include "../powerpc/cache.S"
#elif defined(__ia64__)
#else
#error "No target cpu type is defined"
#endif

View file

@ -50,6 +50,15 @@ grub_emu_init (void)
grub_no_autoload = 1;
}
#ifdef __ia64__
void grub_arch_dl_get_tramp_got_size (const void *ehdr __attribute__ ((unused)),
grub_size_t *tramp, grub_size_t *got)
{
*tramp = 0;
*got = 0;
}
#endif
#ifdef GRUB_LINKER_HAVE_INIT
void
grub_arch_dl_init_linker (void)

View file

@ -17,7 +17,9 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config-util.h>
#include <config.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
@ -96,6 +98,14 @@ xgetcwd (void)
#ifdef __linux__
struct mountinfo_entry
{
int id;
int major, minor;
char enc_root[PATH_MAX], enc_path[PATH_MAX];
char fstype[PATH_MAX], device[PATH_MAX];
};
/* 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
@ -103,75 +113,120 @@ xgetcwd (void)
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)
char *
grub_find_root_device_from_mountinfo (const char *dir, char **relroot)
{
FILE *fp;
char *buf = NULL;
size_t len = 0;
char *ret = NULL;
int entry_len = 0, entry_max = 4;
struct mountinfo_entry *entries;
struct mountinfo_entry parent_entry = { 0, 0, 0, "", "", "", "" };
int i;
if (! *dir)
dir = "/";
if (relroot)
*relroot = NULL;
fp = fopen ("/proc/self/mountinfo", "r");
if (! fp)
return NULL; /* fall through to other methods */
entries = xmalloc (entry_max * sizeof (*entries));
/* First, build a list of relevant visible mounts. */
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];
struct mountinfo_entry entry;
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)
&entry.id, &parent_entry.id, &entry.major, &entry.minor,
entry.enc_root, entry.enc_path, &count) < 6)
continue;
if (strcmp (enc_root, "/") != 0)
continue; /* only a subtree is mounted */
enc_path_len = strlen (enc_path);
enc_path_len = strlen (entry.enc_path);
/* Check that enc_path is a prefix of dir. The prefix must either be
the entire string, or end with a slash, or be immediately followed
by a slash. */
if (strncmp (dir, enc_path, enc_path_len) != 0 ||
if (strncmp (dir, entry.enc_path, enc_path_len) != 0 ||
(enc_path_len && dir[enc_path_len - 1] != '/' &&
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)
if (sscanf (sep, "%s %s", entry.fstype, entry.device) != 2)
continue;
if (stat (device, &st) < 0)
/* Using the mount IDs, find out where this fits in the list of
visible mount entries we've seen so far. There are three
interesting cases. Firstly, it may be inserted at the end: this is
the usual case of /foo/bar being mounted after /foo. Secondly, it
may be inserted at the start: for example, this can happen for
filesystems that are mounted before / and later moved under it.
Thirdly, it may occlude part or all of the existing filesystem
tree, in which case the end of the list needs to be pruned and this
new entry will be inserted at the end. */
if (entry_len >= entry_max)
{
entry_max <<= 1;
entries = xrealloc (entries, entry_max * sizeof (*entries));
}
if (!entry_len)
{
/* Initialise list. */
entry_len = 2;
entries[0] = parent_entry;
entries[1] = entry;
}
else
{
for (i = entry_len - 1; i >= 0; i--)
{
if (entries[i].id == parent_entry.id)
{
/* Insert at end, pruning anything previously above this. */
entry_len = i + 2;
entries[i + 1] = entry;
break;
}
else if (i == 0 && entries[i].id == entry.id)
{
/* Insert at start. */
entry_len++;
memmove (entries + 1, entries,
(entry_len - 1) * sizeof (*entries));
entries[0] = parent_entry;
entries[1] = entry;
break;
}
}
}
}
/* Now scan visible mounts for the ones we're interested in. */
for (i = entry_len - 1; i >= 0; i--)
{
if (!*entries[i].device)
continue;
if (!S_ISBLK (st.st_mode))
continue; /* not a block device */
ret = strdup (device);
ret = strdup (entries[i].device);
if (relroot)
*relroot = strdup (entries[i].enc_root);
break;
}
free (buf);
free (entries);
fclose (fp);
return ret;
}
@ -182,7 +237,7 @@ find_root_device_from_mountinfo (const char *dir)
static char *
find_root_device_from_libzfs (const char *dir)
{
char *device;
char *device = NULL;
char *poolname;
char *poolfs;
@ -223,7 +278,10 @@ find_root_device_from_libzfs (const char *dir)
struct stat st;
if (stat (device, &st) == 0)
break;
{
device = xstrdup (device);
break;
}
device = NULL;
}
@ -474,7 +532,7 @@ grub_find_device (const char *path, dev_t dev)
char *
grub_guess_root_device (const char *dir)
{
char *os_dev;
char *os_dev = NULL;
#ifdef __GNU__
file_t file;
mach_port_t *ports;
@ -533,30 +591,42 @@ grub_guess_root_device (const char *dir)
mach_port_deallocate (mach_task_self (), file);
#else /* !__GNU__ */
struct stat st;
dev_t dev;
#ifdef __linux__
os_dev = find_root_device_from_mountinfo (dir);
if (os_dev)
return os_dev;
if (!os_dev)
os_dev = grub_find_root_device_from_mountinfo (dir, NULL);
#endif /* __linux__ */
#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
os_dev = find_root_device_from_libzfs (dir);
if (os_dev)
return os_dev;
if (!os_dev)
os_dev = find_root_device_from_libzfs (dir);
#endif
if (stat (dir, &st) < 0)
grub_util_error ("cannot stat `%s'", dir);
if (os_dev)
{
if (stat (os_dev, &st) >= 0)
dev = st.st_rdev;
else
grub_util_error ("cannot stat `%s'", os_dev);
free (os_dev);
}
else
{
if (stat (dir, &st) >= 0)
dev = st.st_dev;
else
grub_util_error ("cannot stat `%s'", dir);
}
#ifdef __CYGWIN__
/* Cygwin specific function. */
os_dev = grub_find_device (dir, st.st_dev);
os_dev = grub_find_device (dir, dev);
#else
/* This might be truly slow, but is there any better way? */
os_dev = grub_find_device ("/dev", st.st_dev);
os_dev = grub_find_device ("/dev", dev);
#endif
#endif /* !__GNU__ */
@ -617,7 +687,7 @@ grub_util_get_dev_abstraction (const char *os_dev __attribute__((unused)))
#ifdef __linux__
static char *
get_mdadm_name (const char *os_dev)
get_mdadm_uuid (const char *os_dev)
{
int mdadm_pipe[2];
pid_t mdadm_pid;
@ -669,19 +739,21 @@ get_mdadm_name (const char *os_dev)
while (getline (&buf, &len, mdadm) > 0)
{
if (strncmp (buf, "MD_NAME=", sizeof ("MD_NAME=") - 1) == 0)
if (strncmp (buf, "MD_UUID=", sizeof ("MD_UUID=") - 1) == 0)
{
char *name_start, *colon;
char *name_start, *ptri, *ptro;
size_t name_len;
free (name);
name_start = buf + sizeof ("MD_NAME=") - 1;
/* Strip off the homehost if present. */
colon = strchr (name_start, ':');
name = strdup (colon ? colon + 1 : name_start);
name_len = strlen (name);
if (name[name_len - 1] == '\n')
name[name_len - 1] = '\0';
name_start = buf + sizeof ("MD_UUID=") - 1;
ptro = name = xmalloc (strlen (name_start) + 1);
for (ptri = name_start; *ptri && *ptri != '\n' && *ptri != '\r';
ptri++)
if ((*ptri >= '0' && *ptri <= '9')
|| (*ptri >= 'a' && *ptri <= 'f')
|| (*ptri >= 'A' && *ptri <= 'F'))
*ptro++ = *ptri;
*ptro = 0;
}
}
@ -797,19 +869,26 @@ grub_util_get_grub_dev (const char *os_dev)
#ifdef __linux__
{
char *mdadm_name = get_mdadm_name (os_dev);
char *mdadm_name = get_mdadm_uuid (os_dev);
struct stat st;
if (mdadm_name)
{
char *newname;
newname = xasprintf ("/dev/md/%s", mdadm_name);
if (stat (newname, &st) == 0)
const char *q;
for (q = os_dev + strlen (os_dev) - 1; q >= os_dev
&& grub_isdigit (*q); q--);
if (q >= os_dev && *q == 'p')
{
free (grub_dev);
grub_dev = xasprintf ("md/%s", mdadm_name);
grub_dev = xasprintf ("mduuid/%s,%s", mdadm_name, q + 1);
goto done;
}
free (newname);
free (grub_dev);
grub_dev = xasprintf ("mduuid/%s", mdadm_name);
done:
free (mdadm_name);
}
}

View file

@ -92,6 +92,8 @@ struct hd_geometry
# include <sys/disk.h> /* DIOCGMEDIASIZE */
# include <sys/param.h>
# include <sys/sysctl.h>
# define MAJOR(dev) major(dev)
# define FLOPPY_MAJOR 2
#endif
#if defined(__APPLE__)
@ -102,7 +104,9 @@ struct hd_geometry
# include <libdevmapper.h>
#endif
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#include <libgeom.h>
#elif defined(__NetBSD__)
# define HAVE_DIOCGDINFO
# include <sys/ioctl.h>
# include <sys/disklabel.h> /* struct disklabel */
@ -134,6 +138,7 @@ struct grub_util_biosdisk_data
char *dev;
int access_mode;
int fd;
int is_disk;
};
#ifdef __linux__
@ -235,6 +240,7 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk)
data->dev = NULL;
data->access_mode = 0;
data->fd = -1;
data->is_disk = 0;
/* Get the size. */
#if defined(__MINGW32__)
@ -275,6 +281,7 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk)
close (fd);
goto fail;
}
data->is_disk = 1;
# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
if (ioctl (fd, DIOCGMEDIASIZE, &nr))
@ -337,7 +344,68 @@ device_is_mapped (const char *dev)
}
#endif /* HAVE_DEVICE_MAPPER */
#if defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO)
#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
/* FIXME: geom actually gives us the whole container hierarchy.
It can be used more efficiently than this. */
static void
follow_geom_up (const char *name, grub_disk_addr_t *off_out, char **name_out)
{
struct gmesh mesh;
struct gclass *class;
int error;
struct ggeom *geom;
grub_util_info ("following geom '%s'", name);
error = geom_gettree (&mesh);
if (error != 0)
grub_util_error ("couldn't open geom");
LIST_FOREACH (class, &mesh.lg_class, lg_class)
if (strcasecmp (class->lg_name, "part") == 0)
break;
if (!class)
grub_util_error ("couldn't open geom part");
LIST_FOREACH (geom, &class->lg_geom, lg_geom)
{
struct gprovider *provider;
LIST_FOREACH (provider, &geom->lg_provider, lg_provider)
if (strcmp (provider->lg_name, name) == 0)
{
char *name_tmp = xstrdup (geom->lg_name);
grub_disk_addr_t off = 0;
struct gconfig *config;
grub_util_info ("geom '%s' has parent '%s'", name, geom->lg_name);
follow_geom_up (name_tmp, &off, name_out);
free (name_tmp);
LIST_FOREACH (config, &provider->lg_config, lg_config)
if (strcasecmp (config->lg_name, "start") == 0)
off += strtoull (config->lg_val, 0, 10);
if (off_out)
*off_out = off;
return;
}
}
grub_util_info ("geom '%s' has no parent", name);
if (name_out)
*name_out = xstrdup (name);
if (off_out)
*off_out = 0;
}
static grub_disk_addr_t
find_partition_start (const char *dev)
{
grub_disk_addr_t out;
if (strncmp (dev, "/dev/", sizeof ("/dev/") - 1) != 0)
return 0;
follow_geom_up (dev + sizeof ("/dev/") - 1, &out, NULL);
return out;
}
#elif defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO)
static grub_disk_addr_t
find_partition_start (const char *dev)
{
@ -453,9 +521,12 @@ devmapper_fail:
# if !defined(HAVE_DIOCGDINFO)
return hdg.start;
# else /* defined(HAVE_DIOCGDINFO) */
p_index = dev[strlen(dev) - 1] - 'a';
if (p_index >= label.d_npartitions)
if (dev[0])
p_index = dev[strlen(dev) - 1] - 'a';
else
p_index = -1;
if (p_index >= label.d_npartitions || p_index < 0)
{
grub_error (GRUB_ERR_BAD_DEVICE,
"no disk label entry for `%s'", dev);
@ -479,7 +550,7 @@ struct linux_partition_cache
struct linux_partition_cache *linux_partition_cache_list;
static int
linux_find_partition (char *dev, unsigned long sector)
linux_find_partition (char *dev, grub_disk_addr_t sector)
{
size_t len = strlen (dev);
const char *format;
@ -525,7 +596,7 @@ linux_find_partition (char *dev, unsigned long sector)
fd = open (real_dev, O_RDONLY);
if (fd == -1)
return 0;
continue;
close (fd);
start = find_partition_start (real_dev);
@ -596,7 +667,19 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
{
free (data->dev);
if (data->fd != -1)
close (data->fd);
{
if (data->access_mode == O_RDWR || data->access_mode == O_WRONLY)
{
fsync (data->fd);
#ifdef __linux__
if (data->is_disk)
ioctl (data->fd, BLKFLSBUF, 0);
#endif
}
close (data->fd);
data->fd = -1;
}
/* Open the partition. */
grub_dprintf ("hostdisk", "opening the device `%s' in open_device()\n", dev);
@ -607,10 +690,6 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
return -1;
}
/* Flush the buffer cache to the physical disk.
XXX: This also empties the buffer cache. */
ioctl (fd, BLKFLSBUF, 0);
data->dev = xstrdup (dev);
data->access_mode = (flags & O_ACCMODE);
data->fd = fd;
@ -648,7 +727,18 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
{
free (data->dev);
if (data->fd != -1)
close (data->fd);
{
if (data->access_mode == O_RDWR || data->access_mode == O_WRONLY)
{
fsync (data->fd);
#ifdef __linux__
if (data->is_disk)
ioctl (data->fd, BLKFLSBUF, 0);
#endif
}
close (data->fd);
data->fd = -1;
}
fd = open (map[disk->id].device, flags);
if (fd >= 0)
@ -808,7 +898,6 @@ grub_util_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
if (nread (fd, buf, GRUB_DISK_SECTOR_SIZE) != GRUB_DISK_SECTOR_SIZE)
{
grub_error (GRUB_ERR_READ_ERROR, "cannot read `%s'", map[disk->id].device);
close (fd);
return grub_errno;
}
@ -858,6 +947,27 @@ grub_util_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector,
return grub_errno;
}
grub_err_t
grub_util_biosdisk_flush (struct grub_disk *disk)
{
struct grub_util_biosdisk_data *data = disk->data;
if (disk->dev->id != GRUB_DISK_DEVICE_BIOSDISK_ID)
return GRUB_ERR_NONE;
if (data->fd == -1)
{
data->fd = open_device (disk, 0, O_RDONLY);
if (data->fd < 0)
return grub_errno;
}
fsync (data->fd);
#ifdef __linux__
if (data->is_disk)
ioctl (data->fd, BLKFLSBUF, 0);
#endif
return GRUB_ERR_NONE;
}
static void
grub_util_biosdisk_close (struct grub_disk *disk)
{
@ -865,7 +975,11 @@ grub_util_biosdisk_close (struct grub_disk *disk)
free (data->dev);
if (data->fd != -1)
close (data->fd);
{
if (data->access_mode == O_RDWR || data->access_mode == O_WRONLY)
grub_util_biosdisk_flush (disk);
close (data->fd);
}
free (data);
}
@ -1284,7 +1398,17 @@ devmapper_out:
path[8] = 0;
return path;
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
char *out, *out2;
if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
return xstrdup (os_dev);
follow_geom_up (os_dev + sizeof ("/dev/") - 1, NULL, &out);
out2 = xasprintf ("/dev/%s", out);
free (out);
return out2;
#elif defined(__APPLE__)
char *path = xstrdup (os_dev);
if (strncmp ("/dev/", path, 5) == 0)
{
@ -1440,6 +1564,7 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
if (stat (os_dev, &st) < 0)
{
grub_error (GRUB_ERR_BAD_DEVICE, "cannot stat `%s'", os_dev);
grub_util_info ("cannot stat `%s'", os_dev);
return 0;
}
@ -1448,6 +1573,7 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
{
grub_error (GRUB_ERR_UNKNOWN_DEVICE,
"no mapping exists for `%s'", os_dev);
grub_util_info ("no mapping exists for `%s'", os_dev);
return 0;
}
@ -1462,7 +1588,8 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
#endif
return make_device_name (drive, -1, -1);
#if defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO)
#if defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
/* Linux counts partitions uniformly, whether a BSD partition or a DOS
partition, so mapping them to GRUB devices is not trivial.
Here, get the start sector of a partition by HDIO_GETGEO, and

View file

@ -15,6 +15,8 @@
#include "../mips/dl.c"
#elif defined(__powerpc__)
#include "../powerpc/dl.c"
#elif defined(__ia64__)
#include "../ia64/dl.c"
#else
#error "No target cpu type is defined"
#endif

View file

@ -415,6 +415,18 @@ grub_make_system_path_relative_to_its_root (const char *path)
if (offset == 0)
{
free (buf);
#ifdef __linux__
{
char *bind;
grub_free (grub_find_root_device_from_mountinfo (buf2, &bind));
if (bind && bind[0] && bind[1])
{
buf3 = bind;
goto parsedir;
}
grub_free (bind);
}
#endif
free (buf2);
#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
if (poolfs)
@ -437,6 +449,21 @@ grub_make_system_path_relative_to_its_root (const char *path)
}
free (buf);
buf3 = xstrdup (buf2 + offset);
buf2[offset] = 0;
#ifdef __linux__
{
char *bind;
grub_free (grub_find_root_device_from_mountinfo (buf2, &bind));
if (bind && bind[0] && bind[1])
{
char *temp = buf3;
buf3 = grub_xasprintf ("%s%s%s", bind, buf3[0] == '/' ?"":"/", buf3);
grub_free (temp);
}
grub_free (bind);
}
#endif
free (buf2);
#ifdef __CYGWIN__
@ -452,6 +479,7 @@ grub_make_system_path_relative_to_its_root (const char *path)
}
#endif
parsedir:
/* Remove trailing slashes, return empty string if root directory. */
len = strlen (buf3);
while (len > 0 && buf3[len - 1] == '/')

View file

@ -68,7 +68,7 @@ grub_file_open (const char *name)
goto fail;
/* Get the file part of NAME. */
file_name = grub_strchr (name, ')');
file_name = (name[0] == '(') ? grub_strchr (name, ')') : NULL;
if (file_name)
file_name++;
else

276
grub-core/kern/ia64/dl.c Normal file
View file

@ -0,0 +1,276 @@
/* dl.c - arch-dependent part of loadable module support */
/*
* GRUB -- GRand Unified Bootloader
* 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
* 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/mm.h>
/* 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. */
if (e->e_ident[EI_CLASS] != ELFCLASS64
|| e->e_ident[EI_DATA] != ELFDATA2LSB
|| e->e_machine != EM_IA_64)
return grub_error (GRUB_ERR_BAD_OS, "invalid arch specific ELF magic");
return GRUB_ERR_NONE;
}
#define MASK20 ((1 << 20) - 1)
#define MASK19 ((1 << 19) - 1)
struct unaligned_uint32
{
grub_uint32_t val;
} __attribute__ ((packed));
static void
add_value_to_slot_20b (grub_addr_t addr, grub_uint32_t value)
{
struct unaligned_uint32 *p;
switch (addr & 3)
{
case 0:
p = (struct unaligned_uint32 *) ((addr & ~3ULL) + 2);
p->val = ((((((p->val >> 2) & MASK20) + value) & MASK20) << 2)
| (p->val & ~(MASK20 << 2)));
break;
case 1:
p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 7);
p->val = ((((((p->val >> 3) & MASK20) + value) & MASK20) << 3)
| (p->val & ~(MASK20 << 3)));
break;
case 2:
p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 12);
p->val = ((((((p->val >> 4) & MASK20) + value) & MASK20) << 4)
| (p->val & ~(MASK20 << 4)));
break;
}
}
#define MASKF21 ( ((1 << 23) - 1) & ~((1 << 7) | (1 << 8)) )
static grub_uint32_t
add_value_to_slot_21_real (grub_uint32_t a, grub_uint32_t value)
{
grub_uint32_t high, mid, low, c;
low = (a & 0x00007f);
mid = (a & 0x7fc000) >> 7;
high = (a & 0x003e00) << 7;
c = (low | mid | high) + value;
return (c & 0x7f) | ((c << 7) & 0x7fc000) | ((c >> 7) & 0x0003e00); //0x003e00
}
static void
add_value_to_slot_21 (grub_addr_t addr, grub_uint32_t value)
{
struct unaligned_uint32 *p;
switch (addr & 3)
{
case 0:
p = (struct unaligned_uint32 *) ((addr & ~3ULL) + 2);
p->val = ((add_value_to_slot_21_real (((p->val >> 2) & MASKF21), value) & MASKF21) << 2) | (p->val & ~(MASKF21 << 2));
break;
case 1:
p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 7);
p->val = ((add_value_to_slot_21_real (((p->val >> 3) & MASKF21), value) & MASKF21) << 3) | (p->val & ~(MASKF21 << 3));
break;
case 2:
p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 12);
p->val = ((add_value_to_slot_21_real (((p->val >> 4) & MASKF21), value) & MASKF21) << 4) | (p->val & ~(MASKF21 << 4));
break;
}
}
static grub_uint8_t nopm[5] =
{
/* [MLX] nop.m 0x0 */
0x05, 0x00, 0x00, 0x00, 0x01
};
static grub_uint8_t jump[0x20] =
{
/* ld8 r16=[r15],8 */
0x02, 0x80, 0x20, 0x1e, 0x18, 0x14,
/* mov r14=r1;; */
0xe0, 0x00, 0x04, 0x00, 0x42, 0x00,
/* nop.i 0x0 */
0x00, 0x00, 0x04, 0x00,
/* ld8 r1=[r15] */
0x11, 0x08, 0x00, 0x1e, 0x18, 0x10,
/* mov b6=r16 */
0x60, 0x80, 0x04, 0x80, 0x03, 0x00,
/* br.few b6;; */
0x60, 0x00, 0x80, 0x00
};
struct ia64_trampoline
{
/* nop.m */
grub_uint8_t nop[5];
/* movl r15 = addr*/
grub_uint8_t addr_hi[6];
grub_uint8_t e0;
grub_uint8_t addr_lo[4];
grub_uint8_t jump[0x20];
};
static void
make_trampoline (struct ia64_trampoline *tr, grub_uint64_t addr)
{
COMPILE_TIME_ASSERT (sizeof (struct ia64_trampoline)
== GRUB_IA64_DL_TRAMP_SIZE);
grub_memcpy (tr->nop, nopm, sizeof (tr->nop));
tr->addr_hi[0] = ((addr & 0xc00000) >> 16);
tr->addr_hi[1] = (addr >> 24) & 0xff;
tr->addr_hi[2] = (addr >> 32) & 0xff;
tr->addr_hi[3] = (addr >> 40) & 0xff;
tr->addr_hi[4] = (addr >> 48) & 0xff;
tr->addr_hi[5] = (addr >> 56) & 0xff;
tr->e0 = 0xe0;
tr->addr_lo[0] = ((addr & 0x000f) << 4) | 0x01;
tr->addr_lo[1] = (((addr & 0x0070) >> 4) | ((addr & 0x070000) >> 11)
| ((addr & 0x200000) >> 17));
tr->addr_lo[2] = ((addr & 0x1f80) >> 5) | ((addr & 0x180000) >> 19);
tr->addr_lo[3] = ((addr & 0xe000) >> 13) | 0x60;
grub_memcpy (tr->jump, jump, sizeof (tr->jump));
}
/* 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_uint64_t *gp, *gpptr;
struct ia64_trampoline *tr;
gp = (grub_uint64_t *) mod->base;
gpptr = (grub_uint64_t *) mod->got;
tr = mod->tramp;
/* 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;
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_RELA)
{
grub_dl_segment_t seg;
/* Find the target segment. */
for (seg = mod->segment; seg; seg = seg->next)
if (seg->section == s->sh_info)
break;
if (seg)
{
Elf_Rela *rel, *max;
for (rel = (Elf_Rela *) ((char *) e + s->sh_offset),
max = rel + s->sh_size / s->sh_entsize;
rel < max;
rel++)
{
grub_addr_t addr;
Elf_Sym *sym;
grub_uint64_t value;
if (seg->size < (rel->r_offset & ~3))
return grub_error (GRUB_ERR_BAD_MODULE,
"reloc offset is out of the segment");
addr = (grub_addr_t) seg->addr + rel->r_offset;
sym = (Elf_Sym *) ((char *) mod->symtab
+ entsize * ELF_R_SYM (rel->r_info));
/* On the PPC the value does not have an explicit
addend, add it. */
value = sym->st_value + rel->r_addend;
switch (ELF_R_TYPE (rel->r_info))
{
case R_IA64_PCREL21B:
{
grub_uint64_t noff;
make_trampoline (tr, value);
noff = ((char *) tr - (char *) (addr & ~3)) >> 4;
tr++;
if (noff & ~MASK19)
return grub_error (GRUB_ERR_BAD_OS,
"trampoline offset too big (%lx)", noff);
add_value_to_slot_20b (addr, noff);
}
break;
case R_IA64_SEGREL64LSB:
*(grub_uint64_t *) addr += value - (grub_addr_t) seg->addr;
break;
case R_IA64_FPTR64LSB:
case R_IA64_DIR64LSB:
*(grub_uint64_t *) addr += value;
break;
case R_IA64_PCREL64LSB:
*(grub_uint64_t *) addr += value - addr;
break;
case R_IA64_GPREL22:
add_value_to_slot_21 (addr, value - (grub_addr_t) gp);
break;
case R_IA64_LTOFF22X:
case R_IA64_LTOFF22:
if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
value = *(grub_uint64_t *) sym->st_value + rel->r_addend;
case R_IA64_LTOFF_FPTR22:
*gpptr = value;
add_value_to_slot_21 (addr, (grub_addr_t) gpptr - (grub_addr_t) gp);
gpptr++;
break;
/* We treat LTOFF22X as LTOFF22, so we can ignore LDXMOV. */
case R_IA64_LDXMOV:
break;
default:
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"this relocation (0x%x) is not implemented yet",
ELF_R_TYPE (rel->r_info));
}
}
}
}
return GRUB_ERR_NONE;
}

View file

@ -0,0 +1,73 @@
/* dl.c - arch-dependent part of loadable module support */
/*
* GRUB -- GRand Unified Bootloader
* 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
* 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/mm.h>
void
grub_ia64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
grub_size_t *got)
{
const Elf_Ehdr *e = ehdr;
grub_size_t cntt = 0, cntg = 0;;
const Elf_Shdr *s;
Elf_Word entsize;
unsigned i;
/* 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;
entsize = s->sh_entsize;
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
if (s->sh_type == SHT_RELA)
{
Elf_Rela *rel, *max;
for (rel = (Elf_Rela *) ((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_IA64_PCREL21B:
cntt++;
break;
case R_IA64_LTOFF_FPTR22:
case R_IA64_LTOFF22X:
case R_IA64_LTOFF22:
cntg++;
break;
}
}
*tramp = cntt;
*got = cntg;
}

View file

@ -0,0 +1,60 @@
/* init.c - initialize an ia64-based EFI system */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2008 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/types.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/time.h>
#include <grub/err.h>
#include <grub/dl.h>
#include <grub/cache.h>
#include <grub/kernel.h>
#include <grub/efi/efi.h>
void
grub_machine_init (void)
{
grub_efi_init ();
grub_install_get_time_ms (grub_rtc_get_time_ms);
}
void
grub_machine_fini (void)
{
grub_efi_fini ();
}
void
grub_machine_set_prefix (void)
{
grub_efi_set_prefix ();
}
void
grub_arch_sync_caches (void *address, grub_size_t len)
{
/* Cache line length is at least 32. */
grub_uint64_t a = (grub_uint64_t)address & ~0x1f;
/* Flush data. */
for (len = (len + 31) & ~0x1f; len > 0; len -= 0x20, a += 0x20)
asm volatile ("fc.i %0" : : "r" (a));
/* Sync and serialize. Maybe extra. */
asm volatile (";; sync.i;; srlz.i;;");
}

View file

@ -0,0 +1,54 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2008 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <grub/symbol.h>
#include <grub/offsets.h>
.text
.psr abi64
.psr lsb
.lsb
.global _start
.proc _start
_start:
alloc loc0=ar.pfs,2,4,0,0
mov loc1=rp
addl loc2=@gprel(grub_efi_image_handle),gp
addl loc3=@gprel(grub_efi_system_table),gp
;;
st8 [loc2]=in0
st8 [loc3]=in1
br.call.sptk.few rp=grub_main
;;
mov ar.pfs=loc0
mov rp=loc1
;;
br.ret.sptk.few rp
.endp _start
. = _start + GRUB_KERNEL_MACHINE_PREFIX
VARIABLE(grub_prefix)
.byte 0
/* to be filled by grub-mkimage */
/*
* Leave some breathing room for the prefix.
*/
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END

View file

@ -84,6 +84,9 @@ grub_ieee1275_find_options (void)
if (rc >= 0 && !grub_strcmp (tmp, "Emulated PC"))
is_qemu = 1;
if (grub_strncmp (tmp, "PowerMac", sizeof ("PowerMac") - 1) == 0)
grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_BROKEN_ADDRESS_CELLS);
if (is_smartfirmware)
{
/* Broken in all versions */

View file

@ -50,6 +50,12 @@ grub_machine_mmap_iterate (grub_memory_hook_t hook)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
"couldn't examine /memory/available property");
if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_BROKEN_ADDRESS_CELLS))
{
address_cells = 1;
size_cells = 1;
}
/* Decode each entry and call `hook'. */
i = 0;
available_size /= sizeof (grub_uint32_t);

View file

@ -53,8 +53,8 @@ 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)
/* This is actualy platform-independant but used only on loongson and sparc. */
#if defined (GRUB_MACHINE_MIPS_LOONGSON) || defined (GRUB_MACHINE_MIPS_QEMU_MIPS) || defined (GRUB_MACHINE_SPARC64)
grub_addr_t
grub_modules_get_end (void)
{

View file

@ -0,0 +1,203 @@
/*
* 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/arc/console.h>
#include <grub/cpu/memory.h>
#include <grub/cpu/time.h>
#include <grub/memory.h>
#include <grub/term.h>
#include <grub/arc/arc.h>
#include <grub/offsets.h>
const char *type_names[] = {
#ifdef GRUB_CPU_WORDS_BIGENDIAN
NULL,
#endif
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
"eisa", "tc", "scsi", "dti", "multi", "disk", "tape", "cdrom", "worm",
"serial", "net", "video", "par", "point", "key", "audio", "other",
"rdisk", "fdisk", "tape", "modem", "monitor", "print", "pointer",
"keyboard", "term", "other", "line", "network", NULL
};
static int
iterate_rec (const char *prefix, const struct grub_arc_component *parent,
int (*hook) (const char *name,
const struct grub_arc_component *comp),
int alt_names)
{
const struct grub_arc_component *comp;
FOR_ARC_CHILDREN(comp, parent)
{
char *name;
const char *cname = NULL;
if (comp->type < ARRAY_SIZE (type_names))
cname = type_names[comp->type];
if (!cname)
cname = "unknown";
if (alt_names)
name = grub_xasprintf ("%s/%s%lu", prefix, cname, comp->key);
else
name = grub_xasprintf ("%s%s(%lu)", prefix, cname, comp->key);
if (!name)
return 1;
if (hook (name, comp))
{
grub_free (name);
return 1;
}
if (iterate_rec ((parent ? name : prefix), comp, hook, alt_names))
{
grub_free (name);
return 1;
}
grub_free (name);
}
return 0;
}
int
grub_arc_iterate_devs (int (*hook) (const char *name,
const struct grub_arc_component *comp),
int alt_names)
{
return iterate_rec ((alt_names ? "arc" : ""), NULL, hook, alt_names);
}
grub_err_t
grub_machine_mmap_iterate (grub_memory_hook_t hook)
{
struct grub_arc_memory_descriptor *cur = NULL;
while (1)
{
grub_memory_type_t type;
cur = GRUB_ARC_FIRMWARE_VECTOR->getmemorydescriptor (cur);
if (!cur)
return GRUB_ERR_NONE;
switch (cur->type)
{
case GRUB_ARC_MEMORY_EXCEPTION_BLOCK:
case GRUB_ARC_MEMORY_SYSTEM_PARAMETER_BLOCK:
case GRUB_ARC_MEMORY_FW_PERMANENT:
default:
type = GRUB_MEMORY_RESERVED;
break;
case GRUB_ARC_MEMORY_FW_TEMPORARY:
case GRUB_ARC_MEMORY_FREE:
case GRUB_ARC_MEMORY_LOADED:
case GRUB_ARC_MEMORY_FREE_CONTIGUOUS:
type = GRUB_MEMORY_AVAILABLE;
break;
case GRUB_ARC_MEMORY_BADRAM:
type = GRUB_MEMORY_BADRAM;
break;
}
if (hook (((grub_uint64_t) cur->start_page) << 12,
((grub_uint64_t) cur->num_pages) << 12, type))
return GRUB_ERR_NONE;
}
}
void
grub_machine_init (void)
{
struct grub_arc_memory_descriptor *cur = NULL;
grub_console_init_early ();
/* FIXME: measure this. */
grub_arch_cpuclock = 64000000;
grub_install_get_time_ms (grub_rtc_get_time_ms);
while (1)
{
grub_uint64_t start, end;
cur = GRUB_ARC_FIRMWARE_VECTOR->getmemorydescriptor (cur);
if (!cur)
break;
if (cur->type != GRUB_ARC_MEMORY_FREE
&& cur->type != GRUB_ARC_MEMORY_LOADED
&& cur->type != GRUB_ARC_MEMORY_FREE_CONTIGUOUS)
continue;
start = ((grub_uint64_t) cur->start_page) << 12;
end = ((grub_uint64_t) cur->num_pages) << 12;
end += start;
if ((grub_uint64_t) end > (GRUB_KERNEL_MIPS_ARC_LINK_ADDR & 0x1fffffff))
end = (GRUB_KERNEL_MIPS_ARC_LINK_ADDR & 0x1fffffff);
if (end > start)
grub_mm_init_region ((void *) (grub_addr_t) (start | 0x80000000),
end - start);
}
grub_console_init_lately ();
grub_arcdisk_init ();
}
void
grub_machine_fini (void)
{
}
void
grub_halt (void)
{
GRUB_ARC_FIRMWARE_VECTOR->powerdown ();
grub_millisleep (1500);
grub_printf ("Shutdown failed\n");
grub_refresh ();
while (1);
}
void
grub_exit (void)
{
GRUB_ARC_FIRMWARE_VECTOR->exit ();
grub_millisleep (1500);
grub_printf ("Exit failed\n");
grub_refresh ();
while (1);
}
void
grub_reboot (void)
{
GRUB_ARC_FIRMWARE_VECTOR->restart ();
grub_millisleep (1500);
grub_printf ("Reboot failed\n");
grub_refresh ();
while (1);
}

View file

@ -8,3 +8,38 @@ FUNCTION (grub_cpu_flush_cache)
FUNCTION (grub_arch_sync_caches)
#include "cache_flush.S"
j $ra
FUNCTION (grub_arch_sync_dma_caches)
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 $t1, $t1, 0xffff
bne $t1, $zero, 1b
addiu $t0, $t0, 0x1
sync
move $t0, $t2
subu $t1, $t3, $t2
2:
cache 0, 0($t0)
addiu $t1, $t1, 0xffff
bne $t1, $zero, 2b
addiu $t0, $t0, 0x1
sync
move $t0, $t2
subu $t1, $t3, $t2
2:
cache 23, 0($t0)
addiu $t1, $t1, 0xffff
bne $t1, $zero, 2b
addiu $t0, $t0, 0x1
sync
jr $ra

View file

@ -12,16 +12,16 @@
subu $t1, $t3, $t2
1:
cache 1, 0($t0)
addiu $t1, $t1, 0xffff
addiu $t1, $t1, -0x4
bne $t1, $zero, 1b
addiu $t0, $t0, 0x1
addiu $t0, $t0, 0x4
sync
move $t0, $t2
subu $t1, $t3, $t2
2:
cache 0, 0($t0)
addiu $t1, $t1, 0xffff
addiu $t1, $t1, -0x4
bne $t1, $zero, 2b
addiu $t0, $t0, 0x1
addiu $t0, $t0, 0x4
sync
#endif

View file

@ -34,7 +34,7 @@ grub_arch_dl_check_header (void *ehdr)
Elf_Ehdr *e = ehdr;
/* Check the magic numbers. */
#ifdef WORDS_BIGENDIAN
#ifdef GRUB_CPU_WORDS_BIGENDIAN
if (e->e_ident[EI_CLASS] != ELFCLASS32
|| e->e_ident[EI_DATA] != ELFDATA2MSB
|| e->e_machine != EM_MIPS)
@ -144,14 +144,14 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
rel < max;
rel++)
{
Elf_Word *addr;
grub_uint8_t *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);
addr = (grub_uint8_t *) ((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)
@ -163,7 +163,11 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
{
grub_uint32_t value;
Elf_Rel *rel2;
#ifdef GRUB_CPU_WORDS_BIGENDIAN
addr += 2;
#endif
/* Handle partner lo16 relocation. Lower part is
treated as signed. Hence add 0x8000 to compensate.
*/
@ -175,13 +179,20 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
&& ELF_R_TYPE (rel2->r_info) == R_MIPS_LO16)
{
value += *(grub_int16_t *)
((char *) seg->addr + rel2->r_offset);
((char *) seg->addr + rel2->r_offset
#ifdef GRUB_CPU_WORDS_BIGENDIAN
+ 2
#endif
);
break;
}
*(grub_uint16_t *) addr = (value >> 16) & 0xffff;
}
break;
case R_MIPS_LO16:
#ifdef GRUB_CPU_WORDS_BIGENDIAN
addr += 2;
#endif
*(grub_uint16_t *) addr += (sym->st_value) & 0xffff;
break;
case R_MIPS_32:
@ -208,11 +219,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
case R_MIPS_GOT16:
case R_MIPS_CALL16:
/* FIXME: reuse*/
#ifdef GRUB_CPU_WORDS_BIGENDIAN
addr += 2;
#endif
*gpptr = sym->st_value + *(grub_uint16_t *) addr;
*(grub_uint16_t *) addr
= sizeof (grub_uint32_t) * (gpptr - gp);
gpptr++;
break;
case R_MIPS_JALR:
break;
default:
{
grub_free (gp);
@ -232,6 +248,6 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
void
grub_arch_dl_init_linker (void)
{
grub_dl_register_symbol ("__gnu_local_gp", &__gnu_local_gp_dummy, 0);
grub_dl_register_symbol ("__gnu_local_gp", &__gnu_local_gp_dummy, 0, 0);
}

View file

@ -18,6 +18,24 @@
#include <grub/kernel.h>
#include <grub/env.h>
#include <grub/cpu/time.h>
#include <grub/cpu/mips.h>
/* 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_MIPS_COP0_TIMER_COUNT : "=r" (low));
if (low < last)
high++;
last = low;
return (((grub_uint64_t) high) << 32) | low;
}
void
grub_machine_set_prefix (void)

View file

@ -31,8 +31,10 @@
#include <grub/cs5536.h>
#include <grub/term.h>
#include <grub/machine/ec.h>
#include <grub/cpu/memory.h>
extern void grub_video_sm712_init (void);
extern void grub_video_sis315pro_init (void);
extern void grub_video_init (void);
extern void grub_bitmap_init (void);
extern void grub_font_init (void);
@ -41,22 +43,7 @@ extern void grub_at_keyboard_init (void);
extern void grub_serial_init (void);
extern void grub_terminfo_init (void);
extern void grub_keylayouts_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;
}
extern void grub_boot_init (void);
grub_err_t
grub_machine_mmap_iterate (grub_memory_hook_t hook)
@ -78,7 +65,7 @@ init_pci (void)
/* FIXME: autoscan for BARs and devices. */
switch (pciid)
{
case GRUB_YEELOONG_OHCI_PCIID:
case GRUB_LOONGSON_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);
@ -90,7 +77,7 @@ init_pci (void)
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:
case GRUB_LOONGSON_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);
@ -162,7 +149,7 @@ grub_machine_init (void)
if (err)
grub_fatal ("Couldn't init SMBus: %s\n", grub_errmsg);
/* Yeeloong has only one memory slot. */
/* Yeeloong and Fuloong have 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);
@ -201,15 +188,19 @@ grub_machine_init (void)
relies on a working heap. */
grub_video_init ();
grub_video_sm712_init ();
grub_video_sis315pro_init ();
grub_bitmap_init ();
grub_font_init ();
grub_gfxterm_init ();
grub_keylayouts_init ();
grub_at_keyboard_init ();
if (grub_arch_machine == GRUB_ARCH_MACHINE_YEELOONG)
grub_at_keyboard_init ();
grub_terminfo_init ();
grub_serial_init ();
grub_boot_init ();
}
void
@ -220,10 +211,28 @@ 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_millisleep (1500);
switch (grub_arch_machine)
{
case GRUB_ARCH_MACHINE_FULOONG:
{
grub_pci_device_t dev;
grub_port_t p;
if (grub_cs5536_find (&dev))
{
p = (grub_cs5536_read_msr (dev, GRUB_CS5536_MSR_GPIO_BAR)
& GRUB_CS5536_LBAR_ADDR_MASK) + GRUB_MACHINE_PCI_IO_BASE;
grub_outl ((1 << 13), p + 4);
grub_outl ((1 << 29), p);
grub_millisleep (5000);
}
}
break;
case GRUB_ARCH_MACHINE_YEELOONG:
grub_outb (grub_inb (GRUB_CPU_LOONGSON_GPIOCFG)
& ~GRUB_CPU_YEELOONG_SHUTDOWN_GPIO, GRUB_CPU_LOONGSON_GPIOCFG);
grub_millisleep (1500);
break;
}
grub_printf ("Shutdown failed\n");
grub_refresh ();

View file

@ -7,23 +7,30 @@
#include <grub/mm.h>
#include <grub/time.h>
#include <grub/machine/memory.h>
#include <grub/cpu/memory.h>
#include <grub/memory.h>
#define RAMSIZE (*(grub_uint32_t *) ((16 << 20) - 264))
grub_uint32_t
grub_get_rtc (void)
{
static int calln = 0;
return calln++;
}
extern void grub_serial_init (void);
extern void grub_terminfo_init (void);
void
grub_machine_init (void)
{
grub_mm_init_region ((void *) GRUB_MACHINE_MEMORY_USABLE,
RAMSIZE - (GRUB_MACHINE_MEMORY_USABLE & 0x7fffffff));
grub_addr_t modend;
/* FIXME: measure this. */
grub_arch_cpuclock = 64000000;
modend = grub_modules_get_end ();
grub_mm_init_region ((void *) modend, RAMSIZE
- (modend - GRUB_ARCH_LOWMEMVSTART));
grub_install_get_time_ms (grub_rtc_get_time_ms);
grub_terminfo_init ();
grub_serial_init ();
}
void

View file

@ -20,6 +20,7 @@
#include <grub/symbol.h>
#include <grub/offsets.h>
#include <grub/machine/memory.h>
#include <grub/machine/kernel.h>
#include <grub/offsets.h>
#define BASE_ADDR 8
@ -35,7 +36,7 @@ start:
bal cont
nop
. = _start + GRUB_KERNEL_MIPS_YEELOONG_TOTAL_MODULE_SIZE
. = _start + GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE
total_module_size:
.long 0
@ -50,27 +51,30 @@ VARIABLE(grub_prefix)
*/
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END
#ifdef GRUB_MACHINE_MIPS_YEELOONG
VARIABLE (grub_arch_busclock)
.long 0
VARIABLE (grub_arch_cpuclock)
.long 0
#ifdef GRUB_MACHINE_MIPS_LOONGSON
VARIABLE (grub_arch_busclock)
.long 0
VARIABLE (grub_arch_memsize)
.long 0
VARIABLE (grub_arch_highmemsize)
.long 0
VARIABLE (grub_arch_machine)
.long GRUB_ARCH_MACHINE_FULOONG
#endif
cont:
/* Save our base. */
move $s0, $ra
#ifdef GRUB_MACHINE_MIPS_YEELOONG
#ifdef GRUB_MACHINE_MIPS_LOONGSON
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)
sw $s7, 16($t1)
#endif
/* Move the modules out of BSS. */

View file

@ -597,23 +597,23 @@ grub_reverse (char *str)
/* Divide N by D, return the quotient, and store the remainder in *R. */
grub_uint64_t
grub_divmod64 (grub_uint64_t n, grub_uint32_t d, grub_uint32_t *r)
grub_divmod64_full (grub_uint64_t n, grub_uint64_t d, grub_uint64_t *r)
{
/* This algorithm is typically implemented by hardware. The idea
is to get the highest bit in N, 64 times, by keeping
upper(N * 2^i) = upper((Q * 10 + M) * 2^i), where upper
upper(N * 2^i) = (Q * D + M), where upper
represents the high 64 bits in 128-bits space. */
unsigned bits = 64;
unsigned long long q = 0;
unsigned m = 0;
grub_uint64_t q = 0;
grub_uint64_t m = 0;
/* Skip the slow computation if 32-bit arithmetic is possible. */
if (n < 0xffffffff)
if (n < 0xffffffff && d < 0xffffffff)
{
if (r)
*r = ((grub_uint32_t) n) % d;
*r = ((grub_uint32_t) n) % (grub_uint32_t) d;
return ((grub_uint32_t) n) / d;
return ((grub_uint32_t) n) / (grub_uint32_t) d;
}
while (bits--)

View file

@ -311,11 +311,13 @@ grub_memalign (grub_size_t align, grub_size_t size)
count++;
goto again;
#if 0
case 1:
/* Unload unneeded modules. */
grub_dl_unload_unneeded ();
count++;
goto again;
#endif
default:
break;

View file

@ -37,80 +37,80 @@
.text
FUNCTION(efi_wrap_0)
subq $40, %rsp
subq $48, %rsp
call *%rdi
addq $40, %rsp
addq $48, %rsp
ret
FUNCTION(efi_wrap_1)
subq $40, %rsp
subq $48, %rsp
mov %rsi, %rcx
call *%rdi
addq $40, %rsp
addq $48, %rsp
ret
FUNCTION(efi_wrap_2)
subq $40, %rsp
subq $48, %rsp
mov %rsi, %rcx
call *%rdi
addq $40, %rsp
addq $48, %rsp
ret
FUNCTION(efi_wrap_3)
subq $40, %rsp
subq $48, %rsp
mov %rcx, %r8
mov %rsi, %rcx
call *%rdi
addq $40, %rsp
addq $48, %rsp
ret
FUNCTION(efi_wrap_4)
subq $40, %rsp
subq $48, %rsp
mov %r8, %r9
mov %rcx, %r8
mov %rsi, %rcx
call *%rdi
addq $40, %rsp
addq $48, %rsp
ret
FUNCTION(efi_wrap_5)
subq $40, %rsp
subq $48, %rsp
mov %r9, 32(%rsp)
mov %r8, %r9
mov %rcx, %r8
mov %rsi, %rcx
call *%rdi
addq $40, %rsp
addq $48, %rsp
ret
FUNCTION(efi_wrap_6)
subq $56, %rsp
mov 56+8(%rsp), %rax
subq $64, %rsp
mov 64+8(%rsp), %rax
mov %rax, 40(%rsp)
mov %r9, 32(%rsp)
mov %r8, %r9
mov %rcx, %r8
mov %rsi, %rcx
call *%rdi
addq $56, %rsp
addq $64, %rsp
ret
FUNCTION(efi_wrap_10)
subq $88, %rsp
mov 88+40(%rsp), %rax
subq $96, %rsp
mov 96+40(%rsp), %rax
mov %rax, 72(%rsp)
mov 88+32(%rsp), %rax
mov 96+32(%rsp), %rax
mov %rax, 64(%rsp)
mov 88+24(%rsp), %rax
mov 96+24(%rsp), %rax
mov %rax, 56(%rsp)
mov 88+16(%rsp), %rax
mov 96+16(%rsp), %rax
mov %rax, 48(%rsp)
mov 88+8(%rsp), %rax
mov 96+8(%rsp), %rax
mov %rax, 40(%rsp)
mov %r9, 32(%rsp)
mov %r8, %r9
mov %rcx, %r8
mov %rsi, %rcx
call *%rdi
addq $88, %rsp
addq $96, %rsp
ret