merge mainline into 4096
This commit is contained in:
commit
a5edbcb3a1
393 changed files with 15834 additions and 2186 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
13
grub-core/kern/emu/cache.c
Normal file
13
grub-core/kern/emu/cache.c
Normal 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
|
||||
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -34,6 +34,10 @@
|
|||
#include <stdint.h>
|
||||
#include <grub/util/misc.h>
|
||||
|
||||
#ifdef HAVE_DEVICE_MAPPER
|
||||
# include <libdevmapper.h>
|
||||
#endif
|
||||
|
||||
#ifdef __GNU__
|
||||
#include <hurd.h>
|
||||
#include <hurd/lookup.h>
|
||||
|
@ -98,6 +102,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
|
||||
|
@ -105,75 +117,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;
|
||||
}
|
||||
|
@ -301,7 +358,7 @@ grub_find_device (const char *dir, dev_t dev)
|
|||
|
||||
if (S_ISLNK (st.st_mode)) {
|
||||
#ifdef __linux__
|
||||
if (strcmp (dir, "mapper") == 0) {
|
||||
if (strcmp (dir, "mapper") == 0 || strcmp (dir, "/dev/mapper") == 0) {
|
||||
/* Follow symbolic links under /dev/mapper/; the canonical name
|
||||
may be something like /dev/dm-0, but the names under
|
||||
/dev/mapper/ are more human-readable and so we prefer them if
|
||||
|
@ -479,7 +536,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;
|
||||
|
@ -538,30 +595,49 @@ 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 (os_dev)
|
||||
{
|
||||
char *tmp = os_dev;
|
||||
os_dev = canonicalize_file_name (os_dev);
|
||||
free (tmp);
|
||||
}
|
||||
|
||||
if (os_dev)
|
||||
{
|
||||
if (strncmp (os_dev, "/dev/dm-", sizeof ("/dev/dm-") - 1) != 0)
|
||||
return os_dev;
|
||||
if (stat (os_dev, &st) < 0)
|
||||
grub_util_error ("cannot stat `%s'", os_dev);
|
||||
free (os_dev);
|
||||
dev = st.st_rdev;
|
||||
return grub_find_device ("/dev/mapper", dev);
|
||||
}
|
||||
|
||||
if (stat (dir, &st) < 0)
|
||||
grub_util_error ("cannot stat `%s'", dir);
|
||||
|
||||
dev = st.st_dev;
|
||||
|
||||
#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__ */
|
||||
|
||||
|
@ -569,32 +645,65 @@ grub_guess_root_device (const char *dir)
|
|||
}
|
||||
|
||||
static int
|
||||
grub_util_is_dmraid (const char *os_dev)
|
||||
grub_util_is_lvm (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;
|
||||
else if (! strncmp (os_dev, "/dev/mapper/ddf1_", 17))
|
||||
return 1;
|
||||
if ((strncmp ("/dev/mapper/", os_dev, 12) != 0))
|
||||
return 0;
|
||||
|
||||
#ifdef HAVE_DEVICE_MAPPER
|
||||
{
|
||||
struct dm_tree *tree;
|
||||
uint32_t maj, min;
|
||||
struct dm_tree_node *node = NULL;
|
||||
const char *node_uuid;
|
||||
struct stat st;
|
||||
|
||||
return 0;
|
||||
if (stat (os_dev, &st) < 0)
|
||||
return 0;
|
||||
|
||||
tree = dm_tree_create ();
|
||||
if (! tree)
|
||||
{
|
||||
grub_printf ("Failed to create tree\n");
|
||||
grub_dprintf ("hostdisk", "dm_tree_create failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
maj = major (st.st_rdev);
|
||||
min = minor (st.st_rdev);
|
||||
|
||||
if (! dm_tree_add_dev (tree, maj, min))
|
||||
{
|
||||
grub_dprintf ("hostdisk", "dm_tree_add_dev failed\n");
|
||||
dm_tree_free (tree);
|
||||
return 0;
|
||||
}
|
||||
|
||||
node = dm_tree_find_node (tree, maj, min);
|
||||
if (! node)
|
||||
{
|
||||
grub_dprintf ("hostdisk", "dm_tree_find_node failed\n");
|
||||
dm_tree_free (tree);
|
||||
return 0;
|
||||
}
|
||||
node_uuid = dm_tree_node_get_uuid (node);
|
||||
if (! node_uuid)
|
||||
{
|
||||
grub_dprintf ("hostdisk", "%s has no DM uuid\n", os_dev);
|
||||
dm_tree_free (tree);
|
||||
return 0;
|
||||
}
|
||||
if (strncmp (node_uuid, "LVM-", 4) != 0)
|
||||
{
|
||||
dm_tree_free (tree);
|
||||
return 0;
|
||||
}
|
||||
dm_tree_free (tree);
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
return 1;
|
||||
#endif /* HAVE_DEVICE_MAPPER */
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -606,13 +715,11 @@ grub_util_get_dev_abstraction (const char *os_dev __attribute__((unused)))
|
|||
return GRUB_DEV_ABSTRACTION_NONE;
|
||||
|
||||
/* Check for LVM. */
|
||||
if (!strncmp (os_dev, "/dev/mapper/", 12)
|
||||
&& ! grub_util_is_dmraid (os_dev)
|
||||
&& strncmp (os_dev, "/dev/mapper/mpath", 17) != 0)
|
||||
if (grub_util_is_lvm (os_dev))
|
||||
return GRUB_DEV_ABSTRACTION_LVM;
|
||||
|
||||
/* Check for RAID. */
|
||||
if (!strncmp (os_dev, "/dev/md", 7))
|
||||
if (!strncmp (os_dev, "/dev/md", 7) && ! grub_util_device_is_mapped (os_dev))
|
||||
return GRUB_DEV_ABSTRACTION_RAID;
|
||||
#endif
|
||||
|
||||
|
@ -622,7 +729,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;
|
||||
|
@ -674,19 +781,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -802,19 +911,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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <grub/err.h>
|
||||
#include <grub/emu/misc.h>
|
||||
#include <grub/emu/hostdisk.h>
|
||||
#include <grub/emu/getroot.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/list.h>
|
||||
|
@ -139,6 +140,7 @@ struct grub_util_biosdisk_data
|
|||
char *dev;
|
||||
int access_mode;
|
||||
int fd;
|
||||
int is_disk;
|
||||
};
|
||||
|
||||
#ifdef __linux__
|
||||
|
@ -240,6 +242,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__)
|
||||
|
@ -281,6 +284,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))
|
||||
|
@ -342,18 +346,23 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk)
|
|||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DEVICE_MAPPER
|
||||
static int
|
||||
device_is_mapped (const char *dev)
|
||||
int
|
||||
grub_util_device_is_mapped (const char *dev)
|
||||
{
|
||||
#ifdef HAVE_DEVICE_MAPPER
|
||||
struct stat st;
|
||||
|
||||
if (!grub_device_mapper_supported ())
|
||||
return 0;
|
||||
|
||||
if (stat (dev, &st) < 0)
|
||||
return 0;
|
||||
|
||||
return dm_is_dm_major (major (st.st_rdev));
|
||||
}
|
||||
#else
|
||||
return 0;
|
||||
#endif /* HAVE_DEVICE_MAPPER */
|
||||
}
|
||||
|
||||
#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
/* FIXME: geom actually gives us the whole container hierarchy.
|
||||
|
@ -429,7 +438,7 @@ find_partition_start (const char *dev)
|
|||
# endif /* !defined(HAVE_DIOCGDINFO) */
|
||||
|
||||
# ifdef HAVE_DEVICE_MAPPER
|
||||
if (grub_device_mapper_supported () && device_is_mapped (dev)) {
|
||||
if (grub_util_device_is_mapped (dev)) {
|
||||
struct dm_task *task = NULL;
|
||||
grub_uint64_t start, length;
|
||||
char *target_type, *params, *space;
|
||||
|
@ -532,9 +541,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);
|
||||
|
@ -558,7 +570,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;
|
||||
|
@ -566,6 +578,7 @@ linux_find_partition (char *dev, unsigned long sector)
|
|||
int i;
|
||||
char real_dev[PATH_MAX];
|
||||
struct linux_partition_cache *cache;
|
||||
int missing = 0;
|
||||
|
||||
strcpy(real_dev, dev);
|
||||
|
||||
|
@ -574,6 +587,12 @@ linux_find_partition (char *dev, unsigned long sector)
|
|||
p = real_dev + len - 4;
|
||||
format = "part%d";
|
||||
}
|
||||
else if (strncmp (real_dev, "/dev/disk/by-id/",
|
||||
sizeof ("/dev/disk/by-id/") - 1) == 0)
|
||||
{
|
||||
p = real_dev + len;
|
||||
format = "-part%d";
|
||||
}
|
||||
else if (real_dev[len - 1] >= '0' && real_dev[len - 1] <= '9')
|
||||
{
|
||||
p = real_dev + len;
|
||||
|
@ -604,7 +623,13 @@ linux_find_partition (char *dev, unsigned long sector)
|
|||
|
||||
fd = open (real_dev, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return 0;
|
||||
{
|
||||
if (missing++ < 10)
|
||||
continue;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
missing = 0;
|
||||
close (fd);
|
||||
|
||||
start = find_partition_start (real_dev);
|
||||
|
@ -675,7 +700,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);
|
||||
|
@ -686,10 +723,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;
|
||||
|
@ -727,7 +760,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)
|
||||
|
@ -888,7 +932,6 @@ grub_util_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
|
|||
!= (1 << disk->log_sector_size))
|
||||
{
|
||||
grub_error (GRUB_ERR_READ_ERROR, "cannot read `%s'", map[disk->id].device);
|
||||
close (fd);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
|
@ -938,6 +981,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)
|
||||
{
|
||||
|
@ -945,7 +1009,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);
|
||||
}
|
||||
|
||||
|
@ -1115,6 +1183,54 @@ make_device_name (int drive, int dos_part, int bsd_part)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DEVICE_MAPPER
|
||||
static int
|
||||
grub_util_get_dm_node_linear_info (const char *dev,
|
||||
int *maj, int *min)
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
void *next = NULL;
|
||||
uint64_t length, start;
|
||||
char *target, *params;
|
||||
char *ptr;
|
||||
int major, minor;
|
||||
|
||||
dmt = dm_task_create(DM_DEVICE_TABLE);
|
||||
if (!dmt)
|
||||
return 0;
|
||||
|
||||
if (!dm_task_set_name(dmt, dev))
|
||||
return 0;
|
||||
dm_task_no_open_count(dmt);
|
||||
if (!dm_task_run(dmt))
|
||||
return 0;
|
||||
next = dm_get_next_target(dmt, next, &start, &length,
|
||||
&target, ¶ms);
|
||||
if (grub_strcmp (target, "linear") != 0)
|
||||
return 0;
|
||||
major = grub_strtoul (params, &ptr, 10);
|
||||
if (grub_errno)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return 0;
|
||||
}
|
||||
if (*ptr != ':')
|
||||
return 0;
|
||||
ptr++;
|
||||
minor = grub_strtoul (ptr, 0, 10);
|
||||
if (grub_errno)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return 0;
|
||||
}
|
||||
if (maj)
|
||||
*maj = major;
|
||||
if (min)
|
||||
*min = minor;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static char *
|
||||
convert_system_partition_to_system_disk (const char *os_dev, struct stat *st)
|
||||
{
|
||||
|
@ -1291,9 +1407,40 @@ convert_system_partition_to_system_disk (const char *os_dev, struct stat *st)
|
|||
node = NULL;
|
||||
goto devmapper_out;
|
||||
}
|
||||
else if (strncmp (node_uuid, "DMRAID-", 7) != 0)
|
||||
if (strncmp (node_uuid, "LVM-", 4) == 0)
|
||||
{
|
||||
grub_dprintf ("hostdisk", "%s is an LVM\n", path);
|
||||
node = NULL;
|
||||
goto devmapper_out;
|
||||
}
|
||||
if (strncmp (node_uuid, "mpath-", 6) == 0)
|
||||
{
|
||||
/* Multipath partitions have partN-mpath-* UUIDs, and are
|
||||
linear mappings so are handled by
|
||||
grub_util_get_dm_node_linear_info. Multipath disks are not
|
||||
linear mappings and must be handled specially. */
|
||||
grub_dprintf ("hostdisk", "%s is a multipath disk\n", path);
|
||||
mapper_name = dm_tree_node_get_name (node);
|
||||
goto devmapper_out;
|
||||
}
|
||||
if (strncmp (node_uuid, "DMRAID-", 7) != 0)
|
||||
{
|
||||
int major, minor;
|
||||
const char *node_name;
|
||||
grub_dprintf ("hostdisk", "%s is not DM-RAID\n", path);
|
||||
|
||||
if ((node_name = dm_tree_node_get_name (node))
|
||||
&& grub_util_get_dm_node_linear_info (node_name,
|
||||
&major, &minor))
|
||||
{
|
||||
if (tree)
|
||||
dm_tree_free (tree);
|
||||
free (path);
|
||||
char *ret = grub_find_device ("/dev/mapper",
|
||||
(major << 8) | minor);
|
||||
return ret;
|
||||
}
|
||||
|
||||
node = NULL;
|
||||
goto devmapper_out;
|
||||
}
|
||||
|
@ -1530,6 +1677,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;
|
||||
}
|
||||
|
||||
|
@ -1538,6 +1686,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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] == '/')
|
||||
|
|
|
@ -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
276
grub-core/kern/ia64/dl.c
Normal 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;
|
||||
}
|
73
grub-core/kern/ia64/dl_helper.c
Normal file
73
grub-core/kern/ia64/dl_helper.c
Normal 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 Elf64_Ehdr *e = ehdr;
|
||||
grub_size_t cntt = 0, cntg = 0;;
|
||||
const Elf64_Shdr *s;
|
||||
Elf64_Word entsize;
|
||||
unsigned i;
|
||||
|
||||
/* Find a symbol table. */
|
||||
for (i = 0, s = (Elf64_Shdr *) ((char *) e + grub_le_to_cpu32 (e->e_shoff));
|
||||
i < grub_le_to_cpu16 (e->e_shnum);
|
||||
i++, s = (Elf64_Shdr *) ((char *) s + grub_le_to_cpu16 (e->e_shentsize)))
|
||||
if (grub_le_to_cpu32 (s->sh_type) == SHT_SYMTAB)
|
||||
break;
|
||||
|
||||
if (i == grub_le_to_cpu16 (e->e_shnum))
|
||||
return;
|
||||
|
||||
entsize = s->sh_entsize;
|
||||
|
||||
for (i = 0, s = (Elf64_Shdr *) ((char *) e + grub_le_to_cpu32 (e->e_shoff));
|
||||
i < grub_le_to_cpu16 (e->e_shnum);
|
||||
i++, s = (Elf64_Shdr *) ((char *) s + grub_le_to_cpu16 (e->e_shentsize)))
|
||||
if (grub_le_to_cpu32 (s->sh_type) == SHT_RELA)
|
||||
{
|
||||
Elf64_Rela *rel, *max;
|
||||
|
||||
for (rel = (Elf64_Rela *) ((char *) e + grub_le_to_cpu32 (s->sh_offset)),
|
||||
max = rel + grub_le_to_cpu32 (s->sh_size) / grub_le_to_cpu16 (s->sh_entsize);
|
||||
rel < max; rel++)
|
||||
switch (ELF64_R_TYPE (grub_le_to_cpu32 (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;
|
||||
}
|
||||
|
60
grub-core/kern/ia64/efi/init.c
Normal file
60
grub-core/kern/ia64/efi/init.c
Normal 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;;");
|
||||
}
|
54
grub-core/kern/ia64/efi/startup.S
Normal file
54
grub-core/kern/ia64/efi/startup.S
Normal 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
|
|
@ -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)
|
||||
{
|
||||
|
|
213
grub-core/kern/mips/arc/init.c
Normal file
213
grub-core/kern/mips/arc/init.c
Normal file
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
extern grub_uint32_t grub_total_modules_size;
|
||||
|
||||
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
|
||||
- grub_total_modules_size) & 0x1fffffff))
|
||||
end = ((GRUB_KERNEL_MIPS_ARC_LINK_ADDR - grub_total_modules_size)
|
||||
& 0x1fffffff);
|
||||
if (end > start)
|
||||
grub_mm_init_region ((void *) (grub_addr_t) (start | 0x80000000),
|
||||
end - start);
|
||||
}
|
||||
|
||||
grub_console_init_lately ();
|
||||
|
||||
grub_arcdisk_init ();
|
||||
}
|
||||
|
||||
grub_addr_t
|
||||
grub_arch_modules_addr (void)
|
||||
{
|
||||
return GRUB_KERNEL_MIPS_ARC_LINK_ADDR - grub_total_modules_size;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
@ -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
|
|
@ -9,15 +9,15 @@
|
|||
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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,17 +18,27 @@
|
|||
|
||||
#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)
|
||||
{
|
||||
grub_env_set ("prefix", grub_prefix);
|
||||
}
|
||||
|
||||
extern char _end[];
|
||||
|
||||
grub_addr_t
|
||||
grub_arch_modules_addr (void)
|
||||
{
|
||||
return (grub_addr_t) _end;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
@ -43,22 +45,6 @@ extern void grub_terminfo_init (void);
|
|||
extern void grub_keylayouts_init (void);
|
||||
extern void grub_boot_init (void);
|
||||
|
||||
/* FIXME: use interrupt to count high. */
|
||||
grub_uint64_t
|
||||
grub_get_rtc (void)
|
||||
{
|
||||
static grub_uint32_t high = 0;
|
||||
static grub_uint32_t last = 0;
|
||||
grub_uint32_t low;
|
||||
|
||||
asm volatile ("mfc0 %0, " GRUB_CPU_LOONGSON_COP0_TIMER_COUNT : "=r" (low));
|
||||
if (low < last)
|
||||
high++;
|
||||
last = low;
|
||||
|
||||
return (((grub_uint64_t) high) << 32) | low;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_machine_mmap_iterate (grub_memory_hook_t hook)
|
||||
{
|
||||
|
@ -79,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);
|
||||
|
@ -91,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);
|
||||
|
@ -163,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);
|
||||
|
@ -202,12 +188,14 @@ 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 ();
|
||||
|
@ -223,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 ();
|
||||
|
@ -251,3 +257,10 @@ grub_reboot (void)
|
|||
while (1);
|
||||
}
|
||||
|
||||
extern char _end[];
|
||||
|
||||
grub_addr_t
|
||||
grub_arch_modules_addr (void)
|
||||
{
|
||||
return (grub_addr_t) _end;
|
||||
}
|
|
@ -6,25 +6,29 @@
|
|||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/machine/kernel.h>
|
||||
#include <grub/machine/memory.h>
|
||||
#include <grub/cpu/kernel.h>
|
||||
#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, grub_arch_memsize
|
||||
- (modend - GRUB_ARCH_LOWMEMVSTART));
|
||||
|
||||
grub_install_get_time_ms (grub_rtc_get_time_ms);
|
||||
|
||||
grub_terminfo_init ();
|
||||
grub_serial_init ();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -53,6 +57,14 @@ grub_reboot (void)
|
|||
grub_err_t
|
||||
grub_machine_mmap_iterate (grub_memory_hook_t hook)
|
||||
{
|
||||
hook (0, RAMSIZE, GRUB_MEMORY_AVAILABLE);
|
||||
hook (0, grub_arch_memsize, GRUB_MEMORY_AVAILABLE);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
extern char _end[];
|
||||
|
||||
grub_addr_t
|
||||
grub_arch_modules_addr (void)
|
||||
{
|
||||
return (grub_addr_t) _end;
|
||||
}
|
|
@ -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,8 +36,8 @@ start:
|
|||
bal cont
|
||||
nop
|
||||
|
||||
. = _start + GRUB_KERNEL_MIPS_YEELOONG_TOTAL_MODULE_SIZE
|
||||
total_module_size:
|
||||
. = _start + GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE
|
||||
VARIABLE(grub_total_modules_size)
|
||||
.long 0
|
||||
|
||||
. = _start + GRUB_KERNEL_MACHINE_PREFIX
|
||||
|
@ -50,7 +51,6 @@ VARIABLE(grub_prefix)
|
|||
*/
|
||||
|
||||
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END
|
||||
#ifdef GRUB_MACHINE_MIPS_YEELOONG
|
||||
VARIABLE (grub_arch_busclock)
|
||||
.long 0
|
||||
VARIABLE (grub_arch_cpuclock)
|
||||
|
@ -59,21 +59,32 @@ VARIABLE (grub_arch_memsize)
|
|||
.long 0
|
||||
VARIABLE (grub_arch_highmemsize)
|
||||
.long 0
|
||||
#ifdef GRUB_MACHINE_MIPS_LOONGSON
|
||||
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_QEMU_MIPS
|
||||
lui $t1, %hi(grub_arch_busclock)
|
||||
addiu $t1, %lo(grub_arch_busclock)
|
||||
sw $s4, 8($t1)
|
||||
#endif
|
||||
|
||||
#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. */
|
||||
#ifndef GRUB_MACHINE_ARC
|
||||
lui $t2, %hi(__bss_start)
|
||||
addiu $t2, %lo(__bss_start)
|
||||
|
||||
|
@ -103,6 +114,7 @@ modulesmovcont:
|
|||
b modulesmovcont
|
||||
addiu $t3, $t3, -1
|
||||
modulesmovdone:
|
||||
#endif
|
||||
|
||||
/* Clean BSS. */
|
||||
|
||||
|
|
|
@ -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 (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--)
|
||||
|
@ -666,7 +666,7 @@ grub_lltoa (char *str, int c, unsigned long long n)
|
|||
/* BASE == 10 */
|
||||
do
|
||||
{
|
||||
unsigned m;
|
||||
grub_uint64_t m;
|
||||
|
||||
n = grub_divmod64 (n, 10, &m);
|
||||
*p++ = m + '0';
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue