merge mainline into hints

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2011-12-23 18:49:00 +01:00
commit 17785932df
448 changed files with 43023 additions and 10176 deletions

View file

@ -26,6 +26,8 @@
#include <grub/env.h>
#include <grub/partition.h>
grub_net_t (*grub_net_open) (const char *name) = NULL;
grub_device_t
grub_device_open (const char *name)
{
@ -35,7 +37,7 @@ grub_device_open (const char *name)
if (! name)
{
name = grub_env_get ("root");
if (*name == '\0')
if (name == NULL || *name == '\0')
{
grub_error (GRUB_ERR_BAD_DEVICE, "no device is set");
goto fail;
@ -46,15 +48,19 @@ grub_device_open (const char *name)
if (! dev)
goto fail;
dev->net = NULL;
/* Try to open a disk. */
disk = grub_disk_open (name);
if (! disk)
goto fail;
dev->disk = grub_disk_open (name);
if (dev->disk)
return dev;
if (grub_net_open && grub_errno == GRUB_ERR_UNKNOWN_DEVICE)
{
grub_errno = GRUB_ERR_NONE;
dev->net = grub_net_open (name);
}
dev->disk = disk;
dev->net = 0; /* FIXME */
return dev;
if (dev->net)
return dev;
fail:
if (disk)
@ -71,6 +77,12 @@ grub_device_close (grub_device_t device)
if (device->disk)
grub_disk_close (device->disk);
if (device->net)
{
grub_free (device->net->server);
grub_free (device->net);
}
grub_free (device);
return grub_errno;

View file

@ -46,11 +46,7 @@ static struct grub_disk_cache grub_disk_cache_table[GRUB_DISK_CACHE_NUM];
void (*grub_disk_firmware_fini) (void);
int grub_disk_firmware_is_tainted;
grub_err_t (* grub_disk_ata_pass_through) (grub_disk_t,
struct grub_disk_ata_pass_through_parms *);
#if 0
#if DISK_CACHE_STATS
static unsigned long grub_disk_cache_hits;
static unsigned long grub_disk_cache_misses;
@ -123,13 +119,13 @@ grub_disk_cache_fetch (unsigned long dev_id, unsigned long disk_id,
&& cache->sector == sector)
{
cache->lock = 1;
#if 0
#if DISK_CACHE_STATS
grub_disk_cache_hits++;
#endif
return cache->data;
}
#if 0
#if DISK_CACHE_STATS
grub_disk_cache_misses++;
#endif
@ -207,10 +203,12 @@ int
grub_disk_dev_iterate (int (*hook) (const char *name))
{
grub_disk_dev_t p;
grub_disk_pull_t pull;
for (p = grub_disk_dev_list; p; p = p->next)
if (p->iterate && (p->iterate) (hook))
return 1;
for (pull = 0; pull < GRUB_DISK_PULL_MAX; pull++)
for (p = grub_disk_dev_list; p; p = p->next)
if (p->iterate && (p->iterate) (hook, pull))
return 1;
return 0;
}
@ -247,6 +245,7 @@ grub_disk_open (const char *name)
disk = (grub_disk_t) grub_zalloc (sizeof (*disk));
if (! disk)
return 0;
disk->log_sector_size = GRUB_DISK_SECTOR_BITS;
p = find_part_sep (name);
if (p)
@ -266,7 +265,6 @@ grub_disk_open (const char *name)
if (! disk->name)
goto fail;
for (dev = grub_disk_dev_list; dev; dev = dev->next)
{
if ((dev->open) (raw, disk) == GRUB_ERR_NONE)
@ -282,6 +280,14 @@ grub_disk_open (const char *name)
grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such disk");
goto fail;
}
if (disk->log_sector_size > GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS
|| disk->log_sector_size < GRUB_DISK_SECTOR_BITS)
{
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"sector sizes of %d bytes aren't supported yet",
(1 << disk->log_sector_size));
goto fail;
}
disk->dev = dev;
@ -373,21 +379,113 @@ grub_disk_adjust_range (grub_disk_t disk, grub_disk_addr_t *sector,
*sector += start;
}
if (disk->total_sectors <= *sector
|| ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1)
>> GRUB_DISK_SECTOR_BITS) > disk->total_sectors - *sector)
if (disk->total_sectors != GRUB_DISK_SIZE_UNKNOWN
&& ((disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)) <= *sector
|| ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1)
>> GRUB_DISK_SECTOR_BITS) > (disk->total_sectors
<< (disk->log_sector_size
- GRUB_DISK_SECTOR_BITS)) - *sector))
return grub_error (GRUB_ERR_OUT_OF_RANGE, "out of disk");
return GRUB_ERR_NONE;
}
static inline grub_disk_addr_t
transform_sector (grub_disk_t disk, grub_disk_addr_t sector)
{
return sector >> (disk->log_sector_size - GRUB_DISK_SECTOR_BITS);
}
/* Small read (less than cache size and not pass across cache unit boundaries).
sector is already adjusted and is divisible by cache unit size.
*/
static grub_err_t
grub_disk_read_small (grub_disk_t disk, grub_disk_addr_t sector,
grub_off_t offset, grub_size_t size, void *buf)
{
char *data;
char *tmp_buf;
/* Fetch the cache. */
data = grub_disk_cache_fetch (disk->dev->id, disk->id, sector);
if (data)
{
/* Just copy it! */
grub_memcpy (buf, data + offset, size);
grub_disk_cache_unlock (disk->dev->id, disk->id, sector);
return GRUB_ERR_NONE;
}
/* Allocate a temporary buffer. */
tmp_buf = grub_malloc (GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
if (! tmp_buf)
return grub_errno;
/* Otherwise read data from the disk actually. */
if (disk->total_sectors == GRUB_DISK_SIZE_UNKNOWN
|| sector + GRUB_DISK_CACHE_SIZE
< (disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)))
{
grub_err_t err;
err = (disk->dev->read) (disk, transform_sector (disk, sector),
1 << (GRUB_DISK_CACHE_BITS
+ GRUB_DISK_SECTOR_BITS
- disk->log_sector_size), tmp_buf);
if (!err)
{
/* Copy it and store it in the disk cache. */
grub_memcpy (buf, tmp_buf + offset, size);
grub_disk_cache_store (disk->dev->id, disk->id,
sector, tmp_buf);
grub_free (tmp_buf);
return GRUB_ERR_NONE;
}
}
grub_free (tmp_buf);
grub_errno = GRUB_ERR_NONE;
{
/* Uggh... Failed. Instead, just read necessary data. */
unsigned num;
grub_disk_addr_t aligned_sector;
sector += (offset >> GRUB_DISK_SECTOR_BITS);
offset &= ((1 << GRUB_DISK_SECTOR_BITS) - 1);
aligned_sector = (sector & ~((1 << (disk->log_sector_size
- GRUB_DISK_SECTOR_BITS))
- 1));
offset += ((sector - aligned_sector) << GRUB_DISK_SECTOR_BITS);
num = ((size + offset + (1 << (disk->log_sector_size))
- 1) >> (disk->log_sector_size));
tmp_buf = grub_malloc (num << disk->log_sector_size);
if (!tmp_buf)
return grub_errno;
if ((disk->dev->read) (disk, transform_sector (disk, aligned_sector),
num, tmp_buf))
{
grub_error_push ();
grub_dprintf ("disk", "%s read failed\n", disk->name);
grub_error_pop ();
grub_free (tmp_buf);
return grub_errno;
}
grub_memcpy (buf, tmp_buf + offset, size);
grub_free (tmp_buf);
return GRUB_ERR_NONE;
}
}
/* Read data from the disk. */
grub_err_t
grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
grub_off_t offset, grub_size_t size, void *buf)
{
char *tmp_buf;
unsigned real_offset;
grub_off_t real_offset;
grub_disk_addr_t real_sector;
grub_size_t real_size;
/* First of all, check if the region is within the disk. */
if (grub_disk_adjust_range (disk, &sector, &offset, size) != GRUB_ERR_NONE)
@ -399,126 +497,125 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
return grub_errno;
}
real_sector = sector;
real_offset = offset;
real_size = size;
/* Allocate a temporary buffer. */
tmp_buf = grub_malloc (GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
if (! tmp_buf)
return grub_errno;
/* Until SIZE is zero... */
while (size)
/* First read until first cache boundary. */
if (offset || (sector & (GRUB_DISK_CACHE_SIZE - 1)))
{
char *data;
grub_disk_addr_t start_sector;
grub_size_t len;
grub_size_t pos;
grub_err_t err;
grub_size_t len;
/* For reading bulk data. */
start_sector = sector & ~(GRUB_DISK_CACHE_SIZE - 1);
pos = (sector - start_sector) << GRUB_DISK_SECTOR_BITS;
len = ((GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS)
- pos - real_offset);
- pos - offset);
if (len > size)
len = size;
/* Fetch the cache. */
data = grub_disk_cache_fetch (disk->dev->id, disk->id, start_sector);
if (data)
{
/* Just copy it! */
grub_memcpy (buf, data + pos + real_offset, len);
grub_disk_cache_unlock (disk->dev->id, disk->id, start_sector);
}
else
{
/* Otherwise read data from the disk actually. */
if (start_sector + GRUB_DISK_CACHE_SIZE > disk->total_sectors
|| (disk->dev->read) (disk, start_sector,
GRUB_DISK_CACHE_SIZE, tmp_buf)
!= GRUB_ERR_NONE)
{
/* Uggh... Failed. Instead, just read necessary data. */
unsigned num;
char *p;
grub_errno = GRUB_ERR_NONE;
num = ((size + real_offset + GRUB_DISK_SECTOR_SIZE - 1)
>> GRUB_DISK_SECTOR_BITS);
p = grub_realloc (tmp_buf, num << GRUB_DISK_SECTOR_BITS);
if (!p)
goto finish;
tmp_buf = p;
if ((disk->dev->read) (disk, sector, num, tmp_buf))
{
grub_error_push ();
grub_dprintf ("disk", "%s read failed\n", disk->name);
grub_error_pop ();
goto finish;
}
grub_memcpy (buf, tmp_buf + real_offset, size);
/* Call the read hook, if any. */
if (disk->read_hook)
while (size)
{
grub_size_t to_read = (size > GRUB_DISK_SECTOR_SIZE) ? GRUB_DISK_SECTOR_SIZE : size;
(disk->read_hook) (sector, real_offset,
to_read);
if (grub_errno != GRUB_ERR_NONE)
goto finish;
sector++;
size -= to_read - real_offset;
real_offset = 0;
}
/* This must be the end. */
goto finish;
}
/* Copy it and store it in the disk cache. */
grub_memcpy (buf, tmp_buf + pos + real_offset, len);
grub_disk_cache_store (disk->dev->id, disk->id,
start_sector, tmp_buf);
}
/* Call the read hook, if any. */
if (disk->read_hook)
{
grub_disk_addr_t s = sector;
grub_size_t l = len;
while (l)
{
(disk->read_hook) (s, real_offset,
((l > GRUB_DISK_SECTOR_SIZE)
? GRUB_DISK_SECTOR_SIZE
: l));
if (l < GRUB_DISK_SECTOR_SIZE - real_offset)
break;
s++;
l -= GRUB_DISK_SECTOR_SIZE - real_offset;
real_offset = 0;
}
}
sector = start_sector + GRUB_DISK_CACHE_SIZE;
err = grub_disk_read_small (disk, start_sector,
offset + pos, len, buf);
if (err)
return err;
buf = (char *) buf + len;
size -= len;
real_offset = 0;
offset += len;
sector += (offset >> GRUB_DISK_SECTOR_BITS);
offset &= ((1 << GRUB_DISK_SECTOR_BITS) - 1);
}
finish:
/* Until SIZE is zero... */
while (size >= (GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS))
{
char *data = NULL;
grub_disk_addr_t agglomerate;
grub_err_t err;
grub_free (tmp_buf);
/* agglomerate read until we find a first cached entry. */
for (agglomerate = 0; agglomerate
< (size >> (GRUB_DISK_SECTOR_BITS + GRUB_DISK_CACHE_BITS));
agglomerate++)
{
data = grub_disk_cache_fetch (disk->dev->id, disk->id,
sector + (agglomerate
<< GRUB_DISK_CACHE_BITS));
if (data)
break;
}
if (data)
{
grub_memcpy ((char *) buf
+ (agglomerate << (GRUB_DISK_CACHE_BITS
+ GRUB_DISK_SECTOR_BITS)),
data, GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS);
grub_disk_cache_unlock (disk->dev->id, disk->id,
sector + (agglomerate
<< GRUB_DISK_CACHE_BITS));
}
if (agglomerate)
{
grub_disk_addr_t i;
err = (disk->dev->read) (disk, transform_sector (disk, sector),
agglomerate << (GRUB_DISK_CACHE_BITS
+ GRUB_DISK_SECTOR_BITS
- disk->log_sector_size),
buf);
if (err)
return err;
for (i = 0; i < agglomerate; i ++)
grub_disk_cache_store (disk->dev->id, disk->id,
sector + (i << GRUB_DISK_CACHE_BITS),
(char *) buf
+ (i << (GRUB_DISK_CACHE_BITS
+ GRUB_DISK_SECTOR_BITS)));
sector += agglomerate << GRUB_DISK_CACHE_BITS;
size -= agglomerate << (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS);
buf = (char *) buf
+ (agglomerate << (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS));
}
if (data)
{
sector += GRUB_DISK_CACHE_SIZE;
buf = (char *) buf + (GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS);
size -= (GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS);
}
}
/* And now read the last part. */
if (size)
{
grub_err_t err;
err = grub_disk_read_small (disk, sector, 0, size, buf);
if (err)
return err;
}
/* Call the read hook, if any. */
if (disk->read_hook)
{
grub_disk_addr_t s = real_sector;
grub_size_t l = real_size;
grub_off_t o = real_offset;
while (l)
{
(disk->read_hook) (s, o,
((l > GRUB_DISK_SECTOR_SIZE)
? GRUB_DISK_SECTOR_SIZE
: l));
s++;
l -= GRUB_DISK_SECTOR_SIZE - o;
o = 0;
}
}
return grub_errno;
}
@ -528,25 +625,31 @@ grub_disk_write (grub_disk_t disk, grub_disk_addr_t sector,
grub_off_t offset, grub_size_t size, const void *buf)
{
unsigned real_offset;
grub_disk_addr_t aligned_sector;
grub_dprintf ("disk", "Writing `%s'...\n", disk->name);
if (grub_disk_adjust_range (disk, &sector, &offset, size) != GRUB_ERR_NONE)
return -1;
real_offset = offset;
aligned_sector = (sector & ~((1 << (disk->log_sector_size
- GRUB_DISK_SECTOR_BITS)) - 1));
real_offset = offset + ((sector - aligned_sector) << GRUB_DISK_SECTOR_BITS);
sector = aligned_sector;
while (size)
{
if (real_offset != 0 || (size < GRUB_DISK_SECTOR_SIZE && size != 0))
if (real_offset != 0 || (size < (1U << disk->log_sector_size)
&& size != 0))
{
char tmp_buf[GRUB_DISK_SECTOR_SIZE];
char tmp_buf[1 << disk->log_sector_size];
grub_size_t len;
grub_partition_t part;
part = disk->partition;
disk->partition = 0;
if (grub_disk_read (disk, sector, 0, GRUB_DISK_SECTOR_SIZE, tmp_buf)
if (grub_disk_read (disk, sector,
0, (1 << disk->log_sector_size), tmp_buf)
!= GRUB_ERR_NONE)
{
disk->partition = part;
@ -554,7 +657,7 @@ grub_disk_write (grub_disk_t disk, grub_disk_addr_t sector,
}
disk->partition = part;
len = GRUB_DISK_SECTOR_SIZE - real_offset;
len = (1 << disk->log_sector_size) - real_offset;
if (len > size)
len = size;
@ -565,7 +668,7 @@ grub_disk_write (grub_disk_t disk, grub_disk_addr_t sector,
if ((disk->dev->write) (disk, sector, 1, tmp_buf) != GRUB_ERR_NONE)
goto finish;
sector++;
sector += (1 << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS));
buf = (char *) buf + len;
size -= len;
real_offset = 0;
@ -575,8 +678,8 @@ grub_disk_write (grub_disk_t disk, grub_disk_addr_t sector,
grub_size_t len;
grub_size_t n;
len = size & ~(GRUB_DISK_SECTOR_SIZE - 1);
n = size >> GRUB_DISK_SECTOR_BITS;
len = size & ~((1 << disk->log_sector_size) - 1);
n = size >> disk->log_sector_size;
if ((disk->dev->write) (disk, sector, n, buf) != GRUB_ERR_NONE)
goto finish;
@ -599,6 +702,8 @@ grub_disk_get_size (grub_disk_t disk)
{
if (disk->partition)
return grub_partition_get_len (disk->partition);
else if (disk->total_sectors != GRUB_DISK_SIZE_UNKNOWN)
return disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS);
else
return disk->total_sectors;
return GRUB_DISK_SIZE_UNKNOWN;
}

View file

@ -233,7 +233,7 @@ 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__
#if defined (__ia64__) || defined (__powerpc__)
grub_size_t tramp;
grub_size_t got;
#endif
@ -243,14 +243,14 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
i < e->e_shnum;
i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize))
{
tsize += ALIGN_UP (s->sh_size, s->sh_addralign);
tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size;
if (talign < s->sh_addralign)
talign = s->sh_addralign;
}
#ifdef __ia64__
#if defined (__ia64__) || defined (__powerpc__)
grub_arch_dl_get_tramp_got_size (e, &tramp, &got);
tramp *= GRUB_IA64_DL_TRAMP_SIZE;
tramp *= GRUB_ARCH_DL_TRAMP_SIZE;
got *= sizeof (grub_uint64_t);
tsize += ALIGN_UP (tramp, GRUB_ARCH_DL_TRAMP_ALIGN);
if (talign < GRUB_ARCH_DL_TRAMP_ALIGN)
@ -269,6 +269,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
mod->base = grub_memalign (talign, tsize);
if (!mod->base)
return grub_errno;
mod->sz = tsize;
ptr = mod->base;
#ifdef GRUB_MACHINE_EMU
@ -316,7 +317,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
mod->segment = seg;
}
}
#ifdef __ia64__
#if defined (__ia64__) || defined (__powerpc__)
ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN);
mod->tramp = ptr;
ptr += tramp;
@ -575,15 +576,9 @@ grub_dl_unref (grub_dl_t mod)
static void
grub_dl_flush_cache (grub_dl_t mod)
{
grub_dl_segment_t seg;
for (seg = mod->segment; seg; seg = seg->next) {
if (seg->size) {
grub_dprintf ("modules", "flushing 0x%lx bytes at %p\n",
(unsigned long) seg->size, seg->addr);
grub_arch_sync_caches (seg->addr, seg->size);
}
}
grub_dprintf ("modules", "flushing 0x%lx bytes at %p\n",
(unsigned long) mod->sz, mod->base);
grub_arch_sync_caches (mod->base, mod->sz);
}
/* Load a module from core memory. */
@ -688,11 +683,9 @@ grub_dl_load_file (const char *filename)
grub_file_close (file);
mod = grub_dl_load_core (core, size);
grub_free (core);
if (! mod)
{
grub_free (core);
return 0;
}
return 0;
mod->ref_count--;
return mod;
@ -704,7 +697,7 @@ grub_dl_load (const char *name)
{
char *filename;
grub_dl_t mod;
char *grub_dl_dir = grub_env_get ("prefix");
const char *grub_dl_dir = grub_env_get ("prefix");
mod = grub_dl_get (name);
if (mod)
@ -736,7 +729,6 @@ int
grub_dl_unload (grub_dl_t mod)
{
grub_dl_dep_t dep, depn;
grub_dl_segment_t seg, segn;
if (mod->ref_count > 0)
return 0;
@ -756,13 +748,7 @@ grub_dl_unload (grub_dl_t mod)
grub_free (dep);
}
for (seg = mod->segment; seg; seg = segn)
{
segn = seg->next;
grub_free (seg->addr);
grub_free (seg);
}
grub_free (mod->base);
grub_free (mod->name);
#ifdef GRUB_MODULES_MACHINE_READONLY
grub_free (mod->symtab);

View file

@ -163,18 +163,6 @@ grub_exit (void)
for (;;) ;
}
/* On i386, a firmware-independant grub_reboot() is provided by realmode.S. */
#ifndef __i386__
void
grub_reboot (void)
{
grub_efi_fini ();
efi_call_4 (grub_efi_system_table->runtime_services->reset_system,
GRUB_EFI_RESET_COLD, GRUB_EFI_SUCCESS, 0, NULL);
for (;;) ;
}
#endif
grub_err_t
grub_efi_set_virtual_address_map (grub_efi_uintn_t memory_map_size,
grub_efi_uintn_t descriptor_size,
@ -218,7 +206,7 @@ grub_get_rtc (void)
/* Search the mods section from the PE32/PE32+ image. This code uses
a PE32 header, but should work with PE32+ as well. */
grub_addr_t
grub_arch_modules_addr (void)
grub_efi_modules_addr (void)
{
grub_efi_loaded_image_t *image;
struct grub_pe32_header *header;
@ -746,3 +734,51 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
dp = (grub_efi_device_path_t *) ((char *) dp + len);
}
}
/* Compare device paths. */
int
grub_efi_compare_device_paths (const grub_efi_device_path_t *dp1,
const grub_efi_device_path_t *dp2)
{
if (! dp1 || ! dp2)
/* Return non-zero. */
return 1;
while (1)
{
grub_efi_uint8_t type1, type2;
grub_efi_uint8_t subtype1, subtype2;
grub_efi_uint16_t len1, len2;
int ret;
type1 = GRUB_EFI_DEVICE_PATH_TYPE (dp1);
type2 = GRUB_EFI_DEVICE_PATH_TYPE (dp2);
if (type1 != type2)
return (int) type2 - (int) type1;
subtype1 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp1);
subtype2 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp2);
if (subtype1 != subtype2)
return (int) subtype1 - (int) subtype2;
len1 = GRUB_EFI_DEVICE_PATH_LENGTH (dp1);
len2 = GRUB_EFI_DEVICE_PATH_LENGTH (dp2);
if (len1 != len2)
return (int) len1 - (int) len2;
ret = grub_memcmp (dp1, dp2, len1);
if (ret != 0)
return ret;
if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp1))
break;
dp1 = (grub_efi_device_path_t *) ((char *) dp1 + len1);
dp2 = (grub_efi_device_path_t *) ((char *) dp2 + len2);
}
return 0;
}

View file

@ -26,9 +26,12 @@
#include <grub/mm.h>
#include <grub/kernel.h>
grub_addr_t grub_modbase;
void
grub_efi_init (void)
{
grub_modbase = grub_efi_modules_addr ();
/* First of all, initialize the console so that GRUB can display
messages. */
grub_console_init ();
@ -42,84 +45,28 @@ grub_efi_init (void)
grub_efidisk_init ();
}
void (*grub_efi_net_config) (grub_efi_handle_t hnd,
char **device,
char **path);
void
grub_efi_set_prefix (void)
grub_machine_get_bootlocation (char **device, char **path)
{
grub_efi_loaded_image_t *image = NULL;
char *device = NULL;
char *path = NULL;
char *p;
{
char *pptr = NULL;
if (grub_prefix[0] == '(')
{
pptr = grub_strrchr (grub_prefix, ')');
if (pptr)
{
device = grub_strndup (grub_prefix + 1, pptr - grub_prefix - 1);
pptr++;
}
}
if (!pptr)
pptr = grub_prefix;
if (pptr[0])
path = grub_strdup (pptr);
}
image = grub_efi_get_loaded_image (grub_efi_image_handle);
if (!image)
return;
*device = grub_efidisk_get_device_name (image->device_handle);
*path = grub_efi_get_filename (image->file_path);
if (!*device && grub_efi_net_config)
grub_efi_net_config (image->device_handle, device, path);
if ((!device || device[0] == ',' || !device[0]) || !path)
image = grub_efi_get_loaded_image (grub_efi_image_handle);
if (image)
{
if (!device)
device = grub_efidisk_get_device_name (image->device_handle);
else if (device[0] == ',' || !device[0])
{
/* We have a partition, but still need to fill in the drive. */
char *image_device, *comma, *new_device;
image_device = grub_efidisk_get_device_name (image->device_handle);
comma = grub_strchr (image_device, ',');
if (comma)
{
char *drive = grub_strndup (image_device, comma - image_device);
new_device = grub_xasprintf ("%s%s", drive, device);
grub_free (drive);
}
else
new_device = grub_xasprintf ("%s%s", image_device, device);
grub_free (image_device);
grub_free (device);
device = new_device;
}
}
if (image && !path)
{
char *p;
path = grub_efi_get_filename (image->file_path);
/* Get the directory. */
p = grub_strrchr (path, '/');
if (p)
*p = '\0';
}
if (device && path)
{
char *prefix;
prefix = grub_xasprintf ("(%s)%s", device, path);
if (prefix)
{
grub_env_set ("prefix", prefix);
grub_free (prefix);
}
}
grub_free (device);
grub_free (path);
/* Get the directory. */
p = grub_strrchr (*path, '/');
if (p)
*p = '\0';
}
void

View file

@ -1,967 +0,0 @@
/* getroot.c - Get root device */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config-util.h>
#include <config.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <error.h>
#include <stdio.h>
#include <stdlib.h>
#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>
#include <hurd/fs.h>
#include <sys/mman.h>
#endif
#ifdef __linux__
# include <sys/types.h>
# include <sys/wait.h>
#endif
#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
# include <grub/util/libzfs.h>
# include <grub/util/libnvpair.h>
#endif
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/emu/misc.h>
#include <grub/emu/hostdisk.h>
#include <grub/emu/getroot.h>
static void
strip_extra_slashes (char *dir)
{
char *p = dir;
while ((p = strchr (p, '/')) != 0)
{
if (p[1] == '/')
{
memmove (p, p + 1, strlen (p));
continue;
}
else if (p[1] == '\0')
{
if (p > dir)
p[0] = '\0';
break;
}
p++;
}
}
static char *
xgetcwd (void)
{
size_t size = 10;
char *path;
path = xmalloc (size);
while (! getcwd (path, size))
{
size <<= 1;
path = xrealloc (path, size);
}
return path;
}
#ifdef __linux__
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
using a single device it can be dynamically extended onto another). We
can't deal with the multiple-device case yet, but in the meantime, we can
at least cope with the single-device case by scanning
/proc/self/mountinfo. */
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)
{
struct mountinfo_entry entry;
int count;
size_t enc_path_len;
const char *sep;
if (sscanf (buf, "%d %d %u:%u %s %s%n",
&entry.id, &parent_entry.id, &entry.major, &entry.minor,
entry.enc_root, entry.enc_path, &count) < 6)
continue;
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, entry.enc_path, enc_path_len) != 0 ||
(enc_path_len && dir[enc_path_len - 1] != '/' &&
dir[enc_path_len] && dir[enc_path_len] != '/'))
continue;
sep = strstr (buf + count, " - ");
if (!sep)
continue;
sep += sizeof (" - ") - 1;
if (sscanf (sep, "%s %s", entry.fstype, entry.device) != 2)
continue;
/* 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;
ret = strdup (entries[i].device);
if (relroot)
*relroot = strdup (entries[i].enc_root);
break;
}
free (buf);
free (entries);
fclose (fp);
return ret;
}
#endif /* __linux__ */
#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
static char *
find_root_device_from_libzfs (const char *dir)
{
char *device = NULL;
char *poolname;
char *poolfs;
grub_find_zpool_from_dir (dir, &poolname, &poolfs);
if (! poolname)
return NULL;
{
zpool_handle_t *zpool;
libzfs_handle_t *libzfs;
nvlist_t *config, *vdev_tree;
nvlist_t **children, **path;
unsigned int nvlist_count;
unsigned int i;
libzfs = grub_get_libzfs_handle ();
if (! libzfs)
return NULL;
zpool = zpool_open (libzfs, poolname);
config = zpool_get_config (zpool, NULL);
if (nvlist_lookup_nvlist (config, "vdev_tree", &vdev_tree) != 0)
error (1, errno, "nvlist_lookup_nvlist (\"vdev_tree\")");
if (nvlist_lookup_nvlist_array (vdev_tree, "children", &children, &nvlist_count) != 0)
error (1, errno, "nvlist_lookup_nvlist_array (\"children\")");
assert (nvlist_count > 0);
while (nvlist_lookup_nvlist_array (children[0], "children",
&children, &nvlist_count) == 0)
assert (nvlist_count > 0);
for (i = 0; i < nvlist_count; i++)
{
if (nvlist_lookup_string (children[i], "path", &device) != 0)
error (1, errno, "nvlist_lookup_string (\"path\")");
struct stat st;
if (stat (device, &st) == 0)
{
device = xstrdup (device);
break;
}
device = NULL;
}
zpool_close (zpool);
}
free (poolname);
if (poolfs)
free (poolfs);
return device;
}
#endif
#ifdef __MINGW32__
char *
grub_find_device (const char *dir __attribute__ ((unused)),
dev_t dev __attribute__ ((unused)))
{
return 0;
}
#elif ! defined(__CYGWIN__)
char *
grub_find_device (const char *dir, dev_t dev)
{
DIR *dp;
char *saved_cwd;
struct dirent *ent;
if (! dir)
{
#ifdef __CYGWIN__
return NULL;
#else
dir = "/dev";
#endif
}
dp = opendir (dir);
if (! dp)
return 0;
saved_cwd = xgetcwd ();
grub_util_info ("changing current directory to %s", dir);
if (chdir (dir) < 0)
{
free (saved_cwd);
closedir (dp);
return 0;
}
while ((ent = readdir (dp)) != 0)
{
struct stat st;
/* Avoid:
- dotfiles (like "/dev/.tmp.md0") since they could be duplicates.
- dotdirs (like "/dev/.static") since they could contain duplicates. */
if (ent->d_name[0] == '.')
continue;
if (lstat (ent->d_name, &st) < 0)
/* Ignore any error. */
continue;
if (S_ISLNK (st.st_mode)) {
#ifdef __linux__
if (strcmp (dir, "mapper") == 0) {
/* Follow symbolic links under /dev/mapper/; the canonical name
may be something like /dev/dm-0, but the names under
/dev/mapper/ are more human-readable and so we prefer them if
we can get them. */
if (stat (ent->d_name, &st) < 0)
continue;
} else
#endif /* __linux__ */
/* Don't follow other symbolic links. */
continue;
}
if (S_ISDIR (st.st_mode))
{
/* Find it recursively. */
char *res;
res = grub_find_device (ent->d_name, dev);
if (res)
{
if (chdir (saved_cwd) < 0)
grub_util_error ("cannot restore the original directory");
free (saved_cwd);
closedir (dp);
return res;
}
}
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
if (S_ISCHR (st.st_mode) && st.st_rdev == dev)
#else
if (S_ISBLK (st.st_mode) && st.st_rdev == dev)
#endif
{
#ifdef __linux__
/* Skip device names like /dev/dm-0, which are short-hand aliases
to more descriptive device names, e.g. those under /dev/mapper */
if (ent->d_name[0] == 'd' &&
ent->d_name[1] == 'm' &&
ent->d_name[2] == '-' &&
ent->d_name[3] >= '0' &&
ent->d_name[3] <= '9')
continue;
#endif
/* Found! */
char *res;
char *cwd;
#if defined(__NetBSD__)
/* Convert this block device to its character (raw) device. */
const char *template = "%s/r%s";
#else
/* Keep the device name as it is. */
const char *template = "%s/%s";
#endif
cwd = xgetcwd ();
res = xmalloc (strlen (cwd) + strlen (ent->d_name) + 3);
sprintf (res, template, cwd, ent->d_name);
strip_extra_slashes (res);
free (cwd);
/* /dev/root is not a real block device keep looking, takes care
of situation where root filesystem is on the same partition as
grub files */
if (strcmp(res, "/dev/root") == 0)
continue;
if (chdir (saved_cwd) < 0)
grub_util_error ("cannot restore the original directory");
free (saved_cwd);
closedir (dp);
return res;
}
}
if (chdir (saved_cwd) < 0)
grub_util_error ("cannot restore the original directory");
free (saved_cwd);
closedir (dp);
return 0;
}
#else /* __CYGWIN__ */
/* Read drive/partition serial number from mbr/boot sector,
return 0 on read error, ~0 on unknown serial. */
static unsigned
get_bootsec_serial (const char *os_dev, int mbr)
{
/* Read boot sector. */
int fd = open (os_dev, O_RDONLY);
if (fd < 0)
return 0;
unsigned char buf[0x200];
int n = read (fd, buf, sizeof (buf));
close (fd);
if (n != sizeof(buf))
return 0;
/* Check signature. */
if (!(buf[0x1fe] == 0x55 && buf[0x1ff] == 0xaa))
return ~0;
/* Serial number offset depends on boot sector type. */
if (mbr)
n = 0x1b8;
else if (memcmp (buf + 0x03, "NTFS", 4) == 0)
n = 0x048;
else if (memcmp (buf + 0x52, "FAT32", 5) == 0)
n = 0x043;
else if (memcmp (buf + 0x36, "FAT", 3) == 0)
n = 0x027;
else
return ~0;
unsigned serial = *(unsigned *)(buf + n);
if (serial == 0)
return ~0;
return serial;
}
char *
grub_find_device (const char *path, dev_t dev)
{
/* No root device for /cygdrive. */
if (dev == (DEV_CYGDRIVE_MAJOR << 16))
return 0;
/* Convert to full POSIX and Win32 path. */
char fullpath[PATH_MAX], winpath[PATH_MAX];
cygwin_conv_to_full_posix_path (path, fullpath);
cygwin_conv_to_full_win32_path (fullpath, winpath);
/* If identical, this is no real filesystem path. */
if (strcmp (fullpath, winpath) == 0)
return 0;
/* Check for floppy drive letter. */
if (winpath[0] && winpath[1] == ':' && strchr ("AaBb", winpath[0]))
return xstrdup (strchr ("Aa", winpath[0]) ? "/dev/fd0" : "/dev/fd1");
/* Cygwin returns the partition serial number in stat.st_dev.
This is never identical to the device number of the emulated
/dev/sdXN device, so above grub_find_device () does not work.
Search the partition with the same serial in boot sector instead. */
char devpath[sizeof ("/dev/sda15") + 13]; /* Size + Paranoia. */
int d;
for (d = 'a'; d <= 'z'; d++)
{
sprintf (devpath, "/dev/sd%c", d);
if (get_bootsec_serial (devpath, 1) == 0)
continue;
int p;
for (p = 1; p <= 15; p++)
{
sprintf (devpath, "/dev/sd%c%d", d, p);
unsigned ser = get_bootsec_serial (devpath, 0);
if (ser == 0)
break;
if (ser != (unsigned)~0 && dev == (dev_t)ser)
return xstrdup (devpath);
}
}
return 0;
}
#endif /* __CYGWIN__ */
char *
grub_guess_root_device (const char *dir)
{
char *os_dev = NULL;
#ifdef __GNU__
file_t file;
mach_port_t *ports;
int *ints;
loff_t *offsets;
char *data;
error_t err;
mach_msg_type_number_t num_ports = 0, num_ints = 0, num_offsets = 0, data_len = 0;
size_t name_len;
file = file_name_lookup (dir, 0, 0);
if (file == MACH_PORT_NULL)
return 0;
err = file_get_storage_info (file,
&ports, &num_ports,
&ints, &num_ints,
&offsets, &num_offsets,
&data, &data_len);
if (num_ints < 1)
grub_util_error ("Storage info for `%s' does not include type", dir);
if (ints[0] != STORAGE_DEVICE)
grub_util_error ("Filesystem of `%s' is not stored on local disk", dir);
if (num_ints < 5)
grub_util_error ("Storage info for `%s' does not include name", dir);
name_len = ints[4];
if (name_len < data_len)
grub_util_error ("Bogus name length for storage info for `%s'", dir);
if (data[name_len - 1] != '\0')
grub_util_error ("Storage name for `%s' not NUL-terminated", dir);
os_dev = xmalloc (strlen ("/dev/") + data_len);
memcpy (os_dev, "/dev/", strlen ("/dev/"));
memcpy (os_dev + strlen ("/dev/"), data, data_len);
if (ports && num_ports > 0)
{
mach_msg_type_number_t i;
for (i = 0; i < num_ports; i++)
{
mach_port_t port = ports[i];
if (port != MACH_PORT_NULL)
mach_port_deallocate (mach_task_self(), port);
}
munmap ((caddr_t) ports, num_ports * sizeof (*ports));
}
if (ints && num_ints > 0)
munmap ((caddr_t) ints, num_ints * sizeof (*ints));
if (offsets && num_offsets > 0)
munmap ((caddr_t) offsets, num_offsets * sizeof (*offsets));
if (data && data_len > 0)
munmap (data, data_len);
mach_port_deallocate (mach_task_self (), file);
#else /* !__GNU__ */
struct stat st;
dev_t dev;
#ifdef __linux__
if (!os_dev)
os_dev = grub_find_root_device_from_mountinfo (dir, NULL);
#endif /* __linux__ */
#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
if (!os_dev)
os_dev = find_root_device_from_libzfs (dir);
#endif
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, dev);
#else
/* This might be truly slow, but is there any better way? */
os_dev = grub_find_device ("/dev", dev);
#endif
#endif /* !__GNU__ */
return os_dev;
}
static int
grub_util_is_lvm (const char *os_dev)
{
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;
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
grub_util_get_dev_abstraction (const char *os_dev __attribute__((unused)))
{
#ifdef __linux__
/* User explicitly claims that this drive is visible by BIOS. */
if (grub_util_biosdisk_is_present (os_dev))
return GRUB_DEV_ABSTRACTION_NONE;
/* Check for LVM. */
if (grub_util_is_lvm (os_dev))
return GRUB_DEV_ABSTRACTION_LVM;
/* Check for RAID. */
if (!strncmp (os_dev, "/dev/md", 7) && ! grub_util_device_is_mapped (os_dev))
return GRUB_DEV_ABSTRACTION_RAID;
#endif
/* No abstraction found. */
return GRUB_DEV_ABSTRACTION_NONE;
}
#ifdef __linux__
static char *
get_mdadm_uuid (const char *os_dev)
{
int mdadm_pipe[2];
pid_t mdadm_pid;
char *name = NULL;
if (pipe (mdadm_pipe) < 0)
{
grub_util_warn ("Unable to create pipe for mdadm: %s", strerror (errno));
return NULL;
}
mdadm_pid = fork ();
if (mdadm_pid < 0)
grub_util_warn ("Unable to fork mdadm: %s", strerror (errno));
else if (mdadm_pid == 0)
{
/* Child. */
char *argv[5];
close (mdadm_pipe[0]);
dup2 (mdadm_pipe[1], STDOUT_FILENO);
close (mdadm_pipe[1]);
/* execvp has inconvenient types, hence the casts. None of these
strings will actually be modified. */
argv[0] = (char *) "mdadm";
argv[1] = (char *) "--detail";
argv[2] = (char *) "--export";
argv[3] = (char *) os_dev;
argv[4] = NULL;
execvp ("mdadm", argv);
exit (127);
}
else
{
/* Parent. Read mdadm's output. */
FILE *mdadm;
char *buf = NULL;
size_t len = 0;
close (mdadm_pipe[1]);
mdadm = fdopen (mdadm_pipe[0], "r");
if (! mdadm)
{
grub_util_warn ("Unable to open stream from mdadm: %s",
strerror (errno));
goto out;
}
while (getline (&buf, &len, mdadm) > 0)
{
if (strncmp (buf, "MD_UUID=", sizeof ("MD_UUID=") - 1) == 0)
{
char *name_start, *ptri, *ptro;
size_t name_len;
free (name);
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;
}
}
out:
close (mdadm_pipe[0]);
waitpid (mdadm_pid, NULL, 0);
}
return name;
}
#endif /* __linux__ */
char *
grub_util_get_grub_dev (const char *os_dev)
{
char *grub_dev = NULL;
switch (grub_util_get_dev_abstraction (os_dev))
{
case GRUB_DEV_ABSTRACTION_LVM:
{
unsigned short i, len;
grub_size_t offset = sizeof ("/dev/mapper/") - 1;
len = strlen (os_dev) - offset + 1;
grub_dev = xmalloc (len);
for (i = 0; i < len; i++, offset++)
{
grub_dev[i] = os_dev[offset];
if (os_dev[offset] == '-' && os_dev[offset + 1] == '-')
offset++;
}
}
break;
case GRUB_DEV_ABSTRACTION_RAID:
if (os_dev[7] == '_' && os_dev[8] == 'd')
{
/* This a partitionable RAID device of the form /dev/md_dNNpMM. */
char *p, *q;
p = strdup (os_dev + sizeof ("/dev/md_d") - 1);
q = strchr (p, 'p');
if (q)
*q = ',';
grub_dev = xasprintf ("md%s", p);
free (p);
}
else if (os_dev[7] == '/' && os_dev[8] == 'd')
{
/* This a partitionable RAID device of the form /dev/md/dNNpMM. */
char *p, *q;
p = strdup (os_dev + sizeof ("/dev/md/d") - 1);
q = strchr (p, 'p');
if (q)
*q = ',';
grub_dev = xasprintf ("md%s", p);
free (p);
}
else if (os_dev[7] >= '0' && os_dev[7] <= '9')
{
char *p , *q;
p = strdup (os_dev + sizeof ("/dev/md") - 1);
q = strchr (p, 'p');
if (q)
*q = ',';
grub_dev = xasprintf ("md%s", p);
free (p);
}
else if (os_dev[7] == '/' && os_dev[8] >= '0' && os_dev[8] <= '9')
{
char *p , *q;
p = strdup (os_dev + sizeof ("/dev/md/") - 1);
q = strchr (p, 'p');
if (q)
*q = ',';
grub_dev = xasprintf ("md%s", p);
free (p);
}
else if (os_dev[7] == '/')
{
/* mdraid 1.x with a free name. */
char *p , *q;
p = strdup (os_dev + sizeof ("/dev/md/") - 1);
q = strchr (p, 'p');
if (q)
*q = ',';
grub_dev = xasprintf ("md/%s", p);
free (p);
}
else
grub_util_error ("unknown kind of RAID device `%s'", os_dev);
#ifdef __linux__
{
char *mdadm_name = get_mdadm_uuid (os_dev);
struct stat st;
if (mdadm_name)
{
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 ("mduuid/%s,%s", mdadm_name, q + 1);
goto done;
}
free (grub_dev);
grub_dev = xasprintf ("mduuid/%s", mdadm_name);
done:
free (mdadm_name);
}
}
#endif /* __linux__ */
break;
default: /* GRUB_DEV_ABSTRACTION_NONE */
grub_dev = grub_util_biosdisk_get_grub_dev (os_dev);
}
return grub_dev;
}
const char *
grub_util_check_block_device (const char *blk_dev)
{
struct stat st;
if (stat (blk_dev, &st) < 0)
grub_util_error ("cannot stat `%s'", blk_dev);
if (S_ISBLK (st.st_mode))
return (blk_dev);
else
return 0;
}
const char *
grub_util_check_char_device (const char *blk_dev)
{
struct stat st;
if (stat (blk_dev, &st) < 0)
grub_util_error ("cannot stat `%s'", blk_dev);
if (S_ISCHR (st.st_mode))
return (blk_dev);
else
return 0;
}

View file

@ -43,6 +43,7 @@
#ifdef __linux__
# include <sys/ioctl.h> /* ioctl */
# include <sys/mount.h>
# if !defined(__GLIBC__) || \
((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
/* Maybe libc doesn't have large file support. */
@ -93,10 +94,16 @@ struct hd_geometry
# include <sys/disk.h> /* DIOCGMEDIASIZE */
# include <sys/param.h>
# include <sys/sysctl.h>
# include <sys/mount.h>
#include <libgeom.h>
# define MAJOR(dev) major(dev)
# define FLOPPY_MAJOR 2
#endif
#if defined (__sun__)
# include <sys/dkio.h>
#endif
#if defined(__APPLE__)
# include <sys/disk.h>
#endif
@ -105,9 +112,7 @@ struct hd_geometry
# include <libdevmapper.h>
#endif
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#include <libgeom.h>
#elif defined(__NetBSD__)
#if defined(__NetBSD__)
# define HAVE_DIOCGDINFO
# include <sys/ioctl.h>
# include <sys/disklabel.h> /* struct disklabel */
@ -187,6 +192,27 @@ configure_device_driver (int fd)
}
#endif /* defined(__NetBSD__) */
static int
unescape_cmp (const char *a, const char *b_escaped)
{
while (*a || *b_escaped)
{
if (*b_escaped == '\\' && b_escaped[1] != 0)
b_escaped++;
if (*a < *b_escaped)
return -1;
if (*a > *b_escaped)
return +1;
a++;
b_escaped++;
}
if (*a)
return +1;
if (*b_escaped)
return -1;
return 0;
}
static int
find_grub_drive (const char *name)
{
@ -195,7 +221,7 @@ find_grub_drive (const char *name)
if (name)
{
for (i = 0; i < ARRAY_SIZE (map); i++)
if (map[i].drive && ! strcmp (map[i].drive, name))
if (map[i].drive && unescape_cmp (map[i].drive, name) == 0)
return i;
}
@ -215,10 +241,14 @@ find_free_slot (void)
}
static int
grub_util_biosdisk_iterate (int (*hook) (const char *name))
grub_util_biosdisk_iterate (int (*hook) (const char *name),
grub_disk_pull_t pull)
{
unsigned i;
if (pull != GRUB_DISK_PULL_NONE)
return 0;
for (i = 0; i < sizeof (map) / sizeof (map[0]); i++)
if (map[i].drive && hook (map[i].drive))
return 1;
@ -226,6 +256,98 @@ grub_util_biosdisk_iterate (int (*hook) (const char *name))
return 0;
}
#if !defined(__MINGW32__)
grub_uint64_t
grub_util_get_fd_sectors (int fd, unsigned *log_secsize)
{
# if defined(__NetBSD__)
struct disklabel label;
# elif defined (__sun__)
struct dk_minfo minfo;
#else
unsigned long long nr;
# endif
unsigned sector_size, log_sector_size;
struct stat st;
if (fstat (fd, &st) < 0)
grub_util_error (_("fstat failed"));
#if defined(__linux__) || defined(__CYGWIN__) || defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) \
|| defined (__sun__)
# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) || defined (__sun__)
if (! S_ISCHR (st.st_mode))
# else
if (! S_ISBLK (st.st_mode))
# endif
goto fail;
# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
if (ioctl (fd, DIOCGMEDIASIZE, &nr))
# elif defined(__APPLE__)
if (ioctl (fd, DKIOCGETBLOCKCOUNT, &nr))
# elif defined(__NetBSD__)
configure_device_driver (fd);
if (ioctl (fd, DIOCGDINFO, &label) == -1)
# elif defined (__sun__)
if (!ioctl (fd, DKIOCGMEDIAINFO, &minfo))
# else
if (ioctl (fd, BLKGETSIZE64, &nr))
# endif
goto fail;
# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
if (ioctl (fd, DIOCGSECTORSIZE, &sector_size))
goto fail;
# elif defined(__sun__)
sector_size = minfo.dki_lbsize;
# elif defined(__NetBSD__)
sector_size = label.d_secsize;
# else
if (ioctl (fd, BLKSSZGET, &sector_size))
goto fail;
# endif
if (sector_size & (sector_size - 1) || !sector_size)
goto fail;
for (log_sector_size = 0;
(1 << log_sector_size) < sector_size;
log_sector_size++);
if (log_secsize)
*log_secsize = log_sector_size;
# if defined (__APPLE__)
return nr;
# elif defined(__NetBSD__)
return label.d_secperunit;
# elif defined (__sun__)
return minfo.dki_capacity;
# else
if (nr & ((1 << log_sector_size) - 1))
grub_util_error (_("unaligned device size"));
return (nr >> log_sector_size);
# endif
fail:
/* In GNU/Hurd, stat() will return the right size. */
#elif !defined (__GNU__)
# warning "No special routine to get the size of a block device is implemented for your OS. This is not possibly fatal."
#endif
sector_size = 512;
log_sector_size = 9;
if (log_secsize)
*log_secsize = 9;
return st.st_size >> 9;
}
#endif
static grub_err_t
grub_util_biosdisk_open (const char *name, grub_disk_t disk)
{
@ -254,7 +376,7 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk)
size = grub_util_get_disk_size (map[drive].device);
if (size % 512)
grub_util_error ("unaligned device size");
grub_util_error (_("unaligned device size"));
disk->total_sectors = size >> 9;
@ -262,77 +384,30 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk)
return GRUB_ERR_NONE;
}
#elif defined(__linux__) || defined(__CYGWIN__) || defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__)
#else
{
# if defined(__NetBSD__)
struct disklabel label;
# else
unsigned long long nr;
# endif
int fd;
fd = open (map[drive].device, O_RDONLY);
if (fd == -1)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "cannot open `%s' while attempting to get disk size", map[drive].device);
disk->total_sectors = grub_util_get_fd_sectors (fd, &disk->log_sector_size);
# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__)
if (fstat (fd, &st) < 0 || ! S_ISCHR (st.st_mode))
# else
if (fstat (fd, &st) < 0 || ! S_ISBLK (st.st_mode))
# endif
{
close (fd);
goto fail;
}
data->is_disk = 1;
# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
if (ioctl (fd, DIOCGMEDIASIZE, &nr))
# elif defined(__APPLE__)
if (ioctl (fd, DKIOCGETBLOCKCOUNT, &nr))
# elif defined(__NetBSD__)
configure_device_driver (fd);
if (ioctl (fd, DIOCGDINFO, &label) == -1)
# else
if (ioctl (fd, BLKGETSIZE64, &nr))
# endif
{
close (fd);
goto fail;
}
data->is_disk = 1;
close (fd);
# if defined (__APPLE__)
disk->total_sectors = nr;
# elif defined(__NetBSD__)
disk->total_sectors = label.d_secperunit;
# else
disk->total_sectors = nr / 512;
if (nr % 512)
grub_util_error ("unaligned device size");
# endif
grub_util_info ("the size of %s is %llu", name, disk->total_sectors);
return GRUB_ERR_NONE;
}
fail:
/* In GNU/Hurd, stat() will return the right size. */
#elif !defined (__GNU__)
# warning "No special routine to get the size of a block device is implemented for your OS. This is not possibly fatal."
#endif
if (stat (map[drive].device, &st) < 0)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "cannot stat `%s'", map[drive].device);
disk->total_sectors = st.st_size >> GRUB_DISK_SECTOR_BITS;
grub_util_info ("the size of %s is %lu", name, disk->total_sectors);
return GRUB_ERR_NONE;
}
int
@ -353,11 +428,13 @@ grub_util_device_is_mapped (const char *dev)
#endif /* HAVE_DEVICE_MAPPER */
}
#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)
void
grub_util_follow_gpart_up (const char *name, grub_disk_addr_t *off_out, char **name_out)
{
struct gmesh mesh;
struct gclass *class;
@ -368,13 +445,13 @@ follow_geom_up (const char *name, grub_disk_addr_t *off_out, char **name_out)
error = geom_gettree (&mesh);
if (error != 0)
grub_util_error ("couldn't open geom");
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");
grub_util_error (_("couldn't open geom part"));
LIST_FOREACH (geom, &class->lg_geom, lg_geom)
{
@ -387,7 +464,7 @@ follow_geom_up (const char *name, grub_disk_addr_t *off_out, char **name_out)
struct gconfig *config;
grub_util_info ("geom '%s' has parent '%s'", name, geom->lg_name);
follow_geom_up (name_tmp, &off, name_out);
grub_util_follow_gpart_up (name_tmp, &off, name_out);
free (name_tmp);
LIST_FOREACH (config, &provider->lg_config, lg_config)
if (strcasecmp (config->lg_name, "start") == 0)
@ -410,16 +487,19 @@ 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);
grub_util_follow_gpart_up (dev + sizeof ("/dev/") - 1, &out, NULL);
return out;
}
#elif defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO)
#elif defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined (__sun__)
static grub_disk_addr_t
find_partition_start (const char *dev)
{
int fd;
# if !defined(HAVE_DIOCGDINFO)
#ifdef __sun__
struct extpart_info pinfo;
# elif !defined(HAVE_DIOCGDINFO)
struct hd_geometry hdg;
# else /* defined(HAVE_DIOCGDINFO) */
struct disklabel label;
@ -506,7 +586,9 @@ devmapper_fail:
return 0;
}
# if !defined(HAVE_DIOCGDINFO)
#if defined(__sun__)
if (ioctl (fd, DKIOCEXTPARTINFO, &pinfo))
# elif !defined(HAVE_DIOCGDINFO)
if (ioctl (fd, HDIO_GETGEO, &hdg))
# else /* defined(HAVE_DIOCGDINFO) */
# if defined(__NetBSD__)
@ -527,7 +609,9 @@ devmapper_fail:
close (fd);
# if !defined(HAVE_DIOCGDINFO)
#ifdef __sun__
return pinfo.p_start;
# elif !defined(HAVE_DIOCGDINFO)
return hdg.start;
# else /* defined(HAVE_DIOCGDINFO) */
if (dev[0])
@ -567,6 +651,7 @@ linux_find_partition (char *dev, grub_disk_addr_t sector)
int i;
char real_dev[PATH_MAX];
struct linux_partition_cache *cache;
int missing = 0;
strcpy(real_dev, dev);
@ -575,6 +660,12 @@ linux_find_partition (char *dev, grub_disk_addr_t 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;
@ -605,7 +696,13 @@ linux_find_partition (char *dev, grub_disk_addr_t sector)
fd = open (real_dev, O_RDONLY);
if (fd == -1)
continue;
{
if (missing++ < 10)
continue;
else
return 0;
}
missing = 0;
close (fd);
start = find_partition_start (real_dev);
@ -632,6 +729,37 @@ linux_find_partition (char *dev, grub_disk_addr_t sector)
}
#endif /* __linux__ */
#if defined(__linux__) && (!defined(__GLIBC__) || \
((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
/* Maybe libc doesn't have large file support. */
grub_err_t
grub_util_fd_seek (int fd, const char *name, grub_uint64_t off)
{
loff_t offset, result;
static int _llseek (uint filedes, ulong hi, ulong lo,
loff_t *res, uint wh);
_syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo,
loff_t *, res, uint, wh);
offset = (loff_t) off;
if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
{
return grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", name);
}
return GRUB_ERR_NONE;
}
#else
grub_err_t
grub_util_fd_seek (int fd, const char *name, grub_uint64_t off)
{
off_t offset = (off_t) off;
if (lseek (fd, offset, SEEK_SET) != offset)
return grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", name);
return 0;
}
#endif
static int
open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
{
@ -784,44 +912,20 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
configure_device_driver (fd);
#endif /* defined(__NetBSD__) */
#if defined(__linux__) && (!defined(__GLIBC__) || \
((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
/* Maybe libc doesn't have large file support. */
{
loff_t offset, result;
static int _llseek (uint filedes, ulong hi, ulong lo,
loff_t *res, uint wh);
_syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo,
loff_t *, res, uint, wh);
offset = (loff_t) sector << GRUB_DISK_SECTOR_BITS;
if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
{
grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id].device);
close (fd);
return -1;
}
}
#else
{
off_t offset = (off_t) sector << GRUB_DISK_SECTOR_BITS;
if (lseek (fd, offset, SEEK_SET) != offset)
{
grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id].device);
close (fd);
return -1;
}
}
#endif
if (grub_util_fd_seek (fd, map[disk->id].device,
sector << disk->log_sector_size))
{
close (fd);
return -1;
}
return fd;
}
/* Read LEN bytes from FD in BUF. Return less than or equal to zero if an
error occurs, otherwise return LEN. */
static ssize_t
nread (int fd, char *buf, size_t len)
ssize_t
grub_util_fd_read (int fd, char *buf, size_t len)
{
ssize_t size = len;
@ -904,19 +1008,20 @@ grub_util_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
sectors that are read together with the MBR in one read. It
should only remap the MBR, so we split the read in two
parts. -jochen */
if (nread (fd, buf, GRUB_DISK_SECTOR_SIZE) != GRUB_DISK_SECTOR_SIZE)
if (grub_util_fd_read (fd, buf, (1 << disk->log_sector_size))
!= (1 << disk->log_sector_size))
{
grub_error (GRUB_ERR_READ_ERROR, "cannot read `%s'", map[disk->id].device);
return grub_errno;
}
buf += GRUB_DISK_SECTOR_SIZE;
buf += (1 << disk->log_sector_size);
size--;
}
#endif /* __linux__ */
if (nread (fd, buf, size << GRUB_DISK_SECTOR_BITS)
!= (ssize_t) (size << GRUB_DISK_SECTOR_BITS))
if (grub_util_fd_read (fd, buf, size << disk->log_sector_size)
!= (ssize_t) (size << disk->log_sector_size))
grub_error (GRUB_ERR_READ_ERROR, "cannot read from `%s'", map[disk->id].device);
return grub_errno;
@ -949,8 +1054,8 @@ grub_util_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector,
if (fd < 0)
return grub_errno;
if (nwrite (fd, buf, size << GRUB_DISK_SECTOR_BITS)
!= (ssize_t) (size << GRUB_DISK_SECTOR_BITS))
if (nwrite (fd, buf, size << disk->log_sector_size)
!= (ssize_t) (size << disk->log_sector_size))
grub_error (GRUB_ERR_WRITE_ERROR, "cannot write to `%s'", map[disk->id].device);
return grub_errno;
@ -1048,18 +1153,18 @@ read_device_map (const char *dev_map)
continue;
if (*p != '(')
show_error ("No open parenthesis found");
show_error (_("No open parenthesis found"));
p++;
/* Find a free slot. */
drive = find_free_slot ();
if (drive < 0)
show_error ("Map table size exceeded");
show_error (_("Map table size exceeded"));
e = p;
p = strchr (p, ')');
if (! p)
show_error ("No close parenthesis found");
show_error (_("No close parenthesis found"));
map[drive].drive = xmalloc (p - e + sizeof ('\0'));
strncpy (map[drive].drive, e, p - e + sizeof ('\0'));
@ -1072,7 +1177,7 @@ read_device_map (const char *dev_map)
p++;
if (*p == '\0')
show_error ("No filename found");
show_error (_("No filename found"));
/* NUL-terminate the filename. */
e = p;
@ -1101,7 +1206,7 @@ read_device_map (const char *dev_map)
{
map[drive].device = xmalloc (PATH_MAX);
if (! realpath (p, map[drive].device))
grub_util_error ("cannot get the real path of `%s'", p);
grub_util_error (_("cannot get the real path of `%s'"), p);
}
else
#endif
@ -1142,25 +1247,28 @@ grub_util_biosdisk_fini (void)
static char *
make_device_name (int drive, int dos_part, int bsd_part)
{
char *ret;
char *dos_part_str = NULL;
char *bsd_part_str = NULL;
char *ret, *ptr, *end;
const char *iptr;
ret = xmalloc (strlen (map[drive].drive) * 2
+ sizeof (",XXXXXXXXXXXXXXXXXXXXXXXXXX"
",XXXXXXXXXXXXXXXXXXXXXXXXXX"));
end = (ret + strlen (map[drive].drive) * 2
+ sizeof (",XXXXXXXXXXXXXXXXXXXXXXXXXX"
",XXXXXXXXXXXXXXXXXXXXXXXXXX"));
ptr = ret;
for (iptr = map[drive].drive; *iptr; iptr++)
{
if (*iptr == ',')
*ptr++ = '\\';
*ptr++ = *iptr;
}
*ptr = 0;
if (dos_part >= 0)
dos_part_str = xasprintf (",%d", dos_part + 1);
snprintf (ptr, end - ptr, ",%d", dos_part + 1);
ptr += strlen (ptr);
if (bsd_part >= 0)
bsd_part_str = xasprintf (",%d", bsd_part + 1);
ret = xasprintf ("%s%s%s", map[drive].drive,
dos_part_str ? : "",
bsd_part_str ? : "");
if (dos_part_str)
free (dos_part_str);
if (bsd_part_str)
free (bsd_part_str);
snprintf (ptr, end - ptr, ",%d", bsd_part + 1);
return ret;
}
@ -1418,7 +1526,8 @@ convert_system_partition_to_system_disk (const char *os_dev, struct stat *st)
if (tree)
dm_tree_free (tree);
free (path);
char *ret = grub_find_device (NULL, (major << 8) | minor);
char *ret = grub_find_device ("/dev",
(major << 8) | minor);
return ret;
}
@ -1496,7 +1605,7 @@ devmapper_out:
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);
grub_util_follow_gpart_up (os_dev + sizeof ("/dev/") - 1, NULL, &out);
out2 = xasprintf ("/dev/%s", out);
free (out);
@ -1545,12 +1654,37 @@ devmapper_out:
}
return path;
#elif defined (__sun__)
char *colon = grub_strrchr (os_dev, ':');
if (grub_memcmp (os_dev, "/devices", sizeof ("/devices") - 1) == 0
&& colon)
{
char *ret = xmalloc (colon - os_dev + sizeof (":q,raw"));
grub_memcpy (ret, os_dev, colon - os_dev);
grub_memcpy (ret + (colon - os_dev), ":q,raw", sizeof (":q,raw"));
return ret;
}
else
return xstrdup (os_dev);
#else
# warning "The function `convert_system_partition_to_system_disk' might not work on your OS correctly."
return xstrdup (os_dev);
#endif
}
#if defined(__sun__)
static int
device_is_wholedisk (const char *os_dev)
{
if (grub_memcmp (os_dev, "/devices/", sizeof ("/devices/") - 1) != 0)
return 1;
if (grub_memcmp (os_dev + strlen (os_dev) - (sizeof (":q,raw") - 1),
":q,raw", (sizeof (":q,raw") - 1)) == 0)
return 1;
return 0;
}
#endif
#if defined(__linux__) || defined(__CYGWIN__)
static int
device_is_wholedisk (const char *os_dev)
@ -1627,7 +1761,10 @@ find_system_device (const char *os_dev, struct stat *st, int convert, int add)
}
if (!add)
return -1;
{
free (os_disk);
return -1;
}
if (i == ARRAY_SIZE (map))
grub_util_error (_("device count exceeds limit"));
@ -1657,6 +1794,9 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
{
struct stat st;
int drive;
char *sys_disk;
grub_util_info ("Looking for %s", os_dev);
if (stat (os_dev, &st) < 0)
{
@ -1674,18 +1814,22 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
return 0;
}
if (grub_strcmp (os_dev,
convert_system_partition_to_system_disk (os_dev, &st)) == 0)
return make_device_name (drive, -1, -1);
sys_disk = convert_system_partition_to_system_disk (os_dev, &st);
if (grub_strcmp (os_dev, sys_disk) == 0)
{
free (sys_disk);
return make_device_name (drive, -1, -1);
}
free (sys_disk);
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__)
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) || defined (__sun__)
if (! S_ISCHR (st.st_mode))
#else
if (! S_ISBLK (st.st_mode))
#endif
return make_device_name (drive, -1, -1);
#if defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#if defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__sun__)
/* Linux counts partitions uniformly, whether a BSD partition or a DOS
partition, so mapping them to GRUB devices is not trivial.
@ -1725,7 +1869,7 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
name = make_device_name (drive, -1, -1);
# if !defined(HAVE_DIOCGDINFO)
# if !defined(HAVE_DIOCGDINFO) && !defined(__sun__)
if (MAJOR (st.st_rdev) == FLOPPY_MAJOR)
return name;
# else /* defined(HAVE_DIOCGDINFO) */
@ -1788,6 +1932,7 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
if (partname == NULL)
{
grub_disk_close (disk);
grub_util_info ("cannot find the partition of `%s'", os_dev);
grub_error (GRUB_ERR_BAD_DEVICE,
"cannot find the partition of `%s'", os_dev);
return 0;
@ -1851,6 +1996,9 @@ grub_util_biosdisk_is_floppy (grub_disk_t disk)
struct stat st;
int fd;
if (disk->dev != &grub_util_biosdisk_dev)
return 0;
fd = open (map[disk->id].device, O_RDONLY);
/* Shouldn't happen. */
if (fd == -1)
@ -1858,7 +2006,12 @@ grub_util_biosdisk_is_floppy (grub_disk_t disk)
/* Shouldn't happen either. */
if (fstat (fd, &st) < 0)
return 0;
{
close (fd);
return 0;
}
close (fd);
#if defined(__NetBSD__)
if (major(st.st_rdev) == RAW_FLOPPY_MAJOR)

View file

@ -49,15 +49,11 @@
static jmp_buf main_env;
/* Store the prefix specified by an argument. */
static char *prefix = NULL;
static char *root_dev = NULL, *dir = NULL;
int grub_no_autoload;
grub_addr_t
grub_arch_modules_addr (void)
{
return 0;
}
grub_addr_t grub_modbase = 0;
void
grub_reboot (void)
@ -71,11 +67,10 @@ grub_machine_init (void)
}
void
grub_machine_set_prefix (void)
grub_machine_get_bootlocation (char **device, char **path)
{
grub_env_set ("prefix", prefix);
free (prefix);
prefix = 0;
*device = root_dev;
*path = dir;
}
void
@ -103,14 +98,14 @@ usage (int status)
{
if (status)
fprintf (stderr,
"Try `%s --help' for more information.\n", program_name);
_("Try `%s --help' for more information.\n"), program_name);
else
printf (
"Usage: %s [OPTION]...\n"
_("Usage: %s [OPTION]...\n"
"\n"
"GRUB emulator.\n"
"\n"
" -r, --root-device=DEV use DEV as the root device [default=guessed]\n"
" -r, --root-device=DEV use DEV as the root device [default=host]\n"
" -m, --device-map=FILE use FILE as the device map [default=%s]\n"
" -d, --directory=DIR use GRUB files in the directory DIR [default=%s]\n"
" -v, --verbose print verbose messages\n"
@ -118,7 +113,7 @@ usage (int status)
" -h, --help display this message and exit\n"
" -V, --version print version information and exit\n"
"\n"
"Report bugs to <%s>.\n", program_name, DEFAULT_DEVICE_MAP, DEFAULT_DIRECTORY, PACKAGE_BUGREPORT);
"Report bugs to <%s>.\n"), program_name, DEFAULT_DEVICE_MAP, DEFAULT_DIRECTORY, PACKAGE_BUGREPORT);
return status;
}
@ -132,22 +127,24 @@ void grub_emu_init (void);
int
main (int argc, char *argv[])
{
char *root_dev = 0;
char *dir = DEFAULT_DIRECTORY;
char *dev_map = DEFAULT_DEVICE_MAP;
const char *dev_map = DEFAULT_DEVICE_MAP;
volatile int hold = 0;
int opt;
set_program_name (argv[0]);
dir = xstrdup (DEFAULT_DIRECTORY);
while ((opt = getopt_long (argc, argv, "r:d:m:vH:hV", options, 0)) != -1)
switch (opt)
{
case 'r':
root_dev = optarg;
free (root_dev);
root_dev = xstrdup (optarg);
break;
case 'd':
dir = optarg;
free (dir);
dir = xstrdup (optarg);
break;
case 'm':
dev_map = optarg;
@ -169,13 +166,13 @@ main (int argc, char *argv[])
if (optind < argc)
{
fprintf (stderr, "Unknown extra argument `%s'.\n", argv[optind]);
fprintf (stderr, _("Unknown extra argument `%s'.\n"), argv[optind]);
return usage (1);
}
/* Wait until the ARGS.HOLD variable is cleared by an attached debugger. */
if (hold && verbosity > 0)
printf ("Run \"gdb %s %d\", and set ARGS.HOLD to zero.\n",
printf (_("Run \"gdb %s %d\", and set ARGS.HOLD to zero.\n"),
program_name, (int) getpid ());
while (hold)
{
@ -201,27 +198,9 @@ main (int argc, char *argv[])
/* Make sure that there is a root device. */
if (! root_dev)
{
char *device_name = grub_guess_root_device (dir);
if (! device_name)
grub_util_error ("cannot find a device for %s", dir);
root_dev = grub_strdup ("host");
root_dev = grub_util_get_grub_dev (device_name);
if (! root_dev)
{
grub_util_info ("guessing the root device failed, because of `%s'",
grub_errmsg);
grub_util_error ("cannot guess the root device. Specify the option `--root-device'");
}
}
if (strcmp (root_dev, "host") == 0)
dir = xstrdup (dir);
else
dir = grub_make_system_path_relative_to_its_root (dir);
prefix = xmalloc (strlen (root_dev) + 2 + strlen (dir) + 1);
sprintf (prefix, "(%s)%s", root_dev, dir);
free (dir);
dir = xstrdup (dir);
/* Start GRUB! */
if (setjmp (main_env) == 0)

View file

@ -46,14 +46,6 @@
# include <libdevmapper.h>
#endif
#ifdef HAVE_LIBZFS
# include <grub/util/libzfs.h>
#endif
#ifdef HAVE_LIBNVPAIR
# include <grub/util/libnvpair.h>
#endif
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
@ -125,7 +117,7 @@ xmalloc (grub_size_t size)
p = malloc (size);
if (! p)
grub_util_error ("out of memory");
grub_util_error (_("out of memory"));
return p;
}
@ -135,7 +127,7 @@ xrealloc (void *ptr, grub_size_t size)
{
ptr = realloc (ptr, size);
if (! ptr)
grub_util_error ("out of memory");
grub_util_error (_("out of memory"));
return ptr;
}
@ -193,7 +185,7 @@ xasprintf (const char *fmt, ...)
if (vasprintf (&result, fmt, ap) < 0)
{
if (errno == ENOMEM)
grub_util_error ("out of memory");
grub_util_error (_("out of memory"));
return NULL;
}
@ -232,7 +224,11 @@ char *
canonicalize_file_name (const char *path)
{
char *ret;
#ifdef PATH_MAX
#ifdef __MINGW32__
ret = xmalloc (PATH_MAX);
if (!_fullpath (ret, path, PATH_MAX))
return NULL;
#elif defined (PATH_MAX)
ret = xmalloc (PATH_MAX);
if (!realpath (path, ret))
return NULL;
@ -242,265 +238,6 @@ canonicalize_file_name (const char *path)
return ret;
}
#ifdef __CYGWIN__
/* Convert POSIX path to Win32 path,
remove drive letter, replace backslashes. */
static char *
get_win32_path (const char *path)
{
char winpath[PATH_MAX];
if (cygwin_conv_path (CCP_POSIX_TO_WIN_A, path, winpath, sizeof(winpath)))
grub_util_error ("cygwin_conv_path() failed");
int len = strlen (winpath);
int offs = (len > 2 && winpath[1] == ':' ? 2 : 0);
int i;
for (i = offs; i < len; i++)
if (winpath[i] == '\\')
winpath[i] = '/';
return xstrdup (winpath + offs);
}
#endif
#ifdef HAVE_LIBZFS
static libzfs_handle_t *__libzfs_handle;
static void
fini_libzfs (void)
{
libzfs_fini (__libzfs_handle);
}
libzfs_handle_t *
grub_get_libzfs_handle (void)
{
if (! __libzfs_handle)
{
__libzfs_handle = libzfs_init ();
if (__libzfs_handle)
atexit (fini_libzfs);
}
return __libzfs_handle;
}
#endif /* HAVE_LIBZFS */
#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
/* ZFS has similar problems to those of btrfs (see above). */
void
grub_find_zpool_from_dir (const char *dir, char **poolname, char **poolfs)
{
char *slash;
*poolname = *poolfs = NULL;
#if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) && defined(HAVE_STRUCT_STATFS_F_MNTFROMNAME)
/* FreeBSD and GNU/kFreeBSD. */
{
struct statfs mnt;
if (statfs (dir, &mnt) != 0)
return;
if (strcmp (mnt.f_fstypename, "zfs") != 0)
return;
*poolname = xstrdup (mnt.f_mntfromname);
}
#elif defined(HAVE_GETEXTMNTENT)
/* Solaris. */
{
struct stat st;
struct extmnttab mnt;
if (stat (dir, &st) != 0)
return;
FILE *mnttab = fopen ("/etc/mnttab", "r");
if (! mnttab)
return;
while (getextmntent (mnttab, &mnt, sizeof (mnt)) == 0)
{
if (makedev (mnt.mnt_major, mnt.mnt_minor) == st.st_dev
&& !strcmp (mnt.mnt_fstype, "zfs"))
{
*poolname = xstrdup (mnt.mnt_special);
break;
}
}
fclose (mnttab);
}
#endif
if (! *poolname)
return;
slash = strchr (*poolname, '/');
if (slash)
{
*slash = '\0';
*poolfs = xstrdup (slash + 1);
}
else
*poolfs = xstrdup ("");
}
#endif
/* This function never prints trailing slashes (so that its output
can be appended a slash unconditionally). */
char *
grub_make_system_path_relative_to_its_root (const char *path)
{
struct stat st;
char *p, *buf, *buf2, *buf3, *ret;
uintptr_t offset = 0;
dev_t num;
size_t len;
#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
char *poolfs = NULL;
#endif
/* canonicalize. */
p = canonicalize_file_name (path);
if (p == NULL)
grub_util_error ("failed to get canonical path of %s", path);
#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
/* For ZFS sub-pool filesystems, could be extended to others (btrfs?). */
{
char *dummy;
grub_find_zpool_from_dir (p, &dummy, &poolfs);
}
#endif
len = strlen (p) + 1;
buf = xstrdup (p);
free (p);
if (stat (buf, &st) < 0)
grub_util_error ("cannot stat %s: %s", buf, strerror (errno));
buf2 = xstrdup (buf);
num = st.st_dev;
/* This loop sets offset to the number of chars of the root
directory we're inspecting. */
while (1)
{
p = strrchr (buf, '/');
if (p == NULL)
/* This should never happen. */
grub_util_error ("FIXME: no / in buf. (make_system_path_relative_to_its_root)");
if (p != buf)
*p = 0;
else
*++p = 0;
if (stat (buf, &st) < 0)
grub_util_error ("cannot stat %s: %s", buf, strerror (errno));
/* buf is another filesystem; we found it. */
if (st.st_dev != num)
{
/* offset == 0 means path given is the mount point.
This works around special-casing of "/" in Un*x. This function never
prints trailing slashes (so that its output can be appended a slash
unconditionally). Each slash in is considered a preceding slash, and
therefore the root directory is an empty string. */
if (offset == 0)
{
free (buf);
#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)
return xasprintf ("/%s/@", poolfs);
#endif
return xstrdup ("");
}
else
break;
}
offset = p - buf;
/* offset == 1 means root directory. */
if (offset == 1)
{
/* Include leading slash. */
offset = 0;
break;
}
}
free (buf);
buf3 = xstrdup (buf2 + offset);
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__
if (st.st_dev != (DEV_CYGDRIVE_MAJOR << 16))
{
/* Reached some mount point not below /cygdrive.
GRUB does not know Cygwin's emulated mounts,
convert to Win32 path. */
grub_util_info ("Cygwin path = %s\n", buf3);
char * temp = get_win32_path (buf3);
free (buf3);
buf3 = temp;
}
#endif
parsedir:
/* Remove trailing slashes, return empty string if root directory. */
len = strlen (buf3);
while (len > 0 && buf3[len - 1] == '/')
{
buf3[len - 1] = '\0';
len--;
}
#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
if (poolfs)
{
ret = xasprintf ("/%s/@%s", poolfs, buf3);
free (buf3);
}
else
#endif
ret = buf3;
return ret;
}
#ifdef HAVE_DEVICE_MAPPER
static void device_mapper_null_log (int level __attribute__ ((unused)),
const char *file __attribute__ ((unused)),

View file

@ -77,7 +77,7 @@ grub_memalign (grub_size_t align, grub_size_t size)
#else
(void) align;
(void) size;
grub_util_error ("grub_memalign is not supported");
grub_util_error (_("grub_memalign is not supported"));
#endif
if (!p)

View file

@ -132,7 +132,7 @@ grub_env_set (const char *name, const char *val)
return grub_errno;
}
char *
const char *
grub_env_get (const char *name)
{
struct grub_env_var *var;

View file

@ -20,10 +20,13 @@
#include <grub/misc.h>
#include <grub/err.h>
#include <grub/file.h>
#include <grub/net.h>
#include <grub/mm.h>
#include <grub/fs.h>
#include <grub/device.h>
void (*EXPORT_VAR (grub_grubnet_fini)) (void);
grub_file_filter_t grub_file_filters_all[GRUB_FILE_FILTER_MAX];
grub_file_filter_t grub_file_filters_enabled[GRUB_FILE_FILTER_MAX];
@ -148,7 +151,6 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len)
if (len == 0)
return 0;
res = (file->fs->read) (file, buf, len);
if (res > 0)
file->offset += res;
@ -179,8 +181,9 @@ grub_file_seek (grub_file_t file, grub_off_t offset)
"attempt to seek outside of the file");
return -1;
}
old = file->offset;
file->offset = offset;
return old;
}

View file

@ -94,7 +94,7 @@ grub_fs_probe (grub_device_t device)
count--;
}
}
else if (device->net->fs)
else if (device->net && device->net->fs)
return device->net->fs;
grub_error (GRUB_ERR_UNKNOWN_FS, "unknown filesystem");

View file

@ -38,8 +38,9 @@
#include <grub/machine/kernel.h>
#endif
extern char _start[];
extern char _end[];
extern grub_uint8_t _start[];
extern grub_uint8_t _end[];
extern grub_uint8_t _edata[];
grub_uint32_t
grub_get_rtc (void)
@ -56,10 +57,18 @@ grub_exit (void)
grub_cpu_idle ();
}
#ifdef GRUB_MACHINE_QEMU
grub_addr_t grub_modbase;
#else
grub_addr_t grub_modbase = ALIGN_UP((grub_addr_t) _end, GRUB_KERNEL_MACHINE_MOD_ALIGN);
#endif
void
grub_machine_init (void)
{
#ifdef GRUB_MACHINE_QEMU
grub_modbase = grub_core_entry_addr + (_edata - _start);
grub_qemu_init_cirrus ();
#endif
/* Initialize the console as early as possible. */
@ -107,10 +116,9 @@ grub_machine_init (void)
}
void
grub_machine_set_prefix (void)
grub_machine_get_bootlocation (char **device __attribute__ ((unused)),
char **path __attribute__ ((unused)))
{
/* Initialize the prefix. */
grub_env_set ("prefix", grub_prefix);
}
void
@ -119,14 +127,3 @@ grub_machine_fini (void)
grub_vga_text_fini ();
grub_stop_floppy ();
}
/* Return the end of the core image. */
grub_addr_t
grub_arch_modules_addr (void)
{
#ifdef GRUB_MACHINE_QEMU
return grub_core_entry_addr + grub_kernel_image_size;
#else
return ALIGN_UP((grub_addr_t) _end, GRUB_KERNEL_MACHINE_MOD_ALIGN);
#endif
}

View file

@ -38,36 +38,6 @@
.globl start, _start
start:
_start:
jmp codestart
/*
* This is a special data area at a fixed offset from the beginning.
*/
. = _start + GRUB_KERNEL_MACHINE_PREFIX
VARIABLE(grub_prefix)
/* to be filled by grub-mkimage */
/*
* Leave some breathing room for the prefix.
*/
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END
/*
* Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself).
*/
.p2align 2 /* force 4-byte alignment */
multiboot_header:
/* magic */
.long 0x1BADB002
/* flags */
.long MULTIBOOT_MEMORY_INFO
/* checksum */
.long -0x1BADB002 - MULTIBOOT_MEMORY_INFO
codestart:
#ifdef GRUB_MACHINE_MULTIBOOT
cmpl $MULTIBOOT_BOOTLOADER_MAGIC, %eax
jne 0f
@ -81,9 +51,22 @@ codestart:
/* jump to the main body of C code */
jmp EXT_C(grub_main)
/*
* Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself).
*/
.p2align 2 /* force 4-byte alignment */
multiboot_header:
/* magic */
.long 0x1BADB002
/* flags */
.long MULTIBOOT_MEMORY_INFO
/* checksum */
.long -0x1BADB002 - MULTIBOOT_MEMORY_INFO
/*
* prot_to_real and associated structures (but NOT real_to_prot, that is
* only needed for BIOS gates).
*/
#include "../realmode.S"
#include "../int.S"

View file

@ -39,9 +39,3 @@ grub_machine_fini (void)
{
grub_efi_fini ();
}
void
grub_machine_set_prefix (void)
{
grub_efi_set_prefix ();
}

View file

@ -19,40 +19,12 @@
#include <config.h>
#include <grub/symbol.h>
#include <grub/boot.h>
.file "startup.S"
.text
.globl start, _start
start:
_start:
jmp codestart
/*
* Compatibility version number
*
* These MUST be at byte offset 6 and 7 of the executable
* DO NOT MOVE !!!
*/
. = _start + 0x6
.byte GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR
/*
* This is a special data area 8 bytes from the beginning.
*/
. = _start + 0x8
VARIABLE(grub_prefix)
/* to be filled by grub-mkimage */
/*
* Leave some breathing room for the prefix.
*/
. = _start + 0x50
codestart:
/*
* EFI_SYSTEM_TABLE * and EFI_HANDLE are passed on the stack.
*/
@ -62,5 +34,3 @@ codestart:
movl %eax, EXT_C(grub_efi_system_table)
call EXT_C(grub_main)
ret
#include "../realmode.S"

View file

@ -36,30 +36,6 @@
start:
_start:
jmp codestart
/*
* This is a special data area at a fixed offset from the beginning.
*/
. = _start + GRUB_KERNEL_MACHINE_PREFIX
VARIABLE(grub_prefix)
/* to be filled by grub-mkimage */
/*
* Leave some breathing room for the prefix.
*/
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END
codestart:
movl %eax, EXT_C(grub_ieee1275_entry_fn)
jmp EXT_C(grub_main)
/*
* prot_to_real and associated structures (but NOT real_to_prot, that is
* only needed for BIOS gates).
*/
#include "../realmode.S"

140
grub-core/kern/i386/int.S Normal file
View file

@ -0,0 +1,140 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010,2011 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/>.
*/
FUNCTION(grub_bios_interrupt)
pushf
cli
#ifndef GRUB_MACHINE_PCBIOS
sidt protidt
#endif
popf
pushl %ebp
pushl %ecx
pushl %eax
pushl %ebx
pushl %esi
pushl %edi
pushl %edx
movb %al, intno
movl (%edx), %eax
movl %eax, LOCAL(bios_register_eax)
movw 4(%edx), %ax
movw %ax, LOCAL(bios_register_es)
movw 6(%edx), %ax
movw %ax, LOCAL(bios_register_ds)
movw 8(%edx), %ax
movw %ax, LOCAL(bios_register_flags)
movl 12(%edx), %ebx
movl 16(%edx), %ecx
movl 20(%edx), %edi
movl 24(%edx), %esi
movl 28(%edx), %edx
PROT_TO_REAL
.code16
pushf
cli
#ifndef GRUB_MACHINE_PCBIOS
lidt realidt
#endif
mov %ds, %ax
push %ax
/* movw imm16, %ax*/
.byte 0xb8
LOCAL(bios_register_es):
.short 0
movw %ax, %es
/* movw imm16, %ax*/
.byte 0xb8
LOCAL(bios_register_ds):
.short 0
movw %ax, %ds
/* movw imm16, %ax*/
.byte 0xb8
LOCAL(bios_register_flags):
.short 0
push %ax
popf
/* movl imm32, %eax*/
.byte 0x66, 0xb8
LOCAL(bios_register_eax):
.long 0
/* int imm8. */
.byte 0xcd
intno:
.byte 0
movl %eax, %cs:LOCAL(bios_register_eax)
movw %ds, %ax
movw %ax, %cs:LOCAL(bios_register_ds)
pop %ax
mov %ax, %ds
pushf
pop %ax
movw %ax, LOCAL(bios_register_flags)
mov %es, %ax
movw %ax, LOCAL(bios_register_es)
popf
REAL_TO_PROT
.code32
popl %eax
movl %ebx, 12(%eax)
movl %ecx, 16(%eax)
movl %edi, 20(%eax)
movl %esi, 24(%eax)
movl %edx, 28(%eax)
movl %eax, %edx
movl LOCAL(bios_register_eax), %eax
movl %eax, (%edx)
movw LOCAL(bios_register_es), %ax
movw %ax, 4(%edx)
movw LOCAL(bios_register_ds), %ax
movw %ax, 6(%edx)
movw LOCAL(bios_register_flags), %ax
movw %ax, 8(%edx)
popl %edi
popl %esi
popl %ebx
popl %eax
popl %ecx
popl %ebp
#ifndef GRUB_MACHINE_PCBIOS
lidt protidt
#endif
ret
#ifndef GRUB_MACHINE_PCBIOS
realidt:
.word 0x100
.long 0
protidt:
.word 0
.long 0
#endif

View file

@ -45,52 +45,62 @@ struct mem_region
static struct mem_region mem_regions[MAX_REGIONS];
static int num_regions;
static char *
make_install_device (void)
void (*grub_pc_net_config) (char **device, char **path);
/*
* return the real time in ticks, of which there are about
* 18-20 per second
*/
grub_uint32_t
grub_get_rtc (void)
{
struct grub_bios_int_registers regs;
regs.eax = 0;
regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
grub_bios_interrupt (0x1a, &regs);
return (regs.ecx << 16) | (regs.edx & 0xffff);
}
void
grub_machine_get_bootlocation (char **device, char **path)
{
char *ptr;
grub_uint8_t boot_drive, dos_part, bsd_part;
boot_drive = (grub_boot_device >> 24);
dos_part = (grub_boot_device >> 16);
bsd_part = (grub_boot_device >> 8);
/* No hardcoded root partition - make it from the boot drive and the
partition number encoded at the install time. */
if (boot_drive == GRUB_BOOT_MACHINE_PXE_DL)
{
if (grub_pc_net_config)
grub_pc_net_config (device, path);
return;
}
/* XXX: This should be enough. */
char dev[100], *ptr = dev;
#define DEV_SIZE 100
*device = grub_malloc (DEV_SIZE);
ptr = *device;
grub_snprintf (*device, DEV_SIZE,
"%cd%u", (boot_drive & 0x80) ? 'h' : 'f',
boot_drive & 0x7f);
ptr += grub_strlen (ptr);
if (grub_prefix[0] != '(')
{
/* No hardcoded root partition - make it from the boot drive and the
partition number encoded at the install time. */
if (grub_boot_drive == GRUB_BOOT_MACHINE_PXE_DL)
{
grub_strcpy (dev, "(pxe");
ptr += sizeof ("(pxe") - 1;
}
else
{
grub_snprintf (dev, sizeof (dev),
"(%cd%u", (grub_boot_drive & 0x80) ? 'h' : 'f',
grub_boot_drive & 0x7f);
ptr += grub_strlen (ptr);
if (dos_part != 0xff)
grub_snprintf (ptr, DEV_SIZE - (ptr - *device),
",%u", dos_part + 1);
ptr += grub_strlen (ptr);
if (grub_install_dos_part >= 0)
grub_snprintf (ptr, sizeof (dev) - (ptr - dev),
",%u", grub_install_dos_part + 1);
ptr += grub_strlen (ptr);
if (grub_install_bsd_part >= 0)
grub_snprintf (ptr, sizeof (dev) - (ptr - dev), ",%u",
grub_install_bsd_part + 1);
ptr += grub_strlen (ptr);
}
grub_snprintf (ptr, sizeof (dev) - (ptr - dev), ")%s", grub_prefix);
grub_strcpy (grub_prefix, dev);
}
else if (grub_prefix[1] == ',' || grub_prefix[1] == ')')
{
/* We have a prefix, but still need to fill in the boot drive. */
grub_snprintf (dev, sizeof (dev),
"(%cd%u%s", (grub_boot_drive & 0x80) ? 'h' : 'f',
grub_boot_drive & 0x7f, grub_prefix + 1);
grub_strcpy (grub_prefix, dev);
}
return grub_prefix;
if (bsd_part != 0xff)
grub_snprintf (ptr, DEV_SIZE - (ptr - *device), ",%u",
bsd_part + 1);
ptr += grub_strlen (ptr);
*ptr = 0;
}
/* Add a memory region. */
@ -140,6 +150,9 @@ compact_mem_regions (void)
}
}
grub_addr_t grub_modbase;
extern grub_uint8_t _start[], _edata[];
void
grub_machine_init (void)
{
@ -148,6 +161,8 @@ grub_machine_init (void)
int grub_lower_mem;
#endif
grub_modbase = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR + (_edata - _start);
/* Initialize the console as early as possible. */
grub_console_init ();
@ -211,24 +226,9 @@ grub_machine_init (void)
grub_tsc_init ();
}
void
grub_machine_set_prefix (void)
{
/* Initialize the prefix. */
grub_env_set ("prefix", make_install_device ());
}
void
grub_machine_fini (void)
{
grub_console_fini ();
grub_stop_floppy ();
}
/* Return the end of the core image. */
grub_addr_t
grub_arch_modules_addr (void)
{
return GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR
+ (grub_kernel_image_size - GRUB_KERNEL_MACHINE_RAW_SIZE);
}

View file

@ -1,614 +0,0 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2008 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#define FIXED_PROPS
#define LZMA_BASE_SIZE 1846
#define LZMA_LIT_SIZE 768
#define LZMA_PROPERTIES_SIZE 5
#define kNumTopBits 24
#define kTopValue (1 << kNumTopBits)
#define kNumBitModelTotalBits 11
#define kBitModelTotal (1 << kNumBitModelTotalBits)
#define kNumMoveBits 5
#define kNumPosBitsMax 4
#define kNumPosStatesMax (1 << kNumPosBitsMax)
#define kLenNumLowBits 3
#define kLenNumLowSymbols (1 << kLenNumLowBits)
#define kLenNumMidBits 3
#define kLenNumMidSymbols (1 << kLenNumMidBits)
#define kLenNumHighBits 8
#define kLenNumHighSymbols (1 << kLenNumHighBits)
#define LenChoice 0
#define LenChoice2 (LenChoice + 1)
#define LenLow (LenChoice2 + 1)
#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
#define kNumStates 12
#define kNumLitStates 7
#define kStartPosModelIndex 4
#define kEndPosModelIndex 14
#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
#define kNumPosSlotBits 6
#define kNumLenToPosStates 4
#define kNumAlignBits 4
#define kAlignTableSize (1 << kNumAlignBits)
#define kMatchMinLen 2
#define IsMatch 0
#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
#define IsRepG0 (IsRep + kNumStates)
#define IsRepG1 (IsRepG0 + kNumStates)
#define IsRepG2 (IsRepG1 + kNumStates)
#define IsRep0Long (IsRepG2 + kNumStates)
#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
#define LenCoder (Align + kAlignTableSize)
#define RepLenCoder (LenCoder + kNumLenProbs)
#define Literal (RepLenCoder + kNumLenProbs)
#define out_size 8(%ebp)
#define now_pos -4(%ebp)
#define prev_byte -8(%ebp)
#define range -12(%ebp)
#define code -16(%ebp)
#define state -20(%ebp)
#define rep0 -24(%ebp)
#define rep1 -28(%ebp)
#define rep2 -32(%ebp)
#define rep3 -36(%ebp)
#ifdef FIXED_PROPS
#define FIXED_LC 3
#define FIXED_LP 0
#define FIXED_PB 2
#define POS_STATE_MASK ((1 << (FIXED_PB)) - 1)
#define LIT_POS_MASK ((1 << (FIXED_LP)) - 1)
#define LOCAL_SIZE 36
#else
#define lc (%ebx)
#define lp 4(%ebx)
#define pb 8(%ebx)
#define probs 12(%ebx)
#define pos_state_mask -40(%ebp)
#define lit_pos_mask -44(%ebp)
#define LOCAL_SIZE 44
#endif
RangeDecoderBitDecode:
#ifdef FIXED_PROPS
leal (%ebx, %eax, 4), %eax
#else
shll $2, %eax
addl probs, %eax
#endif
movl %eax, %ecx
movl (%ecx), %eax
movl range, %edx
shrl $kNumBitModelTotalBits, %edx
mull %edx
cmpl code, %eax
jbe 1f
movl %eax, range
movl $kBitModelTotal, %edx
subl (%ecx), %edx
shrl $kNumMoveBits, %edx
addl %edx, (%ecx)
clc
3:
pushf
cmpl $kTopValue, range
jnc 2f
shll $8, code
lodsb
movb %al, code
shll $8, range
2:
popf
ret
1:
subl %eax, range
subl %eax, code
movl (%ecx), %edx
shrl $kNumMoveBits, %edx
subl %edx, (%ecx)
stc
jmp 3b
RangeDecoderBitTreeDecode:
RangeDecoderReverseBitTreeDecode:
movzbl %cl, %ecx
xorl %edx, %edx
pushl %edx
incl %edx
pushl %edx
1:
pushl %eax
pushl %ecx
pushl %edx
addl %edx, %eax
call RangeDecoderBitDecode
popl %edx
popl %ecx
jnc 2f
movl 4(%esp), %eax
orl %eax, 8(%esp)
stc
2:
adcl %edx, %edx
popl %eax
shll $1, (%esp)
loop 1b
popl %ecx
subl %ecx, %edx /* RangeDecoderBitTreeDecode */
popl %ecx /* RangeDecoderReverseBitTreeDecode */
ret
LzmaLenDecode:
pushl %eax
addl $LenChoice, %eax
call RangeDecoderBitDecode
popl %eax
jc 1f
pushl $0
movb $kLenNumLowBits, %cl
addl $LenLow, %eax
2:
movl 12(%esp), %edx
shll %cl, %edx
addl %edx, %eax
3:
call RangeDecoderBitTreeDecode
popl %eax
addl %eax, %edx
ret
1:
pushl %eax
addl $LenChoice2, %eax
call RangeDecoderBitDecode
popl %eax
jc 1f
pushl $kLenNumLowSymbols
movb $kLenNumMidBits, %cl
addl $LenMid, %eax
jmp 2b
1:
pushl $(kLenNumLowSymbols + kLenNumMidSymbols)
addl $LenHigh, %eax
movb $kLenNumHighBits, %cl
jmp 3b
WriteByte:
movb %al, prev_byte
stosb
incl now_pos
ret
/*
* int LzmaDecode(CLzmaDecoderState *vs,
* const unsigned char *inStream,
* unsigned char *outStream,
* SizeT outSize);
*/
_LzmaDecodeA:
pushl %ebp
movl %esp, %ebp
subl $LOCAL_SIZE, %esp
#ifndef ASM_FILE
pushl %esi
pushl %edi
pushl %ebx
movl %eax, %ebx
movl %edx, %esi
pushl %ecx
#else
pushl %edi
#endif
cld
#ifdef FIXED_PROPS
movl %ebx, %edi
movl $(Literal + (LZMA_LIT_SIZE << (FIXED_LC + FIXED_LP))), %ecx
#else
movl $LZMA_LIT_SIZE, %eax
movb lc, %cl
addb lp, %cl
shll %cl, %eax
addl $Literal, %eax
movl %eax, %ecx
movl probs, %edi
#endif
movl $(kBitModelTotal >> 1), %eax
rep
stosl
popl %edi
xorl %eax, %eax
movl %eax, now_pos
movl %eax, prev_byte
movl %eax, state
incl %eax
movl %eax, rep0
movl %eax, rep1
movl %eax, rep2
movl %eax, rep3
#ifndef FIXED_PROPS
movl %eax, %edx
movb pb, %cl
shll %cl, %edx
decl %edx
movl %edx, pos_state_mask
movl %eax, %edx
movb lp, %cl
shll %cl, %edx
decl %edx
movl %edx, lit_pos_mask;
#endif
/* RangeDecoderInit */
negl %eax
movl %eax, range
incl %eax
movb $5, %cl
1:
shll $8, %eax
lodsb
loop 1b
movl %eax, code
lzma_decode_loop:
movl now_pos, %eax
cmpl out_size, %eax
jb 1f
#ifndef ASM_FILE
xorl %eax, %eax
popl %ebx
popl %edi
popl %esi
#endif
movl %ebp, %esp
popl %ebp
ret
1:
#ifdef FIXED_PROPS
andl $POS_STATE_MASK, %eax
#else
andl pos_state_mask, %eax
#endif
pushl %eax /* posState */
movl state, %edx
shll $kNumPosBitsMax, %edx
addl %edx, %eax
pushl %eax /* (state << kNumPosBitsMax) + posState */
call RangeDecoderBitDecode
jc 1f
movl now_pos, %eax
#ifdef FIXED_PROPS
andl $LIT_POS_MASK, %eax
shll $FIXED_LC, %eax
movl prev_byte, %edx
shrl $(8 - FIXED_LC), %edx
#else
andl lit_pos_mask, %eax
movb lc, %cl
shll %cl, %eax
negb %cl
addb $8, %cl
movl prev_byte, %edx
shrl %cl, %edx
#endif
addl %edx, %eax
movl $LZMA_LIT_SIZE, %edx
mull %edx
addl $Literal, %eax
pushl %eax
incl %edx /* edx = 1 */
movl rep0, %eax
negl %eax
pushl (%edi, %eax) /* matchByte */
cmpb $kNumLitStates, state
jb 5f
/* LzmaLiteralDecodeMatch */
3:
cmpl $0x100, %edx
jae 4f
xorl %eax, %eax
shlb $1, (%esp)
adcl %eax, %eax
pushl %eax
pushl %edx
shll $8, %eax
leal 0x100(%edx, %eax), %eax
addl 12(%esp), %eax
call RangeDecoderBitDecode
setc %al
popl %edx
adcl %edx, %edx
popl %ecx
cmpb %cl, %al
jz 3b
5:
/* LzmaLiteralDecode */
cmpl $0x100, %edx
jae 4f
pushl %edx
movl %edx, %eax
addl 8(%esp), %eax
call RangeDecoderBitDecode
popl %edx
adcl %edx, %edx
jmp 5b
4:
addl $16, %esp
movb %dl, %al
call WriteByte
movb state, %al
cmpb $4, %al
jae 2f
xorb %al, %al
jmp 3f
2:
subb $3, %al
cmpb $7, %al
jb 3f
subb $3, %al
3:
movb %al, state
jmp lzma_decode_loop
1:
movl state, %eax
addl $IsRep, %eax
call RangeDecoderBitDecode
jnc 1f
movl state, %eax
addl $IsRepG0, %eax
call RangeDecoderBitDecode
jc 10f
movl (%esp), %eax
addl $IsRep0Long, %eax
call RangeDecoderBitDecode
jc 20f
cmpb $7, state
movb $9, state
jb 100f
addb $2, state
100:
movl $1, %ecx
3:
movl rep0, %edx
negl %edx
4:
movb (%edi, %edx), %al
call WriteByte
loop 4b
popl %eax
popl %eax
jmp lzma_decode_loop
10:
movl state, %eax
addl $IsRepG1, %eax
call RangeDecoderBitDecode
movl rep1, %edx
jnc 100f
movl state, %eax
addl $IsRepG2, %eax
call RangeDecoderBitDecode
movl rep2, %edx
jnc 1000f
movl rep2, %edx
xchgl rep3, %edx
1000:
pushl rep1
popl rep2
100:
xchg rep0, %edx
movl %edx, rep1
20:
movl $RepLenCoder, %eax
call LzmaLenDecode
cmpb $7, state
movb $8, state
jb 100f
addb $3, state
100:
jmp 2f
1:
movl rep0, %eax
xchgl rep1, %eax
xchgl rep2, %eax
movl %eax, rep3
cmpb $7, state
movb $7, state
jb 10f
addb $3, state
10:
movl $LenCoder, %eax
call LzmaLenDecode
pushl %edx
movl $(kNumLenToPosStates - 1), %eax
cmpl %eax, %edx
jbe 100f
movl %eax, %edx
100:
movb $kNumPosSlotBits, %cl
shll %cl, %edx
leal PosSlot(%edx), %eax
call RangeDecoderBitTreeDecode
movl %edx, rep0
cmpl $kStartPosModelIndex, %edx
jb 100f
movl %edx, %ecx
shrl $1, %ecx
decl %ecx
movzbl %dl, %eax
andb $1, %al
orb $2, %al
shll %cl, %eax
movl %eax, rep0
cmpl $kEndPosModelIndex, %edx
jae 200f
movl rep0, %eax
addl $(SpecPos - 1), %eax
subl %edx, %eax
jmp 300f
200:
subb $kNumAlignBits, %cl
/* RangeDecoderDecodeDirectBits */
xorl %edx, %edx
1000:
shrl $1, range
shll $1, %edx
movl range, %eax
cmpl %eax, code
jb 2000f
subl %eax, code
orb $1, %dl
2000:
cmpl $kTopValue, %eax
jae 3000f
shll $8, range
shll $8, code
lodsb
movb %al, code
3000:
loop 1000b
movb $kNumAlignBits, %cl
shll %cl, %edx
addl %edx, rep0
movl $Align, %eax
300:
call RangeDecoderReverseBitTreeDecode
addl %ecx, rep0
100:
incl rep0
popl %edx
2:
addl $kMatchMinLen, %edx
movl %edx, %ecx
jmp 3b

View file

@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
* Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008,2009,2011 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
@ -43,211 +43,30 @@
#include <config.h>
#include <grub/symbol.h>
#include <grub/boot.h>
#include <grub/machine/boot.h>
#include <grub/machine/memory.h>
#include <grub/machine/console.h>
#include <grub/cpu/linux.h>
#include <grub/machine/kernel.h>
#include <grub/term.h>
#include <multiboot.h>
#include <multiboot2.h>
#define ABS(x) ((x) - LOCAL (base) + GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200)
.file "startup.S"
.text
/* Tell GAS to generate 16-bit instructions so that this code works
in real mode. */
.code16
.globl start, _start
start:
_start:
LOCAL (base):
/*
* Guarantee that "main" is loaded at 0x0:0x8200.
*/
#ifdef __APPLE__
ljmp $0, $(ABS(LOCAL (codestart)) - 0x10000)
#else
ljmp $0, $ABS(LOCAL (codestart))
#endif
/*
* Compatibility version number
*
* These MUST be at byte offset 6 and 7 of the executable
* DO NOT MOVE !!!
*/
. = _start + 0x6
.byte GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR
/*
* This is a special data area 8 bytes from the beginning.
*/
. = _start + 0x8
VARIABLE(grub_total_module_size)
.long 0
VARIABLE(grub_kernel_image_size)
.long 0
VARIABLE(grub_compressed_size)
.long 0
VARIABLE(grub_install_dos_part)
.long 0xFFFFFFFF
VARIABLE(grub_install_bsd_part)
.long 0xFFFFFFFF
reed_solomon_redundancy:
.long 0
#ifdef APPLE_CC
bss_start:
.long 0
bss_end:
.long 0
#endif
/*
* This is the area for all of the special variables.
*/
VARIABLE(grub_boot_drive)
.byte 0
/* the real mode code continues... */
LOCAL (codestart):
cli /* we're not safe here! */
/* set up %ds, %ss, and %es */
xorw %ax, %ax
movw %ax, %ds
movw %ax, %ss
movw %ax, %es
/* set up the real mode/BIOS stack */
movl $GRUB_MEMORY_MACHINE_REAL_STACK, %ebp
movl %ebp, %esp
sti /* we're safe again */
/* save the boot drive */
ADDR32 movb %dl, EXT_C(grub_boot_drive)
/* reset disk system (%ah = 0) */
int $0x13
/* transition to protected mode */
DATA32 call real_to_prot
/* The ".code32" directive takes GAS out of 16-bit mode. */
.code32
incl %eax
call grub_gate_a20
movl EXT_C(grub_compressed_size), %edx
addl $(GRUB_KERNEL_MACHINE_RAW_SIZE - GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART), %edx
movl reed_solomon_redundancy, %ecx
leal _start + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART, %eax
call EXT_C (grub_reed_solomon_recover)
jmp post_reed_solomon
#include <rs_decoder.S>
.text
. = _start + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART
/*
* Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself).
* This uses the a.out kludge to load raw binary to the area starting at 1MB,
* and relocates itself after loaded.
*/
.p2align 2 /* force 4-byte alignment */
multiboot_header:
/* magic */
.long 0x1BADB002
/* flags */
.long (1 << 16)
/* checksum */
.long -0x1BADB002 - (1 << 16)
/* header addr */
.long multiboot_header - _start + 0x100000 + 0x200
/* load addr */
.long 0x100000
/* load end addr */
.long 0
/* bss end addr */
.long 0
/* entry addr */
.long multiboot_entry - _start + 0x100000 + 0x200
multiboot_entry:
.code32
/* obtain the boot device */
movl 12(%ebx), %edx
movl $GRUB_MEMORY_MACHINE_PROT_STACK, %ebp
movl %ebp, %esp
/* relocate the code */
movl $(GRUB_KERNEL_MACHINE_RAW_SIZE + 0x200), %ecx
addl EXT_C(grub_compressed_size) - _start + 0x100000 + 0x200, %ecx
movl $0x100000, %esi
movl $GRUB_BOOT_MACHINE_KERNEL_ADDR, %edi
cld
rep
movsb
/* jump to the real address */
movl $multiboot_trampoline, %eax
jmp *%eax
multiboot_trampoline:
/* fill the boot information */
movl %edx, %eax
shrl $8, %eax
xorl %ebx, %ebx
cmpb $0xFF, %ah
je 1f
movb %ah, %bl
movl %ebx, EXT_C(grub_install_dos_part)
1:
cmpb $0xFF, %al
je 2f
movb %al, %bl
movl %ebx, EXT_C(grub_install_bsd_part)
2:
shrl $24, %edx
movb $0xFF, %dh
/* enter the usual booting */
call prot_to_real
jmp LOCAL (codestart)
post_reed_solomon:
#ifdef ENABLE_LZMA
movl $GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR, %edi
movl $(_start + GRUB_KERNEL_MACHINE_RAW_SIZE), %esi
pushl %edi
pushl %esi
movl EXT_C(grub_kernel_image_size), %ecx
addl EXT_C(grub_total_module_size), %ecx
subl $GRUB_KERNEL_MACHINE_RAW_SIZE, %ecx
pushl %ecx
leal (%edi, %ecx), %ebx
call _LzmaDecodeA
/* _LzmaDecodeA clears DF, so no need to run cld */
popl %ecx
popl %edi
popl %esi
#endif
movl %ecx, (LOCAL(real_to_prot_addr) - _start) (%esi)
movl %edi, (LOCAL(prot_to_real_addr) - _start) (%esi)
/* copy back the decompressed part (except the modules) */
subl EXT_C(grub_total_module_size), %ecx
movl $(_edata - _start), %ecx
movl $(_start), %edi
rep
movsb
movl $LOCAL (cont), %esi
jmp *%esi
LOCAL(cont):
#if 0
/* copy modules before cleaning out the bss */
movl EXT_C(grub_total_module_size), %ecx
@ -263,24 +82,12 @@ post_reed_solomon:
movsb
#endif
#ifdef APPLE_CC
/* clean out the bss */
bss_start_abs = ABS (bss_start)
bss_end_abs = ABS (bss_end)
movl bss_start_abs, %edi
/* compute the bss length */
movl bss_end_abs, %ecx
subl %edi, %ecx
#else
/* clean out the bss */
movl $BSS_START_SYMBOL, %edi
/* compute the bss length */
movl $END_SYMBOL, %ecx
subl %edi, %ecx
#endif
/* clean out */
xorl %eax, %eax
@ -288,183 +95,27 @@ post_reed_solomon:
rep
stosb
movl %edx, EXT_C(grub_boot_device)
/*
* Call the start of main body of C code.
*/
call EXT_C(grub_main)
#include "../realmode.S"
/*
* grub_gate_a20(int on)
*
* Gate address-line 20 for high memory.
*
* This routine is probably overconservative in what it does, but so what?
*
* It also eats any keystrokes in the keyboard buffer. :-(
*/
grub_gate_a20:
movl %eax, %edx
gate_a20_test_current_state:
/* first of all, test if already in a good state */
call gate_a20_check_state
cmpb %al, %dl
jnz gate_a20_try_bios
ret
gate_a20_try_bios:
/* second, try a BIOS call */
pushl %ebp
call prot_to_real
.code16
movw $0x2400, %ax
testb %dl, %dl
jz 1f
incw %ax
1: int $0x15
DATA32 call real_to_prot
.code32
popl %ebp
call gate_a20_check_state
cmpb %al, %dl
jnz gate_a20_try_system_control_port_a
ret
gate_a20_try_system_control_port_a:
/*
* In macbook, the keyboard test would hang the machine, so we move
* this forward.
*/
/* fourth, try the system control port A */
inb $0x92
andb $(~0x03), %al
testb %dl, %dl
jz 6f
orb $0x02, %al
6: outb $0x92
/* When turning off Gate A20, do not check the state strictly,
because a failure is not fatal usually, and Gate A20 is always
on some modern machines. */
testb %dl, %dl
jz 7f
call gate_a20_check_state
cmpb %al, %dl
jnz gate_a20_try_keyboard_controller
7: ret
gate_a20_flush_keyboard_buffer:
inb $0x64
andb $0x02, %al
jnz gate_a20_flush_keyboard_buffer
2:
inb $0x64
andb $0x01, %al
jz 3f
inb $0x60
jmp 2b
3:
ret
gate_a20_try_keyboard_controller:
/* third, try the keyboard controller */
call gate_a20_flush_keyboard_buffer
movb $0xd1, %al
outb $0x64
4:
inb $0x64
andb $0x02, %al
jnz 4b
movb $0xdd, %al
testb %dl, %dl
jz 5f
orb $0x02, %al
5: outb $0x60
call gate_a20_flush_keyboard_buffer
/* output a dummy command (USB keyboard hack) */
movb $0xff, %al
outb $0x64
call gate_a20_flush_keyboard_buffer
call gate_a20_check_state
cmpb %al, %dl
/* everything failed, so restart from the beginning */
jnz gate_a20_try_bios
ret
gate_a20_check_state:
/* iterate the checking for a while */
movl $100, %ecx
1:
call 3f
cmpb %al, %dl
jz 2f
loop 1b
2:
ret
3:
pushl %ebx
pushl %ecx
xorl %eax, %eax
/* compare the byte at 0x8000 with that at 0x108000 */
movl $GRUB_BOOT_MACHINE_KERNEL_ADDR, %ebx
pushl %ebx
/* save the original byte in CL */
movb (%ebx), %cl
/* store the value at 0x108000 in AL */
addl $0x100000, %ebx
movb (%ebx), %al
/* try to set one less value at 0x8000 */
popl %ebx
movb %al, %ch
decb %ch
movb %ch, (%ebx)
/* serialize */
outb %al, $0x80
outb %al, $0x80
/* obtain the value at 0x108000 in CH */
pushl %ebx
addl $0x100000, %ebx
movb (%ebx), %ch
/* this result is 1 if A20 is on or 0 if it is off */
subb %ch, %al
xorb $1, %al
/* restore the original */
popl %ebx
movb %cl, (%ebx)
popl %ecx
popl %ebx
ret
#ifdef ENABLE_LZMA
#include "lzma_decode.S"
#endif
/*
* The code beyond this point is compressed. Assert that the uncompressed
* code fits GRUB_KERNEL_MACHINE_RAW_SIZE.
*/
. = _start + GRUB_KERNEL_MACHINE_RAW_SIZE
. = _start + GRUB_KERNEL_MACHINE_PREFIX
VARIABLE(grub_prefix)
/* to be filled by grub-mkimage */
/*
* Leave some breathing room for the prefix.
*/
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END
LOCAL(real_to_prot_addr):
.long 0
LOCAL(prot_to_real_addr):
.long 0
.macro PROT_TO_REAL
movl LOCAL(prot_to_real_addr), %eax
call *%eax
.endm
.macro REAL_TO_PROT
movl LOCAL(real_to_prot_addr), %eax
DATA32 call *%ax
.endm
/*
* grub_exit()
@ -472,403 +123,17 @@ VARIABLE(grub_prefix)
* Exit the system.
*/
FUNCTION(grub_exit)
call prot_to_real
PROT_TO_REAL
.code16
/* Tell the BIOS a boot failure. If this does not work, reboot. */
int $0x18
jmp cold_reboot
/* set 0x472 to 0x0000 for cold boot (0x1234 for warm boot) */
xorw %ax, %ax
movw $0x0472, %di
movw %ax, (%di)
ljmp $0xf000, $0xfff0
.code32
/*
* void grub_chainloader_real_boot (int drive, void *part_addr)
*
* This starts another boot loader.
*/
FUNCTION(grub_chainloader_real_boot)
pushl %edx
pushl %eax
/* Turn off Gate A20 */
xorl %eax, %eax
call grub_gate_a20
/* set up to pass boot drive */
popl %edx
/* ESI must point to a partition table entry */
popl %esi
call prot_to_real
.code16
ljmp $0, $GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR
.code32
/*
* void grub_console_putchar (int c)
*
* Put the character C on the console. Because GRUB wants to write a
* character with an attribute, this implementation is a bit tricky.
* If C is a control character (CR, LF, BEL, BS), use INT 10, AH = 0Eh
* (TELETYPE OUTPUT). Otherwise, save the original position, put a space,
* save the current position, restore the original position, write the
* character and the attribute, and restore the current position.
*
* The reason why this is so complicated is that there is no easy way to
* get the height of the screen, and the TELETYPE OUTPUT BIOS call doesn't
* support setting a background attribute.
*/
FUNCTION(grub_console_putchar)
/* Retrieve the base character. */
movl 0(%edx), %edx
pusha
movb EXT_C(grub_console_cur_color), %bl
call prot_to_real
.code16
movb %dl, %al
xorb %bh, %bh
/* use teletype output if control character */
cmpb $0x7, %al
je 1f
cmpb $0x8, %al
je 1f
cmpb $0xa, %al
je 1f
cmpb $0xd, %al
je 1f
/* save the character and the attribute on the stack */
pushw %ax
pushw %bx
/* get the current position */
movb $0x3, %ah
int $0x10
/* check the column with the width */
cmpb $79, %dl
jl 2f
/* print CR and LF, if next write will exceed the width */
movw $0x0e0d, %ax
int $0x10
movb $0x0a, %al
int $0x10
/* get the current position */
movb $0x3, %ah
int $0x10
2:
/* restore the character and the attribute */
popw %bx
popw %ax
/* write the character with the attribute */
movb $0x9, %ah
movw $1, %cx
int $0x10
/* move the cursor forward */
incb %dl
movb $0x2, %ah
int $0x10
jmp 3f
1: movw $1, %bx
movb $0xe, %ah
int $0x10
3: DATA32 call real_to_prot
.code32
popa
ret
LOCAL(bypass_table):
.word 0x011b, 0x0f00 | '\t', 0x0e00 | '\b', 0x1c00 | '\r'
.word 0x1c00 | '\n'
LOCAL(bypass_table_end):
/*
* int grub_console_getkey (void)
* if there is a character pending, return it; otherwise return -1
* BIOS call "INT 16H Function 01H" to check whether a character is pending
* Call with %ah = 0x1
* Return:
* If key waiting to be input:
* %ah = keyboard scan code
* %al = ASCII character
* Zero flag = clear
* else
* Zero flag = set
* BIOS call "INT 16H Function 00H" to read character from keyboard
* Call with %ah = 0x0
* Return: %ah = keyboard scan code
* %al = ASCII character
*/
FUNCTION(grub_console_getkey)
pushl %ebp
pushl %edi
call prot_to_real
.code16
/*
* Due to a bug in apple's bootcamp implementation, INT 16/AH = 0 would
* cause the machine to hang at the second keystroke. However, we can
* work around this problem by ensuring the presence of keystroke with
* INT 16/AH = 1 before calling INT 16/AH = 0.
*/
movb $1, %ah
int $0x16
jz notpending
movb $0, %ah
int $0x16
xorl %edx, %edx
movw %ax, %dx /* real_to_prot uses %eax */
DATA32 call real_to_prot
.code32
movl $0xff, %eax
testl %eax, %edx
jz 1f
andl %edx, %eax
cmpl $0x20, %eax
jae 2f
movl %edx, %eax
leal LOCAL(bypass_table), %edi
movl $((LOCAL(bypass_table_end) - LOCAL(bypass_table)) >> 1), %ecx
repne scasw
jz 3f
andl $0xff, %eax
addl $(('a' - 1) | GRUB_TERM_CTRL), %eax
jmp 2f
3:
andl $0xff, %eax
jmp 2f
1: movl %edx, %eax
shrl $8, %eax
orl $GRUB_TERM_EXTENDED, %eax
2:
popl %edi
popl %ebp
ret
notpending:
.code16
DATA32 call real_to_prot
.code32
#if GRUB_TERM_NO_KEY != 0
#error Fix this asm code
#endif
jmp 2b
/*
* grub_uint16_t grub_console_getxy (void)
* BIOS call "INT 10H Function 03h" to get cursor position
* Call with %ah = 0x03
* %bh = page
* Returns %ch = starting scan line
* %cl = ending scan line
* %dh = row (0 is top)
* %dl = column (0 is left)
*/
FUNCTION(grub_console_getxy)
pushl %ebp
pushl %ebx /* save EBX */
call prot_to_real
.code16
xorb %bh, %bh /* set page to 0 */
movb $0x3, %ah
int $0x10 /* get cursor position */
DATA32 call real_to_prot
.code32
movb %dl, %ah
movb %dh, %al
popl %ebx
popl %ebp
ret
/*
* void grub_console_gotoxy(grub_uint8_t x, grub_uint8_t y)
* BIOS call "INT 10H Function 02h" to set cursor position
* Call with %ah = 0x02
* %bh = page
* %dh = row (0 is top)
* %dl = column (0 is left)
*/
FUNCTION(grub_console_gotoxy)
pushl %ebp
pushl %ebx /* save EBX */
movb %cl, %dh /* %dh = y */
/* %dl = x */
call prot_to_real
.code16
xorb %bh, %bh /* set page to 0 */
movb $0x2, %ah
int $0x10 /* set cursor position */
DATA32 call real_to_prot
.code32
popl %ebx
popl %ebp
ret
/*
* void grub_console_cls (void)
* BIOS call "INT 10H Function 09h" to write character and attribute
* Call with %ah = 0x09
* %al = (character)
* %bh = (page number)
* %bl = (attribute)
* %cx = (number of times)
*/
FUNCTION(grub_console_cls)
pushl %ebp
pushl %ebx /* save EBX */
call prot_to_real
.code16
/* move the cursor to the beginning */
movb $0x02, %ah
xorb %bh, %bh
xorw %dx, %dx
int $0x10
/* write spaces to the entire screen */
movw $0x0920, %ax
movw $0x07, %bx
movw $(80 * 25), %cx
int $0x10
/* move back the cursor */
movb $0x02, %ah
int $0x10
DATA32 call real_to_prot
.code32
popl %ebx
popl %ebp
ret
/*
* void grub_console_setcursor (int on)
* BIOS call "INT 10H Function 01h" to set cursor type
* Call with %ah = 0x01
* %ch = cursor starting scanline
* %cl = cursor ending scanline
*/
console_cursor_state:
.byte 1
console_cursor_shape:
.word 0
FUNCTION(grub_console_setcursor)
pushl %ebp
pushl %ebx
/* push ON */
pushl %edx
/* check if the standard cursor shape has already been saved */
movw console_cursor_shape, %ax
testw %ax, %ax
jne 1f
call prot_to_real
.code16
movb $0x03, %ah
xorb %bh, %bh
int $0x10
DATA32 call real_to_prot
.code32
cmp %cl, %ch
jb 3f
movw $0x0d0e, %cx
3:
movw %cx, console_cursor_shape
1:
/* set %cx to the designated cursor shape */
movw $0x2000, %cx
popl %eax
testl %eax, %eax
jz 2f
movw console_cursor_shape, %cx
2:
call prot_to_real
.code16
movb $0x1, %ah
int $0x10
DATA32 call real_to_prot
.code32
popl %ebx
popl %ebp
ret
/*
* grub_get_rtc()
* return the real time in ticks, of which there are about
* 18-20 per second
*/
FUNCTION(grub_get_rtc)
pushl %ebp
call prot_to_real /* enter real mode */
.code16
/* %ax is already zero */
int $0x1a
DATA32 call real_to_prot
.code32
movl %ecx, %eax
shll $16, %eax
movw %dx, %ax
popl %ebp
ret
/*
* int grub_pxe_call (int func, void* data, grub_uint32_t pxe_rm_entry);
*/
@ -887,7 +152,7 @@ FUNCTION(grub_pxe_call)
shll $16, %edx
addl %eax, %edx
call prot_to_real
PROT_TO_REAL
.code16
pushl %ebx
@ -899,7 +164,7 @@ FUNCTION(grub_pxe_call)
addw $10, %sp
movw %ax, %cx
DATA32 call real_to_prot
REAL_TO_PROT
.code32
movzwl %cx, %eax
@ -910,102 +175,8 @@ FUNCTION(grub_pxe_call)
popl %ebp
ret
FUNCTION(grub_bios_interrupt)
pushl %ebp
pushl %ecx
pushl %eax
pushl %ebx
pushl %esi
pushl %edi
pushl %edx
movb %al, intno
movl (%edx), %eax
movl %eax, LOCAL(bios_register_eax)
movw 4(%edx), %ax
movw %ax, LOCAL(bios_register_es)
movw 6(%edx), %ax
movw %ax, LOCAL(bios_register_ds)
movw 8(%edx), %ax
movw %ax, LOCAL(bios_register_flags)
#include "../int.S"
movl 12(%edx), %ebx
movl 16(%edx), %ecx
movl 20(%edx), %edi
movl 24(%edx), %esi
movl 28(%edx), %edx
call prot_to_real
.code16
mov %ds, %ax
push %ax
/* movw imm16, %ax*/
.byte 0xb8
LOCAL(bios_register_es):
.short 0
movw %ax, %es
/* movw imm16, %ax*/
.byte 0xb8
LOCAL(bios_register_ds):
.short 0
movw %ax, %ds
/* movw imm16, %ax*/
.byte 0xb8
LOCAL(bios_register_flags):
.short 0
push %ax
popf
/* movl imm32, %eax*/
.byte 0x66, 0xb8
LOCAL(bios_register_eax):
.long 0
/* int imm8. */
.byte 0xcd
intno:
.byte 0
movl %eax, %cs:LOCAL(bios_register_eax)
movw %ds, %ax
movw %ax, %cs:LOCAL(bios_register_ds)
pop %ax
mov %ax, %ds
pushf
pop %ax
movw %ax, LOCAL(bios_register_flags)
mov %es, %ax
movw %ax, LOCAL(bios_register_es)
DATA32 call real_to_prot
.code32
popl %eax
movl %ebx, 12(%eax)
movl %ecx, 16(%eax)
movl %edi, 20(%eax)
movl %esi, 24(%eax)
movl %edx, 28(%eax)
movl %eax, %edx
movl LOCAL(bios_register_eax), %eax
movl %eax, (%edx)
movw LOCAL(bios_register_es), %ax
movw %ax, 4(%edx)
movw LOCAL(bios_register_ds), %ax
movw %ax, 6(%edx)
movw LOCAL(bios_register_flags), %ax
movw %ax, 8(%edx)
popl %edi
popl %esi
popl %ebx
popl %eax
popl %ecx
popl %ebp
ret
.bss
VARIABLE(grub_boot_device)
.long 0

View file

@ -41,8 +41,11 @@ static grub_uint64_t mem_size, above_4g;
void
grub_machine_mmap_init ()
{
mem_size = ((grub_uint64_t) grub_cmos_read (QEMU_CMOS_MEMSIZE_HIGH)) << 24
| ((grub_uint64_t) grub_cmos_read (QEMU_CMOS_MEMSIZE_LOW)) << 16;
grub_uint8_t high, low, b, c, d;
grub_cmos_read (QEMU_CMOS_MEMSIZE_HIGH, &high);
grub_cmos_read (QEMU_CMOS_MEMSIZE_LOW, &low);
mem_size = ((grub_uint64_t) high) << 24
| ((grub_uint64_t) low) << 16;
if (mem_size > 0)
{
/* Don't ask... */
@ -50,15 +53,19 @@ grub_machine_mmap_init ()
}
else
{
grub_cmos_read (QEMU_CMOS_MEMSIZE2_HIGH, &high);
grub_cmos_read (QEMU_CMOS_MEMSIZE2_LOW, &low);
mem_size
= ((((grub_uint64_t) grub_cmos_read (QEMU_CMOS_MEMSIZE2_HIGH)) << 18)
| ((grub_uint64_t) (grub_cmos_read (QEMU_CMOS_MEMSIZE2_LOW)) << 10))
= ((((grub_uint64_t) high) << 18) | (((grub_uint64_t) low) << 10))
+ 1024 * 1024;
}
above_4g = (((grub_uint64_t) grub_cmos_read (0x5b)) << 16)
| (((grub_uint64_t) grub_cmos_read (0x5c)) << 24)
| (((grub_uint64_t) grub_cmos_read (0x5d)) << 32);
grub_cmos_read (0x5b, &b);
grub_cmos_read (0x5c, &c);
grub_cmos_read (0x5d, &d);
above_4g = (((grub_uint64_t) b) << 16)
| (((grub_uint64_t) c) << 24)
| (((grub_uint64_t) d) << 32);
}
grub_err_t

View file

@ -32,16 +32,6 @@ _start:
. = _start + GRUB_KERNEL_I386_QEMU_CORE_ENTRY_ADDR
VARIABLE(grub_core_entry_addr)
.long 0
VARIABLE(grub_kernel_image_size)
.long 0
VARIABLE(grub_prefix)
/* to be filled by grub-mkimage */
/*
* Leave some breathing room for the prefix.
*/
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END
codestart:
/* Relocate to low memory. First we figure out our location.
@ -53,11 +43,7 @@ codestart:
value of `grub_core_entry_addr' in %esi. */
xorw %si, %si
/* ... which allows us to access `grub_kernel_image_size'
before relocation. */
movl (grub_kernel_image_size - _start)(%esi), %ecx
movl $(_edata - _start), %ecx
movl $_start, %edi
cld
rep
@ -65,24 +51,12 @@ codestart:
ljmp $GRUB_MEMORY_MACHINE_PROT_MODE_CSEG, $1f
1:
#ifdef APPLE_CC
/* clean out the bss */
bss_start_abs = ABS (bss_start)
bss_end_abs = ABS (bss_end)
movl bss_start_abs, %edi
/* compute the bss length */
movl bss_end_abs, %ecx
subl %edi, %ecx
#else
/* clean out the bss */
movl $BSS_START_SYMBOL, %edi
/* compute the bss length */
movl $END_SYMBOL, %ecx
subl %edi, %ecx
#endif
/* clean out */
xorl %eax, %eax

View file

@ -46,11 +46,19 @@
* This is the area for all of the special variables.
*/
.p2align 2 /* force 4-byte alignment */
.p2align 5 /* force 4-byte alignment */
protstack:
.long GRUB_MEMORY_MACHINE_PROT_STACK
.macro PROT_TO_REAL
call prot_to_real
.endm
.macro REAL_TO_PROT
DATA32 call real_to_prot
.endm
/*
* This is the Global Descriptor Table
*
@ -71,7 +79,7 @@ protstack:
* description.
*/
.p2align 2 /* force 4-byte alignment */
.p2align 5 /* force 4-byte alignment */
gdt:
.word 0, 0
.byte 0, 0, 0, 0
@ -105,6 +113,7 @@ gdt:
.byte 0, 0x92, 0, 0
.p2align 5
/* this is the GDT descriptor */
gdtdesc:
.word 0x27 /* limit */
@ -162,6 +171,25 @@ protcseg:
/* return on the old (or initialized) stack! */
ret
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2009,2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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/i386/pc/memory.h>
prot_to_real:
/* just in case, set GDT */
@ -225,18 +253,3 @@ realcseg:
DATA32 ret
.code32
/*
* grub_reboot()
*
* Reboot the system. At the moment, rely on BIOS.
*/
FUNCTION(grub_reboot)
call prot_to_real
.code16
cold_reboot:
/* set 0x472 to 0x0000 for cold boot (0x1234 for warm boot) */
movw $0x0472, %di
movw %ax, (%di)
ljmp $0xf000, $0xfff0
.code32

View file

@ -104,13 +104,13 @@ add_value_to_slot_21 (grub_addr_t addr, grub_uint32_t value)
}
}
static grub_uint8_t nopm[5] =
static const grub_uint8_t nopm[5] =
{
/* [MLX] nop.m 0x0 */
0x05, 0x00, 0x00, 0x00, 0x01
};
static grub_uint8_t jump[0x20] =
static const grub_uint8_t jump[0x20] =
{
/* ld8 r16=[r15],8 */
0x02, 0x80, 0x20, 0x1e, 0x18, 0x14,

View file

@ -30,7 +30,6 @@ grub_ia64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
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. */
@ -43,8 +42,6 @@ grub_ia64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
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)))

View file

@ -40,12 +40,6 @@ 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)
{

View file

@ -42,13 +42,3 @@ _start:
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

@ -60,6 +60,10 @@ grub_ieee1275_find_options (void)
int is_olpc = 0;
int is_qemu = 0;
#ifdef __sparc__
grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_PARTITION_0);
#endif
grub_ieee1275_finddevice ("/", &root);
grub_ieee1275_finddevice ("/options", &options);
grub_ieee1275_finddevice ("/openprom", &openprom);

View file

@ -27,7 +27,7 @@
int
grub_ieee1275_finddevice (char *name, grub_ieee1275_phandle_t *phandlep)
grub_ieee1275_finddevice (const char *name, grub_ieee1275_phandle_t *phandlep)
{
struct find_device_args
{
@ -532,7 +532,7 @@ grub_ieee1275_release (grub_addr_t addr, grub_size_t size)
int
grub_ieee1275_set_property (grub_ieee1275_phandle_t phandle,
const char *propname, void *buf,
const char *propname, const void *buf,
grub_size_t size, grub_ssize_t *actual)
{
struct set_property_args

View file

@ -31,8 +31,12 @@
#include <grub/ieee1275/console.h>
#include <grub/ieee1275/ofdisk.h>
#include <grub/ieee1275/ieee1275.h>
#include <grub/net.h>
#include <grub/offsets.h>
#include <grub/memory.h>
#ifdef __sparc__
#include <grub/machine/kernel.h>
#endif
/* The minimal heap size we can live with. */
#define HEAP_MIN_SIZE (unsigned long) (2 * 1024 * 1024)
@ -47,6 +51,10 @@
extern char _start[];
extern char _end[];
#ifdef __sparc__
grub_addr_t grub_ieee1275_original_stack;
#endif
void
grub_exit (void)
{
@ -68,37 +76,51 @@ grub_translate_ieee1275_path (char *filepath)
}
}
void (*grub_ieee1275_net_config) (const char *dev,
char **device,
char **path);
void
grub_machine_set_prefix (void)
grub_machine_get_bootlocation (char **device, char **path)
{
char bootpath[64]; /* XXX check length */
char *filename;
char *prefix;
if (grub_prefix[0])
{
grub_env_set ("prefix", grub_prefix);
/* Prefix is hardcoded in the core image. */
return;
}
char *type;
if (grub_ieee1275_get_property (grub_ieee1275_chosen, "bootpath", &bootpath,
sizeof (bootpath), 0))
{
/* Should never happen. */
grub_printf ("/chosen/bootpath property missing!\n");
grub_env_set ("prefix", "");
return;
}
/* Transform an OF device path to a GRUB path. */
prefix = grub_ieee1275_encode_devname (bootpath);
type = grub_ieee1275_get_device_type (bootpath);
if (type && grub_strcmp (type, "network") == 0)
{
char *dev, *canon;
char *ptr;
dev = grub_ieee1275_get_aliasdevname (bootpath);
canon = grub_ieee1275_canonicalise_devname (dev);
ptr = canon + grub_strlen (canon) - 1;
while (ptr > canon && (*ptr == ',' || *ptr == ':'))
ptr--;
ptr++;
*ptr = 0;
if (grub_ieee1275_net_config)
grub_ieee1275_net_config (canon, device, path);
grub_free (dev);
grub_free (canon);
}
else
*device = grub_ieee1275_encode_devname (bootpath);
grub_free (type);
filename = grub_ieee1275_get_filename (bootpath);
if (filename)
{
char *newprefix;
char *lastslash = grub_strrchr (filename, '\\');
/* Truncate at last directory. */
@ -107,23 +129,22 @@ grub_machine_set_prefix (void)
*lastslash = '\0';
grub_translate_ieee1275_path (filename);
newprefix = grub_xasprintf ("%s%s", prefix, filename);
if (newprefix)
{
grub_free (prefix);
prefix = newprefix;
}
*path = filename;
}
}
grub_env_set ("prefix", prefix);
grub_free (filename);
grub_free (prefix);
}
/* Claim some available memory in the first /memory node. */
static void grub_claim_heap (void)
#ifdef __sparc__
static void
grub_claim_heap (void)
{
grub_mm_init_region ((void *) (grub_modules_get_end ()
+ GRUB_KERNEL_MACHINE_STACK_SIZE), 0x200000);
}
#else
static void
grub_claim_heap (void)
{
unsigned long total = 0;
@ -191,23 +212,14 @@ static void grub_claim_heap (void)
else
grub_machine_mmap_iterate (heap_init);
}
#endif
static grub_uint64_t ieee1275_get_time_ms (void);
void
grub_machine_init (void)
static void
grub_parse_cmdline (void)
{
char args[256];
grub_ssize_t actual;
char args[256];
grub_ieee1275_init ();
grub_console_init_early ();
grub_claim_heap ();
grub_console_init_lately ();
grub_ofdisk_init ();
/* Process commandline. */
if (grub_ieee1275_get_property (grub_ieee1275_chosen, "bootargs", &args,
sizeof args, &actual) == 0
&& actual > 1)
@ -240,6 +252,26 @@ grub_machine_init (void)
}
}
}
}
static grub_uint64_t ieee1275_get_time_ms (void);
grub_addr_t grub_modbase;
void
grub_machine_init (void)
{
grub_modbase = ALIGN_UP((grub_addr_t) _end
+ GRUB_KERNEL_MACHINE_MOD_GAP,
GRUB_KERNEL_MACHINE_MOD_ALIGN);
grub_ieee1275_init ();
grub_console_init_early ();
grub_claim_heap ();
grub_console_init_lately ();
grub_ofdisk_init ();
grub_parse_cmdline ();
grub_install_get_time_ms (ieee1275_get_time_ms);
}
@ -266,9 +298,3 @@ grub_get_rtc (void)
{
return ieee1275_get_time_ms ();
}
grub_addr_t
grub_arch_modules_addr (void)
{
return ALIGN_UP((grub_addr_t) _end + GRUB_KERNEL_MACHINE_MOD_GAP, GRUB_KERNEL_MACHINE_MOD_ALIGN);
}

View file

@ -22,16 +22,19 @@
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/ieee1275/ieee1275.h>
#include <grub/net.h>
enum grub_ieee1275_parse_type
{
GRUB_PARSE_FILENAME,
GRUB_PARSE_PARTITION,
GRUB_PARSE_DEVICE,
GRUB_PARSE_DEVICE_TYPE
};
/* Walk children of 'devpath', calling hook for each. */
int
grub_children_iterate (char *devpath,
grub_children_iterate (const char *devpath,
int (*hook) (struct grub_ieee1275_devalias *alias))
{
grub_ieee1275_phandle_t dev;
@ -317,14 +320,9 @@ grub_ieee1275_parse_args (const char *path, enum grub_ieee1275_parse_type ptype)
{
char type[64]; /* XXX check size. */
char *device = grub_ieee1275_get_devname (path);
char *args = grub_ieee1275_get_devargs (path);
char *ret = 0;
grub_ieee1275_phandle_t dev;
if (!args)
/* Shouldn't happen. */
return 0;
/* We need to know what type of device it is in order to parse the full
file path properly. */
if (grub_ieee1275_finddevice (device, &dev))
@ -339,48 +337,93 @@ grub_ieee1275_parse_args (const char *path, enum grub_ieee1275_parse_type ptype)
goto fail;
}
if (!grub_strcmp ("block", type))
switch (ptype)
{
/* The syntax of the device arguments is defined in the CHRP and PReP
IEEE1275 bindings: "[partition][,[filename]]". */
char *comma = grub_strchr (args, ',');
case GRUB_PARSE_DEVICE:
ret = grub_strdup (device);
break;
case GRUB_PARSE_DEVICE_TYPE:
ret = grub_strdup (type);
break;
case GRUB_PARSE_FILENAME:
{
char *comma;
char *args;
if (ptype == GRUB_PARSE_FILENAME)
{
if (comma)
{
char *filepath = comma + 1;
if (grub_strcmp ("block", type) != 0)
goto unknown;
/* Make sure filepath has leading backslash. */
if (filepath[0] != '\\')
ret = grub_xasprintf ("\\%s", filepath);
else
ret = grub_strdup (filepath);
args = grub_ieee1275_get_devargs (path);
if (!args)
/* Shouldn't happen. */
return 0;
/* The syntax of the device arguments is defined in the CHRP and PReP
IEEE1275 bindings: "[partition][,[filename]]". */
comma = grub_strchr (args, ',');
if (comma)
{
char *filepath = comma + 1;
/* Make sure filepath has leading backslash. */
if (filepath[0] != '\\')
ret = grub_xasprintf ("\\%s", filepath);
else
ret = grub_strdup (filepath);
}
grub_free (args);
}
else if (ptype == GRUB_PARSE_PARTITION)
{
if (!comma)
ret = grub_strdup (args);
else
ret = grub_strndup (args, (grub_size_t)(comma - args));
}
}
else
{
/* XXX Handle net devices by configuring & registering a grub_net_dev
here, then return its name?
Example path: "net:<server ip>,<file name>,<client ip>,<gateway
ip>,<bootp retries>,<tftp retries>". */
grub_printf ("Unsupported type %s for device %s\n", type, device);
break;
case GRUB_PARSE_PARTITION:
{
char *comma;
char *args;
if (grub_strcmp ("block", type) != 0)
goto unknown;
args = grub_ieee1275_get_devargs (path);
if (!args)
/* Shouldn't happen. */
return 0;
comma = grub_strchr (args, ',');
if (!comma)
ret = grub_strdup (args);
else
ret = grub_strndup (args, (grub_size_t)(comma - args));
/* Consistently provide numbered partitions to GRUB.
OpenBOOT traditionally uses alphabetical partition
specifiers. */
if (ret[0] >= 'a' && ret[0] <= 'z')
ret[0] = '1' + (ret[0] - 'a');
grub_free (args);
}
break;
default:
unknown:
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"unsupported type %s for device %s", type, device);
}
fail:
grub_free (device);
grub_free (args);
return ret;
}
char *
grub_ieee1275_get_device_type (const char *path)
{
return grub_ieee1275_parse_args (path, GRUB_PARSE_DEVICE_TYPE);
}
char *
grub_ieee1275_get_aliasdevname (const char *path)
{
return grub_ieee1275_parse_args (path, GRUB_PARSE_DEVICE);
}
char *
grub_ieee1275_get_filename (const char *path)
{
@ -403,10 +446,10 @@ grub_ieee1275_encode_devname (const char *path)
/* GRUB partition 1 is OF partition 0. */
partno++;
encoding = grub_xasprintf ("(%s,%d)", device, partno);
encoding = grub_xasprintf ("%s,%d", device, partno);
}
else
encoding = grub_xasprintf ("(%s)", device);
encoding = grub_strdup (device);
grub_free (partition);
grub_free (device);
@ -414,16 +457,6 @@ grub_ieee1275_encode_devname (const char *path)
return encoding;
}
/* On i386, a firmware-independant grub_reboot() is provided by realmode.S. */
#ifndef __i386__
void
grub_reboot (void)
{
grub_ieee1275_interpret ("reset-all", 0);
for (;;) ;
}
#endif
/* Resolve aliases. */
char *
grub_ieee1275_canonicalise_devname (const char *path)
@ -467,3 +500,4 @@ grub_ieee1275_canonicalise_devname (const char *path)
grub_free (buf);
return NULL;
}

View file

@ -30,45 +30,20 @@
#include <grub/reader.h>
#include <grub/parser.h>
void
grub_module_iterate (int (*hook) (struct grub_module_header *header))
{
struct grub_module_info *modinfo;
struct grub_module_header *header;
grub_addr_t modbase;
modbase = grub_arch_modules_addr ();
modinfo = (struct grub_module_info *) modbase;
/* Check if there are any modules. */
if ((modinfo == 0) || modinfo->magic != GRUB_MODULE_MAGIC)
return;
for (header = (struct grub_module_header *) (modbase + modinfo->offset);
header < (struct grub_module_header *) (modbase + modinfo->size);
header = (struct grub_module_header *) ((char *) header + header->size))
{
if (hook (header))
break;
}
}
/* 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)
{
struct grub_module_info *modinfo;
grub_addr_t modbase;
modbase = grub_arch_modules_addr ();
modinfo = (struct grub_module_info *) modbase;
modinfo = (struct grub_module_info *) grub_modbase;
/* Check if there are any modules. */
if ((modinfo == 0) || modinfo->magic != GRUB_MODULE_MAGIC)
return modbase;
return grub_modbase;
return modbase + modinfo->size;
return grub_modbase + modinfo->size;
}
#endif
@ -76,42 +51,36 @@ grub_modules_get_end (void)
static void
grub_load_modules (void)
{
auto int hook (struct grub_module_header *);
int hook (struct grub_module_header *header)
{
/* Not an ELF module, skip. */
if (header->type != OBJ_TYPE_ELF)
return 0;
struct grub_module_header *header;
FOR_MODULES (header)
{
/* Not an ELF module, skip. */
if (header->type != OBJ_TYPE_ELF)
continue;
if (! grub_dl_load_core ((char *) header + sizeof (struct grub_module_header),
(header->size - sizeof (struct grub_module_header))))
grub_fatal ("%s", grub_errmsg);
if (! grub_dl_load_core ((char *) header + sizeof (struct grub_module_header),
(header->size - sizeof (struct grub_module_header))))
grub_fatal ("%s", grub_errmsg);
if (grub_errno)
grub_print_error ();
return 0;
}
grub_module_iterate (hook);
if (grub_errno)
grub_print_error ();
}
}
static void
grub_load_config (void)
{
auto int hook (struct grub_module_header *);
int hook (struct grub_module_header *header)
{
/* Not an embedded config, skip. */
if (header->type != OBJ_TYPE_CONFIG)
return 0;
grub_parser_execute ((char *) header +
sizeof (struct grub_module_header));
return 1;
}
grub_module_iterate (hook);
struct grub_module_header *header;
FOR_MODULES (header)
{
/* Not an embedded config, skip. */
if (header->type != OBJ_TYPE_CONFIG)
continue;
grub_parser_execute ((char *) header +
sizeof (struct grub_module_header));
break;
}
}
/* Write hook for the environment variables of root. Remove surrounding
@ -129,27 +98,81 @@ grub_env_write_root (struct grub_env_var *var __attribute__ ((unused)),
return grub_strdup (val);
}
/* Set the root device according to the dl prefix. */
static void
grub_set_root_dev (void)
grub_set_prefix_and_root (void)
{
const char *prefix;
char *device = NULL;
char *path = NULL;
char *fwdevice = NULL;
char *fwpath = NULL;
char *prefix = NULL;
struct grub_module_header *header;
FOR_MODULES (header)
if (header->type == OBJ_TYPE_PREFIX)
prefix = (char *) header + sizeof (struct grub_module_header);
grub_register_variable_hook ("root", 0, grub_env_write_root);
prefix = grub_env_get ("prefix");
if (prefix)
{
char *dev;
dev = grub_file_get_device_name (prefix);
if (dev)
char *pptr = NULL;
if (prefix[0] == '(')
{
grub_env_set ("root", dev);
grub_free (dev);
pptr = grub_strrchr (prefix, ')');
if (pptr)
{
device = grub_strndup (prefix + 1, pptr - prefix - 1);
pptr++;
}
}
if (!pptr)
pptr = prefix;
if (pptr[0])
path = grub_strdup (pptr);
}
if ((!device || device[0] == ',' || !device[0]) || !path)
grub_machine_get_bootlocation (&fwdevice, &fwpath);
if (!device && fwdevice)
device = fwdevice;
else if (fwdevice && (device[0] == ',' || !device[0]))
{
/* We have a partition, but still need to fill in the drive. */
char *comma, *new_device;
comma = grub_strchr (fwdevice, ',');
if (comma)
{
char *drive = grub_strndup (fwdevice, comma - fwdevice);
new_device = grub_xasprintf ("%s%s", drive, device);
grub_free (drive);
}
else
new_device = grub_xasprintf ("%s%s", fwdevice, device);
grub_free (fwdevice);
grub_free (device);
device = new_device;
}
if (fwpath && !path)
path = fwpath;
if (device)
{
char *prefix_set;
prefix_set = grub_xasprintf ("(%s)%s", device, path ? : "");
if (prefix_set)
{
grub_env_set ("prefix", prefix_set);
grub_free (prefix_set);
}
grub_env_set ("root", device);
}
grub_free (device);
grub_free (path);
grub_print_error ();
}
/* Load the normal mode module and execute the normal mode if possible. */
@ -159,7 +182,7 @@ grub_load_normal_mode (void)
/* Load the module. */
grub_dl_load ("normal");
/* Something went wrong. Print errors here to let user know why we're entering rescue mode. */
/* Print errors if any. */
grub_print_error ();
grub_errno = 0;
@ -167,7 +190,7 @@ grub_load_normal_mode (void)
}
/* The main routine. */
void
void __attribute__ ((noreturn))
grub_main (void)
{
/* First of all, initialize the machine. */
@ -187,8 +210,7 @@ grub_main (void)
/* It is better to set the root device as soon as possible,
for convenience. */
grub_machine_set_prefix ();
grub_set_root_dev ();
grub_set_prefix_and_root ();
grub_env_export ("root");
grub_env_export ("prefix");

View file

@ -33,6 +33,7 @@
#include <grub/term.h>
#include <grub/arc/arc.h>
#include <grub/offsets.h>
#include <grub/i18n.h>
const char *type_names[] = {
#ifdef GRUB_CPU_WORDS_BIGENDIAN
@ -125,12 +126,14 @@ grub_machine_mmap_iterate (grub_memory_hook_t hook)
}
extern grub_uint32_t grub_total_modules_size;
grub_addr_t grub_modbase;
void
grub_machine_init (void)
{
struct grub_arc_memory_descriptor *cur = NULL;
grub_modbase = GRUB_KERNEL_MIPS_ARC_LINK_ADDR - grub_total_modules_size;
grub_console_init_early ();
/* FIXME: measure this. */
@ -164,12 +167,6 @@ grub_machine_init (void)
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)
{
@ -182,7 +179,7 @@ grub_halt (void)
grub_millisleep (1500);
grub_printf ("Shutdown failed\n");
grub_puts_ (N_("Shutdown failed"));
grub_refresh ();
while (1);
}
@ -194,19 +191,7 @@ grub_exit (void)
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_puts_ (N_("Exit failed"));
grub_refresh ();
while (1);
}

View file

@ -9,6 +9,13 @@
subu $t1, $t3, $t2
1:
cache 1, 0($t0)
/* All four ways. */
#ifdef GRUB_MACHINE_MIPS_LOONGSON
cache 1, 1($t0)
cache 1, 2($t0)
cache 1, 3($t0)
#endif
addiu $t1, $t1, -0x4
bne $t1, $zero, 1b
addiu $t0, $t0, 0x4

View file

@ -38,7 +38,7 @@ grub_get_rtc (void)
}
void
grub_machine_set_prefix (void)
grub_machine_get_bootlocation (char **device __attribute__ ((unused)),
char **path __attribute__ ((unused)))
{
grub_env_set ("prefix", grub_prefix);
}

View file

@ -30,11 +30,12 @@
#include <grub/mips/loongson.h>
#include <grub/cs5536.h>
#include <grub/term.h>
#include <grub/machine/ec.h>
#include <grub/cpu/memory.h>
#include <grub/i18n.h>
extern void grub_video_sm712_init (void);
extern void grub_video_sis315pro_init (void);
extern void grub_video_radeon_fuloong2e_init (void);
extern void grub_video_init (void);
extern void grub_bitmap_init (void);
extern void grub_font_init (void);
@ -123,6 +124,23 @@ void
grub_machine_init (void)
{
grub_addr_t modend;
grub_uint32_t prid;
asm volatile ("mfc0 %0, " GRUB_CPU_LOONGSON_COP0_PRID : "=r" (prid));
switch (prid)
{
/* Loongson 2E. */
case 0x6302:
grub_arch_machine = GRUB_ARCH_MACHINE_FULOONG2E;
break;
/* Loongson 2F. */
case 0x6303:
if (grub_arch_machine != GRUB_ARCH_MACHINE_FULOONG2F
&& grub_arch_machine != GRUB_ARCH_MACHINE_YEELOONG)
grub_arch_machine = GRUB_ARCH_MACHINE_YEELOONG;
break;
}
/* FIXME: measure this. */
if (grub_arch_busclock == 0)
@ -170,7 +188,7 @@ grub_machine_init (void)
}
else
{
grub_arch_memsize = (totalmem >> 20);
grub_arch_memsize = totalmem;
grub_arch_highmemsize = 0;
}
@ -189,6 +207,7 @@ grub_machine_init (void)
grub_video_init ();
grub_video_sm712_init ();
grub_video_sis315pro_init ();
grub_video_radeon_fuloong2e_init ();
grub_bitmap_init ();
grub_font_init ();
grub_gfxterm_init ();
@ -213,7 +232,9 @@ grub_halt (void)
{
switch (grub_arch_machine)
{
case GRUB_ARCH_MACHINE_FULOONG:
case GRUB_ARCH_MACHINE_FULOONG2E:
break;
case GRUB_ARCH_MACHINE_FULOONG2F:
{
grub_pci_device_t dev;
grub_port_t p;
@ -234,7 +255,7 @@ grub_halt (void)
break;
}
grub_printf ("Shutdown failed\n");
grub_puts_ (N_("Shutdown failed"));
grub_refresh ();
while (1);
}
@ -245,22 +266,6 @@ grub_exit (void)
grub_halt ();
}
void
grub_reboot (void)
{
grub_write_ec (GRUB_MACHINE_EC_COMMAND_REBOOT);
grub_millisleep (1500);
grub_printf ("Reboot failed\n");
grub_refresh ();
while (1);
}
extern char _end[];
grub_addr_t grub_modbase = (grub_addr_t) _end;
grub_addr_t
grub_arch_modules_addr (void)
{
return (grub_addr_t) _end;
}

View file

@ -7,17 +7,51 @@
#include <grub/mm.h>
#include <grub/time.h>
#include <grub/machine/memory.h>
#include <grub/machine/kernel.h>
#include <grub/cpu/memory.h>
#include <grub/memory.h>
extern void grub_serial_init (void);
extern void grub_terminfo_init (void);
extern void grub_at_keyboard_init (void);
extern void grub_video_init (void);
extern void grub_bitmap_init (void);
extern void grub_font_init (void);
extern void grub_gfxterm_init (void);
extern void grub_keylayouts_init (void);
extern void grub_boot_init (void);
extern void grub_vga_text_init (void);
static inline int
probe_mem (grub_addr_t addr)
{
volatile grub_uint8_t *ptr = (grub_uint8_t *) (0xa0000000 | addr);
grub_uint8_t c = *ptr;
*ptr = 0xAA;
if (*ptr != 0xAA)
return 0;
*ptr = 0x55;
if (*ptr != 0x55)
return 0;
*ptr = c;
return 1;
}
void
grub_machine_init (void)
{
grub_addr_t modend;
if (grub_arch_memsize == 0)
{
int i;
for (i = 27; i >= 0; i--)
if (probe_mem (grub_arch_memsize | (1 << i)))
grub_arch_memsize |= (1 << i);
grub_arch_memsize++;
}
/* FIXME: measure this. */
grub_arch_cpuclock = 64000000;
@ -27,8 +61,22 @@ grub_machine_init (void)
grub_install_get_time_ms (grub_rtc_get_time_ms);
grub_video_init ();
grub_bitmap_init ();
grub_font_init ();
grub_keylayouts_init ();
grub_at_keyboard_init ();
grub_qemu_init_cirrus ();
grub_vga_text_init ();
grub_terminfo_init ();
grub_serial_init ();
grub_boot_init ();
grub_gfxterm_init ();
}
void
@ -48,12 +96,6 @@ grub_halt (void)
while (1);
}
void
grub_reboot (void)
{
while (1);
}
grub_err_t
grub_machine_mmap_iterate (grub_memory_hook_t hook)
{
@ -62,9 +104,5 @@ grub_machine_mmap_iterate (grub_memory_hook_t hook)
}
extern char _end[];
grub_addr_t grub_modbase = (grub_addr_t) _end;
grub_addr_t
grub_arch_modules_addr (void)
{
return (grub_addr_t) _end;
}

View file

@ -40,17 +40,6 @@ start:
VARIABLE(grub_total_modules_size)
.long 0
. = _start + GRUB_KERNEL_MACHINE_PREFIX
VARIABLE(grub_prefix)
/* to be filled by grub-mkimage */
/*
* Leave some breathing room for the prefix.
*/
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END
VARIABLE (grub_arch_busclock)
.long 0
VARIABLE (grub_arch_cpuclock)
@ -61,7 +50,7 @@ VARIABLE (grub_arch_highmemsize)
.long 0
#ifdef GRUB_MACHINE_MIPS_LOONGSON
VARIABLE (grub_arch_machine)
.long GRUB_ARCH_MACHINE_FULOONG
.long GRUB_ARCH_MACHINE_FULOONG2F
#endif
cont:
/* Save our base. */

View file

@ -210,11 +210,14 @@ grub_vprintf (const char *fmt, va_list args)
buf[PREALLOC_SIZE - 2] = '.';
buf[PREALLOC_SIZE - 1] = '.';
buf[PREALLOC_SIZE] = 0;
curbuf = buf;
}
else
s = grub_vsnprintf_real (curbuf, s, fmt, ap2);
}
va_end (ap2);
grub_xputs (curbuf);
if (curbuf != buf)
@ -311,52 +314,6 @@ grub_strrchr (const char *s, int c)
return p;
}
/* Copied from gnulib.
Written by Bruno Haible <bruno@clisp.org>, 2005. */
char *
grub_strstr (const char *haystack, const char *needle)
{
/* Be careful not to look at the entire extent of haystack or needle
until needed. This is useful because of these two cases:
- haystack may be very long, and a match of needle found early,
- needle may be very long, and not even a short initial segment of
needle may be found in haystack. */
if (*needle != '\0')
{
/* Speed up the following searches of needle by caching its first
character. */
char b = *needle++;
for (;; haystack++)
{
if (*haystack == '\0')
/* No match. */
return NULL;
if (*haystack == b)
/* The first character matches. */
{
const char *rhaystack = haystack + 1;
const char *rneedle = needle;
for (;; rhaystack++, rneedle++)
{
if (*rneedle == '\0')
/* Found a match. */
return (char *) haystack;
if (*rhaystack == '\0')
/* No match. */
return NULL;
if (*rhaystack != *rneedle)
/* Nothing in this round. */
break;
}
}
}
}
else
return (char *) haystack;
}
int
grub_strword (const char *haystack, const char *needle)
{
@ -680,10 +637,13 @@ grub_lltoa (char *str, int c, unsigned long long n)
}
static int
grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt, va_list args)
grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt0, va_list args_in)
{
char c;
grub_size_t n = 0;
grub_size_t count = 0;
grub_size_t count_args = 0;
const char *fmt;
auto void write_char (unsigned char ch);
auto void write_str (const char *s);
auto void write_fill (const char ch, int n);
@ -702,209 +662,368 @@ grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt, va_list ar
write_char (*s++);
}
void write_fill (const char ch, int n)
void write_fill (const char ch, int count_fill)
{
int i;
for (i = 0; i < n; i++)
for (i = 0; i < count_fill; i++)
write_char (ch);
}
fmt = fmt0;
while ((c = *fmt++) != 0)
{
if (c != '%')
write_char (c);
else
continue;
if (*fmt && *fmt =='-')
fmt++;
while (*fmt && grub_isdigit (*fmt))
fmt++;
if (*fmt && *fmt == '$')
fmt++;
if (*fmt && *fmt =='-')
fmt++;
while (*fmt && grub_isdigit (*fmt))
fmt++;
if (*fmt && *fmt =='.')
fmt++;
while (*fmt && grub_isdigit (*fmt))
fmt++;
c = *fmt++;
if (c == 'l')
{
char tmp[32];
char *p;
unsigned int format1 = 0;
unsigned int format2 = ~ 0U;
char zerofill = ' ';
int rightfill = 0;
int n;
int longfmt = 0;
int longlongfmt = 0;
int unsig = 0;
c = *fmt++;
if (c == 'l')
c = *fmt++;
}
switch (c)
{
case 'p':
case 'x':
case 'u':
case 'd':
case 'c':
case 'C':
case 's':
count_args++;
break;
}
}
if (*fmt && *fmt =='-')
enum { INT, WCHAR, LONG, LONGLONG, POINTER } types[count_args];
union
{
int i;
grub_uint32_t w;
long l;
long long ll;
void *p;
} args[count_args];
grub_memset (types, 0, sizeof (types));
fmt = fmt0;
n = 0;
while ((c = *fmt++) != 0)
{
int longfmt = 0;
int longlongfmt = 0;
grub_size_t curn;
const char *p;
if (c != '%')
continue;
curn = n++;
if (*fmt && *fmt =='-')
fmt++;
while (*fmt && grub_isdigit (*fmt))
fmt++;
if (*fmt && *fmt =='.')
fmt++;
while (*fmt && grub_isdigit (*fmt))
fmt++;
p = fmt;
if (*fmt && *fmt == '$')
{
curn = grub_strtoull (p, 0, 10) - 1;
fmt++;
}
while (*fmt && grub_isdigit (*fmt))
fmt++;
c = *fmt++;
if (c == 'l')
{
c = *fmt++;
longfmt = 1;
if (c == 'l')
{
rightfill = 1;
fmt++;
c = *fmt++;
longlongfmt = 1;
}
}
if (curn >= count_args)
continue;
switch (c)
{
case 'x':
case 'u':
case 'd':
if (longlongfmt)
types[curn] = LONGLONG;
else if (longfmt)
types[curn] = LONG;
else
types[curn] = INT;
break;
case 'p':
case 's':
types[curn] = POINTER;
break;
case 'c':
types[curn] = INT;
break;
case 'C':
types[curn] = WCHAR;
break;
}
}
p = (char *) fmt;
/* Read formatting parameters. */
for (n = 0; n < count_args; n++)
switch (types[n])
{
case WCHAR:
args[n].w = va_arg (args_in, grub_uint32_t);
break;
case POINTER:
args[n].p = va_arg (args_in, void *);
break;
case INT:
args[n].i = va_arg (args_in, int);
break;
case LONG:
args[n].l = va_arg (args_in, long);
break;
case LONGLONG:
args[n].ll = va_arg (args_in, long long);
break;
}
fmt = fmt0;
n = 0;
while ((c = *fmt++) != 0)
{
char tmp[32];
char *p;
unsigned int format1 = 0;
unsigned int format2 = ~ 0U;
char zerofill = ' ';
int rightfill = 0;
int longfmt = 0;
int longlongfmt = 0;
int unsig = 0;
grub_size_t curn;
if (c != '%')
{
write_char (c);
continue;
}
curn = n++;
rescan:;
if (*fmt && *fmt =='-')
{
rightfill = 1;
fmt++;
}
p = (char *) fmt;
/* Read formatting parameters. */
while (*p && grub_isdigit (*p))
p++;
if (p > fmt)
{
char s[p - fmt + 1];
grub_strncpy (s, fmt, p - fmt);
s[p - fmt] = 0;
if (s[0] == '0')
zerofill = '0';
format1 = grub_strtoul (s, 0, 10);
fmt = p;
}
if (*p && *p == '.')
{
p++;
fmt++;
while (*p && grub_isdigit (*p))
p++;
if (p > fmt)
{
char s[p - fmt + 1];
grub_strncpy (s, fmt, p - fmt);
s[p - fmt] = 0;
if (s[0] == '0')
zerofill = '0';
format1 = grub_strtoul (s, 0, 10);
char fstr[p - fmt + 1];
grub_strncpy (fstr, fmt, p - fmt);
fstr[p - fmt] = 0;
format2 = grub_strtoul (fstr, 0, 10);
fmt = p;
}
}
if (*fmt == '$')
{
curn = format1 - 1;
fmt++;
format1 = 0;
format2 = ~ 0U;
zerofill = ' ';
rightfill = 0;
if (*p && *p == '.')
{
p++;
fmt++;
while (*p && grub_isdigit (*p))
p++;
if (p > fmt)
{
char fstr[p - fmt + 1];
grub_strncpy (fstr, fmt, p - fmt);
fstr[p - fmt] = 0;
format2 = grub_strtoul (fstr, 0, 10);
fmt = p;
}
}
goto rescan;
}
c = *fmt++;
if (c == 'l')
{
longfmt = 1;
c = *fmt++;
if (c == 'l')
{
longfmt = 1;
longlongfmt = 1;
c = *fmt++;
if (c == 'l')
{
longlongfmt = 1;
c = *fmt++;
}
}
}
switch (c)
{
case 'p':
write_str ("0x");
c = 'x';
longlongfmt |= (sizeof (void *) == sizeof (long long));
/* Fall through. */
case 'x':
case 'u':
unsig = 1;
/* Fall through. */
case 'd':
if (longlongfmt)
{
long long ll;
if (curn >= count_args)
continue;
ll = va_arg (args, long long);
grub_lltoa (tmp, c, ll);
}
else if (longfmt && unsig)
{
unsigned long l = va_arg (args, unsigned long);
grub_lltoa (tmp, c, l);
}
else if (longfmt)
{
long l = va_arg (args, long);
grub_lltoa (tmp, c, l);
}
else if (unsig)
{
unsigned u = va_arg (args, unsigned);
grub_lltoa (tmp, c, u);
}
else
{
n = va_arg (args, int);
grub_lltoa (tmp, c, n);
}
if (! rightfill && grub_strlen (tmp) < format1)
write_fill (zerofill, format1 - grub_strlen (tmp));
write_str (tmp);
if (rightfill && grub_strlen (tmp) < format1)
write_fill (zerofill, format1 - grub_strlen (tmp));
break;
switch (c)
{
case 'p':
write_str ("0x");
c = 'x';
longlongfmt |= (sizeof (void *) == sizeof (long long));
/* Fall through. */
case 'x':
case 'u':
unsig = 1;
/* Fall through. */
case 'd':
if (longlongfmt)
grub_lltoa (tmp, c, args[curn].ll);
else if (longfmt && unsig)
grub_lltoa (tmp, c, (unsigned long) args[curn].l);
else if (longfmt)
grub_lltoa (tmp, c, args[curn].l);
else if (unsig)
grub_lltoa (tmp, c, (unsigned) args[curn].i);
else
grub_lltoa (tmp, c, args[curn].i);
if (! rightfill && grub_strlen (tmp) < format1)
write_fill (zerofill, format1 - grub_strlen (tmp));
write_str (tmp);
if (rightfill && grub_strlen (tmp) < format1)
write_fill (zerofill, format1 - grub_strlen (tmp));
break;
case 'c':
n = va_arg (args, int);
write_char (n & 0xff);
break;
case 'c':
write_char (args[curn].i & 0xff);
break;
case 'C':
case 'C':
{
grub_uint32_t code = args[curn].w;
int shift;
unsigned mask;
if (code <= 0x7f)
{
grub_uint32_t code = va_arg (args, grub_uint32_t);
int shift;
unsigned mask;
if (code <= 0x7f)
{
shift = 0;
mask = 0;
}
else if (code <= 0x7ff)
{
shift = 6;
mask = 0xc0;
}
else if (code <= 0xffff)
{
shift = 12;
mask = 0xe0;
}
else if (code <= 0x1fffff)
{
shift = 18;
mask = 0xf0;
}
else if (code <= 0x3ffffff)
{
shift = 24;
mask = 0xf8;
}
else if (code <= 0x7fffffff)
{
shift = 30;
mask = 0xfc;
}
else
{
code = '?';
shift = 0;
mask = 0;
}
write_char (mask | (code >> shift));
for (shift -= 6; shift >= 0; shift -= 6)
write_char (0x80 | (0x3f & (code >> shift)));
shift = 0;
mask = 0;
}
else if (code <= 0x7ff)
{
shift = 6;
mask = 0xc0;
}
else if (code <= 0xffff)
{
shift = 12;
mask = 0xe0;
}
else if (code <= 0x1fffff)
{
shift = 18;
mask = 0xf0;
}
else if (code <= 0x3ffffff)
{
shift = 24;
mask = 0xf8;
}
else if (code <= 0x7fffffff)
{
shift = 30;
mask = 0xfc;
}
else
{
code = '?';
shift = 0;
mask = 0;
}
break;
case 's':
p = va_arg (args, char *);
if (p)
{
grub_size_t len = 0;
while (len < format2 && p[len])
len++;
write_char (mask | (code >> shift));
if (!rightfill && len < format1)
write_fill (zerofill, format1 - len);
for (shift -= 6; shift >= 0; shift -= 6)
write_char (0x80 | (0x3f & (code >> shift)));
}
break;
grub_size_t i;
for (i = 0; i < len; i++)
write_char (*p++);
case 's':
p = args[curn].p;
if (p)
{
grub_size_t len = 0;
while (len < format2 && p[len])
len++;
if (rightfill && len < format1)
write_fill (zerofill, format1 - len);
}
else
write_str ("(null)");
if (!rightfill && len < format1)
write_fill (zerofill, format1 - len);
break;
grub_size_t i;
for (i = 0; i < len; i++)
write_char (*p++);
default:
write_char (c);
break;
if (rightfill && len < format1)
write_fill (zerofill, format1 - len);
}
else
write_str ("(null)");
break;
default:
write_char (c);
break;
}
}
@ -956,6 +1075,9 @@ grub_xvasprintf (const char *fmt, va_list ap)
return NULL;
s = grub_vsnprintf_real (ret, as, fmt, ap2);
va_end (ap2);
if (s <= as)
return ret;

View file

@ -515,7 +515,7 @@ grub_debug_malloc (const char *file, int line, grub_size_t size)
void *ptr;
if (grub_mm_debug)
grub_printf ("%s:%d: malloc (0x%zx) = ", file, line, size);
grub_printf ("%s:%d: malloc (0x%" PRIxGRUB_SIZE ") = ", file, line, size);
ptr = grub_malloc (size);
if (grub_mm_debug)
grub_printf ("%p\n", ptr);
@ -528,7 +528,7 @@ grub_debug_zalloc (const char *file, int line, grub_size_t size)
void *ptr;
if (grub_mm_debug)
grub_printf ("%s:%d: zalloc (0x%zx) = ", file, line, size);
grub_printf ("%s:%d: zalloc (0x%" PRIxGRUB_SIZE ") = ", file, line, size);
ptr = grub_zalloc (size);
if (grub_mm_debug)
grub_printf ("%p\n", ptr);
@ -547,7 +547,7 @@ void *
grub_debug_realloc (const char *file, int line, void *ptr, grub_size_t size)
{
if (grub_mm_debug)
grub_printf ("%s:%d: realloc (%p, 0x%zx) = ", file, line, ptr, size);
grub_printf ("%s:%d: realloc (%p, 0x%" PRIxGRUB_SIZE ") = ", file, line, ptr, size);
ptr = grub_realloc (ptr, size);
if (grub_mm_debug)
grub_printf ("%p\n", ptr);
@ -561,8 +561,8 @@ grub_debug_memalign (const char *file, int line, grub_size_t align,
void *ptr;
if (grub_mm_debug)
grub_printf ("%s:%d: memalign (0x%zx, 0x%zx) = ",
file, line, align, size);
grub_printf ("%s:%d: memalign (0x%" PRIxGRUB_SIZE ", 0x%" PRIxGRUB_SIZE
") = ", file, line, align, size);
ptr = grub_memalign (align, size);
if (grub_mm_debug)
grub_printf ("%p\n", ptr);

View file

@ -123,7 +123,7 @@ grub_parser_split_cmdline (const char *cmdline, grub_reader_getline_t getline,
void add_var (grub_parser_state_t newstate)
{
char *val;
const char *val;
/* Check if a variable was being read in and the end of the name
was reached. */

View file

@ -20,6 +20,7 @@
#include <grub/mm.h>
#include <grub/partition.h>
#include <grub/disk.h>
#include <grub/i18n.h>
#ifdef GRUB_UTIL
#include <grub/util/misc.h>
@ -47,7 +48,7 @@ grub_partition_check_containment (const grub_disk_t disk,
grub_dprintf ("partition", "sub-partition %s%d of (%s,%s) ends after parent.\n",
part->partmap->name, part->number + 1, disk->name, partname);
#ifdef GRUB_UTIL
grub_util_warn ("Discarding improperly nested partition (%s,%s,%s%d)",
grub_util_warn (_("Discarding improperly nested partition (%s,%s,%s%d)"),
disk->name, partname, part->partmap->name, part->number + 1);
#endif
grub_free (partname);

View file

@ -37,6 +37,65 @@ grub_arch_dl_check_header (void *ehdr)
return GRUB_ERR_NONE;
}
void
grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
grub_size_t *got)
{
const Elf_Ehdr *e = ehdr;
const Elf_Shdr *s;
Elf_Word entsize;
unsigned i;
*tramp = 0;
*got = 0;
/* Find a symbol table. */
for (i = 0, s = (const Elf_Shdr *) ((const char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (const Elf_Shdr *) ((const 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 = (const Elf_Shdr *) ((const char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (const Elf_Shdr *) ((const char *) s + e->e_shentsize))
if (s->sh_type == SHT_RELA)
{
const Elf_Rela *rel, *max;
for (rel = (const Elf_Rela *) ((const char *) e + s->sh_offset),
max = rel + s->sh_size / s->sh_entsize;
rel < max;
rel++)
if (ELF_R_TYPE (rel->r_info) == R_PPC_REL24)
(*tramp)++;
}
return;
}
/* For low-endian reverse lis and addr_high as well as ori and addr_low. */
struct trampoline
{
grub_uint32_t lis;
grub_uint32_t ori;
grub_uint32_t mtctr;
grub_uint32_t bctr;
};
static const struct trampoline trampoline_template =
{
0x3c000000,
0x60000000,
0x7c0903a6,
0x4e800420,
};
/* Relocate symbols. */
grub_err_t
@ -46,6 +105,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
Elf_Shdr *s;
Elf_Word entsize;
unsigned i;
struct trampoline *tptr = mod->tramp;
/* Find a symbol table. */
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
@ -106,7 +166,20 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
Elf_Sword delta = value - (Elf_Word) addr;
if (delta << 6 >> 6 != delta)
return grub_error (GRUB_ERR_BAD_MODULE, "relocation overflow");
{
COMPILE_TIME_ASSERT (sizeof (struct trampoline)
== GRUB_ARCH_DL_TRAMP_SIZE);
grub_memcpy (tptr, &trampoline_template,
sizeof (*tptr));
delta = (grub_uint8_t *) tptr - (grub_uint8_t *) addr;
tptr->lis |= (((value) >> 16) & 0xffff);
tptr->ori |= ((value) & 0xffff);
tptr++;
}
if (delta << 6 >> 6 != delta)
return grub_error (GRUB_ERR_BAD_MODULE,
"relocation overflow");
*addr = (*addr & 0xfc000003) | (delta & 0x3fffffc);
break;
}

View file

@ -28,20 +28,6 @@
.globl start, _start
start:
_start:
b codestart
. = _start + GRUB_KERNEL_MACHINE_PREFIX
VARIABLE(grub_prefix)
/* to be filled by grub-mkimage */
/*
* Leave some breathing room for the prefix.
*/
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END
codestart:
li 2, 0
li 13, 0

View file

@ -74,7 +74,7 @@ grub_rescue_read_line (char **line, int cont)
return 0;
}
void
void __attribute__ ((noreturn))
grub_rescue_run (void)
{
grub_printf ("Entering rescue mode...\n");

View file

@ -111,10 +111,13 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
(((grub_int32_t) ((value - (Elf_Addr) addr) >> 2)) &
0x3FFFFFFF);
break;
case R_SPARC_HH22: /* 9 V-imm22 */
*addr = (*addr & 0xFFC00000) | ((value >> 42) & 0x3FFFFF);
break;
case R_SPARC_HM10: /* 12 T-simm13 */
*addr = (*addr & 0xFFFFFC00) | ((value >> 32) & 0x3FF);
break;
case R_SPARC_HI22: /* 9 V-imm22 */
if (((grub_int32_t) value) & 0xFF00000000)
return grub_error (GRUB_ERR_BAD_MODULE,
"high address out of 22 bits range");
*addr = (*addr & 0xFFC00000) | ((value >> 10) & 0x3FFFFF);
break;
case R_SPARC_LO10: /* 12 T-simm13 */

View file

@ -31,18 +31,6 @@ _start:
VARIABLE(grub_total_module_size)
.word 0
VARIABLE(grub_kernel_image_size)
.word 0
VARIABLE(grub_compressed_size)
.word 0
VARIABLE(grub_prefix)
/* to be filled by grub-mkimage */
/*
* Leave some breathing room for the prefix.
*/
. = EXT_C(_start) + GRUB_KERNEL_MACHINE_PREFIX_END
codestart:
/* Copy the modules past the end of the kernel image.

View file

@ -1,174 +0,0 @@
/* init.c -- Initialize GRUB on SPARC64. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/kernel.h>
#include <grub/mm.h>
#include <grub/env.h>
#include <grub/err.h>
#include <grub/misc.h>
#include <grub/time.h>
#include <grub/machine/boot.h>
#include <grub/ieee1275/console.h>
#include <grub/machine/kernel.h>
#include <grub/machine/time.h>
#include <grub/ieee1275/ofdisk.h>
#include <grub/ieee1275/ieee1275.h>
grub_addr_t grub_ieee1275_original_stack;
void
grub_exit (void)
{
grub_ieee1275_exit ();
}
static grub_uint64_t
ieee1275_get_time_ms (void)
{
grub_uint32_t msecs = 0;
grub_ieee1275_milliseconds (&msecs);
return msecs;
}
grub_uint32_t
grub_get_rtc (void)
{
return ieee1275_get_time_ms ();
}
grub_addr_t
grub_arch_modules_addr (void)
{
extern char _end[];
return (grub_addr_t) _end;
}
void
grub_machine_set_prefix (void)
{
if (grub_prefix[0] != '(')
{
char bootpath[IEEE1275_MAX_PATH_LEN];
char *prefix, *path, *colon;
grub_ssize_t actual;
if (grub_ieee1275_get_property (grub_ieee1275_chosen, "bootpath",
&bootpath, sizeof (bootpath), &actual))
{
/* Should never happen. */
grub_printf ("/chosen/bootpath property missing!\n");
grub_env_set ("prefix", "");
return;
}
/* Transform an OF device path to a GRUB path. */
colon = grub_strchr (bootpath, ':');
if (colon)
{
char *part = colon + 1;
/* Consistently provide numbered partitions to GRUB.
OpenBOOT traditionally uses alphabetical partition
specifiers. */
if (part[0] >= 'a' && part[0] <= 'z')
part[0] = '1' + (part[0] - 'a');
}
prefix = grub_ieee1275_encode_devname (bootpath);
path = grub_xasprintf("%s%s", prefix, grub_prefix);
grub_strcpy (grub_prefix, path);
grub_free (path);
grub_free (prefix);
}
grub_env_set ("prefix", grub_prefix);
}
static void
grub_heap_init (void)
{
grub_mm_init_region ((void *) (grub_modules_get_end ()
+ GRUB_KERNEL_MACHINE_STACK_SIZE), 0x200000);
}
static void
grub_parse_cmdline (void)
{
grub_ssize_t actual;
char args[256];
if (grub_ieee1275_get_property (grub_ieee1275_chosen, "bootargs", &args,
sizeof args, &actual) == 0
&& actual > 1)
{
int i = 0;
while (i < actual)
{
char *command = &args[i];
char *end;
char *val;
end = grub_strchr (command, ';');
if (end == 0)
i = actual; /* No more commands after this one. */
else
{
*end = '\0';
i += end - command + 1;
while (grub_isspace(args[i]))
i++;
}
/* Process command. */
val = grub_strchr (command, '=');
if (val)
{
*val = '\0';
grub_env_set (command, val + 1);
}
}
}
}
void
grub_machine_init (void)
{
grub_ieee1275_init ();
grub_console_init_early ();
grub_heap_init ();
grub_console_init_lately ();
grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_PARTITION_0);
grub_ofdisk_init ();
grub_parse_cmdline ();
grub_install_get_time_ms (ieee1275_get_time_ms);
}
void
grub_machine_fini (void)
{
grub_ofdisk_fini ();
grub_console_fini ();
}

View file

@ -29,6 +29,7 @@ struct grub_term_output *grub_term_outputs;
struct grub_term_input *grub_term_inputs;
void (*grub_term_poll_usb) (void) = NULL;
void (*grub_net_poll_cards_idle) (void) = NULL;
/* Put a Unicode character. */
static void
@ -91,6 +92,9 @@ grub_checkkey (void)
if (grub_term_poll_usb)
grub_term_poll_usb ();
if (grub_net_poll_cards_idle)
grub_net_poll_cards_idle ();
FOR_ACTIVE_TERM_INPUTS(term)
{
pending_key = term->getkey (term);

View file

@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010 Free Software Foundation, Inc.
* Copyright (C) 2010,2011 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -16,7 +16,9 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __mips__
#include <grub/pci.h>
#endif
#include <grub/machine/kernel.h>
#include <grub/misc.h>
#include <grub/vga.h>
@ -43,7 +45,17 @@ static struct {grub_uint8_t r, g, b, a; } colors[] =
{0xFE, 0xFE, 0xFE, 0xFF} // 15 = white
};
#ifdef __mips__
extern unsigned char ascii_bitmaps[];
#else
#include <ascii.h>
#endif
#ifdef __mips__
#define VGA_ADDR 0xb00a0000
#else
#define VGA_ADDR 0xa0000
#endif
static void
load_font (void)
@ -61,7 +73,7 @@ load_font (void)
grub_vga_gr_write (0xff, GRUB_VGA_GR_BITMASK);
for (i = 0; i < 128; i++)
grub_memcpy ((void *) (0xa0000 + 32 * i), ascii_bitmaps + 16 * i, 16);
grub_memcpy ((void *) (VGA_ADDR + 32 * i), ascii_bitmaps + 16 * i, 16);
}
static void
@ -78,6 +90,7 @@ load_palette (void)
void
grub_qemu_init_cirrus (void)
{
#ifndef __mips__
auto int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev, grub_pci_id_t pciid);
int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev, grub_pci_id_t pciid __attribute__ ((unused)))
{
@ -106,8 +119,10 @@ grub_qemu_init_cirrus (void)
}
grub_pci_iterate (find_card);
#endif
grub_outb (GRUB_VGA_IO_MISC_COLOR, GRUB_VGA_IO_MISC_WRITE);
grub_outb (GRUB_VGA_IO_MISC_COLOR,
GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_MISC_WRITE);
load_font ();
@ -143,5 +158,5 @@ grub_qemu_init_cirrus (void)
grub_vga_cr_write (14, GRUB_VGA_CR_CURSOR_START);
grub_vga_cr_write (15, GRUB_VGA_CR_CURSOR_END);
grub_outb (0x20, 0x3c0);
grub_outb (0x20, GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_ARX);
}

View file

@ -109,7 +109,9 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
break;
default:
grub_fatal ("Unrecognized relocation: %d\n", ELF_R_TYPE (rel->r_info));
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"this relocation (%d) is not implemented yet",
ELF_R_TYPE (rel->r_info));
}
}
}

View file

@ -19,14 +19,13 @@
#include <config.h>
#include <grub/symbol.h>
#include <grub/boot.h>
/*
* x86_64 uses registry to pass parameters. Unfortunately, gcc and efi use
* different call conversion, so we need to do some conversion.
*
* gcc:
* %rdi, %esi, %rdx, %rcx, %r8, %r9, 8(%rsp), 16(%rsp), ...
* %rdi, %rsi, %rdx, %rcx, %r8, %r9, 8(%rsp), 16(%rsp), ...
*
* efi:
* %rcx, %rdx, %r8, %r9, 32(%rsp), 40(%rsp), 48(%rsp), ...
@ -95,6 +94,20 @@ FUNCTION(efi_wrap_6)
addq $64, %rsp
ret
FUNCTION(efi_wrap_7)
subq $96, %rsp
mov 96+16(%rsp), %rax
mov %rax, 48(%rsp)
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 $96, %rsp
ret
FUNCTION(efi_wrap_10)
subq $96, %rsp
mov 96+40(%rsp), %rax

View file

@ -19,7 +19,6 @@
#include <config.h>
#include <grub/symbol.h>
#include <grub/boot.h>
.file "startup.S"
.text
@ -28,33 +27,6 @@
start:
_start:
jmp codestart
/*
* Compatibility version number
*
* These MUST be at byte offset 6 and 7 of the executable
* DO NOT MOVE !!!
*/
. = _start + 0x6
.byte GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR
/*
* This is a special data area 8 bytes from the beginning.
*/
. = _start + 0x8
VARIABLE(grub_prefix)
/* to be filled by grub-mkimage */
/*
* Leave some breathing room for the prefix.
*/
. = _start + 0x50
codestart:
movq %rcx, EXT_C(grub_efi_image_handle)(%rip)
movq %rdx, EXT_C(grub_efi_system_table)(%rip)